From 4082b5808a2d65c622e932f71eae373c61ad8487 Mon Sep 17 00:00:00 2001 From: geromueller Date: Mon, 19 Mar 2012 11:39:10 +0100 Subject: [PATCH 0001/1298] add cmake install, improve getDataPath --- CMakeLists.txt | 69 ++++++++++++++++++++++--------------------- src/module/common.cpp | 41 +++++++++++++++++++++---- 2 files changed, 72 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 98c6cf5be..0a0865d7f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,7 +56,11 @@ if(OPENMP_FOUND) endif() include_directories(include ${MPC_EXTRA_INCLUDES}) +add_definitions(-DMPC_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") +# ---------------------------------------------------------------------------- +# mpc and mpc-run +# ---------------------------------------------------------------------------- add_library(mpc SHARED src/Random.cpp src/Vector3.cpp @@ -83,23 +87,15 @@ TARGET_LINK_LIBRARIES(mpc ${MPC_EXTRA_LIBRARIES}) add_executable(mpc-run src/main.cpp) TARGET_LINK_LIBRARIES(mpc-run mpc) -add_executable(openmp example/openmp.cpp) -TARGET_LINK_LIBRARIES(openmp mpc) - -# MPI needed for mpc-mpi -find_package(MPI) -if (MPI_FOUND) - include_directories(${MPI_INCLUDE_PATH}) - - set(CMAKE_CXX_COMPILE_FLAGS ${CMAKE_CXX_COMPILE_FLAGS} ${MPI_COMPILE_FLAGS}) - set(CMAKE_CXX_LINK_FLAGS ${CMAKE_CXX_LINK_FLAGS} ${MPI_LINK_FLAGS}) - - add_executable(mpc-mpi mpi/main mpi/Slave mpi/Master mpi/Job) - TARGET_LINK_LIBRARIES(mpc-mpi mpc ${MPI_LIBRARIES}) -endif() +INSTALL(TARGETS mpc-run RUNTIME DESTINATION bin) +INSTALL(TARGETS mpc DESTINATION lib) +INSTALL(DIRECTORY include/ DESTINATION include FILES_MATCHING PATTERN "*.h") +INSTALL(DIRECTORY share/ DESTINATION share/mpc) -# GTest needed for testing +# ---------------------------------------------------------------------------- +# Testing using gTest +# ---------------------------------------------------------------------------- find_package(GTest) if (GTEST_FOUND) enable_testing() @@ -120,26 +116,31 @@ if (GTEST_FOUND) target_link_libraries(testBreakCondition mpc ${GTEST_BOTH_LIBRARIES} pthread) endif (GTEST_FOUND) -INCLUDE (Python.cmake) -include_directories(${PYTHON_INCLUDE_PATH}) -FILE(GLOB_RECURSE MPC_INCLUDES include/*.h) -#message("Includes: ${MPC_INCLUDES}") -#SET_SOURCE_FILES_PROPERTIES( ${CMAKE_CURRENT_BINARY_DIR}/genmodule.py PROPERTIES GENERATED true ) -#ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/genmodule.py -# COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/python/genbindings.py ${CMAKE_CURRENT_BINARY_DIR}/genmodule.py ${CMAKE_SOURCE_DIR}/include ${MPC_INCLUDES} -# DEPENDS ${CMAKE_SOURCE_DIR}/python/genbindings.py ${MPC_INCLUDES} ) +# ---------------------------------------------------------------------------- +# OpenMP and OpenMPI +# ---------------------------------------------------------------------------- +add_executable(openmp example/openmp.cpp) +TARGET_LINK_LIBRARIES(openmp mpc) + +# MPI needed for mpc-mpi +find_package(MPI) +if (MPI_FOUND) + include_directories(${MPI_INCLUDE_PATH}) + + set(CMAKE_CXX_COMPILE_FLAGS ${CMAKE_CXX_COMPILE_FLAGS} ${MPI_COMPILE_FLAGS}) + set(CMAKE_CXX_LINK_FLAGS ${CMAKE_CXX_LINK_FLAGS} ${MPI_LINK_FLAGS}) + + add_executable(mpc-mpi mpi/main mpi/Slave mpi/Master mpi/Job) + TARGET_LINK_LIBRARIES(mpc-mpi mpc ${MPI_LIBRARIES}) +endif() -#SET_SOURCE_FILES_PROPERTIES( ${CMAKE_CURRENT_BINARY_DIR}/mpc_python.cpp PROPERTIES GENERATED true ) -#ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mpc_python.cpp -# COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/genmodule.py > ${CMAKE_CURRENT_BINARY_DIR}/mpc_python.cpp -# DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/genmodule.py ) - -#add_library(mpc_python MODULE ${CMAKE_CURRENT_BINARY_DIR}/mpc_python.cpp) -#set_target_properties(mpc_python PROPERTIES PREFIX "") -#set_target_properties(mpc_python PROPERTIES OUTPUT_NAME "mpc") -#target_link_libraries(mpc_python libppropa ${PYTHON_LIBRARIES}) +# ---------------------------------------------------------------------------- +# Python +# ---------------------------------------------------------------------------- +INCLUDE (Python.cmake) +include_directories(${PYTHON_INCLUDE_PATH}) SET_SOURCE_FILES_PROPERTIES( ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx PROPERTIES GENERATED true ) ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx @@ -148,4 +149,6 @@ ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx add_library(mpc-swig MODULE ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx) set_target_properties(mpc-swig PROPERTIES PREFIX "") set_target_properties(mpc-swig PROPERTIES OUTPUT_NAME "_mpc") -target_link_libraries(mpc-swig mpc ${PYTHON_LIBRARIES}) \ No newline at end of file +target_link_libraries(mpc-swig mpc ${PYTHON_LIBRARIES}) +INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/mpc.py" DESTINATION ${PYTHON_SITE_PACKAGES}) +INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/_mpc.so" DESTINATION ${PYTHON_SITE_PACKAGES}) diff --git a/src/module/common.cpp b/src/module/common.cpp index 72886eda4..045d6fe84 100644 --- a/src/module/common.cpp +++ b/src/module/common.cpp @@ -1,15 +1,46 @@ #include "mpc/module/common.h" +#include "kiss/path.h" + #include +#include +#include namespace mpc { std::string getDataPath(std::string filename) { - std::string dataPath = "data"; - if (getenv("MPC_DATA_PATH")) - dataPath = getenv("MPC_DATA_PATH"); - dataPath += "/" + filename; - return dataPath; + static std::string dataPath; + if (dataPath.size()) + return dataPath; + + const char *env_path = getenv("MPC_DATA_PATH"); + if (env_path) { + if (is_directory(env_path)) { + dataPath = env_path; + return dataPath; + } + } + +#ifdef MPC_INSTALL_PREFIX + { + std::string _path = MPC_INSTALL_PREFIX "/share/mpc"; + if (is_directory(_path)) { + dataPath = _path; + return dataPath; + } + } +#endif + + { + std::string _path = executable_path() + "../data"; + if (is_directory(_path)) { + dataPath = _path; + return dataPath; + } + } + + return "data"; } } // namespace mpc + From 66a5ae0efe584fa1ebb0678f07425c7fa93919f7 Mon Sep 17 00:00:00 2001 From: geromueller Date: Mon, 19 Mar 2012 12:52:46 +0100 Subject: [PATCH 0002/1298] refactor output --- CMakeLists.txt | 1 + include/mpc/module/Output.h | 87 ++++------------------------ src/module/Output.cpp | 109 ++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 77 deletions(-) create mode 100644 src/module/Output.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a0865d7f..8d1a2f4f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,7 @@ add_library(mpc SHARED src/module/PhotoDisintegration.cpp src/module/NuclearDecay.cpp src/module/Redshift.cpp + src/module/Output.cpp src/magneticField/magneticFieldGrid.cpp ${MPC_EXTRA_SOURCES} ) diff --git a/include/mpc/module/Output.h b/include/mpc/module/Output.h index fcc714057..26b648b74 100644 --- a/include/mpc/module/Output.h +++ b/include/mpc/module/Output.h @@ -2,28 +2,10 @@ #define OUTPUT_H_ #include "mpc/Module.h" -#include -#include #include -#include namespace mpc { -std::string getOutputString(ParticleState particle) { - std::stringstream s; - s << particle.getId() << ", "; - s << particle.getEnergy() / EeV << ", "; - Vector3 pos = particle.getPosition() / Mpc; - s << pos.x() << ", "; - s << pos.y() << ", "; - s << pos.z() << ", "; - Vector3 dir = particle.getDirection(); - s << dir.x() << ", "; - s << dir.y() << ", "; - s << dir.z(); - return s.str(); -} - /** @class TrajectoryOutput @brief Saves trajectories to CSV file. @@ -33,24 +15,10 @@ class TrajectoryOutput: public Module { std::ofstream outfile; public: - TrajectoryOutput(std::string name) { - outfile.open(name.c_str()); - outfile - << "# Age, HepId, E, posX, posY, posZ, dirX, dirY, dirZ, event\n"; - } - - ~TrajectoryOutput() { - outfile.close(); - } - - void process(Candidate *candidate) { - outfile << candidate->getTrajectoryLength() / Mpc << ", " - << getOutputString(candidate->current) << "\n"; - } - - std::string getDescription() const { - return "Trajectory output"; - } + TrajectoryOutput(std::string name); + ~TrajectoryOutput(); + void process(Candidate *candidate); + std::string getDescription() const; }; /** @@ -63,33 +31,10 @@ class FlaggedOutput: public Module { Candidate::Status flag; public: - FlaggedOutput(std::string name, Candidate::Status flag) { - this->flag = flag; - outfile.open(name.c_str()); - outfile << "(initial) Age, Id, E, x, y, z, dirX, dirY, dirZ, "; - outfile << "(flagged) Age, Id, E, x, y, z, dirX, dirY, dirZ\n"; - } - - ~FlaggedOutput() { - outfile.close(); - } - - void process(Candidate *candidate) const { - if (candidate->getStatus() != flag) - return; - // initial state - outfile << "0, "; - outfile << getOutputString(candidate->initial); - outfile << ", "; - // final state - outfile << candidate->getTrajectoryLength() / Mpc << ", "; - outfile << getOutputString(candidate->current); - outfile << "\n"; - } - - std::string getDescription() const { - return "Output, flag: "; - } + FlaggedOutput(std::string name, Candidate::Status flag); + ~FlaggedOutput(); + void process(Candidate *candidate) const; + std::string getDescription() const; }; /** @@ -98,20 +43,8 @@ class FlaggedOutput: public Module { */ class ShellOutput: public Module { public: - void process(Candidate *candidate) const { - std::cout << std::fixed << std::showpoint << std::setprecision(2) - << std::setw(6); - std::cout << candidate->getTrajectoryLength() / Mpc << " Mpc, "; - std::cout << candidate->current.getId() << ", "; - std::cout << candidate->current.getEnergy() / EeV << " EeV, "; - std::cout << candidate->current.getPosition() / Mpc << " Mpc, Status: "; - std::cout << candidate->getStatus(); - std::cout << std::endl; - } - - std::string getDescription() const { - return "ShellOutput"; - } + void process(Candidate *candidate) const; + std::string getDescription() const; }; } // namespace mpc diff --git a/src/module/Output.cpp b/src/module/Output.cpp new file mode 100644 index 000000000..799c6417b --- /dev/null +++ b/src/module/Output.cpp @@ -0,0 +1,109 @@ +#include "mpc/module/Output.h" + +#include +#include +#include +#include +#include + +namespace mpc { + +std::string getOutputString(ParticleState particle) { + std::stringstream s; + s << particle.getId() << ", "; + s << particle.getEnergy() / EeV << ", "; + Vector3 pos = particle.getPosition() / Mpc; + s << pos.x() << ", "; + s << pos.y() << ", "; + s << pos.z() << ", "; + Vector3 dir = particle.getDirection(); + s << dir.x() << ", "; + s << dir.y() << ", "; + s << dir.z(); + return s.str(); +} + +TrajectoryOutput::TrajectoryOutput(std::string name) { + outfile.open(name.c_str()); + outfile << "# Age, HepId, E, posX, posY, posZ, dirX, dirY, dirZ, event\n"; +} + +TrajectoryOutput::~TrajectoryOutput() { + outfile.close(); +} + +void TrajectoryOutput::process(Candidate *candidate) { + outfile << candidate->getTrajectoryLength() / Mpc << ", " + << getOutputString(candidate->current) << "\n"; +} + +std::string TrajectoryOutput::getDescription() const { + return "Trajectory output"; +} + +FlaggedOutput::FlaggedOutput(std::string name, Candidate::Status flag) { + this->flag = flag; + outfile.open(name.c_str()); + outfile + << "id, x, y, z, E, phi, theta, distance, i_id, i_x, i_y, i_z, i_E, i_phi, i_theta\n"; +} + +FlaggedOutput::~FlaggedOutput() { + outfile.close(); +} + +void FlaggedOutput::process(Candidate *candidate) const { + if (candidate->getStatus() != flag) + return; + + outfile << candidate->current.getId() << ", "; + outfile << candidate->current.getPosition().x() << ", "; + outfile << candidate->current.getPosition().y() << ", "; + outfile << candidate->current.getPosition().z() << ", "; + outfile << candidate->current.getEnergy() << ", "; + outfile << candidate->current.getDirection().phi() << ", "; + outfile << candidate->current.getDirection().theta() << ", "; + outfile << candidate->getTrajectoryLength() << ", "; + outfile << candidate->initial.getId() << ", "; + outfile << candidate->initial.getPosition().x() << ", "; + outfile << candidate->initial.getPosition().y() << ", "; + outfile << candidate->initial.getPosition().z() << ", "; + outfile << candidate->initial.getEnergy() << ", "; + outfile << candidate->initial.getDirection().phi() << ", "; + outfile << candidate->initial.getDirection().theta() << ", "; + outfile << "\n"; +} + +std::string FlaggedOutput::getDescription() const { + switch (flag) { + case Candidate::Active: + return "FlaggedOutput, Active"; + case Candidate::Detected: + return "FlaggedOutput, Detected"; + case Candidate::OutOfBounds: + return "FlaggedOutput, OutOfBounds"; + case Candidate::Stopped: + return "FlaggedOutput, Stopped"; + case Candidate::UserDefined: + default: + return "FlaggedOutput, user defined (" + kiss::str(flag) + ")"; + } + +} + +void ShellOutput::process(Candidate *candidate) const { + std::cout << std::fixed << std::showpoint << std::setprecision(2) + << std::setw(6); + std::cout << candidate->getTrajectoryLength() / Mpc << " Mpc, "; + std::cout << candidate->current.getId() << ", "; + std::cout << candidate->current.getEnergy() / EeV << " EeV, "; + std::cout << candidate->current.getPosition() / Mpc << " Mpc, Status: "; + std::cout << candidate->getStatus(); + std::cout << std::endl; +} + +std::string ShellOutput::getDescription() const { + return "ShellOutput"; +} + +} // namespace mpc From cd7469e7faa5c54d65102d05a11fb2c4d390a5e8 Mon Sep 17 00:00:00 2001 From: geromueller Date: Mon, 19 Mar 2012 13:38:54 +0100 Subject: [PATCH 0003/1298] add ParticleState ctor --- include/mpc/ParticleState.h | 1 + src/ParticleState.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/mpc/ParticleState.h b/include/mpc/ParticleState.h index f9668edf4..489ac7f57 100644 --- a/include/mpc/ParticleState.h +++ b/include/mpc/ParticleState.h @@ -13,6 +13,7 @@ namespace mpc { */ class ParticleState { public: + ParticleState(); void setPosition(const Vector3 &pos); const Vector3 &getPosition() const; diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index 19feded6a..011dde3ec 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -2,6 +2,11 @@ namespace mpc { +ParticleState::ParticleState() : + id(0), energy(0) { + +} + void ParticleState::setPosition(const Vector3 &pos) { position = pos; } From 6790a9d1667d9340d6eb82afe4aa0b4c2ac2d4fe Mon Sep 17 00:00:00 2001 From: geromueller Date: Mon, 19 Mar 2012 13:43:54 +0100 Subject: [PATCH 0004/1298] fix getDataPath --- src/module/common.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/module/common.cpp b/src/module/common.cpp index 045d6fe84..3434f139c 100644 --- a/src/module/common.cpp +++ b/src/module/common.cpp @@ -1,6 +1,7 @@ #include "mpc/module/common.h" #include "kiss/path.h" +#include "kiss/logger.h" #include #include @@ -11,13 +12,16 @@ namespace mpc { std::string getDataPath(std::string filename) { static std::string dataPath; if (dataPath.size()) - return dataPath; + return concat_path(dataPath, filename); const char *env_path = getenv("MPC_DATA_PATH"); if (env_path) { if (is_directory(env_path)) { dataPath = env_path; - return dataPath; + KISS_LOG_INFO + << "getDataPath: use environment variable, " << dataPath + << std::endl; + return concat_path(dataPath, filename); } } @@ -26,7 +30,9 @@ std::string getDataPath(std::string filename) { std::string _path = MPC_INSTALL_PREFIX "/share/mpc"; if (is_directory(_path)) { dataPath = _path; - return dataPath; + KISS_LOG_INFO + << "getDataPath: use define, " << dataPath << std::endl; + return concat_path(dataPath, filename); } } #endif @@ -35,11 +41,17 @@ std::string getDataPath(std::string filename) { std::string _path = executable_path() + "../data"; if (is_directory(_path)) { dataPath = _path; - return dataPath; + KISS_LOG_INFO + << "getDataPath: use executable path, " << dataPath + << std::endl; + return concat_path(dataPath, filename); } } - return "data"; + dataPath = "data"; + KISS_LOG_INFO + << "getDataPath: use default, " << dataPath << std::endl; + return concat_path(dataPath, filename); } } // namespace mpc From 8aff11ba2c9e1b0caae7bcf93d2df992bc9150c1 Mon Sep 17 00:00:00 2001 From: geromueller Date: Mon, 19 Mar 2012 13:44:44 +0100 Subject: [PATCH 0005/1298] make Output OpenMP safe --- src/module/Output.cpp | 61 +++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 799c6417b..76d356ff0 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -33,8 +33,11 @@ TrajectoryOutput::~TrajectoryOutput() { } void TrajectoryOutput::process(Candidate *candidate) { - outfile << candidate->getTrajectoryLength() / Mpc << ", " - << getOutputString(candidate->current) << "\n"; +#pragma omp critical + { + outfile << candidate->getTrajectoryLength() / Mpc << ", " + << getOutputString(candidate->current) << "\n"; + } } std::string TrajectoryOutput::getDescription() const { @@ -56,22 +59,25 @@ void FlaggedOutput::process(Candidate *candidate) const { if (candidate->getStatus() != flag) return; - outfile << candidate->current.getId() << ", "; - outfile << candidate->current.getPosition().x() << ", "; - outfile << candidate->current.getPosition().y() << ", "; - outfile << candidate->current.getPosition().z() << ", "; - outfile << candidate->current.getEnergy() << ", "; - outfile << candidate->current.getDirection().phi() << ", "; - outfile << candidate->current.getDirection().theta() << ", "; - outfile << candidate->getTrajectoryLength() << ", "; - outfile << candidate->initial.getId() << ", "; - outfile << candidate->initial.getPosition().x() << ", "; - outfile << candidate->initial.getPosition().y() << ", "; - outfile << candidate->initial.getPosition().z() << ", "; - outfile << candidate->initial.getEnergy() << ", "; - outfile << candidate->initial.getDirection().phi() << ", "; - outfile << candidate->initial.getDirection().theta() << ", "; - outfile << "\n"; +#pragma omp critical + { + outfile << candidate->current.getId() << ", "; + outfile << candidate->current.getPosition().x() / Mpc << ", "; + outfile << candidate->current.getPosition().y() / Mpc << ", "; + outfile << candidate->current.getPosition().z() / Mpc << ", "; + outfile << candidate->current.getEnergy() / EeV << ", "; + outfile << candidate->current.getDirection().phi() << ", "; + outfile << candidate->current.getDirection().theta() << ", "; + outfile << candidate->getTrajectoryLength() / Mpc << ", "; + outfile << candidate->initial.getId() << ", "; + outfile << candidate->initial.getPosition().x() / Mpc << ", "; + outfile << candidate->initial.getPosition().y() / Mpc << ", "; + outfile << candidate->initial.getPosition().z() / Mpc << ", "; + outfile << candidate->initial.getEnergy() / EeV << ", "; + outfile << candidate->initial.getDirection().phi() << ", "; + outfile << candidate->initial.getDirection().theta(); + outfile << std::endl; + } } std::string FlaggedOutput::getDescription() const { @@ -92,14 +98,17 @@ std::string FlaggedOutput::getDescription() const { } void ShellOutput::process(Candidate *candidate) const { - std::cout << std::fixed << std::showpoint << std::setprecision(2) - << std::setw(6); - std::cout << candidate->getTrajectoryLength() / Mpc << " Mpc, "; - std::cout << candidate->current.getId() << ", "; - std::cout << candidate->current.getEnergy() / EeV << " EeV, "; - std::cout << candidate->current.getPosition() / Mpc << " Mpc, Status: "; - std::cout << candidate->getStatus(); - std::cout << std::endl; +#pragma omp critical + { + std::cout << std::fixed << std::showpoint << std::setprecision(2) + << std::setw(6); + std::cout << candidate->getTrajectoryLength() / Mpc << " Mpc, "; + std::cout << candidate->current.getId() << ", "; + std::cout << candidate->current.getEnergy() / EeV << " EeV, "; + std::cout << candidate->current.getPosition() / Mpc << " Mpc, Status: "; + std::cout << candidate->getStatus(); + std::cout << std::endl; + } } std::string ShellOutput::getDescription() const { From b70a5cb5ec5524d1bc3cd568c8d8e4c0b1bb13a2 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 21 Mar 2012 14:15:15 +0100 Subject: [PATCH 0006/1298] change test plot naming scheme add PhotoDisintegration multiplicity plot --- test/python/testDeflectionCK.py | 8 ++-- test/python/testElectronPairProduction.py | 10 ++--- .../{testDecay.py => testNuclearDecay.py} | 6 +-- test/python/testPhotoDisintegration.py | 41 +++++++++++++++---- test/python/testTurbulentField.py | 8 ++-- 5 files changed, 49 insertions(+), 24 deletions(-) rename test/python/{testDecay.py => testNuclearDecay.py} (94%) diff --git a/test/python/testDeflectionCK.py b/test/python/testDeflectionCK.py index d201c737a..8e95ad9f5 100644 --- a/test/python/testDeflectionCK.py +++ b/test/python/testDeflectionCK.py @@ -59,7 +59,7 @@ def propagate(tolerance): xlabel(r'$x / R_L$') ylabel(r'$y / R_L$') grid() -savefig('deflection_xtrajectory', bbox_inches='tight') +savefig('DeflectionCK_xtrajectory', bbox_inches='tight') ### Plot trajectory in p-space with 1e-4 tolerance @@ -74,7 +74,7 @@ def propagate(tolerance): xlabel(r'$p_x / |p_x|$') ylabel(r'$p_y / |p_y|$') grid() -savefig('deflection_ptrajectory', bbox_inches='tight') +savefig('DeflectionCK_ptrajectory', bbox_inches='tight') ### Directional error as function of distance for different tolerances @@ -87,7 +87,7 @@ def propagate(tolerance): ylabel(r'Directional Error [$^\circ$]') xlim(0,1) grid() -savefig('deflection_pdeviation.png',bbox_inches='tight') +savefig('DeflectionCK_pdeviation.png',bbox_inches='tight') ### Positional error as function of distance for different tolerances @@ -101,6 +101,6 @@ def propagate(tolerance): ylabel(r'Positional Error / $R_L$') xlim(0,1) grid() -savefig('deflection_xdeviation.png',bbox_inches='tight') +savefig('DeflectionCK_xdeviation.png',bbox_inches='tight') diff --git a/test/python/testElectronPairProduction.py b/test/python/testElectronPairProduction.py index 8d85e02be..a02209b8c 100644 --- a/test/python/testElectronPairProduction.py +++ b/test/python/testElectronPairProduction.py @@ -24,8 +24,8 @@ def compare(dataFileName, photonField, plotFileName): plot(E, dE,'k+', label='simulated', linewidth=2, markeredgewidth=2) - xlabel('proton energy [eV]') - ylabel('energy loss rate [eV / Mpc]') + xlabel('Energy [eV]') + ylabel('Energy Loss Rate [eV / Mpc]') legend(loc='lower right') grid() loglog() @@ -33,6 +33,6 @@ def compare(dataFileName, photonField, plotFileName): savefig(plotFileName, bbox_inches='tight') -compare(getDataPath("/ElectronPairProduction/cmb.txt"), ElectronPairProduction.CMB, 'epair_cmb.png') -compare(getDataPath("/ElectronPairProduction/cmbir.txt"), ElectronPairProduction.CMBIR, 'epair_cmbir.png') -compare(getDataPath("/ElectronPairProduction/ir.txt"), ElectronPairProduction.IR, 'epair_ir.png') \ No newline at end of file +compare(getDataPath("/ElectronPairProduction/cmb.txt"), ElectronPairProduction.CMB, 'ElectronPairProduction_cmb.png') +compare(getDataPath("/ElectronPairProduction/cmbir.txt"), ElectronPairProduction.CMBIR, 'ElectronPairProduction_cmbir.png') +compare(getDataPath("/ElectronPairProduction/ir.txt"), ElectronPairProduction.IR, 'ElectronPairProduction_ir.png') \ No newline at end of file diff --git a/test/python/testDecay.py b/test/python/testNuclearDecay.py similarity index 94% rename from test/python/testDecay.py rename to test/python/testNuclearDecay.py index a96eee920..616a4e565 100644 --- a/test/python/testDecay.py +++ b/test/python/testNuclearDecay.py @@ -49,7 +49,7 @@ ax.text(0.56, 0.44, 'beta- decay', ha='center', va='center', rotation=40, transform=ax.transAxes) ax.text(0.78, 0.22, 'neutron dripping', ha='center', va='center', rotation=40, transform=ax.transAxes) ax.text(0.2, 0.8, 'proton dripping', ha='center', va='center', rotation=40, transform=ax.transAxes) -fig.savefig('decay_mode.png',bbox_inches='tight') +fig.savefig('NuclearDecay_mode.png',bbox_inches='tight') fig = figure() ax = fig.add_subplot(111) @@ -61,7 +61,7 @@ ax.set_xlabel('neutrons') ax.set_ylabel('protons') ax.grid() -fig.savefig('decay_lifetime.png',bbox_inches='tight') +fig.savefig('NuclearDecay_lifetime.png',bbox_inches='tight') fig = figure() ax = fig.add_subplot(111) @@ -72,7 +72,7 @@ ax.set_xlabel('neutrons') ax.set_ylabel('protons') ax.grid() -fig.savefig('decay_multiplicity.png',bbox_inches='tight') +fig.savefig('NuclearDecay_multiplicity.png',bbox_inches='tight') diff --git a/test/python/testPhotoDisintegration.py b/test/python/testPhotoDisintegration.py index 04d9329f5..e462249f8 100644 --- a/test/python/testPhotoDisintegration.py +++ b/test/python/testPhotoDisintegration.py @@ -5,7 +5,7 @@ gamma = logspace(6, 14, 200) -def get_rates(interaction, id, gamma, count=100000): +def get_rates(interaction, id, gamma, count=10000): D = {} c = Candidate() c.current.setId(id) @@ -57,23 +57,26 @@ def plot_channel(rates_simulated, rates_data, id, channel): if channel in rates_simulated: plot(gamma, rates_simulated[channel], 'k+', label="Simulated") legend(loc='lower right') - text(0.1, 0.85, 'Nucleus '+parse_id(id)+'\nDecay Channel '+parse_channel(channel), transform=gca().transAxes) + text(0.1, 0.85, 'Nucleus ' + parse_id(id) + '\nDecay Channel ' + parse_channel(channel), transform=gca().transAxes) xlabel('Lorentzfactor $\gamma$') ylabel('Rate [1/Mpc]') loglog() - ylim(1e-10,1e2) + ylim(1e-10, 1e2) grid() savefig('PhotoDisintegration_' + str(id) + '_' + str(channel) + '.png', bbox_inches='tight') +def get_id(a, z): + return 1e9 + a * 1e6 + z * 1e3 + def parse_id(id): z = ((id - 1000000000) % 1000000) // 1000 a = (id - 1000000000) // 1000000 - return 'Z=%i, A=%i'%(z,a) + return 'Z=%i, A=%i' % (z, a) def parse_channel(c): - s = '%06d'%c + s = '%06d' % c d = list(map(int, s)) - s = 'n, '*d[0] + 'p, '*d[1] + 'H$^2$, '*d[2] + 'H$^3$, '*d[3] + 'He$^3$, '*d[4] + 'He$^4$, '*d[5] + s = 'n, ' * d[0] + 'p, ' * d[1] + 'H$^2$, ' * d[2] + 'H$^3$, ' * d[3] + 'He$^3$, ' * d[4] + 'He$^4$, ' * d[5] return s[0:-2] interaction = PhotoDisintegration() @@ -81,12 +84,34 @@ def parse_channel(c): id = 1004002000 if len(sys.argv) >= 3: - id = 1000000000 + int(sys.argv[1]) * 1000000 + int(sys.argv[2]) * 1000 + a = int(sys.argv[1]) + z = int(sys.argv[2]) + id = get_id(a, z) -print id +print 'Plotting Disintegration Rates for', id rates_simulated = get_rates_per_channel(interaction, id) rates_data = get_data_rates_per_channel(table, id) channels = set.union(set(rates_simulated.keys()), set(rates_data.keys())) for channel in channels: plot_channel(rates_simulated, rates_data, id, channel) +# plot channel multiplicity +print 'Plotting Channel Multiplicity' +multi = zeros((27, 31)) +for z in range(1, 27): + for n in range(1, 31): + multi[z][n] = len(get_data_rates_per_channel(table, get_id(z + n, z))) + +fig = figure() +ax = fig.add_subplot(111) +mmulti = ma.masked_array(multi, multi==0) +im = ax.imshow(mmulti, aspect='equal', interpolation='nearest', origin='lower') +cbar = fig.colorbar(im, orientation='horizontal') +cbar.set_label('Photo-Disintegration Channels') +ax.set_xlabel('Neutrons') +ax.set_ylabel('Protons') +ax.grid() +fig.savefig('PhotoDisintegration_multiplicity.png',bbox_inches='tight') + + + diff --git a/test/python/testTurbulentField.py b/test/python/testTurbulentField.py index 1e81390db..c8de6d44c 100644 --- a/test/python/testTurbulentField.py +++ b/test/python/testTurbulentField.py @@ -172,7 +172,7 @@ def retrieveField(field): ylim(0,3*n) xlabel(r'$x$ [gridpoints]') ylabel(r'$y$ [gridpoints]') -savefig('turbulentField_periodicity.png', bbox_inches='tight') +savefig('TurbulentField_periodicity.png', bbox_inches='tight') ### correlation length + isotropy figure() @@ -197,13 +197,13 @@ def retrieveField(field): grid() s = 'Correlation Length\n Nominal %.2f\n Simulated %.2f $\pm$ %.2f'%(field.getCorrelationLength(), mean(Lc), std(Lc)/(len(Lc))**.5) text(0.5, 0.95, s, ha='left', va='top', transform=gca().transAxes) -savefig('turbulentField_correlation.png', bbox_inches='tight') +savefig('TurbulentField_correlation.png', bbox_inches='tight') ### energy spectrum esd = VectorFieldEnergySpectralDensity(Bx, By, Bz) figure() esd.plot() -savefig('turbulentField_spectrum.png', bbox_inches='tight') +savefig('TurbulentField_spectrum.png', bbox_inches='tight') ### field strength, mean and brms Bx.resize(n**3) @@ -219,4 +219,4 @@ def retrieveField(field): ylabel('Frequency') Brms = (mean( Bx**2 + By**2 + Bz**2 ))**.5 text(1.45, 0.5, '$B_{RMS}$ = %.2f'%(Brms)) -savefig('turbulentField_amplitude.png', bbox_inches='tight') +savefig('TurbulentField_amplitude.png', bbox_inches='tight') From 51ec4e0a9be70dde59ddaaeebca75d605b942208 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 21 Mar 2012 19:32:36 +0100 Subject: [PATCH 0007/1298] fix Output --- include/mpc/module/Output.h | 4 ++-- src/module/Output.cpp | 29 +++++++++++------------------ 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/include/mpc/module/Output.h b/include/mpc/module/Output.h index 26b648b74..7884803d5 100644 --- a/include/mpc/module/Output.h +++ b/include/mpc/module/Output.h @@ -12,12 +12,12 @@ namespace mpc { */ class TrajectoryOutput: public Module { private: - std::ofstream outfile; + mutable std::ofstream outfile; public: TrajectoryOutput(std::string name); ~TrajectoryOutput(); - void process(Candidate *candidate); + void process(Candidate *candidate) const; std::string getDescription() const; }; diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 76d356ff0..5c7b129fe 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -8,21 +8,6 @@ namespace mpc { -std::string getOutputString(ParticleState particle) { - std::stringstream s; - s << particle.getId() << ", "; - s << particle.getEnergy() / EeV << ", "; - Vector3 pos = particle.getPosition() / Mpc; - s << pos.x() << ", "; - s << pos.y() << ", "; - s << pos.z() << ", "; - Vector3 dir = particle.getDirection(); - s << dir.x() << ", "; - s << dir.y() << ", "; - s << dir.z(); - return s.str(); -} - TrajectoryOutput::TrajectoryOutput(std::string name) { outfile.open(name.c_str()); outfile << "# Age, HepId, E, posX, posY, posZ, dirX, dirY, dirZ, event\n"; @@ -32,11 +17,19 @@ TrajectoryOutput::~TrajectoryOutput() { outfile.close(); } -void TrajectoryOutput::process(Candidate *candidate) { +void TrajectoryOutput::process(Candidate *candidate) const { #pragma omp critical { - outfile << candidate->getTrajectoryLength() / Mpc << ", " - << getOutputString(candidate->current) << "\n"; + outfile << candidate->getTrajectoryLength() / Mpc << ", "; + outfile << candidate->current.getId() << ", "; + outfile << candidate->current.getEnergy() / EeV << ", "; + outfile << candidate->current.getPosition().x() / Mpc << ", "; + outfile << candidate->current.getPosition().y() / Mpc << ", "; + outfile << candidate->current.getPosition().z() / Mpc << ", "; + outfile << candidate->current.getDirection().x() << ", "; + outfile << candidate->current.getDirection().y() << ", "; + outfile << candidate->current.getDirection().y() << ", "; + outfile << std::endl; } } From f22e734f2a924c5f94a5b6f694f097b4d383f32c Mon Sep 17 00:00:00 2001 From: geromueller Date: Thu, 22 Mar 2012 10:53:55 +0100 Subject: [PATCH 0008/1298] add Source, add ModuleList run with source and OpenMP --- CMakeLists.txt | 5 ++++- include/mpc/ModuleList.h | 2 ++ include/mpc/Source.h | 34 ++++++++++++++++++++++++++++++++++ python/mpc.i | 12 ++++++++++-- src/ModuleList.cpp | 11 ++++++++++- src/Source.cpp | 22 ++++++++++++++++++++++ 6 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 include/mpc/Source.h create mode 100644 src/Source.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d1a2f4f2..41c612e00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}" ${CMAKE_MODULE_PATH}) set (MPC_EXTRA_SOURCES) set (MPC_EXTRA_INCLUDES) set (MPC_EXTRA_LIBRARIES) +set (MPC_SWIG_DEFINES) # GSL required find_package(GSL REQUIRED) @@ -25,6 +26,7 @@ if (GADGET_FOUND) list( APPEND MPC_EXTRA_INCLUDES ${GADGET_INCLUDE_DIR}) list( APPEND MPC_EXTRA_LIBRARIES ${GADGET_LIBRARY}) add_definitions(-DMPC_HAVE_GADGET) + list( APPEND MPC_SWIG_DEFINES -DMPC_HAVE_GADGET) endif (GADGET_FOUND) # freeglut and GLU needed for GlutDisplay @@ -71,6 +73,7 @@ add_library(mpc SHARED src/Candidate.cpp src/IO.cpp src/ParticleState.cpp + src/Source.cpp src/module/common.cpp src/module/SimplePropagation.cpp src/module/DeflectionCK.cpp @@ -145,7 +148,7 @@ include_directories(${PYTHON_INCLUDE_PATH}) SET_SOURCE_FILES_PROPERTIES( ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx PROPERTIES GENERATED true ) ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx - COMMAND swig -c++ -python -I${CMAKE_SOURCE_DIR}/include -o ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx -outdir ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/python/mpc.i + COMMAND swig -c++ -python ${MPC_SWIG_DEFINES} -I${CMAKE_SOURCE_DIR}/include -o ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx -outdir ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/python/mpc.i DEPENDS ${CMAKE_SOURCE_DIR}/python/mpc.i ${MPC_INCLUDES} ) add_library(mpc-swig MODULE ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx) set_target_properties(mpc-swig PROPERTIES PREFIX "") diff --git a/include/mpc/ModuleList.h b/include/mpc/ModuleList.h index 84e9bf846..e5abb8237 100644 --- a/include/mpc/ModuleList.h +++ b/include/mpc/ModuleList.h @@ -5,6 +5,7 @@ #include "mpc/Candidate.h" #include "mpc/Module.h" +#include "mpc/Source.h" namespace mpc { @@ -19,6 +20,7 @@ class ModuleList: public std::list > { void process(Candidate *candidate); void run(Candidate *candidate, bool recursive); + void run(Source *source, size_t count, bool recursive); }; } // namespace mpc diff --git a/include/mpc/Source.h b/include/mpc/Source.h new file mode 100644 index 000000000..3beaa1aa3 --- /dev/null +++ b/include/mpc/Source.h @@ -0,0 +1,34 @@ +#ifndef MPC_SOURCE_H +#define MPC_SOURCE_H + +#include "mpc/ParticleState.h" +#include "mpc/Referenced.h" + +#include + +namespace mpc { + +class Source: public Referenced { +public: + virtual ~Source() { + } + + virtual void prepare(ParticleState &state) const = 0; +}; + +class BasicSource: public Source { +public: + Vector3 position; + double index1, index2, breakpoint, Emin, Emax; + int id; + + BasicSource(const Vector3 &sposition, int type, double Emin = 5 * EeV, + double Emax = 1000 * EeV, double index1 = -1, double index2 = -1, + double breakpoint = 1); + + virtual void prepare(ParticleState &state) const; +}; + +} // namespace mpc + +#endif /* MPC_SOURCE_H */ diff --git a/python/mpc.i b/python/mpc.i index b98ad98b3..5ffe83021 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -8,6 +8,7 @@ %include std_multimap.i %include std_vector.i %include std_string.i +%include std_list.i %include stdint.i %include std_container.i @@ -33,12 +34,14 @@ #include "mpc/ParticleState.h" #include "mpc/Module.h" #include "mpc/ModuleChain.h" +#include "mpc/ModuleList.h" #include "mpc/PhasePoint.h" #include "mpc/ExplicitRungeKutta.h" #include "mpc/HepPID.h" #include "mpc/Random.h" #include "mpc/Units.h" #include "mpc/Vector3.h" +#include "mpc/Source.h" #include "mpc/Referenced.h" #include "mpc/module/common.h" %} @@ -52,16 +55,20 @@ %include "mpc/Vector3.h" %include "mpc/Random.h" %include "mpc/ParticleState.h" +%feature("director") mpc::Source; +%include "mpc/Source.h" %include "mpc/module/common.h" %template(CandidateVector) std::vector< mpc::ref_ptr >; %template(CandidateRefPtr) mpc::ref_ptr; %include "mpc/Candidate.h" -%template(ModuleVector) std::vector< mpc::ref_ptr >; %template(ModuleRefPtr) mpc::ref_ptr; +%template(stdModuleVector) std::vector< mpc::ref_ptr >; +%template(stdModuleList) std::list< mpc::ref_ptr >; +%feature("director") mpc::Module; %include "mpc/Module.h" -%template(MagneticFieldVector) std::vector< mpc::ref_ptr >; +%template(stdMagneticFieldVector) std::vector< mpc::ref_ptr >; %template(MagneticFieldRefPtr) mpc::ref_ptr; %include "mpc/magneticField/magneticField.h" %include "mpc/magneticField/magneticFieldGrid.h" @@ -85,3 +92,4 @@ %include "mpc/ModuleChain.h" +%include "mpc/ModuleList.h" diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 9e4d47012..9de967ae3 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -20,13 +20,22 @@ void ModuleList::run(Candidate *candidate, bool recursive) { // propagate secondaries if (recursive) { -#pragma omp parallel for for (size_t i = 0; i < candidate->secondaries.size(); i++) run(candidate->secondaries[i], recursive); } } +void ModuleList::run(Source *source, size_t count, bool recursive) { +#pragma omp parallel for schedule(dynamic, 1000) + for (size_t i = 0; i < count; i++) { + ParticleState state; + source->prepare(state); + ref_ptr candidate = new Candidate(state); + run(candidate, recursive); + } +} + } // namespace mpc std::ostream &operator<<(std::ostream &out, diff --git a/src/Source.cpp b/src/Source.cpp new file mode 100644 index 000000000..a61aca31c --- /dev/null +++ b/src/Source.cpp @@ -0,0 +1,22 @@ +#include "mpc/Source.h" + +#include "mpc/Random.h" + +namespace mpc { + +BasicSource::BasicSource(const Vector3 &sposition, int type, double Emin, + double Emax, double index1, double index2, double breakpoint) : + position(position), id(id), index1(index1), index2(index2), breakpoint( + breakpoint), Emin(Emin), Emax(Emax) { +} + +void BasicSource::prepare(ParticleState &state) const { + state.setPosition(position); + state.setId(id); + state.setEnergy( + Random::instance().randBrokenPowerLaw(index1, index2, breakpoint, + Emin, Emax)); + state.setDirection(Random::instance().randUnitVectorOnSphere()); +} + +} // namespace mpc From e6aca362784f52446701b40fd4239948ce654f14 Mon Sep 17 00:00:00 2001 From: geromueller Date: Thu, 22 Mar 2012 11:50:30 +0100 Subject: [PATCH 0009/1298] change ModuleList --- example/openmp.cpp | 14 +++++++------- include/mpc/ModuleList.h | 10 +++++++--- python/mpc.i | 5 +++-- src/ModuleList.cpp | 21 ++++++++++++++------- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/example/openmp.cpp b/example/openmp.cpp index 0b4818d24..d3bab37a1 100644 --- a/example/openmp.cpp +++ b/example/openmp.cpp @@ -19,13 +19,13 @@ int main(int argc, char **argv) { Vector3(0, 0, 0), 64, 1., 2., 8., 1e-12, -11. / 3.); ModuleList modules; - modules.push_back(new DeflectionCK(field)); - modules.push_back(new NuclearDecay()); - modules.push_back(new PhotoDisintegration()); - modules.push_back(new ElectronPairProduction(ElectronPairProduction::CMB)); - modules.push_back(new PhotoPionProduction(PhotoPionProduction::CMBIR)); - modules.push_back(new MaximumTrajectoryLength(50 * Mpc)); - modules.push_back(new MinimumEnergy(5 * EeV)); + modules.add(new DeflectionCK(field)); + modules.add(new NuclearDecay()); + modules.add(new PhotoDisintegration()); + modules.add(new ElectronPairProduction(ElectronPairProduction::CMB)); + modules.add(new PhotoPionProduction(PhotoPionProduction::CMBIR)); + modules.add(new MaximumTrajectoryLength(50 * Mpc)); + modules.add(new MinimumEnergy(5 * EeV)); //modules.push_back(new ShellOutput); cout << modules << endl; diff --git a/include/mpc/ModuleList.h b/include/mpc/ModuleList.h index e5abb8237..2100ece9b 100644 --- a/include/mpc/ModuleList.h +++ b/include/mpc/ModuleList.h @@ -13,19 +13,23 @@ namespace mpc { @class ModuleList @brief List of modules */ -class ModuleList: public std::list > { +class ModuleList { + std::list > modules; + public: typedef std::list >::iterator iterator; typedef std::list >::const_iterator const_iterator; + void add(Module *module); void process(Candidate *candidate); void run(Candidate *candidate, bool recursive); void run(Source *source, size_t count, bool recursive); + + const std::list > &getModules() const; }; } // namespace mpc -std::ostream &operator<<(std::ostream &out, - const std::list > &chain); +std::ostream &operator<<(std::ostream &out, const mpc::ModuleList &list); #endif /* MPC_MODULE_LIST_H_ */ diff --git a/python/mpc.i b/python/mpc.i index 5ffe83021..9c5e735c3 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -1,4 +1,4 @@ -%module mpc +%module(directors="1") mpc %include stl.i %include std_set.i @@ -45,7 +45,7 @@ #include "mpc/Referenced.h" #include "mpc/module/common.h" %} - + /* Parse the header file to generate wrappers */ %feature("ref") mpc::Referenced "$this->addReference();" %feature("unref") mpc::Referenced "$this->removeReference();" @@ -58,6 +58,7 @@ %feature("director") mpc::Source; %include "mpc/Source.h" %include "mpc/module/common.h" + %template(CandidateVector) std::vector< mpc::ref_ptr >; %template(CandidateRefPtr) mpc::ref_ptr; %include "mpc/Candidate.h" diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 9de967ae3..4f92c86d0 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -4,9 +4,13 @@ using namespace std; namespace mpc { +void ModuleList::add(Module *module) { + modules.push_back(module); +} + void ModuleList::process(Candidate *candidate) { - iterator iEntry = begin(); - while (iEntry != end()) { + iterator iEntry = modules.begin(); + while (iEntry != modules.end()) { ref_ptr &module = *iEntry; iEntry++; module->process(candidate); @@ -36,14 +40,17 @@ void ModuleList::run(Source *source, size_t count, bool recursive) { } } +const std::list > &ModuleList::getModules() const { + return modules; +} + } // namespace mpc -std::ostream &operator<<(std::ostream &out, - const std::list > &modules) { - std::list >::const_iterator iEntry; +std::ostream &operator<<(std::ostream &out, const mpc::ModuleList &list) { + mpc::ModuleList::const_iterator iEntry; - iEntry = modules.begin(); - while (iEntry != modules.end()) { + iEntry = list.getModules().begin(); + while (iEntry != list.getModules().end()) { const mpc::ref_ptr &entry = *iEntry; iEntry++; out << " " << entry->getDescription() << "\n"; From 4e2e3dc5cdd9f395284e36f8848d4e2624eb4908 Mon Sep 17 00:00:00 2001 From: geromueller Date: Thu, 22 Mar 2012 12:44:55 +0100 Subject: [PATCH 0010/1298] fix installation --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 41c612e00..bf596b16c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,7 +95,7 @@ TARGET_LINK_LIBRARIES(mpc-run mpc) INSTALL(TARGETS mpc-run RUNTIME DESTINATION bin) INSTALL(TARGETS mpc DESTINATION lib) INSTALL(DIRECTORY include/ DESTINATION include FILES_MATCHING PATTERN "*.h") -INSTALL(DIRECTORY share/ DESTINATION share/mpc) +INSTALL(DIRECTORY data/ DESTINATION share/mpc) # ---------------------------------------------------------------------------- # Testing using gTest From c815736d02d8ebba0343e9575bcb2924e4513153 Mon Sep 17 00:00:00 2001 From: geromueller Date: Fri, 23 Mar 2012 17:07:54 +0100 Subject: [PATCH 0011/1298] add show progress to module list --- include/mpc/ModuleList.h | 5 ++++- src/ModuleList.cpp | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/include/mpc/ModuleList.h b/include/mpc/ModuleList.h index 2100ece9b..85885c17b 100644 --- a/include/mpc/ModuleList.h +++ b/include/mpc/ModuleList.h @@ -15,11 +15,14 @@ namespace mpc { */ class ModuleList { std::list > modules; - + bool showProgress; public: typedef std::list >::iterator iterator; typedef std::list >::const_iterator const_iterator; + ModuleList(); + void setShowProgress(bool show); + void add(Module *module); void process(Candidate *candidate); void run(Candidate *candidate, bool recursive); diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 4f92c86d0..96f0581f4 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -4,6 +4,15 @@ using namespace std; namespace mpc { +ModuleList::ModuleList() : + showProgress(false) { + +} + +void ModuleList::setShowProgress(bool show) { + showProgress = show; +} + void ModuleList::add(Module *module) { modules.push_back(module); } @@ -31,8 +40,14 @@ void ModuleList::run(Candidate *candidate, bool recursive) { } void ModuleList::run(Source *source, size_t count, bool recursive) { + size_t cent = count / 100; + size_t pc = 0; #pragma omp parallel for schedule(dynamic, 1000) for (size_t i = 0; i < count; i++) { + if (showProgress && (i % cent == 0)) { + std::cout << pc << "% - " << i << std::endl; + pc++; + } ParticleState state; source->prepare(state); ref_ptr candidate = new Candidate(state); From 1b20e4cedbb9c07362d359290a50c434713ab99b Mon Sep 17 00:00:00 2001 From: geromueller Date: Fri, 23 Mar 2012 17:09:03 +0100 Subject: [PATCH 0012/1298] add default ctor to BasicSource --- include/mpc/Source.h | 2 +- src/Source.cpp | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/mpc/Source.h b/include/mpc/Source.h index 3beaa1aa3..f5afc2411 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -21,7 +21,7 @@ class BasicSource: public Source { Vector3 position; double index1, index2, breakpoint, Emin, Emax; int id; - + BasicSource(); BasicSource(const Vector3 &sposition, int type, double Emin = 5 * EeV, double Emax = 1000 * EeV, double index1 = -1, double index2 = -1, double breakpoint = 1); diff --git a/src/Source.cpp b/src/Source.cpp index a61aca31c..1775086b2 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -4,6 +4,12 @@ namespace mpc { +BasicSource::BasicSource() : + position(Vector3(0, 0, 0)), id(0), index1(-1), index2(-1), breakpoint( + 10 * EeV), Emin(5 * EeV), Emax(1000 * EeV) { + +} + BasicSource::BasicSource(const Vector3 &sposition, int type, double Emin, double Emax, double index1, double index2, double breakpoint) : position(position), id(id), index1(index1), index2(index2), breakpoint( @@ -11,11 +17,12 @@ BasicSource::BasicSource(const Vector3 &sposition, int type, double Emin, } void BasicSource::prepare(ParticleState &state) const { + state.setPosition(position); state.setId(id); - state.setEnergy( - Random::instance().randBrokenPowerLaw(index1, index2, breakpoint, - Emin, Emax)); + double E = Random::instance().randBrokenPowerLaw(index1, index2, breakpoint, + Emin, Emax); + state.setEnergy(E); state.setDirection(Random::instance().randUnitVectorOnSphere()); } From 98e570e256a52e461e7aaffa5f82d1da739fd3e1 Mon Sep 17 00:00:00 2001 From: geromueller Date: Fri, 23 Mar 2012 17:19:09 +0100 Subject: [PATCH 0013/1298] add google performance tools option to cmake --- CMakeLists.txt | 12 ++++++--- FindGadget.cmake | 10 +++++--- FindGooglePerfTools.cmake | 52 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 FindGooglePerfTools.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index bf596b16c..20839a2a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,13 @@ if (Freeglut_FOUND) endif (OPENGL_GLU_FOUND) endif (Freeglut_FOUND) +# Google Performance Tools +find_package(GooglePerfTools) +SET(TCMALLOC) +IF (GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) + SET(TCMALLOC ${TCMALLOC_LIBRARY}) +endif(GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) + # pugixml provided add_library (pugixml libs/pugixml/pugixml.cpp) SET_TARGET_PROPERTIES( pugixml PROPERTIES COMPILE_FLAGS -fPIC) @@ -86,11 +93,10 @@ add_library(mpc SHARED src/magneticField/magneticFieldGrid.cpp ${MPC_EXTRA_SOURCES} ) -TARGET_LINK_LIBRARIES(mpc ${MPC_EXTRA_LIBRARIES}) +TARGET_LINK_LIBRARIES(mpc ${MPC_EXTRA_LIBRARIES} ${TCMALLOC}) add_executable(mpc-run src/main.cpp) -TARGET_LINK_LIBRARIES(mpc-run mpc) - +TARGET_LINK_LIBRARIES(mpc-run mpc ${TCMALLOC}) INSTALL(TARGETS mpc-run RUNTIME DESTINATION bin) INSTALL(TARGETS mpc DESTINATION lib) diff --git a/FindGadget.cmake b/FindGadget.cmake index 2e5513cff..e2273a7c6 100644 --- a/FindGadget.cmake +++ b/FindGadget.cmake @@ -9,11 +9,13 @@ set(GADGET_FOUND FALSE) if(GADGET_INCLUDE_DIR AND GADGET_LIBRARY) set(GADGET_FOUND TRUE) MESSAGE(STATUS "Found Gadget") + MESSAGE(STATUS " Include: ${GADGET_INCLUDE_DIR}") + MESSAGE(STATUS " Library: ${GADGET_LIBRARY}") else() - MESSAGE(STATUS "Gadget NOT found") + IF (GADGET_FIND_REQUIRED) + MESSAGE(STATUS "Gadget NOT found") + ENDIF (GADGET_FIND_REQUIRED) + endif() -MESSAGE(STATUS " Include: ${GADGET_INCLUDE_DIR}") -MESSAGE(STATUS " Library: ${GADGET_LIBRARY}") - mark_as_advanced(GADGET_INCLUDE_DIR GADGET_LIBRARY GADGET_FOUND) diff --git a/FindGooglePerfTools.cmake b/FindGooglePerfTools.cmake new file mode 100644 index 000000000..09d7526db --- /dev/null +++ b/FindGooglePerfTools.cmake @@ -0,0 +1,52 @@ +# Find the Google perftools includes and libraries +# This module defines +# GOOGLE_PERFTOOLS_INCLUDE_DIR, where to find heap-profiler.h, etc. +# GOOGLE_PERFTOOLS_FOUND, If false, do not try to use Google perftools. +# also defined for general use are +# TCMALLOC_LIBRARIES, where to find the tcmalloc library. +# STACKTRACE_LIBRARIES, where to find the stacktrace library. +# PROFILER_LIBRARIES, where to find the profiler library. + +FIND_PATH(GOOGLE_PERFTOOLS_INCLUDE_DIR google/heap-profiler.h) + +SET(TCMALLOC_NAMES ${TCMALLOC_NAMES} tcmalloc) +FIND_LIBRARY(TCMALLOC_LIBRARY NAMES ${TCMALLOC_NAMES}) + +IF (TCMALLOC_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR) + SET(TCMALLOC_LIBRARIES ${TCMALLOC_LIBRARY}) + SET(GOOGLE_PERFTOOLS_FOUND "YES") +ELSE (TCMALLOC_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR) + SET(GOOGLE_PERFTOOLS_FOUND "NO") +ENDIF (TCMALLOC_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR) + +SET(STACKTRACE_NAMES ${STACKTRACE_NAMES} stacktrace) +FIND_LIBRARY(STACKTRACE_LIBRARY NAMES ${STACKTRACE_LIBRARY}) + +IF (STACKTRACE_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR) + SET(STACKTRACE_LIBRARIES ${STACKTRACE_LIBRARY}) +ENDIF (STACKTRACE_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR) + +SET(PROFILER_NAMES ${PROFILER_NAMES} profiler) +FIND_LIBRARY(PROFILER_LIBRARY NAMES ${PROFILER_LIBRARY}) + +IF (PROFILER_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR) + SET(PROFILER_LIBRARIES ${PROFILER_LIBRARY}) +ENDIF (PROFILER_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR) + +IF (GOOGLE_PERFTOOLS_FOUND) + IF (NOT GOOGLE_PERFTOOLS_FIND_QUIETLY) + MESSAGE(STATUS "Found Google perftools: ${GOOGLE_PERFTOOLS_INCLUDE_DIR}") + ENDIF (NOT GOOGLE_PERFTOOLS_FIND_QUIETLY) +ELSE (GOOGLE_PERFTOOLS_FOUND) + MESSAGE(STATUS "Could not find Google perftools library") + IF (GOOGLE_PERFTOOLS_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find Google perftools library") + ENDIF (GOOGLE_PERFTOOLS_FIND_REQUIRED) +ENDIF (GOOGLE_PERFTOOLS_FOUND) + +MARK_AS_ADVANCED( + TCMALLOC_LIBRARY + STACKTRACE_LIBRARY + PROFILER_LIBRARY + GOOGLE_PERFTOOLS_INCLUDE_DIR +) \ No newline at end of file From fb9f1c0e7dbd4540ef5499cb28047143f3923901 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 23 Mar 2012 18:20:15 +0100 Subject: [PATCH 0014/1298] PhotoPion: change test case from Fe56 to He4 --- test/testInteractions.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/testInteractions.cpp b/test/testInteractions.cpp index 5850d1329..7485d6eb4 100644 --- a/test/testInteractions.cpp +++ b/test/testInteractions.cpp @@ -183,15 +183,15 @@ TEST(PhotoPionProduction, Proton) { EXPECT_EQ(candidate.current.getMassNumber(), 1); } -TEST(PhotoPionProduction, Iron) { +TEST(PhotoPionProduction, Helium) { PhotoPionProduction ppp(PhotoPionProduction::CMBIR); Candidate candidate; candidate.setCurrentStep(100 * Mpc); - candidate.current.setId(getNucleusId(56, 26)); - candidate.current.setEnergy(100 * EeV); + candidate.current.setId(getNucleusId(4, 2)); + candidate.current.setEnergy(300 * EeV); ppp.process(&candidate); - EXPECT_TRUE(candidate.current.getEnergy() / EeV < 1000); - EXPECT_TRUE(candidate.current.getMassNumber() == 56); + EXPECT_TRUE(candidate.current.getEnergy() / EeV < 300); + EXPECT_TRUE(candidate.current.getMassNumber() < 4); } From cd9d7393822e939ab3acc330318dd01ac43307ee Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 23 Mar 2012 18:35:04 +0100 Subject: [PATCH 0015/1298] add propagation tests, move testCommon to testCore --- CMakeLists.txt | 22 ++-- test/testCommon.cpp | 19 ---- test/testCore.cpp | 8 +- test/testERK.cpp | 64 ----------- ...stInteractions.cpp => testInteraction.cpp} | 1 + test/testPropagation.cpp | 104 +++++++++++++++--- 6 files changed, 105 insertions(+), 113 deletions(-) delete mode 100644 test/testCommon.cpp delete mode 100644 test/testERK.cpp rename test/{testInteractions.cpp => testInteraction.cpp} (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 20839a2a2..480c3bcbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,28 +110,28 @@ find_package(GTest) if (GTEST_FOUND) enable_testing() - add_executable(testCommon test/testCommon.cpp) - target_link_libraries(testCommon mpc ${GTEST_BOTH_LIBRARIES} pthread) - add_executable(testCore test/testCore.cpp) target_link_libraries(testCore mpc ${GTEST_BOTH_LIBRARIES} pthread) - - add_executable(testInteractions test/testInteractions.cpp) - target_link_libraries(testInteractions mpc ${GTEST_BOTH_LIBRARIES} pthread) add_executable(testMagneticField test/testMagneticField.cpp) target_link_libraries(testMagneticField mpc ${GTEST_BOTH_LIBRARIES} pthread) - + + add_executable(testPropagation test/testPropagation.cpp) + target_link_libraries(testPropagation mpc ${GTEST_BOTH_LIBRARIES} pthread) + add_executable(testBreakCondition test/testBreakCondition.cpp) target_link_libraries(testBreakCondition mpc ${GTEST_BOTH_LIBRARIES} pthread) + + add_executable(testInteraction test/testInteraction.cpp) + target_link_libraries(testInteraction mpc ${GTEST_BOTH_LIBRARIES} pthread) endif (GTEST_FOUND) # ---------------------------------------------------------------------------- # OpenMP and OpenMPI # ---------------------------------------------------------------------------- -add_executable(openmp example/openmp.cpp) -TARGET_LINK_LIBRARIES(openmp mpc) +add_executable(mpc-omp-run example/openmp.cpp) +TARGET_LINK_LIBRARIES(mpc-omp-run mpc) # MPI needed for mpc-mpi find_package(MPI) @@ -141,8 +141,8 @@ if (MPI_FOUND) set(CMAKE_CXX_COMPILE_FLAGS ${CMAKE_CXX_COMPILE_FLAGS} ${MPI_COMPILE_FLAGS}) set(CMAKE_CXX_LINK_FLAGS ${CMAKE_CXX_LINK_FLAGS} ${MPI_LINK_FLAGS}) - add_executable(mpc-mpi mpi/main mpi/Slave mpi/Master mpi/Job) - TARGET_LINK_LIBRARIES(mpc-mpi mpc ${MPI_LIBRARIES}) + add_executable(mpc-mpi-run mpi/main mpi/Slave mpi/Master mpi/Job) + TARGET_LINK_LIBRARIES(mpc-mpi-run mpc ${MPI_LIBRARIES}) endif() diff --git a/test/testCommon.cpp b/test/testCommon.cpp deleted file mode 100644 index 630cc171a..000000000 --- a/test/testCommon.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "mpc/module/common.h" - -#include "gtest/gtest.h" - -namespace mpc { - -TEST(common, digit) { - EXPECT_EQ(1, digit(1234, 1000)); - EXPECT_EQ(2, digit(1234, 100)); - EXPECT_EQ(3, digit(1234, 10)); - EXPECT_EQ(4, digit(1234, 1)); -} - -int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} - -} // namespace mpc diff --git a/test/testCore.cpp b/test/testCore.cpp index 22ee8208a..57cc88434 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -1,4 +1,5 @@ #include "mpc/Candidate.h" +#include "mpc/module/common.h" #include "gtest/gtest.h" @@ -95,7 +96,12 @@ TEST(testCandidate, status) { EXPECT_EQ(candidate.getStatus(), Candidate::UserDefined); } - +TEST(common, digit) { + EXPECT_EQ(1, digit(1234, 1000)); + EXPECT_EQ(2, digit(1234, 100)); + EXPECT_EQ(3, digit(1234, 10)); + EXPECT_EQ(4, digit(1234, 1)); +} int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); diff --git a/test/testERK.cpp b/test/testERK.cpp deleted file mode 100644 index 8a5fa4beb..000000000 --- a/test/testERK.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "gtest/gtest.h" -#include "mpc/ExplicitRungeKutta.h" -#include "mpc/PhasePoint.h" -#include - - -namespace mpc { - -TEST(testERK, cashKarpCoefficients) { - // Runge-Kutta coefficients have to add up to 1 in every row of the Butcher table - double sum; - - sum = 0; - for (size_t i = 0; i < 6; i++) - sum += cash_karp_b[i]; - EXPECT_DOUBLE_EQ(1, sum); - - sum = 0; - for (size_t i = 0; i < 6; i++) - sum += cash_karp_bs[i]; - EXPECT_DOUBLE_EQ(1, sum); - - for (size_t j = 0; j < 6; j++) { - sum = 0; - for (size_t i = 0; i < 5; i++) - sum += cash_karp_a[i + j * 5]; - EXPECT_DOUBLE_EQ(cash_karp_c[j], sum); - } -} - -class CentralPotential: public ExplicitRungeKutta::F { -public: - PhasePoint operator()(double t, const PhasePoint &v) { - double GM = 3.986004418e14; // gravitational constant * mass of earth - Vector3 acceleration = -v.a.unit() * GM / v.a.mag2(); - return PhasePoint(v.b, acceleration); - } -}; - -TEST(testERK, geoStationaryOrbit) { - double siderialDay = 86164.0954; // siderial day in seconds - double GM = 3.986004418e14; // gravitational constant * mass of earth - double f = 2*3.14159/siderialDay; // angular frequency - double r = pow(GM/(f*f), 1./3.); // radius - double v = r*f; // radial velocity - ExplicitRungeKutta erk; - erk.loadCashKarp(); - PhasePoint y(Vector3(r, 0, 0), Vector3(0, v, 0)), yOut, yErr; - CentralPotential dydt; - - double step = 100; // time step in seconds - for (size_t i = 0; i < int(siderialDay/step); i++) { - erk.step(0, y, yOut, yErr, step, dydt); // step of 1 second - y = yOut; - std::cout << y.a.x() << "," << y.a.y() << "," << y.a.z() << std::endl; - } -} - -int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} - -} // namespace mpc diff --git a/test/testInteractions.cpp b/test/testInteraction.cpp similarity index 99% rename from test/testInteractions.cpp rename to test/testInteraction.cpp index 7485d6eb4..6ceb82e90 100644 --- a/test/testInteractions.cpp +++ b/test/testInteraction.cpp @@ -151,6 +151,7 @@ TEST(PhotoDisintegration, Carbon) { pd.process(&candidate); EXPECT_TRUE(candidate.current.getMassNumber() < 12); EXPECT_TRUE(candidate.current.getEnergy() < 200 * EeV); + EXPECT_TRUE(candidate.secondaries.size() > 0); } TEST(PhotoDisintegration, Iron) { diff --git a/test/testPropagation.cpp b/test/testPropagation.cpp index 0a8301e42..9d8f944aa 100644 --- a/test/testPropagation.cpp +++ b/test/testPropagation.cpp @@ -1,26 +1,94 @@ +#include "mpc/Candidate.h" +#include "mpc/module/SimplePropagation.h" +#include "mpc/module/DeflectionCK.h" +#include "mpc/magneticField/uniformMagneticField.h" + #include "gtest/gtest.h" -#include "mpc/DeflectionCK.h" +namespace mpc { + +TEST(testSimplePropagation, noMinStep) { + ParticleState p; + p.setPosition(Vector3(0, 0, 0)); + p.setDirection(Vector3(0, 1, 0)); + + Candidate c(p); + c.setNextStep(10); + + double acceleration = 5; + double minStep = 0; + SimplePropagation propa(acceleration, minStep); + propa.process(&c); + + EXPECT_EQ(10, c.getCurrentStep()); + EXPECT_EQ(50, c.getNextStep()); + EXPECT_EQ(Vector3(0,10,0), c.current.getPosition()); + EXPECT_EQ(Vector3(0,1,0), c.current.getDirection()); +} + +TEST(testSimplePropagation, withMinStep) { + ParticleState p; + p.setPosition(Vector3(0, 0, 0)); + p.setDirection(Vector3(0, 1, 0)); + + Candidate c(p); + c.setNextStep(10); + + double acceleration = 5; + double minStep = 20; + SimplePropagation propa(acceleration, minStep); + propa.process(&c); + + EXPECT_EQ(20, c.getCurrentStep()); + EXPECT_EQ(100, c.getNextStep()); + EXPECT_EQ(Vector3(0,20,0), c.current.getPosition()); + EXPECT_EQ(Vector3(0,1,0), c.current.getDirection()); +} +TEST(testDeflectionCK, proton) { + ParticleState p; + p.setId(getNucleusId(1, 1)); + p.setEnergy(100 * EeV); + p.setPosition(Vector3(0, 0, 0)); + p.setDirection(Vector3(0, 1, 0)); -//TEST(testDeflectionCK, noBfield) { -// HomogeneousMagneticField field(Hep3Vector(0., 0., 0.)); -// DeflectionCK d(1e-3); -// -// Particle particle; -// particle.setChargeMassNumber(1,1); -// particle.setStepMpc(0.001); -// particle.setNextStepMpc(0.001); -// particle.setPositionMpc(Hep3Vector(0.,0.,0.)); -// particle.setDirection(Hep3Vector(0.,1.,0.)); -// particle.setEnergyEeV(1); -// -// for (int i = 0; i < 10; i++) -// d.apply(particle, field); -// EXPECT_EQUAL + Candidate c(p); + c.setNextStep(0); + ref_ptr field = new UniformMagneticField( + Vector3(0, 0, 1e-12)); + + DeflectionCK propa(field); + propa.process(&c); + + EXPECT_DOUBLE_EQ(0.1 * kpc, c.getCurrentStep()); + EXPECT_DOUBLE_EQ(0.5 * kpc, c.getNextStep()); +} + +TEST(testDeflectionCK, neutron) { + ParticleState p; + p.setId(getNucleusId(1, 0)); + p.setEnergy(100 * EeV); + p.setPosition(Vector3(0, 0, 0)); + p.setDirection(Vector3(0, 1, 0)); + + Candidate c(p); + + ref_ptr field = new UniformMagneticField( + Vector3(0, 0, 1e-12)); + + DeflectionCK propa(field); + propa.process(&c); + + EXPECT_DOUBLE_EQ(0.1 * kpc, c.getCurrentStep()); + EXPECT_DOUBLE_EQ(0.5 * kpc, c.getNextStep()); + EXPECT_EQ(Vector3(0, 0.1 * kpc, 0), c.current.getPosition()); + EXPECT_EQ(Vector3(0, 1, 0), c.current.getDirection()); +} int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } + +} // namespace mpc From 223a32322bc76e531c0080aaf6390760d03ebdfe Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 23 Mar 2012 20:30:11 +0100 Subject: [PATCH 0016/1298] improved testPionProduction.py --- include/mpc/Module.h | 3 +- include/mpc/magneticField/magneticField.h | 2 +- src/Vector3.cpp | 2 - test/python/testPhotoPionProduction.py | 89 +++++++++++------------ 4 files changed, 44 insertions(+), 52 deletions(-) diff --git a/include/mpc/Module.h b/include/mpc/Module.h index 27472bb88..3f6c27c31 100644 --- a/include/mpc/Module.h +++ b/include/mpc/Module.h @@ -5,7 +5,6 @@ #include "mpc/Referenced.h" #include -#include namespace mpc { @@ -13,7 +12,7 @@ class Candidate; /** @class Module - @brief Module base class. + @brief Abstract base class for modules */ class Module: public Referenced { public: diff --git a/include/mpc/magneticField/magneticField.h b/include/mpc/magneticField/magneticField.h index 3664062d6..55e9441f5 100644 --- a/include/mpc/magneticField/magneticField.h +++ b/include/mpc/magneticField/magneticField.h @@ -8,7 +8,7 @@ namespace mpc { /** @class MagneticField - @brief Magnetic field base class. + @brief Abstract base class for magnetic fields. */ class MagneticField: public Referenced { public: diff --git a/src/Vector3.cpp b/src/Vector3.cpp index 3da3fce44..6a2958282 100644 --- a/src/Vector3.cpp +++ b/src/Vector3.cpp @@ -894,8 +894,6 @@ Vector3 rotationZOf(const Vector3 & vec, double delta) { return vv.rotateZ(delta); } - - double Vector3::tolerance = Vector3::ToleranceTicks * 2.22045e-16; } // namespace mpc diff --git a/test/python/testPhotoPionProduction.py b/test/python/testPhotoPionProduction.py index 6792a49f5..60b9dbf17 100644 --- a/test/python/testPhotoPionProduction.py +++ b/test/python/testPhotoPionProduction.py @@ -1,60 +1,55 @@ -import mpc -import pylab as lab -import sys -# make sure root is startet in Batch mode -sys.argv.append('-b') +from mpc import * +from pylab import * import ROOT -def getSlope(interaction, energy, charge, count = 100000): - c = mpc.Candidate() - c.current.setId(mpc.getNucleusId(1, charge)) +def getSlope(interaction, energy, charge): + c = Candidate() + c.current.setId(getNucleusId(1, charge)) c.current.setEnergy(energy) - c.setCurrentStep(0.0 * mpc.Mpc) + s = InteractionState() - h = ROOT.TH1F('', '', 100, 0, 1000) - - for i in range(count): - c.setNextStep(100000 * mpc.Mpc) + l = [] + for i in range(10000): c.clearInteractionStates() - interaction.process(c) - h.Fill(c.getNextStep() / mpc.Mpc) - if h.GetEffectiveEntries() == 0: - return [0, 0] + c.getInteractionState('mpc::PhotoPionProduction', s) + l.append(s.distance / Mpc) + + h = ROOT.TH1F('', '', 100, 0, max(l)) + + for element in l: + h.Fill(element) + f = ROOT.TF1('f1', 'expo') h.Fit(f, "q") - s = -f.GetParameter(1) ds = f.GetParError(1) * s ** 2 - return [s, ds] + return s -def compare(type, name, count = 100000): - print "> compare ", name - ppp = mpc.PhotoPionProduction(type) - E, P, N = lab.genfromtxt(mpc.getDataPath('/PhotoPionProduction/' + name + '.txt'), unpack=True) +def compare(type, name): + print "compare ", name + ppp = PhotoPionProduction(type) + E_data, P_data, N_data = genfromtxt(getDataPath('/PhotoPionProduction/' + name + '.txt'), unpack=True) - p = lab.zeros(len(E)) - n = lab.zeros(len(E)) - print "[", - for i in range(len(E)): - print '=', - sds = getSlope(ppp, E[i] * mpc.EeV, 1, count) - p[i] = sds[0] - sds = getSlope(ppp, E[i] * mpc.EeV, 0, count) - n[i] = sds[0] - print "]" - lab.plot(E, p, 'k+', label="proton simulated", linewidth=2, markeredgewidth=2) - lab.plot(E, P, "r", label="proton data") - lab.plot(E, n, 'k.', label="neutron simulated") - lab.plot(E, N, "b", label="neutron data") - lab.xlabel('energy [EeV]') - lab.ylabel('rate [1/Mpc]') - lab.legend(loc='lower right') - lab.grid() - lab.semilogx() - lab.savefig('PhotoPionProduction_' + name + '.png', bbox_inches='tight') - lab.close() + E = logspace(1.5,5,10) * EeV + p = zeros(len(E)) + n = zeros(len(E)) + for i,energy in enumerate(E*EeV): + p[i] = getSlope(ppp, energy, 1) + n[i] = getSlope(ppp, energy, 0) + plot(E_data, P_data, "r", label="Proton Data") + plot(E, p, 'k+', label="Proton Simulated") + plot(E_data, N_data, "b", label="Neutron Data") + plot(E, n, 'k.', label="Neutron Simulated") + xlabel('Energy [EeV]') + ylabel('Rate [1/Mpc]') + legend(loc='center right') + grid() + loglog() + ylim(1e-4, 1) + savefig('PhotoPionProduction_' + name + '.png', bbox_inches='tight') + close() -compare(mpc.PhotoPionProduction.CMB, "cmb"); -compare(mpc.PhotoPionProduction.CMBIR, "cmbir"); -compare(mpc.PhotoPionProduction.IR, "ir", 1000000); +compare(PhotoPionProduction.CMB, "cmb") +compare(PhotoPionProduction.CMBIR, "cmbir") +compare(PhotoPionProduction.IR, "ir") From d002daf0070d6e382c4de4634d10767d4b739c4e Mon Sep 17 00:00:00 2001 From: geromueller Date: Mon, 26 Mar 2012 12:44:41 +0200 Subject: [PATCH 0017/1298] add performance module, fix modulelist --- CMakeLists.txt | 2 + include/mpc/Clock.h | 23 ++++++ include/mpc/module/Tools.h | 28 +++++++ python/mpc.i | 7 +- src/Clock.cpp | 155 +++++++++++++++++++++++++++++++++++++ src/ModuleList.cpp | 2 + src/module/Tools.cpp | 69 +++++++++++++++++ 7 files changed, 284 insertions(+), 2 deletions(-) create mode 100644 include/mpc/Clock.h create mode 100644 include/mpc/module/Tools.h create mode 100644 src/Clock.cpp create mode 100644 src/module/Tools.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 480c3bcbf..00beeb47d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,7 @@ add_definitions(-DMPC_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") # ---------------------------------------------------------------------------- add_library(mpc SHARED src/Random.cpp + src/Clock.cpp src/Vector3.cpp src/XMLImport.cpp src/ModuleChain.cpp @@ -90,6 +91,7 @@ add_library(mpc SHARED src/module/NuclearDecay.cpp src/module/Redshift.cpp src/module/Output.cpp + src/module/Tools.cpp src/magneticField/magneticFieldGrid.cpp ${MPC_EXTRA_SOURCES} ) diff --git a/include/mpc/Clock.h b/include/mpc/Clock.h new file mode 100644 index 000000000..a91bcd065 --- /dev/null +++ b/include/mpc/Clock.h @@ -0,0 +1,23 @@ +#ifndef CLOCK_H_ +#define CLOCK_H_ + +namespace mpc { + +//class ClockImpl; + +class Clock { +private: + class Impl; + Impl *impl; +public: + Clock(); + virtual ~Clock(); + + void reset(); + double getSecond(); + double getMillisecond(); + static Clock &getInstance(); +}; + +} /* namespace scs */ +#endif /* CLOCK_H_ */ diff --git a/include/mpc/module/Tools.h b/include/mpc/module/Tools.h new file mode 100644 index 000000000..e890821d4 --- /dev/null +++ b/include/mpc/module/Tools.h @@ -0,0 +1,28 @@ +#ifndef MPC_MODULE_TOOLS_H_ +#define MPC_MODULE_TOOLS_H_ + +#include "mpc/Module.h" + +namespace mpc { + +class PerformanceModule: public Module { +private: + struct _module_info { + double time; + ref_ptr module; + }; + + mutable std::vector<_module_info> modules; + mutable size_t calls; + +public: + PerformanceModule(); + ~PerformanceModule(); + void add(Module *module); + void process(Candidate *candidate) const; + std::string getDescription() const; +}; + +} // namespace mpc + +#endif /* MPC_MODULE_TOOLS_H_ */ diff --git a/python/mpc.i b/python/mpc.i index 9c5e735c3..1384ae987 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -23,6 +23,7 @@ #include "mpc/module/SimplePropagation.h" #include "mpc/module/DeflectionCK.h" #include "mpc/module/GlutDisplay.h" +#include "mpc/module/Tools.h" #include "mpc/magneticField/magneticField.h" #include "mpc/magneticField/uniformMagneticField.h" @@ -55,7 +56,8 @@ %include "mpc/Vector3.h" %include "mpc/Random.h" %include "mpc/ParticleState.h" -%feature("director") mpc::Source; +// %feature("director") mpc::Source; +%template(SourceRefPtr) mpc::ref_ptr; %include "mpc/Source.h" %include "mpc/module/common.h" @@ -66,7 +68,7 @@ %template(ModuleRefPtr) mpc::ref_ptr; %template(stdModuleVector) std::vector< mpc::ref_ptr >; %template(stdModuleList) std::list< mpc::ref_ptr >; -%feature("director") mpc::Module; +// %feature("director") mpc::Module; %include "mpc/Module.h" %template(stdMagneticFieldVector) std::vector< mpc::ref_ptr >; @@ -90,6 +92,7 @@ %include "mpc/module/PhotoDisintegration.h" %include "mpc/module/Redshift.h" %include "mpc/module/GlutDisplay.h" +%include "mpc/module/Tools.h" %include "mpc/ModuleChain.h" diff --git a/src/Clock.cpp b/src/Clock.cpp new file mode 100644 index 000000000..ccd353718 --- /dev/null +++ b/src/Clock.cpp @@ -0,0 +1,155 @@ +#include "mpc/Clock.h" + +#if defined(WIN32) || defined(_WIN32) + +#define USE_WINDOWS_TIMERS +#define WIN32_LEAN_AND_MEAN +#define NOWINRES +#define NOMCX +#define NOIME +#ifdef _XBOX +#include +#else +#include +#endif +#include + +#else +#include +#endif + +#include +#ifdef _OPENMP +#include +#include +#endif + +namespace mpc { + +#ifdef WIN32 +class Clock::Impl { + LARGE_INTEGER clockFrequency; + DWORD startTick; + LONGLONG prevElapsedTime; + LARGE_INTEGER startTime; +public: + Impl() { + QueryPerformanceFrequency(&clockFrequency); + reset(); + } + + void reset() { + QueryPerformanceCounter(&startTime); + startTick = GetTickCount(); + prevElapsedTime = 0; + } + + /// Returns the time in ms since the last call to reset or since + /// the btClock was created. + double getSecond() { + LARGE_INTEGER currentTime; + QueryPerformanceCounter(¤tTime); + LONGLONG elapsedTime = currentTime.QuadPart - startTime.QuadPart; + + // Compute the number of millisecond ticks elapsed. + unsigned long msecTicks = (unsigned long) (1000 * elapsedTime + / clockFrequency.QuadPart); + + // Check for unexpected leaps in the Win32 performance counter. + // (This is caused by unexpected data across the PCI to ISA + // bridge, aka south bridge. See Microsoft KB274323.) + unsigned long elapsedTicks = GetTickCount() - startTick; + signed long msecOff = (signed long) (msecTicks - elapsedTicks); + if (msecOff < -100 || msecOff > 100) { + // Adjust the starting time forwards. + LONGLONG msecAdjustment = std::min( + msecOff * clockFrequency.QuadPart / 1000, + elapsedTime - prevElapsedTime); + startTime.QuadPart += msecAdjustment; + elapsedTime -= msecAdjustment; + } + + // Store the current elapsed time for adjustments next time. + prevElapsedTime = elapsedTime; + + // Convert to microseconds. + unsigned long usecTicks = (unsigned long) (1000000 * elapsedTime + / clockFrequency.QuadPart); + + return double(usecTicks) / 1000000; + } +}; +#else + +class Clock::Impl { + struct timeval startTime; +public: + Impl() { + reset(); + } + + void reset() { + gettimeofday(&startTime, 0); + } + + /// Returns the time in since the last call to reset or since + /// the btClock was created. + double getTime() { + struct timeval currentTime; + gettimeofday(¤tTime, 0); + double t = double(currentTime.tv_sec - startTime.tv_sec); + t += double(currentTime.tv_usec - startTime.tv_usec) / 1000000.; + return t; + } +}; +#endif + +Clock::Clock() { + impl = new Impl; +} + +Clock::~Clock() { + delete impl; +} + +void Clock::reset() { + impl->reset(); +} + +double Clock::getSecond() { + return impl->getTime(); +} + +double Clock::getMillisecond() { + return impl->getTime() * 1000; +} + +#ifdef _OPENMP + +// see http://stackoverflow.com/questions/8051108/using-the-openmp-threadprivate-directive-on-static-instances-of-c-stl-types +const static int MAX_THREAD = 256; + +struct CLOCK_TLS_ITEM { + Clock r; + char padding[64 - sizeof(Clock)]; +}; + +Clock &Clock::getInstance() { +#ifdef _MSC_VER + __declspec(align(64)) static CLOCK_TLS_ITEM tls[MAX_THREAD]; +#else + __attribute__ ((aligned(64))) static CLOCK_TLS_ITEM tls[MAX_THREAD]; +#endif + int i = omp_get_thread_num(); + if (i >= MAX_THREAD) + throw std::runtime_error("mpc::Clock: more than MAX_THREAD threads!"); + return tls[i].r; +} +#else +Clock &Clock::getInstance() { + static Clock r; + return r; +} +#endif + +} /* namespace scs */ diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 96f0581f4..0e2893e36 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -41,6 +41,8 @@ void ModuleList::run(Candidate *candidate, bool recursive) { void ModuleList::run(Source *source, size_t count, bool recursive) { size_t cent = count / 100; + if (cent == 0) + cent = 1; size_t pc = 0; #pragma omp parallel for schedule(dynamic, 1000) for (size_t i = 0; i < count; i++) { diff --git a/src/module/Tools.cpp b/src/module/Tools.cpp new file mode 100644 index 000000000..1c696d548 --- /dev/null +++ b/src/module/Tools.cpp @@ -0,0 +1,69 @@ +#include "mpc/module/Tools.h" +#include "mpc/Clock.h" + +#include +#include + +using namespace std; + +namespace mpc { + +PerformanceModule::PerformanceModule() { + +} + +PerformanceModule::~PerformanceModule() { + double total = 0; + for (size_t i = 0; i < modules.size(); i++) { + _module_info &m = modules[i]; + total += m.time; + } + cout << "Performance for " << calls << " calls:" << endl; + for (size_t i = 0; i < modules.size(); i++) { + _module_info &m = modules[i]; + cout << " - " << floor((1000 * m.time / total) + 0.5) / 10 << "% -> " << m.module->getDescription() << ": " << (m.time / calls) + << endl; + } +} + +void PerformanceModule::add(Module *module) { + _module_info info; + info.module = module; + info.time = 0; + modules.push_back(info); +} + +void PerformanceModule::process(Candidate *candidate) const { + vector times(modules.size()); + for (size_t i = 0; i < modules.size(); i++) { + _module_info &m = modules[i]; + double start = Clock::getInstance().getMillisecond(); + m.module->process(candidate); + double end = Clock::getInstance().getMillisecond(); + times[i] = end - start; + } + +#pragma omp critical + { + for (size_t i = 0; i < modules.size(); i++) { + _module_info &m = modules[i]; + m.time += times[i]; + } + calls++; + } +} + +string PerformanceModule::getDescription() const { + stringstream sstr; + sstr << "PerformanceModule ("; + for (size_t i = 0; i < modules.size(); i++) { + _module_info &m = modules[i]; + if (i > 0) + sstr << ", "; + sstr << m.module->getDescription(); + } + sstr << ")"; + return sstr.str(); +} + +} // namespace mpc From dedd0c6794184fd2ce324d12bd2a4f38a5f0f45a Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 27 Mar 2012 12:59:08 +0200 Subject: [PATCH 0018/1298] change Candidate: enum status is now resolved in bool isActive and map properties --- include/mpc/Candidate.h | 20 +++--- include/mpc/module/BreakCondition.h | 90 ++++++++++-------------- include/mpc/module/Output.h | 12 ++-- mpi/Slave.cpp | 10 ++- src/Candidate.cpp | 53 +++++++++----- src/IO.cpp | 6 +- src/ModuleChain.cpp | 4 +- src/ModuleList.cpp | 2 +- src/module/Output.cpp | 65 +++++++---------- test/testBreakCondition.cpp | 105 ++++++++++++++++------------ test/testCore.cpp | 44 ++++++------ 11 files changed, 205 insertions(+), 206 deletions(-) diff --git a/include/mpc/Candidate.h b/include/mpc/Candidate.h index 1dbb1d430..da09d20e5 100644 --- a/include/mpc/Candidate.h +++ b/include/mpc/Candidate.h @@ -33,10 +33,7 @@ struct InteractionState { */ class Candidate: public Referenced { public: - enum Status { - Active = 0, Detected, OutOfBounds, Stopped, UserDefined - }; - + bool active; ParticleState current; ParticleState initial; std::vector > secondaries; @@ -44,15 +41,17 @@ class Candidate: public Referenced { private: double redshift, trajectoryLength; double currentStep, nextStep; - Status status; + std::map properties; std::map interactionStates; public: Candidate(); Candidate(const ParticleState &state); - virtual ~Candidate() { + virtual ~Candidate() {}; + + bool isActive() const; + void setActive(const bool b); - } double getRedshift() const; void setRedshift(double z); @@ -66,13 +65,14 @@ class Candidate: public Referenced { void setNextStep(double step); void limitNextStep(double step); - Status getStatus() const; - void setStatus(Status stat); + bool getProperty(const std::string &name, std::string &value) const; + void setProperty(const std::string &name, const std::string &value); + bool hasProperty(const std::string &name) const; bool getInteractionState(const std::string &moduleName, InteractionState &state) const; void setInteractionState(const std::string &moduleName, - InteractionState state); + const InteractionState &state); const std::map getInteractionStates() const; void clearInteractionStates(); diff --git a/include/mpc/module/BreakCondition.h b/include/mpc/module/BreakCondition.h index 2133f54b5..c43050566 100644 --- a/include/mpc/module/BreakCondition.h +++ b/include/mpc/module/BreakCondition.h @@ -23,7 +23,7 @@ class MaximumTrajectoryLength: public Module { void process(Candidate *candidate) const { double l = candidate->getTrajectoryLength(); if (l >= maxLength) - candidate->setStatus(Candidate::Stopped); + candidate->setActive(false); candidate->limitNextStep(maxLength - l); } @@ -42,13 +42,13 @@ class MinimumEnergy: public Module { public: double minEnergy; - MinimumEnergy(double minEnergy) { - this->minEnergy = minEnergy; + MinimumEnergy(double minEnergy) : + minEnergy(minEnergy) { } void process(Candidate *candidate) const { if (candidate->current.getEnergy() <= minEnergy) - candidate->setStatus(Candidate::Stopped); + candidate->setActive(false); } std::string getDescription() const { @@ -67,16 +67,16 @@ class SmallObserverSphere: public Module { double radius; Vector3 center; - SmallObserverSphere(Vector3 center, double radius) { - this->radius = radius; - this->center = center; + SmallObserverSphere(Vector3 center, double radius) : + center(center), radius(radius) { } void process(Candidate *candidate) const { double d = (candidate->current.getPosition() - center).mag(); - if (d <= radius * 1.01) - candidate->setStatus(Candidate::Detected); - else + if (d <= radius * 1.01) { + candidate->setActive(false); + candidate->setProperty("Detected", ""); + } else candidate->limitNextStep((d - radius)); } @@ -95,26 +95,16 @@ class CubicBoundary: public Module { protected: Vector3 origin; double size; - Candidate::Status flag; - bool hardBoundary; + bool limitStep; double margin; public: - CubicBoundary(Vector3 origin, double size, Candidate::Status flag) { - this->origin = origin; - this->size = size; - this->hardBoundary = true; - this->flag = flag; - this->margin = 0; - } - - CubicBoundary(Vector3 origin, double size, double margin, - Candidate::Status flag) { - this->origin = origin; - this->size = size; - this->flag = flag; - this->hardBoundary = false; - this->margin = margin; + CubicBoundary(Vector3 origin, double size) : + origin(origin), size(size), limitStep(false) { + } + + CubicBoundary(Vector3 origin, double size, double margin) : + origin(origin), size(size), limitStep(true), margin(margin) { } void process(Candidate *candidate) const { @@ -122,8 +112,8 @@ class CubicBoundary: public Module { double lo = std::min(relPos.x(), std::min(relPos.y(), relPos.z())); double hi = std::max(relPos.x(), std::max(relPos.y(), relPos.z())); if ((lo <= 0.) or (hi >= size)) - candidate->setStatus(flag); - if (!hardBoundary) { + candidate->setActive(false); + if (limitStep) { candidate->limitNextStep(lo + margin); candidate->limitNextStep(size - hi + margin); } @@ -144,31 +134,23 @@ class SphericalBoundary: public Module { protected: Vector3 center; double radius; - Candidate::Status flag; - bool hardBoundary; + bool limitStep; double margin; public: - SphericalBoundary(Vector3 center, double radius, Candidate::Status flag) { - this->center = center; - this->radius = radius; - this->flag = flag; - } - - SphericalBoundary(Vector3 center, double radius, double margin, - Candidate::Status flag) { - this->center = center; - this->radius = radius; - this->flag = flag; - this->hardBoundary = true; - this->margin = margin; + SphericalBoundary(Vector3 center, double radius) : + center(center), radius(radius), limitStep(false) { + } + + SphericalBoundary(Vector3 center, double radius, double margin) : + center(center), radius(radius), limitStep(true), margin(margin) { } void process(Candidate *candidate) const { double d = (candidate->current.getPosition() - center).mag(); if (d >= radius) - candidate->setStatus(flag); - if (hardBoundary) + candidate->setActive(false); + if (limitStep) candidate->limitNextStep(radius - d + margin); } @@ -188,26 +170,24 @@ class EllipsoidalBoundary: public Module { Vector3 focalPoint1; Vector3 focalPoint2; double majorAxis; - Candidate::Status flag; - bool hardBoundary; + bool limitStep; double margin; public: EllipsoidalBoundary(Vector3 focalPoint1, Vector3 focalPoint2, - double majorAxis, Candidate::Status flag) { + double majorAxis) { this->focalPoint1 = focalPoint1; this->focalPoint2 = focalPoint2; this->majorAxis = majorAxis; - this->flag = flag; + this->limitStep = false; } EllipsoidalBoundary(Vector3 focalPoint1, Vector3 focalPoint2, - double majorAxis, double margin, Candidate::Status flag) { + double majorAxis, double margin) { this->focalPoint1 = focalPoint1; this->focalPoint2 = focalPoint2; this->majorAxis = majorAxis; - this->flag = flag; - this->hardBoundary = true; + this->limitStep = true; this->margin = margin; } @@ -215,8 +195,8 @@ class EllipsoidalBoundary: public Module { Vector3 pos = candidate->current.getPosition(); double d = (pos - focalPoint1).mag() + (pos - focalPoint2).mag(); if (d >= majorAxis) - candidate->setStatus(flag); - if (hardBoundary) + candidate->setActive(false); + if (limitStep) candidate->limitNextStep(majorAxis - d + margin); } diff --git a/include/mpc/module/Output.h b/include/mpc/module/Output.h index 7884803d5..892541ba3 100644 --- a/include/mpc/module/Output.h +++ b/include/mpc/module/Output.h @@ -22,17 +22,17 @@ class TrajectoryOutput: public Module { }; /** - @class FlaggedOutput - @brief Saves particles with a given flag to a CSV file. + @class ConditionalOutput + @brief Saves particles with a given property to a CSV file. */ -class FlaggedOutput: public Module { +class ConditionalOutput: public Module { private: mutable std::ofstream outfile; - Candidate::Status flag; + std::string propertyName; public: - FlaggedOutput(std::string name, Candidate::Status flag); - ~FlaggedOutput(); + ConditionalOutput(std::string name, std::string propName); + ~ConditionalOutput(); void process(Candidate *candidate) const; std::string getDescription() const; }; diff --git a/mpi/Slave.cpp b/mpi/Slave.cpp index 6f8baaa7d..60128177e 100644 --- a/mpi/Slave.cpp +++ b/mpi/Slave.cpp @@ -49,18 +49,16 @@ void Slave::load(const string &filename) { // break conditions --------------------------------------------------- // chain.add(new MinimumEnergy(5 * EeV), 50); // chain.add(new MaximumTrajectoryLength(100 * Mpc), 51); - chain.add( - 52, - new SphericalBoundary(Vector3(0, 0, 0) * Mpc, 20 * Mpc, 0.1 * Mpc, - Candidate::Detected)); + chain.add(52, + new SphericalBoundary(Vector3(0, 0, 0) * Mpc, 20 * Mpc, 0.1 * Mpc)); // chain.add(new SmallObserverSphere(Vector3(0, 0, 0) * Mpc, 1 * Mpc), 53); // output ------------------------------------------------------------- chain.add(79, new ShellOutput()); // chain.add(new TrajectoryOutput("trajectories.csv"), 80); // chain.add(new GlutDisplay(), 80); - chain.add(100, new FlaggedOutput("final.txt", Candidate::Detected)); -} +chain.add(100, new ConditionalOutput("final.txt", "Detected")); + } void Slave::acquireJob() { job_t job; diff --git a/src/Candidate.cpp b/src/Candidate.cpp index 50865a26d..8ffda0e95 100644 --- a/src/Candidate.cpp +++ b/src/Candidate.cpp @@ -3,13 +3,21 @@ namespace mpc { Candidate::Candidate() : - redshift(0), trajectoryLength(0), currentStep(0), nextStep(0), status( - Active) { + redshift(0), trajectoryLength(0), currentStep(0), nextStep(0), active( + true) { } Candidate::Candidate(const ParticleState &state) : current(state), initial(state), redshift(0), trajectoryLength(0), currentStep( - 0), nextStep(0), status(Active) { + 0), nextStep(0), active(true) { +} + +bool Candidate::isActive() const { + return active; +} + +void Candidate::setActive(const bool b) { + active = b; } double Candidate::getRedshift() const { @@ -28,10 +36,6 @@ double Candidate::getNextStep() const { return nextStep; } -Candidate::Status Candidate::getStatus() const { - return status; -} - void Candidate::setRedshift(double z) { redshift = z; } @@ -53,10 +57,6 @@ void Candidate::limitNextStep(double step) { nextStep = std::min(nextStep, step); } -void Candidate::setStatus(Status stat) { - status = stat; -} - bool Candidate::getInteractionState(const std::string &moduleName, InteractionState &state) const { std::map::const_iterator i = @@ -68,29 +68,48 @@ bool Candidate::getInteractionState(const std::string &moduleName, } void Candidate::setInteractionState(const std::string &moduleName, - InteractionState state) { -#pragma omp critical + const InteractionState &state) { interactionStates[moduleName] = state; } +const std::map Candidate::getInteractionStates() const { + return interactionStates; +} + void Candidate::clearInteractionStates() { interactionStates.clear(); } -const std::map Candidate::getInteractionStates() const { - return interactionStates; +bool Candidate::getProperty(const std::string &name, std::string &value) const { + std::map::const_iterator i = properties.find( + name); + if (i == properties.end()) + return false; + value = i->second; + return true; +} + +void Candidate::setProperty(const std::string &name, const std::string &value) { + properties[name] = value; +} + +bool Candidate::hasProperty(const std::string &name) const { + std::map::const_iterator i = properties.find( + name); + if (i == properties.end()) + return false; + return true; } +; void Candidate::addSecondary(int id, double energy) { ref_ptr secondary = new Candidate; - secondary->setStatus(Candidate::Active); secondary->setRedshift(redshift); secondary->setTrajectoryLength(trajectoryLength); secondary->initial = initial; secondary->current = current; secondary->current.setId(id); secondary->current.setEnergy(energy); -#pragma omp critical secondaries.push_back(secondary); } diff --git a/src/IO.cpp b/src/IO.cpp index 3e05fc688..8bcd538b7 100644 --- a/src/IO.cpp +++ b/src/IO.cpp @@ -29,8 +29,6 @@ void write(kiss::Output &out, const mpc::Candidate &candidate) { write(out, candidate.getTrajectoryLength()); write(out, candidate.getCurrentStep()); write(out, candidate.getNextStep()); - write(out, candidate.getStatus()); -//write(out, candidate.getInteractionStates()); } bool read(kiss::Input &in, mpc::Vector3 &vec3) { @@ -61,8 +59,8 @@ bool read(kiss::Input &in, mpc::Candidate &candidate) { candidate.setTrajectoryLength(kiss::read(in)); candidate.setCurrentStep(kiss::read(in)); candidate.setNextStep(kiss::read(in)); - candidate.setStatus((mpc::Candidate::Status) kiss::read(in)); -//read(in, candidate.getInteractionStates()); +// candidate.setStatus((mpc::Candidate::Status) kiss::read(in)); +// read(in, candidate.getInteractionStates()); return (in); } diff --git a/src/ModuleChain.cpp b/src/ModuleChain.cpp index 60b29cfd1..2ac6cb277 100644 --- a/src/ModuleChain.cpp +++ b/src/ModuleChain.cpp @@ -51,7 +51,7 @@ void ModuleChain::process(Candidate *candidate) { process(startModules, candidate); - while (candidate->getStatus() == Candidate::Active) { + while (candidate->isActive()) { if (mainModules.size() == 0) break; process(mainModules, candidate); @@ -65,7 +65,7 @@ void ModuleChain::process(std::vector > &candidates, #pragma omp parallel for for (size_t i = 0; i < candidates.size(); i++) { Candidate *candidate = candidates[i]; - if (candidate->getStatus() != Candidate::Active) + if (candidate->isActive()) continue; process(candidate); diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 0e2893e36..1bef5ede0 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -27,7 +27,7 @@ void ModuleList::process(Candidate *candidate) { } void ModuleList::run(Candidate *candidate, bool recursive) { - while (candidate->getStatus() == Candidate::Active) { + while (candidate->isActive()) { process(candidate); } diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 5c7b129fe..87e86f243 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -37,57 +37,43 @@ std::string TrajectoryOutput::getDescription() const { return "Trajectory output"; } -FlaggedOutput::FlaggedOutput(std::string name, Candidate::Status flag) { - this->flag = flag; +ConditionalOutput::ConditionalOutput(std::string name, std::string propName) { + propertyName = propName; outfile.open(name.c_str()); outfile << "id, x, y, z, E, phi, theta, distance, i_id, i_x, i_y, i_z, i_E, i_phi, i_theta\n"; } -FlaggedOutput::~FlaggedOutput() { +ConditionalOutput::~ConditionalOutput() { outfile.close(); } -void FlaggedOutput::process(Candidate *candidate) const { - if (candidate->getStatus() != flag) - return; - +void ConditionalOutput::process(Candidate *candidate) const { + if (candidate->hasProperty(propertyName)) { #pragma omp critical - { - outfile << candidate->current.getId() << ", "; - outfile << candidate->current.getPosition().x() / Mpc << ", "; - outfile << candidate->current.getPosition().y() / Mpc << ", "; - outfile << candidate->current.getPosition().z() / Mpc << ", "; - outfile << candidate->current.getEnergy() / EeV << ", "; - outfile << candidate->current.getDirection().phi() << ", "; - outfile << candidate->current.getDirection().theta() << ", "; - outfile << candidate->getTrajectoryLength() / Mpc << ", "; - outfile << candidate->initial.getId() << ", "; - outfile << candidate->initial.getPosition().x() / Mpc << ", "; - outfile << candidate->initial.getPosition().y() / Mpc << ", "; - outfile << candidate->initial.getPosition().z() / Mpc << ", "; - outfile << candidate->initial.getEnergy() / EeV << ", "; - outfile << candidate->initial.getDirection().phi() << ", "; - outfile << candidate->initial.getDirection().theta(); - outfile << std::endl; + { + outfile << candidate->current.getId() << ", "; + outfile << candidate->current.getPosition().x() / Mpc << ", "; + outfile << candidate->current.getPosition().y() / Mpc << ", "; + outfile << candidate->current.getPosition().z() / Mpc << ", "; + outfile << candidate->current.getEnergy() / EeV << ", "; + outfile << candidate->current.getDirection().phi() << ", "; + outfile << candidate->current.getDirection().theta() << ", "; + outfile << candidate->getTrajectoryLength() / Mpc << ", "; + outfile << candidate->initial.getId() << ", "; + outfile << candidate->initial.getPosition().x() / Mpc << ", "; + outfile << candidate->initial.getPosition().y() / Mpc << ", "; + outfile << candidate->initial.getPosition().z() / Mpc << ", "; + outfile << candidate->initial.getEnergy() / EeV << ", "; + outfile << candidate->initial.getDirection().phi() << ", "; + outfile << candidate->initial.getDirection().theta(); + outfile << std::endl; + } } } -std::string FlaggedOutput::getDescription() const { - switch (flag) { - case Candidate::Active: - return "FlaggedOutput, Active"; - case Candidate::Detected: - return "FlaggedOutput, Detected"; - case Candidate::OutOfBounds: - return "FlaggedOutput, OutOfBounds"; - case Candidate::Stopped: - return "FlaggedOutput, Stopped"; - case Candidate::UserDefined: - default: - return "FlaggedOutput, user defined (" + kiss::str(flag) + ")"; - } - +std::string ConditionalOutput::getDescription() const { + return "ConditionalOutput, condition: " + propertyName; } void ShellOutput::process(Candidate *candidate) const { @@ -99,7 +85,6 @@ void ShellOutput::process(Candidate *candidate) const { std::cout << candidate->current.getId() << ", "; std::cout << candidate->current.getEnergy() / EeV << " EeV, "; std::cout << candidate->current.getPosition() / Mpc << " Mpc, Status: "; - std::cout << candidate->getStatus(); std::cout << std::endl; } } diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index 854be010c..f76e6f2d4 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -6,125 +6,140 @@ namespace mpc { class ModuleTest: public testing::Test { protected: - Candidate candidate; - std::vector secondaries; }; -TEST_F(ModuleTest, MinimumEnergy_Continue) { +TEST(MinimumEnergy, Continue) { MinimumEnergy minEnergy(5); + Candidate candidate; candidate.current.setEnergy(5.1); minEnergy.process(&candidate); - EXPECT_EQ(candidate.getStatus(), Candidate::Active); + EXPECT_TRUE(candidate.isActive()); } -TEST_F(ModuleTest, MinimumEnergy_Break) { +TEST(MinimumEnergy, Stop) { MinimumEnergy minEnergy(5); + Candidate candidate; candidate.current.setEnergy(4.9); minEnergy.process(&candidate); - EXPECT_EQ(candidate.getStatus(), Candidate::Stopped); + EXPECT_FALSE(candidate.isActive()); } -TEST_F(ModuleTest, MaximumTrajectoryLength_Continue) { +TEST(MaximumTrajectoryLength, Continue) { MaximumTrajectoryLength maxLength(10); + Candidate candidate; candidate.setTrajectoryLength(9.9); maxLength.process(&candidate); - EXPECT_EQ(candidate.getStatus(), Candidate::Active); + EXPECT_TRUE(candidate.isActive()); } -TEST_F(ModuleTest, MaximumTrajectoryLength_Break) { +TEST(MaximumTrajectoryLength, Stop) { MaximumTrajectoryLength maxLength(10); + Candidate candidate; candidate.setTrajectoryLength(10.1); maxLength.process(&candidate); - EXPECT_EQ(candidate.getStatus(), Candidate::Stopped); + EXPECT_FALSE(candidate.isActive()); } -TEST_F(ModuleTest, SmallObserverSphere) { +TEST(SmallObserverSphere, Continue) { SmallObserverSphere obs(Vector3(0, 0, 0), 1); + Candidate candidate; candidate.current.setPosition(Vector3(2, 0, 0)); obs.process(&candidate); - EXPECT_EQ(candidate.getStatus(), Candidate::Active); + EXPECT_TRUE(candidate.isActive()); +} - candidate.setStatus(Candidate::Active); +TEST(SmallObserverSphere, Detect) { + SmallObserverSphere obs(Vector3(0, 0, 0), 1); + Candidate candidate; candidate.current.setPosition(Vector3(0.1, 0.5, -0.1)); obs.process(&candidate); - EXPECT_EQ(candidate.getStatus(), Candidate::Detected); + EXPECT_FALSE(candidate.isActive()); + EXPECT_TRUE(candidate.hasProperty("Detected")); +} +TEST(SmallObserverSphere, LimitStep) { + SmallObserverSphere obs(Vector3(0, 0, 0), 1); + Candidate candidate; candidate.setNextStep(10); candidate.current.setPosition(Vector3(0, 0, 2)); obs.process(&candidate); EXPECT_DOUBLE_EQ(candidate.getNextStep(), 1); } -TEST_F(ModuleTest, CubicBoundary_Inside) { - CubicBoundary cube(Vector3(0, 0, 0), 10, Candidate::Stopped); +TEST(CubicBoundary, Inside) { + CubicBoundary cube(Vector3(0, 0, 0), 10); + Candidate candidate; candidate.current.setPosition(Vector3(9, 5, 5)); cube.process(&candidate); - EXPECT_EQ(candidate.getStatus(), Candidate::Active); + EXPECT_TRUE(candidate.isActive()); } -TEST_F(ModuleTest, CubicBoundary_Above) { - CubicBoundary cube(Vector3(0, 0, 0), 10, Candidate::Stopped); +TEST(CubicBoundary, Outside) { + CubicBoundary cube(Vector3(0, 0, 0), 10); + Candidate candidate; candidate.current.setPosition(Vector3(10.1, 5, 5)); cube.process(&candidate); - EXPECT_EQ(candidate.getStatus(), Candidate::Stopped); -} + EXPECT_FALSE(candidate.isActive()); -TEST_F(ModuleTest, CubicBoundary_Below) { - CubicBoundary cube(Vector3(0, 0, 0), 10, Candidate::Stopped); candidate.current.setPosition(Vector3(5, -0.1, 5)); + candidate.setActive(true); cube.process(&candidate); - EXPECT_EQ(candidate.getStatus(), Candidate::Stopped); + EXPECT_FALSE(candidate.isActive()); } -TEST_F(ModuleTest, CubicBoundary_LimitStep) { - CubicBoundary cube(Vector3(0, 0, 0), 10, 1, Candidate::Stopped); +TEST(CubicBoundary, LimitStep) { + CubicBoundary cube(Vector3(0, 0, 0), 10, 1); + Candidate candidate; candidate.setNextStep(10); candidate.current.setPosition(Vector3(5, 5, 0.5)); cube.process(&candidate); EXPECT_DOUBLE_EQ(candidate.getNextStep(), 1.5); } -TEST_F(ModuleTest, SphericalBoundary_Inside) { - SphericalBoundary sphere(Vector3(0, 0, 0), 10, Candidate::Stopped); +TEST(SphericalBoundary, Inside) { + SphericalBoundary sphere(Vector3(0, 0, 0), 10); + Candidate candidate; candidate.current.setPosition(Vector3(9, 0, 0)); sphere.process(&candidate); - EXPECT_EQ(candidate.getStatus(), Candidate::Active); + EXPECT_TRUE(candidate.isActive()); } -TEST_F(ModuleTest, SphericalBoundary_Outside) { - SphericalBoundary sphere(Vector3(0, 0, 0), 10, Candidate::Stopped); +TEST(SphericalBoundary, Outside) { + SphericalBoundary sphere(Vector3(0, 0, 0), 10); + Candidate candidate; candidate.current.setPosition(Vector3(0, -10.1, 0)); sphere.process(&candidate); - EXPECT_EQ(candidate.getStatus(), Candidate::Stopped); + EXPECT_FALSE(candidate.isActive()); } -TEST_F(ModuleTest, SphericalBoundary_LimitStep) { - SphericalBoundary sphere(Vector3(0, 0, 0), 10, 1, Candidate::Stopped); +TEST(SphericalBoundary, LimitStep) { + SphericalBoundary sphere(Vector3(0, 0, 0), 10, 1); + Candidate candidate; candidate.setNextStep(2); candidate.current.setPosition(Vector3(0, 0, 9.5)); sphere.process(&candidate); EXPECT_DOUBLE_EQ(candidate.getNextStep(), 1.5); } -TEST_F(ModuleTest, EllipsoidalBoundary_Inside) { - EllipsoidalBoundary ellipsoid(Vector3(-5, 0, 0), Vector3(5, 0, 0), 15, - Candidate::Stopped); +TEST(EllipsoidalBoundary, Inside) { + EllipsoidalBoundary ellipsoid(Vector3(-5, 0, 0), Vector3(5, 0, 0), 15); + Candidate candidate; candidate.current.setPosition(Vector3(3, 2, 0)); ellipsoid.process(&candidate); - EXPECT_EQ(candidate.getStatus(), Candidate::Active); + EXPECT_TRUE(candidate.isActive()); } -TEST_F(ModuleTest, EllipsoidalBoundary_Outside) { - EllipsoidalBoundary ellipsoid(Vector3(-5, 0, 0), Vector3(5, 0, 0), 15, - Candidate::Stopped); +TEST(EllipsoidalBoundary, Outside) { + EllipsoidalBoundary ellipsoid(Vector3(-5, 0, 0), Vector3(5, 0, 0), 15); + Candidate candidate; candidate.current.setPosition(Vector3(0, 25, 0)); ellipsoid.process(&candidate); - EXPECT_EQ(candidate.getStatus(), Candidate::Stopped); + EXPECT_FALSE(candidate.isActive()); } -TEST_F(ModuleTest, EllipsoidalBoundary_LimitStep) { - EllipsoidalBoundary ellipsoid(Vector3(-5, 0, 0), Vector3(5, 0, 0), 15, 0.5, - Candidate::Stopped); +TEST(EllipsoidalBoundary, LimitStep) { + EllipsoidalBoundary ellipsoid(Vector3(-5, 0, 0), Vector3(5, 0, 0), 15, 0.5); + Candidate candidate; candidate.setNextStep(2); candidate.current.setPosition(Vector3(7, 0, 0)); ellipsoid.process(&candidate); diff --git a/test/testCore.cpp b/test/testCore.cpp index 57cc88434..fcd6f4f75 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -5,34 +5,34 @@ namespace mpc { -TEST(testParticleState, position) { +TEST(ParticleState, position) { ParticleState particle; Vector3 v(1, 3, 5); particle.setPosition(v * Mpc); EXPECT_TRUE(particle.getPosition() == v * Mpc); } -TEST(testParticleState, energy) { +TEST(ParticleState, energy) { ParticleState particle; particle.setEnergy(10 * EeV); EXPECT_EQ(particle.getEnergy(), 10 * EeV); } -TEST(testParticleState, direction) { +TEST(ParticleState, direction) { ParticleState particle; Vector3 v(1, 2, 3); particle.setDirection(v); EXPECT_TRUE(particle.getDirection() == v / v.mag()); } -TEST(testParticleState, velocity) { +TEST(ParticleState, velocity) { ParticleState particle; Vector3 v(1, 1, 0); particle.setDirection(v); EXPECT_TRUE(particle.getVelocity() == v / v.mag() * c_light); } -TEST(testParticleState, momentum) { +TEST(ParticleState, momentum) { ParticleState particle; Vector3 v(0, 1, 0); particle.setDirection(v); @@ -40,27 +40,27 @@ TEST(testParticleState, momentum) { EXPECT_TRUE(particle.getMomentum() == v * (particle.getEnergy() / c_light)); } -TEST(testParticleState, id) { +TEST(ParticleState, id) { ParticleState particle; particle.setId(1045026000); EXPECT_EQ(particle.getId(), 1045026000); } -TEST(testParticleState, charge) { +TEST(ParticleState, charge) { ParticleState particle; particle.setId(1056026000); EXPECT_EQ(particle.getChargeNumber(), 26); EXPECT_DOUBLE_EQ(particle.getCharge(), 26 * eplus); } -TEST(testParticleState, mass) { +TEST(ParticleState, mass) { ParticleState particle; particle.setId(1056026000); EXPECT_EQ(particle.getMassNumber(), 56); EXPECT_DOUBLE_EQ(particle.getMass(), 56 * amu); } -TEST(testParticleState, lorentzFactor) { +TEST(ParticleState, lorentzFactor) { ParticleState particle; particle.setId(1010005000); particle.setEnergy(1e12 * eV); @@ -68,13 +68,13 @@ TEST(testParticleState, lorentzFactor) { EXPECT_DOUBLE_EQ(particle.getLorentzFactor(), lf); } -TEST(testCandidate, currentStep) { +TEST(Candidate, currentStep) { Candidate candidate; candidate.setCurrentStep(1 * Mpc); EXPECT_DOUBLE_EQ(candidate.getCurrentStep(), 1 * Mpc); } -TEST(testCandidate, limitNextStep) { +TEST(Candidate, limitNextStep) { Candidate candidate; candidate.setNextStep(5 * Mpc); EXPECT_DOUBLE_EQ(candidate.getNextStep(), 5 * Mpc); @@ -84,16 +84,20 @@ TEST(testCandidate, limitNextStep) { EXPECT_DOUBLE_EQ(candidate.getNextStep(), 2 * Mpc); } -TEST(testCandidate, status) { +TEST(Candidate, isActive) { Candidate candidate; - candidate.setStatus(Candidate::Active); - EXPECT_EQ(candidate.getStatus(), Candidate::Active); - candidate.setStatus(Candidate::Detected); - EXPECT_EQ(candidate.getStatus(), Candidate::Detected); - candidate.setStatus(Candidate::Stopped); - EXPECT_EQ(candidate.getStatus(), Candidate::Stopped); - candidate.setStatus(Candidate::UserDefined); - EXPECT_EQ(candidate.getStatus(), Candidate::UserDefined); + EXPECT_TRUE(candidate.isActive()); + candidate.setActive(false); + EXPECT_FALSE(candidate.isActive()); +} + +TEST(Candidate, property) { + Candidate candidate; + candidate.setProperty("foo","bar"); + EXPECT_TRUE(candidate.hasProperty("foo")); + std::string value; + candidate.getProperty("foo", value); + EXPECT_EQ("bar", value); } TEST(common, digit) { From 74c5a88b08a078de5c814257ba960fd486dbfcda Mon Sep 17 00:00:00 2001 From: geromueller Date: Tue, 27 Mar 2012 13:36:31 +0200 Subject: [PATCH 0019/1298] use simple stepping for neutral particles in DeflectionCK --- src/module/DeflectionCK.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index f88169fec..7047ba4ef 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -43,6 +43,15 @@ std::string DeflectionCK::getDescription() const { } void DeflectionCK::process(Candidate *candidate) const { + if (candidate->current.getChargeNumber() == 0) { + double nextStep = std::max(minimumStep, candidate->getNextStep()); + Vector3 pos = candidate->current.getPosition(); + Vector3 dir = candidate->current.getDirection(); + candidate->current.setPosition(pos + dir * nextStep); + candidate->setCurrentStep(nextStep); + candidate->setNextStep(nextStep * 5); + return; + } PhasePoint yIn(candidate->current.getPosition(), candidate->current.getMomentum()); From d433da0f0ad6a2583973d2b0ed54744d84001dea Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 27 Mar 2012 14:03:44 +0200 Subject: [PATCH 0020/1298] make Candidate.active private --- include/mpc/Candidate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mpc/Candidate.h b/include/mpc/Candidate.h index da09d20e5..026f52f6b 100644 --- a/include/mpc/Candidate.h +++ b/include/mpc/Candidate.h @@ -33,12 +33,12 @@ struct InteractionState { */ class Candidate: public Referenced { public: - bool active; ParticleState current; ParticleState initial; std::vector > secondaries; private: + bool active; double redshift, trajectoryLength; double currentStep, nextStep; std::map properties; From e8d1478ca6b363fc814891fcfd477b21020d33cc Mon Sep 17 00:00:00 2001 From: geromueller Date: Tue, 27 Mar 2012 15:43:50 +0200 Subject: [PATCH 0021/1298] add HepPID library --- CMakeLists.txt | 6 + libs/HepPID/CMakeLists.txt | 19 + .../include/HepPID/ParticleIDMethods.hh | 111 + .../include/HepPID/ParticleIDTranslations.hh | 85 + libs/HepPID/include/HepPID/ParticleName.hh | 42 + libs/HepPID/include/HepPID/Version.hh | 23 + libs/HepPID/src/ParticleIDMethods.cc | 559 +++++ libs/HepPID/src/ParticleName.cc | 1999 +++++++++++++++++ libs/HepPID/src/Version.cc | 30 + libs/HepPID/src/translateEvtGen.cc | 724 ++++++ libs/HepPID/src/translateGeanttoPDT.cc | 97 + libs/HepPID/src/translateHerwig.cc | 641 ++++++ libs/HepPID/src/translateIsajet.cc | 1003 +++++++++ libs/HepPID/src/translatePDG.cc | 503 +++++ libs/HepPID/src/translatePDTtoGeant.cc | 100 + libs/HepPID/src/translatePythia.cc | 827 +++++++ libs/HepPID/src/translateQQ.cc | 656 ++++++ 17 files changed, 7425 insertions(+) create mode 100644 libs/HepPID/CMakeLists.txt create mode 100644 libs/HepPID/include/HepPID/ParticleIDMethods.hh create mode 100644 libs/HepPID/include/HepPID/ParticleIDTranslations.hh create mode 100644 libs/HepPID/include/HepPID/ParticleName.hh create mode 100644 libs/HepPID/include/HepPID/Version.hh create mode 100644 libs/HepPID/src/ParticleIDMethods.cc create mode 100644 libs/HepPID/src/ParticleName.cc create mode 100644 libs/HepPID/src/Version.cc create mode 100644 libs/HepPID/src/translateEvtGen.cc create mode 100644 libs/HepPID/src/translateGeanttoPDT.cc create mode 100644 libs/HepPID/src/translateHerwig.cc create mode 100644 libs/HepPID/src/translateIsajet.cc create mode 100644 libs/HepPID/src/translatePDG.cc create mode 100644 libs/HepPID/src/translatePDTtoGeant.cc create mode 100644 libs/HepPID/src/translatePythia.cc create mode 100644 libs/HepPID/src/translateQQ.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index d5d30e74e..d25970642 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,12 @@ add_subdirectory(libs/kiss) list (APPEND MPC_EXTRA_LIBRARIES kiss) list (APPEND MPC_EXTRA_INCLUDES libs/kiss/include) +# HepID provided +add_subdirectory(libs/HepPID) +list (APPEND MPC_EXTRA_LIBRARIES HepPID) +list (APPEND MPC_EXTRA_INCLUDES libs/HepPID/include) + + include(FindOpenMP) if(OPENMP_FOUND) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") diff --git a/libs/HepPID/CMakeLists.txt b/libs/HepPID/CMakeLists.txt new file mode 100644 index 000000000..d9e31fd8b --- /dev/null +++ b/libs/HepPID/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 2.6) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) + +add_library(HepPID + src/ParticleIDMethods.cc + src/ParticleName.cc + src/Version.cc + src/translateEvtGen.cc + src/translateGeanttoPDT.cc + src/translateHerwig.cc + src/translateIsajet.cc + src/translatePDG.cc + src/translatePDTtoGeant.cc + src/translatePythia.cc + src/translateQQ.cc +) + +SET_TARGET_PROPERTIES(HepPID PROPERTIES COMPILE_FLAGS -fPIC) diff --git a/libs/HepPID/include/HepPID/ParticleIDMethods.hh b/libs/HepPID/include/HepPID/ParticleIDMethods.hh new file mode 100644 index 000000000..42aef6065 --- /dev/null +++ b/libs/HepPID/include/HepPID/ParticleIDMethods.hh @@ -0,0 +1,111 @@ +// ---------------------------------------------------------------------- +// +// ParticleIDMethods.hh +// Author: Lynn Garren +// +// various utilities to extract information from the particle ID +// +// In the standard numbering scheme, the PID digits (base 10) are: +// +/- n nr nl nq1 nq2 nq3 nj +// It is expected that any 7 digit number used as a PID will adhere to +// the Monte Carlo numbering scheme documented by the PDG. +// Note that many "new" particles not explicitly defined already +// can be expressed within this numbering scheme. +// +// These are the same methods that can be found in HepPDT::ParticleID +// ---------------------------------------------------------------------- +#ifndef PARTICLE_ID_METHODS_HH +#define PARTICLE_ID_METHODS_HH + +namespace HepPID { + +/// PID digits (base 10) are: n nr nl nq1 nq2 nq3 nj +/// The location enum provides a convenient index into the PID. +enum location { nj=1, nq3, nq2, nq1, nl, nr, n, n8, n9, n10 }; + +/// return the digit at a named location in the PID +unsigned short digit( location loc, const int & pid ); + +/// if this is a nucleus (ion), get A +/// Ion numbers are +/- 10LZZZAAAI. +int A(const int & pid ); + +/// if this is a nucleus (ion), get Z +/// Ion numbers are +/- 10LZZZAAAI. +int Z(const int & pid ); + +/// if this is a nucleus (ion), get nLambda +/// Ion numbers are +/- 10LZZZAAAI. +int lambda( const int & pid ); + +/// absolute value of particle ID +int abspid( const int & pid ); + +/// extract fundamental ID (1-100) if this is a "fundamental" particle +int fundamentalID( const int & pid ); +/// if this is a fundamental particle, does it have a valid antiparticle? +bool hasFundamentalAnti( const int & pid ); + +/// returns everything beyond the 7th digit +/// (e.g. outside the standard numbering scheme) +int extraBits( const int & pid ); + +// --- boolean methods: +// +/// is this a valid ID? +bool isValid( const int & pid ); +/// is this a valid meson ID? +bool isMeson( const int & pid ); +/// is this a valid baryon ID? +bool isBaryon( const int & pid ); +/// is this a valid diquark ID? +bool isDiQuark( const int & pid ); +/// is this a valid hadron ID? +bool isHadron( const int & pid ); +/// is this a valid lepton ID? +bool isLepton( const int & pid ); +/// is this a valid ion ID? +bool isNucleus( const int & pid ); +/// is this a valid pentaquark ID? +bool isPentaquark( const int & pid ); +/// is this a valid SUSY ID? +bool isSUSY( const int & pid ); +/// is this a valid R-hadron ID? +bool isRhadron( const int & pid ); +/// is this a valid Dyon (magnetic monopole) ID? +bool isDyon( const int & pid ); +/// Check for QBall or any exotic particle with electric charge beyond the qqq scheme +/// Ad-hoc numbering for such particles is 100xxxx0, where xxxx is the charge in tenths. +bool isQBall( const int & pid ); + +/// does this particle contain an up quark? +bool hasUp( const int & pid ); +/// does this particle contain a down quark? +bool hasDown( const int & pid ); +/// does this particle contain a strange quark? +bool hasStrange( const int & pid ); +/// does this particle contain a charm quark? +bool hasCharm( const int & pid ); +/// does this particle contain a bottom quark? +bool hasBottom( const int & pid ); +/// does this particle contain a top quark? +bool hasTop( const int & pid ); + +// --- other information +// +/// jSpin returns 2J+1, where J is the total spin +int jSpin( const int & pid ); +/// sSpin returns 2S+1, where S is the spin +int sSpin( const int & pid ); +/// lSpin returns 2L+1, where L is the orbital angular momentum +int lSpin( const int & pid ); +/// return 3 times the charge (3 x quark charge is an int) +/// If this is a Q-ball, return 30 times the charge. +int threeCharge( const int & pid ); +/// return the actual charge +double charge( const int & pid ); + + +} // HepPID + +#endif // PARTICLE_ID_METHODS_HH diff --git a/libs/HepPID/include/HepPID/ParticleIDTranslations.hh b/libs/HepPID/include/HepPID/ParticleIDTranslations.hh new file mode 100644 index 000000000..f7c756b32 --- /dev/null +++ b/libs/HepPID/include/HepPID/ParticleIDTranslations.hh @@ -0,0 +1,85 @@ +#ifndef PARTICLE_ID_TRANSLATIONS_HH +#define PARTICLE_ID_TRANSLATIONS_HH +// ---------------------------------------------------------------------- +// +// ParticleIDTranslations.hh +// Author: Lynn Garren +// +// ..convert between various numbering implementations +// +// ---------------------------------------------------------------------- + +#include + +//! The HepPID namespace has independent particle ID translation methods + +/// +/// \namespace HepPID +/// The HepPID namespace contains a set of independent +/// particle ID translation methods +/// +namespace HepPID { + +// translate between generator ID's and standard numbering scheme + +// Herwig translations +/// translate Herwig to PDG standard +int translateHerwigtoPDT( const int herwigID); +/// translate PDG standard to Herwig +int translatePDTtoHerwig( const int pid ); +/// output the translation list +void writeHerwigTranslation( std::ostream & os ); + +// Isajet translations +/// translate Isajet to PDG standard +int translateIsajettoPDT( const int isajetID ); +/// translate PDG standard to Isajet +int translatePDTtoIsajet( const int pid ); +/// output the translation list +void writeIsajetTranslation( std::ostream & os ); + +// Pythia translations +/// translate Pythia to PDG standard +int translatePythiatoPDT( const int pythiaID ); +/// translate PDG standard to Pythia +int translatePDTtoPythia( const int pid ); +/// output the translation list +void writePythiaTranslation( std::ostream & os ); + +// EvtGen translations +/// translate EvtGen to PDG standard +int translateEvtGentoPDT( const int evtGenID ); +/// translate PDG standard to EvtGen +int translatePDTtoEvtGen( const int pid ); +/// output the translation list +void writeEvtGenTranslation( std::ostream & os ); + +// PDG table translations (yes,there can be differences) +/// translate PDG table to PDG standard +int translatePDGtabletoPDT( const int pdgID); +/// translate PDG standard to PDG table +int translatePDTtoPDGtable( const int pid ); +/// output the translation list +void writePDGTranslation( std::ostream & os ); + +// QQ translations +/// translate QQ to PDG standard +int translateQQtoPDT( const int qqID); +/// translate PDG standard to QQ +int translatePDTtoQQ( const int pid ); +/// QQ helper function +int translateQQbar( const int id ); +/// QQ helper function +int translateInverseQQbar( const int id ); +/// output the translation list +void writeQQTranslation( std::ostream & os ); + +// Geant3 translations +/// translate Geant3 to PDG standard +int translateGeanttoPDT( const int geantID); +/// translate PDG standard to Geant3 +int translatePDTtoGeant( const int pid ); + +} // namespace HepPID + +#endif // PARTICLE_ID_TRANSLATIONS_HH diff --git a/libs/HepPID/include/HepPID/ParticleName.hh b/libs/HepPID/include/HepPID/ParticleName.hh new file mode 100644 index 000000000..2a9c58d6c --- /dev/null +++ b/libs/HepPID/include/HepPID/ParticleName.hh @@ -0,0 +1,42 @@ +#ifndef PARTICLENAME_HH +#define PARTICLENAME_HH +// ---------------------------------------------------------------------- +// +// ParticleName.hh +// Author: Lynn Garren and Walter Brown +// +// Create a map that gives a standard name for each pre-defined +// particle ID number. This map is initialized if and only if +// the public functions are called. Because the map is static, +// the initialization happens only once. +// +// +// ---------------------------------------------------------------------- + +#include +#include +#include + +namespace HepPID { + +/// get a known HepPID Particle name +std::string particleName( const int & ); +/// lookup a known ID +int particleName( const std::string & ); + +/// list all known names +void listParticleNames( std::ostream & os ); + +/// verify that this number has a valid name +bool validParticleName( const int & ); +/// verify that this string has a valid id +bool validParticleName( const std::string & ); + +// forward definition of ParticleNameMap class +class ParticleNameMap; +/// access the ParticleNameMap for other purposes +ParticleNameMap const & getParticleNameMap(); + +} // namespace HepPID + +#endif // PARTICLENAME_HH diff --git a/libs/HepPID/include/HepPID/Version.hh b/libs/HepPID/include/HepPID/Version.hh new file mode 100644 index 000000000..757c5b1d2 --- /dev/null +++ b/libs/HepPID/include/HepPID/Version.hh @@ -0,0 +1,23 @@ +// ---------------------------------------------------------------------- +// +// Version.hh +// Author: Lynn Garren +// +// for now, this is a free function +// +// ---------------------------------------------------------------------- +#ifndef HepPIDVERSION_HH +#define HepPIDVERSION_HH + +#include +#include + +namespace HepPID { + +void version( ); //!< print HepPID version +void writeVersion( std::ostream & os ); //!< write HepPID version to os +std::string versionName( ); //!< return HepPID version + +} // HepPID + +#endif // HepPIDVERSION_HH diff --git a/libs/HepPID/src/ParticleIDMethods.cc b/libs/HepPID/src/ParticleIDMethods.cc new file mode 100644 index 000000000..cf9297073 --- /dev/null +++ b/libs/HepPID/src/ParticleIDMethods.cc @@ -0,0 +1,559 @@ +// ---------------------------------------------------------------------- +// +// ParticleIDMethods.cc +// +// ---------------------------------------------------------------------- + +#include // for pow() + +#include "HepPID/ParticleIDMethods.hh" +#include "HepPID/ParticleName.hh" + +namespace HepPID { + +namespace { + +// internal function used by hasXXX methods +bool findQ( const int & pid, const int & q ) +{ + if( isDyon(pid) ) { return false; } + if( isRhadron(pid) ) { + int iz = 7; + for( int i=6; i > 1; --i ) { + if( digit(location(i),pid) == 0 ) { + iz = i; + } else if ( i == iz-1 ) { + // ignore squark or gluino + } else { + if( digit(location(i),pid) == q ) { return true; } + } + } + return false; + } + if( digit(nq3,pid) == q || digit(nq2,pid) == q || digit(nq1,pid) == q ) { return true; } + if( isPentaquark(pid) ) { + if( digit(nl,pid) == q || digit(nr,pid) == q ) { return true; } + } + return false; +} + +} + +// absolute value +int abspid( const int & pid ) +{ + return (pid < 0) ? -pid : pid; +} + +// returns everything beyond the 7th digit (e.g. outside the numbering scheme) +int extraBits( const int & pid ) +{ + return abspid(pid)/10000000; +} + +// split the PID into constituent integers +unsigned short digit( location loc, const int & pid ) +{ + // PID digits (base 10) are: n nr nl nq1 nq2 nq3 nj + // the location enum provides a convenient index into the PID + int numerator = (int) std::pow(10.0,(loc-1)); + return (abspid(pid)/numerator)%10; +} + +// return the first two digits if this is a "fundamental" particle +// ID = 100 is a special case (internal generator ID's are 81-100) +int fundamentalID( const int & pid ) +{ + if( extraBits(pid) > 0 ) return 0; + if( digit(nq2,pid) == 0 && digit(nq1,pid) == 0) { + return abspid(pid)%10000; + } else if( abspid(pid) <= 100 ) { + return abspid(pid); + } else { + return 0; + } +} + +// Ion numbers are +/- 10LZZZAAAI. +int Z( const int & pid ) +{ + // a proton can also be a Hydrogen nucleus + if( abspid(pid) == 2212 ) { return 1; } + if( isNucleus(pid) ) return (abspid(pid)/10000)%1000; + return 0; +} + +// Ion numbers are +/- 10LZZZAAAI. +int A( const int & pid ) +{ + // a proton can also be a Hydrogen nucleus + if( abspid(pid) == 2212 ) { return 1; } + if( isNucleus(pid) ) return (abspid(pid)/10)%1000; + return 0; +} + +// if this is a nucleus (ion), get nLambda +// Ion numbers are +/- 10LZZZAAAI. +int lambda( const int & pid ) +{ + // a proton can also be a Hydrogen nucleus + if( abspid(pid) == 2212 ) { return 0; } + if( isNucleus(pid) ) return digit(n8,pid); + return 0; +} + + +// --- boolean methods: +// + +// check to see if this is a valid PID +bool isValid( const int & pid ) +{ + if( extraBits(pid) > 0 ) { + if( isNucleus(pid) ) { return true; } + if( isQBall(pid) ) { return true; } + return false; + } + if( isSUSY(pid) ) { return true; } + if( isRhadron(pid) ) { return true; } + if( isDyon(pid) ) { return true; } + // Meson signature + if( isMeson(pid) ) { return true; } + // Baryon signature + if( isBaryon(pid) ) { return true; } + // DiQuark signature + if( isDiQuark(pid) ) { return true; } + // fundamental particle + if( fundamentalID(pid) > 0 ) { + if(pid > 0 ) { + return true; + } else { + if( hasFundamentalAnti(pid) ) { return true; } + return false; + } + } + // pentaquark + if( isPentaquark(pid) ) { return true; } + // don't recognize this number + return false; +} + +// if this is a fundamental particle, does it have a valid antiparticle? +bool hasFundamentalAnti( const int & pid ) +{ + // these are defined by the generator and therefore are always valid + if( fundamentalID(pid) <= 100 && fundamentalID(pid) >= 80 ) { return true; } + // check id's from 1 to 79 + if( fundamentalID(pid) > 0 && fundamentalID(pid) < 80 ) { + if( validParticleName(-pid) ) { return true; } + } + return false; +} + +// check to see if this is a valid meson +bool isMeson( const int & pid ) +{ + if( extraBits(pid) > 0 ) { return false; } + if( abspid(pid) <= 100 ) { return false; } + if( fundamentalID(pid) <= 100 && fundamentalID(pid) > 0 ) { return false; } + if( isRhadron(pid) ) { return false; } + int aid = abspid(pid); + if( aid == 130 || aid == 310 || aid == 210 ) { return true; } + // EvtGen uses some odd numbers + if( aid == 150 || aid == 350 || aid == 510 || aid == 530 ) { return true; } + // pomeron, etc. + if( pid == 110 || pid == 990 || pid == 9990 ) { return true; } + if( digit(nj,pid) > 0 && digit(nq3,pid) > 0 + && digit(nq2,pid) > 0 && digit(nq1,pid) == 0 ) { + // check for illegal antiparticles + if( digit(nq3,pid) == digit(nq2,pid) && pid < 0 ) { + return false; + } else { + return true; + } + } + return false; +} + +// check to see if this is a valid baryon +bool isBaryon( const int & pid ) +{ + if( extraBits(pid) > 0 ) { return false; } + if( abspid(pid) <= 100 ) { return false; } + if( fundamentalID(pid) <= 100 && fundamentalID(pid) > 0 ) { return false; } + if( isRhadron(pid) ) { return false; } + if( isPentaquark(pid) ) { return false; } + if( abspid(pid) == 2110 || abspid(pid) == 2210 ) { return true; } + if( digit(nj,pid) > 0 && digit(nq3,pid) > 0 + && digit(nq2,pid) > 0 && digit(nq1,pid) > 0 ) { return true; } + return false; +} + +// check to see if this is a valid diquark +bool isDiQuark( const int & pid ) +{ + if( extraBits(pid) > 0 ) { return false; } + if( abspid(pid) <= 100 ) { return false; } + if( fundamentalID(pid) <= 100 && fundamentalID(pid) > 0 ) { return false; } + if( digit(nj,pid) > 0 && digit(nq3,pid) == 0 + && digit(nq2,pid) > 0 && digit(nq1,pid) > 0 ) { // diquark signature + // EvtGen uses the diquarks for quark pairs, so, for instance, + // 5501 is a valid "diquark" for EvtGen + //if( digit(nj) == 1 && digit(nq2) == digit(nq1) ) { // illegal + // return false; + //} else { + return true; + //} + } + return false; +} + +// is this a valid hadron ID? +bool isHadron( const int & pid ) +{ + if( extraBits(pid) > 0 ) { return false; } + if( isMeson(pid) ) { return true; } + if( isBaryon(pid) ) { return true; } + if( isPentaquark(pid) ) { return true; } + if( isRhadron(pid) ) { return true; } + return false; +} +// is this a valid lepton ID? +bool isLepton( const int & pid ) +{ + if( extraBits(pid) > 0 ) { return false; } + if( fundamentalID(pid) >= 11 && fundamentalID(pid) <= 18 ) { return true; } + return false; +} + +// +// This implements the 2006 Monte Carlo nuclear code scheme. +// Ion numbers are +/- 10LZZZAAAI. +// AAA is A - total baryon number +// ZZZ is Z - total charge +// L is the total number of strange quarks. +// I is the isomer number, with I=0 corresponding to the ground state. +bool isNucleus( const int & pid ) +{ + // a proton can also be a Hydrogen nucleus + if( abspid(pid) == 2212 ) { return true; } + // new standard: +/- 10LZZZAAAI + if( ( digit(n10,pid) == 1 ) && ( digit(n9,pid) == 0 ) ) { + // charge should always be less than or equal to baryon number + // the following line is A >= Z + if( (abspid(pid)/10)%1000 >= (abspid(pid)/10000)%1000 ) { return true; } + } + return false; +} + +// check to see if this is a valid pentaquark +bool isPentaquark( const int & pid ) +{ + // a pentaquark is of the form 9abcdej, + // where j is the spin and a, b, c, d, and e are quarks + if( extraBits(pid) > 0 ) { return false; } + if( digit(n,pid) != 9 ) { return false; } + if( digit(nr,pid) == 9 || digit(nr,pid) == 0 ) { return false; } + if( digit(nj,pid) == 9 || digit(nl,pid) == 0 ) { return false; } + if( digit(nq1,pid) == 0 ) { return false; } + if( digit(nq2,pid) == 0 ) { return false; } + if( digit(nq3,pid) == 0 ) { return false; } + if( digit(nj,pid) == 0 ) { return false; } + // check ordering + if( digit(nq2,pid) > digit(nq1,pid) ) { return false; } + if( digit(nq1,pid) > digit(nl,pid) ) { return false; } + if( digit(nl,pid) > digit(nr,pid) ) { return false; } + return true; +} + +// is this a SUSY? +bool isSUSY( const int & pid ) +{ + // fundamental SUSY particles have n = 1 or 2 + if( extraBits(pid) > 0 ) { return false; } + if( digit(n,pid) != 1 && digit(n,pid) != 2 ) { return false; } + if( digit(nr,pid) != 0 ) { return false; } + // check fundamental part + if( fundamentalID(pid) == 0 ) { return false; } + return true; +} + +// is this an R-hadron? +bool isRhadron( const int & pid ) +{ + // an R-hadron is of the form 10abcdj, 100abcj, or 1000abj + // where j is the spin, b, c, and d are quarks or gluons, + // and a (the digit following the zero's) is a SUSY particle + if( extraBits(pid) > 0 ) { return false; } + if( digit(n,pid) != 1 ) { return false; } + if( digit(nr,pid) != 0 ) { return false; } + // make sure this isn't a SUSY particle + if( isSUSY(pid) ) { return false; } + // All R-hadrons have at least 3 core digits + if( digit(nq2,pid) == 0 ) { return false; } + if( digit(nq3,pid) == 0 ) { return false; } + if( digit(nj,pid) == 0 ) { return false; } + return true; +} + +// is this a Dyon (magnetic monopole)? +bool isDyon( const int & pid ) +{ + ///Magnetic monopoles and Dyons are assumed to have one unit of + ///Dirac monopole charge and a variable integer number xyz units + ///of electric charge. + /// + ///Codes 411xyz0 are then used when the magnetic and electrical + ///charge sign agree and 412xyz0 when they disagree, + ///with the overall sign of the particle set by the magnetic charge. + ///For now no spin information is provided. + /// + if( extraBits(pid) > 0 ) { return false; } + if( digit(n,pid) != 4 ) { return false; } + if( digit(nr,pid) != 1 ) { return false; } + if( (digit(nl,pid) != 1) && (digit(nl,pid) != 2) ) { return false; } + // All Dyons have at least 1 core digit + if( digit(nq3,pid) == 0 ) { return false; } + // Dyons have spin zero for now + if( digit(nj,pid) != 0 ) { return false; } + return true; +} + +// Check for QBalls +// Ad-hoc numbering for such particles is 100xxxx0, +// where xxxx is the charge in tenths. +bool isQBall( const int & pid ) +{ + if( extraBits(pid) != 1 ) { return false; } + if( digit(n,pid) != 0 ) { return false; } + if( digit(nr,pid) != 0 ) { return false; } + // check the core number + if( (abspid(pid)/10)%10000 == 0 ) { return false; } + // these particles have spin zero for now + if( digit(nj,pid) != 0 ) { return false; } + return true; +} + +// does this particle contain an up quark? +bool hasUp( const int & pid) +{ + if( extraBits(pid) > 0 ) { return false; } + if( fundamentalID(pid) > 0 ) { return false; } + return findQ(pid,2); +} +// does this particle contain a down quark? +bool hasDown( const int & pid) +{ + if( extraBits(pid) > 0 ) { return false; } + if( fundamentalID(pid) > 0 ) { return false; } + return findQ(pid,1); +} +// does this particle contain a strange quark? +bool hasStrange( const int & pid ) +{ + if( extraBits(pid) > 0 ) { return false; } + if( fundamentalID(pid) > 0 ) { return false; } + return findQ(pid,3); +} +// does this particle contain a charm quark? +bool hasCharm( const int & pid ) +{ + if( extraBits(pid) > 0 ) { return false; } + if( fundamentalID(pid) > 0 ) { return false; } + return findQ(pid,4); +} +// does this particle contain a bottom quark? +bool hasBottom( const int & pid ) +{ + if( extraBits(pid) > 0 ) { return false; } + if( fundamentalID(pid) > 0 ) { return false; } + return findQ(pid,5); +} +// does this particle contain a top quark? +bool hasTop( const int & pid ) +{ + if( extraBits(pid) > 0 ) { return false; } + if( fundamentalID(pid) > 0 ) { return false; } + return findQ(pid,6); +} + +// --- other information +// +// jSpin returns 2J+1, where J is the total spin +int jSpin( const int & pid ) +{ + if( fundamentalID(pid) > 0 ) { + // some of these are known + int fund = fundamentalID(pid); + if( fund > 0 && fund < 7 ) return 2; + if( fund == 9 ) return 3; + if( fund > 10 && fund < 17 ) return 2; + if( fund > 20 && fund < 25 ) return 3; + return 0; + } else if( extraBits(pid) > 0 ) { + return 0; + } + return abspid(pid)%10; +} +// sSpin returns 2S+1, where S is the spin +int sSpin( const int & pid ) +{ + if( !isMeson(pid) ) { return 0; } + int inl = digit(nl,pid); + //int tent = digit(n,pid); + int js = digit(nj,pid); + if( digit(n,pid) == 9 ) { return 0; } // tentative ID + //if( tent == 9 ) { return 0; } // tentative assignment + if( inl == 0 && js >= 3 ) { + return 1; + } else if( inl == 0 && js == 1 ) { + return 0; + } else if( inl == 1 && js >= 3 ) { + return 0; + } else if( inl == 2 && js >= 3 ) { + return 1; + } else if( inl == 1 && js == 1 ) { + return 1; + } else if( inl == 3 && js >= 3 ) { + return 1; + } + // default to zero + return 0; +} +// lSpin returns 2L+1, where L is the orbital angular momentum +int lSpin( const int & pid ) +{ + if( !isMeson(pid) ) { return 0; } + int inl = digit(nl,pid); + //int tent = digit(n,pid); + int js = digit(nj,pid); + if( digit(n,pid) == 9 ) { return 0; } // tentative ID + if( inl == 0 && js == 3 ) { + return 0; + } else if( inl == 0 && js == 5 ) { + return 1; + } else if( inl == 0 && js == 7 ) { + return 2; + } else if( inl == 0 && js == 9 ) { + return 3; + } else if( inl == 0 && js == 1 ) { + return 0; + } else if( inl == 1 && js == 3 ) { + return 1; + } else if( inl == 1 && js == 5 ) { + return 2; + } else if( inl == 1 && js == 7 ) { + return 3; + } else if( inl == 1 && js == 9 ) { + return 4; + } else if( inl == 2 && js == 3 ) { + return 1; + } else if( inl == 2 && js == 5 ) { + return 2; + } else if( inl == 2 && js == 7 ) { + return 3; + } else if( inl == 2 && js == 9 ) { + return 4; + } else if( inl == 1 && js == 1 ) { + return 1; + } else if( inl == 3 && js == 3 ) { + return 2; + } else if( inl == 3 && js == 5 ) { + return 3; + } else if( inl == 3 && js == 7 ) { + return 4; + } else if( inl == 3 && js == 9 ) { + return 5; + } + // default to zero + return 0; +} + +// 3 times the charge +int threeCharge( const int & pid ) +{ + int charge=0; + int ida, sid; + unsigned short q1, q2, q3, ql; + static int ch100[100] = { -1, 2,-1, 2,-1, 2,-1, 2, 0, 0, + -3, 0,-3, 0,-3, 0,-3, 0, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 0, 0, 3, 0, 0, 0, + 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 6, 3, 6, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + q1 = digit(nq1,pid); + q2 = digit(nq2,pid); + q3 = digit(nq3,pid); + ql = digit(nl,pid); + ida = abspid(pid); + sid = fundamentalID(pid); + if( ida == 0 ) { // illegal + return 0; + } else if( isQBall(pid) ) { // QBall + charge = 3*((abspid(pid)/10)%10000); + } else if( extraBits(pid) > 0 ) { // ion + return 0; + } else if( isDyon(pid) ) { // Dyon + charge = 3*( (abspid(pid)/10)%1000 ); + // this is half right + // the charge sign will be changed below if pid < 0 + if( ql == 2 ) { + charge = -charge; + } + } else if( sid > 0 && sid <= 100 ) { // use table + charge = ch100[sid-1]; + if(ida==1000017 || ida==1000018) { charge = 0; } + if(ida==1000034 || ida==1000052) { charge = 0; } + if(ida==1000053 || ida==1000054) { charge = 0; } + if(ida==5100061 || ida==5100062) { charge = 6; } + } else if( digit(nj,pid) == 0 ) { // KL, Ks, or undefined + return 0; + } else if( isMeson(pid) ) { // mesons + if( q2 == 3 || q2 == 5 ) { + charge = ch100[q3-1] - ch100[q2-1]; + } else { + charge = ch100[q2-1] - ch100[q3-1]; + } + } else if( isRhadron(pid) ) { // Rhadron + if (( q1 == 0 ) || ( q1 == 9 )) { + if( q2 == 3 || q2 == 5 ) { + charge = ch100[q3-1] - ch100[q2-1]; + } else { + charge = ch100[q2-1] - ch100[q3-1]; + } + } else if( ql == 0 ) { + charge = ch100[q3-1] + ch100[q2-1] + ch100[q1-1]; + } else if ( digit(nr,pid) == 0 ) { + charge = ch100[q3-1] + ch100[q2-1] + ch100[q1-1] + ch100[ql-1]; + } + } else if( isDiQuark(pid) ) { // diquarks + charge = ch100[q2-1] + ch100[q1-1]; + } else if( isBaryon(pid) ) { // baryons + charge = ch100[q3-1] + ch100[q2-1] + ch100[q1-1]; + } else { // unknown + return 0; + } + if( charge == 0 ) { + return 0; + } else if( pid < 0 ) { + charge = -charge; + } + return charge; +} + +// the actual charge +double charge( const int & pid ) +{ + int tc = threeCharge(pid); + if( isQBall(pid) ) { + return double(tc)/30.; + } else { + return double(tc)/3.; + } +} + +} // HepPID diff --git a/libs/HepPID/src/ParticleName.cc b/libs/HepPID/src/ParticleName.cc new file mode 100644 index 000000000..b66c587b2 --- /dev/null +++ b/libs/HepPID/src/ParticleName.cc @@ -0,0 +1,1999 @@ +// ---------------------------------------------------------------------- +// +// ParticleName.cc +// Author: Lynn Garren and Walter Brown +// +// Create a map that gives a standard name for each pre-defined +// particle ID number. Also create a map for the reverse lookup of +// the ID number from a string. These maps are initialized if and only if +// the public functions are called. Because the maps are static, +// the initialization happens only once. +// +// The user NEVER calls ParticleNameInit() +// We use a data table (struct Snames) so that compile time is not impacted. +// +// public functions: +// PartcleIdMap const & getPartcleIdMap() +// std::string ParticleName( const int pid ) +// void listParticleNames( std::ostream & os ) +// +// ---------------------------------------------------------------------- + +#include +#include +#include +#include +#include // width +#include // make_pair + +#include "HepPID/ParticleName.hh" +#include "HepPID/ParticleIDMethods.hh" +#include "HepPID/Version.hh" + +namespace HepPID { + +typedef std::map< int, std::string > PartcleIdMap; +typedef std::map< std::string, int > ParticleLookupMap; + +/// +/// \class ParticleNameMap +/// \author Lynn Garren +/// +/// Used internally to store the static maps +/// +class ParticleNameMap{ + +public: + + typedef PartcleIdMap::const_iterator idIterator; + typedef ParticleLookupMap::const_iterator nameIterator; + + ParticleNameMap(PartcleIdMap m1,ParticleLookupMap m2) + : itsNameMap(m1), itsLookupMap(m2) {} + ~ParticleNameMap() {} + + PartcleIdMap nameMap() const { return itsNameMap; } + ParticleLookupMap lookupMap() const { return itsLookupMap; } + idIterator begin() const { return itsNameMap.begin(); } + idIterator end() const { return itsNameMap.end(); } + idIterator find( const int & id) const { return itsNameMap.find(id); } + nameIterator beginLookupMap() const { return itsLookupMap.begin(); } + nameIterator endLookupMap() const { return itsLookupMap.end(); } + nameIterator findString( const std::string & s) const { return itsLookupMap.find(s); } + +private: + + PartcleIdMap itsNameMap; + ParticleLookupMap itsLookupMap; + + // copies are not allowed + ParticleNameMap( const ParticleNameMap & ); + ParticleNameMap & operator = ( const ParticleNameMap & ); + +}; + +namespace { // ParticleNameInit and ParticleNameMap are private + +ParticleNameMap const & ParticleNameInit() +{ + + PartcleIdMap m; + ParticleLookupMap nameMap; + + static const struct { + int pid; + const char* pname; + } SNames[] = { + { 0, "" }, + { 1, "d" }, + { -1, "d~" }, + { 2, "u" }, + { -2, "u~" }, + { 3, "s" }, + { -3, "s~" }, + { 4, "c" }, + { -4, "c~" }, + { 5, "b" }, + { -5, "b~" }, + { 6, "t" }, + { -6, "t~" }, + { 7, "b'" }, + { -7, "b'~" }, + { 8, "t'" }, + { -8, "t'~" }, + { 11, "e^-" }, + { -11, "e^+" }, + { 12, "nu_e" }, + { -12, "nu_e~" }, + { 13, "mu^-" }, + { -13, "mu^+" }, + { 14, "nu_mu" }, + { -14, "nu_mu~" }, + { 15, "tau^-" }, + { -15, "tau^+" }, + { 16, "nu_tau" }, + { -16, "nu_tau~" }, + { 17, "tau'^-" }, + { -17, "tau'^+" }, + { 18, "nu_tau'" }, + { -18, "nu_tau'~" }, + { 21, "g" }, + { 22, "gamma" }, + { 10022, "virtual-photon" }, + { 20022, "Cerenkov-radiation" }, + { 23, "Z^0" }, + { 24, "W^+" }, + { -24, "W^-" }, + { 25, "H_1^0" }, + { 32, "Z_2^0" }, + { 33, "Z_3^0" }, + { 34, "W_2^+" }, + { -34, "W_2^-" }, + { 35, "H_2^0" }, + { 36, "H_3^0" }, + { 37, "H^+" }, + { -37, "H^-" }, + { 39, "G" }, + { 41, "R^0" }, + { -41, "R~^0" }, + { 42, "LQ_c" }, + { -42, "LQ_c~" }, + { 43, "Xu^0" }, + { 44, "Xu^+" }, + { -44, "Xu^-" }, + { 51, "H_L^0" }, + { 52, "H_1^++" }, + { -52, "H_1^--" }, + { 53, "H_2^+" }, + { -53, "H_2^-" }, + { 54, "H_2^++" }, + { -54, "H_2^--" }, + { 55, "H_4^0" }, + { -55, "H_4~^0" }, + { 81, "generator-specific+81" }, + { 82, "generator-specific+82" }, + { 83, "generator-specific+83" }, + { 84, "generator-specific+84" }, + { 85, "generator-specific+85" }, + { 86, "generator-specific+86" }, + { 87, "generator-specific+87" }, + { 88, "generator-specific+88" }, + { 89, "generator-specific+89" }, + { 90, "generator-specific+90" }, + { 91, "generator-specific+91" }, + { 92, "generator-specific+92" }, + { 93, "generator-specific+93" }, + { 94, "generator-specific+94" }, + { 95, "generator-specific+95" }, + { 96, "generator-specific+96" }, + { 97, "generator-specific+97" }, + { 98, "generator-specific+98" }, + { 99, "generator-specific+99" }, + { -81, "generator-specific-81" }, + { -82, "generator-specific-82" }, + { -83, "generator-specific-83" }, + { -84, "generator-specific-84" }, + { -85, "generator-specific-85" }, + { -86, "generator-specific-86" }, + { -87, "generator-specific-87" }, + { -88, "generator-specific-88" }, + { -89, "generator-specific-89" }, + { -90, "generator-specific-90" }, + { -91, "generator-specific-91" }, + { -92, "generator-specific-92" }, + { -93, "generator-specific-93" }, + { -94, "generator-specific-94" }, + { -95, "generator-specific-95" }, + { -96, "generator-specific-96" }, + { -97, "generator-specific-97" }, + { -98, "generator-specific-98" }, + { -99, "generator-specific-99" }, + { 100, "generator-specific+100" }, + { -100, "generator-specific-100" }, + { 101, "geantino" }, + { 102, "charged-geantino" }, + { 110, "reggeon" }, + { 130, "K_L^0" }, + { 310, "K_S^0" }, + { 990, "pomeron" }, + { 9990, "odderon" }, + { 1000001, "susy-d_L" }, + { -1000001, "susy-d_L~" }, + { 1000002, "susy-u_L" }, + { -1000002, "susy-u_L~" }, + { 1000003, "susy-s_L" }, + { -1000003, "susy-s_L~" }, + { 1000004, "susy-c_L" }, + { -1000004, "susy-c_L~" }, + { 1000005, "susy-b_1" }, + { -1000005, "susy-b_1~" }, + { 1000006, "susy-t_1" }, + { -1000006, "susy-t_1~" }, + { 1000011, "susy-e_L^-" }, + { -1000011, "susy-e_L^+" }, + { 1000012, "susy-nu_eL" }, + { -1000012, "susy-nu_eL~" }, + { 1000013, "susy-mu_L^-" }, + { -1000013, "susy-mu_L^+" }, + { 1000014, "susy-nu_muL" }, + { -1000014, "susy-nu_muL~" }, + { 1000015, "susy-tau_L^-" }, + { -1000015, "susy-tau_L^+" }, + { 1000016, "susy-nu_tauL" }, + { -1000016, "susy-nu_tauL~" }, + { 1000021, "gluino" }, + { 1000022, "susy-chi_1^0" }, + { 1000023, "susy-chi_2^0" }, + { 1000024, "susy-chi_1^+" }, + { -1000024, "susy-chi_1^-" }, + { 1000025, "susy-chi_3^0" }, + { 1000035, "susy-chi_4^0" }, + { 1000037, "susy-chi_2^+" }, + { -1000037, "susy-chi_2^-" }, + { 1000039, "gravitino" }, + { 2000001, "susy-d_R" }, + { -2000001, "susy-d_R~" }, + { 2000002, "susy-u_R" }, + { -2000002, "susy-u_R~" }, + { 2000003, "susy-s_R" }, + { -2000003, "susy-s_R~" }, + { 2000004, "susy-c_R" }, + { -2000004, "susy-c_R~" }, + { 2000005, "susy-b_R" }, + { -2000005, "susy-b_R~" }, + { 2000006, "susy-t_R" }, + { -2000006, "susy-t_R~" }, + { 2000011, "susy-e_R^-" }, + { -2000011, "susy-e_R^+" }, + { 2000012, "susy-nu_eR" }, + { -2000012, "susy-nu_eR~" }, + { 2000013, "susy-mu_R^-" }, + { -2000013, "susy-mu_R^+" }, + { 2000014, "susy-nu_muR" }, + { -2000014, "susy-nu_muR~" }, + { 2000015, "susy-tau_R^-" }, + { -2000015, "susy-tau_R^+" }, + { 2000016, "susy-nu_tauR" }, + { -2000016, "susy-nu_tauR~" }, + { 3100021, "V8_tech" }, + { -3100021, "V8_tech~" }, + { 3000111, "pi_tech^0" }, + { 3000115, "a_tech^0" }, + { 3060111, "pi_tech_22_1" }, + { 3160111, "pi_tech_22_8" }, + { 3000113, "rho_tech^0" }, + { 3130113, "rho_tech_11" }, + { 3140113, "rho_tech_12" }, + { 3150113, "rho_tech_21" }, + { 3160113, "rho_tech_22" }, + { 3000211, "pi_tech^+" }, + { -3000211, "pi_tech^-" }, + { 3000213, "rho_tech^+" }, + { -3000213, "rho_tech^-" }, + { 3000215, "a_tech^+" }, + { -3000215, "a_tech^-" }, + { 3000221, "pi'_tech" }, + { 3100221, "eta_tech" }, + { 3000223, "omega_tech" }, + { 4000001, "d*" }, + { -4000001, "d*~" }, + { 4000002, "u*" }, + { -4000002, "u*~" }, + { 4000011, "e*^-" }, + { -4000011, "e*^+" }, + { 4000012, "nu*_e" }, + { -4000012, "nu*_e~" }, + { 4000039, "G*" }, + { -4000039, "G*~" }, + { 5000040, "black_hole" }, + { 5100001, "d_L^(1)" }, + { -5100001, "d~_L^(1)" }, + { 5100002, "u_L^(1)" }, + { -5100002, "u~_L^(1)" }, + { 5100003, "s_L^(1)" }, + { -5100003, "s~_L^(1)" }, + { 5100004, "c_L^(1)" }, + { -5100004, "c~_L^(1)" }, + { 5100005, "b_L^(1)" }, + { -5100005, "b~_L^(1)" }, + { 5100006, "t_L^(1)" }, + { -5100006, "t~_L^(1)" }, + { 5100011, "e_L^(1)-" }, + { -5100011, "e_L^(1)+" }, + { 5100012, "nu_eL^(1)" }, + { -5100012, "nu_eL~^(1)" }, + { 5100013, "mu_L^(1)-" }, + { -5100013, "mu_L^(1)+" }, + { 5100014, "nu_muL^(1)" }, + { -5100014, "nu_muL~^(1)" }, + { 5100015, "tau_L^(1)-" }, + { -5100015, "tau_L^(1)+" }, + { 5100016, "nu_tauL^(1)" }, + { -5100016, "nu_tauL~^(1)" }, + { 6100001, "d_R^(1)" }, + { -6100001, "d~_R^(1)" }, + { 6100002, "u_R^(1)" }, + { -6100002, "u~_R^(1)" }, + { 6100003, "s_R^(1)" }, + { -6100003, "s~_R^(1)" }, + { 6100004, "c_R^(1)" }, + { -6100004, "c~_R^(1)" }, + { 6100005, "b_R^(1)" }, + { -6100005, "b~_R^(1)" }, + { 6100006, "t_R^(1)" }, + { -6100006, "t~_R^(1)" }, + { 6100011, "e_R^(1)-" }, + { -6100011, "e_R^(1)+" }, + { 6100012, "nu_eR^(1)" }, + { -6100012, "nu_eR~^(1)" }, + { 6100013, "mu_R^(1)-" }, + { -6100013, "mu_R^(1)+" }, + { 6100014, "nu_muR^(1)" }, + { -6100014, "nu_muR~^(1)" }, + { 6100015, "tau_R^(1)-" }, + { -6100015, "tau_R^(1)+" }, + { 6100016, "nu_tauR^(1)" }, + { -6100016, "nu_tauR~^(1)" }, + { 5100021, "g^(1)" }, + { 5100022, "gamma^(1)" }, + { 5100023, "Z^(1)0" }, + { 5100024, "W^(1)+" }, + { -5100024, "W^(1)-" }, + { 5100025, "h^(1)0" }, + { 5100039, "G^(1)" }, + { 9900012, "nu_Re" }, + { -9900012, "nu_Re~" }, + { 9900014, "nu_Rmu" }, + { -9900014, "nu_Rmu~" }, + { 9900016, "nu_Rtau" }, + { -9900016, "nu_Rtau~" }, + { 9900023, "Z_R^0" }, + { -9900023, "Z_R~^0" }, + { 9900024, "W_R^+" }, + { -9900024, "W_R^-" }, + { 9900041, "H_L^++" }, + { -9900041, "H_L^--" }, + { 9900042, "H_R^++" }, + { -9900042, "H_R^--" }, + { 9910113, "rho_diffr^0" }, + { 9910211, "pi_diffr^+" }, + { -9910211, "pi_diffr^-" }, + { 9910223, "omega_diffr" }, + { 9910333, "phi_diffr" }, + { 9910443, "psi_diffr" }, + { 9912112, "n_diffr^0" }, + { -9912112, "n_diffr~^0" }, + { 9912212, "p_diffr^+" }, + { -9912212, "p_diffr~^-" }, + { 9920022, "remnant photon" }, + { 9922212, "remnant nucleon" }, + { -9922212, "remnant nucleon~" }, + { 9900441, "cc~[1S08]" }, + { 9910441, "cc~[3P08]" }, + { 9900443, "cc~[3S18]" }, + { 9900551, "bb~[1S08]" }, + { 9910551, "bb~[3P08]" }, + { 9900553, "bb~[3S18]" }, + { 1103, "dd_1" }, + { -1103, "dd_1~" }, + { 2101, "ud_0" }, + { -2101, "ud_0~" }, + { 2103, "ud_1" }, + { -2103, "ud_1~" }, + { 2203, "uu_1" }, + { -2203, "uu_1~" }, + { 3101, "sd_0" }, + { -3101, "sd_0~" }, + { 3103, "sd_1" }, + { -3103, "sd_1~" }, + { 3201, "su_0" }, + { -3201, "su_0~" }, + { 3203, "su_1" }, + { -3203, "su_1~" }, + { 3303, "ss_1" }, + { -3303, "ss_1~" }, + { 4101, "cd_0" }, + { -4101, "cd_0~" }, + { 4103, "cd_1" }, + { -4103, "cd_1~" }, + { 4201, "cu_0" }, + { -4201, "cu_0~" }, + { 4203, "cu_1" }, + { -4203, "cu_1~" }, + { 4301, "cs_0" }, + { -4301, "cs_0~" }, + { 4303, "cs_1" }, + { -4303, "cs_1~" }, + { 4403, "cc_1" }, + { -4403, "cc_1~" }, + { 5101, "bd_0" }, + { -5101, "bd_0~" }, + { 5103, "bd_1" }, + { -5103, "bd_1~" }, + { 5201, "bu_0" }, + { -5201, "bu_0~" }, + { 5203, "bu_1" }, + { -5203, "bu_1~" }, + { 5301, "bs_0" }, + { -5301, "bs_0~" }, + { 5303, "bs_1" }, + { -5303, "bs_1~" }, + { 5401, "bc_0" }, + { -5401, "bc_0~" }, + { 5403, "bc_1" }, + { -5403, "bc_1~" }, + { 5503, "bb_1" }, + { -5503, "bb_1~" }, + { 6101, "td_0" }, + { -6101, "td_0~" }, + { 6103, "td_1" }, + { -6103, "td_1~" }, + { 6201, "tu_0" }, + { -6201, "tu_0~" }, + { 6203, "tu_1" }, + { -6203, "tu_1~" }, + { 6301, "ts_0" }, + { -6301, "ts_0~" }, + { 6303, "ts_1" }, + { -6303, "ts_1~" }, + { 6401, "tc_0" }, + { -6401, "tc_0~" }, + { 6403, "tc_1" }, + { -6403, "tc_1~" }, + { 6501, "tb_0" }, + { -6501, "tb_0~" }, + { 6503, "tb_1" }, + { -6503, "tb_1~" }, + { 6603, "tt_1" }, + { -6603, "tt_1~" }, + { 7101, "b'd_0" }, + { -7101, "b'd_0~" }, + { 7103, "b'd_1" }, + { -7103, "b'd_1~" }, + { 7201, "b'u_0" }, + { -7201, "b'u_0~" }, + { 7203, "b'u_1" }, + { -7203, "b'u_1~" }, + { 7301, "b's_0" }, + { -7301, "b's_0~" }, + { 7303, "b's_1" }, + { -7303, "b's_1~" }, + { 7401, "b'c_0" }, + { -7401, "b'c_0~" }, + { 7403, "b'c_1" }, + { -7403, "b'c_1~" }, + { 7501, "b'b_0" }, + { -7501, "b'b_0~" }, + { 7503, "b'b_1" }, + { -7503, "b'b_1~" }, + { 7601, "b't_0" }, + { -7601, "b't_0~" }, + { 7603, "b't_1" }, + { -7603, "b't_1~" }, + { 7703, "b'b'_1" }, + { -7703, "b'b'_1~" }, + { 8101, "t'd_0" }, + { -8101, "t'd_0~" }, + { 8103, "t'd_1" }, + { -8103, "t'd_1~" }, + { 8201, "t'u_0" }, + { -8201, "t'u_0~" }, + { 8203, "t'u_1" }, + { -8203, "t'u_1~" }, + { 8301, "t's_0" }, + { -8301, "t's_0~" }, + { 8303, "t's_1" }, + { -8303, "t's_1~" }, + { 8401, "t'c_0" }, + { -8401, "t'c_0~" }, + { 8403, "t'c_1" }, + { -8403, "t'c_1~" }, + { 8501, "t'b_0" }, + { -8501, "t'b_0~" }, + { 8503, "t'b_1" }, + { -8503, "t'b_1~" }, + { 8601, "t't_0" }, + { -8601, "t't_0~" }, + { 8603, "t't_1" }, + { -8603, "t't_1~" }, + { 8701, "t'b'_0" }, + { -8701, "t'b'_0~" }, + { 8703, "t'b'_1" }, + { -8703, "t'b'_1~" }, + { 8803, "t't'_1" }, + { -8803, "t't'_1~" }, + { 111, "pi^0" }, + { 9000111, "a_0(980)^0" }, + { 10111, "a_0(1450)^0" }, + { 100111, "pi(1300)^0" }, + { 9010111, "pi(1800)^0" }, + { 113, "rho(770)^0" }, + { 10113, "b_1(1235)^0" }, + { 20113, "a_1(1260)^0" }, + { 9000113, "pi_1(1400)^0" }, + { 100113, "rho(1450)^0" }, + { 9010113, "pi_1(1600)^0" }, + { 9020113, "a_1(1640)^0" }, + { 30113, "rho(1700)^0" }, + { 9030113, "rho(1900)^0" }, + { 9040113, "rho(2150)^0" }, + { 115, "a_2(1320)^0" }, + { 10115, "pi_2(1670)^0" }, + { 9000115, "a_2(1700)^0" }, + { 9010115, "pi_2(2100)^0" }, + { 117, "rho_3(1690)^0" }, + { 9000117, "rho_3(1990)^0" }, + { 9010117, "rho_3(2250)^0" }, + { 119, "a_4(2040)^0" }, + { 211, "pi^+" }, + { -211, "pi^-" }, + { 9000211, "a_0(980)^+" }, + { -9000211, "a_0(980)^-" }, + { 10211, "a_0(1450)^+" }, + { -10211, "a_0(1450)^-" }, + { 100211, "pi(1300)^+" }, + { -100211, "pi(1300)^-" }, + { 9010211, "pi(1800)^+" }, + { -9010211, "pi(1800)^-" }, + { 213, "rho(770)^+" }, + { -213, "rho(770)^-" }, + { 10213, "b_1(1235)^+" }, + { -10213, "b_1(1235)^-" }, + { 20213, "a_1(1260)^+" }, + { -20213, "a_1(1260)^-" }, + { 9000213, "pi_1(1400)^+" }, + { -9000213, "pi_1(1400)^-" }, + { 100213, "rho(1450)^+" }, + { -100213, "rho(1450)^-" }, + { 9010213, "pi_1(1600)^+" }, + { -9010213, "pi_1(1600)^-" }, + { 9020213, "a_1(1640)^+" }, + { -9020213, "a_1(1640)^-" }, + { 30213, "rho(1700)^+" }, + { -30213, "rho(1700)^-" }, + { 9030213, "rho(1900)^+" }, + { -9030213, "rho(1900)^-" }, + { 9040213, "rho(2150)^+" }, + { -9040213, "rho(2150)^-" }, + { 215, "a_2(1320)^+" }, + { -215, "a_2(1320)^-" }, + { 10215, "pi_2(1670)^+" }, + { -10215, "pi_2(1670)^-" }, + { 9000215, "a_2(1700)^+" }, + { -9000215, "a_2(1700)^-" }, + { 9010215, "pi_2(2100)^+" }, + { -9010215, "pi_2(2100)^-" }, + { 217, "rho_3(1690)^+" }, + { -217, "rho_3(1690)^-" }, + { 9000217, "rho_3(1990)^+" }, + { -9000217, "rho_3(1990)^-" }, + { 9010217, "rho_3(2250)^+" }, + { -9010217, "rho_3(2250)^-" }, + { 219, "a_4(2040)^+" }, + { -219, "a_4(2040)^-" }, + { 221, "eta" }, + { 9000221, "f_0(600)" }, + { 10221, "f_0(1370)" }, + { 9010221, "f_0(980)" }, + { 9020221, "eta(1405)" }, + { 9030221, "f_0(1500)" }, + { 9040221, "eta(1760)" }, + { 9050221, "f_0(2020)" }, + { 9060221, "f_0(2100)" }, + { 9070221, "f_0(2200)" }, + { 9080221, "eta(2225)" }, + { 9090221, "sigma_0" }, + { 100221, "eta(1295)" }, + { 331, "eta'(958)" }, + { 10331, "f_0(1710)" }, + { 100331, "eta(1475)" }, + { 223, "omega(782)" }, + { 9000223, "f_1(1510)" }, + { 9010223, "h_1(1595)" }, + { 10223, "h_1(1170)" }, + { 20223, "f_1(1285)" }, + { 30223, "omega(1650)" }, + { 100223, "omega(1420)" }, + { 333, "phi(1020)" }, + { 10333, "h_1(1380)" }, + { 20333, "f_1(1420)" }, + { 100333, "phi(1680)" }, + { 225, "f_2(1270)" }, + { 9000225, "f_2(1430)" }, + { 10225, "eta_2(1645)" }, + { 9010225, "f_2(1565)" }, + { 9020225, "f_2(1640)" }, + { 9030225, "f_2(1810)" }, + { 9040225, "f_2(1910)" }, + { 9050225, "f_2(1950)" }, + { 9060225, "f_2(2010)" }, + { 9070225, "f_2(2150)" }, + { 9080225, "f_2(2300)" }, + { 9090225, "f_2(2340)" }, + { 335, "f'_2(1525)" }, + { 10335, "eta_2(1870)" }, + { 227, "omega_3(1670)" }, + { 337, "phi_3(1850)" }, + { 229, "f_4(2050)" }, + { 9000229, "f_J(2220)" }, + { 9010229, "f_4(2300)" }, + { 311, "K^0" }, + { -311, "K~^0" }, + { 9000311, "K*_0(800)^0" }, + { -9000311, "K*_0(800)~^0" }, + { 10311, "K*_0(1430)^0" }, + { -10311, "K*_0(1430)~^0" }, + { 100311, "K(1460)^0" }, + { -100311, "K(1460)~^0" }, + { 9010311, "K(1830)^0" }, + { -9010311, "K(1830)~^0" }, + { 9020311, "K*_0(1950)^0" }, + { -9020311, "K*_0(1950)~^0" }, + { 321, "K^+" }, + { -321, "K^-" }, + { 9000321, "K*_0(800)^+" }, + { -9000321, "K*_0(800)^-" }, + { 10321, "K*_0(1430)^+" }, + { -10321, "K*_0(1430)^-" }, + { 100321, "K(1460)^+" }, + { -100321, "K(1460)^-" }, + { 9010321, "K(1830)^+" }, + { -9010321, "K(1830)^-" }, + { 9020321, "K*_0(1950)^+" }, + { -9020321, "K*_0(1950)^-" }, + { 313, "K*(892)^0" }, + { -313, "K*(892)~^0" }, + { 10313, "K_1(1270)^0" }, + { -10313, "K_1(1270)~^0" }, + { 20313, "K_1(1400)^0" }, + { -20313, "K_1(1400)~^0" }, + { 30313, "K*(1680)^0" }, + { -30313, "K*(1680)~^0" }, + { 100313, "K*(1410)^0" }, + { -100313, "K*(1410)~^0" }, + { 9000313, "K_1(1650)^0" }, + { -9000313, "K_1(1650)~^0" }, + { 323, "K*(892)^+" }, + { -323, "K*(892)^-" }, + { 10323, "K_1(1270)^+" }, + { -10323, "K_1(1270)^-" }, + { 20323, "K_1(1400)^+" }, + { -20323, "K_1(1400)^-" }, + { 30323, "K*(1680)^+" }, + { -30323, "K*(1680)^-" }, + { 100323, "K*(1410)^+" }, + { -100323, "K*(1410)^-" }, + { 9000323, "K_1(1650)^+" }, + { -9000323, "K_1(1650)^-" }, + { 315, "K*_2(1430)^0" }, + { -315, "K*_2(1430)~^0" }, + { 9000315, "K_2(1580)^0" }, + { -9000315, "K_2(1580)~^0" }, + { 10315, "K_2(1770)^0" }, + { -10315, "K_2(1770)~^0" }, + { 9010315, "K*_2(1980)^0" }, + { -9010315, "K*_2(1980)~^0" }, + { 9020315, "K_2(2250)^0" }, + { -9020315, "K_2(2250)~^0" }, + { 20315, "K_2(1820)^0" }, + { -20315, "K_2(1820)~^0" }, + { 325, "K*_2(1430)^+" }, + { -325, "K*_2(1430)^-" }, + { 9000325, "K_2(1580)^+" }, + { -9000325, "K_2(1580)^-" }, + { 10325, "K_2(1770)^+" }, + { -10325, "K_2(1770)^-" }, + { 9010325, "K*_2(1980)^+" }, + { -9010325, "K*_2(1980)^-" }, + { 9020325, "K_2(2250)^+" }, + { -9020325, "K_2(2250)^-" }, + { 20325, "K_2(1820)^+" }, + { -20325, "K_2(1820)^-" }, + { 100325, "K_2(1980)^+" }, + { -100325, "K_2(1980)^-" }, + { 317, "K*_3(1780)^0" }, + { -317, "K*_3(1780)~^0" }, + { 9010317, "K_3(2320)^0" }, + { -9010317, "K_3(2320)~^0" }, + { 327, "K*_3(1780)^+" }, + { -327, "K*_3(1780)^-" }, + { 9010327, "K_3(2320)^+" }, + { -9010327, "K_3(2320)^-" }, + { 319, "K*_4(2045)^0" }, + { -319, "K*_4(2045)~^0" }, + { 9000319, "K_4(2500)^0" }, + { -9000319, "K_4(2500)~^0" }, + { 329, "K*_4(2045)^+" }, + { -329, "K*_4(2045)^-" }, + { 9000329, "K_4(2500)^+" }, + { -9000329, "K_4(2500)^-" }, + { 411, "D^+" }, + { -411, "D^-" }, + { 10411, "D*_0(2400)^+" }, + { -10411, "D*_0(2400)^-" }, + { 100411, "D(2S)^+" }, + { -100411, "D(2S)^-" }, + { 413, "D*(2010)^+" }, + { -413, "D*(2010)^-" }, + { 10413, "D_1(2420)^+" }, + { -10413, "D_1(2420)^-" }, + { 20413, "D_1(H)^+" }, + { -20413, "D_1(H)^-" }, + { 100413, "D*(2S)^+" }, + { -100413, "D*(2S)^-" }, + { 415, "D*_2(2460)^+" }, + { -415, "D*_2(2460)^-" }, + { 421, "D^0" }, + { -421, "D~^0" }, + { 10421, "D*_0(2400)^0" }, + { -10421, "D*_0(2400)~^0" }, + { 100421, "D(2S)^0" }, + { -100421, "D(2S)~^0" }, + { 423, "D*(2007)^0" }, + { -423, "D*(2007)~^0" }, + { 10423, "D_1(2420)^0" }, + { -10423, "D_1(2420)~^0" }, + { 20423, "D_1(2430)^0" }, + { -20423, "D_1(2430)~^0" }, + { 100423, "D*(2S)^0" }, + { -100423, "D*(2S)~^0" }, + { 425, "D*_2(2460)^0" }, + { -425, "D*_2(2460)~^0" }, + { 431, "D_s^+" }, + { -431, "D_s^-" }, + { 10431, "D*_s0(2317)^+" }, + { -10431, "D*_s0(2317)^-" }, + { 433, "D*_s^+" }, + { -433, "D*_s^-" }, + { 10433, "D_s1(2536)^+" }, + { -10433, "D_s1(2536)^-" }, + { 20433, "D_s1(2460)^+" }, + { -20433, "D_s1(2460)^-" }, + { 435, "D*_s2(2573)^+" }, + { -435, "D*_s2(2573)^-" }, + { 441, "eta_c(1S)" }, + { 10441, "chi_c0(1P)" }, + { 100441, "eta_c(2S)" }, + { 443, "J/psi(1S)" }, + { 9000443, "psi(4040)" }, + { 10443, "hc(1P)" }, + { 9010443, "psi(4160)" }, + { 20443, "chi_c1(1P)" }, + { 9020443, "psi(4415)" }, + { 30443, "psi(3770)" }, + { 100443, "psi(2S)" }, + { 445, "chi_c2(1P)" }, + { 100445, "chi_c2(2P)" }, + { 511, "B^0" }, + { -511, "B~^0" }, + { 10511, "B*_0^0" }, + { -10511, "B*_0~^0" }, + { 513, "B*^0" }, + { -513, "B*~^0" }, + { 10513, "B_1(L)^0" }, + { -10513, "B_1(L)~^0" }, + { 20513, "B_1(H)^0" }, + { -20513, "B_1(H)~^0" }, + { 515, "B*_2^0" }, + { -515, "B*_2~^0" }, + { 521, "B^+" }, + { -521, "B^-" }, + { 10521, "B*_0^+" }, + { -10521, "B*_0^-" }, + { 523, "B*^+" }, + { -523, "B*^-" }, + { 10523, "B_1(L)^+" }, + { -10523, "B_1(L)^-" }, + { 20523, "B_1(H)^+" }, + { -20523, "B_1(H)^-" }, + { 525, "B*_2^+" }, + { -525, "B*_2^-" }, + { 531, "B_s^0" }, + { -531, "B_s~^0" }, + { 10531, "B*_s0^0" }, + { -10531, "B*_s0~^0" }, + { 533, "B*_s^0" }, + { -533, "B*_s~^0" }, + { 10533, "B_s1(L)^0" }, + { -10533, "B_s1(L)~^0" }, + { 20533, "B_s1(H)^0" }, + { -20533, "B_s1(H)~^0" }, + { 535, "B*_s2^0" }, + { -535, "B*_s2~^0" }, + { 541, "B_c^+" }, + { -541, "B_c^-" }, + { 10541, "B*_c0^+" }, + { -10541, "B*_c0^-" }, + { 543, "B*_c^+" }, + { -543, "B*_c^-" }, + { 10543, "B_c1(L)^+" }, + { -10543, "B_c1(L)^-" }, + { 20543, "B_c1(H)^+" }, + { -20543, "B_c1(H)^-" }, + { 545, "B*_c2^+" }, + { -545, "B*_c2^-" }, + { 551, "eta_b(1S)" }, + { 10551, "chi_b0(1P)" }, + { 100551, "eta_b(2S)" }, + { 110551, "chi_b0(2P)" }, + { 200551, "eta_b(3S)" }, + { 210551, "chi_b0(3P)" }, + { 553, "Upsilon(1S)" }, + { 9000553, "Upsilon(10860)" }, + { 10553, "h_b(1P)" }, + { 9010553, "Upsilon(11020)" }, + { 20553, "chi_b1(1P)" }, + { 9020553, "Upsilon(7S)" }, + { 30553, "Upsilon_1(1D)" }, + { 100553, "Upsilon(2S)" }, + { 110553, "h_b(2P)" }, + { 120553, "chi_b1(2P)" }, + { 130553, "Upsilon_1(2D)" }, + { 200553, "Upsilon(3S)" }, + { 210553, "h_b(3P)" }, + { 220553, "chi_b1(3P)" }, + { 300553, "Upsilon(4S)" }, + { 555, "chi_b2(1P)" }, + { 10555, "eta_b2(1D)" }, + { 20555, "Upsilon_2(1D)" }, + { 100555, "chi_b2(2P)" }, + { 110555, "eta_b2(2D)" }, + { 120555, "Upsilon_2(2D)" }, + { 200555, "chi_b2(3P)" }, + { 557, "Upsilon_3(1D)" }, + { 100557, "Upsilon_3(2D)" }, + { 611, "T^+" }, + { -611, "T^-" }, + { 613, "T*^+" }, + { -613, "T*^-" }, + { 621, "T^0" }, + { -621, "T~^0" }, + { 623, "T*^0" }, + { -623, "T*~^0" }, + { 631, "T_s^+" }, + { -631, "T_s^-" }, + { 633, "T*_s^+" }, + { -633, "T*_s^-" }, + { 641, "T_c^0" }, + { -641, "T_c~^0" }, + { 643, "T*_c^0" }, + { -643, "T*_c~^0" }, + { 651, "T_b^+" }, + { -651, "T_b^-" }, + { 653, "T*_b^+" }, + { -653, "T*_b^-" }, + { 661, "eta_t" }, + { 663, "theta" }, + { 711, "L^0" }, + { -711, "L~^0" }, + { 713, "L*^0" }, + { -713, "L*~^0" }, + { 721, "L^-" }, + { -721, "L^+" }, + { 723, "L*^-" }, + { -723, "L*^+" }, + { 731, "L_s^0" }, + { -731, "L_s~^0" }, + { 733, "L*_s^0" }, + { -733, "L*_s~^0" }, + { 741, "L_c^-" }, + { -741, "L_c^+" }, + { 743, "L*_c^-" }, + { -743, "L*_c^+" }, + { 751, "L_b^0" }, + { -751, "L_b~^0" }, + { 753, "L*_b^0" }, + { -753, "L*_b~^0" }, + { 761, "L_t^-" }, + { -761, "L_t^+" }, + { 763, "L*_t^-" }, + { -763, "L*_t^+" }, + { 771, "eta_l" }, + { 773, "theta_l" }, + { 811, "X^+" }, + { -811, "X^-" }, + { 813, "X*^+" }, + { -813, "X*^-" }, + { 821, "X^0" }, + { -821, "X~^0" }, + { 823, "X*^0" }, + { -823, "X*~^0" }, + { 831, "X_s^+" }, + { -831, "X_s^-" }, + { 833, "X*_s^+" }, + { -833, "X*_s^-" }, + { 841, "X_c^0" }, + { -841, "X_c~^0" }, + { 843, "X*_c^0" }, + { -843, "X*_c~^0" }, + { 851, "X_b^+" }, + { -851, "X_b^-" }, + { 853, "X*_b^+" }, + { -853, "X*_b^-" }, + { 861, "X_t^0" }, + { -861, "X_t~^0" }, + { 863, "X*_t^0" }, + { -863, "X*_t~^0" }, + { 871, "X_l^+" }, + { -871, "X_l^-" }, + { 873, "X*_l^+" }, + { -873, "X*_l^-" }, + { 881, "eta_h" }, + { 883, "theta_H" }, + { 30343, "Xsd" }, + { -30343, "anti-Xsd" }, + { 30353, "Xsu" }, + { -30353, "anti-Xsu" }, + { 30363, "Xss" }, + { -30363, "anti-Xss" }, + { 30373, "Xdd" }, + { -30373, "anti-Xdd" }, + { 30383, "Xdu" }, + { -30383, "anti-Xdu" }, + { 2112, "n^0" }, + { -2112, "n~^0" }, + { 2212, "p^+" }, + { -2212, "p~^-" }, + { 12212, "N(1440)^+"}, + { 12112, "N(1440)^0"}, + { 22212, "N(1535)^+"}, + { 22112, "N(1535)^0"}, + { 32212, "N(1650)^+"}, + { 32112, "N(1650)^0"}, + { 42212, "N(1710)^+"}, + { 42112, "N(1710)^0"}, + { 1214, "N(1520)^0"}, + { 2124, "N(1520)^+"}, + { 21214, "N(1700)^0"}, + { 22124, "N(1700)^+"}, + { 31214, "N(1720)^0"}, + { 32124, "N(1720)^+"}, + { 2116, "N(1675)^0"}, + { 2216, "N(1675)^+"}, + { 12116, "N(1680)^0"}, + { 12216, "N(1680)^+"}, + { 1218, "N(2190)^0"}, + { 2128, "N(2190)^+" }, + { 1114, "Delta^-" }, + { -1114, "Delta~^+" }, + { 2114, "Delta^0" }, + { -2114, "Delta~^0" }, + { 2214, "Delta^+" }, + { -2214, "Delta~^-" }, + { 2224, "Delta^++" }, + { -2224, "Delta~^--" }, + { 31114, "Delta(1600)^-" }, + { 32114, "Delta(1600)^0" }, + { 32214, "Delta(1600)^+" }, + { 32224, "Delta(1600)^++" }, + { 1112, "Delta(1620)^-" }, + { 1212, "Delta(1620)^0" }, + { 2122, "Delta(1620)^+" }, + { 2222, "Delta(1620)^++" }, + { 11114, "Delta(1700)^-" }, + { 12114, "Delta(1700)^0" }, + { 12214, "Delta(1700)^+" }, + { 12224, "Delta(1700)^++" }, + { 1116, "Delta(1905)^-" }, + { 1216, "Delta(1905)^0" }, + { 2126, "Delta(1905)^+" }, + { 2226, "Delta(1905)^++" }, + { 21112, "Delta(1910)^-" }, + { 21212, "Delta(1910)^0" }, + { 22122, "Delta(1910)^+" }, + { 22222, "Delta(1910)^++" }, + { 21114, "Delta(1920)^-" }, + { 22114, "Delta(1920)^0" }, + { 22214, "Delta(1920)^+" }, + { 22224, "Delta(1920)^++" }, + { 11116, "Delta(1930)^-" }, + { 11216, "Delta(1930)^0" }, + { 12126, "Delta(1930)^+" }, + { 12226, "Delta(1930)^++" }, + { 1118, "Delta(1950)^-" }, + { 2118, "Delta(1950)^0" }, + { 2218, "Delta(1950)^+" }, + { 2228, "Delta(1950)^++" }, + { 3122, "Lambda^0" }, + { -3122, "Lambda~^0" }, + { 13122, "Lambda(1405)^0" }, + { -13122, "Lambda~(1405)^0" }, + { 23122, "Lambda(1600)^0" }, + { -23122, "Lambda~(1600)^0" }, + { 33122, "Lambda(1670)^0" }, + { -33122, "Lambda~(1670)^0" }, + { 43122, "Lambda(1800)^0" }, + { -43122, "Lambda~(1800)^0" }, + { 53122, "Lambda(1810)^0" }, + { -53122, "Lambda~(1810)^0" }, + { 3124, "Lambda(1520)^0" }, + { -3124, "Lambda~(1520)^0" }, + { 13124, "Lambda(1690)^0" }, + { -13124, "Lambda~(1690)^0" }, + { 23124, "Lambda(1890)^0" }, + { -23124, "Lambda~(1890)^0" }, + { 3126, "Lambda(1820)^0" }, + { -3126, "Lambda~(1820)^0" }, + { 13126, "Lambda(1830)^0" }, + { -13126, "Lambda~(1830)^0" }, + { 23126, "Lambda(2110)^0" }, + { -23126, "Lambda~(2110)^0" }, + { 3128, "Lambda(2100)^0" }, + { -3128, "Lambda~(2100)^0" }, + { 3112, "Sigma^-" }, + { -3112, "Sigma~^+" }, + { 3212, "Sigma^0" }, + { -3212, "Sigma~^0" }, + { 3222, "Sigma^+" }, + { -3222, "Sigma~^-" }, + { 13222, "Sigma(1660)^+" }, + { -13222, "Sigma~(1660)^+" }, + { 13212, "Sigma(1660)^0" }, + { -13212, "Sigma~(1660)^0" }, + { 13112, "Sigma(1660)^-" }, + { -13112, "Sigma~(1660)^-" }, + { 23112, "Sigma(1750)^-" }, + { -23112, "Sigma~(1750)^-" }, + { 23212, "Sigma(1750)^0" }, + { -23212, "Sigma~(1750)^0" }, + { 23222, "Sigma(1750)^+" }, + { -23222, "Sigma~(1750)^+" }, + { 3114, "Sigma*^-" }, + { -3114, "Sigma*~^+" }, + { 3214, "Sigma*^0" }, + { -3214, "Sigma*~^0" }, + { 3224, "Sigma*^+" }, + { -3224, "Sigma*~^-" }, + { 13224, "Sigma(1670)^+" }, + { -13224, "Sigma~(1670)^+" }, + { 13214, "Sigma(1670)^0" }, + { -13214, "Sigma~(1670)^0" }, + { 13114, "Sigma(1670)^-" }, + { -13114, "Sigma~(1670)^-" }, + { 23224, "Sigma(1940)^+" }, + { -23224, "Sigma~(1940)^+" }, + { 23214, "Sigma(1940)^0" }, + { -23214, "Sigma~(1940)^0" }, + { 23114, "Sigma(1940)^-" }, + { -23114, "Sigma~(1940)^-" }, + { 3226, "Sigma(1775)^+" }, + { -3226, "Sigma~(1775)^+" }, + { 3216, "Sigma(1775)^0" }, + { -3216, "Sigma~(1775)^0" }, + { 3116, "Sigma(1775)^-" }, + { -3116, "Sigma~(1775)^-" }, + { 13226, "Sigma(1915)^+" }, + { -13226, "Sigma~(1915)^+" }, + { 13216, "Sigma(1915)^0" }, + { -13216, "Sigma~(1915)^0" }, + { 13116, "Sigma(1915)^-" }, + { -13116, "Sigma~(1915)^-" }, + { 3228, "Sigma(2030)^+" }, + { -3228, "Sigma~(2030)^+" }, + { 3218, "Sigma(2030)^0" }, + { -3218, "Sigma~(2030)^0" }, + { 3118, "Sigma(2030)^-" }, + { -3118, "Sigma~(2030)^-" }, + { 3312, "Xi^-" }, + { -3312, "Xi~^+" }, + { 3322, "Xi^0" }, + { -3322, "Xi~^0" }, + { 3314, "Xi*^-" }, + { -3314, "Xi*~^+" }, + { 3324, "Xi*^0" }, + { -3324, "Xi*~^0" }, + { 13314, "Xi(1820)^-" }, + { -13314, "Xi(1820)~^+" }, + { 13324, "Xi(1820)^0" }, + { -13324, "Xi(1820)~^0" }, + { 3334, "Omega^-" }, + { -3334, "Omega~^+" }, + { 4112, "Sigma_c^0" }, + { -4112, "Sigma_c~^0" }, + { 4114, "Sigma*_c^0" }, + { -4114, "Sigma*_c~^0" }, + { 4122, "Lambda_c^+" }, + { -4122, "Lambda_c~^-" }, + { 14122, "Lambda_c(2593)^+" }, + { -14122, "Lambda_c~(2593)^-" }, + { 14124, "Lambda_c(2625)^+" }, + { -14124, "Lambda_c~(2625)^-" }, + { 4132, "Xi_c^0" }, + { -4132, "Xi_c~^0" }, + { 4212, "Sigma_c^+" }, + { -4212, "Sigma_c~^-" }, + { 4214, "Sigma*_c^+" }, + { -4214, "Sigma*_c~^-" }, + { 4222, "Sigma_c^++" }, + { -4222, "Sigma_c~^--" }, + { 4224, "Sigma*_c^++" }, + { -4224, "Sigma*_c~^--" }, + { 4232, "Xi_c^+" }, + { -4232, "Xi_c~^-" }, + { 4312, "Xi'_c^0" }, + { -4312, "Xi'_c~^0" }, + { 4314, "Xi*_c^0" }, + { -4314, "Xi*_c~^0" }, + { 4322, "Xi'_c^+" }, + { -4322, "Xi'_c~^-" }, + { 4324, "Xi*_c^+" }, + { -4324, "Xi*_c~^-" }, + { 4332, "Omega_c^0" }, + { -4332, "Omega_c~^0" }, + { 4334, "Omega*_c^0" }, + { -4334, "Omega*_c~^0" }, + { 4412, "Xi_cc^+" }, + { -4412, "Xi_cc~^-" }, + { 4414, "Xi*_cc^+" }, + { -4414, "Xi*_cc~^-" }, + { 4422, "Xi_cc^++" }, + { -4422, "Xi_cc~^--" }, + { 4424, "Xi*_cc^++" }, + { -4424, "Xi*_cc~^--" }, + { 4432, "Omega_cc^+" }, + { -4432, "Omega_cc~^-" }, + { 4434, "Omega*_cc^+" }, + { -4434, "Omega*_cc~^-" }, + { 4444, "Omega*_ccc^++" }, + { -4444, "Omega*_ccc~^--" }, + { 5112, "Sigma_b^-" }, + { -5112, "Sigma_b~^+" }, + { 5114, "Sigma*_b^-" }, + { -5114, "Sigma*_b~^+" }, + { 5122, "Lambda_b^0" }, + { -5122, "Lambda_b~^0" }, + { 5132, "Xi_b^-" }, + { -5132, "Xi_b~^+" }, + { 5142, "Xi_bc^0" }, + { -5142, "Xi_bc~^0" }, + { 5212, "Sigma_b^0" }, + { -5212, "Sigma_b~^0" }, + { 5214, "Sigma*_b^0" }, + { -5214, "Sigma*_b~^0" }, + { 5222, "Sigma_b^+" }, + { -5222, "Sigma_b~^-" }, + { 5224, "Sigma*_b^+" }, + { -5224, "Sigma*_b~^-" }, + { 5232, "Xi_b^0" }, + { -5232, "Xi_b~^0" }, + { 5242, "Xi_bc^+" }, + { -5242, "Xi_bc~^-" }, + { 5312, "Xi'_b^-" }, + { -5312, "Xi'_b~^+" }, + { 5314, "Xi*_b^-" }, + { -5314, "Xi*_b~^+" }, + { 5322, "Xi'_b^0" }, + { -5322, "Xi'_b~^0" }, + { 5324, "Xi*_b^0" }, + { -5324, "Xi*_b~^0" }, + { 5332, "Omega_b^-" }, + { -5332, "Omega_b~^+" }, + { 5334, "Omega*_b^-" }, + { -5334, "Omega*_b~^+" }, + { 5342, "Omega_bc^0" }, + { -5342, "Omega_bc~^0" }, + { 5412, "Xi'_bc^0" }, + { -5412, "Xi'_bc~^0" }, + { 5414, "Xi*_bc^0" }, + { -5414, "Xi*_bc~^0" }, + { 5422, "Xi'_bc^+" }, + { -5422, "Xi'_bc~^-" }, + { 5424, "Xi*_bc^+" }, + { -5424, "Xi*_bc~^-" }, + { 5432, "Omega'_bc^0" }, + { -5432, "Omega'_bc~^0" }, + { 5434, "Omega*_bc^0" }, + { -5434, "Omega*_bc~^0" }, + { 5442, "Omega_bcc^+" }, + { -5442, "Omega_bcc~^-" }, + { 5444, "Omega*_bcc^+" }, + { -5444, "Omega*_bcc~^-" }, + { 5512, "Xi_bb^-" }, + { -5512, "Xi_bb~^+" }, + { 5514, "Xi*_bb^-" }, + { -5514, "Xi*_bb~^+" }, + { 5522, "Xi_bb^0" }, + { -5522, "Xi_bb~^0" }, + { 5524, "Xi*_bb^0" }, + { -5524, "Xi*_bb~^0" }, + { 5532, "Omega_bb^-" }, + { -5532, "Omega_bb~^+" }, + { 5534, "Omega*_bb^-" }, + { -5534, "Omega*_bb~^+" }, + { 5542, "Omega_bbc^0" }, + { -5542, "Omega_bbc~^0" }, + { 5544, "Omega*_bbc^0" }, + { -5544, "Omega*_bbc~^0" }, + { 5554, "Omega*_bbb^-" }, + { -5554, "Omega*_bbb~^+" }, + { 6112, "Sigma_t^0" }, + { -6112, "Sigma_t~^0" }, + { 6114, "Sigma*_t^0" }, + { -6114, "Sigma*_t~^0" }, + { 6122, "Lambda_t^+" }, + { -6122, "Lambda_t~^-" }, + { 6132, "Xi_t^0" }, + { -6132, "Xi_t~^0" }, + { 6142, "Xi_tc^+" }, + { -6142, "Xi_tc~^-" }, + { 6152, "Xi_tb^0" }, + { -6152, "Xi_tb~^0" }, + { 6212, "Sigma_t^+" }, + { -6212, "Sigma_t~^-" }, + { 6214, "Sigma*_t^+" }, + { -6214, "Sigma*_t~^-" }, + { 6222, "Sigma_t^++" }, + { -6222, "Sigma_t~^--" }, + { 6224, "Sigma*_t^++" }, + { -6224, "Sigma*_t~^--" }, + { 6232, "Xi_t^+" }, + { -6232, "Xi_t~^-" }, + { 6242, "Xi_tc^++" }, + { -6242, "Xi_tc~^--" }, + { 6252, "Xi_tb^+" }, + { -6252, "Xi_tb~^-" }, + { 6312, "Xi'_t^0" }, + { -6312, "Xi'_t~^0" }, + { 6314, "Xi*_t^0" }, + { -6314, "Xi*_t~^0" }, + { 6322, "Xi'_t^+" }, + { -6322, "Xi'_t~^-" }, + { 6324, "Xi*_t^+" }, + { -6324, "Xi*_t~^-" }, + { 6332, "Omega_t^0" }, + { -6332, "Omega_t~^0" }, + { 6334, "Omega*_t^0" }, + { -6334, "Omega*_t~^0" }, + { 6342, "Omega_tc^+" }, + { -6342, "Omega_tc~^-" }, + { 6352, "Omega_tb^0" }, + { -6352, "Omega_tb~^0" }, + { 6412, "Xi'_tc^+" }, + { -6412, "Xi'_tc~^-" }, + { 6414, "Xi*_tc^+" }, + { -6414, "Xi*_tc~^-" }, + { 6422, "Xi'_tc^++" }, + { -6422, "Xi'_tc~^--" }, + { 6424, "Xi*_tc^++" }, + { -6424, "Xi*_tc~^--" }, + { 6432, "Omega'_tc^+" }, + { -6432, "Omega'_tc~^-" }, + { 6434, "Omega*_tc^+" }, + { -6434, "Omega*_tc~^-" }, + { 6442, "Omega_tcc^++" }, + { -6442, "Omega_tcc~^--" }, + { 6444, "Omega*_tcc^++" }, + { -6444, "Omega*_tcc~^--" }, + { 6452, "Omega_tbc^+" }, + { -6452, "Omega_tbc~^-" }, + { 6512, "Xi'_tb^0" }, + { -6512, "Xi'_tb~^0" }, + { 6514, "Xi*_tb^0" }, + { -6514, "Xi*_tb~^0" }, + { 6522, "Xi'_tb^+" }, + { -6522, "Xi'_tb~^-" }, + { 6524, "Xi*_tb^+" }, + { -6524, "Xi*_tb~^-" }, + { 6532, "Omega'_tb^0" }, + { -6532, "Omega'_tb~^0" }, + { 6534, "Omega*_tb^0" }, + { -6534, "Omega*_tb~^0" }, + { 6542, "Omega'_tbc^+" }, + { -6542, "Omega'_tbc~^-" }, + { 6544, "Omega*_tbc^+" }, + { -6544, "Omega*_tbc~^-" }, + { 6552, "Omega_tbb^0" }, + { -6552, "Omega_tbb~^0" }, + { 6554, "Omega*_tbb^0" }, + { -6554, "Omega*_tbb~^0" }, + { 6612, "Xi_tt^+" }, + { -6612, "Xi_tt~^-" }, + { 6614, "Xi*_tt^+" }, + { -6614, "Xi*_tt~^-" }, + { 6622, "Xi_tt^++" }, + { -6622, "Xi_tt~^--" }, + { 6624, "Xi*_tt^++" }, + { -6624, "Xi*_tt~^--" }, + { 6632, "Omega_tt^+" }, + { -6632, "Omega_tt~^-" }, + { 6634, "Omega*_tt^+" }, + { -6634, "Omega*_tt~^-" }, + { 6642, "Omega_ttc^++" }, + { -6642, "Omega_ttc~^--" }, + { 6644, "Omega*_ttc^++" }, + { -6644, "Omega*_ttc~^--" }, + { 6652, "Omega_ttb^+" }, + { -6652, "Omega_ttb~^-" }, + { 6654, "Omega*_ttb^+" }, + { -6654, "Omega*_ttb~^-" }, + { 6664, "Omega*_ttt^++" }, + { -6664, "Omega*_ttt~^--" }, + { 7112, "Sigma_b'^-" }, + { -7112, "Sigma_b'~^+" }, + { 7114, "Sigma*_b'^-" }, + { -7114, "Sigma*_b'~^+" }, + { 7122, "Lambda_b'^0" }, + { -7122, "Lambda_b'~^0" }, + { 7132, "Xi_b'^-" }, + { -7132, "Xi_b'~^+" }, + { 7142, "Xi_b'c^0" }, + { -7142, "Xi_b'c~^0" }, + { 7152, "Xi_b'b^-" }, + { -7152, "Xi_b'b~^+" }, + { 7162, "Xi_b't^0" }, + { -7162, "Xi_b't~^0" }, + { 7212, "Sigma_b'^0" }, + { -7212, "Sigma_b'~^0" }, + { 7214, "Sigma*_b'^0" }, + { -7214, "Sigma*_b'~^0" }, + { 7222, "Sigma_b'^+" }, + { -7222, "Sigma_b'~^-" }, + { 7224, "Sigma*_b'^+" }, + { -7224, "Sigma*_b'~^-" }, + { 7232, "Xi_b'^0" }, + { -7232, "Xi_b'~^0" }, + { 7242, "Xi_b'c^+" }, + { -7242, "Xi_b'c~^-" }, + { 7252, "Xi_b'b^0" }, + { -7252, "Xi_b'b~^0" }, + { 7262, "Xi_b't^+" }, + { -7262, "Xi_b't~^-" }, + { 7312, "Xi'_b'^-" }, + { -7312, "Xi'_b'~^+" }, + { 7314, "Xi*_b'^-" }, + { -7314, "Xi*_b'~^+" }, + { 7322, "Xi'_b'^0" }, + { -7322, "Xi'_b'~^0" }, + { 7324, "Xi*_b'^0" }, + { -7324, "Xi*_b'~^0" }, + { 7332, "Omega'_b'^-" }, + { -7332, "Omega'_b'~^+" }, + { 7334, "Omega*_b'^-" }, + { -7334, "Omega*_b'~^+" }, + { 7342, "Omega_b'c^0" }, + { -7342, "Omega_b'c~^0" }, + { 7352, "Omega_b'b^-" }, + { -7352, "Omega_b'b~^+" }, + { 7362, "Omega_b't^0" }, + { -7362, "Omega_b't~^0" }, + { 7412, "Xi'_b'c^0" }, + { -7412, "Xi'_b'c~^0" }, + { 7414, "Xi*_b'c^0" }, + { -7414, "Xi*_b'c~^0" }, + { 7422, "Xi'_b'c^+" }, + { -7422, "Xi'_b'c~^-" }, + { 7424, "Xi*_b'c^+" }, + { -7424, "Xi*_b'c~^-" }, + { 7432, "Omega'_b'c^0" }, + { -7432, "Omega'_b'c~^0" }, + { 7434, "Omega*_b'c^0" }, + { -7434, "Omega*_b'c~^0" }, + { 7442, "Omega'_b'cc^+" }, + { -7442, "Omega'_b'cc~^-" }, + { 7444, "Omega*_b'cc^+" }, + { -7444, "Omega*_b'cc~^-" }, + { 7452, "Omega_b'bc^0" }, + { -7452, "Omega_b'bc~^0" }, + { 7462, "Omega_b'tc^+" }, + { -7462, "Omega_b'tc~^-" }, + { 7512, "Xi'_b'b^-" }, + { -7512, "Xi'_b'b~^+" }, + { 7514, "Xi*_b'b^-" }, + { -7514, "Xi*_b'b~^+" }, + { 7522, "Xi'_b'b^0" }, + { -7522, "Xi'_b'b~^0" }, + { 7524, "Xi*_b'b^0" }, + { -7524, "Xi*_b'b~^0" }, + { 7532, "Omega'_b'b^-" }, + { -7532, "Omega'_b'b~^+" }, + { 7534, "Omega*_b'b^-" }, + { -7534, "Omega*_b'b~^+" }, + { 7542, "Omega'_b'bc^0" }, + { -7542, "Omega'_b'bc~^0" }, + { 7544, "Omega*_b'bc^0" }, + { -7544, "Omega*_b'bc~^0" }, + { 7552, "Omega'_b'bb^-" }, + { -7552, "Omega'_b'bb~^+" }, + { 7554, "Omega*_b'bb^-" }, + { -7554, "Omega*_b'bb~^+" }, + { 7562, "Omega_b'tb^0" }, + { -7562, "Omega_b'tb~^0" }, + { 7612, "Xi'_b't^0" }, + { -7612, "Xi'_b't~^0" }, + { 7614, "Xi*_b't^0" }, + { -7614, "Xi*_b't~^0" }, + { 7622, "Xi'_b't^+" }, + { -7622, "Xi'_b't~^-" }, + { 7624, "Xi*_b't^+" }, + { -7624, "Xi*_b't~^-" }, + { 7632, "Omega'_b't^0" }, + { -7632, "Omega'_b't~^0" }, + { 7634, "Omega*_b't^0" }, + { -7634, "Omega*_b't~^0" }, + { 7642, "Omega'_b'tc^+" }, + { -7642, "Omega'_b'tc~^-" }, + { 7644, "Omega*_b'tc^+" }, + { -7644, "Omega*_b'tc~^-" }, + { 7652, "Omega'_b'tb^0" }, + { -7652, "Omega'_b'tb~^0" }, + { 7654, "Omega*_b'tb^0" }, + { -7654, "Omega*_b'tb~^0" }, + { 7662, "Omega'_b'tt^+" }, + { -7662, "Omega'_b'tt~^-" }, + { 7664, "Omega*_b'tt^+" }, + { -7664, "Omega*_b'tt~^-" }, + { 7712, "Xi'_b'b'^-" }, + { -7712, "Xi'_b'b'~^+" }, + { 7714, "Xi*_b'b'^-" }, + { -7714, "Xi*_b'b'~^+" }, + { 7722, "Xi'_b'b'^0" }, + { -7722, "Xi'_b'b'~^0" }, + { 7724, "Xi*_b'b'^0" }, + { -7724, "Xi*_b'b'~^0" }, + { 7732, "Omega'_b'b'^-" }, + { -7732, "Omega'_b'b'~^+" }, + { 7734, "Omega*_b'b'^-" }, + { -7734, "Omega*_b'b'~^+" }, + { 7742, "Omega'_b'b'c^0" }, + { -7742, "Omega'_b'b'c~^0" }, + { 7744, "Omega*_b'b'c^0" }, + { -7744, "Omega*_b'b'c~^0" }, + { 7752, "Omega'_b'b'b^-" }, + { -7752, "Omega'_b'b'b~^+" }, + { 7754, "Omega*_b'b'b^-" }, + { -7754, "Omega*_b'b'b~^+" }, + { 7762, "Omega'_b'b't^0" }, + { -7762, "Omega'_b'b't~^0" }, + { 7764, "Omega*_b'b't^0" }, + { -7764, "Omega*_b'b't~^0" }, + { 7774, "Omega*_b'b'b'^-" }, + { -7774, "Omega*_b'b'b'~^+" }, + { 8112, "Sigma_t'^0" }, + { -8112, "Sigma_t'~^0" }, + { 8114, "Sigma*_t'^0" }, + { -8114, "Sigma*_t'~^0" }, + { 8122, "Lambda_t'^+" }, + { -8122, "Lambda_t'~^-" }, + { 8132, "Xi_t'^0" }, + { -8132, "Xi_t'~^0" }, + { 8142, "Xi_t'c^+" }, + { -8142, "Xi_t'c~^-" }, + { 8152, "Xi_t'b^0" }, + { -8152, "Xi_t'b~^0" }, + { 8162, "Xi_t't^+" }, + { -8162, "Xi_t't~^-" }, + { 8172, "Xi_t'b'^0" }, + { -8172, "Xi_t'b'~^0" }, + { 8212, "Sigma_t'^+" }, + { -8212, "Sigma_t'~^-" }, + { 8214, "Sigma*_t'^+" }, + { -8214, "Sigma*_t'~^-" }, + { 8222, "Sigma_t'^++" }, + { -8222, "Sigma_t'~^--" }, + { 8224, "Sigma*_t'^++" }, + { -8224, "Sigma*_t'~^--" }, + { 8232, "Xi_t'^+" }, + { -8232, "Xi_t'~^-" }, + { 8242, "Xi_t'c^++" }, + { -8242, "Xi_t'c~^--" }, + { 8252, "Xi_t'b^+" }, + { -8252, "Xi_t'b~^-" }, + { 8262, "Xi_t't^++" }, + { -8262, "Xi_t't~^--" }, + { 8272, "Xi_t'b'^+" }, + { -8272, "Xi_t'b'~^-" }, + { 8312, "Xi'_t'^0" }, + { -8312, "Xi'_t'~^0" }, + { 8314, "Xi*_t'^0" }, + { -8314, "Xi*_t'~^0" }, + { 8322, "Xi'_t'^+" }, + { -8322, "Xi'_t'~^-" }, + { 8324, "Xi*_t'^+" }, + { -8324, "Xi*_t'~^-" }, + { 8332, "Omega'_t'^0" }, + { -8332, "Omega'_t'~^0" }, + { 8334, "Omega*_t'^0" }, + { -8334, "Omega*_t'~^0" }, + { 8342, "Omega_t'c^+" }, + { -8342, "Omega_t'c~^-" }, + { 8352, "Omega_t'b^0" }, + { -8352, "Omega_t'b~^0" }, + { 8362, "Omega_t't^+" }, + { -8362, "Omega_t't~^-" }, + { 8372, "Omega_t'b'^0" }, + { -8372, "Omega_t'b'~^0" }, + { 8412, "Xi'_t'c^+" }, + { -8412, "Xi'_t'c~^-" }, + { 8414, "Xi*_t'c^+" }, + { -8414, "Xi*_t'c~^-" }, + { 8422, "Xi'_t'c^++" }, + { -8422, "Xi'_t'c~^--" }, + { 8424, "Xi*_t'c^++" }, + { -8424, "Xi*_t'c~^--" }, + { 8432, "Omega'_t'c^+" }, + { -8432, "Omega'_t'c~^-" }, + { 8434, "Omega*_t'c^+" }, + { -8434, "Omega*_t'c~^-" }, + { 8442, "Omega'_t'cc^++" }, + { -8442, "Omega'_t'cc~^--" }, + { 8444, "Omega*_t'cc^++" }, + { -8444, "Omega*_t'cc~^--" }, + { 8452, "Omega_t'bc^+" }, + { -8452, "Omega_t'bc~^-" }, + { 8462, "Omega_t'tc^++" }, + { -8462, "Omega_t'tc~^--" }, + { 8472, "Omega_t'b'c ^+" }, + { -8472, "Omega_t'b'c ~^-" }, + { 8512, "Xi'_t'b^0" }, + { -8512, "Xi'_t'b~^0" }, + { 8514, "Xi*_t'b^0" }, + { -8514, "Xi*_t'b~^0" }, + { 8522, "Xi'_t'b^+" }, + { -8522, "Xi'_t'b~^-" }, + { 8524, "Xi*_t'b^+" }, + { -8524, "Xi*_t'b~^-" }, + { 8532, "Omega'_t'b^0" }, + { -8532, "Omega'_t'b~^0" }, + { 8534, "Omega*_t'b^0" }, + { -8534, "Omega*_t'b~^0" }, + { 8542, "Omega'_t'bc^+" }, + { -8542, "Omega'_t'bc~^-" }, + { 8544, "Omega*_t'bc^+" }, + { -8544, "Omega*_t'bc~^-" }, + { 8552, "Omega'_t'bb^0" }, + { -8552, "Omega'_t'bb~^0" }, + { 8554, "Omega*_t'bb^0" }, + { -8554, "Omega*_t'bb~^0" }, + { 8562, "Omega_t'tb^+" }, + { -8562, "Omega_t'tb~^-" }, + { 8572, "Omega_t'b'b ^0" }, + { -8572, "Omega_t'b'b ~^0" }, + { 8612, "Xi'_t't^+" }, + { -8612, "Xi'_t't~^-" }, + { 8614, "Xi*_t't^+" }, + { -8614, "Xi*_t't~^-" }, + { 8622, "Xi'_t't^++" }, + { -8622, "Xi'_t't~^--" }, + { 8624, "Xi*_t't^++" }, + { -8624, "Xi*_t't~^--" }, + { 8632, "Omega'_t't^+" }, + { -8632, "Omega'_t't~^-" }, + { 8634, "Omega*_t't^+" }, + { -8634, "Omega*_t't~^-" }, + { 8642, "Omega'_t'tc^++" }, + { -8642, "Omega'_t'tc~^--" }, + { 8644, "Omega*_t'tc^++" }, + { -8644, "Omega*_t'tc~^--" }, + { 8652, "Omega'_t'tb^+" }, + { -8652, "Omega'_t'tb~^-" }, + { 8654, "Omega*_t'tb^+" }, + { -8654, "Omega*_t'tb~^-" }, + { 8662, "Omega'_t'tt^++" }, + { -8662, "Omega'_t'tt~^--" }, + { 8664, "Omega*_t'tt^++" }, + { -8664, "Omega*_t'tt~^--" }, + { 8672, "Omega_t'b't ^+" }, + { -8672, "Omega_t'b't ~^-" }, + { 8712, "Xi'_t'b'^0" }, + { -8712, "Xi'_t'b'~^0" }, + { 8714, "Xi*_t'b'^0" }, + { -8714, "Xi*_t'b'~^0" }, + { 8722, "Xi'_t'b'^+" }, + { -8722, "Xi'_t'b'~^-" }, + { 8724, "Xi*_t'b'^+" }, + { -8724, "Xi*_t'b'~^-" }, + { 8732, "Omega'_t'b'^0" }, + { -8732, "Omega'_t'b'~^0" }, + { 8734, "Omega*_t'b'^0" }, + { -8734, "Omega*_t'b'~^0" }, + { 8742, "Omega'_t'b'c^+" }, + { -8742, "Omega'_t'b'c~^-" }, + { 8744, "Omega*_t'b'c^+" }, + { -8744, "Omega*_t'b'c~^-" }, + { 8752, "Omega'_t'b'b^0" }, + { -8752, "Omega'_t'b'b~^0" }, + { 8754, "Omega*_t'b'b^0" }, + { -8754, "Omega*_t'b'b~^0" }, + { 8762, "Omega'_t'b't^+" }, + { -8762, "Omega'_t'b't~^-" }, + { 8764, "Omega*_t'b't^+" }, + { -8764, "Omega*_t'b't~^-" }, + { 8772, "Omega'_t'b'b'^0" }, + { -8772, "Omega'_t'b'b'~^0" }, + { 8774, "Omega*_t'b'b'^0" }, + { -8774, "Omega*_t'b'b'~^0" }, + { 8812, "Xi'_t't'^+" }, + { -8812, "Xi'_t't'~^-" }, + { 8814, "Xi*_t't'^+" }, + { -8814, "Xi*_t't'~^-" }, + { 8822, "Xi'_t't'^++" }, + { -8822, "Xi'_t't'~^--" }, + { 8824, "Xi*_t't'^++" }, + { -8824, "Xi*_t't'~^--" }, + { 8832, "Omega'_t't'^+" }, + { -8832, "Omega'_t't'~^-" }, + { 8834, "Omega*_t't'^+" }, + { -8834, "Omega*_t't'~^-" }, + { 8842, "Omega'_t't'c^++" }, + { -8842, "Omega'_t't'c~^--" }, + { 8844, "Omega*_t't'c^++" }, + { -8844, "Omega*_t't'c~^--" }, + { 8852, "Omega'_t't'b^+" }, + { -8852, "Omega'_t't'b~^-" }, + { 8854, "Omega*_t't'b^+" }, + { -8854, "Omega*_t't'b~^-" }, + { 8862, "Omega'_t't't^++" }, + { -8862, "Omega'_t't't~^--" }, + { 8864, "Omega*_t't't^++" }, + { -8864, "Omega*_t't't~^--" }, + { 8872, "Omega'_t't'b'^+" }, + { -8872, "Omega'_t't'b'~^-" }, + { 8874, "Omega*_t't'b'^+" }, + { -8874, "Omega*_t't'b'~^-" }, + { 8884, "Omega*_t't't'^++" }, + { -8884, "Omega*_t't't'~^--" }, + { 9221132, "Theta^+" }, + { 9331122, "Phi^--" }, + { 1000993, "R_~gg^0" }, + { 1009113, "R_~gd~d^0" }, + { 1009213, "R_~gu~d^+" }, + { 1009223, "R_~gu~u^0" }, + { 1009313, "R_~gd~s^0" }, + { 1009323, "R_~gu~s^+" }, + { 1009333, "R_~gs~s^0" }, + { 1091114, "R_~gddd^-" }, + { 1092114, "R_~gudd^0" }, + { 1092214, "R_~guud^+" }, + { 1092224, "R_~guuu^++" }, + { 1093114, "R_~gsdd^-" }, + { 1093214, "R_~gsud^0" }, + { 1093224, "R_~gsuu^+" }, + { 1093314, "R_~gssd^-" }, + { 1093324, "R_~gssu^0" }, + { 1093334, "R_~gsss^-" }, + { 1000612, "R_~t_1~d^+" }, + { 1000622, "R_~t_1~u^0" }, + { 1000632, "R_~t_1~s^+" }, + { 1000642, "R_~t_1~c^0" }, + { 1000652, "R_~t_1~b^+" }, + { 1006113, "R_~t_1dd_1^0" }, + { 1006211, "R_~t_1ud_0^+" }, + { 1006213, "R_~t_1ud_1^+" }, + { 1006223, "R_~t_1uu_1^++" }, + { 1006311, "R_~t_1sd_0^0" }, + { 1006313, "R_~t_1sd_1^0" }, + { 1006321, "R_~t_1su_0^+" }, + { 1006323, "R_~t_1su_1^+" }, + { 1006333, "R_~t_1ss_1^0" }, + { 1000010010, "Hydrogen" }, + { 1000010020, "Deuterium" }, + {-1000010020, "Anti-Deuterium" }, + { 1000010030, "Tritium" }, + {-1000010030, "Anti-Tritium" }, + { 1000020030, "He3" }, + {-1000020030, "Anti-He3" }, + { 1000020040, "Alpha-(He4)" }, + {-1000020040, "Anti-Alpha-(He4)" } + }; + + int lnames = sizeof(SNames)/sizeof(SNames[0]); + for( int k=0; k!=lnames; ++k) { + m.insert( std::make_pair( SNames[k].pid, std::string(SNames[k].pname)) ); + nameMap.insert( std::make_pair( std::string(SNames[k].pname), SNames[k].pid ) ); + } + static ParticleNameMap mymaps(m,nameMap); + + return mymaps; +} // ParticleNameInit() + +void writeParticleNameLine( int i, std::ostream & os ) +{ + if ( validParticleName( i ) ) { + std::string pn = particleName( i ); + int pid = particleName( pn ); + os << " PDT number: " ; + os.width(12); + os << i << " PDT name: " << pn << std::endl; + // verify reverse lookup + if( pid != i ) { + os << "HepPID::writeParticleNameLine ERROR: " + << " got " << pid << " instead of " << i << std::endl; + } + } + return; +} // writeParticleNameLine() + +std::string dyonName( const int & pid ) +{ + std::ostringstream pn; + pn << "Dyon^" << digit(nq1,pid) << digit(nq2,pid) << digit(nq3,pid); + if ( digit(nl,pid) == 1 ) { + if ( pid > 0 ) { + pn << "++"; + } else { + pn << "--"; + } + } else if ( digit(nl,pid) == 2 ) { + if ( pid > 0 ) { + pn << "+-"; + } else { + pn << "-+"; + } + } + return pn.str(); +} + +std::string qballName( const int & pid ) +{ + std::ostringstream pn; + pn << "QBall^" << ((abspid(pid)/100)%1000) << "." << digit(nq3,pid); + if ( pid > 0 ) { + pn << "+"; + } else { + pn << "-"; + } + return pn.str(); +} + +int checkForSpecialParticle( const std::string & s ) +{ + int chg, chg2, id; + int m = 1; + int len = s.length(); + if( s.substr(0,4) == "Dyon" ) { + std::istringstream var1(s.substr(5,3).c_str()); + var1 >> chg; + if( s.substr(len-2,1) == "+" && s.substr(len-1,1) == "-") m = 2; + if( s.substr(len-2,1) == "-" && s.substr(len-1,1) == "+") m = 2; + id = 4100000 + m*10000 + chg*10; + if( s.substr(len-2,1) == "-" ) id = -id; + return id; + } + if( s.substr(0,5) == "QBall" ) { + int rem = len - 9; + std::istringstream var2(s.substr(6,rem).c_str()); + var2 >> chg; + std::istringstream var3(s.substr(7+rem,1).c_str()); + var3 >> chg2; + id = 10000000 + chg*100+chg2*10; + if( s.substr(len-1,1) == "-" ) id = -id; + return id; + } + return 0; +} + +} // unnamed namespace + +// +// getPartcleIdMap is the ONLY function allowed to call ParticleNameInit +// +ParticleNameMap const & getParticleNameMap() +{ + static ParticleNameMap const & pmap = ParticleNameInit(); + return pmap; +} // getPartcleIdMap() + +bool validParticleName( const int & pid ) +{ + // check for the special cases first + if ( isDyon(pid) ) return true; + if ( isQBall(pid) ) return true; + + static ParticleNameMap const & pmap = getParticleNameMap(); + + ParticleNameMap::idIterator const cit = pmap.find( pid ); + return ( cit == pmap.end() ) + ? false + : true; +} // validParticleName() + +bool validParticleName( const std::string & s ) +{ + static ParticleNameMap const & pmap = getParticleNameMap(); + ParticleNameMap::nameIterator const cit = pmap.findString( s ); + return ( cit == pmap.endLookupMap() ) + ? false + : true; +} // validParticleName() + +std::string particleName( const int & pid ) +{ + // check for the special cases first + if ( isDyon(pid) ) return dyonName(pid); + if ( isQBall(pid) ) return qballName(pid); + + static ParticleNameMap const & pmap = getParticleNameMap(); + + ParticleNameMap::idIterator const cit = pmap.find( pid ); + return ( cit == pmap.end() ) + ? std::string("not defined") + : cit->second; +} // particleName() + +int particleName( const std::string & s ) +{ + static ParticleNameMap const & pmap = getParticleNameMap(); + ParticleNameMap::nameIterator const cit = pmap.findString( s ); + return ( cit == pmap.endLookupMap() ) + ? checkForSpecialParticle(s) + : cit->second; +} // particleName() + +// +// list all the defined names +// +void listParticleNames( std::ostream & os ) +{ + writeVersion( os ); + os << " HepPID Particle List" << std::endl; + os << std::endl; + + // simple: static PartcleIdMap const & pmap = getPartcleIdMap(); + // simple: for( PartcleIdMap::const_iterator cit = pmap.begin(), mend = pmap.end(); + // simple: cit != mend; + // simple: ++cit ) { + // simple: os << " PDT number: " ; + // simple: os.width(12); + // simple: os << cit->first << " PDT name: " << cit->second << std::endl; + // simple: } + int id, i, j, q1, q2, q3, l, m, n; + // special cases + for( id=1; id<101; ++id) { + writeParticleNameLine( id, os ); + writeParticleNameLine( -id, os ); + } + for( i=11; i<1000; ++i) { + id = i*10; + writeParticleNameLine( id, os ); + writeParticleNameLine( -id, os ); + } + // SUSY + for( n=1; n<3; ++n) { + for( q1=0; q1<10; ++q1) { + for( j=0; j<10; ++j) { + id = 1000000*n+10*q1+j; + writeParticleNameLine( id, os ); + writeParticleNameLine( -id, os ); + } + } + } + // technicolor, etc. + for( n=3; n<7; ++n) { + for( q2=0; q2<10; ++q2) { + for( q1=0; q1<10; ++q1) { + for( j=0; j<10; ++j) { + for( m=0; m<10; ++m) { + for( l=0; l<7; ++l) { + id = 1000000*n+100000*m+10000*l+100*q2+10*q1+j; + // save dyons for later + if( !(n == 4 && m == 1) ) { + writeParticleNameLine( id, os ); + writeParticleNameLine( -id, os ); + } + } + } + } + } + } + } + // R-hadrons + for( q3=0; q3<10; ++q3) { + for( q2=1; q2<10; ++q2) { + for( q1=1; q1<10; ++q1) { + for( j=1; j<5; ++j) { + id = 1000000+1000*q3+100*q2+10*q1+j; + writeParticleNameLine( id, os ); + if(q3 > 0 ) id = 1000000+90000+1000*q3+100*q2+10*q1+j; + writeParticleNameLine( id, os ); + } + } + } + } + // miscellaneous generator particles + for( l=0; l<9; ++l) { + for( i=1; i<100; ++i) { + id = 9900000+10000*l+i; + writeParticleNameLine( id, os ); + writeParticleNameLine( -id, os ); + } + for( q3=0; q3<10; ++q3) { + for( q2=1; q2<10; ++q2) { + for( q1=1; q1<10; ++q1) { + for( j=0; j<10; ++j) { + id = 9900000+10000*l+1000*q3+100*q2+10*q1+j; + writeParticleNameLine( id, os ); + writeParticleNameLine( -id, os ); + } + } + } + } + } + // diquark + for( i=11; i<100; ++i) { + for( j=0; j<10; ++j) { + id = 100*i+j; + writeParticleNameLine( id, os ); + writeParticleNameLine( -id, os ); + } + } + // mesons + for( q2=1; q2<10; ++q2) { + for( q1=1; q1<10; ++q1) { + for( j=1; j<10; ++j) { + for( m=0; m<9; ++m) { + for( l=0; l<10; ++l) { + id = 100000*m+10000*l+100*q2+10*q1+j; + writeParticleNameLine( id, os ); + writeParticleNameLine( -id, os ); + id = 9000000+100000*m+10000*l+100*q2+10*q1+j; + writeParticleNameLine( id, os ); + writeParticleNameLine( -id, os ); + } + } + } + } + } + // baryons + for( q3=1; q3<10; ++q3) { + for( q2=1; q2<10; ++q2) { + for( q1=1; q1<10; ++q1) { + for( j=1; j<10; ++j) { + for( m=0; m<9; ++m) { + id = 10000*m+1000*q3+100*q2+10*q1+j; + writeParticleNameLine( id, os ); + writeParticleNameLine( -id, os ); + } + } + } + } + } + // pentaquarks + for( l=1; l<9; ++l ) { + for ( m=1; m<9; ++m ) { + for( q3=1; q3<9; ++q3) { + for( q2=1; q2<9; ++q2) { + for( q1=1; q1<9; ++q1) { + id = 9*1000000+l*100000+m*10000+1000*q3+100*q2+10*q1+2; + writeParticleNameLine( id, os ); + writeParticleNameLine( -id, os ); + } + } + } + } + } + // ions + for( i=1; i<3; ++i) { + for( m=1; m<5; ++m) { + id = 1000000000+10*m+10000*i; + writeParticleNameLine( id, os ); + writeParticleNameLine( -id, os ); + } + } + // some Dyons + for( q3=0; q3<2; ++q3) { + for( q2=0; q2<4; ++q2) { + for( q1=0; q1<10; ++q1) { + ++q1; + id = 4110000+1000*q3+100*q2+10*q1; + writeParticleNameLine( id, os ); + writeParticleNameLine( -id, os ); + id = 4120000+1000*q3+100*q2+10*q1; + writeParticleNameLine( id, os ); + writeParticleNameLine( -id, os ); + } + } + } + // a few QBalls + for( i=1; i<199; ++i ) { + for( m=1; m<10; ) { + id = 10000000+10*m+100*i; + writeParticleNameLine( id, os ); + writeParticleNameLine( -id, os ); + m += 3; + } + i += 11; + } + return; +} // listParticleNames() + +} // HepPID diff --git a/libs/HepPID/src/Version.cc b/libs/HepPID/src/Version.cc new file mode 100644 index 000000000..d10cb58a7 --- /dev/null +++ b/libs/HepPID/src/Version.cc @@ -0,0 +1,30 @@ +// ---------------------------------------------------------------------- +// +// version.cc +// Author: Lynn Garren +// +// for now, this is a free function +// +// ---------------------------------------------------------------------- + +#include "HepPID/Version.hh" + +namespace HepPID { + +std::string versionName( ) +{ + return "3.04.01"; +} + +void version( ) +{ + std::cout << " --------------- HepPID Version " << versionName() + << " --------------- " << std::endl; +} + +void writeVersion( std::ostream & os ) +{ + os << " HepPID Version: " << versionName() << std::endl; +} + +} // HepPID diff --git a/libs/HepPID/src/translateEvtGen.cc b/libs/HepPID/src/translateEvtGen.cc new file mode 100644 index 000000000..b418e0df4 --- /dev/null +++ b/libs/HepPID/src/translateEvtGen.cc @@ -0,0 +1,724 @@ +// ------------------------------------ +// +// translateEvtGent.cc +// Author: Lynn Garren +// +// translate an ID number to or from the standard numbering scheme and EvtGen +// use static maps +// +// The maps are initialized if and only if the public functions are called. +// Because the maps are static, the initialization happens only once. +// +// The user NEVER calls EvtGenPDTMapInit() +// We use a data table (struct SList) so that compile time is not impacted. +// +// public functions: +// int translateEvtGentoPDT( const int id ) +// int translatePDTtoEvtGen( const int id ) +// EvtGenPDTMap const & getEvtGenPDTMap() +// PDTEvtGenMap const & getPDTEvtGenMap() +// +// ------------------------------------ + +#include +#include // make_pair + +#include "HepPID/Version.hh" +#include "HepPID/ParticleIDTranslations.hh" +#include "HepPID/ParticleIDMethods.hh" +#include "HepPID/ParticleName.hh" + +namespace HepPID { + + typedef std::map< int, int > EvtGenPDTMap; + typedef std::map< int, int > PDTEvtGenMap; + +namespace { // EvtGenPDTMapInit is private + + EvtGenPDTMap const & getEvtGenPDTMap(); + PDTEvtGenMap const & getPDTEvtGenMap(); + +EvtGenPDTMap const & EvtGenPDTMapInit() +{ + + static EvtGenPDTMap m; + + static const struct { + int hid; // EvtGen + int pid; // PDT + } SList[] = { + { 1, 1 }, + { -1, -1 }, + { 2, 2 }, + { -2, -2 }, + { 3, 3 }, + { -3, -3 }, + { 4, 4 }, + { -4, -4 }, + { 5, 5 }, + { -5, -5 }, + { 6, 6 }, + { -6, -6 }, + { 7, 7 }, + { -7, -7 }, + { 8, 8 }, + { -8, -8 }, + { 21, 21 }, + { 11, 11 }, + { -11, -11 }, + { 12, 12 }, + { -12, -12 }, + { 13, 13 }, + { -13, -13 }, + { 14, 14 }, + { -14, -14 }, + { 15, 15 }, + { -15, -15 }, + { 16, 16 }, + { -16, -16 }, + { 17, 17 }, + { -17, -17 }, + { 18, 18 }, + { -18, -18 }, + { 22, 22 }, + { 10022, 10022 }, + { 20022, 20022 }, + { 23, 23 }, + { 24, 24 }, + { -24, -24 }, + { 25, 25 }, + { 110, 110 }, + { 990, 990 }, + { 32, 32 }, + { 33, 33 }, + { 34, 34 }, + { -34, -34 }, + { 35, 35 }, + { 36, 36 }, + { 37, 37 }, + { -37, -37 }, + { 41, 41 }, + { -41, -41 }, + { 43, 43 }, + { 44, 44 }, + { -44, -44 }, + { 81, 81 }, + { 82, 82 }, + { -82, -82 }, + { 83, 83 }, + { 84, 84 }, + { -84, -84 }, + { 85, 85 }, + { -85, -85 }, + { 86, 86 }, + { -86, -86 }, + { 87, 87 }, + { -87, -87 }, + { 88, 88 }, + { -88, -88 }, + { 89, 89 }, + { -89, -89 }, + { 90, 90 }, + { -90, -90 }, + { 91, 91 }, + { 92, 92 }, + { 93, 93 }, + { 94, 94 }, + { 95, 95 }, + { 96, 96 }, + { 97, 97 }, + { 98, 98 }, + { 99, 99 }, + { 111, 111 }, + { 211, 211 }, + { -211, -211 }, + { 9910211, 9910211 }, + { -9910211, -9910211 }, + { 100111, 100111 }, + { 100211, 100211 }, + { -100211, -100211 }, + { 221, 221 }, + { 100221, 100221 }, + { 331, 331 }, + { 113, 113 }, + { 9910113, 9910113 }, + { 213, 213 }, + { -213, -213 }, + { 100113, 100113 }, + { 100213, 100213 }, + { -100213, -100213 }, + { 30113, 30113 }, + { 30213, 30213 }, + { -30213, -30213 }, + { 223, 223 }, + { 9910223, 9910223 }, + { 100223, 100223 }, + { 333, 333 }, + { 9910333, 9910333 }, + { 9000111, 9000111 }, + { 9000211, 9000211 }, + { -9000211, -9000211 }, + { 9010221, 9010221 }, + { 10221, 10221 }, + { 10113, 10113 }, + { 10213, 10213 }, + { -10213, -10213 }, + { 10223, 10223 }, + { 10333, 10333 }, + { 20113, 20113 }, + { 20213, 20213 }, + { -20213, -20213 }, + { 20223, 20223 }, + { 20333, 20333 }, + { 115, 115 }, + { 215, 215 }, + { -215, -215 }, + { 225, 225 }, + { 9020221, 9030221 }, + { 335, 335 }, + { 311, 311 }, + { -311, -311 }, + { 310, 310 }, + { 130, 130 }, + { 321, 321 }, + { -321, -321 }, + { 313, 313 }, + { -313, -313 }, + { 323, 323 }, + { -323, -323 }, + { 10311, 10311 }, + { -10311, -10311 }, + { 10321, 10321 }, + { -10321, -10321 }, + { 10313, 10313 }, + { -10313, -10313 }, + { 10323, 10323 }, + { -10323, -10323 }, + { 315, 315 }, + { -315, -315 }, + { 325, 325 }, + { -325, -325 }, + { 20313, 20313 }, + { -20313, -20313 }, + { 20323, 20323 }, + { -20323, -20323 }, + { 100313, 100313 }, + { -100313, -100313 }, + { 100323, 100323 }, + { -100323, -100323 }, + { 30313, 30313 }, + { -30313, -30313 }, + { 30323, 30323 }, + { -30323, -30323 }, + { 317, 317 }, + { -317, -317 }, + { 327, 327 }, + { -327, -327 }, + { 319, 319 }, + { -319, -319 }, + { 329, 329 }, + { -329, -329 }, + { 411, 411 }, + { -411, -411 }, + { 421, 421 }, + { -421, -421 }, + { 413, 413 }, + { -413, -413 }, + { 423, 423 }, + { -423, -423 }, + { 10411, 10411 }, + { -10411, -10411 }, + { 10421, 10421 }, + { -10421, -10421 }, + { 10413, 10413 }, + { -10413, -10413 }, + { 10423, 10423 }, + { -10423, -10423 }, + { 415, 415 }, + { -415, -415 }, + { 425, 425 }, + { -425, -425 }, + { 20413, 20413 }, + { -20413, -20413 }, + { 20423, 20423 }, + { -20423, -20423 }, + { 431, 431 }, + { -431, -431 }, + { 433, 433 }, + { -433, -433 }, + { 10431, 10431 }, + { -10431, -10431 }, + { 10433, 10433 }, + { -10433, -10433 }, + { 435, 435 }, + { -435, -435 }, + { 20433, 20433 }, + { -20433, -20433 }, + { 30411, 100411 }, + { -30411, -100411 }, + { 30421, 100421 }, + { -30421, -100421 }, + { 30413, 100413 }, + { -30413, -100413 }, + { 30423, 100423 }, + { -30423, -100423 }, + { 511, 511 }, + { -511, -511 }, + { 521, 521 }, + { -521, -521 }, + { 513, 513 }, + { -513, -513 }, + { 523, 523 }, + { -523, -523 }, + { 10511, 10511 }, + { -10511, -10511 }, + { 10521, 10521 }, + { -10521, -10521 }, + { 10513, 10513 }, + { -10513, -10513 }, + { 10523, 10523 }, + { -10523, -10523 }, + { 515, 515 }, + { -515, -515 }, + { 525, 525 }, + { -525, -525 }, + { 20513, 20513 }, + { -20513, -20513 }, + { 20523, 20523 }, + { -20523, -20523 }, + { 531, 531 }, + { -531, -531 }, + { 533, 533 }, + { -533, -533 }, + { 10531, 10531 }, + { -10531, -10531 }, + { 10533, 10533 }, + { -10533, -10533 }, + { 535, 535 }, + { -535, -535 }, + { 20533, 20533 }, + { -20533, -20533 }, + { 541, 541 }, + { -541, -541 }, + { 543, 543 }, + { -543, -543 }, + { 10541, 10541 }, + { -10541, -10541 }, + { 10543, 10543 }, + { -10543, -10543 }, + { 545, 545 }, + { -545, -545 }, + { 20543, 20543 }, + { -20543, -20543 }, + { 441, 441 }, + { 100441, 100441 }, + { 443, 443 }, + { 9910443, 9910443 }, + { 100443, 100443 }, + { 30443, 30443 }, + { 9000443, 9000443 }, + { 9010443, 9010443 }, + { 9020443, 9020443 }, + { 10443, 10443 }, + { 10441, 10441 }, + { 20443, 20443 }, + { 445, 445 }, + { 551, 551 }, + { 100551, 100551 }, + { 200551, 200551 }, + { 553, 553 }, + { 100553, 100553 }, + { 200553, 200553 }, + { 300553, 300553 }, + { 9000553, 9000553 }, + { 10553, 10553 }, + { 110553, 110553 }, + { 210553, 210553 }, + { 10551, 10551 }, + { 20553, 20553 }, + { 555, 555 }, + { 110551, 110551 }, + { 120553, 120553 }, + { 100555, 100555 }, + { 210551, 210551 }, + { 220553, 220553 }, + { 200555, 200555 }, + { 10555, 10555 }, + { 110555, 110555 }, + { 30553, 30553 }, + { 20555, 20555 }, + { 557, 557 }, + { 130553, 130553 }, + { 120555, 120555 }, + { 100557, 100557 }, + { 9000221, 9090221 }, + { 1114, 1114 }, + { -1114, -1114 }, + { 9912112, 9912112 }, + { -9912112, -9912112 }, + { 2112, 2112 }, + { -2112, -2112 }, + { 2114, 2114 }, + { -2114, -2114 }, + { 9912212, 9912212 }, + { -9912212, -9912212 }, + { 2212, 2212 }, + { -2212, -2212 }, + { 2214, 2214 }, + { -2214, -2214 }, + { 2224, 2224 }, + { -2224, -2224 }, + { 3112, 3112 }, + { -3112, -3112 }, + { 3114, 3114 }, + { -3114, -3114 }, + { 3122, 3122 }, + { -3122, -3122 }, + { 13122, 13122 }, + { -13122, -13122 }, + { 3124, 3124 }, + { -3124, -3124 }, + { 23122, 23122 }, + { -23122, -23122 }, + { 33122, 33122 }, + { -33122, -33122 }, + { 13124, 13124 }, + { -13124, -13124 }, + { 43122, 43122 }, + { -43122, -43122 }, + { 53122, 53122 }, + { -53122, -53122 }, + { 3126, 3126 }, + { -3126, -3126 }, + { 13126, 13126 }, + { -13126, -13126 }, + { 13212, 13212 }, + { -13212, -13212 }, + { 13214, 13214 }, + { -13214, -13214 }, + { 23212, 23212 }, + { -23212, -23212 }, + { 3216, 3216 }, + { -3216, -3216 }, + { 3212, 3212 }, + { -3212, -3212 }, + { 3214, 3214 }, + { -3214, -3214 }, + { 3222, 3222 }, + { -3222, -3222 }, + { 3224, 3224 }, + { -3224, -3224 }, + { 3312, 3312 }, + { -3312, -3312 }, + { 3314, 3314 }, + { -3314, -3314 }, + { 3322, 3322 }, + { -3322, -3322 }, + { 3324, 3324 }, + { -3324, -3324 }, + { 3334, 3334 }, + { -3334, -3334 }, + { 14122, 14122 }, + { -14122, -14122 }, + { 14124, 14124 }, + { -14124, -14124 }, + { 4112, 4112 }, + { -4112, -4112 }, + { 4114, 4114 }, + { -4114, -4114 }, + { 4212, 4212 }, + { -4212, -4212 }, + { 4214, 4214 }, + { -4214, -4214 }, + { 4222, 4222 }, + { -4222, -4222 }, + { 4224, 4224 }, + { -4224, -4224 }, + { 4312, 4312 }, + { -4312, -4312 }, + { 4322, 4322 }, + { -4322, -4322 }, + { 4324, 4324 }, + { -4324, -4324 }, + { 4122, 4122 }, + { -4122, -4122 }, + { 4132, 4132 }, + { -4132, -4132 }, + { 4232, 4232 }, + { -4232, -4232 }, + { 4314, 4314 }, + { -4314, -4314 }, + { 4332, 4332 }, + { -4332, -4332 }, + { 4334, 4334 }, + { -4334, -4334 }, + { 4412, 4412 }, + { -4412, -4412 }, + { 4414, 4414 }, + { -4414, -4414 }, + { 4422, 4422 }, + { -4422, -4422 }, + { 4424, 4424 }, + { -4424, -4424 }, + { 4432, 4432 }, + { -4432, -4432 }, + { 4434, 4434 }, + { -4434, -4434 }, + { 5112, 5112 }, + { -5112, -5112 }, + { 5114, 5114 }, + { -5114, -5114 }, + { 5122, 5122 }, + { -5122, -5122 }, + { 5132, 5132 }, + { -5132, -5132 }, + { 5212, 5212 }, + { -5212, -5212 }, + { 5214, 5214 }, + { -5214, -5214 }, + { 5222, 5222 }, + { -5222, -5222 }, + { 5224, 5224 }, + { -5224, -5224 }, + { 5232, 5232 }, + { -5232, -5232 }, + { 5312, 5312 }, + { -5312, -5312 }, + { 5314, 5314 }, + { -5314, -5314 }, + { 5322, 5322 }, + { -5322, -5322 }, + { 5324, 5324 }, + { -5324, -5324 }, + { 5332, 5332 }, + { -5332, -5332 }, + { 5334, 5334 }, + { -5334, -5334 }, + { 2101, 2101 }, + { -2101, -2101 }, + { 3101, 3101 }, + { -3101, -3101 }, + { 3201, 3201 }, + { -3201, -3201 }, + { 4101, 4101 }, + { -4101, -4101 }, + { 4201, 4201 }, + { -4201, -4201 }, + { 4301, 4301 }, + { -4301, -4301 }, + { 5101, 5101 }, + { -5101, -5101 }, + { 5201, 5201 }, + { -5201, -5201 }, + { 5301, 5301 }, + { -5301, -5301 }, + { 5401, 5401 }, + { -5401, -5401 }, + { 1103, 1103 }, + { -1103, -1103 }, + { 2103, 2103 }, + { -2103, -2103 }, + { 2203, 2203 }, + { -2203, -2203 }, + { 3103, 3103 }, + { -3103, -3103 }, + { 3203, 3203 }, + { -3203, -3203 }, + { 3303, 3303 }, + { -3303, -3303 }, + { 4103, 4103 }, + { -4103, -4103 }, + { 4203, 4203 }, + { -4203, -4203 }, + { 4303, 4303 }, + { -4303, -4303 }, + { 4403, 4403 }, + { -4403, -4403 }, + { 5103, 5103 }, + { -5103, -5103 }, + { 5203, 5203 }, + { -5203, -5203 }, + { 5303, 5303 }, + { -5303, -5303 }, + { 5403, 5403 }, + { -5403, -5403 }, + { 5503, 5503 }, + { -5503, -5503 }, + { 30343, 30343 }, + { -30343, -30343 }, + { 30353, 30353 }, + { -30353, -30353 }, + { 30373, 30373 }, + { -30373, -30373 }, + { 30383, 30383 }, + { -30383, -30383 }, + { 30363, 30363 }, + { -30363, -30363 }, + { 450000000, 1000010020 }, + { -450000000, -1000010020 }, + { 460000000, 1000010030 }, + { -460000000, -1000010030 }, + { 470000000, 1000020040 }, + { -470000000, -1000020040 }, + { 490000000, 1000020030 }, + { -490000000, -1000020030 }, + { 480000000, 101 } + }; + + int listSize = sizeof(SList)/sizeof(SList[0]); + for( int k=0; k!=listSize; ++k) { + m.insert( std::make_pair( SList[k].hid, SList[k].pid) ); + } + return m; +} // EvtGenPDTMapInit() + +PDTEvtGenMap const & PDTEvtGenMapInit() +{ + static PDTEvtGenMap m; + static EvtGenPDTMap const & hmap = getEvtGenPDTMap(); + + for(EvtGenPDTMap::const_iterator cit=hmap.begin(), mend=hmap.end(); cit!=mend; ++cit ) { + m.insert( std::make_pair( cit->second, cit->first )); + } + return m; +} + +// +// getEvtGenPDTMap is the ONLY function allowed to call EvtGenPDTMapInit +// +EvtGenPDTMap const & getEvtGenPDTMap() +{ + static EvtGenPDTMap const & hmap = EvtGenPDTMapInit(); + return hmap; +} // getEvtGenPDTMap() + +// +// getPDTEvtGenMap is the ONLY function allowed to call EvtGenPDTMapInit +// +PDTEvtGenMap const & getPDTEvtGenMap() +{ + static PDTEvtGenMap const & hmap = PDTEvtGenMapInit(); + return hmap; +} // getPDTEvtGenMap() + +} // unnamed namespace + +int translateEvtGentoPDT( const int id ) +{ + static EvtGenPDTMap const & hmap = getEvtGenPDTMap(); + + EvtGenPDTMap::const_iterator const cit = hmap.find( id ); + // found it in the map + if ( cit != hmap.end() ) { return cit->second; } + // check to see if someone has defined a valid particle type + // that isn't in the map + if( isValid(id) ) { return id; } + return 0; +} + +int translatePDTtoEvtGen( const int id ) +{ + static PDTEvtGenMap const & pmap = getPDTEvtGenMap(); + + PDTEvtGenMap::const_iterator const cit = pmap.find( id ); + // found it in the map + if ( cit != pmap.end() ) { return cit->second; } + // check to see if someone has defined a valid particle type + // that isn't in the map + if( isValid(id) ) { return id; } + return 0; +} + +void writeEvtGenTranslationLine( int i, std::ostream & os ) +{ + // only write map entries + static EvtGenPDTMap const & hmap = getEvtGenPDTMap(); + + EvtGenPDTMap::const_iterator const cit = hmap.find( i ); + // found it in the map + if ( cit != hmap.end() ) { + int id = cit->second; + os << " EvtGen number: " ; + os.width(10); + os << i << " HepPID number: " ; + os.width(11); + os << id << " " << particleName(id) << std::endl; + // check reverse translation + int iback = translatePDTtoEvtGen(id); + if(iback != i) { + os << " WARNING: " << id << " translates back to " + << iback << " not to " << i << std::endl; + } + } + return; +} // writeEvtGenTranslationLine() + +void writeEvtGenTranslation( std::ostream & os ) +{ + writeVersion( os ); + os << " HepPID Particle List" << std::endl; + os << std::endl; + + int id, i, j, q1, q2, q3, l, m; + // special cases + for( id=1; id<102; ++id) { + writeEvtGenTranslationLine( id, os ); + writeEvtGenTranslationLine( -id, os ); + } + for( i=11; i<1000; ++i) { + id = i*10; + writeEvtGenTranslationLine( id, os ); + writeEvtGenTranslationLine( -id, os ); + } + // diquark + for( q2=1; q2<7; ++q2) { + for( q1=1; q1<7; ++q1) { + for( j=1; j<4; ++j) { + id = 1000*q2+100*q1+j; + writeEvtGenTranslationLine( id, os ); + writeEvtGenTranslationLine( -id, os ); + } + } + } + // mesons + for( q2=1; q2<10; ++q2) { + for( q1=1; q1<10; ++q1) { + for( j=1; j<10; ++j) { + for( m=0; m<9; ++m) { + for( l=0; l<10; ++l) { + id = 100000*m+10000*l+100*q2+10*q1+j; + writeEvtGenTranslationLine( id, os ); + writeEvtGenTranslationLine( -id, os ); + id = 9000000+100000*m+10000*l+100*q2+10*q1+j; + writeEvtGenTranslationLine( id, os ); + writeEvtGenTranslationLine( -id, os ); + } + } + } + } + } + // baryons + for( q3=1; q3<10; ++q3) { + for( q2=1; q2<10; ++q2) { + for( q1=1; q1<10; ++q1) { + for( j=1; j<10; ++j) { + for( m=0; m<9; ++m) { + id = 10000*m+1000*q3+100*q2+10*q1+j; + writeEvtGenTranslationLine( id, os ); + writeEvtGenTranslationLine( -id, os ); + } + } + } + } + } + // ions + for( i=1; i<=9; ++i) { + id = 400000000+10000000*i; + writeEvtGenTranslationLine( id, os ); + writeEvtGenTranslationLine( -id, os ); + } + + return; +} // writeEvtGenTranslation() + +} // HepPID diff --git a/libs/HepPID/src/translateGeanttoPDT.cc b/libs/HepPID/src/translateGeanttoPDT.cc new file mode 100644 index 000000000..4a3696b08 --- /dev/null +++ b/libs/HepPID/src/translateGeanttoPDT.cc @@ -0,0 +1,97 @@ +// ---------------------------------------------------------------------- +// +// translateGeanttoPDT.cc +// Author: Lynn Garren +// +// translate a Geant ID number to the standard numbering scheme +// +// ---------------------------------------------------------------------- + +#include + +#include "HepPID/Version.hh" +#include "HepPID/ParticleIDTranslations.hh" +#include "HepPID/ParticleIDMethods.hh" + +#define IDMAX 49 + +namespace HepPID { + +int translateGeanttoPDT( const int id ) +{ + static int IDG2H[IDMAX] = { + 22, // gamma + -11, // e + 11, // e- + 12, // nu (nu_e) + -13, // mu + 13, // mu- + 111, // pi0 + 211, // pi + -211, // pi- + 130, // K0L + 321, // K + -321, // K- + 2112, // n + 2212, // p + -2212, // p~ + 310, // K0s + 221, // eta + 3122, // Lambda + 3222, // Sigma + 3212, // Sigma0 + 3112, // Sigma- + 3322, // Xi0 + 3312, // Xi- + 3334, // Omega- + -2112, // n~ + -3122, // Lambda~ + -3112, // Sigma~ + -3212, // Sigma0~ + -3222, // sigma-~ + -3322, // Xi0~ + -3312, // Xi-~ + -3334, // Omega-~ + -15, // tau + 15, // tau- + 411, // D + -411, // D- + 421, // D0 + -421, // D0~ + 431, // Ds + -431, // Ds- + 4122, // Lambda_ + 24, // W + -24, // W- + 23, // Z + 1000010020, // deuteron + 1000010030, // tritium + 1000020040, // alpha + 0, // geantino + 1000020030 }; // He3 + static int nwhine_max = 10; + int nwhine = 0; + int gtran = 0; + +//..............geantino + if( id == 48 ) { + nwhine = nwhine + 1; + if( nwhine <= nwhine_max ) { + std::cout << "GTRAN: geantino " << id + << " not known to HEP (set to 0)" << std::endl; + } +//...............normal translation + } else if( id <= IDMAX ) { + gtran = IDG2H[id-1]; +//............anything } else { + } else { + nwhine = nwhine + 1; + if( nwhine <= nwhine_max ) { + std::cout << "GTRAN: GEANT particle " << id + << " not known to HEP (set to 0)" << std::endl; + } + } + return gtran; +} + +} // HepPID diff --git a/libs/HepPID/src/translateHerwig.cc b/libs/HepPID/src/translateHerwig.cc new file mode 100644 index 000000000..6b3a026ba --- /dev/null +++ b/libs/HepPID/src/translateHerwig.cc @@ -0,0 +1,641 @@ +// ------------------------------------ +// +// translateHerwig.cc +// Author: Lynn Garren +// +// ..convert from HERWIG numbering scheme to PDT numbering scheme +// use a static map for both translateHerwigtoPDT and translatePDTtoHerwig +// +// The maps are initialized if and only if the public functions are called. +// Because the maps are static, the initialization happens only once. +// +// The user NEVER calls HerwigPDTMapInit() +// We use a data table (struct SList) so that compile time is not impacted. +// +// public functions: +// int translateHerwigtoPDT( const int id ) +// int translatePDTtoHerwig( const int id ) +// HerwigPDTMap const & getHerwigPDTMap() +// PDTHerwigMap const & getPDTHerwigMap() +// +// ------------------------------------ + +#include +#include // make_pair + +#include "HepPID/Version.hh" +#include "HepPID/ParticleIDTranslations.hh" +#include "HepPID/ParticleIDMethods.hh" +#include "HepPID/ParticleName.hh" + +namespace HepPID { + + typedef std::map< int, int > HerwigPDTMap; + typedef std::map< int, int > PDTHerwigMap; + +namespace { // HerwigPDTMapInit is private + + HerwigPDTMap const & getHerwigPDTMap(); + PDTHerwigMap const & getPDTHerwigMap(); + +HerwigPDTMap const & HerwigPDTMapInit() +{ + + static HerwigPDTMap m; + + static const struct { + int hid; // Herwig + int pid; // PDT + } SList[] = { + { 1, 1 }, + { 2, 2 }, + { 3, 3 }, + { 4, 4 }, + { 5, 5 }, + { 6, 6 }, + { 7, 7 }, + { 8, 8 }, + { -1, -1 }, + { -2, -2 }, + { -3, -3 }, + { -4, -4 }, + { -5, -5 }, + { -6, -6 }, + { -7, -7 }, + { -8, -8 }, + { 11, 11 }, + { 12, 12 }, + { 13, 13 }, + { 14, 14 }, + { 15, 15 }, + { 16, 16 }, + { -11, -11 }, + { -12, -12 }, + { -13, -13 }, + { -14, -14 }, + { -15, -15 }, + { -16, -16 }, + { 21, 21 }, + { 22, 22 }, + { 23, 23 }, + { 24, 24 }, + { -24, -24 }, + { 25, 25 }, + { 26, 51 }, + { 32, 32 }, + { 35, 35 }, + { 36, 36 }, + { 37, 37 }, + { -37, -37 }, + { 39, 39 }, + { 91, 91 }, + { 98, 9920022 }, + { 99, 9922212 }, + { -99, -9922212 }, + { 111, 111 }, + { 221, 221 }, + { 113, 113 }, + { 223, 223 }, + { 331, 331 }, + { 225, 225 }, + { 20113, 20113 }, + { 20223, 20223 }, + { 115, 115 }, + { -211, -211 }, + { -213, -213 }, + { -20213, -20213 }, + { -215, -215 }, + { -321, -321 }, + { -323, -323 }, + { -20323, -20323 }, + { -325, -325 }, + { 211, 211 }, + { 213, 213 }, + { 20213, 20213 }, + { 215, 215 }, + { -311, -311 }, + { -313, -313 }, + { -20313, -20313 }, + { -315, -315 }, + { 321, 321 }, + { 323, 323 }, + { 20323, 20323 }, + { 325, 325 }, + { 311, 311 }, + { 313, 313 }, + { 20313, 20313 }, + { 315, 315 }, + { 333, 333 }, + { 20333, 20333 }, + { 335, 335 }, + { 310, 310 }, + { 130, 130 }, + { 10111, 10111 }, + { 10211, 10211 }, + { -10211, -10211 }, + { 2212, 2212 }, + { 2214, 2214 }, + { 2112, 2112 }, + { 2114, 2114 }, + { 1114, 1114 }, + { 3122, 3122 }, + { 3212, 3212 }, + { 3214, 3214 }, + { 3112, 3112 }, + { 3114, 3114 }, + { 3312, 3312 }, + { 3314, 3314 }, + { 2224, 2224 }, + { 3222, 3222 }, + { 3224, 3224 }, + { 3322, 3322 }, + { 3324, 3324 }, + { 3334, 3334 }, + { -2212, -2212 }, + { -2214, -2214 }, + { -2112, -2112 }, + { -2114, -2114 }, + { -1114, -1114 }, + { -3122, -3122 }, + { -3212, -3212 }, + { -3214, -3214 }, + { -3112, -3112 }, + { -3114, -3114 }, + { -3312, -3312 }, + { -3314, -3314 }, + { -2224, -2224 }, + { -3222, -3222 }, + { -3224, -3224 }, + { -3322, -3322 }, + { -3324, -3324 }, + { -3334, -3334 }, + { 2203, 2203 }, + { 2101, 2101 }, + { 1103, 1103 }, + { 3201, 3201 }, + { 3101, 3101 }, + { 3303, 3303 }, + { -2203, -2203 }, + { -2101, -2101 }, + { -1103, -1103 }, + { -3201, -3201 }, + { -3101, -3101 }, + { -3303, -3303 }, + { 411, 411 }, + { 413, 413 }, + { 20413, 20413 }, + { 415, 415 }, + { 421, 421 }, + { 423, 423 }, + { 20423, 20423 }, + { 425, 425 }, + { 431, 431 }, + { 433, 433 }, + { 20433, 20433 }, + { 435, 435 }, + { 4222, 4222 }, + { 4224, 4224 }, + { 4122, 4122 }, + { 4212, 4212 }, + { 4214, 4214 }, + { 4112, 4112 }, + { 4114, 4114 }, + { 4232, 4232 }, + { 4322, 4322 }, + { 4324, 4324 }, + { 4132, 4132 }, + { 4312, 4312 }, + { 4314, 4314 }, + { 4332, 4332 }, + { 4334, 4334 }, + { 441, 441 }, + { 443, 443 }, + { 10441, 10441 }, + { 100443, 100443 }, + { 30443, 30443 }, + { -411, -411 }, + { -413, -413 }, + { -20413, -20413 }, + { -415, -415 }, + { -421, -421 }, + { -423, -423 }, + { -20423, -20423 }, + { -425, -425 }, + { -431, -431 }, + { -433, -433 }, + { -20433, -20433 }, + { -435, -435 }, + { -4222, -4222 }, + { -4224, -4224 }, + { -4122, -4122 }, + { -4212, -4212 }, + { -4214, -4214 }, + { -4112, -4112 }, + { -4114, -4114 }, + { -4232, -4232 }, + { -4322, -4322 }, + { -4324, -4324 }, + { -4132, -4132 }, + { -4312, -4312 }, + { -4314, -4314 }, + { -4332, -4332 }, + { -4334, -4334 }, + { -511, -511 }, + { -521, -521 }, + { -531, -531 }, + { 5222, 5222 }, + { 5122, 5122 }, + { 5112, 5112 }, + { 5232, 5232 }, + { 5132, 5132 }, + { 5332, 5332 }, + { -541, -541 }, + { 553, 553 }, + { -651, -651 }, + { 611, 611 }, + { 621, 621 }, + { 631, 631 }, + { 6222, 6222 }, + { 6122, 6122 }, + { 6112, 6112 }, + { 6232, 6232 }, + { 6132, 6132 }, + { 6332, 6332 }, + { 641, 641 }, + { 651, 651 }, + { 663, 663 }, + { 511, 511 }, + { 521, 521 }, + { 531, 531 }, + { -5222, -5222 }, + { -5122, -5122 }, + { -5112, -5112 }, + { -5232, -5232 }, + { -5132, -5132 }, + { -5332, -5332 }, + { 541, 541 }, + { -611, -611 }, + { -621, -621 }, + { -631, -631 }, + { -6222, -6222 }, + { -6122, -6122 }, + { -6112, -6112 }, + { -6232, -6232 }, + { -6132, -6132 }, + { -6332, -6332 }, + { -641, -641 }, + { -513, -513 }, + { -523, -523 }, + { -533, -533 }, + { -20513, -20513 }, + { -20523, -20523 }, + { -20533, -20533 }, + { -515, -515 }, + { -525, -525 }, + { -535, -535 }, + { 513, 513 }, + { 523, 523 }, + { 533, 533 }, + { 20513, 20513 }, + { 20523, 20523 }, + { 20533, 20533 }, + { 515, 515 }, + { 525, 525 }, + { 535, 535 }, + { 10113, 10113 }, + { 10213, 10213 }, + { -10213, -10213 }, + { 10223, 10223 }, + { 10333, 10333 }, + { 9000111, 9000111 }, + { 9000211, 9000211 }, + { -9000211, -9000211 }, + { 9010221, 9010221 }, + { 10221, 10221 }, + { 543, 543 }, + { -543, -543 }, + { 20543, 20543 }, + { -20543, -20543 }, + { 545, 545 }, + { -545, -545 }, + { 10443, 10443 }, + { 20443, 20443 }, + { 445, 445 }, + { 551, 551 }, + { 10553, 10553 }, + { 10551, 10551 }, + { 20553, 20553 }, + { 555, 555 }, + { 10313, 10313 }, + { 10323, 10323 }, + { -10313, -10313 }, + { -10323, -10323 }, + { 10413, 10413 }, + { 10423, 10423 }, + { 10433, 10433 }, + { -10413, -10413 }, + { -10423, -10423 }, + { -10433, -10433 }, + { 10513, 10513 }, + { 10523, 10523 }, + { 10533, 10533 }, + { 10543, 10543 }, + { -10513, -10513 }, + { -10523, -10523 }, + { -10533, -10533 }, + { -10543, -10543 }, + { 10321, 10321 }, + { 10311, 10311 }, + { -10311, -10311 }, + { -10321, -10321 }, + { 10411, 10411 }, + { 10421, 10421 }, + { 10431, 10431 }, + { -10411, -10411 }, + { -10421, -10421 }, + { -10431, -10431 }, + { 10511, 10511 }, + { 10521, 10521 }, + { 10531, 10531 }, + { 10541, 10541 }, + { -10511, -10511 }, + { -10521, -10521 }, + { -10531, -10531 }, + { -10541, -10541 }, + { 5114, 5114 }, + { 5212, 5212 }, + { 5214, 5214 }, + { 5224, 5224 }, + { 5322, 5322 }, + { 5324, 5324 }, + { 5312, 5312 }, + { 5314, 5314 }, + { 5334, 5334 }, + { -5114, -5114 }, + { -5212, -5212 }, + { -5214, -5214 }, + { -5224, -5224 }, + { -5322, -5322 }, + { -5324, -5324 }, + { -5312, -5312 }, + { -5314, -5314 }, + { -5334, -5334 }, + { 10325, 10325 }, + { 10315, 10315 }, + { -10315, -10315 }, + { -10325, -10325 }, + { 30323, 30323 }, + { 30313, 30313 }, + { -30313, -30313 }, + { -30323, -30323 }, + { 20325, 20325 }, + { 20315, 20315 }, + { -20315, -20315 }, + { -20325, -20325 }, + { 327, 327 }, + { 317, 317 }, + { -317, -317 }, + { -327, -327 }, + { 10215, 10215 }, + { 10115, 10115 }, + { -10215, -10215 }, + { 30213, 30213 }, + { 30113, 30113 }, + { -30213, -30213 }, + { 217, 217 }, + { 117, 117 }, + { -217, -217 }, + { 100553, 100553 }, + { 110551, 110551 }, + { 120553, 120553 }, + { 100555, 100555 }, + { 200553, 200553 }, + { 300553, 300553 }, + { 227, 227 }, + { 337, 337 }, + { 10225, 10225 }, + { 10335, 10335 }, + { 30223, 30223 }, + { 1000001, 1000001 }, + { 1000002, 1000002 }, + { 1000003, 1000003 }, + { 1000004, 1000004 }, + { 1000005, 1000005 }, + { 1000006, 1000006 }, + { -1000001, -1000001 }, + { -1000002, -1000002 }, + { -1000003, -1000003 }, + { -1000004, -1000004 }, + { -1000005, -1000005 }, + { -1000006, -1000006 }, + { 2000001, 2000001 }, + { 2000002, 2000002 }, + { 2000003, 2000003 }, + { 2000004, 2000004 }, + { 2000005, 2000005 }, + { 2000006, 2000006 }, + { -2000001, -2000001 }, + { -2000002, -2000002 }, + { -2000003, -2000003 }, + { -2000004, -2000004 }, + { -2000005, -2000005 }, + { -2000006, -2000006 }, + { 1000011, 1000011 }, + { 1000012, 1000012 }, + { 1000013, 1000013 }, + { 1000014, 1000014 }, + { 1000015, 1000015 }, + { 1000016, 1000016 }, + { -1000011, -1000011 }, + { -1000012, -1000012 }, + { -1000013, -1000013 }, + { -1000014, -1000014 }, + { -1000015, -1000015 }, + { -1000016, -1000016 }, + { 2000011, 2000011 }, + { 2000012, 2000012 }, + { 2000013, 2000013 }, + { 2000014, 2000014 }, + { 2000015, 2000015 }, + { 2000016, 2000016 }, + { -2000011, -2000011 }, + { -2000012, -2000012 }, + { -2000013, -2000013 }, + { -2000014, -2000014 }, + { -2000015, -2000015 }, + { -2000016, -2000016 }, + { 1000021, 1000021 }, + { 1000022, 1000022 }, + { 1000023, 1000023 }, + { 1000025, 1000025 }, + { 1000035, 1000035 }, + { 1000024, 1000024 }, + { 1000037, 1000037 }, + { -1000024, -1000024 }, + { -1000037, -1000037 }, + { 1000039, 1000039 } + }; + + int listSize = sizeof(SList)/sizeof(SList[0]); + for( int k=0; k!=listSize; ++k) { + m.insert( std::make_pair( SList[k].hid, SList[k].pid) ); + } + return m; +} // HerwigPDTMapInit() + +PDTHerwigMap const & PDTHerwigMapInit() +{ + static PDTHerwigMap m; + static HerwigPDTMap const & hmap = getHerwigPDTMap(); + + for(HerwigPDTMap::const_iterator cit=hmap.begin(), mend=hmap.end(); cit!=mend; ++cit ) { + m.insert( std::make_pair( cit->second, cit->first )); + } + return m; +} + +// +// getHerwigPDTMap is the ONLY function allowed to call HerwigPDTMapInit +// +HerwigPDTMap const & getHerwigPDTMap() +{ + static HerwigPDTMap const & hmap = HerwigPDTMapInit(); + return hmap; +} // getHerwigPDTMap() + +// +// getPDTHerwigMap is the ONLY function allowed to call HerwigPDTMapInit +// +PDTHerwigMap const & getPDTHerwigMap() +{ + static PDTHerwigMap const & hmap = PDTHerwigMapInit(); + return hmap; +} // getPDTHerwigMap() + +} // unnamed namespace + +int translateHerwigtoPDT( const int id ) +{ + static HerwigPDTMap const & hmap = getHerwigPDTMap(); + + HerwigPDTMap::const_iterator const cit = hmap.find( id ); + // found it in the map + if ( cit != hmap.end() ) { return cit->second; } + // check to see if someone has defined a valid particle type + // that isn't in the map + if( isValid(id) ) { return id; } + return 0; +} + +int translatePDTtoHerwig( const int id ) +{ + static PDTHerwigMap const & pmap = getPDTHerwigMap(); + + PDTHerwigMap::const_iterator const cit = pmap.find( id ); + // found it in the map + if ( cit != pmap.end() ) { return cit->second; } + // check to see if someone has defined a valid particle type + // that isn't in the map + if( isValid(id) ) { return id; } + return 0; +} + +void writeHerwigTranslationLine( int i, std::ostream & os ) +{ + // only write map entries + static HerwigPDTMap const & hmap = getHerwigPDTMap(); + + HerwigPDTMap::const_iterator const cit = hmap.find( i ); + // found it in the map + if ( cit != hmap.end() ) { + int id = cit->second; + os << " Herwig number: " ; + os.width(10); + os << i << " HepPID number: " ; + os.width(10); + os << id << " " << particleName(id) << std::endl; + // check reverse translation + int iback = translatePDTtoHerwig(id); + if(iback != i) { + os << " WARNING: " << id << " translates back to " + << iback << " not to " << i << std::endl; + } + } + return; +} // writeHerwigTranslationLine() + +void writeHerwigTranslation( std::ostream & os ) +{ + writeVersion( os ); + os << " HepPID Particle List" << std::endl; + os << std::endl; + + int id, i, j, q1, q2, q3, l, m, n; + // special cases + for( id=1; id<101; ++id) { + writeHerwigTranslationLine( id, os ); + writeHerwigTranslationLine( -id, os ); + } + // SUSY + for( n=1; n<3; ++n) { + for( i=1; i<40; ++i) { + id = 1000000*n+i; + writeHerwigTranslationLine( id, os ); + writeHerwigTranslationLine( -id, os ); + } + } + // diquark + for( i=11; i<100; ++i) { + for( j=0; j<10; ++j) { + id = 100*i+j; + writeHerwigTranslationLine( id, os ); + writeHerwigTranslationLine( -id, os ); + } + } + // mesons + for( q2=1; q2<10; ++q2) { + for( q1=1; q1<10; ++q1) { + for( j=1; j<10; ++j) { + for( m=0; m<9; ++m) { + for( l=0; l<10; ++l) { + id = 100000*m+10000*l+100*q2+10*q1+j; + writeHerwigTranslationLine( id, os ); + writeHerwigTranslationLine( -id, os ); + id = 9000000+100000*m+10000*l+100*q2+10*q1+j; + writeHerwigTranslationLine( id, os ); + writeHerwigTranslationLine( -id, os ); + } + } + } + } + } + // baryons + for( q3=1; q3<10; ++q3) { + for( q2=1; q2<10; ++q2) { + for( q1=1; q1<10; ++q1) { + for( j=1; j<10; ++j) { + id = 1000*q3+100*q2+10*q1+j; + writeHerwigTranslationLine( id, os ); + writeHerwigTranslationLine( -id, os ); + } + } + } + } + // pentaquarks + for( l=1; l<9; ++l ) { + for ( m=1; m<9; ++m ) { + for( q3=1; q3<9; ++q3) { + for( q2=1; q2<9; ++q2) { + for( q1=1; q1<9; ++q1) { + id = 9*1000000+l*100000+m*10000+1000*q3+100*q2+10*q1+2; + writeHerwigTranslationLine( id, os ); + writeHerwigTranslationLine( -id, os ); + } + } + } + } + } + return; +} // writeHerwigTranslation() + +} // HepPID diff --git a/libs/HepPID/src/translateIsajet.cc b/libs/HepPID/src/translateIsajet.cc new file mode 100644 index 000000000..3ba1473b7 --- /dev/null +++ b/libs/HepPID/src/translateIsajet.cc @@ -0,0 +1,1003 @@ +// ---------------------------------------------------------------------- +// +// translateIsajet.cc +// Author: Lynn Garren +// +// translate an ID number to or from the standard numbering scheme and Isajet +// use static maps +// +// Isajet uses a different numbering scheme +// Private methods will attempt to convert mesons and baryons not in the map +// +// The maps are initialized if and only if the public functions are called. +// Because the maps are static, the initialization happens only once. +// +// The user NEVER calls IsajetPDTMapInit() +// We use a data table (struct SList) so that compile time is not impacted. +// +// public functions: +// int translateIsajettoPDT( const int id ) +// int translatePDTtoIsajet( const int id ) +// IsajetPDTMap const & getIsajetPDTMap() +// PDTIsajetMap const & getPDTIsajetMap() +// +// ---------------------------------------------------------------------- + +#include +#include // make_pair + +#include "HepPID/Version.hh" +#include "HepPID/ParticleIDTranslations.hh" +#include "HepPID/ParticleIDMethods.hh" +#include "HepPID/ParticleName.hh" + +namespace HepPID { + + typedef std::map< int, int > IsajetPDTMap; + typedef std::map< int, int > PDTIsajetMap; + +namespace { // IsajetPDTMapInit is private + + IsajetPDTMap const & getIsajetPDTMap(); + PDTIsajetMap const & getPDTIsajetMap(); + +IsajetPDTMap const & IsajetPDTMapInit() +{ + + static IsajetPDTMap m; + + static const struct { + int id; // Isajet + int pid; // PDT + } SList[] = { + { 1, 2 }, + { -1, -2 }, + { 2, 1 }, + { -2, -1 }, + { 3, 3 }, + { -3, -3 }, + { 4, 4 }, + { -4, -4 }, + { 5, 5 }, + { -5, -5 }, + { 6, 6 }, + { -6, -6 }, + { 7, 7 }, + { -7, -7 }, + { 8, 8 }, + { -8, -8 }, + { 9, 21 }, + { 10, 22 }, + { 11, 12 }, + { -11, -12 }, + { 12, 11 }, + { -12, -11 }, + { 13, 14 }, + { -13, -14 }, + { 14, 13 }, + { -14, -13 }, + { 15, 16 }, + { -15, -16 }, + { 16, 15 }, + { -16, -15 }, + { 20, 310 }, + { -20, 130 }, + { 21, 1000002 }, + { -21, -1000002 }, + { 22, 1000001 }, + { -22, -1000001 }, + { 23, 1000003 }, + { -23, -1000003 }, + { 24, 1000004 }, + { -24, -1000004 }, + { 25, 1000005 }, + { -25, -1000005 }, + { 26, 1000006 }, + { -26, -1000006 }, + { 29, 1000021 }, + { 30, 1000022 }, + { 31, 1000012 }, + { -31, -1000012 }, + { 32, 1000011 }, + { -32, -1000011 }, + { 33, 1000014 }, + { -33, -1000014 }, + { 34, 1000013 }, + { -34, -1000013 }, + { 35, 1000016 }, + { -35, -1000016 }, + { 36, 1000015 }, + { -36, -1000015 }, + { 39, 1000024 }, + { -39, -1000024 }, + { 40, 1000023 }, + { 41, 2000002 }, + { -41, -2000002 }, + { 42, 2000001 }, + { -42, -2000001 }, + { 43, 2000003 }, + { -43, -2000003 }, + { 44, 2000004 }, + { -44, -2000004 }, + { 45, 2000005 }, + { -45, -2000005 }, + { 46, 2000006 }, + { -46, -2000006 }, + { 49, 1000037 }, + { -49, -1000037 }, + { 50, 1000025 }, + { 51, 2000012 }, + { -51, -2000012 }, + { 52, 2000011 }, + { -52, -2000011 }, + { 53, 2000014 }, + { -53, -2000014 }, + { 54, 2000013 }, + { -54, -2000013 }, + { 55, 2000016 }, + { -55, -2000016 }, + { 56, 2000015 }, + { -56, -2000015 }, + { 60, 1000035 }, + { 80, 24 }, + { -80, -24 }, + { 81, 25 }, + { 82, 51 }, + { 83, 35 }, + { 84, 36 }, + { 85, 55 }, + { -85, -55 }, + { 86, 37 }, + { -86, -37 }, + { 87, 53 }, + { -87, -53 }, + { 88, 52 }, + { -88, -52 }, + { 89, 54 }, + { -89, -54 }, + { 90, 23 }, + { 91, 1000039 }, + { 92, 39 }, + { 110, 111 }, + { 111, 113 }, + { 112, 225 }, + { 120, 211 }, + { -120, -211 }, + { 121, 213 }, + { -121, -213 }, + { 130, 321 }, + { -130, -321 }, + { 131, 323 }, + { -131, -323 }, + { 132, 325 }, + { -132, -325 }, + { 140, -421 }, + { -140, 421 }, + { 141, -423 }, + { -141, 423 }, + { 150, 521 }, + { -150, -521 }, + { 151, 523 }, + { -151, -523 }, + { 160, -621 }, + { -160, 621 }, + { 161, -623 }, + { -161, 623 }, + { 170, 721 }, + { -170, -721 }, + { 171, 723 }, + { -171, -723 }, + { 180, 821 }, + { -180, -821 }, + { 181, 823 }, + { -181, -823 }, + { 220, 221 }, + { 221, 223 }, + { 230, 311 }, + { -230, -311 }, + { 231, 313 }, + { -231, -313 }, + { 232, 315 }, + { -232, -315 }, + { 240, -411 }, + { -240, 411 }, + { 241, -413 }, + { -241, 413 }, + { 250, 511 }, + { -250, -511 }, + { 251, 513 }, + { -251, -513 }, + { 260, -611 }, + { -260, 611 }, + { 261, -613 }, + { -261, 613 }, + { 270, 711 }, + { -270, -711 }, + { 271, 713 }, + { -271, -713 }, + { 280, 811 }, + { -280, -811 }, + { 281, 813 }, + { -281, -813 }, + { 330, 331 }, + { 331, 333 }, + { 340, -431 }, + { -340, 431 }, + { 341, -433 }, + { -341, 433 }, + { 350, 531 }, + { -350, -531 }, + { 351, 533 }, + { -351, -533 }, + { 360, -631 }, + { -360, 631 }, + { 361, -633 }, + { -361, 633 }, + { 370, 731 }, + { -370, -731 }, + { 371, 733 }, + { -371, -733 }, + { 380, 831 }, + { -380, -831 }, + { 381, 833 }, + { -381, -833 }, + { 440, 441 }, + { 441, 443 }, + { 450, 541 }, + { -450, -541 }, + { 451, 543 }, + { -451, -543 }, + { 460, 641 }, + { -460, -641 }, + { 461, 643 }, + { -461, -643 }, + { 470, 741 }, + { -470, -741 }, + { 471, 743 }, + { -471, -743 }, + { 480, 841 }, + { -480, -841 }, + { 481, 843 }, + { -481, -843 }, + { 550, 551 }, + { 551, 553 }, + { 560, -651 }, + { -560, 651 }, + { 561, -653 }, + { -561, 653 }, + { 570, 751 }, + { -570, -751 }, + { 571, 753 }, + { -571, -753 }, + { 580, 851 }, + { -580, -851 }, + { 581, 853 }, + { -581, -853 }, + { 660, 661 }, + { 661, 663 }, + { 670, 761 }, + { -670, -761 }, + { 671, 763 }, + { -671, -763 }, + { 680, 861 }, + { -680, -861 }, + { 681, 863 }, + { -681, -863 }, + { 770, 771 }, + { 771, 773 }, + { 780, 871 }, + { -780, -871 }, + { 781, 873 }, + { -781, -873 }, + { 880, 881 }, + { 881, 883 }, + { 1100, 2203 }, + { -1100, -2203 }, + { 1111, 2224 }, + { -1111, -2224 }, + { 1120, 2212 }, + { -1120, -2212 }, + { 1121, 2214 }, + { -1121, -2214 }, + { 1130, 3222 }, + { -1130, -3222 }, + { 1131, 3224 }, + { -1131, -3224 }, + { 1140, 4222 }, + { -1140, -4222 }, + { 1141, 4224 }, + { -1141, -4224 }, + { 1150, 5222 }, + { -1150, -5222 }, + { 1151, 5224 }, + { -1151, -5224 }, + { 1160, 6222 }, + { -1160, -6222 }, + { 1161, 6224 }, + { -1161, -6224 }, + { 1170, 7222 }, + { -1170, -7222 }, + { 1171, 7224 }, + { -1171, -7224 }, + { 1180, 8222 }, + { -1180, -8222 }, + { 1181, 8224 }, + { -1181, -8224 }, + { 1200, 2101 }, + { -1200, -2101 }, + { 1220, 2112 }, + { -1220, -2112 }, + { 1221, 2114 }, + { -1221, -2114 }, + { 1230, 3212 }, + { -1230, -3212 }, + { 1231, 3214 }, + { -1231, -3214 }, + { 1240, 4212 }, + { -1240, -4212 }, + { 1241, 4214 }, + { -1241, -4214 }, + { 1250, 5212 }, + { -1250, -5212 }, + { 1251, 5214 }, + { -1251, -5214 }, + { 1260, 6212 }, + { -1260, -6212 }, + { 1261, 6214 }, + { -1261, -6214 }, + { 1270, 7212 }, + { -1270, -7212 }, + { 1271, 7214 }, + { -1271, -7214 }, + { 1280, 8212 }, + { -1280, -8212 }, + { 1281, 8214 }, + { -1281, -8214 }, + { 1300, 3201 }, + { -1300, -3201 }, + { 1330, 3322 }, + { -1330, -3322 }, + { 1331, 3324 }, + { -1331, -3324 }, + { 1340, 4322 }, + { -1340, -4322 }, + { 1341, 4324 }, + { -1341, -4324 }, + { 1350, 5322 }, + { -1350, -5322 }, + { 1351, 5324 }, + { -1351, -5324 }, + { 1360, 6322 }, + { -1360, -6322 }, + { 1361, 6324 }, + { -1361, -6324 }, + { 1370, 7322 }, + { -1370, -7322 }, + { 1371, 7324 }, + { -1371, -7324 }, + { 1380, 8322 }, + { -1380, -8322 }, + { 1381, 8324 }, + { -1381, -8324 }, + { 1400, -4201 }, + { -1400, 4201 }, + { 1440, 4422 }, + { -1440, -4422 }, + { 1441, 4424 }, + { -1441, -4424 }, + { 1450, 5422 }, + { -1450, -5422 }, + { 1451, 5424 }, + { -1451, -5424 }, + { 1460, 6422 }, + { -1460, -6422 }, + { 1461, 6424 }, + { -1461, -6424 }, + { 1500, 5201 }, + { -1500, -5201 }, + { 1550, 5522 }, + { -1550, -5522 }, + { 1551, 5524 }, + { -1551, -5524 }, + { 1560, 6522 }, + { -1560, -6522 }, + { 1561, 6524 }, + { -1561, -6524 }, + { 1600, -6201 }, + { -1600, 6201 }, + { 1660, 6622 }, + { -1660, -6622 }, + { 1661, 6624 }, + { -1661, -6624 }, + { 2130, 3122 }, + { -2130, -3122 }, + { 2140, 4122 }, + { -2140, -4122 }, + { 2150, 5122 }, + { -2150, -5122 }, + { 2160, 6122 }, + { -2160, -6122 }, + { 2170, 7122 }, + { -2170, -7122 }, + { 2180, 8122 }, + { -2180, -8122 }, + { 2200, 1103 }, + { -2200, -1103 }, + { 2221, 1114 }, + { -2221, -1114 }, + { 2230, 3112 }, + { -2230, -3112 }, + { 2231, 3114 }, + { -2231, -3114 }, + { 2240, 4112 }, + { -2240, -4112 }, + { 2241, 4114 }, + { -2241, -4114 }, + { 2250, 5112 }, + { -2250, -5112 }, + { 2251, 5114 }, + { -2251, -5114 }, + { 2260, 6112 }, + { -2260, -6112 }, + { 2261, 6114 }, + { -2261, -6114 }, + { 2270, 7112 }, + { -2270, -7112 }, + { 2271, 7114 }, + { -2271, -7114 }, + { 2280, 8112 }, + { -2280, -8112 }, + { 2281, 8114 }, + { -2281, -8114 }, + { 2300, 3101 }, + { -2300, -3101 }, + { 2330, 3312 }, + { -2330, -3312 }, + { 2331, 3314 }, + { -2331, -3314 }, + { 2340, 4312 }, + { -2340, -4312 }, + { 2341, 4314 }, + { -2341, -4314 }, + { 2350, 5312 }, + { -2350, -5312 }, + { 2351, 5314 }, + { -2351, -5314 }, + { 2360, 6312 }, + { -2360, -6312 }, + { 2361, 6314 }, + { -2361, -6314 }, + { 2370, 7312 }, + { -2370, -7312 }, + { 2371, 7314 }, + { -2371, -7314 }, + { 2380, 8312 }, + { -2380, -8312 }, + { 2381, 8314 }, + { -2381, -8314 }, + { 2400, -4101 }, + { -2400, 4101 }, + { 2440, 4412 }, + { -2440, -4412 }, + { 2441, 4414 }, + { -2441, -4414 }, + { 2450, 5412 }, + { -2450, -5412 }, + { 2451, 5414 }, + { -2451, -5414 }, + { 2460, 6412 }, + { -2460, -6412 }, + { 2461, 6414 }, + { -2461, -6414 }, + { 2500, 5101 }, + { -2500, -5101 }, + { 2550, 5512 }, + { -2550, -5512 }, + { 2551, 5514 }, + { -2551, -5514 }, + { 2560, 6512 }, + { -2560, -6512 }, + { 2561, 6514 }, + { -2561, -6514 }, + { 2600, -6101 }, + { -2600, 6101 }, + { 2660, 6612 }, + { -2660, -6612 }, + { 2661, 6614 }, + { -2661, -6614 }, + { 3140, 4232 }, + { -3140, -4232 }, + { 3150, 5232 }, + { -3150, -5232 }, + { 3160, 6232 }, + { -3160, -6232 }, + { 3170, 7232 }, + { -3170, -7232 }, + { 3180, 8232 }, + { -3180, -8232 }, + { 3240, 4132 }, + { -3240, -4132 }, + { 3250, 5132 }, + { -3250, -5132 }, + { 3260, 6132 }, + { -3260, -6132 }, + { 3270, 7132 }, + { -3270, -7132 }, + { 3280, 8132 }, + { -3280, -8132 }, + { 3300, 3303 }, + { -3300, -3303 }, + { 3331, 3334 }, + { -3331, -3334 }, + { 3340, 4332 }, + { -3340, -4332 }, + { 3341, 4334 }, + { -3341, -4334 }, + { 3350, 5332 }, + { -3350, -5332 }, + { 3351, 5334 }, + { -3351, -5334 }, + { 3360, 6332 }, + { -3360, -6332 }, + { 3361, 6334 }, + { -3361, -6334 }, + { 3370, 7332 }, + { -3370, -7332 }, + { 3371, 7334 }, + { -3371, -7334 }, + { 3380, 8332 }, + { -3380, -8332 }, + { 3381, 8334 }, + { -3381, -8334 }, + { 3400, -4301 }, + { -3400, 4301 }, + { 3440, 4432 }, + { -3440, -4432 }, + { 3441, 4434 }, + { -3441, -4434 }, + { 3450, 5432 }, + { -3450, -5432 }, + { 3451, 5434 }, + { -3451, -5434 }, + { 3460, 6432 }, + { -3460, -6432 }, + { 3461, 6434 }, + { -3461, -6434 }, + { 3500, 5301 }, + { -3500, -5301 }, + { 3550, 5532 }, + { -3550, -5532 }, + { 3551, 5534 }, + { -3551, -5534 }, + { 3560, 6532 }, + { -3560, -6532 }, + { 3561, 6534 }, + { -3561, -6534 }, + { 3600, -6301 }, + { -3600, 6301 }, + { 3660, 6632 }, + { -3660, -6632 }, + { 3661, 6634 }, + { -3661, -6634 }, + { 4150, 5242 }, + { -4150, -5242 }, + { 4160, 6242 }, + { -4160, -6242 }, + { 4250, 5142 }, + { -4250, -5142 }, + { 4260, 6142 }, + { -4260, -6142 }, + { 4350, 5342 }, + { -4350, -5342 }, + { 4360, 6342 }, + { -4360, -6342 }, + { 4400, 4403 }, + { -4400, -4403 }, + { 4441, 4444 }, + { -4441, -4444 }, + { 4450, 5442 }, + { -4450, -5442 }, + { 4451, 5444 }, + { -4451, -5444 }, + { 4460, 6442 }, + { -4460, -6442 }, + { 4461, 6444 }, + { -4461, -6444 }, + { 4500, 5401 }, + { -4500, -5401 }, + { 4550, 5542 }, + { -4550, -5542 }, + { 4551, 5544 }, + { -4551, -5544 }, + { 4560, 6542 }, + { -4560, -6542 }, + { 4561, 6544 }, + { -4561, -6544 }, + { 4600, 6401 }, + { -4600, -6401 }, + { 4660, 6642 }, + { -4660, -6642 }, + { 4661, 6644 }, + { -4661, -6644 }, + { 5160, 6252 }, + { -5160, -6252 }, + { 5260, 6152 }, + { -5260, -6152 }, + { 5360, 6352 }, + { -5360, -6352 }, + { 5460, 6452 }, + { -5460, -6452 }, + { 5500, 5503 }, + { -5500, -5503 }, + { 5551, 5554 }, + { -5551, -5554 }, + { 5560, 6552 }, + { -5560, -6552 }, + { 5561, 6554 }, + { -5561, -6554 }, + { 5600, -6501 }, + { -5600, 6501 }, + { 5660, 6652 }, + { -5660, -6652 }, + { 5661, 6654 }, + { -5661, -6654 }, + { 6600, 6603 }, + { -6600, -6603 }, + { 6661, 6664 }, + { -6661, -6664 }, + { 10016, 93 }, + { -10016, -93 }, + { 20016, 94 }, + { -20016, -94 }, + { 10110, 9010221 }, + { 10111, 20113 }, + { 10121, 20213 }, + { -10121, -20213 }, + { 10131, 10323 }, + { -10131, -10323 }, + { 10231, 10313 }, + { -10231, -10313 }, + { 10441, 100443 }, + { 20440, 10441 }, + { 20441, 20443 }, + { 20442, 445 }, + { 30131, 100323 }, + { -30131, -100323 }, + { 30231, 100313 }, + { -30231, -100313 } + }; + + int listSize = sizeof(SList)/sizeof(SList[0]); + for( int k=0; k!=listSize; ++k) { + m.insert( std::make_pair( SList[k].id, SList[k].pid) ); + } + return m; +} // IsajetPDTMapInit() + +PDTIsajetMap const & PDTIsajetMapInit() +{ + static PDTIsajetMap m; + static IsajetPDTMap const & hmap = getIsajetPDTMap(); + + for(IsajetPDTMap::const_iterator cit=hmap.begin(), mend=hmap.end(); cit!=mend; ++cit ) { + m.insert( std::make_pair( cit->second, cit->first )); + } + return m; +} + +// if a number isn't in the map, we try to convert it +int convIsajettoPDT( const int id ) +{ + // we have no idea what to do, these numbers must be in the map + if( abspid(id) <= 100 ) { return 0; } + if( abspid(id) > 99999 ) { return 0; } + + // find constituents + int istran; + unsigned short js = digit(nj,id); + unsigned short i1 = digit(nq3,id); + unsigned short i2 = digit(nq2,id); + unsigned short i3 = digit(nq1,id); + unsigned short i4 = digit(nl,id); + + // mesons + if(i1 != 0 && i2 != 0 && i3 == 0) { + // u and d have opposite definitions - sometimes + if(i2 <= 2 && i1 <= 2){ + // don't change + } else { + if(i1 == 2) { + i1 = 1; + } else if(i1 == 1) { + i1 = 2; + } + if(i2 == 2) { + i2 = 1; + } else if(i2 == 1) { + i2 = 2; + } + } + istran=i1*100 + i2*10 + 2*js+1 + i4*10000; + if( id < 0 ) { istran = -istran; } + // charmed and top mesons have wrong sign + if(i1 == 4 && i2 != 4) { istran = -istran; } + if(i1 == 6 && i2 != 6 && i2 != 4) { istran = -istran; } + // ...check for illegal antiparticles + if(i2 == i1 && id < 0) { istran=0; } + return istran; + } + // diquarks + if(i2 != 0 && i3 != 0 && i1 == 0) { + // ... u and d have opposite definitions + if(i3 == 2) { + i3 = 1; + } else if(i3 == 1) { + i3 = 2; + } + if(i2 == 2) { + i2 = 1; + } else if(i2 == 1) { + i2 = 2; + } + istran = 0; + if(i2 < i3){ + istran=i3*1000 + i2*100 + 1; + } else if(i2 == i3){ + istran=i2*1000 + i3*100 + 3; + } else { + istran=i2*1000 + i3*100 + 1; + } + if( id < 0 ) { istran = -istran; } + // ... charmed and top quarks have wrong sign + if(i2 == 4 && i3 != 4) { istran=-istran; } + if(i2 == 6 && i3 != 6 && i3 != 4) { istran=-istran; } + return istran; + } + // baryons + if( i1 != 0 && i3 != 0 && i2 != 0 ) { + // u and d have opposite definitions + if(i3 == 2) { + i3 = 1; + } else if(i3 == 1) { + i3 = 2; + } + if(i2 == 2) { + i2 = 1; + } else if(i2 == 1) { + i2 = 2; + } + if(i1 == 2) { + i1 = 1; + } else if(i1 == 1) { + i1 = 2; + } + istran = 0; + if(i1 <= 2){ + istran=i3*1000 + i2*100 + i1*10 + 2*js+2; + } else if(i3 <= 2 && i2 <= 2){ + istran=i1*1000 + i3*100 + i2*10 + 2*js+2; + } else { + istran=i1*1000 + i2*100 + i3*10 + 2*js+2; + } + if( id < 0 ) { istran = -istran; } + } + // unknown + return 0; + +} + +// if a number isn't in the map, we try to convert it +int convPDTtoIsajet( const int id ) +{ + // we have no idea what to do, these numbers must be in the map + if( fundamentalID(id) != 0 ) { return 0; } + if( abspid(id) > 99999 ) { return 0; } + + // find constituents + int istran; + unsigned short js = digit(nj,id); + unsigned short i1 = digit(nq3,id); + unsigned short i2 = digit(nq2,id); + unsigned short i3 = digit(nq1,id); + unsigned short i4 = digit(nl,id); + + // mesons + if(i1 != 0 && i2 != 0 && i3 == 0) { + // u and d have opposite definitions - sometimes + if(i2 <= 2 && i1 <= 2){ + // don't change + } else { + if(i1 == 2) { + i1 = 1; + } else if(i1 == 1) { + i1 = 2; + } + if(i2 == 2) { + i2 = 1; + } else if(i2 == 1) { + i2 = 2; + } + } + istran=i1*100 + i2*10 + (js-1)/2 + i4*10000; + if( id < 0 ) { istran = -istran; } + // ... charmed and top mesons have wrong sign + if(i2 == 4 && i1 != 4) { istran = -istran; } + if(i2 == 6 && i1 != 6 && i1 != 4) { istran = -istran; } + // ...check for illegal antiparticles + if(i2 == i1 && id < 0) { istran=0; } + return istran; + } + // diquarks + if(i1 == 0){ + // ... u and d have opposite definitions + if(i3 == 2) { + i3 = 1; + } else if(i3 == 1) { + i3 = 2; + } + if(i2 == 2) { + i2 = 1; + } else if(i2 == 1) { + i2 = 2; + } + istran = 0; + if(i3 < i2){ + istran=i3*1000 + i2*100 + (js-1)/2; + } else { + istran=i2*1000 + i3*100 + (js-1)/2; + } + if( id < 0 ) { istran = -istran; } + // ... charmed and top mesons have wrong sign + if(i2 == 4 && i3 != 4) { istran=-istran; } + if(i2 == 6 && i3 != 6 && i3 != 4) { istran=-istran; } + return istran; + } + // ...spin 1/2 or spin 3/2 baryons + if( i1 != 0 && i3 != 0 && i2 != 0 && ( js == 2 || js == 4) && i4 == 0 ) { + // u and d have opposite definitions + if(i3 == 2) { + i3 = 1; + } else if(i3 == 1) { + i3 = 2; + } + if(i2 == 2) { + i2 = 1; + } else if(i2 == 1) { + i2 = 2; + } + if(i1 == 2) { + i1 = 1; + } else if(i1 == 1) { + i1 = 2; + } + istran = 0; + if(i3 <= 2){ + istran=i3*1000 + i2*100 + i1*10 + (js-2)/2; + } else if(i1 <= 2 && i2 <= 2){ + istran=i2*1000 + i1*100 + i3*10 + (js-2)/2; + } else { + istran=i1*1000 + i2*100 + i3*10 + (js-2)/2; + } + if( id < 0 ) { istran = -istran; } + return istran; + } + // unknown + return 0; +} + +// +// getIsajetPDTMap is the ONLY function allowed to call IsajetPDTMapInit +// +IsajetPDTMap const & getIsajetPDTMap() +{ + static IsajetPDTMap const & hmap = IsajetPDTMapInit(); + return hmap; +} // getIsajetPDTMap() + +// +// getPDTIsajetMap is the ONLY function allowed to call IsajetPDTMapInit +// +PDTIsajetMap const & getPDTIsajetMap() +{ + static PDTIsajetMap const & hmap = PDTIsajetMapInit(); + return hmap; +} // getPDTIsajetMap() + +} // unnamed namespace + +int translateIsajettoPDT( const int id ) +{ + static IsajetPDTMap const & hmap = getIsajetPDTMap(); + + IsajetPDTMap::const_iterator const cit = hmap.find( id ); + // found it in the map + if ( cit != hmap.end() ) { return cit->second; } + // try converting anyway + return convIsajettoPDT(id); +} + +int translatePDTtoIsajet( const int id ) +{ + static PDTIsajetMap const & pmap = getPDTIsajetMap(); + + PDTIsajetMap::const_iterator const cit = pmap.find( id ); + // found it in the map + if ( cit != pmap.end() ) { return cit->second; } + // try converting anyway + return convPDTtoIsajet(id); +} + +void writeIsajetTranslationLine( int i, std::ostream & os ) +{ + // only write map entries + static IsajetPDTMap const & hmap = getIsajetPDTMap(); + + IsajetPDTMap::const_iterator const cit = hmap.find( i ); + // found it in the map + if ( cit != hmap.end() ) { + int id = cit->second; + os << " Isajet number: " ; + os.width(10); + os << i << " HepPID number: " ; + os.width(10); + os << id << " " << particleName(id) << std::endl; + // check reverse translation + int iback = translatePDTtoIsajet(id); + if(iback != i) { + os << " WARNING: " << id << " translates back to " + << iback << " not to " << i << std::endl; + } + } + return; +} // writeIsajetTranslationLine() + +void writeIsajetTranslation( std::ostream & os ) +{ + writeVersion( os ); + os << " HepPID Particle List" << std::endl; + os << std::endl; + + int id, j, q1, q2, q3, m; + // special cases + for( id=1; id<101; ++id) { + writeIsajetTranslationLine( id, os ); + writeIsajetTranslationLine( -id, os ); + } + // diquark + for( q2=1; q2<7; ++q2) { + for( q1=1; q1<7; ++q1) { + for( j=0; j<2; ++j) { + id = 1000*q2+100*q1+j; + writeIsajetTranslationLine( id, os ); + writeIsajetTranslationLine( -id, os ); + } + } + } + // mesons + for( q2=1; q2<9; ++q2) { + for( q1=1; q1<9; ++q1) { + for( j=0; j<3; ++j) { + for( m=0; m<4; ++m) { + id = 10000*m+100*q2+10*q1+j; + writeIsajetTranslationLine( id, os ); + writeIsajetTranslationLine( -id, os ); + } + } + } + } + // baryons + for( q3=1; q3<7; ++q3) { + for( q2=1; q2<7; ++q2) { + for( q1=1; q1<7; ++q1) { + for( j=1; j<2; ++j) { + id = 1000*q3+100*q2+10*q1+j; + writeIsajetTranslationLine( id, os ); + writeIsajetTranslationLine( -id, os ); + } + } + } + } + return; +} // writeIsajetTranslation() + +} // HepPID diff --git a/libs/HepPID/src/translatePDG.cc b/libs/HepPID/src/translatePDG.cc new file mode 100644 index 000000000..0cb92dda9 --- /dev/null +++ b/libs/HepPID/src/translatePDG.cc @@ -0,0 +1,503 @@ +// ------------------------------------ +// +// translatePDG.cc +// Author: Lynn Garren +// +// translate an ID number to or from the standard numbering scheme and the PDG table +// use static maps +// +// The maps are initialized if and only if the public functions are called. +// Because the maps are static, the initialization happens only once. +// +// The user NEVER calls PDGtoPDTMapInit() +// We use a data table (struct SList) so that compile time is not impacted. +// +// public functions: +// int translatePDGtabletoPDT( const int id ) +// int translatePDTtoPDGtable( const int id ) +// PDGtoPDTMap const & getPDGtoPDTMap() +// PDTtoPDGMap const & getPDTtoPDGMap() +// +// ------------------------------------ + +#include +#include // make_pair + +#include "HepPID/Version.hh" +#include "HepPID/ParticleIDTranslations.hh" +#include "HepPID/ParticleIDMethods.hh" +#include "HepPID/ParticleName.hh" + +namespace HepPID { + + typedef std::map< int, int > PDGtoPDTMap; + typedef std::map< int, int > PDTtoPDGMap; + +namespace { // PDGtoPDTMapInit is private + + PDGtoPDTMap const & getPDGtoPDTMap(); + PDTtoPDGMap const & getPDTtoPDGMap(); + +PDGtoPDTMap const & PDGtoPDTMapInit() +{ + + static PDGtoPDTMap m; + + static const struct { + int hid; // PDG + int pid; // PDT + } SList[] = { + { 1, 1 }, + { -1, -1 }, + { 2, 2 }, + { -2, -2 }, + { 3, 3 }, + { -3, -3 }, + { 4, 4 }, + { -4, -4 }, + { 5, 5 }, + { -5, -5 }, + { 6, 6 }, + { -6, -6 }, + { 7, 7 }, + { -7, -7 }, + { 8, 8 }, + { -8, -8 }, + { 11, 11 }, + { -11, -11 }, + { 12, 12 }, + { -12, -12 }, + { 13, 13 }, + { -13, -13 }, + { 14, 14 }, + { -14, -14 }, + { 15, 15 }, + { -15, -15 }, + { 16, 16 }, + { -16, -16 }, + { 17, 17 }, + { -17, -17 }, + { 18, 18 }, + { -18, -18 }, + { 21, 21 }, + { 22, 22 }, + { 23, 23 }, + { 24, 24 }, + { -24, -24 }, + { 25, 25 }, + { 32, 32 }, + { 33, 33 }, + { 34, 34 }, + { -34, -34 }, + { 35, 35 }, + { 36, 36 }, + { 37, 37 }, + { -37, -37 }, + { 39, 39 }, + { 41, 41 }, + { -41, -41 }, + { 42, 42 }, + { -42, -42 }, + { 110, 110 }, + { 990, 990 }, + { 9990, 9990 }, + { 130, 130 }, + { 310, 310 }, + { 211, 211}, + { 111, 111}, + { 221, 221}, + { 113, 113}, + { 213, 213}, + { 223, 223}, + { 331, 331}, + { 9010221, 9010221}, + { 9000111, 9000111}, + { 9000211, 9000211}, + { 333, 333}, + { 10223, 10223}, + { 10113, 10113}, + { 10213, 10213}, + { 20113, 20113}, + { 20213, 20213}, + { 225, 225}, + { 20223, 20223}, + { 100221, 100221}, + { 100111, 100111}, + { 100211, 100211}, + { 115, 115}, + { 215, 215}, + { 9000113, 9000113}, + { 9000213, 9000213}, + { 9020221, 9020221}, + { 20333, 20333}, + { 10111, 10111}, + { 10211, 10211}, + { 100113, 100113}, + { 100213, 100213}, + { 100331, 100331}, + { 9030221, 9030221}, + { 335, 335}, + { 9010113, 9010113}, + { 9010213, 9010213}, + { 10225, 10225}, + { 30223, 30223}, + { 227, 227}, + { 10115, 10115}, + { 10215, 10215}, + { 100333, 100333}, + { 117, 117}, + { 217, 217}, + { 30113, 30113}, + { 30213, 30213}, + { 10331, 10331}, + { 9010111, 9010111}, + { 9010211, 9010211}, + { 337, 337}, + { 9050225, 9050225}, + { 9060225, 9060225}, + { 119, 119}, + { 219, 219}, + { 229, 229}, + { 9080225, 9080225}, + { 9090225, 9090225}, + { 321, 321}, + { 311, 311}, + { 323, 323}, + { 313, 313}, + { 10313, 10313}, + { 10323, 10323}, + { 20313, 20313}, + { 20323, 20323}, + { 100313, 100313}, + { 100323, 100323}, + { 10311, 10311}, + { 10321, 10321}, + { 325, 325}, + { 315, 315}, + { 30313, 30313}, + { 30323, 30323}, + { 10315, 10315}, + { 10325, 10325}, + { 317, 317}, + { 327, 327}, + { 20315, 20315}, + { 20325, 20325}, + { 319, 319}, + { 329, 329}, + { 411, 411}, + { 421, 421}, + { 423, 423}, + { 413, 413}, + { 10423, 10423}, + { 425, 425}, + { 415, 415}, + { 431, 431}, + { 433, 433}, + { 10431, 10431}, + { 20433, 20433}, + { 10433, 10433}, + { 435, 435}, + { 521, 521}, + { 511, 511}, + { 513, 513}, + { 523, 523}, + { 531, 531}, + { 541, 541}, + { 441, 441}, + { 443, 443}, + { 10441, 10441}, + { 20443, 20443}, + { 445, 445}, + { 100443, 100443}, + { 30443, 30443}, + { 9000443, 9000443}, + { 9010443, 9010443}, + { 9020443, 9020443}, + { 553, 553}, + { 10551, 10551}, + { 20553, 20553}, + { 555, 555}, + { 100553, 100553}, + { 110551, 110551}, + { 120553, 120553}, + { 100555, 100555}, + { 200553, 200553}, + { 300553, 300553}, + { 9000553, 9000553}, + { 9010553, 9010553}, + { 2212, 2212}, + { 12212, 12212}, + { 22212, 22212}, + { 32212, 32212}, + { 42212, 42212}, + { 2112, 2112}, + { 12112, 12112}, + { 22112, 22112}, + { 32112, 32112}, + { 42112, 42112}, + { 1114, 1114}, + { 2114, 2114}, + { 2214, 2214}, + { 2224, 2224}, + { 31114, 31114}, + { 32114, 32114}, + { 32214, 32214}, + { 32224, 32224}, + { 1112, 1112}, + { 1212, 1212}, + { 2122, 2122}, + { 2222, 2222}, + { 11114, 11114}, + { 12114, 12114}, + { 12214, 12214}, + { 12224, 12224}, + { 1116, 1116}, + { 1216, 1216}, + { 2126, 2126}, + { 2226, 2226}, + { 21112, 21112}, + { 21212, 21212}, + { 22122, 22122}, + { 22222, 22222}, + { 21114, 21114}, + { 22114, 22114}, + { 22214, 22214}, + { 22224, 22224}, + { 11116, 11116}, + { 11216, 11216}, + { 12126, 12126}, + { 12226, 12226}, + { 1118, 1118}, + { 2118, 2118}, + { 2218, 2218}, + { 2228, 2228}, + { 1214, 1214}, + { 2124, 2124}, + { 21214, 21214}, + { 22124, 22124}, + { 31214, 31214}, + { 32124, 32124}, + { 2116, 2116}, + { 2216, 2216}, + { 12116, 12116}, + { 12216, 12216}, + { 1218, 1218}, + { 2128, 2128}, + { 3122, 3122}, + { 13122, 13122 }, + { 23122, 23122 }, + { 33122, 33122 }, + { 43122, 43122 }, + { 53122, 53122 }, + { 3124, 3124 }, + { 13124, 13124 }, + { 23124, 23124 }, + { 3126, 3126 }, + { 13126, 13126 }, + { 3128, 3128 }, + { 23126, 23126 }, + { 3222, 3222}, + { 3212, 3212}, + { 3112, 3112}, + { 13112, 13112 }, + { 13212, 13212 }, + { 13222, 13222 }, + { 23112, 23112 }, + { 23212, 23212 }, + { 23222, 23222 }, + { 3224, 3224}, + { 3214, 3214}, + { 3114, 3114}, + { 13224, 13224 }, + { 13214, 13214 }, + { 13114, 13114 }, + { 23224, 23224 }, + { 23214, 23214 }, + { 23114, 23114 }, + { 3226, 3226 }, + { 3216, 3216 }, + { 3116, 3116 }, + { 13226, 13226 }, + { 13216, 13216 }, + { 13116, 13116 }, + { 3228, 3228 }, + { 3218, 3218 }, + { 3118, 3118 }, + { 3322, 3322}, + { 3312, 3312}, + { 3324, 3324}, + { 13314, 13314}, + { 13324, 13324}, + { 3314, 3314}, + { 3334, 3334}, + { 4122, 4122}, + { 14122, 14122}, + { 4222, 4222}, + { 4212, 4212}, + { 4112, 4112}, + { 4232, 4232}, + { 4132, 4132}, + { 4322, 4322}, + { 4312, 4312}, + { 4332, 4332}, + { 5122, 5122}, + { 9221132, 9221132}, + { 9331122, 9331122} + }; + + int listSize = sizeof(SList)/sizeof(SList[0]); + for( int k=0; k!=listSize; ++k) { + m.insert( std::make_pair( SList[k].hid, SList[k].pid) ); + } + return m; +} // PDGtoPDTMapInit() + +PDTtoPDGMap const & PDTtoPDGMapInit() +{ + static PDTtoPDGMap m; + static PDGtoPDTMap const & hmap = getPDGtoPDTMap(); + + for(PDGtoPDTMap::const_iterator cit=hmap.begin(), mend=hmap.end(); cit!=mend; ++cit ) { + m.insert( std::make_pair( cit->second, cit->first )); + } + return m; +} + +// +// getPDGtoPDTMap is the ONLY function allowed to call PDGtoPDTMapInit +// +PDGtoPDTMap const & getPDGtoPDTMap() +{ + static PDGtoPDTMap const & hmap = PDGtoPDTMapInit(); + return hmap; +} // getPDGtoPDTMap() + +// +// getPDTtoPDGMap is the ONLY function allowed to call PDGtoPDTMapInit +// +PDTtoPDGMap const & getPDTtoPDGMap() +{ + static PDTtoPDGMap const & hmap = PDTtoPDGMapInit(); + return hmap; +} // getPDTtoPDGMap() + +} // unnamed namespace + +int translatePDGtabletoPDT( const int id ) +{ + static PDGtoPDTMap const & hmap = getPDGtoPDTMap(); + + PDGtoPDTMap::const_iterator const cit = hmap.find( id ); + // found it in the map + if ( cit != hmap.end() ) { return cit->second; } + // check to see if someone has defined a valid particle type + // that isn't in the map + if( isValid(id) ) { return id; } + return 0; +} + +int translatePDTtoPDGtable( const int id ) +{ + static PDTtoPDGMap const & pmap = getPDTtoPDGMap(); + + PDTtoPDGMap::const_iterator const cit = pmap.find( id ); + // found it in the map + if ( cit != pmap.end() ) { return cit->second; } + // check to see if someone has defined a valid particle type + // that isn't in the map + if( isValid(id) ) { return id; } + return 0; +} + +void writePDGTranslationLine( int i, std::ostream & os ) +{ + // only write map entries + static PDGtoPDTMap const & hmap = getPDGtoPDTMap(); + + PDGtoPDTMap::const_iterator const cit = hmap.find( i ); + // found it in the map + if ( cit != hmap.end() ) { + int id = cit->second; + os << " PDG number: " ; + os.width(10); + os << i << " HepPID number: " ; + os.width(11); + os << id << " " << particleName(id) << std::endl; + // check reverse translation + int iback = translatePDTtoPDGtable(id); + if(iback != i) { + os << " WARNING: " << id << " translates back to " + << iback << " not to " << i << std::endl; + } + } + return; +} // writePDGTranslationLine() + +void writePDGTranslation( std::ostream & os ) +{ + writeVersion( os ); + os << " HepPID Particle List" << std::endl; + os << std::endl; + + int id, i, j, q1, q2, q3, l, m; + // special cases + for( id=1; id<102; ++id) { + writePDGTranslationLine( id, os ); + writePDGTranslationLine( -id, os ); + } + for( i=11; i<1000; ++i) { + id = i*10; + writePDGTranslationLine( id, os ); + writePDGTranslationLine( -id, os ); + } + // diquark + for( q2=1; q2<7; ++q2) { + for( q1=1; q1<7; ++q1) { + for( j=1; j<4; ++j) { + id = 1000*q2+100*q1+j; + writePDGTranslationLine( id, os ); + writePDGTranslationLine( -id, os ); + } + } + } + // mesons + for( q2=1; q2<10; ++q2) { + for( q1=1; q1<10; ++q1) { + for( j=1; j<10; ++j) { + for( m=0; m<9; ++m) { + for( l=0; l<10; ++l) { + id = 100000*m+10000*l+100*q2+10*q1+j; + writePDGTranslationLine( id, os ); + writePDGTranslationLine( -id, os ); + } + } + } + } + } + // baryons + for( q3=1; q3<10; ++q3) { + for( q2=1; q2<10; ++q2) { + for( q1=1; q1<10; ++q1) { + for( j=1; j<10; ++j) { + for( m=0; m<9; ++m) { + id = 10000*m+1000*q3+100*q2+10*q1+j; + writePDGTranslationLine( id, os ); + writePDGTranslationLine( -id, os ); + } + } + } + } + } + // ions + for( i=1; i<3; ++i) { + for( m=1; m<3; ++m) { + id = 1000+10*i+m; + writePDGTranslationLine( id, os ); + writePDGTranslationLine( -id, os ); + } + } + + return; +} // writePDGTranslation() + +} // HepPID diff --git a/libs/HepPID/src/translatePDTtoGeant.cc b/libs/HepPID/src/translatePDTtoGeant.cc new file mode 100644 index 000000000..bb2ceea50 --- /dev/null +++ b/libs/HepPID/src/translatePDTtoGeant.cc @@ -0,0 +1,100 @@ +// ---------------------------------------------------------------------- +// +// translatePDTtoGeant.cc +// Author: Lynn Garren +// +// Translate from the standard numbering scheme to GEANT. +// Particles unknown to GEANT are entered as geantino's. +// A warning message is also printed. +// +// ---------------------------------------------------------------------- + +#include + +#include "HepPID/Version.hh" +#include "HepPID/ParticleIDTranslations.hh" +#include "HepPID/ParticleIDMethods.hh" + +#define IDMAX 49 + +namespace HepPID { + +int translatePDTtoGeant( const int id ) +{ + static int IDG2H[IDMAX] = { + 22, // gamma + -11, // e + 11, // e- + 12, // nu (nu_e) + -13, // mu + 13, // mu- + 111, // pi0 + 211, // pi + -211, // pi- + 130, // K0L + 321, // K + -321, // K- + 2112, // n + 2212, // p + -2212, // p~ + 310, // K0s + 221, // eta + 3122, // Lambda + 3222, // Sigma + 3212, // Sigma0 + 3112, // Sigma- + 3322, // Xi0 + 3312, // Xi- + 3334, // Omega- + -2112, // n~ + -3122, // Lambda~ + -3112, // Sigma~ + -3212, // Sigma0~ + -3222, // sigma-~ + -3322, // Xi0~ + -3312, // Xi-~ + -3334, // Omega-~ + -15, // tau + 15, // tau- + 411, // D + -411, // D- + 421, // D0 + -421, // D0~ + 431, // Ds + -431, // Ds- + 4122, // Lambda_ + 24, // W + -24, // W- + 23, // Z + 1000010020, // deuteron + 1000010030, // tritium + 1000020040, // alpha + 0, // geantino + 1000020030 }; // He3 + static int nwhine_max = 10; + int nwhine = 0; + int gtran, i; + +//...........first check if its an e, mu or tau neutrino + if( abspid(id) == 12 || abspid(id) == 14 || abspid(id) == 16 ) { + gtran = 4; + } else { +//..............loop over all GEANT particles, see if it matches +//..............the current HEP particle + gtran = IDMAX + 1; + for( i=0; i < IDMAX; ++i ) { + if( IDG2H[i] == id ) { gtran = i; } + } + } + if( gtran > IDMAX || gtran == 48 ) { + gtran = 48; // geantino + nwhine = nwhine + 1; + if( nwhine <= nwhine_max ) { + std::cout << "translatePDTtoGeant: HEP particle " << id + << " not known to GEANT (converted to geantino)" << std::endl; + } + } + return gtran; +} + +} // HepPID diff --git a/libs/HepPID/src/translatePythia.cc b/libs/HepPID/src/translatePythia.cc new file mode 100644 index 000000000..bc2a826a8 --- /dev/null +++ b/libs/HepPID/src/translatePythia.cc @@ -0,0 +1,827 @@ +// ------------------------------------ +// +// translatePythia.cc +// Author: Lynn Garren +// +// translate an ID number to or from the standard numbering scheme and Pythia +// use static maps +// +// The maps are initialized if and only if the public functions are called. +// Because the maps are static, the initialization happens only once. +// +// The user NEVER calls PythiaPDTMapInit() +// We use a data table (struct SList) so that compile time is not impacted. +// +// public functions: +// int translatePythiatoPDT( const int id ) +// int translatePDTtoPythia( const int id ) +// PythiaPDTMap const & getPythiaPDTMap() +// PDTPythiaMap const & getPDTPythiaMap() +// +// ------------------------------------ + +#include +#include // make_pair + +#include "HepPID/Version.hh" +#include "HepPID/ParticleIDTranslations.hh" +#include "HepPID/ParticleIDMethods.hh" +#include "HepPID/ParticleName.hh" + +namespace HepPID { + + typedef std::map< int, int > PythiaPDTMap; + typedef std::map< int, int > PDTPythiaMap; + +namespace { // PythiaPDTMapInit is private + + PythiaPDTMap const & getPythiaPDTMap(); + PDTPythiaMap const & getPDTPythiaMap(); + +PythiaPDTMap const & PythiaPDTMapInit() +{ + + static PythiaPDTMap m; + + static const struct { + int hid; // Pythia + int pid; // PDT + } SList[] = { + { 1, 1 }, + { -1, -1 }, + { 2, 2 }, + { -2, -2 }, + { 3, 3 }, + { -3, -3 }, + { 4, 4 }, + { -4, -4 }, + { 5, 5 }, + { -5, -5 }, + { 6, 6 }, + { -6, -6 }, + { 7, 7 }, + { -7, -7 }, + { 8, 8 }, + { -8, -8 }, + { 11, 11 }, + { -11, -11 }, + { 12, 12 }, + { -12, -12 }, + { 13, 13 }, + { -13, -13 }, + { 14, 14 }, + { -14, -14 }, + { 15, 15 }, + { -15, -15 }, + { 16, 16 }, + { -16, -16 }, + { 17, 17 }, + { -17, -17 }, + { 18, 18 }, + { -18, -18 }, + { 21, 21 }, + { 22, 22 }, + { 23, 23 }, + { 24, 24 }, + { -24, -24 }, + { 25, 25 }, + { 32, 32 }, + { 33, 33 }, + { 34, 34 }, + { -34, -34 }, + { 35, 35 }, + { 36, 36 }, + { 37, 37 }, + { -37, -37 }, + { 39, 39 }, + { 41, 41 }, + { -41, -41 }, + { 42, 42 }, + { -42, -42 }, + { 81, 81 }, + { 82, 82 }, + { -82, -82 }, + { 83, 83 }, + { 84, 84 }, + { -84, -84 }, + { 85, 85 }, + { -85, -85 }, + { 88, 88 }, + { 90, 90 }, + { 91, 91 }, + { 92, 92 }, + { 93, 93 }, + { 94, 94 }, + { 95, 95 }, + { 96, 96 }, + { 97, 97 }, + { 98, 98 }, + { 99, 99 }, + { 110, 110 }, + { 990, 990 }, + { 111, 111 }, + { 113, 113 }, + { 115, 115 }, + { 130, 130 }, + { 211, 211 }, + { -211, -211 }, + { 213, 213 }, + { -213, -213 }, + { 215, 215 }, + { -215, -215 }, + { 221, 221 }, + { 223, 223 }, + { 225, 225 }, + { 310, 310 }, + { 311, 311 }, + { -311, -311 }, + { 313, 313 }, + { -313, -313 }, + { 315, 315 }, + { -315, -315 }, + { 321, 321 }, + { -321, -321 }, + { 323, 323 }, + { -323, -323 }, + { 325, 325 }, + { -325, -325 }, + { 331, 331 }, + { 333, 333 }, + { 335, 335 }, + { 411, 411 }, + { -411, -411 }, + { 413, 413 }, + { -413, -413 }, + { 415, 415 }, + { -415, -415 }, + { 421, 421 }, + { -421, -421 }, + { 423, 423 }, + { -423, -423 }, + { 425, 425 }, + { -425, -425 }, + { 431, 431 }, + { -431, -431 }, + { 433, 433 }, + { -433, -433 }, + { 435, 435 }, + { -435, -435 }, + { 441, 441 }, + { 443, 443 }, + { 445, 445 }, + { 511, 511 }, + { -511, -511 }, + { 513, 513 }, + { -513, -513 }, + { 515, 515 }, + { -515, -515 }, + { 521, 521 }, + { -521, -521 }, + { 523, 523 }, + { -523, -523 }, + { 525, 525 }, + { -525, -525 }, + { 531, 531 }, + { -531, -531 }, + { 533, 533 }, + { -533, -533 }, + { 535, 535 }, + { -535, -535 }, + { 541, 541 }, + { -541, -541 }, + { 543, 543 }, + { -543, -543 }, + { 545, 545 }, + { -545, -545 }, + { 551, 551 }, + { 553, 553 }, + { 555, 555 }, + { 1103, 1103 }, + { -1103, -1103 }, + { 1114, 1114 }, + { -1114, -1114 }, + { 2101, 2101 }, + { -2101, -2101 }, + { 2103, 2103 }, + { -2103, -2103 }, + { 2112, 2112 }, + { -2112, -2112 }, + { 2114, 2114 }, + { -2114, -2114 }, + { 2203, 2203 }, + { -2203, -2203 }, + { 2212, 2212 }, + { -2212, -2212 }, + { 2214, 2214 }, + { -2214, -2214 }, + { 2224, 2224 }, + { -2224, -2224 }, + { 3101, 3101 }, + { -3101, -3101 }, + { 3103, 3103 }, + { -3103, -3103 }, + { 3112, 3112 }, + { -3112, -3112 }, + { 3114, 3114 }, + { -3114, -3114 }, + { 3122, 3122 }, + { -3122, -3122 }, + { 3201, 3201 }, + { -3201, -3201 }, + { 3203, 3203 }, + { -3203, -3203 }, + { 3212, 3212 }, + { -3212, -3212 }, + { 3214, 3214 }, + { -3214, -3214 }, + { 3222, 3222 }, + { -3222, -3222 }, + { 3224, 3224 }, + { -3224, -3224 }, + { 3303, 3303 }, + { -3303, -3303 }, + { 3312, 3312 }, + { -3312, -3312 }, + { 3314, 3314 }, + { -3314, -3314 }, + { 3322, 3322 }, + { -3322, -3322 }, + { 3324, 3324 }, + { -3324, -3324 }, + { 3334, 3334 }, + { -3334, -3334 }, + { 4101, 4101 }, + { -4101, -4101 }, + { 4103, 4103 }, + { -4103, -4103 }, + { 4112, 4112 }, + { -4112, -4112 }, + { 4114, 4114 }, + { -4114, -4114 }, + { 4122, 4122 }, + { -4122, -4122 }, + { 4132, 4132 }, + { -4132, -4132 }, + { 4201, 4201 }, + { -4201, -4201 }, + { 4203, 4203 }, + { -4203, -4203 }, + { 4212, 4212 }, + { -4212, -4212 }, + { 4214, 4214 }, + { -4214, -4214 }, + { 4222, 4222 }, + { -4222, -4222 }, + { 4224, 4224 }, + { -4224, -4224 }, + { 4232, 4232 }, + { -4232, -4232 }, + { 4301, 4301 }, + { -4301, -4301 }, + { 4303, 4303 }, + { -4303, -4303 }, + { 4312, 4312 }, + { -4312, -4312 }, + { 4314, 4314 }, + { -4314, -4314 }, + { 4322, 4322 }, + { -4322, -4322 }, + { 4324, 4324 }, + { -4324, -4324 }, + { 4332, 4332 }, + { -4332, -4332 }, + { 4334, 4334 }, + { -4334, -4334 }, + { 4403, 4403 }, + { -4403, -4403 }, + { 4412, 4412 }, + { -4412, -4412 }, + { 4414, 4414 }, + { -4414, -4414 }, + { 4422, 4422 }, + { -4422, -4422 }, + { 4424, 4424 }, + { -4424, -4424 }, + { 4432, 4432 }, + { -4432, -4432 }, + { 4434, 4434 }, + { -4434, -4434 }, + { 4444, 4444 }, + { -4444, -4444 }, + { 5101, 5101 }, + { -5101, -5101 }, + { 5103, 5103 }, + { -5103, -5103 }, + { 5112, 5112 }, + { -5112, -5112 }, + { 5114, 5114 }, + { -5114, -5114 }, + { 5122, 5122 }, + { -5122, -5122 }, + { 5132, 5132 }, + { -5132, -5132 }, + { 5142, 5142 }, + { -5142, -5142 }, + { 5201, 5201 }, + { -5201, -5201 }, + { 5203, 5203 }, + { -5203, -5203 }, + { 5212, 5212 }, + { -5212, -5212 }, + { 5214, 5214 }, + { -5214, -5214 }, + { 5222, 5222 }, + { -5222, -5222 }, + { 5224, 5224 }, + { -5224, -5224 }, + { 5232, 5232 }, + { -5232, -5232 }, + { 5242, 5242 }, + { -5242, -5242 }, + { 5301, 5301 }, + { -5301, -5301 }, + { 5303, 5303 }, + { -5303, -5303 }, + { 5312, 5312 }, + { -5312, -5312 }, + { 5314, 5314 }, + { -5314, -5314 }, + { 5322, 5322 }, + { -5322, -5322 }, + { 5324, 5324 }, + { -5324, -5324 }, + { 5332, 5332 }, + { -5332, -5332 }, + { 5334, 5334 }, + { -5334, -5334 }, + { 5342, 5342 }, + { -5342, -5342 }, + { 5401, 5401 }, + { -5401, -5401 }, + { 5403, 5403 }, + { -5403, -5403 }, + { 5412, 5412 }, + { -5412, -5412 }, + { 5414, 5414 }, + { -5414, -5414 }, + { 5422, 5422 }, + { -5422, -5422 }, + { 5424, 5424 }, + { -5424, -5424 }, + { 5432, 5432 }, + { -5432, -5432 }, + { 5434, 5434 }, + { -5434, -5434 }, + { 5442, 5442 }, + { -5442, -5442 }, + { 5444, 5444 }, + { -5444, -5444 }, + { 5503, 5503 }, + { -5503, -5503 }, + { 5512, 5512 }, + { -5512, -5512 }, + { 5514, 5514 }, + { -5514, -5514 }, + { 5522, 5522 }, + { -5522, -5522 }, + { 5524, 5524 }, + { -5524, -5524 }, + { 5532, 5532 }, + { -5532, -5532 }, + { 5534, 5534 }, + { -5534, -5534 }, + { 5542, 5542 }, + { -5542, -5542 }, + { 5544, 5544 }, + { -5544, -5544 }, + { 5554, 5554 }, + { -5554, -5554 }, + { 10111, 9000111 }, + { 10113, 10113 }, + { 10211, 9000211 }, + { -10211, -9000211 }, + { 10213, 10213 }, + { -10213, -10213 }, + { 10221, 9010221 }, + { 10223, 10223 }, + { 10311, 10311 }, + { -10311, -10311 }, + { 10313, 10313 }, + { -10313, -10313 }, + { 10321, 10321 }, + { -10321, -10321 }, + { 10323, 10323 }, + { -10323, -10323 }, + { 10331, 10221 }, + { 10333, 10333 }, + { 10411, 10411 }, + { -10411, -10411 }, + { 10413, 10413 }, + { -10413, -10413 }, + { 10421, 10421 }, + { -10421, -10421 }, + { 10423, 10423 }, + { -10423, -10423 }, + { 10431, 10431 }, + { -10431, -10431 }, + { 10433, 10433 }, + { -10433, -10433 }, + { 10441, 10441 }, + { 10443, 10443 }, + { 10511, 10511 }, + { -10511, -10511 }, + { 10513, 10513 }, + { -10513, -10513 }, + { 10521, 10521 }, + { -10521, -10521 }, + { 10523, 10523 }, + { -10523, -10523 }, + { 10531, 10531 }, + { -10531, -10531 }, + { 10533, 10533 }, + { -10533, -10533 }, + { 10541, 10541 }, + { -10541, -10541 }, + { 10543, 10543 }, + { -10543, -10543 }, + { 10551, 10551 }, + { 10553, 10553 }, + { 20113, 20113 }, + { 20213, 20213 }, + { -20213, -20213 }, + { 20223, 20223 }, + { 20313, 20313 }, + { -20313, -20313 }, + { 20323, 20323 }, + { -20323, -20323 }, + { 20333, 20333 }, + { 20413, 20413 }, + { -20413, -20413 }, + { 20423, 20423 }, + { -20423, -20423 }, + { 20433, 20433 }, + { -20433, -20433 }, + { 20443, 20443 }, + { 20513, 20513 }, + { -20513, -20513 }, + { 20523, 20523 }, + { -20523, -20523 }, + { 20533, 20533 }, + { -20533, -20533 }, + { 20543, 20543 }, + { -20543, -20543 }, + { 20553, 20553 }, + { 100443, 100443 }, + { 100553, 100553 }, + { 1000001, 1000001 }, + { -1000001, -1000001 }, + { 1000002, 1000002 }, + { -1000002, -1000002 }, + { 1000003, 1000003 }, + { -1000003, -1000003 }, + { 1000004, 1000004 }, + { -1000004, -1000004 }, + { 1000005, 1000005 }, + { -1000005, -1000005 }, + { 1000006, 1000006 }, + { -1000006, -1000006 }, + { 1000011, 1000011 }, + { -1000011, -1000011 }, + { 1000012, 1000012 }, + { -1000012, -1000012 }, + { 1000013, 1000013 }, + { -1000013, -1000013 }, + { 1000014, 1000014 }, + { -1000014, -1000014 }, + { 1000015, 1000015 }, + { -1000015, -1000015 }, + { 1000016, 1000016 }, + { -1000016, -1000016 }, + { 1000021, 1000021 }, + { 1000022, 1000022 }, + { 1000023, 1000023 }, + { 1000024, 1000024 }, + { -1000024, -1000024 }, + { 1000025, 1000025 }, + { 1000035, 1000035 }, + { 1000037, 1000037 }, + { -1000037, -1000037 }, + { 1000039, 1000039 }, + { 2000001, 2000001 }, + { -2000001, -2000001 }, + { 2000002, 2000002 }, + { -2000002, -2000002 }, + { 2000003, 2000003 }, + { -2000003, -2000003 }, + { 2000004, 2000004 }, + { -2000004, -2000004 }, + { 2000005, 2000005 }, + { -2000005, -2000005 }, + { 2000006, 2000006 }, + { -2000006, -2000006 }, + { 2000011, 2000011 }, + { -2000011, -2000011 }, + { 2000012, 2000012 }, + { -2000012, -2000012 }, + { 2000013, 2000013 }, + { -2000013, -2000013 }, + { 2000014, 2000014 }, + { -2000014, -2000014 }, + { 2000015, 2000015 }, + { -2000015, -2000015 }, + { 2000016, 2000016 }, + { -2000016, -2000016 }, + { 3000111, 3000111 }, + { 3000211, 3000211 }, + { -3000211, -3000211 }, + { 3000115, 3000115 }, + { 3000215, 3000215 }, + { -3000215, -3000215 }, + { 3000221, 3000221 }, + { 3000331, 3100221 }, + { 3000113, 3000113 }, + { 3000213, 3000213 }, + { -3000213, -3000213 }, + { 3000223, 3000223 }, + { 3100021, 3100021 }, + { 3100111, 3060111 }, + { 3200111, 3160111 }, + { 3100113, 3130113 }, + { 3200113, 3140113 }, + { 3300113, 3150113 }, + { 3400113, 3160113 }, + { 4000001, 4000001 }, + { -4000001, -4000001 }, + { 4000002, 4000002 }, + { -4000002, -4000002 }, + { 4000011, 4000011 }, + { -4000011, -4000011 }, + { 4000012, 4000012 }, + { -4000012, -4000012 }, + { 5000039, 4000039 }, + { 5100001, 5100001 }, + { 5100002, 5100002 }, + { 5100003, 5100003 }, + { 5100004, 5100004 }, + { 5100005, 5100005 }, + { 5100006, 5100006 }, + { 5100011, 5100011 }, + { 5100012, 5100012 }, + { 5100013, 5100013 }, + { 5100014, 5100014 }, + { 5100015, 5100015 }, + { 5100016, 5100016 }, + { 5100021, 5100021 }, + { 5100022, 5100022 }, + { 5100023, 5100023 }, + { 5100024, 5100024 }, + { 6100001, 6100001 }, + { 6100002, 6100002 }, + { 6100003, 6100003 }, + { 6100004, 6100004 }, + { 6100005, 6100005 }, + { 6100006, 6100006 }, + { 6100011, 6100011 }, + { 6100012, 6100012 }, + { 6100013, 6100013 }, + { 6100014, 6100014 }, + { 6100015, 6100015 }, + { 6100016, 6100016 }, + { 9900012, 9900012 }, + { 9900014, 9900014 }, + { 9900016, 9900016 }, + { 9900023, 9900023 }, + { 9900024, 9900024 }, + { -9900024, -9900024 }, + { 9900041, 9900041 }, + { -9900041, -9900041 }, + { 9900042, 9900042 }, + { -9900042, -9900042 }, + { 9900110, 9910113 }, + { 9900210, 9910211 }, + { -9900210, -9910211 }, + { 9900220, 9910223 }, + { 9900330, 9910333 }, + { 9900440, 9910443 }, + { 9902110, 9912112 }, + { -9902110, -9912112 }, + { 9902210, 9912212 }, + { -9902210, -9912212 }, + { 9900441, 9900441 }, + { 9910441, 9910441 }, + { 9900443, 9900443 }, + { 9900551, 9900551 }, + { 9910551, 9910551 }, + { 9900553, 9900553 }, + { 1000010020, 1000010020 }, + { -1000010020, -1000010020 }, + { 1000010030, 1000010030 }, + { -1000010030, -1000010030 }, + { 1000020030, 1000020030 }, + { -1000020030, -1000020030 }, + { 1000020040, 1000020040 }, + { -1000020040, -1000020040 } + }; + + int listSize = sizeof(SList)/sizeof(SList[0]); + for( int k=0; k!=listSize; ++k) { + m.insert( std::make_pair( SList[k].hid, SList[k].pid) ); + } + return m; +} // PythiaPDTMapInit() + +PDTPythiaMap const & PDTPythiaMapInit() +{ + static PDTPythiaMap m; + static PythiaPDTMap const & hmap = getPythiaPDTMap(); + + for(PythiaPDTMap::const_iterator cit=hmap.begin(), mend=hmap.end(); cit!=mend; ++cit ) { + m.insert( std::make_pair( cit->second, cit->first )); + } + return m; +} + +// +// getPythiaPDTMap is the ONLY function allowed to call PythiaPDTMapInit +// +PythiaPDTMap const & getPythiaPDTMap() +{ + static PythiaPDTMap const & hmap = PythiaPDTMapInit(); + return hmap; +} // getPythiaPDTMap() + +// +// getPDTPythiaMap is the ONLY function allowed to call PythiaPDTMapInit +// +PDTPythiaMap const & getPDTPythiaMap() +{ + static PDTPythiaMap const & hmap = PDTPythiaMapInit(); + return hmap; +} // getPDTPythiaMap() + +} // unnamed namespace + +int translatePythiatoPDT( const int id ) +{ + static PythiaPDTMap const & hmap = getPythiaPDTMap(); + + PythiaPDTMap::const_iterator const cit = hmap.find( id ); + // found it in the map + if ( cit != hmap.end() ) { return cit->second; } + // check to see if someone has defined a valid particle type + // that isn't in the map + if( isValid(id) ) { return id; } + return 0; +} + +int translatePDTtoPythia( const int id ) +{ + static PDTPythiaMap const & pmap = getPDTPythiaMap(); + + PDTPythiaMap::const_iterator const cit = pmap.find( id ); + // found it in the map + if ( cit != pmap.end() ) { return cit->second; } + // check to see if someone has defined a valid particle type + // that isn't in the map + if( isValid(id) ) { return id; } + return 0; +} + +void writePythiaTranslationLine( int i, std::ostream & os ) +{ + // only write map entries + static PythiaPDTMap const & hmap = getPythiaPDTMap(); + + PythiaPDTMap::const_iterator const cit = hmap.find( i ); + // found it in the map + if ( cit != hmap.end() ) { + int id = cit->second; + os << " Pythia number: " ; + os.width(10); + os << i << " HepPID number: " ; + os.width(10); + os << id << " " << particleName(id) << std::endl; + // check reverse translation + int iback = translatePDTtoPythia(id); + if(iback != i) { + os << " WARNING: " << id << " translates back to " + << iback << " not to " << i << std::endl; + } + } + return; +} // writePythiaTranslationLine() + +void writePythiaTranslation( std::ostream & os ) +{ + writeVersion( os ); + os << " HepPID Particle List" << std::endl; + os << std::endl; + + int id, i, j, q1, q2, q3, l, m, n; + // special cases + for( id=1; id<101; ++id) { + writePythiaTranslationLine( id, os ); + writePythiaTranslationLine( -id, os ); + } + for( i=11; i<1000; ++i) { + id = i*10; + writePythiaTranslationLine( id, os ); + writePythiaTranslationLine( -id, os ); + } + // SUSY + for( n=1; n<3; ++n) { + for( i=1; i<40; ++i) { + id = 1000000*n+i; + writePythiaTranslationLine( id, os ); + writePythiaTranslationLine( -id, os ); + } + } + // technicolor + for( q2=1; q2<4; ++q2) { + for( q1=1; q1<4; ++q1) { + for( j=1; j<6; ++j) { + for( m=0; m<5; ++m) { + id = 3000000+100000*m+100*q2+10*q1+j; + writePythiaTranslationLine( id, os ); + writePythiaTranslationLine( -id, os ); + } + } + } + } + // excited particles + for( n=4; n<6; ++n) { + for( i=1; i<40; ++i) { + id = 1000000*n+i; + writePythiaTranslationLine( id, os ); + writePythiaTranslationLine( -id, os ); + } + } + // miscellaneous generator particles + for( l=0; l<9; ++l) { + for( q3=0; q3<10; ++q3) { + for( q2=0; q2<10; ++q2) { + for( q1=0; q1<10; ++q1) { + for( j=0; j<10; ++j) { + id = 9900000+10000*l+1000*q3+100*q2+10*q1+j; + writePythiaTranslationLine( id, os ); + writePythiaTranslationLine( -id, os ); + } + } + } + } + } + // diquark + for( i=11; i<100; ++i) { + for( j=0; j<10; ++j) { + id = 100*i+j; + writePythiaTranslationLine( id, os ); + writePythiaTranslationLine( -id, os ); + } + } + // mesons + for( q2=1; q2<10; ++q2) { + for( q1=1; q1<10; ++q1) { + for( j=1; j<10; ++j) { + for( m=0; m<9; ++m) { + for( l=0; l<10; ++l) { + id = 100000*m+10000*l+100*q2+10*q1+j; + writePythiaTranslationLine( id, os ); + writePythiaTranslationLine( -id, os ); + id = 9000000+100000*m+10000*l+100*q2+10*q1+j; + writePythiaTranslationLine( id, os ); + writePythiaTranslationLine( -id, os ); + } + } + } + } + } + // baryons + for( q3=1; q3<10; ++q3) { + for( q2=1; q2<10; ++q2) { + for( q1=1; q1<10; ++q1) { + for( j=1; j<10; ++j) { + id = 1000*q3+100*q2+10*q1+j; + writePythiaTranslationLine( id, os ); + writePythiaTranslationLine( -id, os ); + } + } + } + } + // pentaquarks + for( l=1; l<9; ++l ) { + for ( m=1; m<9; ++m ) { + for( q3=1; q3<9; ++q3) { + for( q2=1; q2<9; ++q2) { + for( q1=1; q1<9; ++q1) { + id = 9*1000000+l*100000+m*10000+1000*q3+100*q2+10*q1+2; + writePythiaTranslationLine( id, os ); + writePythiaTranslationLine( -id, os ); + } + } + } + } + } + return; +} // writePythiaTranslation() + +} // HepPID diff --git a/libs/HepPID/src/translateQQ.cc b/libs/HepPID/src/translateQQ.cc new file mode 100644 index 000000000..8fd126ae4 --- /dev/null +++ b/libs/HepPID/src/translateQQ.cc @@ -0,0 +1,656 @@ +// ------------------------------------ +// +// translateQQ.cc +// Author: Lynn Garren +// +// translate an ID number to or from the standard numbering scheme and QQ +// use static maps +// +// The maps are initialized if and only if the public functions are called. +// Because the maps are static, the initialization happens only once. +// +// The user NEVER calls QQPDTMapInit() +// We use a data table (struct SList) so that compile time is not impacted. +// +// public functions: +// int translateQQtoPDT( const int id ) +// int translatePDTtoQQ( const int id ) +// QQPDTMap const & getQQPDTMap() +// PDTQQMap const & getPDTQQMap() +// int translateQQbar( const int id ) +// int translateInverseQQbar( const int id ) +// QQbarMap const & getQQbarMap() +// InverseQQbarMap const & getInverseQQbarMap() +// +// ------------------------------------ + +#include +#include // make_pair + +#include "HepPID/Version.hh" +#include "HepPID/ParticleIDTranslations.hh" +#include "HepPID/ParticleIDMethods.hh" +#include "HepPID/ParticleName.hh" + +namespace HepPID { + + typedef std::map< int, int > QQPDTMap; + typedef std::map< int, int > PDTQQMap; + typedef std::map< int, int > QQbarMap; + typedef std::map< int, int > InverseQQbarMap; + +namespace { // QQPDTMapInit is private + + QQPDTMap const & getQQPDTMap(); + PDTQQMap const & getPDTQQMap(); + QQbarMap const & getQQbarMap(); + InverseQQbarMap const & getInverseQQbarMap(); + +QQPDTMap const & QQPDTMapInit() +{ + + static QQPDTMap m; + + static const struct { + int hid; // Pythia + int pid; // PDT + } SList[] = { + { -13, 21 }, + { -12, -6 }, + { -11, -5 }, + { -10, -4 }, + { -9, -3 }, + { -8, -1 }, + { -7, -2 }, + { -6, 6 }, + { -5, 5 }, + { -4, 4 }, + { -3, 3 }, + { -2, 1 }, + { -1, 2 }, + { 0, 10022}, + { 1, 22 }, + { 2, 23 }, + { 3, 24 }, + { 4, -24 }, + { 5, 82 }, + { 7, 11 }, + { 8, -11 }, + { 9, 12 }, + { 10, -12 }, + { 11, 13 }, + { 12, -13 }, + { 13, 14 }, + { 14, -14 }, + { 15, 15 }, + { 16, -15 }, + { 17, 16 }, + { 18, -16 }, + { 19, 20313 }, + { 20, -20313 }, + { 21, 211 }, + { 22, -211 }, + { 23, 321 }, + { 24, -321 }, + { 25, 311 }, + { 26, -311 }, + { 27, 421 }, + { 28, -421 }, + { 29, 411 }, + { 30, -411 }, + { 31, 431 }, + { 32, -431 }, + { 33, -521 }, + { 34, 521 }, + { 35, -511 }, + { 36, 511 }, + { 37, -531 }, + { 38, 531 }, + { 39, -541 }, + { 40, 541 }, + { 41, 621 }, + { 42, -621 }, + { 43, 611 }, + { 44, -611 }, + { 45, 631 }, + { 46, -631 }, + { 47, 641 }, + { 48, -641 }, + { 49, 651 }, + { 50, -651 }, + { 51, 111 }, + { 52, 221 }, + { 53, 331 }, + { 54, 441 }, + { 55, 551 }, + { 56, 661 }, + { 57, 310 }, + { 58, 130 }, + { 59, 10313 }, + { 60, -10313 }, + { 61, 213 }, + { 62, -213 }, + { 63, 323 }, + { 64, -323 }, + { 65, 313 }, + { 66, -313 }, + { 67, 423 }, + { 68, -423 }, + { 69, 413 }, + { 70, -413 }, + { 71, 433 }, + { 72, -433 }, + { 73, -523 }, + { 74, 523 }, + { 75, -513 }, + { 76, 513 }, + { 77, -533 }, + { 78, 533 }, + { 79, -543 }, + { 80, 543 }, + { 81, 623 }, + { 82, -623 }, + { 83, 613 }, + { 84, -613 }, + { 85, 633 }, + { 86, -633 }, + { 87, 643 }, + { 88, -643 }, + { 89, 653 }, + { 90, -653 }, + { 91, 113 }, + { 92, 223 }, + { 93, 333 }, + { 94, 443 }, + { 95, 553 }, + { 96, 663 }, + { 97, 100553 }, + { 98, 200553 }, + { 99, 300553 }, + { 100, 10551 }, + { 101, 20553 }, + { 102, 555 }, + { 103, 110551 }, + { 104, 120553 }, + { 105, 100555 }, + { 106, 30113 }, + { 107, 20213 }, + { 108, 20113 }, + { 109, -20213 }, + { 110, 10441 }, + { 111, 20443 }, + { 112, 445 }, + { 121, 3122 }, + { 122, -3122 }, + { 123, 4122 }, + { 124, -4122 }, + { 125, 4232 }, + { 126, -4232 }, + { 127, 4132 }, + { 128, -4132 }, + { 129, 3212 }, + { 130, -3212 }, + { 131, 4212 }, + { 132, -4212 }, + { 133, 4322 }, + { 134, -4322 }, + { 135, 4312 }, + { 136, -4312 }, + { 137, 2212 }, + { 138, -2212 }, + { 139, 3222 }, + { 140, -3222 }, + { 141, 4222 }, + { 142, -4222 }, + { 143, 2112 }, + { 144, -2112 }, + { 145, 3112 }, + { 146, -3112 }, + { 147, 4112 }, + { 148, -4112 }, + { 149, 3322 }, + { 150, -3322 }, + { 151, 3312 }, + { 152, -3312 }, + { 153, 4332 }, + { 154, -4332 }, + { 155, 4422 }, + { 156, -4422 }, + { 157, 4412 }, + { 158, -4412 }, + { 159, 4432 }, + { 160, -4432 }, + { 161, 3214 }, + { 162, -3214 }, + { 163, 4214 }, + { 164, -4214 }, + { 165, 4324 }, + { 166, -4324 }, + { 167, 4314 }, + { 168, -4314 }, + { 169, 2214 }, + { 170, -2214 }, + { 171, 3224 }, + { 172, -3224 }, + { 173, 4224 }, + { 174, -4224 }, + { 175, 2114 }, + { 176, -2114 }, + { 177, 3114 }, + { 178, -3114 }, + { 179, 4114 }, + { 180, -4114 }, + { 181, 3324 }, + { 182, -3324 }, + { 183, 3314 }, + { 184, -3314 }, + { 185, 4334 }, + { 186, -4334 }, + { 187, 4424 }, + { 188, -4424 }, + { 189, 4414 }, + { 190, -4414 }, + { 191, 4434 }, + { 192, -4434 }, + { 193, 2224 }, + { 194, -2224 }, + { 195, 1114 }, + { 196, -1114 }, + { 197, 3334 }, + { 198, -3334 }, + { 199, 4444 }, + { 200, -4444 }, + { 201, 10323 }, + { 202, -10323 }, + { 203, 20323 }, + { 204, -20323 }, + { 205, 30213 }, + { 206, -30213 }, + { 207, 84 }, + { 208, -84 }, + { 209, 85 }, + { 210, -85 }, + { 211, 30443 }, + { 212, 9000443 }, + { 213, 9010443 }, + { 214, 9020443 }, + { 215, 10443 }, + { 216, 9000553 }, + { 217, 9010553 }, + { 218, 10553 }, + { 219, 100443 }, + { 220, 9020553 }, + { 221, 10411 }, + { 222, 20413 }, + { 223, 10413 }, + { 224, 415 }, + { 225, -10411 }, + { 226, -20413 }, + { 227, -10413 }, + { 228, -415 }, + { 229, 10421 }, + { 230, 20423 }, + { 231, 10423 }, + { 232, 425 }, + { 233, -10421 }, + { 234, -20423 }, + { 235, -10423 }, + { 236, -425 }, + { 237, 10431 }, + { 238, 20433 }, + { 239, 10433 }, + { 240, 435 }, + { 241, -10431 }, + { 242, -20433 }, + { 243, -10433 }, + { 244, -435 }, + { 251, 9000111 }, + { 252, 9000211 }, + { 253, -9000211 }, + { 254, 115 }, + { 255, 215 }, + { 256, -215 }, + { 257, 9010221 }, + { 258, 10221 }, + { 259, 20223 }, + { 260, 20333 }, + { 261, 225 }, + { 262, 335 }, + { 263, 10223 }, + { 264, 10333 }, + { 265, 10113 }, + { 266, 10213 }, + { 267, -10213 }, + { 268, 10311 }, + { 269, -10311 }, + { 270, 10321 }, + { 271, -10321 }, + { 272, 315 }, + { 273, -315 }, + { 274, 325 }, + { 275, -325 }, + { 276, 86 }, + { 277, -86 }, + { 278, 317 }, + { 279, -317 }, + { 280, 327 }, + { 281, -327 }, + { 291, 87 }, + { 292, -87 }, + { 293, 88 }, + { 294, -88 }, + { 295, 89 }, + { 296, -89 }, + { 297, 90 }, + { 298, -90 }, + { 401, 5122 }, + { 402, -5122 }, + { 403, 5232 }, + { 404, -5232 }, + { 405, 5132 }, + { 406, -5132 }, + { 407, 5242 }, + { 408, -5242 }, + { 409, 5142 }, + { 410, -5142 }, + { 411, 5342 }, + { 412, -5342 }, + { 413, 5212 }, + { 414, -5212 }, + { 415, 5322 }, + { 416, -5322 }, + { 417, 5312 }, + { 418, -5312 }, + { 419, 5422 }, + { 420, -5422 }, + { 421, 5412 }, + { 422, -5412 }, + { 423, 5432 }, + { 424, -5432 }, + { 425, 5222 }, + { 426, -5222 }, + { 427, 5112 }, + { 428, -5112 }, + { 429, 5332 }, + { 430, -5332 }, + { 431, 5442 }, + { 432, -5442 }, + { 433, 5522 }, + { 434, -5522 }, + { 435, 5512 }, + { 436, -5512 }, + { 437, 5532 }, + { 438, -5532 }, + { 439, 5542 }, + { 440, -5542 }, + { 441, 5214 }, + { 442, -5214 }, + { 443, 5324 }, + { 444, -5324 }, + { 445, 5314 }, + { 446, -5314 }, + { 447, 5424 }, + { 448, -5424 }, + { 449, 5414 }, + { 450, -5414 }, + { 451, 5434 }, + { 452, -5434 }, + { 453, 5224 }, + { 454, -5224 }, + { 455, 5114 }, + { 456, -5114 }, + { 457, 5334 }, + { 458, -5334 }, + { 459, 5444 }, + { 460, -5444 }, + { 461, 5524 }, + { 462, -5524 }, + { 463, 5514 }, + { 464, -5514 }, + { 465, 5534 }, + { 466, -5534 }, + { 467, 5544 }, + { 468, -5544 }, + { 469, 5554 }, + { 470, -5554 }, + { 471, 10521 }, + { 472, 20523 }, + { 473, 10523 }, + { 474, 525 }, + { 475, -10521 }, + { 476, -20523 }, + { 477, -10523 }, + { 478, -525 }, + { 479, 10511 }, + { 480, 20513 }, + { 481, 10513 }, + { 482, 515 }, + { 483, -10511 }, + { 484, -20513 }, + { 485, -10513 }, + { 486, -515 }, + { 487, 10531 }, + { 488, 20533 }, + { 489, 10533 }, + { 490, 535 }, + { 491, -10531 }, + { 492, -20533 }, + { 493, -10533 }, + { 494, -535 }, + { 495, 92 }, + { 496, -92 }, + { 497, 93 }, + { 498, -93 } + }; + + int listSize = sizeof(SList)/sizeof(SList[0]); + for( int k=0; k!=listSize; ++k) { + m.insert( std::make_pair( SList[k].hid, SList[k].pid) ); + } + return m; +} // QQPDTMapInit() + +// we need a separate map for the QQ quark pair pseudo-particles +// use diquark particle ID numbers +QQbarMap const & QQbarMapInit() +{ + static QQbarMap m; + + static const struct { + int hid; // Pythia + int pid; // PDT + } SList[] = { + { 1, 2203 }, + { 2, 2101 }, + { 3, 3203 }, + { 4, 4203 }, + { 5, 5203 }, + { 6, 6203 }, + { 7, 2103 }, + { 8, 1103 }, + { 9, 3103 }, + { 10, 4103 }, + { 11, 5103 }, + { 12, 6103 }, + { 13, 3201 }, + { 14, 3101 }, + { 15, 3303 }, + { 16, 4303 }, + { 17, 5303 }, + { 18, 6303 }, + { 19, 4201 }, + { 20, 4101 }, + { 21, 4301 }, + { 22, 4403 }, + { 23, 5403 }, + { 24, 6403 }, + { 25, 5201 }, + { 26, 5101 }, + { 27, 5301 }, + { 28, 5401 }, + { 29, 5503 }, + { 30, 6503 }, + { 31, 6201 }, + { 32, 6101 }, + { 33, 6301 }, + { 34, 6401 }, + { 35, 6501 }, + { 36, 6603 }, + { 37, 81 } + }; + + int listSize = sizeof(SList)/sizeof(SList[0]); + for( int k=0; k!=listSize; ++k) { + m.insert( std::make_pair( SList[k].hid, SList[k].pid) ); + } + return m; +} // QQbarMapInit() + +PDTQQMap const & PDTQQMapInit() +{ + static PDTQQMap m; + static QQPDTMap const & hmap = getQQPDTMap(); + + for(QQPDTMap::const_iterator cit=hmap.begin(), mend=hmap.end(); cit!=mend; ++cit ) { + m.insert( std::make_pair( cit->second, cit->first )); + } + return m; +} + +InverseQQbarMap const & InverseQQbarMapInit() +{ + static InverseQQbarMap m; + static QQbarMap const & hmap = getQQbarMap(); + + for(QQbarMap::const_iterator cit=hmap.begin(), mend=hmap.end(); cit!=mend; ++cit ) { + m.insert( std::make_pair( cit->second, cit->first )); + } + return m; +} + +// +// getQQPDTMap is the ONLY function allowed to call QQPDTMapInit +// +QQPDTMap const & getQQPDTMap() +{ + static QQPDTMap const & hmap = QQPDTMapInit(); + return hmap; +} // getQQPDTMap() + +// +// getPDTQQMap is the ONLY function allowed to call QQPDTMapInit +// +PDTQQMap const & getPDTQQMap() +{ + static PDTQQMap const & hmap = PDTQQMapInit(); + return hmap; +} // getPDTQQMap() +// +// getQQbarMap is the ONLY function allowed to call QQbarMapInit +// +QQbarMap const & getQQbarMap() +{ + static QQbarMap const & hmap = QQbarMapInit(); + return hmap; +} // getQQbarMap() + +// +// getInverseQQbarMap is the ONLY function allowed to call QQbarMapInit +// +InverseQQbarMap const & getInverseQQbarMap() +{ + static InverseQQbarMap const & hmap = InverseQQbarMapInit(); + return hmap; +} // getInverseQQbarMap() + +} // unnamed namespace + +int translateQQbar( const int id ) +{ + static QQbarMap const & hmap = getQQbarMap(); + + QQbarMap::const_iterator const cit = hmap.find( id ); + // found it in the map + if ( cit != hmap.end() ) { return cit->second; } + // for QQ, you can only use the map + return 0; +} + +int translateInverseQQbar( const int id ) +{ + static InverseQQbarMap const & pmap = getInverseQQbarMap(); + + InverseQQbarMap::const_iterator const cit = pmap.find( id ); + // found it in the map + if ( cit != pmap.end() ) { return cit->second; } + // for QQ, you can only use the map + return 0; +} + +int translateQQtoPDT( const int id ) +{ + static QQPDTMap const & hmap = getQQPDTMap(); + + QQPDTMap::const_iterator const cit = hmap.find( id ); + // found it in the map + if ( cit != hmap.end() ) { return cit->second; } + // for QQ, you can only use the map + return 0; +} + +int translatePDTtoQQ( const int id ) +{ + static PDTQQMap const & pmap = getPDTQQMap(); + + PDTQQMap::const_iterator const cit = pmap.find( id ); + // found it in the map + if ( cit != pmap.end() ) { return cit->second; } + // for QQ, you can only use the map + return 0; +} + +void writeQQTranslation ( std::ostream & os ) +{ + int id, iq, iback; + writeVersion( os ); + os << " HepPID Particle List" << std::endl; + os << std::endl; + + // quark pairs have overlapping QQ ID numbers + for( iq=1; iq<40; ++iq) { + id = translateQQbar( iq ); + if ( id != 0 ) { + os << " QQ number: " ; + os.width(10); + os << iq << " HepPID number: " ; + os.width(10); + os << id << " " << particleName(id) << std::endl; + // check reverse translation + iback = translateInverseQQbar(id); + if(iback != iq) { + os << " WARNING: " << id << " translates back to " + << iback << " not to " << iq << std::endl; + } + } + } + // regular QQ particles + for( iq=-13; iq<501; ++iq) { + id = translateQQtoPDT( iq ); + if ( id != 0 ) { + os << " QQ number: " ; + os.width(10); + os << iq << " HepPID number: " ; + os.width(10); + os << id << " " << particleName(id) << std::endl; + // check reverse translation + iback = translatePDTtoQQ(id); + if(iback != iq) { + os << " WARNING: " << id << " translates back to " + << iback << " not to " << iq << std::endl; + } + } + } + return; +} // writeQQTranslation() + +} // HepPID From 8c1478cf4bb548ec19319fbf71fd34c3acf4276e Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 27 Mar 2012 16:24:22 +0200 Subject: [PATCH 0022/1298] fix isActive --- include/mpc/Candidate.h | 8 ++++---- include/mpc/module/BreakCondition.h | 3 ++- python/mpc.i | 1 - src/Candidate.cpp | 2 +- test/python/testDeflectionCK.py | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/mpc/Candidate.h b/include/mpc/Candidate.h index 026f52f6b..a7fb1b336 100644 --- a/include/mpc/Candidate.h +++ b/include/mpc/Candidate.h @@ -50,14 +50,14 @@ class Candidate: public Referenced { virtual ~Candidate() {}; bool isActive() const; - void setActive(const bool b); - - double getRedshift() const; - void setRedshift(double z); + void setActive(bool b); double getTrajectoryLength() const; void setTrajectoryLength(double a); + double getRedshift() const; + void setRedshift(double z); + double getCurrentStep() const; void setCurrentStep(double lstep); diff --git a/include/mpc/module/BreakCondition.h b/include/mpc/module/BreakCondition.h index c43050566..5998ae74d 100644 --- a/include/mpc/module/BreakCondition.h +++ b/include/mpc/module/BreakCondition.h @@ -24,7 +24,8 @@ class MaximumTrajectoryLength: public Module { double l = candidate->getTrajectoryLength(); if (l >= maxLength) candidate->setActive(false); - candidate->limitNextStep(maxLength - l); + else + candidate->limitNextStep(maxLength - l); } std::string getDescription() const { diff --git a/python/mpc.i b/python/mpc.i index 1384ae987..9baf40c40 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -94,6 +94,5 @@ %include "mpc/module/GlutDisplay.h" %include "mpc/module/Tools.h" - %include "mpc/ModuleChain.h" %include "mpc/ModuleList.h" diff --git a/src/Candidate.cpp b/src/Candidate.cpp index 8ffda0e95..ec9ab9e0c 100644 --- a/src/Candidate.cpp +++ b/src/Candidate.cpp @@ -16,7 +16,7 @@ bool Candidate::isActive() const { return active; } -void Candidate::setActive(const bool b) { +void Candidate::setActive(bool b) { active = b; } diff --git a/test/python/testDeflectionCK.py b/test/python/testDeflectionCK.py index 8e95ad9f5..bb45b3f61 100644 --- a/test/python/testDeflectionCK.py +++ b/test/python/testDeflectionCK.py @@ -24,11 +24,11 @@ def propagate(tolerance): c.setNextStep(1 * kpc) c.current.setPosition(Vector3(0, R, 0)) c.current.setDirection(Vector3(1, 0, 0)) - c.setStatus(Candidate.Active) + c.setActive(True) posX, posY, dirX, dirY, dirDeviation, theta = [], [], [], [], [], [] nSteps = 0 - while (c.getStatus() == Candidate.Active): + while c.isActive(): prop.process(c) maxLen.process(c) nSteps +=1 @@ -84,7 +84,7 @@ def propagate(tolerance): plot(theta/2/pi, arccos(dirDev)*180/pi, label='%.0e, %i'%(tolerance, n)) legend(title='Tolerance, Steps', loc='upper left') xlabel(r'Travelled Distance / $2 \pi R_L$') -ylabel(r'Directional Error [$^\circ$]') +ylabel(r'Direction Error [$^\circ$]') xlim(0,1) grid() savefig('DeflectionCK_pdeviation.png',bbox_inches='tight') @@ -98,7 +98,7 @@ def propagate(tolerance): plot(theta/2/pi, displacement, label='%.0e, %i'%(tolerance, n)) legend(title='Tolerance, Steps', loc='upper left') xlabel(r'Travelled Distance / $2 \pi R_L$') -ylabel(r'Positional Error / $R_L$') +ylabel(r'Position Error / $R_L$') xlim(0,1) grid() savefig('DeflectionCK_xdeviation.png',bbox_inches='tight') From 186c5520ceb5861fac9243844dae8eceb9a4c174 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 27 Mar 2012 17:22:05 +0200 Subject: [PATCH 0023/1298] move FindXXX.cmake to /cmake --- CMakeLists.txt | 4 +-- FindFFTW.cmake => cmake/FindFFTW.cmake | 0 .../FindFreeGlut.cmake | 0 FindGSL.cmake => cmake/FindGSL.cmake | 0 FindGadget.cmake => cmake/FindGadget.cmake | 0 .../FindGooglePerfTools.cmake | 0 FindOpenGl.cmake => cmake/FindOpenGl.cmake | 0 libs/kiss/include/kiss/io.h | 4 +-- Python.cmake => python/Python.cmake | 0 test/python/testNuclearDecay.py | 36 ------------------- 10 files changed, 4 insertions(+), 40 deletions(-) rename FindFFTW.cmake => cmake/FindFFTW.cmake (100%) rename FindFreeGlut.cmake => cmake/FindFreeGlut.cmake (100%) rename FindGSL.cmake => cmake/FindGSL.cmake (100%) rename FindGadget.cmake => cmake/FindGadget.cmake (100%) rename FindGooglePerfTools.cmake => cmake/FindGooglePerfTools.cmake (100%) rename FindOpenGl.cmake => cmake/FindOpenGl.cmake (100%) rename Python.cmake => python/Python.cmake (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 00beeb47d..d5d30e74e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 2.6) project(ModularPropagationCode) -set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}" ${CMAKE_MODULE_PATH}) +set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) set (MPC_EXTRA_SOURCES) set (MPC_EXTRA_INCLUDES) @@ -151,7 +151,7 @@ endif() # ---------------------------------------------------------------------------- # Python # ---------------------------------------------------------------------------- -INCLUDE (Python.cmake) +INCLUDE (python/Python.cmake) include_directories(${PYTHON_INCLUDE_PATH}) SET_SOURCE_FILES_PROPERTIES( ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx PROPERTIES GENERATED true ) diff --git a/FindFFTW.cmake b/cmake/FindFFTW.cmake similarity index 100% rename from FindFFTW.cmake rename to cmake/FindFFTW.cmake diff --git a/FindFreeGlut.cmake b/cmake/FindFreeGlut.cmake similarity index 100% rename from FindFreeGlut.cmake rename to cmake/FindFreeGlut.cmake diff --git a/FindGSL.cmake b/cmake/FindGSL.cmake similarity index 100% rename from FindGSL.cmake rename to cmake/FindGSL.cmake diff --git a/FindGadget.cmake b/cmake/FindGadget.cmake similarity index 100% rename from FindGadget.cmake rename to cmake/FindGadget.cmake diff --git a/FindGooglePerfTools.cmake b/cmake/FindGooglePerfTools.cmake similarity index 100% rename from FindGooglePerfTools.cmake rename to cmake/FindGooglePerfTools.cmake diff --git a/FindOpenGl.cmake b/cmake/FindOpenGl.cmake similarity index 100% rename from FindOpenGl.cmake rename to cmake/FindOpenGl.cmake diff --git a/libs/kiss/include/kiss/io.h b/libs/kiss/include/kiss/io.h index b33d430ba..0b13ac2ff 100644 --- a/libs/kiss/include/kiss/io.h +++ b/libs/kiss/include/kiss/io.h @@ -53,14 +53,14 @@ class CompressedOutput { 0) { } - bool writeBytes(char *data, size_t size) { +// bool writeBytes(char *data, size_t size) { // data_left = size; // while (data_left) { // // output.write(data, size); // } // return (output); - } +// } }; template diff --git a/Python.cmake b/python/Python.cmake similarity index 100% rename from Python.cmake rename to python/Python.cmake diff --git a/test/python/testNuclearDecay.py b/test/python/testNuclearDecay.py index 616a4e565..91fce003e 100644 --- a/test/python/testNuclearDecay.py +++ b/test/python/testNuclearDecay.py @@ -74,39 +74,3 @@ ax.grid() fig.savefig('NuclearDecay_multiplicity.png',bbox_inches='tight') - - -#def getDecayChannel(hepId): -# c = Candidate() -# c.current.setId(hepId) -# c.current.setEnergy(1*EeV) -# -# c.clearInteractionStates() -# decay.process(c) -# s = InteractionState() -# c.getInteractionState('mpc::NuclearDecay', s) -# -# return s.channel - -#import ROOT -#def getDecayTime(hepId, n=1000): -# c = Candidate() -# c.current.setId(hepId) -# c.current.setEnergy(1*EeV) -# -# h = ROOT.TH1F('','',40,0,100) -# -# for i in range(n): -# c.clearInteractionStates() -# decay.process(c) -# s = InteractionState() -# c.getInteractionState('mpc::NuclearDecay', s) -# h.Fill(s.distance / c_light) -# -# if h.GetEffectiveEntries() == 0: -# return np.inf -# -# print h.GetEntries() -# f = ROOT.TF1('f1', 'expo') -# h.Fit(f, "q") -# return 1/-f.GetParameter(1) \ No newline at end of file From 901ca27ebfabd717d54cedc6c05e52d175eb64fa Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 28 Mar 2012 12:06:28 +0200 Subject: [PATCH 0024/1298] add some getters to turbulentMagneticFieldGrid --- README | 13 ++++++++++++- .../mpc/magneticField/turbulentMagneticFieldGrid.h | 2 ++ src/magneticField/turbulentMagneticFieldGrid.cpp | 8 ++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/README b/README index 196dff673..e3be9d13e 100644 --- a/README +++ b/README @@ -1,6 +1,17 @@ Installation from source -mpc is build using CMAKE - for more information see www.cmake.org +MPC is built using CMAKE - for more information see www.cmake.org 1) $cd build/ 2) $cmake .. or $ccmake .. 3) make + +Dependencies: +GNU Scientific Library - for interpolation + +Optional dependencies: +Python - to use MPC from python +OpenMP - for shared memory parallelization +FFTW - for turbulent magnetic field +Gadget - for smooth particle large scale structure +GTest - for unit-tests + diff --git a/include/mpc/magneticField/turbulentMagneticFieldGrid.h b/include/mpc/magneticField/turbulentMagneticFieldGrid.h index ea994bece..0ac13e200 100644 --- a/include/mpc/magneticField/turbulentMagneticFieldGrid.h +++ b/include/mpc/magneticField/turbulentMagneticFieldGrid.h @@ -28,7 +28,9 @@ class TurbulentMagneticFieldGrid: public MagneticFieldGrid { double lMin, double lMax, double Brms, double powerSpectralIndex); void setSeed(int seed); void initialize(); + double getRMSFieldStrength() const; double getCorrelationLength() const; + double getPowerSpectralIndex() const; protected: double Brms, lMin, lMax, powerSpectralIndex; diff --git a/src/magneticField/turbulentMagneticFieldGrid.cpp b/src/magneticField/turbulentMagneticFieldGrid.cpp index 0e43df048..1a993d70b 100644 --- a/src/magneticField/turbulentMagneticFieldGrid.cpp +++ b/src/magneticField/turbulentMagneticFieldGrid.cpp @@ -130,6 +130,14 @@ void TurbulentMagneticFieldGrid::initialize() { fftw_free(Bz); } +double TurbulentMagneticFieldGrid::getRMSFieldStrength() const { + return Brms; +} + +double TurbulentMagneticFieldGrid::getPowerSpectralIndex() const { + return powerSpectralIndex; +} + double TurbulentMagneticFieldGrid::getCorrelationLength() const { double r = lMin / lMax; double a = -powerSpectralIndex - 2; From 34272144325e95259549b9e6af132313b8305f48 Mon Sep 17 00:00:00 2001 From: geromueller Date: Wed, 28 Mar 2012 17:08:56 +0200 Subject: [PATCH 0025/1298] minor fix in ConditionalOutput --- include/mpc/module/Output.h | 2 +- src/module/Output.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/mpc/module/Output.h b/include/mpc/module/Output.h index 892541ba3..da696cbd6 100644 --- a/include/mpc/module/Output.h +++ b/include/mpc/module/Output.h @@ -31,7 +31,7 @@ class ConditionalOutput: public Module { std::string propertyName; public: - ConditionalOutput(std::string name, std::string propName); + ConditionalOutput(std::string filename, std::string propName); ~ConditionalOutput(); void process(Candidate *candidate) const; std::string getDescription() const; diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 87e86f243..dba0c3ff2 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -37,11 +37,13 @@ std::string TrajectoryOutput::getDescription() const { return "Trajectory output"; } -ConditionalOutput::ConditionalOutput(std::string name, std::string propName) { +ConditionalOutput::ConditionalOutput(std::string filename, + std::string propName) { propertyName = propName; outfile.open(name.c_str()); outfile - << "id, x, y, z, E, phi, theta, distance, i_id, i_x, i_y, i_z, i_E, i_phi, i_theta\n"; + << "id, x, y, z, E, phi, theta, distance, i_id, i_x, i_y, i_z, i_E, i_phi, i_theta" + << std::endl; } ConditionalOutput::~ConditionalOutput() { From 8ac2adb4b9f4fbe0f5457874baa05bb18e5e2abe Mon Sep 17 00:00:00 2001 From: geromueller Date: Wed, 28 Mar 2012 17:45:24 +0200 Subject: [PATCH 0026/1298] minor update --- src/module/common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/module/common.cpp b/src/module/common.cpp index 3434f139c..bbaae7782 100644 --- a/src/module/common.cpp +++ b/src/module/common.cpp @@ -31,7 +31,7 @@ std::string getDataPath(std::string filename) { if (is_directory(_path)) { dataPath = _path; KISS_LOG_INFO - << "getDataPath: use define, " << dataPath << std::endl; + << "getDataPath: use install prefix, " << dataPath << std::endl; return concat_path(dataPath, filename); } } From cba3f6a9aa39d3f9cb5e804ce5cadc62ec1af859 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 28 Mar 2012 19:03:06 +0200 Subject: [PATCH 0027/1298] add flags to Boundaries add removeProperty to Candidate --- include/mpc/Candidate.h | 3 +- include/mpc/module/BreakCondition.h | 124 +++++++++++++++++++++------- mpi/Slave.cpp | 13 +-- src/Candidate.cpp | 18 ++-- test/testBreakCondition.cpp | 55 +++++++----- test/testCore.cpp | 2 +- 6 files changed, 144 insertions(+), 71 deletions(-) diff --git a/include/mpc/Candidate.h b/include/mpc/Candidate.h index a7fb1b336..b32cc901e 100644 --- a/include/mpc/Candidate.h +++ b/include/mpc/Candidate.h @@ -65,8 +65,9 @@ class Candidate: public Referenced { void setNextStep(double step); void limitNextStep(double step); + void addProperty(const std::string &name, const std::string &value); + bool removeProperty(const std::string &name); bool getProperty(const std::string &name, std::string &value) const; - void setProperty(const std::string &name, const std::string &value); bool hasProperty(const std::string &name) const; bool getInteractionState(const std::string &moduleName, diff --git a/include/mpc/module/BreakCondition.h b/include/mpc/module/BreakCondition.h index 5998ae74d..123d5e4f0 100644 --- a/include/mpc/module/BreakCondition.h +++ b/include/mpc/module/BreakCondition.h @@ -67,18 +67,31 @@ class SmallObserverSphere: public Module { public: double radius; Vector3 center; + std::string flag; + std::string flagValue; + bool makeInactive; - SmallObserverSphere(Vector3 center, double radius) : - center(center), radius(radius) { + SmallObserverSphere(Vector3 center, double radius, std::string flag = + "Detected", std::string flagValue = "") { + this->center = center; + this->radius = radius; + this->flag = flag; + this->flagValue = flagValue; + this->makeInactive = true; + } + + void setMakeInactive(bool makeInactive) { + this->makeInactive = makeInactive; } void process(Candidate *candidate) const { double d = (candidate->current.getPosition() - center).mag(); if (d <= radius * 1.01) { - candidate->setActive(false); - candidate->setProperty("Detected", ""); - } else - candidate->limitNextStep((d - radius)); + candidate->addProperty("Detected", ""); + if (makeInactive) + candidate->setActive(false); + } + candidate->limitNextStep((d - radius)); } std::string getDescription() const { @@ -96,24 +109,42 @@ class CubicBoundary: public Module { protected: Vector3 origin; double size; - bool limitStep; double margin; + std::string flag; + std::string flagValue; + bool makeInactive; + bool limitStep; public: - CubicBoundary(Vector3 origin, double size) : - origin(origin), size(size), limitStep(false) { + CubicBoundary(Vector3 origin, double size, std::string flag = "OutOfBounds", + std::string flagValue = "") { + this->origin = origin; + this->size = size; + this->flag = flag; + this->flagValue = flagValue; + this->makeInactive = false; + this->limitStep = false; + this->margin = 0; } - CubicBoundary(Vector3 origin, double size, double margin) : - origin(origin), size(size), limitStep(true), margin(margin) { + void setMakeInactive(bool makeInactive) { + this->makeInactive = makeInactive; + } + + void setLimitStep(bool limitStep, double margin) { + this->limitStep = limitStep; + this->margin = margin; } void process(Candidate *candidate) const { Vector3 relPos = candidate->current.getPosition() - origin; double lo = std::min(relPos.x(), std::min(relPos.y(), relPos.z())); double hi = std::max(relPos.x(), std::max(relPos.y(), relPos.z())); - if ((lo <= 0.) or (hi >= size)) - candidate->setActive(false); + if ((lo <= 0.) or (hi >= size)) { + candidate->addProperty(flag, flagValue); + if (makeInactive) + candidate->setActive(false); + } if (limitStep) { candidate->limitNextStep(lo + margin); candidate->limitNextStep(size - hi + margin); @@ -129,28 +160,46 @@ class CubicBoundary: public Module { /** @class SphericalBoundary - @brief Flags a particle when exiting the sphere. + @brief Flag a particle when leaving the sphere. */ class SphericalBoundary: public Module { protected: Vector3 center; double radius; - bool limitStep; double margin; + std::string flag; + std::string flagValue; + bool makeInactive; + bool limitStep; public: - SphericalBoundary(Vector3 center, double radius) : - center(center), radius(radius), limitStep(false) { + SphericalBoundary(Vector3 center, double radius, std::string flag = + "OutOfBounds", std::string flagValue = "") { + this->center = center; + this->radius = radius; + this->flag = flag; + this->flagValue = flagValue; + this->makeInactive = false; + this->limitStep = false; + this->margin = 0; } - SphericalBoundary(Vector3 center, double radius, double margin) : - center(center), radius(radius), limitStep(true), margin(margin) { + void setMakeInactive(bool makeInactive) { + this->makeInactive = makeInactive; + } + + void setLimitStep(bool limitStep, double margin) { + this->limitStep = limitStep; + this->margin = margin; } void process(Candidate *candidate) const { double d = (candidate->current.getPosition() - center).mag(); - if (d >= radius) - candidate->setActive(false); + if (d >= radius) { + candidate->addProperty(flag, flagValue); + if (makeInactive) + candidate->setActive(false); + } if (limitStep) candidate->limitNextStep(radius - d + margin); } @@ -164,39 +213,50 @@ class SphericalBoundary: public Module { /** @class EllipsoidalBoundary - @brief Flags a particle when leaving then ellipsoid. + @brief Flags a particle when leaving the ellipsoid. */ class EllipsoidalBoundary: public Module { protected: Vector3 focalPoint1; Vector3 focalPoint2; double majorAxis; - bool limitStep; double margin; + std::string flag; + std::string flagValue; + bool makeInactive; + bool limitStep; public: EllipsoidalBoundary(Vector3 focalPoint1, Vector3 focalPoint2, - double majorAxis) { + double majorAxis, std::string flag = "OutOfBounds", + std::string flagValue = "") { this->focalPoint1 = focalPoint1; this->focalPoint2 = focalPoint2; this->majorAxis = majorAxis; + this->flag = flag; + this->flagValue = flagValue; + this->makeInactive = false; this->limitStep = false; + this->margin = 0; } - EllipsoidalBoundary(Vector3 focalPoint1, Vector3 focalPoint2, - double majorAxis, double margin) { - this->focalPoint1 = focalPoint1; - this->focalPoint2 = focalPoint2; - this->majorAxis = majorAxis; - this->limitStep = true; + void setMakeInactive(bool makeInactive) { + this->makeInactive = makeInactive; + } + + void setLimitStep(bool limitStep, double margin) { + this->limitStep = limitStep; this->margin = margin; } void process(Candidate *candidate) const { Vector3 pos = candidate->current.getPosition(); double d = (pos - focalPoint1).mag() + (pos - focalPoint2).mag(); - if (d >= majorAxis) - candidate->setActive(false); + if (d >= majorAxis) { + candidate->addProperty(flag, flagValue); + if (makeInactive) + candidate->setActive(false); + } if (limitStep) candidate->limitNextStep(majorAxis - d + margin); } diff --git a/mpi/Slave.cpp b/mpi/Slave.cpp index 60128177e..1382e34a6 100644 --- a/mpi/Slave.cpp +++ b/mpi/Slave.cpp @@ -37,7 +37,6 @@ void Slave::load(const string &filename) { // import.import(filename); UniformMagneticField *field = new UniformMagneticField( Vector3(0., 0., 1e-20)); -// TurbulentMagneticFieldGrid *field = new TurbulentMagneticFieldGrid(Vector3(0, 0, 0), 64, 0.1 * Mpc, 1e-12, 1, 8, -11. / 3., 10); chain.add(25, new DeflectionCK(field)); // interactions ------------------------------------------------------- @@ -46,18 +45,10 @@ void Slave::load(const string &filename) { chain.add(32, new ElectronPairProduction(ElectronPairProduction::CMB)); chain.add(33, new PhotoPionProduction(PhotoPionProduction::CMBIR)); - // break conditions --------------------------------------------------- -// chain.add(new MinimumEnergy(5 * EeV), 50); -// chain.add(new MaximumTrajectoryLength(100 * Mpc), 51); - chain.add(52, - new SphericalBoundary(Vector3(0, 0, 0) * Mpc, 20 * Mpc, 0.1 * Mpc)); -// chain.add(new SmallObserverSphere(Vector3(0, 0, 0) * Mpc, 1 * Mpc), 53); - -// output ------------------------------------------------------------- + // output ------------------------------------------------------------- chain.add(79, new ShellOutput()); // chain.add(new TrajectoryOutput("trajectories.csv"), 80); -// chain.add(new GlutDisplay(), 80); -chain.add(100, new ConditionalOutput("final.txt", "Detected")); + chain.add(100, new ConditionalOutput("final.txt", "Detected")); } void Slave::acquireJob() { diff --git a/src/Candidate.cpp b/src/Candidate.cpp index ec9ab9e0c..bd6a4face 100644 --- a/src/Candidate.cpp +++ b/src/Candidate.cpp @@ -80,6 +80,19 @@ void Candidate::clearInteractionStates() { interactionStates.clear(); } +void Candidate::addProperty(const std::string &name, const std::string &value) { + properties[name] = value; +} + +bool Candidate::removeProperty(const std::string& name) { + std::map::iterator i = properties.find( + name); + if (i == properties.end()) + return false; + properties.erase(i); + return true; +} + bool Candidate::getProperty(const std::string &name, std::string &value) const { std::map::const_iterator i = properties.find( name); @@ -89,10 +102,6 @@ bool Candidate::getProperty(const std::string &name, std::string &value) const { return true; } -void Candidate::setProperty(const std::string &name, const std::string &value) { - properties[name] = value; -} - bool Candidate::hasProperty(const std::string &name) const { std::map::const_iterator i = properties.find( name); @@ -100,7 +109,6 @@ bool Candidate::hasProperty(const std::string &name) const { return false; return true; } -; void Candidate::addSecondary(int id, double energy) { ref_ptr secondary = new Candidate; diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index f76e6f2d4..2776d0122 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -32,7 +32,7 @@ TEST(MaximumTrajectoryLength, Continue) { EXPECT_TRUE(candidate.isActive()); } -TEST(MaximumTrajectoryLength, Stop) { +TEST(MaximumTrajectoryLength, stop) { MaximumTrajectoryLength maxLength(10); Candidate candidate; candidate.setTrajectoryLength(10.1); @@ -48,7 +48,7 @@ TEST(SmallObserverSphere, Continue) { EXPECT_TRUE(candidate.isActive()); } -TEST(SmallObserverSphere, Detect) { +TEST(SmallObserverSphere, detect) { SmallObserverSphere obs(Vector3(0, 0, 0), 1); Candidate candidate; candidate.current.setPosition(Vector3(0.1, 0.5, -0.1)); @@ -57,7 +57,7 @@ TEST(SmallObserverSphere, Detect) { EXPECT_TRUE(candidate.hasProperty("Detected")); } -TEST(SmallObserverSphere, LimitStep) { +TEST(SmallObserverSphere, limitStep) { SmallObserverSphere obs(Vector3(0, 0, 0), 1); Candidate candidate; candidate.setNextStep(10); @@ -66,7 +66,7 @@ TEST(SmallObserverSphere, LimitStep) { EXPECT_DOUBLE_EQ(candidate.getNextStep(), 1); } -TEST(CubicBoundary, Inside) { +TEST(CubicBoundary, inside) { CubicBoundary cube(Vector3(0, 0, 0), 10); Candidate candidate; candidate.current.setPosition(Vector3(9, 5, 5)); @@ -74,21 +74,22 @@ TEST(CubicBoundary, Inside) { EXPECT_TRUE(candidate.isActive()); } -TEST(CubicBoundary, Outside) { +TEST(CubicBoundary, outside) { CubicBoundary cube(Vector3(0, 0, 0), 10); Candidate candidate; candidate.current.setPosition(Vector3(10.1, 5, 5)); cube.process(&candidate); - EXPECT_FALSE(candidate.isActive()); + EXPECT_TRUE(candidate.isActive()); + EXPECT_TRUE(candidate.hasProperty("OutOfBounds")); - candidate.current.setPosition(Vector3(5, -0.1, 5)); - candidate.setActive(true); + cube.setMakeInactive(true); cube.process(&candidate); EXPECT_FALSE(candidate.isActive()); } -TEST(CubicBoundary, LimitStep) { - CubicBoundary cube(Vector3(0, 0, 0), 10, 1); +TEST(CubicBoundary, limitStep) { + CubicBoundary cube(Vector3(0, 0, 0), 10); + cube.setLimitStep(true, 1); Candidate candidate; candidate.setNextStep(10); candidate.current.setPosition(Vector3(5, 5, 0.5)); @@ -96,24 +97,30 @@ TEST(CubicBoundary, LimitStep) { EXPECT_DOUBLE_EQ(candidate.getNextStep(), 1.5); } -TEST(SphericalBoundary, Inside) { +TEST(SphericalBoundary, inside) { SphericalBoundary sphere(Vector3(0, 0, 0), 10); Candidate candidate; candidate.current.setPosition(Vector3(9, 0, 0)); sphere.process(&candidate); - EXPECT_TRUE(candidate.isActive()); + EXPECT_FALSE(candidate.hasProperty("OutOfBounds")); } -TEST(SphericalBoundary, Outside) { - SphericalBoundary sphere(Vector3(0, 0, 0), 10); +TEST(SphericalBoundary, outside) { + SphericalBoundary sphere(Vector3(0, 0, 0), 10, "PassedGalacticBorder"); Candidate candidate; candidate.current.setPosition(Vector3(0, -10.1, 0)); sphere.process(&candidate); + EXPECT_TRUE(candidate.isActive()); + EXPECT_TRUE(candidate.hasProperty("PassedGalacticBorder")); + + sphere.setMakeInactive(true); + sphere.process(&candidate); EXPECT_FALSE(candidate.isActive()); } -TEST(SphericalBoundary, LimitStep) { - SphericalBoundary sphere(Vector3(0, 0, 0), 10, 1); +TEST(SphericalBoundary, limitStep) { + SphericalBoundary sphere(Vector3(0, 0, 0), 10); + sphere.setLimitStep(true, 1); Candidate candidate; candidate.setNextStep(2); candidate.current.setPosition(Vector3(0, 0, 9.5)); @@ -121,24 +128,30 @@ TEST(SphericalBoundary, LimitStep) { EXPECT_DOUBLE_EQ(candidate.getNextStep(), 1.5); } -TEST(EllipsoidalBoundary, Inside) { +TEST(EllipsoidalBoundary, inside) { EllipsoidalBoundary ellipsoid(Vector3(-5, 0, 0), Vector3(5, 0, 0), 15); Candidate candidate; candidate.current.setPosition(Vector3(3, 2, 0)); ellipsoid.process(&candidate); - EXPECT_TRUE(candidate.isActive()); + EXPECT_FALSE(candidate.hasProperty("OutOfBounds")); } -TEST(EllipsoidalBoundary, Outside) { +TEST(EllipsoidalBoundary, outside) { EllipsoidalBoundary ellipsoid(Vector3(-5, 0, 0), Vector3(5, 0, 0), 15); Candidate candidate; candidate.current.setPosition(Vector3(0, 25, 0)); ellipsoid.process(&candidate); + EXPECT_TRUE(candidate.hasProperty("OutOfBounds")); + EXPECT_TRUE(candidate.isActive()); + + ellipsoid.setMakeInactive(true); + ellipsoid.process(&candidate); EXPECT_FALSE(candidate.isActive()); } -TEST(EllipsoidalBoundary, LimitStep) { - EllipsoidalBoundary ellipsoid(Vector3(-5, 0, 0), Vector3(5, 0, 0), 15, 0.5); +TEST(EllipsoidalBoundary, limitStep) { + EllipsoidalBoundary ellipsoid(Vector3(-5, 0, 0), Vector3(5, 0, 0), 15); + ellipsoid.setLimitStep(true, 0.5); Candidate candidate; candidate.setNextStep(2); candidate.current.setPosition(Vector3(7, 0, 0)); diff --git a/test/testCore.cpp b/test/testCore.cpp index fcd6f4f75..09dc89eff 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -93,7 +93,7 @@ TEST(Candidate, isActive) { TEST(Candidate, property) { Candidate candidate; - candidate.setProperty("foo","bar"); + candidate.addProperty("foo","bar"); EXPECT_TRUE(candidate.hasProperty("foo")); std::string value; candidate.getProperty("foo", value); From 945b0be6ce3fcbfe2b4ca1fd5be96d1a7a26124a Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 28 Mar 2012 19:08:24 +0200 Subject: [PATCH 0028/1298] ConditionalOutput now removes property after output is written --- src/module/Output.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/module/Output.cpp b/src/module/Output.cpp index dba0c3ff2..001fb6bd6 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -40,7 +40,7 @@ std::string TrajectoryOutput::getDescription() const { ConditionalOutput::ConditionalOutput(std::string filename, std::string propName) { propertyName = propName; - outfile.open(name.c_str()); + outfile.open(filename.c_str()); outfile << "id, x, y, z, E, phi, theta, distance, i_id, i_x, i_y, i_z, i_E, i_phi, i_theta" << std::endl; @@ -72,6 +72,7 @@ void ConditionalOutput::process(Candidate *candidate) const { outfile << std::endl; } } + candidate->removeProperty(propertyName); } std::string ConditionalOutput::getDescription() const { From 0e01926e13b02de98e339e799c6cc654f2a0b938 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 28 Mar 2012 19:22:34 +0200 Subject: [PATCH 0029/1298] rerenamed addProperty --- include/mpc/Candidate.h | 2 +- include/mpc/module/BreakCondition.h | 8 ++++---- src/Candidate.cpp | 2 +- test/testCore.cpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/mpc/Candidate.h b/include/mpc/Candidate.h index b32cc901e..db6aceaeb 100644 --- a/include/mpc/Candidate.h +++ b/include/mpc/Candidate.h @@ -65,7 +65,7 @@ class Candidate: public Referenced { void setNextStep(double step); void limitNextStep(double step); - void addProperty(const std::string &name, const std::string &value); + void setProperty(const std::string &name, const std::string &value); bool removeProperty(const std::string &name); bool getProperty(const std::string &name, std::string &value) const; bool hasProperty(const std::string &name) const; diff --git a/include/mpc/module/BreakCondition.h b/include/mpc/module/BreakCondition.h index 123d5e4f0..69ef67a3e 100644 --- a/include/mpc/module/BreakCondition.h +++ b/include/mpc/module/BreakCondition.h @@ -87,7 +87,7 @@ class SmallObserverSphere: public Module { void process(Candidate *candidate) const { double d = (candidate->current.getPosition() - center).mag(); if (d <= radius * 1.01) { - candidate->addProperty("Detected", ""); + candidate->setProperty("Detected", ""); if (makeInactive) candidate->setActive(false); } @@ -141,7 +141,7 @@ class CubicBoundary: public Module { double lo = std::min(relPos.x(), std::min(relPos.y(), relPos.z())); double hi = std::max(relPos.x(), std::max(relPos.y(), relPos.z())); if ((lo <= 0.) or (hi >= size)) { - candidate->addProperty(flag, flagValue); + candidate->setProperty(flag, flagValue); if (makeInactive) candidate->setActive(false); } @@ -196,7 +196,7 @@ class SphericalBoundary: public Module { void process(Candidate *candidate) const { double d = (candidate->current.getPosition() - center).mag(); if (d >= radius) { - candidate->addProperty(flag, flagValue); + candidate->setProperty(flag, flagValue); if (makeInactive) candidate->setActive(false); } @@ -253,7 +253,7 @@ class EllipsoidalBoundary: public Module { Vector3 pos = candidate->current.getPosition(); double d = (pos - focalPoint1).mag() + (pos - focalPoint2).mag(); if (d >= majorAxis) { - candidate->addProperty(flag, flagValue); + candidate->setProperty(flag, flagValue); if (makeInactive) candidate->setActive(false); } diff --git a/src/Candidate.cpp b/src/Candidate.cpp index bd6a4face..f34214fd4 100644 --- a/src/Candidate.cpp +++ b/src/Candidate.cpp @@ -80,7 +80,7 @@ void Candidate::clearInteractionStates() { interactionStates.clear(); } -void Candidate::addProperty(const std::string &name, const std::string &value) { +void Candidate::setProperty(const std::string &name, const std::string &value) { properties[name] = value; } diff --git a/test/testCore.cpp b/test/testCore.cpp index 09dc89eff..fcd6f4f75 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -93,7 +93,7 @@ TEST(Candidate, isActive) { TEST(Candidate, property) { Candidate candidate; - candidate.addProperty("foo","bar"); + candidate.setProperty("foo","bar"); EXPECT_TRUE(candidate.hasProperty("foo")); std::string value; candidate.getProperty("foo", value); From a37874348a054f5587d586278d94e5e3228320b6 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 28 Mar 2012 19:31:16 +0200 Subject: [PATCH 0030/1298] small cleanup --- .hgignore | 2 +- CMakeLists.txt | 2 +- example/example.xml | 18 ------------------ {example => src}/openmp.cpp | 0 4 files changed, 2 insertions(+), 20 deletions(-) delete mode 100644 example/example.xml rename {example => src}/openmp.cpp (100%) diff --git a/.hgignore b/.hgignore index 137ab202f..87bd37521 100644 --- a/.hgignore +++ b/.hgignore @@ -10,4 +10,4 @@ syntax: regexp syntax: regexp ^.settings$ syntax: regexp -^\test\python\$.png \ No newline at end of file +.png$ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index d25970642..32ade007b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,7 +138,7 @@ endif (GTEST_FOUND) # ---------------------------------------------------------------------------- # OpenMP and OpenMPI # ---------------------------------------------------------------------------- -add_executable(mpc-omp-run example/openmp.cpp) +add_executable(mpc-omp-run src/openmp.cpp) TARGET_LINK_LIBRARIES(mpc-omp-run mpc) # MPI needed for mpc-mpi diff --git a/example/example.xml b/example/example.xml deleted file mode 100644 index 2c71f0a76..000000000 --- a/example/example.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - 0 0 0 - 0 - 10 - 1 - 0 - 0 - 1 - - - 0 1 0 - - - - default - - diff --git a/example/openmp.cpp b/src/openmp.cpp similarity index 100% rename from example/openmp.cpp rename to src/openmp.cpp From 7a7400cbc22eda7a76616c470438901f49baa20f Mon Sep 17 00:00:00 2001 From: geromueller Date: Thu, 29 Mar 2012 16:03:10 +0200 Subject: [PATCH 0031/1298] fix cash-karp tableau --- include/mpc/ExplicitRungeKutta.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/mpc/ExplicitRungeKutta.h b/include/mpc/ExplicitRungeKutta.h index a2abf590c..ef7e2752d 100644 --- a/include/mpc/ExplicitRungeKutta.h +++ b/include/mpc/ExplicitRungeKutta.h @@ -85,10 +85,12 @@ inline void ExplicitRungeKutta::step(double t, const Y &y, Y &result, } // Cash-Karp coefficients -const double cash_karp_a[] = { 0., 0., 0., 0., 0., 1. / 5., 0., 0., 0., 0., 3. - / 40., 9. / 40., 0., 0., 0., 3. / 10., -9. / 10., 6. / 5., 0., 0., -11. - / 54., 5. / 2., -70. / 27., 35. / 27., 0., 1631. / 55296., 175. / 512., - 575. / 13824., 44275. / 110592., 253. / 4096. }; +const double cash_karp_a[] = { 0., 0., 0., 0., 0., 0., 1. / 5., 0., 0., 0., 0., + 0., 3. / 40., 9. / 40., 0., 0., 0., 0., 3. / 10., -9. / 10., 6. / 5., + 0., 0., 0., -11. / 54., 5. / 2., -70. / 27., 35. / 27., 0., 0., 1631. + / 55296., 175. / 512., 575. / 13824., 44275. / 110592., 253. + / 4096., 0. }; + const double cash_karp_b[] = { 37. / 378., 0, 250. / 621., 125. / 594., 0., 512. / 1771. }; const double cash_karp_bs[] = { 2825. / 27648., 0., 18575. / 48384., 13525. From 95688c696bbaf47dd5734cf850b6552a6a8ca11f Mon Sep 17 00:00:00 2001 From: geromueller Date: Thu, 29 Mar 2012 16:31:48 +0200 Subject: [PATCH 0032/1298] fix deflectionck test --- test/python/testDeflectionCK.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/test/python/testDeflectionCK.py b/test/python/testDeflectionCK.py index bb45b3f61..55ebd50bd 100644 --- a/test/python/testDeflectionCK.py +++ b/test/python/testDeflectionCK.py @@ -50,8 +50,8 @@ def propagate(tolerance): ### Plot trajectory in x-space with 1e-4 tolerance figure() posX, posY, dirX, dirY, dirDev, theta, n = propagate(1e-4) -plot(posX/R, posY/R, label='Simulated') -plot(sin(theta), cos(theta),'k--',label='True') +plot(posX/R, posY/R, "o", label='Simulated') +plot(sin(linspace(0,2*pi)), cos(linspace(0,2*pi)),'k--',label='True') title('Trajectory using $10^{-4}$ tolerance') legend() xlim(-1.5,1.5) @@ -61,12 +61,11 @@ def propagate(tolerance): grid() savefig('DeflectionCK_xtrajectory', bbox_inches='tight') - ### Plot trajectory in p-space with 1e-4 tolerance figure() posX, posY, dirX, dirY, dirDev, theta, n = propagate(1e-4) -plot(dirX, dirY, label='Simulated') -plot(sin(theta), cos(theta),'k--',label='True') +plot(dirX, dirY, "o", label='Simulated') +plot(sin(linspace(0,2*pi)), cos(linspace(0,2*pi)),'k--',label='True') title(r'Trajectory in $\vec{p}$-space using $10^{-4}$ tolerance') legend() xlim(-1.5,1.5) @@ -76,7 +75,6 @@ def propagate(tolerance): grid() savefig('DeflectionCK_ptrajectory', bbox_inches='tight') - ### Directional error as function of distance for different tolerances figure() for tolerance in [1e-3, 1e-4, 1e-5, 1e-6]: @@ -89,7 +87,6 @@ def propagate(tolerance): grid() savefig('DeflectionCK_pdeviation.png',bbox_inches='tight') - ### Positional error as function of distance for different tolerances figure() for tolerance in [1e-3, 1e-4, 1e-5, 1e-6]: @@ -103,4 +100,3 @@ def propagate(tolerance): grid() savefig('DeflectionCK_xdeviation.png',bbox_inches='tight') - From f67984b1e96f99b12898a3c8cdd315ee4a89282c Mon Sep 17 00:00:00 2001 From: geromueller Date: Thu, 29 Mar 2012 16:38:41 +0200 Subject: [PATCH 0033/1298] fix swig compile on header change, improve module output, fix ParticleState ctor --- CMakeLists.txt | 2 ++ src/ParticleState.cpp | 2 +- src/module/DeflectionCK.cpp | 6 ++++-- src/module/Output.cpp | 4 +++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 32ade007b..d4a85f804 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,11 +160,13 @@ endif() INCLUDE (python/Python.cmake) include_directories(${PYTHON_INCLUDE_PATH}) +FILE(GLOB_RECURSE MPC_INCLUDES include/*.h) SET_SOURCE_FILES_PROPERTIES( ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx PROPERTIES GENERATED true ) ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx COMMAND swig -c++ -python ${MPC_SWIG_DEFINES} -I${CMAKE_SOURCE_DIR}/include -o ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx -outdir ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/python/mpc.i DEPENDS ${CMAKE_SOURCE_DIR}/python/mpc.i ${MPC_INCLUDES} ) add_library(mpc-swig MODULE ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx) +#set_source_file_properties( ${CMAKE_SOURCE_DIR}/python/mpc.i PROPERTIES OBJECT_DEPENDS ${MPC_INCLUDES}) set_target_properties(mpc-swig PROPERTIES PREFIX "") set_target_properties(mpc-swig PROPERTIES OUTPUT_NAME "_mpc") target_link_libraries(mpc-swig mpc ${PYTHON_LIBRARIES}) diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index 011dde3ec..8275b5244 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -3,7 +3,7 @@ namespace mpc { ParticleState::ParticleState() : - id(0), energy(0) { + id(0), energy(0), position(0,0,0), direction(1,0,0) { } diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index 7047ba4ef..606a7b144 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -1,6 +1,7 @@ #include "mpc/module/DeflectionCK.h" #include +#include namespace mpc { @@ -39,7 +40,9 @@ DeflectionCK::DeflectionCK(MagneticField *field, double tolerance, } std::string DeflectionCK::getDescription() const { - return "Propagation in magnetic fields using the Cash-Karp method"; + std::stringstream sstr; + sstr << "Propagation in magnetic fields using the Cash-Karp method. Tolerance: " << tolerance << ", Minimum Step: " << minimumStep / kpc << " kpc"; + return sstr.str(); } void DeflectionCK::process(Candidate *candidate) const { @@ -66,7 +69,6 @@ void DeflectionCK::process(Candidate *candidate) const { do { hTry = h; erk.step(0, yIn, yOut, yErr, hTry, dydt); - if (controlType == NoStepSizeControl) { // no step size control break; diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 001fb6bd6..61942b3f1 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -87,7 +87,9 @@ void ShellOutput::process(Candidate *candidate) const { std::cout << candidate->getTrajectoryLength() / Mpc << " Mpc, "; std::cout << candidate->current.getId() << ", "; std::cout << candidate->current.getEnergy() / EeV << " EeV, "; - std::cout << candidate->current.getPosition() / Mpc << " Mpc, Status: "; + std::cout << candidate->current.getPosition() / Mpc << " Mpc, "; + std::cout << candidate->current.getDirection().phi() << " / "; + std::cout << candidate->current.getDirection().theta(); std::cout << std::endl; } } From 6c4239bdaed5a5a968497aa8e5bb22852d5b6fc1 Mon Sep 17 00:00:00 2001 From: geromueller Date: Thu, 29 Mar 2012 17:38:03 +0200 Subject: [PATCH 0034/1298] refactor module: provide description string. Refactor BreakCondition modules. --- CMakeLists.txt | 1 + include/mpc/Module.h | 4 + include/mpc/module/BreakCondition.h | 197 ++++---------------------- src/Module.cpp | 12 +- src/module/BreakCondition.cpp | 206 ++++++++++++++++++++++++++++ 5 files changed, 245 insertions(+), 175 deletions(-) create mode 100644 src/module/BreakCondition.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d4a85f804..66af52b58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,6 +89,7 @@ add_library(mpc SHARED src/ParticleState.cpp src/Source.cpp src/module/common.cpp + src/module/BreakCondition.cpp src/module/SimplePropagation.cpp src/module/DeflectionCK.cpp src/module/ElectronPairProduction.cpp diff --git a/include/mpc/Module.h b/include/mpc/Module.h index 3f6c27c31..b8a298d11 100644 --- a/include/mpc/Module.h +++ b/include/mpc/Module.h @@ -15,11 +15,15 @@ class Candidate; @brief Abstract base class for modules */ class Module: public Referenced { + std::string description; public: + Module(); + virtual ~Module() { } virtual std::string getDescription() const; + virtual void setDescription(const std::string &description); virtual void process(Candidate *candidate) const = 0; diff --git a/include/mpc/module/BreakCondition.h b/include/mpc/module/BreakCondition.h index 69ef67a3e..438721346 100644 --- a/include/mpc/module/BreakCondition.h +++ b/include/mpc/module/BreakCondition.h @@ -16,23 +16,8 @@ class MaximumTrajectoryLength: public Module { double maxLength; public: - MaximumTrajectoryLength(double length) : - maxLength(length) { - } - - void process(Candidate *candidate) const { - double l = candidate->getTrajectoryLength(); - if (l >= maxLength) - candidate->setActive(false); - else - candidate->limitNextStep(maxLength - l); - } - - std::string getDescription() const { - std::stringstream s; - s << "Maximum trajectory length: " << maxLength / Mpc << " Mpc"; - return s.str(); - } + MaximumTrajectoryLength(double length); + void process(Candidate *candidate) const; }; /** @@ -43,20 +28,8 @@ class MinimumEnergy: public Module { public: double minEnergy; - MinimumEnergy(double minEnergy) : - minEnergy(minEnergy) { - } - - void process(Candidate *candidate) const { - if (candidate->current.getEnergy() <= minEnergy) - candidate->setActive(false); - } - - std::string getDescription() const { - std::stringstream s; - s << "Minimum energy: " << minEnergy / EeV << " EeV"; - return s.str(); - } + MinimumEnergy(double minEnergy); + void process(Candidate *candidate) const; }; /** @@ -64,6 +37,7 @@ class MinimumEnergy: public Module { @brief Detects particles when entering the sphere. */ class SmallObserverSphere: public Module { + void updateDescription(); public: double radius; Vector3 center; @@ -72,33 +46,9 @@ class SmallObserverSphere: public Module { bool makeInactive; SmallObserverSphere(Vector3 center, double radius, std::string flag = - "Detected", std::string flagValue = "") { - this->center = center; - this->radius = radius; - this->flag = flag; - this->flagValue = flagValue; - this->makeInactive = true; - } - - void setMakeInactive(bool makeInactive) { - this->makeInactive = makeInactive; - } - - void process(Candidate *candidate) const { - double d = (candidate->current.getPosition() - center).mag(); - if (d <= radius * 1.01) { - candidate->setProperty("Detected", ""); - if (makeInactive) - candidate->setActive(false); - } - candidate->limitNextStep((d - radius)); - } - - std::string getDescription() const { - std::stringstream s; - s << "Small observer sphere: " << radius << " radius around " << center; - return s.str(); - } + "Detected", std::string flagValue = ""); + void setMakeInactive(bool makeInactive); + void process(Candidate *candidate) const; }; /** @@ -114,48 +64,13 @@ class CubicBoundary: public Module { std::string flagValue; bool makeInactive; bool limitStep; - + void updateDescription(); public: CubicBoundary(Vector3 origin, double size, std::string flag = "OutOfBounds", - std::string flagValue = "") { - this->origin = origin; - this->size = size; - this->flag = flag; - this->flagValue = flagValue; - this->makeInactive = false; - this->limitStep = false; - this->margin = 0; - } - - void setMakeInactive(bool makeInactive) { - this->makeInactive = makeInactive; - } - - void setLimitStep(bool limitStep, double margin) { - this->limitStep = limitStep; - this->margin = margin; - } - - void process(Candidate *candidate) const { - Vector3 relPos = candidate->current.getPosition() - origin; - double lo = std::min(relPos.x(), std::min(relPos.y(), relPos.z())); - double hi = std::max(relPos.x(), std::max(relPos.y(), relPos.z())); - if ((lo <= 0.) or (hi >= size)) { - candidate->setProperty(flag, flagValue); - if (makeInactive) - candidate->setActive(false); - } - if (limitStep) { - candidate->limitNextStep(lo + margin); - candidate->limitNextStep(size - hi + margin); - } - } - - std::string getDescription() const { - std::stringstream s; - s << "Cubic Boundary: origin " << origin << ", size " << size; - return s.str(); - } + std::string flagValue = ""); + void setMakeInactive(bool makeInactive); + void setLimitStep(bool limitStep, double margin); + void process(Candidate *candidate) const; }; /** @@ -163,6 +78,7 @@ class CubicBoundary: public Module { @brief Flag a particle when leaving the sphere. */ class SphericalBoundary: public Module { + protected: Vector3 center; double radius; @@ -171,44 +87,13 @@ class SphericalBoundary: public Module { std::string flagValue; bool makeInactive; bool limitStep; - + void updateDescription(); public: SphericalBoundary(Vector3 center, double radius, std::string flag = - "OutOfBounds", std::string flagValue = "") { - this->center = center; - this->radius = radius; - this->flag = flag; - this->flagValue = flagValue; - this->makeInactive = false; - this->limitStep = false; - this->margin = 0; - } - - void setMakeInactive(bool makeInactive) { - this->makeInactive = makeInactive; - } - - void setLimitStep(bool limitStep, double margin) { - this->limitStep = limitStep; - this->margin = margin; - } - - void process(Candidate *candidate) const { - double d = (candidate->current.getPosition() - center).mag(); - if (d >= radius) { - candidate->setProperty(flag, flagValue); - if (makeInactive) - candidate->setActive(false); - } - if (limitStep) - candidate->limitNextStep(radius - d + margin); - } - - std::string getDescription() const { - std::stringstream s; - s << "Spherical Boundary: radius " << radius << " around " << center; - return s.str(); - } + "OutOfBounds", std::string flagValue = ""); + void setMakeInactive(bool makeInactive); + void setLimitStep(bool limitStep, double margin); + void process(Candidate *candidate) const; }; /** @@ -225,48 +110,14 @@ class EllipsoidalBoundary: public Module { std::string flagValue; bool makeInactive; bool limitStep; - + void updateDescription(); public: EllipsoidalBoundary(Vector3 focalPoint1, Vector3 focalPoint2, double majorAxis, std::string flag = "OutOfBounds", - std::string flagValue = "") { - this->focalPoint1 = focalPoint1; - this->focalPoint2 = focalPoint2; - this->majorAxis = majorAxis; - this->flag = flag; - this->flagValue = flagValue; - this->makeInactive = false; - this->limitStep = false; - this->margin = 0; - } - - void setMakeInactive(bool makeInactive) { - this->makeInactive = makeInactive; - } - - void setLimitStep(bool limitStep, double margin) { - this->limitStep = limitStep; - this->margin = margin; - } - - void process(Candidate *candidate) const { - Vector3 pos = candidate->current.getPosition(); - double d = (pos - focalPoint1).mag() + (pos - focalPoint2).mag(); - if (d >= majorAxis) { - candidate->setProperty(flag, flagValue); - if (makeInactive) - candidate->setActive(false); - } - if (limitStep) - candidate->limitNextStep(majorAxis - d + margin); - } - - std::string getDescription() const { - std::stringstream s; - s << "Ellipsoidal Boundary: F1 = " << focalPoint1 << ", F2 = " - << focalPoint2 << ", major axis = " << majorAxis; - return s.str(); - } + std::string flagValue = ""); + void setMakeInactive(bool makeInactive); + void setLimitStep(bool limitStep, double margin); + void process(Candidate *candidate) const; }; } // namespace mpc diff --git a/src/Module.cpp b/src/Module.cpp index 66e3bcd2d..09657263c 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -4,9 +4,17 @@ namespace mpc { -std::string Module::getDescription() const { +Module::Module() { const std::type_info &info = typeid(*this); - return info.name(); + setDescription(info.name()); +} + +std::string Module::getDescription() const { + return description; +} + +void Module::setDescription(const std::string &description) { + this->description = description; } } diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp new file mode 100644 index 000000000..f255a7c3f --- /dev/null +++ b/src/module/BreakCondition.cpp @@ -0,0 +1,206 @@ +#include "mpc/module/BreakCondition.h" + +namespace mpc { + +MaximumTrajectoryLength::MaximumTrajectoryLength(double length) : + maxLength(length) { + std::stringstream s; + s << "Maximum trajectory length: " << maxLength / Mpc << " Mpc"; + setDescription(s.str()); +} + +void MaximumTrajectoryLength::process(Candidate *candidate) const { + double l = candidate->getTrajectoryLength(); + if (l >= maxLength) { + candidate->setActive(false); + candidate->setProperty("Deactivated", getDescription()); + } else + candidate->limitNextStep(maxLength - l); +} + +MinimumEnergy::MinimumEnergy(double minEnergy) : + minEnergy(minEnergy) { + std::stringstream s; + s << "Minimum energy: " << minEnergy / EeV << " EeV"; + setDescription(s.str()); +} + +void MinimumEnergy::process(Candidate *candidate) const { + if (candidate->current.getEnergy() <= minEnergy) { + candidate->setActive(false); + candidate->setProperty("Deactivated", getDescription()); + } +} + +SmallObserverSphere::SmallObserverSphere(Vector3 center, double radius, + std::string flag, std::string flagValue) { + this->center = center; + this->radius = radius; + this->flag = flag; + this->flagValue = flagValue; + this->makeInactive = true; + updateDescription(); +} + +void SmallObserverSphere::setMakeInactive(bool makeInactive) { + this->makeInactive = makeInactive; + updateDescription(); +} + +void SmallObserverSphere::process(Candidate *candidate) const { + double d = (candidate->current.getPosition() - center).mag(); + if (d <= radius * 1.01) { + candidate->setProperty("Detected", ""); + if (makeInactive) { + candidate->setActive(false); + candidate->setProperty("Deactivated", getDescription()); + } + } + candidate->limitNextStep((d - radius)); +} + +void SmallObserverSphere::updateDescription() { + std::stringstream s; + s << "Small observer sphere: " << radius << " radius around " << center; + s << " Flag: " << flag << " -> " << flagValue; + setDescription(s.str()); +} + +CubicBoundary::CubicBoundary(Vector3 origin, double size, std::string flag, + std::string flagValue) { + this->origin = origin; + this->size = size; + this->flag = flag; + this->flagValue = flagValue; + this->makeInactive = false; + this->limitStep = false; + this->margin = 0; + updateDescription(); +} + +void CubicBoundary::setMakeInactive(bool makeInactive) { + this->makeInactive = makeInactive; + updateDescription(); +} + +void CubicBoundary::setLimitStep(bool limitStep, double margin) { + this->limitStep = limitStep; + this->margin = margin; + updateDescription(); +} + +void CubicBoundary::process(Candidate *candidate) const { + Vector3 relPos = candidate->current.getPosition() - origin; + double lo = std::min(relPos.x(), std::min(relPos.y(), relPos.z())); + double hi = std::max(relPos.x(), std::max(relPos.y(), relPos.z())); + if ((lo <= 0.) or (hi >= size)) { + candidate->setProperty(flag, flagValue); + if (makeInactive) { + candidate->setActive(false); + candidate->setProperty("Deactivated", getDescription()); + } + } + if (limitStep) { + candidate->limitNextStep(lo + margin); + candidate->limitNextStep(size - hi + margin); + } +} + +void CubicBoundary::updateDescription() { + std::stringstream s; + s << "Cubic Boundary: origin " << origin << ", size " << size; + s << " Flag: " << flag << " -> " << flagValue; + setDescription(s.str()); +} + +SphericalBoundary::SphericalBoundary(Vector3 center, double radius, + std::string flag, std::string flagValue) { + this->center = center; + this->radius = radius; + this->flag = flag; + this->flagValue = flagValue; + this->makeInactive = false; + this->limitStep = false; + this->margin = 0; + updateDescription(); +} + +void SphericalBoundary::setMakeInactive(bool makeInactive) { + this->makeInactive = makeInactive; + updateDescription(); +} + +void SphericalBoundary::setLimitStep(bool limitStep, double margin) { + this->limitStep = limitStep; + this->margin = margin; + updateDescription(); +} + +void SphericalBoundary::process(Candidate *candidate) const { + double d = (candidate->current.getPosition() - center).mag(); + if (d >= radius) { + candidate->setProperty(flag, flagValue); + if (makeInactive) { + candidate->setActive(false); + candidate->setProperty("Deactivated", getDescription()); + } + } + if (limitStep) + candidate->limitNextStep(radius - d + margin); +} + +void SphericalBoundary::updateDescription() { + std::stringstream s; + s << "Spherical Boundary: radius " << radius << " around " << center; + s << " Flag: " << flag << " -> " << flagValue; + setDescription(s.str()); +} + +EllipsoidalBoundary::EllipsoidalBoundary(Vector3 focalPoint1, + Vector3 focalPoint2, double majorAxis, std::string flag, + std::string flagValue) { + this->focalPoint1 = focalPoint1; + this->focalPoint2 = focalPoint2; + this->majorAxis = majorAxis; + this->flag = flag; + this->flagValue = flagValue; + this->makeInactive = false; + this->limitStep = false; + this->margin = 0; + updateDescription(); +} + +void EllipsoidalBoundary::setMakeInactive(bool makeInactive) { + this->makeInactive = makeInactive; + updateDescription(); +} + +void EllipsoidalBoundary::setLimitStep(bool limitStep, double margin) { + this->limitStep = limitStep; + this->margin = margin; + updateDescription(); +} + +void EllipsoidalBoundary::process(Candidate *candidate) const { + Vector3 pos = candidate->current.getPosition(); + double d = (pos - focalPoint1).mag() + (pos - focalPoint2).mag(); + if (d >= majorAxis) { + candidate->setProperty(flag, flagValue); + if (makeInactive) { + candidate->setActive(false); + candidate->setProperty("Deactivated", getDescription()); + } + } + if (limitStep) + candidate->limitNextStep(majorAxis - d + margin); +} + +void EllipsoidalBoundary::updateDescription() { + std::stringstream s; + s << "Ellipsoidal Boundary: F1 = " << focalPoint1 / Mpc << ", F2 = " + << focalPoint2 / Mpc << ", major axis = " << majorAxis / Mpc; + s << " Flag: " << flag << " -> " << flagValue; + setDescription(s.str()); +} + +} // namespace mpc From bec227be1aae58212ad33ad0b0259a2243f89bd3 Mon Sep 17 00:00:00 2001 From: geromueller Date: Thu, 29 Mar 2012 17:52:10 +0200 Subject: [PATCH 0035/1298] add PropertyStatistics module --- include/mpc/module/Tools.h | 11 +++++++++++ src/module/Tools.cpp | 31 ++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/include/mpc/module/Tools.h b/include/mpc/module/Tools.h index e890821d4..997b0f8e6 100644 --- a/include/mpc/module/Tools.h +++ b/include/mpc/module/Tools.h @@ -23,6 +23,17 @@ class PerformanceModule: public Module { std::string getDescription() const; }; +class PropertyStatistics: public Module { +private: + mutable std::map properties; + std::string key; + +public: + PropertyStatistics(const std::string &key); + ~PropertyStatistics(); + void process(Candidate *candidate) const; +}; + } // namespace mpc #endif /* MPC_MODULE_TOOLS_H_ */ diff --git a/src/module/Tools.cpp b/src/module/Tools.cpp index 1c696d548..3ce988e12 100644 --- a/src/module/Tools.cpp +++ b/src/module/Tools.cpp @@ -21,7 +21,8 @@ PerformanceModule::~PerformanceModule() { cout << "Performance for " << calls << " calls:" << endl; for (size_t i = 0; i < modules.size(); i++) { _module_info &m = modules[i]; - cout << " - " << floor((1000 * m.time / total) + 0.5) / 10 << "% -> " << m.module->getDescription() << ": " << (m.time / calls) + cout << " - " << floor((1000 * m.time / total) + 0.5) / 10 << "% -> " + << m.module->getDescription() << ": " << (m.time / calls) << endl; } } @@ -66,4 +67,32 @@ string PerformanceModule::getDescription() const { return sstr.str(); } +PropertyStatistics::PropertyStatistics(const std::string &key) : + key(key) { + setDescription("PropertyStatistics: " + key); +} + +PropertyStatistics::~PropertyStatistics() { + std::cout << "Property Statistics for " << key << ":" << std::endl; + std::map::iterator i; + for (i = properties.begin(); i != properties.end(); i++) { + std::cout << i->first << "\t\t-> " << i->second << std::endl; + } +} + +void PropertyStatistics::process(Candidate *candidate) const { +#pragma omp critical + { + std::string property; + if (candidate->getProperty(key, property)) { + std::map::iterator i = properties.find( + property); + if (i == properties.end()) { + properties[property] = 1; + } else { + i->second++; + } + } + } +} } // namespace mpc From 547acf51e5681ec218af37860c85fcc96aaa94bf Mon Sep 17 00:00:00 2001 From: geromueller Date: Fri, 30 Mar 2012 10:05:27 +0200 Subject: [PATCH 0036/1298] add remveProperty flag to cond. output --- include/mpc/module/Output.h | 3 ++- src/module/Output.cpp | 12 +++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/mpc/module/Output.h b/include/mpc/module/Output.h index da696cbd6..fa4aa5140 100644 --- a/include/mpc/module/Output.h +++ b/include/mpc/module/Output.h @@ -29,10 +29,11 @@ class ConditionalOutput: public Module { private: mutable std::ofstream outfile; std::string propertyName; - + bool removeProperty; public: ConditionalOutput(std::string filename, std::string propName); ~ConditionalOutput(); + void setRemoveProperty(bool removeProperty); void process(Candidate *candidate) const; std::string getDescription() const; }; diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 61942b3f1..728f14297 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -37,8 +37,8 @@ std::string TrajectoryOutput::getDescription() const { return "Trajectory output"; } -ConditionalOutput::ConditionalOutput(std::string filename, - std::string propName) { +ConditionalOutput::ConditionalOutput(std::string filename, std::string propName) : + removeProperty(false) { propertyName = propName; outfile.open(filename.c_str()); outfile @@ -50,6 +50,10 @@ ConditionalOutput::~ConditionalOutput() { outfile.close(); } +void ConditionalOutput::setRemoveProperty(bool removeProperty) { + this->removeProperty = removeProperty; +} + void ConditionalOutput::process(Candidate *candidate) const { if (candidate->hasProperty(propertyName)) { #pragma omp critical @@ -72,7 +76,9 @@ void ConditionalOutput::process(Candidate *candidate) const { outfile << std::endl; } } - candidate->removeProperty(propertyName); + if (removeProperty) { + candidate->removeProperty(propertyName); + } } std::string ConditionalOutput::getDescription() const { From 5ba87f736bd36b6a035349f06423b962e87e6875 Mon Sep 17 00:00:00 2001 From: geromueller Date: Fri, 30 Mar 2012 11:43:07 +0200 Subject: [PATCH 0037/1298] add Loki AssocVector to improve performance --- include/mpc/AssocVector.h | 381 ++++++++++++++++++++++++++++++++++++++ include/mpc/Candidate.h | 15 +- src/Candidate.cpp | 16 +- 3 files changed, 398 insertions(+), 14 deletions(-) create mode 100644 include/mpc/AssocVector.h diff --git a/include/mpc/AssocVector.h b/include/mpc/AssocVector.h new file mode 100644 index 000000000..707a56bd5 --- /dev/null +++ b/include/mpc/AssocVector.h @@ -0,0 +1,381 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_ASSOCVECTOR_INC_ +#define LOKI_ASSOCVECTOR_INC_ + +// $Id$ + + +#include +#include +#include +#include +#include +#include + + +namespace Loki +{ +//////////////////////////////////////////////////////////////////////////////// +// class template AssocVectorCompare +// Used by AssocVector +//////////////////////////////////////////////////////////////////////////////// + + namespace Private + { + template + class AssocVectorCompare : public C + { + typedef std::pair + Data; + typedef typename C::first_argument_type first_argument_type; + + public: + AssocVectorCompare() + {} + + AssocVectorCompare(const C& src) : C(src) + {} + + bool operator()(const first_argument_type& lhs, + const first_argument_type& rhs) const + { return C::operator()(lhs, rhs); } + + bool operator()(const Data& lhs, const Data& rhs) const + { return operator()(lhs.first, rhs.first); } + + bool operator()(const Data& lhs, + const first_argument_type& rhs) const + { return operator()(lhs.first, rhs); } + + bool operator()(const first_argument_type& lhs, + const Data& rhs) const + { return operator()(lhs, rhs.first); } + }; + } + +//////////////////////////////////////////////////////////////////////////////// +// class template AssocVector +// An associative vector built as a syntactic drop-in replacement for std::map +// BEWARE: AssocVector doesn't respect all map's guarantees, the most important +// being: +// * iterators are invalidated by insert and erase operations +// * the complexity of insert/erase is O(N) not O(log N) +// * value_type is std::pair not std::pair +// * iterators are random +//////////////////////////////////////////////////////////////////////////////// + + + template + < + class K, + class V, + class C = std::less, + class A = std::allocator< std::pair > + > + class AssocVector + : private std::vector< std::pair, A > + , private Private::AssocVectorCompare + { + typedef std::vector, A> Base; + typedef Private::AssocVectorCompare MyCompare; + + public: + typedef K key_type; + typedef V mapped_type; + typedef typename Base::value_type value_type; + + typedef C key_compare; + typedef A allocator_type; + typedef typename A::reference reference; + typedef typename A::const_reference const_reference; + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + typedef typename Base::size_type size_type; + typedef typename Base::difference_type difference_type; + typedef typename A::pointer pointer; + typedef typename A::const_pointer const_pointer; + typedef typename Base::reverse_iterator reverse_iterator; + typedef typename Base::const_reverse_iterator const_reverse_iterator; + + class value_compare + : public std::binary_function + , private key_compare + { + friend class AssocVector; + + protected: + value_compare(key_compare pred) : key_compare(pred) + {} + + public: + bool operator()(const value_type& lhs, const value_type& rhs) const + { return key_compare::operator()(lhs.first, rhs.first); } + }; + + // 23.3.1.1 construct/copy/destroy + + explicit AssocVector(const key_compare& comp = key_compare(), + const A& alloc = A()) + : Base(alloc), MyCompare(comp) + {} + + template + AssocVector(InputIterator first, InputIterator last, + const key_compare& comp = key_compare(), + const A& alloc = A()) + : Base( alloc ), MyCompare( comp ) + { + typedef ::std::vector< ::std::pair< K, V >, A > BaseType; + typedef ::std::map< K, V, C, A > TempMap; + typedef ::std::back_insert_iterator< Base > MyInserter; + MyCompare & me = *this; + const A tempAlloc; + // Make a temporary map similar to this type to prevent any duplicate elements. + TempMap temp( first, last, me, tempAlloc ); + Base::reserve( temp.size() ); + BaseType & target = static_cast< BaseType & >( *this ); + MyInserter myInserter = ::std::back_inserter( target ); + ::std::copy( temp.begin(), temp.end(), myInserter ); + } + + AssocVector& operator=(const AssocVector& rhs) + { + AssocVector(rhs).swap(*this); + return *this; + } + + // iterators: + // The following are here because MWCW gets 'using' wrong + iterator begin() { return Base::begin(); } + const_iterator begin() const { return Base::begin(); } + iterator end() { return Base::end(); } + const_iterator end() const { return Base::end(); } + reverse_iterator rbegin() { return Base::rbegin(); } + const_reverse_iterator rbegin() const { return Base::rbegin(); } + reverse_iterator rend() { return Base::rend(); } + const_reverse_iterator rend() const { return Base::rend(); } + + // capacity: + bool empty() const { return Base::empty(); } + size_type size() const { return Base::size(); } + size_type max_size() { return Base::max_size(); } + + // 23.3.1.2 element access: + mapped_type& operator[](const key_type& key) + { return insert(value_type(key, mapped_type())).first->second; } + + // modifiers: + std::pair insert(const value_type& val) + { + bool found(true); + iterator i(lower_bound(val.first)); + + if (i == end() || this->operator()(val.first, i->first)) + { + i = Base::insert(i, val); + found = false; + } + return std::make_pair(i, !found); + } + //Section [23.1.2], Table 69 + //http://developer.apple.com/documentation/DeveloperTools/gcc-3.3/libstdc++/23_containers/howto.html#4 + iterator insert(iterator pos, const value_type& val) + { + if( (pos == begin() || this->operator()(*(pos-1),val)) && + (pos == end() || this->operator()(val, *pos)) ) + { + return Base::insert(pos, val); + } + return insert(val).first; + } + + template + void insert(InputIterator first, InputIterator last) + { for (; first != last; ++first) insert(*first); } + + void erase(iterator pos) + { Base::erase(pos); } + + size_type erase(const key_type& k) + { + iterator i(find(k)); + if (i == end()) return 0; + erase(i); + return 1; + } + + void erase(iterator first, iterator last) + { Base::erase(first, last); } + + void swap(AssocVector& other) + { + Base::swap(other); + MyCompare& me = *this; + MyCompare& rhs = other; + std::swap(me, rhs); + } + + void clear() + { Base::clear(); } + + // observers: + key_compare key_comp() const + { return *this; } + + value_compare value_comp() const + { + const key_compare& comp = *this; + return value_compare(comp); + } + + // 23.3.1.3 map operations: + iterator find(const key_type& k) + { + iterator i(lower_bound(k)); + if (i != end() && this->operator()(k, i->first)) + { + i = end(); + } + return i; + } + + const_iterator find(const key_type& k) const + { + const_iterator i(lower_bound(k)); + if (i != end() && this->operator()(k, i->first)) + { + i = end(); + } + return i; + } + + size_type count(const key_type& k) const + { return find(k) != end(); } + + iterator lower_bound(const key_type& k) + { + MyCompare& me = *this; + return std::lower_bound(begin(), end(), k, me); + } + + const_iterator lower_bound(const key_type& k) const + { + const MyCompare& me = *this; + return std::lower_bound(begin(), end(), k, me); + } + + iterator upper_bound(const key_type& k) + { + MyCompare& me = *this; + return std::upper_bound(begin(), end(), k, me); + } + + const_iterator upper_bound(const key_type& k) const + { + const MyCompare& me = *this; + return std::upper_bound(begin(), end(), k, me); + } + + std::pair equal_range(const key_type& k) + { + MyCompare& me = *this; + return std::equal_range(begin(), end(), k, me); + } + + std::pair equal_range( + const key_type& k) const + { + const MyCompare& me = *this; + return std::equal_range(begin(), end(), k, me); + } + + template + friend bool operator==(const AssocVector& lhs, + const AssocVector& rhs); + + bool operator<(const AssocVector& rhs) const + { + const Base& me = *this; + const Base& yo = rhs; + return me < yo; + } + + template + friend bool operator!=(const AssocVector& lhs, + const AssocVector& rhs); + + template + friend bool operator>(const AssocVector& lhs, + const AssocVector& rhs); + + template + friend bool operator>=(const AssocVector& lhs, + const AssocVector& rhs); + + template + friend bool operator<=(const AssocVector& lhs, + const AssocVector& rhs); + }; + + template + inline bool operator==(const AssocVector& lhs, + const AssocVector& rhs) + { + const std::vector, A>& me = lhs; + return me == rhs; + } + + template + inline bool operator!=(const AssocVector& lhs, + const AssocVector& rhs) + { return !(lhs == rhs); } + + template + inline bool operator>(const AssocVector& lhs, + const AssocVector& rhs) + { return rhs < lhs; } + + template + inline bool operator>=(const AssocVector& lhs, + const AssocVector& rhs) + { return !(lhs < rhs); } + + template + inline bool operator<=(const AssocVector& lhs, + const AssocVector& rhs) + { return !(rhs < lhs); } + + + // specialized algorithms: + template + void swap(AssocVector& lhs, AssocVector& rhs) + { lhs.swap(rhs); } + +} // namespace Loki + +#endif // end file guardian + diff --git a/include/mpc/Candidate.h b/include/mpc/Candidate.h index db6aceaeb..596f5111c 100644 --- a/include/mpc/Candidate.h +++ b/include/mpc/Candidate.h @@ -3,6 +3,7 @@ #include "mpc/ParticleState.h" #include "mpc/Referenced.h" +#include "mpc/AssocVector.h" #include #include @@ -37,17 +38,23 @@ class Candidate: public Referenced { ParticleState initial; std::vector > secondaries; + typedef Loki::AssocVector PropertyMap; + typedef Loki::AssocVector InteractionStatesMap; + private: bool active; double redshift, trajectoryLength; double currentStep, nextStep; - std::map properties; - std::map interactionStates; + + PropertyMap properties; + InteractionStatesMap interactionStates; public: Candidate(); Candidate(const ParticleState &state); - virtual ~Candidate() {}; + virtual ~Candidate() { + } + ; bool isActive() const; void setActive(bool b); @@ -74,7 +81,7 @@ class Candidate: public Referenced { InteractionState &state) const; void setInteractionState(const std::string &moduleName, const InteractionState &state); - const std::map getInteractionStates() const; + const InteractionStatesMap getInteractionStates() const; void clearInteractionStates(); void addSecondary(int id, double energy); diff --git a/src/Candidate.cpp b/src/Candidate.cpp index f34214fd4..3299d002d 100644 --- a/src/Candidate.cpp +++ b/src/Candidate.cpp @@ -59,8 +59,7 @@ void Candidate::limitNextStep(double step) { bool Candidate::getInteractionState(const std::string &moduleName, InteractionState &state) const { - std::map::const_iterator i = - interactionStates.find(moduleName); + InteractionStatesMap::const_iterator i = interactionStates.find(moduleName); if (i == interactionStates.end()) return false; state = i->second; @@ -72,7 +71,7 @@ void Candidate::setInteractionState(const std::string &moduleName, interactionStates[moduleName] = state; } -const std::map Candidate::getInteractionStates() const { +const Candidate::InteractionStatesMap Candidate::getInteractionStates() const { return interactionStates; } @@ -85,17 +84,15 @@ void Candidate::setProperty(const std::string &name, const std::string &value) { } bool Candidate::removeProperty(const std::string& name) { - std::map::iterator i = properties.find( - name); + PropertyMap::iterator i = properties.find(name); if (i == properties.end()) - return false; + return false; properties.erase(i); return true; } bool Candidate::getProperty(const std::string &name, std::string &value) const { - std::map::const_iterator i = properties.find( - name); + PropertyMap::const_iterator i = properties.find(name); if (i == properties.end()) return false; value = i->second; @@ -103,8 +100,7 @@ bool Candidate::getProperty(const std::string &name, std::string &value) const { } bool Candidate::hasProperty(const std::string &name) const { - std::map::const_iterator i = properties.find( - name); + PropertyMap::const_iterator i = properties.find(name); if (i == properties.end()) return false; return true; From 014c103f52db1091f040928e0a41ad342a289368 Mon Sep 17 00:00:00 2001 From: geromueller Date: Fri, 30 Mar 2012 11:48:23 +0200 Subject: [PATCH 0038/1298] use AssocVector in PropertyStatistics --- include/mpc/module/Tools.h | 3 ++- src/module/Tools.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/mpc/module/Tools.h b/include/mpc/module/Tools.h index 997b0f8e6..5f5ab84e0 100644 --- a/include/mpc/module/Tools.h +++ b/include/mpc/module/Tools.h @@ -2,6 +2,7 @@ #define MPC_MODULE_TOOLS_H_ #include "mpc/Module.h" +#include "mpc/AssocVector.h" namespace mpc { @@ -25,7 +26,7 @@ class PerformanceModule: public Module { class PropertyStatistics: public Module { private: - mutable std::map properties; + mutable Loki::AssocVector properties; std::string key; public: diff --git a/src/module/Tools.cpp b/src/module/Tools.cpp index 3ce988e12..7f33d0315 100644 --- a/src/module/Tools.cpp +++ b/src/module/Tools.cpp @@ -74,7 +74,7 @@ PropertyStatistics::PropertyStatistics(const std::string &key) : PropertyStatistics::~PropertyStatistics() { std::cout << "Property Statistics for " << key << ":" << std::endl; - std::map::iterator i; + Loki::AssocVector::iterator i; for (i = properties.begin(); i != properties.end(); i++) { std::cout << i->first << "\t\t-> " << i->second << std::endl; } @@ -85,7 +85,7 @@ void PropertyStatistics::process(Candidate *candidate) const { { std::string property; if (candidate->getProperty(key, property)) { - std::map::iterator i = properties.find( + Loki::AssocVector::iterator i = properties.find( property); if (i == properties.end()) { properties[property] = 1; From 686c5b655d27b9b521fc0ad8b66cee5cd0f01fb9 Mon Sep 17 00:00:00 2001 From: geromueller Date: Fri, 30 Mar 2012 12:18:45 +0200 Subject: [PATCH 0039/1298] use sprintf for better performance --- src/module/Output.cpp | 69 +++++++++++++++++++++++++------------------ src/module/Tools.cpp | 11 +++---- 2 files changed, 46 insertions(+), 34 deletions(-) diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 728f14297..4ed824256 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -4,6 +4,8 @@ #include #include #include +#include + #include namespace mpc { @@ -18,18 +20,19 @@ TrajectoryOutput::~TrajectoryOutput() { } void TrajectoryOutput::process(Candidate *candidate) const { + char buffer[128]; + size_t pos = 0; + pos += ::sprintf(buffer + pos, "%f, %d", + candidate->getTrajectoryLength() / Mpc, candidate->current.getId()); + Vector3 position = candidate->current.getPosition() / Mpc; + pos += ::sprintf(buffer + pos, ", %f, %f, %f", position.x(), position.y(), + position.z()); + const Vector3 &dir = candidate->current.getDirection(); + pos += ::sprintf(buffer + pos, ", %f, %f, %f\n", dir.x(), dir.y(), dir.z()); + #pragma omp critical { - outfile << candidate->getTrajectoryLength() / Mpc << ", "; - outfile << candidate->current.getId() << ", "; - outfile << candidate->current.getEnergy() / EeV << ", "; - outfile << candidate->current.getPosition().x() / Mpc << ", "; - outfile << candidate->current.getPosition().y() / Mpc << ", "; - outfile << candidate->current.getPosition().z() / Mpc << ", "; - outfile << candidate->current.getDirection().x() << ", "; - outfile << candidate->current.getDirection().y() << ", "; - outfile << candidate->current.getDirection().y() << ", "; - outfile << std::endl; + outfile.write(buffer, pos); } } @@ -56,28 +59,36 @@ void ConditionalOutput::setRemoveProperty(bool removeProperty) { void ConditionalOutput::process(Candidate *candidate) const { if (candidate->hasProperty(propertyName)) { + char buffer[256]; + size_t pos = 0; + + pos += ::sprintf(buffer + pos, "%d", candidate->current.getId()); + Vector3 position = candidate->current.getPosition() / Mpc; + pos += ::sprintf(buffer + pos, ", %f, %f, %f", position.x(), + position.y(), position.z()); + const Vector3 &dir = candidate->current.getDirection(); + pos += ::sprintf(buffer + pos, ", %f, %f, %f", + candidate->current.getEnergy(), dir.phi(), dir.theta()); + + pos += ::sprintf(buffer + pos, ", %f", + candidate->getTrajectoryLength()); + + pos += ::sprintf(buffer + pos, ", %d", candidate->initial.getId()); + Vector3 ipos = candidate->initial.getPosition() / Mpc; + pos += ::sprintf(buffer + pos, ", %f, %f, %f", ipos.x(), ipos.y(), + ipos.z()); + const Vector3 &idir = candidate->initial.getDirection(); + pos += ::sprintf(buffer + pos, ", %f, %f, %f\n", + candidate->initial.getEnergy(), idir.phi(), idir.theta()); + #pragma omp critical { - outfile << candidate->current.getId() << ", "; - outfile << candidate->current.getPosition().x() / Mpc << ", "; - outfile << candidate->current.getPosition().y() / Mpc << ", "; - outfile << candidate->current.getPosition().z() / Mpc << ", "; - outfile << candidate->current.getEnergy() / EeV << ", "; - outfile << candidate->current.getDirection().phi() << ", "; - outfile << candidate->current.getDirection().theta() << ", "; - outfile << candidate->getTrajectoryLength() / Mpc << ", "; - outfile << candidate->initial.getId() << ", "; - outfile << candidate->initial.getPosition().x() / Mpc << ", "; - outfile << candidate->initial.getPosition().y() / Mpc << ", "; - outfile << candidate->initial.getPosition().z() / Mpc << ", "; - outfile << candidate->initial.getEnergy() / EeV << ", "; - outfile << candidate->initial.getDirection().phi() << ", "; - outfile << candidate->initial.getDirection().theta(); - outfile << std::endl; + outfile.write(buffer, pos); + } + + if (removeProperty) { + candidate->removeProperty(propertyName); } - } - if (removeProperty) { - candidate->removeProperty(propertyName); } } diff --git a/src/module/Tools.cpp b/src/module/Tools.cpp index 7f33d0315..98d7468c9 100644 --- a/src/module/Tools.cpp +++ b/src/module/Tools.cpp @@ -81,12 +81,12 @@ PropertyStatistics::~PropertyStatistics() { } void PropertyStatistics::process(Candidate *candidate) const { + std::string property; + if (candidate->getProperty(key, property)) { #pragma omp critical - { - std::string property; - if (candidate->getProperty(key, property)) { - Loki::AssocVector::iterator i = properties.find( - property); + { + Loki::AssocVector::iterator i = + properties.find(property); if (i == properties.end()) { properties[property] = 1; } else { @@ -95,4 +95,5 @@ void PropertyStatistics::process(Candidate *candidate) const { } } } + } // namespace mpc From abdaa0aba3662deb2d794a576b529660a45bdab1 Mon Sep 17 00:00:00 2001 From: geromueller Date: Fri, 30 Mar 2012 12:30:03 +0200 Subject: [PATCH 0040/1298] improve description of Small observer sphere --- src/module/BreakCondition.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp index f255a7c3f..0c28aac78 100644 --- a/src/module/BreakCondition.cpp +++ b/src/module/BreakCondition.cpp @@ -61,8 +61,9 @@ void SmallObserverSphere::process(Candidate *candidate) const { void SmallObserverSphere::updateDescription() { std::stringstream s; - s << "Small observer sphere: " << radius << " radius around " << center; - s << " Flag: " << flag << " -> " << flagValue; + s << "Small observer sphere: " << radius / Mpc << " Mpc radius around " + << center / Mpc; + s << " Mpc, Flag: '" << flag << "' -> '" << flagValue << "'"; setDescription(s.str()); } From fbde30115b317b011528e9b056d1c2be90621061 Mon Sep 17 00:00:00 2001 From: geromueller Date: Fri, 30 Mar 2012 15:16:02 +0200 Subject: [PATCH 0041/1298] catch gadget exception and set b field to zero. fix output units. --- src/module/DeflectionCK.cpp | 13 +++++++++++-- src/module/Output.cpp | 11 ++++++----- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index 606a7b144..9f0ebf576 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -23,7 +23,14 @@ class LorentzForce: public ExplicitRungeKutta::F { PhasePoint operator()(double t, const PhasePoint &v) { Vector3 velocity = v.b.unit() * c_light; - Vector3 B = field->getField(v.a); + Vector3 B(0, 0, 0); + try { + B = field->getField(v.a); + } catch (std::exception &e) { + std::cerr << "mpc::LorentzForce: Exception in getField." + << std::endl; + std::cerr << e.what() << std::endl; + } Vector3 force = (double) particle->getChargeNumber() * eplus * velocity.cross(B); return PhasePoint(velocity, force); @@ -41,7 +48,9 @@ DeflectionCK::DeflectionCK(MagneticField *field, double tolerance, std::string DeflectionCK::getDescription() const { std::stringstream sstr; - sstr << "Propagation in magnetic fields using the Cash-Karp method. Tolerance: " << tolerance << ", Minimum Step: " << minimumStep / kpc << " kpc"; + sstr + << "Propagation in magnetic fields using the Cash-Karp method. Tolerance: " + << tolerance << ", Minimum Step: " << minimumStep / kpc << " kpc"; return sstr.str(); } diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 4ed824256..7dc59fe0a 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -22,8 +22,9 @@ TrajectoryOutput::~TrajectoryOutput() { void TrajectoryOutput::process(Candidate *candidate) const { char buffer[128]; size_t pos = 0; - pos += ::sprintf(buffer + pos, "%f, %d", - candidate->getTrajectoryLength() / Mpc, candidate->current.getId()); + pos += ::sprintf(buffer + pos, "%f, %d, %f", + candidate->getTrajectoryLength() / Mpc, candidate->current.getId(), + candidate->current.getEnergy() / EeV); Vector3 position = candidate->current.getPosition() / Mpc; pos += ::sprintf(buffer + pos, ", %f, %f, %f", position.x(), position.y(), position.z()); @@ -68,10 +69,10 @@ void ConditionalOutput::process(Candidate *candidate) const { position.y(), position.z()); const Vector3 &dir = candidate->current.getDirection(); pos += ::sprintf(buffer + pos, ", %f, %f, %f", - candidate->current.getEnergy(), dir.phi(), dir.theta()); + candidate->current.getEnergy() / EeV, dir.phi(), dir.theta()); pos += ::sprintf(buffer + pos, ", %f", - candidate->getTrajectoryLength()); + candidate->getTrajectoryLength() / Mpc); pos += ::sprintf(buffer + pos, ", %d", candidate->initial.getId()); Vector3 ipos = candidate->initial.getPosition() / Mpc; @@ -79,7 +80,7 @@ void ConditionalOutput::process(Candidate *candidate) const { ipos.z()); const Vector3 &idir = candidate->initial.getDirection(); pos += ::sprintf(buffer + pos, ", %f, %f, %f\n", - candidate->initial.getEnergy(), idir.phi(), idir.theta()); + candidate->initial.getEnergy() / EeV, idir.phi(), idir.theta()); #pragma omp critical { From dd6cae759d81158b36e37066f9b96af493088eea Mon Sep 17 00:00:00 2001 From: geromueller Date: Fri, 30 Mar 2012 15:40:11 +0200 Subject: [PATCH 0042/1298] print number of threads in ModuleList --- src/ModuleList.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 1bef5ede0..4baad471a 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -1,5 +1,7 @@ #include "mpc/ModuleList.h" +#include + using namespace std; namespace mpc { @@ -46,6 +48,12 @@ void ModuleList::run(Source *source, size_t count, bool recursive) { size_t pc = 0; #pragma omp parallel for schedule(dynamic, 1000) for (size_t i = 0; i < count; i++) { +#if _OPENMP + if (i == 0) { + std::cout << "Number of Threads: " << omp_get_thread_num() + << std::endl; + } +#endif if (showProgress && (i % cent == 0)) { std::cout << pc << "% - " << i << std::endl; pc++; From 497a2864aed84d6e87e78e84bc99cfbf81ce08ae Mon Sep 17 00:00:00 2001 From: geromueller Date: Fri, 30 Mar 2012 16:22:38 +0200 Subject: [PATCH 0043/1298] fix list output --- src/ModuleList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 4baad471a..9d6dccaaf 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -50,7 +50,7 @@ void ModuleList::run(Source *source, size_t count, bool recursive) { for (size_t i = 0; i < count; i++) { #if _OPENMP if (i == 0) { - std::cout << "Number of Threads: " << omp_get_thread_num() + std::cout << "Number of Threads: " << omp_get_num_threads() << std::endl; } #endif From 9e286608b4c2746cb4d810e31e3afc422a58af6d Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sat, 7 Apr 2012 08:12:42 +0200 Subject: [PATCH 0044/1298] add another turbulent field test --- test/python/testTurbulentField.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/python/testTurbulentField.py b/test/python/testTurbulentField.py index c8de6d44c..c57f5e8d9 100644 --- a/test/python/testTurbulentField.py +++ b/test/python/testTurbulentField.py @@ -159,6 +159,7 @@ def retrieveField(field): field = TurbulentMagneticFieldGrid(Vector3(0, 0, 0), n, 1, 2, 16, 1, -11. / 3) Bx, By, Bz = retrieveField(field) + ### periodicity figure() subplot(111, aspect='equal') @@ -174,6 +175,29 @@ def retrieveField(field): ylabel(r'$y$ [gridpoints]') savefig('TurbulentField_periodicity.png', bbox_inches='tight') + +### slice in configuration space +Bkx = fftshift(fftn(Bx)) +Bky = fftshift(fftn(By)) +Bkz = fftshift(fftn(Bz)) +Bk = ((Bkx*Bkx.conjugate() + Bky*Bky.conjugate() + Bkz*Bkz.conjugate())**.2).real +del Bkx, Bky, Bkz +figure() +subplot(111, aspect='equal') +pc = pcolor(Bk[:,:,n/2]) +cbar = colorbar(pc) +cbar.set_label(r'$|\vec{B}(\vec{k})|$ [a.u.]') +xlabel(r'$\vec{k}_x$') +ylabel(r'$\vec{k}_y$') +k = fftshift(fftfreq(n)) +idx = arange(0,n,n/4) +xticks(idx, k[idx]) +yticks(idx, k[idx]) +xlim(0,n) +ylim(0,n) +savefig('TurbulentField_configurationSpace.png', bbox_inches='tight') + + ### correlation length + isotropy figure() corr = VectorFieldAutoCorrelation(Bx,By,Bz) @@ -199,12 +223,14 @@ def retrieveField(field): text(0.5, 0.95, s, ha='left', va='top', transform=gca().transAxes) savefig('TurbulentField_correlation.png', bbox_inches='tight') + ### energy spectrum esd = VectorFieldEnergySpectralDensity(Bx, By, Bz) figure() esd.plot() savefig('TurbulentField_spectrum.png', bbox_inches='tight') + ### field strength, mean and brms Bx.resize(n**3) By.resize(n**3) From e7a00037da4d7dfc9175918dca13cdde8b822f76 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sat, 7 Apr 2012 08:32:02 +0200 Subject: [PATCH 0045/1298] implement complex to real Fourier transform to reduce memory consumption when creating turbulent field --- CMakeLists.txt | 2 +- cmake/FindFFTW.cmake | 2 + .../turbulentMagneticFieldGrid.cpp | 84 ++++++++++--------- 3 files changed, 49 insertions(+), 39 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 66af52b58..f41afc2da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ list (APPEND MPC_EXTRA_LIBRARIES ${GSL_LIBRARIES} ${GSLCBLAS_LIBRARIES}) find_package(FFTW) if (FFTW_FOUND) list( APPEND MPC_EXTRA_SOURCES src/magneticField/turbulentMagneticFieldGrid.cpp) - list( APPEND MPC_EXTRA_LIBRARIES ${FFTW_LIBRARY}) + list( APPEND MPC_EXTRA_LIBRARIES ${FFTW_LIBRARY} ${FFTWF_LIBRARY}) endif (FFTW_FOUND) # gadget needed for SphMagneticField diff --git a/cmake/FindFFTW.cmake b/cmake/FindFFTW.cmake index d2ab87ae5..e622ea62b 100644 --- a/cmake/FindFFTW.cmake +++ b/cmake/FindFFTW.cmake @@ -1,9 +1,11 @@ # FFTW_INCLUDE_DIR = fftw3.h # FFTW_LIBRARY = libfftw3.a +# FFTWF_LIBRARY = libfftw3f.a # FFTW_FOUND = true if FFTW3 is found find_path(FFTW_INCLUDE_DIR fftw3.h) find_library(FFTW_LIBRARY fftw3) +find_library(FFTWF_LIBRARY fftw3f) set(FFTW_FOUND FALSE) if(FFTW_INCLUDE_DIR AND FFTW_LIBRARY) diff --git a/src/magneticField/turbulentMagneticFieldGrid.cpp b/src/magneticField/turbulentMagneticFieldGrid.cpp index 1a993d70b..85344dde7 100644 --- a/src/magneticField/turbulentMagneticFieldGrid.cpp +++ b/src/magneticField/turbulentMagneticFieldGrid.cpp @@ -21,46 +21,49 @@ void TurbulentMagneticFieldGrid::setSeed(int seed) { void TurbulentMagneticFieldGrid::initialize() { size_t n = samples; + size_t n2 = floor(n/2) + 1; // size of complex array - // arrays to hold the complex vector components of the B-field - fftw_complex *Bx, *By, *Bz; - Bx = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * n * n * n); - By = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * n * n * n); - Bz = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * n * n * n); + // arrays to hold the complex vector components of the B(k)-field + fftw_complex *Bkx, *Bky, *Bkz; + Bkx = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * n * n * n2); + Bky = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * n * n * n2); + Bkz = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * n * n * n2); - // N discrete possible wave numbers + // calculate the n possible discrete wave numbers double K[n]; for (int i = 0; i < n; i++) K[i] = (double) i / n - i / (n / 2); - // create field in configuration space + // construct the field in configuration space int i; double k, theta, phase, cosPhase, sinPhase; double kMin = spacing / lMax; double kMax = spacing / lMin; - Vector3 e1, e2, ek, b; + Vector3 b; // real b-field vector + Vector3 ek, e1, e2; // orthogonal base Vector3 n0(1, 1, 1); // arbitrary vector to construct orthogonal base for (size_t ix = 0; ix < n; ix++) { for (size_t iy = 0; iy < n; iy++) { - for (size_t iz = 0; iz < n; iz++) { + for (size_t iz = 0; iz < n2; iz++) { - i = ix * n * n + iy * n + iz; + i = ix * n * n2 + iy * n2 + iz; ek.set(K[ix], K[iy], K[iz]); k = ek.mag(); + // wave outside of turbulent range -> B(k) = 0 if ((k < kMin) || (k > kMax)) { - Bx[i][0] = 0; - Bx[i][1] = 0; - By[i][0] = 0; - By[i][1] = 0; - Bz[i][0] = 0; - Bz[i][1] = 0; - continue; // wave outside of turbulent range -> B(k) = 0 + Bkx[i][0] = 0; + Bkx[i][1] = 0; + Bky[i][0] = 0; + Bky[i][1] = 0; + Bkz[i][0] = 0; + Bkz[i][1] = 0; + continue; } // construct an orthogonal base ek, e1, e2 - if ((ix == iy) && (iy == iz)) { + if (ek.isParallel(n0, 1e-6)) { // ek parallel to (1,1,1) e1.set(-1., 1., 0); e2.set(1., 1., -2.); @@ -84,50 +87,55 @@ void TurbulentMagneticFieldGrid::initialize() { cosPhase = cos(phase); // real part sinPhase = sin(phase); // imaginary part - Bx[i][0] = b.x() * cosPhase; - Bx[i][1] = b.x() * sinPhase; - By[i][0] = b.y() * cosPhase; - By[i][1] = b.y() * sinPhase; - Bz[i][0] = b.z() * cosPhase; - Bz[i][1] = b.z() * sinPhase; + Bkx[i][0] = b.x() * cosPhase; + Bkx[i][1] = b.x() * sinPhase; + Bky[i][0] = b.y() * cosPhase; + Bky[i][1] = b.y() * sinPhase; + Bkz[i][0] = b.z() * cosPhase; + Bkz[i][1] = b.z() * sinPhase; } } } - // perform inverse FFT on each component - fftw_plan plan_x = fftw_plan_dft_3d(n, n, n, Bx, Bx, FFTW_BACKWARD, - FFTW_ESTIMATE); + // in-place, complex to real, inverse Fourier transformation on each component + // note that the last elements of B(x) are unused now + double *Bx = (double*) Bkx; + fftw_plan plan_x = fftw_plan_dft_c2r_3d(n, n, n, Bkx, Bx, FFTW_ESTIMATE); fftw_execute(plan_x); fftw_destroy_plan(plan_x); - fftw_plan plan_y = fftw_plan_dft_3d(n, n, n, By, By, FFTW_BACKWARD, - FFTW_ESTIMATE); + double *By = (double*) Bky; + fftw_plan plan_y = fftw_plan_dft_c2r_3d(n, n, n, Bky, By, FFTW_ESTIMATE); fftw_execute(plan_y); fftw_destroy_plan(plan_y); - fftw_plan plan_z = fftw_plan_dft_3d(n, n, n, Bz, Bz, FFTW_BACKWARD, - FFTW_ESTIMATE); + double *Bz = (double*) Bkz; + fftw_plan plan_z = fftw_plan_dft_c2r_3d(n, n, n, Bkz, Bz, FFTW_ESTIMATE); fftw_execute(plan_z); fftw_destroy_plan(plan_z); // calculate normalization double sumB2 = 0; - for (unsigned int i = 0; i < n * n * n; i++) - sumB2 += pow(Bx[i][0], 2) + pow(By[i][0], 2) + pow(Bz[i][0], 2); + for (size_t ix = 0; ix < n; ix++) + for (size_t iy = 0; iy < n; iy++) + for (size_t iz = 0; iz < n; iz++) { + i = ix * n * (n+2) + iy * (n+2) + iz; + sumB2 += pow(Bx[i], 2) + pow(By[i], 2) + pow(Bz[i], 2); + } double weight = Brms / sqrt(sumB2 / (n * n * n)); // normalize and save real component to the grid for (size_t ix = 0; ix < n; ix++) for (size_t iy = 0; iy < n; iy++) for (size_t iz = 0; iz < n; iz++) { - int i = ix * n * n + iy * n + iz; - grid[ix][iy][iz] = Vector3(Bx[i][0], By[i][0], Bz[i][0]) + i = ix * n * (n+2) + iy * (n+2) + iz; + grid[ix][iy][iz] = Vector3(Bx[i], By[i], Bz[i]) * weight; } - fftw_free(Bx); - fftw_free(By); - fftw_free(Bz); + fftw_free(Bkx); + fftw_free(Bky); + fftw_free(Bkz); } double TurbulentMagneticFieldGrid::getRMSFieldStrength() const { From 1fe9af4f247acd5c3ad62d5e044877f6734a40fb Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sat, 7 Apr 2012 08:32:28 +0200 Subject: [PATCH 0046/1298] minor changes --- include/mpc/Candidate.h | 4 ++-- include/mpc/PhasePoint.h | 4 ++++ include/mpc/module/BreakCondition.h | 1 - src/module/Output.cpp | 34 +++++++++++++++-------------- test/python/testDeflectionCK.py | 1 + 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/include/mpc/Candidate.h b/include/mpc/Candidate.h index 596f5111c..95eaa72fe 100644 --- a/include/mpc/Candidate.h +++ b/include/mpc/Candidate.h @@ -53,8 +53,8 @@ class Candidate: public Referenced { Candidate(); Candidate(const ParticleState &state); virtual ~Candidate() { - } - ; + + }; bool isActive() const; void setActive(bool b); diff --git a/include/mpc/PhasePoint.h b/include/mpc/PhasePoint.h index 29e01da77..7ed86d4c4 100644 --- a/include/mpc/PhasePoint.h +++ b/include/mpc/PhasePoint.h @@ -5,6 +5,10 @@ namespace mpc { +/** + @class PhasePoint + @brief 6D point in (momentum - position) phase space + */ class PhasePoint { public: Vector3 a, b; diff --git a/include/mpc/module/BreakCondition.h b/include/mpc/module/BreakCondition.h index 438721346..97304ccce 100644 --- a/include/mpc/module/BreakCondition.h +++ b/include/mpc/module/BreakCondition.h @@ -78,7 +78,6 @@ class CubicBoundary: public Module { @brief Flag a particle when leaving the sphere. */ class SphericalBoundary: public Module { - protected: Vector3 center; double radius; diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 7dc59fe0a..5ce854b58 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -6,8 +6,6 @@ #include #include -#include - namespace mpc { TrajectoryOutput::TrajectoryOutput(std::string name) { @@ -41,8 +39,8 @@ std::string TrajectoryOutput::getDescription() const { return "Trajectory output"; } -ConditionalOutput::ConditionalOutput(std::string filename, std::string propName) : - removeProperty(false) { +ConditionalOutput::ConditionalOutput(std::string filename, std::string propName) { + removeProperty = false; propertyName = propName; outfile.open(filename.c_str()); outfile @@ -61,30 +59,34 @@ void ConditionalOutput::setRemoveProperty(bool removeProperty) { void ConditionalOutput::process(Candidate *candidate) const { if (candidate->hasProperty(propertyName)) { char buffer[256]; - size_t pos = 0; + size_t p = 0; + + p += ::sprintf(buffer + p, "%d", candidate->current.getId()); + + const Vector3 &pos = candidate->current.getPosition() / Mpc; + p += ::sprintf(buffer + p, ", %f, %f, %f", pos.x(), + pos.y(), pos.z()); - pos += ::sprintf(buffer + pos, "%d", candidate->current.getId()); - Vector3 position = candidate->current.getPosition() / Mpc; - pos += ::sprintf(buffer + pos, ", %f, %f, %f", position.x(), - position.y(), position.z()); const Vector3 &dir = candidate->current.getDirection(); - pos += ::sprintf(buffer + pos, ", %f, %f, %f", + p += ::sprintf(buffer + p, ", %f, %f, %f", candidate->current.getEnergy() / EeV, dir.phi(), dir.theta()); - pos += ::sprintf(buffer + pos, ", %f", + p += ::sprintf(buffer + p, ", %f", candidate->getTrajectoryLength() / Mpc); - pos += ::sprintf(buffer + pos, ", %d", candidate->initial.getId()); - Vector3 ipos = candidate->initial.getPosition() / Mpc; - pos += ::sprintf(buffer + pos, ", %f, %f, %f", ipos.x(), ipos.y(), + p += ::sprintf(buffer + p, ", %d", candidate->initial.getId()); + + const Vector3 &ipos = candidate->initial.getPosition() / Mpc; + p += ::sprintf(buffer + p, ", %f, %f, %f", ipos.x(), ipos.y(), ipos.z()); + const Vector3 &idir = candidate->initial.getDirection(); - pos += ::sprintf(buffer + pos, ", %f, %f, %f\n", + p += ::sprintf(buffer + p, ", %f, %f, %f\n", candidate->initial.getEnergy() / EeV, idir.phi(), idir.theta()); #pragma omp critical { - outfile.write(buffer, pos); + outfile.write(buffer, p); } if (removeProperty) { diff --git a/test/python/testDeflectionCK.py b/test/python/testDeflectionCK.py index 55ebd50bd..45776e7ef 100644 --- a/test/python/testDeflectionCK.py +++ b/test/python/testDeflectionCK.py @@ -100,3 +100,4 @@ def propagate(tolerance): grid() savefig('DeflectionCK_xdeviation.png',bbox_inches='tight') + From 5a57640c38a74efb97738976582d2c4117cdb962 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 10 Apr 2012 14:17:39 +0200 Subject: [PATCH 0047/1298] improved test scripts --- test/python/testDeflectionCK.py | 11 +- test/python/testTurbulentField.py | 243 +++++++++++++----------------- 2 files changed, 111 insertions(+), 143 deletions(-) diff --git a/test/python/testDeflectionCK.py b/test/python/testDeflectionCK.py index 45776e7ef..25ebab205 100644 --- a/test/python/testDeflectionCK.py +++ b/test/python/testDeflectionCK.py @@ -21,7 +21,7 @@ def propagate(tolerance): c.setTrajectoryLength(0) c.setCurrentStep(0) - c.setNextStep(1 * kpc) + c.setNextStep(1 * Mpc) # set a large initial step, so that an initial acceleration is uneccessary c.current.setPosition(Vector3(0, R, 0)) c.current.setDirection(Vector3(1, 0, 0)) c.setActive(True) @@ -52,13 +52,13 @@ def propagate(tolerance): posX, posY, dirX, dirY, dirDev, theta, n = propagate(1e-4) plot(posX/R, posY/R, "o", label='Simulated') plot(sin(linspace(0,2*pi)), cos(linspace(0,2*pi)),'k--',label='True') -title('Trajectory using $10^{-4}$ tolerance') legend() xlim(-1.5,1.5) ylim(-1.5,1.5) xlabel(r'$x / R_L$') ylabel(r'$y / R_L$') grid() +text(0.05, 0.95, 'Tolerance 1e-4', ha='left', transform=gca().transAxes) savefig('DeflectionCK_xtrajectory', bbox_inches='tight') ### Plot trajectory in p-space with 1e-4 tolerance @@ -66,13 +66,13 @@ def propagate(tolerance): posX, posY, dirX, dirY, dirDev, theta, n = propagate(1e-4) plot(dirX, dirY, "o", label='Simulated') plot(sin(linspace(0,2*pi)), cos(linspace(0,2*pi)),'k--',label='True') -title(r'Trajectory in $\vec{p}$-space using $10^{-4}$ tolerance') legend() xlim(-1.5,1.5) ylim(-1.5,1.5) xlabel(r'$p_x / |p_x|$') ylabel(r'$p_y / |p_y|$') grid() +text(0.05, 0.95, 'Tolerance 1e-4', ha='left', transform=gca().transAxes) savefig('DeflectionCK_ptrajectory', bbox_inches='tight') ### Directional error as function of distance for different tolerances @@ -83,8 +83,8 @@ def propagate(tolerance): legend(title='Tolerance, Steps', loc='upper left') xlabel(r'Travelled Distance / $2 \pi R_L$') ylabel(r'Direction Error [$^\circ$]') -xlim(0,1) grid() +semilogy() savefig('DeflectionCK_pdeviation.png',bbox_inches='tight') ### Positional error as function of distance for different tolerances @@ -96,8 +96,9 @@ def propagate(tolerance): legend(title='Tolerance, Steps', loc='upper left') xlabel(r'Travelled Distance / $2 \pi R_L$') ylabel(r'Position Error / $R_L$') -xlim(0,1) grid() +semilogy() +ylim(1e-8,1e-1) savefig('DeflectionCK_xdeviation.png',bbox_inches='tight') diff --git a/test/python/testTurbulentField.py b/test/python/testTurbulentField.py index c57f5e8d9..e31471e26 100644 --- a/test/python/testTurbulentField.py +++ b/test/python/testTurbulentField.py @@ -36,16 +36,6 @@ def getCorrelationCurve(self, step=(1, 1, 1)): y[i] += self.Rz[ i * step[0], i * step[1], i * step[2] ] y /= y[0] return x, y - - def plotCorrelationCurve(self, step=(1, 1, 1)): - x, y = self.getCorrelationCurve(step) - fig = figure() - plot(x, y, label=str(step)) - legend() - grid() - xlabel(r'$|\vec{d}| \left[\rm{gridpoints}\right]$') - ylabel(r'$R(\vec{d})/R(0)$') - return fig def getIntegralLengthscale(self, step=(1, 1, 1)): ''' @@ -64,144 +54,113 @@ def fftEnergySpectralDensity(a): return (b * conjugate(b)).real -class VectorFieldEnergySpectralDensity(): - def __init__(self, Bx, By, Bz): - # sum of the energy spectral density of each component - E = fftEnergySpectralDensity(Bx) - E += fftEnergySpectralDensity(By) - E += fftEnergySpectralDensity(Bz) - - n = shape(Bx)[0] - K = fftfreq(n) - - # project E(kx,ky,kz) -> E(k) in a dictionary - d = {} - for ix in range(n): - for iy in range(n): - for iz in range(n): - magK = (K[ix]**2 + K[iy]**2 + K[iz]**2)**.5 - energy = E[ix,iy,iz] - d.setdefault(magK,[energy]).append(energy) - - # make two arrays out of the dictionary - keys = d.keys() - keys.sort() - self.k = zeros(len(keys)) - self.Ek = zeros(len(keys)) - for i,key in enumerate(keys): - self.k[i] = key - self.Ek[i] = mean(d[key]) - - # normalize Ek - self.Ek /= max(self.Ek) - - - def findKmin(self, threshold=1e-6): - for i in range(len(self.Ek)): - if self.Ek[i] > threshold: - return self.k[i] - - def findKmax(self, threshold=1e-6): - for i in range(len(self.Ek)-1,-1,-1): - if self.Ek[i] > threshold: - return self.k[i] - - def powerLaw(self, p, x): - return (p[1]*x)**(p[0]) - - def costFunction(self, p, x, y): - return self.powerLaw(p, x) - y - - def fitPowerLaw(self): - # determine fitting range - kmin=self.findKmin() - kmax=self.findKmax() - iMin = self.k.searchsorted(kmin) - iMax = self.k.searchsorted(kmax) - x = self.k[iMin:iMax] - y = self.Ek[iMin:iMax] - # fit - p0 = [-11./3., 1.] # initial guess - p1, success = optimize.leastsq(self.costFunction, p0, args=(x, y)) - return p1 - - def plot(self): - plot(self.k, self.Ek, label='Sim. Turbulence') - p1 = self.fitPowerLaw() - alabel = 'Fit: $k^{%.2f/3}$'%(p1[0]*3) - plot(self.k, self.powerLaw(p1, self.k), label=alabel) - kmin = self.findKmin() - kmax = self.findKmax() - axvline(kmin, color='r',linestyle='--',label='$k_{min}=1/'+str(1/kmin)+'$') - axvline(kmax, color='r',linestyle='--',label='$k_{max}=1/'+str(1/kmax)+'$') - loglog() - legend(loc=0) - xlabel('Wavenumber $k$') - ylabel('Energy Spectral Density $E(k)$') - grid() - - -def retrieveField(field): - n = field.getGridSamples() - Bx, By, Bz = zeros((3, n, n, n)) +def getVectorFieldEnergySpectralDensity(Bx, By, Bz): + ''' + calculate the energy spectral density for an 3-dimensional Vector field + ''' + E = fftEnergySpectralDensity(Bx) + E += fftEnergySpectralDensity(By) + E += fftEnergySpectralDensity(Bz) + n = shape(Bx)[0] + K = fftfreq(n) + # project E(kx,ky,kz) -> E(k) + d = {} for ix in range(n): for iy in range(n): for iz in range(n): - b = field.getField(Vector3(ix, iy, iz)) - Bx[ix, iy, iz] = b.x() - By[ix, iy, iz] = b.y() - Bz[ix, iy, iz] = b.z() - return Bx, By, Bz + magK = (K[ix]**2 + K[iy]**2 + K[iz]**2)**.5 + energy = E[ix,iy,iz] + d.setdefault(magK, [energy]).append(energy) + k = d.keys() + k.sort() + k = array(k) + Ek = zeros(len(k)) + for i,key in enumerate(k): + Ek[i] = mean(d[key]) + return k, Ek #if __name__ == '__main__': -n = 64 -field = TurbulentMagneticFieldGrid(Vector3(0, 0, 0), n, 1, 2, 16, 1, -11. / 3) -Bx, By, Bz = retrieveField(field) - - -### periodicity +### create field +n = 128 +lMin, lMax = 2, 32 +Brms = 1 +alpha = -11./3 +field = TurbulentMagneticFieldGrid(Vector3(0, 0, 0), n, 1, lMin, lMax, Brms, alpha) +Lc = field.getCorrelationLength() + +### copy field to array +Bx, By, Bz = zeros((3, n, n, n)) +for ix in range(n): + for iy in range(n): + for iz in range(n): + b = field.getField(Vector3(ix, iy, iz)) + Bx[ix, iy, iz] = b.x() + By[ix, iy, iz] = b.y() + Bz[ix, iy, iz] = b.z() +del field + +### plot slice in position space +slice = n/2 figure() subplot(111, aspect='equal') -A = zeros((3*n,3*n)) -for i,j in ((0,1), (1,0), (1,1), (1,2), (2,1)): - A[i*n:(i+1)*n, j*n:(j+1)*n] = Bx[:,:,32] -pc = pcolor(ma.masked_array(A, A == 0)) +pc = pcolor(((Bx**2 + By**2 + Bz**2)**.5)[:,:,slice]) cbar = colorbar(pc) -cbar.set_label(r'$|\vec{B_x}|/B_{rms}$') -xlim(0,3*n) -ylim(0,3*n) -xlabel(r'$x$ [gridpoints]') -ylabel(r'$y$ [gridpoints]') -savefig('TurbulentField_periodicity.png', bbox_inches='tight') - +cbar.set_label(r'$|\vec{B}(\vec{x})| / B_{RMS}$') +xlabel(r'$x$') +ylabel(r'$y$') +xlim(0,n) +ylim(0,n) +text(0.8, 1.05, '$z=%i$'%slice, transform=gca().transAxes) +savefig('TurbulentField_slicePositionSpace.png', bbox_inches='tight') -### slice in configuration space +### plot slice in configuration space +slice = n/2 +figure() +subplot(111, aspect='equal') Bkx = fftshift(fftn(Bx)) Bky = fftshift(fftn(By)) Bkz = fftshift(fftn(Bz)) -Bk = ((Bkx*Bkx.conjugate() + Bky*Bky.conjugate() + Bkz*Bkz.conjugate())**.2).real -del Bkx, Bky, Bkz -figure() -subplot(111, aspect='equal') -pc = pcolor(Bk[:,:,n/2]) +Bk = ((Bkx*Bkx.conjugate() + Bky*Bky.conjugate() + Bkz*Bkz.conjugate()).real)**.5 +pc = pcolor(log10(Bk[:,:,slice]), vmin=0) +del Bk, Bkx, Bky, Bkz cbar = colorbar(pc) -cbar.set_label(r'$|\vec{B}(\vec{k})|$ [a.u.]') -xlabel(r'$\vec{k}_x$') -ylabel(r'$\vec{k}_y$') +cbar.set_label(r'$log_{10}(|\vec{B}(\vec{k})| / B_{RMS})$') +xlabel(r'$k_x$') +ylabel(r'$k_y$') k = fftshift(fftfreq(n)) idx = arange(0,n,n/4) xticks(idx, k[idx]) yticks(idx, k[idx]) xlim(0,n) ylim(0,n) -savefig('TurbulentField_configurationSpace.png', bbox_inches='tight') - +text(0.8, 1.05, '$k_z=%.2f$'%k[slice], transform=gca().transAxes) +savefig('TurbulentField_sliceConfigurationSpace.png', bbox_inches='tight') -### correlation length + isotropy +### plot slice and periodical extension in position space +slice = n/2 +figure() +subplot(111, aspect='equal') +A = zeros((3*n,3*n)) +for i,j in ((0,1), (1,0), (1,1), (1,2), (2,1)): + A[i*n:(i+1)*n, j*n:(j+1)*n] = Bx[:,:,slice] +pc = pcolor(ma.masked_array(A, A == 0)) +del A +cbar = colorbar(pc) +cbar.set_label(r'$|\vec{B_x}|/B_{rms}$') +xlim(0,3*n) +ylim(0,3*n) +xticks([0, n, 2*n, 3*n]) +yticks([0, n, 2*n, 3*n]) +xlabel(r'$x$') +ylabel(r'$y$') +text(0.8, 1.05, '$z=%i$'%slice, transform=gca().transAxes) +savefig('TurbulentField_slicePeriodicity.png', bbox_inches='tight') + +### plot (2pt-auto-)correlation curves for various directions figure() corr = VectorFieldAutoCorrelation(Bx,By,Bz) -Lc = [] +Lcs = [] steps = [] for ix in arange(-2,3): for iy in arange(-2,3): @@ -212,37 +171,45 @@ def retrieveField(field): continue step = (ix,iy,iz) # steps.append(step) - Lc.append( corr.getIntegralLengthscale(step) ) + Lcs.append( corr.getIntegralLengthscale(step) ) x,y = corr.getCorrelationCurve(step) plot(x,y,label=str(step)) xlabel('Distance [gridpoints]') ylabel('Normalized Autocorrelation') xlim(0,32) grid() -s = 'Correlation Length\n Nominal %.2f\n Simulated %.2f $\pm$ %.2f'%(field.getCorrelationLength(), mean(Lc), std(Lc)/(len(Lc))**.5) +s = 'Correlation Length\n Nominal %.2f\n Simulated %.2f $\pm$ %.2f'%(Lc, mean(Lcs), std(Lcs)/(len(Lcs))**.5) text(0.5, 0.95, s, ha='left', va='top', transform=gca().transAxes) -savefig('TurbulentField_correlation.png', bbox_inches='tight') - +savefig('TurbulentField_correlationCurves.png', bbox_inches='tight') -### energy spectrum -esd = VectorFieldEnergySpectralDensity(Bx, By, Bz) +### plot energy spectrum figure() -esd.plot() +k, Ek = getVectorFieldEnergySpectralDensity(Bx, By, Bz) +plot(k, Ek, label='Turbulent Spectrum') +i = k.searchsorted(1./lMax) + 2 +plot(k, Ek[i]/k[i]**alpha * k**alpha, label='Slope $k^{-11/3}$') +axvline(1./lMax, color='r', linestyle='--', label='$k_{min}=1/%.1f$'%lMax) +axvline(1./lMin, color='r', linestyle='--', label='$k_{max}=1/%.1f$'%lMin) +loglog() +legend(loc='center left') +xlabel('Wavenumber $k$') +ylabel('Energy Spectral Density $E(k) [a.u.]$') +grid() savefig('TurbulentField_spectrum.png', bbox_inches='tight') - -### field strength, mean and brms +### plot histogram of field strengths +figure() Bx.resize(n**3) By.resize(n**3) Bz.resize(n**3) -figure() hist(Bx, bins=40, range=(-3,3), histtype='step', normed=True, label='$B_x$', linewidth=2) hist(By, bins=40, range=(-3,3), histtype='step', normed=True, label='$B_y$', linewidth=2) hist(Bz, bins=40, range=(-3,3), histtype='step', normed=True, label='$B_z$', linewidth=2) legend() grid() -xlabel('Magnetic Field Amplitude$') +xlabel('$B/B_{RMS}$') ylabel('Frequency') -Brms = (mean( Bx**2 + By**2 + Bz**2 ))**.5 -text(1.45, 0.5, '$B_{RMS}$ = %.2f'%(Brms)) +brms = (mean( Bx**2 + By**2 + Bz**2 ))**.5 +bmean = abs(mean(Bx + By + Bz)) +text(0.95, 0.7, '$RMS$ = %.2f\nMean = %.2f'%(brms, bmean), ha='right', va='top', transform=gca().transAxes) savefig('TurbulentField_amplitude.png', bbox_inches='tight') From 1ea11d1a47e8dc4cf82e03e19bd16937052b7648 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 13 Apr 2012 13:42:06 +0200 Subject: [PATCH 0048/1298] renamed and moved module/common.h to Common.h renamed HepId.h to Nucleus.h --- CMakeLists.txt | 7 ++++++- include/mpc/{module/common.h => Common.h} | 0 include/mpc/{HepPID.h => Nucleus.h} | 14 +++++++------- include/mpc/ParticleState.h | 4 +++- python/mpc.i | 8 ++++---- src/{module/common.cpp => Common.cpp} | 2 +- src/ParticleState.cpp | 5 +++-- src/module/ElectronPairProduction.cpp | 1 - src/module/NuclearDecay.cpp | 1 - src/module/PhotoDisintegration.cpp | 1 - src/module/PhotoPionProduction.cpp | 1 - test/python/testTurbulentField.py | 5 +---- test/testCore.cpp | 1 - 13 files changed, 25 insertions(+), 25 deletions(-) rename include/mpc/{module/common.h => Common.h} (100%) rename include/mpc/{HepPID.h => Nucleus.h} (59%) rename src/{module/common.cpp => Common.cpp} (97%) diff --git a/CMakeLists.txt b/CMakeLists.txt index f41afc2da..b2c764774 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,12 @@ add_subdirectory(libs/HepPID) list (APPEND MPC_EXTRA_LIBRARIES HepPID) list (APPEND MPC_EXTRA_INCLUDES libs/HepPID/include) +# SOPHIA provided +#add_subdirectory(libs/sophia) +#list (APPEND MPC_EXTRA_LIBRARIES sophia) +#list (APPEND MPC_EXTRA_INCLUDES libs/sophia) +# OpenMP needed for shared memory multiprocessing include(FindOpenMP) if(OPENMP_FOUND) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") @@ -88,7 +93,7 @@ add_library(mpc SHARED src/IO.cpp src/ParticleState.cpp src/Source.cpp - src/module/common.cpp + src/Common.cpp src/module/BreakCondition.cpp src/module/SimplePropagation.cpp src/module/DeflectionCK.cpp diff --git a/include/mpc/module/common.h b/include/mpc/Common.h similarity index 100% rename from include/mpc/module/common.h rename to include/mpc/Common.h diff --git a/include/mpc/HepPID.h b/include/mpc/Nucleus.h similarity index 59% rename from include/mpc/HepPID.h rename to include/mpc/Nucleus.h index 75ad8e8b7..f21b219ea 100644 --- a/include/mpc/HepPID.h +++ b/include/mpc/Nucleus.h @@ -1,5 +1,5 @@ -#ifndef HEPPID_H_ -#define HEPPID_H_ +#ifndef NUCLEUS_H_ +#define NUCLEUS_H_ #include @@ -10,12 +10,12 @@ namespace mpc { // nj = 2J+1 is the nucleus total spin and is currently neglected inline int getNucleusId(int a, int z) { if (z < 0) - throw std::runtime_error("mpc::HepId: no nucleus with Z < 0"); + throw std::runtime_error("mpc::Nucleus: no nucleus with Z < 0"); if (a < 0) - throw std::runtime_error("mpc::HepId: no nucleus with A < 0"); + throw std::runtime_error("mpc::Nucleus: no nucleus with A < 0"); if (a < z) - throw std::runtime_error("mpc::HepId: no nucleus with A < Z"); - return 1e9 + a * 1e6 + z * 1e3; + throw std::runtime_error("mpc::Nucleus: no nucleus with A < Z"); + return 1000000000 + a * 1000000 + z * 1000; } inline int getChargeNumberFromNucleusId(int id) { @@ -28,4 +28,4 @@ inline int getMassNumberFromNucleusId(int id) { } -#endif /* HEPPID_H_ */ +#endif /* NUCLEUS_H_ */ diff --git a/include/mpc/ParticleState.h b/include/mpc/ParticleState.h index 489ac7f57..a4ed034d4 100644 --- a/include/mpc/ParticleState.h +++ b/include/mpc/ParticleState.h @@ -3,7 +3,8 @@ #include "mpc/Vector3.h" #include "mpc/Units.h" -#include "mpc/HepPID.h" +#include "mpc/Nucleus.h" +#include "mpc/Common.h" namespace mpc { @@ -41,6 +42,7 @@ class ParticleState { private: int id; + double pmass; double energy; Vector3 position; Vector3 direction; diff --git a/python/mpc.i b/python/mpc.i index 9baf40c40..cd69d16a2 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -38,13 +38,13 @@ #include "mpc/ModuleList.h" #include "mpc/PhasePoint.h" #include "mpc/ExplicitRungeKutta.h" -#include "mpc/HepPID.h" +#include "mpc/Nucleus.h" #include "mpc/Random.h" #include "mpc/Units.h" #include "mpc/Vector3.h" #include "mpc/Source.h" #include "mpc/Referenced.h" -#include "mpc/module/common.h" +#include "mpc/Common.h" %} /* Parse the header file to generate wrappers */ @@ -52,14 +52,14 @@ %feature("unref") mpc::Referenced "$this->removeReference();" %include "mpc/Referenced.h" %include "mpc/Units.h" -%include "mpc/HepPID.h" +%include "mpc/Nucleus.h" %include "mpc/Vector3.h" %include "mpc/Random.h" %include "mpc/ParticleState.h" // %feature("director") mpc::Source; %template(SourceRefPtr) mpc::ref_ptr; %include "mpc/Source.h" -%include "mpc/module/common.h" +%include "mpc/Common.h" %template(CandidateVector) std::vector< mpc::ref_ptr >; %template(CandidateRefPtr) mpc::ref_ptr; diff --git a/src/module/common.cpp b/src/Common.cpp similarity index 97% rename from src/module/common.cpp rename to src/Common.cpp index bbaae7782..3f4368cc4 100644 --- a/src/module/common.cpp +++ b/src/Common.cpp @@ -1,4 +1,4 @@ -#include "mpc/module/common.h" +#include "mpc/Common.h" #include "kiss/path.h" #include "kiss/logger.h" diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index 8275b5244..90038fddc 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -3,7 +3,7 @@ namespace mpc { ParticleState::ParticleState() : - id(0), energy(0), position(0,0,0), direction(1,0,0) { + id(0), pmass(0), energy(0), position(0, 0, 0), direction(1, 0, 0) { } @@ -33,6 +33,7 @@ double ParticleState::getEnergy() const { void ParticleState::setId(int newId) { id = newId; + pmass = getMassNumber() * amu; } int ParticleState::getId() const { @@ -52,7 +53,7 @@ int ParticleState::getMassNumber() const { } double ParticleState::getMass() const { - return getMassNumberFromNucleusId(id) * amu; + return pmass; } double ParticleState::getLorentzFactor() const { diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 88606434b..5b2461a58 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -1,5 +1,4 @@ #include "mpc/module/ElectronPairProduction.h" -#include "mpc/module/common.h" #include #include diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index 004a255b3..1e8fbdde0 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -1,5 +1,4 @@ #include "mpc/module/NuclearDecay.h" -#include "mpc/module/common.h" #include #include diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index c28bf5297..3563aeb1c 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -1,5 +1,4 @@ #include "mpc/module/PhotoDisintegration.h" -#include "mpc/module/common.h" #include #include diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 05d1af471..e1eee6e2a 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -1,5 +1,4 @@ #include "mpc/module/PhotoPionProduction.h" -#include "mpc/module/common.h" #include #include diff --git a/test/python/testTurbulentField.py b/test/python/testTurbulentField.py index e31471e26..896701ef4 100644 --- a/test/python/testTurbulentField.py +++ b/test/python/testTurbulentField.py @@ -3,7 +3,6 @@ from mpc import * from scipy import optimize - def fftAutoCorrelation(a): ''' calculate 2point-autocorrelation for an n-dimensional array of real input @@ -45,7 +44,6 @@ def getIntegralLengthscale(self, step=(1, 1, 1)): # use symmetry: Lc = \int_{-inf}^{inf} R/R_0 dx = 2*\int_{0}^{inf} R/R_0 dx return (2 * sum(y[1:]) + y[0]) * norm(step) - def fftEnergySpectralDensity(a): ''' calculate the energy spectral density for an n-dimensional array @@ -53,7 +51,6 @@ def fftEnergySpectralDensity(a): b = fftn(a) return (b * conjugate(b)).real - def getVectorFieldEnergySpectralDensity(Bx, By, Bz): ''' calculate the energy spectral density for an 3-dimensional Vector field @@ -80,7 +77,7 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): return k, Ek -#if __name__ == '__main__': + ### create field n = 128 lMin, lMax = 2, 32 diff --git a/test/testCore.cpp b/test/testCore.cpp index fcd6f4f75..1de10e9ac 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -1,5 +1,4 @@ #include "mpc/Candidate.h" -#include "mpc/module/common.h" #include "gtest/gtest.h" From 91d1dc709b245620fb5cf59c392e73d6f06f0122 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 13 Apr 2012 13:43:38 +0200 Subject: [PATCH 0049/1298] add neutron and electron mass to Units.h --- include/mpc/Units.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/mpc/Units.h b/include/mpc/Units.h index 010c7747a..1d185431f 100644 --- a/include/mpc/Units.h +++ b/include/mpc/Units.h @@ -25,6 +25,8 @@ static const double c_light = 2.99792458e+8 * meter / second; static const double c_squared = c_light * c_light; static const double amu = 1.660538921e-27 * kilogram; static const double mass_proton = 1.67262158e-27 * kilogram; +static const double mass_neutron = 1.67492735e-27 * kilogram; +static const double mass_electron = 9.10938291e-31 * kilogram; // other units From 883a31a7aa66dd8d0af5f879dc00faa7badd1d8b Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 13 Apr 2012 13:44:28 +0200 Subject: [PATCH 0050/1298] small fix in turbulentField --- src/magneticField/turbulentMagneticFieldGrid.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/magneticField/turbulentMagneticFieldGrid.cpp b/src/magneticField/turbulentMagneticFieldGrid.cpp index 85344dde7..464832803 100644 --- a/src/magneticField/turbulentMagneticFieldGrid.cpp +++ b/src/magneticField/turbulentMagneticFieldGrid.cpp @@ -20,8 +20,8 @@ void TurbulentMagneticFieldGrid::setSeed(int seed) { } void TurbulentMagneticFieldGrid::initialize() { - size_t n = samples; - size_t n2 = floor(n/2) + 1; // size of complex array + size_t n = samples; // size of array + size_t n2 = floor(n/2) + 1; // size array in z-direction in configuration space // arrays to hold the complex vector components of the B(k)-field fftw_complex *Bkx, *Bky, *Bkz; @@ -119,7 +119,7 @@ void TurbulentMagneticFieldGrid::initialize() { for (size_t ix = 0; ix < n; ix++) for (size_t iy = 0; iy < n; iy++) for (size_t iz = 0; iz < n; iz++) { - i = ix * n * (n+2) + iy * (n+2) + iz; + i = ix * n * 2*n2 + iy * 2*n2 + iz; sumB2 += pow(Bx[i], 2) + pow(By[i], 2) + pow(Bz[i], 2); } double weight = Brms / sqrt(sumB2 / (n * n * n)); @@ -128,7 +128,7 @@ void TurbulentMagneticFieldGrid::initialize() { for (size_t ix = 0; ix < n; ix++) for (size_t iy = 0; iy < n; iy++) for (size_t iz = 0; iz < n; iz++) { - i = ix * n * (n+2) + iy * (n+2) + iz; + i = ix * n * 2*n2 + iy * 2*n2 + iz; grid[ix][iy][iz] = Vector3(Bx[i], By[i], Bz[i]) * weight; } From a916bd6216ab9c505bf9945952f68103a7087072 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 13 Apr 2012 15:13:17 +0200 Subject: [PATCH 0051/1298] implemented nuclear mass table --- CMakeLists.txt | 1 + include/mpc/Common.h | 1 - include/mpc/Nucleus.h | 7 ++++++- include/mpc/ParticleState.h | 1 - src/Common.cpp | 15 ++++++-------- src/Nucleus.cpp | 41 +++++++++++++++++++++++++++++++++++++ src/ParticleState.cpp | 5 ++--- test/testCore.cpp | 21 +++++++++++-------- 8 files changed, 69 insertions(+), 23 deletions(-) create mode 100644 src/Nucleus.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b2c764774..6bc732932 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,7 @@ add_library(mpc SHARED src/ParticleState.cpp src/Source.cpp src/Common.cpp + src/Nucleus.cpp src/module/BreakCondition.cpp src/module/SimplePropagation.cpp src/module/DeflectionCK.cpp diff --git a/include/mpc/Common.h b/include/mpc/Common.h index 58c9f5429..9d049c1ea 100644 --- a/include/mpc/Common.h +++ b/include/mpc/Common.h @@ -11,7 +11,6 @@ inline int digit(const int &value, const int &d) { return (value % (d * 10)) / d; } - } // namespace mpc #endif /* COMMON_H_ */ diff --git a/include/mpc/Nucleus.h b/include/mpc/Nucleus.h index f21b219ea..bd830b037 100644 --- a/include/mpc/Nucleus.h +++ b/include/mpc/Nucleus.h @@ -1,6 +1,7 @@ #ifndef NUCLEUS_H_ #define NUCLEUS_H_ +#include "mpc/AssocVector.h" #include namespace mpc { @@ -26,6 +27,10 @@ inline int getMassNumberFromNucleusId(int id) { return (id - 1000000000) / 1000000; } -} +static Loki::AssocVector nuclearMassTable; +void initNuclearMassTable(); +double getNucleusMass(int id); + +} // namespace mpc #endif /* NUCLEUS_H_ */ diff --git a/include/mpc/ParticleState.h b/include/mpc/ParticleState.h index a4ed034d4..8cefc9802 100644 --- a/include/mpc/ParticleState.h +++ b/include/mpc/ParticleState.h @@ -42,7 +42,6 @@ class ParticleState { private: int id; - double pmass; double energy; Vector3 position; Vector3 direction; diff --git a/src/Common.cpp b/src/Common.cpp index 3f4368cc4..3a4732a38 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -18,9 +18,8 @@ std::string getDataPath(std::string filename) { if (env_path) { if (is_directory(env_path)) { dataPath = env_path; - KISS_LOG_INFO - << "getDataPath: use environment variable, " << dataPath - << std::endl; + KISS_LOG_INFO << "getDataPath: use environment variable, " + << dataPath << std::endl; return concat_path(dataPath, filename); } } @@ -31,7 +30,7 @@ std::string getDataPath(std::string filename) { if (is_directory(_path)) { dataPath = _path; KISS_LOG_INFO - << "getDataPath: use install prefix, " << dataPath << std::endl; + << "getDataPath: use install prefix, " << dataPath << std::endl; return concat_path(dataPath, filename); } } @@ -41,16 +40,14 @@ std::string getDataPath(std::string filename) { std::string _path = executable_path() + "../data"; if (is_directory(_path)) { dataPath = _path; - KISS_LOG_INFO - << "getDataPath: use executable path, " << dataPath - << std::endl; + KISS_LOG_INFO << "getDataPath: use executable path, " << dataPath + << std::endl; return concat_path(dataPath, filename); } } dataPath = "data"; - KISS_LOG_INFO - << "getDataPath: use default, " << dataPath << std::endl; + KISS_LOG_INFO << "getDataPath: use default, " << dataPath << std::endl; return concat_path(dataPath, filename); } diff --git a/src/Nucleus.cpp b/src/Nucleus.cpp new file mode 100644 index 000000000..a2f11f1c0 --- /dev/null +++ b/src/Nucleus.cpp @@ -0,0 +1,41 @@ +#include "mpc/Nucleus.h" +#include "mpc/Common.h" + +#include + +#include +#include + +namespace mpc { + +void initNuclearMassTable() { + std::string filename = getDataPath("/NuclearMass/nuclearMassTable.txt"); + std::ifstream infile(filename.c_str()); + + if (!infile.good()) + throw std::runtime_error("mpc: could not open file " + filename); + + int Z, N; + double mass; + while (infile.good()) { + if (infile.peek() != '#') { + infile >> Z >> N >> mass; + nuclearMassTable[getNucleusId(Z + N, Z)] = mass; + } + infile.ignore(std::numeric_limits::max(), '\n'); + } + + infile.close(); +} + +double getNucleusMass(int id) { + if (nuclearMassTable.size() == 0) + initNuclearMassTable(); + + Loki::AssocVector::const_iterator i = nuclearMassTable.find(id); + if (i == nuclearMassTable.end()) + throw std::runtime_error("mpc: nuclear mass not found " + kiss::str(id)); + return i->second; +} + +} // namespace mpc diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index 90038fddc..dc9878361 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -3,7 +3,7 @@ namespace mpc { ParticleState::ParticleState() : - id(0), pmass(0), energy(0), position(0, 0, 0), direction(1, 0, 0) { + id(0), energy(0), position(0, 0, 0), direction(1, 0, 0) { } @@ -33,7 +33,6 @@ double ParticleState::getEnergy() const { void ParticleState::setId(int newId) { id = newId; - pmass = getMassNumber() * amu; } int ParticleState::getId() const { @@ -53,7 +52,7 @@ int ParticleState::getMassNumber() const { } double ParticleState::getMass() const { - return pmass; + return getNucleusMass(id); } double ParticleState::getLorentzFactor() const { diff --git a/test/testCore.cpp b/test/testCore.cpp index 1de10e9ac..18d605114 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -52,19 +52,24 @@ TEST(ParticleState, charge) { EXPECT_DOUBLE_EQ(particle.getCharge(), 26 * eplus); } -TEST(ParticleState, mass) { +TEST(ParticleState, massProton) { ParticleState particle; - particle.setId(1056026000); - EXPECT_EQ(particle.getMassNumber(), 56); - EXPECT_DOUBLE_EQ(particle.getMass(), 56 * amu); + particle.setId(1001001000); + EXPECT_EQ(particle.getMassNumber(), 1); + EXPECT_DOUBLE_EQ(particle.getMass(), mass_proton); +} + +TEST(ParticleState, massException) { + ParticleState particle; + particle.setId(1002002000); + EXPECT_THROW(particle.getMass(), std::runtime_error); } TEST(ParticleState, lorentzFactor) { ParticleState particle; - particle.setId(1010005000); + particle.setId(1001001000); particle.setEnergy(1e12 * eV); - double lf = 1e12 * eV / (10 * amu * c_squared); - EXPECT_DOUBLE_EQ(particle.getLorentzFactor(), lf); + EXPECT_DOUBLE_EQ(particle.getLorentzFactor(), 1e12 * eV / mass_proton / c_squared); } TEST(Candidate, currentStep) { @@ -92,7 +97,7 @@ TEST(Candidate, isActive) { TEST(Candidate, property) { Candidate candidate; - candidate.setProperty("foo","bar"); + candidate.setProperty("foo", "bar"); EXPECT_TRUE(candidate.hasProperty("foo")); std::string value; candidate.getProperty("foo", value); From 92a9b4e1d7bf9286e7deea3a3d7f6f2ff80afdc6 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 13 Apr 2012 15:21:17 +0200 Subject: [PATCH 0052/1298] fix nuclearMassTable --- include/mpc/Nucleus.h | 1 - src/Nucleus.cpp | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/mpc/Nucleus.h b/include/mpc/Nucleus.h index bd830b037..35cc63466 100644 --- a/include/mpc/Nucleus.h +++ b/include/mpc/Nucleus.h @@ -27,7 +27,6 @@ inline int getMassNumberFromNucleusId(int id) { return (id - 1000000000) / 1000000; } -static Loki::AssocVector nuclearMassTable; void initNuclearMassTable(); double getNucleusMass(int id); diff --git a/src/Nucleus.cpp b/src/Nucleus.cpp index a2f11f1c0..972583c9e 100644 --- a/src/Nucleus.cpp +++ b/src/Nucleus.cpp @@ -8,6 +8,8 @@ namespace mpc { +static Loki::AssocVector nuclearMassTable; + void initNuclearMassTable() { std::string filename = getDataPath("/NuclearMass/nuclearMassTable.txt"); std::ifstream infile(filename.c_str()); From f454b8e0fe91a14228982aacb7d134b7fb19d43e Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 13 Apr 2012 16:03:42 +0200 Subject: [PATCH 0053/1298] change nuclearMassTable AssocVector to Vector --- include/mpc/ParticleState.h | 3 ++- src/Nucleus.cpp | 15 +++++++++------ src/ParticleState.cpp | 5 +++-- test/testCore.cpp | 11 +++++------ 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/include/mpc/ParticleState.h b/include/mpc/ParticleState.h index 8cefc9802..ec9c715ff 100644 --- a/include/mpc/ParticleState.h +++ b/include/mpc/ParticleState.h @@ -3,8 +3,8 @@ #include "mpc/Vector3.h" #include "mpc/Units.h" -#include "mpc/Nucleus.h" #include "mpc/Common.h" +#include "mpc/Nucleus.h" namespace mpc { @@ -42,6 +42,7 @@ class ParticleState { private: int id; + double pmass; double energy; Vector3 position; Vector3 direction; diff --git a/src/Nucleus.cpp b/src/Nucleus.cpp index 972583c9e..51da0739f 100644 --- a/src/Nucleus.cpp +++ b/src/Nucleus.cpp @@ -3,12 +3,13 @@ #include +#include #include #include namespace mpc { -static Loki::AssocVector nuclearMassTable; +static std::vector nuclearMassTable; void initNuclearMassTable() { std::string filename = getDataPath("/NuclearMass/nuclearMassTable.txt"); @@ -22,7 +23,7 @@ void initNuclearMassTable() { while (infile.good()) { if (infile.peek() != '#') { infile >> Z >> N >> mass; - nuclearMassTable[getNucleusId(Z + N, Z)] = mass; + nuclearMassTable.push_back(mass); } infile.ignore(std::numeric_limits::max(), '\n'); } @@ -34,10 +35,12 @@ double getNucleusMass(int id) { if (nuclearMassTable.size() == 0) initNuclearMassTable(); - Loki::AssocVector::const_iterator i = nuclearMassTable.find(id); - if (i == nuclearMassTable.end()) - throw std::runtime_error("mpc: nuclear mass not found " + kiss::str(id)); - return i->second; + int Z = getChargeNumberFromNucleusId(id); + int N = getMassNumberFromNucleusId(id) - Z; + double mass = nuclearMassTable[Z * 31 + N]; + if (mass == 0) + throw std::runtime_error("mpc: nucleus not found " + kiss::str(id)); + return mass; } } // namespace mpc diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index dc9878361..bec651839 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -3,7 +3,7 @@ namespace mpc { ParticleState::ParticleState() : - id(0), energy(0), position(0, 0, 0), direction(1, 0, 0) { + id(0), pmass(0), energy(0), position(0, 0, 0), direction(1, 0, 0) { } @@ -33,6 +33,7 @@ double ParticleState::getEnergy() const { void ParticleState::setId(int newId) { id = newId; + pmass = getNucleusMass(id); } int ParticleState::getId() const { @@ -52,7 +53,7 @@ int ParticleState::getMassNumber() const { } double ParticleState::getMass() const { - return getNucleusMass(id); + return pmass; } double ParticleState::getLorentzFactor() const { diff --git a/test/testCore.cpp b/test/testCore.cpp index 18d605114..5e76dc2a1 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -45,6 +45,11 @@ TEST(ParticleState, id) { EXPECT_EQ(particle.getId(), 1045026000); } +TEST(ParticleState, idException) { + ParticleState particle; + EXPECT_THROW(particle.setId(1002002000), std::runtime_error); +} + TEST(ParticleState, charge) { ParticleState particle; particle.setId(1056026000); @@ -59,12 +64,6 @@ TEST(ParticleState, massProton) { EXPECT_DOUBLE_EQ(particle.getMass(), mass_proton); } -TEST(ParticleState, massException) { - ParticleState particle; - particle.setId(1002002000); - EXPECT_THROW(particle.getMass(), std::runtime_error); -} - TEST(ParticleState, lorentzFactor) { ParticleState particle; particle.setId(1001001000); From 6039b33b0f032488902ddc4a9d479fa94693a9ce Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 13 Apr 2012 16:30:51 +0200 Subject: [PATCH 0054/1298] pass exceptions through SWIG --- python/mpc.i | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/python/mpc.i b/python/mpc.i index cd69d16a2..84ecbc647 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -12,6 +12,23 @@ %include stdint.i %include std_container.i +// Handle standard exceptions. +// NOTE: needs to be before the %import! +%include "exception.i" +%exception +{ + try + { + $action + } + catch (const std::runtime_error& e) { + SWIG_exception(SWIG_RuntimeError, e.what()); + } + catch (...) { + SWIG_exception(SWIG_RuntimeError, "unknown exception"); + } +} + %{ #include "mpc/module/NuclearDecay.h" #include "mpc/module/ElectronPairProduction.h" From 492ec2b9f69cad7a7432a000b7c2027de1156352 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 13 Apr 2012 16:31:26 +0200 Subject: [PATCH 0055/1298] add nuclear mass test script --- test/python/testNuclearMass.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 test/python/testNuclearMass.py diff --git a/test/python/testNuclearMass.py b/test/python/testNuclearMass.py new file mode 100644 index 000000000..6b9b7976c --- /dev/null +++ b/test/python/testNuclearMass.py @@ -0,0 +1,33 @@ +from mpc import * +from pylab import * + +D = zeros((27, 31)) +D2 = zeros((27, 31)) + +for z in range(0, 27): + for n in range(0, 31): + try: + D[z, n] = getNucleusMass(getNucleusId(n + z, z)) / amu + D2[z, n] = D[z, n] - (z + n) - z * mass_electron / amu + except: + continue + +# nuclear masses +figure() +im = imshow(ma.masked_array(D, D==0), aspect='equal', interpolation='nearest', origin='lower') +cbar = colorbar(im) +cbar.set_label('Mass [amu]') +xlabel('Neutrons') +ylabel('Protons') +grid() +savefig('testNuclearMass_mass.png') + +# deviation from m = (Z + N) * amu - Z * m_e +figure() +im = imshow(ma.masked_array(D2, D==0), aspect='equal', interpolation='nearest', origin='lower') +cbar = colorbar(im) +cbar.set_label('$\Delta$Mass [amu]') +xlabel('Neutrons') +ylabel('Protons') +grid() +savefig('testNuclearMass_massImprovement.png') \ No newline at end of file From 6fcf28727606690648fac2f4b37c60a8976a7d80 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 16 Apr 2012 10:12:19 +0200 Subject: [PATCH 0056/1298] small changes --- README | 5 ++++- include/mpc/ParticleState.h | 2 +- include/mpc/PhasePoint.h | 2 +- include/mpc/Referenced.h | 10 ++++++++++ include/mpc/Source.h | 8 ++++++++ test/python/testNuclearMass.py | 12 +----------- 6 files changed, 25 insertions(+), 14 deletions(-) diff --git a/README b/README index e3be9d13e..fa5c92430 100644 --- a/README +++ b/README @@ -9,9 +9,12 @@ Dependencies: GNU Scientific Library - for interpolation Optional dependencies: -Python - to use MPC from python +Python and SWIG - to use MPC from python OpenMP - for shared memory parallelization FFTW - for turbulent magnetic field Gadget - for smooth particle large scale structure GTest - for unit-tests +To use MPC from python the following environment variables have to be set. +PYTHONPATH=[path to mpc.py] +MPC_DATA_PATH=[path to mpc/data] diff --git a/include/mpc/ParticleState.h b/include/mpc/ParticleState.h index ec9c715ff..761da0d7f 100644 --- a/include/mpc/ParticleState.h +++ b/include/mpc/ParticleState.h @@ -10,7 +10,7 @@ namespace mpc { /** @class ParticleState - @brief The state defining the particle. + @brief State of the particle: ID, energy, position, direction */ class ParticleState { public: diff --git a/include/mpc/PhasePoint.h b/include/mpc/PhasePoint.h index 7ed86d4c4..e33c0ce50 100644 --- a/include/mpc/PhasePoint.h +++ b/include/mpc/PhasePoint.h @@ -7,7 +7,7 @@ namespace mpc { /** @class PhasePoint - @brief 6D point in (momentum - position) phase space + @brief 6D point in (position - momentum) phase space */ class PhasePoint { public: diff --git a/include/mpc/Referenced.h b/include/mpc/Referenced.h index 8a5c96188..cfbfdb872 100644 --- a/include/mpc/Referenced.h +++ b/include/mpc/Referenced.h @@ -8,6 +8,16 @@ namespace mpc { +/** + @class Referenced + @brief Base class for reference counting + + A form of memory management is needed to prevent memory leaks when using MPC via SWIG. + This base class enables reference counting. + Every reference increases the reference counter, every dereference decreases it. + When the counter is decreased to 0, the object is deleted. + Candidate, Module, MagneticField and Source inherit from this class + */ class Referenced { public: diff --git a/include/mpc/Source.h b/include/mpc/Source.h index f5afc2411..6b28e26f7 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -8,6 +8,10 @@ namespace mpc { +/** + @class Source + @brief Base cosmic ray source + */ class Source: public Referenced { public: virtual ~Source() { @@ -16,6 +20,10 @@ class Source: public Referenced { virtual void prepare(ParticleState &state) const = 0; }; +/** + @class BasicSource + @brief Simple cosmic ray source + */ class BasicSource: public Source { public: Vector3 position; diff --git a/test/python/testNuclearMass.py b/test/python/testNuclearMass.py index 6b9b7976c..294a8148d 100644 --- a/test/python/testNuclearMass.py +++ b/test/python/testNuclearMass.py @@ -20,14 +20,4 @@ xlabel('Neutrons') ylabel('Protons') grid() -savefig('testNuclearMass_mass.png') - -# deviation from m = (Z + N) * amu - Z * m_e -figure() -im = imshow(ma.masked_array(D2, D==0), aspect='equal', interpolation='nearest', origin='lower') -cbar = colorbar(im) -cbar.set_label('$\Delta$Mass [amu]') -xlabel('Neutrons') -ylabel('Protons') -grid() -savefig('testNuclearMass_massImprovement.png') \ No newline at end of file +savefig('NuclearMass_mass.png', bbox_inches='tight') From 9e8240b982027b5738e41d2942e64dbd48c093c4 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 16 Apr 2012 10:12:53 +0200 Subject: [PATCH 0057/1298] add module SophiaPhotoPionProduction --- CMakeLists.txt | 7 +- .../mpc/module/SophiaPhotoPionProduction.h | 46 + libs/sophia/CMakeLists.txt | 11 + libs/sophia/sophia.h | 44 + libs/sophia/sophia_interface.f | 17160 ++++++++++++++++ python/mpc.i | 4 +- src/module/SophiaPhotoPionProduction.cpp | 231 + 7 files changed, 17498 insertions(+), 5 deletions(-) create mode 100644 include/mpc/module/SophiaPhotoPionProduction.h create mode 100644 libs/sophia/CMakeLists.txt create mode 100644 libs/sophia/sophia.h create mode 100644 libs/sophia/sophia_interface.f create mode 100644 src/module/SophiaPhotoPionProduction.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6bc732932..8fada992a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,9 +63,9 @@ list (APPEND MPC_EXTRA_LIBRARIES HepPID) list (APPEND MPC_EXTRA_INCLUDES libs/HepPID/include) # SOPHIA provided -#add_subdirectory(libs/sophia) -#list (APPEND MPC_EXTRA_LIBRARIES sophia) -#list (APPEND MPC_EXTRA_INCLUDES libs/sophia) +add_subdirectory(libs/sophia) +list (APPEND MPC_EXTRA_LIBRARIES sophia gfortran) +list (APPEND MPC_EXTRA_INCLUDES libs/sophia) # OpenMP needed for shared memory multiprocessing include(FindOpenMP) @@ -100,6 +100,7 @@ add_library(mpc SHARED src/module/DeflectionCK.cpp src/module/ElectronPairProduction.cpp src/module/PhotoPionProduction.cpp + src/module/SophiaPhotoPionProduction.cpp src/module/PhotoDisintegration.cpp src/module/NuclearDecay.cpp src/module/Redshift.cpp diff --git a/include/mpc/module/SophiaPhotoPionProduction.h b/include/mpc/module/SophiaPhotoPionProduction.h new file mode 100644 index 000000000..d4b481834 --- /dev/null +++ b/include/mpc/module/SophiaPhotoPionProduction.h @@ -0,0 +1,46 @@ +#ifndef SOPHIAPHOTOPIONPRODUCTION_H_ +#define SOPHIAPHOTOPIONPRODUCTION_H_ + +#include "mpc/Module.h" +#include "mpc/Random.h" + +#include +#include + +namespace mpc { + +/** + @class SophiaPhotoPionProduction + @brief Photo-pion interactions of nuclei with background photons using SOPHIA. + + This module simulates photo-hadronic interactions of nuclei with background photons.\n + Several photon fields can be selected. They are considered as homogeneous and evolving as the CMB.\n + */ +class SophiaPhotoPionProduction: public Module { +public: + enum PhotonField { + CMB, IR + }; + + SophiaPhotoPionProduction(PhotonField photonField); + SophiaPhotoPionProduction(); + ~SophiaPhotoPionProduction(); + void init(PhotonField photonField); + void init(std::string filename); + void process(Candidate *candidate) const; + bool setNextInteraction(Candidate *candidate) const; + void performInteraction(Candidate *candidate) const; + std::string getDescription() const; + +private: + std::string name; + PhotonField photonField; + gsl_interp_accel *acc; + gsl_spline *pRate; // interaction rate in [1/m] for protons + gsl_spline *nRate; // interaction rate in [1/m] for neutrons + double Emin, Emax; +}; + +} // namespace mpc + +#endif /* SOPHIAPHOTOPIONPRODUCTION_H_ */ diff --git a/libs/sophia/CMakeLists.txt b/libs/sophia/CMakeLists.txt new file mode 100644 index 000000000..1e85f5d90 --- /dev/null +++ b/libs/sophia/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 2.6) + +enable_language(Fortran) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +add_library(sophia + sophia_interface.f +) + +set_target_properties(sophia PROPERTIES COMPILE_FLAGS -fPIC) diff --git a/libs/sophia/sophia.h b/libs/sophia/sophia.h new file mode 100644 index 000000000..473174f0b --- /dev/null +++ b/libs/sophia/sophia.h @@ -0,0 +1,44 @@ +#ifndef _SOPHIA_H_ +#define _SOPHIA_H_ + +extern "C" { +void sophiaevent_(int&, double&, double[][2000], int[], int&, double&, int&, + double&, int&, double[], double[]); +} + +/* + The arguments are the following (see sophiaevent.f) : + + - nature, Ein = input nature and energy of the nucleon + nature = 0 -> p ; 1 -> n + Ein : in GeV (Sophia standard energy unit) + - OutPart,OutPartType,NbOutPart = output data, respectively : + P(2000,5) list of 4-momenta + masses of output particles (in GeV) + LList(2000) list of output particle IDs + NP nb of output particles + Particle IDs are : + + cc 13 proton + cc 14 neutron + cc -13 antiproton + cc -14 antineutron + cc 1 photon + cc 2 e+ + cc 3 e- + cc 15 nu_e + cc 16 antinu_e + cc 17 nu_muon + cc 18 antinu_muon + + - z_particle : needed to estimate the CMB temperature or IRB density + - bgFlag = 1 for CMB, 2 for Primack et al. (1999) IRB. NO OTHER REDSHIFT MODEL + IS IMPLEMENTED, AND ITS REDSHIFT EVOLUTION IS "TRIVIAL", ie. same as CMB. + - Zmax_IRB : the photon density of IRB is null above this redshift + + Warning with passing arguments (variables->pointers) in fortran->C ! + + */ + +//#define sophiaevent sophiaevent_ + +#endif diff --git a/libs/sophia/sophia_interface.f b/libs/sophia/sophia_interface.f new file mode 100644 index 000000000..dee16051c --- /dev/null +++ b/libs/sophia/sophia_interface.f @@ -0,0 +1,17160 @@ +c***************************************************************************** +c**!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*** +c**!! IF YOU USE THIS PROGRAM, PLEASE CITE: !!*** +c**!! A.M"ucke, Ralph Engel, J.P.Rachen, R.J.Protheroe and Todor Stanev, !!*** +c**!! 1999, astro-ph/9903478, to appear in Comp.Phys.Commun. !!*** +c**!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*** +c***************************************************************************** +c** Further SOPHIA related papers: *** +c** (1) M"ucke A., et al 1999, astro-ph/9808279, to appear in PASA. *** +c** (2) M"ucke A., et al 1999, to appear in: Proc. of the *** +c** 19th Texas Symposium on Relativistic Astrophysics, Paris, France, *** +c** Dec. 1998. Eds.: J.~Paul, T.~Montmerle \& E.~Aubourg (CEA Saclay) *** +c** (3) M"ucke A., et al 1999, astro-ph/9905153, to appear in: Proc. of *** +c** 19th Texas Symposium on Relativistic Astrophysics, Paris, France, *** +c** Dec. 1998. Eds.: J.~Paul, T.~Montmerle \& E.~Aubourg (CEA Saclay) *** +c** (4) M"ucke A., et al 1999, to appear in: Proc. of 26th Int.Cosmic Ray *** +c** Conf. (Salt Lake City, Utah) *** +c***************************************************************************** + + + subroutine eventgen(L0,E0,eps,theta,Imode) + +c******************************************************* +c** subroutine for photopion production of ** +c** relativistic nucleons in a soft photon field ** +c** subroutine for SOPHIA inVersion 1.2 ** +c****** INPUT ****************************************** +c E0 = energy of incident proton (in lab frame) [in GeV] +c eps = energy of incident photon [in GeV] (in lab frame) +c theta = angle between incident proton and photon [in degrees] +c L0 = code number of the incident nucleon +c****** OUTPUT ************************************************* +c P(2000,5) = 5-momentum of produced particles +c LLIST(2000) = code numbers of produced particles +c NP = number of produced particles +c*************************************************************** +c** Date: 20/01/98 ** +c** correct.:19/02/98 ** +c** change: 23/05/98 ** +c** last change:06/09/98 ** +c** authors: A.Muecke ** +c** R.Engel ** +c************************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + SAVE + + COMMON /S_RUN/ SQS, S, Q2MIN, XMIN, ZMIN, kb, kt, a1, a2, Nproc + COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb + COMMON /S_MASS1/ AM(49), AM2(49) + COMMON /S_CHP/ S_LIFE(49), ICHP(49), ISTR(49), IBAR(49) + COMMON /S_CSYDEC/ CBR(102), IDB(49), KDEC(612), LBARP(49) + + CHARACTER NAMPRES*6 + COMMON /RES_PROP/ AMRES(9), SIG0(9),WIDTH(9), + + NAMPRES(0:9) + + CHARACTER NAMPRESp*6 + COMMON /RES_PROPp/ AMRESp(9), BGAMMAp(9),WIDTHp(9), + + RATIOJp(9),NAMPRESp(0:9) + + CHARACTER NAMPRESn*6 + COMMON /RES_PROPn/ AMRESn(9), BGAMMAn(9),WIDTHn(9), + + RATIOJn(9),NAMPRESn(0:9) + + DOUBLE PRECISION P_nuc(4),P_gam(4),P_sum(4),PC(4),GamBet(4) + + DATA pi /3.141593D0/ + DATA IRESMAX /9/ + DATA Icount / 0 / + +c****** INPUT ************************************************** +c E0 = energy of incident proton (in lab frame) [in GeV] +c eps = energy of incident photon [in GeV] (in lab frame) +c theta = angle between incident proton and photon [in degrees] +c L0 = code number of the incident nucleon +c*************************************************************** +c** calculate eps_prime = photon energy in nuclear rest frame, +c** sqrt(s) = CMF energy of the N\gamma-system + +c... declare stable particles: + +C muons stable +c IDB(4) = -ABS(IDB(4)) +c IDB(5) = -ABS(IDB(5)) +C +C pi+,pi0,pi- stable +c IDB(6) = -ABS(IDB(6)) +c IDB(7) = -ABS(IDB(7)) +c IDB(8) = -ABS(IDB(8)) +C +C Deltas stable +C IDB(40) = -ABS(IDB(40)) +C IDB(41) = -ABS(IDB(41)) +C IDB(42) = -ABS(IDB(42)) +C IDB(43) = -ABS(IDB(43)) +C rho, omega, phi stable +C IDB(25) = -ABS(IDB(25)) +C IDB(26) = -ABS(IDB(26)) +C IDB(27) = -ABS(IDB(27)) +C IDB(32) = -ABS(IDB(32)) +C IDB(33) = -ABS(IDB(33)) +C print *,' WARNING: Deltas, eta, VMs are stable in this version' + +C rho0,omega stable +c IDB(27) = -ABS(IDB(27)) +c IDB(32) = -ABS(IDB(32)) + +C STRANGE PARTICLES: +C kaons stable +c IDB(9) = -ABS(IDB(9)) +c IDB(10) = -ABS(IDB(10)) + +C IDB(11) = -ABS(IDB(11)) +C IDB(12) = -ABS(IDB(12)) +C IDB(21) = -ABS(IDB(21)) +C IDB(22) = -ABS(IDB(22)) +C kaons* stable +c IDB(28) = -ABS(IDB(28)) +c IDB(29) = -ABS(IDB(29)) +c IDB(30) = -ABS(IDB(30)) +c IDB(31) = -ABS(IDB(31)) + +C eta stable +C IDB(23) = -ABS(IDB(23)) + + +C incoming nucleon + pm = AM(L0) + P_nuc(1) = 0.D0 + P_nuc(2) = 0.D0 + P_nuc(3) = SQRT(MAX((E0-pm)*(E0+pm),0.D0)) + P_nuc(4) = E0 +C incoming photon + P_gam(1) = EPS*SIN(theta*pi/180.D0) + P_gam(2) = 0.D0 + P_gam(3) = -EPS*COS(theta*pi/180.D0) + P_gam(4) = EPS + + Esum = P_nuc(4)+P_gam(4) + PXsum = P_nuc(1)+P_gam(1) + PYsum = P_nuc(2)+P_gam(2) + PZsum = P_nuc(3)+P_gam(3) + IQchr = ICHP(1)+ICHP(L0) + IQbar = IBAR(1)+IBAR(L0) + + gammap = E0/pm + xx = 1.D0/gammap + if(gammap.gt.1000.D0) then + betap = 1.D0 - 0.5D0*xx**2 - 0.125D0*xx**4 + else + betap = sqrt(1.D0-xx)*sqrt(1.D0+xx) + endif +c Etot = E0+eps + s = pm*pm + 2.D0*eps*E0*(1.D0-betap*cos(theta*pi/180.D0)) + + sqsm = sqrt(s) + eps_prime = (s-pm*pm)/2.D0/pm + +C calculate Lorentz boots and rotation + P_sum(1) = P_nuc(1)+P_gam(1) + P_sum(2) = P_nuc(2)+P_gam(2) + P_sum(3) = P_nuc(3)+P_gam(3) + P_sum(4) = P_nuc(4)+P_gam(4) +C Lorentz transformation into c.m. system + DO I=1,4 + GamBet(I) = P_sum(I)/sqsm + ENDDO +C calculate rotation angles + IF(GamBet(4).lt.1.d5) then +C transform nucleon vector + GamBet(1) = -GamBet(1) + GamBet(2) = -GamBet(2) + GamBet(3) = -GamBet(3) + CALL PO_ALTRA(GamBet(4),GamBet(1),GamBet(2),GamBet(3), + & P_nuc(1),P_nuc(2),P_nuc(3),P_nuc(4),Ptot, + & PC(1),PC(2),PC(3),PC(4)) + GamBet(1) = -GamBet(1) + GamBet(2) = -GamBet(2) + GamBet(3) = -GamBet(3) +C rotation angle: nucleon moves along +z + COD = PC(3)/Ptot + SID = SQRT(PC(1)**2+PC(2)**2)/Ptot + COF = 1.D0 + SIF = 0.D0 + IF(Ptot*SID.GT.1.D-5) THEN + COF=PC(1)/(SID*Ptot) + SIF=PC(2)/(SID*Ptot) + Anorf=SQRT(COF*COF+SIF*SIF) + COF=COF/Anorf + SIF=SIF/Anorf + ENDIF + else + COD = 1.D0 + SID = 0.D0 + COF = 1.D0 + SIF = 0.D0 + endif + +c... check for threshold: + sth = 1.1646D0 + if (s.lt.sth) then + print*,'input energy below threshold for photopion production !' + print*,'sqrt(s) = ',sqrt(s) + NP = 0 + RETURN + endif + + 200 continue + Icount = Icount+1 + Imode = 0 + +c******************************************************************* +c decide which process occurs: *** +c (1) decay of resonance *** +c (2) direct pion production (interaction of photon with *** +c virtual pions in nucleon cloud) and diffractive scattering *** +c (3) multipion production *** +c******************************************************************* + + call dec_inter3(eps_prime,Imode,L0) + +c********************************************* +c******* PARTICLE PRODUCTION ***************** +c********************************************* +c 42 continue + if (Imode.le.5) then +c... direct/multipion/diffractive scattering production channel: + call GAMMA_H(sqsm,L0,Imode,Ifbad) + if(Ifbad.ne.0) then + print *,' eventgen: simulation of particle production failed' + goto 200 + endif + else if (Imode.eq.6) then +c... Resonances: +c... decide which resonance decays with ID=IRES in list: +c... IRESMAX = number of considered resonances = 9 so far + IRES = 0 + 46 call dec_res2(eps_prime,IRES,IRESMAX,L0) + Nproc = 10+IRES + call dec_proc2(eps_prime,IPROC,IRANGE,IRES,L0) +c 2-particle decay of resonance in CM system: + NP = 2 + call res_decay3(IRES,IPROC,IRANGE,s,L0,nbad) + if (nbad.eq.1) then + print *,' eventgen: event rejected by res_decay3' + goto 46 + endif + call DECSIB + else + print*,'invalid Imode !!' + STOP + endif + +c... consider only stable particles: + 18 istable=0 + do 16 i=1,NP + if (abs(LLIST(i)).lt.10000) then + istable = istable+1 + LLIST(istable) = LLIST(i) + P(istable,1) = P(i,1) + P(istable,2) = P(i,2) + P(istable,3) = P(i,3) + P(istable,4) = P(i,4) + P(istable,5) = P(i,5) + endif + 16 continue + if (NP.gt.istable) then + do i=istable+1,NP + LLIST(i) = 0 + P(i,1) = 0. + P(i,2) = 0. + P(i,3) = 0. + P(i,4) = 0. + P(i,5) = 0. + enddo + endif + NP = istable + +c*********************************************** +c transformation from CM-system to lab-system: * +c*********************************************** + + DO I=1,NP + CALL PO_TRANS(P(I,1),P(I,2),P(I,3),COD,SID,COF,SIF, + & PC(1),PC(2),PC(3)) + PC(4) = P(I,4) + CALL PO_ALTRA(GamBet(4),GamBet(1),GamBet(2),GamBet(3), + & PC(1),PC(2),PC(3),PC(4),Ptot, + & P(I,1),P(I,2),P(I,3),P(I,4)) + ENDDO + +c call check_event(Icount,Esum,PXsum,PYsum,PZsum,IQchr,IQbar,Irej) +c if(Irej.ne.0) then +c print *,' eventgen: event rejected by check_event' +c goto 200 +c endif + + return + + END + + +c***************************** +c*** List of SUBROUTINES ***** +C***************************** + + DOUBLE PRECISION function crossection(x,NDIR,NL0) + + IMPLICIT DOUBLE PRECISION (A-M,O-Z) + IMPLICIT INTEGER (N) + + SAVE + + CHARACTER NAMPRES*6 + COMMON /RES_PROP/ AMRES(9), SIG0(9),WIDTH(9), + + NAMPRES(0:9) + COMMON /S_MASS1/ AM(49), AM2(49) + + DIMENSION sig_res(9) + + external breitwigner, Ef, singleback, twoback + + DATA sth /1.1646D0/ + +c***************************************************** +C calculates crossection of N-gamma-interaction +C (see thesis of J.Rachen, p.45ff and corrections +C report from 27/04/98, 5/05/98, 22/05/98 of J.Rachen) +C***************************************************** +c** Date: 20/01/98 ** +c** correct.:27/04/98** +c** update: 23/05/98 ** +c** author: A.Muecke ** +c********************** +c +c x = eps_prime in GeV + pm = AM(NL0) + s = pm*pm+2.D0*pm*x + + if (s.lt.sth) then + crossection = 0. + RETURN + endif + if (x.gt.10.D0) then +c only multipion production: + cross_res = 0.D0 + cross_dir = 0.D0 + cross_dir1 = 0.D0 + cross_dir2 = 0.D0 + goto 10 + endif + +c**************************** +c RESONANCES: +c**************************** + + cross_res = 0.D0 + + cross_res = breitwigner(SIG0(1),WIDTH(1),AMRES(1),x) + & *Ef(x,0.152D0,0.17D0) + sig_res(1) = cross_res + DO N=2,9 + + sig_res(N) = breitwigner(SIG0(N),WIDTH(N),AMRES(N),x) + & *Ef(x,0.15D0,0.38D0) + cross_res = cross_res + sig_res(N) + + ENDDO + +c**************************** +c DIRECT CHANNEL: +c**************************** + + if((x.gt.0.1D0).and.(x.lt.0.6D0)) then + cross_dir1 = singleback(x) + & + 40.D0*exp(-(x-0.29D0)**2/0.002D0) + & - 15.D0*exp(-(x-0.37D0)**2/0.002D0) + else + cross_dir1 = singleback(x) + endif + cross_dir2 = twoback(x) + + cross_dir = cross_dir1 + cross_dir2 + +c**************************** +c FRAGMENTATION 2: +c**************************** + 10 continue + if (NL0.eq.13) then + cross_frag2 = 80.3D0*Ef(x,0.5D0,0.1D0)*(s**(-0.34D0)) + else if (NL0.eq.14) then + cross_frag2 = 60.2D0*Ef(x,0.5D0,0.1D0)*(s**(-0.34D0)) + endif + +c**************************************************** +c MULTIPION PRODUCTION/FRAGMENTATION 1 CROSS SECTION +c**************************************************** + if (x.gt.0.85D0) then + ss1 = (x-.85D0)/.69D0 + if (NL0.eq.13) then + ss2 = 29.3D0*(s**(-.34D0))+59.3D0*(s**.095D0) + else if (NL0.eq.14) then + ss2 = 26.4D0*(s**(-.34D0))+59.3D0*(s**.095D0) + endif + cs_multidiff = (1.-exp(-ss1))*ss2 + cs_multi = 0.89D0*cs_multidiff + +c**************************** +c DIFFRACTIVE SCATTERING: +c**************************** + + cross_diffr1 = .099D0*cs_multidiff + cross_diffr2 = .011D0*cs_multidiff + cross_diffr = 0.11D0*cs_multidiff + +C*********************************************************************** + + ss1 = ((x-.85D0)**.75D0)/.64D0 + ss2 = 74.1D0*(x**(-.44D0))+62.D0*(s**.08D0) + cs_tmp = 0.96D0*(1.D0-exp(-ss1))*ss2 + cross_diffr1 = 0.14D0*cs_tmp + cross_diffr2 = 0.013D0*cs_tmp + cs_delta = cross_frag2 - (cross_diffr1+cross_diffr2-cross_diffr) + if(cs_delta.lt.0.D0) then + cross_frag2 = 0.D0 + cs_multi = cs_multi+cs_delta + else + cross_frag2 = cs_delta + endif + cross_diffr = cross_diffr1 + cross_diffr2 + cs_multidiff = cs_multi + cross_diffr + +C*********************************************************************** + + + else + cross_diffr = 0.D0 + cross_diffr1 = 0.D0 + cross_diffr2 = 0.D0 + cs_multidiff = 0.D0 + cs_multi = 0.D0 + endif + + if (NDIR.eq.3) then + + crossection = cross_res+cross_dir+cs_multidiff+cross_frag2 + RETURN + + else if (NDIR.eq.0) then + + crossection = cross_res+cross_dir+cross_diffr+cross_frag2 + RETURN + + else if (NDIR.eq.2) then + + crossection = cross_res+cross_dir + RETURN + + else if (NDIR.eq.1) then + + crossection = cross_res + RETURN + + else if (NDIR.eq.4) then + + crossection = cross_dir + RETURN + + else if (NDIR.eq.5) then + + crossection = cs_multi + RETURN + + else if (NDIR.eq.6) then + + crossection = cross_res+cross_dir2 + RETURN + + else if (NDIR.eq.7) then + + crossection = cross_res+cross_dir1 + RETURN + + else if (NDIR.eq.8) then + + crossection = cross_res+cross_dir+cross_diffr1 + RETURN + + else if (NDIR.eq.9) then + + crossection = cross_res+cross_dir+cross_diffr + RETURN + + else if (NDIR.eq.10) then + + crossection = cross_diffr + RETURN + + else if ((NDIR.ge.11).and.(NDIR.le.19)) then + + crossection = sig_res(NDIR-10) + RETURN + + else + + print*,'wrong input NDIR in crossection.f !' + STOP + + endif + + END + + + DOUBLE PRECISION function breitwigner(sigma_0,Gamma, + & DMM,eps_prime) + + IMPLICIT DOUBLE PRECISION (A-M,O-Z) + IMPLICIT INTEGER (N) + + SAVE + +c*************************************************************************** +c calculates Breit-Wigner cross section of a resonance with width Gamma [GeV], +c mass DMM [GeV], max. cross section sigma_0 [mubarn] and total mass of the +c interaction s [GeV] +c*************************************************************************** + pm = 0.93827D0 + s = pm*pm+2.D0*pm*eps_prime + gam2s = Gamma*Gamma*s + breitwigner = sigma_0 + & *(s/eps_prime**2)*gam2s/((s-DMM*DMM)**2+gam2s) + + RETURN + + END + + + DOUBLE PRECISION function Pl(x,xth,xmax,alpha) + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + SAVE + + if (xth.gt.x) then + Pl = 0. + RETURN + endif + + a = alpha*xmax/xth + prod1 = ((x-xth)/(xmax-xth))**(a-alpha) + prod2 = (x/xmax)**(-a) + Pl = prod1*prod2 + + END + + + DOUBLE PRECISION function Ef(x,th,w) + + IMPLICIT DOUBLE PRECISION (A-M,O-Z) + IMPLICIT INTEGER (N) + + SAVE + + wth = w+th + if (x.le.th) then + Ef = 0. + RETURN + else if (x.gt.th.and.x.lt.wth) then + Ef = (x-th)/w + RETURN + else if (x.ge.wth) then + Ef = 1. + RETURN + else + print*,'error in function EF' + STOP + endif + + END + + + + subroutine dec_inter3(eps_prime,Imode,L0) + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + SAVE + + DOUBLE PRECISION RNDM + external RNDM + +c*** decides which process takes place at eps_prime ******** +c (6) excitation/decay of resonance *** +c (2) direct pion production: N\gamma --> N \pi *** +c (3) direct pion production: N\gamma --> \Delta \pi *** +c (1) diffractive scattering: N\gamma --> N \rho *** +c (4) diffractive scattering: N\gamma --> N \omega *** +c (0) multipion production (fragmentation) *** +c (5) fragmentation in resonance region *** +c*********************************************************** +c** Date: 15/04/98 ** +c** author: A.Muecke ** +c********************** + tot = crossection(eps_prime,3,L0) + if (tot.eq.0.) tot = 1.D0 + prob1 = crossection(eps_prime,1,L0)/tot + prob2 = crossection(eps_prime,7,L0)/tot + prob3 = crossection(eps_prime,2,L0)/tot + prob4 = crossection(eps_prime,8,L0)/tot + prob5 = crossection(eps_prime,9,L0)/tot + prob6 = crossection(eps_prime,0,L0)/tot + prob7 = 1.D0 + rn = RNDM(0) + if (rn.lt.prob1) then + Imode = 6 +c ... --> resonance decay + RETURN + else if (prob1.le.rn.and.rn.lt.prob2) then + Imode = 2 +c ... --> direct channel: N\gamma --> N\pi + RETURN + else if (prob2.le.rn.and.rn.lt.prob3) then + Imode = 3 +c ... --> direct channel: N\gamma --> \Delta \pi + RETURN + else if (prob3.le.rn.and.rn.lt.prob4) then + Imode = 1 +c ... --> diffractive scattering: N\gamma --> N \rho + RETURN + else if (prob4.le.rn.and.rn.lt.prob5) then + Imode = 4 +c ... --> diffractive scattering: N\gamma --> N \omega + RETURN + else if (prob5.le.rn.and.rn.lt.prob6) then + Imode = 5 +c ... --> fragmentation (2) in resonance region + return + else if (prob6.le.rn.and.rn.lt.1.D0) then + Imode = 0 +c ... --> fragmentation mode/multipion production + RETURN + else if (rn.eq.1.D0) then + Imode = 0 + RETURN + else + print*,'error in dec_inter.f !' + STOP + endif + + END + + + SUBROUTINE PROC_TWOPART(LA,LB,AMD,Lres,Pres,costheta,nbad) + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + COMMON /S_MASS1/ AM(49), AM2(49) + COMMON /RES_FLAG/ FRES(49),XLIMRES(49) + SAVE + DIMENSION Pres(2000,5),Lres(2000) + +c*********************************************************** +c 2-particle decay of CMF mass AMD INTO M1 + M2 +C NUCLEON ENERGY E0 [in GeV]; +C E1,E2 [in GeV] are energies of decay products +c LA,LB are code numbers of decay products +c P1(1:5),P2(1:5) are 5-momenta of particles LA,LB; +c resulting momenta are calculated in CM frame; +c costheta is cos of scattering angle in CM frame +c this program also checks if the resulting particles are +c resonances; if yes, it is also allowed to decay a +c mass AMD < M1 + M2 by using the width of the resonance(s) +c*********************************************************** +c** Date: 20/01/98 ** +c** correct.:19/02/98** +c** author: A.Muecke ** +c********************** + + nbad = 0 + SM1 = AM(LA) + if (LB.eq.0) then + SM2 = 2.D0*AM(7) + else + SM2 = AM(LB) + endif + E1 = (AMD*AMD + SM1*SM1 - SM2*SM2)/AMD/2.D0 + E2 = (AMD*AMD + SM2*SM2 - SM1*SM1)/AMD/2.D0 +c... check if SM1+SM2 < AMD: + if ((SM1+SM2).gt.AMD) then +c... if one of the decay products is a resonance, this 'problem' can +c be solved by using a reduced mass for the resonance and assume that +c this resonance is produced at its threshold; + if (FRES(LA).eq.1.D0) then +c ... particle LA is a resonance: + SM1 = AMD-SM2 + E1 = SM1 + E2 = AMD-E1 + if (E1.lt.XLIMRES(LA).or.E2.lt.XLIMRES(LB)) nbad = 1 + endif + if (FRES(LB).eq.1.D0) then +c ... particle LB is a resonance: + SM2 = AMD-SM1 + E2 = SM2 + E1 = AMD-E2 + if (E1.lt.XLIMRES(LA).or.E2.lt.XLIMRES(LB)) nbad = 1 + endif +c ... both particles are NOT resonances: -> error ! + if (FRES(LA).eq.0.D0.and.FRES(LB).eq.0.D0) then + print*,'SM1 + SM2 > AMD in PROC_TWOPART',SM1,SM2,AMD,LA,LB + STOP + endif + endif + + if (nbad.eq.0) then + PC = SQRT((E1*E1 - SM1*SM1)) + Pres(1,4) = E1 + Pres(2,4) = E2 + Pres(1,5) = SM1 + Pres(2,5) = SM2 + + +C ********************************************************* +c theta is scattering angle in CM frame: + r = RNDM(0) + P1Z= PC*costheta + P2Z=-PC*costheta + + P1X = sqrt(r*(PC*PC-P1Z*P1Z)) + P2X = sqrt(r*(PC*PC-P2Z*P2Z)) + P1Y = sqrt((1.D0-r)*(PC*PC-P1Z*P1Z)) + P2Y = sqrt((1.D0-r)*(PC*PC-P2Z*P2Z)) + if(RNDM(0).lt.0.5D0) then + P1X = -P1X + else + P2X = -P2X + endif + if(RNDM(0).lt.0.5D0) then + P1Y = -P1Y + else + P2Y = -P2Y + endif + + Pres(1,1) = P1X + Pres(1,2) = P1Y + Pres(1,3) = P1Z + Pres(2,1) = P2X + Pres(2,2) = P2Y + Pres(2,3) = P2Z + Lres(1) = LA + Lres(2) = LB + endif + + RETURN + + END + + + subroutine dec_res2(eps_prime,IRES,IRESMAX,L0) + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + SAVE + +c***************************************************************************** +c*** decides which resonance with ID=IRES in list takes place at eps_prime *** +c***************************************************************************** +c** Date: 20/01/98 ** +c** author: A.Muecke ** +c********************** + + DIMENSION prob_sum(9) + + +c*** sum of all resonances: + sumres = 0.D0 + do 12 j=1,IRESMAX + j10 = j+10 + sumres = sumres+crossection(eps_prime,j10,L0) + prob_sum(j) = sumres + 12 continue + + + r = RNDM(0) + + IRES = 0 + i = 0 + prob = 0.D0 + 10 continue + i = i+1 + probold = prob + prob = prob_sum(i)/sumres + if (r.ge.probold.and.r.lt.prob) then + IRES = i + RETURN + endif + if (i.lt.IRESMAX) goto 10 + if (r.eq.1.D0) IRES = i + if (IRES.eq.0) then + print*,'no resonance possible !' + STOP + endif + + RETURN + + END + + + subroutine dec_proc2(x,IPROC,IRANGE,IRES,L0) + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + SAVE + +c********************************************************************** +c*** decide which decay with ID=IPROC of resonance IRES takes place *** +c********************************************************************** +c** Date: 20/01/98 ** +c** correct.: 27/04/98* +c** author: A.Muecke ** +c********************** + + COMMON /S_RESp/ CBRRES1p(18),CBRRES2p(36),CBRRES3p(26), + + RESLIMp(36),ELIMITSp(9),KDECRES1p(90),KDECRES2p(180), + + KDECRES3p(130),IDBRES1p(9),IDBRES2p(9),IDBRES3p(9) + COMMON /S_RESn/ CBRRES1n(18),CBRRES2n(36),CBRRES3n(22), + + RESLIMn(36),ELIMITSn(9),KDECRES1n(90),KDECRES2n(180), + + KDECRES3n(110),IDBRES1n(9),IDBRES2n(9),IDBRES3n(9) + DIMENSION prob_sum(0:9) + +c x = eps_prime +c ... choose arrays /S_RESp/ for charged resonances, +c ... arrays /S_RESn/ for neutral resonances + if (L0.eq.13) then +c ... charged resonances: + + r = RNDM(0) +c... determine the energy range of the resonance: + nlim = ELIMITSp(IRES) + istart = (IRES-1)*4+1 + if (nlim.gt.0) then + do ie=istart,nlim-2+istart + reslimp1 = RESLIMp(ie) + reslimp2 = RESLIMp(ie+1) + if (x.le.reslimp2.and.x.gt.reslimp1) then + IRANGE = ie+1-istart + endif + enddo + else + irange = 1 + 13 endif + + + + IPROC = -1 + i = 0 + prob_sum(0) = 0.D0 + + if (IRANGE.eq.1) then + j = IDBRES1p(IRES)-1 + if (j.eq.-1) then + print*,'invalid resonance in energy range 1' + endif + 10 continue + j = j+1 + i = i+1 + prob_sum(i) = CBRRES1p(j) + if (r.ge.prob_sum(i-1).and.r.lt.prob_sum(i)) then + IPROC = j + endif + if (prob_sum(i).lt.1.D0) goto 10 + if (r.eq.1.D0) IPROC = j + if (IPROC.eq.-1) then + print*,'no resonance decay possible !' + endif + + else if (IRANGE.eq.2) then + j = IDBRES2p(IRES)-1 + if (j.eq.-1) then + print*,'invalid resonance in energy range 2' + endif + 11 continue + j = j+1 + i = i+1 + prob_sum(i) = CBRRES2p(j) + if (r.ge.prob_sum(i-1).and.r.lt.prob_sum(i)) then + IPROC = j + endif + if (prob_sum(i).lt.1.D0) goto 11 + if (r.eq.1.D0) IPROC = j + if (IPROC.eq.-1) then + print*,'no resonance decay possible !' + endif + + else if (IRANGE.eq.3) then + j = IDBRES3p(IRES)-1 + if (j.eq.-1) then + print*,'invalid resonance in energy range 3' + endif + 12 continue + j = j+1 + i = i+1 + prob_sum(i) = CBRRES3p(j) + if (r.ge.prob_sum(i-1).and.r.lt.prob_sum(i)) then + IPROC = j + endif + if (prob_sum(i).lt.1.D0) goto 12 + if (r.eq.1.D0) IPROC = j + if (IPROC.eq.-1) then + print*,'no resonance decay possible !' + endif + + else + print*,'invalid IRANGE in DEC_PROC2' + endif + + RETURN + + + else if (L0.eq.14) then +c ... neutral resonances: + + r = RNDM(0) +c... determine the energy range of the resonance: + nlim = ELIMITSn(IRES) + istart = (IRES-1)*4+1 + if (nlim.gt.0) then + do ie=istart,nlim-2+istart + if (x.le.RESLIMn(ie+1).and.x.gt.RESLIMn(ie)) then + IRANGE = ie+1-istart + endif + enddo + else + irange = 1 + endif + + + IPROC = -1 + i = 0 + prob_sum(0) = 0.D0 + + if (IRANGE.eq.1) then + j = IDBRES1n(IRES)-1 + if (j.eq.-1) then + print*,'invalid resonance in this energy range' + endif + 20 continue + j = j+1 + i = i+1 + prob_sum(i) = CBRRES1n(j) + if (r.ge.prob_sum(i-1).and.r.lt.prob_sum(i)) then + IPROC = j + endif + if (prob_sum(i).lt.1.D0) goto 20 + if (r.eq.1.D0) IPROC = j + if (IPROC.eq.-1) then + print*,'no resonance decay possible !' + endif + + else if (IRANGE.eq.2) then + j = IDBRES2n(IRES)-1 + if (j.eq.-1) then + print*,'invalid resonance in this energy range' + endif + 21 continue + j = j+1 + i = i+1 + prob_sum(i) = CBRRES2n(j) + if (r.ge.prob_sum(i-1).and.r.lt.prob_sum(i)) then + IPROC = j + endif + if (prob_sum(i).lt.1.D0) goto 21 + if (r.eq.1.) IPROC = j + if (IPROC.eq.-1) then + print*,'no resonance decay possible !' + endif + + else if (IRANGE.eq.3) then + j = IDBRES3n(IRES)-1 + if (j.eq.-1) then + print*,'invalid resonance in this energy range' + endif + 22 continue + j = j+1 + i = i+1 + prob_sum(i) = CBRRES3n(j) + if (r.ge.prob_sum(i-1).and.r.lt.prob_sum(i)) then + IPROC = j + endif + if (prob_sum(i).lt.1.D0) goto 22 + if (r.eq.1.D0) IPROC = j + if (IPROC.eq.-1) then + print*,'no resonance decay possible !' + endif + + else + print*,'invalid IRANGE in DEC_PROC2' + endif + + RETURN + + else + print*,'no valid L0 in DEC_PROC !' + STOP + endif + + END + + + SUBROUTINE RES_DECAY3(IRES,IPROC,IRANGE,s,L0,nbad) + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + SAVE + + COMMON /S_RESp/ CBRRES1p(18),CBRRES2p(36),CBRRES3p(26), + + RESLIMp(36),ELIMITSp(9),KDECRES1p(90),KDECRES2p(180), + + KDECRES3p(130),IDBRES1p(9),IDBRES2p(9),IDBRES3p(9) + COMMON /S_RESn/ CBRRES1n(18),CBRRES2n(36),CBRRES3n(22), + + RESLIMn(36),ELIMITSn(9),KDECRES1n(90),KDECRES2n(180), + + KDECRES3n(110),IDBRES1n(9),IDBRES2n(9),IDBRES3n(9) + COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb +c COMMON /S_CNAM/ NAMP (0:49) +c CHARACTER NAMP*6, NAMPRESp*6, NAMPRESn*6 + +* external scatangle, proc_twopart + +c******************************************************** +c RESONANCE AMD with code number IRES INTO M1 + M2 +C PROTON ENERGY E0 [in GeV] IN DMM [in GeV] +C E1,E2 [in GeV] are energies of decay products +c LA,LB are code numbers of decay products +c P(1,1:5),P(2,1:5) are 5-momenta of particles LA,LB; +c resulting momenta are calculated in CM frame; +c ANGLESCAT is cos of scattering angle in CM frame +c******************************************************** +c** Date: 20/01/98 ** +c** correct.:28/04/98** +c** author: A.Muecke ** +c********************** + +c... determine decay products LA, LB: + NP = 2 + if (L0.eq.13) then +c ... proton is incident nucleon: + if (IRANGE.eq.1) then + LA = KDECRES1p(5*(IPROC-1)+3) + LB = KDECRES1p(5*(IPROC-1)+4) + else if (IRANGE.eq.2) then + LA = KDECRES2p(5*(IPROC-1)+3) + LB = KDECRES2p(5*(IPROC-1)+4) + else if (IRANGE.eq.3) then + LA = KDECRES3p(5*(IPROC-1)+3) + LB = KDECRES3p(5*(IPROC-1)+4) + else + print*,'error in res_decay3' + endif + else if (L0.eq.14) then +c ... neutron is incident nucleon: + if (IRANGE.eq.1) then + LA = KDECRES1n(5*(IPROC-1)+3) + LB = KDECRES1n(5*(IPROC-1)+4) + else if (IRANGE.eq.2) then + LA = KDECRES2n(5*(IPROC-1)+3) + LB = KDECRES2n(5*(IPROC-1)+4) + else if (IRANGE.eq.3) then + LA = KDECRES3n(5*(IPROC-1)+3) + LB = KDECRES3n(5*(IPROC-1)+4) + else + print*,'error in res_decay3' + endif + + else + print*,'no valid L0 in RES_DECAY' + STOP + endif + + LLIST(1) = LA + LLIST(2) = LB + +c... sample scattering angle: + call scatangle(anglescat,IRES,L0) + +c ... 2-particle decay: + call proc_twopart(LA,LB,sqrt(s),LLIST,P,anglescat,nbad) + + RETURN + + END + +c*********************************************************** +C calculates functions for crossection of direct channel +c NOT isospin-corrected, simply a samelsurium of functions +c x is eps_prime in GeV (see main program) +C (see thesis of J.Rachen, p.45ff) +c note: neglect strange- and eta-channel +C*********************************************************** +c** Date: 27/04/98 ** +c** last chg:23/05/98** +c** author: A.Muecke ** +c********************** +c + + DOUBLE PRECISION FUNCTION singleback(x) +c**************************** +c SINGLE PION CHANNEL +c**************************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + SAVE + singleback = 92.7D0*Pl(x,.152D0,.25D0,2.D0) + + END + + + DOUBLE PRECISION FUNCTION twoback(x) +c***************************** +c TWO PION PRODUCTION +c***************************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + SAVE + twoback = 37.7D0*Pl(x,.4D0,.6D0,2.D0) + + END + + + subroutine scatangle(anglescat,IRES,L0) + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + SAVE + +c******************************************************************* +c This routine samples the cos of the scattering angle for a given * +c resonance IRES and incident nucleon L0; it is exact for ** +c one-pion decay channel and if there is no ** +c other contribution to the cross section from another resonance ** +c and an approximation for an overlay of resonances; ** +c for decay channels other than the one-pion decay a isotropic ** +c distribution is used ** +c******************************************************************* +c** Date: 16/02/98 ** +c** author: A.Muecke ** +c********************** + + COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb + +c ... use rejection method for sampling: + LA = LLIST(1) + LB = LLIST(2) + 10 continue + r = RNDM(0) +c*** sample anglescat random between -1 ... 1 ** + anglescat = 2.D0*(r-0.5D0) +c ... distribution is isotropic for other than one-pion decays: + if ((LA.eq.13.or.LA.eq.14).and.LB.ge.6.and.LB.le.8) then + prob = probangle(IRES,L0,anglescat) + else + prob = 0.5D0 + endif + r = RNDM(0) + if (r.le.prob) then + RETURN + else + goto 10 + endif + 12 continue + + END + + DOUBLE PRECISION function probangle(IRES,L0,z) + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + SAVE + +c******************************************************************** +c probability distribution for scattering angle of given resonance ** +c IRES and incident nucleon L0 ; ** +c z is cosine of scattering angle in CMF frame ** +c******************************************************************** + + if (IRES.eq.4.or.IRES.eq.5.or.IRES.eq.2) then +c ... N1535 andf N1650 decay isotropically. + probangle = 0.5D0 + return + endif + + if (IRES.eq.1) then +c ... for D1232: + probangle = 0.636263D0 - 0.408790D0*z*z + return + endif + + if (IRES.eq.3.and.L0.eq.14) then +c ... for N1520 and incident n: + probangle = 0.673669D0 - 0.521007D0*z*z + return + endif + + if (IRES.eq.3.and.L0.eq.13) then +c ... for N1520 and incident p: + probangle = 0.739763D0 - 0.719288D0*z*z + return + endif + + if (IRES.eq.6.and.L0.eq.14) then +c ... for N1680 (more precisely: N1675) and incident n: + q=z*z + probangle = 0.254005D0 + 1.427918D0*q - 1.149888D0*q*q + return + endif + + + if (IRES.eq.6.and.L0.eq.13) then +c ... for N1680 and incident p: + q=z*z + probangle = 0.189855D0 + 2.582610D0*q - 2.753625D0*q*q + return + endif + + if (IRES.eq.7) then +c ... for D1700: + probangle = 0.450238D0 + 0.149285D0*z*z + return + endif + + + if (IRES.eq.8) then +c ... for D1905: + q=z*z + probangle = 0.230034D0 + 1.859396D0*q - 1.749161D0*q*q + return + endif + + + if (IRES.eq.9) then +c ... for D1950: + q=z*z + probangle = 0.397430D0 - 1.498240D0*q + 5.880814D0*q*q + & - 4.019252D0*q*q*q + return + endif + + print*,'error in function probangle !' + STOP + END + +C-> + DOUBLE PRECISION FUNCTION GAUSS (FUN, A,B) +c********************************************************* +C Returns the 8 points Gauss-Legendre integral +C of function FUN from A to B +c this routine was provided by T.Stanev +c********************************************************* +c** Date: 20/01/98 ** +c** A.Muecke ** +c********************** + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) +c SAVE c modified Sept 2005 because of recursive calls in Total_rate_ir + + EXTERNAL FUN + +C........................................................... + DIMENSION X(8), W(8) + DATA X /.0950125098D0,.2816035507D0,.4580167776D0,.6178762444D0 + + ,.7554044083D0,.8656312023D0,.9445750230D0,.9894009349D0/ + DATA W /.1894506104D0,.1826034150D0,.1691565193D0,.1495959888D0 + + ,.1246289712D0,.0951585116D0,.0622535239D0, .0271524594D0/ + + XM = 0.5D0*(B+A) + XR = 0.5D0*(B-A) + SS = 0.D0 + DO NJ=1,8 + DX = XR*X(NJ) + SS = SS + W(NJ) * (FUN(XM+DX) + FUN(XM-DX)) + ENDDO + GAUSS = XR*SS + RETURN + END + + + + + +C-> +c*************************** +c** last change: 12/10/98 ** +c** author: A.Muecke ** +c*************************** + BLOCK DATA DATDEC + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + SAVE + COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb + COMMON /S_CSYDEC/ CBR(102), IDB(49), KDEC(612), LBARP(49) + COMMON /S_MASS1/ AM(49), AM2(49) + COMMON /S_CHP/ S_LIFE(49), ICHP(49), ISTR(49), IBAR(49) + COMMON /S_CNAM/ NAMP (0:49) + + CHARACTER NAMPRESp*6 + COMMON /RES_PROPp/ AMRESp(9), BGAMMAp(9),WIDTHp(9), + + RATIOJp(9),NAMPRESp(0:9) + + CHARACTER NAMPRESn*6 + COMMON /RES_PROPn/ AMRESn(9), BGAMMAn(9),WIDTHn(9), + + RATIOJn(9),NAMPRESn(0:9) + + COMMON /S_RESp/ CBRRES1p(18),CBRRES2p(36),CBRRES3p(26), + + RESLIMp(36),ELIMITSp(9),KDECRES1p(90),KDECRES2p(180), + + KDECRES3p(130),IDBRES1p(9),IDBRES2p(9),IDBRES3p(9) + COMMON /S_RESn/ CBRRES1n(18),CBRRES2n(36),CBRRES3n(22), + + RESLIMn(36),ELIMITSn(9),KDECRES1n(90),KDECRES2n(180), + + KDECRES3n(110),IDBRES1n(9),IDBRES2n(9),IDBRES3n(9) + COMMON /RES_FLAG/ FRES(49),XLIMRES(49) + CHARACTER NAMP*6 + + DATA Ideb / 0 / + + DATA FRES /0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + + 1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,1/ + DATA XLIMRES /0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0. + + ,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., + + .275,.275,.28,0.,0.,0.,0.,.41,.9954,0.,0.,0.,0.,0.,0., + + 1.078,1.08,1.078,1.08,0,0,0,0,0,1/ + DATA AMRESp / 1.231,1.440,1.515,1.525,1.675,1.680,1.690, + + 1.895,1.950/ + DATA AMRESn / 1.231,1.440,1.515,1.525,1.675,1.675,1.690, + + 1.895,1.950/ + DATA IDBRES1p / + + 1,3,5,7,9,11,13,15,17/ + DATA IDBRES2p / + + 0,1,6,11,14,19,24,27,32/ + DATA IDBRES3p / + + 0,0,1,0,3,9,16,21,26/ + DATA IDBRES1n / + + 1,3,5,7,9,11,13,15,17/ + DATA IDBRES2n / + + 0,1,6,11,14,19,24,27,32/ + DATA IDBRES3n / + + 0,0,1,0,3,0,9,14,19/ + + DATA CBRRES1p / + + .667,1.,.667,1.,.667,1.,.667,1.,.667,1.,.667,1.,.667,1., + + .667,1.,.667,1./ + DATA CBRRES1n / + + .667,1.,.667,1.,.667,1.,.667,1.,.667,1.,.667,1.,.667,1., + + .667,1.,.667,1./ +C************************** settings of versions 1.4 - 2.0 ********* + DATA CBRRES2p / + + .333,.5,.750,.917,1.,.333,.5,.75,.917,1.,.167,.25,1., + + .567,.85,.925,.975,1.,.433,.65,.825,.942,1.,.4,.467,1., + + .267,.4,.64,.68,1.,.4,.6,.76,.787,1./ + DATA CBRRES2n / + + .333,.5,.750,.917,1.,.333,.5,.75,.917,1.,.167,.25,1., + + .567,.85,.925,.975,1.,.267,.4,.7,.9,1.,.4,.467,1., + + .267,.4,.64,.68,1.,.4,.6,.76,.787,1./ + DATA CBRRES3p / + + .333,1.,.467,.7,.775,.825,.85,1.,.367,.55,.7, + + 1.,.08,.093,.2,.733,1.,.667,1., + + .2,.3,.46,.487,.7,.9,1./ + DATA CBRRES3n / + + .333,1.,.467,.7,.775,.825,.85,1., + + .08,.093,.2,.733,1.,.667,1., + + .2,.3,.46,.487,.7,.9,1./ + DATA KDECRES1p / + + 2,0,13,6,0,2,0,14,7,0,2,0,14,7,0,2,0,13,6,0,2,0,14,7,0, + + 2,0,13,6,0,2,0,14,7,0,2,0,13,6,0,2,0,14,7,0,2,0,13,6,0, + + 2,0,14,7,0,2,0,13,6,0,2,0,13,6,0,2,0,14,7,0,2,0,13,6,0, + + 2,0,14,7,0,2,0,13,6,0,2,0,14,7,0/ + DATA KDECRES2p / + + 2,0,14,7,0,2,0,13,6,0,2,0,40,8,0,2,0,41,6,0,2,0,42,7,0, + + 2,0,14,7,0,2,0,13,6,0,2,0,40,8,0,2,0,41,6,0,2,0,42,7,0, + + 2,0,14,7,0,2,0,13,6,0,2,0,13,23,0,2,0,14,7,0,2,0,13,6,0, + + 2,0,40,8,0,2,0,41,6,0,2,0,42,7,0, + + 2,0,14,7,0,2,0,13,6,0,2,0,40,8,0,2,0,41,6,0,2,0,42,7,0, + + 2,0,40,8,0,2,0,41,6,0,2,0,42,7,0, + + 2,0,13,6,0,2,0,14,7,0,2,0,40,8,0,2,0,41,6,0,2,0,42,7,0, + + 2,0,13,6,0,2,0,14,7,0,2,0,40,8,0,2,0,41,6,0,2,0,42,7,0/ + DATA KDECRES3p / + + 2,0,13,27,0,2,0,14,25,0, + + 2,0,14,7,0,2,0,13,6,0,2,0,40,8,0,2,0,41,6,0,2,0,42,7,0, + + 2,0,39,9,0, + + 2,0,14,7,0,2,0,13,6,0, + + 2,0,13,27,0,2,0,14,25,0,2,0,40,8,0,2,0,41,6,0,2,0,42,7,0, + + 2,0,13,27,0,2,0,14,25,0, + + 2,0,13,27,0,2,0,14,25,0, + + 2,0,13,6,0,2,0,14,7,0, + + 2,0,40,8,0,2,0,41,6,0,2,0,42,7,0,2,0,13,27,0,2,0,14,25,0/ + DATA KDECRES1n / + + 2,0,14,6,0,2,0,13,8,0,2,0,13,8,0,2,0,14,6,0,2,0,13,8,0, + + 2,0,14,6,0,2,0,13,8,0,2,0,14,6,0,2,0,13,8,0,2,0,14,6,0, + + 2,0,13,8,0,2,0,14,6,0,2,0,14,6,0,2,0,13,8,0,2,0,14,6,0, + + 2,0,13,8,0,2,0,14,6,0,2,0,13,8,0/ + DATA KDECRES2n / + + 2,0,13,8,0,2,0,14,6,0,2,0,43,7,0,2,0,42,6,0,2,0,41,8,0, + + 2,0,13,8,0,2,0,14,6,0,2,0,43,7,0,2,0,42,6,0,2,0,41,8,0, + + 2,0,13,8,0,2,0,14,6,0,2,0,14,23,0,2,0,13,8,0,2,0,14,6,0, + + 2,0,43,7,0,2,0,42,6,0,2,0,41,8,0, + + 2,0,13,8,0,2,0,14,6,0,2,0,43,7,0,2,0,42,6,0,2,0,41,8,0, + + 2,0,43,7,0,2,0,42,6,0,2,0,41,8,0, + + 2,0,14,6,0,2,0,13,8,0,2,0,43,7,0,2,0,42,6,0,2,0,41,8,0, + + 2,0,14,6,0,2,0,13,8,0,2,0,43,7,0,2,0,42,6,0,2,0,41,8,0/ + DATA KDECRES3n / + + 2,0,14,27,0,2,0,13,26,0, + + 2,0,13,8,0,2,0,14,6,0,2,0,43,7,0,2,0,42,6,0,2,0,41,8,0, + + 2,0,39,21,0, + + 2,0,43,7,0,2,0,42,6,0,2,0,41,8,0, + + 2,0,14,27,0,2,0,13,26,0, + + 2,0,14,27,0,2,0,13,26,0, + + 2,0,14,6,0,2,0,13,8,0, + + 2,0,43,7,0,2,0,42,6,0,2,0,41,8,0,2,0,14,27,0,2,0,13,26,0/ + DATA RESLIMp / + + 0.,0.,0.,0.,0.,.54,10.,0.,0.,.54,1.09,10., + + 0.,.71,10.,0.,0.,.54,.918,10., + + 0.,.54,1.09,10.,0.,.54,1.09,10., + + 0.,.54,1.09,10.,0.,.54,1.09,10./ + DATA RESLIMn / + + 0.,.0,.0,.0,0.,.54,10.,0.,0.,.54,1.09,10., + + 0.,.71,10.,0.,0.,.54,.918,10., + + 0.,.54,10.,0.,0.,.54,1.09,10.,0.,.54,1.09,10., + + 0.,.54,1.09,10./ + DATA ELIMITSp /0,3,4,3,4,4,4,4,4/ + DATA ELIMITSn /0,3,4,3,4,3,4,4,4/ + DATA NAMPRESp / + + ' ','D+1232','N+1440','N+1520','N+1535','N+1650', + + 'N+1680','D+1700','D+1905','D+1950'/ + DATA NAMPRESn / + + ' ','D01232','N01440','N01520','N01535','N01650', + + 'N01675','D01700','D01905','D01950'/ + DATA BGAMMAp / + + 5.6,0.5,4.6,2.5,1.0,2.1,2.0,0.2,1.0/ + DATA RATIOJp / + + 1.,0.5,1.,0.5,0.5,1.5,1.,1.5,2./ + DATA WIDTHp / + + .11,.35,.11,.10,.16,.125,.29,.35,.3/ + DATA BGAMMAn / + + 6.1,0.3,4.0,2.5,0.,0.2,2.0,0.2,1.0/ + DATA RATIOJn / + + 1.,0.5,1.,0.5,0.5,1.5,1.,1.5,2./ + DATA WIDTHn / + + .11,.35,.11,.10,.16,.15,.29,.35,.3/ + + + DATA CBR /3*1.,0.,1.,1.,0.6351,0.8468,0.9027,0.9200,0.9518,1., + + 0.6351,0.8468,0.9027,0.9200,0.9518,1.,0.2160,0.3398,0.4748, + + 0.6098,0.8049,1.,0.6861,1.,3*0.,0.5,1.,0.5,1., + + 0.3890,0.7080,0.9440,0.9930,1.,0.,0.4420,0.6470,0.9470,0.9770, + + 0.9990,4*1.,0.6670,1.,9*0.,0.6670,1.,0.6670,1.,0.6670,1., + + 0.8880,0.9730,1.,0.4950,0.8390,0.9870,1.,0.5160,5*1.,0.6410,1., + + 1.,0.67,1.,0.33,1.,1.,0.88,0.94,1.,0.88,0.94,1.,0.88,0.94,1., + + 0.33,1.,0.67,1.,0.678,0.914,1./ + DATA AM / 0.,2*0.511E-3, 2*0.10566, 0.13497, 2*0.13957, + + 2*0.49365, 2*0.49767, 0.93827, 0.93957, 4*0.,0.93827, + + 0.93957, 2*0.49767, 0.54880,0.95750,2*0.76830,0.76860, + + 2*0.89183,2*0.89610,0.78195,1.01941,1.18937,1.19255, + + 1.19743,1.31490,1.32132,1.11563,1.23100,1.23500, + + 1.23400,1.23300,1.38280,1.38370,1.38720, + + 1.53180,1.53500,1.67243 / + DATA AM2 /0.,2*2.61121E-07,2*0.011164,0.018217,0.019480, + + 0.019480,0.243690,0.243690,0.247675,0.247675,0.880351,0.882792, + + 0.000000,0.000000,0.000000,0.000000,0.880351,0.882792,0.247675, + + 0.247675,0.301181,0.916806,0.590285,0.590285,0.590746,0.795361, + + 0.795361,0.802995,0.802995,0.611446,1.039197,1.414601,1.422176, + + 1.433839,1.728962,1.745887,1.244630,1.515361,1.525225,1.522765, + + 1.520289,1.912136,1.914626,1.924324,2.346411,2.356225,2.797022/ + DATA IDB / + + 0,0,0,1,2,3,5,6,7,13,19,25,8*0,30,32,34,40,46,47,48,49,60,62, + + 64,66,69,73,75,76,77,78,79,81,82,84,86,87,90,93,96,98,100/ + DATA KDEC / + + 3,1,15,2,18,0,3,1,16,3,17,0,2,0,1,1,8*0,2,0,4,17,0,0,2,0,5,18,0, + + 0,2,0,4,17,0,0,2,0,7,6,0,0,3,0,7,7,8,0,3,0,7,6,6,0,3,1,17,4,6,0, + + 3,1,15,2,6,0,2,0,5,18,0,0,2,0,8,6,0,0,3,0,8,8,7,0,3,0,8,6,6,0,3, + + 1,18,5,6,0,3,1,16,3,6,0,3,0,6,6,6,0,3,0,7,8,6,0,3,1,18,5,7,0,3, + + 1,17,4,8,0,3,1,16,3,7,0,3,1,15,2,8,0,2,0,7,8,0,0,2,0,6,6,20*0,1, + + 0,11,3*0,1,0,12,0,0,0,1,0,11,0,0,0,1,0,12,0,0,0,2,0,1,1,0,0,3,0, + + 6,6,6,0,3,0,7,8,6,0,3,0,1,7,8,0,3,0,1,3,2,7*0,3,0,7,8,23,0,3,0,6 + + ,6,23,0,2,0,1,27,0,0,2,0,1,32,0,0,2,0,1,1,0,0,3,0,6,6,6,0,2,0,7, + + 6,0,0,2,0,8,6,0,0,2,0,7,8,0,0,2,0,21,7,0,0,2,0,9,6,0,0,54*0,2,0, + + 22,8,0,0,2,0,10,6,0,0,2,0,9,8,0,0,2,0,21,6,0,0,2,0,10,7,0,0, + + 2,0,22,6,0,0,3,0,7,8,6,0,2,0,1,6,0,0,2,0,7,8,0,0,2,0,9,10,0, + + 0,2,0,11,12,0,0,3,0,7, + + 8,6,0,2,0,1,23,0,0,2,0,13,6,0,0,2,0,14,7,0,0,2,0,39,1,0,0,2, + + 0,14,8,0,0,2,0,39,6,0,0,2,0,39,8,0,0,2,0,13,8,0,0,2,0, + + 14,6,0,0,2,0,13,7,0,0,2,0,13,6, + + 0,0,2,0,14,7,0,0,2,0,13,8,0,0,2,0,14,6,0,0,2,0,14,8,0,0,2,0, + + 39,7,0,0,2,0,34,6,0,0,2,0,35,7,0,0,2,0,39,6,0,0,2,0,34,8,0,0, + + 2,0,36,7,0,0,2,0,39,8,0,0,2, + + 0,35,8,0,0,2,0,36,6,0,0,2,0,37,6,0,0,2,0,38,7,0,0,2,0, + + 37,8,0,0,2,0,38,6,0,0,2,0,39,10,0,0,2,0,37,8,0,0,2,0,38,6,0,0/ + DATA LBARP/1,3,2,5,4,6,8,7,10,9,11,12,-13,-14,16,15,18,17,13,14, + + 22,21,23,24,26,25,27,29,28,31,30,32,33,-34,-35,-36,-37,-38,-39, + + -40,-41,-42,-43,-44,-45,-46,-47,-48,-49/ + DATA ICHP /0,1,-1,1,-1,0,1,-1,1,-1,0,0,1,0,4*0,-1,0,4*0, + + 1,-1,0,1,-1,4*0,1,0,-1,0,-1,0,2,1,0,-1,1,0,-1,0,-1,-1/ + DATA ISTR /8*0,-1,+1,10,10,8*0,-1,+1,5*0,-1,+1,-1,+1,2*0, + + 3*1,2*2,1,4*0,3*1,2*2,3 / + DATA IBAR /12*0,2*1,4*0,2*-1,13*0,16*1/ + DATA NAMP / + + ' ','gam ','e+','e-','mu+','mu-','pi0', + + 'pi+','pi-','k+', 'k-', 'k0l','k0s', + + 'p', 'n', 'nue', 'nueb', 'num', 'numb', 'pbar', 'nbar', + + 'k0', 'k0b', 'eta', 'etap', 'rho+', 'rho-','rho0', + + 'k*+','k*-','k*0','k*0b','omeg', 'phi', 'SIG+', 'SIG0', + + 'SIG-','XI0','XI-','LAM','DELT++','DELT+','DELT0','DELT-', + + 'SIG*+ ','SIG*0','SIG*-', 'XI*0', 'XI*-', 'OME*-'/ + DATA S_LIFE /0.,0.,0.,2.197D-6,2.197D-6,8.4D-17,2.6033D-8, + + 2.6033D-8,1.2371D-8,1.2371D-8, + + 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., + + 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., + + 0.,0.,0./ + END +C-> + BLOCK DATA PARAM_INI +C....This block data contains default values +C. of the parameters used in fragmentation +C................................................ + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + SAVE + COMMON /S_CZDIS/ FA, FB0 + COMMON /S_CZDISs/ FAs1, fAs2 + COMMON /S_CZLEAD/ CLEAD, FLEAD + COMMON /S_CPSPL/ CCHIK(3,6:14) + COMMON /S_CQDIS/ PPT0 (33),ptflag + COMMON /S_CDIF0/ FFD, FBD, FDD + COMMON /S_CFLAFR/ PAR(8) +C...Longitudinal Fragmentation function + DATA FA /0.5/, FB0 /0.8/ +C...Longitudinal Fragmentation function for leading baryons + DATA CLEAD /0.0/, FLEAD /0.6/ +c strange fragmentation + data FAs1 /3./, fAs2 /3./ +c data FAs1 /0./, fAs2 /0./ +C...pT of sea partons + DATA PTFLAG /1./ + DATA PPT0 /0.30,0.30,0.450,30*0.60/ +C...Splitting parameters + DATA CCHIK /21*2.,6*3./ +C...Parameters of flavor formation + DATA PAR /0.04,0.25,0.25,0.14,0.3,0.3,0.15,0./ + END + + + SUBROUTINE gamma_h(Ecm,ip1,Imode,ifbad) +C********************************************************************** +C +C simple simulation of low-energy interactions (R.E. 03/98) +C +C changed to simulate superposition of reggeon and pomeron exchange +C interface to Lund / JETSET 7.4 fragmentation +C (R.E. 08/98) +C +C +C +C input: ip1 incoming particle +C 13 - p +C 14 - n +C Ecm CM energy in GeV +C Imode interaction mode +C 0 - multi-pion fragmentation +C 5 - fragmentation in resonance region +C 1 - quasi-elastic / diffractive interaction +C (p/n-gamma --> n/p rho) +C 4 - quasi-elastic / diffractive interaction +C (p/n-gamma --> n/p omega) +C 2 - direct interaction (p/n-gamma --> n/p pi) +C 3 - direct interaction (p/n-gamma --> delta pi) +C IFBAD control flag +C (0 all OK, +C 1 generation of interaction not possible) +C +C********************************************************************** + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + COMMON /S_RUN/ SQS, S, Q2MIN, XMIN, ZMIN, kb, kt, a1, a2, Nproc + COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb + COMMON /S_CHP/ S_LIFE(49), ICHP(49), ISTR(49), IBAR(49) + COMMON /S_MASS1/ AM(49), AM2(49) + COMMON /S_CFLAFR/ PAR(8) + SAVE + + DIMENSION P_dec(10,5), P_in(5) + DIMENSION xs1(2), xs2(2), xmi(2), xma(2) + DIMENSION LL(10), Ijoin(4) + + DOUBLE PRECISION PA1(4), PA2(4), P1(4), P2(4) + + DATA Ic / 0 / + +C second particle is always photon + IP2 = 1 +C parameters of pi0 suppression + a1 = 0.5D0 + a2 = 0.5D0 +C parameter of strangeness suppression + PAR(2) = 0.18D0 +C slope of pomeron trajectory + alphap = 0.25D0 + + ifbad = 0 + SQS = Ecm + S = SQS*SQS + Ic = Ic+1 + + + IF((Imode.eq.1).or.(Imode.eq.4)) THEN + +C*********************************************************************** + +C simulation of diffraction + + ipa = ip1 + ipb = ip2 + + if(Imode.eq.1) then + Nproc = 1 + if(ip1.eq.1) then + ipa = 27 + else if(ip2.eq.1) then + ipb = 27 + endif + else if(Imode.eq.4) then + Nproc = 4 + if(ip1.eq.1) then + ipa = 32 + else if(ip2.eq.1) then + ipb = 32 + endif + endif + + am_a = AM(ipa) + am_b = AM(ipb) + if(am_a+am_b.ge.Ecm-1.D-2) am_a = Ecm - am_b-1.D-2 + +C find t range + e1 = 0.5D0*(Ecm + AM(ip1)**2/Ecm - AM(ip2)**2/Ecm) + if(e1.gt.100.D0*AM(ip1)) then + pcm1 = e1 - 0.5D0*AM(ip1)**2/e1 + else + pcm1 = sqrt((e1-AM(ip1))*(e1+AM(ip1))) + endif + e3 = 0.5D0*(Ecm + am_a**2/Ecm - am_b**2/Ecm) + if(e3.gt.100.D0*am_a) then + pcm3 = e3 - 0.5D0*am_a**2/e3 + else + pcm3 = sqrt((e3-am_a)*(e3+am_a)) + endif + t0 = ((AM(ip1)**2-am_a**2-AM(ip2)**2+am_b**2)/(2.D0*Ecm))**2 + & -(pcm1-pcm3)**2-0.0001D0 + t1 = ((AM(ip1)**2-am_a**2-AM(ip2)**2+am_b**2)/(2.D0*Ecm))**2 + & -(pcm1+pcm3)**2+0.0001D0 + +C sample t + b = 6.5D0+2.D0*alphap*log(S) + t = 1.D0/b*log((exp(b*t0)-exp(b*t1))*RNDM(0)+exp(b*t1)) + +C kinematics + pl = (2.D0*e1*e3+t-AM(ip1)**2-am_a**2)/(2.D0*pcm1) + pt = (pcm3-pl)*(pcm3+pl) + if(pt.lt.0.D0) then + pl = sign(pcm3,pl) + pt = 1.D-6 + else + pt = sqrt(pt) + endif + phi = 6.28318530717959D0*RNDM(0) + + LLIST(1) = ipa + P(1,4) = e3 + P(1,1) = SIN(phi)*pt + P(1,2) = COS(phi)*pt + P(1,3) = pl + P(1,5) = am_a + LLIST(2) = ipb + P(2,1) = -P(1,1) + P(2,2) = -P(1,2) + P(2,3) = -P(1,3) + P(2,4) = Ecm - P(1,4) + P(2,5) = am_b + np = 2 + + call DECSIB + + ELSE IF((Imode.eq.2).or.(Imode.eq.3)) THEN + +C*********************************************************************** + +C simulation of direct p-gamma process + + if(ip1.eq.13) then +C projectile is a proton + if(Imode.eq.2) then + Nproc = 2 + ipa = 14 + ipb = 7 + else + Nproc = 3 + if(rndm(0).gt.0.25) then + ipa = 40 + ipb = 8 + else + ipa = 42 + ipb = 7 + endif + endif + else if(ip1.eq.14) then +C projectile is a neutron + if(Imode.eq.2) then + Nproc = 2 + ipa = 13 + ipb = 8 + else + Nproc = 3 + if(rndm(0).gt.0.25) then + ipa = 43 + ipb = 7 + else + ipa = 41 + ipb = 8 + endif + endif + endif + + am_a = AM(ipa) + am_b = AM(ipb) + if(am_a+am_b.ge.Ecm-1.e-3) am_a = Ecm - am_b-1.D-3 + +C find t range + e1 = 0.5D0*(Ecm + AM(ip1)**2/Ecm - AM(ip2)**2/Ecm) + if(e1.gt.100.D0*AM(ip1)) then + pcm1 = e1 - 0.5D0*AM(ip1)**2/e1 + else + pcm1 = sqrt((e1-AM(ip1))*(e1+AM(ip1))) + endif + e3 = 0.5D0*(Ecm + am_a**2/Ecm - am_b**2/Ecm) + if(e3.gt.100.D0*am_a) then + pcm3 = e3 - 0.5D0*am_a**2/e3 + else + pcm3 = sqrt((e3-am_a)*(e3+am_a)) + endif + t0 = ((AM(ip1)**2-am_a**2-AM(ip2)**2+am_b**2)/(2.D0*Ecm))**2 + & -(pcm1-pcm3)**2-0.0001D0 + t1 = ((AM(ip1)**2-am_a**2-AM(ip2)**2+am_b**2)/(2.D0*Ecm))**2 + & -(pcm1+pcm3)**2+0.0001D0 + +C sample t + b = 12.D0 + t = 1./b*log((exp(b*t0)-exp(b*t1))*RNDM(0)+exp(b*t1)) + +C kinematics + pl = (2.D0*e1*e3+t-AM(ip1)**2-am_a**2)/(2.D0*pcm1) + pt = (pcm3-pl)*(pcm3+pl) + if(pt.lt.0.D0) then + pl = sign(pcm3,pl) + pt = 1.D-6 + else + pt = sqrt(pt) + endif + phi = 6.28318530717959D0*RNDM(0) + + LLIST(1) = ipa + P(1,4) = e3 + P(1,1) = SIN(phi)*pt + P(1,2) = COS(phi)*pt + P(1,3) = pl + P(1,5) = am_a + LLIST(2) = ipb + P(2,1) = -P(1,1) + P(2,2) = -P(1,2) + P(2,3) = -P(1,3) + P(2,4) = Ecm - P(1,4) + P(2,5) = am_b + np = 2 + + call DECSIB + + ELSE + +C*********************************************************************** + +C simulation of multiparticle production via fragmentation + + Nproc = 0 + + SIG_reg = 129.D0*(S-AM(13)**2)**(-0.4525D0) + SIG_pom = 67.7D0*(S-AM(13)**2)**0.0808D0 + + if(S.gt.2.6D0) then + prob_reg = SIG_reg/(SIG_pom+SIG_reg) + else + prob_reg = 1.D0 + endif + + ptu =.36D0+.08D0*log10(sqs/30.D0) + + s1 = 1.2D0 + s2 = 0.6D0 + as1 = s1**2/S + as2 = s2**2/S + if(s1+s2.ge.sqs-0.2) then + prob_reg = 1.D0 + endif + + itry = 0 + 100 continue + Istring = 0 + +C avoid infinite looping + itry = itry+1 + if(itry.gt.50) then + print *,' gamma_h: more than 50 internal rejections,' + print *,' called with ip1,ip2,Ecm,Imode:',ip1,ip2,Ecm,Imode + PAUSE + ifbad = 1 + return + endif + +C simulate reggeon (one-string topology) + + if(RNDM(0).lt.prob_reg) then + + do i=1,1000 + call valences(IP1,Ifl1a,Ifl1b) + call valences(IP2,Ifl2a,Ifl2b) + if(Ifl1b.eq.-Ifl2b) goto 200 + enddo + print *,'gamma_h: simulation of reggeon impossible:',ip1,ip2 + goto 100 + + 200 continue + + np = 0 + Istring = 1 + + ee = Ecm/2.D0 + 250 continue + pt = ptu*sqrt(-log(max(1.D-10,RNDM(0)))) + if(pt.ge.ee) goto 250 + phi = 6.2831853D0*RNDM(0) + px = pt*COS(phi) + py = pt*SIN(phi) + + pz = SQRT(ee**2-px**2-py**2) + call lund_put(1,Ifl1a,px,py,pz,ee) + px = -px + py = -py + pz = -pz + call lund_put(2,Ifl2a,px,py,pz,ee) + Ijoin(1) = 1 + Ijoin(2) = 2 + call lujoin(2,Ijoin) + + call lund_frag(Ecm,NP) + if(NP.lt.0) then + if(Ideb.ge.5) + & print *,' gamma_h: rejection (1) by lund_frag, sqs:',Ecm + NP = 0 + goto 100 + endif + + do i=1,NP + call lund_get(i,LLIST(i), + & P(i,1),P(i,2),P(i,3),P(i,4),P(i,5)) + enddo + + +C simulate pomeron (two-string topology) + + else + + call valences(IP1,Ifl1a,Ifl1b) + call valences(IP2,Ifl2a,Ifl2b) + if(Ifl1a*Ifl2a.lt.0) then + j = Ifl2a + Ifl2a = Ifl2b + Ifl2b = j + endif + + pl1 = (1.D0+as1-as2) + ps1 = 0.25D0*pl1**2-as1 + if(ps1.le.0.D0) then + if(Ideb.ge.5) print *,' rejection by x-limits (1) ',Ecm + prob_reg = 1.D0 + goto 100 + endif + ps1 = sqrt(ps1) + xmi(1) = 0.5D0*pl1-ps1 + xma(1) = 0.5D0*pl1+ps1 + + pl2 = (1.D0+as2-as1) + ps2 = 0.25D0*pl2**2-as2 + if(ps2.le.0.D0) then + if(Ideb.ge.5) print *,' rejection by x-limits (2) ',Ecm + prob_reg = 1.D0 + goto 100 + endif + ps2 = sqrt(ps2) + xmi(2) = 0.5D0*pl2-ps2 + xma(2) = 0.5D0*pl2+ps2 + + if((xmi(1).ge.xma(1)+0.05D0).or. + & (xmi(2).ge.xma(2)+0.05D0)) then + if(Ideb.ge.5) print *,' rejection by x-limits (3) ',Ecm + prob_reg = 1.D0 + goto 100 + endif + call PO_SELSX2(xs1,xs2,xmi,xma,as1,as2,Irej) + if(Irej.ne.0) then + if(Ideb.ge.5) print *, + & 'gamma_h: rejection by PO_SELSX2, sqs,m1,m2:',Ecm,s1,s2 + prob_reg = 1.D0 + goto 100 + endif + + NP = 0 + Istring = 1 + + ee = SQRT(XS1(1)*XS2(1))*Ecm/2.D0 + 260 continue + pt = ptu*sqrt(-log(max(1.D-10,RNDM(0)))) + if(pt.ge.ee) goto 260 + phi = 6.2831853D0*RNDM(0) + px = pt*COS(phi) + py = pt*SIN(phi) + + PA1(1) = px + PA1(2) = py + PA1(3) = XS1(1)*Ecm/2.D0 + PA1(4) = PA1(3) + + PA2(1) = -px + PA2(2) = -py + PA2(3) = -XS2(1)*Ecm/2.D0 + PA2(4) = -PA2(3) + + XM1 = 0.D0 + XM2 = 0.D0 + call PO_MSHELL(PA1,PA2,XM1,XM2,P1,P2) + px = P1(1) + py = P1(2) + pz = P1(3) + ee = P1(4) + call lund_put(1,Ifl1a,px,py,pz,ee) + px = P2(1) + py = P2(2) + pz = P2(3) + ee = P2(4) + call lund_put(2,Ifl2a,px,py,pz,ee) + + Ijoin(1) = 1 + Ijoin(2) = 2 + call lujoin(2,Ijoin) + + ee = SQRT(XS1(2)*XS2(2))*Ecm/2.D0 + 270 continue + pt = ptu*sqrt(-log(max(1.D-10,RNDM(0)))) + if(pt.ge.ee) goto 270 + phi = 6.2831853D0*RNDM(0) + px = pt*COS(phi) + py = pt*SIN(phi) + + PA1(1) = px + PA1(2) = py + PA1(3) = XS1(2)*Ecm/2.D0 + PA1(4) = PA1(3) + + PA2(1) = -px + PA2(2) = -py + PA2(3) = -XS2(2)*Ecm/2.D0 + PA2(4) = -PA2(3) + + XM1 = 0.D0 + XM2 = 0.D0 + call PO_MSHELL(PA1,PA2,XM1,XM2,P1,P2) + + px = P1(1) + py = P1(2) + pz = P1(3) + ee = P1(4) + call lund_put(3,Ifl1b,px,py,pz,ee) + px = P2(1) + py = P2(2) + pz = P2(3) + ee = P2(4) + call lund_put(4,Ifl2b,px,py,pz,ee) + + Ijoin(1) = 3 + Ijoin(2) = 4 + call lujoin(2,Ijoin) + + call lund_frag(Ecm,NP) + if(NP.lt.0) then + if(Ideb.ge.5) + & print *,' gamma_h: rejection (2) by lund_frag, sqs:',Ecm + NP = 0 + prob_reg = prob_reg+0.1D0 + goto 100 + endif + + do i=1,NP + call lund_get(i,LLIST(i), + & P(i,1),P(i,2),P(i,3),P(i,4),P(i,5)) + enddo + + endif + + if(Ideb.ge.10) then + print *,' multi-pion event',Istring,NP + call print_event(1) + endif + +C... for fragmentation in resonance region: + if (Imode.eq.5) goto 400 + +C leading baryon/meson effect + + do j=1,np + if(((LLIST(J).eq.13).or.(LLIST(J).eq.14)) + & .and.(p(j,3).lt.0.D0)) then + if(rndm(0).lt.(2.D0*p(j,4)/Ecm)**2) goto 100 + endif + if((LLIST(J).ge.6).and.(LLIST(J).le.8) + & .and.(p(j,3).lt.-0.4D0)) then + if(rndm(0).lt.(2.D0*p(j,4)/Ecm)**2) goto 100 + endif + enddo + +C remove elastic/diffractive channels + + ima_0 = 0 + imb_0 = 0 + ima_1 = 0 + imb_1 = 0 + ima_2 = 0 + imb_2 = 0 + imul = 0 + + if(ip1.eq.1) then + iba_0 = 6 + iba_1 = 27 + iba_2 = 32 + else + iba_0 = ip1 + iba_1 = ip1 + iba_2 = ip1 + endif + if(ip2.eq.1) then + ibb_0 = 6 + ibb_1 = 27 + ibb_2 = 32 + else + ibb_0 = ip2 + ibb_1 = ip2 + ibb_2 = ip2 + endif + + do j=1,np + l1 = abs(LLIST(J)) + if(l1.lt.10000) then + if(LLIST(J).eq.iba_0) ima_0 = 1 + if(LLIST(J).eq.iba_1) ima_1 = 1 + if(LLIST(J).eq.iba_2) ima_2 = 1 + if(LLIST(J).eq.ibb_0) imb_0 = 1 + if(LLIST(J).eq.ibb_1) imb_1 = 1 + if(LLIST(J).eq.ibb_2) imb_2 = 1 + imul = imul+1 + endif + enddo + + if(imul.eq.2) then + if(ima_0*imb_0.eq.1) goto 100 + if(ima_1*imb_1.eq.1) goto 100 + if(ima_2*imb_2.eq.1) goto 100 + endif + +C remove direct channels + + if((imul.eq.2).and. + & (ip2.eq.1).and.((ip1.eq.13).or.(ip1.eq.14))) then + + ima_0 = 0 + imb_0 = 0 + ima_1 = 0 + imb_1 = 0 + ima_2 = 0 + imb_2 = 0 + ima_3 = 0 + imb_3 = 0 + + if(ip1.eq.13) then + iba_0 = 14 + ibb_0 = 7 + iba_1 = 40 + ibb_1 = 8 + iba_2 = 42 + ibb_2 = 7 + iba_3 = 13 + ibb_3 = 23 + else + iba_0 = 13 + ibb_0 = 8 + iba_1 = 43 + ibb_1 = 7 + iba_2 = 41 + ibb_2 = 8 + iba_3 = 14 + ibb_3 = 23 + endif + + do j=1,np + l1 = abs(LLIST(J)) + if(l1.lt.10000) then + if(LLIST(J).eq.iba_0) ima_0 = 1 + if(LLIST(J).eq.iba_1) ima_1 = 1 + if(LLIST(J).eq.iba_2) ima_2 = 1 + if(LLIST(J).eq.iba_3) ima_3 = 1 + if(LLIST(J).eq.ibb_0) imb_0 = 1 + if(LLIST(J).eq.ibb_1) imb_1 = 1 + if(LLIST(J).eq.ibb_2) imb_2 = 1 + if(LLIST(J).eq.ibb_3) imb_3 = 1 + endif + enddo + + if(ima_0*imb_0.eq.1) goto 100 + if(ima_1*imb_1.eq.1) goto 100 + if(ima_2*imb_2.eq.1) goto 100 + if(ima_3*imb_3.eq.1) goto 100 + + endif + +C suppress events with many pi0's + + ima_0 = 0 + imb_0 = 0 + do j=1,np +C neutral mesons + if(LLIST(J).eq.6) ima_0 = ima_0+1 + if(LLIST(J).eq.11) ima_0 = ima_0+1 + if(LLIST(J).eq.12) ima_0 = ima_0+1 + if(LLIST(J).eq.21) ima_0 = ima_0+1 + if(LLIST(J).eq.22) ima_0 = ima_0+1 + if(LLIST(J).eq.23) ima_0 = ima_0+1 + if(LLIST(J).eq.24) ima_0 = ima_0+1 + if(LLIST(J).eq.27) ima_0 = ima_0+1 + if(LLIST(J).eq.32) ima_0 = ima_0+1 + if(LLIST(J).eq.33) ima_0 = ima_0+1 +C charged mesons + if(LLIST(J).eq.7) imb_0 = imb_0+1 + if(LLIST(J).eq.8) imb_0 = imb_0+1 + if(LLIST(J).eq.9) imb_0 = imb_0+1 + if(LLIST(J).eq.10) imb_0 = imb_0+1 + if(LLIST(J).eq.25) imb_0 = imb_0+1 + if(LLIST(J).eq.26) imb_0 = imb_0+1 + enddo + + prob_1 = a1*DBLE(imb_0)/max(DBLE(ima_0+imb_0),1.D0)+a2 + + if(RNDM(0).GT.prob_1) goto 100 + + +C correct multiplicity at very low energies + + ND = 0 + + E_ref_1 = 1.6D0 + E_ref_2 = 1.95D0 + + if((imul.eq.3) + & .and.(Ecm.gt.E_ref_1).and.(Ecm.lt.E_ref_2)) then + + ima_0 = 0 + ima_1 = 0 + ima_2 = 0 + imb_0 = 0 + imb_1 = 0 + iba_0 = 0 + iba_1 = 0 + iba_2 = 0 + ibb_0 = 0 + ibb_1 = 0 +C incoming proton + if(ip1.eq.13) then + iba_0 = 13 + iba_1 = 7 + iba_2 = 8 + ibb_0 = 14 + ibb_1 = 6 +C incoming neutron + else if(ip1.eq.14) then + iba_0 = 14 + iba_1 = 7 + iba_2 = 8 + ibb_0 = 13 + ibb_1 = 6 + endif + do j=1,np + if(LLIST(J).eq.iba_0) ima_0 = ima_0+1 + if(LLIST(J).eq.iba_1) ima_1 = ima_1+1 + if(LLIST(J).eq.iba_2) ima_2 = ima_2+1 + if(LLIST(J).eq.ibb_0) imb_0 = imb_0+1 + if(LLIST(J).eq.ibb_1) imb_1 = imb_1+1 + enddo + +C N gamma --> N pi+ pi- + if(ima_0*ima_1*ima_2.eq.1) then + Elog = LOG(Ecm) + Elog_1 = LOG(E_ref_1) + Elog_2 = LOG(E_ref_2) + prob = 0.1D0*4.D0/(Elog_2-Elog_1)**2 + & *(Elog-Elog_1)*(Elog_2-Elog) + + if(RNDM(0).lt.prob) then + LL(1) = ip1 + LL(2) = 7 + LL(3) = 8 + LL(4) = 6 + ND = 4 + endif + + endif + + endif + + + E_ref_1 = 1.95D0 + E_ref_2 = 2.55D0 + + if((imul.eq.4) + & .and.(Ecm.gt.E_ref_1).and.(Ecm.lt.E_ref_2)) then + + ima_0 = 0 + ima_1 = 0 + ima_2 = 0 + imb_0 = 0 + imb_1 = 0 + iba_0 = 0 + iba_1 = 0 + iba_2 = 0 + ibb_0 = 0 + ibb_1 = 0 +C incoming proton + if(ip1.eq.13) then + iba_0 = 13 + iba_1 = 7 + iba_2 = 8 + ibb_0 = 14 + ibb_1 = 6 +C incoming neutron + else if(ip1.eq.14) then + iba_0 = 14 + iba_1 = 7 + iba_2 = 8 + ibb_0 = 13 + ibb_1 = 6 + endif + do j=1,np + if(LLIST(J).eq.iba_0) ima_0 = ima_0+1 + if(LLIST(J).eq.iba_1) ima_1 = ima_1+1 + if(LLIST(J).eq.iba_2) ima_2 = ima_2+1 + if(LLIST(J).eq.ibb_0) imb_0 = imb_0+1 + if(LLIST(J).eq.ibb_1) imb_1 = imb_1+1 + enddo + +C N gamma --> N pi+ pi- pi0 + if(ima_0*ima_1*ima_2*imb_1.eq.1) then + Elog = LOG(Ecm) + Elog_2 = LOG(E_ref_2) + Elog_1 = LOG(E_ref_1) + prob = 0.1D0*4.D0/(Elog_2-Elog_1)**2 + & *(Elog-Elog_1)*(Elog_2-Elog) + + if(RNDM(0).lt.prob) then + if(ip1.eq.13) then + LL(1) = 14 + LL(2) = 7 + LL(3) = 7 + LL(4) = 8 + else + LL(1) = 13 + LL(2) = 7 + LL(3) = 8 + LL(4) = 8 + endif + ND = 4 + endif + + endif + + endif + + + if(ND.gt.0) then + P_in(1) = 0.D0 + P_in(2) = 0.D0 + P_in(3) = 0.D0 + P_in(4) = Ecm + P_in(5) = Ecm + call DECPAR(0,P_in,ND,LL,P_dec) + Iflip = 0 + do j=1,ND + LLIST(j) = LL(j) + do k=1,5 + P(j,k) = P_dec(j,k) + enddo + if(((LLIST(j).eq.13).or.(LLIST(j).eq.14)) + & .and.(P(j,3).lt.0.D0)) Iflip = 1 + enddo + if(Iflip.ne.0) then + do j=1,ND + P(j,3) = -P(j,3) + enddo + endif + NP = ND + endif + +C... for fragmentation in resonance region: + 400 continue + + call DECSIB + + ENDIF + + if(Ideb.ge.10) then + if(Ideb.ge.20) then + call print_event(2) + else + call print_event(1) + endif + endif + + IQchr = ICHP(ip1)+ICHP(ip2) + IQbar = IBAR(ip1)+IBAR(ip2) + call check_event(-Ic,Ecm,0.D0,0.D0,0.D0,IQchr,IQbar,Irej) + + end + + + SUBROUTINE print_event(Iout) +C********************************************************************* +C +C print final state particles +C +C (R.E. 03/98) +C +C********************************************************************** + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + COMMON /S_RUN/ SQS, S, Q2MIN, XMIN, ZMIN, kb, kt, a1, a2, Nproc + COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb + COMMON /S_CSYDEC/ CBR(102), IDB(49), KDEC(612), LBARP(49) + COMMON /S_CHP/ S_LIFE(49), ICHP(49), ISTR(49), IBAR(49) + COMMON /S_MASS1/ AM(49), AM2(49) + COMMON /S_CNAM/ NAMP (0:49) + CHARACTER*6 NAMP + CHARACTER CODE*18 + SAVE + + if(iout.gt.0) then + + print *,' --------------------------------------------------' + + if(Nproc.eq.1) then + print *,' diffractive rho-0 production',Nproc + else if(Nproc.eq.2) then + print *,' direct interaction 1',Nproc + else if(Nproc.eq.3) then + print *,' direct interaction 2',Nproc + else if(Nproc.eq.4) then + print *,' diffractive omega production',Nproc + else if(Nproc.eq.0) then + print *,' multi-pion/fragmentation contribution',Nproc + else if((Nproc.gt.10).and.(Nproc.lt.20)) then + print *,' resonance production and decay',Nproc-10 + else + print *,' unknown process',Nproc + endif + + i0 = 0 + px = 0.D0 + py = 0.D0 + pz = 0.D0 + ee = 0.D0 + ichar = 0 + ibary = 0 + do j=1,np + l1 = abs(LLIST(J)) + l = mod(llist(j),10000) + if(l1.lt.10000) then + px = px + P(j,1) + py = py + P(j,2) + pz = pz + P(j,3) + ee = ee + P(j,4) + ichar = ichar+sign(1,l)*ICHP(iabs(l)) + ibary = ibary+sign(1,l)*IBAR(iabs(l)) + endif + if((l1.lt.10000).or.(Iout.GE.2)) then + i0 = i0+1 + code = ' ' + code(1:6) = namp(iabs(l)) + if (l .lt. 0) code(7:9) = 'bar' + write (6,120) i0,CODE,l1*sign(1,l),sign(1,l)*ICHP(iabs(l)), + & (P(j,k),k=1,4) + endif + enddo + write (6,122) ' sum: ',px,py,pz,ee + print *,' charge QN: ',ichar,' baryon QN: ',ibary + print *,' --------------------------------------------------' +120 FORMAT(1X,I4,1X,A18,1X,I6,1X,I2,1X,2(F9.3,2X),2(E9.3,2X)) +122 FORMAT(7X,A8,20X,2(F9.3,2X),2(E9.3,2X)) + + endif + + END + + + SUBROUTINE check_event(Ic,Esum,PXsum,PYsum,PZsum,IQchr,IQbar,Irej) +C*********************************************************************** +C +C check energy-momentum and quantum number conservation +C +C (R.E. 08/98) +C +C*********************************************************************** + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + COMMON /S_RUN/ SQS, S, Q2MIN, XMIN, ZMIN, kb, kt, a1, a2, Nproc + COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb + COMMON /S_CSYDEC/ CBR(102), IDB(49), KDEC(612), LBARP(49) + COMMON /S_CHP/ S_LIFE(49), ICHP(49), ISTR(49), IBAR(49) + COMMON /S_MASS1/ AM(49), AM2(49) + COMMON /S_CNAM/ NAMP (0:49) + CHARACTER*6 NAMP + SAVE + + px = 0.D0 + py = 0.D0 + pz = 0.D0 + ee = 0.D0 + ichar = 0 + ibary = 0 + Iprint = 0 + + PLscale = Esum + PTscale = 1.D0 + + do j=1,np + l1 = abs(LLIST(J)) + l = mod(llist(j),10000) + if(l1.lt.10000) then + px = px + P(j,1) + py = py + P(j,2) + pz = pz + P(j,3) + ee = ee + P(j,4) + ichar = ichar+sign(1,l)*ICHP(iabs(l)) + ibary = ibary+sign(1,l)*IBAR(iabs(l)) + endif + enddo + + if(ichar.ne.IQchr) then + print *,' charge conservation violated',Ic + Iprint = 1 + endif + if(ibary.ne.IQbar) then + print *,' baryon number conservation violated',Ic + Iprint = 1 + endif + if(abs((px-PXsum)/MAX(PXsum,PTscale)).gt.1.D-3) then + print *,' x momentum conservation violated',Ic + Iprint = 1 + endif + if(abs((py-PYsum)/MAX(PYsum,PTscale)).gt.1.D-3) then + print *,' y momentum conservation violated',Ic + Iprint = 1 + endif + if(abs((pz-Pzsum)/MAX(ABS(PZsum),PLscale)).gt.1.D-3) then + print *,' z momentum conservation violated',Ic + Iprint = 1 + endif + if(abs((ee-Esum)/MAX(Esum,1.D0)).gt.1.D-3) then + print *,' energy conservation violated',Ic + Iprint = 1 + endif + + if(Iprint.ne.0) call print_event(1) + + Irej = Iprint + + END + + + SUBROUTINE valences(ip,ival1,ival2) +C********************************************************************** +C +C valence quark composition of various particles (R.E. 03/98) +C (with special treatment of photons) +C +C********************************************************************** + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + SAVE + + if(ip.eq.1) then + if(rndm(0).gt.0.2D0) then + ival1 = 1 + ival2 = -1 + else + ival1 = 2 + ival2 = -2 + endif + else if(ip.eq.6) then + if(rndm(0).gt.0.5D0) then + ival1 = 1 + ival2 = -1 + else + ival1 = 2 + ival2 = -2 + endif + else if(ip.eq.7) then + ival1 = 1 + ival2 = -2 + else if(ip.eq.8) then + ival1 = 2 + ival2 = -1 + else if(ip.eq.13) then + Xi = rndm(0) + if(Xi.lt.0.3333D0) then + ival1 = 12 + ival2 = 1 + else if(Xi.lt.0.6666D0) then + ival1 = 21 + ival2 = 1 + else + ival1 = 11 + ival2 = 2 + endif + else if(ip.eq.14) then + Xi = rndm(0) + if(Xi.lt.0.3333D0) then + ival1 = 12 + ival2 = 2 + else if(Xi.lt.0.6666D0) then + ival1 = 21 + ival2 = 2 + else + ival1 = 22 + ival2 = 1 + endif + endif + + if((ip.lt.13).and.(rndm(0).lt.0.5D0)) then + k = ival1 + ival1 = ival2 + ival2 = k + endif + + END + + + SUBROUTINE DECSIB +C*********************************************************************** +C +C Decay all unstable particle in SIBYLL +C decayed particle have the code increased by 10000 +C +C (taken from SIBYLL 1.7, R.E. 04/98) +C +C*********************************************************************** + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + COMMON /S_CSYDEC/ CBR(102), IDB(49), KDEC(612), LBARP(49) + COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb + COMMON /S_PLIST1/ LLIST1(2000) + SAVE + + DIMENSION P0(5), LL(10), PD(10,5) + + NN = 1 + DO J=1,NP + LLIST1(J) = 0 + ENDDO + DO WHILE (NN .LE. NP) + L= LLIST(NN) + IF (IDB(IABS(L)) .GT. 0) THEN + DO K=1,5 + P0(K) = P(NN,K) + ENDDO + ND = 0 + CALL DECPAR (L,P0,ND,LL,PD) + LLIST(NN) = LLIST(NN)+ISIGN(10000,LLIST(NN)) + DO J=1,ND + DO K=1,5 + P(NP+J,K) = PD(J,K) + ENDDO + LLIST(NP+J)=LL(J) + LLIST1(NP+J)=NN + ENDDO + NP=NP+ND + ENDIF + NN = NN+1 + ENDDO + + END + + + SUBROUTINE DECPAR(LA,P0,ND,LL,P) +C*********************************************************************** +C +C This subroutine generates the decay of a particle +C with ID = LA, and 5-momentum P0(1:5) +C into ND particles of 5-momenta P(j,1:5) (j=1:ND) +C +C If the initial particle code is LA=0 +C then ND and LL(1:ND) are considered as input and +C the routine generates a phase space decay into ND +C particles of codes LL(1:nd) +C +C (taken from SIBYLL 1.7, muon decay corrected, R.E. 04/98) +C +C*********************************************************************** + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + COMMON /S_CSYDEC/ CBR(102), IDB(49), KDEC(612), LBARP(49) + COMMON /S_MASS1/ AM(49), AM2(49) + SAVE + + DIMENSION P0(5), LL(10), P(10,5) + DIMENSION PV(10,5), RORD(10), UE(3),BE(3), FACN(3:10) + + DATA FACN /2.D0,5.D0,15.D0,60.D0,250.D0, + + 1500.D0,12000.D0,120000.D0/ + DATA PI /3.1415926D0/ + +C...c.m.s. Momentum in two particle decays + PAWT(A,B,C) = SQRT((A**2-(B+C)**2)*(A**2-(B-C)**2))/(2.D0*A) + +C...Phase space decay into the particles in the list + IF (LA .EQ. 0) THEN + MAT = 0 + MBST = 0 + PS = 0. + DO J=1,ND + P (J,5) = AM(IABS(LL(J))) + PV(J,5) = AM(IABS(LL(J))) + PS = PS+P(J,5) + ENDDO + DO J=1,4 + PV(1,J) = P0(J) + ENDDO + PV(1,5) = P0(5) + GOTO 140 + ENDIF + +C...Choose decay channel + L = IABS(LA) + ND=0 + IDC = IDB(L)-1 + IF (IDC+1 .LE.0) RETURN + RBR = RNDM(0) +110 IDC=IDC+1 + IF(RBR.GT.CBR(IDC)) GOTO 110 + + KD =6*(IDC-1)+1 + ND = KDEC(KD) + MAT= KDEC(KD+1) + + MBST=0 + IF (MAT .GT.0 .AND. P0(4) .GT. 20.D0*P0(5)) MBST=1 + IF (MAT .GT.0 .AND. MBST .EQ. 0) + + BETA = SQRT(P0(1)**2+P0(2)**2+P0(3)**2)/P0(4) + + PS = 0.D0 + DO J=1,ND + LL(J) = KDEC(KD+1+J) + P(J,5) = AM(LL(J)) + PV(J,5) = AM(LL(J)) + PS = PS + P(J,5) + ENDDO + DO J=1,4 + PV(1,J) = 0.D0 + IF (MBST .EQ. 0) PV(1,J) = P0(J) + ENDDO + IF (MBST .EQ. 1) PV(1,4) = P0(5) + PV(1,5) = P0(5) + +140 IF (ND .EQ. 2) GOTO 280 + + IF (ND .EQ. 1) THEN + DO J=1,4 + P(1,J) = P0(J) + ENDDO + RETURN + ENDIF + +C...Calculate maximum weight for ND-particle decay + WWTMAX = 1.D0/FACN(ND) + PMAX=PV(1,5)-PS+P(ND,5) + PMIN=0.D0 + DO IL=ND-1,1,-1 + PMAX = PMAX+P(IL,5) + PMIN = PMIN+P(IL+1,5) + WWTMAX = WWTMAX*PAWT(PMAX,PMIN,P(IL,5)) + ENDDO + +C...generation of the masses, compute weight, if rejected try again +240 RORD(1) = 1.D0 + DO 260 IL1=2,ND-1 + RSAV = RNDM(0) + DO 250 IL2=IL1-1,1,-1 + IF(RSAV.LE.RORD(IL2)) GOTO 260 +250 RORD(IL2+1)=RORD(IL2) +260 RORD(IL2+1)=RSAV + RORD(ND) = 0.D0 + WT = 1.D0 + DO 270 IL=ND-1,1,-1 + PV(IL,5)=PV(IL+1,5)+P(IL,5)+(RORD(IL)-RORD(IL+1))*(PV(1,5)-PS) +270 WT=WT*PAWT(PV(IL,5),PV(IL+1,5),P(IL,5)) + IF (WT.LT.RNDM(0)*WWTMAX) GOTO 240 + +C...Perform two particle decays in respective cm frame +280 DO 300 IL=1,ND-1 + PA=PAWT(PV(IL,5),PV(IL+1,5),P(IL,5)) + UE(3)=2.D0*RNDM(0)-1.D0 + PHI=2.D0*PI*RNDM(0) + UT = SQRT(1.D0-UE(3)**2) + UE(1) = UT*COS(PHI) + UE(2) = UT*SIN(PHI) + DO 290 J=1,3 + P(IL,J)=PA*UE(J) +290 PV(IL+1,J)=-PA*UE(J) + P(IL,4)=SQRT(PA**2+P(IL,5)**2) +300 PV(IL+1,4)=SQRT(PA**2+PV(IL+1,5)**2) + +C...Lorentz transform decay products to lab frame + DO 310 J=1,4 +310 P(ND,J)=PV(ND,J) + DO 340 IL=ND-1,1,-1 + DO 320 J=1,3 +320 BE(J)=PV(IL,J)/PV(IL,4) + GA=PV(IL,4)/PV(IL,5) + DO 340 I=IL,ND + BEP = BE(1)*P(I,1)+BE(2)*P(I,2)+BE(3)*P(I,3) + DO 330 J=1,3 +330 P(I,J)=P(I,J)+GA*(GA*BEP/(1.+GA)+P(I,4))*BE(J) +340 P(I,4)=GA*(P(I,4)+BEP) + +C...Weak decays + IF (MAT .EQ. 1) THEN + F1=P(2,4)*P(3,4)-P(2,1)*P(3,1)-P(2,2)*P(3,2)-P(2,3)*P(3,3) + IF (MBST.EQ.1) WT = P0(5)*P(1,4)*F1 + IF (MBST.EQ.0) + + WT=F1*(P(1,4)*P0(4)-P(1,1)*P0(1)-P(1,2)*P0(2)-P(1,3)*P0(3)) + WTMAX = P0(5)**4/16.D0 + IF(WT.LT.RNDM(0)*WTMAX) GOTO 240 + ENDIF + + +C...Boost back for rapidly moving particle + IF (MBST .EQ. 1) THEN + DO 440 J=1,3 +440 BE(J)=P0(J)/P0(4) + GA= P0(4)/P0(5) + DO 460 I=1,ND + BEP=BE(1)*P(I,1)+BE(2)*P(I,2)+BE(3)*P(I,3) + DO 450 J=1,3 +450 P(I,J)=P(I,J)+GA*(GA*BEP/(1.+GA)+P(I,4))*BE(J) +460 P(I,4)=GA*(P(I,4)+BEP) + ENDIF + +C...labels for antiparticle decay + IF (LA .LT. 0 .AND. L .GT. 18) THEN + DO J=1,ND + LL(J) = LBARP(LL(J)) + ENDDO + ENDIF + + END + + + SUBROUTINE PO_ALTRA(GA,BGX,BGY,BGZ,PCX,PCY,PCZ,EC,P,PX,PY,PZ,E) +C********************************************************************* +C +C arbitrary Lorentz transformation +C +C (taken from PHOJET v1.12, R.E. 08/98) +C +C********************************************************************* + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + SAVE + + EP=PCX*BGX+PCY*BGY+PCZ*BGZ + PE=EP/(GA+1.D0)+EC + PX=PCX+BGX*PE + PY=PCY+BGY*PE + PZ=PCZ+BGZ*PE + P=SQRT(PX*PX+PY*PY+PZ*PZ) + E=GA*EC+EP + + END + + + SUBROUTINE PO_TRANS(XO,YO,ZO,CDE,SDE,CFE,SFE,X,Y,Z) +C********************************************************************** +C +C rotation of coordinate frame (1) de rotation around y axis +C (2) fe rotation around z axis +C +C (taken from PHOJET v1.12, R.E. 08/98) +C +C********************************************************************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + SAVE + + X= CDE*CFE*XO-SFE*YO+SDE*CFE*ZO + Y= CDE*SFE*XO+CFE*YO+SDE*SFE*ZO + Z=-SDE *XO +CDE *ZO + + END + + + SUBROUTINE PO_SELSX2(XS1,XS2,XMIN,XMAX,AS1,AS2,IREJ) +C*********************************************************************** +C +C select x values of soft string ends using PO_RNDBET +C +C (taken from PHOJET v1.12, R.E. 08/98) +C +C*********************************************************************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + SAVE + + DIMENSION XS1(2),XS2(2) + DIMENSION XMIN(2),XMAX(2) + + IREJ = 0 + + GAM1 = +1.5D0 + 1.D0 + GAM2 = -0.5D0 + 1.D0 + BET1 = -0.5D0 + 1.D0 + BET2 = -0.5D0 + 1.D0 + + ITRY0 = 0 + DO 100 I=1,100 + + ITRY1 = 0 + 10 CONTINUE + X1 = PO_RNDBET(GAM1,BET1) + ITRY1 = ITRY1+1 + IF(ITRY1.GE.50) THEN + IREJ = 1 + RETURN + ENDIF + IF((X1.LE.XMIN(1)).OR.(X1.GE.XMAX(1))) GOTO 10 + + ITRY2 = 0 + 11 CONTINUE + X2 = PO_RNDBET(GAM2,BET2) + ITRY2 = ITRY2+1 + IF(ITRY2.GE.50) THEN + IREJ = 2 + RETURN + ENDIF + IF((X2.LE.XMIN(2)).OR.(X2.GE.XMAX(2))) GOTO 11 + + X3 = 1.D0 - X1 + X4 = 1.D0 - X2 + IF(X1*X2.GT.AS1) THEN + IF(X3*X4.GT.AS2) GOTO 300 + ENDIF + ITRY0 = ITRY0+1 + + 100 CONTINUE + + IREJ = 3 + RETURN + + 300 CONTINUE + + XS1(1) = X1 + XS1(2) = X3 + + XS2(1) = X2 + XS2(2) = X4 + + END + + + DOUBLE PRECISION FUNCTION PO_RNDBET(GAM,ETA) +C******************************************************************** +C +C random number generation from beta +C distribution in region 0 < X < 1. +C F(X) = X**(GAM-1.)*(1.-X)**(ETA-1)*GAMM(ETA+GAM) / (GAMM(GAM +C *GAMM(ETA)) +C +C (taken from PHOJET v1.12, R.E. 08/98) +C +C******************************************************************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + SAVE + + Y = PO_RNDGAM(1.D0,GAM) + Z = PO_RNDGAM(1.D0,ETA) + PO_RNDBET = Y/(Y+Z) + + END + + + DOUBLE PRECISION FUNCTION PO_RNDGAM(ALAM,ETA) +C******************************************************************** +C +C random number selection from gamma distribution +C F(X) = ALAM**ETA*X**(ETA-1)*EXP(-ALAM*X) / GAM(ETA) +C +C (taken from PHOJET v1.12, R.E. 08/98) +C +C******************************************************************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + SAVE + + NCOU=0 + N = ETA + F = ETA - N + IF(F.EQ.0.D0) GOTO 20 + 10 R = RNDM(0) + NCOU=NCOU+1 + IF (NCOU.GE.11) GOTO 20 + IF(R.LT.F/(F+2.71828D0)) GOTO 30 + YYY=LOG(RNDM(0)+1.e-7)/F + IF(ABS(YYY).GT.50.D0) GOTO 20 + Y = EXP(YYY) + IF(LOG(RNDM(0)+1.D-7).GT.-Y) GOTO 10 + GOTO 40 + 20 Y = 0.D0 + GOTO 50 + 30 Y = 1.D0-LOG(RNDM(0)+1.D-7) + IF(RNDM(0).GT.Y**(F-1.D0)) GOTO 10 + 40 IF(N.EQ.0) GOTO 70 + 50 Z = 1.D0 + DO 60 I = 1,N + 60 Z = Z*RNDM(0) + Y = Y-LOG(Z+1.D-7) + 70 PO_RNDGAM = Y/ALAM + + END + + + SUBROUTINE lund_frag(SQS,NP) +C*********************************************************************** +C +C interface to Lund/Jetset fragmentation +C +C (R.E. 08/98) +C +C*********************************************************************** + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) + SAVE + + DATA init / 0 / + + + if(init.eq.0) then + +C no title page + + MSTU(12) = 0 + +C define some particles as stable + + MSTJ(22) = 2 + +C in addition pi0 stable + + KC=LUCOMP(111) + MDCY(KC,1)=0 + +C switch popcorn effect off + + MSTJ(12) = 1 + +C suppress all warning and error messages + + MSTU(22) = 0 + MSTU(25) = 0 + + init = 1 + + endif + + +C set energy dependent parameters + + IF(SQS.LT.2.D0) THEN + PARJ(36) = 0.1D0 + ELSE IF(SQS.LT.4.D0) THEN + PARJ(36) = 0.7D0*(SQS-2.D0)/2.D0+0.1D0 + ELSE + PARJ(36) = 0.8D0 + ENDIF + +C fragment string configuration + + II = MSTU(21) + MSTU(21) = 1 + CALL LUEXEC + MSTU(21) = II + +C event accepted? + + if(MSTU(24).ne.0) then + NP = -1 + return + endif + + CALL LUEDIT(1) + + NP = KLU(0,1) + + END + + + SUBROUTINE lund_put(I,IFL,PX,PY,PZ,EE) +C*********************************************************************** +C +C store initial configuration into Lund common block +C +C (R.E. 08/98) +C +C*********************************************************************** + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) + SAVE + + if(IFL.eq.1) then + Il = 2 + else if(IFL.eq.-1) then + Il = -2 + else if(IFL.eq.2) then + Il = 1 + else if(IFL.eq.-2) then + Il = -1 + else if(IFL.eq.11) then + Il = 2203 + else if(IFL.eq.12) then + Il = 2101 + else if(IFL.eq.21) then + Il = 2103 + else if(IFL.eq.22) then + Il = 1103 + else + print *,' lund_put: unkown flavor code',IFL + endif + + P(I,1) = PX + P(I,2) = PY + P(I,3) = PZ + P(I,4) = EE + P(I,5) = (EE-PZ)*(EE+PZ)-PX**2-PY**2 + + K(I,1) = 1 + K(I,2) = Il + K(I,3) = 0 + K(I,4) = 0 + K(I,5) = 0 + + N = I + + END + + + SUBROUTINE lund_get(I,IFL,PX,PY,PZ,EE,XM) +C*********************************************************************** +C +C read final states from Lund common block +C +C (R.E. 08/98) +C +C*********************************************************************** + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) + SAVE + + PX = PLU(I,1) + PY = PLU(I,2) + PZ = PLU(I,3) + EE = PLU(I,4) + XM = PLU(I,5) + + Il = KLU(I,8) + +C convert particle ID + + IFL = ICON_PDG_SIB(Il) + + END + + + + INTEGER FUNCTION ICON_PDG_SIB(ID) +C************************************************************************ +C +C convert PDG particle codes to SIBYLL particle codes +C +C (R.E. 09/97) +C +C************************************************************************ + SAVE + + DIMENSION ITABLE(49) + DATA ITABLE / + & 22, -11, 11, -13, 13, 111, 211, -211, 321, -321, 130, 310, 2212, + & 2112, 12, -12, 14, -14, -99999999, -99999999, 311, -311, 221, + & 331, 213, -213, 113, 323, -323, 313, -313, 223, 333, 3222, 3212, + & 3112, 3322, 3312, 3122, 2224, 2214, 2114, 1114, 3224, 3214, + & 3114, 3324, 3314, 3334 / + + IDPDG = ID + + 100 CONTINUE + IDA = ABS(ID) + + IF(IDA.GT.1000) THEN + IS = IDA + IC = SIGN(1,IDPDG) + ELSE + IS = IDPDG + IC = 1 + ENDIF + + DO I=1,49 + IF(IS.EQ.ITABLE(I)) THEN + ICON_PDG_SIB = I*IC + RETURN + ENDIF + ENDDO + + IF(IDPDG.EQ.80000) THEN + ICON_PDG_SIB = 13 + ELSE + print *,'ICON_PDG_DTU: no particle found for ',IDPDG + ICON_PDG_SIB = 0 + RETURN + ENDIF + + END + + + + SUBROUTINE PO_MSHELL(PA1,PA2,XM1,XM2,P1,P2) +C******************************************************************** +C +C rescaling of momenta of two partons to put both +C on mass shell +C +C input: PA1,PA2 input momentum vectors +C XM1,2 desired masses of particles afterwards +C P1,P2 changed momentum vectors +C +C (taken from PHOJET 1.12, R.E. 08/98) +C +C******************************************************************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + SAVE + + PARAMETER ( DEPS = 1.D-5 ) + + DIMENSION PA1(4),PA2(4),P1(4),P2(4) + +C Lorentz transformation into system CMS + PX = PA1(1)+PA2(1) + PY = PA1(2)+PA2(2) + PZ = PA1(3)+PA2(3) + EE = PA1(4)+PA2(4) + XMS = EE**2-PX**2-PY**2-PZ**2 + XMS = SQRT(XMS) + BGX = PX/XMS + BGY = PY/XMS + BGZ = PZ/XMS + GAM = EE/XMS + CALL PO_ALTRA(GAM,-BGX,-BGY,-BGZ,PA1(1),PA1(2),PA1(3), + & PA1(4),PTOT1,P1(1),P1(2),P1(3),P1(4)) +C rotation angles + PTOT1 = MAX(DEPS,PTOT1) + COD= P1(3)/PTOT1 + SID= SQRT((1.D0-COD)*(1.D0+COD)) + COF=1.D0 + SIF=0.D0 + IF(PTOT1*SID.GT.1.D-5) THEN + COF=P1(1)/(SID*PTOT1) + SIF=P1(2)/(SID*PTOT1) + ANORF=SQRT(COF*COF+SIF*SIF) + COF=COF/ANORF + SIF=SIF/ANORF + ENDIF + +C new CM momentum and energies (for masses XM1,XM2) + XM12 = XM1**2 + XM22 = XM2**2 + SS = XMS**2 + PCMP = PO_XLAM(SS,XM12,XM22)/(2.D0*XMS) + EE1 = SQRT(XM12+PCMP**2) + EE2 = XMS-EE1 +C back rotation + CALL PO_TRANS(0.D0,0.D0,PCMP,COD,SID,COF,SIF,XX,YY,ZZ) + CALL PO_ALTRA(GAM,BGX,BGY,BGZ,XX,YY,ZZ,EE1, + & PTOT1,P1(1),P1(2),P1(3),P1(4)) + CALL PO_ALTRA(GAM,BGX,BGY,BGZ,-XX,-YY,-ZZ,EE2, + & PTOT2,P2(1),P2(2),P2(3),P2(4)) + + END + + + DOUBLE PRECISION FUNCTION PO_XLAM(X,Y,Z) +C********************************************************************** +C +C auxiliary function for two/three particle decay mode +C (standard LAMBDA**(1/2) function) +C +C (taken from PHOJET 1.12, R.E. 08/98) +C +C********************************************************************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + SAVE + + YZ=Y-Z + XLAM=X*X-2.D0*X*(Y+Z)+YZ*YZ + IF(XLAM.LT.0.D0) XLAM=-XLAM + PO_XLAM=SQRT(XLAM) + + END + + + + SUBROUTINE INITIAL(L0) + +c******************************************************************* +c initialization routine for setting parameters of resonances +c******************************************************************* + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + SAVE + COMMON /RES_PROP/ AMRES(9),SIG0(9),WIDTH(9), + + NAMPRES(0:9) + COMMON /RES_PROPp/ AMRESp(9), BGAMMAp(9),WIDTHp(9), + + RATIOJp(9),NAMPRESp(0:9) + COMMON /RES_PROPn/ AMRESn(9), BGAMMAn(9),WIDTHn(9), + + RATIOJn(9),NAMPRESn(0:9) + COMMON /S_MASS1/ AM(49), AM2(49) + CHARACTER NAMPRESp*6, NAMPRESn*6 + CHARACTER NAMPRES*6 + + if (L0.eq.13) then + do i=1,9 + SIG0(i) = 4.893089117D0/AM2(13)*RATIOJp(i)*BGAMMAp(i) + AMRES(i) = AMRESp(i) + WIDTH(i) = WIDTHp(i) + NAMPRES(i) = NAMPRESp(i) + enddo + endif + + if (L0.eq.14) then + do i=1,9 + SIG0(i) = 4.893089117D0/AM2(14)*RATIOJn(i)*BGAMMAn(i) + AMRES(i) = AMRESn(i) + WIDTH(i) = WIDTHn(i) + NAMPRES(i) = NAMPRESn(i) + enddo + endif + + RETURN + END +c***************************************************************************** +c**!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*** +c**!! IF YOU USE THIS PROGRAM, PLEASE CITE: !!*** +c**!! A.M"ucke, Ralph Engel, J.P.Rachen, R.J.Protheroe and Todor Stanev, !!*** +c**!! 1999, astro-ph/9903478, to appear in Comp.Phys.Commun. !!*** +c**!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*** +c***************************************************************************** +c** Further SOPHIA related papers: *** +c** (1) M"ucke A., et al 1999, astro-ph/9808279, to appear in PASA. *** +c** (2) M"ucke A., et al 1999, to appear in: Proc. of the *** +c** 19th Texas Symposium on Relativistic Astrophysics, Paris, France, *** +c** Dec. 1998. Eds.: J.~Paul, T.~Montmerle \& E.~Aubourg (CEA Saclay) *** +c** (3) M"ucke A., et al 1999, astro-ph/9905153, to appear in: Proc. of *** +c** 19th Texas Symposium on Relativistic Astrophysics, Paris, France, *** +c** Dec. 1998. Eds.: J.~Paul, T.~Montmerle \& E.~Aubourg (CEA Saclay) *** +c** (4) M"ucke A., et al 1999, to appear in: Proc. of 26th Int.Cosmic Ray *** +c** Conf. (Salt Lake City, Utah) *** +c***************************************************************************** + + +c********************************* +c*** Routines related to output: * +c********************************* + + + subroutine LISTDISTR(E0,Dg,Dnum,Dnuma,Dnue,Dnuea,Dp,Dn,Dem, + & Dep,nbins,delx) + +c********************************************************************* +c** calculates distribution of energy of given particle to incident ** +c** proton energy; considered particles are: ** +c** photons, protons, neutrons, e-neutrinos, nu-neutrinos ** +c** Note: Dg(),Dnum(),Dnue(),Dp(),Dn(),Dem(),Dep(),Dnuea(),Dnuma() ** +c** gives # of photons per logarithmic bin width: dN/dlog(f) ** +c********************************************************************* +c** Date: 20/01/98 ** +c** author: A.Muecke ** +c********************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + SAVE + + COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb + DIMENSION Dg(201),Dnum(201),Dnue(201),Dp(201),Dn(201) + DIMENSION Dem(201),Dep(201),Dnuea(201),Dnuma(201) + + do i=1,201 + Dg(i) = 0. + Dnum(i) = 0. + Dnue(i) = 0. + Dp(i) = 0. + Dn(i) = 0. + Dem(i) = 0. + Dep(i) = 0. + Dnuma(i) = 0. + Dnuea(i) = 0. + enddo + + xini = -nbins*delx +c go through LLIST: + do 10 i=1,NP + LA = abs(LLIST(i)) + EI = abs(P(i,4)) + Ep = E0/1.D10 + r = EI/Ep/1.D10 + x = log10(r) + if (LA.lt.10000) then +c** gamma ray distribution + if (LA.eq.1) then + do 20 j=1,nbins + x1 = xini+delx*(j-1) + x2 = xini+delx*j + if (x.ge.x1.and.x.lt.x2) then + Dg(j) = Dg(j)+1.D0 + endif + if (x.eq.0.D0) then + Dg(nbins) = Dg(nbins)+1.D0 + endif + 20 continue + endif +c** neutron distribution + if (LA.eq.14) then + do 21 j=1,nbins + x1 = xini+delx*(j-1) + x2 = xini+delx*j + if (x.ge.x1.and.x.lt.x2) then + Dn(j) = Dn(j)+1.D0 + endif + if (x.eq.0.D0) then + Dn(nbins) = Dn(nbins)+1.D0 + endif + 21 continue + endif +c** proton distribution + if (LA.eq.13) then + do 22 j=1,nbins + x1 = xini+delx*(j-1) + x2 = xini+delx*j + if (x.ge.x1.and.x.lt.x2) then + Dp(j) = Dp(j)+1.D0 + endif + if (x.eq.0.D0) then + Dp(nbins) = Dp(nbins)+1.D0 + endif + 22 continue + endif +c** neutrino distribution + if (LA.eq.17) then + do 23 j=1,nbins + x1 = xini+delx*(j-1) + x2 = xini+delx*j + if (x.ge.x1.and.x.lt.x2) then + Dnum(j) = Dnum(j)+1.D0 + endif + if (x.eq.0.D0) then + Dnum(nbins) = Dnum(nbins)+1.D0 + endif + 23 continue + endif + + if (LA.eq.18) then + do 27 j=1,nbins + x1 = xini+delx*(j-1) + x2 = xini+delx*j + if (x.ge.x1.and.x.lt.x2) then + Dnuma(j) = Dnuma(j)+1.D0 + endif + if (x.eq.0.D0) then + Dnuma(nbins) = Dnuma(nbins)+1.D0 + endif + 27 continue + endif + + + if (LA.eq.15) then + do 24 j=1,nbins + x1 = xini+delx*(j-1) + x2 = xini+delx*j + if (x.ge.x1.and.x.lt.x2) then + Dnue(j) = Dnue(j)+1.D0 + endif + if (x.eq.0.D0) then + Dnue(nbins) = Dnue(nbins)+1.D0 + endif + 24 continue + endif + + if (LA.eq.16) then + do 28 j=1,nbins + x1 = xini+delx*(j-1) + x2 = xini+delx*j + if (x.ge.x1.and.x.lt.x2) then + Dnuea(j) = Dnuea(j)+1.D0 + endif + if (x.eq.0.D0) then + Dnuea(nbins) = Dnuea(nbins)+1.D0 + endif + 28 continue + endif + +c** electron distribution + if (LA.eq.3) then + do 25 j=1,nbins + x1 = xini+delx*(j-1) + x2 = xini+delx*j + if (x.ge.x1.and.x.lt.x2) then + Dem(j) = Dem(j)+1.D0 + endif + if (x.eq.0.D0) then + Dem(nbins) = Dem(nbins)+1.D0 + endif + 25 continue + endif + +c** positron distribution + if (LA.eq.2) then + do 26 j=1,nbins + x1 = xini+delx*(j-1) + x2 = xini+delx*j + if (x.ge.x1.and.x.lt.x2) then + Dep(j) = Dep(j)+1.D0 + endif + if (x.eq.0.D0) then + Dep(nbins) = Dep(nbins)+1.D0 + endif + 26 continue + endif + + endif + 10 continue + + RETURN + + END + + subroutine output(Dg,Dnum,Dnuma,Dnue,Dnuea,Dp,Dn,Dem,Dep,nbins, + & ninc,nameinc,delx,Emin,Emax,E0_arr,epsmin,epsmax) + +c******************************************************************** +c*** OUTPUT ROUTINE for particle spectra: ******* +c*** considered particles: ******* +c*** photons, protons, neutrons, e-neutrinos, nu-neutrinos, ******* +c*** electron, positron ******* +c*** spectra of each particle stored in separate files ******* +c******************************************************************** +c** Date: 20/02/98 ** +c** author: A.Muecke ** +c********************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-M) + SAVE + + COMMON/input/ tbb,E0,alpha1,alpha2, + & epsm1,epsm2,epsb,L0 + + DIMENSION Dg(101,201),Dnum(101,201),Dnue(101,201) + DIMENSION Dp(101,201),Dn(101,201),Dnuma(101,201),E0_arr(101) + DIMENSION Dem(101,201),Dep(101,201),Dnuea(101,201) + character*5 particle + character*7 spart,fpart + character*13 filename + character*6 nameinc + character mat*20, strnm1*2 + character mat1*20, strnm11*2 + character mat2*20, strnm12*2 + + 571 format(2(3x,E10.5),3x,I3,5(3x,E10.5), + & 3x,I3,3x,E10.5,3x,A10,3x,A10) + 572 format(E10.5,3x,2(I3,3x)) + 573 format(2x,E10.5) + + print* + print*,'OUTPUT files:' +c********************************************** +c******** GAMMA spectra: ********************** + particle = 'gamma' + filename = nameinc // '.' // particle + print*,'filename = ',filename + if (L0.eq.13) spart = 'proton' + if (L0.eq.14) spart = 'neutron' + fpart = 'photon' + if (tbb.gt.0.) then + target1 = tbb + target2 = 0. + else + target1 = alpha1 + target2 = alpha2 + endif + open(1,file=filename) +c... write input parameters: + write(1,571) Emin,Emax,ninc,target1,target2, + & epsmin,epsb,epsmax,nbins,delx,spart,fpart +c... nucleon energy loop: + do i=1,ninc +c ... determine j-range = range of energy bins not equal zero + jini = 0 + jfin = 0 +c... particle spectrum loop: + do j=1,nbins + if (Dg(i,j).gt.0.D0) then + jfin = j + if (jini.eq.0) jini = j + endif + enddo + nm = jfin-jini+1 + nm1 = nm+1 + write(strnm1,'(I2)') nm1 + mat = '(' // strnm1 // '(5X,E10.4))' + nmc = 81 + nmc2 = 82 + write(strnm11,'(I2)') nmc2 + mat1 = '(' // strnm11 // '(5X,E10.4))' + nmcf = jfin-jini-80+1 + nmcf2 = nmcf+1 + write(strnm12,'(I2)') nmcf2 + mat2 = '(' // strnm12 // '(5X,E10.4))' + if (jfin.gt.0) then + write(1,572) E0_arr(i),jini,jfin +c... values written in one line: + if (jfin-jini.lt.80) then + write(1,FMT=mat) (Dg(i,jl),jl=jini,jfin) + else + jfin0 = jini+80 + write(1,FMT=mat1) (Dg(i,jl),jl=jini,jfin0) + write(1,FMT=mat2) (Dg(i,jl),jl=jfin0+1,jfin) + endif + endif + enddo + close(1) + +c********************************************** +c******** MU-NEUTRINO spectra: ********************** + particle = 'muneu' + filename = nameinc // '.' // particle + print*,'filename = ',filename + open(1,file=filename) + write(1,571) Emin,Emax,ninc,target1,target2, + & epsmin,epsb,epsmax,nbins,delx,spart,fpart +c... nucleon energy loop: + do i=1,ninc +c ... determine j-range = range of energy bins not equal zero + jini = 0 + jfin = 0 +c... particle spectrum loop: + do j=1,nbins + if (Dnum(i,j).gt.0.D0) then + jfin = j + if (jini.eq.0) jini = j + endif + enddo + nm = jfin-jini+1 + nm1 = nm+1 + write(strnm1,'(I2)') nm1 + mat = '(' // strnm1 // '(5X,E10.4))' + nmc = 81 + nmc2 = 82 + write(strnm11,'(I2)') nmc2 + mat1 = '(' // strnm11 // '(5X,E10.4))' + nmcf = jfin-jini-80+1 + nmcf2 = nmcf+1 + write(strnm12,'(I2)') nmcf2 + mat2 = '(' // strnm12 // '(5X,E10.4))' + if (jfin.gt.0) then + write(1,572) E0_arr(i),jini,jfin +c... values written in one line: + if (jfin-jini.lt.80) then + write(1,FMT=mat) (Dnum(i,jl),jl=jini,jfin) + else + jfin0 = jini+80 + write(1,FMT=mat1) (Dnum(i,jl),jl=jini,jfin0) + write(1,FMT=mat2) (Dnum(i,jl),jl=jfin0+1,jfin) + endif + endif + enddo + close(1) + + particle = 'muane' + filename = nameinc // '.' // particle + print*,'filename = ',filename + open(1,file=filename) + write(1,571) Emin,Emax,ninc,target1,target2, + & epsmin,epsb,epsmax,nbins,delx,spart,fpart +c... nucleon energy loop: + do i=1,ninc +c ... determine j-range = range of energy bins not equal zero + jini = 0 + jfin = 0 +c... particle spectrum loop: + do j=1,nbins + if (Dnuma(i,j).gt.0.D0) then + jfin = j + if (jini.eq.0) jini = j + endif + enddo + nm = jfin-jini+1 + nm1 = nm+1 + write(strnm1,'(I2)') nm1 + mat = '(' // strnm1 // '(5X,E10.4))' + nmc = 81 + nmc2 = 82 + write(strnm11,'(I2)') nmc2 + mat1 = '(' // strnm11 // '(5X,E10.4))' + nmcf = jfin-jini-80+1 + nmcf2 = nmcf+1 + write(strnm12,'(I2)') nmcf2 + mat2 = '(' // strnm12 // '(5X,E10.4))' + if (jfin.gt.0) then + write(1,572) E0_arr(i),jini,jfin +c... values written in one line: + if (jfin-jini.lt.80) then + write(1,FMT=mat) (Dnuma(i,jl),jl=jini,jfin) + else + jfin0 = jini+80 + write(1,FMT=mat1) (Dnuma(i,jl),jl=jini,jfin0) + write(1,FMT=mat2) (Dnuma(i,jl),jl=jfin0+1,jfin) + endif + endif + enddo + close(1) + +c********************************************** +c******** ELECTRON NEUTRINO spectra: ********** + particle = 'e_neu' + filename = nameinc // '.' // particle + print*,'filename = ',filename + open(1,file=filename) + write(1,571) Emin,Emax,ninc,target1,target2, + & epsmin,epsb,epsmax,nbins,delx,spart,fpart +c... nucleon energy loop: + do i=1,ninc +c ... determine j-range = range of energy bins not equal zero + jini = 0 + jfin = 0 +c... particle spectrum loop: + do j=1,nbins + if (Dnue(i,j).gt.0.D0) then + jfin = j + if (jini.eq.0) jini = j + endif + enddo + nm = jfin-jini+1 + nm1 = nm+1 + write(strnm1,'(I2)') nm1 + mat = '(' // strnm1 // '(5X,E10.4))' + nmc = 81 + nmc2 = 82 + write(strnm11,'(I2)') nmc2 + mat1 = '(' // strnm11 // '(5X,E10.4))' + nmcf = jfin-jini-80+1 + nmcf2 = nmcf+1 + write(strnm12,'(I2)') nmcf2 + mat2 = '(' // strnm12 // '(5X,E10.4))' + if (jfin.gt.0) then + write(1,572) E0_arr(i),jini,jfin +c... values written in one line: + if (jfin-jini.lt.80) then + write(1,FMT=mat) (Dnue(i,jl),jl=jini,jfin) + else + jfin0 = jini+80 + write(1,FMT=mat1) (Dnue(i,jl),jl=jini,jfin0) + write(1,FMT=mat2) (Dnue(i,jl),jl=jfin0+1,jfin) + endif + endif + enddo + close(1) + + particle = 'eaneu' + filename = nameinc // '.' // particle + print*,'filename = ',filename + open(1,file=filename) + write(1,571) Emin,Emax,ninc,target1,target2, + & epsmin,epsb,epsmax,nbins,delx,spart,fpart +c... nucleon energy loop: + do i=1,ninc +c ... determine j-range = range of energy bins not equal zero + jini = 0 + jfin = 0 +c... particle spectrum loop: + do j=1,nbins + if (Dnuea(i,j).gt.0.D0) then + jfin = j + if (jini.eq.0) jini = j + endif + enddo + nm = jfin-jini+1 + nm1 = nm+1 + write(strnm1,'(I2)') nm1 + mat = '(' // strnm1 // '(5X,E10.4))' + nmc = 81 + nmc2 = 82 + write(strnm11,'(I2)') nmc2 + mat1 = '(' // strnm11 // '(5X,E10.4))' + nmcf = jfin-jini-80+1 + nmcf2 = nmcf+1 + write(strnm12,'(I2)') nmcf2 + mat2 = '(' // strnm12 // '(5X,E10.4))' + if (jfin.gt.0) then + write(1,572) E0_arr(i),jini,jfin +c... values written in one line: + if (jfin-jini.lt.80) then + write(1,FMT=mat) (Dnuea(i,jl),jl=jini,jfin) + else + jfin0 = jini+80 + write(1,FMT=mat1) (Dnuea(i,jl),jl=jini,jfin0) + write(1,FMT=mat2) (Dnuea(i,jl),jl=jfin0+1,jfin) + endif + endif + enddo + close(1) + +c********************************************** +c******** ELECTRON spectra: ********************** + particle = 'elect' + filename = nameinc // '.' // particle + print*,'filename = ',filename + open(1,file=filename) + write(1,571) Emin,Emax,ninc,target1,target2, + & epsmin,epsb,epsmax,nbins,delx,spart,fpart +c... nucleon energy loop: + do i=1,ninc +c ... determine j-range = range of energy bins not equal zero + jini = 0 + jfin = 0 +c... particle spectrum loop: + do j=1,nbins + if (Dem(i,j).gt.0.D0) then + jfin = j + if (jini.eq.0) jini = j + endif + enddo + nm = jfin-jini+1 + nm1 = nm+1 + write(strnm1,'(I2)') nm1 + mat = '(' // strnm1 // '(5X,E10.4))' + nmc = 81 + nmc2 = 82 + write(strnm11,'(I2)') nmc2 + mat1 = '(' // strnm11 // '(5X,E10.4))' + nmcf = jfin-jini-80+1 + nmcf2 = nmcf+1 + write(strnm12,'(I2)') nmcf2 + mat2 = '(' // strnm12 // '(5X,E10.4))' + if (jfin.gt.0) then + write(1,572) E0_arr(i),jini,jfin +c... values written in one line: + if (jfin-jini.lt.80) then + write(1,FMT=mat) (Dem(i,jl),jl=jini,jfin) + else + jfin0 = jini+80 + write(1,FMT=mat1) (Dem(i,jl),jl=jini,jfin0) + write(1,FMT=mat2) (Dem(i,jl),jl=jfin0+1,jfin) + endif + endif + enddo + close(1) + +c********************************************** +c******** POSITRON spectra: ********************** + particle = 'posit' + filename = nameinc // '.' // particle + print*,'filename = ',filename + open(1,file=filename) + write(1,571) Emin,Emax,ninc,target1,target2, + & epsmin,epsb,epsmax,nbins,delx,spart,fpart +c... nucleon energy loop: + do i=1,ninc +c ... determine j-range = range of energy bins not equal zero + jini = 0 + jfin = 0 +c... particle spectrum loop: + do j=1,nbins + if (Dep(i,j).gt.0.D0) then + jfin = j + if (jini.eq.0) jini = j + endif + enddo + nm = jfin-jini+1 + nm1 = nm+1 + write(strnm1,'(I2)') nm1 + mat = '(' // strnm1 // '(5X,E10.4))' + nmc = 81 + nmc2 = 82 + write(strnm11,'(I2)') nmc2 + mat1 = '(' // strnm11 // '(5X,E10.4))' + nmcf = jfin-jini-80+1 + nmcf2 = nmcf+1 + write(strnm12,'(I2)') nmcf2 + mat2 = '(' // strnm12 // '(5X,E10.4))' + if (jfin.gt.0) then + write(1,572) E0_arr(i),jini,jfin +c... values written in one line: + if (jfin-jini.lt.80) then + write(1,FMT=mat) (Dep(i,jl),jl=jini,jfin) + else + jfin0 = jini+80 + write(1,FMT=mat1) (Dep(i,jl),jl=jini,jfin0) + write(1,FMT=mat2) (Dep(i,jl),jl=jfin0+1,jfin) + endif + endif + enddo + close(1) + +c********************************************** +c******** PROTON spectra: ********************** + particle = 'proto' + filename = nameinc // '.' // particle + print*,'filename = ',filename + open(1,file=filename) + write(1,571) Emin,Emax,ninc,target1,target2, + & epsmin,epsb,epsmax,nbins,delx,spart,fpart +c... nucleon energy loop: + do i=1,ninc +c ... determine j-range = range of energy bins not equal zero + jini = 0 + jfin = 0 +c... particle spectrum loop: + do j=1,nbins + if (Dp(i,j).gt.0.D0) then + jfin = j + if (jini.eq.0) jini = j + endif + enddo + nm = jfin-jini+1 + nm1 = nm+1 + write(strnm1,'(I2)') nm1 + mat = '(' // strnm1 // '(5X,E10.4))' + nmc = 81 + nmc2 = 82 + write(strnm11,'(I2)') nmc2 + mat1 = '(' // strnm11 // '(5X,E10.4))' + nmcf = jfin-jini-80+1 + nmcf2 = nmcf+1 + write(strnm12,'(I2)') nmcf2 + mat2 = '(' // strnm12 // '(5X,E10.4))' + if (jfin.gt.0) then + write(1,572) E0_arr(i),jini,jfin +c... values written in one line: + if (jfin-jini.lt.80) then + write(1,FMT=mat) (Dp(i,jl),jl=jini,jfin) + else + jfin0 = jini+80 + write(1,FMT=mat1) (Dp(i,jl),jl=jini,jfin0) + write(1,FMT=mat2) (Dp(i,jl),jl=jfin0+1,jfin) + endif + endif + enddo + close(1) + +c********************************************** +c******** NEUTRON spectra: ********************** + particle = 'neutr' + filename = nameinc // '.' // particle + print*,'filename = ',filename + open(1,file=filename) + write(1,571) Emin,Emax,ninc,target1,target2, + & epsmin,epsb,epsmax,nbins,delx,spart,fpart +c... nucleon energy loop: + do i=1,ninc +c ... determine j-range = range of energy bins not equal zero + jini = 0 + jfin = 0 +c... particle spectrum loop: + do j=1,nbins + if (Dn(i,j).gt.0.D0) then + jfin = j + if (jini.eq.0) jini = j + endif + enddo + nm = jfin-jini+1 + nm1 = nm+1 + write(strnm1,'(I2)') nm1 + mat = '(' // strnm1 // '(5X,E10.4))' + nmc = 81 + nmc2 = 82 + write(strnm11,'(I2)') nmc2 + mat1 = '(' // strnm11 // '(5X,E10.4))' + nmcf = jfin-jini-80+1 + nmcf2 = nmcf+1 + write(strnm12,'(I2)') nmcf2 + mat2 = '(' // strnm12 // '(5X,E10.4))' + if (jfin.gt.0) then + write(1,572) E0_arr(i),jini,jfin +c... values written in one line: + if (jfin-jini.lt.80) then + write(1,FMT=mat) (Dn(i,jl),jl=jini,jfin) + else + jfin0 = jini+80 + write(1,FMT=mat1) (Dn(i,jl),jl=jini,jfin0) + write(1,FMT=mat2) (Dn(i,jl),jl=jfin0+1,jfin) + endif + endif + enddo + close(1) + + RETURN + END +cFrom eng@lepton.bartol.udel.edu +cDate: Sun, 15 Nov 1998 18:18:44 -0500 +cFrom: Ralph R Engel +cTo: amuecke@physics.adelaide.edu.au +cSubject: File: jetset74dp.f +c +C +C WARNING: this file has been changed to double precision, +C alignment problems made it necessary to change also +C /LUJETS/, /PYSUBS/, and /PYINT5/ +C +C********************************************************************* +C********************************************************************* +C* ** +C* December 1993 ** +C* ** +C* The Lund Monte Carlo for Jet Fragmentation and e+e- Physics ** +C* ** +C* JETSET version 7.4 ** +C* ** +C* Torbjorn Sjostrand ** +C* Department of theoretical physics 2 ** +C* University of Lund ** +C* Solvegatan 14A, S-223 62 Lund, Sweden ** +C* E-mail torbjorn@thep.lu.se ** +C* phone +46 - 46 - 222 48 16 ** +C* ** +C* LUSHOW is written together with Mats Bengtsson ** +C* ** +C* The latest program version and documentation is found on WWW ** +C* http://thep.lu.se/tf2/staff/torbjorn/Welcome.html ** +C* ** +C* Copyright Torbjorn Sjostrand and CERN, Geneva 1993 ** +C* ** +C********************************************************************* +C********************************************************************* +C * +C List of subprograms in order of appearance, with main purpose * +C (S = subroutine, F = function, B = block data) * +C * +C S LU1ENT to fill one entry (= parton or particle) * +C S LU2ENT to fill two entries * +C S LU3ENT to fill three entries * +C S LU4ENT to fill four entries * +C S LUJOIN to connect entries with colour flow information * +C S LUGIVE to fill (or query) commonblock variables * +C S LUEXEC to administrate fragmentation and decay chain * +C S LUPREP to rearrange showered partons along strings * +C S LUSTRF to do string fragmentation of jet system * +C S LUINDF to do independent fragmentation of one or many jets * +C S LUDECY to do the decay of a particle * +C S LUKFDI to select parton and hadron flavours in fragm * +C S LUPTDI to select transverse momenta in fragm * +C S LUZDIS to select longitudinal scaling variable in fragm * +C S LUSHOW to do timelike parton shower evolution * +C S LUBOEI to include Bose-Einstein effects (crudely) * +C F ULMASS to give the mass of a particle or parton * +C S LUNAME to give the name of a particle or parton * +C F LUCHGE to give three times the electric charge * +C F LUCOMP to compress standard KF flavour code to internal KC * +C S LUERRM to write error messages and abort faulty run * +C F ULALEM to give the alpha_electromagnetic value * +C F ULALPS to give the alpha_strong value * +C F ULANGL to give the angle from known x and y components * +C F RLU to provide a random number generator * +C S RLUGET to save the state of the random number generator * +C S RLUSET to set the state of the random number generator * +C S LUROBO to rotate and/or boost an event * +C S LUEDIT to remove unwanted entries from record * +C S LULIST to list event record or particle data * +C S LULOGO to write a logo for JETSET and PYTHIA * +C S LUUPDA to update particle data * +C F KLU to provide integer-valued event information * +C F PLU to provide real-valued event information * +C S LUSPHE to perform sphericity analysis * +C S LUTHRU to perform thrust analysis * +C S LUCLUS to perform three-dimensional cluster analysis * +C S LUCELL to perform cluster analysis in (eta, phi, E_T) * +C S LUJMAS to give high and low jet mass of event * +C S LUFOWO to give Fox-Wolfram moments * +C S LUTABU to analyze events, with tabular output * +C * +C S LUEEVT to administrate the generation of an e+e- event * +C S LUXTOT to give the total cross-section at given CM energy * +C S LURADK to generate initial state photon radiation * +C S LUXKFL to select flavour of primary qqbar pair * +C S LUXJET to select (matrix element) jet multiplicity * +C S LUX3JT to select kinematics of three-jet event * +C S LUX4JT to select kinematics of four-jet event * +C S LUXDIF to select angular orientation of event * +C S LUONIA to perform generation of onium decay to gluons * +C * +C S LUHEPC to convert between /LUJETS/ and /HEPEVT/ records * +C S LUTEST to test the proper functioning of the package * +C B LUDATA to contain default values and particle data * +C * +C********************************************************************* + +CDECK ID>, LU1ENT + SUBROUTINE LU1ENT(IP,KF,PE,THE,PHI) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to store one parton/particle in commonblock LUJETS. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + +C...Standard checks. + MSTU(28)=0 + IF(MSTU(12).GE.1) CALL LULIST(0) + IPA=MAX(1,IABS(IP)) + IF(IPA.GT.MSTU(4)) CALL LUERRM(21, + &'(LU1ENT:) writing outside LUJETS memory') + KC=LUCOMP(KF) + IF(KC.EQ.0) CALL LUERRM(12,'(LU1ENT:) unknown flavour code') + +C...Find mass. Reset K, P and V vectors. + PM=0. + IF(MSTU(10).EQ.1) PM=P(IPA,5) + IF(MSTU(10).GE.2) PM=ULMASS(KF) + DO 100 J=1,5 + K(IPA,J)=0 + P(IPA,J)=0. + V(IPA,J)=0. + 100 CONTINUE + +C...Store parton/particle in K and P vectors. + K(IPA,1)=1 + IF(IP.LT.0) K(IPA,1)=2 + K(IPA,2)=KF + P(IPA,5)=PM + P(IPA,4)=MAX(PE,PM) + PA=SQRT(P(IPA,4)**2-P(IPA,5)**2) + P(IPA,1)=PA*SIN(THE)*COS(PHI) + P(IPA,2)=PA*SIN(THE)*SIN(PHI) + P(IPA,3)=PA*COS(THE) + +C...Set N. Optionally fragment/decay. + N=IPA + IF(IP.EQ.0) CALL LUEXEC + + RETURN + END + +C********************************************************************* + +CDECK ID>, LU2ENT + SUBROUTINE LU2ENT(IP,KF1,KF2,PECM) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to store two partons/particles in their CM frame, +C...with the first along the +z axis. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + +C...Standard checks. + MSTU(28)=0 + IF(MSTU(12).GE.1) CALL LULIST(0) + IPA=MAX(1,IABS(IP)) + IF(IPA.GT.MSTU(4)-1) CALL LUERRM(21, + &'(LU2ENT:) writing outside LUJETS memory') + KC1=LUCOMP(KF1) + KC2=LUCOMP(KF2) + IF(KC1.EQ.0.OR.KC2.EQ.0) CALL LUERRM(12, + &'(LU2ENT:) unknown flavour code') + +C...Find masses. Reset K, P and V vectors. + PM1=0. + IF(MSTU(10).EQ.1) PM1=P(IPA,5) + IF(MSTU(10).GE.2) PM1=ULMASS(KF1) + PM2=0. + IF(MSTU(10).EQ.1) PM2=P(IPA+1,5) + IF(MSTU(10).GE.2) PM2=ULMASS(KF2) + DO 110 I=IPA,IPA+1 + DO 100 J=1,5 + K(I,J)=0 + P(I,J)=0. + V(I,J)=0. + 100 CONTINUE + 110 CONTINUE + +C...Check flavours. + KQ1=KCHG(KC1,2)*ISIGN(1,KF1) + KQ2=KCHG(KC2,2)*ISIGN(1,KF2) + IF(MSTU(19).EQ.1) THEN + MSTU(19)=0 + ELSE + IF(KQ1+KQ2.NE.0.AND.KQ1+KQ2.NE.4) CALL LUERRM(2, + & '(LU2ENT:) unphysical flavour combination') + ENDIF + K(IPA,2)=KF1 + K(IPA+1,2)=KF2 + +C...Store partons/particles in K vectors for normal case. + IF(IP.GE.0) THEN + K(IPA,1)=1 + IF(KQ1.NE.0.AND.KQ2.NE.0) K(IPA,1)=2 + K(IPA+1,1)=1 + +C...Store partons in K vectors for parton shower evolution. + ELSE + K(IPA,1)=3 + K(IPA+1,1)=3 + K(IPA,4)=MSTU(5)*(IPA+1) + K(IPA,5)=K(IPA,4) + K(IPA+1,4)=MSTU(5)*IPA + K(IPA+1,5)=K(IPA+1,4) + ENDIF + +C...Check kinematics and store partons/particles in P vectors. + IF(PECM.LE.PM1+PM2) CALL LUERRM(13, + &'(LU2ENT:) energy smaller than sum of masses') + PA=SQRT(MAX(0.D0,(PECM**2-PM1**2-PM2**2)**2-(2.*PM1*PM2)**2))/ + &(2.*PECM) + P(IPA,3)=PA + P(IPA,4)=SQRT(PM1**2+PA**2) + P(IPA,5)=PM1 + P(IPA+1,3)=-PA + P(IPA+1,4)=SQRT(PM2**2+PA**2) + P(IPA+1,5)=PM2 + +C...Set N. Optionally fragment/decay. + N=IPA+1 + IF(IP.EQ.0) CALL LUEXEC + + RETURN + END + +C********************************************************************* + +CDECK ID>, LU3ENT + SUBROUTINE LU3ENT(IP,KF1,KF2,KF3,PECM,X1,X3) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to store three partons or particles in their CM frame, +C...with the first along the +z axis and the third in the (x,z) +C...plane with x > 0. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + +C...Standard checks. + MSTU(28)=0 + IF(MSTU(12).GE.1) CALL LULIST(0) + IPA=MAX(1,IABS(IP)) + IF(IPA.GT.MSTU(4)-2) CALL LUERRM(21, + &'(LU3ENT:) writing outside LUJETS memory') + KC1=LUCOMP(KF1) + KC2=LUCOMP(KF2) + KC3=LUCOMP(KF3) + IF(KC1.EQ.0.OR.KC2.EQ.0.OR.KC3.EQ.0) CALL LUERRM(12, + &'(LU3ENT:) unknown flavour code') + +C...Find masses. Reset K, P and V vectors. + PM1=0. + IF(MSTU(10).EQ.1) PM1=P(IPA,5) + IF(MSTU(10).GE.2) PM1=ULMASS(KF1) + PM2=0. + IF(MSTU(10).EQ.1) PM2=P(IPA+1,5) + IF(MSTU(10).GE.2) PM2=ULMASS(KF2) + PM3=0. + IF(MSTU(10).EQ.1) PM3=P(IPA+2,5) + IF(MSTU(10).GE.2) PM3=ULMASS(KF3) + DO 110 I=IPA,IPA+2 + DO 100 J=1,5 + K(I,J)=0 + P(I,J)=0. + V(I,J)=0. + 100 CONTINUE + 110 CONTINUE + +C...Check flavours. + KQ1=KCHG(KC1,2)*ISIGN(1,KF1) + KQ2=KCHG(KC2,2)*ISIGN(1,KF2) + KQ3=KCHG(KC3,2)*ISIGN(1,KF3) + IF(MSTU(19).EQ.1) THEN + MSTU(19)=0 + ELSEIF(KQ1.EQ.0.AND.KQ2.EQ.0.AND.KQ3.EQ.0) THEN + ELSEIF(KQ1.NE.0.AND.KQ2.EQ.2.AND.(KQ1+KQ3.EQ.0.OR. + &KQ1+KQ3.EQ.4)) THEN + ELSE + CALL LUERRM(2,'(LU3ENT:) unphysical flavour combination') + ENDIF + K(IPA,2)=KF1 + K(IPA+1,2)=KF2 + K(IPA+2,2)=KF3 + +C...Store partons/particles in K vectors for normal case. + IF(IP.GE.0) THEN + K(IPA,1)=1 + IF(KQ1.NE.0.AND.(KQ2.NE.0.OR.KQ3.NE.0)) K(IPA,1)=2 + K(IPA+1,1)=1 + IF(KQ2.NE.0.AND.KQ3.NE.0) K(IPA+1,1)=2 + K(IPA+2,1)=1 + +C...Store partons in K vectors for parton shower evolution. + ELSE + K(IPA,1)=3 + K(IPA+1,1)=3 + K(IPA+2,1)=3 + KCS=4 + IF(KQ1.EQ.-1) KCS=5 + K(IPA,KCS)=MSTU(5)*(IPA+1) + K(IPA,9-KCS)=MSTU(5)*(IPA+2) + K(IPA+1,KCS)=MSTU(5)*(IPA+2) + K(IPA+1,9-KCS)=MSTU(5)*IPA + K(IPA+2,KCS)=MSTU(5)*IPA + K(IPA+2,9-KCS)=MSTU(5)*(IPA+1) + ENDIF + +C...Check kinematics. + MKERR=0 + IF(0.5*X1*PECM.LE.PM1.OR.0.5*(2.-X1-X3)*PECM.LE.PM2.OR. + &0.5*X3*PECM.LE.PM3) MKERR=1 + PA1=SQRT(MAX(1D-10,(0.5*X1*PECM)**2-PM1**2)) + PA2=SQRT(MAX(1D-10,(0.5*(2.-X1-X3)*PECM)**2-PM2**2)) + PA3=SQRT(MAX(1D-10,(0.5*X3*PECM)**2-PM3**2)) + CTHE2=(PA3**2-PA1**2-PA2**2)/(2.*PA1*PA2) + CTHE3=(PA2**2-PA1**2-PA3**2)/(2.*PA1*PA3) + IF(ABS(CTHE2).GE.1.001.OR.ABS(CTHE3).GE.1.001) MKERR=1 + CTHE3=MAX(-1.D0,MIN(1.D0,CTHE3)) + IF(MKERR.NE.0) CALL LUERRM(13, + &'(LU3ENT:) unphysical kinematical variable setup') + +C...Store partons/particles in P vectors. + P(IPA,3)=PA1 + P(IPA,4)=SQRT(PA1**2+PM1**2) + P(IPA,5)=PM1 + P(IPA+2,1)=PA3*SQRT(1.-CTHE3**2) + P(IPA+2,3)=PA3*CTHE3 + P(IPA+2,4)=SQRT(PA3**2+PM3**2) + P(IPA+2,5)=PM3 + P(IPA+1,1)=-P(IPA+2,1) + P(IPA+1,3)=-P(IPA,3)-P(IPA+2,3) + P(IPA+1,4)=SQRT(P(IPA+1,1)**2+P(IPA+1,3)**2+PM2**2) + P(IPA+1,5)=PM2 + +C...Set N. Optionally fragment/decay. + N=IPA+2 + IF(IP.EQ.0) CALL LUEXEC + + RETURN + END + +C********************************************************************* + +CDECK ID>, LU4ENT + SUBROUTINE LU4ENT(IP,KF1,KF2,KF3,KF4,PECM,X1,X2,X4,X12,X14) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to store four partons or particles in their CM frame, with +C...the first along the +z axis, the last in the xz plane with x > 0 +C...and the second having y < 0 and y > 0 with equal probability. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + +C...Standard checks. + MSTU(28)=0 + IF(MSTU(12).GE.1) CALL LULIST(0) + IPA=MAX(1,IABS(IP)) + IF(IPA.GT.MSTU(4)-3) CALL LUERRM(21, + &'(LU4ENT:) writing outside LUJETS momory') + KC1=LUCOMP(KF1) + KC2=LUCOMP(KF2) + KC3=LUCOMP(KF3) + KC4=LUCOMP(KF4) + IF(KC1.EQ.0.OR.KC2.EQ.0.OR.KC3.EQ.0.OR.KC4.EQ.0) CALL LUERRM(12, + &'(LU4ENT:) unknown flavour code') + +C...Find masses. Reset K, P and V vectors. + PM1=0. + IF(MSTU(10).EQ.1) PM1=P(IPA,5) + IF(MSTU(10).GE.2) PM1=ULMASS(KF1) + PM2=0. + IF(MSTU(10).EQ.1) PM2=P(IPA+1,5) + IF(MSTU(10).GE.2) PM2=ULMASS(KF2) + PM3=0. + IF(MSTU(10).EQ.1) PM3=P(IPA+2,5) + IF(MSTU(10).GE.2) PM3=ULMASS(KF3) + PM4=0. + IF(MSTU(10).EQ.1) PM4=P(IPA+3,5) + IF(MSTU(10).GE.2) PM4=ULMASS(KF4) + DO 110 I=IPA,IPA+3 + DO 100 J=1,5 + K(I,J)=0 + P(I,J)=0. + V(I,J)=0. + 100 CONTINUE + 110 CONTINUE + +C...Check flavours. + KQ1=KCHG(KC1,2)*ISIGN(1,KF1) + KQ2=KCHG(KC2,2)*ISIGN(1,KF2) + KQ3=KCHG(KC3,2)*ISIGN(1,KF3) + KQ4=KCHG(KC4,2)*ISIGN(1,KF4) + IF(MSTU(19).EQ.1) THEN + MSTU(19)=0 + ELSEIF(KQ1.EQ.0.AND.KQ2.EQ.0.AND.KQ3.EQ.0.AND.KQ4.EQ.0) THEN + ELSEIF(KQ1.NE.0.AND.KQ2.EQ.2.AND.KQ3.EQ.2.AND.(KQ1+KQ4.EQ.0.OR. + &KQ1+KQ4.EQ.4)) THEN + ELSEIF(KQ1.NE.0.AND.KQ1+KQ2.EQ.0.AND.KQ3.NE.0.AND.KQ3+KQ4.EQ.0.) + &THEN + ELSE + CALL LUERRM(2,'(LU4ENT:) unphysical flavour combination') + ENDIF + K(IPA,2)=KF1 + K(IPA+1,2)=KF2 + K(IPA+2,2)=KF3 + K(IPA+3,2)=KF4 + +C...Store partons/particles in K vectors for normal case. + IF(IP.GE.0) THEN + K(IPA,1)=1 + IF(KQ1.NE.0.AND.(KQ2.NE.0.OR.KQ3.NE.0.OR.KQ4.NE.0)) K(IPA,1)=2 + K(IPA+1,1)=1 + IF(KQ2.NE.0.AND.KQ1+KQ2.NE.0.AND.(KQ3.NE.0.OR.KQ4.NE.0)) + & K(IPA+1,1)=2 + K(IPA+2,1)=1 + IF(KQ3.NE.0.AND.KQ4.NE.0) K(IPA+2,1)=2 + K(IPA+3,1)=1 + +C...Store partons for parton shower evolution from q-g-g-qbar or +C...g-g-g-g event. + ELSEIF(KQ1+KQ2.NE.0) THEN + K(IPA,1)=3 + K(IPA+1,1)=3 + K(IPA+2,1)=3 + K(IPA+3,1)=3 + KCS=4 + IF(KQ1.EQ.-1) KCS=5 + K(IPA,KCS)=MSTU(5)*(IPA+1) + K(IPA,9-KCS)=MSTU(5)*(IPA+3) + K(IPA+1,KCS)=MSTU(5)*(IPA+2) + K(IPA+1,9-KCS)=MSTU(5)*IPA + K(IPA+2,KCS)=MSTU(5)*(IPA+3) + K(IPA+2,9-KCS)=MSTU(5)*(IPA+1) + K(IPA+3,KCS)=MSTU(5)*IPA + K(IPA+3,9-KCS)=MSTU(5)*(IPA+2) + +C...Store partons for parton shower evolution from q-qbar-q-qbar event. + ELSE + K(IPA,1)=3 + K(IPA+1,1)=3 + K(IPA+2,1)=3 + K(IPA+3,1)=3 + K(IPA,4)=MSTU(5)*(IPA+1) + K(IPA,5)=K(IPA,4) + K(IPA+1,4)=MSTU(5)*IPA + K(IPA+1,5)=K(IPA+1,4) + K(IPA+2,4)=MSTU(5)*(IPA+3) + K(IPA+2,5)=K(IPA+2,4) + K(IPA+3,4)=MSTU(5)*(IPA+2) + K(IPA+3,5)=K(IPA+3,4) + ENDIF + +C...Check kinematics. + MKERR=0 + IF(0.5*X1*PECM.LE.PM1.OR.0.5*X2*PECM.LE.PM2.OR.0.5*(2.-X1-X2-X4)* + &PECM.LE.PM3.OR.0.5*X4*PECM.LE.PM4) MKERR=1 + PA1=SQRT(MAX(1D-10,(0.5*X1*PECM)**2-PM1**2)) + PA2=SQRT(MAX(1D-10,(0.5*X2*PECM)**2-PM2**2)) + PA4=SQRT(MAX(1D-10,(0.5*X4*PECM)**2-PM4**2)) + X24=X1+X2+X4-1.-X12-X14+(PM3**2-PM1**2-PM2**2-PM4**2)/PECM**2 + CTHE4=(X1*X4-2.*X14)*PECM**2/(4.*PA1*PA4) + IF(ABS(CTHE4).GE.1.002) MKERR=1 + CTHE4=MAX(-1.D0,MIN(1.D0,CTHE4)) + STHE4=SQRT(1.-CTHE4**2) + CTHE2=(X1*X2-2.*X12)*PECM**2/(4.*PA1*PA2) + IF(ABS(CTHE2).GE.1.002) MKERR=1 + CTHE2=MAX(-1.D0,MIN(1.D0,CTHE2)) + STHE2=SQRT(1.-CTHE2**2) + CPHI2=((X2*X4-2.*X24)*PECM**2-4.*PA2*CTHE2*PA4*CTHE4)/ + &MAX(1D-8*PECM**2,4.*PA2*STHE2*PA4*STHE4) + IF(ABS(CPHI2).GE.1.05) MKERR=1 + CPHI2=MAX(-1.D0,MIN(1.D0,CPHI2)) + IF(MKERR.EQ.1) CALL LUERRM(13, + &'(LU4ENT:) unphysical kinematical variable setup') + +C...Store partons/particles in P vectors. + P(IPA,3)=PA1 + P(IPA,4)=SQRT(PA1**2+PM1**2) + P(IPA,5)=PM1 + P(IPA+3,1)=PA4*STHE4 + P(IPA+3,3)=PA4*CTHE4 + P(IPA+3,4)=SQRT(PA4**2+PM4**2) + P(IPA+3,5)=PM4 + P(IPA+1,1)=PA2*STHE2*CPHI2 + P(IPA+1,2)=PA2*STHE2*SQRT(1.-CPHI2**2)*(-1.)**INT(RLU(0)+0.5) + P(IPA+1,3)=PA2*CTHE2 + P(IPA+1,4)=SQRT(PA2**2+PM2**2) + P(IPA+1,5)=PM2 + P(IPA+2,1)=-P(IPA+1,1)-P(IPA+3,1) + P(IPA+2,2)=-P(IPA+1,2) + P(IPA+2,3)=-P(IPA,3)-P(IPA+1,3)-P(IPA+3,3) + P(IPA+2,4)=SQRT(P(IPA+2,1)**2+P(IPA+2,2)**2+P(IPA+2,3)**2+PM3**2) + P(IPA+2,5)=PM3 + +C...Set N. Optionally fragment/decay. + N=IPA+3 + IF(IP.EQ.0) CALL LUEXEC + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUJOIN + SUBROUTINE LUJOIN(NJOIN,IJOIN) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to connect a sequence of partons with colour flow indices, +C...as required for subsequent shower evolution (or other operations). + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + DIMENSION IJOIN(*) + +C...Check that partons are of right types to be connected. + IF(NJOIN.LT.2) GOTO 120 + KQSUM=0 + DO 100 IJN=1,NJOIN + I=IJOIN(IJN) + IF(I.LE.0.OR.I.GT.N) GOTO 120 + IF(K(I,1).LT.1.OR.K(I,1).GT.3) GOTO 120 + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0) GOTO 120 + KQ=KCHG(KC,2)*ISIGN(1,K(I,2)) + IF(KQ.EQ.0) GOTO 120 + IF(IJN.NE.1.AND.IJN.NE.NJOIN.AND.KQ.NE.2) GOTO 120 + IF(KQ.NE.2) KQSUM=KQSUM+KQ + IF(IJN.EQ.1) KQS=KQ + 100 CONTINUE + IF(KQSUM.NE.0) GOTO 120 + +C...Connect the partons sequentially (closing for gluon loop). + KCS=(9-KQS)/2 + IF(KQS.EQ.2) KCS=INT(4.5+RLU(0)) + DO 110 IJN=1,NJOIN + I=IJOIN(IJN) + K(I,1)=3 + IF(IJN.NE.1) IP=IJOIN(IJN-1) + IF(IJN.EQ.1) IP=IJOIN(NJOIN) + IF(IJN.NE.NJOIN) IN=IJOIN(IJN+1) + IF(IJN.EQ.NJOIN) IN=IJOIN(1) + K(I,KCS)=MSTU(5)*IN + K(I,9-KCS)=MSTU(5)*IP + IF(IJN.EQ.1.AND.KQS.NE.2) K(I,9-KCS)=0 + IF(IJN.EQ.NJOIN.AND.KQS.NE.2) K(I,KCS)=0 + 110 CONTINUE + +C...Error exit: no action taken. + RETURN + 120 CALL LUERRM(12, + &'(LUJOIN:) given entries can not be joined by one string') + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUGIVE + SUBROUTINE LUGIVE(CHIN) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to set values of commonblock variables (also in PYTHIA!). + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) + COMMON/LUDAT4/CHAF(500) + CHARACTER CHAF*8 + COMMON/LUDATR/MRLU(6),RRLU(100) + COMMON/PYSUBS/MSUB(200),KFIN(2,-40:40),CKIN(200),MSEL + COMMON/PYPARS/MSTP(200),PARP(200),MSTI(200),PARI(200) + COMMON/PYINT1/MINT(400),VINT(400) + COMMON/PYINT2/ISET(200),KFPR(200,2),COEF(200,20),ICOL(40,4,2) + COMMON/PYINT3/XSFX(2,-40:40),ISIG(1000,3),SIGH(1000) + COMMON/PYINT4/WIDP(21:40,0:40),WIDE(21:40,0:40),WIDS(21:40,3) + COMMON/PYINT5/XSEC(0:200,3),NGEN(0:200,3) + COMMON/PYINT6/PROC(0:200) + COMMON/PYINT7/SIGT(0:6,0:6,0:5) + CHARACTER PROC*28 + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/,/LUDAT3/,/LUDAT4/,/LUDATR/ + SAVE /PYSUBS/,/PYPARS/,/PYINT1/,/PYINT2/,/PYINT3/,/PYINT4/, + &/PYINT5/,/PYINT6/,/PYINT7/ + CHARACTER CHIN*(*),CHFIX*104,CHBIT*104,CHOLD*8,CHNEW*8,CHOLD2*28, + &CHNEW2*28,CHNAM*4,CHVAR(43)*4,CHALP(2)*26,CHIND*8,CHINI*10, + &CHINR*16 + DIMENSION MSVAR(43,8) + +C...For each variable to be translated give: name, +C...integer/real/character, no. of indices, lower&upper index bounds. + DATA CHVAR/'N','K','P','V','MSTU','PARU','MSTJ','PARJ','KCHG', + &'PMAS','PARF','VCKM','MDCY','MDME','BRAT','KFDP','CHAF','MRLU', + &'RRLU','MSEL','MSUB','KFIN','CKIN','MSTP','PARP','MSTI','PARI', + &'MINT','VINT','ISET','KFPR','COEF','ICOL','XSFX','ISIG','SIGH', + &'WIDP','WIDE','WIDS','NGEN','XSEC','PROC','SIGT'/ + DATA ((MSVAR(I,J),J=1,8),I=1,43)/ 1,7*0, 1,2,1,4000,1,5,2*0, + & 2,2,1,4000,1,5,2*0, 2,2,1,4000,1,5,2*0, 1,1,1,200,4*0, + & 2,1,1,200,4*0, 1,1,1,200,4*0, 2,1,1,200,4*0, + & 1,2,1,500,1,3,2*0, 2,2,1,500,1,4,2*0, 2,1,1,2000,4*0, + & 2,2,1,4,1,4,2*0, 1,2,1,500,1,3,2*0, 1,2,1,2000,1,2,2*0, + & 2,1,1,2000,4*0, 1,2,1,2000,1,5,2*0, 3,1,1,500,4*0, + & 1,1,1,6,4*0, 2,1,1,100,4*0, + & 1,7*0, 1,1,1,200,4*0, 1,2,1,2,-40,40,2*0, 2,1,1,200,4*0, + & 1,1,1,200,4*0, 2,1,1,200,4*0, 1,1,1,200,4*0, 2,1,1,200,4*0, + & 1,1,1,400,4*0, 2,1,1,400,4*0, 1,1,1,200,4*0, + & 1,2,1,200,1,2,2*0, 2,2,1,200,1,20,2*0, 1,3,1,40,1,4,1,2, + & 2,2,1,2,-40,40,2*0, 1,2,1,1000,1,3,2*0, 2,1,1,1000,4*0, + & 2,2,21,40,0,40,2*0, 2,2,21,40,0,40,2*0, 2,2,21,40,1,3,2*0, + & 1,2,0,200,1,3,2*0, 2,2,0,200,1,3,2*0, 4,1,0,200,4*0, + & 2,3,0,6,0,6,0,5/ + DATA CHALP/'abcdefghijklmnopqrstuvwxyz', + &'ABCDEFGHIJKLMNOPQRSTUVWXYZ'/ + +C...Length of character variable. Subdivide it into instructions. + IF(MSTU(12).GE.1) CALL LULIST(0) + CHBIT=CHIN//' ' + LBIT=101 + 100 LBIT=LBIT-1 + IF(CHBIT(LBIT:LBIT).EQ.' ') GOTO 100 + LTOT=0 + DO 110 LCOM=1,LBIT + IF(CHBIT(LCOM:LCOM).EQ.' ') GOTO 110 + LTOT=LTOT+1 + CHFIX(LTOT:LTOT)=CHBIT(LCOM:LCOM) + 110 CONTINUE + LLOW=0 + 120 LHIG=LLOW+1 + 130 LHIG=LHIG+1 + IF(LHIG.LE.LTOT.AND.CHFIX(LHIG:LHIG).NE.';') GOTO 130 + LBIT=LHIG-LLOW-1 + CHBIT(1:LBIT)=CHFIX(LLOW+1:LHIG-1) + +C...Identify commonblock variable. + LNAM=1 + 140 LNAM=LNAM+1 + IF(CHBIT(LNAM:LNAM).NE.'('.AND.CHBIT(LNAM:LNAM).NE.'='.AND. + &LNAM.LE.4) GOTO 140 + CHNAM=CHBIT(1:LNAM-1)//' ' + DO 160 LCOM=1,LNAM-1 + DO 150 LALP=1,26 + IF(CHNAM(LCOM:LCOM).EQ.CHALP(1)(LALP:LALP)) CHNAM(LCOM:LCOM)= + &CHALP(2)(LALP:LALP) + 150 CONTINUE + 160 CONTINUE + IVAR=0 + DO 170 IV=1,43 + IF(CHNAM.EQ.CHVAR(IV)) IVAR=IV + 170 CONTINUE + IF(IVAR.EQ.0) THEN + CALL LUERRM(18,'(LUGIVE:) do not recognize variable '//CHNAM) + LLOW=LHIG + IF(LLOW.LT.LTOT) GOTO 120 + RETURN + ENDIF + +C...Identify any indices. + I1=0 + I2=0 + I3=0 + NINDX=0 + IF(CHBIT(LNAM:LNAM).EQ.'(') THEN + LIND=LNAM + 180 LIND=LIND+1 + IF(CHBIT(LIND:LIND).NE.')'.AND.CHBIT(LIND:LIND).NE.',') GOTO 180 + CHIND=' ' + IF((CHBIT(LNAM+1:LNAM+1).EQ.'C'.OR.CHBIT(LNAM+1:LNAM+1).EQ.'c'). + & AND.(IVAR.EQ.9.OR.IVAR.EQ.10.OR.IVAR.EQ.13.OR.IVAR.EQ.17)) THEN + CHIND(LNAM-LIND+11:8)=CHBIT(LNAM+2:LIND-1) + READ(CHIND,'(I8)') KF + I1=LUCOMP(KF) + ELSEIF(CHBIT(LNAM+1:LNAM+1).EQ.'C'.OR.CHBIT(LNAM+1:LNAM+1).EQ. + & 'c') THEN + CALL LUERRM(18,'(LUGIVE:) not allowed to use C index for '// + & CHNAM) + LLOW=LHIG + IF(LLOW.LT.LTOT) GOTO 120 + RETURN + ELSE + CHIND(LNAM-LIND+10:8)=CHBIT(LNAM+1:LIND-1) + READ(CHIND,'(I8)') I1 + ENDIF + LNAM=LIND + IF(CHBIT(LNAM:LNAM).EQ.')') LNAM=LNAM+1 + NINDX=1 + ENDIF + IF(CHBIT(LNAM:LNAM).EQ.',') THEN + LIND=LNAM + 190 LIND=LIND+1 + IF(CHBIT(LIND:LIND).NE.')'.AND.CHBIT(LIND:LIND).NE.',') GOTO 190 + CHIND=' ' + CHIND(LNAM-LIND+10:8)=CHBIT(LNAM+1:LIND-1) + READ(CHIND,'(I8)') I2 + LNAM=LIND + IF(CHBIT(LNAM:LNAM).EQ.')') LNAM=LNAM+1 + NINDX=2 + ENDIF + IF(CHBIT(LNAM:LNAM).EQ.',') THEN + LIND=LNAM + 200 LIND=LIND+1 + IF(CHBIT(LIND:LIND).NE.')'.AND.CHBIT(LIND:LIND).NE.',') GOTO 200 + CHIND=' ' + CHIND(LNAM-LIND+10:8)=CHBIT(LNAM+1:LIND-1) + READ(CHIND,'(I8)') I3 + LNAM=LIND+1 + NINDX=3 + ENDIF + +C...Check that indices allowed. + IERR=0 + IF(NINDX.NE.MSVAR(IVAR,2)) IERR=1 + IF(NINDX.GE.1.AND.(I1.LT.MSVAR(IVAR,3).OR.I1.GT.MSVAR(IVAR,4))) + &IERR=2 + IF(NINDX.GE.2.AND.(I2.LT.MSVAR(IVAR,5).OR.I2.GT.MSVAR(IVAR,6))) + &IERR=3 + IF(NINDX.EQ.3.AND.(I3.LT.MSVAR(IVAR,7).OR.I3.GT.MSVAR(IVAR,8))) + &IERR=4 + IF(CHBIT(LNAM:LNAM).NE.'=') IERR=5 + IF(IERR.GE.1) THEN + CALL LUERRM(18,'(LUGIVE:) unallowed indices for '// + & CHBIT(1:LNAM-1)) + LLOW=LHIG + IF(LLOW.LT.LTOT) GOTO 120 + RETURN + ENDIF + +C...Save old value of variable. + IF(IVAR.EQ.1) THEN + IOLD=N + ELSEIF(IVAR.EQ.2) THEN + IOLD=K(I1,I2) + ELSEIF(IVAR.EQ.3) THEN + ROLD=P(I1,I2) + ELSEIF(IVAR.EQ.4) THEN + ROLD=V(I1,I2) + ELSEIF(IVAR.EQ.5) THEN + IOLD=MSTU(I1) + ELSEIF(IVAR.EQ.6) THEN + ROLD=PARU(I1) + ELSEIF(IVAR.EQ.7) THEN + IOLD=MSTJ(I1) + ELSEIF(IVAR.EQ.8) THEN + ROLD=PARJ(I1) + ELSEIF(IVAR.EQ.9) THEN + IOLD=KCHG(I1,I2) + ELSEIF(IVAR.EQ.10) THEN + ROLD=PMAS(I1,I2) + ELSEIF(IVAR.EQ.11) THEN + ROLD=PARF(I1) + ELSEIF(IVAR.EQ.12) THEN + ROLD=VCKM(I1,I2) + ELSEIF(IVAR.EQ.13) THEN + IOLD=MDCY(I1,I2) + ELSEIF(IVAR.EQ.14) THEN + IOLD=MDME(I1,I2) + ELSEIF(IVAR.EQ.15) THEN + ROLD=BRAT(I1) + ELSEIF(IVAR.EQ.16) THEN + IOLD=KFDP(I1,I2) + ELSEIF(IVAR.EQ.17) THEN + CHOLD=CHAF(I1) + ELSEIF(IVAR.EQ.18) THEN + IOLD=MRLU(I1) + ELSEIF(IVAR.EQ.19) THEN + ROLD=RRLU(I1) + ELSEIF(IVAR.EQ.20) THEN + IOLD=MSEL + ELSEIF(IVAR.EQ.21) THEN + IOLD=MSUB(I1) + ELSEIF(IVAR.EQ.22) THEN + IOLD=KFIN(I1,I2) + ELSEIF(IVAR.EQ.23) THEN + ROLD=CKIN(I1) + ELSEIF(IVAR.EQ.24) THEN + IOLD=MSTP(I1) + ELSEIF(IVAR.EQ.25) THEN + ROLD=PARP(I1) + ELSEIF(IVAR.EQ.26) THEN + IOLD=MSTI(I1) + ELSEIF(IVAR.EQ.27) THEN + ROLD=PARI(I1) + ELSEIF(IVAR.EQ.28) THEN + IOLD=MINT(I1) + ELSEIF(IVAR.EQ.29) THEN + ROLD=VINT(I1) + ELSEIF(IVAR.EQ.30) THEN + IOLD=ISET(I1) + ELSEIF(IVAR.EQ.31) THEN + IOLD=KFPR(I1,I2) + ELSEIF(IVAR.EQ.32) THEN + ROLD=COEF(I1,I2) + ELSEIF(IVAR.EQ.33) THEN + IOLD=ICOL(I1,I2,I3) + ELSEIF(IVAR.EQ.34) THEN + ROLD=XSFX(I1,I2) + ELSEIF(IVAR.EQ.35) THEN + IOLD=ISIG(I1,I2) + ELSEIF(IVAR.EQ.36) THEN + ROLD=SIGH(I1) + ELSEIF(IVAR.EQ.37) THEN + ROLD=WIDP(I1,I2) + ELSEIF(IVAR.EQ.38) THEN + ROLD=WIDE(I1,I2) + ELSEIF(IVAR.EQ.39) THEN + ROLD=WIDS(I1,I2) + ELSEIF(IVAR.EQ.40) THEN + IOLD=NGEN(I1,I2) + ELSEIF(IVAR.EQ.41) THEN + ROLD=XSEC(I1,I2) + ELSEIF(IVAR.EQ.42) THEN + CHOLD2=PROC(I1) + ELSEIF(IVAR.EQ.43) THEN + ROLD=SIGT(I1,I2,I3) + ENDIF + +C...Print current value of variable. Loop back. + IF(LNAM.GE.LBIT) THEN + CHBIT(LNAM:14)=' ' + CHBIT(15:60)=' has the value ' + IF(MSVAR(IVAR,1).EQ.1) THEN + WRITE(CHBIT(51:60),'(I10)') IOLD + ELSEIF(MSVAR(IVAR,1).EQ.2) THEN + WRITE(CHBIT(47:60),'(F14.5)') ROLD + ELSEIF(MSVAR(IVAR,1).EQ.3) THEN + CHBIT(53:60)=CHOLD + ELSE + CHBIT(33:60)=CHOLD + ENDIF + IF(MSTU(13).GE.1) WRITE(MSTU(11),5000) CHBIT(1:60) + LLOW=LHIG + IF(LLOW.LT.LTOT) GOTO 120 + RETURN + ENDIF + +C...Read in new variable value. + IF(MSVAR(IVAR,1).EQ.1) THEN + CHINI=' ' + CHINI(LNAM-LBIT+11:10)=CHBIT(LNAM+1:LBIT) + READ(CHINI,'(I10)') INEW + ELSEIF(MSVAR(IVAR,1).EQ.2) THEN + CHINR=' ' + CHINR(LNAM-LBIT+17:16)=CHBIT(LNAM+1:LBIT) + READ(CHINR,'(F16.2)') RNEW + ELSEIF(MSVAR(IVAR,1).EQ.3) THEN + CHNEW=CHBIT(LNAM+1:LBIT)//' ' + ELSE + CHNEW2=CHBIT(LNAM+1:LBIT)//' ' + ENDIF + +C...Store new variable value. + IF(IVAR.EQ.1) THEN + N=INEW + ELSEIF(IVAR.EQ.2) THEN + K(I1,I2)=INEW + ELSEIF(IVAR.EQ.3) THEN + P(I1,I2)=RNEW + ELSEIF(IVAR.EQ.4) THEN + V(I1,I2)=RNEW + ELSEIF(IVAR.EQ.5) THEN + MSTU(I1)=INEW + ELSEIF(IVAR.EQ.6) THEN + PARU(I1)=RNEW + ELSEIF(IVAR.EQ.7) THEN + MSTJ(I1)=INEW + ELSEIF(IVAR.EQ.8) THEN + PARJ(I1)=RNEW + ELSEIF(IVAR.EQ.9) THEN + KCHG(I1,I2)=INEW + ELSEIF(IVAR.EQ.10) THEN + PMAS(I1,I2)=RNEW + ELSEIF(IVAR.EQ.11) THEN + PARF(I1)=RNEW + ELSEIF(IVAR.EQ.12) THEN + VCKM(I1,I2)=RNEW + ELSEIF(IVAR.EQ.13) THEN + MDCY(I1,I2)=INEW + ELSEIF(IVAR.EQ.14) THEN + MDME(I1,I2)=INEW + ELSEIF(IVAR.EQ.15) THEN + BRAT(I1)=RNEW + ELSEIF(IVAR.EQ.16) THEN + KFDP(I1,I2)=INEW + ELSEIF(IVAR.EQ.17) THEN + CHAF(I1)=CHNEW + ELSEIF(IVAR.EQ.18) THEN + MRLU(I1)=INEW + ELSEIF(IVAR.EQ.19) THEN + RRLU(I1)=RNEW + ELSEIF(IVAR.EQ.20) THEN + MSEL=INEW + ELSEIF(IVAR.EQ.21) THEN + MSUB(I1)=INEW + ELSEIF(IVAR.EQ.22) THEN + KFIN(I1,I2)=INEW + ELSEIF(IVAR.EQ.23) THEN + CKIN(I1)=RNEW + ELSEIF(IVAR.EQ.24) THEN + MSTP(I1)=INEW + ELSEIF(IVAR.EQ.25) THEN + PARP(I1)=RNEW + ELSEIF(IVAR.EQ.26) THEN + MSTI(I1)=INEW + ELSEIF(IVAR.EQ.27) THEN + PARI(I1)=RNEW + ELSEIF(IVAR.EQ.28) THEN + MINT(I1)=INEW + ELSEIF(IVAR.EQ.29) THEN + VINT(I1)=RNEW + ELSEIF(IVAR.EQ.30) THEN + ISET(I1)=INEW + ELSEIF(IVAR.EQ.31) THEN + KFPR(I1,I2)=INEW + ELSEIF(IVAR.EQ.32) THEN + COEF(I1,I2)=RNEW + ELSEIF(IVAR.EQ.33) THEN + ICOL(I1,I2,I3)=INEW + ELSEIF(IVAR.EQ.34) THEN + XSFX(I1,I2)=RNEW + ELSEIF(IVAR.EQ.35) THEN + ISIG(I1,I2)=INEW + ELSEIF(IVAR.EQ.36) THEN + SIGH(I1)=RNEW + ELSEIF(IVAR.EQ.37) THEN + WIDP(I1,I2)=RNEW + ELSEIF(IVAR.EQ.38) THEN + WIDE(I1,I2)=RNEW + ELSEIF(IVAR.EQ.39) THEN + WIDS(I1,I2)=RNEW + ELSEIF(IVAR.EQ.40) THEN + NGEN(I1,I2)=INEW + ELSEIF(IVAR.EQ.41) THEN + XSEC(I1,I2)=RNEW + ELSEIF(IVAR.EQ.42) THEN + PROC(I1)=CHNEW2 + ELSEIF(IVAR.EQ.43) THEN + SIGT(I1,I2,I3)=RNEW + ENDIF + +C...Write old and new value. Loop back. + CHBIT(LNAM:14)=' ' + CHBIT(15:60)=' changed from to ' + IF(MSVAR(IVAR,1).EQ.1) THEN + WRITE(CHBIT(33:42),'(I10)') IOLD + WRITE(CHBIT(51:60),'(I10)') INEW + IF(MSTU(13).GE.1) WRITE(MSTU(11),5000) CHBIT(1:60) + ELSEIF(MSVAR(IVAR,1).EQ.2) THEN + WRITE(CHBIT(29:42),'(F14.5)') ROLD + WRITE(CHBIT(47:60),'(F14.5)') RNEW + IF(MSTU(13).GE.1) WRITE(MSTU(11),5000) CHBIT(1:60) + ELSEIF(MSVAR(IVAR,1).EQ.3) THEN + CHBIT(35:42)=CHOLD + CHBIT(53:60)=CHNEW + IF(MSTU(13).GE.1) WRITE(MSTU(11),5000) CHBIT(1:60) + ELSE + CHBIT(15:88)=' changed from '//CHOLD2//' to '//CHNEW2 + IF(MSTU(13).GE.1) WRITE(MSTU(11),5100) CHBIT(1:88) + ENDIF + LLOW=LHIG + IF(LLOW.LT.LTOT) GOTO 120 + +C...Format statement for output on unit MSTU(11) (by default 6). + 5000 FORMAT(5X,A60) + 5100 FORMAT(5X,A88) + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUEXEC + SUBROUTINE LUEXEC + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to administrate the fragmentation and decay chain. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/,/LUDAT3/ + DIMENSION PS(2,6) + +C...Initialize and reset. + MSTU(24)=0 + IF(MSTU(12).GE.1) CALL LULIST(0) + MSTU(31)=MSTU(31)+1 + MSTU(1)=0 + MSTU(2)=0 + MSTU(3)=0 + IF(MSTU(17).LE.0) MSTU(90)=0 + MCONS=1 + +C...Sum up momentum, energy and charge for starting entries. + NSAV=N + DO 110 I=1,2 + DO 100 J=1,6 + PS(I,J)=0. + 100 CONTINUE + 110 CONTINUE + DO 130 I=1,N + IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 130 + DO 120 J=1,4 + PS(1,J)=PS(1,J)+P(I,J) + 120 CONTINUE + PS(1,6)=PS(1,6)+LUCHGE(K(I,2)) + 130 CONTINUE + PARU(21)=PS(1,4) + +C...Prepare system for subsequent fragmentation/decay. + CALL LUPREP(0) + +C...Loop through jet fragmentation and particle decays. + MBE=0 + 140 MBE=MBE+1 + IP=0 + 150 IP=IP+1 + KC=0 + IF(K(IP,1).GT.0.AND.K(IP,1).LE.10) KC=LUCOMP(K(IP,2)) + IF(KC.EQ.0) THEN + +C...Particle decay if unstable and allowed. Save long-lived particle +C...decays until second pass after Bose-Einstein effects. + ELSEIF(KCHG(KC,2).EQ.0) THEN + IF(MSTJ(21).GE.1.AND.MDCY(KC,1).GE.1.AND.(MSTJ(51).LE.0.OR.MBE + & .EQ.2.OR.PMAS(KC,2).GE.PARJ(91).OR.IABS(K(IP,2)).EQ.311)) + & CALL LUDECY(IP) + +C...Decay products may develop a shower. + IF(MSTJ(92).GT.0) THEN + IP1=MSTJ(92) + QMAX=SQRT(MAX(0.D0,(P(IP1,4)+P(IP1+1,4))**2-(P(IP1,1)+P(IP1+1, + & 1))**2-(P(IP1,2)+P(IP1+1,2))**2-(P(IP1,3)+P(IP1+1,3))**2)) + CALL LUSHOW(IP1,IP1+1,QMAX) + CALL LUPREP(IP1) + MSTJ(92)=0 + ELSEIF(MSTJ(92).LT.0) THEN + IP1=-MSTJ(92) + CALL LUSHOW(IP1,-3,P(IP,5)) + CALL LUPREP(IP1) + MSTJ(92)=0 + ENDIF + +C...Jet fragmentation: string or independent fragmentation. + ELSEIF(K(IP,1).EQ.1.OR.K(IP,1).EQ.2) THEN + MFRAG=MSTJ(1) + IF(MFRAG.GE.1.AND.K(IP,1).EQ.1) MFRAG=2 + IF(MSTJ(21).GE.2.AND.K(IP,1).EQ.2.AND.N.GT.IP) THEN + IF(K(IP+1,1).EQ.1.AND.K(IP+1,3).EQ.K(IP,3).AND. + & K(IP,3).GT.0.AND.K(IP,3).LT.IP) THEN + IF(KCHG(LUCOMP(K(K(IP,3),2)),2).EQ.0) MFRAG=MIN(1,MFRAG) + ENDIF + ENDIF + IF(MFRAG.EQ.1) CALL LUSTRF(IP) + IF(MFRAG.EQ.2) CALL LUINDF(IP) + IF(MFRAG.EQ.2.AND.K(IP,1).EQ.1) MCONS=0 + IF(MFRAG.EQ.2.AND.(MSTJ(3).LE.0.OR.MOD(MSTJ(3),5).EQ.0)) MCONS=0 + ENDIF + +C...Loop back if enough space left in LUJETS and no error abort. + IF(MSTU(24).NE.0.AND.MSTU(21).GE.2) THEN + ELSEIF(IP.LT.N.AND.N.LT.MSTU(4)-20-MSTU(32)) THEN + GOTO 150 + ELSEIF(IP.LT.N) THEN + CALL LUERRM(11,'(LUEXEC:) no more memory left in LUJETS') + ENDIF + +C...Include simple Bose-Einstein effect parametrization if desired. + IF(MBE.EQ.1.AND.MSTJ(51).GE.1) THEN + CALL LUBOEI(NSAV) + GOTO 140 + ENDIF + +C...Check that momentum, energy and charge were conserved. + DO 170 I=1,N + IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 170 + DO 160 J=1,4 + PS(2,J)=PS(2,J)+P(I,J) + 160 CONTINUE + PS(2,6)=PS(2,6)+LUCHGE(K(I,2)) + 170 CONTINUE + PDEV=(ABS(PS(2,1)-PS(1,1))+ABS(PS(2,2)-PS(1,2))+ABS(PS(2,3)- + &PS(1,3))+ABS(PS(2,4)-PS(1,4)))/(1.+ABS(PS(2,4))+ABS(PS(1,4))) + IF(MCONS.EQ.1.AND.PDEV.GT.PARU(11)) CALL LUERRM(15, + &'(LUEXEC:) four-momentum was not conserved') + IF(MCONS.EQ.1.AND.ABS(PS(2,6)-PS(1,6)).GT.0.1) CALL LUERRM(15, + &'(LUEXEC:) charge was not conserved') + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUPREP + SUBROUTINE LUPREP(IP) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to rearrange partons along strings, to allow small systems +C...to collapse into one or two particles and to check flavours. +C IMPLICIT DOUBLE PRECISION(D) + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/,/LUDAT3/ + DIMENSION DPS(5),DPC(5),UE(3) + +C...Rearrange parton shower product listing along strings: begin loop. + I1=N + DO 130 MQGST=1,2 + DO 120 I=MAX(1,IP),N + IF(K(I,1).NE.3) GOTO 120 + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0) GOTO 120 + KQ=KCHG(KC,2) + IF(KQ.EQ.0.OR.(MQGST.EQ.1.AND.KQ.EQ.2)) GOTO 120 + +C...Pick up loose string end. + KCS=4 + IF(KQ*ISIGN(1,K(I,2)).LT.0) KCS=5 + IA=I + NSTP=0 + 100 NSTP=NSTP+1 + IF(NSTP.GT.4*N) THEN + CALL LUERRM(14,'(LUPREP:) caught in infinite loop') + RETURN + ENDIF + +C...Copy undecayed parton. + IF(K(IA,1).EQ.3) THEN + IF(I1.GE.MSTU(4)-MSTU(32)-5) THEN + CALL LUERRM(11,'(LUPREP:) no more memory left in LUJETS') + RETURN + ENDIF + I1=I1+1 + K(I1,1)=2 + IF(NSTP.GE.2.AND.IABS(K(IA,2)).NE.21) K(I1,1)=1 + K(I1,2)=K(IA,2) + K(I1,3)=IA + K(I1,4)=0 + K(I1,5)=0 + DO 110 J=1,5 + P(I1,J)=P(IA,J) + V(I1,J)=V(IA,J) + 110 CONTINUE + K(IA,1)=K(IA,1)+10 + IF(K(I1,1).EQ.1) GOTO 120 + ENDIF + +C...Go to next parton in colour space. + IB=IA + IF(MOD(K(IB,KCS)/MSTU(5)**2,2).EQ.0.AND.MOD(K(IB,KCS),MSTU(5)) + &.NE.0) THEN + IA=MOD(K(IB,KCS),MSTU(5)) + K(IB,KCS)=K(IB,KCS)+MSTU(5)**2 + MREV=0 + ELSE + IF(K(IB,KCS).GE.2*MSTU(5)**2.OR.MOD(K(IB,KCS)/MSTU(5),MSTU(5)) + & .EQ.0) KCS=9-KCS + IA=MOD(K(IB,KCS)/MSTU(5),MSTU(5)) + K(IB,KCS)=K(IB,KCS)+2*MSTU(5)**2 + MREV=1 + ENDIF + IF(IA.LE.0.OR.IA.GT.N) THEN + CALL LUERRM(12,'(LUPREP:) colour rearrangement failed') + RETURN + ENDIF + IF(MOD(K(IA,4)/MSTU(5),MSTU(5)).EQ.IB.OR.MOD(K(IA,5)/MSTU(5), + &MSTU(5)).EQ.IB) THEN + IF(MREV.EQ.1) KCS=9-KCS + IF(MOD(K(IA,KCS)/MSTU(5),MSTU(5)).NE.IB) KCS=9-KCS + K(IA,KCS)=K(IA,KCS)+2*MSTU(5)**2 + ELSE + IF(MREV.EQ.0) KCS=9-KCS + IF(MOD(K(IA,KCS),MSTU(5)).NE.IB) KCS=9-KCS + K(IA,KCS)=K(IA,KCS)+MSTU(5)**2 + ENDIF + IF(IA.NE.I) GOTO 100 + K(I1,1)=1 + 120 CONTINUE + 130 CONTINUE + N=I1 + IF(MSTJ(14).LT.0) RETURN + +C...Find lowest-mass colour singlet jet system, OK if above threshold. + IF(MSTJ(14).EQ.0) GOTO 320 + NS=N + 140 NSIN=N-NS + PDM=1.+PARJ(32) + IC=0 + DO 190 I=MAX(1,IP),NS + IF(K(I,1).NE.1.AND.K(I,1).NE.2) THEN + ELSEIF(K(I,1).EQ.2.AND.IC.EQ.0) THEN + NSIN=NSIN+1 + IC=I + DO 150 J=1,4 + DPS(J)=P(I,J) + 150 CONTINUE + MSTJ(93)=1 + DPS(5)=ULMASS(K(I,2)) + ELSEIF(K(I,1).EQ.2) THEN + DO 160 J=1,4 + DPS(J)=DPS(J)+P(I,J) + 160 CONTINUE + ELSEIF(IC.NE.0.AND.KCHG(LUCOMP(K(I,2)),2).NE.0) THEN + DO 170 J=1,4 + DPS(J)=DPS(J)+P(I,J) + 170 CONTINUE + MSTJ(93)=1 + DPS(5)=DPS(5)+ULMASS(K(I,2)) + PD=SQRT(MAX(0D0,DPS(4)**2-DPS(1)**2-DPS(2)**2-DPS(3)**2))-DPS(5) + IF(PD.LT.PDM) THEN + PDM=PD + DO 180 J=1,5 + DPC(J)=DPS(J) + 180 CONTINUE + IC1=IC + IC2=I + ENDIF + IC=0 + ELSE + NSIN=NSIN+1 + ENDIF + 190 CONTINUE + IF(PDM.GE.PARJ(32)) GOTO 320 + +C...Fill small-mass system as cluster. + NSAV=N + PECM=SQRT(MAX(0D0,DPC(4)**2-DPC(1)**2-DPC(2)**2-DPC(3)**2)) + K(N+1,1)=11 + K(N+1,2)=91 + K(N+1,3)=IC1 + K(N+1,4)=N+2 + K(N+1,5)=N+3 + P(N+1,1)=DPC(1) + P(N+1,2)=DPC(2) + P(N+1,3)=DPC(3) + P(N+1,4)=DPC(4) + P(N+1,5)=PECM + +C...Form two particles from flavours of lowest-mass system, if feasible. + K(N+2,1)=1 + K(N+3,1)=1 + IF(MSTU(16).NE.2) THEN + K(N+2,3)=N+1 + K(N+3,3)=N+1 + ELSE + K(N+2,3)=IC1 + K(N+3,3)=IC2 + ENDIF + K(N+2,4)=0 + K(N+3,4)=0 + K(N+2,5)=0 + K(N+3,5)=0 + IF(IABS(K(IC1,2)).NE.21) THEN + KC1=LUCOMP(K(IC1,2)) + KC2=LUCOMP(K(IC2,2)) + IF(KC1.EQ.0.OR.KC2.EQ.0) GOTO 320 + KQ1=KCHG(KC1,2)*ISIGN(1,K(IC1,2)) + KQ2=KCHG(KC2,2)*ISIGN(1,K(IC2,2)) + IF(KQ1+KQ2.NE.0) GOTO 320 + 200 CALL LUKFDI(K(IC1,2),0,KFLN,K(N+2,2)) + CALL LUKFDI(K(IC2,2),-KFLN,KFLDMP,K(N+3,2)) + IF(K(N+2,2).EQ.0.OR.K(N+3,2).EQ.0) GOTO 200 + ELSE + IF(IABS(K(IC2,2)).NE.21) GOTO 320 + 210 CALL LUKFDI(1+INT((2.+PARJ(2))*RLU(0)),0,KFLN,KFDMP) + CALL LUKFDI(KFLN,0,KFLM,K(N+2,2)) + CALL LUKFDI(-KFLN,-KFLM,KFLDMP,K(N+3,2)) + IF(K(N+2,2).EQ.0.OR.K(N+3,2).EQ.0) GOTO 210 + ENDIF + P(N+2,5)=ULMASS(K(N+2,2)) + P(N+3,5)=ULMASS(K(N+3,2)) + IF(P(N+2,5)+P(N+3,5)+PARJ(64).GE.PECM.AND.NSIN.EQ.1) GOTO 320 + IF(P(N+2,5)+P(N+3,5)+PARJ(64).GE.PECM) GOTO 260 + +C...Perform two-particle decay of jet system, if possible. + IF(PECM.GE.0.02*DPC(4)) THEN + PA=SQRT((PECM**2-(P(N+2,5)+P(N+3,5))**2)*(PECM**2- + & (P(N+2,5)-P(N+3,5))**2))/(2.*PECM) + UE(3)=2.*RLU(0)-1. + PHI=PARU(2)*RLU(0) + UE(1)=SQRT(1.-UE(3)**2)*COS(PHI) + UE(2)=SQRT(1.-UE(3)**2)*SIN(PHI) + DO 220 J=1,3 + P(N+2,J)=PA*UE(J) + P(N+3,J)=-PA*UE(J) + 220 CONTINUE + P(N+2,4)=SQRT(PA**2+P(N+2,5)**2) + P(N+3,4)=SQRT(PA**2+P(N+3,5)**2) + MSTU(33)=1 + CALL LUDBRB(N+2,N+3,0.D0,0.D0,DPC(1)/DPC(4),DPC(2)/DPC(4), + & DPC(3)/DPC(4)) + ELSE + NP=0 + DO 230 I=IC1,IC2 + IF(K(I,1).EQ.1.OR.K(I,1).EQ.2) NP=NP+1 + 230 CONTINUE + HA=P(IC1,4)*P(IC2,4)-P(IC1,1)*P(IC2,1)-P(IC1,2)*P(IC2,2)- + & P(IC1,3)*P(IC2,3) + IF(NP.GE.3.OR.HA.LE.1.25*P(IC1,5)*P(IC2,5)) GOTO 260 + HD1=0.5*(P(N+2,5)**2-P(IC1,5)**2) + HD2=0.5*(P(N+3,5)**2-P(IC2,5)**2) + HR=SQRT(MAX(0.D0,((HA-HD1-HD2)**2-(P(N+2,5)*P(N+3,5))**2)/ + & (HA**2-(P(IC1,5)*P(IC2,5))**2)))-1. + HC=P(IC1,5)**2+2.*HA+P(IC2,5)**2 + HK1=((P(IC2,5)**2+HA)*HR+HD1-HD2)/HC + HK2=((P(IC1,5)**2+HA)*HR+HD2-HD1)/HC + DO 240 J=1,4 + P(N+2,J)=(1.+HK1)*P(IC1,J)-HK2*P(IC2,J) + P(N+3,J)=(1.+HK2)*P(IC2,J)-HK1*P(IC1,J) + 240 CONTINUE + ENDIF + DO 250 J=1,4 + V(N+1,J)=V(IC1,J) + V(N+2,J)=V(IC1,J) + V(N+3,J)=V(IC2,J) + 250 CONTINUE + V(N+1,5)=0. + V(N+2,5)=0. + V(N+3,5)=0. + N=N+3 + GOTO 300 + +C...Else form one particle from the flavours available, if possible. + 260 K(N+1,5)=N+2 + IF(IABS(K(IC1,2)).GT.100.AND.IABS(K(IC2,2)).GT.100) THEN + GOTO 320 + ELSEIF(IABS(K(IC1,2)).NE.21) THEN + CALL LUKFDI(K(IC1,2),K(IC2,2),KFLDMP,K(N+2,2)) + ELSE + KFLN=1+INT((2.+PARJ(2))*RLU(0)) + CALL LUKFDI(KFLN,-KFLN,KFLDMP,K(N+2,2)) + ENDIF + IF(K(N+2,2).EQ.0) GOTO 260 + P(N+2,5)=ULMASS(K(N+2,2)) + +C...Find parton/particle which combines to largest extra mass. + IR=0 + HA=0. + HSM=0. + DO 280 MCOMB=1,3 + IF(IR.NE.0) GOTO 280 + DO 270 I=MAX(1,IP),N + IF(K(I,1).LE.0.OR.K(I,1).GT.10.OR.(I.GE.IC1.AND.I.LE.IC2 + &.AND.K(I,1).GE.1.AND.K(I,1).LE.2)) GOTO 270 + IF(MCOMB.EQ.1) KCI=LUCOMP(K(I,2)) + IF(MCOMB.EQ.1.AND.KCI.EQ.0) GOTO 270 + IF(MCOMB.EQ.1.AND.KCHG(KCI,2).EQ.0.AND.I.LE.NS) GOTO 270 + IF(MCOMB.EQ.2.AND.IABS(K(I,2)).GT.10.AND.IABS(K(I,2)).LE.100) + &GOTO 270 + HCR=DPC(4)*P(I,4)-DPC(1)*P(I,1)-DPC(2)*P(I,2)-DPC(3)*P(I,3) + HSR=2.*HCR+PECM**2-P(N+2,5)**2-2.*P(N+2,5)*P(I,5) + IF(HSR.GT.HSM) THEN + IR=I + HA=HCR + HSM=HSR + ENDIF + 270 CONTINUE + 280 CONTINUE + +C...Shuffle energy and momentum to put new particle on mass shell. + IF(IR.NE.0) THEN + HB=PECM**2+HA + HC=P(N+2,5)**2+HA + HD=P(IR,5)**2+HA + HK2=0.5*(HB*SQRT(MAX(0.D0,((HB+HC)**2-4.*(HB+HD)*P(N+2,5)**2)/ + & (HA**2-(PECM*P(IR,5))**2)))-(HB+HC))/(HB+HD) + HK1=(0.5*(P(N+2,5)**2-PECM**2)+HD*HK2)/HB + DO 290 J=1,4 + P(N+2,J)=(1.+HK1)*DPC(J)-HK2*P(IR,J) + P(IR,J)=(1.+HK2)*P(IR,J)-HK1*DPC(J) + V(N+1,J)=V(IC1,J) + V(N+2,J)=V(IC1,J) + 290 CONTINUE + V(N+1,5)=0. + V(N+2,5)=0. + N=N+2 + ELSE + CALL LUERRM(3,'(LUPREP:) no match for collapsing cluster') + RETURN + ENDIF + +C...Mark collapsed system and store daughter pointers. Iterate. + 300 DO 310 I=IC1,IC2 + IF((K(I,1).EQ.1.OR.K(I,1).EQ.2).AND.KCHG(LUCOMP(K(I,2)),2).NE.0) + &THEN + K(I,1)=K(I,1)+10 + IF(MSTU(16).NE.2) THEN + K(I,4)=NSAV+1 + K(I,5)=NSAV+1 + ELSE + K(I,4)=NSAV+2 + K(I,5)=N + ENDIF + ENDIF + 310 CONTINUE + IF(N.LT.MSTU(4)-MSTU(32)-5) GOTO 140 + +C...Check flavours and invariant masses in parton systems. + 320 NP=0 + KFN=0 + KQS=0 + DO 330 J=1,5 + DPS(J)=0. + 330 CONTINUE + DO 360 I=MAX(1,IP),N + IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 360 + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0) GOTO 360 + KQ=KCHG(KC,2)*ISIGN(1,K(I,2)) + IF(KQ.EQ.0) GOTO 360 + NP=NP+1 + IF(KQ.NE.2) THEN + KFN=KFN+1 + KQS=KQS+KQ + MSTJ(93)=1 + DPS(5)=DPS(5)+ULMASS(K(I,2)) + ENDIF + DO 340 J=1,4 + DPS(J)=DPS(J)+P(I,J) + 340 CONTINUE + IF(K(I,1).EQ.1) THEN + IF(NP.NE.1.AND.(KFN.EQ.1.OR.KFN.GE.3.OR.KQS.NE.0)) CALL + & LUERRM(2,'(LUPREP:) unphysical flavour combination') + IF(NP.NE.1.AND.DPS(4)**2-DPS(1)**2-DPS(2)**2-DPS(3)**2.LT. + & (0.9*PARJ(32)+DPS(5))**2) CALL LUERRM(3, + & '(LUPREP:) too small mass in jet system') + NP=0 + KFN=0 + KQS=0 + DO 350 J=1,5 + DPS(J)=0. + 350 CONTINUE + ENDIF + 360 CONTINUE + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUSTRF + SUBROUTINE LUSTRF(IP) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) +C...Purpose: to handle the fragmentation of an arbitrary colour singlet +C...jet system according to the Lund string fragmentation model. +C IMPLICIT DOUBLE PRECISION(D) + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + DIMENSION DPS(5),KFL(3),PMQ(3),PX(3),PY(3),GAM(3),IE(2),PR(2), + &IN(9),DHM(4),DHG(4),DP(5,5),IRANK(2),MJU(4),IJU(3),PJU(5,5), + &TJU(5),KFJH(2),NJS(2),KFJS(2),PJS(4,5),MSTU9T(8),PARU9T(8) + +C...Function: four-product of two vectors. + FOUR(I,J)=P(I,4)*P(J,4)-P(I,1)*P(J,1)-P(I,2)*P(J,2)-P(I,3)*P(J,3) + DFOUR(I,J)=DP(I,4)*DP(J,4)-DP(I,1)*DP(J,1)-DP(I,2)*DP(J,2)- + &DP(I,3)*DP(J,3) + +C...Reset counters. Identify parton system. + MSTJ(91)=0 + NSAV=N + MSTU90=MSTU(90) + NP=0 + KQSUM=0 + DO 100 J=1,5 + DPS(J)=0D0 + 100 CONTINUE + MJU(1)=0 + MJU(2)=0 + I=IP-1 + 110 I=I+1 + IF(I.GT.MIN(N,MSTU(4)-MSTU(32))) THEN + CALL LUERRM(12,'(LUSTRF:) failed to reconstruct jet system') + IF(MSTU(21).GE.1) RETURN + ENDIF + IF(K(I,1).NE.1.AND.K(I,1).NE.2.AND.K(I,1).NE.41) GOTO 110 + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0) GOTO 110 + KQ=KCHG(KC,2)*ISIGN(1,K(I,2)) + IF(KQ.EQ.0) GOTO 110 + IF(N+5*NP+11.GT.MSTU(4)-MSTU(32)-5) THEN + CALL LUERRM(11,'(LUSTRF:) no more memory left in LUJETS') + IF(MSTU(21).GE.1) RETURN + ENDIF + +C...Take copy of partons to be considered. Check flavour sum. + NP=NP+1 + DO 120 J=1,5 + K(N+NP,J)=K(I,J) + P(N+NP,J)=P(I,J) + IF(J.NE.4) DPS(J)=DPS(J)+P(I,J) + 120 CONTINUE + DPS(4)=DPS(4)+SQRT(DBLE(P(I,1))**2+DBLE(P(I,2))**2+ + &DBLE(P(I,3))**2+DBLE(P(I,5))**2) + K(N+NP,3)=I + IF(KQ.NE.2) KQSUM=KQSUM+KQ + IF(K(I,1).EQ.41) THEN + KQSUM=KQSUM+2*KQ + IF(KQSUM.EQ.KQ) MJU(1)=N+NP + IF(KQSUM.NE.KQ) MJU(2)=N+NP + ENDIF + IF(K(I,1).EQ.2.OR.K(I,1).EQ.41) GOTO 110 + IF(KQSUM.NE.0) THEN + CALL LUERRM(12,'(LUSTRF:) unphysical flavour combination') + IF(MSTU(21).GE.1) RETURN + ENDIF + +C...Boost copied system to CM frame (for better numerical precision). + IF(ABS(DPS(3)).LT.0.99D0*DPS(4)) THEN + MBST=0 + MSTU(33)=1 + CALL LUDBRB(N+1,N+NP,0.D0,0.D0,-DPS(1)/DPS(4),-DPS(2)/DPS(4), + & -DPS(3)/DPS(4)) + ELSE + MBST=1 + HHBZ=SQRT(MAX(1D-6,DPS(4)+DPS(3))/MAX(1D-6,DPS(4)-DPS(3))) + DO 130 I=N+1,N+NP + HHPMT=P(I,1)**2+P(I,2)**2+P(I,5)**2 + IF(P(I,3).GT.0.) THEN + HHPEZ=(P(I,4)+P(I,3))/HHBZ + P(I,3)=0.5*(HHPEZ-HHPMT/HHPEZ) + P(I,4)=0.5*(HHPEZ+HHPMT/HHPEZ) + ELSE + HHPEZ=(P(I,4)-P(I,3))*HHBZ + P(I,3)=-0.5*(HHPEZ-HHPMT/HHPEZ) + P(I,4)=0.5*(HHPEZ+HHPMT/HHPEZ) + ENDIF + 130 CONTINUE + ENDIF + +C...Search for very nearby partons that may be recombined. + NTRYR=0 + PARU12=PARU(12) + PARU13=PARU(13) + MJU(3)=MJU(1) + MJU(4)=MJU(2) + NR=NP + 140 IF(NR.GE.3) THEN + PDRMIN=2.*PARU12 + DO 150 I=N+1,N+NR + IF(I.EQ.N+NR.AND.IABS(K(N+1,2)).NE.21) GOTO 150 + I1=I+1 + IF(I.EQ.N+NR) I1=N+1 + IF(K(I,1).EQ.41.OR.K(I1,1).EQ.41) GOTO 150 + IF(MJU(1).NE.0.AND.I1.LT.MJU(1).AND.IABS(K(I1,2)).NE.21) + & GOTO 150 + IF(MJU(2).NE.0.AND.I.GT.MJU(2).AND.IABS(K(I,2)).NE.21) GOTO 150 + PAP=SQRT((P(I,1)**2+P(I,2)**2+P(I,3)**2)*(P(I1,1)**2+ + & P(I1,2)**2+P(I1,3)**2)) + PVP=P(I,1)*P(I1,1)+P(I,2)*P(I1,2)+P(I,3)*P(I1,3) + PDR=4.*(PAP-PVP)**2/MAX(1D-6,PARU13**2*PAP+2.*(PAP-PVP)) + IF(PDR.LT.PDRMIN) THEN + IR=I + PDRMIN=PDR + ENDIF + 150 CONTINUE + +C...Recombine very nearby partons to avoid machine precision problems. + IF(PDRMIN.LT.PARU12.AND.IR.EQ.N+NR) THEN + DO 160 J=1,4 + P(N+1,J)=P(N+1,J)+P(N+NR,J) + 160 CONTINUE + P(N+1,5)=SQRT(MAX(0.D0,P(N+1,4)**2-P(N+1,1)**2-P(N+1,2)**2- + & P(N+1,3)**2)) + NR=NR-1 + GOTO 140 + ELSEIF(PDRMIN.LT.PARU12) THEN + DO 170 J=1,4 + P(IR,J)=P(IR,J)+P(IR+1,J) + 170 CONTINUE + P(IR,5)=SQRT(MAX(0.D0,P(IR,4)**2-P(IR,1)**2-P(IR,2)**2- + & P(IR,3)**2)) + DO 190 I=IR+1,N+NR-1 + K(I,2)=K(I+1,2) + DO 180 J=1,5 + P(I,J)=P(I+1,J) + 180 CONTINUE + 190 CONTINUE + IF(IR.EQ.N+NR-1) K(IR,2)=K(N+NR,2) + NR=NR-1 + IF(MJU(1).GT.IR) MJU(1)=MJU(1)-1 + IF(MJU(2).GT.IR) MJU(2)=MJU(2)-1 + GOTO 140 + ENDIF + ENDIF + NTRYR=NTRYR+1 + +C...Reset particle counter. Skip ahead if no junctions are present; +C...this is usually the case! + NRS=MAX(5*NR+11,NP) + NTRY=0 + 200 NTRY=NTRY+1 + IF(NTRY.GT.100.AND.NTRYR.LE.4) THEN + PARU12=4.*PARU12 + PARU13=2.*PARU13 + GOTO 140 + ELSEIF(NTRY.GT.100) THEN + CALL LUERRM(14,'(LUSTRF:) caught in infinite loop') + IF(MSTU(21).GE.1) RETURN + ENDIF + I=N+NRS + MSTU(90)=MSTU90 + IF(MJU(1).EQ.0.AND.MJU(2).EQ.0) GOTO 580 + DO 570 JT=1,2 + NJS(JT)=0 + IF(MJU(JT).EQ.0) GOTO 570 + JS=3-2*JT + +C...Find and sum up momentum on three sides of junction. Check flavours. + DO 220 IU=1,3 + IJU(IU)=0 + DO 210 J=1,5 + PJU(IU,J)=0. + 210 CONTINUE + 220 CONTINUE + IU=0 + DO 240 I1=N+1+(JT-1)*(NR-1),N+NR+(JT-1)*(1-NR),JS + IF(K(I1,2).NE.21.AND.IU.LE.2) THEN + IU=IU+1 + IJU(IU)=I1 + ENDIF + DO 230 J=1,4 + PJU(IU,J)=PJU(IU,J)+P(I1,J) + 230 CONTINUE + 240 CONTINUE + DO 250 IU=1,3 + PJU(IU,5)=SQRT(PJU(IU,1)**2+PJU(IU,2)**2+PJU(IU,3)**2) + 250 CONTINUE + IF(K(IJU(3),2)/100.NE.10*K(IJU(1),2)+K(IJU(2),2).AND. + &K(IJU(3),2)/100.NE.10*K(IJU(2),2)+K(IJU(1),2)) THEN + CALL LUERRM(12,'(LUSTRF:) unphysical flavour combination') + IF(MSTU(21).GE.1) RETURN + ENDIF + +C...Calculate (approximate) boost to rest frame of junction. + T12=(PJU(1,1)*PJU(2,1)+PJU(1,2)*PJU(2,2)+PJU(1,3)*PJU(2,3))/ + &(PJU(1,5)*PJU(2,5)) + T13=(PJU(1,1)*PJU(3,1)+PJU(1,2)*PJU(3,2)+PJU(1,3)*PJU(3,3))/ + &(PJU(1,5)*PJU(3,5)) + T23=(PJU(2,1)*PJU(3,1)+PJU(2,2)*PJU(3,2)+PJU(2,3)*PJU(3,3))/ + &(PJU(2,5)*PJU(3,5)) + T11=SQRT((2./3.)*(1.-T12)*(1.-T13)/(1.-T23)) + T22=SQRT((2./3.)*(1.-T12)*(1.-T23)/(1.-T13)) + TSQ=SQRT((2.*T11*T22+T12-1.)*(1.+T12)) + T1F=(TSQ-T22*(1.+T12))/(1.-T12**2) + T2F=(TSQ-T11*(1.+T12))/(1.-T12**2) + DO 260 J=1,3 + TJU(J)=-(T1F*PJU(1,J)/PJU(1,5)+T2F*PJU(2,J)/PJU(2,5)) + 260 CONTINUE + TJU(4)=SQRT(1.+TJU(1)**2+TJU(2)**2+TJU(3)**2) + DO 270 IU=1,3 + PJU(IU,5)=TJU(4)*PJU(IU,4)-TJU(1)*PJU(IU,1)-TJU(2)*PJU(IU,2)- + &TJU(3)*PJU(IU,3) + 270 CONTINUE + +C...Put junction at rest if motion could give inconsistencies. + IF(PJU(1,5)+PJU(2,5).GT.PJU(1,4)+PJU(2,4)) THEN + DO 280 J=1,3 + TJU(J)=0. + 280 CONTINUE + TJU(4)=1. + PJU(1,5)=PJU(1,4) + PJU(2,5)=PJU(2,4) + PJU(3,5)=PJU(3,4) + ENDIF + +C...Start preparing for fragmentation of two strings from junction. + ISTA=I + DO 550 IU=1,2 + NS=IJU(IU+1)-IJU(IU) + +C...Junction strings: find longitudinal string directions. + DO 310 IS=1,NS + IS1=IJU(IU)+IS-1 + IS2=IJU(IU)+IS + DO 290 J=1,5 + DP(1,J)=0.5*P(IS1,J) + IF(IS.EQ.1) DP(1,J)=P(IS1,J) + DP(2,J)=0.5*P(IS2,J) + IF(IS.EQ.NS) DP(2,J)=-PJU(IU,J) + 290 CONTINUE + IF(IS.EQ.NS) DP(2,4)=SQRT(PJU(IU,1)**2+PJU(IU,2)**2+PJU(IU,3)**2) + IF(IS.EQ.NS) DP(2,5)=0. + DP(3,5)=DFOUR(1,1) + DP(4,5)=DFOUR(2,2) + DHKC=DFOUR(1,2) + IF(DP(3,5)+2.*DHKC+DP(4,5).LE.0.) THEN + DP(1,4)=SQRT(DP(1,1)**2+DP(1,2)**2+DP(1,3)**2) + DP(2,4)=SQRT(DP(2,1)**2+DP(2,2)**2+DP(2,3)**2) + DP(3,5)=0D0 + DP(4,5)=0D0 + DHKC=DFOUR(1,2) + ENDIF + DHKS=SQRT(DHKC**2-DP(3,5)*DP(4,5)) + DHK1=0.5*((DP(4,5)+DHKC)/DHKS-1.) + DHK2=0.5*((DP(3,5)+DHKC)/DHKS-1.) + IN1=N+NR+4*IS-3 + P(IN1,5)=SQRT(DP(3,5)+2.*DHKC+DP(4,5)) + DO 300 J=1,4 + P(IN1,J)=(1.+DHK1)*DP(1,J)-DHK2*DP(2,J) + P(IN1+1,J)=(1.+DHK2)*DP(2,J)-DHK1*DP(1,J) + 300 CONTINUE + 310 CONTINUE + +C...Junction strings: initialize flavour, momentum and starting pos. + ISAV=I + MSTU91=MSTU(90) + 320 NTRY=NTRY+1 + IF(NTRY.GT.100.AND.NTRYR.LE.4) THEN + PARU12=4.*PARU12 + PARU13=2.*PARU13 + GOTO 140 + ELSEIF(NTRY.GT.100) THEN + CALL LUERRM(14,'(LUSTRF:) caught in infinite loop') + IF(MSTU(21).GE.1) RETURN + ENDIF + I=ISAV + MSTU(90)=MSTU91 + IRANKJ=0 + IE(1)=K(N+1+(JT/2)*(NP-1),3) + IN(4)=N+NR+1 + IN(5)=IN(4)+1 + IN(6)=N+NR+4*NS+1 + DO 340 JQ=1,2 + DO 330 IN1=N+NR+2+JQ,N+NR+4*NS-2+JQ,4 + P(IN1,1)=2-JQ + P(IN1,2)=JQ-1 + P(IN1,3)=1. + 330 CONTINUE + 340 CONTINUE + KFL(1)=K(IJU(IU),2) + PX(1)=0. + PY(1)=0. + GAM(1)=0. + DO 350 J=1,5 + PJU(IU+3,J)=0. + 350 CONTINUE + +C...Junction strings: find initial transverse directions. + DO 360 J=1,4 + DP(1,J)=P(IN(4),J) + DP(2,J)=P(IN(4)+1,J) + DP(3,J)=0. + DP(4,J)=0. + 360 CONTINUE + DP(1,4)=SQRT(DP(1,1)**2+DP(1,2)**2+DP(1,3)**2) + DP(2,4)=SQRT(DP(2,1)**2+DP(2,2)**2+DP(2,3)**2) + DP(5,1)=DP(1,1)/DP(1,4)-DP(2,1)/DP(2,4) + DP(5,2)=DP(1,2)/DP(1,4)-DP(2,2)/DP(2,4) + DP(5,3)=DP(1,3)/DP(1,4)-DP(2,3)/DP(2,4) + IF(DP(5,1)**2.LE.DP(5,2)**2+DP(5,3)**2) DP(3,1)=1. + IF(DP(5,1)**2.GT.DP(5,2)**2+DP(5,3)**2) DP(3,3)=1. + IF(DP(5,2)**2.LE.DP(5,1)**2+DP(5,3)**2) DP(4,2)=1. + IF(DP(5,2)**2.GT.DP(5,1)**2+DP(5,3)**2) DP(4,3)=1. + DHC12=DFOUR(1,2) + DHCX1=DFOUR(3,1)/DHC12 + DHCX2=DFOUR(3,2)/DHC12 + DHCXX=1D0/SQRT(1D0+2D0*DHCX1*DHCX2*DHC12) + DHCY1=DFOUR(4,1)/DHC12 + DHCY2=DFOUR(4,2)/DHC12 + DHCYX=DHCXX*(DHCX1*DHCY2+DHCX2*DHCY1)*DHC12 + DHCYY=1D0/SQRT(1D0+2D0*DHCY1*DHCY2*DHC12-DHCYX**2) + DO 370 J=1,4 + DP(3,J)=DHCXX*(DP(3,J)-DHCX2*DP(1,J)-DHCX1*DP(2,J)) + P(IN(6),J)=DP(3,J) + P(IN(6)+1,J)=DHCYY*(DP(4,J)-DHCY2*DP(1,J)-DHCY1*DP(2,J)- + &DHCYX*DP(3,J)) + 370 CONTINUE + +C...Junction strings: produce new particle, origin. + 380 I=I+1 + IF(2*I-NSAV.GE.MSTU(4)-MSTU(32)-5) THEN + CALL LUERRM(11,'(LUSTRF:) no more memory left in LUJETS') + IF(MSTU(21).GE.1) RETURN + ENDIF + IRANKJ=IRANKJ+1 + K(I,1)=1 + K(I,3)=IE(1) + K(I,4)=0 + K(I,5)=0 + +C...Junction strings: generate flavour, hadron, pT, z and Gamma. + 390 CALL LUKFDI(KFL(1),0,KFL(3),K(I,2)) + IF(K(I,2).EQ.0) GOTO 320 + IF(MSTJ(12).GE.3.AND.IRANKJ.EQ.1.AND.IABS(KFL(1)).LE.10.AND. + &IABS(KFL(3)).GT.10) THEN + IF(RLU(0).GT.PARJ(19)) GOTO 390 + ENDIF + P(I,5)=ULMASS(K(I,2)) + CALL LUPTDI(KFL(1),PX(3),PY(3)) + PR(1)=P(I,5)**2+(PX(1)+PX(3))**2+(PY(1)+PY(3))**2 + CALL LUZDIS(KFL(1),KFL(3),PR(1),Z) + IF(IABS(KFL(1)).GE.4.AND.IABS(KFL(1)).LE.8.AND. + &MSTU(90).LT.8) THEN + MSTU(90)=MSTU(90)+1 + MSTU(90+MSTU(90))=I + PARU(90+MSTU(90))=Z + ENDIF + GAM(3)=(1.-Z)*(GAM(1)+PR(1)/Z) + DO 400 J=1,3 + IN(J)=IN(3+J) + 400 CONTINUE + +C...Junction strings: stepping within or from 'low' string region easy. + IF(IN(1)+1.EQ.IN(2).AND.Z*P(IN(1)+2,3)*P(IN(2)+2,3)* + &P(IN(1),5)**2.GE.PR(1)) THEN + P(IN(1)+2,4)=Z*P(IN(1)+2,3) + P(IN(2)+2,4)=PR(1)/(P(IN(1)+2,4)*P(IN(1),5)**2) + DO 410 J=1,4 + P(I,J)=(PX(1)+PX(3))*P(IN(3),J)+(PY(1)+PY(3))*P(IN(3)+1,J) + 410 CONTINUE + GOTO 500 + ELSEIF(IN(1)+1.EQ.IN(2)) THEN + P(IN(2)+2,4)=P(IN(2)+2,3) + P(IN(2)+2,1)=1. + IN(2)=IN(2)+4 + IF(IN(2).GT.N+NR+4*NS) GOTO 320 + IF(FOUR(IN(1),IN(2)).LE.1D-2) THEN + P(IN(1)+2,4)=P(IN(1)+2,3) + P(IN(1)+2,1)=0. + IN(1)=IN(1)+4 + ENDIF + ENDIF + +C...Junction strings: find new transverse directions. + 420 IF(IN(1).GT.N+NR+4*NS.OR.IN(2).GT.N+NR+4*NS.OR. + &IN(1).GT.IN(2)) GOTO 320 + IF(IN(1).NE.IN(4).OR.IN(2).NE.IN(5)) THEN + DO 430 J=1,4 + DP(1,J)=P(IN(1),J) + DP(2,J)=P(IN(2),J) + DP(3,J)=0. + DP(4,J)=0. + 430 CONTINUE + DP(1,4)=SQRT(DP(1,1)**2+DP(1,2)**2+DP(1,3)**2) + DP(2,4)=SQRT(DP(2,1)**2+DP(2,2)**2+DP(2,3)**2) + DHC12=DFOUR(1,2) + IF(DHC12.LE.1D-2) THEN + P(IN(1)+2,4)=P(IN(1)+2,3) + P(IN(1)+2,1)=0. + IN(1)=IN(1)+4 + GOTO 420 + ENDIF + IN(3)=N+NR+4*NS+5 + DP(5,1)=DP(1,1)/DP(1,4)-DP(2,1)/DP(2,4) + DP(5,2)=DP(1,2)/DP(1,4)-DP(2,2)/DP(2,4) + DP(5,3)=DP(1,3)/DP(1,4)-DP(2,3)/DP(2,4) + IF(DP(5,1)**2.LE.DP(5,2)**2+DP(5,3)**2) DP(3,1)=1. + IF(DP(5,1)**2.GT.DP(5,2)**2+DP(5,3)**2) DP(3,3)=1. + IF(DP(5,2)**2.LE.DP(5,1)**2+DP(5,3)**2) DP(4,2)=1. + IF(DP(5,2)**2.GT.DP(5,1)**2+DP(5,3)**2) DP(4,3)=1. + DHCX1=DFOUR(3,1)/DHC12 + DHCX2=DFOUR(3,2)/DHC12 + DHCXX=1D0/SQRT(1D0+2D0*DHCX1*DHCX2*DHC12) + DHCY1=DFOUR(4,1)/DHC12 + DHCY2=DFOUR(4,2)/DHC12 + DHCYX=DHCXX*(DHCX1*DHCY2+DHCX2*DHCY1)*DHC12 + DHCYY=1D0/SQRT(1D0+2D0*DHCY1*DHCY2*DHC12-DHCYX**2) + DO 440 J=1,4 + DP(3,J)=DHCXX*(DP(3,J)-DHCX2*DP(1,J)-DHCX1*DP(2,J)) + P(IN(3),J)=DP(3,J) + P(IN(3)+1,J)=DHCYY*(DP(4,J)-DHCY2*DP(1,J)-DHCY1*DP(2,J)- + & DHCYX*DP(3,J)) + 440 CONTINUE +C...Express pT with respect to new axes, if sensible. + PXP=-(PX(3)*FOUR(IN(6),IN(3))+PY(3)*FOUR(IN(6)+1,IN(3))) + PYP=-(PX(3)*FOUR(IN(6),IN(3)+1)+PY(3)*FOUR(IN(6)+1,IN(3)+1)) + IF(ABS(PXP**2+PYP**2-PX(3)**2-PY(3)**2).LT.0.01) THEN + PX(3)=PXP + PY(3)=PYP + ENDIF + ENDIF + +C...Junction strings: sum up known four-momentum, coefficients for m2. + DO 470 J=1,4 + DHG(J)=0. + P(I,J)=PX(1)*P(IN(6),J)+PY(1)*P(IN(6)+1,J)+PX(3)*P(IN(3),J)+ + &PY(3)*P(IN(3)+1,J) + DO 450 IN1=IN(4),IN(1)-4,4 + P(I,J)=P(I,J)+P(IN1+2,3)*P(IN1,J) + 450 CONTINUE + DO 460 IN2=IN(5),IN(2)-4,4 + P(I,J)=P(I,J)+P(IN2+2,3)*P(IN2,J) + 460 CONTINUE + 470 CONTINUE + DHM(1)=FOUR(I,I) + DHM(2)=2.*FOUR(I,IN(1)) + DHM(3)=2.*FOUR(I,IN(2)) + DHM(4)=2.*FOUR(IN(1),IN(2)) + +C...Junction strings: find coefficients for Gamma expression. + DO 490 IN2=IN(1)+1,IN(2),4 + DO 480 IN1=IN(1),IN2-1,4 + DHC=2.*FOUR(IN1,IN2) + DHG(1)=DHG(1)+P(IN1+2,1)*P(IN2+2,1)*DHC + IF(IN1.EQ.IN(1)) DHG(2)=DHG(2)-P(IN2+2,1)*DHC + IF(IN2.EQ.IN(2)) DHG(3)=DHG(3)+P(IN1+2,1)*DHC + IF(IN1.EQ.IN(1).AND.IN2.EQ.IN(2)) DHG(4)=DHG(4)-DHC + 480 CONTINUE + 490 CONTINUE + +C...Junction strings: solve (m2, Gamma) equation system for energies. + DHS1=DHM(3)*DHG(4)-DHM(4)*DHG(3) + IF(ABS(DHS1).LT.1D-4) GOTO 320 + DHS2=DHM(4)*(GAM(3)-DHG(1))-DHM(2)*DHG(3)-DHG(4)* + &(P(I,5)**2-DHM(1))+DHG(2)*DHM(3) + DHS3=DHM(2)*(GAM(3)-DHG(1))-DHG(2)*(P(I,5)**2-DHM(1)) + P(IN(2)+2,4)=0.5*(SQRT(MAX(0D0,DHS2**2-4.*DHS1*DHS3))/ABS(DHS1)- + &DHS2/DHS1) + IF(DHM(2)+DHM(4)*P(IN(2)+2,4).LE.0.) GOTO 320 + P(IN(1)+2,4)=(P(I,5)**2-DHM(1)-DHM(3)*P(IN(2)+2,4))/ + &(DHM(2)+DHM(4)*P(IN(2)+2,4)) + +C...Junction strings: step to new region if necessary. + IF(P(IN(2)+2,4).GT.P(IN(2)+2,3)) THEN + P(IN(2)+2,4)=P(IN(2)+2,3) + P(IN(2)+2,1)=1. + IN(2)=IN(2)+4 + IF(IN(2).GT.N+NR+4*NS) GOTO 320 + IF(FOUR(IN(1),IN(2)).LE.1D-2) THEN + P(IN(1)+2,4)=P(IN(1)+2,3) + P(IN(1)+2,1)=0. + IN(1)=IN(1)+4 + ENDIF + GOTO 420 + ELSEIF(P(IN(1)+2,4).GT.P(IN(1)+2,3)) THEN + P(IN(1)+2,4)=P(IN(1)+2,3) + P(IN(1)+2,1)=0. + IN(1)=IN(1)+JS + GOTO 820 + ENDIF + +C...Junction strings: particle four-momentum, remainder, loop back. + 500 DO 510 J=1,4 + P(I,J)=P(I,J)+P(IN(1)+2,4)*P(IN(1),J)+P(IN(2)+2,4)*P(IN(2),J) + PJU(IU+3,J)=PJU(IU+3,J)+P(I,J) + 510 CONTINUE + IF(P(I,4).LT.P(I,5)) GOTO 320 + PJU(IU+3,5)=TJU(4)*PJU(IU+3,4)-TJU(1)*PJU(IU+3,1)- + &TJU(2)*PJU(IU+3,2)-TJU(3)*PJU(IU+3,3) + IF(PJU(IU+3,5).LT.PJU(IU,5)) THEN + KFL(1)=-KFL(3) + PX(1)=-PX(3) + PY(1)=-PY(3) + GAM(1)=GAM(3) + IF(IN(3).NE.IN(6)) THEN + DO 520 J=1,4 + P(IN(6),J)=P(IN(3),J) + P(IN(6)+1,J)=P(IN(3)+1,J) + 520 CONTINUE + ENDIF + DO 530 JQ=1,2 + IN(3+JQ)=IN(JQ) + P(IN(JQ)+2,3)=P(IN(JQ)+2,3)-P(IN(JQ)+2,4) + P(IN(JQ)+2,1)=P(IN(JQ)+2,1)-(3-2*JQ)*P(IN(JQ)+2,4) + 530 CONTINUE + GOTO 380 + ENDIF + +C...Junction strings: save quantities left after each string. + IF(IABS(KFL(1)).GT.10) GOTO 320 + I=I-1 + KFJH(IU)=KFL(1) + DO 540 J=1,4 + PJU(IU+3,J)=PJU(IU+3,J)-P(I+1,J) + 540 CONTINUE + 550 CONTINUE + +C...Junction strings: put together to new effective string endpoint. + NJS(JT)=I-ISTA + KFJS(JT)=K(K(MJU(JT+2),3),2) + KFLS=2*INT(RLU(0)+3.*PARJ(4)/(1.+3.*PARJ(4)))+1 + IF(KFJH(1).EQ.KFJH(2)) KFLS=3 + IF(ISTA.NE.I) KFJS(JT)=ISIGN(1000*MAX(IABS(KFJH(1)), + &IABS(KFJH(2)))+100*MIN(IABS(KFJH(1)),IABS(KFJH(2)))+ + &KFLS,KFJH(1)) + DO 560 J=1,4 + PJS(JT,J)=PJU(1,J)+PJU(2,J)+P(MJU(JT),J) + PJS(JT+2,J)=PJU(4,J)+PJU(5,J) + 560 CONTINUE + PJS(JT,5)=SQRT(MAX(0.D0,PJS(JT,4)**2-PJS(JT,1)**2-PJS(JT,2)**2- + &PJS(JT,3)**2)) + 570 CONTINUE + +C...Open versus closed strings. Choose breakup region for latter. + 580 IF(MJU(1).NE.0.AND.MJU(2).NE.0) THEN + NS=MJU(2)-MJU(1) + NB=MJU(1)-N + ELSEIF(MJU(1).NE.0) THEN + NS=N+NR-MJU(1) + NB=MJU(1)-N + ELSEIF(MJU(2).NE.0) THEN + NS=MJU(2)-N + NB=1 + ELSEIF(IABS(K(N+1,2)).NE.21) THEN + NS=NR-1 + NB=1 + ELSE + NS=NR+1 + W2SUM=0. + DO 590 IS=1,NR + P(N+NR+IS,1)=0.5*FOUR(N+IS,N+IS+1-NR*(IS/NR)) + W2SUM=W2SUM+P(N+NR+IS,1) + 590 CONTINUE + W2RAN=RLU(0)*W2SUM + NB=0 + 600 NB=NB+1 + W2SUM=W2SUM-P(N+NR+NB,1) + IF(W2SUM.GT.W2RAN.AND.NB.LT.NR) GOTO 600 + ENDIF + +C...Find longitudinal string directions (i.e. lightlike four-vectors). + DO 630 IS=1,NS + IS1=N+IS+NB-1-NR*((IS+NB-2)/NR) + IS2=N+IS+NB-NR*((IS+NB-1)/NR) + DO 610 J=1,5 + DP(1,J)=P(IS1,J) + IF(IABS(K(IS1,2)).EQ.21) DP(1,J)=0.5*DP(1,J) + IF(IS1.EQ.MJU(1)) DP(1,J)=PJS(1,J)-PJS(3,J) + DP(2,J)=P(IS2,J) + IF(IABS(K(IS2,2)).EQ.21) DP(2,J)=0.5*DP(2,J) + IF(IS2.EQ.MJU(2)) DP(2,J)=PJS(2,J)-PJS(4,J) + 610 CONTINUE + DP(3,5)=DFOUR(1,1) + DP(4,5)=DFOUR(2,2) + DHKC=DFOUR(1,2) + IF(DP(3,5)+2.*DHKC+DP(4,5).LE.0.) THEN + DP(3,5)=DP(1,5)**2 + DP(4,5)=DP(2,5)**2 + DP(1,4)=SQRT(DP(1,1)**2+DP(1,2)**2+DP(1,3)**2+DP(1,5)**2) + DP(2,4)=SQRT(DP(2,1)**2+DP(2,2)**2+DP(2,3)**2+DP(2,5)**2) + DHKC=DFOUR(1,2) + ENDIF + DHKS=SQRT(DHKC**2-DP(3,5)*DP(4,5)) + DHK1=0.5*((DP(4,5)+DHKC)/DHKS-1.) + DHK2=0.5*((DP(3,5)+DHKC)/DHKS-1.) + IN1=N+NR+4*IS-3 + P(IN1,5)=SQRT(DP(3,5)+2.*DHKC+DP(4,5)) + DO 620 J=1,4 + P(IN1,J)=(1.+DHK1)*DP(1,J)-DHK2*DP(2,J) + P(IN1+1,J)=(1.+DHK2)*DP(2,J)-DHK1*DP(1,J) + 620 CONTINUE + 630 CONTINUE + +C...Begin initialization: sum up energy, set starting position. + ISAV=I + MSTU91=MSTU(90) + 640 NTRY=NTRY+1 + IF(NTRY.GT.100.AND.NTRYR.LE.4) THEN + PARU12=4.*PARU12 + PARU13=2.*PARU13 + GOTO 140 + ELSEIF(NTRY.GT.100) THEN + CALL LUERRM(14,'(LUSTRF:) caught in infinite loop') + IF(MSTU(21).GE.1) RETURN + ENDIF + I=ISAV + MSTU(90)=MSTU91 + DO 660 J=1,4 + P(N+NRS,J)=0. + DO 650 IS=1,NR + P(N+NRS,J)=P(N+NRS,J)+P(N+IS,J) + 650 CONTINUE + 660 CONTINUE + DO 680 JT=1,2 + IRANK(JT)=0 + IF(MJU(JT).NE.0) IRANK(JT)=NJS(JT) + IF(NS.GT.NR) IRANK(JT)=1 + IE(JT)=K(N+1+(JT/2)*(NP-1),3) + IN(3*JT+1)=N+NR+1+4*(JT/2)*(NS-1) + IN(3*JT+2)=IN(3*JT+1)+1 + IN(3*JT+3)=N+NR+4*NS+2*JT-1 + DO 670 IN1=N+NR+2+JT,N+NR+4*NS-2+JT,4 + P(IN1,1)=2-JT + P(IN1,2)=JT-1 + P(IN1,3)=1. + 670 CONTINUE + 680 CONTINUE + +C...Initialize flavour and pT variables for open string. + IF(NS.LT.NR) THEN + PX(1)=0. + PY(1)=0. + IF(NS.EQ.1.AND.MJU(1)+MJU(2).EQ.0) CALL LUPTDI(0,PX(1),PY(1)) + PX(2)=-PX(1) + PY(2)=-PY(1) + DO 690 JT=1,2 + KFL(JT)=K(IE(JT),2) + IF(MJU(JT).NE.0) KFL(JT)=KFJS(JT) + MSTJ(93)=1 + PMQ(JT)=ULMASS(KFL(JT)) + GAM(JT)=0. + 690 CONTINUE + +C...Closed string: random initial breakup flavour, pT and vertex. + ELSE + KFL(3)=INT(1.+(2.+PARJ(2))*RLU(0))*(-1)**INT(RLU(0)+0.5) + CALL LUKFDI(KFL(3),0,KFL(1),KDUMP) + KFL(2)=-KFL(1) + IF(IABS(KFL(1)).GT.10.AND.RLU(0).GT.0.5) THEN + KFL(2)=-(KFL(1)+ISIGN(10000,KFL(1))) + ELSEIF(IABS(KFL(1)).GT.10) THEN + KFL(1)=-(KFL(2)+ISIGN(10000,KFL(2))) + ENDIF + CALL LUPTDI(KFL(1),PX(1),PY(1)) + PX(2)=-PX(1) + PY(2)=-PY(1) + PR3=MIN(25.D0,0.1*P(N+NR+1,5)**2) + 700 CALL LUZDIS(KFL(1),KFL(2),PR3,Z) + ZR=PR3/(Z*P(N+NR+1,5)**2) + IF(ZR.GE.1.) GOTO 700 + DO 710 JT=1,2 + MSTJ(93)=1 + PMQ(JT)=ULMASS(KFL(JT)) + GAM(JT)=PR3*(1.-Z)/Z + IN1=N+NR+3+4*(JT/2)*(NS-1) + P(IN1,JT)=1.-Z + P(IN1,3-JT)=JT-1 + P(IN1,3)=(2-JT)*(1.-Z)+(JT-1)*Z + P(IN1+1,JT)=ZR + P(IN1+1,3-JT)=2-JT + P(IN1+1,3)=(2-JT)*(1.-ZR)+(JT-1)*ZR + 710 CONTINUE + ENDIF + +C...Find initial transverse directions (i.e. spacelike four-vectors). + DO 750 JT=1,2 + IF(JT.EQ.1.OR.NS.EQ.NR-1) THEN + IN1=IN(3*JT+1) + IN3=IN(3*JT+3) + DO 720 J=1,4 + DP(1,J)=P(IN1,J) + DP(2,J)=P(IN1+1,J) + DP(3,J)=0. + DP(4,J)=0. + 720 CONTINUE + DP(1,4)=SQRT(DP(1,1)**2+DP(1,2)**2+DP(1,3)**2) + DP(2,4)=SQRT(DP(2,1)**2+DP(2,2)**2+DP(2,3)**2) + DP(5,1)=DP(1,1)/DP(1,4)-DP(2,1)/DP(2,4) + DP(5,2)=DP(1,2)/DP(1,4)-DP(2,2)/DP(2,4) + DP(5,3)=DP(1,3)/DP(1,4)-DP(2,3)/DP(2,4) + IF(DP(5,1)**2.LE.DP(5,2)**2+DP(5,3)**2) DP(3,1)=1. + IF(DP(5,1)**2.GT.DP(5,2)**2+DP(5,3)**2) DP(3,3)=1. + IF(DP(5,2)**2.LE.DP(5,1)**2+DP(5,3)**2) DP(4,2)=1. + IF(DP(5,2)**2.GT.DP(5,1)**2+DP(5,3)**2) DP(4,3)=1. + DHC12=DFOUR(1,2) + DHCX1=DFOUR(3,1)/DHC12 + DHCX2=DFOUR(3,2)/DHC12 + DHCXX=1D0/SQRT(1D0+2D0*DHCX1*DHCX2*DHC12) + DHCY1=DFOUR(4,1)/DHC12 + DHCY2=DFOUR(4,2)/DHC12 + DHCYX=DHCXX*(DHCX1*DHCY2+DHCX2*DHCY1)*DHC12 + DHCYY=1D0/SQRT(1D0+2D0*DHCY1*DHCY2*DHC12-DHCYX**2) + DO 730 J=1,4 + DP(3,J)=DHCXX*(DP(3,J)-DHCX2*DP(1,J)-DHCX1*DP(2,J)) + P(IN3,J)=DP(3,J) + P(IN3+1,J)=DHCYY*(DP(4,J)-DHCY2*DP(1,J)-DHCY1*DP(2,J)- + & DHCYX*DP(3,J)) + 730 CONTINUE + ELSE + DO 740 J=1,4 + P(IN3+2,J)=P(IN3,J) + P(IN3+3,J)=P(IN3+1,J) + 740 CONTINUE + ENDIF + 750 CONTINUE + +C...Remove energy used up in junction string fragmentation. + IF(MJU(1)+MJU(2).GT.0) THEN + DO 770 JT=1,2 + IF(NJS(JT).EQ.0) GOTO 770 + DO 760 J=1,4 + P(N+NRS,J)=P(N+NRS,J)-PJS(JT+2,J) + 760 CONTINUE + 770 CONTINUE + ENDIF + +C...Produce new particle: side, origin. + 780 I=I+1 + IF(2*I-NSAV.GE.MSTU(4)-MSTU(32)-5) THEN + CALL LUERRM(11,'(LUSTRF:) no more memory left in LUJETS') + IF(MSTU(21).GE.1) RETURN + ENDIF + JT=1.5+RLU(0) + IF(IABS(KFL(3-JT)).GT.10) JT=3-JT + IF(IABS(KFL(3-JT)).GE.4.AND.IABS(KFL(3-JT)).LE.8) JT=3-JT + JR=3-JT + JS=3-2*JT + IRANK(JT)=IRANK(JT)+1 + K(I,1)=1 + K(I,3)=IE(JT) + K(I,4)=0 + K(I,5)=0 + +C...Generate flavour, hadron and pT. + 790 CALL LUKFDI(KFL(JT),0,KFL(3),K(I,2)) + IF(K(I,2).EQ.0) GOTO 640 + IF(MSTJ(12).GE.3.AND.IRANK(JT).EQ.1.AND.IABS(KFL(JT)).LE.10.AND. + &IABS(KFL(3)).GT.10) THEN + IF(RLU(0).GT.PARJ(19)) GOTO 790 + ENDIF + P(I,5)=ULMASS(K(I,2)) + CALL LUPTDI(KFL(JT),PX(3),PY(3)) + PR(JT)=P(I,5)**2+(PX(JT)+PX(3))**2+(PY(JT)+PY(3))**2 + +C...Final hadrons for small invariant mass. + MSTJ(93)=1 + PMQ(3)=ULMASS(KFL(3)) + PARJST=PARJ(33) + IF(MSTJ(11).EQ.2) PARJST=PARJ(34) + WMIN=PARJST+PMQ(1)+PMQ(2)+PARJ(36)*PMQ(3) + IF(IABS(KFL(JT)).GT.10.AND.IABS(KFL(3)).GT.10) WMIN= + &WMIN-0.5*PARJ(36)*PMQ(3) + WREM2=FOUR(N+NRS,N+NRS) + IF(WREM2.LT.0.10) GOTO 640 + IF(WREM2.LT.MAX(WMIN*(1.+(2.*RLU(0)-1.)*PARJ(37)), + &PARJ(32)+PMQ(1)+PMQ(2))**2) GOTO 940 + +C...Choose z, which gives Gamma. Shift z for heavy flavours. + CALL LUZDIS(KFL(JT),KFL(3),PR(JT),Z) + IF(IABS(KFL(JT)).GE.4.AND.IABS(KFL(JT)).LE.8.AND. + &MSTU(90).LT.8) THEN + MSTU(90)=MSTU(90)+1 + MSTU(90+MSTU(90))=I + PARU(90+MSTU(90))=Z + ENDIF + KFL1A=IABS(KFL(1)) + KFL2A=IABS(KFL(2)) + IF(MAX(MOD(KFL1A,10),MOD(KFL1A/1000,10),MOD(KFL2A,10), + &MOD(KFL2A/1000,10)).GE.4) THEN + PR(JR)=(PMQ(JR)+PMQ(3))**2+(PX(JR)-PX(3))**2+(PY(JR)-PY(3))**2 + PW12=SQRT(MAX(0.D0,(WREM2-PR(1)-PR(2))**2-4.*PR(1)*PR(2))) + Z=(WREM2+PR(JT)-PR(JR)+PW12*(2.*Z-1.))/(2.*WREM2) + PR(JR)=(PMQ(JR)+PARJST)**2+(PX(JR)-PX(3))**2+(PY(JR)-PY(3))**2 + IF((1.-Z)*(WREM2-PR(JT)/Z).LT.PR(JR)) GOTO 940 + ENDIF + GAM(3)=(1.-Z)*(GAM(JT)+PR(JT)/Z) + DO 800 J=1,3 + IN(J)=IN(3*JT+J) + 800 CONTINUE + +C...Stepping within or from 'low' string region easy. + IF(IN(1)+1.EQ.IN(2).AND.Z*P(IN(1)+2,3)*P(IN(2)+2,3)* + &P(IN(1),5)**2.GE.PR(JT)) THEN + P(IN(JT)+2,4)=Z*P(IN(JT)+2,3) + P(IN(JR)+2,4)=PR(JT)/(P(IN(JT)+2,4)*P(IN(1),5)**2) + DO 810 J=1,4 + P(I,J)=(PX(JT)+PX(3))*P(IN(3),J)+(PY(JT)+PY(3))*P(IN(3)+1,J) + 810 CONTINUE + GOTO 900 + ELSEIF(IN(1)+1.EQ.IN(2)) THEN + P(IN(JR)+2,4)=P(IN(JR)+2,3) + P(IN(JR)+2,JT)=1. + IN(JR)=IN(JR)+4*JS + IF(JS*IN(JR).GT.JS*IN(4*JR)) GOTO 640 + IF(FOUR(IN(1),IN(2)).LE.1D-2) THEN + P(IN(JT)+2,4)=P(IN(JT)+2,3) + P(IN(JT)+2,JT)=0. + IN(JT)=IN(JT)+4*JS + ENDIF + ENDIF + +C...Find new transverse directions (i.e. spacelike string vectors). + 820 IF(JS*IN(1).GT.JS*IN(3*JR+1).OR.JS*IN(2).GT.JS*IN(3*JR+2).OR. + &IN(1).GT.IN(2)) GOTO 640 + IF(IN(1).NE.IN(3*JT+1).OR.IN(2).NE.IN(3*JT+2)) THEN + DO 830 J=1,4 + DP(1,J)=P(IN(1),J) + DP(2,J)=P(IN(2),J) + DP(3,J)=0. + DP(4,J)=0. + 830 CONTINUE + DP(1,4)=SQRT(DP(1,1)**2+DP(1,2)**2+DP(1,3)**2) + DP(2,4)=SQRT(DP(2,1)**2+DP(2,2)**2+DP(2,3)**2) + DHC12=DFOUR(1,2) + IF(DHC12.LE.1D-2) THEN + P(IN(JT)+2,4)=P(IN(JT)+2,3) + P(IN(JT)+2,JT)=0. + IN(JT)=IN(JT)+4*JS + GOTO 820 + ENDIF + IN(3)=N+NR+4*NS+5 + DP(5,1)=DP(1,1)/DP(1,4)-DP(2,1)/DP(2,4) + DP(5,2)=DP(1,2)/DP(1,4)-DP(2,2)/DP(2,4) + DP(5,3)=DP(1,3)/DP(1,4)-DP(2,3)/DP(2,4) + IF(DP(5,1)**2.LE.DP(5,2)**2+DP(5,3)**2) DP(3,1)=1. + IF(DP(5,1)**2.GT.DP(5,2)**2+DP(5,3)**2) DP(3,3)=1. + IF(DP(5,2)**2.LE.DP(5,1)**2+DP(5,3)**2) DP(4,2)=1. + IF(DP(5,2)**2.GT.DP(5,1)**2+DP(5,3)**2) DP(4,3)=1. + DHCX1=DFOUR(3,1)/DHC12 + DHCX2=DFOUR(3,2)/DHC12 + DHCXX=1D0/SQRT(1D0+2D0*DHCX1*DHCX2*DHC12) + DHCY1=DFOUR(4,1)/DHC12 + DHCY2=DFOUR(4,2)/DHC12 + DHCYX=DHCXX*(DHCX1*DHCY2+DHCX2*DHCY1)*DHC12 + DHCYY=1D0/SQRT(1D0+2D0*DHCY1*DHCY2*DHC12-DHCYX**2) + DO 840 J=1,4 + DP(3,J)=DHCXX*(DP(3,J)-DHCX2*DP(1,J)-DHCX1*DP(2,J)) + P(IN(3),J)=DP(3,J) + P(IN(3)+1,J)=DHCYY*(DP(4,J)-DHCY2*DP(1,J)-DHCY1*DP(2,J)- + & DHCYX*DP(3,J)) + 840 CONTINUE +C...Express pT with respect to new axes, if sensible. + PXP=-(PX(3)*FOUR(IN(3*JT+3),IN(3))+PY(3)* + & FOUR(IN(3*JT+3)+1,IN(3))) + PYP=-(PX(3)*FOUR(IN(3*JT+3),IN(3)+1)+PY(3)* + & FOUR(IN(3*JT+3)+1,IN(3)+1)) + IF(ABS(PXP**2+PYP**2-PX(3)**2-PY(3)**2).LT.0.01) THEN + PX(3)=PXP + PY(3)=PYP + ENDIF + ENDIF + +C...Sum up known four-momentum. Gives coefficients for m2 expression. + DO 870 J=1,4 + DHG(J)=0. + P(I,J)=PX(JT)*P(IN(3*JT+3),J)+PY(JT)*P(IN(3*JT+3)+1,J)+ + &PX(3)*P(IN(3),J)+PY(3)*P(IN(3)+1,J) + DO 850 IN1=IN(3*JT+1),IN(1)-4*JS,4*JS + P(I,J)=P(I,J)+P(IN1+2,3)*P(IN1,J) + 850 CONTINUE + DO 860 IN2=IN(3*JT+2),IN(2)-4*JS,4*JS + P(I,J)=P(I,J)+P(IN2+2,3)*P(IN2,J) + 860 CONTINUE + 870 CONTINUE + DHM(1)=FOUR(I,I) + DHM(2)=2.*FOUR(I,IN(1)) + DHM(3)=2.*FOUR(I,IN(2)) + DHM(4)=2.*FOUR(IN(1),IN(2)) + +C...Find coefficients for Gamma expression. + DO 890 IN2=IN(1)+1,IN(2),4 + DO 880 IN1=IN(1),IN2-1,4 + DHC=2.*FOUR(IN1,IN2) + DHG(1)=DHG(1)+P(IN1+2,JT)*P(IN2+2,JT)*DHC + IF(IN1.EQ.IN(1)) DHG(2)=DHG(2)-JS*P(IN2+2,JT)*DHC + IF(IN2.EQ.IN(2)) DHG(3)=DHG(3)+JS*P(IN1+2,JT)*DHC + IF(IN1.EQ.IN(1).AND.IN2.EQ.IN(2)) DHG(4)=DHG(4)-DHC + 880 CONTINUE + 890 CONTINUE + +C...Solve (m2, Gamma) equation system for energies taken. + DHS1=DHM(JR+1)*DHG(4)-DHM(4)*DHG(JR+1) + IF(ABS(DHS1).LT.1D-4) GOTO 640 + DHS2=DHM(4)*(GAM(3)-DHG(1))-DHM(JT+1)*DHG(JR+1)-DHG(4)* + &(P(I,5)**2-DHM(1))+DHG(JT+1)*DHM(JR+1) + DHS3=DHM(JT+1)*(GAM(3)-DHG(1))-DHG(JT+1)*(P(I,5)**2-DHM(1)) + P(IN(JR)+2,4)=0.5*(SQRT(MAX(0D0,DHS2**2-4.*DHS1*DHS3))/ABS(DHS1)- + &DHS2/DHS1) + IF(DHM(JT+1)+DHM(4)*P(IN(JR)+2,4).LE.0.) GOTO 640 + P(IN(JT)+2,4)=(P(I,5)**2-DHM(1)-DHM(JR+1)*P(IN(JR)+2,4))/ + &(DHM(JT+1)+DHM(4)*P(IN(JR)+2,4)) + +C...Step to new region if necessary. + IF(P(IN(JR)+2,4).GT.P(IN(JR)+2,3)) THEN + P(IN(JR)+2,4)=P(IN(JR)+2,3) + P(IN(JR)+2,JT)=1. + IN(JR)=IN(JR)+4*JS + IF(JS*IN(JR).GT.JS*IN(4*JR)) GOTO 640 + IF(FOUR(IN(1),IN(2)).LE.1D-2) THEN + P(IN(JT)+2,4)=P(IN(JT)+2,3) + P(IN(JT)+2,JT)=0. + IN(JT)=IN(JT)+4*JS + ENDIF + GOTO 820 + ELSEIF(P(IN(JT)+2,4).GT.P(IN(JT)+2,3)) THEN + P(IN(JT)+2,4)=P(IN(JT)+2,3) + P(IN(JT)+2,JT)=0. + IN(JT)=IN(JT)+4*JS + GOTO 820 + ENDIF + +C...Four-momentum of particle. Remaining quantities. Loop back. + 900 DO 910 J=1,4 + P(I,J)=P(I,J)+P(IN(1)+2,4)*P(IN(1),J)+P(IN(2)+2,4)*P(IN(2),J) + P(N+NRS,J)=P(N+NRS,J)-P(I,J) + 910 CONTINUE + IF(P(I,4).LT.P(I,5)) GOTO 640 + KFL(JT)=-KFL(3) + PMQ(JT)=PMQ(3) + PX(JT)=-PX(3) + PY(JT)=-PY(3) + GAM(JT)=GAM(3) + IF(IN(3).NE.IN(3*JT+3)) THEN + DO 920 J=1,4 + P(IN(3*JT+3),J)=P(IN(3),J) + P(IN(3*JT+3)+1,J)=P(IN(3)+1,J) + 920 CONTINUE + ENDIF + DO 930 JQ=1,2 + IN(3*JT+JQ)=IN(JQ) + P(IN(JQ)+2,3)=P(IN(JQ)+2,3)-P(IN(JQ)+2,4) + P(IN(JQ)+2,JT)=P(IN(JQ)+2,JT)-JS*(3-2*JQ)*P(IN(JQ)+2,4) + 930 CONTINUE + GOTO 780 + +C...Final hadron: side, flavour, hadron, mass. + 940 I=I+1 + K(I,1)=1 + K(I,3)=IE(JR) + K(I,4)=0 + K(I,5)=0 + CALL LUKFDI(KFL(JR),-KFL(3),KFLDMP,K(I,2)) + IF(K(I,2).EQ.0) GOTO 640 + P(I,5)=ULMASS(K(I,2)) + PR(JR)=P(I,5)**2+(PX(JR)-PX(3))**2+(PY(JR)-PY(3))**2 + +C...Final two hadrons: find common setup of four-vectors. + JQ=1 + IF(P(IN(4)+2,3)*P(IN(5)+2,3)*FOUR(IN(4),IN(5)).LT.P(IN(7),3)* + &P(IN(8),3)*FOUR(IN(7),IN(8))) JQ=2 + DHC12=FOUR(IN(3*JQ+1),IN(3*JQ+2)) + DHR1=FOUR(N+NRS,IN(3*JQ+2))/DHC12 + DHR2=FOUR(N+NRS,IN(3*JQ+1))/DHC12 + IF(IN(4).NE.IN(7).OR.IN(5).NE.IN(8)) THEN + PX(3-JQ)=-FOUR(N+NRS,IN(3*JQ+3))-PX(JQ) + PY(3-JQ)=-FOUR(N+NRS,IN(3*JQ+3)+1)-PY(JQ) + PR(3-JQ)=P(I+(JT+JQ-3)**2-1,5)**2+(PX(3-JQ)+(2*JQ-3)*JS* + & PX(3))**2+(PY(3-JQ)+(2*JQ-3)*JS*PY(3))**2 + ENDIF + +C...Solve kinematics for final two hadrons, if possible. + WREM2=WREM2+(PX(1)+PX(2))**2+(PY(1)+PY(2))**2 + FD=(SQRT(PR(1))+SQRT(PR(2)))/SQRT(WREM2) + IF(MJU(1)+MJU(2).NE.0.AND.I.EQ.ISAV+2.AND.FD.GE.1.) GOTO 200 + IF(FD.GE.1.) GOTO 640 + FA=WREM2+PR(JT)-PR(JR) + IF(MSTJ(11).NE.2) PREV=0.5*EXP(MAX(-50.D0,LOG(FD)*PARJ(38)* + &(PR(1)+PR(2))**2)) + IF(MSTJ(11).EQ.2) PREV=0.5*FD**PARJ(39) + FB=SIGN(SQRT(MAX(0.D0,FA**2-4.*WREM2*PR(JT))),JS*(RLU(0)-PREV)) + KFL1A=IABS(KFL(1)) + KFL2A=IABS(KFL(2)) + IF(MAX(MOD(KFL1A,10),MOD(KFL1A/1000,10),MOD(KFL2A,10), + &MOD(KFL2A/1000,10)).GE.6) FB=SIGN(SQRT(MAX(0.D0,FA**2- + &4.*WREM2*PR(JT))),DBLE(JS)) + DO 950 J=1,4 + P(I-1,J)=(PX(JT)+PX(3))*P(IN(3*JQ+3),J)+(PY(JT)+PY(3))* + &P(IN(3*JQ+3)+1,J)+0.5*(DHR1*(FA+FB)*P(IN(3*JQ+1),J)+ + &DHR2*(FA-FB)*P(IN(3*JQ+2),J))/WREM2 + P(I,J)=P(N+NRS,J)-P(I-1,J) + 950 CONTINUE + IF(P(I-1,4).LT.P(I-1,5).OR.P(I,4).LT.P(I,5)) GOTO 640 + +C...Mark jets as fragmented and give daughter pointers. + N=I-NRS+1 + DO 960 I=NSAV+1,NSAV+NP + IM=K(I,3) + K(IM,1)=K(IM,1)+10 + IF(MSTU(16).NE.2) THEN + K(IM,4)=NSAV+1 + K(IM,5)=NSAV+1 + ELSE + K(IM,4)=NSAV+2 + K(IM,5)=N + ENDIF + 960 CONTINUE + +C...Document string system. Move up particles. + NSAV=NSAV+1 + K(NSAV,1)=11 + K(NSAV,2)=92 + K(NSAV,3)=IP + K(NSAV,4)=NSAV+1 + K(NSAV,5)=N + DO 970 J=1,4 + P(NSAV,J)=DPS(J) + V(NSAV,J)=V(IP,J) + 970 CONTINUE + P(NSAV,5)=SQRT(MAX(0D0,DPS(4)**2-DPS(1)**2-DPS(2)**2-DPS(3)**2)) + V(NSAV,5)=0. + DO 990 I=NSAV+1,N + DO 980 J=1,5 + K(I,J)=K(I+NRS-1,J) + P(I,J)=P(I+NRS-1,J) + V(I,J)=0. + 980 CONTINUE + 990 CONTINUE + MSTU91=MSTU(90) + DO 1000 IZ=MSTU90+1,MSTU91 + MSTU9T(IZ)=MSTU(90+IZ)-NRS+1-NSAV+N + PARU9T(IZ)=PARU(90+IZ) + 1000 CONTINUE + MSTU(90)=MSTU90 + +C...Order particles in rank along the chain. Update mother pointer. + DO 1020 I=NSAV+1,N + DO 1010 J=1,5 + K(I-NSAV+N,J)=K(I,J) + P(I-NSAV+N,J)=P(I,J) + 1010 CONTINUE + 1020 CONTINUE + I1=NSAV + DO 1050 I=N+1,2*N-NSAV + IF(K(I,3).NE.IE(1)) GOTO 1050 + I1=I1+1 + DO 1030 J=1,5 + K(I1,J)=K(I,J) + P(I1,J)=P(I,J) + 1030 CONTINUE + IF(MSTU(16).NE.2) K(I1,3)=NSAV + DO 1040 IZ=MSTU90+1,MSTU91 + IF(MSTU9T(IZ).EQ.I) THEN + MSTU(90)=MSTU(90)+1 + MSTU(90+MSTU(90))=I1 + PARU(90+MSTU(90))=PARU9T(IZ) + ENDIF + 1040 CONTINUE + 1050 CONTINUE + DO 1080 I=2*N-NSAV,N+1,-1 + IF(K(I,3).EQ.IE(1)) GOTO 1080 + I1=I1+1 + DO 1060 J=1,5 + K(I1,J)=K(I,J) + P(I1,J)=P(I,J) + 1060 CONTINUE + IF(MSTU(16).NE.2) K(I1,3)=NSAV + DO 1070 IZ=MSTU90+1,MSTU91 + IF(MSTU9T(IZ).EQ.I) THEN + MSTU(90)=MSTU(90)+1 + MSTU(90+MSTU(90))=I1 + PARU(90+MSTU(90))=PARU9T(IZ) + ENDIF + 1070 CONTINUE + 1080 CONTINUE + +C...Boost back particle system. Set production vertices. + IF(MBST.EQ.0) THEN + MSTU(33)=1 + CALL LUDBRB(NSAV+1,N,0.D0,0.D0,DPS(1)/DPS(4),DPS(2)/DPS(4), + & DPS(3)/DPS(4)) + ELSE + DO 1090 I=NSAV+1,N + HHPMT=P(I,1)**2+P(I,2)**2+P(I,5)**2 + IF(P(I,3).GT.0.) THEN + HHPEZ=(P(I,4)+P(I,3))*HHBZ + P(I,3)=0.5*(HHPEZ-HHPMT/HHPEZ) + P(I,4)=0.5*(HHPEZ+HHPMT/HHPEZ) + ELSE + HHPEZ=(P(I,4)-P(I,3))/HHBZ + P(I,3)=-0.5*(HHPEZ-HHPMT/HHPEZ) + P(I,4)=0.5*(HHPEZ+HHPMT/HHPEZ) + ENDIF + 1090 CONTINUE + ENDIF + DO 1110 I=NSAV+1,N + DO 1100 J=1,4 + V(I,J)=V(IP,J) + 1100 CONTINUE + 1110 CONTINUE + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUINDF + SUBROUTINE LUINDF(IP) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to handle the fragmentation of a jet system (or a single +C...jet) according to independent fragmentation models. +C IMPLICIT DOUBLE PRECISION(D) + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + DIMENSION DPS(5),PSI(4),NFI(3),NFL(3),IFET(3),KFLF(3), + &KFLO(2),PXO(2),PYO(2),WO(2) + +C...Reset counters. Identify parton system and take copy. Check flavour. + NSAV=N + MSTU90=MSTU(90) + NJET=0 + KQSUM=0 + DO 100 J=1,5 + DPS(J)=0. + 100 CONTINUE + I=IP-1 + 110 I=I+1 + IF(I.GT.MIN(N,MSTU(4)-MSTU(32))) THEN + CALL LUERRM(12,'(LUINDF:) failed to reconstruct jet system') + IF(MSTU(21).GE.1) RETURN + ENDIF + IF(K(I,1).NE.1.AND.K(I,1).NE.2) GOTO 110 + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0) GOTO 110 + KQ=KCHG(KC,2)*ISIGN(1,K(I,2)) + IF(KQ.EQ.0) GOTO 110 + NJET=NJET+1 + IF(KQ.NE.2) KQSUM=KQSUM+KQ + DO 120 J=1,5 + K(NSAV+NJET,J)=K(I,J) + P(NSAV+NJET,J)=P(I,J) + DPS(J)=DPS(J)+P(I,J) + 120 CONTINUE + K(NSAV+NJET,3)=I + IF(K(I,1).EQ.2.OR.(MSTJ(3).LE.5.AND.N.GT.I.AND. + &K(I+1,1).EQ.2)) GOTO 110 + IF(NJET.NE.1.AND.KQSUM.NE.0) THEN + CALL LUERRM(12,'(LUINDF:) unphysical flavour combination') + IF(MSTU(21).GE.1) RETURN + ENDIF + +C...Boost copied system to CM frame. Find CM energy and sum flavours. + IF(NJET.NE.1) THEN + MSTU(33)=1 + CALL LUDBRB(NSAV+1,NSAV+NJET,0.D0,0.D0,-DPS(1)/DPS(4), + & -DPS(2)/DPS(4),-DPS(3)/DPS(4)) + ENDIF + PECM=0. + DO 130 J=1,3 + NFI(J)=0 + 130 CONTINUE + DO 140 I=NSAV+1,NSAV+NJET + PECM=PECM+P(I,4) + KFA=IABS(K(I,2)) + IF(KFA.LE.3) THEN + NFI(KFA)=NFI(KFA)+ISIGN(1,K(I,2)) + ELSEIF(KFA.GT.1000) THEN + KFLA=MOD(KFA/1000,10) + KFLB=MOD(KFA/100,10) + IF(KFLA.LE.3) NFI(KFLA)=NFI(KFLA)+ISIGN(1,K(I,2)) + IF(KFLB.LE.3) NFI(KFLB)=NFI(KFLB)+ISIGN(1,K(I,2)) + ENDIF + 140 CONTINUE + +C...Loop over attempts made. Reset counters. + NTRY=0 + 150 NTRY=NTRY+1 + IF(NTRY.GT.200) THEN + CALL LUERRM(14,'(LUINDF:) caught in infinite loop') + IF(MSTU(21).GE.1) RETURN + ENDIF + N=NSAV+NJET + MSTU(90)=MSTU90 + DO 160 J=1,3 + NFL(J)=NFI(J) + IFET(J)=0 + KFLF(J)=0 + 160 CONTINUE + +C...Loop over jets to be fragmented. + DO 230 IP1=NSAV+1,NSAV+NJET + MSTJ(91)=0 + NSAV1=N + MSTU91=MSTU(90) + +C...Initial flavour and momentum values. Jet along +z axis. + KFLH=IABS(K(IP1,2)) + IF(KFLH.GT.10) KFLH=MOD(KFLH/1000,10) + KFLO(2)=0 + WF=P(IP1,4)+SQRT(P(IP1,1)**2+P(IP1,2)**2+P(IP1,3)**2) + +C...Initial values for quark or diquark jet. + 170 IF(IABS(K(IP1,2)).NE.21) THEN + NSTR=1 + KFLO(1)=K(IP1,2) + CALL LUPTDI(0,PXO(1),PYO(1)) + WO(1)=WF + +C...Initial values for gluon treated like random quark jet. + ELSEIF(MSTJ(2).LE.2) THEN + NSTR=1 + IF(MSTJ(2).EQ.2) MSTJ(91)=1 + KFLO(1)=INT(1.+(2.+PARJ(2))*RLU(0))*(-1)**INT(RLU(0)+0.5) + CALL LUPTDI(0,PXO(1),PYO(1)) + WO(1)=WF + +C...Initial values for gluon treated like quark-antiquark jet pair, +C...sharing energy according to Altarelli-Parisi splitting function. + ELSE + NSTR=2 + IF(MSTJ(2).EQ.4) MSTJ(91)=1 + KFLO(1)=INT(1.+(2.+PARJ(2))*RLU(0))*(-1)**INT(RLU(0)+0.5) + KFLO(2)=-KFLO(1) + CALL LUPTDI(0,PXO(1),PYO(1)) + PXO(2)=-PXO(1) + PYO(2)=-PYO(1) + WO(1)=WF*RLU(0)**(1./3.) + WO(2)=WF-WO(1) + ENDIF + +C...Initial values for rank, flavour, pT and W+. + DO 220 ISTR=1,NSTR + 180 I=N + MSTU(90)=MSTU91 + IRANK=0 + KFL1=KFLO(ISTR) + PX1=PXO(ISTR) + PY1=PYO(ISTR) + W=WO(ISTR) + +C...New hadron. Generate flavour and hadron species. + 190 I=I+1 + IF(I.GE.MSTU(4)-MSTU(32)-NJET-5) THEN + CALL LUERRM(11,'(LUINDF:) no more memory left in LUJETS') + IF(MSTU(21).GE.1) RETURN + ENDIF + IRANK=IRANK+1 + K(I,1)=1 + K(I,3)=IP1 + K(I,4)=0 + K(I,5)=0 + 200 CALL LUKFDI(KFL1,0,KFL2,K(I,2)) + IF(K(I,2).EQ.0) GOTO 180 + IF(MSTJ(12).GE.3.AND.IRANK.EQ.1.AND.IABS(KFL1).LE.10.AND. + &IABS(KFL2).GT.10) THEN + IF(RLU(0).GT.PARJ(19)) GOTO 200 + ENDIF + +C...Find hadron mass. Generate four-momentum. + P(I,5)=ULMASS(K(I,2)) + CALL LUPTDI(KFL1,PX2,PY2) + P(I,1)=PX1+PX2 + P(I,2)=PY1+PY2 + PR=P(I,5)**2+P(I,1)**2+P(I,2)**2 + CALL LUZDIS(KFL1,KFL2,PR,Z) + MZSAV=0 + IF(IABS(KFL1).GE.4.AND.IABS(KFL1).LE.8.AND.MSTU(90).LT.8) THEN + MZSAV=1 + MSTU(90)=MSTU(90)+1 + MSTU(90+MSTU(90))=I + PARU(90+MSTU(90))=Z + ENDIF + P(I,3)=0.5*(Z*W-PR/MAX(1D-4,Z*W)) + P(I,4)=0.5*(Z*W+PR/MAX(1D-4,Z*W)) + IF(MSTJ(3).GE.1.AND.IRANK.EQ.1.AND.KFLH.GE.4.AND. + &P(I,3).LE.0.001) THEN + IF(W.GE.P(I,5)+0.5*PARJ(32)) GOTO 180 + P(I,3)=0.0001 + P(I,4)=SQRT(PR) + Z=P(I,4)/W + ENDIF + +C...Remaining flavour and momentum. + KFL1=-KFL2 + PX1=-PX2 + PY1=-PY2 + W=(1.-Z)*W + DO 210 J=1,5 + V(I,J)=0. + 210 CONTINUE + +C...Check if pL acceptable. Go back for new hadron if enough energy. + IF(MSTJ(3).GE.0.AND.P(I,3).LT.0.) THEN + I=I-1 + IF(MZSAV.EQ.1) MSTU(90)=MSTU(90)-1 + ENDIF + IF(W.GT.PARJ(31)) GOTO 190 + N=I + 220 CONTINUE + IF(MOD(MSTJ(3),5).EQ.4.AND.N.EQ.NSAV1) WF=WF+0.1*PARJ(32) + IF(MOD(MSTJ(3),5).EQ.4.AND.N.EQ.NSAV1) GOTO 170 + +C...Rotate jet to new direction. + THE=ULANGL(P(IP1,3),SQRT(P(IP1,1)**2+P(IP1,2)**2)) + PHI=ULANGL(P(IP1,1),P(IP1,2)) + MSTU(33)=1 + CALL LUDBRB(NSAV1+1,N,THE,PHI,0D0,0D0,0D0) + K(K(IP1,3),4)=NSAV1+1 + K(K(IP1,3),5)=N + +C...End of jet generation loop. Skip conservation in some cases. + 230 CONTINUE + IF(NJET.EQ.1.OR.MSTJ(3).LE.0) GOTO 490 + IF(MOD(MSTJ(3),5).NE.0.AND.N-NSAV-NJET.LT.2) GOTO 150 + +C...Subtract off produced hadron flavours, finished if zero. + DO 240 I=NSAV+NJET+1,N + KFA=IABS(K(I,2)) + KFLA=MOD(KFA/1000,10) + KFLB=MOD(KFA/100,10) + KFLC=MOD(KFA/10,10) + IF(KFLA.EQ.0) THEN + IF(KFLB.LE.3) NFL(KFLB)=NFL(KFLB)-ISIGN(1,K(I,2))*(-1)**KFLB + IF(KFLC.LE.3) NFL(KFLC)=NFL(KFLC)+ISIGN(1,K(I,2))*(-1)**KFLB + ELSE + IF(KFLA.LE.3) NFL(KFLA)=NFL(KFLA)-ISIGN(1,K(I,2)) + IF(KFLB.LE.3) NFL(KFLB)=NFL(KFLB)-ISIGN(1,K(I,2)) + IF(KFLC.LE.3) NFL(KFLC)=NFL(KFLC)-ISIGN(1,K(I,2)) + ENDIF + 240 CONTINUE + NREQ=(IABS(NFL(1))+IABS(NFL(2))+IABS(NFL(3))-IABS(NFL(1)+ + &NFL(2)+NFL(3)))/2+IABS(NFL(1)+NFL(2)+NFL(3))/3 + IF(NREQ.EQ.0) GOTO 320 + +C...Take away flavour of low-momentum particles until enough freedom. + NREM=0 + 250 IREM=0 + P2MIN=PECM**2 + DO 260 I=NSAV+NJET+1,N + P2=P(I,1)**2+P(I,2)**2+P(I,3)**2 + IF(K(I,1).EQ.1.AND.P2.LT.P2MIN) IREM=I + IF(K(I,1).EQ.1.AND.P2.LT.P2MIN) P2MIN=P2 + 260 CONTINUE + IF(IREM.EQ.0) GOTO 150 + K(IREM,1)=7 + KFA=IABS(K(IREM,2)) + KFLA=MOD(KFA/1000,10) + KFLB=MOD(KFA/100,10) + KFLC=MOD(KFA/10,10) + IF(KFLA.GE.4.OR.KFLB.GE.4) K(IREM,1)=8 + IF(K(IREM,1).EQ.8) GOTO 250 + IF(KFLA.EQ.0) THEN + ISGN=ISIGN(1,K(IREM,2))*(-1)**KFLB + IF(KFLB.LE.3) NFL(KFLB)=NFL(KFLB)+ISGN + IF(KFLC.LE.3) NFL(KFLC)=NFL(KFLC)-ISGN + ELSE + IF(KFLA.LE.3) NFL(KFLA)=NFL(KFLA)+ISIGN(1,K(IREM,2)) + IF(KFLB.LE.3) NFL(KFLB)=NFL(KFLB)+ISIGN(1,K(IREM,2)) + IF(KFLC.LE.3) NFL(KFLC)=NFL(KFLC)+ISIGN(1,K(IREM,2)) + ENDIF + NREM=NREM+1 + NREQ=(IABS(NFL(1))+IABS(NFL(2))+IABS(NFL(3))-IABS(NFL(1)+ + &NFL(2)+NFL(3)))/2+IABS(NFL(1)+NFL(2)+NFL(3))/3 + IF(NREQ.GT.NREM) GOTO 250 + DO 270 I=NSAV+NJET+1,N + IF(K(I,1).EQ.8) K(I,1)=1 + 270 CONTINUE + +C...Find combination of existing and new flavours for hadron. + 280 NFET=2 + IF(NFL(1)+NFL(2)+NFL(3).NE.0) NFET=3 + IF(NREQ.LT.NREM) NFET=1 + IF(IABS(NFL(1))+IABS(NFL(2))+IABS(NFL(3)).EQ.0) NFET=0 + DO 290 J=1,NFET + IFET(J)=1+(IABS(NFL(1))+IABS(NFL(2))+IABS(NFL(3)))*RLU(0) + KFLF(J)=ISIGN(1,NFL(1)) + IF(IFET(J).GT.IABS(NFL(1))) KFLF(J)=ISIGN(2,NFL(2)) + IF(IFET(J).GT.IABS(NFL(1))+IABS(NFL(2))) KFLF(J)=ISIGN(3,NFL(3)) + 290 CONTINUE + IF(NFET.EQ.2.AND.(IFET(1).EQ.IFET(2).OR.KFLF(1)*KFLF(2).GT.0)) + &GOTO 280 + IF(NFET.EQ.3.AND.(IFET(1).EQ.IFET(2).OR.IFET(1).EQ.IFET(3).OR. + &IFET(2).EQ.IFET(3).OR.KFLF(1)*KFLF(2).LT.0.OR.KFLF(1)*KFLF(3) + &.LT.0.OR.KFLF(1)*(NFL(1)+NFL(2)+NFL(3)).LT.0)) GOTO 280 + IF(NFET.EQ.0) KFLF(1)=1+INT((2.+PARJ(2))*RLU(0)) + IF(NFET.EQ.0) KFLF(2)=-KFLF(1) + IF(NFET.EQ.1) KFLF(2)=ISIGN(1+INT((2.+PARJ(2))*RLU(0)),-KFLF(1)) + IF(NFET.LE.2) KFLF(3)=0 + IF(KFLF(3).NE.0) THEN + KFLFC=ISIGN(1000*MAX(IABS(KFLF(1)),IABS(KFLF(3)))+ + & 100*MIN(IABS(KFLF(1)),IABS(KFLF(3)))+1,KFLF(1)) + IF(KFLF(1).EQ.KFLF(3).OR.(1.+3.*PARJ(4))*RLU(0).GT.1.) + & KFLFC=KFLFC+ISIGN(2,KFLFC) + ELSE + KFLFC=KFLF(1) + ENDIF + CALL LUKFDI(KFLFC,KFLF(2),KFLDMP,KF) + IF(KF.EQ.0) GOTO 280 + DO 300 J=1,MAX(2,NFET) + NFL(IABS(KFLF(J)))=NFL(IABS(KFLF(J)))-ISIGN(1,KFLF(J)) + 300 CONTINUE + +C...Store hadron at random among free positions. + NPOS=MIN(1+INT(RLU(0)*NREM),NREM) + DO 310 I=NSAV+NJET+1,N + IF(K(I,1).EQ.7) NPOS=NPOS-1 + IF(K(I,1).EQ.1.OR.NPOS.NE.0) GOTO 310 + K(I,1)=1 + K(I,2)=KF + P(I,5)=ULMASS(K(I,2)) + P(I,4)=SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2+P(I,5)**2) + 310 CONTINUE + NREM=NREM-1 + NREQ=(IABS(NFL(1))+IABS(NFL(2))+IABS(NFL(3))-IABS(NFL(1)+ + &NFL(2)+NFL(3)))/2+IABS(NFL(1)+NFL(2)+NFL(3))/3 + IF(NREM.GT.0) GOTO 280 + +C...Compensate for missing momentum in global scheme (3 options). + 320 IF(MOD(MSTJ(3),5).NE.0.AND.MOD(MSTJ(3),5).NE.4) THEN + DO 340 J=1,3 + PSI(J)=0. + DO 330 I=NSAV+NJET+1,N + PSI(J)=PSI(J)+P(I,J) + 330 CONTINUE + 340 CONTINUE + PSI(4)=PSI(1)**2+PSI(2)**2+PSI(3)**2 + PWS=0. + DO 350 I=NSAV+NJET+1,N + IF(MOD(MSTJ(3),5).EQ.1) PWS=PWS+P(I,4) + IF(MOD(MSTJ(3),5).EQ.2) PWS=PWS+SQRT(P(I,5)**2+(PSI(1)*P(I,1)+ + & PSI(2)*P(I,2)+PSI(3)*P(I,3))**2/PSI(4)) + IF(MOD(MSTJ(3),5).EQ.3) PWS=PWS+1. + 350 CONTINUE + DO 370 I=NSAV+NJET+1,N + IF(MOD(MSTJ(3),5).EQ.1) PW=P(I,4) + IF(MOD(MSTJ(3),5).EQ.2) PW=SQRT(P(I,5)**2+(PSI(1)*P(I,1)+ + & PSI(2)*P(I,2)+PSI(3)*P(I,3))**2/PSI(4)) + IF(MOD(MSTJ(3),5).EQ.3) PW=1. + DO 360 J=1,3 + P(I,J)=P(I,J)-PSI(J)*PW/PWS + 360 CONTINUE + P(I,4)=SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2+P(I,5)**2) + 370 CONTINUE + +C...Compensate for missing momentum withing each jet separately. + ELSEIF(MOD(MSTJ(3),5).EQ.4) THEN + DO 390 I=N+1,N+NJET + K(I,1)=0 + DO 380 J=1,5 + P(I,J)=0. + 380 CONTINUE + 390 CONTINUE + DO 410 I=NSAV+NJET+1,N + IR1=K(I,3) + IR2=N+IR1-NSAV + K(IR2,1)=K(IR2,1)+1 + PLS=(P(I,1)*P(IR1,1)+P(I,2)*P(IR1,2)+P(I,3)*P(IR1,3))/ + & (P(IR1,1)**2+P(IR1,2)**2+P(IR1,3)**2) + DO 400 J=1,3 + P(IR2,J)=P(IR2,J)+P(I,J)-PLS*P(IR1,J) + 400 CONTINUE + P(IR2,4)=P(IR2,4)+P(I,4) + P(IR2,5)=P(IR2,5)+PLS + 410 CONTINUE + PSS=0. + DO 420 I=N+1,N+NJET + IF(K(I,1).NE.0) PSS=PSS+P(I,4)/(PECM*(0.8*P(I,5)+0.2)) + 420 CONTINUE + DO 440 I=NSAV+NJET+1,N + IR1=K(I,3) + IR2=N+IR1-NSAV + PLS=(P(I,1)*P(IR1,1)+P(I,2)*P(IR1,2)+P(I,3)*P(IR1,3))/ + & (P(IR1,1)**2+P(IR1,2)**2+P(IR1,3)**2) + DO 430 J=1,3 + P(I,J)=P(I,J)-P(IR2,J)/K(IR2,1)+(1./(P(IR2,5)*PSS)-1.)*PLS* + & P(IR1,J) + 430 CONTINUE + P(I,4)=SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2+P(I,5)**2) + 440 CONTINUE + ENDIF + +C...Scale momenta for energy conservation. + IF(MOD(MSTJ(3),5).NE.0) THEN + PMS=0. + PES=0. + PQS=0. + DO 450 I=NSAV+NJET+1,N + PMS=PMS+P(I,5) + PES=PES+P(I,4) + PQS=PQS+P(I,5)**2/P(I,4) + 450 CONTINUE + IF(PMS.GE.PECM) GOTO 150 + NECO=0 + 460 NECO=NECO+1 + PFAC=(PECM-PQS)/(PES-PQS) + PES=0. + PQS=0. + DO 480 I=NSAV+NJET+1,N + DO 470 J=1,3 + P(I,J)=PFAC*P(I,J) + 470 CONTINUE + P(I,4)=SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2+P(I,5)**2) + PES=PES+P(I,4) + PQS=PQS+P(I,5)**2/P(I,4) + 480 CONTINUE + IF(NECO.LT.10.AND.ABS(PECM-PES).GT.2D-6*PECM) GOTO 460 + ENDIF + +C...Origin of produced particles and parton daughter pointers. + 490 DO 500 I=NSAV+NJET+1,N + IF(MSTU(16).NE.2) K(I,3)=NSAV+1 + IF(MSTU(16).EQ.2) K(I,3)=K(K(I,3),3) + 500 CONTINUE + DO 510 I=NSAV+1,NSAV+NJET + I1=K(I,3) + K(I1,1)=K(I1,1)+10 + IF(MSTU(16).NE.2) THEN + K(I1,4)=NSAV+1 + K(I1,5)=NSAV+1 + ELSE + K(I1,4)=K(I1,4)-NJET+1 + K(I1,5)=K(I1,5)-NJET+1 + IF(K(I1,5).LT.K(I1,4)) THEN + K(I1,4)=0 + K(I1,5)=0 + ENDIF + ENDIF + 510 CONTINUE + +C...Document independent fragmentation system. Remove copy of jets. + NSAV=NSAV+1 + K(NSAV,1)=11 + K(NSAV,2)=93 + K(NSAV,3)=IP + K(NSAV,4)=NSAV+1 + K(NSAV,5)=N-NJET+1 + DO 520 J=1,4 + P(NSAV,J)=DPS(J) + V(NSAV,J)=V(IP,J) + 520 CONTINUE + P(NSAV,5)=SQRT(MAX(0D0,DPS(4)**2-DPS(1)**2-DPS(2)**2-DPS(3)**2)) + V(NSAV,5)=0. + DO 540 I=NSAV+NJET,N + DO 530 J=1,5 + K(I-NJET+1,J)=K(I,J) + P(I-NJET+1,J)=P(I,J) + V(I-NJET+1,J)=V(I,J) + 530 CONTINUE + 540 CONTINUE + N=N-NJET+1 + DO 550 IZ=MSTU90+1,MSTU(90) + MSTU(90+IZ)=MSTU(90+IZ)-NJET+1 + 550 CONTINUE + +C...Boost back particle system. Set production vertices. + IF(NJET.NE.1) CALL LUDBRB(NSAV+1,N,0.D0,0.D0,DPS(1)/DPS(4), + &DPS(2)/DPS(4),DPS(3)/DPS(4)) + DO 570 I=NSAV+1,N + DO 560 J=1,4 + V(I,J)=V(IP,J) + 560 CONTINUE + 570 CONTINUE + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUDECY + SUBROUTINE LUDECY(IP) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to handle the decay of unstable particles. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/,/LUDAT3/ + DIMENSION VDCY(4),KFLO(4),KFL1(4),PV(10,5),RORD(10),UE(3),BE(3), + &WTCOR(10),PTAU(4),PCMTAU(4) +C DOUBLE PRECISION DBETAU(3) + DIMENSION DBETAU(3) + DATA WTCOR/2.,5.,15.,60.,250.,1500.,1.2E4,1.2E5,150.,16./ + +C...Functions: momentum in two-particle decays, four-product and +C...matrix element times phase space in weak decays. + PAWT(A,B,C)=SQRT((A**2-(B+C)**2)*(A**2-(B-C)**2))/(2.*A) + FOUR(I,J)=P(I,4)*P(J,4)-P(I,1)*P(J,1)-P(I,2)*P(J,2)-P(I,3)*P(J,3) + HMEPS(HA)=((1.-HRQ-HA)**2+3.*HA*(1.+HRQ-HA))* + &SQRT((1.-HRQ-HA)**2-4.*HRQ*HA) + +C...Initial values. + NTRY=0 + NSAV=N + KFA=IABS(K(IP,2)) + KFS=ISIGN(1,K(IP,2)) + KC=LUCOMP(KFA) + MSTJ(92)=0 + +C...Choose lifetime and determine decay vertex. + IF(K(IP,1).EQ.5) THEN + V(IP,5)=0. + ELSEIF(K(IP,1).NE.4) THEN + V(IP,5)=-PMAS(KC,4)*LOG(RLU(0)) + ENDIF + DO 100 J=1,4 + VDCY(J)=V(IP,J)+V(IP,5)*P(IP,J)/P(IP,5) + 100 CONTINUE + +C...Determine whether decay allowed or not. + MOUT=0 + IF(MSTJ(22).EQ.2) THEN + IF(PMAS(KC,4).GT.PARJ(71)) MOUT=1 + ELSEIF(MSTJ(22).EQ.3) THEN + IF(VDCY(1)**2+VDCY(2)**2+VDCY(3)**2.GT.PARJ(72)**2) MOUT=1 + ELSEIF(MSTJ(22).EQ.4) THEN + IF(VDCY(1)**2+VDCY(2)**2.GT.PARJ(73)**2) MOUT=1 + IF(ABS(VDCY(3)).GT.PARJ(74)) MOUT=1 + ENDIF + IF(MOUT.EQ.1.AND.K(IP,1).NE.5) THEN + K(IP,1)=4 + RETURN + ENDIF + +C...Interface to external tau decay library (for tau polarization). + IF(KFA.EQ.15.AND.MSTJ(28).GE.1) THEN + +C...Starting values for pointers and momenta. + ITAU=IP + DO 110 J=1,4 + PTAU(J)=P(ITAU,J) + PCMTAU(J)=P(ITAU,J) + 110 CONTINUE + +C...Iterate to find position and code of mother of tau. + IMTAU=ITAU + 120 IMTAU=K(IMTAU,3) + + IF(IMTAU.EQ.0) THEN +C...If no known origin then impossible to do anything further. + KFORIG=0 + IORIG=0 + + ELSEIF(K(IMTAU,2).EQ.K(ITAU,2)) THEN +C...If tau -> tau + gamma then add gamma energy and loop. + IF(K(K(IMTAU,4),2).EQ.22) THEN + DO 130 J=1,4 + PCMTAU(J)=PCMTAU(J)+P(K(IMTAU,4),J) + 130 CONTINUE + ELSEIF(K(K(IMTAU,5),2).EQ.22) THEN + DO 140 J=1,4 + PCMTAU(J)=PCMTAU(J)+P(K(IMTAU,5),J) + 140 CONTINUE + ENDIF + GOTO 120 + + ELSEIF(IABS(K(IMTAU,2)).GT.100) THEN +C...If coming from weak decay of hadron then W is not stored in record, +C...but can be reconstructed by adding neutrino momentum. + KFORIG=-ISIGN(24,K(ITAU,2)) + IORIG=0 + DO 160 II=K(IMTAU,4),K(IMTAU,5) + IF(K(II,2)*ISIGN(1,K(ITAU,2)).EQ.-16) THEN + DO 150 J=1,4 + PCMTAU(J)=PCMTAU(J)+P(II,J) + 150 CONTINUE + ENDIF + 160 CONTINUE + + ELSE +C...If coming from resonance decay then find latest copy of this +C...resonance (may not completely agree). + KFORIG=K(IMTAU,2) + IORIG=IMTAU + DO 170 II=IMTAU+1,IP-1 + IF(K(II,2).EQ.KFORIG.AND.K(II,3).EQ.IORIG.AND. + & ABS(P(II,5)-P(IORIG,5)).LT.1D-5*P(IORIG,5)) IORIG=II + 170 CONTINUE + DO 180 J=1,4 + PCMTAU(J)=P(IORIG,J) + 180 CONTINUE + ENDIF + +C...Boost tau to rest frame of production process (where known) +C...and rotate it to sit along +z axis. + DO 190 J=1,3 + DBETAU(J)=PCMTAU(J)/PCMTAU(4) + 190 CONTINUE + IF(KFORIG.NE.0) CALL LUDBRB(ITAU,ITAU,0.D0,0.D0,-DBETAU(1), + & -DBETAU(2),-DBETAU(3)) + PHITAU=ULANGL(P(ITAU,1),P(ITAU,2)) + CALL LUDBRB(ITAU,ITAU,0.D0,-PHITAU,0D0,0D0,0D0) + THETAU=ULANGL(P(ITAU,3),P(ITAU,1)) + CALL LUDBRB(ITAU,ITAU,-THETAU,0.D0,0D0,0D0,0D0) + +C...Call tau decay routine (if meaningful) and fill extra info. + IF(KFORIG.NE.0.OR.MSTJ(28).EQ.2) THEN + CALL LUTAUD(ITAU,IORIG,KFORIG,NDECAY) + DO 200 II=NSAV+1,NSAV+NDECAY + K(II,1)=1 + K(II,3)=IP + K(II,4)=0 + K(II,5)=0 + 200 CONTINUE + N=NSAV+NDECAY + ENDIF + +C...Boost back decay tau and decay products. + DO 210 J=1,4 + P(ITAU,J)=PTAU(J) + 210 CONTINUE + IF(KFORIG.NE.0.OR.MSTJ(28).EQ.2) THEN + CALL LUDBRB(NSAV+1,N,THETAU,PHITAU,0D0,0D0,0D0) + IF(KFORIG.NE.0) CALL LUDBRB(NSAV+1,N,0.D0,0.D0,DBETAU(1), + & DBETAU(2),DBETAU(3)) + +C...Skip past ordinary tau decay treatment. + MMAT=0 + MBST=0 + ND=0 + GOTO 660 + ENDIF + ENDIF + +C...B-B~ mixing: flip sign of meson appropriately. + MMIX=0 + IF((KFA.EQ.511.OR.KFA.EQ.531).AND.MSTJ(26).GE.1) THEN + XBBMIX=PARJ(76) + IF(KFA.EQ.531) XBBMIX=PARJ(77) + IF(SIN(0.5*XBBMIX*V(IP,5)/PMAS(KC,4))**2.GT.RLU(0)) MMIX=1 + IF(MMIX.EQ.1) KFS=-KFS + ENDIF + +C...Check existence of decay channels. Particle/antiparticle rules. + KCA=KC + IF(MDCY(KC,2).GT.0) THEN + MDMDCY=MDME(MDCY(KC,2),2) + IF(MDMDCY.GT.80.AND.MDMDCY.LE.90) KCA=MDMDCY + ENDIF + IF(MDCY(KCA,2).LE.0.OR.MDCY(KCA,3).LE.0) THEN + CALL LUERRM(9,'(LUDECY:) no decay channel defined') + RETURN + ENDIF + IF(MOD(KFA/1000,10).EQ.0.AND.(KCA.EQ.85.OR.KCA.EQ.87)) KFS=-KFS + IF(KCHG(KC,3).EQ.0) THEN + KFSP=1 + KFSN=0 + IF(RLU(0).GT.0.5) KFS=-KFS + ELSEIF(KFS.GT.0) THEN + KFSP=1 + KFSN=0 + ELSE + KFSP=0 + KFSN=1 + ENDIF + +C...Sum branching ratios of allowed decay channels. + 220 NOPE=0 + BRSU=0. + DO 230 IDL=MDCY(KCA,2),MDCY(KCA,2)+MDCY(KCA,3)-1 + IF(MDME(IDL,1).NE.1.AND.KFSP*MDME(IDL,1).NE.2.AND. + &KFSN*MDME(IDL,1).NE.3) GOTO 230 + IF(MDME(IDL,2).GT.100) GOTO 230 + NOPE=NOPE+1 + BRSU=BRSU+BRAT(IDL) + 230 CONTINUE + IF(NOPE.EQ.0) THEN + CALL LUERRM(2,'(LUDECY:) all decay channels closed by user') + RETURN + ENDIF + +C...Select decay channel among allowed ones. + 240 RBR=BRSU*RLU(0) + IDL=MDCY(KCA,2)-1 + 250 IDL=IDL+1 + IF(MDME(IDL,1).NE.1.AND.KFSP*MDME(IDL,1).NE.2.AND. + &KFSN*MDME(IDL,1).NE.3) THEN + IF(IDL.LT.MDCY(KCA,2)+MDCY(KCA,3)-1) GOTO 250 + ELSEIF(MDME(IDL,2).GT.100) THEN + IF(IDL.LT.MDCY(KCA,2)+MDCY(KCA,3)-1) GOTO 250 + ELSE + IDC=IDL + RBR=RBR-BRAT(IDL) + IF(IDL.LT.MDCY(KCA,2)+MDCY(KCA,3)-1.AND.RBR.GT.0.) GOTO 250 + ENDIF + +C...Start readout of decay channel: matrix element, reset counters. + MMAT=MDME(IDC,2) + 260 NTRY=NTRY+1 + IF(NTRY.GT.1000) THEN + CALL LUERRM(14,'(LUDECY:) caught in infinite loop') + IF(MSTU(21).GE.1) RETURN + ENDIF + I=N + NP=0 + NQ=0 + MBST=0 + IF(MMAT.GE.11.AND.MMAT.NE.46.AND.P(IP,4).GT.20.*P(IP,5)) MBST=1 + DO 270 J=1,4 + PV(1,J)=0. + IF(MBST.EQ.0) PV(1,J)=P(IP,J) + 270 CONTINUE + IF(MBST.EQ.1) PV(1,4)=P(IP,5) + PV(1,5)=P(IP,5) + PS=0. + PSQ=0. + MREM=0 + MHADDY=0 + IF(KFA.GT.80) MHADDY=1 + +C...Read out decay products. Convert to standard flavour code. + JTMAX=5 + IF(MDME(IDC+1,2).EQ.101) JTMAX=10 + DO 280 JT=1,JTMAX + IF(JT.LE.5) KP=KFDP(IDC,JT) + IF(JT.GE.6) KP=KFDP(IDC+1,JT-5) + IF(KP.EQ.0) GOTO 280 + KPA=IABS(KP) + KCP=LUCOMP(KPA) + IF(KPA.GT.80) MHADDY=1 + IF(KCHG(KCP,3).EQ.0.AND.KPA.NE.81.AND.KPA.NE.82) THEN + KFP=KP + ELSEIF(KPA.NE.81.AND.KPA.NE.82) THEN + KFP=KFS*KP + ELSEIF(KPA.EQ.81.AND.MOD(KFA/1000,10).EQ.0) THEN + KFP=-KFS*MOD(KFA/10,10) + ELSEIF(KPA.EQ.81.AND.MOD(KFA/100,10).GE.MOD(KFA/10,10)) THEN + KFP=KFS*(100*MOD(KFA/10,100)+3) + ELSEIF(KPA.EQ.81) THEN + KFP=KFS*(1000*MOD(KFA/10,10)+100*MOD(KFA/100,10)+1) + ELSEIF(KP.EQ.82) THEN + CALL LUKFDI(-KFS*INT(1.+(2.+PARJ(2))*RLU(0)),0,KFP,KDUMP) + IF(KFP.EQ.0) GOTO 260 + MSTJ(93)=1 + IF(PV(1,5).LT.PARJ(32)+2.*ULMASS(KFP)) GOTO 260 + ELSEIF(KP.EQ.-82) THEN + KFP=-KFP + IF(IABS(KFP).GT.10) KFP=KFP+ISIGN(10000,KFP) + ENDIF + IF(KPA.EQ.81.OR.KPA.EQ.82) KCP=LUCOMP(KFP) + +C...Add decay product to event record or to quark flavour list. + KFPA=IABS(KFP) + KQP=KCHG(KCP,2) + IF(MMAT.GE.11.AND.MMAT.LE.30.AND.KQP.NE.0) THEN + NQ=NQ+1 + KFLO(NQ)=KFP + MSTJ(93)=2 + PSQ=PSQ+ULMASS(KFLO(NQ)) + ELSEIF((MMAT.EQ.42.OR.MMAT.EQ.43.OR.MMAT.EQ.48).AND.NP.EQ.3.AND. + &MOD(NQ,2).EQ.1) THEN + NQ=NQ-1 + PS=PS-P(I,5) + K(I,1)=1 + KFI=K(I,2) + CALL LUKFDI(KFP,KFI,KFLDMP,K(I,2)) + IF(K(I,2).EQ.0) GOTO 260 + MSTJ(93)=1 + P(I,5)=ULMASS(K(I,2)) + PS=PS+P(I,5) + ELSE + I=I+1 + NP=NP+1 + IF(MMAT.NE.33.AND.KQP.NE.0) NQ=NQ+1 + IF(MMAT.EQ.33.AND.KQP.NE.0.AND.KQP.NE.2) NQ=NQ+1 + K(I,1)=1+MOD(NQ,2) + IF(MMAT.EQ.4.AND.JT.LE.2.AND.KFP.EQ.21) K(I,1)=2 + IF(MMAT.EQ.4.AND.JT.EQ.3) K(I,1)=1 + K(I,2)=KFP + K(I,3)=IP + K(I,4)=0 + K(I,5)=0 + P(I,5)=ULMASS(KFP) + IF(MMAT.EQ.45.AND.KFPA.EQ.89) P(I,5)=PARJ(32) + PS=PS+P(I,5) + ENDIF + 280 CONTINUE + +C...Check masses for resonance decays. + IF(MHADDY.EQ.0) THEN + IF(PS+PARJ(64).GT.PV(1,5)) GOTO 240 + ENDIF + +C...Choose decay multiplicity in phase space model. + 290 IF(MMAT.GE.11.AND.MMAT.LE.30) THEN + PSP=PS + CNDE=PARJ(61)*LOG(MAX((PV(1,5)-PS-PSQ)/PARJ(62),1.1D0)) + IF(MMAT.EQ.12) CNDE=CNDE+PARJ(63) + 300 NTRY=NTRY+1 + IF(NTRY.GT.1000) THEN + CALL LUERRM(14,'(LUDECY:) caught in infinite loop') + IF(MSTU(21).GE.1) RETURN + ENDIF + IF(MMAT.LE.20) THEN + GAUSS=SQRT(-2.*CNDE*LOG(MAX(1D-10,RLU(0))))* + & SIN(PARU(2)*RLU(0)) + ND=0.5+0.5*NP+0.25*NQ+CNDE+GAUSS + IF(ND.LT.NP+NQ/2.OR.ND.LT.2.OR.ND.GT.10) GOTO 300 + IF(MMAT.EQ.13.AND.ND.EQ.2) GOTO 300 + IF(MMAT.EQ.14.AND.ND.LE.3) GOTO 300 + IF(MMAT.EQ.15.AND.ND.LE.4) GOTO 300 + ELSE + ND=MMAT-20 + ENDIF + +C...Form hadrons from flavour content. + DO 310 JT=1,4 + KFL1(JT)=KFLO(JT) + 310 CONTINUE + IF(ND.EQ.NP+NQ/2) GOTO 330 + DO 320 I=N+NP+1,N+ND-NQ/2 + JT=1+INT((NQ-1)*RLU(0)) + CALL LUKFDI(KFL1(JT),0,KFL2,K(I,2)) + IF(K(I,2).EQ.0) GOTO 300 + KFL1(JT)=-KFL2 + 320 CONTINUE + 330 JT=2 + JT2=3 + JT3=4 + IF(NQ.EQ.4.AND.RLU(0).LT.PARJ(66)) JT=4 + IF(JT.EQ.4.AND.ISIGN(1,KFL1(1)*(10-IABS(KFL1(1))))* + & ISIGN(1,KFL1(JT)*(10-IABS(KFL1(JT)))).GT.0) JT=3 + IF(JT.EQ.3) JT2=2 + IF(JT.EQ.4) JT3=2 + CALL LUKFDI(KFL1(1),KFL1(JT),KFLDMP,K(N+ND-NQ/2+1,2)) + IF(K(N+ND-NQ/2+1,2).EQ.0) GOTO 300 + IF(NQ.EQ.4) CALL LUKFDI(KFL1(JT2),KFL1(JT3),KFLDMP,K(N+ND,2)) + IF(NQ.EQ.4.AND.K(N+ND,2).EQ.0) GOTO 300 + +C...Check that sum of decay product masses not too large. + PS=PSP + DO 340 I=N+NP+1,N+ND + K(I,1)=1 + K(I,3)=IP + K(I,4)=0 + K(I,5)=0 + P(I,5)=ULMASS(K(I,2)) + PS=PS+P(I,5) + 340 CONTINUE + IF(PS+PARJ(64).GT.PV(1,5)) GOTO 300 + +C...Rescale energy to subtract off spectator quark mass. + ELSEIF((MMAT.EQ.31.OR.MMAT.EQ.33.OR.MMAT.EQ.44.OR.MMAT.EQ.45) + &.AND.NP.GE.3) THEN + PS=PS-P(N+NP,5) + PQT=(P(N+NP,5)+PARJ(65))/PV(1,5) + DO 350 J=1,5 + P(N+NP,J)=PQT*PV(1,J) + PV(1,J)=(1.-PQT)*PV(1,J) + 350 CONTINUE + IF(PS+PARJ(64).GT.PV(1,5)) GOTO 260 + ND=NP-1 + MREM=1 + +C...Phase space factors imposed in W decay. + ELSEIF(MMAT.EQ.46) THEN + MSTJ(93)=1 + PSMC=ULMASS(K(N+1,2)) + MSTJ(93)=1 + PSMC=PSMC+ULMASS(K(N+2,2)) + IF(MAX(PS,PSMC)+PARJ(32).GT.PV(1,5)) GOTO 240 + HR1=(P(N+1,5)/PV(1,5))**2 + HR2=(P(N+2,5)/PV(1,5))**2 + IF((1.-HR1-HR2)*(2.+HR1+HR2)*SQRT((1.-HR1-HR2)**2-4.*HR1*HR2) + & .LT.2.*RLU(0)) GOTO 240 + ND=NP + +C...Fully specified final state: check mass broadening effects. + ELSE + IF(NP.GE.2.AND.PS+PARJ(64).GT.PV(1,5)) GOTO 260 + ND=NP + ENDIF + +C...Select W mass in decay Q -> W + q, without W propagator. + IF(MMAT.EQ.45.AND.MSTJ(25).LE.0) THEN + HLQ=(PARJ(32)/PV(1,5))**2 + HUQ=(1.-(P(N+2,5)+PARJ(64))/PV(1,5))**2 + HRQ=(P(N+2,5)/PV(1,5))**2 + 360 HW=HLQ+RLU(0)*(HUQ-HLQ) + IF(HMEPS(HW).LT.RLU(0)) GOTO 360 + P(N+1,5)=PV(1,5)*SQRT(HW) + +C...Ditto, including W propagator. Divide mass range into three regions. + ELSEIF(MMAT.EQ.45) THEN + HQW=(PV(1,5)/PMAS(24,1))**2 + HLW=(PARJ(32)/PMAS(24,1))**2 + HUW=((PV(1,5)-P(N+2,5)-PARJ(64))/PMAS(24,1))**2 + HRQ=(P(N+2,5)/PV(1,5))**2 + HG=PMAS(24,2)/PMAS(24,1) + HATL=ATAN((HLW-1.)/HG) + HM=MIN(1.D0,HUW-0.001) + HMV1=HMEPS(HM/HQW)/((HM-1.)**2+HG**2) + 370 HM=HM-HG + HMV2=HMEPS(HM/HQW)/((HM-1.)**2+HG**2) + IF(HMV2.GT.HMV1.AND.HM-HG.GT.HLW) THEN + HMV1=HMV2 + GOTO 370 + ENDIF + HMV=MIN(2.*HMV1,HMEPS(HM/HQW)/HG**2) + HM1=1.-SQRT(1./HMV-HG**2) + IF(HM1.GT.HLW.AND.HM1.LT.HM) THEN + HM=HM1 + ELSEIF(HMV2.LE.HMV1) THEN + HM=MAX(HLW,HM-MIN(0.1D0,1.-HM)) + ENDIF + HATM=ATAN((HM-1.)/HG) + HWT1=(HATM-HATL)/HG + HWT2=HMV*(MIN(1.D0,HUW)-HM) + HWT3=0. + IF(HUW.GT.1.) THEN + HATU=ATAN((HUW-1.)/HG) + HMP1=HMEPS(1./HQW) + HWT3=HMP1*HATU/HG + ENDIF + +C...Select mass region and W mass there. Accept according to weight. + 380 HREG=RLU(0)*(HWT1+HWT2+HWT3) + IF(HREG.LE.HWT1) THEN + HW=1.+HG*TAN(HATL+RLU(0)*(HATM-HATL)) + HACC=HMEPS(HW/HQW) + ELSEIF(HREG.LE.HWT1+HWT2) THEN + HW=HM+RLU(0)*(MIN(1.D0,HUW)-HM) + HACC=HMEPS(HW/HQW)/((HW-1.)**2+HG**2)/HMV + ELSE + HW=1.+HG*TAN(RLU(0)*HATU) + HACC=HMEPS(HW/HQW)/HMP1 + ENDIF + IF(HACC.LT.RLU(0)) GOTO 380 + P(N+1,5)=PMAS(24,1)*SQRT(HW) + ENDIF + +C...Determine position of grandmother, number of sisters, Q -> W sign. + NM=0 + KFAS=0 + MSGN=0 + IF(MMAT.EQ.3.OR.MMAT.EQ.46) THEN + IM=K(IP,3) + IF(IM.LT.0.OR.IM.GE.IP) IM=0 + IF(MMAT.EQ.46.AND.MSTJ(27).EQ.1) THEN + IM=0 + ELSEIF(MMAT.EQ.46.AND.MSTJ(27).GE.2.AND.IM.NE.0) THEN + IF(K(IM,2).EQ.94) THEN + IM=K(K(IM,3),3) + IF(IM.LT.0.OR.IM.GE.IP) IM=0 + ENDIF + ENDIF + IF(IM.NE.0) KFAM=IABS(K(IM,2)) + IF(IM.NE.0.AND.MMAT.EQ.3) THEN + DO 390 IL=MAX(IP-2,IM+1),MIN(IP+2,N) + IF(K(IL,3).EQ.IM) NM=NM+1 + IF(K(IL,3).EQ.IM.AND.IL.NE.IP) ISIS=IL + 390 CONTINUE + IF(NM.NE.2.OR.KFAM.LE.100.OR.MOD(KFAM,10).NE.1.OR. + & MOD(KFAM/1000,10).NE.0) NM=0 + IF(NM.EQ.2) THEN + KFAS=IABS(K(ISIS,2)) + IF((KFAS.LE.100.OR.MOD(KFAS,10).NE.1.OR. + & MOD(KFAS/1000,10).NE.0).AND.KFAS.NE.22) NM=0 + ENDIF + ELSEIF(IM.NE.0.AND.MMAT.EQ.46) THEN + MSGN=ISIGN(1,K(IM,2)*K(IP,2)) + IF(KFAM.GT.100.AND.MOD(KFAM/1000,10).EQ.0) MSGN= + & MSGN*(-1)**MOD(KFAM/100,10) + ENDIF + ENDIF + +C...Kinematics of one-particle decays. + IF(ND.EQ.1) THEN + DO 400 J=1,4 + P(N+1,J)=P(IP,J) + 400 CONTINUE + GOTO 660 + ENDIF + +C...Calculate maximum weight ND-particle decay. + PV(ND,5)=P(N+ND,5) + IF(ND.GE.3) THEN + WTMAX=1./WTCOR(ND-2) + PMAX=PV(1,5)-PS+P(N+ND,5) + PMIN=0. + DO 410 IL=ND-1,1,-1 + PMAX=PMAX+P(N+IL,5) + PMIN=PMIN+P(N+IL+1,5) + WTMAX=WTMAX*PAWT(PMAX,PMIN,P(N+IL,5)) + 410 CONTINUE + ENDIF + +C...Find virtual gamma mass in Dalitz decay. + 420 IF(ND.EQ.2) THEN + ELSEIF(MMAT.EQ.2) THEN + PMES=4.*PMAS(11,1)**2 + PMRHO2=PMAS(131,1)**2 + PGRHO2=PMAS(131,2)**2 + 430 PMST=PMES*(P(IP,5)**2/PMES)**RLU(0) + WT=(1+0.5*PMES/PMST)*SQRT(MAX(0.D0,1.-PMES/PMST))* + & (1.-PMST/P(IP,5)**2)**3*(1.+PGRHO2/PMRHO2)/ + & ((1.-PMST/PMRHO2)**2+PGRHO2/PMRHO2) + IF(WT.LT.RLU(0)) GOTO 430 + PV(2,5)=MAX(2.00001*PMAS(11,1),SQRT(PMST)) + +C...M-generator gives weight. If rejected, try again. + ELSE + 440 RORD(1)=1. + DO 470 IL1=2,ND-1 + RSAV=RLU(0) + DO 450 IL2=IL1-1,1,-1 + IF(RSAV.LE.RORD(IL2)) GOTO 460 + RORD(IL2+1)=RORD(IL2) + 450 CONTINUE + 460 RORD(IL2+1)=RSAV + 470 CONTINUE + RORD(ND)=0. + WT=1. + DO 480 IL=ND-1,1,-1 + PV(IL,5)=PV(IL+1,5)+P(N+IL,5)+(RORD(IL)-RORD(IL+1))*(PV(1,5)-PS) + WT=WT*PAWT(PV(IL,5),PV(IL+1,5),P(N+IL,5)) + 480 CONTINUE + IF(WT.LT.RLU(0)*WTMAX) GOTO 440 + ENDIF + +C...Perform two-particle decays in respective CM frame. + 490 DO 510 IL=1,ND-1 + PA=PAWT(PV(IL,5),PV(IL+1,5),P(N+IL,5)) + UE(3)=2.*RLU(0)-1. + PHI=PARU(2)*RLU(0) + UE(1)=SQRT(1.-UE(3)**2)*COS(PHI) + UE(2)=SQRT(1.-UE(3)**2)*SIN(PHI) + DO 500 J=1,3 + P(N+IL,J)=PA*UE(J) + PV(IL+1,J)=-PA*UE(J) + 500 CONTINUE + P(N+IL,4)=SQRT(PA**2+P(N+IL,5)**2) + PV(IL+1,4)=SQRT(PA**2+PV(IL+1,5)**2) + 510 CONTINUE + +C...Lorentz transform decay products to lab frame. + DO 520 J=1,4 + P(N+ND,J)=PV(ND,J) + 520 CONTINUE + DO 560 IL=ND-1,1,-1 + DO 530 J=1,3 + BE(J)=PV(IL,J)/PV(IL,4) + 530 CONTINUE + GA=PV(IL,4)/PV(IL,5) + DO 550 I=N+IL,N+ND + BEP=BE(1)*P(I,1)+BE(2)*P(I,2)+BE(3)*P(I,3) + DO 540 J=1,3 + P(I,J)=P(I,J)+GA*(GA*BEP/(1.+GA)+P(I,4))*BE(J) + 540 CONTINUE + P(I,4)=GA*(P(I,4)+BEP) + 550 CONTINUE + 560 CONTINUE + +C...Check that no infinite loop in matrix element weight. + NTRY=NTRY+1 + IF(NTRY.GT.800) GOTO 590 + +C...Matrix elements for omega and phi decays. + IF(MMAT.EQ.1) THEN + WT=(P(N+1,5)*P(N+2,5)*P(N+3,5))**2-(P(N+1,5)*FOUR(N+2,N+3))**2 + & -(P(N+2,5)*FOUR(N+1,N+3))**2-(P(N+3,5)*FOUR(N+1,N+2))**2 + & +2.*FOUR(N+1,N+2)*FOUR(N+1,N+3)*FOUR(N+2,N+3) + IF(MAX(WT*WTCOR(9)/P(IP,5)**6,0.001D0).LT.RLU(0)) GOTO 420 + +C...Matrix elements for pi0 or eta Dalitz decay to gamma e+ e-. + ELSEIF(MMAT.EQ.2) THEN + FOUR12=FOUR(N+1,N+2) + FOUR13=FOUR(N+1,N+3) + WT=(PMST-0.5*PMES)*(FOUR12**2+FOUR13**2)+ + & PMES*(FOUR12*FOUR13+FOUR12**2+FOUR13**2) + IF(WT.LT.RLU(0)*0.25*PMST*(P(IP,5)**2-PMST)**2) GOTO 490 + +C...Matrix element for S0 -> S1 + V1 -> S1 + S2 + S3 (S scalar, +C...V vector), of form cos**2(theta02) in V1 rest frame, and for +C...S0 -> gamma + V1 -> gamma + S2 + S3, of form sin**2(theta02). + ELSEIF(MMAT.EQ.3.AND.NM.EQ.2) THEN + FOUR10=FOUR(IP,IM) + FOUR12=FOUR(IP,N+1) + FOUR02=FOUR(IM,N+1) + PMS1=P(IP,5)**2 + PMS0=P(IM,5)**2 + PMS2=P(N+1,5)**2 + IF(KFAS.NE.22) HNUM=(FOUR10*FOUR12-PMS1*FOUR02)**2 + IF(KFAS.EQ.22) HNUM=PMS1*(2.*FOUR10*FOUR12*FOUR02- + & PMS1*FOUR02**2-PMS0*FOUR12**2-PMS2*FOUR10**2+PMS1*PMS0*PMS2) + HNUM=MAX(1D-6*PMS1**2*PMS0*PMS2,HNUM) + HDEN=(FOUR10**2-PMS1*PMS0)*(FOUR12**2-PMS1*PMS2) + IF(HNUM.LT.RLU(0)*HDEN) GOTO 490 + +C...Matrix element for "onium" -> g + g + g or gamma + g + g. + ELSEIF(MMAT.EQ.4) THEN + HX1=2.*FOUR(IP,N+1)/P(IP,5)**2 + HX2=2.*FOUR(IP,N+2)/P(IP,5)**2 + HX3=2.*FOUR(IP,N+3)/P(IP,5)**2 + WT=((1.-HX1)/(HX2*HX3))**2+((1.-HX2)/(HX1*HX3))**2+ + & ((1.-HX3)/(HX1*HX2))**2 + IF(WT.LT.2.*RLU(0)) GOTO 420 + IF(K(IP+1,2).EQ.22.AND.(1.-HX1)*P(IP,5)**2.LT.4.*PARJ(32)**2) + & GOTO 420 + +C...Effective matrix element for nu spectrum in tau -> nu + hadrons. + ELSEIF(MMAT.EQ.41) THEN + HX1=2.*FOUR(IP,N+1)/P(IP,5)**2 + HXM=MIN(0.75D0,2.*(1.-PS/P(IP,5))) + IF(HX1*(3.-2.*HX1).LT.RLU(0)*HXM*(3.-2.*HXM)) GOTO 420 + +C...Matrix elements for weak decays (only semileptonic for c and b) + ELSEIF((MMAT.EQ.42.OR.MMAT.EQ.43.OR.MMAT.EQ.44.OR.MMAT.EQ.48) + &.AND.ND.EQ.3) THEN + IF(MBST.EQ.0) WT=FOUR(IP,N+1)*FOUR(N+2,N+3) + IF(MBST.EQ.1) WT=P(IP,5)*P(N+1,4)*FOUR(N+2,N+3) + IF(WT.LT.RLU(0)*P(IP,5)*PV(1,5)**3/WTCOR(10)) GOTO 420 + ELSEIF(MMAT.EQ.42.OR.MMAT.EQ.43.OR.MMAT.EQ.44.OR.MMAT.EQ.48) THEN + DO 580 J=1,4 + P(N+NP+1,J)=0. + DO 570 IS=N+3,N+NP + P(N+NP+1,J)=P(N+NP+1,J)+P(IS,J) + 570 CONTINUE + 580 CONTINUE + IF(MBST.EQ.0) WT=FOUR(IP,N+1)*FOUR(N+2,N+NP+1) + IF(MBST.EQ.1) WT=P(IP,5)*P(N+1,4)*FOUR(N+2,N+NP+1) + IF(WT.LT.RLU(0)*P(IP,5)*PV(1,5)**3/WTCOR(10)) GOTO 420 + +C...Angular distribution in W decay. + ELSEIF(MMAT.EQ.46.AND.MSGN.NE.0) THEN + IF(MSGN.GT.0) WT=FOUR(IM,N+1)*FOUR(N+2,IP+1) + IF(MSGN.LT.0) WT=FOUR(IM,N+2)*FOUR(N+1,IP+1) + IF(WT.LT.RLU(0)*P(IM,5)**4/WTCOR(10)) GOTO 490 + ENDIF + +C...Scale back energy and reattach spectator. + 590 IF(MREM.EQ.1) THEN + DO 600 J=1,5 + PV(1,J)=PV(1,J)/(1.-PQT) + 600 CONTINUE + ND=ND+1 + MREM=0 + ENDIF + +C...Low invariant mass for system with spectator quark gives particle, +C...not two jets. Readjust momenta accordingly. + IF((MMAT.EQ.31.OR.MMAT.EQ.45).AND.ND.EQ.3) THEN + MSTJ(93)=1 + PM2=ULMASS(K(N+2,2)) + MSTJ(93)=1 + PM3=ULMASS(K(N+3,2)) + IF(P(N+2,5)**2+P(N+3,5)**2+2.*FOUR(N+2,N+3).GE. + & (PARJ(32)+PM2+PM3)**2) GOTO 660 + K(N+2,1)=1 + KFTEMP=K(N+2,2) + CALL LUKFDI(KFTEMP,K(N+3,2),KFLDMP,K(N+2,2)) + IF(K(N+2,2).EQ.0) GOTO 260 + P(N+2,5)=ULMASS(K(N+2,2)) + PS=P(N+1,5)+P(N+2,5) + PV(2,5)=P(N+2,5) + MMAT=0 + ND=2 + GOTO 490 + ELSEIF(MMAT.EQ.44) THEN + MSTJ(93)=1 + PM3=ULMASS(K(N+3,2)) + MSTJ(93)=1 + PM4=ULMASS(K(N+4,2)) + IF(P(N+3,5)**2+P(N+4,5)**2+2.*FOUR(N+3,N+4).GE. + & (PARJ(32)+PM3+PM4)**2) GOTO 630 + K(N+3,1)=1 + KFTEMP=K(N+3,2) + CALL LUKFDI(KFTEMP,K(N+4,2),KFLDMP,K(N+3,2)) + IF(K(N+3,2).EQ.0) GOTO 260 + P(N+3,5)=ULMASS(K(N+3,2)) + DO 610 J=1,3 + P(N+3,J)=P(N+3,J)+P(N+4,J) + 610 CONTINUE + P(N+3,4)=SQRT(P(N+3,1)**2+P(N+3,2)**2+P(N+3,3)**2+P(N+3,5)**2) + HA=P(N+1,4)**2-P(N+2,4)**2 + HB=HA-(P(N+1,5)**2-P(N+2,5)**2) + HC=(P(N+1,1)-P(N+2,1))**2+(P(N+1,2)-P(N+2,2))**2+ + & (P(N+1,3)-P(N+2,3))**2 + HD=(PV(1,4)-P(N+3,4))**2 + HE=HA**2-2.*HD*(P(N+1,4)**2+P(N+2,4)**2)+HD**2 + HF=HD*HC-HB**2 + HG=HD*HC-HA*HB + HH=(SQRT(HG**2+HE*HF)-HG)/(2.*HF) + DO 620 J=1,3 + PCOR=HH*(P(N+1,J)-P(N+2,J)) + P(N+1,J)=P(N+1,J)+PCOR + P(N+2,J)=P(N+2,J)-PCOR + 620 CONTINUE + P(N+1,4)=SQRT(P(N+1,1)**2+P(N+1,2)**2+P(N+1,3)**2+P(N+1,5)**2) + P(N+2,4)=SQRT(P(N+2,1)**2+P(N+2,2)**2+P(N+2,3)**2+P(N+2,5)**2) + ND=ND-1 + ENDIF + +C...Check invariant mass of W jets. May give one particle or start over. + 630 IF((MMAT.EQ.42.OR.MMAT.EQ.43.OR.MMAT.EQ.44.OR.MMAT.EQ.48) + &.AND.IABS(K(N+1,2)).LT.10) THEN + PMR=SQRT(MAX(0.D0,P(N+1,5)**2+P(N+2,5)**2+2.*FOUR(N+1,N+2))) + MSTJ(93)=1 + PM1=ULMASS(K(N+1,2)) + MSTJ(93)=1 + PM2=ULMASS(K(N+2,2)) + IF(PMR.GT.PARJ(32)+PM1+PM2) GOTO 640 + KFLDUM=INT(1.5+RLU(0)) + CALL LUKFDI(K(N+1,2),-ISIGN(KFLDUM,K(N+1,2)),KFLDMP,KF1) + CALL LUKFDI(K(N+2,2),-ISIGN(KFLDUM,K(N+2,2)),KFLDMP,KF2) + IF(KF1.EQ.0.OR.KF2.EQ.0) GOTO 260 + PSM=ULMASS(KF1)+ULMASS(KF2) + IF((MMAT.EQ.42.OR.MMAT.EQ.48).AND.PMR.GT.PARJ(64)+PSM) GOTO 640 + IF(MMAT.GE.43.AND.PMR.GT.0.2*PARJ(32)+PSM) GOTO 640 + IF(MMAT.EQ.48) GOTO 420 + IF(ND.EQ.4.OR.KFA.EQ.15) GOTO 260 + K(N+1,1)=1 + KFTEMP=K(N+1,2) + CALL LUKFDI(KFTEMP,K(N+2,2),KFLDMP,K(N+1,2)) + IF(K(N+1,2).EQ.0) GOTO 260 + P(N+1,5)=ULMASS(K(N+1,2)) + K(N+2,2)=K(N+3,2) + P(N+2,5)=P(N+3,5) + PS=P(N+1,5)+P(N+2,5) + IF(PS+PARJ(64).GT.PV(1,5)) GOTO 260 + PV(2,5)=P(N+3,5) + MMAT=0 + ND=2 + GOTO 490 + ENDIF + +C...Phase space decay of partons from W decay. + 640 IF((MMAT.EQ.42.OR.MMAT.EQ.48).AND.IABS(K(N+1,2)).LT.10) THEN + KFLO(1)=K(N+1,2) + KFLO(2)=K(N+2,2) + K(N+1,1)=K(N+3,1) + K(N+1,2)=K(N+3,2) + DO 650 J=1,5 + PV(1,J)=P(N+1,J)+P(N+2,J) + P(N+1,J)=P(N+3,J) + 650 CONTINUE + PV(1,5)=PMR + N=N+1 + NP=0 + NQ=2 + PS=0. + MSTJ(93)=2 + PSQ=ULMASS(KFLO(1)) + MSTJ(93)=2 + PSQ=PSQ+ULMASS(KFLO(2)) + MMAT=11 + GOTO 290 + ENDIF + +C...Boost back for rapidly moving particle. + 660 N=N+ND + IF(MBST.EQ.1) THEN + DO 670 J=1,3 + BE(J)=P(IP,J)/P(IP,4) + 670 CONTINUE + GA=P(IP,4)/P(IP,5) + DO 690 I=NSAV+1,N + BEP=BE(1)*P(I,1)+BE(2)*P(I,2)+BE(3)*P(I,3) + DO 680 J=1,3 + P(I,J)=P(I,J)+GA*(GA*BEP/(1.+GA)+P(I,4))*BE(J) + 680 CONTINUE + P(I,4)=GA*(P(I,4)+BEP) + 690 CONTINUE + ENDIF + +C...Fill in position of decay vertex. + DO 710 I=NSAV+1,N + DO 700 J=1,4 + V(I,J)=VDCY(J) + 700 CONTINUE + V(I,5)=0. + 710 CONTINUE + +C...Set up for parton shower evolution from jets. + IF(MSTJ(23).GE.1.AND.MMAT.EQ.4.AND.K(NSAV+1,2).EQ.21) THEN + K(NSAV+1,1)=3 + K(NSAV+2,1)=3 + K(NSAV+3,1)=3 + K(NSAV+1,4)=MSTU(5)*(NSAV+2) + K(NSAV+1,5)=MSTU(5)*(NSAV+3) + K(NSAV+2,4)=MSTU(5)*(NSAV+3) + K(NSAV+2,5)=MSTU(5)*(NSAV+1) + K(NSAV+3,4)=MSTU(5)*(NSAV+1) + K(NSAV+3,5)=MSTU(5)*(NSAV+2) + MSTJ(92)=-(NSAV+1) + ELSEIF(MSTJ(23).GE.1.AND.MMAT.EQ.4) THEN + K(NSAV+2,1)=3 + K(NSAV+3,1)=3 + K(NSAV+2,4)=MSTU(5)*(NSAV+3) + K(NSAV+2,5)=MSTU(5)*(NSAV+3) + K(NSAV+3,4)=MSTU(5)*(NSAV+2) + K(NSAV+3,5)=MSTU(5)*(NSAV+2) + MSTJ(92)=NSAV+2 + ELSEIF(MSTJ(23).GE.1.AND.(MMAT.EQ.32.OR.MMAT.EQ.44.OR.MMAT.EQ.46) + &.AND.IABS(K(NSAV+1,2)).LE.10.AND.IABS(K(NSAV+2,2)).LE.10) THEN + K(NSAV+1,1)=3 + K(NSAV+2,1)=3 + K(NSAV+1,4)=MSTU(5)*(NSAV+2) + K(NSAV+1,5)=MSTU(5)*(NSAV+2) + K(NSAV+2,4)=MSTU(5)*(NSAV+1) + K(NSAV+2,5)=MSTU(5)*(NSAV+1) + MSTJ(92)=NSAV+1 + ELSEIF(MSTJ(23).GE.1.AND.(MMAT.EQ.32.OR.MMAT.EQ.44.OR.MMAT.EQ.46) + &.AND.IABS(K(NSAV+1,2)).LE.20.AND.IABS(K(NSAV+2,2)).LE.20) THEN + MSTJ(92)=NSAV+1 + ELSEIF(MSTJ(23).GE.1.AND.MMAT.EQ.33.AND.IABS(K(NSAV+2,2)).EQ.21) + &THEN + K(NSAV+1,1)=3 + K(NSAV+2,1)=3 + K(NSAV+3,1)=3 + KCP=LUCOMP(K(NSAV+1,2)) + KQP=KCHG(KCP,2)*ISIGN(1,K(NSAV+1,2)) + JCON=4 + IF(KQP.LT.0) JCON=5 + K(NSAV+1,JCON)=MSTU(5)*(NSAV+2) + K(NSAV+2,9-JCON)=MSTU(5)*(NSAV+1) + K(NSAV+2,JCON)=MSTU(5)*(NSAV+3) + K(NSAV+3,9-JCON)=MSTU(5)*(NSAV+2) + MSTJ(92)=NSAV+1 + ELSEIF(MSTJ(23).GE.1.AND.MMAT.EQ.33) THEN + K(NSAV+1,1)=3 + K(NSAV+3,1)=3 + K(NSAV+1,4)=MSTU(5)*(NSAV+3) + K(NSAV+1,5)=MSTU(5)*(NSAV+3) + K(NSAV+3,4)=MSTU(5)*(NSAV+1) + K(NSAV+3,5)=MSTU(5)*(NSAV+1) + MSTJ(92)=NSAV+1 + +C...Set up for parton shower evolution in t -> W + b. + ELSEIF(MSTJ(27).GE.1.AND.MMAT.EQ.45.AND.ND.EQ.3) THEN + K(NSAV+2,1)=3 + K(NSAV+3,1)=3 + K(NSAV+2,4)=MSTU(5)*(NSAV+3) + K(NSAV+2,5)=MSTU(5)*(NSAV+3) + K(NSAV+3,4)=MSTU(5)*(NSAV+2) + K(NSAV+3,5)=MSTU(5)*(NSAV+2) + MSTJ(92)=NSAV+1 + ENDIF + +C...Mark decayed particle; special option for B-B~ mixing. + IF(K(IP,1).EQ.5) K(IP,1)=15 + IF(K(IP,1).LE.10) K(IP,1)=11 + IF(MMIX.EQ.1.AND.MSTJ(26).EQ.2.AND.K(IP,1).EQ.11) K(IP,1)=12 + K(IP,4)=NSAV+1 + K(IP,5)=N + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUKFDI + SUBROUTINE LUKFDI(KFL1,KFL2,KFL3,KF) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to generate a new flavour pair and combine off a hadron. + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUDAT1/,/LUDAT2/ + +C...Default flavour values. Input consistency checks. + KF1A=IABS(KFL1) + KF2A=IABS(KFL2) + KFL3=0 + KF=0 + IF(KF1A.EQ.0) RETURN + IF(KF2A.NE.0) THEN + IF(KF1A.LE.10.AND.KF2A.LE.10.AND.KFL1*KFL2.GT.0) RETURN + IF(KF1A.GT.10.AND.KF2A.GT.10) RETURN + IF((KF1A.GT.10.OR.KF2A.GT.10).AND.KFL1*KFL2.LT.0) RETURN + ENDIF + +C...Check if tabulated flavour probabilities are to be used. + IF(MSTJ(15).EQ.1) THEN + KTAB1=-1 + IF(KF1A.GE.1.AND.KF1A.LE.6) KTAB1=KF1A + KFL1A=MOD(KF1A/1000,10) + KFL1B=MOD(KF1A/100,10) + KFL1S=MOD(KF1A,10) + IF(KFL1A.GE.1.AND.KFL1A.LE.4.AND.KFL1B.GE.1.AND.KFL1B.LE.4) + & KTAB1=6+KFL1A*(KFL1A-2)+2*KFL1B+(KFL1S-1)/2 + IF(KFL1A.GE.1.AND.KFL1A.LE.4.AND.KFL1A.EQ.KFL1B) KTAB1=KTAB1-1 + IF(KF1A.GE.1.AND.KF1A.LE.6) KFL1A=KF1A + KTAB2=0 + IF(KF2A.NE.0) THEN + KTAB2=-1 + IF(KF2A.GE.1.AND.KF2A.LE.6) KTAB2=KF2A + KFL2A=MOD(KF2A/1000,10) + KFL2B=MOD(KF2A/100,10) + KFL2S=MOD(KF2A,10) + IF(KFL2A.GE.1.AND.KFL2A.LE.4.AND.KFL2B.GE.1.AND.KFL2B.LE.4) + & KTAB2=6+KFL2A*(KFL2A-2)+2*KFL2B+(KFL2S-1)/2 + IF(KFL2A.GE.1.AND.KFL2A.LE.4.AND.KFL2A.EQ.KFL2B) KTAB2=KTAB2-1 + ENDIF + IF(KTAB1.GE.0.AND.KTAB2.GE.0) GOTO 150 + ENDIF + +C...Parameters and breaking diquark parameter combinations. + 100 PAR2=PARJ(2) + PAR3=PARJ(3) + PAR4=3.*PARJ(4) + IF(MSTJ(12).GE.2) THEN + PAR3M=SQRT(PARJ(3)) + PAR4M=1./(3.*SQRT(PARJ(4))) + PARDM=PARJ(7)/(PARJ(7)+PAR3M*PARJ(6)) + PARS0=PARJ(5)*(2.+(1.+PAR2*PAR3M*PARJ(7))*(1.+PAR4M)) + PARS1=PARJ(7)*PARS0/(2.*PAR3M)+PARJ(5)*(PARJ(6)*(1.+PAR4M)+ + & PAR2*PAR3M*PARJ(6)*PARJ(7)) + PARS2=PARJ(5)*2.*PARJ(6)*PARJ(7)*(PAR2*PARJ(7)+(1.+PAR4M)/PAR3M) + PARSM=MAX(PARS0,PARS1,PARS2) + PAR4=PAR4*(1.+PARSM)/(1.+PARSM/(3.*PAR4M)) + ENDIF + +C...Choice of whether to generate meson or baryon. + 110 MBARY=0 + KFDA=0 + IF(KF1A.LE.10) THEN + IF(KF2A.EQ.0.AND.MSTJ(12).GE.1.AND.(1.+PARJ(1))*RLU(0).GT.1.) + & MBARY=1 + IF(KF2A.GT.10) MBARY=2 + IF(KF2A.GT.10.AND.KF2A.LE.10000) KFDA=KF2A + ELSE + MBARY=2 + IF(KF1A.LE.10000) KFDA=KF1A + ENDIF + +C...Possibility of process diquark -> meson + new diquark. + IF(KFDA.NE.0.AND.MSTJ(12).GE.2) THEN + KFLDA=MOD(KFDA/1000,10) + KFLDB=MOD(KFDA/100,10) + KFLDS=MOD(KFDA,10) + WTDQ=PARS0 + IF(MAX(KFLDA,KFLDB).EQ.3) WTDQ=PARS1 + IF(MIN(KFLDA,KFLDB).EQ.3) WTDQ=PARS2 + IF(KFLDS.EQ.1) WTDQ=WTDQ/(3.*PAR4M) + IF((1.+WTDQ)*RLU(0).GT.1.) MBARY=-1 + IF(MBARY.EQ.-1.AND.KF2A.NE.0) RETURN + ENDIF + +C...Flavour for meson, possibly with new flavour. + IF(MBARY.LE.0) THEN + KFS=ISIGN(1,KFL1) + IF(MBARY.EQ.0) THEN + IF(KF2A.EQ.0) KFL3=ISIGN(1+INT((2.+PAR2)*RLU(0)),-KFL1) + KFLA=MAX(KF1A,KF2A+IABS(KFL3)) + KFLB=MIN(KF1A,KF2A+IABS(KFL3)) + IF(KFLA.NE.KF1A) KFS=-KFS + +C...Splitting of diquark into meson plus new diquark. + ELSE + KFL1A=MOD(KF1A/1000,10) + KFL1B=MOD(KF1A/100,10) + 120 KFL1D=KFL1A+INT(RLU(0)+0.5)*(KFL1B-KFL1A) + KFL1E=KFL1A+KFL1B-KFL1D + IF((KFL1D.EQ.3.AND.RLU(0).GT.PARDM).OR.(KFL1E.EQ.3.AND. + & RLU(0).LT.PARDM)) THEN + KFL1D=KFL1A+KFL1B-KFL1D + KFL1E=KFL1A+KFL1B-KFL1E + ENDIF + KFL3A=1+INT((2.+PAR2*PAR3M*PARJ(7))*RLU(0)) + IF + & ((KFL1E.NE.KFL3A.AND.RLU(0).GT.(1.+PAR4M)/MAX(2.D0,1.+PAR4M)) + & .OR.(KFL1E.EQ.KFL3A.AND.RLU(0).GT.2./MAX(2.D0,1.+PAR4M))) + & GOTO 120 + KFLDS=3 + IF(KFL1E.NE.KFL3A) KFLDS=2*INT(RLU(0)+1./(1.+PAR4M))+1 + KFL3=ISIGN(10000+1000*MAX(KFL1E,KFL3A)+100*MIN(KFL1E,KFL3A)+ + & KFLDS,-KFL1) + KFLA=MAX(KFL1D,KFL3A) + KFLB=MIN(KFL1D,KFL3A) + IF(KFLA.NE.KFL1D) KFS=-KFS + ENDIF + +C...Form meson, with spin and flavour mixing for diagonal states. + IF(KFLA.LE.2) KMUL=INT(PARJ(11)+RLU(0)) + IF(KFLA.EQ.3) KMUL=INT(PARJ(12)+RLU(0)) + IF(KFLA.GE.4) KMUL=INT(PARJ(13)+RLU(0)) + IF(KMUL.EQ.0.AND.PARJ(14).GT.0.) THEN + IF(RLU(0).LT.PARJ(14)) KMUL=2 + ELSEIF(KMUL.EQ.1.AND.PARJ(15)+PARJ(16)+PARJ(17).GT.0.) THEN + RMUL=RLU(0) + IF(RMUL.LT.PARJ(15)) KMUL=3 + IF(KMUL.EQ.1.AND.RMUL.LT.PARJ(15)+PARJ(16)) KMUL=4 + IF(KMUL.EQ.1.AND.RMUL.LT.PARJ(15)+PARJ(16)+PARJ(17)) KMUL=5 + ENDIF + KFLS=3 + IF(KMUL.EQ.0.OR.KMUL.EQ.3) KFLS=1 + IF(KMUL.EQ.5) KFLS=5 + IF(KFLA.NE.KFLB) THEN + KF=(100*KFLA+10*KFLB+KFLS)*KFS*(-1)**KFLA + ELSE + RMIX=RLU(0) + IMIX=2*KFLA+10*KMUL + IF(KFLA.LE.3) KF=110*(1+INT(RMIX+PARF(IMIX-1))+ + & INT(RMIX+PARF(IMIX)))+KFLS + IF(KFLA.GE.4) KF=110*KFLA+KFLS + ENDIF + IF(KMUL.EQ.2.OR.KMUL.EQ.3) KF=KF+ISIGN(10000,KF) + IF(KMUL.EQ.4) KF=KF+ISIGN(20000,KF) + +C...Optional extra suppression of eta and eta'. + IF(KF.EQ.221) THEN + IF(RLU(0).GT.PARJ(25)) GOTO 110 + ELSEIF(KF.EQ.331) THEN + IF(RLU(0).GT.PARJ(26)) GOTO 110 + ENDIF + +C...Generate diquark flavour. + ELSE + 130 IF(KF1A.LE.10.AND.KF2A.EQ.0) THEN + KFLA=KF1A + 140 KFLB=1+INT((2.+PAR2*PAR3)*RLU(0)) + KFLC=1+INT((2.+PAR2*PAR3)*RLU(0)) + KFLDS=1 + IF(KFLB.GE.KFLC) KFLDS=3 + IF(KFLDS.EQ.1.AND.PAR4*RLU(0).GT.1.) GOTO 140 + IF(KFLDS.EQ.3.AND.PAR4.LT.RLU(0)) GOTO 140 + KFL3=ISIGN(1000*MAX(KFLB,KFLC)+100*MIN(KFLB,KFLC)+KFLDS,KFL1) + +C...Take diquark flavour from input. + ELSEIF(KF1A.LE.10) THEN + KFLA=KF1A + KFLB=MOD(KF2A/1000,10) + KFLC=MOD(KF2A/100,10) + KFLDS=MOD(KF2A,10) + +C...Generate (or take from input) quark to go with diquark. + ELSE + IF(KF2A.EQ.0) KFL3=ISIGN(1+INT((2.+PAR2)*RLU(0)),KFL1) + KFLA=KF2A+IABS(KFL3) + KFLB=MOD(KF1A/1000,10) + KFLC=MOD(KF1A/100,10) + KFLDS=MOD(KF1A,10) + ENDIF + +C...SU(6) factors for formation of baryon. Try again if fails. + KBARY=KFLDS + IF(KFLDS.EQ.3.AND.KFLB.NE.KFLC) KBARY=5 + IF(KFLA.NE.KFLB.AND.KFLA.NE.KFLC) KBARY=KBARY+1 + WT=PARF(60+KBARY)+PARJ(18)*PARF(70+KBARY) + IF(MBARY.EQ.1.AND.MSTJ(12).GE.2) THEN + WTDQ=PARS0 + IF(MAX(KFLB,KFLC).EQ.3) WTDQ=PARS1 + IF(MIN(KFLB,KFLC).EQ.3) WTDQ=PARS2 + IF(KFLDS.EQ.1) WTDQ=WTDQ/(3.*PAR4M) + IF(KFLDS.EQ.1) WT=WT*(1.+WTDQ)/(1.+PARSM/(3.*PAR4M)) + IF(KFLDS.EQ.3) WT=WT*(1.+WTDQ)/(1.+PARSM) + ENDIF + IF(KF2A.EQ.0.AND.WT.LT.RLU(0)) GOTO 130 + +C...Form baryon. Distinguish Lambda- and Sigmalike baryons. + KFLD=MAX(KFLA,KFLB,KFLC) + KFLF=MIN(KFLA,KFLB,KFLC) + KFLE=KFLA+KFLB+KFLC-KFLD-KFLF + KFLS=2 + IF((PARF(60+KBARY)+PARJ(18)*PARF(70+KBARY))*RLU(0).GT. + & PARF(60+KBARY)) KFLS=4 + KFLL=0 + IF(KFLS.EQ.2.AND.KFLD.GT.KFLE.AND.KFLE.GT.KFLF) THEN + IF(KFLDS.EQ.1.AND.KFLA.EQ.KFLD) KFLL=1 + IF(KFLDS.EQ.1.AND.KFLA.NE.KFLD) KFLL=INT(0.25+RLU(0)) + IF(KFLDS.EQ.3.AND.KFLA.NE.KFLD) KFLL=INT(0.75+RLU(0)) + ENDIF + IF(KFLL.EQ.0) KF=ISIGN(1000*KFLD+100*KFLE+10*KFLF+KFLS,KFL1) + IF(KFLL.EQ.1) KF=ISIGN(1000*KFLD+100*KFLF+10*KFLE+KFLS,KFL1) + ENDIF + RETURN + +C...Use tabulated probabilities to select new flavour and hadron. + 150 IF(KTAB2.EQ.0.AND.MSTJ(12).LE.0) THEN + KT3L=1 + KT3U=6 + ELSEIF(KTAB2.EQ.0.AND.KTAB1.GE.7.AND.MSTJ(12).LE.1) THEN + KT3L=1 + KT3U=6 + ELSEIF(KTAB2.EQ.0) THEN + KT3L=1 + KT3U=22 + ELSE + KT3L=KTAB2 + KT3U=KTAB2 + ENDIF + RFL=0. + DO 170 KTS=0,2 + DO 160 KT3=KT3L,KT3U + RFL=RFL+PARF(120+80*KTAB1+25*KTS+KT3) + 160 CONTINUE + 170 CONTINUE + RFL=RLU(0)*RFL + DO 190 KTS=0,2 + KTABS=KTS + DO 180 KT3=KT3L,KT3U + KTAB3=KT3 + RFL=RFL-PARF(120+80*KTAB1+25*KTS+KT3) + IF(RFL.LE.0.) GOTO 200 + 180 CONTINUE + 190 CONTINUE + 200 CONTINUE + +C...Reconstruct flavour of produced quark/diquark. + IF(KTAB3.LE.6) THEN + KFL3A=KTAB3 + KFL3B=0 + KFL3=ISIGN(KFL3A,KFL1*(2*KTAB1-13)) + ELSE + KFL3A=1 + IF(KTAB3.GE.8) KFL3A=2 + IF(KTAB3.GE.11) KFL3A=3 + IF(KTAB3.GE.16) KFL3A=4 + KFL3B=(KTAB3-6-KFL3A*(KFL3A-2))/2 + KFL3=1000*KFL3A+100*KFL3B+1 + IF(KFL3A.EQ.KFL3B.OR.KTAB3.NE.6+KFL3A*(KFL3A-2)+2*KFL3B) KFL3= + & KFL3+2 + KFL3=ISIGN(KFL3,KFL1*(13-2*KTAB1)) + ENDIF + +C...Reconstruct meson code. + IF(KFL3A.EQ.KFL1A.AND.KFL3B.EQ.KFL1B.AND.(KFL3A.LE.3.OR. + &KFL3B.NE.0)) THEN + RFL=RLU(0)*(PARF(143+80*KTAB1+25*KTABS)+PARF(144+80*KTAB1+ + & 25*KTABS)+PARF(145+80*KTAB1+25*KTABS)) + KF=110+2*KTABS+1 + IF(RFL.GT.PARF(143+80*KTAB1+25*KTABS)) KF=220+2*KTABS+1 + IF(RFL.GT.PARF(143+80*KTAB1+25*KTABS)+PARF(144+80*KTAB1+ + & 25*KTABS)) KF=330+2*KTABS+1 + ELSEIF(KTAB1.LE.6.AND.KTAB3.LE.6) THEN + KFLA=MAX(KTAB1,KTAB3) + KFLB=MIN(KTAB1,KTAB3) + KFS=ISIGN(1,KFL1) + IF(KFLA.NE.KF1A) KFS=-KFS + KF=(100*KFLA+10*KFLB+2*KTABS+1)*KFS*(-1)**KFLA + ELSEIF(KTAB1.GE.7.AND.KTAB3.GE.7) THEN + KFS=ISIGN(1,KFL1) + IF(KFL1A.EQ.KFL3A) THEN + KFLA=MAX(KFL1B,KFL3B) + KFLB=MIN(KFL1B,KFL3B) + IF(KFLA.NE.KFL1B) KFS=-KFS + ELSEIF(KFL1A.EQ.KFL3B) THEN + KFLA=KFL3A + KFLB=KFL1B + KFS=-KFS + ELSEIF(KFL1B.EQ.KFL3A) THEN + KFLA=KFL1A + KFLB=KFL3B + ELSEIF(KFL1B.EQ.KFL3B) THEN + KFLA=MAX(KFL1A,KFL3A) + KFLB=MIN(KFL1A,KFL3A) + IF(KFLA.NE.KFL1A) KFS=-KFS + ELSE + CALL LUERRM(2,'(LUKFDI:) no matching flavours for qq -> qq') + GOTO 100 + ENDIF + KF=(100*KFLA+10*KFLB+2*KTABS+1)*KFS*(-1)**KFLA + +C...Reconstruct baryon code. + ELSE + IF(KTAB1.GE.7) THEN + KFLA=KFL3A + KFLB=KFL1A + KFLC=KFL1B + ELSE + KFLA=KFL1A + KFLB=KFL3A + KFLC=KFL3B + ENDIF + KFLD=MAX(KFLA,KFLB,KFLC) + KFLF=MIN(KFLA,KFLB,KFLC) + KFLE=KFLA+KFLB+KFLC-KFLD-KFLF + IF(KTABS.EQ.0) KF=ISIGN(1000*KFLD+100*KFLF+10*KFLE+2,KFL1) + IF(KTABS.GE.1) KF=ISIGN(1000*KFLD+100*KFLE+10*KFLF+2*KTABS,KFL1) + ENDIF + +C...Check that constructed flavour code is an allowed one. + IF(KFL2.NE.0) KFL3=0 + KC=LUCOMP(KF) + IF(KC.EQ.0) THEN + CALL LUERRM(2,'(LUKFDI:) user-defined flavour probabilities '// + & 'failed') + GOTO 100 + ENDIF + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUPTDI + SUBROUTINE LUPTDI(KFL,PX,PY) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to generate transverse momentum according to a Gaussian. + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + SAVE /LUDAT1/ + +C...Generate p_T and azimuthal angle, gives p_x and p_y. + KFLA=IABS(KFL) + PT=PARJ(21)*SQRT(-LOG(MAX(1D-10,RLU(0)))) + IF(PARJ(23).GT.RLU(0)) PT=PARJ(24)*PT + IF(MSTJ(91).EQ.1) PT=PARJ(22)*PT + IF(KFLA.EQ.0.AND.MSTJ(13).LE.0) PT=0. + PHI=PARU(2)*RLU(0) + PX=PT*COS(PHI) + PY=PT*SIN(PHI) + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUZDIS + SUBROUTINE LUZDIS(KFL1,KFL2,PR,Z) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to generate the longitudinal splitting variable z. + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUDAT1/,/LUDAT2/ + +C...Check if heavy flavour fragmentation. + KFLA=IABS(KFL1) + KFLB=IABS(KFL2) + KFLH=KFLA + IF(KFLA.GE.10) KFLH=MOD(KFLA/1000,10) + +C...Lund symmetric scaling function: determine parameters of shape. + IF(MSTJ(11).EQ.1.OR.(MSTJ(11).EQ.3.AND.KFLH.LE.3).OR. + &MSTJ(11).GE.4) THEN + FA=PARJ(41) + IF(MSTJ(91).EQ.1) FA=PARJ(43) + IF(KFLB.GE.10) FA=FA+PARJ(45) + FBB=PARJ(42) + IF(MSTJ(91).EQ.1) FBB=PARJ(44) + FB=FBB*PR + FC=1. + IF(KFLA.GE.10) FC=FC-PARJ(45) + IF(KFLB.GE.10) FC=FC+PARJ(45) + IF(MSTJ(11).GE.4.AND.KFLH.GE.4.AND.KFLH.LE.5) THEN + FRED=PARJ(46) + IF(MSTJ(11).EQ.5.AND.KFLH.EQ.5) FRED=PARJ(47) + FC=FC+FRED*FBB*PARF(100+KFLH)**2 + ELSEIF(MSTJ(11).GE.4.AND.KFLH.GE.6.AND.KFLH.LE.8) THEN + FRED=PARJ(46) + IF(MSTJ(11).EQ.5) FRED=PARJ(48) + FC=FC+FRED*FBB*PMAS(KFLH,1)**2 + ENDIF + MC=1 + IF(ABS(FC-1.).GT.0.01) MC=2 + +C...Determine position of maximum. Special cases for a = 0 or a = c. + IF(FA.LT.0.02) THEN + MA=1 + ZMAX=1. + IF(FC.GT.FB) ZMAX=FB/FC + ELSEIF(ABS(FC-FA).LT.0.01) THEN + MA=2 + ZMAX=FB/(FB+FC) + ELSE + MA=3 + ZMAX=0.5*(FB+FC-SQRT((FB-FC)**2+4.*FA*FB))/(FC-FA) + IF(ZMAX.GT.0.9999.AND.FB.GT.100.) ZMAX=MIN(ZMAX,1.-FA/FB) + ENDIF + +C...Subdivide z range if distribution very peaked near endpoint. + MMAX=2 + IF(ZMAX.LT.0.1) THEN + MMAX=1 + ZDIV=2.75*ZMAX + IF(MC.EQ.1) THEN + FINT=1.-LOG(ZDIV) + ELSE + ZDIVC=ZDIV**(1.-FC) + FINT=1.+(1.-1./ZDIVC)/(FC-1.) + ENDIF + ELSEIF(ZMAX.GT.0.85.AND.FB.GT.1.) THEN + MMAX=3 + FSCB=SQRT(4.+(FC/FB)**2) + ZDIV=FSCB-1./ZMAX-(FC/FB)*LOG(ZMAX*0.5*(FSCB+FC/FB)) + IF(MA.GE.2) ZDIV=ZDIV+(FA/FB)*LOG(1.-ZMAX) + ZDIV=MIN(ZMAX,MAX(0.D0,ZDIV)) + FINT=1.+FB*(1.-ZDIV) + ENDIF + +C...Choice of z, preweighted for peaks at low or high z. + 100 Z=RLU(0) + FPRE=1. + IF(MMAX.EQ.1) THEN + IF(FINT*RLU(0).LE.1.) THEN + Z=ZDIV*Z + ELSEIF(MC.EQ.1) THEN + Z=ZDIV**Z + FPRE=ZDIV/Z + ELSE + Z=1./(ZDIVC+Z*(1.-ZDIVC))**(1./(1.-FC)) + FPRE=(ZDIV/Z)**FC + ENDIF + ELSEIF(MMAX.EQ.3) THEN + IF(FINT*RLU(0).LE.1.) THEN + Z=ZDIV+LOG(Z)/FB + FPRE=EXP(FB*(Z-ZDIV)) + ELSE + Z=ZDIV+Z*(1.-ZDIV) + ENDIF + ENDIF + +C...Weighting according to correct formula. + IF(Z.LE.0..OR.Z.GE.1.) GOTO 100 + FEXP=FC*LOG(ZMAX/Z)+FB*(1./ZMAX-1./Z) + IF(MA.GE.2) FEXP=FEXP+FA*LOG((1.-Z)/(1.-ZMAX)) + FVAL=EXP(MAX(-50.D0,MIN(50.D0,FEXP))) + IF(FVAL.LT.RLU(0)*FPRE) GOTO 100 + +C...Generate z according to Field-Feynman, SLAC, (1-z)**c OR z**c. + ELSE + FC=PARJ(50+MAX(1,KFLH)) + IF(MSTJ(91).EQ.1) FC=PARJ(59) + 110 Z=RLU(0) + IF(FC.GE.0..AND.FC.LE.1.) THEN + IF(FC.GT.RLU(0)) Z=1.-Z**(1./3.) + ELSEIF(FC.GT.-1.AND.FC.LT.0.) THEN + IF(-4.*FC*Z*(1.-Z)**2.LT.RLU(0)*((1.-Z)**2-FC*Z)**2) GOTO 110 + ELSE + IF(FC.GT.0.) Z=1.-Z**(1./FC) + IF(FC.LT.0.) Z=Z**(-1./FC) + ENDIF + ENDIF + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUSHOW + SUBROUTINE LUSHOW(IP1,IP2,QMAX) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to generate timelike parton showers from given partons. +C IMPLICIT DOUBLE PRECISION(D) + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + DIMENSION PMTH(5,50),PS(5),PMA(4),PMSD(4),IEP(4),IPA(4), + &KFLA(4),KFLD(4),KFL(4),ITRY(4),ISI(4),ISL(4),DP(4),DPT(5,4), + &KSH(0:40),KCII(2),NIIS(2),IIIS(2,2),THEIIS(2,2),PHIIIS(2,2), + &ISII(2) + +C...Initialization of cutoff masses etc. + IF(MSTJ(41).LE.0.OR.(MSTJ(41).EQ.1.AND.QMAX.LE.PARJ(82)).OR. + &QMAX.LE.MIN(PARJ(82),PARJ(83))) RETURN + DO 100 IFL=0,40 + KSH(IFL)=0 + 100 CONTINUE + KSH(21)=1 + PMTH(1,21)=ULMASS(21) + PMTH(2,21)=SQRT(PMTH(1,21)**2+0.25*PARJ(82)**2) + PMTH(3,21)=2.*PMTH(2,21) + PMTH(4,21)=PMTH(3,21) + PMTH(5,21)=PMTH(3,21) + PMTH(1,22)=ULMASS(22) + PMTH(2,22)=SQRT(PMTH(1,22)**2+0.25*PARJ(83)**2) + PMTH(3,22)=2.*PMTH(2,22) + PMTH(4,22)=PMTH(3,22) + PMTH(5,22)=PMTH(3,22) + PMQTH1=PARJ(82) + IF(MSTJ(41).GE.2) PMQTH1=MIN(PARJ(82),PARJ(83)) + PMQTH2=PMTH(2,21) + IF(MSTJ(41).GE.2) PMQTH2=MIN(PMTH(2,21),PMTH(2,22)) + DO 110 IFL=1,8 + KSH(IFL)=1 + PMTH(1,IFL)=ULMASS(IFL) + PMTH(2,IFL)=SQRT(PMTH(1,IFL)**2+0.25*PMQTH1**2) + PMTH(3,IFL)=PMTH(2,IFL)+PMQTH2 + PMTH(4,IFL)=SQRT(PMTH(1,IFL)**2+0.25*PARJ(82)**2)+PMTH(2,21) + PMTH(5,IFL)=SQRT(PMTH(1,IFL)**2+0.25*PARJ(83)**2)+PMTH(2,22) + 110 CONTINUE + DO 120 IFL=11,17,2 + IF(MSTJ(41).GE.2) KSH(IFL)=1 + PMTH(1,IFL)=ULMASS(IFL) + PMTH(2,IFL)=SQRT(PMTH(1,IFL)**2+0.25*PARJ(83)**2) + PMTH(3,IFL)=PMTH(2,IFL)+PMTH(2,22) + PMTH(4,IFL)=PMTH(3,IFL) + PMTH(5,IFL)=PMTH(3,IFL) + 120 CONTINUE + PT2MIN=MAX(0.5*PARJ(82),1.1*PARJ(81))**2 + ALAMS=PARJ(81)**2 + ALFM=LOG(PT2MIN/ALAMS) + +C...Store positions of shower initiating partons. + IF(IP1.GT.0.AND.IP1.LE.MIN(N,MSTU(4)-MSTU(32)).AND.IP2.EQ.0) THEN + NPA=1 + IPA(1)=IP1 + ELSEIF(MIN(IP1,IP2).GT.0.AND.MAX(IP1,IP2).LE.MIN(N,MSTU(4)- + &MSTU(32))) THEN + NPA=2 + IPA(1)=IP1 + IPA(2)=IP2 + ELSEIF(IP1.GT.0.AND.IP1.LE.MIN(N,MSTU(4)-MSTU(32)).AND.IP2.LT.0 + &.AND.IP2.GE.-3) THEN + NPA=IABS(IP2) + DO 130 I=1,NPA + IPA(I)=IP1+I-1 + 130 CONTINUE + ELSE + CALL LUERRM(12, + & '(LUSHOW:) failed to reconstruct showering system') + IF(MSTU(21).GE.1) RETURN + ENDIF + +C...Check on phase space available for emission. + IREJ=0 + DO 140 J=1,5 + PS(J)=0. + 140 CONTINUE + PM=0. + DO 160 I=1,NPA + KFLA(I)=IABS(K(IPA(I),2)) + PMA(I)=P(IPA(I),5) +C...Special cutoff masses for t, l, h with variable masses. + IFLA=KFLA(I) + IF(KFLA(I).GE.6.AND.KFLA(I).LE.8) THEN + IFLA=37+KFLA(I)+ISIGN(2,K(IPA(I),2)) + PMTH(1,IFLA)=PMA(I) + PMTH(2,IFLA)=SQRT(PMTH(1,IFLA)**2+0.25*PMQTH1**2) + PMTH(3,IFLA)=PMTH(2,IFLA)+PMQTH2 + PMTH(4,IFLA)=SQRT(PMTH(1,IFLA)**2+0.25*PARJ(82)**2)+PMTH(2,21) + PMTH(5,IFLA)=SQRT(PMTH(1,IFLA)**2+0.25*PARJ(83)**2)+PMTH(2,22) + ENDIF + IF(KFLA(I).LE.40) THEN + IF(KSH(KFLA(I)).EQ.1) PMA(I)=PMTH(3,IFLA) + ENDIF + PM=PM+PMA(I) + IF(KFLA(I).GT.40) THEN + IREJ=IREJ+1 + ELSE + IF(KSH(KFLA(I)).EQ.0.OR.PMA(I).GT.QMAX) IREJ=IREJ+1 + ENDIF + DO 150 J=1,4 + PS(J)=PS(J)+P(IPA(I),J) + 150 CONTINUE + 160 CONTINUE + IF(IREJ.EQ.NPA) RETURN + PS(5)=SQRT(MAX(0.D0,PS(4)**2-PS(1)**2-PS(2)**2-PS(3)**2)) + IF(NPA.EQ.1) PS(5)=PS(4) + IF(PS(5).LE.PM+PMQTH1) RETURN + +C...Check if 3-jet matrix elements to be used. + M3JC=0 + IF(NPA.EQ.2.AND.MSTJ(47).GE.1) THEN + IF(KFLA(1).GE.1.AND.KFLA(1).LE.8.AND.KFLA(2).GE.1.AND. + & KFLA(2).LE.8) M3JC=1 + IF((KFLA(1).EQ.11.OR.KFLA(1).EQ.13.OR.KFLA(1).EQ.15.OR. + & KFLA(1).EQ.17).AND.KFLA(2).EQ.KFLA(1)) M3JC=1 + IF((KFLA(1).EQ.11.OR.KFLA(1).EQ.13.OR.KFLA(1).EQ.15.OR. + & KFLA(1).EQ.17).AND.KFLA(2).EQ.KFLA(1)+1) M3JC=1 + IF((KFLA(1).EQ.12.OR.KFLA(1).EQ.14.OR.KFLA(1).EQ.16.OR. + & KFLA(1).EQ.18).AND.KFLA(2).EQ.KFLA(1)-1) M3JC=1 + IF(MSTJ(47).EQ.2.OR.MSTJ(47).EQ.4) M3JC=1 + M3JCM=0 + IF(M3JC.EQ.1.AND.MSTJ(47).GE.3.AND.KFLA(1).EQ.KFLA(2)) THEN + M3JCM=1 + QME=(2.*PMTH(1,KFLA(1))/PS(5))**2 + ENDIF + ENDIF + +C...Find if interference with initial state partons. + MIIS=0 + IF(MSTJ(50).GE.1.AND.MSTJ(50).LE.3.AND.NPA.EQ.2) MIIS=MSTJ(50) + IF(MIIS.NE.0) THEN + DO 180 I=1,2 + KCII(I)=0 + KCA=LUCOMP(KFLA(I)) + IF(KCA.NE.0) KCII(I)=KCHG(KCA,2)*ISIGN(1,K(IPA(I),2)) + NIIS(I)=0 + IF(KCII(I).NE.0) THEN + DO 170 J=1,2 + ICSI=MOD(K(IPA(I),3+J)/MSTU(5),MSTU(5)) + IF(ICSI.GT.0.AND.ICSI.NE.IPA(1).AND.ICSI.NE.IPA(2).AND. + & (KCII(I).EQ.(-1)**(J+1).OR.KCII(I).EQ.2)) THEN + NIIS(I)=NIIS(I)+1 + IIIS(I,NIIS(I))=ICSI + ENDIF + 170 CONTINUE + ENDIF + 180 CONTINUE + IF(NIIS(1)+NIIS(2).EQ.0) MIIS=0 + ENDIF + +C...Boost interfering initial partons to rest frame +C...and reconstruct their polar and azimuthal angles. + IF(MIIS.NE.0) THEN + DO 200 I=1,2 + DO 190 J=1,5 + K(N+I,J)=K(IPA(I),J) + P(N+I,J)=P(IPA(I),J) + V(N+I,J)=0. + 190 CONTINUE + 200 CONTINUE + DO 220 I=3,2+NIIS(1) + DO 210 J=1,5 + K(N+I,J)=K(IIIS(1,I-2),J) + P(N+I,J)=P(IIIS(1,I-2),J) + V(N+I,J)=0. + 210 CONTINUE + 220 CONTINUE + DO 240 I=3+NIIS(1),2+NIIS(1)+NIIS(2) + DO 230 J=1,5 + K(N+I,J)=K(IIIS(2,I-2-NIIS(1)),J) + P(N+I,J)=P(IIIS(2,I-2-NIIS(1)),J) + V(N+I,J)=0. + 230 CONTINUE + 240 CONTINUE + CALL + & LUDBRB(N+1,N+2+NIIS(1)+NIIS(2),0.D0,0.D0,-DBLE(PS(1)/PS(4)), + & -DBLE(PS(2)/PS(4)),-DBLE(PS(3)/PS(4))) + PHI=ULANGL(P(N+1,1),P(N+1,2)) + CALL LUDBRB(N+1,N+2+NIIS(1)+NIIS(2),0.D0,-PHI,0D0,0D0,0D0) + THE=ULANGL(P(N+1,3),P(N+1,1)) + CALL LUDBRB(N+1,N+2+NIIS(1)+NIIS(2),-THE,0.D0,0D0,0D0,0D0) + DO 250 I=3,2+NIIS(1) + THEIIS(1,I-2)=ULANGL(P(N+I,3),SQRT(P(N+I,1)**2+P(N+I,2)**2)) + PHIIIS(1,I-2)=ULANGL(P(N+I,1),P(N+I,2)) + 250 CONTINUE + DO 260 I=3+NIIS(1),2+NIIS(1)+NIIS(2) + THEIIS(2,I-2-NIIS(1))=PARU(1)-ULANGL(P(N+I,3), + & SQRT(P(N+I,1)**2+P(N+I,2)**2)) + PHIIIS(2,I-2-NIIS(1))=ULANGL(P(N+I,1),P(N+I,2)) + 260 CONTINUE + ENDIF + +C...Define imagined single initiator of shower for parton system. + NS=N + IF(N.GT.MSTU(4)-MSTU(32)-5) THEN + CALL LUERRM(11,'(LUSHOW:) no more memory left in LUJETS') + IF(MSTU(21).GE.1) RETURN + ENDIF + IF(NPA.GE.2) THEN + K(N+1,1)=11 + K(N+1,2)=21 + K(N+1,3)=0 + K(N+1,4)=0 + K(N+1,5)=0 + P(N+1,1)=0. + P(N+1,2)=0. + P(N+1,3)=0. + P(N+1,4)=PS(5) + P(N+1,5)=PS(5) + V(N+1,5)=PS(5)**2 + N=N+1 + ENDIF + +C...Loop over partons that may branch. + NEP=NPA + IM=NS + IF(NPA.EQ.1) IM=NS-1 + 270 IM=IM+1 + IF(N.GT.NS) THEN + IF(IM.GT.N) GOTO 510 + KFLM=IABS(K(IM,2)) + IF(KFLM.GT.40) GOTO 270 + IF(KSH(KFLM).EQ.0) GOTO 270 + IFLM=KFLM + IF(KFLM.GE.6.AND.KFLM.LE.8) IFLM=37+KFLM+ISIGN(2,K(IM,2)) + IF(P(IM,5).LT.PMTH(2,IFLM)) GOTO 270 + IGM=K(IM,3) + ELSE + IGM=-1 + ENDIF + IF(N+NEP.GT.MSTU(4)-MSTU(32)-5) THEN + CALL LUERRM(11,'(LUSHOW:) no more memory left in LUJETS') + IF(MSTU(21).GE.1) RETURN + ENDIF + +C...Position of aunt (sister to branching parton). +C...Origin and flavour of daughters. + IAU=0 + IF(IGM.GT.0) THEN + IF(K(IM-1,3).EQ.IGM) IAU=IM-1 + IF(N.GE.IM+1.AND.K(IM+1,3).EQ.IGM) IAU=IM+1 + ENDIF + IF(IGM.GE.0) THEN + K(IM,4)=N+1 + DO 280 I=1,NEP + K(N+I,3)=IM + 280 CONTINUE + ELSE + K(N+1,3)=IPA(1) + ENDIF + IF(IGM.LE.0) THEN + DO 290 I=1,NEP + K(N+I,2)=K(IPA(I),2) + 290 CONTINUE + ELSEIF(KFLM.NE.21) THEN + K(N+1,2)=K(IM,2) + K(N+2,2)=K(IM,5) + ELSEIF(K(IM,5).EQ.21) THEN + K(N+1,2)=21 + K(N+2,2)=21 + ELSE + K(N+1,2)=K(IM,5) + K(N+2,2)=-K(IM,5) + ENDIF + +C...Reset flags on daughers and tries made. + DO 300 IP=1,NEP + K(N+IP,1)=3 + K(N+IP,4)=0 + K(N+IP,5)=0 + KFLD(IP)=IABS(K(N+IP,2)) + IF(KCHG(LUCOMP(KFLD(IP)),2).EQ.0) K(N+IP,1)=1 + ITRY(IP)=0 + ISL(IP)=0 + ISI(IP)=0 + IF(KFLD(IP).LE.40) THEN + IF(KSH(KFLD(IP)).EQ.1) ISI(IP)=1 + ENDIF + 300 CONTINUE + ISLM=0 + +C...Maximum virtuality of daughters. + IF(IGM.LE.0) THEN + DO 310 I=1,NPA + IF(NPA.GE.3) P(N+I,4)=(PS(4)*P(IPA(I),4)-PS(1)*P(IPA(I),1)- + & PS(2)*P(IPA(I),2)-PS(3)*P(IPA(I),3))/PS(5) + P(N+I,5)=MIN(QMAX,PS(5)) + IF(NPA.GE.3) P(N+I,5)=MIN(P(N+I,5),P(N+I,4)) + IF(ISI(I).EQ.0) P(N+I,5)=P(IPA(I),5) + 310 CONTINUE + ELSE + IF(MSTJ(43).LE.2) PEM=V(IM,2) + IF(MSTJ(43).GE.3) PEM=P(IM,4) + P(N+1,5)=MIN(P(IM,5),V(IM,1)*PEM) + P(N+2,5)=MIN(P(IM,5),(1.-V(IM,1))*PEM) + IF(K(N+2,2).EQ.22) P(N+2,5)=PMTH(1,22) + ENDIF + DO 320 I=1,NEP + PMSD(I)=P(N+I,5) + IF(ISI(I).EQ.1) THEN + IFLD=KFLD(I) + IF(KFLD(I).GE.6.AND.KFLD(I).LE.8) IFLD=37+KFLD(I)+ + & ISIGN(2,K(N+I,2)) + IF(P(N+I,5).LE.PMTH(3,IFLD)) P(N+I,5)=PMTH(1,IFLD) + ENDIF + V(N+I,5)=P(N+I,5)**2 + 320 CONTINUE + +C...Choose one of the daughters for evolution. + 330 INUM=0 + IF(NEP.EQ.1) INUM=1 + DO 340 I=1,NEP + IF(INUM.EQ.0.AND.ISL(I).EQ.1) INUM=I + 340 CONTINUE + DO 350 I=1,NEP + IF(INUM.EQ.0.AND.ITRY(I).EQ.0.AND.ISI(I).EQ.1) THEN + IFLD=KFLD(I) + IF(KFLD(I).GE.6.AND.KFLD(I).LE.8) IFLD=37+KFLD(I)+ + & ISIGN(2,K(N+I,2)) + IF(P(N+I,5).GE.PMTH(2,IFLD)) INUM=I + ENDIF + 350 CONTINUE + IF(INUM.EQ.0) THEN + RMAX=0. + DO 360 I=1,NEP + IF(ISI(I).EQ.1.AND.PMSD(I).GE.PMQTH2) THEN + RPM=P(N+I,5)/PMSD(I) + IFLD=KFLD(I) + IF(KFLD(I).GE.6.AND.KFLD(I).LE.8) IFLD=37+KFLD(I)+ + & ISIGN(2,K(N+I,2)) + IF(RPM.GT.RMAX.AND.P(N+I,5).GE.PMTH(2,IFLD)) THEN + RMAX=RPM + INUM=I + ENDIF + ENDIF + 360 CONTINUE + ENDIF + +C...Store information on choice of evolving daughter. + INUM=MAX(1,INUM) + IEP(1)=N+INUM + DO 370 I=2,NEP + IEP(I)=IEP(I-1)+1 + IF(IEP(I).GT.N+NEP) IEP(I)=N+1 + 370 CONTINUE + DO 380 I=1,NEP + KFL(I)=IABS(K(IEP(I),2)) + 380 CONTINUE + ITRY(INUM)=ITRY(INUM)+1 + IF(ITRY(INUM).GT.200) THEN + CALL LUERRM(14,'(LUSHOW:) caught in infinite loop') + IF(MSTU(21).GE.1) RETURN + ENDIF + Z=0.5 + IF(KFL(1).GT.40) GOTO 430 + IF(KSH(KFL(1)).EQ.0) GOTO 430 + IFL=KFL(1) + IF(KFL(1).GE.6.AND.KFL(1).LE.8) IFL=37+KFL(1)+ + &ISIGN(2,K(IEP(1),2)) + IF(P(IEP(1),5).LT.PMTH(2,IFL)) GOTO 430 + +C...Select side for interference with initial state partons. + IF(MIIS.GE.1.AND.IEP(1).LE.NS+3) THEN + III=IEP(1)-NS-1 + ISII(III)=0 + IF(IABS(KCII(III)).EQ.1.AND.NIIS(III).EQ.1) THEN + ISII(III)=1 + ELSEIF(KCII(III).EQ.2.AND.NIIS(III).EQ.1) THEN + IF(RLU(0).GT.0.5) ISII(III)=1 + ELSEIF(KCII(III).EQ.2.AND.NIIS(III).EQ.2) THEN + ISII(III)=1 + IF(RLU(0).GT.0.5) ISII(III)=2 + ENDIF + ENDIF + +C...Calculate allowed z range. + IF(NEP.EQ.1) THEN + PMED=PS(4) + ELSEIF(IGM.EQ.0.OR.MSTJ(43).LE.2) THEN + PMED=P(IM,5) + ELSE + IF(INUM.EQ.1) PMED=V(IM,1)*PEM + IF(INUM.EQ.2) PMED=(1.-V(IM,1))*PEM + ENDIF + IF(MOD(MSTJ(43),2).EQ.1) THEN + ZC=PMTH(2,21)/PMED + ZCE=PMTH(2,22)/PMED + ELSE + ZC=0.5*(1.-SQRT(MAX(0.D0,1.-(2.*PMTH(2,21)/PMED)**2))) + IF(ZC.LT.1D-4) ZC=(PMTH(2,21)/PMED)**2 + ZCE=0.5*(1.-SQRT(MAX(0.D0,1.-(2.*PMTH(2,22)/PMED)**2))) + IF(ZCE.LT.1D-4) ZCE=(PMTH(2,22)/PMED)**2 + ENDIF + ZC=MIN(ZC,0.491D0) + ZCE=MIN(ZCE,0.491D0) + IF((MSTJ(41).EQ.1.AND.ZC.GT.0.49).OR.(MSTJ(41).GE.2.AND. + &MIN(ZC,ZCE).GT.0.49)) THEN + P(IEP(1),5)=PMTH(1,IFL) + V(IEP(1),5)=P(IEP(1),5)**2 + GOTO 430 + ENDIF + +C...Integral of Altarelli-Parisi z kernel for QCD. + IF(MSTJ(49).EQ.0.AND.KFL(1).EQ.21) THEN + FBR=6.*LOG((1.-ZC)/ZC)+MSTJ(45)*(0.5-ZC) + ELSEIF(MSTJ(49).EQ.0) THEN + FBR=(8./3.)*LOG((1.-ZC)/ZC) + +C...Integral of Altarelli-Parisi z kernel for scalar gluon. + ELSEIF(MSTJ(49).EQ.1.AND.KFL(1).EQ.21) THEN + FBR=(PARJ(87)+MSTJ(45)*PARJ(88))*(1.-2.*ZC) + ELSEIF(MSTJ(49).EQ.1) THEN + FBR=(1.-2.*ZC)/3. + IF(IGM.EQ.0.AND.M3JC.EQ.1) FBR=4.*FBR + +C...Integral of Altarelli-Parisi z kernel for Abelian vector gluon. + ELSEIF(KFL(1).EQ.21) THEN + FBR=6.*MSTJ(45)*(0.5-ZC) + ELSE + FBR=2.*LOG((1.-ZC)/ZC) + ENDIF + +C...Reset QCD probability for lepton. + IF(KFL(1).GE.11.AND.KFL(1).LE.18) FBR=0. + +C...Integral of Altarelli-Parisi kernel for photon emission. + IF(MSTJ(41).GE.2.AND.KFL(1).GE.1.AND.KFL(1).LE.18) THEN + FBRE=(KCHG(KFL(1),1)/3.)**2*2.*LOG((1.-ZCE)/ZCE) + IF(MSTJ(41).EQ.10) FBRE=PARJ(84)*FBRE + ENDIF + +C...Inner veto algorithm starts. Find maximum mass for evolution. + 390 PMS=V(IEP(1),5) + IF(IGM.GE.0) THEN + PM2=0. + DO 400 I=2,NEP + PM=P(IEP(I),5) + IF(KFL(I).LE.40) THEN + IFLI=KFL(I) + IF(KFL(I).GE.6.AND.KFL(I).LE.8) IFLI=37+KFL(I)+ + & ISIGN(2,K(IEP(I),2)) + IF(KSH(KFL(I)).EQ.1) PM=PMTH(2,IFLI) + ENDIF + PM2=PM2+PM + 400 CONTINUE + PMS=MIN(PMS,(P(IM,5)-PM2)**2) + ENDIF + +C...Select mass for daughter in QCD evolution. + B0=27./6. + DO 410 IFF=4,MSTJ(45) + IF(PMS.GT.4.*PMTH(2,IFF)**2) B0=(33.-2.*IFF)/6. + 410 CONTINUE + IF(FBR.LT.1D-3) THEN + PMSQCD=0. + ELSEIF(MSTJ(44).LE.0) THEN + PMSQCD=PMS*EXP(MAX(-50.D0,LOG(RLU(0))*PARU(2)/(PARU(111)*FBR))) + ELSEIF(MSTJ(44).EQ.1) THEN + PMSQCD=4.*ALAMS*(0.25*PMS/ALAMS)**(RLU(0)**(B0/FBR)) + ELSE + PMSQCD=PMS*EXP(MAX(-50.D0,ALFM*B0*LOG(RLU(0))/FBR)) + ENDIF + IF(ZC.GT.0.49.OR.PMSQCD.LE.PMTH(4,IFL)**2) PMSQCD=PMTH(2,IFL)**2 + V(IEP(1),5)=PMSQCD + MCE=1 + +C...Select mass for daughter in QED evolution. + IF(MSTJ(41).GE.2.AND.KFL(1).GE.1.AND.KFL(1).LE.18) THEN + PMSQED=PMS*EXP(MAX(-50.D0,LOG(RLU(0))*PARU(2)/(PARU(101)*FBRE))) + IF(ZCE.GT.0.49.OR.PMSQED.LE.PMTH(5,IFL)**2) PMSQED= + & PMTH(2,IFL)**2 + IF(PMSQED.GT.PMSQCD) THEN + V(IEP(1),5)=PMSQED + MCE=2 + ENDIF + ENDIF + +C...Check whether daughter mass below cutoff. + P(IEP(1),5)=SQRT(V(IEP(1),5)) + IF(P(IEP(1),5).LE.PMTH(3,IFL)) THEN + P(IEP(1),5)=PMTH(1,IFL) + V(IEP(1),5)=P(IEP(1),5)**2 + GOTO 430 + ENDIF + +C...Select z value of branching: q -> qgamma. + IF(MCE.EQ.2) THEN + Z=1.-(1.-ZCE)*(ZCE/(1.-ZCE))**RLU(0) + IF(1.+Z**2.LT.2.*RLU(0)) GOTO 390 + K(IEP(1),5)=22 + +C...Select z value of branching: q -> qg, g -> gg, g -> qqbar. + ELSEIF(MSTJ(49).NE.1.AND.KFL(1).NE.21) THEN + Z=1.-(1.-ZC)*(ZC/(1.-ZC))**RLU(0) + IF(1.+Z**2.LT.2.*RLU(0)) GOTO 390 + K(IEP(1),5)=21 + ELSEIF(MSTJ(49).EQ.0.AND.MSTJ(45)*(0.5-ZC).LT.RLU(0)*FBR) THEN + Z=(1.-ZC)*(ZC/(1.-ZC))**RLU(0) + IF(RLU(0).GT.0.5) Z=1.-Z + IF((1.-Z*(1.-Z))**2.LT.RLU(0)) GOTO 390 + K(IEP(1),5)=21 + ELSEIF(MSTJ(49).NE.1) THEN + Z=ZC+(1.-2.*ZC)*RLU(0) + IF(Z**2+(1.-Z)**2.LT.RLU(0)) GOTO 390 + KFLB=1+INT(MSTJ(45)*RLU(0)) + PMQ=4.*PMTH(2,KFLB)**2/V(IEP(1),5) + IF(PMQ.GE.1.) GOTO 390 + PMQ0=4.*PMTH(2,21)**2/V(IEP(1),5) + IF(MOD(MSTJ(43),2).EQ.0.AND.(1.+0.5*PMQ)*SQRT(1.-PMQ).LT. + & RLU(0)*(1.+0.5*PMQ0)*SQRT(1.-PMQ0)) GOTO 390 + K(IEP(1),5)=KFLB + +C...Ditto for scalar gluon model. + ELSEIF(KFL(1).NE.21) THEN + Z=1.-SQRT(ZC**2+RLU(0)*(1.-2.*ZC)) + K(IEP(1),5)=21 + ELSEIF(RLU(0)*(PARJ(87)+MSTJ(45)*PARJ(88)).LE.PARJ(87)) THEN + Z=ZC+(1.-2.*ZC)*RLU(0) + K(IEP(1),5)=21 + ELSE + Z=ZC+(1.-2.*ZC)*RLU(0) + KFLB=1+INT(MSTJ(45)*RLU(0)) + PMQ=4.*PMTH(2,KFLB)**2/V(IEP(1),5) + IF(PMQ.GE.1.) GOTO 390 + K(IEP(1),5)=KFLB + ENDIF + IF(MCE.EQ.1.AND.MSTJ(44).GE.2) THEN + IF(Z*(1.-Z)*V(IEP(1),5).LT.PT2MIN) GOTO 390 + IF(ALFM/LOG(V(IEP(1),5)*Z*(1.-Z)/ALAMS).LT.RLU(0)) GOTO 390 + ENDIF + +C...Check if z consistent with chosen m. + IF(KFL(1).EQ.21) THEN + KFLGD1=IABS(K(IEP(1),5)) + KFLGD2=KFLGD1 + ELSE + KFLGD1=KFL(1) + KFLGD2=IABS(K(IEP(1),5)) + ENDIF + IF(NEP.EQ.1) THEN + PED=PS(4) + ELSEIF(NEP.GE.3) THEN + PED=P(IEP(1),4) + ELSEIF(IGM.EQ.0.OR.MSTJ(43).LE.2) THEN + PED=0.5*(V(IM,5)+V(IEP(1),5)-PM2**2)/P(IM,5) + ELSE + IF(IEP(1).EQ.N+1) PED=V(IM,1)*PEM + IF(IEP(1).EQ.N+2) PED=(1.-V(IM,1))*PEM + ENDIF + IF(MOD(MSTJ(43),2).EQ.1) THEN + IFLGD1=KFLGD1 + IF(KFLGD1.GE.6.AND.KFLGD1.LE.8) IFLGD1=IFL + PMQTH3=0.5*PARJ(82) + IF(KFLGD2.EQ.22) PMQTH3=0.5*PARJ(83) + PMQ1=(PMTH(1,IFLGD1)**2+PMQTH3**2)/V(IEP(1),5) + PMQ2=(PMTH(1,KFLGD2)**2+PMQTH3**2)/V(IEP(1),5) + ZD=SQRT(MAX(0.D0,(1.-V(IEP(1),5)/PED**2)*((1.-PMQ1-PMQ2)**2- + & 4.*PMQ1*PMQ2))) + ZH=1.+PMQ1-PMQ2 + ELSE + ZD=SQRT(MAX(0.D0,1.-V(IEP(1),5)/PED**2)) + ZH=1. + ENDIF + ZL=0.5*(ZH-ZD) + ZU=0.5*(ZH+ZD) + IF(Z.LT.ZL.OR.Z.GT.ZU) GOTO 390 + IF(KFL(1).EQ.21) V(IEP(1),3)=LOG(ZU*(1.-ZL)/MAX(1D-20,ZL* + &(1.-ZU))) + IF(KFL(1).NE.21) V(IEP(1),3)=LOG((1.-ZL)/MAX(1D-10,1.-ZU)) + +C...Width suppression for q -> q + g. + IF(MSTJ(40).NE.0.AND.KFL(1).NE.21) THEN + IF(IGM.EQ.0) THEN + EGLU=0.5*PS(5)*(1.-Z)*(1.+V(IEP(1),5)/V(NS+1,5)) + ELSE + EGLU=PMED*(1.-Z) + ENDIF + CHI=PARJ(89)**2/(PARJ(89)**2+EGLU**2) + IF(MSTJ(40).EQ.1) THEN + IF(CHI.LT.RLU(0)) GOTO 390 + ELSEIF(MSTJ(40).EQ.2) THEN + IF(1.-CHI.LT.RLU(0)) GOTO 390 + ENDIF + ENDIF + +C...Three-jet matrix element correction. + IF(IGM.EQ.0.AND.M3JC.EQ.1) THEN + X1=Z*(1.+V(IEP(1),5)/V(NS+1,5)) + X2=1.-V(IEP(1),5)/V(NS+1,5) + X3=(1.-X1)+(1.-X2) + IF(MCE.EQ.2) THEN + KI1=K(IPA(INUM),2) + KI2=K(IPA(3-INUM),2) + QF1=KCHG(IABS(KI1),1)*ISIGN(1,KI1)/3. + QF2=KCHG(IABS(KI2),1)*ISIGN(1,KI2)/3. + WSHOW=QF1**2*(1.-X1)/X3*(1.+(X1/(2.-X2))**2)+ + & QF2**2*(1.-X2)/X3*(1.+(X2/(2.-X1))**2) + WME=(QF1*(1.-X1)/X3-QF2*(1.-X2)/X3)**2*(X1**2+X2**2) + ELSEIF(MSTJ(49).NE.1) THEN + WSHOW=1.+(1.-X1)/X3*(X1/(2.-X2))**2+ + & (1.-X2)/X3*(X2/(2.-X1))**2 + WME=X1**2+X2**2 + IF(M3JCM.EQ.1) WME=WME-QME*X3-0.5*QME**2- + & (0.5*QME+0.25*QME**2)*((1.-X2)/MAX(1D-7,1.-X1)+ + & (1.-X1)/MAX(1D-7,1.-X2)) + ELSE + WSHOW=4.*X3*((1.-X1)/(2.-X2)**2+(1.-X2)/(2.-X1)**2) + WME=X3**2 + IF(MSTJ(102).GE.2) WME=X3**2-2.*(1.+X3)*(1.-X1)*(1.-X2)* + & PARJ(171) + ENDIF + IF(WME.LT.RLU(0)*WSHOW) GOTO 390 + +C...Impose angular ordering by rejection of nonordered emission. + ELSEIF(MCE.EQ.1.AND.IGM.GT.0.AND.MSTJ(42).GE.2) THEN + MAOM=1 + ZM=V(IM,1) + IF(IEP(1).EQ.N+2) ZM=1.-V(IM,1) + THE2ID=Z*(1.-Z)*(ZM*P(IM,4))**2/V(IEP(1),5) + IAOM=IM + 420 IF(K(IAOM,5).EQ.22) THEN + IAOM=K(IAOM,3) + IF(K(IAOM,3).LE.NS) MAOM=0 + IF(MAOM.EQ.1) GOTO 420 + ENDIF + IF(MAOM.EQ.1) THEN + THE2IM=V(IAOM,1)*(1.-V(IAOM,1))*P(IAOM,4)**2/V(IAOM,5) + IF(THE2ID.LT.THE2IM) GOTO 390 + ENDIF + ENDIF + +C...Impose user-defined maximum angle at first branching. + IF(MSTJ(48).EQ.1) THEN + IF(NEP.EQ.1.AND.IM.EQ.NS) THEN + THE2ID=Z*(1.-Z)*PS(4)**2/V(IEP(1),5) + IF(THE2ID.LT.1./PARJ(85)**2) GOTO 390 + ELSEIF(NEP.EQ.2.AND.IEP(1).EQ.NS+2) THEN + THE2ID=Z*(1.-Z)*(0.5*P(IM,4))**2/V(IEP(1),5) + IF(THE2ID.LT.1./PARJ(85)**2) GOTO 390 + ELSEIF(NEP.EQ.2.AND.IEP(1).EQ.NS+3) THEN + THE2ID=Z*(1.-Z)*(0.5*P(IM,4))**2/V(IEP(1),5) + IF(THE2ID.LT.1./PARJ(86)**2) GOTO 390 + ENDIF + ENDIF + +C...Impose angular constraint in first branching from interference +C...with initial state partons. + IF(MIIS.GE.2.AND.IEP(1).LE.NS+3) THEN + THE2D=MAX((1.-Z)/Z,Z/(1.-Z))*V(IEP(1),5)/(0.5*P(IM,4))**2 + IF(IEP(1).EQ.NS+2.AND.ISII(1).GE.1) THEN + IF(THE2D.GT.THEIIS(1,ISII(1))**2) GOTO 390 + ELSEIF(IEP(1).EQ.NS+3.AND.ISII(2).GE.1) THEN + IF(THE2D.GT.THEIIS(2,ISII(2))**2) GOTO 390 + ENDIF + ENDIF + +C...End of inner veto algorithm. Check if only one leg evolved so far. + 430 V(IEP(1),1)=Z + ISL(1)=0 + ISL(2)=0 + IF(NEP.EQ.1) GOTO 460 + IF(NEP.EQ.2.AND.P(IEP(1),5)+P(IEP(2),5).GE.P(IM,5)) GOTO 330 + DO 440 I=1,NEP + IF(ITRY(I).EQ.0.AND.KFLD(I).LE.40) THEN + IF(KSH(KFLD(I)).EQ.1) THEN + IFLD=KFLD(I) + IF(KFLD(I).GE.6.AND.KFLD(I).LE.8) IFLD=37+KFLD(I)+ + & ISIGN(2,K(N+I,2)) + IF(P(N+I,5).GE.PMTH(2,IFLD)) GOTO 330 + ENDIF + ENDIF + 440 CONTINUE + +C...Check if chosen multiplet m1,m2,z1,z2 is physical. + IF(NEP.EQ.3) THEN + PA1S=(P(N+1,4)+P(N+1,5))*(P(N+1,4)-P(N+1,5)) + PA2S=(P(N+2,4)+P(N+2,5))*(P(N+2,4)-P(N+2,5)) + PA3S=(P(N+3,4)+P(N+3,5))*(P(N+3,4)-P(N+3,5)) + PTS=0.25*(2.*PA1S*PA2S+2.*PA1S*PA3S+2.*PA2S*PA3S- + & PA1S**2-PA2S**2-PA3S**2)/PA1S + IF(PTS.LE.0.) GOTO 330 + ELSEIF(IGM.EQ.0.OR.MSTJ(43).LE.2.OR.MOD(MSTJ(43),2).EQ.0) THEN + DO 450 I1=N+1,N+2 + KFLDA=IABS(K(I1,2)) + IF(KFLDA.GT.40) GOTO 450 + IF(KSH(KFLDA).EQ.0) GOTO 450 + IFLDA=KFLDA + IF(KFLDA.GE.6.AND.KFLDA.LE.8) IFLDA=37+KFLDA+ + & ISIGN(2,K(I1,2)) + IF(P(I1,5).LT.PMTH(2,IFLDA)) GOTO 450 + IF(KFLDA.EQ.21) THEN + KFLGD1=IABS(K(I1,5)) + KFLGD2=KFLGD1 + ELSE + KFLGD1=KFLDA + KFLGD2=IABS(K(I1,5)) + ENDIF + I2=2*N+3-I1 + IF(IGM.EQ.0.OR.MSTJ(43).LE.2) THEN + PED=0.5*(V(IM,5)+V(I1,5)-V(I2,5))/P(IM,5) + ELSE + IF(I1.EQ.N+1) ZM=V(IM,1) + IF(I1.EQ.N+2) ZM=1.-V(IM,1) + PML=SQRT((V(IM,5)-V(N+1,5)-V(N+2,5))**2- + & 4.*V(N+1,5)*V(N+2,5)) + PED=PEM*(0.5*(V(IM,5)-PML+V(I1,5)-V(I2,5))+PML*ZM)/V(IM,5) + ENDIF + IF(MOD(MSTJ(43),2).EQ.1) THEN + PMQTH3=0.5*PARJ(82) + IF(KFLGD2.EQ.22) PMQTH3=0.5*PARJ(83) + IFLGD1=KFLGD1 + IF(KFLGD1.GE.6.AND.KFLGD1.LE.8) IFLGD1=IFLDA + PMQ1=(PMTH(1,IFLGD1)**2+PMQTH3**2)/V(I1,5) + PMQ2=(PMTH(1,KFLGD2)**2+PMQTH3**2)/V(I1,5) + ZD=SQRT(MAX(0.D0,(1.-V(I1,5)/PED**2)*((1.-PMQ1-PMQ2)**2- + & 4.*PMQ1*PMQ2))) + ZH=1.+PMQ1-PMQ2 + ELSE + ZD=SQRT(MAX(0.D0,1.-V(I1,5)/PED**2)) + ZH=1. + ENDIF + ZL=0.5*(ZH-ZD) + ZU=0.5*(ZH+ZD) + IF(I1.EQ.N+1.AND.(V(I1,1).LT.ZL.OR.V(I1,1).GT.ZU)) ISL(1)=1 + IF(I1.EQ.N+2.AND.(V(I1,1).LT.ZL.OR.V(I1,1).GT.ZU)) ISL(2)=1 + IF(KFLDA.EQ.21) V(I1,4)=LOG(ZU*(1.-ZL)/MAX(1D-20,ZL*(1.-ZU))) + IF(KFLDA.NE.21) V(I1,4)=LOG((1.-ZL)/MAX(1D-10,1.-ZU)) + 450 CONTINUE + IF(ISL(1).EQ.1.AND.ISL(2).EQ.1.AND.ISLM.NE.0) THEN + ISL(3-ISLM)=0 + ISLM=3-ISLM + ELSEIF(ISL(1).EQ.1.AND.ISL(2).EQ.1) THEN + ZDR1=MAX(0.D0,V(N+1,3)/MAX(1D-6,V(N+1,4))-1.) + ZDR2=MAX(0.D0,V(N+2,3)/MAX(1D-6,V(N+2,4))-1.) + IF(ZDR2.GT.RLU(0)*(ZDR1+ZDR2)) ISL(1)=0 + IF(ISL(1).EQ.1) ISL(2)=0 + IF(ISL(1).EQ.0) ISLM=1 + IF(ISL(2).EQ.0) ISLM=2 + ENDIF + IF(ISL(1).EQ.1.OR.ISL(2).EQ.1) GOTO 330 + ENDIF + IFLD1=KFLD(1) + IF(KFLD(1).GE.6.AND.KFLD(1).LE.8) IFLD1=37+KFLD(1)+ + &ISIGN(2,K(N+1,2)) + IFLD2=KFLD(2) + IF(KFLD(2).GE.6.AND.KFLD(2).LE.8) IFLD2=37+KFLD(2)+ + &ISIGN(2,K(N+2,2)) + IF(IGM.GT.0.AND.MOD(MSTJ(43),2).EQ.1.AND.(P(N+1,5).GE. + &PMTH(2,IFLD1).OR.P(N+2,5).GE.PMTH(2,IFLD2))) THEN + PMQ1=V(N+1,5)/V(IM,5) + PMQ2=V(N+2,5)/V(IM,5) + ZD=SQRT(MAX(0.D0,(1.-V(IM,5)/PEM**2)*((1.-PMQ1-PMQ2)**2- + & 4.*PMQ1*PMQ2))) + ZH=1.+PMQ1-PMQ2 + ZL=0.5*(ZH-ZD) + ZU=0.5*(ZH+ZD) + IF(V(IM,1).LT.ZL.OR.V(IM,1).GT.ZU) GOTO 330 + ENDIF + +C...Accepted branch. Construct four-momentum for initial partons. + 460 MAZIP=0 + MAZIC=0 + IF(NEP.EQ.1) THEN + P(N+1,1)=0. + P(N+1,2)=0. + P(N+1,3)=SQRT(MAX(0.D0,(P(IPA(1),4)+P(N+1,5))*(P(IPA(1),4)- + & P(N+1,5)))) + P(N+1,4)=P(IPA(1),4) + V(N+1,2)=P(N+1,4) + ELSEIF(IGM.EQ.0.AND.NEP.EQ.2) THEN + PED1=0.5*(V(IM,5)+V(N+1,5)-V(N+2,5))/P(IM,5) + P(N+1,1)=0. + P(N+1,2)=0. + P(N+1,3)=SQRT(MAX(0.D0,(PED1+P(N+1,5))*(PED1-P(N+1,5)))) + P(N+1,4)=PED1 + P(N+2,1)=0. + P(N+2,2)=0. + P(N+2,3)=-P(N+1,3) + P(N+2,4)=P(IM,5)-PED1 + V(N+1,2)=P(N+1,4) + V(N+2,2)=P(N+2,4) + ELSEIF(NEP.EQ.3) THEN + P(N+1,1)=0. + P(N+1,2)=0. + P(N+1,3)=SQRT(MAX(0.D0,PA1S)) + P(N+2,1)=SQRT(PTS) + P(N+2,2)=0. + P(N+2,3)=0.5*(PA3S-PA2S-PA1S)/P(N+1,3) + P(N+3,1)=-P(N+2,1) + P(N+3,2)=0. + P(N+3,3)=-(P(N+1,3)+P(N+2,3)) + V(N+1,2)=P(N+1,4) + V(N+2,2)=P(N+2,4) + V(N+3,2)=P(N+3,4) + +C...Construct transverse momentum for ordinary branching in shower. + ELSE + ZM=V(IM,1) + PZM=SQRT(MAX(0.D0,(PEM+P(IM,5))*(PEM-P(IM,5)))) + PMLS=(V(IM,5)-V(N+1,5)-V(N+2,5))**2-4.*V(N+1,5)*V(N+2,5) + IF(PZM.LE.0.) THEN + PTS=0. + ELSEIF(MOD(MSTJ(43),2).EQ.1) THEN + PTS=(PEM**2*(ZM*(1.-ZM)*V(IM,5)-(1.-ZM)*V(N+1,5)- + & ZM*V(N+2,5))-0.25*PMLS)/PZM**2 + ELSE + PTS=PMLS*(ZM*(1.-ZM)*PEM**2/V(IM,5)-0.25)/PZM**2 + ENDIF + PT=SQRT(MAX(0.D0,PTS)) + +C...Find coefficient of azimuthal asymmetry due to gluon polarization. + HAZIP=0. + IF(MSTJ(49).NE.1.AND.MOD(MSTJ(46),2).EQ.1.AND.K(IM,2).EQ.21. + & AND.IAU.NE.0) THEN + IF(K(IGM,3).NE.0) MAZIP=1 + ZAU=V(IGM,1) + IF(IAU.EQ.IM+1) ZAU=1.-V(IGM,1) + IF(MAZIP.EQ.0) ZAU=0. + IF(K(IGM,2).NE.21) THEN + HAZIP=2.*ZAU/(1.+ZAU**2) + ELSE + HAZIP=(ZAU/(1.-ZAU*(1.-ZAU)))**2 + ENDIF + IF(K(N+1,2).NE.21) THEN + HAZIP=HAZIP*(-2.*ZM*(1.-ZM))/(1.-2.*ZM*(1.-ZM)) + ELSE + HAZIP=HAZIP*(ZM*(1.-ZM)/(1.-ZM*(1.-ZM)))**2 + ENDIF + ENDIF + +C...Find coefficient of azimuthal asymmetry due to soft gluon +C...interference. + HAZIC=0. + IF(MSTJ(49).NE.2.AND.MSTJ(46).GE.2.AND.(K(N+1,2).EQ.21.OR. + & K(N+2,2).EQ.21).AND.IAU.NE.0) THEN + IF(K(IGM,3).NE.0) MAZIC=N+1 + IF(K(IGM,3).NE.0.AND.K(N+1,2).NE.21) MAZIC=N+2 + IF(K(IGM,3).NE.0.AND.K(N+1,2).EQ.21.AND.K(N+2,2).EQ.21.AND. + & ZM.GT.0.5) MAZIC=N+2 + IF(K(IAU,2).EQ.22) MAZIC=0 + ZS=ZM + IF(MAZIC.EQ.N+2) ZS=1.-ZM + ZGM=V(IGM,1) + IF(IAU.EQ.IM-1) ZGM=1.-V(IGM,1) + IF(MAZIC.EQ.0) ZGM=1. + IF(MAZIC.NE.0) HAZIC=(P(IM,5)/P(IGM,5))* + & SQRT((1.-ZS)*(1.-ZGM)/(ZS*ZGM)) + HAZIC=MIN(0.95D0,HAZIC) + ENDIF + ENDIF + +C...Construct kinematics for ordinary branching in shower. + 470 IF(NEP.EQ.2.AND.IGM.GT.0) THEN + IF(MOD(MSTJ(43),2).EQ.1) THEN + P(N+1,4)=PEM*V(IM,1) + ELSE + P(N+1,4)=PEM*(0.5*(V(IM,5)-SQRT(PMLS)+V(N+1,5)-V(N+2,5))+ + & SQRT(PMLS)*ZM)/V(IM,5) + ENDIF + PHI=PARU(2)*RLU(0) + P(N+1,1)=PT*COS(PHI) + P(N+1,2)=PT*SIN(PHI) + IF(PZM.GT.0.) THEN + P(N+1,3)=0.5*(V(N+2,5)-V(N+1,5)-V(IM,5)+2.*PEM*P(N+1,4))/PZM + ELSE + P(N+1,3)=0. + ENDIF + P(N+2,1)=-P(N+1,1) + P(N+2,2)=-P(N+1,2) + P(N+2,3)=PZM-P(N+1,3) + P(N+2,4)=PEM-P(N+1,4) + IF(MSTJ(43).LE.2) THEN + V(N+1,2)=(PEM*P(N+1,4)-PZM*P(N+1,3))/P(IM,5) + V(N+2,2)=(PEM*P(N+2,4)-PZM*P(N+2,3))/P(IM,5) + ENDIF + ENDIF + +C...Rotate and boost daughters. + IF(IGM.GT.0) THEN + IF(MSTJ(43).LE.2) THEN + BEX=P(IGM,1)/P(IGM,4) + BEY=P(IGM,2)/P(IGM,4) + BEZ=P(IGM,3)/P(IGM,4) + GA=P(IGM,4)/P(IGM,5) + GABEP=GA*(GA*(BEX*P(IM,1)+BEY*P(IM,2)+BEZ*P(IM,3))/(1.+GA)- + & P(IM,4)) + ELSE + BEX=0. + BEY=0. + BEZ=0. + GA=1. + GABEP=0. + ENDIF + THE=ULANGL(P(IM,3)+GABEP*BEZ,SQRT((P(IM,1)+GABEP*BEX)**2+ + & (P(IM,2)+GABEP*BEY)**2)) + PHI=ULANGL(P(IM,1)+GABEP*BEX,P(IM,2)+GABEP*BEY) + DO 480 I=N+1,N+2 + DP(1)=COS(THE)*COS(PHI)*P(I,1)-SIN(PHI)*P(I,2)+ + & SIN(THE)*COS(PHI)*P(I,3) + DP(2)=COS(THE)*SIN(PHI)*P(I,1)+COS(PHI)*P(I,2)+ + & SIN(THE)*SIN(PHI)*P(I,3) + DP(3)=-SIN(THE)*P(I,1)+COS(THE)*P(I,3) + DP(4)=P(I,4) + DBP=BEX*DP(1)+BEY*DP(2)+BEZ*DP(3) + DGABP=GA*(GA*DBP/(1D0+GA)+DP(4)) + P(I,1)=DP(1)+DGABP*BEX + P(I,2)=DP(2)+DGABP*BEY + P(I,3)=DP(3)+DGABP*BEZ + P(I,4)=GA*(DP(4)+DBP) + 480 CONTINUE + ENDIF + +C...Weight with azimuthal distribution, if required. + IF(MAZIP.NE.0.OR.MAZIC.NE.0) THEN + DO 490 J=1,3 + DPT(1,J)=P(IM,J) + DPT(2,J)=P(IAU,J) + DPT(3,J)=P(N+1,J) + 490 CONTINUE + DPMA=DPT(1,1)*DPT(2,1)+DPT(1,2)*DPT(2,2)+DPT(1,3)*DPT(2,3) + DPMD=DPT(1,1)*DPT(3,1)+DPT(1,2)*DPT(3,2)+DPT(1,3)*DPT(3,3) + DPMM=DPT(1,1)**2+DPT(1,2)**2+DPT(1,3)**2 + DO 500 J=1,3 + DPT(4,J)=DPT(2,J)-DPMA*DPT(1,J)/DPMM + DPT(5,J)=DPT(3,J)-DPMD*DPT(1,J)/DPMM + 500 CONTINUE + DPT(4,4)=SQRT(DPT(4,1)**2+DPT(4,2)**2+DPT(4,3)**2) + DPT(5,4)=SQRT(DPT(5,1)**2+DPT(5,2)**2+DPT(5,3)**2) + IF(MIN(DPT(4,4),DPT(5,4)).GT.0.1*PARJ(82)) THEN + CAD=(DPT(4,1)*DPT(5,1)+DPT(4,2)*DPT(5,2)+ + & DPT(4,3)*DPT(5,3))/(DPT(4,4)*DPT(5,4)) + IF(MAZIP.NE.0) THEN + IF(1.+HAZIP*(2.*CAD**2-1.).LT.RLU(0)*(1.+ABS(HAZIP))) + & GOTO 470 + ENDIF + IF(MAZIC.NE.0) THEN + IF(MAZIC.EQ.N+2) CAD=-CAD + IF((1.-HAZIC)*(1.-HAZIC*CAD)/(1.+HAZIC**2-2.*HAZIC*CAD) + & .LT.RLU(0)) GOTO 470 + ENDIF + ENDIF + ENDIF + +C...Azimuthal anisotropy due to interference with initial state partons. + IF(MOD(MIIS,2).EQ.1.AND.IGM.EQ.NS+1.AND.(K(N+1,2).EQ.21.OR. + &K(N+2,2).EQ.21)) THEN + III=IM-NS-1 + IF(ISII(III).GE.1) THEN + IAZIID=N+1 + IF(K(N+1,2).NE.21) IAZIID=N+2 + IF(K(N+1,2).EQ.21.AND.K(N+2,2).EQ.21.AND. + & P(N+1,4).GT.P(N+2,4)) IAZIID=N+2 + THEIID=ULANGL(P(IAZIID,3),SQRT(P(IAZIID,1)**2+P(IAZIID,2)**2)) + IF(III.EQ.2) THEIID=PARU(1)-THEIID + PHIIID=ULANGL(P(IAZIID,1),P(IAZIID,2)) + HAZII=MIN(0.95D0,THEIID/THEIIS(III,ISII(III))) + CAD=COS(PHIIID-PHIIIS(III,ISII(III))) + PHIREL=ABS(PHIIID-PHIIIS(III,ISII(III))) + IF(PHIREL.GT.PARU(1)) PHIREL=PARU(2)-PHIREL + IF((1.-HAZII)*(1.-HAZII*CAD)/(1.+HAZII**2-2.*HAZII*CAD) + & .LT.RLU(0)) GOTO 470 + ENDIF + ENDIF + +C...Continue loop over partons that may branch, until none left. + IF(IGM.GE.0) K(IM,1)=14 + N=N+NEP + NEP=2 + IF(N.GT.MSTU(4)-MSTU(32)-5) THEN + CALL LUERRM(11,'(LUSHOW:) no more memory left in LUJETS') + IF(MSTU(21).GE.1) N=NS + IF(MSTU(21).GE.1) RETURN + ENDIF + GOTO 270 + +C...Set information on imagined shower initiator. + 510 IF(NPA.GE.2) THEN + K(NS+1,1)=11 + K(NS+1,2)=94 + K(NS+1,3)=IP1 + IF(IP2.GT.0.AND.IP2.LT.IP1) K(NS+1,3)=IP2 + K(NS+1,4)=NS+2 + K(NS+1,5)=NS+1+NPA + IIM=1 + ELSE + IIM=0 + ENDIF + +C...Reconstruct string drawing information. + DO 520 I=NS+1+IIM,N + IF(K(I,1).LE.10.AND.K(I,2).EQ.22) THEN + K(I,1)=1 + ELSEIF(K(I,1).LE.10.AND.IABS(K(I,2)).GE.11.AND. + &IABS(K(I,2)).LE.18) THEN + K(I,1)=1 + ELSEIF(K(I,1).LE.10) THEN + K(I,4)=MSTU(5)*(K(I,4)/MSTU(5)) + K(I,5)=MSTU(5)*(K(I,5)/MSTU(5)) + ELSEIF(K(MOD(K(I,4),MSTU(5))+1,2).NE.22) THEN + ID1=MOD(K(I,4),MSTU(5)) + IF(K(I,2).GE.1.AND.K(I,2).LE.8) ID1=MOD(K(I,4),MSTU(5))+1 + ID2=2*MOD(K(I,4),MSTU(5))+1-ID1 + K(I,4)=MSTU(5)*(K(I,4)/MSTU(5))+ID1 + K(I,5)=MSTU(5)*(K(I,5)/MSTU(5))+ID2 + K(ID1,4)=K(ID1,4)+MSTU(5)*I + K(ID1,5)=K(ID1,5)+MSTU(5)*ID2 + K(ID2,4)=K(ID2,4)+MSTU(5)*ID1 + K(ID2,5)=K(ID2,5)+MSTU(5)*I + ELSE + ID1=MOD(K(I,4),MSTU(5)) + ID2=ID1+1 + K(I,4)=MSTU(5)*(K(I,4)/MSTU(5))+ID1 + K(I,5)=MSTU(5)*(K(I,5)/MSTU(5))+ID1 + IF(IABS(K(I,2)).LE.10.OR.K(ID1,1).GE.11) THEN + K(ID1,4)=K(ID1,4)+MSTU(5)*I + K(ID1,5)=K(ID1,5)+MSTU(5)*I + ELSE + K(ID1,4)=0 + K(ID1,5)=0 + ENDIF + K(ID2,4)=0 + K(ID2,5)=0 + ENDIF + 520 CONTINUE + +C...Transformation from CM frame. + IF(NPA.GE.2) THEN + BEX=PS(1)/PS(4) + BEY=PS(2)/PS(4) + BEZ=PS(3)/PS(4) + GA=PS(4)/PS(5) + GABEP=GA*(GA*(BEX*P(IPA(1),1)+BEY*P(IPA(1),2)+BEZ*P(IPA(1),3)) + & /(1.+GA)-P(IPA(1),4)) + ELSE + BEX=0. + BEY=0. + BEZ=0. + GABEP=0. + ENDIF + THE=ULANGL(P(IPA(1),3)+GABEP*BEZ,SQRT((P(IPA(1),1) + &+GABEP*BEX)**2+(P(IPA(1),2)+GABEP*BEY)**2)) + PHI=ULANGL(P(IPA(1),1)+GABEP*BEX,P(IPA(1),2)+GABEP*BEY) + IF(NPA.EQ.3) THEN + CHI=ULANGL(COS(THE)*COS(PHI)*(P(IPA(2),1)+GABEP*BEX)+COS(THE)* + & SIN(PHI)*(P(IPA(2),2)+GABEP*BEY)-SIN(THE)*(P(IPA(2),3)+GABEP* + & BEZ),-SIN(PHI)*(P(IPA(2),1)+GABEP*BEX)+COS(PHI)*(P(IPA(2),2)+ + & GABEP*BEY)) + MSTU(33)=1 + CALL LUDBRB(NS+1,N,0.D0,CHI,0D0,0D0,0D0) + ENDIF + DBEX=DBLE(BEX) + DBEY=DBLE(BEY) + DBEZ=DBLE(BEZ) + MSTU(33)=1 + CALL LUDBRB(NS+1,N,THE,PHI,DBEX,DBEY,DBEZ) + +C...Decay vertex of shower. + DO 540 I=NS+1,N + DO 530 J=1,5 + V(I,J)=V(IP1,J) + 530 CONTINUE + 540 CONTINUE + +C...Delete trivial shower, else connect initiators. + IF(N.EQ.NS+NPA+IIM) THEN + N=NS + ELSE + DO 550 IP=1,NPA + K(IPA(IP),1)=14 + K(IPA(IP),4)=K(IPA(IP),4)+NS+IIM+IP + K(IPA(IP),5)=K(IPA(IP),5)+NS+IIM+IP + K(NS+IIM+IP,3)=IPA(IP) + IF(IIM.EQ.1.AND.MSTU(16).NE.2) K(NS+IIM+IP,3)=NS+1 + IF(K(NS+IIM+IP,1).NE.1) THEN + K(NS+IIM+IP,4)=MSTU(5)*IPA(IP)+K(NS+IIM+IP,4) + K(NS+IIM+IP,5)=MSTU(5)*IPA(IP)+K(NS+IIM+IP,5) + ENDIF + 550 CONTINUE + ENDIF + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUBOEI + SUBROUTINE LUBOEI(NSAV) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to modify event so as to approximately take into account +C...Bose-Einstein effects according to a simple phenomenological +C...parametrization. +C IMPLICIT DOUBLE PRECISION(D) + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + SAVE /LUJETS/,/LUDAT1/ + DIMENSION DPS(4),KFBE(9),NBE(0:9),BEI(100) + DATA KFBE/211,-211,111,321,-321,130,310,221,331/ + +C...Boost event to overall CM frame. Calculate CM energy. + IF((MSTJ(51).NE.1.AND.MSTJ(51).NE.2).OR.N-NSAV.LE.1) RETURN + DO 100 J=1,4 + DPS(J)=0. + 100 CONTINUE + DO 120 I=1,N + KFA=IABS(K(I,2)) + IF(K(I,1).LE.10.AND.((KFA.GT.10.AND.KFA.LE.20).OR.KFA.EQ.22).AND. + &K(I,3).GT.0) THEN + KFMA=IABS(K(K(I,3),2)) + IF(KFMA.GT.10.AND.KFMA.LE.80) K(I,1)=-K(I,1) + ENDIF + IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 120 + DO 110 J=1,4 + DPS(J)=DPS(J)+P(I,J) + 110 CONTINUE + 120 CONTINUE + CALL LUDBRB(0,0,0.D0,0.D0,-DPS(1)/DPS(4),-DPS(2)/DPS(4), + &-DPS(3)/DPS(4)) + PECM=0. + DO 130 I=1,N + IF(K(I,1).GE.1.AND.K(I,1).LE.10) PECM=PECM+P(I,4) + 130 CONTINUE + +C...Reserve copy of particles by species at end of record. + NBE(0)=N+MSTU(3) + DO 160 IBE=1,MIN(9,MSTJ(52)) + NBE(IBE)=NBE(IBE-1) + DO 150 I=NSAV+1,N + IF(K(I,2).NE.KFBE(IBE)) GOTO 150 + IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 150 + IF(NBE(IBE).GE.MSTU(4)-MSTU(32)-5) THEN + CALL LUERRM(11,'(LUBOEI:) no more memory left in LUJETS') + RETURN + ENDIF + NBE(IBE)=NBE(IBE)+1 + K(NBE(IBE),1)=I + DO 140 J=1,3 + P(NBE(IBE),J)=0. + 140 CONTINUE + 150 CONTINUE + 160 CONTINUE + IF(NBE(MIN(9,MSTJ(52)))-NBE(0).LE.1) GOTO 280 + +C...Tabulate integral for subsequent momentum shift. + DO 220 IBE=1,MIN(9,MSTJ(52)) + IF(IBE.NE.1.AND.IBE.NE.4.AND.IBE.LE.7) GOTO 180 + IF(IBE.EQ.1.AND.MAX(NBE(1)-NBE(0),NBE(2)-NBE(1),NBE(3)-NBE(2)) + &.LE.1) GOTO 180 + IF(IBE.EQ.4.AND.MAX(NBE(4)-NBE(3),NBE(5)-NBE(4),NBE(6)-NBE(5), + &NBE(7)-NBE(6)).LE.1) GOTO 180 + IF(IBE.GE.8.AND.NBE(IBE)-NBE(IBE-1).LE.1) GOTO 180 + IF(IBE.EQ.1) PMHQ=2.*ULMASS(211) + IF(IBE.EQ.4) PMHQ=2.*ULMASS(321) + IF(IBE.EQ.8) PMHQ=2.*ULMASS(221) + IF(IBE.EQ.9) PMHQ=2.*ULMASS(331) + QDEL=0.1*MIN(PMHQ,PARJ(93)) + IF(MSTJ(51).EQ.1) THEN + NBIN=MIN(100,NINT(9.*PARJ(93)/QDEL)) + BEEX=EXP(0.5*QDEL/PARJ(93)) + BERT=EXP(-QDEL/PARJ(93)) + ELSE + NBIN=MIN(100,NINT(3.*PARJ(93)/QDEL)) + ENDIF + DO 170 IBIN=1,NBIN + QBIN=QDEL*(IBIN-0.5) + BEI(IBIN)=QDEL*(QBIN**2+QDEL**2/12.)/SQRT(QBIN**2+PMHQ**2) + IF(MSTJ(51).EQ.1) THEN + BEEX=BEEX*BERT + BEI(IBIN)=BEI(IBIN)*BEEX + ELSE + BEI(IBIN)=BEI(IBIN)*EXP(-(QBIN/PARJ(93))**2) + ENDIF + IF(IBIN.GE.2) BEI(IBIN)=BEI(IBIN)+BEI(IBIN-1) + 170 CONTINUE + +C...Loop through particle pairs and find old relative momentum. + 180 DO 210 I1M=NBE(IBE-1)+1,NBE(IBE)-1 + I1=K(I1M,1) + DO 200 I2M=I1M+1,NBE(IBE) + I2=K(I2M,1) + Q2OLD=MAX(0.D0,(P(I1,4)+P(I2,4))**2-(P(I1,1)+P(I2,1))**2-(P(I1,2)+ + &P(I2,2))**2-(P(I1,3)+P(I2,3))**2-(P(I1,5)+P(I2,5))**2) + QOLD=SQRT(Q2OLD) + +C...Calculate new relative momentum. + IF(QOLD.LT.1D-3*QDEL) THEN + GOTO 200 + ELSEIF(QOLD.LE.QDEL) THEN + QMOV=QOLD/3. + ELSEIF(QOLD.LT.(NBIN-0.1)*QDEL) THEN + RBIN=QOLD/QDEL + IBIN=RBIN + RINP=(RBIN**3-IBIN**3)/(3*IBIN*(IBIN+1)+1) + QMOV=(BEI(IBIN)+RINP*(BEI(IBIN+1)-BEI(IBIN)))* + & SQRT(Q2OLD+PMHQ**2)/Q2OLD + ELSE + QMOV=BEI(NBIN)*SQRT(Q2OLD+PMHQ**2)/Q2OLD + ENDIF + Q2NEW=Q2OLD*(QOLD/(QOLD+3.*PARJ(92)*QMOV))**(2./3.) + +C...Calculate and save shift to be performed on three-momenta. + HC1=(P(I1,4)+P(I2,4))**2-(Q2OLD-Q2NEW) + HC2=(Q2OLD-Q2NEW)*(P(I1,4)-P(I2,4))**2 + HA=0.5*(1.-SQRT(HC1*Q2NEW/(HC1*Q2OLD-HC2))) + DO 190 J=1,3 + PD=HA*(P(I2,J)-P(I1,J)) + P(I1M,J)=P(I1M,J)+PD + P(I2M,J)=P(I2M,J)-PD + 190 CONTINUE + 200 CONTINUE + 210 CONTINUE + 220 CONTINUE + +C...Shift momenta and recalculate energies. + DO 240 IM=NBE(0)+1,NBE(MIN(9,MSTJ(52))) + I=K(IM,1) + DO 230 J=1,3 + P(I,J)=P(I,J)+P(IM,J) + 230 CONTINUE + P(I,4)=SQRT(P(I,5)**2+P(I,1)**2+P(I,2)**2+P(I,3)**2) + 240 CONTINUE + +C...Rescale all momenta for energy conservation. + PES=0. + PQS=0. + DO 250 I=1,N + IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 250 + PES=PES+P(I,4) + PQS=PQS+P(I,5)**2/P(I,4) + 250 CONTINUE + FAC=(PECM-PQS)/(PES-PQS) + DO 270 I=1,N + IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 270 + DO 260 J=1,3 + P(I,J)=FAC*P(I,J) + 260 CONTINUE + P(I,4)=SQRT(P(I,5)**2+P(I,1)**2+P(I,2)**2+P(I,3)**2) + 270 CONTINUE + +C...Boost back to correct reference frame. + 280 CALL + & LUDBRB(0,0,0.D0,0.D0,DPS(1)/DPS(4),DPS(2)/DPS(4),DPS(3)/DPS(4)) + DO 290 I=1,N + IF(K(I,1).LT.0) K(I,1)=-K(I,1) + 290 CONTINUE + + RETURN + END + +C********************************************************************* + +CDECK ID>, ULMASS + FUNCTION ULMASS(KF) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to give the mass of a particle/parton. + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUDAT1/,/LUDAT2/ + +C...Reset variables. Compressed code. + ULMASS=0. + KFA=IABS(KF) + KC=LUCOMP(KF) + IF(KC.EQ.0) RETURN + PARF(106)=PMAS(6,1) + PARF(107)=PMAS(7,1) + PARF(108)=PMAS(8,1) + +C...Guarantee use of constituent masses for internal checks. + IF((MSTJ(93).EQ.1.OR.MSTJ(93).EQ.2).AND.KFA.LE.10) THEN + ULMASS=PARF(100+KFA) + IF(MSTJ(93).EQ.2) ULMASS=MAX(0.D0,ULMASS-PARF(121)) + +C...Masses that can be read directly off table. + ELSEIF(KFA.LE.100.OR.KC.LE.80.OR.KC.GT.100) THEN + ULMASS=PMAS(KC,1) + +C...Find constituent partons and their masses. + ELSE + KFLA=MOD(KFA/1000,10) + KFLB=MOD(KFA/100,10) + KFLC=MOD(KFA/10,10) + KFLS=MOD(KFA,10) + KFLR=MOD(KFA/10000,10) + PMA=PARF(100+KFLA) + PMB=PARF(100+KFLB) + PMC=PARF(100+KFLC) + +C...Construct masses for various meson, diquark and baryon cases. + IF(KFLA.EQ.0.AND.KFLR.EQ.0.AND.KFLS.LE.3) THEN + IF(KFLS.EQ.1) PMSPL=-3./(PMB*PMC) + IF(KFLS.GE.3) PMSPL=1./(PMB*PMC) + ULMASS=PARF(111)+PMB+PMC+PARF(113)*PARF(101)**2*PMSPL + ELSEIF(KFLA.EQ.0) THEN + KMUL=2 + IF(KFLS.EQ.1) KMUL=3 + IF(KFLR.EQ.2) KMUL=4 + IF(KFLS.EQ.5) KMUL=5 + ULMASS=PARF(113+KMUL)+PMB+PMC + ELSEIF(KFLC.EQ.0) THEN + IF(KFLS.EQ.1) PMSPL=-3./(PMA*PMB) + IF(KFLS.EQ.3) PMSPL=1./(PMA*PMB) + ULMASS=2.*PARF(112)/3.+PMA+PMB+PARF(114)*PARF(101)**2*PMSPL + IF(MSTJ(93).EQ.1) ULMASS=PMA+PMB + IF(MSTJ(93).EQ.2) ULMASS=MAX(0.D0,ULMASS-PARF(122)- + & 2.*PARF(112)/3.) + ELSE + IF(KFLS.EQ.2.AND.KFLA.EQ.KFLB) THEN + PMSPL=1./(PMA*PMB)-2./(PMA*PMC)-2./(PMB*PMC) + ELSEIF(KFLS.EQ.2.AND.KFLB.GE.KFLC) THEN + PMSPL=-2./(PMA*PMB)-2./(PMA*PMC)+1./(PMB*PMC) + ELSEIF(KFLS.EQ.2) THEN + PMSPL=-3./(PMB*PMC) + ELSE + PMSPL=1./(PMA*PMB)+1./(PMA*PMC)+1./(PMB*PMC) + ENDIF + ULMASS=PARF(112)+PMA+PMB+PMC+PARF(114)*PARF(101)**2*PMSPL + ENDIF + ENDIF + +C...Optional mass broadening according to truncated Breit-Wigner +C...(either in m or in m^2). + IF(MSTJ(24).GE.1.AND.PMAS(KC,2).GT.1D-4) THEN + IF(MSTJ(24).EQ.1.OR.(MSTJ(24).EQ.2.AND.KFA.GT.100)) THEN + ULMASS=ULMASS+0.5*PMAS(KC,2)*TAN((2.*RLU(0)-1.)* + & ATAN(2.*PMAS(KC,3)/PMAS(KC,2))) + ELSE + PM0=ULMASS + PMLOW=ATAN((MAX(0.D0,PM0-PMAS(KC,3))**2-PM0**2)/ + & (PM0*PMAS(KC,2))) + PMUPP=ATAN(((PM0+PMAS(KC,3))**2-PM0**2)/(PM0*PMAS(KC,2))) + ULMASS=SQRT(MAX(0.D0,PM0**2+PM0*PMAS(KC,2)*TAN(PMLOW+ + & (PMUPP-PMLOW)*RLU(0)))) + ENDIF + ENDIF + MSTJ(93)=0 + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUNAME + SUBROUTINE LUNAME(KF,CHAU) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to give the particle/parton name as a character string. + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + COMMON/LUDAT4/CHAF(500) + CHARACTER CHAF*8 + SAVE /LUDAT1/,/LUDAT2/,/LUDAT4/ + CHARACTER CHAU*16 + +C...Initial values. Charge. Subdivide code. + CHAU=' ' + KFA=IABS(KF) + KC=LUCOMP(KF) + IF(KC.EQ.0) RETURN + KQ=LUCHGE(KF) + KFLA=MOD(KFA/1000,10) + KFLB=MOD(KFA/100,10) + KFLC=MOD(KFA/10,10) + KFLS=MOD(KFA,10) + KFLR=MOD(KFA/10000,10) + +C...Read out root name and spin for simple particle. + IF(KFA.LE.100.OR.(KFA.GT.100.AND.KC.GT.100)) THEN + CHAU=CHAF(KC) + LEN=0 + DO 100 LEM=1,8 + IF(CHAU(LEM:LEM).NE.' ') LEN=LEM + 100 CONTINUE + +C...Construct root name for diquark. Add on spin. + ELSEIF(KFLC.EQ.0) THEN + CHAU(1:2)=CHAF(KFLA)(1:1)//CHAF(KFLB)(1:1) + IF(KFLS.EQ.1) CHAU(3:4)='_0' + IF(KFLS.EQ.3) CHAU(3:4)='_1' + LEN=4 + +C...Construct root name for heavy meson. Add on spin and heavy flavour. + ELSEIF(KFLA.EQ.0) THEN + IF(KFLB.EQ.5) CHAU(1:1)='B' + IF(KFLB.EQ.6) CHAU(1:1)='T' + IF(KFLB.EQ.7) CHAU(1:1)='L' + IF(KFLB.EQ.8) CHAU(1:1)='H' + LEN=1 + IF(KFLR.EQ.0.AND.KFLS.EQ.1) THEN + ELSEIF(KFLR.EQ.0.AND.KFLS.EQ.3) THEN + CHAU(2:2)='*' + LEN=2 + ELSEIF(KFLR.EQ.1.AND.KFLS.EQ.3) THEN + CHAU(2:3)='_1' + LEN=3 + ELSEIF(KFLR.EQ.1.AND.KFLS.EQ.1) THEN + CHAU(2:4)='*_0' + LEN=4 + ELSEIF(KFLR.EQ.2) THEN + CHAU(2:4)='*_1' + LEN=4 + ELSEIF(KFLS.EQ.5) THEN + CHAU(2:4)='*_2' + LEN=4 + ENDIF + IF(KFLC.GE.3.AND.KFLR.EQ.0.AND.KFLS.LE.3) THEN + CHAU(LEN+1:LEN+2)='_'//CHAF(KFLC)(1:1) + LEN=LEN+2 + ELSEIF(KFLC.GE.3) THEN + CHAU(LEN+1:LEN+1)=CHAF(KFLC)(1:1) + LEN=LEN+1 + ENDIF + +C...Construct root name and spin for heavy baryon. + ELSE + IF(KFLB.LE.2.AND.KFLC.LE.2) THEN + CHAU='Sigma ' + IF(KFLC.GT.KFLB) CHAU='Lambda' + IF(KFLS.EQ.4) CHAU='Sigma*' + LEN=5 + IF(CHAU(6:6).NE.' ') LEN=6 + ELSEIF(KFLB.LE.2.OR.KFLC.LE.2) THEN + CHAU='Xi ' + IF(KFLA.GT.KFLB.AND.KFLB.GT.KFLC) CHAU='Xi''' + IF(KFLS.EQ.4) CHAU='Xi*' + LEN=2 + IF(CHAU(3:3).NE.' ') LEN=3 + ELSE + CHAU='Omega ' + IF(KFLA.GT.KFLB.AND.KFLB.GT.KFLC) CHAU='Omega''' + IF(KFLS.EQ.4) CHAU='Omega*' + LEN=5 + IF(CHAU(6:6).NE.' ') LEN=6 + ENDIF + +C...Add on heavy flavour content for heavy baryon. + CHAU(LEN+1:LEN+2)='_'//CHAF(KFLA)(1:1) + LEN=LEN+2 + IF(KFLB.GE.KFLC.AND.KFLC.GE.4) THEN + CHAU(LEN+1:LEN+2)=CHAF(KFLB)(1:1)//CHAF(KFLC)(1:1) + LEN=LEN+2 + ELSEIF(KFLB.GE.KFLC.AND.KFLB.GE.4) THEN + CHAU(LEN+1:LEN+1)=CHAF(KFLB)(1:1) + LEN=LEN+1 + ELSEIF(KFLC.GT.KFLB.AND.KFLB.GE.4) THEN + CHAU(LEN+1:LEN+2)=CHAF(KFLC)(1:1)//CHAF(KFLB)(1:1) + LEN=LEN+2 + ELSEIF(KFLC.GT.KFLB.AND.KFLC.GE.4) THEN + CHAU(LEN+1:LEN+1)=CHAF(KFLC)(1:1) + LEN=LEN+1 + ENDIF + ENDIF + +C...Add on bar sign for antiparticle (where necessary). + IF(KF.GT.0.OR.LEN.EQ.0) THEN + ELSEIF(KFA.GT.10.AND.KFA.LE.40.AND.KQ.NE.0.AND.MOD(KQ,3).EQ.0) + &THEN + ELSEIF(KFA.EQ.89.OR.(KFA.GE.91.AND.KFA.LE.99)) THEN + ELSEIF(KFA.GT.100.AND.KFLA.EQ.0.AND.KQ.NE.0) THEN + ELSEIF(MSTU(15).LE.1) THEN + CHAU(LEN+1:LEN+1)='~' + LEN=LEN+1 + ELSE + CHAU(LEN+1:LEN+3)='bar' + LEN=LEN+3 + ENDIF + +C...Add on charge where applicable (conventional cases skipped). + IF(KQ.EQ.6) CHAU(LEN+1:LEN+2)='++' + IF(KQ.EQ.-6) CHAU(LEN+1:LEN+2)='--' + IF(KQ.EQ.3) CHAU(LEN+1:LEN+1)='+' + IF(KQ.EQ.-3) CHAU(LEN+1:LEN+1)='-' + IF(KQ.EQ.0.AND.(KFA.LE.22.OR.LEN.EQ.0)) THEN + ELSEIF(KQ.EQ.0.AND.(KFA.GE.81.AND.KFA.LE.100)) THEN + ELSEIF(KFA.EQ.28.OR.KFA.EQ.29) THEN + ELSEIF(KFA.GT.100.AND.KFLA.EQ.0.AND.KFLB.EQ.KFLC.AND. + &KFLB.NE.1) THEN + ELSEIF(KQ.EQ.0) THEN + CHAU(LEN+1:LEN+1)='0' + ENDIF + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUCHGE + FUNCTION LUCHGE(KF) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to give three times the charge for a particle/parton. + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUDAT2/ + +C...Initial values. Simple case of direct readout. + LUCHGE=0 + KFA=IABS(KF) + KC=LUCOMP(KFA) + IF(KC.EQ.0) THEN + ELSEIF(KFA.LE.100.OR.KC.LE.80.OR.KC.GT.100) THEN + LUCHGE=KCHG(KC,1) + +C...Construction from quark content for heavy meson, diquark, baryon. + ELSEIF(MOD(KFA/1000,10).EQ.0) THEN + LUCHGE=(KCHG(MOD(KFA/100,10),1)-KCHG(MOD(KFA/10,10),1))* + & (-1)**MOD(KFA/100,10) + ELSEIF(MOD(KFA/10,10).EQ.0) THEN + LUCHGE=KCHG(MOD(KFA/1000,10),1)+KCHG(MOD(KFA/100,10),1) + ELSE + LUCHGE=KCHG(MOD(KFA/1000,10),1)+KCHG(MOD(KFA/100,10),1)+ + & KCHG(MOD(KFA/10,10),1) + ENDIF + +C...Add on correct sign. + LUCHGE=LUCHGE*ISIGN(1,KF) + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUCOMP + FUNCTION LUCOMP(KF) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to compress the standard KF codes for use in mass and decay +C...arrays; also to check whether a given code actually is defined. + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUDAT2/ + DIMENSION KFTAB(25),KCTAB(25) + DATA KFTAB/211,111,221,311,321,130,310,213,113,223, + &313,323,2112,2212,210,2110,2210,110,220,330,440,30443,30553,0,0/ + DATA KCTAB/101,111,112,102,103,221,222,121,131,132, + &122,123,332,333,281,282,283,284,285,286,287,231,235,0,0/ + +C...Starting values. + LUCOMP=0 + KFA=IABS(KF) + +C...Simple cases: direct translation or table. + IF(KFA.EQ.0.OR.KFA.GE.100000) THEN + RETURN + ELSEIF(KFA.LE.100) THEN + LUCOMP=KFA + IF(KF.LT.0.AND.KCHG(KFA,3).EQ.0) LUCOMP=0 + RETURN + ELSE + DO 100 IKF=1,23 + IF(KFA.EQ.KFTAB(IKF)) THEN + LUCOMP=KCTAB(IKF) + IF(KF.LT.0.AND.KCHG(LUCOMP,3).EQ.0) LUCOMP=0 + RETURN + ENDIF + 100 CONTINUE + ENDIF + +C...Subdivide KF code into constituent pieces. + KFLA=MOD(KFA/1000,10) + KFLB=MOD(KFA/100,10) + KFLC=MOD(KFA/10,10) + KFLS=MOD(KFA,10) + KFLR=MOD(KFA/10000,10) + +C...Mesons. + IF(KFA-10000*KFLR.LT.1000) THEN + IF(KFLB.EQ.0.OR.KFLB.EQ.9.OR.KFLC.EQ.0.OR.KFLC.EQ.9) THEN + ELSEIF(KFLB.LT.KFLC) THEN + ELSEIF(KF.LT.0.AND.KFLB.EQ.KFLC) THEN + ELSEIF(KFLB.EQ.KFLC) THEN + IF(KFLR.EQ.0.AND.KFLS.EQ.1) THEN + LUCOMP=110+KFLB + ELSEIF(KFLR.EQ.0.AND.KFLS.EQ.3) THEN + LUCOMP=130+KFLB + ELSEIF(KFLR.EQ.1.AND.KFLS.EQ.3) THEN + LUCOMP=150+KFLB + ELSEIF(KFLR.EQ.1.AND.KFLS.EQ.1) THEN + LUCOMP=170+KFLB + ELSEIF(KFLR.EQ.2.AND.KFLS.EQ.3) THEN + LUCOMP=190+KFLB + ELSEIF(KFLR.EQ.0.AND.KFLS.EQ.5) THEN + LUCOMP=210+KFLB + ENDIF + ELSEIF(KFLB.LE.5) THEN + IF(KFLR.EQ.0.AND.KFLS.EQ.1) THEN + LUCOMP=100+((KFLB-1)*(KFLB-2))/2+KFLC + ELSEIF(KFLR.EQ.0.AND.KFLS.EQ.3) THEN + LUCOMP=120+((KFLB-1)*(KFLB-2))/2+KFLC + ELSEIF(KFLR.EQ.1.AND.KFLS.EQ.3) THEN + LUCOMP=140+((KFLB-1)*(KFLB-2))/2+KFLC + ELSEIF(KFLR.EQ.1.AND.KFLS.EQ.1) THEN + LUCOMP=160+((KFLB-1)*(KFLB-2))/2+KFLC + ELSEIF(KFLR.EQ.2.AND.KFLS.EQ.3) THEN + LUCOMP=180+((KFLB-1)*(KFLB-2))/2+KFLC + ELSEIF(KFLR.EQ.0.AND.KFLS.EQ.5) THEN + LUCOMP=200+((KFLB-1)*(KFLB-2))/2+KFLC + ENDIF + ELSEIF((KFLS.EQ.1.AND.KFLR.LE.1).OR.(KFLS.EQ.3.AND.KFLR.LE.2) + & .OR.(KFLS.EQ.5.AND.KFLR.EQ.0)) THEN + LUCOMP=80+KFLB + ENDIF + +C...Diquarks. + ELSEIF((KFLR.EQ.0.OR.KFLR.EQ.1).AND.KFLC.EQ.0) THEN + IF(KFLS.NE.1.AND.KFLS.NE.3) THEN + ELSEIF(KFLA.EQ.9.OR.KFLB.EQ.0.OR.KFLB.EQ.9) THEN + ELSEIF(KFLA.LT.KFLB) THEN + ELSEIF(KFLS.EQ.1.AND.KFLA.EQ.KFLB) THEN + ELSE + LUCOMP=90 + ENDIF + +C...Spin 1/2 baryons. + ELSEIF(KFLR.EQ.0.AND.KFLS.EQ.2) THEN + IF(KFLA.EQ.9.OR.KFLB.EQ.0.OR.KFLB.EQ.9.OR.KFLC.EQ.9) THEN + ELSEIF(KFLA.LE.KFLC.OR.KFLA.LT.KFLB) THEN + ELSEIF(KFLA.GE.6.OR.KFLB.GE.4.OR.KFLC.GE.4) THEN + LUCOMP=80+KFLA + ELSEIF(KFLB.LT.KFLC) THEN + LUCOMP=300+((KFLA+1)*KFLA*(KFLA-1))/6+(KFLC*(KFLC-1))/2+KFLB + ELSE + LUCOMP=330+((KFLA+1)*KFLA*(KFLA-1))/6+(KFLB*(KFLB-1))/2+KFLC + ENDIF + +C...Spin 3/2 baryons. + ELSEIF(KFLR.EQ.0.AND.KFLS.EQ.4) THEN + IF(KFLA.EQ.9.OR.KFLB.EQ.0.OR.KFLB.EQ.9.OR.KFLC.EQ.9) THEN + ELSEIF(KFLA.LT.KFLB.OR.KFLB.LT.KFLC) THEN + ELSEIF(KFLA.GE.6.OR.KFLB.GE.4) THEN + LUCOMP=80+KFLA + ELSE + LUCOMP=360+((KFLA+1)*KFLA*(KFLA-1))/6+(KFLB*(KFLB-1))/2+KFLC + ENDIF + ENDIF + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUERRM + SUBROUTINE LUERRM(MERR,CHMESS) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to inform user of errors in program execution. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + SAVE /LUJETS/,/LUDAT1/ + CHARACTER CHMESS*(*) + +C...Write first few warnings, then be silent. + IF(MERR.LE.10) THEN + MSTU(27)=MSTU(27)+1 + MSTU(28)=MERR + IF(MSTU(25).EQ.1.AND.MSTU(27).LE.MSTU(26)) WRITE(MSTU(11),5000) + & MERR,MSTU(31),CHMESS + +C...Write first few errors, then be silent or stop program. + ELSEIF(MERR.LE.20) THEN + MSTU(23)=MSTU(23)+1 + MSTU(24)=MERR-10 + IF(MSTU(21).GE.1.AND.MSTU(23).LE.MSTU(22)) WRITE(MSTU(11),5100) + & MERR-10,MSTU(31),CHMESS + IF(MSTU(21).GE.2.AND.MSTU(23).GT.MSTU(22)) THEN + WRITE(MSTU(11),5100) MERR-10,MSTU(31),CHMESS + WRITE(MSTU(11),5200) + IF(MERR.NE.17) CALL LULIST(2) + STOP + ENDIF + +C...Stop program in case of irreparable error. + ELSE + WRITE(MSTU(11),5300) MERR-20,MSTU(31),CHMESS + STOP + ENDIF + +C...Formats for output. + 5000 FORMAT(/5X,'Advisory warning type',I2,' given after',I6, + &' LUEXEC calls:'/5X,A) + 5100 FORMAT(/5X,'Error type',I2,' has occured after',I6, + &' LUEXEC calls:'/5X,A) + 5200 FORMAT(5X,'Execution will be stopped after listing of last ', + &'event!') + 5300 FORMAT(/5X,'Fatal error type',I2,' has occured after',I6, + &' LUEXEC calls:'/5X,A/5X,'Execution will now be stopped!') + + RETURN + END + +C********************************************************************* + +CDECK ID>, ULALEM + FUNCTION ULALEM(Q2) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to calculate the running alpha_electromagnetic. + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + SAVE /LUDAT1/ + +C...Calculate real part of photon vacuum polarization. +C...For leptons simplify by using asymptotic (Q^2 >> m^2) expressions. +C...For hadrons use parametrization of H. Burkhardt et al. +C...See R. Kleiss et al, CERN 89-08, vol. 3, pp. 129-131. + AEMPI=PARU(101)/(3.*PARU(1)) + IF(MSTU(101).LE.0.OR.Q2.LT.2D-6) THEN + RPIGG=0. + ELSEIF(MSTU(101).EQ.2.AND.Q2.LT.PARU(104)) THEN + RPIGG=0. + ELSEIF(MSTU(101).EQ.2) THEN + RPIGG=1.-PARU(101)/PARU(103) + ELSEIF(Q2.LT.0.09) THEN + RPIGG=AEMPI*(13.4916+LOG(Q2))+0.00835*LOG(1.+Q2) + ELSEIF(Q2.LT.9.) THEN + RPIGG=AEMPI*(16.3200+2.*LOG(Q2))+0.00238*LOG(1.+3.927*Q2) + ELSEIF(Q2.LT.1E4) THEN + RPIGG=AEMPI*(13.4955+3.*LOG(Q2))+0.00165+0.00299*LOG(1.+Q2) + ELSE + RPIGG=AEMPI*(13.4955+3.*LOG(Q2))+0.00221+0.00293*LOG(1.+Q2) + ENDIF + +C...Calculate running alpha_em. + ULALEM=PARU(101)/(1.-RPIGG) + PARU(108)=ULALEM + + RETURN + END + +C********************************************************************* + +CDECK ID>, ULALPS + FUNCTION ULALPS(Q2) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to give the value of alpha_strong. + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUDAT1/,/LUDAT2/ + +C...Constant alpha_strong trivial. + IF(MSTU(111).LE.0) THEN + ULALPS=PARU(111) + MSTU(118)=MSTU(112) + PARU(117)=0. + PARU(118)=PARU(111) + RETURN + ENDIF + +C...Find effective Q2, number of flavours and Lambda. + Q2EFF=Q2 + IF(MSTU(115).GE.2) Q2EFF=MAX(Q2,PARU(114)) + NF=MSTU(112) + ALAM2=PARU(112)**2 + 100 IF(NF.GT.MAX(2,MSTU(113))) THEN + Q2THR=PARU(113)*PMAS(NF,1)**2 + IF(Q2EFF.LT.Q2THR) THEN + NF=NF-1 + ALAM2=ALAM2*(Q2THR/ALAM2)**(2./(33.-2.*NF)) + GOTO 100 + ENDIF + ENDIF + 110 IF(NF.LT.MIN(8,MSTU(114))) THEN + Q2THR=PARU(113)*PMAS(NF+1,1)**2 + IF(Q2EFF.GT.Q2THR) THEN + NF=NF+1 + ALAM2=ALAM2*(ALAM2/Q2THR)**(2./(33.-2.*NF)) + GOTO 110 + ENDIF + ENDIF + IF(MSTU(115).EQ.1) Q2EFF=Q2EFF+ALAM2 + PARU(117)=SQRT(ALAM2) + +C...Evaluate first or second order alpha_strong. + B0=(33.-2.*NF)/6. + ALGQ=LOG(MAX(1.0001D0,Q2EFF/ALAM2)) + IF(MSTU(111).EQ.1) THEN + ULALPS=MIN(PARU(115),PARU(2)/(B0*ALGQ)) + ELSE + B1=(153.-19.*NF)/6. + ULALPS=MIN(PARU(115),PARU(2)/(B0*ALGQ)*(1.-B1*LOG(ALGQ)/ + & (B0**2*ALGQ))) + ENDIF + MSTU(118)=NF + PARU(118)=ULALPS + + RETURN + END + +C********************************************************************* + +CDECK ID>, ULANGL + FUNCTION ULANGL(X,Y) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to reconstruct an angle from given x and y coordinates. + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + SAVE /LUDAT1/ + + ULANGL=0. + R=SQRT(X**2+Y**2) + IF(R.LT.1D-20) RETURN + IF(ABS(X)/R.LT.0.8) THEN + ULANGL=SIGN(ACOS(X/R),Y) + ELSE + ULANGL=ASIN(Y/R) + IF(X.LT.0..AND.ULANGL.GE.0.) THEN + ULANGL=PARU(1)-ULANGL + ELSEIF(X.LT.0.) THEN + ULANGL=-PARU(1)-ULANGL + ENDIF + ENDIF + + RETURN + END + +C********************************************************************* + +CDECK ID>, RLU + FUNCTION RLU(IDUMMY) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to generate random numbers uniformly distributed between +C...0 and 1, excluding the endpoints. + COMMON/LUDATR/MRLU(6),RRLU(100) + SAVE /LUDATR/ + EQUIVALENCE (MRLU1,MRLU(1)),(MRLU2,MRLU(2)),(MRLU3,MRLU(3)), + &(MRLU4,MRLU(4)),(MRLU5,MRLU(5)),(MRLU6,MRLU(6)), + &(RRLU98,RRLU(98)),(RRLU99,RRLU(99)),(RRLU00,RRLU(100)) + +C...Initialize generation from given seed. + IF(MRLU2.EQ.0) THEN + IJ=MOD(MRLU1/30082,31329) + KL=MOD(MRLU1,30082) + I=MOD(IJ/177,177)+2 + J=MOD(IJ,177)+2 + K=MOD(KL/169,178)+1 + L=MOD(KL,169) + DO 110 II=1,97 + S=0. + T=0.5 + DO 100 JJ=1,24 + M=MOD(MOD(I*J,179)*K,179) + I=J + J=K + K=M + L=MOD(53*L+1,169) + IF(MOD(L*M,64).GE.32) S=S+T + T=0.5*T + 100 CONTINUE + RRLU(II)=S + 110 CONTINUE + TWOM24=1. + DO 120 I24=1,24 + TWOM24=0.5*TWOM24 + 120 CONTINUE + RRLU98=362436.*TWOM24 + RRLU99=7654321.*TWOM24 + RRLU00=16777213.*TWOM24 + MRLU2=1 + MRLU3=0 + MRLU4=97 + MRLU5=33 + ENDIF + +C...Generate next random number. + 130 RUNI=RRLU(MRLU4)-RRLU(MRLU5) + IF(RUNI.LT.0.) RUNI=RUNI+1. + RRLU(MRLU4)=RUNI + MRLU4=MRLU4-1 + IF(MRLU4.EQ.0) MRLU4=97 + MRLU5=MRLU5-1 + IF(MRLU5.EQ.0) MRLU5=97 + RRLU98=RRLU98-RRLU99 + IF(RRLU98.LT.0.) RRLU98=RRLU98+RRLU00 + RUNI=RUNI-RRLU98 + IF(RUNI.LT.0.) RUNI=RUNI+1. + IF(RUNI.LE.0.OR.RUNI.GE.1.) GOTO 130 + +C...Update counters. Random number to output. + MRLU3=MRLU3+1 + IF(MRLU3.EQ.1000000000) THEN + MRLU2=MRLU2+1 + MRLU3=0 + ENDIF + RLU=RUNI + + RETURN + END + +C********************************************************************* + +CDECK ID>, RLUGET + SUBROUTINE RLUGET(LFN,MOVE) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to dump the state of the random number generator on a file +C...for subsequent startup from this state onwards. + COMMON/LUDATR/MRLU(6),RRLU(100) + SAVE /LUDATR/ + CHARACTER CHERR*8 + +C...Backspace required number of records (or as many as there are). + IF(MOVE.LT.0) THEN + NBCK=MIN(MRLU(6),-MOVE) + DO 100 IBCK=1,NBCK + BACKSPACE(LFN,ERR=110,IOSTAT=IERR) + 100 CONTINUE + MRLU(6)=MRLU(6)-NBCK + ENDIF + +C...Unformatted write on unit LFN. + WRITE(LFN,ERR=110,IOSTAT=IERR) (MRLU(I1),I1=1,5), + &(RRLU(I2),I2=1,100) + MRLU(6)=MRLU(6)+1 + RETURN + +C...Write error. + 110 WRITE(CHERR,'(I8)') IERR + CALL LUERRM(18,'(RLUGET:) error when accessing file, IOSTAT ='// + &CHERR) + + RETURN + END + +C********************************************************************* + +CDECK ID>, RLUSET + SUBROUTINE RLUSET(LFN,MOVE) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to read a state of the random number generator from a file +C...for subsequent generation from this state onwards. + COMMON/LUDATR/MRLU(6),RRLU(100) + SAVE /LUDATR/ + CHARACTER CHERR*8 + +C...Backspace required number of records (or as many as there are). + IF(MOVE.LT.0) THEN + NBCK=MIN(MRLU(6),-MOVE) + DO 100 IBCK=1,NBCK + BACKSPACE(LFN,ERR=120,IOSTAT=IERR) + 100 CONTINUE + MRLU(6)=MRLU(6)-NBCK + ENDIF + +C...Unformatted read from unit LFN. + NFOR=1+MAX(0,MOVE) + DO 110 IFOR=1,NFOR + READ(LFN,ERR=120,IOSTAT=IERR) (MRLU(I1),I1=1,5), + &(RRLU(I2),I2=1,100) + 110 CONTINUE + MRLU(6)=MRLU(6)+NFOR + RETURN + +C...Write error. + 120 WRITE(CHERR,'(I8)') IERR + CALL LUERRM(18,'(RLUSET:) error when accessing file, IOSTAT ='// + &CHERR) + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUROBO + SUBROUTINE LUROBO(THE,PHI,BEX,BEY,BEZ) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to perform rotations and boosts. +C IMPLICIT DOUBLE PRECISION(D) + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + SAVE /LUJETS/,/LUDAT1/ + DIMENSION ROT(3,3),PR(3),VR(3),DP(4),DV(4) + +C...Find range of rotation/boost. Convert boost to double precision. + IMIN=1 + IF(MSTU(1).GT.0) IMIN=MSTU(1) + IMAX=N + IF(MSTU(2).GT.0) IMAX=MSTU(2) + DBX=BEX + DBY=BEY + DBZ=BEZ + GOTO 120 + +C...Entry for specific range and double precision boost. + ENTRY LUDBRB(IMI,IMA,THE,PHI,DBEX,DBEY,DBEZ) + IMIN=IMI + IF(IMIN.LE.0) IMIN=1 + IMAX=IMA + IF(IMAX.LE.0) IMAX=N + DBX=DBEX + DBY=DBEY + DBZ=DBEZ + +C...Optional resetting of V (when not set before.) + IF(MSTU(33).NE.0) THEN + DO 110 I=MIN(IMIN,MSTU(4)),MIN(IMAX,MSTU(4)) + DO 100 J=1,5 + V(I,J)=0. + 100 CONTINUE + 110 CONTINUE + MSTU(33)=0 + ENDIF + +C...Check range of rotation/boost. + 120 IF(IMIN.GT.MSTU(4).OR.IMAX.GT.MSTU(4)) THEN + CALL LUERRM(11,'(LUROBO:) range outside LUJETS memory') + RETURN + ENDIF + +C...Rotate, typically from z axis to direction (theta,phi). + IF(THE**2+PHI**2.GT.1D-20) THEN + ROT(1,1)=COS(THE)*COS(PHI) + ROT(1,2)=-SIN(PHI) + ROT(1,3)=SIN(THE)*COS(PHI) + ROT(2,1)=COS(THE)*SIN(PHI) + ROT(2,2)=COS(PHI) + ROT(2,3)=SIN(THE)*SIN(PHI) + ROT(3,1)=-SIN(THE) + ROT(3,2)=0. + ROT(3,3)=COS(THE) + DO 150 I=IMIN,IMAX + IF(K(I,1).LE.0) GOTO 150 + DO 130 J=1,3 + PR(J)=P(I,J) + VR(J)=V(I,J) + 130 CONTINUE + DO 140 J=1,3 + P(I,J)=ROT(J,1)*PR(1)+ROT(J,2)*PR(2)+ROT(J,3)*PR(3) + V(I,J)=ROT(J,1)*VR(1)+ROT(J,2)*VR(2)+ROT(J,3)*VR(3) + 140 CONTINUE + 150 CONTINUE + ENDIF + +C...Boost, typically from rest to momentum/energy=beta. + IF(DBX**2+DBY**2+DBZ**2.GT.1D-20) THEN + DB=SQRT(DBX**2+DBY**2+DBZ**2) + IF(DB.GT.0.99999999D0) THEN +C...Rescale boost vector if too close to unity. + CALL LUERRM(3,'(LUROBO:) boost vector too large') + DBX=DBX*(0.99999999D0/DB) + DBY=DBY*(0.99999999D0/DB) + DBZ=DBZ*(0.99999999D0/DB) + DB=0.99999999D0 + ENDIF + DGA=1D0/SQRT(1D0-DB**2) + DO 170 I=IMIN,IMAX + IF(K(I,1).LE.0) GOTO 170 + DO 160 J=1,4 + DP(J)=P(I,J) + DV(J)=V(I,J) + 160 CONTINUE + DBP=DBX*DP(1)+DBY*DP(2)+DBZ*DP(3) + DGABP=DGA*(DGA*DBP/(1D0+DGA)+DP(4)) + P(I,1)=DP(1)+DGABP*DBX + P(I,2)=DP(2)+DGABP*DBY + P(I,3)=DP(3)+DGABP*DBZ + P(I,4)=DGA*(DP(4)+DBP) + DBV=DBX*DV(1)+DBY*DV(2)+DBZ*DV(3) + DGABV=DGA*(DGA*DBV/(1D0+DGA)+DV(4)) + V(I,1)=DV(1)+DGABV*DBX + V(I,2)=DV(2)+DGABV*DBY + V(I,3)=DV(3)+DGABV*DBZ + V(I,4)=DGA*(DV(4)+DBV) + 170 CONTINUE + ENDIF + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUEDIT + SUBROUTINE LUEDIT(MEDIT) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to perform global manipulations on the event record, +C...in particular to exclude unstable or undetectable partons/particles. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + DIMENSION NS(2),PTS(2),PLS(2) + +C...Remove unwanted partons/particles. + IF((MEDIT.GE.0.AND.MEDIT.LE.3).OR.MEDIT.EQ.5) THEN + IMAX=N + IF(MSTU(2).GT.0) IMAX=MSTU(2) + I1=MAX(1,MSTU(1))-1 + DO 110 I=MAX(1,MSTU(1)),IMAX + IF(K(I,1).EQ.0.OR.K(I,1).GT.20) GOTO 110 + IF(MEDIT.EQ.1) THEN + IF(K(I,1).GT.10) GOTO 110 + ELSEIF(MEDIT.EQ.2) THEN + IF(K(I,1).GT.10) GOTO 110 + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR.KC.EQ.18) + & GOTO 110 + ELSEIF(MEDIT.EQ.3) THEN + IF(K(I,1).GT.10) GOTO 110 + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0) GOTO 110 + IF(KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) GOTO 110 + ELSEIF(MEDIT.EQ.5) THEN + IF(K(I,1).EQ.13.OR.K(I,1).EQ.14) GOTO 110 + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0) GOTO 110 + IF(K(I,1).GE.11.AND.KCHG(KC,2).EQ.0) GOTO 110 + ENDIF + +C...Pack remaining partons/particles. Origin no longer known. + I1=I1+1 + DO 100 J=1,5 + K(I1,J)=K(I,J) + P(I1,J)=P(I,J) + V(I1,J)=V(I,J) + 100 CONTINUE + K(I1,3)=0 + 110 CONTINUE + IF(I1.LT.N) MSTU(3)=0 + IF(I1.LT.N) MSTU(70)=0 + N=I1 + +C...Selective removal of class of entries. New position of retained. + ELSEIF(MEDIT.GE.11.AND.MEDIT.LE.15) THEN + I1=0 + DO 120 I=1,N + K(I,3)=MOD(K(I,3),MSTU(5)) + IF(MEDIT.EQ.11.AND.K(I,1).LT.0) GOTO 120 + IF(MEDIT.EQ.12.AND.K(I,1).EQ.0) GOTO 120 + IF(MEDIT.EQ.13.AND.(K(I,1).EQ.11.OR.K(I,1).EQ.12.OR. + & K(I,1).EQ.15).AND.K(I,2).NE.94) GOTO 120 + IF(MEDIT.EQ.14.AND.(K(I,1).EQ.13.OR.K(I,1).EQ.14.OR. + & K(I,2).EQ.94)) GOTO 120 + IF(MEDIT.EQ.15.AND.K(I,1).GE.21) GOTO 120 + I1=I1+1 + K(I,3)=K(I,3)+MSTU(5)*I1 + 120 CONTINUE + +C...Find new event history information and replace old. + DO 140 I=1,N + IF(K(I,1).LE.0.OR.K(I,1).GT.20.OR.K(I,3)/MSTU(5).EQ.0) GOTO 140 + ID=I + 130 IM=MOD(K(ID,3),MSTU(5)) + IF(MEDIT.EQ.13.AND.IM.GT.0.AND.IM.LE.N) THEN + IF((K(IM,1).EQ.11.OR.K(IM,1).EQ.12.OR.K(IM,1).EQ.15).AND. + & K(IM,2).NE.94) THEN + ID=IM + GOTO 130 + ENDIF + ELSEIF(MEDIT.EQ.14.AND.IM.GT.0.AND.IM.LE.N) THEN + IF(K(IM,1).EQ.13.OR.K(IM,1).EQ.14.OR.K(IM,2).EQ.94) THEN + ID=IM + GOTO 130 + ENDIF + ENDIF + K(I,3)=MSTU(5)*(K(I,3)/MSTU(5)) + IF(IM.NE.0) K(I,3)=K(I,3)+K(IM,3)/MSTU(5) + IF(K(I,1).NE.3.AND.K(I,1).NE.13.AND.K(I,1).NE.14) THEN + IF(K(I,4).GT.0.AND.K(I,4).LE.MSTU(4)) K(I,4)= + & K(K(I,4),3)/MSTU(5) + IF(K(I,5).GT.0.AND.K(I,5).LE.MSTU(4)) K(I,5)= + & K(K(I,5),3)/MSTU(5) + ELSE + KCM=MOD(K(I,4)/MSTU(5),MSTU(5)) + IF(KCM.GT.0.AND.KCM.LE.MSTU(4)) KCM=K(KCM,3)/MSTU(5) + KCD=MOD(K(I,4),MSTU(5)) + IF(KCD.GT.0.AND.KCD.LE.MSTU(4)) KCD=K(KCD,3)/MSTU(5) + K(I,4)=MSTU(5)**2*(K(I,4)/MSTU(5)**2)+MSTU(5)*KCM+KCD + KCM=MOD(K(I,5)/MSTU(5),MSTU(5)) + IF(KCM.GT.0.AND.KCM.LE.MSTU(4)) KCM=K(KCM,3)/MSTU(5) + KCD=MOD(K(I,5),MSTU(5)) + IF(KCD.GT.0.AND.KCD.LE.MSTU(4)) KCD=K(KCD,3)/MSTU(5) + K(I,5)=MSTU(5)**2*(K(I,5)/MSTU(5)**2)+MSTU(5)*KCM+KCD + ENDIF + 140 CONTINUE + +C...Pack remaining entries. + I1=0 + MSTU90=MSTU(90) + MSTU(90)=0 + DO 170 I=1,N + IF(K(I,3)/MSTU(5).EQ.0) GOTO 170 + I1=I1+1 + DO 150 J=1,5 + K(I1,J)=K(I,J) + P(I1,J)=P(I,J) + V(I1,J)=V(I,J) + 150 CONTINUE + K(I1,3)=MOD(K(I1,3),MSTU(5)) + DO 160 IZ=1,MSTU90 + IF(I.EQ.MSTU(90+IZ)) THEN + MSTU(90)=MSTU(90)+1 + MSTU(90+MSTU(90))=I1 + PARU(90+MSTU(90))=PARU(90+IZ) + ENDIF + 160 CONTINUE + 170 CONTINUE + IF(I1.LT.N) MSTU(3)=0 + IF(I1.LT.N) MSTU(70)=0 + N=I1 + +C...Fill in some missing daughter pointers (lost in colour flow). + ELSEIF(MEDIT.EQ.16) THEN + DO 190 I=1,N + IF(K(I,1).LE.10.OR.K(I,1).GT.20) GOTO 190 + IF(K(I,4).NE.0.OR.K(I,5).NE.0) GOTO 190 +C...Find daughters who point to mother. + DO 180 I1=I+1,N + IF(K(I1,3).NE.I) THEN + ELSEIF(K(I,4).EQ.0) THEN + K(I,4)=I1 + ELSE + K(I,5)=I1 + ENDIF + 180 CONTINUE + IF(K(I,5).EQ.0) K(I,5)=K(I,4) + IF(K(I,4).NE.0) GOTO 190 +C...Find daughters who point to documentation version of mother. + IM=K(I,3) + IF(IM.LE.0.OR.IM.GE.I) GOTO 190 + IF(K(IM,1).LE.20.OR.K(IM,1).GT.30) GOTO 190 + IF(K(IM,2).NE.K(I,2).OR.ABS(P(IM,5)-P(I,5)).GT.1D-2) GOTO 190 + DO 182 I1=I+1,N + IF(K(I1,3).NE.IM) THEN + ELSEIF(K(I,4).EQ.0) THEN + K(I,4)=I1 + ELSE + K(I,5)=I1 + ENDIF + 182 CONTINUE + IF(K(I,5).EQ.0) K(I,5)=K(I,4) + IF(K(I,4).NE.0) GOTO 190 +C...Find daughters who point to documentation daughters who, +C...in their turn, point to documentation mother. + ID1=IM + ID2=IM + DO 184 I1=IM+1,I-1 + IF(K(I1,3).EQ.IM.AND.K(I1,1).GT.20.AND.K(I1,1).LE.30) THEN + ID2=I1 + IF(ID1.EQ.IM) ID1=I1 + ENDIF + 184 CONTINUE + DO 186 I1=I+1,N + IF(K(I1,3).NE.ID1.AND.K(I1,3).NE.ID2) THEN + ELSEIF(K(I,4).EQ.0) THEN + K(I,4)=I1 + ELSE + K(I,5)=I1 + ENDIF + 186 CONTINUE + IF(K(I,5).EQ.0) K(I,5)=K(I,4) + 190 CONTINUE + +C...Save top entries at bottom of LUJETS commonblock. + ELSEIF(MEDIT.EQ.21) THEN + IF(2*N.GE.MSTU(4)) THEN + CALL LUERRM(11,'(LUEDIT:) no more memory left in LUJETS') + RETURN + ENDIF + DO 210 I=1,N + DO 200 J=1,5 + K(MSTU(4)-I,J)=K(I,J) + P(MSTU(4)-I,J)=P(I,J) + V(MSTU(4)-I,J)=V(I,J) + 200 CONTINUE + 210 CONTINUE + MSTU(32)=N + +C...Restore bottom entries of commonblock LUJETS to top. + ELSEIF(MEDIT.EQ.22) THEN + DO 230 I=1,MSTU(32) + DO 220 J=1,5 + K(I,J)=K(MSTU(4)-I,J) + P(I,J)=P(MSTU(4)-I,J) + V(I,J)=V(MSTU(4)-I,J) + 220 CONTINUE + 230 CONTINUE + N=MSTU(32) + +C...Mark primary entries at top of commonblock LUJETS as untreated. + ELSEIF(MEDIT.EQ.23) THEN + I1=0 + DO 240 I=1,N + KH=K(I,3) + IF(KH.GE.1) THEN + IF(K(KH,1).GT.20) KH=0 + ENDIF + IF(KH.NE.0) GOTO 250 + I1=I1+1 + IF(K(I,1).GT.10.AND.K(I,1).LE.20) K(I,1)=K(I,1)-10 + 240 CONTINUE + 250 N=I1 + +C...Place largest axis along z axis and second largest in xy plane. + ELSEIF(MEDIT.EQ.31.OR.MEDIT.EQ.32) THEN + CALL LUDBRB(1,N+MSTU(3),0.D0,-ULANGL(P(MSTU(61),1), + & P(MSTU(61),2)),0D0,0D0,0D0) + CALL LUDBRB(1,N+MSTU(3),-ULANGL(P(MSTU(61),3), + & P(MSTU(61),1)),0.D0,0D0,0D0,0D0) + CALL LUDBRB(1,N+MSTU(3),0.D0,-ULANGL(P(MSTU(61)+1,1), + & P(MSTU(61)+1,2)),0D0,0D0,0D0) + IF(MEDIT.EQ.31) RETURN + +C...Rotate to put slim jet along +z axis. + DO 260 IS=1,2 + NS(IS)=0 + PTS(IS)=0. + PLS(IS)=0. + 260 CONTINUE + DO 270 I=1,N + IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 270 + IF(MSTU(41).GE.2) THEN + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR. + & KC.EQ.18) GOTO 270 + IF(MSTU(41).GE.3.AND.KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) + & GOTO 270 + ENDIF + IS=2.-SIGN(0.5D0,P(I,3)) + NS(IS)=NS(IS)+1 + PTS(IS)=PTS(IS)+SQRT(P(I,1)**2+P(I,2)**2) + 270 CONTINUE + IF(NS(1)*PTS(2)**2.LT.NS(2)*PTS(1)**2) + & CALL LUDBRB(1,N+MSTU(3),PARU(1),0.D0,0D0,0D0,0D0) + +C...Rotate to put second largest jet into -z,+x quadrant. + DO 280 I=1,N + IF(P(I,3).GE.0.) GOTO 280 + IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 280 + IF(MSTU(41).GE.2) THEN + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR. + & KC.EQ.18) GOTO 280 + IF(MSTU(41).GE.3.AND.KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) + & GOTO 280 + ENDIF + IS=2.-SIGN(0.5D0,P(I,1)) + PLS(IS)=PLS(IS)-P(I,3) + 280 CONTINUE + IF(PLS(2).GT.PLS(1)) CALL LUDBRB(1,N+MSTU(3),0.D0,PARU(1), + & 0D0,0D0,0D0) + ENDIF + + RETURN + END + +C********************************************************************* + +CDECK ID>, LULIST + SUBROUTINE LULIST(MLIST) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to give program heading, or list an event, or particle +C...data, or current parameter values. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/,/LUDAT3/ + CHARACTER CHAP*16,CHAC*16,CHAN*16,CHAD(5)*16,CHDL(7)*4 + DIMENSION PS(6) + DATA CHDL/'(())',' ','()','!!','<>','==','(==)'/ + +C...Initialization printout: version number and date of last change. + IF(MLIST.EQ.0.OR.MSTU(12).EQ.1) THEN + CALL LULOGO + MSTU(12)=0 + IF(MLIST.EQ.0) RETURN + ENDIF + +C...List event data, including additional lines after N. + IF(MLIST.GE.1.AND.MLIST.LE.3) THEN + IF(MLIST.EQ.1) WRITE(MSTU(11),5100) + IF(MLIST.EQ.2) WRITE(MSTU(11),5200) + IF(MLIST.EQ.3) WRITE(MSTU(11),5300) + LMX=12 + IF(MLIST.GE.2) LMX=16 + ISTR=0 + IMAX=N + IF(MSTU(2).GT.0) IMAX=MSTU(2) + DO 120 I=MAX(1,MSTU(1)),MAX(IMAX,N+MAX(0,MSTU(3))) + IF((I.GT.IMAX.AND.I.LE.N).OR.K(I,1).LT.0) GOTO 120 + +C...Get particle name, pad it and check it is not too long. + CALL LUNAME(K(I,2),CHAP) + LEN=0 + DO 100 LEM=1,16 + IF(CHAP(LEM:LEM).NE.' ') LEN=LEM + 100 CONTINUE + MDL=(K(I,1)+19)/10 + LDL=0 + IF(MDL.EQ.2.OR.MDL.GE.8) THEN + CHAC=CHAP + IF(LEN.GT.LMX) CHAC(LMX:LMX)='?' + ELSE + LDL=1 + IF(MDL.EQ.1.OR.MDL.EQ.7) LDL=2 + IF(LEN.EQ.0) THEN + CHAC=CHDL(MDL)(1:2*LDL)//' ' + ELSE + CHAC=CHDL(MDL)(1:LDL)//CHAP(1:MIN(LEN,LMX-2*LDL))// + & CHDL(MDL)(LDL+1:2*LDL)//' ' + IF(LEN+2*LDL.GT.LMX) CHAC(LMX:LMX)='?' + ENDIF + ENDIF + +C...Add information on string connection. + IF(K(I,1).EQ.1.OR.K(I,1).EQ.2.OR.K(I,1).EQ.11.OR.K(I,1).EQ.12) + & THEN + KC=LUCOMP(K(I,2)) + KCC=0 + IF(KC.NE.0) KCC=KCHG(KC,2) + IF(IABS(K(I,2)).EQ.39) THEN + IF(LEN+2*LDL+3.LE.LMX) CHAC(LMX-1:LMX-1)='X' + ELSEIF(KCC.NE.0.AND.ISTR.EQ.0) THEN + ISTR=1 + IF(LEN+2*LDL+3.LE.LMX) CHAC(LMX-1:LMX-1)='A' + ELSEIF(KCC.NE.0.AND.(K(I,1).EQ.2.OR.K(I,1).EQ.12)) THEN + IF(LEN+2*LDL+3.LE.LMX) CHAC(LMX-1:LMX-1)='I' + ELSEIF(KCC.NE.0) THEN + ISTR=0 + IF(LEN+2*LDL+3.LE.LMX) CHAC(LMX-1:LMX-1)='V' + ENDIF + ENDIF + +C...Write data for particle/jet. + IF(MLIST.EQ.1.AND.ABS(P(I,4)).LT.9999.) THEN + WRITE(MSTU(11),5400) I,CHAC(1:12),(K(I,J1),J1=1,3), + & (P(I,J2),J2=1,5) + ELSEIF(MLIST.EQ.1.AND.ABS(P(I,4)).LT.99999.) THEN + WRITE(MSTU(11),5500) I,CHAC(1:12),(K(I,J1),J1=1,3), + & (P(I,J2),J2=1,5) + ELSEIF(MLIST.EQ.1) THEN + WRITE(MSTU(11),5600) I,CHAC(1:12),(K(I,J1),J1=1,3), + & (P(I,J2),J2=1,5) + ELSEIF(MSTU(5).EQ.10000.AND.(K(I,1).EQ.3.OR.K(I,1).EQ.13.OR. + & K(I,1).EQ.14)) THEN + WRITE(MSTU(11),5700) I,CHAC,(K(I,J1),J1=1,3), + & K(I,4)/100000000,MOD(K(I,4)/10000,10000),MOD(K(I,4),10000), + & K(I,5)/100000000,MOD(K(I,5)/10000,10000),MOD(K(I,5),10000), + & (P(I,J2),J2=1,5) + ELSE + WRITE(MSTU(11),5800) I,CHAC,(K(I,J1),J1=1,5),(P(I,J2),J2=1,5) + ENDIF + IF(MLIST.EQ.3) WRITE(MSTU(11),5900) (V(I,J),J=1,5) + +C...Insert extra separator lines specified by user. + IF(MSTU(70).GE.1) THEN + ISEP=0 + DO 110 J=1,MIN(10,MSTU(70)) + IF(I.EQ.MSTU(70+J)) ISEP=1 + 110 CONTINUE + IF(ISEP.EQ.1.AND.MLIST.EQ.1) WRITE(MSTU(11),6000) + IF(ISEP.EQ.1.AND.MLIST.GE.2) WRITE(MSTU(11),6100) + ENDIF + 120 CONTINUE + +C...Sum of charges and momenta. + DO 130 J=1,6 + PS(J)=PLU(0,J) + 130 CONTINUE + IF(MLIST.EQ.1.AND.ABS(PS(4)).LT.9999.) THEN + WRITE(MSTU(11),6200) PS(6),(PS(J),J=1,5) + ELSEIF(MLIST.EQ.1.AND.ABS(PS(4)).LT.99999.) THEN + WRITE(MSTU(11),6300) PS(6),(PS(J),J=1,5) + ELSEIF(MLIST.EQ.1) THEN + WRITE(MSTU(11),6400) PS(6),(PS(J),J=1,5) + ELSE + WRITE(MSTU(11),6500) PS(6),(PS(J),J=1,5) + ENDIF + +C...Give simple list of KF codes defined in program. + ELSEIF(MLIST.EQ.11) THEN + WRITE(MSTU(11),6600) + DO 140 KF=1,40 + CALL LUNAME(KF,CHAP) + CALL LUNAME(-KF,CHAN) + IF(CHAP.NE.' '.AND.CHAN.EQ.' ') WRITE(MSTU(11),6700) KF,CHAP + IF(CHAN.NE.' ') WRITE(MSTU(11),6700) KF,CHAP,-KF,CHAN + 140 CONTINUE + DO 170 KFLS=1,3,2 + DO 160 KFLA=1,8 + DO 150 KFLB=1,KFLA-(3-KFLS)/2 + KF=1000*KFLA+100*KFLB+KFLS + CALL LUNAME(KF,CHAP) + CALL LUNAME(-KF,CHAN) + WRITE(MSTU(11),6700) KF,CHAP,-KF,CHAN + 150 CONTINUE + 160 CONTINUE + 170 CONTINUE + KF=130 + CALL LUNAME(KF,CHAP) + WRITE(MSTU(11),6700) KF,CHAP + KF=310 + CALL LUNAME(KF,CHAP) + WRITE(MSTU(11),6700) KF,CHAP + DO 200 KMUL=0,5 + KFLS=3 + IF(KMUL.EQ.0.OR.KMUL.EQ.3) KFLS=1 + IF(KMUL.EQ.5) KFLS=5 + KFLR=0 + IF(KMUL.EQ.2.OR.KMUL.EQ.3) KFLR=1 + IF(KMUL.EQ.4) KFLR=2 + DO 190 KFLB=1,8 + DO 180 KFLC=1,KFLB-1 + KF=10000*KFLR+100*KFLB+10*KFLC+KFLS + CALL LUNAME(KF,CHAP) + CALL LUNAME(-KF,CHAN) + WRITE(MSTU(11),6700) KF,CHAP,-KF,CHAN + 180 CONTINUE + KF=10000*KFLR+110*KFLB+KFLS + CALL LUNAME(KF,CHAP) + WRITE(MSTU(11),6700) KF,CHAP + 190 CONTINUE + 200 CONTINUE + KF=30443 + CALL LUNAME(KF,CHAP) + WRITE(MSTU(11),6700) KF,CHAP + KF=30553 + CALL LUNAME(KF,CHAP) + WRITE(MSTU(11),6700) KF,CHAP + DO 240 KFLSP=1,3 + KFLS=2+2*(KFLSP/3) + DO 230 KFLA=1,8 + DO 220 KFLB=1,KFLA + DO 210 KFLC=1,KFLB + IF(KFLSP.EQ.1.AND.(KFLA.EQ.KFLB.OR.KFLB.EQ.KFLC)) GOTO 210 + IF(KFLSP.EQ.2.AND.KFLA.EQ.KFLC) GOTO 210 + IF(KFLSP.EQ.1) KF=1000*KFLA+100*KFLC+10*KFLB+KFLS + IF(KFLSP.GE.2) KF=1000*KFLA+100*KFLB+10*KFLC+KFLS + CALL LUNAME(KF,CHAP) + CALL LUNAME(-KF,CHAN) + WRITE(MSTU(11),6700) KF,CHAP,-KF,CHAN + 210 CONTINUE + 220 CONTINUE + 230 CONTINUE + 240 CONTINUE + +C...List parton/particle data table. Check whether to be listed. + ELSEIF(MLIST.EQ.12) THEN + WRITE(MSTU(11),6800) + MSTJ24=MSTJ(24) + MSTJ(24)=0 + KFMAX=30553 + IF(MSTU(2).NE.0) KFMAX=MSTU(2) + DO 270 KF=MAX(1,MSTU(1)),KFMAX + KC=LUCOMP(KF) + IF(KC.EQ.0) GOTO 270 + IF(MSTU(14).EQ.0.AND.KF.GT.100.AND.KC.LE.100) GOTO 270 + IF(MSTU(14).GT.0.AND.KF.GT.100.AND.MAX(MOD(KF/1000,10), + & MOD(KF/100,10)).GT.MSTU(14)) GOTO 270 + IF(MSTU(14).GT.0.AND.KF.GT.100.AND.KC.EQ.90) GOTO 270 + +C...Find particle name and mass. Print information. + CALL LUNAME(KF,CHAP) + IF(KF.LE.100.AND.CHAP.EQ.' '.AND.MDCY(KC,2).EQ.0) GOTO 270 + CALL LUNAME(-KF,CHAN) + PM=ULMASS(KF) + WRITE(MSTU(11),6900) KF,KC,CHAP,CHAN,KCHG(KC,1),KCHG(KC,2), + & KCHG(KC,3),PM,PMAS(KC,2),PMAS(KC,3),PMAS(KC,4),MDCY(KC,1) + +C...Particle decay: channel number, branching ration, matrix element, +C...decay products. + IF(KF.GT.100.AND.KC.LE.100) GOTO 270 + DO 260 IDC=MDCY(KC,2),MDCY(KC,2)+MDCY(KC,3)-1 + DO 250 J=1,5 + CALL LUNAME(KFDP(IDC,J),CHAD(J)) + 250 CONTINUE + WRITE(MSTU(11),7000) IDC,MDME(IDC,1),MDME(IDC,2),BRAT(IDC), + & (CHAD(J),J=1,5) + 260 CONTINUE + 270 CONTINUE + MSTJ(24)=MSTJ24 + +C...List parameter value table. + ELSEIF(MLIST.EQ.13) THEN + WRITE(MSTU(11),7100) + DO 280 I=1,200 + WRITE(MSTU(11),7200) I,MSTU(I),PARU(I),MSTJ(I),PARJ(I),PARF(I) + 280 CONTINUE + ENDIF + +C...Format statements for output on unit MSTU(11) (by default 6). + 5100 FORMAT(///28X,'Event listing (summary)'//4X,'I particle/jet KS', + &5X,'KF orig p_x p_y p_z E m'/) + 5200 FORMAT(///28X,'Event listing (standard)'//4X,'I particle/jet', + &' K(I,1) K(I,2) K(I,3) K(I,4) K(I,5) P(I,1)', + &' P(I,2) P(I,3) P(I,4) P(I,5)'/) + 5300 FORMAT(///28X,'Event listing (with vertices)'//4X,'I particle/j', + &'et K(I,1) K(I,2) K(I,3) K(I,4) K(I,5) P(I,1)', + &' P(I,2) P(I,3) P(I,4) P(I,5)'/73X, + &'V(I,1) V(I,2) V(I,3) V(I,4) V(I,5)'/) + 5400 FORMAT(1X,I4,2X,A12,1X,I2,1X,I6,1X,I4,5F9.3) + 5500 FORMAT(1X,I4,2X,A12,1X,I2,1X,I6,1X,I4,5F9.2) + 5600 FORMAT(1X,I4,2X,A12,1X,I2,1X,I6,1X,I4,5F9.1) + 5700 FORMAT(1X,I4,2X,A16,1X,I3,1X,I8,2X,I4,2(3X,I1,2I4),5F13.5) + 5800 FORMAT(1X,I4,2X,A16,1X,I3,1X,I8,2X,I4,2(3X,I9),5F13.5) + 5900 FORMAT(66X,5(1X,F12.3)) + 6000 FORMAT(1X,78('=')) + 6100 FORMAT(1X,130('=')) + 6200 FORMAT(19X,'sum:',F6.2,5X,5F9.3) + 6300 FORMAT(19X,'sum:',F6.2,5X,5F9.2) + 6400 FORMAT(19X,'sum:',F6.2,5X,5F9.1) + 6500 FORMAT(19X,'sum charge:',F6.2,3X,'sum momentum and inv. mass:', + &5F13.5) + 6600 FORMAT(///20X,'List of KF codes in program'/) + 6700 FORMAT(4X,I6,4X,A16,6X,I6,4X,A16) + 6800 FORMAT(///30X,'Particle/parton data table'//5X,'KF',5X,'KC',4X, + &'particle',8X,'antiparticle',6X,'chg col anti',8X,'mass',7X, + &'width',7X,'w-cut',5X,'lifetime',1X,'decay'/11X,'IDC',1X,'on/off', + &1X,'ME',3X,'Br.rat.',4X,'decay products') + 6900 FORMAT(/1X,I6,3X,I4,4X,A16,A16,3I5,1X,F12.5,2(1X,F11.5), + &2X,F12.5,3X,I2) + 7000 FORMAT(10X,I4,2X,I3,2X,I3,2X,F8.5,4X,5A16) + 7100 FORMAT(///20X,'Parameter value table'//4X,'I',3X,'MSTU(I)', + &8X,'PARU(I)',3X,'MSTJ(I)',8X,'PARJ(I)',8X,'PARF(I)') + 7200 FORMAT(1X,I4,1X,I9,1X,F14.5,1X,I9,1X,F14.5,1X,F14.5) + + RETURN + END + +C********************************************************************* + +CDECK ID>, LULOGO + SUBROUTINE LULOGO + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to write logo for JETSET and PYTHIA programs. + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/PYPARS/MSTP(200),PARP(200),MSTI(200),PARI(200) + SAVE /LUDAT1/ + SAVE /PYPARS/ + CHARACTER MONTH(12)*3, LOGO(48)*32, REFER(22)*36, LINE*79, + &VERS*1, SUBV*3, DATE*2, YEAR*4 + +C...Data on months, logo, titles, and references. + DATA MONTH/'Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep', + &'Oct','Nov','Dec'/ + DATA (LOGO(J),J=1,10)/ + &'PPP Y Y TTTTT H H III A ', + &'P P Y Y T H H I A A ', + &'PPP Y T HHHHH I AAAAA', + &'P Y T H H I A A', + &'P Y T H H III A A', + &'JJJJ EEEE TTTTT SSS EEEE TTTTT', + &' J E T S E T ', + &' J EEE T SSS EEE T ', + &'J J E T S E T ', + &' JJ EEEE T SSS EEEE T '/ + DATA (LOGO(J),J=11,29)/ + &' *......* ', + &' *:::!!:::::::::::* ', + &' *::::::!!::::::::::::::* ', + &' *::::::::!!::::::::::::::::* ', + &' *:::::::::!!:::::::::::::::::* ', + &' *:::::::::!!:::::::::::::::::* ', + &' *::::::::!!::::::::::::::::*! ', + &' *::::::!!::::::::::::::* !! ', + &' !! *:::!!:::::::::::* !! ', + &' !! !* -><- * !! ', + &' !! !! !! ', + &' !! !! !! ', + &' !! !! ', + &' !! ep !! ', + &' !! !! ', + &' !! pp !! ', + &' !! e+e- !! ', + &' !! !! ', + &' !! '/ + DATA (LOGO(J),J=30,48)/ + &'Welcome to the Lund Monte Carlo!', + &' ', + &' This is PYTHIA version x.xxx ', + &'Last date of change: xx xxx 199x', + &' ', + &' This is JETSET version x.xxx ', + &'Last date of change: xx xxx 199x', + &' ', + &' Main author: ', + &' Torbjorn Sjostrand ', + &' Dept. of theoretical physics 2 ', + &' University of Lund ', + &' Solvegatan 14A ', + &' S-223 62 Lund, Sweden ', + &' phone: +46 - 46 - 222 48 16 ', + &' E-mail: torbjorn@thep.lu.se ', + &' ', + &' Copyright Torbjorn Sjostrand ', + &' and CERN, Geneva 1993 '/ + DATA (REFER(J),J=1,6)/ + &'The latest program versions and docu', + &'mentation is found on WWW address ', + &'http://thep.lu.se/tf2/staff/torbjorn', + &'/Welcome.html ', + &' ', + &' '/ + DATA (REFER(J),J=7,22)/ + &'When you cite these programs, priori', + &'ty should always be given to the ', + &'latest published description. Curren', + &'tly this is ', + &'T. Sjostrand, Computer Physics Commu', + &'n. 82 (1994) 74. ', + &'The most recent long description (un', + &'published) is ', + &'T. Sjostrand, LU TP 95-20 and CERN-T', + &'H.7112/93 (revised August 1995). ', + &'Also remember that the programs, to ', + &'a large extent, represent original ', + &'physics research. Other publications', + &' of special relevance to your ', + &'studies may therefore deserve separa', + &'te mention. '/ + +C...Check if PYTHIA linked. + IF(MSTP(183)/10.NE.199) THEN + LOGO(32)=' Warning: PYTHIA is not loaded! ' + LOGO(33)='Did you remember to link PYDATA?' + ELSE + WRITE(VERS,'(I1)') MSTP(181) + LOGO(32)(26:26)=VERS + WRITE(SUBV,'(I3)') MSTP(182) + LOGO(32)(28:30)=SUBV + WRITE(DATE,'(I2)') MSTP(185) + LOGO(33)(22:23)=DATE + LOGO(33)(25:27)=MONTH(MSTP(184)) + WRITE(YEAR,'(I4)') MSTP(183) + LOGO(33)(29:32)=YEAR + ENDIF + +C...Check if JETSET linked. + IF(MSTU(183)/10.NE.199) THEN + LOGO(35)=' Error: JETSET is not loaded! ' + LOGO(36)='Did you remember to link LUDATA?' + ELSE + WRITE(VERS,'(I1)') MSTU(181) + LOGO(35)(26:26)=VERS + WRITE(SUBV,'(I3)') MSTU(182) + LOGO(35)(28:30)=SUBV + WRITE(DATE,'(I2)') MSTU(185) + LOGO(36)(22:23)=DATE + LOGO(36)(25:27)=MONTH(MSTU(184)) + WRITE(YEAR,'(I4)') MSTU(183) + LOGO(36)(29:32)=YEAR + ENDIF + +C...Loop over lines in header. Define page feed and side borders. + DO 100 ILIN=1,48 + LINE=' ' + IF(ILIN.EQ.1) THEN + LINE(1:1)='1' + ELSE + LINE(2:3)='**' + LINE(78:79)='**' + ENDIF + +C...Separator lines and logos. + IF(ILIN.EQ.2.OR.ILIN.EQ.3.OR.ILIN.EQ.47.OR.ILIN.EQ.48) THEN + LINE(4:77)='***********************************************'// + & '***************************' + ELSEIF(ILIN.GE.6.AND.ILIN.LE.10) THEN + LINE(6:37)=LOGO(ILIN-5) + LINE(44:75)=LOGO(ILIN) + ELSEIF(ILIN.GE.13.AND.ILIN.LE.31) THEN + LINE(6:37)=LOGO(ILIN-2) + LINE(44:75)=LOGO(ILIN+17) + ELSEIF(ILIN.GE.34.AND.ILIN.LE.44) THEN + LINE(5:40)=REFER(2*ILIN-67) + LINE(41:76)=REFER(2*ILIN-66) + ENDIF + +C...Write lines to appropriate unit. + IF(MSTU(183)/10.EQ.199) THEN + WRITE(MSTU(11),'(A79)') LINE + ELSE + WRITE(*,'(A79)') LINE + ENDIF + 100 CONTINUE + +C...Check that matching subversions are linked. + IF(MSTU(183)/10.EQ.199.AND.MSTP(183)/10.EQ.199) THEN + IF(MSTU(182).LT.MSTP(186)) WRITE(MSTU(11), + & '(/'' Warning: JETSET subversion too old for PYTHIA''/)') + IF(MSTP(182).LT.MSTU(186)) WRITE(MSTU(11), + & '(/'' Warning: PYTHIA subversion too old for JETSET''/)') + ENDIF + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUUPDA + SUBROUTINE LUUPDA(MUPDA,LFN) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to facilitate the updating of particle and decay data. + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) + COMMON/LUDAT4/CHAF(500) + CHARACTER CHAF*8 + SAVE /LUDAT1/,/LUDAT2/,/LUDAT3/,/LUDAT4/ + CHARACTER CHINL*80,CHKC*4,CHVAR(19)*9,CHLIN*72, + &CHBLK(20)*72,CHOLD*12,CHTMP*12,CHNEW*12,CHCOM*12 + DATA CHVAR/ 'KCHG(I,1)','KCHG(I,2)','KCHG(I,3)','PMAS(I,1)', + &'PMAS(I,2)','PMAS(I,3)','PMAS(I,4)','MDCY(I,1)','MDCY(I,2)', + &'MDCY(I,3)','MDME(I,1)','MDME(I,2)','BRAT(I) ','KFDP(I,1)', + &'KFDP(I,2)','KFDP(I,3)','KFDP(I,4)','KFDP(I,5)','CHAF(I) '/ + +C...Write information on file for editing. + IF(MSTU(12).GE.1) CALL LULIST(0) + IF(MUPDA.EQ.1) THEN + DO 110 KC=1,MSTU(6) + WRITE(LFN,5000) KC,CHAF(KC),(KCHG(KC,J1),J1=1,3), + & (PMAS(KC,J2),J2=1,4),MDCY(KC,1) + DO 100 IDC=MDCY(KC,2),MDCY(KC,2)+MDCY(KC,3)-1 + WRITE(LFN,5100) MDME(IDC,1),MDME(IDC,2),BRAT(IDC), + & (KFDP(IDC,J),J=1,5) + 100 CONTINUE + 110 CONTINUE + +C...Reset variables and read information from edited file. + ELSEIF(MUPDA.EQ.2) THEN + DO 130 I=1,MSTU(7) + MDME(I,1)=1 + MDME(I,2)=0 + BRAT(I)=0. + DO 120 J=1,5 + KFDP(I,J)=0 + 120 CONTINUE + 130 CONTINUE + KC=0 + IDC=0 + NDC=0 + 140 READ(LFN,5200,END=150) CHINL + IF(CHINL(2:5).NE.' ') THEN + CHKC=CHINL(2:5) + IF(KC.NE.0) THEN + MDCY(KC,2)=0 + IF(NDC.NE.0) MDCY(KC,2)=IDC+1-NDC + MDCY(KC,3)=NDC + ENDIF + READ(CHKC,5300) KC + IF(KC.LE.0.OR.KC.GT.MSTU(6)) CALL LUERRM(27, + & '(LUUPDA:) Read KC code illegal, KC ='//CHKC) + READ(CHINL,5000) KCR,CHAF(KC),(KCHG(KC,J1),J1=1,3), + & (PMAS(KC,J2),J2=1,4),MDCY(KC,1) + NDC=0 + ELSE + IDC=IDC+1 + NDC=NDC+1 + IF(IDC.GE.MSTU(7)) CALL LUERRM(27, + & '(LUUPDA:) Decay data arrays full by KC ='//CHKC) + READ(CHINL,5100) MDME(IDC,1),MDME(IDC,2),BRAT(IDC), + & (KFDP(IDC,J),J=1,5) + ENDIF + GOTO 140 + 150 MDCY(KC,2)=0 + IF(NDC.NE.0) MDCY(KC,2)=IDC+1-NDC + MDCY(KC,3)=NDC + +C...Perform possible tests that new information is consistent. + MSTJ24=MSTJ(24) + MSTJ(24)=0 + DO 180 KC=1,MSTU(6) + WRITE(CHKC,5300) KC + IF(MIN(PMAS(KC,1),PMAS(KC,2),PMAS(KC,3),PMAS(KC,1)-PMAS(KC,3), + & PMAS(KC,4)).LT.0..OR.MDCY(KC,3).LT.0) CALL LUERRM(17, + & '(LUUPDA:) Mass/width/life/(# channels) wrong for KC ='//CHKC) + BRSUM=0. + DO 170 IDC=MDCY(KC,2),MDCY(KC,2)+MDCY(KC,3)-1 + IF(MDME(IDC,2).GT.80) GOTO 170 + KQ=KCHG(KC,1) + PMS=PMAS(KC,1)-PMAS(KC,3)-PARJ(64) + MERR=0 + DO 160 J=1,5 + KP=KFDP(IDC,J) + IF(KP.EQ.0.OR.KP.EQ.81.OR.IABS(KP).EQ.82) THEN + ELSEIF(LUCOMP(KP).EQ.0) THEN + MERR=3 + ELSE + KQ=KQ-LUCHGE(KP) + PMS=PMS-ULMASS(KP) + ENDIF + 160 CONTINUE + IF(KQ.NE.0) MERR=MAX(2,MERR) + IF(KFDP(IDC,2).NE.0.AND.(KC.LE.20.OR.KC.GT.40).AND. + & (KC.LE.80.OR.KC.GT.100).AND.MDME(IDC,2).NE.34.AND. + & MDME(IDC,2).NE.61.AND.PMS.LT.0.) MERR=MAX(1,MERR) + IF(MERR.EQ.3) CALL LUERRM(17, + & '(LUUPDA:) Unknown particle code in decay of KC ='//CHKC) + IF(MERR.EQ.2) CALL LUERRM(17, + & '(LUUPDA:) Charge not conserved in decay of KC ='//CHKC) + IF(MERR.EQ.1) CALL LUERRM(7, + & '(LUUPDA:) Kinematically unallowed decay of KC ='//CHKC) + BRSUM=BRSUM+BRAT(IDC) + 170 CONTINUE + WRITE(CHTMP,5500) BRSUM + IF(ABS(BRSUM).GT.0.0005.AND.ABS(BRSUM-1.).GT.0.0005) CALL + & LUERRM(7,'(LUUPDA:) Sum of branching ratios is '//CHTMP(5:12)// + & ' for KC ='//CHKC) + 180 CONTINUE + MSTJ(24)=MSTJ24 + +C...Initialize writing of DATA statements for inclusion in program. + ELSEIF(MUPDA.EQ.3) THEN + DO 250 IVAR=1,19 + NDIM=MSTU(6) + IF(IVAR.GE.11.AND.IVAR.LE.18) NDIM=MSTU(7) + NLIN=1 + CHLIN=' ' + CHLIN(7:35)='DATA ('//CHVAR(IVAR)//',I= 1, )/' + LLIN=35 + CHOLD='START' + +C...Loop through variables for conversion to characters. + DO 230 IDIM=1,NDIM + IF(IVAR.EQ.1) WRITE(CHTMP,5400) KCHG(IDIM,1) + IF(IVAR.EQ.2) WRITE(CHTMP,5400) KCHG(IDIM,2) + IF(IVAR.EQ.3) WRITE(CHTMP,5400) KCHG(IDIM,3) + IF(IVAR.EQ.4) WRITE(CHTMP,5500) PMAS(IDIM,1) + IF(IVAR.EQ.5) WRITE(CHTMP,5500) PMAS(IDIM,2) + IF(IVAR.EQ.6) WRITE(CHTMP,5500) PMAS(IDIM,3) + IF(IVAR.EQ.7) WRITE(CHTMP,5500) PMAS(IDIM,4) + IF(IVAR.EQ.8) WRITE(CHTMP,5400) MDCY(IDIM,1) + IF(IVAR.EQ.9) WRITE(CHTMP,5400) MDCY(IDIM,2) + IF(IVAR.EQ.10) WRITE(CHTMP,5400) MDCY(IDIM,3) + IF(IVAR.EQ.11) WRITE(CHTMP,5400) MDME(IDIM,1) + IF(IVAR.EQ.12) WRITE(CHTMP,5400) MDME(IDIM,2) + IF(IVAR.EQ.13) WRITE(CHTMP,5500) BRAT(IDIM) + IF(IVAR.EQ.14) WRITE(CHTMP,5400) KFDP(IDIM,1) + IF(IVAR.EQ.15) WRITE(CHTMP,5400) KFDP(IDIM,2) + IF(IVAR.EQ.16) WRITE(CHTMP,5400) KFDP(IDIM,3) + IF(IVAR.EQ.17) WRITE(CHTMP,5400) KFDP(IDIM,4) + IF(IVAR.EQ.18) WRITE(CHTMP,5400) KFDP(IDIM,5) + IF(IVAR.EQ.19) CHTMP=CHAF(IDIM) + +C...Length of variable, trailing decimal zeros, quotation marks. + LLOW=1 + LHIG=1 + DO 190 LL=1,12 + IF(CHTMP(13-LL:13-LL).NE.' ') LLOW=13-LL + IF(CHTMP(LL:LL).NE.' ') LHIG=LL + 190 CONTINUE + CHNEW=CHTMP(LLOW:LHIG)//' ' + LNEW=1+LHIG-LLOW + IF((IVAR.GE.4.AND.IVAR.LE.7).OR.IVAR.EQ.13) THEN + LNEW=LNEW+1 + 200 LNEW=LNEW-1 + IF(CHNEW(LNEW:LNEW).EQ.'0') GOTO 200 + IF(LNEW.EQ.1) CHNEW(1:2)='0.' + IF(LNEW.EQ.1) LNEW=2 + ELSEIF(IVAR.EQ.19) THEN + DO 210 LL=LNEW,1,-1 + IF(CHNEW(LL:LL).EQ.'''') THEN + CHTMP=CHNEW + CHNEW=CHTMP(1:LL)//''''//CHTMP(LL+1:11) + LNEW=LNEW+1 + ENDIF + 210 CONTINUE + CHTMP=CHNEW + CHNEW(1:LNEW+2)=''''//CHTMP(1:LNEW)//'''' + LNEW=LNEW+2 + ENDIF + +C...Form composite character string, often including repetition counter. + IF(CHNEW.NE.CHOLD) THEN + NRPT=1 + CHOLD=CHNEW + CHCOM=CHNEW + LCOM=LNEW + ELSE + LRPT=LNEW+1 + IF(NRPT.GE.2) LRPT=LNEW+3 + IF(NRPT.GE.10) LRPT=LNEW+4 + IF(NRPT.GE.100) LRPT=LNEW+5 + IF(NRPT.GE.1000) LRPT=LNEW+6 + LLIN=LLIN-LRPT + NRPT=NRPT+1 + WRITE(CHTMP,5400) NRPT + LRPT=1 + IF(NRPT.GE.10) LRPT=2 + IF(NRPT.GE.100) LRPT=3 + IF(NRPT.GE.1000) LRPT=4 + CHCOM(1:LRPT+1+LNEW)=CHTMP(13-LRPT:12)//'*'//CHNEW(1:LNEW) + LCOM=LRPT+1+LNEW + ENDIF + +C...Add characters to end of line, to new line (after storing old line), +C...or to new block of lines (after writing old block). + IF(LLIN+LCOM.LE.70) THEN + CHLIN(LLIN+1:LLIN+LCOM+1)=CHCOM(1:LCOM)//',' + LLIN=LLIN+LCOM+1 + ELSEIF(NLIN.LE.19) THEN + CHLIN(LLIN+1:72)=' ' + CHBLK(NLIN)=CHLIN + NLIN=NLIN+1 + CHLIN(6:6+LCOM+1)='&'//CHCOM(1:LCOM)//',' + LLIN=6+LCOM+1 + ELSE + CHLIN(LLIN:72)='/'//' ' + CHBLK(NLIN)=CHLIN + WRITE(CHTMP,5400) IDIM-NRPT + CHBLK(1)(30:33)=CHTMP(9:12) + DO 220 ILIN=1,NLIN + WRITE(LFN,5600) CHBLK(ILIN) + 220 CONTINUE + NLIN=1 + CHLIN=' ' + CHLIN(7:35+LCOM+1)='DATA ('//CHVAR(IVAR)//',I= , )/'// + & CHCOM(1:LCOM)//',' + WRITE(CHTMP,5400) IDIM-NRPT+1 + CHLIN(25:28)=CHTMP(9:12) + LLIN=35+LCOM+1 + ENDIF + 230 CONTINUE + +C...Write final block of lines. + CHLIN(LLIN:72)='/'//' ' + CHBLK(NLIN)=CHLIN + WRITE(CHTMP,5400) NDIM + CHBLK(1)(30:33)=CHTMP(9:12) + DO 240 ILIN=1,NLIN + WRITE(LFN,5600) CHBLK(ILIN) + 240 CONTINUE + 250 CONTINUE + ENDIF + +C...Formats for reading and writing particle data. + 5000 FORMAT(1X,I4,2X,A8,3I3,3F12.5,2X,F12.5,I3) + 5100 FORMAT(5X,2I5,F12.5,5I8) + 5200 FORMAT(A80) + 5300 FORMAT(I4) + 5400 FORMAT(I12) + 5500 FORMAT(F12.5) + 5600 FORMAT(A72) + + RETURN + END + +C********************************************************************* + +CDECK ID>, KLU + FUNCTION KLU(I,J) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to provide various integer-valued event related data. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + +C...Default value. For I=0 number of entries, number of stable entries +C...or 3 times total charge. + KLU=0 + IF(I.LT.0.OR.I.GT.MSTU(4).OR.J.LE.0) THEN + ELSEIF(I.EQ.0.AND.J.EQ.1) THEN + KLU=N + ELSEIF(I.EQ.0.AND.(J.EQ.2.OR.J.EQ.6)) THEN + DO 100 I1=1,N + IF(J.EQ.2.AND.K(I1,1).GE.1.AND.K(I1,1).LE.10) KLU=KLU+1 + IF(J.EQ.6.AND.K(I1,1).GE.1.AND.K(I1,1).LE.10) KLU=KLU+ + & LUCHGE(K(I1,2)) + 100 CONTINUE + ELSEIF(I.EQ.0) THEN + +C...For I > 0 direct readout of K matrix or charge. + ELSEIF(J.LE.5) THEN + KLU=K(I,J) + ELSEIF(J.EQ.6) THEN + KLU=LUCHGE(K(I,2)) + +C...Status (existing/fragmented/decayed), parton/hadron separation. + ELSEIF(J.LE.8) THEN + IF(K(I,1).GE.1.AND.K(I,1).LE.10) KLU=1 + IF(J.EQ.8) KLU=KLU*K(I,2) + ELSEIF(J.LE.12) THEN + KFA=IABS(K(I,2)) + KC=LUCOMP(KFA) + KQ=0 + IF(KC.NE.0) KQ=KCHG(KC,2) + IF(J.EQ.9.AND.KC.NE.0.AND.KQ.NE.0) KLU=K(I,2) + IF(J.EQ.10.AND.KC.NE.0.AND.KQ.EQ.0) KLU=K(I,2) + IF(J.EQ.11) KLU=KC + IF(J.EQ.12) KLU=KQ*ISIGN(1,K(I,2)) + +C...Heaviest flavour in hadron/diquark. + ELSEIF(J.EQ.13) THEN + KFA=IABS(K(I,2)) + KLU=MOD(KFA/100,10)*(-1)**MOD(KFA/100,10) + IF(KFA.LT.10) KLU=KFA + IF(MOD(KFA/1000,10).NE.0) KLU=MOD(KFA/1000,10) + KLU=KLU*ISIGN(1,K(I,2)) + +C...Particle history: generation, ancestor, rank. + ELSEIF(J.LE.15) THEN + I2=I + I1=I + 110 KLU=KLU+1 + I2=I1 + I1=K(I1,3) + IF(I1.GT.0.AND.K(I1,1).GT.0.AND.K(I1,1).LE.20) GOTO 110 + IF(J.EQ.15) KLU=I2 + ELSEIF(J.EQ.16) THEN + KFA=IABS(K(I,2)) + IF(K(I,1).LE.20.AND.((KFA.GE.11.AND.KFA.LE.20).OR.KFA.EQ.22.OR. + & (KFA.GT.100.AND.MOD(KFA/10,10).NE.0))) THEN + I1=I + 120 I2=I1 + I1=K(I1,3) + IF(I1.GT.0) THEN + KFAM=IABS(K(I1,2)) + ILP=1 + IF(KFAM.NE.0.AND.KFAM.LE.10) ILP=0 + IF(KFAM.EQ.21.OR.KFAM.EQ.91.OR.KFAM.EQ.92.OR.KFAM.EQ.93) + & ILP=0 + IF(KFAM.GT.100.AND.MOD(KFAM/10,10).EQ.0) ILP=0 + IF(ILP.EQ.1) GOTO 120 + ENDIF + IF(K(I1,1).EQ.12) THEN + DO 130 I3=I1+1,I2 + IF(K(I3,3).EQ.K(I2,3).AND.K(I3,2).NE.91.AND.K(I3,2).NE.92 + & .AND.K(I3,2).NE.93) KLU=KLU+1 + 130 CONTINUE + ELSE + I3=I2 + 140 KLU=KLU+1 + I3=I3+1 + IF(I3.LT.N.AND.K(I3,3).EQ.K(I2,3)) GOTO 140 + ENDIF + ENDIF + +C...Particle coming from collapsing jet system or not. + ELSEIF(J.EQ.17) THEN + I1=I + 150 KLU=KLU+1 + I3=I1 + I1=K(I1,3) + I0=MAX(1,I1) + KC=LUCOMP(K(I0,2)) + IF(I1.EQ.0.OR.K(I0,1).LE.0.OR.K(I0,1).GT.20.OR.KC.EQ.0) THEN + IF(KLU.EQ.1) KLU=-1 + IF(KLU.GT.1) KLU=0 + RETURN + ENDIF + IF(KCHG(KC,2).EQ.0) GOTO 150 + IF(K(I1,1).NE.12) KLU=0 + IF(K(I1,1).NE.12) RETURN + I2=I1 + 160 I2=I2+1 + IF(I2.LT.N.AND.K(I2,1).NE.11) GOTO 160 + K3M=K(I3-1,3) + IF(K3M.GE.I1.AND.K3M.LE.I2) KLU=0 + K3P=K(I3+1,3) + IF(I3.LT.N.AND.K3P.GE.I1.AND.K3P.LE.I2) KLU=0 + +C...Number of decay products. Colour flow. + ELSEIF(J.EQ.18) THEN + IF(K(I,1).EQ.11.OR.K(I,1).EQ.12) KLU=MAX(0,K(I,5)-K(I,4)+1) + IF(K(I,4).EQ.0.OR.K(I,5).EQ.0) KLU=0 + ELSEIF(J.LE.22) THEN + IF(K(I,1).NE.3.AND.K(I,1).NE.13.AND.K(I,1).NE.14) RETURN + IF(J.EQ.19) KLU=MOD(K(I,4)/MSTU(5),MSTU(5)) + IF(J.EQ.20) KLU=MOD(K(I,5)/MSTU(5),MSTU(5)) + IF(J.EQ.21) KLU=MOD(K(I,4),MSTU(5)) + IF(J.EQ.22) KLU=MOD(K(I,5),MSTU(5)) + ELSE + ENDIF + + RETURN + END + +C********************************************************************* + +CDECK ID>, PLU + FUNCTION PLU(I,J) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to provide various real-valued event related data. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + DIMENSION PSUM(4) + +C...Set default value. For I = 0 sum of momenta or charges, +C...or invariant mass of system. + PLU=0. + IF(I.LT.0.OR.I.GT.MSTU(4).OR.J.LE.0) THEN + ELSEIF(I.EQ.0.AND.J.LE.4) THEN + DO 100 I1=1,N + IF(K(I1,1).GT.0.AND.K(I1,1).LE.10) PLU=PLU+P(I1,J) + 100 CONTINUE + ELSEIF(I.EQ.0.AND.J.EQ.5) THEN + DO 120 J1=1,4 + PSUM(J1)=0. + DO 110 I1=1,N + IF(K(I1,1).GT.0.AND.K(I1,1).LE.10) PSUM(J1)=PSUM(J1)+P(I1,J1) + 110 CONTINUE + 120 CONTINUE + PLU=SQRT(MAX(0.D0,PSUM(4)**2-PSUM(1)**2-PSUM(2)**2-PSUM(3)**2)) + ELSEIF(I.EQ.0.AND.J.EQ.6) THEN + DO 130 I1=1,N + IF(K(I1,1).GT.0.AND.K(I1,1).LE.10) PLU=PLU+LUCHGE(K(I1,2))/3. + 130 CONTINUE + ELSEIF(I.EQ.0) THEN + +C...Direct readout of P matrix. + ELSEIF(J.LE.5) THEN + PLU=P(I,J) + +C...Charge, total momentum, transverse momentum, transverse mass. + ELSEIF(J.LE.12) THEN + IF(J.EQ.6) PLU=LUCHGE(K(I,2))/3. + IF(J.EQ.7.OR.J.EQ.8) PLU=P(I,1)**2+P(I,2)**2+P(I,3)**2 + IF(J.EQ.9.OR.J.EQ.10) PLU=P(I,1)**2+P(I,2)**2 + IF(J.EQ.11.OR.J.EQ.12) PLU=P(I,5)**2+P(I,1)**2+P(I,2)**2 + IF(J.EQ.8.OR.J.EQ.10.OR.J.EQ.12) PLU=SQRT(PLU) + +C...Theta and phi angle in radians or degrees. + ELSEIF(J.LE.16) THEN + IF(J.LE.14) PLU=ULANGL(P(I,3),SQRT(P(I,1)**2+P(I,2)**2)) + IF(J.GE.15) PLU=ULANGL(P(I,1),P(I,2)) + IF(J.EQ.14.OR.J.EQ.16) PLU=PLU*180./PARU(1) + +C...True rapidity, rapidity with pion mass, pseudorapidity. + ELSEIF(J.LE.19) THEN + PMR=0. + IF(J.EQ.17) PMR=P(I,5) + IF(J.EQ.18) PMR=ULMASS(211) + PR=MAX(1D-20,PMR**2+P(I,1)**2+P(I,2)**2) + PLU=SIGN(LOG(MIN((SQRT(PR+P(I,3)**2)+ABS(P(I,3)))/SQRT(PR), + & 1D20)),P(I,3)) + +C...Energy and momentum fractions (only to be used in CM frame). + ELSEIF(J.LE.25) THEN + IF(J.EQ.20) PLU=2.*SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2)/PARU(21) + IF(J.EQ.21) PLU=2.*P(I,3)/PARU(21) + IF(J.EQ.22) PLU=2.*SQRT(P(I,1)**2+P(I,2)**2)/PARU(21) + IF(J.EQ.23) PLU=2.*P(I,4)/PARU(21) + IF(J.EQ.24) PLU=(P(I,4)+P(I,3))/PARU(21) + IF(J.EQ.25) PLU=(P(I,4)-P(I,3))/PARU(21) + ENDIF + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUSPHE + SUBROUTINE LUSPHE(SPH,APL) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to perform sphericity tensor analysis to give sphericity, +C...aplanarity and the related event axes. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + DIMENSION SM(3,3),SV(3,3) + +C...Calculate matrix to be diagonalized. + NP=0 + DO 110 J1=1,3 + DO 100 J2=J1,3 + SM(J1,J2)=0. + 100 CONTINUE + 110 CONTINUE + PS=0. + DO 140 I=1,N + IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 140 + IF(MSTU(41).GE.2) THEN + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR. + & KC.EQ.18) GOTO 140 + IF(MSTU(41).GE.3.AND.KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) + & GOTO 140 + ENDIF + NP=NP+1 + PA=SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2) + PWT=1. + IF(ABS(PARU(41)-2.).GT.0.001) PWT=MAX(1D-10,PA)**(PARU(41)-2.) + DO 130 J1=1,3 + DO 120 J2=J1,3 + SM(J1,J2)=SM(J1,J2)+PWT*P(I,J1)*P(I,J2) + 120 CONTINUE + 130 CONTINUE + PS=PS+PWT*PA**2 + 140 CONTINUE + +C...Very low multiplicities (0 or 1) not considered. + IF(NP.LE.1) THEN + CALL LUERRM(8,'(LUSPHE:) too few particles for analysis') + SPH=-1. + APL=-1. + RETURN + ENDIF + DO 160 J1=1,3 + DO 150 J2=J1,3 + SM(J1,J2)=SM(J1,J2)/PS + 150 CONTINUE + 160 CONTINUE + +C...Find eigenvalues to matrix (third degree equation). + SQ=(SM(1,1)*SM(2,2)+SM(1,1)*SM(3,3)+SM(2,2)*SM(3,3)-SM(1,2)**2- + &SM(1,3)**2-SM(2,3)**2)/3.-1./9. + SR=-0.5*(SQ+1./9.+SM(1,1)*SM(2,3)**2+SM(2,2)*SM(1,3)**2+SM(3,3)* + &SM(1,2)**2-SM(1,1)*SM(2,2)*SM(3,3))+SM(1,2)*SM(1,3)*SM(2,3)+1./27. + SP=COS(ACOS(MAX(MIN(SR/SQRT(-SQ**3),1.D0),-1.D0))/3.) + P(N+1,4)=1./3.+SQRT(-SQ)*MAX(2.*SP,SQRT(3.*(1.-SP**2))-SP) + P(N+3,4)=1./3.+SQRT(-SQ)*MIN(2.*SP,-SQRT(3.*(1.-SP**2))-SP) + P(N+2,4)=1.-P(N+1,4)-P(N+3,4) + IF(P(N+2,4).LT.1D-5) THEN + CALL LUERRM(8,'(LUSPHE:) all particles back-to-back') + SPH=-1. + APL=-1. + RETURN + ENDIF + +C...Find first and last eigenvector by solving equation system. + DO 240 I=1,3,2 + DO 180 J1=1,3 + SV(J1,J1)=SM(J1,J1)-P(N+I,4) + DO 170 J2=J1+1,3 + SV(J1,J2)=SM(J1,J2) + SV(J2,J1)=SM(J1,J2) + 170 CONTINUE + 180 CONTINUE + SMAX=0. + DO 200 J1=1,3 + DO 190 J2=1,3 + IF(ABS(SV(J1,J2)).LE.SMAX) GOTO 190 + JA=J1 + JB=J2 + SMAX=ABS(SV(J1,J2)) + 190 CONTINUE + 200 CONTINUE + SMAX=0. + DO 220 J3=JA+1,JA+2 + J1=J3-3*((J3-1)/3) + RL=SV(J1,JB)/SV(JA,JB) + DO 210 J2=1,3 + SV(J1,J2)=SV(J1,J2)-RL*SV(JA,J2) + IF(ABS(SV(J1,J2)).LE.SMAX) GOTO 210 + JC=J1 + SMAX=ABS(SV(J1,J2)) + 210 CONTINUE + 220 CONTINUE + JB1=JB+1-3*(JB/3) + JB2=JB+2-3*((JB+1)/3) + P(N+I,JB1)=-SV(JC,JB2) + P(N+I,JB2)=SV(JC,JB1) + P(N+I,JB)=-(SV(JA,JB1)*P(N+I,JB1)+SV(JA,JB2)*P(N+I,JB2))/ + &SV(JA,JB) + PA=SQRT(P(N+I,1)**2+P(N+I,2)**2+P(N+I,3)**2) + SGN=(-1.)**INT(RLU(0)+0.5) + DO 230 J=1,3 + P(N+I,J)=SGN*P(N+I,J)/PA + 230 CONTINUE + 240 CONTINUE + +C...Middle axis orthogonal to other two. Fill other codes. + SGN=(-1.)**INT(RLU(0)+0.5) + P(N+2,1)=SGN*(P(N+1,2)*P(N+3,3)-P(N+1,3)*P(N+3,2)) + P(N+2,2)=SGN*(P(N+1,3)*P(N+3,1)-P(N+1,1)*P(N+3,3)) + P(N+2,3)=SGN*(P(N+1,1)*P(N+3,2)-P(N+1,2)*P(N+3,1)) + DO 260 I=1,3 + K(N+I,1)=31 + K(N+I,2)=95 + K(N+I,3)=I + K(N+I,4)=0 + K(N+I,5)=0 + P(N+I,5)=0. + DO 250 J=1,5 + V(I,J)=0. + 250 CONTINUE + 260 CONTINUE + +C...Calculate sphericity and aplanarity. Select storing option. + SPH=1.5*(P(N+2,4)+P(N+3,4)) + APL=1.5*P(N+3,4) + MSTU(61)=N+1 + MSTU(62)=NP + IF(MSTU(43).LE.1) MSTU(3)=3 + IF(MSTU(43).GE.2) N=N+3 + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUTHRU + SUBROUTINE LUTHRU(THR,OBL) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to perform thrust analysis to give thrust, oblateness +C...and the related event axes. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + DIMENSION TDI(3),TPR(3) + +C...Take copy of particles that are to be considered in thrust analysis. + NP=0 + PS=0. + DO 100 I=1,N + IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 100 + IF(MSTU(41).GE.2) THEN + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR. + & KC.EQ.18) GOTO 100 + IF(MSTU(41).GE.3.AND.KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) + & GOTO 100 + ENDIF + IF(N+NP+MSTU(44)+15.GE.MSTU(4)-MSTU(32)-5) THEN + CALL LUERRM(11,'(LUTHRU:) no more memory left in LUJETS') + THR=-2. + OBL=-2. + RETURN + ENDIF + NP=NP+1 + K(N+NP,1)=23 + P(N+NP,1)=P(I,1) + P(N+NP,2)=P(I,2) + P(N+NP,3)=P(I,3) + P(N+NP,4)=SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2) + P(N+NP,5)=1. + IF(ABS(PARU(42)-1.).GT.0.001) P(N+NP,5)=P(N+NP,4)**(PARU(42)-1.) + PS=PS+P(N+NP,4)*P(N+NP,5) + 100 CONTINUE + +C...Very low multiplicities (0 or 1) not considered. + IF(NP.LE.1) THEN + CALL LUERRM(8,'(LUTHRU:) too few particles for analysis') + THR=-1. + OBL=-1. + RETURN + ENDIF + +C...Loop over thrust and major. T axis along z direction in latter case. + DO 320 ILD=1,2 + IF(ILD.EQ.2) THEN + K(N+NP+1,1)=31 + PHI=ULANGL(P(N+NP+1,1),P(N+NP+1,2)) + MSTU(33)=1 + CALL LUDBRB(N+1,N+NP+1,0.D0,-PHI,0D0,0D0,0D0) + THE=ULANGL(P(N+NP+1,3),P(N+NP+1,1)) + CALL LUDBRB(N+1,N+NP+1,-THE,0.D0,0D0,0D0,0D0) + ENDIF + +C...Find and order particles with highest p (pT for major). + DO 110 ILF=N+NP+4,N+NP+MSTU(44)+4 + P(ILF,4)=0. + 110 CONTINUE + DO 160 I=N+1,N+NP + IF(ILD.EQ.2) P(I,4)=SQRT(P(I,1)**2+P(I,2)**2) + DO 130 ILF=N+NP+MSTU(44)+3,N+NP+4,-1 + IF(P(I,4).LE.P(ILF,4)) GOTO 140 + DO 120 J=1,5 + P(ILF+1,J)=P(ILF,J) + 120 CONTINUE + 130 CONTINUE + ILF=N+NP+3 + 140 DO 150 J=1,5 + P(ILF+1,J)=P(I,J) + 150 CONTINUE + 160 CONTINUE + +C...Find and order initial axes with highest thrust (major). + DO 170 ILG=N+NP+MSTU(44)+5,N+NP+MSTU(44)+15 + P(ILG,4)=0. + 170 CONTINUE + NC=2**(MIN(MSTU(44),NP)-1) + DO 250 ILC=1,NC + DO 180 J=1,3 + TDI(J)=0. + 180 CONTINUE + DO 200 ILF=1,MIN(MSTU(44),NP) + SGN=P(N+NP+ILF+3,5) + IF(2**ILF*((ILC+2**(ILF-1)-1)/2**ILF).GE.ILC) SGN=-SGN + DO 190 J=1,4-ILD + TDI(J)=TDI(J)+SGN*P(N+NP+ILF+3,J) + 190 CONTINUE + 200 CONTINUE + TDS=TDI(1)**2+TDI(2)**2+TDI(3)**2 + DO 220 ILG=N+NP+MSTU(44)+MIN(ILC,10)+4,N+NP+MSTU(44)+5,-1 + IF(TDS.LE.P(ILG,4)) GOTO 230 + DO 210 J=1,4 + P(ILG+1,J)=P(ILG,J) + 210 CONTINUE + 220 CONTINUE + ILG=N+NP+MSTU(44)+4 + 230 DO 240 J=1,3 + P(ILG+1,J)=TDI(J) + 240 CONTINUE + P(ILG+1,4)=TDS + 250 CONTINUE + +C...Iterate direction of axis until stable maximum. + P(N+NP+ILD,4)=0. + ILG=0 + 260 ILG=ILG+1 + THP=0. + 270 THPS=THP + DO 280 J=1,3 + IF(THP.LE.1D-10) TDI(J)=P(N+NP+MSTU(44)+4+ILG,J) + IF(THP.GT.1D-10) TDI(J)=TPR(J) + TPR(J)=0. + 280 CONTINUE + DO 300 I=N+1,N+NP + SGN=SIGN(P(I,5),TDI(1)*P(I,1)+TDI(2)*P(I,2)+TDI(3)*P(I,3)) + DO 290 J=1,4-ILD + TPR(J)=TPR(J)+SGN*P(I,J) + 290 CONTINUE + 300 CONTINUE + THP=SQRT(TPR(1)**2+TPR(2)**2+TPR(3)**2)/PS + IF(THP.GE.THPS+PARU(48)) GOTO 270 + +C...Save good axis. Try new initial axis until a number of tries agree. + IF(THP.LT.P(N+NP+ILD,4)-PARU(48).AND.ILG.LT.MIN(10,NC)) GOTO 260 + IF(THP.GT.P(N+NP+ILD,4)+PARU(48)) THEN + IAGR=0 + SGN=(-1.)**INT(RLU(0)+0.5) + DO 310 J=1,3 + P(N+NP+ILD,J)=SGN*TPR(J)/(PS*THP) + 310 CONTINUE + P(N+NP+ILD,4)=THP + P(N+NP+ILD,5)=0. + ENDIF + IAGR=IAGR+1 + IF(IAGR.LT.MSTU(45).AND.ILG.LT.MIN(10,NC)) GOTO 260 + 320 CONTINUE + +C...Find minor axis and value by orthogonality. + SGN=(-1.)**INT(RLU(0)+0.5) + P(N+NP+3,1)=-SGN*P(N+NP+2,2) + P(N+NP+3,2)=SGN*P(N+NP+2,1) + P(N+NP+3,3)=0. + THP=0. + DO 330 I=N+1,N+NP + THP=THP+P(I,5)*ABS(P(N+NP+3,1)*P(I,1)+P(N+NP+3,2)*P(I,2)) + 330 CONTINUE + P(N+NP+3,4)=THP/PS + P(N+NP+3,5)=0. + +C...Fill axis information. Rotate back to original coordinate system. + DO 350 ILD=1,3 + K(N+ILD,1)=31 + K(N+ILD,2)=96 + K(N+ILD,3)=ILD + K(N+ILD,4)=0 + K(N+ILD,5)=0 + DO 340 J=1,5 + P(N+ILD,J)=P(N+NP+ILD,J) + V(N+ILD,J)=0. + 340 CONTINUE + 350 CONTINUE + CALL LUDBRB(N+1,N+3,THE,PHI,0D0,0D0,0D0) + +C...Calculate thrust and oblateness. Select storing option. + THR=P(N+1,4) + OBL=P(N+2,4)-P(N+3,4) + MSTU(61)=N+1 + MSTU(62)=NP + IF(MSTU(43).LE.1) MSTU(3)=3 + IF(MSTU(43).GE.2) N=N+3 + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUCLUS + SUBROUTINE LUCLUS(NJET) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to subdivide the particle content of an event into +C...jets/clusters. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + DIMENSION PS(5) + SAVE NSAV,NP,PS,PSS,RINIT,NPRE,NREM + +C...Functions: distance measure in pT or (pseudo)mass. + R2T(I1,I2)=(P(I1,5)*P(I2,5)-P(I1,1)*P(I2,1)-P(I1,2)*P(I2,2)- + &P(I1,3)*P(I2,3))*2.*P(I1,5)*P(I2,5)/(0.0001+P(I1,5)+P(I2,5))**2 + R2M(I1,I2)=2.*P(I1,4)*P(I2,4)*(1.-(P(I1,1)*P(I2,1)+P(I1,2)* + &P(I2,2)+P(I1,3)*P(I2,3))/(P(I1,5)*P(I2,5))) + +C...If first time, reset. If reentering, skip preliminaries. + IF(MSTU(48).LE.0) THEN + NP=0 + DO 100 J=1,5 + PS(J)=0. + 100 CONTINUE + PSS=0. + ELSE + NJET=NSAV + IF(MSTU(43).GE.2) N=N-NJET + DO 110 I=N+1,N+NJET + P(I,5)=SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2) + 110 CONTINUE + IF(MSTU(46).LE.3) R2ACC=PARU(44)**2 + IF(MSTU(46).GE.4) R2ACC=PARU(45)*PS(5)**2 + NLOOP=0 + GOTO 300 + ENDIF + +C...Find which particles are to be considered in cluster search. + DO 140 I=1,N + IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 140 + IF(MSTU(41).GE.2) THEN + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR. + & KC.EQ.18) GOTO 140 + IF(MSTU(41).GE.3.AND.KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) + & GOTO 140 + ENDIF + IF(N+2*NP.GE.MSTU(4)-MSTU(32)-5) THEN + CALL LUERRM(11,'(LUCLUS:) no more memory left in LUJETS') + NJET=-1 + RETURN + ENDIF + +C...Take copy of these particles, with space left for jets later on. + NP=NP+1 + K(N+NP,3)=I + DO 120 J=1,5 + P(N+NP,J)=P(I,J) + 120 CONTINUE + IF(MSTU(42).EQ.0) P(N+NP,5)=0. + IF(MSTU(42).EQ.1.AND.K(I,2).NE.22) P(N+NP,5)=PMAS(101,1) + P(N+NP,4)=SQRT(P(N+NP,5)**2+P(I,1)**2+P(I,2)**2+P(I,3)**2) + P(N+NP,5)=SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2) + DO 130 J=1,4 + PS(J)=PS(J)+P(N+NP,J) + 130 CONTINUE + PSS=PSS+P(N+NP,5) + 140 CONTINUE + DO 160 I=N+1,N+NP + K(I+NP,3)=K(I,3) + DO 150 J=1,5 + P(I+NP,J)=P(I,J) + 150 CONTINUE + 160 CONTINUE + PS(5)=SQRT(MAX(0.D0,PS(4)**2-PS(1)**2-PS(2)**2-PS(3)**2)) + +C...Very low multiplicities not considered. + IF(NP.LT.MSTU(47)) THEN + CALL LUERRM(8,'(LUCLUS:) too few particles for analysis') + NJET=-1 + RETURN + ENDIF + +C...Find precluster configuration. If too few jets, make harder cuts. + NLOOP=0 + IF(MSTU(46).LE.3) R2ACC=PARU(44)**2 + IF(MSTU(46).GE.4) R2ACC=PARU(45)*PS(5)**2 + RINIT=1.25*PARU(43) + IF(NP.LE.MSTU(47)+2) RINIT=0. + 170 RINIT=0.8*RINIT + NPRE=0 + NREM=NP + DO 180 I=N+NP+1,N+2*NP + K(I,4)=0 + 180 CONTINUE + +C...Sum up small momentum region. Jet if enough absolute momentum. + IF(MSTU(46).LE.2) THEN + DO 190 J=1,4 + P(N+1,J)=0. + 190 CONTINUE + DO 210 I=N+NP+1,N+2*NP + IF(P(I,5).GT.2.*RINIT) GOTO 210 + NREM=NREM-1 + K(I,4)=1 + DO 200 J=1,4 + P(N+1,J)=P(N+1,J)+P(I,J) + 200 CONTINUE + 210 CONTINUE + P(N+1,5)=SQRT(P(N+1,1)**2+P(N+1,2)**2+P(N+1,3)**2) + IF(P(N+1,5).GT.2.*RINIT) NPRE=1 + IF(RINIT.GE.0.2*PARU(43).AND.NPRE+NREM.LT.MSTU(47)) GOTO 170 + IF(NREM.EQ.0) GOTO 170 + ENDIF + +C...Find fastest remaining particle. + 220 NPRE=NPRE+1 + PMAX=0. + DO 230 I=N+NP+1,N+2*NP + IF(K(I,4).NE.0.OR.P(I,5).LE.PMAX) GOTO 230 + IMAX=I + PMAX=P(I,5) + 230 CONTINUE + DO 240 J=1,5 + P(N+NPRE,J)=P(IMAX,J) + 240 CONTINUE + NREM=NREM-1 + K(IMAX,4)=NPRE + +C...Sum up precluster around it according to pT separation. + IF(MSTU(46).LE.2) THEN + DO 260 I=N+NP+1,N+2*NP + IF(K(I,4).NE.0) GOTO 260 + R2=R2T(I,IMAX) + IF(R2.GT.RINIT**2) GOTO 260 + NREM=NREM-1 + K(I,4)=NPRE + DO 250 J=1,4 + P(N+NPRE,J)=P(N+NPRE,J)+P(I,J) + 250 CONTINUE + 260 CONTINUE + P(N+NPRE,5)=SQRT(P(N+NPRE,1)**2+P(N+NPRE,2)**2+P(N+NPRE,3)**2) + +C...Sum up precluster around it according to mass separation. + ELSE + 270 IMIN=0 + R2MIN=RINIT**2 + DO 280 I=N+NP+1,N+2*NP + IF(K(I,4).NE.0) GOTO 280 + R2=R2M(I,N+NPRE) + IF(R2.GE.R2MIN) GOTO 280 + IMIN=I + R2MIN=R2 + 280 CONTINUE + IF(IMIN.NE.0) THEN + DO 290 J=1,4 + P(N+NPRE,J)=P(N+NPRE,J)+P(IMIN,J) + 290 CONTINUE + P(N+NPRE,5)=SQRT(P(N+NPRE,1)**2+P(N+NPRE,2)**2+P(N+NPRE,3)**2) + NREM=NREM-1 + K(IMIN,4)=NPRE + GOTO 270 + ENDIF + ENDIF + +C...Check if more preclusters to be found. Start over if too few. + IF(RINIT.GE.0.2*PARU(43).AND.NPRE+NREM.LT.MSTU(47)) GOTO 170 + IF(NREM.GT.0) GOTO 220 + NJET=NPRE + +C...Reassign all particles to nearest jet. Sum up new jet momenta. + 300 TSAV=0. + PSJT=0. + 310 IF(MSTU(46).LE.1) THEN + DO 330 I=N+1,N+NJET + DO 320 J=1,4 + V(I,J)=0. + 320 CONTINUE + 330 CONTINUE + DO 360 I=N+NP+1,N+2*NP + R2MIN=PSS**2 + DO 340 IJET=N+1,N+NJET + IF(P(IJET,5).LT.RINIT) GOTO 340 + R2=R2T(I,IJET) + IF(R2.GE.R2MIN) GOTO 340 + IMIN=IJET + R2MIN=R2 + 340 CONTINUE + K(I,4)=IMIN-N + DO 350 J=1,4 + V(IMIN,J)=V(IMIN,J)+P(I,J) + 350 CONTINUE + 360 CONTINUE + PSJT=0. + DO 380 I=N+1,N+NJET + DO 370 J=1,4 + P(I,J)=V(I,J) + 370 CONTINUE + P(I,5)=SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2) + PSJT=PSJT+P(I,5) + 380 CONTINUE + ENDIF + +C...Find two closest jets. + R2MIN=2.*MAX(R2ACC,PS(5)**2) + DO 400 ITRY1=N+1,N+NJET-1 + DO 390 ITRY2=ITRY1+1,N+NJET + IF(MSTU(46).LE.2) R2=R2T(ITRY1,ITRY2) + IF(MSTU(46).GE.3) R2=R2M(ITRY1,ITRY2) + IF(R2.GE.R2MIN) GOTO 390 + IMIN1=ITRY1 + IMIN2=ITRY2 + R2MIN=R2 + 390 CONTINUE + 400 CONTINUE + +C...If allowed, join two closest jets and start over. + IF(NJET.GT.MSTU(47).AND.R2MIN.LT.R2ACC) THEN + IREC=MIN(IMIN1,IMIN2) + IDEL=MAX(IMIN1,IMIN2) + DO 410 J=1,4 + P(IREC,J)=P(IMIN1,J)+P(IMIN2,J) + 410 CONTINUE + P(IREC,5)=SQRT(P(IREC,1)**2+P(IREC,2)**2+P(IREC,3)**2) + DO 430 I=IDEL+1,N+NJET + DO 420 J=1,5 + P(I-1,J)=P(I,J) + 420 CONTINUE + 430 CONTINUE + IF(MSTU(46).GE.2) THEN + DO 440 I=N+NP+1,N+2*NP + IORI=N+K(I,4) + IF(IORI.EQ.IDEL) K(I,4)=IREC-N + IF(IORI.GT.IDEL) K(I,4)=K(I,4)-1 + 440 CONTINUE + ENDIF + NJET=NJET-1 + GOTO 300 + +C...Divide up broad jet if empty cluster in list of final ones. + ELSEIF(NJET.EQ.MSTU(47).AND.MSTU(46).LE.1.AND.NLOOP.LE.2) THEN + DO 450 I=N+1,N+NJET + K(I,5)=0 + 450 CONTINUE + DO 460 I=N+NP+1,N+2*NP + K(N+K(I,4),5)=K(N+K(I,4),5)+1 + 460 CONTINUE + IEMP=0 + DO 470 I=N+1,N+NJET + IF(K(I,5).EQ.0) IEMP=I + 470 CONTINUE + IF(IEMP.NE.0) THEN + NLOOP=NLOOP+1 + ISPL=0 + R2MAX=0. + DO 480 I=N+NP+1,N+2*NP + IF(K(N+K(I,4),5).LE.1.OR.P(I,5).LT.RINIT) GOTO 480 + IJET=N+K(I,4) + R2=R2T(I,IJET) + IF(R2.LE.R2MAX) GOTO 480 + ISPL=I + R2MAX=R2 + 480 CONTINUE + IF(ISPL.NE.0) THEN + IJET=N+K(ISPL,4) + DO 490 J=1,4 + P(IEMP,J)=P(ISPL,J) + P(IJET,J)=P(IJET,J)-P(ISPL,J) + 490 CONTINUE + P(IEMP,5)=P(ISPL,5) + P(IJET,5)=SQRT(P(IJET,1)**2+P(IJET,2)**2+P(IJET,3)**2) + IF(NLOOP.LE.2) GOTO 300 + ENDIF + ENDIF + ENDIF + +C...If generalized thrust has not yet converged, continue iteration. + IF(MSTU(46).LE.1.AND.NLOOP.LE.2.AND.PSJT/PSS.GT.TSAV+PARU(48)) + &THEN + TSAV=PSJT/PSS + GOTO 310 + ENDIF + +C...Reorder jets according to energy. + DO 510 I=N+1,N+NJET + DO 500 J=1,5 + V(I,J)=P(I,J) + 500 CONTINUE + 510 CONTINUE + DO 540 INEW=N+1,N+NJET + PEMAX=0. + DO 520 ITRY=N+1,N+NJET + IF(V(ITRY,4).LE.PEMAX) GOTO 520 + IMAX=ITRY + PEMAX=V(ITRY,4) + 520 CONTINUE + K(INEW,1)=31 + K(INEW,2)=97 + K(INEW,3)=INEW-N + K(INEW,4)=0 + DO 530 J=1,5 + P(INEW,J)=V(IMAX,J) + 530 CONTINUE + V(IMAX,4)=-1. + K(IMAX,5)=INEW + 540 CONTINUE + +C...Clean up particle-jet assignments and jet information. + DO 550 I=N+NP+1,N+2*NP + IORI=K(N+K(I,4),5) + K(I,4)=IORI-N + IF(K(K(I,3),1).NE.3) K(K(I,3),4)=IORI-N + K(IORI,4)=K(IORI,4)+1 + 550 CONTINUE + IEMP=0 + PSJT=0. + DO 570 I=N+1,N+NJET + K(I,5)=0 + PSJT=PSJT+P(I,5) + P(I,5)=SQRT(MAX(P(I,4)**2-P(I,5)**2,0.D0)) + DO 560 J=1,5 + V(I,J)=0. + 560 CONTINUE + IF(K(I,4).EQ.0) IEMP=I + 570 CONTINUE + +C...Select storing option. Output variables. Check for failure. + MSTU(61)=N+1 + MSTU(62)=NP + MSTU(63)=NPRE + PARU(61)=PS(5) + PARU(62)=PSJT/PSS + PARU(63)=SQRT(R2MIN) + IF(NJET.LE.1) PARU(63)=0. + IF(IEMP.NE.0) THEN + CALL LUERRM(8,'(LUCLUS:) failed to reconstruct as requested') + NJET=-1 + ENDIF + IF(MSTU(43).LE.1) MSTU(3)=NJET + IF(MSTU(43).GE.2) N=N+NJET + NSAV=NJET + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUCELL + SUBROUTINE LUCELL(NJET) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to provide a simple way of jet finding in an eta-phi-ET +C...coordinate frame, as used for calorimeters at hadron colliders. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + +C...Loop over all particles. Find cell that was hit by given particle. + PTLRAT=1./SINH(PARU(51))**2 + NP=0 + NC=N + DO 110 I=1,N + IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 110 + IF(P(I,1)**2+P(I,2)**2.LE.PTLRAT*P(I,3)**2) GOTO 110 + IF(MSTU(41).GE.2) THEN + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR. + & KC.EQ.18) GOTO 110 + IF(MSTU(41).GE.3.AND.KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) + & GOTO 110 + ENDIF + NP=NP+1 + PT=SQRT(P(I,1)**2+P(I,2)**2) + ETA=SIGN(LOG((SQRT(PT**2+P(I,3)**2)+ABS(P(I,3)))/PT),P(I,3)) + IETA=MAX(1,MIN(MSTU(51),1+INT(MSTU(51)*0.5*(ETA/PARU(51)+1.)))) + PHI=ULANGL(P(I,1),P(I,2)) + IPHI=MAX(1,MIN(MSTU(52),1+INT(MSTU(52)*0.5*(PHI/PARU(1)+1.)))) + IETPH=MSTU(52)*IETA+IPHI + +C...Add to cell already hit, or book new cell. + DO 100 IC=N+1,NC + IF(IETPH.EQ.K(IC,3)) THEN + K(IC,4)=K(IC,4)+1 + P(IC,5)=P(IC,5)+PT + GOTO 110 + ENDIF + 100 CONTINUE + IF(NC.GE.MSTU(4)-MSTU(32)-5) THEN + CALL LUERRM(11,'(LUCELL:) no more memory left in LUJETS') + NJET=-2 + RETURN + ENDIF + NC=NC+1 + K(NC,3)=IETPH + K(NC,4)=1 + K(NC,5)=2 + P(NC,1)=(PARU(51)/MSTU(51))*(2*IETA-1-MSTU(51)) + P(NC,2)=(PARU(1)/MSTU(52))*(2*IPHI-1-MSTU(52)) + P(NC,5)=PT + 110 CONTINUE + +C...Smear true bin content by calorimeter resolution. + IF(MSTU(53).GE.1) THEN + DO 130 IC=N+1,NC + PEI=P(IC,5) + IF(MSTU(53).EQ.2) PEI=P(IC,5)*COSH(P(IC,1)) + 120 PEF=PEI+PARU(55)*SQRT(-2.*LOG(MAX(1D-10,RLU(0)))*PEI)* + & COS(PARU(2)*RLU(0)) + IF(PEF.LT.0..OR.PEF.GT.PARU(56)*PEI) GOTO 120 + P(IC,5)=PEF + IF(MSTU(53).EQ.2) P(IC,5)=PEF/COSH(P(IC,1)) + 130 CONTINUE + ENDIF + +C...Remove cells below threshold. + IF(PARU(58).GT.0.) THEN + NCC=NC + NC=N + DO 140 IC=N+1,NCC + IF(P(IC,5).GT.PARU(58)) THEN + NC=NC+1 + K(NC,3)=K(IC,3) + K(NC,4)=K(IC,4) + K(NC,5)=K(IC,5) + P(NC,1)=P(IC,1) + P(NC,2)=P(IC,2) + P(NC,5)=P(IC,5) + ENDIF + 140 CONTINUE + ENDIF + +C...Find initiator cell: the one with highest pT of not yet used ones. + NJ=NC + 150 ETMAX=0. + DO 160 IC=N+1,NC + IF(K(IC,5).NE.2) GOTO 160 + IF(P(IC,5).LE.ETMAX) GOTO 160 + ICMAX=IC + ETA=P(IC,1) + PHI=P(IC,2) + ETMAX=P(IC,5) + 160 CONTINUE + IF(ETMAX.LT.PARU(52)) GOTO 220 + IF(NJ.GE.MSTU(4)-MSTU(32)-5) THEN + CALL LUERRM(11,'(LUCELL:) no more memory left in LUJETS') + NJET=-2 + RETURN + ENDIF + K(ICMAX,5)=1 + NJ=NJ+1 + K(NJ,4)=0 + K(NJ,5)=1 + P(NJ,1)=ETA + P(NJ,2)=PHI + P(NJ,3)=0. + P(NJ,4)=0. + P(NJ,5)=0. + +C...Sum up unused cells within required distance of initiator. + DO 170 IC=N+1,NC + IF(K(IC,5).EQ.0) GOTO 170 + IF(ABS(P(IC,1)-ETA).GT.PARU(54)) GOTO 170 + DPHIA=ABS(P(IC,2)-PHI) + IF(DPHIA.GT.PARU(54).AND.DPHIA.LT.PARU(2)-PARU(54)) GOTO 170 + PHIC=P(IC,2) + IF(DPHIA.GT.PARU(1)) PHIC=PHIC+SIGN(PARU(2),PHI) + IF((P(IC,1)-ETA)**2+(PHIC-PHI)**2.GT.PARU(54)**2) GOTO 170 + K(IC,5)=-K(IC,5) + K(NJ,4)=K(NJ,4)+K(IC,4) + P(NJ,3)=P(NJ,3)+P(IC,5)*P(IC,1) + P(NJ,4)=P(NJ,4)+P(IC,5)*PHIC + P(NJ,5)=P(NJ,5)+P(IC,5) + 170 CONTINUE + +C...Reject cluster below minimum ET, else accept. + IF(P(NJ,5).LT.PARU(53)) THEN + NJ=NJ-1 + DO 180 IC=N+1,NC + IF(K(IC,5).LT.0) K(IC,5)=-K(IC,5) + 180 CONTINUE + ELSEIF(MSTU(54).LE.2) THEN + P(NJ,3)=P(NJ,3)/P(NJ,5) + P(NJ,4)=P(NJ,4)/P(NJ,5) + IF(ABS(P(NJ,4)).GT.PARU(1)) P(NJ,4)=P(NJ,4)-SIGN(PARU(2), + & P(NJ,4)) + DO 190 IC=N+1,NC + IF(K(IC,5).LT.0) K(IC,5)=0 + 190 CONTINUE + ELSE + DO 200 J=1,4 + P(NJ,J)=0. + 200 CONTINUE + DO 210 IC=N+1,NC + IF(K(IC,5).GE.0) GOTO 210 + P(NJ,1)=P(NJ,1)+P(IC,5)*COS(P(IC,2)) + P(NJ,2)=P(NJ,2)+P(IC,5)*SIN(P(IC,2)) + P(NJ,3)=P(NJ,3)+P(IC,5)*SINH(P(IC,1)) + P(NJ,4)=P(NJ,4)+P(IC,5)*COSH(P(IC,1)) + K(IC,5)=0 + 210 CONTINUE + ENDIF + GOTO 150 + +C...Arrange clusters in falling ET sequence. + 220 DO 250 I=1,NJ-NC + ETMAX=0. + DO 230 IJ=NC+1,NJ + IF(K(IJ,5).EQ.0) GOTO 230 + IF(P(IJ,5).LT.ETMAX) GOTO 230 + IJMAX=IJ + ETMAX=P(IJ,5) + 230 CONTINUE + K(IJMAX,5)=0 + K(N+I,1)=31 + K(N+I,2)=98 + K(N+I,3)=I + K(N+I,4)=K(IJMAX,4) + K(N+I,5)=0 + DO 240 J=1,5 + P(N+I,J)=P(IJMAX,J) + V(N+I,J)=0. + 240 CONTINUE + 250 CONTINUE + NJET=NJ-NC + +C...Convert to massless or massive four-vectors. + IF(MSTU(54).EQ.2) THEN + DO 260 I=N+1,N+NJET + ETA=P(I,3) + P(I,1)=P(I,5)*COS(P(I,4)) + P(I,2)=P(I,5)*SIN(P(I,4)) + P(I,3)=P(I,5)*SINH(ETA) + P(I,4)=P(I,5)*COSH(ETA) + P(I,5)=0. + 260 CONTINUE + ELSEIF(MSTU(54).GE.3) THEN + DO 270 I=N+1,N+NJET + P(I,5)=SQRT(MAX(0.D0,P(I,4)**2-P(I,1)**2-P(I,2)**2-P(I,3)**2)) + 270 CONTINUE + ENDIF + +C...Information about storage. + MSTU(61)=N+1 + MSTU(62)=NP + MSTU(63)=NC-N + IF(MSTU(43).LE.1) MSTU(3)=NJET + IF(MSTU(43).GE.2) N=N+NJET + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUJMAS + SUBROUTINE LUJMAS(PMH,PML) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to determine, approximately, the two jet masses that +C...minimize the sum m_H^2 + m_L^2, a la Clavelli and Wyler. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + DIMENSION SM(3,3),SAX(3),PS(3,5) + +C...Reset. + NP=0 + DO 120 J1=1,3 + DO 100 J2=J1,3 + SM(J1,J2)=0. + 100 CONTINUE + DO 110 J2=1,4 + PS(J1,J2)=0. + 110 CONTINUE + 120 CONTINUE + PSS=0. + +C...Take copy of particles that are to be considered in mass analysis. + DO 170 I=1,N + IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 170 + IF(MSTU(41).GE.2) THEN + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR. + & KC.EQ.18) GOTO 170 + IF(MSTU(41).GE.3.AND.KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) + & GOTO 170 + ENDIF + IF(N+NP+1.GE.MSTU(4)-MSTU(32)-5) THEN + CALL LUERRM(11,'(LUJMAS:) no more memory left in LUJETS') + PMH=-2. + PML=-2. + RETURN + ENDIF + NP=NP+1 + DO 130 J=1,5 + P(N+NP,J)=P(I,J) + 130 CONTINUE + IF(MSTU(42).EQ.0) P(N+NP,5)=0. + IF(MSTU(42).EQ.1.AND.K(I,2).NE.22) P(N+NP,5)=PMAS(101,1) + P(N+NP,4)=SQRT(P(N+NP,5)**2+P(I,1)**2+P(I,2)**2+P(I,3)**2) + +C...Fill information in sphericity tensor and total momentum vector. + DO 150 J1=1,3 + DO 140 J2=J1,3 + SM(J1,J2)=SM(J1,J2)+P(I,J1)*P(I,J2) + 140 CONTINUE + 150 CONTINUE + PSS=PSS+(P(I,1)**2+P(I,2)**2+P(I,3)**2) + DO 160 J=1,4 + PS(3,J)=PS(3,J)+P(N+NP,J) + 160 CONTINUE + 170 CONTINUE + +C...Very low multiplicities (0 or 1) not considered. + IF(NP.LE.1) THEN + CALL LUERRM(8,'(LUJMAS:) too few particles for analysis') + PMH=-1. + PML=-1. + RETURN + ENDIF + PARU(61)= + &SQRT(MAX(0.D0,PS(3,4)**2-PS(3,1)**2-PS(3,2)**2-PS(3,3)**2)) + +C...Find largest eigenvalue to matrix (third degree equation). + DO 190 J1=1,3 + DO 180 J2=J1,3 + SM(J1,J2)=SM(J1,J2)/PSS + 180 CONTINUE + 190 CONTINUE + SQ=(SM(1,1)*SM(2,2)+SM(1,1)*SM(3,3)+SM(2,2)*SM(3,3)-SM(1,2)**2- + &SM(1,3)**2-SM(2,3)**2)/3.-1./9. + SR=-0.5*(SQ+1./9.+SM(1,1)*SM(2,3)**2+SM(2,2)*SM(1,3)**2+SM(3,3)* + &SM(1,2)**2-SM(1,1)*SM(2,2)*SM(3,3))+SM(1,2)*SM(1,3)*SM(2,3)+1./27. + SP=COS(ACOS(MAX(MIN(SR/SQRT(-SQ**3),1.D0),-1.D0))/3.) + SMA=1./3.+SQRT(-SQ)*MAX(2.*SP,SQRT(3.*(1.-SP**2))-SP) + +C...Find largest eigenvector by solving equation system. + DO 210 J1=1,3 + SM(J1,J1)=SM(J1,J1)-SMA + DO 200 J2=J1+1,3 + SM(J2,J1)=SM(J1,J2) + 200 CONTINUE + 210 CONTINUE + SMAX=0. + DO 230 J1=1,3 + DO 220 J2=1,3 + IF(ABS(SM(J1,J2)).LE.SMAX) GOTO 220 + JA=J1 + JB=J2 + SMAX=ABS(SM(J1,J2)) + 220 CONTINUE + 230 CONTINUE + SMAX=0. + DO 250 J3=JA+1,JA+2 + J1=J3-3*((J3-1)/3) + RL=SM(J1,JB)/SM(JA,JB) + DO 240 J2=1,3 + SM(J1,J2)=SM(J1,J2)-RL*SM(JA,J2) + IF(ABS(SM(J1,J2)).LE.SMAX) GOTO 240 + JC=J1 + SMAX=ABS(SM(J1,J2)) + 240 CONTINUE + 250 CONTINUE + JB1=JB+1-3*(JB/3) + JB2=JB+2-3*((JB+1)/3) + SAX(JB1)=-SM(JC,JB2) + SAX(JB2)=SM(JC,JB1) + SAX(JB)=-(SM(JA,JB1)*SAX(JB1)+SM(JA,JB2)*SAX(JB2))/SM(JA,JB) + +C...Divide particles into two initial clusters by hemisphere. + DO 270 I=N+1,N+NP + PSAX=P(I,1)*SAX(1)+P(I,2)*SAX(2)+P(I,3)*SAX(3) + IS=1 + IF(PSAX.LT.0.) IS=2 + K(I,3)=IS + DO 260 J=1,4 + PS(IS,J)=PS(IS,J)+P(I,J) + 260 CONTINUE + 270 CONTINUE + PMS=MAX(1D-10,PS(1,4)**2-PS(1,1)**2-PS(1,2)**2-PS(1,3)**2)+ + &MAX(1D-10,PS(2,4)**2-PS(2,1)**2-PS(2,2)**2-PS(2,3)**2) + +C...Reassign one particle at a time; find maximum decrease of m^2 sum. + 280 PMD=0. + IM=0 + DO 290 J=1,4 + PS(3,J)=PS(1,J)-PS(2,J) + 290 CONTINUE + DO 300 I=N+1,N+NP + PPS=P(I,4)*PS(3,4)-P(I,1)*PS(3,1)-P(I,2)*PS(3,2)-P(I,3)*PS(3,3) + IF(K(I,3).EQ.1) PMDI=2.*(P(I,5)**2-PPS) + IF(K(I,3).EQ.2) PMDI=2.*(P(I,5)**2+PPS) + IF(PMDI.LT.PMD) THEN + PMD=PMDI + IM=I + ENDIF + 300 CONTINUE + +C...Loop back if significant reduction in sum of m^2. + IF(PMD.LT.-PARU(48)*PMS) THEN + PMS=PMS+PMD + IS=K(IM,3) + DO 310 J=1,4 + PS(IS,J)=PS(IS,J)-P(IM,J) + PS(3-IS,J)=PS(3-IS,J)+P(IM,J) + 310 CONTINUE + K(IM,3)=3-IS + GOTO 280 + ENDIF + +C...Final masses and output. + MSTU(61)=N+1 + MSTU(62)=NP + PS(1,5)= + &SQRT(MAX(0.D0,PS(1,4)**2-PS(1,1)**2-PS(1,2)**2-PS(1,3)**2)) + PS(2,5)= + &SQRT(MAX(0.D0,PS(2,4)**2-PS(2,1)**2-PS(2,2)**2-PS(2,3)**2)) + PMH=MAX(PS(1,5),PS(2,5)) + PML=MIN(PS(1,5),PS(2,5)) + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUFOWO + SUBROUTINE LUFOWO(H10,H20,H30,H40) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to calculate the first few Fox-Wolfram moments. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + +C...Copy momenta for particles and calculate H0. + NP=0 + H0=0. + HD=0. + DO 110 I=1,N + IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 110 + IF(MSTU(41).GE.2) THEN + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR. + & KC.EQ.18) GOTO 110 + IF(MSTU(41).GE.3.AND.KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) + & GOTO 110 + ENDIF + IF(N+NP.GE.MSTU(4)-MSTU(32)-5) THEN + CALL LUERRM(11,'(LUFOWO:) no more memory left in LUJETS') + H10=-1. + H20=-1. + H30=-1. + H40=-1. + RETURN + ENDIF + NP=NP+1 + DO 100 J=1,3 + P(N+NP,J)=P(I,J) + 100 CONTINUE + P(N+NP,4)=SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2) + H0=H0+P(N+NP,4) + HD=HD+P(N+NP,4)**2 + 110 CONTINUE + H0=H0**2 + +C...Very low multiplicities (0 or 1) not considered. + IF(NP.LE.1) THEN + CALL LUERRM(8,'(LUFOWO:) too few particles for analysis') + H10=-1. + H20=-1. + H30=-1. + H40=-1. + RETURN + ENDIF + +C...Calculate H1 - H4. + H10=0. + H20=0. + H30=0. + H40=0. + DO 130 I1=N+1,N+NP + DO 120 I2=I1+1,N+NP + CTHE=(P(I1,1)*P(I2,1)+P(I1,2)*P(I2,2)+P(I1,3)*P(I2,3))/ + &(P(I1,4)*P(I2,4)) + H10=H10+P(I1,4)*P(I2,4)*CTHE + H20=H20+P(I1,4)*P(I2,4)*(1.5*CTHE**2-0.5) + H30=H30+P(I1,4)*P(I2,4)*(2.5*CTHE**3-1.5*CTHE) + H40=H40+P(I1,4)*P(I2,4)*(4.375*CTHE**4-3.75*CTHE**2+0.375) + 120 CONTINUE + 130 CONTINUE + +C...Calculate H1/H0 - H4/H0. Output. + MSTU(61)=N+1 + MSTU(62)=NP + H10=(HD+2.*H10)/H0 + H20=(HD+2.*H20)/H0 + H30=(HD+2.*H30)/H0 + H40=(HD+2.*H40)/H0 + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUTABU + SUBROUTINE LUTABU(MTABU) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to evaluate various properties of an event, with +C...statistics accumulated during the course of the run and +C...printed at the end. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/,/LUDAT3/ + DIMENSION KFIS(100,2),NPIS(100,0:10),KFFS(400),NPFS(400,4), + &FEVFM(10,4),FM1FM(3,10,4),FM2FM(3,10,4),FMOMA(4),FMOMS(4), + &FEVEE(50),FE1EC(50),FE2EC(50),FE1EA(25),FE2EA(25), + &KFDM(8),KFDC(200,0:8),NPDC(200) + SAVE NEVIS,NKFIS,KFIS,NPIS,NEVFS,NPRFS,NFIFS,NCHFS,NKFFS, + &KFFS,NPFS,NEVFM,NMUFM,FM1FM,FM2FM,NEVEE,FE1EC,FE2EC,FE1EA, + &FE2EA,NEVDC,NKFDC,NREDC,KFDC,NPDC + CHARACTER CHAU*16,CHIS(2)*12,CHDC(8)*12 + DATA NEVIS/0/,NKFIS/0/,NEVFS/0/,NPRFS/0/,NFIFS/0/,NCHFS/0/, + &NKFFS/0/,NEVFM/0/,NMUFM/0/,FM1FM/120*0./,FM2FM/120*0./, + &NEVEE/0/,FE1EC/50*0./,FE2EC/50*0./,FE1EA/25*0./,FE2EA/25*0./, + &NEVDC/0/,NKFDC/0/,NREDC/0/ + +C...Reset statistics on initial parton state. + IF(MTABU.EQ.10) THEN + NEVIS=0 + NKFIS=0 + +C...Identify and order flavour content of initial state. + ELSEIF(MTABU.EQ.11) THEN + NEVIS=NEVIS+1 + KFM1=2*IABS(MSTU(161)) + IF(MSTU(161).GT.0) KFM1=KFM1-1 + KFM2=2*IABS(MSTU(162)) + IF(MSTU(162).GT.0) KFM2=KFM2-1 + KFMN=MIN(KFM1,KFM2) + KFMX=MAX(KFM1,KFM2) + DO 100 I=1,NKFIS + IF(KFMN.EQ.KFIS(I,1).AND.KFMX.EQ.KFIS(I,2)) THEN + IKFIS=-I + GOTO 110 + ELSEIF(KFMN.LT.KFIS(I,1).OR.(KFMN.EQ.KFIS(I,1).AND. + & KFMX.LT.KFIS(I,2))) THEN + IKFIS=I + GOTO 110 + ENDIF + 100 CONTINUE + IKFIS=NKFIS+1 + 110 IF(IKFIS.LT.0) THEN + IKFIS=-IKFIS + ELSE + IF(NKFIS.GE.100) RETURN + DO 130 I=NKFIS,IKFIS,-1 + KFIS(I+1,1)=KFIS(I,1) + KFIS(I+1,2)=KFIS(I,2) + DO 120 J=0,10 + NPIS(I+1,J)=NPIS(I,J) + 120 CONTINUE + 130 CONTINUE + NKFIS=NKFIS+1 + KFIS(IKFIS,1)=KFMN + KFIS(IKFIS,2)=KFMX + DO 140 J=0,10 + NPIS(IKFIS,J)=0 + 140 CONTINUE + ENDIF + NPIS(IKFIS,0)=NPIS(IKFIS,0)+1 + +C...Count number of partons in initial state. + NP=0 + DO 160 I=1,N + IF(K(I,1).LE.0.OR.K(I,1).GT.12) THEN + ELSEIF(IABS(K(I,2)).GT.80.AND.IABS(K(I,2)).LE.100) THEN + ELSEIF(IABS(K(I,2)).GT.100.AND.MOD(IABS(K(I,2))/10,10).NE.0) + & THEN + ELSE + IM=I + 150 IM=K(IM,3) + IF(IM.LE.0.OR.IM.GT.N) THEN + NP=NP+1 + ELSEIF(K(IM,1).LE.0.OR.K(IM,1).GT.20) THEN + NP=NP+1 + ELSEIF(IABS(K(IM,2)).GT.80.AND.IABS(K(IM,2)).LE.100) THEN + ELSEIF(IABS(K(IM,2)).GT.100.AND.MOD(IABS(K(IM,2))/10,10).NE.0) + & THEN + ELSE + GOTO 150 + ENDIF + ENDIF + 160 CONTINUE + NPCO=MAX(NP,1) + IF(NP.GE.6) NPCO=6 + IF(NP.GE.8) NPCO=7 + IF(NP.GE.11) NPCO=8 + IF(NP.GE.16) NPCO=9 + IF(NP.GE.26) NPCO=10 + NPIS(IKFIS,NPCO)=NPIS(IKFIS,NPCO)+1 + MSTU(62)=NP + +C...Write statistics on initial parton state. + ELSEIF(MTABU.EQ.12) THEN + FAC=1./MAX(1,NEVIS) + WRITE(MSTU(11),5000) NEVIS + DO 170 I=1,NKFIS + KFMN=KFIS(I,1) + IF(KFMN.EQ.0) KFMN=KFIS(I,2) + KFM1=(KFMN+1)/2 + IF(2*KFM1.EQ.KFMN) KFM1=-KFM1 + CALL LUNAME(KFM1,CHAU) + CHIS(1)=CHAU(1:12) + IF(CHAU(13:13).NE.' ') CHIS(1)(12:12)='?' + KFMX=KFIS(I,2) + IF(KFIS(I,1).EQ.0) KFMX=0 + KFM2=(KFMX+1)/2 + IF(2*KFM2.EQ.KFMX) KFM2=-KFM2 + CALL LUNAME(KFM2,CHAU) + CHIS(2)=CHAU(1:12) + IF(CHAU(13:13).NE.' ') CHIS(2)(12:12)='?' + WRITE(MSTU(11),5100) CHIS(1),CHIS(2),FAC*NPIS(I,0), + & (NPIS(I,J)/ DBLE(NPIS(I,0)),J=1,10) + 170 CONTINUE + +C...Copy statistics on initial parton state into /LUJETS/. + ELSEIF(MTABU.EQ.13) THEN + FAC=1./MAX(1,NEVIS) + DO 190 I=1,NKFIS + KFMN=KFIS(I,1) + IF(KFMN.EQ.0) KFMN=KFIS(I,2) + KFM1=(KFMN+1)/2 + IF(2*KFM1.EQ.KFMN) KFM1=-KFM1 + KFMX=KFIS(I,2) + IF(KFIS(I,1).EQ.0) KFMX=0 + KFM2=(KFMX+1)/2 + IF(2*KFM2.EQ.KFMX) KFM2=-KFM2 + K(I,1)=32 + K(I,2)=99 + K(I,3)=KFM1 + K(I,4)=KFM2 + K(I,5)=NPIS(I,0) + DO 180 J=1,5 + P(I,J)=FAC*NPIS(I,J) + V(I,J)=FAC*NPIS(I,J+5) + 180 CONTINUE + 190 CONTINUE + N=NKFIS + DO 200 J=1,5 + K(N+1,J)=0 + P(N+1,J)=0. + V(N+1,J)=0. + 200 CONTINUE + K(N+1,1)=32 + K(N+1,2)=99 + K(N+1,5)=NEVIS + MSTU(3)=1 + +C...Reset statistics on number of particles/partons. + ELSEIF(MTABU.EQ.20) THEN + NEVFS=0 + NPRFS=0 + NFIFS=0 + NCHFS=0 + NKFFS=0 + +C...Identify whether particle/parton is primary or not. + ELSEIF(MTABU.EQ.21) THEN + NEVFS=NEVFS+1 + MSTU(62)=0 + DO 260 I=1,N + IF(K(I,1).LE.0.OR.K(I,1).GT.20.OR.K(I,1).EQ.13) GOTO 260 + MSTU(62)=MSTU(62)+1 + KC=LUCOMP(K(I,2)) + MPRI=0 + IF(K(I,3).LE.0.OR.K(I,3).GT.N) THEN + MPRI=1 + ELSEIF(K(K(I,3),1).LE.0.OR.K(K(I,3),1).GT.20) THEN + MPRI=1 + ELSEIF(K(K(I,3),2).GE.91.AND.K(K(I,3),2).LE.93) THEN + MPRI=1 + ELSEIF(KC.EQ.0) THEN + ELSEIF(K(K(I,3),1).EQ.13) THEN + IM=K(K(I,3),3) + IF(IM.LE.0.OR.IM.GT.N) THEN + MPRI=1 + ELSEIF(K(IM,1).LE.0.OR.K(IM,1).GT.20) THEN + MPRI=1 + ENDIF + ELSEIF(KCHG(KC,2).EQ.0) THEN + KCM=LUCOMP(K(K(I,3),2)) + IF(KCM.NE.0) THEN + IF(KCHG(KCM,2).NE.0) MPRI=1 + ENDIF + ENDIF + IF(KC.NE.0.AND.MPRI.EQ.1) THEN + IF(KCHG(KC,2).EQ.0) NPRFS=NPRFS+1 + ENDIF + IF(K(I,1).LE.10) THEN + NFIFS=NFIFS+1 + IF(LUCHGE(K(I,2)).NE.0) NCHFS=NCHFS+1 + ENDIF + +C...Fill statistics on number of particles/partons in event. + KFA=IABS(K(I,2)) + KFS=3-ISIGN(1,K(I,2))-MPRI + DO 210 IP=1,NKFFS + IF(KFA.EQ.KFFS(IP)) THEN + IKFFS=-IP + GOTO 220 + ELSEIF(KFA.LT.KFFS(IP)) THEN + IKFFS=IP + GOTO 220 + ENDIF + 210 CONTINUE + IKFFS=NKFFS+1 + 220 IF(IKFFS.LT.0) THEN + IKFFS=-IKFFS + ELSE + IF(NKFFS.GE.400) RETURN + DO 240 IP=NKFFS,IKFFS,-1 + KFFS(IP+1)=KFFS(IP) + DO 230 J=1,4 + NPFS(IP+1,J)=NPFS(IP,J) + 230 CONTINUE + 240 CONTINUE + NKFFS=NKFFS+1 + KFFS(IKFFS)=KFA + DO 250 J=1,4 + NPFS(IKFFS,J)=0 + 250 CONTINUE + ENDIF + NPFS(IKFFS,KFS)=NPFS(IKFFS,KFS)+1 + 260 CONTINUE + +C...Write statistics on particle/parton composition of events. + ELSEIF(MTABU.EQ.22) THEN + FAC=1./MAX(1,NEVFS) + WRITE(MSTU(11),5200) NEVFS,FAC*NPRFS,FAC*NFIFS,FAC*NCHFS + DO 270 I=1,NKFFS + CALL LUNAME(KFFS(I),CHAU) + KC=LUCOMP(KFFS(I)) + MDCYF=0 + IF(KC.NE.0) MDCYF=MDCY(KC,1) + WRITE(MSTU(11),5300) KFFS(I),CHAU,MDCYF,(FAC*NPFS(I,J),J=1,4), + & FAC*(NPFS(I,1)+NPFS(I,2)+NPFS(I,3)+NPFS(I,4)) + 270 CONTINUE + +C...Copy particle/parton composition information into /LUJETS/. + ELSEIF(MTABU.EQ.23) THEN + FAC=1./MAX(1,NEVFS) + DO 290 I=1,NKFFS + K(I,1)=32 + K(I,2)=99 + K(I,3)=KFFS(I) + K(I,4)=0 + K(I,5)=NPFS(I,1)+NPFS(I,2)+NPFS(I,3)+NPFS(I,4) + DO 280 J=1,4 + P(I,J)=FAC*NPFS(I,J) + V(I,J)=0. + 280 CONTINUE + P(I,5)=FAC*K(I,5) + V(I,5)=0. + 290 CONTINUE + N=NKFFS + DO 300 J=1,5 + K(N+1,J)=0 + P(N+1,J)=0. + V(N+1,J)=0. + 300 CONTINUE + K(N+1,1)=32 + K(N+1,2)=99 + K(N+1,5)=NEVFS + P(N+1,1)=FAC*NPRFS + P(N+1,2)=FAC*NFIFS + P(N+1,3)=FAC*NCHFS + MSTU(3)=1 + +C...Reset factorial moments statistics. + ELSEIF(MTABU.EQ.30) THEN + NEVFM=0 + NMUFM=0 + DO 330 IM=1,3 + DO 320 IB=1,10 + DO 310 IP=1,4 + FM1FM(IM,IB,IP)=0. + FM2FM(IM,IB,IP)=0. + 310 CONTINUE + 320 CONTINUE + 330 CONTINUE + +C...Find particles to include, with (pion,pseudo)rapidity and azimuth. + ELSEIF(MTABU.EQ.31) THEN + NEVFM=NEVFM+1 + NLOW=N+MSTU(3) + NUPP=NLOW + DO 410 I=1,N + IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 410 + IF(MSTU(41).GE.2) THEN + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR. + & KC.EQ.18) GOTO 410 + IF(MSTU(41).GE.3.AND.KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) + & GOTO 410 + ENDIF + PMR=0. + IF(MSTU(42).EQ.1.AND.K(I,2).NE.22) PMR=ULMASS(211) + IF(MSTU(42).GE.2) PMR=P(I,5) + PR=MAX(1D-20,PMR**2+P(I,1)**2+P(I,2)**2) + YETA=SIGN(LOG(MIN((SQRT(PR+P(I,3)**2)+ABS(P(I,3)))/SQRT(PR), + & 1D20)),P(I,3)) + IF(ABS(YETA).GT.PARU(57)) GOTO 410 + PHI=ULANGL(P(I,1),P(I,2)) + IYETA=512.*(YETA+PARU(57))/(2.*PARU(57)) + IYETA=MAX(0,MIN(511,IYETA)) + IPHI=512.*(PHI+PARU(1))/PARU(2) + IPHI=MAX(0,MIN(511,IPHI)) + IYEP=0 + DO 340 IB=0,9 + IYEP=IYEP+4**IB*(2*MOD(IYETA/2**IB,2)+MOD(IPHI/2**IB,2)) + 340 CONTINUE + +C...Order particles in (pseudo)rapidity and/or azimuth. + IF(NUPP.GT.MSTU(4)-5-MSTU(32)) THEN + CALL LUERRM(11,'(LUTABU:) no more memory left in LUJETS') + RETURN + ENDIF + NUPP=NUPP+1 + IF(NUPP.EQ.NLOW+1) THEN + K(NUPP,1)=IYETA + K(NUPP,2)=IPHI + K(NUPP,3)=IYEP + ELSE + DO 350 I1=NUPP-1,NLOW+1,-1 + IF(IYETA.GE.K(I1,1)) GOTO 360 + K(I1+1,1)=K(I1,1) + 350 CONTINUE + 360 K(I1+1,1)=IYETA + DO 370 I1=NUPP-1,NLOW+1,-1 + IF(IPHI.GE.K(I1,2)) GOTO 380 + K(I1+1,2)=K(I1,2) + 370 CONTINUE + 380 K(I1+1,2)=IPHI + DO 390 I1=NUPP-1,NLOW+1,-1 + IF(IYEP.GE.K(I1,3)) GOTO 400 + K(I1+1,3)=K(I1,3) + 390 CONTINUE + 400 K(I1+1,3)=IYEP + ENDIF + 410 CONTINUE + K(NUPP+1,1)=2**10 + K(NUPP+1,2)=2**10 + K(NUPP+1,3)=4**10 + +C...Calculate sum of factorial moments in event. + DO 480 IM=1,3 + DO 430 IB=1,10 + DO 420 IP=1,4 + FEVFM(IB,IP)=0. + 420 CONTINUE + 430 CONTINUE + DO 450 IB=1,10 + IF(IM.LE.2) IBIN=2**(10-IB) + IF(IM.EQ.3) IBIN=4**(10-IB) + IAGR=K(NLOW+1,IM)/IBIN + NAGR=1 + DO 440 I=NLOW+2,NUPP+1 + ICUT=K(I,IM)/IBIN + IF(ICUT.EQ.IAGR) THEN + NAGR=NAGR+1 + ELSE + IF(NAGR.EQ.1) THEN + ELSEIF(NAGR.EQ.2) THEN + FEVFM(IB,1)=FEVFM(IB,1)+2. + ELSEIF(NAGR.EQ.3) THEN + FEVFM(IB,1)=FEVFM(IB,1)+6. + FEVFM(IB,2)=FEVFM(IB,2)+6. + ELSEIF(NAGR.EQ.4) THEN + FEVFM(IB,1)=FEVFM(IB,1)+12. + FEVFM(IB,2)=FEVFM(IB,2)+24. + FEVFM(IB,3)=FEVFM(IB,3)+24. + ELSE + FEVFM(IB,1)=FEVFM(IB,1)+NAGR*(NAGR-1.) + FEVFM(IB,2)=FEVFM(IB,2)+NAGR*(NAGR-1.)*(NAGR-2.) + FEVFM(IB,3)=FEVFM(IB,3)+NAGR*(NAGR-1.)*(NAGR-2.)*(NAGR-3.) + FEVFM(IB,4)=FEVFM(IB,4)+NAGR*(NAGR-1.)*(NAGR-2.)*(NAGR-3.)* + & (NAGR-4.) + ENDIF + IAGR=ICUT + NAGR=1 + ENDIF + 440 CONTINUE + 450 CONTINUE + +C...Add results to total statistics. + DO 470 IB=10,1,-1 + DO 460 IP=1,4 + IF(FEVFM(1,IP).LT.0.5) THEN + FEVFM(IB,IP)=0. + ELSEIF(IM.LE.2) THEN + FEVFM(IB,IP)=2.**((IB-1)*IP)*FEVFM(IB,IP)/FEVFM(1,IP) + ELSE + FEVFM(IB,IP)=4.**((IB-1)*IP)*FEVFM(IB,IP)/FEVFM(1,IP) + ENDIF + FM1FM(IM,IB,IP)=FM1FM(IM,IB,IP)+FEVFM(IB,IP) + FM2FM(IM,IB,IP)=FM2FM(IM,IB,IP)+FEVFM(IB,IP)**2 + 460 CONTINUE + 470 CONTINUE + 480 CONTINUE + NMUFM=NMUFM+(NUPP-NLOW) + MSTU(62)=NUPP-NLOW + +C...Write accumulated statistics on factorial moments. + ELSEIF(MTABU.EQ.32) THEN + FAC=1./MAX(1,NEVFM) + IF(MSTU(42).LE.0) WRITE(MSTU(11),5400) NEVFM,'eta' + IF(MSTU(42).EQ.1) WRITE(MSTU(11),5400) NEVFM,'ypi' + IF(MSTU(42).GE.2) WRITE(MSTU(11),5400) NEVFM,'y ' + DO 510 IM=1,3 + WRITE(MSTU(11),5500) + DO 500 IB=1,10 + BYETA=2.*PARU(57) + IF(IM.NE.2) BYETA=BYETA/2**(IB-1) + BPHI=PARU(2) + IF(IM.NE.1) BPHI=BPHI/2**(IB-1) + IF(IM.LE.2) BNAVE=FAC*NMUFM/ DBLE(2**(IB-1)) + IF(IM.EQ.3) BNAVE=FAC*NMUFM/ DBLE(4**(IB-1)) + DO 490 IP=1,4 + FMOMA(IP)=FAC*FM1FM(IM,IB,IP) + FMOMS(IP)=SQRT(MAX(0.D0,FAC*(FAC*FM2FM(IM,IB,IP)-FMOMA(IP)**2))) + 490 CONTINUE + WRITE(MSTU(11),5600) BYETA,BPHI,BNAVE,(FMOMA(IP),FMOMS(IP), + & IP=1,4) + 500 CONTINUE + 510 CONTINUE + +C...Copy statistics on factorial moments into /LUJETS/. + ELSEIF(MTABU.EQ.33) THEN + FAC=1./MAX(1,NEVFM) + DO 540 IM=1,3 + DO 530 IB=1,10 + I=10*(IM-1)+IB + K(I,1)=32 + K(I,2)=99 + K(I,3)=1 + IF(IM.NE.2) K(I,3)=2**(IB-1) + K(I,4)=1 + IF(IM.NE.1) K(I,4)=2**(IB-1) + K(I,5)=0 + P(I,1)=2.*PARU(57)/K(I,3) + V(I,1)=PARU(2)/K(I,4) + DO 520 IP=1,4 + P(I,IP+1)=FAC*FM1FM(IM,IB,IP) + V(I,IP+1)=SQRT(MAX(0.D0,FAC*(FAC*FM2FM(IM,IB,IP)-P(I,IP+1)**2))) + 520 CONTINUE + 530 CONTINUE + 540 CONTINUE + N=30 + DO 550 J=1,5 + K(N+1,J)=0 + P(N+1,J)=0. + V(N+1,J)=0. + 550 CONTINUE + K(N+1,1)=32 + K(N+1,2)=99 + K(N+1,5)=NEVFM + MSTU(3)=1 + +C...Reset statistics on Energy-Energy Correlation. + ELSEIF(MTABU.EQ.40) THEN + NEVEE=0 + DO 560 J=1,25 + FE1EC(J)=0. + FE2EC(J)=0. + FE1EC(51-J)=0. + FE2EC(51-J)=0. + FE1EA(J)=0. + FE2EA(J)=0. + 560 CONTINUE + +C...Find particles to include, with proper assumed mass. + ELSEIF(MTABU.EQ.41) THEN + NEVEE=NEVEE+1 + NLOW=N+MSTU(3) + NUPP=NLOW + ECM=0. + DO 570 I=1,N + IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 570 + IF(MSTU(41).GE.2) THEN + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR. + & KC.EQ.18) GOTO 570 + IF(MSTU(41).GE.3.AND.KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) + & GOTO 570 + ENDIF + PMR=0. + IF(MSTU(42).EQ.1.AND.K(I,2).NE.22) PMR=ULMASS(211) + IF(MSTU(42).GE.2) PMR=P(I,5) + IF(NUPP.GT.MSTU(4)-5-MSTU(32)) THEN + CALL LUERRM(11,'(LUTABU:) no more memory left in LUJETS') + RETURN + ENDIF + NUPP=NUPP+1 + P(NUPP,1)=P(I,1) + P(NUPP,2)=P(I,2) + P(NUPP,3)=P(I,3) + P(NUPP,4)=SQRT(PMR**2+P(I,1)**2+P(I,2)**2+P(I,3)**2) + P(NUPP,5)=MAX(1D-10,SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2)) + ECM=ECM+P(NUPP,4) + 570 CONTINUE + IF(NUPP.EQ.NLOW) RETURN + +C...Analyze Energy-Energy Correlation in event. + FAC=(2./ECM**2)*50./PARU(1) + DO 580 J=1,50 + FEVEE(J)=0. + 580 CONTINUE + DO 600 I1=NLOW+2,NUPP + DO 590 I2=NLOW+1,I1-1 + CTHE=(P(I1,1)*P(I2,1)+P(I1,2)*P(I2,2)+P(I1,3)*P(I2,3))/ + & (P(I1,5)*P(I2,5)) + THE=ACOS(MAX(-1.D0,MIN(1.D0,CTHE))) + ITHE=MAX(1,MIN(50,1+INT(50.*THE/PARU(1)))) + FEVEE(ITHE)=FEVEE(ITHE)+FAC*P(I1,4)*P(I2,4) + 590 CONTINUE + 600 CONTINUE + DO 610 J=1,25 + FE1EC(J)=FE1EC(J)+FEVEE(J) + FE2EC(J)=FE2EC(J)+FEVEE(J)**2 + FE1EC(51-J)=FE1EC(51-J)+FEVEE(51-J) + FE2EC(51-J)=FE2EC(51-J)+FEVEE(51-J)**2 + FE1EA(J)=FE1EA(J)+(FEVEE(51-J)-FEVEE(J)) + FE2EA(J)=FE2EA(J)+(FEVEE(51-J)-FEVEE(J))**2 + 610 CONTINUE + MSTU(62)=NUPP-NLOW + +C...Write statistics on Energy-Energy Correlation. + ELSEIF(MTABU.EQ.42) THEN + FAC=1./MAX(1,NEVEE) + WRITE(MSTU(11),5700) NEVEE + DO 620 J=1,25 + FEEC1=FAC*FE1EC(J) + FEES1=SQRT(MAX(0.D0,FAC*(FAC*FE2EC(J)-FEEC1**2))) + FEEC2=FAC*FE1EC(51-J) + FEES2=SQRT(MAX(0.D0,FAC*(FAC*FE2EC(51-J)-FEEC2**2))) + FEECA=FAC*FE1EA(J) + FEESA=SQRT(MAX(0.D0,FAC*(FAC*FE2EA(J)-FEECA**2))) + WRITE(MSTU(11),5800) 3.6*(J-1),3.6*J,FEEC1,FEES1,FEEC2,FEES2, + & FEECA,FEESA + 620 CONTINUE + +C...Copy statistics on Energy-Energy Correlation into /LUJETS/. + ELSEIF(MTABU.EQ.43) THEN + FAC=1./MAX(1,NEVEE) + DO 630 I=1,25 + K(I,1)=32 + K(I,2)=99 + K(I,3)=0 + K(I,4)=0 + K(I,5)=0 + P(I,1)=FAC*FE1EC(I) + V(I,1)=SQRT(MAX(0.D0,FAC*(FAC*FE2EC(I)-P(I,1)**2))) + P(I,2)=FAC*FE1EC(51-I) + V(I,2)=SQRT(MAX(0.D0,FAC*(FAC*FE2EC(51-I)-P(I,2)**2))) + P(I,3)=FAC*FE1EA(I) + V(I,3)=SQRT(MAX(0.D0,FAC*(FAC*FE2EA(I)-P(I,3)**2))) + P(I,4)=PARU(1)*(I-1)/50. + P(I,5)=PARU(1)*I/50. + V(I,4)=3.6*(I-1) + V(I,5)=3.6*I + 630 CONTINUE + N=25 + DO 640 J=1,5 + K(N+1,J)=0 + P(N+1,J)=0. + V(N+1,J)=0. + 640 CONTINUE + K(N+1,1)=32 + K(N+1,2)=99 + K(N+1,5)=NEVEE + MSTU(3)=1 + +C...Reset statistics on decay channels. + ELSEIF(MTABU.EQ.50) THEN + NEVDC=0 + NKFDC=0 + NREDC=0 + +C...Identify and order flavour content of final state. + ELSEIF(MTABU.EQ.51) THEN + NEVDC=NEVDC+1 + NDS=0 + DO 670 I=1,N + IF(K(I,1).LE.0.OR.K(I,1).GE.6) GOTO 670 + NDS=NDS+1 + IF(NDS.GT.8) THEN + NREDC=NREDC+1 + RETURN + ENDIF + KFM=2*IABS(K(I,2)) + IF(K(I,2).LT.0) KFM=KFM-1 + DO 650 IDS=NDS-1,1,-1 + IIN=IDS+1 + IF(KFM.LT.KFDM(IDS)) GOTO 660 + KFDM(IDS+1)=KFDM(IDS) + 650 CONTINUE + IIN=1 + 660 KFDM(IIN)=KFM + 670 CONTINUE + +C...Find whether old or new final state. + DO 690 IDC=1,NKFDC + IF(NDS.LT.KFDC(IDC,0)) THEN + IKFDC=IDC + GOTO 700 + ELSEIF(NDS.EQ.KFDC(IDC,0)) THEN + DO 680 I=1,NDS + IF(KFDM(I).LT.KFDC(IDC,I)) THEN + IKFDC=IDC + GOTO 700 + ELSEIF(KFDM(I).GT.KFDC(IDC,I)) THEN + GOTO 690 + ENDIF + 680 CONTINUE + IKFDC=-IDC + GOTO 700 + ENDIF + 690 CONTINUE + IKFDC=NKFDC+1 + 700 IF(IKFDC.LT.0) THEN + IKFDC=-IKFDC + ELSEIF(NKFDC.GE.200) THEN + NREDC=NREDC+1 + RETURN + ELSE + DO 720 IDC=NKFDC,IKFDC,-1 + NPDC(IDC+1)=NPDC(IDC) + DO 710 I=0,8 + KFDC(IDC+1,I)=KFDC(IDC,I) + 710 CONTINUE + 720 CONTINUE + NKFDC=NKFDC+1 + KFDC(IKFDC,0)=NDS + DO 730 I=1,NDS + KFDC(IKFDC,I)=KFDM(I) + 730 CONTINUE + NPDC(IKFDC)=0 + ENDIF + NPDC(IKFDC)=NPDC(IKFDC)+1 + +C...Write statistics on decay channels. + ELSEIF(MTABU.EQ.52) THEN + FAC=1./MAX(1,NEVDC) + WRITE(MSTU(11),5900) NEVDC + DO 750 IDC=1,NKFDC + DO 740 I=1,KFDC(IDC,0) + KFM=KFDC(IDC,I) + KF=(KFM+1)/2 + IF(2*KF.NE.KFM) KF=-KF + CALL LUNAME(KF,CHAU) + CHDC(I)=CHAU(1:12) + IF(CHAU(13:13).NE.' ') CHDC(I)(12:12)='?' + 740 CONTINUE + WRITE(MSTU(11),6000) FAC*NPDC(IDC),(CHDC(I),I=1,KFDC(IDC,0)) + 750 CONTINUE + IF(NREDC.NE.0) WRITE(MSTU(11),6100) FAC*NREDC + +C...Copy statistics on decay channels into /LUJETS/. + ELSEIF(MTABU.EQ.53) THEN + FAC=1./MAX(1,NEVDC) + DO 780 IDC=1,NKFDC + K(IDC,1)=32 + K(IDC,2)=99 + K(IDC,3)=0 + K(IDC,4)=0 + K(IDC,5)=KFDC(IDC,0) + DO 760 J=1,5 + P(IDC,J)=0. + V(IDC,J)=0. + 760 CONTINUE + DO 770 I=1,KFDC(IDC,0) + KFM=KFDC(IDC,I) + KF=(KFM+1)/2 + IF(2*KF.NE.KFM) KF=-KF + IF(I.LE.5) P(IDC,I)=KF + IF(I.GE.6) V(IDC,I-5)=KF + 770 CONTINUE + V(IDC,5)=FAC*NPDC(IDC) + 780 CONTINUE + N=NKFDC + DO 790 J=1,5 + K(N+1,J)=0 + P(N+1,J)=0. + V(N+1,J)=0. + 790 CONTINUE + K(N+1,1)=32 + K(N+1,2)=99 + K(N+1,5)=NEVDC + V(N+1,5)=FAC*NREDC + MSTU(3)=1 + ENDIF + +C...Format statements for output on unit MSTU(11) (default 6). + 5000 FORMAT(///20X,'Event statistics - initial state'/ + &20X,'based on an analysis of ',I6,' events'// + &3X,'Main flavours after',8X,'Fraction',4X,'Subfractions ', + &'according to fragmenting system multiplicity'/ + &4X,'hard interaction',24X,'1',7X,'2',7X,'3',7X,'4',7X,'5', + &6X,'6-7',5X,'8-10',3X,'11-15',3X,'16-25',4X,'>25'/) + 5100 FORMAT(3X,A12,1X,A12,F10.5,1X,10F8.4) + 5200 FORMAT(///20X,'Event statistics - final state'/ + &20X,'based on an analysis of ',I7,' events'// + &5X,'Mean primary multiplicity =',F10.4/ + &5X,'Mean final multiplicity =',F10.4/ + &5X,'Mean charged multiplicity =',F10.4// + &5X,'Number of particles produced per event (directly and via ', + &'decays/branchings)'/ + &5X,'KF Particle/jet MDCY',10X,'Particles',13X,'Antiparticles', + &8X,'Total'/35X,'prim seco prim seco'/) + 5300 FORMAT(1X,I6,4X,A16,I2,5(1X,F11.6)) + 5400 FORMAT(///20X,'Factorial moments analysis of multiplicity'/ + &20X,'based on an analysis of ',I6,' events'// + &3X,'delta-',A3,' delta-phi /bin',10X,'',18X,'', + &18X,'',18X,''/35X,4(' value error ')) + 5500 FORMAT(10X) + 5600 FORMAT(2X,2F10.4,F12.4,4(F12.4,F10.4)) + 5700 FORMAT(///20X,'Energy-Energy Correlation and Asymmetry'/ + &20X,'based on an analysis of ',I6,' events'// + &2X,'theta range',8X,'EEC(theta)',8X,'EEC(180-theta)',7X, + &'EECA(theta)'/2X,'in degrees ',3(' value error')/) + 5800 FORMAT(2X,F4.1,' - ',F4.1,3(F11.4,F9.4)) + 5900 FORMAT(///20X,'Decay channel analysis - final state'/ + &20X,'based on an analysis of ',I6,' events'// + &2X,'Probability',10X,'Complete final state'/) + 6000 FORMAT(2X,F9.5,5X,8(A12,1X)) + 6100 FORMAT(2X,F9.5,5X,'into other channels (more than 8 particles ', + &'or table overflow)') + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUEEVT + SUBROUTINE LUEEVT(KFL,ECM) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to handle the generation of an e+e- annihilation jet event. +C IMPLICIT DOUBLE PRECISION(D) + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + +C...Check input parameters. + IF(MSTU(12).GE.1) CALL LULIST(0) + IF(KFL.LT.0.OR.KFL.GT.8) THEN + CALL LUERRM(16,'(LUEEVT:) called with unknown flavour code') + IF(MSTU(21).GE.1) RETURN + ENDIF + IF(KFL.LE.5) ECMMIN=PARJ(127)+2.02*PARF(100+MAX(1,KFL)) + IF(KFL.GE.6) ECMMIN=PARJ(127)+2.02*PMAS(KFL,1) + IF(ECM.LT.ECMMIN) THEN + CALL LUERRM(16,'(LUEEVT:) called with too small CM energy') + IF(MSTU(21).GE.1) RETURN + ENDIF + +C...Check consistency of MSTJ options set. + IF(MSTJ(109).EQ.2.AND.MSTJ(110).NE.1) THEN + CALL LUERRM(6, + & '(LUEEVT:) MSTJ(109) value requires MSTJ(110) = 1') + MSTJ(110)=1 + ENDIF + IF(MSTJ(109).EQ.2.AND.MSTJ(111).NE.0) THEN + CALL LUERRM(6, + & '(LUEEVT:) MSTJ(109) value requires MSTJ(111) = 0') + MSTJ(111)=0 + ENDIF + +C...Initialize alpha_strong and total cross-section. + MSTU(111)=MSTJ(108) + IF(MSTJ(108).EQ.2.AND.(MSTJ(101).EQ.0.OR.MSTJ(101).EQ.1)) + &MSTU(111)=1 + PARU(112)=PARJ(121) + IF(MSTU(111).EQ.2) PARU(112)=PARJ(122) + IF(MSTJ(116).GT.0.AND.(MSTJ(116).GE.2.OR.ABS(ECM-PARJ(151)).GE. + &PARJ(139).OR.10*MSTJ(102)+KFL.NE.MSTJ(119))) CALL LUXTOT(KFL,ECM, + &XTOT) + IF(MSTJ(116).GE.3) MSTJ(116)=1 + PARJ(171)=0. + +C...Add initial e+e- to event record (documentation only). + NTRY=0 + 100 NTRY=NTRY+1 + IF(NTRY.GT.100) THEN + CALL LUERRM(14,'(LUEEVT:) caught in an infinite loop') + RETURN + ENDIF + MSTU(24)=0 + NC=0 + IF(MSTJ(115).GE.2) THEN + NC=NC+2 + CALL LU1ENT(NC-1,11,0.5*ECM,0.D0,0.D0) + K(NC-1,1)=21 + CALL LU1ENT(NC,-11,0.5*ECM,PARU(1),0.D0) + K(NC,1)=21 + ENDIF + +C...Radiative photon (in initial state). + MK=0 + ECMC=ECM + IF(MSTJ(107).GE.1.AND.MSTJ(116).GE.1) CALL LURADK(ECM,MK,PAK, + &THEK,PHIK,ALPK) + IF(MK.EQ.1) ECMC=SQRT(ECM*(ECM-2.*PAK)) + IF(MSTJ(115).GE.1.AND.MK.EQ.1) THEN + NC=NC+1 + CALL LU1ENT(NC,22,PAK,THEK,PHIK) + K(NC,3)=MIN(MSTJ(115)/2,1) + ENDIF + +C...Virtual exchange boson (gamma or Z0). + IF(MSTJ(115).GE.3) THEN + NC=NC+1 + KF=22 + IF(MSTJ(102).EQ.2) KF=23 + MSTU10=MSTU(10) + MSTU(10)=1 + P(NC,5)=ECMC + CALL LU1ENT(NC,KF,ECMC,0.D0,0.D0) + K(NC,1)=21 + K(NC,3)=1 + MSTU(10)=MSTU10 + ENDIF + +C...Choice of flavour and jet configuration. + CALL LUXKFL(KFL,ECM,ECMC,KFLC) + IF(KFLC.EQ.0) GOTO 100 + CALL LUXJET(ECMC,NJET,CUT) + KFLN=21 + IF(NJET.EQ.4) CALL LUX4JT(NJET,CUT,KFLC,ECMC,KFLN,X1,X2,X4, + &X12,X14) + IF(NJET.EQ.3) CALL LUX3JT(NJET,CUT,KFLC,ECMC,X1,X3) + IF(NJET.EQ.2) MSTJ(120)=1 + +C...Fill jet configuration and origin. + IF(NJET.EQ.2.AND.MSTJ(101).NE.5) CALL LU2ENT(NC+1,KFLC,-KFLC,ECMC) + IF(NJET.EQ.2.AND.MSTJ(101).EQ.5) CALL LU2ENT(-(NC+1),KFLC,-KFLC, + &ECMC) + IF(NJET.EQ.3) CALL LU3ENT(NC+1,KFLC,21,-KFLC,ECMC,X1,X3) + IF(NJET.EQ.4.AND.KFLN.EQ.21) CALL LU4ENT(NC+1,KFLC,KFLN,KFLN, + &-KFLC,ECMC,X1,X2,X4,X12,X14) + IF(NJET.EQ.4.AND.KFLN.NE.21) CALL LU4ENT(NC+1,KFLC,-KFLN,KFLN, + &-KFLC,ECMC,X1,X2,X4,X12,X14) + IF(MSTU(24).NE.0) GOTO 100 + DO 110 IP=NC+1,N + K(IP,3)=K(IP,3)+MIN(MSTJ(115)/2,1)+(MSTJ(115)/3)*(NC-1) + 110 CONTINUE + +C...Angular orientation according to matrix element. + IF(MSTJ(106).EQ.1) THEN + CALL LUXDIF(NC,NJET,KFLC,ECMC,CHI,THE,PHI) + CALL LUDBRB(NC+1,N,0.D0,CHI,0D0,0D0,0D0) + CALL LUDBRB(NC+1,N,THE,PHI,0D0,0D0,0D0) + ENDIF + +C...Rotation and boost from radiative photon. + IF(MK.EQ.1) THEN + DBEK=-PAK/(ECM-PAK) + NMIN=NC+1-MSTJ(115)/3 + CALL LUDBRB(NMIN,N,0.D0,-PHIK,0D0,0D0,0D0) + CALL LUDBRB(NMIN,N,ALPK,0.D0,DBEK*SIN(THEK),0D0,DBEK*COS(THEK)) + CALL LUDBRB(NMIN,N,0.D0,PHIK,0D0,0D0,0D0) + ENDIF + +C...Generate parton shower. Rearrange along strings and check. + IF(MSTJ(101).EQ.5) THEN + CALL LUSHOW(N-1,N,ECMC) + MSTJ14=MSTJ(14) + IF(MSTJ(105).EQ.-1) MSTJ(14)=-1 + IF(MSTJ(105).GE.0) MSTU(28)=0 + CALL LUPREP(0) + MSTJ(14)=MSTJ14 + IF(MSTJ(105).GE.0.AND.MSTU(28).NE.0) GOTO 100 + ENDIF + +C...Fragmentation/decay generation. Information for LUTABU. + IF(MSTJ(105).EQ.1) CALL LUEXEC + MSTU(161)=KFLC + MSTU(162)=-KFLC + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUXTOT + SUBROUTINE LUXTOT(KFL,ECM,XTOT) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to calculate total cross-section, including initial +C...state radiation effects. + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUDAT1/,/LUDAT2/ + +C...Status, (optimized) Q^2 scale, alpha_strong. + PARJ(151)=ECM + MSTJ(119)=10*MSTJ(102)+KFL + IF(MSTJ(111).EQ.0) THEN + Q2R=ECM**2 + ELSEIF(MSTU(111).EQ.0) THEN + PARJ(168)=MIN(1.D0,MAX(PARJ(128),EXP(-12.*PARU(1)/ + & ((33.-2.*MSTU(112))*PARU(111))))) + Q2R=PARJ(168)*ECM**2 + ELSE + PARJ(168)=MIN(1.D0,MAX(PARJ(128),PARU(112)/ECM, + & (2.*PARU(112)/ECM)**2)) + Q2R=PARJ(168)*ECM**2 + ENDIF + ALSPI=ULALPS(Q2R)/PARU(1) + +C...QCD corrections factor in R. + IF(MSTJ(101).EQ.0.OR.MSTJ(109).EQ.1) THEN + RQCD=1. + ELSEIF(IABS(MSTJ(101)).EQ.1.AND.MSTJ(109).EQ.0) THEN + RQCD=1.+ALSPI + ELSEIF(MSTJ(109).EQ.0) THEN + RQCD=1.+ALSPI+(1.986-0.115*MSTU(118))*ALSPI**2 + IF(MSTJ(111).EQ.1) RQCD=MAX(1.D0,RQCD+(33.-2.*MSTU(112))/12.* + & LOG(PARJ(168))*ALSPI**2) + ELSEIF(IABS(MSTJ(101)).EQ.1) THEN + RQCD=1.+(3./4.)*ALSPI + ELSE + RQCD=1.+(3./4.)*ALSPI-(3./32.+0.519*MSTU(118))*ALSPI**2 + ENDIF + +C...Calculate Z0 width if default value not acceptable. + IF(MSTJ(102).GE.3) THEN + RVA=3.*(3.+(4.*PARU(102)-1.)**2)+6.*RQCD*(2.+(1.-8.*PARU(102)/ + & 3.)**2+(4.*PARU(102)/3.-1.)**2) + DO 100 KFLC=5,6 + VQ=1. + IF(MOD(MSTJ(103),2).EQ.1) VQ=SQRT(MAX(0.D0,1.-(2.*ULMASS(KFLC)/ + & ECM)**2)) + IF(KFLC.EQ.5) VF=4.*PARU(102)/3.-1. + IF(KFLC.EQ.6) VF=1.-8.*PARU(102)/3. + RVA=RVA+3.*RQCD*(0.5*VQ*(3.-VQ**2)*VF**2+VQ**3) + 100 CONTINUE + PARJ(124)=PARU(101)*PARJ(123)*RVA/(48.*PARU(102)*(1.-PARU(102))) + ENDIF + +C...Calculate propagator and related constants for QFD case. + POLL=1.-PARJ(131)*PARJ(132) + IF(MSTJ(102).GE.2) THEN + SFF=1./(16.*PARU(102)*(1.-PARU(102))) + SFW=ECM**4/((ECM**2-PARJ(123)**2)**2+(PARJ(123)*PARJ(124))**2) + SFI=SFW*(1.-(PARJ(123)/ECM)**2) + VE=4.*PARU(102)-1. + SF1I=SFF*(VE*POLL+PARJ(132)-PARJ(131)) + SF1W=SFF**2*((VE**2+1.)*POLL+2.*VE*(PARJ(132)-PARJ(131))) + HF1I=SFI*SF1I + HF1W=SFW*SF1W + ENDIF + +C...Loop over different flavours: charge, velocity. + RTOT=0. + RQQ=0. + RQV=0. + RVA=0. + DO 110 KFLC=1,MAX(MSTJ(104),KFL) + IF(KFL.GT.0.AND.KFLC.NE.KFL) GOTO 110 + MSTJ(93)=1 + PMQ=ULMASS(KFLC) + IF(ECM.LT.2.*PMQ+PARJ(127)) GOTO 110 + QF=KCHG(KFLC,1)/3. + VQ=1. + IF(MOD(MSTJ(103),2).EQ.1) VQ=SQRT(1.-(2.*PMQ/ECM)**2) + +C...Calculate R and sum of charges for QED or QFD case. + RQQ=RQQ+3.*QF**2*POLL + IF(MSTJ(102).LE.1) THEN + RTOT=RTOT+3.*0.5*VQ*(3.-VQ**2)*QF**2*POLL + ELSE + VF=SIGN(1.D0,QF)-4.*QF*PARU(102) + RQV=RQV-6.*QF*VF*SF1I + RVA=RVA+3.*(VF**2+1.)*SF1W + RTOT=RTOT+3.*(0.5*VQ*(3.-VQ**2)*(QF**2*POLL-2.*QF*VF*HF1I+ + & VF**2*HF1W)+VQ**3*HF1W) + ENDIF + 110 CONTINUE + RSUM=RQQ + IF(MSTJ(102).GE.2) RSUM=RQQ+SFI*RQV+SFW*RVA + +C...Calculate cross-section, including QCD corrections. + PARJ(141)=RQQ + PARJ(142)=RTOT + PARJ(143)=RTOT*RQCD + PARJ(144)=PARJ(143) + PARJ(145)=PARJ(141)*86.8/ECM**2 + PARJ(146)=PARJ(142)*86.8/ECM**2 + PARJ(147)=PARJ(143)*86.8/ECM**2 + PARJ(148)=PARJ(147) + PARJ(157)=RSUM*RQCD + PARJ(158)=0. + PARJ(159)=0. + XTOT=PARJ(147) + IF(MSTJ(107).LE.0) RETURN + +C...Virtual cross-section. + XKL=PARJ(135) + XKU=MIN(PARJ(136),1.-(2.*PARJ(127)/ECM)**2) + ALE=2.*LOG(ECM/ULMASS(11))-1. + SIGV=ALE/3.+2.*LOG(ECM**2/(ULMASS(13)*ULMASS(15)))/3.-4./3.+ + &1.526*LOG(ECM**2/0.932) + +C...Soft and hard radiative cross-section in QED case. + IF(MSTJ(102).LE.1) THEN + SIGV=1.5*ALE-0.5+PARU(1)**2/3.+2.*SIGV + SIGS=ALE*(2.*LOG(XKL)-LOG(1.-XKL)-XKL) + SIGH=ALE*(2.*LOG(XKU/XKL)-LOG((1.-XKU)/(1.-XKL))-(XKU-XKL)) + +C...Soft and hard radiative cross-section in QFD case. + ELSE + SZM=1.-(PARJ(123)/ECM)**2 + SZW=PARJ(123)*PARJ(124)/ECM**2 + PARJ(161)=-RQQ/RSUM + PARJ(162)=-(RQQ+RQV+RVA)/RSUM + PARJ(163)=(RQV*(1.-0.5*SZM-SFI)+RVA*(1.5-SZM-SFW))/RSUM + PARJ(164)=(RQV*SZW**2*(1.-2.*SFW)+RVA*(2.*SFI+SZW**2-4.+3.*SZM- + & SZM**2))/(SZW*RSUM) + SIGV=1.5*ALE-0.5+PARU(1)**2/3.+((2.*RQQ+SFI*RQV)/RSUM)*SIGV+ + & (SZW*SFW*RQV/RSUM)*PARU(1)*20./9. + SIGS=ALE*(2.*LOG(XKL)+PARJ(161)*LOG(1.-XKL)+PARJ(162)*XKL+ + & PARJ(163)*LOG(((XKL-SZM)**2+SZW**2)/(SZM**2+SZW**2))+ + & PARJ(164)*(ATAN((XKL-SZM)/SZW)-ATAN(-SZM/SZW))) + SIGH=ALE*(2.*LOG(XKU/XKL)+PARJ(161)*LOG((1.-XKU)/(1.-XKL))+ + & PARJ(162)*(XKU-XKL)+PARJ(163)*LOG(((XKU-SZM)**2+SZW**2)/ + & ((XKL-SZM)**2+SZW**2))+PARJ(164)*(ATAN((XKU-SZM)/SZW)- + & ATAN((XKL-SZM)/SZW))) + ENDIF + +C...Total cross-section and fraction of hard photon events. + PARJ(160)=SIGH/(PARU(1)/PARU(101)+SIGV+SIGS+SIGH) + PARJ(157)=RSUM*(1.+(PARU(101)/PARU(1))*(SIGV+SIGS+SIGH))*RQCD + PARJ(144)=PARJ(157) + PARJ(148)=PARJ(144)*86.8/ECM**2 + XTOT=PARJ(148) + + RETURN + END + +C********************************************************************* + +CDECK ID>, LURADK + SUBROUTINE LURADK(ECM,MK,PAK,THEK,PHIK,ALPK) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to generate initial state photon radiation. + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + SAVE /LUDAT1/ + +C...Function: cumulative hard photon spectrum in QFD case. + FXK(XX)=2.*LOG(XX)+PARJ(161)*LOG(1.-XX)+PARJ(162)*XX+ + &PARJ(163)*LOG((XX-SZM)**2+SZW**2)+PARJ(164)*ATAN((XX-SZM)/SZW) + +C...Determine whether radiative photon or not. + MK=0 + PAK=0. + IF(PARJ(160).LT.RLU(0)) RETURN + MK=1 + +C...Photon energy range. Find photon momentum in QED case. + XKL=PARJ(135) + XKU=MIN(PARJ(136),1.-(2.*PARJ(127)/ECM)**2) + IF(MSTJ(102).LE.1) THEN + 100 XK=1./(1.+(1./XKL-1.)*((1./XKU-1.)/(1./XKL-1.))**RLU(0)) + IF(1.+(1.-XK)**2.LT.2.*RLU(0)) GOTO 100 + +C...Ditto in QFD case, by numerical inversion of integrated spectrum. + ELSE + SZM=1.-(PARJ(123)/ECM)**2 + SZW=PARJ(123)*PARJ(124)/ECM**2 + FXKL=FXK(XKL) + FXKU=FXK(XKU) + FXKD=1D-4*(FXKU-FXKL) + FXKR=FXKL+RLU(0)*(FXKU-FXKL) + NXK=0 + 110 NXK=NXK+1 + XK=0.5*(XKL+XKU) + FXKV=FXK(XK) + IF(FXKV.GT.FXKR) THEN + XKU=XK + FXKU=FXKV + ELSE + XKL=XK + FXKL=FXKV + ENDIF + IF(NXK.LT.15.AND.FXKU-FXKL.GT.FXKD) GOTO 110 + XK=XKL+(XKU-XKL)*(FXKR-FXKL)/(FXKU-FXKL) + ENDIF + PAK=0.5*ECM*XK + +C...Photon polar and azimuthal angle. + PME=2.*(ULMASS(11)/ECM)**2 + 120 CTHM=PME*(2./PME)**RLU(0) + IF(1.-(XK**2*CTHM*(1.-0.5*CTHM)+2.*(1.-XK)*PME/MAX(PME, + &CTHM*(1.-0.5*CTHM)))/(1.+(1.-XK)**2).LT.RLU(0)) GOTO 120 + CTHE=1.-CTHM + IF(RLU(0).GT.0.5) CTHE=-CTHE + STHE=SQRT(MAX(0.D0,(CTHM-PME)*(2.-CTHM))) + THEK=ULANGL(CTHE,STHE) + PHIK=PARU(2)*RLU(0) + +C...Rotation angle for hadronic system. + SGN=1. + IF(0.5*(2.-XK*(1.-CTHE))**2/((2.-XK)**2+(XK*CTHE)**2).GT. + &RLU(0)) SGN=-1. + ALPK=ASIN(SGN*STHE*(XK-SGN*(2.*SQRT(1.-XK)-2.+XK)*CTHE)/ + &(2.-XK*(1.-SGN*CTHE))) + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUXKFL + SUBROUTINE LUXKFL(KFL,ECM,ECMC,KFLC) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to select flavour for produced qqbar pair. + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUDAT1/,/LUDAT2/ + +C...Calculate maximum weight in QED or QFD case. + IF(MSTJ(102).LE.1) THEN + RFMAX=4./9. + ELSE + POLL=1.-PARJ(131)*PARJ(132) + SFF=1./(16.*PARU(102)*(1.-PARU(102))) + SFW=ECMC**4/((ECMC**2-PARJ(123)**2)**2+(PARJ(123)*PARJ(124))**2) + SFI=SFW*(1.-(PARJ(123)/ECMC)**2) + VE=4.*PARU(102)-1. + HF1I=SFI*SFF*(VE*POLL+PARJ(132)-PARJ(131)) + HF1W=SFW*SFF**2*((VE**2+1.)*POLL+2.*VE*(PARJ(132)-PARJ(131))) + RFMAX=MAX(4./9.*POLL-4./3.*(1.-8.*PARU(102)/3.)*HF1I+ + & ((1.-8.*PARU(102)/3.)**2+1.)*HF1W,1./9.*POLL+2./3.* + & (-1.+4.*PARU(102)/3.)*HF1I+((-1.+4.*PARU(102)/3.)**2+1.)*HF1W) + ENDIF + +C...Choose flavour. Gives charge and velocity. + NTRY=0 + 100 NTRY=NTRY+1 + IF(NTRY.GT.100) THEN + CALL LUERRM(14,'(LUXKFL:) caught in an infinite loop') + KFLC=0 + RETURN + ENDIF + KFLC=KFL + IF(KFL.LE.0) KFLC=1+INT(MSTJ(104)*RLU(0)) + MSTJ(93)=1 + PMQ=ULMASS(KFLC) + IF(ECM.LT.2.*PMQ+PARJ(127)) GOTO 100 + QF=KCHG(KFLC,1)/3. + VQ=1. + IF(MOD(MSTJ(103),2).EQ.1) VQ=SQRT(MAX(0.D0,1.-(2.*PMQ/ECMC)**2)) + +C...Calculate weight in QED or QFD case. + IF(MSTJ(102).LE.1) THEN + RF=QF**2 + RFV=0.5*VQ*(3.-VQ**2)*QF**2 + ELSE + VF=SIGN(1.D0,QF)-4.*QF*PARU(102) + RF=QF**2*POLL-2.*QF*VF*HF1I+(VF**2+1.)*HF1W + RFV=0.5*VQ*(3.-VQ**2)*(QF**2*POLL-2.*QF*VF*HF1I+VF**2*HF1W)+ + & VQ**3*HF1W + IF(RFV.GT.0.) PARJ(171)=MIN(1.D0,VQ**3*HF1W/RFV) + ENDIF + +C...Weighting or new event (radiative photon). Cross-section update. + IF(KFL.LE.0.AND.RF.LT.RLU(0)*RFMAX) GOTO 100 + PARJ(158)=PARJ(158)+1. + IF(ECMC.LT.2.*PMQ+PARJ(127).OR.RFV.LT.RLU(0)*RF) KFLC=0 + IF(MSTJ(107).LE.0.AND.KFLC.EQ.0) GOTO 100 + IF(KFLC.NE.0) PARJ(159)=PARJ(159)+1. + PARJ(144)=PARJ(157)*PARJ(159)/PARJ(158) + PARJ(148)=PARJ(144)*86.8/ECM**2 + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUXJET + SUBROUTINE LUXJET(ECM,NJET,CUT) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to select number of jets in matrix element approach. + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + SAVE /LUDAT1/ + DIMENSION ZHUT(5) + +C...Relative three-jet rate in Zhu second order parametrization. + DATA ZHUT/3.0922, 6.2291, 7.4782, 7.8440, 8.2560/ + +C...Trivial result for two-jets only, including parton shower. + IF(MSTJ(101).EQ.0.OR.MSTJ(101).EQ.5) THEN + CUT=0. + +C...QCD and Abelian vector gluon theory: Q^2 for jet rate and R. + ELSEIF(MSTJ(109).EQ.0.OR.MSTJ(109).EQ.2) THEN + CF=4./3. + IF(MSTJ(109).EQ.2) CF=1. + IF(MSTJ(111).EQ.0) THEN + Q2=ECM**2 + Q2R=ECM**2 + ELSEIF(MSTU(111).EQ.0) THEN + PARJ(169)=MIN(1.D0,PARJ(129)) + Q2=PARJ(169)*ECM**2 + PARJ(168)=MIN(1.D0,MAX(PARJ(128),EXP(-12.*PARU(1)/ + & ((33.-2.*MSTU(112))*PARU(111))))) + Q2R=PARJ(168)*ECM**2 + ELSE + PARJ(169)=MIN(1.D0,MAX(PARJ(129),(2.*PARU(112)/ECM)**2)) + Q2=PARJ(169)*ECM**2 + PARJ(168)=MIN(1.D0,MAX(PARJ(128),PARU(112)/ECM, + & (2.*PARU(112)/ECM)**2)) + Q2R=PARJ(168)*ECM**2 + ENDIF + +C...alpha_strong for R and R itself. + ALSPI=(3./4.)*CF*ULALPS(Q2R)/PARU(1) + IF(IABS(MSTJ(101)).EQ.1) THEN + RQCD=1.+ALSPI + ELSEIF(MSTJ(109).EQ.0) THEN + RQCD=1.+ALSPI+(1.986-0.115*MSTU(118))*ALSPI**2 + IF(MSTJ(111).EQ.1) RQCD=MAX(1.D0,RQCD+(33.-2.*MSTU(112))/12.* + & LOG(PARJ(168))*ALSPI**2) + ELSE + RQCD=1.+ALSPI-(3./32.+0.519*MSTU(118))*(4.*ALSPI/3.)**2 + ENDIF + +C...alpha_strong for jet rate. Initial value for y cut. + ALSPI=(3./4.)*CF*ULALPS(Q2)/PARU(1) + CUT=MAX(0.001D0,PARJ(125),(PARJ(126)/ECM)**2) + IF(IABS(MSTJ(101)).LE.1.OR.(MSTJ(109).EQ.0.AND.MSTJ(111).EQ.0)) + & CUT=MAX(CUT,EXP(-SQRT(0.75/ALSPI))/2.) + IF(MSTJ(110).EQ.2) CUT=MAX(0.01D0,MIN(0.05D0,CUT)) + +C...Parametrization of first order three-jet cross-section. + 100 IF(MSTJ(101).EQ.0.OR.CUT.GE.0.25) THEN + PARJ(152)=0. + ELSE + PARJ(152)=(2.*ALSPI/3.)*((3.-6.*CUT+2.*LOG(CUT))* + & LOG(CUT/(1.-2.*CUT))+(2.5+1.5*CUT-6.571)*(1.-3.*CUT)+ + & 5.833*(1.-3.*CUT)**2-3.894*(1.-3.*CUT)**3+ + & 1.342*(1.-3.*CUT)**4)/RQCD + IF(MSTJ(109).EQ.2.AND.(MSTJ(101).EQ.2.OR.MSTJ(101).LE.-2)) + & PARJ(152)=0. + ENDIF + +C...Parametrization of second order three-jet cross-section. + IF(IABS(MSTJ(101)).LE.1.OR.MSTJ(101).EQ.3.OR.MSTJ(109).EQ.2.OR. + & CUT.GE.0.25) THEN + PARJ(153)=0. + ELSEIF(MSTJ(110).LE.1) THEN + CT=LOG(1./CUT-2.) + PARJ(153)=ALSPI**2*CT**2*(2.419+0.5989*CT+0.6782*CT**2- + & 0.2661*CT**3+0.01159*CT**4)/RQCD + +C...Interpolation in second/first order ratio for Zhu parametrization. + ELSEIF(MSTJ(110).EQ.2) THEN + IZA=0 + DO 110 IY=1,5 + IF(ABS(CUT-0.01*IY).LT.0.0001) IZA=IY + 110 CONTINUE + IF(IZA.NE.0) THEN + ZHURAT=ZHUT(IZA) + ELSE + IZ=100.*CUT + ZHURAT=ZHUT(IZ)+(100.*CUT-IZ)*(ZHUT(IZ+1)-ZHUT(IZ)) + ENDIF + PARJ(153)=ALSPI*PARJ(152)*ZHURAT + ENDIF + +C...Shift in second order three-jet cross-section with optimized Q^2. + IF(MSTJ(111).EQ.1.AND.IABS(MSTJ(101)).GE.2.AND.MSTJ(101).NE.3. + & AND.CUT.LT.0.25) PARJ(153)=PARJ(153)+(33.-2.*MSTU(112))/12.* + & LOG(PARJ(169))*ALSPI*PARJ(152) + +C...Parametrization of second order four-jet cross-section. + IF(IABS(MSTJ(101)).LE.1.OR.CUT.GE.0.125) THEN + PARJ(154)=0. + ELSE + CT=LOG(1./CUT-5.) + IF(CUT.LE.0.018) THEN + XQQGG=6.349-4.330*CT+0.8304*CT**2 + IF(MSTJ(109).EQ.2) XQQGG=(4./3.)**2*(3.035-2.091*CT+ + & 0.4059*CT**2) + XQQQQ=1.25*(-0.1080+0.01486*CT+0.009364*CT**2) + IF(MSTJ(109).EQ.2) XQQQQ=8.*XQQQQ + ELSE + XQQGG=-0.09773+0.2959*CT-0.2764*CT**2+0.08832*CT**3 + IF(MSTJ(109).EQ.2) XQQGG=(4./3.)**2*(-0.04079+0.1340*CT- + & 0.1326*CT**2+0.04365*CT**3) + XQQQQ=1.25*(0.003661-0.004888*CT-0.001081*CT**2+0.002093* + & CT**3) + IF(MSTJ(109).EQ.2) XQQQQ=8.*XQQQQ + ENDIF + PARJ(154)=ALSPI**2*CT**2*(XQQGG+XQQQQ)/RQCD + PARJ(155)=XQQQQ/(XQQGG+XQQQQ) + ENDIF + +C...If negative three-jet rate, change y' optimization parameter. + IF(MSTJ(111).EQ.1.AND.PARJ(152)+PARJ(153).LT.0..AND. + & PARJ(169).LT.0.99) THEN + PARJ(169)=MIN(1.D0,1.2*PARJ(169)) + Q2=PARJ(169)*ECM**2 + ALSPI=(3./4.)*CF*ULALPS(Q2)/PARU(1) + GOTO 100 + ENDIF + +C...If too high cross-section, use harder cuts, or fail. + IF(PARJ(152)+PARJ(153)+PARJ(154).GE.1) THEN + IF(MSTJ(110).EQ.2.AND.CUT.GT.0.0499.AND.MSTJ(111).EQ.1.AND. + & PARJ(169).LT.0.99) THEN + PARJ(169)=MIN(1.D0,1.2*PARJ(169)) + Q2=PARJ(169)*ECM**2 + ALSPI=(3./4.)*CF*ULALPS(Q2)/PARU(1) + GOTO 100 + ELSEIF(MSTJ(110).EQ.2.AND.CUT.GT.0.0499) THEN + CALL LUERRM(26, + & '(LUXJET:) no allowed y cut value for Zhu parametrization') + ENDIF + CUT=0.26*(4.*CUT)**(PARJ(152)+PARJ(153)+PARJ(154))**(-1./3.) + IF(MSTJ(110).EQ.2) CUT=MAX(0.01D0,MIN(0.05D0,CUT)) + GOTO 100 + ENDIF + +C...Scalar gluon (first order only). + ELSE + ALSPI=ULALPS(ECM**2)/PARU(1) + CUT=MAX(0.001D0,PARJ(125),(PARJ(126)/ECM)**2,EXP(-3./ALSPI)) + PARJ(152)=0. + IF(CUT.LT.0.25) PARJ(152)=(ALSPI/3.)*((1.-2.*CUT)* + & LOG((1.-2.*CUT)/CUT)+0.5*(9.*CUT**2-1.)) + PARJ(153)=0. + PARJ(154)=0. + ENDIF + +C...Select number of jets. + PARJ(150)=CUT + IF(MSTJ(101).EQ.0.OR.MSTJ(101).EQ.5) THEN + NJET=2 + ELSEIF(MSTJ(101).LE.0) THEN + NJET=MIN(4,2-MSTJ(101)) + ELSE + RNJ=RLU(0) + NJET=2 + IF(PARJ(152)+PARJ(153)+PARJ(154).GT.RNJ) NJET=3 + IF(PARJ(154).GT.RNJ) NJET=4 + ENDIF + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUX3JT + SUBROUTINE LUX3JT(NJET,CUT,KFL,ECM,X1,X2) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to select the kinematical variables of three-jet events. + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + SAVE /LUDAT1/ + DIMENSION ZHUP(5,12) + +C...Coefficients of Zhu second order parametrization. + DATA ((ZHUP(IC1,IC2),IC2=1,12),IC1=1,5)/ + & 18.29, 89.56, 4.541, -52.09, -109.8, 24.90, + & 11.63, 3.683, 17.50, 0.002440, -1.362, -0.3537, + & 11.42, 6.299, -22.55, -8.915, 59.25, -5.855, + & -32.85, -1.054, -16.90, 0.006489, -0.8156, 0.01095, + & 7.847, -3.964, -35.83, 1.178, 29.39, 0.2806, + & 47.82, -12.36, -56.72, 0.04054, -0.4365, 0.6062, + & 5.441, -56.89, -50.27, 15.13, 114.3, -18.19, + & 97.05, -1.890, -139.9, 0.08153, -0.4984, 0.9439, + & -17.65, 51.44, -58.32, 70.95, -255.7, -78.99, + & 476.9, 29.65, -239.3, 0.4745, -1.174, 6.081/ + +C...Dilogarithm of x for x<0.5 (x>0.5 obtained by analytic trick). + DILOG(X)=X+X**2/4.+X**3/9.+X**4/16.+X**5/25.+X**6/36.+X**7/49. + +C...Event type. Mass effect factors and other common constants. + MSTJ(120)=2 + MSTJ(121)=0 + PMQ=ULMASS(KFL) + QME=(2.*PMQ/ECM)**2 + IF(MSTJ(109).NE.1) THEN + CUTL=LOG(CUT) + CUTD=LOG(1./CUT-2.) + IF(MSTJ(109).EQ.0) THEN + CF=4./3. + CN=3. + TR=2. + WTMX=MIN(20.D0,37.-6.*CUTD) + IF(MSTJ(110).EQ.2) WTMX=2.*(7.5+80.*CUT) + ELSE + CF=1. + CN=0. + TR=12. + WTMX=0. + ENDIF + +C...Alpha_strong and effects of optimized Q^2 scale. Maximum weight. + ALS2PI=PARU(118)/PARU(2) + WTOPT=0. + IF(MSTJ(111).EQ.1) WTOPT=(33.-2.*MSTU(112))/6.*LOG(PARJ(169))* + & ALS2PI + WTMAX=MAX(0.D0,1.+WTOPT+ALS2PI*WTMX) + +C...Choose three-jet events in allowed region. + 100 NJET=3 + 110 Y13L=CUTL+CUTD*RLU(0) + Y23L=CUTL+CUTD*RLU(0) + Y13=EXP(Y13L) + Y23=EXP(Y23L) + Y12=1.-Y13-Y23 + IF(Y12.LE.CUT) GOTO 110 + IF(Y13**2+Y23**2+2.*Y12.LE.2.*RLU(0)) GOTO 110 + +C...Second order corrections. + IF(MSTJ(101).EQ.2.AND.MSTJ(110).LE.1) THEN + Y12L=LOG(Y12) + Y13M=LOG(1.-Y13) + Y23M=LOG(1.-Y23) + Y12M=LOG(1.-Y12) + IF(Y13.LE.0.5) Y13I=DILOG(Y13) + IF(Y13.GE.0.5) Y13I=1.644934-Y13L*Y13M-DILOG(1.-Y13) + IF(Y23.LE.0.5) Y23I=DILOG(Y23) + IF(Y23.GE.0.5) Y23I=1.644934-Y23L*Y23M-DILOG(1.-Y23) + IF(Y12.LE.0.5) Y12I=DILOG(Y12) + IF(Y12.GE.0.5) Y12I=1.644934-Y12L*Y12M-DILOG(1.-Y12) + WT1=(Y13**2+Y23**2+2.*Y12)/(Y13*Y23) + WT2=CF*(-2.*(CUTL-Y12L)**2-3.*CUTL-1.+3.289868+ + & 2.*(2.*CUTL-Y12L)*CUT/Y12)+ + & CN*((CUTL-Y12L)**2-(CUTL-Y13L)**2-(CUTL-Y23L)**2-11.*CUTL/6.+ + & 67./18.+1.644934-(2.*CUTL-Y12L)*CUT/Y12+(2.*CUTL-Y13L)* + & CUT/Y13+(2.*CUTL-Y23L)*CUT/Y23)+ + & TR*(2.*CUTL/3.-10./9.)+ + & CF*(Y12/(Y12+Y13)+Y12/(Y12+Y23)+(Y12+Y23)/Y13+(Y12+Y13)/Y23+ + & Y13L*(4.*Y12**2+2.*Y12*Y13+4.*Y12*Y23+Y13*Y23)/(Y12+Y23)**2+ + & Y23L*(4.*Y12**2+2.*Y12*Y23+4.*Y12*Y13+Y13*Y23)/(Y12+Y13)**2)/ + & WT1+ + & CN*(Y13L*Y13/(Y12+Y23)+Y23L*Y23/(Y12+Y13))/WT1+ + & (CN-2.*CF)*((Y12**2+(Y12+Y13)**2)*(Y12L*Y23L-Y12L*Y12M-Y23L* + & Y23M+1.644934-Y12I-Y23I)/(Y13*Y23)+(Y12**2+(Y12+Y23)**2)* + & (Y12L*Y13L-Y12L*Y12M-Y13L*Y13M+1.644934-Y12I-Y13I)/ + & (Y13*Y23)+(Y13**2+Y23**2)/(Y13*Y23*(Y13+Y23))- + & 2.*Y12L*Y12**2/(Y13+Y23)**2-4.*Y12L*Y12/(Y13+Y23))/WT1- + & CN*(Y13L*Y23L-Y13L*Y13M-Y23L*Y23M+1.644934-Y13I-Y23I) + IF(1.+WTOPT+ALS2PI*WT2.LE.0.) MSTJ(121)=1 + IF(1.+WTOPT+ALS2PI*WT2.LE.WTMAX*RLU(0)) GOTO 110 + PARJ(156)=(WTOPT+ALS2PI*WT2)/(1.+WTOPT+ALS2PI*WT2) + + ELSEIF(MSTJ(101).EQ.2.AND.MSTJ(110).EQ.2) THEN +C...Second order corrections; Zhu parametrization of ERT. + ZX=(Y23-Y13)**2 + ZY=1.-Y12 + IZA=0 + DO 120 IY=1,5 + IF(ABS(CUT-0.01*IY).LT.0.0001) IZA=IY + 120 CONTINUE + IF(IZA.NE.0) THEN + IZ=IZA + WT2=ZHUP(IZ,1)+ZHUP(IZ,2)*ZX+ZHUP(IZ,3)*ZX**2+(ZHUP(IZ,4)+ + & ZHUP(IZ,5)*ZX)*ZY+(ZHUP(IZ,6)+ZHUP(IZ,7)*ZX)*ZY**2+ + & (ZHUP(IZ,8)+ZHUP(IZ,9)*ZX)*ZY**3+ZHUP(IZ,10)/(ZX-ZY**2)+ + & ZHUP(IZ,11)/(1.-ZY)+ZHUP(IZ,12)/ZY + ELSE + IZ=100.*CUT + WTL=ZHUP(IZ,1)+ZHUP(IZ,2)*ZX+ZHUP(IZ,3)*ZX**2+(ZHUP(IZ,4)+ + & ZHUP(IZ,5)*ZX)*ZY+(ZHUP(IZ,6)+ZHUP(IZ,7)*ZX)*ZY**2+ + & (ZHUP(IZ,8)+ZHUP(IZ,9)*ZX)*ZY**3+ZHUP(IZ,10)/(ZX-ZY**2)+ + & ZHUP(IZ,11)/(1.-ZY)+ZHUP(IZ,12)/ZY + IZ=IZ+1 + WTU=ZHUP(IZ,1)+ZHUP(IZ,2)*ZX+ZHUP(IZ,3)*ZX**2+(ZHUP(IZ,4)+ + & ZHUP(IZ,5)*ZX)*ZY+(ZHUP(IZ,6)+ZHUP(IZ,7)*ZX)*ZY**2+ + & (ZHUP(IZ,8)+ZHUP(IZ,9)*ZX)*ZY**3+ZHUP(IZ,10)/(ZX-ZY**2)+ + & ZHUP(IZ,11)/(1.-ZY)+ZHUP(IZ,12)/ZY + WT2=WTL+(WTU-WTL)*(100.*CUT+1.-IZ) + ENDIF + IF(1.+WTOPT+2.*ALS2PI*WT2.LE.0.) MSTJ(121)=1 + IF(1.+WTOPT+2.*ALS2PI*WT2.LE.WTMAX*RLU(0)) GOTO 110 + PARJ(156)=(WTOPT+2.*ALS2PI*WT2)/(1.+WTOPT+2.*ALS2PI*WT2) + ENDIF + +C...Impose mass cuts (gives two jets). For fixed jet number new try. + X1=1.-Y23 + X2=1.-Y13 + X3=1.-Y12 + IF(4.*Y23*Y13*Y12/X3**2.LE.QME) NJET=2 + IF(MOD(MSTJ(103),4).GE.2.AND.IABS(MSTJ(101)).LE.1.AND.QME*X3+ + & 0.5*QME**2+(0.5*QME+0.25*QME**2)*((1.-X2)/(1.-X1)+ + & (1.-X1)/(1.-X2)).GT.(X1**2+X2**2)*RLU(0)) NJET=2 + IF(MSTJ(101).EQ.-1.AND.NJET.EQ.2) GOTO 100 + +C...Scalar gluon model (first order only, no mass effects). + ELSE + 130 NJET=3 + 140 X3=SQRT(4.*CUT**2+RLU(0)*((1.-CUT)**2-4.*CUT**2)) + IF(LOG((X3-CUT)/CUT).LE.RLU(0)*LOG((1.-2.*CUT)/CUT)) GOTO 140 + YD=SIGN(2.*CUT*((X3-CUT)/CUT)**RLU(0)-X3,RLU(0)-0.5) + X1=1.-0.5*(X3+YD) + X2=1.-0.5*(X3-YD) + IF(4.*(1.-X1)*(1.-X2)*(1.-X3)/X3**2.LE.QME) NJET=2 + IF(MSTJ(102).GE.2) THEN + IF(X3**2-2.*(1.+X3)*(1.-X1)*(1.-X2)*PARJ(171).LT. + & X3**2*RLU(0)) NJET=2 + ENDIF + IF(MSTJ(101).EQ.-1.AND.NJET.EQ.2) GOTO 130 + ENDIF + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUX4JT + SUBROUTINE LUX4JT(NJET,CUT,KFL,ECM,KFLN,X1,X2,X4,X12,X14) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to select the kinematical variables of four-jet events. + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + SAVE /LUDAT1/ + DIMENSION WTA(4),WTB(4),WTC(4),WTD(4),WTE(4) + +C...Common constants. Colour factors for QCD and Abelian gluon theory. + PMQ=ULMASS(KFL) + QME=(2.*PMQ/ECM)**2 + CT=LOG(1./CUT-5.) + IF(MSTJ(109).EQ.0) THEN + CF=4./3. + CN=3. + TR=2.5 + ELSE + CF=1. + CN=0. + TR=15. + ENDIF + +C...Choice of process (qqbargg or qqbarqqbar). + 100 NJET=4 + IT=1 + IF(PARJ(155).GT.RLU(0)) IT=2 + IF(MSTJ(101).LE.-3) IT=-MSTJ(101)-2 + IF(IT.EQ.1) WTMX=0.7/CUT**2 + IF(IT.EQ.1.AND.MSTJ(109).EQ.2) WTMX=0.6/CUT**2 + IF(IT.EQ.2) WTMX=0.1125*CF*TR/CUT**2 + ID=1 + +C...Sample the five kinematical variables (for qqgg preweighted in y34). + 110 Y134=3.*CUT+(1.-6.*CUT)*RLU(0) + Y234=3.*CUT+(1.-6.*CUT)*RLU(0) + IF(IT.EQ.1) Y34=(1.-5.*CUT)*EXP(-CT*RLU(0)) + IF(IT.EQ.2) Y34=CUT+(1.-6.*CUT)*RLU(0) + IF(Y34.LE.Y134+Y234-1..OR.Y34.GE.Y134*Y234) GOTO 110 + VT=RLU(0) + CP=COS(PARU(1)*RLU(0)) + Y14=(Y134-Y34)*VT + Y13=Y134-Y14-Y34 + VB=Y34*(1.-Y134-Y234+Y34)/((Y134-Y34)*(Y234-Y34)) + Y24=0.5*(Y234-Y34)*(1.-4.*SQRT(MAX(0.D0,VT*(1.-VT)*VB*(1.-VB)))* + &CP-(1.-2.*VT)*(1.-2.*VB)) + Y23=Y234-Y34-Y24 + Y12=1.-Y134-Y23-Y24 + IF(MIN(Y12,Y13,Y14,Y23,Y24).LE.CUT) GOTO 110 + Y123=Y12+Y13+Y23 + Y124=Y12+Y14+Y24 + +C...Calculate matrix elements for qqgg or qqqq process. + IC=0 + WTTOT=0. + 120 IC=IC+1 + IF(IT.EQ.1) THEN + WTA(IC)=(Y12*Y34**2-Y13*Y24*Y34+Y14*Y23*Y34+3.*Y12*Y23*Y34+ + & 3.*Y12*Y14*Y34+4.*Y12**2*Y34-Y13*Y23*Y24+2.*Y12*Y23*Y24- + & Y13*Y14*Y24-2.*Y12*Y13*Y24+2.*Y12**2*Y24+Y14*Y23**2+2.*Y12* + & Y23**2+Y14**2*Y23+4.*Y12*Y14*Y23+4.*Y12**2*Y23+2.*Y12*Y14**2+ + & 2.*Y12*Y13*Y14+4.*Y12**2*Y14+2.*Y12**2*Y13+2.*Y12**3)/(2.*Y13* + & Y134*Y234*Y24)+(Y24*Y34+Y12*Y34+Y13*Y24-Y14*Y23+Y12*Y13)/(Y13* + & Y134**2)+2.*Y23*(1.-Y13)/(Y13*Y134*Y24)+Y34/(2.*Y13*Y24) + WTB(IC)=(Y12*Y24*Y34+Y12*Y14*Y34-Y13*Y24**2+Y13*Y14*Y24+2.*Y12* + & Y14*Y24)/(Y13*Y134*Y23*Y14)+Y12*(1.+Y34)*Y124/(Y134*Y234*Y14* + & Y24)-(2.*Y13*Y24+Y14**2+Y13*Y23+2.*Y12*Y13)/(Y13*Y134*Y14)+ + & Y12*Y123*Y124/(2.*Y13*Y14*Y23*Y24) + WTC(IC)=-(5.*Y12*Y34**2+2.*Y12*Y24*Y34+2.*Y12*Y23*Y34+2.*Y12* + & Y14*Y34+2.*Y12*Y13*Y34+4.*Y12**2*Y34-Y13*Y24**2+Y14*Y23*Y24+ + & Y13*Y23*Y24+Y13*Y14*Y24-Y12*Y14*Y24-Y13**2*Y24-3.*Y12*Y13*Y24- + & Y14*Y23**2-Y14**2*Y23+Y13*Y14*Y23-3.*Y12*Y14*Y23-Y12*Y13*Y23)/ + & (4.*Y134*Y234*Y34**2)+(3.*Y12*Y34**2-3.*Y13*Y24*Y34+3.*Y12*Y24* + & Y34+3.*Y14*Y23*Y34-Y13*Y24**2-Y12*Y23*Y34+6.*Y12*Y14*Y34+2.*Y12* + & Y13*Y34-2.*Y12**2*Y34+Y14*Y23*Y24-3.*Y13*Y23*Y24-2.*Y13*Y14* + & Y24+4.*Y12*Y14*Y24+2.*Y12*Y13*Y24+3.*Y14*Y23**2+2.*Y14**2*Y23+ + & 2.*Y14**2*Y12+2.*Y12**2*Y14+6.*Y12*Y14*Y23-2.*Y12*Y13**2- + & 2.*Y12**2*Y13)/(4.*Y13*Y134*Y234*Y34) + WTC(IC)=WTC(IC)+(2.*Y12*Y34**2-2.*Y13*Y24*Y34+Y12*Y24*Y34+ + & 4.*Y13*Y23*Y34+4.*Y12*Y14*Y34+2.*Y12*Y13*Y34+2.*Y12**2*Y34- + & Y13*Y24**2+3.*Y14*Y23*Y24+4.*Y13*Y23*Y24-2.*Y13*Y14*Y24+ + & 4.*Y12*Y14*Y24+2.*Y12*Y13*Y24+2.*Y14*Y23**2+4.*Y13*Y23**2+ + & 2.*Y13*Y14*Y23+2.*Y12*Y14*Y23+4.*Y12*Y13*Y23+2.*Y12*Y14**2+4.* + & Y12**2*Y13+4.*Y12*Y13*Y14+2.*Y12**2*Y14)/(4.*Y13*Y134*Y24*Y34)- + & (Y12*Y34**2-2.*Y14*Y24*Y34-2.*Y13*Y24*Y34-Y14*Y23*Y34+Y13*Y23* + & Y34+Y12*Y14*Y34+2.*Y12*Y13*Y34-2.*Y14**2*Y24-4.*Y13*Y14*Y24- + & 4.*Y13**2*Y24-Y14**2*Y23-Y13**2*Y23+Y12*Y13*Y14-Y12*Y13**2)/ + & (2.*Y13*Y34*Y134**2)+(Y12*Y34**2-4.*Y14*Y24*Y34-2.*Y13*Y24*Y34- + & 2.*Y14*Y23*Y34-4.*Y13*Y23*Y34-4.*Y12*Y14*Y34-4.*Y12*Y13*Y34- + & 2.*Y13*Y14*Y24+2.*Y13**2*Y24+2.*Y14**2*Y23-2.*Y13*Y14*Y23- + & Y12*Y14**2-6.*Y12*Y13*Y14-Y12*Y13**2)/(4.*Y34**2*Y134**2) + WTTOT=WTTOT+Y34*CF*(CF*WTA(IC)+(CF-0.5*CN)*WTB(IC)+CN*WTC(IC))/ + & 8. + ELSE + WTD(IC)=(Y13*Y23*Y34+Y12*Y23*Y34-Y12**2*Y34+Y13*Y23*Y24+2.*Y12* + & Y23*Y24-Y14*Y23**2+Y12*Y13*Y24+Y12*Y14*Y23+Y12*Y13*Y14)/(Y13**2* + & Y123**2)-(Y12*Y34**2-Y13*Y24*Y34+Y12*Y24*Y34-Y14*Y23*Y34-Y12* + & Y23*Y34-Y13*Y24**2+Y14*Y23*Y24-Y13*Y23*Y24-Y13**2*Y24+Y14* + & Y23**2)/(Y13**2*Y123*Y134)+(Y13*Y14*Y12+Y34*Y14*Y12-Y34**2*Y12+ + & Y13*Y14*Y24+2.*Y34*Y14*Y24-Y23*Y14**2+Y34*Y13*Y24+Y34*Y23*Y14+ + & Y34*Y13*Y23)/(Y13**2*Y134**2)-(Y34*Y12**2-Y13*Y24*Y12+Y34*Y24* + & Y12-Y23*Y14*Y12-Y34*Y14*Y12-Y13*Y24**2+Y23*Y14*Y24-Y13*Y14*Y24- + & Y13**2*Y24+Y23*Y14**2)/(Y13**2*Y134*Y123) + WTE(IC)=(Y12*Y34*(Y23-Y24+Y14+Y13)+Y13*Y24**2-Y14*Y23*Y24+Y13* + & Y23*Y24+Y13*Y14*Y24+Y13**2*Y24-Y14*Y23*(Y14+Y23+Y13))/(Y13*Y23* + & Y123*Y134)-Y12*(Y12*Y34-Y23*Y24-Y13*Y24-Y14*Y23-Y14*Y13)/(Y13* + & Y23*Y123**2)-(Y14+Y13)*(Y24+Y23)*Y34/(Y13*Y23*Y134*Y234)+ + & (Y12*Y34*(Y14-Y24+Y23+Y13)+Y13*Y24**2-Y23*Y14*Y24+Y13*Y14*Y24+ + & Y13*Y23*Y24+Y13**2*Y24-Y23*Y14*(Y14+Y23+Y13))/(Y13*Y14*Y134* + & Y123)-Y34*(Y34*Y12-Y14*Y24-Y13*Y24-Y23*Y14-Y23*Y13)/(Y13*Y14* + & Y134**2)-(Y23+Y13)*(Y24+Y14)*Y12/(Y13*Y14*Y123*Y124) + WTTOT=WTTOT+CF*(TR*WTD(IC)+(CF-0.5*CN)*WTE(IC))/16. + ENDIF + +C...Permutations of momenta in matrix element. Weighting. + 130 IF(IC.EQ.1.OR.IC.EQ.3.OR.ID.EQ.2.OR.ID.EQ.3) THEN + YSAV=Y13 + Y13=Y14 + Y14=YSAV + YSAV=Y23 + Y23=Y24 + Y24=YSAV + YSAV=Y123 + Y123=Y124 + Y124=YSAV + ENDIF + IF(IC.EQ.2.OR.IC.EQ.4.OR.ID.EQ.3.OR.ID.EQ.4) THEN + YSAV=Y13 + Y13=Y23 + Y23=YSAV + YSAV=Y14 + Y14=Y24 + Y24=YSAV + YSAV=Y134 + Y134=Y234 + Y234=YSAV + ENDIF + IF(IC.LE.3) GOTO 120 + IF(ID.EQ.1.AND.WTTOT.LT.RLU(0)*WTMX) GOTO 110 + IC=5 + +C...qqgg events: string configuration and event type. + IF(IT.EQ.1) THEN + IF(MSTJ(109).EQ.0.AND.ID.EQ.1) THEN + PARJ(156)=Y34*(2.*(WTA(1)+WTA(2)+WTA(3)+WTA(4))+4.*(WTC(1)+ + & WTC(2)+WTC(3)+WTC(4)))/(9.*WTTOT) + IF(WTA(2)+WTA(4)+2.*(WTC(2)+WTC(4)).GT.RLU(0)*(WTA(1)+WTA(2)+ + & WTA(3)+WTA(4)+2.*(WTC(1)+WTC(2)+WTC(3)+WTC(4)))) ID=2 + IF(ID.EQ.2) GOTO 130 + ELSEIF(MSTJ(109).EQ.2.AND.ID.EQ.1) THEN + PARJ(156)=Y34*(WTA(1)+WTA(2)+WTA(3)+WTA(4))/(8.*WTTOT) + IF(WTA(2)+WTA(4).GT.RLU(0)*(WTA(1)+WTA(2)+WTA(3)+WTA(4))) ID=2 + IF(ID.EQ.2) GOTO 130 + ENDIF + MSTJ(120)=3 + IF(MSTJ(109).EQ.0.AND.0.5*Y34*(WTC(1)+WTC(2)+WTC(3)+WTC(4)).GT. + & RLU(0)*WTTOT) MSTJ(120)=4 + KFLN=21 + +C...Mass cuts. Kinematical variables out. + IF(Y12.LE.CUT+QME) NJET=2 + IF(NJET.EQ.2) GOTO 150 + Q12=0.5*(1.-SQRT(1.-QME/Y12)) + X1=1.-(1.-Q12)*Y234-Q12*Y134 + X4=1.-(1.-Q12)*Y134-Q12*Y234 + X2=1.-Y124 + X12=(1.-Q12)*Y13+Q12*Y23 + X14=Y12-0.5*QME + IF(Y134*Y234/((1.-X1)*(1.-X4)).LE.RLU(0)) NJET=2 + +C...qqbarqqbar events: string configuration, choose new flavour. + ELSE + IF(ID.EQ.1) THEN + WTR=RLU(0)*(WTD(1)+WTD(2)+WTD(3)+WTD(4)) + IF(WTR.LT.WTD(2)+WTD(3)+WTD(4)) ID=2 + IF(WTR.LT.WTD(3)+WTD(4)) ID=3 + IF(WTR.LT.WTD(4)) ID=4 + IF(ID.GE.2) GOTO 130 + ENDIF + MSTJ(120)=5 + PARJ(156)=CF*TR*(WTD(1)+WTD(2)+WTD(3)+WTD(4))/(16.*WTTOT) + 140 KFLN=1+INT(5.*RLU(0)) + IF(KFLN.NE.KFL.AND.0.2*PARJ(156).LE.RLU(0)) GOTO 140 + IF(KFLN.EQ.KFL.AND.1.-0.8*PARJ(156).LE.RLU(0)) GOTO 140 + IF(KFLN.GT.MSTJ(104)) NJET=2 + PMQN=ULMASS(KFLN) + QMEN=(2.*PMQN/ECM)**2 + +C...Mass cuts. Kinematical variables out. + IF(Y24.LE.CUT+QME.OR.Y13.LE.1.1*QMEN) NJET=2 + IF(NJET.EQ.2) GOTO 150 + Q24=0.5*(1.-SQRT(1.-QME/Y24)) + Q13=0.5*(1.-SQRT(1.-QMEN/Y13)) + X1=1.-(1.-Q24)*Y123-Q24*Y134 + X4=1.-(1.-Q24)*Y134-Q24*Y123 + X2=1.-(1.-Q13)*Y234-Q13*Y124 + X12=(1.-Q24)*((1.-Q13)*Y14+Q13*Y34)+Q24*((1.-Q13)*Y12+Q13*Y23) + X14=Y24-0.5*QME + X34=(1.-Q24)*((1.-Q13)*Y23+Q13*Y12)+Q24*((1.-Q13)*Y34+Q13*Y14) + IF(PMQ**2+PMQN**2+MIN(X12,X34)*ECM**2.LE. + & (PARJ(127)+PMQ+PMQN)**2) NJET=2 + IF(Y123*Y134/((1.-X1)*(1.-X4)).LE.RLU(0)) NJET=2 + ENDIF + 150 IF(MSTJ(101).LE.-2.AND.NJET.EQ.2) GOTO 100 + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUXDIF + SUBROUTINE LUXDIF(NC,NJET,KFL,ECM,CHI,THE,PHI) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to give the angular orientation of events. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + +C...Charge. Factors depending on polarization for QED case. + QF=KCHG(KFL,1)/3. + POLL=1.-PARJ(131)*PARJ(132) + POLD=PARJ(132)-PARJ(131) + IF(MSTJ(102).LE.1.OR.MSTJ(109).EQ.1) THEN + HF1=POLL + HF2=0. + HF3=PARJ(133)**2 + HF4=0. + +C...Factors depending on flavour, energy and polarization for QFD case. + ELSE + SFF=1./(16.*PARU(102)*(1.-PARU(102))) + SFW=ECM**4/((ECM**2-PARJ(123)**2)**2+(PARJ(123)*PARJ(124))**2) + SFI=SFW*(1.-(PARJ(123)/ECM)**2) + AE=-1. + VE=4.*PARU(102)-1. + AF=SIGN(1.D0,QF) + VF=AF-4.*QF*PARU(102) + HF1=QF**2*POLL-2.*QF*VF*SFI*SFF*(VE*POLL-AE*POLD)+ + & (VF**2+AF**2)*SFW*SFF**2*((VE**2+AE**2)*POLL-2.*VE*AE*POLD) + HF2=-2.*QF*AF*SFI*SFF*(AE*POLL-VE*POLD)+2.*VF*AF*SFW*SFF**2* + & (2.*VE*AE*POLL-(VE**2+AE**2)*POLD) + HF3=PARJ(133)**2*(QF**2-2.*QF*VF*SFI*SFF*VE+(VF**2+AF**2)* + & SFW*SFF**2*(VE**2-AE**2)) + HF4=-PARJ(133)**2*2.*QF*VF*SFW*(PARJ(123)*PARJ(124)/ECM**2)* + & SFF*AE + ENDIF + +C...Mass factor. Differential cross-sections for two-jet events. + SQ2=SQRT(2.) + QME=0. + IF(MSTJ(103).GE.4.AND.IABS(MSTJ(101)).LE.1.AND.MSTJ(102).LE.1.AND. + &MSTJ(109).NE.1) QME=(2.*ULMASS(KFL)/ECM)**2 + IF(NJET.EQ.2) THEN + SIGU=4.*SQRT(1.-QME) + SIGL=2.*QME*SQRT(1.-QME) + SIGT=0. + SIGI=0. + SIGA=0. + SIGP=4. + +C...Kinematical variables. Reduce four-jet event to three-jet one. + ELSE + IF(NJET.EQ.3) THEN + X1=2.*P(NC+1,4)/ECM + X2=2.*P(NC+3,4)/ECM + ELSE + ECMR=P(NC+1,4)+P(NC+4,4)+SQRT((P(NC+2,1)+P(NC+3,1))**2+ + & (P(NC+2,2)+P(NC+3,2))**2+(P(NC+2,3)+P(NC+3,3))**2) + X1=2.*P(NC+1,4)/ECMR + X2=2.*P(NC+4,4)/ECMR + ENDIF + +C...Differential cross-sections for three-jet (or reduced four-jet). + XQ=(1.-X1)/(1.-X2) + CT12=(X1*X2-2.*X1-2.*X2+2.+QME)/SQRT((X1**2-QME)*(X2**2-QME)) + ST12=SQRT(1.-CT12**2) + IF(MSTJ(109).NE.1) THEN + SIGU=2.*X1**2+X2**2*(1.+CT12**2)-QME*(3.+CT12**2-X1-X2)- + & QME*X1/XQ+0.5*QME*((X2**2-QME)*ST12**2-2.*X2)*XQ + SIGL=(X2*ST12)**2-QME*(3.-CT12**2-2.5*(X1+X2)+X1*X2+QME)+ + & 0.5*QME*(X1**2-X1-QME)/XQ+0.5*QME*((X2**2-QME)*CT12**2-X2)*XQ + SIGT=0.5*(X2**2-QME-0.5*QME*(X2**2-QME)/XQ)*ST12**2 + SIGI=((1.-0.5*QME*XQ)*(X2**2-QME)*ST12*CT12+QME*(1.-X1-X2+ + & 0.5*X1*X2+0.5*QME)*ST12/CT12)/SQ2 + SIGA=X2**2*ST12/SQ2 + SIGP=2.*(X1**2-X2**2*CT12) + +C...Differential cross-sect for scalar gluons (no mass effects). + ELSE + X3=2.-X1-X2 + XT=X2*ST12 + CT13=SQRT(MAX(0.D0,1.-(XT/X3)**2)) + SIGU=(1.-PARJ(171))*(X3**2-0.5*XT**2)+ + & PARJ(171)*(X3**2-0.5*XT**2-4.*(1.-X1)*(1.-X2)**2/X1) + SIGL=(1.-PARJ(171))*0.5*XT**2+ + & PARJ(171)*0.5*(1.-X1)**2*XT**2 + SIGT=(1.-PARJ(171))*0.25*XT**2+ + & PARJ(171)*0.25*XT**2*(1.-2.*X1) + SIGI=-(0.5/SQ2)*((1.-PARJ(171))*XT*X3*CT13+ + & PARJ(171)*XT*((1.-2.*X1)*X3*CT13-X1*(X1-X2))) + SIGA=(0.25/SQ2)*XT*(2.*(1.-X1)-X1*X3) + SIGP=X3**2-2.*(1.-X1)*(1.-X2)/X1 + ENDIF + ENDIF + +C...Upper bounds for differential cross-section. + HF1A=ABS(HF1) + HF2A=ABS(HF2) + HF3A=ABS(HF3) + HF4A=ABS(HF4) + SIGMAX=(2.*HF1A+HF3A+HF4A)*ABS(SIGU)+2.*(HF1A+HF3A+HF4A)* + &ABS(SIGL)+2.*(HF1A+2.*HF3A+2.*HF4A)*ABS(SIGT)+2.*SQ2* + &(HF1A+2.*HF3A+2.*HF4A)*ABS(SIGI)+4.*SQ2*HF2A*ABS(SIGA)+ + &2.*HF2A*ABS(SIGP) + +C...Generate angular orientation according to differential cross-sect. + 100 CHI=PARU(2)*RLU(0) + CTHE=2.*RLU(0)-1. + PHI=PARU(2)*RLU(0) + CCHI=COS(CHI) + SCHI=SIN(CHI) + C2CHI=COS(2.*CHI) + S2CHI=SIN(2.*CHI) + THE=ACOS(CTHE) + STHE=SIN(THE) + C2PHI=COS(2.*(PHI-PARJ(134))) + S2PHI=SIN(2.*(PHI-PARJ(134))) + SIG=((1.+CTHE**2)*HF1+STHE**2*(C2PHI*HF3-S2PHI*HF4))*SIGU+ + &2.*(STHE**2*HF1-STHE**2*(C2PHI*HF3-S2PHI*HF4))*SIGL+ + &2.*(STHE**2*C2CHI*HF1+((1.+CTHE**2)*C2CHI*C2PHI-2.*CTHE*S2CHI* + &S2PHI)*HF3-((1.+CTHE**2)*C2CHI*S2PHI+2.*CTHE*S2CHI*C2PHI)*HF4)* + &SIGT-2.*SQ2*(2.*STHE*CTHE*CCHI*HF1-2.*STHE*(CTHE*CCHI*C2PHI- + &SCHI*S2PHI)*HF3+2.*STHE*(CTHE*CCHI*S2PHI+SCHI*C2PHI)*HF4)*SIGI+ + &4.*SQ2*STHE*CCHI*HF2*SIGA+2.*CTHE*HF2*SIGP + IF(SIG.LT.SIGMAX*RLU(0)) GOTO 100 + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUONIA + SUBROUTINE LUONIA(KFL,ECM) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to generate Upsilon and toponium decays into three +C...gluons or two gluons and a photon. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + +C...Printout. Check input parameters. + IF(MSTU(12).GE.1) CALL LULIST(0) + IF(KFL.LT.0.OR.KFL.GT.8) THEN + CALL LUERRM(16,'(LUONIA:) called with unknown flavour code') + IF(MSTU(21).GE.1) RETURN + ENDIF + IF(ECM.LT.PARJ(127)+2.02*PARF(101)) THEN + CALL LUERRM(16,'(LUONIA:) called with too small CM energy') + IF(MSTU(21).GE.1) RETURN + ENDIF + +C...Initial e+e- and onium state (optional). + NC=0 + IF(MSTJ(115).GE.2) THEN + NC=NC+2 + CALL LU1ENT(NC-1,11,0.5*ECM,0.D0,0.D0) + K(NC-1,1)=21 + CALL LU1ENT(NC,-11,0.5*ECM,PARU(1),0.D0) + K(NC,1)=21 + ENDIF + KFLC=IABS(KFL) + IF(MSTJ(115).GE.3.AND.KFLC.GE.5) THEN + NC=NC+1 + KF=110*KFLC+3 + MSTU10=MSTU(10) + MSTU(10)=1 + P(NC,5)=ECM + CALL LU1ENT(NC,KF,ECM,0.D0,0.D0) + K(NC,1)=21 + K(NC,3)=1 + MSTU(10)=MSTU10 + ENDIF + +C...Choose x1 and x2 according to matrix element. + NTRY=0 + 100 X1=RLU(0) + X2=RLU(0) + X3=2.-X1-X2 + IF(X3.GE.1..OR.((1.-X1)/(X2*X3))**2+((1.-X2)/(X1*X3))**2+ + &((1.-X3)/(X1*X2))**2.LE.2.*RLU(0)) GOTO 100 + NTRY=NTRY+1 + NJET=3 + IF(MSTJ(101).LE.4) CALL LU3ENT(NC+1,21,21,21,ECM,X1,X3) + IF(MSTJ(101).GE.5) CALL LU3ENT(-(NC+1),21,21,21,ECM,X1,X3) + +C...Photon-gluon-gluon events. Small system modifications. Jet origin. + MSTU(111)=MSTJ(108) + IF(MSTJ(108).EQ.2.AND.(MSTJ(101).EQ.0.OR.MSTJ(101).EQ.1)) + &MSTU(111)=1 + PARU(112)=PARJ(121) + IF(MSTU(111).EQ.2) PARU(112)=PARJ(122) + QF=0. + IF(KFLC.NE.0) QF=KCHG(KFLC,1)/3. + RGAM=7.2*QF**2*PARU(101)/ULALPS(ECM**2) + MK=0 + ECMC=ECM + IF(RLU(0).GT.RGAM/(1.+RGAM)) THEN + IF(1.-MAX(X1,X2,X3).LE.MAX((PARJ(126)/ECM)**2,PARJ(125))) + & NJET=2 + IF(NJET.EQ.2.AND.MSTJ(101).LE.4) CALL LU2ENT(NC+1,21,21,ECM) + IF(NJET.EQ.2.AND.MSTJ(101).GE.5) CALL LU2ENT(-(NC+1),21,21,ECM) + ELSE + MK=1 + ECMC=SQRT(1.-X1)*ECM + IF(ECMC.LT.2.*PARJ(127)) GOTO 100 + K(NC+1,1)=1 + K(NC+1,2)=22 + K(NC+1,4)=0 + K(NC+1,5)=0 + IF(MSTJ(101).GE.5) K(NC+2,4)=MSTU(5)*(NC+3) + IF(MSTJ(101).GE.5) K(NC+2,5)=MSTU(5)*(NC+3) + IF(MSTJ(101).GE.5) K(NC+3,4)=MSTU(5)*(NC+2) + IF(MSTJ(101).GE.5) K(NC+3,5)=MSTU(5)*(NC+2) + NJET=2 + IF(ECMC.LT.4.*PARJ(127)) THEN + MSTU10=MSTU(10) + MSTU(10)=1 + P(NC+2,5)=ECMC + CALL LU1ENT(NC+2,83,0.5*(X2+X3)*ECM,PARU(1),0.D0) + MSTU(10)=MSTU10 + NJET=0 + ENDIF + ENDIF + DO 110 IP=NC+1,N + K(IP,3)=K(IP,3)+(MSTJ(115)/2)+(KFLC/5)*(MSTJ(115)/3)*(NC-1) + 110 CONTINUE + +C...Differential cross-sections. Upper limit for cross-section. + IF(MSTJ(106).EQ.1) THEN + SQ2=SQRT(2.) + HF1=1.-PARJ(131)*PARJ(132) + HF3=PARJ(133)**2 + CT13=(X1*X3-2.*X1-2.*X3+2.)/(X1*X3) + ST13=SQRT(1.-CT13**2) + SIGL=0.5*X3**2*((1.-X2)**2+(1.-X3)**2)*ST13**2 + SIGU=(X1*(1.-X1))**2+(X2*(1.-X2))**2+(X3*(1.-X3))**2-SIGL + SIGT=0.5*SIGL + SIGI=(SIGL*CT13/ST13+0.5*X1*X3*(1.-X2)**2*ST13)/SQ2 + SIGMAX=(2.*HF1+HF3)*ABS(SIGU)+2.*(HF1+HF3)*ABS(SIGL)+2.*(HF1+ + & 2.*HF3)*ABS(SIGT)+2.*SQ2*(HF1+2.*HF3)*ABS(SIGI) + +C...Angular orientation of event. + 120 CHI=PARU(2)*RLU(0) + CTHE=2.*RLU(0)-1. + PHI=PARU(2)*RLU(0) + CCHI=COS(CHI) + SCHI=SIN(CHI) + C2CHI=COS(2.*CHI) + S2CHI=SIN(2.*CHI) + THE=ACOS(CTHE) + STHE=SIN(THE) + C2PHI=COS(2.*(PHI-PARJ(134))) + S2PHI=SIN(2.*(PHI-PARJ(134))) + SIG=((1.+CTHE**2)*HF1+STHE**2*C2PHI*HF3)*SIGU+2.*(STHE**2*HF1- + & STHE**2*C2PHI*HF3)*SIGL+2.*(STHE**2*C2CHI*HF1+((1.+CTHE**2)* + & C2CHI*C2PHI-2.*CTHE*S2CHI*S2PHI)*HF3)*SIGT-2.*SQ2*(2.*STHE*CTHE* + & CCHI*HF1-2.*STHE*(CTHE*CCHI*C2PHI-SCHI*S2PHI)*HF3)*SIGI + IF(SIG.LT.SIGMAX*RLU(0)) GOTO 120 + CALL LUDBRB(NC+1,N,0.D0,CHI,0D0,0D0,0D0) + CALL LUDBRB(NC+1,N,THE,PHI,0D0,0D0,0D0) + ENDIF + +C...Generate parton shower. Rearrange along strings and check. + IF(MSTJ(101).GE.5.AND.NJET.GE.2) THEN + CALL LUSHOW(NC+MK+1,-NJET,ECMC) + MSTJ14=MSTJ(14) + IF(MSTJ(105).EQ.-1) MSTJ(14)=-1 + IF(MSTJ(105).GE.0) MSTU(28)=0 + CALL LUPREP(0) + MSTJ(14)=MSTJ14 + IF(MSTJ(105).GE.0.AND.MSTU(28).NE.0) GOTO 100 + ENDIF + +C...Generate fragmentation. Information for LUTABU: + IF(MSTJ(105).EQ.1) CALL LUEXEC + MSTU(161)=110*KFLC+3 + MSTU(162)=0 + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUHEPC + SUBROUTINE LUHEPC(MCONV) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to convert JETSET event record contents to or from +C...the standard event record commonblock. +C...Note that HEPEVT is in double precision according to LEP 2 standard. + PARAMETER (NMXHEP=2000) + COMMON/HEPEVT/NEVHEP,NHEP,ISTHEP(NMXHEP),IDHEP(NMXHEP), + &JMOHEP(2,NMXHEP),JDAHEP(2,NMXHEP),PHEP(5,NMXHEP),VHEP(4,NMXHEP) +C DOUBLE PRECISION PHEP,VHEP + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + SAVE /HEPEVT/ + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + +C...Conversion from JETSET to standard, the easy part. + IF(MCONV.EQ.1) THEN + NEVHEP=0 + IF(N.GT.NMXHEP) CALL LUERRM(8, + & '(LUHEPC:) no more space in /HEPEVT/') + NHEP=MIN(N,NMXHEP) + DO 140 I=1,NHEP + ISTHEP(I)=0 + IF(K(I,1).GE.1.AND.K(I,1).LE.10) ISTHEP(I)=1 + IF(K(I,1).GE.11.AND.K(I,1).LE.20) ISTHEP(I)=2 + IF(K(I,1).GE.21.AND.K(I,1).LE.30) ISTHEP(I)=3 + IF(K(I,1).GE.31.AND.K(I,1).LE.100) ISTHEP(I)=K(I,1) + IDHEP(I)=K(I,2) + JMOHEP(1,I)=K(I,3) + JMOHEP(2,I)=0 + IF(K(I,1).NE.3.AND.K(I,1).NE.13.AND.K(I,1).NE.14) THEN + JDAHEP(1,I)=K(I,4) + JDAHEP(2,I)=K(I,5) + ELSE + JDAHEP(1,I)=0 + JDAHEP(2,I)=0 + ENDIF + DO 100 J=1,5 + PHEP(J,I)=P(I,J) + 100 CONTINUE + DO 110 J=1,4 + VHEP(J,I)=V(I,J) + 110 CONTINUE + +C...Check if new event (from pileup). + IF(I.EQ.1) THEN + INEW=1 + ELSE + IF(K(I,1).EQ.21.AND.K(I-1,1).NE.21) INEW=I + ENDIF + +C...Fill in missing mother information. + IF(I.GE.INEW+2.AND.K(I,1).EQ.21.AND.K(I,3).EQ.0) THEN + IMO1=I-2 + IF(I.GE.INEW+3.AND.K(I-1,1).EQ.21.AND.K(I-1,3).EQ.0) + & IMO1=IMO1-1 + JMOHEP(1,I)=IMO1 + JMOHEP(2,I)=IMO1+1 + ELSEIF(K(I,2).GE.91.AND.K(I,2).LE.93) THEN + I1=K(I,3)-1 + 120 I1=I1+1 + IF(I1.GE.I) CALL LUERRM(8, + & '(LUHEPC:) translation of inconsistent event history') + IF(I1.LT.I.AND.K(I1,1).NE.1.AND.K(I1,1).NE.11) GOTO 120 + KC=LUCOMP(K(I1,2)) + IF(I1.LT.I.AND.KC.EQ.0) GOTO 120 + IF(I1.LT.I.AND.KCHG(KC,2).EQ.0) GOTO 120 + JMOHEP(2,I)=I1 + ELSEIF(K(I,2).EQ.94) THEN + NJET=2 + IF(NHEP.GE.I+3.AND.K(I+3,3).LE.I) NJET=3 + IF(NHEP.GE.I+4.AND.K(I+4,3).LE.I) NJET=4 + JMOHEP(2,I)=MOD(K(I+NJET,4)/MSTU(5),MSTU(5)) + IF(JMOHEP(2,I).EQ.JMOHEP(1,I)) JMOHEP(2,I)= + & MOD(K(I+1,4)/MSTU(5),MSTU(5)) + ENDIF + +C...Fill in missing daughter information. + IF(K(I,2).EQ.94.AND.MSTU(16).NE.2) THEN + DO 130 I1=JDAHEP(1,I),JDAHEP(2,I) + I2=MOD(K(I1,4)/MSTU(5),MSTU(5)) + JDAHEP(1,I2)=I + 130 CONTINUE + ENDIF + IF(K(I,2).GE.91.AND.K(I,2).LE.94) GOTO 140 + I1=JMOHEP(1,I) + IF(I1.LE.0.OR.I1.GT.NHEP) GOTO 140 + IF(K(I1,1).NE.13.AND.K(I1,1).NE.14) GOTO 140 + IF(JDAHEP(1,I1).EQ.0) THEN + JDAHEP(1,I1)=I + ELSE + JDAHEP(2,I1)=I + ENDIF + 140 CONTINUE + DO 150 I=1,NHEP + IF(K(I,1).NE.13.AND.K(I,1).NE.14) GOTO 150 + IF(JDAHEP(2,I).EQ.0) JDAHEP(2,I)=JDAHEP(1,I) + 150 CONTINUE + +C...Conversion from standard to JETSET, the easy part. + ELSE + IF(NHEP.GT.MSTU(4)) CALL LUERRM(8, + & '(LUHEPC:) no more space in /LUJETS/') + N=MIN(NHEP,MSTU(4)) + NKQ=0 + KQSUM=0 + DO 180 I=1,N + K(I,1)=0 + IF(ISTHEP(I).EQ.1) K(I,1)=1 + IF(ISTHEP(I).EQ.2) K(I,1)=11 + IF(ISTHEP(I).EQ.3) K(I,1)=21 + K(I,2)=IDHEP(I) + K(I,3)=JMOHEP(1,I) + K(I,4)=JDAHEP(1,I) + K(I,5)=JDAHEP(2,I) + DO 160 J=1,5 + P(I,J)=PHEP(J,I) + 160 CONTINUE + DO 170 J=1,4 + V(I,J)=VHEP(J,I) + 170 CONTINUE + V(I,5)=0. + IF(ISTHEP(I).EQ.2.AND.PHEP(4,I).GT.PHEP(5,I)) THEN + I1=JDAHEP(1,I) + IF(I1.GT.0.AND.I1.LE.NHEP) V(I,5)=(VHEP(4,I1)-VHEP(4,I))* + & PHEP(5,I)/PHEP(4,I) + ENDIF + +C...Fill in missing information on colour connection in jet systems. + IF(ISTHEP(I).EQ.1) THEN + KC=LUCOMP(K(I,2)) + KQ=0 + IF(KC.NE.0) KQ=KCHG(KC,2)*ISIGN(1,K(I,2)) + IF(KQ.NE.0) NKQ=NKQ+1 + IF(KQ.NE.2) KQSUM=KQSUM+KQ + IF(KQ.NE.0.AND.KQSUM.NE.0) THEN + K(I,1)=2 + ELSEIF(KQ.EQ.2.AND.I.LT.N) THEN + IF(K(I+1,2).EQ.21) K(I,1)=2 + ENDIF + ENDIF + 180 CONTINUE + IF(NKQ.EQ.1.OR.KQSUM.NE.0) CALL LUERRM(8, + & '(LUHEPC:) input parton configuration not colour singlet') + ENDIF + + END + +C********************************************************************* + +CDECK ID>, LUTEST + SUBROUTINE LUTEST(MTEST) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to provide a simple program (disguised as subroutine) to +C...run at installation as a check that the program works as intended. + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + SAVE /LUJETS/,/LUDAT1/ + DIMENSION PSUM(5),PINI(6),PFIN(6) + +C...Loop over events to be generated. + IF(MTEST.GE.1) CALL LUTABU(20) + NERR=0 + DO 180 IEV=1,600 + +C...Reset parameter values. Switch on some nonstandard features. + MSTJ(1)=1 + MSTJ(3)=0 + MSTJ(11)=1 + MSTJ(42)=2 + MSTJ(43)=4 + MSTJ(44)=2 + PARJ(17)=0.1 + PARJ(22)=1.5 + PARJ(43)=1. + PARJ(54)=-0.05 + MSTJ(101)=5 + MSTJ(104)=5 + MSTJ(105)=0 + MSTJ(107)=1 + IF(IEV.EQ.301.OR.IEV.EQ.351.OR.IEV.EQ.401) MSTJ(116)=3 + +C...Ten events each for some single jets configurations. + IF(IEV.LE.50) THEN + ITY=(IEV+9)/10 + MSTJ(3)=-1 + IF(ITY.EQ.3.OR.ITY.EQ.4) MSTJ(11)=2 + IF(ITY.EQ.1) CALL LU1ENT(1,1,15.D0,0.D0,0.D0) + IF(ITY.EQ.2) CALL LU1ENT(1,3101,15.D0,0.D0,0.D0) + IF(ITY.EQ.3) CALL LU1ENT(1,-2203,15.D0,0.D0,0.D0) + IF(ITY.EQ.4) CALL LU1ENT(1,-4,30.D0,0.D0,0.D0) + IF(ITY.EQ.5) CALL LU1ENT(1,21,15.D0,0.D0,0.D0) + +C...Ten events each for some simple jet systems; string fragmentation. + ELSEIF(IEV.LE.130) THEN + ITY=(IEV-41)/10 + IF(ITY.EQ.1) CALL LU2ENT(1,1,-1,40.D0) + IF(ITY.EQ.2) CALL LU2ENT(1,4,-4,30.D0) + IF(ITY.EQ.3) CALL LU2ENT(1,2,2103,100.D0) + IF(ITY.EQ.4) CALL LU2ENT(1,21,21,40.D0) + IF(ITY.EQ.5) CALL LU3ENT(1,2101,21,-3203,30.D0,0.6D0,0.8D0) + IF(ITY.EQ.6) CALL LU3ENT(1,5,21,-5,40.D0,0.9D0,0.8D0) + IF(ITY.EQ.7) CALL LU3ENT(1,21,21,21,60.D0,0.7D0,0.5D0) + IF(ITY.EQ.8) + & CALL LU4ENT(1,2,21,21,-2,40.D0,0.4D0,0.64D0,0.6D0,0.12D0,0.2D0) + +C...Seventy events with independent fragmentation and momentum cons. + ELSEIF(IEV.LE.200) THEN + ITY=1+(IEV-131)/16 + MSTJ(2)=1+MOD(IEV-131,4) + MSTJ(3)=1+MOD((IEV-131)/4,4) + IF(ITY.EQ.1) CALL LU2ENT(1,4,-5,40.D0) + IF(ITY.EQ.2) CALL LU3ENT(1,3,21,-3,40.D0,0.9D0,0.4D0) + IF(ITY.EQ.3) + & CALL LU4ENT(1,2,21,21,-2,40.D0,0.4D0,0.64D0,0.6D0,0.12D0,0.2D0) + IF(ITY.GE.4) + & CALL LU4ENT(1,2,-3,3,-2,40.D0,0.4D0,0.64D0,0.6D0,0.12D0,0.2D0) + +C...A hundred events with random jets (check invariant mass). + ELSEIF(IEV.LE.300) THEN + 100 DO 110 J=1,5 + PSUM(J)=0. + 110 CONTINUE + NJET=2.+6.*RLU(0) + DO 130 I=1,NJET + KFL=21 + IF(I.EQ.1) KFL=INT(1.+4.*RLU(0)) + IF(I.EQ.NJET) KFL=-INT(1.+4.*RLU(0)) + EJET=5.+20.*RLU(0) + THETA=ACOS(2.*RLU(0)-1.) + PHI=6.2832*RLU(0) + IF(I.LT.NJET) CALL LU1ENT(-I,KFL,EJET,THETA,PHI) + IF(I.EQ.NJET) CALL LU1ENT(I,KFL,EJET,THETA,PHI) + IF(I.EQ.1.OR.I.EQ.NJET) MSTJ(93)=1 + IF(I.EQ.1.OR.I.EQ.NJET) PSUM(5)=PSUM(5)+ULMASS(KFL) + DO 120 J=1,4 + PSUM(J)=PSUM(J)+P(I,J) + 120 CONTINUE + 130 CONTINUE + IF(PSUM(4)**2-PSUM(1)**2-PSUM(2)**2-PSUM(3)**2.LT. + & (PSUM(5)+PARJ(32))**2) GOTO 100 + +C...Fifty e+e- continuum events with matrix elements. + ELSEIF(IEV.LE.350) THEN + MSTJ(101)=2 + CALL LUEEVT(0,40.D0) + +C...Fifty e+e- continuum event with varying shower options. + ELSEIF(IEV.LE.400) THEN + MSTJ(42)=1+MOD(IEV,2) + MSTJ(43)=1+MOD(IEV/2,4) + MSTJ(44)=MOD(IEV/8,3) + CALL LUEEVT(0,90.D0) + +C...Fifty e+e- continuum events with coherent shower, including top. + ELSEIF(IEV.LE.450) THEN + MSTJ(104)=6 + CALL LUEEVT(0,500.D0) + +C...Fifty Upsilon decays to ggg or gammagg with coherent shower. + ELSEIF(IEV.LE.500) THEN + CALL LUONIA(5,9.46D0) + +C...One decay each for some heavy mesons. + ELSEIF(IEV.LE.560) THEN + ITY=IEV-501 + KFLS=2*(ITY/20)+1 + KFLB=8-MOD(ITY/5,4) + KFLC=KFLB-MOD(ITY,5) + CALL LU1ENT(1,100*KFLB+10*KFLC+KFLS,0.D0,0.D0,0.D0) + +C...One decay each for some heavy baryons. + ELSEIF(IEV.LE.600) THEN + ITY=IEV-561 + KFLS=2*(ITY/20)+2 + KFLA=8-MOD(ITY/5,4) + KFLB=KFLA-MOD(ITY,5) + KFLC=MAX(1,KFLB-1) + CALL LU1ENT(1,1000*KFLA+100*KFLB+10*KFLC+KFLS,0.D0,0.D0,0.D0) + ENDIF + +C...Generate event. Find total momentum, energy and charge. + DO 140 J=1,4 + PINI(J)=PLU(0,J) + 140 CONTINUE + PINI(6)=PLU(0,6) + CALL LUEXEC + DO 150 J=1,4 + PFIN(J)=PLU(0,J) + 150 CONTINUE + PFIN(6)=PLU(0,6) + +C...Check conservation of energy, momentum and charge; +C...usually exact, but only approximate for single jets. + MERR=0 + IF(IEV.LE.50) THEN + IF((PFIN(1)-PINI(1))**2+(PFIN(2)-PINI(2))**2.GE.4.) MERR=MERR+1 + EPZREM=PINI(4)+PINI(3)-PFIN(4)-PFIN(3) + IF(EPZREM.LT.0..OR.EPZREM.GT.2.*PARJ(31)) MERR=MERR+1 + IF(ABS(PFIN(6)-PINI(6)).GT.2.1) MERR=MERR+1 + ELSE + DO 160 J=1,4 + IF(ABS(PFIN(J)-PINI(J)).GT.0.0001*PINI(4)) MERR=MERR+1 + 160 CONTINUE + IF(ABS(PFIN(6)-PINI(6)).GT.0.1) MERR=MERR+1 + ENDIF + IF(MERR.NE.0) WRITE(MSTU(11),5000) (PINI(J),J=1,4),PINI(6), + &(PFIN(J),J=1,4),PFIN(6) + +C...Check that all KF codes are known ones, and that partons/particles +C...satisfy energy-momentum-mass relation. Store particle statistics. + DO 170 I=1,N + IF(K(I,1).GT.20) GOTO 170 + IF(LUCOMP(K(I,2)).EQ.0) THEN + WRITE(MSTU(11),5100) I + MERR=MERR+1 + ENDIF + PD=P(I,4)**2-P(I,1)**2-P(I,2)**2-P(I,3)**2-P(I,5)**2 + IF(ABS(PD).GT.MAX(0.1D0,0.001*P(I,4)**2).OR.P(I,4).LT.0.) THEN + WRITE(MSTU(11),5200) I + MERR=MERR+1 + ENDIF + 170 CONTINUE + IF(MTEST.GE.1) CALL LUTABU(21) + +C...List all erroneous events and some normal ones. + IF(MERR.NE.0.OR.MSTU(24).NE.0.OR.MSTU(28).NE.0) THEN + CALL LULIST(2) + ELSEIF(MTEST.GE.1.AND.MOD(IEV-5,100).EQ.0) THEN + CALL LULIST(1) + ENDIF + +C...Stop execution if too many errors. + IF(MERR.NE.0) NERR=NERR+1 + IF(NERR.GE.10) THEN + WRITE(MSTU(11),5300) IEV + STOP + ENDIF + 180 CONTINUE + +C...Summarize result of run. + IF(MTEST.GE.1) CALL LUTABU(22) + IF(NERR.EQ.0) WRITE(MSTU(11),5400) + IF(NERR.GT.0) WRITE(MSTU(11),5500) NERR + +C...Reset commonblock variables changed during run. + MSTJ(2)=3 + PARJ(17)=0. + PARJ(22)=1. + PARJ(43)=0.5 + PARJ(54)=0. + MSTJ(105)=1 + MSTJ(107)=0 + +C...Format statements for output. + 5000 FORMAT(/' Momentum, energy and/or charge were not conserved ', + &'in following event'/' sum of',9X,'px',11X,'py',11X,'pz',11X, + &'E',8X,'charge'/' before',2X,4(1X,F12.5),1X,F8.2/' after',3X, + &4(1X,F12.5),1X,F8.2) + 5100 FORMAT(/5X,'Entry no.',I4,' in following event not known code') + 5200 FORMAT(/5X,'Entry no.',I4,' in following event has faulty ', + &'kinematics') + 5300 FORMAT(/5X,'Ten errors experienced by event ',I3/ + &5X,'Something is seriously wrong! Execution stopped now!') + 5400 FORMAT(//5X,'End result of LUTEST: no errors detected.') + 5500 FORMAT(//5X,'End result of LUTEST:',I2,' errors detected.'/ + &5X,'This should not have happened!') + + RETURN + END + +C********************************************************************* + +CDECK ID>, LUDATA + BLOCK DATA LUDATA + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Purpose: to give default values to parameters and particle and +C...decay data. + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) + COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) + COMMON/LUDAT4/CHAF(500) + CHARACTER CHAF*8 + COMMON/LUDATR/MRLU(6),RRLU(100) + SAVE /LUDAT1/,/LUDAT2/,/LUDAT3/,/LUDAT4/,/LUDATR/ + +C...LUDAT1, containing status codes and most parameters. + DATA MSTU/ + & 0, 0, 0, 4000,10000, 500, 2000, 0, 0, 2, + 1 6, 1, 1, 0, 1, 1, 0, 0, 0, 0, + 2 2, 10, 0, 0, 1, 10, 0, 0, 0, 0, + 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4 2, 2, 1, 4, 2, 1, 1, 0, 0, 0, + 5 25, 24, 0, 1, 0, 0, 0, 0, 0, 0, + 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7 30*0, + & 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1 1, 5, 3, 5, 0, 0, 0, 0, 0, 0, + 2 60*0, + 8 7, 408, 1995, 08, 23, 700, 0, 0, 0, 0, + 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0/ + DATA PARU/ + & 3.1415927, 6.2831854, 0.1973, 5.068, 0.3894, 2.568, 4*0., + 1 0.001, 0.09, 0.01, 0., 0., 0., 0., 0., 0., 0., + 2 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 3 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 4 2.0, 1.0, 0.25, 2.5, 0.05, 0., 0., 0.0001, 0., 0., + 5 2.5, 1.5, 7.0, 1.0, 0.5, 2.0, 3.2, 0., 0., 0., + 6 40*0., + & 0.00729735, 0.232, 0.007764, 1.0, 1.16639D-5, 0., 0., 0., + & 0., 0., + 1 0.20, 0.25, 1.0, 4.0, 10., 0., 0., 0., 0., 0., + 2 -0.693, -1.0, 0.387, 1.0, -0.08, -1.0, 1.0, 1.0, 1.0, 0., + 3 1.0, -1.0, 1.0, -1.0, 1.0, 0., 0., 0., 0., 0., + 4 5.0, 1.0, 1.0, 0., 1.0, 1.0, 0., 0., 0., 0., + 5 1.0, 0., 0., 0., 1000., 1.0, 1.0, 1.0, 1.0, 0., + 6 1.0, 1.0, 1.0, 1.0, 1.0, 0., 0., 0., 0., 0., + 7 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0., 0., 0., + 8 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0., + 9 0., 0., 0., 0., 1.0, 0., 0., 0., 0., 0./ + DATA MSTJ/ + & 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, + 1 4, 2, 0, 1, 0, 0, 0, 0, 0, 0, + 2 2, 1, 1, 2, 1, 2, 2, 0, 0, 0, + 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4 2, 2, 4, 2, 5, 3, 3, 0, 0, 0, + 5 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, + 6 40*0, + & 5, 2, 7, 5, 1, 1, 0, 2, 0, 2, + 1 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 2 80*0/ + DATA PARJ/ + & 0.10, 0.30, 0.40, 0.05, 0.50, 0.50, 0.50, 0., 0., 0., + 1 0.50, 0.60, 0.75, 0., 0., 0., 0., 1.0, 1.0, 0., + 2 0.36, 1.0, 0.01, 2.0, 1.0, 0.4, 0., 0., 0., 0., + 3 0.10, 1.0, 0.8, 1.5, 0., 2.0, 0.2, 2.5, 0.6, 0., + 4 0.3, 0.58, 0.5, 0.9, 0.5, 1.0, 1.0, 1.0, 0., 0., + 5 0.77,0.77,0.77,-0.05,-0.005,-0.00001,-0.00001,-0.00001,1.0,0., + 6 4.5, 0.7, 0., 0.003, 0.5, 0.5, 0., 0., 0., 0., + 7 10., 1000., 100., 1000., 0., 0.7, 10., 0., 0., 0., + 8 0.29, 1.0, 1.0, 0., 10., 10., 0., 0., 0., 0., + 9 0.02, 1.0, 0.2, 0., 0., 0., 0., 0., 0., 0., + & 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 1 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 2 1.0, 0.25,91.187,2.489, 0.01, 2.0, 1.0, 0.25,0.002, 0., + 3 0., 0., 0., 0., 0.01, 0.99, 0., 0., 0.2, 0., + 4 60*0./ + +C...LUDAT2, with particle data and flavour treatment parameters. + DATA (KCHG(I,1),I= 1, 500)/-1,2,-1,2,-1,2,-1,2,2*0,-3,0,-3,0, + &-3,0,-3,6*0,3,9*0,3,2*0,3,0,-1,44*0,2,-1,2,-1,2,3,11*0,3,0,2*3,0, + &3,0,3,0,3,10*0,3,0,2*3,0,3,0,3,0,3,10*0,3,0,2*3,0,3,0,3,0,3,10*0, + &3,0,2*3,0,3,0,3,0,3,10*0,3,0,2*3,0,3,0,3,0,3,10*0,3,0,2*3,0,3,0, + &3,0,3,70*0,3,0,3,28*0,3,2*0,3,8*0,-3,8*0,3,0,-3,0,3,-3,3*0,3,6,0, + &3,5*0,-3,0,3,-3,0,-3,4*0,-3,0,3,6,-3,0,3,-3,0,-3,0,3,6,0,3,5*0, + &-3,0,3,-3,0,-3,114*0/ + DATA (KCHG(I,2),I= 1, 500)/8*1,12*0,2,16*0,2,1,50*0,-1,410*0/ + DATA (KCHG(I,3),I= 1, 500)/8*1,2*0,8*1,5*0,1,9*0,1,2*0,1,0,2*1, + &41*0,1,0,7*1,10*0,10*1,10*0,10*1,10*0,10*1,10*0,10*1,10*0,10*1, + &10*0,10*1,70*0,3*1,22*0,1,5*0,1,0,2*1,6*0,1,0,2*1,6*0,2*1,0,5*1, + &0,6*1,4*0,6*1,4*0,16*1,4*0,6*1,114*0/ + DATA (PMAS(I,1),I= 1, 500)/0.0099,0.0056,0.199,1.35,5.,160., + &2*250.,2*0.,0.00051,0.,0.1057,0.,1.777,0.,250.,5*0.,91.187,80.25, + &80.,6*0.,500.,900.,500.,3*300.,350.,200.,5000.,60*0.,0.1396, + &0.4977,0.4936,1.8693,1.8645,1.9688,5.2787,5.2786,5.47972,6.594, + &0.135,0.5475,0.9578,2.9788,9.4,320.,2*500.,2*0.,0.7669,0.8961, + &0.8916,2.0101,2.0071,2.11,2*5.325,5.5068,6.602,0.7683,0.782, + &1.0194,3.0969,9.4603,320.,2*500.,2*0.,1.232,2*1.29,2*2.424,2.536, + &2*5.73,5.97,7.3,1.232,1.17,1.4,3.46,9.875,320.,2*500.,2*0.,0.983, + &2*1.429,2*2.272,2.5,2*5.68,5.92,7.25,0.9827,1.,1.4,3.4151,9.8598, + &320.,2*500.,2*0.,1.26,2*1.402,2*2.372,2.56,2*5.78,6.02,7.3,1.26, + &1.282,1.42,3.5106,9.8919,320.,2*500.,2*0.,1.318,1.432,1.425, + &2*2.46,2.61,2*5.83,6.07,7.35,1.318,1.275,1.525,3.5562,9.9132, + &320.,2*500.,2*0.,2*0.4977,8*0.,3.686,3*0.,10.0233,70*0.,1.1156, + &5*0.,2.2849,0.,2.473,2.466,6*0.,5.641,0.,2*5.84,6*0.,0.9396, + &0.9383,0.,1.1974,1.1926,1.1894,1.3213,1.3149,0.,2.4525,2.4529, + &2.4527,2*2.55,2.73,4*0.,3*5.8,2*5.96,6.12,4*0.,1.234,1.233,1.232, + &1.231,1.3872,1.3837,1.3828,1.535,1.5318,1.6724,3*2.5,2*2.63,2.8, + &4*0.,3*5.81,2*5.97,6.13,114*0./ + DATA (PMAS(I,2),I= 1, 500)/22*0.,2.489,2.066,88*0.,0.0002, + &0.001,6*0.,0.149,0.0505,0.0498,7*0.,0.151,0.00843,0.0044,7*0., + &0.155,2*0.09,2*0.02,0.,4*0.05,0.155,0.36,0.08,2*0.01,5*0.,0.057, + &2*0.287,7*0.05,0.057,0.,0.25,0.014,6*0.,0.4,2*0.174,7*0.05,0.4, + &0.024,0.06,0.0009,6*0.,0.11,0.109,0.098,2*0.019,5*0.02,0.11, + &0.185,0.076,0.002,146*0.,4*0.12,0.0394,0.036,0.0358,0.0099, + &0.0091,131*0./ + DATA (PMAS(I,3),I= 1, 500)/22*0.,2*20.,88*0.,0.002,0.005,6*0., + &0.4,2*0.2,7*0.,0.4,0.1,0.015,7*0.,0.25,0.005,0.01,2*0.08,0., + &4*0.1,0.25,0.2,0.001,2*0.02,5*0.,0.05,2*0.4,6*0.1,2*0.05,0.,0.35, + &0.05,6*0.,3*0.3,2*0.1,0.03,4*0.1,0.3,0.05,0.02,0.001,6*0.,0.25, + &4*0.12,5*0.05,0.25,0.17,0.2,0.01,146*0.,4*0.14,0.04,2*0.035, + &2*0.05,131*0./ + DATA (PMAS(I,4),I= 1, 500)/12*0.,658650.,0.,0.0914,68*0.,0.1, + &0.387,15*0.,7804.,0.,3709.,0.32,0.1259,0.135,3*0.387,0.15,110*0., + &15500.,26.75,83*0.,78.88,5*0.,0.057,0.,0.025,0.09,6*0.,0.387,0., + &2*0.387,9*0.,44.3,0.,23.95,49.1,86.9,6*0.,0.13,9*0.,0.387,13*0., + &24.60001,130*0./ + DATA PARF/ + & 0.5, 0.25, 0.5, 0.25, 1., 0.5, 0., 0., 0., 0., + 1 0.5, 0., 0.5, 0., 1., 1., 0., 0., 0., 0., + 2 0.5, 0., 0.5, 0., 1., 1., 0., 0., 0., 0., + 3 0.5, 0., 0.5, 0., 1., 1., 0., 0., 0., 0., + 4 0.5, 0., 0.5, 0., 1., 1., 0., 0., 0., 0., + 5 0.5, 0., 0.5, 0., 1., 1., 0., 0., 0., 0., + 6 0.75, 0.5, 0., 0.1667, 0.0833, 0.1667, 0., 0., 0., 0., + 7 0., 0., 1., 0.3333, 0.6667, 0.3333, 0., 0., 0., 0., + 8 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 9 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + & 0.325, 0.325, 0.5, 1.6, 5.0, 0., 0., 0., 0., 0., + 1 0., 0.11, 0.16, 0.048, 0.50, 0.45, 0.55, 0.60, 0., 0., + 2 0.2, 0.1, 0., 0., 0., 0., 0., 0., 0., 0., + 3 1870*0./ + DATA ((VCKM(I,J),J=1,4),I=1,4)/ + 1 0.95113, 0.04884, 0.00003, 0.00000, + 2 0.04884, 0.94940, 0.00176, 0.00000, + 3 0.00003, 0.00176, 0.99821, 0.00000, + 4 0.00000, 0.00000, 0.00000, 1.00000/ + +C...LUDAT3, with particle decay parameters and data. + DATA (MDCY(I,1),I= 1, 500)/5*0,3*1,6*0,1,0,1,5*0,3*1,6*0,1,0,1, + &2*0,4*1,42*0,7*1,12*0,1,0,15*1,2*0,18*1,2*0,18*1,2*0,18*1,2*0, + &18*1,2*0,18*1,3*0,1,8*0,1,3*0,1,70*0,1,5*0,1,0,2*1,6*0,1,0,2*1, + &9*0,5*1,0,6*1,4*0,6*1,4*0,16*1,4*0,6*1,114*0/ + DATA (MDCY(I,2),I= 1, 500)/1,9,17,25,33,41,50,60,2*0,70,74,76, + &81,83,124,126,132,2*0,135,144,156,172,192,6*0,209,0,231,254,274, + &292,301,304,305,42*0,314,315,319,328,331,336,338,11*0,358,359, + &361,367,430,491,524,560,596,635,666,668,675,681,682,683,684,685, + &2*0,686,688,691,694,697,699,700,701,702,703,704,708,713,721,724, + &733,734,735,2*0,736,737,742,747,749,751,753,755,757,759,761,762, + &765,769,770,771,772,773,2*0,774,775,777,779,781,783,785,787,789, + &791,793,794,799,804,806,808,809,810,2*0,811,813,815,817,819,821, + &823,825,827,829,831,833,846,850,852,854,855,856,2*0,857,863,873, + &884,892,900,904,912,920,924,928,936,945,951,953,955,956,957,2*0, + &958,966,8*0,968,3*0,979,70*0,993,5*0,997,0,1073,1074,6*0,1075,0, + &1092,1093,9*0,1094,1096,1097,1100,1101,0,1103,1104,1105,1106, + &1107,1108,4*0,1109,1110,1111,1112,1113,1114,4*0,1115,1116,1119, + &1122,1123,1126,1129,1132,1134,1136,1140,1141,1142,1143,1145,1147, + &4*0,1148,1149,1150,1151,1152,1153,114*0/ + DATA (MDCY(I,3),I= 1, 500)/5*8,9,2*10,2*0,4,2,5,2,41,2,6,3,2*0, + &9,12,16,20,17,6*0,22,0,23,20,18,9,3,1,9,42*0,1,4,9,3,5,2,20,11*0, + &1,2,6,63,61,33,2*36,39,31,2,7,6,5*1,2*0,2,3*3,2,5*1,4,5,8,3,9, + &3*1,2*0,1,2*5,7*2,1,3,4,5*1,2*0,1,9*2,1,2*5,2*2,3*1,2*0,11*2,13, + &4,2*2,3*1,2*0,6,10,11,2*8,4,2*8,2*4,8,9,6,2*2,3*1,2*0,8,2,8*0,11, + &3*0,14,70*0,4,5*0,76,0,2*1,6*0,17,0,2*1,9*0,2,1,3,1,2,0,6*1,4*0, + &6*1,4*0,1,2*3,1,3*3,2*2,4,3*1,2*2,1,4*0,6*1,114*0/ + DATA (MDME(I,1),I= 1,2000)/6*1,-1,7*1,-1,7*1,-1,7*1,-1,7*1,-1, + &7*1,-1,1,-1,8*1,2*-1,8*1,2*-1,61*1,-1,2*1,-1,6*1,2*-1,7*1,2*-1, + &3*1,-1,6*1,2*-1,6*1,2*-1,3*1,-1,3*1,-1,3*1,5*-1,3*1,-1,6*1,2*-1, + &3*1,-1,11*1,2*-1,6*1,8*-1,3*1,-1,3*1,-1,3*1,5*-1,3*1,4*-1,6*1, + &2*-1,3*1,-1,5*1,-1,8*1,2*-1,3*1,-1,9*1,-1,3*1,-1,9*1,2*-1,2*1,-1, + &16*1,-1,2*1,3*-1,1665*1/ + DATA (MDME(I,2),I= 1,2000)/75*102,42,6*102,2*42,2*0,7*41,2*0, + &24*41,6*102,45,29*102,8*32,8*0,16*32,4*0,8*32,4*0,32,4*0,8*32, + &14*0,16*32,7*0,8*32,4*0,32,7*0,8*32,4*0,32,5*0,4*32,5*0,3*32,0, + &6*32,3*0,12,2*42,2*11,9*42,2*45,31,2*45,2*33,31,2*45,20*46,7*0, + &24*42,41*0,16*42,46*0,10*42,20*0,2*13,14*42,16*0,48,3*13,16*42, + &16*0,48,3*13,16*42,19*0,48,3*13,2*42,0,2*11,28*42,0,2,4*0,2,8*0, + &12,32,86,87,88,3,0,2*3,0,2*3,0,2*3,0,3,6*0,3,3*0,1,0,3,2*0,2*3, + &3*0,1,4*0,12,3*0,4*32,2*4,86,87,88,33*0,12,32,86,87,88,31*0,12,0, + &32,86,87,88,40*0,12,0,32,86,87,88,95*0,12,0,32,86,87,88,2*0,4*42, + &6*0,12,11*0,4*32,2*4,9*0,14*42,52*0,10*13,2*84,3*42,8*0,48,3*13, + &2*42,2*85,14*0,84,5*0,85,886*0/ + DATA (BRAT(I) ,I= 1, 439)/75*0.,1.,6*0.,0.179,0.178,0.116, + &0.235,0.005,0.056,0.018,0.023,0.011,2*0.004,0.0067,0.014,2*0.002, + &2*0.001,0.0022,0.054,0.002,0.016,0.005,0.011,0.0101,5*0.006, + &0.002,2*0.001,5*0.002,6*0.,1.,29*0.,0.15394,0.11936,0.15394, + &0.11926,0.15254,3*0.,0.03368,0.06664,0.03368,0.06664,0.03368, + &0.06664,2*0.,0.3214,0.0165,2*0.,0.0165,0.3207,2*0.,0.00001, + &0.00059,6*0.,3*0.1081,3*0.,0.0003,0.048,0.8705,4*0.,0.0002, + &0.0603,0.,0.0199,0.0008,3*0.,0.143,0.111,0.143,0.111,0.143,0.085, + &2*0.,0.03,0.058,0.03,0.058,0.03,0.058,8*0.,0.25,0.01,2*0.,0.01, + &0.25,4*0.,0.24,5*0.,3*0.08,6*0.,0.01,0.08,0.82,5*0.,0.09,11*0., + &0.01,0.08,0.82,5*0.,0.09,9*0.,1.,6*0.,0.01,0.98,0.01,1.,4*0.215, + &2*0.,2*0.07,0.,1.,2*0.08,0.76,0.08,2*0.105,0.04,0.5,0.08,0.14, + &0.01,0.015,0.005,1.,3*0.,1.,4*0.,1.,0.25,0.01,2*0.,0.01,0.25, + &4*0.,0.24,5*0.,3*0.08,0.,1.,2*0.5,0.635,0.212,0.056,0.017,0.048, + &0.032,0.07,0.065,2*0.005,2*0.011,5*0.001,0.07,0.065,2*0.005, + &2*0.011,5*0.001,0.026,0.019,0.066,0.041,0.045,0.076,0.0073, + &2*0.0047,0.026,0.001,0.0006,0.0066,0.005,2*0.003,2*0.0006, + &2*0.001,0.006,0.005,0.012,0.0057,0.067,0.008,0.0022,0.027,0.004, + &0.019,0.012,0.002,0.009,0.0218,0.001,0.022,0.087,0.001,0.0019, + &0.0015,0.0028,0.034,0.027,2*0.002,2*0.004,2*0.002,0.034,0.027/ + DATA (BRAT(I) ,I= 440, 655)/2*0.002,2*0.004,2*0.002,0.0365, + &0.045,0.073,0.062,3*0.021,0.0061,0.015,0.025,0.0088,0.074,0.0109, + &0.0041,0.002,0.0035,0.0011,0.001,0.0027,2*0.0016,0.0018,0.011, + &0.0063,0.0052,0.018,0.016,0.0034,0.0036,0.0009,0.0006,0.015, + &0.0923,0.018,0.022,0.0077,0.009,0.0075,0.024,0.0085,0.067,0.0511, + &0.017,0.0004,0.0028,0.01,2*0.02,0.03,2*0.005,2*0.02,0.03,2*0.005, + &0.015,0.037,0.028,0.079,0.095,0.052,0.0078,4*0.001,0.028,0.033, + &0.026,0.05,0.01,4*0.005,0.25,0.0952,0.02,0.055,2*0.005,0.008, + &0.012,0.02,0.055,2*0.005,0.008,0.012,0.01,0.03,0.0035,0.011, + &0.0055,0.0042,0.009,0.018,0.015,0.0185,0.0135,0.025,0.0004, + &0.0007,0.0008,0.0014,0.0019,0.0025,0.4291,0.08,0.07,0.02,0.015, + &0.005,0.02,0.055,2*0.005,0.008,0.012,0.02,0.055,2*0.005,0.008, + &0.012,0.01,0.03,0.0035,0.011,0.0055,0.0042,0.009,0.018,0.015, + &0.0185,0.0135,0.025,0.0004,0.0007,0.0008,0.0014,0.0019,0.0025, + &0.4291,0.08,0.07,0.02,0.015,0.005,0.02,0.055,2*0.005,0.008,0.012, + &0.02,0.055,2*0.005,0.008,0.012,0.01,0.03,0.0035,0.011,0.0055, + &0.0042,0.009,0.018,0.015,0.0185,0.0135,0.025,2*0.0002,0.0007, + &2*0.0004,0.0014,0.001,0.0009,0.0025,0.4291,0.08,0.07,0.02,0.015, + &0.005,0.047,0.122,0.006,0.012,0.035,0.012,0.035,0.003,0.007,0.15, + &0.037,0.008,0.002,0.05,0.015,0.003,0.001,0.014,0.042,0.014,0.042/ + DATA (BRAT(I) ,I= 656, 931)/0.24,0.065,0.012,0.003,0.001,0.002, + &0.001,0.002,0.014,0.003,0.988,0.012,0.389,0.319,0.2367,0.049, + &0.005,0.001,0.0003,0.441,0.206,0.3,0.03,0.022,0.001,5*1.,0.99955, + &0.00045,0.665,0.333,0.002,0.666,0.333,0.001,0.65,0.3,0.05,0.56, + &0.44,5*1.,0.99912,0.00079,0.00005,0.00004,0.888,0.085,0.021, + &2*0.003,0.49,0.344,3*0.043,0.023,0.013,0.001,0.0627,0.0597, + &0.8776,3*0.027,0.015,0.045,0.015,0.045,0.77,0.029,4*1.,0.28,0.14, + &0.313,0.157,0.11,0.28,0.14,0.313,0.157,0.11,0.667,0.333,0.667, + &0.333,2*0.5,0.667,0.333,0.667,0.333,4*0.5,1.,0.333,0.334,0.333, + &4*0.25,6*1.,0.667,0.333,0.667,0.333,0.667,0.333,0.667,0.333, + &2*0.5,0.667,0.333,0.667,0.333,4*0.5,1.,0.52,0.26,0.11,2*0.055, + &0.62,0.31,0.035,2*0.0175,0.007,0.993,0.02,0.98,3*1.,2*0.5,0.667, + &0.333,0.667,0.333,0.667,0.333,0.667,0.333,2*0.5,0.667,0.333, + &0.667,0.333,6*0.5,3*0.12,0.097,0.043,4*0.095,4*0.03,4*0.25,0.273, + &0.727,0.35,0.65,3*1.,2*0.35,0.144,0.105,0.048,0.003,0.333,0.166, + &0.168,0.084,0.087,0.043,0.059,2*0.029,0.002,0.332,0.166,0.168, + &0.084,0.086,0.043,0.059,2*0.029,2*0.002,0.3,0.15,0.16,0.08,0.13, + &0.06,0.08,0.04,0.3,0.15,0.16,0.08,0.13,0.06,0.08,0.04,2*0.3, + &2*0.2,0.3,0.15,0.16,0.08,0.13,0.06,0.08,0.04,0.3,0.15,0.16,0.08, + &0.13,0.06,0.08,0.04,2*0.3,2*0.2,2*0.3,2*0.2,2*0.35,0.144,0.105/ + DATA (BRAT(I) ,I= 932,2000)/0.024,2*0.012,0.003,0.566,0.283, + &0.069,0.028,0.023,2*0.0115,0.005,0.003,0.356,2*0.178,0.28, + &2*0.004,0.135,0.865,0.22,0.78,3*1.,0.217,0.124,2*0.193,2*0.135, + &0.002,0.001,0.686,0.314,2*0.0083,0.1866,0.324,0.184,0.027,0.001, + &0.093,0.087,0.078,0.0028,3*0.014,0.008,0.024,0.008,0.024,0.425, + &0.02,0.185,0.088,0.043,0.067,0.066,0.641,0.357,2*0.001,0.018, + &2*0.005,0.003,0.002,2*0.006,0.018,2*0.005,0.003,0.002,2*0.006, + &0.0066,0.025,0.016,0.0088,2*0.005,0.0058,0.005,0.0055,4*0.004, + &2*0.002,2*0.004,0.003,0.002,2*0.003,3*0.002,2*0.001,0.002, + &2*0.001,2*0.002,0.0013,0.0018,5*0.001,4*0.003,2*0.005,2*0.002, + &2*0.001,2*0.002,2*0.001,0.2432,0.057,2*0.035,0.15,2*0.075,0.03, + &2*0.015,2*1.,2*0.105,0.04,0.0077,0.02,0.0235,0.0285,0.0435, + &0.0011,0.0022,0.0044,0.4291,0.08,0.07,0.02,0.015,0.005,2*1., + &0.999,0.001,1.,0.516,0.483,0.001,1.,0.995,0.005,13*1.,0.331, + &0.663,0.006,0.663,0.331,0.006,1.,0.88,2*0.06,0.88,2*0.06,0.88, + &2*0.06,0.667,2*0.333,0.667,0.676,0.234,0.085,0.005,3*1.,4*0.5, + &7*1.,847*0./ + DATA (KFDP(I,1),I= 1, 507)/21,22,23,4*-24,25,21,22,23,4*24,25, + &21,22,23,4*-24,25,21,22,23,4*24,25,21,22,23,4*-24,25,21,22,23, + &4*24,25,37,21,22,23,4*-24,25,2*-37,21,22,23,4*24,25,2*37,22,23, + &-24,25,23,24,-12,22,23,-24,25,23,24,-12,-14,35*16,22,23,-24,25, + &23,24,-89,22,23,-24,25,-37,23,24,37,1,2,3,4,5,6,7,8,21,1,2,3,4,5, + &6,7,8,11,13,15,17,1,2,3,4,5,6,7,8,11,12,13,14,15,16,17,18,4*-1, + &4*-3,4*-5,4*-7,-11,-13,-15,-17,1,2,3,4,5,6,7,8,11,13,15,17,21, + &2*22,23,24,1,2,3,4,5,6,7,8,11,12,13,14,15,16,17,18,24,37,2*23,25, + &35,4*-1,4*-3,4*-5,4*-7,-11,-13,-15,-17,3*24,1,2,3,4,5,6,7,8,11, + &13,15,17,21,2*22,23,24,23,25,36,1,2,3,4,5,6,7,8,11,13,15,17,21, + &2*22,23,24,23,-1,-3,-5,-7,-11,-13,-15,-17,24,5,6,21,2,1,2,3,4,5, + &6,11,13,15,82,-11,-13,2*2,-12,-14,-16,2*-2,2*-4,-2,-4,2*89,37, + &2*-89,2*5,-37,2*89,4*-1,4*-3,4*-5,4*-7,-11,-13,-15,-17,-13,130, + &310,-13,3*211,12,14,11*-11,11*-13,-311,-313,-311,-313,-20313, + &2*-311,-313,-311,-313,2*111,2*221,2*331,2*113,2*223,2*333,-311, + &-313,2*-321,211,-311,-321,333,-311,-313,-321,211,2*-321,2*-311, + &-321,211,113,8*-11,8*-13,-321,-323,-321,-323,-311,2*-313,-311, + &-313,2*-311,-321,-10323,-321,-323,-321,-311,2*-313,211,111,333, + &3*-321,-311,-313,-321,-313,310,333,211,2*-321,-311,-313,-311,211, + &-321,3*-311,211,113,321,-15,5*-11,5*-13,221,331,333,221,331,333/ + DATA (KFDP(I,1),I= 508, 924)/10221,211,213,211,213,321,323,321, + &323,2212,221,331,333,221,2*2,6*12,6*14,2*16,3*-411,3*-413,2*-411, + &2*-413,2*441,2*443,2*20443,2*2,2*4,2,4,6*12,6*14,2*16,3*-421, + &3*-423,2*-421,2*-423,2*441,2*443,2*20443,2*2,2*4,2,4,6*12,6*14, + &2*16,3*-431,3*-433,2*-431,2*-433,3*441,3*443,3*20443,2*2,2*4,2,4, + &16,2*4,2*12,2*14,2*16,4*2,4*4,2*-11,2*-13,2*-1,2*-3,2*-11,2*-13, + &2*-1,3*22,111,211,2*22,211,22,211,111,3*22,111,82,21,3*0,2*211, + &321,3*311,2*321,421,2*411,2*421,431,511,521,531,541,211,111,13, + &11,211,22,211,2*111,321,130,-213,113,213,211,22,111,11,13,82,11, + &13,15,1,2,3,4,21,22,3*0,223,321,311,323,313,2*311,321,313,323, + &321,423,2*413,2*423,413,523,2*513,2*523,2*513,523,223,213,113, + &-213,313,-313,323,-323,82,21,3*0,221,321,2*311,321,421,2*411,421, + &411,421,521,2*511,2*521,2*511,521,221,211,111,321,130,310,211, + &111,321,130,310,443,82,553,21,3*0,113,213,323,2*313,323,423, + &2*413,2*423,413,523,2*513,2*523,2*513,523,213,-213,10211,10111, + &-10211,2*221,213,2*113,-213,2*321,2*311,313,-313,323,-323,443,82, + &553,21,3*0,213,113,221,223,321,211,321,311,323,313,323,313,321, + &4*311,321,313,323,313,323,311,4*321,421,411,423,413,423,413,421, + &2*411,421,413,423,413,423,411,2*421,411,423,413,521,511,523,513, + &523,513,521,2*511,521,513,523,513,523,511,2*521,511,523,513,511/ + DATA (KFDP(I,1),I= 925,2000)/521,513,523,213,-213,221,223,321, + &130,310,111,211,111,2*211,321,130,310,221,111,321,130,310,221, + &211,111,443,82,553,21,3*0,111,211,-12,12,-14,14,211,111,211,111, + &11,13,82,4*443,10441,20443,445,441,11,13,15,1,2,3,4,21,22,2*553, + &10551,20553,555,2212,2*2112,-12,7*-11,7*-13,2*2224,2*2212,2*2214, + &2*3122,2*3212,2*3214,5*3222,4*3224,2*3322,3324,2*2224,7*2212, + &5*2214,2*2112,2*2114,2*3122,2*3212,2*3214,2*3222,2*3224,4*2,3, + &2*2,1,2*2,2*0,-12,-14,-16,5*4122,441,443,20443,2*-2,2*-4,-2,-4, + &2*0,2112,-12,3122,2212,2112,2212,3*3122,3*4122,4132,4232,0, + &3*5122,5132,5232,0,2112,2212,2*2112,2212,2112,2*2212,3122,3212, + &3112,3122,3222,3112,3122,3222,3212,3322,3312,3322,3312,3122,3322, + &3312,-12,3*4122,2*4132,2*4232,4332,3*5122,5132,5232,5332,847*0/ + DATA (KFDP(I,2),I= 1, 476)/3*1,2,4,6,8,1,3*2,1,3,5,7,2,3*3,2,4, + &6,8,3,3*4,1,3,5,7,4,3*5,2,4,6,8,5,3*6,1,3,5,7,6,5,3*7,2,4,6,8,7, + &4,6,3*8,1,3,5,7,8,5,7,2*11,12,11,12,2*11,2*13,14,13,14,13,11,13, + &-211,-213,-211,-213,-211,-213,3*-211,-321,-323,-321,-323,3*-321, + &4*-211,-213,-211,-213,-211,-213,-211,-213,-211,-213,6*-211,2*15, + &16,15,16,15,18,2*17,18,17,2*18,2*17,-1,-2,-3,-4,-5,-6,-7,-8,21, + &-1,-2,-3,-4,-5,-6,-7,-8,-11,-13,-15,-17,-1,-2,-3,-4,-5,-6,-7,-8, + &-11,-12,-13,-14,-15,-16,-17,-18,2,4,6,8,2,4,6,8,2,4,6,8,2,4,6,8, + &12,14,16,18,-1,-2,-3,-4,-5,-6,-7,-8,-11,-13,-15,-17,21,22,2*23, + &-24,-1,-2,-3,-4,-5,-6,-7,-8,-11,-12,-13,-14,-15,-16,-17,-18,-24, + &-37,22,25,2*36,2,4,6,8,2,4,6,8,2,4,6,8,2,4,6,8,12,14,16,18,23,22, + &25,-1,-2,-3,-4,-5,-6,-7,-8,-11,-13,-15,-17,21,22,2*23,-24,2*25, + &36,-1,-2,-3,-4,-5,-6,-7,-8,-11,-13,-15,-17,21,22,2*23,-24,25,2,4, + &6,8,12,14,16,18,25,-5,-6,21,11,-3,-4,-5,-6,-7,-8,-13,-15,-17,-82, + &12,14,-1,-3,11,13,15,1,4,3,4,1,3,5,3,5,6,4,21,22,4,7,5,2,4,6,8,2, + &4,6,8,2,4,6,8,2,4,6,8,12,14,16,18,14,2*0,14,111,211,111,-11,-13, + &11*12,11*14,2*211,2*213,211,20213,2*321,2*323,211,213,211,213, + &211,213,211,213,211,213,211,213,3*211,213,211,2*321,8*211,2*113, + &2*211,8*12,8*14,2*211,2*213,2*111,221,2*113,223,333,20213,211, + &2*321,323,2*311,313,-211,111,113,2*211,321,2*211,311,321,310,211/ + DATA (KFDP(I,2),I= 477, 857)/-211,4*211,321,4*211,113,2*211,-321, + &16,5*12,5*14,3*211,3*213,211,2*111,2*113,2*-311,2*-313,-2112, + &3*321,323,2*-1,6*-11,6*-13,2*-15,211,213,20213,211,213,20213,431, + &433,431,433,311,313,311,313,311,313,-1,-4,-3,-4,-1,-3,6*-11, + &6*-13,2*-15,211,213,20213,211,213,20213,431,433,431,433,321,323, + &321,323,321,323,-1,-4,-3,-4,-1,-3,6*-11,6*-13,2*-15,211,213, + &20213,211,213,20213,431,433,431,433,221,331,333,221,331,333,221, + &331,333,-1,-4,-3,-4,-1,-3,-15,-3,-1,2*-11,2*-13,2*-15,-1,-4,-3, + &-4,-3,-4,-1,-4,2*12,2*14,2,3,2,3,2*12,2*14,2,1,22,11,22,111,-211, + &211,11,-211,13,-211,111,113,223,22,111,-82,21,3*0,111,22,-211, + &111,22,211,111,22,211,111,22,111,6*22,-211,22,-13,-11,-211,111, + &-211,2*111,-321,310,211,111,2*-211,221,22,-11,-13,-82,-11,-13, + &-15,-1,-2,-3,-4,2*21,3*0,211,-213,113,-211,111,223,213,113,211, + &111,223,211,111,-211,111,321,311,-211,111,211,111,-321,-311,411, + &421,111,-211,111,211,-311,311,-321,321,-82,21,3*0,211,-211,111, + &211,111,211,111,-211,111,311,321,-211,111,211,111,-321,-311,411, + &421,111,-211,111,-321,130,310,-211,111,-321,130,310,22,-82,22,21, + &3*0,211,111,-211,111,211,111,211,111,-211,111,321,311,-211,111, + &211,111,-321,-311,411,421,-211,211,-211,111,2*211,111,-211,211, + &111,211,-321,2*-311,-321,-311,311,-321,321,22,-82,22,21,3*0,111/ + DATA (KFDP(I,2),I= 858,2000)/3*211,-311,22,-211,111,-211,111, + &-211,211,-213,113,223,221,211,111,211,111,2*211,213,113,223,221, + &22,211,111,211,111,4*211,-211,111,-211,111,-211,211,-211,211,321, + &311,321,311,-211,111,-211,111,-211,211,-211,2*211,111,211,111, + &4*211,-321,-311,-321,-311,411,421,411,421,-211,211,111,211,-321, + &130,310,22,-211,111,2*-211,-321,130,310,221,111,-321,130,310,221, + &-211,111,22,-82,22,21,3*0,111,-211,11,-11,13,-13,-211,111,-211, + &111,-11,-13,-82,211,111,221,111,4*22,-11,-13,-15,-1,-2,-3,-4, + &2*21,211,111,3*22,-211,111,22,11,7*12,7*14,-321,-323,-311,-313, + &-311,-313,211,213,211,213,211,213,111,221,331,113,223,111,221, + &113,223,321,323,321,-211,-213,111,221,331,113,223,333,10221,111, + &221,331,113,223,211,213,211,213,321,323,321,323,321,323,311,313, + &311,313,2*-1,-3,-1,2203,3201,3203,2203,2101,2103,2*0,11,13,15, + &-211,-213,-20213,-431,-433,3*3122,1,4,3,4,1,3,2*0,-211,11,22,111, + &211,22,-211,111,22,-211,111,211,2*22,0,-211,111,211,2*22,0, + &2*-211,111,22,111,211,22,211,2*-211,2*111,-211,2*211,111,211, + &-211,2*111,211,-321,-211,111,11,-211,111,211,111,22,111,2*22, + &-211,111,211,3*22,847*0/ + DATA (KFDP(I,3),I= 1, 944)/75*0,14,6*0,2*16,2*0,5*111,310,130, + &2*0,2*111,310,130,321,113,211,223,221,2*113,2*211,2*223,2*221, + &2*113,221,113,2*213,-213,195*0,4*3,4*4,1,4,3,2*2,10*81,25*0,-211, + &3*111,-311,-313,-311,-321,-313,-323,111,221,331,113,223,-311, + &-313,-311,-321,-313,-323,111,221,331,113,223,22*0,111,113,2*211, + &-211,-311,211,111,3*211,-211,7*211,-321,-323,-311,-321,-313,-323, + &-211,-213,-321,-323,-311,-321,-313,-323,-211,-213,22*0,111,113, + &-311,2*-211,211,-211,310,-211,2*111,211,2*-211,-321,-211,2*211, + &-211,111,-211,2*211,0,221,331,333,321,311,221,331,333,321,311, + &20*0,3,0,-411,-413,-10413,-10411,-20413,-415,-411,-413,-10413, + &-10411,-20413,-415,-411,-413,16*0,-4,-1,-4,-3,2*-2,-421,-423, + &-10423,-10421,-20423,-425,-421,-423,-10423,-10421,-20423,-425, + &-421,-423,16*0,-4,-1,-4,-3,2*-2,-431,-433,-10433,-10431,-20433, + &-435,-431,-433,-10433,-10431,-20433,-435,-431,-433,19*0,-4,-1,-4, + &-3,2*-2,3*0,441,443,441,443,441,443,-4,-1,-4,-3,-4,-3,-4,-1,531, + &533,531,533,3,2,3,2,511,513,511,513,1,2,0,-11,0,2*111,-211,-11, + &11,-13,2*221,3*0,111,27*0,111,2*0,22,111,5*0,111,12*0,2*21,103*0, + &-211,2*111,-211,3*111,-211,111,211,14*0,111,6*0,111,-211,8*0,111, + &-211,9*0,111,-211,111,-211,4*0,111,-211,111,-211,8*0,111,-211, + &111,-211,4*0,111,-211,111,-211,11*0,-211,6*0,111,211,4*0,111/ + DATA (KFDP(I,3),I= 945,2000)/13*0,2*111,211,-211,211,-211,7*0, + &-211,111,13*0,2*21,-211,111,6*0,2212,3122,3212,3214,2112,2114, + &2212,2112,3122,3212,3214,2112,2114,2212,2112,52*0,3*3,1,8*0, + &3*4122,8*0,4,1,4,3,2*2,3*0,2112,43*0,3322,861*0/ + DATA (KFDP(I,4),I= 1,2000)/88*0,3*111,8*0,-211,0,-211,3*0,111, + &2*-211,0,111,0,2*111,113,221,111,-213,-211,211,195*0,13*81,41*0, + &111,211,111,211,7*0,111,211,111,211,35*0,2*-211,2*111,211,111, + &-211,2*211,2*-211,2*0,-211,111,-211,111,4*0,-211,111,-211,111, + &34*0,111,-211,3*111,3*-211,2*111,3*-211,4*0,-321,-311,3*0,-321, + &-311,20*0,-3,31*0,6*1,30*0,6*2,33*0,6*3,9*0,8*4,4*0,4*-5,4*0, + &2*-5,7*0,-11,264*0,111,-211,4*0,111,57*0,-211,111,5*0,-211,111, + &52*0,2101,2103,2*2101,19*0,6*2101,909*0/ + DATA (KFDP(I,5),I= 1,2000)/90*0,111,16*0,111,7*0,111,0,2*111, + &303*0,-211,2*111,-211,111,-211,111,54*0,111,-211,3*111,-211,111, + &1510*0/ + +C...LUDAT4, with character strings. + DATA (CHAF(I) ,I= 1, 281)/'d','u','s','c','b','t','l','h', + &2*' ','e','nu_e','mu','nu_mu','tau','nu_tau','chi','nu_chi', + &2*' ','g','gamma','Z','W','H',2*' ','reggeon','pomeron',2*' ', + &'Z''','Z"','W''','H''','A','H','eta_tech','LQ_ue','R',40*' ', + &'specflav','rndmflav','phasespa','c-hadron','b-hadron', + &'t-hadron','l-hadron','h-hadron','Wvirt','diquark','cluster', + &'string','indep.','CMshower','SPHEaxis','THRUaxis','CLUSjet', + &'CELLjet','table',' ','pi',2*'K',2*'D','D_s',2*'B','B_s','B_c', + &'pi','eta','eta''','eta_c','eta_b','eta_t','eta_l','eta_h',2*' ', + &'rho',2*'K*',2*'D*','D*_s',2*'B*','B*_s','B*_c','rho','omega', + &'phi','J/psi','Upsilon','Theta','Theta_l','Theta_h',2*' ','b_1', + &2*'K_1',2*'D_1','D_1s',2*'B_1','B_1s','B_1c','b_1','h_1','h''_1', + &'h_1c','h_1b','h_1t','h_1l','h_1h',2*' ','a_0',2*'K*_0',2*'D*_0', + &'D*_0s',2*'B*_0','B*_0s','B*_0c','a_0','f_0','f''_0','chi_0c', + &'chi_0b','chi_0t','chi_0l','chi_0h',2*' ','a_1',2*'K*_1', + &2*'D*_1','D*_1s',2*'B*_1','B*_1s','B*_1c','a_1','f_1','f''_1', + &'chi_1c','chi_1b','chi_1t','chi_1l','chi_1h',2*' ','a_2', + &2*'K*_2',2*'D*_2','D*_2s',2*'B*_2','B*_2s','B*_2c','a_2','f_2', + &'f''_2','chi_2c','chi_2b','chi_2t','chi_2l','chi_2h',2*' ','K_L', + &'K_S',8*' ','psi''',3*' ','Upsilon''',45*' ','pi_diffr'/ + DATA (CHAF(I) ,I= 282, 500)/'n_diffr','p_diffr','rho_diff', + &'omega_di','phi_diff','J/psi_di',18*' ','Lambda',5*' ', + &'Lambda_c',' ',2*'Xi_c',6*' ','Lambda_b',' ',2*'Xi_b',6*' ','n', + &'p',' ',3*'Sigma',2*'Xi',' ',3*'Sigma_c',2*'Xi''_c','Omega_c', + &4*' ',3*'Sigma_b',2*'Xi''_b','Omega_b',4*' ',4*'Delta', + &3*'Sigma*',2*'Xi*','Omega',3*'Sigma*_c',2*'Xi*_c','Omega*_c', + &4*' ',3*'Sigma*_b',2*'Xi*_b','Omega*_b',114*' '/ + +C...LUDATR, with initial values for the random number generator. + DATA MRLU/19780503,0,0,97,33,0/ + + END + +C********************************************************************* + +CDECK ID>, LUTAUD + SUBROUTINE LUTAUD(ITAU,IORIG,KFORIG,NDECAY) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + +C...Dummy routine, to be replaced by user, to handle the decay of a +C...polarized tau lepton. +C...Input: +C...ITAU is the position where the decaying tau is stored in /LUJETS/. +C...IORIG is the position where the mother of the tau is stored; +C... is 0 when the mother is not stored. +C...KFORIG is the flavour of the mother of the tau; +C... is 0 when the mother is not known. +C...Note that IORIG=0 does not necessarily imply KFORIG=0; +C... e.g. in B hadron semileptonic decays the W propagator +C... is not explicitly stored but the W code is still unambiguous. +C...Output: +C...NDECAY is the number of decay products in the current tau decay. +C...These decay products should be added to the /LUJETS/ common block, +C...in positions N+1 through N+NDECAY. For each product I you must +C...give the flavour codes K(I,2) and the five-momenta P(I,1), P(I,2), +C...P(I,3), P(I,4) and P(I,5). The rest will be stored automatically. + + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N + COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) + SAVE /LUJETS/,/LUDAT1/ + +C...Stop program if this routine is ever called. +C...You should not copy these lines to your own routine. + NDECAY=ITAU+IORIG+KFORIG + WRITE(MSTU(11),5000) + IF(RLU(0).LT.10.) STOP + +C...Format for error printout. + 5000 FORMAT(1X,'Error: you did not link your LUTAUD routine ', + &'correctly.'/1X,'Dummy routine in JETSET file called instead.'/ + &1X,'Execution stopped!') + + + RETURN + END + + DOUBLE PRECISION FUNCTION RNDM(IDUMMY) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) +C...Generator from the LUND montecarlo +C...Purpose: to generate random numbers uniformly distributed between +C...0 and 1, excluding the endpoints. + COMMON/LUDATR/MRLU(6),RRLU(100) + EQUIVALENCE (MRLU1,MRLU(1)),(MRLU2,MRLU(2)),(MRLU3,MRLU(3)), + &(MRLU4,MRLU(4)),(MRLU5,MRLU(5)),(MRLU6,MRLU(6)), + &(RRLU98,RRLU(98)),(RRLU99,RRLU(99)),(RRLU00,RRLU(100)) + SAVE + +C...Initialize generation from given seed. + IF(MRLU2.EQ.0) THEN + IF (MRLU1 .EQ. 0) MRLU1 = 19780503 ! initial seed + IJ=MOD(MRLU1/30082,31329) + KL=MOD(MRLU1,30082) + I=MOD(IJ/177,177)+2 + J=MOD(IJ,177)+2 + K=MOD(KL/169,178)+1 + L=MOD(KL,169) + DO 110 II=1,97 + S=0. + T=0.5 + DO 100 JJ=1,24 + M=MOD(MOD(I*J,179)*K,179) + I=J + J=K + K=M + L=MOD(53*L+1,169) + IF(MOD(L*M,64).GE.32) S=S+T + T=0.5*T + 100 CONTINUE + RRLU(II)=S + 110 CONTINUE + TWOM24=1. + DO 120 I24=1,24 + TWOM24=0.5*TWOM24 + 120 CONTINUE + RRLU98=362436.*TWOM24 + RRLU99=7654321.*TWOM24 + RRLU00=16777213.*TWOM24 + MRLU2=1 + MRLU3=0 + MRLU4=97 + MRLU5=33 + ENDIF + +C...Generate next random number. + 130 RUNI=RRLU(MRLU4)-RRLU(MRLU5) + IF(RUNI.LT.0.) RUNI=RUNI+1. + RRLU(MRLU4)=RUNI + MRLU4=MRLU4-1 + IF(MRLU4.EQ.0) MRLU4=97 + MRLU5=MRLU5-1 + IF(MRLU5.EQ.0) MRLU5=97 + RRLU98=RRLU98-RRLU99 + IF(RRLU98.LT.0.) RRLU98=RRLU98+RRLU00 + RUNI=RUNI-RRLU98 + IF(RUNI.LT.0.) RUNI=RUNI+1. + IF(RUNI.LE.0.OR.RUNI.GE.1.) GOTO 130 + +C...Update counters. Random number to output. + MRLU3=MRLU3+1 + IF(MRLU3.EQ.1000000000) THEN + MRLU2=MRLU2+1 + MRLU3=0 + ENDIF +C RLU=RUNI + RNDM=RUNI + RETURN + END +c***************************************************************************** +c**!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*** +c**!! IF YOU USE THIS PROGRAM, PLEASE CITE: !!*** +c**!! A.M"ucke, Ralph Engel, J.P.Rachen, R.J.Protheroe and Todor Stanev, !!*** +c**!! 1999, astro-ph/9903478, to appear in Comp.Phys.Commun. !!*** +c**!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*** +c***************************************************************************** +c** Further SOPHIA related papers: *** +c** (1) M"ucke A., et al 1999, astro-ph/9808279, to appear in PASA. *** +c** (2) M"ucke A., et al 1999, to appear in: Proc. of the *** +c** 19th Texas Symposium on Relativistic Astrophysics, Paris, France, *** +c** Dec. 1998. Eds.: J.~Paul, T.~Montmerle \& E.~Aubourg (CEA Saclay) *** +c** (3) M"ucke A., et al 1999, astro-ph/9905153, to appear in: Proc. of *** +c** 19th Texas Symposium on Relativistic Astrophysics, Paris, France, *** +c** Dec. 1998. Eds.: J.~Paul, T.~Montmerle \& E.~Aubourg (CEA Saclay) *** +c** (4) M"ucke A., et al 1999, to appear in: Proc. of 26th Int.Cosmic Ray *** +c** Conf. (Salt Lake City, Utah) *** +c***************************************************************************** + + +c********************************************** +c** Routines/functions related to sampling *** +c** photon energy and squared CMF energy: *** +c********************************************** + + + + subroutine sample_s(s,eps) + +c*********************************************************************** +c samples distribution of s: p(s) = (s-mp^2)sigma_Ngamma +c rejection for s=[sth,s0], analyt.inversion for s=[s0,smax] +c*********************************************************************** +c** Date: 20/01/98 ** +c** author: A.Muecke ** +c********************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + SAVE + + common/input/ tbb,E0,alpha1,alpha2, + & epsm1,epsm2,epsb,L0 + COMMON /S_MASS1/ AM(49), AM2(49) + + external functs,gauss,rndm + double precision functs,gauss,rndm + +c*** calculate smin,smax : ************************ + xmpi = AM(7) + xmp = AM(L0) + Pp = sqrt(E0*E0-xmp*xmp) + smin = 1.1646D0 + smax = max(smin,xmp*xmp+2.D0*eps*(E0+Pp)) + if ((smax-smin).le.1.D-8) then + s = smin+rndm(0)*1.d-6 + RETURN + endif + s0 = 10.D0 +c*** determine which method applies: rejection or analyt.inversion: ** + sintegr1 = gauss(functs,smin,s0) + sintegr2 = gauss(functs,s0,smax) + if (smax.le.s0) then +c rejection method: + nmethod=1 + goto 41 + endif + r1 = rndm(0) + quo = sintegr1/(sintegr1+sintegr2) + if (r1.le.quo) then +c rejection method: + nmethod=1 + else +c analyt. inversion: + nmethod=2 + endif + + 41 continue + + +c*** rejection method: ************************ + if (nmethod.eq.1) then + i_rept = 0 + 10 continue +c*** sample s random between smin ... s0 ** + if (i_rept.ge.100000) RETURN !LM + r2 = rndm(0) + s = smin+r2*(smax-smin) +c*** calculate p(s) = pes ********************** + ps = functs(s) +c*** rejection method to sample s ********************* + r3 = rndm(1) +c pmax is roughly p(s) at s=s0 + pmax = 1300.D0/sintegr1 + i_rept = i_rept+1 + if (r3*pmax.le.ps/sintegr1) then + RETURN + else + goto 10 + endif + endif + +c*** analyt. inversion method: ******************* + if (nmethod.eq.2) then + r4 = rndm(0) + beta = 2.04D0 + betai = 1.D0/beta + term1 = r4*(smax**beta) + term2 = (r4-1.D0)*(s0**beta) + s = (term1-term2)**betai + RETURN + endif + + RETURN + END + + + subroutine sample_ir_eps(eps,epsmin,epsmax) + +c**************************************************************************** +c samples distribution of n(epsilon)/epsilon^2 for ir background using +c rejection technique +c**************************************************************************** +c** Date: Aug '05 ** +c** author: G.Sigl ** +c********************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + SAVE + + common/input/ tbb,E0,alpha1,alpha2, + & epsm1,epsm2,epsb,L0 + common/PLindex/ alphaxx + COMMON /S_MASS1/ AM(49), AM2(49) + + external photd_ir,rndm + double precision prob_epskt,prob_epspl,rndm,gauss + double precision functs,probint_pl + + xmpi = AM(7) + xmp = AM(L0) + Pp = sqrt(E0*E0-xmp*xmp) + epsm1 = max(epsmin,1.D9*(1.1646D0-xmp*xmp)/2.D0/(E0+Pp)) + + if (epsmax.gt.epsm1) then + i_max=idint(10.d0*dlog(epsmax/epsm1))+1 + de=dlog(epsmax/epsm1)/dble(i_max) + rmax=0.d0 + do i=0,i_max + eps_dum=epsm1*dexp(dble(i)*de) + dum=eps_dum**2*PHOTD_IR(eps_dum) + if (dum.gt.rmax) rmax=dum + enddo + beta=4.d0 + e1=epsm1**(1.d0-beta) + e2=epsmax**(1.d0-beta) + i_try=1 + i_rep = 0 + do while(i_try.eq.1) + if (i_rep.ge.100000) then + i_try = 0 + result = 0. + endif + r1 = rndm(0) + result=(r1*(e1-e2)+e2)**(1.d0/(1.d0-beta)) + r1 = rndm(1) + i_rep = i_rep + 1 + if (r1.lt.result**2*PHOTD_IR(result)/rmax) i_try=0 + enddo + else + result=0. + endif + eps=result + RETURN + END + + subroutine sample_eps(eps,epsmin,epsmax) + +c**************************************************************************** +c samples distribution of epsilon p(epsilon) for blackbody spectrum if tbb>0 +c and power law \sim eps^-alpha, epsm1 [eV] < eps [eV] < epsm2 [eV], +c eps in LAB frame if tbb \leq 0 +c**************************************************************************** +c** Date: 20/01/98 ** +c** author: A.Muecke ** +c********************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + SAVE + + common/input/ tbb,E0,alpha1,alpha2, + & epsm1,epsm2,epsb,L0 + common/PLindex/ alphaxx + COMMON /S_MASS1/ AM(49), AM2(49) + + external prob_epskt,prob_epspl,rndm,gauss,functs,probint_pl + double precision prob_epskt,prob_epspl,rndm,gauss + double precision functs,probint_pl + + xmpi = AM(7) + xmp = AM(L0) + gammap = E0/xmp + betap = sqrt(1.-1./gammap/gammap) + Pp = sqrt(E0*E0-xmp*xmp) + 1 continue + facpmax = 1.6D0 +c*** for tbb<=0: power law photon spectrum n(eps) ~ eps^-alpha ********* + if (tbb.gt.0.D0) then + epsm1 = (1.1646D0-xmp*xmp)/2.D0/(E0+Pp) + epsm1 = epsm1*1.D9 + epsm2 = 0.007D0*tbb + epskt = 8.619D-5*tbb + epspmax = (3.D-3*((E0*epskt*1.D-9)**(-0.97D0)) + & +0.047D0)/3.9D2*tbb + if (epsm1.gt.epsm2) then + print*, + & 'CMF energy is below threshold for nucleon energy ' + & ,E0,' GeV !' + eps = 0.D0 + RETURN + endif + cnorm = gauss(prob_epskt,epsm1,epsm2) + pmaxc = prob_epskt(epspmax)/cnorm + pmax = facpmax*pmaxc + + else +c*** determine distribution: + epsth = (1.1646D0-xmp*xmp)/2.D0/(E0+Pp) + epsth = epsth*1.D9 + epsm1 = max(epsmin,epsth) + epsm2 = epsmax + if (epsm1.ge.epsm2) then + eps = 0. + RETURN + endif + endif + + epsmx1 = epsm1 + epsmx2 = epsm2 + epsbx = epsb + epsdelta = 0.159368/E0*1.d9 + epsxx = 126.D0/E0*1.d9 + alpha12 = alpha2-alpha1 + a1 = 1.D0 + 10 continue +c*** sample eps randomly between epsmin ... epsmax ** + r1 = rndm(0) +c*** calculate p(eps) = peps *************************************** + if (tbb.le.0.D0) then + rn = rndm(0) +c******************************************************************* +c... sample from straight power law (alpha = alpha2, epsb < epsm1): + if (alpha12.eq.0.D0.or.epsm1.ge.epsb) then + if (epsxx.ge.epsm2) then + alphaxx = alpha2 + else if (epsxx.le.epsm1) then + alphaxx = (alpha2+2.D0) + else if (epsm1.lt.epsxx.and.epsxx.lt.epsm2) then + a2 = epxx*epsxx + alphaxx = alpha2 + pintegr1 = a1*probint_pl(epsm1,epsxx,alphaxx) + alphaxx = (alpha2+2.D0) + pintegr2 = a2*probint_pl(epsxx,epsm2,alphaxx) + pintegr1 = pintegr1/(pintegr1+pintegr2) + if (rn.lt.pintegr1) then + alphaxx = alpha2 + epsm2 = epsxx + ampl = a1 + else if (pintegr1.le.rn.and.rn.lt.1.D0) then + alphaxx = alpha2+2.D0 + epsm1 = epsxx + ampl = a2 + endif + endif + endif +c... sample from broken power law: input always epsm1 < epsb < epsm2 + if (epsm1.lt.epsb) then +c... determine where epsb,epsxx lies: + if (epsm1.lt.epsxx.and.epsxx.lt.epsb) then + a2 = epxx*epsxx + a3 = a2*(epsb**(alpha2-alpha1)) + alphaxx = alpha1 + pintegr1 = a1*probint_pl(epsm1,epsxx,alphaxx) + alphaxx = (alpha1+2.D0) + pintegr2 = a2*probint_pl(epsxx,epsb,alphaxx) + alphaxx = (alpha2+2.D0) + pintegr3 = a3*probint_pl(epsb,epsm2,alphaxx) + pintegr1 = pintegr1/(pintegr1+pintegr2+pintegr3) + pintegr2 = (pintegr1+pintegr2)/(pintegr1+pintegr2+pintegr3) + pintegr3 = 1.D0 + if (rn.lt.pintegr1) then + alphaxx = alpha1 + epsm2 = epsxx + ampl = a1 + else if (pintegr1.le.rn.and.rn.lt.pintegr2) then + alphaxx = alpha1+2.D0 + epsm1 = epsxx + epsm2 = epsb + ampl = a2 + else if (pintegr2.le.rn.and.rn.le.pintegr3) then + alphaxx = alpha2+2.D0 + epsm1 = epsb + ampl = a3 + else + print*,'error in sampling broken power law: SAMPLE_EPS (1)!' + STOP + endif + + else if (epsb.le.epsxx.and.epsxx.lt.epsm2) then + a2 = epsb**(alpha2-alpha1) + a3 = a2*epsxx*epsxx + alphaxx = alpha1 + pintegr1 = a1*probint_pl(epsm1,epsb,alphaxx) + alphaxx = alpha2 + pintegr2 = a2*probint_pl(epsb,epsxx,alphaxx) + alphaxx = (alpha2+2.D0) + pintegr3 = a3*probint_pl(epsxx,epsm2,alphaxx) + pintegr1 = pintegr1/(pintegr1+pintegr2+pintegr3) + pintegr2 = (pintegr1+pintegr2)/(pintegr1+pintegr2+pintegr3) + pintegr3 = 1.D0 + if (rn.lt.pintegr1) then + alphaxx = alpha1 + epsm2 = epsb + ampl = a1 + else if (pintegr1.le.rn.and.rn.lt.pintegr2) then + alphaxx = alpha2 + epsm1 = epsb + epsm2 = epsxx + ampl = a2 + else if (pintegr2.le.rn.and.rn.le.pintegr3) then + alphaxx = alpha2+2.D0 + epsm1 = epsxx + ampl = a3 + else + print*,'error in sampling broken power law: SAMPLE_EPS (2)!' + STOP + endif + + else if (epsxx.ge.epsm2) then + a2 = epsb**(alpha2-alpha1) + a3 = 0.D0 + alphaxx = alpha1 + pintegr1 = a1*probint_pl(epsm1,epsb,alphaxx) + alphaxx = alpha2 + pintegr2 = a2*probint_pl(epsb,epsm2,alphaxx) + pintegr1 = pintegr1/(pintegr1+pintegr2) + pintegr2 = 1.D0 + if (rn.lt.pintegr1) then + alphaxx = alpha1 + epsm2 = epsb + ampl = a1 + else if (pintegr1.le.rn.and.rn.le.pintegr2) then + alphaxx = alpha2 + epsm1 = epsb + ampl = a2 + else + print*,'error in sampling broken power law: SAMPLE_EPS (3)!' + STOP + endif + + else if (epsxx.le.epsm1) then + a2 = epsb**(alpha2-alpha1) + a3 = 0.D0 + alphaxx = (alpha1+2.D0) + pintegr1 = a1*probint_pl(epsm1,epsb,alphaxx) + alphaxx = (alpha2+2.D0) + pintegr2 = a2*probint_pl(epsb,epsm2,alphaxx) + pintegr1 = pintegr1/(pintegr1+pintegr2) + pintegr2 = 1.D0 + if (rn.lt.pintegr1) then + alphaxx = alpha1+2.D0 + epsm2 = epsb + ampl = a1 + else if (pintegr1.le.rn.and.rn.le.pintegr2) then + alphaxx = alpha2+2.D0 + epsm1 = epsb + ampl = a2 + else + print*,'error in sampling broken power law: SAMPLE_EPS (4)!' + STOP + endif + + endif +cxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +c... END: sample from broken power law: + endif +c***************************************************** + if (alphaxx.eq.1.D0) then + term1 = r1*log(epsm2/epsm1) + eps = epsm1*exp(term1) + else + beta = 1.D0-alphaxx + betai = 1.D0/beta + term1 = r1*(epsm2**beta) + term2 = (r1-1.D0)*(epsm1**beta) + eps = (term1-term2)**betai + endif + + +c****************************************************** +c*** for thermal spectrum: *** + else + eps = epsm1+r1*(epsm2-epsm1) + peps = prob_epskt(eps)/cnorm +c endif +c*** rejection method to sample eps ********************* + r2 = rndm(0) + if (r2*pmax.gt.peps) then + goto 10 + endif + + endif + + epsm1 = epsmx1 + epsm2 = epsmx2 + epsb = epsbx + +c... check maximum of epsilon distribution: + if (pmax.lt.peps) then + facpmax = facpmax + 0.1D0 + goto 1 + endif + + RETURN + END + + + DOUBLE PRECISION function prob_epskt(eps) + +c*** calculates probability distribution for thermal photon field *** +c*** with temerature tbb (in K), eps (in eV) ************* +c** Date: 20/01/98 ** +c** author: A.Muecke ** +c********************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + SAVE + + common/input/ tbb,E0,alpha1,alpha2, + & epsm1,epsm2,epsb,L0 + + external functs,photd,gauss + double precision functs,photd,gauss + + xmpi = 0.135D0 + xmp = 0.93827D0 + Pp = sqrt(E0*E0-xmp*xmp) + gammap = E0/xmp + betap = sqrt(1.D0-1.D0/gammap/gammap) + deps = photd(eps,tbb) + if (deps.eq.0.D0) then + prob_epskt = 0.D0 + RETURN + else +c*** calculate \int_sth^smax ds (s-mp^2) sigma_pg ******* +c*** smin is for head-on collision ********************** + smin = 1.1646D0 + smax = max(smin,xmp*xmp+2.D0*eps/1.D9*E0*(1.D0+betap)) + sintegr = gauss(functs,smin,smax) + + prob_epskt = deps/eps/eps*sintegr/ + & 8.D0/betap/E0/E0*1.D18*1.D6 + endif + + RETURN + + END + + DOUBLE PRECISION function prob_epspl(eps) + +c*** calculates probability distribution for power law photon field *** +c*** n = anorm*eps^-alpha, eps=[epsm1,epsm2], eps in eV ************* +c** Date: 20/01/98 ** +c** author: A.Muecke ** +c********************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + SAVE + + common/input/ tbb,E0,alpha1,alpha2, + & epsm1,epsm2,epsb,L0 + + external functs,gauss + double precision functs,gauss + + xmpi = 0.135D0 + xmp = 0.93827D0 + Pp = sqrt(E0*E0-xmp*xmp) + gammap = E0/xmp + betap = sqrt(1.D0-1.D0/gammap/gammap) + alpha12 = alpha2-alpha1 + ampl = epsb**alpha12 + if (eps.lt.epsb) then + deps = eps**(-alpha1) + else + deps = ampl*(eps**(-alpha2)) + endif + +c*** calculate \int_sth^smax ds (s-mp^2) sigma_pg ******* +c*** smin is for head-on collision ********************** + smin = 1.1646D0 + smax = max(smin,xmp*xmp+2.D0*eps/1.D9*(E0+Pp)) + + sintegr = gauss(functs,smin,smax) + + prob_epspl = deps/eps/eps*sintegr/ + & 8.D0/betap/E0/E0*1.D18*1.D6 + + RETURN + + END + + DOUBLE PRECISION function probint_pl(epsi,epsf,p) + +c*** returns \int_epsi^epsf eps^-p ************** +c*** calling program is SAMPLE_EPS **************** +c** Date: 03/03/99 ** +c** author: A.Muecke ** +c********************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + SAVE + + if (p.eq.1.D0) then + probint_pl = log(epsf/epsi) + else + p1 = 1.D0-p + probint_pl = ((epsf**p1)-(epsi**p1))/p1 + endif + + RETURN + + END + + + DOUBLE PRECISION function functs(s) + +c*** returns (s-pm^2)*sigma_Ngamma ************** +c*** calling program is SAMPLE_S **************** +c** Date: 20/01/98 ** +c** author: A.Muecke ** +c********************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + SAVE + + common/input/ tbb,E0,alpha1,alpha2, + & epsm1,epsm2,epsb,L0 + + external crossection + double precision crossection + + + pm = 0.93827D0 + factor = (s-pm*pm) + epsprime = factor/2.D0/pm + sigma_pg = crossection(epsprime,3,L0) + functs = factor*sigma_pg + + RETURN + + END + + DOUBLE PRECISION FUNCTION PHOTD(EPS,TBB) +C ************************************************************** +C RETURNS THE DENSITY OF BLACKBODY RADIATION OF TEMPERATURE * +C "TBB" DEGREES (DENS1). EPS IN eV, PHOTD IN #/(cm^3.eV) * +C TSS, May '92 * +C ************************************************************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + SAVE +C CONVERT TEMPERATURE TO eV + EPH = EPS + EKT = 8.619D-5*TBB + EPHKT = EPS/EKT + IF (EPHKT .GT. 80.D0) GO TO 10 + IF (EPHKT .LT. 1.D-4) GO TO 11 + FEE = DEXP(EPHKT) - 1.D0 + GO TO 12 + 11 FEE = EPHKT + 12 BB = 1.318D13*EPH*EPH/FEE + GO TO 15 + 10 BB = 0.D0 + 15 PHOTD = BB + END + + DOUBLE PRECISION FUNCTION PHOTD_IR(EPS) +C ************************************************************** +C RETURNS THE DENSITY OF IR background at redshift Z* +C EPS IN eV, PHOTD_IR IN #/(cm^3.eV) * +C G.Sigl, Aug '05 * +C At the moment, redshift is a dummy variable within the program +C IR background from Primack et al. (1999) +C ************************************************************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + SAVE +c NN put the following line up from some line below (f77 error) + COMMON /REDSHIFT/ Z,ZMAX_IR + PARAMETER (FLUX_CONVERSION = 3.82182d3) + + DIMENSION XData(15), YData(15) + DATA (XData(I),I=1,15)/ -1., -0.75, -0.5, -0.25, 0., +c COMMON /REDSHIFT/ Z,ZMAX_IR + & 0.25, 0.5, 0.75, 1., 1.25, 1.5, 1.75, 2., 2.25, 2.5/ +c DATA (YData(I),I=1,15)/ 0.8, 1.1, 1.15, 1.2, 1.3, +c & 1.2, 1.05, 0.7, 0.4, 0.3, 0.5, 0.8, 1.1, 1.3, 1./ +c Kneiske background + DATA (YData(I),I=1,15)/-0.214401, 0.349313, 0.720354, 0.890389, + & 1.16042, 1.24692, 1.06525, 0.668659, 0.536312, 0.595859, + & 0.457456, 0.623521, 1.20208, 1.33657, 1.04461/ +c Redshift evolution as for CMB. (added Dec.'05) +c conversion from nW/cm^3/sr to eV/cm^3 +c FLUX_CONVERSION = +c & 2.9979e10/4./dacos(-1.d0)*1.602e-19*1.e9*1.e4 +c PARAMETER (FLUX_CONVERSION = 3.82182d3) + +c print*,Z + +c conversion from eV to micrometers + X = 1.2398d0*(1.+Z)/EPS + if (X.gt.500.) then + RESULT=0. + else + if (dlog10(X).ge.XData(15)) then + RESULT = (YData(15) - YData(14))/(XData(15) - XData(14))* + & (dlog10(X) - XData(14)) + YData(14) + RESULT = 10.d0**RESULT + endif + endif + if (dlog10(X).le.XData(1)) RESULT=0. + if ((dlog10(X).lt.XData(15)).and.(dlog10(X).gt.XData(1))) then + INDEX = 2 + do while (XData(INDEX).lt.dlog10(X)) + INDEX = INDEX+1 + enddo + RESULT = (YData(INDEX) - YData(INDEX-1))/ + & (XData(INDEX) - XData(INDEX-1))*(dlog10(X) - XData(INDEX-1))+ + & YData(INDEX-1) + RESULT = 10.d0**RESULT + endif + PHOTD_IR = RESULT*(1.+Z)**2/(EPS/(1.+Z))**2/FLUX_CONVERSION + + if (Z.gt.ZMAX_IR) then + PHOTD_IR = 0.d0 + endif + + RETURN + END + + DOUBLE PRECISION function plinterpol(alpha) + +c*** interpolates p(Ep) to give the max. probability p(eps) for *** +c*** a given initial proton energy *** +c** Date: 20/01/98 ** +c** author: A.Muecke ** +c********************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + SAVE + + DIMENSION AINDEX(4), A(4) + DATA A / 0.D0,1.D0,2.D0,3.D0/ + DATA AINDEX / 8.D8,5.D8,5.D8,1.D9/ + + plinterpol = 0.D0 + + do 1 ni=1,3 + p1 = A(ni) + p2 = A(ni+1) + if (alpha.le.p2.and.alpha.gt.p1) then + tang = (log10(AINDEX(ni+1))-log10(AINDEX(ni)))/(p2-p1) + plinterpol = log10(AINDEX(ni))+(alpha-p1)*tang + plinterpol = 10.D0**plinterpol + endif + 1 continue + + if (alpha.eq.0.D0) plinterpol = 5.D8 + + if (plinterpol.eq.0.D0) then + print*,'interpolation not sucessful !' + pause + endif + + END + + DOUBLE PRECISION function f_epspl(eps) + +c*** gives energy density law of power law photon field *** +c*** f(epsilon) = eps^-alpha, eps=[epsm1,epsm2], eps in eV ************* +c** Date: 14/03/99 ** +c** author: A.Muecke ** +c********************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + SAVE + + common/input/ tbb,E0,alpha1,alpha2, + & epsm1,epsm2,epsb,L0 + + + alpha12 = alpha2-alpha1 + ampl = epsb**alpha12 + if (eps.lt.epsb) then + f_epspl = eps*(eps**(-alpha1)) + else + f_epspl = eps*ampl*(eps**(-alpha2)) + endif + + RETURN + + END + + + + +C ************************************************************** +C integrand for Total_rate_ir +C G.Sigl, Aug '05 * +C ************************************************************** + DOUBLE PRECISION function functs_int_ir(eps_ln) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + SAVE + common/input/ tbb,E0,alpha1,alpha2, + & epsm1,epsm2,epsb,L0 + COMMON /S_MASS1/ AM(49), AM2(49) + COMMON /REDSHIFT/ Z,ZMAX_IR + external functs,gauss + + eps=dexp(eps_ln) + xmpi = AM(7) + xmp = AM(L0) + Pp = sqrt(E0*E0-xmp*xmp) + smin = 1.1646D0 + smax = xmp*xmp+2.D0*eps*1.d-9*(E0+Pp) + s0 = 10.D0 + if (smax.lt.smin) result=0.d0 + if (smax.gt.smin) then + if (smax.le.s0) result=gauss(functs,smin,smax) + if (smax.gt.s0) result=gauss(functs,smin,s0)+ + & gauss(functs,s0,smax) + endif + functs_int_ir=photd_ir(eps)/eps*result + RETURN + END + +C ************************************************************** +C RETURNS interaction rate with IRB in Mpc^-1 +C G.Sigl, Aug '05 * +C ************************************************************** + DOUBLE PRECISION function Total_rate_ir(epsmin,epsmax) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + SAVE + common/input/ tbb,E0,alpha1,alpha2, + & epsm1,epsm2,epsb,L0 + COMMON /S_MASS1/ AM(49), AM2(49) + COMMON /REDSHIFT/ Z,ZMAX_IR + external functs_int_ir,gauss + + pm = 0.93827D0 + xmpi = AM(7) + xmp = AM(L0) + Pp = sqrt(E0*E0-xmp*xmp) + epsm1 = max(epsmin,1.D9*(1.1646D0-xmp*xmp)/2.D0/(E0+Pp)) + if (epsmax.gt.epsm1) then + result=2.d0*xmp*gauss(functs_int_ir,dlog(epsm1),dlog(epsmax)) + else + result=0.d0 + endif + Total_rate_ir=1.d18/8.d0/E0/Pp*result*1.d-30*3.0856d24 + + RETURN + END + +C ************************************************************** +C integrand for Total_rate_cmb +C G.Sigl, Aug '05 * +C ************************************************************** + DOUBLE PRECISION function functs_int_cmb(eps_ln) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + SAVE + common/input/ tbb,E0,alpha1,alpha2, + & epsm1,epsm2,epsb,L0 + COMMON /S_MASS1/ AM(49), AM2(49) + COMMON /REDSHIFT/ Z,ZMAX_IR + external functs,gauss + + eps=dexp(eps_ln) + xmpi = AM(7) + xmp = AM(L0) + Pp = sqrt(E0*E0-xmp*xmp) + smin = 1.1646D0 + smax = xmp*xmp+2.D0*eps*1.d-9*(E0+Pp) + s0 = 10.D0 + if (smax.lt.smin) result=0.d0 + if (smax.gt.smin) then + if (smax.le.s0) result=gauss(functs,smin,smax) + if (smax.gt.s0) result=gauss(functs,smin,s0)+ + & gauss(functs,s0,smax) + endif + functs_int_cmb=photd(eps,(1.d0+Z)*2.75)/eps*result + RETURN + END + +C ************************************************************** +C RETURNS total interaction rate with CMB in Mpc^-1 +C G.Sigl, Aug '05 * +C ************************************************************** + DOUBLE PRECISION function Total_rate_cmb(epsmin,epsmax) + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + SAVE + common/input/ tbb,E0,alpha1,alpha2, + & epsm1,epsm2,epsb,L0 + COMMON /S_MASS1/ AM(49), AM2(49) + COMMON /REDSHIFT/ Z,ZMAX_IR + external functs_int_cmb,gauss + + pm = 0.93827D0 + xmpi = AM(7) + xmp = AM(L0) + Pp = sqrt(E0*E0-xmp*xmp) + epsm1 = max(epsmin,1.D9*(1.1646D0-xmp*xmp)/2.D0/(E0+Pp)) + if (epsmax.gt.epsm1) then + result=2.d0*xmp*gauss(functs_int_cmb,dlog(epsm1),dlog(epsmax)) + else + result=0.d0 + endif + Total_rate_cmb=1.d18/8.d0/E0/Pp*result*1.d-30*3.0856d24 + + RETURN + END +c**************************************************************************** +c +c SOPHIAEVENT +c +c interface between Sophia and CRPropa +c simulate an interaction between p/n of given energy and the CMB +c +c Eric Armengaud, 2005 +c******************************* +c add Sept 2005 : redshift effect and interactions on IRB (from Primack 1999) +c**************************************************************************** + +c subroutine sophiaevent(nature,Ein,OutPart,OutPartType,NbOutPart, +c & z_particle,bgFlag,Zmax_IRB) + +c********************************** +c nature, Ein = input nature and energy of the nucleon +c nature = 0 -> p ; 1 -> n +c Ein : in GeV (SOPHIA standard energy unit) +c OutPart,OutPartType,NbOutPart = output data: +c P(2000,5) list of 4-momenta + masses of output particles +c LList(2000) list of output particle IDs +c NP nb of output particles +c Added Sept. 2005 : +c z_particle : needed to estimate the CMB temperature (no redshift +c evolution of IRB at the moment) +c bgFlag = 1 for CMB, 2 for Primack et al. (1999) IRB +c Added Dec. 2005 : +c zmax : now there is a "standard" IRB evolution which requires to +c know the redshift and z_max of the irb. +c********************************** + +c IMPLICIT DOUBLE PRECISION (A-H,O-Z) +c IMPLICIT INTEGER (I-N) +c SAVE + +c COMMON/input/ tbb,E0,alpha1,alpha2, +c & epsm1,epsm2,epsb,L0cc + +c COMMON /REDSHIFT/ Z, ZMAX_IR + +c COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb +c COMMON /S_MASS1/ AM(49), AM2(49) +c COMMON /S_CHP/ S_LIFE(49), ICHP(49), ISTR(49), IBAR(49) +c COMMON /S_CSYDEC/ CBR(102), IDB(49), KDEC(612), LBARP(49) +c +c CHARACTER*6 NAMPRES +c COMMON /RES_PROP/ AMRES(9), SIG0(9),WIDTH(9), +c + NAMPRES(0:9) + +c CHARACTER*6 NAMPRESp +c COMMON /RES_PROPp/ AMRESp(9), BGAMMAp(9),WIDTHp(9), +c + RATIOJp(9),NAMPRESp(0:9) + +c CHARACTER*6 NAMPRESn +c COMMON /RES_PROPn/ AMRESn(9), BGAMMAn(9),WIDTHn(9), +c + RATIOJn(9),NAMPRESn(0:9) + + +c external sample_eps,sample_s,eventgen,initial,prob_epskt, +c & sample_ir_eps + +c integer nature +c integer bgFlag +c double precision Ein +c double precision z_particle +c double precision OutPart(2000,5) +c integer OutPartType(2000) +c integer NbOutPart + +c double precision epsmin,epsmax + +c DATA pi /3.141593D0/ + +c if (nature.eq.0) then +c L0=13 +c else if (nature.eq.1) then +c L0=14 +c else +c print*,'sophiaevent: incoming particle incorrectly specified' +c stop +c endif + +c$$$ call initial(L0) +c$$$ E0 = Ein +c$$$ pm = AM(L0) +c$$$ +c$$$ tbb=2.73*(1.D0+z_particle) +c$$$ Z = z_particle +c$$$ ZMAX_IR = Zmax_IRB +c$$$ +c$$$ if (bgFlag.eq.1) then +c$$$ epsmin = 0. +c$$$ epsmax = 0. +c$$$ call sample_eps(epseV,epsmin,epsmax) +c$$$ else if (bgFlag.eq.2) then +c$$$c Choice for epsmin/epsmax : the Primack data is for -1 p ; 1 -> n +c Ein : in GeV (SOPHIA standard energy unit) +c OutPart,OutPartType,NbOutPart = output data: +c P(2000,5) list of 4-momenta + masses of output particles +c LList(2000) list of output particle IDs +c NP nb of output particles +c Added Sept. 2005 : +c z_particle : needed to estimate the CMB temperature (no redshift +c evolution of IRB at the moment) +c bgFlag = 1 for CMB, 2 for Primack et al. (1999) IRB +c Added Dec. 2005 : +c zmax : now there is a "standard" IRB evolution which requires to +c know the redshift and z_max of the irb. +c********************************** + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + SAVE + + COMMON/input/ tbb,E0,alpha1,alpha2, + & epsm1,epsm2,epsb,L0 + + COMMON /REDSHIFT/ Z, ZMAX_IR + + COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb + COMMON /S_MASS1/ AM(49), AM2(49) + COMMON /S_CHP/ S_LIFE(49), ICHP(49), ISTR(49), IBAR(49) + COMMON /S_CSYDEC/ CBR(102), IDB(49), KDEC(612), LBARP(49) + + CHARACTER*6 NAMPRES + COMMON /RES_PROP/ AMRES(9), SIG0(9),WIDTH(9), + + NAMPRES(0:9) + + CHARACTER*6 NAMPRESp + COMMON /RES_PROPp/ AMRESp(9), BGAMMAp(9),WIDTHp(9), + + RATIOJp(9),NAMPRESp(0:9) + + CHARACTER*6 NAMPRESn + COMMON /RES_PROPn/ AMRESn(9), BGAMMAn(9),WIDTHn(9), + + RATIOJn(9),NAMPRESn(0:9) + + + external sample_eps,sample_s,eventgen,initial,prob_epskt, + & sample_ir_eps + + integer nature + integer bgFlag + double precision Ein,Pp + double precision z_particle + double precision OutPart(2000,5) + integer OutPartType(2000) + integer NbOutPart + + double precision epsmin,epsmax + + DATA pi /3.141593D0/ + + +cc 15.09.2009 + integer idatamax + double precision en_data(idatamax),flux_data(idatamax) ! eV, eV/cm3 +cc + if (nature.eq.0) then + L0=13 + else if (nature.eq.1) then + L0=14 + else + print*,'sophiaevent: incoming particle incorrectly specified' + stop + endif + + call initial(L0) + + E0 = Ein + pm = AM(L0) + + tbb=2.73*(1.D0+z_particle) + Z = z_particle + ZMAX_IR = Zmax_IRB + +* check +c return +*** + if (bgFlag.eq.1) then + epsmin = 0. + epsmax = 0. + call sample_eps(epseV,epsmin,epsmax) + else if (bgFlag.eq.2) then +c Choice for epsmin/epsmax : the Primack data is for -1 calculation of alpha + e2prob_max = -1d100 + do i = 1,idatamax + eps = en_data(i) ! eV + prob_ir(i) = prob_eps_ir(eps + $ ,idatamax,en_data,flux_data) + + + if(eps**2*prob_ir(i) .gt. e2prob_max) then + eps_max = eps + e2prob_max = eps**2*prob_ir(i) + endif + enddo + alpha = e2prob_max + +c loop -> acceptance-rejection method, comparison function alpha*E^(-2) + do + r1 = rndm(0) + + eps = 1.d0/epsm1 - r1*(1.d0/epsm1 - 1.d0/epsmax) + eps = 1.d0/eps + + f_comp = factor*alpha*eps**(-2.d0) + + r2 = rndm(1) + Prob = divdif(prob_ir,en_data,idatamax,eps,1) + + if(Prob .gt. f_comp*r2) exit + enddo + endif + +*** check +c write(14,*)eps,Prob,f_comp +* 5 format(5E16.6) +*** + + + return + end + + +c.... + + double precision function prob_eps_ir(eps + $ ,idatamax,en_data,flux_data) ! eps (eV) + implicit none + + integer L0 + double precision tbb,E0,alpha1,alpha2,epsm1,epsm2,epsb,am + $ ,am2 + + common/input/ tbb,E0,alpha1,alpha2, + & epsm1,epsm2,epsb,L0 + COMMON /S_MASS1/ AM(49), AM2(49) + + external functs,photd,gauss + double precision functs,photd,gauss + + external n_ir + double precision n_ir + + double precision xmpi,xmp,Pp,gammap,betap,deps,eps + double precision smin,smax,sintegr + +c + integer idatamax + double precision en_data(idatamax),flux_data(idatamax) ! eV, eV/cm3 +c + + xmpi = 0.135D0 + xmp = am(l0) + Pp = sqrt(E0*E0-xmp*xmp) + gammap = E0/xmp + betap = sqrt(1.D0-1.D0/gammap/gammap) + deps = n_ir(eps,idatamax,en_data,flux_data) ! n_photon(eps) 1/(cm^3 eV) + + if (deps.eq.0.D0) then + prob_eps_ir = 0.D0 + RETURN + else +c*** calculate \int_sth^smax ds (s-mp^2) sigma_pg ******* +c*** smin is for head-on collision ********************** + smin = (xmpi+xmp)**2 ! GeV^2 + +c isotropy + smax = xmp*xmp+2.D0*eps/1.D9*E0*(1.D0+betap) + + endif + + + if(smax .gt. smin)then +c isotropy + sintegr = gauss(functs,smin,smax) ! GeV^4 microbn + + prob_eps_ir = deps/eps/eps*sintegr/ + & 8.D0/betap/E0/E0*1.D-12 ! 1/(cm^3 eV)*1/eV^2*GeV^4*microbn/GeV^2 -> 1/(cm*eV) + + else + prob_eps_ir = 0.d0 + endif + + return + end + + +c........ + + double precision function n_ir(eps,idatamax,en_data,flux_data)! 1/(eV cm3) + implicit none + + integer idatairmax + integer idatamax + double precision en_data(idatamax),flux_data(idatamax) ! eV, eV/cm3 + + double precision eps + external divdif + double precision divdif + + n_ir = divdif(flux_data,en_data,idatamax,eps,1) ! eV/cm^3 + n_ir = n_ir/eps**2 + + if(n_ir .lt. 0.d0)n_ir = 0.d0 + + return + end + + +c.............................................................................. +c Performs polynomial interpolation. The first term F(NN) contains the values. +c of the function to interpolate, A(NN) contains the corresponding x-values, . +c x is the point at which we want to evaluate the function and the last +c parameter MM corresponds to the order of the polynomial +c interpolation 1 p ; 14 -> n +c Ein : in GeV (SOPHIA standard energy unit) +c Nsec_arg : flag to request the total cross section +c crosssection : output. Total cross section (mub) +c********************************** + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + SAVE + + COMMON/input/ tbb,E0,alpha1,alpha2, + & epsm1,epsm2,epsb,L0 + + COMMON /REDSHIFT/ Z, ZMAX_IR + + COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb + COMMON /S_MASS1/ AM(49), AM2(49) + COMMON /S_CHP/ S_LIFE(49), ICHP(49), ISTR(49), IBAR(49) + COMMON /S_CSYDEC/ CBR(102), IDB(49), KDEC(612), LBARP(49) + + CHARACTER*6 NAMPRES + COMMON /RES_PROP/ AMRES(9), SIG0(9),WIDTH(9), + + NAMPRES(0:9) + + CHARACTER*6 NAMPRESp + COMMON /RES_PROPp/ AMRESp(9), BGAMMAp(9),WIDTHp(9), + + RATIOJp(9),NAMPRESp(0:9) + + CHARACTER*6 NAMPRESn + COMMON /RES_PROPn/ AMRESn(9), BGAMMAn(9),WIDTHn(9), + + RATIOJn(9),NAMPRESn(0:9) + + + external sample_eps,sample_s,eventgen,initial,prob_epskt, + & sample_ir_eps, crossection + + integer Npartid + integer Nsec_arg + double precision Ein + double precision crosssection + double precision epsprime + + DATA pi /3.141593D0/ + + L0=Npartid + + call initial(L0) + + E0 = Ein + pm = AM(L0) + tbb=2.73*(1.D0) + Z = 0 + + ZMAX_IR = 0 + + crosssection = crossection(epsprime, Nsec_arg, Npartid) + return + END diff --git a/python/mpc.i b/python/mpc.i index 84ecbc647..5387fef76 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -12,8 +12,6 @@ %include stdint.i %include std_container.i -// Handle standard exceptions. -// NOTE: needs to be before the %import! %include "exception.i" %exception { @@ -34,6 +32,7 @@ #include "mpc/module/ElectronPairProduction.h" #include "mpc/module/PhotoDisintegration.h" #include "mpc/module/PhotoPionProduction.h" +#include "mpc/module/SophiaPhotoPionProduction.h" #include "mpc/module/Redshift.h" #include "mpc/module/BreakCondition.h" #include "mpc/module/Output.h" @@ -106,6 +105,7 @@ %include "mpc/module/NuclearDecay.h" %include "mpc/module/ElectronPairProduction.h" %include "mpc/module/PhotoPionProduction.h" +%include "mpc/module/SophiaPhotoPionProduction.h" %include "mpc/module/PhotoDisintegration.h" %include "mpc/module/Redshift.h" %include "mpc/module/GlutDisplay.h" diff --git a/src/module/SophiaPhotoPionProduction.cpp b/src/module/SophiaPhotoPionProduction.cpp new file mode 100644 index 000000000..2cf387653 --- /dev/null +++ b/src/module/SophiaPhotoPionProduction.cpp @@ -0,0 +1,231 @@ +#include "mpc/module/SophiaPhotoPionProduction.h" + +#include "sophia.h" + +#include +#include +#include +#include +#include + +namespace mpc { + +SophiaPhotoPionProduction::SophiaPhotoPionProduction(PhotonField photonField) { + init(photonField); +} + +SophiaPhotoPionProduction::SophiaPhotoPionProduction() { + init(CMB); +} + +void SophiaPhotoPionProduction::init(PhotonField field) { + name = "mpc::PhotoPionProduction"; + + photonField = field; + switch (photonField) { + case CMB: + init(getDataPath("PhotoPionProduction/cmb.txt")); + break; + case IR: + init(getDataPath("PhotoPionProduction/ir.txt")); + break; + } +} + +void SophiaPhotoPionProduction::init(std::string filename) { + std::ifstream infile(filename.c_str()); + if (!infile.good()) + throw std::runtime_error(name + ": could not open file " + filename); + + std::vector x, yp, yn; + x.reserve(100); + yp.reserve(100); + yn.reserve(100); + while (infile.good()) { + if (infile.peek() != '#') { + double a, b, c; + infile >> a >> b >> c; + if (infile) { + x.push_back(a * EeV); // energy in [EeV] + yp.push_back(b / Mpc); // rate in [1/Mpc] + yn.push_back(c / Mpc); // rate in [1/Mpc] + } + } + infile.ignore(std::numeric_limits::max(), '\n'); + } + + infile.close(); + + acc = gsl_interp_accel_alloc(); + pRate = gsl_spline_alloc(gsl_interp_linear, x.size()); + nRate = gsl_spline_alloc(gsl_interp_linear, x.size()); + gsl_spline_init(pRate, &x[0], &yp[0], x.size()); + gsl_spline_init(nRate, &x[0], &yn[0], x.size()); + Emin = x.front(); + Emax = x.back(); +} + +SophiaPhotoPionProduction::~SophiaPhotoPionProduction() { + gsl_spline_free(pRate); + gsl_spline_free(nRate); + gsl_interp_accel_free(acc); +} + +std::string SophiaPhotoPionProduction::getDescription() const { + switch (photonField) { + case CMB: { + return "Photo-pion production on CMB using SOPHIA"; + break; + } + case IR: { + return "Photo-pion production on IR using SOPHIA"; + break; + } + default: { + return "Photo-pion production using SOPHIA (unknown)"; + break; + } + } +} + +void SophiaPhotoPionProduction::process(Candidate *candidate) const { + double step = candidate->getCurrentStep(); + InteractionState interaction; + + while (true) { + // check if interaction is set + bool noState = !candidate->getInteractionState(name, interaction); + if (noState) { + // try to set a new interaction + bool noInteraction = !setNextInteraction(candidate); + if (noInteraction) + return; + // get the new interaction + candidate->getInteractionState(name, interaction); + } + + // if not over, reduce distance and return + if (interaction.distance > step) { + interaction.distance -= step; + candidate->limitNextStep(interaction.distance); + candidate->setInteractionState(name, interaction); + return; + } + + // counter over: interact + step -= interaction.distance; + performInteraction(candidate); + } +} + +bool SophiaPhotoPionProduction::setNextInteraction(Candidate *candidate) const { + double z = candidate->getRedshift(); + double E = candidate->current.getEnergy(); + int A = candidate->current.getMassNumber(); + int Z = candidate->current.getChargeNumber(); + int N = A - Z; + double EpA = E / A * (1 + z); // CMB energies increase with (1+z)^3 + + // check if out of energy range + if ((EpA < Emin) or (EpA > Emax)) + return false; + + // find interaction with minimum random distance + // check for interaction on protons + InteractionState interaction; + interaction.distance = std::numeric_limits::max(); + Random &random = Random::instance(); + if (Z > 0) { + double rate = gsl_spline_eval(pRate, EpA, acc) * Z; + if (rate != 0) { + interaction.distance = -log(random.rand()) / rate; + interaction.channel = 1; + } + } + // check for interaction on neutrons + if (N > 0) { + double rate = gsl_spline_eval(nRate, EpA, acc) * N; + if (rate != 0) { + double d = -log(random.rand()) / rate; + if (d < interaction.distance) { + interaction.distance = -log(random.rand()) / rate; + interaction.channel = 0; + } + } + } + + // CMB density increases with (1+z)^3 -> free distance decreases accordingly + interaction.distance /= pow((1 + z), 3); + + if (isnan(interaction.distance)) { + return false; + } + + candidate->setInteractionState(name, interaction); + return true; +} + +void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { + InteractionState interaction; + candidate->getInteractionState(name, interaction); + candidate->clearInteractionStates(); + + int dZ = interaction.channel; // charge number loss of interacting nucleus + + double E = candidate->current.getEnergy(); + int A = candidate->current.getMassNumber(); + int Z = candidate->current.getChargeNumber(); + double EpA = E / A; + + // arguments for sophia + int nature = 1 - dZ; // interacting particle: 0 for proton, 1 for neutron + double Ein = EpA / GeV; // energy of in-going nucleon in GeV + double momentaList[5][2000]; // momentum list, what are the five components? + int particleList[2000]; // particle id list + int nParticles; // number of outgoing particles + double redshift = candidate->getRedshift(); + int background = photonField + 1; // Photon background: 1 for CMB, 2 for Primack IR + double maxRedshift = 100; // IR photon density is zero above this redshift + int IRNE = 2; // ??? + double dummy[2]; // ??? + + sophiaevent_(nature, Ein, momentaList, particleList, nParticles, redshift, + background, maxRedshift, IRNE, dummy, dummy); + + for (int i = 0; i < nParticles; i++) { // loop over out-going particles + double Eout = momentaList[3][i] * GeV; // only the energy is used; could be changed for more realism + int pType = particleList[i]; +// 13 proton +// 14 neutron +// -13 antiproton +// -14 antineutron +// 1 photon +// 2 e+ +// 3 e- +// 15 nu_e +// 16 antinu_e +// 17 nu_muon +// 18 antinu_muon + + if (pType == 13 or pType == 14) { + int Zout = 14 - pType; // 1 for proton, 0 for neutron + if (A == 1) { // in-going particle was a nucleon: update its properties + candidate->current.setEnergy(Eout); + candidate->current.setId(getNucleusId(1, Zout)); + } else { + // // in-going particle was a nucleus: update nucleus and emit nucleon + candidate->current.setEnergy(E - Eout); + candidate->current.setId(getNucleusId(A - 1, Z - dZ)); + candidate->addSecondary(getNucleusId(1, Zout), Eout); + } + } else if (pType == -13 or pType == -14) { + continue; // anti-proton/neutron annihilate quickly -> new electromagnetic cascade? + } else if (pType >= 1 and pType <= 3) { + continue; // new electromagnetic cascade + } else if (pType >= 15) { + continue; // new neutrino + } + } +} + +} // namespace mpc From c6d4c2aafadac4286be52101a62fc81651252a59 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 17 Apr 2012 08:50:49 +0200 Subject: [PATCH 0058/1298] refactored stochastic interactions --- CMakeLists.txt | 4 +- include/mpc/Common.h | 7 + include/mpc/Module.h | 3 +- include/mpc/magneticField/magneticFieldGrid.h | 8 +- include/mpc/magneticField/magneticFieldRing.h | 48 ---- include/mpc/module/ElectronPairProduction.h | 19 +- include/mpc/module/NuclearDecay.h | 11 +- include/mpc/module/PhotoDisintegration.h | 5 +- include/mpc/module/PhotoPionProduction.h | 37 +-- .../mpc/module/SophiaPhotoPionProduction.h | 46 ---- include/mpc/module/StochasticInteraction.h | 25 ++ libs/sophia/sophia.h | 55 ++--- mpi/Slave.cpp | 5 +- python/mpc.i | 9 +- src/IO.cpp | 2 - src/main.cpp | 4 +- src/module/ElectronPairProduction.cpp | 6 +- src/module/NuclearDecay.cpp | 38 +-- src/module/PhotoDisintegration.cpp | 35 +-- src/module/PhotoPionProduction.cpp | 202 --------------- src/module/SophiaPhotoPionProduction.cpp | 231 ------------------ src/module/StochasticInteraction.cpp | 39 +++ src/openmp.cpp | 4 +- test/testInteraction.cpp | 36 ++- 24 files changed, 168 insertions(+), 711 deletions(-) delete mode 100644 include/mpc/magneticField/magneticFieldRing.h delete mode 100644 include/mpc/module/SophiaPhotoPionProduction.h create mode 100644 include/mpc/module/StochasticInteraction.h delete mode 100644 src/module/PhotoPionProduction.cpp delete mode 100644 src/module/SophiaPhotoPionProduction.cpp create mode 100644 src/module/StochasticInteraction.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fada992a..471469de4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,10 +99,10 @@ add_library(mpc SHARED src/module/SimplePropagation.cpp src/module/DeflectionCK.cpp src/module/ElectronPairProduction.cpp + src/module/StochasticInteraction.cpp + src/module/NuclearDecay.cpp src/module/PhotoPionProduction.cpp - src/module/SophiaPhotoPionProduction.cpp src/module/PhotoDisintegration.cpp - src/module/NuclearDecay.cpp src/module/Redshift.cpp src/module/Output.cpp src/module/Tools.cpp diff --git a/include/mpc/Common.h b/include/mpc/Common.h index 9d049c1ea..a6075cd2c 100644 --- a/include/mpc/Common.h +++ b/include/mpc/Common.h @@ -5,12 +5,19 @@ namespace mpc { +// Returns the full path to a mpc data file std::string getDataPath(std::string filename); +// Returns a certain digit from a given integer inline int digit(const int &value, const int &d) { return (value % (d * 10)) / d; } +// Photon fields +enum PhotonField { + CMB, IR, CMBIR +}; + } // namespace mpc #endif /* COMMON_H_ */ diff --git a/include/mpc/Module.h b/include/mpc/Module.h index b8a298d11..381f53782 100644 --- a/include/mpc/Module.h +++ b/include/mpc/Module.h @@ -3,6 +3,7 @@ #include "mpc/Candidate.h" #include "mpc/Referenced.h" +#include "mpc/Common.h" #include @@ -27,7 +28,7 @@ class Module: public Referenced { virtual void process(Candidate *candidate) const = 0; - void process(ref_ptr &candidate) const { + inline void process(ref_ptr candidate) const { process(candidate.get()); } }; diff --git a/include/mpc/magneticField/magneticFieldGrid.h b/include/mpc/magneticField/magneticFieldGrid.h index 1536d8131..16fb2ddee 100644 --- a/include/mpc/magneticField/magneticFieldGrid.h +++ b/include/mpc/magneticField/magneticFieldGrid.h @@ -11,10 +11,10 @@ namespace mpc { @class MagneticFieldGrid @brief Cubic, cartesian magnetic field grid with trilinear interpolation. - This class provides a magnetic field grid. \n - The grid spacing is constant and equal along all three axes (cartesian). \n - The grid is of cubic shape. \n - Magnetic field values are calculated by trilinear interpolation of the surrounding 8 grid points. \n + This class provides a magnetic field grid. + The grid spacing is constant and equal along all three axes (cartesian). + The grid is of cubic shape. + Magnetic field values are calculated by trilinear interpolation of the surrounding 8 grid points. The grid is periodically extended. */ class MagneticFieldGrid: public MagneticField { diff --git a/include/mpc/magneticField/magneticFieldRing.h b/include/mpc/magneticField/magneticFieldRing.h deleted file mode 100644 index 87768bc04..000000000 --- a/include/mpc/magneticField/magneticFieldRing.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef _MAGNETICFIELDRING_H_ -#define _MAGNETICFIELDRING_H_ - -#include "mpc/magneticField/magneticField.h" -#include - -namespace mpc { - -class MagneticFieldRing: public MagneticField { - -protected: - Vector3 center; - double Bnorm; - double innerEdge; - double outerEdge; - double scaleHeight; - -public: - MagneticFieldRing(Vector3 center, double Bnorm, double innerEdge, - double outerEdge, double scaleHeight) { - this->center = center; - this->Bnorm = Bnorm; - this->innerEdge = innerEdge; - this->outerEdge = outerEdge; - this->scaleHeight = scaleHeight; - } - - ~MagneticFieldRing() { - } - - Vector3 getField(const Vector3 &position) const { - Vector3 b(0, 0, 0); - Vector3 r = position - center; - - if ((r.mag() < innerEdge) || (r.mag() > outerEdge)) - return b; - - double phi = -1. * atan2(r.y(), r.x()); - double weight = exp(-fabs(r.z()) / scaleHeight); - b.setX(Bnorm * sin(phi) * weight); - b.setY(Bnorm * cos(phi) * weight); - return b; - } -}; - -} // namespace mpc - -#endif // _MAGNETICFIELDRING_H_ diff --git a/include/mpc/module/ElectronPairProduction.h b/include/mpc/module/ElectronPairProduction.h index 348acbacf..a1e67e27b 100644 --- a/include/mpc/module/ElectronPairProduction.h +++ b/include/mpc/module/ElectronPairProduction.h @@ -2,7 +2,6 @@ #define ELECTRONPAIRPRODUCTION_H_ #include "mpc/Module.h" -#include "mpc/ParticleState.h" #include #include @@ -17,24 +16,18 @@ namespace mpc { Several photon fields can be selected. They are considered as homogeneous and evolving as the CMB. */ class ElectronPairProduction: public Module { +protected: + int photonField; + std::vector y; // energy loss rate table for protons in [J/m] + std::vector x; // energy table in [J] public: - enum PhotonField { - CMB, IR, CMBIR - }; - - ElectronPairProduction(PhotonField photonField); + ElectronPairProduction(int photonField); ElectronPairProduction(); - void init(PhotonField photonField); + void init(int photonField); void init(std::string filename); std::string getDescription() const; void process(Candidate *candidate) const; - -private: - PhotonField photonField; - std::vector y; // energy loss rate table for protons in [J/m] - std::vector x; // energy table in [J] - }; } // namespace mpc diff --git a/include/mpc/module/NuclearDecay.h b/include/mpc/module/NuclearDecay.h index a03137b90..d6b8b1d42 100644 --- a/include/mpc/module/NuclearDecay.h +++ b/include/mpc/module/NuclearDecay.h @@ -1,7 +1,7 @@ #ifndef DECAY_H_ #define DECAY_H_ -#include "mpc/Module.h" +#include "mpc/module/StochasticInteraction.h" #include "mpc/Random.h" #include @@ -13,20 +13,15 @@ namespace mpc { @class NuclearDecay @brief Nuclear decay of unstable nuclei. - This module simulates the nuclear decay of unstable nuclei. - decayTable is a map of nuclei id to (distance, channel) where - channel is the number of (beta-, beta+, alpha, p, n) decays and - distance is the mean decay length in [m] + This module simulates the nuclear decay of unstable nuclei using data from NuDat2. */ -class NuclearDecay: public Module { +class NuclearDecay: public StochasticInteraction { private: - std::string name; std::map > decayTable; public: NuclearDecay(); std::string getDescription() const; - void process(Candidate *candidate) const; bool setNextInteraction(Candidate *candidate) const; void performInteraction(Candidate *candidate) const; }; diff --git a/include/mpc/module/PhotoDisintegration.h b/include/mpc/module/PhotoDisintegration.h index 487063a27..7c62a8b19 100644 --- a/include/mpc/module/PhotoDisintegration.h +++ b/include/mpc/module/PhotoDisintegration.h @@ -1,7 +1,7 @@ #ifndef PHOTODISINTEGRATION_H_ #define PHOTODISINTEGRATION_H_ -#include "mpc/Module.h" +#include "mpc/module/StochasticInteraction.h" #include "mpc/Random.h" #include @@ -18,7 +18,7 @@ namespace mpc { This module simulates photo-disintegration of nuclei with background photons.\n Background photons are considered as homogeneous and evolving as the CMB.\n */ -class PhotoDisintegration: public Module { +class PhotoDisintegration: public StochasticInteraction { private: struct DisintegrationMode { int channel; // number of emitted (n, p, H2, H3, He3, He4) @@ -34,7 +34,6 @@ class PhotoDisintegration: public Module { PhotoDisintegration(); ~PhotoDisintegration(); std::string getDescription() const; - void process(Candidate *candidate) const; bool setNextInteraction(Candidate *candidate) const; void performInteraction(Candidate *candidate) const; }; diff --git a/include/mpc/module/PhotoPionProduction.h b/include/mpc/module/PhotoPionProduction.h index e7b2d5bd1..61ae5a389 100644 --- a/include/mpc/module/PhotoPionProduction.h +++ b/include/mpc/module/PhotoPionProduction.h @@ -1,7 +1,7 @@ #ifndef PHOTOPIONPRODUCTION_H_ #define PHOTOPIONPRODUCTION_H_ -#include "mpc/Module.h" +#include "mpc/module/StochasticInteraction.h" #include "mpc/Random.h" #include @@ -16,29 +16,30 @@ namespace mpc { This module simulates photo-hadronic interactions of nuclei with background photons.\n Several photon fields can be selected. They are considered as homogeneous and evolving as the CMB.\n */ -class PhotoPionProduction: public Module { -public: - enum PhotonField { - CMB, IR, CMBIR - }; +class PhotoPionProduction: public StochasticInteraction { +protected: + int photonField; + gsl_interp_accel *acc; + gsl_spline *pRate; // interaction rate in [1/m] for protons + gsl_spline *nRate; // interaction rate in [1/m] for neutrons + double Emin, Emax; - PhotoPionProduction(PhotonField photonField); - PhotoPionProduction(); +public: + PhotoPionProduction(int photonField); ~PhotoPionProduction(); - void init(PhotonField photonField); + void init(int photonField); void init(std::string filename); - void process(Candidate *candidate) const; + std::string getDescription() const; bool setNextInteraction(Candidate *candidate) const; void performInteraction(Candidate *candidate) const; - std::string getDescription() const; +}; -private: - std::string name; - PhotonField photonField; - gsl_interp_accel *acc; - gsl_spline *pRate; // interaction rate in [1/m] for protons - gsl_spline *nRate; // interaction rate in [1/m] for neutrons - double Emin, Emax; +/** + @class SophiaPhotoPionProduction + @brief Photo-pion interactions of nuclei with background photons using SOPHIA. + */ +class SophiaPhotoPionProduction : public PhotoPionProduction { + void performInteraction(Candidate *candidate) const; }; } // namespace mpc diff --git a/include/mpc/module/SophiaPhotoPionProduction.h b/include/mpc/module/SophiaPhotoPionProduction.h deleted file mode 100644 index d4b481834..000000000 --- a/include/mpc/module/SophiaPhotoPionProduction.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef SOPHIAPHOTOPIONPRODUCTION_H_ -#define SOPHIAPHOTOPIONPRODUCTION_H_ - -#include "mpc/Module.h" -#include "mpc/Random.h" - -#include -#include - -namespace mpc { - -/** - @class SophiaPhotoPionProduction - @brief Photo-pion interactions of nuclei with background photons using SOPHIA. - - This module simulates photo-hadronic interactions of nuclei with background photons.\n - Several photon fields can be selected. They are considered as homogeneous and evolving as the CMB.\n - */ -class SophiaPhotoPionProduction: public Module { -public: - enum PhotonField { - CMB, IR - }; - - SophiaPhotoPionProduction(PhotonField photonField); - SophiaPhotoPionProduction(); - ~SophiaPhotoPionProduction(); - void init(PhotonField photonField); - void init(std::string filename); - void process(Candidate *candidate) const; - bool setNextInteraction(Candidate *candidate) const; - void performInteraction(Candidate *candidate) const; - std::string getDescription() const; - -private: - std::string name; - PhotonField photonField; - gsl_interp_accel *acc; - gsl_spline *pRate; // interaction rate in [1/m] for protons - gsl_spline *nRate; // interaction rate in [1/m] for neutrons - double Emin, Emax; -}; - -} // namespace mpc - -#endif /* SOPHIAPHOTOPIONPRODUCTION_H_ */ diff --git a/include/mpc/module/StochasticInteraction.h b/include/mpc/module/StochasticInteraction.h new file mode 100644 index 000000000..44c89f4ad --- /dev/null +++ b/include/mpc/module/StochasticInteraction.h @@ -0,0 +1,25 @@ +#ifndef STOCHASTICINTERACTION_H_ +#define STOCHASTICINTERACTION_H_ + +#include "mpc/Module.h" + +namespace mpc { + +/** + @class StochasticInteraction + @brief Base class for stochastic interactions + */ +class StochasticInteraction: public Module { +protected: + std::string name; + +public: + StochasticInteraction(std::string name); + void process(Candidate *candidate) const; + virtual bool setNextInteraction(Candidate *candidate) const = 0; + virtual void performInteraction(Candidate *candidate) const = 0; +}; + +} // namespace mpc + +#endif /* STOCHASTICINTERACTION_H_ */ diff --git a/libs/sophia/sophia.h b/libs/sophia/sophia.h index 473174f0b..c6123fe39 100644 --- a/libs/sophia/sophia.h +++ b/libs/sophia/sophia.h @@ -7,38 +7,29 @@ void sophiaevent_(int&, double&, double[][2000], int[], int&, double&, int&, } /* - The arguments are the following (see sophiaevent.f) : - - - nature, Ein = input nature and energy of the nucleon - nature = 0 -> p ; 1 -> n - Ein : in GeV (Sophia standard energy unit) - - OutPart,OutPartType,NbOutPart = output data, respectively : - P(2000,5) list of 4-momenta + masses of output particles (in GeV) - LList(2000) list of output particle IDs - NP nb of output particles - Particle IDs are : - - cc 13 proton - cc 14 neutron - cc -13 antiproton - cc -14 antineutron - cc 1 photon - cc 2 e+ - cc 3 e- - cc 15 nu_e - cc 16 antinu_e - cc 17 nu_muon - cc 18 antinu_muon - - - z_particle : needed to estimate the CMB temperature or IRB density - - bgFlag = 1 for CMB, 2 for Primack et al. (1999) IRB. NO OTHER REDSHIFT MODEL - IS IMPLEMENTED, AND ITS REDSHIFT EVOLUTION IS "TRIVIAL", ie. same as CMB. - - Zmax_IRB : the photon density of IRB is null above this redshift - - Warning with passing arguments (variables->pointers) in fortran->C ! - + The arguments are the following + - nature: 0 -> p, 1 -> n + - input energy of nucleon in GeV + - list of 4-momenta + masses of output particles (in GeV) + 13 proton + 14 neutron + -13 antiproton + -14 antineutron + 1 photon + 2 e+ + 3 e- + 15 nu_e + 16 antinu_e + 17 nu_muon + 18 antinu_muon + - list of output particle ids + - number of output particles + - redshift + - photon background flag: 1 -> CMB, 2 -> Primack et al. (1999) IRB + - maximum redshift: the photon density of IRB is null above this redshift + - + - + - */ -//#define sophiaevent sophiaevent_ - #endif diff --git a/mpi/Slave.cpp b/mpi/Slave.cpp index 1382e34a6..1de3f8265 100644 --- a/mpi/Slave.cpp +++ b/mpi/Slave.cpp @@ -5,6 +5,7 @@ #include "mpc/ModuleChain.h" #include "mpc/Vector3.h" #include "mpc/Units.h" +#include "mpc/Common.h" #include "mpc/module/DeflectionCK.h" #include "mpc/module/BreakCondition.h" #include "mpc/module/GlutDisplay.h" @@ -42,8 +43,8 @@ void Slave::load(const string &filename) { // interactions ------------------------------------------------------- chain.add(30, new NuclearDecay()); chain.add(31, new PhotoDisintegration()); - chain.add(32, new ElectronPairProduction(ElectronPairProduction::CMB)); - chain.add(33, new PhotoPionProduction(PhotoPionProduction::CMBIR)); +// chain.add(32, new ElectronPairProduction(CMBIR)); +// chain.add(33, new PhotoPionProduction(CMBIR)); // output ------------------------------------------------------------- chain.add(79, new ShellOutput()); diff --git a/python/mpc.i b/python/mpc.i index 5387fef76..b5e4611c2 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -30,9 +30,9 @@ %{ #include "mpc/module/NuclearDecay.h" #include "mpc/module/ElectronPairProduction.h" +#include "mpc/module/StochasticInteraction.h" #include "mpc/module/PhotoDisintegration.h" #include "mpc/module/PhotoPionProduction.h" -#include "mpc/module/SophiaPhotoPionProduction.h" #include "mpc/module/Redshift.h" #include "mpc/module/BreakCondition.h" #include "mpc/module/Output.h" @@ -47,6 +47,7 @@ #include "mpc/magneticField/turbulentMagneticFieldGrid.h" #include "mpc/magneticField/sphMagneticField.h" +#include "mpc/Referenced.h" #include "mpc/Candidate.h" #include "mpc/ParticleState.h" #include "mpc/Module.h" @@ -59,7 +60,6 @@ #include "mpc/Units.h" #include "mpc/Vector3.h" #include "mpc/Source.h" -#include "mpc/Referenced.h" #include "mpc/Common.h" %} @@ -102,14 +102,13 @@ %include "mpc/module/SimplePropagation.h" %include "mpc/module/DeflectionCK.h" %include "mpc/module/Output.h" -%include "mpc/module/NuclearDecay.h" %include "mpc/module/ElectronPairProduction.h" +%include "mpc/module/StochasticInteraction.h" +%include "mpc/module/NuclearDecay.h" %include "mpc/module/PhotoPionProduction.h" -%include "mpc/module/SophiaPhotoPionProduction.h" %include "mpc/module/PhotoDisintegration.h" %include "mpc/module/Redshift.h" %include "mpc/module/GlutDisplay.h" %include "mpc/module/Tools.h" - %include "mpc/ModuleChain.h" %include "mpc/ModuleList.h" diff --git a/src/IO.cpp b/src/IO.cpp index 8bcd538b7..e3d120c22 100644 --- a/src/IO.cpp +++ b/src/IO.cpp @@ -1,7 +1,5 @@ #include "mpc/IO.h" -#include - namespace mpc { void write(kiss::Output &out, const mpc::Vector3 &vec3) { diff --git a/src/main.cpp b/src/main.cpp index 77b3f0d50..9d3f94cc8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,8 +35,8 @@ int main(int argc, char **argv) { // interactions ------------------------------------------------------- chain.add(10, new NuclearDecay()); chain.add(11, new PhotoDisintegration()); - chain.add(12, new ElectronPairProduction(ElectronPairProduction::CMB)); - chain.add(13, new PhotoPionProduction(PhotoPionProduction::CMBIR)); + chain.add(12, new ElectronPairProduction(CMBIR)); + chain.add(13, new PhotoPionProduction(CMBIR)); // break conditions --------------------------------------------------- chain.add(20, new MaximumTrajectoryLength(50 * Mpc)); diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 5b2461a58..489c9d507 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -7,7 +7,7 @@ namespace mpc { -ElectronPairProduction::ElectronPairProduction(PhotonField photonField) { +ElectronPairProduction::ElectronPairProduction(int photonField) { init(photonField); } @@ -15,8 +15,8 @@ ElectronPairProduction::ElectronPairProduction() { init(CMBIR); } -void ElectronPairProduction::init(PhotonField field) { - photonField = field; +void ElectronPairProduction::init(int photonField) { + this->photonField = photonField; switch (photonField) { case CMB: init(getDataPath("ElectronPairProduction/cmb.txt")); diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index 1e8fbdde0..0692bfb41 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -7,14 +7,12 @@ namespace mpc { -NuclearDecay::NuclearDecay() { - name = "mpc::NuclearDecay"; - +NuclearDecay::NuclearDecay() : StochasticInteraction("NuclearDecay") { std::string filename = getDataPath("/NuclearDecay/decay_table.txt"); std::ifstream infile(filename.c_str()); if (!infile.good()) - throw std::runtime_error(name + ": could not open file " + filename); + throw std::runtime_error("mpc::NuclearDecay: could not open file " + filename); while (infile.good()) { if (infile.peek() != '#') { @@ -36,37 +34,6 @@ std::string NuclearDecay::getDescription() const { return "Nuclear decay"; } -void NuclearDecay::process(Candidate *candidate) const { - double gamma = candidate->current.getLorentzFactor(); - double step = candidate->getCurrentStep() / gamma; - InteractionState decay; - - while (true) { - // check if decay is set - bool noState = !candidate->getInteractionState(name, decay); - if (noState) { - // try to set a new decay - bool noInteraction = !setNextInteraction(candidate); - if (noInteraction) - return; - // get the new decay - candidate->getInteractionState(name, decay); - } - - // if not over, reduce distance and return - if (decay.distance > step) { - decay.distance -= step; - candidate->limitNextStep(decay.distance * gamma); - candidate->setInteractionState(name, decay); - return; - } - - // counter over: interact - step -= decay.distance; - performInteraction(candidate); - } -} - bool NuclearDecay::setNextInteraction(Candidate *candidate) const { int id = candidate->current.getId(); @@ -88,6 +55,7 @@ bool NuclearDecay::setNextInteraction(Candidate *candidate) const { decay.distance = d; decay.channel = states[i].channel; } + decay.distance *= candidate->current.getLorentzFactor(); candidate->setInteractionState(name, decay); return true; } diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 3563aeb1c..592a9e648 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -14,8 +14,7 @@ enum _Constants { SAMPLE_COUNT = 200 }; -PhotoDisintegration::PhotoDisintegration() { - name = "mpc::PhotoDisintegration"; +PhotoDisintegration::PhotoDisintegration() : StochasticInteraction("PhotoDisintegration") { acc = gsl_interp_accel_alloc(); // create spline x-axis @@ -31,7 +30,7 @@ PhotoDisintegration::PhotoDisintegration() { std::ifstream infile(filename.c_str()); if (!infile.good()) - throw std::runtime_error(name + ": could not open file " + filename); + throw std::runtime_error("mpc::PhotoDisitegration: could not open file " + filename); std::string line; size_t lineNo = 0; @@ -80,36 +79,6 @@ std::string PhotoDisintegration::getDescription() const { return "Photo-disintegration"; } -void PhotoDisintegration::process(Candidate *candidate) const { - double step = candidate->getCurrentStep(); - InteractionState interaction; - - while (true) { - // check if interaction is set - bool noState = !candidate->getInteractionState(name, interaction); - if (noState) { - // try to set a new interaction - bool noInteraction = !setNextInteraction(candidate); - if (noInteraction) - return; - // get the new interaction - candidate->getInteractionState(name, interaction); - } - - // if not over, reduce distance and return - if (interaction.distance > step) { - interaction.distance -= step; - candidate->limitNextStep(interaction.distance); - candidate->setInteractionState(name, interaction); - return; - } - - // if over, interact and repeat - step -= interaction.distance; - performInteraction(candidate); - } -} - bool PhotoDisintegration::setNextInteraction(Candidate *candidate) const { int id = candidate->current.getId(); diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp deleted file mode 100644 index e1eee6e2a..000000000 --- a/src/module/PhotoPionProduction.cpp +++ /dev/null @@ -1,202 +0,0 @@ -#include "mpc/module/PhotoPionProduction.h" - -#include -#include -#include -#include -#include - -namespace mpc { - -PhotoPionProduction::PhotoPionProduction(PhotonField photonField) { - init(photonField); -} - -PhotoPionProduction::PhotoPionProduction() { - init(CMBIR); -} - -void PhotoPionProduction::init(PhotonField field) { - name = "mpc::PhotoPionProduction"; - - photonField = field; - switch (photonField) { - case CMB: - init(getDataPath("PhotoPionProduction/cmb.txt")); - break; - case IR: - init(getDataPath("PhotoPionProduction/ir.txt")); - break; - case CMBIR: - init(getDataPath("PhotoPionProduction/cmbir.txt")); - break; - } -} - -void PhotoPionProduction::init(std::string filename) { - std::ifstream infile(filename.c_str()); - if (!infile.good()) - throw std::runtime_error(name + ": could not open file " + filename); - - std::vector x, yp, yn; - x.reserve(100); - yp.reserve(100); - yn.reserve(100); - while (infile.good()) { - if (infile.peek() != '#') { - double a, b, c; - infile >> a >> b >> c; - if (infile) { - x.push_back(a * EeV); // energy in [EeV] - yp.push_back(b / Mpc); // rate in [1/Mpc] - yn.push_back(c / Mpc); // rate in [1/Mpc] - } - } - infile.ignore(std::numeric_limits::max(), '\n'); - } - - infile.close(); - - acc = gsl_interp_accel_alloc(); - pRate = gsl_spline_alloc(gsl_interp_linear, x.size()); - nRate = gsl_spline_alloc(gsl_interp_linear, x.size()); - gsl_spline_init(pRate, &x[0], &yp[0], x.size()); - gsl_spline_init(nRate, &x[0], &yn[0], x.size()); - Emin = x.front(); - Emax = x.back(); -} - -PhotoPionProduction::~PhotoPionProduction() { - gsl_spline_free(pRate); - gsl_spline_free(nRate); - gsl_interp_accel_free(acc); -} - -std::string PhotoPionProduction::getDescription() const { - switch (photonField) { - case CMB: { - return "Photo-pion production on CMB"; - break; - } - case IR: { - return "Photo-pion production on IR"; - break; - } - case CMBIR: { - return "Photo-pion production on CMBIR"; - break; - } - default: { - return "Photo-pion production (unknown)"; - break; - } - } -} - -void PhotoPionProduction::process(Candidate *candidate) const { - double step = candidate->getCurrentStep(); - InteractionState interaction; - - while (true) { - // check if interaction is set - bool noState = !candidate->getInteractionState(name, interaction); - if (noState) { - // try to set a new interaction - bool noInteraction = !setNextInteraction(candidate); - if (noInteraction) - return; - // get the new interaction - candidate->getInteractionState(name, interaction); - } - - // if not over, reduce distance and return - if (interaction.distance > step) { - interaction.distance -= step; - candidate->limitNextStep(interaction.distance); - candidate->setInteractionState(name, interaction); - return; - } - - // counter over: interact - step -= interaction.distance; - performInteraction(candidate); - } -} - -bool PhotoPionProduction::setNextInteraction(Candidate *candidate) const { - double z = candidate->getRedshift(); - double E = candidate->current.getEnergy(); - int A = candidate->current.getMassNumber(); - int Z = candidate->current.getChargeNumber(); - int N = A - Z; - double EpA = E / A * (1 + z); // CMB energies increase with (1+z)^3 - - // check if out of energy range - if ((EpA < Emin) or (EpA > Emax)) - return false; - - // find interaction with minimum random distance - // check for interaction on protons - InteractionState interaction; - interaction.distance = std::numeric_limits::max(); - Random &random = Random::instance(); - if (Z > 0) { - double rate = gsl_spline_eval(pRate, EpA, acc) * Z; - if (rate != 0) { - interaction.distance = -log(random.rand()) / rate; - interaction.channel = 1; - } - } - // check for interaction on neutrons - if (N > 0) { - double rate = gsl_spline_eval(nRate, EpA, acc) * N; - if (rate != 0) { - double d = -log(random.rand()) / rate; - if (d < interaction.distance) { - interaction.distance = -log(random.rand()) / rate; - interaction.channel = 0; - } - } - } - - // CMB density increases with (1+z)^3 -> free distance decreases accordingly - interaction.distance /= pow((1 + z), 3); - - if (isnan(interaction.distance)) { - return false; - } - - candidate->setInteractionState(name, interaction); - return true; -} - -void PhotoPionProduction::performInteraction(Candidate *candidate) const { - InteractionState interaction; - candidate->getInteractionState(name, interaction); - candidate->clearInteractionStates(); - - // charge number loss of interaction nucleus - int dZ = interaction.channel; - // final proton number of emitted nucleon - int Zfinal = dZ; - // 1/3 probability of isospin change p <-> n - if (Random::instance().rand() < 1. / 3.) - Zfinal = abs(Zfinal - 1); - - double E = candidate->current.getEnergy(); - int A = candidate->current.getMassNumber(); - int Z = candidate->current.getChargeNumber(); - - if (A == 1) { - // interaction on single nucleon - candidate->current.setEnergy(E * 938. / 1232.); - candidate->current.setId(getNucleusId(1, Zfinal)); - } else { - // interaction on nucleus, update nucleus and emit nucleon - candidate->current.setEnergy(E * (A - 1) / A); - candidate->current.setId(getNucleusId(A - 1, Z - dZ)); - candidate->addSecondary(getNucleusId(1, Zfinal), E / A * 938. / 1232.); - } -} - -} // namespace mpc diff --git a/src/module/SophiaPhotoPionProduction.cpp b/src/module/SophiaPhotoPionProduction.cpp deleted file mode 100644 index 2cf387653..000000000 --- a/src/module/SophiaPhotoPionProduction.cpp +++ /dev/null @@ -1,231 +0,0 @@ -#include "mpc/module/SophiaPhotoPionProduction.h" - -#include "sophia.h" - -#include -#include -#include -#include -#include - -namespace mpc { - -SophiaPhotoPionProduction::SophiaPhotoPionProduction(PhotonField photonField) { - init(photonField); -} - -SophiaPhotoPionProduction::SophiaPhotoPionProduction() { - init(CMB); -} - -void SophiaPhotoPionProduction::init(PhotonField field) { - name = "mpc::PhotoPionProduction"; - - photonField = field; - switch (photonField) { - case CMB: - init(getDataPath("PhotoPionProduction/cmb.txt")); - break; - case IR: - init(getDataPath("PhotoPionProduction/ir.txt")); - break; - } -} - -void SophiaPhotoPionProduction::init(std::string filename) { - std::ifstream infile(filename.c_str()); - if (!infile.good()) - throw std::runtime_error(name + ": could not open file " + filename); - - std::vector x, yp, yn; - x.reserve(100); - yp.reserve(100); - yn.reserve(100); - while (infile.good()) { - if (infile.peek() != '#') { - double a, b, c; - infile >> a >> b >> c; - if (infile) { - x.push_back(a * EeV); // energy in [EeV] - yp.push_back(b / Mpc); // rate in [1/Mpc] - yn.push_back(c / Mpc); // rate in [1/Mpc] - } - } - infile.ignore(std::numeric_limits::max(), '\n'); - } - - infile.close(); - - acc = gsl_interp_accel_alloc(); - pRate = gsl_spline_alloc(gsl_interp_linear, x.size()); - nRate = gsl_spline_alloc(gsl_interp_linear, x.size()); - gsl_spline_init(pRate, &x[0], &yp[0], x.size()); - gsl_spline_init(nRate, &x[0], &yn[0], x.size()); - Emin = x.front(); - Emax = x.back(); -} - -SophiaPhotoPionProduction::~SophiaPhotoPionProduction() { - gsl_spline_free(pRate); - gsl_spline_free(nRate); - gsl_interp_accel_free(acc); -} - -std::string SophiaPhotoPionProduction::getDescription() const { - switch (photonField) { - case CMB: { - return "Photo-pion production on CMB using SOPHIA"; - break; - } - case IR: { - return "Photo-pion production on IR using SOPHIA"; - break; - } - default: { - return "Photo-pion production using SOPHIA (unknown)"; - break; - } - } -} - -void SophiaPhotoPionProduction::process(Candidate *candidate) const { - double step = candidate->getCurrentStep(); - InteractionState interaction; - - while (true) { - // check if interaction is set - bool noState = !candidate->getInteractionState(name, interaction); - if (noState) { - // try to set a new interaction - bool noInteraction = !setNextInteraction(candidate); - if (noInteraction) - return; - // get the new interaction - candidate->getInteractionState(name, interaction); - } - - // if not over, reduce distance and return - if (interaction.distance > step) { - interaction.distance -= step; - candidate->limitNextStep(interaction.distance); - candidate->setInteractionState(name, interaction); - return; - } - - // counter over: interact - step -= interaction.distance; - performInteraction(candidate); - } -} - -bool SophiaPhotoPionProduction::setNextInteraction(Candidate *candidate) const { - double z = candidate->getRedshift(); - double E = candidate->current.getEnergy(); - int A = candidate->current.getMassNumber(); - int Z = candidate->current.getChargeNumber(); - int N = A - Z; - double EpA = E / A * (1 + z); // CMB energies increase with (1+z)^3 - - // check if out of energy range - if ((EpA < Emin) or (EpA > Emax)) - return false; - - // find interaction with minimum random distance - // check for interaction on protons - InteractionState interaction; - interaction.distance = std::numeric_limits::max(); - Random &random = Random::instance(); - if (Z > 0) { - double rate = gsl_spline_eval(pRate, EpA, acc) * Z; - if (rate != 0) { - interaction.distance = -log(random.rand()) / rate; - interaction.channel = 1; - } - } - // check for interaction on neutrons - if (N > 0) { - double rate = gsl_spline_eval(nRate, EpA, acc) * N; - if (rate != 0) { - double d = -log(random.rand()) / rate; - if (d < interaction.distance) { - interaction.distance = -log(random.rand()) / rate; - interaction.channel = 0; - } - } - } - - // CMB density increases with (1+z)^3 -> free distance decreases accordingly - interaction.distance /= pow((1 + z), 3); - - if (isnan(interaction.distance)) { - return false; - } - - candidate->setInteractionState(name, interaction); - return true; -} - -void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { - InteractionState interaction; - candidate->getInteractionState(name, interaction); - candidate->clearInteractionStates(); - - int dZ = interaction.channel; // charge number loss of interacting nucleus - - double E = candidate->current.getEnergy(); - int A = candidate->current.getMassNumber(); - int Z = candidate->current.getChargeNumber(); - double EpA = E / A; - - // arguments for sophia - int nature = 1 - dZ; // interacting particle: 0 for proton, 1 for neutron - double Ein = EpA / GeV; // energy of in-going nucleon in GeV - double momentaList[5][2000]; // momentum list, what are the five components? - int particleList[2000]; // particle id list - int nParticles; // number of outgoing particles - double redshift = candidate->getRedshift(); - int background = photonField + 1; // Photon background: 1 for CMB, 2 for Primack IR - double maxRedshift = 100; // IR photon density is zero above this redshift - int IRNE = 2; // ??? - double dummy[2]; // ??? - - sophiaevent_(nature, Ein, momentaList, particleList, nParticles, redshift, - background, maxRedshift, IRNE, dummy, dummy); - - for (int i = 0; i < nParticles; i++) { // loop over out-going particles - double Eout = momentaList[3][i] * GeV; // only the energy is used; could be changed for more realism - int pType = particleList[i]; -// 13 proton -// 14 neutron -// -13 antiproton -// -14 antineutron -// 1 photon -// 2 e+ -// 3 e- -// 15 nu_e -// 16 antinu_e -// 17 nu_muon -// 18 antinu_muon - - if (pType == 13 or pType == 14) { - int Zout = 14 - pType; // 1 for proton, 0 for neutron - if (A == 1) { // in-going particle was a nucleon: update its properties - candidate->current.setEnergy(Eout); - candidate->current.setId(getNucleusId(1, Zout)); - } else { - // // in-going particle was a nucleus: update nucleus and emit nucleon - candidate->current.setEnergy(E - Eout); - candidate->current.setId(getNucleusId(A - 1, Z - dZ)); - candidate->addSecondary(getNucleusId(1, Zout), Eout); - } - } else if (pType == -13 or pType == -14) { - continue; // anti-proton/neutron annihilate quickly -> new electromagnetic cascade? - } else if (pType >= 1 and pType <= 3) { - continue; // new electromagnetic cascade - } else if (pType >= 15) { - continue; // new neutrino - } - } -} - -} // namespace mpc diff --git a/src/module/StochasticInteraction.cpp b/src/module/StochasticInteraction.cpp new file mode 100644 index 000000000..1009092b5 --- /dev/null +++ b/src/module/StochasticInteraction.cpp @@ -0,0 +1,39 @@ +#include "mpc/module/StochasticInteraction.h" + +namespace mpc { + +StochasticInteraction::StochasticInteraction(std::string name) : + name(name) { +} + +void StochasticInteraction::process(Candidate* candidate) const { + double step = candidate->getCurrentStep(); + InteractionState interaction; + + while (true) { + // check if an interaction is set + bool noState = !candidate->getInteractionState(name, interaction); + if (noState) { + // try to set a new interaction + bool successful = setNextInteraction(candidate); + if (not (successful)) + return; + // get the new interaction + candidate->getInteractionState(name, interaction); + } + + // if not over, reduce distance and return + if (interaction.distance > step) { + interaction.distance -= step; + candidate->limitNextStep(interaction.distance); + candidate->setInteractionState(name, interaction); + return; + } + + // counter over: interact + step -= interaction.distance; + performInteraction(candidate); + } +} + +} // namespace mpc diff --git a/src/openmp.cpp b/src/openmp.cpp index 477302054..87799c8cd 100644 --- a/src/openmp.cpp +++ b/src/openmp.cpp @@ -25,8 +25,8 @@ int main(int argc, char **argv) { modules.add(new DeflectionCK(field)); modules.add(new NuclearDecay()); modules.add(new PhotoDisintegration()); - modules.add(new ElectronPairProduction(ElectronPairProduction::CMB)); - modules.add(new PhotoPionProduction(PhotoPionProduction::CMBIR)); + modules.add(new ElectronPairProduction(CMBIR)); + modules.add(new PhotoPionProduction(CMBIR)); modules.add(new MaximumTrajectoryLength(50 * Mpc)); modules.add(new MinimumEnergy(5 * EeV)); diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 6ceb82e90..4784acee7 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -15,7 +15,7 @@ TEST(ElectronPairProduction, EnergyDecreasing) { candidate.setCurrentStep(1 * Mpc); candidate.current.setId(getNucleusId(1, 1)); // proton - ElectronPairProduction epp1(ElectronPairProduction::CMB); + ElectronPairProduction epp1(CMB); for (int i = 0; i < 80; i++) { double E = pow(10, 15 + i * 0.1) * eV; candidate.current.setEnergy(E); @@ -23,7 +23,7 @@ TEST(ElectronPairProduction, EnergyDecreasing) { EXPECT_TRUE(candidate.current.getEnergy() <= E); } - ElectronPairProduction epp2(ElectronPairProduction::IR); + ElectronPairProduction epp2(IR); for (int i = 0; i < 80; i++) { double E = pow(10, 15 + i * 0.1) * eV; candidate.current.setEnergy(E); @@ -31,7 +31,7 @@ TEST(ElectronPairProduction, EnergyDecreasing) { EXPECT_TRUE(candidate.current.getEnergy() < E); } - ElectronPairProduction epp3(ElectronPairProduction::CMBIR); + ElectronPairProduction epp3(CMBIR); for (int i = 0; i < 80; i++) { double E = pow(10, 15 + i * 0.1) * eV; candidate.current.setEnergy(E); @@ -42,7 +42,7 @@ TEST(ElectronPairProduction, EnergyDecreasing) { TEST(ElectronPairProduction, BelowEnergyTreshold) { // test if nothing happens below 1e15 eV - ElectronPairProduction epp(ElectronPairProduction::CMB); + ElectronPairProduction epp(CMB); Candidate candidate; candidate.current.setId(getNucleusId(1, 1)); // proton double E = 1e14 * eV; @@ -107,26 +107,26 @@ TEST(NuclearDecay, Scandium44) { EXPECT_EQ(candidate.current.getId(), getNucleusId(44,20)); } -TEST(NuclearDecay, H30) { - // test neutron dripping H-30 -> H-3 (-> He-3) +TEST(NuclearDecay, Li4) { + // test proton dripping Li-4 -> He-3 Candidate candidate; candidate.setCurrentStep(1 * kpc); - candidate.current.setId(getNucleusId(30, 1)); + candidate.current.setId(getNucleusId(4, 3)); candidate.current.setEnergy(1 * EeV); NuclearDecay d; d.process(&candidate); - EXPECT_EQ(getNucleusId(3,1), candidate.current.getId()); + EXPECT_EQ(getNucleusId(3,2), candidate.current.getId()); } -TEST(NuclearDecay, Fe27) { - // test proton dripping Fe-27 -> He-3 +TEST(NuclearDecay, He5) { + // test neturon dripping He-5 -> He-4 Candidate candidate; candidate.setCurrentStep(1 * Mpc); - candidate.current.setId(getNucleusId(27, 26)); + candidate.current.setId(getNucleusId(5, 2)); candidate.current.setEnergy(1 * EeV); NuclearDecay d; d.process(&candidate); - EXPECT_EQ(getNucleusId(3,2), candidate.current.getId()); + EXPECT_EQ(getNucleusId(4,2), candidate.current.getId()); } TEST(NuclearDecay, LimitNextStep) { @@ -140,8 +140,6 @@ TEST(NuclearDecay, LimitNextStep) { EXPECT_TRUE(candidate.getNextStep() < 10 * Mpc); } - - TEST(PhotoDisintegration, Carbon) { PhotoDisintegration pd; Candidate candidate; @@ -168,13 +166,13 @@ TEST(PhotoDisintegration, Iron) { TEST(PhotoPionProduction, Backgrounds) { - PhotoPionProduction ppp1(PhotoPionProduction::CMB); - PhotoPionProduction ppp2(PhotoPionProduction::IR); - PhotoPionProduction ppp3(PhotoPionProduction::CMBIR); + PhotoPionProduction ppp1(CMB); + PhotoPionProduction ppp2(IR); + PhotoPionProduction ppp3(CMBIR); } TEST(PhotoPionProduction, Proton) { - PhotoPionProduction ppp(PhotoPionProduction::CMBIR); + PhotoPionProduction ppp(CMBIR); Candidate candidate; candidate.setCurrentStep(100 * Mpc); candidate.current.setId(getNucleusId(1, 1)); @@ -185,7 +183,7 @@ TEST(PhotoPionProduction, Proton) { } TEST(PhotoPionProduction, Helium) { - PhotoPionProduction ppp(PhotoPionProduction::CMBIR); + PhotoPionProduction ppp(CMBIR); Candidate candidate; candidate.setCurrentStep(100 * Mpc); candidate.current.setId(getNucleusId(4, 2)); From 1ebc1774ffc1e88e310b818f07766dfd84ff0770 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 17 Apr 2012 09:29:13 +0200 Subject: [PATCH 0059/1298] fill nuclear mass table to prevent "unknown nucleus" errors in photopion interactions --- src/module/PhotoPionProduction.cpp | 219 +++++++++++++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 src/module/PhotoPionProduction.cpp diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp new file mode 100644 index 000000000..d50a4538b --- /dev/null +++ b/src/module/PhotoPionProduction.cpp @@ -0,0 +1,219 @@ +#include "mpc/module/PhotoPionProduction.h" +#include "sophia.h" + +#include +#include +#include +#include +#include + +namespace mpc { + +PhotoPionProduction::PhotoPionProduction(int photonField) : + StochasticInteraction("PhotoPionProduction") { + init(photonField); +} + +void PhotoPionProduction::init(int photonField) { + this->photonField = photonField; + switch (photonField) { + case CMB: + name = "PhotoPionProduction:CMB"; + init(getDataPath("PhotoPionProduction/cmb.txt")); + break; + case IR: + name = "PhotoPionProduction:IR"; + init(getDataPath("PhotoPionProduction/ir.txt")); + break; + case CMBIR: + name = "PhotoPionProduction:CMBIR"; + init(getDataPath("PhotoPionProduction/cmbir.txt")); + break; + } +} + +std::string PhotoPionProduction::getDescription() const { + return name; +} + +void PhotoPionProduction::init(std::string filename) { + std::ifstream infile(filename.c_str()); + if (!infile.good()) + throw std::runtime_error( + "mpc::PhotoPionProduction: could not open file " + filename); + + std::vector x, yp, yn; + x.reserve(100); + yp.reserve(100); + yn.reserve(100); + while (infile.good()) { + if (infile.peek() != '#') { + double a, b, c; + infile >> a >> b >> c; + if (infile) { + x.push_back(a * EeV); // energy in [EeV] + yp.push_back(b / Mpc); // rate in [1/Mpc] + yn.push_back(c / Mpc); // rate in [1/Mpc] + } + } + infile.ignore(std::numeric_limits::max(), '\n'); + } + + infile.close(); + + acc = gsl_interp_accel_alloc(); + pRate = gsl_spline_alloc(gsl_interp_linear, x.size()); + nRate = gsl_spline_alloc(gsl_interp_linear, x.size()); + gsl_spline_init(pRate, &x[0], &yp[0], x.size()); + gsl_spline_init(nRate, &x[0], &yn[0], x.size()); + Emin = x.front(); + Emax = x.back(); +} + +PhotoPionProduction::~PhotoPionProduction() { + gsl_spline_free(pRate); + gsl_spline_free(nRate); + gsl_interp_accel_free(acc); +} + +bool PhotoPionProduction::setNextInteraction(Candidate *candidate) const { + double z = candidate->getRedshift(); + double E = candidate->current.getEnergy(); + int A = candidate->current.getMassNumber(); + int Z = candidate->current.getChargeNumber(); + int N = A - Z; + double EpA = E / A * (1 + z); // CMB energies increase with (1+z)^3 + + // check if out of energy range + if ((EpA < Emin) or (EpA > Emax)) + return false; + + // find interaction with minimum random distance + // check for interaction on protons + InteractionState interaction; + interaction.distance = std::numeric_limits::max(); + Random &random = Random::instance(); + if (Z > 0) { + double rate = gsl_spline_eval(pRate, EpA, acc) * Z; + if (rate != 0) { + interaction.distance = -log(random.rand()) / rate; + interaction.channel = 1; + } + } + // check for interaction on neutrons + if (N > 0) { + double rate = gsl_spline_eval(nRate, EpA, acc) * N; + if (rate != 0) { + double d = -log(random.rand()) / rate; + if (d < interaction.distance) { + interaction.distance = -log(random.rand()) / rate; + interaction.channel = 0; + } + } + } + + // CMB density increases with (1+z)^3 -> free distance decreases accordingly + interaction.distance /= pow((1 + z), 3); + + if (isnan(interaction.distance)) { + return false; + } + + candidate->setInteractionState(name, interaction); + return true; +} + +void PhotoPionProduction::performInteraction(Candidate *candidate) const { + InteractionState interaction; + candidate->getInteractionState(name, interaction); + candidate->clearInteractionStates(); + + // charge number loss of interaction nucleus + int dZ = interaction.channel; + // final proton number of emitted nucleon + int Zfinal = dZ; + // 1/3 probability of isospin change p <-> n + if (Random::instance().rand() < 1. / 3.) + Zfinal = abs(Zfinal - 1); + + double E = candidate->current.getEnergy(); + int A = candidate->current.getMassNumber(); + int Z = candidate->current.getChargeNumber(); + + if (A == 1) { + // interaction on single nucleon + candidate->current.setEnergy(E * 938. / 1232.); + candidate->current.setId(getNucleusId(1, Zfinal)); + } else { + // interaction on nucleus, update nucleus and emit nucleon + candidate->current.setEnergy(E * (A - 1) / A); + candidate->current.setId(getNucleusId(A - 1, Z - dZ)); + candidate->addSecondary(getNucleusId(1, Zfinal), E / A * 938. / 1232.); + } +} + +void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { + InteractionState interaction; + candidate->getInteractionState(name, interaction); + candidate->clearInteractionStates(); + + int dZ = interaction.channel; // charge number loss of interacting nucleus + + double E = candidate->current.getEnergy(); + int A = candidate->current.getMassNumber(); + int Z = candidate->current.getChargeNumber(); + double EpA = E / A; + + // arguments for sophia + int nature = 1 - dZ; // interacting particle: 0 for proton, 1 for neutron + double Ein = EpA / GeV; // energy of in-going nucleon in GeV + double momentaList[5][2000]; // momentum list, what are the five components? + int particleList[2000]; // particle id list + int nParticles; // number of outgoing particles + double redshift = candidate->getRedshift(); + int background; // Photon background: 1 for CMB, 2 for Primack IR + switch (photonField) { + case CMB: + background = 1; + break; + case IR: + background = 2; + break; + case CMBIR: + throw std::runtime_error( + "mpc::SophiaPhotoPionProduction: CMBIR not possible for SophiaPhotoPionProduction"); + break; + } + double maxRedshift = 100; // IR photon density is zero above this redshift + int dummy1; + double dummy2[2]; + + sophiaevent_(nature, Ein, momentaList, particleList, nParticles, redshift, + background, maxRedshift, dummy1, dummy2, dummy2); + + for (int i = 0; i < nParticles; i++) { // loop over out-going particles + double Eout = momentaList[3][i] * GeV; // only the energy is used; could be changed for more detail + int pType = particleList[i]; + + if (pType == 13 or pType == 14) { + int Zout = 14 - pType; // 1 for proton, 0 for neutron + if (A == 1) { // in-going particle was a nucleon: update its properties + candidate->current.setEnergy(Eout); + candidate->current.setId(getNucleusId(1, Zout)); + } else { + // // in-going particle was a nucleus: update nucleus and emit nucleon + candidate->current.setEnergy(E - Eout); + candidate->current.setId(getNucleusId(A - 1, Z - dZ)); + candidate->addSecondary(getNucleusId(1, Zout), Eout); + } + } else if (pType == -13 or pType == -14) { + continue; // anti-proton/neutron -> new electromagnetic cascade after annihilation? + } else if (pType >= 1 and pType <= 3) { + continue; // new electromagnetic cascade + } else if (pType >= 15) { + continue; // new neutrino + } + } +} + +} // namespace mpc From fa8dc2ff697641551b53b8465b01cf9904f83029 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 17 Apr 2012 10:26:50 +0200 Subject: [PATCH 0060/1298] refactor StochasticInteraction to remove unnecessary getInteractionState --- include/mpc/Module.h | 6 ++---- include/mpc/ParticleState.h | 14 ++++++------- include/mpc/module/NuclearDecay.h | 4 ++-- include/mpc/module/PhotoDisintegration.h | 5 ++--- include/mpc/module/PhotoPionProduction.h | 6 +++--- include/mpc/module/StochasticInteraction.h | 7 ++----- src/module/NuclearDecay.cpp | 18 ++++++++--------- src/module/PhotoDisintegration.cpp | 14 +++++-------- src/module/PhotoPionProduction.cpp | 23 +++++++++------------- src/module/StochasticInteraction.cpp | 14 ++++--------- test/testInteraction.cpp | 1 + 11 files changed, 45 insertions(+), 67 deletions(-) diff --git a/include/mpc/Module.h b/include/mpc/Module.h index 381f53782..ae0d70f27 100644 --- a/include/mpc/Module.h +++ b/include/mpc/Module.h @@ -16,18 +16,16 @@ class Candidate; @brief Abstract base class for modules */ class Module: public Referenced { +protected: std::string description; + public: Module(); - virtual ~Module() { } - virtual std::string getDescription() const; virtual void setDescription(const std::string &description); - virtual void process(Candidate *candidate) const = 0; - inline void process(ref_ptr candidate) const { process(candidate.get()); } diff --git a/include/mpc/ParticleState.h b/include/mpc/ParticleState.h index 761da0d7f..c8d001ca1 100644 --- a/include/mpc/ParticleState.h +++ b/include/mpc/ParticleState.h @@ -13,6 +13,13 @@ namespace mpc { @brief State of the particle: ID, energy, position, direction */ class ParticleState { +private: + int id; + double pmass; + double energy; + Vector3 position; + Vector3 direction; + public: ParticleState(); void setPosition(const Vector3 &pos); @@ -39,13 +46,6 @@ class ParticleState { Vector3 getVelocity() const; Vector3 getMomentum() const; - -private: - int id; - double pmass; - double energy; - Vector3 position; - Vector3 direction; }; } // namespace mpc diff --git a/include/mpc/module/NuclearDecay.h b/include/mpc/module/NuclearDecay.h index d6b8b1d42..c3cacbd9a 100644 --- a/include/mpc/module/NuclearDecay.h +++ b/include/mpc/module/NuclearDecay.h @@ -21,8 +21,8 @@ class NuclearDecay: public StochasticInteraction { public: NuclearDecay(); - std::string getDescription() const; - bool setNextInteraction(Candidate *candidate) const; + bool setNextInteraction(Candidate *candidate, + InteractionState &interaction) const; void performInteraction(Candidate *candidate) const; }; diff --git a/include/mpc/module/PhotoDisintegration.h b/include/mpc/module/PhotoDisintegration.h index 7c62a8b19..bb6227df8 100644 --- a/include/mpc/module/PhotoDisintegration.h +++ b/include/mpc/module/PhotoDisintegration.h @@ -27,14 +27,13 @@ class PhotoDisintegration: public StochasticInteraction { typedef std::map > DisintegrationModeMap; DisintegrationModeMap PDTable; - std::string name; gsl_interp_accel *acc; public: PhotoDisintegration(); ~PhotoDisintegration(); - std::string getDescription() const; - bool setNextInteraction(Candidate *candidate) const; + bool setNextInteraction(Candidate *candidate, + InteractionState &interaction) const; void performInteraction(Candidate *candidate) const; }; diff --git a/include/mpc/module/PhotoPionProduction.h b/include/mpc/module/PhotoPionProduction.h index 61ae5a389..3d29e702c 100644 --- a/include/mpc/module/PhotoPionProduction.h +++ b/include/mpc/module/PhotoPionProduction.h @@ -29,8 +29,8 @@ class PhotoPionProduction: public StochasticInteraction { ~PhotoPionProduction(); void init(int photonField); void init(std::string filename); - std::string getDescription() const; - bool setNextInteraction(Candidate *candidate) const; + bool setNextInteraction(Candidate *candidate, + InteractionState &interaction) const; void performInteraction(Candidate *candidate) const; }; @@ -38,7 +38,7 @@ class PhotoPionProduction: public StochasticInteraction { @class SophiaPhotoPionProduction @brief Photo-pion interactions of nuclei with background photons using SOPHIA. */ -class SophiaPhotoPionProduction : public PhotoPionProduction { +class SophiaPhotoPionProduction: public PhotoPionProduction { void performInteraction(Candidate *candidate) const; }; diff --git a/include/mpc/module/StochasticInteraction.h b/include/mpc/module/StochasticInteraction.h index 44c89f4ad..6b0f82c4e 100644 --- a/include/mpc/module/StochasticInteraction.h +++ b/include/mpc/module/StochasticInteraction.h @@ -10,13 +10,10 @@ namespace mpc { @brief Base class for stochastic interactions */ class StochasticInteraction: public Module { -protected: - std::string name; - public: - StochasticInteraction(std::string name); void process(Candidate *candidate) const; - virtual bool setNextInteraction(Candidate *candidate) const = 0; + virtual bool setNextInteraction(Candidate *candidate, + InteractionState &interaction) const = 0; virtual void performInteraction(Candidate *candidate) const = 0; }; diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index 0692bfb41..dbccf2140 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -7,12 +7,14 @@ namespace mpc { -NuclearDecay::NuclearDecay() : StochasticInteraction("NuclearDecay") { +NuclearDecay::NuclearDecay() { + setDescription("NuclearDecay"); std::string filename = getDataPath("/NuclearDecay/decay_table.txt"); std::ifstream infile(filename.c_str()); if (!infile.good()) - throw std::runtime_error("mpc::NuclearDecay: could not open file " + filename); + throw std::runtime_error( + "mpc::NuclearDecay: could not open file " + filename); while (infile.good()) { if (infile.peek() != '#') { @@ -30,11 +32,8 @@ NuclearDecay::NuclearDecay() : StochasticInteraction("NuclearDecay") { infile.close(); } -std::string NuclearDecay::getDescription() const { - return "Nuclear decay"; -} - -bool NuclearDecay::setNextInteraction(Candidate *candidate) const { +bool NuclearDecay::setNextInteraction(Candidate *candidate, + InteractionState &decay) const { int id = candidate->current.getId(); std::map >::const_iterator iMode = @@ -45,7 +44,6 @@ bool NuclearDecay::setNextInteraction(Candidate *candidate) const { const std::vector &states = iMode->second; // find decay mode with minimum random decay distance - InteractionState decay; decay.distance = std::numeric_limits::max(); int decayChannel; for (size_t i = 0; i < states.size(); i++) { @@ -56,13 +54,13 @@ bool NuclearDecay::setNextInteraction(Candidate *candidate) const { decay.channel = states[i].channel; } decay.distance *= candidate->current.getLorentzFactor(); - candidate->setInteractionState(name, decay); + candidate->setInteractionState(getDescription(), decay); return true; } void NuclearDecay::performInteraction(Candidate *candidate) const { InteractionState decay; - candidate->getInteractionState(name, decay); + candidate->getInteractionState(getDescription(), decay); candidate->clearInteractionStates(); // parse decay channel diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 592a9e648..84bf0e8a4 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -14,7 +14,8 @@ enum _Constants { SAMPLE_COUNT = 200 }; -PhotoDisintegration::PhotoDisintegration() : StochasticInteraction("PhotoDisintegration") { +PhotoDisintegration::PhotoDisintegration() { + setDescription("PhotoDisintegration"); acc = gsl_interp_accel_alloc(); // create spline x-axis @@ -75,11 +76,7 @@ PhotoDisintegration::~PhotoDisintegration() { } } -std::string PhotoDisintegration::getDescription() const { - return "Photo-disintegration"; -} - -bool PhotoDisintegration::setNextInteraction(Candidate *candidate) const { +bool PhotoDisintegration::setNextInteraction(Candidate *candidate, InteractionState &interaction) const { int id = candidate->current.getId(); // check if disintegration data available @@ -98,7 +95,6 @@ bool PhotoDisintegration::setNextInteraction(Candidate *candidate) const { return false; // find channel with minimum random decay distance - InteractionState interaction; interaction.distance = std::numeric_limits::max(); for (size_t i = 0; i < modes.size(); i++) { double rate = gsl_spline_eval(modes[i].rate, lg, acc); @@ -112,13 +108,13 @@ bool PhotoDisintegration::setNextInteraction(Candidate *candidate) const { // CMB density increases with (1+z)^3 -> free distance decreases accordingly interaction.distance /= pow((1 + z), 3); - candidate->setInteractionState(name, interaction); + candidate->setInteractionState(getDescription(), interaction); return true; } void PhotoDisintegration::performInteraction(Candidate *candidate) const { InteractionState interaction; - candidate->getInteractionState(name, interaction); + candidate->getInteractionState(getDescription(), interaction); candidate->clearInteractionStates(); // parse disintegration channel diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index d50a4538b..d259ba12d 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -9,8 +9,7 @@ namespace mpc { -PhotoPionProduction::PhotoPionProduction(int photonField) : - StochasticInteraction("PhotoPionProduction") { +PhotoPionProduction::PhotoPionProduction(int photonField) { init(photonField); } @@ -18,24 +17,20 @@ void PhotoPionProduction::init(int photonField) { this->photonField = photonField; switch (photonField) { case CMB: - name = "PhotoPionProduction:CMB"; + setDescription("PhotoPionProduction:CMB"); init(getDataPath("PhotoPionProduction/cmb.txt")); break; case IR: - name = "PhotoPionProduction:IR"; + setDescription("PhotoPionProduction:IR"); init(getDataPath("PhotoPionProduction/ir.txt")); break; case CMBIR: - name = "PhotoPionProduction:CMBIR"; + setDescription("PhotoPionProduction:CMBIR"); init(getDataPath("PhotoPionProduction/cmbir.txt")); break; } } -std::string PhotoPionProduction::getDescription() const { - return name; -} - void PhotoPionProduction::init(std::string filename) { std::ifstream infile(filename.c_str()); if (!infile.good()) @@ -76,7 +71,8 @@ PhotoPionProduction::~PhotoPionProduction() { gsl_interp_accel_free(acc); } -bool PhotoPionProduction::setNextInteraction(Candidate *candidate) const { +bool PhotoPionProduction::setNextInteraction(Candidate *candidate, + InteractionState &interaction) const { double z = candidate->getRedshift(); double E = candidate->current.getEnergy(); int A = candidate->current.getMassNumber(); @@ -90,7 +86,6 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate) const { // find interaction with minimum random distance // check for interaction on protons - InteractionState interaction; interaction.distance = std::numeric_limits::max(); Random &random = Random::instance(); if (Z > 0) { @@ -119,13 +114,13 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate) const { return false; } - candidate->setInteractionState(name, interaction); + candidate->setInteractionState(getDescription(), interaction); return true; } void PhotoPionProduction::performInteraction(Candidate *candidate) const { InteractionState interaction; - candidate->getInteractionState(name, interaction); + candidate->getInteractionState(getDescription(), interaction); candidate->clearInteractionStates(); // charge number loss of interaction nucleus @@ -154,7 +149,7 @@ void PhotoPionProduction::performInteraction(Candidate *candidate) const { void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { InteractionState interaction; - candidate->getInteractionState(name, interaction); + candidate->getInteractionState(getDescription(), interaction); candidate->clearInteractionStates(); int dZ = interaction.channel; // charge number loss of interacting nucleus diff --git a/src/module/StochasticInteraction.cpp b/src/module/StochasticInteraction.cpp index 1009092b5..5d0932cd9 100644 --- a/src/module/StochasticInteraction.cpp +++ b/src/module/StochasticInteraction.cpp @@ -2,31 +2,25 @@ namespace mpc { -StochasticInteraction::StochasticInteraction(std::string name) : - name(name) { -} - void StochasticInteraction::process(Candidate* candidate) const { double step = candidate->getCurrentStep(); InteractionState interaction; while (true) { // check if an interaction is set - bool noState = !candidate->getInteractionState(name, interaction); + bool noState = !candidate->getInteractionState(getDescription(), interaction); if (noState) { // try to set a new interaction - bool successful = setNextInteraction(candidate); + bool successful = setNextInteraction(candidate, interaction); if (not (successful)) - return; - // get the new interaction - candidate->getInteractionState(name, interaction); + return; // no new interaction for this particle } // if not over, reduce distance and return if (interaction.distance > step) { interaction.distance -= step; candidate->limitNextStep(interaction.distance); - candidate->setInteractionState(name, interaction); + candidate->setInteractionState(getDescription(), interaction); return; } diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 4784acee7..e440e3656 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -131,6 +131,7 @@ TEST(NuclearDecay, He5) { TEST(NuclearDecay, LimitNextStep) { // test if nextStep is limited + // the decay length of a neutron at 10 EeV is 93 kpc NuclearDecay d; Candidate candidate; candidate.setNextStep(10 * Mpc); From 3419ba4ef282f409d6fed520a49ee8476607a9c5 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 17 Apr 2012 18:53:42 +0200 Subject: [PATCH 0061/1298] add CMB and IRB support for PhotoDisintegration --- include/mpc/Common.h | 2 +- include/mpc/module/ElectronPairProduction.h | 6 +-- include/mpc/module/PhotoDisintegration.h | 5 ++- include/mpc/module/PhotoPionProduction.h | 2 +- mpi/common.h | 6 +-- src/main.cpp | 4 +- src/module/ElectronPairProduction.cpp | 41 ++++-------------- src/module/PhotoDisintegration.cpp | 45 ++++++++++++++------ src/module/PhotoPionProduction.cpp | 16 +++---- src/openmp.cpp | 4 +- test/testInteraction.cpp | 46 +++++++++++++++++---- 11 files changed, 104 insertions(+), 73 deletions(-) diff --git a/include/mpc/Common.h b/include/mpc/Common.h index a6075cd2c..d1d612beb 100644 --- a/include/mpc/Common.h +++ b/include/mpc/Common.h @@ -15,7 +15,7 @@ inline int digit(const int &value, const int &d) { // Photon fields enum PhotonField { - CMB, IR, CMBIR + CMB, IRB, CMB_IRB }; } // namespace mpc diff --git a/include/mpc/module/ElectronPairProduction.h b/include/mpc/module/ElectronPairProduction.h index a1e67e27b..631d9e1d1 100644 --- a/include/mpc/module/ElectronPairProduction.h +++ b/include/mpc/module/ElectronPairProduction.h @@ -2,9 +2,9 @@ #define ELECTRONPAIRPRODUCTION_H_ #include "mpc/Module.h" +#include "mpc/Common.h" #include -#include namespace mpc { @@ -22,11 +22,9 @@ class ElectronPairProduction: public Module { std::vector x; // energy table in [J] public: - ElectronPairProduction(int photonField); - ElectronPairProduction(); + ElectronPairProduction(int photonField = CMB_IRB); void init(int photonField); void init(std::string filename); - std::string getDescription() const; void process(Candidate *candidate) const; }; diff --git a/include/mpc/module/PhotoDisintegration.h b/include/mpc/module/PhotoDisintegration.h index bb6227df8..321a53882 100644 --- a/include/mpc/module/PhotoDisintegration.h +++ b/include/mpc/module/PhotoDisintegration.h @@ -20,6 +20,7 @@ namespace mpc { */ class PhotoDisintegration: public StochasticInteraction { private: + int photonField; struct DisintegrationMode { int channel; // number of emitted (n, p, H2, H3, He3, He4) gsl_spline *rate; // disintegration rate [1/m] @@ -30,8 +31,10 @@ class PhotoDisintegration: public StochasticInteraction { gsl_interp_accel *acc; public: - PhotoDisintegration(); + PhotoDisintegration(int photonField = CMB_IRB); ~PhotoDisintegration(); + void init(int photonField); + void init(std::string filename); bool setNextInteraction(Candidate *candidate, InteractionState &interaction) const; void performInteraction(Candidate *candidate) const; diff --git a/include/mpc/module/PhotoPionProduction.h b/include/mpc/module/PhotoPionProduction.h index 3d29e702c..eaf9d676f 100644 --- a/include/mpc/module/PhotoPionProduction.h +++ b/include/mpc/module/PhotoPionProduction.h @@ -25,7 +25,7 @@ class PhotoPionProduction: public StochasticInteraction { double Emin, Emax; public: - PhotoPionProduction(int photonField); + PhotoPionProduction(int photonField = CMB_IRB); ~PhotoPionProduction(); void init(int photonField); void init(std::string filename); diff --git a/mpi/common.h b/mpi/common.h index c4365d245..519764b63 100644 --- a/mpi/common.h +++ b/mpi/common.h @@ -1,5 +1,5 @@ -#ifndef COMMON_H_ -#define COMMON_H_ +#ifndef COMMONMPI_H_ +#define COMMONMPI_H_ #define TAG_WORK 1 #define TAG_STOP 2 @@ -10,4 +10,4 @@ typedef int job_t; typedef double unit_result_t; -#endif /* COMMON_H_ */ +#endif /* COMMONMPI_H_ */ diff --git a/src/main.cpp b/src/main.cpp index 9d3f94cc8..f99e8cb3d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,8 +35,8 @@ int main(int argc, char **argv) { // interactions ------------------------------------------------------- chain.add(10, new NuclearDecay()); chain.add(11, new PhotoDisintegration()); - chain.add(12, new ElectronPairProduction(CMBIR)); - chain.add(13, new PhotoPionProduction(CMBIR)); + chain.add(12, new ElectronPairProduction()); + chain.add(13, new PhotoPionProduction()); // break conditions --------------------------------------------------- chain.add(20, new MaximumTrajectoryLength(50 * Mpc)); diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 489c9d507..00f365fbe 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -1,7 +1,6 @@ #include "mpc/module/ElectronPairProduction.h" #include -#include #include #include @@ -11,22 +10,23 @@ ElectronPairProduction::ElectronPairProduction(int photonField) { init(photonField); } -ElectronPairProduction::ElectronPairProduction() { - init(CMBIR); -} - void ElectronPairProduction::init(int photonField) { this->photonField = photonField; switch (photonField) { case CMB: + setDescription("ElectronPairProduction:CMB"); init(getDataPath("ElectronPairProduction/cmb.txt")); break; - case IR: + case IRB: + setDescription("ElectronPairProduction:IRB"); init(getDataPath("ElectronPairProduction/ir.txt")); break; - case CMBIR: + case CMB_IRB: + setDescription("ElectronPairProduction:CMB_IRB"); init(getDataPath("ElectronPairProduction/cmbir.txt")); break; + default: + throw std::runtime_error("mpc::ElectronPairProduction: unknown photon background"); } } @@ -42,37 +42,14 @@ void ElectronPairProduction::init(std::string filename) { if (infile.peek() != '#') { double a, b; infile >> a >> b; - if (infile) { - x.push_back(a * eV); - y.push_back(b * eV / Mpc); - } + x.push_back(a * eV); + y.push_back(b * eV / Mpc); } infile.ignore(std::numeric_limits::max(), '\n'); } infile.close(); } -std::string ElectronPairProduction::getDescription() const { - switch (photonField) { - case CMB: { - return "Electron-pair production on CMB"; - break; - } - case IR: { - return "Electron-pair production on IB"; - break; - } - case CMBIR: { - return "Electron-pair production on CMB + IR"; - break; - } - default: { - return "Electron-pair production (unknown)"; - break; - } - } -} - void ElectronPairProduction::process(Candidate *candidate) const { double A = candidate->current.getMassNumber(); double E = candidate->current.getEnergy(); diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 84bf0e8a4..1da6eda8a 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -14,24 +14,44 @@ enum _Constants { SAMPLE_COUNT = 200 }; -PhotoDisintegration::PhotoDisintegration() { - setDescription("PhotoDisintegration"); +PhotoDisintegration::PhotoDisintegration(int photonField) { + init(photonField); +} + +void PhotoDisintegration::init(int photonField) { + this->photonField = photonField; + switch (photonField) { + case CMB: + setDescription("PhotoDisintegration:CMB"); + init(getDataPath("PhotoDisintegration/PDtable_CMB.txt")); + break; + case IRB: + setDescription("PhotoDisintegration:IRB"); + init(getDataPath("PhotoDisintegration/PDtable_IRB.txt")); + break; + case CMB_IRB: + setDescription("PhotoDisintegration:CMB_IRB"); + init(getDataPath("PhotoDisintegration/PDtable_CMB_IRB.txt")); + break; + default: + throw std::runtime_error("mpc::PhotoDisintegration: unknown photon background"); + } +} + +void PhotoDisintegration::init(std::string filename) { + std::ifstream infile(filename.c_str()); + acc = gsl_interp_accel_alloc(); // create spline x-axis std::vector x(SAMPLE_COUNT); - for (size_t i = 0; i < 200; i++) { + for (size_t i = 0; i < 200; i++) x[i] = 6.0 + i * 8.0 / (SAMPLE_COUNT - 1); - } std::vector y(SAMPLE_COUNT); - // load photo-disintegration table - std::string filename = getDataPath("PhotoDisintegration/pd_table.txt"); - std::ifstream infile(filename.c_str()); - if (!infile.good()) - throw std::runtime_error("mpc::PhotoDisitegration: could not open file " + filename); + throw std::runtime_error("mpc::PhotoDisintegration: could not open file " + filename); std::string line; size_t lineNo = 0; @@ -41,8 +61,9 @@ PhotoDisintegration::PhotoDisintegration() { continue; std::stringstream lineStream(line); - int id = 0; - lineStream >> id; // nucleus id + int Z, A; + lineStream >> Z; // charge number + lineStream >> A; // mass number DisintegrationMode mode; lineStream >> mode.channel; // disintegration channel @@ -61,7 +82,7 @@ PhotoDisintegration::PhotoDisintegration() { mode.rate = gsl_spline_alloc(gsl_interp_linear, SAMPLE_COUNT); gsl_spline_init(mode.rate, &x[0], &y[0], SAMPLE_COUNT); - PDTable[id].push_back(mode); + PDTable[getNucleusId(A, Z)].push_back(mode); } infile.close(); diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index d259ba12d..377cc45ad 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -20,14 +20,16 @@ void PhotoPionProduction::init(int photonField) { setDescription("PhotoPionProduction:CMB"); init(getDataPath("PhotoPionProduction/cmb.txt")); break; - case IR: - setDescription("PhotoPionProduction:IR"); + case IRB: + setDescription("PhotoPionProduction:IRB"); init(getDataPath("PhotoPionProduction/ir.txt")); break; - case CMBIR: - setDescription("PhotoPionProduction:CMBIR"); + case CMB_IRB: + setDescription("PhotoPionProduction:CMB_IRB"); init(getDataPath("PhotoPionProduction/cmbir.txt")); break; + default: + throw std::runtime_error("mpc::PhotoPionProduction: unknown photon background"); } } @@ -171,12 +173,12 @@ void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { case CMB: background = 1; break; - case IR: + case IRB: background = 2; break; - case CMBIR: + case CMB_IRB: throw std::runtime_error( - "mpc::SophiaPhotoPionProduction: CMBIR not possible for SophiaPhotoPionProduction"); + "mpc::SophiaPhotoPionProduction: CMB_IRB not possible for SophiaPhotoPionProduction"); break; } double maxRedshift = 100; // IR photon density is zero above this redshift diff --git a/src/openmp.cpp b/src/openmp.cpp index 87799c8cd..84f3c3eaa 100644 --- a/src/openmp.cpp +++ b/src/openmp.cpp @@ -25,8 +25,8 @@ int main(int argc, char **argv) { modules.add(new DeflectionCK(field)); modules.add(new NuclearDecay()); modules.add(new PhotoDisintegration()); - modules.add(new ElectronPairProduction(CMBIR)); - modules.add(new PhotoPionProduction(CMBIR)); + modules.add(new ElectronPairProduction()); + modules.add(new PhotoPionProduction()); modules.add(new MaximumTrajectoryLength(50 * Mpc)); modules.add(new MinimumEnergy(5 * EeV)); diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index e440e3656..6d787cdba 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -23,7 +23,7 @@ TEST(ElectronPairProduction, EnergyDecreasing) { EXPECT_TRUE(candidate.current.getEnergy() <= E); } - ElectronPairProduction epp2(IR); + ElectronPairProduction epp2(IRB); for (int i = 0; i < 80; i++) { double E = pow(10, 15 + i * 0.1) * eV; candidate.current.setEnergy(E); @@ -31,7 +31,7 @@ TEST(ElectronPairProduction, EnergyDecreasing) { EXPECT_TRUE(candidate.current.getEnergy() < E); } - ElectronPairProduction epp3(CMBIR); + ElectronPairProduction epp3(CMB_IRB); for (int i = 0; i < 80; i++) { double E = pow(10, 15 + i * 0.1) * eV; candidate.current.setEnergy(E); @@ -141,6 +141,14 @@ TEST(NuclearDecay, LimitNextStep) { EXPECT_TRUE(candidate.getNextStep() < 10 * Mpc); } + + +TEST(PhotoDisintegration, Backgrounds) { + PhotoPionProduction ppp1(CMB); + PhotoPionProduction ppp2(IRB); + PhotoPionProduction ppp3(CMB_IRB); +} + TEST(PhotoDisintegration, Carbon) { PhotoDisintegration pd; Candidate candidate; @@ -162,18 +170,30 @@ TEST(PhotoDisintegration, Iron) { pd.process(&candidate); EXPECT_TRUE(candidate.current.getMassNumber() < 56); EXPECT_TRUE(candidate.current.getEnergy() < 200 * EeV); + EXPECT_TRUE(candidate.secondaries.size() > 0); +} + +TEST(PhotoDisintegration, LimitNextStep) { + // test if nextStep is limited + PhotoDisintegration pd; + Candidate candidate; + candidate.setNextStep(100 * Mpc); + candidate.current.setId(getNucleusId(4, 2)); + candidate.current.setEnergy(200 * EeV); + pd.process(&candidate); + EXPECT_TRUE(candidate.getNextStep() < 100 * Mpc); } TEST(PhotoPionProduction, Backgrounds) { PhotoPionProduction ppp1(CMB); - PhotoPionProduction ppp2(IR); - PhotoPionProduction ppp3(CMBIR); + PhotoPionProduction ppp2(IRB); + PhotoPionProduction ppp3(CMB_IRB); } TEST(PhotoPionProduction, Proton) { - PhotoPionProduction ppp(CMBIR); + PhotoPionProduction ppp; Candidate candidate; candidate.setCurrentStep(100 * Mpc); candidate.current.setId(getNucleusId(1, 1)); @@ -184,17 +204,27 @@ TEST(PhotoPionProduction, Proton) { } TEST(PhotoPionProduction, Helium) { - PhotoPionProduction ppp(CMBIR); + PhotoPionProduction ppp; Candidate candidate; candidate.setCurrentStep(100 * Mpc); candidate.current.setId(getNucleusId(4, 2)); - candidate.current.setEnergy(300 * EeV); + candidate.current.setEnergy(400 * EeV); ppp.process(&candidate); EXPECT_TRUE(candidate.current.getEnergy() / EeV < 300); EXPECT_TRUE(candidate.current.getMassNumber() < 4); + EXPECT_TRUE(candidate.secondaries.size() > 0); } - +TEST(PhotoPionProduction, LimitNextStep) { + // test if nextStep is limited + PhotoPionProduction ppp; + Candidate candidate; + candidate.setNextStep(100 * Mpc); + candidate.current.setId(getNucleusId(1, 1)); + candidate.current.setEnergy(200 * EeV); + ppp.process(&candidate); + EXPECT_TRUE(candidate.getNextStep() < 100 * Mpc); +} int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); From 5216fc736035f018ed2eb4e0d56258e0cca4d5e7 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 17 Apr 2012 19:34:17 +0200 Subject: [PATCH 0062/1298] change interpolation to GSL in ElectronPairProduction --- include/mpc/module/ElectronPairProduction.h | 10 +++--- src/module/ElectronPairProduction.cpp | 36 ++++++++++++--------- src/module/PhotoPionProduction.cpp | 3 +- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/include/mpc/module/ElectronPairProduction.h b/include/mpc/module/ElectronPairProduction.h index 631d9e1d1..060334e24 100644 --- a/include/mpc/module/ElectronPairProduction.h +++ b/include/mpc/module/ElectronPairProduction.h @@ -4,7 +4,8 @@ #include "mpc/Module.h" #include "mpc/Common.h" -#include +#include +#include namespace mpc { @@ -16,10 +17,11 @@ namespace mpc { Several photon fields can be selected. They are considered as homogeneous and evolving as the CMB. */ class ElectronPairProduction: public Module { -protected: +private: int photonField; - std::vector y; // energy loss rate table for protons in [J/m] - std::vector x; // energy table in [J] + gsl_interp_accel *acc; + gsl_spline *lossRate; // energy loss rate in [J/m] + double xMin, xMax, yMax; public: ElectronPairProduction(int photonField = CMB_IRB); diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 00f365fbe..7f9f13b64 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -26,7 +26,8 @@ void ElectronPairProduction::init(int photonField) { init(getDataPath("ElectronPairProduction/cmbir.txt")); break; default: - throw std::runtime_error("mpc::ElectronPairProduction: unknown photon background"); + throw std::runtime_error( + "mpc::ElectronPairProduction: unknown photon background"); } } @@ -38,16 +39,26 @@ void ElectronPairProduction::init(std::string filename) { throw std::runtime_error( "mpc::ElectronPairProduction: could not open file " + filename); + std::vector x, y; while (infile.good()) { if (infile.peek() != '#') { double a, b; infile >> a >> b; - x.push_back(a * eV); - y.push_back(b * eV / Mpc); + if (infile) { + x.push_back(a * eV); + y.push_back(b * eV / Mpc); + } } infile.ignore(std::numeric_limits::max(), '\n'); } infile.close(); + + acc = gsl_interp_accel_alloc(); + lossRate = gsl_spline_alloc(gsl_interp_linear, x.size()); + gsl_spline_init(lossRate, &x[0], &y[0], x.size()); + xMin = x.front(); + xMax = x.back(); + yMax = y.back(); } void ElectronPairProduction::process(Candidate *candidate) const { @@ -55,23 +66,16 @@ void ElectronPairProduction::process(Candidate *candidate) const { double E = candidate->current.getEnergy(); double z = candidate->getRedshift(); - // energy per nucleon - double xi = E / A * (1 + z); - - // no data for EpA < 10^15 eV - if (xi < 1.e15 * eV) + double EpA = E / A * (1 + z); + if (EpA < xMin) return; double rate; - if (xi < 1.e22 * eV) { - // index of next lower energy bin - int i = floor(log10(xi / x[0]) * 69 / 7); - // linear interpolation: y(x) = y0 + dy/dx * (x-x0) - rate = y[i] + (y[i + 1] - y[i]) / (x[i + 1] - x[i]) * (xi - x[i]); - } else { + if (EpA < xMax) + rate = gsl_spline_eval(lossRate, EpA, acc); + else // extrapolation for higher energies - rate = y[69] * pow(xi / x[69], 0.4); - } + rate = yMax * pow(EpA / xMax, 0.4); // dE(E) = Z^2 * loss_rate(E/A) * step double step = candidate->getCurrentStep(); diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 377cc45ad..067bb0aaa 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -29,7 +29,8 @@ void PhotoPionProduction::init(int photonField) { init(getDataPath("PhotoPionProduction/cmbir.txt")); break; default: - throw std::runtime_error("mpc::PhotoPionProduction: unknown photon background"); + throw std::runtime_error( + "mpc::PhotoPionProduction: unknown photon background"); } } From 537732c4efa6ce1cf2a159143a22a2b61581812b Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 19 Apr 2012 14:12:50 +0200 Subject: [PATCH 0063/1298] remove untested error control types in DeflectionCK --- include/mpc/module/DeflectionCK.h | 8 +------ src/module/DeflectionCK.cpp | 39 +++++++++++-------------------- test/python/testDeflectionCK.py | 2 +- 3 files changed, 15 insertions(+), 34 deletions(-) diff --git a/include/mpc/module/DeflectionCK.h b/include/mpc/module/DeflectionCK.h index 469f0390c..6313fe086 100644 --- a/include/mpc/module/DeflectionCK.h +++ b/include/mpc/module/DeflectionCK.h @@ -20,15 +20,9 @@ class DeflectionCK: public Module { public: ref_ptr field; ExplicitRungeKutta erk; - enum ControlType { - NoStepSizeControl, WorstOffender, RMS - }; - ControlType controlType; double tolerance, minimumStep; - DeflectionCK(MagneticField *field, double tolerance = 1e-4, - ControlType controlType = WorstOffender, - double minimumStep = 0.1 * kpc); + DeflectionCK(MagneticField *field, double tolerance = 1e-4, double minimumStep = 0.1 * kpc); std::string getDescription() const; void process(Candidate *candidate) const; }; diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index 9f0ebf576..5f0722232 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -37,11 +37,9 @@ class LorentzForce: public ExplicitRungeKutta::F { } }; -DeflectionCK::DeflectionCK(MagneticField *field, double tolerance, - ControlType controlType, double minimumStep) { +DeflectionCK::DeflectionCK(MagneticField *field, double tolerance, double minimumStep) { this->field = field; this->tolerance = tolerance; - this->controlType = controlType; this->minimumStep = minimumStep; erk.loadCashKarp(); } @@ -55,6 +53,7 @@ std::string DeflectionCK::getDescription() const { } void DeflectionCK::process(Candidate *candidate) const { + // rectlinear propagation in case of no charge if (candidate->current.getChargeNumber() == 0) { double nextStep = std::max(minimumStep, candidate->getNextStep()); Vector3 pos = candidate->current.getPosition(); @@ -78,31 +77,19 @@ void DeflectionCK::process(Candidate *candidate) const { do { hTry = h; erk.step(0, yIn, yOut, yErr, hTry, dydt); - if (controlType == NoStepSizeControl) { - // no step size control - break; - } else if (controlType == WorstOffender) { - // maximum of ratio yErr(i) / yScale(i) - r = 0; - if (yScale.b.x() > std::numeric_limits::min()) - r = std::max(r, fabs(yErr.b.x() / yScale.b.x())); - if (yScale.b.y() > std::numeric_limits::min()) - r = std::max(r, fabs(yErr.b.y() / yScale.b.y())); - if (yScale.b.z() > std::numeric_limits::min()) - r = std::max(r, fabs(yErr.b.z() / yScale.b.z())); - } else if (controlType == RMS) { - // RMS of ratio yErr(i) / yScale(i) - r = 0; - if (yScale.b.x() > std::numeric_limits::min()) - r += pow(yErr.b.x() / (yScale.b.x()), 2); - if (yScale.b.y() > std::numeric_limits::min()) - r += pow(yErr.b.y() / (yScale.b.y()), 2); - if (yScale.b.z() > std::numeric_limits::min()) - r += pow(yErr.b.z() / (yScale.b.z()), 2); - r = pow(r / 3., 0.5); - } + + // maximum of ratio yErr(i) / yScale(i) + r = 0; + if (yScale.b.x() > std::numeric_limits::min()) + r = std::max(r, fabs(yErr.b.x() / yScale.b.x())); + if (yScale.b.y() > std::numeric_limits::min()) + r = std::max(r, fabs(yErr.b.y() / yScale.b.y())); + if (yScale.b.z() > std::numeric_limits::min()) + r = std::max(r, fabs(yErr.b.z() / yScale.b.z())); + // for efficient integration try to keep r close to one h *= 0.95 * pow(r, -0.2); + // limit step change h = std::max(h, 0.1 * hTry); h = std::min(h, 5 * hTry); diff --git a/test/python/testDeflectionCK.py b/test/python/testDeflectionCK.py index 25ebab205..17d2513d2 100644 --- a/test/python/testDeflectionCK.py +++ b/test/python/testDeflectionCK.py @@ -16,7 +16,7 @@ def propagate(tolerance): - prop = DeflectionCK(field, tolerance, DeflectionCK.WorstOffender, 0.1 * kpc) + prop = DeflectionCK(field, tolerance, 0.1 * kpc) maxLen = MaximumTrajectoryLength(2 * pi * R) c.setTrajectoryLength(0) From 954f686e1cd9174f53c72896b9d4b72bb496b19b Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 19 Apr 2012 14:18:17 +0200 Subject: [PATCH 0064/1298] remove GlutDisplay --- CMakeLists.txt | 10 -- include/mpc/module/GlutDisplay.h | 28 ----- mpi/Slave.cpp | 1 - python/mpc.i | 4 +- src/XMLImport.cpp | 16 --- src/main.cpp | 2 - src/module/GlutDisplay.cpp | 183 ------------------------------- 7 files changed, 1 insertion(+), 243 deletions(-) delete mode 100644 include/mpc/module/GlutDisplay.h delete mode 100644 src/module/GlutDisplay.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 471469de4..1281f7c64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,16 +29,6 @@ if (GADGET_FOUND) list( APPEND MPC_SWIG_DEFINES -DMPC_HAVE_GADGET) endif (GADGET_FOUND) -# freeglut and GLU needed for GlutDisplay -find_package(FreeGlut) -find_package(OpenGl) -if (Freeglut_FOUND) - if (OPENGL_GLU_FOUND) - list( APPEND MPC_EXTRA_SOURCES src/module/GlutDisplay.cpp) - list( APPEND MPC_EXTRA_LIBRARIES ${Freeglut_LIBRARIES} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY}) - endif (OPENGL_GLU_FOUND) -endif (Freeglut_FOUND) - # Google Performance Tools find_package(GooglePerfTools) SET(TCMALLOC) diff --git a/include/mpc/module/GlutDisplay.h b/include/mpc/module/GlutDisplay.h deleted file mode 100644 index 228eae516..000000000 --- a/include/mpc/module/GlutDisplay.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef GLUTDISPLAY_H_ -#define GLUTDISPLAY_H_ - -#include "mpc/ModuleChain.h" - -namespace mpc { - -/** - @class GlutDisplay - @brief Visualization of the particle trajectory. - - This module displays the particle trajectory in an interactive window. - */ -class GlutDisplay: public Module { -public: - int counter; - - GlutDisplay(); - ~GlutDisplay(); - - void process(Candidate *candidate) const; - std::string getDescription() const; -}; - -} // namspace mpc - -#endif /* GLUTDISPLAY_H_ */ - diff --git a/mpi/Slave.cpp b/mpi/Slave.cpp index 1de3f8265..346155e6c 100644 --- a/mpi/Slave.cpp +++ b/mpi/Slave.cpp @@ -8,7 +8,6 @@ #include "mpc/Common.h" #include "mpc/module/DeflectionCK.h" #include "mpc/module/BreakCondition.h" -#include "mpc/module/GlutDisplay.h" #include "mpc/module/Output.h" #include "mpc/module/ElectronPairProduction.h" #include "mpc/module/PhotoPionProduction.h" diff --git a/python/mpc.i b/python/mpc.i index b5e4611c2..eb9631af9 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -38,7 +38,6 @@ #include "mpc/module/Output.h" #include "mpc/module/SimplePropagation.h" #include "mpc/module/DeflectionCK.h" -#include "mpc/module/GlutDisplay.h" #include "mpc/module/Tools.h" #include "mpc/magneticField/magneticField.h" @@ -50,12 +49,12 @@ #include "mpc/Referenced.h" #include "mpc/Candidate.h" #include "mpc/ParticleState.h" +#include "mpc/Nucleus.h" #include "mpc/Module.h" #include "mpc/ModuleChain.h" #include "mpc/ModuleList.h" #include "mpc/PhasePoint.h" #include "mpc/ExplicitRungeKutta.h" -#include "mpc/Nucleus.h" #include "mpc/Random.h" #include "mpc/Units.h" #include "mpc/Vector3.h" @@ -108,7 +107,6 @@ %include "mpc/module/PhotoPionProduction.h" %include "mpc/module/PhotoDisintegration.h" %include "mpc/module/Redshift.h" -%include "mpc/module/GlutDisplay.h" %include "mpc/module/Tools.h" %include "mpc/ModuleChain.h" %include "mpc/ModuleList.h" diff --git a/src/XMLImport.cpp b/src/XMLImport.cpp index 34680430e..7efeb34e9 100644 --- a/src/XMLImport.cpp +++ b/src/XMLImport.cpp @@ -3,7 +3,6 @@ #include "mpc/magneticField/magneticField.h" #include "mpc/magneticField/uniformMagneticField.h" #include "mpc/module/DeflectionCK.h" -#include "mpc/module/GlutDisplay.h" #include "pugixml.hpp" @@ -88,21 +87,6 @@ class DeflectionCKProducer: public ModuleProducer { } }; -class GlutDislpayProducer: public ModuleProducer { -public: - - GlutDislpayProducer() : - ModuleProducer("GluDisplay") { - - } - - Module *create(pugi::xml_node &module) { - return new GlutDisplay(); - } -}; - -static GlutDislpayProducer _glut_display_producer; - static DeflectionCKProducer _deflection_ck_producer; } // namespace mpc diff --git a/src/main.cpp b/src/main.cpp index f99e8cb3d..958425ccc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,7 +5,6 @@ #include "mpc/module/SimplePropagation.h" #include "mpc/module/DeflectionCK.h" #include "mpc/module/BreakCondition.h" -#include "mpc/module/GlutDisplay.h" #include "mpc/module/Output.h" #include "mpc/module/ElectronPairProduction.h" #include "mpc/module/PhotoPionProduction.h" @@ -43,7 +42,6 @@ int main(int argc, char **argv) { // output ------------------------------------------------------------- chain.add(79, new ShellOutput()); - //chain.add(80, new GlutDisplay()); std::cout << chain << std::endl; diff --git a/src/module/GlutDisplay.cpp b/src/module/GlutDisplay.cpp deleted file mode 100644 index 5984e7758..000000000 --- a/src/module/GlutDisplay.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include -#include -#include -#include -#include - -#include "mpc/module/GlutDisplay.h" -#include "mpc/ParticleState.h" - -namespace mpc { - -std::vector points; - -// Viewer state -int refreshAfter = 5; -float cameraPhi = 45.0; -float cameraTheta = 90.0; -float cameraDepth = 10; -bool leftButton = false; -bool middleButton = false; -int downX; -int downY; -float windowWidth = 500; -float windowHeight = 500; -bool continueDisplay; - -void keyboard(unsigned char key, int x, int y) { - switch (key) { - case 13: // enter - continueDisplay = 0; - break; - case 27: // escape - break; - case 32: // space - continueDisplay = 0; - break; - } -} - -void mouseButton(int button, int state, int x, int y) { - // mouse position at moment of button press - downX = x; - downY = y; - // mouse buttons - leftButton = ((button == 0) && (state == 0)); - middleButton = ((button == 1) && (state == 0)); - // scroll wheel - if (button == 3) - cameraDepth -= 0.5; - if (button == 4) - cameraDepth += 0.5; - glutPostRedisplay(); -} - -void mouseMove(int x, int y) { - // rotate - if (leftButton) { - cameraPhi += (float) (x - downX) / 4.0; - cameraTheta += (float) (downY - y) / 4.0; - } - // zoom - if (middleButton) { - cameraDepth += (float) (downY - y) / 10.0; - } - downX = x; - downY = y; - glutPostRedisplay(); -} - -void drawTrajectoryPoints() { - glColor3f(1., 1., 1.); - for (std::vector::size_type i = 0; i < points.size(); i++) { - Vector3 pos = points[i].getPosition() / Mpc; - glPushMatrix(); - glTranslatef(pos.x(), pos.y(), pos.z()); - glutSolidSphere(0.015, 10, 5); - glPopMatrix(); - } -} - -void display(void) { - glLoadIdentity(); - glTranslatef(0, 0, -cameraDepth); - glRotatef(-cameraTheta, 1.0, 0.0, 0.0); - glRotatef(cameraPhi, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - drawTrajectoryPoints(); - glutSwapBuffers(); -} - -void reshape(int width, int height) { - windowWidth = width; - windowHeight = height; - glViewport(0, 0, width, height); -} - -//int displayMenu, mainMenu; -//enum { -// TIME, ENERGY, CHARGE -//}; -//int displayMode = TIME; -// -//void setMainMenu(int value) { -// switch (value) { -// case 99: -// exit(0); -// break; -// } -//} -// -//void setDisplayMenu(int value) { -// displayMode = value; -// switch (value) { -// case TIME: -// break; -// case ENERGY: -// break; -// case CHARGE: -// break; -// } -// glutPostRedisplay(); -//} - -void initGlutDisplay() { - int argc = 0; - char *argv[1] = { 0 }; - // initialize GLUT and create window - glutInit(&argc, argv); - glutInitWindowSize(windowWidth, windowHeight); - glutCreateWindow("Trajectory Display"); - // register callback functions - glutDisplayFunc(display); - glutReshapeFunc(reshape); - glutKeyboardFunc(keyboard); - glutMouseFunc(mouseButton); - glutMotionFunc(mouseMove); - // camera view - glMatrixMode(GL_PROJECTION); - gluPerspective(64.0, 1., 0., 100.); - glMatrixMode(GL_MODELVIEW); -// // menu -// displayMenu = glutCreateMenu(setDisplayMenu); -// glutAddMenuEntry("Wireframe", WIREFRAME); -// glutAddMenuEntry("Hidden Line", HIDDENLINE); -// glutAddMenuEntry("Flat Shaded", FLATSHADED); -// glutAddMenuEntry("Smooth Shaded", SMOOTHSHADED); -// mainMenu = glutCreateMenu(setMainMenu); -// glutAddSubMenu("Display", displayMenu); -// glutAddMenuEntry("Exit", 99); -// glutAttachMenu(GLUT_RIGHT_BUTTON); -} - -GlutDisplay::GlutDisplay() { - counter = 0; - initGlutDisplay(); -} - -GlutDisplay::~GlutDisplay() { - glutDestroyWindow(glutGetWindow()); -} - -void GlutDisplay::process(Candidate *candidate) const { - - if (counter % refreshAfter == 0) { - // append trajectory point - points.push_back(candidate->current); - - glutPostRedisplay(); - - // wait for user to continue - continueDisplay = 1; - while (continueDisplay == 1) { - glutMainLoopEvent(); - } - } - return; -} - -std::string GlutDisplay::getDescription() const { - return "GlutDisplay"; -} - -} // namspace mpc From 9af43143e3bc170c820dba3e97e0917fa39e6f32 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 19 Apr 2012 14:27:49 +0200 Subject: [PATCH 0065/1298] remove MPI --- CMakeLists.txt | 16 +------ mpi/Job.cpp | 32 -------------- mpi/Job.h | 22 ---------- mpi/Master.cpp | 113 ----------------------------------------------- mpi/Master.h | 31 ------------- mpi/Slave.cpp | 116 ------------------------------------------------- mpi/Slave.h | 23 ---------- mpi/common.h | 13 ------ mpi/main.cpp | 48 -------------------- 9 files changed, 1 insertion(+), 413 deletions(-) delete mode 100644 mpi/Job.cpp delete mode 100644 mpi/Job.h delete mode 100644 mpi/Master.cpp delete mode 100644 mpi/Master.h delete mode 100644 mpi/Slave.cpp delete mode 100644 mpi/Slave.h delete mode 100644 mpi/common.h delete mode 100644 mpi/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1281f7c64..ea54fe3ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,26 +132,12 @@ if (GTEST_FOUND) target_link_libraries(testInteraction mpc ${GTEST_BOTH_LIBRARIES} pthread) endif (GTEST_FOUND) - # ---------------------------------------------------------------------------- -# OpenMP and OpenMPI +# OpenMP # ---------------------------------------------------------------------------- add_executable(mpc-omp-run src/openmp.cpp) TARGET_LINK_LIBRARIES(mpc-omp-run mpc) -# MPI needed for mpc-mpi -find_package(MPI) -if (MPI_FOUND) - include_directories(${MPI_INCLUDE_PATH}) - - set(CMAKE_CXX_COMPILE_FLAGS ${CMAKE_CXX_COMPILE_FLAGS} ${MPI_COMPILE_FLAGS}) - set(CMAKE_CXX_LINK_FLAGS ${CMAKE_CXX_LINK_FLAGS} ${MPI_LINK_FLAGS}) - - add_executable(mpc-mpi-run mpi/main mpi/Slave mpi/Master mpi/Job) - TARGET_LINK_LIBRARIES(mpc-mpi-run mpc ${MPI_LIBRARIES}) -endif() - - # ---------------------------------------------------------------------------- # Python # ---------------------------------------------------------------------------- diff --git a/mpi/Job.cpp b/mpi/Job.cpp deleted file mode 100644 index 243469b01..000000000 --- a/mpi/Job.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "Job.h" - -#include "kiss/convert.h" - -using namespace std; -using namespace kiss; - -Job::Job(job_t job) : - in(in_stream), out(out_stream) { - string in_filename = "job_" + str(job) + ".dat"; - in_stream.open(in_filename.c_str(), ios::binary); - - string out_filename = "job_" + str(job) + "_out.dat"; - out_stream.open(out_filename.c_str(), ios::binary); -} - -size_t processSome(size_t count) { - size_t processed = 0; - while (true) { -// Candidate candidate; -// if (!read(in, candidate)) -// break; -// chain.process(&candidate); -// write(out, candidate); -// processed++; -// for (size_t iSec = 0; iSec < secondaries.size(); iSec++) { -// write(out, *secondaries[iSec]); -// delete secondaries[iSec]; -// } - } - return processed; -} diff --git a/mpi/Job.h b/mpi/Job.h deleted file mode 100644 index 115514e69..000000000 --- a/mpi/Job.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef MPC_JOB_H_ -#define MPC_JOB_H_ - -#include "common.h" - -#include "kiss/io.h" - -#include - -class Job { - std::ifstream in_stream; - kiss::StreamInput in; - - std::ofstream out_stream; - kiss::StreamOutput out; - -public: - Job(job_t job); - size_t processSome(); -}; - -#endif /* MPC_JOB_H_ */ diff --git a/mpi/Master.cpp b/mpi/Master.cpp deleted file mode 100644 index 754dfd63b..000000000 --- a/mpi/Master.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include "Master.h" - -#include "mpc/IO.h" -#include "mpc/Candidate.h" - -#include -#include - -#include - -using namespace std; -using namespace kiss; -using namespace mpc; - -Master::Master() : - _NextJob(0) { - MPI_Comm_size(MPI_COMM_WORLD, &_RankCount); - _Slaves.reserve(_RankCount); -} - -Master::~Master() { -} - -void Master::run() { - sendFirstWorkItem(); - - job_t work = getNextJob(); - size_t total = 1; - while (work != 0) { - - unit_result_t result; - MPI_Status status; - - receiveResult(result, status); - - sendJob(work, status.MPI_SOURCE); - - work = getNextJob(); - total--; - if (total == 0) - break; - } - - receiveOutstandingResults(); - - stopSlaves(); -} - -void Master::receiveResult(unit_result_t &result, MPI_Status &status) { - MPI_Recv(&result, 1, MPI_DOUBLE, MPI_ANY_SOURCE, MPI_ANY_TAG, - MPI_COMM_WORLD, &status); - KISS_LOG_DEBUG - << "receive result '" << result << "' from '" << status.MPI_SOURCE - << "'"; -} - -void Master::sendJob(job_t &job, int rank) { - KISS_LOG_DEBUG - << "sent job '" << job << "' to '" << rank << "'"; - _Slaves[rank].job = job; - Candidate candidate; - ParticleState initial; - initial.setId(getNucleusId(56, 26)); - initial.setEnergy(200 * EeV); - initial.setPosition(Vector3(0, 0, 0)); - initial.setDirection(Vector3(1, 0, 0)); - - candidate.current = initial; - candidate.initial = initial; - candidate.setNextStep(0.01 * Mpc); - - string out_filename = "job_" + str(job) + ".dat"; - ofstream out_stream(out_filename.c_str(), ios::binary); - StreamOutput out(out_stream); - write(out, candidate); - - MPI_Send(&job, 1, MPI_INT, rank, TAG_WORK, MPI_COMM_WORLD); -} - -int Master::getNextJob() { - job_t next = 0; - if (_FreeJobs.size()) { - next = _FreeJobs.back(); - _FreeJobs.pop_back(); - } else { - _NextJob++; - return _NextJob; - } - - return next; -} - -void Master::sendFirstWorkItem() { - for (size_t rank = 1; rank < _RankCount; ++rank) { - job_t work = getNextJob(); - sendJob(work, rank); - } -} - -void Master::receiveOutstandingResults() { - for (size_t rank = 1; rank < _RankCount; ++rank) { - unit_result_t result; - MPI_Status status; - MPI_Recv(&result, 1, MPI_DOUBLE, MPI_ANY_SOURCE, MPI_ANY_TAG, - MPI_COMM_WORLD, &status); - } - -} -void Master::stopSlaves() { - for (size_t rank = 1; rank < _RankCount; ++rank) { - MPI_Send(0, 0, MPI_INT, rank, TAG_STOP, MPI_COMM_WORLD); - } -} diff --git a/mpi/Master.h b/mpi/Master.h deleted file mode 100644 index 701680fc9..000000000 --- a/mpi/Master.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef MASTER_H_ -#define MASTER_H_ - -#include "common.h" - -#include - -#include - -class Master { - struct SlaveInfo { - job_t job; - }; - std::vector _FreeJobs; - std::vector _Slaves; - job_t _NextJob; - int _RankCount; - - void sendFirstWorkItem(); - int getNextJob(); - void stopSlaves(); - void receiveOutstandingResults(); - void receiveResult(unit_result_t &result, MPI_Status &status); - void sendJob(job_t &work, int rank); -public: - Master(); - virtual ~Master(); - void run(); -}; - -#endif /* MASTER_H_ */ diff --git a/mpi/Slave.cpp b/mpi/Slave.cpp deleted file mode 100644 index 346155e6c..000000000 --- a/mpi/Slave.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "Slave.h" - -#include "mpc/IO.h" -#include "mpc/XMLImport.h" -#include "mpc/ModuleChain.h" -#include "mpc/Vector3.h" -#include "mpc/Units.h" -#include "mpc/Common.h" -#include "mpc/module/DeflectionCK.h" -#include "mpc/module/BreakCondition.h" -#include "mpc/module/Output.h" -#include "mpc/module/ElectronPairProduction.h" -#include "mpc/module/PhotoPionProduction.h" -#include "mpc/module/PhotoDisintegration.h" -#include "mpc/module/NuclearDecay.h" -#include "mpc/magneticField/uniformMagneticField.h" -#include "mpc/magneticField/turbulentMagneticFieldGrid.h" - -#include - -#include -#include - -using namespace mpc; -using namespace std; -using namespace kiss; - -Slave::Slave() : - running(true) { -} - -Slave::~Slave() { -} - -void Slave::load(const string &filename) { -// XMLImport import(&chain); -// import.import(filename); - UniformMagneticField *field = new UniformMagneticField( - Vector3(0., 0., 1e-20)); - chain.add(25, new DeflectionCK(field)); - - // interactions ------------------------------------------------------- - chain.add(30, new NuclearDecay()); - chain.add(31, new PhotoDisintegration()); -// chain.add(32, new ElectronPairProduction(CMBIR)); -// chain.add(33, new PhotoPionProduction(CMBIR)); - - // output ------------------------------------------------------------- - chain.add(79, new ShellOutput()); -// chain.add(new TrajectoryOutput("trajectories.csv"), 80); - chain.add(100, new ConditionalOutput("final.txt", "Detected")); - } - -void Slave::acquireJob() { - job_t job; - double result; - MPI_Status status; - - MPI_Send(0, 0, MPI_DATATYPE_NULL, 0, TAG_REQUEST_JOB, MPI_COMM_WORLD); - MPI_Recv(&job, 1, MPI_INT, 0, MPI_ANY_TAG, MPI_COMM_WORLD, &status); - - if (status.MPI_TAG == TAG_STOP) { - running = false; - } else if (status.MPI_TAG == TAG_WORK) { - processJob(job); - MPI_Send(&result, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD); - } else { - printf("unknown tag"); - } -} - -void Slave::run() { - while (running) - acquireJob(); -} - -struct JobInfo { - Vector3 partition_offset; - double partition_size, partition_margin; -}; - -void Slave::processJob(job_t job) { - - // any local jobs available? - // otherwise ask master/other ranks - - // collect particles - // process job - // store particles for each block in files - // register job at master - - string in_filename = "job_" + str(job) + ".dat"; - ifstream in_stream(in_filename.c_str(), ios::binary); - StreamInput in(in_stream); - - string out_filename = "job_" + str(job) + "_out.dat"; - ofstream out_stream(out_filename.c_str(), ios::binary); - StreamOutput out(out_stream); - -// JobInfo info; -// in.read((char *) &info, sizeof(info)); -// chain.setSimulationPartition(info.partition_offset, info.partition_size, -// info.partition_margin); - while (true) { - Candidate candidate; - if (!read(in, candidate)) - break; - chain.process(&candidate); - write(out, candidate); -// for (size_t iSec = 0; iSec < secondaries.size(); iSec++) { -// write(out, *secondaries[iSec]); -// delete secondaries[iSec]; -// } - } - -} diff --git a/mpi/Slave.h b/mpi/Slave.h deleted file mode 100644 index 3af941562..000000000 --- a/mpi/Slave.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef SLAVE_H_ -#define SLAVE_H_ - -#include "common.h" - -#include "mpc/ModuleChain.h" - -#include - -class Slave { - bool running; - mpc::ModuleChain chain; - void processJob(job_t job); - void acquireJob(); -public: - Slave(); - virtual ~Slave(); - - void load(const std::string &filename); - void run(); -}; - -#endif /* SLAVE_H_ */ diff --git a/mpi/common.h b/mpi/common.h deleted file mode 100644 index 519764b63..000000000 --- a/mpi/common.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef COMMONMPI_H_ -#define COMMONMPI_H_ - -#define TAG_WORK 1 -#define TAG_STOP 2 -#define TAG_SLEEP 3 -#define TAG_REQUEST_JOB 4 -#define TAG_RECEIVE_JOB 5 - -typedef int job_t; -typedef double unit_result_t; - -#endif /* COMMONMPI_H_ */ diff --git a/mpi/main.cpp b/mpi/main.cpp deleted file mode 100644 index 14382c5a9..000000000 --- a/mpi/main.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "Slave.h" -#include "Master.h" - -#include -#include - -#include - -#include -#include -#include - -using namespace kiss; -using namespace std; - -int main(int argc, char **argv) { - if (argc < 2) { - cout << "Usage: mpc-mpi " << endl; - return 1; - } - - MPI_Init(&argc, &argv); - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - string filename = "log-" + str(rank) + ".txt"; - ofstream log_file(filename.c_str()); - Logger::setLogStream(log_file); - - KISS_LOG_INFO - << "Starting " << rank; - - if (rank == 0) { - Master master; - master.run(); - } else { - Slave slave; - slave.load(argv[1]); - slave.run(); - } - - MPI_Finalize(); - - KISS_LOG_INFO - << "Done."; - - return 0; -} From 7b4e062ccf07d4499a38085158a50b44a78dfba8 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 20 Apr 2012 12:49:45 +0200 Subject: [PATCH 0066/1298] remove XMLImport remove ModuleChain --- CMakeLists.txt | 2 - include/mpc/ModuleChain.h | 49 ----------------- include/mpc/XMLImport.h | 45 ---------------- python/mpc.i | 2 - src/ModuleChain.cpp | 110 -------------------------------------- src/XMLImport.cpp | 92 ------------------------------- src/main.cpp | 37 +++++-------- 7 files changed, 12 insertions(+), 325 deletions(-) delete mode 100644 include/mpc/ModuleChain.h delete mode 100644 include/mpc/XMLImport.h delete mode 100644 src/ModuleChain.cpp delete mode 100644 src/XMLImport.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ea54fe3ae..03303c44d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,8 +75,6 @@ add_library(mpc SHARED src/Random.cpp src/Clock.cpp src/Vector3.cpp - src/XMLImport.cpp - src/ModuleChain.cpp src/ModuleList.cpp src/Module.cpp src/Candidate.cpp diff --git a/include/mpc/ModuleChain.h b/include/mpc/ModuleChain.h deleted file mode 100644 index db72acf56..000000000 --- a/include/mpc/ModuleChain.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef MPC_MODULE_CHAIN_H_ -#define MPC_MODULE_CHAIN_H_ - -#include -#include -#include - -#include "mpc/Candidate.h" -#include "mpc/Module.h" - -namespace mpc { - -/** - @class ModuleChain - @brief The simulation chain. - */ -class ModuleChain { -public: - struct Priority { - enum Enum { - Start = 0, Propagation = 1, End = 100 - }; - }; - - typedef std::pair > list_entry_t; - typedef std::list list_t; - - const list_t &getStartModules() const; - const list_t &getMainModules() const; - const list_t &getEndModules() const; - -private: - list_t startModules; - list_t mainModules; - list_t endModules; - -public: - void add(size_t priority, Module *module); - void process(Candidate *candidate); - void process(std::vector > &candidates, bool recursive); - void process(list_t &list, Candidate *candidate); - void clear(); -}; - -} // namespace mpc - -std::ostream &operator<<(std::ostream &out, const mpc::ModuleChain &chain); - -#endif /* MPC_MODULE_CHAIN_H_ */ diff --git a/include/mpc/XMLImport.h b/include/mpc/XMLImport.h deleted file mode 100644 index 3d226c4e5..000000000 --- a/include/mpc/XMLImport.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef MODULECHAINIMPORT_H_ -#define MODULECHAINIMPORT_H_ - -#include "mpc/ModuleChain.h" - -#include "pugixml.hpp" - -#include -#include - -namespace mpc { - -class ModuleProducer; - -class ModuleFactory { - std::map producers; -public: - static ModuleFactory &instance(); - Module *create(const std::string type, pugi::xml_node &modules); - void registerProducer(const std::string &type, ModuleProducer *producer); -}; - -class ModuleProducer { -public: - - inline ModuleProducer(const std::string &name) { - ModuleFactory::instance().registerProducer(name, this); - } - - virtual ~ModuleProducer() { - } - virtual Module*create(pugi::xml_node &modules) = 0; -}; - -class XMLImport { - ModuleChain *chain; -public: - XMLImport(ModuleChain *chain); - void import(const std::string &filename); - void import(pugi::xml_node &node); -}; - -} // namespace mpc - -#endif /* MODULECHAINIMPORT_H_ */ diff --git a/python/mpc.i b/python/mpc.i index eb9631af9..022844c3f 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -51,7 +51,6 @@ #include "mpc/ParticleState.h" #include "mpc/Nucleus.h" #include "mpc/Module.h" -#include "mpc/ModuleChain.h" #include "mpc/ModuleList.h" #include "mpc/PhasePoint.h" #include "mpc/ExplicitRungeKutta.h" @@ -108,5 +107,4 @@ %include "mpc/module/PhotoDisintegration.h" %include "mpc/module/Redshift.h" %include "mpc/module/Tools.h" -%include "mpc/ModuleChain.h" %include "mpc/ModuleList.h" diff --git a/src/ModuleChain.cpp b/src/ModuleChain.cpp deleted file mode 100644 index 2ac6cb277..000000000 --- a/src/ModuleChain.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "mpc/ModuleChain.h" - -namespace mpc { - -const ModuleChain::list_t &ModuleChain::getStartModules() const { - return startModules; -} -const ModuleChain::list_t &ModuleChain::getMainModules() const { - return mainModules; -} -const ModuleChain::list_t &ModuleChain::getEndModules() const { - return endModules; -} - -void ModuleChain::add(size_t priority, Module *module) { - if (module == 0) - return; - - list_entry_t entry; - entry.first = priority; - entry.second = module; - - if (priority == Priority::Start) { - startModules.push_back(entry); - } else if (priority == Priority::End) { - endModules.push_back(entry); - } else { - mainModules.push_back(entry); - mainModules.sort(); - } -} - -void ModuleChain::clear() { - startModules.clear(); - mainModules.clear(); - endModules.clear(); -} - -void ModuleChain::process(list_t &list, Candidate *candidate) { - list_t::iterator iEntry = list.begin(); - while (iEntry != list.end()) { - list_entry_t &entry = *iEntry; - iEntry++; - entry.second->process(candidate); - } -} - -void ModuleChain::process(Candidate *candidate) { - if (mainModules.size() == 0) - return; - - process(startModules, candidate); - - while (candidate->isActive()) { - if (mainModules.size() == 0) - break; - process(mainModules, candidate); - } - - process(endModules, candidate); -} - -void ModuleChain::process(std::vector > &candidates, - bool recursive) { -#pragma omp parallel for - for (size_t i = 0; i < candidates.size(); i++) { - Candidate *candidate = candidates[i]; - if (candidate->isActive()) - continue; - process(candidate); - - // propagate secondaries - if (recursive) - process(candidate->secondaries, recursive); - } -} - -} // namespace mpc - -std::ostream &operator<<(std::ostream &out, const mpc::ModuleChain &chain) { - mpc::ModuleChain::list_t::const_iterator iEntry; - - out << "Start Modules" << "\n"; - iEntry = chain.getStartModules().begin(); - while (iEntry != chain.getStartModules().end()) { - const mpc::ModuleChain::list_entry_t &entry = *iEntry; - iEntry++; - out << " " << entry.first << " -> " << entry.second->getDescription() - << "\n"; - } - - out << "\nMain Modules" << "\n"; - iEntry = chain.getMainModules().begin(); - while (iEntry != chain.getMainModules().end()) { - const mpc::ModuleChain::list_entry_t &entry = *iEntry; - iEntry++; - out << " " << entry.first << " -> " << entry.second->getDescription() - << "\n"; - } - - out << "\nEnd Modules" << "\n"; - iEntry = chain.getEndModules().begin(); - while (iEntry != chain.getEndModules().end()) { - const mpc::ModuleChain::list_entry_t &entry = *iEntry; - iEntry++; - out << " " << entry.first << " -> " << entry.second->getDescription() - << "\n"; - } - return out; -} diff --git a/src/XMLImport.cpp b/src/XMLImport.cpp deleted file mode 100644 index 7efeb34e9..000000000 --- a/src/XMLImport.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "mpc/XMLImport.h" -#include "mpc/ModuleChain.h" -#include "mpc/magneticField/magneticField.h" -#include "mpc/magneticField/uniformMagneticField.h" -#include "mpc/module/DeflectionCK.h" - -#include "pugixml.hpp" - -#include -#include - -namespace mpc { - -Module *ModuleFactory::create(const std::string type, - pugi::xml_node &moduleNode) { - std::map::iterator i; - i = producers.find(type); - if (i == producers.end()) - return 0; - - return i->second->create(moduleNode); -} - -void ModuleFactory::registerProducer(const std::string &type, - ModuleProducer *producer) { - producers.insert(make_pair(type, producer)); -} - -XMLImport::XMLImport(ModuleChain *chain) : - chain(chain) { - -} - -void XMLImport::import(const std::string &filename) { - pugi::xml_document doc; - pugi::xml_parse_result result = doc.load_file(filename.c_str()); - - if (!result) { - std::stringstream sstr; - sstr << "XML [" << filename << "] parsed with errors, attr value: [" - << doc.child("node").attribute("attr").value() << "]\n"; - sstr << "Error description: " << result.description() << "\n"; - throw std::runtime_error(sstr.str()); - } - - pugi::xml_node node = doc.child("mpc"); - if (!node) { - std::stringstream sstr; - sstr << "XML [" << filename << "] no 'mpc' element found!\n"; - throw std::runtime_error(sstr.str()); - } - - import(node); -} - -ModuleFactory &ModuleFactory::instance() { - static ModuleFactory factory; - return factory; -} - -void XMLImport::import(pugi::xml_node &modules) { - for (pugi::xml_node moduleNode = modules.child("module"); moduleNode; - moduleNode = moduleNode.next_sibling("module")) { - std::string type = moduleNode.attribute("type").value(); - unsigned int priority = moduleNode.attribute("priority").as_uint(); - - ref_ptr module = ModuleFactory::instance().create(type, moduleNode); - if (module.valid()) - chain->add(priority, module); - else - std::cout << "No module '" << type << "' found!" << std::endl; - } -} - -class DeflectionCKProducer: public ModuleProducer { -public: - - DeflectionCKProducer() : - ModuleProducer("DeflectionCK") { - - } - - Module *create(pugi::xml_node &module) { - UniformMagneticField *field = new UniformMagneticField( - Vector3(0, 1, 0)); - return new DeflectionCK(field); - } -}; - -static DeflectionCKProducer _deflection_ck_producer; - -} // namespace mpc diff --git a/src/main.cpp b/src/main.cpp index 958425ccc..519b76ceb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,4 @@ -#include "mpc/XMLImport.h" -#include "mpc/ModuleChain.h" -#include "mpc/Vector3.h" -#include "mpc/Units.h" +#include "mpc/ModuleList.h" #include "mpc/module/SimplePropagation.h" #include "mpc/module/DeflectionCK.h" #include "mpc/module/BreakCondition.h" @@ -16,34 +13,25 @@ using namespace mpc; int main(int argc, char **argv) { - ModuleChain chain; + ModuleList modules; -// if (argc > 1) { -// XMLImport import(&chain); -// import.import(argv[1]); -// } else { - -// propagation -------------------------------------------------------- -// UniformMagneticField *field = new UniformMagneticField(Vector3(0., 0., 1e-20)); -// SPHMagneticField *field = new SPHMagneticField(Vector3(119717, 221166, 133061) * kpc, 3 * Mpc, 50); -// field->gadgetField->load("test/coma-0.7.raw"); + // propagation -------------------------------------------------------- TurbulentMagneticFieldGrid *field = new TurbulentMagneticFieldGrid(Vector3(0, 0, 0), 64, 1., 2., 8., 1e-12, -11. / 3.); - chain.add(1, new DeflectionCK(field)); -// chain.add(1, new SimplePropagation); + modules.add(new DeflectionCK(field)); // interactions ------------------------------------------------------- - chain.add(10, new NuclearDecay()); - chain.add(11, new PhotoDisintegration()); - chain.add(12, new ElectronPairProduction()); - chain.add(13, new PhotoPionProduction()); + modules.add(new NuclearDecay()); + modules.add(new PhotoDisintegration()); + modules.add(new ElectronPairProduction()); + modules.add(new PhotoPionProduction()); // break conditions --------------------------------------------------- - chain.add(20, new MaximumTrajectoryLength(50 * Mpc)); + modules.add(new MaximumTrajectoryLength(50 * Mpc)); // output ------------------------------------------------------------- - chain.add(79, new ShellOutput()); + modules.add(new ShellOutput()); - std::cout << chain << std::endl; + std::cout << modules << std::endl; ParticleState initial; initial.setId(getNucleusId(56, 26)); @@ -52,8 +40,7 @@ int main(int argc, char **argv) { initial.setDirection(Vector3(1, 0, 0)); ref_ptr candidate = new Candidate(initial); - - chain.process(candidate); + modules.process(candidate); std::cout << "done" << std::endl; From b1a6494bd0d79eef9d6a94b8da8527471f9105ee Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 23 Apr 2012 14:38:27 +0200 Subject: [PATCH 0067/1298] all changes --- include/mpc/Nucleus.h | 24 +++----- include/mpc/ParticleState.h | 8 ++- include/mpc/module/PhotoPionProduction.h | 2 +- libs/sophia/sophia.h | 3 +- src/Nucleus.cpp | 5 +- src/ParticleState.cpp | 44 ++++++++++---- src/module/PhotoPionProduction.cpp | 66 +++++++++++++++------ test/python/testElectronPairProduction.py | 6 +- test/python/testNuclearMass.py | 11 +++- test/python/testPhotoDisintegration.py | 70 +++++++++++------------ test/python/testPhotoPionProduction.py | 16 +++--- test/testCore.cpp | 20 ++++--- 12 files changed, 168 insertions(+), 107 deletions(-) diff --git a/include/mpc/Nucleus.h b/include/mpc/Nucleus.h index 35cc63466..ea762d5df 100644 --- a/include/mpc/Nucleus.h +++ b/include/mpc/Nucleus.h @@ -1,30 +1,24 @@ #ifndef NUCLEUS_H_ #define NUCLEUS_H_ -#include "mpc/AssocVector.h" #include namespace mpc { -// HepPID codes for ions 1AAAZZZ00nj -// see http://cepa.fnal.gov/psm/HepPID -// nj = 2J+1 is the nucleus total spin and is currently neglected +// This implements the 2006 Monte Carlo nuclear code scheme. +// Ion numbers are +/- 10LZZZAAAI. +// AAA is A - total baryon number +// ZZZ is Z - total charge +// L is the total number of strange quarks. +// I is the isomer number, with I=0 corresponding to the ground state. inline int getNucleusId(int a, int z) { if (z < 0) throw std::runtime_error("mpc::Nucleus: no nucleus with Z < 0"); - if (a < 0) - throw std::runtime_error("mpc::Nucleus: no nucleus with A < 0"); + if (a < 1) + throw std::runtime_error("mpc::Nucleus: no nucleus with A < 1"); if (a < z) throw std::runtime_error("mpc::Nucleus: no nucleus with A < Z"); - return 1000000000 + a * 1000000 + z * 1000; -} - -inline int getChargeNumberFromNucleusId(int id) { - return ((id - 1000000000) % 1000000) / 1000; -} - -inline int getMassNumberFromNucleusId(int id) { - return (id - 1000000000) / 1000000; + return 1000000000 + z * 10000 + a * 10; } void initNuclearMassTable(); diff --git a/include/mpc/ParticleState.h b/include/mpc/ParticleState.h index c8d001ca1..c81528240 100644 --- a/include/mpc/ParticleState.h +++ b/include/mpc/ParticleState.h @@ -28,10 +28,10 @@ class ParticleState { void setDirection(const Vector3 &dir); const Vector3 &getDirection() const; - void setEnergy(double newEnergy); + void setEnergy(const double newEnergy); double getEnergy() const; - void setId(int); + void setId(const int); int getId() const; int getChargeNumber() const; @@ -41,8 +41,10 @@ class ParticleState { double getMass() const; // convenience functions + bool isNucleus() const; + + void setLorentzFactor(const double gamma); double getLorentzFactor() const; - void setLorentzFactor(double gamma); Vector3 getVelocity() const; Vector3 getMomentum() const; diff --git a/include/mpc/module/PhotoPionProduction.h b/include/mpc/module/PhotoPionProduction.h index eaf9d676f..13e4a37f5 100644 --- a/include/mpc/module/PhotoPionProduction.h +++ b/include/mpc/module/PhotoPionProduction.h @@ -25,7 +25,7 @@ class PhotoPionProduction: public StochasticInteraction { double Emin, Emax; public: - PhotoPionProduction(int photonField = CMB_IRB); + PhotoPionProduction(int photonField = CMB); ~PhotoPionProduction(); void init(int photonField); void init(std::string filename); diff --git a/libs/sophia/sophia.h b/libs/sophia/sophia.h index c6123fe39..548c11dba 100644 --- a/libs/sophia/sophia.h +++ b/libs/sophia/sophia.h @@ -25,7 +25,8 @@ void sophiaevent_(int&, double&, double[][2000], int[], int&, double&, int&, - list of output particle ids - number of output particles - redshift - - photon background flag: 1 -> CMB, 2 -> Primack et al. (1999) IRB + - photon background flag: 1 -> CMB, 2 -> IRB Kneiske + (Primack et al. (1999) IRB is outcommented in sophia_interface.f on line 16320 - maximum redshift: the photon density of IRB is null above this redshift - - diff --git a/src/Nucleus.cpp b/src/Nucleus.cpp index 51da0739f..072806cb5 100644 --- a/src/Nucleus.cpp +++ b/src/Nucleus.cpp @@ -2,6 +2,7 @@ #include "mpc/Common.h" #include +#include #include #include @@ -35,8 +36,8 @@ double getNucleusMass(int id) { if (nuclearMassTable.size() == 0) initNuclearMassTable(); - int Z = getChargeNumberFromNucleusId(id); - int N = getMassNumberFromNucleusId(id) - Z; + int Z = HepPID::Z(id); + int N = HepPID::A(id) - Z; double mass = nuclearMassTable[Z * 31 + N]; if (mass == 0) throw std::runtime_error("mpc: nucleus not found " + kiss::str(id)); diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index bec651839..af75b0f1c 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -1,5 +1,7 @@ #include "mpc/ParticleState.h" +#include + namespace mpc { ParticleState::ParticleState() : @@ -23,7 +25,7 @@ const Vector3 &ParticleState::getDirection() const { return direction; } -void ParticleState::setEnergy(double newEnergy) { +void ParticleState::setEnergy(const double newEnergy) { energy = newEnergy; } @@ -31,9 +33,10 @@ double ParticleState::getEnergy() const { return energy; } -void ParticleState::setId(int newId) { +void ParticleState::setId(const int newId) { id = newId; - pmass = getNucleusMass(id); + if (HepPID::isNucleus(id)) + pmass = getNucleusMass(id); } int ParticleState::getId() const { @@ -41,27 +44,46 @@ int ParticleState::getId() const { } int ParticleState::getChargeNumber() const { - return getChargeNumberFromNucleusId(id); + return HepPID::Z(id); } double ParticleState::getCharge() const { - return getChargeNumberFromNucleusId(id) * eplus; + return HepPID::Z(id) * eplus; } int ParticleState::getMassNumber() const { - return getMassNumberFromNucleusId(id); + return HepPID::A(id); } double ParticleState::getMass() const { - return pmass; + if (HepPID::isNucleus(id)) + return pmass; + else + throw std::runtime_error( + "mpc::ParticleState::getMass only for nuclei/nucleons"); } -double ParticleState::getLorentzFactor() const { - return energy / (this->getMass() * c_squared); +bool ParticleState::isNucleus() const { + if (HepPID::isNucleus(id)) + return true; + else + return false; } -void ParticleState::setLorentzFactor(double gamma) { - energy = gamma * this->getMass() * c_squared; +double ParticleState::getLorentzFactor() const { + if (HepPID::isNucleus(id)) + return energy / (pmass * c_squared); + else + throw std::runtime_error( + "mpc::ParticleState::getLorentzFactor only for nuclei/nucleons"); +} + +void ParticleState::setLorentzFactor(const double gamma) { + if (HepPID::isNucleus(id)) + energy = gamma * pmass * c_squared; + else + throw std::runtime_error( + "mpc::ParticleState::setLorentzFactor only for nuclei/nucleons"); } Vector3 ParticleState::getVelocity() const { diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 067bb0aaa..13266f1e7 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -1,4 +1,6 @@ #include "mpc/module/PhotoPionProduction.h" + +#include #include "sophia.h" #include @@ -18,15 +20,15 @@ void PhotoPionProduction::init(int photonField) { switch (photonField) { case CMB: setDescription("PhotoPionProduction:CMB"); - init(getDataPath("PhotoPionProduction/cmb.txt")); + init(getDataPath("PhotoPionProduction/PPtable_CMB.txt")); break; case IRB: setDescription("PhotoPionProduction:IRB"); - init(getDataPath("PhotoPionProduction/ir.txt")); + init(getDataPath("PhotoPionProduction/PPtable_IRB.txt")); break; case CMB_IRB: setDescription("PhotoPionProduction:CMB_IRB"); - init(getDataPath("PhotoPionProduction/cmbir.txt")); + init(getDataPath("PhotoPionProduction/PPtable_CMB_IRB.txt")); break; default: throw std::runtime_error( @@ -155,7 +157,7 @@ void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { candidate->getInteractionState(getDescription(), interaction); candidate->clearInteractionStates(); - int dZ = interaction.channel; // charge number loss of interacting nucleus + int channel = interaction.channel; // 1 for interaction proton, 0 for neutron double E = candidate->current.getEnergy(); int A = candidate->current.getMassNumber(); @@ -163,13 +165,13 @@ void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { double EpA = E / A; // arguments for sophia - int nature = 1 - dZ; // interacting particle: 0 for proton, 1 for neutron + int nature = 1 - channel; // interacting particle: 0 for proton, 1 for neutron double Ein = EpA / GeV; // energy of in-going nucleon in GeV double momentaList[5][2000]; // momentum list, what are the five components? int particleList[2000]; // particle id list int nParticles; // number of outgoing particles double redshift = candidate->getRedshift(); - int background; // Photon background: 1 for CMB, 2 for Primack IR + int background; // Photon background: 1 for CMB, 2 for Kneiske IRB switch (photonField) { case CMB: background = 1; @@ -193,23 +195,49 @@ void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { double Eout = momentaList[3][i] * GeV; // only the energy is used; could be changed for more detail int pType = particleList[i]; - if (pType == 13 or pType == 14) { - int Zout = 14 - pType; // 1 for proton, 0 for neutron + switch (pType) { + case 13: // proton + case 14: // neutron if (A == 1) { // in-going particle was a nucleon: update its properties candidate->current.setEnergy(Eout); - candidate->current.setId(getNucleusId(1, Zout)); - } else { - // // in-going particle was a nucleus: update nucleus and emit nucleon + candidate->current.setId(getNucleusId(1, 14 - pType)); + } else { // in-going particle was a nucleus: update nucleus and emit nucleon candidate->current.setEnergy(E - Eout); - candidate->current.setId(getNucleusId(A - 1, Z - dZ)); - candidate->addSecondary(getNucleusId(1, Zout), Eout); + candidate->current.setId(getNucleusId(A - 1, Z - channel)); + candidate->addSecondary(getNucleusId(1, 14 - pType), Eout); } - } else if (pType == -13 or pType == -14) { - continue; // anti-proton/neutron -> new electromagnetic cascade after annihilation? - } else if (pType >= 1 and pType <= 3) { - continue; // new electromagnetic cascade - } else if (pType >= 15) { - continue; // new neutrino + break; + case -13: // anti-proton + candidate->addSecondary(-getNucleusId(1, 1), Eout); + break; + case -14: // anti-neutron + candidate->addSecondary(-getNucleusId(1, 0), Eout); + break; + case 1: // photon + candidate->addSecondary(22, Eout); + break; + case 2: // positron + candidate->addSecondary(-11, Eout); + break; + case 3: // electron + candidate->addSecondary(11, Eout); + break; + case 15: // nu_e + candidate->addSecondary(12, Eout); + break; + case 16: // antinu_e + candidate->addSecondary(-12, Eout); + break; + case 17: // nu_muon + candidate->addSecondary(14, Eout); + break; + case 18: // antinu_muon + candidate->addSecondary(-14, Eout); + break; + default: + throw std::runtime_error( + "mpc::PhotoPionProduction: unexpected particle " + + kiss::str(pType)); } } } diff --git a/test/python/testElectronPairProduction.py b/test/python/testElectronPairProduction.py index a02209b8c..3c247e291 100644 --- a/test/python/testElectronPairProduction.py +++ b/test/python/testElectronPairProduction.py @@ -33,6 +33,6 @@ def compare(dataFileName, photonField, plotFileName): savefig(plotFileName, bbox_inches='tight') -compare(getDataPath("/ElectronPairProduction/cmb.txt"), ElectronPairProduction.CMB, 'ElectronPairProduction_cmb.png') -compare(getDataPath("/ElectronPairProduction/cmbir.txt"), ElectronPairProduction.CMBIR, 'ElectronPairProduction_cmbir.png') -compare(getDataPath("/ElectronPairProduction/ir.txt"), ElectronPairProduction.IR, 'ElectronPairProduction_ir.png') \ No newline at end of file +compare(getDataPath("/ElectronPairProduction/cmb.txt"), CMB, 'ElectronPairProduction_CMB.png') +compare(getDataPath("/ElectronPairProduction/ir.txt"), IRB, 'ElectronPairProduction_IRB.png') +compare(getDataPath("/ElectronPairProduction/cmbir.txt"), CMB_IRB, 'ElectronPairProduction_CMB_IRB.png') \ No newline at end of file diff --git a/test/python/testNuclearMass.py b/test/python/testNuclearMass.py index 294a8148d..c8117d0f9 100644 --- a/test/python/testNuclearMass.py +++ b/test/python/testNuclearMass.py @@ -20,4 +20,13 @@ xlabel('Neutrons') ylabel('Protons') grid() -savefig('NuclearMass_mass.png', bbox_inches='tight') +savefig('NuclearMass_table.png', bbox_inches='tight') + +figure() +im = imshow(ma.masked_array(D2, D==0), aspect='equal', interpolation='nearest', origin='lower') +cbar = colorbar(im) +cbar.set_label('Mass - $A \cdot amu - Z \cdot m_e$ [amu]') +xlabel('Neutrons') +ylabel('Protons') +grid() +savefig('NuclearMass_difference.png', bbox_inches='tight') diff --git a/test/python/testPhotoDisintegration.py b/test/python/testPhotoDisintegration.py index e462249f8..5ecf3340a 100644 --- a/test/python/testPhotoDisintegration.py +++ b/test/python/testPhotoDisintegration.py @@ -5,7 +5,7 @@ gamma = logspace(6, 14, 200) -def get_rates(interaction, id, gamma, count=10000): +def get_rates(pd, id, gamma, count=1000): D = {} c = Candidate() c.current.setId(id) @@ -13,22 +13,21 @@ def get_rates(interaction, id, gamma, count=10000): for i in range(count): c.clearInteractionStates() - interaction.process(c) + pd.process(c) state = InteractionState() - c.getInteractionState("mpc::PhotoDisintegration", state) + c.getInteractionState("PhotoDisintegration:CMB_IRB", state) D.setdefault(state.channel, []).append(state.distance / Mpc) - for channel in D.keys(): - l = D[channel] - hist = ROOT.TH1F('', '', 50, 0, max(l)) - for element in l: - hist.Fill(element) + for k in D.keys(): + hist = ROOT.TH1F('', '', 50, 0, max(D[k])) + for entry in D[k]: + hist.Fill(entry) f = ROOT.TF1('f1', 'expo') hist.Fit(f, "q") l = -f.GetParameter(1) p = hist.GetEntries() / float(count) exclu = l * p # exclusive decay constant for this channel - D[channel] = max(0, exclu) # take 0 if slope is negative + D[k] = max(0, exclu) # take 0 if slope is negative return D @@ -38,14 +37,16 @@ def get_rates_per_channel(interaction, id): if iE % 20 != 0: continue D2 = get_rates(interaction, id, gamma[iE]) - for channel in D2.keys(): - D.setdefault(channel, zeros(200))[iE] = D2[channel] + for k in D2.keys(): + D.setdefault(k, zeros(200))[iE] = D2[k] return D def get_data_rates_per_channel(table, id): rates = {} - for i in xrange(len(table)): - if int(table[i][0]) != id: + for i in range(len(table)): + z, a = int(table[i][0]), int(table[i][1]) + print z, a + if getNucleusId(a, z) != id: continue rates[table[i][1]] = table[i][2:] return rates @@ -60,14 +61,11 @@ def plot_channel(rates_simulated, rates_data, id, channel): text(0.1, 0.85, 'Nucleus ' + parse_id(id) + '\nDecay Channel ' + parse_channel(channel), transform=gca().transAxes) xlabel('Lorentzfactor $\gamma$') ylabel('Rate [1/Mpc]') - loglog() + #loglog() ylim(1e-10, 1e2) grid() savefig('PhotoDisintegration_' + str(id) + '_' + str(channel) + '.png', bbox_inches='tight') -def get_id(a, z): - return 1e9 + a * 1e6 + z * 1e3 - def parse_id(id): z = ((id - 1000000000) % 1000000) // 1000 a = (id - 1000000000) // 1000000 @@ -79,14 +77,14 @@ def parse_channel(c): s = 'n, ' * d[0] + 'p, ' * d[1] + 'H$^2$, ' * d[2] + 'H$^3$, ' * d[3] + 'He$^3$, ' * d[4] + 'He$^4$, ' * d[5] return s[0:-2] -interaction = PhotoDisintegration() -table = genfromtxt(getDataPath('/PhotoDisintegration/pd_table.txt')) +interaction = PhotoDisintegration(CMB_IRB) +table = genfromtxt(getDataPath('/PhotoDisintegration/PDtable_CMB_IRB.txt')) id = 1004002000 if len(sys.argv) >= 3: a = int(sys.argv[1]) z = int(sys.argv[2]) - id = get_id(a, z) + id = getNucleusId(a, z) print 'Plotting Disintegration Rates for', id rates_simulated = get_rates_per_channel(interaction, id) @@ -96,22 +94,22 @@ def parse_channel(c): plot_channel(rates_simulated, rates_data, id, channel) # plot channel multiplicity -print 'Plotting Channel Multiplicity' -multi = zeros((27, 31)) -for z in range(1, 27): - for n in range(1, 31): - multi[z][n] = len(get_data_rates_per_channel(table, get_id(z + n, z))) - -fig = figure() -ax = fig.add_subplot(111) -mmulti = ma.masked_array(multi, multi==0) -im = ax.imshow(mmulti, aspect='equal', interpolation='nearest', origin='lower') -cbar = fig.colorbar(im, orientation='horizontal') -cbar.set_label('Photo-Disintegration Channels') -ax.set_xlabel('Neutrons') -ax.set_ylabel('Protons') -ax.grid() -fig.savefig('PhotoDisintegration_multiplicity.png',bbox_inches='tight') +#print 'Plotting Channel Multiplicity' +#multi = zeros((27, 31)) +#for z in range(1, 27): +# for n in range(1, 31): +# multi[z][n] = len(get_data_rates_per_channel(table, get_id(z + n, z))) +# +#fig = figure() +#ax = fig.add_subplot(111) +#mmulti = ma.masked_array(multi, multi==0) +#im = ax.imshow(mmulti, aspect='equal', interpolation='nearest', origin='lower') +#cbar = fig.colorbar(im, orientation='horizontal') +#cbar.set_label('Photo-Disintegration Channels') +#ax.set_xlabel('Neutrons') +#ax.set_ylabel('Protons') +#ax.grid() +#fig.savefig('PhotoDisintegration_multiplicity.png',bbox_inches='tight') diff --git a/test/python/testPhotoPionProduction.py b/test/python/testPhotoPionProduction.py index 60b9dbf17..82e9af1c3 100644 --- a/test/python/testPhotoPionProduction.py +++ b/test/python/testPhotoPionProduction.py @@ -2,7 +2,7 @@ from pylab import * import ROOT -def getSlope(interaction, energy, charge): +def getSlope(interaction, energy, charge, name): c = Candidate() c.current.setId(getNucleusId(1, charge)) c.current.setEnergy(energy) @@ -12,7 +12,7 @@ def getSlope(interaction, energy, charge): for i in range(10000): c.clearInteractionStates() interaction.process(c) - c.getInteractionState('mpc::PhotoPionProduction', s) + c.getInteractionState('PhotoPionProduction:'+name, s) l.append(s.distance / Mpc) h = ROOT.TH1F('', '', 100, 0, max(l)) @@ -29,14 +29,14 @@ def getSlope(interaction, energy, charge): def compare(type, name): print "compare ", name ppp = PhotoPionProduction(type) - E_data, P_data, N_data = genfromtxt(getDataPath('/PhotoPionProduction/' + name + '.txt'), unpack=True) + E_data, P_data, N_data = genfromtxt(getDataPath('/PhotoPionProduction/PPtable_' + name + '.txt'), unpack=True) E = logspace(1.5,5,10) * EeV p = zeros(len(E)) n = zeros(len(E)) for i,energy in enumerate(E*EeV): - p[i] = getSlope(ppp, energy, 1) - n[i] = getSlope(ppp, energy, 0) + p[i] = getSlope(ppp, energy, 1, name) + n[i] = getSlope(ppp, energy, 0, name) plot(E_data, P_data, "r", label="Proton Data") plot(E, p, 'k+', label="Proton Simulated") plot(E_data, N_data, "b", label="Neutron Data") @@ -50,6 +50,6 @@ def compare(type, name): savefig('PhotoPionProduction_' + name + '.png', bbox_inches='tight') close() -compare(PhotoPionProduction.CMB, "cmb") -compare(PhotoPionProduction.CMBIR, "cmbir") -compare(PhotoPionProduction.IR, "ir") +compare(CMB, "CMB") +compare(IRB, "IRB") +compare(CMB_IRB, "CMB_IRB") diff --git a/test/testCore.cpp b/test/testCore.cpp index 5e76dc2a1..5b4dc5a65 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -41,32 +41,38 @@ TEST(ParticleState, momentum) { TEST(ParticleState, id) { ParticleState particle; - particle.setId(1045026000); - EXPECT_EQ(particle.getId(), 1045026000); + particle.setId(getNucleusId(12, 6)); + EXPECT_EQ(particle.getId(), 1000060120); } TEST(ParticleState, idException) { - ParticleState particle; - EXPECT_THROW(particle.setId(1002002000), std::runtime_error); + EXPECT_THROW(getNucleusId(5, 6), std::runtime_error); } TEST(ParticleState, charge) { ParticleState particle; - particle.setId(1056026000); + particle.setId(getNucleusId(56, 26)); EXPECT_EQ(particle.getChargeNumber(), 26); EXPECT_DOUBLE_EQ(particle.getCharge(), 26 * eplus); } TEST(ParticleState, massProton) { ParticleState particle; - particle.setId(1001001000); + particle.setId(getNucleusId(1, 1)); EXPECT_EQ(particle.getMassNumber(), 1); EXPECT_DOUBLE_EQ(particle.getMass(), mass_proton); } +TEST(ParticleState, massNeutron) { + ParticleState particle; + particle.setId(getNucleusId(1, 0)); + EXPECT_EQ(particle.getMassNumber(), 1); + EXPECT_DOUBLE_EQ(particle.getMass(), mass_neutron); +} + TEST(ParticleState, lorentzFactor) { ParticleState particle; - particle.setId(1001001000); + particle.setId(getNucleusId(1, 1)); particle.setEnergy(1e12 * eV); EXPECT_DOUBLE_EQ(particle.getLorentzFactor(), 1e12 * eV / mass_proton / c_squared); } From 8e47563d3de8d70ed37f51cc366c6d985e9b0524 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 25 Apr 2012 12:41:24 +0200 Subject: [PATCH 0068/1298] add testTurbulentDeflection.py --- test/python/testTurbulentDeflection.py | 64 ++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 test/python/testTurbulentDeflection.py diff --git a/test/python/testTurbulentDeflection.py b/test/python/testTurbulentDeflection.py new file mode 100644 index 000000000..65bf142d2 --- /dev/null +++ b/test/python/testTurbulentDeflection.py @@ -0,0 +1,64 @@ +from mpc import * +from pylab import * + + +E = 10 # proton energy [EeV] +nT = 1000 # number of trajectories +nS = 100 # number of sampling points to simulate +nP = range(75) # sampling points to plot + +# create turbulent field with B_RMS = 1 nG and 0.5 Mpc correlation length +field = TurbulentMagneticFieldGrid(Vector3(0, 0, 0), 256, 0.05 * Mpc, 0.1 * Mpc, 2.2 * Mpc, 1*nG, -11/3.) +propa = DeflectionCK(field) + +age = linspace(1, 150, nS) +distance, rms1, rms2 = zeros((3, nS)) + +for j in range(nT): + if j%(nT//10) == 0: + print j + + ps = ParticleState() + ps.setId(getNucleusId(1, 1)) + ps.setEnergy(E * EeV) + ps.setDirection(Random.instance().randUnitVectorOnSphere()) + ps.setPosition(Vector3(0, 0, 0)) + c = Candidate(ps) + + for i in range(nS): + maxLen = MaximumTrajectoryLength(age[i] * Mpc) + c.setNextStep(c.getNextStep() * 0.99) + c.setActive(True) + + while c.isActive(): + propa.process(c) + maxLen.process(c) + + x = c.current.getPosition() / Mpc + p = c.current.getDirection() + p0 = c.initial.getDirection() + distance[i] += x.mag() + rms1[i] += (x.angle(p))**2 + rms2[i] += (p0.angle(p))**2 + + +distance /= nT +rms1 = (rms1 / nT)**.5 +rms2 = (rms2 / nT)**.5 + +Lc = field.getCorrelationLength() / Mpc +Brms = field.getRMSFieldStrength() / nG +Rg = 1.08 * E / Brms # Mpc +theory = 38 * (distance * Lc)**.5 * Brms / E * pi/180 + +plot(distance[nP], rms1[nP], label='position, final direction') +plot(distance[nP], theory[nP] / 3**.5, 'k--') +plot(distance[nP], rms2[nP], label='initial, final direction') +plot(distance[nP], theory[nP], 'k--', label='Harari') +xlabel('Distance [Mpc]') +ylabel('RMS(Deflection) [rad]') +legend(loc='lower right', frameon=False) +s = 'Gyroradius $r_g=%.2f$ Mpc\nCorr. Length $L_c=%.2f$ Mpc'%(Rg, Lc) +text(0.05, 0.95, s, ha='left', va='top', transform=gca().transAxes) +savefig('TurbulentDeflection.png', bbox_inches='tight') + From 37a2333395c82a87e2fb54e0a7e666f6b424e088 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 25 Apr 2012 12:45:29 +0200 Subject: [PATCH 0069/1298] reimplement constructor in SophiaPPP to check for background --- include/mpc/module/PhotoPionProduction.h | 4 +++- src/module/PhotoPionProduction.cpp | 11 +++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/mpc/module/PhotoPionProduction.h b/include/mpc/module/PhotoPionProduction.h index 13e4a37f5..73358c815 100644 --- a/include/mpc/module/PhotoPionProduction.h +++ b/include/mpc/module/PhotoPionProduction.h @@ -25,7 +25,7 @@ class PhotoPionProduction: public StochasticInteraction { double Emin, Emax; public: - PhotoPionProduction(int photonField = CMB); + PhotoPionProduction(int photonField = CMB_IRB); ~PhotoPionProduction(); void init(int photonField); void init(std::string filename); @@ -39,6 +39,8 @@ class PhotoPionProduction: public StochasticInteraction { @brief Photo-pion interactions of nuclei with background photons using SOPHIA. */ class SophiaPhotoPionProduction: public PhotoPionProduction { +public: + SophiaPhotoPionProduction(int photonField = CMB); void performInteraction(Candidate *candidate) const; }; diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 13266f1e7..ec6199f6f 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -152,6 +152,13 @@ void PhotoPionProduction::performInteraction(Candidate *candidate) const { } } +SophiaPhotoPionProduction::SophiaPhotoPionProduction(int photonField) { + if ((photonField == CMB) or (photonField == IRB)) + init(photonField); + else + std::runtime_error("mpc::SophiaPhotoPionProduction: only CMB or IRB background possible"); +} + void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { InteractionState interaction; candidate->getInteractionState(getDescription(), interaction); @@ -179,10 +186,6 @@ void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { case IRB: background = 2; break; - case CMB_IRB: - throw std::runtime_error( - "mpc::SophiaPhotoPionProduction: CMB_IRB not possible for SophiaPhotoPionProduction"); - break; } double maxRedshift = 100; // IR photon density is zero above this redshift int dummy1; From 60db38e9c9d4b47184f81aba3aeccc50825781d0 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 25 Apr 2012 14:49:56 +0200 Subject: [PATCH 0070/1298] update PhotoPion data tables, implemtation and tests --- include/mpc/module/PhotoPionProduction.h | 4 ++-- src/module/PhotoPionProduction.cpp | 16 +------------- test/python/testPhotoPionProduction.py | 20 +++++++++--------- test/testInteraction.cpp | 27 +++++++++++++++++++----- 4 files changed, 35 insertions(+), 32 deletions(-) diff --git a/include/mpc/module/PhotoPionProduction.h b/include/mpc/module/PhotoPionProduction.h index 73358c815..d1f6c58e2 100644 --- a/include/mpc/module/PhotoPionProduction.h +++ b/include/mpc/module/PhotoPionProduction.h @@ -25,7 +25,7 @@ class PhotoPionProduction: public StochasticInteraction { double Emin, Emax; public: - PhotoPionProduction(int photonField = CMB_IRB); + PhotoPionProduction(int photonField = CMB); ~PhotoPionProduction(); void init(int photonField); void init(std::string filename); @@ -40,7 +40,7 @@ class PhotoPionProduction: public StochasticInteraction { */ class SophiaPhotoPionProduction: public PhotoPionProduction { public: - SophiaPhotoPionProduction(int photonField = CMB); + SophiaPhotoPionProduction(int photonField = CMB) : PhotoPionProduction(photonField) {}; void performInteraction(Candidate *candidate) const; }; diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index ec6199f6f..6b36f41d9 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -26,13 +26,9 @@ void PhotoPionProduction::init(int photonField) { setDescription("PhotoPionProduction:IRB"); init(getDataPath("PhotoPionProduction/PPtable_IRB.txt")); break; - case CMB_IRB: - setDescription("PhotoPionProduction:CMB_IRB"); - init(getDataPath("PhotoPionProduction/PPtable_CMB_IRB.txt")); - break; default: throw std::runtime_error( - "mpc::PhotoPionProduction: unknown photon background"); + "mpc::PhotoPionProduction: only CMB or IRB possible as photon background"); } } @@ -43,9 +39,6 @@ void PhotoPionProduction::init(std::string filename) { "mpc::PhotoPionProduction: could not open file " + filename); std::vector x, yp, yn; - x.reserve(100); - yp.reserve(100); - yn.reserve(100); while (infile.good()) { if (infile.peek() != '#') { double a, b, c; @@ -152,13 +145,6 @@ void PhotoPionProduction::performInteraction(Candidate *candidate) const { } } -SophiaPhotoPionProduction::SophiaPhotoPionProduction(int photonField) { - if ((photonField == CMB) or (photonField == IRB)) - init(photonField); - else - std::runtime_error("mpc::SophiaPhotoPionProduction: only CMB or IRB background possible"); -} - void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { InteractionState interaction; candidate->getInteractionState(getDescription(), interaction); diff --git a/test/python/testPhotoPionProduction.py b/test/python/testPhotoPionProduction.py index 82e9af1c3..7226f0fc0 100644 --- a/test/python/testPhotoPionProduction.py +++ b/test/python/testPhotoPionProduction.py @@ -1,18 +1,18 @@ from mpc import * from pylab import * import ROOT +ROOT.gROOT.SetBatch(True) -def getSlope(interaction, energy, charge, name): + +def getSlope(module, energy, charge, name): c = Candidate() c.current.setId(getNucleusId(1, charge)) c.current.setEnergy(energy) - s = InteractionState() - + l = [] - for i in range(10000): - c.clearInteractionStates() - interaction.process(c) - c.getInteractionState('PhotoPionProduction:'+name, s) + for i in range(5000): + s = InteractionState() + module.setNextInteraction(c, s) l.append(s.distance / Mpc) h = ROOT.TH1F('', '', 100, 0, max(l)) @@ -31,12 +31,13 @@ def compare(type, name): ppp = PhotoPionProduction(type) E_data, P_data, N_data = genfromtxt(getDataPath('/PhotoPionProduction/PPtable_' + name + '.txt'), unpack=True) - E = logspace(1.5,5,10) * EeV + E = E_data[1:-1:5] p = zeros(len(E)) n = zeros(len(E)) for i,energy in enumerate(E*EeV): p[i] = getSlope(ppp, energy, 1, name) n[i] = getSlope(ppp, energy, 0, name) + figure() plot(E_data, P_data, "r", label="Proton Data") plot(E, p, 'k+', label="Proton Simulated") plot(E_data, N_data, "b", label="Neutron Data") @@ -46,10 +47,9 @@ def compare(type, name): legend(loc='center right') grid() loglog() + xlim(10, 1e5) ylim(1e-4, 1) savefig('PhotoPionProduction_' + name + '.png', bbox_inches='tight') - close() compare(CMB, "CMB") compare(IRB, "IRB") -compare(CMB_IRB, "CMB_IRB") diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 6d787cdba..e77b4a1e7 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -144,9 +144,9 @@ TEST(NuclearDecay, LimitNextStep) { TEST(PhotoDisintegration, Backgrounds) { - PhotoPionProduction ppp1(CMB); - PhotoPionProduction ppp2(IRB); - PhotoPionProduction ppp3(CMB_IRB); + PhotoDisintegration pd1(CMB); + PhotoDisintegration pd2(IRB); + PhotoDisintegration pd3(CMB_IRB); } TEST(PhotoDisintegration, Carbon) { @@ -188,8 +188,7 @@ TEST(PhotoDisintegration, LimitNextStep) { TEST(PhotoPionProduction, Backgrounds) { PhotoPionProduction ppp1(CMB); - PhotoPionProduction ppp2(IRB); - PhotoPionProduction ppp3(CMB_IRB); + PhotoPionProduction ppp2(IRB);; } TEST(PhotoPionProduction, Proton) { @@ -226,6 +225,24 @@ TEST(PhotoPionProduction, LimitNextStep) { EXPECT_TRUE(candidate.getNextStep() < 100 * Mpc); } +TEST(SophiaPhotoPionProduction, Backgrounds) { + SophiaPhotoPionProduction ppp1(CMB); + SophiaPhotoPionProduction ppp2(IRB);; +} + +TEST(SophiaPhotoPionProduction, Proton) { + SophiaPhotoPionProduction ppp; + Candidate candidate; + candidate.setCurrentStep(100 * Mpc); + candidate.current.setId(getNucleusId(1, 1)); + candidate.current.setEnergy(100 * EeV); + ppp.process(&candidate); + EXPECT_TRUE(candidate.current.getEnergy() / EeV < 100); + EXPECT_EQ(candidate.current.getMassNumber(), 1); + EXPECT_TRUE(candidate.secondaries.size() != 0); +} + + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); From 2e8771b47d50f43ef4fe6cff839e5e55e2938f67 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 25 Apr 2012 15:19:36 +0200 Subject: [PATCH 0071/1298] add test script for plotting the pn ratio in photo pion interactions --- .../python/testPhotoPionProduction_pnRatio.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 test/python/testPhotoPionProduction_pnRatio.py diff --git a/test/python/testPhotoPionProduction_pnRatio.py b/test/python/testPhotoPionProduction_pnRatio.py new file mode 100644 index 000000000..72bb88f31 --- /dev/null +++ b/test/python/testPhotoPionProduction_pnRatio.py @@ -0,0 +1,35 @@ +''' +Simulate the p/n-ratio of the final baryon states in SOPHIA photo-pion interactions +''' +from mpc import * +from pylab import * + +spp = SophiaPhotoPionProduction() +c = Candidate() +s = InteractionState() + +def getPNRatio(E): + nP, nN = 0, 0 + for i in range(2000): + c.current.setId(getNucleusId(1, 1)) + c.current.setEnergy(E * EeV) + spp.setNextInteraction(c, s) + spp.performInteraction(c) + if c.current.getId() == getNucleusId(1,1): + nP += 1. + if c.current.getId() == getNucleusId(1,0): + nN += 1. + return nP / nN + +E = logspace(log10(50), 4, 20) +Rpn = zeros(20) +for i in range(20): + print i + Rpn[i] = getPNRatio(E[i]) + +plot(E, Rpn) +grid() +xlabel('Energy of Incident Proton [EeV]') +ylabel('Proton / Neutron Ratio') +semilogx() +savefig('PhotoPionProduction_pnRatio.png', bbox_inches='tight') From 7c6214f45350c8bb955f54418bfbdf862fefb09f Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 26 Apr 2012 17:22:05 +0200 Subject: [PATCH 0072/1298] fix f2bfs on mac --- CMakeLists.txt | 5 +++-- libs/kiss/src/path.cpp | 8 ++++---- src/module/PhotoPionProduction.cpp | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 03303c44d..623177562 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 2.6) -project(ModularPropagationCode) +project(ModularPropagationCode Fortran CXX) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) @@ -11,12 +11,13 @@ set (MPC_SWIG_DEFINES) # GSL required find_package(GSL REQUIRED) list (APPEND MPC_EXTRA_LIBRARIES ${GSL_LIBRARIES} ${GSLCBLAS_LIBRARIES}) +list (APPEND MPC_EXTRA_INCLUDES ${GSL_INCLUDE_DIR}) # fftw needed for TurbulentMagneticField find_package(FFTW) if (FFTW_FOUND) list( APPEND MPC_EXTRA_SOURCES src/magneticField/turbulentMagneticFieldGrid.cpp) - list( APPEND MPC_EXTRA_LIBRARIES ${FFTW_LIBRARY} ${FFTWF_LIBRARY}) + list( APPEND MPC_EXTRA_LIBRARIES ${FFTW_LIBRARY}) endif (FFTW_FOUND) # gadget needed for SphMagneticField diff --git a/libs/kiss/src/path.cpp b/libs/kiss/src/path.cpp index 9be1f4f55..85d727763 100644 --- a/libs/kiss/src/path.cpp +++ b/libs/kiss/src/path.cpp @@ -154,11 +154,11 @@ void append_file(const std::string &target, const std::string &source, std::string executable_path() { char buf[1024]; -#if linux +//#if linux size_t len = readlink("/proc/self/exe", buf, sizeof(buf)-1); -#else - size_t len = ::GetModuleFileName(NULL, buf, sizeof(buf)-1 ); -#endif +//#else +// size_t len = ::GetModuleFileName(NULL, buf, sizeof(buf)-1 ); +//#endif for (size_t i = 1; i < len; i++) { if (buf[len - 1] == path_seperator) break; diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 6b36f41d9..64a5e2847 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -4,7 +4,7 @@ #include "sophia.h" #include -#include +#include #include #include #include @@ -108,7 +108,7 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, // CMB density increases with (1+z)^3 -> free distance decreases accordingly interaction.distance /= pow((1 + z), 3); - if (isnan(interaction.distance)) { + if (std::isnan(interaction.distance)) { return false; } From 0b4c3d5fffce3e3a5645f3c5472619429a6fa873 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 27 Apr 2012 11:05:15 +0200 Subject: [PATCH 0073/1298] add switches for secondary particles in SophiaPhotoPion --- include/mpc/module/PhotoPionProduction.h | 7 ++++- src/module/PhotoPionProduction.cpp | 39 +++++++++++++++++------- test/testInteraction.cpp | 25 ++++++++------- 3 files changed, 46 insertions(+), 25 deletions(-) diff --git a/include/mpc/module/PhotoPionProduction.h b/include/mpc/module/PhotoPionProduction.h index d1f6c58e2..86e8d797d 100644 --- a/include/mpc/module/PhotoPionProduction.h +++ b/include/mpc/module/PhotoPionProduction.h @@ -39,8 +39,13 @@ class PhotoPionProduction: public StochasticInteraction { @brief Photo-pion interactions of nuclei with background photons using SOPHIA. */ class SophiaPhotoPionProduction: public PhotoPionProduction { +protected: + bool havePhotonsElectrons; + bool haveNeutrinos; + bool haveAntiNucleons; public: - SophiaPhotoPionProduction(int photonField = CMB) : PhotoPionProduction(photonField) {}; + SophiaPhotoPionProduction(int photonField = CMB, bool photonsElectrons = + false, bool neutrinos = false, bool antiNucleons = false); void performInteraction(Candidate *candidate) const; }; diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 64a5e2847..384031e1e 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -125,8 +125,8 @@ void PhotoPionProduction::performInteraction(Candidate *candidate) const { int dZ = interaction.channel; // final proton number of emitted nucleon int Zfinal = dZ; - // 1/3 probability of isospin change p <-> n - if (Random::instance().rand() < 1. / 3.) + // 50% probability of isospin change p <-> n + if (Random::instance().rand() < 1. / 2.) Zfinal = abs(Zfinal - 1); double E = candidate->current.getEnergy(); @@ -145,6 +145,14 @@ void PhotoPionProduction::performInteraction(Candidate *candidate) const { } } +SophiaPhotoPionProduction::SophiaPhotoPionProduction(int photonField, + bool photonsElectrons, bool neutrinos, bool antiNucleons) : + PhotoPionProduction(photonField) { + havePhotonsElectrons = photonsElectrons; + haveNeutrinos = neutrinos; + haveAntiNucleons = antiNucleons; +} + void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { InteractionState interaction; candidate->getInteractionState(getDescription(), interaction); @@ -197,31 +205,40 @@ void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { } break; case -13: // anti-proton - candidate->addSecondary(-getNucleusId(1, 1), Eout); + if (haveAntiNucleons) + candidate->addSecondary(-getNucleusId(1, 1), Eout); break; case -14: // anti-neutron - candidate->addSecondary(-getNucleusId(1, 0), Eout); + if (haveAntiNucleons) + candidate->addSecondary(-getNucleusId(1, 0), Eout); break; case 1: // photon - candidate->addSecondary(22, Eout); + if (havePhotonsElectrons) + candidate->addSecondary(22, Eout); break; case 2: // positron - candidate->addSecondary(-11, Eout); + if (havePhotonsElectrons) + candidate->addSecondary(-11, Eout); break; case 3: // electron - candidate->addSecondary(11, Eout); + if (havePhotonsElectrons) + candidate->addSecondary(11, Eout); break; case 15: // nu_e - candidate->addSecondary(12, Eout); + if (haveNeutrinos) + candidate->addSecondary(12, Eout); break; case 16: // antinu_e - candidate->addSecondary(-12, Eout); + if (haveNeutrinos) + candidate->addSecondary(-12, Eout); break; case 17: // nu_muon - candidate->addSecondary(14, Eout); + if (haveNeutrinos) + candidate->addSecondary(14, Eout); break; case 18: // antinu_muon - candidate->addSecondary(-14, Eout); + if (haveNeutrinos) + candidate->addSecondary(-14, Eout); break; default: throw std::runtime_error( diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index e77b4a1e7..8266fc40e 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -83,8 +83,6 @@ TEST(ElectronPairProduction, EnergyLossValues) { } } - - TEST(NuclearDecay, Neutron) { // test beta- decay n -> p Candidate candidate; @@ -141,8 +139,6 @@ TEST(NuclearDecay, LimitNextStep) { EXPECT_TRUE(candidate.getNextStep() < 10 * Mpc); } - - TEST(PhotoDisintegration, Backgrounds) { PhotoDisintegration pd1(CMB); PhotoDisintegration pd2(IRB); @@ -184,11 +180,9 @@ TEST(PhotoDisintegration, LimitNextStep) { EXPECT_TRUE(candidate.getNextStep() < 100 * Mpc); } - - TEST(PhotoPionProduction, Backgrounds) { PhotoPionProduction ppp1(CMB); - PhotoPionProduction ppp2(IRB);; + PhotoPionProduction ppp2(IRB); } TEST(PhotoPionProduction, Proton) { @@ -225,11 +219,6 @@ TEST(PhotoPionProduction, LimitNextStep) { EXPECT_TRUE(candidate.getNextStep() < 100 * Mpc); } -TEST(SophiaPhotoPionProduction, Backgrounds) { - SophiaPhotoPionProduction ppp1(CMB); - SophiaPhotoPionProduction ppp2(IRB);; -} - TEST(SophiaPhotoPionProduction, Proton) { SophiaPhotoPionProduction ppp; Candidate candidate; @@ -239,9 +228,19 @@ TEST(SophiaPhotoPionProduction, Proton) { ppp.process(&candidate); EXPECT_TRUE(candidate.current.getEnergy() / EeV < 100); EXPECT_EQ(candidate.current.getMassNumber(), 1); - EXPECT_TRUE(candidate.secondaries.size() != 0); + EXPECT_TRUE(candidate.secondaries.size() == 0); } +TEST(SophiaPhotoPionProduction, withSecondaries) { + SophiaPhotoPionProduction ppp(CMB, true, true, true); + Candidate candidate; + candidate.current.setId(getNucleusId(1, 1)); + candidate.current.setEnergy(100 * EeV); + InteractionState interaction; + ppp.setNextInteraction(&candidate, interaction); + ppp.performInteraction(&candidate); + EXPECT_TRUE(candidate.secondaries.size() >= 2); +} int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); From 63bc142f00bb6de2e162f24f4bb4ae7d9eb93f57 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 30 Apr 2012 13:34:48 +0200 Subject: [PATCH 0074/1298] add leptonic secondaries to NuclearDecay --- CMakeLists.txt | 82 ++++++++---------- include/mpc/Vector3.h | 2 +- include/mpc/module/NuclearDecay.h | 11 ++- include/mpc/module/PhotoPionProduction.h | 5 ++ src/module/NuclearDecay.cpp | 106 +++++++++++++++++------ test/testBreakCondition.cpp | 1 + test/testInteraction.cpp | 16 ++-- test/testMagneticField.cpp | 3 +- 8 files changed, 146 insertions(+), 80 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 623177562..a5ad33664 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,60 +3,60 @@ project(ModularPropagationCode Fortran CXX) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) -set (MPC_EXTRA_SOURCES) -set (MPC_EXTRA_INCLUDES) -set (MPC_EXTRA_LIBRARIES) -set (MPC_SWIG_DEFINES) +set(MPC_EXTRA_SOURCES) +set(MPC_EXTRA_INCLUDES) +set(MPC_EXTRA_LIBRARIES) +set(MPC_SWIG_DEFINES) # GSL required find_package(GSL REQUIRED) -list (APPEND MPC_EXTRA_LIBRARIES ${GSL_LIBRARIES} ${GSLCBLAS_LIBRARIES}) -list (APPEND MPC_EXTRA_INCLUDES ${GSL_INCLUDE_DIR}) +list(APPEND MPC_EXTRA_LIBRARIES ${GSL_LIBRARIES} ${GSLCBLAS_LIBRARIES}) +list(APPEND MPC_EXTRA_INCLUDES ${GSL_INCLUDE_DIR}) # fftw needed for TurbulentMagneticField find_package(FFTW) if (FFTW_FOUND) - list( APPEND MPC_EXTRA_SOURCES src/magneticField/turbulentMagneticFieldGrid.cpp) - list( APPEND MPC_EXTRA_LIBRARIES ${FFTW_LIBRARY}) + list(APPEND MPC_EXTRA_SOURCES src/magneticField/turbulentMagneticFieldGrid.cpp) + list(APPEND MPC_EXTRA_LIBRARIES ${FFTW_LIBRARY}) endif (FFTW_FOUND) # gadget needed for SphMagneticField find_package(Gadget) if (GADGET_FOUND) - list( APPEND MPC_EXTRA_SOURCES src/magneticField/sphMagneticField.cpp) - list( APPEND MPC_EXTRA_INCLUDES ${GADGET_INCLUDE_DIR}) - list( APPEND MPC_EXTRA_LIBRARIES ${GADGET_LIBRARY}) - add_definitions(-DMPC_HAVE_GADGET) - list( APPEND MPC_SWIG_DEFINES -DMPC_HAVE_GADGET) + list(APPEND MPC_EXTRA_SOURCES src/magneticField/sphMagneticField.cpp) + list(APPEND MPC_EXTRA_INCLUDES ${GADGET_INCLUDE_DIR}) + list(APPEND MPC_EXTRA_LIBRARIES ${GADGET_LIBRARY}) + add_definitions (-DMPC_HAVE_GADGET) + list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_GADGET) endif (GADGET_FOUND) -# Google Performance Tools +# Google Performance Tools optional find_package(GooglePerfTools) -SET(TCMALLOC) -IF (GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) - SET(TCMALLOC ${TCMALLOC_LIBRARY}) +set(TCMALLOC) +if (GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) + set(TCMALLOC ${TCMALLOC_LIBRARY}) endif(GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) # pugixml provided add_library (pugixml libs/pugixml/pugixml.cpp) -SET_TARGET_PROPERTIES( pugixml PROPERTIES COMPILE_FLAGS -fPIC) -list (APPEND MPC_EXTRA_LIBRARIES pugixml) -list (APPEND MPC_EXTRA_INCLUDES libs/pugixml) +set_target_properties( pugixml PROPERTIES COMPILE_FLAGS -fPIC) +list(APPEND MPC_EXTRA_LIBRARIES pugixml) +list(APPEND MPC_EXTRA_INCLUDES libs/pugixml) # kiss provided add_subdirectory(libs/kiss) -list (APPEND MPC_EXTRA_LIBRARIES kiss) -list (APPEND MPC_EXTRA_INCLUDES libs/kiss/include) +list(APPEND MPC_EXTRA_LIBRARIES kiss) +list(APPEND MPC_EXTRA_INCLUDES libs/kiss/include) # HepID provided add_subdirectory(libs/HepPID) -list (APPEND MPC_EXTRA_LIBRARIES HepPID) -list (APPEND MPC_EXTRA_INCLUDES libs/HepPID/include) +list(APPEND MPC_EXTRA_LIBRARIES HepPID) +list(APPEND MPC_EXTRA_INCLUDES libs/HepPID/include) # SOPHIA provided add_subdirectory(libs/sophia) -list (APPEND MPC_EXTRA_LIBRARIES sophia gfortran) -list (APPEND MPC_EXTRA_INCLUDES libs/sophia) +list(APPEND MPC_EXTRA_LIBRARIES sophia gfortran) +list(APPEND MPC_EXTRA_INCLUDES libs/sophia) # OpenMP needed for shared memory multiprocessing include(FindOpenMP) @@ -98,15 +98,15 @@ add_library(mpc SHARED src/magneticField/magneticFieldGrid.cpp ${MPC_EXTRA_SOURCES} ) -TARGET_LINK_LIBRARIES(mpc ${MPC_EXTRA_LIBRARIES} ${TCMALLOC}) +target_link_libraries(mpc ${MPC_EXTRA_LIBRARIES} ${TCMALLOC}) add_executable(mpc-run src/main.cpp) -TARGET_LINK_LIBRARIES(mpc-run mpc ${TCMALLOC}) +target_link_libraries(mpc-run mpc ${TCMALLOC}) -INSTALL(TARGETS mpc-run RUNTIME DESTINATION bin) -INSTALL(TARGETS mpc DESTINATION lib) -INSTALL(DIRECTORY include/ DESTINATION include FILES_MATCHING PATTERN "*.h") -INSTALL(DIRECTORY data/ DESTINATION share/mpc) +install(TARGETS mpc-run RUNTIME DESTINATION bin) +install(TARGETS mpc DESTINATION lib) +install(DIRECTORY include/ DESTINATION include FILES_MATCHING PATTERN "*.h") +install(DIRECTORY data/ DESTINATION share/mpc) # ---------------------------------------------------------------------------- # Testing using gTest @@ -131,21 +131,15 @@ if (GTEST_FOUND) target_link_libraries(testInteraction mpc ${GTEST_BOTH_LIBRARIES} pthread) endif (GTEST_FOUND) -# ---------------------------------------------------------------------------- -# OpenMP -# ---------------------------------------------------------------------------- -add_executable(mpc-omp-run src/openmp.cpp) -TARGET_LINK_LIBRARIES(mpc-omp-run mpc) - # ---------------------------------------------------------------------------- # Python # ---------------------------------------------------------------------------- -INCLUDE (python/Python.cmake) +include(python/Python.cmake) include_directories(${PYTHON_INCLUDE_PATH}) -FILE(GLOB_RECURSE MPC_INCLUDES include/*.h) -SET_SOURCE_FILES_PROPERTIES( ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx PROPERTIES GENERATED true ) -ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx +file(GLOB_RECURSE MPC_INCLUDES include/*.h) +set_source_files_properties( ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx PROPERTIES GENERATED true ) +add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx COMMAND swig -c++ -python ${MPC_SWIG_DEFINES} -I${CMAKE_SOURCE_DIR}/include -o ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx -outdir ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/python/mpc.i DEPENDS ${CMAKE_SOURCE_DIR}/python/mpc.i ${MPC_INCLUDES} ) add_library(mpc-swig MODULE ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx) @@ -153,5 +147,5 @@ add_library(mpc-swig MODULE ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx) set_target_properties(mpc-swig PROPERTIES PREFIX "") set_target_properties(mpc-swig PROPERTIES OUTPUT_NAME "_mpc") target_link_libraries(mpc-swig mpc ${PYTHON_LIBRARIES}) -INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/mpc.py" DESTINATION ${PYTHON_SITE_PACKAGES}) -INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/_mpc.so" DESTINATION ${PYTHON_SITE_PACKAGES}) +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/mpc.py" DESTINATION ${PYTHON_SITE_PACKAGES}) +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_mpc.so" DESTINATION ${PYTHON_SITE_PACKAGES}) diff --git a/include/mpc/Vector3.h b/include/mpc/Vector3.h index 0df57c27b..520d51532 100644 --- a/include/mpc/Vector3.h +++ b/include/mpc/Vector3.h @@ -119,7 +119,7 @@ class Vector3 { // Set the transverse component keeping phi and z constant. void setCylTheta(double); - // Set theta while keeping transvers component and phi fixed + // Set theta while keeping transverse component and phi fixed inline double perp2(const Vector3 &) const; // The transverse component w.r.t. given axis squared. diff --git a/include/mpc/module/NuclearDecay.h b/include/mpc/module/NuclearDecay.h index c3cacbd9a..e2254d041 100644 --- a/include/mpc/module/NuclearDecay.h +++ b/include/mpc/module/NuclearDecay.h @@ -4,6 +4,8 @@ #include "mpc/module/StochasticInteraction.h" #include "mpc/Random.h" +#include +#include #include #include @@ -17,13 +19,20 @@ namespace mpc { */ class NuclearDecay: public StochasticInteraction { private: + bool haveElectrons; + bool haveNeutrinos; + std::map > decayTable; + gsl_interp_accel *acc; + gsl_spline *Tbeta; // inverse cdf electron kinetic energy [J] in neutron decay public: - NuclearDecay(); + NuclearDecay(bool electrons = false, bool neutrinos = false); bool setNextInteraction(Candidate *candidate, InteractionState &interaction) const; void performInteraction(Candidate *candidate) const; + void betaDecay(Candidate *candidate, bool isBetaPlus) const; + void nucleonEmission(Candidate *candidate, int dA, int dZ) const; }; } // namespace mpc diff --git a/include/mpc/module/PhotoPionProduction.h b/include/mpc/module/PhotoPionProduction.h index 86e8d797d..9ab0d2a0f 100644 --- a/include/mpc/module/PhotoPionProduction.h +++ b/include/mpc/module/PhotoPionProduction.h @@ -37,6 +37,11 @@ class PhotoPionProduction: public StochasticInteraction { /** @class SophiaPhotoPionProduction @brief Photo-pion interactions of nuclei with background photons using SOPHIA. + + This module simulates photo-hadronic interactions of nuclei with background photons.\n + Several photon fields can be selected. They are considered as homogeneous and evolving as the CMB.\n + The interaction itself is simulated with SOPHIA.\n + Electromagnetic particles, neutrinos and antiparticles as secondaries from these interactions can be switched on independently. */ class SophiaPhotoPionProduction: public PhotoPionProduction { protected: diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index dbccf2140..2f746a16c 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -7,11 +7,14 @@ namespace mpc { -NuclearDecay::NuclearDecay() { +NuclearDecay::NuclearDecay(bool electrons, bool neutrinos) { setDescription("NuclearDecay"); + haveElectrons = electrons; + haveNeutrinos = neutrinos; + + // load decay table std::string filename = getDataPath("/NuclearDecay/decay_table.txt"); std::ifstream infile(filename.c_str()); - if (!infile.good()) throw std::runtime_error( "mpc::NuclearDecay: could not open file " + filename); @@ -28,8 +31,27 @@ NuclearDecay::NuclearDecay() { } infile.ignore(std::numeric_limits::max(), '\n'); } - infile.close(); + + // generate inverse cdf for electron kinetic energies in neutron decays + double Q = mass_neutron - mass_proton; + double cdf = 0; + std::vector x, y; + x.resize(50); + y.resize(50); + for (int i = 0; i < 50; i++) { + double E = mass_electron + i / 50. * (Q - mass_electron); + cdf += sqrt(pow(E, 2) - pow(mass_electron, 2)) * pow(Q - E, 2) * E; + x[i] = cdf; + y[i] = (E - mass_electron) * c_squared; + } + for (int i = 0; i < 50; i++) { + x[i] /= x.back(); + } + + acc = gsl_interp_accel_alloc(); + Tbeta = gsl_spline_alloc(gsl_interp_linear, x.size()); + gsl_spline_init(Tbeta, &x[0], &y[0], x.size()); } bool NuclearDecay::setNextInteraction(Candidate *candidate, @@ -63,40 +85,70 @@ void NuclearDecay::performInteraction(Candidate *candidate) const { candidate->getInteractionState(getDescription(), decay); candidate->clearInteractionStates(); - // parse decay channel + // parse decay channels int nBeta = digit(decay.channel, 10000); int nBetaPlus = digit(decay.channel, 1000); int nAlpha = digit(decay.channel, 100); int nProton = digit(decay.channel, 10); int nNeutron = digit(decay.channel, 1); - int dA = -4 * nAlpha - nProton - nNeutron; - int dZ = -2 * nAlpha - nProton + nBeta - nBetaPlus; + // perform decays + for (size_t i = 0; i < nBeta; i++) + betaDecay(candidate, false); + for (size_t i = 0; i < nBetaPlus; i++) + betaDecay(candidate, true); + for (size_t i = 0; i < nAlpha; i++) + nucleonEmission(candidate, 4, 2); + for (size_t i = 0; i < nProton; i++) + nucleonEmission(candidate, 1, 1); + for (size_t i = 0; i < nNeutron; i++) + nucleonEmission(candidate, 1, 0); +} - int A = candidate->current.getMassNumber(); +void NuclearDecay::betaDecay(Candidate *candidate, bool isBetaPlus) const { + double gamma = candidate->current.getLorentzFactor(); int Z = candidate->current.getChargeNumber(); - double EpA = candidate->current.getEnergy() / double(A); + int A = candidate->current.getMassNumber(); + double mass = candidate->current.getMass(); + + int electronId = 11; // electron + int neutrinoId = -12; // anti-electron neutrino + int dZ = 1; + if (isBetaPlus) { + electronId = -11; // positron + neutrinoId = 12; // electron neutrion + dZ = -1; + } - // update particle - candidate->current.setId(getNucleusId(A + dA, Z + dZ)); - candidate->current.setEnergy(EpA * (A + dA)); + // update candidate + candidate->current.setId(getNucleusId(A, Z + dZ)); + candidate->current.setLorentzFactor(gamma); + + // random kinetic energy of electron in neutron decay + double T = gsl_spline_eval(Tbeta, Random::instance().rand(), acc); + double Q = (mass - candidate->current.getMass()) * c_squared; + double Qneutron = (mass_neutron - mass_proton) * c_squared; + // electron energy in this decay + double E = T * Q / Qneutron + mass_electron * c_squared; + double p = sqrt(E * E - pow(mass_electron * c_squared, 2)); + double cosTheta = 2 * Random::instance().rand() - 1; + + if (haveElectrons) + // add electron/positron boosted to lab frame + candidate->addSecondary(electronId, gamma * E * (1 + p * cosTheta)); + if (haveNeutrinos) + // add neutrino with remaining energy and opposite momentum + candidate->addSecondary(neutrinoId, gamma * (Q - E) * (1 - p * cosTheta)); +} - // create secondaries - for (size_t i = 0; i < nBeta; i++) { - // electron + neutrino not implemented - } - for (size_t i = 0; i < nBetaPlus; i++) { - // positron + neutrino not implemented - } - for (size_t i = 0; i < nAlpha; i++) { - candidate->addSecondary(getNucleusId(4, 2), EpA * 4); - } - for (size_t i = 0; i < nProton; i++) { - candidate->addSecondary(getNucleusId(1, 1), EpA); - } - for (size_t i = 0; i < nNeutron; i++) { - candidate->addSecondary(getNucleusId(1, 0), EpA); - } +void NuclearDecay::nucleonEmission(Candidate *candidate, int dA, int dZ) const { + int Z = candidate->current.getChargeNumber(); + int A = candidate->current.getMassNumber(); + double EpA = candidate->current.getEnergy() + / double(candidate->current.getMassNumber()); + candidate->current.setId(getNucleusId(A - dA, Z - dZ)); + candidate->current.setEnergy(EpA * (A - dA)); + candidate->addSecondary(getNucleusId(dA, dZ), EpA * dA); } } // namespace mpc diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index 2776d0122..4e9b849d8 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -1,5 +1,6 @@ #include "mpc/module/BreakCondition.h" #include "mpc/Candidate.h" + #include "gtest/gtest.h" namespace mpc { diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 8266fc40e..6fcf3a1ba 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -84,14 +84,16 @@ TEST(ElectronPairProduction, EnergyLossValues) { } TEST(NuclearDecay, Neutron) { - // test beta- decay n -> p + // test beta- decay n -> p within 1 hour Candidate candidate; - candidate.setCurrentStep(1 * Mpc); + candidate.setCurrentStep(3600 * c_light); candidate.current.setId(getNucleusId(1, 0)); - candidate.current.setEnergy(1 * EeV); + candidate.current.setEnergy(mass_neutron * c_squared); NuclearDecay d; d.process(&candidate); - EXPECT_EQ(candidate.current.getId(), getNucleusId(1,1)); + EXPECT_EQ(getNucleusId(1,1), candidate.current.getId()); + // leptonic secondaries not turned on + EXPECT_EQ(0, candidate.secondaries.size()); } TEST(NuclearDecay, Scandium44) { @@ -100,9 +102,11 @@ TEST(NuclearDecay, Scandium44) { candidate.setCurrentStep(1 * Mpc); candidate.current.setId(getNucleusId(44, 21)); candidate.current.setEnergy(1 * EeV); - NuclearDecay d; + NuclearDecay d(true, true); d.process(&candidate); - EXPECT_EQ(candidate.current.getId(), getNucleusId(44,20)); + EXPECT_EQ(getNucleusId(44,20), candidate.current.getId()); + // 2 leptons expected + EXPECT_EQ(2, candidate.secondaries.size()); } TEST(NuclearDecay, Li4) { diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index c92d3021e..5c81c337d 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -1,8 +1,9 @@ -#include "gtest/gtest.h" #include "mpc/magneticField/uniformMagneticField.h" #include "mpc/magneticField/magneticFieldGrid.h" #include "mpc/magneticField/turbulentMagneticFieldGrid.h" #include "mpc/Units.h" + +#include "gtest/gtest.h" #include "fftw3.h" #include From fc29849a0e5684379f8277732d683be29475df3d Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 3 May 2012 15:05:19 +0200 Subject: [PATCH 0075/1298] fix NuclearDecay, add quantitative test --- src/module/NuclearDecay.cpp | 4 ++-- src/module/StochasticInteraction.cpp | 22 ++++++++++++---------- test/testInteraction.cpp | 19 ++++++++++++------- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index 2f746a16c..61bca4dd2 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -126,8 +126,8 @@ void NuclearDecay::betaDecay(Candidate *candidate, bool isBetaPlus) const { // random kinetic energy of electron in neutron decay double T = gsl_spline_eval(Tbeta, Random::instance().rand(), acc); - double Q = (mass - candidate->current.getMass()) * c_squared; - double Qneutron = (mass_neutron - mass_proton) * c_squared; + double Q = (mass - candidate->current.getMass() - mass_electron) * c_squared; + double Qneutron = (mass_neutron - mass_proton - mass_electron) * c_squared; // electron energy in this decay double E = T * Q / Qneutron + mass_electron * c_squared; double p = sqrt(E * E - pow(mass_electron * c_squared, 2)); diff --git a/src/module/StochasticInteraction.cpp b/src/module/StochasticInteraction.cpp index 5d0932cd9..34c320495 100644 --- a/src/module/StochasticInteraction.cpp +++ b/src/module/StochasticInteraction.cpp @@ -4,19 +4,21 @@ namespace mpc { void StochasticInteraction::process(Candidate* candidate) const { double step = candidate->getCurrentStep(); - InteractionState interaction; - while (true) { - // check if an interaction is set + while (step >= 0) { + // get the interaction state, if there is one + InteractionState interaction; bool noState = !candidate->getInteractionState(getDescription(), interaction); + + // if no interaction state, set a new one if (noState) { - // try to set a new interaction - bool successful = setNextInteraction(candidate, interaction); - if (not (successful)) - return; // no new interaction for this particle + bool noNewState = !setNextInteraction(candidate, interaction); + // no new interaction; return + if (noNewState) + return; } - // if not over, reduce distance and return + // if interaction distance not reached, reduce it and return if (interaction.distance > step) { interaction.distance -= step; candidate->limitNextStep(interaction.distance); @@ -24,9 +26,9 @@ void StochasticInteraction::process(Candidate* candidate) const { return; } - // counter over: interact - step -= interaction.distance; + // else: interaction distance reached; interact and repeat with remaining step performInteraction(candidate); + step -= interaction.distance; } } diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 6fcf3a1ba..754804d03 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -84,16 +84,20 @@ TEST(ElectronPairProduction, EnergyLossValues) { } TEST(NuclearDecay, Neutron) { - // test beta- decay n -> p within 1 hour + // Quantitativ test of decaying neutrons at rest + // Due to the stochastic nature this test might fail. Candidate candidate; - candidate.setCurrentStep(3600 * c_light); candidate.current.setId(getNucleusId(1, 0)); candidate.current.setEnergy(mass_neutron * c_squared); - NuclearDecay d; - d.process(&candidate); - EXPECT_EQ(getNucleusId(1,1), candidate.current.getId()); - // leptonic secondaries not turned on - EXPECT_EQ(0, candidate.secondaries.size()); + NuclearDecay decay; + InteractionState state; + double tau = 0; + for (int i=0; i<100000; i++) { + decay.setNextInteraction(&candidate, state); + tau += state.distance; + } + tau /= c_light * 100000; + EXPECT_NEAR(tau, 881.46, 8.8); } TEST(NuclearDecay, Scandium44) { @@ -118,6 +122,7 @@ TEST(NuclearDecay, Li4) { NuclearDecay d; d.process(&candidate); EXPECT_EQ(getNucleusId(3,2), candidate.current.getId()); + EXPECT_EQ(1, candidate.secondaries.size()); } TEST(NuclearDecay, He5) { From 6811e0c6328286c7a5874e7cd3f39bc5030b8343 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 3 May 2012 19:44:38 +0200 Subject: [PATCH 0076/1298] change to template Vector3 class --- CMakeLists.txt | 2 +- include/mpc/IO.h | 4 +- include/mpc/ParticleState.h | 16 +- include/mpc/PhasePoint.h | 14 +- include/mpc/Random.h | 2 +- include/mpc/Source.h | 4 +- include/mpc/Vector3.h | 438 ------------------ include/mpc/Vector3Inline.h | 346 -------------- include/mpc/magneticField/magneticField.h | 4 +- include/mpc/magneticField/magneticFieldGrid.h | 12 +- include/mpc/magneticField/sphMagneticField.h | 12 +- .../turbulentMagneticFieldGrid.h | 2 +- .../mpc/magneticField/uniformMagneticField.h | 8 +- include/mpc/module/BreakCondition.h | 18 +- include/mpc/module/Redshift.h | 4 +- python/mpc.i | 1 - src/IO.cpp | 20 +- src/ParticleState.cpp | 12 +- src/Random.cpp | 4 +- src/Source.cpp | 4 +- src/magneticField/magneticFieldGrid.cpp | 18 +- src/magneticField/sphMagneticField.cpp | 35 +- .../turbulentMagneticFieldGrid.cpp | 24 +- src/main.cpp | 6 +- src/module/BreakCondition.cpp | 18 +- src/module/DeflectionCK.cpp | 24 +- src/module/Output.cpp | 28 +- src/module/Redshift.cpp | 2 +- src/module/SimplePropagation.cpp | 4 +- test/python/testDeflectionCK.py | 10 +- test/testBreakCondition.cpp | 48 +- test/testCore.cpp | 8 +- test/testMagneticField.cpp | 57 +-- test/testPropagation.cpp | 32 +- 34 files changed, 226 insertions(+), 1015 deletions(-) delete mode 100644 include/mpc/Vector3.h delete mode 100644 include/mpc/Vector3Inline.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a5ad33664..f547e2c28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,7 +75,7 @@ add_definitions(-DMPC_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") add_library(mpc SHARED src/Random.cpp src/Clock.cpp - src/Vector3.cpp +# src/Vector3.cpp src/ModuleList.cpp src/Module.cpp src/Candidate.cpp diff --git a/include/mpc/IO.h b/include/mpc/IO.h index 9b4bb9975..5f43af4e2 100644 --- a/include/mpc/IO.h +++ b/include/mpc/IO.h @@ -7,7 +7,7 @@ namespace mpc { -void write(kiss::Output &out, const mpc::Vector3 &vec3); +void write(kiss::Output &out, const mpc::Vector3d &vec3); void write(kiss::Output &out, const mpc::ParticleState &state); @@ -15,7 +15,7 @@ void write(kiss::Output &out, const mpc::InteractionState &s); void write(kiss::Output &out, const mpc::Candidate &candidate); -bool read(kiss::Input &in, mpc::Vector3 &vec3); +bool read(kiss::Input &in, mpc::Vector3d &vec3); bool read(kiss::Input &in, mpc::ParticleState &state); diff --git a/include/mpc/ParticleState.h b/include/mpc/ParticleState.h index c81528240..c6d42dbce 100644 --- a/include/mpc/ParticleState.h +++ b/include/mpc/ParticleState.h @@ -17,16 +17,16 @@ class ParticleState { int id; double pmass; double energy; - Vector3 position; - Vector3 direction; + Vector3d position; + Vector3d direction; public: ParticleState(); - void setPosition(const Vector3 &pos); - const Vector3 &getPosition() const; + void setPosition(const Vector3d &pos); + const Vector3d &getPosition() const; - void setDirection(const Vector3 &dir); - const Vector3 &getDirection() const; + void setDirection(const Vector3d &dir); + const Vector3d &getDirection() const; void setEnergy(const double newEnergy); double getEnergy() const; @@ -46,8 +46,8 @@ class ParticleState { void setLorentzFactor(const double gamma); double getLorentzFactor() const; - Vector3 getVelocity() const; - Vector3 getMomentum() const; + Vector3d getVelocity() const; + Vector3d getMomentum() const; }; } // namespace mpc diff --git a/include/mpc/PhasePoint.h b/include/mpc/PhasePoint.h index e33c0ce50..1da519d69 100644 --- a/include/mpc/PhasePoint.h +++ b/include/mpc/PhasePoint.h @@ -11,17 +11,17 @@ namespace mpc { */ class PhasePoint { public: - Vector3 a, b; + Vector3d a, b; PhasePoint() { } - PhasePoint(const Vector3 &a, const Vector3 &b) : + PhasePoint(const Vector3d &a, const Vector3d &b) : a(a), b(b) { } PhasePoint(double f) : - a(Vector3(f, f, f)), b(Vector3(f, f, f)) { + a(Vector3d(f, f, f)), b(Vector3d(f, f, f)) { } PhasePoint operator *(double f) const { @@ -29,8 +29,8 @@ class PhasePoint { } PhasePoint &operator =(double f) { - a.set(f, f, f); - b.set(f, f, f); + a = Vector3d(f, f, f); + b = Vector3d(f, f, f); return *this; } @@ -45,8 +45,8 @@ class PhasePoint { } PhasePoint abs() const { - Vector3 abs_a( fabs(a.x()), fabs(a.y()), fabs(a.z()) ); - Vector3 abs_b( fabs(b.x()), fabs(b.y()), fabs(b.z()) ); + Vector3d abs_a( fabs(a.x), fabs(a.y), fabs(a.z) ); + Vector3d abs_b( fabs(b.x), fabs(b.y), fabs(b.z) ); return PhasePoint(abs_a, abs_b); } }; diff --git a/include/mpc/Random.h b/include/mpc/Random.h index fe1e54f19..f58f47e39 100644 --- a/include/mpc/Random.h +++ b/include/mpc/Random.h @@ -137,7 +137,7 @@ class Random { /// Broken power-law distribution double randBrokenPowerLaw(double index1, double index2, double breakpoint, double min, double max ); /// Random point on a unit-sphere - Vector3 randUnitVectorOnSphere(); + Vector3d randUnitVectorOnSphere(); /// Seed the generator with a simple uint32 void seed( const uint32 oneSeed ); diff --git a/include/mpc/Source.h b/include/mpc/Source.h index 6b28e26f7..d95dee110 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -26,11 +26,11 @@ class Source: public Referenced { */ class BasicSource: public Source { public: - Vector3 position; + Vector3d position; double index1, index2, breakpoint, Emin, Emax; int id; BasicSource(); - BasicSource(const Vector3 &sposition, int type, double Emin = 5 * EeV, + BasicSource(const Vector3d &sposition, int type, double Emin = 5 * EeV, double Emax = 1000 * EeV, double index1 = -1, double index2 = -1, double breakpoint = 1); diff --git a/include/mpc/Vector3.h b/include/mpc/Vector3.h deleted file mode 100644 index 520d51532..000000000 --- a/include/mpc/Vector3.h +++ /dev/null @@ -1,438 +0,0 @@ -// -*- C++ -*- -// CLASSDOC OFF -// $Id: ThreeVector.h,v 1.4 2010/06/16 17:15:57 garren Exp $ -// --------------------------------------------------------------------------- -// CLASSDOC ON -// -// This file is a part of the CLHEP - a Class Library for High Energy Physics. -// -// Vector3 is a general 3-vector class defining vectors in three -// dimension using double components. Rotations of these vectors are -// performed by multiplying with an object of the HepRotation class. -// -// .SS See Also -// LorentzVector.h, Rotation.h, LorentzRotation.h -// -// .SS Authors -// Leif Lonnblad and Anders Nilsson; Modified by Evgueni Tcherniaev; -// ZOOM additions by Mark Fischler -// - -#ifndef HEP_THREEVECTOR_H -#define HEP_THREEVECTOR_H - -#ifdef GNUPRAGMA -#pragma interface -#endif - -#include - -namespace mpc { - -/** - @class Vector3 - @brief CLHEP 3-vector - */ -class Vector3 { - -public: - - // Basic properties and operations on 3-vectors: - - enum { - X = 0, Y = 1, Z = 2, NUM_COORDINATES = 3, SIZE = NUM_COORDINATES - }; - // Safe indexing of the coordinates when using with matrices, arrays, etc. - // (BaBar) - - Vector3(); - explicit Vector3(double x); - Vector3(double x, double y); - Vector3(double x, double y, double z); - // The constructor. - - inline Vector3(const Vector3 &); - // The copy constructor. - - inline ~Vector3(); - // The destructor. Not virtual - inheritance from this class is dangerous. - - double operator ()(int) const; - // Get components by index -- 0-based (Geant4) - - inline double operator [](int) const; - // Get components by index -- 0-based (Geant4) - - double & operator ()(int); - // Set components by index. 0-based. - - inline double & operator [](int); - // Set components by index. 0-based. - - inline double x() const; - inline double y() const; - inline double z() const; - // The components in cartesian coordinate system. Same as getX() etc. - - inline void setX(double); - inline void setY(double); - inline void setZ(double); - // Set the components in cartesian coordinate system. - - inline void set(double x, double y, double z); - // Set all three components in cartesian coordinate system. - - inline double phi() const; - // The azimuth angle. - - inline double theta() const; - // The polar angle. - - inline double cosTheta() const; - // Cosine of the polar angle. - - inline double cos2Theta() const; - // Cosine squared of the polar angle - faster than cosTheta(). (ZOOM) - - inline double mag2() const; - // The magnitude squared (r^2 in spherical coordinate system). - - inline double mag() const; - // The magnitude (r in spherical coordinate system). - - inline void setPhi(double); - // Set phi keeping mag and theta constant (BaBar). - - inline void setTheta(double); - // Set theta keeping mag and phi constant (BaBar). - - void setMag(double); - // Set magnitude keeping theta and phi constant (BaBar). - - inline double perp2() const; - // The transverse component squared (rho^2 in cylindrical coordinate system). - - inline double perp() const; - // The transverse component (rho in cylindrical coordinate system). - - inline void setPerp(double); - // Set the transverse component keeping phi and z constant. - - void setCylTheta(double); - // Set theta while keeping transverse component and phi fixed - - inline double perp2(const Vector3 &) const; - // The transverse component w.r.t. given axis squared. - - inline double perp(const Vector3 &) const; - // The transverse component w.r.t. given axis. - - inline Vector3 & operator =(const Vector3 &); - // Assignment. - - inline bool operator ==(const Vector3 &) const; - inline bool operator !=(const Vector3 &) const; - // Comparisons (Geant4). - - bool isNear(const Vector3 &, double epsilon = tolerance) const; - // Check for equality within RELATIVE tolerance (default 2.2E-14). (ZOOM) - // |v1 - v2|**2 <= epsilon**2 * |v1.dot(v2)| - - double howNear(const Vector3 & v) const; - // sqrt ( |v1-v2|**2 / v1.dot(v2) ) with a maximum of 1. - // If v1.dot(v2) is negative, will return 1. - - double deltaR(const Vector3 & v) const; - // sqrt( pseudorapity_difference**2 + deltaPhi **2 ) - - inline Vector3 & operator +=(const Vector3 &); - // Addition. - - inline Vector3 & operator -=(const Vector3 &); - // Subtraction. - - inline Vector3 operator -() const; - // Unary minus. - - inline Vector3 & operator *=(double); - // Scaling with real numbers. - - Vector3 & operator /=(double); - // Division by (non-zero) real number. - - inline Vector3 unit() const; - // Vector parallel to this, but of length 1. - - inline Vector3 orthogonal() const; - // Vector orthogonal to this (Geant4). - - inline double dot(const Vector3 &) const; - // double product. - - inline Vector3 cross(const Vector3 &) const; - // Cross product. - - double angle(const Vector3 &) const; - // The angle w.r.t. another 3-vector. - - double pseudoRapidity() const; - // Returns the pseudo-rapidity, i.e. -ln(tan(theta/2)) - - void setEta(double p); - // Set pseudo-rapidity, keeping magnitude and phi fixed. (ZOOM) - - void setCylEta(double p); - // Set pseudo-rapidity, keeping transverse component and phi fixed. (ZOOM) - - Vector3 & rotateX(double); - // Rotates the Vector3 around the x-axis. - - Vector3 & rotateY(double); - // Rotates the Vector3 around the y-axis. - - Vector3 & rotateZ(double); - // Rotates the Vector3 around the z-axis. - - Vector3 & rotateUz(const Vector3&); - // Rotates reference frame from Uz to newUz (unit vector) (Geant4). - - //Vector3 & rotate(double, const Vector3 &); - // Rotates around the axis specified by another Vector3. - // (Uses methods of HepRotation, forcing linking in of Rotation.cc.) - - // Transformation with a Rotation matrix. - - // = = = = = = = = = = = = = = = = = = = = = = = = - // - // Esoteric properties and operations on 3-vectors: - // - // 1 - Set vectors in various coordinate systems - // 2 - Synonyms for accessing coordinates and properties - // 3 - Comparisions (dictionary, near-ness, and geometric) - // 4 - Intrinsic properties - // 5 - Properties releative to z axis and arbitrary directions - // 6 - Polar and azimuthal angle decomposition and deltaPhi - // 7 - Rotations - // - // = = = = = = = = = = = = = = = = = = = = = = = = - - // 1 - Set vectors in various coordinate systems - - inline void setRThetaPhi(double r, double theta, double phi); - // Set in spherical coordinates: Angles are measured in RADIANS - - inline void setREtaPhi(double r, double eta, double phi); - // Set in spherical coordinates, but specify peudorapidiy to determine theta. - - inline void setRhoPhiZ(double rho, double phi, double z); - // Set in cylindrical coordinates: Phi angle is measured in RADIANS - - void setRhoPhiTheta(double rho, double phi, double theta); - // Set in cylindrical coordinates, but specify theta to determine z. - - void setRhoPhiEta(double rho, double phi, double eta); - // Set in cylindrical coordinates, but specify pseudorapidity to determine z. - - // 2 - Synonyms for accessing coordinates and properties - - inline double getX() const; - inline double getY() const; - inline double getZ() const; - // x(), y(), and z() - - inline double getR() const; - inline double getTheta() const; - inline double getPhi() const; - // mag(), theta(), and phi() - - inline double r() const; - // mag() - - inline double rho() const; - inline double getRho() const; - // perp() - - double eta() const; - double getEta() const; - // pseudoRapidity() - - inline void setR(double s); - // setMag() - - inline void setRho(double s); - // setPerp() - - // 3 - Comparisions (dictionary, near-ness, and geometric) - - int compare(const Vector3 & v) const; - bool operator >(const Vector3 & v) const; - bool operator <(const Vector3 & v) const; - bool operator>=(const Vector3 & v) const; - bool operator<=(const Vector3 & v) const; - // dictionary ordering according to z, then y, then x component - - inline double diff2(const Vector3 & v) const; - // |v1-v2|**2 - - static double setTolerance(double tol); - static inline double getTolerance(); - // Set the tolerance used in isNear() for Vector3s - - bool isParallel(const Vector3 & v, double epsilon = tolerance) const; - // Are the vectors parallel, within the given tolerance? - - bool isOrthogonal(const Vector3 & v, double epsilon = tolerance) const; - // Are the vectors orthogonal, within the given tolerance? - - double howParallel(const Vector3 & v) const; - // | v1.cross(v2) / v1.dot(v2) |, to a maximum of 1. - - double howOrthogonal(const Vector3 & v) const; - // | v1.dot(v2) / v1.cross(v2) |, to a maximum of 1. - - enum { - ToleranceTicks = 100 - }; - - // 4 - Intrinsic properties - - double beta() const; - // relativistic beta (considering v as a velocity vector with c=1) - // Same as mag() but will object if >= 1 - - double gamma() const; - // relativistic gamma (considering v as a velocity vector with c=1) - - double coLinearRapidity() const; - // inverse tanh (beta) - - // 5 - Properties relative to Z axis and to an arbitrary direction - - // Note that the non-esoteric CLHEP provides - // theta(), cosTheta(), cos2Theta, and angle(const Vector3&) - - inline double angle() const; - // angle against the Z axis -- synonym for theta() - - inline double theta(const Vector3 & v2) const; - // synonym for angle(v2) - - double cosTheta(const Vector3 & v2) const; - double cos2Theta(const Vector3 & v2) const; - // cos and cos^2 of the angle between two vectors - - inline Vector3 project() const; - Vector3 project(const Vector3 & v2) const; - // projection of a vector along a direction. - - inline Vector3 perpPart() const; - inline Vector3 perpPart(const Vector3 & v2) const; - // vector minus its projection along a direction. - - double rapidity() const; - // inverse tanh(v.z()) - - double rapidity(const Vector3 & v2) const; - // rapidity with respect to specified direction: - // inverse tanh (v.dot(u)) where u is a unit in the direction of v2 - - double eta(const Vector3 & v2) const; - // - ln tan of the angle beween the vector and the ref direction. - - // 6 - Polar and azimuthal angle decomposition and deltaPhi - - // Decomposition of an angle within reference defined by a direction: - - double polarAngle(const Vector3 & v2) const; - // The reference direction is Z: the polarAngle is abs(v.theta()-v2.theta()). - - double deltaPhi(const Vector3 & v2) const; - // v.phi()-v2.phi(), brought into the range (-PI,PI] - - double azimAngle(const Vector3 & v2) const; - // The reference direction is Z: the azimAngle is the same as deltaPhi - - double polarAngle(const Vector3 & v2, const Vector3 & ref) const; - // For arbitrary reference direction, - // polarAngle is abs(v.angle(ref) - v2.angle(ref)). - - double azimAngle(const Vector3 & v2, const Vector3 & ref) const; - // To compute azimangle, project v and v2 into the plane normal to - // the reference direction. Then in that plane take the angle going - // clockwise around the direction from projection of v to that of v2. - - // 7 - Rotations - - // These mehtods **DO NOT** use anything in the HepRotation class. - // Thus, use of v.rotate(axis,delta) does not force linking in Rotation.cc. - - Vector3 & rotate(const Vector3 & axis, double delta); - // Synonym for rotate (delta, axis) - - Vector3 & rotate(double phi, double theta, double psi); - // Rotate via Euler Angles. Our Euler Angles conventions are - // those of Goldstein Classical Mechanics page 107. - - inline Vector3 operator +(const Vector3 &) const; - // Addition of 3-vectors. - - inline Vector3 operator -(const Vector3 &) const; - Vector3 operator /(double a) const; - inline Vector3 operator *( double a)const; - -protected: - void setSpherical(double r, double theta, double phi); - void setCylindrical(double r, double phi, double z); - double negativeInfinity() const; - -protected: - - double dx; - double dy; - double dz; - // The components. - - static double tolerance; - // default tolerance criterion for isNear() to return true. -}; -// Vector3 - -// Global Methods -// -//Vector3 rotationXOf(const Vector3 & vec, double delta); -//Vector3 rotationYOf(const Vector3 & vec, double delta); -//Vector3 rotationZOf(const Vector3 & vec, double delta); - -//Vector3 rotationOf(const Vector3 & vec, const Vector3 & axis, double delta); -// -//Vector3 rotationOf(const Vector3 & vec, double phi, double theta, double psi); - -// Return a new vector based on a rotation of the supplied vector - -std::ostream & operator <<(std::ostream &, const Vector3 &); -// Output to a stream. - -std::istream & operator >>(std::istream &, Vector3 &); -// Input from a stream. - -//extern const Vector3 HepXHat, HepYHat, HepZHat; -// -//typedef Vector3 HepThreeVectorD; -//typedef Vector3 HepThreeVectorF; -// -// Division of 3-vectors by non-zero real number - - -// Subtraction of 3-vectors. - -inline double operator *(const Vector3 &, const Vector3 &); -// double product of 3-vectors. - -inline Vector3 operator *(double a, const Vector3 &); -//// Scaling of 3-vectors with a real number - -}// namespace mpc - -#include "mpc/Vector3Inline.h" - -#endif /* HEP_THREEVECTOR_H */ diff --git a/include/mpc/Vector3Inline.h b/include/mpc/Vector3Inline.h deleted file mode 100644 index 1c89cda64..000000000 --- a/include/mpc/Vector3Inline.h +++ /dev/null @@ -1,346 +0,0 @@ -// -*- C++ -*- -// $Id: ThreeVector.icc,v 1.2 2010/06/16 17:15:57 garren Exp $ -// --------------------------------------------------------------------------- -// -// This file is a part of the CLHEP - a Class Library for High Energy Physics. -// -// This is the definitions of the inline member functions of the -// Vector3 class. -// - -#include - -// ------------------ -// Access to elements -// ------------------ - -// x, y, z -namespace mpc { -inline double & Vector3::operator[](int i) { - return operator()(i); -} -inline double Vector3::operator[](int i) const { - return operator()(i); -} - -inline double Vector3::x() const { - return dx; -} -inline double Vector3::y() const { - return dy; -} -inline double Vector3::z() const { - return dz; -} - -inline double Vector3::getX() const { - return dx; -} -inline double Vector3::getY() const { - return dy; -} -inline double Vector3::getZ() const { - return dz; -} - -inline void Vector3::setX(double x) { - dx = x; -} -inline void Vector3::setY(double y) { - dy = y; -} -inline void Vector3::setZ(double z) { - dz = z; -} - -inline void Vector3::set(double x, double y, double z) { - dx = x; - dy = y; - dz = z; -} - -// -------------- -// Global methods -// -------------- - -inline Vector3 Vector3::operator +(const Vector3 & b) const { - return Vector3(x() + b.x(), y() + b.y(), z() + b.z()); -} - -inline Vector3 Vector3::operator -(const Vector3 & b) const { - return Vector3(x() - b.x(), y() - b.y(), z() - b.z()); -} - -inline Vector3 Vector3::operator *( double a) const { - return Vector3(a * x(), a * y(), a * z()); -} - -inline Vector3 operator *(double a, const Vector3 & p) { - return Vector3(a * p.x(), a * p.y(), a * p.z()); -} - -inline double operator *(const Vector3 & a, const Vector3 & b) { - return a.dot(b); -} - -// -------------------------- -// Set in various coordinates -// -------------------------- - -inline void Vector3::setRThetaPhi(double r, double theta, double phi) { - setSpherical(r, theta, phi); -} - -inline void Vector3::setREtaPhi(double r, double eta, double phi) { - setSpherical(r, 2 * std::atan(std::exp(-eta)), phi); -} - -inline void Vector3::setRhoPhiZ(double rho, double phi, double z) { - setCylindrical(rho, phi, z); -} - -// ------------ -// Constructors -// ------------ - -inline Vector3::Vector3() : - dx(0.), dy(0.), dz(0.) { -} -inline Vector3::Vector3(double x) : - dx(x), dy(0.), dz(0.) { -} -inline Vector3::Vector3(double x, double y) : - dx(x), dy(y), dz(0.) { -} -inline Vector3::Vector3(double x, double y, double z) : - dx(x), dy(y), dz(z) { -} - -inline Vector3::Vector3(const Vector3 & p) : - dx(p.dx), dy(p.dy), dz(p.dz) { -} - -inline Vector3::~Vector3() { -} - -inline Vector3 & Vector3::operator =(const Vector3 & p) { - dx = p.dx; - dy = p.dy; - dz = p.dz; - return *this; -} - -// ------------------ -// Access to elements -// ------------------ - -// r, theta, phi - -inline double Vector3::mag2() const { - return dx * dx + dy * dy + dz * dz; -} -inline double Vector3::mag() const { - return std::sqrt(mag2()); -} -inline double Vector3::r() const { - return mag(); -} - -inline double Vector3::theta() const { - return dx == 0.0 && dy == 0.0 && dz == 0.0 ? 0.0 : std::atan2(perp(), dz); -} -inline double Vector3::phi() const { - return dx == 0.0 && dy == 0.0 ? 0.0 : std::atan2(dy, dx); -} - -inline double Vector3::getR() const { - return mag(); -} -inline double Vector3::getTheta() const { - return theta(); -} -inline double Vector3::getPhi() const { - return phi(); -} -inline double Vector3::angle() const { - return theta(); -} - -inline double Vector3::cosTheta() const { - double ptot = mag(); - return ptot == 0.0 ? 1.0 : dz / ptot; -} - -inline double Vector3::cos2Theta() const { - double ptot2 = mag2(); - return ptot2 == 0.0 ? 1.0 : dz * dz / ptot2; -} - -inline void Vector3::setR(double r) { - setMag(r); -} - -inline void Vector3::setTheta(double th) { - double ma = mag(); - double ph = phi(); - setX(ma * std::sin(th) * std::cos(ph)); - setY(ma * std::sin(th) * std::sin(ph)); - setZ(ma * std::cos(th)); -} - -inline void Vector3::setPhi(double ph) { - double xy = perp(); - setX(xy * std::cos(ph)); - setY(xy * std::sin(ph)); -} - -// perp, eta, - -inline double Vector3::perp2() const { - return dx * dx + dy * dy; -} -inline double Vector3::perp() const { - return std::sqrt(perp2()); -} -inline double Vector3::rho() const { - return perp(); -} -inline double Vector3::eta() const { - return pseudoRapidity(); -} - -inline double Vector3::getRho() const { - return perp(); -} -inline double Vector3::getEta() const { - return pseudoRapidity(); -} - -inline void Vector3::setPerp(double r) { - double p = perp(); - if (p != 0.0) { - dx *= r / p; - dy *= r / p; - } -} -inline void Vector3::setRho(double rho) { - setPerp(rho); -} - -// ---------- -// Comparison -// ---------- - -inline bool Vector3::operator ==(const Vector3& v) const { - return (v.x() == x() && v.y() == y() && v.z() == z()) ? true : false; -} - -inline bool Vector3::operator !=(const Vector3& v) const { - return (v.x() != x() || v.y() != y() || v.z() != z()) ? true : false; -} - -inline double Vector3::getTolerance() { - return tolerance; -} - -// ---------- -// Arithmetic -// ---------- - -inline Vector3& Vector3::operator +=(const Vector3 & p) { - dx += p.x(); - dy += p.y(); - dz += p.z(); - return *this; -} - -inline Vector3& Vector3::operator -=(const Vector3 & p) { - dx -= p.x(); - dy -= p.y(); - dz -= p.z(); - return *this; -} - -inline Vector3 Vector3::operator -() const { - return Vector3(-dx, -dy, -dz); -} - -inline Vector3& Vector3::operator *=(double a) { - dx *= a; - dy *= a; - dz *= a; - return *this; -} - -// ------------------- -// Combine two Vectors -// ------------------- - -inline double Vector3::diff2(const Vector3 & p) const { - return (*this - p).mag2(); -} - -inline double Vector3::dot(const Vector3 & p) const { - return dx * p.x() + dy * p.y() + dz * p.z(); -} - -inline Vector3 Vector3::cross(const Vector3 & p) const { - return Vector3(dy * p.z() - p.y() * dz, dz * p.x() - p.z() * dx, dx - * p.y() - p.x() * dy); -} - -inline double Vector3::perp2(const Vector3 & p) const { - double tot = p.mag2(); - double ss = dot(p); - return tot > 0.0 ? mag2() - ss * ss / tot : mag2(); -} - -inline double Vector3::perp(const Vector3 & p) const { - return std::sqrt(perp2(p)); -} - -inline Vector3 Vector3::perpPart() const { - return Vector3(dx, dy, 0); -} -inline Vector3 Vector3::project() const { - return Vector3(0, 0, dz); -} - -inline Vector3 Vector3::perpPart(const Vector3 & v2) const { - return (*this - project(v2)); -} - -inline double Vector3::angle(const Vector3 & q) const { - return std::acos(cosTheta(q)); -} - -inline double Vector3::theta(const Vector3 & q) const { - return angle(q); -} - -inline double Vector3::azimAngle(const Vector3 & v2) const { - return deltaPhi(v2); -} - -// ---------- -// Properties -// ---------- - -inline Vector3 Vector3::unit() const { - double tot = mag2(); - Vector3 p(x(), y(), z()); - return tot > 0.0 ? p *= (1.0 / std::sqrt(tot)) : p; -} - -inline Vector3 Vector3::orthogonal() const { - double x = dx < 0.0 ? -dx : dx; - double y = dy < 0.0 ? -dy : dy; - double z = dz < 0.0 ? -dz : dz; - if (x < y) { - return x < z ? Vector3(0, dz, -dy) : Vector3(dy, -dx, 0); - } else { - return y < z ? Vector3(-dz, 0, dx) : Vector3(dy, -dx, 0); - } -} - -} // namespace mpc diff --git a/include/mpc/magneticField/magneticField.h b/include/mpc/magneticField/magneticField.h index 55e9441f5..6d44a8cdc 100644 --- a/include/mpc/magneticField/magneticField.h +++ b/include/mpc/magneticField/magneticField.h @@ -14,8 +14,8 @@ class MagneticField: public Referenced { public: virtual ~MagneticField() { } - virtual Vector3 getField(const Vector3 &position) const = 0; - virtual void updateSimulationVolume(const Vector3 &origin, double size) = 0; + virtual Vector3d getField(const Vector3d &position) const = 0; + virtual void updateSimulationVolume(const Vector3d &origin, double size) = 0; }; } // namespace mpc diff --git a/include/mpc/magneticField/magneticFieldGrid.h b/include/mpc/magneticField/magneticFieldGrid.h index 16fb2ddee..59268ea93 100644 --- a/include/mpc/magneticField/magneticFieldGrid.h +++ b/include/mpc/magneticField/magneticFieldGrid.h @@ -19,19 +19,19 @@ namespace mpc { */ class MagneticFieldGrid: public MagneticField { public: - MagneticFieldGrid(Vector3 origin, size_t n, double spacing); - Vector3 getField(const Vector3 &position) const; - Vector3 getGridOrigin() const; + MagneticFieldGrid(Vector3d origin, size_t n, double spacing); + Vector3d getField(const Vector3d &position) const; + Vector3d getGridOrigin() const; size_t getGridSamples() const; double getGridSpacing() const; double getGridSize() const; - virtual void updateSimulationVolume(const Vector3 &origin, double size); + virtual void updateSimulationVolume(const Vector3d &origin, double size); protected: - std::vector > > grid; + std::vector > > grid; size_t samples; double spacing; - Vector3 origin; + Vector3d origin; }; } // namespace mpc diff --git a/include/mpc/magneticField/sphMagneticField.h b/include/mpc/magneticField/sphMagneticField.h index e86e83d1b..b206c80b1 100644 --- a/include/mpc/magneticField/sphMagneticField.h +++ b/include/mpc/magneticField/sphMagneticField.h @@ -26,10 +26,10 @@ namespace mpc { gadget::DirectMagneticField field; gadget::FileDatabase database; public: - SPHMagneticField(Vector3 origin, double size, size_t gridSize, + SPHMagneticField(Vector3d origin, double size, size_t gridSize, const std::string filename); - Vector3 getField(const Vector3 &position) const; - void updateSimulationVolume(const Vector3 &origin, double size); + Vector3d getField(const Vector3d &position) const; + void updateSimulationVolume(const Vector3d &origin, double size); }; @@ -41,10 +41,10 @@ namespace mpc { gadget::SampledMagneticField field; gadget::FileDatabase database; public: - SPHMagneticFieldGrid(Vector3 origin, double size, size_t samples, + SPHMagneticFieldGrid(Vector3d origin, double size, size_t samples, const std::string filename); - Vector3 getField(const Vector3 &position) const; - void updateSimulationVolume(const Vector3 &origin, double size); + Vector3d getField(const Vector3d &position) const; + void updateSimulationVolume(const Vector3d &origin, double size); }; diff --git a/include/mpc/magneticField/turbulentMagneticFieldGrid.h b/include/mpc/magneticField/turbulentMagneticFieldGrid.h index 0ac13e200..2272a7a48 100644 --- a/include/mpc/magneticField/turbulentMagneticFieldGrid.h +++ b/include/mpc/magneticField/turbulentMagneticFieldGrid.h @@ -24,7 +24,7 @@ namespace mpc { */ class TurbulentMagneticFieldGrid: public MagneticFieldGrid { public: - TurbulentMagneticFieldGrid(Vector3 origin, size_t samples, double spacing, + TurbulentMagneticFieldGrid(Vector3d origin, size_t samples, double spacing, double lMin, double lMax, double Brms, double powerSpectralIndex); void setSeed(int seed); void initialize(); diff --git a/include/mpc/magneticField/uniformMagneticField.h b/include/mpc/magneticField/uniformMagneticField.h index 281d409dd..b74f4a673 100644 --- a/include/mpc/magneticField/uniformMagneticField.h +++ b/include/mpc/magneticField/uniformMagneticField.h @@ -12,19 +12,19 @@ namespace mpc { */ class UniformMagneticField: public MagneticField { public: - UniformMagneticField(const Vector3 &value) : + UniformMagneticField(const Vector3d &value) : value(value) { } - Vector3 getField(const Vector3 &position) const { + Vector3d getField(const Vector3d &position) const { return value; } - void updateSimulationVolume(const Vector3 &origin, double size) { + void updateSimulationVolume(const Vector3d &origin, double size) { } private: - Vector3 value; + Vector3d value; }; } // namespace mpc diff --git a/include/mpc/module/BreakCondition.h b/include/mpc/module/BreakCondition.h index 97304ccce..1f7731756 100644 --- a/include/mpc/module/BreakCondition.h +++ b/include/mpc/module/BreakCondition.h @@ -40,12 +40,12 @@ class SmallObserverSphere: public Module { void updateDescription(); public: double radius; - Vector3 center; + Vector3d center; std::string flag; std::string flagValue; bool makeInactive; - SmallObserverSphere(Vector3 center, double radius, std::string flag = + SmallObserverSphere(Vector3d center, double radius, std::string flag = "Detected", std::string flagValue = ""); void setMakeInactive(bool makeInactive); void process(Candidate *candidate) const; @@ -57,7 +57,7 @@ class SmallObserverSphere: public Module { */ class CubicBoundary: public Module { protected: - Vector3 origin; + Vector3d origin; double size; double margin; std::string flag; @@ -66,7 +66,7 @@ class CubicBoundary: public Module { bool limitStep; void updateDescription(); public: - CubicBoundary(Vector3 origin, double size, std::string flag = "OutOfBounds", + CubicBoundary(Vector3d origin, double size, std::string flag = "OutOfBounds", std::string flagValue = ""); void setMakeInactive(bool makeInactive); void setLimitStep(bool limitStep, double margin); @@ -79,7 +79,7 @@ class CubicBoundary: public Module { */ class SphericalBoundary: public Module { protected: - Vector3 center; + Vector3d center; double radius; double margin; std::string flag; @@ -88,7 +88,7 @@ class SphericalBoundary: public Module { bool limitStep; void updateDescription(); public: - SphericalBoundary(Vector3 center, double radius, std::string flag = + SphericalBoundary(Vector3d center, double radius, std::string flag = "OutOfBounds", std::string flagValue = ""); void setMakeInactive(bool makeInactive); void setLimitStep(bool limitStep, double margin); @@ -101,8 +101,8 @@ class SphericalBoundary: public Module { */ class EllipsoidalBoundary: public Module { protected: - Vector3 focalPoint1; - Vector3 focalPoint2; + Vector3d focalPoint1; + Vector3d focalPoint2; double majorAxis; double margin; std::string flag; @@ -111,7 +111,7 @@ class EllipsoidalBoundary: public Module { bool limitStep; void updateDescription(); public: - EllipsoidalBoundary(Vector3 focalPoint1, Vector3 focalPoint2, + EllipsoidalBoundary(Vector3d focalPoint1, Vector3d focalPoint2, double majorAxis, std::string flag = "OutOfBounds", std::string flagValue = ""); void setMakeInactive(bool makeInactive); diff --git a/include/mpc/module/Redshift.h b/include/mpc/module/Redshift.h index 7174c66d4..22a489d6d 100644 --- a/include/mpc/module/Redshift.h +++ b/include/mpc/module/Redshift.h @@ -13,10 +13,10 @@ namespace mpc { */ class SimpleRedshift { private: - Vector3 center; + Vector3d center; public: - SimpleRedshift(Vector3 center); + SimpleRedshift(Vector3d center); void process(Candidate *candidate) const; std::string getDescription() const; }; diff --git a/python/mpc.i b/python/mpc.i index 022844c3f..2dd588691 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -11,7 +11,6 @@ %include std_list.i %include stdint.i %include std_container.i - %include "exception.i" %exception { diff --git a/src/IO.cpp b/src/IO.cpp index e3d120c22..5975e2220 100644 --- a/src/IO.cpp +++ b/src/IO.cpp @@ -2,10 +2,10 @@ namespace mpc { -void write(kiss::Output &out, const mpc::Vector3 &vec3) { - write(out, vec3.getX()); - write(out, vec3.getY()); - write(out, vec3.getZ()); +void write(kiss::Output &out, const mpc::Vector3d &vec3) { + write(out, vec3.x); + write(out, vec3.y); + write(out, vec3.z); } void write(kiss::Output &out, const mpc::ParticleState &state) { @@ -29,18 +29,18 @@ void write(kiss::Output &out, const mpc::Candidate &candidate) { write(out, candidate.getNextStep()); } -bool read(kiss::Input &in, mpc::Vector3 &vec3) { - kiss::read(in, vec3[0]); - kiss::read(in, vec3[1]); - kiss::read(in, vec3[2]); +bool read(kiss::Input &in, mpc::Vector3d &vec3) { + kiss::read(in, vec3.x); + kiss::read(in, vec3.y); + kiss::read(in, vec3.z); return (in); } bool read(kiss::Input &in, mpc::ParticleState &state) { state.setId(kiss::read(in)); state.setEnergy(kiss::read(in)); - state.setPosition(kiss::read(in)); - state.setDirection(kiss::read(in)); + state.setPosition(kiss::read(in)); + state.setDirection(kiss::read(in)); return (in); } diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index af75b0f1c..deee93308 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -9,19 +9,19 @@ ParticleState::ParticleState() : } -void ParticleState::setPosition(const Vector3 &pos) { +void ParticleState::setPosition(const Vector3d &pos) { position = pos; } -const Vector3 &ParticleState::getPosition() const { +const Vector3d &ParticleState::getPosition() const { return position; } -void ParticleState::setDirection(const Vector3 &dir) { +void ParticleState::setDirection(const Vector3d &dir) { direction = dir / dir.mag(); } -const Vector3 &ParticleState::getDirection() const { +const Vector3d &ParticleState::getDirection() const { return direction; } @@ -86,11 +86,11 @@ void ParticleState::setLorentzFactor(const double gamma) { "mpc::ParticleState::setLorentzFactor only for nuclei/nucleons"); } -Vector3 ParticleState::getVelocity() const { +Vector3d ParticleState::getVelocity() const { return direction * c_light; } -Vector3 ParticleState::getMomentum() const { +Vector3d ParticleState::getMomentum() const { return direction * (energy / c_light); } diff --git a/src/Random.cpp b/src/Random.cpp index 710ba5b8d..a100e6037 100644 --- a/src/Random.cpp +++ b/src/Random.cpp @@ -122,11 +122,11 @@ double Random::randFisher(double k) { return acos(1. + 1. / k * log(1 - rand() * (1 - exp(-2 * k)))); } -Vector3 Random::randUnitVectorOnSphere() { +Vector3d Random::randUnitVectorOnSphere() { double z = this->randUniform(-1.0, 1.0); double t = this->randUniform(-1.0 * M_PI, M_PI); double r = sqrt(1 - z * z); - return Vector3(r * cos(t), r * sin(t), z); + return Vector3d(r * cos(t), r * sin(t), z); } double Random::randPowerLaw(double index, double min, double max) { diff --git a/src/Source.cpp b/src/Source.cpp index 1775086b2..17d658003 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -5,12 +5,12 @@ namespace mpc { BasicSource::BasicSource() : - position(Vector3(0, 0, 0)), id(0), index1(-1), index2(-1), breakpoint( + position(Vector3d(0, 0, 0)), id(0), index1(-1), index2(-1), breakpoint( 10 * EeV), Emin(5 * EeV), Emax(1000 * EeV) { } -BasicSource::BasicSource(const Vector3 &sposition, int type, double Emin, +BasicSource::BasicSource(const Vector3d &sposition, int type, double Emin, double Emax, double index1, double index2, double breakpoint) : position(position), id(id), index1(index1), index2(index2), breakpoint( breakpoint), Emin(Emin), Emax(Emax) { diff --git a/src/magneticField/magneticFieldGrid.cpp b/src/magneticField/magneticFieldGrid.cpp index 316ba0c14..c463a5f12 100644 --- a/src/magneticField/magneticFieldGrid.cpp +++ b/src/magneticField/magneticFieldGrid.cpp @@ -11,7 +11,7 @@ void periodicClamp(double x, int n, int &lo, int &hi, double &fLo, fHi = 1 - fLo; } -MagneticFieldGrid::MagneticFieldGrid(Vector3 origin, size_t n, double spacing) : +MagneticFieldGrid::MagneticFieldGrid(Vector3d origin, size_t n, double spacing) : origin(origin), samples(n), spacing(spacing) { grid.resize(n); for (int ix = 0; ix < n; ix++) { @@ -22,13 +22,13 @@ MagneticFieldGrid::MagneticFieldGrid(Vector3 origin, size_t n, double spacing) : } } -void MagneticFieldGrid::updateSimulationVolume(const Vector3 &origin, +void MagneticFieldGrid::updateSimulationVolume(const Vector3d &origin, double size) { this->origin = origin; this->spacing = size / (samples - 1); } -Vector3 MagneticFieldGrid::getGridOrigin() const { +Vector3d MagneticFieldGrid::getGridOrigin() const { return origin; } @@ -44,17 +44,17 @@ double MagneticFieldGrid::getGridSize() const { return samples * spacing; } -Vector3 MagneticFieldGrid::getField(const Vector3 &position) const { - Vector3 r = (position - origin) / spacing; +Vector3d MagneticFieldGrid::getField(const Vector3d &position) const { + Vector3d r = (position - origin) / spacing; int ix, iX, iy, iY, iz, iZ; double fx, fX, fy, fY, fz, fZ; - periodicClamp(r.x(), samples, ix, iX, fx, fX); - periodicClamp(r.y(), samples, iy, iY, fy, fY); - periodicClamp(r.z(), samples, iz, iZ, fz, fZ); + periodicClamp(r.x, samples, ix, iX, fx, fX); + periodicClamp(r.y, samples, iy, iY, fy, fY); + periodicClamp(r.z, samples, iz, iZ, fz, fZ); // trilinear interpolation // check: http://paulbourke.net/miscellaneous/interpolation/ - Vector3 b(0, 0, 0); + Vector3d b(0, 0, 0); //V000 (1 - x) (1 - y) (1 - z) + b += grid[ix][iy][iz] * fX * fY * fZ; //V100 x (1 - y) (1 - z) + diff --git a/src/magneticField/sphMagneticField.cpp b/src/magneticField/sphMagneticField.cpp index 2b5ae16b2..057bcf782 100644 --- a/src/magneticField/sphMagneticField.cpp +++ b/src/magneticField/sphMagneticField.cpp @@ -5,50 +5,45 @@ namespace mpc { -SPHMagneticField::SPHMagneticField(Vector3 origin, double size, size_t gridSize, - const std::string filename) : +SPHMagneticField::SPHMagneticField(Vector3d origin, double size, + size_t gridSize, const std::string filename) : field(gridSize) { database.open(filename); - gadget::Vector3f v = gadget::Vector3f(origin.x(), origin.y(), origin.z()) - / kpc; + gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; field.init(v, size / kpc, database); } -Vector3 SPHMagneticField::getField(const Vector3 &position) const { - gadget::Vector3f r = gadget::Vector3f(position.x(), position.y(), - position.z()); +Vector3d SPHMagneticField::getField(const Vector3d &position) const { + gadget::Vector3f r = gadget::Vector3f(position.x, position.y, position.z); gadget::Vector3f b = field.getField(r / kpc); - Vector3 bField = Vector3(b.x, b.y, b.z) * gauss; + Vector3d bField = Vector3d(b.x, b.y, b.z) * gauss; return bField; } -void SPHMagneticField::updateSimulationVolume(const Vector3 &origin, +void SPHMagneticField::updateSimulationVolume(const Vector3d &origin, double size) { - gadget::Vector3f v = gadget::Vector3f(origin.x(), origin.y(), origin.z()) - / kpc; + gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; field.init(v, size / kpc, database); } -SPHMagneticFieldGrid::SPHMagneticFieldGrid(Vector3 origin, double size, +SPHMagneticFieldGrid::SPHMagneticFieldGrid(Vector3d origin, double size, size_t samples, const std::string filename) : field(samples) { database.open(filename); - gadget::Vector3f v = gadget::Vector3f(origin.x(), origin.y(), origin.z()) - / kpc; + gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; field.init(v, size / kpc, database); } -Vector3 SPHMagneticFieldGrid::getField(const Vector3 &position) const { - gadget::Vector3f r = gadget::Vector3f(position.x(), position.y(), - position.z()); +Vector3d SPHMagneticFieldGrid::getField(const Vector3d &position) const { + gadget::Vector3f r = gadget::Vector3f(position.x, position.y, position.z); gadget::Vector3f b = field.getField(r / kpc); - Vector3 bField = Vector3(b.x, b.y, b.z) * gauss; + Vector3d bField = Vector3d(b.x, b.y, b.z) * gauss; return bField; } -void SPHMagneticFieldGrid::updateSimulationVolume(const Vector3 &origin, +void SPHMagneticFieldGrid::updateSimulationVolume(const Vector3d &origin, double size) { - gadget::Vector3f v = gadget::Vector3f(origin.x(), origin.y(), origin.z()) + gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; field.init(v, size / kpc, database); } diff --git a/src/magneticField/turbulentMagneticFieldGrid.cpp b/src/magneticField/turbulentMagneticFieldGrid.cpp index 464832803..f4410037e 100644 --- a/src/magneticField/turbulentMagneticFieldGrid.cpp +++ b/src/magneticField/turbulentMagneticFieldGrid.cpp @@ -3,7 +3,7 @@ namespace mpc { -TurbulentMagneticFieldGrid::TurbulentMagneticFieldGrid(Vector3 origin, +TurbulentMagneticFieldGrid::TurbulentMagneticFieldGrid(Vector3d origin, size_t samples, double spacing, double lMin, double lMax, double Brms, double powerSpectralIndex) : MagneticFieldGrid(origin, samples, spacing) { @@ -39,9 +39,9 @@ void TurbulentMagneticFieldGrid::initialize() { double k, theta, phase, cosPhase, sinPhase; double kMin = spacing / lMax; double kMax = spacing / lMin; - Vector3 b; // real b-field vector - Vector3 ek, e1, e2; // orthogonal base - Vector3 n0(1, 1, 1); // arbitrary vector to construct orthogonal base + Vector3d b; // real b-field vector + Vector3d ek, e1, e2; // orthogonal base + Vector3d n0(1, 1, 1); // arbitrary vector to construct orthogonal base for (size_t ix = 0; ix < n; ix++) { for (size_t iy = 0; iy < n; iy++) { @@ -63,7 +63,7 @@ void TurbulentMagneticFieldGrid::initialize() { } // construct an orthogonal base ek, e1, e2 - if (ek.isParallel(n0, 1e-6)) { + if (ek.isParallelTo(n0, 1e-6)) { // ek parallel to (1,1,1) e1.set(-1., 1., 0); e2.set(1., 1., -2.); @@ -87,12 +87,12 @@ void TurbulentMagneticFieldGrid::initialize() { cosPhase = cos(phase); // real part sinPhase = sin(phase); // imaginary part - Bkx[i][0] = b.x() * cosPhase; - Bkx[i][1] = b.x() * sinPhase; - Bky[i][0] = b.y() * cosPhase; - Bky[i][1] = b.y() * sinPhase; - Bkz[i][0] = b.z() * cosPhase; - Bkz[i][1] = b.z() * sinPhase; + Bkx[i][0] = b.x * cosPhase; + Bkx[i][1] = b.x * sinPhase; + Bky[i][0] = b.y * cosPhase; + Bky[i][1] = b.y * sinPhase; + Bkz[i][0] = b.z * cosPhase; + Bkz[i][1] = b.z * sinPhase; } } } @@ -129,7 +129,7 @@ void TurbulentMagneticFieldGrid::initialize() { for (size_t iy = 0; iy < n; iy++) for (size_t iz = 0; iz < n; iz++) { i = ix * n * 2*n2 + iy * 2*n2 + iz; - grid[ix][iy][iz] = Vector3(Bx[i], By[i], Bz[i]) + grid[ix][iy][iz] = Vector3d(Bx[i], By[i], Bz[i]) * weight; } diff --git a/src/main.cpp b/src/main.cpp index 519b76ceb..4610dca9b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,7 +16,7 @@ int main(int argc, char **argv) { ModuleList modules; // propagation -------------------------------------------------------- - TurbulentMagneticFieldGrid *field = new TurbulentMagneticFieldGrid(Vector3(0, 0, 0), 64, 1., 2., 8., 1e-12, -11. / 3.); + TurbulentMagneticFieldGrid *field = new TurbulentMagneticFieldGrid(Vector3d(0, 0, 0), 64, 1., 2., 8., 1e-12, -11. / 3.); modules.add(new DeflectionCK(field)); // interactions ------------------------------------------------------- @@ -36,8 +36,8 @@ int main(int argc, char **argv) { ParticleState initial; initial.setId(getNucleusId(56, 26)); initial.setEnergy(100 * EeV); - initial.setPosition(Vector3(0, 0, 0)); - initial.setDirection(Vector3(1, 0, 0)); + initial.setPosition(Vector3d(0, 0, 0)); + initial.setDirection(Vector3d(1, 0, 0)); ref_ptr candidate = new Candidate(initial); modules.process(candidate); diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp index 0c28aac78..35a1671f5 100644 --- a/src/module/BreakCondition.cpp +++ b/src/module/BreakCondition.cpp @@ -32,7 +32,7 @@ void MinimumEnergy::process(Candidate *candidate) const { } } -SmallObserverSphere::SmallObserverSphere(Vector3 center, double radius, +SmallObserverSphere::SmallObserverSphere(Vector3d center, double radius, std::string flag, std::string flagValue) { this->center = center; this->radius = radius; @@ -67,7 +67,7 @@ void SmallObserverSphere::updateDescription() { setDescription(s.str()); } -CubicBoundary::CubicBoundary(Vector3 origin, double size, std::string flag, +CubicBoundary::CubicBoundary(Vector3d origin, double size, std::string flag, std::string flagValue) { this->origin = origin; this->size = size; @@ -91,9 +91,9 @@ void CubicBoundary::setLimitStep(bool limitStep, double margin) { } void CubicBoundary::process(Candidate *candidate) const { - Vector3 relPos = candidate->current.getPosition() - origin; - double lo = std::min(relPos.x(), std::min(relPos.y(), relPos.z())); - double hi = std::max(relPos.x(), std::max(relPos.y(), relPos.z())); + Vector3d relPos = candidate->current.getPosition() - origin; + double lo = std::min(relPos.x, std::min(relPos.y, relPos.z)); + double hi = std::max(relPos.x, std::max(relPos.y, relPos.z)); if ((lo <= 0.) or (hi >= size)) { candidate->setProperty(flag, flagValue); if (makeInactive) { @@ -114,7 +114,7 @@ void CubicBoundary::updateDescription() { setDescription(s.str()); } -SphericalBoundary::SphericalBoundary(Vector3 center, double radius, +SphericalBoundary::SphericalBoundary(Vector3d center, double radius, std::string flag, std::string flagValue) { this->center = center; this->radius = radius; @@ -157,8 +157,8 @@ void SphericalBoundary::updateDescription() { setDescription(s.str()); } -EllipsoidalBoundary::EllipsoidalBoundary(Vector3 focalPoint1, - Vector3 focalPoint2, double majorAxis, std::string flag, +EllipsoidalBoundary::EllipsoidalBoundary(Vector3d focalPoint1, + Vector3d focalPoint2, double majorAxis, std::string flag, std::string flagValue) { this->focalPoint1 = focalPoint1; this->focalPoint2 = focalPoint2; @@ -183,7 +183,7 @@ void EllipsoidalBoundary::setLimitStep(bool limitStep, double margin) { } void EllipsoidalBoundary::process(Candidate *candidate) const { - Vector3 pos = candidate->current.getPosition(); + Vector3d pos = candidate->current.getPosition(); double d = (pos - focalPoint1).mag() + (pos - focalPoint2).mag(); if (d >= majorAxis) { candidate->setProperty(flag, flagValue); diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index 5f0722232..9392e7b0b 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -22,8 +22,8 @@ class LorentzForce: public ExplicitRungeKutta::F { } PhasePoint operator()(double t, const PhasePoint &v) { - Vector3 velocity = v.b.unit() * c_light; - Vector3 B(0, 0, 0); + Vector3d velocity = v.b / v.b.mag() * c_light; + Vector3d B(0, 0, 0); try { B = field->getField(v.a); } catch (std::exception &e) { @@ -31,7 +31,7 @@ class LorentzForce: public ExplicitRungeKutta::F { << std::endl; std::cerr << e.what() << std::endl; } - Vector3 force = (double) particle->getChargeNumber() * eplus + Vector3d force = (double) particle->getChargeNumber() * eplus * velocity.cross(B); return PhasePoint(velocity, force); } @@ -56,8 +56,8 @@ void DeflectionCK::process(Candidate *candidate) const { // rectlinear propagation in case of no charge if (candidate->current.getChargeNumber() == 0) { double nextStep = std::max(minimumStep, candidate->getNextStep()); - Vector3 pos = candidate->current.getPosition(); - Vector3 dir = candidate->current.getDirection(); + Vector3d pos = candidate->current.getPosition(); + Vector3d dir = candidate->current.getDirection(); candidate->current.setPosition(pos + dir * nextStep); candidate->setCurrentStep(nextStep); candidate->setNextStep(nextStep * 5); @@ -80,12 +80,12 @@ void DeflectionCK::process(Candidate *candidate) const { // maximum of ratio yErr(i) / yScale(i) r = 0; - if (yScale.b.x() > std::numeric_limits::min()) - r = std::max(r, fabs(yErr.b.x() / yScale.b.x())); - if (yScale.b.y() > std::numeric_limits::min()) - r = std::max(r, fabs(yErr.b.y() / yScale.b.y())); - if (yScale.b.z() > std::numeric_limits::min()) - r = std::max(r, fabs(yErr.b.z() / yScale.b.z())); + if (yScale.b.x > std::numeric_limits::min()) + r = std::max(r, fabs(yErr.b.x / yScale.b.x)); + if (yScale.b.y > std::numeric_limits::min()) + r = std::max(r, fabs(yErr.b.y / yScale.b.y)); + if (yScale.b.z > std::numeric_limits::min()) + r = std::max(r, fabs(yErr.b.z / yScale.b.z)); // for efficient integration try to keep r close to one h *= 0.95 * pow(r, -0.2); @@ -96,7 +96,7 @@ void DeflectionCK::process(Candidate *candidate) const { } while (r > 1 && h >= minimumStep); candidate->current.setPosition(yOut.a); - candidate->current.setDirection(yOut.b.unit()); + candidate->current.setDirection(yOut.b / yOut.b.mag()); candidate->setCurrentStep(hTry * c_light); candidate->setNextStep(h * c_light); } diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 5ce854b58..a5ea2a8a0 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -23,11 +23,11 @@ void TrajectoryOutput::process(Candidate *candidate) const { pos += ::sprintf(buffer + pos, "%f, %d, %f", candidate->getTrajectoryLength() / Mpc, candidate->current.getId(), candidate->current.getEnergy() / EeV); - Vector3 position = candidate->current.getPosition() / Mpc; - pos += ::sprintf(buffer + pos, ", %f, %f, %f", position.x(), position.y(), - position.z()); - const Vector3 &dir = candidate->current.getDirection(); - pos += ::sprintf(buffer + pos, ", %f, %f, %f\n", dir.x(), dir.y(), dir.z()); + Vector3d position = candidate->current.getPosition() / Mpc; + pos += ::sprintf(buffer + pos, ", %f, %f, %f", position.x, position.y, + position.z); + const Vector3d &dir = candidate->current.getDirection(); + pos += ::sprintf(buffer + pos, ", %f, %f, %f\n", dir.x, dir.y, dir.z); #pragma omp critical { @@ -39,7 +39,8 @@ std::string TrajectoryOutput::getDescription() const { return "Trajectory output"; } -ConditionalOutput::ConditionalOutput(std::string filename, std::string propName) { +ConditionalOutput::ConditionalOutput(std::string filename, + std::string propName) { removeProperty = false; propertyName = propName; outfile.open(filename.c_str()); @@ -63,11 +64,10 @@ void ConditionalOutput::process(Candidate *candidate) const { p += ::sprintf(buffer + p, "%d", candidate->current.getId()); - const Vector3 &pos = candidate->current.getPosition() / Mpc; - p += ::sprintf(buffer + p, ", %f, %f, %f", pos.x(), - pos.y(), pos.z()); + const Vector3d &pos = candidate->current.getPosition() / Mpc; + p += ::sprintf(buffer + p, ", %f, %f, %f", pos.x, pos.y, pos.z); - const Vector3 &dir = candidate->current.getDirection(); + const Vector3d &dir = candidate->current.getDirection(); p += ::sprintf(buffer + p, ", %f, %f, %f", candidate->current.getEnergy() / EeV, dir.phi(), dir.theta()); @@ -76,11 +76,11 @@ void ConditionalOutput::process(Candidate *candidate) const { p += ::sprintf(buffer + p, ", %d", candidate->initial.getId()); - const Vector3 &ipos = candidate->initial.getPosition() / Mpc; - p += ::sprintf(buffer + p, ", %f, %f, %f", ipos.x(), ipos.y(), - ipos.z()); + const Vector3d &ipos = candidate->initial.getPosition() / Mpc; + p += ::sprintf(buffer + p, ", %f, %f, %f", ipos.x, ipos.y, + ipos.z); - const Vector3 &idir = candidate->initial.getDirection(); + const Vector3d &idir = candidate->initial.getDirection(); p += ::sprintf(buffer + p, ", %f, %f, %f\n", candidate->initial.getEnergy() / EeV, idir.phi(), idir.theta()); diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index 236bc289d..5874ca9d1 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -3,7 +3,7 @@ namespace mpc { -SimpleRedshift::SimpleRedshift(Vector3 center) { +SimpleRedshift::SimpleRedshift(Vector3d center) { this->center = center; } diff --git a/src/module/SimplePropagation.cpp b/src/module/SimplePropagation.cpp index b85f63483..29ed19933 100644 --- a/src/module/SimplePropagation.cpp +++ b/src/module/SimplePropagation.cpp @@ -8,8 +8,8 @@ SimplePropagation::SimplePropagation(double acceleration, double minimumStep) : void SimplePropagation::process(Candidate *candidate) const { double nextStep = std::max(minimumStep, candidate->getNextStep()); - Vector3 pos = candidate->current.getPosition(); - Vector3 dir = candidate->current.getDirection(); + Vector3d pos = candidate->current.getPosition(); + Vector3d dir = candidate->current.getDirection(); candidate->current.setPosition(pos + dir * nextStep); candidate->setCurrentStep(nextStep); candidate->setNextStep(nextStep * acceleration); diff --git a/test/python/testDeflectionCK.py b/test/python/testDeflectionCK.py index 17d2513d2..adc293861 100644 --- a/test/python/testDeflectionCK.py +++ b/test/python/testDeflectionCK.py @@ -6,10 +6,10 @@ c = Candidate() c.current.setId(getNucleusId(1,1)) c.current.setEnergy(100 * EeV) -c.current.setDirection(Vector3(1, 0, 0)) +c.current.setDirection(Vector3d(1, 0, 0)) # uniform perpendicular magnetic field of 10 nG -field = UniformMagneticField(Vector3(0,0,1e-12)) +field = UniformMagneticField(Vector3d(0,0,1e-12)) # resulting gyroradius R = c.current.getMomentum().mag() / c.current.getCharge() / 1e-12 @@ -22,8 +22,8 @@ def propagate(tolerance): c.setTrajectoryLength(0) c.setCurrentStep(0) c.setNextStep(1 * Mpc) # set a large initial step, so that an initial acceleration is uneccessary - c.current.setPosition(Vector3(0, R, 0)) - c.current.setDirection(Vector3(1, 0, 0)) + c.current.setPosition(Vector3d(0, R, 0)) + c.current.setDirection(Vector3d(1, 0, 0)) c.setActive(True) posX, posY, dirX, dirY, dirDeviation, theta = [], [], [], [], [], [] @@ -41,7 +41,7 @@ def propagate(tolerance): t = c.getTrajectoryLength() / R theta.append(t) - dirDeviation.append(c.current.getDirection().dot(Vector3(cos(t), -sin(t), 0))) + dirDeviation.append(c.current.getDirection().dot(Vector3d(cos(t), -sin(t), 0))) return array(posX), array(posY), array(dirX), array(dirY), array(dirDeviation), array(theta), nSteps diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index 4e9b849d8..9a79ce2d5 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -42,43 +42,43 @@ TEST(MaximumTrajectoryLength, stop) { } TEST(SmallObserverSphere, Continue) { - SmallObserverSphere obs(Vector3(0, 0, 0), 1); + SmallObserverSphere obs(Vector3d(0, 0, 0), 1); Candidate candidate; - candidate.current.setPosition(Vector3(2, 0, 0)); + candidate.current.setPosition(Vector3d(2, 0, 0)); obs.process(&candidate); EXPECT_TRUE(candidate.isActive()); } TEST(SmallObserverSphere, detect) { - SmallObserverSphere obs(Vector3(0, 0, 0), 1); + SmallObserverSphere obs(Vector3d(0, 0, 0), 1); Candidate candidate; - candidate.current.setPosition(Vector3(0.1, 0.5, -0.1)); + candidate.current.setPosition(Vector3d(0.1, 0.5, -0.1)); obs.process(&candidate); EXPECT_FALSE(candidate.isActive()); EXPECT_TRUE(candidate.hasProperty("Detected")); } TEST(SmallObserverSphere, limitStep) { - SmallObserverSphere obs(Vector3(0, 0, 0), 1); + SmallObserverSphere obs(Vector3d(0, 0, 0), 1); Candidate candidate; candidate.setNextStep(10); - candidate.current.setPosition(Vector3(0, 0, 2)); + candidate.current.setPosition(Vector3d(0, 0, 2)); obs.process(&candidate); EXPECT_DOUBLE_EQ(candidate.getNextStep(), 1); } TEST(CubicBoundary, inside) { - CubicBoundary cube(Vector3(0, 0, 0), 10); + CubicBoundary cube(Vector3d(0, 0, 0), 10); Candidate candidate; - candidate.current.setPosition(Vector3(9, 5, 5)); + candidate.current.setPosition(Vector3d(9, 5, 5)); cube.process(&candidate); EXPECT_TRUE(candidate.isActive()); } TEST(CubicBoundary, outside) { - CubicBoundary cube(Vector3(0, 0, 0), 10); + CubicBoundary cube(Vector3d(0, 0, 0), 10); Candidate candidate; - candidate.current.setPosition(Vector3(10.1, 5, 5)); + candidate.current.setPosition(Vector3d(10.1, 5, 5)); cube.process(&candidate); EXPECT_TRUE(candidate.isActive()); EXPECT_TRUE(candidate.hasProperty("OutOfBounds")); @@ -89,27 +89,27 @@ TEST(CubicBoundary, outside) { } TEST(CubicBoundary, limitStep) { - CubicBoundary cube(Vector3(0, 0, 0), 10); + CubicBoundary cube(Vector3d(0, 0, 0), 10); cube.setLimitStep(true, 1); Candidate candidate; candidate.setNextStep(10); - candidate.current.setPosition(Vector3(5, 5, 0.5)); + candidate.current.setPosition(Vector3d(5, 5, 0.5)); cube.process(&candidate); EXPECT_DOUBLE_EQ(candidate.getNextStep(), 1.5); } TEST(SphericalBoundary, inside) { - SphericalBoundary sphere(Vector3(0, 0, 0), 10); + SphericalBoundary sphere(Vector3d(0, 0, 0), 10); Candidate candidate; - candidate.current.setPosition(Vector3(9, 0, 0)); + candidate.current.setPosition(Vector3d(9, 0, 0)); sphere.process(&candidate); EXPECT_FALSE(candidate.hasProperty("OutOfBounds")); } TEST(SphericalBoundary, outside) { - SphericalBoundary sphere(Vector3(0, 0, 0), 10, "PassedGalacticBorder"); + SphericalBoundary sphere(Vector3d(0, 0, 0), 10, "PassedGalacticBorder"); Candidate candidate; - candidate.current.setPosition(Vector3(0, -10.1, 0)); + candidate.current.setPosition(Vector3d(0, -10.1, 0)); sphere.process(&candidate); EXPECT_TRUE(candidate.isActive()); EXPECT_TRUE(candidate.hasProperty("PassedGalacticBorder")); @@ -120,27 +120,27 @@ TEST(SphericalBoundary, outside) { } TEST(SphericalBoundary, limitStep) { - SphericalBoundary sphere(Vector3(0, 0, 0), 10); + SphericalBoundary sphere(Vector3d(0, 0, 0), 10); sphere.setLimitStep(true, 1); Candidate candidate; candidate.setNextStep(2); - candidate.current.setPosition(Vector3(0, 0, 9.5)); + candidate.current.setPosition(Vector3d(0, 0, 9.5)); sphere.process(&candidate); EXPECT_DOUBLE_EQ(candidate.getNextStep(), 1.5); } TEST(EllipsoidalBoundary, inside) { - EllipsoidalBoundary ellipsoid(Vector3(-5, 0, 0), Vector3(5, 0, 0), 15); + EllipsoidalBoundary ellipsoid(Vector3d(-5, 0, 0), Vector3d(5, 0, 0), 15); Candidate candidate; - candidate.current.setPosition(Vector3(3, 2, 0)); + candidate.current.setPosition(Vector3d(3, 2, 0)); ellipsoid.process(&candidate); EXPECT_FALSE(candidate.hasProperty("OutOfBounds")); } TEST(EllipsoidalBoundary, outside) { - EllipsoidalBoundary ellipsoid(Vector3(-5, 0, 0), Vector3(5, 0, 0), 15); + EllipsoidalBoundary ellipsoid(Vector3d(-5, 0, 0), Vector3d(5, 0, 0), 15); Candidate candidate; - candidate.current.setPosition(Vector3(0, 25, 0)); + candidate.current.setPosition(Vector3d(0, 25, 0)); ellipsoid.process(&candidate); EXPECT_TRUE(candidate.hasProperty("OutOfBounds")); EXPECT_TRUE(candidate.isActive()); @@ -151,11 +151,11 @@ TEST(EllipsoidalBoundary, outside) { } TEST(EllipsoidalBoundary, limitStep) { - EllipsoidalBoundary ellipsoid(Vector3(-5, 0, 0), Vector3(5, 0, 0), 15); + EllipsoidalBoundary ellipsoid(Vector3d(-5, 0, 0), Vector3d(5, 0, 0), 15); ellipsoid.setLimitStep(true, 0.5); Candidate candidate; candidate.setNextStep(2); - candidate.current.setPosition(Vector3(7, 0, 0)); + candidate.current.setPosition(Vector3d(7, 0, 0)); ellipsoid.process(&candidate); EXPECT_DOUBLE_EQ(candidate.getNextStep(), 1.5); } diff --git a/test/testCore.cpp b/test/testCore.cpp index 5b4dc5a65..f77b62fb4 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -6,7 +6,7 @@ namespace mpc { TEST(ParticleState, position) { ParticleState particle; - Vector3 v(1, 3, 5); + Vector3d v(1, 3, 5); particle.setPosition(v * Mpc); EXPECT_TRUE(particle.getPosition() == v * Mpc); } @@ -19,21 +19,21 @@ TEST(ParticleState, energy) { TEST(ParticleState, direction) { ParticleState particle; - Vector3 v(1, 2, 3); + Vector3d v(1, 2, 3); particle.setDirection(v); EXPECT_TRUE(particle.getDirection() == v / v.mag()); } TEST(ParticleState, velocity) { ParticleState particle; - Vector3 v(1, 1, 0); + Vector3d v(1, 1, 0); particle.setDirection(v); EXPECT_TRUE(particle.getVelocity() == v / v.mag() * c_light); } TEST(ParticleState, momentum) { ParticleState particle; - Vector3 v(0, 1, 0); + Vector3d v(0, 1, 0); particle.setDirection(v); particle.setEnergy(100 * EeV); EXPECT_TRUE(particle.getMomentum() == v * (particle.getEnergy() / c_light)); diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index 5c81c337d..a26a455fd 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -10,68 +10,69 @@ namespace mpc { TEST(testUniformMagneticField, SimpleTest) { - UniformMagneticField B(Vector3(-1, 5, 3)); - Vector3 b = B.getField(Vector3(1, 0, 0)); - EXPECT_DOUBLE_EQ(b.x(), -1); - EXPECT_DOUBLE_EQ(b.y(), 5); - EXPECT_DOUBLE_EQ(b.z(), 3); + UniformMagneticField B(Vector3d(-1, 5, 3)); + Vector3d b = B.getField(Vector3d(1, 0, 0)); + EXPECT_DOUBLE_EQ(b.x, -1); + EXPECT_DOUBLE_EQ(b.y, 5); + EXPECT_DOUBLE_EQ(b.z, 3); } TEST(testTurbulentMagneticFieldGrid, PeriodicBoundaries) { // B(x+a*n) = B(x) size_t n = 64; - TurbulentMagneticFieldGrid B(Vector3(0, 0, 0), n, 1, 2, 8, 1, -11. / 3.); + TurbulentMagneticFieldGrid B(Vector3d(0, 0, 0), n, 1, 2, 8, 1, -11. / 3.); - Vector3 pos(1.1, 2.1, 3.1); - Vector3 b = B.getField(pos); - Vector3 b1 = B.getField(pos + Vector3(n, 0, 0)); - Vector3 b2 = B.getField(pos + Vector3(0, n, 0)); - Vector3 b3 = B.getField(pos + Vector3(0, 0, n)); + Vector3d pos(1.1, 2.1, 3.1); + Vector3d b = B.getField(pos); + Vector3d b1 = B.getField(pos + Vector3d(n, 0, 0)); + Vector3d b2 = B.getField(pos + Vector3d(0, n, 0)); + Vector3d b3 = B.getField(pos + Vector3d(0, 0, n)); - EXPECT_FLOAT_EQ(b.x(), b1.x()); - EXPECT_FLOAT_EQ(b.y(), b1.y()); - EXPECT_FLOAT_EQ(b.z(), b1.z()); + EXPECT_FLOAT_EQ(b.x, b1.x); + EXPECT_FLOAT_EQ(b.y, b1.y); + EXPECT_FLOAT_EQ(b.z, b1.z); - EXPECT_FLOAT_EQ(b.x(), b2.x()); - EXPECT_FLOAT_EQ(b.y(), b2.y()); - EXPECT_FLOAT_EQ(b.z(), b2.z()); + EXPECT_FLOAT_EQ(b.x, b2.x); + EXPECT_FLOAT_EQ(b.y, b2.y); + EXPECT_FLOAT_EQ(b.z, b2.z); - EXPECT_FLOAT_EQ(b.x(), b3.x()); - EXPECT_FLOAT_EQ(b.y(), b3.y()); - EXPECT_FLOAT_EQ(b.z(), b3.z()); + EXPECT_FLOAT_EQ(b.x, b3.x); + EXPECT_FLOAT_EQ(b.y, b3.y); + EXPECT_FLOAT_EQ(b.z, b3.z); } TEST(testTurbulentMagneticFieldGrid, ZeroMean) { // = 0 size_t n = 64; - TurbulentMagneticFieldGrid B(Vector3(0, 0, 0), n, 1, 2, 8, 1, -11. / 3.); + TurbulentMagneticFieldGrid B(Vector3d(0, 0, 0), n, 1, 2, 8, 1, -11. / 3.); - Vector3 b(0, 0, 0); + Vector3d b(0, 0, 0); for (unsigned int ix = 0; ix < n; ix++) for (unsigned int iy = 0; iy < n; iy++) for (unsigned int iz = 0; iz < n; iz++) - b += B.getField(Vector3(ix, iy, iz)); + b += B.getField(Vector3d(ix, iy, iz)); + b /= n * n * n; double precision = 1e-12; - EXPECT_NEAR(b.x(), 0, precision); - EXPECT_NEAR(b.y(), 0, precision); - EXPECT_NEAR(b.z(), 0, precision); + EXPECT_NEAR(b.x, 0, precision); + EXPECT_NEAR(b.y, 0, precision); + EXPECT_NEAR(b.z, 0, precision); } TEST(testTurbulentMagneticFieldGrid, Brms) { // = Brms^2 size_t n = 64; - TurbulentMagneticFieldGrid B(Vector3(0, 0, 0), n, 1*Mpc, 2*Mpc, 8*Mpc, 1., -11. / 3.); + TurbulentMagneticFieldGrid B(Vector3d(0, 0, 0), n, 1*Mpc, 2*Mpc, 8*Mpc, 1., -11. / 3.); double brms = 0; for (unsigned int ix = 0; ix < n; ix++) for (unsigned int iy = 0; iy < n; iy++) for (unsigned int iz = 0; iz < n; iz++) - brms += B.getField(Vector3(ix, iy, iz)*Mpc).mag2(); + brms += B.getField(Vector3d(ix, iy, iz)*Mpc).mag2(); brms = sqrt(brms / n / n / n); double precision = 1e-12; diff --git a/test/testPropagation.cpp b/test/testPropagation.cpp index 9d8f944aa..7da559ab2 100644 --- a/test/testPropagation.cpp +++ b/test/testPropagation.cpp @@ -9,8 +9,8 @@ namespace mpc { TEST(testSimplePropagation, noMinStep) { ParticleState p; - p.setPosition(Vector3(0, 0, 0)); - p.setDirection(Vector3(0, 1, 0)); + p.setPosition(Vector3d(0, 0, 0)); + p.setDirection(Vector3d(0, 1, 0)); Candidate c(p); c.setNextStep(10); @@ -22,14 +22,14 @@ TEST(testSimplePropagation, noMinStep) { EXPECT_EQ(10, c.getCurrentStep()); EXPECT_EQ(50, c.getNextStep()); - EXPECT_EQ(Vector3(0,10,0), c.current.getPosition()); - EXPECT_EQ(Vector3(0,1,0), c.current.getDirection()); + EXPECT_EQ(Vector3d(0,10,0), c.current.getPosition()); + EXPECT_EQ(Vector3d(0,1,0), c.current.getDirection()); } TEST(testSimplePropagation, withMinStep) { ParticleState p; - p.setPosition(Vector3(0, 0, 0)); - p.setDirection(Vector3(0, 1, 0)); + p.setPosition(Vector3d(0, 0, 0)); + p.setDirection(Vector3d(0, 1, 0)); Candidate c(p); c.setNextStep(10); @@ -41,22 +41,22 @@ TEST(testSimplePropagation, withMinStep) { EXPECT_EQ(20, c.getCurrentStep()); EXPECT_EQ(100, c.getNextStep()); - EXPECT_EQ(Vector3(0,20,0), c.current.getPosition()); - EXPECT_EQ(Vector3(0,1,0), c.current.getDirection()); + EXPECT_EQ(Vector3d(0,20,0), c.current.getPosition()); + EXPECT_EQ(Vector3d(0,1,0), c.current.getDirection()); } TEST(testDeflectionCK, proton) { ParticleState p; p.setId(getNucleusId(1, 1)); p.setEnergy(100 * EeV); - p.setPosition(Vector3(0, 0, 0)); - p.setDirection(Vector3(0, 1, 0)); + p.setPosition(Vector3d(0, 0, 0)); + p.setDirection(Vector3d(0, 1, 0)); Candidate c(p); c.setNextStep(0); ref_ptr field = new UniformMagneticField( - Vector3(0, 0, 1e-12)); + Vector3d(0, 0, 1e-12)); DeflectionCK propa(field); propa.process(&c); @@ -69,21 +69,21 @@ TEST(testDeflectionCK, neutron) { ParticleState p; p.setId(getNucleusId(1, 0)); p.setEnergy(100 * EeV); - p.setPosition(Vector3(0, 0, 0)); - p.setDirection(Vector3(0, 1, 0)); + p.setPosition(Vector3d(0, 0, 0)); + p.setDirection(Vector3d(0, 1, 0)); Candidate c(p); ref_ptr field = new UniformMagneticField( - Vector3(0, 0, 1e-12)); + Vector3d(0, 0, 1e-12)); DeflectionCK propa(field); propa.process(&c); EXPECT_DOUBLE_EQ(0.1 * kpc, c.getCurrentStep()); EXPECT_DOUBLE_EQ(0.5 * kpc, c.getNextStep()); - EXPECT_EQ(Vector3(0, 0.1 * kpc, 0), c.current.getPosition()); - EXPECT_EQ(Vector3(0, 1, 0), c.current.getDirection()); + EXPECT_EQ(Vector3d(0, 0.1 * kpc, 0), c.current.getPosition()); + EXPECT_EQ(Vector3d(0, 1, 0), c.current.getDirection()); } int main(int argc, char **argv) { From f44ceec9a9dfd44cfa3827736dce44a7140be0a1 Mon Sep 17 00:00:00 2001 From: geromueller Date: Fri, 4 May 2012 09:43:30 +0200 Subject: [PATCH 0077/1298] add SimulationVolumeDependentModule, DeflectionCK --- include/mpc/Module.h | 5 +++++ include/mpc/module/DeflectionCK.h | 3 ++- src/module/DeflectionCK.cpp | 7 ++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/include/mpc/Module.h b/include/mpc/Module.h index ae0d70f27..5fa4bcede 100644 --- a/include/mpc/Module.h +++ b/include/mpc/Module.h @@ -31,6 +31,11 @@ class Module: public Referenced { } }; +class SimulationVolumeDependentModule: public Module { +public: + virtual void updateSimulationVolume(const Vector3 &origin, double size) = 0; +}; + } // namespace mpc #endif /* MPC_MODULE_H_ */ diff --git a/include/mpc/module/DeflectionCK.h b/include/mpc/module/DeflectionCK.h index 6313fe086..81c8934b0 100644 --- a/include/mpc/module/DeflectionCK.h +++ b/include/mpc/module/DeflectionCK.h @@ -16,7 +16,7 @@ namespace mpc { It uses the Runge-Kutta integration method with Cash-Karp coefficients.\n The step size control tries to keep the relative error close to, but smaller than the designated tolerance. */ -class DeflectionCK: public Module { +class DeflectionCK: public SimulationVolumeDependentModule { public: ref_ptr field; ExplicitRungeKutta erk; @@ -25,6 +25,7 @@ class DeflectionCK: public Module { DeflectionCK(MagneticField *field, double tolerance = 1e-4, double minimumStep = 0.1 * kpc); std::string getDescription() const; void process(Candidate *candidate) const; + void updateSimulationVolume(const Vector3 &origin, double size); }; } // namespace mpc diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index 5f0722232..0e5aa2eb0 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -37,7 +37,8 @@ class LorentzForce: public ExplicitRungeKutta::F { } }; -DeflectionCK::DeflectionCK(MagneticField *field, double tolerance, double minimumStep) { +DeflectionCK::DeflectionCK(MagneticField *field, double tolerance, + double minimumStep) { this->field = field; this->tolerance = tolerance; this->minimumStep = minimumStep; @@ -101,4 +102,8 @@ void DeflectionCK::process(Candidate *candidate) const { candidate->setNextStep(h * c_light); } +void DeflectionCK::updateSimulationVolume(const Vector3 &origin, double size) { + field->updateSimulationVolume(origin, size); +} + } /* namespace mpc */ From 9e9bc18bf6db0d188339800db5619200583a532d Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 4 May 2012 11:44:49 +0200 Subject: [PATCH 0078/1298] add python binding for Vector3 typedefs fix python tests --- python/mpc.i | 9 +++++--- test/python/testDeflectionCK.py | 8 +++---- test/python/testPhotoDisintegration.py | 6 +++--- test/python/testPhotoPionProduction.py | 29 ++++++++------------------ test/python/testTurbulentDeflection.py | 8 +++---- test/python/testTurbulentField.py | 11 +++++----- 6 files changed, 31 insertions(+), 40 deletions(-) diff --git a/python/mpc.i b/python/mpc.i index 2dd588691..613af76a0 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -66,13 +66,17 @@ %include "mpc/Referenced.h" %include "mpc/Units.h" %include "mpc/Nucleus.h" +%include "mpc/Common.h" + %include "mpc/Vector3.h" +%template(Vector3d) mpc::Vector3; +%template(Vector3f) mpc::Vector3; + %include "mpc/Random.h" %include "mpc/ParticleState.h" -// %feature("director") mpc::Source; + %template(SourceRefPtr) mpc::ref_ptr; %include "mpc/Source.h" -%include "mpc/Common.h" %template(CandidateVector) std::vector< mpc::ref_ptr >; %template(CandidateRefPtr) mpc::ref_ptr; @@ -81,7 +85,6 @@ %template(ModuleRefPtr) mpc::ref_ptr; %template(stdModuleVector) std::vector< mpc::ref_ptr >; %template(stdModuleList) std::list< mpc::ref_ptr >; -// %feature("director") mpc::Module; %include "mpc/Module.h" %template(stdMagneticFieldVector) std::vector< mpc::ref_ptr >; diff --git a/test/python/testDeflectionCK.py b/test/python/testDeflectionCK.py index adc293861..ef15af15c 100644 --- a/test/python/testDeflectionCK.py +++ b/test/python/testDeflectionCK.py @@ -33,11 +33,11 @@ def propagate(tolerance): maxLen.process(c) nSteps +=1 - posX.append(c.current.getPosition().x()) - posY.append(c.current.getPosition().y()) + posX.append(c.current.getPosition().x) + posY.append(c.current.getPosition().y) - dirX.append(c.current.getDirection().x()) - dirY.append(c.current.getDirection().y()) + dirX.append(c.current.getDirection().x) + dirY.append(c.current.getDirection().y) t = c.getTrajectoryLength() / R theta.append(t) diff --git a/test/python/testPhotoDisintegration.py b/test/python/testPhotoDisintegration.py index 5ecf3340a..45c0cff88 100644 --- a/test/python/testPhotoDisintegration.py +++ b/test/python/testPhotoDisintegration.py @@ -67,8 +67,8 @@ def plot_channel(rates_simulated, rates_data, id, channel): savefig('PhotoDisintegration_' + str(id) + '_' + str(channel) + '.png', bbox_inches='tight') def parse_id(id): - z = ((id - 1000000000) % 1000000) // 1000 - a = (id - 1000000000) // 1000000 + z = (id / 10000) % 1000 + a = (id / 10) % 1000 return 'Z=%i, A=%i' % (z, a) def parse_channel(c): @@ -79,7 +79,7 @@ def parse_channel(c): interaction = PhotoDisintegration(CMB_IRB) table = genfromtxt(getDataPath('/PhotoDisintegration/PDtable_CMB_IRB.txt')) -id = 1004002000 +id = getNucleusId(4,2) if len(sys.argv) >= 3: a = int(sys.argv[1]) diff --git a/test/python/testPhotoPionProduction.py b/test/python/testPhotoPionProduction.py index 7226f0fc0..da16587d6 100644 --- a/test/python/testPhotoPionProduction.py +++ b/test/python/testPhotoPionProduction.py @@ -1,30 +1,19 @@ from mpc import * from pylab import * -import ROOT -ROOT.gROOT.SetBatch(True) - -def getSlope(module, energy, charge, name): +def getRate(module, energy, charge): c = Candidate() c.current.setId(getNucleusId(1, charge)) c.current.setEnergy(energy) - l = [] - for i in range(5000): + N = 5000 + l = 0 + for i in range(N): s = InteractionState() module.setNextInteraction(c, s) - l.append(s.distance / Mpc) - - h = ROOT.TH1F('', '', 100, 0, max(l)) - - for element in l: - h.Fill(element) - - f = ROOT.TF1('f1', 'expo') - h.Fit(f, "q") - s = -f.GetParameter(1) - ds = f.GetParError(1) * s ** 2 - return s + l += s.distance / Mpc / N + + return 1 / l def compare(type, name): print "compare ", name @@ -35,8 +24,8 @@ def compare(type, name): p = zeros(len(E)) n = zeros(len(E)) for i,energy in enumerate(E*EeV): - p[i] = getSlope(ppp, energy, 1, name) - n[i] = getSlope(ppp, energy, 0, name) + p[i] = getRate(ppp, energy, 1) + n[i] = getRate(ppp, energy, 0) figure() plot(E_data, P_data, "r", label="Proton Data") plot(E, p, 'k+', label="Proton Simulated") diff --git a/test/python/testTurbulentDeflection.py b/test/python/testTurbulentDeflection.py index 65bf142d2..58b86cacb 100644 --- a/test/python/testTurbulentDeflection.py +++ b/test/python/testTurbulentDeflection.py @@ -8,7 +8,7 @@ nP = range(75) # sampling points to plot # create turbulent field with B_RMS = 1 nG and 0.5 Mpc correlation length -field = TurbulentMagneticFieldGrid(Vector3(0, 0, 0), 256, 0.05 * Mpc, 0.1 * Mpc, 2.2 * Mpc, 1*nG, -11/3.) +field = TurbulentMagneticFieldGrid(Vector3d(0, 0, 0), 256, 0.05 * Mpc, 0.1 * Mpc, 2.2 * Mpc, 1*nG, -11/3.) propa = DeflectionCK(field) age = linspace(1, 150, nS) @@ -22,7 +22,7 @@ ps.setId(getNucleusId(1, 1)) ps.setEnergy(E * EeV) ps.setDirection(Random.instance().randUnitVectorOnSphere()) - ps.setPosition(Vector3(0, 0, 0)) + ps.setPosition(Vector3d(0, 0, 0)) c = Candidate(ps) for i in range(nS): @@ -38,8 +38,8 @@ p = c.current.getDirection() p0 = c.initial.getDirection() distance[i] += x.mag() - rms1[i] += (x.angle(p))**2 - rms2[i] += (p0.angle(p))**2 + rms1[i] += (x.angleTo(p))**2 + rms2[i] += (p0.angleTo(p))**2 distance /= nT diff --git a/test/python/testTurbulentField.py b/test/python/testTurbulentField.py index 896701ef4..dedf576bf 100644 --- a/test/python/testTurbulentField.py +++ b/test/python/testTurbulentField.py @@ -1,7 +1,6 @@ # evaluating functions for the turbulentField module from pylab import * from mpc import * -from scipy import optimize def fftAutoCorrelation(a): ''' @@ -83,7 +82,7 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): lMin, lMax = 2, 32 Brms = 1 alpha = -11./3 -field = TurbulentMagneticFieldGrid(Vector3(0, 0, 0), n, 1, lMin, lMax, Brms, alpha) +field = TurbulentMagneticFieldGrid(Vector3d(0, 0, 0), n, 1, lMin, lMax, Brms, alpha) Lc = field.getCorrelationLength() ### copy field to array @@ -91,10 +90,10 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): for ix in range(n): for iy in range(n): for iz in range(n): - b = field.getField(Vector3(ix, iy, iz)) - Bx[ix, iy, iz] = b.x() - By[ix, iy, iz] = b.y() - Bz[ix, iy, iz] = b.z() + b = field.getField(Vector3d(ix, iy, iz)) + Bx[ix, iy, iz] = b.x + By[ix, iy, iz] = b.y + Bz[ix, iy, iz] = b.z del field ### plot slice in position space From 11708f99e0cd94c3dcbe3045e2b6280c0202c756 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 4 May 2012 12:25:21 +0200 Subject: [PATCH 0079/1298] change MagneticFieldGrid and field construction in TurbulentMagneticFieldGrid to float precision --- CMakeLists.txt | 2 +- include/mpc/magneticField/magneticFieldGrid.h | 2 +- .../turbulentMagneticFieldGrid.cpp | 55 +++++++++---------- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f547e2c28..f4e075ce2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ list(APPEND MPC_EXTRA_INCLUDES ${GSL_INCLUDE_DIR}) find_package(FFTW) if (FFTW_FOUND) list(APPEND MPC_EXTRA_SOURCES src/magneticField/turbulentMagneticFieldGrid.cpp) - list(APPEND MPC_EXTRA_LIBRARIES ${FFTW_LIBRARY}) + list(APPEND MPC_EXTRA_LIBRARIES ${FFTW_LIBRARY} ${FFTWF_LIBRARY}) endif (FFTW_FOUND) # gadget needed for SphMagneticField diff --git a/include/mpc/magneticField/magneticFieldGrid.h b/include/mpc/magneticField/magneticFieldGrid.h index 59268ea93..aa3f7d4b9 100644 --- a/include/mpc/magneticField/magneticFieldGrid.h +++ b/include/mpc/magneticField/magneticFieldGrid.h @@ -28,7 +28,7 @@ class MagneticFieldGrid: public MagneticField { virtual void updateSimulationVolume(const Vector3d &origin, double size); protected: - std::vector > > grid; + std::vector > > grid; size_t samples; double spacing; Vector3d origin; diff --git a/src/magneticField/turbulentMagneticFieldGrid.cpp b/src/magneticField/turbulentMagneticFieldGrid.cpp index f4410037e..cb90c9dc2 100644 --- a/src/magneticField/turbulentMagneticFieldGrid.cpp +++ b/src/magneticField/turbulentMagneticFieldGrid.cpp @@ -21,13 +21,13 @@ void TurbulentMagneticFieldGrid::setSeed(int seed) { void TurbulentMagneticFieldGrid::initialize() { size_t n = samples; // size of array - size_t n2 = floor(n/2) + 1; // size array in z-direction in configuration space + size_t n2 = floor(n / 2) + 1; // size array in z-direction in configuration space // arrays to hold the complex vector components of the B(k)-field - fftw_complex *Bkx, *Bky, *Bkz; - Bkx = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * n * n * n2); - Bky = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * n * n * n2); - Bkz = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * n * n * n2); + fftwf_complex *Bkx, *Bky, *Bkz; + Bkx = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * n * n * n2); + Bky = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * n * n * n2); + Bkz = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * n * n * n2); // calculate the n possible discrete wave numbers double K[n]; @@ -39,9 +39,9 @@ void TurbulentMagneticFieldGrid::initialize() { double k, theta, phase, cosPhase, sinPhase; double kMin = spacing / lMax; double kMax = spacing / lMin; - Vector3d b; // real b-field vector - Vector3d ek, e1, e2; // orthogonal base - Vector3d n0(1, 1, 1); // arbitrary vector to construct orthogonal base + Vector3f b; // real b-field vector + Vector3f ek, e1, e2; // orthogonal base + Vector3f n0(1, 1, 1); // arbitrary vector to construct orthogonal base for (size_t ix = 0; ix < n; ix++) { for (size_t iy = 0; iy < n; iy++) { @@ -99,43 +99,42 @@ void TurbulentMagneticFieldGrid::initialize() { // in-place, complex to real, inverse Fourier transformation on each component // note that the last elements of B(x) are unused now - double *Bx = (double*) Bkx; - fftw_plan plan_x = fftw_plan_dft_c2r_3d(n, n, n, Bkx, Bx, FFTW_ESTIMATE); - fftw_execute(plan_x); - fftw_destroy_plan(plan_x); + float *Bx = (float*) Bkx; + fftwf_plan plan_x = fftwf_plan_dft_c2r_3d(n, n, n, Bkx, Bx, FFTW_ESTIMATE); + fftwf_execute(plan_x); + fftwf_destroy_plan(plan_x); - double *By = (double*) Bky; - fftw_plan plan_y = fftw_plan_dft_c2r_3d(n, n, n, Bky, By, FFTW_ESTIMATE); - fftw_execute(plan_y); - fftw_destroy_plan(plan_y); + float *By = (float*) Bky; + fftwf_plan plan_y = fftwf_plan_dft_c2r_3d(n, n, n, Bky, By, FFTW_ESTIMATE); + fftwf_execute(plan_y); + fftwf_destroy_plan(plan_y); - double *Bz = (double*) Bkz; - fftw_plan plan_z = fftw_plan_dft_c2r_3d(n, n, n, Bkz, Bz, FFTW_ESTIMATE); - fftw_execute(plan_z); - fftw_destroy_plan(plan_z); + float *Bz = (float*) Bkz; + fftwf_plan plan_z = fftwf_plan_dft_c2r_3d(n, n, n, Bkz, Bz, FFTW_ESTIMATE); + fftwf_execute(plan_z); + fftwf_destroy_plan(plan_z); // calculate normalization double sumB2 = 0; for (size_t ix = 0; ix < n; ix++) for (size_t iy = 0; iy < n; iy++) for (size_t iz = 0; iz < n; iz++) { - i = ix * n * 2*n2 + iy * 2*n2 + iz; + i = ix * n * 2 * n2 + iy * 2 * n2 + iz; sumB2 += pow(Bx[i], 2) + pow(By[i], 2) + pow(Bz[i], 2); } - double weight = Brms / sqrt(sumB2 / (n * n * n)); + double w = Brms / sqrt(sumB2 / (n * n * n)); // normalize and save real component to the grid for (size_t ix = 0; ix < n; ix++) for (size_t iy = 0; iy < n; iy++) for (size_t iz = 0; iz < n; iz++) { - i = ix * n * 2*n2 + iy * 2*n2 + iz; - grid[ix][iy][iz] = Vector3d(Bx[i], By[i], Bz[i]) - * weight; + i = ix * n * 2 * n2 + iy * 2 * n2 + iz; + grid[ix][iy][iz] = Vector3f(Bx[i], By[i], Bz[i]) * w; } - fftw_free(Bkx); - fftw_free(Bky); - fftw_free(Bkz); + fftwf_free(Bkx); + fftwf_free(Bky); + fftwf_free(Bkz); } double TurbulentMagneticFieldGrid::getRMSFieldStrength() const { From db6a7de1601a8fb728065044d2d05976981b594a Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 4 May 2012 16:46:50 +0200 Subject: [PATCH 0080/1298] refactor magnetic fields --- CMakeLists.txt | 12 +- .../{magneticField.h => MagneticField.h} | 6 +- ...agneticFieldGrid.h => MagneticFieldGrid.h} | 15 +- ...{sphMagneticField.h => SPHMagneticField.h} | 2 +- ...icFieldGrid.h => TurbulentMagneticField.h} | 20 +- ...MagneticField.h => UniformMagneticField.h} | 8 +- include/mpc/module/DeflectionCK.h | 2 +- python/mpc.i | 20 +- src/Vector3.cpp | 899 ------------------ src/magneticField/MagneticFieldGrid.cpp | 91 ++ ...MagneticField.cpp => SPHMagneticField.cpp} | 2 +- ...eldGrid.cpp => TurbulentMagneticField.cpp} | 31 +- src/magneticField/magneticFieldGrid.cpp | 78 -- src/main.cpp | 9 +- test/python/testTurbulentDeflection.py | 2 +- test/python/testTurbulentField.py | 2 +- test/testMagneticField.cpp | 31 +- test/testPropagation.cpp | 2 +- 18 files changed, 178 insertions(+), 1054 deletions(-) rename include/mpc/magneticField/{magneticField.h => MagneticField.h} (81%) rename include/mpc/magneticField/{magneticFieldGrid.h => MagneticFieldGrid.h} (70%) rename include/mpc/magneticField/{sphMagneticField.h => SPHMagneticField.h} (96%) rename include/mpc/magneticField/{turbulentMagneticFieldGrid.h => TurbulentMagneticField.h} (62%) rename include/mpc/magneticField/{uniformMagneticField.h => UniformMagneticField.h} (74%) delete mode 100644 src/Vector3.cpp create mode 100644 src/magneticField/MagneticFieldGrid.cpp rename src/magneticField/{sphMagneticField.cpp => SPHMagneticField.cpp} (97%) rename src/magneticField/{turbulentMagneticFieldGrid.cpp => TurbulentMagneticField.cpp} (85%) delete mode 100644 src/magneticField/magneticFieldGrid.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f4e075ce2..08b243819 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,18 +16,22 @@ list(APPEND MPC_EXTRA_INCLUDES ${GSL_INCLUDE_DIR}) # fftw needed for TurbulentMagneticField find_package(FFTW) if (FFTW_FOUND) - list(APPEND MPC_EXTRA_SOURCES src/magneticField/turbulentMagneticFieldGrid.cpp) + list(APPEND MPC_EXTRA_SOURCES src/magneticField/TurbulentMagneticField.cpp) list(APPEND MPC_EXTRA_LIBRARIES ${FFTW_LIBRARY} ${FFTWF_LIBRARY}) endif (FFTW_FOUND) -# gadget needed for SphMagneticField +# gadget needed for SPHMagneticField and SPHTurbulentMagneticField find_package(Gadget) if (GADGET_FOUND) - list(APPEND MPC_EXTRA_SOURCES src/magneticField/sphMagneticField.cpp) + list(APPEND MPC_EXTRA_SOURCES src/magneticField/SPHMagneticField.cpp) list(APPEND MPC_EXTRA_INCLUDES ${GADGET_INCLUDE_DIR}) list(APPEND MPC_EXTRA_LIBRARIES ${GADGET_LIBRARY}) add_definitions (-DMPC_HAVE_GADGET) list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_GADGET) + # fftw needed for SPHTurbulentMagneticField + if (FFTW_FOUND) + list(APPEND MPC_EXTRA_SOURCES src/magneticField/SPHTurbulentMagneticField.cpp) + endif (FFTW_FOUND) endif (GADGET_FOUND) # Google Performance Tools optional @@ -95,7 +99,7 @@ add_library(mpc SHARED src/module/Redshift.cpp src/module/Output.cpp src/module/Tools.cpp - src/magneticField/magneticFieldGrid.cpp + src/magneticField/MagneticFieldGrid.cpp ${MPC_EXTRA_SOURCES} ) target_link_libraries(mpc ${MPC_EXTRA_LIBRARIES} ${TCMALLOC}) diff --git a/include/mpc/magneticField/magneticField.h b/include/mpc/magneticField/MagneticField.h similarity index 81% rename from include/mpc/magneticField/magneticField.h rename to include/mpc/magneticField/MagneticField.h index 6d44a8cdc..74becdcb1 100644 --- a/include/mpc/magneticField/magneticField.h +++ b/include/mpc/magneticField/MagneticField.h @@ -1,5 +1,5 @@ -#ifndef MAGNETICFIELD_H_ -#define MAGNETICFIELD_H_ +#ifndef MPC_MAGNETICFIELD_H_ +#define MPC_MAGNETICFIELD_H_ #include "mpc/Vector3.h" #include "mpc/Referenced.h" @@ -20,4 +20,4 @@ class MagneticField: public Referenced { } // namespace mpc -#endif /* MAGNETICFIELD_H_ */ +#endif /* MPC_MAGNETICFIELD_H_ */ diff --git a/include/mpc/magneticField/magneticFieldGrid.h b/include/mpc/magneticField/MagneticFieldGrid.h similarity index 70% rename from include/mpc/magneticField/magneticFieldGrid.h rename to include/mpc/magneticField/MagneticFieldGrid.h index aa3f7d4b9..94f9a81f1 100644 --- a/include/mpc/magneticField/magneticFieldGrid.h +++ b/include/mpc/magneticField/MagneticFieldGrid.h @@ -1,8 +1,7 @@ -#ifndef MAGNETICFIELDGRID_H_ -#define MAGNETICFIELDGRID_H_ +#ifndef MPC_MAGNETICFIELDGRID_H_ +#define MPC_MAGNETICFIELDGRID_H_ -#include "mpc/magneticField/magneticField.h" -#include "mpc/Vector3.h" +#include "mpc/magneticField/MagneticField.h" #include namespace mpc { @@ -20,15 +19,19 @@ namespace mpc { class MagneticFieldGrid: public MagneticField { public: MagneticFieldGrid(Vector3d origin, size_t n, double spacing); + Vector3f &get(size_t ix, size_t iy, size_t iz); + const Vector3f &get(size_t ix, size_t iy, size_t iz) const; Vector3d getField(const Vector3d &position) const; Vector3d getGridOrigin() const; size_t getGridSamples() const; double getGridSpacing() const; double getGridSize() const; virtual void updateSimulationVolume(const Vector3d &origin, double size); + void setGridOrigin(const Vector3d &origin); + void setGridSpacing(const double spacing); protected: - std::vector > > grid; + std::vector grid; size_t samples; double spacing; Vector3d origin; @@ -36,4 +39,4 @@ class MagneticFieldGrid: public MagneticField { } // namespace mpc -#endif /* MAGNETICFIELDGRID_H_ */ +#endif /* MPC_MAGNETICFIELDGRID_H_ */ diff --git a/include/mpc/magneticField/sphMagneticField.h b/include/mpc/magneticField/SPHMagneticField.h similarity index 96% rename from include/mpc/magneticField/sphMagneticField.h rename to include/mpc/magneticField/SPHMagneticField.h index b206c80b1..1e4349049 100644 --- a/include/mpc/magneticField/sphMagneticField.h +++ b/include/mpc/magneticField/SPHMagneticField.h @@ -3,7 +3,7 @@ #ifdef MPC_HAVE_GADGET -#include "mpc/magneticField/magneticFieldGrid.h" +#include "mpc/magneticField/MagneticField.h" #include "gadget/Database.h" #include "gadget/MagneticField.h" diff --git a/include/mpc/magneticField/turbulentMagneticFieldGrid.h b/include/mpc/magneticField/TurbulentMagneticField.h similarity index 62% rename from include/mpc/magneticField/turbulentMagneticFieldGrid.h rename to include/mpc/magneticField/TurbulentMagneticField.h index 2272a7a48..278bb2ad2 100644 --- a/include/mpc/magneticField/turbulentMagneticFieldGrid.h +++ b/include/mpc/magneticField/TurbulentMagneticField.h @@ -1,13 +1,13 @@ -#ifndef TURBULENTMAGNETICFIELD_H_ -#define TURBULENTMAGNETICFIELD_H_ +#ifndef MPC_TURBULENTMAGNETICFIELD_H_ +#define MPC_TURBULENTMAGNETICFIELD_H_ -#include "mpc/magneticField/magneticFieldGrid.h" +#include "mpc/magneticField/MagneticFieldGrid.h" #include "mpc/Random.h" namespace mpc { /** - @class TurbulentMagneticFieldGrid + @class TurbulentMagneticField @brief Random turbulent magnetic field on a cubic grid with trilinear interpolation. This class creates a random magnetic field with the following properties. \n @@ -22,12 +22,14 @@ namespace mpc { isotropy: \n same coherence length in all directions */ -class TurbulentMagneticFieldGrid: public MagneticFieldGrid { +class TurbulentMagneticField: public MagneticFieldGrid { public: - TurbulentMagneticFieldGrid(Vector3d origin, size_t samples, double spacing, - double lMin, double lMax, double Brms, double powerSpectralIndex); + TurbulentMagneticField(Vector3d origin, size_t samples, double spacing) : + MagneticFieldGrid(origin, samples, spacing) { + } + void initialize(double lMin, double lMax, double Brms, + double powerSpectralIndex = -11. / 3.); void setSeed(int seed); - void initialize(); double getRMSFieldStrength() const; double getCorrelationLength() const; double getPowerSpectralIndex() const; @@ -39,4 +41,4 @@ class TurbulentMagneticFieldGrid: public MagneticFieldGrid { } // namespace mpc -#endif /* TURBULENTMAGNETICFIELD_H_ */ +#endif /* MPC_TURBULENTMAGNETICFIELD_H_ */ diff --git a/include/mpc/magneticField/uniformMagneticField.h b/include/mpc/magneticField/UniformMagneticField.h similarity index 74% rename from include/mpc/magneticField/uniformMagneticField.h rename to include/mpc/magneticField/UniformMagneticField.h index b74f4a673..359bfb78c 100644 --- a/include/mpc/magneticField/uniformMagneticField.h +++ b/include/mpc/magneticField/UniformMagneticField.h @@ -1,7 +1,7 @@ -#ifndef UNIFORMAGNETICFIELD_H_ -#define UNIFORMAGNETICFIELD_H_ +#ifndef MPC_UNIFORMAGNETICFIELD_H_ +#define MPC_UNIFORMAGNETICFIELD_H_ -#include "mpc/magneticField/magneticField.h" +#include "mpc/magneticField/MagneticField.h" #include "mpc/Vector3.h" namespace mpc { @@ -29,4 +29,4 @@ class UniformMagneticField: public MagneticField { } // namespace mpc -#endif /* UNIFORMAGNETICFIELD_H_ */ +#endif /* MPC_UNIFORMAGNETICFIELD_H_ */ diff --git a/include/mpc/module/DeflectionCK.h b/include/mpc/module/DeflectionCK.h index 6313fe086..505369be3 100644 --- a/include/mpc/module/DeflectionCK.h +++ b/include/mpc/module/DeflectionCK.h @@ -2,7 +2,7 @@ #define MPC_DEFLECTION_H_ #include "mpc/Module.h" -#include "mpc/magneticField/magneticField.h" +#include "mpc/magneticField/MagneticField.h" #include "mpc/ExplicitRungeKutta.h" #include "mpc/PhasePoint.h" diff --git a/python/mpc.i b/python/mpc.i index 613af76a0..9b5f61a25 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -39,11 +39,11 @@ #include "mpc/module/DeflectionCK.h" #include "mpc/module/Tools.h" -#include "mpc/magneticField/magneticField.h" -#include "mpc/magneticField/uniformMagneticField.h" -#include "mpc/magneticField/magneticFieldGrid.h" -#include "mpc/magneticField/turbulentMagneticFieldGrid.h" -#include "mpc/magneticField/sphMagneticField.h" +#include "mpc/magneticField/MagneticField.h" +#include "mpc/magneticField/UniformMagneticField.h" +#include "mpc/magneticField/MagneticFieldGrid.h" +#include "mpc/magneticField/TurbulentMagneticField.h" +#include "mpc/magneticField/SPHMagneticField.h" #include "mpc/Referenced.h" #include "mpc/Candidate.h" @@ -89,11 +89,11 @@ %template(stdMagneticFieldVector) std::vector< mpc::ref_ptr >; %template(MagneticFieldRefPtr) mpc::ref_ptr; -%include "mpc/magneticField/magneticField.h" -%include "mpc/magneticField/magneticFieldGrid.h" -%include "mpc/magneticField/uniformMagneticField.h" -%include "mpc/magneticField/sphMagneticField.h" -%include "mpc/magneticField/turbulentMagneticFieldGrid.h" +%include "mpc/magneticField/MagneticField.h" +%include "mpc/magneticField/MagneticFieldGrid.h" +%include "mpc/magneticField/UniformMagneticField.h" +%include "mpc/magneticField/SPHMagneticField.h" +%include "mpc/magneticField/TurbulentMagneticField.h" %include "mpc/ExplicitRungeKutta.h" %include "mpc/PhasePoint.h" diff --git a/src/Vector3.cpp b/src/Vector3.cpp deleted file mode 100644 index 6a2958282..000000000 --- a/src/Vector3.cpp +++ /dev/null @@ -1,899 +0,0 @@ -// -*- C++ -*- -// $Id: ThreeVector.cc,v 1.3 2003/08/13 20:00:14 garren Exp $ -// --------------------------------------------------------------------------- -// -// This file is a part of the CLHEP - a Class Library for High Energy Physics. -// -// This is the implementation of the Vector3 class. -// -// See also ThreeVectorR.cc for implementation of Vector3 methods which -// would couple in all the HepRotation methods. -// - -#ifdef GNUPRAGMA -#pragma implementation -#endif - -#include "mpc/Vector3.h" - -#include -#include -#include - -namespace mpc { -void Vector3::setMag(double ma) { - double factor = mag(); - if (factor == 0) { - std::cerr << "Vector3::setMag : zero vector can't be stretched" - << std::endl; - } else { - factor = ma / factor; - setX(x() * factor); - setY(y() * factor); - setZ(z() * factor); - } -} - -double Vector3::operator ()(int i) const { - switch (i) { - case X: - return x(); - case Y: - return y(); - case Z: - return z(); - default: - std::cerr << "Vector3 subscripting: bad index (" << i << ")" - << std::endl; - } - return 0.; -} - -double & Vector3::operator ()(int i) { - static double dummy; - switch (i) { - case X: - return dx; - case Y: - return dy; - case Z: - return dz; - default: - std::cerr << "Vector3 subscripting: bad index (" << i << ")" - << std::endl; - return dummy; - } -} - -Vector3 & Vector3::rotateUz(const Vector3& NewUzVector) { - // NewUzVector must be normalized ! - - double u1 = NewUzVector.x(); - double u2 = NewUzVector.y(); - double u3 = NewUzVector.z(); - double up = u1 * u1 + u2 * u2; - - if (up > 0) { - up = sqrt(up); - double px = dx, py = dy, pz = dz; - dx = (u1 * u3 * px - u2 * py) / up + u1 * pz; - dy = (u2 * u3 * px + u1 * py) / up + u2 * pz; - dz = -up * px + u3 * pz; - } else if (u3 < 0.) { - dx = -dx; - dz = -dz; - } // phi=0 teta=pi - else { - }; - return *this; -} - -double Vector3::pseudoRapidity() const { - double m = mag(); - if (m == 0) - return 0.0; - if (m == z()) - return 1.0E72; - if (m == -z()) - return -1.0E72; - return 0.5 * log((m + z()) / (m - z())); -} - -std::ostream & operator<<(std::ostream & os, const Vector3 & v) { - return os << "(" << v.x() << "," << v.y() << "," << v.z() << ")"; -} - -std::istream & operator>>(std::istream & is, Vector3 & v) { - double x, y, z; - is >> x; - is >> y; - is >> z; - v.set(x, y, z); - return is; -} // operator>>() - -const Vector3 HepXHat(1.0, 0.0, 0.0); -const Vector3 HepYHat(0.0, 1.0, 0.0); -const Vector3 HepZHat(0.0, 0.0, 1.0); - -//------------------- -// -// New methods introduced when ZOOM PhysicsVectors was merged in: -// -//------------------- - -Vector3 & Vector3::rotateX(double phi) { - double sinphi = sin(phi); - double cosphi = cos(phi); - double ty; - ty = dy * cosphi - dz * sinphi; - dz = dz * cosphi + dy * sinphi; - dy = ty; - return *this; -} /* rotateX */ - -Vector3 & Vector3::rotateY(double phi) { - double sinphi = sin(phi); - double cosphi = cos(phi); - double tz; - tz = dz * cosphi - dx * sinphi; - dx = dx * cosphi + dz * sinphi; - dz = tz; - return *this; -} /* rotateY */ - -Vector3 & Vector3::rotateZ(double phi) { - double sinphi = sin(phi); - double cosphi = cos(phi); - double tx; - tx = dx * cosphi - dy * sinphi; - dy = dy * cosphi + dx * sinphi; - dx = tx; - return *this; -} /* rotateZ */ - -bool Vector3::isNear(const Vector3 & v, double epsilon) const { - double limit = dot(v) * epsilon * epsilon; - return ((*this - v).mag2() <= limit); -} /* isNear() */ - -double Vector3::howNear(const Vector3 & v) const { - // | V1 - V2 | **2 / V1 dot V2, up to 1 - double d = (*this - v).mag2(); - double vdv = dot(v); - if ((vdv > 0) && (d < vdv)) { - return sqrt(d / vdv); - } else if ((vdv == 0) && (d == 0)) { - return 0; - } else { - return 1; - } -} /* howNear */ - -double Vector3::deltaPhi(const Vector3 & v2) const { - double dphi = v2.getPhi() - getPhi(); - if (dphi > M_PI) { - dphi -= 2 * M_PI; - } else if (dphi <= -M_PI) { - dphi += 2 * M_PI; - } - return dphi; -} /* deltaPhi */ - -double Vector3::deltaR(const Vector3 & v) const { - double a = eta() - v.eta(); - double b = deltaPhi(v); - return sqrt(a * a + b * b); -} /* deltaR */ - -double Vector3::cosTheta(const Vector3 & q) const { - double arg; - double ptot2 = mag2() * q.mag2(); - if (ptot2 <= 0) { - arg = 0.0; - } else { - arg = dot(q) / sqrt(ptot2); - if (arg > 1.0) - arg = 1.0; - if (arg < -1.0) - arg = -1.0; - } - return arg; -} - -double Vector3::cos2Theta(const Vector3 & q) const { - double arg; - double ptot2 = mag2(); - double qtot2 = q.mag2(); - if (ptot2 == 0 || qtot2 == 0) { - arg = 1.0; - } else { - double pdq = dot(q); - arg = (pdq / ptot2) * (pdq / qtot2); - // More naive methods overflow on vectors which can be squared - // but can't be raised to the 4th power. - if (arg > 1.0) - arg = 1.0; - } - return arg; -} - -void Vector3::setEta(double eta) { - double phi = 0; - double r; - if ((dx == 0) && (dy == 0)) { - if (dz == 0) { - std::cerr - << "Attempt to set eta of zero vector -- vector is unchanged" - << std::endl; - return; - } - std::cerr - << "Attempt to set eta of vector along Z axis -- will use phi = 0" - << std::endl; - r = fabs(dz); - } else { - r = getR(); - phi = getPhi(); - } - double tanHalfTheta = exp(-eta); - double cosTheta = (1 - tanHalfTheta * tanHalfTheta) - / (1 + tanHalfTheta * tanHalfTheta); - dz = r * cosTheta; - double rho = r * sqrt(1 - cosTheta * cosTheta); - dy = rho * sin(phi); - dx = rho * cos(phi); - return; -} - -void Vector3::setCylTheta(double theta) { - - // In cylindrical coords, set theta while keeping rho and phi fixed - - if ((dx == 0) && (dy == 0)) { - if (dz == 0) { - std::cerr - << "Attempt to set cylTheta of zero vector -- vector is unchanged" - << std::endl; - return; - } - if (theta == 0) { - dz = fabs(dz); - return; - } - if (theta == M_PI) { - dz = -fabs(dz); - return; - } - std::cerr << "Attempt set cylindrical theta of vector along Z axis " - "to a non-trivial value, while keeping rho fixed -- " - "will return zero vector" << std::endl; - dz = 0; - return; - } - if ((theta < 0) || (theta > M_PI)) { - std::cerr - << "Setting Cyl theta of a vector based on a value not in [0, PI]" - << std::endl; - // No special return needed if warning is ignored. - } - double phi(getPhi()); - double rho = getRho(); - if ((theta == 0) || (theta == M_PI)) { - std::cerr << "Attempt to set cylindrical theta to 0 or PI " - "while keeping rho fixed -- infinite Z will be computed" - << std::endl; - dz = (theta == 0) ? 1.0E72 : -1.0E72; - return; - } - dz = rho / tan(theta); - dy = rho * sin(phi); - dx = rho * cos(phi); - -} /* setCylTheta */ - -void Vector3::setCylEta(double eta) { - - // In cylindrical coords, set eta while keeping rho and phi fixed - - double theta = 2 * atan(exp(-eta)); - - //-| The remaining code is similar to setCylTheta, The reason for - //-| using a copy is so as to be able to change the messages in the - //-| ZMthrows to say eta rather than theta. Besides, we assumedly - //-| need not check for theta of 0 or PI. - - if ((dx == 0) && (dy == 0)) { - if (dz == 0) { - std::cerr - << "Attempt to set cylEta of zero vector -- vector is unchanged" - << std::endl; - return; - } - if (theta == 0) { - dz = fabs(dz); - return; - } - if (theta == M_PI) { - dz = -fabs(dz); - return; - } - std::cerr << "Attempt set cylindrical eta of vector along Z axis " - "to a non-trivial value, while keeping rho fixed -- " - "will return zero vector" << std::endl; - dz = 0; - return; - } - double phi(getPhi()); - double rho = getRho(); - dz = rho / tan(theta); - dy = rho * sin(phi); - dx = rho * cos(phi); - -} /* setCylEta */ - -Vector3 Vector3::operator/(double c) const { - if (c == 0) { - std::cerr << "Attempt to divide vector by 0 -- " - "will produce infinities and/or NANs" << std::endl; - } - double oneOverC = 1.0 / c; - return Vector3(x() * oneOverC, y() * oneOverC, z() * oneOverC); -} /* v / c */ - -Vector3 & Vector3::operator/=(double c) { - if (c == 0) { - std::cerr << "Attempt to do vector /= 0 -- " - "division by zero would produce infinite or NAN components" - << std::endl; - } - double oneOverC = 1.0 / c; - dx *= oneOverC; - dy *= oneOverC; - dz *= oneOverC; - return *this; -} - -void Vector3::setSpherical(double r, double theta, double phi) { - if (r < 0) { - throw std::runtime_error("Spherical coordinates set with negative R"); - // No special return needed if warning is ignored. - } - if ((theta < 0) || (theta > M_PI)) { - throw std::runtime_error( - "Spherical coordinates set with theta not in [0, PI]"); - // No special return needed if warning is ignored. - } - dz = r * cos(theta); - double rho(r * sin(theta)); - dy = rho * sin(phi); - dx = rho * cos(phi); - return; -} /* setSpherical (r, theta, phi) */ - -void Vector3::setCylindrical(double rho, double phi, double z) { - if (rho < 0) { - throw std::runtime_error( - "Cylindrical coordinates supplied with negative Rho"); - // No special return needed if warning is ignored. - } - dz = z; - dy = rho * sin(phi); - dx = rho * cos(phi); - return; -} /* setCylindrical (r, phi, z) */ - -void Vector3::setRhoPhiTheta(double rho, double phi, double theta) { - if (rho == 0) { - throw std::runtime_error( - "Attempt set vector components rho, phi, theta with zero rho -- " - "zero vector is returned, ignoring theta and phi"); - dx = 0; - dy = 0; - dz = 0; - return; - } - if ((theta == 0) || (theta == M_PI)) { - throw std::runtime_error( - "Attempt set cylindrical vector vector with finite rho and " - "theta along the Z axis: infinite Z would be computed"); - } - if ((theta < 0) || (theta > M_PI)) { - throw std::runtime_error( - "Rho, phi, theta set with theta not in [0, PI]"); - // No special return needed if warning is ignored. - } - dz = rho / tan(theta); - dy = rho * sin(phi); - dx = rho * cos(phi); - return; -} /* setCyl (rho, phi, theta) */ - -void Vector3::setRhoPhiEta(double rho, double phi, double eta) { - if (rho == 0) { - throw std::runtime_error( - "Attempt set vector components rho, phi, eta with zero rho -- " - "zero vector is returned, ignoring eta and phi"); - dx = 0; - dy = 0; - dz = 0; - return; - } - double theta(2 * atan(exp(-eta))); - dz = rho / tan(theta); - dy = rho * sin(phi); - dx = rho * cos(phi); - return; -} /* setCyl (rho, phi, eta) */ - -//************ -// - 3 - -// Comparisons -// -//************ - -int Vector3::compare(const Vector3 & v) const { - if (dz > v.dz) { - return 1; - } else if (dz < v.dz) { - return -1; - } else if (dy > v.dy) { - return 1; - } else if (dy < v.dy) { - return -1; - } else if (dx > v.dx) { - return 1; - } else if (dx < v.dx) { - return -1; - } else { - return 0; - } -} /* Compare */ - -bool Vector3::operator >(const Vector3 & v) const { - return (compare(v) > 0); -} -bool Vector3::operator <(const Vector3 & v) const { - return (compare(v) < 0); -} -bool Vector3::operator>=(const Vector3 & v) const { - return (compare(v) >= 0); -} -bool Vector3::operator<=(const Vector3 & v) const { - return (compare(v) <= 0); -} - -//-******** -// Nearness -//-******** - -// These methods all assume you can safely take mag2() of each vector. -// Absolutely safe but slower and much uglier alternatives were -// provided as build-time options in ZOOM SpaceVectors. -// Also, much smaller codes were provided tht assume you can square -// mag2() of each vector; but those return bad answers without warning -// when components exceed 10**90. -// -// IsNear, HowNear, and DeltaR are found in ThreeVector.cc - -double Vector3::howParallel(const Vector3 & v) const { - // | V1 x V2 | / | V1 dot V2 | - double v1v2 = fabs(dot(v)); - if (v1v2 == 0) { - // Zero is parallel to no other vector except for zero. - return ((mag2() == 0) && (v.mag2() == 0)) ? 0 : 1; - } - Vector3 v1Xv2(cross(v)); - double abscross = v1Xv2.mag(); - if (abscross >= v1v2) { - return 1; - } else { - return abscross / v1v2; - } -} /* howParallel() */ - -bool Vector3::isParallel(const Vector3 & v, double epsilon) const { - // | V1 x V2 | **2 <= epsilon **2 | V1 dot V2 | **2 - // V1 is *this, V2 is v - - static const double TOOBIG = pow(2.0, 507); - static const double SCALE = pow(2.0, -507); - double v1v2 = fabs(dot(v)); - if (v1v2 == 0) { - return ((mag2() == 0) && (v.mag2() == 0)); - } - if (v1v2 >= TOOBIG) { - Vector3 sv1(*this * SCALE); - Vector3 sv2(v * SCALE); - Vector3 sv1Xsv2 = sv1.cross(sv2); - double x2 = sv1Xsv2.mag2(); - double limit = v1v2 * SCALE * SCALE; - limit = epsilon * epsilon * limit * limit; - return (x2 <= limit); - } - - // At this point we know v1v2 can be squared. - - Vector3 v1Xv2(cross(v)); - if ((fabs(v1Xv2.dx) > TOOBIG) || (fabs(v1Xv2.dy) > TOOBIG) - || (fabs(v1Xv2.dz) > TOOBIG)) { - return false; - } - - return ((v1Xv2.mag2()) <= ((epsilon * v1v2) * (epsilon * v1v2))); - -} /* isParallel() */ - -double Vector3::howOrthogonal(const Vector3 & v) const { - // | V1 dot V2 | / | V1 x V2 | - - double v1v2 = fabs(dot(v)); - //-| Safe because both v1 and v2 can be squared - if (v1v2 == 0) { - return 0; // Even if one or both are 0, they are considered orthogonal - } - Vector3 v1Xv2(cross(v)); - double abscross = v1Xv2.mag(); - if (v1v2 >= abscross) { - return 1; - } else { - return v1v2 / abscross; - } - -} /* howOrthogonal() */ - -bool Vector3::isOrthogonal(const Vector3 & v, double epsilon) const { -// | V1 x V2 | **2 <= epsilon **2 | V1 dot V2 | **2 -// V1 is *this, V2 is v - - static const double TOOBIG = pow(2.0, 507); - static const double SCALE = pow(2.0, -507); - double v1v2 = fabs(dot(v)); - //-| Safe because both v1 and v2 can be squared - if (v1v2 >= TOOBIG) { - Vector3 sv1(*this * SCALE); - Vector3 sv2(v * SCALE); - Vector3 sv1Xsv2 = sv1.cross(sv2); - double x2 = sv1Xsv2.mag2(); - double limit = epsilon * epsilon * x2; - double y2 = v1v2 * SCALE * SCALE; - return (y2 * y2 <= limit); - } - - // At this point we know v1v2 can be squared. - - Vector3 eps_v1Xv2(cross(epsilon * v)); - if ((fabs(eps_v1Xv2.dx) > TOOBIG) || (fabs(eps_v1Xv2.dy) > TOOBIG) - || (fabs(eps_v1Xv2.dz) > TOOBIG)) { - return true; - } - - // At this point we know all the math we need can be done. - - return (v1v2 * v1v2 <= eps_v1Xv2.mag2()); - -} /* isOrthogonal() */ - -double Vector3::setTolerance(double tol) { -// Set the tolerance for Vector3s to be considered near one another - double oldTolerance(tolerance); - tolerance = tol; - return oldTolerance; -} - -//-*********************** -// Helper Methods: -// negativeInfinity() -//-*********************** - -double Vector3::negativeInfinity() const { - // A byte-order-independent way to return -Infinity - struct Dib { - union { - double d; - unsigned char i[8]; - } u; - }; - Dib negOne; - Dib posTwo; - negOne.u.d = -1.0; - posTwo.u.d = 2.0; - Dib value; - int k; - for (k = 0; k < 8; k++) { - value.u.i[k] = negOne.u.i[k] | posTwo.u.i[k]; - } - return value.u.d; -} -double Vector3::beta() const { - double b = sqrt(mag2()); - if (b >= 1) { - throw std::runtime_error( - "Beta taken for Vector3 of at least unit length"); - } - return b; -} - -double Vector3::gamma() const { - double beta = sqrt(mag2()); - if (beta == 1) { - throw std::runtime_error( - "Gamma taken for Vector3 of unit magnitude -- infinite result"); - } - if (beta > 1) { - throw std::runtime_error( - "Gamma taken for Vector3 of more than unit magnitude -- " - "the sqrt function would return NAN"); - } - return 1 / sqrt(1 - beta * beta); -} - -double Vector3::rapidity() const { - if (fabs(dz) == 1) { - throw std::runtime_error( - "Rapidity in Z direction taken for Vector3 with |Z| = 1 -- \n" - "the log should return infinity"); - } - if (fabs(dz) > 1) { - throw std::runtime_error( - "Rapidity in Z direction taken for Vector3 with |Z| > 1 -- \n" - "the log would return a NAN"); - } -// Want inverse tanh(dz): - return (.5 * log((1 + dz) / (1 - dz))); -} - -double Vector3::coLinearRapidity() const { - double b = beta(); - if (b == 1) { - throw std::runtime_error( - "Co-linear Rapidity taken for Vector3 of unit length -- " - "the log should return infinity"); - } - if (b > 1) { - throw std::runtime_error( - "Co-linear Rapidity taken for Vector3 of more than unit length -- " - "the log would return a NAN"); - } -// Want inverse tanh(b): - return (.5 * log((1 + b) / (1 - b))); -} - -//-*********************************************** -// Other properties relative to a reference vector -//-*********************************************** - -Vector3 Vector3::project(const Vector3 & v2) const { - double mag2v2 = v2.mag2(); - if (mag2v2 == 0) { - throw std::runtime_error( - "Attempt to take projection of vector against zero reference vector "); - return project(); - } - return (v2 * (dot(v2) / mag2v2)); -} - -double Vector3::rapidity(const Vector3 & v2) const { - double vmag = v2.mag(); - if (vmag == 0) { - throw std::runtime_error("Rapidity taken with respect to zero vector"); - return 0; - } - double z = dot(v2) / vmag; - if (fabs(z) >= 1) { - throw std::runtime_error("Rapidity taken for too large a Vector3 " - "-- would return infinity or NAN"); - } -// Want inverse tanh(z): - return (.5 * log((1 + z) / (1 - z))); -} - -double Vector3::eta(const Vector3 & v2) const { - // Defined as -log ( tan ( .5* theta(u) ) ); - // - // Quicker is to use cosTheta: - // tan (theta/2) = sin(theta)/(1 + cos(theta)) - - double r = getR(); - double v2r = v2.mag(); - if ((r == 0) || (v2r == 0)) { - throw std::runtime_error( - "Cannot find pseudorapidity of a zero vector relative to a vector"); - return 0.; - } - double c = dot(v2) / (r * v2r); - if (c >= 1) { - c = 1; //-| We don't want to return NAN because of roundoff - throw std::runtime_error( - "Pseudorapidity of vector relative to parallel vector -- " - "will give infinite result"); - // We can just go on; tangent will be 0, so - // log (tangent) will be -INFINITY, so result - // will be +INFINITY. - } - if (c <= -1) { - throw std::runtime_error( - "Pseudorapidity of vector relative to anti-parallel vector -- " - "will give negative infinite result"); - //-| We don't want to return NAN because of roundoff - return (negativeInfinity()); - // If we just went on, the tangent would be NAN - // so return would be NAN. But the proper limit - // of tan is +Infinity, so the return should be - // -INFINITY. - } - - double tangent = sqrt(1 - c * c) / (1 + c); - return (-log(tangent)); - -} /* eta (u) */ - -//-********************************************* -// - 6 - -// Decomposition of an angle between two vectors -// -//-********************************************* - -double Vector3::polarAngle(const Vector3 & v2) const { - return fabs(v2.getTheta() - getTheta()); -} /* polarAngle */ - -double Vector3::polarAngle(const Vector3 & v2, const Vector3 & ref) const { - return fabs(v2.angle(ref) - angle(ref)); -} /* polarAngle (v2, ref) */ - -// double Vector3::azimAngle (const Vector3 & v2) const -// is now in the .icc file as deltaPhi(v2) - -double Vector3::azimAngle(const Vector3 & v2, const Vector3 & ref) const { - - Vector3 vperp(perpPart(ref)); - if (vperp.mag2() == 0) { - throw std::runtime_error( - "Cannot find azimuthal angle with reference direction parallel to " - "vector 1 -- will return zero"); - return 0; - } - - Vector3 v2perp(v2.perpPart(ref)); - if (v2perp.mag2() == 0) { - throw std::runtime_error( - "Cannot find azimuthal angle with reference direction parallel to " - "vector 2 -- will return zero"); - return 0; - } - - double ang = vperp.angle(v2perp); - - // Now compute the sign of the answer: that of U*(VxV2) or - // the equivalent expression V*(V2xU). - - if (dot(v2.cross(ref)) >= 0) { - return ang; - } else { - return -ang; - } - - //-| Note that if V*(V2xU) is zero, we want to return 0 or PI - //-| depending on whether vperp is aligned or antialigned with v2perp. - //-| The computed angle() expression does this properly. - -} /* azimAngle (v2, ref) */ -//-************************ -// rotate about axis -//-************************ - -Vector3 & Vector3::rotate(const Vector3 & axis, double delta) { - double r = axis.mag(); - if (r == 0) { - throw std::runtime_error( - "Attempt to rotate around a zero vector axis! "); - return *this; - } - register double scale = 1.0 / r; - register double ux = scale * axis.getX(); - register double uy = scale * axis.getY(); - register double uz = scale * axis.getZ(); - double cd = cos(delta); - double sd = sin(delta); - register double ocd = 1 - cd; - double rx; - double ry; - double rz; - - { - register double ocdux = ocd * ux; - rx = dx * (cd + ocdux * ux) + dy * (ocdux * uy - sd * uz) - + dz * (ocdux * uz + sd * uy); - } - - { - register double ocduy = ocd * uy; - ry = dy * (cd + ocduy * uy) + dz * (ocduy * uz - sd * ux) - + dx * (ocduy * ux + sd * uz); - } - - { - register double ocduz = ocd * uz; - rz = dz * (cd + ocduz * uz) + dx * (ocduz * ux - sd * uy) - + dy * (ocduz * uy + sd * ux); - } - - dx = rx; - dy = ry; - dz = rz; - - return *this; -} /* rotate */ - -//-**************************** -// rotate by three euler angles -//-**************************** - -Vector3 & Vector3::rotate(double phi, double theta, double psi) { - - double rx; - double ry; - double rz; - - register double sinPhi = sin(phi), cosPhi = cos(phi); - register double sinTheta = sin(theta), cosTheta = cos(theta); - register double sinPsi = sin(psi), cosPsi = cos(psi); - - rx = (cosPsi * cosPhi - cosTheta * sinPsi * sinPhi) * dx - + (cosPsi * sinPhi + cosTheta * sinPsi * cosPhi) * dy - + (sinPsi * sinTheta) * dz; - - ry = (-sinPsi * cosPhi - cosTheta * cosPsi * sinPhi) * dx - + (-sinPsi * sinPhi + cosTheta * cosPsi * cosPhi) * dy - + (cosPsi * sinTheta) * dz; - - rz = (sinTheta * sinPhi) * dx + (-sinTheta * cosPhi) * dy + (cosTheta) * dz; - - dx = rx; - dy = ry; - dz = rz; - - return *this; - -} /* rotate */ - -//-******************* -// rotate(HepAxisAngle) -// rotate(HepEulerAngles) -//-******************* - -//-*********************** -// rotationOf(HepAxisAngle) -// rotationOf(HepEulerAngles) -// and coordinate axis rotations -//-*********************** - -Vector3 rotationOf(const Vector3 & vec, const Vector3 & axis, double delta) { - Vector3 vv(vec); - return vv.rotate(axis, delta); -} - -Vector3 rotationOf(const Vector3 & vec, double phi, double theta, double psi) { - Vector3 vv(vec); - return vv.rotate(phi, theta, psi); -} - -Vector3 rotationXOf(const Vector3 & vec, double delta) { - Vector3 vv(vec); - return vv.rotateX(delta); -} - -Vector3 rotationYOf(const Vector3 & vec, double delta) { - Vector3 vv(vec); - return vv.rotateY(delta); -} - -Vector3 rotationZOf(const Vector3 & vec, double delta) { - Vector3 vv(vec); - return vv.rotateZ(delta); -} - -double Vector3::tolerance = Vector3::ToleranceTicks * 2.22045e-16; - -} // namespace mpc diff --git a/src/magneticField/MagneticFieldGrid.cpp b/src/magneticField/MagneticFieldGrid.cpp new file mode 100644 index 000000000..aa1c1e996 --- /dev/null +++ b/src/magneticField/MagneticFieldGrid.cpp @@ -0,0 +1,91 @@ +#include "mpc/magneticField/MagneticFieldGrid.h" + +namespace mpc { + +void periodicClamp(double x, int n, int &low, int &high, double &fLow, + double &fHigh) { + // closest lower and upper neighbour in a periodically continued grid + low = ((int(x) % n) + n) % n; + high = (low + 1) % n; + fLow = x - floor(x); + fHigh = 1 - fLow; +} + +MagneticFieldGrid::MagneticFieldGrid(Vector3d origin, size_t samples, + double spacing) : + origin(origin), samples(samples), spacing(spacing) { + grid.resize(samples * samples * samples); +} + +void MagneticFieldGrid::updateSimulationVolume(const Vector3d &origin, + double size) { + this->origin = origin; + this->spacing = size / (samples - 1); +} + +Vector3d MagneticFieldGrid::getGridOrigin() const { + return origin; +} + +size_t MagneticFieldGrid::getGridSamples() const { + return samples; +} + +double MagneticFieldGrid::getGridSpacing() const { + return spacing; +} + +double MagneticFieldGrid::getGridSize() const { + return samples * spacing; +} + +Vector3f &MagneticFieldGrid::get(size_t ix, size_t iy, size_t iz) { + int i = ix * samples * samples + iy * samples + iz; + return grid[i]; +} + +const Vector3f &MagneticFieldGrid::get(size_t ix, size_t iy, size_t iz) const { + int i = ix * samples * samples + iy * samples + iz; + return grid[i]; +} + +Vector3d MagneticFieldGrid::getField(const Vector3d &position) const { + Vector3d r = (position - origin) / spacing; + int ix, iX, iy, iY, iz, iZ; + double fx, fX, fy, fY, fz, fZ; + periodicClamp(r.x, samples, ix, iX, fx, fX); + periodicClamp(r.y, samples, iy, iY, fy, fY); + periodicClamp(r.z, samples, iz, iZ, fz, fZ); + + // trilinear interpolation + // check: http://paulbourke.net/miscellaneous/interpolation/ + Vector3d b(0, 0, 0); + //V000 (1 - x) (1 - y) (1 - z) + + b += get(ix, iy, iz) * fX * fY * fZ; + //V100 x (1 - y) (1 - z) + + b += get(iX, iy, iz) * fx * fY * fZ; + //V010 (1 - x) y (1 - z) + + b += get(ix, iY, iz) * fX * fy * fZ; + //V001 (1 - x) (1 - y) z + + b += get(ix, iy, iZ) * fX * fY * fz; + //V101 x (1 - y) z + + b += get(iX, iy, iZ) * fx * fY * fz; + //V011 (1 - x) y z + + b += get(ix, iY, iZ) * fX * fy * fz; + //V110 x y (1 - z) + + b += get(iX, iY, iz) * fx * fy * fZ; + //V111 x y z + b += get(iX, iY, iZ) * fx * fy * fz; + + return b; +} + +void MagneticFieldGrid::setGridOrigin(const Vector3d& origin) { + this->origin = origin; +} + +void MagneticFieldGrid::setGridSpacing(const double spacing) { + this->spacing = spacing; +} + +} // namespace mpc diff --git a/src/magneticField/sphMagneticField.cpp b/src/magneticField/SPHMagneticField.cpp similarity index 97% rename from src/magneticField/sphMagneticField.cpp rename to src/magneticField/SPHMagneticField.cpp index 057bcf782..fc4c72aa3 100644 --- a/src/magneticField/sphMagneticField.cpp +++ b/src/magneticField/SPHMagneticField.cpp @@ -1,4 +1,4 @@ -#include "mpc/magneticField/sphMagneticField.h" +#include "mpc/magneticField/SPHMagneticField.h" #include "mpc/Units.h" #include "kiss/logger.h" diff --git a/src/magneticField/turbulentMagneticFieldGrid.cpp b/src/magneticField/TurbulentMagneticField.cpp similarity index 85% rename from src/magneticField/turbulentMagneticFieldGrid.cpp rename to src/magneticField/TurbulentMagneticField.cpp index cb90c9dc2..c5b6d72b5 100644 --- a/src/magneticField/turbulentMagneticFieldGrid.cpp +++ b/src/magneticField/TurbulentMagneticField.cpp @@ -1,25 +1,19 @@ -#include "mpc/magneticField/turbulentMagneticFieldGrid.h" +#include "mpc/magneticField/TurbulentMagneticField.h" #include "fftw3.h" namespace mpc { -TurbulentMagneticFieldGrid::TurbulentMagneticFieldGrid(Vector3d origin, - size_t samples, double spacing, double lMin, double lMax, double Brms, - double powerSpectralIndex) : - MagneticFieldGrid(origin, samples, spacing) { +void TurbulentMagneticField::setSeed(int seed) { + random.seed(seed); +} + +void TurbulentMagneticField::initialize(double lMin, double lMax, double Brms, + double powerSpectralIndex) { this->lMin = lMin; this->lMax = lMax; this->Brms = Brms; this->powerSpectralIndex = powerSpectralIndex; - initialize(); -} - -void TurbulentMagneticFieldGrid::setSeed(int seed) { - random.seed(seed); - initialize(); -} -void TurbulentMagneticFieldGrid::initialize() { size_t n = samples; // size of array size_t n2 = floor(n / 2) + 1; // size array in z-direction in configuration space @@ -129,7 +123,10 @@ void TurbulentMagneticFieldGrid::initialize() { for (size_t iy = 0; iy < n; iy++) for (size_t iz = 0; iz < n; iz++) { i = ix * n * 2 * n2 + iy * 2 * n2 + iz; - grid[ix][iy][iz] = Vector3f(Bx[i], By[i], Bz[i]) * w; + Vector3f &b = get(ix, iy, iz); + b.x = Bx[i] * w; + b.y = By[i] * w; + b.z = Bz[i] * w; } fftwf_free(Bkx); @@ -137,15 +134,15 @@ void TurbulentMagneticFieldGrid::initialize() { fftwf_free(Bkz); } -double TurbulentMagneticFieldGrid::getRMSFieldStrength() const { +double TurbulentMagneticField::getRMSFieldStrength() const { return Brms; } -double TurbulentMagneticFieldGrid::getPowerSpectralIndex() const { +double TurbulentMagneticField::getPowerSpectralIndex() const { return powerSpectralIndex; } -double TurbulentMagneticFieldGrid::getCorrelationLength() const { +double TurbulentMagneticField::getCorrelationLength() const { double r = lMin / lMax; double a = -powerSpectralIndex - 2; return lMax / 2 * (a - 1) / a * (1 - pow(r, a)) / (1 - pow(r, a - 1)); diff --git a/src/magneticField/magneticFieldGrid.cpp b/src/magneticField/magneticFieldGrid.cpp deleted file mode 100644 index c463a5f12..000000000 --- a/src/magneticField/magneticFieldGrid.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "mpc/magneticField/magneticFieldGrid.h" - -namespace mpc { - -void periodicClamp(double x, int n, int &lo, int &hi, double &fLo, - double &fHi) { - // closest lower and upper neighbour in a periodically continued grid - lo = ((int(x) % n) + n) % n; - hi = (lo + 1) % n; - fLo = x - floor(x); - fHi = 1 - fLo; -} - -MagneticFieldGrid::MagneticFieldGrid(Vector3d origin, size_t n, double spacing) : - origin(origin), samples(n), spacing(spacing) { - grid.resize(n); - for (int ix = 0; ix < n; ix++) { - grid[ix].resize(n); - for (int iy = 0; iy < n; iy++) { - grid[ix][iy].resize(n); - } - } -} - -void MagneticFieldGrid::updateSimulationVolume(const Vector3d &origin, - double size) { - this->origin = origin; - this->spacing = size / (samples - 1); -} - -Vector3d MagneticFieldGrid::getGridOrigin() const { - return origin; -} - -size_t MagneticFieldGrid::getGridSamples() const { - return samples; -} - -double MagneticFieldGrid::getGridSpacing() const { - return spacing; -} - -double MagneticFieldGrid::getGridSize() const { - return samples * spacing; -} - -Vector3d MagneticFieldGrid::getField(const Vector3d &position) const { - Vector3d r = (position - origin) / spacing; - int ix, iX, iy, iY, iz, iZ; - double fx, fX, fy, fY, fz, fZ; - periodicClamp(r.x, samples, ix, iX, fx, fX); - periodicClamp(r.y, samples, iy, iY, fy, fY); - periodicClamp(r.z, samples, iz, iZ, fz, fZ); - - // trilinear interpolation - // check: http://paulbourke.net/miscellaneous/interpolation/ - Vector3d b(0, 0, 0); - //V000 (1 - x) (1 - y) (1 - z) + - b += grid[ix][iy][iz] * fX * fY * fZ; - //V100 x (1 - y) (1 - z) + - b += grid[iX][iy][iz] * fx * fY * fZ; - //V010 (1 - x) y (1 - z) + - b += grid[ix][iY][iz] * fX * fy * fZ; - //V001 (1 - x) (1 - y) z + - b += grid[ix][iy][iZ] * fX * fY * fz; - //V101 x (1 - y) z + - b += grid[iX][iy][iZ] * fx * fY * fz; - //V011 (1 - x) y z + - b += grid[ix][iY][iZ] * fX * fy * fz; - //V110 x y (1 - z) + - b += grid[iX][iY][iz] * fx * fy * fZ; - //V111 x y z - b += grid[iX][iY][iZ] * fx * fy * fz; - - return b; -} - -} // namespace mpc diff --git a/src/main.cpp b/src/main.cpp index 4610dca9b..ada116f82 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,8 +7,8 @@ #include "mpc/module/PhotoPionProduction.h" #include "mpc/module/PhotoDisintegration.h" #include "mpc/module/NuclearDecay.h" -#include "mpc/magneticField/uniformMagneticField.h" -#include "mpc/magneticField/turbulentMagneticFieldGrid.h" +#include "mpc/magneticField/UniformMagneticField.h" +#include "mpc/magneticField/TurbulentMagneticField.h" using namespace mpc; @@ -16,8 +16,9 @@ int main(int argc, char **argv) { ModuleList modules; // propagation -------------------------------------------------------- - TurbulentMagneticFieldGrid *field = new TurbulentMagneticFieldGrid(Vector3d(0, 0, 0), 64, 1., 2., 8., 1e-12, -11. / 3.); - modules.add(new DeflectionCK(field)); + TurbulentMagneticField *bField = new TurbulentMagneticField(Vector3d(0, 0, 0), 64, 1.); + bField->initialize(2., 8., 1e-12, -11. / 3.); + modules.add(new DeflectionCK(bField)); // interactions ------------------------------------------------------- modules.add(new NuclearDecay()); diff --git a/test/python/testTurbulentDeflection.py b/test/python/testTurbulentDeflection.py index 58b86cacb..4f06eac5d 100644 --- a/test/python/testTurbulentDeflection.py +++ b/test/python/testTurbulentDeflection.py @@ -8,7 +8,7 @@ nP = range(75) # sampling points to plot # create turbulent field with B_RMS = 1 nG and 0.5 Mpc correlation length -field = TurbulentMagneticFieldGrid(Vector3d(0, 0, 0), 256, 0.05 * Mpc, 0.1 * Mpc, 2.2 * Mpc, 1*nG, -11/3.) +field = TurbulentMagneticField(Vector3d(0, 0, 0), 256, 0.05 * Mpc, 0.1 * Mpc, 2.2 * Mpc, 1*nG, -11/3.) propa = DeflectionCK(field) age = linspace(1, 150, nS) diff --git a/test/python/testTurbulentField.py b/test/python/testTurbulentField.py index dedf576bf..f3090d87d 100644 --- a/test/python/testTurbulentField.py +++ b/test/python/testTurbulentField.py @@ -82,7 +82,7 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): lMin, lMax = 2, 32 Brms = 1 alpha = -11./3 -field = TurbulentMagneticFieldGrid(Vector3d(0, 0, 0), n, 1, lMin, lMax, Brms, alpha) +field = TurbulentMagneticField(Vector3d(0, 0, 0), n, 1, lMin, lMax, Brms, alpha) Lc = field.getCorrelationLength() ### copy field to array diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index a26a455fd..c209ce0f6 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -1,6 +1,6 @@ -#include "mpc/magneticField/uniformMagneticField.h" -#include "mpc/magneticField/magneticFieldGrid.h" -#include "mpc/magneticField/turbulentMagneticFieldGrid.h" +#include "mpc/magneticField/UniformMagneticField.h" +#include "mpc/magneticField/MagneticFieldGrid.h" +#include "mpc/magneticField/TurbulentMagneticField.h" #include "mpc/Units.h" #include "gtest/gtest.h" @@ -21,13 +21,14 @@ TEST(testTurbulentMagneticFieldGrid, PeriodicBoundaries) { // B(x+a*n) = B(x) size_t n = 64; - TurbulentMagneticFieldGrid B(Vector3d(0, 0, 0), n, 1, 2, 8, 1, -11. / 3.); + TurbulentMagneticField bField(Vector3d(0, 0, 0), n, 1); + bField.initialize(2, 8, 1, -11. / 3.); Vector3d pos(1.1, 2.1, 3.1); - Vector3d b = B.getField(pos); - Vector3d b1 = B.getField(pos + Vector3d(n, 0, 0)); - Vector3d b2 = B.getField(pos + Vector3d(0, n, 0)); - Vector3d b3 = B.getField(pos + Vector3d(0, 0, n)); + Vector3d b = bField.getField(pos); + Vector3d b1 = bField.getField(pos + Vector3d(n, 0, 0)); + Vector3d b2 = bField.getField(pos + Vector3d(0, n, 0)); + Vector3d b3 = bField.getField(pos + Vector3d(0, 0, n)); EXPECT_FLOAT_EQ(b.x, b1.x); EXPECT_FLOAT_EQ(b.y, b1.y); @@ -46,17 +47,18 @@ TEST(testTurbulentMagneticFieldGrid, ZeroMean) { // = 0 size_t n = 64; - TurbulentMagneticFieldGrid B(Vector3d(0, 0, 0), n, 1, 2, 8, 1, -11. / 3.); + TurbulentMagneticField bField(Vector3d(0, 0, 0), n, 1); + bField.initialize(2, 8, 1, -11. / 3.); Vector3d b(0, 0, 0); for (unsigned int ix = 0; ix < n; ix++) for (unsigned int iy = 0; iy < n; iy++) for (unsigned int iz = 0; iz < n; iz++) - b += B.getField(Vector3d(ix, iy, iz)); + b += bField.getField(Vector3d(ix, iy, iz)); b /= n * n * n; - double precision = 1e-12; + double precision = 1e-7; EXPECT_NEAR(b.x, 0, precision); EXPECT_NEAR(b.y, 0, precision); EXPECT_NEAR(b.z, 0, precision); @@ -66,16 +68,17 @@ TEST(testTurbulentMagneticFieldGrid, Brms) { // = Brms^2 size_t n = 64; - TurbulentMagneticFieldGrid B(Vector3d(0, 0, 0), n, 1*Mpc, 2*Mpc, 8*Mpc, 1., -11. / 3.); + TurbulentMagneticField bField(Vector3d(0, 0, 0), n, 1); + bField.initialize(2, 8, 1, -11. / 3.); double brms = 0; for (unsigned int ix = 0; ix < n; ix++) for (unsigned int iy = 0; iy < n; iy++) for (unsigned int iz = 0; iz < n; iz++) - brms += B.getField(Vector3d(ix, iy, iz)*Mpc).mag2(); + brms += bField.getField(Vector3d(ix, iy, iz)).mag2(); brms = sqrt(brms / n / n / n); - double precision = 1e-12; + double precision = 1e-7; EXPECT_NEAR(brms, 1, precision); } diff --git a/test/testPropagation.cpp b/test/testPropagation.cpp index 7da559ab2..73b4b009a 100644 --- a/test/testPropagation.cpp +++ b/test/testPropagation.cpp @@ -1,7 +1,7 @@ #include "mpc/Candidate.h" #include "mpc/module/SimplePropagation.h" #include "mpc/module/DeflectionCK.h" -#include "mpc/magneticField/uniformMagneticField.h" +#include "mpc/magneticField/UniformMagneticField.h" #include "gtest/gtest.h" From c1ae765759f5871ecd6d9db49302c39ccf0e0ab6 Mon Sep 17 00:00:00 2001 From: geromueller Date: Fri, 4 May 2012 18:11:39 +0200 Subject: [PATCH 0081/1298] improve --- CMakeLists.txt | 1 + include/mpc/ModuleList.h | 21 +- include/mpc/SpatialPartitioning.h | 55 +++++ include/mpc/magneticField/sphMagneticField.h | 64 +++--- python/mpc.i | 4 + src/ModuleList.cpp | 36 +++- src/SpatialPartitioning.cpp | 215 +++++++++++++++++++ src/magneticField/sphMagneticField.cpp | 11 + 8 files changed, 366 insertions(+), 41 deletions(-) create mode 100644 include/mpc/SpatialPartitioning.h create mode 100644 src/SpatialPartitioning.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 623177562..7af09e0c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,6 +77,7 @@ add_library(mpc SHARED src/Clock.cpp src/Vector3.cpp src/ModuleList.cpp + src/SpatialPartitioning.cpp src/Module.cpp src/Candidate.cpp src/IO.cpp diff --git a/include/mpc/ModuleList.h b/include/mpc/ModuleList.h index 85885c17b..3e0b8f790 100644 --- a/include/mpc/ModuleList.h +++ b/include/mpc/ModuleList.h @@ -6,6 +6,8 @@ #include "mpc/Candidate.h" #include "mpc/Module.h" #include "mpc/Source.h" +#include "mpc/AssocVector.h" +#include "mpc/Referenced.h" namespace mpc { @@ -13,22 +15,27 @@ namespace mpc { @class ModuleList @brief List of modules */ -class ModuleList { - std::list > modules; - bool showProgress; +class ModuleList: public Referenced { public: - typedef std::list >::iterator iterator; - typedef std::list >::const_iterator const_iterator; + typedef std::list > module_list_t; + typedef std::vector > candidate_vector_t; ModuleList(); + virtual ~ModuleList(); void setShowProgress(bool show); void add(Module *module); - void process(Candidate *candidate); + virtual void process(Candidate *candidate); void run(Candidate *candidate, bool recursive); + void run(candidate_vector_t &candidates, bool recursive); void run(Source *source, size_t count, bool recursive); - const std::list > &getModules() const; + module_list_t &getModules(); + const module_list_t &getModules() const; + +private: + module_list_t modules; + bool showProgress; }; } // namespace mpc diff --git a/include/mpc/SpatialPartitioning.h b/include/mpc/SpatialPartitioning.h new file mode 100644 index 000000000..b838e3764 --- /dev/null +++ b/include/mpc/SpatialPartitioning.h @@ -0,0 +1,55 @@ +#ifndef MPC_SPATIAL_PARTITIONING_H +#define MPC_SPATIAL_PARTITIONING_H + +#include "mpc/ModuleList.h" +#include "mpc/Candidate.h" + +#include +#include + +namespace mpc { + +struct Count { + size_t count; + Count(); +// operator size_t(); + void operator +=(size_t v); +}; + +struct Index { + int x, y, z; + Index(); + Index(Vector3 v); + bool operator<(const Index &rhs) const; +}; + +class SpatialPartitioning: public Referenced { + +public: + + typedef std::vector > candidate_vector_t; + + SpatialPartitioning(ModuleList *moduleList); + + void run(candidate_vector_t &candidates, bool recursive); + void run(Source *source, size_t count, bool recursive); + + void setPartitionOrigin(const Vector3 &origin); + void setPartitionSize(double size); + void setCurrentPartition(const Vector3 &offset); + + void setVerbose(bool verbose); +private: + void run(Candidate *candidate, bool recursive, + Loki::AssocVector &partitions); + Vector3 partitionOrigin, currentPartition, currentPartitionMargin; + double partitionSize, partitionSizeMargin; + bool verbose; + ref_ptr moduleList; +}; + +} // namespace mpc + +std::ostream &operator<<(std::ostream &out, const mpc::Index &idx); + +#endif // MPC_SPATIAL_PARTITIONING_H diff --git a/include/mpc/magneticField/sphMagneticField.h b/include/mpc/magneticField/sphMagneticField.h index e86e83d1b..daf6f74b0 100644 --- a/include/mpc/magneticField/sphMagneticField.h +++ b/include/mpc/magneticField/sphMagneticField.h @@ -12,41 +12,43 @@ #include namespace gadget { - class DirectMagneticField; - class SampledMagneticField; +class DirectMagneticField; +class SampledMagneticField; } namespace mpc { - /** - @class SPHMagneticField - @brief Wrapper for gadget::DirectMagneticField - */ - class SPHMagneticField: public MagneticField { - gadget::DirectMagneticField field; - gadget::FileDatabase database; - public: - SPHMagneticField(Vector3 origin, double size, size_t gridSize, - const std::string filename); - Vector3 getField(const Vector3 &position) const; - void updateSimulationVolume(const Vector3 &origin, double size); - - }; - - /** - @class SPHMagneticFieldGrid - @brief Wrapper for gadget::SampledMagneticField - */ - class SPHMagneticFieldGrid: public MagneticField { - gadget::SampledMagneticField field; - gadget::FileDatabase database; - public: - SPHMagneticFieldGrid(Vector3 origin, double size, size_t samples, - const std::string filename); - Vector3 getField(const Vector3 &position) const; - void updateSimulationVolume(const Vector3 &origin, double size); - - }; +/** + @class SPHMagneticField + @brief Wrapper for gadget::DirectMagneticField + */ +class SPHMagneticField: public MagneticField { + gadget::DirectMagneticField field; + gadget::FileDatabase database; +public: + SPHMagneticField(Vector3 origin, double size, size_t gridSize, + const std::string filename); + SPHMagneticField(size_t gridSize, const std::string filename); + Vector3 getField(const Vector3 &position) const; + void updateSimulationVolume(const Vector3 &origin, double size); + +}; + +/** + @class SPHMagneticFieldGrid + @brief Wrapper for gadget::SampledMagneticField + */ +class SPHMagneticFieldGrid: public MagneticField { + gadget::SampledMagneticField field; + gadget::FileDatabase database; +public: + SPHMagneticFieldGrid(Vector3 origin, double size, size_t samples, + const std::string filename); + SPHMagneticFieldGrid(size_t samples, const std::string filename); + Vector3 getField(const Vector3 &position) const; + void updateSimulationVolume(const Vector3 &origin, double size); + +}; } // namespace mpc diff --git a/python/mpc.i b/python/mpc.i index 022844c3f..1e0da424e 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -52,6 +52,7 @@ #include "mpc/Nucleus.h" #include "mpc/Module.h" #include "mpc/ModuleList.h" +#include "mpc/SpatialPartitioning.h" #include "mpc/PhasePoint.h" #include "mpc/ExplicitRungeKutta.h" #include "mpc/Random.h" @@ -107,4 +108,7 @@ %include "mpc/module/PhotoDisintegration.h" %include "mpc/module/Redshift.h" %include "mpc/module/Tools.h" +%template(ModuleListRefPtr) mpc::ref_ptr; %include "mpc/ModuleList.h" +%template(SpatialPartitioningRefPtr) mpc::ref_ptr; +%include "mpc/SpatialPartitioning.h" diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 9d6dccaaf..340b56f2e 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -11,6 +11,10 @@ ModuleList::ModuleList() : } +ModuleList::~ModuleList() { + +} + void ModuleList::setShowProgress(bool show) { showProgress = show; } @@ -20,7 +24,7 @@ void ModuleList::add(Module *module) { } void ModuleList::process(Candidate *candidate) { - iterator iEntry = modules.begin(); + module_list_t::iterator iEntry = modules.begin(); while (iEntry != modules.end()) { ref_ptr &module = *iEntry; iEntry++; @@ -41,6 +45,28 @@ void ModuleList::run(Candidate *candidate, bool recursive) { } +void ModuleList::run(candidate_vector_t &candidates, bool recursive) { + size_t count = candidates.size(); + size_t cent = count / 100; + if (cent == 0) + cent = 1; + size_t pc = 0; +#pragma omp parallel for schedule(dynamic, 1000) + for (size_t i = 0; i < count; i++) { +#if _OPENMP + if (i == 0) { + std::cout << "Number of Threads: " << omp_get_num_threads() + << std::endl; + } +#endif + if (showProgress && (i % cent == 0)) { + std::cout << pc << "% - " << i << std::endl; + pc++; + } + run(candidates[i], recursive); + } +} + void ModuleList::run(Source *source, size_t count, bool recursive) { size_t cent = count / 100; if (cent == 0) @@ -65,14 +91,18 @@ void ModuleList::run(Source *source, size_t count, bool recursive) { } } -const std::list > &ModuleList::getModules() const { +ModuleList::module_list_t &ModuleList::getModules() { + return modules; +} + +const ModuleList::module_list_t &ModuleList::getModules() const { return modules; } } // namespace mpc std::ostream &operator<<(std::ostream &out, const mpc::ModuleList &list) { - mpc::ModuleList::const_iterator iEntry; + mpc::ModuleList::module_list_t::const_iterator iEntry; iEntry = list.getModules().begin(); while (iEntry != list.getModules().end()) { diff --git a/src/SpatialPartitioning.cpp b/src/SpatialPartitioning.cpp new file mode 100644 index 000000000..a6de3c4b2 --- /dev/null +++ b/src/SpatialPartitioning.cpp @@ -0,0 +1,215 @@ +#include "mpc/SpatialPartitioning.h" + +namespace mpc { + +Count::Count() : + count(0) { + +} + +//operator Count::size_t () { +// return count; +//} + +void Count::operator +=(size_t v) { + count += v; +} + +Index::Index() : + x(0), y(0), z(0) { + +} +Index::Index(Vector3 v) : + x(floor(v.x())), y(floor(v.y())), z(floor(v.z())) { + +} + +bool Index::operator<(const Index &rhs) const { + if (x < rhs.x) + return true; + else if (x > rhs.x) + return false; + + if (y < rhs.y) + return true; + else if (y > rhs.y) + return false; + + if (z < rhs.z) + return true; + else + return false; + +} + +SpatialPartitioning::SpatialPartitioning(ModuleList *moduleList) : + partitionOrigin(0, 0, 0), partitionSize(1 * Mpc), verbose(false), moduleList( + moduleList) { +} + +bool findActivePosition(Candidate *candidate, bool recursive, + Vector3 &position) { + if (candidate->isActive()) { + position = candidate->current.getPosition(); + return true; + } + + if (recursive) { + for (size_t i = 0; i < candidate->secondaries.size(); i++) { + if (findActivePosition(candidate->secondaries[i], recursive, + position)) + return true; + } + } + + return false; +} + +void SpatialPartitioning::run(candidate_vector_t &candidates, bool recursive) { + size_t count = candidates.size(); + Loki::AssocVector partitions; + + for (size_t i = 0; i < count; i++) { + if (candidates[i]->isActive()) { + Vector3 pos = candidates[i]->current.getPosition() + - partitionOrigin; + Index idx(pos / partitionSize); + partitions[idx] += 1; + } + } + + while (partitions.size() > 0) { + + Loki::AssocVector::iterator iPartition = + partitions.begin(); + Index nextPartition = iPartition->first; + size_t nextCount = iPartition->second.count; + for (iPartition = partitions.begin(); iPartition != partitions.end(); + iPartition++) { +// std::cout << "testing: " << iPartition->second << std::endl; + if (iPartition->second.count > nextCount) + nextPartition = iPartition->first; + } + + Vector3 o(nextPartition.x, nextPartition.y, nextPartition.z); + setCurrentPartition(o * partitionSize); + + // do the loop + partitions.clear(); +#pragma omp parallel shared(partitions) + { + Loki::AssocVector _partitions; +#pragma omp for schedule(dynamic, 1000) + for (size_t i = 0; i < count; i++) { + run(candidates[i], recursive, _partitions); + } + + Loki::AssocVector::iterator i; +#pragma omp critical + for (i = _partitions.begin(); i != _partitions.end(); i++) { +// std::cout << "cp "; +// std::cout << i->first.x << ", " << i->first.y << ", " +// << i->first.z; +// std::cout << " -> " << i->second << std::endl; + partitions[i->first] += i->second.count; + } + } + } +} + +void SpatialPartitioning::run(Candidate *candidate, bool recursive, + Loki::AssocVector &partitions) { + size_t active = 0; + + while (candidate->isActive()) { + Vector3 relPos = candidate->current.getPosition() - currentPartition; + double lo = std::min(relPos.x(), std::min(relPos.y(), relPos.z())); + double hi = std::max(relPos.x(), std::max(relPos.y(), relPos.z())); + if ((lo < 0.) || (hi > partitionSize)) { + break; + } + candidate->limitNextStep(lo + 0.1 * partitionSize); + candidate->limitNextStep(partitionSize - hi + 0.1 * partitionSize); + + moduleList->process(candidate); + } + + if (candidate->isActive()) { + Vector3 pos = candidate->current.getPosition() - partitionOrigin; + Index idx(pos / partitionSize); +// std::cout << pos / Mpc; +// std::cout << " -> "; +// std::cout << idx.x << ", " << idx.y << ", " << idx.z << std::endl; + partitions[idx] += 1; + } + +// propagate secondaries + if (recursive) { + for (size_t i = 0; i < candidate->secondaries.size(); i++) + run(candidate->secondaries[i], recursive, partitions); + } +} + +void SpatialPartitioning::run(Source *source, size_t count, bool recursive) { + candidate_vector_t candidates; + candidates.reserve(count); + for (size_t i = 0; i < count; i++) { + ParticleState state; + source->prepare(state); + ref_ptr candidate = new Candidate(state); + candidates.push_back(candidate); + } + + run(candidates, recursive); +} + +void SpatialPartitioning::setPartitionOrigin(const Vector3 &origin) { + partitionOrigin = origin; +} + +void SpatialPartitioning::setPartitionSize(double size) { + partitionSize = size; + partitionSizeMargin = size * 1.2; +} + +struct _UpdateSimulationVolume { + Vector3 currentPartition; + double partitionSize; + _UpdateSimulationVolume(Vector3 currentPartition, double partitionSize) : + currentPartition(currentPartition), partitionSize(partitionSize) { + + } + + void operator()(ref_ptr &module) { + SimulationVolumeDependentModule *svm = + dynamic_cast(module.get()); + if (svm) + svm->updateSimulationVolume(currentPartition, partitionSize); + } +}; + +void SpatialPartitioning::setCurrentPartition(const Vector3 &offset) { + currentPartition = offset; + currentPartitionMargin = offset + - Vector3(partitionSize * 0.1, partitionSize * 0.1, + partitionSize * 0.1); + if (verbose) { + std::cout << "mpc::SpatialPartitioningExecutor::setCurrentPartition -> " + << offset / Mpc << std::endl; + } + std::for_each(moduleList->getModules().begin(), + moduleList->getModules().end(), + _UpdateSimulationVolume(currentPartitionMargin, + partitionSizeMargin)); +} + +void SpatialPartitioning::setVerbose(bool verbose) { + this->verbose = verbose; +} + +} // namespace mpc + +std::ostream &operator<<(std::ostream &out, const mpc::Index &idx) { + out << idx.x << ", " << idx.y << ", " << idx.z; + return out; +} diff --git a/src/magneticField/sphMagneticField.cpp b/src/magneticField/sphMagneticField.cpp index 2b5ae16b2..a0975d668 100644 --- a/src/magneticField/sphMagneticField.cpp +++ b/src/magneticField/sphMagneticField.cpp @@ -14,6 +14,11 @@ SPHMagneticField::SPHMagneticField(Vector3 origin, double size, size_t gridSize, field.init(v, size / kpc, database); } +SPHMagneticField::SPHMagneticField(size_t gridSize, const std::string filename) : + field(gridSize) { + database.open(filename); +} + Vector3 SPHMagneticField::getField(const Vector3 &position) const { gadget::Vector3f r = gadget::Vector3f(position.x(), position.y(), position.z()); @@ -38,6 +43,12 @@ SPHMagneticFieldGrid::SPHMagneticFieldGrid(Vector3 origin, double size, field.init(v, size / kpc, database); } +SPHMagneticFieldGrid::SPHMagneticFieldGrid(size_t samples, + const std::string filename) : + field(samples) { + database.open(filename); +} + Vector3 SPHMagneticFieldGrid::getField(const Vector3 &position) const { gadget::Vector3f r = gadget::Vector3f(position.x(), position.y(), position.z()); From 37ee468db162a640470734c4a6bdfce893ffe1eb Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 4 May 2012 23:20:39 +0200 Subject: [PATCH 0082/1298] add missing files --- include/mpc/Vector3.h | 270 ++++++++++++++++++ .../magneticField/SPHTurbulentMagneticField.h | 19 ++ .../SPHTurbulentMagneticField.cpp | 12 + 3 files changed, 301 insertions(+) create mode 100644 include/mpc/Vector3.h create mode 100644 include/mpc/magneticField/SPHTurbulentMagneticField.h create mode 100644 src/magneticField/SPHTurbulentMagneticField.cpp diff --git a/include/mpc/Vector3.h b/include/mpc/Vector3.h new file mode 100644 index 000000000..fc0c90ade --- /dev/null +++ b/include/mpc/Vector3.h @@ -0,0 +1,270 @@ +#ifndef _MPC_VECTOR3_H_ +#define _MPC_VECTOR3_H_ + +#include +#include +#include +#include + +namespace mpc { + +template +class Vector3 { +public: + T x, y, z; + + Vector3() : + x(0), y(0), z(0) { + } + + template + Vector3(const Vector3 &v) : + x(v.x), y(v.y), z(v.z) { + } + + explicit Vector3(const double *v) : + x(v[0]), y(v[1]), z(v[2]) { + } + + explicit Vector3(const float *v) : + x(v[0]), y(v[1]), z(v[2]) { + } + + explicit Vector3(const T &X, const T &Y, const T &Z) : + x(X), y(Y), z(Z) { + } + + explicit Vector3(T t) : + x(t), y(t), z(t) { + } + + bool operator <(const Vector3 &v) const { + if (x > v.x) + return false; + else if (x < v.x) + return true; + if (y > v.y) + return false; + else if (y < v.y) + return true; + if (z >= v.z) + return false; + else + return true; + } + + bool operator ==(const Vector3 &v) const { + if (x != v.x) + return false; + if (y != v.y) + return false; + if (z != v.z) + return false; + return true; + } + + Vector3 operator -(const Vector3 &v) const { + return Vector3(x - v.x, y - v.y, z - v.z); + } + + Vector3 operator +(const Vector3 &v) const { + return Vector3(x + v.x, y + v.y, z + v.z); + } + + Vector3 operator *(const Vector3 &v) const { + return Vector3(x * v.x, y * v.y, z * v.z); + } + + Vector3 operator *(const T &v) const { + return Vector3(x * v, y * v, z * v); + } + + Vector3 operator /(const T &f) const { + return Vector3(x / f, y / f, z / f); + } + + Vector3 &operator /=(const T &f) { + x /= f; + y /= f; + z /= f; + return *this; + } + + Vector3 operator %(const T &f) const { + return Vector3(x % f, y % f, z % f); + } + + Vector3 &operator %=(const T &f) { + x %= f; + y %= f; + z %= f; + return *this; + } + + Vector3 &operator *=(const T &f) { + x *= f; + y *= f; + z *= f; + return *this; + } + + Vector3 &operator +=(const Vector3 &v) { + x += v.x; + y += v.y; + z += v.z; + return *this; + } + + Vector3 &operator -=(const Vector3 &v) { + x -= v.x; + y -= v.y; + z -= v.z; + return *this; + } + + Vector3 &operator =(const Vector3 &v) { + x = v.x; + y = v.y; + z = v.z; + return *this; + } + + void clamp(T lower, T upper) { + x = std::max(lower, std::min(x, upper)); + y = std::max(lower, std::min(y, upper)); + z = std::max(lower, std::min(z, upper)); + } + + T mag() const { + return std::sqrt(x * x + y * y + z * z); + } + + T mag2() { + return (x * x + y * y + z * z); + } + + T dot(const Vector3 & p) const { + return x * p.x + y * p.y + z * p.z; + } + + Vector3 cross(const Vector3 & p) const { + return Vector3(y * p.z - p.y * z, z * p.x - p.z * x, + x * p.y - p.x * y); + } + + Vector3 floor() const { + return Vector3(std::floor(x), std::floor(y), std::floor(z)); + } + + Vector3 ceil() const { + return Vector3(std::ceil(x), std::ceil(y), std::ceil(z)); + } + + T phi() const { + T eps = std::numeric_limits::min(); + if (abs(x) < eps && abs(y) < eps) + return 0.0; + else + return std::atan2(y, x); + } + + T theta() const { + T eps = std::numeric_limits::min(); + if (abs(x) < eps && abs(y) < eps && abs(z) < eps) + return 0.0; + else + return std::atan2(sqrt(x * x + y * y), z); + } + + T angleTo(const Vector3 &v) const { + T cosdistance = this->dot(v) / this->mag() / v.mag(); + // In some directions cosdistance is > 1 on some compilers + // This ensures that the correct result is returned + return (cosdistance >= 1.) ? + 0 : ((cosdistance <= -1.) ? M_PI : acos(cosdistance)); + } + + bool isParallelTo(const Vector3 &v, T maxAngle) const { + T angle = this->angleTo(v); + return angle < maxAngle; + } + + T distanceTo(const Vector3 &point) const { + Vector3 d = *this - point; + return d.mag(); + } + + void set(const T x, const T y, const T z) { + this->x = x; + this->y = y; + this->z = z; + } + + void setLower(const Vector3 &v) { + if (v.x < x) + x = v.x; + if (v.y < y) + y = v.y; + if (v.z < z) + z = v.z; + } + + void setUpper(const Vector3 &v) { + if (v.x > x) + x = v.x; + if (v.y > y) + y = v.y; + if (v.z > z) + z = v.z; + } +}; + +template<> +inline Vector3 Vector3::operator %(const float &f) const { + return Vector3(fmod(x, f), fmod(y, f), fmod(z, f)); +} + +template<> +inline Vector3 &Vector3::operator %=(const float &f) { + x = fmod(x, f); + y = fmod(y, f); + z = fmod(z, f); + return *this; +} + +template<> +inline Vector3 Vector3::operator %(const double &f) const { + return Vector3(fmod(x, f), fmod(y, f), fmod(z, f)); +} + +template<> +inline Vector3 &Vector3::operator %=(const double &f) { + x = fmod(x, f); + y = fmod(y, f); + z = fmod(z, f); + return *this; +} + +template +inline std::ostream &operator <<(std::ostream &out, const Vector3 &v) { + out << v.x << " " << v.y << " " << v.z; + return out; +} + +template +inline std::istream &operator >>(std::istream &in, Vector3 &v) { + in >> v.x >> v.y >> v.z; + return in; +} + +template +Vector3 operator *(T f, const Vector3 &v) { + return Vector3(v.x * f, v.y * f, v.z * f); +} + +typedef Vector3 Vector3d; +typedef Vector3 Vector3f; + +} // namespace mpc + +#endif /* _MPC_VECTOR3_H_ */ diff --git a/include/mpc/magneticField/SPHTurbulentMagneticField.h b/include/mpc/magneticField/SPHTurbulentMagneticField.h new file mode 100644 index 000000000..6e9755d45 --- /dev/null +++ b/include/mpc/magneticField/SPHTurbulentMagneticField.h @@ -0,0 +1,19 @@ +#ifndef MPC_SPHTURBULENTMAGNETICFIELD_H_ +#define MPC_SPHTURBULENTMAGNETICFIELD_H_ + +#include "mpc/magneticField/TurbulentMagneticField.h" + +namespace mpc { + +/** + @class SPHTurbulentMagneticField + @brief Random turbulent magnetic field on a cubic grid modulated with large scale structure. + */ +class SPHTurbulentMagneticField: public TurbulentMagneticField { +public: + void initialize(const std::string filename); +}; + +} // namespace mpc + +#endif /* MPC_SPHTURBULENTMAGNETICFIELD_H_ */ diff --git a/src/magneticField/SPHTurbulentMagneticField.cpp b/src/magneticField/SPHTurbulentMagneticField.cpp new file mode 100644 index 000000000..12f0783cf --- /dev/null +++ b/src/magneticField/SPHTurbulentMagneticField.cpp @@ -0,0 +1,12 @@ +#include "mpc/magneticField/SPHTurbulentMagneticField.h" +#include "mpc/magneticField/SPHMagneticField.h" + +namespace mpc { + +void modulate(const std::string filename) { + // create sph field + // modulate turbulent field + // destroy sph field, or let it go out of scope +} + +} // namespace mpc From c8c5191d71f791e50820259fec22be713e0f5bef Mon Sep 17 00:00:00 2001 From: geromueller Date: Sat, 5 May 2012 10:00:40 +0200 Subject: [PATCH 0083/1298] fix merge --- include/mpc/Module.h | 2 +- include/mpc/SpatialPartitioning.h | 8 +++--- include/mpc/Vector3.h | 4 +-- include/mpc/magneticField/SPHMagneticField.h | 2 +- python/mpc.i | 30 +++++++++++--------- src/SpatialPartitioning.cpp | 28 +++++++++--------- src/magneticField/SPHMagneticField.cpp | 22 +++++++------- 7 files changed, 49 insertions(+), 47 deletions(-) diff --git a/include/mpc/Module.h b/include/mpc/Module.h index 5fa4bcede..1c8aa9852 100644 --- a/include/mpc/Module.h +++ b/include/mpc/Module.h @@ -33,7 +33,7 @@ class Module: public Referenced { class SimulationVolumeDependentModule: public Module { public: - virtual void updateSimulationVolume(const Vector3 &origin, double size) = 0; + virtual void updateSimulationVolume(const Vector3d &origin, double size) = 0; }; } // namespace mpc diff --git a/include/mpc/SpatialPartitioning.h b/include/mpc/SpatialPartitioning.h index b838e3764..a3758f26c 100644 --- a/include/mpc/SpatialPartitioning.h +++ b/include/mpc/SpatialPartitioning.h @@ -19,7 +19,7 @@ struct Count { struct Index { int x, y, z; Index(); - Index(Vector3 v); + Index(Vector3d v); bool operator<(const Index &rhs) const; }; @@ -34,15 +34,15 @@ class SpatialPartitioning: public Referenced { void run(candidate_vector_t &candidates, bool recursive); void run(Source *source, size_t count, bool recursive); - void setPartitionOrigin(const Vector3 &origin); + void setPartitionOrigin(const Vector3d &origin); void setPartitionSize(double size); - void setCurrentPartition(const Vector3 &offset); + void setCurrentPartition(const Vector3d &offset); void setVerbose(bool verbose); private: void run(Candidate *candidate, bool recursive, Loki::AssocVector &partitions); - Vector3 partitionOrigin, currentPartition, currentPartitionMargin; + Vector3d partitionOrigin, currentPartition, currentPartitionMargin; double partitionSize, partitionSizeMargin; bool verbose; ref_ptr moduleList; diff --git a/include/mpc/Vector3.h b/include/mpc/Vector3.h index fc0c90ade..c8632764b 100644 --- a/include/mpc/Vector3.h +++ b/include/mpc/Vector3.h @@ -162,7 +162,7 @@ class Vector3 { T phi() const { T eps = std::numeric_limits::min(); - if (abs(x) < eps && abs(y) < eps) + if (fabs(x) < eps && fabs(y) < eps) return 0.0; else return std::atan2(y, x); @@ -170,7 +170,7 @@ class Vector3 { T theta() const { T eps = std::numeric_limits::min(); - if (abs(x) < eps && abs(y) < eps && abs(z) < eps) + if (fabs(x) < eps && fabs(y) < eps && fabs(z) < eps) return 0.0; else return std::atan2(sqrt(x * x + y * y), z); diff --git a/include/mpc/magneticField/SPHMagneticField.h b/include/mpc/magneticField/SPHMagneticField.h index cfd412bcc..7dff725a6 100644 --- a/include/mpc/magneticField/SPHMagneticField.h +++ b/include/mpc/magneticField/SPHMagneticField.h @@ -3,7 +3,7 @@ #ifdef MPC_HAVE_GADGET -#include "mpc/magneticField/magneticFieldGrid.h" +#include "mpc/magneticField/MagneticFieldGrid.h" #include "gadget/Database.h" #include "gadget/MagneticField.h" diff --git a/python/mpc.i b/python/mpc.i index 1e0da424e..69c1fbc46 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -11,7 +11,6 @@ %include std_list.i %include stdint.i %include std_container.i - %include "exception.i" %exception { @@ -40,11 +39,11 @@ #include "mpc/module/DeflectionCK.h" #include "mpc/module/Tools.h" -#include "mpc/magneticField/magneticField.h" -#include "mpc/magneticField/uniformMagneticField.h" -#include "mpc/magneticField/magneticFieldGrid.h" -#include "mpc/magneticField/turbulentMagneticFieldGrid.h" -#include "mpc/magneticField/sphMagneticField.h" +#include "mpc/magneticField/MagneticField.h" +#include "mpc/magneticField/UniformMagneticField.h" +#include "mpc/magneticField/MagneticFieldGrid.h" +#include "mpc/magneticField/TurbulentMagneticField.h" +#include "mpc/magneticField/SPHMagneticField.h" #include "mpc/Referenced.h" #include "mpc/Candidate.h" @@ -68,13 +67,17 @@ %include "mpc/Referenced.h" %include "mpc/Units.h" %include "mpc/Nucleus.h" +%include "mpc/Common.h" + %include "mpc/Vector3.h" +%template(Vector3d) mpc::Vector3; +%template(Vector3f) mpc::Vector3; + %include "mpc/Random.h" %include "mpc/ParticleState.h" -// %feature("director") mpc::Source; + %template(SourceRefPtr) mpc::ref_ptr; %include "mpc/Source.h" -%include "mpc/Common.h" %template(CandidateVector) std::vector< mpc::ref_ptr >; %template(CandidateRefPtr) mpc::ref_ptr; @@ -83,16 +86,15 @@ %template(ModuleRefPtr) mpc::ref_ptr; %template(stdModuleVector) std::vector< mpc::ref_ptr >; %template(stdModuleList) std::list< mpc::ref_ptr >; -// %feature("director") mpc::Module; %include "mpc/Module.h" %template(stdMagneticFieldVector) std::vector< mpc::ref_ptr >; %template(MagneticFieldRefPtr) mpc::ref_ptr; -%include "mpc/magneticField/magneticField.h" -%include "mpc/magneticField/magneticFieldGrid.h" -%include "mpc/magneticField/uniformMagneticField.h" -%include "mpc/magneticField/sphMagneticField.h" -%include "mpc/magneticField/turbulentMagneticFieldGrid.h" +%include "mpc/magneticField/MagneticField.h" +%include "mpc/magneticField/MagneticFieldGrid.h" +%include "mpc/magneticField/UniformMagneticField.h" +%include "mpc/magneticField/SPHMagneticField.h" +%include "mpc/magneticField/TurbulentMagneticField.h" %include "mpc/ExplicitRungeKutta.h" %include "mpc/PhasePoint.h" diff --git a/src/SpatialPartitioning.cpp b/src/SpatialPartitioning.cpp index a6de3c4b2..82df32d84 100644 --- a/src/SpatialPartitioning.cpp +++ b/src/SpatialPartitioning.cpp @@ -19,8 +19,8 @@ Index::Index() : x(0), y(0), z(0) { } -Index::Index(Vector3 v) : - x(floor(v.x())), y(floor(v.y())), z(floor(v.z())) { +Index::Index(Vector3d v) : + x(floor(v.x)), y(floor(v.y)), z(floor(v.z)) { } @@ -48,7 +48,7 @@ SpatialPartitioning::SpatialPartitioning(ModuleList *moduleList) : } bool findActivePosition(Candidate *candidate, bool recursive, - Vector3 &position) { + Vector3d &position) { if (candidate->isActive()) { position = candidate->current.getPosition(); return true; @@ -71,7 +71,7 @@ void SpatialPartitioning::run(candidate_vector_t &candidates, bool recursive) { for (size_t i = 0; i < count; i++) { if (candidates[i]->isActive()) { - Vector3 pos = candidates[i]->current.getPosition() + Vector3d pos = candidates[i]->current.getPosition() - partitionOrigin; Index idx(pos / partitionSize); partitions[idx] += 1; @@ -91,7 +91,7 @@ void SpatialPartitioning::run(candidate_vector_t &candidates, bool recursive) { nextPartition = iPartition->first; } - Vector3 o(nextPartition.x, nextPartition.y, nextPartition.z); + Vector3d o(nextPartition.x, nextPartition.y, nextPartition.z); setCurrentPartition(o * partitionSize); // do the loop @@ -122,9 +122,9 @@ void SpatialPartitioning::run(Candidate *candidate, bool recursive, size_t active = 0; while (candidate->isActive()) { - Vector3 relPos = candidate->current.getPosition() - currentPartition; - double lo = std::min(relPos.x(), std::min(relPos.y(), relPos.z())); - double hi = std::max(relPos.x(), std::max(relPos.y(), relPos.z())); + Vector3d relPos = candidate->current.getPosition() - currentPartition; + double lo = std::min(relPos.x, std::min(relPos.y, relPos.z)); + double hi = std::max(relPos.x, std::max(relPos.y, relPos.z)); if ((lo < 0.) || (hi > partitionSize)) { break; } @@ -135,7 +135,7 @@ void SpatialPartitioning::run(Candidate *candidate, bool recursive, } if (candidate->isActive()) { - Vector3 pos = candidate->current.getPosition() - partitionOrigin; + Vector3d pos = candidate->current.getPosition() - partitionOrigin; Index idx(pos / partitionSize); // std::cout << pos / Mpc; // std::cout << " -> "; @@ -163,7 +163,7 @@ void SpatialPartitioning::run(Source *source, size_t count, bool recursive) { run(candidates, recursive); } -void SpatialPartitioning::setPartitionOrigin(const Vector3 &origin) { +void SpatialPartitioning::setPartitionOrigin(const Vector3d &origin) { partitionOrigin = origin; } @@ -173,9 +173,9 @@ void SpatialPartitioning::setPartitionSize(double size) { } struct _UpdateSimulationVolume { - Vector3 currentPartition; + Vector3d currentPartition; double partitionSize; - _UpdateSimulationVolume(Vector3 currentPartition, double partitionSize) : + _UpdateSimulationVolume(Vector3d currentPartition, double partitionSize) : currentPartition(currentPartition), partitionSize(partitionSize) { } @@ -188,10 +188,10 @@ struct _UpdateSimulationVolume { } }; -void SpatialPartitioning::setCurrentPartition(const Vector3 &offset) { +void SpatialPartitioning::setCurrentPartition(const Vector3d &offset) { currentPartition = offset; currentPartitionMargin = offset - - Vector3(partitionSize * 0.1, partitionSize * 0.1, + - Vector3d(partitionSize * 0.1, partitionSize * 0.1, partitionSize * 0.1); if (verbose) { std::cout << "mpc::SpatialPartitioningExecutor::setCurrentPartition -> " diff --git a/src/magneticField/SPHMagneticField.cpp b/src/magneticField/SPHMagneticField.cpp index 747c87d10..fad9da3ca 100644 --- a/src/magneticField/SPHMagneticField.cpp +++ b/src/magneticField/SPHMagneticField.cpp @@ -1,4 +1,4 @@ -#include "mpc/magneticField/sphMagneticField.h" +#include "mpc/magneticField/SPHMagneticField.h" #include "mpc/Units.h" #include "kiss/logger.h" @@ -9,7 +9,7 @@ SPHMagneticField::SPHMagneticField(Vector3d origin, double size, size_t gridSize const std::string filename) : field(gridSize) { database.open(filename); - gadget::Vector3df v = gadget::Vector3f(origin.x(), origin.y(), origin.z()) + gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; field.init(v, size / kpc, database); } @@ -20,16 +20,16 @@ SPHMagneticField::SPHMagneticField(size_t gridSize, const std::string filename) } Vector3d SPHMagneticField::getField(const Vector3d &position) const { - gadget::Vector3df r = gadget::Vector3df(position.x(), position.y(), - position.z()); - gadget::Vector3df b = field.getField(r / kpc); + gadget::Vector3f r = gadget::Vector3f(position.x, position.y, + position.z); + gadget::Vector3f b = field.getField(r / kpc); Vector3d bField = Vector3d(b.x, b.y, b.z) * gauss; return bField; } void SPHMagneticField::updateSimulationVolume(const Vector3d &origin, double size) { - gadget::Vector3df v = gadget::Vector3f(origin.x(), origin.y(), origin.z()) + gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; field.init(v, size / kpc, database); } @@ -38,7 +38,7 @@ SPHMagneticFieldGrid::SPHMagneticFieldGrid(Vector3d origin, double size, size_t samples, const std::string filename) : field(samples) { database.open(filename); - gadget::Vector3df v = gadget::Vector3f(origin.x(), origin.y(), origin.z()) + gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; field.init(v, size / kpc, database); } @@ -50,16 +50,16 @@ SPHMagneticFieldGrid::SPHMagneticFieldGrid(size_t samples, } Vector3d SPHMagneticFieldGrid::getField(const Vector3d &position) const { - gadget::Vector3df r = gadget::Vector3df(position.x(), position.y(), - position.z()); - gadget::Vector3df b = field.getField(r / kpc); + gadget::Vector3f r = gadget::Vector3f(position.x, position.y, + position.z); + gadget::Vector3f b = field.getField(r / kpc); Vector3d bField = Vector3d(b.x, b.y, b.z) * gauss; return bField; } void SPHMagneticFieldGrid::updateSimulationVolume(const Vector3d &origin, double size) { - gadget::Vector3df v = gadget::Vector3f(origin.x(), origin.y(), origin.z()) + gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; field.init(v, size / kpc, database); } From a68742c3c80f6e3da7162b81595a640e6a6f07f3 Mon Sep 17 00:00:00 2001 From: geromueller Date: Sat, 5 May 2012 22:46:22 +0200 Subject: [PATCH 0084/1298] cleanup SpatialPartitioning, add margin and caching --- include/mpc/SpatialPartitioning.h | 5 +- include/mpc/magneticField/SPHMagneticField.h | 6 ++- src/SpatialPartitioning.cpp | 38 +++++++------ src/magneticField/SPHMagneticField.cpp | 56 ++++++++++++++------ 4 files changed, 68 insertions(+), 37 deletions(-) diff --git a/include/mpc/SpatialPartitioning.h b/include/mpc/SpatialPartitioning.h index a3758f26c..129ca0385 100644 --- a/include/mpc/SpatialPartitioning.h +++ b/include/mpc/SpatialPartitioning.h @@ -37,13 +37,14 @@ class SpatialPartitioning: public Referenced { void setPartitionOrigin(const Vector3d &origin); void setPartitionSize(double size); void setCurrentPartition(const Vector3d &offset); + void setPartitionMargin(double margin); void setVerbose(bool verbose); private: void run(Candidate *candidate, bool recursive, Loki::AssocVector &partitions); - Vector3d partitionOrigin, currentPartition, currentPartitionMargin; - double partitionSize, partitionSizeMargin; + Vector3d partitionOrigin, currentPartition; + double partitionSize, partitionMargin; bool verbose; ref_ptr moduleList; }; diff --git a/include/mpc/magneticField/SPHMagneticField.h b/include/mpc/magneticField/SPHMagneticField.h index 7dff725a6..b0a5359ea 100644 --- a/include/mpc/magneticField/SPHMagneticField.h +++ b/include/mpc/magneticField/SPHMagneticField.h @@ -39,15 +39,19 @@ class SPHMagneticField: public MagneticField { @brief Wrapper for gadget::SampledMagneticField */ class SPHMagneticFieldGrid: public MagneticField { + size_t samples; gadget::SampledMagneticField field; gadget::FileDatabase database; + std::string cachePrefix; + bool cacheEnabled; public: SPHMagneticFieldGrid(Vector3d origin, double size, size_t samples, const std::string filename); SPHMagneticFieldGrid(size_t samples, const std::string filename); Vector3d getField(const Vector3d &position) const; void updateSimulationVolume(const Vector3d &origin, double size); - + void setCachePrefix(const std::string &prefix); + void setCacheEnabled(bool enabled ); }; } // namespace mpc diff --git a/src/SpatialPartitioning.cpp b/src/SpatialPartitioning.cpp index 82df32d84..ecd883ece 100644 --- a/src/SpatialPartitioning.cpp +++ b/src/SpatialPartitioning.cpp @@ -43,8 +43,8 @@ bool Index::operator<(const Index &rhs) const { } SpatialPartitioning::SpatialPartitioning(ModuleList *moduleList) : - partitionOrigin(0, 0, 0), partitionSize(1 * Mpc), verbose(false), moduleList( - moduleList) { + partitionOrigin(0, 0, 0), partitionSize(10 * Mpc), partitionMargin( + 1 * Mpc), verbose(false), moduleList(moduleList) { } bool findActivePosition(Candidate *candidate, bool recursive, @@ -86,7 +86,6 @@ void SpatialPartitioning::run(candidate_vector_t &candidates, bool recursive) { size_t nextCount = iPartition->second.count; for (iPartition = partitions.begin(); iPartition != partitions.end(); iPartition++) { -// std::cout << "testing: " << iPartition->second << std::endl; if (iPartition->second.count > nextCount) nextPartition = iPartition->first; } @@ -96,21 +95,23 @@ void SpatialPartitioning::run(candidate_vector_t &candidates, bool recursive) { // do the loop partitions.clear(); -#pragma omp parallel shared(partitions) + size_t cent = std::max(1ul, count / 100), pc = 0; + +#pragma omp parallel shared(partitions, pc) { Loki::AssocVector _partitions; #pragma omp for schedule(dynamic, 1000) for (size_t i = 0; i < count; i++) { + if (verbose && (i % cent == 0)) { + std::cout << pc << "% - " << i << std::endl; + pc++; + } run(candidates[i], recursive, _partitions); } Loki::AssocVector::iterator i; #pragma omp critical for (i = _partitions.begin(); i != _partitions.end(); i++) { -// std::cout << "cp "; -// std::cout << i->first.x << ", " << i->first.y << ", " -// << i->first.z; -// std::cout << " -> " << i->second << std::endl; partitions[i->first] += i->second.count; } } @@ -128,8 +129,8 @@ void SpatialPartitioning::run(Candidate *candidate, bool recursive, if ((lo < 0.) || (hi > partitionSize)) { break; } - candidate->limitNextStep(lo + 0.1 * partitionSize); - candidate->limitNextStep(partitionSize - hi + 0.1 * partitionSize); + candidate->limitNextStep(lo + partitionMargin); + candidate->limitNextStep(partitionSize - hi + partitionMargin); moduleList->process(candidate); } @@ -137,9 +138,6 @@ void SpatialPartitioning::run(Candidate *candidate, bool recursive, if (candidate->isActive()) { Vector3d pos = candidate->current.getPosition() - partitionOrigin; Index idx(pos / partitionSize); -// std::cout << pos / Mpc; -// std::cout << " -> "; -// std::cout << idx.x << ", " << idx.y << ", " << idx.z << std::endl; partitions[idx] += 1; } @@ -169,7 +167,11 @@ void SpatialPartitioning::setPartitionOrigin(const Vector3d &origin) { void SpatialPartitioning::setPartitionSize(double size) { partitionSize = size; - partitionSizeMargin = size * 1.2; +} + +void SpatialPartitioning::setPartitionMargin(double margin) { + partitionMargin = margin; + } struct _UpdateSimulationVolume { @@ -190,13 +192,15 @@ struct _UpdateSimulationVolume { void SpatialPartitioning::setCurrentPartition(const Vector3d &offset) { currentPartition = offset; - currentPartitionMargin = offset - - Vector3d(partitionSize * 0.1, partitionSize * 0.1, - partitionSize * 0.1); if (verbose) { std::cout << "mpc::SpatialPartitioningExecutor::setCurrentPartition -> " << offset / Mpc << std::endl; } + + Vector3d currentPartitionMargin = offset + - Vector3d(partitionMargin, partitionMargin, partitionMargin); + double partitionSizeMargin = partitionSize + 2 * partitionMargin; + std::for_each(moduleList->getModules().begin(), moduleList->getModules().end(), _UpdateSimulationVolume(currentPartitionMargin, diff --git a/src/magneticField/SPHMagneticField.cpp b/src/magneticField/SPHMagneticField.cpp index fad9da3ca..0c809a025 100644 --- a/src/magneticField/SPHMagneticField.cpp +++ b/src/magneticField/SPHMagneticField.cpp @@ -5,12 +5,11 @@ namespace mpc { -SPHMagneticField::SPHMagneticField(Vector3d origin, double size, size_t gridSize, - const std::string filename) : +SPHMagneticField::SPHMagneticField(Vector3d origin, double size, + size_t gridSize, const std::string filename) : field(gridSize) { database.open(filename); - gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) - / kpc; + gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; field.init(v, size / kpc, database); } @@ -20,8 +19,7 @@ SPHMagneticField::SPHMagneticField(size_t gridSize, const std::string filename) } Vector3d SPHMagneticField::getField(const Vector3d &position) const { - gadget::Vector3f r = gadget::Vector3f(position.x, position.y, - position.z); + gadget::Vector3f r = gadget::Vector3f(position.x, position.y, position.z); gadget::Vector3f b = field.getField(r / kpc); Vector3d bField = Vector3d(b.x, b.y, b.z) * gauss; return bField; @@ -29,29 +27,26 @@ Vector3d SPHMagneticField::getField(const Vector3d &position) const { void SPHMagneticField::updateSimulationVolume(const Vector3d &origin, double size) { - gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) - / kpc; + gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; field.init(v, size / kpc, database); } SPHMagneticFieldGrid::SPHMagneticFieldGrid(Vector3d origin, double size, size_t samples, const std::string filename) : - field(samples) { + samples(samples), field(samples), cacheEnabled(false) { database.open(filename); - gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) - / kpc; + gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; field.init(v, size / kpc, database); } SPHMagneticFieldGrid::SPHMagneticFieldGrid(size_t samples, const std::string filename) : - field(samples) { + samples(samples), field(samples) { database.open(filename); } Vector3d SPHMagneticFieldGrid::getField(const Vector3d &position) const { - gadget::Vector3f r = gadget::Vector3f(position.x, position.y, - position.z); + gadget::Vector3f r = gadget::Vector3f(position.x, position.y, position.z); gadget::Vector3f b = field.getField(r / kpc); Vector3d bField = Vector3d(b.x, b.y, b.z) * gauss; return bField; @@ -59,9 +54,36 @@ Vector3d SPHMagneticFieldGrid::getField(const Vector3d &position) const { void SPHMagneticFieldGrid::updateSimulationVolume(const Vector3d &origin, double size) { - gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) - / kpc; - field.init(v, size / kpc, database); + gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; + float s = size / kpc; + if (cacheEnabled) { + std::stringstream path; + path << cachePrefix << samples << "_" << s << "_" << v.x << "_" << v.y + << "_" << v.z << ".cache"; + std::string filename = path.str(); + std::ifstream infile(filename.c_str()); + if (infile) { + std::cout << "load cache file " << filename << std::endl; + field.init(v, s); + field.restore(filename); + } else { + field.init(v, s, database); + path << "." << time(NULL) << clock(); + std::string filename_tmp = path.str(); + field.dump(filename_tmp); + rename(filename_tmp.c_str(), filename.c_str()); + } + } else { + field.init(v, s, database); + } +} + +void SPHMagneticFieldGrid::setCachePrefix(const std::string &prefix) { + cachePrefix = prefix; +} + +void SPHMagneticFieldGrid::setCacheEnabled(bool enabled) { + cacheEnabled = enabled; } } // namespace mpc From 98b8471c1cb5f3b0c421ccaa2f2f983eef907c07 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sun, 6 May 2012 16:41:34 +0200 Subject: [PATCH 0085/1298] improve interaction tests --- src/module/NuclearDecay.cpp | 2 + test/testInteraction.cpp | 302 ++++++++++++++++++++++-------------- 2 files changed, 184 insertions(+), 120 deletions(-) diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index 61bca4dd2..32b6e259d 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -111,9 +111,11 @@ void NuclearDecay::betaDecay(Candidate *candidate, bool isBetaPlus) const { int A = candidate->current.getMassNumber(); double mass = candidate->current.getMass(); + // beta- decay int electronId = 11; // electron int neutrinoId = -12; // anti-electron neutrino int dZ = 1; + // beta+ decay if (isBetaPlus) { electronId = -11; // positron neutrinoId = 12; // electron neutrion diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 754804d03..ca11d8f30 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -10,49 +10,49 @@ namespace mpc { TEST(ElectronPairProduction, EnergyDecreasing) { - // test if energy loss occurs for protons with energies from 1e15 - 1e23 eV - Candidate candidate; - candidate.setCurrentStep(1 * Mpc); - candidate.current.setId(getNucleusId(1, 1)); // proton + // Test if energy loss occurs for protons with energies from 1e15 - 1e23 eV + Candidate c; + c.setCurrentStep(1 * Mpc); + c.current.setId(getNucleusId(1, 1)); // proton ElectronPairProduction epp1(CMB); for (int i = 0; i < 80; i++) { double E = pow(10, 15 + i * 0.1) * eV; - candidate.current.setEnergy(E); - epp1.process(&candidate); - EXPECT_TRUE(candidate.current.getEnergy() <= E); + c.current.setEnergy(E); + epp1.process(&c); + EXPECT_TRUE(c.current.getEnergy() <= E); } ElectronPairProduction epp2(IRB); for (int i = 0; i < 80; i++) { double E = pow(10, 15 + i * 0.1) * eV; - candidate.current.setEnergy(E); - epp2.process(&candidate); - EXPECT_TRUE(candidate.current.getEnergy() < E); + c.current.setEnergy(E); + epp2.process(&c); + EXPECT_TRUE(c.current.getEnergy() < E); } ElectronPairProduction epp3(CMB_IRB); for (int i = 0; i < 80; i++) { double E = pow(10, 15 + i * 0.1) * eV; - candidate.current.setEnergy(E); - epp3.process(&candidate); - EXPECT_TRUE(candidate.current.getEnergy() < E); + c.current.setEnergy(E); + epp3.process(&c); + EXPECT_TRUE(c.current.getEnergy() < E); } } TEST(ElectronPairProduction, BelowEnergyTreshold) { - // test if nothing happens below 1e15 eV + // Test if nothing happens below 1e15 eV ElectronPairProduction epp(CMB); - Candidate candidate; - candidate.current.setId(getNucleusId(1, 1)); // proton + Candidate c; + c.current.setId(getNucleusId(1, 1)); // proton double E = 1e14 * eV; - candidate.current.setEnergy(E); - epp.process(&candidate); - EXPECT_DOUBLE_EQ(candidate.current.getEnergy(), E); + c.current.setEnergy(E); + epp.process(&c); + EXPECT_DOUBLE_EQ(c.current.getEnergy(), E); } TEST(ElectronPairProduction, EnergyLossValues) { - // test if energy loss corresponds to table + // Test if energy loss corresponds to the data table. std::vector x; std::vector y; std::ifstream infile("data/ElectronPairProduction/cmbir.txt"); @@ -69,23 +69,24 @@ TEST(ElectronPairProduction, EnergyLossValues) { } infile.close(); - Candidate candidate; - candidate.setCurrentStep(1 * Mpc); - candidate.current.setId(getNucleusId(1, 1)); // proton + Candidate c; + c.setCurrentStep(1 * Mpc); + c.current.setId(getNucleusId(1, 1)); // proton ElectronPairProduction epp; for (int i = 0; i < x.size(); i++) { - candidate.current.setEnergy(x[i]); - epp.process(&candidate); - double dE = x[i] - candidate.current.getEnergy(); + c.current.setEnergy(x[i]); + epp.process(&c); + double dE = x[i] - c.current.getEnergy(); double dE_table = y[i] * 1 * Mpc; EXPECT_NEAR(dE, dE_table, 1e-12); } } TEST(NuclearDecay, Neutron) { - // Quantitativ test of decaying neutrons at rest - // Due to the stochastic nature this test might fail. + // Quantitative test of decaying neutrons at rest. + // The mean decay time is expected to be within 1% of the literature value. + // This test can stochastically fail. Candidate candidate; candidate.current.setId(getNucleusId(1, 0)); candidate.current.setEnergy(mass_neutron * c_squared); @@ -101,154 +102,215 @@ TEST(NuclearDecay, Neutron) { } TEST(NuclearDecay, Scandium44) { - // test beta+ decay 44Sc -> 44Ca - Candidate candidate; - candidate.setCurrentStep(1 * Mpc); - candidate.current.setId(getNucleusId(44, 21)); - candidate.current.setEnergy(1 * EeV); + // Test beta+ decay of 44Sc 44Ca. + // This test can stochastically fail. NuclearDecay d(true, true); - d.process(&candidate); - EXPECT_EQ(getNucleusId(44,20), candidate.current.getId()); - // 2 leptons expected - EXPECT_EQ(2, candidate.secondaries.size()); + Candidate c; + c.setCurrentStep(1 * Mpc); + c.current.setId(getNucleusId(44, 21)); + c.current.setEnergy(1 * EeV); + double gamma = c.current.getLorentzFactor(); + d.process(&c); + // primary + EXPECT_EQ(getNucleusId(44,20), c.current.getId()); + EXPECT_DOUBLE_EQ(gamma, c.current.getLorentzFactor()); + // secondaries + EXPECT_EQ(2, c.secondaries.size()); + Candidate c1 = *c.secondaries[0]; + Candidate c2 = *c.secondaries[1]; + EXPECT_EQ(-11, c1.current.getId()); // positron + EXPECT_EQ( 12, c2.current.getId()); // electron neutrino } TEST(NuclearDecay, Li4) { - // test proton dripping Li-4 -> He-3 - Candidate candidate; - candidate.setCurrentStep(1 * kpc); - candidate.current.setId(getNucleusId(4, 3)); - candidate.current.setEnergy(1 * EeV); + // Test proton dripping of Li-4 to He-3. + // This test can stochastically fail. NuclearDecay d; - d.process(&candidate); - EXPECT_EQ(getNucleusId(3,2), candidate.current.getId()); - EXPECT_EQ(1, candidate.secondaries.size()); + Candidate c; + c.setCurrentStep(1 * kpc); + c.current.setId(getNucleusId(4, 3)); + c.current.setEnergy(4 * EeV); + d.process(&c); + // primary + EXPECT_EQ(getNucleusId(3,2), c.current.getId()); + EXPECT_EQ(1, c.secondaries.size()); + // secondary + Candidate c1 = *c.secondaries[0]; + EXPECT_EQ(getNucleusId(1,1), c1.current.getId()); + EXPECT_EQ(1, c1.current.getEnergy() / EeV); } TEST(NuclearDecay, He5) { - // test neturon dripping He-5 -> He-4 - Candidate candidate; - candidate.setCurrentStep(1 * Mpc); - candidate.current.setId(getNucleusId(5, 2)); - candidate.current.setEnergy(1 * EeV); + // Test neturon dripping of He-5 to He-4. + // This test can stochastically fail if no interaction occurs over 1 Mpc. NuclearDecay d; - d.process(&candidate); - EXPECT_EQ(getNucleusId(4,2), candidate.current.getId()); + Candidate c; + c.setCurrentStep(1 * Mpc); + c.current.setId(getNucleusId(5, 2)); + c.current.setEnergy(5 * EeV); + d.process(&c); + // primary + EXPECT_EQ(getNucleusId(4,2), c.current.getId()); + EXPECT_EQ(4, c.current.getEnergy() / EeV); + // secondary + Candidate c2 = *c.secondaries[0]; + EXPECT_EQ(getNucleusId(1,0), c2.current.getId()); + EXPECT_EQ(1, c2.current.getEnergy() / EeV); } TEST(NuclearDecay, LimitNextStep) { - // test if nextStep is limited - // the decay length of a neutron at 10 EeV is 93 kpc + // Test if next step is limited. NuclearDecay d; - Candidate candidate; - candidate.setNextStep(10 * Mpc); - candidate.current.setId(getNucleusId(1, 0)); - candidate.current.setEnergy(10 * EeV); - d.process(&candidate); - EXPECT_TRUE(candidate.getNextStep() < 10 * Mpc); + Candidate c; + c.setNextStep(std::numeric_limits::max()); + c.current.setId(getNucleusId(1, 0)); + c.current.setEnergy(10 * EeV); + d.process(&c); + EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); } TEST(PhotoDisintegration, Backgrounds) { + // Test if all interaction can be initialized with all backgrounds. PhotoDisintegration pd1(CMB); PhotoDisintegration pd2(IRB); PhotoDisintegration pd3(CMB_IRB); } TEST(PhotoDisintegration, Carbon) { + // Test if a 100 EeV C-12 nucleus photo-disintegrates (at least once) over a distance of 50 Mpc. + // This test can stochastically fail if no interaction occurs over 50 Mpc. PhotoDisintegration pd; - Candidate candidate; - candidate.current.setId(getNucleusId(12, 6)); - candidate.current.setEnergy(200 * EeV); - candidate.setCurrentStep(50 * Mpc); - pd.process(&candidate); - EXPECT_TRUE(candidate.current.getMassNumber() < 12); - EXPECT_TRUE(candidate.current.getEnergy() < 200 * EeV); - EXPECT_TRUE(candidate.secondaries.size() > 0); + Candidate c; + c.current.setId(getNucleusId(12, 6)); + c.current.setEnergy(100 * EeV); + c.setCurrentStep(50 * Mpc); + pd.process(&c); + + EXPECT_TRUE(c.current.getEnergy() < 100 * EeV); // energy loss + EXPECT_TRUE(c.secondaries.size() > 0); // secondaries produced + + int A = c.current.getMassNumber(); + int Z = c.current.getChargeNumber(); + double E = c.current.getEnergy(); + + for (int i = 0; i < c.secondaries.size(); i++) { + A += (*c.secondaries[i]).current.getMassNumber(); + Z += (*c.secondaries[i]).current.getChargeNumber(); + E += (*c.secondaries[i]).current.getEnergy(); + } + EXPECT_EQ(12, A); // nucleon number conserved + EXPECT_EQ(6, Z); // proton number conserved + EXPECT_DOUBLE_EQ(100 * EeV, E); // energy conserved } TEST(PhotoDisintegration, Iron) { + // Test if a 100 EeV Fe-56 nucleus photo-disintegrates (at least once) over a distance of 50 Mpc. + // This test can stochastically fail if no interaction occurs over 50 Mpc. PhotoDisintegration pd; - Candidate candidate; - candidate.current.setId(getNucleusId(56, 26)); - candidate.current.setEnergy(200 * EeV); - candidate.setCurrentStep(50 * Mpc); - pd.process(&candidate); - EXPECT_TRUE(candidate.current.getMassNumber() < 56); - EXPECT_TRUE(candidate.current.getEnergy() < 200 * EeV); - EXPECT_TRUE(candidate.secondaries.size() > 0); + Candidate c; + c.current.setId(getNucleusId(56, 26)); + c.current.setEnergy(100 * EeV); + c.setCurrentStep(50 * Mpc); + pd.process(&c); + + EXPECT_TRUE(c.current.getEnergy() < 100 * EeV); // energy loss + EXPECT_TRUE(c.secondaries.size() > 0); // secondaries produced + + int A = c.current.getMassNumber(); + int Z = c.current.getChargeNumber(); + double E = c.current.getEnergy(); + + for (int i = 0; i < c.secondaries.size(); i++) { + A += (*c.secondaries[i]).current.getMassNumber(); + Z += (*c.secondaries[i]).current.getChargeNumber(); + E += (*c.secondaries[i]).current.getEnergy(); + } + EXPECT_EQ(56, A); // nucleon number conserved + EXPECT_EQ(26, Z); // proton number conserved + EXPECT_DOUBLE_EQ(100 * EeV, E); // energy conserved } TEST(PhotoDisintegration, LimitNextStep) { - // test if nextStep is limited + // Test if the interaction limits the next propagation step. PhotoDisintegration pd; - Candidate candidate; - candidate.setNextStep(100 * Mpc); - candidate.current.setId(getNucleusId(4, 2)); - candidate.current.setEnergy(200 * EeV); - pd.process(&candidate); - EXPECT_TRUE(candidate.getNextStep() < 100 * Mpc); + Candidate c; + c.setNextStep(std::numeric_limits::max()); + c.current.setId(getNucleusId(4, 2)); + c.current.setEnergy(200 * EeV); + pd.process(&c); + EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); } TEST(PhotoPionProduction, Backgrounds) { + // Test if interaction data files are loaded. PhotoPionProduction ppp1(CMB); PhotoPionProduction ppp2(IRB); } TEST(PhotoPionProduction, Proton) { + // Test photo-pion interaction for 100 EeV proton. + // This test can stochastically fail if no interaction occurs over 100 Mpc. PhotoPionProduction ppp; - Candidate candidate; - candidate.setCurrentStep(100 * Mpc); - candidate.current.setId(getNucleusId(1, 1)); - candidate.current.setEnergy(100 * EeV); - ppp.process(&candidate); - EXPECT_TRUE(candidate.current.getEnergy() / EeV < 100); - EXPECT_EQ(candidate.current.getMassNumber(), 1); + Candidate c; + c.setCurrentStep(100 * Mpc); + c.current.setId(getNucleusId(1, 1)); + c.current.setEnergy(100 * EeV); + ppp.process(&c); + EXPECT_TRUE(c.current.getEnergy() / EeV < 100); // energy loss + EXPECT_EQ(1, c.current.getMassNumber()); // nucleon number conserved + EXPECT_EQ(0, c.secondaries.size()); // no (nucleonic) secondaries } TEST(PhotoPionProduction, Helium) { + // Test photo-pion interaction for 400 EeV He nucleus. + // This test can stochastically fail if no interaction occurs over 100 Mpc. PhotoPionProduction ppp; - Candidate candidate; - candidate.setCurrentStep(100 * Mpc); - candidate.current.setId(getNucleusId(4, 2)); - candidate.current.setEnergy(400 * EeV); - ppp.process(&candidate); - EXPECT_TRUE(candidate.current.getEnergy() / EeV < 300); - EXPECT_TRUE(candidate.current.getMassNumber() < 4); - EXPECT_TRUE(candidate.secondaries.size() > 0); + Candidate c; + c.setCurrentStep(100 * Mpc); + c.current.setId(getNucleusId(4, 2)); + c.current.setEnergy(400 * EeV); + ppp.process(&c); + EXPECT_LT(c.current.getEnergy(), 400 * EeV); + EXPECT_TRUE(c.current.getMassNumber() < 4); + EXPECT_TRUE(c.secondaries.size() > 0); } TEST(PhotoPionProduction, LimitNextStep) { - // test if nextStep is limited + // Test if the interaction limits the next propagation step. PhotoPionProduction ppp; - Candidate candidate; - candidate.setNextStep(100 * Mpc); - candidate.current.setId(getNucleusId(1, 1)); - candidate.current.setEnergy(200 * EeV); - ppp.process(&candidate); - EXPECT_TRUE(candidate.getNextStep() < 100 * Mpc); + Candidate c; + c.setNextStep(std::numeric_limits::max()); + c.current.setId(getNucleusId(1, 1)); + c.current.setEnergy(200 * EeV); + ppp.process(&c); + EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); } -TEST(SophiaPhotoPionProduction, Proton) { +TEST(SophiaPhotoPionProduction, withoutSecondaries) { + // Test photo-pion (SOPHIA) interaction for 100 EeV proton. + // This test can stochastically fail if no interaction occurs over 100 Mpc. SophiaPhotoPionProduction ppp; - Candidate candidate; - candidate.setCurrentStep(100 * Mpc); - candidate.current.setId(getNucleusId(1, 1)); - candidate.current.setEnergy(100 * EeV); - ppp.process(&candidate); - EXPECT_TRUE(candidate.current.getEnergy() / EeV < 100); - EXPECT_EQ(candidate.current.getMassNumber(), 1); - EXPECT_TRUE(candidate.secondaries.size() == 0); + Candidate c; + c.setCurrentStep(100 * Mpc); + c.current.setId(getNucleusId(1, 1)); + c.current.setEnergy(100 * EeV); + ppp.process(&c); + EXPECT_GT(100 * EeV, c.current.getEnergy()); // energy loss + EXPECT_EQ(1, c.current.getMassNumber()); // nucleon number conserved + EXPECT_EQ(0, c.secondaries.size()); // secondaries turned off } TEST(SophiaPhotoPionProduction, withSecondaries) { + // Test photo-pion interaction for 100 EeV proton. + // This test can stochastically fail if no interaction occurs over 100 Mpc. SophiaPhotoPionProduction ppp(CMB, true, true, true); - Candidate candidate; - candidate.current.setId(getNucleusId(1, 1)); - candidate.current.setEnergy(100 * EeV); + Candidate c; + c.current.setId(getNucleusId(1, 1)); + c.current.setEnergy(100 * EeV); InteractionState interaction; - ppp.setNextInteraction(&candidate, interaction); - ppp.performInteraction(&candidate); - EXPECT_TRUE(candidate.secondaries.size() >= 2); + ppp.setNextInteraction(&c, interaction); + ppp.performInteraction(&c); + EXPECT_GT(c.secondaries.size(), 1); // secondaries turned on } int main(int argc, char **argv) { From 44772605ca99b83b0b4b9d2e01e654d03ebfe323 Mon Sep 17 00:00:00 2001 From: geromueller Date: Sun, 6 May 2012 18:45:34 +0200 Subject: [PATCH 0086/1298] deactivate primry particle when A reaches 0 --- src/module/PhotoDisintegration.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 1da6eda8a..41cd78cc0 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -34,7 +34,8 @@ void PhotoDisintegration::init(int photonField) { init(getDataPath("PhotoDisintegration/PDtable_CMB_IRB.txt")); break; default: - throw std::runtime_error("mpc::PhotoDisintegration: unknown photon background"); + throw std::runtime_error( + "mpc::PhotoDisintegration: unknown photon background"); } } @@ -51,7 +52,8 @@ void PhotoDisintegration::init(std::string filename) { std::vector y(SAMPLE_COUNT); if (!infile.good()) - throw std::runtime_error("mpc::PhotoDisintegration: could not open file " + filename); + throw std::runtime_error( + "mpc::PhotoDisintegration: could not open file " + filename); std::string line; size_t lineNo = 0; @@ -97,7 +99,8 @@ PhotoDisintegration::~PhotoDisintegration() { } } -bool PhotoDisintegration::setNextInteraction(Candidate *candidate, InteractionState &interaction) const { +bool PhotoDisintegration::setNextInteraction(Candidate *candidate, + InteractionState &interaction) const { int id = candidate->current.getId(); // check if disintegration data available @@ -154,8 +157,13 @@ void PhotoDisintegration::performInteraction(Candidate *candidate) const { double EpA = candidate->current.getEnergy() / double(A); // update particle - candidate->current.setId(getNucleusId(A + dA, Z + dZ)); - candidate->current.setEnergy(EpA * (A + dA)); + int nA = A + dA; + if (nA > 0) { + candidate->current.setId(getNucleusId(A + dA, Z + dZ)); + candidate->current.setEnergy(EpA * (A + dA)); + } else { + candidate->setActive(false); + } // create secondaries for (size_t i = 0; i < nNeutron; i++) From 35e643da774d1dd9677e3df4a2f8a9a979572860 Mon Sep 17 00:00:00 2001 From: geromueller Date: Sun, 6 May 2012 18:46:37 +0200 Subject: [PATCH 0087/1298] fix SpatialPartitioning margin, add deleteInactive flag --- include/mpc/SpatialPartitioning.h | 14 +++-- src/SpatialPartitioning.cpp | 89 ++++++++++++++++++++++--------- 2 files changed, 73 insertions(+), 30 deletions(-) diff --git a/include/mpc/SpatialPartitioning.h b/include/mpc/SpatialPartitioning.h index 129ca0385..672815a1e 100644 --- a/include/mpc/SpatialPartitioning.h +++ b/include/mpc/SpatialPartitioning.h @@ -31,20 +31,26 @@ class SpatialPartitioning: public Referenced { SpatialPartitioning(ModuleList *moduleList); - void run(candidate_vector_t &candidates, bool recursive); + void run(candidate_vector_t &candidates, bool recursive, + bool deleteInactive); void run(Source *source, size_t count, bool recursive); void setPartitionOrigin(const Vector3d &origin); void setPartitionSize(double size); void setCurrentPartition(const Vector3d &offset); - void setPartitionMargin(double margin); + void setPartitionMargin(double inner, double outer); void setVerbose(bool verbose); private: void run(Candidate *candidate, bool recursive, - Loki::AssocVector &partitions); + Loki::AssocVector &partitions, bool deleteInactive); Vector3d partitionOrigin, currentPartition; - double partitionSize, partitionMargin; + double partitionSize, partitionMarginInner, partitionMarginOuter; + + void updateMargins(); + Vector3d currentPartitionInner, currentPartitionOuter; + double partitionSizeInner, partitionSizeOuter; + bool verbose; ref_ptr moduleList; }; diff --git a/src/SpatialPartitioning.cpp b/src/SpatialPartitioning.cpp index ecd883ece..a5c3eed5e 100644 --- a/src/SpatialPartitioning.cpp +++ b/src/SpatialPartitioning.cpp @@ -43,8 +43,11 @@ bool Index::operator<(const Index &rhs) const { } SpatialPartitioning::SpatialPartitioning(ModuleList *moduleList) : - partitionOrigin(0, 0, 0), partitionSize(10 * Mpc), partitionMargin( - 1 * Mpc), verbose(false), moduleList(moduleList) { + partitionOrigin(0, 0, 0), partitionSize(10 * Mpc), partitionMarginInner( + 0.5 * Mpc), partitionMarginOuter(1 * Mpc), verbose(false), moduleList( + moduleList) { + updateMargins(); + } bool findActivePosition(Candidate *candidate, bool recursive, @@ -65,11 +68,17 @@ bool findActivePosition(Candidate *candidate, bool recursive, return false; } -void SpatialPartitioning::run(candidate_vector_t &candidates, bool recursive) { - size_t count = candidates.size(); +bool toBeRemoved(ref_ptr &candidate) { + bool inactive = (candidate->isActive() == false); + bool nochild = (candidate->secondaries.size() == 0); + return (inactive && nochild); +} + +void SpatialPartitioning::run(candidate_vector_t &candidates, bool recursive, + bool deleteInactive) { Loki::AssocVector partitions; - for (size_t i = 0; i < count; i++) { + for (size_t i = 0; i < candidates.size(); i++) { if (candidates[i]->isActive()) { Vector3d pos = candidates[i]->current.getPosition() - partitionOrigin; @@ -86,8 +95,10 @@ void SpatialPartitioning::run(candidate_vector_t &candidates, bool recursive) { size_t nextCount = iPartition->second.count; for (iPartition = partitions.begin(); iPartition != partitions.end(); iPartition++) { - if (iPartition->second.count > nextCount) + if (iPartition->second.count > nextCount) { nextPartition = iPartition->first; + nextCount = iPartition->second.count; + } } Vector3d o(nextPartition.x, nextPartition.y, nextPartition.z); @@ -95,18 +106,18 @@ void SpatialPartitioning::run(candidate_vector_t &candidates, bool recursive) { // do the loop partitions.clear(); - size_t cent = std::max(1ul, count / 100), pc = 0; + size_t cent = std::max(1ul, candidates.size() / 100), pc = 0; #pragma omp parallel shared(partitions, pc) { Loki::AssocVector _partitions; #pragma omp for schedule(dynamic, 1000) - for (size_t i = 0; i < count; i++) { + for (size_t i = 0; i < candidates.size(); i++) { if (verbose && (i % cent == 0)) { std::cout << pc << "% - " << i << std::endl; pc++; } - run(candidates[i], recursive, _partitions); + run(candidates[i], recursive, _partitions, deleteInactive); } Loki::AssocVector::iterator i; @@ -115,22 +126,29 @@ void SpatialPartitioning::run(candidate_vector_t &candidates, bool recursive) { partitions[i->first] += i->second.count; } } + + if (deleteInactive) { + candidates.erase( + remove_if(candidates.begin(), candidates.end(), + toBeRemoved), candidates.end()); + } } } void SpatialPartitioning::run(Candidate *candidate, bool recursive, - Loki::AssocVector &partitions) { + Loki::AssocVector &partitions, bool deleteInactive) { size_t active = 0; while (candidate->isActive()) { - Vector3d relPos = candidate->current.getPosition() - currentPartition; + Vector3d relPos = candidate->current.getPosition() + - currentPartitionInner; double lo = std::min(relPos.x, std::min(relPos.y, relPos.z)); double hi = std::max(relPos.x, std::max(relPos.y, relPos.z)); - if ((lo < 0.) || (hi > partitionSize)) { + if ((lo <= 0.) || (hi >= partitionSizeInner)) { break; } - candidate->limitNextStep(lo + partitionMargin); - candidate->limitNextStep(partitionSize - hi + partitionMargin); + candidate->limitNextStep(lo); + candidate->limitNextStep(partitionSizeInner - hi); moduleList->process(candidate); } @@ -143,8 +161,16 @@ void SpatialPartitioning::run(Candidate *candidate, bool recursive, // propagate secondaries if (recursive) { - for (size_t i = 0; i < candidate->secondaries.size(); i++) - run(candidate->secondaries[i], recursive, partitions); + for (size_t i = 0; i < candidate->secondaries.size(); i++) { + run(candidate->secondaries[i], recursive, partitions, + deleteInactive); + } + if (deleteInactive) { + candidate->secondaries.erase( + remove_if(candidate->secondaries.begin(), + candidate->secondaries.end(), toBeRemoved), + candidate->secondaries.end()); + } } } @@ -158,7 +184,7 @@ void SpatialPartitioning::run(Source *source, size_t count, bool recursive) { candidates.push_back(candidate); } - run(candidates, recursive); + run(candidates, recursive, true); } void SpatialPartitioning::setPartitionOrigin(const Vector3d &origin) { @@ -167,11 +193,14 @@ void SpatialPartitioning::setPartitionOrigin(const Vector3d &origin) { void SpatialPartitioning::setPartitionSize(double size) { partitionSize = size; -} + updateMargins(); -void SpatialPartitioning::setPartitionMargin(double margin) { - partitionMargin = margin; +} +void SpatialPartitioning::setPartitionMargin(double inner, double outer) { + partitionMarginInner = inner; + partitionMarginOuter = outer; + updateMargins(); } struct _UpdateSimulationVolume { @@ -192,19 +221,27 @@ struct _UpdateSimulationVolume { void SpatialPartitioning::setCurrentPartition(const Vector3d &offset) { currentPartition = offset; + updateMargins(); if (verbose) { std::cout << "mpc::SpatialPartitioningExecutor::setCurrentPartition -> " << offset / Mpc << std::endl; } - Vector3d currentPartitionMargin = offset - - Vector3d(partitionMargin, partitionMargin, partitionMargin); - double partitionSizeMargin = partitionSize + 2 * partitionMargin; - std::for_each(moduleList->getModules().begin(), moduleList->getModules().end(), - _UpdateSimulationVolume(currentPartitionMargin, - partitionSizeMargin)); + _UpdateSimulationVolume(currentPartitionOuter, partitionSizeOuter)); +} + +void SpatialPartitioning::updateMargins() { + currentPartitionInner = currentPartition + - Vector3d(partitionMarginInner, partitionMarginInner, + partitionMarginInner); + partitionSizeInner = partitionSize + 2 * partitionMarginInner; + + currentPartitionOuter = currentPartition + - Vector3d(partitionMarginOuter, partitionMarginOuter, + partitionMarginOuter); + partitionSizeOuter = partitionSize + 2 * partitionMarginOuter; } void SpatialPartitioning::setVerbose(bool verbose) { From 498f9e511dc9d7ee523f737058451fc3a98735ca Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sun, 6 May 2012 22:24:44 +0200 Subject: [PATCH 0088/1298] refactor PD, improve preprocessing, test all PD channels --- include/mpc/module/PhotoDisintegration.h | 11 ++--- src/module/PhotoDisintegration.cpp | 55 +++++++++--------------- test/testInteraction.cpp | 37 ++++++++++++++-- 3 files changed, 59 insertions(+), 44 deletions(-) diff --git a/include/mpc/module/PhotoDisintegration.h b/include/mpc/module/PhotoDisintegration.h index 321a53882..b9f6ca4a8 100644 --- a/include/mpc/module/PhotoDisintegration.h +++ b/include/mpc/module/PhotoDisintegration.h @@ -5,7 +5,6 @@ #include "mpc/Random.h" #include -#include #include #include @@ -16,19 +15,17 @@ namespace mpc { @brief Photo-disintegration of nuclei with background photons. This module simulates photo-disintegration of nuclei with background photons.\n - Background photons are considered as homogeneous and evolving as the CMB.\n + Background photon fields are considered as homogeneous and evolving as the CMB.\n */ class PhotoDisintegration: public StochasticInteraction { private: int photonField; - struct DisintegrationMode { + struct PDMode { int channel; // number of emitted (n, p, H2, H3, He3, He4) gsl_spline *rate; // disintegration rate [1/m] }; - - typedef std::map > DisintegrationModeMap; - DisintegrationModeMap PDTable; - gsl_interp_accel *acc; + std::vector > pdTable; // pdTable[Z * 31 + N] = vector + gsl_interp_accel *acc; // accelerator for the interpolation public: PhotoDisintegration(int photonField = CMB_IRB); diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 1da6eda8a..44e616388 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -1,13 +1,11 @@ #include "mpc/module/PhotoDisintegration.h" +#include #include -#include #include #include #include -#include - namespace mpc { enum _Constants { @@ -39,9 +37,8 @@ void PhotoDisintegration::init(int photonField) { } void PhotoDisintegration::init(std::string filename) { - std::ifstream infile(filename.c_str()); - acc = gsl_interp_accel_alloc(); + pdTable.resize(31 * 57); // create spline x-axis std::vector x(SAMPLE_COUNT); @@ -50,39 +47,31 @@ void PhotoDisintegration::init(std::string filename) { std::vector y(SAMPLE_COUNT); + std::ifstream infile(filename.c_str()); if (!infile.good()) throw std::runtime_error("mpc::PhotoDisintegration: could not open file " + filename); std::string line; - size_t lineNo = 0; while (std::getline(infile, line)) { - lineNo++; if (line[0] == '#') continue; std::stringstream lineStream(line); - int Z, A; + int Z, N; lineStream >> Z; // charge number - lineStream >> A; // mass number + lineStream >> N; // mass number - DisintegrationMode mode; - lineStream >> mode.channel; // disintegration channel + PDMode pd; + lineStream >> pd.channel; // disintegration channel for (size_t i = 0; i < SAMPLE_COUNT; i++) { lineStream >> y[i]; y[i] /= Mpc; // disintegration rate in [1/m] - - if (!lineStream) - throw std::runtime_error( - "mpc::PhotoDisintegration: Not enough entries in rate.txt. Expected 200 got " - + kiss::str(i) + " in line " - + kiss::str(lineNo)); } - mode.rate = gsl_spline_alloc(gsl_interp_linear, SAMPLE_COUNT); - gsl_spline_init(mode.rate, &x[0], &y[0], SAMPLE_COUNT); - - PDTable[getNucleusId(A, Z)].push_back(mode); + pd.rate = gsl_spline_alloc(gsl_interp_linear, SAMPLE_COUNT); + gsl_spline_init(pd.rate, &x[0], &y[0], SAMPLE_COUNT); + pdTable[Z * 31 + N].push_back(pd); } infile.close(); @@ -90,23 +79,21 @@ void PhotoDisintegration::init(std::string filename) { PhotoDisintegration::~PhotoDisintegration() { gsl_interp_accel_free(acc); - DisintegrationModeMap::iterator iModes; - for (iModes = PDTable.begin(); iModes != PDTable.end(); iModes++) { - for (size_t iMode = 0; iMode < iModes->second.size(); iMode++) - gsl_spline_free(iModes->second[iMode].rate); - } + for (size_t i = 0; i < pdTable.size(); i++) + for (size_t j = 0; j < pdTable[i].size(); j++) + gsl_spline_free(pdTable[i][j].rate); } bool PhotoDisintegration::setNextInteraction(Candidate *candidate, InteractionState &interaction) const { - int id = candidate->current.getId(); + int A = candidate->current.getMassNumber(); + int Z = candidate->current.getChargeNumber(); + int N = A - Z; // check if disintegration data available - DisintegrationModeMap::const_iterator iMode = PDTable.find(id); - if (iMode == PDTable.end()) + std::vector pdModes = pdTable[Z * 31 + N]; + if (pdModes.size() == 0) return false; - const std::vector &modes = iMode->second; - // CMB energy increases with (1+z), increase nucleus energy accordingly double z = candidate->getRedshift(); double lg = log10(candidate->current.getLorentzFactor() * (1 + z)); @@ -117,13 +104,13 @@ bool PhotoDisintegration::setNextInteraction(Candidate *candidate, InteractionSt // find channel with minimum random decay distance interaction.distance = std::numeric_limits::max(); - for (size_t i = 0; i < modes.size(); i++) { - double rate = gsl_spline_eval(modes[i].rate, lg, acc); + for (size_t i = 0; i < pdModes.size(); i++) { + double rate = gsl_spline_eval(pdModes[i].rate, lg, acc); double d = -log(Random::instance().rand()) / rate; if (d > interaction.distance) continue; interaction.distance = d; - interaction.channel = modes[i].channel; + interaction.channel = pdModes[i].channel; } // CMB density increases with (1+z)^3 -> free distance decreases accordingly diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index ca11d8f30..abe85d658 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -171,9 +171,9 @@ TEST(NuclearDecay, LimitNextStep) { TEST(PhotoDisintegration, Backgrounds) { // Test if all interaction can be initialized with all backgrounds. - PhotoDisintegration pd1(CMB); - PhotoDisintegration pd2(IRB); - PhotoDisintegration pd3(CMB_IRB); +// PhotoDisintegration pd1(CMB); +// PhotoDisintegration pd2(IRB); +// PhotoDisintegration pd3(CMB_IRB); } TEST(PhotoDisintegration, Carbon) { @@ -241,6 +241,37 @@ TEST(PhotoDisintegration, LimitNextStep) { EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); } +TEST(PhotoDisintegration, AllWorking) { + // Test if all photo-disintegrations are working. + PhotoDisintegration pd; + Candidate c; + InteractionState interaction; + + std::ifstream infile(getDataPath("PhotoDisintegration/PDtable_CMB_IRB.txt").c_str()); + std::string line; + while (std::getline(infile, line)) { + if (line[0] == '#') + continue; + std::stringstream lineStream(line); + int Z, N; + lineStream >> Z; + lineStream >> N; + lineStream >> interaction.channel; + + double y; + for (size_t i = 0; i < 200; i++) { + lineStream >> y; + EXPECT_TRUE(lineStream); // test if all 200 entries are present + } + + c.current.setId(getNucleusId(Z + N, Z)); + c.current.setEnergy(80 * EeV); + c.setInteractionState(pd.getDescription(), interaction); + pd.performInteraction(&c); + } + infile.close(); +} + TEST(PhotoPionProduction, Backgrounds) { // Test if interaction data files are loaded. PhotoPionProduction ppp1(CMB); From 783b35b6347d3afcfb6e63494ee0ed22a5efd2ad Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sun, 6 May 2012 23:01:58 +0200 Subject: [PATCH 0089/1298] small change to NuclearDecay, test all decays --- .../magneticField/SPHTurbulentMagneticField.h | 2 +- include/mpc/module/NuclearDecay.h | 4 +- src/module/NuclearDecay.cpp | 49 +++++----- test/testInteraction.cpp | 94 ++++++++++++++----- 4 files changed, 96 insertions(+), 53 deletions(-) diff --git a/include/mpc/magneticField/SPHTurbulentMagneticField.h b/include/mpc/magneticField/SPHTurbulentMagneticField.h index 6e9755d45..50b12c578 100644 --- a/include/mpc/magneticField/SPHTurbulentMagneticField.h +++ b/include/mpc/magneticField/SPHTurbulentMagneticField.h @@ -11,7 +11,7 @@ namespace mpc { */ class SPHTurbulentMagneticField: public TurbulentMagneticField { public: - void initialize(const std::string filename); + void modulate(const std::string filename); }; } // namespace mpc diff --git a/include/mpc/module/NuclearDecay.h b/include/mpc/module/NuclearDecay.h index e2254d041..297ecd205 100644 --- a/include/mpc/module/NuclearDecay.h +++ b/include/mpc/module/NuclearDecay.h @@ -2,12 +2,10 @@ #define DECAY_H_ #include "mpc/module/StochasticInteraction.h" -#include "mpc/Random.h" #include #include #include -#include namespace mpc { @@ -22,7 +20,7 @@ class NuclearDecay: public StochasticInteraction { bool haveElectrons; bool haveNeutrinos; - std::map > decayTable; + std::vector > decayTable; gsl_interp_accel *acc; gsl_spline *Tbeta; // inverse cdf electron kinetic energy [J] in neutron decay diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index 32b6e259d..dda67981a 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -1,8 +1,9 @@ #include "mpc/module/NuclearDecay.h" +#include "mpc/Random.h" #include #include -#include +#include #include namespace mpc { @@ -19,15 +20,15 @@ NuclearDecay::NuclearDecay(bool electrons, bool neutrinos) { throw std::runtime_error( "mpc::NuclearDecay: could not open file " + filename); + decayTable.resize(31 * 57); while (infile.good()) { if (infile.peek() != '#') { InteractionState decay; int Z, N; infile >> Z >> N >> decay.distance >> decay.channel; - if (infile) { - decay.distance *= c_light; - decayTable[getNucleusId(Z + N, Z)].push_back(decay); - } + decay.distance *= c_light; // mean decay distance [m] + if (infile) + decayTable[Z * 31 + N].push_back(decay); } infile.ignore(std::numeric_limits::max(), '\n'); } @@ -55,28 +56,26 @@ NuclearDecay::NuclearDecay(bool electrons, bool neutrinos) { } bool NuclearDecay::setNextInteraction(Candidate *candidate, - InteractionState &decay) const { - int id = candidate->current.getId(); + InteractionState &interaction) const { + int A = candidate->current.getMassNumber(); + int Z = candidate->current.getChargeNumber(); + int N = A - Z; - std::map >::const_iterator iMode = - decayTable.find(id); - if (iMode == decayTable.end()) + std::vector decays = decayTable[Z * 31 + N]; + if (decays.size() == 0) return false; - const std::vector &states = iMode->second; - - // find decay mode with minimum random decay distance - decay.distance = std::numeric_limits::max(); - int decayChannel; - for (size_t i = 0; i < states.size(); i++) { - double d = -log(Random::instance().rand()) * states[i].distance; - if (d > decay.distance) + // find interaction mode with minimum random decay distance + interaction.distance = std::numeric_limits::max(); + for (size_t i = 0; i < decays.size(); i++) { + double d = -log(Random::instance().rand()) * decays[i].distance; + if (d > interaction.distance) continue; - decay.distance = d; - decay.channel = states[i].channel; + interaction.distance = d; + interaction.channel = decays[i].channel; } - decay.distance *= candidate->current.getLorentzFactor(); - candidate->setInteractionState(getDescription(), decay); + interaction.distance *= candidate->current.getLorentzFactor(); + candidate->setInteractionState(getDescription(), interaction); return true; } @@ -128,7 +127,8 @@ void NuclearDecay::betaDecay(Candidate *candidate, bool isBetaPlus) const { // random kinetic energy of electron in neutron decay double T = gsl_spline_eval(Tbeta, Random::instance().rand(), acc); - double Q = (mass - candidate->current.getMass() - mass_electron) * c_squared; + double Q = (mass - candidate->current.getMass() - mass_electron) + * c_squared; double Qneutron = (mass_neutron - mass_proton - mass_electron) * c_squared; // electron energy in this decay double E = T * Q / Qneutron + mass_electron * c_squared; @@ -140,7 +140,8 @@ void NuclearDecay::betaDecay(Candidate *candidate, bool isBetaPlus) const { candidate->addSecondary(electronId, gamma * E * (1 + p * cosTheta)); if (haveNeutrinos) // add neutrino with remaining energy and opposite momentum - candidate->addSecondary(neutrinoId, gamma * (Q - E) * (1 - p * cosTheta)); + candidate->addSecondary(neutrinoId, + gamma * (Q - E) * (1 - p * cosTheta)); } void NuclearDecay::nucleonEmission(Candidate *candidate, int dA, int dZ) const { diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index abe85d658..966c1755a 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -93,7 +93,8 @@ TEST(NuclearDecay, Neutron) { NuclearDecay decay; InteractionState state; double tau = 0; - for (int i=0; i<100000; i++) { + for (int i = 0; i < 100000; i++) { +// std::cout << i << std::endl; decay.setNextInteraction(&candidate, state); tau += state.distance; } @@ -118,8 +119,10 @@ TEST(NuclearDecay, Scandium44) { EXPECT_EQ(2, c.secondaries.size()); Candidate c1 = *c.secondaries[0]; Candidate c2 = *c.secondaries[1]; - EXPECT_EQ(-11, c1.current.getId()); // positron - EXPECT_EQ( 12, c2.current.getId()); // electron neutrino + EXPECT_EQ(-11, c1.current.getId()); + // positron + EXPECT_EQ( 12, c2.current.getId()); + // electron neutrino } TEST(NuclearDecay, Li4) { @@ -169,12 +172,34 @@ TEST(NuclearDecay, LimitNextStep) { EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); } -TEST(PhotoDisintegration, Backgrounds) { - // Test if all interaction can be initialized with all backgrounds. +TEST(NuclearDecay, AllWorking) { + // Test if all nuclear decays are working. + NuclearDecay d; + Candidate c; + InteractionState interaction; + + std::ifstream infile(getDataPath("/NuclearDecay/decay_table.txt").c_str()); + while (infile.good()) { + if (infile.peek() != '#') { + int Z, N, x, channel; + infile >> Z >> N >> x >> interaction.channel; + + c.current.setId(getNucleusId(Z + N, Z)); + c.current.setEnergy(80 * EeV); + c.setInteractionState(d.getDescription(), interaction); + d.performInteraction(&c); + } + infile.ignore(std::numeric_limits::max(), '\n'); + } + infile.close(); +} + +//TEST(PhotoDisintegration, Backgrounds) { +// // Test if all interaction can be initialized with all backgrounds. // PhotoDisintegration pd1(CMB); // PhotoDisintegration pd2(IRB); // PhotoDisintegration pd3(CMB_IRB); -} +//} TEST(PhotoDisintegration, Carbon) { // Test if a 100 EeV C-12 nucleus photo-disintegrates (at least once) over a distance of 50 Mpc. @@ -186,8 +211,10 @@ TEST(PhotoDisintegration, Carbon) { c.setCurrentStep(50 * Mpc); pd.process(&c); - EXPECT_TRUE(c.current.getEnergy() < 100 * EeV); // energy loss - EXPECT_TRUE(c.secondaries.size() > 0); // secondaries produced + EXPECT_TRUE(c.current.getEnergy() < 100 * EeV); + // energy loss + EXPECT_TRUE(c.secondaries.size() > 0); + // secondaries produced int A = c.current.getMassNumber(); int Z = c.current.getChargeNumber(); @@ -198,9 +225,12 @@ TEST(PhotoDisintegration, Carbon) { Z += (*c.secondaries[i]).current.getChargeNumber(); E += (*c.secondaries[i]).current.getEnergy(); } - EXPECT_EQ(12, A); // nucleon number conserved - EXPECT_EQ(6, Z); // proton number conserved - EXPECT_DOUBLE_EQ(100 * EeV, E); // energy conserved + EXPECT_EQ(12, A); + // nucleon number conserved + EXPECT_EQ(6, Z); + // proton number conserved + EXPECT_DOUBLE_EQ(100 * EeV, E); + // energy conserved } TEST(PhotoDisintegration, Iron) { @@ -213,8 +243,10 @@ TEST(PhotoDisintegration, Iron) { c.setCurrentStep(50 * Mpc); pd.process(&c); - EXPECT_TRUE(c.current.getEnergy() < 100 * EeV); // energy loss - EXPECT_TRUE(c.secondaries.size() > 0); // secondaries produced + EXPECT_TRUE(c.current.getEnergy() < 100 * EeV); + // energy loss + EXPECT_TRUE(c.secondaries.size() > 0); + // secondaries produced int A = c.current.getMassNumber(); int Z = c.current.getChargeNumber(); @@ -225,9 +257,12 @@ TEST(PhotoDisintegration, Iron) { Z += (*c.secondaries[i]).current.getChargeNumber(); E += (*c.secondaries[i]).current.getEnergy(); } - EXPECT_EQ(56, A); // nucleon number conserved - EXPECT_EQ(26, Z); // proton number conserved - EXPECT_DOUBLE_EQ(100 * EeV, E); // energy conserved + EXPECT_EQ(56, A); + // nucleon number conserved + EXPECT_EQ(26, Z); + // proton number conserved + EXPECT_DOUBLE_EQ(100 * EeV, E); + // energy conserved } TEST(PhotoDisintegration, LimitNextStep) { @@ -247,7 +282,8 @@ TEST(PhotoDisintegration, AllWorking) { Candidate c; InteractionState interaction; - std::ifstream infile(getDataPath("PhotoDisintegration/PDtable_CMB_IRB.txt").c_str()); + std::ifstream infile( + getDataPath("PhotoDisintegration/PDtable_CMB_IRB.txt").c_str()); std::string line; while (std::getline(infile, line)) { if (line[0] == '#') @@ -261,7 +297,8 @@ TEST(PhotoDisintegration, AllWorking) { double y; for (size_t i = 0; i < 200; i++) { lineStream >> y; - EXPECT_TRUE(lineStream); // test if all 200 entries are present + EXPECT_TRUE(lineStream); + // test if all 200 entries are present } c.current.setId(getNucleusId(Z + N, Z)); @@ -287,9 +324,12 @@ TEST(PhotoPionProduction, Proton) { c.current.setId(getNucleusId(1, 1)); c.current.setEnergy(100 * EeV); ppp.process(&c); - EXPECT_TRUE(c.current.getEnergy() / EeV < 100); // energy loss - EXPECT_EQ(1, c.current.getMassNumber()); // nucleon number conserved - EXPECT_EQ(0, c.secondaries.size()); // no (nucleonic) secondaries + EXPECT_TRUE(c.current.getEnergy() / EeV < 100); + // energy loss + EXPECT_EQ(1, c.current.getMassNumber()); + // nucleon number conserved + EXPECT_EQ(0, c.secondaries.size()); + // no (nucleonic) secondaries } TEST(PhotoPionProduction, Helium) { @@ -326,9 +366,12 @@ TEST(SophiaPhotoPionProduction, withoutSecondaries) { c.current.setId(getNucleusId(1, 1)); c.current.setEnergy(100 * EeV); ppp.process(&c); - EXPECT_GT(100 * EeV, c.current.getEnergy()); // energy loss - EXPECT_EQ(1, c.current.getMassNumber()); // nucleon number conserved - EXPECT_EQ(0, c.secondaries.size()); // secondaries turned off + EXPECT_GT(100 * EeV, c.current.getEnergy()); + // energy loss + EXPECT_EQ(1, c.current.getMassNumber()); + // nucleon number conserved + EXPECT_EQ(0, c.secondaries.size()); + // secondaries turned off } TEST(SophiaPhotoPionProduction, withSecondaries) { @@ -341,7 +384,8 @@ TEST(SophiaPhotoPionProduction, withSecondaries) { InteractionState interaction; ppp.setNextInteraction(&c, interaction); ppp.performInteraction(&c); - EXPECT_GT(c.secondaries.size(), 1); // secondaries turned on + EXPECT_GT(c.secondaries.size(), 1); + // secondaries turned on } int main(int argc, char **argv) { From 082eb79ba8a0b694e039bea4018969d446d31695 Mon Sep 17 00:00:00 2001 From: geromueller Date: Tue, 8 May 2012 10:21:14 +0200 Subject: [PATCH 0090/1298] remove temporary cahce files --- src/magneticField/SPHMagneticField.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/magneticField/SPHMagneticField.cpp b/src/magneticField/SPHMagneticField.cpp index 0c809a025..cd6cf86da 100644 --- a/src/magneticField/SPHMagneticField.cpp +++ b/src/magneticField/SPHMagneticField.cpp @@ -71,7 +71,9 @@ void SPHMagneticFieldGrid::updateSimulationVolume(const Vector3d &origin, path << "." << time(NULL) << clock(); std::string filename_tmp = path.str(); field.dump(filename_tmp); - rename(filename_tmp.c_str(), filename.c_str()); + int ren = rename(filename_tmp.c_str(), filename.c_str()); + if (ren != 0) + remove(filename_tmp.c_str()); } } else { field.init(v, s, database); From 927e42f36a04d7d9d7e3e6faff1a18a61f38578f Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 8 May 2012 15:54:12 +0200 Subject: [PATCH 0091/1298] update and remove PhotoDisintegration files + other small changes --- .hgignore | 8 +++- CMakeLists.txt | 1 - include/mpc/Nucleus.h | 14 ++++-- include/mpc/module/NuclearDecay.h | 2 + include/mpc/module/PhotoDisintegration.h | 2 +- src/module/NuclearDecay.cpp | 10 ++--- src/module/PhotoDisintegration.cpp | 4 -- test/testInteraction.cpp | 55 +++++++++++++++++------- 8 files changed, 66 insertions(+), 30 deletions(-) diff --git a/.hgignore b/.hgignore index 87bd37521..0b3e15036 100644 --- a/.hgignore +++ b/.hgignore @@ -10,4 +10,10 @@ syntax: regexp syntax: regexp ^.settings$ syntax: regexp -.png$ \ No newline at end of file +.png$ +syntax: regexp +^data/NuclearDecay/bnl_z0-36\.txt$ +syntax: regexp +^data/PhotoDisintegration/CMB$ +syntax: regexp +^data/PhotoDisintegration/IRB$ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 653684ef8..6da687377 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,7 +79,6 @@ add_definitions(-DMPC_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") add_library(mpc SHARED src/Random.cpp src/Clock.cpp -# src/Vector3.cpp src/ModuleList.cpp src/SpatialPartitioning.cpp src/Module.cpp diff --git a/include/mpc/Nucleus.h b/include/mpc/Nucleus.h index ea762d5df..2abf94ee3 100644 --- a/include/mpc/Nucleus.h +++ b/include/mpc/Nucleus.h @@ -1,6 +1,8 @@ #ifndef NUCLEUS_H_ #define NUCLEUS_H_ +#include "kiss/convert.h" + #include namespace mpc { @@ -13,11 +15,17 @@ namespace mpc { // I is the isomer number, with I=0 corresponding to the ground state. inline int getNucleusId(int a, int z) { if (z < 0) - throw std::runtime_error("mpc::Nucleus: no nucleus with Z < 0"); + throw std::runtime_error( + "mpc::Nucleus: no nucleus with Z < 0, A=" + kiss::str(a) + " Z=" + + kiss::str(z)); if (a < 1) - throw std::runtime_error("mpc::Nucleus: no nucleus with A < 1"); + throw std::runtime_error( + "mpc::Nucleus: no nucleus with A < 1, A=" + kiss::str(a) + " Z=" + + kiss::str(z)); if (a < z) - throw std::runtime_error("mpc::Nucleus: no nucleus with A < Z"); + throw std::runtime_error( + "mpc::Nucleus: no nucleus with A < Z, A=" + kiss::str(a) + " Z=" + + kiss::str(z)); return 1000000000 + z * 10000 + a * 10; } diff --git a/include/mpc/module/NuclearDecay.h b/include/mpc/module/NuclearDecay.h index 297ecd205..50508540b 100644 --- a/include/mpc/module/NuclearDecay.h +++ b/include/mpc/module/NuclearDecay.h @@ -21,6 +21,8 @@ class NuclearDecay: public StochasticInteraction { bool haveNeutrinos; std::vector > decayTable; + // InteractionState.channel is (#beta- #beta+ #alpha #proton #neutron) + // InteractionState.distance is the mean free path [m] gsl_interp_accel *acc; gsl_spline *Tbeta; // inverse cdf electron kinetic energy [J] in neutron decay diff --git a/include/mpc/module/PhotoDisintegration.h b/include/mpc/module/PhotoDisintegration.h index b9f6ca4a8..3596c14e5 100644 --- a/include/mpc/module/PhotoDisintegration.h +++ b/include/mpc/module/PhotoDisintegration.h @@ -28,7 +28,7 @@ class PhotoDisintegration: public StochasticInteraction { gsl_interp_accel *acc; // accelerator for the interpolation public: - PhotoDisintegration(int photonField = CMB_IRB); + PhotoDisintegration(int photonField = CMB); ~PhotoDisintegration(); void init(int photonField); void init(std::string filename); diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index dda67981a..9887021f0 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -14,18 +14,18 @@ NuclearDecay::NuclearDecay(bool electrons, bool neutrinos) { haveNeutrinos = neutrinos; // load decay table - std::string filename = getDataPath("/NuclearDecay/decay_table.txt"); + std::string filename = getDataPath("/NuclearDecay/decayTable.txt"); std::ifstream infile(filename.c_str()); if (!infile.good()) throw std::runtime_error( "mpc::NuclearDecay: could not open file " + filename); - decayTable.resize(31 * 57); + decayTable.resize(27 * 31); while (infile.good()) { if (infile.peek() != '#') { InteractionState decay; int Z, N; - infile >> Z >> N >> decay.distance >> decay.channel; + infile >> Z >> N >> decay.channel >> decay.distance; decay.distance *= c_light; // mean decay distance [m] if (infile) decayTable[Z * 31 + N].push_back(decay); @@ -85,14 +85,14 @@ void NuclearDecay::performInteraction(Candidate *candidate) const { candidate->clearInteractionStates(); // parse decay channels - int nBeta = digit(decay.channel, 10000); + int nBetaMinus = digit(decay.channel, 10000); int nBetaPlus = digit(decay.channel, 1000); int nAlpha = digit(decay.channel, 100); int nProton = digit(decay.channel, 10); int nNeutron = digit(decay.channel, 1); // perform decays - for (size_t i = 0; i < nBeta; i++) + for (size_t i = 0; i < nBetaMinus; i++) betaDecay(candidate, false); for (size_t i = 0; i < nBetaPlus; i++) betaDecay(candidate, true); diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 5a30012e2..485502007 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -27,10 +27,6 @@ void PhotoDisintegration::init(int photonField) { setDescription("PhotoDisintegration:IRB"); init(getDataPath("PhotoDisintegration/PDtable_IRB.txt")); break; - case CMB_IRB: - setDescription("PhotoDisintegration:CMB_IRB"); - init(getDataPath("PhotoDisintegration/PDtable_CMB_IRB.txt")); - break; default: throw std::runtime_error( "mpc::PhotoDisintegration: unknown photon background"); diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 966c1755a..935e90659 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -94,7 +94,6 @@ TEST(NuclearDecay, Neutron) { InteractionState state; double tau = 0; for (int i = 0; i < 100000; i++) { -// std::cout << i << std::endl; decay.setNextInteraction(&candidate, state); tau += state.distance; } @@ -178,11 +177,11 @@ TEST(NuclearDecay, AllWorking) { Candidate c; InteractionState interaction; - std::ifstream infile(getDataPath("/NuclearDecay/decay_table.txt").c_str()); + std::ifstream infile(getDataPath("/NuclearDecay/decayTable.txt").c_str()); while (infile.good()) { if (infile.peek() != '#') { - int Z, N, x, channel; - infile >> Z >> N >> x >> interaction.channel; + int Z, N, channel, foo; + infile >> Z >> N >> interaction.channel >> foo; c.current.setId(getNucleusId(Z + N, Z)); c.current.setEnergy(80 * EeV); @@ -194,13 +193,6 @@ TEST(NuclearDecay, AllWorking) { infile.close(); } -//TEST(PhotoDisintegration, Backgrounds) { -// // Test if all interaction can be initialized with all backgrounds. -// PhotoDisintegration pd1(CMB); -// PhotoDisintegration pd2(IRB); -// PhotoDisintegration pd3(CMB_IRB); -//} - TEST(PhotoDisintegration, Carbon) { // Test if a 100 EeV C-12 nucleus photo-disintegrates (at least once) over a distance of 50 Mpc. // This test can stochastically fail if no interaction occurs over 50 Mpc. @@ -236,7 +228,7 @@ TEST(PhotoDisintegration, Carbon) { TEST(PhotoDisintegration, Iron) { // Test if a 100 EeV Fe-56 nucleus photo-disintegrates (at least once) over a distance of 50 Mpc. // This test can stochastically fail if no interaction occurs over 50 Mpc. - PhotoDisintegration pd; + PhotoDisintegration pd(IRB); Candidate c; c.current.setId(getNucleusId(56, 26)); c.current.setEnergy(100 * EeV); @@ -276,14 +268,47 @@ TEST(PhotoDisintegration, LimitNextStep) { EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); } -TEST(PhotoDisintegration, AllWorking) { +TEST(PhotoDisintegration, AllWorkingCMB) { // Test if all photo-disintegrations are working. - PhotoDisintegration pd; + PhotoDisintegration pd(CMB); + Candidate c; + InteractionState interaction; + + std::ifstream infile( + getDataPath("PhotoDisintegration/PDtable_CMB.txt").c_str()); + std::string line; + while (std::getline(infile, line)) { + if (line[0] == '#') + continue; + std::stringstream lineStream(line); + int Z, N; + lineStream >> Z; + lineStream >> N; + lineStream >> interaction.channel; + + double y; + for (size_t i = 0; i < 200; i++) { + lineStream >> y; + EXPECT_TRUE(lineStream); + // test if all 200 entries are present + } + + c.current.setId(getNucleusId(Z + N, Z)); + c.current.setEnergy(80 * EeV); + c.setInteractionState(pd.getDescription(), interaction); + pd.performInteraction(&c); + } + infile.close(); +} + +TEST(PhotoDisintegration, AllWorkingIRB) { + // Test if all photo-disintegrations are working. + PhotoDisintegration pd(IRB); Candidate c; InteractionState interaction; std::ifstream infile( - getDataPath("PhotoDisintegration/PDtable_CMB_IRB.txt").c_str()); + getDataPath("PhotoDisintegration/PDtable_IRB.txt").c_str()); std::string line; while (std::getline(infile, line)) { if (line[0] == '#') From d509bc820cf80f42b2785d021db56967ad95fd3d Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 8 May 2012 19:06:38 +0200 Subject: [PATCH 0092/1298] add beta+ correction in nuclear decay fix small bug in nuclear mass --- include/mpc/Units.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/mpc/Units.h b/include/mpc/Units.h index 1d185431f..05fee567a 100644 --- a/include/mpc/Units.h +++ b/include/mpc/Units.h @@ -27,6 +27,7 @@ static const double amu = 1.660538921e-27 * kilogram; static const double mass_proton = 1.67262158e-27 * kilogram; static const double mass_neutron = 1.67492735e-27 * kilogram; static const double mass_electron = 9.10938291e-31 * kilogram; +static const double h_planck = 6.62606957e-34 * joule * second; // other units From 341ef4a49c1df8923a08314b1a23dd9cb260e200 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 10 May 2012 11:33:14 +0200 Subject: [PATCH 0093/1298] fix FindFFTW.cmake --- cmake/FindFFTW.cmake | 15 ++++++--------- test/python/testNuclearDecay.py | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/cmake/FindFFTW.cmake b/cmake/FindFFTW.cmake index e622ea62b..7dc003c1d 100644 --- a/cmake/FindFFTW.cmake +++ b/cmake/FindFFTW.cmake @@ -8,16 +8,13 @@ find_library(FFTW_LIBRARY fftw3) find_library(FFTWF_LIBRARY fftw3f) set(FFTW_FOUND FALSE) -if(FFTW_INCLUDE_DIR AND FFTW_LIBRARY) +if(FFTW_INCLUDE_DIR AND FFTW_LIBRARY AND FFTWF_LIBRARY) set(FFTW_FOUND TRUE) endif() -mark_as_advanced( -FFTW_INCLUDE_DIR -FFTW_LIBRARY -FFTW_FOUND -) +mark_as_advanced(FFTW_INCLUDE_DIR FFTW_LIBRARY FFTWF_LIBRARY FFTW_FOUND) -#MESSAGE("FFTW_FOUND=${FFTW_FOUND}\n" -# "FFTW_LIBRARY=${FFTW_LIBRARY}\n" -# "FFTW_INCLUDE_DIR=${FFTW_INCLUDE_DIR}") \ No newline at end of file +MESSAGE("FFTW_FOUND=${FFTW_FOUND}\n" + "FFTW_LIBRARY=${FFTW_LIBRARY}\n" + "FFTWF_LIBRARY=${FFTWF_LIBRARY}\n" + "FFTW_INCLUDE_DIR=${FFTW_INCLUDE_DIR}") \ No newline at end of file diff --git a/test/python/testNuclearDecay.py b/test/python/testNuclearDecay.py index 91fce003e..7604c6030 100644 --- a/test/python/testNuclearDecay.py +++ b/test/python/testNuclearDecay.py @@ -13,13 +13,13 @@ ### read and evaluate decay tables -data = genfromtxt(getDataPath('NuclearDecay/decay_table.txt'), comments='#') +data = genfromtxt(getDataPath('NuclearDecay/decayTable.txt'), comments='#') modes = zeros((27, 31)) times = zeros((27, 31)) multi = zeros((27, 31)) inclu = zeros((27, 31)) -for z, n, time, mode in data: +for z, n, mode, time in data: inclu[z,n] += 1/time multi[z,n] += 1 if modes[z, n] != 0: @@ -41,8 +41,8 @@ fig = figure() ax = fig.add_subplot(111) ax.imshow(ma.masked_array(modes, modes==0), aspect='equal', interpolation='nearest', origin='lower') -ax.set_xlabel('neutrons') -ax.set_ylabel('protons') +ax.set_xlabel('Neutrons') +ax.set_ylabel('Protons') ax.grid() ax.text(0.41, 0.59, 'beta+ decay', ha='center', va='center', rotation=40, transform=ax.transAxes) ax.text(0.48, 0.52, 'stable', ha='center', va='center', rotation=40, transform=ax.transAxes) @@ -57,9 +57,9 @@ cbar = fig.colorbar(im, orientation='horizontal') cbar.set_ticks(logspace(-3,3,7)) cbar.set_ticklabels(['0.001','0.01','0.1','1','10','100','1000']) -cbar.set_label('inclusive decay time [s]') -ax.set_xlabel('neutrons') -ax.set_ylabel('protons') +cbar.set_label('Lifetime [s]') +ax.set_xlabel('Neutrons') +ax.set_ylabel('Protons') ax.grid() fig.savefig('NuclearDecay_lifetime.png',bbox_inches='tight') @@ -68,9 +68,9 @@ mmulti = ma.masked_array(multi, multi==0) im = ax.imshow(mmulti, aspect='equal', interpolation='nearest', origin='lower') cbar = fig.colorbar(im, orientation='horizontal') -cbar.set_label('decay channels') -ax.set_xlabel('neutrons') -ax.set_ylabel('protons') +cbar.set_label('\# Decay Channels') +ax.set_xlabel('Neutrons') +ax.set_ylabel('Protons') ax.grid() fig.savefig('NuclearDecay_multiplicity.png',bbox_inches='tight') From 4c6697ae14e9bef54a770bb1d3d3085627ab5e86 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 10 May 2012 18:11:06 +0200 Subject: [PATCH 0094/1298] improve FindFFTW.cmake --- cmake/FindFFTW.cmake | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cmake/FindFFTW.cmake b/cmake/FindFFTW.cmake index 7dc003c1d..46e046253 100644 --- a/cmake/FindFFTW.cmake +++ b/cmake/FindFFTW.cmake @@ -14,7 +14,6 @@ endif() mark_as_advanced(FFTW_INCLUDE_DIR FFTW_LIBRARY FFTWF_LIBRARY FFTW_FOUND) -MESSAGE("FFTW_FOUND=${FFTW_FOUND}\n" - "FFTW_LIBRARY=${FFTW_LIBRARY}\n" - "FFTWF_LIBRARY=${FFTWF_LIBRARY}\n" - "FFTW_INCLUDE_DIR=${FFTW_INCLUDE_DIR}") \ No newline at end of file +MESSAGE("-- Found FFTW3:\n" + "-- Include: ${FFTW_INCLUDE_DIR}\n" + "-- Library: ${FFTW_LIBRARY}, ${FFTWF_LIBRARY}") \ No newline at end of file From b7831d30a6643a2f44982f7876097c0c9b347c63 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 10 May 2012 18:11:29 +0200 Subject: [PATCH 0095/1298] fix Vector3 theta --- include/mpc/Vector3.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/include/mpc/Vector3.h b/include/mpc/Vector3.h index c8632764b..1aaa83c8f 100644 --- a/include/mpc/Vector3.h +++ b/include/mpc/Vector3.h @@ -173,15 +173,19 @@ class Vector3 { if (fabs(x) < eps && fabs(y) < eps && fabs(z) < eps) return 0.0; else - return std::atan2(sqrt(x * x + y * y), z); + return atan2((T)sqrt(x * x + y * y), z); } T angleTo(const Vector3 &v) const { T cosdistance = this->dot(v) / this->mag() / v.mag(); // In some directions cosdistance is > 1 on some compilers // This ensures that the correct result is returned - return (cosdistance >= 1.) ? - 0 : ((cosdistance <= -1.) ? M_PI : acos(cosdistance)); + if (cosdistance >= 1.) + return 0; + if (cosdistance <= -1.) + return M_PI; + else + return acos(cosdistance); } bool isParallelTo(const Vector3 &v, T maxAngle) const { From 752e4485c8fe2d7d80c7683c7b2ef2e147b87580 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 10 May 2012 18:12:27 +0200 Subject: [PATCH 0096/1298] change Boundaries to default makeInactive = true --- src/module/BreakCondition.cpp | 6 +++--- test/testBreakCondition.cpp | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp index 35a1671f5..ec46b4116 100644 --- a/src/module/BreakCondition.cpp +++ b/src/module/BreakCondition.cpp @@ -73,7 +73,7 @@ CubicBoundary::CubicBoundary(Vector3d origin, double size, std::string flag, this->size = size; this->flag = flag; this->flagValue = flagValue; - this->makeInactive = false; + this->makeInactive = true; this->limitStep = false; this->margin = 0; updateDescription(); @@ -120,7 +120,7 @@ SphericalBoundary::SphericalBoundary(Vector3d center, double radius, this->radius = radius; this->flag = flag; this->flagValue = flagValue; - this->makeInactive = false; + this->makeInactive = true; this->limitStep = false; this->margin = 0; updateDescription(); @@ -165,7 +165,7 @@ EllipsoidalBoundary::EllipsoidalBoundary(Vector3d focalPoint1, this->majorAxis = majorAxis; this->flag = flag; this->flagValue = flagValue; - this->makeInactive = false; + this->makeInactive = true; this->limitStep = false; this->margin = 0; updateDescription(); diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index 9a79ce2d5..f363bcd45 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -79,6 +79,8 @@ TEST(CubicBoundary, outside) { CubicBoundary cube(Vector3d(0, 0, 0), 10); Candidate candidate; candidate.current.setPosition(Vector3d(10.1, 5, 5)); + + cube.setMakeInactive(false); cube.process(&candidate); EXPECT_TRUE(candidate.isActive()); EXPECT_TRUE(candidate.hasProperty("OutOfBounds")); @@ -103,13 +105,17 @@ TEST(SphericalBoundary, inside) { Candidate candidate; candidate.current.setPosition(Vector3d(9, 0, 0)); sphere.process(&candidate); + EXPECT_TRUE(candidate.isActive()); EXPECT_FALSE(candidate.hasProperty("OutOfBounds")); } TEST(SphericalBoundary, outside) { SphericalBoundary sphere(Vector3d(0, 0, 0), 10, "PassedGalacticBorder"); + Candidate candidate; candidate.current.setPosition(Vector3d(0, -10.1, 0)); + + sphere.setMakeInactive(false); sphere.process(&candidate); EXPECT_TRUE(candidate.isActive()); EXPECT_TRUE(candidate.hasProperty("PassedGalacticBorder")); @@ -141,6 +147,8 @@ TEST(EllipsoidalBoundary, outside) { EllipsoidalBoundary ellipsoid(Vector3d(-5, 0, 0), Vector3d(5, 0, 0), 15); Candidate candidate; candidate.current.setPosition(Vector3d(0, 25, 0)); + + ellipsoid.setMakeInactive(false); ellipsoid.process(&candidate); EXPECT_TRUE(candidate.hasProperty("OutOfBounds")); EXPECT_TRUE(candidate.isActive()); From 288b68968c35a853d6c6d3859130e93976f4b59f Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 11 May 2012 10:39:02 +0200 Subject: [PATCH 0097/1298] remove search for FFTW (double precision) --- CMakeLists.txt | 16 +- cmake/FindFFTW.cmake | 19 --- cmake/FindFFTW3F.cmake | 17 ++ include/mpc/magneticField/SPHMagneticField.h | 5 +- .../magneticField/SPHTurbulentMagneticField.h | 28 ++-- python/mpc.i | 6 +- test/testMagneticField.cpp | 150 +++++++++--------- 7 files changed, 123 insertions(+), 118 deletions(-) delete mode 100644 cmake/FindFFTW.cmake create mode 100644 cmake/FindFFTW3F.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 6da687377..e56bd4d64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,11 +14,11 @@ list(APPEND MPC_EXTRA_LIBRARIES ${GSL_LIBRARIES} ${GSLCBLAS_LIBRARIES}) list(APPEND MPC_EXTRA_INCLUDES ${GSL_INCLUDE_DIR}) # fftw needed for TurbulentMagneticField -find_package(FFTW) -if (FFTW_FOUND) +find_package(FFTW3F) +if (FFTW3F_FOUND) list(APPEND MPC_EXTRA_SOURCES src/magneticField/TurbulentMagneticField.cpp) - list(APPEND MPC_EXTRA_LIBRARIES ${FFTW_LIBRARY} ${FFTWF_LIBRARY}) -endif (FFTW_FOUND) + list(APPEND MPC_EXTRA_LIBRARIES ${FFTW3F_LIBRARY}) +endif (FFTW3F_FOUND) # gadget needed for SPHMagneticField and SPHTurbulentMagneticField find_package(Gadget) @@ -28,10 +28,10 @@ if (GADGET_FOUND) list(APPEND MPC_EXTRA_LIBRARIES ${GADGET_LIBRARY}) add_definitions (-DMPC_HAVE_GADGET) list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_GADGET) - # fftw needed for SPHTurbulentMagneticField - if (FFTW_FOUND) - list(APPEND MPC_EXTRA_SOURCES src/magneticField/SPHTurbulentMagneticField.cpp) - endif (FFTW_FOUND) +# # fftw needed for SPHTurbulentMagneticField +# if (FFTW_FOUND) +# list(APPEND MPC_EXTRA_SOURCES src/magneticField/SPHTurbulentMagneticField.cpp) +# endif (FFTW_FOUND) endif (GADGET_FOUND) # Google Performance Tools optional diff --git a/cmake/FindFFTW.cmake b/cmake/FindFFTW.cmake deleted file mode 100644 index 46e046253..000000000 --- a/cmake/FindFFTW.cmake +++ /dev/null @@ -1,19 +0,0 @@ -# FFTW_INCLUDE_DIR = fftw3.h -# FFTW_LIBRARY = libfftw3.a -# FFTWF_LIBRARY = libfftw3f.a -# FFTW_FOUND = true if FFTW3 is found - -find_path(FFTW_INCLUDE_DIR fftw3.h) -find_library(FFTW_LIBRARY fftw3) -find_library(FFTWF_LIBRARY fftw3f) - -set(FFTW_FOUND FALSE) -if(FFTW_INCLUDE_DIR AND FFTW_LIBRARY AND FFTWF_LIBRARY) - set(FFTW_FOUND TRUE) -endif() - -mark_as_advanced(FFTW_INCLUDE_DIR FFTW_LIBRARY FFTWF_LIBRARY FFTW_FOUND) - -MESSAGE("-- Found FFTW3:\n" - "-- Include: ${FFTW_INCLUDE_DIR}\n" - "-- Library: ${FFTW_LIBRARY}, ${FFTWF_LIBRARY}") \ No newline at end of file diff --git a/cmake/FindFFTW3F.cmake b/cmake/FindFFTW3F.cmake new file mode 100644 index 000000000..aed570a49 --- /dev/null +++ b/cmake/FindFFTW3F.cmake @@ -0,0 +1,17 @@ +# Find FFTW3 with single precision. Sets +# FFTW3F_FOUND = true if fftw3f is found +# FFTW3F_INCLUDE_DIR = fftw3.h +# FFTW3F_LIBRARY = libfftw3f.a .so + +find_path(FFTW3F_INCLUDE_DIR fftw3.h) +find_library(FFTW3F_LIBRARY fftw3f) + +set(FFTW3F_FOUND FALSE) +if(FFTW3F_INCLUDE_DIR AND FFTW3F_LIBRARY) + set(FFTW3F_FOUND TRUE) + MESSAGE("-- Found FFTW3 with single precision (FFTW3F):\n" + "-- Include: ${FFTW3F_INCLUDE_DIR}\n" + "-- Library: ${FFTW3F_LIBRARY}") +endif() + +mark_as_advanced(FFTW3F_INCLUDE_DIR FFTW3F_LIBRARY FFTW3F_FOUND) \ No newline at end of file diff --git a/include/mpc/magneticField/SPHMagneticField.h b/include/mpc/magneticField/SPHMagneticField.h index b0a5359ea..d1906ea65 100644 --- a/include/mpc/magneticField/SPHMagneticField.h +++ b/include/mpc/magneticField/SPHMagneticField.h @@ -31,7 +31,6 @@ class SPHMagneticField: public MagneticField { SPHMagneticField(size_t gridSize, const std::string filename); Vector3d getField(const Vector3d &position) const; void updateSimulationVolume(const Vector3d &origin, double size); - }; /** @@ -39,9 +38,9 @@ class SPHMagneticField: public MagneticField { @brief Wrapper for gadget::SampledMagneticField */ class SPHMagneticFieldGrid: public MagneticField { - size_t samples; gadget::SampledMagneticField field; gadget::FileDatabase database; + size_t samples; std::string cachePrefix; bool cacheEnabled; public: @@ -51,7 +50,7 @@ class SPHMagneticFieldGrid: public MagneticField { Vector3d getField(const Vector3d &position) const; void updateSimulationVolume(const Vector3d &origin, double size); void setCachePrefix(const std::string &prefix); - void setCacheEnabled(bool enabled ); + void setCacheEnabled(bool enabled); }; } // namespace mpc diff --git a/include/mpc/magneticField/SPHTurbulentMagneticField.h b/include/mpc/magneticField/SPHTurbulentMagneticField.h index 50b12c578..10ea39341 100644 --- a/include/mpc/magneticField/SPHTurbulentMagneticField.h +++ b/include/mpc/magneticField/SPHTurbulentMagneticField.h @@ -1,19 +1,19 @@ #ifndef MPC_SPHTURBULENTMAGNETICFIELD_H_ #define MPC_SPHTURBULENTMAGNETICFIELD_H_ -#include "mpc/magneticField/TurbulentMagneticField.h" - -namespace mpc { - -/** - @class SPHTurbulentMagneticField - @brief Random turbulent magnetic field on a cubic grid modulated with large scale structure. - */ -class SPHTurbulentMagneticField: public TurbulentMagneticField { -public: - void modulate(const std::string filename); -}; - -} // namespace mpc +//#include "mpc/magneticField/TurbulentMagneticField.h" +// +//namespace mpc { +// +///** +// @class SPHTurbulentMagneticField +// @brief Random turbulent magnetic field on a cubic grid modulated with large scale structure. +// */ +//class SPHTurbulentMagneticField: public TurbulentMagneticField { +//public: +// void modulate(const std::string filename); +//}; +// +//} // namespace mpc #endif /* MPC_SPHTURBULENTMAGNETICFIELD_H_ */ diff --git a/python/mpc.i b/python/mpc.i index 69c1fbc46..d6186bb54 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -44,6 +44,7 @@ #include "mpc/magneticField/MagneticFieldGrid.h" #include "mpc/magneticField/TurbulentMagneticField.h" #include "mpc/magneticField/SPHMagneticField.h" +#include "mpc/magneticField/SPHTurbulentMagneticField.h" #include "mpc/Referenced.h" #include "mpc/Candidate.h" @@ -91,10 +92,11 @@ %template(stdMagneticFieldVector) std::vector< mpc::ref_ptr >; %template(MagneticFieldRefPtr) mpc::ref_ptr; %include "mpc/magneticField/MagneticField.h" -%include "mpc/magneticField/MagneticFieldGrid.h" %include "mpc/magneticField/UniformMagneticField.h" -%include "mpc/magneticField/SPHMagneticField.h" +%include "mpc/magneticField/MagneticFieldGrid.h" %include "mpc/magneticField/TurbulentMagneticField.h" +%include "mpc/magneticField/SPHMagneticField.h" +%include "mpc/magneticField/SPHTurbulentMagneticField.h" %include "mpc/ExplicitRungeKutta.h" %include "mpc/PhasePoint.h" diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index c209ce0f6..05fd2cc35 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -3,84 +3,90 @@ #include "mpc/magneticField/TurbulentMagneticField.h" #include "mpc/Units.h" +#ifdef MPC_HAVE_GADGET +#include "mpc/magneticField/SPHMagneticField.h" +#endif + #include "gtest/gtest.h" -#include "fftw3.h" -#include namespace mpc { -TEST(testUniformMagneticField, SimpleTest) { - UniformMagneticField B(Vector3d(-1, 5, 3)); - Vector3d b = B.getField(Vector3d(1, 0, 0)); - EXPECT_DOUBLE_EQ(b.x, -1); - EXPECT_DOUBLE_EQ(b.y, 5); - EXPECT_DOUBLE_EQ(b.z, 3); -} - -TEST(testTurbulentMagneticFieldGrid, PeriodicBoundaries) { - // B(x+a*n) = B(x) - - size_t n = 64; - TurbulentMagneticField bField(Vector3d(0, 0, 0), n, 1); - bField.initialize(2, 8, 1, -11. / 3.); - - Vector3d pos(1.1, 2.1, 3.1); - Vector3d b = bField.getField(pos); - Vector3d b1 = bField.getField(pos + Vector3d(n, 0, 0)); - Vector3d b2 = bField.getField(pos + Vector3d(0, n, 0)); - Vector3d b3 = bField.getField(pos + Vector3d(0, 0, n)); - - EXPECT_FLOAT_EQ(b.x, b1.x); - EXPECT_FLOAT_EQ(b.y, b1.y); - EXPECT_FLOAT_EQ(b.z, b1.z); - - EXPECT_FLOAT_EQ(b.x, b2.x); - EXPECT_FLOAT_EQ(b.y, b2.y); - EXPECT_FLOAT_EQ(b.z, b2.z); - - EXPECT_FLOAT_EQ(b.x, b3.x); - EXPECT_FLOAT_EQ(b.y, b3.y); - EXPECT_FLOAT_EQ(b.z, b3.z); -} - -TEST(testTurbulentMagneticFieldGrid, ZeroMean) { - // = 0 - - size_t n = 64; - TurbulentMagneticField bField(Vector3d(0, 0, 0), n, 1); - bField.initialize(2, 8, 1, -11. / 3.); - - Vector3d b(0, 0, 0); - for (unsigned int ix = 0; ix < n; ix++) - for (unsigned int iy = 0; iy < n; iy++) - for (unsigned int iz = 0; iz < n; iz++) - b += bField.getField(Vector3d(ix, iy, iz)); - - b /= n * n * n; - - double precision = 1e-7; - EXPECT_NEAR(b.x, 0, precision); - EXPECT_NEAR(b.y, 0, precision); - EXPECT_NEAR(b.z, 0, precision); +//TEST(testUniformMagneticField, SimpleTest) { +// UniformMagneticField B(Vector3d(-1, 5, 3)); +// Vector3d b = B.getField(Vector3d(1, 0, 0)); +// EXPECT_DOUBLE_EQ(b.x, -1); +// EXPECT_DOUBLE_EQ(b.y, 5); +// EXPECT_DOUBLE_EQ(b.z, 3); +//} +// +//TEST(testTurbulentMagneticFieldGrid, PeriodicBoundaries) { +// // Test turbulent field for periodic boundaries: B(x+a*n) = B(x) +// size_t n = 64; +// TurbulentMagneticField bField(Vector3d(0, 0, 0), n, 1); +// bField.initialize(2, 8, 1, -11. / 3.); +// +// Vector3d pos(1.1, 2.1, 3.1); +// Vector3d b = bField.getField(pos); +// Vector3d b1 = bField.getField(pos + Vector3d(n, 0, 0)); +// Vector3d b2 = bField.getField(pos + Vector3d(0, n, 0)); +// Vector3d b3 = bField.getField(pos + Vector3d(0, 0, n)); +// +// EXPECT_FLOAT_EQ(b.x, b1.x); +// EXPECT_FLOAT_EQ(b.y, b1.y); +// EXPECT_FLOAT_EQ(b.z, b1.z); +// +// EXPECT_FLOAT_EQ(b.x, b2.x); +// EXPECT_FLOAT_EQ(b.y, b2.y); +// EXPECT_FLOAT_EQ(b.z, b2.z); +// +// EXPECT_FLOAT_EQ(b.x, b3.x); +// EXPECT_FLOAT_EQ(b.y, b3.y); +// EXPECT_FLOAT_EQ(b.z, b3.z); +//} +// +//TEST(testTurbulentMagneticFieldGrid, ZeroMean) { +// // Test turbulent field for zero mean: = 0 +// size_t n = 64; +// TurbulentMagneticField bField(Vector3d(0, 0, 0), n, 1); +// bField.initialize(2, 8, 1, -11. / 3.); +// +// Vector3d b(0, 0, 0); +// for (unsigned int ix = 0; ix < n; ix++) +// for (unsigned int iy = 0; iy < n; iy++) +// for (unsigned int iz = 0; iz < n; iz++) +// b += bField.getField(Vector3d(ix, iy, iz)); +// +// b /= n * n * n; +// double precision = 1e-7; +// EXPECT_NEAR(b.x, 0, precision); +// EXPECT_NEAR(b.y, 0, precision); +// EXPECT_NEAR(b.z, 0, precision); +//} +// +//TEST(testTurbulentMagneticFieldGrid, Brms) { +// // Test turbulent field for correct RMS strength: = Brms^2 +// size_t n = 64; +// TurbulentMagneticField bField(Vector3d(0, 0, 0), n, 1); +// bField.initialize(2, 8, 1, -11. / 3.); +// +// double brms = 0; +// for (unsigned int ix = 0; ix < n; ix++) +// for (unsigned int iy = 0; iy < n; iy++) +// for (unsigned int iz = 0; iz < n; iz++) +// brms += bField.getField(Vector3d(ix, iy, iz)).mag2(); +// brms = sqrt(brms / n / n / n); +// +// double precision = 1e-7; +// EXPECT_NEAR(brms, 1, precision); +//} + +TEST(testSPHMagneticField, construction) { + SPHMagneticField(Vector3d(120, 120, 120) * Mpc, 8 * Mpc, 64, "/home/walz/software/mpc/data/mhd_z.db"); } -TEST(testTurbulentMagneticFieldGrid, Brms) { - // = Brms^2 - - size_t n = 64; - TurbulentMagneticField bField(Vector3d(0, 0, 0), n, 1); - bField.initialize(2, 8, 1, -11. / 3.); - - double brms = 0; - for (unsigned int ix = 0; ix < n; ix++) - for (unsigned int iy = 0; iy < n; iy++) - for (unsigned int iz = 0; iz < n; iz++) - brms += bField.getField(Vector3d(ix, iy, iz)).mag2(); - brms = sqrt(brms / n / n / n); - - double precision = 1e-7; - EXPECT_NEAR(brms, 1, precision); -} +//TEST(testSPHMagneticFieldGrid, construction) { +// SPHMagneticFieldGrid(Vector3d(120, 120, 120) * Mpc, 8 * Mpc, 8, "/home/walz/software/mpc/data/mhd1.db"); +//} int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); From 8a2f5a078420121b3b711803f40bbb6759ddfa35 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 14 May 2012 12:22:50 +0200 Subject: [PATCH 0098/1298] add SPHTurbulentMagneticField --- CMakeLists.txt | 10 +- include/mpc/magneticField/SPHMagneticField.h | 1 + .../magneticField/SPHTurbulentMagneticField.h | 31 ++-- src/magneticField/SPHMagneticField.cpp | 6 + .../SPHTurbulentMagneticField.cpp | 28 +++- test/testMagneticField.cpp | 147 +++++++++--------- 6 files changed, 126 insertions(+), 97 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e56bd4d64..dea9f3c34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ find_package(GSL REQUIRED) list(APPEND MPC_EXTRA_LIBRARIES ${GSL_LIBRARIES} ${GSLCBLAS_LIBRARIES}) list(APPEND MPC_EXTRA_INCLUDES ${GSL_INCLUDE_DIR}) -# fftw needed for TurbulentMagneticField +# fftw3f needed for TurbulentMagneticField find_package(FFTW3F) if (FFTW3F_FOUND) list(APPEND MPC_EXTRA_SOURCES src/magneticField/TurbulentMagneticField.cpp) @@ -28,10 +28,10 @@ if (GADGET_FOUND) list(APPEND MPC_EXTRA_LIBRARIES ${GADGET_LIBRARY}) add_definitions (-DMPC_HAVE_GADGET) list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_GADGET) -# # fftw needed for SPHTurbulentMagneticField -# if (FFTW_FOUND) -# list(APPEND MPC_EXTRA_SOURCES src/magneticField/SPHTurbulentMagneticField.cpp) -# endif (FFTW_FOUND) + # fftw3f needed for SPHTurbulentMagneticField + if (FFTW3F_FOUND) + list(APPEND MPC_EXTRA_SOURCES src/magneticField/SPHTurbulentMagneticField.cpp) + endif (FFTW3F_FOUND) endif (GADGET_FOUND) # Google Performance Tools optional diff --git a/include/mpc/magneticField/SPHMagneticField.h b/include/mpc/magneticField/SPHMagneticField.h index d1906ea65..3b65b1922 100644 --- a/include/mpc/magneticField/SPHMagneticField.h +++ b/include/mpc/magneticField/SPHMagneticField.h @@ -30,6 +30,7 @@ class SPHMagneticField: public MagneticField { const std::string filename); SPHMagneticField(size_t gridSize, const std::string filename); Vector3d getField(const Vector3d &position) const; + double getRho(const Vector3d &position) const; void updateSimulationVolume(const Vector3d &origin, double size); }; diff --git a/include/mpc/magneticField/SPHTurbulentMagneticField.h b/include/mpc/magneticField/SPHTurbulentMagneticField.h index 10ea39341..0ce4684a0 100644 --- a/include/mpc/magneticField/SPHTurbulentMagneticField.h +++ b/include/mpc/magneticField/SPHTurbulentMagneticField.h @@ -1,19 +1,22 @@ #ifndef MPC_SPHTURBULENTMAGNETICFIELD_H_ #define MPC_SPHTURBULENTMAGNETICFIELD_H_ -//#include "mpc/magneticField/TurbulentMagneticField.h" -// -//namespace mpc { -// -///** -// @class SPHTurbulentMagneticField -// @brief Random turbulent magnetic field on a cubic grid modulated with large scale structure. -// */ -//class SPHTurbulentMagneticField: public TurbulentMagneticField { -//public: -// void modulate(const std::string filename); -//}; -// -//} // namespace mpc +#include "mpc/magneticField/TurbulentMagneticField.h" + +namespace mpc { + +/** + @class SPHTurbulentMagneticField + @brief Random turbulent magnetic field on a cubic grid modulated with large scale structure. + */ +class SPHTurbulentMagneticField: public TurbulentMagneticField { +public: + SPHTurbulentMagneticField(Vector3d origin, size_t samples, double spacing) : + TurbulentMagneticField(origin, samples, spacing) { + } + void modulate(const std::string filename); +}; + +} // namespace mpc #endif /* MPC_SPHTURBULENTMAGNETICFIELD_H_ */ diff --git a/src/magneticField/SPHMagneticField.cpp b/src/magneticField/SPHMagneticField.cpp index cd6cf86da..16bd050c1 100644 --- a/src/magneticField/SPHMagneticField.cpp +++ b/src/magneticField/SPHMagneticField.cpp @@ -25,6 +25,12 @@ Vector3d SPHMagneticField::getField(const Vector3d &position) const { return bField; } +double SPHMagneticField::getRho(const Vector3d& position) const { + gadget::Vector3f r = gadget::Vector3f(position.x, position.y, position.z); + unsigned int overlaps = 0; + return (double) field.getRho(r / kpc, overlaps); +} + void SPHMagneticField::updateSimulationVolume(const Vector3d &origin, double size) { gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; diff --git a/src/magneticField/SPHTurbulentMagneticField.cpp b/src/magneticField/SPHTurbulentMagneticField.cpp index 12f0783cf..3eda4098c 100644 --- a/src/magneticField/SPHTurbulentMagneticField.cpp +++ b/src/magneticField/SPHTurbulentMagneticField.cpp @@ -3,10 +3,30 @@ namespace mpc { -void modulate(const std::string filename) { - // create sph field - // modulate turbulent field - // destroy sph field, or let it go out of scope +void SPHTurbulentMagneticField::modulate(const std::string filename) { + // create SPH Field to obtain baryon density + SPHMagneticField sphField(origin, spacing * samples, samples, filename); + + // modulate and calculate renormalization + double norm = 0; + for (int ix; ix < samples; ix++) + for (int iy; iy < samples; iy++) + for (int iz; iz < samples; iz++) { + double rho = sphField.getRho( + Vector3d(ix, iy, iz) * spacing + origin); + Vector3f &b = get(ix, iy, iz); + b *= rho; + norm += b.mag2(); + } + + // renormalize + norm = Brms / sqrt(norm / pow(samples, 3)); + for (int ix = 0; ix < samples; ix++) + for (int iy = 0; iy < samples; iy++) + for (int iz = 0; iz < samples; iz++) { + Vector3f &b = get(ix, iy, iz); + b *= norm; + } } } // namespace mpc diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index 05fd2cc35..456ca0dcd 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -5,88 +5,87 @@ #ifdef MPC_HAVE_GADGET #include "mpc/magneticField/SPHMagneticField.h" +#include "mpc/magneticField/SPHTurbulentMagneticField.h" #endif #include "gtest/gtest.h" namespace mpc { -//TEST(testUniformMagneticField, SimpleTest) { -// UniformMagneticField B(Vector3d(-1, 5, 3)); -// Vector3d b = B.getField(Vector3d(1, 0, 0)); -// EXPECT_DOUBLE_EQ(b.x, -1); -// EXPECT_DOUBLE_EQ(b.y, 5); -// EXPECT_DOUBLE_EQ(b.z, 3); -//} -// -//TEST(testTurbulentMagneticFieldGrid, PeriodicBoundaries) { -// // Test turbulent field for periodic boundaries: B(x+a*n) = B(x) -// size_t n = 64; -// TurbulentMagneticField bField(Vector3d(0, 0, 0), n, 1); -// bField.initialize(2, 8, 1, -11. / 3.); -// -// Vector3d pos(1.1, 2.1, 3.1); -// Vector3d b = bField.getField(pos); -// Vector3d b1 = bField.getField(pos + Vector3d(n, 0, 0)); -// Vector3d b2 = bField.getField(pos + Vector3d(0, n, 0)); -// Vector3d b3 = bField.getField(pos + Vector3d(0, 0, n)); -// -// EXPECT_FLOAT_EQ(b.x, b1.x); -// EXPECT_FLOAT_EQ(b.y, b1.y); -// EXPECT_FLOAT_EQ(b.z, b1.z); -// -// EXPECT_FLOAT_EQ(b.x, b2.x); -// EXPECT_FLOAT_EQ(b.y, b2.y); -// EXPECT_FLOAT_EQ(b.z, b2.z); -// -// EXPECT_FLOAT_EQ(b.x, b3.x); -// EXPECT_FLOAT_EQ(b.y, b3.y); -// EXPECT_FLOAT_EQ(b.z, b3.z); -//} -// -//TEST(testTurbulentMagneticFieldGrid, ZeroMean) { -// // Test turbulent field for zero mean: = 0 -// size_t n = 64; -// TurbulentMagneticField bField(Vector3d(0, 0, 0), n, 1); -// bField.initialize(2, 8, 1, -11. / 3.); -// -// Vector3d b(0, 0, 0); -// for (unsigned int ix = 0; ix < n; ix++) -// for (unsigned int iy = 0; iy < n; iy++) -// for (unsigned int iz = 0; iz < n; iz++) -// b += bField.getField(Vector3d(ix, iy, iz)); -// -// b /= n * n * n; -// double precision = 1e-7; -// EXPECT_NEAR(b.x, 0, precision); -// EXPECT_NEAR(b.y, 0, precision); -// EXPECT_NEAR(b.z, 0, precision); -//} -// -//TEST(testTurbulentMagneticFieldGrid, Brms) { -// // Test turbulent field for correct RMS strength: = Brms^2 -// size_t n = 64; -// TurbulentMagneticField bField(Vector3d(0, 0, 0), n, 1); -// bField.initialize(2, 8, 1, -11. / 3.); -// -// double brms = 0; -// for (unsigned int ix = 0; ix < n; ix++) -// for (unsigned int iy = 0; iy < n; iy++) -// for (unsigned int iz = 0; iz < n; iz++) -// brms += bField.getField(Vector3d(ix, iy, iz)).mag2(); -// brms = sqrt(brms / n / n / n); -// -// double precision = 1e-7; -// EXPECT_NEAR(brms, 1, precision); -//} - -TEST(testSPHMagneticField, construction) { - SPHMagneticField(Vector3d(120, 120, 120) * Mpc, 8 * Mpc, 64, "/home/walz/software/mpc/data/mhd_z.db"); +TEST(testUniformMagneticField, SimpleTest) { + UniformMagneticField B(Vector3d(-1, 5, 3)); + Vector3d b = B.getField(Vector3d(1, 0, 0)); + EXPECT_DOUBLE_EQ(b.x, -1); + EXPECT_DOUBLE_EQ(b.y, 5); + EXPECT_DOUBLE_EQ(b.z, 3); } -//TEST(testSPHMagneticFieldGrid, construction) { -// SPHMagneticFieldGrid(Vector3d(120, 120, 120) * Mpc, 8 * Mpc, 8, "/home/walz/software/mpc/data/mhd1.db"); -//} +TEST(testTurbulentMagneticFieldGrid, PeriodicBoundaries) { + // Test turbulent field for periodic boundaries: B(x+a*n) = B(x) + size_t n = 64; + TurbulentMagneticField bField(Vector3d(0, 0, 0), n, 1); + bField.initialize(2, 8, 1, -11. / 3.); + + Vector3d pos(1.1, 2.1, 3.1); + Vector3d b = bField.getField(pos); + Vector3d b1 = bField.getField(pos + Vector3d(n, 0, 0)); + Vector3d b2 = bField.getField(pos + Vector3d(0, n, 0)); + Vector3d b3 = bField.getField(pos + Vector3d(0, 0, n)); + + EXPECT_FLOAT_EQ(b.x, b1.x); + EXPECT_FLOAT_EQ(b.y, b1.y); + EXPECT_FLOAT_EQ(b.z, b1.z); + + EXPECT_FLOAT_EQ(b.x, b2.x); + EXPECT_FLOAT_EQ(b.y, b2.y); + EXPECT_FLOAT_EQ(b.z, b2.z); + + EXPECT_FLOAT_EQ(b.x, b3.x); + EXPECT_FLOAT_EQ(b.y, b3.y); + EXPECT_FLOAT_EQ(b.z, b3.z); +} + +TEST(testTurbulentMagneticFieldGrid, ZeroMean) { + // Test turbulent field for zero mean: = 0 + size_t n = 64; + TurbulentMagneticField bField(Vector3d(0, 0, 0), n, 1); + bField.initialize(2, 8, 1, -11. / 3.); + + Vector3d b(0, 0, 0); + for (int ix = 0; ix < n; ix++) + for (int iy = 0; iy < n; iy++) + for (int iz = 0; iz < n; iz++) + b += bField.getField(Vector3d(ix, iy, iz)); + + b /= n * n * n; + double precision = 1e-7; + EXPECT_NEAR(b.x, 0, precision); + EXPECT_NEAR(b.y, 0, precision); + EXPECT_NEAR(b.z, 0, precision); +} + +TEST(testTurbulentMagneticFieldGrid, Brms) { + // Test turbulent field for correct RMS strength: = Brms^2 + size_t n = 64; + TurbulentMagneticField bField(Vector3d(0, 0, 0), n, 1); + bField.initialize(2, 8, 1, -11. / 3.); + + double brms = 0; + for (int ix = 0; ix < n; ix++) + for (int iy = 0; iy < n; iy++) + for (int iz = 0; iz < n; iz++) + brms += bField.getField(Vector3d(ix, iy, iz)).mag2(); + brms = sqrt(brms / n / n / n); + + double precision = 1e-7; + EXPECT_NEAR(brms, 1, precision); +} + +TEST(testSPHTurbulentMagneticField, construction) { + SPHTurbulentMagneticField bField(Vector3d(80, 80, 80) * Mpc, 64, 40./64); + bField.initialize(2, 8, 1, -11. / 3.); + bField.modulate("/home/walz/software/mpc/data/mhd1.db"); +} int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); From 8488db38ca9dcdc6cd01f2f9b98b3af6b74da9cd Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 16 May 2012 12:10:30 +0200 Subject: [PATCH 0099/1298] improve Vector3, add rotation --- include/mpc/Vector3.h | 217 ++++++++++-------- src/ParticleState.cpp | 2 +- src/magneticField/SPHMagneticField.cpp | 2 +- .../SPHTurbulentMagneticField.cpp | 4 +- src/magneticField/TurbulentMagneticField.cpp | 12 +- src/module/BreakCondition.cpp | 6 +- src/module/DeflectionCK.cpp | 4 +- src/module/Output.cpp | 8 +- src/module/Redshift.cpp | 2 +- test/testCore.cpp | 4 +- test/testMagneticField.cpp | 2 +- 11 files changed, 147 insertions(+), 116 deletions(-) diff --git a/include/mpc/Vector3.h b/include/mpc/Vector3.h index 1aaa83c8f..82e4ed49e 100644 --- a/include/mpc/Vector3.h +++ b/include/mpc/Vector3.h @@ -38,6 +38,130 @@ class Vector3 { x(t), y(t), z(t) { } + void setX(const T x) { + this->x = x; + } + + void setY(const T x) { + this->y = y; + } + + void setZ(const T x) { + this->z = z; + } + + void setXYZ(const T x, const T y, const T z) { + this->x = x; + this->y = y; + this->z = z; + } + + void setRThetaPhi(const T r, const T theta, const T phi) { + this->x = r * sin(theta) * cos(phi); + this->y = r * sin(theta) * sin(phi); + this->z = r * cos(theta); + } + + T getX() const { + return x; + } + + T getY() const { + return y; + } + + T getZ() const { + return z; + } + + T getPhi() const { + T eps = std::numeric_limits::min(); + if (fabs(x) < eps && fabs(y) < eps) + return 0.0; + else + return std::atan2(y, x); + } + + T getTheta() const { + T eps = std::numeric_limits::min(); + if (fabs(x) < eps && fabs(y) < eps && fabs(z) < eps) + return 0.0; + else + return atan2((T) sqrt(x * x + y * y), z); + } + + T getAngleTo(const Vector3 &v) const { + T cosdistance = this->dot(v) / this->getMag() / v.getMag(); + // In some directions cosdistance is > 1 on some compilers + // This ensures that the correct result is returned + if (cosdistance >= 1.) + return 0; + if (cosdistance <= -1.) + return M_PI; + else + return acos(cosdistance); + } + + bool isParallelTo(const Vector3 &v, T maxAngle) const { + T angle = this->getAngleTo(v); + return angle < maxAngle; + } + + T getDistanceTo(const Vector3 &point) const { + Vector3 d = *this - point; + return d.getMag(); + } + + T getMag() const { + return std::sqrt(x * x + y * y + z * z); + } + + T getMag2() const { + return (x * x + y * y + z * z); + } + + Vector3 getUnitVector() const { + return Vector3(x, y, z) / getMag(); + } + + T dot(const Vector3 & p) const { + return x * p.x + y * p.y + z * p.z; + } + + Vector3 cross(const Vector3 & p) const { + return Vector3(y * p.z - p.y * z, z * p.x - p.z * x, + x * p.y - p.x * y); + } + + void rotate(const Vector3 &axis, T angle) { + T c = cos(angle); + T s = sin(angle); + T ux = axis.getX(); + T uy = axis.getY(); + T uz = axis.getZ(); + Vector3 Rx(c + ux * ux * (1 - c), ux * uy * (1 - c) - uz * s, + ux * uz * (1 - c) + uy * s); + Vector3 Ry(uy * ux * (1 - c) + uz * s, c + uy * uy * (1 - c), + uy * uz * (1 - c) - ux * s); + Vector3 Rz(uz * ux * (1 - c) - uy * s, uz * uy * (1 - c) + ux * s, + c + uz * uz * (1 - c)); + this->setXYZ(Rx.dot(*this), Ry.dot(*this), Rz.dot(*this)); + } + + void clamp(T lower, T upper) { + x = std::max(lower, std::min(x, upper)); + y = std::max(lower, std::min(y, upper)); + z = std::max(lower, std::min(z, upper)); + } + + Vector3 floor() const { + return Vector3(std::floor(x), std::floor(y), std::floor(z)); + } + + Vector3 ceil() const { + return Vector3(std::ceil(x), std::ceil(y), std::ceil(z)); + } + bool operator <(const Vector3 &v) const { if (x > v.x) return false; @@ -128,99 +252,6 @@ class Vector3 { z = v.z; return *this; } - - void clamp(T lower, T upper) { - x = std::max(lower, std::min(x, upper)); - y = std::max(lower, std::min(y, upper)); - z = std::max(lower, std::min(z, upper)); - } - - T mag() const { - return std::sqrt(x * x + y * y + z * z); - } - - T mag2() { - return (x * x + y * y + z * z); - } - - T dot(const Vector3 & p) const { - return x * p.x + y * p.y + z * p.z; - } - - Vector3 cross(const Vector3 & p) const { - return Vector3(y * p.z - p.y * z, z * p.x - p.z * x, - x * p.y - p.x * y); - } - - Vector3 floor() const { - return Vector3(std::floor(x), std::floor(y), std::floor(z)); - } - - Vector3 ceil() const { - return Vector3(std::ceil(x), std::ceil(y), std::ceil(z)); - } - - T phi() const { - T eps = std::numeric_limits::min(); - if (fabs(x) < eps && fabs(y) < eps) - return 0.0; - else - return std::atan2(y, x); - } - - T theta() const { - T eps = std::numeric_limits::min(); - if (fabs(x) < eps && fabs(y) < eps && fabs(z) < eps) - return 0.0; - else - return atan2((T)sqrt(x * x + y * y), z); - } - - T angleTo(const Vector3 &v) const { - T cosdistance = this->dot(v) / this->mag() / v.mag(); - // In some directions cosdistance is > 1 on some compilers - // This ensures that the correct result is returned - if (cosdistance >= 1.) - return 0; - if (cosdistance <= -1.) - return M_PI; - else - return acos(cosdistance); - } - - bool isParallelTo(const Vector3 &v, T maxAngle) const { - T angle = this->angleTo(v); - return angle < maxAngle; - } - - T distanceTo(const Vector3 &point) const { - Vector3 d = *this - point; - return d.mag(); - } - - void set(const T x, const T y, const T z) { - this->x = x; - this->y = y; - this->z = z; - } - - void setLower(const Vector3 &v) { - if (v.x < x) - x = v.x; - if (v.y < y) - y = v.y; - if (v.z < z) - z = v.z; - } - - void setUpper(const Vector3 &v) { - if (v.x > x) - x = v.x; - if (v.y > y) - y = v.y; - if (v.z > z) - z = v.z; - } }; template<> diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index deee93308..96d956fb4 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -18,7 +18,7 @@ const Vector3d &ParticleState::getPosition() const { } void ParticleState::setDirection(const Vector3d &dir) { - direction = dir / dir.mag(); + direction = dir / dir.getMag(); } const Vector3d &ParticleState::getDirection() const { diff --git a/src/magneticField/SPHMagneticField.cpp b/src/magneticField/SPHMagneticField.cpp index 16bd050c1..7cd2957af 100644 --- a/src/magneticField/SPHMagneticField.cpp +++ b/src/magneticField/SPHMagneticField.cpp @@ -27,7 +27,7 @@ Vector3d SPHMagneticField::getField(const Vector3d &position) const { double SPHMagneticField::getRho(const Vector3d& position) const { gadget::Vector3f r = gadget::Vector3f(position.x, position.y, position.z); - unsigned int overlaps = 0; + size_t overlaps = 0; return (double) field.getRho(r / kpc, overlaps); } diff --git a/src/magneticField/SPHTurbulentMagneticField.cpp b/src/magneticField/SPHTurbulentMagneticField.cpp index 3eda4098c..213350917 100644 --- a/src/magneticField/SPHTurbulentMagneticField.cpp +++ b/src/magneticField/SPHTurbulentMagneticField.cpp @@ -15,8 +15,8 @@ void SPHTurbulentMagneticField::modulate(const std::string filename) { double rho = sphField.getRho( Vector3d(ix, iy, iz) * spacing + origin); Vector3f &b = get(ix, iy, iz); - b *= rho; - norm += b.mag2(); + b *= pow(rho, 2./3); + norm += b.getMag2(); } // renormalize diff --git a/src/magneticField/TurbulentMagneticField.cpp b/src/magneticField/TurbulentMagneticField.cpp index c5b6d72b5..ccd25d112 100644 --- a/src/magneticField/TurbulentMagneticField.cpp +++ b/src/magneticField/TurbulentMagneticField.cpp @@ -42,8 +42,8 @@ void TurbulentMagneticField::initialize(double lMin, double lMax, double Brms, for (size_t iz = 0; iz < n2; iz++) { i = ix * n * n2 + iy * n2 + iz; - ek.set(K[ix], K[iy], K[iz]); - k = ek.mag(); + ek.setXYZ(K[ix], K[iy], K[iz]); + k = ek.getMag(); // wave outside of turbulent range -> B(k) = 0 if ((k < kMin) || (k > kMax)) { @@ -59,15 +59,15 @@ void TurbulentMagneticField::initialize(double lMin, double lMax, double Brms, // construct an orthogonal base ek, e1, e2 if (ek.isParallelTo(n0, 1e-6)) { // ek parallel to (1,1,1) - e1.set(-1., 1., 0); - e2.set(1., 1., -2.); + e1.setXYZ(-1., 1., 0); + e2.setXYZ(1., 1., -2.); } else { // ek not parallel to (1,1,1) e1 = n0.cross(ek); e2 = ek.cross(e1); } - e1 /= e1.mag(); - e2 /= e2.mag(); + e1 /= e1.getMag(); + e2 /= e2.getMag(); // random orientation perpendicular to k theta = 2 * M_PI * random.rand(); diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp index ec46b4116..e5ee11897 100644 --- a/src/module/BreakCondition.cpp +++ b/src/module/BreakCondition.cpp @@ -48,7 +48,7 @@ void SmallObserverSphere::setMakeInactive(bool makeInactive) { } void SmallObserverSphere::process(Candidate *candidate) const { - double d = (candidate->current.getPosition() - center).mag(); + double d = (candidate->current.getPosition() - center).getMag(); if (d <= radius * 1.01) { candidate->setProperty("Detected", ""); if (makeInactive) { @@ -138,7 +138,7 @@ void SphericalBoundary::setLimitStep(bool limitStep, double margin) { } void SphericalBoundary::process(Candidate *candidate) const { - double d = (candidate->current.getPosition() - center).mag(); + double d = (candidate->current.getPosition() - center).getMag(); if (d >= radius) { candidate->setProperty(flag, flagValue); if (makeInactive) { @@ -184,7 +184,7 @@ void EllipsoidalBoundary::setLimitStep(bool limitStep, double margin) { void EllipsoidalBoundary::process(Candidate *candidate) const { Vector3d pos = candidate->current.getPosition(); - double d = (pos - focalPoint1).mag() + (pos - focalPoint2).mag(); + double d = pos.getDistanceTo(focalPoint1) + pos.getDistanceTo(focalPoint2); if (d >= majorAxis) { candidate->setProperty(flag, flagValue); if (makeInactive) { diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index 2973d1695..f5cf11d82 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -22,7 +22,7 @@ class LorentzForce: public ExplicitRungeKutta::F { } PhasePoint operator()(double t, const PhasePoint &v) { - Vector3d velocity = v.b / v.b.mag() * c_light; + Vector3d velocity = v.b.getUnitVector() * c_light; Vector3d B(0, 0, 0); try { B = field->getField(v.a); @@ -97,7 +97,7 @@ void DeflectionCK::process(Candidate *candidate) const { } while (r > 1 && h >= minimumStep); candidate->current.setPosition(yOut.a); - candidate->current.setDirection(yOut.b / yOut.b.mag()); + candidate->current.setDirection(yOut.b.getUnitVector()); candidate->setCurrentStep(hTry * c_light); candidate->setNextStep(h * c_light); } diff --git a/src/module/Output.cpp b/src/module/Output.cpp index a5ea2a8a0..d79186e46 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -69,7 +69,7 @@ void ConditionalOutput::process(Candidate *candidate) const { const Vector3d &dir = candidate->current.getDirection(); p += ::sprintf(buffer + p, ", %f, %f, %f", - candidate->current.getEnergy() / EeV, dir.phi(), dir.theta()); + candidate->current.getEnergy() / EeV, dir.getPhi(), dir.getTheta()); p += ::sprintf(buffer + p, ", %f", candidate->getTrajectoryLength() / Mpc); @@ -82,7 +82,7 @@ void ConditionalOutput::process(Candidate *candidate) const { const Vector3d &idir = candidate->initial.getDirection(); p += ::sprintf(buffer + p, ", %f, %f, %f\n", - candidate->initial.getEnergy() / EeV, idir.phi(), idir.theta()); + candidate->initial.getEnergy() / EeV, idir.getPhi(), idir.getTheta()); #pragma omp critical { @@ -108,8 +108,8 @@ void ShellOutput::process(Candidate *candidate) const { std::cout << candidate->current.getId() << ", "; std::cout << candidate->current.getEnergy() / EeV << " EeV, "; std::cout << candidate->current.getPosition() / Mpc << " Mpc, "; - std::cout << candidate->current.getDirection().phi() << " / "; - std::cout << candidate->current.getDirection().theta(); + std::cout << candidate->current.getDirection().getPhi() << " / "; + std::cout << candidate->current.getDirection().getTheta(); std::cout << std::endl; } } diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index 5874ca9d1..b770476e6 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -8,7 +8,7 @@ SimpleRedshift::SimpleRedshift(Vector3d center) { } void SimpleRedshift::process(Candidate *candidate) const { - double d = (candidate->current.getPosition() - center).mag(); + double d = candidate->current.getPosition().getDistanceTo(center); double z = 0.024 * d / 100 / Mpc; double dz = candidate->getRedshift() - z; diff --git a/test/testCore.cpp b/test/testCore.cpp index f77b62fb4..a64b10b91 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -21,14 +21,14 @@ TEST(ParticleState, direction) { ParticleState particle; Vector3d v(1, 2, 3); particle.setDirection(v); - EXPECT_TRUE(particle.getDirection() == v / v.mag()); + EXPECT_TRUE(particle.getDirection() == v.getUnitVector()); } TEST(ParticleState, velocity) { ParticleState particle; Vector3d v(1, 1, 0); particle.setDirection(v); - EXPECT_TRUE(particle.getVelocity() == v / v.mag() * c_light); + EXPECT_TRUE(particle.getVelocity() == v.getUnitVector() * c_light); } TEST(ParticleState, momentum) { diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index 456ca0dcd..cdc18d9ad 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -74,7 +74,7 @@ TEST(testTurbulentMagneticFieldGrid, Brms) { for (int ix = 0; ix < n; ix++) for (int iy = 0; iy < n; iy++) for (int iz = 0; iz < n; iz++) - brms += bField.getField(Vector3d(ix, iy, iz)).mag2(); + brms += bField.getField(Vector3d(ix, iy, iz)).getMag2(); brms = sqrt(brms / n / n / n); double precision = 1e-7; From ae50479c1dac431fbbdab930f42f13dc11f39096 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 16 May 2012 14:01:45 +0200 Subject: [PATCH 0100/1298] add random vector methods --- include/mpc/Random.h | 11 +++++++++-- include/mpc/Vector3.h | 10 +++++++--- src/Random.cpp | 32 +++++++++++++++++++++++++------- 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/include/mpc/Random.h b/include/mpc/Random.h index f58f47e39..a0f38427f 100644 --- a/include/mpc/Random.h +++ b/include/mpc/Random.h @@ -132,12 +132,19 @@ class Random { /// Fisher distributed random number double randFisher(double k); + /// Random point on a unit-sphere + Vector3d randUnitVectorOnSphere(); + /// Random vector with given angular separation around mean direction + Vector3d randVectorAroundMean(const Vector3d &meanDirection, double angularSeparation); + /// Fisher distributed random vector + Vector3d randFisher(const Vector3d &meanDirection, double kappa); + /// Uniform distributed random vector inside a cone + Vector3d randUniformCone(const Vector3d &meanDirection, double alpha); + /// Power-Law distribution, not possible for index == -1 double randPowerLaw(double index, double min, double max); /// Broken power-law distribution double randBrokenPowerLaw(double index1, double index2, double breakpoint, double min, double max ); - /// Random point on a unit-sphere - Vector3d randUnitVectorOnSphere(); /// Seed the generator with a simple uint32 void seed( const uint32 oneSeed ); diff --git a/include/mpc/Vector3.h b/include/mpc/Vector3.h index 82e4ed49e..6f4e00999 100644 --- a/include/mpc/Vector3.h +++ b/include/mpc/Vector3.h @@ -124,6 +124,10 @@ class Vector3 { return Vector3(x, y, z) / getMag(); } + void normalize() { + *this /= getMag(); + } + T dot(const Vector3 & p) const { return x * p.x + y * p.y + z * p.z; } @@ -134,11 +138,11 @@ class Vector3 { } void rotate(const Vector3 &axis, T angle) { + T ux = axis.getX() / axis.getMag(); + T uy = axis.getY() / axis.getMag(); + T uz = axis.getZ() / axis.getMag(); T c = cos(angle); T s = sin(angle); - T ux = axis.getX(); - T uy = axis.getY(); - T uz = axis.getZ(); Vector3 Rx(c + ux * ux * (1 - c), ux * uy * (1 - c) - uz * s, ux * uz * (1 - c) + uy * s); Vector3 Ry(uy * ux * (1 - c) + uz * s, c + uy * uy * (1 - c), diff --git a/src/Random.cpp b/src/Random.cpp index a100e6037..f95f18aad 100644 --- a/src/Random.cpp +++ b/src/Random.cpp @@ -118,17 +118,36 @@ double Random::randRayleigh(double sigma) { return sigma * sqrt(-2.0 * log(1 - this->rand())); } -double Random::randFisher(double k) { - return acos(1. + 1. / k * log(1 - rand() * (1 - exp(-2 * k)))); +double Random::randFisher(double kappa) { + return acos(1. + 1. / kappa * log(1 - rand() * (1 - exp(-2 * kappa)))); } Vector3d Random::randUnitVectorOnSphere() { - double z = this->randUniform(-1.0, 1.0); - double t = this->randUniform(-1.0 * M_PI, M_PI); + double z = randUniform(-1.0, 1.0); + double t = randUniform(-1.0 * M_PI, M_PI); double r = sqrt(1 - z * z); return Vector3d(r * cos(t), r * sin(t), z); } +Vector3d Random::randVectorAroundMean(const Vector3d &meanDirection, double angle) { + Vector3d rotAxis = meanDirection.cross(randUnitVectorOnSphere()); + rotAxis.normalize(); + Vector3d v = meanDirection; + v.rotate(rotAxis, angle); + return v; +} + +Vector3d Random::randFisher(const Vector3d &meanDirection, double kappa) { + return randVectorAroundMean(meanDirection, randFisher(kappa)); +} + +Vector3d Random::randUniformCone(const Vector3d &meanDirection, double alpha) { + double theta = 2 * M_PI; + while (theta > alpha) + theta = acos(2 * rand() - 1); + return randVectorAroundMean(meanDirection, theta); +} + double Random::randPowerLaw(double index, double min, double max) { if ((min < 0) || (max < min)) { throw std::runtime_error( @@ -277,8 +296,7 @@ void Random::seed() { } // Was not successful, so use time() and clock() instead - seed(hash(time(NULL), clock())); -} + seed (hash(time (NULL), clock()));} void Random::initialize(const uint32 seed) { register uint32 *s = state; @@ -378,7 +396,7 @@ Random &Random::instance() { #endif int i = omp_get_thread_num(); if (i >= MAX_THREAD) - throw std::runtime_error("mpc::Random: more than MAX_THREAD threads!"); + throw std::runtime_error("mpc::Random: more than MAX_THREAD threads!"); return tls[i].r; } #else From 5ef83a7c9a91ece707318a1ce28cbfe54596f1de Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 18 May 2012 09:43:43 +0200 Subject: [PATCH 0101/1298] rename random vector methods, set default value for ModuleList::run recursive --- include/mpc/ModuleList.h | 6 +++--- include/mpc/Random.h | 6 +++--- src/Random.cpp | 22 +++++++++++----------- src/module/BreakCondition.cpp | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/mpc/ModuleList.h b/include/mpc/ModuleList.h index 3e0b8f790..fad119c5a 100644 --- a/include/mpc/ModuleList.h +++ b/include/mpc/ModuleList.h @@ -26,9 +26,9 @@ class ModuleList: public Referenced { void add(Module *module); virtual void process(Candidate *candidate); - void run(Candidate *candidate, bool recursive); - void run(candidate_vector_t &candidates, bool recursive); - void run(Source *source, size_t count, bool recursive); + void run(Candidate *candidate, bool recursive = true); + void run(candidate_vector_t &candidates, bool recursive = true); + void run(Source *source, size_t count, bool recursive = true); module_list_t &getModules(); const module_list_t &getModules() const; diff --git a/include/mpc/Random.h b/include/mpc/Random.h index a0f38427f..107642dcd 100644 --- a/include/mpc/Random.h +++ b/include/mpc/Random.h @@ -135,11 +135,11 @@ class Random { /// Random point on a unit-sphere Vector3d randUnitVectorOnSphere(); /// Random vector with given angular separation around mean direction - Vector3d randVectorAroundMean(const Vector3d &meanDirection, double angularSeparation); + Vector3d randVectorAroundMean(const Vector3d &meanDirection, double angle); /// Fisher distributed random vector - Vector3d randFisher(const Vector3d &meanDirection, double kappa); + Vector3d randFisherVector(const Vector3d &meanDirection, double kappa); /// Uniform distributed random vector inside a cone - Vector3d randUniformCone(const Vector3d &meanDirection, double alpha); + Vector3d randConeVector(const Vector3d &meanDirection, double angularRadius); /// Power-Law distribution, not possible for index == -1 double randPowerLaw(double index, double min, double max); diff --git a/src/Random.cpp b/src/Random.cpp index f95f18aad..7941c4dc0 100644 --- a/src/Random.cpp +++ b/src/Random.cpp @@ -111,11 +111,11 @@ double Random::randNorm(const double& mean, const double& variance) { } double Random::randUniform(double min, double max) { - return min + (max - min) * this->rand(); + return min + (max - min) * rand(); } double Random::randRayleigh(double sigma) { - return sigma * sqrt(-2.0 * log(1 - this->rand())); + return sigma * sqrt(-2.0 * log(1 - rand())); } double Random::randFisher(double kappa) { @@ -137,13 +137,13 @@ Vector3d Random::randVectorAroundMean(const Vector3d &meanDirection, double angl return v; } -Vector3d Random::randFisher(const Vector3d &meanDirection, double kappa) { +Vector3d Random::randFisherVector(const Vector3d &meanDirection, double kappa) { return randVectorAroundMean(meanDirection, randFisher(kappa)); } -Vector3d Random::randUniformCone(const Vector3d &meanDirection, double alpha) { +Vector3d Random::randConeVector(const Vector3d &meanDirection, double angularRadius) { double theta = 2 * M_PI; - while (theta > alpha) + while (theta > angularRadius) theta = acos(2 * rand() - 1); return randVectorAroundMean(meanDirection, theta); } @@ -157,12 +157,12 @@ double Random::randPowerLaw(double index, double min, double max) { if ((std::abs(index + 1.0)) < std::numeric_limits::epsilon()) { double part1 = log(max); double part2 = log(min); - return exp((part1 - part2) * this->rand() + part2); + return exp((part1 - part2) * rand() + part2); } else { double part1 = pow(max, index + 1); double part2 = pow(min, index + 1); double ex = 1 / (index + 1); - return pow((part1 - part2) * this->rand() + part2, ex); + return pow((part1 - part2) * rand() + part2, ex); } } @@ -193,17 +193,17 @@ double Random::randBrokenPowerLaw(double index1, double index2, intPL2 = (pow(max, index2 + 1) - pow(breakpoint, index2 + 1)) * pow(breakpoint, index1 - index2) / (index2 + 1); } - if (this->rand() > intPL1 / (intPL1 + intPL2)) - return this->randPowerLaw(index2, breakpoint, max); + if (rand() > intPL1 / (intPL1 + intPL2)) + return randPowerLaw(index2, breakpoint, max); else - return this->randPowerLaw(index1, min, breakpoint); + return randPowerLaw(index1, min, breakpoint); } } double Random::randExponential() { double dum; do { - dum = this->rand(); + dum = rand(); } while (dum < std::numeric_limits::epsilon()); return -1.0 * log(dum); } diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp index e5ee11897..9aeaf437a 100644 --- a/src/module/BreakCondition.cpp +++ b/src/module/BreakCondition.cpp @@ -50,7 +50,7 @@ void SmallObserverSphere::setMakeInactive(bool makeInactive) { void SmallObserverSphere::process(Candidate *candidate) const { double d = (candidate->current.getPosition() - center).getMag(); if (d <= radius * 1.01) { - candidate->setProperty("Detected", ""); + candidate->setProperty(flag, flagValue); if (makeInactive) { candidate->setActive(false); candidate->setProperty("Deactivated", getDescription()); From 617a4c6ee291fc6a1a2dee7e523b08b02d054566 Mon Sep 17 00:00:00 2001 From: geromueller Date: Fri, 18 May 2012 12:32:01 +0200 Subject: [PATCH 0102/1298] fix kiss include --- include/mpc/Nucleus.h | 19 +------------------ src/Nucleus.cpp | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/include/mpc/Nucleus.h b/include/mpc/Nucleus.h index 2abf94ee3..2ba108769 100644 --- a/include/mpc/Nucleus.h +++ b/include/mpc/Nucleus.h @@ -1,8 +1,6 @@ #ifndef NUCLEUS_H_ #define NUCLEUS_H_ -#include "kiss/convert.h" - #include namespace mpc { @@ -13,22 +11,7 @@ namespace mpc { // ZZZ is Z - total charge // L is the total number of strange quarks. // I is the isomer number, with I=0 corresponding to the ground state. -inline int getNucleusId(int a, int z) { - if (z < 0) - throw std::runtime_error( - "mpc::Nucleus: no nucleus with Z < 0, A=" + kiss::str(a) + " Z=" - + kiss::str(z)); - if (a < 1) - throw std::runtime_error( - "mpc::Nucleus: no nucleus with A < 1, A=" + kiss::str(a) + " Z=" - + kiss::str(z)); - if (a < z) - throw std::runtime_error( - "mpc::Nucleus: no nucleus with A < Z, A=" + kiss::str(a) + " Z=" - + kiss::str(z)); - return 1000000000 + z * 10000 + a * 10; -} - +int getNucleusId(int a, int z); void initNuclearMassTable(); double getNucleusMass(int id); diff --git a/src/Nucleus.cpp b/src/Nucleus.cpp index 072806cb5..28576c5ce 100644 --- a/src/Nucleus.cpp +++ b/src/Nucleus.cpp @@ -7,9 +7,27 @@ #include #include #include +#include namespace mpc { +int getNucleusId(int a, int z) { + if (z < 0) + throw std::runtime_error( + "mpc::Nucleus: no nucleus with Z < 0, A=" + kiss::str(a) + " Z=" + + kiss::str(z)); + if (a < 1) + throw std::runtime_error( + "mpc::Nucleus: no nucleus with A < 1, A=" + kiss::str(a) + " Z=" + + kiss::str(z)); + if (a < z) + throw std::runtime_error( + "mpc::Nucleus: no nucleus with A < Z, A=" + kiss::str(a) + " Z=" + + kiss::str(z)); + return 1000000000 + z * 10000 + a * 10; +} + + static std::vector nuclearMassTable; void initNuclearMassTable() { From 9e56186a9a3139e69a573487a5a50db959eb5817 Mon Sep 17 00:00:00 2001 From: geromueller Date: Fri, 18 May 2012 16:25:02 +0200 Subject: [PATCH 0103/1298] add support for Intel Compiler (esp. Fortran) --- CMakeLists.txt | 5 ++++- README | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dea9f3c34..e03354317 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 2.6) -project(ModularPropagationCode Fortran CXX) +project(ModularPropagationCode Fortran C CXX) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) @@ -16,8 +16,11 @@ list(APPEND MPC_EXTRA_INCLUDES ${GSL_INCLUDE_DIR}) # fftw3f needed for TurbulentMagneticField find_package(FFTW3F) if (FFTW3F_FOUND) + message(STATUS "FFTW3F found!") list(APPEND MPC_EXTRA_SOURCES src/magneticField/TurbulentMagneticField.cpp) list(APPEND MPC_EXTRA_LIBRARIES ${FFTW3F_LIBRARY}) +else(FFTW3F_FOUND) + message(STATUS "FFTW3F NOT found!") endif (FFTW3F_FOUND) # gadget needed for SPHMagneticField and SPHTurbulentMagneticField diff --git a/README b/README index fa5c92430..1ef07934e 100644 --- a/README +++ b/README @@ -18,3 +18,6 @@ GTest - for unit-tests To use MPC from python the following environment variables have to be set. PYTHONPATH=[path to mpc.py] MPC_DATA_PATH=[path to mpc/data] + +Notes for Intel Compiler: + -DCMAKE_SHARED_LINKER_FLAGS="-lifcore" -DCMAKE_Fortran_COMPILER=ifort From f49ab90f68fde86d7243f0ca9799135bf7f48503 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 22 May 2012 19:36:30 +0200 Subject: [PATCH 0104/1298] add interpolation to replace GSL method --- include/mpc/Common.h | 15 +++++++++++---- src/Common.cpp | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/include/mpc/Common.h b/include/mpc/Common.h index d1d612beb..ac2cc3673 100644 --- a/include/mpc/Common.h +++ b/include/mpc/Common.h @@ -5,6 +5,11 @@ namespace mpc { +// Photon fields +enum PhotonField { + CMB, IRB, CMB_IRB +}; + // Returns the full path to a mpc data file std::string getDataPath(std::string filename); @@ -13,10 +18,12 @@ inline int digit(const int &value, const int &d) { return (value % (d * 10)) / d; } -// Photon fields -enum PhotonField { - CMB, IRB, CMB_IRB -}; +// Perform linear interpolation +double interpolate(const double x, const double *xD, const double *yD); + +// Perform linear interpolation on equidistant tabulated data +double interpolateEquidistant(const double x, const double xLo, const double dx, + const double *yD); } // namespace mpc diff --git a/src/Common.cpp b/src/Common.cpp index 3a4732a38..a96486b69 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace mpc { @@ -51,5 +52,20 @@ std::string getDataPath(std::string filename) { return concat_path(dataPath, filename); } +double interpolate(const double x, const double *xD, const double *yD) { + size_t i = 0; + while (x > xD[i]) + i++; + i--; + return yD[i] + (x - xD[i]) * (yD[i + 1] - yD[i]) / (xD[i + 1] - xD[i]); +} + +double interpolateEquidistant(const double x, const double xLo, const double dx, + const double *yD) { + double p = (x - xLo) / dx; + size_t i = floor(p); + return yD[i] + (p - i) * (yD[i + 1] - yD[i]); +} + } // namespace mpc From a101d97eb125fbe9227af2e2c389d0fca848115d Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 22 May 2012 19:37:40 +0200 Subject: [PATCH 0105/1298] remove GSL interpolation from interactions --- include/mpc/module/ElectronPairProduction.h | 8 ++---- include/mpc/module/NuclearDecay.h | 6 ++-- include/mpc/module/PhotoDisintegration.h | 6 +--- include/mpc/module/PhotoPionProduction.h | 11 +++----- src/module/ElectronPairProduction.cpp | 19 ++++--------- src/module/NuclearDecay.cpp | 15 +++------- src/module/PhotoDisintegration.cpp | 31 ++++----------------- src/module/PhotoPionProduction.cpp | 27 ++++-------------- 8 files changed, 31 insertions(+), 92 deletions(-) diff --git a/include/mpc/module/ElectronPairProduction.h b/include/mpc/module/ElectronPairProduction.h index 060334e24..c1e4232f8 100644 --- a/include/mpc/module/ElectronPairProduction.h +++ b/include/mpc/module/ElectronPairProduction.h @@ -4,9 +4,6 @@ #include "mpc/Module.h" #include "mpc/Common.h" -#include -#include - namespace mpc { /** @@ -19,9 +16,8 @@ namespace mpc { class ElectronPairProduction: public Module { private: int photonField; - gsl_interp_accel *acc; - gsl_spline *lossRate; // energy loss rate in [J/m] - double xMin, xMax, yMax; + std::vector lossRate; // energy loss rate in [J/m] + std::vector energy; public: ElectronPairProduction(int photonField = CMB_IRB); diff --git a/include/mpc/module/NuclearDecay.h b/include/mpc/module/NuclearDecay.h index 50508540b..ede6a9f1e 100644 --- a/include/mpc/module/NuclearDecay.h +++ b/include/mpc/module/NuclearDecay.h @@ -3,8 +3,6 @@ #include "mpc/module/StochasticInteraction.h" -#include -#include #include namespace mpc { @@ -23,8 +21,8 @@ class NuclearDecay: public StochasticInteraction { std::vector > decayTable; // InteractionState.channel is (#beta- #beta+ #alpha #proton #neutron) // InteractionState.distance is the mean free path [m] - gsl_interp_accel *acc; - gsl_spline *Tbeta; // inverse cdf electron kinetic energy [J] in neutron decay + double tBeta[50]; // electron kinetic energy [J] in neutron decays + double cdfBeta[50]; // cumulative distribution function for the electron kinetic energy [J] in neutron decays public: NuclearDecay(bool electrons = false, bool neutrinos = false); diff --git a/include/mpc/module/PhotoDisintegration.h b/include/mpc/module/PhotoDisintegration.h index 3596c14e5..65390d75f 100644 --- a/include/mpc/module/PhotoDisintegration.h +++ b/include/mpc/module/PhotoDisintegration.h @@ -5,8 +5,6 @@ #include "mpc/Random.h" #include -#include -#include namespace mpc { @@ -22,14 +20,12 @@ class PhotoDisintegration: public StochasticInteraction { int photonField; struct PDMode { int channel; // number of emitted (n, p, H2, H3, He3, He4) - gsl_spline *rate; // disintegration rate [1/m] + double rate[200]; // disintegration rate [1/m] }; std::vector > pdTable; // pdTable[Z * 31 + N] = vector - gsl_interp_accel *acc; // accelerator for the interpolation public: PhotoDisintegration(int photonField = CMB); - ~PhotoDisintegration(); void init(int photonField); void init(std::string filename); bool setNextInteraction(Candidate *candidate, diff --git a/include/mpc/module/PhotoPionProduction.h b/include/mpc/module/PhotoPionProduction.h index 9ab0d2a0f..38e884b98 100644 --- a/include/mpc/module/PhotoPionProduction.h +++ b/include/mpc/module/PhotoPionProduction.h @@ -4,8 +4,7 @@ #include "mpc/module/StochasticInteraction.h" #include "mpc/Random.h" -#include -#include +#include namespace mpc { @@ -19,14 +18,12 @@ namespace mpc { class PhotoPionProduction: public StochasticInteraction { protected: int photonField; - gsl_interp_accel *acc; - gsl_spline *pRate; // interaction rate in [1/m] for protons - gsl_spline *nRate; // interaction rate in [1/m] for neutrons - double Emin, Emax; + std::vector pRate; // interaction rate in [1/m] for protons + std::vector nRate; // interaction rate in [1/m] for neutrons + std::vector energy; // energy in [J] public: PhotoPionProduction(int photonField = CMB); - ~PhotoPionProduction(); void init(int photonField); void init(std::string filename); bool setNextInteraction(Candidate *candidate, diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 7f9f13b64..a88b588dc 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -45,20 +45,13 @@ void ElectronPairProduction::init(std::string filename) { double a, b; infile >> a >> b; if (infile) { - x.push_back(a * eV); - y.push_back(b * eV / Mpc); + energy.push_back(a * eV); + lossRate.push_back(b * eV / Mpc); } } infile.ignore(std::numeric_limits::max(), '\n'); } infile.close(); - - acc = gsl_interp_accel_alloc(); - lossRate = gsl_spline_alloc(gsl_interp_linear, x.size()); - gsl_spline_init(lossRate, &x[0], &y[0], x.size()); - xMin = x.front(); - xMax = x.back(); - yMax = y.back(); } void ElectronPairProduction::process(Candidate *candidate) const { @@ -67,15 +60,15 @@ void ElectronPairProduction::process(Candidate *candidate) const { double z = candidate->getRedshift(); double EpA = E / A * (1 + z); - if (EpA < xMin) + if (EpA < energy.front()) return; double rate; - if (EpA < xMax) - rate = gsl_spline_eval(lossRate, EpA, acc); + if (EpA < energy.back()) + rate = interpolate(EpA, &energy[0], &lossRate[0]); else // extrapolation for higher energies - rate = yMax * pow(EpA / xMax, 0.4); + rate = lossRate.back() * pow(EpA / energy.back(), 0.4); // dE(E) = Z^2 * loss_rate(E/A) * step double step = candidate->getCurrentStep(); diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index 9887021f0..5c753bc90 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -37,22 +37,15 @@ NuclearDecay::NuclearDecay(bool electrons, bool neutrinos) { // generate inverse cdf for electron kinetic energies in neutron decays double Q = mass_neutron - mass_proton; double cdf = 0; - std::vector x, y; - x.resize(50); - y.resize(50); for (int i = 0; i < 50; i++) { double E = mass_electron + i / 50. * (Q - mass_electron); cdf += sqrt(pow(E, 2) - pow(mass_electron, 2)) * pow(Q - E, 2) * E; - x[i] = cdf; - y[i] = (E - mass_electron) * c_squared; + cdfBeta[i] = cdf; + tBeta[i] = (E - mass_electron) * c_squared; } for (int i = 0; i < 50; i++) { - x[i] /= x.back(); + cdfBeta[i] /= cdf; } - - acc = gsl_interp_accel_alloc(); - Tbeta = gsl_spline_alloc(gsl_interp_linear, x.size()); - gsl_spline_init(Tbeta, &x[0], &y[0], x.size()); } bool NuclearDecay::setNextInteraction(Candidate *candidate, @@ -126,7 +119,7 @@ void NuclearDecay::betaDecay(Candidate *candidate, bool isBetaPlus) const { candidate->current.setLorentzFactor(gamma); // random kinetic energy of electron in neutron decay - double T = gsl_spline_eval(Tbeta, Random::instance().rand(), acc); + double T = interpolate(Random::instance().rand(), cdfBeta, tBeta); double Q = (mass - candidate->current.getMass() - mass_electron) * c_squared; double Qneutron = (mass_neutron - mass_proton - mass_electron) * c_squared; diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 485502007..d67b09408 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -8,10 +8,6 @@ namespace mpc { -enum _Constants { - SAMPLE_COUNT = 200 -}; - PhotoDisintegration::PhotoDisintegration(int photonField) { init(photonField); } @@ -34,16 +30,9 @@ void PhotoDisintegration::init(int photonField) { } void PhotoDisintegration::init(std::string filename) { - acc = gsl_interp_accel_alloc(); pdTable.resize(31 * 57); // create spline x-axis - std::vector x(SAMPLE_COUNT); - for (size_t i = 0; i < 200; i++) - x[i] = 6.0 + i * 8.0 / (SAMPLE_COUNT - 1); - - std::vector y(SAMPLE_COUNT); - std::ifstream infile(filename.c_str()); if (!infile.good()) throw std::runtime_error( @@ -62,26 +51,18 @@ void PhotoDisintegration::init(std::string filename) { PDMode pd; lineStream >> pd.channel; // disintegration channel - for (size_t i = 0; i < SAMPLE_COUNT; i++) { - lineStream >> y[i]; - y[i] /= Mpc; // disintegration rate in [1/m] + double r = 0; + for (size_t i = 0; i < 200; i++) { + lineStream >> r; + pd.rate[i] = r / Mpc; // disintegration rate in [1/m] } - pd.rate = gsl_spline_alloc(gsl_interp_linear, SAMPLE_COUNT); - gsl_spline_init(pd.rate, &x[0], &y[0], SAMPLE_COUNT); pdTable[Z * 31 + N].push_back(pd); } infile.close(); } -PhotoDisintegration::~PhotoDisintegration() { - gsl_interp_accel_free(acc); - for (size_t i = 0; i < pdTable.size(); i++) - for (size_t j = 0; j < pdTable[i].size(); j++) - gsl_spline_free(pdTable[i][j].rate); -} - bool PhotoDisintegration::setNextInteraction(Candidate *candidate, InteractionState &interaction) const { int A = candidate->current.getMassNumber(); @@ -98,13 +79,13 @@ bool PhotoDisintegration::setNextInteraction(Candidate *candidate, double lg = log10(candidate->current.getLorentzFactor() * (1 + z)); // check if out of energy range - if ((lg < 6) or (lg > 14)) + if ((lg <= 6) or (lg >= 14)) return false; // find channel with minimum random decay distance interaction.distance = std::numeric_limits::max(); for (size_t i = 0; i < pdModes.size(); i++) { - double rate = gsl_spline_eval(pdModes[i].rate, lg, acc); + double rate = interpolateEquidistant(lg, 6., 8./200., pdModes[i].rate); double d = -log(Random::instance().rand()) / rate; if (d > interaction.distance) continue; diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 384031e1e..3cfbb425b 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -38,35 +38,20 @@ void PhotoPionProduction::init(std::string filename) { throw std::runtime_error( "mpc::PhotoPionProduction: could not open file " + filename); - std::vector x, yp, yn; while (infile.good()) { if (infile.peek() != '#') { double a, b, c; infile >> a >> b >> c; if (infile) { - x.push_back(a * EeV); // energy in [EeV] - yp.push_back(b / Mpc); // rate in [1/Mpc] - yn.push_back(c / Mpc); // rate in [1/Mpc] + energy.push_back(a * EeV); + pRate.push_back(b / Mpc); + nRate.push_back(c / Mpc); } } infile.ignore(std::numeric_limits::max(), '\n'); } infile.close(); - - acc = gsl_interp_accel_alloc(); - pRate = gsl_spline_alloc(gsl_interp_linear, x.size()); - nRate = gsl_spline_alloc(gsl_interp_linear, x.size()); - gsl_spline_init(pRate, &x[0], &yp[0], x.size()); - gsl_spline_init(nRate, &x[0], &yn[0], x.size()); - Emin = x.front(); - Emax = x.back(); -} - -PhotoPionProduction::~PhotoPionProduction() { - gsl_spline_free(pRate); - gsl_spline_free(nRate); - gsl_interp_accel_free(acc); } bool PhotoPionProduction::setNextInteraction(Candidate *candidate, @@ -79,7 +64,7 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, double EpA = E / A * (1 + z); // CMB energies increase with (1+z)^3 // check if out of energy range - if ((EpA < Emin) or (EpA > Emax)) + if ((EpA < energy.front()) or (EpA > energy.back())) return false; // find interaction with minimum random distance @@ -87,7 +72,7 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, interaction.distance = std::numeric_limits::max(); Random &random = Random::instance(); if (Z > 0) { - double rate = gsl_spline_eval(pRate, EpA, acc) * Z; + double rate = interpolate(EpA, &energy[0], &pRate[0]) * Z; if (rate != 0) { interaction.distance = -log(random.rand()) / rate; interaction.channel = 1; @@ -95,7 +80,7 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, } // check for interaction on neutrons if (N > 0) { - double rate = gsl_spline_eval(nRate, EpA, acc) * N; + double rate = interpolate(EpA, &energy[0], &nRate[0]) * N; if (rate != 0) { double d = -log(random.rand()) / rate; if (d < interaction.distance) { From bdbed8a3ac0822a3981a9ea43a5e8b823bc245a8 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 22 May 2012 19:39:06 +0200 Subject: [PATCH 0106/1298] add gtest to repository --- libs/gtest/CMakeLists.txt | 240 + libs/gtest/cmake/internal_utils.cmake | 216 + libs/gtest/include/gtest/gtest-death-test.h | 283 + libs/gtest/include/gtest/gtest-message.h | 230 + libs/gtest/include/gtest/gtest-param-test.h | 1421 +++++ .../include/gtest/gtest-param-test.h.pump | 487 ++ libs/gtest/include/gtest/gtest-printers.h | 796 +++ libs/gtest/include/gtest/gtest-spi.h | 232 + libs/gtest/include/gtest/gtest-test-part.h | 176 + libs/gtest/include/gtest/gtest-typed-test.h | 259 + libs/gtest/include/gtest/gtest.h | 2155 ++++++++ libs/gtest/include/gtest/gtest_pred_impl.h | 358 ++ libs/gtest/include/gtest/gtest_prod.h | 58 + .../internal/gtest-death-test-internal.h | 308 ++ .../include/gtest/internal/gtest-filepath.h | 210 + .../include/gtest/internal/gtest-internal.h | 1226 +++++ .../include/gtest/internal/gtest-linked_ptr.h | 233 + .../internal/gtest-param-util-generated.h | 4822 ++++++++++++++++ .../gtest-param-util-generated.h.pump | 301 + .../include/gtest/internal/gtest-param-util.h | 619 +++ .../gtest/include/gtest/internal/gtest-port.h | 1775 ++++++ .../include/gtest/internal/gtest-string.h | 350 ++ .../include/gtest/internal/gtest-tuple.h | 968 ++++ .../include/gtest/internal/gtest-tuple.h.pump | 336 ++ .../include/gtest/internal/gtest-type-util.h | 3330 +++++++++++ .../gtest/internal/gtest-type-util.h.pump | 296 + libs/gtest/src/gtest-all.cc | 48 + libs/gtest/src/gtest-death-test.cc | 1234 +++++ libs/gtest/src/gtest-filepath.cc | 380 ++ libs/gtest/src/gtest-internal-inl.h | 1038 ++++ libs/gtest/src/gtest-port.cc | 746 +++ libs/gtest/src/gtest-printers.cc | 356 ++ libs/gtest/src/gtest-test-part.cc | 110 + libs/gtest/src/gtest-typed-test.cc | 110 + libs/gtest/src/gtest.cc | 4898 +++++++++++++++++ libs/gtest/src/gtest_main.cc | 39 + 36 files changed, 30644 insertions(+) create mode 100644 libs/gtest/CMakeLists.txt create mode 100644 libs/gtest/cmake/internal_utils.cmake create mode 100644 libs/gtest/include/gtest/gtest-death-test.h create mode 100644 libs/gtest/include/gtest/gtest-message.h create mode 100644 libs/gtest/include/gtest/gtest-param-test.h create mode 100644 libs/gtest/include/gtest/gtest-param-test.h.pump create mode 100644 libs/gtest/include/gtest/gtest-printers.h create mode 100644 libs/gtest/include/gtest/gtest-spi.h create mode 100644 libs/gtest/include/gtest/gtest-test-part.h create mode 100644 libs/gtest/include/gtest/gtest-typed-test.h create mode 100644 libs/gtest/include/gtest/gtest.h create mode 100644 libs/gtest/include/gtest/gtest_pred_impl.h create mode 100644 libs/gtest/include/gtest/gtest_prod.h create mode 100644 libs/gtest/include/gtest/internal/gtest-death-test-internal.h create mode 100644 libs/gtest/include/gtest/internal/gtest-filepath.h create mode 100644 libs/gtest/include/gtest/internal/gtest-internal.h create mode 100644 libs/gtest/include/gtest/internal/gtest-linked_ptr.h create mode 100644 libs/gtest/include/gtest/internal/gtest-param-util-generated.h create mode 100644 libs/gtest/include/gtest/internal/gtest-param-util-generated.h.pump create mode 100644 libs/gtest/include/gtest/internal/gtest-param-util.h create mode 100644 libs/gtest/include/gtest/internal/gtest-port.h create mode 100644 libs/gtest/include/gtest/internal/gtest-string.h create mode 100644 libs/gtest/include/gtest/internal/gtest-tuple.h create mode 100644 libs/gtest/include/gtest/internal/gtest-tuple.h.pump create mode 100644 libs/gtest/include/gtest/internal/gtest-type-util.h create mode 100644 libs/gtest/include/gtest/internal/gtest-type-util.h.pump create mode 100644 libs/gtest/src/gtest-all.cc create mode 100644 libs/gtest/src/gtest-death-test.cc create mode 100644 libs/gtest/src/gtest-filepath.cc create mode 100644 libs/gtest/src/gtest-internal-inl.h create mode 100644 libs/gtest/src/gtest-port.cc create mode 100644 libs/gtest/src/gtest-printers.cc create mode 100644 libs/gtest/src/gtest-test-part.cc create mode 100644 libs/gtest/src/gtest-typed-test.cc create mode 100644 libs/gtest/src/gtest.cc create mode 100644 libs/gtest/src/gtest_main.cc diff --git a/libs/gtest/CMakeLists.txt b/libs/gtest/CMakeLists.txt new file mode 100644 index 000000000..0fe26540b --- /dev/null +++ b/libs/gtest/CMakeLists.txt @@ -0,0 +1,240 @@ +######################################################################## +# CMake build script for Google Test. +# +# To run the tests for Google Test itself on Linux, use 'make test' or +# ctest. You can select which tests to run using 'ctest -R regex'. +# For more options, run 'ctest --help'. + +# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to +# make it prominent in the GUI. +option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF) + +# When other libraries are using a shared version of runtime libraries, +# Google Test also has to use one. +option( + gtest_force_shared_crt + "Use shared (DLL) run-time lib even when Google Test is built as static lib." + OFF) + +option(gtest_build_tests "Build all of gtest's own tests." OFF) + +option(gtest_build_samples "Build gtest's sample programs." OFF) + +option(gtest_disable_pthreads "Disable uses of pthreads in gtest." OFF) + +# Defines pre_project_set_up_hermetic_build() and set_up_hermetic_build(). +include(cmake/hermetic_build.cmake OPTIONAL) + +if (COMMAND pre_project_set_up_hermetic_build) + pre_project_set_up_hermetic_build() +endif() + +######################################################################## +# +# Project-wide settings + +# Name of the project. +# +# CMake files in this project can refer to the root source directory +# as ${gtest_SOURCE_DIR} and to the root binary directory as +# ${gtest_BINARY_DIR}. +# Language "C" is required for find_package(Threads). +project(gtest CXX C) +cmake_minimum_required(VERSION 2.6.2) + +if (COMMAND set_up_hermetic_build) + set_up_hermetic_build() +endif() + +# Define helper functions and macros used by Google Test. +include(cmake/internal_utils.cmake) + +config_compiler_and_linker() # Defined in internal_utils.cmake. + +# Where Google Test's .h files can be found. +include_directories( + ${gtest_SOURCE_DIR}/include + ${gtest_SOURCE_DIR}) + +# Where Google Test's libraries can be found. +link_directories(${gtest_BINARY_DIR}/src) + +######################################################################## +# +# Defines the gtest & gtest_main libraries. User tests should link +# with one of them. + +# Google Test libraries. We build them using more strict warnings than what +# are used for other targets, to ensure that gtest can be compiled by a user +# aggressive about warnings. +cxx_library(gtest "${cxx_strict}" src/gtest-all.cc) +cxx_library(gtest_main "${cxx_strict}" src/gtest_main.cc) +target_link_libraries(gtest_main gtest) + +######################################################################## +# +# Samples on how to link user tests with gtest or gtest_main. +# +# They are not built by default. To build them, set the +# gtest_build_samples option to ON. You can do it by running ccmake +# or specifying the -Dbuild_gtest_samples=ON flag when running cmake. + +if (gtest_build_samples) + cxx_executable(sample1_unittest samples gtest_main samples/sample1.cc) + cxx_executable(sample2_unittest samples gtest_main samples/sample2.cc) + cxx_executable(sample3_unittest samples gtest_main) + cxx_executable(sample4_unittest samples gtest_main samples/sample4.cc) + cxx_executable(sample5_unittest samples gtest_main samples/sample1.cc) + cxx_executable(sample6_unittest samples gtest_main) + cxx_executable(sample7_unittest samples gtest_main) + cxx_executable(sample8_unittest samples gtest_main) + cxx_executable(sample9_unittest samples gtest) + cxx_executable(sample10_unittest samples gtest) +endif() + +######################################################################## +# +# Google Test's own tests. +# +# You can skip this section if you aren't interested in testing +# Google Test itself. +# +# The tests are not built by default. To build them, set the +# gtest_build_tests option to ON. You can do it by running ccmake +# or specifying the -Dgtest_build_tests=ON flag when running cmake. + +if (gtest_build_tests) + # This must be set in the root directory for the tests to be run by + # 'make test' or ctest. + enable_testing() + + ############################################################ + # C++ tests built with standard compiler flags. + + cxx_test(gtest-death-test_test gtest_main) + cxx_test(gtest_environment_test gtest) + cxx_test(gtest-filepath_test gtest_main) + cxx_test(gtest-linked_ptr_test gtest_main) + cxx_test(gtest-listener_test gtest_main) + cxx_test(gtest_main_unittest gtest_main) + cxx_test(gtest-message_test gtest_main) + cxx_test(gtest_no_test_unittest gtest) + cxx_test(gtest-options_test gtest_main) + cxx_test(gtest-param-test_test gtest + test/gtest-param-test2_test.cc) + cxx_test(gtest-port_test gtest_main) + cxx_test(gtest_pred_impl_unittest gtest_main) + cxx_test(gtest-printers_test gtest_main) + cxx_test(gtest_prod_test gtest_main + test/production.cc) + cxx_test(gtest_repeat_test gtest) + cxx_test(gtest_sole_header_test gtest_main) + cxx_test(gtest_stress_test gtest) + cxx_test(gtest-test-part_test gtest_main) + cxx_test(gtest_throw_on_failure_ex_test gtest) + cxx_test(gtest-typed-test_test gtest_main + test/gtest-typed-test2_test.cc) + cxx_test(gtest_unittest gtest_main) + cxx_test(gtest-unittest-api_test gtest) + + ############################################################ + # C++ tests built with non-standard compiler flags. + + cxx_library(gtest_no_exception "${cxx_no_exception}" + src/gtest-all.cc) + cxx_library(gtest_main_no_exception "${cxx_no_exception}" + src/gtest-all.cc src/gtest_main.cc) + cxx_library(gtest_main_no_rtti "${cxx_no_rtti}" + src/gtest-all.cc src/gtest_main.cc) + + cxx_test_with_flags(gtest-death-test_ex_nocatch_test + "${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=0" + gtest test/gtest-death-test_ex_test.cc) + cxx_test_with_flags(gtest-death-test_ex_catch_test + "${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=1" + gtest test/gtest-death-test_ex_test.cc) + + cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}" + gtest_main_no_rtti test/gtest_unittest.cc) + + cxx_shared_library(gtest_dll "${cxx_default}" + src/gtest-all.cc src/gtest_main.cc) + + cxx_executable_with_flags(gtest_dll_test_ "${cxx_default}" + gtest_dll test/gtest_all_test.cc) + set_target_properties(gtest_dll_test_ + PROPERTIES + COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") + + if (NOT MSVC OR NOT MSVC_VERSION EQUAL 1600) + # The C++ Standard specifies tuple_element. + # Yet MSVC 10's declares tuple_element. + # That declaration conflicts with our own standard-conforming + # tuple implementation. Therefore using our own tuple with + # MSVC 10 doesn't compile. + cxx_library(gtest_main_use_own_tuple "${cxx_use_own_tuple}" + src/gtest-all.cc src/gtest_main.cc) + + cxx_test_with_flags(gtest-tuple_test "${cxx_use_own_tuple}" + gtest_main_use_own_tuple test/gtest-tuple_test.cc) + + cxx_test_with_flags(gtest_use_own_tuple_test "${cxx_use_own_tuple}" + gtest_main_use_own_tuple + test/gtest-param-test_test.cc test/gtest-param-test2_test.cc) + endif() + + ############################################################ + # Python tests. + + cxx_executable(gtest_break_on_failure_unittest_ test gtest) + py_test(gtest_break_on_failure_unittest) + + cxx_executable_with_flags( + gtest_catch_exceptions_no_ex_test_ + "${cxx_no_exception}" + gtest_main_no_exception + test/gtest_catch_exceptions_test_.cc) + cxx_executable_with_flags( + gtest_catch_exceptions_ex_test_ + "${cxx_exception}" + gtest_main + test/gtest_catch_exceptions_test_.cc) + py_test(gtest_catch_exceptions_test) + + cxx_executable(gtest_color_test_ test gtest) + py_test(gtest_color_test) + + cxx_executable(gtest_env_var_test_ test gtest) + py_test(gtest_env_var_test) + + cxx_executable(gtest_filter_unittest_ test gtest) + py_test(gtest_filter_unittest) + + cxx_executable(gtest_help_test_ test gtest_main) + py_test(gtest_help_test) + + cxx_executable(gtest_list_tests_unittest_ test gtest) + py_test(gtest_list_tests_unittest) + + cxx_executable(gtest_output_test_ test gtest) + py_test(gtest_output_test) + + cxx_executable(gtest_shuffle_test_ test gtest) + py_test(gtest_shuffle_test) + + cxx_executable(gtest_throw_on_failure_test_ test gtest_no_exception) + set_target_properties(gtest_throw_on_failure_test_ + PROPERTIES + COMPILE_FLAGS "${cxx_no_exception}") + py_test(gtest_throw_on_failure_test) + + cxx_executable(gtest_uninitialized_test_ test gtest) + py_test(gtest_uninitialized_test) + + cxx_executable(gtest_xml_outfile1_test_ test gtest_main) + cxx_executable(gtest_xml_outfile2_test_ test gtest_main) + py_test(gtest_xml_outfiles_test) + + cxx_executable(gtest_xml_output_unittest_ test gtest) + py_test(gtest_xml_output_unittest) +endif() diff --git a/libs/gtest/cmake/internal_utils.cmake b/libs/gtest/cmake/internal_utils.cmake new file mode 100644 index 000000000..9f002c4a1 --- /dev/null +++ b/libs/gtest/cmake/internal_utils.cmake @@ -0,0 +1,216 @@ +# Defines functions and macros useful for building Google Test and +# Google Mock. +# +# Note: +# +# - This file will be run twice when building Google Mock (once via +# Google Test's CMakeLists.txt, and once via Google Mock's). +# Therefore it shouldn't have any side effects other than defining +# the functions and macros. +# +# - The functions/macros defined in this file may depend on Google +# Test and Google Mock's option() definitions, and thus must be +# called *after* the options have been defined. + +# Tweaks CMake's default compiler/linker settings to suit Google Test's needs. +# +# This must be a macro(), as inside a function string() can only +# update variables in the function scope. +macro(fix_default_compiler_settings_) + if (MSVC) + # For MSVC, CMake sets certain flags to defaults we want to override. + # This replacement code is taken from sample in the CMake Wiki at + # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace. + foreach (flag_var + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if (NOT BUILD_SHARED_LIBS AND NOT gtest_force_shared_crt) + # When Google Test is built as a shared library, it should also use + # shared runtime libraries. Otherwise, it may end up with multiple + # copies of runtime library data in different modules, resulting in + # hard-to-find crashes. When it is built as a static library, it is + # preferable to use CRT as static libraries, as we don't have to rely + # on CRT DLLs being available. CMake always defaults to using shared + # CRT libraries, so we override that default here. + string(REPLACE "/MD" "-MT" ${flag_var} "${${flag_var}}") + endif() + + # We prefer more strict warning checking for building Google Test. + # Replaces /W3 with /W4 in defaults. + string(REPLACE "/W3" "-W4" ${flag_var} "${${flag_var}}") + endforeach() + endif() +endmacro() + +# Defines the compiler/linker flags used to build Google Test and +# Google Mock. You can tweak these definitions to suit your need. A +# variable's value is empty before it's explicitly assigned to. +macro(config_compiler_and_linker) + if (NOT gtest_disable_pthreads) + # Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT. + find_package(Threads) + endif() + + #fix_default_compiler_settings_() + if (MSVC) + # Newlines inside flags variables break CMake's NMake generator. + # TODO(vladl@google.com): Add -RTCs and -RTCu to debug builds. + set(cxx_base_flags "-GS -W4 -WX -wd4127 -wd4251 -wd4275 -nologo -J -Zi") + set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32") + set(cxx_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN") + set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1") + set(cxx_no_exception_flags "-D_HAS_EXCEPTIONS=0") + set(cxx_no_rtti_flags "-GR-") + elseif (CMAKE_COMPILER_IS_GNUCXX) + set(cxx_base_flags "-Wall -Wshadow") + set(cxx_exception_flags "-fexceptions") + set(cxx_no_exception_flags "-fno-exceptions") + # Until version 4.3.2, GCC doesn't define a macro to indicate + # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI + # explicitly. + set(cxx_no_rtti_flags "-fno-rtti -DGTEST_HAS_RTTI=0") + set(cxx_strict_flags "-Wextra") + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro") + set(cxx_exception_flags "-features=except") + # Sun Pro doesn't provide macros to indicate whether exceptions and + # RTTI are enabled, so we define GTEST_HAS_* explicitly. + set(cxx_no_exception_flags "-features=no%except -DGTEST_HAS_EXCEPTIONS=0") + set(cxx_no_rtti_flags "-features=no%rtti -DGTEST_HAS_RTTI=0") + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "VisualAge" OR + CMAKE_CXX_COMPILER_ID STREQUAL "XL") + # CMake 2.8 changes Visual Age's compiler ID to "XL". + set(cxx_exception_flags "-qeh") + set(cxx_no_exception_flags "-qnoeh") + # Until version 9.0, Visual Age doesn't define a macro to indicate + # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI + # explicitly. + set(cxx_no_rtti_flags "-qnortti -DGTEST_HAS_RTTI=0") + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "HP") + set(cxx_base_flags "-AA -mt") + set(cxx_exception_flags "-DGTEST_HAS_EXCEPTIONS=1") + set(cxx_no_exception_flags "+noeh -DGTEST_HAS_EXCEPTIONS=0") + # RTTI can not be disabled in HP aCC compiler. + set(cxx_no_rtti_flags "") + endif() + + if (CMAKE_USE_PTHREADS_INIT) # The pthreads library is available and allowed. + set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=1") + else() + set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=0") + endif() + + # For building gtest's own tests and samples. + set(cxx_exception "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_exception_flags}") + set(cxx_no_exception + "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_no_exception_flags}") + set(cxx_default "${cxx_exception}") + set(cxx_no_rtti "${cxx_default} ${cxx_no_rtti_flags}") + set(cxx_use_own_tuple "${cxx_default} -DGTEST_USE_OWN_TR1_TUPLE=1") + + # For building the gtest libraries. + set(cxx_strict "${cxx_default} ${cxx_strict_flags}") +endmacro() + +# Defines the gtest & gtest_main libraries. User tests should link +# with one of them. +function(cxx_library_with_type name type cxx_flags) + # type can be either STATIC or SHARED to denote a static or shared library. + # ARGN refers to additional arguments after 'cxx_flags'. + add_library(${name} ${type} ${ARGN}) + set_target_properties(${name} + PROPERTIES + COMPILE_FLAGS "${cxx_flags}") + if (BUILD_SHARED_LIBS OR type STREQUAL "SHARED") + set_target_properties(${name} + PROPERTIES + COMPILE_DEFINITIONS "GTEST_CREATE_SHARED_LIBRARY=1") + endif() + if (CMAKE_USE_PTHREADS_INIT) + target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT}) + endif() +endfunction() + +######################################################################## +# +# Helper functions for creating build targets. + +function(cxx_shared_library name cxx_flags) + cxx_library_with_type(${name} SHARED "${cxx_flags}" ${ARGN}) +endfunction() + +function(cxx_library name cxx_flags) + cxx_library_with_type(${name} "" "${cxx_flags}" ${ARGN}) +endfunction() + +# cxx_executable_with_flags(name cxx_flags libs srcs...) +# +# creates a named C++ executable that depends on the given libraries and +# is built from the given source files with the given compiler flags. +function(cxx_executable_with_flags name cxx_flags libs) + add_executable(${name} ${ARGN}) + if (cxx_flags) + set_target_properties(${name} + PROPERTIES + COMPILE_FLAGS "${cxx_flags}") + endif() + if (BUILD_SHARED_LIBS) + set_target_properties(${name} + PROPERTIES + COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") + endif() + # To support mixing linking in static and dynamic libraries, link each + # library in with an extra call to target_link_libraries. + foreach (lib "${libs}") + target_link_libraries(${name} ${lib}) + endforeach() +endfunction() + +# cxx_executable(name dir lib srcs...) +# +# creates a named target that depends on the given libs and is built +# from the given source files. dir/name.cc is implicitly included in +# the source file list. +function(cxx_executable name dir libs) + cxx_executable_with_flags( + ${name} "${cxx_default}" "${libs}" "${dir}/${name}.cc" ${ARGN}) +endfunction() + +# Sets PYTHONINTERP_FOUND and PYTHON_EXECUTABLE. +#find_package(PythonInterp) + +# cxx_test_with_flags(name cxx_flags libs srcs...) +# +# creates a named C++ test that depends on the given libs and is built +# from the given source files with the given compiler flags. +function(cxx_test_with_flags name cxx_flags libs) + cxx_executable_with_flags(${name} "${cxx_flags}" "${libs}" ${ARGN}) + add_test(${name} ${name}) +endfunction() + +# cxx_test(name libs srcs...) +# +# creates a named test target that depends on the given libs and is +# built from the given source files. Unlike cxx_test_with_flags, +# test/name.cc is already implicitly included in the source file list. +function(cxx_test name libs) + cxx_test_with_flags("${name}" "${cxx_default}" "${libs}" + "test/${name}.cc" ${ARGN}) +endfunction() + +# py_test(name) +# +# creates a Python test with the given name whose main module is in +# test/name.py. It does nothing if Python is not installed. +function(py_test name) + # We are not supporting Python tests on Linux yet as they consider + # all Linux environments to be google3 and try to use google3 features. + if (PYTHONINTERP_FOUND) + # ${CMAKE_BINARY_DIR} is known at configuration time, so we can + # directly bind it from cmake. ${CTEST_CONFIGURATION_TYPE} is known + # only at ctest runtime (by calling ctest -c ), so + # we have to escape $ to delay variable substitution here. + add_test(${name} + ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE}) + endif() +endfunction() diff --git a/libs/gtest/include/gtest/gtest-death-test.h b/libs/gtest/include/gtest/gtest-death-test.h new file mode 100644 index 000000000..a27883f0a --- /dev/null +++ b/libs/gtest/include/gtest/gtest-death-test.h @@ -0,0 +1,283 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the public API for death tests. It is +// #included by gtest.h so a user doesn't need to include this +// directly. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ + +#include "gtest/internal/gtest-death-test-internal.h" + +namespace testing { + +// This flag controls the style of death tests. Valid values are "threadsafe", +// meaning that the death test child process will re-execute the test binary +// from the start, running only a single death test, or "fast", +// meaning that the child process will execute the test logic immediately +// after forking. +GTEST_DECLARE_string_(death_test_style); + +#if GTEST_HAS_DEATH_TEST + +// The following macros are useful for writing death tests. + +// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is +// executed: +// +// 1. It generates a warning if there is more than one active +// thread. This is because it's safe to fork() or clone() only +// when there is a single thread. +// +// 2. The parent process clone()s a sub-process and runs the death +// test in it; the sub-process exits with code 0 at the end of the +// death test, if it hasn't exited already. +// +// 3. The parent process waits for the sub-process to terminate. +// +// 4. The parent process checks the exit code and error message of +// the sub-process. +// +// Examples: +// +// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number"); +// for (int i = 0; i < 5; i++) { +// EXPECT_DEATH(server.ProcessRequest(i), +// "Invalid request .* in ProcessRequest()") +// << "Failed to die on request " << i); +// } +// +// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting"); +// +// bool KilledBySIGHUP(int exit_code) { +// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP; +// } +// +// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!"); +// +// On the regular expressions used in death tests: +// +// On POSIX-compliant systems (*nix), we use the library, +// which uses the POSIX extended regex syntax. +// +// On other platforms (e.g. Windows), we only support a simple regex +// syntax implemented as part of Google Test. This limited +// implementation should be enough most of the time when writing +// death tests; though it lacks many features you can find in PCRE +// or POSIX extended regex syntax. For example, we don't support +// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and +// repetition count ("x{5,7}"), among others. +// +// Below is the syntax that we do support. We chose it to be a +// subset of both PCRE and POSIX extended regex, so it's easy to +// learn wherever you come from. In the following: 'A' denotes a +// literal character, period (.), or a single \\ escape sequence; +// 'x' and 'y' denote regular expressions; 'm' and 'n' are for +// natural numbers. +// +// c matches any literal character c +// \\d matches any decimal digit +// \\D matches any character that's not a decimal digit +// \\f matches \f +// \\n matches \n +// \\r matches \r +// \\s matches any ASCII whitespace, including \n +// \\S matches any character that's not a whitespace +// \\t matches \t +// \\v matches \v +// \\w matches any letter, _, or decimal digit +// \\W matches any character that \\w doesn't match +// \\c matches any literal character c, which must be a punctuation +// . matches any single character except \n +// A? matches 0 or 1 occurrences of A +// A* matches 0 or many occurrences of A +// A+ matches 1 or many occurrences of A +// ^ matches the beginning of a string (not that of each line) +// $ matches the end of a string (not that of each line) +// xy matches x followed by y +// +// If you accidentally use PCRE or POSIX extended regex features +// not implemented by us, you will get a run-time failure. In that +// case, please try to rewrite your regular expression within the +// above syntax. +// +// This implementation is *not* meant to be as highly tuned or robust +// as a compiled regex library, but should perform well enough for a +// death test, which already incurs significant overhead by launching +// a child process. +// +// Known caveats: +// +// A "threadsafe" style death test obtains the path to the test +// program from argv[0] and re-executes it in the sub-process. For +// simplicity, the current implementation doesn't search the PATH +// when launching the sub-process. This means that the user must +// invoke the test program via a path that contains at least one +// path separator (e.g. path/to/foo_test and +// /absolute/path/to/bar_test are fine, but foo_test is not). This +// is rarely a problem as people usually don't put the test binary +// directory in PATH. +// +// TODO(wan@google.com): make thread-safe death tests search the PATH. + +// Asserts that a given statement causes the program to exit, with an +// integer exit status that satisfies predicate, and emitting error output +// that matches regex. +# define ASSERT_EXIT(statement, predicate, regex) \ + GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) + +// Like ASSERT_EXIT, but continues on to successive tests in the +// test case, if any: +# define EXPECT_EXIT(statement, predicate, regex) \ + GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) + +// Asserts that a given statement causes the program to exit, either by +// explicitly exiting with a nonzero exit code or being killed by a +// signal, and emitting error output that matches regex. +# define ASSERT_DEATH(statement, regex) \ + ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) + +// Like ASSERT_DEATH, but continues on to successive tests in the +// test case, if any: +# define EXPECT_DEATH(statement, regex) \ + EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) + +// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*: + +// Tests that an exit code describes a normal exit with a given exit code. +class GTEST_API_ ExitedWithCode { + public: + explicit ExitedWithCode(int exit_code); + bool operator()(int exit_status) const; + private: + // No implementation - assignment is unsupported. + void operator=(const ExitedWithCode& other); + + const int exit_code_; +}; + +# if !GTEST_OS_WINDOWS +// Tests that an exit code describes an exit due to termination by a +// given signal. +class GTEST_API_ KilledBySignal { + public: + explicit KilledBySignal(int signum); + bool operator()(int exit_status) const; + private: + const int signum_; +}; +# endif // !GTEST_OS_WINDOWS + +// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode. +// The death testing framework causes this to have interesting semantics, +// since the sideeffects of the call are only visible in opt mode, and not +// in debug mode. +// +// In practice, this can be used to test functions that utilize the +// LOG(DFATAL) macro using the following style: +// +// int DieInDebugOr12(int* sideeffect) { +// if (sideeffect) { +// *sideeffect = 12; +// } +// LOG(DFATAL) << "death"; +// return 12; +// } +// +// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { +// int sideeffect = 0; +// // Only asserts in dbg. +// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); +// +// #ifdef NDEBUG +// // opt-mode has sideeffect visible. +// EXPECT_EQ(12, sideeffect); +// #else +// // dbg-mode no visible sideeffect. +// EXPECT_EQ(0, sideeffect); +// #endif +// } +// +// This will assert that DieInDebugReturn12InOpt() crashes in debug +// mode, usually due to a DCHECK or LOG(DFATAL), but returns the +// appropriate fallback value (12 in this case) in opt mode. If you +// need to test that a function has appropriate side-effects in opt +// mode, include assertions against the side-effects. A general +// pattern for this is: +// +// EXPECT_DEBUG_DEATH({ +// // Side-effects here will have an effect after this statement in +// // opt mode, but none in debug mode. +// EXPECT_EQ(12, DieInDebugOr12(&sideeffect)); +// }, "death"); +// +# ifdef NDEBUG + +# define EXPECT_DEBUG_DEATH(statement, regex) \ + do { statement; } while (::testing::internal::AlwaysFalse()) + +# define ASSERT_DEBUG_DEATH(statement, regex) \ + do { statement; } while (::testing::internal::AlwaysFalse()) + +# else + +# define EXPECT_DEBUG_DEATH(statement, regex) \ + EXPECT_DEATH(statement, regex) + +# define ASSERT_DEBUG_DEATH(statement, regex) \ + ASSERT_DEATH(statement, regex) + +# endif // NDEBUG for EXPECT_DEBUG_DEATH +#endif // GTEST_HAS_DEATH_TEST + +// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and +// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if +// death tests are supported; otherwise they just issue a warning. This is +// useful when you are combining death test assertions with normal test +// assertions in one test. +#if GTEST_HAS_DEATH_TEST +# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + EXPECT_DEATH(statement, regex) +# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + ASSERT_DEATH(statement, regex) +#else +# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) +# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) +#endif + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ diff --git a/libs/gtest/include/gtest/gtest-message.h b/libs/gtest/include/gtest/gtest-message.h new file mode 100644 index 000000000..9b7142f32 --- /dev/null +++ b/libs/gtest/include/gtest/gtest-message.h @@ -0,0 +1,230 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the Message class. +// +// IMPORTANT NOTE: Due to limitation of the C++ language, we have to +// leave some internal implementation details in this header file. +// They are clearly marked by comments like this: +// +// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// +// Such code is NOT meant to be used by a user directly, and is subject +// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user +// program! + +#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ + +#include + +#include "gtest/internal/gtest-string.h" +#include "gtest/internal/gtest-internal.h" + +namespace testing { + +// The Message class works like an ostream repeater. +// +// Typical usage: +// +// 1. You stream a bunch of values to a Message object. +// It will remember the text in a stringstream. +// 2. Then you stream the Message object to an ostream. +// This causes the text in the Message to be streamed +// to the ostream. +// +// For example; +// +// testing::Message foo; +// foo << 1 << " != " << 2; +// std::cout << foo; +// +// will print "1 != 2". +// +// Message is not intended to be inherited from. In particular, its +// destructor is not virtual. +// +// Note that stringstream behaves differently in gcc and in MSVC. You +// can stream a NULL char pointer to it in the former, but not in the +// latter (it causes an access violation if you do). The Message +// class hides this difference by treating a NULL char pointer as +// "(null)". +class GTEST_API_ Message { + private: + // The type of basic IO manipulators (endl, ends, and flush) for + // narrow streams. + typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); + + public: + // Constructs an empty Message. + // We allocate the stringstream separately because otherwise each use of + // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's + // stack frame leading to huge stack frames in some cases; gcc does not reuse + // the stack space. + Message() : ss_(new ::std::stringstream) { + // By default, we want there to be enough precision when printing + // a double to a Message. + *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); + } + + // Copy constructor. + Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT + *ss_ << msg.GetString(); + } + + // Constructs a Message from a C-string. + explicit Message(const char* str) : ss_(new ::std::stringstream) { + *ss_ << str; + } + +#if GTEST_OS_SYMBIAN + // Streams a value (either a pointer or not) to this object. + template + inline Message& operator <<(const T& value) { + StreamHelper(typename internal::is_pointer::type(), value); + return *this; + } +#else + // Streams a non-pointer value to this object. + template + inline Message& operator <<(const T& val) { + ::GTestStreamToHelper(ss_.get(), val); + return *this; + } + + // Streams a pointer value to this object. + // + // This function is an overload of the previous one. When you + // stream a pointer to a Message, this definition will be used as it + // is more specialized. (The C++ Standard, section + // [temp.func.order].) If you stream a non-pointer, then the + // previous definition will be used. + // + // The reason for this overload is that streaming a NULL pointer to + // ostream is undefined behavior. Depending on the compiler, you + // may get "0", "(nil)", "(null)", or an access violation. To + // ensure consistent result across compilers, we always treat NULL + // as "(null)". + template + inline Message& operator <<(T* const& pointer) { // NOLINT + if (pointer == NULL) { + *ss_ << "(null)"; + } else { + ::GTestStreamToHelper(ss_.get(), pointer); + } + return *this; + } +#endif // GTEST_OS_SYMBIAN + + // Since the basic IO manipulators are overloaded for both narrow + // and wide streams, we have to provide this specialized definition + // of operator <<, even though its body is the same as the + // templatized version above. Without this definition, streaming + // endl or other basic IO manipulators to Message will confuse the + // compiler. + Message& operator <<(BasicNarrowIoManip val) { + *ss_ << val; + return *this; + } + + // Instead of 1/0, we want to see true/false for bool values. + Message& operator <<(bool b) { + return *this << (b ? "true" : "false"); + } + + // These two overloads allow streaming a wide C string to a Message + // using the UTF-8 encoding. + Message& operator <<(const wchar_t* wide_c_str) { + return *this << internal::String::ShowWideCString(wide_c_str); + } + Message& operator <<(wchar_t* wide_c_str) { + return *this << internal::String::ShowWideCString(wide_c_str); + } + +#if GTEST_HAS_STD_WSTRING + // Converts the given wide string to a narrow string using the UTF-8 + // encoding, and streams the result to this Message object. + Message& operator <<(const ::std::wstring& wstr); +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_WSTRING + // Converts the given wide string to a narrow string using the UTF-8 + // encoding, and streams the result to this Message object. + Message& operator <<(const ::wstring& wstr); +#endif // GTEST_HAS_GLOBAL_WSTRING + + // Gets the text streamed to this object so far as a String. + // Each '\0' character in the buffer is replaced with "\\0". + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + internal::String GetString() const { + return internal::StringStreamToString(ss_.get()); + } + + private: + +#if GTEST_OS_SYMBIAN + // These are needed as the Nokia Symbian Compiler cannot decide between + // const T& and const T* in a function template. The Nokia compiler _can_ + // decide between class template specializations for T and T*, so a + // tr1::type_traits-like is_pointer works, and we can overload on that. + template + inline void StreamHelper(internal::true_type /*dummy*/, T* pointer) { + if (pointer == NULL) { + *ss_ << "(null)"; + } else { + ::GTestStreamToHelper(ss_.get(), pointer); + } + } + template + inline void StreamHelper(internal::false_type /*dummy*/, const T& value) { + ::GTestStreamToHelper(ss_.get(), value); + } +#endif // GTEST_OS_SYMBIAN + + // We'll hold the text streamed to this object here. + const internal::scoped_ptr< ::std::stringstream> ss_; + + // We declare (but don't implement) this to prevent the compiler + // from implementing the assignment operator. + void operator=(const Message&); +}; + +// Streams a Message to an ostream. +inline std::ostream& operator <<(std::ostream& os, const Message& sb) { + return os << sb.GetString(); +} + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ diff --git a/libs/gtest/include/gtest/gtest-param-test.h b/libs/gtest/include/gtest/gtest-param-test.h new file mode 100644 index 000000000..6407cfd68 --- /dev/null +++ b/libs/gtest/include/gtest/gtest-param-test.h @@ -0,0 +1,1421 @@ +// This file was GENERATED by command: +// pump.py gtest-param-test.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: vladl@google.com (Vlad Losev) +// +// Macros and functions for implementing parameterized tests +// in Google C++ Testing Framework (Google Test) +// +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ + + +// Value-parameterized tests allow you to test your code with different +// parameters without writing multiple copies of the same test. +// +// Here is how you use value-parameterized tests: + +#if 0 + +// To write value-parameterized tests, first you should define a fixture +// class. It is usually derived from testing::TestWithParam (see below for +// another inheritance scheme that's sometimes useful in more complicated +// class hierarchies), where the type of your parameter values. +// TestWithParam is itself derived from testing::Test. T can be any +// copyable type. If it's a raw pointer, you are responsible for managing the +// lifespan of the pointed values. + +class FooTest : public ::testing::TestWithParam { + // You can implement all the usual class fixture members here. +}; + +// Then, use the TEST_P macro to define as many parameterized tests +// for this fixture as you want. The _P suffix is for "parameterized" +// or "pattern", whichever you prefer to think. + +TEST_P(FooTest, DoesBlah) { + // Inside a test, access the test parameter with the GetParam() method + // of the TestWithParam class: + EXPECT_TRUE(foo.Blah(GetParam())); + ... +} + +TEST_P(FooTest, HasBlahBlah) { + ... +} + +// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test +// case with any set of parameters you want. Google Test defines a number +// of functions for generating test parameters. They return what we call +// (surprise!) parameter generators. Here is a summary of them, which +// are all in the testing namespace: +// +// +// Range(begin, end [, step]) - Yields values {begin, begin+step, +// begin+step+step, ...}. The values do not +// include end. step defaults to 1. +// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. +// ValuesIn(container) - Yields values from a C-style array, an STL +// ValuesIn(begin,end) container, or an iterator range [begin, end). +// Bool() - Yields sequence {false, true}. +// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product +// for the math savvy) of the values generated +// by the N generators. +// +// For more details, see comments at the definitions of these functions below +// in this file. +// +// The following statement will instantiate tests from the FooTest test case +// each with parameter values "meeny", "miny", and "moe". + +INSTANTIATE_TEST_CASE_P(InstantiationName, + FooTest, + Values("meeny", "miny", "moe")); + +// To distinguish different instances of the pattern, (yes, you +// can instantiate it more then once) the first argument to the +// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the +// actual test case name. Remember to pick unique prefixes for different +// instantiations. The tests from the instantiation above will have +// these names: +// +// * InstantiationName/FooTest.DoesBlah/0 for "meeny" +// * InstantiationName/FooTest.DoesBlah/1 for "miny" +// * InstantiationName/FooTest.DoesBlah/2 for "moe" +// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" +// * InstantiationName/FooTest.HasBlahBlah/1 for "miny" +// * InstantiationName/FooTest.HasBlahBlah/2 for "moe" +// +// You can use these names in --gtest_filter. +// +// This statement will instantiate all tests from FooTest again, each +// with parameter values "cat" and "dog": + +const char* pets[] = {"cat", "dog"}; +INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); + +// The tests from the instantiation above will have these names: +// +// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" +// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" +// +// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests +// in the given test case, whether their definitions come before or +// AFTER the INSTANTIATE_TEST_CASE_P statement. +// +// Please also note that generator expressions (including parameters to the +// generators) are evaluated in InitGoogleTest(), after main() has started. +// This allows the user on one hand, to adjust generator parameters in order +// to dynamically determine a set of tests to run and on the other hand, +// give the user a chance to inspect the generated tests with Google Test +// reflection API before RUN_ALL_TESTS() is executed. +// +// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc +// for more examples. +// +// In the future, we plan to publish the API for defining new parameter +// generators. But for now this interface remains part of the internal +// implementation and is subject to change. +// +// +// A parameterized test fixture must be derived from testing::Test and from +// testing::WithParamInterface, where T is the type of the parameter +// values. Inheriting from TestWithParam satisfies that requirement because +// TestWithParam inherits from both Test and WithParamInterface. In more +// complicated hierarchies, however, it is occasionally useful to inherit +// separately from Test and WithParamInterface. For example: + +class BaseTest : public ::testing::Test { + // You can inherit all the usual members for a non-parameterized test + // fixture here. +}; + +class DerivedTest : public BaseTest, public ::testing::WithParamInterface { + // The usual test fixture members go here too. +}; + +TEST_F(BaseTest, HasFoo) { + // This is an ordinary non-parameterized test. +} + +TEST_P(DerivedTest, DoesBlah) { + // GetParam works just the same here as if you inherit from TestWithParam. + EXPECT_TRUE(foo.Blah(GetParam())); +} + +#endif // 0 + +#include "gtest/internal/gtest-port.h" + +#if !GTEST_OS_SYMBIAN +# include +#endif + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-param-util.h" +#include "gtest/internal/gtest-param-util-generated.h" + +#if GTEST_HAS_PARAM_TEST + +namespace testing { + +// Functions producing parameter generators. +// +// Google Test uses these generators to produce parameters for value- +// parameterized tests. When a parameterized test case is instantiated +// with a particular generator, Google Test creates and runs tests +// for each element in the sequence produced by the generator. +// +// In the following sample, tests from test case FooTest are instantiated +// each three times with parameter values 3, 5, and 8: +// +// class FooTest : public TestWithParam { ... }; +// +// TEST_P(FooTest, TestThis) { +// } +// TEST_P(FooTest, TestThat) { +// } +// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); +// + +// Range() returns generators providing sequences of values in a range. +// +// Synopsis: +// Range(start, end) +// - returns a generator producing a sequence of values {start, start+1, +// start+2, ..., }. +// Range(start, end, step) +// - returns a generator producing a sequence of values {start, start+step, +// start+step+step, ..., }. +// Notes: +// * The generated sequences never include end. For example, Range(1, 5) +// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) +// returns a generator producing {1, 3, 5, 7}. +// * start and end must have the same type. That type may be any integral or +// floating-point type or a user defined type satisfying these conditions: +// * It must be assignable (have operator=() defined). +// * It must have operator+() (operator+(int-compatible type) for +// two-operand version). +// * It must have operator<() defined. +// Elements in the resulting sequences will also have that type. +// * Condition start < end must be satisfied in order for resulting sequences +// to contain any elements. +// +template +internal::ParamGenerator Range(T start, T end, IncrementT step) { + return internal::ParamGenerator( + new internal::RangeGenerator(start, end, step)); +} + +template +internal::ParamGenerator Range(T start, T end) { + return Range(start, end, 1); +} + +// ValuesIn() function allows generation of tests with parameters coming from +// a container. +// +// Synopsis: +// ValuesIn(const T (&array)[N]) +// - returns a generator producing sequences with elements from +// a C-style array. +// ValuesIn(const Container& container) +// - returns a generator producing sequences with elements from +// an STL-style container. +// ValuesIn(Iterator begin, Iterator end) +// - returns a generator producing sequences with elements from +// a range [begin, end) defined by a pair of STL-style iterators. These +// iterators can also be plain C pointers. +// +// Please note that ValuesIn copies the values from the containers +// passed in and keeps them to generate tests in RUN_ALL_TESTS(). +// +// Examples: +// +// This instantiates tests from test case StringTest +// each with C-string values of "foo", "bar", and "baz": +// +// const char* strings[] = {"foo", "bar", "baz"}; +// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); +// +// This instantiates tests from test case StlStringTest +// each with STL strings with values "a" and "b": +// +// ::std::vector< ::std::string> GetParameterStrings() { +// ::std::vector< ::std::string> v; +// v.push_back("a"); +// v.push_back("b"); +// return v; +// } +// +// INSTANTIATE_TEST_CASE_P(CharSequence, +// StlStringTest, +// ValuesIn(GetParameterStrings())); +// +// +// This will also instantiate tests from CharTest +// each with parameter values 'a' and 'b': +// +// ::std::list GetParameterChars() { +// ::std::list list; +// list.push_back('a'); +// list.push_back('b'); +// return list; +// } +// ::std::list l = GetParameterChars(); +// INSTANTIATE_TEST_CASE_P(CharSequence2, +// CharTest, +// ValuesIn(l.begin(), l.end())); +// +template +internal::ParamGenerator< + typename ::testing::internal::IteratorTraits::value_type> +ValuesIn(ForwardIterator begin, ForwardIterator end) { + typedef typename ::testing::internal::IteratorTraits + ::value_type ParamType; + return internal::ParamGenerator( + new internal::ValuesInIteratorRangeGenerator(begin, end)); +} + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]) { + return ValuesIn(array, array + N); +} + +template +internal::ParamGenerator ValuesIn( + const Container& container) { + return ValuesIn(container.begin(), container.end()); +} + +// Values() allows generating tests from explicitly specified list of +// parameters. +// +// Synopsis: +// Values(T v1, T v2, ..., T vN) +// - returns a generator producing sequences with elements v1, v2, ..., vN. +// +// For example, this instantiates tests from test case BarTest each +// with values "one", "two", and "three": +// +// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); +// +// This instantiates tests from test case BazTest each with values 1, 2, 3.5. +// The exact type of values will depend on the type of parameter in BazTest. +// +// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); +// +// Currently, Values() supports from 1 to 50 parameters. +// +template +internal::ValueArray1 Values(T1 v1) { + return internal::ValueArray1(v1); +} + +template +internal::ValueArray2 Values(T1 v1, T2 v2) { + return internal::ValueArray2(v1, v2); +} + +template +internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { + return internal::ValueArray3(v1, v2, v3); +} + +template +internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { + return internal::ValueArray4(v1, v2, v3, v4); +} + +template +internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5) { + return internal::ValueArray5(v1, v2, v3, v4, v5); +} + +template +internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6) { + return internal::ValueArray6(v1, v2, v3, v4, v5, v6); +} + +template +internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7) { + return internal::ValueArray7(v1, v2, v3, v4, v5, + v6, v7); +} + +template +internal::ValueArray8 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { + return internal::ValueArray8(v1, v2, v3, v4, + v5, v6, v7, v8); +} + +template +internal::ValueArray9 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { + return internal::ValueArray9(v1, v2, v3, + v4, v5, v6, v7, v8, v9); +} + +template +internal::ValueArray10 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { + return internal::ValueArray10(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10); +} + +template +internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11) { + return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); +} + +template +internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12) { + return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); +} + +template +internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13) { + return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); +} + +template +internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { + return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14); +} + +template +internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { + return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15); +} + +template +internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16) { + return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16); +} + +template +internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17) { + return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17); +} + +template +internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18) { + return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18); +} + +template +internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { + return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); +} + +template +internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { + return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); +} + +template +internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { + return internal::ValueArray21(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); +} + +template +internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22) { + return internal::ValueArray22(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22); +} + +template +internal::ValueArray23 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23) { + return internal::ValueArray23(v1, v2, v3, + v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23); +} + +template +internal::ValueArray24 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24) { + return internal::ValueArray24(v1, v2, + v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, + v19, v20, v21, v22, v23, v24); +} + +template +internal::ValueArray25 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, + T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, + T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { + return internal::ValueArray25(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, + v18, v19, v20, v21, v22, v23, v24, v25); +} + +template +internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26) { + return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, + v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); +} + +template +internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27) { + return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, + v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); +} + +template +internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28) { + return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, + v28); +} + +template +internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29) { + return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, + v27, v28, v29); +} + +template +internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { + return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, + v26, v27, v28, v29, v30); +} + +template +internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { + return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, + v25, v26, v27, v28, v29, v30, v31); +} + +template +internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32) { + return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32); +} + +template +internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33) { + return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); +} + +template +internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, + T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, + T31 v31, T32 v32, T33 v33, T34 v34) { + return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, + v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); +} + +template +internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { + return internal::ValueArray35(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, + v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); +} + +template +internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { + return internal::ValueArray36(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36); +} + +template +internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37) { + return internal::ValueArray37(v1, v2, v3, + v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36, v37); +} + +template +internal::ValueArray38 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37, T38 v38) { + return internal::ValueArray38(v1, v2, + v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, + v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, + v33, v34, v35, v36, v37, v38); +} + +template +internal::ValueArray39 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37, T38 v38, T39 v39) { + return internal::ValueArray39(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, + v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, + v32, v33, v34, v35, v36, v37, v38, v39); +} + +template +internal::ValueArray40 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, + T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, + T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, + T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, + T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { + return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, + v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, + v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); +} + +template +internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { + return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, + v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, + v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); +} + +template +internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42) { + return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, + v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, + v42); +} + +template +internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43) { + return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, + v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, + v41, v42, v43); +} + +template +internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44) { + return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, + v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, + v40, v41, v42, v43, v44); +} + +template +internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, + T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, + T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { + return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, + v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, + v39, v40, v41, v42, v43, v44, v45); +} + +template +internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { + return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, + v38, v39, v40, v41, v42, v43, v44, v45, v46); +} + +template +internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { + return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, + v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); +} + +template +internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, + T48 v48) { + return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, + v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, + v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); +} + +template +internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, + T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, + T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, + T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, + T47 v47, T48 v48, T49 v49) { + return internal::ValueArray49(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, + v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, + v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); +} + +template +internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, + T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, + T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { + return internal::ValueArray50(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, + v48, v49, v50); +} + +// Bool() allows generating tests with parameters in a set of (false, true). +// +// Synopsis: +// Bool() +// - returns a generator producing sequences with elements {false, true}. +// +// It is useful when testing code that depends on Boolean flags. Combinations +// of multiple flags can be tested when several Bool()'s are combined using +// Combine() function. +// +// In the following example all tests in the test case FlagDependentTest +// will be instantiated twice with parameters false and true. +// +// class FlagDependentTest : public testing::TestWithParam { +// virtual void SetUp() { +// external_flag = GetParam(); +// } +// } +// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); +// +inline internal::ParamGenerator Bool() { + return Values(false, true); +} + +# if GTEST_HAS_COMBINE +// Combine() allows the user to combine two or more sequences to produce +// values of a Cartesian product of those sequences' elements. +// +// Synopsis: +// Combine(gen1, gen2, ..., genN) +// - returns a generator producing sequences with elements coming from +// the Cartesian product of elements from the sequences generated by +// gen1, gen2, ..., genN. The sequence elements will have a type of +// tuple where T1, T2, ..., TN are the types +// of elements from sequences produces by gen1, gen2, ..., genN. +// +// Combine can have up to 10 arguments. This number is currently limited +// by the maximum number of elements in the tuple implementation used by Google +// Test. +// +// Example: +// +// This will instantiate tests in test case AnimalTest each one with +// the parameter values tuple("cat", BLACK), tuple("cat", WHITE), +// tuple("dog", BLACK), and tuple("dog", WHITE): +// +// enum Color { BLACK, GRAY, WHITE }; +// class AnimalTest +// : public testing::TestWithParam > {...}; +// +// TEST_P(AnimalTest, AnimalLooksNice) {...} +// +// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, +// Combine(Values("cat", "dog"), +// Values(BLACK, WHITE))); +// +// This will instantiate tests in FlagDependentTest with all variations of two +// Boolean flags: +// +// class FlagDependentTest +// : public testing::TestWithParam > { +// virtual void SetUp() { +// // Assigns external_flag_1 and external_flag_2 values from the tuple. +// tie(external_flag_1, external_flag_2) = GetParam(); +// } +// }; +// +// TEST_P(FlagDependentTest, TestFeature1) { +// // Test your code using external_flag_1 and external_flag_2 here. +// } +// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, +// Combine(Bool(), Bool())); +// +template +internal::CartesianProductHolder2 Combine( + const Generator1& g1, const Generator2& g2) { + return internal::CartesianProductHolder2( + g1, g2); +} + +template +internal::CartesianProductHolder3 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3) { + return internal::CartesianProductHolder3( + g1, g2, g3); +} + +template +internal::CartesianProductHolder4 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4) { + return internal::CartesianProductHolder4( + g1, g2, g3, g4); +} + +template +internal::CartesianProductHolder5 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5) { + return internal::CartesianProductHolder5( + g1, g2, g3, g4, g5); +} + +template +internal::CartesianProductHolder6 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6) { + return internal::CartesianProductHolder6( + g1, g2, g3, g4, g5, g6); +} + +template +internal::CartesianProductHolder7 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7) { + return internal::CartesianProductHolder7( + g1, g2, g3, g4, g5, g6, g7); +} + +template +internal::CartesianProductHolder8 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8) { + return internal::CartesianProductHolder8( + g1, g2, g3, g4, g5, g6, g7, g8); +} + +template +internal::CartesianProductHolder9 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8, const Generator9& g9) { + return internal::CartesianProductHolder9( + g1, g2, g3, g4, g5, g6, g7, g8, g9); +} + +template +internal::CartesianProductHolder10 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8, const Generator9& g9, + const Generator10& g10) { + return internal::CartesianProductHolder10( + g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); +} +# endif // GTEST_HAS_COMBINE + + + +# define TEST_P(test_case_name, test_name) \ + class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ + : public test_case_name { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ + virtual void TestBody(); \ + private: \ + static int AddToRegistry() { \ + ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ + GetTestCasePatternHolder(\ + #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ + #test_case_name, \ + #test_name, \ + new ::testing::internal::TestMetaFactory< \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ + return 0; \ + } \ + static int gtest_registering_dummy_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ + }; \ + int GTEST_TEST_CLASS_NAME_(test_case_name, \ + test_name)::gtest_registering_dummy_ = \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ + void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() + +# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ + ::testing::internal::ParamGenerator \ + gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ + int gtest_##prefix##test_case_name##_dummy_ = \ + ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ + GetTestCasePatternHolder(\ + #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ + #prefix, \ + >est_##prefix##test_case_name##_EvalGenerator_, \ + __FILE__, __LINE__) + +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ diff --git a/libs/gtest/include/gtest/gtest-param-test.h.pump b/libs/gtest/include/gtest/gtest-param-test.h.pump new file mode 100644 index 000000000..401cb513a --- /dev/null +++ b/libs/gtest/include/gtest/gtest-param-test.h.pump @@ -0,0 +1,487 @@ +$$ -*- mode: c++; -*- +$var n = 50 $$ Maximum length of Values arguments we want to support. +$var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: vladl@google.com (Vlad Losev) +// +// Macros and functions for implementing parameterized tests +// in Google C++ Testing Framework (Google Test) +// +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ + + +// Value-parameterized tests allow you to test your code with different +// parameters without writing multiple copies of the same test. +// +// Here is how you use value-parameterized tests: + +#if 0 + +// To write value-parameterized tests, first you should define a fixture +// class. It is usually derived from testing::TestWithParam (see below for +// another inheritance scheme that's sometimes useful in more complicated +// class hierarchies), where the type of your parameter values. +// TestWithParam is itself derived from testing::Test. T can be any +// copyable type. If it's a raw pointer, you are responsible for managing the +// lifespan of the pointed values. + +class FooTest : public ::testing::TestWithParam { + // You can implement all the usual class fixture members here. +}; + +// Then, use the TEST_P macro to define as many parameterized tests +// for this fixture as you want. The _P suffix is for "parameterized" +// or "pattern", whichever you prefer to think. + +TEST_P(FooTest, DoesBlah) { + // Inside a test, access the test parameter with the GetParam() method + // of the TestWithParam class: + EXPECT_TRUE(foo.Blah(GetParam())); + ... +} + +TEST_P(FooTest, HasBlahBlah) { + ... +} + +// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test +// case with any set of parameters you want. Google Test defines a number +// of functions for generating test parameters. They return what we call +// (surprise!) parameter generators. Here is a summary of them, which +// are all in the testing namespace: +// +// +// Range(begin, end [, step]) - Yields values {begin, begin+step, +// begin+step+step, ...}. The values do not +// include end. step defaults to 1. +// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. +// ValuesIn(container) - Yields values from a C-style array, an STL +// ValuesIn(begin,end) container, or an iterator range [begin, end). +// Bool() - Yields sequence {false, true}. +// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product +// for the math savvy) of the values generated +// by the N generators. +// +// For more details, see comments at the definitions of these functions below +// in this file. +// +// The following statement will instantiate tests from the FooTest test case +// each with parameter values "meeny", "miny", and "moe". + +INSTANTIATE_TEST_CASE_P(InstantiationName, + FooTest, + Values("meeny", "miny", "moe")); + +// To distinguish different instances of the pattern, (yes, you +// can instantiate it more then once) the first argument to the +// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the +// actual test case name. Remember to pick unique prefixes for different +// instantiations. The tests from the instantiation above will have +// these names: +// +// * InstantiationName/FooTest.DoesBlah/0 for "meeny" +// * InstantiationName/FooTest.DoesBlah/1 for "miny" +// * InstantiationName/FooTest.DoesBlah/2 for "moe" +// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" +// * InstantiationName/FooTest.HasBlahBlah/1 for "miny" +// * InstantiationName/FooTest.HasBlahBlah/2 for "moe" +// +// You can use these names in --gtest_filter. +// +// This statement will instantiate all tests from FooTest again, each +// with parameter values "cat" and "dog": + +const char* pets[] = {"cat", "dog"}; +INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); + +// The tests from the instantiation above will have these names: +// +// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" +// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" +// +// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests +// in the given test case, whether their definitions come before or +// AFTER the INSTANTIATE_TEST_CASE_P statement. +// +// Please also note that generator expressions (including parameters to the +// generators) are evaluated in InitGoogleTest(), after main() has started. +// This allows the user on one hand, to adjust generator parameters in order +// to dynamically determine a set of tests to run and on the other hand, +// give the user a chance to inspect the generated tests with Google Test +// reflection API before RUN_ALL_TESTS() is executed. +// +// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc +// for more examples. +// +// In the future, we plan to publish the API for defining new parameter +// generators. But for now this interface remains part of the internal +// implementation and is subject to change. +// +// +// A parameterized test fixture must be derived from testing::Test and from +// testing::WithParamInterface, where T is the type of the parameter +// values. Inheriting from TestWithParam satisfies that requirement because +// TestWithParam inherits from both Test and WithParamInterface. In more +// complicated hierarchies, however, it is occasionally useful to inherit +// separately from Test and WithParamInterface. For example: + +class BaseTest : public ::testing::Test { + // You can inherit all the usual members for a non-parameterized test + // fixture here. +}; + +class DerivedTest : public BaseTest, public ::testing::WithParamInterface { + // The usual test fixture members go here too. +}; + +TEST_F(BaseTest, HasFoo) { + // This is an ordinary non-parameterized test. +} + +TEST_P(DerivedTest, DoesBlah) { + // GetParam works just the same here as if you inherit from TestWithParam. + EXPECT_TRUE(foo.Blah(GetParam())); +} + +#endif // 0 + +#include "gtest/internal/gtest-port.h" + +#if !GTEST_OS_SYMBIAN +# include +#endif + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-param-util.h" +#include "gtest/internal/gtest-param-util-generated.h" + +#if GTEST_HAS_PARAM_TEST + +namespace testing { + +// Functions producing parameter generators. +// +// Google Test uses these generators to produce parameters for value- +// parameterized tests. When a parameterized test case is instantiated +// with a particular generator, Google Test creates and runs tests +// for each element in the sequence produced by the generator. +// +// In the following sample, tests from test case FooTest are instantiated +// each three times with parameter values 3, 5, and 8: +// +// class FooTest : public TestWithParam { ... }; +// +// TEST_P(FooTest, TestThis) { +// } +// TEST_P(FooTest, TestThat) { +// } +// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); +// + +// Range() returns generators providing sequences of values in a range. +// +// Synopsis: +// Range(start, end) +// - returns a generator producing a sequence of values {start, start+1, +// start+2, ..., }. +// Range(start, end, step) +// - returns a generator producing a sequence of values {start, start+step, +// start+step+step, ..., }. +// Notes: +// * The generated sequences never include end. For example, Range(1, 5) +// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) +// returns a generator producing {1, 3, 5, 7}. +// * start and end must have the same type. That type may be any integral or +// floating-point type or a user defined type satisfying these conditions: +// * It must be assignable (have operator=() defined). +// * It must have operator+() (operator+(int-compatible type) for +// two-operand version). +// * It must have operator<() defined. +// Elements in the resulting sequences will also have that type. +// * Condition start < end must be satisfied in order for resulting sequences +// to contain any elements. +// +template +internal::ParamGenerator Range(T start, T end, IncrementT step) { + return internal::ParamGenerator( + new internal::RangeGenerator(start, end, step)); +} + +template +internal::ParamGenerator Range(T start, T end) { + return Range(start, end, 1); +} + +// ValuesIn() function allows generation of tests with parameters coming from +// a container. +// +// Synopsis: +// ValuesIn(const T (&array)[N]) +// - returns a generator producing sequences with elements from +// a C-style array. +// ValuesIn(const Container& container) +// - returns a generator producing sequences with elements from +// an STL-style container. +// ValuesIn(Iterator begin, Iterator end) +// - returns a generator producing sequences with elements from +// a range [begin, end) defined by a pair of STL-style iterators. These +// iterators can also be plain C pointers. +// +// Please note that ValuesIn copies the values from the containers +// passed in and keeps them to generate tests in RUN_ALL_TESTS(). +// +// Examples: +// +// This instantiates tests from test case StringTest +// each with C-string values of "foo", "bar", and "baz": +// +// const char* strings[] = {"foo", "bar", "baz"}; +// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); +// +// This instantiates tests from test case StlStringTest +// each with STL strings with values "a" and "b": +// +// ::std::vector< ::std::string> GetParameterStrings() { +// ::std::vector< ::std::string> v; +// v.push_back("a"); +// v.push_back("b"); +// return v; +// } +// +// INSTANTIATE_TEST_CASE_P(CharSequence, +// StlStringTest, +// ValuesIn(GetParameterStrings())); +// +// +// This will also instantiate tests from CharTest +// each with parameter values 'a' and 'b': +// +// ::std::list GetParameterChars() { +// ::std::list list; +// list.push_back('a'); +// list.push_back('b'); +// return list; +// } +// ::std::list l = GetParameterChars(); +// INSTANTIATE_TEST_CASE_P(CharSequence2, +// CharTest, +// ValuesIn(l.begin(), l.end())); +// +template +internal::ParamGenerator< + typename ::testing::internal::IteratorTraits::value_type> +ValuesIn(ForwardIterator begin, ForwardIterator end) { + typedef typename ::testing::internal::IteratorTraits + ::value_type ParamType; + return internal::ParamGenerator( + new internal::ValuesInIteratorRangeGenerator(begin, end)); +} + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]) { + return ValuesIn(array, array + N); +} + +template +internal::ParamGenerator ValuesIn( + const Container& container) { + return ValuesIn(container.begin(), container.end()); +} + +// Values() allows generating tests from explicitly specified list of +// parameters. +// +// Synopsis: +// Values(T v1, T v2, ..., T vN) +// - returns a generator producing sequences with elements v1, v2, ..., vN. +// +// For example, this instantiates tests from test case BarTest each +// with values "one", "two", and "three": +// +// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); +// +// This instantiates tests from test case BazTest each with values 1, 2, 3.5. +// The exact type of values will depend on the type of parameter in BazTest. +// +// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); +// +// Currently, Values() supports from 1 to $n parameters. +// +$range i 1..n +$for i [[ +$range j 1..i + +template <$for j, [[typename T$j]]> +internal::ValueArray$i<$for j, [[T$j]]> Values($for j, [[T$j v$j]]) { + return internal::ValueArray$i<$for j, [[T$j]]>($for j, [[v$j]]); +} + +]] + +// Bool() allows generating tests with parameters in a set of (false, true). +// +// Synopsis: +// Bool() +// - returns a generator producing sequences with elements {false, true}. +// +// It is useful when testing code that depends on Boolean flags. Combinations +// of multiple flags can be tested when several Bool()'s are combined using +// Combine() function. +// +// In the following example all tests in the test case FlagDependentTest +// will be instantiated twice with parameters false and true. +// +// class FlagDependentTest : public testing::TestWithParam { +// virtual void SetUp() { +// external_flag = GetParam(); +// } +// } +// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); +// +inline internal::ParamGenerator Bool() { + return Values(false, true); +} + +# if GTEST_HAS_COMBINE +// Combine() allows the user to combine two or more sequences to produce +// values of a Cartesian product of those sequences' elements. +// +// Synopsis: +// Combine(gen1, gen2, ..., genN) +// - returns a generator producing sequences with elements coming from +// the Cartesian product of elements from the sequences generated by +// gen1, gen2, ..., genN. The sequence elements will have a type of +// tuple where T1, T2, ..., TN are the types +// of elements from sequences produces by gen1, gen2, ..., genN. +// +// Combine can have up to $maxtuple arguments. This number is currently limited +// by the maximum number of elements in the tuple implementation used by Google +// Test. +// +// Example: +// +// This will instantiate tests in test case AnimalTest each one with +// the parameter values tuple("cat", BLACK), tuple("cat", WHITE), +// tuple("dog", BLACK), and tuple("dog", WHITE): +// +// enum Color { BLACK, GRAY, WHITE }; +// class AnimalTest +// : public testing::TestWithParam > {...}; +// +// TEST_P(AnimalTest, AnimalLooksNice) {...} +// +// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, +// Combine(Values("cat", "dog"), +// Values(BLACK, WHITE))); +// +// This will instantiate tests in FlagDependentTest with all variations of two +// Boolean flags: +// +// class FlagDependentTest +// : public testing::TestWithParam > { +// virtual void SetUp() { +// // Assigns external_flag_1 and external_flag_2 values from the tuple. +// tie(external_flag_1, external_flag_2) = GetParam(); +// } +// }; +// +// TEST_P(FlagDependentTest, TestFeature1) { +// // Test your code using external_flag_1 and external_flag_2 here. +// } +// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, +// Combine(Bool(), Bool())); +// +$range i 2..maxtuple +$for i [[ +$range j 1..i + +template <$for j, [[typename Generator$j]]> +internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( + $for j, [[const Generator$j& g$j]]) { + return internal::CartesianProductHolder$i<$for j, [[Generator$j]]>( + $for j, [[g$j]]); +} + +]] +# endif // GTEST_HAS_COMBINE + + + +# define TEST_P(test_case_name, test_name) \ + class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ + : public test_case_name { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ + virtual void TestBody(); \ + private: \ + static int AddToRegistry() { \ + ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ + GetTestCasePatternHolder(\ + #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ + #test_case_name, \ + #test_name, \ + new ::testing::internal::TestMetaFactory< \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ + return 0; \ + } \ + static int gtest_registering_dummy_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ + }; \ + int GTEST_TEST_CLASS_NAME_(test_case_name, \ + test_name)::gtest_registering_dummy_ = \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ + void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() + +# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ + ::testing::internal::ParamGenerator \ + gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ + int gtest_##prefix##test_case_name##_dummy_ = \ + ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ + GetTestCasePatternHolder(\ + #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ + #prefix, \ + >est_##prefix##test_case_name##_EvalGenerator_, \ + __FILE__, __LINE__) + +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ diff --git a/libs/gtest/include/gtest/gtest-printers.h b/libs/gtest/include/gtest/gtest-printers.h new file mode 100644 index 000000000..9cbab3ff4 --- /dev/null +++ b/libs/gtest/include/gtest/gtest-printers.h @@ -0,0 +1,796 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Test - The Google C++ Testing Framework +// +// This file implements a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); +// +// A user can teach this function how to print a class type T by +// defining either operator<<() or PrintTo() in the namespace that +// defines T. More specifically, the FIRST defined function in the +// following list will be used (assuming T is defined in namespace +// foo): +// +// 1. foo::PrintTo(const T&, ostream*) +// 2. operator<<(ostream&, const T&) defined in either foo or the +// global namespace. +// +// If none of the above is defined, it will print the debug string of +// the value if it is a protocol buffer, or print the raw bytes in the +// value otherwise. +// +// To aid debugging: when T is a reference type, the address of the +// value is also printed; when T is a (const) char pointer, both the +// pointer value and the NUL-terminated string it points to are +// printed. +// +// We also provide some convenient wrappers: +// +// // Prints a value to a string. For a (const or not) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// std::string ::testing::PrintToString(const T& value); +// +// // Prints a value tersely: for a reference type, the referenced +// // value (but not the address) is printed; for a (const or not) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// void ::testing::internal::UniversalTersePrint(const T& value, ostream*); +// +// // Prints value using the type inferred by the compiler. The difference +// // from UniversalTersePrint() is that this function prints both the +// // pointer and the NUL-terminated string for a (const or not) char pointer. +// void ::testing::internal::UniversalPrint(const T& value, ostream*); +// +// // Prints the fields of a tuple tersely to a string vector, one +// // element for each field. Tuple support must be enabled in +// // gtest-port.h. +// std::vector UniversalTersePrintTupleFieldsToStrings( +// const Tuple& value); +// +// Known limitation: +// +// The print primitives print the elements of an STL-style container +// using the compiler-inferred type of *iter where iter is a +// const_iterator of the container. When const_iterator is an input +// iterator but not a forward iterator, this inferred type may not +// match value_type, and the print output may be incorrect. In +// practice, this is rarely a problem as for most containers +// const_iterator is a forward iterator. We'll fix this if there's an +// actual need for it. Note that this fix cannot rely on value_type +// being defined as many user-defined container types don't have +// value_type. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ + +#include // NOLINT +#include +#include +#include +#include +#include "gtest/internal/gtest-port.h" +#include "gtest/internal/gtest-internal.h" + +namespace testing { + +// Definitions in the 'internal' and 'internal2' name spaces are +// subject to change without notice. DO NOT USE THEM IN USER CODE! +namespace internal2 { + +// Prints the given number of bytes in the given object to the given +// ostream. +GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes, + size_t count, + ::std::ostream* os); + +// For selecting which printer to use when a given type has neither << +// nor PrintTo(). +enum TypeKind { + kProtobuf, // a protobuf type + kConvertibleToInteger, // a type implicitly convertible to BiggestInt + // (e.g. a named or unnamed enum type) + kOtherType // anything else +}; + +// TypeWithoutFormatter::PrintValue(value, os) is called +// by the universal printer to print a value of type T when neither +// operator<< nor PrintTo() is defined for T, where kTypeKind is the +// "kind" of T as defined by enum TypeKind. +template +class TypeWithoutFormatter { + public: + // This default version is called when kTypeKind is kOtherType. + static void PrintValue(const T& value, ::std::ostream* os) { + PrintBytesInObjectTo(reinterpret_cast(&value), + sizeof(value), os); + } +}; + +// We print a protobuf using its ShortDebugString() when the string +// doesn't exceed this many characters; otherwise we print it using +// DebugString() for better readability. +const size_t kProtobufOneLinerMaxLength = 50; + +template +class TypeWithoutFormatter { + public: + static void PrintValue(const T& value, ::std::ostream* os) { + const ::testing::internal::string short_str = value.ShortDebugString(); + const ::testing::internal::string pretty_str = + short_str.length() <= kProtobufOneLinerMaxLength ? + short_str : ("\n" + value.DebugString()); + *os << ("<" + pretty_str + ">"); + } +}; + +template +class TypeWithoutFormatter { + public: + // Since T has no << operator or PrintTo() but can be implicitly + // converted to BiggestInt, we print it as a BiggestInt. + // + // Most likely T is an enum type (either named or unnamed), in which + // case printing it as an integer is the desired behavior. In case + // T is not an enum, printing it as an integer is the best we can do + // given that it has no user-defined printer. + static void PrintValue(const T& value, ::std::ostream* os) { + const internal::BiggestInt kBigInt = value; + *os << kBigInt; + } +}; + +// Prints the given value to the given ostream. If the value is a +// protocol message, its debug string is printed; if it's an enum or +// of a type implicitly convertible to BiggestInt, it's printed as an +// integer; otherwise the bytes in the value are printed. This is +// what UniversalPrinter::Print() does when it knows nothing about +// type T and T has neither << operator nor PrintTo(). +// +// A user can override this behavior for a class type Foo by defining +// a << operator in the namespace where Foo is defined. +// +// We put this operator in namespace 'internal2' instead of 'internal' +// to simplify the implementation, as much code in 'internal' needs to +// use << in STL, which would conflict with our own << were it defined +// in 'internal'. +// +// Note that this operator<< takes a generic std::basic_ostream type instead of the more restricted std::ostream. If +// we define it to take an std::ostream instead, we'll get an +// "ambiguous overloads" compiler error when trying to print a type +// Foo that supports streaming to std::basic_ostream, as the compiler cannot tell whether +// operator<<(std::ostream&, const T&) or +// operator<<(std::basic_stream, const Foo&) is more +// specific. +template +::std::basic_ostream& operator<<( + ::std::basic_ostream& os, const T& x) { + TypeWithoutFormatter::value ? kProtobuf : + internal::ImplicitlyConvertible::value ? + kConvertibleToInteger : kOtherType)>::PrintValue(x, &os); + return os; +} + +} // namespace internal2 +} // namespace testing + +// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up +// magic needed for implementing UniversalPrinter won't work. +namespace testing_internal { + +// Used to print a value that is not an STL-style container when the +// user doesn't define PrintTo() for it. +template +void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { + // With the following statement, during unqualified name lookup, + // testing::internal2::operator<< appears as if it was declared in + // the nearest enclosing namespace that contains both + // ::testing_internal and ::testing::internal2, i.e. the global + // namespace. For more details, refer to the C++ Standard section + // 7.3.4-1 [namespace.udir]. This allows us to fall back onto + // testing::internal2::operator<< in case T doesn't come with a << + // operator. + // + // We cannot write 'using ::testing::internal2::operator<<;', which + // gcc 3.3 fails to compile due to a compiler bug. + using namespace ::testing::internal2; // NOLINT + + // Assuming T is defined in namespace foo, in the next statement, + // the compiler will consider all of: + // + // 1. foo::operator<< (thanks to Koenig look-up), + // 2. ::operator<< (as the current namespace is enclosed in ::), + // 3. testing::internal2::operator<< (thanks to the using statement above). + // + // The operator<< whose type matches T best will be picked. + // + // We deliberately allow #2 to be a candidate, as sometimes it's + // impossible to define #1 (e.g. when foo is ::std, defining + // anything in it is undefined behavior unless you are a compiler + // vendor.). + *os << value; +} + +} // namespace testing_internal + +namespace testing { +namespace internal { + +// UniversalPrinter::Print(value, ostream_ptr) prints the given +// value to the given ostream. The caller must ensure that +// 'ostream_ptr' is not NULL, or the behavior is undefined. +// +// We define UniversalPrinter as a class template (as opposed to a +// function template), as we need to partially specialize it for +// reference types, which cannot be done with function templates. +template +class UniversalPrinter; + +template +void UniversalPrint(const T& value, ::std::ostream* os); + +// Used to print an STL-style container when the user doesn't define +// a PrintTo() for it. +template +void DefaultPrintTo(IsContainer /* dummy */, + false_type /* is not a pointer */, + const C& container, ::std::ostream* os) { + const size_t kMaxCount = 32; // The maximum number of elements to print. + *os << '{'; + size_t count = 0; + for (typename C::const_iterator it = container.begin(); + it != container.end(); ++it, ++count) { + if (count > 0) { + *os << ','; + if (count == kMaxCount) { // Enough has been printed. + *os << " ..."; + break; + } + } + *os << ' '; + // We cannot call PrintTo(*it, os) here as PrintTo() doesn't + // handle *it being a native array. + internal::UniversalPrint(*it, os); + } + + if (count > 0) { + *os << ' '; + } + *os << '}'; +} + +// Used to print a pointer that is neither a char pointer nor a member +// pointer, when the user doesn't define PrintTo() for it. (A member +// variable pointer or member function pointer doesn't really point to +// a location in the address space. Their representation is +// implementation-defined. Therefore they will be printed as raw +// bytes.) +template +void DefaultPrintTo(IsNotContainer /* dummy */, + true_type /* is a pointer */, + T* p, ::std::ostream* os) { + if (p == NULL) { + *os << "NULL"; + } else { + // C++ doesn't allow casting from a function pointer to any object + // pointer. + // + // IsTrue() silences warnings: "Condition is always true", + // "unreachable code". + if (IsTrue(ImplicitlyConvertible::value)) { + // T is not a function type. We just call << to print p, + // relying on ADL to pick up user-defined << for their pointer + // types, if any. + *os << p; + } else { + // T is a function type, so '*os << p' doesn't do what we want + // (it just prints p as bool). We want to print p as a const + // void*. However, we cannot cast it to const void* directly, + // even using reinterpret_cast, as earlier versions of gcc + // (e.g. 3.4.5) cannot compile the cast when p is a function + // pointer. Casting to UInt64 first solves the problem. + *os << reinterpret_cast( + reinterpret_cast(p)); + } + } +} + +// Used to print a non-container, non-pointer value when the user +// doesn't define PrintTo() for it. +template +void DefaultPrintTo(IsNotContainer /* dummy */, + false_type /* is not a pointer */, + const T& value, ::std::ostream* os) { + ::testing_internal::DefaultPrintNonContainerTo(value, os); +} + +// Prints the given value using the << operator if it has one; +// otherwise prints the bytes in it. This is what +// UniversalPrinter::Print() does when PrintTo() is not specialized +// or overloaded for type T. +// +// A user can override this behavior for a class type Foo by defining +// an overload of PrintTo() in the namespace where Foo is defined. We +// give the user this option as sometimes defining a << operator for +// Foo is not desirable (e.g. the coding style may prevent doing it, +// or there is already a << operator but it doesn't do what the user +// wants). +template +void PrintTo(const T& value, ::std::ostream* os) { + // DefaultPrintTo() is overloaded. The type of its first two + // arguments determine which version will be picked. If T is an + // STL-style container, the version for container will be called; if + // T is a pointer, the pointer version will be called; otherwise the + // generic version will be called. + // + // Note that we check for container types here, prior to we check + // for protocol message types in our operator<<. The rationale is: + // + // For protocol messages, we want to give people a chance to + // override Google Mock's format by defining a PrintTo() or + // operator<<. For STL containers, other formats can be + // incompatible with Google Mock's format for the container + // elements; therefore we check for container types here to ensure + // that our format is used. + // + // The second argument of DefaultPrintTo() is needed to bypass a bug + // in Symbian's C++ compiler that prevents it from picking the right + // overload between: + // + // PrintTo(const T& x, ...); + // PrintTo(T* x, ...); + DefaultPrintTo(IsContainerTest(0), is_pointer(), value, os); +} + +// The following list of PrintTo() overloads tells +// UniversalPrinter::Print() how to print standard types (built-in +// types, strings, plain arrays, and pointers). + +// Overloads for various char types. +GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os); +GTEST_API_ void PrintTo(signed char c, ::std::ostream* os); +inline void PrintTo(char c, ::std::ostream* os) { + // When printing a plain char, we always treat it as unsigned. This + // way, the output won't be affected by whether the compiler thinks + // char is signed or not. + PrintTo(static_cast(c), os); +} + +// Overloads for other simple built-in types. +inline void PrintTo(bool x, ::std::ostream* os) { + *os << (x ? "true" : "false"); +} + +// Overload for wchar_t type. +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its decimal code (except for L'\0'). +// The L'\0' char is printed as "L'\\0'". The decimal code is printed +// as signed integer when wchar_t is implemented by the compiler +// as a signed type and is printed as an unsigned integer when wchar_t +// is implemented as an unsigned type. +GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); + +// Overloads for C strings. +GTEST_API_ void PrintTo(const char* s, ::std::ostream* os); +inline void PrintTo(char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} + +// signed/unsigned char is often used for representing binary data, so +// we print pointers to it as void* to be safe. +inline void PrintTo(const signed char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(signed char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(const unsigned char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(unsigned char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} + +// MSVC can be configured to define wchar_t as a typedef of unsigned +// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native +// type. When wchar_t is a typedef, defining an overload for const +// wchar_t* would cause unsigned short* be printed as a wide string, +// possibly causing invalid memory accesses. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Overloads for wide C strings +GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os); +inline void PrintTo(wchar_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +#endif + +// Overload for C arrays. Multi-dimensional arrays are printed +// properly. + +// Prints the given number of elements in an array, without printing +// the curly braces. +template +void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { + UniversalPrint(a[0], os); + for (size_t i = 1; i != count; i++) { + *os << ", "; + UniversalPrint(a[i], os); + } +} + +// Overloads for ::string and ::std::string. +#if GTEST_HAS_GLOBAL_STRING +GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os); +inline void PrintTo(const ::string& s, ::std::ostream* os) { + PrintStringTo(s, os); +} +#endif // GTEST_HAS_GLOBAL_STRING + +GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os); +inline void PrintTo(const ::std::string& s, ::std::ostream* os) { + PrintStringTo(s, os); +} + +// Overloads for ::wstring and ::std::wstring. +#if GTEST_HAS_GLOBAL_WSTRING +GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os); +inline void PrintTo(const ::wstring& s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); +inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_TR1_TUPLE +// Overload for ::std::tr1::tuple. Needed for printing function arguments, +// which are packed as tuples. + +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template +void PrintTupleTo(const T& t, ::std::ostream* os); + +// Overloaded PrintTo() for tuples of various arities. We support +// tuples of up-to 10 fields. The following implementation works +// regardless of whether tr1::tuple is implemented using the +// non-standard variadic template feature or not. + +inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo( + const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} +#endif // GTEST_HAS_TR1_TUPLE + +// Overload for std::pair. +template +void PrintTo(const ::std::pair& value, ::std::ostream* os) { + *os << '('; + // We cannot use UniversalPrint(value.first, os) here, as T1 may be + // a reference type. The same for printing value.second. + UniversalPrinter::Print(value.first, os); + *os << ", "; + UniversalPrinter::Print(value.second, os); + *os << ')'; +} + +// Implements printing a non-reference type T by letting the compiler +// pick the right overload of PrintTo() for T. +template +class UniversalPrinter { + public: + // MSVC warns about adding const to a function type, so we want to + // disable the warning. +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4180) // Temporarily disables warning 4180. +#endif // _MSC_VER + + // Note: we deliberately don't call this PrintTo(), as that name + // conflicts with ::testing::internal::PrintTo in the body of the + // function. + static void Print(const T& value, ::std::ostream* os) { + // By default, ::testing::internal::PrintTo() is used for printing + // the value. + // + // Thanks to Koenig look-up, if T is a class and has its own + // PrintTo() function defined in its namespace, that function will + // be visible here. Since it is more specific than the generic ones + // in ::testing::internal, it will be picked by the compiler in the + // following statement - exactly what we want. + PrintTo(value, os); + } + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif // _MSC_VER +}; + +// UniversalPrintArray(begin, len, os) prints an array of 'len' +// elements, starting at address 'begin'. +template +void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { + if (len == 0) { + *os << "{}"; + } else { + *os << "{ "; + const size_t kThreshold = 18; + const size_t kChunkSize = 8; + // If the array has more than kThreshold elements, we'll have to + // omit some details by printing only the first and the last + // kChunkSize elements. + // TODO(wan@google.com): let the user control the threshold using a flag. + if (len <= kThreshold) { + PrintRawArrayTo(begin, len, os); + } else { + PrintRawArrayTo(begin, kChunkSize, os); + *os << ", ..., "; + PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os); + } + *os << " }"; + } +} +// This overload prints a (const) char array compactly. +GTEST_API_ void UniversalPrintArray(const char* begin, + size_t len, + ::std::ostream* os); + +// Implements printing an array type T[N]. +template +class UniversalPrinter { + public: + // Prints the given array, omitting some elements when there are too + // many. + static void Print(const T (&a)[N], ::std::ostream* os) { + UniversalPrintArray(a, N, os); + } +}; + +// Implements printing a reference type T&. +template +class UniversalPrinter { + public: + // MSVC warns about adding const to a function type, so we want to + // disable the warning. +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4180) // Temporarily disables warning 4180. +#endif // _MSC_VER + + static void Print(const T& value, ::std::ostream* os) { + // Prints the address of the value. We use reinterpret_cast here + // as static_cast doesn't compile when T is a function type. + *os << "@" << reinterpret_cast(&value) << " "; + + // Then prints the value itself. + UniversalPrint(value, os); + } + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif // _MSC_VER +}; + +// Prints a value tersely: for a reference type, the referenced value +// (but not the address) is printed; for a (const) char pointer, the +// NUL-terminated string (but not the pointer) is printed. +template +void UniversalTersePrint(const T& value, ::std::ostream* os) { + UniversalPrint(value, os); +} +inline void UniversalTersePrint(const char* str, ::std::ostream* os) { + if (str == NULL) { + *os << "NULL"; + } else { + UniversalPrint(string(str), os); + } +} +inline void UniversalTersePrint(char* str, ::std::ostream* os) { + UniversalTersePrint(static_cast(str), os); +} + +// Prints a value using the type inferred by the compiler. The +// difference between this and UniversalTersePrint() is that for a +// (const) char pointer, this prints both the pointer and the +// NUL-terminated string. +template +void UniversalPrint(const T& value, ::std::ostream* os) { + UniversalPrinter::Print(value, os); +} + +#if GTEST_HAS_TR1_TUPLE +typedef ::std::vector Strings; + +// This helper template allows PrintTo() for tuples and +// UniversalTersePrintTupleFieldsToStrings() to be defined by +// induction on the number of tuple fields. The idea is that +// TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N +// fields in tuple t, and can be defined in terms of +// TuplePrefixPrinter. + +// The inductive case. +template +struct TuplePrefixPrinter { + // Prints the first N fields of a tuple. + template + static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { + TuplePrefixPrinter::PrintPrefixTo(t, os); + *os << ", "; + UniversalPrinter::type> + ::Print(::std::tr1::get(t), os); + } + + // Tersely prints the first N fields of a tuple to a string vector, + // one element for each field. + template + static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { + TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); + ::std::stringstream ss; + UniversalTersePrint(::std::tr1::get(t), &ss); + strings->push_back(ss.str()); + } +}; + +// Base cases. +template <> +struct TuplePrefixPrinter<0> { + template + static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} + + template + static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} +}; +// We have to specialize the entire TuplePrefixPrinter<> class +// template here, even though the definition of +// TersePrintPrefixToStrings() is the same as the generic version, as +// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't +// support specializing a method template of a class template. +template <> +struct TuplePrefixPrinter<1> { + template + static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { + UniversalPrinter::type>:: + Print(::std::tr1::get<0>(t), os); + } + + template + static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { + ::std::stringstream ss; + UniversalTersePrint(::std::tr1::get<0>(t), &ss); + strings->push_back(ss.str()); + } +}; + +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template +void PrintTupleTo(const T& t, ::std::ostream* os) { + *os << "("; + TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: + PrintPrefixTo(t, os); + *os << ")"; +} + +// Prints the fields of a tuple tersely to a string vector, one +// element for each field. See the comment before +// UniversalTersePrint() for how we define "tersely". +template +Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { + Strings result; + TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: + TersePrintPrefixToStrings(value, &result); + return result; +} +#endif // GTEST_HAS_TR1_TUPLE + +} // namespace internal + +template +::std::string PrintToString(const T& value) { + ::std::stringstream ss; + internal::UniversalTersePrint(value, &ss); + return ss.str(); +} + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ diff --git a/libs/gtest/include/gtest/gtest-spi.h b/libs/gtest/include/gtest/gtest-spi.h new file mode 100644 index 000000000..b226e5504 --- /dev/null +++ b/libs/gtest/include/gtest/gtest-spi.h @@ -0,0 +1,232 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Utilities for testing Google Test itself and code that uses Google Test +// (e.g. frameworks built on top of Google Test). + +#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ +#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ + +#include "gtest/gtest.h" + +namespace testing { + +// This helper class can be used to mock out Google Test failure reporting +// so that we can test Google Test or code that builds on Google Test. +// +// An object of this class appends a TestPartResult object to the +// TestPartResultArray object given in the constructor whenever a Google Test +// failure is reported. It can either intercept only failures that are +// generated in the same thread that created this object or it can intercept +// all generated failures. The scope of this mock object can be controlled with +// the second argument to the two arguments constructor. +class GTEST_API_ ScopedFakeTestPartResultReporter + : public TestPartResultReporterInterface { + public: + // The two possible mocking modes of this object. + enum InterceptMode { + INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. + INTERCEPT_ALL_THREADS // Intercepts all failures. + }; + + // The c'tor sets this object as the test part result reporter used + // by Google Test. The 'result' parameter specifies where to report the + // results. This reporter will only catch failures generated in the current + // thread. DEPRECATED + explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); + + // Same as above, but you can choose the interception scope of this object. + ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, + TestPartResultArray* result); + + // The d'tor restores the previous test part result reporter. + virtual ~ScopedFakeTestPartResultReporter(); + + // Appends the TestPartResult object to the TestPartResultArray + // received in the constructor. + // + // This method is from the TestPartResultReporterInterface + // interface. + virtual void ReportTestPartResult(const TestPartResult& result); + private: + void Init(); + + const InterceptMode intercept_mode_; + TestPartResultReporterInterface* old_reporter_; + TestPartResultArray* const result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); +}; + +namespace internal { + +// A helper class for implementing EXPECT_FATAL_FAILURE() and +// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +class GTEST_API_ SingleFailureChecker { + public: + // The constructor remembers the arguments. + SingleFailureChecker(const TestPartResultArray* results, + TestPartResult::Type type, + const string& substr); + ~SingleFailureChecker(); + private: + const TestPartResultArray* const results_; + const TestPartResult::Type type_; + const string substr_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); +}; + +} // namespace internal + +} // namespace testing + +// A set of macros for testing Google Test assertions or code that's expected +// to generate Google Test fatal failures. It verifies that the given +// statement will cause exactly one fatal Google Test failure with 'substr' +// being part of the failure message. +// +// There are two different versions of this macro. EXPECT_FATAL_FAILURE only +// affects and considers failures generated in the current thread and +// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. +// +// The verification of the assertion is done correctly even when the statement +// throws an exception or aborts the current function. +// +// Known restrictions: +// - 'statement' cannot reference local non-static variables or +// non-static members of the current object. +// - 'statement' cannot return a value. +// - You cannot stream a failure message to this macro. +// +// Note that even though the implementations of the following two +// macros are much alike, we cannot refactor them to use a common +// helper macro, due to some peculiarity in how the preprocessor +// works. The AcceptsMacroThatExpandsToUnprotectedComma test in +// gtest_unittest.cc will fail to compile if we do that. +#define EXPECT_FATAL_FAILURE(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper {\ + public:\ + static void Execute() { statement; }\ + };\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ + GTestExpectFatalFailureHelper::Execute();\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper {\ + public:\ + static void Execute() { statement; }\ + };\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ALL_THREADS, >est_failures);\ + GTestExpectFatalFailureHelper::Execute();\ + }\ + } while (::testing::internal::AlwaysFalse()) + +// A macro for testing Google Test assertions or code that's expected to +// generate Google Test non-fatal failures. It asserts that the given +// statement will cause exactly one non-fatal Google Test failure with 'substr' +// being part of the failure message. +// +// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only +// affects and considers failures generated in the current thread and +// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. +// +// 'statement' is allowed to reference local variables and members of +// the current object. +// +// The verification of the assertion is done correctly even when the statement +// throws an exception or aborts the current function. +// +// Known restrictions: +// - You cannot stream a failure message to this macro. +// +// Note that even though the implementations of the following two +// macros are much alike, we cannot refactor them to use a common +// helper macro, due to some peculiarity in how the preprocessor +// works. If we do that, the code won't compile when the user gives +// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that +// expands to code containing an unprotected comma. The +// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc +// catches that. +// +// For the same reason, we have to write +// if (::testing::internal::AlwaysTrue()) { statement; } +// instead of +// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) +// to avoid an MSVC warning on unreachable code. +#define EXPECT_NONFATAL_FAILURE(statement, substr) \ + do {\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ + if (::testing::internal::AlwaysTrue()) { statement; }\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do {\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\ + >est_failures);\ + if (::testing::internal::AlwaysTrue()) { statement; }\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ diff --git a/libs/gtest/include/gtest/gtest-test-part.h b/libs/gtest/include/gtest/gtest-test-part.h new file mode 100644 index 000000000..8aeea1498 --- /dev/null +++ b/libs/gtest/include/gtest/gtest-test-part.h @@ -0,0 +1,176 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// + +#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ +#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ + +#include +#include +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-string.h" + +namespace testing { + +// A copyable object representing the result of a test part (i.e. an +// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). +// +// Don't inherit from TestPartResult as its destructor is not virtual. +class GTEST_API_ TestPartResult { + public: + // The possible outcomes of a test part (i.e. an assertion or an + // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). + enum Type { + kSuccess, // Succeeded. + kNonFatalFailure, // Failed but the test can continue. + kFatalFailure // Failed and the test should be terminated. + }; + + // C'tor. TestPartResult does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestPartResult object. + TestPartResult(Type a_type, + const char* a_file_name, + int a_line_number, + const char* a_message) + : type_(a_type), + file_name_(a_file_name), + line_number_(a_line_number), + summary_(ExtractSummary(a_message)), + message_(a_message) { + } + + // Gets the outcome of the test part. + Type type() const { return type_; } + + // Gets the name of the source file where the test part took place, or + // NULL if it's unknown. + const char* file_name() const { return file_name_.c_str(); } + + // Gets the line in the source file where the test part took place, + // or -1 if it's unknown. + int line_number() const { return line_number_; } + + // Gets the summary of the failure message. + const char* summary() const { return summary_.c_str(); } + + // Gets the message associated with the test part. + const char* message() const { return message_.c_str(); } + + // Returns true iff the test part passed. + bool passed() const { return type_ == kSuccess; } + + // Returns true iff the test part failed. + bool failed() const { return type_ != kSuccess; } + + // Returns true iff the test part non-fatally failed. + bool nonfatally_failed() const { return type_ == kNonFatalFailure; } + + // Returns true iff the test part fatally failed. + bool fatally_failed() const { return type_ == kFatalFailure; } + private: + Type type_; + + // Gets the summary of the failure message by omitting the stack + // trace in it. + static internal::String ExtractSummary(const char* message); + + // The name of the source file where the test part took place, or + // NULL if the source file is unknown. + internal::String file_name_; + // The line in the source file where the test part took place, or -1 + // if the line number is unknown. + int line_number_; + internal::String summary_; // The test failure summary. + internal::String message_; // The test failure message. +}; + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result); + +// An array of TestPartResult objects. +// +// Don't inherit from TestPartResultArray as its destructor is not +// virtual. +class GTEST_API_ TestPartResultArray { + public: + TestPartResultArray() {} + + // Appends the given TestPartResult to the array. + void Append(const TestPartResult& result); + + // Returns the TestPartResult at the given index (0-based). + const TestPartResult& GetTestPartResult(int index) const; + + // Returns the number of TestPartResult objects in the array. + int size() const; + + private: + std::vector array_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); +}; + +// This interface knows how to report a test part result. +class TestPartResultReporterInterface { + public: + virtual ~TestPartResultReporterInterface() {} + + virtual void ReportTestPartResult(const TestPartResult& result) = 0; +}; + +namespace internal { + +// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a +// statement generates new fatal failures. To do so it registers itself as the +// current test part result reporter. Besides checking if fatal failures were +// reported, it only delegates the reporting to the former result reporter. +// The original result reporter is restored in the destructor. +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +class GTEST_API_ HasNewFatalFailureHelper + : public TestPartResultReporterInterface { + public: + HasNewFatalFailureHelper(); + virtual ~HasNewFatalFailureHelper(); + virtual void ReportTestPartResult(const TestPartResult& result); + bool has_new_fatal_failure() const { return has_new_fatal_failure_; } + private: + bool has_new_fatal_failure_; + TestPartResultReporterInterface* original_reporter_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); +}; + +} // namespace internal + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ diff --git a/libs/gtest/include/gtest/gtest-typed-test.h b/libs/gtest/include/gtest/gtest-typed-test.h new file mode 100644 index 000000000..fe1e83b27 --- /dev/null +++ b/libs/gtest/include/gtest/gtest-typed-test.h @@ -0,0 +1,259 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ + +// This header implements typed tests and type-parameterized tests. + +// Typed (aka type-driven) tests repeat the same test for types in a +// list. You must know which types you want to test with when writing +// typed tests. Here's how you do it: + +#if 0 + +// First, define a fixture class template. It should be parameterized +// by a type. Remember to derive it from testing::Test. +template +class FooTest : public testing::Test { + public: + ... + typedef std::list List; + static T shared_; + T value_; +}; + +// Next, associate a list of types with the test case, which will be +// repeated for each type in the list. The typedef is necessary for +// the macro to parse correctly. +typedef testing::Types MyTypes; +TYPED_TEST_CASE(FooTest, MyTypes); + +// If the type list contains only one type, you can write that type +// directly without Types<...>: +// TYPED_TEST_CASE(FooTest, int); + +// Then, use TYPED_TEST() instead of TEST_F() to define as many typed +// tests for this test case as you want. +TYPED_TEST(FooTest, DoesBlah) { + // Inside a test, refer to TypeParam to get the type parameter. + // Since we are inside a derived class template, C++ requires use to + // visit the members of FooTest via 'this'. + TypeParam n = this->value_; + + // To visit static members of the fixture, add the TestFixture:: + // prefix. + n += TestFixture::shared_; + + // To refer to typedefs in the fixture, add the "typename + // TestFixture::" prefix. + typename TestFixture::List values; + values.push_back(n); + ... +} + +TYPED_TEST(FooTest, HasPropertyA) { ... } + +#endif // 0 + +// Type-parameterized tests are abstract test patterns parameterized +// by a type. Compared with typed tests, type-parameterized tests +// allow you to define the test pattern without knowing what the type +// parameters are. The defined pattern can be instantiated with +// different types any number of times, in any number of translation +// units. +// +// If you are designing an interface or concept, you can define a +// suite of type-parameterized tests to verify properties that any +// valid implementation of the interface/concept should have. Then, +// each implementation can easily instantiate the test suite to verify +// that it conforms to the requirements, without having to write +// similar tests repeatedly. Here's an example: + +#if 0 + +// First, define a fixture class template. It should be parameterized +// by a type. Remember to derive it from testing::Test. +template +class FooTest : public testing::Test { + ... +}; + +// Next, declare that you will define a type-parameterized test case +// (the _P suffix is for "parameterized" or "pattern", whichever you +// prefer): +TYPED_TEST_CASE_P(FooTest); + +// Then, use TYPED_TEST_P() to define as many type-parameterized tests +// for this type-parameterized test case as you want. +TYPED_TEST_P(FooTest, DoesBlah) { + // Inside a test, refer to TypeParam to get the type parameter. + TypeParam n = 0; + ... +} + +TYPED_TEST_P(FooTest, HasPropertyA) { ... } + +// Now the tricky part: you need to register all test patterns before +// you can instantiate them. The first argument of the macro is the +// test case name; the rest are the names of the tests in this test +// case. +REGISTER_TYPED_TEST_CASE_P(FooTest, + DoesBlah, HasPropertyA); + +// Finally, you are free to instantiate the pattern with the types you +// want. If you put the above code in a header file, you can #include +// it in multiple C++ source files and instantiate it multiple times. +// +// To distinguish different instances of the pattern, the first +// argument to the INSTANTIATE_* macro is a prefix that will be added +// to the actual test case name. Remember to pick unique prefixes for +// different instances. +typedef testing::Types MyTypes; +INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); + +// If the type list contains only one type, you can write that type +// directly without Types<...>: +// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); + +#endif // 0 + +#include "gtest/internal/gtest-port.h" +#include "gtest/internal/gtest-type-util.h" + +// Implements typed tests. + +#if GTEST_HAS_TYPED_TEST + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the name of the typedef for the type parameters of the +// given test case. +# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ + +// The 'Types' template argument below must have spaces around it +// since some compilers may choke on '>>' when passing a template +// instance (e.g. Types) +# define TYPED_TEST_CASE(CaseName, Types) \ + typedef ::testing::internal::TypeList< Types >::type \ + GTEST_TYPE_PARAMS_(CaseName) + +# define TYPED_TEST(CaseName, TestName) \ + template \ + class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ + : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTest< \ + CaseName, \ + ::testing::internal::TemplateSel< \ + GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ + GTEST_TYPE_PARAMS_(CaseName)>::Register(\ + "", #CaseName, #TestName, 0); \ + template \ + void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::TestBody() + +#endif // GTEST_HAS_TYPED_TEST + +// Implements type-parameterized tests. + +#if GTEST_HAS_TYPED_TEST_P + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the namespace name that the type-parameterized tests for +// the given type-parameterized test case are defined in. The exact +// name of the namespace is subject to change without notice. +# define GTEST_CASE_NAMESPACE_(TestCaseName) \ + gtest_case_##TestCaseName##_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the name of the variable used to remember the names of +// the defined tests in the given test case. +# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \ + gtest_typed_test_case_p_state_##TestCaseName##_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. +// +// Expands to the name of the variable used to remember the names of +// the registered tests in the given test case. +# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \ + gtest_registered_test_names_##TestCaseName##_ + +// The variables defined in the type-parameterized test macros are +// static as typically these macros are used in a .h file that can be +// #included in multiple translation units linked together. +# define TYPED_TEST_CASE_P(CaseName) \ + static ::testing::internal::TypedTestCasePState \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName) + +# define TYPED_TEST_P(CaseName, TestName) \ + namespace GTEST_CASE_NAMESPACE_(CaseName) { \ + template \ + class TestName : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ + __FILE__, __LINE__, #CaseName, #TestName); \ + } \ + template \ + void GTEST_CASE_NAMESPACE_(CaseName)::TestName::TestBody() + +# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \ + namespace GTEST_CASE_NAMESPACE_(CaseName) { \ + typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ + } \ + static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ + __FILE__, __LINE__, #__VA_ARGS__) + +// The 'Types' template argument below must have spaces around it +// since some compilers may choke on '>>' when passing a template +// instance (e.g. Types) +# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ + bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTestCase::type>::Register(\ + #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) + +#endif // GTEST_HAS_TYPED_TEST_P + +#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ diff --git a/libs/gtest/include/gtest/gtest.h b/libs/gtest/include/gtest/gtest.h new file mode 100644 index 000000000..cd01c7ba7 --- /dev/null +++ b/libs/gtest/include/gtest/gtest.h @@ -0,0 +1,2155 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the public API for Google Test. It should be +// included by any test program that uses Google Test. +// +// IMPORTANT NOTE: Due to limitation of the C++ language, we have to +// leave some internal implementation details in this header file. +// They are clearly marked by comments like this: +// +// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// +// Such code is NOT meant to be used by a user directly, and is subject +// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user +// program! +// +// Acknowledgment: Google Test borrowed the idea of automatic test +// registration from Barthelemy Dagenais' (barthelemy@prologique.com) +// easyUnit framework. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_H_ + +#include +#include + +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-string.h" +#include "gtest/gtest-death-test.h" +#include "gtest/gtest-message.h" +#include "gtest/gtest-param-test.h" +#include "gtest/gtest-printers.h" +#include "gtest/gtest_prod.h" +#include "gtest/gtest-test-part.h" +#include "gtest/gtest-typed-test.h" + +// Depending on the platform, different string classes are available. +// On Linux, in addition to ::std::string, Google also makes use of +// class ::string, which has the same interface as ::std::string, but +// has a different implementation. +// +// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that +// ::string is available AND is a distinct type to ::std::string, or +// define it to 0 to indicate otherwise. +// +// If the user's ::std::string and ::string are the same class due to +// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. +// +// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined +// heuristically. + +namespace testing { + +// Declares the flags. + +// This flag temporary enables the disabled tests. +GTEST_DECLARE_bool_(also_run_disabled_tests); + +// This flag brings the debugger on an assertion failure. +GTEST_DECLARE_bool_(break_on_failure); + +// This flag controls whether Google Test catches all test-thrown exceptions +// and logs them as failures. +GTEST_DECLARE_bool_(catch_exceptions); + +// This flag enables using colors in terminal output. Available values are +// "yes" to enable colors, "no" (disable colors), or "auto" (the default) +// to let Google Test decide. +GTEST_DECLARE_string_(color); + +// This flag sets up the filter to select by name using a glob pattern +// the tests to run. If the filter is not given all tests are executed. +GTEST_DECLARE_string_(filter); + +// This flag causes the Google Test to list tests. None of the tests listed +// are actually run if the flag is provided. +GTEST_DECLARE_bool_(list_tests); + +// This flag controls whether Google Test emits a detailed XML report to a file +// in addition to its normal textual output. +GTEST_DECLARE_string_(output); + +// This flags control whether Google Test prints the elapsed time for each +// test. +GTEST_DECLARE_bool_(print_time); + +// This flag specifies the random number seed. +GTEST_DECLARE_int32_(random_seed); + +// This flag sets how many times the tests are repeated. The default value +// is 1. If the value is -1 the tests are repeating forever. +GTEST_DECLARE_int32_(repeat); + +// This flag controls whether Google Test includes Google Test internal +// stack frames in failure stack traces. +GTEST_DECLARE_bool_(show_internal_stack_frames); + +// When this flag is specified, tests' order is randomized on every iteration. +GTEST_DECLARE_bool_(shuffle); + +// This flag specifies the maximum number of stack frames to be +// printed in a failure message. +GTEST_DECLARE_int32_(stack_trace_depth); + +// When this flag is specified, a failed assertion will throw an +// exception if exceptions are enabled, or exit the program with a +// non-zero code otherwise. +GTEST_DECLARE_bool_(throw_on_failure); + +// When this flag is set with a "host:port" string, on supported +// platforms test results are streamed to the specified port on +// the specified host machine. +GTEST_DECLARE_string_(stream_result_to); + +// The upper limit for valid stack trace depths. +const int kMaxStackTraceDepth = 100; + +namespace internal { + +class AssertHelper; +class DefaultGlobalTestPartResultReporter; +class ExecDeathTest; +class NoExecDeathTest; +class FinalSuccessChecker; +class GTestFlagSaver; +class TestResultAccessor; +class TestEventListenersAccessor; +class TestEventRepeater; +class WindowsDeathTest; +class UnitTestImpl* GetUnitTestImpl(); +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, + const String& message); + +// Converts a streamable value to a String. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". +// Declared in gtest-internal.h but defined here, so that it has access +// to the definition of the Message class, required by the ARM +// compiler. +template +String StreamableToString(const T& streamable) { + return (Message() << streamable).GetString(); +} + +} // namespace internal + +// The friend relationship of some of these classes is cyclic. +// If we don't forward declare them the compiler might confuse the classes +// in friendship clauses with same named classes on the scope. +class Test; +class TestCase; +class TestInfo; +class UnitTest; + +// A class for indicating whether an assertion was successful. When +// the assertion wasn't successful, the AssertionResult object +// remembers a non-empty message that describes how it failed. +// +// To create an instance of this class, use one of the factory functions +// (AssertionSuccess() and AssertionFailure()). +// +// This class is useful for two purposes: +// 1. Defining predicate functions to be used with Boolean test assertions +// EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts +// 2. Defining predicate-format functions to be +// used with predicate assertions (ASSERT_PRED_FORMAT*, etc). +// +// For example, if you define IsEven predicate: +// +// testing::AssertionResult IsEven(int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess(); +// else +// return testing::AssertionFailure() << n << " is odd"; +// } +// +// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) +// will print the message +// +// Value of: IsEven(Fib(5)) +// Actual: false (5 is odd) +// Expected: true +// +// instead of a more opaque +// +// Value of: IsEven(Fib(5)) +// Actual: false +// Expected: true +// +// in case IsEven is a simple Boolean predicate. +// +// If you expect your predicate to be reused and want to support informative +// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up +// about half as often as positive ones in our tests), supply messages for +// both success and failure cases: +// +// testing::AssertionResult IsEven(int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess() << n << " is even"; +// else +// return testing::AssertionFailure() << n << " is odd"; +// } +// +// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print +// +// Value of: IsEven(Fib(6)) +// Actual: true (8 is even) +// Expected: false +// +// NB: Predicates that support negative Boolean assertions have reduced +// performance in positive ones so be careful not to use them in tests +// that have lots (tens of thousands) of positive Boolean assertions. +// +// To use this class with EXPECT_PRED_FORMAT assertions such as: +// +// // Verifies that Foo() returns an even number. +// EXPECT_PRED_FORMAT1(IsEven, Foo()); +// +// you need to define: +// +// testing::AssertionResult IsEven(const char* expr, int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess(); +// else +// return testing::AssertionFailure() +// << "Expected: " << expr << " is even\n Actual: it's " << n; +// } +// +// If Foo() returns 5, you will see the following message: +// +// Expected: Foo() is even +// Actual: it's 5 +// +class GTEST_API_ AssertionResult { + public: + // Copy constructor. + // Used in EXPECT_TRUE/FALSE(assertion_result). + AssertionResult(const AssertionResult& other); + // Used in the EXPECT_TRUE/FALSE(bool_expression). + explicit AssertionResult(bool success) : success_(success) {} + + // Returns true iff the assertion succeeded. + operator bool() const { return success_; } // NOLINT + + // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. + AssertionResult operator!() const; + + // Returns the text streamed into this AssertionResult. Test assertions + // use it when they fail (i.e., the predicate's outcome doesn't match the + // assertion's expectation). When nothing has been streamed into the + // object, returns an empty string. + const char* message() const { + return message_.get() != NULL ? message_->c_str() : ""; + } + // TODO(vladl@google.com): Remove this after making sure no clients use it. + // Deprecated; please use message() instead. + const char* failure_message() const { return message(); } + + // Streams a custom failure message into this object. + template AssertionResult& operator<<(const T& value) { + AppendMessage(Message() << value); + return *this; + } + + // Allows streaming basic output manipulators such as endl or flush into + // this object. + AssertionResult& operator<<( + ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) { + AppendMessage(Message() << basic_manipulator); + return *this; + } + + private: + // Appends the contents of message to message_. + void AppendMessage(const Message& a_message) { + if (message_.get() == NULL) + message_.reset(new ::std::string); + message_->append(a_message.GetString().c_str()); + } + + // Stores result of the assertion predicate. + bool success_; + // Stores the message describing the condition in case the expectation + // construct is not satisfied with the predicate's outcome. + // Referenced via a pointer to avoid taking too much stack frame space + // with test assertions. + internal::scoped_ptr< ::std::string> message_; + + GTEST_DISALLOW_ASSIGN_(AssertionResult); +}; + +// Makes a successful assertion result. +GTEST_API_ AssertionResult AssertionSuccess(); + +// Makes a failed assertion result. +GTEST_API_ AssertionResult AssertionFailure(); + +// Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << msg. +GTEST_API_ AssertionResult AssertionFailure(const Message& msg); + +// The abstract class that all tests inherit from. +// +// In Google Test, a unit test program contains one or many TestCases, and +// each TestCase contains one or many Tests. +// +// When you define a test using the TEST macro, you don't need to +// explicitly derive from Test - the TEST macro automatically does +// this for you. +// +// The only time you derive from Test is when defining a test fixture +// to be used a TEST_F. For example: +// +// class FooTest : public testing::Test { +// protected: +// virtual void SetUp() { ... } +// virtual void TearDown() { ... } +// ... +// }; +// +// TEST_F(FooTest, Bar) { ... } +// TEST_F(FooTest, Baz) { ... } +// +// Test is not copyable. +class GTEST_API_ Test { + public: + friend class TestInfo; + + // Defines types for pointers to functions that set up and tear down + // a test case. + typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; + typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; + + // The d'tor is virtual as we intend to inherit from Test. + virtual ~Test(); + + // Sets up the stuff shared by all tests in this test case. + // + // Google Test will call Foo::SetUpTestCase() before running the first + // test in test case Foo. Hence a sub-class can define its own + // SetUpTestCase() method to shadow the one defined in the super + // class. + static void SetUpTestCase() {} + + // Tears down the stuff shared by all tests in this test case. + // + // Google Test will call Foo::TearDownTestCase() after running the last + // test in test case Foo. Hence a sub-class can define its own + // TearDownTestCase() method to shadow the one defined in the super + // class. + static void TearDownTestCase() {} + + // Returns true iff the current test has a fatal failure. + static bool HasFatalFailure(); + + // Returns true iff the current test has a non-fatal failure. + static bool HasNonfatalFailure(); + + // Returns true iff the current test has a (either fatal or + // non-fatal) failure. + static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } + + // Logs a property for the current test. Only the last value for a given + // key is remembered. + // These are public static so they can be called from utility functions + // that are not members of the test fixture. + // The arguments are const char* instead strings, as Google Test is used + // on platforms where string doesn't compile. + // + // Note that a driving consideration for these RecordProperty methods + // was to produce xml output suited to the Greenspan charting utility, + // which at present will only chart values that fit in a 32-bit int. It + // is the user's responsibility to restrict their values to 32-bit ints + // if they intend them to be used with Greenspan. + static void RecordProperty(const char* key, const char* value); + static void RecordProperty(const char* key, int value); + + protected: + // Creates a Test object. + Test(); + + // Sets up the test fixture. + virtual void SetUp(); + + // Tears down the test fixture. + virtual void TearDown(); + + private: + // Returns true iff the current test has the same fixture class as + // the first test in the current test case. + static bool HasSameFixtureClass(); + + // Runs the test after the test fixture has been set up. + // + // A sub-class must implement this to define the test logic. + // + // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. + // Instead, use the TEST or TEST_F macro. + virtual void TestBody() = 0; + + // Sets up, executes, and tears down the test. + void Run(); + + // Deletes self. We deliberately pick an unusual name for this + // internal method to avoid clashing with names used in user TESTs. + void DeleteSelf_() { delete this; } + + // Uses a GTestFlagSaver to save and restore all Google Test flags. + const internal::GTestFlagSaver* const gtest_flag_saver_; + + // Often a user mis-spells SetUp() as Setup() and spends a long time + // wondering why it is never called by Google Test. The declaration of + // the following method is solely for catching such an error at + // compile time: + // + // - The return type is deliberately chosen to be not void, so it + // will be a conflict if a user declares void Setup() in his test + // fixture. + // + // - This method is private, so it will be another compiler error + // if a user calls it from his test fixture. + // + // DO NOT OVERRIDE THIS FUNCTION. + // + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } + + // We disallow copying Tests. + GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); +}; + +typedef internal::TimeInMillis TimeInMillis; + +// A copyable object representing a user specified test property which can be +// output as a key/value string pair. +// +// Don't inherit from TestProperty as its destructor is not virtual. +class TestProperty { + public: + // C'tor. TestProperty does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestProperty object. + TestProperty(const char* a_key, const char* a_value) : + key_(a_key), value_(a_value) { + } + + // Gets the user supplied key. + const char* key() const { + return key_.c_str(); + } + + // Gets the user supplied value. + const char* value() const { + return value_.c_str(); + } + + // Sets a new value, overriding the one supplied in the constructor. + void SetValue(const char* new_value) { + value_ = new_value; + } + + private: + // The key supplied by the user. + internal::String key_; + // The value supplied by the user. + internal::String value_; +}; + +// The result of a single Test. This includes a list of +// TestPartResults, a list of TestProperties, a count of how many +// death tests there are in the Test, and how much time it took to run +// the Test. +// +// TestResult is not copyable. +class GTEST_API_ TestResult { + public: + // Creates an empty TestResult. + TestResult(); + + // D'tor. Do not inherit from TestResult. + ~TestResult(); + + // Gets the number of all test parts. This is the sum of the number + // of successful test parts and the number of failed test parts. + int total_part_count() const; + + // Returns the number of the test properties. + int test_property_count() const; + + // Returns true iff the test passed (i.e. no test part failed). + bool Passed() const { return !Failed(); } + + // Returns true iff the test failed. + bool Failed() const; + + // Returns true iff the test fatally failed. + bool HasFatalFailure() const; + + // Returns true iff the test has a non-fatal failure. + bool HasNonfatalFailure() const; + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns the i-th test part result among all the results. i can range + // from 0 to test_property_count() - 1. If i is not in that range, aborts + // the program. + const TestPartResult& GetTestPartResult(int i) const; + + // Returns the i-th test property. i can range from 0 to + // test_property_count() - 1. If i is not in that range, aborts the + // program. + const TestProperty& GetTestProperty(int i) const; + + private: + friend class TestInfo; + friend class UnitTest; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::ExecDeathTest; + friend class internal::TestResultAccessor; + friend class internal::UnitTestImpl; + friend class internal::WindowsDeathTest; + + // Gets the vector of TestPartResults. + const std::vector& test_part_results() const { + return test_part_results_; + } + + // Gets the vector of TestProperties. + const std::vector& test_properties() const { + return test_properties_; + } + + // Sets the elapsed time. + void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } + + // Adds a test property to the list. The property is validated and may add + // a non-fatal failure if invalid (e.g., if it conflicts with reserved + // key names). If a property is already recorded for the same key, the + // value will be updated, rather than storing multiple values for the same + // key. + void RecordProperty(const TestProperty& test_property); + + // Adds a failure if the key is a reserved attribute of Google Test + // testcase tags. Returns true if the property is valid. + // TODO(russr): Validate attribute names are legal and human readable. + static bool ValidateTestProperty(const TestProperty& test_property); + + // Adds a test part result to the list. + void AddTestPartResult(const TestPartResult& test_part_result); + + // Returns the death test count. + int death_test_count() const { return death_test_count_; } + + // Increments the death test count, returning the new count. + int increment_death_test_count() { return ++death_test_count_; } + + // Clears the test part results. + void ClearTestPartResults(); + + // Clears the object. + void Clear(); + + // Protects mutable state of the property vector and of owned + // properties, whose values may be updated. + internal::Mutex test_properites_mutex_; + + // The vector of TestPartResults + std::vector test_part_results_; + // The vector of TestProperties + std::vector test_properties_; + // Running count of death tests. + int death_test_count_; + // The elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + + // We disallow copying TestResult. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); +}; // class TestResult + +// A TestInfo object stores the following information about a test: +// +// Test case name +// Test name +// Whether the test should be run +// A function pointer that creates the test object when invoked +// Test result +// +// The constructor of TestInfo registers itself with the UnitTest +// singleton such that the RUN_ALL_TESTS() macro knows which tests to +// run. +class GTEST_API_ TestInfo { + public: + // Destructs a TestInfo object. This function is not virtual, so + // don't inherit from TestInfo. + ~TestInfo(); + + // Returns the test case name. + const char* test_case_name() const { return test_case_name_.c_str(); } + + // Returns the test name. + const char* name() const { return name_.c_str(); } + + // Returns the name of the parameter type, or NULL if this is not a typed + // or a type-parameterized test. + const char* type_param() const { + if (type_param_.get() != NULL) + return type_param_->c_str(); + return NULL; + } + + // Returns the text representation of the value parameter, or NULL if this + // is not a value-parameterized test. + const char* value_param() const { + if (value_param_.get() != NULL) + return value_param_->c_str(); + return NULL; + } + + // Returns true if this test should run, that is if the test is not disabled + // (or it is disabled but the also_run_disabled_tests flag has been specified) + // and its full name matches the user-specified filter. + // + // Google Test allows the user to filter the tests by their full names. + // The full name of a test Bar in test case Foo is defined as + // "Foo.Bar". Only the tests that match the filter will run. + // + // A filter is a colon-separated list of glob (not regex) patterns, + // optionally followed by a '-' and a colon-separated list of + // negative patterns (tests to exclude). A test is run if it + // matches one of the positive patterns and does not match any of + // the negative patterns. + // + // For example, *A*:Foo.* is a filter that matches any string that + // contains the character 'A' or starts with "Foo.". + bool should_run() const { return should_run_; } + + // Returns the result of the test. + const TestResult* result() const { return &result_; } + + private: + +#if GTEST_HAS_DEATH_TEST + friend class internal::DefaultDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + friend class Test; + friend class TestCase; + friend class internal::UnitTestImpl; + friend TestInfo* internal::MakeAndRegisterTestInfo( + const char* test_case_name, const char* name, + const char* type_param, + const char* value_param, + internal::TypeId fixture_class_id, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc, + internal::TestFactoryBase* factory); + + // Constructs a TestInfo object. The newly constructed instance assumes + // ownership of the factory object. + TestInfo(const char* test_case_name, const char* name, + const char* a_type_param, + const char* a_value_param, + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory); + + // Increments the number of death tests encountered in this test so + // far. + int increment_death_test_count() { + return result_.increment_death_test_count(); + } + + // Creates the test object, runs it, records its result, and then + // deletes it. + void Run(); + + static void ClearTestResult(TestInfo* test_info) { + test_info->result_.Clear(); + } + + // These fields are immutable properties of the test. + const std::string test_case_name_; // Test case name + const std::string name_; // Test name + // Name of the parameter type, or NULL if this is not a typed or a + // type-parameterized test. + const internal::scoped_ptr type_param_; + // Text representation of the value parameter, or NULL if this is not a + // value-parameterized test. + const internal::scoped_ptr value_param_; + const internal::TypeId fixture_class_id_; // ID of the test fixture class + bool should_run_; // True iff this test should run + bool is_disabled_; // True iff this test is disabled + bool matches_filter_; // True if this test matches the + // user-specified filter. + internal::TestFactoryBase* const factory_; // The factory that creates + // the test object + + // This field is mutable and needs to be reset before running the + // test for the second time. + TestResult result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); +}; + +// A test case, which consists of a vector of TestInfos. +// +// TestCase is not copyable. +class GTEST_API_ TestCase { + public: + // Creates a TestCase with the given name. + // + // TestCase does NOT have a default constructor. Always use this + // constructor to create a TestCase object. + // + // Arguments: + // + // name: name of the test case + // a_type_param: the name of the test's type parameter, or NULL if + // this is not a type-parameterized test. + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + TestCase(const char* name, const char* a_type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc); + + // Destructor of TestCase. + virtual ~TestCase(); + + // Gets the name of the TestCase. + const char* name() const { return name_.c_str(); } + + // Returns the name of the parameter type, or NULL if this is not a + // type-parameterized test case. + const char* type_param() const { + if (type_param_.get() != NULL) + return type_param_->c_str(); + return NULL; + } + + // Returns true if any test in this test case should run. + bool should_run() const { return should_run_; } + + // Gets the number of successful tests in this test case. + int successful_test_count() const; + + // Gets the number of failed tests in this test case. + int failed_test_count() const; + + // Gets the number of disabled tests in this test case. + int disabled_test_count() const; + + // Get the number of tests in this test case that should run. + int test_to_run_count() const; + + // Gets the number of all tests in this test case. + int total_test_count() const; + + // Returns true iff the test case passed. + bool Passed() const { return !Failed(); } + + // Returns true iff the test case failed. + bool Failed() const { return failed_test_count() > 0; } + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + const TestInfo* GetTestInfo(int i) const; + + private: + friend class Test; + friend class internal::UnitTestImpl; + + // Gets the (mutable) vector of TestInfos in this TestCase. + std::vector& test_info_list() { return test_info_list_; } + + // Gets the (immutable) vector of TestInfos in this TestCase. + const std::vector& test_info_list() const { + return test_info_list_; + } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + TestInfo* GetMutableTestInfo(int i); + + // Sets the should_run member. + void set_should_run(bool should) { should_run_ = should; } + + // Adds a TestInfo to this test case. Will delete the TestInfo upon + // destruction of the TestCase object. + void AddTestInfo(TestInfo * test_info); + + // Clears the results of all tests in this test case. + void ClearResult(); + + // Clears the results of all tests in the given test case. + static void ClearTestCaseResult(TestCase* test_case) { + test_case->ClearResult(); + } + + // Runs every test in this TestCase. + void Run(); + + // Runs SetUpTestCase() for this TestCase. This wrapper is needed + // for catching exceptions thrown from SetUpTestCase(). + void RunSetUpTestCase() { (*set_up_tc_)(); } + + // Runs TearDownTestCase() for this TestCase. This wrapper is + // needed for catching exceptions thrown from TearDownTestCase(). + void RunTearDownTestCase() { (*tear_down_tc_)(); } + + // Returns true iff test passed. + static bool TestPassed(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Passed(); + } + + // Returns true iff test failed. + static bool TestFailed(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Failed(); + } + + // Returns true iff test is disabled. + static bool TestDisabled(const TestInfo* test_info) { + return test_info->is_disabled_; + } + + // Returns true if the given test should run. + static bool ShouldRunTest(const TestInfo* test_info) { + return test_info->should_run(); + } + + // Shuffles the tests in this test case. + void ShuffleTests(internal::Random* random); + + // Restores the test order to before the first shuffle. + void UnshuffleTests(); + + // Name of the test case. + internal::String name_; + // Name of the parameter type, or NULL if this is not a typed or a + // type-parameterized test. + const internal::scoped_ptr type_param_; + // The vector of TestInfos in their original order. It owns the + // elements in the vector. + std::vector test_info_list_; + // Provides a level of indirection for the test list to allow easy + // shuffling and restoring the test order. The i-th element in this + // vector is the index of the i-th test in the shuffled test list. + std::vector test_indices_; + // Pointer to the function that sets up the test case. + Test::SetUpTestCaseFunc set_up_tc_; + // Pointer to the function that tears down the test case. + Test::TearDownTestCaseFunc tear_down_tc_; + // True iff any test in this test case should run. + bool should_run_; + // Elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + + // We disallow copying TestCases. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); +}; + +// An Environment object is capable of setting up and tearing down an +// environment. The user should subclass this to define his own +// environment(s). +// +// An Environment object does the set-up and tear-down in virtual +// methods SetUp() and TearDown() instead of the constructor and the +// destructor, as: +// +// 1. You cannot safely throw from a destructor. This is a problem +// as in some cases Google Test is used where exceptions are enabled, and +// we may want to implement ASSERT_* using exceptions where they are +// available. +// 2. You cannot use ASSERT_* directly in a constructor or +// destructor. +class Environment { + public: + // The d'tor is virtual as we need to subclass Environment. + virtual ~Environment() {} + + // Override this to define how to set up the environment. + virtual void SetUp() {} + + // Override this to define how to tear down the environment. + virtual void TearDown() {} + private: + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } +}; + +// The interface for tracing execution of tests. The methods are organized in +// the order the corresponding events are fired. +class TestEventListener { + public: + virtual ~TestEventListener() {} + + // Fired before any test activity starts. + virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; + + // Fired before each iteration of tests starts. There may be more than + // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration + // index, starting from 0. + virtual void OnTestIterationStart(const UnitTest& unit_test, + int iteration) = 0; + + // Fired before environment set-up for each iteration of tests starts. + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; + + // Fired after environment set-up for each iteration of tests ends. + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; + + // Fired before the test case starts. + virtual void OnTestCaseStart(const TestCase& test_case) = 0; + + // Fired before the test starts. + virtual void OnTestStart(const TestInfo& test_info) = 0; + + // Fired after a failed assertion or a SUCCEED() invocation. + virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; + + // Fired after the test ends. + virtual void OnTestEnd(const TestInfo& test_info) = 0; + + // Fired after the test case ends. + virtual void OnTestCaseEnd(const TestCase& test_case) = 0; + + // Fired before environment tear-down for each iteration of tests starts. + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; + + // Fired after environment tear-down for each iteration of tests ends. + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; + + // Fired after each iteration of tests finishes. + virtual void OnTestIterationEnd(const UnitTest& unit_test, + int iteration) = 0; + + // Fired after all test activities have ended. + virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; +}; + +// The convenience class for users who need to override just one or two +// methods and are not concerned that a possible change to a signature of +// the methods they override will not be caught during the build. For +// comments about each method please see the definition of TestEventListener +// above. +class EmptyTestEventListener : public TestEventListener { + public: + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, + int /*iteration*/) {} + virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} + virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} + virtual void OnTestStart(const TestInfo& /*test_info*/) {} + virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} + virtual void OnTestEnd(const TestInfo& /*test_info*/) {} + virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} + virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} + virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int /*iteration*/) {} + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} +}; + +// TestEventListeners lets users add listeners to track events in Google Test. +class GTEST_API_ TestEventListeners { + public: + TestEventListeners(); + ~TestEventListeners(); + + // Appends an event listener to the end of the list. Google Test assumes + // the ownership of the listener (i.e. it will delete the listener when + // the test program finishes). + void Append(TestEventListener* listener); + + // Removes the given event listener from the list and returns it. It then + // becomes the caller's responsibility to delete the listener. Returns + // NULL if the listener is not found in the list. + TestEventListener* Release(TestEventListener* listener); + + // Returns the standard listener responsible for the default console + // output. Can be removed from the listeners list to shut down default + // console output. Note that removing this object from the listener list + // with Release transfers its ownership to the caller and makes this + // function return NULL the next time. + TestEventListener* default_result_printer() const { + return default_result_printer_; + } + + // Returns the standard listener responsible for the default XML output + // controlled by the --gtest_output=xml flag. Can be removed from the + // listeners list by users who want to shut down the default XML output + // controlled by this flag and substitute it with custom one. Note that + // removing this object from the listener list with Release transfers its + // ownership to the caller and makes this function return NULL the next + // time. + TestEventListener* default_xml_generator() const { + return default_xml_generator_; + } + + private: + friend class TestCase; + friend class TestInfo; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::NoExecDeathTest; + friend class internal::TestEventListenersAccessor; + friend class internal::UnitTestImpl; + + // Returns repeater that broadcasts the TestEventListener events to all + // subscribers. + TestEventListener* repeater(); + + // Sets the default_result_printer attribute to the provided listener. + // The listener is also added to the listener list and previous + // default_result_printer is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultResultPrinter(TestEventListener* listener); + + // Sets the default_xml_generator attribute to the provided listener. The + // listener is also added to the listener list and previous + // default_xml_generator is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultXmlGenerator(TestEventListener* listener); + + // Controls whether events will be forwarded by the repeater to the + // listeners in the list. + bool EventForwardingEnabled() const; + void SuppressEventForwarding(); + + // The actual list of listeners. + internal::TestEventRepeater* repeater_; + // Listener responsible for the standard result output. + TestEventListener* default_result_printer_; + // Listener responsible for the creation of the XML output file. + TestEventListener* default_xml_generator_; + + // We disallow copying TestEventListeners. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); +}; + +// A UnitTest consists of a vector of TestCases. +// +// This is a singleton class. The only instance of UnitTest is +// created when UnitTest::GetInstance() is first called. This +// instance is never deleted. +// +// UnitTest is not copyable. +// +// This class is thread-safe as long as the methods are called +// according to their specification. +class GTEST_API_ UnitTest { + public: + // Gets the singleton UnitTest object. The first time this method + // is called, a UnitTest object is constructed and returned. + // Consecutive calls will return the same object. + static UnitTest* GetInstance(); + + // Runs all tests in this UnitTest object and prints the result. + // Returns 0 if successful, or 1 otherwise. + // + // This method can only be called from the main thread. + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + int Run() GTEST_MUST_USE_RESULT_; + + // Returns the working directory when the first TEST() or TEST_F() + // was executed. The UnitTest object owns the string. + const char* original_working_dir() const; + + // Returns the TestCase object for the test that's currently running, + // or NULL if no test is running. + const TestCase* current_test_case() const; + + // Returns the TestInfo object for the test that's currently running, + // or NULL if no test is running. + const TestInfo* current_test_info() const; + + // Returns the random seed used at the start of the current test run. + int random_seed() const; + +#if GTEST_HAS_PARAM_TEST + // Returns the ParameterizedTestCaseRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + internal::ParameterizedTestCaseRegistry& parameterized_test_registry(); +#endif // GTEST_HAS_PARAM_TEST + + // Gets the number of successful test cases. + int successful_test_case_count() const; + + // Gets the number of failed test cases. + int failed_test_case_count() const; + + // Gets the number of all test cases. + int total_test_case_count() const; + + // Gets the number of all test cases that contain at least one test + // that should run. + int test_case_to_run_count() const; + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const; + + // Returns true iff the unit test passed (i.e. all test cases passed). + bool Passed() const; + + // Returns true iff the unit test failed (i.e. some test case failed + // or something outside of all tests failed). + bool Failed() const; + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + const TestCase* GetTestCase(int i) const; + + // Returns the list of event listeners that can be used to track events + // inside Google Test. + TestEventListeners& listeners(); + + private: + // Registers and returns a global test environment. When a test + // program is run, all global test environments will be set-up in + // the order they were registered. After all tests in the program + // have finished, all global test environments will be torn-down in + // the *reverse* order they were registered. + // + // The UnitTest object takes ownership of the given environment. + // + // This method can only be called from the main thread. + Environment* AddEnvironment(Environment* env); + + // Adds a TestPartResult to the current TestResult object. All + // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) + // eventually call this to report their results. The user code + // should use the assertion macros instead of calling this directly. + void AddTestPartResult(TestPartResult::Type result_type, + const char* file_name, + int line_number, + const internal::String& message, + const internal::String& os_stack_trace); + + // Adds a TestProperty to the current TestResult object. If the result already + // contains a property with the same key, the value will be updated. + void RecordPropertyForCurrentTest(const char* key, const char* value); + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + TestCase* GetMutableTestCase(int i); + + // Accessors for the implementation object. + internal::UnitTestImpl* impl() { return impl_; } + const internal::UnitTestImpl* impl() const { return impl_; } + + // These classes and funcions are friends as they need to access private + // members of UnitTest. + friend class Test; + friend class internal::AssertHelper; + friend class internal::ScopedTrace; + friend Environment* AddGlobalTestEnvironment(Environment* env); + friend internal::UnitTestImpl* internal::GetUnitTestImpl(); + friend void internal::ReportFailureInUnknownLocation( + TestPartResult::Type result_type, + const internal::String& message); + + // Creates an empty UnitTest. + UnitTest(); + + // D'tor + virtual ~UnitTest(); + + // Pushes a trace defined by SCOPED_TRACE() on to the per-thread + // Google Test trace stack. + void PushGTestTrace(const internal::TraceInfo& trace); + + // Pops a trace from the per-thread Google Test trace stack. + void PopGTestTrace(); + + // Protects mutable state in *impl_. This is mutable as some const + // methods need to lock it too. + mutable internal::Mutex mutex_; + + // Opaque implementation object. This field is never changed once + // the object is constructed. We don't mark it as const here, as + // doing so will cause a warning in the constructor of UnitTest. + // Mutable state in *impl_ is protected by mutex_. + internal::UnitTestImpl* impl_; + + // We disallow copying UnitTest. + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); +}; + +// A convenient wrapper for adding an environment for the test +// program. +// +// You should call this before RUN_ALL_TESTS() is called, probably in +// main(). If you use gtest_main, you need to call this before main() +// starts for it to take effect. For example, you can define a global +// variable like this: +// +// testing::Environment* const foo_env = +// testing::AddGlobalTestEnvironment(new FooEnvironment); +// +// However, we strongly recommend you to write your own main() and +// call AddGlobalTestEnvironment() there, as relying on initialization +// of global variables makes the code harder to read and may cause +// problems when you register multiple environments from different +// translation units and the environments have dependencies among them +// (remember that the compiler doesn't guarantee the order in which +// global variables from different translation units are initialized). +inline Environment* AddGlobalTestEnvironment(Environment* env) { + return UnitTest::GetInstance()->AddEnvironment(env); +} + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +// +// Calling the function for the second time has no user-visible effect. +GTEST_API_ void InitGoogleTest(int* argc, char** argv); + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); + +namespace internal { + +// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) +// operand to be used in a failure message. The type (but not value) +// of the other operand may affect the format. This allows us to +// print a char* as a raw pointer when it is compared against another +// char*, and print it as a C string when it is compared against an +// std::string object, for example. +// +// The default implementation ignores the type of the other operand. +// Some specialized versions are used to handle formatting wide or +// narrow C strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +String FormatForComparisonFailureMessage(const T1& value, + const T2& /* other_operand */) { + // C++Builder compiles this incorrectly if the namespace isn't explicitly + // given. + return ::testing::PrintToString(value); +} + +// The helper function for {ASSERT|EXPECT}_EQ. +template +AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual) { +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4389) // Temporarily disables warning on + // signed/unsigned mismatch. +#endif + + if (expected == actual) { + return AssertionSuccess(); + } + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif + + return EqFailure(expected_expression, + actual_expression, + FormatForComparisonFailureMessage(expected, actual), + FormatForComparisonFailureMessage(actual, expected), + false); +} + +// With this overloaded version, we allow anonymous enums to be used +// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums +// can be implicitly cast to BiggestInt. +GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual); + +// The helper class for {ASSERT|EXPECT}_EQ. The template argument +// lhs_is_null_literal is true iff the first argument to ASSERT_EQ() +// is a null pointer literal. The following default implementation is +// for lhs_is_null_literal being false. +template +class EqHelper { + public: + // This templatized version is for the general case. + template + static AssertionResult Compare(const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } + + // With this overloaded version, we allow anonymous enums to be used + // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous + // enums can be implicitly cast to BiggestInt. + // + // Even though its body looks the same as the above version, we + // cannot merge the two, as it will make anonymous enums unhappy. + static AssertionResult Compare(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } +}; + +// This specialization is used when the first argument to ASSERT_EQ() +// is a null pointer literal, like NULL, false, or 0. +template <> +class EqHelper { + public: + // We define two overloaded versions of Compare(). The first + // version will be picked when the second argument to ASSERT_EQ() is + // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or + // EXPECT_EQ(false, a_bool). + template + static AssertionResult Compare( + const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual, + // The following line prevents this overload from being considered if T2 + // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr) + // expands to Compare("", "", NULL, my_ptr), which requires a conversion + // to match the Secret* in the other overload, which would otherwise make + // this template match better. + typename EnableIf::value>::type* = 0) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } + + // This version will be picked when the second argument to ASSERT_EQ() is a + // pointer, e.g. ASSERT_EQ(NULL, a_pointer). + template + static AssertionResult Compare( + const char* expected_expression, + const char* actual_expression, + // We used to have a second template parameter instead of Secret*. That + // template parameter would deduce to 'long', making this a better match + // than the first overload even without the first overload's EnableIf. + // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to + // non-pointer argument" (even a deduced integral argument), so the old + // implementation caused warnings in user code. + Secret* /* expected (NULL) */, + T* actual) { + // We already know that 'expected' is a null pointer. + return CmpHelperEQ(expected_expression, actual_expression, + static_cast(NULL), actual); + } +}; + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste +// of similar code. +// +// For each templatized helper function, we also define an overloaded +// version for BiggestInt in order to reduce code bloat and allow +// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled +// with gcc 4. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ +template \ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + const T1& val1, const T2& val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + return AssertionFailure() \ + << "Expected: (" << expr1 << ") " #op " (" << expr2\ + << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ + << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + }\ +}\ +GTEST_API_ AssertionResult CmpHelper##op_name(\ + const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) + +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + +// Implements the helper function for {ASSERT|EXPECT}_NE +GTEST_IMPL_CMP_HELPER_(NE, !=); +// Implements the helper function for {ASSERT|EXPECT}_LE +GTEST_IMPL_CMP_HELPER_(LE, <=); +// Implements the helper function for {ASSERT|EXPECT}_LT +GTEST_IMPL_CMP_HELPER_(LT, < ); +// Implements the helper function for {ASSERT|EXPECT}_GE +GTEST_IMPL_CMP_HELPER_(GE, >=); +// Implements the helper function for {ASSERT|EXPECT}_GT +GTEST_IMPL_CMP_HELPER_(GT, > ); + +#undef GTEST_IMPL_CMP_HELPER_ + +// The helper function for {ASSERT|EXPECT}_STREQ. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual); + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual); + +// The helper function for {ASSERT|EXPECT}_STRNE. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + + +// Helper function for *_STREQ on wide strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const wchar_t* expected, + const wchar_t* actual); + +// Helper function for *_STRNE on wide strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2); + +} // namespace internal + +// IsSubstring() and IsNotSubstring() are intended to be used as the +// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by +// themselves. They check whether needle is a substring of haystack +// (NULL is considered a substring of itself only), and return an +// appropriate error message when they fail. +// +// The {needle,haystack}_expr arguments are the stringified +// expressions that generated the two real arguments. +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack); +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack); +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack); + +#if GTEST_HAS_STD_WSTRING +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack); +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +// Helper template function for comparing floating-points. +// +// Template parameter: +// +// RawType: the raw floating-point type (either float or double) +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, + const char* actual_expression, + RawType expected, + RawType actual) { + const FloatingPoint lhs(expected), rhs(actual); + + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + ::std::stringstream expected_ss; + expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << expected; + + ::std::stringstream actual_ss; + actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << actual; + + return EqFailure(expected_expression, + actual_expression, + StringStreamToString(&expected_ss), + StringStreamToString(&actual_ss), + false); +} + +// Helper function for implementing ASSERT_NEAR. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error); + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// A class that enables one to stream messages to assertion macros +class GTEST_API_ AssertHelper { + public: + // Constructor. + AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message); + ~AssertHelper(); + + // Message assignment is a semantic trick to enable assertion + // streaming; see the GTEST_MESSAGE_ macro below. + void operator=(const Message& message) const; + + private: + // We put our data in a struct so that the size of the AssertHelper class can + // be as small as possible. This is important because gcc is incapable of + // re-using stack space even for temporary variables, so every EXPECT_EQ + // reserves stack space for another AssertHelper. + struct AssertHelperData { + AssertHelperData(TestPartResult::Type t, + const char* srcfile, + int line_num, + const char* msg) + : type(t), file(srcfile), line(line_num), message(msg) { } + + TestPartResult::Type const type; + const char* const file; + int const line; + String const message; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); + }; + + AssertHelperData* const data_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); +}; + +} // namespace internal + +#if GTEST_HAS_PARAM_TEST +// The pure interface class that all value-parameterized tests inherit from. +// A value-parameterized class must inherit from both ::testing::Test and +// ::testing::WithParamInterface. In most cases that just means inheriting +// from ::testing::TestWithParam, but more complicated test hierarchies +// may need to inherit from Test and WithParamInterface at different levels. +// +// This interface has support for accessing the test parameter value via +// the GetParam() method. +// +// Use it with one of the parameter generator defining functions, like Range(), +// Values(), ValuesIn(), Bool(), and Combine(). +// +// class FooTest : public ::testing::TestWithParam { +// protected: +// FooTest() { +// // Can use GetParam() here. +// } +// virtual ~FooTest() { +// // Can use GetParam() here. +// } +// virtual void SetUp() { +// // Can use GetParam() here. +// } +// virtual void TearDown { +// // Can use GetParam() here. +// } +// }; +// TEST_P(FooTest, DoesBar) { +// // Can use GetParam() method here. +// Foo foo; +// ASSERT_TRUE(foo.DoesBar(GetParam())); +// } +// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); + +template +class WithParamInterface { + public: + typedef T ParamType; + virtual ~WithParamInterface() {} + + // The current parameter value. Is also available in the test fixture's + // constructor. This member function is non-static, even though it only + // references static data, to reduce the opportunity for incorrect uses + // like writing 'WithParamInterface::GetParam()' for a test that + // uses a fixture whose parameter type is int. + const ParamType& GetParam() const { return *parameter_; } + + private: + // Sets parameter value. The caller is responsible for making sure the value + // remains alive and unchanged throughout the current test. + static void SetParam(const ParamType* parameter) { + parameter_ = parameter; + } + + // Static value used for accessing parameter during a test lifetime. + static const ParamType* parameter_; + + // TestClass must be a subclass of WithParamInterface and Test. + template friend class internal::ParameterizedTestFactory; +}; + +template +const T* WithParamInterface::parameter_ = NULL; + +// Most value-parameterized classes can ignore the existence of +// WithParamInterface, and can just inherit from ::testing::TestWithParam. + +template +class TestWithParam : public Test, public WithParamInterface { +}; + +#endif // GTEST_HAS_PARAM_TEST + +// Macros for indicating success/failure in test code. + +// ADD_FAILURE unconditionally adds a failure to the current test. +// SUCCEED generates a success - it doesn't automatically make the +// current test successful, as a test is only successful when it has +// no failure. +// +// EXPECT_* verifies that a certain condition is satisfied. If not, +// it behaves like ADD_FAILURE. In particular: +// +// EXPECT_TRUE verifies that a Boolean condition is true. +// EXPECT_FALSE verifies that a Boolean condition is false. +// +// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except +// that they will also abort the current function on failure. People +// usually want the fail-fast behavior of FAIL and ASSERT_*, but those +// writing data-driven tests often find themselves using ADD_FAILURE +// and EXPECT_* more. +// +// Examples: +// +// EXPECT_TRUE(server.StatusIsOK()); +// ASSERT_FALSE(server.HasPendingRequest(port)) +// << "There are still pending requests " << "on port " << port; + +// Generates a nonfatal failure with a generic message. +#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") + +// Generates a nonfatal failure at the given source file location with +// a generic message. +#define ADD_FAILURE_AT(file, line) \ + GTEST_MESSAGE_AT_(file, line, "Failed", \ + ::testing::TestPartResult::kNonFatalFailure) + +// Generates a fatal failure with a generic message. +#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") + +// Define this macro to 1 to omit the definition of FAIL(), which is a +// generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_FAIL +# define FAIL() GTEST_FAIL() +#endif + +// Generates a success with a generic message. +#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") + +// Define this macro to 1 to omit the definition of SUCCEED(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_SUCCEED +# define SUCCEED() GTEST_SUCCEED() +#endif + +// Macros for testing exceptions. +// +// * {ASSERT|EXPECT}_THROW(statement, expected_exception): +// Tests that the statement throws the expected exception. +// * {ASSERT|EXPECT}_NO_THROW(statement): +// Tests that the statement doesn't throw any exception. +// * {ASSERT|EXPECT}_ANY_THROW(statement): +// Tests that the statement throws an exception. + +#define EXPECT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) +#define EXPECT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define EXPECT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define ASSERT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) +#define ASSERT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) +#define ASSERT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) + +// Boolean assertions. Condition can be either a Boolean expression or an +// AssertionResult. For more information on how to use AssertionResult with +// these macros see comments on that class. +#define EXPECT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_NONFATAL_FAILURE_) +#define EXPECT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_NONFATAL_FAILURE_) +#define ASSERT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_FATAL_FAILURE_) +#define ASSERT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_FATAL_FAILURE_) + +// Includes the auto-generated header that implements a family of +// generic predicate assertion macros. +#include "gtest/gtest_pred_impl.h" + +// Macros for testing equalities and inequalities. +// +// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual +// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 +// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 +// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 +// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 +// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 +// +// When they are not, Google Test prints both the tested expressions and +// their actual values. The values must be compatible built-in types, +// or you will get a compiler error. By "compatible" we mean that the +// values can be compared by the respective operator. +// +// Note: +// +// 1. It is possible to make a user-defined type work with +// {ASSERT|EXPECT}_??(), but that requires overloading the +// comparison operators and is thus discouraged by the Google C++ +// Usage Guide. Therefore, you are advised to use the +// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are +// equal. +// +// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on +// pointers (in particular, C strings). Therefore, if you use it +// with two C strings, you are testing how their locations in memory +// are related, not how their content is related. To compare two C +// strings by content, use {ASSERT|EXPECT}_STR*(). +// +// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to +// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you +// what the actual value is when it fails, and similarly for the +// other comparisons. +// +// 4. Do not depend on the order in which {ASSERT|EXPECT}_??() +// evaluate their arguments, which is undefined. +// +// 5. These macros evaluate their arguments exactly once. +// +// Examples: +// +// EXPECT_NE(5, Foo()); +// EXPECT_EQ(NULL, a_pointer); +// ASSERT_LT(i, array_size); +// ASSERT_GT(records.size(), 0) << "There is no record left."; + +#define EXPECT_EQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal:: \ + EqHelper::Compare, \ + expected, actual) +#define EXPECT_NE(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) +#define EXPECT_LE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) +#define EXPECT_LT(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) +#define EXPECT_GE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) +#define EXPECT_GT(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) + +#define GTEST_ASSERT_EQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal:: \ + EqHelper::Compare, \ + expected, actual) +#define GTEST_ASSERT_NE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) +#define GTEST_ASSERT_LE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) +#define GTEST_ASSERT_LT(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) +#define GTEST_ASSERT_GE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) +#define GTEST_ASSERT_GT(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) + +// Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of +// ASSERT_XY(), which clashes with some users' own code. + +#if !GTEST_DONT_DEFINE_ASSERT_EQ +# define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_NE +# define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_LE +# define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_LT +# define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_GE +# define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_GT +# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2) +#endif + +// C String Comparisons. All tests treat NULL and any non-NULL string +// as different. Two NULLs are equal. +// +// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 +// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 +// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case +// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case +// +// For wide or narrow string objects, you can use the +// {ASSERT|EXPECT}_??() macros. +// +// Don't depend on the order in which the arguments are evaluated, +// which is undefined. +// +// These macros evaluate their arguments exactly once. + +#define EXPECT_STREQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define EXPECT_STRNE(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) +#define EXPECT_STRCASEEQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define EXPECT_STRCASENE(s1, s2)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) + +#define ASSERT_STREQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define ASSERT_STRNE(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) +#define ASSERT_STRCASEEQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define ASSERT_STRCASENE(s1, s2)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) + +// Macros for comparing floating-point numbers. +// +// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): +// Tests that two float values are almost equal. +// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): +// Tests that two double values are almost equal. +// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): +// Tests that v1 and v2 are within the given distance to each other. +// +// Google Test uses ULP-based comparison to automatically pick a default +// error bound that is appropriate for the operands. See the +// FloatingPoint template class in gtest-internal.h if you are +// interested in the implementation details. + +#define EXPECT_FLOAT_EQ(expected, actual)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define EXPECT_DOUBLE_EQ(expected, actual)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define ASSERT_FLOAT_EQ(expected, actual)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define ASSERT_DOUBLE_EQ(expected, actual)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define EXPECT_NEAR(val1, val2, abs_error)\ + EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + val1, val2, abs_error) + +#define ASSERT_NEAR(val1, val2, abs_error)\ + ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + val1, val2, abs_error) + +// These predicate format functions work on floating-point values, and +// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. +// +// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2); +GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2); + + +#if GTEST_OS_WINDOWS + +// Macros that test for HRESULT failure and success, these are only useful +// on Windows, and rely on Windows SDK macros and APIs to compile. +// +// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) +// +// When expr unexpectedly fails or succeeds, Google Test prints the +// expected result and the actual result with both a human-readable +// string representation of the error, if available, as well as the +// hex result code. +# define EXPECT_HRESULT_SUCCEEDED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) + +# define ASSERT_HRESULT_SUCCEEDED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) + +# define EXPECT_HRESULT_FAILED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) + +# define ASSERT_HRESULT_FAILED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) + +#endif // GTEST_OS_WINDOWS + +// Macros that execute statement and check that it doesn't generate new fatal +// failures in the current thread. +// +// * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); +// +// Examples: +// +// EXPECT_NO_FATAL_FAILURE(Process()); +// ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; +// +#define ASSERT_NO_FATAL_FAILURE(statement) \ + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) +#define EXPECT_NO_FATAL_FAILURE(statement) \ + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) + +// Causes a trace (including the source file path, the current line +// number, and the given message) to be included in every test failure +// message generated by code in the current scope. The effect is +// undone when the control leaves the current scope. +// +// The message argument can be anything streamable to std::ostream. +// +// In the implementation, we include the current line number as part +// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s +// to appear in the same block - as long as they are on different +// lines. +#define SCOPED_TRACE(message) \ + ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ + __FILE__, __LINE__, ::testing::Message() << (message)) + +// Compile-time assertion for type equality. +// StaticAssertTypeEq() compiles iff type1 and type2 are +// the same type. The value it returns is not interesting. +// +// Instead of making StaticAssertTypeEq a class template, we make it a +// function template that invokes a helper class template. This +// prevents a user from misusing StaticAssertTypeEq by +// defining objects of that type. +// +// CAVEAT: +// +// When used inside a method of a class template, +// StaticAssertTypeEq() is effective ONLY IF the method is +// instantiated. For example, given: +// +// template class Foo { +// public: +// void Bar() { testing::StaticAssertTypeEq(); } +// }; +// +// the code: +// +// void Test1() { Foo foo; } +// +// will NOT generate a compiler error, as Foo::Bar() is never +// actually instantiated. Instead, you need: +// +// void Test2() { Foo foo; foo.Bar(); } +// +// to cause a compiler error. +template +bool StaticAssertTypeEq() { + (void)internal::StaticAssertTypeEqHelper(); + return true; +} + +// Defines a test. +// +// The first parameter is the name of the test case, and the second +// parameter is the name of the test within the test case. +// +// The convention is to end the test case name with "Test". For +// example, a test case for the Foo class can be named FooTest. +// +// The user should put his test code between braces after using this +// macro. Example: +// +// TEST(FooTest, InitializesCorrectly) { +// Foo foo; +// EXPECT_TRUE(foo.StatusIsOK()); +// } + +// Note that we call GetTestTypeId() instead of GetTypeId< +// ::testing::Test>() here to get the type ID of testing::Test. This +// is to work around a suspected linker bug when using Google Test as +// a framework on Mac OS X. The bug causes GetTypeId< +// ::testing::Test>() to return different values depending on whether +// the call is from the Google Test framework itself or from user test +// code. GetTestTypeId() is guaranteed to always return the same +// value, as it always calls GetTypeId<>() from the Google Test +// framework. +#define GTEST_TEST(test_case_name, test_name)\ + GTEST_TEST_(test_case_name, test_name, \ + ::testing::Test, ::testing::internal::GetTestTypeId()) + +// Define this macro to 1 to omit the definition of TEST(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_TEST +# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) +#endif + +// Defines a test that uses a test fixture. +// +// The first parameter is the name of the test fixture class, which +// also doubles as the test case name. The second parameter is the +// name of the test within the test case. +// +// A test fixture class must be declared earlier. The user should put +// his test code between braces after using this macro. Example: +// +// class FooTest : public testing::Test { +// protected: +// virtual void SetUp() { b_.AddElement(3); } +// +// Foo a_; +// Foo b_; +// }; +// +// TEST_F(FooTest, InitializesCorrectly) { +// EXPECT_TRUE(a_.StatusIsOK()); +// } +// +// TEST_F(FooTest, ReturnsElementCountCorrectly) { +// EXPECT_EQ(0, a_.size()); +// EXPECT_EQ(1, b_.size()); +// } + +#define TEST_F(test_fixture, test_name)\ + GTEST_TEST_(test_fixture, test_name, test_fixture, \ + ::testing::internal::GetTypeId()) + +// Use this macro in main() to run all tests. It returns 0 if all +// tests are successful, or 1 otherwise. +// +// RUN_ALL_TESTS() should be invoked after the command line has been +// parsed by InitGoogleTest(). + +#define RUN_ALL_TESTS()\ + (::testing::UnitTest::GetInstance()->Run()) + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_H_ diff --git a/libs/gtest/include/gtest/gtest_pred_impl.h b/libs/gtest/include/gtest/gtest_pred_impl.h new file mode 100644 index 000000000..3805f85bd --- /dev/null +++ b/libs/gtest/include/gtest/gtest_pred_impl.h @@ -0,0 +1,358 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is AUTOMATICALLY GENERATED on 09/24/2010 by command +// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! +// +// Implements a family of generic predicate assertion macros. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ + +// Makes sure this header is not included before gtest.h. +#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ +# error Do not include gtest_pred_impl.h directly. Include gtest.h instead. +#endif // GTEST_INCLUDE_GTEST_GTEST_H_ + +// This header implements a family of generic predicate assertion +// macros: +// +// ASSERT_PRED_FORMAT1(pred_format, v1) +// ASSERT_PRED_FORMAT2(pred_format, v1, v2) +// ... +// +// where pred_format is a function or functor that takes n (in the +// case of ASSERT_PRED_FORMATn) values and their source expression +// text, and returns a testing::AssertionResult. See the definition +// of ASSERT_EQ in gtest.h for an example. +// +// If you don't care about formatting, you can use the more +// restrictive version: +// +// ASSERT_PRED1(pred, v1) +// ASSERT_PRED2(pred, v1, v2) +// ... +// +// where pred is an n-ary function or functor that returns bool, +// and the values v1, v2, ..., must support the << operator for +// streaming to std::ostream. +// +// We also define the EXPECT_* variations. +// +// For now we only support predicates whose arity is at most 5. +// Please email googletestframework@googlegroups.com if you need +// support for higher arities. + +// GTEST_ASSERT_ is the basic statement to which all of the assertions +// in this file reduce. Don't use this in your code. + +#define GTEST_ASSERT_(expression, on_failure) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar = (expression)) \ + ; \ + else \ + on_failure(gtest_ar.failure_message()) + + +// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +template +AssertionResult AssertPred1Helper(const char* pred_text, + const char* e1, + Pred pred, + const T1& v1) { + if (pred(v1)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. +// Don't use this in your code. +#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, v1),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +#define GTEST_PRED1_(pred, v1, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ + #v1, \ + pred, \ + v1), on_failure) + +// Unary predicate assertion macros. +#define EXPECT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +template +AssertionResult AssertPred2Helper(const char* pred_text, + const char* e1, + const char* e2, + Pred pred, + const T1& v1, + const T2& v2) { + if (pred(v1, v2)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. +// Don't use this in your code. +#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +#define GTEST_PRED2_(pred, v1, v2, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ + #v1, \ + #v2, \ + pred, \ + v1, \ + v2), on_failure) + +// Binary predicate assertion macros. +#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +template +AssertionResult AssertPred3Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3) { + if (pred(v1, v2, v3)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. +// Don't use this in your code. +#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + pred, \ + v1, \ + v2, \ + v3), on_failure) + +// Ternary predicate assertion macros. +#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +template +AssertionResult AssertPred4Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4) { + if (pred(v1, v2, v3, v4)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ", " + << e4 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3 + << "\n" << e4 << " evaluates to " << v4; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. +// Don't use this in your code. +#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4), on_failure) + +// 4-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +template +AssertionResult AssertPred5Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + const char* e5, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4, + const T5& v5) { + if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ", " + << e4 << ", " + << e5 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3 + << "\n" << e4 << " evaluates to " << v4 + << "\n" << e5 << " evaluates to " << v5; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. +// Don't use this in your code. +#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + #v5, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4, \ + v5), on_failure) + +// 5-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) + + + +#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ diff --git a/libs/gtest/include/gtest/gtest_prod.h b/libs/gtest/include/gtest/gtest_prod.h new file mode 100644 index 000000000..da80ddc6c --- /dev/null +++ b/libs/gtest/include/gtest/gtest_prod.h @@ -0,0 +1,58 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Google C++ Testing Framework definitions useful in production code. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ + +// When you need to test the private or protected members of a class, +// use the FRIEND_TEST macro to declare your tests as friends of the +// class. For example: +// +// class MyClass { +// private: +// void MyMethod(); +// FRIEND_TEST(MyClassTest, MyMethod); +// }; +// +// class MyClassTest : public testing::Test { +// // ... +// }; +// +// TEST_F(MyClassTest, MyMethod) { +// // Can call MyClass::MyMethod() here. +// } + +#define FRIEND_TEST(test_case_name, test_name)\ +friend class test_case_name##_##test_name##_Test + +#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ diff --git a/libs/gtest/include/gtest/internal/gtest-death-test-internal.h b/libs/gtest/include/gtest/internal/gtest-death-test-internal.h new file mode 100644 index 000000000..1d9f83b65 --- /dev/null +++ b/libs/gtest/include/gtest/internal/gtest-death-test-internal.h @@ -0,0 +1,308 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines internal utilities needed for implementing +// death tests. They are subject to change without notice. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ + +#include "gtest/internal/gtest-internal.h" + +#include + +namespace testing { +namespace internal { + +GTEST_DECLARE_string_(internal_run_death_test); + +// Names of the flags (needed for parsing Google Test flags). +const char kDeathTestStyleFlag[] = "death_test_style"; +const char kDeathTestUseFork[] = "death_test_use_fork"; +const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; + +#if GTEST_HAS_DEATH_TEST + +// DeathTest is a class that hides much of the complexity of the +// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method +// returns a concrete class that depends on the prevailing death test +// style, as defined by the --gtest_death_test_style and/or +// --gtest_internal_run_death_test flags. + +// In describing the results of death tests, these terms are used with +// the corresponding definitions: +// +// exit status: The integer exit information in the format specified +// by wait(2) +// exit code: The integer code passed to exit(3), _exit(2), or +// returned from main() +class GTEST_API_ DeathTest { + public: + // Create returns false if there was an error determining the + // appropriate action to take for the current death test; for example, + // if the gtest_death_test_style flag is set to an invalid value. + // The LastMessage method will return a more detailed message in that + // case. Otherwise, the DeathTest pointer pointed to by the "test" + // argument is set. If the death test should be skipped, the pointer + // is set to NULL; otherwise, it is set to the address of a new concrete + // DeathTest object that controls the execution of the current test. + static bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test); + DeathTest(); + virtual ~DeathTest() { } + + // A helper class that aborts a death test when it's deleted. + class ReturnSentinel { + public: + explicit ReturnSentinel(DeathTest* test) : test_(test) { } + ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } + private: + DeathTest* const test_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel); + } GTEST_ATTRIBUTE_UNUSED_; + + // An enumeration of possible roles that may be taken when a death + // test is encountered. EXECUTE means that the death test logic should + // be executed immediately. OVERSEE means that the program should prepare + // the appropriate environment for a child process to execute the death + // test, then wait for it to complete. + enum TestRole { OVERSEE_TEST, EXECUTE_TEST }; + + // An enumeration of the three reasons that a test might be aborted. + enum AbortReason { + TEST_ENCOUNTERED_RETURN_STATEMENT, + TEST_THREW_EXCEPTION, + TEST_DID_NOT_DIE + }; + + // Assumes one of the above roles. + virtual TestRole AssumeRole() = 0; + + // Waits for the death test to finish and returns its status. + virtual int Wait() = 0; + + // Returns true if the death test passed; that is, the test process + // exited during the test, its exit status matches a user-supplied + // predicate, and its stderr output matches a user-supplied regular + // expression. + // The user-supplied predicate may be a macro expression rather + // than a function pointer or functor, or else Wait and Passed could + // be combined. + virtual bool Passed(bool exit_status_ok) = 0; + + // Signals that the death test did not die as expected. + virtual void Abort(AbortReason reason) = 0; + + // Returns a human-readable outcome message regarding the outcome of + // the last death test. + static const char* LastMessage(); + + static void set_last_death_test_message(const String& message); + + private: + // A string containing a description of the outcome of the last death test. + static String last_death_test_message_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); +}; + +// Factory interface for death tests. May be mocked out for testing. +class DeathTestFactory { + public: + virtual ~DeathTestFactory() { } + virtual bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test) = 0; +}; + +// A concrete DeathTestFactory implementation for normal use. +class DefaultDeathTestFactory : public DeathTestFactory { + public: + virtual bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test); +}; + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +GTEST_API_ bool ExitedUnsuccessfully(int exit_status); + +// Traps C++ exceptions escaping statement and reports them as test +// failures. Note that trapping SEH exceptions is not implemented here. +# if GTEST_HAS_EXCEPTIONS +# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } catch (const ::std::exception& gtest_exception) { \ + fprintf(\ + stderr, \ + "\n%s: Caught std::exception-derived exception escaping the " \ + "death test statement. Exception message: %s\n", \ + ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \ + gtest_exception.what()); \ + fflush(stderr); \ + death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ + } catch (...) { \ + death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ + } + +# else +# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) + +# endif + +// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, +// ASSERT_EXIT*, and EXPECT_EXIT*. +# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + const ::testing::internal::RE& gtest_regex = (regex); \ + ::testing::internal::DeathTest* gtest_dt; \ + if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \ + __FILE__, __LINE__, >est_dt)) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + if (gtest_dt != NULL) { \ + ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \ + gtest_dt_ptr(gtest_dt); \ + switch (gtest_dt->AssumeRole()) { \ + case ::testing::internal::DeathTest::OVERSEE_TEST: \ + if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + break; \ + case ::testing::internal::DeathTest::EXECUTE_TEST: { \ + ::testing::internal::DeathTest::ReturnSentinel \ + gtest_sentinel(gtest_dt); \ + GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ + gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ + break; \ + } \ + default: \ + break; \ + } \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \ + fail(::testing::internal::DeathTest::LastMessage()) +// The symbol "fail" here expands to something into which a message +// can be streamed. + +// A class representing the parsed contents of the +// --gtest_internal_run_death_test flag, as it existed when +// RUN_ALL_TESTS was called. +class InternalRunDeathTestFlag { + public: + InternalRunDeathTestFlag(const String& a_file, + int a_line, + int an_index, + int a_write_fd) + : file_(a_file), line_(a_line), index_(an_index), + write_fd_(a_write_fd) {} + + ~InternalRunDeathTestFlag() { + if (write_fd_ >= 0) + posix::Close(write_fd_); + } + + String file() const { return file_; } + int line() const { return line_; } + int index() const { return index_; } + int write_fd() const { return write_fd_; } + + private: + String file_; + int line_; + int index_; + int write_fd_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag); +}; + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); + +#else // GTEST_HAS_DEATH_TEST + +// This macro is used for implementing macros such as +// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where +// death tests are not supported. Those macros must compile on such systems +// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on +// systems that support death tests. This allows one to write such a macro +// on a system that does not support death tests and be sure that it will +// compile on a death-test supporting system. +// +// Parameters: +// statement - A statement that a macro such as EXPECT_DEATH would test +// for program termination. This macro has to make sure this +// statement is compiled but not executed, to ensure that +// EXPECT_DEATH_IF_SUPPORTED compiles with a certain +// parameter iff EXPECT_DEATH compiles with it. +// regex - A regex that a macro such as EXPECT_DEATH would use to test +// the output of statement. This parameter has to be +// compiled but not evaluated by this macro, to ensure that +// this macro only accepts expressions that a macro such as +// EXPECT_DEATH would accept. +// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED +// and a return statement for ASSERT_DEATH_IF_SUPPORTED. +// This ensures that ASSERT_DEATH_IF_SUPPORTED will not +// compile inside functions where ASSERT_DEATH doesn't +// compile. +// +// The branch that has an always false condition is used to ensure that +// statement and regex are compiled (and thus syntactically correct) but +// never executed. The unreachable code macro protects the terminator +// statement from generating an 'unreachable code' warning in case +// statement unconditionally returns or throws. The Message constructor at +// the end allows the syntax of streaming additional messages into the +// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. +# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_LOG_(WARNING) \ + << "Death tests are not supported on this platform.\n" \ + << "Statement '" #statement "' cannot be verified."; \ + } else if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::RE::PartialMatch(".*", (regex)); \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + terminator; \ + } else \ + ::testing::Message() + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ diff --git a/libs/gtest/include/gtest/internal/gtest-filepath.h b/libs/gtest/include/gtest/internal/gtest-filepath.h new file mode 100644 index 000000000..b36b3cf21 --- /dev/null +++ b/libs/gtest/include/gtest/internal/gtest-filepath.h @@ -0,0 +1,210 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: keith.ray@gmail.com (Keith Ray) +// +// Google Test filepath utilities +// +// This header file declares classes and functions used internally by +// Google Test. They are subject to change without notice. +// +// This file is #included in . +// Do not include this header file separately! + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ + +#include "gtest/internal/gtest-string.h" + +namespace testing { +namespace internal { + +// FilePath - a class for file and directory pathname manipulation which +// handles platform-specific conventions (like the pathname separator). +// Used for helper functions for naming files in a directory for xml output. +// Except for Set methods, all methods are const or static, which provides an +// "immutable value object" -- useful for peace of mind. +// A FilePath with a value ending in a path separator ("like/this/") represents +// a directory, otherwise it is assumed to represent a file. In either case, +// it may or may not represent an actual file or directory in the file system. +// Names are NOT checked for syntax correctness -- no checking for illegal +// characters, malformed paths, etc. + +class GTEST_API_ FilePath { + public: + FilePath() : pathname_("") { } + FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } + + explicit FilePath(const char* pathname) : pathname_(pathname) { + Normalize(); + } + + explicit FilePath(const String& pathname) : pathname_(pathname) { + Normalize(); + } + + FilePath& operator=(const FilePath& rhs) { + Set(rhs); + return *this; + } + + void Set(const FilePath& rhs) { + pathname_ = rhs.pathname_; + } + + String ToString() const { return pathname_; } + const char* c_str() const { return pathname_.c_str(); } + + // Returns the current working directory, or "" if unsuccessful. + static FilePath GetCurrentDir(); + + // Given directory = "dir", base_name = "test", number = 0, + // extension = "xml", returns "dir/test.xml". If number is greater + // than zero (e.g., 12), returns "dir/test_12.xml". + // On Windows platform, uses \ as the separator rather than /. + static FilePath MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension); + + // Given directory = "dir", relative_path = "test.xml", + // returns "dir/test.xml". + // On Windows, uses \ as the separator rather than /. + static FilePath ConcatPaths(const FilePath& directory, + const FilePath& relative_path); + + // Returns a pathname for a file that does not currently exist. The pathname + // will be directory/base_name.extension or + // directory/base_name_.extension if directory/base_name.extension + // already exists. The number will be incremented until a pathname is found + // that does not already exist. + // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. + // There could be a race condition if two or more processes are calling this + // function at the same time -- they could both pick the same filename. + static FilePath GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension); + + // Returns true iff the path is NULL or "". + bool IsEmpty() const { return c_str() == NULL || *c_str() == '\0'; } + + // If input name has a trailing separator character, removes it and returns + // the name, otherwise return the name string unmodified. + // On Windows platform, uses \ as the separator, other platforms use /. + FilePath RemoveTrailingPathSeparator() const; + + // Returns a copy of the FilePath with the directory part removed. + // Example: FilePath("path/to/file").RemoveDirectoryName() returns + // FilePath("file"). If there is no directory part ("just_a_file"), it returns + // the FilePath unmodified. If there is no file part ("just_a_dir/") it + // returns an empty FilePath (""). + // On Windows platform, '\' is the path separator, otherwise it is '/'. + FilePath RemoveDirectoryName() const; + + // RemoveFileName returns the directory path with the filename removed. + // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". + // If the FilePath is "a_file" or "/a_file", RemoveFileName returns + // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does + // not have a file, like "just/a/dir/", it returns the FilePath unmodified. + // On Windows platform, '\' is the path separator, otherwise it is '/'. + FilePath RemoveFileName() const; + + // Returns a copy of the FilePath with the case-insensitive extension removed. + // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns + // FilePath("dir/file"). If a case-insensitive extension is not + // found, returns a copy of the original FilePath. + FilePath RemoveExtension(const char* extension) const; + + // Creates directories so that path exists. Returns true if successful or if + // the directories already exist; returns false if unable to create + // directories for any reason. Will also return false if the FilePath does + // not represent a directory (that is, it doesn't end with a path separator). + bool CreateDirectoriesRecursively() const; + + // Create the directory so that path exists. Returns true if successful or + // if the directory already exists; returns false if unable to create the + // directory for any reason, including if the parent directory does not + // exist. Not named "CreateDirectory" because that's a macro on Windows. + bool CreateFolder() const; + + // Returns true if FilePath describes something in the file-system, + // either a file, directory, or whatever, and that something exists. + bool FileOrDirectoryExists() const; + + // Returns true if pathname describes a directory in the file-system + // that exists. + bool DirectoryExists() const; + + // Returns true if FilePath ends with a path separator, which indicates that + // it is intended to represent a directory. Returns false otherwise. + // This does NOT check that a directory (or file) actually exists. + bool IsDirectory() const; + + // Returns true if pathname describes a root directory. (Windows has one + // root directory per disk drive.) + bool IsRootDirectory() const; + + // Returns true if pathname describes an absolute path. + bool IsAbsolutePath() const; + + private: + // Replaces multiple consecutive separators with a single separator. + // For example, "bar///foo" becomes "bar/foo". Does not eliminate other + // redundancies that might be in a pathname involving "." or "..". + // + // A pathname with multiple consecutive separators may occur either through + // user error or as a result of some scripts or APIs that generate a pathname + // with a trailing separator. On other platforms the same API or script + // may NOT generate a pathname with a trailing "/". Then elsewhere that + // pathname may have another "/" and pathname components added to it, + // without checking for the separator already being there. + // The script language and operating system may allow paths like "foo//bar" + // but some of the functions in FilePath will not handle that correctly. In + // particular, RemoveTrailingPathSeparator() only removes one separator, and + // it is called in CreateDirectoriesRecursively() assuming that it will change + // a pathname from directory syntax (trailing separator) to filename syntax. + // + // On Windows this method also replaces the alternate path separator '/' with + // the primary path separator '\\', so that for example "bar\\/\\foo" becomes + // "bar\\foo". + + void Normalize(); + + // Returns a pointer to the last occurence of a valid path separator in + // the FilePath. On Windows, for example, both '/' and '\' are valid path + // separators. Returns NULL if no path separator was found. + const char* FindLastPathSeparator() const; + + String pathname_; +}; // class FilePath + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ diff --git a/libs/gtest/include/gtest/internal/gtest-internal.h b/libs/gtest/include/gtest/internal/gtest-internal.h new file mode 100644 index 000000000..7aa1197f1 --- /dev/null +++ b/libs/gtest/include/gtest/internal/gtest-internal.h @@ -0,0 +1,1226 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file declares functions and macros used internally by +// Google Test. They are subject to change without notice. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ + +#include "gtest/internal/gtest-port.h" + +#if GTEST_OS_LINUX +# include +# include +# include +# include +#endif // GTEST_OS_LINUX + +#include +#include +#include +#include +#include + +#include "gtest/internal/gtest-string.h" +#include "gtest/internal/gtest-filepath.h" +#include "gtest/internal/gtest-type-util.h" + +// Due to C++ preprocessor weirdness, we need double indirection to +// concatenate two tokens when one of them is __LINE__. Writing +// +// foo ## __LINE__ +// +// will result in the token foo__LINE__, instead of foo followed by +// the current line number. For more details, see +// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 +#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) +#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar + +// Google Test defines the testing::Message class to allow construction of +// test messages via the << operator. The idea is that anything +// streamable to std::ostream can be streamed to a testing::Message. +// This allows a user to use his own types in Google Test assertions by +// overloading the << operator. +// +// util/gtl/stl_logging-inl.h overloads << for STL containers. These +// overloads cannot be defined in the std namespace, as that will be +// undefined behavior. Therefore, they are defined in the global +// namespace instead. +// +// C++'s symbol lookup rule (i.e. Koenig lookup) says that these +// overloads are visible in either the std namespace or the global +// namespace, but not other namespaces, including the testing +// namespace which Google Test's Message class is in. +// +// To allow STL containers (and other types that has a << operator +// defined in the global namespace) to be used in Google Test assertions, +// testing::Message must access the custom << operator from the global +// namespace. Hence this helper function. +// +// Note: Jeffrey Yasskin suggested an alternative fix by "using +// ::operator<<;" in the definition of Message's operator<<. That fix +// doesn't require a helper function, but unfortunately doesn't +// compile with MSVC. +template +inline void GTestStreamToHelper(std::ostream* os, const T& val) { + *os << val; +} + +class ProtocolMessage; +namespace proto2 { class Message; } + +namespace testing { + +// Forward declarations. + +class AssertionResult; // Result of an assertion. +class Message; // Represents a failure message. +class Test; // Represents a test. +class TestInfo; // Information about a test. +class TestPartResult; // Result of a test part. +class UnitTest; // A collection of test cases. + +template +::std::string PrintToString(const T& value); + +namespace internal { + +struct TraceInfo; // Information about a trace point. +class ScopedTrace; // Implements scoped trace. +class TestInfoImpl; // Opaque implementation of TestInfo +class UnitTestImpl; // Opaque implementation of UnitTest + +// How many times InitGoogleTest() has been called. +extern int g_init_gtest_count; + +// The text used in failure messages to indicate the start of the +// stack trace. +GTEST_API_ extern const char kStackTraceMarker[]; + +// A secret type that Google Test users don't know about. It has no +// definition on purpose. Therefore it's impossible to create a +// Secret object, which is what we want. +class Secret; + +// Two overloaded helpers for checking at compile time whether an +// expression is a null pointer literal (i.e. NULL or any 0-valued +// compile-time integral constant). Their return values have +// different sizes, so we can use sizeof() to test which version is +// picked by the compiler. These helpers have no implementations, as +// we only need their signatures. +// +// Given IsNullLiteralHelper(x), the compiler will pick the first +// version if x can be implicitly converted to Secret*, and pick the +// second version otherwise. Since Secret is a secret and incomplete +// type, the only expression a user can write that has type Secret* is +// a null pointer literal. Therefore, we know that x is a null +// pointer literal if and only if the first version is picked by the +// compiler. +char IsNullLiteralHelper(Secret* p); +char (&IsNullLiteralHelper(...))[2]; // NOLINT + +// A compile-time bool constant that is true if and only if x is a +// null pointer literal (i.e. NULL or any 0-valued compile-time +// integral constant). +#ifdef GTEST_ELLIPSIS_NEEDS_POD_ +// We lose support for NULL detection where the compiler doesn't like +// passing non-POD classes through ellipsis (...). +# define GTEST_IS_NULL_LITERAL_(x) false +#else +# define GTEST_IS_NULL_LITERAL_(x) \ + (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) +#endif // GTEST_ELLIPSIS_NEEDS_POD_ + +// Appends the user-supplied message to the Google-Test-generated message. +GTEST_API_ String AppendUserMessage(const String& gtest_msg, + const Message& user_msg); + +// A helper class for creating scoped traces in user programs. +class GTEST_API_ ScopedTrace { + public: + // The c'tor pushes the given source file location and message onto + // a trace stack maintained by Google Test. + ScopedTrace(const char* file, int line, const Message& message); + + // The d'tor pops the info pushed by the c'tor. + // + // Note that the d'tor is not virtual in order to be efficient. + // Don't inherit from ScopedTrace! + ~ScopedTrace(); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); +} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its + // c'tor and d'tor. Therefore it doesn't + // need to be used otherwise. + +// Converts a streamable value to a String. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". +// Declared here but defined in gtest.h, so that it has access +// to the definition of the Message class, required by the ARM +// compiler. +template +String StreamableToString(const T& streamable); + +// The Symbian compiler has a bug that prevents it from selecting the +// correct overload of FormatForComparisonFailureMessage (see below) +// unless we pass the first argument by reference. If we do that, +// however, Visual Age C++ 10.1 generates a compiler error. Therefore +// we only apply the work-around for Symbian. +#if defined(__SYMBIAN32__) +# define GTEST_CREF_WORKAROUND_ const& +#else +# define GTEST_CREF_WORKAROUND_ +#endif + +// When this operand is a const char* or char*, if the other operand +// is a ::std::string or ::string, we print this operand as a C string +// rather than a pointer (we do the same for wide strings); otherwise +// we print it as a pointer to be safe. + +// This internal macro is used to avoid duplicated code. +#define GTEST_FORMAT_IMPL_(operand2_type, operand1_printer)\ +inline String FormatForComparisonFailureMessage(\ + operand2_type::value_type* GTEST_CREF_WORKAROUND_ str, \ + const operand2_type& /*operand2*/) {\ + return operand1_printer(str);\ +}\ +inline String FormatForComparisonFailureMessage(\ + const operand2_type::value_type* GTEST_CREF_WORKAROUND_ str, \ + const operand2_type& /*operand2*/) {\ + return operand1_printer(str);\ +} + +GTEST_FORMAT_IMPL_(::std::string, String::ShowCStringQuoted) +#if GTEST_HAS_STD_WSTRING +GTEST_FORMAT_IMPL_(::std::wstring, String::ShowWideCStringQuoted) +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_STRING +GTEST_FORMAT_IMPL_(::string, String::ShowCStringQuoted) +#endif // GTEST_HAS_GLOBAL_STRING +#if GTEST_HAS_GLOBAL_WSTRING +GTEST_FORMAT_IMPL_(::wstring, String::ShowWideCStringQuoted) +#endif // GTEST_HAS_GLOBAL_WSTRING + +#undef GTEST_FORMAT_IMPL_ + +// The next four overloads handle the case where the operand being +// printed is a char/wchar_t pointer and the other operand is not a +// string/wstring object. In such cases, we just print the operand as +// a pointer to be safe. +#define GTEST_FORMAT_CHAR_PTR_IMPL_(CharType) \ + template \ + String FormatForComparisonFailureMessage(CharType* GTEST_CREF_WORKAROUND_ p, \ + const T&) { \ + return PrintToString(static_cast(p)); \ + } + +GTEST_FORMAT_CHAR_PTR_IMPL_(char) +GTEST_FORMAT_CHAR_PTR_IMPL_(const char) +GTEST_FORMAT_CHAR_PTR_IMPL_(wchar_t) +GTEST_FORMAT_CHAR_PTR_IMPL_(const wchar_t) + +#undef GTEST_FORMAT_CHAR_PTR_IMPL_ + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// expected_expression: "foo" +// actual_expression: "bar" +// expected_value: "5" +// actual_value: "6" +// +// The ignoring_case parameter is true iff the assertion is a +// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// be inserted into the message. +GTEST_API_ AssertionResult EqFailure(const char* expected_expression, + const char* actual_expression, + const String& expected_value, + const String& actual_value, + bool ignoring_case); + +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +GTEST_API_ String GetBoolAssertionFailureMessage( + const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value); + +// This template class represents an IEEE floating-point number +// (either single-precision or double-precision, depending on the +// template parameters). +// +// The purpose of this class is to do more sophisticated number +// comparison. (Due to round-off error, etc, it's very unlikely that +// two floating-points will be equal exactly. Hence a naive +// comparison by the == operation often doesn't work.) +// +// Format of IEEE floating-point: +// +// The most-significant bit being the leftmost, an IEEE +// floating-point looks like +// +// sign_bit exponent_bits fraction_bits +// +// Here, sign_bit is a single bit that designates the sign of the +// number. +// +// For float, there are 8 exponent bits and 23 fraction bits. +// +// For double, there are 11 exponent bits and 52 fraction bits. +// +// More details can be found at +// http://en.wikipedia.org/wiki/IEEE_floating-point_standard. +// +// Template parameter: +// +// RawType: the raw floating-point type (either float or double) +template +class FloatingPoint { + public: + // Defines the unsigned integer type that has the same size as the + // floating point number. + typedef typename TypeWithSize::UInt Bits; + + // Constants. + + // # of bits in a number. + static const size_t kBitCount = 8*sizeof(RawType); + + // # of fraction bits in a number. + static const size_t kFractionBitCount = + std::numeric_limits::digits - 1; + + // # of exponent bits in a number. + static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; + + // The mask for the sign bit. + static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); + + // The mask for the fraction bits. + static const Bits kFractionBitMask = + ~static_cast(0) >> (kExponentBitCount + 1); + + // The mask for the exponent bits. + static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); + + // How many ULP's (Units in the Last Place) we want to tolerate when + // comparing two numbers. The larger the value, the more error we + // allow. A 0 value means that two numbers must be exactly the same + // to be considered equal. + // + // The maximum error of a single floating-point operation is 0.5 + // units in the last place. On Intel CPU's, all floating-point + // calculations are done with 80-bit precision, while double has 64 + // bits. Therefore, 4 should be enough for ordinary use. + // + // See the following article for more details on ULP: + // http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm. + static const size_t kMaxUlps = 4; + + // Constructs a FloatingPoint from a raw floating-point number. + // + // On an Intel CPU, passing a non-normalized NAN (Not a Number) + // around may change its bits, although the new value is guaranteed + // to be also a NAN. Therefore, don't expect this constructor to + // preserve the bits in x when x is a NAN. + explicit FloatingPoint(const RawType& x) { u_.value_ = x; } + + // Static methods + + // Reinterprets a bit pattern as a floating-point number. + // + // This function is needed to test the AlmostEquals() method. + static RawType ReinterpretBits(const Bits bits) { + FloatingPoint fp(0); + fp.u_.bits_ = bits; + return fp.u_.value_; + } + + // Returns the floating-point number that represent positive infinity. + static RawType Infinity() { + return ReinterpretBits(kExponentBitMask); + } + + // Non-static methods + + // Returns the bits that represents this number. + const Bits &bits() const { return u_.bits_; } + + // Returns the exponent bits of this number. + Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } + + // Returns the fraction bits of this number. + Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } + + // Returns the sign bit of this number. + Bits sign_bit() const { return kSignBitMask & u_.bits_; } + + // Returns true iff this is NAN (not a number). + bool is_nan() const { + // It's a NAN if the exponent bits are all ones and the fraction + // bits are not entirely zeros. + return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); + } + + // Returns true iff this number is at most kMaxUlps ULP's away from + // rhs. In particular, this function: + // + // - returns false if either number is (or both are) NAN. + // - treats really large numbers as almost equal to infinity. + // - thinks +0.0 and -0.0 are 0 DLP's apart. + bool AlmostEquals(const FloatingPoint& rhs) const { + // The IEEE standard says that any comparison operation involving + // a NAN must return false. + if (is_nan() || rhs.is_nan()) return false; + + return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) + <= kMaxUlps; + } + + private: + // The data type used to store the actual floating-point number. + union FloatingPointUnion { + RawType value_; // The raw floating-point number. + Bits bits_; // The bits that represent the number. + }; + + // Converts an integer from the sign-and-magnitude representation to + // the biased representation. More precisely, let N be 2 to the + // power of (kBitCount - 1), an integer x is represented by the + // unsigned number x + N. + // + // For instance, + // + // -N + 1 (the most negative number representable using + // sign-and-magnitude) is represented by 1; + // 0 is represented by N; and + // N - 1 (the biggest number representable using + // sign-and-magnitude) is represented by 2N - 1. + // + // Read http://en.wikipedia.org/wiki/Signed_number_representations + // for more details on signed number representations. + static Bits SignAndMagnitudeToBiased(const Bits &sam) { + if (kSignBitMask & sam) { + // sam represents a negative number. + return ~sam + 1; + } else { + // sam represents a positive number. + return kSignBitMask | sam; + } + } + + // Given two numbers in the sign-and-magnitude representation, + // returns the distance between them as an unsigned number. + static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, + const Bits &sam2) { + const Bits biased1 = SignAndMagnitudeToBiased(sam1); + const Bits biased2 = SignAndMagnitudeToBiased(sam2); + return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); + } + + FloatingPointUnion u_; +}; + +// Typedefs the instances of the FloatingPoint template class that we +// care to use. +typedef FloatingPoint Float; +typedef FloatingPoint Double; + +// In order to catch the mistake of putting tests that use different +// test fixture classes in the same test case, we need to assign +// unique IDs to fixture classes and compare them. The TypeId type is +// used to hold such IDs. The user should treat TypeId as an opaque +// type: the only operation allowed on TypeId values is to compare +// them for equality using the == operator. +typedef const void* TypeId; + +template +class TypeIdHelper { + public: + // dummy_ must not have a const type. Otherwise an overly eager + // compiler (e.g. MSVC 7.1 & 8.0) may try to merge + // TypeIdHelper::dummy_ for different Ts as an "optimization". + static bool dummy_; +}; + +template +bool TypeIdHelper::dummy_ = false; + +// GetTypeId() returns the ID of type T. Different values will be +// returned for different types. Calling the function twice with the +// same type argument is guaranteed to return the same ID. +template +TypeId GetTypeId() { + // The compiler is required to allocate a different + // TypeIdHelper::dummy_ variable for each T used to instantiate + // the template. Therefore, the address of dummy_ is guaranteed to + // be unique. + return &(TypeIdHelper::dummy_); +} + +// Returns the type ID of ::testing::Test. Always call this instead +// of GetTypeId< ::testing::Test>() to get the type ID of +// ::testing::Test, as the latter may give the wrong result due to a +// suspected linker bug when compiling Google Test as a Mac OS X +// framework. +GTEST_API_ TypeId GetTestTypeId(); + +// Defines the abstract factory interface that creates instances +// of a Test object. +class TestFactoryBase { + public: + virtual ~TestFactoryBase() {} + + // Creates a test instance to run. The instance is both created and destroyed + // within TestInfoImpl::Run() + virtual Test* CreateTest() = 0; + + protected: + TestFactoryBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); +}; + +// This class provides implementation of TeastFactoryBase interface. +// It is used in TEST and TEST_F macros. +template +class TestFactoryImpl : public TestFactoryBase { + public: + virtual Test* CreateTest() { return new TestClass; } +}; + +#if GTEST_OS_WINDOWS + +// Predicate-formatters for implementing the HRESULT checking macros +// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} +// We pass a long instead of HRESULT to avoid causing an +// include dependency for the HRESULT type. +GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, + long hr); // NOLINT +GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, + long hr); // NOLINT + +#endif // GTEST_OS_WINDOWS + +// Types of SetUpTestCase() and TearDownTestCase() functions. +typedef void (*SetUpTestCaseFunc)(); +typedef void (*TearDownTestCaseFunc)(); + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. +// +// Arguments: +// +// test_case_name: name of the test case +// name: name of the test +// type_param the name of the test's type parameter, or NULL if +// this is not a typed or a type-parameterized test. +// value_param text representation of the test's value parameter, +// or NULL if this is not a type-parameterized test. +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +GTEST_API_ TestInfo* MakeAndRegisterTestInfo( + const char* test_case_name, const char* name, + const char* type_param, + const char* value_param, + TypeId fixture_class_id, + SetUpTestCaseFunc set_up_tc, + TearDownTestCaseFunc tear_down_tc, + TestFactoryBase* factory); + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// State of the definition of a type-parameterized test case. +class GTEST_API_ TypedTestCasePState { + public: + TypedTestCasePState() : registered_(false) {} + + // Adds the given test name to defined_test_names_ and return true + // if the test case hasn't been registered; otherwise aborts the + // program. + bool AddTestName(const char* file, int line, const char* case_name, + const char* test_name) { + if (registered_) { + fprintf(stderr, "%s Test %s must be defined before " + "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", + FormatFileLocation(file, line).c_str(), test_name, case_name); + fflush(stderr); + posix::Abort(); + } + defined_test_names_.insert(test_name); + return true; + } + + // Verifies that registered_tests match the test names in + // defined_test_names_; returns registered_tests if successful, or + // aborts the program otherwise. + const char* VerifyRegisteredTestNames( + const char* file, int line, const char* registered_tests); + + private: + bool registered_; + ::std::set defined_test_names_; +}; + +// Skips to the first non-space char after the first comma in 'str'; +// returns NULL if no comma is found in 'str'. +inline const char* SkipComma(const char* str) { + const char* comma = strchr(str, ','); + if (comma == NULL) { + return NULL; + } + while (IsSpace(*(++comma))) {} + return comma; +} + +// Returns the prefix of 'str' before the first comma in it; returns +// the entire string if it contains no comma. +inline String GetPrefixUntilComma(const char* str) { + const char* comma = strchr(str, ','); + return comma == NULL ? String(str) : String(str, comma - str); +} + +// TypeParameterizedTest::Register() +// registers a list of type-parameterized tests with Google Test. The +// return value is insignificant - we just need to return something +// such that we can call this function in a namespace scope. +// +// Implementation note: The GTEST_TEMPLATE_ macro declares a template +// template parameter. It's defined in gtest-type-util.h. +template +class TypeParameterizedTest { + public: + // 'index' is the index of the test in the type list 'Types' + // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, + // Types). Valid values for 'index' are [0, N - 1] where N is the + // length of Types. + static bool Register(const char* prefix, const char* case_name, + const char* test_names, int index) { + typedef typename Types::Head Type; + typedef Fixture FixtureClass; + typedef typename GTEST_BIND_(TestSel, Type) TestClass; + + // First, registers the first type-parameterized test in the type + // list. + MakeAndRegisterTestInfo( + String::Format("%s%s%s/%d", prefix, prefix[0] == '\0' ? "" : "/", + case_name, index).c_str(), + GetPrefixUntilComma(test_names).c_str(), + GetTypeName().c_str(), + NULL, // No value parameter. + GetTypeId(), + TestClass::SetUpTestCase, + TestClass::TearDownTestCase, + new TestFactoryImpl); + + // Next, recurses (at compile time) with the tail of the type list. + return TypeParameterizedTest + ::Register(prefix, case_name, test_names, index + 1); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTest { + public: + static bool Register(const char* /*prefix*/, const char* /*case_name*/, + const char* /*test_names*/, int /*index*/) { + return true; + } +}; + +// TypeParameterizedTestCase::Register() +// registers *all combinations* of 'Tests' and 'Types' with Google +// Test. The return value is insignificant - we just need to return +// something such that we can call this function in a namespace scope. +template +class TypeParameterizedTestCase { + public: + static bool Register(const char* prefix, const char* case_name, + const char* test_names) { + typedef typename Tests::Head Head; + + // First, register the first test in 'Test' for each type in 'Types'. + TypeParameterizedTest::Register( + prefix, case_name, test_names, 0); + + // Next, recurses (at compile time) with the tail of the test list. + return TypeParameterizedTestCase + ::Register(prefix, case_name, SkipComma(test_names)); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTestCase { + public: + static bool Register(const char* /*prefix*/, const char* /*case_name*/, + const char* /*test_names*/) { + return true; + } +}; + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +GTEST_API_ String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, + int skip_count); + +// Helpers for suppressing warnings on unreachable code or constant +// condition. + +// Always returns true. +GTEST_API_ bool AlwaysTrue(); + +// Always returns false. +inline bool AlwaysFalse() { return !AlwaysTrue(); } + +// Helper for suppressing false warning from Clang on a const char* +// variable declared in a conditional expression always being NULL in +// the else branch. +struct GTEST_API_ ConstCharPtr { + ConstCharPtr(const char* str) : value(str) {} + operator bool() const { return true; } + const char* value; +}; + +// A simple Linear Congruential Generator for generating random +// numbers with a uniform distribution. Unlike rand() and srand(), it +// doesn't use global state (and therefore can't interfere with user +// code). Unlike rand_r(), it's portable. An LCG isn't very random, +// but it's good enough for our purposes. +class GTEST_API_ Random { + public: + static const UInt32 kMaxRange = 1u << 31; + + explicit Random(UInt32 seed) : state_(seed) {} + + void Reseed(UInt32 seed) { state_ = seed; } + + // Generates a random number from [0, range). Crashes if 'range' is + // 0 or greater than kMaxRange. + UInt32 Generate(UInt32 range); + + private: + UInt32 state_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); +}; + +// Defining a variable of type CompileAssertTypesEqual will cause a +// compiler error iff T1 and T2 are different types. +template +struct CompileAssertTypesEqual; + +template +struct CompileAssertTypesEqual { +}; + +// Removes the reference from a type if it is a reference type, +// otherwise leaves it unchanged. This is the same as +// tr1::remove_reference, which is not widely available yet. +template +struct RemoveReference { typedef T type; }; // NOLINT +template +struct RemoveReference { typedef T type; }; // NOLINT + +// A handy wrapper around RemoveReference that works when the argument +// T depends on template parameters. +#define GTEST_REMOVE_REFERENCE_(T) \ + typename ::testing::internal::RemoveReference::type + +// Removes const from a type if it is a const type, otherwise leaves +// it unchanged. This is the same as tr1::remove_const, which is not +// widely available yet. +template +struct RemoveConst { typedef T type; }; // NOLINT +template +struct RemoveConst { typedef T type; }; // NOLINT + +// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above +// definition to fail to remove the const in 'const int[3]' and 'const +// char[3][4]'. The following specialization works around the bug. +// However, it causes trouble with GCC and thus needs to be +// conditionally compiled. +#if defined(_MSC_VER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) +template +struct RemoveConst { + typedef typename RemoveConst::type type[N]; +}; +#endif + +// A handy wrapper around RemoveConst that works when the argument +// T depends on template parameters. +#define GTEST_REMOVE_CONST_(T) \ + typename ::testing::internal::RemoveConst::type + +// Turns const U&, U&, const U, and U all into U. +#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ + GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) + +// Adds reference to a type if it is not a reference type, +// otherwise leaves it unchanged. This is the same as +// tr1::add_reference, which is not widely available yet. +template +struct AddReference { typedef T& type; }; // NOLINT +template +struct AddReference { typedef T& type; }; // NOLINT + +// A handy wrapper around AddReference that works when the argument T +// depends on template parameters. +#define GTEST_ADD_REFERENCE_(T) \ + typename ::testing::internal::AddReference::type + +// Adds a reference to const on top of T as necessary. For example, +// it transforms +// +// char ==> const char& +// const char ==> const char& +// char& ==> const char& +// const char& ==> const char& +// +// The argument T must depend on some template parameters. +#define GTEST_REFERENCE_TO_CONST_(T) \ + GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T)) + +// ImplicitlyConvertible::value is a compile-time bool +// constant that's true iff type From can be implicitly converted to +// type To. +template +class ImplicitlyConvertible { + private: + // We need the following helper functions only for their types. + // They have no implementations. + + // MakeFrom() is an expression whose type is From. We cannot simply + // use From(), as the type From may not have a public default + // constructor. + static From MakeFrom(); + + // These two functions are overloaded. Given an expression + // Helper(x), the compiler will pick the first version if x can be + // implicitly converted to type To; otherwise it will pick the + // second version. + // + // The first version returns a value of size 1, and the second + // version returns a value of size 2. Therefore, by checking the + // size of Helper(x), which can be done at compile time, we can tell + // which version of Helper() is used, and hence whether x can be + // implicitly converted to type To. + static char Helper(To); + static char (&Helper(...))[2]; // NOLINT + + // We have to put the 'public' section after the 'private' section, + // or MSVC refuses to compile the code. + public: + // MSVC warns about implicitly converting from double to int for + // possible loss of data, so we need to temporarily disable the + // warning. +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4244) // Temporarily disables warning 4244. + + static const bool value = + sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; +# pragma warning(pop) // Restores the warning state. +#elif defined(__BORLANDC__) + // C++Builder cannot use member overload resolution during template + // instantiation. The simplest workaround is to use its C++0x type traits + // functions (C++Builder 2009 and above only). + static const bool value = __is_convertible(From, To); +#else + static const bool value = + sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; +#endif // _MSV_VER +}; +template +const bool ImplicitlyConvertible::value; + +// IsAProtocolMessage::value is a compile-time bool constant that's +// true iff T is type ProtocolMessage, proto2::Message, or a subclass +// of those. +template +struct IsAProtocolMessage + : public bool_constant< + ImplicitlyConvertible::value || + ImplicitlyConvertible::value> { +}; + +// When the compiler sees expression IsContainerTest(0), if C is an +// STL-style container class, the first overload of IsContainerTest +// will be viable (since both C::iterator* and C::const_iterator* are +// valid types and NULL can be implicitly converted to them). It will +// be picked over the second overload as 'int' is a perfect match for +// the type of argument 0. If C::iterator or C::const_iterator is not +// a valid type, the first overload is not viable, and the second +// overload will be picked. Therefore, we can determine whether C is +// a container class by checking the type of IsContainerTest(0). +// The value of the expression is insignificant. +// +// Note that we look for both C::iterator and C::const_iterator. The +// reason is that C++ injects the name of a class as a member of the +// class itself (e.g. you can refer to class iterator as either +// 'iterator' or 'iterator::iterator'). If we look for C::iterator +// only, for example, we would mistakenly think that a class named +// iterator is an STL container. +// +// Also note that the simpler approach of overloading +// IsContainerTest(typename C::const_iterator*) and +// IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. +typedef int IsContainer; +template +IsContainer IsContainerTest(int /* dummy */, + typename C::iterator* /* it */ = NULL, + typename C::const_iterator* /* const_it */ = NULL) { + return 0; +} + +typedef char IsNotContainer; +template +IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } + +// EnableIf::type is void when 'Cond' is true, and +// undefined when 'Cond' is false. To use SFINAE to make a function +// overload only apply when a particular expression is true, add +// "typename EnableIf::type* = 0" as the last parameter. +template struct EnableIf; +template<> struct EnableIf { typedef void type; }; // NOLINT + +// Utilities for native arrays. + +// ArrayEq() compares two k-dimensional native arrays using the +// elements' operator==, where k can be any integer >= 0. When k is +// 0, ArrayEq() degenerates into comparing a single pair of values. + +template +bool ArrayEq(const T* lhs, size_t size, const U* rhs); + +// This generic version is used when k is 0. +template +inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } + +// This overload is used when k >= 1. +template +inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { + return internal::ArrayEq(lhs, N, rhs); +} + +// This helper reduces code bloat. If we instead put its logic inside +// the previous ArrayEq() function, arrays with different sizes would +// lead to different copies of the template code. +template +bool ArrayEq(const T* lhs, size_t size, const U* rhs) { + for (size_t i = 0; i != size; i++) { + if (!internal::ArrayEq(lhs[i], rhs[i])) + return false; + } + return true; +} + +// Finds the first element in the iterator range [begin, end) that +// equals elem. Element may be a native array type itself. +template +Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { + for (Iter it = begin; it != end; ++it) { + if (internal::ArrayEq(*it, elem)) + return it; + } + return end; +} + +// CopyArray() copies a k-dimensional native array using the elements' +// operator=, where k can be any integer >= 0. When k is 0, +// CopyArray() degenerates into copying a single value. + +template +void CopyArray(const T* from, size_t size, U* to); + +// This generic version is used when k is 0. +template +inline void CopyArray(const T& from, U* to) { *to = from; } + +// This overload is used when k >= 1. +template +inline void CopyArray(const T(&from)[N], U(*to)[N]) { + internal::CopyArray(from, N, *to); +} + +// This helper reduces code bloat. If we instead put its logic inside +// the previous CopyArray() function, arrays with different sizes +// would lead to different copies of the template code. +template +void CopyArray(const T* from, size_t size, U* to) { + for (size_t i = 0; i != size; i++) { + internal::CopyArray(from[i], to + i); + } +} + +// The relation between an NativeArray object (see below) and the +// native array it represents. +enum RelationToSource { + kReference, // The NativeArray references the native array. + kCopy // The NativeArray makes a copy of the native array and + // owns the copy. +}; + +// Adapts a native array to a read-only STL-style container. Instead +// of the complete STL container concept, this adaptor only implements +// members useful for Google Mock's container matchers. New members +// should be added as needed. To simplify the implementation, we only +// support Element being a raw type (i.e. having no top-level const or +// reference modifier). It's the client's responsibility to satisfy +// this requirement. Element can be an array type itself (hence +// multi-dimensional arrays are supported). +template +class NativeArray { + public: + // STL-style container typedefs. + typedef Element value_type; + typedef Element* iterator; + typedef const Element* const_iterator; + + // Constructs from a native array. + NativeArray(const Element* array, size_t count, RelationToSource relation) { + Init(array, count, relation); + } + + // Copy constructor. + NativeArray(const NativeArray& rhs) { + Init(rhs.array_, rhs.size_, rhs.relation_to_source_); + } + + ~NativeArray() { + // Ensures that the user doesn't instantiate NativeArray with a + // const or reference type. + static_cast(StaticAssertTypeEqHelper()); + if (relation_to_source_ == kCopy) + delete[] array_; + } + + // STL-style container methods. + size_t size() const { return size_; } + const_iterator begin() const { return array_; } + const_iterator end() const { return array_ + size_; } + bool operator==(const NativeArray& rhs) const { + return size() == rhs.size() && + ArrayEq(begin(), size(), rhs.begin()); + } + + private: + // Initializes this object; makes a copy of the input array if + // 'relation' is kCopy. + void Init(const Element* array, size_t a_size, RelationToSource relation) { + if (relation == kReference) { + array_ = array; + } else { + Element* const copy = new Element[a_size]; + CopyArray(array, a_size, copy); + array_ = copy; + } + size_ = a_size; + relation_to_source_ = relation; + } + + const Element* array_; + size_t size_; + RelationToSource relation_to_source_; + + GTEST_DISALLOW_ASSIGN_(NativeArray); +}; + +} // namespace internal +} // namespace testing + +#define GTEST_MESSAGE_AT_(file, line, message, result_type) \ + ::testing::internal::AssertHelper(result_type, file, line, message) \ + = ::testing::Message() + +#define GTEST_MESSAGE_(message, result_type) \ + GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type) + +#define GTEST_FATAL_FAILURE_(message) \ + return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) + +#define GTEST_NONFATAL_FAILURE_(message) \ + GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) + +#define GTEST_SUCCESS_(message) \ + GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) + +// Suppresses MSVC warnings 4072 (unreachable code) for the code following +// statement if it returns or throws (or doesn't return or throw in some +// situations). +#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ + if (::testing::internal::AlwaysTrue()) { statement; } + +#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::ConstCharPtr gtest_msg = "") { \ + bool gtest_caught_expected = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (expected_exception const&) { \ + gtest_caught_expected = true; \ + } \ + catch (...) { \ + gtest_msg.value = \ + "Expected: " #statement " throws an exception of type " \ + #expected_exception ".\n Actual: it throws a different type."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + if (!gtest_caught_expected) { \ + gtest_msg.value = \ + "Expected: " #statement " throws an exception of type " \ + #expected_exception ".\n Actual: it throws nothing."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ + fail(gtest_msg.value) + +#define GTEST_TEST_NO_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (...) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ + fail("Expected: " #statement " doesn't throw an exception.\n" \ + " Actual: it throws.") + +#define GTEST_TEST_ANY_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + bool gtest_caught_any = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (...) { \ + gtest_caught_any = true; \ + } \ + if (!gtest_caught_any) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ + fail("Expected: " #statement " throws an exception.\n" \ + " Actual: it doesn't.") + + +// Implements Boolean test assertions such as EXPECT_TRUE. expression can be +// either a boolean expression or an AssertionResult. text is a textual +// represenation of expression as it was passed into the EXPECT_TRUE. +#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar_ = \ + ::testing::AssertionResult(expression)) \ + ; \ + else \ + fail(::testing::internal::GetBoolAssertionFailureMessage(\ + gtest_ar_, text, #actual, #expected).c_str()) + +#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ + fail("Expected: " #statement " doesn't generate new fatal " \ + "failures in the current thread.\n" \ + " Actual: it does.") + +// Expands to the name of the class that implements the given test. +#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ + test_case_name##_##test_name##_Test + +// Helper macro for defining tests. +#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ +class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ + public:\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ + private:\ + virtual void TestBody();\ + static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\ + GTEST_DISALLOW_COPY_AND_ASSIGN_(\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ +};\ +\ +::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ + ::test_info_ =\ + ::testing::internal::MakeAndRegisterTestInfo(\ + #test_case_name, #test_name, NULL, NULL, \ + (parent_id), \ + parent_class::SetUpTestCase, \ + parent_class::TearDownTestCase, \ + new ::testing::internal::TestFactoryImpl<\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ +void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ diff --git a/libs/gtest/include/gtest/internal/gtest-linked_ptr.h b/libs/gtest/include/gtest/internal/gtest-linked_ptr.h new file mode 100644 index 000000000..57147b4e8 --- /dev/null +++ b/libs/gtest/include/gtest/internal/gtest-linked_ptr.h @@ -0,0 +1,233 @@ +// Copyright 2003 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Dan Egnor (egnor@google.com) +// +// A "smart" pointer type with reference tracking. Every pointer to a +// particular object is kept on a circular linked list. When the last pointer +// to an object is destroyed or reassigned, the object is deleted. +// +// Used properly, this deletes the object when the last reference goes away. +// There are several caveats: +// - Like all reference counting schemes, cycles lead to leaks. +// - Each smart pointer is actually two pointers (8 bytes instead of 4). +// - Every time a pointer is assigned, the entire list of pointers to that +// object is traversed. This class is therefore NOT SUITABLE when there +// will often be more than two or three pointers to a particular object. +// - References are only tracked as long as linked_ptr<> objects are copied. +// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS +// will happen (double deletion). +// +// A good use of this class is storing object references in STL containers. +// You can safely put linked_ptr<> in a vector<>. +// Other uses may not be as good. +// +// Note: If you use an incomplete type with linked_ptr<>, the class +// *containing* linked_ptr<> must have a constructor and destructor (even +// if they do nothing!). +// +// Bill Gibbons suggested we use something like this. +// +// Thread Safety: +// Unlike other linked_ptr implementations, in this implementation +// a linked_ptr object is thread-safe in the sense that: +// - it's safe to copy linked_ptr objects concurrently, +// - it's safe to copy *from* a linked_ptr and read its underlying +// raw pointer (e.g. via get()) concurrently, and +// - it's safe to write to two linked_ptrs that point to the same +// shared object concurrently. +// TODO(wan@google.com): rename this to safe_linked_ptr to avoid +// confusion with normal linked_ptr. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ + +#include +#include + +#include "gtest/internal/gtest-port.h" + +namespace testing { +namespace internal { + +// Protects copying of all linked_ptr objects. +GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); + +// This is used internally by all instances of linked_ptr<>. It needs to be +// a non-template class because different types of linked_ptr<> can refer to +// the same object (linked_ptr(obj) vs linked_ptr(obj)). +// So, it needs to be possible for different types of linked_ptr to participate +// in the same circular linked list, so we need a single class type here. +// +// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr. +class linked_ptr_internal { + public: + // Create a new circle that includes only this instance. + void join_new() { + next_ = this; + } + + // Many linked_ptr operations may change p.link_ for some linked_ptr + // variable p in the same circle as this object. Therefore we need + // to prevent two such operations from occurring concurrently. + // + // Note that different types of linked_ptr objects can coexist in a + // circle (e.g. linked_ptr, linked_ptr, and + // linked_ptr). Therefore we must use a single mutex to + // protect all linked_ptr objects. This can create serious + // contention in production code, but is acceptable in a testing + // framework. + + // Join an existing circle. + // L < g_linked_ptr_mutex + void join(linked_ptr_internal const* ptr) { + MutexLock lock(&g_linked_ptr_mutex); + + linked_ptr_internal const* p = ptr; + while (p->next_ != ptr) p = p->next_; + p->next_ = this; + next_ = ptr; + } + + // Leave whatever circle we're part of. Returns true if we were the + // last member of the circle. Once this is done, you can join() another. + // L < g_linked_ptr_mutex + bool depart() { + MutexLock lock(&g_linked_ptr_mutex); + + if (next_ == this) return true; + linked_ptr_internal const* p = next_; + while (p->next_ != this) p = p->next_; + p->next_ = next_; + return false; + } + + private: + mutable linked_ptr_internal const* next_; +}; + +template +class linked_ptr { + public: + typedef T element_type; + + // Take over ownership of a raw pointer. This should happen as soon as + // possible after the object is created. + explicit linked_ptr(T* ptr = NULL) { capture(ptr); } + ~linked_ptr() { depart(); } + + // Copy an existing linked_ptr<>, adding ourselves to the list of references. + template linked_ptr(linked_ptr const& ptr) { copy(&ptr); } + linked_ptr(linked_ptr const& ptr) { // NOLINT + assert(&ptr != this); + copy(&ptr); + } + + // Assignment releases the old value and acquires the new. + template linked_ptr& operator=(linked_ptr const& ptr) { + depart(); + copy(&ptr); + return *this; + } + + linked_ptr& operator=(linked_ptr const& ptr) { + if (&ptr != this) { + depart(); + copy(&ptr); + } + return *this; + } + + // Smart pointer members. + void reset(T* ptr = NULL) { + depart(); + capture(ptr); + } + T* get() const { return value_; } + T* operator->() const { return value_; } + T& operator*() const { return *value_; } + + bool operator==(T* p) const { return value_ == p; } + bool operator!=(T* p) const { return value_ != p; } + template + bool operator==(linked_ptr const& ptr) const { + return value_ == ptr.get(); + } + template + bool operator!=(linked_ptr const& ptr) const { + return value_ != ptr.get(); + } + + private: + template + friend class linked_ptr; + + T* value_; + linked_ptr_internal link_; + + void depart() { + if (link_.depart()) delete value_; + } + + void capture(T* ptr) { + value_ = ptr; + link_.join_new(); + } + + template void copy(linked_ptr const* ptr) { + value_ = ptr->get(); + if (value_) + link_.join(&ptr->link_); + else + link_.join_new(); + } +}; + +template inline +bool operator==(T* ptr, const linked_ptr& x) { + return ptr == x.get(); +} + +template inline +bool operator!=(T* ptr, const linked_ptr& x) { + return ptr != x.get(); +} + +// A function to convert T* into linked_ptr +// Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation +// for linked_ptr >(new FooBarBaz(arg)) +template +linked_ptr make_linked_ptr(T* ptr) { + return linked_ptr(ptr); +} + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ diff --git a/libs/gtest/include/gtest/internal/gtest-param-util-generated.h b/libs/gtest/include/gtest/internal/gtest-param-util-generated.h new file mode 100644 index 000000000..258267500 --- /dev/null +++ b/libs/gtest/include/gtest/internal/gtest-param-util-generated.h @@ -0,0 +1,4822 @@ +// This file was GENERATED by command: +// pump.py gtest-param-util-generated.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) + +// Type and function utilities for implementing parameterized tests. +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently Google Test supports at most 50 arguments in Values, +// and at most 10 arguments in Combine. Please contact +// googletestframework@googlegroups.com if you need more. +// Please note that the number of arguments to Combine is limited +// by the maximum arity of the implementation of tr1::tuple which is +// currently set at 10. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +#include "gtest/internal/gtest-param-util.h" +#include "gtest/internal/gtest-port.h" + +#if GTEST_HAS_PARAM_TEST + +namespace testing { + +// Forward declarations of ValuesIn(), which is implemented in +// include/gtest/gtest-param-test.h. +template +internal::ParamGenerator< + typename ::testing::internal::IteratorTraits::value_type> +ValuesIn(ForwardIterator begin, ForwardIterator end); + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]); + +template +internal::ParamGenerator ValuesIn( + const Container& container); + +namespace internal { + +// Used in the Values() function to provide polymorphic capabilities. +template +class ValueArray1 { + public: + explicit ValueArray1(T1 v1) : v1_(v1) {} + + template + operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray1& other); + + const T1 v1_; +}; + +template +class ValueArray2 { + public: + ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray2& other); + + const T1 v1_; + const T2 v2_; +}; + +template +class ValueArray3 { + public: + ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray3& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; +}; + +template +class ValueArray4 { + public: + ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray4& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; +}; + +template +class ValueArray5 { + public: + ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray5& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; +}; + +template +class ValueArray6 { + public: + ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray6& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; +}; + +template +class ValueArray7 { + public: + ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray7& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; +}; + +template +class ValueArray8 { + public: + ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray8& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; +}; + +template +class ValueArray9 { + public: + ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray9& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; +}; + +template +class ValueArray10 { + public: + ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray10& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; +}; + +template +class ValueArray11 { + public: + ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray11& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; +}; + +template +class ValueArray12 { + public: + ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray12& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; +}; + +template +class ValueArray13 { + public: + ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray13& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; +}; + +template +class ValueArray14 { + public: + ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray14& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; +}; + +template +class ValueArray15 { + public: + ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray15& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; +}; + +template +class ValueArray16 { + public: + ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray16& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; +}; + +template +class ValueArray17 { + public: + ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray17& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; +}; + +template +class ValueArray18 { + public: + ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray18& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; +}; + +template +class ValueArray19 { + public: + ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray19& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; +}; + +template +class ValueArray20 { + public: + ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray20& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; +}; + +template +class ValueArray21 { + public: + ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray21& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; +}; + +template +class ValueArray22 { + public: + ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray22& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; +}; + +template +class ValueArray23 { + public: + ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, + v23_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray23& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; +}; + +template +class ValueArray24 { + public: + ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray24& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; +}; + +template +class ValueArray25 { + public: + ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray25& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; +}; + +template +class ValueArray26 { + public: + ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray26& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; +}; + +template +class ValueArray27 { + public: + ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray27& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; +}; + +template +class ValueArray28 { + public: + ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray28& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; +}; + +template +class ValueArray29 { + public: + ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray29& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; +}; + +template +class ValueArray30 { + public: + ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray30& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; +}; + +template +class ValueArray31 { + public: + ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray31& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; +}; + +template +class ValueArray32 { + public: + ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray32& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; +}; + +template +class ValueArray33 { + public: + ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, + T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray33& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; +}; + +template +class ValueArray34 { + public: + ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray34& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; +}; + +template +class ValueArray35 { + public: + ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), + v32_(v32), v33_(v33), v34_(v34), v35_(v35) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, + v35_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray35& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; +}; + +template +class ValueArray36 { + public: + ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), + v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray36& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; +}; + +template +class ValueArray37 { + public: + ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), + v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), + v36_(v36), v37_(v37) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray37& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; +}; + +template +class ValueArray38 { + public: + ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray38& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; +}; + +template +class ValueArray39 { + public: + ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray39& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; +}; + +template +class ValueArray40 { + public: + ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), + v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), + v40_(v40) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray40& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; +}; + +template +class ValueArray41 { + public: + ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, + T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray41& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; +}; + +template +class ValueArray42 { + public: + ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray42& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; +}; + +template +class ValueArray43 { + public: + ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), + v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), + v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray43& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; +}; + +template +class ValueArray44 { + public: + ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), + v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), + v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), + v43_(v43), v44_(v44) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray44& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; +}; + +template +class ValueArray45 { + public: + ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), + v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), + v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), + v42_(v42), v43_(v43), v44_(v44), v45_(v45) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray45& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; +}; + +template +class ValueArray46 { + public: + ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), + v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray46& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; +}; + +template +class ValueArray47 { + public: + ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), + v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), + v47_(v47) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, + v47_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray47& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; +}; + +template +class ValueArray48 { + public: + ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), + v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), + v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), + v46_(v46), v47_(v47), v48_(v48) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, + v48_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray48& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; +}; + +template +class ValueArray49 { + public: + ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, + T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), + v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, + v48_, v49_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray49& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; + const T49 v49_; +}; + +template +class ValueArray50 { + public: + ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, + T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), + v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, + v48_, v49_, v50_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray50& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; + const T49 v49_; + const T50 v50_; +}; + +# if GTEST_HAS_COMBINE +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Generates values from the Cartesian product of values produced +// by the argument generators. +// +template +class CartesianProductGenerator2 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator2(const ParamGenerator& g1, + const ParamGenerator& g2) + : g1_(g1), g2_(g2) {} + virtual ~CartesianProductGenerator2() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current2_; + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + ParamType current_value_; + }; // class CartesianProductGenerator2::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator2& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; +}; // class CartesianProductGenerator2 + + +template +class CartesianProductGenerator3 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator3(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3) + : g1_(g1), g2_(g2), g3_(g3) {} + virtual ~CartesianProductGenerator3() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current3_; + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + ParamType current_value_; + }; // class CartesianProductGenerator3::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator3& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; +}; // class CartesianProductGenerator3 + + +template +class CartesianProductGenerator4 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator4(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} + virtual ~CartesianProductGenerator4() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current4_; + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + ParamType current_value_; + }; // class CartesianProductGenerator4::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator4& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; +}; // class CartesianProductGenerator4 + + +template +class CartesianProductGenerator5 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator5(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} + virtual ~CartesianProductGenerator5() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current5_; + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + ParamType current_value_; + }; // class CartesianProductGenerator5::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator5& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; +}; // class CartesianProductGenerator5 + + +template +class CartesianProductGenerator6 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator6(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} + virtual ~CartesianProductGenerator6() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current6_; + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + ParamType current_value_; + }; // class CartesianProductGenerator6::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator6& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; +}; // class CartesianProductGenerator6 + + +template +class CartesianProductGenerator7 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator7(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} + virtual ~CartesianProductGenerator7() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current7_; + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + ParamType current_value_; + }; // class CartesianProductGenerator7::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator7& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; +}; // class CartesianProductGenerator7 + + +template +class CartesianProductGenerator8 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator8(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), + g8_(g8) {} + virtual ~CartesianProductGenerator8() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current8_; + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + ParamType current_value_; + }; // class CartesianProductGenerator8::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator8& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; +}; // class CartesianProductGenerator8 + + +template +class CartesianProductGenerator9 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator9(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8, const ParamGenerator& g9) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9) {} + virtual ~CartesianProductGenerator9() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end(), g9_, g9_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8, + const ParamGenerator& g9, + const typename ParamGenerator::iterator& current9) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8), + begin9_(g9.begin()), end9_(g9.end()), current9_(current9) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current9_; + if (current9_ == end9_) { + current9_ = begin9_; + ++current8_; + } + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_ && + current9_ == typed_other->current9_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_), + begin9_(other.begin9_), + end9_(other.end9_), + current9_(other.current9_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_, + *current9_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_ || + current9_ == end9_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + const typename ParamGenerator::iterator begin9_; + const typename ParamGenerator::iterator end9_; + typename ParamGenerator::iterator current9_; + ParamType current_value_; + }; // class CartesianProductGenerator9::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator9& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; + const ParamGenerator g9_; +}; // class CartesianProductGenerator9 + + +template +class CartesianProductGenerator10 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator10(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8, const ParamGenerator& g9, + const ParamGenerator& g10) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9), g10_(g10) {} + virtual ~CartesianProductGenerator10() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end(), g9_, g9_.end(), g10_, g10_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8, + const ParamGenerator& g9, + const typename ParamGenerator::iterator& current9, + const ParamGenerator& g10, + const typename ParamGenerator::iterator& current10) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8), + begin9_(g9.begin()), end9_(g9.end()), current9_(current9), + begin10_(g10.begin()), end10_(g10.end()), current10_(current10) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current10_; + if (current10_ == end10_) { + current10_ = begin10_; + ++current9_; + } + if (current9_ == end9_) { + current9_ = begin9_; + ++current8_; + } + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_ && + current9_ == typed_other->current9_ && + current10_ == typed_other->current10_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_), + begin9_(other.begin9_), + end9_(other.end9_), + current9_(other.current9_), + begin10_(other.begin10_), + end10_(other.end10_), + current10_(other.current10_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_, + *current9_, *current10_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_ || + current9_ == end9_ || + current10_ == end10_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + const typename ParamGenerator::iterator begin9_; + const typename ParamGenerator::iterator end9_; + typename ParamGenerator::iterator current9_; + const typename ParamGenerator::iterator begin10_; + const typename ParamGenerator::iterator end10_; + typename ParamGenerator::iterator current10_; + ParamType current_value_; + }; // class CartesianProductGenerator10::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator10& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; + const ParamGenerator g9_; + const ParamGenerator g10_; +}; // class CartesianProductGenerator10 + + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Helper classes providing Combine() with polymorphic features. They allow +// casting CartesianProductGeneratorN to ParamGenerator if T is +// convertible to U. +// +template +class CartesianProductHolder2 { + public: +CartesianProductHolder2(const Generator1& g1, const Generator2& g2) + : g1_(g1), g2_(g2) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator2( + static_cast >(g1_), + static_cast >(g2_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder2& other); + + const Generator1 g1_; + const Generator2 g2_; +}; // class CartesianProductHolder2 + +template +class CartesianProductHolder3 { + public: +CartesianProductHolder3(const Generator1& g1, const Generator2& g2, + const Generator3& g3) + : g1_(g1), g2_(g2), g3_(g3) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator3( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder3& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; +}; // class CartesianProductHolder3 + +template +class CartesianProductHolder4 { + public: +CartesianProductHolder4(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator4( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder4& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; +}; // class CartesianProductHolder4 + +template +class CartesianProductHolder5 { + public: +CartesianProductHolder5(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator5( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder5& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; +}; // class CartesianProductHolder5 + +template +class CartesianProductHolder6 { + public: +CartesianProductHolder6(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator6( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder6& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; +}; // class CartesianProductHolder6 + +template +class CartesianProductHolder7 { + public: +CartesianProductHolder7(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator7( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder7& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; +}; // class CartesianProductHolder7 + +template +class CartesianProductHolder8 { + public: +CartesianProductHolder8(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), + g8_(g8) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator8( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder8& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; +}; // class CartesianProductHolder8 + +template +class CartesianProductHolder9 { + public: +CartesianProductHolder9(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8, + const Generator9& g9) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator9( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_), + static_cast >(g9_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder9& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; + const Generator9 g9_; +}; // class CartesianProductHolder9 + +template +class CartesianProductHolder10 { + public: +CartesianProductHolder10(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8, + const Generator9& g9, const Generator10& g10) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9), g10_(g10) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator10( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_), + static_cast >(g9_), + static_cast >(g10_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder10& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; + const Generator9 g9_; + const Generator10 g10_; +}; // class CartesianProductHolder10 + +# endif // GTEST_HAS_COMBINE + +} // namespace internal +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ diff --git a/libs/gtest/include/gtest/internal/gtest-param-util-generated.h.pump b/libs/gtest/include/gtest/internal/gtest-param-util-generated.h.pump new file mode 100644 index 000000000..dbe938630 --- /dev/null +++ b/libs/gtest/include/gtest/internal/gtest-param-util-generated.h.pump @@ -0,0 +1,301 @@ +$$ -*- mode: c++; -*- +$var n = 50 $$ Maximum length of Values arguments we want to support. +$var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) + +// Type and function utilities for implementing parameterized tests. +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently Google Test supports at most $n arguments in Values, +// and at most $maxtuple arguments in Combine. Please contact +// googletestframework@googlegroups.com if you need more. +// Please note that the number of arguments to Combine is limited +// by the maximum arity of the implementation of tr1::tuple which is +// currently set at $maxtuple. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +#include "gtest/internal/gtest-param-util.h" +#include "gtest/internal/gtest-port.h" + +#if GTEST_HAS_PARAM_TEST + +namespace testing { + +// Forward declarations of ValuesIn(), which is implemented in +// include/gtest/gtest-param-test.h. +template +internal::ParamGenerator< + typename ::testing::internal::IteratorTraits::value_type> +ValuesIn(ForwardIterator begin, ForwardIterator end); + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]); + +template +internal::ParamGenerator ValuesIn( + const Container& container); + +namespace internal { + +// Used in the Values() function to provide polymorphic capabilities. +template +class ValueArray1 { + public: + explicit ValueArray1(T1 v1) : v1_(v1) {} + + template + operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray1& other); + + const T1 v1_; +}; + +$range i 2..n +$for i [[ +$range j 1..i + +template <$for j, [[typename T$j]]> +class ValueArray$i { + public: + ValueArray$i($for j, [[T$j v$j]]) : $for j, [[v$(j)_(v$j)]] {} + + template + operator ParamGenerator() const { + const T array[] = {$for j, [[v$(j)_]]}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray$i& other); + +$for j [[ + + const T$j v$(j)_; +]] + +}; + +]] + +# if GTEST_HAS_COMBINE +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Generates values from the Cartesian product of values produced +// by the argument generators. +// +$range i 2..maxtuple +$for i [[ +$range j 1..i +$range k 2..i + +template <$for j, [[typename T$j]]> +class CartesianProductGenerator$i + : public ParamGeneratorInterface< ::std::tr1::tuple<$for j, [[T$j]]> > { + public: + typedef ::std::tr1::tuple<$for j, [[T$j]]> ParamType; + + CartesianProductGenerator$i($for j, [[const ParamGenerator& g$j]]) + : $for j, [[g$(j)_(g$j)]] {} + virtual ~CartesianProductGenerator$i() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, $for j, [[g$(j)_, g$(j)_.begin()]]); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, $for j, [[g$(j)_, g$(j)_.end()]]); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, $for j, [[ + + const ParamGenerator& g$j, + const typename ParamGenerator::iterator& current$(j)]]) + : base_(base), +$for j, [[ + + begin$(j)_(g$j.begin()), end$(j)_(g$j.end()), current$(j)_(current$j) +]] { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current$(i)_; + +$for k [[ + if (current$(i+2-k)_ == end$(i+2-k)_) { + current$(i+2-k)_ = begin$(i+2-k)_; + ++current$(i+2-k-1)_; + } + +]] + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ($for j && [[ + + current$(j)_ == typed_other->current$(j)_ +]]); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), $for j, [[ + + begin$(j)_(other.begin$(j)_), + end$(j)_(other.end$(j)_), + current$(j)_(other.current$(j)_) +]] { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType($for j, [[*current$(j)_]]); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return +$for j || [[ + + current$(j)_ == end$(j)_ +]]; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. +$for j [[ + + const typename ParamGenerator::iterator begin$(j)_; + const typename ParamGenerator::iterator end$(j)_; + typename ParamGenerator::iterator current$(j)_; +]] + + ParamType current_value_; + }; // class CartesianProductGenerator$i::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator$i& other); + + +$for j [[ + const ParamGenerator g$(j)_; + +]] +}; // class CartesianProductGenerator$i + + +]] + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Helper classes providing Combine() with polymorphic features. They allow +// casting CartesianProductGeneratorN to ParamGenerator if T is +// convertible to U. +// +$range i 2..maxtuple +$for i [[ +$range j 1..i + +template <$for j, [[class Generator$j]]> +class CartesianProductHolder$i { + public: +CartesianProductHolder$i($for j, [[const Generator$j& g$j]]) + : $for j, [[g$(j)_(g$j)]] {} + template <$for j, [[typename T$j]]> + operator ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >() const { + return ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >( + new CartesianProductGenerator$i<$for j, [[T$j]]>( +$for j,[[ + + static_cast >(g$(j)_) +]])); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder$i& other); + + +$for j [[ + const Generator$j g$(j)_; + +]] +}; // class CartesianProductHolder$i + +]] + +# endif // GTEST_HAS_COMBINE + +} // namespace internal +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ diff --git a/libs/gtest/include/gtest/internal/gtest-param-util.h b/libs/gtest/include/gtest/internal/gtest-param-util.h new file mode 100644 index 000000000..0ef9718cf --- /dev/null +++ b/libs/gtest/include/gtest/internal/gtest-param-util.h @@ -0,0 +1,619 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) + +// Type and function utilities for implementing parameterized tests. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ + +#include +#include +#include + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-linked_ptr.h" +#include "gtest/internal/gtest-port.h" +#include "gtest/gtest-printers.h" + +#if GTEST_HAS_PARAM_TEST + +namespace testing { +namespace internal { + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Outputs a message explaining invalid registration of different +// fixture class for the same test case. This may happen when +// TEST_P macro is used to define two tests with the same name +// but in different namespaces. +GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, + const char* file, int line); + +template class ParamGeneratorInterface; +template class ParamGenerator; + +// Interface for iterating over elements provided by an implementation +// of ParamGeneratorInterface. +template +class ParamIteratorInterface { + public: + virtual ~ParamIteratorInterface() {} + // A pointer to the base generator instance. + // Used only for the purposes of iterator comparison + // to make sure that two iterators belong to the same generator. + virtual const ParamGeneratorInterface* BaseGenerator() const = 0; + // Advances iterator to point to the next element + // provided by the generator. The caller is responsible + // for not calling Advance() on an iterator equal to + // BaseGenerator()->End(). + virtual void Advance() = 0; + // Clones the iterator object. Used for implementing copy semantics + // of ParamIterator. + virtual ParamIteratorInterface* Clone() const = 0; + // Dereferences the current iterator and provides (read-only) access + // to the pointed value. It is the caller's responsibility not to call + // Current() on an iterator equal to BaseGenerator()->End(). + // Used for implementing ParamGenerator::operator*(). + virtual const T* Current() const = 0; + // Determines whether the given iterator and other point to the same + // element in the sequence generated by the generator. + // Used for implementing ParamGenerator::operator==(). + virtual bool Equals(const ParamIteratorInterface& other) const = 0; +}; + +// Class iterating over elements provided by an implementation of +// ParamGeneratorInterface. It wraps ParamIteratorInterface +// and implements the const forward iterator concept. +template +class ParamIterator { + public: + typedef T value_type; + typedef const T& reference; + typedef ptrdiff_t difference_type; + + // ParamIterator assumes ownership of the impl_ pointer. + ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {} + ParamIterator& operator=(const ParamIterator& other) { + if (this != &other) + impl_.reset(other.impl_->Clone()); + return *this; + } + + const T& operator*() const { return *impl_->Current(); } + const T* operator->() const { return impl_->Current(); } + // Prefix version of operator++. + ParamIterator& operator++() { + impl_->Advance(); + return *this; + } + // Postfix version of operator++. + ParamIterator operator++(int /*unused*/) { + ParamIteratorInterface* clone = impl_->Clone(); + impl_->Advance(); + return ParamIterator(clone); + } + bool operator==(const ParamIterator& other) const { + return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_); + } + bool operator!=(const ParamIterator& other) const { + return !(*this == other); + } + + private: + friend class ParamGenerator; + explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} + scoped_ptr > impl_; +}; + +// ParamGeneratorInterface is the binary interface to access generators +// defined in other translation units. +template +class ParamGeneratorInterface { + public: + typedef T ParamType; + + virtual ~ParamGeneratorInterface() {} + + // Generator interface definition + virtual ParamIteratorInterface* Begin() const = 0; + virtual ParamIteratorInterface* End() const = 0; +}; + +// Wraps ParamGeneratorInterface and provides general generator syntax +// compatible with the STL Container concept. +// This class implements copy initialization semantics and the contained +// ParamGeneratorInterface instance is shared among all copies +// of the original object. This is possible because that instance is immutable. +template +class ParamGenerator { + public: + typedef ParamIterator iterator; + + explicit ParamGenerator(ParamGeneratorInterface* impl) : impl_(impl) {} + ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {} + + ParamGenerator& operator=(const ParamGenerator& other) { + impl_ = other.impl_; + return *this; + } + + iterator begin() const { return iterator(impl_->Begin()); } + iterator end() const { return iterator(impl_->End()); } + + private: + linked_ptr > impl_; +}; + +// Generates values from a range of two comparable values. Can be used to +// generate sequences of user-defined types that implement operator+() and +// operator<(). +// This class is used in the Range() function. +template +class RangeGenerator : public ParamGeneratorInterface { + public: + RangeGenerator(T begin, T end, IncrementT step) + : begin_(begin), end_(end), + step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} + virtual ~RangeGenerator() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, begin_, 0, step_); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, end_, end_index_, step_); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, T value, int index, + IncrementT step) + : base_(base), value_(value), index_(index), step_(step) {} + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + virtual void Advance() { + value_ = value_ + step_; + index_++; + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const T* Current() const { return &value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const int other_index = + CheckedDowncastToActualType(&other)->index_; + return index_ == other_index; + } + + private: + Iterator(const Iterator& other) + : ParamIteratorInterface(), + base_(other.base_), value_(other.value_), index_(other.index_), + step_(other.step_) {} + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + T value_; + int index_; + const IncrementT step_; + }; // class RangeGenerator::Iterator + + static int CalculateEndIndex(const T& begin, + const T& end, + const IncrementT& step) { + int end_index = 0; + for (T i = begin; i < end; i = i + step) + end_index++; + return end_index; + } + + // No implementation - assignment is unsupported. + void operator=(const RangeGenerator& other); + + const T begin_; + const T end_; + const IncrementT step_; + // The index for the end() iterator. All the elements in the generated + // sequence are indexed (0-based) to aid iterator comparison. + const int end_index_; +}; // class RangeGenerator + + +// Generates values from a pair of STL-style iterators. Used in the +// ValuesIn() function. The elements are copied from the source range +// since the source can be located on the stack, and the generator +// is likely to persist beyond that stack frame. +template +class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { + public: + template + ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) + : container_(begin, end) {} + virtual ~ValuesInIteratorRangeGenerator() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, container_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, container_.end()); + } + + private: + typedef typename ::std::vector ContainerType; + + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + typename ContainerType::const_iterator iterator) + : base_(base), iterator_(iterator) {} + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + virtual void Advance() { + ++iterator_; + value_.reset(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + // We need to use cached value referenced by iterator_ because *iterator_ + // can return a temporary object (and of type other then T), so just + // having "return &*iterator_;" doesn't work. + // value_ is updated here and not in Advance() because Advance() + // can advance iterator_ beyond the end of the range, and we cannot + // detect that fact. The client code, on the other hand, is + // responsible for not calling Current() on an out-of-range iterator. + virtual const T* Current() const { + if (value_.get() == NULL) + value_.reset(new T(*iterator_)); + return value_.get(); + } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + return iterator_ == + CheckedDowncastToActualType(&other)->iterator_; + } + + private: + Iterator(const Iterator& other) + // The explicit constructor call suppresses a false warning + // emitted by gcc when supplied with the -Wextra option. + : ParamIteratorInterface(), + base_(other.base_), + iterator_(other.iterator_) {} + + const ParamGeneratorInterface* const base_; + typename ContainerType::const_iterator iterator_; + // A cached value of *iterator_. We keep it here to allow access by + // pointer in the wrapping iterator's operator->(). + // value_ needs to be mutable to be accessed in Current(). + // Use of scoped_ptr helps manage cached value's lifetime, + // which is bound by the lifespan of the iterator itself. + mutable scoped_ptr value_; + }; // class ValuesInIteratorRangeGenerator::Iterator + + // No implementation - assignment is unsupported. + void operator=(const ValuesInIteratorRangeGenerator& other); + + const ContainerType container_; +}; // class ValuesInIteratorRangeGenerator + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Stores a parameter value and later creates tests parameterized with that +// value. +template +class ParameterizedTestFactory : public TestFactoryBase { + public: + typedef typename TestClass::ParamType ParamType; + explicit ParameterizedTestFactory(ParamType parameter) : + parameter_(parameter) {} + virtual Test* CreateTest() { + TestClass::SetParam(¶meter_); + return new TestClass(); + } + + private: + const ParamType parameter_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// TestMetaFactoryBase is a base class for meta-factories that create +// test factories for passing into MakeAndRegisterTestInfo function. +template +class TestMetaFactoryBase { + public: + virtual ~TestMetaFactoryBase() {} + + virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0; +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// TestMetaFactory creates test factories for passing into +// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives +// ownership of test factory pointer, same factory object cannot be passed +// into that method twice. But ParameterizedTestCaseInfo is going to call +// it for each Test/Parameter value combination. Thus it needs meta factory +// creator class. +template +class TestMetaFactory + : public TestMetaFactoryBase { + public: + typedef typename TestCase::ParamType ParamType; + + TestMetaFactory() {} + + virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { + return new ParameterizedTestFactory(parameter); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseInfoBase is a generic interface +// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase +// accumulates test information provided by TEST_P macro invocations +// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations +// and uses that information to register all resulting test instances +// in RegisterTests method. The ParameterizeTestCaseRegistry class holds +// a collection of pointers to the ParameterizedTestCaseInfo objects +// and calls RegisterTests() on each of them when asked. +class ParameterizedTestCaseInfoBase { + public: + virtual ~ParameterizedTestCaseInfoBase() {} + + // Base part of test case name for display purposes. + virtual const string& GetTestCaseName() const = 0; + // Test case id to verify identity. + virtual TypeId GetTestCaseTypeId() const = 0; + // UnitTest class invokes this method to register tests in this + // test case right before running them in RUN_ALL_TESTS macro. + // This method should not be called more then once on any single + // instance of a ParameterizedTestCaseInfoBase derived class. + virtual void RegisterTests() = 0; + + protected: + ParameterizedTestCaseInfoBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P +// macro invocations for a particular test case and generators +// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that +// test case. It registers tests with all values generated by all +// generators when asked. +template +class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { + public: + // ParamType and GeneratorCreationFunc are private types but are required + // for declarations of public methods AddTestPattern() and + // AddTestCaseInstantiation(). + typedef typename TestCase::ParamType ParamType; + // A function that returns an instance of appropriate generator type. + typedef ParamGenerator(GeneratorCreationFunc)(); + + explicit ParameterizedTestCaseInfo(const char* name) + : test_case_name_(name) {} + + // Test case base name for display purposes. + virtual const string& GetTestCaseName() const { return test_case_name_; } + // Test case id to verify identity. + virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } + // TEST_P macro uses AddTestPattern() to record information + // about a single test in a LocalTestInfo structure. + // test_case_name is the base name of the test case (without invocation + // prefix). test_base_name is the name of an individual test without + // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is + // test case base name and DoBar is test base name. + void AddTestPattern(const char* test_case_name, + const char* test_base_name, + TestMetaFactoryBase* meta_factory) { + tests_.push_back(linked_ptr(new TestInfo(test_case_name, + test_base_name, + meta_factory))); + } + // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information + // about a generator. + int AddTestCaseInstantiation(const string& instantiation_name, + GeneratorCreationFunc* func, + const char* /* file */, + int /* line */) { + instantiations_.push_back(::std::make_pair(instantiation_name, func)); + return 0; // Return value used only to run this method in namespace scope. + } + // UnitTest class invokes this method to register tests in this test case + // test cases right before running tests in RUN_ALL_TESTS macro. + // This method should not be called more then once on any single + // instance of a ParameterizedTestCaseInfoBase derived class. + // UnitTest has a guard to prevent from calling this method more then once. + virtual void RegisterTests() { + for (typename TestInfoContainer::iterator test_it = tests_.begin(); + test_it != tests_.end(); ++test_it) { + linked_ptr test_info = *test_it; + for (typename InstantiationContainer::iterator gen_it = + instantiations_.begin(); gen_it != instantiations_.end(); + ++gen_it) { + const string& instantiation_name = gen_it->first; + ParamGenerator generator((*gen_it->second)()); + + Message test_case_name_stream; + if ( !instantiation_name.empty() ) + test_case_name_stream << instantiation_name << "/"; + test_case_name_stream << test_info->test_case_base_name; + + int i = 0; + for (typename ParamGenerator::iterator param_it = + generator.begin(); + param_it != generator.end(); ++param_it, ++i) { + Message test_name_stream; + test_name_stream << test_info->test_base_name << "/" << i; + MakeAndRegisterTestInfo( + test_case_name_stream.GetString().c_str(), + test_name_stream.GetString().c_str(), + NULL, // No type parameter. + PrintToString(*param_it).c_str(), + GetTestCaseTypeId(), + TestCase::SetUpTestCase, + TestCase::TearDownTestCase, + test_info->test_meta_factory->CreateTestFactory(*param_it)); + } // for param_it + } // for gen_it + } // for test_it + } // RegisterTests + + private: + // LocalTestInfo structure keeps information about a single test registered + // with TEST_P macro. + struct TestInfo { + TestInfo(const char* a_test_case_base_name, + const char* a_test_base_name, + TestMetaFactoryBase* a_test_meta_factory) : + test_case_base_name(a_test_case_base_name), + test_base_name(a_test_base_name), + test_meta_factory(a_test_meta_factory) {} + + const string test_case_base_name; + const string test_base_name; + const scoped_ptr > test_meta_factory; + }; + typedef ::std::vector > TestInfoContainer; + // Keeps pairs of + // received from INSTANTIATE_TEST_CASE_P macros. + typedef ::std::vector > + InstantiationContainer; + + const string test_case_name_; + TestInfoContainer tests_; + InstantiationContainer instantiations_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo); +}; // class ParameterizedTestCaseInfo + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase +// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P +// macros use it to locate their corresponding ParameterizedTestCaseInfo +// descriptors. +class ParameterizedTestCaseRegistry { + public: + ParameterizedTestCaseRegistry() {} + ~ParameterizedTestCaseRegistry() { + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + delete *it; + } + } + + // Looks up or creates and returns a structure containing information about + // tests and instantiations of a particular test case. + template + ParameterizedTestCaseInfo* GetTestCasePatternHolder( + const char* test_case_name, + const char* file, + int line) { + ParameterizedTestCaseInfo* typed_test_info = NULL; + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + if ((*it)->GetTestCaseName() == test_case_name) { + if ((*it)->GetTestCaseTypeId() != GetTypeId()) { + // Complain about incorrect usage of Google Test facilities + // and terminate the program since we cannot guaranty correct + // test case setup and tear-down in this case. + ReportInvalidTestCaseType(test_case_name, file, line); + posix::Abort(); + } else { + // At this point we are sure that the object we found is of the same + // type we are looking for, so we downcast it to that type + // without further checks. + typed_test_info = CheckedDowncastToActualType< + ParameterizedTestCaseInfo >(*it); + } + break; + } + } + if (typed_test_info == NULL) { + typed_test_info = new ParameterizedTestCaseInfo(test_case_name); + test_case_infos_.push_back(typed_test_info); + } + return typed_test_info; + } + void RegisterTests() { + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + (*it)->RegisterTests(); + } + } + + private: + typedef ::std::vector TestCaseInfoContainer; + + TestCaseInfoContainer test_case_infos_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); +}; + +} // namespace internal +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ diff --git a/libs/gtest/include/gtest/internal/gtest-port.h b/libs/gtest/include/gtest/internal/gtest-port.h new file mode 100644 index 000000000..157b47f86 --- /dev/null +++ b/libs/gtest/include/gtest/internal/gtest-port.h @@ -0,0 +1,1775 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan) +// +// Low-level types and utilities for porting Google Test to various +// platforms. They are subject to change without notice. DO NOT USE +// THEM IN USER CODE. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ + +// The user can define the following macros in the build script to +// control Google Test's behavior. If the user doesn't define a macro +// in this list, Google Test will define it. +// +// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) +// is/isn't available. +// GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions +// are enabled. +// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string +// is/isn't available (some systems define +// ::string, which is different to std::string). +// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string +// is/isn't available (some systems define +// ::wstring, which is different to std::wstring). +// GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular +// expressions are/aren't available. +// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that +// is/isn't available. +// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't +// enabled. +// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that +// std::wstring does/doesn't work (Google Test can +// be used where std::wstring is unavailable). +// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple +// is/isn't available. +// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the +// compiler supports Microsoft's "Structured +// Exception Handling". +// GTEST_HAS_STREAM_REDIRECTION +// - Define it to 1/0 to indicate whether the +// platform supports I/O stream redirection using +// dup() and dup2(). +// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google +// Test's own tr1 tuple implementation should be +// used. Unused when the user sets +// GTEST_HAS_TR1_TUPLE to 0. +// GTEST_LINKED_AS_SHARED_LIBRARY +// - Define to 1 when compiling tests that use +// Google Test as a shared library (known as +// DLL on Windows). +// GTEST_CREATE_SHARED_LIBRARY +// - Define to 1 when compiling Google Test itself +// as a shared library. + +// This header defines the following utilities: +// +// Macros indicating the current platform (defined to 1 if compiled on +// the given platform; otherwise undefined): +// GTEST_OS_AIX - IBM AIX +// GTEST_OS_CYGWIN - Cygwin +// GTEST_OS_HPUX - HP-UX +// GTEST_OS_LINUX - Linux +// GTEST_OS_LINUX_ANDROID - Google Android +// GTEST_OS_MAC - Mac OS X +// GTEST_OS_NACL - Google Native Client (NaCl) +// GTEST_OS_SOLARIS - Sun Solaris +// GTEST_OS_SYMBIAN - Symbian +// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) +// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop +// GTEST_OS_WINDOWS_MINGW - MinGW +// GTEST_OS_WINDOWS_MOBILE - Windows Mobile +// GTEST_OS_ZOS - z/OS +// +// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the +// most stable support. Since core members of the Google Test project +// don't have access to other platforms, support for them may be less +// stable. If you notice any problems on your platform, please notify +// googletestframework@googlegroups.com (patches for fixing them are +// even more welcome!). +// +// Note that it is possible that none of the GTEST_OS_* macros are defined. +// +// Macros indicating available Google Test features (defined to 1 if +// the corresponding feature is supported; otherwise undefined): +// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized +// tests) +// GTEST_HAS_DEATH_TEST - death tests +// GTEST_HAS_PARAM_TEST - value-parameterized tests +// GTEST_HAS_TYPED_TEST - typed tests +// GTEST_HAS_TYPED_TEST_P - type-parameterized tests +// GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with +// GTEST_HAS_POSIX_RE (see above) which users can +// define themselves. +// GTEST_USES_SIMPLE_RE - our own simple regex is used; +// the above two are mutually exclusive. +// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). +// +// Macros for basic C++ coding: +// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. +// GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a +// variable don't have to be used. +// GTEST_DISALLOW_ASSIGN_ - disables operator=. +// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. +// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. +// +// Synchronization: +// Mutex, MutexLock, ThreadLocal, GetThreadCount() +// - synchronization primitives. +// GTEST_IS_THREADSAFE - defined to 1 to indicate that the above +// synchronization primitives have real implementations +// and Google Test is thread-safe; or 0 otherwise. +// +// Template meta programming: +// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. +// IteratorTraits - partial implementation of std::iterator_traits, which +// is not available in libCstd when compiled with Sun C++. +// +// Smart pointers: +// scoped_ptr - as in TR2. +// +// Regular expressions: +// RE - a simple regular expression class using the POSIX +// Extended Regular Expression syntax on UNIX-like +// platforms, or a reduced regular exception syntax on +// other platforms, including Windows. +// +// Logging: +// GTEST_LOG_() - logs messages at the specified severity level. +// LogToStderr() - directs all log messages to stderr. +// FlushInfoLog() - flushes informational log messages. +// +// Stdout and stderr capturing: +// CaptureStdout() - starts capturing stdout. +// GetCapturedStdout() - stops capturing stdout and returns the captured +// string. +// CaptureStderr() - starts capturing stderr. +// GetCapturedStderr() - stops capturing stderr and returns the captured +// string. +// +// Integer types: +// TypeWithSize - maps an integer to a int type. +// Int32, UInt32, Int64, UInt64, TimeInMillis +// - integers of known sizes. +// BiggestInt - the biggest signed integer type. +// +// Command-line utilities: +// GTEST_FLAG() - references a flag. +// GTEST_DECLARE_*() - declares a flag. +// GTEST_DEFINE_*() - defines a flag. +// GetArgvs() - returns the command line as a vector of strings. +// +// Environment variable utilities: +// GetEnv() - gets the value of an environment variable. +// BoolFromGTestEnv() - parses a bool environment variable. +// Int32FromGTestEnv() - parses an Int32 environment variable. +// StringFromGTestEnv() - parses a string environment variable. + +#include // for isspace, etc +#include // for ptrdiff_t +#include +#include +#include +#ifndef _WIN32_WCE +# include +# include +#endif // !_WIN32_WCE + +#include // NOLINT +#include // NOLINT +#include // NOLINT + +#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" +#define GTEST_FLAG_PREFIX_ "gtest_" +#define GTEST_FLAG_PREFIX_DASH_ "gtest-" +#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" +#define GTEST_NAME_ "Google Test" +#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" + +// Determines the version of gcc that is used to compile this. +#ifdef __GNUC__ +// 40302 means version 4.3.2. +# define GTEST_GCC_VER_ \ + (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) +#endif // __GNUC__ + +// Determines the platform on which Google Test is compiled. +#ifdef __CYGWIN__ +# define GTEST_OS_CYGWIN 1 +#elif defined __SYMBIAN32__ +# define GTEST_OS_SYMBIAN 1 +#elif defined _WIN32 +# define GTEST_OS_WINDOWS 1 +# ifdef _WIN32_WCE +# define GTEST_OS_WINDOWS_MOBILE 1 +# elif defined(__MINGW__) || defined(__MINGW32__) +# define GTEST_OS_WINDOWS_MINGW 1 +# else +# define GTEST_OS_WINDOWS_DESKTOP 1 +# endif // _WIN32_WCE +#elif defined __APPLE__ +# define GTEST_OS_MAC 1 +#elif defined __linux__ +# define GTEST_OS_LINUX 1 +# ifdef ANDROID +# define GTEST_OS_LINUX_ANDROID 1 +# endif // ANDROID +#elif defined __MVS__ +# define GTEST_OS_ZOS 1 +#elif defined(__sun) && defined(__SVR4) +# define GTEST_OS_SOLARIS 1 +#elif defined(_AIX) +# define GTEST_OS_AIX 1 +#elif defined(__hpux) +# define GTEST_OS_HPUX 1 +#elif defined __native_client__ +# define GTEST_OS_NACL 1 +#endif // __CYGWIN__ + +// Brings in definitions for functions used in the testing::internal::posix +// namespace (read, write, close, chdir, isatty, stat). We do not currently +// use them on Windows Mobile. +#if !GTEST_OS_WINDOWS +// This assumes that non-Windows OSes provide unistd.h. For OSes where this +// is not the case, we need to include headers that provide the functions +// mentioned above. +# include +# if !GTEST_OS_NACL +// TODO(vladl@google.com): Remove this condition when Native Client SDK adds +// strings.h (tracked in +// http://code.google.com/p/nativeclient/issues/detail?id=1175). +# include // Native Client doesn't provide strings.h. +# endif +#elif !GTEST_OS_WINDOWS_MOBILE +# include +# include +#endif + +// Defines this to true iff Google Test can use POSIX regular expressions. +#ifndef GTEST_HAS_POSIX_RE +# define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) +#endif + +#if GTEST_HAS_POSIX_RE + +// On some platforms, needs someone to define size_t, and +// won't compile otherwise. We can #include it here as we already +// included , which is guaranteed to define size_t through +// . +# include // NOLINT + +# define GTEST_USES_POSIX_RE 1 + +#elif GTEST_OS_WINDOWS + +// is not available on Windows. Use our own simple regex +// implementation instead. +# define GTEST_USES_SIMPLE_RE 1 + +#else + +// may not be available on this platform. Use our own +// simple regex implementation instead. +# define GTEST_USES_SIMPLE_RE 1 + +#endif // GTEST_HAS_POSIX_RE + +#ifndef GTEST_HAS_EXCEPTIONS +// The user didn't tell us whether exceptions are enabled, so we need +// to figure it out. +# if defined(_MSC_VER) || defined(__BORLANDC__) +// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS +// macro to enable exceptions, so we'll do the same. +// Assumes that exceptions are enabled by default. +# ifndef _HAS_EXCEPTIONS +# define _HAS_EXCEPTIONS 1 +# endif // _HAS_EXCEPTIONS +# define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS +# elif defined(__GNUC__) && __EXCEPTIONS +// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__SUNPRO_CC) +// Sun Pro CC supports exceptions. However, there is no compile-time way of +// detecting whether they are enabled or not. Therefore, we assume that +// they are enabled unless the user tells us otherwise. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__IBMCPP__) && __EXCEPTIONS +// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__HP_aCC) +// Exception handling is in effect by default in HP aCC compiler. It has to +// be turned of by +noeh compiler option if desired. +# define GTEST_HAS_EXCEPTIONS 1 +# else +// For other compilers, we assume exceptions are disabled to be +// conservative. +# define GTEST_HAS_EXCEPTIONS 0 +# endif // defined(_MSC_VER) || defined(__BORLANDC__) +#endif // GTEST_HAS_EXCEPTIONS + +#if !defined(GTEST_HAS_STD_STRING) +// Even though we don't use this macro any longer, we keep it in case +// some clients still depend on it. +# define GTEST_HAS_STD_STRING 1 +#elif !GTEST_HAS_STD_STRING +// The user told us that ::std::string isn't available. +# error "Google Test cannot be used where ::std::string isn't available." +#endif // !defined(GTEST_HAS_STD_STRING) + +#ifndef GTEST_HAS_GLOBAL_STRING +// The user didn't tell us whether ::string is available, so we need +// to figure it out. + +# define GTEST_HAS_GLOBAL_STRING 0 + +#endif // GTEST_HAS_GLOBAL_STRING + +#ifndef GTEST_HAS_STD_WSTRING +// The user didn't tell us whether ::std::wstring is available, so we need +// to figure it out. +// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring +// is available. + +// Cygwin 1.7 and below doesn't support ::std::wstring. +// Solaris' libc++ doesn't support it either. Android has +// no support for it at least as recent as Froyo (2.2). +# define GTEST_HAS_STD_WSTRING \ + (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) + +#endif // GTEST_HAS_STD_WSTRING + +#ifndef GTEST_HAS_GLOBAL_WSTRING +// The user didn't tell us whether ::wstring is available, so we need +// to figure it out. +# define GTEST_HAS_GLOBAL_WSTRING \ + (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) +#endif // GTEST_HAS_GLOBAL_WSTRING + +// Determines whether RTTI is available. +#ifndef GTEST_HAS_RTTI +// The user didn't tell us whether RTTI is enabled, so we need to +// figure it out. + +# ifdef _MSC_VER + +# ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. +# define GTEST_HAS_RTTI 1 +# else +# define GTEST_HAS_RTTI 0 +# endif + +// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. +# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) + +# ifdef __GXX_RTTI +# define GTEST_HAS_RTTI 1 +# else +# define GTEST_HAS_RTTI 0 +# endif // __GXX_RTTI + +// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if +// both the typeid and dynamic_cast features are present. +# elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) + +# ifdef __RTTI_ALL__ +# define GTEST_HAS_RTTI 1 +# else +# define GTEST_HAS_RTTI 0 +# endif + +# else + +// For all other compilers, we assume RTTI is enabled. +# define GTEST_HAS_RTTI 1 + +# endif // _MSC_VER + +#endif // GTEST_HAS_RTTI + +// It's this header's responsibility to #include when RTTI +// is enabled. +#if GTEST_HAS_RTTI +# include +#endif + +// Determines whether Google Test can use the pthreads library. +#ifndef GTEST_HAS_PTHREAD +// The user didn't tell us explicitly, so we assume pthreads support is +// available on Linux and Mac. +// +// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 +// to your compiler flags. +# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX) +#endif // GTEST_HAS_PTHREAD + +#if GTEST_HAS_PTHREAD +// gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is +// true. +# include // NOLINT + +// For timespec and nanosleep, used below. +# include // NOLINT +#endif + +// Determines whether Google Test can use tr1/tuple. You can define +// this macro to 0 to prevent Google Test from using tuple (any +// feature depending on tuple with be disabled in this mode). +#ifndef GTEST_HAS_TR1_TUPLE +// The user didn't tell us not to do it, so we assume it's OK. +# define GTEST_HAS_TR1_TUPLE 1 +#endif // GTEST_HAS_TR1_TUPLE + +// Determines whether Google Test's own tr1 tuple implementation +// should be used. +#ifndef GTEST_USE_OWN_TR1_TUPLE +// The user didn't tell us, so we need to figure it out. + +// We use our own TR1 tuple if we aren't sure the user has an +// implementation of it already. At this time, GCC 4.0.0+ and MSVC +// 2010 are the only mainstream compilers that come with a TR1 tuple +// implementation. NVIDIA's CUDA NVCC compiler pretends to be GCC by +// defining __GNUC__ and friends, but cannot compile GCC's tuple +// implementation. MSVC 2008 (9.0) provides TR1 tuple in a 323 MB +// Feature Pack download, which we cannot assume the user has. +# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000)) \ + || _MSC_VER >= 1600 +# define GTEST_USE_OWN_TR1_TUPLE 0 +# else +# define GTEST_USE_OWN_TR1_TUPLE 1 +# endif + +#endif // GTEST_USE_OWN_TR1_TUPLE + +// To avoid conditional compilation everywhere, we make it +// gtest-port.h's responsibility to #include the header implementing +// tr1/tuple. +#if GTEST_HAS_TR1_TUPLE + +# if GTEST_USE_OWN_TR1_TUPLE +# include "gtest/internal/gtest-tuple.h" +# elif GTEST_OS_SYMBIAN + +// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to +// use STLport's tuple implementation, which unfortunately doesn't +// work as the copy of STLport distributed with Symbian is incomplete. +// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to +// use its own tuple implementation. +# ifdef BOOST_HAS_TR1_TUPLE +# undef BOOST_HAS_TR1_TUPLE +# endif // BOOST_HAS_TR1_TUPLE + +// This prevents , which defines +// BOOST_HAS_TR1_TUPLE, from being #included by Boost's . +# define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED +# include + +# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) +// GCC 4.0+ implements tr1/tuple in the header. This does +// not conform to the TR1 spec, which requires the header to be . + +# if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 +// Until version 4.3.2, gcc has a bug that causes , +// which is #included by , to not compile when RTTI is +// disabled. _TR1_FUNCTIONAL is the header guard for +// . Hence the following #define is a hack to prevent +// from being included. +# define _TR1_FUNCTIONAL 1 +# include +# undef _TR1_FUNCTIONAL // Allows the user to #include + // if he chooses to. +# else +# include // NOLINT +# endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 + +# else +// If the compiler is not GCC 4.0+, we assume the user is using a +// spec-conforming TR1 implementation. +# include // NOLINT +# endif // GTEST_USE_OWN_TR1_TUPLE + +#endif // GTEST_HAS_TR1_TUPLE + +// Determines whether clone(2) is supported. +// Usually it will only be available on Linux, excluding +// Linux on the Itanium architecture. +// Also see http://linux.die.net/man/2/clone. +#ifndef GTEST_HAS_CLONE +// The user didn't tell us, so we need to figure it out. + +# if GTEST_OS_LINUX && !defined(__ia64__) +# define GTEST_HAS_CLONE 1 +# else +# define GTEST_HAS_CLONE 0 +# endif // GTEST_OS_LINUX && !defined(__ia64__) + +#endif // GTEST_HAS_CLONE + +// Determines whether to support stream redirection. This is used to test +// output correctness and to implement death tests. +#ifndef GTEST_HAS_STREAM_REDIRECTION +// By default, we assume that stream redirection is supported on all +// platforms except known mobile ones. +# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN +# define GTEST_HAS_STREAM_REDIRECTION 0 +# else +# define GTEST_HAS_STREAM_REDIRECTION 1 +# endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN +#endif // GTEST_HAS_STREAM_REDIRECTION + +// Determines whether to support death tests. +// Google Test does not support death tests for VC 7.1 and earlier as +// abort() in a VC 7.1 application compiled as GUI in debug config +// pops up a dialog window that cannot be suppressed programmatically. +#if (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ + GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX) +# define GTEST_HAS_DEATH_TEST 1 +# include // NOLINT +#endif + +// We don't support MSVC 7.1 with exceptions disabled now. Therefore +// all the compilers we care about are adequate for supporting +// value-parameterized tests. +#define GTEST_HAS_PARAM_TEST 1 + +// Determines whether to support type-driven tests. + +// Typed tests need and variadic macros, which GCC, VC++ 8.0, +// Sun Pro CC, IBM Visual Age, and HP aCC support. +#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ + defined(__IBMCPP__) || defined(__HP_aCC) +# define GTEST_HAS_TYPED_TEST 1 +# define GTEST_HAS_TYPED_TEST_P 1 +#endif + +// Determines whether to support Combine(). This only makes sense when +// value-parameterized tests are enabled. The implementation doesn't +// work on Sun Studio since it doesn't understand templated conversion +// operators. +#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) +# define GTEST_HAS_COMBINE 1 +#endif + +// Determines whether the system compiler uses UTF-16 for encoding wide strings. +#define GTEST_WIDE_STRING_USES_UTF16_ \ + (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) + +// Determines whether test results can be streamed to a socket. +#if GTEST_OS_LINUX +# define GTEST_CAN_STREAM_RESULTS_ 1 +#endif + +// Defines some utility macros. + +// The GNU compiler emits a warning if nested "if" statements are followed by +// an "else" statement and braces are not used to explicitly disambiguate the +// "else" binding. This leads to problems with code like: +// +// if (gate) +// ASSERT_*(condition) << "Some message"; +// +// The "switch (0) case 0:" idiom is used to suppress this. +#ifdef __INTEL_COMPILER +# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ +#else +# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default: // NOLINT +#endif + +// Use this annotation at the end of a struct/class definition to +// prevent the compiler from optimizing away instances that are never +// used. This is useful when all interesting logic happens inside the +// c'tor and / or d'tor. Example: +// +// struct Foo { +// Foo() { ... } +// } GTEST_ATTRIBUTE_UNUSED_; +// +// Also use it after a variable or parameter declaration to tell the +// compiler the variable/parameter does not have to be used. +#if defined(__GNUC__) && !defined(COMPILER_ICC) +# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) +#else +# define GTEST_ATTRIBUTE_UNUSED_ +#endif + +// A macro to disallow operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_ASSIGN_(type)\ + void operator=(type const &) + +// A macro to disallow copy constructor and operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ + type(type const &);\ + GTEST_DISALLOW_ASSIGN_(type) + +// Tell the compiler to warn about unused return values for functions declared +// with this macro. The macro should be used on function declarations +// following the argument list: +// +// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; +#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) +# define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) +#else +# define GTEST_MUST_USE_RESULT_ +#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC + +// Determine whether the compiler supports Microsoft's Structured Exception +// Handling. This is supported by several Windows compilers but generally +// does not exist on any other system. +#ifndef GTEST_HAS_SEH +// The user didn't tell us, so we need to figure it out. + +# if defined(_MSC_VER) || defined(__BORLANDC__) +// These two compilers are known to support SEH. +# define GTEST_HAS_SEH 1 +# else +// Assume no SEH. +# define GTEST_HAS_SEH 0 +# endif + +#endif // GTEST_HAS_SEH + +#ifdef _MSC_VER + +# if GTEST_LINKED_AS_SHARED_LIBRARY +# define GTEST_API_ __declspec(dllimport) +# elif GTEST_CREATE_SHARED_LIBRARY +# define GTEST_API_ __declspec(dllexport) +# endif + +#endif // _MSC_VER + +#ifndef GTEST_API_ +# define GTEST_API_ +#endif + +#ifdef __GNUC__ +// Ask the compiler to never inline a given function. +# define GTEST_NO_INLINE_ __attribute__((noinline)) +#else +# define GTEST_NO_INLINE_ +#endif + +namespace testing { + +class Message; + +namespace internal { + +class String; + +// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time +// expression is true. For example, you could use it to verify the +// size of a static array: +// +// GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, +// content_type_names_incorrect_size); +// +// or to make sure a struct is smaller than a certain size: +// +// GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); +// +// The second argument to the macro is the name of the variable. If +// the expression is false, most compilers will issue a warning/error +// containing the name of the variable. + +template +struct CompileAssert { +}; + +#define GTEST_COMPILE_ASSERT_(expr, msg) \ + typedef ::testing::internal::CompileAssert<(bool(expr))> \ + msg[bool(expr) ? 1 : -1] + +// Implementation details of GTEST_COMPILE_ASSERT_: +// +// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1 +// elements (and thus is invalid) when the expression is false. +// +// - The simpler definition +// +// #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] +// +// does not work, as gcc supports variable-length arrays whose sizes +// are determined at run-time (this is gcc's extension and not part +// of the C++ standard). As a result, gcc fails to reject the +// following code with the simple definition: +// +// int foo; +// GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is +// // not a compile-time constant. +// +// - By using the type CompileAssert<(bool(expr))>, we ensures that +// expr is a compile-time constant. (Template arguments must be +// determined at compile-time.) +// +// - The outter parentheses in CompileAssert<(bool(expr))> are necessary +// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written +// +// CompileAssert +// +// instead, these compilers will refuse to compile +// +// GTEST_COMPILE_ASSERT_(5 > 0, some_message); +// +// (They seem to think the ">" in "5 > 0" marks the end of the +// template argument list.) +// +// - The array size is (bool(expr) ? 1 : -1), instead of simply +// +// ((expr) ? 1 : -1). +// +// This is to avoid running into a bug in MS VC 7.1, which +// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. + +// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h. +// +// This template is declared, but intentionally undefined. +template +struct StaticAssertTypeEqHelper; + +template +struct StaticAssertTypeEqHelper {}; + +#if GTEST_HAS_GLOBAL_STRING +typedef ::string string; +#else +typedef ::std::string string; +#endif // GTEST_HAS_GLOBAL_STRING + +#if GTEST_HAS_GLOBAL_WSTRING +typedef ::wstring wstring; +#elif GTEST_HAS_STD_WSTRING +typedef ::std::wstring wstring; +#endif // GTEST_HAS_GLOBAL_WSTRING + +// A helper for suppressing warnings on constant condition. It just +// returns 'condition'. +GTEST_API_ bool IsTrue(bool condition); + +// Defines scoped_ptr. + +// This implementation of scoped_ptr is PARTIAL - it only contains +// enough stuff to satisfy Google Test's need. +template +class scoped_ptr { + public: + typedef T element_type; + + explicit scoped_ptr(T* p = NULL) : ptr_(p) {} + ~scoped_ptr() { reset(); } + + T& operator*() const { return *ptr_; } + T* operator->() const { return ptr_; } + T* get() const { return ptr_; } + + T* release() { + T* const ptr = ptr_; + ptr_ = NULL; + return ptr; + } + + void reset(T* p = NULL) { + if (p != ptr_) { + if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. + delete ptr_; + } + ptr_ = p; + } + } + private: + T* ptr_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); +}; + +// Defines RE. + +// A simple C++ wrapper for . It uses the POSIX Extended +// Regular Expression syntax. +class GTEST_API_ RE { + public: + // A copy constructor is required by the Standard to initialize object + // references from r-values. + RE(const RE& other) { Init(other.pattern()); } + + // Constructs an RE from a string. + RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT + +#if GTEST_HAS_GLOBAL_STRING + + RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT + +#endif // GTEST_HAS_GLOBAL_STRING + + RE(const char* regex) { Init(regex); } // NOLINT + ~RE(); + + // Returns the string representation of the regex. + const char* pattern() const { return pattern_; } + + // FullMatch(str, re) returns true iff regular expression re matches + // the entire str. + // PartialMatch(str, re) returns true iff regular expression re + // matches a substring of str (including str itself). + // + // TODO(wan@google.com): make FullMatch() and PartialMatch() work + // when str contains NUL characters. + static bool FullMatch(const ::std::string& str, const RE& re) { + return FullMatch(str.c_str(), re); + } + static bool PartialMatch(const ::std::string& str, const RE& re) { + return PartialMatch(str.c_str(), re); + } + +#if GTEST_HAS_GLOBAL_STRING + + static bool FullMatch(const ::string& str, const RE& re) { + return FullMatch(str.c_str(), re); + } + static bool PartialMatch(const ::string& str, const RE& re) { + return PartialMatch(str.c_str(), re); + } + +#endif // GTEST_HAS_GLOBAL_STRING + + static bool FullMatch(const char* str, const RE& re); + static bool PartialMatch(const char* str, const RE& re); + + private: + void Init(const char* regex); + + // We use a const char* instead of a string, as Google Test may be used + // where string is not available. We also do not use Google Test's own + // String type here, in order to simplify dependencies between the + // files. + const char* pattern_; + bool is_valid_; + +#if GTEST_USES_POSIX_RE + + regex_t full_regex_; // For FullMatch(). + regex_t partial_regex_; // For PartialMatch(). + +#else // GTEST_USES_SIMPLE_RE + + const char* full_pattern_; // For FullMatch(); + +#endif + + GTEST_DISALLOW_ASSIGN_(RE); +}; + +// Formats a source file path and a line number as they would appear +// in an error message from the compiler used to compile this code. +GTEST_API_ ::std::string FormatFileLocation(const char* file, int line); + +// Formats a file location for compiler-independent XML output. +// Although this function is not platform dependent, we put it next to +// FormatFileLocation in order to contrast the two functions. +GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file, + int line); + +// Defines logging utilities: +// GTEST_LOG_(severity) - logs messages at the specified severity level. The +// message itself is streamed into the macro. +// LogToStderr() - directs all log messages to stderr. +// FlushInfoLog() - flushes informational log messages. + +enum GTestLogSeverity { + GTEST_INFO, + GTEST_WARNING, + GTEST_ERROR, + GTEST_FATAL +}; + +// Formats log entry severity, provides a stream object for streaming the +// log message, and terminates the message with a newline when going out of +// scope. +class GTEST_API_ GTestLog { + public: + GTestLog(GTestLogSeverity severity, const char* file, int line); + + // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. + ~GTestLog(); + + ::std::ostream& GetStream() { return ::std::cerr; } + + private: + const GTestLogSeverity severity_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); +}; + +#define GTEST_LOG_(severity) \ + ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ + __FILE__, __LINE__).GetStream() + +inline void LogToStderr() {} +inline void FlushInfoLog() { fflush(NULL); } + +// INTERNAL IMPLEMENTATION - DO NOT USE. +// +// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition +// is not satisfied. +// Synopsys: +// GTEST_CHECK_(boolean_condition); +// or +// GTEST_CHECK_(boolean_condition) << "Additional message"; +// +// This checks the condition and if the condition is not satisfied +// it prints message about the condition violation, including the +// condition itself, plus additional message streamed into it, if any, +// and then it aborts the program. It aborts the program irrespective of +// whether it is built in the debug mode or not. +#define GTEST_CHECK_(condition) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::IsTrue(condition)) \ + ; \ + else \ + GTEST_LOG_(FATAL) << "Condition " #condition " failed. " + +// An all-mode assert to verify that the given POSIX-style function +// call returns 0 (indicating success). Known limitation: this +// doesn't expand to a balanced 'if' statement, so enclose the macro +// in {} if you need to use it as the only statement in an 'if' +// branch. +#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ + if (const int gtest_error = (posix_call)) \ + GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ + << gtest_error + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Use ImplicitCast_ as a safe version of static_cast for upcasting in +// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a +// const Foo*). When you use ImplicitCast_, the compiler checks that +// the cast is safe. Such explicit ImplicitCast_s are necessary in +// surprisingly many situations where C++ demands an exact type match +// instead of an argument type convertable to a target type. +// +// The syntax for using ImplicitCast_ is the same as for static_cast: +// +// ImplicitCast_(expr) +// +// ImplicitCast_ would have been part of the C++ standard library, +// but the proposal was submitted too late. It will probably make +// its way into the language in the future. +// +// This relatively ugly name is intentional. It prevents clashes with +// similar functions users may have (e.g., implicit_cast). The internal +// namespace alone is not enough because the function can be found by ADL. +template +inline To ImplicitCast_(To x) { return x; } + +// When you upcast (that is, cast a pointer from type Foo to type +// SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts +// always succeed. When you downcast (that is, cast a pointer from +// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because +// how do you know the pointer is really of type SubclassOfFoo? It +// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, +// when you downcast, you should use this macro. In debug mode, we +// use dynamic_cast<> to double-check the downcast is legal (we die +// if it's not). In normal mode, we do the efficient static_cast<> +// instead. Thus, it's important to test in debug mode to make sure +// the cast is legal! +// This is the only place in the code we should use dynamic_cast<>. +// In particular, you SHOULDN'T be using dynamic_cast<> in order to +// do RTTI (eg code like this: +// if (dynamic_cast(foo)) HandleASubclass1Object(foo); +// if (dynamic_cast(foo)) HandleASubclass2Object(foo); +// You should design the code some other way not to need this. +// +// This relatively ugly name is intentional. It prevents clashes with +// similar functions users may have (e.g., down_cast). The internal +// namespace alone is not enough because the function can be found by ADL. +template // use like this: DownCast_(foo); +inline To DownCast_(From* f) { // so we only accept pointers + // Ensures that To is a sub-type of From *. This test is here only + // for compile-time type checking, and has no overhead in an + // optimized build at run-time, as it will be optimized away + // completely. + if (false) { + const To to = NULL; + ::testing::internal::ImplicitCast_(to); + } + +#if GTEST_HAS_RTTI + // RTTI: debug mode only! + GTEST_CHECK_(f == NULL || dynamic_cast(f) != NULL); +#endif + return static_cast(f); +} + +// Downcasts the pointer of type Base to Derived. +// Derived must be a subclass of Base. The parameter MUST +// point to a class of type Derived, not any subclass of it. +// When RTTI is available, the function performs a runtime +// check to enforce this. +template +Derived* CheckedDowncastToActualType(Base* base) { +#if GTEST_HAS_RTTI + GTEST_CHECK_(typeid(*base) == typeid(Derived)); + return dynamic_cast(base); // NOLINT +#else + return static_cast(base); // Poor man's downcast. +#endif +} + +#if GTEST_HAS_STREAM_REDIRECTION + +// Defines the stderr capturer: +// CaptureStdout - starts capturing stdout. +// GetCapturedStdout - stops capturing stdout and returns the captured string. +// CaptureStderr - starts capturing stderr. +// GetCapturedStderr - stops capturing stderr and returns the captured string. +// +GTEST_API_ void CaptureStdout(); +GTEST_API_ String GetCapturedStdout(); +GTEST_API_ void CaptureStderr(); +GTEST_API_ String GetCapturedStderr(); + +#endif // GTEST_HAS_STREAM_REDIRECTION + + +#if GTEST_HAS_DEATH_TEST + +// A copy of all command line arguments. Set by InitGoogleTest(). +extern ::std::vector g_argvs; + +// GTEST_HAS_DEATH_TEST implies we have ::std::string. +const ::std::vector& GetArgvs(); + +#endif // GTEST_HAS_DEATH_TEST + +// Defines synchronization primitives. + +#if GTEST_HAS_PTHREAD + +// Sleeps for (roughly) n milli-seconds. This function is only for +// testing Google Test's own constructs. Don't use it in user tests, +// either directly or indirectly. +inline void SleepMilliseconds(int n) { + const timespec time = { + 0, // 0 seconds. + n * 1000L * 1000L, // And n ms. + }; + nanosleep(&time, NULL); +} + +// Allows a controller thread to pause execution of newly created +// threads until notified. Instances of this class must be created +// and destroyed in the controller thread. +// +// This class is only for testing Google Test's own constructs. Do not +// use it in user tests, either directly or indirectly. +class Notification { + public: + Notification() : notified_(false) {} + + // Notifies all threads created with this notification to start. Must + // be called from the controller thread. + void Notify() { notified_ = true; } + + // Blocks until the controller thread notifies. Must be called from a test + // thread. + void WaitForNotification() { + while(!notified_) { + SleepMilliseconds(10); + } + } + + private: + volatile bool notified_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); +}; + +// As a C-function, ThreadFuncWithCLinkage cannot be templated itself. +// Consequently, it cannot select a correct instantiation of ThreadWithParam +// in order to call its Run(). Introducing ThreadWithParamBase as a +// non-templated base class for ThreadWithParam allows us to bypass this +// problem. +class ThreadWithParamBase { + public: + virtual ~ThreadWithParamBase() {} + virtual void Run() = 0; +}; + +// pthread_create() accepts a pointer to a function type with the C linkage. +// According to the Standard (7.5/1), function types with different linkages +// are different even if they are otherwise identical. Some compilers (for +// example, SunStudio) treat them as different types. Since class methods +// cannot be defined with C-linkage we need to define a free C-function to +// pass into pthread_create(). +extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { + static_cast(thread)->Run(); + return NULL; +} + +// Helper class for testing Google Test's multi-threading constructs. +// To use it, write: +// +// void ThreadFunc(int param) { /* Do things with param */ } +// Notification thread_can_start; +// ... +// // The thread_can_start parameter is optional; you can supply NULL. +// ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); +// thread_can_start.Notify(); +// +// These classes are only for testing Google Test's own constructs. Do +// not use them in user tests, either directly or indirectly. +template +class ThreadWithParam : public ThreadWithParamBase { + public: + typedef void (*UserThreadFunc)(T); + + ThreadWithParam( + UserThreadFunc func, T param, Notification* thread_can_start) + : func_(func), + param_(param), + thread_can_start_(thread_can_start), + finished_(false) { + ThreadWithParamBase* const base = this; + // The thread can be created only after all fields except thread_ + // have been initialized. + GTEST_CHECK_POSIX_SUCCESS_( + pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); + } + ~ThreadWithParam() { Join(); } + + void Join() { + if (!finished_) { + GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); + finished_ = true; + } + } + + virtual void Run() { + if (thread_can_start_ != NULL) + thread_can_start_->WaitForNotification(); + func_(param_); + } + + private: + const UserThreadFunc func_; // User-supplied thread function. + const T param_; // User-supplied parameter to the thread function. + // When non-NULL, used to block execution until the controller thread + // notifies. + Notification* const thread_can_start_; + bool finished_; // true iff we know that the thread function has finished. + pthread_t thread_; // The native thread object. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); +}; + +// MutexBase and Mutex implement mutex on pthreads-based platforms. They +// are used in conjunction with class MutexLock: +// +// Mutex mutex; +// ... +// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end +// // of the current scope. +// +// MutexBase implements behavior for both statically and dynamically +// allocated mutexes. Do not use MutexBase directly. Instead, write +// the following to define a static mutex: +// +// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); +// +// You can forward declare a static mutex like this: +// +// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); +// +// To create a dynamic mutex, just define an object of type Mutex. +class MutexBase { + public: + // Acquires this mutex. + void Lock() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); + owner_ = pthread_self(); + } + + // Releases this mutex. + void Unlock() { + // We don't protect writing to owner_ here, as it's the caller's + // responsibility to ensure that the current thread holds the + // mutex when this is called. + owner_ = 0; + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); + } + + // Does nothing if the current thread holds the mutex. Otherwise, crashes + // with high probability. + void AssertHeld() const { + GTEST_CHECK_(owner_ == pthread_self()) + << "The current thread is not holding the mutex @" << this; + } + + // A static mutex may be used before main() is entered. It may even + // be used before the dynamic initialization stage. Therefore we + // must be able to initialize a static mutex object at link time. + // This means MutexBase has to be a POD and its member variables + // have to be public. + public: + pthread_mutex_t mutex_; // The underlying pthread mutex. + pthread_t owner_; // The thread holding the mutex; 0 means no one holds it. +}; + +// Forward-declares a static mutex. +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::MutexBase mutex + +// Defines and statically (i.e. at link time) initializes a static mutex. +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, 0 } + +// The Mutex class can only be used for mutexes created at runtime. It +// shares its API with MutexBase otherwise. +class Mutex : public MutexBase { + public: + Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); + owner_ = 0; + } + ~Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); +}; + +// We cannot name this class MutexLock as the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(MutexBase* mutex) + : mutex_(mutex) { mutex_->Lock(); } + + ~GTestMutexLock() { mutex_->Unlock(); } + + private: + MutexBase* const mutex_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); +}; + +typedef GTestMutexLock MutexLock; + +// Helpers for ThreadLocal. + +// pthread_key_create() requires DeleteThreadLocalValue() to have +// C-linkage. Therefore it cannot be templatized to access +// ThreadLocal. Hence the need for class +// ThreadLocalValueHolderBase. +class ThreadLocalValueHolderBase { + public: + virtual ~ThreadLocalValueHolderBase() {} +}; + +// Called by pthread to delete thread-local data stored by +// pthread_setspecific(). +extern "C" inline void DeleteThreadLocalValue(void* value_holder) { + delete static_cast(value_holder); +} + +// Implements thread-local storage on pthreads-based systems. +// +// // Thread 1 +// ThreadLocal tl(100); // 100 is the default value for each thread. +// +// // Thread 2 +// tl.set(150); // Changes the value for thread 2 only. +// EXPECT_EQ(150, tl.get()); +// +// // Thread 1 +// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. +// tl.set(200); +// EXPECT_EQ(200, tl.get()); +// +// The template type argument T must have a public copy constructor. +// In addition, the default ThreadLocal constructor requires T to have +// a public default constructor. +// +// An object managed for a thread by a ThreadLocal instance is deleted +// when the thread exits. Or, if the ThreadLocal instance dies in +// that thread, when the ThreadLocal dies. It's the user's +// responsibility to ensure that all other threads using a ThreadLocal +// have exited when it dies, or the per-thread objects for those +// threads will not be deleted. +// +// Google Test only uses global ThreadLocal objects. That means they +// will die after main() has returned. Therefore, no per-thread +// object managed by Google Test will be leaked as long as all threads +// using Google Test have exited when main() returns. +template +class ThreadLocal { + public: + ThreadLocal() : key_(CreateKey()), + default_() {} + explicit ThreadLocal(const T& value) : key_(CreateKey()), + default_(value) {} + + ~ThreadLocal() { + // Destroys the managed object for the current thread, if any. + DeleteThreadLocalValue(pthread_getspecific(key_)); + + // Releases resources associated with the key. This will *not* + // delete managed objects for other threads. + GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); + } + + T* pointer() { return GetOrCreateValue(); } + const T* pointer() const { return GetOrCreateValue(); } + const T& get() const { return *pointer(); } + void set(const T& value) { *pointer() = value; } + + private: + // Holds a value of type T. + class ValueHolder : public ThreadLocalValueHolderBase { + public: + explicit ValueHolder(const T& value) : value_(value) {} + + T* pointer() { return &value_; } + + private: + T value_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); + }; + + static pthread_key_t CreateKey() { + pthread_key_t key; + // When a thread exits, DeleteThreadLocalValue() will be called on + // the object managed for that thread. + GTEST_CHECK_POSIX_SUCCESS_( + pthread_key_create(&key, &DeleteThreadLocalValue)); + return key; + } + + T* GetOrCreateValue() const { + ThreadLocalValueHolderBase* const holder = + static_cast(pthread_getspecific(key_)); + if (holder != NULL) { + return CheckedDowncastToActualType(holder)->pointer(); + } + + ValueHolder* const new_holder = new ValueHolder(default_); + ThreadLocalValueHolderBase* const holder_base = new_holder; + GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); + return new_holder->pointer(); + } + + // A key pthreads uses for looking up per-thread values. + const pthread_key_t key_; + const T default_; // The default value for each thread. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); +}; + +# define GTEST_IS_THREADSAFE 1 + +#else // GTEST_HAS_PTHREAD + +// A dummy implementation of synchronization primitives (mutex, lock, +// and thread-local variable). Necessary for compiling Google Test where +// mutex is not supported - using Google Test in multiple threads is not +// supported on such platforms. + +class Mutex { + public: + Mutex() {} + void AssertHeld() const {} +}; + +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::Mutex mutex + +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex + +class GTestMutexLock { + public: + explicit GTestMutexLock(Mutex*) {} // NOLINT +}; + +typedef GTestMutexLock MutexLock; + +template +class ThreadLocal { + public: + ThreadLocal() : value_() {} + explicit ThreadLocal(const T& value) : value_(value) {} + T* pointer() { return &value_; } + const T* pointer() const { return &value_; } + const T& get() const { return value_; } + void set(const T& value) { value_ = value; } + private: + T value_; +}; + +// The above synchronization primitives have dummy implementations. +// Therefore Google Test is not thread-safe. +# define GTEST_IS_THREADSAFE 0 + +#endif // GTEST_HAS_PTHREAD + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +GTEST_API_ size_t GetThreadCount(); + +// Passing non-POD classes through ellipsis (...) crashes the ARM +// compiler and generates a warning in Sun Studio. The Nokia Symbian +// and the IBM XL C/C++ compiler try to instantiate a copy constructor +// for objects passed through ellipsis (...), failing for uncopyable +// objects. We define this to ensure that only POD is passed through +// ellipsis on these systems. +#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) +// We lose support for NULL detection where the compiler doesn't like +// passing non-POD classes through ellipsis (...). +# define GTEST_ELLIPSIS_NEEDS_POD_ 1 +#else +# define GTEST_CAN_COMPARE_NULL 1 +#endif + +// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between +// const T& and const T* in a function template. These compilers +// _can_ decide between class template specializations for T and T*, +// so a tr1::type_traits-like is_pointer works. +#if defined(__SYMBIAN32__) || defined(__IBMCPP__) +# define GTEST_NEEDS_IS_POINTER_ 1 +#endif + +template +struct bool_constant { + typedef bool_constant type; + static const bool value = bool_value; +}; +template const bool bool_constant::value; + +typedef bool_constant false_type; +typedef bool_constant true_type; + +template +struct is_pointer : public false_type {}; + +template +struct is_pointer : public true_type {}; + +template +struct IteratorTraits { + typedef typename Iterator::value_type value_type; +}; + +template +struct IteratorTraits { + typedef T value_type; +}; + +template +struct IteratorTraits { + typedef T value_type; +}; + +#if GTEST_OS_WINDOWS +# define GTEST_PATH_SEP_ "\\" +# define GTEST_HAS_ALT_PATH_SEP_ 1 +// The biggest signed integer type the compiler supports. +typedef __int64 BiggestInt; +#else +# define GTEST_PATH_SEP_ "/" +# define GTEST_HAS_ALT_PATH_SEP_ 0 +typedef long long BiggestInt; // NOLINT +#endif // GTEST_OS_WINDOWS + +// Utilities for char. + +// isspace(int ch) and friends accept an unsigned char or EOF. char +// may be signed, depending on the compiler (or compiler flags). +// Therefore we need to cast a char to unsigned char before calling +// isspace(), etc. + +inline bool IsAlpha(char ch) { + return isalpha(static_cast(ch)) != 0; +} +inline bool IsAlNum(char ch) { + return isalnum(static_cast(ch)) != 0; +} +inline bool IsDigit(char ch) { + return isdigit(static_cast(ch)) != 0; +} +inline bool IsLower(char ch) { + return islower(static_cast(ch)) != 0; +} +inline bool IsSpace(char ch) { + return isspace(static_cast(ch)) != 0; +} +inline bool IsUpper(char ch) { + return isupper(static_cast(ch)) != 0; +} +inline bool IsXDigit(char ch) { + return isxdigit(static_cast(ch)) != 0; +} + +inline char ToLower(char ch) { + return static_cast(tolower(static_cast(ch))); +} +inline char ToUpper(char ch) { + return static_cast(toupper(static_cast(ch))); +} + +// The testing::internal::posix namespace holds wrappers for common +// POSIX functions. These wrappers hide the differences between +// Windows/MSVC and POSIX systems. Since some compilers define these +// standard functions as macros, the wrapper cannot have the same name +// as the wrapped function. + +namespace posix { + +// Functions with a different name on Windows. + +#if GTEST_OS_WINDOWS + +typedef struct _stat StatStruct; + +# ifdef __BORLANDC__ +inline int IsATTY(int fd) { return isatty(fd); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return stricmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +# else // !__BORLANDC__ +# if GTEST_OS_WINDOWS_MOBILE +inline int IsATTY(int /* fd */) { return 0; } +# else +inline int IsATTY(int fd) { return _isatty(fd); } +# endif // GTEST_OS_WINDOWS_MOBILE +inline int StrCaseCmp(const char* s1, const char* s2) { + return _stricmp(s1, s2); +} +inline char* StrDup(const char* src) { return _strdup(src); } +# endif // __BORLANDC__ + +# if GTEST_OS_WINDOWS_MOBILE +inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } +// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this +// time and thus not defined there. +# else +inline int FileNo(FILE* file) { return _fileno(file); } +inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } +inline int RmDir(const char* dir) { return _rmdir(dir); } +inline bool IsDir(const StatStruct& st) { + return (_S_IFDIR & st.st_mode) != 0; +} +# endif // GTEST_OS_WINDOWS_MOBILE + +#else + +typedef struct stat StatStruct; + +inline int FileNo(FILE* file) { return fileno(file); } +inline int IsATTY(int fd) { return isatty(fd); } +inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return strcasecmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +inline int RmDir(const char* dir) { return rmdir(dir); } +inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } + +#endif // GTEST_OS_WINDOWS + +// Functions deprecated by MSVC 8.0. + +#ifdef _MSC_VER +// Temporarily disable warning 4996 (deprecated function). +# pragma warning(push) +# pragma warning(disable:4996) +#endif + +inline const char* StrNCpy(char* dest, const char* src, size_t n) { + return strncpy(dest, src, n); +} + +// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and +// StrError() aren't needed on Windows CE at this time and thus not +// defined there. + +#if !GTEST_OS_WINDOWS_MOBILE +inline int ChDir(const char* dir) { return chdir(dir); } +#endif +inline FILE* FOpen(const char* path, const char* mode) { + return fopen(path, mode); +} +#if !GTEST_OS_WINDOWS_MOBILE +inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { + return freopen(path, mode, stream); +} +inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } +#endif +inline int FClose(FILE* fp) { return fclose(fp); } +#if !GTEST_OS_WINDOWS_MOBILE +inline int Read(int fd, void* buf, unsigned int count) { + return static_cast(read(fd, buf, count)); +} +inline int Write(int fd, const void* buf, unsigned int count) { + return static_cast(write(fd, buf, count)); +} +inline int Close(int fd) { return close(fd); } +inline const char* StrError(int errnum) { return strerror(errnum); } +#endif +inline const char* GetEnv(const char* name) { +#if GTEST_OS_WINDOWS_MOBILE + // We are on Windows CE, which has no environment variables. + return NULL; +#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) + // Environment variables which we programmatically clear will be set to the + // empty string rather than unset (NULL). Handle that case. + const char* const env = getenv(name); + return (env != NULL && env[0] != '\0') ? env : NULL; +#else + return getenv(name); +#endif +} + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif + +#if GTEST_OS_WINDOWS_MOBILE +// Windows CE has no C library. The abort() function is used in +// several places in Google Test. This implementation provides a reasonable +// imitation of standard behaviour. +void Abort(); +#else +inline void Abort() { abort(); } +#endif // GTEST_OS_WINDOWS_MOBILE + +} // namespace posix + +// The maximum number a BiggestInt can represent. This definition +// works no matter BiggestInt is represented in one's complement or +// two's complement. +// +// We cannot rely on numeric_limits in STL, as __int64 and long long +// are not part of standard C++ and numeric_limits doesn't need to be +// defined for them. +const BiggestInt kMaxBiggestInt = + ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); + +// This template class serves as a compile-time function from size to +// type. It maps a size in bytes to a primitive type with that +// size. e.g. +// +// TypeWithSize<4>::UInt +// +// is typedef-ed to be unsigned int (unsigned integer made up of 4 +// bytes). +// +// Such functionality should belong to STL, but I cannot find it +// there. +// +// Google Test uses this class in the implementation of floating-point +// comparison. +// +// For now it only handles UInt (unsigned int) as that's all Google Test +// needs. Other types can be easily added in the future if need +// arises. +template +class TypeWithSize { + public: + // This prevents the user from using TypeWithSize with incorrect + // values of N. + typedef void UInt; +}; + +// The specialization for size 4. +template <> +class TypeWithSize<4> { + public: + // unsigned int has size 4 in both gcc and MSVC. + // + // As base/basictypes.h doesn't compile on Windows, we cannot use + // uint32, uint64, and etc here. + typedef int Int; + typedef unsigned int UInt; +}; + +// The specialization for size 8. +template <> +class TypeWithSize<8> { + public: + +#if GTEST_OS_WINDOWS + typedef __int64 Int; + typedef unsigned __int64 UInt; +#else + typedef long long Int; // NOLINT + typedef unsigned long long UInt; // NOLINT +#endif // GTEST_OS_WINDOWS +}; + +// Integer types of known sizes. +typedef TypeWithSize<4>::Int Int32; +typedef TypeWithSize<4>::UInt UInt32; +typedef TypeWithSize<8>::Int Int64; +typedef TypeWithSize<8>::UInt UInt64; +typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. + +// Utilities for command line flags and environment variables. + +// Macro for referencing flags. +#define GTEST_FLAG(name) FLAGS_gtest_##name + +// Macros for declaring flags. +#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) +#define GTEST_DECLARE_int32_(name) \ + GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) +#define GTEST_DECLARE_string_(name) \ + GTEST_API_ extern ::testing::internal::String GTEST_FLAG(name) + +// Macros for defining flags. +#define GTEST_DEFINE_bool_(name, default_val, doc) \ + GTEST_API_ bool GTEST_FLAG(name) = (default_val) +#define GTEST_DEFINE_int32_(name, default_val, doc) \ + GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) +#define GTEST_DEFINE_string_(name, default_val, doc) \ + GTEST_API_ ::testing::internal::String GTEST_FLAG(name) = (default_val) + +// Parses 'str' for a 32-bit signed integer. If successful, writes the result +// to *value and returns true; otherwise leaves *value unchanged and returns +// false. +// TODO(chandlerc): Find a better way to refactor flag and environment parsing +// out of both gtest-port.cc and gtest.cc to avoid exporting this utility +// function. +bool ParseInt32(const Message& src_text, const char* str, Int32* value); + +// Parses a bool/Int32/string from the environment variable +// corresponding to the given Google Test flag. +bool BoolFromGTestEnv(const char* flag, bool default_val); +GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); +const char* StringFromGTestEnv(const char* flag, const char* default_val); + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ diff --git a/libs/gtest/include/gtest/internal/gtest-string.h b/libs/gtest/include/gtest/internal/gtest-string.h new file mode 100644 index 000000000..dc3a07be8 --- /dev/null +++ b/libs/gtest/include/gtest/internal/gtest-string.h @@ -0,0 +1,350 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file declares the String class and functions used internally by +// Google Test. They are subject to change without notice. They should not used +// by code external to Google Test. +// +// This header file is #included by . +// It should not be #included by other files. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ + +#ifdef __BORLANDC__ +// string.h is not guaranteed to provide strcpy on C++ Builder. +# include +#endif + +#include +#include "gtest/internal/gtest-port.h" + +#include + +namespace testing { +namespace internal { + +// String - a UTF-8 string class. +// +// For historic reasons, we don't use std::string. +// +// TODO(wan@google.com): replace this class with std::string or +// implement it in terms of the latter. +// +// Note that String can represent both NULL and the empty string, +// while std::string cannot represent NULL. +// +// NULL and the empty string are considered different. NULL is less +// than anything (including the empty string) except itself. +// +// This class only provides minimum functionality necessary for +// implementing Google Test. We do not intend to implement a full-fledged +// string class here. +// +// Since the purpose of this class is to provide a substitute for +// std::string on platforms where it cannot be used, we define a copy +// constructor and assignment operators such that we don't need +// conditional compilation in a lot of places. +// +// In order to make the representation efficient, the d'tor of String +// is not virtual. Therefore DO NOT INHERIT FROM String. +class GTEST_API_ String { + public: + // Static utility methods + + // Returns the input enclosed in double quotes if it's not NULL; + // otherwise returns "(null)". For example, "\"Hello\"" is returned + // for input "Hello". + // + // This is useful for printing a C string in the syntax of a literal. + // + // Known issue: escape sequences are not handled yet. + static String ShowCStringQuoted(const char* c_str); + + // Clones a 0-terminated C string, allocating memory using new. The + // caller is responsible for deleting the return value using + // delete[]. Returns the cloned string, or NULL if the input is + // NULL. + // + // This is different from strdup() in string.h, which allocates + // memory using malloc(). + static const char* CloneCString(const char* c_str); + +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be + // able to pass strings to Win32 APIs on CE we need to convert them + // to 'Unicode', UTF-16. + + // Creates a UTF-16 wide string from the given ANSI string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the wide string, or NULL if the + // input is NULL. + // + // The wide string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static LPCWSTR AnsiToUtf16(const char* c_str); + + // Creates an ANSI string from the given wide string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the ANSI string, or NULL if the + // input is NULL. + // + // The returned string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static const char* Utf16ToAnsi(LPCWSTR utf16_str); +#endif + + // Compares two C strings. Returns true iff they have the same content. + // + // Unlike strcmp(), this function can handle NULL argument(s). A + // NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool CStringEquals(const char* lhs, const char* rhs); + + // Converts a wide C string to a String using the UTF-8 encoding. + // NULL will be converted to "(null)". If an error occurred during + // the conversion, "(failed to convert from wide string)" is + // returned. + static String ShowWideCString(const wchar_t* wide_c_str); + + // Similar to ShowWideCString(), except that this function encloses + // the converted string in double quotes. + static String ShowWideCStringQuoted(const wchar_t* wide_c_str); + + // Compares two wide C strings. Returns true iff they have the same + // content. + // + // Unlike wcscmp(), this function can handle NULL argument(s). A + // NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); + + // Compares two C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike strcasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool CaseInsensitiveCStringEquals(const char* lhs, + const char* rhs); + + // Compares two wide C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike wcscasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL wide C string, + // including the empty string. + // NB: The implementations on different platforms slightly differ. + // On windows, this method uses _wcsicmp which compares according to LC_CTYPE + // environment variable. On GNU platform this method uses wcscasecmp + // which compares according to LC_CTYPE category of the current locale. + // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the + // current locale. + static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs); + + // Formats a list of arguments to a String, using the same format + // spec string as for printf. + // + // We do not use the StringPrintf class as it is not universally + // available. + // + // The result is limited to 4096 characters (including the tailing + // 0). If 4096 characters are not enough to format the input, + // "" is returned. + static String Format(const char* format, ...); + + // C'tors + + // The default c'tor constructs a NULL string. + String() : c_str_(NULL), length_(0) {} + + // Constructs a String by cloning a 0-terminated C string. + String(const char* a_c_str) { // NOLINT + if (a_c_str == NULL) { + c_str_ = NULL; + length_ = 0; + } else { + ConstructNonNull(a_c_str, strlen(a_c_str)); + } + } + + // Constructs a String by copying a given number of chars from a + // buffer. E.g. String("hello", 3) creates the string "hel", + // String("a\0bcd", 4) creates "a\0bc", String(NULL, 0) creates "", + // and String(NULL, 1) results in access violation. + String(const char* buffer, size_t a_length) { + ConstructNonNull(buffer, a_length); + } + + // The copy c'tor creates a new copy of the string. The two + // String objects do not share content. + String(const String& str) : c_str_(NULL), length_(0) { *this = str; } + + // D'tor. String is intended to be a final class, so the d'tor + // doesn't need to be virtual. + ~String() { delete[] c_str_; } + + // Allows a String to be implicitly converted to an ::std::string or + // ::string, and vice versa. Converting a String containing a NULL + // pointer to ::std::string or ::string is undefined behavior. + // Converting a ::std::string or ::string containing an embedded NUL + // character to a String will result in the prefix up to the first + // NUL character. + String(const ::std::string& str) { + ConstructNonNull(str.c_str(), str.length()); + } + + operator ::std::string() const { return ::std::string(c_str(), length()); } + +#if GTEST_HAS_GLOBAL_STRING + String(const ::string& str) { + ConstructNonNull(str.c_str(), str.length()); + } + + operator ::string() const { return ::string(c_str(), length()); } +#endif // GTEST_HAS_GLOBAL_STRING + + // Returns true iff this is an empty string (i.e. ""). + bool empty() const { return (c_str() != NULL) && (length() == 0); } + + // Compares this with another String. + // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 + // if this is greater than rhs. + int Compare(const String& rhs) const; + + // Returns true iff this String equals the given C string. A NULL + // string and a non-NULL string are considered not equal. + bool operator==(const char* a_c_str) const { return Compare(a_c_str) == 0; } + + // Returns true iff this String is less than the given String. A + // NULL string is considered less than "". + bool operator<(const String& rhs) const { return Compare(rhs) < 0; } + + // Returns true iff this String doesn't equal the given C string. A NULL + // string and a non-NULL string are considered not equal. + bool operator!=(const char* a_c_str) const { return !(*this == a_c_str); } + + // Returns true iff this String ends with the given suffix. *Any* + // String is considered to end with a NULL or empty suffix. + bool EndsWith(const char* suffix) const; + + // Returns true iff this String ends with the given suffix, not considering + // case. Any String is considered to end with a NULL or empty suffix. + bool EndsWithCaseInsensitive(const char* suffix) const; + + // Returns the length of the encapsulated string, or 0 if the + // string is NULL. + size_t length() const { return length_; } + + // Gets the 0-terminated C string this String object represents. + // The String object still owns the string. Therefore the caller + // should NOT delete the return value. + const char* c_str() const { return c_str_; } + + // Assigns a C string to this object. Self-assignment works. + const String& operator=(const char* a_c_str) { + return *this = String(a_c_str); + } + + // Assigns a String object to this object. Self-assignment works. + const String& operator=(const String& rhs) { + if (this != &rhs) { + delete[] c_str_; + if (rhs.c_str() == NULL) { + c_str_ = NULL; + length_ = 0; + } else { + ConstructNonNull(rhs.c_str(), rhs.length()); + } + } + + return *this; + } + + private: + // Constructs a non-NULL String from the given content. This + // function can only be called when c_str_ has not been allocated. + // ConstructNonNull(NULL, 0) results in an empty string (""). + // ConstructNonNull(NULL, non_zero) is undefined behavior. + void ConstructNonNull(const char* buffer, size_t a_length) { + char* const str = new char[a_length + 1]; + memcpy(str, buffer, a_length); + str[a_length] = '\0'; + c_str_ = str; + length_ = a_length; + } + + const char* c_str_; + size_t length_; +}; // class String + +// Streams a String to an ostream. Each '\0' character in the String +// is replaced with "\\0". +inline ::std::ostream& operator<<(::std::ostream& os, const String& str) { + if (str.c_str() == NULL) { + os << "(null)"; + } else { + const char* const c_str = str.c_str(); + for (size_t i = 0; i != str.length(); i++) { + if (c_str[i] == '\0') { + os << "\\0"; + } else { + os << c_str[i]; + } + } + } + return os; +} + +// Gets the content of the stringstream's buffer as a String. Each '\0' +// character in the buffer is replaced with "\\0". +GTEST_API_ String StringStreamToString(::std::stringstream* stream); + +// Converts a streamable value to a String. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". + +// Declared here but defined in gtest.h, so that it has access +// to the definition of the Message class, required by the ARM +// compiler. +template +String StreamableToString(const T& streamable); + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ diff --git a/libs/gtest/include/gtest/internal/gtest-tuple.h b/libs/gtest/include/gtest/internal/gtest-tuple.h new file mode 100644 index 000000000..d1af50e18 --- /dev/null +++ b/libs/gtest/include/gtest/internal/gtest-tuple.h @@ -0,0 +1,968 @@ +// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! + +// Copyright 2009 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Implements a subset of TR1 tuple needed by Google Test and Google Mock. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ + +#include // For ::std::pair. + +// The compiler used in Symbian has a bug that prevents us from declaring the +// tuple template as a friend (it complains that tuple is redefined). This +// hack bypasses the bug by declaring the members that should otherwise be +// private as public. +// Sun Studio versions < 12 also have the above bug. +#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) +# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: +#else +# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ + template friend class tuple; \ + private: +#endif + +// GTEST_n_TUPLE_(T) is the type of an n-tuple. +#define GTEST_0_TUPLE_(T) tuple<> +#define GTEST_1_TUPLE_(T) tuple +#define GTEST_2_TUPLE_(T) tuple +#define GTEST_3_TUPLE_(T) tuple +#define GTEST_4_TUPLE_(T) tuple +#define GTEST_5_TUPLE_(T) tuple +#define GTEST_6_TUPLE_(T) tuple +#define GTEST_7_TUPLE_(T) tuple +#define GTEST_8_TUPLE_(T) tuple +#define GTEST_9_TUPLE_(T) tuple +#define GTEST_10_TUPLE_(T) tuple + +// GTEST_n_TYPENAMES_(T) declares a list of n typenames. +#define GTEST_0_TYPENAMES_(T) +#define GTEST_1_TYPENAMES_(T) typename T##0 +#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1 +#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2 +#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3 +#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4 +#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5 +#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6 +#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, typename T##7 +#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, \ + typename T##7, typename T##8 +#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, \ + typename T##7, typename T##8, typename T##9 + +// In theory, defining stuff in the ::std namespace is undefined +// behavior. We can do this as we are playing the role of a standard +// library vendor. +namespace std { +namespace tr1 { + +template +class tuple; + +// Anything in namespace gtest_internal is Google Test's INTERNAL +// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. +namespace gtest_internal { + +// ByRef::type is T if T is a reference; otherwise it's const T&. +template +struct ByRef { typedef const T& type; }; // NOLINT +template +struct ByRef { typedef T& type; }; // NOLINT + +// A handy wrapper for ByRef. +#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type + +// AddRef::type is T if T is a reference; otherwise it's T&. This +// is the same as tr1::add_reference::type. +template +struct AddRef { typedef T& type; }; // NOLINT +template +struct AddRef { typedef T& type; }; // NOLINT + +// A handy wrapper for AddRef. +#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type + +// A helper for implementing get(). +template class Get; + +// A helper for implementing tuple_element. kIndexValid is true +// iff k < the number of fields in tuple type T. +template +struct TupleElement; + +template +struct TupleElement { typedef T0 type; }; + +template +struct TupleElement { typedef T1 type; }; + +template +struct TupleElement { typedef T2 type; }; + +template +struct TupleElement { typedef T3 type; }; + +template +struct TupleElement { typedef T4 type; }; + +template +struct TupleElement { typedef T5 type; }; + +template +struct TupleElement { typedef T6 type; }; + +template +struct TupleElement { typedef T7 type; }; + +template +struct TupleElement { typedef T8 type; }; + +template +struct TupleElement { typedef T9 type; }; + +} // namespace gtest_internal + +template <> +class tuple<> { + public: + tuple() {} + tuple(const tuple& /* t */) {} + tuple& operator=(const tuple& /* t */) { return *this; } +}; + +template +class GTEST_1_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} + + tuple(const tuple& t) : f0_(t.f0_) {} + + template + tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_1_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { + f0_ = t.f0_; + return *this; + } + + T0 f0_; +}; + +template +class GTEST_2_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0), + f1_(f1) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {} + + template + tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} + template + tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_2_TUPLE_(U)& t) { + return CopyFrom(t); + } + template + tuple& operator=(const ::std::pair& p) { + f0_ = p.first; + f1_ = p.second; + return *this; + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + return *this; + } + + T0 f0_; + T1 f1_; +}; + +template +class GTEST_3_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} + + template + tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_3_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; +}; + +template +class GTEST_4_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} + + template + tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_4_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; +}; + +template +class GTEST_5_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, + GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_) {} + + template + tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_5_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; +}; + +template +class GTEST_6_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_) {} + + template + tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_6_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; +}; + +template +class GTEST_7_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3), f4_(f4), f5_(f5), f6_(f6) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} + + template + tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_7_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; +}; + +template +class GTEST_8_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, + GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5), f6_(f6), f7_(f7) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} + + template + tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_8_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; +}; + +template +class GTEST_9_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, + GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5), f6_(f6), f7_(f7), f8_(f8) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} + + template + tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_9_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + f8_ = t.f8_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; + T8 f8_; +}; + +template +class tuple { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(), + f9_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, + GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} + + template + tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), + f9_(t.f9_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_10_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + f8_ = t.f8_; + f9_ = t.f9_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; + T8 f8_; + T9 f9_; +}; + +// 6.1.3.2 Tuple creation functions. + +// Known limitations: we don't support passing an +// std::tr1::reference_wrapper to make_tuple(). And we don't +// implement tie(). + +inline tuple<> make_tuple() { return tuple<>(); } + +template +inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { + return GTEST_1_TUPLE_(T)(f0); +} + +template +inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { + return GTEST_2_TUPLE_(T)(f0, f1); +} + +template +inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) { + return GTEST_3_TUPLE_(T)(f0, f1, f2); +} + +template +inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3) { + return GTEST_4_TUPLE_(T)(f0, f1, f2, f3); +} + +template +inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4) { + return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4); +} + +template +inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5) { + return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5); +} + +template +inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6) { + return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6); +} + +template +inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) { + return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7); +} + +template +inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, + const T8& f8) { + return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8); +} + +template +inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, + const T8& f8, const T9& f9) { + return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); +} + +// 6.1.3.3 Tuple helper classes. + +template struct tuple_size; + +template +struct tuple_size { static const int value = 0; }; + +template +struct tuple_size { static const int value = 1; }; + +template +struct tuple_size { static const int value = 2; }; + +template +struct tuple_size { static const int value = 3; }; + +template +struct tuple_size { static const int value = 4; }; + +template +struct tuple_size { static const int value = 5; }; + +template +struct tuple_size { static const int value = 6; }; + +template +struct tuple_size { static const int value = 7; }; + +template +struct tuple_size { static const int value = 8; }; + +template +struct tuple_size { static const int value = 9; }; + +template +struct tuple_size { static const int value = 10; }; + +template +struct tuple_element { + typedef typename gtest_internal::TupleElement< + k < (tuple_size::value), k, Tuple>::type type; +}; + +#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type + +// 6.1.3.4 Element access. + +namespace gtest_internal { + +template <> +class Get<0> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) + Field(Tuple& t) { return t.f0_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) + ConstField(const Tuple& t) { return t.f0_; } +}; + +template <> +class Get<1> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) + Field(Tuple& t) { return t.f1_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) + ConstField(const Tuple& t) { return t.f1_; } +}; + +template <> +class Get<2> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) + Field(Tuple& t) { return t.f2_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) + ConstField(const Tuple& t) { return t.f2_; } +}; + +template <> +class Get<3> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) + Field(Tuple& t) { return t.f3_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) + ConstField(const Tuple& t) { return t.f3_; } +}; + +template <> +class Get<4> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) + Field(Tuple& t) { return t.f4_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) + ConstField(const Tuple& t) { return t.f4_; } +}; + +template <> +class Get<5> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) + Field(Tuple& t) { return t.f5_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) + ConstField(const Tuple& t) { return t.f5_; } +}; + +template <> +class Get<6> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) + Field(Tuple& t) { return t.f6_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) + ConstField(const Tuple& t) { return t.f6_; } +}; + +template <> +class Get<7> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) + Field(Tuple& t) { return t.f7_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) + ConstField(const Tuple& t) { return t.f7_; } +}; + +template <> +class Get<8> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) + Field(Tuple& t) { return t.f8_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) + ConstField(const Tuple& t) { return t.f8_; } +}; + +template <> +class Get<9> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) + Field(Tuple& t) { return t.f9_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) + ConstField(const Tuple& t) { return t.f9_; } +}; + +} // namespace gtest_internal + +template +GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) +get(GTEST_10_TUPLE_(T)& t) { + return gtest_internal::Get::Field(t); +} + +template +GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) +get(const GTEST_10_TUPLE_(T)& t) { + return gtest_internal::Get::ConstField(t); +} + +// 6.1.3.5 Relational operators + +// We only implement == and !=, as we don't have a need for the rest yet. + +namespace gtest_internal { + +// SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the +// first k fields of t1 equals the first k fields of t2. +// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if +// k1 != k2. +template +struct SameSizeTuplePrefixComparator; + +template <> +struct SameSizeTuplePrefixComparator<0, 0> { + template + static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { + return true; + } +}; + +template +struct SameSizeTuplePrefixComparator { + template + static bool Eq(const Tuple1& t1, const Tuple2& t2) { + return SameSizeTuplePrefixComparator::Eq(t1, t2) && + ::std::tr1::get(t1) == ::std::tr1::get(t2); + } +}; + +} // namespace gtest_internal + +template +inline bool operator==(const GTEST_10_TUPLE_(T)& t, + const GTEST_10_TUPLE_(U)& u) { + return gtest_internal::SameSizeTuplePrefixComparator< + tuple_size::value, + tuple_size::value>::Eq(t, u); +} + +template +inline bool operator!=(const GTEST_10_TUPLE_(T)& t, + const GTEST_10_TUPLE_(U)& u) { return !(t == u); } + +// 6.1.4 Pairs. +// Unimplemented. + +} // namespace tr1 +} // namespace std + +#undef GTEST_0_TUPLE_ +#undef GTEST_1_TUPLE_ +#undef GTEST_2_TUPLE_ +#undef GTEST_3_TUPLE_ +#undef GTEST_4_TUPLE_ +#undef GTEST_5_TUPLE_ +#undef GTEST_6_TUPLE_ +#undef GTEST_7_TUPLE_ +#undef GTEST_8_TUPLE_ +#undef GTEST_9_TUPLE_ +#undef GTEST_10_TUPLE_ + +#undef GTEST_0_TYPENAMES_ +#undef GTEST_1_TYPENAMES_ +#undef GTEST_2_TYPENAMES_ +#undef GTEST_3_TYPENAMES_ +#undef GTEST_4_TYPENAMES_ +#undef GTEST_5_TYPENAMES_ +#undef GTEST_6_TYPENAMES_ +#undef GTEST_7_TYPENAMES_ +#undef GTEST_8_TYPENAMES_ +#undef GTEST_9_TYPENAMES_ +#undef GTEST_10_TYPENAMES_ + +#undef GTEST_DECLARE_TUPLE_AS_FRIEND_ +#undef GTEST_BY_REF_ +#undef GTEST_ADD_REF_ +#undef GTEST_TUPLE_ELEMENT_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ diff --git a/libs/gtest/include/gtest/internal/gtest-tuple.h.pump b/libs/gtest/include/gtest/internal/gtest-tuple.h.pump new file mode 100644 index 000000000..ef519094a --- /dev/null +++ b/libs/gtest/include/gtest/internal/gtest-tuple.h.pump @@ -0,0 +1,336 @@ +$$ -*- mode: c++; -*- +$var n = 10 $$ Maximum number of tuple fields we want to support. +$$ This meta comment fixes auto-indentation in Emacs. }} +// Copyright 2009 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Implements a subset of TR1 tuple needed by Google Test and Google Mock. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ + +#include // For ::std::pair. + +// The compiler used in Symbian has a bug that prevents us from declaring the +// tuple template as a friend (it complains that tuple is redefined). This +// hack bypasses the bug by declaring the members that should otherwise be +// private as public. +// Sun Studio versions < 12 also have the above bug. +#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) +# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: +#else +# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ + template friend class tuple; \ + private: +#endif + + +$range i 0..n-1 +$range j 0..n +$range k 1..n +// GTEST_n_TUPLE_(T) is the type of an n-tuple. +#define GTEST_0_TUPLE_(T) tuple<> + +$for k [[ +$range m 0..k-1 +$range m2 k..n-1 +#define GTEST_$(k)_TUPLE_(T) tuple<$for m, [[T##$m]]$for m2 [[, void]]> + +]] + +// GTEST_n_TYPENAMES_(T) declares a list of n typenames. + +$for j [[ +$range m 0..j-1 +#define GTEST_$(j)_TYPENAMES_(T) $for m, [[typename T##$m]] + + +]] + +// In theory, defining stuff in the ::std namespace is undefined +// behavior. We can do this as we are playing the role of a standard +// library vendor. +namespace std { +namespace tr1 { + +template <$for i, [[typename T$i = void]]> +class tuple; + +// Anything in namespace gtest_internal is Google Test's INTERNAL +// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. +namespace gtest_internal { + +// ByRef::type is T if T is a reference; otherwise it's const T&. +template +struct ByRef { typedef const T& type; }; // NOLINT +template +struct ByRef { typedef T& type; }; // NOLINT + +// A handy wrapper for ByRef. +#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type + +// AddRef::type is T if T is a reference; otherwise it's T&. This +// is the same as tr1::add_reference::type. +template +struct AddRef { typedef T& type; }; // NOLINT +template +struct AddRef { typedef T& type; }; // NOLINT + +// A handy wrapper for AddRef. +#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type + +// A helper for implementing get(). +template class Get; + +// A helper for implementing tuple_element. kIndexValid is true +// iff k < the number of fields in tuple type T. +template +struct TupleElement; + + +$for i [[ +template +struct TupleElement [[]] +{ typedef T$i type; }; + + +]] +} // namespace gtest_internal + +template <> +class tuple<> { + public: + tuple() {} + tuple(const tuple& /* t */) {} + tuple& operator=(const tuple& /* t */) { return *this; } +}; + + +$for k [[ +$range m 0..k-1 +template +class $if k < n [[GTEST_$(k)_TUPLE_(T)]] $else [[tuple]] { + public: + template friend class gtest_internal::Get; + + tuple() : $for m, [[f$(m)_()]] {} + + explicit tuple($for m, [[GTEST_BY_REF_(T$m) f$m]]) : [[]] +$for m, [[f$(m)_(f$m)]] {} + + tuple(const tuple& t) : $for m, [[f$(m)_(t.f$(m)_)]] {} + + template + tuple(const GTEST_$(k)_TUPLE_(U)& t) : $for m, [[f$(m)_(t.f$(m)_)]] {} + +$if k == 2 [[ + template + tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} + +]] + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_$(k)_TUPLE_(U)& t) { + return CopyFrom(t); + } + +$if k == 2 [[ + template + tuple& operator=(const ::std::pair& p) { + f0_ = p.first; + f1_ = p.second; + return *this; + } + +]] + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_$(k)_TUPLE_(U)& t) { + +$for m [[ + f$(m)_ = t.f$(m)_; + +]] + return *this; + } + + +$for m [[ + T$m f$(m)_; + +]] +}; + + +]] +// 6.1.3.2 Tuple creation functions. + +// Known limitations: we don't support passing an +// std::tr1::reference_wrapper to make_tuple(). And we don't +// implement tie(). + +inline tuple<> make_tuple() { return tuple<>(); } + +$for k [[ +$range m 0..k-1 + +template +inline GTEST_$(k)_TUPLE_(T) make_tuple($for m, [[const T$m& f$m]]) { + return GTEST_$(k)_TUPLE_(T)($for m, [[f$m]]); +} + +]] + +// 6.1.3.3 Tuple helper classes. + +template struct tuple_size; + + +$for j [[ +template +struct tuple_size { static const int value = $j; }; + + +]] +template +struct tuple_element { + typedef typename gtest_internal::TupleElement< + k < (tuple_size::value), k, Tuple>::type type; +}; + +#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type + +// 6.1.3.4 Element access. + +namespace gtest_internal { + + +$for i [[ +template <> +class Get<$i> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple)) + Field(Tuple& t) { return t.f$(i)_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple)) + ConstField(const Tuple& t) { return t.f$(i)_; } +}; + + +]] +} // namespace gtest_internal + +template +GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T))) +get(GTEST_$(n)_TUPLE_(T)& t) { + return gtest_internal::Get::Field(t); +} + +template +GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T))) +get(const GTEST_$(n)_TUPLE_(T)& t) { + return gtest_internal::Get::ConstField(t); +} + +// 6.1.3.5 Relational operators + +// We only implement == and !=, as we don't have a need for the rest yet. + +namespace gtest_internal { + +// SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the +// first k fields of t1 equals the first k fields of t2. +// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if +// k1 != k2. +template +struct SameSizeTuplePrefixComparator; + +template <> +struct SameSizeTuplePrefixComparator<0, 0> { + template + static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { + return true; + } +}; + +template +struct SameSizeTuplePrefixComparator { + template + static bool Eq(const Tuple1& t1, const Tuple2& t2) { + return SameSizeTuplePrefixComparator::Eq(t1, t2) && + ::std::tr1::get(t1) == ::std::tr1::get(t2); + } +}; + +} // namespace gtest_internal + +template +inline bool operator==(const GTEST_$(n)_TUPLE_(T)& t, + const GTEST_$(n)_TUPLE_(U)& u) { + return gtest_internal::SameSizeTuplePrefixComparator< + tuple_size::value, + tuple_size::value>::Eq(t, u); +} + +template +inline bool operator!=(const GTEST_$(n)_TUPLE_(T)& t, + const GTEST_$(n)_TUPLE_(U)& u) { return !(t == u); } + +// 6.1.4 Pairs. +// Unimplemented. + +} // namespace tr1 +} // namespace std + + +$for j [[ +#undef GTEST_$(j)_TUPLE_ + +]] + + +$for j [[ +#undef GTEST_$(j)_TYPENAMES_ + +]] + +#undef GTEST_DECLARE_TUPLE_AS_FRIEND_ +#undef GTEST_BY_REF_ +#undef GTEST_ADD_REF_ +#undef GTEST_TUPLE_ELEMENT_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ diff --git a/libs/gtest/include/gtest/internal/gtest-type-util.h b/libs/gtest/include/gtest/internal/gtest-type-util.h new file mode 100644 index 000000000..b7b01b094 --- /dev/null +++ b/libs/gtest/include/gtest/internal/gtest-type-util.h @@ -0,0 +1,3330 @@ +// This file was GENERATED by command: +// pump.py gtest-type-util.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Type utilities needed for implementing typed and type-parameterized +// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently we support at most 50 types in a list, and at most 50 +// type-parameterized tests in one type-parameterized test case. +// Please contact googletestframework@googlegroups.com if you need +// more. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ + +#include "gtest/internal/gtest-port.h" +#include "gtest/internal/gtest-string.h" + +// #ifdef __GNUC__ is too general here. It is possible to use gcc without using +// libstdc++ (which is where cxxabi.h comes from). +# ifdef __GLIBCXX__ +# include +# elif defined(__HP_aCC) +# include +# endif // __GLIBCXX__ + +namespace testing { +namespace internal { + +// GetTypeName() returns a human-readable name of type T. +// NB: This function is also used in Google Mock, so don't move it inside of +// the typed-test-only section below. +template +String GetTypeName() { +# if GTEST_HAS_RTTI + + const char* const name = typeid(T).name(); +# if defined(__GLIBCXX__) || defined(__HP_aCC) + int status = 0; + // gcc's implementation of typeid(T).name() mangles the type name, + // so we have to demangle it. +# ifdef __GLIBCXX__ + using abi::__cxa_demangle; +# endif // __GLIBCXX__ + char* const readable_name = __cxa_demangle(name, 0, 0, &status); + const String name_str(status == 0 ? readable_name : name); + free(readable_name); + return name_str; +# else + return name; +# endif // __GLIBCXX__ || __HP_aCC + +# else + + return ""; + +# endif // GTEST_HAS_RTTI +} + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// AssertyTypeEq::type is defined iff T1 and T2 are the same +// type. This can be used as a compile-time assertion to ensure that +// two types are equal. + +template +struct AssertTypeEq; + +template +struct AssertTypeEq { + typedef bool type; +}; + +// A unique type used as the default value for the arguments of class +// template Types. This allows us to simulate variadic templates +// (e.g. Types, Type, and etc), which C++ doesn't +// support directly. +struct None {}; + +// The following family of struct and struct templates are used to +// represent type lists. In particular, TypesN +// represents a type list with N types (T1, T2, ..., and TN) in it. +// Except for Types0, every struct in the family has two member types: +// Head for the first type in the list, and Tail for the rest of the +// list. + +// The empty type list. +struct Types0 {}; + +// Type lists of length 1, 2, 3, and so on. + +template +struct Types1 { + typedef T1 Head; + typedef Types0 Tail; +}; +template +struct Types2 { + typedef T1 Head; + typedef Types1 Tail; +}; + +template +struct Types3 { + typedef T1 Head; + typedef Types2 Tail; +}; + +template +struct Types4 { + typedef T1 Head; + typedef Types3 Tail; +}; + +template +struct Types5 { + typedef T1 Head; + typedef Types4 Tail; +}; + +template +struct Types6 { + typedef T1 Head; + typedef Types5 Tail; +}; + +template +struct Types7 { + typedef T1 Head; + typedef Types6 Tail; +}; + +template +struct Types8 { + typedef T1 Head; + typedef Types7 Tail; +}; + +template +struct Types9 { + typedef T1 Head; + typedef Types8 Tail; +}; + +template +struct Types10 { + typedef T1 Head; + typedef Types9 Tail; +}; + +template +struct Types11 { + typedef T1 Head; + typedef Types10 Tail; +}; + +template +struct Types12 { + typedef T1 Head; + typedef Types11 Tail; +}; + +template +struct Types13 { + typedef T1 Head; + typedef Types12 Tail; +}; + +template +struct Types14 { + typedef T1 Head; + typedef Types13 Tail; +}; + +template +struct Types15 { + typedef T1 Head; + typedef Types14 Tail; +}; + +template +struct Types16 { + typedef T1 Head; + typedef Types15 Tail; +}; + +template +struct Types17 { + typedef T1 Head; + typedef Types16 Tail; +}; + +template +struct Types18 { + typedef T1 Head; + typedef Types17 Tail; +}; + +template +struct Types19 { + typedef T1 Head; + typedef Types18 Tail; +}; + +template +struct Types20 { + typedef T1 Head; + typedef Types19 Tail; +}; + +template +struct Types21 { + typedef T1 Head; + typedef Types20 Tail; +}; + +template +struct Types22 { + typedef T1 Head; + typedef Types21 Tail; +}; + +template +struct Types23 { + typedef T1 Head; + typedef Types22 Tail; +}; + +template +struct Types24 { + typedef T1 Head; + typedef Types23 Tail; +}; + +template +struct Types25 { + typedef T1 Head; + typedef Types24 Tail; +}; + +template +struct Types26 { + typedef T1 Head; + typedef Types25 Tail; +}; + +template +struct Types27 { + typedef T1 Head; + typedef Types26 Tail; +}; + +template +struct Types28 { + typedef T1 Head; + typedef Types27 Tail; +}; + +template +struct Types29 { + typedef T1 Head; + typedef Types28 Tail; +}; + +template +struct Types30 { + typedef T1 Head; + typedef Types29 Tail; +}; + +template +struct Types31 { + typedef T1 Head; + typedef Types30 Tail; +}; + +template +struct Types32 { + typedef T1 Head; + typedef Types31 Tail; +}; + +template +struct Types33 { + typedef T1 Head; + typedef Types32 Tail; +}; + +template +struct Types34 { + typedef T1 Head; + typedef Types33 Tail; +}; + +template +struct Types35 { + typedef T1 Head; + typedef Types34 Tail; +}; + +template +struct Types36 { + typedef T1 Head; + typedef Types35 Tail; +}; + +template +struct Types37 { + typedef T1 Head; + typedef Types36 Tail; +}; + +template +struct Types38 { + typedef T1 Head; + typedef Types37 Tail; +}; + +template +struct Types39 { + typedef T1 Head; + typedef Types38 Tail; +}; + +template +struct Types40 { + typedef T1 Head; + typedef Types39 Tail; +}; + +template +struct Types41 { + typedef T1 Head; + typedef Types40 Tail; +}; + +template +struct Types42 { + typedef T1 Head; + typedef Types41 Tail; +}; + +template +struct Types43 { + typedef T1 Head; + typedef Types42 Tail; +}; + +template +struct Types44 { + typedef T1 Head; + typedef Types43 Tail; +}; + +template +struct Types45 { + typedef T1 Head; + typedef Types44 Tail; +}; + +template +struct Types46 { + typedef T1 Head; + typedef Types45 Tail; +}; + +template +struct Types47 { + typedef T1 Head; + typedef Types46 Tail; +}; + +template +struct Types48 { + typedef T1 Head; + typedef Types47 Tail; +}; + +template +struct Types49 { + typedef T1 Head; + typedef Types48 Tail; +}; + +template +struct Types50 { + typedef T1 Head; + typedef Types49 Tail; +}; + + +} // namespace internal + +// We don't want to require the users to write TypesN<...> directly, +// as that would require them to count the length. Types<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Types +// will appear as Types in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Types, and Google Test will translate +// that to TypesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Types template. +template +struct Types { + typedef internal::Types50 type; +}; + +template <> +struct Types { + typedef internal::Types0 type; +}; +template +struct Types { + typedef internal::Types1 type; +}; +template +struct Types { + typedef internal::Types2 type; +}; +template +struct Types { + typedef internal::Types3 type; +}; +template +struct Types { + typedef internal::Types4 type; +}; +template +struct Types { + typedef internal::Types5 type; +}; +template +struct Types { + typedef internal::Types6 type; +}; +template +struct Types { + typedef internal::Types7 type; +}; +template +struct Types { + typedef internal::Types8 type; +}; +template +struct Types { + typedef internal::Types9 type; +}; +template +struct Types { + typedef internal::Types10 type; +}; +template +struct Types { + typedef internal::Types11 type; +}; +template +struct Types { + typedef internal::Types12 type; +}; +template +struct Types { + typedef internal::Types13 type; +}; +template +struct Types { + typedef internal::Types14 type; +}; +template +struct Types { + typedef internal::Types15 type; +}; +template +struct Types { + typedef internal::Types16 type; +}; +template +struct Types { + typedef internal::Types17 type; +}; +template +struct Types { + typedef internal::Types18 type; +}; +template +struct Types { + typedef internal::Types19 type; +}; +template +struct Types { + typedef internal::Types20 type; +}; +template +struct Types { + typedef internal::Types21 type; +}; +template +struct Types { + typedef internal::Types22 type; +}; +template +struct Types { + typedef internal::Types23 type; +}; +template +struct Types { + typedef internal::Types24 type; +}; +template +struct Types { + typedef internal::Types25 type; +}; +template +struct Types { + typedef internal::Types26 type; +}; +template +struct Types { + typedef internal::Types27 type; +}; +template +struct Types { + typedef internal::Types28 type; +}; +template +struct Types { + typedef internal::Types29 type; +}; +template +struct Types { + typedef internal::Types30 type; +}; +template +struct Types { + typedef internal::Types31 type; +}; +template +struct Types { + typedef internal::Types32 type; +}; +template +struct Types { + typedef internal::Types33 type; +}; +template +struct Types { + typedef internal::Types34 type; +}; +template +struct Types { + typedef internal::Types35 type; +}; +template +struct Types { + typedef internal::Types36 type; +}; +template +struct Types { + typedef internal::Types37 type; +}; +template +struct Types { + typedef internal::Types38 type; +}; +template +struct Types { + typedef internal::Types39 type; +}; +template +struct Types { + typedef internal::Types40 type; +}; +template +struct Types { + typedef internal::Types41 type; +}; +template +struct Types { + typedef internal::Types42 type; +}; +template +struct Types { + typedef internal::Types43 type; +}; +template +struct Types { + typedef internal::Types44 type; +}; +template +struct Types { + typedef internal::Types45 type; +}; +template +struct Types { + typedef internal::Types46 type; +}; +template +struct Types { + typedef internal::Types47 type; +}; +template +struct Types { + typedef internal::Types48 type; +}; +template +struct Types { + typedef internal::Types49 type; +}; + +namespace internal { + +# define GTEST_TEMPLATE_ template class + +// The template "selector" struct TemplateSel is used to +// represent Tmpl, which must be a class template with one type +// parameter, as a type. TemplateSel::Bind::type is defined +// as the type Tmpl. This allows us to actually instantiate the +// template "selected" by TemplateSel. +// +// This trick is necessary for simulating typedef for class templates, +// which C++ doesn't support directly. +template +struct TemplateSel { + template + struct Bind { + typedef Tmpl type; + }; +}; + +# define GTEST_BIND_(TmplSel, T) \ + TmplSel::template Bind::type + +// A unique struct template used as the default value for the +// arguments of class template Templates. This allows us to simulate +// variadic templates (e.g. Templates, Templates, +// and etc), which C++ doesn't support directly. +template +struct NoneT {}; + +// The following family of struct and struct templates are used to +// represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except +// for Templates0, every struct in the family has two member types: +// Head for the selector of the first template in the list, and Tail +// for the rest of the list. + +// The empty template list. +struct Templates0 {}; + +// Template lists of length 1, 2, 3, and so on. + +template +struct Templates1 { + typedef TemplateSel Head; + typedef Templates0 Tail; +}; +template +struct Templates2 { + typedef TemplateSel Head; + typedef Templates1 Tail; +}; + +template +struct Templates3 { + typedef TemplateSel Head; + typedef Templates2 Tail; +}; + +template +struct Templates4 { + typedef TemplateSel Head; + typedef Templates3 Tail; +}; + +template +struct Templates5 { + typedef TemplateSel Head; + typedef Templates4 Tail; +}; + +template +struct Templates6 { + typedef TemplateSel Head; + typedef Templates5 Tail; +}; + +template +struct Templates7 { + typedef TemplateSel Head; + typedef Templates6 Tail; +}; + +template +struct Templates8 { + typedef TemplateSel Head; + typedef Templates7 Tail; +}; + +template +struct Templates9 { + typedef TemplateSel Head; + typedef Templates8 Tail; +}; + +template +struct Templates10 { + typedef TemplateSel Head; + typedef Templates9 Tail; +}; + +template +struct Templates11 { + typedef TemplateSel Head; + typedef Templates10 Tail; +}; + +template +struct Templates12 { + typedef TemplateSel Head; + typedef Templates11 Tail; +}; + +template +struct Templates13 { + typedef TemplateSel Head; + typedef Templates12 Tail; +}; + +template +struct Templates14 { + typedef TemplateSel Head; + typedef Templates13 Tail; +}; + +template +struct Templates15 { + typedef TemplateSel Head; + typedef Templates14 Tail; +}; + +template +struct Templates16 { + typedef TemplateSel Head; + typedef Templates15 Tail; +}; + +template +struct Templates17 { + typedef TemplateSel Head; + typedef Templates16 Tail; +}; + +template +struct Templates18 { + typedef TemplateSel Head; + typedef Templates17 Tail; +}; + +template +struct Templates19 { + typedef TemplateSel Head; + typedef Templates18 Tail; +}; + +template +struct Templates20 { + typedef TemplateSel Head; + typedef Templates19 Tail; +}; + +template +struct Templates21 { + typedef TemplateSel Head; + typedef Templates20 Tail; +}; + +template +struct Templates22 { + typedef TemplateSel Head; + typedef Templates21 Tail; +}; + +template +struct Templates23 { + typedef TemplateSel Head; + typedef Templates22 Tail; +}; + +template +struct Templates24 { + typedef TemplateSel Head; + typedef Templates23 Tail; +}; + +template +struct Templates25 { + typedef TemplateSel Head; + typedef Templates24 Tail; +}; + +template +struct Templates26 { + typedef TemplateSel Head; + typedef Templates25 Tail; +}; + +template +struct Templates27 { + typedef TemplateSel Head; + typedef Templates26 Tail; +}; + +template +struct Templates28 { + typedef TemplateSel Head; + typedef Templates27 Tail; +}; + +template +struct Templates29 { + typedef TemplateSel Head; + typedef Templates28 Tail; +}; + +template +struct Templates30 { + typedef TemplateSel Head; + typedef Templates29 Tail; +}; + +template +struct Templates31 { + typedef TemplateSel Head; + typedef Templates30 Tail; +}; + +template +struct Templates32 { + typedef TemplateSel Head; + typedef Templates31 Tail; +}; + +template +struct Templates33 { + typedef TemplateSel Head; + typedef Templates32 Tail; +}; + +template +struct Templates34 { + typedef TemplateSel Head; + typedef Templates33 Tail; +}; + +template +struct Templates35 { + typedef TemplateSel Head; + typedef Templates34 Tail; +}; + +template +struct Templates36 { + typedef TemplateSel Head; + typedef Templates35 Tail; +}; + +template +struct Templates37 { + typedef TemplateSel Head; + typedef Templates36 Tail; +}; + +template +struct Templates38 { + typedef TemplateSel Head; + typedef Templates37 Tail; +}; + +template +struct Templates39 { + typedef TemplateSel Head; + typedef Templates38 Tail; +}; + +template +struct Templates40 { + typedef TemplateSel Head; + typedef Templates39 Tail; +}; + +template +struct Templates41 { + typedef TemplateSel Head; + typedef Templates40 Tail; +}; + +template +struct Templates42 { + typedef TemplateSel Head; + typedef Templates41 Tail; +}; + +template +struct Templates43 { + typedef TemplateSel Head; + typedef Templates42 Tail; +}; + +template +struct Templates44 { + typedef TemplateSel Head; + typedef Templates43 Tail; +}; + +template +struct Templates45 { + typedef TemplateSel Head; + typedef Templates44 Tail; +}; + +template +struct Templates46 { + typedef TemplateSel Head; + typedef Templates45 Tail; +}; + +template +struct Templates47 { + typedef TemplateSel Head; + typedef Templates46 Tail; +}; + +template +struct Templates48 { + typedef TemplateSel Head; + typedef Templates47 Tail; +}; + +template +struct Templates49 { + typedef TemplateSel Head; + typedef Templates48 Tail; +}; + +template +struct Templates50 { + typedef TemplateSel Head; + typedef Templates49 Tail; +}; + + +// We don't want to require the users to write TemplatesN<...> directly, +// as that would require them to count the length. Templates<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Templates +// will appear as Templates in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Templates, and Google Test will translate +// that to TemplatesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Templates template. +template +struct Templates { + typedef Templates50 type; +}; + +template <> +struct Templates { + typedef Templates0 type; +}; +template +struct Templates { + typedef Templates1 type; +}; +template +struct Templates { + typedef Templates2 type; +}; +template +struct Templates { + typedef Templates3 type; +}; +template +struct Templates { + typedef Templates4 type; +}; +template +struct Templates { + typedef Templates5 type; +}; +template +struct Templates { + typedef Templates6 type; +}; +template +struct Templates { + typedef Templates7 type; +}; +template +struct Templates { + typedef Templates8 type; +}; +template +struct Templates { + typedef Templates9 type; +}; +template +struct Templates { + typedef Templates10 type; +}; +template +struct Templates { + typedef Templates11 type; +}; +template +struct Templates { + typedef Templates12 type; +}; +template +struct Templates { + typedef Templates13 type; +}; +template +struct Templates { + typedef Templates14 type; +}; +template +struct Templates { + typedef Templates15 type; +}; +template +struct Templates { + typedef Templates16 type; +}; +template +struct Templates { + typedef Templates17 type; +}; +template +struct Templates { + typedef Templates18 type; +}; +template +struct Templates { + typedef Templates19 type; +}; +template +struct Templates { + typedef Templates20 type; +}; +template +struct Templates { + typedef Templates21 type; +}; +template +struct Templates { + typedef Templates22 type; +}; +template +struct Templates { + typedef Templates23 type; +}; +template +struct Templates { + typedef Templates24 type; +}; +template +struct Templates { + typedef Templates25 type; +}; +template +struct Templates { + typedef Templates26 type; +}; +template +struct Templates { + typedef Templates27 type; +}; +template +struct Templates { + typedef Templates28 type; +}; +template +struct Templates { + typedef Templates29 type; +}; +template +struct Templates { + typedef Templates30 type; +}; +template +struct Templates { + typedef Templates31 type; +}; +template +struct Templates { + typedef Templates32 type; +}; +template +struct Templates { + typedef Templates33 type; +}; +template +struct Templates { + typedef Templates34 type; +}; +template +struct Templates { + typedef Templates35 type; +}; +template +struct Templates { + typedef Templates36 type; +}; +template +struct Templates { + typedef Templates37 type; +}; +template +struct Templates { + typedef Templates38 type; +}; +template +struct Templates { + typedef Templates39 type; +}; +template +struct Templates { + typedef Templates40 type; +}; +template +struct Templates { + typedef Templates41 type; +}; +template +struct Templates { + typedef Templates42 type; +}; +template +struct Templates { + typedef Templates43 type; +}; +template +struct Templates { + typedef Templates44 type; +}; +template +struct Templates { + typedef Templates45 type; +}; +template +struct Templates { + typedef Templates46 type; +}; +template +struct Templates { + typedef Templates47 type; +}; +template +struct Templates { + typedef Templates48 type; +}; +template +struct Templates { + typedef Templates49 type; +}; + +// The TypeList template makes it possible to use either a single type +// or a Types<...> list in TYPED_TEST_CASE() and +// INSTANTIATE_TYPED_TEST_CASE_P(). + +template +struct TypeList { typedef Types1 type; }; + +template +struct TypeList > { + typedef typename Types::type type; +}; + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ diff --git a/libs/gtest/include/gtest/internal/gtest-type-util.h.pump b/libs/gtest/include/gtest/internal/gtest-type-util.h.pump new file mode 100644 index 000000000..27f331dea --- /dev/null +++ b/libs/gtest/include/gtest/internal/gtest-type-util.h.pump @@ -0,0 +1,296 @@ +$$ -*- mode: c++; -*- +$var n = 50 $$ Maximum length of type lists we want to support. +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Type utilities needed for implementing typed and type-parameterized +// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently we support at most $n types in a list, and at most $n +// type-parameterized tests in one type-parameterized test case. +// Please contact googletestframework@googlegroups.com if you need +// more. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ + +#include "gtest/internal/gtest-port.h" +#include "gtest/internal/gtest-string.h" + +// #ifdef __GNUC__ is too general here. It is possible to use gcc without using +// libstdc++ (which is where cxxabi.h comes from). +# ifdef __GLIBCXX__ +# include +# elif defined(__HP_aCC) +# include +# endif // __GLIBCXX__ + +namespace testing { +namespace internal { + +// GetTypeName() returns a human-readable name of type T. +// NB: This function is also used in Google Mock, so don't move it inside of +// the typed-test-only section below. +template +String GetTypeName() { +# if GTEST_HAS_RTTI + + const char* const name = typeid(T).name(); +# if defined(__GLIBCXX__) || defined(__HP_aCC) + int status = 0; + // gcc's implementation of typeid(T).name() mangles the type name, + // so we have to demangle it. +# ifdef __GLIBCXX__ + using abi::__cxa_demangle; +# endif // __GLIBCXX__ + char* const readable_name = __cxa_demangle(name, 0, 0, &status); + const String name_str(status == 0 ? readable_name : name); + free(readable_name); + return name_str; +# else + return name; +# endif // __GLIBCXX__ || __HP_aCC + +# else + + return ""; + +# endif // GTEST_HAS_RTTI +} + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// AssertyTypeEq::type is defined iff T1 and T2 are the same +// type. This can be used as a compile-time assertion to ensure that +// two types are equal. + +template +struct AssertTypeEq; + +template +struct AssertTypeEq { + typedef bool type; +}; + +// A unique type used as the default value for the arguments of class +// template Types. This allows us to simulate variadic templates +// (e.g. Types, Type, and etc), which C++ doesn't +// support directly. +struct None {}; + +// The following family of struct and struct templates are used to +// represent type lists. In particular, TypesN +// represents a type list with N types (T1, T2, ..., and TN) in it. +// Except for Types0, every struct in the family has two member types: +// Head for the first type in the list, and Tail for the rest of the +// list. + +// The empty type list. +struct Types0 {}; + +// Type lists of length 1, 2, 3, and so on. + +template +struct Types1 { + typedef T1 Head; + typedef Types0 Tail; +}; + +$range i 2..n + +$for i [[ +$range j 1..i +$range k 2..i +template <$for j, [[typename T$j]]> +struct Types$i { + typedef T1 Head; + typedef Types$(i-1)<$for k, [[T$k]]> Tail; +}; + + +]] + +} // namespace internal + +// We don't want to require the users to write TypesN<...> directly, +// as that would require them to count the length. Types<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Types +// will appear as Types in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Types, and Google Test will translate +// that to TypesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Types template. + +$range i 1..n +template <$for i, [[typename T$i = internal::None]]> +struct Types { + typedef internal::Types$n<$for i, [[T$i]]> type; +}; + +template <> +struct Types<$for i, [[internal::None]]> { + typedef internal::Types0 type; +}; + +$range i 1..n-1 +$for i [[ +$range j 1..i +$range k i+1..n +template <$for j, [[typename T$j]]> +struct Types<$for j, [[T$j]]$for k[[, internal::None]]> { + typedef internal::Types$i<$for j, [[T$j]]> type; +}; + +]] + +namespace internal { + +# define GTEST_TEMPLATE_ template class + +// The template "selector" struct TemplateSel is used to +// represent Tmpl, which must be a class template with one type +// parameter, as a type. TemplateSel::Bind::type is defined +// as the type Tmpl. This allows us to actually instantiate the +// template "selected" by TemplateSel. +// +// This trick is necessary for simulating typedef for class templates, +// which C++ doesn't support directly. +template +struct TemplateSel { + template + struct Bind { + typedef Tmpl type; + }; +}; + +# define GTEST_BIND_(TmplSel, T) \ + TmplSel::template Bind::type + +// A unique struct template used as the default value for the +// arguments of class template Templates. This allows us to simulate +// variadic templates (e.g. Templates, Templates, +// and etc), which C++ doesn't support directly. +template +struct NoneT {}; + +// The following family of struct and struct templates are used to +// represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except +// for Templates0, every struct in the family has two member types: +// Head for the selector of the first template in the list, and Tail +// for the rest of the list. + +// The empty template list. +struct Templates0 {}; + +// Template lists of length 1, 2, 3, and so on. + +template +struct Templates1 { + typedef TemplateSel Head; + typedef Templates0 Tail; +}; + +$range i 2..n + +$for i [[ +$range j 1..i +$range k 2..i +template <$for j, [[GTEST_TEMPLATE_ T$j]]> +struct Templates$i { + typedef TemplateSel Head; + typedef Templates$(i-1)<$for k, [[T$k]]> Tail; +}; + + +]] + +// We don't want to require the users to write TemplatesN<...> directly, +// as that would require them to count the length. Templates<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Templates +// will appear as Templates in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Templates, and Google Test will translate +// that to TemplatesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Templates template. + +$range i 1..n +template <$for i, [[GTEST_TEMPLATE_ T$i = NoneT]]> +struct Templates { + typedef Templates$n<$for i, [[T$i]]> type; +}; + +template <> +struct Templates<$for i, [[NoneT]]> { + typedef Templates0 type; +}; + +$range i 1..n-1 +$for i [[ +$range j 1..i +$range k i+1..n +template <$for j, [[GTEST_TEMPLATE_ T$j]]> +struct Templates<$for j, [[T$j]]$for k[[, NoneT]]> { + typedef Templates$i<$for j, [[T$j]]> type; +}; + +]] + +// The TypeList template makes it possible to use either a single type +// or a Types<...> list in TYPED_TEST_CASE() and +// INSTANTIATE_TYPED_TEST_CASE_P(). + +template +struct TypeList { typedef Types1 type; }; + + +$range i 1..n +template <$for i, [[typename T$i]]> +struct TypeList > { + typedef typename Types<$for i, [[T$i]]>::type type; +}; + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ diff --git a/libs/gtest/src/gtest-all.cc b/libs/gtest/src/gtest-all.cc new file mode 100644 index 000000000..0a9cee522 --- /dev/null +++ b/libs/gtest/src/gtest-all.cc @@ -0,0 +1,48 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// +// Google C++ Testing Framework (Google Test) +// +// Sometimes it's desirable to build Google Test by compiling a single file. +// This file serves this purpose. + +// This line ensures that gtest.h can be compiled on its own, even +// when it's fused. +#include "gtest/gtest.h" + +// The following lines pull in the real gtest *.cc files. +#include "src/gtest.cc" +#include "src/gtest-death-test.cc" +#include "src/gtest-filepath.cc" +#include "src/gtest-port.cc" +#include "src/gtest-printers.cc" +#include "src/gtest-test-part.cc" +#include "src/gtest-typed-test.cc" diff --git a/libs/gtest/src/gtest-death-test.cc b/libs/gtest/src/gtest-death-test.cc new file mode 100644 index 000000000..8b2e4131c --- /dev/null +++ b/libs/gtest/src/gtest-death-test.cc @@ -0,0 +1,1234 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) +// +// This file implements death tests. + +#include "gtest/gtest-death-test.h" +#include "gtest/internal/gtest-port.h" + +#if GTEST_HAS_DEATH_TEST + +# if GTEST_OS_MAC +# include +# endif // GTEST_OS_MAC + +# include +# include +# include +# include + +# if GTEST_OS_WINDOWS +# include +# else +# include +# include +# endif // GTEST_OS_WINDOWS + +#endif // GTEST_HAS_DEATH_TEST + +#include "gtest/gtest-message.h" +#include "gtest/internal/gtest-string.h" + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +namespace testing { + +// Constants. + +// The default death test style. +static const char kDefaultDeathTestStyle[] = "fast"; + +GTEST_DEFINE_string_( + death_test_style, + internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), + "Indicates how to run a death test in a forked child process: " + "\"threadsafe\" (child process re-executes the test binary " + "from the beginning, running only the specific death test) or " + "\"fast\" (child process runs the death test immediately " + "after forking)."); + +GTEST_DEFINE_bool_( + death_test_use_fork, + internal::BoolFromGTestEnv("death_test_use_fork", false), + "Instructs to use fork()/_exit() instead of clone() in death tests. " + "Ignored and always uses fork() on POSIX systems where clone() is not " + "implemented. Useful when running under valgrind or similar tools if " + "those do not support clone(). Valgrind 3.3.1 will just fail if " + "it sees an unsupported combination of clone() flags. " + "It is not recommended to use this flag w/o valgrind though it will " + "work in 99% of the cases. Once valgrind is fixed, this flag will " + "most likely be removed."); + +namespace internal { +GTEST_DEFINE_string_( + internal_run_death_test, "", + "Indicates the file, line number, temporal index of " + "the single death test to run, and a file descriptor to " + "which a success code may be sent, all separated by " + "colons. This flag is specified if and only if the current " + "process is a sub-process launched for running a thread-safe " + "death test. FOR INTERNAL USE ONLY."); +} // namespace internal + +#if GTEST_HAS_DEATH_TEST + +// ExitedWithCode constructor. +ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { +} + +// ExitedWithCode function-call operator. +bool ExitedWithCode::operator()(int exit_status) const { +# if GTEST_OS_WINDOWS + + return exit_status == exit_code_; + +# else + + return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; + +# endif // GTEST_OS_WINDOWS +} + +# if !GTEST_OS_WINDOWS +// KilledBySignal constructor. +KilledBySignal::KilledBySignal(int signum) : signum_(signum) { +} + +// KilledBySignal function-call operator. +bool KilledBySignal::operator()(int exit_status) const { + return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; +} +# endif // !GTEST_OS_WINDOWS + +namespace internal { + +// Utilities needed for death tests. + +// Generates a textual description of a given exit code, in the format +// specified by wait(2). +static String ExitSummary(int exit_code) { + Message m; + +# if GTEST_OS_WINDOWS + + m << "Exited with exit status " << exit_code; + +# else + + if (WIFEXITED(exit_code)) { + m << "Exited with exit status " << WEXITSTATUS(exit_code); + } else if (WIFSIGNALED(exit_code)) { + m << "Terminated by signal " << WTERMSIG(exit_code); + } +# ifdef WCOREDUMP + if (WCOREDUMP(exit_code)) { + m << " (core dumped)"; + } +# endif +# endif // GTEST_OS_WINDOWS + + return m.GetString(); +} + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +bool ExitedUnsuccessfully(int exit_status) { + return !ExitedWithCode(0)(exit_status); +} + +# if !GTEST_OS_WINDOWS +// Generates a textual failure message when a death test finds more than +// one thread running, or cannot determine the number of threads, prior +// to executing the given statement. It is the responsibility of the +// caller not to pass a thread_count of 1. +static String DeathTestThreadWarning(size_t thread_count) { + Message msg; + msg << "Death tests use fork(), which is unsafe particularly" + << " in a threaded context. For this test, " << GTEST_NAME_ << " "; + if (thread_count == 0) + msg << "couldn't detect the number of threads."; + else + msg << "detected " << thread_count << " threads."; + return msg.GetString(); +} +# endif // !GTEST_OS_WINDOWS + +// Flag characters for reporting a death test that did not die. +static const char kDeathTestLived = 'L'; +static const char kDeathTestReturned = 'R'; +static const char kDeathTestThrew = 'T'; +static const char kDeathTestInternalError = 'I'; + +// An enumeration describing all of the possible ways that a death test can +// conclude. DIED means that the process died while executing the test +// code; LIVED means that process lived beyond the end of the test code; +// RETURNED means that the test statement attempted to execute a return +// statement, which is not allowed; THREW means that the test statement +// returned control by throwing an exception. IN_PROGRESS means the test +// has not yet concluded. +// TODO(vladl@google.com): Unify names and possibly values for +// AbortReason, DeathTestOutcome, and flag characters above. +enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; + +// Routine for aborting the program which is safe to call from an +// exec-style death test child process, in which case the error +// message is propagated back to the parent process. Otherwise, the +// message is simply printed to stderr. In either case, the program +// then exits with status 1. +void DeathTestAbort(const String& message) { + // On a POSIX system, this function may be called from a threadsafe-style + // death test child process, which operates on a very small stack. Use + // the heap for any additional non-minuscule memory requirements. + const InternalRunDeathTestFlag* const flag = + GetUnitTestImpl()->internal_run_death_test_flag(); + if (flag != NULL) { + FILE* parent = posix::FDOpen(flag->write_fd(), "w"); + fputc(kDeathTestInternalError, parent); + fprintf(parent, "%s", message.c_str()); + fflush(parent); + _exit(1); + } else { + fprintf(stderr, "%s", message.c_str()); + fflush(stderr); + posix::Abort(); + } +} + +// A replacement for CHECK that calls DeathTestAbort if the assertion +// fails. +# define GTEST_DEATH_TEST_CHECK_(expression) \ + do { \ + if (!::testing::internal::IsTrue(expression)) { \ + DeathTestAbort(::testing::internal::String::Format( \ + "CHECK failed: File %s, line %d: %s", \ + __FILE__, __LINE__, #expression)); \ + } \ + } while (::testing::internal::AlwaysFalse()) + +// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for +// evaluating any system call that fulfills two conditions: it must return +// -1 on failure, and set errno to EINTR when it is interrupted and +// should be tried again. The macro expands to a loop that repeatedly +// evaluates the expression as long as it evaluates to -1 and sets +// errno to EINTR. If the expression evaluates to -1 but errno is +// something other than EINTR, DeathTestAbort is called. +# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ + do { \ + int gtest_retval; \ + do { \ + gtest_retval = (expression); \ + } while (gtest_retval == -1 && errno == EINTR); \ + if (gtest_retval == -1) { \ + DeathTestAbort(::testing::internal::String::Format( \ + "CHECK failed: File %s, line %d: %s != -1", \ + __FILE__, __LINE__, #expression)); \ + } \ + } while (::testing::internal::AlwaysFalse()) + +// Returns the message describing the last system error in errno. +String GetLastErrnoDescription() { + return String(errno == 0 ? "" : posix::StrError(errno)); +} + +// This is called from a death test parent process to read a failure +// message from the death test child process and log it with the FATAL +// severity. On Windows, the message is read from a pipe handle. On other +// platforms, it is read from a file descriptor. +static void FailFromInternalError(int fd) { + Message error; + char buffer[256]; + int num_read; + + do { + while ((num_read = posix::Read(fd, buffer, 255)) > 0) { + buffer[num_read] = '\0'; + error << buffer; + } + } while (num_read == -1 && errno == EINTR); + + if (num_read == 0) { + GTEST_LOG_(FATAL) << error.GetString(); + } else { + const int last_error = errno; + GTEST_LOG_(FATAL) << "Error while reading death test internal: " + << GetLastErrnoDescription() << " [" << last_error << "]"; + } +} + +// Death test constructor. Increments the running death test count +// for the current test. +DeathTest::DeathTest() { + TestInfo* const info = GetUnitTestImpl()->current_test_info(); + if (info == NULL) { + DeathTestAbort("Cannot run a death test outside of a TEST or " + "TEST_F construct"); + } +} + +// Creates and returns a death test by dispatching to the current +// death test factory. +bool DeathTest::Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test) { + return GetUnitTestImpl()->death_test_factory()->Create( + statement, regex, file, line, test); +} + +const char* DeathTest::LastMessage() { + return last_death_test_message_.c_str(); +} + +void DeathTest::set_last_death_test_message(const String& message) { + last_death_test_message_ = message; +} + +String DeathTest::last_death_test_message_; + +// Provides cross platform implementation for some death functionality. +class DeathTestImpl : public DeathTest { + protected: + DeathTestImpl(const char* a_statement, const RE* a_regex) + : statement_(a_statement), + regex_(a_regex), + spawned_(false), + status_(-1), + outcome_(IN_PROGRESS), + read_fd_(-1), + write_fd_(-1) {} + + // read_fd_ is expected to be closed and cleared by a derived class. + ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } + + void Abort(AbortReason reason); + virtual bool Passed(bool status_ok); + + const char* statement() const { return statement_; } + const RE* regex() const { return regex_; } + bool spawned() const { return spawned_; } + void set_spawned(bool is_spawned) { spawned_ = is_spawned; } + int status() const { return status_; } + void set_status(int a_status) { status_ = a_status; } + DeathTestOutcome outcome() const { return outcome_; } + void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } + int read_fd() const { return read_fd_; } + void set_read_fd(int fd) { read_fd_ = fd; } + int write_fd() const { return write_fd_; } + void set_write_fd(int fd) { write_fd_ = fd; } + + // Called in the parent process only. Reads the result code of the death + // test child process via a pipe, interprets it to set the outcome_ + // member, and closes read_fd_. Outputs diagnostics and terminates in + // case of unexpected codes. + void ReadAndInterpretStatusByte(); + + private: + // The textual content of the code this object is testing. This class + // doesn't own this string and should not attempt to delete it. + const char* const statement_; + // The regular expression which test output must match. DeathTestImpl + // doesn't own this object and should not attempt to delete it. + const RE* const regex_; + // True if the death test child process has been successfully spawned. + bool spawned_; + // The exit status of the child process. + int status_; + // How the death test concluded. + DeathTestOutcome outcome_; + // Descriptor to the read end of the pipe to the child process. It is + // always -1 in the child process. The child keeps its write end of the + // pipe in write_fd_. + int read_fd_; + // Descriptor to the child's write end of the pipe to the parent process. + // It is always -1 in the parent process. The parent keeps its end of the + // pipe in read_fd_. + int write_fd_; +}; + +// Called in the parent process only. Reads the result code of the death +// test child process via a pipe, interprets it to set the outcome_ +// member, and closes read_fd_. Outputs diagnostics and terminates in +// case of unexpected codes. +void DeathTestImpl::ReadAndInterpretStatusByte() { + char flag; + int bytes_read; + + // The read() here blocks until data is available (signifying the + // failure of the death test) or until the pipe is closed (signifying + // its success), so it's okay to call this in the parent before + // the child process has exited. + do { + bytes_read = posix::Read(read_fd(), &flag, 1); + } while (bytes_read == -1 && errno == EINTR); + + if (bytes_read == 0) { + set_outcome(DIED); + } else if (bytes_read == 1) { + switch (flag) { + case kDeathTestReturned: + set_outcome(RETURNED); + break; + case kDeathTestThrew: + set_outcome(THREW); + break; + case kDeathTestLived: + set_outcome(LIVED); + break; + case kDeathTestInternalError: + FailFromInternalError(read_fd()); // Does not return. + break; + default: + GTEST_LOG_(FATAL) << "Death test child process reported " + << "unexpected status byte (" + << static_cast(flag) << ")"; + } + } else { + GTEST_LOG_(FATAL) << "Read from death test child process failed: " + << GetLastErrnoDescription(); + } + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); + set_read_fd(-1); +} + +// Signals that the death test code which should have exited, didn't. +// Should be called only in a death test child process. +// Writes a status byte to the child's status file descriptor, then +// calls _exit(1). +void DeathTestImpl::Abort(AbortReason reason) { + // The parent process considers the death test to be a failure if + // it finds any data in our pipe. So, here we write a single flag byte + // to the pipe, then exit. + const char status_ch = + reason == TEST_DID_NOT_DIE ? kDeathTestLived : + reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; + + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); + // We are leaking the descriptor here because on some platforms (i.e., + // when built as Windows DLL), destructors of global objects will still + // run after calling _exit(). On such systems, write_fd_ will be + // indirectly closed from the destructor of UnitTestImpl, causing double + // close if it is also closed here. On debug configurations, double close + // may assert. As there are no in-process buffers to flush here, we are + // relying on the OS to close the descriptor after the process terminates + // when the destructors are not run. + _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) +} + +// Returns an indented copy of stderr output for a death test. +// This makes distinguishing death test output lines from regular log lines +// much easier. +static ::std::string FormatDeathTestOutput(const ::std::string& output) { + ::std::string ret; + for (size_t at = 0; ; ) { + const size_t line_end = output.find('\n', at); + ret += "[ DEATH ] "; + if (line_end == ::std::string::npos) { + ret += output.substr(at); + break; + } + ret += output.substr(at, line_end + 1 - at); + at = line_end + 1; + } + return ret; +} + +// Assesses the success or failure of a death test, using both private +// members which have previously been set, and one argument: +// +// Private data members: +// outcome: An enumeration describing how the death test +// concluded: DIED, LIVED, THREW, or RETURNED. The death test +// fails in the latter three cases. +// status: The exit status of the child process. On *nix, it is in the +// in the format specified by wait(2). On Windows, this is the +// value supplied to the ExitProcess() API or a numeric code +// of the exception that terminated the program. +// regex: A regular expression object to be applied to +// the test's captured standard error output; the death test +// fails if it does not match. +// +// Argument: +// status_ok: true if exit_status is acceptable in the context of +// this particular death test, which fails if it is false +// +// Returns true iff all of the above conditions are met. Otherwise, the +// first failing condition, in the order given above, is the one that is +// reported. Also sets the last death test message string. +bool DeathTestImpl::Passed(bool status_ok) { + if (!spawned()) + return false; + + const String error_message = GetCapturedStderr(); + + bool success = false; + Message buffer; + + buffer << "Death test: " << statement() << "\n"; + switch (outcome()) { + case LIVED: + buffer << " Result: failed to die.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case THREW: + buffer << " Result: threw an exception.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case RETURNED: + buffer << " Result: illegal return in test statement.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case DIED: + if (status_ok) { + const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); + if (matched) { + success = true; + } else { + buffer << " Result: died but not with expected error.\n" + << " Expected: " << regex()->pattern() << "\n" + << "Actual msg:\n" << FormatDeathTestOutput(error_message); + } + } else { + buffer << " Result: died but not with expected exit code:\n" + << " " << ExitSummary(status()) << "\n" + << "Actual msg:\n" << FormatDeathTestOutput(error_message); + } + break; + case IN_PROGRESS: + default: + GTEST_LOG_(FATAL) + << "DeathTest::Passed somehow called before conclusion of test"; + } + + DeathTest::set_last_death_test_message(buffer.GetString()); + return success; +} + +# if GTEST_OS_WINDOWS +// WindowsDeathTest implements death tests on Windows. Due to the +// specifics of starting new processes on Windows, death tests there are +// always threadsafe, and Google Test considers the +// --gtest_death_test_style=fast setting to be equivalent to +// --gtest_death_test_style=threadsafe there. +// +// A few implementation notes: Like the Linux version, the Windows +// implementation uses pipes for child-to-parent communication. But due to +// the specifics of pipes on Windows, some extra steps are required: +// +// 1. The parent creates a communication pipe and stores handles to both +// ends of it. +// 2. The parent starts the child and provides it with the information +// necessary to acquire the handle to the write end of the pipe. +// 3. The child acquires the write end of the pipe and signals the parent +// using a Windows event. +// 4. Now the parent can release the write end of the pipe on its side. If +// this is done before step 3, the object's reference count goes down to +// 0 and it is destroyed, preventing the child from acquiring it. The +// parent now has to release it, or read operations on the read end of +// the pipe will not return when the child terminates. +// 5. The parent reads child's output through the pipe (outcome code and +// any possible error messages) from the pipe, and its stderr and then +// determines whether to fail the test. +// +// Note: to distinguish Win32 API calls from the local method and function +// calls, the former are explicitly resolved in the global namespace. +// +class WindowsDeathTest : public DeathTestImpl { + public: + WindowsDeathTest(const char* a_statement, + const RE* a_regex, + const char* file, + int line) + : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + virtual TestRole AssumeRole(); + + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; + // Handle to the write end of the pipe to the child process. + AutoHandle write_handle_; + // Child process handle. + AutoHandle child_handle_; + // Event the child process uses to signal the parent that it has + // acquired the handle to the write end of the pipe. After seeing this + // event the parent can release its own handles to make sure its + // ReadFile() calls return when the child terminates. + AutoHandle event_handle_; +}; + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int WindowsDeathTest::Wait() { + if (!spawned()) + return 0; + + // Wait until the child either signals that it has acquired the write end + // of the pipe or it dies. + const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; + switch (::WaitForMultipleObjects(2, + wait_handles, + FALSE, // Waits for any of the handles. + INFINITE)) { + case WAIT_OBJECT_0: + case WAIT_OBJECT_0 + 1: + break; + default: + GTEST_DEATH_TEST_CHECK_(false); // Should not get here. + } + + // The child has acquired the write end of the pipe or exited. + // We release the handle on our side and continue. + write_handle_.Reset(); + event_handle_.Reset(); + + ReadAndInterpretStatusByte(); + + // Waits for the child process to exit if it haven't already. This + // returns immediately if the child has already exited, regardless of + // whether previous calls to WaitForMultipleObjects synchronized on this + // handle or not. + GTEST_DEATH_TEST_CHECK_( + WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), + INFINITE)); + DWORD status_code; + GTEST_DEATH_TEST_CHECK_( + ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); + child_handle_.Reset(); + set_status(static_cast(status_code)); + return status(); +} + +// The AssumeRole process for a Windows death test. It creates a child +// process with the same executable as the current process to run the +// death test. The child process is given the --gtest_filter and +// --gtest_internal_run_death_test flags such that it knows to run the +// current death test only. +DeathTest::TestRole WindowsDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + // ParseInternalRunDeathTestFlag() has performed all the necessary + // processing. + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + // WindowsDeathTest uses an anonymous pipe to communicate results of + // a death test. + SECURITY_ATTRIBUTES handles_are_inheritable = { + sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + HANDLE read_handle, write_handle; + GTEST_DEATH_TEST_CHECK_( + ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, + 0) // Default buffer size. + != FALSE); + set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), + O_RDONLY)); + write_handle_.Reset(write_handle); + event_handle_.Reset(::CreateEvent( + &handles_are_inheritable, + TRUE, // The event will automatically reset to non-signaled state. + FALSE, // The initial state is non-signalled. + NULL)); // The even is unnamed. + GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); + const String filter_flag = String::Format("--%s%s=%s.%s", + GTEST_FLAG_PREFIX_, kFilterFlag, + info->test_case_name(), + info->name()); + const String internal_flag = String::Format( + "--%s%s=%s|%d|%d|%u|%Iu|%Iu", + GTEST_FLAG_PREFIX_, + kInternalRunDeathTestFlag, + file_, line_, + death_test_index, + static_cast(::GetCurrentProcessId()), + // size_t has the same with as pointers on both 32-bit and 64-bit + // Windows platforms. + // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. + reinterpret_cast(write_handle), + reinterpret_cast(event_handle_.Get())); + + char executable_path[_MAX_PATH + 1]; // NOLINT + GTEST_DEATH_TEST_CHECK_( + _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, + executable_path, + _MAX_PATH)); + + String command_line = String::Format("%s %s \"%s\"", + ::GetCommandLineA(), + filter_flag.c_str(), + internal_flag.c_str()); + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // Flush the log buffers since the log streams are shared with the child. + FlushInfoLog(); + + // The child process will share the standard handles with the parent. + STARTUPINFOA startup_info; + memset(&startup_info, 0, sizeof(STARTUPINFO)); + startup_info.dwFlags = STARTF_USESTDHANDLES; + startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); + startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); + startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); + + PROCESS_INFORMATION process_info; + GTEST_DEATH_TEST_CHECK_(::CreateProcessA( + executable_path, + const_cast(command_line.c_str()), + NULL, // Retuned process handle is not inheritable. + NULL, // Retuned thread handle is not inheritable. + TRUE, // Child inherits all inheritable handles (for write_handle_). + 0x0, // Default creation flags. + NULL, // Inherit the parent's environment. + UnitTest::GetInstance()->original_working_dir(), + &startup_info, + &process_info) != FALSE); + child_handle_.Reset(process_info.hProcess); + ::CloseHandle(process_info.hThread); + set_spawned(true); + return OVERSEE_TEST; +} +# else // We are not on Windows. + +// ForkingDeathTest provides implementations for most of the abstract +// methods of the DeathTest interface. Only the AssumeRole method is +// left undefined. +class ForkingDeathTest : public DeathTestImpl { + public: + ForkingDeathTest(const char* statement, const RE* regex); + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + + protected: + void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } + + private: + // PID of child process during death test; 0 in the child process itself. + pid_t child_pid_; +}; + +// Constructs a ForkingDeathTest. +ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) + : DeathTestImpl(a_statement, a_regex), + child_pid_(-1) {} + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int ForkingDeathTest::Wait() { + if (!spawned()) + return 0; + + ReadAndInterpretStatusByte(); + + int status_value; + GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); + set_status(status_value); + return status_value; +} + +// A concrete death test class that forks, then immediately runs the test +// in the child process. +class NoExecDeathTest : public ForkingDeathTest { + public: + NoExecDeathTest(const char* a_statement, const RE* a_regex) : + ForkingDeathTest(a_statement, a_regex) { } + virtual TestRole AssumeRole(); +}; + +// The AssumeRole process for a fork-and-run death test. It implements a +// straightforward fork, with a simple pipe to transmit the status byte. +DeathTest::TestRole NoExecDeathTest::AssumeRole() { + const size_t thread_count = GetThreadCount(); + if (thread_count != 1) { + GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); + + DeathTest::set_last_death_test_message(""); + CaptureStderr(); + // When we fork the process below, the log file buffers are copied, but the + // file descriptors are shared. We flush all log files here so that closing + // the file descriptors in the child process doesn't throw off the + // synchronization between descriptors and buffers in the parent process. + // This is as close to the fork as possible to avoid a race condition in case + // there are multiple threads running before the death test, and another + // thread writes to the log file. + FlushInfoLog(); + + const pid_t child_pid = fork(); + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + set_child_pid(child_pid); + if (child_pid == 0) { + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); + set_write_fd(pipe_fd[1]); + // Redirects all logging to stderr in the child process to prevent + // concurrent writes to the log files. We capture stderr in the parent + // process and append the child process' output to a log. + LogToStderr(); + // Event forwarding to the listeners of event listener API mush be shut + // down in death test subprocesses. + GetUnitTestImpl()->listeners()->SuppressEventForwarding(); + return EXECUTE_TEST; + } else { + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); + set_read_fd(pipe_fd[0]); + set_spawned(true); + return OVERSEE_TEST; + } +} + +// A concrete death test class that forks and re-executes the main +// program from the beginning, with command-line flags set that cause +// only this specific death test to be run. +class ExecDeathTest : public ForkingDeathTest { + public: + ExecDeathTest(const char* a_statement, const RE* a_regex, + const char* file, int line) : + ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } + virtual TestRole AssumeRole(); + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; +}; + +// Utility class for accumulating command-line arguments. +class Arguments { + public: + Arguments() { + args_.push_back(NULL); + } + + ~Arguments() { + for (std::vector::iterator i = args_.begin(); i != args_.end(); + ++i) { + free(*i); + } + } + void AddArgument(const char* argument) { + args_.insert(args_.end() - 1, posix::StrDup(argument)); + } + + template + void AddArguments(const ::std::vector& arguments) { + for (typename ::std::vector::const_iterator i = arguments.begin(); + i != arguments.end(); + ++i) { + args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); + } + } + char* const* Argv() { + return &args_[0]; + } + private: + std::vector args_; +}; + +// A struct that encompasses the arguments to the child process of a +// threadsafe-style death test process. +struct ExecDeathTestArgs { + char* const* argv; // Command-line arguments for the child's call to exec + int close_fd; // File descriptor to close; the read end of a pipe +}; + +# if GTEST_OS_MAC +inline char** GetEnviron() { + // When Google Test is built as a framework on MacOS X, the environ variable + // is unavailable. Apple's documentation (man environ) recommends using + // _NSGetEnviron() instead. + return *_NSGetEnviron(); +} +# else +// Some POSIX platforms expect you to declare environ. extern "C" makes +// it reside in the global namespace. +extern "C" char** environ; +inline char** GetEnviron() { return environ; } +# endif // GTEST_OS_MAC + +// The main function for a threadsafe-style death test child process. +// This function is called in a clone()-ed process and thus must avoid +// any potentially unsafe operations like malloc or libc functions. +static int ExecDeathTestChildMain(void* child_arg) { + ExecDeathTestArgs* const args = static_cast(child_arg); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); + + // We need to execute the test program in the same environment where + // it was originally invoked. Therefore we change to the original + // working directory first. + const char* const original_dir = + UnitTest::GetInstance()->original_working_dir(); + // We can safely call chdir() as it's a direct system call. + if (chdir(original_dir) != 0) { + DeathTestAbort(String::Format("chdir(\"%s\") failed: %s", + original_dir, + GetLastErrnoDescription().c_str())); + return EXIT_FAILURE; + } + + // We can safely call execve() as it's a direct system call. We + // cannot use execvp() as it's a libc function and thus potentially + // unsafe. Since execve() doesn't search the PATH, the user must + // invoke the test program via a valid path that contains at least + // one path separator. + execve(args->argv[0], args->argv, GetEnviron()); + DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s", + args->argv[0], + original_dir, + GetLastErrnoDescription().c_str())); + return EXIT_FAILURE; +} + +// Two utility routines that together determine the direction the stack +// grows. +// This could be accomplished more elegantly by a single recursive +// function, but we want to guard against the unlikely possibility of +// a smart compiler optimizing the recursion away. +// +// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining +// StackLowerThanAddress into StackGrowsDown, which then doesn't give +// correct answer. +bool StackLowerThanAddress(const void* ptr) GTEST_NO_INLINE_; +bool StackLowerThanAddress(const void* ptr) { + int dummy; + return &dummy < ptr; +} + +bool StackGrowsDown() { + int dummy; + return StackLowerThanAddress(&dummy); +} + +// A threadsafe implementation of fork(2) for threadsafe-style death tests +// that uses clone(2). It dies with an error message if anything goes +// wrong. +static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { + ExecDeathTestArgs args = { argv, close_fd }; + pid_t child_pid = -1; + +# if GTEST_HAS_CLONE + const bool use_fork = GTEST_FLAG(death_test_use_fork); + + if (!use_fork) { + static const bool stack_grows_down = StackGrowsDown(); + const size_t stack_size = getpagesize(); + // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. + void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); + void* const stack_top = + static_cast(stack) + (stack_grows_down ? stack_size : 0); + + child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); + + GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); + } +# else + const bool use_fork = true; +# endif // GTEST_HAS_CLONE + + if (use_fork && (child_pid = fork()) == 0) { + ExecDeathTestChildMain(&args); + _exit(0); + } + + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + return child_pid; +} + +// The AssumeRole process for a fork-and-exec death test. It re-executes the +// main program from the beginning, setting the --gtest_filter +// and --gtest_internal_run_death_test flags to cause only the current +// death test to be re-run. +DeathTest::TestRole ExecDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); + // Clear the close-on-exec flag on the write end of the pipe, lest + // it be closed when the child process does an exec: + GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); + + const String filter_flag = + String::Format("--%s%s=%s.%s", + GTEST_FLAG_PREFIX_, kFilterFlag, + info->test_case_name(), info->name()); + const String internal_flag = + String::Format("--%s%s=%s|%d|%d|%d", + GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, + file_, line_, death_test_index, pipe_fd[1]); + Arguments args; + args.AddArguments(GetArgvs()); + args.AddArgument(filter_flag.c_str()); + args.AddArgument(internal_flag.c_str()); + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // See the comment in NoExecDeathTest::AssumeRole for why the next line + // is necessary. + FlushInfoLog(); + + const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); + set_child_pid(child_pid); + set_read_fd(pipe_fd[0]); + set_spawned(true); + return OVERSEE_TEST; +} + +# endif // !GTEST_OS_WINDOWS + +// Creates a concrete DeathTest-derived class that depends on the +// --gtest_death_test_style flag, and sets the pointer pointed to +// by the "test" argument to its address. If the test should be +// skipped, sets that pointer to NULL. Returns true, unless the +// flag is set to an invalid value. +bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, + const char* file, int line, + DeathTest** test) { + UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const int death_test_index = impl->current_test_info() + ->increment_death_test_count(); + + if (flag != NULL) { + if (death_test_index > flag->index()) { + DeathTest::set_last_death_test_message(String::Format( + "Death test count (%d) somehow exceeded expected maximum (%d)", + death_test_index, flag->index())); + return false; + } + + if (!(flag->file() == file && flag->line() == line && + flag->index() == death_test_index)) { + *test = NULL; + return true; + } + } + +# if GTEST_OS_WINDOWS + + if (GTEST_FLAG(death_test_style) == "threadsafe" || + GTEST_FLAG(death_test_style) == "fast") { + *test = new WindowsDeathTest(statement, regex, file, line); + } + +# else + + if (GTEST_FLAG(death_test_style) == "threadsafe") { + *test = new ExecDeathTest(statement, regex, file, line); + } else if (GTEST_FLAG(death_test_style) == "fast") { + *test = new NoExecDeathTest(statement, regex); + } + +# endif // GTEST_OS_WINDOWS + + else { // NOLINT - this is more readable than unbalanced brackets inside #if. + DeathTest::set_last_death_test_message(String::Format( + "Unknown death test style \"%s\" encountered", + GTEST_FLAG(death_test_style).c_str())); + return false; + } + + return true; +} + +// Splits a given string on a given delimiter, populating a given +// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have +// ::std::string, so we can use it here. +static void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest) { + ::std::vector< ::std::string> parsed; + ::std::string::size_type pos = 0; + while (::testing::internal::AlwaysTrue()) { + const ::std::string::size_type colon = str.find(delimiter, pos); + if (colon == ::std::string::npos) { + parsed.push_back(str.substr(pos)); + break; + } else { + parsed.push_back(str.substr(pos, colon - pos)); + pos = colon + 1; + } + } + dest->swap(parsed); +} + +# if GTEST_OS_WINDOWS +// Recreates the pipe and event handles from the provided parameters, +// signals the event, and returns a file descriptor wrapped around the pipe +// handle. This function is called in the child process only. +int GetStatusFileDescriptor(unsigned int parent_process_id, + size_t write_handle_as_size_t, + size_t event_handle_as_size_t) { + AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, + FALSE, // Non-inheritable. + parent_process_id)); + if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { + DeathTestAbort(String::Format("Unable to open parent process %u", + parent_process_id)); + } + + // TODO(vladl@google.com): Replace the following check with a + // compile-time assertion when available. + GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); + + const HANDLE write_handle = + reinterpret_cast(write_handle_as_size_t); + HANDLE dup_write_handle; + + // The newly initialized handle is accessible only in in the parent + // process. To obtain one accessible within the child, we need to use + // DuplicateHandle. + if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, + ::GetCurrentProcess(), &dup_write_handle, + 0x0, // Requested privileges ignored since + // DUPLICATE_SAME_ACCESS is used. + FALSE, // Request non-inheritable handler. + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort(String::Format( + "Unable to duplicate the pipe handle %Iu from the parent process %u", + write_handle_as_size_t, parent_process_id)); + } + + const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); + HANDLE dup_event_handle; + + if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, + ::GetCurrentProcess(), &dup_event_handle, + 0x0, + FALSE, + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort(String::Format( + "Unable to duplicate the event handle %Iu from the parent process %u", + event_handle_as_size_t, parent_process_id)); + } + + const int write_fd = + ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); + if (write_fd == -1) { + DeathTestAbort(String::Format( + "Unable to convert pipe handle %Iu to a file descriptor", + write_handle_as_size_t)); + } + + // Signals the parent that the write end of the pipe has been acquired + // so the parent can release its own write end. + ::SetEvent(dup_event_handle); + + return write_fd; +} +# endif // GTEST_OS_WINDOWS + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { + if (GTEST_FLAG(internal_run_death_test) == "") return NULL; + + // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we + // can use it here. + int line = -1; + int index = -1; + ::std::vector< ::std::string> fields; + SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); + int write_fd = -1; + +# if GTEST_OS_WINDOWS + + unsigned int parent_process_id = 0; + size_t write_handle_as_size_t = 0; + size_t event_handle_as_size_t = 0; + + if (fields.size() != 6 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &parent_process_id) + || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) + || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { + DeathTestAbort(String::Format( + "Bad --gtest_internal_run_death_test flag: %s", + GTEST_FLAG(internal_run_death_test).c_str())); + } + write_fd = GetStatusFileDescriptor(parent_process_id, + write_handle_as_size_t, + event_handle_as_size_t); +# else + + if (fields.size() != 4 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &write_fd)) { + DeathTestAbort(String::Format( + "Bad --gtest_internal_run_death_test flag: %s", + GTEST_FLAG(internal_run_death_test).c_str())); + } + +# endif // GTEST_OS_WINDOWS + + return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); +} + +} // namespace internal + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace testing diff --git a/libs/gtest/src/gtest-filepath.cc b/libs/gtest/src/gtest-filepath.cc new file mode 100644 index 000000000..91b257138 --- /dev/null +++ b/libs/gtest/src/gtest-filepath.cc @@ -0,0 +1,380 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: keith.ray@gmail.com (Keith Ray) + +#include "gtest/internal/gtest-filepath.h" +#include "gtest/internal/gtest-port.h" + +#include + +#if GTEST_OS_WINDOWS_MOBILE +# include +#elif GTEST_OS_WINDOWS +# include +# include +#elif GTEST_OS_SYMBIAN || GTEST_OS_NACL +// Symbian OpenC and NaCl have PATH_MAX in sys/syslimits.h +# include +#else +# include +# include // Some Linux distributions define PATH_MAX here. +#endif // GTEST_OS_WINDOWS_MOBILE + +#if GTEST_OS_WINDOWS +# define GTEST_PATH_MAX_ _MAX_PATH +#elif defined(PATH_MAX) +# define GTEST_PATH_MAX_ PATH_MAX +#elif defined(_XOPEN_PATH_MAX) +# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX +#else +# define GTEST_PATH_MAX_ _POSIX_PATH_MAX +#endif // GTEST_OS_WINDOWS + +#include "gtest/internal/gtest-string.h" + +namespace testing { +namespace internal { + +#if GTEST_OS_WINDOWS +// On Windows, '\\' is the standard path separator, but many tools and the +// Windows API also accept '/' as an alternate path separator. Unless otherwise +// noted, a file path can contain either kind of path separators, or a mixture +// of them. +const char kPathSeparator = '\\'; +const char kAlternatePathSeparator = '/'; +const char kPathSeparatorString[] = "\\"; +const char kAlternatePathSeparatorString[] = "/"; +# if GTEST_OS_WINDOWS_MOBILE +// Windows CE doesn't have a current directory. You should not use +// the current directory in tests on Windows CE, but this at least +// provides a reasonable fallback. +const char kCurrentDirectoryString[] = "\\"; +// Windows CE doesn't define INVALID_FILE_ATTRIBUTES +const DWORD kInvalidFileAttributes = 0xffffffff; +# else +const char kCurrentDirectoryString[] = ".\\"; +# endif // GTEST_OS_WINDOWS_MOBILE +#else +const char kPathSeparator = '/'; +const char kPathSeparatorString[] = "/"; +const char kCurrentDirectoryString[] = "./"; +#endif // GTEST_OS_WINDOWS + +// Returns whether the given character is a valid path separator. +static bool IsPathSeparator(char c) { +#if GTEST_HAS_ALT_PATH_SEP_ + return (c == kPathSeparator) || (c == kAlternatePathSeparator); +#else + return c == kPathSeparator; +#endif +} + +// Returns the current working directory, or "" if unsuccessful. +FilePath FilePath::GetCurrentDir() { +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE doesn't have a current directory, so we just return + // something reasonable. + return FilePath(kCurrentDirectoryString); +#elif GTEST_OS_WINDOWS + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; + return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); +#else + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; + return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Returns a copy of the FilePath with the case-insensitive extension removed. +// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns +// FilePath("dir/file"). If a case-insensitive extension is not +// found, returns a copy of the original FilePath. +FilePath FilePath::RemoveExtension(const char* extension) const { + String dot_extension(String::Format(".%s", extension)); + if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) { + return FilePath(String(pathname_.c_str(), pathname_.length() - 4)); + } + return *this; +} + +// Returns a pointer to the last occurence of a valid path separator in +// the FilePath. On Windows, for example, both '/' and '\' are valid path +// separators. Returns NULL if no path separator was found. +const char* FilePath::FindLastPathSeparator() const { + const char* const last_sep = strrchr(c_str(), kPathSeparator); +#if GTEST_HAS_ALT_PATH_SEP_ + const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); + // Comparing two pointers of which only one is NULL is undefined. + if (last_alt_sep != NULL && + (last_sep == NULL || last_alt_sep > last_sep)) { + return last_alt_sep; + } +#endif + return last_sep; +} + +// Returns a copy of the FilePath with the directory part removed. +// Example: FilePath("path/to/file").RemoveDirectoryName() returns +// FilePath("file"). If there is no directory part ("just_a_file"), it returns +// the FilePath unmodified. If there is no file part ("just_a_dir/") it +// returns an empty FilePath (""). +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveDirectoryName() const { + const char* const last_sep = FindLastPathSeparator(); + return last_sep ? FilePath(String(last_sep + 1)) : *this; +} + +// RemoveFileName returns the directory path with the filename removed. +// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". +// If the FilePath is "a_file" or "/a_file", RemoveFileName returns +// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does +// not have a file, like "just/a/dir/", it returns the FilePath unmodified. +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveFileName() const { + const char* const last_sep = FindLastPathSeparator(); + String dir; + if (last_sep) { + dir = String(c_str(), last_sep + 1 - c_str()); + } else { + dir = kCurrentDirectoryString; + } + return FilePath(dir); +} + +// Helper functions for naming files in a directory for xml output. + +// Given directory = "dir", base_name = "test", number = 0, +// extension = "xml", returns "dir/test.xml". If number is greater +// than zero (e.g., 12), returns "dir/test_12.xml". +// On Windows platform, uses \ as the separator rather than /. +FilePath FilePath::MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension) { + String file; + if (number == 0) { + file = String::Format("%s.%s", base_name.c_str(), extension); + } else { + file = String::Format("%s_%d.%s", base_name.c_str(), number, extension); + } + return ConcatPaths(directory, FilePath(file)); +} + +// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". +// On Windows, uses \ as the separator rather than /. +FilePath FilePath::ConcatPaths(const FilePath& directory, + const FilePath& relative_path) { + if (directory.IsEmpty()) + return relative_path; + const FilePath dir(directory.RemoveTrailingPathSeparator()); + return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator, + relative_path.c_str())); +} + +// Returns true if pathname describes something findable in the file-system, +// either a file, directory, or whatever. +bool FilePath::FileOrDirectoryExists() const { +#if GTEST_OS_WINDOWS_MOBILE + LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + return attributes != kInvalidFileAttributes; +#else + posix::StatStruct file_stat; + return posix::Stat(pathname_.c_str(), &file_stat) == 0; +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Returns true if pathname describes a directory in the file-system +// that exists. +bool FilePath::DirectoryExists() const { + bool result = false; +#if GTEST_OS_WINDOWS + // Don't strip off trailing separator if path is a root directory on + // Windows (like "C:\\"). + const FilePath& path(IsRootDirectory() ? *this : + RemoveTrailingPathSeparator()); +#else + const FilePath& path(*this); +#endif + +#if GTEST_OS_WINDOWS_MOBILE + LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + if ((attributes != kInvalidFileAttributes) && + (attributes & FILE_ATTRIBUTE_DIRECTORY)) { + result = true; + } +#else + posix::StatStruct file_stat; + result = posix::Stat(path.c_str(), &file_stat) == 0 && + posix::IsDir(file_stat); +#endif // GTEST_OS_WINDOWS_MOBILE + + return result; +} + +// Returns true if pathname describes a root directory. (Windows has one +// root directory per disk drive.) +bool FilePath::IsRootDirectory() const { +#if GTEST_OS_WINDOWS + // TODO(wan@google.com): on Windows a network share like + // \\server\share can be a root directory, although it cannot be the + // current directory. Handle this properly. + return pathname_.length() == 3 && IsAbsolutePath(); +#else + return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); +#endif +} + +// Returns true if pathname describes an absolute path. +bool FilePath::IsAbsolutePath() const { + const char* const name = pathname_.c_str(); +#if GTEST_OS_WINDOWS + return pathname_.length() >= 3 && + ((name[0] >= 'a' && name[0] <= 'z') || + (name[0] >= 'A' && name[0] <= 'Z')) && + name[1] == ':' && + IsPathSeparator(name[2]); +#else + return IsPathSeparator(name[0]); +#endif +} + +// Returns a pathname for a file that does not currently exist. The pathname +// will be directory/base_name.extension or +// directory/base_name_.extension if directory/base_name.extension +// already exists. The number will be incremented until a pathname is found +// that does not already exist. +// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. +// There could be a race condition if two or more processes are calling this +// function at the same time -- they could both pick the same filename. +FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension) { + FilePath full_pathname; + int number = 0; + do { + full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); + } while (full_pathname.FileOrDirectoryExists()); + return full_pathname; +} + +// Returns true if FilePath ends with a path separator, which indicates that +// it is intended to represent a directory. Returns false otherwise. +// This does NOT check that a directory (or file) actually exists. +bool FilePath::IsDirectory() const { + return !pathname_.empty() && + IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); +} + +// Create directories so that path exists. Returns true if successful or if +// the directories already exist; returns false if unable to create directories +// for any reason. +bool FilePath::CreateDirectoriesRecursively() const { + if (!this->IsDirectory()) { + return false; + } + + if (pathname_.length() == 0 || this->DirectoryExists()) { + return true; + } + + const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); + return parent.CreateDirectoriesRecursively() && this->CreateFolder(); +} + +// Create the directory so that path exists. Returns true if successful or +// if the directory already exists; returns false if unable to create the +// directory for any reason, including if the parent directory does not +// exist. Not named "CreateDirectory" because that's a macro on Windows. +bool FilePath::CreateFolder() const { +#if GTEST_OS_WINDOWS_MOBILE + FilePath removed_sep(this->RemoveTrailingPathSeparator()); + LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); + int result = CreateDirectory(unicode, NULL) ? 0 : -1; + delete [] unicode; +#elif GTEST_OS_WINDOWS + int result = _mkdir(pathname_.c_str()); +#else + int result = mkdir(pathname_.c_str(), 0777); +#endif // GTEST_OS_WINDOWS_MOBILE + + if (result == -1) { + return this->DirectoryExists(); // An error is OK if the directory exists. + } + return true; // No error. +} + +// If input name has a trailing separator character, remove it and return the +// name, otherwise return the name string unmodified. +// On Windows platform, uses \ as the separator, other platforms use /. +FilePath FilePath::RemoveTrailingPathSeparator() const { + return IsDirectory() + ? FilePath(String(pathname_.c_str(), pathname_.length() - 1)) + : *this; +} + +// Removes any redundant separators that might be in the pathname. +// For example, "bar///foo" becomes "bar/foo". Does not eliminate other +// redundancies that might be in a pathname involving "." or "..". +// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). +void FilePath::Normalize() { + if (pathname_.c_str() == NULL) { + pathname_ = ""; + return; + } + const char* src = pathname_.c_str(); + char* const dest = new char[pathname_.length() + 1]; + char* dest_ptr = dest; + memset(dest_ptr, 0, pathname_.length() + 1); + + while (*src != '\0') { + *dest_ptr = *src; + if (!IsPathSeparator(*src)) { + src++; + } else { +#if GTEST_HAS_ALT_PATH_SEP_ + if (*dest_ptr == kAlternatePathSeparator) { + *dest_ptr = kPathSeparator; + } +#endif + while (IsPathSeparator(*src)) + src++; + } + dest_ptr++; + } + *dest_ptr = '\0'; + pathname_ = dest; + delete[] dest; +} + +} // namespace internal +} // namespace testing diff --git a/libs/gtest/src/gtest-internal-inl.h b/libs/gtest/src/gtest-internal-inl.h new file mode 100644 index 000000000..65a2101a4 --- /dev/null +++ b/libs/gtest/src/gtest-internal-inl.h @@ -0,0 +1,1038 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Utility functions and classes used by the Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) +// +// This file contains purely Google Test's internal implementation. Please +// DO NOT #INCLUDE IT IN A USER PROGRAM. + +#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ +#define GTEST_SRC_GTEST_INTERNAL_INL_H_ + +// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is +// part of Google Test's implementation; otherwise it's undefined. +#if !GTEST_IMPLEMENTATION_ +// A user is trying to include this from his code - just say no. +# error "gtest-internal-inl.h is part of Google Test's internal implementation." +# error "It must not be included except by Google Test itself." +#endif // GTEST_IMPLEMENTATION_ + +#ifndef _WIN32_WCE +# include +#endif // !_WIN32_WCE +#include +#include // For strtoll/_strtoul64/malloc/free. +#include // For memmove. + +#include +#include +#include + +#include "gtest/internal/gtest-port.h" + +#if GTEST_OS_WINDOWS +# include // NOLINT +#endif // GTEST_OS_WINDOWS + +#include "gtest/gtest.h" // NOLINT +#include "gtest/gtest-spi.h" + +namespace testing { + +// Declares the flags. +// +// We don't want the users to modify this flag in the code, but want +// Google Test's own unit tests to be able to access it. Therefore we +// declare it here as opposed to in gtest.h. +GTEST_DECLARE_bool_(death_test_use_fork); + +namespace internal { + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; + +// Names of the flags (needed for parsing Google Test flags). +const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; +const char kBreakOnFailureFlag[] = "break_on_failure"; +const char kCatchExceptionsFlag[] = "catch_exceptions"; +const char kColorFlag[] = "color"; +const char kFilterFlag[] = "filter"; +const char kListTestsFlag[] = "list_tests"; +const char kOutputFlag[] = "output"; +const char kPrintTimeFlag[] = "print_time"; +const char kRandomSeedFlag[] = "random_seed"; +const char kRepeatFlag[] = "repeat"; +const char kShuffleFlag[] = "shuffle"; +const char kStackTraceDepthFlag[] = "stack_trace_depth"; +const char kStreamResultToFlag[] = "stream_result_to"; +const char kThrowOnFailureFlag[] = "throw_on_failure"; + +// A valid random seed must be in [1, kMaxRandomSeed]. +const int kMaxRandomSeed = 99999; + +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +GTEST_API_ extern bool g_help_flag; + +// Returns the current time in milliseconds. +GTEST_API_ TimeInMillis GetTimeInMillis(); + +// Returns true iff Google Test should use colors in the output. +GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); + +// Formats the given time in milliseconds as seconds. +GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); + +// Parses a string for an Int32 flag, in the form of "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +GTEST_API_ bool ParseInt32Flag( + const char* str, const char* flag, Int32* value); + +// Returns a random seed in range [1, kMaxRandomSeed] based on the +// given --gtest_random_seed flag value. +inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { + const unsigned int raw_seed = (random_seed_flag == 0) ? + static_cast(GetTimeInMillis()) : + static_cast(random_seed_flag); + + // Normalizes the actual seed to range [1, kMaxRandomSeed] such that + // it's easy to type. + const int normalized_seed = + static_cast((raw_seed - 1U) % + static_cast(kMaxRandomSeed)) + 1; + return normalized_seed; +} + +// Returns the first valid random seed after 'seed'. The behavior is +// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is +// considered to be 1. +inline int GetNextRandomSeed(int seed) { + GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) + << "Invalid random seed " << seed << " - must be in [1, " + << kMaxRandomSeed << "]."; + const int next_seed = seed + 1; + return (next_seed > kMaxRandomSeed) ? 1 : next_seed; +} + +// This class saves the values of all Google Test flags in its c'tor, and +// restores them in its d'tor. +class GTestFlagSaver { + public: + // The c'tor. + GTestFlagSaver() { + also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); + break_on_failure_ = GTEST_FLAG(break_on_failure); + catch_exceptions_ = GTEST_FLAG(catch_exceptions); + color_ = GTEST_FLAG(color); + death_test_style_ = GTEST_FLAG(death_test_style); + death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); + filter_ = GTEST_FLAG(filter); + internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); + list_tests_ = GTEST_FLAG(list_tests); + output_ = GTEST_FLAG(output); + print_time_ = GTEST_FLAG(print_time); + random_seed_ = GTEST_FLAG(random_seed); + repeat_ = GTEST_FLAG(repeat); + shuffle_ = GTEST_FLAG(shuffle); + stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); + stream_result_to_ = GTEST_FLAG(stream_result_to); + throw_on_failure_ = GTEST_FLAG(throw_on_failure); + } + + // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. + ~GTestFlagSaver() { + GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; + GTEST_FLAG(break_on_failure) = break_on_failure_; + GTEST_FLAG(catch_exceptions) = catch_exceptions_; + GTEST_FLAG(color) = color_; + GTEST_FLAG(death_test_style) = death_test_style_; + GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; + GTEST_FLAG(filter) = filter_; + GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; + GTEST_FLAG(list_tests) = list_tests_; + GTEST_FLAG(output) = output_; + GTEST_FLAG(print_time) = print_time_; + GTEST_FLAG(random_seed) = random_seed_; + GTEST_FLAG(repeat) = repeat_; + GTEST_FLAG(shuffle) = shuffle_; + GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; + GTEST_FLAG(stream_result_to) = stream_result_to_; + GTEST_FLAG(throw_on_failure) = throw_on_failure_; + } + private: + // Fields for saving the original values of flags. + bool also_run_disabled_tests_; + bool break_on_failure_; + bool catch_exceptions_; + String color_; + String death_test_style_; + bool death_test_use_fork_; + String filter_; + String internal_run_death_test_; + bool list_tests_; + String output_; + bool print_time_; + bool pretty_; + internal::Int32 random_seed_; + internal::Int32 repeat_; + bool shuffle_; + internal::Int32 stack_trace_depth_; + String stream_result_to_; + bool throw_on_failure_; +} GTEST_ATTRIBUTE_UNUSED_; + +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// The output buffer str must containt at least 32 characters. +// The function returns the address of the output buffer. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. +GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str); + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +GTEST_API_ String WideStringToUtf8(const wchar_t* str, int num_chars); + +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded(); + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (e.g., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +GTEST_API_ bool ShouldShard(const char* total_shards_str, + const char* shard_index_str, + bool in_subprocess_for_death_test); + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error and +// and aborts. +GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); + +// Given the total number of shards, the shard index, and the test id, +// returns true iff the test should be run on this shard. The test id is +// some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +GTEST_API_ bool ShouldRunTestOnShard( + int total_shards, int shard_index, int test_id); + +// STL container utilities. + +// Returns the number of elements in the given container that satisfy +// the given predicate. +template +inline int CountIf(const Container& c, Predicate predicate) { + // Implemented as an explicit loop since std::count_if() in libCstd on + // Solaris has a non-standard signature. + int count = 0; + for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) { + if (predicate(*it)) + ++count; + } + return count; +} + +// Applies a function/functor to each element in the container. +template +void ForEach(const Container& c, Functor functor) { + std::for_each(c.begin(), c.end(), functor); +} + +// Returns the i-th element of the vector, or default_value if i is not +// in range [0, v.size()). +template +inline E GetElementOr(const std::vector& v, int i, E default_value) { + return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; +} + +// Performs an in-place shuffle of a range of the vector's elements. +// 'begin' and 'end' are element indices as an STL-style range; +// i.e. [begin, end) are shuffled, where 'end' == size() means to +// shuffle to the end of the vector. +template +void ShuffleRange(internal::Random* random, int begin, int end, + std::vector* v) { + const int size = static_cast(v->size()); + GTEST_CHECK_(0 <= begin && begin <= size) + << "Invalid shuffle range start " << begin << ": must be in range [0, " + << size << "]."; + GTEST_CHECK_(begin <= end && end <= size) + << "Invalid shuffle range finish " << end << ": must be in range [" + << begin << ", " << size << "]."; + + // Fisher-Yates shuffle, from + // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle + for (int range_width = end - begin; range_width >= 2; range_width--) { + const int last_in_range = begin + range_width - 1; + const int selected = begin + random->Generate(range_width); + std::swap((*v)[selected], (*v)[last_in_range]); + } +} + +// Performs an in-place shuffle of the vector's elements. +template +inline void Shuffle(internal::Random* random, std::vector* v) { + ShuffleRange(random, 0, static_cast(v->size()), v); +} + +// A function for deleting an object. Handy for being used as a +// functor. +template +static void Delete(T* x) { + delete x; +} + +// A predicate that checks the key of a TestProperty against a known key. +// +// TestPropertyKeyIs is copyable. +class TestPropertyKeyIs { + public: + // Constructor. + // + // TestPropertyKeyIs has NO default constructor. + explicit TestPropertyKeyIs(const char* key) + : key_(key) {} + + // Returns true iff the test name of test property matches on key_. + bool operator()(const TestProperty& test_property) const { + return String(test_property.key()).Compare(key_) == 0; + } + + private: + String key_; +}; + +// Class UnitTestOptions. +// +// This class contains functions for processing options the user +// specifies when running the tests. It has only static members. +// +// In most cases, the user can specify an option using either an +// environment variable or a command line flag. E.g. you can set the +// test filter using either GTEST_FILTER or --gtest_filter. If both +// the variable and the flag are present, the latter overrides the +// former. +class GTEST_API_ UnitTestOptions { + public: + // Functions for processing the gtest_output flag. + + // Returns the output format, or "" for normal printed output. + static String GetOutputFormat(); + + // Returns the absolute path of the requested output file, or the + // default (test_detail.xml in the original working directory) if + // none was explicitly specified. + static String GetAbsolutePathToOutputFile(); + + // Functions for processing the gtest_filter flag. + + // Returns true iff the wildcard pattern matches the string. The + // first ':' or '\0' character in pattern marks the end of it. + // + // This recursive algorithm isn't very efficient, but is clear and + // works well enough for matching test names, which are short. + static bool PatternMatchesString(const char *pattern, const char *str); + + // Returns true iff the user-specified filter matches the test case + // name and the test name. + static bool FilterMatchesTest(const String &test_case_name, + const String &test_name); + +#if GTEST_OS_WINDOWS + // Function for supporting the gtest_catch_exception flag. + + // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the + // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. + // This function is useful as an __except condition. + static int GTestShouldProcessSEH(DWORD exception_code); +#endif // GTEST_OS_WINDOWS + + // Returns true if "name" matches the ':' separated list of glob-style + // filters in "filter". + static bool MatchesFilter(const String& name, const char* filter); +}; + +// Returns the current application's name, removing directory path if that +// is present. Used by UnitTestOptions::GetOutputFile. +GTEST_API_ FilePath GetCurrentExecutableName(); + +// The role interface for getting the OS stack trace as a string. +class OsStackTraceGetterInterface { + public: + OsStackTraceGetterInterface() {} + virtual ~OsStackTraceGetterInterface() {} + + // Returns the current OS stack trace as a String. Parameters: + // + // max_depth - the maximum number of stack frames to be included + // in the trace. + // skip_count - the number of top frames to be skipped; doesn't count + // against max_depth. + virtual String CurrentStackTrace(int max_depth, int skip_count) = 0; + + // UponLeavingGTest() should be called immediately before Google Test calls + // user code. It saves some information about the current stack that + // CurrentStackTrace() will use to find and hide Google Test stack frames. + virtual void UponLeavingGTest() = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); +}; + +// A working implementation of the OsStackTraceGetterInterface interface. +class OsStackTraceGetter : public OsStackTraceGetterInterface { + public: + OsStackTraceGetter() : caller_frame_(NULL) {} + virtual String CurrentStackTrace(int max_depth, int skip_count); + virtual void UponLeavingGTest(); + + // This string is inserted in place of stack frames that are part of + // Google Test's implementation. + static const char* const kElidedFramesMarker; + + private: + Mutex mutex_; // protects all internal state + + // We save the stack frame below the frame that calls user code. + // We do this because the address of the frame immediately below + // the user code changes between the call to UponLeavingGTest() + // and any calls to CurrentStackTrace() from within the user code. + void* caller_frame_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); +}; + +// Information about a Google Test trace point. +struct TraceInfo { + const char* file; + int line; + String message; +}; + +// This is the default global test part result reporter used in UnitTestImpl. +// This class should only be used by UnitTestImpl. +class DefaultGlobalTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. Reports the test part + // result in the current test. + virtual void ReportTestPartResult(const TestPartResult& result); + + private: + UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); +}; + +// This is the default per thread test part result reporter used in +// UnitTestImpl. This class should only be used by UnitTestImpl. +class DefaultPerThreadTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. The implementation just + // delegates to the current global test part result reporter of *unit_test_. + virtual void ReportTestPartResult(const TestPartResult& result); + + private: + UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); +}; + +// The private implementation of the UnitTest class. We don't protect +// the methods under a mutex, as this class is not accessible by a +// user and the UnitTest class that delegates work to this class does +// proper locking. +class GTEST_API_ UnitTestImpl { + public: + explicit UnitTestImpl(UnitTest* parent); + virtual ~UnitTestImpl(); + + // There are two different ways to register your own TestPartResultReporter. + // You can register your own repoter to listen either only for test results + // from the current thread or for results from all threads. + // By default, each per-thread test result repoter just passes a new + // TestPartResult to the global test result reporter, which registers the + // test part result for the currently running test. + + // Returns the global test part result reporter. + TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); + + // Sets the global test part result reporter. + void SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter); + + // Returns the test part result reporter for the current thread. + TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); + + // Sets the test part result reporter for the current thread. + void SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter); + + // Gets the number of successful test cases. + int successful_test_case_count() const; + + // Gets the number of failed test cases. + int failed_test_case_count() const; + + // Gets the number of all test cases. + int total_test_case_count() const; + + // Gets the number of all test cases that contain at least one test + // that should run. + int test_case_to_run_count() const; + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns true iff the unit test passed (i.e. all test cases passed). + bool Passed() const { return !Failed(); } + + // Returns true iff the unit test failed (i.e. some test case failed + // or something outside of all tests failed). + bool Failed() const { + return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); + } + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + const TestCase* GetTestCase(int i) const { + const int index = GetElementOr(test_case_indices_, i, -1); + return index < 0 ? NULL : test_cases_[i]; + } + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + TestCase* GetMutableTestCase(int i) { + const int index = GetElementOr(test_case_indices_, i, -1); + return index < 0 ? NULL : test_cases_[index]; + } + + // Provides access to the event listener list. + TestEventListeners* listeners() { return &listeners_; } + + // Returns the TestResult for the test that's currently running, or + // the TestResult for the ad hoc test if no test is running. + TestResult* current_test_result(); + + // Returns the TestResult for the ad hoc test. + const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } + + // Sets the OS stack trace getter. + // + // Does nothing if the input and the current OS stack trace getter + // are the same; otherwise, deletes the old getter and makes the + // input the current getter. + void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); + + // Returns the current OS stack trace getter if it is not NULL; + // otherwise, creates an OsStackTraceGetter, makes it the current + // getter, and returns it. + OsStackTraceGetterInterface* os_stack_trace_getter(); + + // Returns the current OS stack trace as a String. + // + // The maximum number of stack frames to be included is specified by + // the gtest_stack_trace_depth flag. The skip_count parameter + // specifies the number of top frames to be skipped, which doesn't + // count against the number of frames to be included. + // + // For example, if Foo() calls Bar(), which in turn calls + // CurrentOsStackTraceExceptTop(1), Foo() will be included in the + // trace but Bar() and CurrentOsStackTraceExceptTop() won't. + String CurrentOsStackTraceExceptTop(int skip_count); + + // Finds and returns a TestCase with the given name. If one doesn't + // exist, creates one and returns it. + // + // Arguments: + // + // test_case_name: name of the test case + // type_param: the name of the test's type parameter, or NULL if + // this is not a typed or a type-parameterized test. + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + TestCase* GetTestCase(const char* test_case_name, + const char* type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc); + + // Adds a TestInfo to the unit test. + // + // Arguments: + // + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + // test_info: the TestInfo object + void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc, + TestInfo* test_info) { + // In order to support thread-safe death tests, we need to + // remember the original working directory when the test program + // was first invoked. We cannot do this in RUN_ALL_TESTS(), as + // the user may have changed the current directory before calling + // RUN_ALL_TESTS(). Therefore we capture the current directory in + // AddTestInfo(), which is called to register a TEST or TEST_F + // before main() is reached. + if (original_working_dir_.IsEmpty()) { + original_working_dir_.Set(FilePath::GetCurrentDir()); + GTEST_CHECK_(!original_working_dir_.IsEmpty()) + << "Failed to get the current working directory."; + } + + GetTestCase(test_info->test_case_name(), + test_info->type_param(), + set_up_tc, + tear_down_tc)->AddTestInfo(test_info); + } + +#if GTEST_HAS_PARAM_TEST + // Returns ParameterizedTestCaseRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { + return parameterized_test_registry_; + } +#endif // GTEST_HAS_PARAM_TEST + + // Sets the TestCase object for the test that's currently running. + void set_current_test_case(TestCase* a_current_test_case) { + current_test_case_ = a_current_test_case; + } + + // Sets the TestInfo object for the test that's currently running. If + // current_test_info is NULL, the assertion results will be stored in + // ad_hoc_test_result_. + void set_current_test_info(TestInfo* a_current_test_info) { + current_test_info_ = a_current_test_info; + } + + // Registers all parameterized tests defined using TEST_P and + // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter + // combination. This method can be called more then once; it has guards + // protecting from registering the tests more then once. If + // value-parameterized tests are disabled, RegisterParameterizedTests is + // present but does nothing. + void RegisterParameterizedTests(); + + // Runs all tests in this UnitTest object, prints the result, and + // returns true if all tests are successful. If any exception is + // thrown during a test, this test is considered to be failed, but + // the rest of the tests will still be run. + bool RunAllTests(); + + // Clears the results of all tests, except the ad hoc tests. + void ClearNonAdHocTestResult() { + ForEach(test_cases_, TestCase::ClearTestCaseResult); + } + + // Clears the results of ad-hoc test assertions. + void ClearAdHocTestResult() { + ad_hoc_test_result_.Clear(); + } + + enum ReactionToSharding { + HONOR_SHARDING_PROTOCOL, + IGNORE_SHARDING_PROTOCOL + }; + + // Matches the full name of each test against the user-specified + // filter to decide whether the test should run, then records the + // result in each TestCase and TestInfo object. + // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests + // based on sharding variables in the environment. + // Returns the number of tests that should run. + int FilterTests(ReactionToSharding shard_tests); + + // Prints the names of the tests matching the user-specified filter flag. + void ListTestsMatchingFilter(); + + const TestCase* current_test_case() const { return current_test_case_; } + TestInfo* current_test_info() { return current_test_info_; } + const TestInfo* current_test_info() const { return current_test_info_; } + + // Returns the vector of environments that need to be set-up/torn-down + // before/after the tests are run. + std::vector& environments() { return environments_; } + + // Getters for the per-thread Google Test trace stack. + std::vector& gtest_trace_stack() { + return *(gtest_trace_stack_.pointer()); + } + const std::vector& gtest_trace_stack() const { + return gtest_trace_stack_.get(); + } + +#if GTEST_HAS_DEATH_TEST + void InitDeathTestSubprocessControlInfo() { + internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); + } + // Returns a pointer to the parsed --gtest_internal_run_death_test + // flag, or NULL if that flag was not specified. + // This information is useful only in a death test child process. + // Must not be called before a call to InitGoogleTest. + const InternalRunDeathTestFlag* internal_run_death_test_flag() const { + return internal_run_death_test_flag_.get(); + } + + // Returns a pointer to the current death test factory. + internal::DeathTestFactory* death_test_factory() { + return death_test_factory_.get(); + } + + void SuppressTestEventsIfInSubprocess(); + + friend class ReplaceDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + + // Initializes the event listener performing XML output as specified by + // UnitTestOptions. Must not be called before InitGoogleTest. + void ConfigureXmlOutput(); + +#if GTEST_CAN_STREAM_RESULTS_ + // Initializes the event listener for streaming test results to a socket. + // Must not be called before InitGoogleTest. + void ConfigureStreamingOutput(); +#endif + + // Performs initialization dependent upon flag values obtained in + // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to + // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest + // this function is also called from RunAllTests. Since this function can be + // called more than once, it has to be idempotent. + void PostFlagParsingInit(); + + // Gets the random seed used at the start of the current test iteration. + int random_seed() const { return random_seed_; } + + // Gets the random number generator. + internal::Random* random() { return &random_; } + + // Shuffles all test cases, and the tests within each test case, + // making sure that death tests are still run first. + void ShuffleTests(); + + // Restores the test cases and tests to their order before the first shuffle. + void UnshuffleTests(); + + // Returns the value of GTEST_FLAG(catch_exceptions) at the moment + // UnitTest::Run() starts. + bool catch_exceptions() const { return catch_exceptions_; } + + private: + friend class ::testing::UnitTest; + + // Used by UnitTest::Run() to capture the state of + // GTEST_FLAG(catch_exceptions) at the moment it starts. + void set_catch_exceptions(bool value) { catch_exceptions_ = value; } + + // The UnitTest object that owns this implementation object. + UnitTest* const parent_; + + // The working directory when the first TEST() or TEST_F() was + // executed. + internal::FilePath original_working_dir_; + + // The default test part result reporters. + DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; + DefaultPerThreadTestPartResultReporter + default_per_thread_test_part_result_reporter_; + + // Points to (but doesn't own) the global test part result reporter. + TestPartResultReporterInterface* global_test_part_result_repoter_; + + // Protects read and write access to global_test_part_result_reporter_. + internal::Mutex global_test_part_result_reporter_mutex_; + + // Points to (but doesn't own) the per-thread test part result reporter. + internal::ThreadLocal + per_thread_test_part_result_reporter_; + + // The vector of environments that need to be set-up/torn-down + // before/after the tests are run. + std::vector environments_; + + // The vector of TestCases in their original order. It owns the + // elements in the vector. + std::vector test_cases_; + + // Provides a level of indirection for the test case list to allow + // easy shuffling and restoring the test case order. The i-th + // element of this vector is the index of the i-th test case in the + // shuffled order. + std::vector test_case_indices_; + +#if GTEST_HAS_PARAM_TEST + // ParameterizedTestRegistry object used to register value-parameterized + // tests. + internal::ParameterizedTestCaseRegistry parameterized_test_registry_; + + // Indicates whether RegisterParameterizedTests() has been called already. + bool parameterized_tests_registered_; +#endif // GTEST_HAS_PARAM_TEST + + // Index of the last death test case registered. Initially -1. + int last_death_test_case_; + + // This points to the TestCase for the currently running test. It + // changes as Google Test goes through one test case after another. + // When no test is running, this is set to NULL and Google Test + // stores assertion results in ad_hoc_test_result_. Initially NULL. + TestCase* current_test_case_; + + // This points to the TestInfo for the currently running test. It + // changes as Google Test goes through one test after another. When + // no test is running, this is set to NULL and Google Test stores + // assertion results in ad_hoc_test_result_. Initially NULL. + TestInfo* current_test_info_; + + // Normally, a user only writes assertions inside a TEST or TEST_F, + // or inside a function called by a TEST or TEST_F. Since Google + // Test keeps track of which test is current running, it can + // associate such an assertion with the test it belongs to. + // + // If an assertion is encountered when no TEST or TEST_F is running, + // Google Test attributes the assertion result to an imaginary "ad hoc" + // test, and records the result in ad_hoc_test_result_. + TestResult ad_hoc_test_result_; + + // The list of event listeners that can be used to track events inside + // Google Test. + TestEventListeners listeners_; + + // The OS stack trace getter. Will be deleted when the UnitTest + // object is destructed. By default, an OsStackTraceGetter is used, + // but the user can set this field to use a custom getter if that is + // desired. + OsStackTraceGetterInterface* os_stack_trace_getter_; + + // True iff PostFlagParsingInit() has been called. + bool post_flag_parse_init_performed_; + + // The random number seed used at the beginning of the test run. + int random_seed_; + + // Our random number generator. + internal::Random random_; + + // How long the test took to run, in milliseconds. + TimeInMillis elapsed_time_; + +#if GTEST_HAS_DEATH_TEST + // The decomposed components of the gtest_internal_run_death_test flag, + // parsed when RUN_ALL_TESTS is called. + internal::scoped_ptr internal_run_death_test_flag_; + internal::scoped_ptr death_test_factory_; +#endif // GTEST_HAS_DEATH_TEST + + // A per-thread stack of traces created by the SCOPED_TRACE() macro. + internal::ThreadLocal > gtest_trace_stack_; + + // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests() + // starts. + bool catch_exceptions_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); +}; // class UnitTestImpl + +// Convenience function for accessing the global UnitTest +// implementation object. +inline UnitTestImpl* GetUnitTestImpl() { + return UnitTest::GetInstance()->impl(); +} + +#if GTEST_USES_SIMPLE_RE + +// Internal helper functions for implementing the simple regular +// expression matcher. +GTEST_API_ bool IsInSet(char ch, const char* str); +GTEST_API_ bool IsAsciiDigit(char ch); +GTEST_API_ bool IsAsciiPunct(char ch); +GTEST_API_ bool IsRepeat(char ch); +GTEST_API_ bool IsAsciiWhiteSpace(char ch); +GTEST_API_ bool IsAsciiWordChar(char ch); +GTEST_API_ bool IsValidEscape(char ch); +GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); +GTEST_API_ bool ValidateRegex(const char* regex); +GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); +GTEST_API_ bool MatchRepetitionAndRegexAtHead( + bool escaped, char ch, char repeat, const char* regex, const char* str); +GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); + +#endif // GTEST_USES_SIMPLE_RE + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); + +#if GTEST_HAS_DEATH_TEST + +// Returns the message describing the last system error, regardless of the +// platform. +GTEST_API_ String GetLastErrnoDescription(); + +# if GTEST_OS_WINDOWS +// Provides leak-safe Windows kernel handle ownership. +class AutoHandle { + public: + AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} + explicit AutoHandle(HANDLE handle) : handle_(handle) {} + + ~AutoHandle() { Reset(); } + + HANDLE Get() const { return handle_; } + void Reset() { Reset(INVALID_HANDLE_VALUE); } + void Reset(HANDLE handle) { + if (handle != handle_) { + if (handle_ != INVALID_HANDLE_VALUE) + ::CloseHandle(handle_); + handle_ = handle; + } + } + + private: + HANDLE handle_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); +}; +# endif // GTEST_OS_WINDOWS + +// Attempts to parse a string into a positive integer pointed to by the +// number parameter. Returns true if that is possible. +// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use +// it here. +template +bool ParseNaturalNumber(const ::std::string& str, Integer* number) { + // Fail fast if the given string does not begin with a digit; + // this bypasses strtoXXX's "optional leading whitespace and plus + // or minus sign" semantics, which are undesirable here. + if (str.empty() || !IsDigit(str[0])) { + return false; + } + errno = 0; + + char* end; + // BiggestConvertible is the largest integer type that system-provided + // string-to-number conversion routines can return. + +# if GTEST_OS_WINDOWS && !defined(__GNUC__) + + // MSVC and C++ Builder define __int64 instead of the standard long long. + typedef unsigned __int64 BiggestConvertible; + const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); + +# else + + typedef unsigned long long BiggestConvertible; // NOLINT + const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); + +# endif // GTEST_OS_WINDOWS && !defined(__GNUC__) + + const bool parse_success = *end == '\0' && errno == 0; + + // TODO(vladl@google.com): Convert this to compile time assertion when it is + // available. + GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); + + const Integer result = static_cast(parsed); + if (parse_success && static_cast(result) == parsed) { + *number = result; + return true; + } + return false; +} +#endif // GTEST_HAS_DEATH_TEST + +// TestResult contains some private methods that should be hidden from +// Google Test user but are required for testing. This class allow our tests +// to access them. +// +// This class is supplied only for the purpose of testing Google Test's own +// constructs. Do not use it in user tests, either directly or indirectly. +class TestResultAccessor { + public: + static void RecordProperty(TestResult* test_result, + const TestProperty& property) { + test_result->RecordProperty(property); + } + + static void ClearTestPartResults(TestResult* test_result) { + test_result->ClearTestPartResults(); + } + + static const std::vector& test_part_results( + const TestResult& test_result) { + return test_result.test_part_results(); + } +}; + +} // namespace internal +} // namespace testing + +#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ diff --git a/libs/gtest/src/gtest-port.cc b/libs/gtest/src/gtest-port.cc new file mode 100644 index 000000000..b860d4812 --- /dev/null +++ b/libs/gtest/src/gtest-port.cc @@ -0,0 +1,746 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#include "gtest/internal/gtest-port.h" + +#include +#include +#include +#include + +#if GTEST_OS_WINDOWS_MOBILE +# include // For TerminateProcess() +#elif GTEST_OS_WINDOWS +# include +# include +#else +# include +#endif // GTEST_OS_WINDOWS_MOBILE + +#if GTEST_OS_MAC +# include +# include +# include +#endif // GTEST_OS_MAC + +#include "gtest/gtest-spi.h" +#include "gtest/gtest-message.h" +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-string.h" + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +namespace testing { +namespace internal { + +#if defined(_MSC_VER) || defined(__BORLANDC__) +// MSVC and C++Builder do not provide a definition of STDERR_FILENO. +const int kStdOutFileno = 1; +const int kStdErrFileno = 2; +#else +const int kStdOutFileno = STDOUT_FILENO; +const int kStdErrFileno = STDERR_FILENO; +#endif // _MSC_VER + +#if GTEST_OS_MAC + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + const task_t task = mach_task_self(); + mach_msg_type_number_t thread_count; + thread_act_array_t thread_list; + const kern_return_t status = task_threads(task, &thread_list, &thread_count); + if (status == KERN_SUCCESS) { + // task_threads allocates resources in thread_list and we need to free them + // to avoid leaks. + vm_deallocate(task, + reinterpret_cast(thread_list), + sizeof(thread_t) * thread_count); + return static_cast(thread_count); + } else { + return 0; + } +} + +#else + +size_t GetThreadCount() { + // There's no portable way to detect the number of threads, so we just + // return 0 to indicate that we cannot detect it. + return 0; +} + +#endif // GTEST_OS_MAC + +#if GTEST_USES_POSIX_RE + +// Implements RE. Currently only needed for death tests. + +RE::~RE() { + if (is_valid_) { + // regfree'ing an invalid regex might crash because the content + // of the regex is undefined. Since the regex's are essentially + // the same, one cannot be valid (or invalid) without the other + // being so too. + regfree(&partial_regex_); + regfree(&full_regex_); + } + free(const_cast(pattern_)); +} + +// Returns true iff regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.full_regex_, str, 1, &match, 0) == 0; +} + +// Returns true iff regular expression re matches a substring of str +// (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = posix::StrDup(regex); + + // Reserves enough bytes to hold the regular expression used for a + // full match. + const size_t full_regex_len = strlen(regex) + 10; + char* const full_pattern = new char[full_regex_len]; + + snprintf(full_pattern, full_regex_len, "^(%s)$", regex); + is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; + // We want to call regcomp(&partial_regex_, ...) even if the + // previous expression returns false. Otherwise partial_regex_ may + // not be properly initialized can may cause trouble when it's + // freed. + // + // Some implementation of POSIX regex (e.g. on at least some + // versions of Cygwin) doesn't accept the empty string as a valid + // regex. We change it to an equivalent form "()" to be safe. + if (is_valid_) { + const char* const partial_regex = (*regex == '\0') ? "()" : regex; + is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; + } + EXPECT_TRUE(is_valid_) + << "Regular expression \"" << regex + << "\" is not a valid POSIX Extended regular expression."; + + delete[] full_pattern; +} + +#elif GTEST_USES_SIMPLE_RE + +// Returns true iff ch appears anywhere in str (excluding the +// terminating '\0' character). +bool IsInSet(char ch, const char* str) { + return ch != '\0' && strchr(str, ch) != NULL; +} + +// Returns true iff ch belongs to the given classification. Unlike +// similar functions in , these aren't affected by the +// current locale. +bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } +bool IsAsciiPunct(char ch) { + return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); +} +bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } +bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } +bool IsAsciiWordChar(char ch) { + return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || + ('0' <= ch && ch <= '9') || ch == '_'; +} + +// Returns true iff "\\c" is a supported escape sequence. +bool IsValidEscape(char c) { + return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); +} + +// Returns true iff the given atom (specified by escaped and pattern) +// matches ch. The result is undefined if the atom is invalid. +bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { + if (escaped) { // "\\p" where p is pattern_char. + switch (pattern_char) { + case 'd': return IsAsciiDigit(ch); + case 'D': return !IsAsciiDigit(ch); + case 'f': return ch == '\f'; + case 'n': return ch == '\n'; + case 'r': return ch == '\r'; + case 's': return IsAsciiWhiteSpace(ch); + case 'S': return !IsAsciiWhiteSpace(ch); + case 't': return ch == '\t'; + case 'v': return ch == '\v'; + case 'w': return IsAsciiWordChar(ch); + case 'W': return !IsAsciiWordChar(ch); + } + return IsAsciiPunct(pattern_char) && pattern_char == ch; + } + + return (pattern_char == '.' && ch != '\n') || pattern_char == ch; +} + +// Helper function used by ValidateRegex() to format error messages. +String FormatRegexSyntaxError(const char* regex, int index) { + return (Message() << "Syntax error at index " << index + << " in simple regular expression \"" << regex << "\": ").GetString(); +} + +// Generates non-fatal failures and returns false if regex is invalid; +// otherwise returns true. +bool ValidateRegex(const char* regex) { + if (regex == NULL) { + // TODO(wan@google.com): fix the source file location in the + // assertion failures to match where the regex is used in user + // code. + ADD_FAILURE() << "NULL is not a valid simple regular expression."; + return false; + } + + bool is_valid = true; + + // True iff ?, *, or + can follow the previous atom. + bool prev_repeatable = false; + for (int i = 0; regex[i]; i++) { + if (regex[i] == '\\') { // An escape sequence + i++; + if (regex[i] == '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "'\\' cannot appear at the end."; + return false; + } + + if (!IsValidEscape(regex[i])) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "invalid escape sequence \"\\" << regex[i] << "\"."; + is_valid = false; + } + prev_repeatable = true; + } else { // Not an escape sequence. + const char ch = regex[i]; + + if (ch == '^' && i > 0) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'^' can only appear at the beginning."; + is_valid = false; + } else if (ch == '$' && regex[i + 1] != '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'$' can only appear at the end."; + is_valid = false; + } else if (IsInSet(ch, "()[]{}|")) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' is unsupported."; + is_valid = false; + } else if (IsRepeat(ch) && !prev_repeatable) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' can only follow a repeatable token."; + is_valid = false; + } + + prev_repeatable = !IsInSet(ch, "^$?*+"); + } + } + + return is_valid; +} + +// Matches a repeated regex atom followed by a valid simple regular +// expression. The regex atom is defined as c if escaped is false, +// or \c otherwise. repeat is the repetition meta character (?, *, +// or +). The behavior is undefined if str contains too many +// characters to be indexable by size_t, in which case the test will +// probably time out anyway. We are fine with this limitation as +// std::string has it too. +bool MatchRepetitionAndRegexAtHead( + bool escaped, char c, char repeat, const char* regex, + const char* str) { + const size_t min_count = (repeat == '+') ? 1 : 0; + const size_t max_count = (repeat == '?') ? 1 : + static_cast(-1) - 1; + // We cannot call numeric_limits::max() as it conflicts with the + // max() macro on Windows. + + for (size_t i = 0; i <= max_count; ++i) { + // We know that the atom matches each of the first i characters in str. + if (i >= min_count && MatchRegexAtHead(regex, str + i)) { + // We have enough matches at the head, and the tail matches too. + // Since we only care about *whether* the pattern matches str + // (as opposed to *how* it matches), there is no need to find a + // greedy match. + return true; + } + if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) + return false; + } + return false; +} + +// Returns true iff regex matches a prefix of str. regex must be a +// valid simple regular expression and not start with "^", or the +// result is undefined. +bool MatchRegexAtHead(const char* regex, const char* str) { + if (*regex == '\0') // An empty regex matches a prefix of anything. + return true; + + // "$" only matches the end of a string. Note that regex being + // valid guarantees that there's nothing after "$" in it. + if (*regex == '$') + return *str == '\0'; + + // Is the first thing in regex an escape sequence? + const bool escaped = *regex == '\\'; + if (escaped) + ++regex; + if (IsRepeat(regex[1])) { + // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so + // here's an indirect recursion. It terminates as the regex gets + // shorter in each recursion. + return MatchRepetitionAndRegexAtHead( + escaped, regex[0], regex[1], regex + 2, str); + } else { + // regex isn't empty, isn't "$", and doesn't start with a + // repetition. We match the first atom of regex with the first + // character of str and recurse. + return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && + MatchRegexAtHead(regex + 1, str + 1); + } +} + +// Returns true iff regex matches any substring of str. regex must be +// a valid simple regular expression, or the result is undefined. +// +// The algorithm is recursive, but the recursion depth doesn't exceed +// the regex length, so we won't need to worry about running out of +// stack space normally. In rare cases the time complexity can be +// exponential with respect to the regex length + the string length, +// but usually it's must faster (often close to linear). +bool MatchRegexAnywhere(const char* regex, const char* str) { + if (regex == NULL || str == NULL) + return false; + + if (*regex == '^') + return MatchRegexAtHead(regex + 1, str); + + // A successful match can be anywhere in str. + do { + if (MatchRegexAtHead(regex, str)) + return true; + } while (*str++ != '\0'); + return false; +} + +// Implements the RE class. + +RE::~RE() { + free(const_cast(pattern_)); + free(const_cast(full_pattern_)); +} + +// Returns true iff regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); +} + +// Returns true iff regular expression re matches a substring of str +// (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = full_pattern_ = NULL; + if (regex != NULL) { + pattern_ = posix::StrDup(regex); + } + + is_valid_ = ValidateRegex(regex); + if (!is_valid_) { + // No need to calculate the full pattern when the regex is invalid. + return; + } + + const size_t len = strlen(regex); + // Reserves enough bytes to hold the regular expression used for a + // full match: we need space to prepend a '^', append a '$', and + // terminate the string with '\0'. + char* buffer = static_cast(malloc(len + 3)); + full_pattern_ = buffer; + + if (*regex != '^') + *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. + + // We don't use snprintf or strncpy, as they trigger a warning when + // compiled with VC++ 8.0. + memcpy(buffer, regex, len); + buffer += len; + + if (len == 0 || regex[len - 1] != '$') + *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. + + *buffer = '\0'; +} + +#endif // GTEST_USES_POSIX_RE + +const char kUnknownFile[] = "unknown file"; + +// Formats a source file path and a line number as they would appear +// in an error message from the compiler used to compile this code. +GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { + const char* const file_name = file == NULL ? kUnknownFile : file; + + if (line < 0) { + return String::Format("%s:", file_name).c_str(); + } +#ifdef _MSC_VER + return String::Format("%s(%d):", file_name, line).c_str(); +#else + return String::Format("%s:%d:", file_name, line).c_str(); +#endif // _MSC_VER +} + +// Formats a file location for compiler-independent XML output. +// Although this function is not platform dependent, we put it next to +// FormatFileLocation in order to contrast the two functions. +// Note that FormatCompilerIndependentFileLocation() does NOT append colon +// to the file location it produces, unlike FormatFileLocation(). +GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( + const char* file, int line) { + const char* const file_name = file == NULL ? kUnknownFile : file; + + if (line < 0) + return file_name; + else + return String::Format("%s:%d", file_name, line).c_str(); +} + + +GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) + : severity_(severity) { + const char* const marker = + severity == GTEST_INFO ? "[ INFO ]" : + severity == GTEST_WARNING ? "[WARNING]" : + severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; + GetStream() << ::std::endl << marker << " " + << FormatFileLocation(file, line).c_str() << ": "; +} + +// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. +GTestLog::~GTestLog() { + GetStream() << ::std::endl; + if (severity_ == GTEST_FATAL) { + fflush(stderr); + posix::Abort(); + } +} +// Disable Microsoft deprecation warnings for POSIX functions called from +// this class (creat, dup, dup2, and close) +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4996) +#endif // _MSC_VER + +#if GTEST_HAS_STREAM_REDIRECTION + +// Object that captures an output stream (stdout/stderr). +class CapturedStream { + public: + // The ctor redirects the stream to a temporary file. + CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { + +# if GTEST_OS_WINDOWS + char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT + char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT + + ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); + const UINT success = ::GetTempFileNameA(temp_dir_path, + "gtest_redir", + 0, // Generate unique file name. + temp_file_path); + GTEST_CHECK_(success != 0) + << "Unable to create a temporary file in " << temp_dir_path; + const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); + GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " + << temp_file_path; + filename_ = temp_file_path; +# else + // There's no guarantee that a test has write access to the + // current directory, so we create the temporary file in the /tmp + // directory instead. + char name_template[] = "/tmp/captured_stream.XXXXXX"; + const int captured_fd = mkstemp(name_template); + filename_ = name_template; +# endif // GTEST_OS_WINDOWS + fflush(NULL); + dup2(captured_fd, fd_); + close(captured_fd); + } + + ~CapturedStream() { + remove(filename_.c_str()); + } + + String GetCapturedString() { + if (uncaptured_fd_ != -1) { + // Restores the original stream. + fflush(NULL); + dup2(uncaptured_fd_, fd_); + close(uncaptured_fd_); + uncaptured_fd_ = -1; + } + + FILE* const file = posix::FOpen(filename_.c_str(), "r"); + const String content = ReadEntireFile(file); + posix::FClose(file); + return content; + } + + private: + // Reads the entire content of a file as a String. + static String ReadEntireFile(FILE* file); + + // Returns the size (in bytes) of a file. + static size_t GetFileSize(FILE* file); + + const int fd_; // A stream to capture. + int uncaptured_fd_; + // Name of the temporary file holding the stderr output. + ::std::string filename_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); +}; + +// Returns the size (in bytes) of a file. +size_t CapturedStream::GetFileSize(FILE* file) { + fseek(file, 0, SEEK_END); + return static_cast(ftell(file)); +} + +// Reads the entire content of a file as a string. +String CapturedStream::ReadEntireFile(FILE* file) { + const size_t file_size = GetFileSize(file); + char* const buffer = new char[file_size]; + + size_t bytes_last_read = 0; // # of bytes read in the last fread() + size_t bytes_read = 0; // # of bytes read so far + + fseek(file, 0, SEEK_SET); + + // Keeps reading the file until we cannot read further or the + // pre-determined file size is reached. + do { + bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); + bytes_read += bytes_last_read; + } while (bytes_last_read > 0 && bytes_read < file_size); + + const String content(buffer, bytes_read); + delete[] buffer; + + return content; +} + +# ifdef _MSC_VER +# pragma warning(pop) +# endif // _MSC_VER + +static CapturedStream* g_captured_stderr = NULL; +static CapturedStream* g_captured_stdout = NULL; + +// Starts capturing an output stream (stdout/stderr). +void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { + if (*stream != NULL) { + GTEST_LOG_(FATAL) << "Only one " << stream_name + << " capturer can exist at a time."; + } + *stream = new CapturedStream(fd); +} + +// Stops capturing the output stream and returns the captured string. +String GetCapturedStream(CapturedStream** captured_stream) { + const String content = (*captured_stream)->GetCapturedString(); + + delete *captured_stream; + *captured_stream = NULL; + + return content; +} + +// Starts capturing stdout. +void CaptureStdout() { + CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); +} + +// Starts capturing stderr. +void CaptureStderr() { + CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); +} + +// Stops capturing stdout and returns the captured string. +String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } + +// Stops capturing stderr and returns the captured string. +String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } + +#endif // GTEST_HAS_STREAM_REDIRECTION + +#if GTEST_HAS_DEATH_TEST + +// A copy of all command line arguments. Set by InitGoogleTest(). +::std::vector g_argvs; + +// Returns the command line as a vector of strings. +const ::std::vector& GetArgvs() { return g_argvs; } + +#endif // GTEST_HAS_DEATH_TEST + +#if GTEST_OS_WINDOWS_MOBILE +namespace posix { +void Abort() { + DebugBreak(); + TerminateProcess(GetCurrentProcess(), 1); +} +} // namespace posix +#endif // GTEST_OS_WINDOWS_MOBILE + +// Returns the name of the environment variable corresponding to the +// given flag. For example, FlagToEnvVar("foo") will return +// "GTEST_FOO" in the open-source version. +static String FlagToEnvVar(const char* flag) { + const String full_flag = + (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); + + Message env_var; + for (size_t i = 0; i != full_flag.length(); i++) { + env_var << ToUpper(full_flag.c_str()[i]); + } + + return env_var.GetString(); +} + +// Parses 'str' for a 32-bit signed integer. If successful, writes +// the result to *value and returns true; otherwise leaves *value +// unchanged and returns false. +bool ParseInt32(const Message& src_text, const char* str, Int32* value) { + // Parses the environment variable as a decimal integer. + char* end = NULL; + const long long_value = strtol(str, &end, 10); // NOLINT + + // Has strtol() consumed all characters in the string? + if (*end != '\0') { + // No - an invalid character was encountered. + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value \"" << str << "\".\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + // Is the parsed value in the range of an Int32? + const Int32 result = static_cast(long_value); + if (long_value == LONG_MAX || long_value == LONG_MIN || + // The parsed value overflows as a long. (strtol() returns + // LONG_MAX or LONG_MIN when the input overflows.) + result != long_value + // The parsed value overflows as an Int32. + ) { + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value " << str << ", which overflows.\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + *value = result; + return true; +} + +// Reads and returns the Boolean environment variable corresponding to +// the given flag; if it's not set, returns default_value. +// +// The value is considered true iff it's not "0". +bool BoolFromGTestEnv(const char* flag, bool default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const string_value = posix::GetEnv(env_var.c_str()); + return string_value == NULL ? + default_value : strcmp(string_value, "0") != 0; +} + +// Reads and returns a 32-bit integer stored in the environment +// variable corresponding to the given flag; if it isn't set or +// doesn't represent a valid 32-bit integer, returns default_value. +Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const string_value = posix::GetEnv(env_var.c_str()); + if (string_value == NULL) { + // The environment variable is not set. + return default_value; + } + + Int32 result = default_value; + if (!ParseInt32(Message() << "Environment variable " << env_var, + string_value, &result)) { + printf("The default value %s is used.\n", + (Message() << default_value).GetString().c_str()); + fflush(stdout); + return default_value; + } + + return result; +} + +// Reads and returns the string environment variable corresponding to +// the given flag; if it's not set, returns default_value. +const char* StringFromGTestEnv(const char* flag, const char* default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const value = posix::GetEnv(env_var.c_str()); + return value == NULL ? default_value : value; +} + +} // namespace internal +} // namespace testing diff --git a/libs/gtest/src/gtest-printers.cc b/libs/gtest/src/gtest-printers.cc new file mode 100644 index 000000000..ed63c7b3b --- /dev/null +++ b/libs/gtest/src/gtest-printers.cc @@ -0,0 +1,356 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Test - The Google C++ Testing Framework +// +// This file implements a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); +// +// It uses the << operator when possible, and prints the bytes in the +// object otherwise. A user can override its behavior for a class +// type Foo by defining either operator<<(::std::ostream&, const Foo&) +// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that +// defines Foo. + +#include "gtest/gtest-printers.h" +#include +#include +#include // NOLINT +#include +#include "gtest/internal/gtest-port.h" + +namespace testing { + +namespace { + +using ::std::ostream; + +#if GTEST_OS_WINDOWS_MOBILE // Windows CE does not define _snprintf_s. +# define snprintf _snprintf +#elif _MSC_VER >= 1400 // VC 8.0 and later deprecate snprintf and _snprintf. +# define snprintf _snprintf_s +#elif _MSC_VER +# define snprintf _snprintf +#endif // GTEST_OS_WINDOWS_MOBILE + +// Prints a segment of bytes in the given object. +void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, + size_t count, ostream* os) { + char text[5] = ""; + for (size_t i = 0; i != count; i++) { + const size_t j = start + i; + if (i != 0) { + // Organizes the bytes into groups of 2 for easy parsing by + // human. + if ((j % 2) == 0) + *os << ' '; + else + *os << '-'; + } + snprintf(text, sizeof(text), "%02X", obj_bytes[j]); + *os << text; + } +} + +// Prints the bytes in the given value to the given ostream. +void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, + ostream* os) { + // Tells the user how big the object is. + *os << count << "-byte object <"; + + const size_t kThreshold = 132; + const size_t kChunkSize = 64; + // If the object size is bigger than kThreshold, we'll have to omit + // some details by printing only the first and the last kChunkSize + // bytes. + // TODO(wan): let the user control the threshold using a flag. + if (count < kThreshold) { + PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); + } else { + PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); + *os << " ... "; + // Rounds up to 2-byte boundary. + const size_t resume_pos = (count - kChunkSize + 1)/2*2; + PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); + } + *os << ">"; +} + +} // namespace + +namespace internal2 { + +// Delegates to PrintBytesInObjectToImpl() to print the bytes in the +// given object. The delegation simplifies the implementation, which +// uses the << operator and thus is easier done outside of the +// ::testing::internal namespace, which contains a << operator that +// sometimes conflicts with the one in STL. +void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, + ostream* os) { + PrintBytesInObjectToImpl(obj_bytes, count, os); +} + +} // namespace internal2 + +namespace internal { + +// Depending on the value of a char (or wchar_t), we print it in one +// of three formats: +// - as is if it's a printable ASCII (e.g. 'a', '2', ' '), +// - as a hexidecimal escape sequence (e.g. '\x7F'), or +// - as a special escape sequence (e.g. '\r', '\n'). +enum CharFormat { + kAsIs, + kHexEscape, + kSpecialEscape +}; + +// Returns true if c is a printable ASCII character. We test the +// value of c directly instead of calling isprint(), which is buggy on +// Windows Mobile. +inline bool IsPrintableAscii(wchar_t c) { + return 0x20 <= c && c <= 0x7E; +} + +// Prints a wide or narrow char c as a character literal without the +// quotes, escaping it when necessary; returns how c was formatted. +// The template argument UnsignedChar is the unsigned version of Char, +// which is the type of c. +template +static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { + switch (static_cast(c)) { + case L'\0': + *os << "\\0"; + break; + case L'\'': + *os << "\\'"; + break; + case L'\\': + *os << "\\\\"; + break; + case L'\a': + *os << "\\a"; + break; + case L'\b': + *os << "\\b"; + break; + case L'\f': + *os << "\\f"; + break; + case L'\n': + *os << "\\n"; + break; + case L'\r': + *os << "\\r"; + break; + case L'\t': + *os << "\\t"; + break; + case L'\v': + *os << "\\v"; + break; + default: + if (IsPrintableAscii(c)) { + *os << static_cast(c); + return kAsIs; + } else { + *os << String::Format("\\x%X", static_cast(c)); + return kHexEscape; + } + } + return kSpecialEscape; +} + +// Prints a char c as if it's part of a string literal, escaping it when +// necessary; returns how c was formatted. +static CharFormat PrintAsWideStringLiteralTo(wchar_t c, ostream* os) { + switch (c) { + case L'\'': + *os << "'"; + return kAsIs; + case L'"': + *os << "\\\""; + return kSpecialEscape; + default: + return PrintAsCharLiteralTo(c, os); + } +} + +// Prints a char c as if it's part of a string literal, escaping it when +// necessary; returns how c was formatted. +static CharFormat PrintAsNarrowStringLiteralTo(char c, ostream* os) { + return PrintAsWideStringLiteralTo(static_cast(c), os); +} + +// Prints a wide or narrow character c and its code. '\0' is printed +// as "'\\0'", other unprintable characters are also properly escaped +// using the standard C++ escape sequence. The template argument +// UnsignedChar is the unsigned version of Char, which is the type of c. +template +void PrintCharAndCodeTo(Char c, ostream* os) { + // First, print c as a literal in the most readable form we can find. + *os << ((sizeof(c) > 1) ? "L'" : "'"); + const CharFormat format = PrintAsCharLiteralTo(c, os); + *os << "'"; + + // To aid user debugging, we also print c's code in decimal, unless + // it's 0 (in which case c was printed as '\\0', making the code + // obvious). + if (c == 0) + return; + *os << " (" << String::Format("%d", c).c_str(); + + // For more convenience, we print c's code again in hexidecimal, + // unless c was already printed in the form '\x##' or the code is in + // [1, 9]. + if (format == kHexEscape || (1 <= c && c <= 9)) { + // Do nothing. + } else { + *os << String::Format(", 0x%X", + static_cast(c)).c_str(); + } + *os << ")"; +} + +void PrintTo(unsigned char c, ::std::ostream* os) { + PrintCharAndCodeTo(c, os); +} +void PrintTo(signed char c, ::std::ostream* os) { + PrintCharAndCodeTo(c, os); +} + +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its code. L'\0' is printed as "L'\\0'". +void PrintTo(wchar_t wc, ostream* os) { + PrintCharAndCodeTo(wc, os); +} + +// Prints the given array of characters to the ostream. +// The array starts at *begin, the length is len, it may include '\0' characters +// and may not be null-terminated. +static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) { + *os << "\""; + bool is_previous_hex = false; + for (size_t index = 0; index < len; ++index) { + const char cur = begin[index]; + if (is_previous_hex && IsXDigit(cur)) { + // Previous character is of '\x..' form and this character can be + // interpreted as another hexadecimal digit in its number. Break string to + // disambiguate. + *os << "\" \""; + } + is_previous_hex = PrintAsNarrowStringLiteralTo(cur, os) == kHexEscape; + } + *os << "\""; +} + +// Prints a (const) char array of 'len' elements, starting at address 'begin'. +void UniversalPrintArray(const char* begin, size_t len, ostream* os) { + PrintCharsAsStringTo(begin, len, os); +} + +// Prints the given array of wide characters to the ostream. +// The array starts at *begin, the length is len, it may include L'\0' +// characters and may not be null-terminated. +static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len, + ostream* os) { + *os << "L\""; + bool is_previous_hex = false; + for (size_t index = 0; index < len; ++index) { + const wchar_t cur = begin[index]; + if (is_previous_hex && isascii(cur) && IsXDigit(static_cast(cur))) { + // Previous character is of '\x..' form and this character can be + // interpreted as another hexadecimal digit in its number. Break string to + // disambiguate. + *os << "\" L\""; + } + is_previous_hex = PrintAsWideStringLiteralTo(cur, os) == kHexEscape; + } + *os << "\""; +} + +// Prints the given C string to the ostream. +void PrintTo(const char* s, ostream* os) { + if (s == NULL) { + *os << "NULL"; + } else { + *os << ImplicitCast_(s) << " pointing to "; + PrintCharsAsStringTo(s, strlen(s), os); + } +} + +// MSVC compiler can be configured to define whar_t as a typedef +// of unsigned short. Defining an overload for const wchar_t* in that case +// would cause pointers to unsigned shorts be printed as wide strings, +// possibly accessing more memory than intended and causing invalid +// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when +// wchar_t is implemented as a native type. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Prints the given wide C string to the ostream. +void PrintTo(const wchar_t* s, ostream* os) { + if (s == NULL) { + *os << "NULL"; + } else { + *os << ImplicitCast_(s) << " pointing to "; + PrintWideCharsAsStringTo(s, wcslen(s), os); + } +} +#endif // wchar_t is native + +// Prints a ::string object. +#if GTEST_HAS_GLOBAL_STRING +void PrintStringTo(const ::string& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_GLOBAL_STRING + +void PrintStringTo(const ::std::string& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} + +// Prints a ::wstring object. +#if GTEST_HAS_GLOBAL_WSTRING +void PrintWideStringTo(const ::wstring& s, ostream* os) { + PrintWideCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +void PrintWideStringTo(const ::std::wstring& s, ostream* os) { + PrintWideCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_STD_WSTRING + +} // namespace internal + +} // namespace testing diff --git a/libs/gtest/src/gtest-test-part.cc b/libs/gtest/src/gtest-test-part.cc new file mode 100644 index 000000000..5ddc67c1c --- /dev/null +++ b/libs/gtest/src/gtest-test-part.cc @@ -0,0 +1,110 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// +// The Google C++ Testing Framework (Google Test) + +#include "gtest/gtest-test-part.h" + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +namespace testing { + +using internal::GetUnitTestImpl; + +// Gets the summary of the failure message by omitting the stack trace +// in it. +internal::String TestPartResult::ExtractSummary(const char* message) { + const char* const stack_trace = strstr(message, internal::kStackTraceMarker); + return stack_trace == NULL ? internal::String(message) : + internal::String(message, stack_trace - message); +} + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { + return os + << result.file_name() << ":" << result.line_number() << ": " + << (result.type() == TestPartResult::kSuccess ? "Success" : + result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : + "Non-fatal failure") << ":\n" + << result.message() << std::endl; +} + +// Appends a TestPartResult to the array. +void TestPartResultArray::Append(const TestPartResult& result) { + array_.push_back(result); +} + +// Returns the TestPartResult at the given index (0-based). +const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { + if (index < 0 || index >= size()) { + printf("\nInvalid index (%d) into TestPartResultArray.\n", index); + internal::posix::Abort(); + } + + return array_[index]; +} + +// Returns the number of TestPartResult objects in the array. +int TestPartResultArray::size() const { + return static_cast(array_.size()); +} + +namespace internal { + +HasNewFatalFailureHelper::HasNewFatalFailureHelper() + : has_new_fatal_failure_(false), + original_reporter_(GetUnitTestImpl()-> + GetTestPartResultReporterForCurrentThread()) { + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); +} + +HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( + original_reporter_); +} + +void HasNewFatalFailureHelper::ReportTestPartResult( + const TestPartResult& result) { + if (result.fatally_failed()) + has_new_fatal_failure_ = true; + original_reporter_->ReportTestPartResult(result); +} + +} // namespace internal + +} // namespace testing diff --git a/libs/gtest/src/gtest-typed-test.cc b/libs/gtest/src/gtest-typed-test.cc new file mode 100644 index 000000000..a5cc88f92 --- /dev/null +++ b/libs/gtest/src/gtest-typed-test.cc @@ -0,0 +1,110 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#include "gtest/gtest-typed-test.h" +#include "gtest/gtest.h" + +namespace testing { +namespace internal { + +#if GTEST_HAS_TYPED_TEST_P + +// Skips to the first non-space char in str. Returns an empty string if str +// contains only whitespace characters. +static const char* SkipSpaces(const char* str) { + while (IsSpace(*str)) + str++; + return str; +} + +// Verifies that registered_tests match the test names in +// defined_test_names_; returns registered_tests if successful, or +// aborts the program otherwise. +const char* TypedTestCasePState::VerifyRegisteredTestNames( + const char* file, int line, const char* registered_tests) { + typedef ::std::set::const_iterator DefinedTestIter; + registered_ = true; + + // Skip initial whitespace in registered_tests since some + // preprocessors prefix stringizied literals with whitespace. + registered_tests = SkipSpaces(registered_tests); + + Message errors; + ::std::set tests; + for (const char* names = registered_tests; names != NULL; + names = SkipComma(names)) { + const String name = GetPrefixUntilComma(names); + if (tests.count(name) != 0) { + errors << "Test " << name << " is listed more than once.\n"; + continue; + } + + bool found = false; + for (DefinedTestIter it = defined_test_names_.begin(); + it != defined_test_names_.end(); + ++it) { + if (name == *it) { + found = true; + break; + } + } + + if (found) { + tests.insert(name); + } else { + errors << "No test named " << name + << " can be found in this test case.\n"; + } + } + + for (DefinedTestIter it = defined_test_names_.begin(); + it != defined_test_names_.end(); + ++it) { + if (tests.count(*it) == 0) { + errors << "You forgot to list test " << *it << ".\n"; + } + } + + const String& errors_str = errors.GetString(); + if (errors_str != "") { + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors_str.c_str()); + fflush(stderr); + posix::Abort(); + } + + return registered_tests; +} + +#endif // GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing diff --git a/libs/gtest/src/gtest.cc b/libs/gtest/src/gtest.cc new file mode 100644 index 000000000..904d9d747 --- /dev/null +++ b/libs/gtest/src/gtest.cc @@ -0,0 +1,4898 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) + +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include // NOLINT +#include +#include + +#if GTEST_OS_LINUX + +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +# define GTEST_HAS_GETTIMEOFDAY_ 1 + +# include // NOLINT +# include // NOLINT +# include // NOLINT +// Declares vsnprintf(). This header is not available on Windows. +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include + +#elif GTEST_OS_SYMBIAN +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT + +#elif GTEST_OS_ZOS +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT + +// On z/OS we additionally need strings.h for strcasecmp. +# include // NOLINT + +#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. + +# include // NOLINT + +#elif GTEST_OS_WINDOWS // We are on Windows proper. + +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT + +# if GTEST_OS_WINDOWS_MINGW +// MinGW has gettimeofday() but not _ftime64(). +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +// TODO(kenton@google.com): There are other ways to get the time on +// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW +// supports these. consider using them instead. +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT +# endif // GTEST_OS_WINDOWS_MINGW + +// cpplint thinks that the header is already included, so we want to +// silence it. +# include // NOLINT + +#else + +// Assume other platforms have gettimeofday(). +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +# define GTEST_HAS_GETTIMEOFDAY_ 1 + +// cpplint thinks that the header is already included, so we want to +// silence it. +# include // NOLINT +# include // NOLINT + +#endif // GTEST_OS_LINUX + +#if GTEST_HAS_EXCEPTIONS +# include +#endif + +#if GTEST_CAN_STREAM_RESULTS_ +# include // NOLINT +# include // NOLINT +#endif + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +#if GTEST_OS_WINDOWS +# define vsnprintf _vsnprintf +#endif // GTEST_OS_WINDOWS + +namespace testing { + +using internal::CountIf; +using internal::ForEach; +using internal::GetElementOr; +using internal::Shuffle; + +// Constants. + +// A test whose test case name or test name matches this filter is +// disabled and not run. +static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; + +// A test case whose name matches this filter is considered a death +// test case and will be run before test cases whose name doesn't +// match this filter. +static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; + +// A test filter that matches everything. +static const char kUniversalFilter[] = "*"; + +// The default output file for XML output. +static const char kDefaultOutputFile[] = "test_detail.xml"; + +// The environment variable name for the test shard index. +static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; +// The environment variable name for the total number of test shards. +static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; +// The environment variable name for the test shard status file. +static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; + +namespace internal { + +// The text used in failure messages to indicate the start of the +// stack trace. +const char kStackTraceMarker[] = "\nStack trace:\n"; + +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +bool g_help_flag = false; + +} // namespace internal + +GTEST_DEFINE_bool_( + also_run_disabled_tests, + internal::BoolFromGTestEnv("also_run_disabled_tests", false), + "Run disabled tests too, in addition to the tests normally being run."); + +GTEST_DEFINE_bool_( + break_on_failure, + internal::BoolFromGTestEnv("break_on_failure", false), + "True iff a failed assertion should be a debugger break-point."); + +GTEST_DEFINE_bool_( + catch_exceptions, + internal::BoolFromGTestEnv("catch_exceptions", true), + "True iff " GTEST_NAME_ + " should catch exceptions and treat them as test failures."); + +GTEST_DEFINE_string_( + color, + internal::StringFromGTestEnv("color", "auto"), + "Whether to use colors in the output. Valid values: yes, no, " + "and auto. 'auto' means to use colors if the output is " + "being sent to a terminal and the TERM environment variable " + "is set to xterm, xterm-color, xterm-256color, linux or cygwin."); + +GTEST_DEFINE_string_( + filter, + internal::StringFromGTestEnv("filter", kUniversalFilter), + "A colon-separated list of glob (not regex) patterns " + "for filtering the tests to run, optionally followed by a " + "'-' and a : separated list of negative patterns (tests to " + "exclude). A test is run if it matches one of the positive " + "patterns and does not match any of the negative patterns."); + +GTEST_DEFINE_bool_(list_tests, false, + "List all tests without running them."); + +GTEST_DEFINE_string_( + output, + internal::StringFromGTestEnv("output", ""), + "A format (currently must be \"xml\"), optionally followed " + "by a colon and an output file name or directory. A directory " + "is indicated by a trailing pathname separator. " + "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " + "If a directory is specified, output files will be created " + "within that directory, with file-names based on the test " + "executable's name and, if necessary, made unique by adding " + "digits."); + +GTEST_DEFINE_bool_( + print_time, + internal::BoolFromGTestEnv("print_time", true), + "True iff " GTEST_NAME_ + " should display elapsed time in text output."); + +GTEST_DEFINE_int32_( + random_seed, + internal::Int32FromGTestEnv("random_seed", 0), + "Random number seed to use when shuffling test orders. Must be in range " + "[1, 99999], or 0 to use a seed based on the current time."); + +GTEST_DEFINE_int32_( + repeat, + internal::Int32FromGTestEnv("repeat", 1), + "How many times to repeat each test. Specify a negative number " + "for repeating forever. Useful for shaking out flaky tests."); + +GTEST_DEFINE_bool_( + show_internal_stack_frames, false, + "True iff " GTEST_NAME_ " should include internal stack frames when " + "printing test failure stack traces."); + +GTEST_DEFINE_bool_( + shuffle, + internal::BoolFromGTestEnv("shuffle", false), + "True iff " GTEST_NAME_ + " should randomize tests' order on every run."); + +GTEST_DEFINE_int32_( + stack_trace_depth, + internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), + "The maximum number of stack frames to print when an " + "assertion fails. The valid range is 0 through 100, inclusive."); + +GTEST_DEFINE_string_( + stream_result_to, + internal::StringFromGTestEnv("stream_result_to", ""), + "This flag specifies the host name and the port number on which to stream " + "test results. Example: \"localhost:555\". The flag is effective only on " + "Linux."); + +GTEST_DEFINE_bool_( + throw_on_failure, + internal::BoolFromGTestEnv("throw_on_failure", false), + "When this flag is specified, a failed assertion will throw an exception " + "if exceptions are enabled or exit the program with a non-zero code " + "otherwise."); + +namespace internal { + +// Generates a random number from [0, range), using a Linear +// Congruential Generator (LCG). Crashes if 'range' is 0 or greater +// than kMaxRange. +UInt32 Random::Generate(UInt32 range) { + // These constants are the same as are used in glibc's rand(3). + state_ = (1103515245U*state_ + 12345U) % kMaxRange; + + GTEST_CHECK_(range > 0) + << "Cannot generate a number in the range [0, 0)."; + GTEST_CHECK_(range <= kMaxRange) + << "Generation of a number in [0, " << range << ") was requested, " + << "but this can only generate numbers in [0, " << kMaxRange << ")."; + + // Converting via modulus introduces a bit of downward bias, but + // it's simple, and a linear congruential generator isn't too good + // to begin with. + return state_ % range; +} + +// GTestIsInitialized() returns true iff the user has initialized +// Google Test. Useful for catching the user mistake of not initializing +// Google Test before calling RUN_ALL_TESTS(). +// +// A user must call testing::InitGoogleTest() to initialize Google +// Test. g_init_gtest_count is set to the number of times +// InitGoogleTest() has been called. We don't protect this variable +// under a mutex as it is only accessed in the main thread. +int g_init_gtest_count = 0; +static bool GTestIsInitialized() { return g_init_gtest_count != 0; } + +// Iterates over a vector of TestCases, keeping a running sum of the +// results of calling a given int-returning method on each. +// Returns the sum. +static int SumOverTestCaseList(const std::vector& case_list, + int (TestCase::*method)() const) { + int sum = 0; + for (size_t i = 0; i < case_list.size(); i++) { + sum += (case_list[i]->*method)(); + } + return sum; +} + +// Returns true iff the test case passed. +static bool TestCasePassed(const TestCase* test_case) { + return test_case->should_run() && test_case->Passed(); +} + +// Returns true iff the test case failed. +static bool TestCaseFailed(const TestCase* test_case) { + return test_case->should_run() && test_case->Failed(); +} + +// Returns true iff test_case contains at least one test that should +// run. +static bool ShouldRunTestCase(const TestCase* test_case) { + return test_case->should_run(); +} + +// AssertHelper constructor. +AssertHelper::AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message) + : data_(new AssertHelperData(type, file, line, message)) { +} + +AssertHelper::~AssertHelper() { + delete data_; +} + +// Message assignment, for assertion streaming support. +void AssertHelper::operator=(const Message& message) const { + UnitTest::GetInstance()-> + AddTestPartResult(data_->type, data_->file, data_->line, + AppendUserMessage(data_->message, message), + UnitTest::GetInstance()->impl() + ->CurrentOsStackTraceExceptTop(1) + // Skips the stack frame for this function itself. + ); // NOLINT +} + +// Mutex for linked pointers. +GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); + +// Application pathname gotten in InitGoogleTest. +String g_executable_path; + +// Returns the current application's name, removing directory path if that +// is present. +FilePath GetCurrentExecutableName() { + FilePath result; + +#if GTEST_OS_WINDOWS + result.Set(FilePath(g_executable_path).RemoveExtension("exe")); +#else + result.Set(FilePath(g_executable_path)); +#endif // GTEST_OS_WINDOWS + + return result.RemoveDirectoryName(); +} + +// Functions for processing the gtest_output flag. + +// Returns the output format, or "" for normal printed output. +String UnitTestOptions::GetOutputFormat() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + if (gtest_output_flag == NULL) return String(""); + + const char* const colon = strchr(gtest_output_flag, ':'); + return (colon == NULL) ? + String(gtest_output_flag) : + String(gtest_output_flag, colon - gtest_output_flag); +} + +// Returns the name of the requested output file, or the default if none +// was explicitly specified. +String UnitTestOptions::GetAbsolutePathToOutputFile() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + if (gtest_output_flag == NULL) + return String(""); + + const char* const colon = strchr(gtest_output_flag, ':'); + if (colon == NULL) + return String(internal::FilePath::ConcatPaths( + internal::FilePath( + UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(kDefaultOutputFile)).ToString() ); + + internal::FilePath output_name(colon + 1); + if (!output_name.IsAbsolutePath()) + // TODO(wan@google.com): on Windows \some\path is not an absolute + // path (as its meaning depends on the current drive), yet the + // following logic for turning it into an absolute path is wrong. + // Fix it. + output_name = internal::FilePath::ConcatPaths( + internal::FilePath(UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(colon + 1)); + + if (!output_name.IsDirectory()) + return output_name.ToString(); + + internal::FilePath result(internal::FilePath::GenerateUniqueFileName( + output_name, internal::GetCurrentExecutableName(), + GetOutputFormat().c_str())); + return result.ToString(); +} + +// Returns true iff the wildcard pattern matches the string. The +// first ':' or '\0' character in pattern marks the end of it. +// +// This recursive algorithm isn't very efficient, but is clear and +// works well enough for matching test names, which are short. +bool UnitTestOptions::PatternMatchesString(const char *pattern, + const char *str) { + switch (*pattern) { + case '\0': + case ':': // Either ':' or '\0' marks the end of the pattern. + return *str == '\0'; + case '?': // Matches any single character. + return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); + case '*': // Matches any string (possibly empty) of characters. + return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || + PatternMatchesString(pattern + 1, str); + default: // Non-special character. Matches itself. + return *pattern == *str && + PatternMatchesString(pattern + 1, str + 1); + } +} + +bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) { + const char *cur_pattern = filter; + for (;;) { + if (PatternMatchesString(cur_pattern, name.c_str())) { + return true; + } + + // Finds the next pattern in the filter. + cur_pattern = strchr(cur_pattern, ':'); + + // Returns if no more pattern can be found. + if (cur_pattern == NULL) { + return false; + } + + // Skips the pattern separater (the ':' character). + cur_pattern++; + } +} + +// TODO(keithray): move String function implementations to gtest-string.cc. + +// Returns true iff the user-specified filter matches the test case +// name and the test name. +bool UnitTestOptions::FilterMatchesTest(const String &test_case_name, + const String &test_name) { + const String& full_name = String::Format("%s.%s", + test_case_name.c_str(), + test_name.c_str()); + + // Split --gtest_filter at '-', if there is one, to separate into + // positive filter and negative filter portions + const char* const p = GTEST_FLAG(filter).c_str(); + const char* const dash = strchr(p, '-'); + String positive; + String negative; + if (dash == NULL) { + positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter + negative = String(""); + } else { + positive = String(p, dash - p); // Everything up to the dash + negative = String(dash+1); // Everything after the dash + if (positive.empty()) { + // Treat '-test1' as the same as '*-test1' + positive = kUniversalFilter; + } + } + + // A filter is a colon-separated list of patterns. It matches a + // test if any pattern in it matches the test. + return (MatchesFilter(full_name, positive.c_str()) && + !MatchesFilter(full_name, negative.c_str())); +} + +#if GTEST_HAS_SEH +// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the +// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. +// This function is useful as an __except condition. +int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { + // Google Test should handle a SEH exception if: + // 1. the user wants it to, AND + // 2. this is not a breakpoint exception, AND + // 3. this is not a C++ exception (VC++ implements them via SEH, + // apparently). + // + // SEH exception code for C++ exceptions. + // (see http://support.microsoft.com/kb/185294 for more information). + const DWORD kCxxExceptionCode = 0xe06d7363; + + bool should_handle = true; + + if (!GTEST_FLAG(catch_exceptions)) + should_handle = false; + else if (exception_code == EXCEPTION_BREAKPOINT) + should_handle = false; + else if (exception_code == kCxxExceptionCode) + should_handle = false; + + return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; +} +#endif // GTEST_HAS_SEH + +} // namespace internal + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. Intercepts only failures from the current thread. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + TestPartResultArray* result) + : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), + result_(result) { + Init(); +} + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + InterceptMode intercept_mode, TestPartResultArray* result) + : intercept_mode_(intercept_mode), + result_(result) { + Init(); +} + +void ScopedFakeTestPartResultReporter::Init() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + old_reporter_ = impl->GetGlobalTestPartResultReporter(); + impl->SetGlobalTestPartResultReporter(this); + } else { + old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); + impl->SetTestPartResultReporterForCurrentThread(this); + } +} + +// The d'tor restores the test part result reporter used by Google Test +// before. +ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + impl->SetGlobalTestPartResultReporter(old_reporter_); + } else { + impl->SetTestPartResultReporterForCurrentThread(old_reporter_); + } +} + +// Increments the test part result count and remembers the result. +// This method is from the TestPartResultReporterInterface interface. +void ScopedFakeTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + result_->Append(result); +} + +namespace internal { + +// Returns the type ID of ::testing::Test. We should always call this +// instead of GetTypeId< ::testing::Test>() to get the type ID of +// testing::Test. This is to work around a suspected linker bug when +// using Google Test as a framework on Mac OS X. The bug causes +// GetTypeId< ::testing::Test>() to return different values depending +// on whether the call is from the Google Test framework itself or +// from user test code. GetTestTypeId() is guaranteed to always +// return the same value, as it always calls GetTypeId<>() from the +// gtest.cc, which is within the Google Test framework. +TypeId GetTestTypeId() { + return GetTypeId(); +} + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); + +// This predicate-formatter checks that 'results' contains a test part +// failure of the given type and that the failure message contains the +// given substring. +AssertionResult HasOneFailure(const char* /* results_expr */, + const char* /* type_expr */, + const char* /* substr_expr */, + const TestPartResultArray& results, + TestPartResult::Type type, + const string& substr) { + const String expected(type == TestPartResult::kFatalFailure ? + "1 fatal failure" : + "1 non-fatal failure"); + Message msg; + if (results.size() != 1) { + msg << "Expected: " << expected << "\n" + << " Actual: " << results.size() << " failures"; + for (int i = 0; i < results.size(); i++) { + msg << "\n" << results.GetTestPartResult(i); + } + return AssertionFailure() << msg; + } + + const TestPartResult& r = results.GetTestPartResult(0); + if (r.type() != type) { + return AssertionFailure() << "Expected: " << expected << "\n" + << " Actual:\n" + << r; + } + + if (strstr(r.message(), substr.c_str()) == NULL) { + return AssertionFailure() << "Expected: " << expected << " containing \"" + << substr << "\"\n" + << " Actual:\n" + << r; + } + + return AssertionSuccess(); +} + +// The constructor of SingleFailureChecker remembers where to look up +// test part results, what type of failure we expect, and what +// substring the failure message should contain. +SingleFailureChecker:: SingleFailureChecker( + const TestPartResultArray* results, + TestPartResult::Type type, + const string& substr) + : results_(results), + type_(type), + substr_(substr) {} + +// The destructor of SingleFailureChecker verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +SingleFailureChecker::~SingleFailureChecker() { + EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_); +} + +DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultGlobalTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->current_test_result()->AddTestPartResult(result); + unit_test_->listeners()->repeater()->OnTestPartResult(result); +} + +DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); +} + +// Returns the global test part result reporter. +TestPartResultReporterInterface* +UnitTestImpl::GetGlobalTestPartResultReporter() { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + return global_test_part_result_repoter_; +} + +// Sets the global test part result reporter. +void UnitTestImpl::SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter) { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + global_test_part_result_repoter_ = reporter; +} + +// Returns the test part result reporter for the current thread. +TestPartResultReporterInterface* +UnitTestImpl::GetTestPartResultReporterForCurrentThread() { + return per_thread_test_part_result_reporter_.get(); +} + +// Sets the test part result reporter for the current thread. +void UnitTestImpl::SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter) { + per_thread_test_part_result_reporter_.set(reporter); +} + +// Gets the number of successful test cases. +int UnitTestImpl::successful_test_case_count() const { + return CountIf(test_cases_, TestCasePassed); +} + +// Gets the number of failed test cases. +int UnitTestImpl::failed_test_case_count() const { + return CountIf(test_cases_, TestCaseFailed); +} + +// Gets the number of all test cases. +int UnitTestImpl::total_test_case_count() const { + return static_cast(test_cases_.size()); +} + +// Gets the number of all test cases that contain at least one test +// that should run. +int UnitTestImpl::test_case_to_run_count() const { + return CountIf(test_cases_, ShouldRunTestCase); +} + +// Gets the number of successful tests. +int UnitTestImpl::successful_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); +} + +// Gets the number of failed tests. +int UnitTestImpl::failed_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); +} + +// Gets the number of disabled tests. +int UnitTestImpl::disabled_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); +} + +// Gets the number of all tests. +int UnitTestImpl::total_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); +} + +// Gets the number of tests that should run. +int UnitTestImpl::test_to_run_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); +} + +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// CurrentOsStackTraceExceptTop(1), Foo() will be included in the +// trace but Bar() and CurrentOsStackTraceExceptTop() won't. +String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { + (void)skip_count; + return String(""); +} + +// Returns the current time in milliseconds. +TimeInMillis GetTimeInMillis() { +#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) + // Difference between 1970-01-01 and 1601-01-01 in milliseconds. + // http://analogous.blogspot.com/2005/04/epoch.html + const TimeInMillis kJavaEpochToWinFileTimeDelta = + static_cast(116444736UL) * 100000UL; + const DWORD kTenthMicrosInMilliSecond = 10000; + + SYSTEMTIME now_systime; + FILETIME now_filetime; + ULARGE_INTEGER now_int64; + // TODO(kenton@google.com): Shouldn't this just use + // GetSystemTimeAsFileTime()? + GetSystemTime(&now_systime); + if (SystemTimeToFileTime(&now_systime, &now_filetime)) { + now_int64.LowPart = now_filetime.dwLowDateTime; + now_int64.HighPart = now_filetime.dwHighDateTime; + now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - + kJavaEpochToWinFileTimeDelta; + return now_int64.QuadPart; + } + return 0; +#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ + __timeb64 now; + +# ifdef _MSC_VER + + // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 + // (deprecated function) there. + // TODO(kenton@google.com): Use GetTickCount()? Or use + // SystemTimeToFileTime() +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4996) // Temporarily disables warning 4996. + _ftime64(&now); +# pragma warning(pop) // Restores the warning state. +# else + + _ftime64(&now); + +# endif // _MSC_VER + + return static_cast(now.time) * 1000 + now.millitm; +#elif GTEST_HAS_GETTIMEOFDAY_ + struct timeval now; + gettimeofday(&now, NULL); + return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; +#else +# error "Don't know how to get the current time on your system." +#endif +} + +// Utilities + +// class String + +// Returns the input enclosed in double quotes if it's not NULL; +// otherwise returns "(null)". For example, "\"Hello\"" is returned +// for input "Hello". +// +// This is useful for printing a C string in the syntax of a literal. +// +// Known issue: escape sequences are not handled yet. +String String::ShowCStringQuoted(const char* c_str) { + return c_str ? String::Format("\"%s\"", c_str) : String("(null)"); +} + +// Copies at most length characters from str into a newly-allocated +// piece of memory of size length+1. The memory is allocated with new[]. +// A terminating null byte is written to the memory, and a pointer to it +// is returned. If str is NULL, NULL is returned. +static char* CloneString(const char* str, size_t length) { + if (str == NULL) { + return NULL; + } else { + char* const clone = new char[length + 1]; + posix::StrNCpy(clone, str, length); + clone[length] = '\0'; + return clone; + } +} + +// Clones a 0-terminated C string, allocating memory using new. The +// caller is responsible for deleting[] the return value. Returns the +// cloned string, or NULL if the input is NULL. +const char * String::CloneCString(const char* c_str) { + return (c_str == NULL) ? + NULL : CloneString(c_str, strlen(c_str)); +} + +#if GTEST_OS_WINDOWS_MOBILE +// Creates a UTF-16 wide string from the given ANSI string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the wide string, or NULL if the +// input is NULL. +LPCWSTR String::AnsiToUtf16(const char* ansi) { + if (!ansi) return NULL; + const int length = strlen(ansi); + const int unicode_length = + MultiByteToWideChar(CP_ACP, 0, ansi, length, + NULL, 0); + WCHAR* unicode = new WCHAR[unicode_length + 1]; + MultiByteToWideChar(CP_ACP, 0, ansi, length, + unicode, unicode_length); + unicode[unicode_length] = 0; + return unicode; +} + +// Creates an ANSI string from the given wide string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the ANSI string, or NULL if the +// input is NULL. +const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { + if (!utf16_str) return NULL; + const int ansi_length = + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + NULL, 0, NULL, NULL); + char* ansi = new char[ansi_length + 1]; + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + ansi, ansi_length, NULL, NULL); + ansi[ansi_length] = 0; + return ansi; +} + +#endif // GTEST_OS_WINDOWS_MOBILE + +// Compares two C strings. Returns true iff they have the same content. +// +// Unlike strcmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CStringEquals(const char * lhs, const char * rhs) { + if ( lhs == NULL ) return rhs == NULL; + + if ( rhs == NULL ) return false; + + return strcmp(lhs, rhs) == 0; +} + +#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING + +// Converts an array of wide chars to a narrow string using the UTF-8 +// encoding, and streams the result to the given Message object. +static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, + Message* msg) { + // TODO(wan): consider allowing a testing::String object to + // contain '\0'. This will make it behave more like std::string, + // and will allow ToUtf8String() to return the correct encoding + // for '\0' s.t. we can get rid of the conditional here (and in + // several other places). + for (size_t i = 0; i != length; ) { // NOLINT + if (wstr[i] != L'\0') { + *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); + while (i != length && wstr[i] != L'\0') + i++; + } else { + *msg << '\0'; + i++; + } + } +} + +#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING + +} // namespace internal + +#if GTEST_HAS_STD_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::std::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +// AssertionResult constructors. +// Used in EXPECT_TRUE/FALSE(assertion_result). +AssertionResult::AssertionResult(const AssertionResult& other) + : success_(other.success_), + message_(other.message_.get() != NULL ? + new ::std::string(*other.message_) : + static_cast< ::std::string*>(NULL)) { +} + +// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. +AssertionResult AssertionResult::operator!() const { + AssertionResult negation(!success_); + if (message_.get() != NULL) + negation << *message_; + return negation; +} + +// Makes a successful assertion result. +AssertionResult AssertionSuccess() { + return AssertionResult(true); +} + +// Makes a failed assertion result. +AssertionResult AssertionFailure() { + return AssertionResult(false); +} + +// Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << message. +AssertionResult AssertionFailure(const Message& message) { + return AssertionFailure() << message; +} + +namespace internal { + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// expected_expression: "foo" +// actual_expression: "bar" +// expected_value: "5" +// actual_value: "6" +// +// The ignoring_case parameter is true iff the assertion is a +// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// be inserted into the message. +AssertionResult EqFailure(const char* expected_expression, + const char* actual_expression, + const String& expected_value, + const String& actual_value, + bool ignoring_case) { + Message msg; + msg << "Value of: " << actual_expression; + if (actual_value != actual_expression) { + msg << "\n Actual: " << actual_value; + } + + msg << "\nExpected: " << expected_expression; + if (ignoring_case) { + msg << " (ignoring case)"; + } + if (expected_value != expected_expression) { + msg << "\nWhich is: " << expected_value; + } + + return AssertionFailure() << msg; +} + +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +String GetBoolAssertionFailureMessage(const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value) { + const char* actual_message = assertion_result.message(); + Message msg; + msg << "Value of: " << expression_text + << "\n Actual: " << actual_predicate_value; + if (actual_message[0] != '\0') + msg << " (" << actual_message << ")"; + msg << "\nExpected: " << expected_predicate_value; + return msg.GetString(); +} + +// Helper function for implementing ASSERT_NEAR. +AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error) { + const double diff = fabs(val1 - val2); + if (diff <= abs_error) return AssertionSuccess(); + + // TODO(wan): do not print the value of an expression if it's + // already a literal. + return AssertionFailure() + << "The difference between " << expr1 << " and " << expr2 + << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" + << expr1 << " evaluates to " << val1 << ",\n" + << expr2 << " evaluates to " << val2 << ", and\n" + << abs_error_expr << " evaluates to " << abs_error << "."; +} + + +// Helper template for implementing FloatLE() and DoubleLE(). +template +AssertionResult FloatingPointLE(const char* expr1, + const char* expr2, + RawType val1, + RawType val2) { + // Returns success if val1 is less than val2, + if (val1 < val2) { + return AssertionSuccess(); + } + + // or if val1 is almost equal to val2. + const FloatingPoint lhs(val1), rhs(val2); + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + // Note that the above two checks will both fail if either val1 or + // val2 is NaN, as the IEEE floating-point standard requires that + // any predicate involving a NaN must return false. + + ::std::stringstream val1_ss; + val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val1; + + ::std::stringstream val2_ss; + val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val2; + + return AssertionFailure() + << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" + << " Actual: " << StringStreamToString(&val1_ss) << " vs " + << StringStreamToString(&val2_ss); +} + +} // namespace internal + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +namespace internal { + +// The helper function for {ASSERT|EXPECT}_EQ with int or enum +// arguments. +AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual) { + if (expected == actual) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + FormatForComparisonFailureMessage(expected, actual), + FormatForComparisonFailureMessage(actual, expected), + false); +} + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here +// just to avoid copy-and-paste of similar code. +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + BiggestInt val1, BiggestInt val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + return AssertionFailure() \ + << "Expected: (" << expr1 << ") " #op " (" << expr2\ + << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ + << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + }\ +} + +// Implements the helper function for {ASSERT|EXPECT}_NE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(NE, !=) +// Implements the helper function for {ASSERT|EXPECT}_LE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(LE, <=) +// Implements the helper function for {ASSERT|EXPECT}_LT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(LT, < ) +// Implements the helper function for {ASSERT|EXPECT}_GE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(GE, >=) +// Implements the helper function for {ASSERT|EXPECT}_GT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(GT, > ) + +#undef GTEST_IMPL_CMP_HELPER_ + +// The helper function for {ASSERT|EXPECT}_STREQ. +AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual) { + if (String::CStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowCStringQuoted(expected), + String::ShowCStringQuoted(actual), + false); +} + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual) { + if (String::CaseInsensitiveCStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowCStringQuoted(expected), + String::ShowCStringQuoted(actual), + true); +} + +// The helper function for {ASSERT|EXPECT}_STRNE. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + return AssertionFailure() << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + } +} + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CaseInsensitiveCStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + return AssertionFailure() + << "Expected: (" << s1_expression << ") != (" + << s2_expression << ") (ignoring case), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + } +} + +} // namespace internal + +namespace { + +// Helper functions for implementing IsSubString() and IsNotSubstring(). + +// This group of overloaded functions return true iff needle is a +// substring of haystack. NULL is considered a substring of itself +// only. + +bool IsSubstringPred(const char* needle, const char* haystack) { + if (needle == NULL || haystack == NULL) + return needle == haystack; + + return strstr(haystack, needle) != NULL; +} + +bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { + if (needle == NULL || haystack == NULL) + return needle == haystack; + + return wcsstr(haystack, needle) != NULL; +} + +// StringType here can be either ::std::string or ::std::wstring. +template +bool IsSubstringPred(const StringType& needle, + const StringType& haystack) { + return haystack.find(needle) != StringType::npos; +} + +// This function implements either IsSubstring() or IsNotSubstring(), +// depending on the value of the expected_to_be_substring parameter. +// StringType here can be const char*, const wchar_t*, ::std::string, +// or ::std::wstring. +template +AssertionResult IsSubstringImpl( + bool expected_to_be_substring, + const char* needle_expr, const char* haystack_expr, + const StringType& needle, const StringType& haystack) { + if (IsSubstringPred(needle, haystack) == expected_to_be_substring) + return AssertionSuccess(); + + const bool is_wide_string = sizeof(needle[0]) > 1; + const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; + return AssertionFailure() + << "Value of: " << needle_expr << "\n" + << " Actual: " << begin_string_quote << needle << "\"\n" + << "Expected: " << (expected_to_be_substring ? "" : "not ") + << "a substring of " << haystack_expr << "\n" + << "Which is: " << begin_string_quote << haystack << "\""; +} + +} // namespace + +// IsSubstring() and IsNotSubstring() check whether needle is a +// substring of haystack (NULL is considered a substring of itself +// only), and return an appropriate error message when they fail. + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +#if GTEST_HAS_STD_WSTRING +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +#if GTEST_OS_WINDOWS + +namespace { + +// Helper function for IsHRESULT{SuccessFailure} predicates +AssertionResult HRESULTFailureHelper(const char* expr, + const char* expected, + long hr) { // NOLINT +# if GTEST_OS_WINDOWS_MOBILE + + // Windows CE doesn't support FormatMessage. + const char error_text[] = ""; + +# else + + // Looks up the human-readable system message for the HRESULT code + // and since we're not passing any params to FormatMessage, we don't + // want inserts expanded. + const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS; + const DWORD kBufSize = 4096; // String::Format can't exceed this length. + // Gets the system's human readable message string for this HRESULT. + char error_text[kBufSize] = { '\0' }; + DWORD message_length = ::FormatMessageA(kFlags, + 0, // no source, we're asking system + hr, // the error + 0, // no line width restrictions + error_text, // output buffer + kBufSize, // buf size + NULL); // no arguments for inserts + // Trims tailing white space (FormatMessage leaves a trailing cr-lf) + for (; message_length && IsSpace(error_text[message_length - 1]); + --message_length) { + error_text[message_length - 1] = '\0'; + } + +# endif // GTEST_OS_WINDOWS_MOBILE + + const String error_hex(String::Format("0x%08X ", hr)); + return ::testing::AssertionFailure() + << "Expected: " << expr << " " << expected << ".\n" + << " Actual: " << error_hex << error_text << "\n"; +} + +} // namespace + +AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT + if (SUCCEEDED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "succeeds", hr); +} + +AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT + if (FAILED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "fails", hr); +} + +#endif // GTEST_OS_WINDOWS + +// Utility functions for encoding Unicode text (wide strings) in +// UTF-8. + +// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 +// like this: +// +// Code-point length Encoding +// 0 - 7 bits 0xxxxxxx +// 8 - 11 bits 110xxxxx 10xxxxxx +// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx +// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + +// The maximum code-point a one-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; + +// The maximum code-point a two-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; + +// The maximum code-point a three-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; + +// The maximum code-point a four-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; + +// Chops off the n lowest bits from a bit pattern. Returns the n +// lowest bits. As a side effect, the original bit pattern will be +// shifted to the right by n bits. +inline UInt32 ChopLowBits(UInt32* bits, int n) { + const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); + *bits >>= n; + return low_bits; +} + +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// The output buffer str must containt at least 32 characters. +// The function returns the address of the output buffer. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. +char* CodePointToUtf8(UInt32 code_point, char* str) { + if (code_point <= kMaxCodePoint1) { + str[1] = '\0'; + str[0] = static_cast(code_point); // 0xxxxxxx + } else if (code_point <= kMaxCodePoint2) { + str[2] = '\0'; + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xC0 | code_point); // 110xxxxx + } else if (code_point <= kMaxCodePoint3) { + str[3] = '\0'; + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xE0 | code_point); // 1110xxxx + } else if (code_point <= kMaxCodePoint4) { + str[4] = '\0'; + str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xF0 | code_point); // 11110xxx + } else { + // The longest string String::Format can produce when invoked + // with these parameters is 28 character long (not including + // the terminating nul character). We are asking for 32 character + // buffer just in case. This is also enough for strncpy to + // null-terminate the destination string. + posix::StrNCpy( + str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32); + str[31] = '\0'; // Makes sure no change in the format to strncpy leaves + // the result unterminated. + } + return str; +} + +// The following two functions only make sense if the the system +// uses UTF-16 for wide string encoding. All supported systems +// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. + +// Determines if the arguments constitute UTF-16 surrogate pair +// and thus should be combined into a single Unicode code point +// using CreateCodePointFromUtf16SurrogatePair. +inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { + return sizeof(wchar_t) == 2 && + (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; +} + +// Creates a Unicode code point from UTF16 surrogate pair. +inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, + wchar_t second) { + const UInt32 mask = (1 << 10) - 1; + return (sizeof(wchar_t) == 2) ? + (((first & mask) << 10) | (second & mask)) + 0x10000 : + // This function should not be called when the condition is + // false, but we provide a sensible default in case it is. + static_cast(first); +} + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +String WideStringToUtf8(const wchar_t* str, int num_chars) { + if (num_chars == -1) + num_chars = static_cast(wcslen(str)); + + ::std::stringstream stream; + for (int i = 0; i < num_chars; ++i) { + UInt32 unicode_code_point; + + if (str[i] == L'\0') { + break; + } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { + unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], + str[i + 1]); + i++; + } else { + unicode_code_point = static_cast(str[i]); + } + + char buffer[32]; // CodePointToUtf8 requires a buffer this big. + stream << CodePointToUtf8(unicode_code_point, buffer); + } + return StringStreamToString(&stream); +} + +// Converts a wide C string to a String using the UTF-8 encoding. +// NULL will be converted to "(null)". +String String::ShowWideCString(const wchar_t * wide_c_str) { + if (wide_c_str == NULL) return String("(null)"); + + return String(internal::WideStringToUtf8(wide_c_str, -1).c_str()); +} + +// Similar to ShowWideCString(), except that this function encloses +// the converted string in double quotes. +String String::ShowWideCStringQuoted(const wchar_t* wide_c_str) { + if (wide_c_str == NULL) return String("(null)"); + + return String::Format("L\"%s\"", + String::ShowWideCString(wide_c_str).c_str()); +} + +// Compares two wide C strings. Returns true iff they have the same +// content. +// +// Unlike wcscmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { + if (lhs == NULL) return rhs == NULL; + + if (rhs == NULL) return false; + + return wcscmp(lhs, rhs) == 0; +} + +// Helper function for *_STREQ on wide strings. +AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const wchar_t* expected, + const wchar_t* actual) { + if (String::WideCStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowWideCStringQuoted(expected), + String::ShowWideCStringQuoted(actual), + false); +} + +// Helper function for *_STRNE on wide strings. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2) { + if (!String::WideCStringEquals(s1, s2)) { + return AssertionSuccess(); + } + + return AssertionFailure() << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: " + << String::ShowWideCStringQuoted(s1) + << " vs " << String::ShowWideCStringQuoted(s2); +} + +// Compares two C strings, ignoring case. Returns true iff they have +// the same content. +// +// Unlike strcasecmp(), this function can handle NULL argument(s). A +// NULL C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { + if (lhs == NULL) + return rhs == NULL; + if (rhs == NULL) + return false; + return posix::StrCaseCmp(lhs, rhs) == 0; +} + + // Compares two wide C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike wcscasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL wide C string, + // including the empty string. + // NB: The implementations on different platforms slightly differ. + // On windows, this method uses _wcsicmp which compares according to LC_CTYPE + // environment variable. On GNU platform this method uses wcscasecmp + // which compares according to LC_CTYPE category of the current locale. + // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the + // current locale. +bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs) { + if (lhs == NULL) return rhs == NULL; + + if (rhs == NULL) return false; + +#if GTEST_OS_WINDOWS + return _wcsicmp(lhs, rhs) == 0; +#elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID + return wcscasecmp(lhs, rhs) == 0; +#else + // Android, Mac OS X and Cygwin don't define wcscasecmp. + // Other unknown OSes may not define it either. + wint_t left, right; + do { + left = towlower(*lhs++); + right = towlower(*rhs++); + } while (left && left == right); + return left == right; +#endif // OS selector +} + +// Compares this with another String. +// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 +// if this is greater than rhs. +int String::Compare(const String & rhs) const { + const char* const lhs_c_str = c_str(); + const char* const rhs_c_str = rhs.c_str(); + + if (lhs_c_str == NULL) { + return rhs_c_str == NULL ? 0 : -1; // NULL < anything except NULL + } else if (rhs_c_str == NULL) { + return 1; + } + + const size_t shorter_str_len = + length() <= rhs.length() ? length() : rhs.length(); + for (size_t i = 0; i != shorter_str_len; i++) { + if (lhs_c_str[i] < rhs_c_str[i]) { + return -1; + } else if (lhs_c_str[i] > rhs_c_str[i]) { + return 1; + } + } + return (length() < rhs.length()) ? -1 : + (length() > rhs.length()) ? 1 : 0; +} + +// Returns true iff this String ends with the given suffix. *Any* +// String is considered to end with a NULL or empty suffix. +bool String::EndsWith(const char* suffix) const { + if (suffix == NULL || CStringEquals(suffix, "")) return true; + + if (c_str() == NULL) return false; + + const size_t this_len = strlen(c_str()); + const size_t suffix_len = strlen(suffix); + return (this_len >= suffix_len) && + CStringEquals(c_str() + this_len - suffix_len, suffix); +} + +// Returns true iff this String ends with the given suffix, ignoring case. +// Any String is considered to end with a NULL or empty suffix. +bool String::EndsWithCaseInsensitive(const char* suffix) const { + if (suffix == NULL || CStringEquals(suffix, "")) return true; + + if (c_str() == NULL) return false; + + const size_t this_len = strlen(c_str()); + const size_t suffix_len = strlen(suffix); + return (this_len >= suffix_len) && + CaseInsensitiveCStringEquals(c_str() + this_len - suffix_len, suffix); +} + +// Formats a list of arguments to a String, using the same format +// spec string as for printf. +// +// We do not use the StringPrintf class as it is not universally +// available. +// +// The result is limited to 4096 characters (including the tailing 0). +// If 4096 characters are not enough to format the input, or if +// there's an error, "" is +// returned. +String String::Format(const char * format, ...) { + va_list args; + va_start(args, format); + + char buffer[4096]; + const int kBufferSize = sizeof(buffer)/sizeof(buffer[0]); + + // MSVC 8 deprecates vsnprintf(), so we want to suppress warning + // 4996 (deprecated function) there. +#ifdef _MSC_VER // We are using MSVC. +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4996) // Temporarily disables warning 4996. + + const int size = vsnprintf(buffer, kBufferSize, format, args); + +# pragma warning(pop) // Restores the warning state. +#else // We are not using MSVC. + const int size = vsnprintf(buffer, kBufferSize, format, args); +#endif // _MSC_VER + va_end(args); + + // vsnprintf()'s behavior is not portable. When the buffer is not + // big enough, it returns a negative value in MSVC, and returns the + // needed buffer size on Linux. When there is an output error, it + // always returns a negative value. For simplicity, we lump the two + // error cases together. + if (size < 0 || size >= kBufferSize) { + return String(""); + } else { + return String(buffer, size); + } +} + +// Converts the buffer in a stringstream to a String, converting NUL +// bytes to "\\0" along the way. +String StringStreamToString(::std::stringstream* ss) { + const ::std::string& str = ss->str(); + const char* const start = str.c_str(); + const char* const end = start + str.length(); + + // We need to use a helper stringstream to do this transformation + // because String doesn't support push_back(). + ::std::stringstream helper; + for (const char* ch = start; ch != end; ++ch) { + if (*ch == '\0') { + helper << "\\0"; // Replaces NUL with "\\0"; + } else { + helper.put(*ch); + } + } + + return String(helper.str().c_str()); +} + +// Appends the user-supplied message to the Google-Test-generated message. +String AppendUserMessage(const String& gtest_msg, + const Message& user_msg) { + // Appends the user message if it's non-empty. + const String user_msg_string = user_msg.GetString(); + if (user_msg_string.empty()) { + return gtest_msg; + } + + Message msg; + msg << gtest_msg << "\n" << user_msg_string; + + return msg.GetString(); +} + +} // namespace internal + +// class TestResult + +// Creates an empty TestResult. +TestResult::TestResult() + : death_test_count_(0), + elapsed_time_(0) { +} + +// D'tor. +TestResult::~TestResult() { +} + +// Returns the i-th test part result among all the results. i can +// range from 0 to total_part_count() - 1. If i is not in that range, +// aborts the program. +const TestPartResult& TestResult::GetTestPartResult(int i) const { + if (i < 0 || i >= total_part_count()) + internal::posix::Abort(); + return test_part_results_.at(i); +} + +// Returns the i-th test property. i can range from 0 to +// test_property_count() - 1. If i is not in that range, aborts the +// program. +const TestProperty& TestResult::GetTestProperty(int i) const { + if (i < 0 || i >= test_property_count()) + internal::posix::Abort(); + return test_properties_.at(i); +} + +// Clears the test part results. +void TestResult::ClearTestPartResults() { + test_part_results_.clear(); +} + +// Adds a test part result to the list. +void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { + test_part_results_.push_back(test_part_result); +} + +// Adds a test property to the list. If a property with the same key as the +// supplied property is already represented, the value of this test_property +// replaces the old value for that key. +void TestResult::RecordProperty(const TestProperty& test_property) { + if (!ValidateTestProperty(test_property)) { + return; + } + internal::MutexLock lock(&test_properites_mutex_); + const std::vector::iterator property_with_matching_key = + std::find_if(test_properties_.begin(), test_properties_.end(), + internal::TestPropertyKeyIs(test_property.key())); + if (property_with_matching_key == test_properties_.end()) { + test_properties_.push_back(test_property); + return; + } + property_with_matching_key->SetValue(test_property.value()); +} + +// Adds a failure if the key is a reserved attribute of Google Test +// testcase tags. Returns true if the property is valid. +bool TestResult::ValidateTestProperty(const TestProperty& test_property) { + internal::String key(test_property.key()); + if (key == "name" || key == "status" || key == "time" || key == "classname") { + ADD_FAILURE() + << "Reserved key used in RecordProperty(): " + << key + << " ('name', 'status', 'time', and 'classname' are reserved by " + << GTEST_NAME_ << ")"; + return false; + } + return true; +} + +// Clears the object. +void TestResult::Clear() { + test_part_results_.clear(); + test_properties_.clear(); + death_test_count_ = 0; + elapsed_time_ = 0; +} + +// Returns true iff the test failed. +bool TestResult::Failed() const { + for (int i = 0; i < total_part_count(); ++i) { + if (GetTestPartResult(i).failed()) + return true; + } + return false; +} + +// Returns true iff the test part fatally failed. +static bool TestPartFatallyFailed(const TestPartResult& result) { + return result.fatally_failed(); +} + +// Returns true iff the test fatally failed. +bool TestResult::HasFatalFailure() const { + return CountIf(test_part_results_, TestPartFatallyFailed) > 0; +} + +// Returns true iff the test part non-fatally failed. +static bool TestPartNonfatallyFailed(const TestPartResult& result) { + return result.nonfatally_failed(); +} + +// Returns true iff the test has a non-fatal failure. +bool TestResult::HasNonfatalFailure() const { + return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; +} + +// Gets the number of all test parts. This is the sum of the number +// of successful test parts and the number of failed test parts. +int TestResult::total_part_count() const { + return static_cast(test_part_results_.size()); +} + +// Returns the number of the test properties. +int TestResult::test_property_count() const { + return static_cast(test_properties_.size()); +} + +// class Test + +// Creates a Test object. + +// The c'tor saves the values of all Google Test flags. +Test::Test() + : gtest_flag_saver_(new internal::GTestFlagSaver) { +} + +// The d'tor restores the values of all Google Test flags. +Test::~Test() { + delete gtest_flag_saver_; +} + +// Sets up the test fixture. +// +// A sub-class may override this. +void Test::SetUp() { +} + +// Tears down the test fixture. +// +// A sub-class may override this. +void Test::TearDown() { +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const char* key, const char* value) { + UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value); +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const char* key, int value) { + Message value_message; + value_message << value; + RecordProperty(key, value_message.GetString().c_str()); +} + +namespace internal { + +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, + const String& message) { + // This function is a friend of UnitTest and as such has access to + // AddTestPartResult. + UnitTest::GetInstance()->AddTestPartResult( + result_type, + NULL, // No info about the source file where the exception occurred. + -1, // We have no info on which line caused the exception. + message, + String()); // No stack trace, either. +} + +} // namespace internal + +// Google Test requires all tests in the same test case to use the same test +// fixture class. This function checks if the current test has the +// same fixture class as the first test in the current test case. If +// yes, it returns true; otherwise it generates a Google Test failure and +// returns false. +bool Test::HasSameFixtureClass() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + const TestCase* const test_case = impl->current_test_case(); + + // Info about the first test in the current test case. + const TestInfo* const first_test_info = test_case->test_info_list()[0]; + const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; + const char* const first_test_name = first_test_info->name(); + + // Info about the current test. + const TestInfo* const this_test_info = impl->current_test_info(); + const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_; + const char* const this_test_name = this_test_info->name(); + + if (this_fixture_id != first_fixture_id) { + // Is the first test defined using TEST? + const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); + // Is this test defined using TEST? + const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); + + if (first_is_TEST || this_is_TEST) { + // The user mixed TEST and TEST_F in this test case - we'll tell + // him/her how to fix it. + + // Gets the name of the TEST and the name of the TEST_F. Note + // that first_is_TEST and this_is_TEST cannot both be true, as + // the fixture IDs are different for the two tests. + const char* const TEST_name = + first_is_TEST ? first_test_name : this_test_name; + const char* const TEST_F_name = + first_is_TEST ? this_test_name : first_test_name; + + ADD_FAILURE() + << "All tests in the same test case must use the same test fixture\n" + << "class, so mixing TEST_F and TEST in the same test case is\n" + << "illegal. In test case " << this_test_info->test_case_name() + << ",\n" + << "test " << TEST_F_name << " is defined using TEST_F but\n" + << "test " << TEST_name << " is defined using TEST. You probably\n" + << "want to change the TEST to TEST_F or move it to another test\n" + << "case."; + } else { + // The user defined two fixture classes with the same name in + // two namespaces - we'll tell him/her how to fix it. + ADD_FAILURE() + << "All tests in the same test case must use the same test fixture\n" + << "class. However, in test case " + << this_test_info->test_case_name() << ",\n" + << "you defined test " << first_test_name + << " and test " << this_test_name << "\n" + << "using two different test fixture classes. This can happen if\n" + << "the two classes are from different namespaces or translation\n" + << "units and have the same name. You should probably rename one\n" + << "of the classes to put the tests into different test cases."; + } + return false; + } + + return true; +} + +#if GTEST_HAS_SEH + +// Adds an "exception thrown" fatal failure to the current test. This +// function returns its result via an output parameter pointer because VC++ +// prohibits creation of objects with destructors on stack in functions +// using __try (see error C2712). +static internal::String* FormatSehExceptionMessage(DWORD exception_code, + const char* location) { + Message message; + message << "SEH exception with code 0x" << std::setbase(16) << + exception_code << std::setbase(10) << " thrown in " << location << "."; + + return new internal::String(message.GetString()); +} + +#endif // GTEST_HAS_SEH + +#if GTEST_HAS_EXCEPTIONS + +// Adds an "exception thrown" fatal failure to the current test. +static internal::String FormatCxxExceptionMessage(const char* description, + const char* location) { + Message message; + if (description != NULL) { + message << "C++ exception with description \"" << description << "\""; + } else { + message << "Unknown C++ exception"; + } + message << " thrown in " << location << "."; + + return message.GetString(); +} + +static internal::String PrintTestPartResultToString( + const TestPartResult& test_part_result); + +// A failed Google Test assertion will throw an exception of this type when +// GTEST_FLAG(throw_on_failure) is true (if exceptions are enabled). We +// derive it from std::runtime_error, which is for errors presumably +// detectable only at run time. Since std::runtime_error inherits from +// std::exception, many testing frameworks know how to extract and print the +// message inside it. +class GoogleTestFailureException : public ::std::runtime_error { + public: + explicit GoogleTestFailureException(const TestPartResult& failure) + : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} +}; +#endif // GTEST_HAS_EXCEPTIONS + +namespace internal { +// We put these helper functions in the internal namespace as IBM's xlC +// compiler rejects the code if they were declared static. + +// Runs the given method and handles SEH exceptions it throws, when +// SEH is supported; returns the 0-value for type Result in case of an +// SEH exception. (Microsoft compilers cannot handle SEH and C++ +// exceptions in the same function. Therefore, we provide a separate +// wrapper function for handling SEH exceptions.) +template +Result HandleSehExceptionsInMethodIfSupported( + T* object, Result (T::*method)(), const char* location) { +#if GTEST_HAS_SEH + __try { + return (object->*method)(); + } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT + GetExceptionCode())) { + // We create the exception message on the heap because VC++ prohibits + // creation of objects with destructors on stack in functions using __try + // (see error C2712). + internal::String* exception_message = FormatSehExceptionMessage( + GetExceptionCode(), location); + internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, + *exception_message); + delete exception_message; + return static_cast(0); + } +#else + (void)location; + return (object->*method)(); +#endif // GTEST_HAS_SEH +} + +// Runs the given method and catches and reports C++ and/or SEH-style +// exceptions, if they are supported; returns the 0-value for type +// Result in case of an SEH exception. +template +Result HandleExceptionsInMethodIfSupported( + T* object, Result (T::*method)(), const char* location) { + // NOTE: The user code can affect the way in which Google Test handles + // exceptions by setting GTEST_FLAG(catch_exceptions), but only before + // RUN_ALL_TESTS() starts. It is technically possible to check the flag + // after the exception is caught and either report or re-throw the + // exception based on the flag's value: + // + // try { + // // Perform the test method. + // } catch (...) { + // if (GTEST_FLAG(catch_exceptions)) + // // Report the exception as failure. + // else + // throw; // Re-throws the original exception. + // } + // + // However, the purpose of this flag is to allow the program to drop into + // the debugger when the exception is thrown. On most platforms, once the + // control enters the catch block, the exception origin information is + // lost and the debugger will stop the program at the point of the + // re-throw in this function -- instead of at the point of the original + // throw statement in the code under test. For this reason, we perform + // the check early, sacrificing the ability to affect Google Test's + // exception handling in the method where the exception is thrown. + if (internal::GetUnitTestImpl()->catch_exceptions()) { +#if GTEST_HAS_EXCEPTIONS + try { + return HandleSehExceptionsInMethodIfSupported(object, method, location); + } catch (const GoogleTestFailureException&) { // NOLINT + // This exception doesn't originate in code under test. It makes no + // sense to report it as a test failure. + throw; + } catch (const std::exception& e) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(e.what(), location)); + } catch (...) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(NULL, location)); + } + return static_cast(0); +#else + return HandleSehExceptionsInMethodIfSupported(object, method, location); +#endif // GTEST_HAS_EXCEPTIONS + } else { + return (object->*method)(); + } +} + +} // namespace internal + +// Runs the test and updates the test result. +void Test::Run() { + if (!HasSameFixtureClass()) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); + // We will run the test only if SetUp() was successful. + if (!HasFatalFailure()) { + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &Test::TestBody, "the test body"); + } + + // However, we want to clean up as much as possible. Hence we will + // always call TearDown(), even if SetUp() or the test body has + // failed. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &Test::TearDown, "TearDown()"); +} + +// Returns true iff the current test has a fatal failure. +bool Test::HasFatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); +} + +// Returns true iff the current test has a non-fatal failure. +bool Test::HasNonfatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()-> + HasNonfatalFailure(); +} + +// class TestInfo + +// Constructs a TestInfo object. It assumes ownership of the test factory +// object. +// TODO(vladl@google.com): Make a_test_case_name and a_name const string&'s +// to signify they cannot be NULLs. +TestInfo::TestInfo(const char* a_test_case_name, + const char* a_name, + const char* a_type_param, + const char* a_value_param, + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory) + : test_case_name_(a_test_case_name), + name_(a_name), + type_param_(a_type_param ? new std::string(a_type_param) : NULL), + value_param_(a_value_param ? new std::string(a_value_param) : NULL), + fixture_class_id_(fixture_class_id), + should_run_(false), + is_disabled_(false), + matches_filter_(false), + factory_(factory), + result_() {} + +// Destructs a TestInfo object. +TestInfo::~TestInfo() { delete factory_; } + +namespace internal { + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. +// +// Arguments: +// +// test_case_name: name of the test case +// name: name of the test +// type_param: the name of the test's type parameter, or NULL if +// this is not a typed or a type-parameterized test. +// value_param: text representation of the test's value parameter, +// or NULL if this is not a value-parameterized test. +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +TestInfo* MakeAndRegisterTestInfo( + const char* test_case_name, const char* name, + const char* type_param, + const char* value_param, + TypeId fixture_class_id, + SetUpTestCaseFunc set_up_tc, + TearDownTestCaseFunc tear_down_tc, + TestFactoryBase* factory) { + TestInfo* const test_info = + new TestInfo(test_case_name, name, type_param, value_param, + fixture_class_id, factory); + GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); + return test_info; +} + +#if GTEST_HAS_PARAM_TEST +void ReportInvalidTestCaseType(const char* test_case_name, + const char* file, int line) { + Message errors; + errors + << "Attempted redefinition of test case " << test_case_name << ".\n" + << "All tests in the same test case must use the same test fixture\n" + << "class. However, in test case " << test_case_name << ", you tried\n" + << "to define a test using a fixture class different from the one\n" + << "used earlier. This can happen if the two fixture classes are\n" + << "from different namespaces and have the same name. You should\n" + << "probably rename one of the classes to put the tests into different\n" + << "test cases."; + + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors.GetString().c_str()); +} +#endif // GTEST_HAS_PARAM_TEST + +} // namespace internal + +namespace { + +// A predicate that checks the test name of a TestInfo against a known +// value. +// +// This is used for implementation of the TestCase class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestNameIs is copyable. +class TestNameIs { + public: + // Constructor. + // + // TestNameIs has NO default constructor. + explicit TestNameIs(const char* name) + : name_(name) {} + + // Returns true iff the test name of test_info matches name_. + bool operator()(const TestInfo * test_info) const { + return test_info && internal::String(test_info->name()).Compare(name_) == 0; + } + + private: + internal::String name_; +}; + +} // namespace + +namespace internal { + +// This method expands all parameterized tests registered with macros TEST_P +// and INSTANTIATE_TEST_CASE_P into regular tests and registers those. +// This will be done just once during the program runtime. +void UnitTestImpl::RegisterParameterizedTests() { +#if GTEST_HAS_PARAM_TEST + if (!parameterized_tests_registered_) { + parameterized_test_registry_.RegisterTests(); + parameterized_tests_registered_ = true; + } +#endif +} + +} // namespace internal + +// Creates the test object, runs it, records its result, and then +// deletes it. +void TestInfo::Run() { + if (!should_run_) return; + + // Tells UnitTest where to store test result. + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_info(this); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + // Notifies the unit test event listeners that a test is about to start. + repeater->OnTestStart(*this); + + const TimeInMillis start = internal::GetTimeInMillis(); + + impl->os_stack_trace_getter()->UponLeavingGTest(); + + // Creates the test object. + Test* const test = internal::HandleExceptionsInMethodIfSupported( + factory_, &internal::TestFactoryBase::CreateTest, + "the test fixture's constructor"); + + // Runs the test only if the test object was created and its + // constructor didn't generate a fatal failure. + if ((test != NULL) && !Test::HasFatalFailure()) { + // This doesn't throw as all user code that can throw are wrapped into + // exception handling code. + test->Run(); + } + + // Deletes the test object. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + test, &Test::DeleteSelf_, "the test fixture's destructor"); + + result_.set_elapsed_time(internal::GetTimeInMillis() - start); + + // Notifies the unit test event listener that a test has just finished. + repeater->OnTestEnd(*this); + + // Tells UnitTest to stop associating assertion results to this + // test. + impl->set_current_test_info(NULL); +} + +// class TestCase + +// Gets the number of successful tests in this test case. +int TestCase::successful_test_count() const { + return CountIf(test_info_list_, TestPassed); +} + +// Gets the number of failed tests in this test case. +int TestCase::failed_test_count() const { + return CountIf(test_info_list_, TestFailed); +} + +int TestCase::disabled_test_count() const { + return CountIf(test_info_list_, TestDisabled); +} + +// Get the number of tests in this test case that should run. +int TestCase::test_to_run_count() const { + return CountIf(test_info_list_, ShouldRunTest); +} + +// Gets the number of all tests. +int TestCase::total_test_count() const { + return static_cast(test_info_list_.size()); +} + +// Creates a TestCase with the given name. +// +// Arguments: +// +// name: name of the test case +// a_type_param: the name of the test case's type parameter, or NULL if +// this is not a typed or a type-parameterized test case. +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +TestCase::TestCase(const char* a_name, const char* a_type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc) + : name_(a_name), + type_param_(a_type_param ? new std::string(a_type_param) : NULL), + set_up_tc_(set_up_tc), + tear_down_tc_(tear_down_tc), + should_run_(false), + elapsed_time_(0) { +} + +// Destructor of TestCase. +TestCase::~TestCase() { + // Deletes every Test in the collection. + ForEach(test_info_list_, internal::Delete); +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +const TestInfo* TestCase::GetTestInfo(int i) const { + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? NULL : test_info_list_[index]; +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +TestInfo* TestCase::GetMutableTestInfo(int i) { + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? NULL : test_info_list_[index]; +} + +// Adds a test to this test case. Will delete the test upon +// destruction of the TestCase object. +void TestCase::AddTestInfo(TestInfo * test_info) { + test_info_list_.push_back(test_info); + test_indices_.push_back(static_cast(test_indices_.size())); +} + +// Runs every test in this TestCase. +void TestCase::Run() { + if (!should_run_) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_case(this); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + repeater->OnTestCaseStart(*this); + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); + + const internal::TimeInMillis start = internal::GetTimeInMillis(); + for (int i = 0; i < total_test_count(); i++) { + GetMutableTestInfo(i)->Run(); + } + elapsed_time_ = internal::GetTimeInMillis() - start; + + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); + + repeater->OnTestCaseEnd(*this); + impl->set_current_test_case(NULL); +} + +// Clears the results of all tests in this test case. +void TestCase::ClearResult() { + ForEach(test_info_list_, TestInfo::ClearTestResult); +} + +// Shuffles the tests in this test case. +void TestCase::ShuffleTests(internal::Random* random) { + Shuffle(random, &test_indices_); +} + +// Restores the test order to before the first shuffle. +void TestCase::UnshuffleTests() { + for (size_t i = 0; i < test_indices_.size(); i++) { + test_indices_[i] = static_cast(i); + } +} + +// Formats a countable noun. Depending on its quantity, either the +// singular form or the plural form is used. e.g. +// +// FormatCountableNoun(1, "formula", "formuli") returns "1 formula". +// FormatCountableNoun(5, "book", "books") returns "5 books". +static internal::String FormatCountableNoun(int count, + const char * singular_form, + const char * plural_form) { + return internal::String::Format("%d %s", count, + count == 1 ? singular_form : plural_form); +} + +// Formats the count of tests. +static internal::String FormatTestCount(int test_count) { + return FormatCountableNoun(test_count, "test", "tests"); +} + +// Formats the count of test cases. +static internal::String FormatTestCaseCount(int test_case_count) { + return FormatCountableNoun(test_case_count, "test case", "test cases"); +} + +// Converts a TestPartResult::Type enum to human-friendly string +// representation. Both kNonFatalFailure and kFatalFailure are translated +// to "Failure", as the user usually doesn't care about the difference +// between the two when viewing the test result. +static const char * TestPartResultTypeToString(TestPartResult::Type type) { + switch (type) { + case TestPartResult::kSuccess: + return "Success"; + + case TestPartResult::kNonFatalFailure: + case TestPartResult::kFatalFailure: +#ifdef _MSC_VER + return "error: "; +#else + return "Failure\n"; +#endif + default: + return "Unknown result type"; + } +} + +// Prints a TestPartResult to a String. +static internal::String PrintTestPartResultToString( + const TestPartResult& test_part_result) { + return (Message() + << internal::FormatFileLocation(test_part_result.file_name(), + test_part_result.line_number()) + << " " << TestPartResultTypeToString(test_part_result.type()) + << test_part_result.message()).GetString(); +} + +// Prints a TestPartResult. +static void PrintTestPartResult(const TestPartResult& test_part_result) { + const internal::String& result = + PrintTestPartResultToString(test_part_result); + printf("%s\n", result.c_str()); + fflush(stdout); + // If the test program runs in Visual Studio or a debugger, the + // following statements add the test part result message to the Output + // window such that the user can double-click on it to jump to the + // corresponding source code location; otherwise they do nothing. +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + // We don't call OutputDebugString*() on Windows Mobile, as printing + // to stdout is done by OutputDebugString() there already - we don't + // want the same message printed twice. + ::OutputDebugStringA(result.c_str()); + ::OutputDebugStringA("\n"); +#endif +} + +// class PrettyUnitTestResultPrinter + +namespace internal { + +enum GTestColor { + COLOR_DEFAULT, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW +}; + +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + +// Returns the character attribute for the given color. +WORD GetColorAttribute(GTestColor color) { + switch (color) { + case COLOR_RED: return FOREGROUND_RED; + case COLOR_GREEN: return FOREGROUND_GREEN; + case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; + default: return 0; + } +} + +#else + +// Returns the ANSI color code for the given color. COLOR_DEFAULT is +// an invalid input. +const char* GetAnsiColorCode(GTestColor color) { + switch (color) { + case COLOR_RED: return "1"; + case COLOR_GREEN: return "2"; + case COLOR_YELLOW: return "3"; + default: return NULL; + }; +} + +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + +// Returns true iff Google Test should use colors in the output. +bool ShouldUseColor(bool stdout_is_tty) { + const char* const gtest_color = GTEST_FLAG(color).c_str(); + + if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { +#if GTEST_OS_WINDOWS + // On Windows the TERM variable is usually not set, but the + // console there does support colors. + return stdout_is_tty; +#else + // On non-Windows platforms, we rely on the TERM variable. + const char* const term = posix::GetEnv("TERM"); + const bool term_supports_color = + String::CStringEquals(term, "xterm") || + String::CStringEquals(term, "xterm-color") || + String::CStringEquals(term, "xterm-256color") || + String::CStringEquals(term, "screen") || + String::CStringEquals(term, "linux") || + String::CStringEquals(term, "cygwin"); + return stdout_is_tty && term_supports_color; +#endif // GTEST_OS_WINDOWS + } + + return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || + String::CaseInsensitiveCStringEquals(gtest_color, "true") || + String::CaseInsensitiveCStringEquals(gtest_color, "t") || + String::CStringEquals(gtest_color, "1"); + // We take "yes", "true", "t", and "1" as meaning "yes". If the + // value is neither one of these nor "auto", we treat it as "no" to + // be conservative. +} + +// Helpers for printing colored strings to stdout. Note that on Windows, we +// cannot simply emit special characters and have the terminal change colors. +// This routine must actually emit the characters rather than return a string +// that would be colored when printed, as can be done on Linux. +void ColoredPrintf(GTestColor color, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS + const bool use_color = false; +#else + static const bool in_color_mode = + ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); + const bool use_color = in_color_mode && (color != COLOR_DEFAULT); +#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS + // The '!= 0' comparison is necessary to satisfy MSVC 7.1. + + if (!use_color) { + vprintf(fmt, args); + va_end(args); + return; + } + +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); + + // Gets the current text color. + CONSOLE_SCREEN_BUFFER_INFO buffer_info; + GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); + const WORD old_color_attrs = buffer_info.wAttributes; + + // We need to flush the stream buffers into the console before each + // SetConsoleTextAttribute call lest it affect the text that is already + // printed but has not yet reached the console. + fflush(stdout); + SetConsoleTextAttribute(stdout_handle, + GetColorAttribute(color) | FOREGROUND_INTENSITY); + vprintf(fmt, args); + + fflush(stdout); + // Restores the text color. + SetConsoleTextAttribute(stdout_handle, old_color_attrs); +#else + printf("\033[0;3%sm", GetAnsiColorCode(color)); + vprintf(fmt, args); + printf("\033[m"); // Resets the terminal to default. +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + va_end(args); +} + +void PrintFullTestCommentIfPresent(const TestInfo& test_info) { + const char* const type_param = test_info.type_param(); + const char* const value_param = test_info.value_param(); + + if (type_param != NULL || value_param != NULL) { + printf(", where "); + if (type_param != NULL) { + printf("TypeParam = %s", type_param); + if (value_param != NULL) + printf(" and "); + } + if (value_param != NULL) { + printf("GetParam() = %s", value_param); + } + } +} + +// This class implements the TestEventListener interface. +// +// Class PrettyUnitTestResultPrinter is copyable. +class PrettyUnitTestResultPrinter : public TestEventListener { + public: + PrettyUnitTestResultPrinter() {} + static void PrintTestName(const char * test_case, const char * test) { + printf("%s.%s", test_case, test); + } + + // The following methods override what's in the TestEventListener class. + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); + virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestCaseStart(const TestCase& test_case); + virtual void OnTestStart(const TestInfo& test_info); + virtual void OnTestPartResult(const TestPartResult& result); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} + + private: + static void PrintFailedTests(const UnitTest& unit_test); + + internal::String test_case_name_; +}; + + // Fired before each iteration of tests starts. +void PrettyUnitTestResultPrinter::OnTestIterationStart( + const UnitTest& unit_test, int iteration) { + if (GTEST_FLAG(repeat) != 1) + printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); + + const char* const filter = GTEST_FLAG(filter).c_str(); + + // Prints the filter if it's not *. This reminds the user that some + // tests may be skipped. + if (!internal::String::CStringEquals(filter, kUniversalFilter)) { + ColoredPrintf(COLOR_YELLOW, + "Note: %s filter = %s\n", GTEST_NAME_, filter); + } + + if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { + const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); + ColoredPrintf(COLOR_YELLOW, + "Note: This is test shard %d of %s.\n", + static_cast(shard_index) + 1, + internal::posix::GetEnv(kTestTotalShards)); + } + + if (GTEST_FLAG(shuffle)) { + ColoredPrintf(COLOR_YELLOW, + "Note: Randomizing tests' orders with a seed of %d .\n", + unit_test.random_seed()); + } + + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("Running %s from %s.\n", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( + const UnitTest& /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment set-up.\n"); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { + test_case_name_ = test_case.name(); + const internal::String counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s", counts.c_str(), test_case_name_.c_str()); + if (test_case.type_param() == NULL) { + printf("\n"); + } else { + printf(", where TypeParam = %s\n", test_case.type_param()); + } + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { + ColoredPrintf(COLOR_GREEN, "[ RUN ] "); + PrintTestName(test_case_name_.c_str(), test_info.name()); + printf("\n"); + fflush(stdout); +} + +// Called after an assertion failure. +void PrettyUnitTestResultPrinter::OnTestPartResult( + const TestPartResult& result) { + // If the test part succeeded, we don't need to do anything. + if (result.type() == TestPartResult::kSuccess) + return; + + // Print failure message from the assertion (e.g. expected this and got that). + PrintTestPartResult(result); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { + if (test_info.result()->Passed()) { + ColoredPrintf(COLOR_GREEN, "[ OK ] "); + } else { + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + } + PrintTestName(test_case_name_.c_str(), test_info.name()); + if (test_info.result()->Failed()) + PrintFullTestCommentIfPresent(test_info); + + if (GTEST_FLAG(print_time)) { + printf(" (%s ms)\n", internal::StreamableToString( + test_info.result()->elapsed_time()).c_str()); + } else { + printf("\n"); + } + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { + if (!GTEST_FLAG(print_time)) return; + + test_case_name_ = test_case.name(); + const internal::String counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s (%s ms total)\n\n", + counts.c_str(), test_case_name_.c_str(), + internal::StreamableToString(test_case.elapsed_time()).c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( + const UnitTest& /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment tear-down\n"); + fflush(stdout); +} + +// Internal helper for printing the list of failed tests. +void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { + const int failed_test_count = unit_test.failed_test_count(); + if (failed_test_count == 0) { + return; + } + + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + const TestCase& test_case = *unit_test.GetTestCase(i); + if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { + continue; + } + for (int j = 0; j < test_case.total_test_count(); ++j) { + const TestInfo& test_info = *test_case.GetTestInfo(j); + if (!test_info.should_run() || test_info.result()->Passed()) { + continue; + } + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s.%s", test_case.name(), test_info.name()); + PrintFullTestCommentIfPresent(test_info); + printf("\n"); + } + } +} + +void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("%s from %s ran.", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + if (GTEST_FLAG(print_time)) { + printf(" (%s ms total)", + internal::StreamableToString(unit_test.elapsed_time()).c_str()); + } + printf("\n"); + ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); + printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); + + int num_failures = unit_test.failed_test_count(); + if (!unit_test.Passed()) { + const int failed_test_count = unit_test.failed_test_count(); + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); + PrintFailedTests(unit_test); + printf("\n%2d FAILED %s\n", num_failures, + num_failures == 1 ? "TEST" : "TESTS"); + } + + int num_disabled = unit_test.disabled_test_count(); + if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { + if (!num_failures) { + printf("\n"); // Add a spacer if no FAILURE banner is displayed. + } + ColoredPrintf(COLOR_YELLOW, + " YOU HAVE %d DISABLED %s\n\n", + num_disabled, + num_disabled == 1 ? "TEST" : "TESTS"); + } + // Ensure that Google Test output is printed before, e.g., heapchecker output. + fflush(stdout); +} + +// End PrettyUnitTestResultPrinter + +// class TestEventRepeater +// +// This class forwards events to other event listeners. +class TestEventRepeater : public TestEventListener { + public: + TestEventRepeater() : forwarding_enabled_(true) {} + virtual ~TestEventRepeater(); + void Append(TestEventListener *listener); + TestEventListener* Release(TestEventListener* listener); + + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled() const { return forwarding_enabled_; } + void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } + + virtual void OnTestProgramStart(const UnitTest& unit_test); + virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); + virtual void OnTestCaseStart(const TestCase& test_case); + virtual void OnTestStart(const TestInfo& test_info); + virtual void OnTestPartResult(const TestPartResult& result); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnTestProgramEnd(const UnitTest& unit_test); + + private: + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled_; + // The list of listeners that receive events. + std::vector listeners_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); +}; + +TestEventRepeater::~TestEventRepeater() { + ForEach(listeners_, Delete); +} + +void TestEventRepeater::Append(TestEventListener *listener) { + listeners_.push_back(listener); +} + +// TODO(vladl@google.com): Factor the search functionality into Vector::Find. +TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { + for (size_t i = 0; i < listeners_.size(); ++i) { + if (listeners_[i] == listener) { + listeners_.erase(listeners_.begin() + i); + return listener; + } + } + + return NULL; +} + +// Since most methods are very similar, use macros to reduce boilerplate. +// This defines a member that forwards the call to all listeners. +#define GTEST_REPEATER_METHOD_(Name, Type) \ +void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (size_t i = 0; i < listeners_.size(); i++) { \ + listeners_[i]->Name(parameter); \ + } \ + } \ +} +// This defines a member that forwards the call to all listeners in reverse +// order. +#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ +void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ + listeners_[i]->Name(parameter); \ + } \ + } \ +} + +GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) +GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) +GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) +GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) +GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) +GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) +GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) +GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) + +#undef GTEST_REPEATER_METHOD_ +#undef GTEST_REVERSE_REPEATER_METHOD_ + +void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (size_t i = 0; i < listeners_.size(); i++) { + listeners_[i]->OnTestIterationStart(unit_test, iteration); + } + } +} + +void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { + listeners_[i]->OnTestIterationEnd(unit_test, iteration); + } + } +} + +// End TestEventRepeater + +// This class generates an XML output file. +class XmlUnitTestResultPrinter : public EmptyTestEventListener { + public: + explicit XmlUnitTestResultPrinter(const char* output_file); + + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + + private: + // Is c a whitespace character that is normalized to a space character + // when it appears in an XML attribute value? + static bool IsNormalizableWhitespace(char c) { + return c == 0x9 || c == 0xA || c == 0xD; + } + + // May c appear in a well-formed XML document? + static bool IsValidXmlCharacter(char c) { + return IsNormalizableWhitespace(c) || c >= 0x20; + } + + // Returns an XML-escaped copy of the input string str. If + // is_attribute is true, the text is meant to appear as an attribute + // value, and normalizable whitespace is preserved by replacing it + // with character references. + static String EscapeXml(const char* str, bool is_attribute); + + // Returns the given string with all characters invalid in XML removed. + static string RemoveInvalidXmlCharacters(const string& str); + + // Convenience wrapper around EscapeXml when str is an attribute value. + static String EscapeXmlAttribute(const char* str) { + return EscapeXml(str, true); + } + + // Convenience wrapper around EscapeXml when str is not an attribute value. + static String EscapeXmlText(const char* str) { return EscapeXml(str, false); } + + // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. + static void OutputXmlCDataSection(::std::ostream* stream, const char* data); + + // Streams an XML representation of a TestInfo object. + static void OutputXmlTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info); + + // Prints an XML representation of a TestCase object + static void PrintXmlTestCase(FILE* out, const TestCase& test_case); + + // Prints an XML summary of unit_test to output stream out. + static void PrintXmlUnitTest(FILE* out, const UnitTest& unit_test); + + // Produces a string representing the test properties in a result as space + // delimited XML attributes based on the property key="value" pairs. + // When the String is not empty, it includes a space at the beginning, + // to delimit this attribute from prior attributes. + static String TestPropertiesAsXmlAttributes(const TestResult& result); + + // The output file. + const String output_file_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); +}; + +// Creates a new XmlUnitTestResultPrinter. +XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) + : output_file_(output_file) { + if (output_file_.c_str() == NULL || output_file_.empty()) { + fprintf(stderr, "XML output file may not be null\n"); + fflush(stderr); + exit(EXIT_FAILURE); + } +} + +// Called after the unit test ends. +void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + FILE* xmlout = NULL; + FilePath output_file(output_file_); + FilePath output_dir(output_file.RemoveFileName()); + + if (output_dir.CreateDirectoriesRecursively()) { + xmlout = posix::FOpen(output_file_.c_str(), "w"); + } + if (xmlout == NULL) { + // TODO(wan): report the reason of the failure. + // + // We don't do it for now as: + // + // 1. There is no urgent need for it. + // 2. It's a bit involved to make the errno variable thread-safe on + // all three operating systems (Linux, Windows, and Mac OS). + // 3. To interpret the meaning of errno in a thread-safe way, + // we need the strerror_r() function, which is not available on + // Windows. + fprintf(stderr, + "Unable to open file \"%s\"\n", + output_file_.c_str()); + fflush(stderr); + exit(EXIT_FAILURE); + } + PrintXmlUnitTest(xmlout, unit_test); + fclose(xmlout); +} + +// Returns an XML-escaped copy of the input string str. If is_attribute +// is true, the text is meant to appear as an attribute value, and +// normalizable whitespace is preserved by replacing it with character +// references. +// +// Invalid XML characters in str, if any, are stripped from the output. +// It is expected that most, if not all, of the text processed by this +// module will consist of ordinary English text. +// If this module is ever modified to produce version 1.1 XML output, +// most invalid characters can be retained using character references. +// TODO(wan): It might be nice to have a minimally invasive, human-readable +// escaping scheme for invalid characters, rather than dropping them. +String XmlUnitTestResultPrinter::EscapeXml(const char* str, bool is_attribute) { + Message m; + + if (str != NULL) { + for (const char* src = str; *src; ++src) { + switch (*src) { + case '<': + m << "<"; + break; + case '>': + m << ">"; + break; + case '&': + m << "&"; + break; + case '\'': + if (is_attribute) + m << "'"; + else + m << '\''; + break; + case '"': + if (is_attribute) + m << """; + else + m << '"'; + break; + default: + if (IsValidXmlCharacter(*src)) { + if (is_attribute && IsNormalizableWhitespace(*src)) + m << String::Format("&#x%02X;", unsigned(*src)); + else + m << *src; + } + break; + } + } + } + + return m.GetString(); +} + +// Returns the given string with all characters invalid in XML removed. +// Currently invalid characters are dropped from the string. An +// alternative is to replace them with certain characters such as . or ?. +string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const string& str) { + string output; + output.reserve(str.size()); + for (string::const_iterator it = str.begin(); it != str.end(); ++it) + if (IsValidXmlCharacter(*it)) + output.push_back(*it); + + return output; +} + +// The following routines generate an XML representation of a UnitTest +// object. +// +// This is how Google Test concepts map to the DTD: +// +// <-- corresponds to a UnitTest object +// <-- corresponds to a TestCase object +// <-- corresponds to a TestInfo object +// ... +// ... +// ... +// <-- individual assertion failures +// +// +// + +// Formats the given time in milliseconds as seconds. +std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { + ::std::stringstream ss; + ss << ms/1000.0; + return ss.str(); +} + +// Streams an XML CDATA section, escaping invalid CDATA sequences as needed. +void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, + const char* data) { + const char* segment = data; + *stream << ""); + if (next_segment != NULL) { + stream->write( + segment, static_cast(next_segment - segment)); + *stream << "]]>]]>"); + } else { + *stream << segment; + break; + } + } + *stream << "]]>"; +} + +// Prints an XML representation of a TestInfo object. +// TODO(wan): There is also value in printing properties with the plain printer. +void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info) { + const TestResult& result = *test_info.result(); + *stream << " \n"; + *stream << " "; + const string location = internal::FormatCompilerIndependentFileLocation( + part.file_name(), part.line_number()); + const string message = location + "\n" + part.message(); + OutputXmlCDataSection(stream, + RemoveInvalidXmlCharacters(message).c_str()); + *stream << "\n"; + } + } + + if (failures == 0) + *stream << " />\n"; + else + *stream << " \n"; +} + +// Prints an XML representation of a TestCase object +void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, + const TestCase& test_case) { + fprintf(out, + " \n", + FormatTimeInMillisAsSeconds(test_case.elapsed_time()).c_str()); + for (int i = 0; i < test_case.total_test_count(); ++i) { + ::std::stringstream stream; + OutputXmlTestInfo(&stream, test_case.name(), *test_case.GetTestInfo(i)); + fprintf(out, "%s", StringStreamToString(&stream).c_str()); + } + fprintf(out, " \n"); +} + +// Prints an XML summary of unit_test to output stream out. +void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, + const UnitTest& unit_test) { + fprintf(out, "\n"); + fprintf(out, + "\n"); + for (int i = 0; i < unit_test.total_test_case_count(); ++i) + PrintXmlTestCase(out, *unit_test.GetTestCase(i)); + fprintf(out, "\n"); +} + +// Produces a string representing the test properties in a result as space +// delimited XML attributes based on the property key="value" pairs. +String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( + const TestResult& result) { + Message attributes; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + attributes << " " << property.key() << "=" + << "\"" << EscapeXmlAttribute(property.value()) << "\""; + } + return attributes.GetString(); +} + +// End XmlUnitTestResultPrinter + +#if GTEST_CAN_STREAM_RESULTS_ + +// Streams test results to the given port on the given host machine. +class StreamingListener : public EmptyTestEventListener { + public: + // Escapes '=', '&', '%', and '\n' characters in str as "%xx". + static string UrlEncode(const char* str); + + StreamingListener(const string& host, const string& port) + : sockfd_(-1), host_name_(host), port_num_(port) { + MakeConnection(); + Send("gtest_streaming_protocol_version=1.0\n"); + } + + virtual ~StreamingListener() { + if (sockfd_ != -1) + CloseConnection(); + } + + void OnTestProgramStart(const UnitTest& /* unit_test */) { + Send("event=TestProgramStart\n"); + } + + void OnTestProgramEnd(const UnitTest& unit_test) { + // Note that Google Test current only report elapsed time for each + // test iteration, not for the entire test program. + Send(String::Format("event=TestProgramEnd&passed=%d\n", + unit_test.Passed())); + + // Notify the streaming server to stop. + CloseConnection(); + } + + void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { + Send(String::Format("event=TestIterationStart&iteration=%d\n", + iteration)); + } + + void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { + Send(String::Format("event=TestIterationEnd&passed=%d&elapsed_time=%sms\n", + unit_test.Passed(), + StreamableToString(unit_test.elapsed_time()).c_str())); + } + + void OnTestCaseStart(const TestCase& test_case) { + Send(String::Format("event=TestCaseStart&name=%s\n", test_case.name())); + } + + void OnTestCaseEnd(const TestCase& test_case) { + Send(String::Format("event=TestCaseEnd&passed=%d&elapsed_time=%sms\n", + test_case.Passed(), + StreamableToString(test_case.elapsed_time()).c_str())); + } + + void OnTestStart(const TestInfo& test_info) { + Send(String::Format("event=TestStart&name=%s\n", test_info.name())); + } + + void OnTestEnd(const TestInfo& test_info) { + Send(String::Format( + "event=TestEnd&passed=%d&elapsed_time=%sms\n", + (test_info.result())->Passed(), + StreamableToString((test_info.result())->elapsed_time()).c_str())); + } + + void OnTestPartResult(const TestPartResult& test_part_result) { + const char* file_name = test_part_result.file_name(); + if (file_name == NULL) + file_name = ""; + Send(String::Format("event=TestPartResult&file=%s&line=%d&message=", + UrlEncode(file_name).c_str(), + test_part_result.line_number())); + Send(UrlEncode(test_part_result.message()) + "\n"); + } + + private: + // Creates a client socket and connects to the server. + void MakeConnection(); + + // Closes the socket. + void CloseConnection() { + GTEST_CHECK_(sockfd_ != -1) + << "CloseConnection() can be called only when there is a connection."; + + close(sockfd_); + sockfd_ = -1; + } + + // Sends a string to the socket. + void Send(const string& message) { + GTEST_CHECK_(sockfd_ != -1) + << "Send() can be called only when there is a connection."; + + const int len = static_cast(message.length()); + if (write(sockfd_, message.c_str(), len) != len) { + GTEST_LOG_(WARNING) + << "stream_result_to: failed to stream to " + << host_name_ << ":" << port_num_; + } + } + + int sockfd_; // socket file descriptor + const string host_name_; + const string port_num_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); +}; // class StreamingListener + +// Checks if str contains '=', '&', '%' or '\n' characters. If yes, +// replaces them by "%xx" where xx is their hexadecimal value. For +// example, replaces "=" with "%3D". This algorithm is O(strlen(str)) +// in both time and space -- important as the input str may contain an +// arbitrarily long test failure message and stack trace. +string StreamingListener::UrlEncode(const char* str) { + string result; + result.reserve(strlen(str) + 1); + for (char ch = *str; ch != '\0'; ch = *++str) { + switch (ch) { + case '%': + case '=': + case '&': + case '\n': + result.append(String::Format("%%%02x", static_cast(ch))); + break; + default: + result.push_back(ch); + break; + } + } + return result; +} + +void StreamingListener::MakeConnection() { + GTEST_CHECK_(sockfd_ == -1) + << "MakeConnection() can't be called when there is already a connection."; + + addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. + hints.ai_socktype = SOCK_STREAM; + addrinfo* servinfo = NULL; + + // Use the getaddrinfo() to get a linked list of IP addresses for + // the given host name. + const int error_num = getaddrinfo( + host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); + if (error_num != 0) { + GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " + << gai_strerror(error_num); + } + + // Loop through all the results and connect to the first we can. + for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; + cur_addr = cur_addr->ai_next) { + sockfd_ = socket( + cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); + if (sockfd_ != -1) { + // Connect the client socket to the server socket. + if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { + close(sockfd_); + sockfd_ = -1; + } + } + } + + freeaddrinfo(servinfo); // all done with this structure + + if (sockfd_ == -1) { + GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " + << host_name_ << ":" << port_num_; + } +} + +// End of class Streaming Listener +#endif // GTEST_CAN_STREAM_RESULTS__ + +// Class ScopedTrace + +// Pushes the given source file location and message onto a per-thread +// trace stack maintained by Google Test. +// L < UnitTest::mutex_ +ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) { + TraceInfo trace; + trace.file = file; + trace.line = line; + trace.message = message.GetString(); + + UnitTest::GetInstance()->PushGTestTrace(trace); +} + +// Pops the info pushed by the c'tor. +// L < UnitTest::mutex_ +ScopedTrace::~ScopedTrace() { + UnitTest::GetInstance()->PopGTestTrace(); +} + + +// class OsStackTraceGetter + +// Returns the current OS stack trace as a String. Parameters: +// +// max_depth - the maximum number of stack frames to be included +// in the trace. +// skip_count - the number of top frames to be skipped; doesn't count +// against max_depth. +// +// L < mutex_ +// We use "L < mutex_" to denote that the function may acquire mutex_. +String OsStackTraceGetter::CurrentStackTrace(int, int) { + return String(""); +} + +// L < mutex_ +void OsStackTraceGetter::UponLeavingGTest() { +} + +const char* const +OsStackTraceGetter::kElidedFramesMarker = + "... " GTEST_NAME_ " internal frames ..."; + +} // namespace internal + +// class TestEventListeners + +TestEventListeners::TestEventListeners() + : repeater_(new internal::TestEventRepeater()), + default_result_printer_(NULL), + default_xml_generator_(NULL) { +} + +TestEventListeners::~TestEventListeners() { delete repeater_; } + +// Returns the standard listener responsible for the default console +// output. Can be removed from the listeners list to shut down default +// console output. Note that removing this object from the listener list +// with Release transfers its ownership to the user. +void TestEventListeners::Append(TestEventListener* listener) { + repeater_->Append(listener); +} + +// Removes the given event listener from the list and returns it. It then +// becomes the caller's responsibility to delete the listener. Returns +// NULL if the listener is not found in the list. +TestEventListener* TestEventListeners::Release(TestEventListener* listener) { + if (listener == default_result_printer_) + default_result_printer_ = NULL; + else if (listener == default_xml_generator_) + default_xml_generator_ = NULL; + return repeater_->Release(listener); +} + +// Returns repeater that broadcasts the TestEventListener events to all +// subscribers. +TestEventListener* TestEventListeners::repeater() { return repeater_; } + +// Sets the default_result_printer attribute to the provided listener. +// The listener is also added to the listener list and previous +// default_result_printer is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { + if (default_result_printer_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_result_printer_); + default_result_printer_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Sets the default_xml_generator attribute to the provided listener. The +// listener is also added to the listener list and previous +// default_xml_generator is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { + if (default_xml_generator_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_xml_generator_); + default_xml_generator_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Controls whether events will be forwarded by the repeater to the +// listeners in the list. +bool TestEventListeners::EventForwardingEnabled() const { + return repeater_->forwarding_enabled(); +} + +void TestEventListeners::SuppressEventForwarding() { + repeater_->set_forwarding_enabled(false); +} + +// class UnitTest + +// Gets the singleton UnitTest object. The first time this method is +// called, a UnitTest object is constructed and returned. Consecutive +// calls will return the same object. +// +// We don't protect this under mutex_ as a user is not supposed to +// call this before main() starts, from which point on the return +// value will never change. +UnitTest * UnitTest::GetInstance() { + // When compiled with MSVC 7.1 in optimized mode, destroying the + // UnitTest object upon exiting the program messes up the exit code, + // causing successful tests to appear failed. We have to use a + // different implementation in this case to bypass the compiler bug. + // This implementation makes the compiler happy, at the cost of + // leaking the UnitTest object. + + // CodeGear C++Builder insists on a public destructor for the + // default implementation. Use this implementation to keep good OO + // design with private destructor. + +#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) + static UnitTest* const instance = new UnitTest; + return instance; +#else + static UnitTest instance; + return &instance; +#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) +} + +// Gets the number of successful test cases. +int UnitTest::successful_test_case_count() const { + return impl()->successful_test_case_count(); +} + +// Gets the number of failed test cases. +int UnitTest::failed_test_case_count() const { + return impl()->failed_test_case_count(); +} + +// Gets the number of all test cases. +int UnitTest::total_test_case_count() const { + return impl()->total_test_case_count(); +} + +// Gets the number of all test cases that contain at least one test +// that should run. +int UnitTest::test_case_to_run_count() const { + return impl()->test_case_to_run_count(); +} + +// Gets the number of successful tests. +int UnitTest::successful_test_count() const { + return impl()->successful_test_count(); +} + +// Gets the number of failed tests. +int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } + +// Gets the number of disabled tests. +int UnitTest::disabled_test_count() const { + return impl()->disabled_test_count(); +} + +// Gets the number of all tests. +int UnitTest::total_test_count() const { return impl()->total_test_count(); } + +// Gets the number of tests that should run. +int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } + +// Gets the elapsed time, in milliseconds. +internal::TimeInMillis UnitTest::elapsed_time() const { + return impl()->elapsed_time(); +} + +// Returns true iff the unit test passed (i.e. all test cases passed). +bool UnitTest::Passed() const { return impl()->Passed(); } + +// Returns true iff the unit test failed (i.e. some test case failed +// or something outside of all tests failed). +bool UnitTest::Failed() const { return impl()->Failed(); } + +// Gets the i-th test case among all the test cases. i can range from 0 to +// total_test_case_count() - 1. If i is not in that range, returns NULL. +const TestCase* UnitTest::GetTestCase(int i) const { + return impl()->GetTestCase(i); +} + +// Gets the i-th test case among all the test cases. i can range from 0 to +// total_test_case_count() - 1. If i is not in that range, returns NULL. +TestCase* UnitTest::GetMutableTestCase(int i) { + return impl()->GetMutableTestCase(i); +} + +// Returns the list of event listeners that can be used to track events +// inside Google Test. +TestEventListeners& UnitTest::listeners() { + return *impl()->listeners(); +} + +// Registers and returns a global test environment. When a test +// program is run, all global test environments will be set-up in the +// order they were registered. After all tests in the program have +// finished, all global test environments will be torn-down in the +// *reverse* order they were registered. +// +// The UnitTest object takes ownership of the given environment. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +Environment* UnitTest::AddEnvironment(Environment* env) { + if (env == NULL) { + return NULL; + } + + impl_->environments().push_back(env); + return env; +} + +// Adds a TestPartResult to the current TestResult object. All Google Test +// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call +// this to report their results. The user code should use the +// assertion macros instead of calling this directly. +// L < mutex_ +void UnitTest::AddTestPartResult(TestPartResult::Type result_type, + const char* file_name, + int line_number, + const internal::String& message, + const internal::String& os_stack_trace) { + Message msg; + msg << message; + + internal::MutexLock lock(&mutex_); + if (impl_->gtest_trace_stack().size() > 0) { + msg << "\n" << GTEST_NAME_ << " trace:"; + + for (int i = static_cast(impl_->gtest_trace_stack().size()); + i > 0; --i) { + const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; + msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) + << " " << trace.message; + } + } + + if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { + msg << internal::kStackTraceMarker << os_stack_trace; + } + + const TestPartResult result = + TestPartResult(result_type, file_name, line_number, + msg.GetString().c_str()); + impl_->GetTestPartResultReporterForCurrentThread()-> + ReportTestPartResult(result); + + if (result_type != TestPartResult::kSuccess) { + // gtest_break_on_failure takes precedence over + // gtest_throw_on_failure. This allows a user to set the latter + // in the code (perhaps in order to use Google Test assertions + // with another testing framework) and specify the former on the + // command line for debugging. + if (GTEST_FLAG(break_on_failure)) { +#if GTEST_OS_WINDOWS + // Using DebugBreak on Windows allows gtest to still break into a debugger + // when a failure happens and both the --gtest_break_on_failure and + // the --gtest_catch_exceptions flags are specified. + DebugBreak(); +#else + // Dereference NULL through a volatile pointer to prevent the compiler + // from removing. We use this rather than abort() or __builtin_trap() for + // portability: Symbian doesn't implement abort() well, and some debuggers + // don't correctly trap abort(). + *static_cast(NULL) = 1; +#endif // GTEST_OS_WINDOWS + } else if (GTEST_FLAG(throw_on_failure)) { +#if GTEST_HAS_EXCEPTIONS + throw GoogleTestFailureException(result); +#else + // We cannot call abort() as it generates a pop-up in debug mode + // that cannot be suppressed in VC 7.1 or below. + exit(1); +#endif + } + } +} + +// Creates and adds a property to the current TestResult. If a property matching +// the supplied value already exists, updates its value instead. +void UnitTest::RecordPropertyForCurrentTest(const char* key, + const char* value) { + const TestProperty test_property(key, value); + impl_->current_test_result()->RecordProperty(test_property); +} + +// Runs all tests in this UnitTest object and prints the result. +// Returns 0 if successful, or 1 otherwise. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +int UnitTest::Run() { + // Captures the value of GTEST_FLAG(catch_exceptions). This value will be + // used for the duration of the program. + impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); + +#if GTEST_HAS_SEH + const bool in_death_test_child_process = + internal::GTEST_FLAG(internal_run_death_test).length() > 0; + + // Either the user wants Google Test to catch exceptions thrown by the + // tests or this is executing in the context of death test child + // process. In either case the user does not want to see pop-up dialogs + // about crashes - they are expected. + if (impl()->catch_exceptions() || in_death_test_child_process) { + +# if !GTEST_OS_WINDOWS_MOBILE + // SetErrorMode doesn't exist on CE. + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | + SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); +# endif // !GTEST_OS_WINDOWS_MOBILE + +# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE + // Death test children can be terminated with _abort(). On Windows, + // _abort() can show a dialog with a warning message. This forces the + // abort message to go to stderr instead. + _set_error_mode(_OUT_TO_STDERR); +# endif + +# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE + // In the debug version, Visual Studio pops up a separate dialog + // offering a choice to debug the aborted program. We need to suppress + // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement + // executed. Google Test will notify the user of any unexpected + // failure via stderr. + // + // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. + // Users of prior VC versions shall suffer the agony and pain of + // clicking through the countless debug dialogs. + // TODO(vladl@google.com): find a way to suppress the abort dialog() in the + // debug mode when compiled with VC 7.1 or lower. + if (!GTEST_FLAG(break_on_failure)) + _set_abort_behavior( + 0x0, // Clear the following flags: + _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. +# endif + + } +#endif // GTEST_HAS_SEH + + return internal::HandleExceptionsInMethodIfSupported( + impl(), + &internal::UnitTestImpl::RunAllTests, + "auxiliary test code (environments or event listeners)") ? 0 : 1; +} + +// Returns the working directory when the first TEST() or TEST_F() was +// executed. +const char* UnitTest::original_working_dir() const { + return impl_->original_working_dir_.c_str(); +} + +// Returns the TestCase object for the test that's currently running, +// or NULL if no test is running. +// L < mutex_ +const TestCase* UnitTest::current_test_case() const { + internal::MutexLock lock(&mutex_); + return impl_->current_test_case(); +} + +// Returns the TestInfo object for the test that's currently running, +// or NULL if no test is running. +// L < mutex_ +const TestInfo* UnitTest::current_test_info() const { + internal::MutexLock lock(&mutex_); + return impl_->current_test_info(); +} + +// Returns the random seed used at the start of the current test run. +int UnitTest::random_seed() const { return impl_->random_seed(); } + +#if GTEST_HAS_PARAM_TEST +// Returns ParameterizedTestCaseRegistry object used to keep track of +// value-parameterized tests and instantiate and register them. +// L < mutex_ +internal::ParameterizedTestCaseRegistry& + UnitTest::parameterized_test_registry() { + return impl_->parameterized_test_registry(); +} +#endif // GTEST_HAS_PARAM_TEST + +// Creates an empty UnitTest. +UnitTest::UnitTest() { + impl_ = new internal::UnitTestImpl(this); +} + +// Destructor of UnitTest. +UnitTest::~UnitTest() { + delete impl_; +} + +// Pushes a trace defined by SCOPED_TRACE() on to the per-thread +// Google Test trace stack. +// L < mutex_ +void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack().push_back(trace); +} + +// Pops a trace from the per-thread Google Test trace stack. +// L < mutex_ +void UnitTest::PopGTestTrace() { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack().pop_back(); +} + +namespace internal { + +UnitTestImpl::UnitTestImpl(UnitTest* parent) + : parent_(parent), +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4355) // Temporarily disables warning 4355 + // (using this in initializer). + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), +# pragma warning(pop) // Restores the warning state again. +#else + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), +#endif // _MSC_VER + global_test_part_result_repoter_( + &default_global_test_part_result_reporter_), + per_thread_test_part_result_reporter_( + &default_per_thread_test_part_result_reporter_), +#if GTEST_HAS_PARAM_TEST + parameterized_test_registry_(), + parameterized_tests_registered_(false), +#endif // GTEST_HAS_PARAM_TEST + last_death_test_case_(-1), + current_test_case_(NULL), + current_test_info_(NULL), + ad_hoc_test_result_(), + os_stack_trace_getter_(NULL), + post_flag_parse_init_performed_(false), + random_seed_(0), // Will be overridden by the flag before first use. + random_(0), // Will be reseeded before first use. + elapsed_time_(0), +#if GTEST_HAS_DEATH_TEST + internal_run_death_test_flag_(NULL), + death_test_factory_(new DefaultDeathTestFactory), +#endif + // Will be overridden by the flag before first use. + catch_exceptions_(false) { + listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); +} + +UnitTestImpl::~UnitTestImpl() { + // Deletes every TestCase. + ForEach(test_cases_, internal::Delete); + + // Deletes every Environment. + ForEach(environments_, internal::Delete); + + delete os_stack_trace_getter_; +} + +#if GTEST_HAS_DEATH_TEST +// Disables event forwarding if the control is currently in a death test +// subprocess. Must not be called before InitGoogleTest. +void UnitTestImpl::SuppressTestEventsIfInSubprocess() { + if (internal_run_death_test_flag_.get() != NULL) + listeners()->SuppressEventForwarding(); +} +#endif // GTEST_HAS_DEATH_TEST + +// Initializes event listeners performing XML output as specified by +// UnitTestOptions. Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureXmlOutput() { + const String& output_format = UnitTestOptions::GetOutputFormat(); + if (output_format == "xml") { + listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); + } else if (output_format != "") { + printf("WARNING: unrecognized output format \"%s\" ignored.\n", + output_format.c_str()); + fflush(stdout); + } +} + +#if GTEST_CAN_STREAM_RESULTS_ +// Initializes event listeners for streaming test results in String form. +// Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureStreamingOutput() { + const string& target = GTEST_FLAG(stream_result_to); + if (!target.empty()) { + const size_t pos = target.find(':'); + if (pos != string::npos) { + listeners()->Append(new StreamingListener(target.substr(0, pos), + target.substr(pos+1))); + } else { + printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", + target.c_str()); + fflush(stdout); + } + } +} +#endif // GTEST_CAN_STREAM_RESULTS_ + +// Performs initialization dependent upon flag values obtained in +// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to +// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest +// this function is also called from RunAllTests. Since this function can be +// called more than once, it has to be idempotent. +void UnitTestImpl::PostFlagParsingInit() { + // Ensures that this function does not execute more than once. + if (!post_flag_parse_init_performed_) { + post_flag_parse_init_performed_ = true; + +#if GTEST_HAS_DEATH_TEST + InitDeathTestSubprocessControlInfo(); + SuppressTestEventsIfInSubprocess(); +#endif // GTEST_HAS_DEATH_TEST + + // Registers parameterized tests. This makes parameterized tests + // available to the UnitTest reflection API without running + // RUN_ALL_TESTS. + RegisterParameterizedTests(); + + // Configures listeners for XML output. This makes it possible for users + // to shut down the default XML output before invoking RUN_ALL_TESTS. + ConfigureXmlOutput(); + +#if GTEST_CAN_STREAM_RESULTS_ + // Configures listeners for streaming test results to the specified server. + ConfigureStreamingOutput(); +#endif // GTEST_CAN_STREAM_RESULTS_ + } +} + +// A predicate that checks the name of a TestCase against a known +// value. +// +// This is used for implementation of the UnitTest class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestCaseNameIs is copyable. +class TestCaseNameIs { + public: + // Constructor. + explicit TestCaseNameIs(const String& name) + : name_(name) {} + + // Returns true iff the name of test_case matches name_. + bool operator()(const TestCase* test_case) const { + return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; + } + + private: + String name_; +}; + +// Finds and returns a TestCase with the given name. If one doesn't +// exist, creates one and returns it. It's the CALLER'S +// RESPONSIBILITY to ensure that this function is only called WHEN THE +// TESTS ARE NOT SHUFFLED. +// +// Arguments: +// +// test_case_name: name of the test case +// type_param: the name of the test case's type parameter, or NULL if +// this is not a typed or a type-parameterized test case. +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, + const char* type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc) { + // Can we find a TestCase with the given name? + const std::vector::const_iterator test_case = + std::find_if(test_cases_.begin(), test_cases_.end(), + TestCaseNameIs(test_case_name)); + + if (test_case != test_cases_.end()) + return *test_case; + + // No. Let's create one. + TestCase* const new_test_case = + new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc); + + // Is this a death test case? + if (internal::UnitTestOptions::MatchesFilter(String(test_case_name), + kDeathTestCaseFilter)) { + // Yes. Inserts the test case after the last death test case + // defined so far. This only works when the test cases haven't + // been shuffled. Otherwise we may end up running a death test + // after a non-death test. + ++last_death_test_case_; + test_cases_.insert(test_cases_.begin() + last_death_test_case_, + new_test_case); + } else { + // No. Appends to the end of the list. + test_cases_.push_back(new_test_case); + } + + test_case_indices_.push_back(static_cast(test_case_indices_.size())); + return new_test_case; +} + +// Helpers for setting up / tearing down the given environment. They +// are for use in the ForEach() function. +static void SetUpEnvironment(Environment* env) { env->SetUp(); } +static void TearDownEnvironment(Environment* env) { env->TearDown(); } + +// Runs all tests in this UnitTest object, prints the result, and +// returns true if all tests are successful. If any exception is +// thrown during a test, the test is considered to be failed, but the +// rest of the tests will still be run. +// +// When parameterized tests are enabled, it expands and registers +// parameterized tests first in RegisterParameterizedTests(). +// All other functions called from RunAllTests() may safely assume that +// parameterized tests are ready to be counted and run. +bool UnitTestImpl::RunAllTests() { + // Makes sure InitGoogleTest() was called. + if (!GTestIsInitialized()) { + printf("%s", + "\nThis test program did NOT call ::testing::InitGoogleTest " + "before calling RUN_ALL_TESTS(). Please fix it.\n"); + return false; + } + + // Do not run any test if the --help flag was specified. + if (g_help_flag) + return true; + + // Repeats the call to the post-flag parsing initialization in case the + // user didn't call InitGoogleTest. + PostFlagParsingInit(); + + // Even if sharding is not on, test runners may want to use the + // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding + // protocol. + internal::WriteToShardStatusFileIfNeeded(); + + // True iff we are in a subprocess for running a thread-safe-style + // death test. + bool in_subprocess_for_death_test = false; + +#if GTEST_HAS_DEATH_TEST + in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); +#endif // GTEST_HAS_DEATH_TEST + + const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, + in_subprocess_for_death_test); + + // Compares the full test names with the filter to decide which + // tests to run. + const bool has_tests_to_run = FilterTests(should_shard + ? HONOR_SHARDING_PROTOCOL + : IGNORE_SHARDING_PROTOCOL) > 0; + + // Lists the tests and exits if the --gtest_list_tests flag was specified. + if (GTEST_FLAG(list_tests)) { + // This must be called *after* FilterTests() has been called. + ListTestsMatchingFilter(); + return true; + } + + random_seed_ = GTEST_FLAG(shuffle) ? + GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; + + // True iff at least one test has failed. + bool failed = false; + + TestEventListener* repeater = listeners()->repeater(); + + repeater->OnTestProgramStart(*parent_); + + // How many times to repeat the tests? We don't want to repeat them + // when we are inside the subprocess of a death test. + const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); + // Repeats forever if the repeat count is negative. + const bool forever = repeat < 0; + for (int i = 0; forever || i != repeat; i++) { + // We want to preserve failures generated by ad-hoc test + // assertions executed before RUN_ALL_TESTS(). + ClearNonAdHocTestResult(); + + const TimeInMillis start = GetTimeInMillis(); + + // Shuffles test cases and tests if requested. + if (has_tests_to_run && GTEST_FLAG(shuffle)) { + random()->Reseed(random_seed_); + // This should be done before calling OnTestIterationStart(), + // such that a test event listener can see the actual test order + // in the event. + ShuffleTests(); + } + + // Tells the unit test event listeners that the tests are about to start. + repeater->OnTestIterationStart(*parent_, i); + + // Runs each test case if there is at least one test to run. + if (has_tests_to_run) { + // Sets up all environments beforehand. + repeater->OnEnvironmentsSetUpStart(*parent_); + ForEach(environments_, SetUpEnvironment); + repeater->OnEnvironmentsSetUpEnd(*parent_); + + // Runs the tests only if there was no fatal failure during global + // set-up. + if (!Test::HasFatalFailure()) { + for (int test_index = 0; test_index < total_test_case_count(); + test_index++) { + GetMutableTestCase(test_index)->Run(); + } + } + + // Tears down all environments in reverse order afterwards. + repeater->OnEnvironmentsTearDownStart(*parent_); + std::for_each(environments_.rbegin(), environments_.rend(), + TearDownEnvironment); + repeater->OnEnvironmentsTearDownEnd(*parent_); + } + + elapsed_time_ = GetTimeInMillis() - start; + + // Tells the unit test event listener that the tests have just finished. + repeater->OnTestIterationEnd(*parent_, i); + + // Gets the result and clears it. + if (!Passed()) { + failed = true; + } + + // Restores the original test order after the iteration. This + // allows the user to quickly repro a failure that happens in the + // N-th iteration without repeating the first (N - 1) iterations. + // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in + // case the user somehow changes the value of the flag somewhere + // (it's always safe to unshuffle the tests). + UnshuffleTests(); + + if (GTEST_FLAG(shuffle)) { + // Picks a new random seed for each iteration. + random_seed_ = GetNextRandomSeed(random_seed_); + } + } + + repeater->OnTestProgramEnd(*parent_); + + return !failed; +} + +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded() { + const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); + if (test_shard_file != NULL) { + FILE* const file = posix::FOpen(test_shard_file, "w"); + if (file == NULL) { + ColoredPrintf(COLOR_RED, + "Could not write to the test shard status file \"%s\" " + "specified by the %s environment variable.\n", + test_shard_file, kTestShardStatusFile); + fflush(stdout); + exit(EXIT_FAILURE); + } + fclose(file); + } +} + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (i.e., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +bool ShouldShard(const char* total_shards_env, + const char* shard_index_env, + bool in_subprocess_for_death_test) { + if (in_subprocess_for_death_test) { + return false; + } + + const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); + const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); + + if (total_shards == -1 && shard_index == -1) { + return false; + } else if (total_shards == -1 && shard_index != -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestShardIndex << " = " << shard_index + << ", but have left " << kTestTotalShards << " unset.\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (total_shards != -1 && shard_index == -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestTotalShards << " = " << total_shards + << ", but have left " << kTestShardIndex << " unset.\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (shard_index < 0 || shard_index >= total_shards) { + const Message msg = Message() + << "Invalid environment variables: we require 0 <= " + << kTestShardIndex << " < " << kTestTotalShards + << ", but you have " << kTestShardIndex << "=" << shard_index + << ", " << kTestTotalShards << "=" << total_shards << ".\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } + + return total_shards > 1; +} + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error +// and aborts. +Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { + const char* str_val = posix::GetEnv(var); + if (str_val == NULL) { + return default_val; + } + + Int32 result; + if (!ParseInt32(Message() << "The value of environment variable " << var, + str_val, &result)) { + exit(EXIT_FAILURE); + } + return result; +} + +// Given the total number of shards, the shard index, and the test id, +// returns true iff the test should be run on this shard. The test id is +// some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { + return (test_id % total_shards) == shard_index; +} + +// Compares the name of each test with the user-specified filter to +// decide whether the test should be run, then records the result in +// each TestCase and TestInfo object. +// If shard_tests == true, further filters tests based on sharding +// variables in the environment - see +// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. +// Returns the number of tests that should run. +int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { + const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestTotalShards, -1) : -1; + const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestShardIndex, -1) : -1; + + // num_runnable_tests are the number of tests that will + // run across all shards (i.e., match filter and are not disabled). + // num_selected_tests are the number of tests to be run on + // this shard. + int num_runnable_tests = 0; + int num_selected_tests = 0; + for (size_t i = 0; i < test_cases_.size(); i++) { + TestCase* const test_case = test_cases_[i]; + const String &test_case_name = test_case->name(); + test_case->set_should_run(false); + + for (size_t j = 0; j < test_case->test_info_list().size(); j++) { + TestInfo* const test_info = test_case->test_info_list()[j]; + const String test_name(test_info->name()); + // A test is disabled if test case name or test name matches + // kDisableTestFilter. + const bool is_disabled = + internal::UnitTestOptions::MatchesFilter(test_case_name, + kDisableTestFilter) || + internal::UnitTestOptions::MatchesFilter(test_name, + kDisableTestFilter); + test_info->is_disabled_ = is_disabled; + + const bool matches_filter = + internal::UnitTestOptions::FilterMatchesTest(test_case_name, + test_name); + test_info->matches_filter_ = matches_filter; + + const bool is_runnable = + (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && + matches_filter; + + const bool is_selected = is_runnable && + (shard_tests == IGNORE_SHARDING_PROTOCOL || + ShouldRunTestOnShard(total_shards, shard_index, + num_runnable_tests)); + + num_runnable_tests += is_runnable; + num_selected_tests += is_selected; + + test_info->should_run_ = is_selected; + test_case->set_should_run(test_case->should_run() || is_selected); + } + } + return num_selected_tests; +} + +// Prints the names of the tests matching the user-specified filter flag. +void UnitTestImpl::ListTestsMatchingFilter() { + for (size_t i = 0; i < test_cases_.size(); i++) { + const TestCase* const test_case = test_cases_[i]; + bool printed_test_case_name = false; + + for (size_t j = 0; j < test_case->test_info_list().size(); j++) { + const TestInfo* const test_info = + test_case->test_info_list()[j]; + if (test_info->matches_filter_) { + if (!printed_test_case_name) { + printed_test_case_name = true; + printf("%s.\n", test_case->name()); + } + printf(" %s\n", test_info->name()); + } + } + } + fflush(stdout); +} + +// Sets the OS stack trace getter. +// +// Does nothing if the input and the current OS stack trace getter are +// the same; otherwise, deletes the old getter and makes the input the +// current getter. +void UnitTestImpl::set_os_stack_trace_getter( + OsStackTraceGetterInterface* getter) { + if (os_stack_trace_getter_ != getter) { + delete os_stack_trace_getter_; + os_stack_trace_getter_ = getter; + } +} + +// Returns the current OS stack trace getter if it is not NULL; +// otherwise, creates an OsStackTraceGetter, makes it the current +// getter, and returns it. +OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { + if (os_stack_trace_getter_ == NULL) { + os_stack_trace_getter_ = new OsStackTraceGetter; + } + + return os_stack_trace_getter_; +} + +// Returns the TestResult for the test that's currently running, or +// the TestResult for the ad hoc test if no test is running. +TestResult* UnitTestImpl::current_test_result() { + return current_test_info_ ? + &(current_test_info_->result_) : &ad_hoc_test_result_; +} + +// Shuffles all test cases, and the tests within each test case, +// making sure that death tests are still run first. +void UnitTestImpl::ShuffleTests() { + // Shuffles the death test cases. + ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); + + // Shuffles the non-death test cases. + ShuffleRange(random(), last_death_test_case_ + 1, + static_cast(test_cases_.size()), &test_case_indices_); + + // Shuffles the tests inside each test case. + for (size_t i = 0; i < test_cases_.size(); i++) { + test_cases_[i]->ShuffleTests(random()); + } +} + +// Restores the test cases and tests to their order before the first shuffle. +void UnitTestImpl::UnshuffleTests() { + for (size_t i = 0; i < test_cases_.size(); i++) { + // Unshuffles the tests in each test case. + test_cases_[i]->UnshuffleTests(); + // Resets the index of each test case. + test_case_indices_[i] = static_cast(i); + } +} + +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +String GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, + int skip_count) { + // We pass skip_count + 1 to skip this wrapper function in addition + // to what the user really wants to skip. + return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); +} + +// Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to +// suppress unreachable code warnings. +namespace { +class ClassUniqueToAlwaysTrue {}; +} + +bool IsTrue(bool condition) { return condition; } + +bool AlwaysTrue() { +#if GTEST_HAS_EXCEPTIONS + // This condition is always false so AlwaysTrue() never actually throws, + // but it makes the compiler think that it may throw. + if (IsTrue(false)) + throw ClassUniqueToAlwaysTrue(); +#endif // GTEST_HAS_EXCEPTIONS + return true; +} + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +bool SkipPrefix(const char* prefix, const char** pstr) { + const size_t prefix_len = strlen(prefix); + if (strncmp(*pstr, prefix, prefix_len) == 0) { + *pstr += prefix_len; + return true; + } + return false; +} + +// Parses a string as a command line flag. The string should have +// the format "--flag=value". When def_optional is true, the "=value" +// part can be omitted. +// +// Returns the value of the flag, or NULL if the parsing failed. +const char* ParseFlagValue(const char* str, + const char* flag, + bool def_optional) { + // str and flag must not be NULL. + if (str == NULL || flag == NULL) return NULL; + + // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. + const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag); + const size_t flag_len = flag_str.length(); + if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; + + // Skips the flag name. + const char* flag_end = str + flag_len; + + // When def_optional is true, it's OK to not have a "=value" part. + if (def_optional && (flag_end[0] == '\0')) { + return flag_end; + } + + // If def_optional is true and there are more characters after the + // flag name, or if def_optional is false, there must be a '=' after + // the flag name. + if (flag_end[0] != '=') return NULL; + + // Returns the string after "=". + return flag_end + 1; +} + +// Parses a string for a bool flag, in the form of either +// "--flag=value" or "--flag". +// +// In the former case, the value is taken as true as long as it does +// not start with '0', 'f', or 'F'. +// +// In the latter case, the value is taken as true. +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseBoolFlag(const char* str, const char* flag, bool* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, true); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Converts the string value to a bool. + *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); + return true; +} + +// Parses a string for an Int32 flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + return ParseInt32(Message() << "The value of flag --" << flag, + value_str, value); +} + +// Parses a string for a string flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseStringFlag(const char* str, const char* flag, String* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + *value = value_str; + return true; +} + +// Determines whether a string has a prefix that Google Test uses for its +// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. +// If Google Test detects that a command line flag has its prefix but is not +// recognized, it will print its help message. Flags starting with +// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test +// internal flags and do not trigger the help message. +static bool HasGoogleTestFlagPrefix(const char* str) { + return (SkipPrefix("--", &str) || + SkipPrefix("-", &str) || + SkipPrefix("/", &str)) && + !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && + (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || + SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); +} + +// Prints a string containing code-encoded text. The following escape +// sequences can be used in the string to control the text color: +// +// @@ prints a single '@' character. +// @R changes the color to red. +// @G changes the color to green. +// @Y changes the color to yellow. +// @D changes to the default terminal text color. +// +// TODO(wan@google.com): Write tests for this once we add stdout +// capturing to Google Test. +static void PrintColorEncoded(const char* str) { + GTestColor color = COLOR_DEFAULT; // The current color. + + // Conceptually, we split the string into segments divided by escape + // sequences. Then we print one segment at a time. At the end of + // each iteration, the str pointer advances to the beginning of the + // next segment. + for (;;) { + const char* p = strchr(str, '@'); + if (p == NULL) { + ColoredPrintf(color, "%s", str); + return; + } + + ColoredPrintf(color, "%s", String(str, p - str).c_str()); + + const char ch = p[1]; + str = p + 2; + if (ch == '@') { + ColoredPrintf(color, "@"); + } else if (ch == 'D') { + color = COLOR_DEFAULT; + } else if (ch == 'R') { + color = COLOR_RED; + } else if (ch == 'G') { + color = COLOR_GREEN; + } else if (ch == 'Y') { + color = COLOR_YELLOW; + } else { + --str; + } + } +} + +static const char kColorEncodedHelpMessage[] = +"This program contains tests written using " GTEST_NAME_ ". You can use the\n" +"following command line flags to control its behavior:\n" +"\n" +"Test Selection:\n" +" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" +" List the names of all tests instead of running them. The name of\n" +" TEST(Foo, Bar) is \"Foo.Bar\".\n" +" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" + "[@G-@YNEGATIVE_PATTERNS]@D\n" +" Run only the tests whose name matches one of the positive patterns but\n" +" none of the negative patterns. '?' matches any single character; '*'\n" +" matches any substring; ':' separates two patterns.\n" +" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" +" Run all disabled tests too.\n" +"\n" +"Test Execution:\n" +" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" +" Run the tests repeatedly; use a negative count to repeat forever.\n" +" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" +" Randomize tests' orders on every iteration.\n" +" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" +" Random number seed to use for shuffling test orders (between 1 and\n" +" 99999, or 0 to use a seed based on the current time).\n" +"\n" +"Test Output:\n" +" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" +" Enable/disable colored output. The default is @Gauto@D.\n" +" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" +" Don't print the elapsed time of each test.\n" +" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" + GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" +" Generate an XML report in the given directory or with the given file\n" +" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" +#if GTEST_CAN_STREAM_RESULTS_ +" @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" +" Stream test results to the given server.\n" +#endif // GTEST_CAN_STREAM_RESULTS_ +"\n" +"Assertion Behavior:\n" +#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" +" Set the default death test style.\n" +#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" +" Turn assertion failures into debugger break-points.\n" +" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" +" Turn assertion failures into C++ exceptions.\n" +" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" +" Do not report exceptions as test failures. Instead, allow them\n" +" to crash the program or throw a pop-up (on Windows).\n" +"\n" +"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " + "the corresponding\n" +"environment variable of a flag (all letters in upper-case). For example, to\n" +"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ + "color=no@D or set\n" +"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" +"\n" +"For more information, please read the " GTEST_NAME_ " documentation at\n" +"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" +"(not one in your own code or tests), please report it to\n" +"@G<" GTEST_DEV_EMAIL_ ">@D.\n"; + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. The type parameter CharType can be +// instantiated to either char or wchar_t. +template +void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { + for (int i = 1; i < *argc; i++) { + const String arg_string = StreamableToString(argv[i]); + const char* const arg = arg_string.c_str(); + + using internal::ParseBoolFlag; + using internal::ParseInt32Flag; + using internal::ParseStringFlag; + + // Do we see a Google Test flag? + if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, + >EST_FLAG(also_run_disabled_tests)) || + ParseBoolFlag(arg, kBreakOnFailureFlag, + >EST_FLAG(break_on_failure)) || + ParseBoolFlag(arg, kCatchExceptionsFlag, + >EST_FLAG(catch_exceptions)) || + ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || + ParseStringFlag(arg, kDeathTestStyleFlag, + >EST_FLAG(death_test_style)) || + ParseBoolFlag(arg, kDeathTestUseFork, + >EST_FLAG(death_test_use_fork)) || + ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || + ParseStringFlag(arg, kInternalRunDeathTestFlag, + >EST_FLAG(internal_run_death_test)) || + ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || + ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || + ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || + ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || + ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || + ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || + ParseInt32Flag(arg, kStackTraceDepthFlag, + >EST_FLAG(stack_trace_depth)) || + ParseStringFlag(arg, kStreamResultToFlag, + >EST_FLAG(stream_result_to)) || + ParseBoolFlag(arg, kThrowOnFailureFlag, + >EST_FLAG(throw_on_failure)) + ) { + // Yes. Shift the remainder of the argv list left by one. Note + // that argv has (*argc + 1) elements, the last one always being + // NULL. The following loop moves the trailing NULL element as + // well. + for (int j = i; j != *argc; j++) { + argv[j] = argv[j + 1]; + } + + // Decrements the argument count. + (*argc)--; + + // We also need to decrement the iterator as we just removed + // an element. + i--; + } else if (arg_string == "--help" || arg_string == "-h" || + arg_string == "-?" || arg_string == "/?" || + HasGoogleTestFlagPrefix(arg)) { + // Both help flag and unrecognized Google Test flags (excluding + // internal ones) trigger help display. + g_help_flag = true; + } + } + + if (g_help_flag) { + // We print the help here instead of in RUN_ALL_TESTS(), as the + // latter may not be called at all if the user is using Google + // Test with another testing framework. + PrintColorEncoded(kColorEncodedHelpMessage); + } +} + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +void ParseGoogleTestFlagsOnly(int* argc, char** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} +void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} + +// The internal implementation of InitGoogleTest(). +// +// The type parameter CharType can be instantiated to either char or +// wchar_t. +template +void InitGoogleTestImpl(int* argc, CharType** argv) { + g_init_gtest_count++; + + // We don't want to run the initialization code twice. + if (g_init_gtest_count != 1) return; + + if (*argc <= 0) return; + + internal::g_executable_path = internal::StreamableToString(argv[0]); + +#if GTEST_HAS_DEATH_TEST + + g_argvs.clear(); + for (int i = 0; i != *argc; i++) { + g_argvs.push_back(StreamableToString(argv[i])); + } + +#endif // GTEST_HAS_DEATH_TEST + + ParseGoogleTestFlagsOnly(argc, argv); + GetUnitTestImpl()->PostFlagParsingInit(); +} + +} // namespace internal + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +// +// Calling the function for the second time has no user-visible effect. +void InitGoogleTest(int* argc, char** argv) { + internal::InitGoogleTestImpl(argc, argv); +} + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +void InitGoogleTest(int* argc, wchar_t** argv) { + internal::InitGoogleTestImpl(argc, argv); +} + +} // namespace testing diff --git a/libs/gtest/src/gtest_main.cc b/libs/gtest/src/gtest_main.cc new file mode 100644 index 000000000..a09bbe0c6 --- /dev/null +++ b/libs/gtest/src/gtest_main.cc @@ -0,0 +1,39 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +#include "gtest/gtest.h" + +GTEST_API_ int main(int argc, char **argv) { + std::cout << "Running main() from gtest_main.cc\n"; + + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From ae5020392f89f8e50c5d9af2cc130ec33fe817bd Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 22 May 2012 19:40:11 +0200 Subject: [PATCH 0107/1298] remove pugixml --- libs/pugixml/pugiconfig.hpp | 62 - libs/pugixml/pugixml.cpp | 9534 ----------------------------------- libs/pugixml/pugixml.hpp | 1131 ----- 3 files changed, 10727 deletions(-) delete mode 100644 libs/pugixml/pugiconfig.hpp delete mode 100644 libs/pugixml/pugixml.cpp delete mode 100644 libs/pugixml/pugixml.hpp diff --git a/libs/pugixml/pugiconfig.hpp b/libs/pugixml/pugiconfig.hpp deleted file mode 100644 index 90b81e117..000000000 --- a/libs/pugixml/pugiconfig.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/** - * pugixml parser - version 1.0 - * -------------------------------------------------------- - * Copyright (C) 2006-2010, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) - * Report bugs and download new versions at http://pugixml.org/ - * - * This library is distributed under the MIT License. See notice at the end - * of this file. - * - * This work is based on the pugxml parser, which is: - * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) - */ - -#ifndef HEADER_PUGICONFIG_HPP -#define HEADER_PUGICONFIG_HPP - -// Uncomment this to enable wchar_t mode -// #define PUGIXML_WCHAR_MODE - -// Uncomment this to disable XPath -// #define PUGIXML_NO_XPATH - -// Uncomment this to disable STL -// Note: you can't use XPath with PUGIXML_NO_STL -// #define PUGIXML_NO_STL - -// Uncomment this to disable exceptions -// Note: you can't use XPath with PUGIXML_NO_EXCEPTIONS -// #define PUGIXML_NO_EXCEPTIONS - -// Set this to control attributes for public classes/functions, i.e.: -// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL -// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL -// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall -// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead - -#endif - -/** - * Copyright (c) 2006-2010 Arseny Kapoulkine - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ diff --git a/libs/pugixml/pugixml.cpp b/libs/pugixml/pugixml.cpp deleted file mode 100644 index bd68ccc75..000000000 --- a/libs/pugixml/pugixml.cpp +++ /dev/null @@ -1,9534 +0,0 @@ -/** - * pugixml parser - version 1.0 - * -------------------------------------------------------- - * Copyright (C) 2006-2010, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) - * Report bugs and download new versions at http://pugixml.org/ - * - * This library is distributed under the MIT License. See notice at the end - * of this file. - * - * This work is based on the pugxml parser, which is: - * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) - */ - -#include "pugixml.hpp" - -#include -#include -#include -#include -#include -#include - -#ifndef PUGIXML_NO_XPATH -# include -# include -#endif - -#ifndef PUGIXML_NO_STL -# include -# include -# include -#endif - -// For placement new -#include - -#ifdef _MSC_VER -# pragma warning(disable: 4127) // conditional expression is constant -# pragma warning(disable: 4324) // structure was padded due to __declspec(align()) -# pragma warning(disable: 4611) // interaction between '_setjmp' and C++ object destruction is non-portable -# pragma warning(disable: 4702) // unreachable code -# pragma warning(disable: 4996) // this function or variable may be unsafe -#endif - -#ifdef __INTEL_COMPILER -# pragma warning(disable: 177) // function was declared but never referenced -# pragma warning(disable: 1478 1786) // function was declared "deprecated" -#endif - -#ifdef __BORLANDC__ -# pragma warn -8008 // condition is always false -# pragma warn -8066 // unreachable code -#endif - -#ifdef __SNC__ -# pragma diag_suppress=178 // function was declared but never referenced -# pragma diag_suppress=237 // controlling expression is constant -#endif - -// uintptr_t -#if !defined(_MSC_VER) || _MSC_VER >= 1600 -# include -#else -# if _MSC_VER < 1300 -// No native uintptr_t in MSVC6 -typedef size_t uintptr_t; -# endif -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -typedef __int32 int32_t; -#endif - -// Inlining controls -#if defined(_MSC_VER) && _MSC_VER >= 1300 -# define PUGIXML_NO_INLINE __declspec(noinline) -#elif defined(__GNUC__) -# define PUGIXML_NO_INLINE __attribute__((noinline)) -#else -# define PUGIXML_NO_INLINE -#endif - -// Simple static assertion -#define STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; } - -// Digital Mars C++ bug workaround for passing char loaded from memory via stack -#ifdef __DMC__ -# define DMC_VOLATILE volatile -#else -# define DMC_VOLATILE -#endif - -using namespace pugi; - -// Memory allocation -namespace { -void* default_allocate(size_t size) { - return malloc(size); -} - -void default_deallocate(void* ptr) { - free(ptr); -} - -allocation_function global_allocate = default_allocate; -deallocation_function global_deallocate = default_deallocate; -} - -// String utilities -namespace { -// Get string length -size_t strlength(const char_t* s) { - assert(s); - -#ifdef PUGIXML_WCHAR_MODE - return wcslen(s); -#else - return strlen(s); -#endif -} - -// Compare two strings -bool strequal(const char_t* src, const char_t* dst) { - assert(src && dst); - -#ifdef PUGIXML_WCHAR_MODE - return wcscmp(src, dst) == 0; -#else - return strcmp(src, dst) == 0; -#endif -} - -// Compare lhs with [rhs_begin, rhs_end) -bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count) { - for (size_t i = 0; i < count; ++i) - if (lhs[i] != rhs[i]) - return false; - - return lhs[count] == 0; -} - -#ifdef PUGIXML_WCHAR_MODE -// Convert string to wide string, assuming all symbols are ASCII -void widen_ascii(wchar_t* dest, const char* source) -{ - for (const char* i = source; *i; ++i) *dest++ = *i; - *dest = 0; -} -#endif -} - -#if !defined(PUGIXML_NO_STL) || !defined(PUGIXML_NO_XPATH) -// auto_ptr-like buffer holder for exception recovery -namespace { -struct buffer_holder { - void* data; - void (*deleter)(void*); - - buffer_holder(void* data, void(*deleter)(void*)) : - data(data), deleter(deleter) { - } - - ~buffer_holder() { - if (data) - deleter(data); - } - - void* release() { - void* result = data; - data = 0; - return result; - } -}; -} -#endif - -namespace { -static const size_t xml_memory_page_size = 32768; - -static const uintptr_t xml_memory_page_alignment = 32; -static const uintptr_t xml_memory_page_pointer_mask = - ~(xml_memory_page_alignment - 1); -static const uintptr_t xml_memory_page_name_allocated_mask = 16; -static const uintptr_t xml_memory_page_value_allocated_mask = 8; -static const uintptr_t xml_memory_page_type_mask = 7; - -struct xml_allocator; - -struct xml_memory_page { - static xml_memory_page* construct(void* memory) { - if (!memory) - return 0; //$ redundant, left for performance - - xml_memory_page* result = static_cast(memory); - - result->allocator = 0; - result->memory = 0; - result->prev = 0; - result->next = 0; - result->busy_size = 0; - result->freed_size = 0; - - return result; - } - - xml_allocator* allocator; - - void* memory; - - xml_memory_page* prev; - xml_memory_page* next; - - size_t busy_size; - size_t freed_size; - - char data[1]; -}; - -struct xml_memory_string_header { - uint16_t page_offset; // offset from page->data - uint16_t full_size; // 0 if string occupies whole page -}; - -struct xml_allocator { - xml_allocator(xml_memory_page* root) : - _root(root), _busy_size(root->busy_size) { - } - - xml_memory_page* allocate_page(size_t data_size) { - size_t size = offsetof(xml_memory_page, data) + data_size; - - // allocate block with some alignment, leaving memory for worst-case padding - void* memory = global_allocate(size + xml_memory_page_alignment); - if (!memory) - return 0; - - // align upwards to page boundary - void* page_memory = - reinterpret_cast((reinterpret_cast(memory) - + (xml_memory_page_alignment - 1)) - & ~(xml_memory_page_alignment - 1)); - - // prepare page structure - xml_memory_page* page = xml_memory_page::construct(page_memory); - - page->memory = memory; - page->allocator = _root->allocator; - - return page; - } - - static void deallocate_page(xml_memory_page* page) { - global_deallocate(page->memory); - } - - void* allocate_memory_oob(size_t size, xml_memory_page*& out_page); - - void* allocate_memory(size_t size, xml_memory_page*& out_page) { - if (_busy_size + size > xml_memory_page_size) - return allocate_memory_oob(size, out_page); - - void* buf = _root->data + _busy_size; - - _busy_size += size; - - out_page = _root; - - return buf; - } - - void deallocate_memory(void* ptr, size_t size, xml_memory_page* page) { - if (page == _root) - page->busy_size = _busy_size; - - assert(ptr >= page->data && ptr < page->data + page->busy_size); - (void) !ptr; - - page->freed_size += size; - assert(page->freed_size <= page->busy_size); - - if (page->freed_size == page->busy_size) { - if (page->next == 0) { - assert(_root == page); - - // top page freed, just reset sizes - page->busy_size = page->freed_size = 0; - _busy_size = 0; - } else { - assert(_root != page); - assert(page->prev); - - // remove from the list - page->prev->next = page->next; - page->next->prev = page->prev; - - // deallocate - deallocate_page(page); - } - } - } - - char_t* allocate_string(size_t length) { - // allocate memory for string and header block - size_t size = sizeof(xml_memory_string_header) - + length * sizeof(char_t); - - // round size up to pointer alignment boundary - size_t full_size = (size + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1); - - xml_memory_page* page; - xml_memory_string_header* header = - static_cast(allocate_memory( - full_size, page)); - - if (!header) - return 0; - - // setup header - ptrdiff_t page_offset = reinterpret_cast(header) - page->data; - - assert(page_offset >= 0 && page_offset < (1 << 16)); - header->page_offset = static_cast(page_offset); - - // full_size == 0 for large strings that occupy the whole page - assert( - full_size < (1 << 16) || (page->busy_size == full_size && page_offset == 0)); - header->full_size = static_cast( - full_size < (1 << 16) ? full_size : 0); - - return reinterpret_cast(header + 1); - } - - void deallocate_string(char_t* string) { - // get header - xml_memory_string_header* header = - reinterpret_cast(string) - 1; - - // deallocate - size_t page_offset = offsetof(xml_memory_page, data) - + header->page_offset; - xml_memory_page* page = - reinterpret_cast(reinterpret_cast(header) - - page_offset); - - // if full_size == 0 then this string occupies the whole page - size_t full_size = - header->full_size == 0 ? page->busy_size : header->full_size; - - deallocate_memory(header, full_size, page); - } - - xml_memory_page* _root; - size_t _busy_size; -}; - -PUGIXML_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, - xml_memory_page*& out_page) { - const size_t large_allocation_threshold = xml_memory_page_size / 4; - - xml_memory_page* page = allocate_page( - size <= large_allocation_threshold ? xml_memory_page_size : size); - if (!page) - return 0; - - if (size <= large_allocation_threshold) { - _root->busy_size = _busy_size; - - // insert page at the end of linked list - page->prev = _root; - _root->next = page; - _root = page; - - _busy_size = size; - } else { - // insert page before the end of linked list, so that it is deleted as soon as possible - // the last page is not deleted even if it's empty (see deallocate_memory) - assert(_root->prev); - - page->prev = _root->prev; - page->next = _root; - - _root->prev->next = page; - _root->prev = page; - } - - // allocate inside page - page->busy_size = size; - - out_page = page; - return page->data; -} -} - -namespace pugi { -/// A 'name=value' XML attribute structure. -struct xml_attribute_struct { - /// Default ctor - xml_attribute_struct(xml_memory_page* page) : - header(reinterpret_cast(page)), name(0), value(0), prev_attribute_c( - 0), next_attribute(0) { - } - - uintptr_t header; - - char_t* name; ///< Pointer to attribute name. - char_t* value; ///< Pointer to attribute value. - - xml_attribute_struct* prev_attribute_c; ///< Previous attribute (cyclic list) - xml_attribute_struct* next_attribute; ///< Next attribute -}; - -/// An XML document tree node. -struct xml_node_struct { - /// Default ctor - /// \param type - node type - xml_node_struct(xml_memory_page* page, xml_node_type type) : - header(reinterpret_cast(page) | (type - 1)), parent(0), name( - 0), value(0), first_child(0), prev_sibling_c(0), next_sibling( - 0), first_attribute(0) { - } - - uintptr_t header; - - xml_node_struct* parent; ///< Pointer to parent - - char_t* name; ///< Pointer to element name. - char_t* value; ///< Pointer to any associated string data. - - xml_node_struct* first_child; ///< First child - - xml_node_struct* prev_sibling_c; ///< Left brother (cyclic list) - xml_node_struct* next_sibling; ///< Right brother - - xml_attribute_struct* first_attribute; ///< First attribute -}; -} - -namespace { -struct xml_document_struct: public xml_node_struct, public xml_allocator { - xml_document_struct(xml_memory_page* page) : - xml_node_struct(page, node_document), xml_allocator(page), buffer(0) { - } - - const char_t* buffer; -}; - -static inline xml_allocator& get_allocator(const xml_node_struct* node) { - assert(node); - - return *reinterpret_cast(node->header - & xml_memory_page_pointer_mask)->allocator; -} -} - -// Low-level DOM operations -namespace { -inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc) { - xml_memory_page* page; - void* memory = alloc.allocate_memory(sizeof(xml_attribute_struct), page); - - return new (memory) xml_attribute_struct(page); -} - -inline xml_node_struct* allocate_node(xml_allocator& alloc, - xml_node_type type) { - xml_memory_page* page; - void* memory = alloc.allocate_memory(sizeof(xml_node_struct), page); - - return new (memory) xml_node_struct(page, type); -} - -inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc) { - uintptr_t header = a->header; - - if (header & xml_memory_page_name_allocated_mask) - alloc.deallocate_string(a->name); - if (header & xml_memory_page_value_allocated_mask) - alloc.deallocate_string(a->value); - - alloc.deallocate_memory( - a, - sizeof(xml_attribute_struct), - reinterpret_cast(header - & xml_memory_page_pointer_mask)); -} - -inline void destroy_node(xml_node_struct* n, xml_allocator& alloc) { - uintptr_t header = n->header; - - if (header & xml_memory_page_name_allocated_mask) - alloc.deallocate_string(n->name); - if (header & xml_memory_page_value_allocated_mask) - alloc.deallocate_string(n->value); - - for (xml_attribute_struct* attr = n->first_attribute; attr;) { - xml_attribute_struct* next = attr->next_attribute; - - destroy_attribute(attr, alloc); - - attr = next; - } - - for (xml_node_struct* child = n->first_child; child;) { - xml_node_struct* next = child->next_sibling; - - destroy_node(child, alloc); - - child = next; - } - - alloc.deallocate_memory( - n, - sizeof(xml_node_struct), - reinterpret_cast(header - & xml_memory_page_pointer_mask)); -} - -PUGIXML_NO_INLINE xml_node_struct* append_node(xml_node_struct* node, - xml_allocator& alloc, xml_node_type type = node_element) { - xml_node_struct* child = allocate_node(alloc, type); - if (!child) - return 0; - - child->parent = node; - - xml_node_struct* first_child = node->first_child; - - if (first_child) { - xml_node_struct* last_child = first_child->prev_sibling_c; - - last_child->next_sibling = child; - child->prev_sibling_c = last_child; - first_child->prev_sibling_c = child; - } else { - node->first_child = child; - child->prev_sibling_c = child; - } - - return child; -} - -PUGIXML_NO_INLINE xml_attribute_struct* append_attribute_ll( - xml_node_struct* node, xml_allocator& alloc) { - xml_attribute_struct* a = allocate_attribute(alloc); - if (!a) - return 0; - - xml_attribute_struct* first_attribute = node->first_attribute; - - if (first_attribute) { - xml_attribute_struct* last_attribute = first_attribute->prev_attribute_c; - - last_attribute->next_attribute = a; - a->prev_attribute_c = last_attribute; - first_attribute->prev_attribute_c = a; - } else { - node->first_attribute = a; - a->prev_attribute_c = a; - } - - return a; -} -} - -// Helper classes for code generation -namespace { -struct opt_false { - enum { - value = 0 - }; -}; - -struct opt_true { - enum { - value = 1 - }; -}; -} - -// Unicode utilities -namespace { -inline uint16_t endian_swap(uint16_t value) { - return static_cast(((value & 0xff) << 8) | (value >> 8)); -} - -inline uint32_t endian_swap(uint32_t value) { - return ((value & 0xff) << 24) | ((value & 0xff00) << 8) - | ((value & 0xff0000) >> 8) | (value >> 24); -} - -struct utf8_counter { - typedef size_t value_type; - - static value_type low(value_type result, uint32_t ch) { - // U+0000..U+007F - if (ch < 0x80) - return result + 1; - // U+0080..U+07FF - else if (ch < 0x800) - return result + 2; - // U+0800..U+FFFF - else - return result + 3; - } - - static value_type high(value_type result, uint32_t) { - // U+10000..U+10FFFF - return result + 4; - } -}; - -struct utf8_writer { - typedef uint8_t* value_type; - - static value_type low(value_type result, uint32_t ch) { - // U+0000..U+007F - if (ch < 0x80) { - *result = static_cast(ch); - return result + 1; - } - // U+0080..U+07FF - else if (ch < 0x800) { - result[0] = static_cast(0xC0 | (ch >> 6)); - result[1] = static_cast(0x80 | (ch & 0x3F)); - return result + 2; - } - // U+0800..U+FFFF - else { - result[0] = static_cast(0xE0 | (ch >> 12)); - result[1] = static_cast(0x80 | ((ch >> 6) & 0x3F)); - result[2] = static_cast(0x80 | (ch & 0x3F)); - return result + 3; - } - } - - static value_type high(value_type result, uint32_t ch) { - // U+10000..U+10FFFF - result[0] = static_cast(0xF0 | (ch >> 18)); - result[1] = static_cast(0x80 | ((ch >> 12) & 0x3F)); - result[2] = static_cast(0x80 | ((ch >> 6) & 0x3F)); - result[3] = static_cast(0x80 | (ch & 0x3F)); - return result + 4; - } - - static value_type any(value_type result, uint32_t ch) { - return (ch < 0x10000) ? low(result, ch) : high(result, ch); - } -}; - -struct utf16_counter { - typedef size_t value_type; - - static value_type low(value_type result, uint32_t) { - return result + 1; - } - - static value_type high(value_type result, uint32_t) { - return result + 2; - } -}; - -struct utf16_writer { - typedef uint16_t* value_type; - - static value_type low(value_type result, uint32_t ch) { - *result = static_cast(ch); - - return result + 1; - } - - static value_type high(value_type result, uint32_t ch) { - uint32_t msh = (uint32_t) (ch - 0x10000) >> 10; - uint32_t lsh = (uint32_t) (ch - 0x10000) & 0x3ff; - - result[0] = static_cast(0xD800 + msh); - result[1] = static_cast(0xDC00 + lsh); - - return result + 2; - } - - static value_type any(value_type result, uint32_t ch) { - return (ch < 0x10000) ? low(result, ch) : high(result, ch); - } -}; - -struct utf32_counter { - typedef size_t value_type; - - static value_type low(value_type result, uint32_t) { - return result + 1; - } - - static value_type high(value_type result, uint32_t) { - return result + 1; - } -}; - -struct utf32_writer { - typedef uint32_t* value_type; - - static value_type low(value_type result, uint32_t ch) { - *result = ch; - - return result + 1; - } - - static value_type high(value_type result, uint32_t ch) { - *result = ch; - - return result + 1; - } - - static value_type any(value_type result, uint32_t ch) { - *result = ch; - - return result + 1; - } -}; - -template struct wchar_selector; - -template<> struct wchar_selector<2> { - typedef uint16_t type; - typedef utf16_counter counter; - typedef utf16_writer writer; -}; - -template<> struct wchar_selector<4> { - typedef uint32_t type; - typedef utf32_counter counter; - typedef utf32_writer writer; -}; - -typedef wchar_selector::counter wchar_counter; -typedef wchar_selector::writer wchar_writer; - -template struct utf_decoder { - static inline typename Traits::value_type decode_utf8_block( - const uint8_t* data, size_t size, - typename Traits::value_type result) { - const uint8_t utf8_byte_mask = 0x3f; - - while (size) { - uint8_t lead = *data; - - // 0xxxxxxx -> U+0000..U+007F - if (lead < 0x80) { - result = Traits::low(result, lead); - data += 1; - size -= 1; - - // process aligned single-byte (ascii) blocks - if ((reinterpret_cast(data) & 3) == 0) { - while (size >= 4 - && (*reinterpret_cast(data) - & 0x80808080) == 0) { - result = Traits::low(result, data[0]); - result = Traits::low(result, data[1]); - result = Traits::low(result, data[2]); - result = Traits::low(result, data[3]); - data += 4; - size -= 4; - } - } - } - // 110xxxxx -> U+0080..U+07FF - else if ((unsigned) (lead - 0xC0) < 0x20 && size >= 2 - && (data[1] & 0xc0) == 0x80) { - result = Traits::low(result, - ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask)); - data += 2; - size -= 2; - } - // 1110xxxx -> U+0800-U+FFFF - else if ((unsigned) (lead - 0xE0) < 0x10 && size >= 3 - && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80) { - result = Traits::low( - result, - ((lead & ~0xE0) << 12) - | ((data[1] & utf8_byte_mask) << 6) - | (data[2] & utf8_byte_mask)); - data += 3; - size -= 3; - } - // 11110xxx -> U+10000..U+10FFFF - else if ((unsigned) (lead - 0xF0) < 0x08 && size >= 4 - && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 - && (data[3] & 0xc0) == 0x80) { - result = Traits::high( - result, - ((lead & ~0xF0) << 18) - | ((data[1] & utf8_byte_mask) << 12) - | ((data[2] & utf8_byte_mask) << 6) - | (data[3] & utf8_byte_mask)); - data += 4; - size -= 4; - } - // 10xxxxxx or 11111xxx -> invalid - else { - data += 1; - size -= 1; - } - } - - return result; - } - - static inline typename Traits::value_type decode_utf16_block( - const uint16_t* data, size_t size, - typename Traits::value_type result) { - const uint16_t* end = data + size; - - while (data < end) { - uint16_t lead = opt_swap::value ? endian_swap(*data) : *data; - - // U+0000..U+D7FF - if (lead < 0xD800) { - result = Traits::low(result, lead); - data += 1; - } - // U+E000..U+FFFF - else if ((unsigned) (lead - 0xE000) < 0x2000) { - result = Traits::low(result, lead); - data += 1; - } - // surrogate pair lead - else if ((unsigned) (lead - 0xD800) < 0x400 && data + 1 < end) { - uint16_t next = - opt_swap::value ? endian_swap(data[1]) : data[1]; - - if ((unsigned) (next - 0xDC00) < 0x400) { - result = Traits::high(result, - 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff)); - data += 2; - } else { - data += 1; - } - } else { - data += 1; - } - } - - return result; - } - - static inline typename Traits::value_type decode_utf32_block( - const uint32_t* data, size_t size, - typename Traits::value_type result) { - const uint32_t* end = data + size; - - while (data < end) { - uint32_t lead = opt_swap::value ? endian_swap(*data) : *data; - - // U+0000..U+FFFF - if (lead < 0x10000) { - result = Traits::low(result, lead); - data += 1; - } - // U+10000..U+10FFFF - else { - result = Traits::high(result, lead); - data += 1; - } - } - - return result; - } -}; - -template inline void convert_utf_endian_swap(T* result, - const T* data, size_t length) { - for (size_t i = 0; i < length; ++i) - result[i] = endian_swap(data[i]); -} - -inline void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, - size_t length) { - for (size_t i = 0; i < length; ++i) - result[i] = static_cast(endian_swap( - static_cast::type>(data[i]))); -} -} - -namespace { -enum chartype_t { - ct_parse_pcdata = 1, // \0, &, \r, < - ct_parse_attr = 2, // \0, &, \r, ', " - ct_parse_attr_ws = 4, // \0, &, \r, ', ", \n, tab - ct_space = 8, // \r, \n, space, tab - ct_parse_cdata = 16, // \0, ], >, \r - ct_parse_comment = 32, // \0, -, >, \r - ct_symbol = 64, // Any symbol > 127, a-z, A-Z, 0-9, _, :, -, . - ct_start_symbol = 128 -// Any symbol > 127, a-z, A-Z, _, : -}; - -const unsigned char chartype_table[256] = { 55, 0, 0, 0, 0, - 0, - 0, - 0, - 0, - 12, - 12, - 0, - 0, - 63, - 0, - 0, // 0-15 - 0, 0, 0, 0, 0, 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, // 16-31 - 8, 0, 6, 0, 0, 0, - 7, - 6, - 0, - 0, - 0, - 0, - 0, - 96, - 64, - 0, // 32-47 - 64, 64, 64, 64, 64, 64, - 64, - 64, - 64, - 64, - 192, - 0, - 1, - 0, - 48, - 0, // 48-63 - 0, 192, 192, 192, 192, 192, - 192, - 192, - 192, - 192, - 192, - 192, - 192, - 192, - 192, - 192, // 64-79 - 192, 192, 192, 192, 192, 192, 192, - 192, - 192, - 192, - 192, - 0, - 0, - 16, - 0, - 192, // 80-95 - 0, 192, 192, 192, 192, 192, 192, - 192, - 192, - 192, - 192, - 192, - 192, - 192, - 192, - 192, // 96-111 - 192, 192, 192, 192, 192, 192, 192, 192, - 192, - 192, - 192, - 0, - 0, - 0, - 0, - 0, // 112-127 - - 192, 192, 192, 192, 192, 192, 192, 192, - 192, - 192, - 192, - 192, - 192, - 192, - 192, - 192, // 128+ - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192 }; - -enum chartypex_t { - ctx_special_pcdata = 1, // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, > - ctx_special_attr = 2, // Any symbol >= 0 and < 32 (except \t), &, <, >, " - ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _ - ctx_digit = 8, // 0-9 - ctx_symbol = 16 -// Any symbol > 127, a-z, A-Z, 0-9, _, -, . -}; - -const unsigned char chartypex_table[256] = { 3, 3, 3, 3, 3, 3, 3, 3, 3, - 0, - 2, - 3, - 3, - 2, - 3, - 3, // 0-15 - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, - 3, - 3, - 3, - 3, - 3, // 16-31 - 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, - 0, - 0, - 0, - 16, - 16, - 0, // 32-47 - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 0, - 0, - 3, - 0, - 3, - 0, // 48-63 - - 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, - 20, - 20, - 20, - 20, - 20, // 64-79 - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, - 0, - 0, - 0, - 0, - 20, // 80-95 - 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, - 20, - 20, - 20, - 20, - 20, // 96-111 - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, - 0, - 0, - 0, - 0, - 0, // 112-127 - - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, - 20, - 20, - 20, - 20, - 20, // 128+ - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20 }; - -#ifdef PUGIXML_WCHAR_MODE -#define IS_CHARTYPE_IMPL(c, ct, table) ((static_cast(c) < 128 ? table[static_cast(c)] : table[128]) & (ct)) -#else -#define IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast(c)] & (ct)) -#endif - -#define IS_CHARTYPE(c, ct) IS_CHARTYPE_IMPL(c, ct, chartype_table) -#define IS_CHARTYPEX(c, ct) IS_CHARTYPE_IMPL(c, ct, chartypex_table) - -bool is_little_endian() { - unsigned int ui = 1; - - return *reinterpret_cast(&ui) == 1; -} - -xml_encoding get_wchar_encoding() { - STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); - - if (sizeof(wchar_t) == 2) - return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - else - return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; -} - -xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, - uint8_t d3) { - // look for BOM in first few bytes - if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) - return encoding_utf32_be; - if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) - return encoding_utf32_le; - if (d0 == 0xfe && d1 == 0xff) - return encoding_utf16_be; - if (d0 == 0xff && d1 == 0xfe) - return encoding_utf16_le; - if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf) - return encoding_utf8; - - // look for <, (contents); - - DMC_VOLATILE - uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3]; - - return guess_buffer_encoding(d0, d1, d2, d3); -} - -bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, - const void* contents, size_t size, bool is_mutable) { - if (is_mutable) { - out_buffer = static_cast(const_cast(contents)); - } else { - void* buffer = global_allocate(size > 0 ? size : 1); - if (!buffer) - return false; - - memcpy(buffer, contents, size); - - out_buffer = static_cast(buffer); - } - - out_length = size / sizeof(char_t); - - return true; -} - -#ifdef PUGIXML_WCHAR_MODE -inline bool need_endian_swap_utf(xml_encoding le, xml_encoding re) -{ - return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) || - (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be); -} - -bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) -{ - const char_t* data = static_cast(contents); - - if (is_mutable) - { - out_buffer = const_cast(data); - } - else - { - out_buffer = static_cast(global_allocate(size > 0 ? size : 1)); - if (!out_buffer) return false; - } - - out_length = size / sizeof(char_t); - - convert_wchar_endian_swap(out_buffer, data, out_length); - - return true; -} - -bool convert_buffer_utf8(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size) -{ - const uint8_t* data = static_cast(contents); - - // first pass: get length in wchar_t units - out_length = utf_decoder::decode_utf8_block(data, size, 0); - - // allocate buffer of suitable length - out_buffer = static_cast(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); - if (!out_buffer) return false; - - // second pass: convert utf8 input to wchar_t - wchar_writer::value_type out_begin = reinterpret_cast(out_buffer); - wchar_writer::value_type out_end = utf_decoder::decode_utf8_block(data, size, out_begin); - - assert(out_end == out_begin + out_length); - (void)!out_end; - - return true; -} - -template bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) -{ - const uint16_t* data = static_cast(contents); - size_t length = size / sizeof(uint16_t); - - // first pass: get length in wchar_t units - out_length = utf_decoder::decode_utf16_block(data, length, 0); - - // allocate buffer of suitable length - out_buffer = static_cast(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); - if (!out_buffer) return false; - - // second pass: convert utf16 input to wchar_t - wchar_writer::value_type out_begin = reinterpret_cast(out_buffer); - wchar_writer::value_type out_end = utf_decoder::decode_utf16_block(data, length, out_begin); - - assert(out_end == out_begin + out_length); - (void)!out_end; - - return true; -} - -template bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) -{ - const uint32_t* data = static_cast(contents); - size_t length = size / sizeof(uint32_t); - - // first pass: get length in wchar_t units - out_length = utf_decoder::decode_utf32_block(data, length, 0); - - // allocate buffer of suitable length - out_buffer = static_cast(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); - if (!out_buffer) return false; - - // second pass: convert utf32 input to wchar_t - wchar_writer::value_type out_begin = reinterpret_cast(out_buffer); - wchar_writer::value_type out_end = utf_decoder::decode_utf32_block(data, length, out_begin); - - assert(out_end == out_begin + out_length); - (void)!out_end; - - return true; -} - -bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) -{ - // get native encoding - xml_encoding wchar_encoding = get_wchar_encoding(); - - // fast path: no conversion required - if (encoding == wchar_encoding) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); - - // only endian-swapping is required - if (need_endian_swap_utf(encoding, wchar_encoding)) return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable); - - // source encoding is utf8 - if (encoding == encoding_utf8) return convert_buffer_utf8(out_buffer, out_length, contents, size); - - // source encoding is utf16 - if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) - { - xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - - return (native_encoding == encoding) ? - convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) : - convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true()); - } - - // source encoding is utf32 - if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) - { - xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - - return (native_encoding == encoding) ? - convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : - convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); - } - - assert(!"Invalid encoding"); - return false; -} -#else -template bool convert_buffer_utf16(char_t*& out_buffer, - size_t& out_length, const void* contents, size_t size, opt_swap) { - const uint16_t* data = static_cast(contents); - size_t length = size / sizeof(uint16_t); - - // first pass: get length in utf8 units - out_length = utf_decoder::decode_utf16_block(data, - length, 0); - - // allocate buffer of suitable length - out_buffer = static_cast(global_allocate( - (out_length > 0 ? out_length : 1) * sizeof(char_t))); - if (!out_buffer) - return false; - - // second pass: convert utf16 input to utf8 - uint8_t* out_begin = reinterpret_cast(out_buffer); - uint8_t* out_end = utf_decoder::decode_utf16_block( - data, length, out_begin); - - assert(out_end == out_begin + out_length); - (void) !out_end; - - return true; -} - -template bool convert_buffer_utf32(char_t*& out_buffer, - size_t& out_length, const void* contents, size_t size, opt_swap) { - const uint32_t* data = static_cast(contents); - size_t length = size / sizeof(uint32_t); - - // first pass: get length in utf8 units - out_length = utf_decoder::decode_utf32_block(data, - length, 0); - - // allocate buffer of suitable length - out_buffer = static_cast(global_allocate( - (out_length > 0 ? out_length : 1) * sizeof(char_t))); - if (!out_buffer) - return false; - - // second pass: convert utf32 input to utf8 - uint8_t* out_begin = reinterpret_cast(out_buffer); - uint8_t* out_end = utf_decoder::decode_utf32_block( - data, length, out_begin); - - assert(out_end == out_begin + out_length); - (void) !out_end; - - return true; -} - -bool convert_buffer(char_t*& out_buffer, size_t& out_length, - xml_encoding encoding, const void* contents, size_t size, - bool is_mutable) { - // fast path: no conversion required - if (encoding == encoding_utf8) - return get_mutable_buffer(out_buffer, out_length, contents, size, - is_mutable); - - // source encoding is utf16 - if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) { - xml_encoding native_encoding = - is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - - return (native_encoding == encoding) ? - convert_buffer_utf16(out_buffer, out_length, contents, size, - opt_false()) : - convert_buffer_utf16(out_buffer, out_length, contents, size, - opt_true()); - } - - // source encoding is utf32 - if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) { - xml_encoding native_encoding = - is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - - return (native_encoding == encoding) ? - convert_buffer_utf32(out_buffer, out_length, contents, size, - opt_false()) : - convert_buffer_utf32(out_buffer, out_length, contents, size, - opt_true()); - } - - assert(!"Invalid encoding"); - return false; -} -#endif - -size_t as_utf8_begin(const wchar_t* str, size_t length) { - STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); - - // get length in utf8 characters - return sizeof(wchar_t) == 2 ? - utf_decoder::decode_utf16_block( - reinterpret_cast(str), length, 0) : - utf_decoder::decode_utf32_block( - reinterpret_cast(str), length, 0); -} - -void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length) { - STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); - - // convert to utf8 - uint8_t* begin = reinterpret_cast(buffer); - uint8_t* end = - sizeof(wchar_t) == 2 ? - utf_decoder::decode_utf16_block( - reinterpret_cast(str), length, - begin) : - utf_decoder::decode_utf32_block( - reinterpret_cast(str), length, - begin); - - assert(begin + size == end); - (void) !end; - - // zero-terminate - buffer[size] = 0; -} - -#ifndef PUGIXML_NO_STL -std::string as_utf8_impl(const wchar_t* str, size_t length) { - // first pass: get length in utf8 characters - size_t size = as_utf8_begin(str, length); - - // allocate resulting string - std::string result; - result.resize(size); - - // second pass: convert to utf8 - if (size > 0) - as_utf8_end(&result[0], size, str, length); - - return result; -} - -std::wstring as_wide_impl(const char* str, size_t size) { - const uint8_t* data = reinterpret_cast(str); - - // first pass: get length in wchar_t units - size_t length = utf_decoder::decode_utf8_block(data, size, - 0); - - // allocate resulting string - std::wstring result; - result.resize(length); - - // second pass: convert to wchar_t - if (length > 0) { - wchar_writer::value_type begin = - reinterpret_cast(&result[0]); - wchar_writer::value_type end = - utf_decoder::decode_utf8_block(data, size, begin); - - assert(begin + length == end); - (void) !end; - } - - return result; -} -#endif - -inline bool strcpy_insitu_allow(size_t length, uintptr_t allocated, - char_t* target) { - assert(target); - size_t target_length = strlength(target); - - // always reuse document buffer memory if possible - if (!allocated) - return target_length >= length; - - // reuse heap memory if waste is not too great - const size_t reuse_threshold = 32; - - return target_length >= length - && (target_length < reuse_threshold - || target_length - length < target_length / 2); -} - -bool strcpy_insitu(char_t*& dest, uintptr_t& header, uintptr_t header_mask, - const char_t* source) { - size_t source_length = strlength(source); - - if (source_length == 0) { - // empty string and null pointer are equivalent, so just deallocate old memory - xml_allocator* alloc = reinterpret_cast(header - & xml_memory_page_pointer_mask)->allocator; - - if (header & header_mask) - alloc->deallocate_string(dest); - - // mark the string as not allocated - dest = 0; - header &= ~header_mask; - - return true; - } else if (dest - && strcpy_insitu_allow(source_length, header & header_mask, dest)) { - // we can reuse old buffer, so just copy the new data (including zero terminator) - memcpy(dest, source, (source_length + 1) * sizeof(char_t)); - - return true; - } else { - xml_allocator* alloc = reinterpret_cast(header - & xml_memory_page_pointer_mask)->allocator; - - // allocate new buffer - char_t* buf = alloc->allocate_string(source_length + 1); - if (!buf) - return false; - - // copy the string (including zero terminator) - memcpy(buf, source, (source_length + 1) * sizeof(char_t)); - - // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures) - if (header & header_mask) - alloc->deallocate_string(dest); - - // the string is now allocated, so set the flag - dest = buf; - header |= header_mask; - - return true; - } -} - -struct gap { - char_t* end; - size_t size; - - gap() : - end(0), size(0) { - } - - // Push new gap, move s count bytes further (skipping the gap). - // Collapse previous gap. - void push(char_t*& s, size_t count) { - if (end) // there was a gap already; collapse it - { - // Move [old_gap_end, new_gap_start) to [old_gap_start, ...) - assert(s >= end); - memmove(end - size, end, - reinterpret_cast(s) - reinterpret_cast(end)); - } - - s += count; // end of current gap - - // "merge" two gaps - end = s; - size += count; - } - - // Collapse all gaps, return past-the-end pointer - char_t* flush(char_t* s) { - if (end) { - // Move [old_gap_end, current_pos) to [old_gap_start, ...) - assert(s >= end); - memmove(end - size, end, - reinterpret_cast(s) - reinterpret_cast(end)); - - return s - size; - } else - return s; - } -}; - -char_t* strconv_escape(char_t* s, gap& g) { - char_t* stre = s + 1; - - switch (*stre) { - case '#': // &#... - { - unsigned int ucsc = 0; - - if (stre[1] == 'x') // &#x... (hex code) - { - stre += 2; - - char_t ch = *stre; - - if (ch == ';') - return stre; - - for (;;) { - if (static_cast(ch - '0') <= 9) - ucsc = 16 * ucsc + (ch - '0'); - else if (static_cast((ch | ' ') - 'a') <= 5) - ucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10); - else if (ch == ';') - break; - else - // cancel - return stre; - - ch = *++stre; - } - - ++stre; - } else // &#... (dec code) - { - char_t ch = *++stre; - - if (ch == ';') - return stre; - - for (;;) { - if (static_cast(ch - '0') <= 9) - ucsc = 10 * ucsc + (ch - '0'); - else if (ch == ';') - break; - else - // cancel - return stre; - - ch = *++stre; - } - - ++stre; - } - -#ifdef PUGIXML_WCHAR_MODE - s = reinterpret_cast(wchar_writer::any(reinterpret_cast(s), ucsc)); -#else - s = reinterpret_cast(utf8_writer::any( - reinterpret_cast(s), ucsc)); -#endif - - g.push(s, stre - s); - return stre; - } - case 'a': // &a - { - ++stre; - - if (*stre == 'm') // &am - { - if (*++stre == 'p' && *++stre == ';') // & - { - *s++ = '&'; - ++stre; - - g.push(s, stre - s); - return stre; - } - } else if (*stre == 'p') // &ap - { - if (*++stre == 'o' && *++stre == 's' && *++stre == ';') // ' - { - *s++ = '\''; - ++stre; - - g.push(s, stre - s); - return stre; - } - } - break; - } - case 'g': // &g - { - if (*++stre == 't' && *++stre == ';') // > - { - *s++ = '>'; - ++stre; - - g.push(s, stre - s); - return stre; - } - break; - } - case 'l': // &l - { - if (*++stre == 't' && *++stre == ';') // < - { - *s++ = '<'; - ++stre; - - g.push(s, stre - s); - return stre; - } - break; - } - case 'q': // &q - { - if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' - && *++stre == ';') // " - { - *s++ = '"'; - ++stre; - - g.push(s, stre - s); - return stre; - } - break; - } - } - - return stre; -} - -// Utility macro for last character handling -#define ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e))) - -char_t* strconv_comment(char_t* s, char_t endch) { - gap g; - - while (true) { - while (!IS_CHARTYPE(*s, ct_parse_comment)) - ++s; - - if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair - { - *s++ = '\n'; // replace first one with 0x0a - - if (*s == '\n') - g.push(s, 1); - } else if (s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')) // comment ends here - { - *g.flush(s) = 0; - - return s + (s[2] == '>' ? 3 : 2); - } else if (*s == 0) { - return 0; - } else - ++s; - } -} - -char_t* strconv_cdata(char_t* s, char_t endch) { - gap g; - - while (true) { - while (!IS_CHARTYPE(*s, ct_parse_cdata)) - ++s; - - if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair - { - *s++ = '\n'; // replace first one with 0x0a - - if (*s == '\n') - g.push(s, 1); - } else if (s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')) // CDATA ends here - { - *g.flush(s) = 0; - - return s + 1; - } else if (*s == 0) { - return 0; - } else - ++s; - } -} - -typedef char_t* (*strconv_pcdata_t)(char_t*); - -template struct strconv_pcdata_impl { - static char_t* parse(char_t* s) { - gap g; - - while (true) { - while (!IS_CHARTYPE(*s, ct_parse_pcdata)) - ++s; - - if (*s == '<') // PCDATA ends here - { - *g.flush(s) = 0; - - return s + 1; - } else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair - { - *s++ = '\n'; // replace first one with 0x0a - - if (*s == '\n') - g.push(s, 1); - } else if (opt_escape::value && *s == '&') { - s = strconv_escape(s, g); - } else if (*s == 0) { - return s; - } else - ++s; - } - } -}; - -strconv_pcdata_t get_strconv_pcdata(unsigned int optmask) { - STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20); - - switch ((optmask >> 4) & 3) // get bitmask for flags (eol escapes) - { - case 0: - return strconv_pcdata_impl::parse; - case 1: - return strconv_pcdata_impl::parse; - case 2: - return strconv_pcdata_impl::parse; - case 3: - return strconv_pcdata_impl::parse; - default: - return 0; // should not get here - } -} - -typedef char_t* (*strconv_attribute_t)(char_t*, char_t); - -template struct strconv_attribute_impl { - static char_t* parse_wnorm(char_t* s, char_t end_quote) { - gap g; - - // trim leading whitespaces - if (IS_CHARTYPE(*s, ct_space)) { - char_t* str = s; - - do - ++str; - while (IS_CHARTYPE(*str, ct_space)); - - g.push(s, str - s); - } - - while (true) { - while (!IS_CHARTYPE(*s, ct_parse_attr_ws | ct_space)) - ++s; - - if (*s == end_quote) { - char_t* str = g.flush(s); - - do - *str-- = 0; - while (IS_CHARTYPE(*str, ct_space)); - - return s + 1; - } else if (IS_CHARTYPE(*s, ct_space)) { - *s++ = ' '; - - if (IS_CHARTYPE(*s, ct_space)) { - char_t* str = s + 1; - while (IS_CHARTYPE(*str, ct_space)) - ++str; - - g.push(s, str - s); - } - } else if (opt_escape::value && *s == '&') { - s = strconv_escape(s, g); - } else if (!*s) { - return 0; - } else - ++s; - } - } - - static char_t* parse_wconv(char_t* s, char_t end_quote) { - gap g; - - while (true) { - while (!IS_CHARTYPE(*s, ct_parse_attr_ws)) - ++s; - - if (*s == end_quote) { - *g.flush(s) = 0; - - return s + 1; - } else if (IS_CHARTYPE(*s, ct_space)) { - if (*s == '\r') { - *s++ = ' '; - - if (*s == '\n') - g.push(s, 1); - } else - *s++ = ' '; - } else if (opt_escape::value && *s == '&') { - s = strconv_escape(s, g); - } else if (!*s) { - return 0; - } else - ++s; - } - } - - static char_t* parse_eol(char_t* s, char_t end_quote) { - gap g; - - while (true) { - while (!IS_CHARTYPE(*s, ct_parse_attr)) - ++s; - - if (*s == end_quote) { - *g.flush(s) = 0; - - return s + 1; - } else if (*s == '\r') { - *s++ = '\n'; - - if (*s == '\n') - g.push(s, 1); - } else if (opt_escape::value && *s == '&') { - s = strconv_escape(s, g); - } else if (!*s) { - return 0; - } else - ++s; - } - } - - static char_t* parse_simple(char_t* s, char_t end_quote) { - gap g; - - while (true) { - while (!IS_CHARTYPE(*s, ct_parse_attr)) - ++s; - - if (*s == end_quote) { - *g.flush(s) = 0; - - return s + 1; - } else if (opt_escape::value && *s == '&') { - s = strconv_escape(s, g); - } else if (!*s) { - return 0; - } else - ++s; - } - } -}; - -strconv_attribute_t get_strconv_attribute(unsigned int optmask) { - STATIC_ASSERT( - parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80); - - switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes) - { - case 0: - return strconv_attribute_impl::parse_simple; - case 1: - return strconv_attribute_impl::parse_simple; - case 2: - return strconv_attribute_impl::parse_eol; - case 3: - return strconv_attribute_impl::parse_eol; - case 4: - return strconv_attribute_impl::parse_wconv; - case 5: - return strconv_attribute_impl::parse_wconv; - case 6: - return strconv_attribute_impl::parse_wconv; - case 7: - return strconv_attribute_impl::parse_wconv; - case 8: - return strconv_attribute_impl::parse_wnorm; - case 9: - return strconv_attribute_impl::parse_wnorm; - case 10: - return strconv_attribute_impl::parse_wnorm; - case 11: - return strconv_attribute_impl::parse_wnorm; - case 12: - return strconv_attribute_impl::parse_wnorm; - case 13: - return strconv_attribute_impl::parse_wnorm; - case 14: - return strconv_attribute_impl::parse_wnorm; - case 15: - return strconv_attribute_impl::parse_wnorm; - default: - return 0; // should not get here - } -} - -inline xml_parse_result make_parse_result(xml_parse_status status, - ptrdiff_t offset = 0) { - xml_parse_result result; - result.status = status; - result.offset = offset; - - return result; -} - -struct xml_parser { - xml_allocator alloc; - char_t* error_offset; - jmp_buf error_handler; - - // Parser utilities. -#define SKIPWS() { while (IS_CHARTYPE(*s, ct_space)) ++s; } -#define OPTSET(OPT) ( optmsk & OPT ) -#define PUSHNODE(TYPE) { cursor = append_node(cursor, alloc, TYPE); if (!cursor) THROW_ERROR(status_out_of_memory, s); } -#define POPNODE() { cursor = cursor->parent; } -#define SCANFOR(X) { while (*s != 0 && !(X)) ++s; } -#define SCANWHILE(X) { while ((X)) ++s; } -#define ENDSEG() { ch = *s; *s = 0; ++s; } -#define THROW_ERROR(err, m) error_offset = m, longjmp(error_handler, err) -#define CHECK_ERROR(err, m) { if (*s == 0) THROW_ERROR(err, m); } - - xml_parser(const xml_allocator& alloc) : - alloc(alloc), error_offset(0) { - } - - // DOCTYPE consists of nested sections of the following possible types: - // , , "...", '...' - // - // - // First group can not contain nested groups - // Second group can contain nested groups of the same type - // Third group can contain all other groups - char_t* parse_doctype_primitive(char_t* s) { - if (*s == '"' || *s == '\'') { - // quoted string - char_t ch = *s++; - SCANFOR(*s == ch); - if (!*s) - THROW_ERROR(status_bad_doctype, s); - - s++; - } else if (s[0] == '<' && s[1] == '?') { - // - s += 2; - SCANFOR(s[0] == '?' && s[1] == '>'); - // no need for ENDSWITH because ?> can't terminate proper doctype - if (!*s) - THROW_ERROR(status_bad_doctype, s); - - s += 2; - } else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-') { - s += 4; - SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); - // no need for ENDSWITH because --> can't terminate proper doctype - if (!*s) - THROW_ERROR(status_bad_doctype, s); - - s += 4; - } else - THROW_ERROR(status_bad_doctype, s); - - return s; - } - - char_t* parse_doctype_ignore(char_t* s) { - assert(s[0] == '<' && s[1] == '!' && s[2] == '['); - s++; - - while (*s) { - if (s[0] == '<' && s[1] == '!' && s[2] == '[') { - // nested ignore section - s = parse_doctype_ignore(s); - } else if (s[0] == ']' && s[1] == ']' && s[2] == '>') { - // ignore section end - s += 3; - - return s; - } else - s++; - } - - THROW_ERROR(status_bad_doctype, s); - - return s; - } - - char_t* parse_doctype_group(char_t* s, char_t endch, bool toplevel) { - assert(s[0] == '<' && s[1] == '!'); - s++; - - while (*s) { - if (s[0] == '<' && s[1] == '!' && s[2] != '-') { - if (s[2] == '[') { - // ignore - s = parse_doctype_ignore(s); - } else { - // some control group - s = parse_doctype_group(s, endch, false); - } - } else if (s[0] == '<' || s[0] == '"' || s[0] == '\'') { - // unknown tag (forbidden), or some primitive group - s = parse_doctype_primitive(s); - } else if (*s == '>') { - s++; - - return s; - } else - s++; - } - - if (!toplevel || endch != '>') - THROW_ERROR(status_bad_doctype, s); - - return s; - } - - char_t* parse_exclamation(char_t* s, xml_node_struct* cursor, - unsigned int optmsk, char_t endch) { - // parse node contents, starting with exclamation mark - ++s; - - if (*s == '-') // 'value = s; // Save the offset. - } - - if (OPTSET(parse_eol) && OPTSET(parse_comments)) { - s = strconv_comment(s, endch); - - if (!s) - THROW_ERROR(status_bad_comment, cursor->value); - } else { - // Scan for terminating '-->'. - SCANFOR(s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')); - CHECK_ERROR(status_bad_comment, s); - - if (OPTSET(parse_comments)) - *s = 0; // Zero-terminate this segment at the first terminating '-'. - - s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'. - } - } else - THROW_ERROR(status_bad_comment, s); - } else if (*s == '[') { - // 'value = s; // Save the offset. - - if (OPTSET(parse_eol)) { - s = strconv_cdata(s, endch); - - if (!s) - THROW_ERROR(status_bad_cdata, cursor->value); - } else { - // Scan for terminating ']]>'. - SCANFOR( - s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')); - CHECK_ERROR(status_bad_cdata, s); - - *s++ = 0; // Zero-terminate this segment. - } - } else // Flagged for discard, but we still have to scan for the terminator. - { - // Scan for terminating ']]>'. - SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')); - CHECK_ERROR(status_bad_cdata, s); - - ++s; - } - - s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'. - } else - THROW_ERROR(status_bad_cdata, s); - } else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' - && s[4] == 'Y' && s[5] == 'P' && ENDSWITH(s[6], 'E')) { - s -= 2; - - if (cursor->parent) - THROW_ERROR(status_bad_doctype, s); - - char_t* mark = s + 9; - - s = parse_doctype_group(s, endch, true); - - if (OPTSET(parse_doctype)) { - while (IS_CHARTYPE(*mark, ct_space)) - ++mark; - - PUSHNODE(node_doctype); - - cursor->value = mark; - - assert((s[0] == 0 && endch == '>') || s[-1] == '>'); - s[*s == 0 ? 0 : -1] = 0; - - POPNODE(); - } - } else if (*s == 0 && endch == '-') - THROW_ERROR(status_bad_comment, s); - else if (*s == 0 && endch == '[') - THROW_ERROR(status_bad_cdata, s); - else - THROW_ERROR(status_unrecognized_tag, s); - - return s; - } - - char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor, - unsigned int optmsk, char_t endch) { - // load into registers - xml_node_struct* cursor = ref_cursor; - char_t ch = 0; - - // parse node contents, starting with question mark - ++s; - - // read PI target - char_t* target = s; - - if (!IS_CHARTYPE(*s, ct_start_symbol)) - THROW_ERROR(status_bad_pi, s); - - SCANWHILE(IS_CHARTYPE(*s, ct_symbol)); - CHECK_ERROR(status_bad_pi, s); - - // determine node type; stricmp / strcasecmp is not portable - bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' - && (target[2] | ' ') == 'l' && target + 3 == s; - - if (declaration ? OPTSET(parse_declaration) : OPTSET(parse_pi)) - { - if (declaration) { - // disallow non top-level declarations - if (cursor->parent) - THROW_ERROR(status_bad_pi, s); - - PUSHNODE(node_declaration); - } else { - PUSHNODE(node_pi); - } - - cursor->name = target; - - ENDSEG(); - - // parse value/attributes - if (ch == '?') { - // empty node - if (!ENDSWITH(*s, '>')) - THROW_ERROR(status_bad_pi, s); - s += (*s == '>'); - - POPNODE(); - } else if (IS_CHARTYPE(ch, ct_space)) { - SKIPWS(); - - // scan for tag end - char_t* value = s; - - SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>')); - CHECK_ERROR(status_bad_pi, s); - - if (declaration) { - // replace ending ? with / so that 'element' terminates properly - *s = '/'; - - // we exit from this function with cursor at node_declaration, which is a signal to parse() to go to LOC_ATTRIBUTES - s = value; - } else { - // store value and step over > - cursor->value = value; - POPNODE(); - - ENDSEG(); - - s += (*s == '>'); - } - } else - THROW_ERROR(status_bad_pi, s); - } else { - // scan for tag end - SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>')); - CHECK_ERROR(status_bad_pi, s); - - s += (s[1] == '>' ? 2 : 1); - } - - // store from registers - ref_cursor = cursor; - - return s; - } - - void parse(char_t* s, xml_node_struct* xmldoc, unsigned int optmsk, - char_t endch) { - strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk); - strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk); - - char_t ch = 0; - xml_node_struct* cursor = xmldoc; - char_t* mark = s; - - while (*s != 0) { - if (*s == '<') { - ++s; - - LOC_TAG: if (IS_CHARTYPE(*s, ct_start_symbol)) // '<#...' - { - PUSHNODE(node_element); - // Append a new node to the tree. - - cursor->name = s; - - SCANWHILE(IS_CHARTYPE(*s, ct_symbol)); - // Scan for a terminator. - ENDSEG(); // Save char in 'ch', terminate & step over. - - if (ch == '>') { - // end of tag - } else if (IS_CHARTYPE(ch, ct_space)) { - LOC_ATTRIBUTES: while (true) { - SKIPWS(); // Eat any whitespace. - - if (IS_CHARTYPE(*s, ct_start_symbol)) // <... #... - { - xml_attribute_struct* a = append_attribute_ll( - cursor, alloc); // Make space for this attribute. - if (!a) - THROW_ERROR(status_out_of_memory, s); - - a->name = s; // Save the offset. - - SCANWHILE(IS_CHARTYPE(*s, ct_symbol)); - // Scan for a terminator. - CHECK_ERROR(status_bad_attribute, s); - //$ redundant, left for performance - - ENDSEG(); // Save char in 'ch', terminate & step over. - CHECK_ERROR(status_bad_attribute, s); - //$ redundant, left for performance - - if (IS_CHARTYPE(ch, ct_space)) { - SKIPWS(); // Eat any whitespace. - CHECK_ERROR(status_bad_attribute, s); - //$ redundant, left for performance - - ch = *s; - ++s; - } - - if (ch == '=') // '<... #=...' - { - SKIPWS(); // Eat any whitespace. - - if (*s == '"' || *s == '\'') // '<... #="...' - { - ch = *s; // Save quote char to avoid breaking on "''" -or- '""'. - ++s; // Step over the quote. - a->value = s; // Save the offset. - - s = strconv_attribute(s, ch); - - if (!s) - THROW_ERROR(status_bad_attribute, - a->value); - - // After this line the loop continues from the start; - // Whitespaces, / and > are ok, symbols and EOF are wrong, - // everything else will be detected - if (IS_CHARTYPE(*s, ct_start_symbol)) - THROW_ERROR(status_bad_attribute, - s); - } else - THROW_ERROR(status_bad_attribute, s); - } else - THROW_ERROR(status_bad_attribute, s); - } else if (*s == '/') { - ++s; - - if (*s == '>') { - POPNODE(); - s++; - break; - } else if (*s == 0 && endch == '>') { - POPNODE(); - break; - } else - THROW_ERROR(status_bad_start_element, s); - } else if (*s == '>') { - ++s; - - break; - } else if (*s == 0 && endch == '>') { - break; - } else - THROW_ERROR(status_bad_start_element, s); - } - - // !!! - } else if (ch == '/') // '<#.../' - { - if (!ENDSWITH(*s, '>')) - THROW_ERROR(status_bad_start_element, s); - - POPNODE(); // Pop. - - s += (*s == '>'); - } else if (ch == 0) { - // we stepped over null terminator, backtrack & handle closing tag - --s; - - if (endch != '>') - THROW_ERROR(status_bad_start_element, s); - } else - THROW_ERROR(status_bad_start_element, s); - } else if (*s == '/') { - ++s; - - char_t* name = cursor->name; - if (!name) - THROW_ERROR(status_end_element_mismatch, s); - - while (IS_CHARTYPE(*s, ct_symbol)) { - if (*s++ != *name++) - THROW_ERROR(status_end_element_mismatch, s); - } - - if (*name) { - if (*s == 0 && name[0] == endch && name[1] == 0) - THROW_ERROR(status_bad_end_element, s); - else - THROW_ERROR(status_end_element_mismatch, s); - } - - POPNODE(); // Pop. - - SKIPWS(); - - if (*s == 0) { - if (endch != '>') - THROW_ERROR(status_bad_end_element, s); - } else { - if (*s != '>') - THROW_ERROR(status_bad_end_element, s); - ++s; - } - } else if (*s == '?') // 'header & xml_memory_page_type_mask) + 1 - == node_declaration) - goto LOC_ATTRIBUTES; - } else if (*s == '!') // 'parent) { - PUSHNODE(node_pcdata); - // Append a new node on the tree. - cursor->value = s; // Save the offset. - - s = strconv_pcdata(s); - - POPNODE(); // Pop since this is a standalone. - - if (!*s) - break; - } else { - SCANFOR(*s == '<'); - // '...<' - if (!*s) - break; - - ++s; - } - - // We're after '<' - goto LOC_TAG; - } - } - - // check that last tag is closed - if (cursor != xmldoc) - THROW_ERROR(status_end_element_mismatch, s); - } - - static xml_parse_result parse(char_t* buffer, size_t length, - xml_node_struct* root, unsigned int optmsk) { - xml_document_struct* xmldoc = static_cast(root); - - // store buffer for offset_debug - xmldoc->buffer = buffer; - - // early-out for empty documents - if (length == 0) - return make_parse_result(status_ok); - - // create parser on stack - xml_parser parser(*xmldoc); - - // save last character and make buffer zero-terminated (speeds up parsing) - char_t endch = buffer[length - 1]; - buffer[length - 1] = 0; - - // perform actual parsing - int error = setjmp(parser.error_handler); - - if (error == 0) { - parser.parse(buffer, xmldoc, optmsk, endch); - } - - xml_parse_result result = make_parse_result( - static_cast(error), - parser.error_offset ? parser.error_offset - buffer : 0); - assert( - result.offset >= 0 && static_cast(result.offset) <= length); - - // update allocator state - *static_cast(xmldoc) = parser.alloc; - - // since we removed last character, we have to handle the only possible false positive - if (result && endch == '<') { - // there's no possible well-formed document with < at the end - return make_parse_result(status_unrecognized_tag, length); - } - - return result; - } -}; - -// Output facilities -xml_encoding get_write_native_encoding() { -#ifdef PUGIXML_WCHAR_MODE - return get_wchar_encoding(); -#else - return encoding_utf8; -#endif -} - -xml_encoding get_write_encoding(xml_encoding encoding) { - // replace wchar encoding with utf implementation - if (encoding == encoding_wchar) - return get_wchar_encoding(); - - // replace utf16 encoding with utf16 with specific endianness - if (encoding == encoding_utf16) - return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - - // replace utf32 encoding with utf32 with specific endianness - if (encoding == encoding_utf32) - return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - - // only do autodetection if no explicit encoding is requested - if (encoding != encoding_auto) - return encoding; - - // assume utf8 encoding - return encoding_utf8; -} - -#ifdef PUGIXML_WCHAR_MODE -size_t get_valid_length(const char_t* data, size_t length) -{ - assert(length > 0); - - // discard last character if it's the lead of a surrogate pair - return (sizeof(wchar_t) == 2 && (unsigned)(static_cast(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length; -} - -size_t convert_buffer(char* result, const char_t* data, size_t length, xml_encoding encoding) -{ - // only endian-swapping is required - if (need_endian_swap_utf(encoding, get_wchar_encoding())) - { - convert_wchar_endian_swap(reinterpret_cast(result), data, length); - - return length * sizeof(char_t); - } - - // convert to utf8 - if (encoding == encoding_utf8) - { - uint8_t* dest = reinterpret_cast(result); - - uint8_t* end = sizeof(wchar_t) == 2 ? - utf_decoder::decode_utf16_block(reinterpret_cast(data), length, dest) : - utf_decoder::decode_utf32_block(reinterpret_cast(data), length, dest); - - return static_cast(end - dest); - } - - // convert to utf16 - if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) - { - uint16_t* dest = reinterpret_cast(result); - - // convert to native utf16 - uint16_t* end = utf_decoder::decode_utf32_block(reinterpret_cast(data), length, dest); - - // swap if necessary - xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - - if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); - - return static_cast(end - dest) * sizeof(uint16_t); - } - - // convert to utf32 - if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) - { - uint32_t* dest = reinterpret_cast(result); - - // convert to native utf32 - uint32_t* end = utf_decoder::decode_utf16_block(reinterpret_cast(data), length, dest); - - // swap if necessary - xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - - if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); - - return static_cast(end - dest) * sizeof(uint32_t); - } - - assert(!"Invalid encoding"); - return 0; -} -#else -size_t get_valid_length(const char_t* data, size_t length) { - assert(length > 4); - - for (size_t i = 1; i <= 4; ++i) { - uint8_t ch = static_cast(data[length - i]); - - // either a standalone character or a leading one - if ((ch & 0xc0) != 0x80) - return length - i; - } - - // there are four non-leading characters at the end, sequence tail is broken so might as well process the whole chunk - return length; -} - -size_t convert_buffer(char* result, const char_t* data, size_t length, - xml_encoding encoding) { - if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) { - uint16_t* dest = reinterpret_cast(result); - - // convert to native utf16 - uint16_t* end = utf_decoder::decode_utf8_block( - reinterpret_cast(data), length, dest); - - // swap if necessary - xml_encoding native_encoding = - is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - - if (native_encoding != encoding) - convert_utf_endian_swap(dest, dest, - static_cast(end - dest)); - - return static_cast(end - dest) * sizeof(uint16_t); - } - - if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) { - uint32_t* dest = reinterpret_cast(result); - - // convert to native utf32 - uint32_t* end = utf_decoder::decode_utf8_block( - reinterpret_cast(data), length, dest); - - // swap if necessary - xml_encoding native_encoding = - is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - - if (native_encoding != encoding) - convert_utf_endian_swap(dest, dest, - static_cast(end - dest)); - - return static_cast(end - dest) * sizeof(uint32_t); - } - - assert(!"Invalid encoding"); - return 0; -} -#endif - -class xml_buffered_writer { - xml_buffered_writer(const xml_buffered_writer&); - xml_buffered_writer& operator=(const xml_buffered_writer&); - -public: - xml_buffered_writer(xml_writer& writer, xml_encoding user_encoding) : - writer(writer), bufsize(0), encoding( - get_write_encoding(user_encoding)) { - } - - ~xml_buffered_writer() { - flush(); - } - - void flush() { - flush(buffer, bufsize); - bufsize = 0; - } - - void flush(const char_t* data, size_t size) { - if (size == 0) - return; - - // fast path, just write data - if (encoding == get_write_native_encoding()) - writer.write(data, size * sizeof(char_t)); - else { - // convert chunk - size_t result = convert_buffer(scratch, data, size, encoding); - assert(result <= sizeof(scratch)); - - // write data - writer.write(scratch, result); - } - } - - void write(const char_t* data, size_t length) { - if (bufsize + length > bufcapacity) { - // flush the remaining buffer contents - flush(); - - // handle large chunks - if (length > bufcapacity) { - if (encoding == get_write_native_encoding()) { - // fast path, can just write data chunk - writer.write(data, length * sizeof(char_t)); - return; - } - - // need to convert in suitable chunks - while (length > bufcapacity) { - // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer - // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary) - size_t chunk_size = get_valid_length(data, bufcapacity); - - // convert chunk and write - flush(data, chunk_size); - - // iterate - data += chunk_size; - length -= chunk_size; - } - - // small tail is copied below - bufsize = 0; - } - } - - memcpy(buffer + bufsize, data, length * sizeof(char_t)); - bufsize += length; - } - - void write(const char_t* data) { - write(data, strlength(data)); - } - - void write(char_t d0) { - if (bufsize + 1 > bufcapacity) - flush(); - - buffer[bufsize + 0] = d0; - bufsize += 1; - } - - void write(char_t d0, char_t d1) { - if (bufsize + 2 > bufcapacity) - flush(); - - buffer[bufsize + 0] = d0; - buffer[bufsize + 1] = d1; - bufsize += 2; - } - - void write(char_t d0, char_t d1, char_t d2) { - if (bufsize + 3 > bufcapacity) - flush(); - - buffer[bufsize + 0] = d0; - buffer[bufsize + 1] = d1; - buffer[bufsize + 2] = d2; - bufsize += 3; - } - - void write(char_t d0, char_t d1, char_t d2, char_t d3) { - if (bufsize + 4 > bufcapacity) - flush(); - - buffer[bufsize + 0] = d0; - buffer[bufsize + 1] = d1; - buffer[bufsize + 2] = d2; - buffer[bufsize + 3] = d3; - bufsize += 4; - } - - void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4) { - if (bufsize + 5 > bufcapacity) - flush(); - - buffer[bufsize + 0] = d0; - buffer[bufsize + 1] = d1; - buffer[bufsize + 2] = d2; - buffer[bufsize + 3] = d3; - buffer[bufsize + 4] = d4; - bufsize += 5; - } - - void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, - char_t d5) { - if (bufsize + 6 > bufcapacity) - flush(); - - buffer[bufsize + 0] = d0; - buffer[bufsize + 1] = d1; - buffer[bufsize + 2] = d2; - buffer[bufsize + 3] = d3; - buffer[bufsize + 4] = d4; - buffer[bufsize + 5] = d5; - bufsize += 6; - } - - // utf8 maximum expansion: x4 (-> utf32) - // utf16 maximum expansion: x2 (-> utf32) - // utf32 maximum expansion: x1 - enum { - bufcapacity = 2048 - }; - - char_t buffer[bufcapacity]; - char scratch[4 * bufcapacity]; - - xml_writer& writer; - size_t bufsize; - xml_encoding encoding; -}; - -void write_bom(xml_writer& writer, xml_encoding encoding) { - switch (encoding) { - case encoding_utf8: - writer.write("\xef\xbb\xbf", 3); - break; - - case encoding_utf16_be: - writer.write("\xfe\xff", 2); - break; - - case encoding_utf16_le: - writer.write("\xff\xfe", 2); - break; - - case encoding_utf32_be: - writer.write("\x00\x00\xfe\xff", 4); - break; - - case encoding_utf32_le: - writer.write("\xff\xfe\x00\x00", 4); - break; - - default: - assert(!"Invalid encoding"); - } -} - -void text_output_escaped(xml_buffered_writer& writer, const char_t* s, - chartypex_t type) { - while (*s) { - const char_t* prev = s; - - // While *s is a usual symbol - while (!IS_CHARTYPEX(*s, type)) - ++s; - - writer.write(prev, static_cast(s - prev)); - - switch (*s) { - case 0: - break; - case '&': - writer.write('&', 'a', 'm', 'p', ';'); - ++s; - break; - case '<': - writer.write('&', 'l', 't', ';'); - ++s; - break; - case '>': - writer.write('&', 'g', 't', ';'); - ++s; - break; - case '"': - writer.write('&', 'q', 'u', 'o', 't', ';'); - ++s; - break; - default: // s is not a usual symbol - { - unsigned int ch = static_cast(*s++); - assert(ch < 32); - - writer.write('&', '#', static_cast((ch / 10) + '0'), - static_cast((ch % 10) + '0'), ';'); - } - } - } -} - -void text_output_cdata(xml_buffered_writer& writer, const char_t* s) { - do { - writer.write('<', '!', '[', 'C', 'D'); - writer.write('A', 'T', 'A', '['); - - const char_t* prev = s; - - // look for ]]> sequence - we can't output it as is since it terminates CDATA - while (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>')) - ++s; - - // skip ]] if we stopped at ]]>, > will go to the next CDATA section - if (*s) - s += 2; - - writer.write(prev, static_cast(s - prev)); - - writer.write(']', ']', '>'); - } while (*s); -} - -void node_output_attributes(xml_buffered_writer& writer, const xml_node& node) { - const char_t* default_name = PUGIXML_TEXT(":anonymous"); - - for (xml_attribute a = node.first_attribute(); a; a = a.next_attribute()) { - writer.write(' '); - writer.write(a.name()[0] ? a.name() : default_name); - writer.write('=', '"'); - - text_output_escaped(writer, a.value(), ctx_special_attr); - - writer.write('"'); - } -} - -void node_output(xml_buffered_writer& writer, const xml_node& node, - const char_t* indent, unsigned int flags, unsigned int depth) { - const char_t* default_name = PUGIXML_TEXT(":anonymous"); - - if ((flags & format_indent) != 0 && (flags & format_raw) == 0) - for (unsigned int i = 0; i < depth; ++i) - writer.write(indent); - - switch (node.type()) { - case node_document: { - for (xml_node n = node.first_child(); n; n = n.next_sibling()) - node_output(writer, n, indent, flags, depth); - break; - } - - case node_element: { - const char_t* name = node.name()[0] ? node.name() : default_name; - - writer.write('<'); - writer.write(name); - - node_output_attributes(writer, node); - - if (flags & format_raw) { - if (!node.first_child()) - writer.write(' ', '/', '>'); - else { - writer.write('>'); - - for (xml_node n = node.first_child(); n; n = n.next_sibling()) - node_output(writer, n, indent, flags, depth + 1); - - writer.write('<', '/'); - writer.write(name); - writer.write('>'); - } - } else if (!node.first_child()) - writer.write(' ', '/', '>', '\n'); - else if (node.first_child() == node.last_child() - && (node.first_child().type() == node_pcdata - || node.first_child().type() == node_cdata)) { - writer.write('>'); - - if (node.first_child().type() == node_pcdata) - text_output_escaped(writer, node.first_child().value(), - ctx_special_pcdata); - else - text_output_cdata(writer, node.first_child().value()); - - writer.write('<', '/'); - writer.write(name); - writer.write('>', '\n'); - } else { - writer.write('>', '\n'); - - for (xml_node n = node.first_child(); n; n = n.next_sibling()) - node_output(writer, n, indent, flags, depth + 1); - - if ((flags & format_indent) != 0 && (flags & format_raw) == 0) - for (unsigned int i = 0; i < depth; ++i) - writer.write(indent); - - writer.write('<', '/'); - writer.write(name); - writer.write('>', '\n'); - } - - break; - } - - case node_pcdata: - text_output_escaped(writer, node.value(), ctx_special_pcdata); - if ((flags & format_raw) == 0) - writer.write('\n'); - break; - - case node_cdata: - text_output_cdata(writer, node.value()); - if ((flags & format_raw) == 0) - writer.write('\n'); - break; - - case node_comment: - writer.write('<', '!', '-', '-'); - writer.write(node.value()); - writer.write('-', '-', '>'); - if ((flags & format_raw) == 0) - writer.write('\n'); - break; - - case node_pi: - case node_declaration: - writer.write('<', '?'); - writer.write(node.name()[0] ? node.name() : default_name); - - if (node.type() == node_declaration) { - node_output_attributes(writer, node); - } else if (node.value()[0]) { - writer.write(' '); - writer.write(node.value()); - } - - writer.write('?', '>'); - if ((flags & format_raw) == 0) - writer.write('\n'); - break; - - case node_doctype: - writer.write('<', '!', 'D', 'O', 'C'); - writer.write('T', 'Y', 'P', 'E'); - - if (node.value()[0]) { - writer.write(' '); - writer.write(node.value()); - } - - writer.write('>'); - if ((flags & format_raw) == 0) - writer.write('\n'); - break; - - default: - assert(!"Invalid node type"); - } -} - -inline bool has_declaration(const xml_node& node) { - for (xml_node child = node.first_child(); child; child = - child.next_sibling()) { - xml_node_type type = child.type(); - - if (type == node_declaration) - return true; - if (type == node_element) - return false; - } - - return false; -} - -inline bool allow_insert_child(xml_node_type parent, xml_node_type child) { - if (parent != node_document && parent != node_element) - return false; - if (child == node_document || child == node_null) - return false; - if (parent != node_document - && (child == node_declaration || child == node_doctype)) - return false; - - return true; -} - -void recursive_copy_skip(xml_node& dest, const xml_node& source, - const xml_node& skip) { - assert(dest.type() == source.type()); - - switch (source.type()) { - case node_element: { - dest.set_name(source.name()); - - for (xml_attribute a = source.first_attribute(); a; a = - a.next_attribute()) - dest.append_attribute(a.name()).set_value(a.value()); - - for (xml_node c = source.first_child(); c; c = c.next_sibling()) { - if (c == skip) - continue; - - xml_node cc = dest.append_child(c.type()); - assert(cc); - - recursive_copy_skip(cc, c, skip); - } - - break; - } - - case node_pcdata: - case node_cdata: - case node_comment: - case node_doctype: - dest.set_value(source.value()); - break; - - case node_pi: - dest.set_name(source.name()); - dest.set_value(source.value()); - break; - - case node_declaration: { - dest.set_name(source.name()); - - for (xml_attribute a = source.first_attribute(); a; a = - a.next_attribute()) - dest.append_attribute(a.name()).set_value(a.value()); - - break; - } - - default: - assert(!"Invalid node type"); - } -} - -// we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick -xml_parse_status get_file_size(FILE* file, size_t& out_result) { -#if defined(_MSC_VER) && _MSC_VER >= 1400 - // there are 64-bit versions of fseek/ftell, let's use them - typedef __int64 length_type; - - _fseeki64(file, 0, SEEK_END); - length_type length = _ftelli64(file); - _fseeki64(file, 0, SEEK_SET); -#elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && !defined(__STRICT_ANSI__) - // there are 64-bit versions of fseek/ftell, let's use them - typedef off64_t length_type; - - fseeko64(file, 0, SEEK_END); - length_type length = ftello64(file); - fseeko64(file, 0, SEEK_SET); -#else - // if this is a 32-bit OS, long is enough; if this is a unix system, long is 64-bit, which is enough; otherwise we can't do anything anyway. - typedef long length_type; - - fseek(file, 0, SEEK_END); - length_type length = ftell(file); - fseek(file, 0, SEEK_SET); -#endif - - // check for I/O errors - if (length < 0) - return status_io_error; - - // check for overflow - size_t result = static_cast(length); - - if (static_cast(result) != length) - return status_out_of_memory; - - // finalize - out_result = result; - - return status_ok; -} - -xml_parse_result load_file_impl(xml_document& doc, FILE* file, - unsigned int options, xml_encoding encoding) { - if (!file) - return make_parse_result(status_file_not_found); - - // get file size (can result in I/O errors) - size_t size = 0; - xml_parse_status size_status = get_file_size(file, size); - - if (size_status != status_ok) { - fclose(file); - return make_parse_result(size_status); - } - - // allocate buffer for the whole file - char* contents = static_cast(global_allocate(size > 0 ? size : 1)); - - if (!contents) { - fclose(file); - return make_parse_result(status_out_of_memory); - } - - // read file in memory - size_t read_size = fread(contents, 1, size, file); - fclose(file); - - if (read_size != size) { - global_deallocate(contents); - return make_parse_result(status_io_error); - } - - return doc.load_buffer_inplace_own(contents, size, options, encoding); -} - -#ifndef PUGIXML_NO_STL -template xml_parse_result load_stream_impl(xml_document& doc, - std::basic_istream& stream, unsigned int options, - xml_encoding encoding) { - // get length of remaining data in stream - typename std::basic_istream::pos_type pos = stream.tellg(); - stream.seekg(0, std::ios::end); - std::streamoff length = stream.tellg() - pos; - stream.seekg(pos); - - if (stream.fail() || pos < 0) - return make_parse_result(status_io_error); - - // guard against huge files - size_t read_length = static_cast(length); - - if (static_cast(read_length) != length || length < 0) - return make_parse_result(status_out_of_memory); - - // read stream data into memory (guard against stream exceptions with buffer holder) - buffer_holder buffer( - global_allocate((read_length > 0 ? read_length : 1) * sizeof(T)), - global_deallocate); - if (!buffer.data) - return make_parse_result(status_out_of_memory); - - stream.read(static_cast(buffer.data), - static_cast(read_length)); - - // read may set failbit | eofbit in case gcount() is less than read_length (i.e. line ending conversion), so check for other I/O errors - if (stream.bad()) - return make_parse_result(status_io_error); - - // load data from buffer - size_t actual_length = static_cast(stream.gcount()); - assert(actual_length <= read_length); - - return doc.load_buffer_inplace_own(buffer.release(), - actual_length * sizeof(T), options, encoding); -} -#endif - -#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) -FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) -{ - return _wfopen(path, mode); -} -#else -char* convert_path_heap(const wchar_t* str) { - assert(str); - - // first pass: get length in utf8 characters - size_t length = wcslen(str); - size_t size = as_utf8_begin(str, length); - - // allocate resulting string - char* result = static_cast(global_allocate(size + 1)); - if (!result) - return 0; - - // second pass: convert to utf8 - as_utf8_end(result, size, str, length); - - return result; -} - -FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) { - // there is no standard function to open wide paths, so our best bet is to try utf8 path - char* path_utf8 = convert_path_heap(path); - if (!path_utf8) - return 0; - - // convert mode to ASCII (we mirror _wfopen interface) - char mode_ascii[4] = { 0 }; - for (size_t i = 0; mode[i]; ++i) - mode_ascii[i] = static_cast(mode[i]); - - // try to open the utf8 path - FILE* result = fopen(path_utf8, mode_ascii); - - // free dummy buffer - global_deallocate(path_utf8); - - return result; -} -#endif -} - -namespace pugi { -xml_writer_file::xml_writer_file(void* file) : - file(file) { -} - -void xml_writer_file::write(const void* data, size_t size) { - fwrite(data, size, 1, static_cast(file)); -} - -#ifndef PUGIXML_NO_STL -xml_writer_stream::xml_writer_stream( - std::basic_ostream >& stream) : - narrow_stream(&stream), wide_stream(0) { -} - -xml_writer_stream::xml_writer_stream( - std::basic_ostream >& stream) : - narrow_stream(0), wide_stream(&stream) { -} - -void xml_writer_stream::write(const void* data, size_t size) { - if (narrow_stream) { - assert(!wide_stream); - narrow_stream->write(reinterpret_cast(data), - static_cast(size)); - } else { - assert(wide_stream); - assert(size % sizeof(wchar_t) == 0); - - wide_stream->write(reinterpret_cast(data), - static_cast(size / sizeof(wchar_t))); - } -} -#endif - -xml_tree_walker::xml_tree_walker() : - _depth(0) { -} - -xml_tree_walker::~xml_tree_walker() { -} - -int xml_tree_walker::depth() const { - return _depth; -} - -bool xml_tree_walker::begin(xml_node&) { - return true; -} - -bool xml_tree_walker::end(xml_node&) { - return true; -} - -xml_attribute::xml_attribute() : - _attr(0) { -} - -xml_attribute::xml_attribute(xml_attribute_struct* attr) : - _attr(attr) { -} - -xml_attribute::operator xml_attribute::unspecified_bool_type() const { - return _attr ? &xml_attribute::_attr : 0; -} - -bool xml_attribute::operator!() const { - return !_attr; -} - -bool xml_attribute::operator==(const xml_attribute& r) const { - return (_attr == r._attr); -} - -bool xml_attribute::operator!=(const xml_attribute& r) const { - return (_attr != r._attr); -} - -bool xml_attribute::operator<(const xml_attribute& r) const { - return (_attr < r._attr); -} - -bool xml_attribute::operator>(const xml_attribute& r) const { - return (_attr > r._attr); -} - -bool xml_attribute::operator<=(const xml_attribute& r) const { - return (_attr <= r._attr); -} - -bool xml_attribute::operator>=(const xml_attribute& r) const { - return (_attr >= r._attr); -} - -xml_attribute xml_attribute::next_attribute() const { - return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute(); -} - -xml_attribute xml_attribute::previous_attribute() const { - return _attr && _attr->prev_attribute_c->next_attribute ? - xml_attribute(_attr->prev_attribute_c) : xml_attribute(); -} - -int xml_attribute::as_int() const { - if (!_attr || !_attr->value) - return 0; - -#ifdef PUGIXML_WCHAR_MODE - return (int)wcstol(_attr->value, 0, 10); -#else - return (int) strtol(_attr->value, 0, 10); -#endif -} - -unsigned int xml_attribute::as_uint() const { - if (!_attr || !_attr->value) - return 0; - -#ifdef PUGIXML_WCHAR_MODE - return (unsigned int)wcstoul(_attr->value, 0, 10); -#else - return (unsigned int) strtoul(_attr->value, 0, 10); -#endif -} - -double xml_attribute::as_double() const { - if (!_attr || !_attr->value) - return 0; - -#ifdef PUGIXML_WCHAR_MODE - return wcstod(_attr->value, 0); -#else - return strtod(_attr->value, 0); -#endif -} - -float xml_attribute::as_float() const { - if (!_attr || !_attr->value) - return 0; - -#ifdef PUGIXML_WCHAR_MODE - return (float)wcstod(_attr->value, 0); -#else - return (float) strtod(_attr->value, 0); -#endif -} - -bool xml_attribute::as_bool() const { - if (!_attr || !_attr->value) - return false; - - // only look at first char - char_t first = *_attr->value; - - // 1*, t* (true), T* (True), y* (yes), Y* (YES) - return (first == '1' || first == 't' || first == 'T' || first == 'y' - || first == 'Y'); -} - -bool xml_attribute::empty() const { - return !_attr; -} - -const char_t* xml_attribute::name() const { - return (_attr && _attr->name) ? _attr->name : PUGIXML_TEXT(""); -} - -const char_t* xml_attribute::value() const { - return (_attr && _attr->value) ? _attr->value : PUGIXML_TEXT(""); -} - -size_t xml_attribute::hash_value() const { - return static_cast(reinterpret_cast(_attr) - / sizeof(xml_attribute_struct)); -} - -xml_attribute_struct* xml_attribute::internal_object() const { - return _attr; -} - -xml_attribute& xml_attribute::operator=(const char_t* rhs) { - set_value(rhs); - return *this; -} - -xml_attribute& xml_attribute::operator=(int rhs) { - set_value(rhs); - return *this; -} - -xml_attribute& xml_attribute::operator=(unsigned int rhs) { - set_value(rhs); - return *this; -} - -xml_attribute& xml_attribute::operator=(double rhs) { - set_value(rhs); - return *this; -} - -xml_attribute& xml_attribute::operator=(bool rhs) { - set_value(rhs); - return *this; -} - -bool xml_attribute::set_name(const char_t* rhs) { - if (!_attr) - return false; - - return strcpy_insitu(_attr->name, _attr->header, - xml_memory_page_name_allocated_mask, rhs); -} - -bool xml_attribute::set_value(const char_t* rhs) { - if (!_attr) - return false; - - return strcpy_insitu(_attr->value, _attr->header, - xml_memory_page_value_allocated_mask, rhs); -} - -bool xml_attribute::set_value(int rhs) { - char buf[128]; - sprintf(buf, "%d", rhs); - -#ifdef PUGIXML_WCHAR_MODE - char_t wbuf[128]; - widen_ascii(wbuf, buf); - - return set_value(wbuf); -#else - return set_value(buf); -#endif -} - -bool xml_attribute::set_value(unsigned int rhs) { - char buf[128]; - sprintf(buf, "%u", rhs); - -#ifdef PUGIXML_WCHAR_MODE - char_t wbuf[128]; - widen_ascii(wbuf, buf); - - return set_value(wbuf); -#else - return set_value(buf); -#endif -} - -bool xml_attribute::set_value(double rhs) { - char buf[128]; - sprintf(buf, "%g", rhs); - -#ifdef PUGIXML_WCHAR_MODE - char_t wbuf[128]; - widen_ascii(wbuf, buf); - - return set_value(wbuf); -#else - return set_value(buf); -#endif -} - -bool xml_attribute::set_value(bool rhs) { - return set_value(rhs ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); -} - -#ifdef __BORLANDC__ -bool operator&&(const xml_attribute& lhs, bool rhs) -{ - return (bool)lhs && rhs; -} - -bool operator||(const xml_attribute& lhs, bool rhs) -{ - return (bool)lhs || rhs; -} -#endif - -xml_node::xml_node() : - _root(0) { -} - -xml_node::xml_node(xml_node_struct* p) : - _root(p) { -} - -xml_node::operator xml_node::unspecified_bool_type() const { - return _root ? &xml_node::_root : 0; -} - -bool xml_node::operator!() const { - return !_root; -} - -xml_node::iterator xml_node::begin() const { - return iterator(_root ? _root->first_child : 0, _root); -} - -xml_node::iterator xml_node::end() const { - return iterator(0, _root); -} - -xml_node::attribute_iterator xml_node::attributes_begin() const { - return attribute_iterator(_root ? _root->first_attribute : 0, _root); -} - -xml_node::attribute_iterator xml_node::attributes_end() const { - return attribute_iterator(0, _root); -} - -bool xml_node::operator==(const xml_node& r) const { - return (_root == r._root); -} - -bool xml_node::operator!=(const xml_node& r) const { - return (_root != r._root); -} - -bool xml_node::operator<(const xml_node& r) const { - return (_root < r._root); -} - -bool xml_node::operator>(const xml_node& r) const { - return (_root > r._root); -} - -bool xml_node::operator<=(const xml_node& r) const { - return (_root <= r._root); -} - -bool xml_node::operator>=(const xml_node& r) const { - return (_root >= r._root); -} - -bool xml_node::empty() const { - return !_root; -} - -const char_t* xml_node::name() const { - return (_root && _root->name) ? _root->name : PUGIXML_TEXT(""); -} - -xml_node_type xml_node::type() const { - return _root ? - static_cast((_root->header - & xml_memory_page_type_mask) + 1) : - node_null; -} - -const char_t* xml_node::value() const { - return (_root && _root->value) ? _root->value : PUGIXML_TEXT(""); -} - -xml_node xml_node::child(const char_t* name) const { - if (!_root) - return xml_node(); - - for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - if (i->name && strequal(name, i->name)) - return xml_node(i); - - return xml_node(); -} - -xml_attribute xml_node::attribute(const char_t* name) const { - if (!_root) - return xml_attribute(); - - for (xml_attribute_struct* i = _root->first_attribute; i; - i = i->next_attribute) - if (i->name && strequal(name, i->name)) - return xml_attribute(i); - - return xml_attribute(); -} - -xml_node xml_node::next_sibling(const char_t* name) const { - if (!_root) - return xml_node(); - - for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) - if (i->name && strequal(name, i->name)) - return xml_node(i); - - return xml_node(); -} - -xml_node xml_node::next_sibling() const { - if (!_root) - return xml_node(); - - if (_root->next_sibling) - return xml_node(_root->next_sibling); - else - return xml_node(); -} - -xml_node xml_node::previous_sibling(const char_t* name) const { - if (!_root) - return xml_node(); - - for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; - i = i->prev_sibling_c) - if (i->name && strequal(name, i->name)) - return xml_node(i); - - return xml_node(); -} - -xml_node xml_node::previous_sibling() const { - if (!_root) - return xml_node(); - - if (_root->prev_sibling_c->next_sibling) - return xml_node(_root->prev_sibling_c); - else - return xml_node(); -} - -xml_node xml_node::parent() const { - return _root ? xml_node(_root->parent) : xml_node(); -} - -xml_node xml_node::root() const { - if (!_root) - return xml_node(); - - xml_memory_page* page = reinterpret_cast(_root->header - & xml_memory_page_pointer_mask); - - return xml_node(static_cast(page->allocator)); -} - -const char_t* xml_node::child_value() const { - if (!_root) - return PUGIXML_TEXT(""); - - for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) { - xml_node_type type = static_cast((i->header - & xml_memory_page_type_mask) + 1); - - if (i->value && (type == node_pcdata || type == node_cdata)) - return i->value; - } - - return PUGIXML_TEXT(""); -} - -const char_t* xml_node::child_value(const char_t* name) const { - return child(name).child_value(); -} - -xml_attribute xml_node::first_attribute() const { - return _root ? xml_attribute(_root->first_attribute) : xml_attribute(); -} - -xml_attribute xml_node::last_attribute() const { - return _root && _root->first_attribute ? - xml_attribute(_root->first_attribute->prev_attribute_c) : - xml_attribute(); -} - -xml_node xml_node::first_child() const { - return _root ? xml_node(_root->first_child) : xml_node(); -} - -xml_node xml_node::last_child() const { - return _root && _root->first_child ? - xml_node(_root->first_child->prev_sibling_c) : xml_node(); -} - -bool xml_node::set_name(const char_t* rhs) { - switch (type()) { - case node_pi: - case node_declaration: - case node_element: - return strcpy_insitu(_root->name, _root->header, - xml_memory_page_name_allocated_mask, rhs); - - default: - return false; - } -} - -bool xml_node::set_value(const char_t* rhs) { - switch (type()) { - case node_pi: - case node_cdata: - case node_pcdata: - case node_comment: - case node_doctype: - return strcpy_insitu(_root->value, _root->header, - xml_memory_page_value_allocated_mask, rhs); - - default: - return false; - } -} - -xml_attribute xml_node::append_attribute(const char_t* name) { - if (type() != node_element && type() != node_declaration) - return xml_attribute(); - - xml_attribute a(append_attribute_ll(_root, get_allocator(_root))); - a.set_name(name); - - return a; -} - -xml_attribute xml_node::prepend_attribute(const char_t* name) { - if (type() != node_element && type() != node_declaration) - return xml_attribute(); - - xml_attribute a(allocate_attribute(get_allocator(_root))); - if (!a) - return xml_attribute(); - - a.set_name(name); - - xml_attribute_struct* head = _root->first_attribute; - - if (head) { - a._attr->prev_attribute_c = head->prev_attribute_c; - head->prev_attribute_c = a._attr; - } else - a._attr->prev_attribute_c = a._attr; - - a._attr->next_attribute = head; - _root->first_attribute = a._attr; - - return a; -} - -xml_attribute xml_node::insert_attribute_before(const char_t* name, - const xml_attribute& attr) { - if ((type() != node_element && type() != node_declaration) || attr.empty()) - return xml_attribute(); - - // check that attribute belongs to *this - xml_attribute_struct* cur = attr._attr; - - while (cur->prev_attribute_c->next_attribute) - cur = cur->prev_attribute_c; - - if (cur != _root->first_attribute) - return xml_attribute(); - - xml_attribute a(allocate_attribute(get_allocator(_root))); - if (!a) - return xml_attribute(); - - a.set_name(name); - - if (attr._attr->prev_attribute_c->next_attribute) - attr._attr->prev_attribute_c->next_attribute = a._attr; - else - _root->first_attribute = a._attr; - - a._attr->prev_attribute_c = attr._attr->prev_attribute_c; - a._attr->next_attribute = attr._attr; - attr._attr->prev_attribute_c = a._attr; - - return a; -} - -xml_attribute xml_node::insert_attribute_after(const char_t* name, - const xml_attribute& attr) { - if ((type() != node_element && type() != node_declaration) || attr.empty()) - return xml_attribute(); - - // check that attribute belongs to *this - xml_attribute_struct* cur = attr._attr; - - while (cur->prev_attribute_c->next_attribute) - cur = cur->prev_attribute_c; - - if (cur != _root->first_attribute) - return xml_attribute(); - - xml_attribute a(allocate_attribute(get_allocator(_root))); - if (!a) - return xml_attribute(); - - a.set_name(name); - - if (attr._attr->next_attribute) - attr._attr->next_attribute->prev_attribute_c = a._attr; - else - _root->first_attribute->prev_attribute_c = a._attr; - - a._attr->next_attribute = attr._attr->next_attribute; - a._attr->prev_attribute_c = attr._attr; - attr._attr->next_attribute = a._attr; - - return a; -} - -xml_attribute xml_node::append_copy(const xml_attribute& proto) { - if (!proto) - return xml_attribute(); - - xml_attribute result = append_attribute(proto.name()); - result.set_value(proto.value()); - - return result; -} - -xml_attribute xml_node::prepend_copy(const xml_attribute& proto) { - if (!proto) - return xml_attribute(); - - xml_attribute result = prepend_attribute(proto.name()); - result.set_value(proto.value()); - - return result; -} - -xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, - const xml_attribute& attr) { - if (!proto) - return xml_attribute(); - - xml_attribute result = insert_attribute_after(proto.name(), attr); - result.set_value(proto.value()); - - return result; -} - -xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, - const xml_attribute& attr) { - if (!proto) - return xml_attribute(); - - xml_attribute result = insert_attribute_before(proto.name(), attr); - result.set_value(proto.value()); - - return result; -} - -xml_node xml_node::append_child(xml_node_type type) { - if (!allow_insert_child(this->type(), type)) - return xml_node(); - - xml_node n(append_node(_root, get_allocator(_root), type)); - - if (type == node_declaration) - n.set_name(PUGIXML_TEXT("xml")); - - return n; -} - -xml_node xml_node::prepend_child(xml_node_type type) { - if (!allow_insert_child(this->type(), type)) - return xml_node(); - - xml_node n(allocate_node(get_allocator(_root), type)); - if (!n) - return xml_node(); - - n._root->parent = _root; - - xml_node_struct* head = _root->first_child; - - if (head) { - n._root->prev_sibling_c = head->prev_sibling_c; - head->prev_sibling_c = n._root; - } else - n._root->prev_sibling_c = n._root; - - n._root->next_sibling = head; - _root->first_child = n._root; - - if (type == node_declaration) - n.set_name(PUGIXML_TEXT("xml")); - - return n; -} - -xml_node xml_node::insert_child_before(xml_node_type type, - const xml_node& node) { - if (!allow_insert_child(this->type(), type)) - return xml_node(); - if (!node._root || node._root->parent != _root) - return xml_node(); - - xml_node n(allocate_node(get_allocator(_root), type)); - if (!n) - return xml_node(); - - n._root->parent = _root; - - if (node._root->prev_sibling_c->next_sibling) - node._root->prev_sibling_c->next_sibling = n._root; - else - _root->first_child = n._root; - - n._root->prev_sibling_c = node._root->prev_sibling_c; - n._root->next_sibling = node._root; - node._root->prev_sibling_c = n._root; - - if (type == node_declaration) - n.set_name(PUGIXML_TEXT("xml")); - - return n; -} - -xml_node xml_node::insert_child_after(xml_node_type type, - const xml_node& node) { - if (!allow_insert_child(this->type(), type)) - return xml_node(); - if (!node._root || node._root->parent != _root) - return xml_node(); - - xml_node n(allocate_node(get_allocator(_root), type)); - if (!n) - return xml_node(); - - n._root->parent = _root; - - if (node._root->next_sibling) - node._root->next_sibling->prev_sibling_c = n._root; - else - _root->first_child->prev_sibling_c = n._root; - - n._root->next_sibling = node._root->next_sibling; - n._root->prev_sibling_c = node._root; - node._root->next_sibling = n._root; - - if (type == node_declaration) - n.set_name(PUGIXML_TEXT("xml")); - - return n; -} - -xml_node xml_node::append_child(const char_t* name) { - xml_node result = append_child(node_element); - - result.set_name(name); - - return result; -} - -xml_node xml_node::prepend_child(const char_t* name) { - xml_node result = prepend_child(node_element); - - result.set_name(name); - - return result; -} - -xml_node xml_node::insert_child_after(const char_t* name, - const xml_node& node) { - xml_node result = insert_child_after(node_element, node); - - result.set_name(name); - - return result; -} - -xml_node xml_node::insert_child_before(const char_t* name, - const xml_node& node) { - xml_node result = insert_child_before(node_element, node); - - result.set_name(name); - - return result; -} - -xml_node xml_node::append_copy(const xml_node& proto) { - xml_node result = append_child(proto.type()); - - if (result) - recursive_copy_skip(result, proto, result); - - return result; -} - -xml_node xml_node::prepend_copy(const xml_node& proto) { - xml_node result = prepend_child(proto.type()); - - if (result) - recursive_copy_skip(result, proto, result); - - return result; -} - -xml_node xml_node::insert_copy_after(const xml_node& proto, - const xml_node& node) { - xml_node result = insert_child_after(proto.type(), node); - - if (result) - recursive_copy_skip(result, proto, result); - - return result; -} - -xml_node xml_node::insert_copy_before(const xml_node& proto, - const xml_node& node) { - xml_node result = insert_child_before(proto.type(), node); - - if (result) - recursive_copy_skip(result, proto, result); - - return result; -} - -bool xml_node::remove_attribute(const char_t* name) { - return remove_attribute(attribute(name)); -} - -bool xml_node::remove_attribute(const xml_attribute& a) { - if (!_root || !a._attr) - return false; - - // check that attribute belongs to *this - xml_attribute_struct* attr = a._attr; - - while (attr->prev_attribute_c->next_attribute) - attr = attr->prev_attribute_c; - - if (attr != _root->first_attribute) - return false; - - if (a._attr->next_attribute) - a._attr->next_attribute->prev_attribute_c = a._attr->prev_attribute_c; - else if (_root->first_attribute) - _root->first_attribute->prev_attribute_c = a._attr->prev_attribute_c; - - if (a._attr->prev_attribute_c->next_attribute) - a._attr->prev_attribute_c->next_attribute = a._attr->next_attribute; - else - _root->first_attribute = a._attr->next_attribute; - - destroy_attribute(a._attr, get_allocator(_root)); - - return true; -} - -bool xml_node::remove_child(const char_t* name) { - return remove_child(child(name)); -} - -bool xml_node::remove_child(const xml_node& n) { - if (!_root || !n._root || n._root->parent != _root) - return false; - - if (n._root->next_sibling) - n._root->next_sibling->prev_sibling_c = n._root->prev_sibling_c; - else if (_root->first_child) - _root->first_child->prev_sibling_c = n._root->prev_sibling_c; - - if (n._root->prev_sibling_c->next_sibling) - n._root->prev_sibling_c->next_sibling = n._root->next_sibling; - else - _root->first_child = n._root->next_sibling; - - destroy_node(n._root, get_allocator(_root)); - - return true; -} - -xml_node xml_node::find_child_by_attribute(const char_t* name, - const char_t* attr_name, const char_t* attr_value) const { - if (!_root) - return xml_node(); - - for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - if (i->name && strequal(name, i->name)) { - for (xml_attribute_struct* a = i->first_attribute; a; - a = a->next_attribute) - if (strequal(attr_name, a->name) - && strequal(attr_value, a->value)) - return xml_node(i); - } - - return xml_node(); -} - -xml_node xml_node::find_child_by_attribute(const char_t* attr_name, - const char_t* attr_value) const { - if (!_root) - return xml_node(); - - for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - for (xml_attribute_struct* a = i->first_attribute; a; - a = a->next_attribute) - if (strequal(attr_name, a->name) && strequal(attr_value, a->value)) - return xml_node(i); - - return xml_node(); -} - -#ifndef PUGIXML_NO_STL -string_t xml_node::path(char_t delimiter) const { - string_t path; - - xml_node cursor = *this; // Make a copy. - - path = cursor.name(); - - while (cursor.parent()) { - cursor = cursor.parent(); - - string_t temp = cursor.name(); - temp += delimiter; - temp += path; - path.swap(temp); - } - - return path; -} -#endif - -xml_node xml_node::first_element_by_path(const char_t* path, - char_t delimiter) const { - xml_node found = *this; // Current search context. - - if (!_root || !path || !path[0]) - return found; - - if (path[0] == delimiter) { - // Absolute path; e.g. '/foo/bar' - found = found.root(); - ++path; - } - - const char_t* path_segment = path; - - while (*path_segment == delimiter) - ++path_segment; - - const char_t* path_segment_end = path_segment; - - while (*path_segment_end && *path_segment_end != delimiter) - ++path_segment_end; - - if (path_segment == path_segment_end) - return found; - - const char_t* next_segment = path_segment_end; - - while (*next_segment == delimiter) - ++next_segment; - - if (*path_segment == '.' && path_segment + 1 == path_segment_end) - return found.first_element_by_path(next_segment, delimiter); - else if (*path_segment == '.' && *(path_segment + 1) == '.' - && path_segment + 2 == path_segment_end) - return found.parent().first_element_by_path(next_segment, delimiter); - else { - for (xml_node_struct* j = found._root->first_child; j; - j = j->next_sibling) { - if (j->name - && strequalrange( - j->name, - path_segment, - static_cast(path_segment_end - path_segment))) { - xml_node subsearch = xml_node(j).first_element_by_path( - next_segment, delimiter); - - if (subsearch) - return subsearch; - } - } - - return xml_node(); - } -} - -bool xml_node::traverse(xml_tree_walker& walker) { - walker._depth = -1; - - xml_node arg_begin = *this; - if (!walker.begin(arg_begin)) - return false; - - xml_node cur = first_child(); - - if (cur) { - ++walker._depth; - - do { - xml_node arg_for_each = cur; - if (!walker.for_each(arg_for_each)) - return false; - - if (cur.first_child()) { - ++walker._depth; - cur = cur.first_child(); - } else if (cur.next_sibling()) - cur = cur.next_sibling(); - else { - // Borland C++ workaround - while (!cur.next_sibling() && cur != *this - && (bool) cur.parent()) { - --walker._depth; - cur = cur.parent(); - } - - if (cur != *this) - cur = cur.next_sibling(); - } - } while (cur && cur != *this); - } - - assert(walker._depth == -1); - - xml_node arg_end = *this; - return walker.end(arg_end); -} - -size_t xml_node::hash_value() const { - return static_cast(reinterpret_cast(_root) - / sizeof(xml_node_struct)); -} - -xml_node_struct* xml_node::internal_object() const { - return _root; -} - -void xml_node::print(xml_writer& writer, const char_t* indent, - unsigned int flags, xml_encoding encoding, unsigned int depth) const { - if (!_root) - return; - - xml_buffered_writer buffered_writer(writer, encoding); - - node_output(buffered_writer, *this, indent, flags, depth); -} - -#ifndef PUGIXML_NO_STL -void xml_node::print(std::basic_ostream >& stream - , const char_t* indent, unsigned int flags, xml_encoding encoding - , unsigned int depth) const { - xml_writer_stream writer(stream); - - print(writer, indent, flags, encoding, depth); -} - -void xml_node::print( - std::basic_ostream >& stream - , const char_t* indent, unsigned int flags, unsigned int depth) const { - xml_writer_stream writer(stream); - - print(writer, indent, flags, encoding_wchar, depth); -} -#endif - -ptrdiff_t xml_node::offset_debug() const { - xml_node_struct* r = root()._root; - - if (!r) - return -1; - - const char_t* buffer = static_cast(r)->buffer; - - if (!buffer) - return -1; - - switch (type()) { - case node_document: - return 0; - - case node_element: - case node_declaration: - case node_pi: - return (_root->header & xml_memory_page_name_allocated_mask) ? - -1 : _root->name - buffer; - - case node_pcdata: - case node_cdata: - case node_comment: - case node_doctype: - return (_root->header & xml_memory_page_value_allocated_mask) ? - -1 : _root->value - buffer; - - default: - return -1; - } -} - -#ifdef __BORLANDC__ -bool operator&&(const xml_node& lhs, bool rhs) -{ - return (bool)lhs && rhs; -} - -bool operator||(const xml_node& lhs, bool rhs) -{ - return (bool)lhs || rhs; -} -#endif - -xml_node_iterator::xml_node_iterator() { -} - -xml_node_iterator::xml_node_iterator(const xml_node& node) : - _wrap(node), _parent(node.parent()) { -} - -xml_node_iterator::xml_node_iterator(xml_node_struct* ref, - xml_node_struct* parent) : - _wrap(ref), _parent(parent) { -} - -bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const { - return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; -} - -bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const { - return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; -} - -xml_node& xml_node_iterator::operator*() { - assert(_wrap._root); - return _wrap; -} - -xml_node* xml_node_iterator::operator->() { - assert(_wrap._root); - return &_wrap; -} - -const xml_node_iterator& xml_node_iterator::operator++() { - assert(_wrap._root); - _wrap._root = _wrap._root->next_sibling; - return *this; -} - -xml_node_iterator xml_node_iterator::operator++(int) { - xml_node_iterator temp = *this; - ++*this; - return temp; -} - -const xml_node_iterator& xml_node_iterator::operator--() { - _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child(); - return *this; -} - -xml_node_iterator xml_node_iterator::operator--(int) { - xml_node_iterator temp = *this; - --*this; - return temp; -} - -xml_attribute_iterator::xml_attribute_iterator() { -} - -xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, - const xml_node& parent) : - _wrap(attr), _parent(parent) { -} - -xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, - xml_node_struct* parent) : - _wrap(ref), _parent(parent) { -} - -bool xml_attribute_iterator::operator==( - const xml_attribute_iterator& rhs) const { - return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root; -} - -bool xml_attribute_iterator::operator!=( - const xml_attribute_iterator& rhs) const { - return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root; -} - -xml_attribute& xml_attribute_iterator::operator*() { - assert(_wrap._attr); - return _wrap; -} - -xml_attribute* xml_attribute_iterator::operator->() { - assert(_wrap._attr); - return &_wrap; -} - -const xml_attribute_iterator& xml_attribute_iterator::operator++() { - assert(_wrap._attr); - _wrap._attr = _wrap._attr->next_attribute; - return *this; -} - -xml_attribute_iterator xml_attribute_iterator::operator++(int) { - xml_attribute_iterator temp = *this; - ++*this; - return temp; -} - -const xml_attribute_iterator& xml_attribute_iterator::operator--() { - _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute(); - return *this; -} - -xml_attribute_iterator xml_attribute_iterator::operator--(int) { - xml_attribute_iterator temp = *this; - --*this; - return temp; -} - -xml_parse_result::xml_parse_result() : - status(status_internal_error), offset(0), encoding(encoding_auto) { -} - -xml_parse_result::operator bool() const { - return status == status_ok; -} - -const char* xml_parse_result::description() const { - switch (status) { - case status_ok: - return "No error"; - - case status_file_not_found: - return "File was not found"; - case status_io_error: - return "Error reading from file/stream"; - case status_out_of_memory: - return "Could not allocate memory"; - case status_internal_error: - return "Internal error occurred"; - - case status_unrecognized_tag: - return "Could not determine tag type"; - - case status_bad_pi: - return "Error parsing document declaration/processing instruction"; - case status_bad_comment: - return "Error parsing comment"; - case status_bad_cdata: - return "Error parsing CDATA section"; - case status_bad_doctype: - return "Error parsing document type declaration"; - case status_bad_pcdata: - return "Error parsing PCDATA section"; - case status_bad_start_element: - return "Error parsing start element tag"; - case status_bad_attribute: - return "Error parsing element attribute"; - case status_bad_end_element: - return "Error parsing end element tag"; - case status_end_element_mismatch: - return "Start-end tags mismatch"; - - default: - return "Unknown error"; - } -} - -xml_document::xml_document() : - _buffer(0) { - create(); -} - -xml_document::~xml_document() { - destroy(); -} - -void xml_document::reset() { - destroy(); - create(); -} - -void xml_document::reset(const xml_document& proto) { - reset(); - - for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling()) - append_copy(cur); -} - -void xml_document::create() { - // initialize sentinel page - STATIC_ASSERT( - offsetof(xml_memory_page, data) + sizeof(xml_document_struct) + xml_memory_page_alignment <= sizeof(_memory)); - - // align upwards to page boundary - void* page_memory = - reinterpret_cast((reinterpret_cast(_memory) - + (xml_memory_page_alignment - 1)) - & ~(xml_memory_page_alignment - 1)); - - // prepare page structure - xml_memory_page* page = xml_memory_page::construct(page_memory); - - page->busy_size = xml_memory_page_size; - - // allocate new root - _root = new (page->data) xml_document_struct(page); - _root->prev_sibling_c = _root; - - // setup sentinel page - page->allocator = static_cast(_root); -} - -void xml_document::destroy() { - // destroy static storage - if (_buffer) { - global_deallocate(_buffer); - _buffer = 0; - } - - // destroy dynamic storage, leave sentinel page (it's in static memory) - if (_root) { - xml_memory_page* root_page = - reinterpret_cast(_root->header - & xml_memory_page_pointer_mask); - assert(root_page && !root_page->prev && !root_page->memory); - - // destroy all pages - for (xml_memory_page* page = root_page->next; page;) { - xml_memory_page* next = page->next; - - xml_allocator::deallocate_page(page); - - page = next; - } - - // cleanup root page - root_page->allocator = 0; - root_page->next = 0; - root_page->busy_size = root_page->freed_size = 0; - - _root = 0; - } -} - -#ifndef PUGIXML_NO_STL -xml_parse_result xml_document::load( - std::basic_istream >& stream - , unsigned int options, xml_encoding encoding) { - reset(); - - return load_stream_impl(*this, stream, options, encoding); -} - -xml_parse_result xml_document::load( - std::basic_istream >& stream - , unsigned int options) { - reset(); - - return load_stream_impl(*this, stream, options, encoding_wchar); -} -#endif - -xml_parse_result xml_document::load(const char_t* contents, - unsigned int options) { - // Force native encoding (skip autodetection) -#ifdef PUGIXML_WCHAR_MODE - xml_encoding encoding = encoding_wchar; -#else - xml_encoding encoding = encoding_utf8; -#endif - - return load_buffer(contents, strlength(contents) * sizeof(char_t), options, - encoding); -} - -xml_parse_result xml_document::load_file(const char* path, unsigned int options, - xml_encoding encoding) { - reset(); - - FILE* file = fopen(path, "rb"); - - return load_file_impl(*this, file, options, encoding); -} - -xml_parse_result xml_document::load_file(const wchar_t* path, - unsigned int options, xml_encoding encoding) { - reset(); - - FILE* file = open_file_wide(path, L"rb"); - - return load_file_impl(*this, file, options, encoding); -} - -xml_parse_result xml_document::load_buffer_impl(void* contents, size_t size, - unsigned int options, xml_encoding encoding, bool is_mutable, - bool own) { - reset(); - - // check input buffer - assert(contents || size == 0); - - // get actual encoding - xml_encoding buffer_encoding = get_buffer_encoding(encoding, contents, - size); - - // get private buffer - char_t* buffer = 0; - size_t length = 0; - - if (!convert_buffer(buffer, length, buffer_encoding, contents, size, - is_mutable)) - return make_parse_result(status_out_of_memory); - - // delete original buffer if we performed a conversion - if (own && buffer != contents && contents) - global_deallocate(contents); - - // parse - xml_parse_result res = xml_parser::parse(buffer, length, _root, options); - - // remember encoding - res.encoding = buffer_encoding; - - // grab onto buffer if it's our buffer, user is responsible for deallocating contens himself - if (own || buffer != contents) - _buffer = buffer; - - return res; -} - -xml_parse_result xml_document::load_buffer(const void* contents, size_t size, - unsigned int options, xml_encoding encoding) { - return load_buffer_impl(const_cast(contents), size, options, - encoding, false, false); -} - -xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, - unsigned int options, xml_encoding encoding) { - return load_buffer_impl(contents, size, options, encoding, true, false); -} - -xml_parse_result xml_document::load_buffer_inplace_own(void* contents, - size_t size, unsigned int options, xml_encoding encoding) { - return load_buffer_impl(contents, size, options, encoding, true, true); -} - -void xml_document::save(xml_writer& writer, const char_t* indent, - unsigned int flags, xml_encoding encoding) const { - if (flags & format_write_bom) - write_bom(writer, get_write_encoding(encoding)); - - xml_buffered_writer buffered_writer(writer, encoding); - - if (!(flags & format_no_declaration) && !has_declaration(*this)) { - buffered_writer.write(PUGIXML_TEXT("")); - if (!(flags & format_raw)) - buffered_writer.write('\n'); - } - - node_output(buffered_writer, *this, indent, flags, 0); -} - -#ifndef PUGIXML_NO_STL -void xml_document::save( - std::basic_ostream >& stream - , const char_t* indent, unsigned int flags - , xml_encoding encoding) const { - xml_writer_stream writer(stream); - - save(writer, indent, flags, encoding); -} - -void xml_document::save( - std::basic_ostream >& stream - , const char_t* indent, unsigned int flags) const { - xml_writer_stream writer(stream); - - save(writer, indent, flags, encoding_wchar); -} -#endif - -bool xml_document::save_file(const char* path, const char_t* indent, - unsigned int flags, xml_encoding encoding) const { - FILE* file = fopen(path, "wb"); - if (!file) - return false; - - xml_writer_file writer(file); - save(writer, indent, flags, encoding); - - fclose(file); - - return true; -} - -bool xml_document::save_file(const wchar_t* path, const char_t* indent, - unsigned int flags, xml_encoding encoding) const { - FILE* file = open_file_wide(path, L"wb"); - if (!file) - return false; - - xml_writer_file writer(file); - save(writer, indent, flags, encoding); - - fclose(file); - - return true; -} - -xml_node xml_document::document_element() const { - for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - if ((i->header & xml_memory_page_type_mask) + 1 == node_element) - return xml_node(i); - - return xml_node(); -} - -#ifndef PUGIXML_NO_STL -std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str) { - assert(str); - - return as_utf8_impl(str, wcslen(str)); -} - -std::string PUGIXML_FUNCTION as_utf8(const std::wstring& str) { - return as_utf8_impl(str.c_str(), str.size()); -} - -std::wstring PUGIXML_FUNCTION as_wide(const char* str) { - assert(str); - - return as_wide_impl(str, strlen(str)); -} - -std::wstring PUGIXML_FUNCTION as_wide(const std::string& str) { - return as_wide_impl(str.c_str(), str.size()); -} -#endif - -void PUGIXML_FUNCTION set_memory_management_functions( - allocation_function allocate, deallocation_function deallocate) { - global_allocate = allocate; - global_deallocate = deallocate; -} - -allocation_function PUGIXML_FUNCTION get_memory_allocation_function() { - return global_allocate; -} - -deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function() { - return global_deallocate; -} -} - -#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) -namespace std -{ - // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) - std::bidirectional_iterator_tag _Iter_cat(const xml_node_iterator&) - { - return std::bidirectional_iterator_tag(); - } - - std::bidirectional_iterator_tag _Iter_cat(const xml_attribute_iterator&) - { - return std::bidirectional_iterator_tag(); - } -} -#endif - -#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) -namespace std -{ - // Workarounds for (non-standard) iterator category detection - std::bidirectional_iterator_tag __iterator_category(const xml_node_iterator&) - { - return std::bidirectional_iterator_tag(); - } - - std::bidirectional_iterator_tag __iterator_category(const xml_attribute_iterator&) - { - return std::bidirectional_iterator_tag(); - } -} -#endif - -#ifndef PUGIXML_NO_XPATH - -// STL replacements -namespace { -struct equal_to { - template bool operator()(const T& lhs, const T& rhs) const { - return lhs == rhs; - } -}; - -struct not_equal_to { - template bool operator()(const T& lhs, const T& rhs) const { - return lhs != rhs; - } -}; - -struct less { - template bool operator()(const T& lhs, const T& rhs) const { - return lhs < rhs; - } -}; - -struct less_equal { - template bool operator()(const T& lhs, const T& rhs) const { - return lhs <= rhs; - } -}; - -template void swap(T& lhs, T& rhs) { - T temp = lhs; - lhs = rhs; - rhs = temp; -} - -template I min_element(I begin, I end, - const Pred& pred) { - I result = begin; - - for (I it = begin + 1; it != end; ++it) - if (pred(*it, *result)) - result = it; - - return result; -} - -template void reverse(I begin, I end) { - while (begin + 1 < end) - swap(*begin++, *--end); -} - -template I unique(I begin, I end) { - // fast skip head - while (begin + 1 < end && *begin != *(begin + 1)) - begin++; - - if (begin == end) - return begin; - - // last written element - I write = begin++; - - // merge unique elements - while (begin != end) { - if (*begin != *write) - *++write = *begin++; - else - begin++; - } - - // past-the-end (write points to live element) - return write + 1; -} - -template void copy_backwards(I begin, I end, I target) { - while (begin != end) - *--target = *--end; -} - -template void insertion_sort(I begin, - I end, const Pred& pred, T*) { - assert(begin != end); - - for (I it = begin + 1; it != end; ++it) { - T val = *it; - - if (pred(val, *begin)) { - // move to front - copy_backwards(begin, it, it + 1); - *begin = val; - } else { - I hole = it; - - // move hole backwards - while (pred(val, *(hole - 1))) { - *hole = *(hole - 1); - hole--; - } - - // fill hole with element - *hole = val; - } - } -} - -// std variant for elements with == -template void partition(I begin, I middle, I end, - const Pred& pred, I* out_eqbeg, I* out_eqend) { - I eqbeg = middle, eqend = middle + 1; - - // expand equal range - while (eqbeg != begin && *(eqbeg - 1) == *eqbeg) - --eqbeg; - while (eqend != end && *eqend == *eqbeg) - ++eqend; - - // process outer elements - I ltend = eqbeg, gtbeg = eqend; - - for (;;) { - // find the element from the right side that belongs to the left one - for (; gtbeg != end; ++gtbeg) - if (!pred(*eqbeg, *gtbeg)) { - if (*gtbeg == *eqbeg) - swap(*gtbeg, *eqend++); - else - break; - } - - // find the element from the left side that belongs to the right one - for (; ltend != begin; --ltend) - if (!pred(*(ltend - 1), *eqbeg)) { - if (*eqbeg == *(ltend - 1)) - swap(*(ltend - 1), *--eqbeg); - else - break; - } - - // scanned all elements - if (gtbeg == end && ltend == begin) { - *out_eqbeg = eqbeg; - *out_eqend = eqend; - return; - } - - // make room for elements by moving equal area - if (gtbeg == end) { - if (--ltend != --eqbeg) - swap(*ltend, *eqbeg); - swap(*eqbeg, *--eqend); - } else if (ltend == begin) { - if (eqend != gtbeg) - swap(*eqbeg, *eqend); - ++eqend; - swap(*gtbeg++, *eqbeg++); - } else - swap(*gtbeg++, *--ltend); - } -} - -template void median3(I first, I middle, I last, - const Pred& pred) { - if (pred(*middle, *first)) - swap(*middle, *first); - if (pred(*last, *middle)) - swap(*last, *middle); - if (pred(*middle, *first)) - swap(*middle, *first); -} - -template void median(I first, I middle, I last, - const Pred& pred) { - if (last - first <= 40) { - // median of three for small chunks - median3(first, middle, last, pred); - } else { - // median of nine - size_t step = (last - first + 1) / 8; - - median3(first, first + step, first + 2 * step, pred); - median3(middle - step, middle, middle + step, pred); - median3(last - 2 * step, last - step, last, pred); - median3(first + step, middle, last - step, pred); - } -} - -template void sort(I begin, I end, - const Pred& pred) { - // sort large chunks - while (end - begin > 32) { - // find median element - I middle = begin + (end - begin) / 2; - median(begin, middle, end - 1, pred); - - // partition in three chunks (< = >) - I eqbeg, eqend; - partition(begin, middle, end, pred, &eqbeg, &eqend); - - // loop on larger half - if (eqbeg - begin > end - eqend) { - sort(eqend, end, pred); - end = eqbeg; - } else { - sort(begin, eqbeg, pred); - begin = eqend; - } - } - - // insertion sort small chunk - if (begin != end) - insertion_sort(begin, end, pred, &*begin); -} -} - -// Allocator used for AST and evaluation stacks -namespace { -struct xpath_memory_block { - xpath_memory_block* next; - - char data[4096]; -}; - -class xpath_allocator { - xpath_memory_block* _root; - size_t _root_size; - -public: -#ifdef PUGIXML_NO_EXCEPTIONS - jmp_buf* error_handler; -#endif - - xpath_allocator(xpath_memory_block* root, size_t root_size = 0) : - _root(root), _root_size(root_size) { -#ifdef PUGIXML_NO_EXCEPTIONS - error_handler = 0; -#endif - } - - void* allocate_nothrow(size_t size) { - const size_t block_capacity = sizeof(_root->data); - - // align size so that we're able to store pointers in subsequent blocks - size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); - - if (_root_size + size <= block_capacity) { - void* buf = _root->data + _root_size; - _root_size += size; - return buf; - } else { - size_t block_data_size = - (size > block_capacity) ? size : block_capacity; - size_t block_size = block_data_size - + offsetof(xpath_memory_block, data); - - xpath_memory_block* block = - static_cast(global_allocate(block_size)); - if (!block) - return 0; - - block->next = _root; - - _root = block; - _root_size = size; - - return block->data; - } - } - - void* allocate(size_t size) { - void* result = allocate_nothrow(size); - - if (!result) { -#ifdef PUGIXML_NO_EXCEPTIONS - assert(error_handler); - longjmp(*error_handler, 1); -#else - throw std::bad_alloc(); -#endif - } - - return result; - } - - void* reallocate(void* ptr, size_t old_size, size_t new_size) { - // align size so that we're able to store pointers in subsequent blocks - old_size = (old_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); - new_size = (new_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); - - // we can only reallocate the last object - assert( - ptr == 0 || static_cast(ptr) + old_size == _root->data + _root_size); - - // adjust root size so that we have not allocated the object at all - bool only_object = (_root_size == old_size); - - if (ptr) - _root_size -= old_size; - - // allocate a new version (this will obviously reuse the memory if possible) - void* result = allocate(new_size); - assert(result); - - // we have a new block - if (result != ptr && ptr) { - // copy old data - assert(new_size > old_size); - memcpy(result, ptr, old_size); - - // free the previous page if it had no other objects - if (only_object) { - assert(_root->data == result); - assert(_root->next); - - xpath_memory_block* next = _root->next->next; - - if (next) { - // deallocate the whole page, unless it was the first one - global_deallocate(_root->next); - _root->next = next; - } - } - } - - return result; - } - - void revert(const xpath_allocator& state) { - // free all new pages - xpath_memory_block* cur = _root; - - while (cur != state._root) { - xpath_memory_block* next = cur->next; - - global_deallocate(cur); - - cur = next; - } - - // restore state - _root = state._root; - _root_size = state._root_size; - } - - void release() { - xpath_memory_block* cur = _root; - assert(cur); - - while (cur->next) { - xpath_memory_block* next = cur->next; - - global_deallocate(cur); - - cur = next; - } - } -}; - -struct xpath_allocator_capture { - xpath_allocator_capture(xpath_allocator* alloc) : - _target(alloc), _state(*alloc) { - } - - ~xpath_allocator_capture() { - _target->revert(_state); - } - - xpath_allocator* _target; - xpath_allocator _state; -}; - -struct xpath_stack { - xpath_allocator* result; - xpath_allocator* temp; -}; - -struct xpath_stack_data { - xpath_memory_block blocks[2]; - xpath_allocator result; - xpath_allocator temp; - xpath_stack stack; - -#ifdef PUGIXML_NO_EXCEPTIONS - jmp_buf error_handler; -#endif - - xpath_stack_data() : - result(blocks + 0), temp(blocks + 1) { - blocks[0].next = blocks[1].next = 0; - - stack.result = &result; - stack.temp = &temp; - -#ifdef PUGIXML_NO_EXCEPTIONS - result.error_handler = temp.error_handler = &error_handler; -#endif - } - - ~xpath_stack_data() { - result.release(); - temp.release(); - } -}; -} - -// String class -namespace { -class xpath_string { - const char_t* _buffer; - bool _uses_heap; - - static char_t* duplicate_string(const char_t* string, size_t length, - xpath_allocator* alloc) { - char_t* result = static_cast(alloc->allocate( - (length + 1) * sizeof(char_t))); - assert(result); - - memcpy(result, string, length * sizeof(char_t)); - result[length] = 0; - - return result; - } - - static char_t* duplicate_string(const char_t* string, - xpath_allocator* alloc) { - return duplicate_string(string, strlength(string), alloc); - } - -public: - xpath_string() : - _buffer(PUGIXML_TEXT("")), _uses_heap(false) { - } - - explicit xpath_string(const char_t* str, xpath_allocator* alloc) { - bool empty = (*str == 0); - - _buffer = empty ? PUGIXML_TEXT("") : duplicate_string(str, alloc); - _uses_heap = !empty; - } - - explicit xpath_string(const char_t* str, bool use_heap) : - _buffer(str), _uses_heap(use_heap) { - } - - xpath_string(const char_t* begin, const char_t* end, - xpath_allocator* alloc) { - assert(begin <= end); - - bool empty = (begin == end); - - _buffer = - empty ? PUGIXML_TEXT("") : duplicate_string(begin, - static_cast(end - begin), alloc); - _uses_heap = !empty; - } - - void append(const xpath_string& o, xpath_allocator* alloc) { - // skip empty sources - if (!*o._buffer) - return; - - // fast append for constant empty target and constant source - if (!*_buffer && !_uses_heap && !o._uses_heap) { - _buffer = o._buffer; - } else { - // need to make heap copy - size_t target_length = strlength(_buffer); - size_t source_length = strlength(o._buffer); - size_t length = target_length + source_length; - - // allocate new buffer - char_t* result = static_cast(alloc->reallocate( - _uses_heap ? const_cast(_buffer) : 0, - (target_length + 1) * sizeof(char_t), - (length + 1) * sizeof(char_t))); - assert(result); - - // append first string to the new buffer in case there was no reallocation - if (!_uses_heap) - memcpy(result, _buffer, target_length * sizeof(char_t)); - - // append second string to the new buffer - memcpy(result + target_length, o._buffer, - source_length * sizeof(char_t)); - result[length] = 0; - - // finalize - _buffer = result; - _uses_heap = true; - } - } - - const char_t* c_str() const { - return _buffer; - } - - size_t length() const { - return strlength(_buffer); - } - - char_t* data(xpath_allocator* alloc) { - // make private heap copy - if (!_uses_heap) { - _buffer = duplicate_string(_buffer, alloc); - _uses_heap = true; - } - - return const_cast(_buffer); - } - - bool empty() const { - return *_buffer == 0; - } - - bool operator==(const xpath_string& o) const { - return strequal(_buffer, o._buffer); - } - - bool operator!=(const xpath_string& o) const { - return !strequal(_buffer, o._buffer); - } - - bool uses_heap() const { - return _uses_heap; - } -}; - -xpath_string xpath_string_const(const char_t* str) { - return xpath_string(str, false); -} -} - -namespace { -bool starts_with(const char_t* string, const char_t* pattern) { - while (*pattern && *string == *pattern) { - string++; - pattern++; - } - - return *pattern == 0; -} - -const char_t* find_char(const char_t* s, char_t c) { -#ifdef PUGIXML_WCHAR_MODE - return wcschr(s, c); -#else - return strchr(s, c); -#endif -} - -const char_t* find_substring(const char_t* s, const char_t* p) { -#ifdef PUGIXML_WCHAR_MODE - // MSVC6 wcsstr bug workaround (if s is empty it always returns 0) - return (*p == 0) ? s : wcsstr(s, p); -#else - return strstr(s, p); -#endif -} - -// Converts symbol to lower case, if it is an ASCII one -char_t tolower_ascii(char_t ch) { - return static_cast(ch - 'A') < 26 ? - static_cast(ch | ' ') : ch; -} - -xpath_string string_value(const xpath_node& na, xpath_allocator* alloc) { - if (na.attribute()) - return xpath_string_const(na.attribute().value()); - else { - const xml_node& n = na.node(); - - switch (n.type()) { - case node_pcdata: - case node_cdata: - case node_comment: - case node_pi: - return xpath_string_const(n.value()); - - case node_document: - case node_element: { - xpath_string result; - - xml_node cur = n.first_child(); - - while (cur && cur != n) { - if (cur.type() == node_pcdata || cur.type() == node_cdata) - result.append(xpath_string_const(cur.value()), alloc); - - if (cur.first_child()) - cur = cur.first_child(); - else if (cur.next_sibling()) - cur = cur.next_sibling(); - else { - while (!cur.next_sibling() && cur != n) - cur = cur.parent(); - - if (cur != n) - cur = cur.next_sibling(); - } - } - - return result; - } - - default: - return xpath_string(); - } - } -} - -unsigned int node_height(xml_node n) { - unsigned int result = 0; - - while (n) { - ++result; - n = n.parent(); - } - - return result; -} - -bool node_is_before(xml_node ln, unsigned int lh, xml_node rn, - unsigned int rh) { - // normalize heights - for (unsigned int i = rh; i < lh; i++) - ln = ln.parent(); - for (unsigned int j = lh; j < rh; j++) - rn = rn.parent(); - - // one node is the ancestor of the other - if (ln == rn) - return lh < rh; - - // find common ancestor - while (ln.parent() != rn.parent()) { - ln = ln.parent(); - rn = rn.parent(); - } - - // there is no common ancestor (the shared parent is null), nodes are from different documents - if (!ln.parent()) - return ln < rn; - - // determine sibling order - for (; ln; ln = ln.next_sibling()) - if (ln == rn) - return true; - - return false; -} - -bool node_is_ancestor(xml_node parent, xml_node node) { - while (node && node != parent) - node = node.parent(); - - return parent && node == parent; -} - -const void* document_order(const xpath_node& xnode) { - xml_node_struct* node = xnode.node().internal_object(); - - if (node) { - if (node->name - && (node->header & xml_memory_page_name_allocated_mask) == 0) - return node->name; - if (node->value - && (node->header & xml_memory_page_value_allocated_mask) == 0) - return node->value; - return 0; - } - - xml_attribute_struct* attr = xnode.attribute().internal_object(); - - if (attr) { - if ((attr->header & xml_memory_page_name_allocated_mask) == 0) - return attr->name; - if ((attr->header & xml_memory_page_value_allocated_mask) == 0) - return attr->value; - return 0; - } - - return 0; -} - -struct document_order_comparator { - bool operator()(const xpath_node& lhs, const xpath_node& rhs) const { - // optimized document order based check - const void* lo = document_order(lhs); - const void* ro = document_order(rhs); - - if (lo && ro) - return lo < ro; - - // slow comparison - xml_node ln = lhs.node(), rn = rhs.node(); - - // compare attributes - if (lhs.attribute() && rhs.attribute()) { - // shared parent - if (lhs.parent() == rhs.parent()) { - // determine sibling order - for (xml_attribute a = lhs.attribute(); a; a = - a.next_attribute()) - if (a == rhs.attribute()) - return true; - - return false; - } - - // compare attribute parents - ln = lhs.parent(); - rn = rhs.parent(); - } else if (lhs.attribute()) { - // attributes go after the parent element - if (lhs.parent() == rhs.node()) - return false; - - ln = lhs.parent(); - } else if (rhs.attribute()) { - // attributes go after the parent element - if (rhs.parent() == lhs.node()) - return true; - - rn = rhs.parent(); - } - - if (ln == rn) - return false; - - unsigned int lh = node_height(ln); - unsigned int rh = node_height(rn); - - return node_is_before(ln, lh, rn, rh); - } -}; - -struct duplicate_comparator { - bool operator()(const xpath_node& lhs, const xpath_node& rhs) const { - if (lhs.attribute()) - return rhs.attribute() ? lhs.attribute() < rhs.attribute() : true; - else - return rhs.attribute() ? false : lhs.node() < rhs.node(); - } -}; - -double gen_nan() { -#if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24)) - union { - float f; - int32_t i; - } u[sizeof(float) == sizeof(int32_t) ? 1 : -1]; - u[0].i = 0x7fc00000; - return u[0].f; -#else - // fallback - const volatile double zero = 0.0; - return zero / zero; -#endif -} - -bool is_nan(double value) { -#if defined(_MSC_VER) || defined(__BORLANDC__) - return !!_isnan(value); -#elif defined(fpclassify) && defined(FP_NAN) - return fpclassify(value) == FP_NAN; -#else - // fallback - const volatile double v = value; - return v != v; -#endif -} - -const char_t* convert_number_to_string_special(double value) { -#if defined(_MSC_VER) || defined(__BORLANDC__) - if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0; - if (_isnan(value)) return PUGIXML_TEXT("NaN"); - return PUGIXML_TEXT("-Infinity") + (value > 0); -#elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO) - switch(fpclassify(value)) - { - case FP_NAN: - return PUGIXML_TEXT("NaN"); - - case FP_INFINITE: - return PUGIXML_TEXT("-Infinity") + (value > 0); - - case FP_ZERO: - return PUGIXML_TEXT("0"); - - default: - return 0; - } -#else - // fallback - const volatile double v = value; - - if (v == 0) return PUGIXML_TEXT("0"); - if (v != v) return PUGIXML_TEXT("NaN"); - if (v * 2 == v) return PUGIXML_TEXT("-Infinity") + (value > 0); - return 0; -#endif -} - -bool convert_number_to_boolean(double value) { - return (value != 0 && !is_nan(value)); -} - -void truncate_zeros(char* begin, char* end) { - while (begin != end && end[-1] == '0') - end--; - - *end = 0; -} - -// gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent -#if defined(_MSC_VER) && _MSC_VER >= 1400 -void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) -{ - // get base values - int sign, exponent; - _ecvt_s(buffer, buffer_size, value, DBL_DIG + 1, &exponent, &sign); - - // truncate redundant zeros - truncate_zeros(buffer, buffer + strlen(buffer)); - - // fill results - *out_mantissa = buffer; - *out_exponent = exponent; -} -#else -void convert_number_to_mantissa_exponent(double value, char* buffer, - size_t buffer_size, char** out_mantissa, int* out_exponent) { - // get a scientific notation value with IEEE DBL_DIG decimals - sprintf(buffer, "%.*e", DBL_DIG, value); - assert(strlen(buffer) < buffer_size); - (void) !buffer_size; - - // get the exponent (possibly negative) - char* exponent_string = strchr(buffer, 'e'); - assert(exponent_string); - - int exponent = atoi(exponent_string + 1); - - // extract mantissa string: skip sign - char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer; - assert(mantissa[0] != '0' && mantissa[1] == '.'); - - // divide mantissa by 10 to eliminate integer part - mantissa[1] = mantissa[0]; - mantissa++; - exponent++; - - // remove extra mantissa digits and zero-terminate mantissa - truncate_zeros(mantissa, exponent_string); - - // fill results - *out_mantissa = mantissa; - *out_exponent = exponent; -} -#endif - -xpath_string convert_number_to_string(double value, xpath_allocator* alloc) { - // try special number conversion - const char_t* special = convert_number_to_string_special(value); - if (special) - return xpath_string_const(special); - - // get mantissa + exponent form - char mantissa_buffer[64]; - - char* mantissa; - int exponent; - convert_number_to_mantissa_exponent(value, mantissa_buffer, - sizeof(mantissa_buffer), &mantissa, &exponent); - - // make the number! - char_t result[512]; - char_t* s = result; - - // sign - if (value < 0) - *s++ = '-'; - - // integer part - if (exponent <= 0) { - *s++ = '0'; - } else { - while (exponent > 0) { - assert(*mantissa == 0 || (unsigned)(*mantissa - '0') <= 9); - *s++ = *mantissa ? *mantissa++ : '0'; - exponent--; - } - } - - // fractional part - if (*mantissa) { - // decimal point - *s++ = '.'; - - // extra zeroes from negative exponent - while (exponent < 0) { - *s++ = '0'; - exponent++; - } - - // extra mantissa digits - while (*mantissa) { - assert((unsigned)(*mantissa - '0') <= 9); - *s++ = *mantissa++; - } - } - - // zero-terminate - assert(s < result + sizeof(result) / sizeof(result[0])); - *s = 0; - - return xpath_string(result, alloc); -} - -bool check_string_to_number_format(const char_t* string) { - // parse leading whitespace - while (IS_CHARTYPE(*string, ct_space)) - ++string; - - // parse sign - if (*string == '-') - ++string; - - if (!*string) - return false; - - // if there is no integer part, there should be a decimal part with at least one digit - if (!IS_CHARTYPEX(string[0], ctx_digit) - && (string[0] != '.' || !IS_CHARTYPEX(string[1], ctx_digit))) - return false; - - // parse integer part - while (IS_CHARTYPEX(*string, ctx_digit)) - ++string; - - // parse decimal part - if (*string == '.') { - ++string; - - while (IS_CHARTYPEX(*string, ctx_digit)) - ++string; - } - - // parse trailing whitespace - while (IS_CHARTYPE(*string, ct_space)) - ++string; - - return *string == 0; -} - -double convert_string_to_number(const char_t* string) { - // check string format - if (!check_string_to_number_format(string)) - return gen_nan(); - - // parse string -#ifdef PUGIXML_WCHAR_MODE - return wcstod(string, 0); -#else - return atof(string); -#endif -} - -bool convert_string_to_number(const char_t* begin, const char_t* end, - double* out_result) { - char_t buffer[32]; - - size_t length = static_cast(end - begin); - char_t* scratch = buffer; - - if (length >= sizeof(buffer) / sizeof(buffer[0])) { - // need to make dummy on-heap copy - scratch = static_cast(global_allocate( - (length + 1) * sizeof(char_t))); - if (!scratch) - return false; - } - - // copy string to zero-terminated buffer and perform conversion - memcpy(scratch, begin, length * sizeof(char_t)); - scratch[length] = 0; - - *out_result = convert_string_to_number(scratch); - - // free dummy buffer - if (scratch != buffer) - global_deallocate(scratch); - - return true; -} - -double round_nearest(double value) { - return floor(value + 0.5); -} - -double round_nearest_nzero(double value) { - // same as round_nearest, but returns -0 for [-0.5, -0] - // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0) - return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5); -} - -const char_t* qualified_name(const xpath_node& node) { - return node.attribute() ? node.attribute().name() : node.node().name(); -} - -const char_t* local_name(const xpath_node& node) { - const char_t* name = qualified_name(node); - const char_t* p = find_char(name, ':'); - - return p ? p + 1 : name; -} - -struct namespace_uri_predicate { - const char_t* prefix; - size_t prefix_length; - - namespace_uri_predicate(const char_t* name) { - const char_t* pos = find_char(name, ':'); - - prefix = pos ? name : 0; - prefix_length = pos ? static_cast(pos - name) : 0; - } - - bool operator()(const xml_attribute& a) const { - const char_t* name = a.name(); - - if (!starts_with(name, PUGIXML_TEXT("xmlns"))) - return false; - - return prefix ? - name[5] == ':' - && strequalrange(name + 6, prefix, prefix_length) : - name[5] == 0; - } -}; - -const char_t* namespace_uri(const xml_node& node) { - namespace_uri_predicate pred = node.name(); - - xml_node p = node; - - while (p) { - xml_attribute a = p.find_attribute(pred); - - if (a) - return a.value(); - - p = p.parent(); - } - - return PUGIXML_TEXT(""); -} - -const char_t* namespace_uri(const xml_attribute& attr, const xml_node& parent) { - namespace_uri_predicate pred = attr.name(); - - // Default namespace does not apply to attributes - if (!pred.prefix) - return PUGIXML_TEXT(""); - - xml_node p = parent; - - while (p) { - xml_attribute a = p.find_attribute(pred); - - if (a) - return a.value(); - - p = p.parent(); - } - - return PUGIXML_TEXT(""); -} - -const char_t* namespace_uri(const xpath_node& node) { - return node.attribute() ? - namespace_uri(node.attribute(), node.parent()) : - namespace_uri(node.node()); -} - -void normalize_space(char_t* buffer) { - char_t* write = buffer; - - for (char_t* it = buffer; *it;) { - char_t ch = *it++; - - if (IS_CHARTYPE(ch, ct_space)) { - // replace whitespace sequence with single space - while (IS_CHARTYPE(*it, ct_space)) - it++; - - // avoid leading spaces - if (write != buffer) - *write++ = ' '; - } else - *write++ = ch; - } - - // remove trailing space - if (write != buffer && IS_CHARTYPE(write[-1], ct_space)) - write--; - - // zero-terminate - *write = 0; -} - -void translate(char_t* buffer, const char_t* from, const char_t* to) { - size_t to_length = strlength(to); - - char_t* write = buffer; - - while (*buffer) { - DMC_VOLATILE char_t ch = *buffer++; - - const char_t* pos = find_char(from, ch); - - if (!pos) - *write++ = ch; // do not process - else if (static_cast(pos - from) < to_length) - *write++ = to[pos - from]; // replace - } - - // zero-terminate - *write = 0; -} - -struct xpath_variable_boolean: xpath_variable { - xpath_variable_boolean() : - value(false) { - } - - bool value; - char_t name[1]; -}; - -struct xpath_variable_number: xpath_variable { - xpath_variable_number() : - value(0) { - } - - double value; - char_t name[1]; -}; - -struct xpath_variable_string: xpath_variable { - xpath_variable_string() : - value(0) { - } - - ~xpath_variable_string() { - if (value) - global_deallocate(value); - } - - char_t* value; - char_t name[1]; -}; - -struct xpath_variable_node_set: xpath_variable { - xpath_node_set value; - char_t name[1]; -}; - -const xpath_node_set dummy_node_set; - -unsigned int hash_string(const char_t* str) { - // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time) - unsigned int result = 0; - - while (*str) { - result += static_cast(*str++); - result += result << 10; - result ^= result >> 6; - } - - result += result << 3; - result ^= result >> 11; - result += result << 15; - - return result; -} - -template T* new_xpath_variable(const char_t* name) { - size_t length = strlength(name); - if (length == 0) - return 0; // empty variable names are invalid - - // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters - void* memory = global_allocate(sizeof(T) + length * sizeof(char_t)); - if (!memory) - return 0; - - T* result = new (memory) T(); - - memcpy(result->name, name, (length + 1) * sizeof(char_t)); - - return result; -} - -xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name) { - switch (type) { - case xpath_type_node_set: - return new_xpath_variable(name); - - case xpath_type_number: - return new_xpath_variable(name); - - case xpath_type_string: - return new_xpath_variable(name); - - case xpath_type_boolean: - return new_xpath_variable(name); - - default: - return 0; - } -} - -template void delete_xpath_variable(T* var) { - var->~T(); - global_deallocate(var); -} - -void delete_xpath_variable(xpath_value_type type, xpath_variable* var) { - switch (type) { - case xpath_type_node_set: - delete_xpath_variable(static_cast(var)); - break; - - case xpath_type_number: - delete_xpath_variable(static_cast(var)); - break; - - case xpath_type_string: - delete_xpath_variable(static_cast(var)); - break; - - case xpath_type_boolean: - delete_xpath_variable(static_cast(var)); - break; - - default: - assert(!"Invalid variable type"); - } -} - -xpath_variable* get_variable(xpath_variable_set* set, const char_t* begin, - const char_t* end) { - char_t buffer[32]; - - size_t length = static_cast(end - begin); - char_t* scratch = buffer; - - if (length >= sizeof(buffer) / sizeof(buffer[0])) { - // need to make dummy on-heap copy - scratch = static_cast(global_allocate( - (length + 1) * sizeof(char_t))); - if (!scratch) - return 0; - } - - // copy string to zero-terminated buffer and perform lookup - memcpy(scratch, begin, length * sizeof(char_t)); - scratch[length] = 0; - - xpath_variable* result = set->get(scratch); - - // free dummy buffer - if (scratch != buffer) - global_deallocate(scratch); - - return result; -} -} - -// Internal node set class -namespace { -xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, - xpath_node_set::type_t type, bool rev) { - xpath_node_set::type_t order = - rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted; - - if (type == xpath_node_set::type_unsorted) { - sort(begin, end, document_order_comparator()); - - type = xpath_node_set::type_sorted; - } - - if (type != order) - reverse(begin, end); - - return order; -} - -xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, - xpath_node_set::type_t type) { - if (begin == end) - return xpath_node(); - - switch (type) { - case xpath_node_set::type_sorted: - return *begin; - - case xpath_node_set::type_sorted_reverse: - return *(end - 1); - - case xpath_node_set::type_unsorted: - return *min_element(begin, end, document_order_comparator()); - - default: - assert(!"Invalid node set type"); - return xpath_node(); - } -} -class xpath_node_set_raw { - xpath_node_set::type_t _type; - - xpath_node* _begin; - xpath_node* _end; - xpath_node* _eos; - -public: - xpath_node_set_raw() : - _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0) { - } - - xpath_node* begin() const { - return _begin; - } - - xpath_node* end() const { - return _end; - } - - bool empty() const { - return _begin == _end; - } - - size_t size() const { - return static_cast(_end - _begin); - } - - xpath_node first() const { - return xpath_first(_begin, _end, _type); - } - - void push_back(const xpath_node& node, xpath_allocator* alloc) { - if (_end == _eos) { - size_t capacity = static_cast(_eos - _begin); - - // get new capacity (1.5x rule) - size_t new_capacity = capacity + capacity / 2 + 1; - - // reallocate the old array or allocate a new one - xpath_node* data = static_cast(alloc->reallocate( - _begin, capacity * sizeof(xpath_node), - new_capacity * sizeof(xpath_node))); - assert(data); - - // finalize - _begin = data; - _end = data + capacity; - _eos = data + new_capacity; - } - - *_end++ = node; - } - - void append(const xpath_node* begin, const xpath_node* end, - xpath_allocator* alloc) { - size_t size = static_cast(_end - _begin); - size_t capacity = static_cast(_eos - _begin); - size_t count = static_cast(end - begin); - - if (size + count > capacity) { - // reallocate the old array or allocate a new one - xpath_node* data = static_cast(alloc->reallocate( - _begin, capacity * sizeof(xpath_node), - (size + count) * sizeof(xpath_node))); - assert(data); - - // finalize - _begin = data; - _end = data + size; - _eos = data + size + count; - } - - memcpy(_end, begin, count * sizeof(xpath_node)); - _end += count; - } - - void sort_do() { - _type = xpath_sort(_begin, _end, _type, false); - } - - void truncate(xpath_node* pos) { - assert(_begin <= pos && pos <= _end); - - _end = pos; - } - - void remove_duplicates() { - if (_type == xpath_node_set::type_unsorted) - sort(_begin, _end, duplicate_comparator()); - - _end = unique(_begin, _end); - } - - xpath_node_set::type_t type() const { - return _type; - } - - void set_type(xpath_node_set::type_t type) { - _type = type; - } -}; -} - -namespace { -struct xpath_context { - xpath_node n; - size_t position, size; - - xpath_context(const xpath_node& n, size_t position, size_t size) : - n(n), position(position), size(size) { - } -}; - -enum lexeme_t { - lex_none = 0, - lex_equal, - lex_not_equal, - lex_less, - lex_greater, - lex_less_or_equal, - lex_greater_or_equal, - lex_plus, - lex_minus, - lex_multiply, - lex_union, - lex_var_ref, - lex_open_brace, - lex_close_brace, - lex_quoted_string, - lex_number, - lex_slash, - lex_double_slash, - lex_open_square_brace, - lex_close_square_brace, - lex_string, - lex_comma, - lex_axis_attribute, - lex_dot, - lex_double_dot, - lex_double_colon, - lex_eof -}; - -struct xpath_lexer_string { - const char_t* begin; - const char_t* end; - - xpath_lexer_string() : - begin(0), end(0) { - } - - bool operator==(const char_t* other) const { - size_t length = static_cast(end - begin); - - return strequalrange(other, begin, length); - } -}; - -class xpath_lexer { - const char_t* _cur; - const char_t* _cur_lexeme_pos; - xpath_lexer_string _cur_lexeme_contents; - - lexeme_t _cur_lexeme; - -public: - explicit xpath_lexer(const char_t* query) : - _cur(query) { - next(); - } - - const char_t* state() const { - return _cur; - } - - void next() { - const char_t* cur = _cur; - - while (IS_CHARTYPE(*cur, ct_space)) - ++cur; - - // save lexeme position for error reporting - _cur_lexeme_pos = cur; - - switch (*cur) { - case 0: - _cur_lexeme = lex_eof; - break; - - case '>': - if (*(cur + 1) == '=') { - cur += 2; - _cur_lexeme = lex_greater_or_equal; - } else { - cur += 1; - _cur_lexeme = lex_greater; - } - break; - - case '<': - if (*(cur + 1) == '=') { - cur += 2; - _cur_lexeme = lex_less_or_equal; - } else { - cur += 1; - _cur_lexeme = lex_less; - } - break; - - case '!': - if (*(cur + 1) == '=') { - cur += 2; - _cur_lexeme = lex_not_equal; - } else { - _cur_lexeme = lex_none; - } - break; - - case '=': - cur += 1; - _cur_lexeme = lex_equal; - - break; - - case '+': - cur += 1; - _cur_lexeme = lex_plus; - - break; - - case '-': - cur += 1; - _cur_lexeme = lex_minus; - - break; - - case '*': - cur += 1; - _cur_lexeme = lex_multiply; - - break; - - case '|': - cur += 1; - _cur_lexeme = lex_union; - - break; - - case '$': - cur += 1; - - if (IS_CHARTYPEX(*cur, ctx_start_symbol)) { - _cur_lexeme_contents.begin = cur; - - while (IS_CHARTYPEX(*cur, ctx_symbol)) - cur++; - - if (cur[0] == ':' && IS_CHARTYPEX(cur[1], ctx_symbol)) // qname - { - cur++; // : - - while (IS_CHARTYPEX(*cur, ctx_symbol)) - cur++; - } - - _cur_lexeme_contents.end = cur; - - _cur_lexeme = lex_var_ref; - } else { - _cur_lexeme = lex_none; - } - - break; - - case '(': - cur += 1; - _cur_lexeme = lex_open_brace; - - break; - - case ')': - cur += 1; - _cur_lexeme = lex_close_brace; - - break; - - case '[': - cur += 1; - _cur_lexeme = lex_open_square_brace; - - break; - - case ']': - cur += 1; - _cur_lexeme = lex_close_square_brace; - - break; - - case ',': - cur += 1; - _cur_lexeme = lex_comma; - - break; - - case '/': - if (*(cur + 1) == '/') { - cur += 2; - _cur_lexeme = lex_double_slash; - } else { - cur += 1; - _cur_lexeme = lex_slash; - } - break; - - case '.': - if (*(cur + 1) == '.') { - cur += 2; - _cur_lexeme = lex_double_dot; - } else if (IS_CHARTYPEX(*(cur+1), ctx_digit)) { - _cur_lexeme_contents.begin = cur; // . - - ++cur; - - while (IS_CHARTYPEX(*cur, ctx_digit)) - cur++; - - _cur_lexeme_contents.end = cur; - - _cur_lexeme = lex_number; - } else { - cur += 1; - _cur_lexeme = lex_dot; - } - break; - - case '@': - cur += 1; - _cur_lexeme = lex_axis_attribute; - - break; - - case '"': - case '\'': { - char_t terminator = *cur; - - ++cur; - - _cur_lexeme_contents.begin = cur; - while (*cur && *cur != terminator) - cur++; - _cur_lexeme_contents.end = cur; - - if (!*cur) - _cur_lexeme = lex_none; - else { - cur += 1; - _cur_lexeme = lex_quoted_string; - } - - break; - } - - case ':': - if (*(cur + 1) == ':') { - cur += 2; - _cur_lexeme = lex_double_colon; - } else { - _cur_lexeme = lex_none; - } - break; - - default: - if (IS_CHARTYPEX(*cur, ctx_digit)) { - _cur_lexeme_contents.begin = cur; - - while (IS_CHARTYPEX(*cur, ctx_digit)) - cur++; - - if (*cur == '.') { - cur++; - - while (IS_CHARTYPEX(*cur, ctx_digit)) - cur++; - } - - _cur_lexeme_contents.end = cur; - - _cur_lexeme = lex_number; - } else if (IS_CHARTYPEX(*cur, ctx_start_symbol)) { - _cur_lexeme_contents.begin = cur; - - while (IS_CHARTYPEX(*cur, ctx_symbol)) - cur++; - - if (cur[0] == ':') { - if (cur[1] == '*') // namespace test ncname:* - { - cur += 2; // :* - } else if (IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname - { - cur++; // : - - while (IS_CHARTYPEX(*cur, ctx_symbol)) - cur++; - } - } - - _cur_lexeme_contents.end = cur; - - _cur_lexeme = lex_string; - } else { - _cur_lexeme = lex_none; - } - } - - _cur = cur; - } - - lexeme_t current() const { - return _cur_lexeme; - } - - const char_t* current_pos() const { - return _cur_lexeme_pos; - } - - const xpath_lexer_string& contents() const { - assert( - _cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string); - - return _cur_lexeme_contents; - } -}; - -enum ast_type_t { - ast_op_or, // left or right - ast_op_and, // left and right - ast_op_equal, // left = right - ast_op_not_equal, // left != right - ast_op_less, // left < right - ast_op_greater, // left > right - ast_op_less_or_equal, // left <= right - ast_op_greater_or_equal, // left >= right - ast_op_add, // left + right - ast_op_subtract, // left - right - ast_op_multiply, // left * right - ast_op_divide, // left / right - ast_op_mod, // left % right - ast_op_negate, // left - right - ast_op_union, // left | right - ast_predicate, // apply predicate to set; next points to next predicate - ast_filter, // select * from left where right - ast_filter_posinv, // select * from left where right; proximity position invariant - ast_string_constant, // string constant - ast_number_constant, // number constant - ast_variable, // variable - ast_func_last, // last() - ast_func_position, // position() - ast_func_count, // count(left) - ast_func_id, // id(left) - ast_func_local_name_0, // local-name() - ast_func_local_name_1, // local-name(left) - ast_func_namespace_uri_0, // namespace-uri() - ast_func_namespace_uri_1, // namespace-uri(left) - ast_func_name_0, // name() - ast_func_name_1, // name(left) - ast_func_string_0, // string() - ast_func_string_1, // string(left) - ast_func_concat, // concat(left, right, siblings) - ast_func_starts_with, // starts_with(left, right) - ast_func_contains, // contains(left, right) - ast_func_substring_before, // substring-before(left, right) - ast_func_substring_after, // substring-after(left, right) - ast_func_substring_2, // substring(left, right) - ast_func_substring_3, // substring(left, right, third) - ast_func_string_length_0, // string-length() - ast_func_string_length_1, // string-length(left) - ast_func_normalize_space_0, // normalize-space() - ast_func_normalize_space_1, // normalize-space(left) - ast_func_translate, // translate(left, right, third) - ast_func_boolean, // boolean(left) - ast_func_not, // not(left) - ast_func_true, // true() - ast_func_false, // false() - ast_func_lang, // lang(left) - ast_func_number_0, // number() - ast_func_number_1, // number(left) - ast_func_sum, // sum(left) - ast_func_floor, // floor(left) - ast_func_ceiling, // ceiling(left) - ast_func_round, // round(left) - ast_step, // process set left with step - ast_step_root -// select root node -}; - -enum axis_t { - axis_ancestor, - axis_ancestor_or_self, - axis_attribute, - axis_child, - axis_descendant, - axis_descendant_or_self, - axis_following, - axis_following_sibling, - axis_namespace, - axis_parent, - axis_preceding, - axis_preceding_sibling, - axis_self -}; - -enum nodetest_t { - nodetest_none, - nodetest_name, - nodetest_type_node, - nodetest_type_comment, - nodetest_type_pi, - nodetest_type_text, - nodetest_pi, - nodetest_all, - nodetest_all_in_namespace -}; - -template struct axis_to_type { - static const axis_t axis; -}; - -template const axis_t axis_to_type::axis = N; - -class xpath_ast_node { -private: - // node type - char _type; - char _rettype; - - // for ast_step / ast_predicate - char _axis; - char _test; - - // tree node structure - xpath_ast_node* _left; - xpath_ast_node* _right; - xpath_ast_node* _next; - - union { - // value for ast_string_constant - const char_t* string; - // value for ast_number_constant - double number; - // variable for ast_variable - xpath_variable* variable; - // node test for ast_step (node name/namespace/node type/pi target) - const char_t* nodetest; - } _data; - - xpath_ast_node(const xpath_ast_node&); - xpath_ast_node& operator=(const xpath_ast_node&); - - template static bool compare_eq(xpath_ast_node* lhs, - xpath_ast_node* rhs, const xpath_context& c, - const xpath_stack& stack, const Comp& comp) { - xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); - - if (lt != xpath_type_node_set && rt != xpath_type_node_set) { - if (lt == xpath_type_boolean || rt == xpath_type_boolean) - return comp(lhs->eval_boolean(c, stack), - rhs->eval_boolean(c, stack)); - else if (lt == xpath_type_number || rt == xpath_type_number) - return comp(lhs->eval_number(c, stack), - rhs->eval_number(c, stack)); - else if (lt == xpath_type_string || rt == xpath_type_string) { - xpath_allocator_capture cr(stack.result); - - xpath_string ls = lhs->eval_string(c, stack); - xpath_string rs = rhs->eval_string(c, stack); - - return comp(ls, rs); - } - } else if (lt == xpath_type_node_set && rt == xpath_type_node_set) { - xpath_allocator_capture cr(stack.result); - - xpath_node_set_raw ls = lhs->eval_node_set(c, stack); - xpath_node_set_raw rs = rhs->eval_node_set(c, stack); - - for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) - for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { - xpath_allocator_capture cri(stack.result); - - if (comp(string_value(*li, stack.result), - string_value(*ri, stack.result))) - return true; - } - - return false; - } else { - if (lt == xpath_type_node_set) { - swap(lhs, rhs); - swap(lt, rt); - } - - if (lt == xpath_type_boolean) - return comp(lhs->eval_boolean(c, stack), - rhs->eval_boolean(c, stack)); - else if (lt == xpath_type_number) { - xpath_allocator_capture cr(stack.result); - - double l = lhs->eval_number(c, stack); - xpath_node_set_raw rs = rhs->eval_node_set(c, stack); - - for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { - xpath_allocator_capture cri(stack.result); - - if (comp( - l, - convert_string_to_number( - string_value(*ri, stack.result).c_str()))) - return true; - } - - return false; - } else if (lt == xpath_type_string) { - xpath_allocator_capture cr(stack.result); - - xpath_string l = lhs->eval_string(c, stack); - xpath_node_set_raw rs = rhs->eval_node_set(c, stack); - - for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { - xpath_allocator_capture cri(stack.result); - - if (comp(l, string_value(*ri, stack.result))) - return true; - } - - return false; - } - } - - assert(!"Wrong types"); - return false; - } - - template static bool compare_rel(xpath_ast_node* lhs, - xpath_ast_node* rhs, const xpath_context& c, - const xpath_stack& stack, const Comp& comp) { - xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); - - if (lt != xpath_type_node_set && rt != xpath_type_node_set) - return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); - else if (lt == xpath_type_node_set && rt == xpath_type_node_set) { - xpath_allocator_capture cr(stack.result); - - xpath_node_set_raw ls = lhs->eval_node_set(c, stack); - xpath_node_set_raw rs = rhs->eval_node_set(c, stack); - - for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) { - xpath_allocator_capture cri(stack.result); - - double l = convert_string_to_number( - string_value(*li, stack.result).c_str()); - - for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { - xpath_allocator_capture crii(stack.result); - - if (comp( - l, - convert_string_to_number( - string_value(*ri, stack.result).c_str()))) - return true; - } - } - - return false; - } else if (lt != xpath_type_node_set && rt == xpath_type_node_set) { - xpath_allocator_capture cr(stack.result); - - double l = lhs->eval_number(c, stack); - xpath_node_set_raw rs = rhs->eval_node_set(c, stack); - - for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { - xpath_allocator_capture cri(stack.result); - - if (comp( - l, - convert_string_to_number( - string_value(*ri, stack.result).c_str()))) - return true; - } - - return false; - } else if (lt == xpath_type_node_set && rt != xpath_type_node_set) { - xpath_allocator_capture cr(stack.result); - - xpath_node_set_raw ls = lhs->eval_node_set(c, stack); - double r = rhs->eval_number(c, stack); - - for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) { - xpath_allocator_capture cri(stack.result); - - if (comp( - convert_string_to_number( - string_value(*li, stack.result).c_str()), r)) - return true; - } - - return false; - } else { - assert(!"Wrong types"); - return false; - } - } - - void apply_predicate(xpath_node_set_raw& ns, size_t first, - xpath_ast_node* expr, const xpath_stack& stack) { - assert(ns.size() >= first); - - size_t i = 1; - size_t size = ns.size() - first; - - xpath_node* last = ns.begin() + first; - - // remove_if... or well, sort of - for (xpath_node* it = last; it != ns.end(); ++it, ++i) { - xpath_context c(*it, i, size); - - if (expr->rettype() == xpath_type_number) { - if (expr->eval_number(c, stack) == i) - *last++ = *it; - } else if (expr->eval_boolean(c, stack)) - *last++ = *it; - } - - ns.truncate(last); - } - - void apply_predicates(xpath_node_set_raw& ns, size_t first, - const xpath_stack& stack) { - if (ns.size() == first) - return; - - for (xpath_ast_node* pred = _right; pred; pred = pred->_next) { - apply_predicate(ns, first, pred->_left, stack); - } - } - - void step_push(xpath_node_set_raw& ns, const xml_attribute& a, - const xml_node& parent, xpath_allocator* alloc) { - if (!a) - return; - - const char_t* name = a.name(); - - // There are no attribute nodes corresponding to attributes that declare namespaces - // That is, "xmlns:..." or "xmlns" - if (starts_with(name, PUGIXML_TEXT("xmlns")) - && (name[5] == 0 || name[5] == ':')) - return; - - switch (_test) { - case nodetest_name: - if (strequal(name, _data.nodetest)) - ns.push_back(xpath_node(a, parent), alloc); - break; - - case nodetest_type_node: - case nodetest_all: - ns.push_back(xpath_node(a, parent), alloc); - break; - - case nodetest_all_in_namespace: - if (starts_with(name, _data.nodetest)) - ns.push_back(xpath_node(a, parent), alloc); - break; - - default: - ; - } - } - - void step_push(xpath_node_set_raw& ns, const xml_node& n, - xpath_allocator* alloc) { - if (!n) - return; - - switch (_test) { - case nodetest_name: - if (n.type() == node_element && strequal(n.name(), _data.nodetest)) - ns.push_back(n, alloc); - break; - - case nodetest_type_node: - ns.push_back(n, alloc); - break; - - case nodetest_type_comment: - if (n.type() == node_comment) - ns.push_back(n, alloc); - break; - - case nodetest_type_text: - if (n.type() == node_pcdata || n.type() == node_cdata) - ns.push_back(n, alloc); - break; - - case nodetest_type_pi: - if (n.type() == node_pi) - ns.push_back(n, alloc); - break; - - case nodetest_pi: - if (n.type() == node_pi && strequal(n.name(), _data.nodetest)) - ns.push_back(n, alloc); - break; - - case nodetest_all: - if (n.type() == node_element) - ns.push_back(n, alloc); - break; - - case nodetest_all_in_namespace: - if (n.type() == node_element - && starts_with(n.name(), _data.nodetest)) - ns.push_back(n, alloc); - break; - - default: - assert(!"Unknown axis"); - } - } - - template void step_fill(xpath_node_set_raw& ns, const xml_node& n, - xpath_allocator* alloc, T) { - const axis_t axis = T::axis; - - switch (axis) { - case axis_attribute: { - for (xml_attribute a = n.first_attribute(); a; a = - a.next_attribute()) - step_push(ns, a, n, alloc); - - break; - } - - case axis_child: { - for (xml_node c = n.first_child(); c; c = c.next_sibling()) - step_push(ns, c, alloc); - - break; - } - - case axis_descendant: - case axis_descendant_or_self: { - if (axis == axis_descendant_or_self) - step_push(ns, n, alloc); - - xml_node cur = n.first_child(); - - while (cur && cur != n) { - step_push(ns, cur, alloc); - - if (cur.first_child()) - cur = cur.first_child(); - else if (cur.next_sibling()) - cur = cur.next_sibling(); - else { - while (!cur.next_sibling() && cur != n) - cur = cur.parent(); - - if (cur != n) - cur = cur.next_sibling(); - } - } - - break; - } - - case axis_following_sibling: { - for (xml_node c = n.next_sibling(); c; c = c.next_sibling()) - step_push(ns, c, alloc); - - break; - } - - case axis_preceding_sibling: { - for (xml_node c = n.previous_sibling(); c; c = c.previous_sibling()) - step_push(ns, c, alloc); - - break; - } - - case axis_following: { - xml_node cur = n; - - // exit from this node so that we don't include descendants - while (cur && !cur.next_sibling()) - cur = cur.parent(); - cur = cur.next_sibling(); - - for (;;) { - step_push(ns, cur, alloc); - - if (cur.first_child()) - cur = cur.first_child(); - else if (cur.next_sibling()) - cur = cur.next_sibling(); - else { - while (cur && !cur.next_sibling()) - cur = cur.parent(); - cur = cur.next_sibling(); - - if (!cur) - break; - } - } - - break; - } - - case axis_preceding: { - xml_node cur = n; - - while (cur && !cur.previous_sibling()) - cur = cur.parent(); - cur = cur.previous_sibling(); - - for (;;) { - if (cur.last_child()) - cur = cur.last_child(); - else { - // leaf node, can't be ancestor - step_push(ns, cur, alloc); - - if (cur.previous_sibling()) - cur = cur.previous_sibling(); - else { - do { - cur = cur.parent(); - if (!cur) - break; - - if (!node_is_ancestor(cur, n)) - step_push(ns, cur, alloc); - } while (!cur.previous_sibling()); - - cur = cur.previous_sibling(); - - if (!cur) - break; - } - } - } - - break; - } - - case axis_ancestor: - case axis_ancestor_or_self: { - if (axis == axis_ancestor_or_self) - step_push(ns, n, alloc); - - xml_node cur = n.parent(); - - while (cur) { - step_push(ns, cur, alloc); - - cur = cur.parent(); - } - - break; - } - - case axis_self: { - step_push(ns, n, alloc); - - break; - } - - case axis_parent: { - if (n.parent()) - step_push(ns, n.parent(), alloc); - - break; - } - - default: - assert(!"Unimplemented axis"); - } - } - - template void step_fill(xpath_node_set_raw& ns, - const xml_attribute& a, const xml_node& p, xpath_allocator* alloc, - T v) { - const axis_t axis = T::axis; - - switch (axis) { - case axis_ancestor: - case axis_ancestor_or_self: { - if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test - step_push(ns, a, p, alloc); - - xml_node cur = p; - - while (cur) { - step_push(ns, cur, alloc); - - cur = cur.parent(); - } - - break; - } - - case axis_descendant_or_self: - case axis_self: { - if (_test == nodetest_type_node) // reject attributes based on principal node type test - step_push(ns, a, p, alloc); - - break; - } - - case axis_following: { - xml_node cur = p; - - for (;;) { - if (cur.first_child()) - cur = cur.first_child(); - else if (cur.next_sibling()) - cur = cur.next_sibling(); - else { - while (cur && !cur.next_sibling()) - cur = cur.parent(); - cur = cur.next_sibling(); - - if (!cur) - break; - } - - step_push(ns, cur, alloc); - } - - break; - } - - case axis_parent: { - step_push(ns, p, alloc); - - break; - } - - case axis_preceding: { - // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding - step_fill(ns, p, alloc, v); - break; - } - - default: - assert(!"Unimplemented axis"); - } - } - - template xpath_node_set_raw step_do(const xpath_context& c, - const xpath_stack& stack, T v) { - const axis_t axis = T::axis; - bool attributes = (axis == axis_ancestor - || axis == axis_ancestor_or_self - || axis == axis_descendant_or_self || axis == axis_following - || axis == axis_parent || axis == axis_preceding - || axis == axis_self); - - xpath_node_set_raw ns; - ns.set_type( - (axis == axis_ancestor || axis == axis_ancestor_or_self - || axis == axis_preceding - || axis == axis_preceding_sibling) ? - xpath_node_set::type_sorted_reverse : - xpath_node_set::type_sorted); - - if (_left) { - xpath_node_set_raw s = _left->eval_node_set(c, stack); - - // self axis preserves the original order - if (axis == axis_self) - ns.set_type(s.type()); - - for (const xpath_node* it = s.begin(); it != s.end(); ++it) { - size_t size = ns.size(); - - // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes - if (axis != axis_self && size != 0) - ns.set_type(xpath_node_set::type_unsorted); - - if (it->node()) - step_fill(ns, it->node(), stack.result, v); - else if (attributes) - step_fill(ns, it->attribute(), it->parent(), stack.result, - v); - - apply_predicates(ns, size, stack); - } - } else { - if (c.n.node()) - step_fill(ns, c.n.node(), stack.result, v); - else if (attributes) - step_fill(ns, c.n.attribute(), c.n.parent(), stack.result, v); - - apply_predicates(ns, 0, stack); - } - - // child, attribute and self axes always generate unique set of nodes - // for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the same node twice - if (axis != axis_child && axis != axis_attribute && axis != axis_self - && ns.type() == xpath_node_set::type_unsorted) - ns.remove_duplicates(); - - return ns; - } - -public: - xpath_ast_node(ast_type_t type, xpath_value_type rettype, - const char_t* value) : - _type((char) type), _rettype((char) rettype), _axis(0), _test(0), _left( - 0), _right(0), _next(0) { - assert(type == ast_string_constant); - _data.string = value; - } - - xpath_ast_node(ast_type_t type, xpath_value_type rettype, double value) : - _type((char) type), _rettype((char) rettype), _axis(0), _test(0), _left( - 0), _right(0), _next(0) { - assert(type == ast_number_constant); - _data.number = value; - } - - xpath_ast_node(ast_type_t type, xpath_value_type rettype, - xpath_variable* value) : - _type((char) type), _rettype((char) rettype), _axis(0), _test(0), _left( - 0), _right(0), _next(0) { - assert(type == ast_variable); - _data.variable = value; - } - - xpath_ast_node(ast_type_t type, xpath_value_type rettype, - xpath_ast_node* left = 0, xpath_ast_node* right = 0) : - _type((char) type), _rettype((char) rettype), _axis(0), _test(0), _left( - left), _right(right), _next(0) { - } - - xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, - nodetest_t test, const char_t* contents) : - _type((char) type), _rettype(xpath_type_node_set), _axis( - (char) axis), _test((char) test), _left(left), _right(0), _next( - 0) { - _data.nodetest = contents; - } - - void set_next(xpath_ast_node* value) { - _next = value; - } - - void set_right(xpath_ast_node* value) { - _right = value; - } - - bool eval_boolean(const xpath_context& c, const xpath_stack& stack) { - switch (_type) { - case ast_op_or: - return _left->eval_boolean(c, stack) - || _right->eval_boolean(c, stack); - - case ast_op_and: - return _left->eval_boolean(c, stack) - && _right->eval_boolean(c, stack); - - case ast_op_equal: - return compare_eq(_left, _right, c, stack, equal_to()); - - case ast_op_not_equal: - return compare_eq(_left, _right, c, stack, not_equal_to()); - - case ast_op_less: - return compare_rel(_left, _right, c, stack, less()); - - case ast_op_greater: - return compare_rel(_right, _left, c, stack, less()); - - case ast_op_less_or_equal: - return compare_rel(_left, _right, c, stack, less_equal()); - - case ast_op_greater_or_equal: - return compare_rel(_right, _left, c, stack, less_equal()); - - case ast_func_starts_with: { - xpath_allocator_capture cr(stack.result); - - xpath_string lr = _left->eval_string(c, stack); - xpath_string rr = _right->eval_string(c, stack); - - return starts_with(lr.c_str(), rr.c_str()); - } - - case ast_func_contains: { - xpath_allocator_capture cr(stack.result); - - xpath_string lr = _left->eval_string(c, stack); - xpath_string rr = _right->eval_string(c, stack); - - return find_substring(lr.c_str(), rr.c_str()) != 0; - } - - case ast_func_boolean: - return _left->eval_boolean(c, stack); - - case ast_func_not: - return !_left->eval_boolean(c, stack); - - case ast_func_true: - return true; - - case ast_func_false: - return false; - - case ast_func_lang: { - if (c.n.attribute()) - return false; - - xpath_allocator_capture cr(stack.result); - - xpath_string lang = _left->eval_string(c, stack); - - for (xml_node n = c.n.node(); n; n = n.parent()) { - xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang")); - - if (a) { - const char_t* value = a.value(); - - // strnicmp / strncasecmp is not portable - for (const char_t* lit = lang.c_str(); *lit; ++lit) { - if (tolower_ascii(*lit) != tolower_ascii(*value)) - return false; - ++value; - } - - return *value == 0 || *value == '-'; - } - } - - return false; - } - - case ast_variable: { - assert(_rettype == _data.variable->type()); - - if (_rettype == xpath_type_boolean) - return _data.variable->get_boolean(); - - // fallthrough to type conversion - } - - default: { - switch (_rettype) { - case xpath_type_number: - return convert_number_to_boolean(eval_number(c, stack)); - - case xpath_type_string: { - xpath_allocator_capture cr(stack.result); - - return !eval_string(c, stack).empty(); - } - - case xpath_type_node_set: { - xpath_allocator_capture cr(stack.result); - - return !eval_node_set(c, stack).empty(); - } - - default: - assert(!"Wrong expression for return type boolean"); - return false; - } - } - } - } - - double eval_number(const xpath_context& c, const xpath_stack& stack) { - switch (_type) { - case ast_op_add: - return _left->eval_number(c, stack) + _right->eval_number(c, stack); - - case ast_op_subtract: - return _left->eval_number(c, stack) - _right->eval_number(c, stack); - - case ast_op_multiply: - return _left->eval_number(c, stack) * _right->eval_number(c, stack); - - case ast_op_divide: - return _left->eval_number(c, stack) / _right->eval_number(c, stack); - - case ast_op_mod: - return fmod(_left->eval_number(c, stack), - _right->eval_number(c, stack)); - - case ast_op_negate: - return -_left->eval_number(c, stack); - - case ast_number_constant: - return _data.number; - - case ast_func_last: - return (double) c.size; - - case ast_func_position: - return (double) c.position; - - case ast_func_count: { - xpath_allocator_capture cr(stack.result); - - return (double) _left->eval_node_set(c, stack).size(); - } - - case ast_func_string_length_0: { - xpath_allocator_capture cr(stack.result); - - return (double) string_value(c.n, stack.result).length(); - } - - case ast_func_string_length_1: { - xpath_allocator_capture cr(stack.result); - - return (double) _left->eval_string(c, stack).length(); - } - - case ast_func_number_0: { - xpath_allocator_capture cr(stack.result); - - return convert_string_to_number( - string_value(c.n, stack.result).c_str()); - } - - case ast_func_number_1: - return _left->eval_number(c, stack); - - case ast_func_sum: { - xpath_allocator_capture cr(stack.result); - - double r = 0; - - xpath_node_set_raw ns = _left->eval_node_set(c, stack); - - for (const xpath_node* it = ns.begin(); it != ns.end(); ++it) { - xpath_allocator_capture cri(stack.result); - - r += convert_string_to_number( - string_value(*it, stack.result).c_str()); - } - - return r; - } - - case ast_func_floor: { - double r = _left->eval_number(c, stack); - - return r == r ? floor(r) : r; - } - - case ast_func_ceiling: { - double r = _left->eval_number(c, stack); - - return r == r ? ceil(r) : r; - } - - case ast_func_round: - return round_nearest_nzero(_left->eval_number(c, stack)); - - case ast_variable: { - assert(_rettype == _data.variable->type()); - - if (_rettype == xpath_type_number) - return _data.variable->get_number(); - - // fallthrough to type conversion - } - - default: { - switch (_rettype) { - case xpath_type_boolean: - return eval_boolean(c, stack) ? 1 : 0; - - case xpath_type_string: { - xpath_allocator_capture cr(stack.result); - - return convert_string_to_number(eval_string(c, stack).c_str()); - } - - case xpath_type_node_set: { - xpath_allocator_capture cr(stack.result); - - return convert_string_to_number(eval_string(c, stack).c_str()); - } - - default: - assert(!"Wrong expression for return type number"); - return 0; - } - - } - } - } - - xpath_string eval_string_concat(const xpath_context& c, - const xpath_stack& stack) { - assert(_type == ast_func_concat); - - xpath_allocator_capture ct(stack.temp); - - // count the string number - size_t count = 1; - for (xpath_ast_node* nc = _right; nc; nc = nc->_next) - count++; - - // gather all strings - xpath_string static_buffer[4]; - xpath_string* buffer = static_buffer; - - // allocate on-heap for large concats - if (count > sizeof(static_buffer) / sizeof(static_buffer[0])) { - buffer = static_cast(stack.temp->allocate( - count * sizeof(xpath_string))); - assert(buffer); - } - - // evaluate all strings to temporary stack - xpath_stack swapped_stack = { stack.temp, stack.result }; - - buffer[0] = _left->eval_string(c, swapped_stack); - - size_t pos = 1; - for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) - buffer[pos] = n->eval_string(c, swapped_stack); - assert(pos == count); - - // get total length - size_t length = 0; - for (size_t i = 0; i < count; ++i) - length += buffer[i].length(); - - // create final string - char_t* result = static_cast(stack.result->allocate( - (length + 1) * sizeof(char_t))); - assert(result); - - char_t* ri = result; - - for (size_t j = 0; j < count; ++j) - for (const char_t* bi = buffer[j].c_str(); *bi; ++bi) - *ri++ = *bi; - - *ri = 0; - - return xpath_string(result, true); - } - - xpath_string eval_string(const xpath_context& c, const xpath_stack& stack) { - switch (_type) { - case ast_string_constant: - return xpath_string_const(_data.string); - - case ast_func_local_name_0: { - xpath_node na = c.n; - - return xpath_string_const(local_name(na)); - } - - case ast_func_local_name_1: { - xpath_allocator_capture cr(stack.result); - - xpath_node_set_raw ns = _left->eval_node_set(c, stack); - xpath_node na = ns.first(); - - return xpath_string_const(local_name(na)); - } - - case ast_func_name_0: { - xpath_node na = c.n; - - return xpath_string_const(qualified_name(na)); - } - - case ast_func_name_1: { - xpath_allocator_capture cr(stack.result); - - xpath_node_set_raw ns = _left->eval_node_set(c, stack); - xpath_node na = ns.first(); - - return xpath_string_const(qualified_name(na)); - } - - case ast_func_namespace_uri_0: { - xpath_node na = c.n; - - return xpath_string_const(namespace_uri(na)); - } - - case ast_func_namespace_uri_1: { - xpath_allocator_capture cr(stack.result); - - xpath_node_set_raw ns = _left->eval_node_set(c, stack); - xpath_node na = ns.first(); - - return xpath_string_const(namespace_uri(na)); - } - - case ast_func_string_0: - return string_value(c.n, stack.result); - - case ast_func_string_1: - return _left->eval_string(c, stack); - - case ast_func_concat: - return eval_string_concat(c, stack); - - case ast_func_substring_before: { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = { stack.temp, stack.result }; - - xpath_string s = _left->eval_string(c, swapped_stack); - xpath_string p = _right->eval_string(c, swapped_stack); - - const char_t* pos = find_substring(s.c_str(), p.c_str()); - - return pos ? - xpath_string(s.c_str(), pos, stack.result) : xpath_string(); - } - - case ast_func_substring_after: { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = { stack.temp, stack.result }; - - xpath_string s = _left->eval_string(c, swapped_stack); - xpath_string p = _right->eval_string(c, swapped_stack); - - const char_t* pos = find_substring(s.c_str(), p.c_str()); - if (!pos) - return xpath_string(); - - const char_t* result = pos + p.length(); - - return s.uses_heap() ? - xpath_string(result, stack.result) : - xpath_string_const(result); - } - - case ast_func_substring_2: { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = { stack.temp, stack.result }; - - xpath_string s = _left->eval_string(c, swapped_stack); - size_t s_length = s.length(); - - double first = round_nearest(_right->eval_number(c, stack)); - - if (is_nan(first)) - return xpath_string(); // NaN - else if (first >= s_length + 1) - return xpath_string(); - - size_t pos = first < 1 ? 1 : (size_t) first; - assert(1 <= pos && pos <= s_length + 1); - - const char_t* rbegin = s.c_str() + (pos - 1); - - return s.uses_heap() ? - xpath_string(rbegin, stack.result) : - xpath_string_const(rbegin); - } - - case ast_func_substring_3: { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = { stack.temp, stack.result }; - - xpath_string s = _left->eval_string(c, swapped_stack); - size_t s_length = s.length(); - - double first = round_nearest(_right->eval_number(c, stack)); - double last = first - + round_nearest(_right->_next->eval_number(c, stack)); - - if (is_nan(first) || is_nan(last)) - return xpath_string(); - else if (first >= s_length + 1) - return xpath_string(); - else if (first >= last) - return xpath_string(); - else if (last < 1) - return xpath_string(); - - size_t pos = first < 1 ? 1 : (size_t) first; - size_t end = last >= s_length + 1 ? s_length + 1 : (size_t) last; - - assert(1 <= pos && pos <= end && end <= s_length + 1); - const char_t* rbegin = s.c_str() + (pos - 1); - const char_t* rend = s.c_str() + (end - 1); - - return (end == s_length + 1 && !s.uses_heap()) ? - xpath_string_const(rbegin) : - xpath_string(rbegin, rend, stack.result); - } - - case ast_func_normalize_space_0: { - xpath_string s = string_value(c.n, stack.result); - - normalize_space(s.data(stack.result)); - - return s; - } - - case ast_func_normalize_space_1: { - xpath_string s = _left->eval_string(c, stack); - - normalize_space(s.data(stack.result)); - - return s; - } - - case ast_func_translate: { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = { stack.temp, stack.result }; - - xpath_string s = _left->eval_string(c, stack); - xpath_string from = _right->eval_string(c, swapped_stack); - xpath_string to = _right->_next->eval_string(c, swapped_stack); - - translate(s.data(stack.result), from.c_str(), to.c_str()); - - return s; - } - - case ast_variable: { - assert(_rettype == _data.variable->type()); - - if (_rettype == xpath_type_string) - return xpath_string_const(_data.variable->get_string()); - - // fallthrough to type conversion - } - - default: { - switch (_rettype) { - case xpath_type_boolean: - return xpath_string_const( - eval_boolean(c, stack) ? - PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); - - case xpath_type_number: - return convert_number_to_string(eval_number(c, stack), - stack.result); - - case xpath_type_node_set: { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = { stack.temp, stack.result }; - - xpath_node_set_raw ns = eval_node_set(c, swapped_stack); - return ns.empty() ? - xpath_string() : string_value(ns.first(), stack.result); - } - - default: - assert(!"Wrong expression for return type string"); - return xpath_string(); - } - } - } - } - - xpath_node_set_raw eval_node_set(const xpath_context& c, - const xpath_stack& stack) { - switch (_type) { - case ast_op_union: { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = { stack.temp, stack.result }; - - xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack); - xpath_node_set_raw rs = _right->eval_node_set(c, stack); - - // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother - rs.set_type(xpath_node_set::type_unsorted); - - rs.append(ls.begin(), ls.end(), stack.result); - rs.remove_duplicates(); - - return rs; - } - - case ast_filter: - case ast_filter_posinv: { - xpath_node_set_raw set = _left->eval_node_set(c, stack); - - // either expression is a number or it contains position() call; sort by document order - if (_type == ast_filter) - set.sort_do(); - - apply_predicate(set, 0, _right, stack); - - return set; - } - - case ast_func_id: - return xpath_node_set_raw(); - - case ast_step: { - switch (_axis) { - case axis_ancestor: - return step_do(c, stack, axis_to_type()); - - case axis_ancestor_or_self: - return step_do(c, stack, axis_to_type()); - - case axis_attribute: - return step_do(c, stack, axis_to_type()); - - case axis_child: - return step_do(c, stack, axis_to_type()); - - case axis_descendant: - return step_do(c, stack, axis_to_type()); - - case axis_descendant_or_self: - return step_do(c, stack, - axis_to_type()); - - case axis_following: - return step_do(c, stack, axis_to_type()); - - case axis_following_sibling: - return step_do(c, stack, axis_to_type()); - - case axis_namespace: - // namespaced axis is not supported - return xpath_node_set_raw(); - - case axis_parent: - return step_do(c, stack, axis_to_type()); - - case axis_preceding: - return step_do(c, stack, axis_to_type()); - - case axis_preceding_sibling: - return step_do(c, stack, axis_to_type()); - - case axis_self: - return step_do(c, stack, axis_to_type()); - } - } - - case ast_step_root: { - assert(!_right); - // root step can't have any predicates - - xpath_node_set_raw ns; - - ns.set_type(xpath_node_set::type_sorted); - - if (c.n.node()) - ns.push_back(c.n.node().root(), stack.result); - else if (c.n.attribute()) - ns.push_back(c.n.parent().root(), stack.result); - - return ns; - } - - case ast_variable: { - assert(_rettype == _data.variable->type()); - - if (_rettype == xpath_type_node_set) { - const xpath_node_set& s = _data.variable->get_node_set(); - - xpath_node_set_raw ns; - - ns.set_type(s.type()); - ns.append(s.begin(), s.end(), stack.result); - - return ns; - } - - // fallthrough to type conversion - } - - default: - assert(!"Wrong expression for return type node set"); - return xpath_node_set_raw(); - } - } - - bool is_posinv() { - switch (_type) { - case ast_func_position: - return false; - - case ast_string_constant: - case ast_number_constant: - case ast_variable: - return true; - - case ast_step: - case ast_step_root: - return true; - - case ast_predicate: - case ast_filter: - case ast_filter_posinv: - return true; - - default: - if (_left && !_left->is_posinv()) - return false; - - for (xpath_ast_node* n = _right; n; n = n->_next) - if (!n->is_posinv()) - return false; - - return true; - } - } - - xpath_value_type rettype() const { - return static_cast(_rettype); - } -}; - -struct xpath_parser { - xpath_allocator* _alloc; - xpath_lexer _lexer; - - const char_t* _query; - xpath_variable_set* _variables; - - xpath_parse_result* _result; - -#ifdef PUGIXML_NO_EXCEPTIONS - jmp_buf _error_handler; -#endif - - void throw_error(const char* message) { - _result->error = message; - _result->offset = _lexer.current_pos() - _query; - -#ifdef PUGIXML_NO_EXCEPTIONS - longjmp(_error_handler, 1); -#else - throw xpath_exception(*_result); -#endif - } - - void throw_error_oom() { -#ifdef PUGIXML_NO_EXCEPTIONS - throw_error("Out of memory"); -#else - throw std::bad_alloc(); -#endif - } - - void* alloc_node() { - void* result = _alloc->allocate_nothrow(sizeof(xpath_ast_node)); - - if (!result) - throw_error_oom(); - - return result; - } - - const char_t* alloc_string(const xpath_lexer_string& value) { - if (value.begin) { - size_t length = static_cast(value.end - value.begin); - - char_t* c = static_cast(_alloc->allocate_nothrow( - (length + 1) * sizeof(char_t))); - if (!c) - throw_error_oom(); - - memcpy(c, value.begin, length * sizeof(char_t)); - c[length] = 0; - - return c; - } else - return 0; - } - - xpath_ast_node* parse_function_helper(ast_type_t type0, ast_type_t type1, - size_t argc, xpath_ast_node* args[2]) { - assert(argc <= 1); - - if (argc == 1 && args[0]->rettype() != xpath_type_node_set) - throw_error("Function has to be applied to node set"); - - return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, - xpath_type_string, args[0]); - } - - xpath_ast_node* parse_function(const xpath_lexer_string& name, size_t argc, - xpath_ast_node* args[2]) { - switch (name.begin[0]) { - case 'b': - if (name == PUGIXML_TEXT("boolean") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_boolean, - xpath_type_boolean, args[0]); - - break; - - case 'c': - if (name == PUGIXML_TEXT("count") && argc == 1) { - if (args[0]->rettype() != xpath_type_node_set) - throw_error("Function has to be applied to node set"); - return new (alloc_node()) xpath_ast_node(ast_func_count, - xpath_type_number, args[0]); - } else if (name == PUGIXML_TEXT("contains") && argc == 2) - return new (alloc_node()) xpath_ast_node(ast_func_contains, - xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("concat") && argc >= 2) - return new (alloc_node()) xpath_ast_node(ast_func_concat, - xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("ceiling") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_ceiling, - xpath_type_number, args[0]); - - break; - - case 'f': - if (name == PUGIXML_TEXT("false") && argc == 0) - return new (alloc_node()) xpath_ast_node(ast_func_false, - xpath_type_boolean); - else if (name == PUGIXML_TEXT("floor") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_floor, - xpath_type_number, args[0]); - - break; - - case 'i': - if (name == PUGIXML_TEXT("id") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_id, - xpath_type_node_set, args[0]); - - break; - - case 'l': - if (name == PUGIXML_TEXT("last") && argc == 0) - return new (alloc_node()) xpath_ast_node(ast_func_last, - xpath_type_number); - else if (name == PUGIXML_TEXT("lang") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_lang, - xpath_type_boolean, args[0]); - else if (name == PUGIXML_TEXT("local-name") && argc <= 1) - return parse_function_helper(ast_func_local_name_0, - ast_func_local_name_1, argc, args); - - break; - - case 'n': - if (name == PUGIXML_TEXT("name") && argc <= 1) - return parse_function_helper(ast_func_name_0, ast_func_name_1, - argc, args); - else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1) - return parse_function_helper(ast_func_namespace_uri_0, - ast_func_namespace_uri_1, argc, args); - else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1) - return new (alloc_node()) xpath_ast_node( - argc == 0 ? - ast_func_normalize_space_0 : - ast_func_normalize_space_1, xpath_type_string, - args[0], args[1]); - else if (name == PUGIXML_TEXT("not") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_not, - xpath_type_boolean, args[0]); - else if (name == PUGIXML_TEXT("number") && argc <= 1) - return new (alloc_node()) xpath_ast_node( - argc == 0 ? ast_func_number_0 : ast_func_number_1, - xpath_type_number, args[0]); - - break; - - case 'p': - if (name == PUGIXML_TEXT("position") && argc == 0) - return new (alloc_node()) xpath_ast_node(ast_func_position, - xpath_type_number); - - break; - - case 'r': - if (name == PUGIXML_TEXT("round") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_round, - xpath_type_number, args[0]); - - break; - - case 's': - if (name == PUGIXML_TEXT("string") && argc <= 1) - return new (alloc_node()) xpath_ast_node( - argc == 0 ? ast_func_string_0 : ast_func_string_1, - xpath_type_string, args[0]); - else if (name == PUGIXML_TEXT("string-length") && argc <= 1) - return new (alloc_node()) xpath_ast_node( - argc == 0 ? - ast_func_string_length_0 : - ast_func_string_length_1, xpath_type_string, - args[0]); - else if (name == PUGIXML_TEXT("starts-with") && argc == 2) - return new (alloc_node()) xpath_ast_node(ast_func_starts_with, - xpath_type_boolean, args[0], args[1]); - else if (name == PUGIXML_TEXT("substring-before") && argc == 2) - return new (alloc_node()) xpath_ast_node( - ast_func_substring_before, xpath_type_string, args[0], - args[1]); - else if (name == PUGIXML_TEXT("substring-after") && argc == 2) - return new (alloc_node()) xpath_ast_node( - ast_func_substring_after, xpath_type_string, args[0], - args[1]); - else if (name == PUGIXML_TEXT("substring") - && (argc == 2 || argc == 3)) - return new (alloc_node()) xpath_ast_node( - argc == 2 ? ast_func_substring_2 : ast_func_substring_3, - xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("sum") && argc == 1) { - if (args[0]->rettype() != xpath_type_node_set) - throw_error("Function has to be applied to node set"); - return new (alloc_node()) xpath_ast_node(ast_func_sum, - xpath_type_number, args[0]); - } - - break; - - case 't': - if (name == PUGIXML_TEXT("translate") && argc == 3) - return new (alloc_node()) xpath_ast_node(ast_func_translate, - xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("true") && argc == 0) - return new (alloc_node()) xpath_ast_node(ast_func_true, - xpath_type_boolean); - - break; - } - - throw_error("Unrecognized function or wrong parameter count"); - - return 0; - } - - axis_t parse_axis_name(const xpath_lexer_string& name, bool& specified) { - specified = true; - - switch (name.begin[0]) { - case 'a': - if (name == PUGIXML_TEXT("ancestor")) - return axis_ancestor; - else if (name == PUGIXML_TEXT("ancestor-or-self")) - return axis_ancestor_or_self; - else if (name == PUGIXML_TEXT("attribute")) - return axis_attribute; - - break; - - case 'c': - if (name == PUGIXML_TEXT("child")) - return axis_child; - - break; - - case 'd': - if (name == PUGIXML_TEXT("descendant")) - return axis_descendant; - else if (name == PUGIXML_TEXT("descendant-or-self")) - return axis_descendant_or_self; - - break; - - case 'f': - if (name == PUGIXML_TEXT("following")) - return axis_following; - else if (name == PUGIXML_TEXT("following-sibling")) - return axis_following_sibling; - - break; - - case 'n': - if (name == PUGIXML_TEXT("namespace")) - return axis_namespace; - - break; - - case 'p': - if (name == PUGIXML_TEXT("parent")) - return axis_parent; - else if (name == PUGIXML_TEXT("preceding")) - return axis_preceding; - else if (name == PUGIXML_TEXT("preceding-sibling")) - return axis_preceding_sibling; - - break; - - case 's': - if (name == PUGIXML_TEXT("self")) - return axis_self; - - break; - } - - specified = false; - return axis_child; - } - - nodetest_t parse_node_test_type(const xpath_lexer_string& name) { - switch (name.begin[0]) { - case 'c': - if (name == PUGIXML_TEXT("comment")) - return nodetest_type_comment; - - break; - - case 'n': - if (name == PUGIXML_TEXT("node")) - return nodetest_type_node; - - break; - - case 'p': - if (name == PUGIXML_TEXT("processing-instruction")) - return nodetest_type_pi; - - break; - - case 't': - if (name == PUGIXML_TEXT("text")) - return nodetest_type_text; - - break; - } - - return nodetest_none; - } - - // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall - xpath_ast_node* parse_primary_expression() { - switch (_lexer.current()) { - case lex_var_ref: { - xpath_lexer_string name = _lexer.contents(); - - if (!_variables) - throw_error("Unknown variable: variable set is not provided"); - - xpath_variable* var = get_variable(_variables, name.begin, - name.end); - - if (!var) - throw_error( - "Unknown variable: variable set does not contain the given name"); - - _lexer.next(); - - return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), - var); - } - - case lex_open_brace: { - _lexer.next(); - - xpath_ast_node* n = parse_expression(); - - if (_lexer.current() != lex_close_brace) - throw_error("Unmatched braces"); - - _lexer.next(); - - return n; - } - - case lex_quoted_string: { - const char_t* value = alloc_string(_lexer.contents()); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node( - ast_string_constant, xpath_type_string, value); - _lexer.next(); - - return n; - } - - case lex_number: { - double value = 0; - - if (!convert_string_to_number(_lexer.contents().begin, - _lexer.contents().end, &value)) - throw_error_oom(); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node( - ast_number_constant, xpath_type_number, value); - _lexer.next(); - - return n; - } - - case lex_string: { - xpath_ast_node* args[2] = { 0 }; - size_t argc = 0; - - xpath_lexer_string function = _lexer.contents(); - _lexer.next(); - - xpath_ast_node* last_arg = 0; - - if (_lexer.current() != lex_open_brace) - throw_error("Unrecognized function call"); - _lexer.next(); - - if (_lexer.current() != lex_close_brace) - args[argc++] = parse_expression(); - - while (_lexer.current() != lex_close_brace) { - if (_lexer.current() != lex_comma) - throw_error("No comma between function arguments"); - _lexer.next(); - - xpath_ast_node* n = parse_expression(); - - if (argc < 2) - args[argc] = n; - else - last_arg->set_next(n); - - argc++; - last_arg = n; - } - - _lexer.next(); - - return parse_function(function, argc, args); - } - - default: - throw_error("Unrecognizable primary expression"); - - return 0; - } - } - - // FilterExpr ::= PrimaryExpr | FilterExpr Predicate - // Predicate ::= '[' PredicateExpr ']' - // PredicateExpr ::= Expr - xpath_ast_node* parse_filter_expression() { - xpath_ast_node* n = parse_primary_expression(); - - while (_lexer.current() == lex_open_square_brace) { - _lexer.next(); - - xpath_ast_node* expr = parse_expression(); - - if (n->rettype() != xpath_type_node_set) - throw_error("Predicate has to be applied to node set"); - - bool posinv = expr->rettype() != xpath_type_number - && expr->is_posinv(); - - n = new (alloc_node()) xpath_ast_node( - posinv ? ast_filter_posinv : ast_filter, - xpath_type_node_set, n, expr); - - if (_lexer.current() != lex_close_square_brace) - throw_error("Unmatched square brace"); - - _lexer.next(); - } - - return n; - } - - // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep - // AxisSpecifier ::= AxisName '::' | '@'? - // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')' - // NameTest ::= '*' | NCName ':' '*' | QName - // AbbreviatedStep ::= '.' | '..' - xpath_ast_node* parse_step(xpath_ast_node* set) { - if (set && set->rettype() != xpath_type_node_set) - throw_error("Step has to be applied to node set"); - - bool axis_specified = false; - axis_t axis = axis_child; // implied child axis - - if (_lexer.current() == lex_axis_attribute) { - axis = axis_attribute; - axis_specified = true; - - _lexer.next(); - } else if (_lexer.current() == lex_dot) { - _lexer.next(); - - return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, - nodetest_type_node, 0); - } else if (_lexer.current() == lex_double_dot) { - _lexer.next(); - - return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, - nodetest_type_node, 0); - } - - nodetest_t nt_type = nodetest_none; - xpath_lexer_string nt_name; - - if (_lexer.current() == lex_string) { - // node name test - nt_name = _lexer.contents(); - _lexer.next(); - - // was it an axis name? - if (_lexer.current() == lex_double_colon) { - // parse axis name - if (axis_specified) - throw_error("Two axis specifiers in one step"); - - axis = parse_axis_name(nt_name, axis_specified); - - if (!axis_specified) - throw_error("Unknown axis"); - - // read actual node test - _lexer.next(); - - if (_lexer.current() == lex_multiply) { - nt_type = nodetest_all; - nt_name = xpath_lexer_string(); - _lexer.next(); - } else if (_lexer.current() == lex_string) { - nt_name = _lexer.contents(); - _lexer.next(); - } else - throw_error("Unrecognized node test"); - } - - if (nt_type == nodetest_none) { - // node type test or processing-instruction - if (_lexer.current() == lex_open_brace) { - _lexer.next(); - - if (_lexer.current() == lex_close_brace) { - _lexer.next(); - - nt_type = parse_node_test_type(nt_name); - - if (nt_type == nodetest_none) - throw_error("Unrecognized node type"); - - nt_name = xpath_lexer_string(); - } else if (nt_name == PUGIXML_TEXT("processing-instruction")) { - if (_lexer.current() != lex_quoted_string) - throw_error( - "Only literals are allowed as arguments to processing-instruction()"); - - nt_type = nodetest_pi; - nt_name = _lexer.contents(); - _lexer.next(); - - if (_lexer.current() != lex_close_brace) - throw_error( - "Unmatched brace near processing-instruction()"); - _lexer.next(); - } else - throw_error("Unmatched brace near node type test"); - - } - // QName or NCName:* - else { - if (nt_name.end - nt_name.begin > 2 - && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:* - { - nt_name.end--; // erase * - - nt_type = nodetest_all_in_namespace; - } else - nt_type = nodetest_name; - } - } - } else if (_lexer.current() == lex_multiply) { - nt_type = nodetest_all; - _lexer.next(); - } else - throw_error("Unrecognized node test"); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, - axis, nt_type, alloc_string(nt_name)); - - xpath_ast_node* last = 0; - - while (_lexer.current() == lex_open_square_brace) { - _lexer.next(); - - xpath_ast_node* expr = parse_expression(); - - xpath_ast_node* pred = new (alloc_node()) xpath_ast_node( - ast_predicate, xpath_type_node_set, expr); - - if (_lexer.current() != lex_close_square_brace) - throw_error("Unmatched square brace"); - _lexer.next(); - - if (last) - last->set_next(pred); - else - n->set_right(pred); - - last = pred; - } - - return n; - } - - // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step - xpath_ast_node* parse_relative_location_path(xpath_ast_node* set) { - xpath_ast_node* n = parse_step(set); - - while (_lexer.current() == lex_slash - || _lexer.current() == lex_double_slash) { - lexeme_t l = _lexer.current(); - _lexer.next(); - - if (l == lex_double_slash) - n = new (alloc_node()) xpath_ast_node(ast_step, n, - axis_descendant_or_self, nodetest_type_node, 0); - - n = parse_step(n); - } - - return n; - } - - // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath - // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath - xpath_ast_node* parse_location_path() { - if (_lexer.current() == lex_slash) { - _lexer.next(); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, - xpath_type_node_set); - - // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path - lexeme_t l = _lexer.current(); - - if (l == lex_string || l == lex_axis_attribute || l == lex_dot - || l == lex_double_dot || l == lex_multiply) - return parse_relative_location_path(n); - else - return n; - } else if (_lexer.current() == lex_double_slash) { - _lexer.next(); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, - xpath_type_node_set); - n = new (alloc_node()) xpath_ast_node(ast_step, n, - axis_descendant_or_self, nodetest_type_node, 0); - - return parse_relative_location_path(n); - } - - // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1 - return parse_relative_location_path(0); - } - - // PathExpr ::= LocationPath - // | FilterExpr - // | FilterExpr '/' RelativeLocationPath - // | FilterExpr '//' RelativeLocationPath - xpath_ast_node* parse_path_expression() { - // Clarification. - // PathExpr begins with either LocationPath or FilterExpr. - // FilterExpr begins with PrimaryExpr - // PrimaryExpr begins with '$' in case of it being a variable reference, - // '(' in case of it being an expression, string literal, number constant or - // function call. - - if (_lexer.current() == lex_var_ref - || _lexer.current() == lex_open_brace - || _lexer.current() == lex_quoted_string - || _lexer.current() == lex_number - || _lexer.current() == lex_string) { - if (_lexer.current() == lex_string) { - // This is either a function call, or not - if not, we shall proceed with location path - const char_t* state = _lexer.state(); - - while (IS_CHARTYPE(*state, ct_space)) - ++state; - - if (*state != '(') - return parse_location_path(); - - // This looks like a function call; however this still can be a node-test. Check it. - if (parse_node_test_type(_lexer.contents()) != nodetest_none) - return parse_location_path(); - } - - xpath_ast_node* n = parse_filter_expression(); - - if (_lexer.current() == lex_slash - || _lexer.current() == lex_double_slash) { - lexeme_t l = _lexer.current(); - _lexer.next(); - - if (l == lex_double_slash) { - if (n->rettype() != xpath_type_node_set) - throw_error("Step has to be applied to node set"); - - n = new (alloc_node()) xpath_ast_node(ast_step, n, - axis_descendant_or_self, nodetest_type_node, 0); - } - - // select from location path - return parse_relative_location_path(n); - } - - return n; - } else - return parse_location_path(); - } - - // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr - xpath_ast_node* parse_union_expression() { - xpath_ast_node* n = parse_path_expression(); - - while (_lexer.current() == lex_union) { - _lexer.next(); - - xpath_ast_node* expr = parse_union_expression(); - - if (n->rettype() != xpath_type_node_set - || expr->rettype() != xpath_type_node_set) - throw_error("Union operator has to be applied to node sets"); - - n = new (alloc_node()) xpath_ast_node(ast_op_union, - xpath_type_node_set, n, expr); - } - - return n; - } - - // UnaryExpr ::= UnionExpr | '-' UnaryExpr - xpath_ast_node* parse_unary_expression() { - if (_lexer.current() == lex_minus) { - _lexer.next(); - - xpath_ast_node* expr = parse_unary_expression(); - - return new (alloc_node()) xpath_ast_node(ast_op_negate, - xpath_type_number, expr); - } else - return parse_union_expression(); - } - - // MultiplicativeExpr ::= UnaryExpr - // | MultiplicativeExpr '*' UnaryExpr - // | MultiplicativeExpr 'div' UnaryExpr - // | MultiplicativeExpr 'mod' UnaryExpr - xpath_ast_node* parse_multiplicative_expression() { - xpath_ast_node* n = parse_unary_expression(); - - while (_lexer.current() == lex_multiply - || (_lexer.current() == lex_string - && (_lexer.contents() == PUGIXML_TEXT("mod") - || _lexer.contents() == PUGIXML_TEXT("div")))) { - ast_type_t op = - _lexer.current() == lex_multiply ? ast_op_multiply : - _lexer.contents().begin[0] == 'd' ? - ast_op_divide : ast_op_mod; - _lexer.next(); - - xpath_ast_node* expr = parse_unary_expression(); - - n = new (alloc_node()) xpath_ast_node(op, xpath_type_number, n, - expr); - } - - return n; - } - - // AdditiveExpr ::= MultiplicativeExpr - // | AdditiveExpr '+' MultiplicativeExpr - // | AdditiveExpr '-' MultiplicativeExpr - xpath_ast_node* parse_additive_expression() { - xpath_ast_node* n = parse_multiplicative_expression(); - - while (_lexer.current() == lex_plus || _lexer.current() == lex_minus) { - lexeme_t l = _lexer.current(); - - _lexer.next(); - - xpath_ast_node* expr = parse_multiplicative_expression(); - - n = new (alloc_node()) xpath_ast_node( - l == lex_plus ? ast_op_add : ast_op_subtract, - xpath_type_number, n, expr); - } - - return n; - } - - // RelationalExpr ::= AdditiveExpr - // | RelationalExpr '<' AdditiveExpr - // | RelationalExpr '>' AdditiveExpr - // | RelationalExpr '<=' AdditiveExpr - // | RelationalExpr '>=' AdditiveExpr - xpath_ast_node* parse_relational_expression() { - xpath_ast_node* n = parse_additive_expression(); - - while (_lexer.current() == lex_less - || _lexer.current() == lex_less_or_equal - || _lexer.current() == lex_greater - || _lexer.current() == lex_greater_or_equal) { - lexeme_t l = _lexer.current(); - _lexer.next(); - - xpath_ast_node* expr = parse_additive_expression(); - - n = new (alloc_node()) xpath_ast_node( - l == lex_less ? ast_op_less : - l == lex_greater ? ast_op_greater : - l == lex_less_or_equal ? - ast_op_less_or_equal : ast_op_greater_or_equal, - xpath_type_boolean, n, expr); - } - - return n; - } - - // EqualityExpr ::= RelationalExpr - // | EqualityExpr '=' RelationalExpr - // | EqualityExpr '!=' RelationalExpr - xpath_ast_node* parse_equality_expression() { - xpath_ast_node* n = parse_relational_expression(); - - while (_lexer.current() == lex_equal - || _lexer.current() == lex_not_equal) { - lexeme_t l = _lexer.current(); - - _lexer.next(); - - xpath_ast_node* expr = parse_relational_expression(); - - n = new (alloc_node()) xpath_ast_node( - l == lex_equal ? ast_op_equal : ast_op_not_equal, - xpath_type_boolean, n, expr); - } - - return n; - } - - // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr - xpath_ast_node* parse_and_expression() { - xpath_ast_node* n = parse_equality_expression(); - - while (_lexer.current() == lex_string - && _lexer.contents() == PUGIXML_TEXT("and")) { - _lexer.next(); - - xpath_ast_node* expr = parse_equality_expression(); - - n = new (alloc_node()) xpath_ast_node(ast_op_and, - xpath_type_boolean, n, expr); - } - - return n; - } - - // OrExpr ::= AndExpr | OrExpr 'or' AndExpr - xpath_ast_node* parse_or_expression() { - xpath_ast_node* n = parse_and_expression(); - - while (_lexer.current() == lex_string - && _lexer.contents() == PUGIXML_TEXT("or")) { - _lexer.next(); - - xpath_ast_node* expr = parse_and_expression(); - - n = new (alloc_node()) xpath_ast_node(ast_op_or, xpath_type_boolean, - n, expr); - } - - return n; - } - - // Expr ::= OrExpr - xpath_ast_node* parse_expression() { - return parse_or_expression(); - } - - xpath_parser(const char_t* query, xpath_variable_set* variables, - xpath_allocator* alloc, xpath_parse_result* result) : - _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result( - result) { - } - - xpath_ast_node* parse() { - xpath_ast_node* result = parse_expression(); - - if (_lexer.current() != lex_eof) { - // there are still unparsed tokens left, error - throw_error("Incorrect query"); - } - - return result; - } - - static xpath_ast_node* parse(const char_t* query, - xpath_variable_set* variables, xpath_allocator* alloc, - xpath_parse_result* result) { - xpath_parser parser(query, variables, alloc, result); - -#ifdef PUGIXML_NO_EXCEPTIONS - int error = setjmp(parser._error_handler); - - return (error == 0) ? parser.parse() : 0; -#else - return parser.parse(); -#endif - } -}; - -struct xpath_query_impl { - static xpath_query_impl* create() { - void* memory = global_allocate(sizeof(xpath_query_impl)); - - return new (memory) xpath_query_impl(); - } - - static void destroy(void* ptr) { - if (!ptr) - return; - - // free all allocated pages - static_cast(ptr)->alloc.release(); - - // free allocator memory (with the first page) - global_deallocate(ptr); - } - - xpath_query_impl() : - root(0), alloc(&block) { - block.next = 0; - } - - xpath_ast_node* root; - xpath_allocator alloc; - xpath_memory_block block; -}; - -xpath_string evaluate_string_impl(xpath_query_impl* impl, const xpath_node& n, - xpath_stack_data& sd) { - if (!impl) - return xpath_string(); - -#ifdef PUGIXML_NO_EXCEPTIONS - if (setjmp(sd.error_handler)) return xpath_string(); -#endif - - xpath_context c(n, 1, 1); - - return impl->root->eval_string(c, sd.stack); -} -} - -namespace pugi { -#ifndef PUGIXML_NO_EXCEPTIONS -xpath_exception::xpath_exception(const xpath_parse_result& result) : - _result(result) { - assert(result.error); -} - -const char* xpath_exception::what() const throw () { - return _result.error; -} - -const xpath_parse_result& xpath_exception::result() const { - return _result; -} -#endif - -xpath_node::xpath_node() { -} - -xpath_node::xpath_node(const xml_node& node) : - _node(node) { -} - -xpath_node::xpath_node(const xml_attribute& attribute, const xml_node& parent) : - _node(attribute ? parent : xml_node()), _attribute(attribute) { -} - -xml_node xpath_node::node() const { - return _attribute ? xml_node() : _node; -} - -xml_attribute xpath_node::attribute() const { - return _attribute; -} - -xml_node xpath_node::parent() const { - return _attribute ? _node : _node.parent(); -} - -xpath_node::operator xpath_node::unspecified_bool_type() const { - return (_node || _attribute) ? &xpath_node::_node : 0; -} - -bool xpath_node::operator!() const { - return !(_node || _attribute); -} - -bool xpath_node::operator==(const xpath_node& n) const { - return _node == n._node && _attribute == n._attribute; -} - -bool xpath_node::operator!=(const xpath_node& n) const { - return _node != n._node || _attribute != n._attribute; -} - -#ifdef __BORLANDC__ -bool operator&&(const xpath_node& lhs, bool rhs) -{ - return (bool)lhs && rhs; -} - -bool operator||(const xpath_node& lhs, bool rhs) -{ - return (bool)lhs || rhs; -} -#endif - -void xpath_node_set::_assign(const_iterator begin, const_iterator end) { - assert(begin <= end); - - size_t size = static_cast(end - begin); - - if (size <= 1) { - // deallocate old buffer - if (_begin != &_storage) - global_deallocate(_begin); - - // use internal buffer - if (begin != end) - _storage = *begin; - - _begin = &_storage; - _end = &_storage + size; - } else { - // make heap copy - xpath_node* storage = static_cast(global_allocate( - size * sizeof(xpath_node))); - - if (!storage) { -#ifdef PUGIXML_NO_EXCEPTIONS - return; -#else - throw std::bad_alloc(); -#endif - } - - memcpy(storage, begin, size * sizeof(xpath_node)); - - // deallocate old buffer - if (_begin != &_storage) - global_deallocate(_begin); - - // finalize - _begin = storage; - _end = storage + size; - } -} - -xpath_node_set::xpath_node_set() : - _type(type_unsorted), _begin(&_storage), _end(&_storage) { -} - -xpath_node_set::xpath_node_set(const_iterator begin, const_iterator end, - type_t type) : - _type(type), _begin(&_storage), _end(&_storage) { - _assign(begin, end); -} - -xpath_node_set::~xpath_node_set() { - if (_begin != &_storage) - global_deallocate(_begin); -} - -xpath_node_set::xpath_node_set(const xpath_node_set& ns) : - _type(ns._type), _begin(&_storage), _end(&_storage) { - _assign(ns._begin, ns._end); -} - -xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns) { - if (this == &ns) - return *this; - - _type = ns._type; - _assign(ns._begin, ns._end); - - return *this; -} - -xpath_node_set::type_t xpath_node_set::type() const { - return _type; -} - -size_t xpath_node_set::size() const { - return _end - _begin; -} - -bool xpath_node_set::empty() const { - return _begin == _end; -} - -const xpath_node& xpath_node_set::operator[](size_t index) const { - assert(index < size()); - return _begin[index]; -} - -xpath_node_set::const_iterator xpath_node_set::begin() const { - return _begin; -} - -xpath_node_set::const_iterator xpath_node_set::end() const { - return _end; -} - -void xpath_node_set::sort(bool reverse) { - _type = xpath_sort(_begin, _end, _type, reverse); -} - -xpath_node xpath_node_set::first() const { - return xpath_first(_begin, _end, _type); -} - -xpath_parse_result::xpath_parse_result() : - error("Internal error"), offset(0) { -} - -xpath_parse_result::operator bool() const { - return error == 0; -} -const char* xpath_parse_result::description() const { - return error ? error : "No error"; -} - -xpath_variable::xpath_variable() { -} - -const char_t* xpath_variable::name() const { - switch (_type) { - case xpath_type_node_set: - return static_cast(this)->name; - - case xpath_type_number: - return static_cast(this)->name; - - case xpath_type_string: - return static_cast(this)->name; - - case xpath_type_boolean: - return static_cast(this)->name; - - default: - assert(!"Invalid variable type"); - return 0; - } -} - -xpath_value_type xpath_variable::type() const { - return _type; -} - -bool xpath_variable::get_boolean() const { - return (_type == xpath_type_boolean) ? - static_cast(this)->value : false; -} - -double xpath_variable::get_number() const { - return (_type == xpath_type_number) ? - static_cast(this)->value : gen_nan(); -} - -const char_t* xpath_variable::get_string() const { - const char_t* value = - (_type == xpath_type_string) ? - static_cast(this)->value : 0; - return value ? value : PUGIXML_TEXT(""); -} - -const xpath_node_set& xpath_variable::get_node_set() const { - return (_type == xpath_type_node_set) ? - static_cast(this)->value : - dummy_node_set; -} - -bool xpath_variable::set(bool value) { - if (_type != xpath_type_boolean) - return false; - - static_cast(this)->value = value; - return true; -} - -bool xpath_variable::set(double value) { - if (_type != xpath_type_number) - return false; - - static_cast(this)->value = value; - return true; -} - -bool xpath_variable::set(const char_t* value) { - if (_type != xpath_type_string) - return false; - - xpath_variable_string* var = static_cast(this); - - // duplicate string - size_t size = (strlength(value) + 1) * sizeof(char_t); - - char_t* copy = static_cast(global_allocate(size)); - if (!copy) - return false; - - memcpy(copy, value, size); - - // replace old string - if (var->value) - global_deallocate(var->value); - var->value = copy; - - return true; -} - -bool xpath_variable::set(const xpath_node_set& value) { - if (_type != xpath_type_node_set) - return false; - - static_cast(this)->value = value; - return true; -} - -xpath_variable_set::xpath_variable_set() { - for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) - _data[i] = 0; -} - -xpath_variable_set::~xpath_variable_set() { - for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) { - xpath_variable* var = _data[i]; - - while (var) { - xpath_variable* next = var->_next; - - delete_xpath_variable(var->_type, var); - - var = next; - } - } -} - -xpath_variable* xpath_variable_set::find(const char_t* name) const { - const size_t hash_size = sizeof(_data) / sizeof(_data[0]); - size_t hash = hash_string(name) % hash_size; - - // look for existing variable - for (xpath_variable* var = _data[hash]; var; var = var->_next) - if (strequal(var->name(), name)) - return var; - - return 0; -} - -xpath_variable* xpath_variable_set::add(const char_t* name, - xpath_value_type type) { - const size_t hash_size = sizeof(_data) / sizeof(_data[0]); - size_t hash = hash_string(name) % hash_size; - - // look for existing variable - for (xpath_variable* var = _data[hash]; var; var = var->_next) - if (strequal(var->name(), name)) - return var->type() == type ? var : 0; - - // add new variable - xpath_variable* result = new_xpath_variable(type, name); - - if (result) { - result->_type = type; - result->_next = _data[hash]; - - _data[hash] = result; - } - - return result; -} - -bool xpath_variable_set::set(const char_t* name, bool value) { - xpath_variable* var = add(name, xpath_type_boolean); - return var ? var->set(value) : false; -} - -bool xpath_variable_set::set(const char_t* name, double value) { - xpath_variable* var = add(name, xpath_type_number); - return var ? var->set(value) : false; -} - -bool xpath_variable_set::set(const char_t* name, const char_t* value) { - xpath_variable* var = add(name, xpath_type_string); - return var ? var->set(value) : false; -} - -bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value) { - xpath_variable* var = add(name, xpath_type_node_set); - return var ? var->set(value) : false; -} - -xpath_variable* xpath_variable_set::get(const char_t* name) { - return find(name); -} - -const xpath_variable* xpath_variable_set::get(const char_t* name) const { - return find(name); -} - -xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables) : - _impl(0) { - xpath_query_impl* impl = xpath_query_impl::create(); - - if (!impl) { -#ifdef PUGIXML_NO_EXCEPTIONS - _result.error = "Out of memory"; -#else - throw std::bad_alloc(); -#endif - } else { - buffer_holder impl_holder(impl, xpath_query_impl::destroy); - - impl->root = xpath_parser::parse(query, variables, &impl->alloc, - &_result); - - if (impl->root) { - _impl = static_cast(impl_holder.release()); - _result.error = 0; - } - } -} - -xpath_query::~xpath_query() { - xpath_query_impl::destroy(_impl); -} - -xpath_value_type xpath_query::return_type() const { - if (!_impl) - return xpath_type_none; - - return static_cast(_impl)->root->rettype(); -} - -bool xpath_query::evaluate_boolean(const xpath_node& n) const { - if (!_impl) - return false; - - xpath_context c(n, 1, 1); - xpath_stack_data sd; - -#ifdef PUGIXML_NO_EXCEPTIONS - if (setjmp(sd.error_handler)) return false; -#endif - - return static_cast(_impl)->root->eval_boolean(c, - sd.stack); -} - -double xpath_query::evaluate_number(const xpath_node& n) const { - if (!_impl) - return gen_nan(); - - xpath_context c(n, 1, 1); - xpath_stack_data sd; - -#ifdef PUGIXML_NO_EXCEPTIONS - if (setjmp(sd.error_handler)) return gen_nan(); -#endif - - return static_cast(_impl)->root->eval_number(c, sd.stack); -} - -#ifndef PUGIXML_NO_STL -string_t xpath_query::evaluate_string(const xpath_node& n) const { - xpath_stack_data sd; - - return evaluate_string_impl(static_cast(_impl), n, sd).c_str(); -} -#endif - -size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, - const xpath_node& n) const { - xpath_stack_data sd; - - xpath_string r = evaluate_string_impl(static_cast(_impl), - n, sd); - - size_t full_size = r.length() + 1; - - if (capacity > 0) { - size_t size = (full_size < capacity) ? full_size : capacity; - assert(size > 0); - - memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t)); - buffer[size - 1] = 0; - } - - return full_size; -} - -xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const { - if (!_impl) - return xpath_node_set(); - - xpath_ast_node* root = static_cast(_impl)->root; - - if (root->rettype() != xpath_type_node_set) { -#ifdef PUGIXML_NO_EXCEPTIONS - return xpath_node_set(); -#else - xpath_parse_result result; - result.error = "Expression does not evaluate to node set"; - - throw xpath_exception(result); -#endif - } - - xpath_context c(n, 1, 1); - xpath_stack_data sd; - -#ifdef PUGIXML_NO_EXCEPTIONS - if (setjmp(sd.error_handler)) return xpath_node_set(); -#endif - - xpath_node_set_raw r = root->eval_node_set(c, sd.stack); - - return xpath_node_set(r.begin(), r.end(), r.type()); -} - -const xpath_parse_result& xpath_query::result() const { - return _result; -} - -xpath_query::operator xpath_query::unspecified_bool_type() const { - return _impl ? &xpath_query::_impl : 0; -} - -bool xpath_query::operator!() const { - return !_impl; -} - -xpath_node xml_node::select_single_node(const char_t* query, - xpath_variable_set* variables) const { - xpath_query q(query, variables); - return select_single_node(q); -} - -xpath_node xml_node::select_single_node(const xpath_query& query) const { - xpath_node_set s = query.evaluate_node_set(*this); - return s.empty() ? xpath_node() : s.first(); -} - -xpath_node_set xml_node::select_nodes(const char_t* query, - xpath_variable_set* variables) const { - xpath_query q(query, variables); - return select_nodes(q); -} - -xpath_node_set xml_node::select_nodes(const xpath_query& query) const { - return query.evaluate_node_set(*this); -} -} - -#endif - -/** - * Copyright (c) 2006-2010 Arseny Kapoulkine - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ diff --git a/libs/pugixml/pugixml.hpp b/libs/pugixml/pugixml.hpp deleted file mode 100644 index 436099628..000000000 --- a/libs/pugixml/pugixml.hpp +++ /dev/null @@ -1,1131 +0,0 @@ -/** - * pugixml parser - version 1.0 - * -------------------------------------------------------- - * Copyright (C) 2006-2010, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) - * Report bugs and download new versions at http://pugixml.org/ - * - * This library is distributed under the MIT License. See notice at the end - * of this file. - * - * This work is based on the pugxml parser, which is: - * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) - */ - -#ifndef HEADER_PUGIXML_HPP -#define HEADER_PUGIXML_HPP - -#include "pugiconfig.hpp" - -#ifndef PUGIXML_NO_STL -namespace std -{ - struct bidirectional_iterator_tag; - -#ifdef __SUNPRO_CC - // Sun C++ compiler has a bug which forces template argument names in forward declarations to be the same as in actual definitions - template class allocator; - template struct char_traits; - template class basic_istream; - template class basic_ostream; - template class basic_string; -#else - // Borland C++ compiler has a bug which forces template argument names in forward declarations to be the same as in actual definitions - template class allocator; - template struct char_traits; - template class basic_istream; - template class basic_ostream; - template class basic_string; -#endif - - // Digital Mars compiler has a bug which requires a forward declaration for explicit instantiation (otherwise type selection is messed up later, producing link errors) - // Also note that we have to declare char_traits as a class here, since it's defined that way -#ifdef __DMC__ - template <> class char_traits; -#endif -} -#endif - -// Macro for deprecated features -#ifndef PUGIXML_DEPRECATED -# if defined(__GNUC__) -# define PUGIXML_DEPRECATED __attribute__((deprecated)) -# elif defined(_MSC_VER) && _MSC_VER >= 1300 -# define PUGIXML_DEPRECATED __declspec(deprecated) -# else -# define PUGIXML_DEPRECATED -# endif -#endif - -// Include exception header for XPath -#if !defined(PUGIXML_NO_XPATH) && !defined(PUGIXML_NO_EXCEPTIONS) -# include -#endif - -// If no API is defined, assume default -#ifndef PUGIXML_API -# define PUGIXML_API -#endif - -// If no API for classes is defined, assume default -#ifndef PUGIXML_CLASS -# define PUGIXML_CLASS PUGIXML_API -#endif - -// If no API for functions is defined, assume default -#ifndef PUGIXML_FUNCTION -# define PUGIXML_FUNCTION PUGIXML_API -#endif - -#include - -// Character interface macros -#ifdef PUGIXML_WCHAR_MODE -# define PUGIXML_TEXT(t) L ## t -# define PUGIXML_CHAR wchar_t -#else -# define PUGIXML_TEXT(t) t -# define PUGIXML_CHAR char -#endif - -namespace pugi -{ - // Character type used for all internal storage and operations; depends on PUGIXML_WCHAR_MODE - typedef PUGIXML_CHAR char_t; - -#ifndef PUGIXML_NO_STL - // String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE - typedef std::basic_string, std::allocator > string_t; -#endif -} - -// The PugiXML namespace -namespace pugi -{ - // Tree node types - enum xml_node_type - { - node_null, // Empty (null) node handle - node_document, // A document tree's absolute root - node_element, // Element tag, i.e. '' - node_pcdata, // Plain character data, i.e. 'text' - node_cdata, // Character data, i.e. '' - node_comment, // Comment tag, i.e. '' - node_pi, // Processing instruction, i.e. '' - node_declaration, // Document declaration, i.e. '' - node_doctype // Document type declaration, i.e. '' - }; - - // Parsing options - - // Minimal parsing mode (equivalent to turning all other flags off). - // Only elements and PCDATA sections are added to the DOM tree, no text conversions are performed. - const unsigned int parse_minimal = 0x0000; - - // This flag determines if processing instructions (node_pi) are added to the DOM tree. This flag is off by default. - const unsigned int parse_pi = 0x0001; - - // This flag determines if comments (node_comment) are added to the DOM tree. This flag is off by default. - const unsigned int parse_comments = 0x0002; - - // This flag determines if CDATA sections (node_cdata) are added to the DOM tree. This flag is on by default. - const unsigned int parse_cdata = 0x0004; - - // This flag determines if plain character data (node_pcdata) that consist only of whitespace are added to the DOM tree. - // This flag is off by default; turning it on usually results in slower parsing and more memory consumption. - const unsigned int parse_ws_pcdata = 0x0008; - - // This flag determines if character and entity references are expanded during parsing. This flag is on by default. - const unsigned int parse_escapes = 0x0010; - - // This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default. - const unsigned int parse_eol = 0x0020; - - // This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default. - const unsigned int parse_wconv_attribute = 0x0040; - - // This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default. - const unsigned int parse_wnorm_attribute = 0x0080; - - // This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default. - const unsigned int parse_declaration = 0x0100; - - // This flag determines if document type declaration (node_doctype) is added to the DOM tree. This flag is off by default. - const unsigned int parse_doctype = 0x0200; - - // The default parsing mode. - // Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded, - // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. - const unsigned int parse_default = parse_cdata | parse_escapes | parse_wconv_attribute | parse_eol; - - // The full parsing mode. - // Nodes of all types are added to the DOM tree, character/reference entities are expanded, - // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. - const unsigned int parse_full = parse_default | parse_pi | parse_comments | parse_declaration | parse_doctype; - - // These flags determine the encoding of input data for XML document - enum xml_encoding - { - encoding_auto, // Auto-detect input encoding using BOM or < / >& stream); - xml_writer_stream(std::basic_ostream >& stream); - - virtual void write(const void* data, size_t size); - - private: - std::basic_ostream >* narrow_stream; - std::basic_ostream >* wide_stream; - }; - #endif - - // A light-weight handle for manipulating attributes in DOM tree - class PUGIXML_CLASS xml_attribute - { - friend class xml_attribute_iterator; - friend class xml_node; - - private: - xml_attribute_struct* _attr; - - typedef xml_attribute_struct* xml_attribute::*unspecified_bool_type; - - public: - // Default constructor. Constructs an empty attribute. - xml_attribute(); - - // Constructs attribute from internal pointer - explicit xml_attribute(xml_attribute_struct* attr); - - // Safe bool conversion operator - operator unspecified_bool_type() const; - - // Borland C++ workaround - bool operator!() const; - - // Comparison operators (compares wrapped attribute pointers) - bool operator==(const xml_attribute& r) const; - bool operator!=(const xml_attribute& r) const; - bool operator<(const xml_attribute& r) const; - bool operator>(const xml_attribute& r) const; - bool operator<=(const xml_attribute& r) const; - bool operator>=(const xml_attribute& r) const; - - // Check if attribute is empty - bool empty() const; - - // Get attribute name/value, or "" if attribute is empty - const char_t* name() const; - const char_t* value() const; - - // Get attribute value as a number, or 0 if conversion did not succeed or attribute is empty - int as_int() const; - unsigned int as_uint() const; - double as_double() const; - float as_float() const; - - // Get attribute value as bool (returns true if first character is in '1tTyY' set), or false if attribute is empty - bool as_bool() const; - - // Set attribute name/value (returns false if attribute is empty or there is not enough memory) - bool set_name(const char_t* rhs); - bool set_value(const char_t* rhs); - - // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") - bool set_value(int rhs); - bool set_value(unsigned int rhs); - bool set_value(double rhs); - bool set_value(bool rhs); - - // Set attribute value (equivalent to set_value without error checking) - xml_attribute& operator=(const char_t* rhs); - xml_attribute& operator=(int rhs); - xml_attribute& operator=(unsigned int rhs); - xml_attribute& operator=(double rhs); - xml_attribute& operator=(bool rhs); - - // Get next/previous attribute in the attribute list of the parent node - xml_attribute next_attribute() const; - xml_attribute previous_attribute() const; - - // Get hash value (unique for handles to the same object) - size_t hash_value() const; - - // Get internal pointer - xml_attribute_struct* internal_object() const; - }; - -#ifdef __BORLANDC__ - // Borland C++ workaround - bool PUGIXML_FUNCTION operator&&(const xml_attribute& lhs, bool rhs); - bool PUGIXML_FUNCTION operator||(const xml_attribute& lhs, bool rhs); -#endif - - // A light-weight handle for manipulating nodes in DOM tree - class PUGIXML_CLASS xml_node - { - friend class xml_attribute_iterator; - friend class xml_node_iterator; - - protected: - xml_node_struct* _root; - - typedef xml_node_struct* xml_node::*unspecified_bool_type; - - public: - // Default constructor. Constructs an empty node. - xml_node(); - - // Constructs node from internal pointer - explicit xml_node(xml_node_struct* p); - - // Safe bool conversion operator - operator unspecified_bool_type() const; - - // Borland C++ workaround - bool operator!() const; - - // Comparison operators (compares wrapped node pointers) - bool operator==(const xml_node& r) const; - bool operator!=(const xml_node& r) const; - bool operator<(const xml_node& r) const; - bool operator>(const xml_node& r) const; - bool operator<=(const xml_node& r) const; - bool operator>=(const xml_node& r) const; - - // Check if node is empty. - bool empty() const; - - // Get node type - xml_node_type type() const; - - // Get node name/value, or "" if node is empty or it has no name/value - const char_t* name() const; - const char_t* value() const; - - // Get attribute list - xml_attribute first_attribute() const; - xml_attribute last_attribute() const; - - // Get children list - xml_node first_child() const; - xml_node last_child() const; - - // Get next/previous sibling in the children list of the parent node - xml_node next_sibling() const; - xml_node previous_sibling() const; - - // Get parent node - xml_node parent() const; - - // Get root of DOM tree this node belongs to - xml_node root() const; - - // Get child, attribute or next/previous sibling with the specified name - xml_node child(const char_t* name) const; - xml_attribute attribute(const char_t* name) const; - xml_node next_sibling(const char_t* name) const; - xml_node previous_sibling(const char_t* name) const; - - // Get child value of current node; that is, value of the first child node of type PCDATA/CDATA - const char_t* child_value() const; - - // Get child value of child with specified name. Equivalent to child(name).child_value(). - const char_t* child_value(const char_t* name) const; - - // Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value) - bool set_name(const char_t* rhs); - bool set_value(const char_t* rhs); - - // Add attribute with specified name. Returns added attribute, or empty attribute on errors. - xml_attribute append_attribute(const char_t* name); - xml_attribute prepend_attribute(const char_t* name); - xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr); - xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr); - - // Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors. - xml_attribute append_copy(const xml_attribute& proto); - xml_attribute prepend_copy(const xml_attribute& proto); - xml_attribute insert_copy_after(const xml_attribute& proto, const xml_attribute& attr); - xml_attribute insert_copy_before(const xml_attribute& proto, const xml_attribute& attr); - - // Add child node with specified type. Returns added node, or empty node on errors. - xml_node append_child(xml_node_type type = node_element); - xml_node prepend_child(xml_node_type type = node_element); - xml_node insert_child_after(xml_node_type type, const xml_node& node); - xml_node insert_child_before(xml_node_type type, const xml_node& node); - - // Add child element with specified name. Returns added node, or empty node on errors. - xml_node append_child(const char_t* name); - xml_node prepend_child(const char_t* name); - xml_node insert_child_after(const char_t* name, const xml_node& node); - xml_node insert_child_before(const char_t* name, const xml_node& node); - - // Add a copy of the specified node as a child. Returns added node, or empty node on errors. - xml_node append_copy(const xml_node& proto); - xml_node prepend_copy(const xml_node& proto); - xml_node insert_copy_after(const xml_node& proto, const xml_node& node); - xml_node insert_copy_before(const xml_node& proto, const xml_node& node); - - // Remove specified attribute - bool remove_attribute(const xml_attribute& a); - bool remove_attribute(const char_t* name); - - // Remove specified child - bool remove_child(const xml_node& n); - bool remove_child(const char_t* name); - - // Find attribute using predicate. Returns first attribute for which predicate returned true. - template xml_attribute find_attribute(Predicate pred) const - { - if (!_root) return xml_attribute(); - - for (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute()) - if (pred(attrib)) - return attrib; - - return xml_attribute(); - } - - // Find child node using predicate. Returns first child for which predicate returned true. - template xml_node find_child(Predicate pred) const - { - if (!_root) return xml_node(); - - for (xml_node node = first_child(); node; node = node.next_sibling()) - if (pred(node)) - return node; - - return xml_node(); - } - - // Find node from subtree using predicate. Returns first node from subtree (depth-first), for which predicate returned true. - template xml_node find_node(Predicate pred) const - { - if (!_root) return xml_node(); - - xml_node cur = first_child(); - - while (cur._root && cur._root != _root) - { - if (pred(cur)) return cur; - - if (cur.first_child()) cur = cur.first_child(); - else if (cur.next_sibling()) cur = cur.next_sibling(); - else - { - while (!cur.next_sibling() && cur._root != _root) cur = cur.parent(); - - if (cur._root != _root) cur = cur.next_sibling(); - } - } - - return xml_node(); - } - - // Find child node by attribute name/value - xml_node find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const; - xml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const; - - #ifndef PUGIXML_NO_STL - // Get the absolute node path from root as a text string. - string_t path(char_t delimiter = '/') const; - #endif - - // Search for a node by path consisting of node names and . or .. elements. - xml_node first_element_by_path(const char_t* path, char_t delimiter = '/') const; - - // Recursively traverse subtree with xml_tree_walker - bool traverse(xml_tree_walker& walker); - - #ifndef PUGIXML_NO_XPATH - // Select single node by evaluating XPath query. Returns first node from the resulting node set. - xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const; - xpath_node select_single_node(const xpath_query& query) const; - - // Select node set by evaluating XPath query - xpath_node_set select_nodes(const char_t* query, xpath_variable_set* variables = 0) const; - xpath_node_set select_nodes(const xpath_query& query) const; - #endif - - // Print subtree using a writer object - void print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; - - #ifndef PUGIXML_NO_STL - // Print subtree to stream - void print(std::basic_ostream >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; - void print(std::basic_ostream >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, unsigned int depth = 0) const; - #endif - - // Child nodes iterators - typedef xml_node_iterator iterator; - - iterator begin() const; - iterator end() const; - - // Attribute iterators - typedef xml_attribute_iterator attribute_iterator; - - attribute_iterator attributes_begin() const; - attribute_iterator attributes_end() const; - - // Get node offset in parsed file/string (in char_t units) for debugging purposes - ptrdiff_t offset_debug() const; - - // Get hash value (unique for handles to the same object) - size_t hash_value() const; - - // Get internal pointer - xml_node_struct* internal_object() const; - }; - -#ifdef __BORLANDC__ - // Borland C++ workaround - bool PUGIXML_FUNCTION operator&&(const xml_node& lhs, bool rhs); - bool PUGIXML_FUNCTION operator||(const xml_node& lhs, bool rhs); -#endif - - // Child node iterator (a bidirectional iterator over a collection of xml_node) - class PUGIXML_CLASS xml_node_iterator - { - friend class xml_node; - - private: - xml_node _wrap; - xml_node _parent; - - xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent); - - public: - // Iterator traits - typedef ptrdiff_t difference_type; - typedef xml_node value_type; - typedef xml_node* pointer; - typedef xml_node& reference; - - #ifndef PUGIXML_NO_STL - typedef std::bidirectional_iterator_tag iterator_category; - #endif - - // Default constructor - xml_node_iterator(); - - // Construct an iterator which points to the specified node - xml_node_iterator(const xml_node& node); - - // Iterator operators - bool operator==(const xml_node_iterator& rhs) const; - bool operator!=(const xml_node_iterator& rhs) const; - - xml_node& operator*(); - xml_node* operator->(); - - const xml_node_iterator& operator++(); - xml_node_iterator operator++(int); - - const xml_node_iterator& operator--(); - xml_node_iterator operator--(int); - }; - - // Attribute iterator (a bidirectional iterator over a collection of xml_attribute) - class PUGIXML_CLASS xml_attribute_iterator - { - friend class xml_node; - - private: - xml_attribute _wrap; - xml_node _parent; - - xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent); - - public: - // Iterator traits - typedef ptrdiff_t difference_type; - typedef xml_attribute value_type; - typedef xml_attribute* pointer; - typedef xml_attribute& reference; - - #ifndef PUGIXML_NO_STL - typedef std::bidirectional_iterator_tag iterator_category; - #endif - - // Default constructor - xml_attribute_iterator(); - - // Construct an iterator which points to the specified attribute - xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent); - - // Iterator operators - bool operator==(const xml_attribute_iterator& rhs) const; - bool operator!=(const xml_attribute_iterator& rhs) const; - - xml_attribute& operator*(); - xml_attribute* operator->(); - - const xml_attribute_iterator& operator++(); - xml_attribute_iterator operator++(int); - - const xml_attribute_iterator& operator--(); - xml_attribute_iterator operator--(int); - }; - - // Abstract tree walker class (see xml_node::traverse) - class PUGIXML_CLASS xml_tree_walker - { - friend class xml_node; - - private: - int _depth; - - protected: - // Get current traversal depth - int depth() const; - - public: - xml_tree_walker(); - virtual ~xml_tree_walker(); - - // Callback that is called when traversal begins - virtual bool begin(xml_node& node); - - // Callback that is called for each node traversed - virtual bool for_each(xml_node& node) = 0; - - // Callback that is called when traversal ends - virtual bool end(xml_node& node); - }; - - // Parsing status, returned as part of xml_parse_result object - enum xml_parse_status - { - status_ok = 0, // No error - - status_file_not_found, // File was not found during load_file() - status_io_error, // Error reading from file/stream - status_out_of_memory, // Could not allocate memory - status_internal_error, // Internal error occurred - - status_unrecognized_tag, // Parser could not determine tag type - - status_bad_pi, // Parsing error occurred while parsing document declaration/processing instruction - status_bad_comment, // Parsing error occurred while parsing comment - status_bad_cdata, // Parsing error occurred while parsing CDATA section - status_bad_doctype, // Parsing error occurred while parsing document type declaration - status_bad_pcdata, // Parsing error occurred while parsing PCDATA section - status_bad_start_element, // Parsing error occurred while parsing start element tag - status_bad_attribute, // Parsing error occurred while parsing element attribute - status_bad_end_element, // Parsing error occurred while parsing end element tag - status_end_element_mismatch // There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag) - }; - - // Parsing result - struct PUGIXML_CLASS xml_parse_result - { - // Parsing status (see xml_parse_status) - xml_parse_status status; - - // Last parsed offset (in char_t units from start of input data) - ptrdiff_t offset; - - // Source document encoding - xml_encoding encoding; - - // Default constructor, initializes object to failed state - xml_parse_result(); - - // Cast to bool operator - operator bool() const; - - // Get error description - const char* description() const; - }; - - // Document class (DOM tree root) - class PUGIXML_CLASS xml_document: public xml_node - { - private: - char_t* _buffer; - - char _memory[192]; - - // Non-copyable semantics - xml_document(const xml_document&); - const xml_document& operator=(const xml_document&); - - void create(); - void destroy(); - - xml_parse_result load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own); - - public: - // Default constructor, makes empty document - xml_document(); - - // Destructor, invalidates all node/attribute handles to this document - ~xml_document(); - - // Removes all nodes, leaving the empty document - void reset(); - - // Removes all nodes, then copies the entire contents of the specified document - void reset(const xml_document& proto); - - #ifndef PUGIXML_NO_STL - // Load document from stream. - xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default); - #endif - - // Load document from zero-terminated string. No encoding conversions are applied. - xml_parse_result load(const char_t* contents, unsigned int options = parse_default); - - // Load document from file - xml_parse_result load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - xml_parse_result load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - - // Load document from buffer. Copies/converts the buffer, so it may be deleted or changed after the function returns. - xml_parse_result load_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - - // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). - // You should ensure that buffer data will persist throughout the document's lifetime, and free the buffer memory manually once document is destroyed. - xml_parse_result load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - - // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). - // You should allocate the buffer with pugixml allocation function; document will free the buffer when it is no longer needed (you can't use it anymore). - xml_parse_result load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - - // Save XML document to writer (semantics is slightly different from xml_node::print, see documentation for details). - void save(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; - - #ifndef PUGIXML_NO_STL - // Save XML document to stream (semantics is slightly different from xml_node::print, see documentation for details). - void save(std::basic_ostream >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; - void save(std::basic_ostream >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default) const; - #endif - - // Save XML to file - bool save_file(const char* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; - bool save_file(const wchar_t* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; - - // Get document element - xml_node document_element() const; - }; - -#ifndef PUGIXML_NO_XPATH - // XPath query return type - enum xpath_value_type - { - xpath_type_none, // Unknown type (query failed to compile) - xpath_type_node_set, // Node set (xpath_node_set) - xpath_type_number, // Number - xpath_type_string, // String - xpath_type_boolean // Boolean - }; - - // XPath parsing result - struct PUGIXML_CLASS xpath_parse_result - { - // Error message (0 if no error) - const char* error; - - // Last parsed offset (in char_t units from string start) - ptrdiff_t offset; - - // Default constructor, initializes object to failed state - xpath_parse_result(); - - // Cast to bool operator - operator bool() const; - - // Get error description - const char* description() const; - }; - - // A single XPath variable - class PUGIXML_CLASS xpath_variable - { - friend class xpath_variable_set; - - protected: - xpath_value_type _type; - xpath_variable* _next; - - xpath_variable(); - - // Non-copyable semantics - xpath_variable(const xpath_variable&); - xpath_variable& operator=(const xpath_variable&); - - public: - // Get variable name - const char_t* name() const; - - // Get variable type - xpath_value_type type() const; - - // Get variable value; no type conversion is performed, default value (false, NaN, empty string, empty node set) is returned on type mismatch error - bool get_boolean() const; - double get_number() const; - const char_t* get_string() const; - const xpath_node_set& get_node_set() const; - - // Set variable value; no type conversion is performed, false is returned on type mismatch error - bool set(bool value); - bool set(double value); - bool set(const char_t* value); - bool set(const xpath_node_set& value); - }; - - // A set of XPath variables - class PUGIXML_CLASS xpath_variable_set - { - private: - xpath_variable* _data[64]; - - // Non-copyable semantics - xpath_variable_set(const xpath_variable_set&); - xpath_variable_set& operator=(const xpath_variable_set&); - - xpath_variable* find(const char_t* name) const; - - public: - // Default constructor/destructor - xpath_variable_set(); - ~xpath_variable_set(); - - // Add a new variable or get the existing one, if the types match - xpath_variable* add(const char_t* name, xpath_value_type type); - - // Set value of an existing variable; no type conversion is performed, false is returned if there is no such variable or if types mismatch - bool set(const char_t* name, bool value); - bool set(const char_t* name, double value); - bool set(const char_t* name, const char_t* value); - bool set(const char_t* name, const xpath_node_set& value); - - // Get existing variable by name - xpath_variable* get(const char_t* name); - const xpath_variable* get(const char_t* name) const; - }; - - // A compiled XPath query object - class PUGIXML_CLASS xpath_query - { - private: - void* _impl; - xpath_parse_result _result; - - typedef void* xpath_query::*unspecified_bool_type; - - // Non-copyable semantics - xpath_query(const xpath_query&); - xpath_query& operator=(const xpath_query&); - - public: - // Construct a compiled object from XPath expression. - // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on compilation errors. - explicit xpath_query(const char_t* query, xpath_variable_set* variables = 0); - - // Destructor - ~xpath_query(); - - // Get query expression return type - xpath_value_type return_type() const; - - // Evaluate expression as boolean value in the specified context; performs type conversion if necessary. - // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. - bool evaluate_boolean(const xpath_node& n) const; - - // Evaluate expression as double value in the specified context; performs type conversion if necessary. - // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. - double evaluate_number(const xpath_node& n) const; - - #ifndef PUGIXML_NO_STL - // Evaluate expression as string value in the specified context; performs type conversion if necessary. - // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. - string_t evaluate_string(const xpath_node& n) const; - #endif - - // Evaluate expression as string value in the specified context; performs type conversion if necessary. - // At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero). - // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. - // If PUGIXML_NO_EXCEPTIONS is defined, returns empty set instead. - size_t evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const; - - // Evaluate expression as node set in the specified context. - // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors. - // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node set instead. - xpath_node_set evaluate_node_set(const xpath_node& n) const; - - // Get parsing result (used to get compilation errors in PUGIXML_NO_EXCEPTIONS mode) - const xpath_parse_result& result() const; - - // Safe bool conversion operator - operator unspecified_bool_type() const; - - // Borland C++ workaround - bool operator!() const; - }; - - #ifndef PUGIXML_NO_EXCEPTIONS - // XPath exception class - class PUGIXML_CLASS xpath_exception: public std::exception - { - private: - xpath_parse_result _result; - - public: - // Construct exception from parse result - explicit xpath_exception(const xpath_parse_result& result); - - // Get error message - virtual const char* what() const throw(); - - // Get parse result - const xpath_parse_result& result() const; - }; - #endif - - // XPath node class (either xml_node or xml_attribute) - class PUGIXML_CLASS xpath_node - { - private: - xml_node _node; - xml_attribute _attribute; - - typedef xml_node xpath_node::*unspecified_bool_type; - - public: - // Default constructor; constructs empty XPath node - xpath_node(); - - // Construct XPath node from XML node/attribute - xpath_node(const xml_node& node); - xpath_node(const xml_attribute& attribute, const xml_node& parent); - - // Get node/attribute, if any - xml_node node() const; - xml_attribute attribute() const; - - // Get parent of contained node/attribute - xml_node parent() const; - - // Safe bool conversion operator - operator unspecified_bool_type() const; - - // Borland C++ workaround - bool operator!() const; - - // Comparison operators - bool operator==(const xpath_node& n) const; - bool operator!=(const xpath_node& n) const; - }; - -#ifdef __BORLANDC__ - // Borland C++ workaround - bool PUGIXML_FUNCTION operator&&(const xpath_node& lhs, bool rhs); - bool PUGIXML_FUNCTION operator||(const xpath_node& lhs, bool rhs); -#endif - - // A fixed-size collection of XPath nodes - class PUGIXML_CLASS xpath_node_set - { - public: - // Collection type - enum type_t - { - type_unsorted, // Not ordered - type_sorted, // Sorted by document order (ascending) - type_sorted_reverse // Sorted by document order (descending) - }; - - // Constant iterator type - typedef const xpath_node* const_iterator; - - // Default constructor. Constructs empty set. - xpath_node_set(); - - // Constructs a set from iterator range; data is not checked for duplicates and is not sorted according to provided type, so be careful - xpath_node_set(const_iterator begin, const_iterator end, type_t type = type_unsorted); - - // Destructor - ~xpath_node_set(); - - // Copy constructor/assignment operator - xpath_node_set(const xpath_node_set& ns); - xpath_node_set& operator=(const xpath_node_set& ns); - - // Get collection type - type_t type() const; - - // Get collection size - size_t size() const; - - // Indexing operator - const xpath_node& operator[](size_t index) const; - - // Collection iterators - const_iterator begin() const; - const_iterator end() const; - - // Sort the collection in ascending/descending order by document order - void sort(bool reverse = false); - - // Get first node in the collection by document order - xpath_node first() const; - - // Check if collection is empty - bool empty() const; - - private: - type_t _type; - - xpath_node _storage; - - xpath_node* _begin; - xpath_node* _end; - - void _assign(const_iterator begin, const_iterator end); - }; -#endif - -#ifndef PUGIXML_NO_STL - // Convert wide string to UTF8 - std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const wchar_t* str); - std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const std::basic_string, std::allocator >& str); - - // Convert UTF8 to wide string - std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const char* str); - std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const std::basic_string, std::allocator >& str); -#endif - - // Memory allocation function interface; returns pointer to allocated memory or NULL on failure - typedef void* (*allocation_function)(size_t size); - - // Memory deallocation function interface - typedef void (*deallocation_function)(void* ptr); - - // Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions. - void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate); - - // Get current memory management functions - allocation_function PUGIXML_FUNCTION get_memory_allocation_function(); - deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function(); -} - -#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) -namespace std -{ - // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) - std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_node_iterator&); - std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_attribute_iterator&); -} -#endif - -#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) -namespace std -{ - // Workarounds for (non-standard) iterator category detection - std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_node_iterator&); - std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_attribute_iterator&); -} -#endif - -#endif - -/** - * Copyright (c) 2006-2010 Arseny Kapoulkine - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ From ac0b44cd443de21e53db922c61cd5267daffd645 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 22 May 2012 19:42:37 +0200 Subject: [PATCH 0108/1298] update CMakeLists remove FindFreeGlut.cmake remove FindGSL.cmake remove FindOpenGl.cmake --- CMakeLists.txt | 107 ++++++++++++---------------- cmake/FindFFTW3F.cmake | 4 +- cmake/FindFreeGlut.cmake | 68 ------------------ cmake/FindGSL.cmake | 150 --------------------------------------- cmake/FindOpenGl.cmake | 136 ----------------------------------- 5 files changed, 47 insertions(+), 418 deletions(-) delete mode 100644 cmake/FindFreeGlut.cmake delete mode 100644 cmake/FindGSL.cmake delete mode 100644 cmake/FindOpenGl.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index e03354317..240e84daf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,48 +8,6 @@ set(MPC_EXTRA_INCLUDES) set(MPC_EXTRA_LIBRARIES) set(MPC_SWIG_DEFINES) -# GSL required -find_package(GSL REQUIRED) -list(APPEND MPC_EXTRA_LIBRARIES ${GSL_LIBRARIES} ${GSLCBLAS_LIBRARIES}) -list(APPEND MPC_EXTRA_INCLUDES ${GSL_INCLUDE_DIR}) - -# fftw3f needed for TurbulentMagneticField -find_package(FFTW3F) -if (FFTW3F_FOUND) - message(STATUS "FFTW3F found!") - list(APPEND MPC_EXTRA_SOURCES src/magneticField/TurbulentMagneticField.cpp) - list(APPEND MPC_EXTRA_LIBRARIES ${FFTW3F_LIBRARY}) -else(FFTW3F_FOUND) - message(STATUS "FFTW3F NOT found!") -endif (FFTW3F_FOUND) - -# gadget needed for SPHMagneticField and SPHTurbulentMagneticField -find_package(Gadget) -if (GADGET_FOUND) - list(APPEND MPC_EXTRA_SOURCES src/magneticField/SPHMagneticField.cpp) - list(APPEND MPC_EXTRA_INCLUDES ${GADGET_INCLUDE_DIR}) - list(APPEND MPC_EXTRA_LIBRARIES ${GADGET_LIBRARY}) - add_definitions (-DMPC_HAVE_GADGET) - list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_GADGET) - # fftw3f needed for SPHTurbulentMagneticField - if (FFTW3F_FOUND) - list(APPEND MPC_EXTRA_SOURCES src/magneticField/SPHTurbulentMagneticField.cpp) - endif (FFTW3F_FOUND) -endif (GADGET_FOUND) - -# Google Performance Tools optional -find_package(GooglePerfTools) -set(TCMALLOC) -if (GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) - set(TCMALLOC ${TCMALLOC_LIBRARY}) -endif(GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) - -# pugixml provided -add_library (pugixml libs/pugixml/pugixml.cpp) -set_target_properties( pugixml PROPERTIES COMPILE_FLAGS -fPIC) -list(APPEND MPC_EXTRA_LIBRARIES pugixml) -list(APPEND MPC_EXTRA_INCLUDES libs/pugixml) - # kiss provided add_subdirectory(libs/kiss) list(APPEND MPC_EXTRA_LIBRARIES kiss) @@ -73,8 +31,28 @@ if(OPENMP_FOUND) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") endif() +# fftw3f needed for TurbulentMagneticField +find_package(FFTW3F) +if (FFTW3F_FOUND) + list(APPEND MPC_EXTRA_SOURCES src/magneticField/TurbulentMagneticField.cpp) + list(APPEND MPC_EXTRA_LIBRARIES ${FFTW3F_LIBRARY}) +endif (FFTW3F_FOUND) + +# gadget needed for SPHMagneticField and SPHTurbulentMagneticField +find_package(Gadget) +if (GADGET_FOUND) + list(APPEND MPC_EXTRA_SOURCES src/magneticField/SPHMagneticField.cpp) + list(APPEND MPC_EXTRA_INCLUDES ${GADGET_INCLUDE_DIR}) + list(APPEND MPC_EXTRA_LIBRARIES ${GADGET_LIBRARY}) + add_definitions (-DMPC_HAVE_GADGET) + list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_GADGET) + # fftw3f needed for SPHTurbulentMagneticField + if (FFTW3F_FOUND) + list(APPEND MPC_EXTRA_SOURCES src/magneticField/SPHTurbulentMagneticField.cpp) + endif (FFTW3F_FOUND) +endif (GADGET_FOUND) + include_directories(include ${MPC_EXTRA_INCLUDES}) -add_definitions(-DMPC_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") # ---------------------------------------------------------------------------- # mpc and mpc-run @@ -105,11 +83,12 @@ add_library(mpc SHARED src/magneticField/MagneticFieldGrid.cpp ${MPC_EXTRA_SOURCES} ) -target_link_libraries(mpc ${MPC_EXTRA_LIBRARIES} ${TCMALLOC}) +target_link_libraries(mpc ${MPC_EXTRA_LIBRARIES}) add_executable(mpc-run src/main.cpp) -target_link_libraries(mpc-run mpc ${TCMALLOC}) +target_link_libraries(mpc-run mpc) +add_definitions(-DMPC_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") install(TARGETS mpc-run RUNTIME DESTINATION bin) install(TARGETS mpc DESTINATION lib) install(DIRECTORY include/ DESTINATION include FILES_MATCHING PATTERN "*.h") @@ -118,25 +97,27 @@ install(DIRECTORY data/ DESTINATION share/mpc) # ---------------------------------------------------------------------------- # Testing using gTest # ---------------------------------------------------------------------------- -find_package(GTest) -if (GTEST_FOUND) - enable_testing() - - add_executable(testCore test/testCore.cpp) - target_link_libraries(testCore mpc ${GTEST_BOTH_LIBRARIES} pthread) - - add_executable(testMagneticField test/testMagneticField.cpp) - target_link_libraries(testMagneticField mpc ${GTEST_BOTH_LIBRARIES} pthread) - - add_executable(testPropagation test/testPropagation.cpp) - target_link_libraries(testPropagation mpc ${GTEST_BOTH_LIBRARIES} pthread) - - add_executable(testBreakCondition test/testBreakCondition.cpp) - target_link_libraries(testBreakCondition mpc ${GTEST_BOTH_LIBRARIES} pthread) +OPTION(ENABLETESTING "Build tests and enable test target" ON) +if(ENABLETESTING) + #enable_testing() + include_directories(libs/gtest/include) + add_subdirectory(libs/gtest) + + add_executable(testCore test/testCore.cpp) + target_link_libraries(testCore mpc gtest gtest_main pthread) + + add_executable(testMagneticField test/testMagneticField.cpp) + target_link_libraries(testMagneticField mpc gtest gtest_main pthread) + + add_executable(testPropagation test/testPropagation.cpp) + target_link_libraries(testPropagation mpc gtest gtest_main pthread) - add_executable(testInteraction test/testInteraction.cpp) - target_link_libraries(testInteraction mpc ${GTEST_BOTH_LIBRARIES} pthread) -endif (GTEST_FOUND) + add_executable(testBreakCondition test/testBreakCondition.cpp) + target_link_libraries(testBreakCondition mpc gtest gtest_main pthread) + + add_executable(testInteraction test/testInteraction.cpp) + target_link_libraries(testInteraction mpc gtest gtest_main pthread) +endif(ENABLETESTING) # ---------------------------------------------------------------------------- # Python diff --git a/cmake/FindFFTW3F.cmake b/cmake/FindFFTW3F.cmake index aed570a49..ac2082579 100644 --- a/cmake/FindFFTW3F.cmake +++ b/cmake/FindFFTW3F.cmake @@ -12,6 +12,8 @@ if(FFTW3F_INCLUDE_DIR AND FFTW3F_LIBRARY) MESSAGE("-- Found FFTW3 with single precision (FFTW3F):\n" "-- Include: ${FFTW3F_INCLUDE_DIR}\n" "-- Library: ${FFTW3F_LIBRARY}") +else() + MESSAGE("-- Could not find FFTW3 with single precision (FFTW3F)") endif() -mark_as_advanced(FFTW3F_INCLUDE_DIR FFTW3F_LIBRARY FFTW3F_FOUND) \ No newline at end of file +mark_as_advanced(FFTW3F_INCLUDE_DIR FFTW3F_LIBRARY FFTW3F_FOUND) diff --git a/cmake/FindFreeGlut.cmake b/cmake/FindFreeGlut.cmake deleted file mode 100644 index 38e298399..000000000 --- a/cmake/FindFreeGlut.cmake +++ /dev/null @@ -1,68 +0,0 @@ -# try to find glut library and include files -# Freeglut_INCLUDE_DIR, where to find GL/glut.h, etc. -# Freeglut_LIBRARIES, the libraries to link against -# Freeglut_FOUND, If false, do not try to use Freeglut. -# Also defined, but not for general use are: -# Freeglut_glut_LIBRARY = the full path to the glut library. - -#============================================================================= -# Copyright 2001-2009 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -IF (WIN32) - FIND_PATH( Freeglut_INCLUDE_DIR NAMES GL/freeglut.h - PATHS ${Freeglut_ROOT_PATH}/include ) - FIND_LIBRARY( Freeglut_glut_LIBRARY NAMES glut glut32 freeglut freeglut_static - PATHS - ${OPENGL_LIBRARY_DIR} - ${Freeglut_ROOT_PATH}/Release - ) -ELSE (WIN32) - IF (APPLE) - # These values for Apple could probably do with improvement. - FIND_PATH( Freeglut_INCLUDE_DIR freeglut.h - /System/Library/Frameworks/Freeglut.framework/Versions/A/Headers - ${OPENGL_LIBRARY_DIR} - ) - SET(Freeglut_glut_LIBRARY "-framework Freeglut" CACHE STRING "Freeglut library for OSX") - SET(Freeglut_cocoa_LIBRARY "-framework Cocoa" CACHE STRING "Cocoa framework for OSX") - ELSE (APPLE) - FIND_PATH( Freeglut_INCLUDE_DIR GL/freeglut.h - /usr/include/GL - /usr/openwin/share/include - /usr/openwin/include - /opt/graphics/OpenGL/include - /opt/graphics/OpenGL/contrib/libglut - ) - - FIND_LIBRARY( Freeglut_glut_LIBRARY glut - /usr/openwin/lib - ) - ENDIF (APPLE) -ENDIF (WIN32) - -SET( Freeglut_FOUND "NO" ) -IF(Freeglut_INCLUDE_DIR) - IF(Freeglut_glut_LIBRARY) - SET( Freeglut_LIBRARIES - ${Freeglut_glut_LIBRARY} - ${Freeglut_cocoa_LIBRARY} - ) - SET( Freeglut_FOUND "YES" ) - - ENDIF(Freeglut_glut_LIBRARY) -ENDIF(Freeglut_INCLUDE_DIR) - -MARK_AS_ADVANCED( - Freeglut_INCLUDE_DIR - Freeglut_glut_LIBRARY - ) \ No newline at end of file diff --git a/cmake/FindGSL.cmake b/cmake/FindGSL.cmake deleted file mode 100644 index 4f4d31bf5..000000000 --- a/cmake/FindGSL.cmake +++ /dev/null @@ -1,150 +0,0 @@ -# Script found on KDE-edu list -# Permission obtained from Jan Woetzel to use under a BSD-style license -# (left to OpenCog to determine the specific BSD license, but this file should -# be included in CMake proper soon...). -# -# Look for the header file -# Try to find gnu scientific library GSL -# See -# http://www.gnu.org/software/gsl/ and -# http://gnuwin32.sourceforge.net/packages/gsl.htm -# -# Once run this will define: -# -# GSL_FOUND = system has GSL lib -# -# GSL_LIBRARIES = full path to the libraries -# on Unix/Linux with additional linker flags from "gsl-config --libs" -# -# CMAKE_GSL_CXX_FLAGS = Unix compiler flags for GSL, essentially "`gsl-config --cxxflags`" -# -# GSL_INCLUDE_DIR = where to find headers -# -# GSL_LINK_DIRECTORIES = link directories, useful for rpath on Unix -# GSL_EXE_LINKER_FLAGS = rpath on Unix -# -# Felix Woelk 07/2004 -# Jan Woetzel -# -# www.mip.informatik.uni-kiel.de -# -------------------------------- - -IF(WIN32) - # JW tested with gsl-1.8, Windows XP, MSVS 7.1 - SET(GSL_POSSIBLE_ROOT_DIRS - ${GSL_ROOT_DIR} - $ENV{GSL_ROOT_DIR} - ${GSL_DIR} - ${GSL_HOME} - $ENV{GSL_DIR} - $ENV{GSL_HOME} - $ENV{EXTRA} - ) - FIND_PATH(GSL_INCLUDE_DIR - NAMES gsl/gsl_cdf.h gsl/gsl_randist.h - PATHS ${GSL_POSSIBLE_ROOT_DIRS} - PATH_SUFFIXES include - DOC "GSL header include dir" - ) - - FIND_LIBRARY(GSL_GSL_LIBRARY - NAMES gsl libgsl - PATHS ${GSL_POSSIBLE_ROOT_DIRS} - PATH_SUFFIXES lib - DOC "GSL library dir" ) - - FIND_LIBRARY(GSL_GSLCBLAS_LIBRARY - NAMES gslcblas libgslcblas - PATHS ${GSL_POSSIBLE_ROOT_DIRS} - PATH_SUFFIXES lib - DOC "GSL cblas library dir" ) - - SET(GSL_LIBRARIES ${GSL_GSL_LIBRARY}) - - #MESSAGE("DBG\n" - # "GSL_GSL_LIBRARY=${GSL_GSL_LIBRARY}\n" - # "GSL_GSLCBLAS_LIBRARY=${GSL_GSLCBLAS_LIBRARY}\n" - # "GSL_LIBRARIES=${GSL_LIBRARIES}") - -ELSE(WIN32) - - IF(UNIX) - SET(GSL_CONFIG_PREFER_PATH - "$ENV{GSL_DIR}/bin" - "$ENV{GSL_DIR}" - "$ENV{GSL_HOME}/bin" - "$ENV{GSL_HOME}" - CACHE STRING "preferred path to GSL (gsl-config)") - FIND_PROGRAM(GSL_CONFIG gsl-config - ${GSL_CONFIG_PREFER_PATH} - /usr/bin/ - ) - # MESSAGE("DBG GSL_CONFIG ${GSL_CONFIG}") - - IF (GSL_CONFIG) - # set CXXFLAGS to be fed into CXX_FLAGS by the user: - SET(GSL_CXX_FLAGS "`${GSL_CONFIG} --cflags`") - - # set INCLUDE_DIRS to prefix+include - EXEC_PROGRAM(${GSL_CONFIG} - ARGS --prefix - OUTPUT_VARIABLE GSL_PREFIX) - SET(GSL_INCLUDE_DIR ${GSL_PREFIX}/include CACHE STRING INTERNAL) - - # set link libraries and link flags - EXEC_PROGRAM(${GSL_CONFIG} - ARGS --libs - OUTPUT_VARIABLE GSL_LIBRARIES) - #SET(GSL_LIBRARIES "`${GSL_CONFIG} --libs`") - - # extract link dirs for rpath - EXEC_PROGRAM(${GSL_CONFIG} - ARGS --libs - OUTPUT_VARIABLE GSL_CONFIG_LIBS ) - - # split off the link dirs (for rpath) - # use regular expression to match wildcard equivalent "-L*" - # with is a space or a semicolon - STRING(REGEX MATCHALL "[-][L]([^ ;])+" - GSL_LINK_DIRECTORIES_WITH_PREFIX - "${GSL_CONFIG_LIBS}" ) - # MESSAGE("DBG GSL_LINK_DIRECTORIES_WITH_PREFIX=${GSL_LINK_DIRECTORIES_WITH_PREFIX}") - - # remove prefix -L because we need the pure directory for LINK_DIRECTORIES - - IF (GSL_LINK_DIRECTORIES_WITH_PREFIX) - STRING(REGEX REPLACE "[-][L]" "" GSL_LINK_DIRECTORIES ${GSL_LINK_DIRECTORIES_WITH_PREFIX} ) - ENDIF (GSL_LINK_DIRECTORIES_WITH_PREFIX) - SET(GSL_EXE_LINKER_FLAGS "-Wl,-rpath,${GSL_LINK_DIRECTORIES}" CACHE STRING INTERNAL) - # MESSAGE("DBG GSL_LINK_DIRECTORIES=${GSL_LINK_DIRECTORIES}") - # MESSAGE("DBG GSL_EXE_LINKER_FLAGS=${GSL_EXE_LINKER_FLAGS}") - - # ADD_DEFINITIONS("-DHAVE_GSL") - # SET(GSL_DEFINITIONS "-DHAVE_GSL") - MARK_AS_ADVANCED( - GSL_CXX_FLAGS - GSL_INCLUDE_DIR - GSL_LIBRARIES - GSL_LINK_DIRECTORIES - GSL_DEFINITIONS - ) - #MESSAGE(STATUS "Using GSL from ${GSL_PREFIX}") - - ELSE(GSL_CONFIG) - MESSAGE("FindGSL.cmake: gsl-config not found. Please set it manually. GSL_CONFIG=${GSL_CONFIG}") - ENDIF(GSL_CONFIG) - - ENDIF(UNIX) -ENDIF(WIN32) - - -IF(GSL_LIBRARIES) - IF(GSL_INCLUDE_DIR OR GSL_CXX_FLAGS) - SET(GSL_FOUND 1) - ENDIF(GSL_INCLUDE_DIR OR GSL_CXX_FLAGS) -ELSE(GSL_LIBRARIES) - IF (GSL_FIND_REQUIRED) - message(SEND_ERROR "FindGSL.cmake: Unable to find the required GSL libraries") - ENDIF(GSL_FIND_REQUIRED) -ENDIF(GSL_LIBRARIES) - diff --git a/cmake/FindOpenGl.cmake b/cmake/FindOpenGl.cmake deleted file mode 100644 index 4a1d0ebb6..000000000 --- a/cmake/FindOpenGl.cmake +++ /dev/null @@ -1,136 +0,0 @@ -# - Try to find OpenGL -# Once done this will define -# -# OPENGL_FOUND - system has OpenGL -# OPENGL_XMESA_FOUND - system has XMESA -# OPENGL_GLU_FOUND - system has GLU -# OPENGL_INCLUDE_DIR - the GL include directory -# OPENGL_LIBRARIES - Link these to use OpenGL and GLU -# -# If you want to use just GL you can use these values -# OPENGL_gl_LIBRARY - Path to OpenGL Library -# OPENGL_glu_LIBRARY - Path to GLU Library -# -# On OSX default to using the framework version of opengl -# People will have to change the cache values of OPENGL_glu_LIBRARY -# and OPENGL_gl_LIBRARY to use OpenGL with X11 on OSX - -IF (WIN32) - IF (CYGWIN) - - FIND_PATH(OPENGL_INCLUDE_DIR GL/gl.h ) - - FIND_LIBRARY(OPENGL_gl_LIBRARY opengl32 ) - - FIND_LIBRARY(OPENGL_glu_LIBRARY glu32 ) - - ELSE (CYGWIN) - - IF(BORLAND) - SET (OPENGL_gl_LIBRARY import32 CACHE STRING "OpenGL library for win32") - SET (OPENGL_glu_LIBRARY import32 CACHE STRING "GLU library for win32") - ELSE(BORLAND) - SET (OPENGL_gl_LIBRARY opengl32 CACHE STRING "OpenGL library for win32") - SET (OPENGL_glu_LIBRARY glu32 CACHE STRING "GLU library for win32") - ENDIF(BORLAND) - - ENDIF (CYGWIN) - -ELSE (WIN32) - - IF (APPLE) - - FIND_LIBRARY(OPENGL_gl_LIBRARY OpenGL DOC "OpenGL lib for OSX") - FIND_LIBRARY(OPENGL_glu_LIBRARY AGL DOC "AGL lib for OSX") - FIND_PATH(OPENGL_INCLUDE_DIR OpenGL/gl.h DOC "Include for OpenGL on OSX") - - ELSE(APPLE) - - # The first line below is to make sure that the proper headers - # are used on a Linux machine with the NVidia drivers installed. - # They replace Mesa with NVidia's own library but normally do not - # install headers and that causes the linking to - # fail since the compiler finds the Mesa headers but NVidia's library. - # Make sure the NVIDIA directory comes BEFORE the others. - # - Atanas Georgiev - - FIND_PATH(OPENGL_INCLUDE_DIR GL/gl.h - /usr/share/doc/NVIDIA_GLX-1.0/include - /usr/openwin/share/include - /opt/graphics/OpenGL/include /usr/X11R6/include - ) - - FIND_PATH(OPENGL_xmesa_INCLUDE_DIR GL/xmesa.h - /usr/share/doc/NVIDIA_GLX-1.0/include - /usr/openwin/share/include - /opt/graphics/OpenGL/include /usr/X11R6/include - ) - - FIND_LIBRARY(OPENGL_gl_LIBRARY - NAMES GL MesaGL - PATHS /opt/graphics/OpenGL/lib - /usr/openwin/lib - /usr/shlib /usr/X11R6/lib - ) - - # On Unix OpenGL most certainly always requires X11. - # Feel free to tighten up these conditions if you don't - # think this is always true. - # It's not true on OSX. - - IF (OPENGL_gl_LIBRARY) - IF(NOT X11_FOUND) - INCLUDE(FindX11) - ENDIF(NOT X11_FOUND) - IF (X11_FOUND) - IF (NOT APPLE) - SET (OPENGL_LIBRARIES ${X11_LIBRARIES}) - ENDIF (NOT APPLE) - ENDIF (X11_FOUND) - ENDIF (OPENGL_gl_LIBRARY) - - FIND_LIBRARY(OPENGL_glu_LIBRARY - NAMES GLU MesaGLU - PATHS ${OPENGL_gl_LIBRARY} - /opt/graphics/OpenGL/lib - /usr/openwin/lib - /usr/shlib /usr/X11R6/lib - ) - - ENDIF(APPLE) -ENDIF (WIN32) - -SET( OPENGL_FOUND "NO" ) -IF(OPENGL_gl_LIBRARY) - - IF(OPENGL_xmesa_INCLUDE_DIR) - SET( OPENGL_XMESA_FOUND "YES" ) - ELSE(OPENGL_xmesa_INCLUDE_DIR) - SET( OPENGL_XMESA_FOUND "NO" ) - ENDIF(OPENGL_xmesa_INCLUDE_DIR) - - SET( OPENGL_LIBRARIES ${OPENGL_gl_LIBRARY} ${OPENGL_LIBRARIES}) - IF(OPENGL_glu_LIBRARY) - SET( OPENGL_GLU_FOUND "YES" ) - SET( OPENGL_LIBRARIES ${OPENGL_glu_LIBRARY} ${OPENGL_LIBRARIES} ) - ELSE(OPENGL_glu_LIBRARY) - SET( OPENGL_GLU_FOUND "NO" ) - ENDIF(OPENGL_glu_LIBRARY) - - SET( OPENGL_FOUND "YES" ) - - # This deprecated setting is for backward compatibility with CMake1.4 - - SET (OPENGL_LIBRARY ${OPENGL_LIBRARIES}) - -ENDIF(OPENGL_gl_LIBRARY) - -# This deprecated setting is for backward compatibility with CMake1.4 -SET(OPENGL_INCLUDE_PATH ${OPENGL_INCLUDE_DIR}) - -MARK_AS_ADVANCED( - OPENGL_INCLUDE_DIR - OPENGL_xmesa_INCLUDE_DIR - OPENGL_glu_LIBRARY - OPENGL_gl_LIBRARY -) \ No newline at end of file From 926821d514f0870e14ed985aad1d7e92970de9e2 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 22 May 2012 19:43:15 +0200 Subject: [PATCH 0109/1298] add interpolatrion test --- python/mpc.i | 39 +++++++++++++++++++++++++-------------- test/testCore.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/python/mpc.i b/python/mpc.i index d6186bb54..ed0a59f6d 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -12,19 +12,6 @@ %include stdint.i %include std_container.i %include "exception.i" -%exception -{ - try - { - $action - } - catch (const std::runtime_error& e) { - SWIG_exception(SWIG_RuntimeError, e.what()); - } - catch (...) { - SWIG_exception(SWIG_RuntimeError, "unknown exception"); - } -} %{ #include "mpc/module/NuclearDecay.h" @@ -62,9 +49,33 @@ #include "mpc/Common.h" %} -/* Parse the header file to generate wrappers */ +%exception +{ + try + { + $action + } + catch (const std::runtime_error& e) { + SWIG_exception(SWIG_RuntimeError, e.what()); + } + catch (...) { + SWIG_exception(SWIG_RuntimeError, "unknown exception"); + } +} + +%ignore operator<<; +%ignore operator>>; + +%ignore operator mpc::Source*; +%ignore operator mpc::Candidate*; +%ignore operator mpc::Module*; +%ignore operator mpc::ModuleList*; +%ignore operator mpc::MagneticField*; +%ignore operator mpc::SpatialPartitioning*; + %feature("ref") mpc::Referenced "$this->addReference();" %feature("unref") mpc::Referenced "$this->removeReference();" + %include "mpc/Referenced.h" %include "mpc/Units.h" %include "mpc/Nucleus.h" diff --git a/test/testCore.cpp b/test/testCore.cpp index a64b10b91..bb5363ac4 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -116,6 +116,38 @@ TEST(common, digit) { EXPECT_EQ(4, digit(1234, 1)); } +TEST(common, interpolate) { + double xD[100]; + double yD[100]; + for (int i=0; i<100; i++) { + xD[i] = 1 + i * 0.02; + yD[i] = pow(xD[i], 2); + } + double yInt = interpolate(1.5001, xD, yD); + EXPECT_NEAR(pow(1.5001, 2), yInt, 1e-4); +} + +TEST(common, interpolateVector) { + std::vector xD, yD; + xD.resize(100); + yD.resize(100); + for (int i=0; i<100; i++) { + xD[i] = 1 + i * 0.02; + yD[i] = pow(xD[i], 2); + } + double yInt = interpolate(1.5001, &xD[0], &yD[0]); + EXPECT_NEAR(pow(1.5001, 2), yInt, 1e-4); +} + +TEST(common, interpolateEquidistant) { + double yD[100]; + for (int i=0; i<100; i++) { + yD[i] = pow(1 + i * 0.02, 2); + } + double yInt = interpolateEquidistant(1.5001, 1, 0.02, yD); + EXPECT_NEAR(pow(1.5001, 2), yInt, 1e-4); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); From 68cff5d501982fa0ab3dbc075fe7320a263f0958 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 23 May 2012 16:21:23 +0200 Subject: [PATCH 0110/1298] fix testTurbulentField script fix SPHTurbulentField --- CMakeLists.txt | 3 +-- src/Common.cpp | 2 +- src/magneticField/SPHTurbulentMagneticField.cpp | 12 ++++++------ src/magneticField/TurbulentMagneticField.cpp | 2 +- test/python/testTurbulentField.py | 4 ++-- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 240e84daf..e3dc3ed8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,11 +95,10 @@ install(DIRECTORY include/ DESTINATION include FILES_MATCHING PATTERN "*.h") install(DIRECTORY data/ DESTINATION share/mpc) # ---------------------------------------------------------------------------- -# Testing using gTest +# Testing # ---------------------------------------------------------------------------- OPTION(ENABLETESTING "Build tests and enable test target" ON) if(ENABLETESTING) - #enable_testing() include_directories(libs/gtest/include) add_subdirectory(libs/gtest) diff --git a/src/Common.cpp b/src/Common.cpp index a96486b69..62b599b32 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -63,7 +63,7 @@ double interpolate(const double x, const double *xD, const double *yD) { double interpolateEquidistant(const double x, const double xLo, const double dx, const double *yD) { double p = (x - xLo) / dx; - size_t i = floor(p); + size_t i = (size_t) floor(p); return yD[i] + (p - i) * (yD[i + 1] - yD[i]); } diff --git a/src/magneticField/SPHTurbulentMagneticField.cpp b/src/magneticField/SPHTurbulentMagneticField.cpp index 213350917..ad8213d9e 100644 --- a/src/magneticField/SPHTurbulentMagneticField.cpp +++ b/src/magneticField/SPHTurbulentMagneticField.cpp @@ -5,17 +5,17 @@ namespace mpc { void SPHTurbulentMagneticField::modulate(const std::string filename) { // create SPH Field to obtain baryon density - SPHMagneticField sphField(origin, spacing * samples, samples, filename); + SPHMagneticField sph(origin, spacing * samples, 100, filename); // modulate and calculate renormalization double norm = 0; - for (int ix; ix < samples; ix++) - for (int iy; iy < samples; iy++) - for (int iz; iz < samples; iz++) { - double rho = sphField.getRho( + for (int ix = 0; ix < samples; ix++) + for (int iy = 0; iy < samples; iy++) + for (int iz = 0; iz < samples; iz++) { + double rho = sph.getRho( Vector3d(ix, iy, iz) * spacing + origin); Vector3f &b = get(ix, iy, iz); - b *= pow(rho, 2./3); + b *= pow(rho, 2. / 3); norm += b.getMag2(); } diff --git a/src/magneticField/TurbulentMagneticField.cpp b/src/magneticField/TurbulentMagneticField.cpp index ccd25d112..fb2939b3b 100644 --- a/src/magneticField/TurbulentMagneticField.cpp +++ b/src/magneticField/TurbulentMagneticField.cpp @@ -15,7 +15,7 @@ void TurbulentMagneticField::initialize(double lMin, double lMax, double Brms, this->powerSpectralIndex = powerSpectralIndex; size_t n = samples; // size of array - size_t n2 = floor(n / 2) + 1; // size array in z-direction in configuration space + size_t n2 = (size_t) floor(n / 2) + 1; // size array in z-direction in configuration space // arrays to hold the complex vector components of the B(k)-field fftwf_complex *Bkx, *Bky, *Bkz; diff --git a/test/python/testTurbulentField.py b/test/python/testTurbulentField.py index f3090d87d..7dc4d0ff2 100644 --- a/test/python/testTurbulentField.py +++ b/test/python/testTurbulentField.py @@ -82,7 +82,8 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): lMin, lMax = 2, 32 Brms = 1 alpha = -11./3 -field = TurbulentMagneticField(Vector3d(0, 0, 0), n, 1, lMin, lMax, Brms, alpha) +field = TurbulentMagneticField(Vector3d(0, 0, 0), n, 1) +field.initialize(lMin, lMax, Brms, alpha) Lc = field.getCorrelationLength() ### copy field to array @@ -94,7 +95,6 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): Bx[ix, iy, iz] = b.x By[ix, iy, iz] = b.y Bz[ix, iy, iz] = b.z -del field ### plot slice in position space slice = n/2 From 0f0cf9507a865d53a15e26f40ea900e6ba9706ae Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 23 May 2012 17:29:02 +0200 Subject: [PATCH 0111/1298] add fftw3f to includes --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e3dc3ed8a..9cfaf20bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ endif() find_package(FFTW3F) if (FFTW3F_FOUND) list(APPEND MPC_EXTRA_SOURCES src/magneticField/TurbulentMagneticField.cpp) + list(APPEND MPC_EXTRA_INCLUDES ${FFTW3F_INCLUDE_DIR}) list(APPEND MPC_EXTRA_LIBRARIES ${FFTW3F_LIBRARY}) endif (FFTW3F_FOUND) From 67b9d237fde04d993df2ec9bbed60c06cbcb9334 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 25 May 2012 11:11:06 +0200 Subject: [PATCH 0112/1298] change CMakeLists fix SPHTurbulentMagneticField --- CMakeLists.txt | 39 +++- libs/gtest/CMakeLists.txt | 192 +----------------- libs/kiss/CMakeLists.txt | 11 +- libs/kiss/test/test_uuid.cpp | 6 +- .../SPHTurbulentMagneticField.cpp | 22 +- test/testMagneticField.cpp | 11 - 6 files changed, 53 insertions(+), 228 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9cfaf20bc..019b66477 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,22 +8,32 @@ set(MPC_EXTRA_INCLUDES) set(MPC_EXTRA_LIBRARIES) set(MPC_SWIG_DEFINES) -# kiss provided +# ---------------------------------------------------------------------------- +# Dependencies +# ---------------------------------------------------------------------------- +# googletest (provided) +OPTION(ENABLETESTING "Build tests and enable test target" ON) +if(ENABLETESTING) + include_directories(libs/gtest/include) + add_subdirectory(libs/gtest) +endif(ENABLETESTING) + +# kiss (provided) add_subdirectory(libs/kiss) list(APPEND MPC_EXTRA_LIBRARIES kiss) list(APPEND MPC_EXTRA_INCLUDES libs/kiss/include) -# HepID provided +# HepID (provided) add_subdirectory(libs/HepPID) list(APPEND MPC_EXTRA_LIBRARIES HepPID) list(APPEND MPC_EXTRA_INCLUDES libs/HepPID/include) -# SOPHIA provided +# SOPHIA (provided) add_subdirectory(libs/sophia) list(APPEND MPC_EXTRA_LIBRARIES sophia gfortran) list(APPEND MPC_EXTRA_INCLUDES libs/sophia) -# OpenMP needed for shared memory multiprocessing +# OpenMP (optional for shared memory multiprocessing) include(FindOpenMP) if(OPENMP_FOUND) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") @@ -31,7 +41,7 @@ if(OPENMP_FOUND) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") endif() -# fftw3f needed for TurbulentMagneticField +# fftw3f (optional for turbulent magnetic fields) find_package(FFTW3F) if (FFTW3F_FOUND) list(APPEND MPC_EXTRA_SOURCES src/magneticField/TurbulentMagneticField.cpp) @@ -39,7 +49,7 @@ if (FFTW3F_FOUND) list(APPEND MPC_EXTRA_LIBRARIES ${FFTW3F_LIBRARY}) endif (FFTW3F_FOUND) -# gadget needed for SPHMagneticField and SPHTurbulentMagneticField +# gadget (optional for SPH magnetic fields) find_package(Gadget) if (GADGET_FOUND) list(APPEND MPC_EXTRA_SOURCES src/magneticField/SPHMagneticField.cpp) @@ -53,11 +63,17 @@ if (GADGET_FOUND) endif (FFTW3F_FOUND) endif (GADGET_FOUND) -include_directories(include ${MPC_EXTRA_INCLUDES}) +# Google Performance Tools (optional as possible performance tweak) +find_package(GooglePerfTools) +set(TCMALLOC) +if (GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) + set(TCMALLOC ${TCMALLOC_LIBRARY}) +endif(GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) # ---------------------------------------------------------------------------- # mpc and mpc-run # ---------------------------------------------------------------------------- +include_directories(include ${MPC_EXTRA_INCLUDES}) add_library(mpc SHARED src/Random.cpp src/Clock.cpp @@ -100,23 +116,26 @@ install(DIRECTORY data/ DESTINATION share/mpc) # ---------------------------------------------------------------------------- OPTION(ENABLETESTING "Build tests and enable test target" ON) if(ENABLETESTING) - include_directories(libs/gtest/include) - add_subdirectory(libs/gtest) - + enable_testing() add_executable(testCore test/testCore.cpp) target_link_libraries(testCore mpc gtest gtest_main pthread) + add_test(testCore testCore) add_executable(testMagneticField test/testMagneticField.cpp) target_link_libraries(testMagneticField mpc gtest gtest_main pthread) + add_test(testMagneticField testMagneticField) add_executable(testPropagation test/testPropagation.cpp) target_link_libraries(testPropagation mpc gtest gtest_main pthread) + add_test(testPropagation testPropagation) add_executable(testBreakCondition test/testBreakCondition.cpp) target_link_libraries(testBreakCondition mpc gtest gtest_main pthread) + add_test(testBreakCondition testBreakCondition) add_executable(testInteraction test/testInteraction.cpp) target_link_libraries(testInteraction mpc gtest gtest_main pthread) + add_test(testInteraction testInteraction) endif(ENABLETESTING) # ---------------------------------------------------------------------------- diff --git a/libs/gtest/CMakeLists.txt b/libs/gtest/CMakeLists.txt index 0fe26540b..ad98748df 100644 --- a/libs/gtest/CMakeLists.txt +++ b/libs/gtest/CMakeLists.txt @@ -1,26 +1,5 @@ ######################################################################## # CMake build script for Google Test. -# -# To run the tests for Google Test itself on Linux, use 'make test' or -# ctest. You can select which tests to run using 'ctest -R regex'. -# For more options, run 'ctest --help'. - -# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to -# make it prominent in the GUI. -option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF) - -# When other libraries are using a shared version of runtime libraries, -# Google Test also has to use one. -option( - gtest_force_shared_crt - "Use shared (DLL) run-time lib even when Google Test is built as static lib." - OFF) - -option(gtest_build_tests "Build all of gtest's own tests." OFF) - -option(gtest_build_samples "Build gtest's sample programs." OFF) - -option(gtest_disable_pthreads "Disable uses of pthreads in gtest." OFF) # Defines pre_project_set_up_hermetic_build() and set_up_hermetic_build(). include(cmake/hermetic_build.cmake OPTIONAL) @@ -32,8 +11,6 @@ endif() ######################################################################## # # Project-wide settings - -# Name of the project. # # CMake files in this project can refer to the root source directory # as ${gtest_SOURCE_DIR} and to the root binary directory as @@ -63,7 +40,7 @@ link_directories(${gtest_BINARY_DIR}/src) # # Defines the gtest & gtest_main libraries. User tests should link # with one of them. - +# # Google Test libraries. We build them using more strict warnings than what # are used for other targets, to ensure that gtest can be compiled by a user # aggressive about warnings. @@ -71,170 +48,3 @@ cxx_library(gtest "${cxx_strict}" src/gtest-all.cc) cxx_library(gtest_main "${cxx_strict}" src/gtest_main.cc) target_link_libraries(gtest_main gtest) -######################################################################## -# -# Samples on how to link user tests with gtest or gtest_main. -# -# They are not built by default. To build them, set the -# gtest_build_samples option to ON. You can do it by running ccmake -# or specifying the -Dbuild_gtest_samples=ON flag when running cmake. - -if (gtest_build_samples) - cxx_executable(sample1_unittest samples gtest_main samples/sample1.cc) - cxx_executable(sample2_unittest samples gtest_main samples/sample2.cc) - cxx_executable(sample3_unittest samples gtest_main) - cxx_executable(sample4_unittest samples gtest_main samples/sample4.cc) - cxx_executable(sample5_unittest samples gtest_main samples/sample1.cc) - cxx_executable(sample6_unittest samples gtest_main) - cxx_executable(sample7_unittest samples gtest_main) - cxx_executable(sample8_unittest samples gtest_main) - cxx_executable(sample9_unittest samples gtest) - cxx_executable(sample10_unittest samples gtest) -endif() - -######################################################################## -# -# Google Test's own tests. -# -# You can skip this section if you aren't interested in testing -# Google Test itself. -# -# The tests are not built by default. To build them, set the -# gtest_build_tests option to ON. You can do it by running ccmake -# or specifying the -Dgtest_build_tests=ON flag when running cmake. - -if (gtest_build_tests) - # This must be set in the root directory for the tests to be run by - # 'make test' or ctest. - enable_testing() - - ############################################################ - # C++ tests built with standard compiler flags. - - cxx_test(gtest-death-test_test gtest_main) - cxx_test(gtest_environment_test gtest) - cxx_test(gtest-filepath_test gtest_main) - cxx_test(gtest-linked_ptr_test gtest_main) - cxx_test(gtest-listener_test gtest_main) - cxx_test(gtest_main_unittest gtest_main) - cxx_test(gtest-message_test gtest_main) - cxx_test(gtest_no_test_unittest gtest) - cxx_test(gtest-options_test gtest_main) - cxx_test(gtest-param-test_test gtest - test/gtest-param-test2_test.cc) - cxx_test(gtest-port_test gtest_main) - cxx_test(gtest_pred_impl_unittest gtest_main) - cxx_test(gtest-printers_test gtest_main) - cxx_test(gtest_prod_test gtest_main - test/production.cc) - cxx_test(gtest_repeat_test gtest) - cxx_test(gtest_sole_header_test gtest_main) - cxx_test(gtest_stress_test gtest) - cxx_test(gtest-test-part_test gtest_main) - cxx_test(gtest_throw_on_failure_ex_test gtest) - cxx_test(gtest-typed-test_test gtest_main - test/gtest-typed-test2_test.cc) - cxx_test(gtest_unittest gtest_main) - cxx_test(gtest-unittest-api_test gtest) - - ############################################################ - # C++ tests built with non-standard compiler flags. - - cxx_library(gtest_no_exception "${cxx_no_exception}" - src/gtest-all.cc) - cxx_library(gtest_main_no_exception "${cxx_no_exception}" - src/gtest-all.cc src/gtest_main.cc) - cxx_library(gtest_main_no_rtti "${cxx_no_rtti}" - src/gtest-all.cc src/gtest_main.cc) - - cxx_test_with_flags(gtest-death-test_ex_nocatch_test - "${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=0" - gtest test/gtest-death-test_ex_test.cc) - cxx_test_with_flags(gtest-death-test_ex_catch_test - "${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=1" - gtest test/gtest-death-test_ex_test.cc) - - cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}" - gtest_main_no_rtti test/gtest_unittest.cc) - - cxx_shared_library(gtest_dll "${cxx_default}" - src/gtest-all.cc src/gtest_main.cc) - - cxx_executable_with_flags(gtest_dll_test_ "${cxx_default}" - gtest_dll test/gtest_all_test.cc) - set_target_properties(gtest_dll_test_ - PROPERTIES - COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") - - if (NOT MSVC OR NOT MSVC_VERSION EQUAL 1600) - # The C++ Standard specifies tuple_element. - # Yet MSVC 10's declares tuple_element. - # That declaration conflicts with our own standard-conforming - # tuple implementation. Therefore using our own tuple with - # MSVC 10 doesn't compile. - cxx_library(gtest_main_use_own_tuple "${cxx_use_own_tuple}" - src/gtest-all.cc src/gtest_main.cc) - - cxx_test_with_flags(gtest-tuple_test "${cxx_use_own_tuple}" - gtest_main_use_own_tuple test/gtest-tuple_test.cc) - - cxx_test_with_flags(gtest_use_own_tuple_test "${cxx_use_own_tuple}" - gtest_main_use_own_tuple - test/gtest-param-test_test.cc test/gtest-param-test2_test.cc) - endif() - - ############################################################ - # Python tests. - - cxx_executable(gtest_break_on_failure_unittest_ test gtest) - py_test(gtest_break_on_failure_unittest) - - cxx_executable_with_flags( - gtest_catch_exceptions_no_ex_test_ - "${cxx_no_exception}" - gtest_main_no_exception - test/gtest_catch_exceptions_test_.cc) - cxx_executable_with_flags( - gtest_catch_exceptions_ex_test_ - "${cxx_exception}" - gtest_main - test/gtest_catch_exceptions_test_.cc) - py_test(gtest_catch_exceptions_test) - - cxx_executable(gtest_color_test_ test gtest) - py_test(gtest_color_test) - - cxx_executable(gtest_env_var_test_ test gtest) - py_test(gtest_env_var_test) - - cxx_executable(gtest_filter_unittest_ test gtest) - py_test(gtest_filter_unittest) - - cxx_executable(gtest_help_test_ test gtest_main) - py_test(gtest_help_test) - - cxx_executable(gtest_list_tests_unittest_ test gtest) - py_test(gtest_list_tests_unittest) - - cxx_executable(gtest_output_test_ test gtest) - py_test(gtest_output_test) - - cxx_executable(gtest_shuffle_test_ test gtest) - py_test(gtest_shuffle_test) - - cxx_executable(gtest_throw_on_failure_test_ test gtest_no_exception) - set_target_properties(gtest_throw_on_failure_test_ - PROPERTIES - COMPILE_FLAGS "${cxx_no_exception}") - py_test(gtest_throw_on_failure_test) - - cxx_executable(gtest_uninitialized_test_ test gtest) - py_test(gtest_uninitialized_test) - - cxx_executable(gtest_xml_outfile1_test_ test gtest_main) - cxx_executable(gtest_xml_outfile2_test_ test gtest_main) - py_test(gtest_xml_outfiles_test) - - cxx_executable(gtest_xml_output_unittest_ test gtest) - py_test(gtest_xml_output_unittest) -endif() diff --git a/libs/kiss/CMakeLists.txt b/libs/kiss/CMakeLists.txt index e839c6718..82a497eb0 100644 --- a/libs/kiss/CMakeLists.txt +++ b/libs/kiss/CMakeLists.txt @@ -11,12 +11,9 @@ add_library(kiss SET_TARGET_PROPERTIES( kiss PROPERTIES COMPILE_FLAGS -fPIC) -# GTest needed for testing -find_package(GTest) -if (GTEST_FOUND) - enable_testing() - +# testing +if(ENABLETESTING) add_executable(test_uuid test/test_uuid.cpp) - target_link_libraries(test_uuid kiss ${GTEST_LIBRARIES} pthread) + target_link_libraries(test_uuid kiss gtest gtest_main pthread) add_test(test_uuid test_uuid) -endif (GTEST_FOUND) +endif(ENABLETESTING) diff --git a/libs/kiss/test/test_uuid.cpp b/libs/kiss/test/test_uuid.cpp index 65d656a21..9f788783b 100644 --- a/libs/kiss/test/test_uuid.cpp +++ b/libs/kiss/test/test_uuid.cpp @@ -1,10 +1,10 @@ #include "kiss/uuid.h" -#include +#include "gtest/gtest.h" using namespace kiss; -TEST(UUID, creation) { +TEST(testUUID, creation) { uuid id1 = uuid::parse("69c09be0-638b-11e1-b86c-0800200c9a66"); uuid id2 = uuid::parse("69c09be0-638b-11e1-b86c-0800200c9a66"); uuid id3 = uuid::parse("69c09be1-638b-11e1-b86c-0800200c9a66"); @@ -13,7 +13,7 @@ TEST(UUID, creation) { EXPECT_NE(id1, id3); } -TEST(UUID, uniqueness) { +TEST(testUUID, uniqueness) { uuid reference = uuid::create(); for (size_t i = 0; i < 100000000; i++) { diff --git a/src/magneticField/SPHTurbulentMagneticField.cpp b/src/magneticField/SPHTurbulentMagneticField.cpp index ad8213d9e..3641f21ba 100644 --- a/src/magneticField/SPHTurbulentMagneticField.cpp +++ b/src/magneticField/SPHTurbulentMagneticField.cpp @@ -1,26 +1,36 @@ #include "mpc/magneticField/SPHTurbulentMagneticField.h" #include "mpc/magneticField/SPHMagneticField.h" +#include "mpc/Units.h" namespace mpc { void SPHTurbulentMagneticField::modulate(const std::string filename) { // create SPH Field to obtain baryon density - SPHMagneticField sph(origin, spacing * samples, 100, filename); + std::cout << "mpc::SPHTurbulentMagneticField: Loading SPH-field." << std::endl; + Vector3d safeOrigin = origin - Vector3d(1,1,1) * kpc; + double safeSize = spacing * samples + 2 * kpc; + SPHMagneticField sph(safeOrigin, safeSize, 32, filename); // modulate and calculate renormalization - double norm = 0; + std::cout << "mpc::SPHTurbulentMagneticField: Modulate turbulent field." << std::endl; + double sumB2 = 0; + int n = 0; for (int ix = 0; ix < samples; ix++) for (int iy = 0; iy < samples; iy++) for (int iz = 0; iz < samples; iz++) { - double rho = sph.getRho( - Vector3d(ix, iy, iz) * spacing + origin); + Vector3d pos = Vector3d(ix, iy, iz) * spacing + origin; + double rho = sph.getRho(pos); Vector3f &b = get(ix, iy, iz); b *= pow(rho, 2. / 3); - norm += b.getMag2(); + double dist = (pos / Mpc - Vector3d(120, 120, 120)).getMag(); + if (dist < 110) { + sumB2 += b.getMag2(); + n++; + } } // renormalize - norm = Brms / sqrt(norm / pow(samples, 3)); + double norm = Brms / sqrt(sumB2 / n); for (int ix = 0; ix < samples; ix++) for (int iy = 0; iy < samples; iy++) for (int iz = 0; iz < samples; iz++) { diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index cdc18d9ad..c99e8701d 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -3,11 +3,6 @@ #include "mpc/magneticField/TurbulentMagneticField.h" #include "mpc/Units.h" -#ifdef MPC_HAVE_GADGET -#include "mpc/magneticField/SPHMagneticField.h" -#include "mpc/magneticField/SPHTurbulentMagneticField.h" -#endif - #include "gtest/gtest.h" namespace mpc { @@ -81,12 +76,6 @@ TEST(testTurbulentMagneticFieldGrid, Brms) { EXPECT_NEAR(brms, 1, precision); } -TEST(testSPHTurbulentMagneticField, construction) { - SPHTurbulentMagneticField bField(Vector3d(80, 80, 80) * Mpc, 64, 40./64); - bField.initialize(2, 8, 1, -11. / 3.); - bField.modulate("/home/walz/software/mpc/data/mhd1.db"); -} - int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); From 2f0ec797c173dfa79828939b91a8268fd690b53c Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 25 May 2012 16:44:22 +0200 Subject: [PATCH 0113/1298] fix bug in turbulent field --- include/mpc/magneticField/SPHTurbulentMagneticField.h | 5 ++++- src/magneticField/TurbulentMagneticField.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/mpc/magneticField/SPHTurbulentMagneticField.h b/include/mpc/magneticField/SPHTurbulentMagneticField.h index 0ce4684a0..03ceb0003 100644 --- a/include/mpc/magneticField/SPHTurbulentMagneticField.h +++ b/include/mpc/magneticField/SPHTurbulentMagneticField.h @@ -3,6 +3,8 @@ #include "mpc/magneticField/TurbulentMagneticField.h" +#ifdef MPC_HAVE_GADGET + namespace mpc { /** @@ -19,4 +21,5 @@ class SPHTurbulentMagneticField: public TurbulentMagneticField { } // namespace mpc -#endif /* MPC_SPHTURBULENTMAGNETICFIELD_H_ */ +#endif // MPC_HAVE_GADGET +#endif // MPC_SPHTURBULENTMAGNETICFIELD_H_ diff --git a/src/magneticField/TurbulentMagneticField.cpp b/src/magneticField/TurbulentMagneticField.cpp index fb2939b3b..29834dc25 100644 --- a/src/magneticField/TurbulentMagneticField.cpp +++ b/src/magneticField/TurbulentMagneticField.cpp @@ -57,7 +57,7 @@ void TurbulentMagneticField::initialize(double lMin, double lMax, double Brms, } // construct an orthogonal base ek, e1, e2 - if (ek.isParallelTo(n0, 1e-6)) { + if (ek.getAngleTo(n0) < 1e-3) { // ek parallel to (1,1,1) e1.setXYZ(-1., 1., 0); e2.setXYZ(1., 1., -2.); From db2c71492824b3613c6a9d2f985bf1db4c3000a0 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 29 May 2012 12:09:17 +0200 Subject: [PATCH 0114/1298] add testSPHField --- CMakeLists.txt | 9 +- include/mpc/magneticField/SPHMagneticField.h | 14 +-- .../magneticField/SPHTurbulentMagneticField.h | 2 +- src/magneticField/SPHMagneticField.cpp | 19 ++-- .../SPHTurbulentMagneticField.cpp | 11 +- test/testInteraction.cpp | 2 +- test/testSPHField.cpp | 106 ++++++++++++++++++ 7 files changed, 136 insertions(+), 27 deletions(-) create mode 100644 test/testSPHField.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 019b66477..f26e7a912 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ set(MPC_SWIG_DEFINES) # Dependencies # ---------------------------------------------------------------------------- # googletest (provided) -OPTION(ENABLETESTING "Build tests and enable test target" ON) +option(ENABLETESTING "Build tests and enable test target" ON) if(ENABLETESTING) include_directories(libs/gtest/include) add_subdirectory(libs/gtest) @@ -114,7 +114,6 @@ install(DIRECTORY data/ DESTINATION share/mpc) # ---------------------------------------------------------------------------- # Testing # ---------------------------------------------------------------------------- -OPTION(ENABLETESTING "Build tests and enable test target" ON) if(ENABLETESTING) enable_testing() add_executable(testCore test/testCore.cpp) @@ -136,6 +135,12 @@ if(ENABLETESTING) add_executable(testInteraction test/testInteraction.cpp) target_link_libraries(testInteraction mpc gtest gtest_main pthread) add_test(testInteraction testInteraction) + + if(GADGET_FOUND AND FFTW3F_FOUND) + add_executable(testSPHField test/testSPHField.cpp) + target_link_libraries(testSPHField mpc gtest gtest_main pthread) + add_test(testSPHField testSPHField) + endif() endif(ENABLETESTING) # ---------------------------------------------------------------------------- diff --git a/include/mpc/magneticField/SPHMagneticField.h b/include/mpc/magneticField/SPHMagneticField.h index 3b65b1922..390f10ab2 100644 --- a/include/mpc/magneticField/SPHMagneticField.h +++ b/include/mpc/magneticField/SPHMagneticField.h @@ -26,9 +26,9 @@ class SPHMagneticField: public MagneticField { gadget::DirectMagneticField field; gadget::FileDatabase database; public: - SPHMagneticField(Vector3d origin, double size, size_t gridSize, - const std::string filename); - SPHMagneticField(size_t gridSize, const std::string filename); + SPHMagneticField(Vector3d origin, double size, size_t samples, + std::string filename); + SPHMagneticField(size_t samples, std::string filename); Vector3d getField(const Vector3d &position) const; double getRho(const Vector3d &position) const; void updateSimulationVolume(const Vector3d &origin, double size); @@ -45,12 +45,12 @@ class SPHMagneticFieldGrid: public MagneticField { std::string cachePrefix; bool cacheEnabled; public: - SPHMagneticFieldGrid(Vector3d origin, double size, size_t samples, - const std::string filename); - SPHMagneticFieldGrid(size_t samples, const std::string filename); + SPHMagneticFieldGrid(Vector3d origin, double size, size_t gridSize, + std::string filename); + SPHMagneticFieldGrid(size_t gridSize, std::string filename); Vector3d getField(const Vector3d &position) const; void updateSimulationVolume(const Vector3d &origin, double size); - void setCachePrefix(const std::string &prefix); + void setCachePrefix(std::string prefix); void setCacheEnabled(bool enabled); }; diff --git a/include/mpc/magneticField/SPHTurbulentMagneticField.h b/include/mpc/magneticField/SPHTurbulentMagneticField.h index 03ceb0003..03367f1f2 100644 --- a/include/mpc/magneticField/SPHTurbulentMagneticField.h +++ b/include/mpc/magneticField/SPHTurbulentMagneticField.h @@ -16,7 +16,7 @@ class SPHTurbulentMagneticField: public TurbulentMagneticField { SPHTurbulentMagneticField(Vector3d origin, size_t samples, double spacing) : TurbulentMagneticField(origin, samples, spacing) { } - void modulate(const std::string filename); + void modulate(std::string filename); }; } // namespace mpc diff --git a/src/magneticField/SPHMagneticField.cpp b/src/magneticField/SPHMagneticField.cpp index 7cd2957af..53bc796a5 100644 --- a/src/magneticField/SPHMagneticField.cpp +++ b/src/magneticField/SPHMagneticField.cpp @@ -5,16 +5,16 @@ namespace mpc { -SPHMagneticField::SPHMagneticField(Vector3d origin, double size, - size_t gridSize, const std::string filename) : - field(gridSize) { +SPHMagneticField::SPHMagneticField(Vector3d origin, double size, size_t samples, + std::string filename) : + field(samples) { database.open(filename); gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; field.init(v, size / kpc, database); } -SPHMagneticField::SPHMagneticField(size_t gridSize, const std::string filename) : - field(gridSize) { +SPHMagneticField::SPHMagneticField(size_t samples, std::string filename) : + field(samples) { database.open(filename); } @@ -31,21 +31,20 @@ double SPHMagneticField::getRho(const Vector3d& position) const { return (double) field.getRho(r / kpc, overlaps); } -void SPHMagneticField::updateSimulationVolume(const Vector3d &origin, - double size) { +void SPHMagneticField::updateSimulationVolume(const Vector3d &origin, double size) { gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; field.init(v, size / kpc, database); } SPHMagneticFieldGrid::SPHMagneticFieldGrid(Vector3d origin, double size, - size_t samples, const std::string filename) : + size_t samples, std::string filename) : samples(samples), field(samples), cacheEnabled(false) { database.open(filename); gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; field.init(v, size / kpc, database); } -SPHMagneticFieldGrid::SPHMagneticFieldGrid(size_t samples, +SPHMagneticFieldGrid::SPHMagneticFieldGrid(const size_t samples, const std::string filename) : samples(samples), field(samples) { database.open(filename); @@ -86,7 +85,7 @@ void SPHMagneticFieldGrid::updateSimulationVolume(const Vector3d &origin, } } -void SPHMagneticFieldGrid::setCachePrefix(const std::string &prefix) { +void SPHMagneticFieldGrid::setCachePrefix(std::string prefix) { cachePrefix = prefix; } diff --git a/src/magneticField/SPHTurbulentMagneticField.cpp b/src/magneticField/SPHTurbulentMagneticField.cpp index 3641f21ba..51dc8a4a1 100644 --- a/src/magneticField/SPHTurbulentMagneticField.cpp +++ b/src/magneticField/SPHTurbulentMagneticField.cpp @@ -4,12 +4,10 @@ namespace mpc { -void SPHTurbulentMagneticField::modulate(const std::string filename) { +void SPHTurbulentMagneticField::modulate(std::string filename) { // create SPH Field to obtain baryon density std::cout << "mpc::SPHTurbulentMagneticField: Loading SPH-field." << std::endl; - Vector3d safeOrigin = origin - Vector3d(1,1,1) * kpc; - double safeSize = spacing * samples + 2 * kpc; - SPHMagneticField sph(safeOrigin, safeSize, 32, filename); + SPHMagneticField sph(origin, spacing * samples, 20, filename); // modulate and calculate renormalization std::cout << "mpc::SPHTurbulentMagneticField: Modulate turbulent field." << std::endl; @@ -22,14 +20,15 @@ void SPHTurbulentMagneticField::modulate(const std::string filename) { double rho = sph.getRho(pos); Vector3f &b = get(ix, iy, iz); b *= pow(rho, 2. / 3); - double dist = (pos / Mpc - Vector3d(120, 120, 120)).getMag(); - if (dist < 110) { + double dist = (pos - Vector3d(120 * Mpc)).getMag(); + if (dist < 110 * Mpc) { sumB2 += b.getMag2(); n++; } } // renormalize + std::cout << "mpc::SPHTurbulentMagneticField: Normalize turbulent field." << std::endl; double norm = Brms / sqrt(sumB2 / n); for (int ix = 0; ix < samples; ix++) for (int iy = 0; iy < samples; iy++) diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 935e90659..2f6ab2356 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -55,7 +55,7 @@ TEST(ElectronPairProduction, EnergyLossValues) { // Test if energy loss corresponds to the data table. std::vector x; std::vector y; - std::ifstream infile("data/ElectronPairProduction/cmbir.txt"); + std::ifstream infile(getDataPath("ElectronPairProduction/cmbir.txt").c_str()); while (infile.good()) { if (infile.peek() != '#') { double a, b; diff --git a/test/testSPHField.cpp b/test/testSPHField.cpp new file mode 100644 index 000000000..1c3bceb5b --- /dev/null +++ b/test/testSPHField.cpp @@ -0,0 +1,106 @@ +#include "mpc/magneticField/SPHMagneticField.h" +#include "mpc/magneticField/SPHTurbulentMagneticField.h" +#include "mpc/Units.h" +#include "mpc/Common.h" + +#include "gtest/gtest.h" + +namespace mpc { + +TEST(testSPHMagneticField, simpleTest) { + // Tests if a direct SPH field can be constructed and prints RMS and mean field strength + Vector3d origin(80 * Mpc); + int n = 64; + double size = 40 * Mpc; + double spacing = size / n; + + SPHMagneticField bField(origin, 40 * Mpc, 20, getDataPath("SPH/mhd_z.db").c_str()); + + double brms = 0; + Vector3d bmean(0, 0, 0); + for (int ix = 0; ix < n; ix++) + for (int iy = 0; iy < n; iy++) + for (int iz = 0; iz < n; iz++) { + Vector3d b = bField.getField(origin + Vector3d(ix, iy, iz) * spacing); + brms += b.getMag2(); + bmean += b; + } + + brms = sqrt(brms / n / n / n); + bmean /= n * n * n; + + std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; + std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; +} + +TEST(testSPHMagneticFieldGrid, simpleTest) { + // Tests if a sampled SPH field can be constructed and prints RMS and mean field strength + Vector3d origin(80 * Mpc); + Vector3d margin(1 * kpc); + int n = 64; + double size = 40 * Mpc; + double spacing = size / n; + + // gadget::SampledField throws errors if queried for magnetic fields on the borders + Vector3d safeOrigin(80.001 * Mpc); + double safeSpacing = (size - 2 * kpc) / n; + + SPHMagneticFieldGrid bField(origin, 40 * Mpc, n, getDataPath("SPH/mhd_z.db").c_str()); + + double brms = 0; + Vector3d bmean(0, 0, 0); + for (int ix = 0; ix < n; ix++) + for (int iy = 0; iy < n; iy++) + for (int iz = 0; iz < n; iz++) { + Vector3d b = bField.getField(safeOrigin + Vector3d(ix, iy, iz) * safeSpacing); + brms += b.getMag2(); + bmean += b; + } + + brms = sqrt(brms / n / n / n); + bmean /= n * n * n; + + std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; + std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; +} + +TEST(testSPHTurbulentMagneticField, modulatedField) { + // Test SPH modulated turbulent field for correct RMS strength: = Brms^2 and mean + Vector3d origin(80 * Mpc); + double size = 40 * Mpc; // subvolume of the SPH field + int n = 64; + double spacing = size / n; + double lMin = 2 * spacing; + double lMax = 16 * spacing; + double Brms = 1; + double alpha = -11./3; + + SPHTurbulentMagneticField bField(origin, n, spacing); + bField.initialize(lMin, lMax, Brms, alpha); + bField.modulate(getDataPath("SPH/mhd_z.db").c_str()); + + double brms = 0; + Vector3d bmean(0, 0, 0); + for (int ix = 0; ix < n; ix++) + for (int iy = 0; iy < n; iy++) + for (int iz = 0; iz < n; iz++) { + Vector3d b = bField.getField(origin + Vector3d(ix, iy, iz) * spacing); + brms += b.getMag2(); + bmean += b; + } + + brms = sqrt(brms / n / n / n); + bmean /= n * n * n; + + EXPECT_NEAR(brms, 1, 1e-7); + EXPECT_NEAR(bmean.x, 0, 1e-2); // compatible with 0 within 1% + EXPECT_NEAR(bmean.y, 0, 1e-2); + EXPECT_NEAR(bmean.z, 0, 1e-2); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + +} // namespace mpc From ac9bca7ce64371f4956f304bce0506f8fb46a0ad Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 31 May 2012 16:49:12 +0200 Subject: [PATCH 0115/1298] update python tests --- test/python/testDeflectionCK.py | 2 +- test/python/testPhotoDisintegration.py | 155 +++++++----------- .../python/testPhotoPionProduction_pnRatio.py | 1 + test/python/testTurbulentDeflection.py | 12 +- test/python/testTurbulentField.py | 60 +++---- 5 files changed, 95 insertions(+), 135 deletions(-) diff --git a/test/python/testDeflectionCK.py b/test/python/testDeflectionCK.py index ef15af15c..b18b5449b 100644 --- a/test/python/testDeflectionCK.py +++ b/test/python/testDeflectionCK.py @@ -12,7 +12,7 @@ field = UniformMagneticField(Vector3d(0,0,1e-12)) # resulting gyroradius -R = c.current.getMomentum().mag() / c.current.getCharge() / 1e-12 +R = c.current.getMomentum().getMag() / c.current.getCharge() / 1e-12 def propagate(tolerance): diff --git a/test/python/testPhotoDisintegration.py b/test/python/testPhotoDisintegration.py index 45c0cff88..3603768b1 100644 --- a/test/python/testPhotoDisintegration.py +++ b/test/python/testPhotoDisintegration.py @@ -1,115 +1,82 @@ from mpc import * from pylab import * -import sys -import ROOT -gamma = logspace(6, 14, 200) -def get_rates(pd, id, gamma, count=1000): +def get_rates(candidate, N=5000): + # perform N interactions D = {} - c = Candidate() - c.current.setId(id) - c.current.setLorentzFactor(gamma) - - for i in range(count): - c.clearInteractionStates() - pd.process(c) - state = InteractionState() - c.getInteractionState("PhotoDisintegration:CMB_IRB", state) - D.setdefault(state.channel, []).append(state.distance / Mpc) - + for i in range(N): + interaction = InteractionState() + pdModule.setNextInteraction(candidate, interaction) + if interaction.channel == 0: + continue + D.setdefault(interaction.channel, []).append(interaction.distance) + + # calculte exclusive mean interaction lengths for k in D.keys(): - hist = ROOT.TH1F('', '', 50, 0, max(D[k])) - for entry in D[k]: - hist.Fill(entry) - f = ROOT.TF1('f1', 'expo') - hist.Fit(f, "q") - l = -f.GetParameter(1) - p = hist.GetEntries() / float(count) - exclu = l * p # exclusive decay constant for this channel - D[k] = max(0, exclu) # take 0 if slope is negative - + l = array(D[k]) + p = len(l) / float(N) # probability for channel + l = mean(l) / p / Mpc # exclusive decay length in Mpc + D[k] = 1 / l # exclusive decay rate in 1/Mpc return D -def get_rates_per_channel(interaction, id): +def get_data_rates(pid): D = {} - for iE in range(200): - if iE % 20 != 0: + for i in range(len(table)): + z, n = int(table[i][0]), int(table[i][1]) + if getNucleusId(z+n, z) != pid: continue - D2 = get_rates(interaction, id, gamma[iE]) - for k in D2.keys(): - D.setdefault(k, zeros(200))[iE] = D2[k] + channel = table[i][2] + rates = table[i][3:] + D[channel] = rates return D -def get_data_rates_per_channel(table, id): - rates = {} - for i in range(len(table)): - z, a = int(table[i][0]), int(table[i][1]) - print z, a - if getNucleusId(a, z) != id: - continue - rates[table[i][1]] = table[i][2:] - return rates +def parse_pid(pid): + return str(pid%100//10) + ' ' + str(pid%100000//10000) + +def parse_channel(channel): + s = '%06d' % channel + d = list(map(int, s)) + s = 'n, ' * d[0] + 'p, ' * d[1] + 'H$^2$, ' * d[2] + 'H$^3$, ' * d[3] + 'He$^3$, ' * d[4] + 'He$^4$, ' * d[5] + return s[0:-2] + + -def plot_channel(rates_simulated, rates_data, id, channel): +### nucleus to test +pid = getNucleusId(4,2) + +candidate = Candidate() +candidate.current.setId(pid) + +table = genfromtxt(getDataPath('PhotoDisintegration/PDtable_CMB.txt')) +pdModule = PhotoDisintegration(CMB) +gamma = logspace(6, 14, 200) +gamma2 = gamma[1::5] + +Dsim = {} +for i,g in enumerate(gamma2): + candidate.current.setLorentzFactor(g) + D = get_rates(candidate) + for k in D.keys(): + Dsim.setdefault(k, zeros(len(gamma2)))[i] = D[k] + +Ddata = get_data_rates(pid) + +# plot +for k in Dsim.keys(): figure() - if channel in rates_data: - plot(gamma, rates_data[channel], 'r', label="Data") - if channel in rates_simulated: - plot(gamma, rates_simulated[channel], 'k+', label="Simulated") - legend(loc='lower right') - text(0.1, 0.85, 'Nucleus ' + parse_id(id) + '\nDecay Channel ' + parse_channel(channel), transform=gca().transAxes) + plot(gamma2, Dsim[k], 'k+') + plot(gamma, Ddata[k], 'b') + s = 'Nucleus ' + parse_pid(pid) + '\nDisintegration Channel ' + parse_channel(k) + text(0.1, 0.85, s, transform=gca().transAxes) xlabel('Lorentzfactor $\gamma$') ylabel('Rate [1/Mpc]') - #loglog() - ylim(1e-10, 1e2) + ylim(1e-6, 1e3) + loglog() grid() - savefig('PhotoDisintegration_' + str(id) + '_' + str(channel) + '.png', bbox_inches='tight') - -def parse_id(id): - z = (id / 10000) % 1000 - a = (id / 10) % 1000 - return 'Z=%i, A=%i' % (z, a) - -def parse_channel(c): - s = '%06d' % c - d = list(map(int, s)) - s = 'n, ' * d[0] + 'p, ' * d[1] + 'H$^2$, ' * d[2] + 'H$^3$, ' * d[3] + 'He$^3$, ' * d[4] + 'He$^4$, ' * d[5] - return s[0:-2] + savefig('PhotoDisintegration_' + str(pid) + '_' + str(k) + '.png', bbox_inches='tight') + show() -interaction = PhotoDisintegration(CMB_IRB) -table = genfromtxt(getDataPath('/PhotoDisintegration/PDtable_CMB_IRB.txt')) -id = getNucleusId(4,2) - -if len(sys.argv) >= 3: - a = int(sys.argv[1]) - z = int(sys.argv[2]) - id = getNucleusId(a, z) - -print 'Plotting Disintegration Rates for', id -rates_simulated = get_rates_per_channel(interaction, id) -rates_data = get_data_rates_per_channel(table, id) -channels = set.union(set(rates_simulated.keys()), set(rates_data.keys())) -for channel in channels: - plot_channel(rates_simulated, rates_data, id, channel) - -# plot channel multiplicity -#print 'Plotting Channel Multiplicity' -#multi = zeros((27, 31)) -#for z in range(1, 27): -# for n in range(1, 31): -# multi[z][n] = len(get_data_rates_per_channel(table, get_id(z + n, z))) -# -#fig = figure() -#ax = fig.add_subplot(111) -#mmulti = ma.masked_array(multi, multi==0) -#im = ax.imshow(mmulti, aspect='equal', interpolation='nearest', origin='lower') -#cbar = fig.colorbar(im, orientation='horizontal') -#cbar.set_label('Photo-Disintegration Channels') -#ax.set_xlabel('Neutrons') -#ax.set_ylabel('Protons') -#ax.grid() -#fig.savefig('PhotoDisintegration_multiplicity.png',bbox_inches='tight') diff --git a/test/python/testPhotoPionProduction_pnRatio.py b/test/python/testPhotoPionProduction_pnRatio.py index 72bb88f31..85ddb3add 100644 --- a/test/python/testPhotoPionProduction_pnRatio.py +++ b/test/python/testPhotoPionProduction_pnRatio.py @@ -27,6 +27,7 @@ def getPNRatio(E): print i Rpn[i] = getPNRatio(E[i]) +figure() plot(E, Rpn) grid() xlabel('Energy of Incident Proton [EeV]') diff --git a/test/python/testTurbulentDeflection.py b/test/python/testTurbulentDeflection.py index 4f06eac5d..80a8afb11 100644 --- a/test/python/testTurbulentDeflection.py +++ b/test/python/testTurbulentDeflection.py @@ -5,10 +5,11 @@ E = 10 # proton energy [EeV] nT = 1000 # number of trajectories nS = 100 # number of sampling points to simulate -nP = range(75) # sampling points to plot +nP = range(75) # sampling points for plot # create turbulent field with B_RMS = 1 nG and 0.5 Mpc correlation length -field = TurbulentMagneticField(Vector3d(0, 0, 0), 256, 0.05 * Mpc, 0.1 * Mpc, 2.2 * Mpc, 1*nG, -11/3.) +field = TurbulentMagneticField(Vector3d(0, 0, 0), 256 * 0.05 * Mpc, 256) +field.initialize(0.1 * Mpc, 2.2 * Mpc, 1 * nG, -11/3.) propa = DeflectionCK(field) age = linspace(1, 150, nS) @@ -37,9 +38,9 @@ x = c.current.getPosition() / Mpc p = c.current.getDirection() p0 = c.initial.getDirection() - distance[i] += x.mag() - rms1[i] += (x.angleTo(p))**2 - rms2[i] += (p0.angleTo(p))**2 + distance[i] += x.getMag() + rms1[i] += (x.getAngleTo(p))**2 + rms2[i] += (p0.getAngleTo(p))**2 distance /= nT @@ -51,6 +52,7 @@ Rg = 1.08 * E / Brms # Mpc theory = 38 * (distance * Lc)**.5 * Brms / E * pi/180 +figure() plot(distance[nP], rms1[nP], label='position, final direction') plot(distance[nP], theory[nP] / 3**.5, 'k--') plot(distance[nP], rms2[nP], label='initial, final direction') diff --git a/test/python/testTurbulentField.py b/test/python/testTurbulentField.py index 7dc4d0ff2..5579b157a 100644 --- a/test/python/testTurbulentField.py +++ b/test/python/testTurbulentField.py @@ -82,11 +82,11 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): lMin, lMax = 2, 32 Brms = 1 alpha = -11./3 -field = TurbulentMagneticField(Vector3d(0, 0, 0), n, 1) +field = TurbulentMagneticField(Vector3d(0, 0, 0), n, n) field.initialize(lMin, lMax, Brms, alpha) Lc = field.getCorrelationLength() -### copy field to array +### copy field grid to array(s) Bx, By, Bz = zeros((3, n, n, n)) for ix in range(n): for iy in range(n): @@ -97,60 +97,50 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): Bz[ix, iy, iz] = b.z ### plot slice in position space -slice = n/2 figure() -subplot(111, aspect='equal') -pc = pcolor(((Bx**2 + By**2 + Bz**2)**.5)[:,:,slice]) -cbar = colorbar(pc) -cbar.set_label(r'$|\vec{B}(\vec{x})| / B_{RMS}$') -xlabel(r'$x$') -ylabel(r'$y$') -xlim(0,n) -ylim(0,n) -text(0.8, 1.05, '$z=%i$'%slice, transform=gca().transAxes) +A = ((Bx**2 + By**2 + Bz**2)**.5)[:,:,n/2] +im = imshow(A, origin='lower', extent=[0,n,0,n], vmin=0, vmax=3) +cbar = colorbar(im) +cbar.set_label(r'$|\vec{B}(\vec{x})| / B_{rms}$') +xlabel('$x$') +ylabel('$y$') +text(0.8, 1.05, '$z=%i$'%(n/2), transform=gca().transAxes) savefig('TurbulentField_slicePositionSpace.png', bbox_inches='tight') ### plot slice in configuration space -slice = n/2 figure() -subplot(111, aspect='equal') Bkx = fftshift(fftn(Bx)) Bky = fftshift(fftn(By)) Bkz = fftshift(fftn(Bz)) Bk = ((Bkx*Bkx.conjugate() + Bky*Bky.conjugate() + Bkz*Bkz.conjugate()).real)**.5 -pc = pcolor(log10(Bk[:,:,slice]), vmin=0) -del Bk, Bkx, Bky, Bkz -cbar = colorbar(pc) -cbar.set_label(r'$log_{10}(|\vec{B}(\vec{k})| / B_{RMS})$') -xlabel(r'$k_x$') -ylabel(r'$k_y$') +A = log10(Bk[:,:,n/2]) +im = imshow(A, origin='lower', vmin=0) +cbar = colorbar(im) +cbar.set_label(r'$log_{10}(|\vec{B}(\vec{k})| / B_{rms})$') +xlabel('$k_x$') +ylabel('$k_y$') k = fftshift(fftfreq(n)) idx = arange(0,n,n/4) xticks(idx, k[idx]) yticks(idx, k[idx]) xlim(0,n) ylim(0,n) -text(0.8, 1.05, '$k_z=%.2f$'%k[slice], transform=gca().transAxes) +text(0.8, 1.05, '$k_z=%.2f$'%k[n/2], transform=gca().transAxes) savefig('TurbulentField_sliceConfigurationSpace.png', bbox_inches='tight') ### plot slice and periodical extension in position space -slice = n/2 figure() -subplot(111, aspect='equal') A = zeros((3*n,3*n)) for i,j in ((0,1), (1,0), (1,1), (1,2), (2,1)): - A[i*n:(i+1)*n, j*n:(j+1)*n] = Bx[:,:,slice] -pc = pcolor(ma.masked_array(A, A == 0)) -del A -cbar = colorbar(pc) + A[i*n:(i+1)*n, j*n:(j+1)*n] = Bx[:,:,n/2] +im = imshow(ma.masked_array(A, A == 0), origin='lower', extent=[-n,2*n,-n,2*n], vmin=0, vmax=3) +cbar = colorbar(im) cbar.set_label(r'$|\vec{B_x}|/B_{rms}$') -xlim(0,3*n) -ylim(0,3*n) -xticks([0, n, 2*n, 3*n]) -yticks([0, n, 2*n, 3*n]) -xlabel(r'$x$') -ylabel(r'$y$') -text(0.8, 1.05, '$z=%i$'%slice, transform=gca().transAxes) +xticks([-n, 0, n, 2*n]) +yticks([-n, 0, n, 2*n]) +xlabel('$x$') +ylabel('$y$') +text(0.8, 1.05, '$z=%i$'%(n/2), transform=gca().transAxes) savefig('TurbulentField_slicePeriodicity.png', bbox_inches='tight') ### plot (2pt-auto-)correlation curves for various directions @@ -170,7 +160,7 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): Lcs.append( corr.getIntegralLengthscale(step) ) x,y = corr.getCorrelationCurve(step) plot(x,y,label=str(step)) -xlabel('Distance [gridpoints]') +xlabel('Distance') ylabel('Normalized Autocorrelation') xlim(0,32) grid() From 0fa287c17933f7306fff0a4ce217b80425379fc7 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 31 May 2012 16:50:01 +0200 Subject: [PATCH 0116/1298] update magnetic fields + tests --- include/mpc/Vector3.h | 2 +- include/mpc/magneticField/MagneticFieldGrid.h | 18 ++- .../magneticField/SPHTurbulentMagneticField.h | 6 +- .../magneticField/TurbulentMagneticField.h | 11 +- src/magneticField/MagneticFieldGrid.cpp | 53 ++++---- .../SPHTurbulentMagneticField.cpp | 32 +++-- src/magneticField/TurbulentMagneticField.cpp | 11 +- test/testMagneticField.cpp | 124 ++++++++++++++---- test/testSPHField.cpp | 50 ++++--- 9 files changed, 201 insertions(+), 106 deletions(-) diff --git a/include/mpc/Vector3.h b/include/mpc/Vector3.h index 6f4e00999..5ebfd71b7 100644 --- a/include/mpc/Vector3.h +++ b/include/mpc/Vector3.h @@ -117,7 +117,7 @@ class Vector3 { } T getMag2() const { - return (x * x + y * y + z * z); + return x * x + y * y + z * z; } Vector3 getUnitVector() const { diff --git a/include/mpc/magneticField/MagneticFieldGrid.h b/include/mpc/magneticField/MagneticFieldGrid.h index 94f9a81f1..e4c66b720 100644 --- a/include/mpc/magneticField/MagneticFieldGrid.h +++ b/include/mpc/magneticField/MagneticFieldGrid.h @@ -8,7 +8,7 @@ namespace mpc { /** @class MagneticFieldGrid - @brief Cubic, cartesian magnetic field grid with trilinear interpolation. + @brief Periodic, cubic, cartesian magnetic field grid with trilinear interpolation. This class provides a magnetic field grid. The grid spacing is constant and equal along all three axes (cartesian). @@ -18,7 +18,7 @@ namespace mpc { */ class MagneticFieldGrid: public MagneticField { public: - MagneticFieldGrid(Vector3d origin, size_t n, double spacing); + MagneticFieldGrid(Vector3d origin, double size, size_t samples); Vector3f &get(size_t ix, size_t iy, size_t iz); const Vector3f &get(size_t ix, size_t iy, size_t iz) const; Vector3d getField(const Vector3d &position) const; @@ -27,16 +27,20 @@ class MagneticFieldGrid: public MagneticField { double getGridSpacing() const; double getGridSize() const; virtual void updateSimulationVolume(const Vector3d &origin, double size); - void setGridOrigin(const Vector3d &origin); - void setGridSpacing(const double spacing); protected: + /** Grid of magnetic field vectors. + * Since the grid is periodic the field at opposite borders is identical and does not need to be sampled twice. + * The field is thus sampled at 0, size / samples, ... size * (samples - 1) / samples. */ std::vector grid; - size_t samples; - double spacing; - Vector3d origin; + Vector3d origin; /** Origin of the field */ + double size; /** Extension of the field */ + size_t samples; /** Number of grid points per edge */ + double spacing; /** Distance between two grid points (= size / samples) */ }; +void periodicClamp(double x, int n, int &lo, int &hi); + } // namespace mpc #endif /* MPC_MAGNETICFIELDGRID_H_ */ diff --git a/include/mpc/magneticField/SPHTurbulentMagneticField.h b/include/mpc/magneticField/SPHTurbulentMagneticField.h index 03367f1f2..32f985f42 100644 --- a/include/mpc/magneticField/SPHTurbulentMagneticField.h +++ b/include/mpc/magneticField/SPHTurbulentMagneticField.h @@ -13,10 +13,10 @@ namespace mpc { */ class SPHTurbulentMagneticField: public TurbulentMagneticField { public: - SPHTurbulentMagneticField(Vector3d origin, size_t samples, double spacing) : - TurbulentMagneticField(origin, samples, spacing) { + SPHTurbulentMagneticField(Vector3d origin, double size, size_t samples) : + TurbulentMagneticField(origin, size, samples) { } - void modulate(std::string filename); + void modulate(std::string filename, double weight); }; } // namespace mpc diff --git a/include/mpc/magneticField/TurbulentMagneticField.h b/include/mpc/magneticField/TurbulentMagneticField.h index 278bb2ad2..8c87ea61b 100644 --- a/include/mpc/magneticField/TurbulentMagneticField.h +++ b/include/mpc/magneticField/TurbulentMagneticField.h @@ -24,8 +24,8 @@ namespace mpc { */ class TurbulentMagneticField: public MagneticFieldGrid { public: - TurbulentMagneticField(Vector3d origin, size_t samples, double spacing) : - MagneticFieldGrid(origin, samples, spacing) { + TurbulentMagneticField(Vector3d origin, double size, size_t samples) : + MagneticFieldGrid(origin, size, samples) { } void initialize(double lMin, double lMax, double Brms, double powerSpectralIndex = -11. / 3.); @@ -35,8 +35,11 @@ class TurbulentMagneticField: public MagneticFieldGrid { double getPowerSpectralIndex() const; protected: - double Brms, lMin, lMax, powerSpectralIndex; - Random random; + double Brms; /** RMS field strength */ + double lMin; /** minimum coherent length scale */ + double lMax; /** maximum coherent lenght scale */ + double powerSpectralIndex; /** turbulence spectral index */ + Random random; /** random number generator instance */ }; } // namespace mpc diff --git a/src/magneticField/MagneticFieldGrid.cpp b/src/magneticField/MagneticFieldGrid.cpp index aa1c1e996..4d7a7f582 100644 --- a/src/magneticField/MagneticFieldGrid.cpp +++ b/src/magneticField/MagneticFieldGrid.cpp @@ -2,25 +2,26 @@ namespace mpc { -void periodicClamp(double x, int n, int &low, int &high, double &fLow, - double &fHigh) { - // closest lower and upper neighbour in a periodically continued grid - low = ((int(x) % n) + n) % n; - high = (low + 1) % n; - fLow = x - floor(x); - fHigh = 1 - fLow; +/** lower and upper neighbor in a periodically continued unit grid */ +void periodicClamp(double x, int n, int &lo, int &hi) { + lo = ( ( int(floor(x)) % n ) + n ) % n; + hi = (lo + 1) % n; } -MagneticFieldGrid::MagneticFieldGrid(Vector3d origin, size_t samples, - double spacing) : - origin(origin), samples(samples), spacing(spacing) { +MagneticFieldGrid::MagneticFieldGrid(Vector3d origin, double size, + size_t samples) { + this->origin = origin; + this->size = size; + this->samples = samples; + this->spacing = size / samples; grid.resize(samples * samples * samples); } void MagneticFieldGrid::updateSimulationVolume(const Vector3d &origin, double size) { this->origin = origin; - this->spacing = size / (samples - 1); + this->size = size; + this->spacing = size / samples; } Vector3d MagneticFieldGrid::getGridOrigin() const { @@ -36,7 +37,7 @@ double MagneticFieldGrid::getGridSpacing() const { } double MagneticFieldGrid::getGridSize() const { - return samples * spacing; + return size; } Vector3f &MagneticFieldGrid::get(size_t ix, size_t iy, size_t iz) { @@ -50,16 +51,26 @@ const Vector3f &MagneticFieldGrid::get(size_t ix, size_t iy, size_t iz) const { } Vector3d MagneticFieldGrid::getField(const Vector3d &position) const { + // position on a unit grid Vector3d r = (position - origin) / spacing; + + // indices of lower and upper neighbors int ix, iX, iy, iY, iz, iZ; - double fx, fX, fy, fY, fz, fZ; - periodicClamp(r.x, samples, ix, iX, fx, fX); - periodicClamp(r.y, samples, iy, iY, fy, fY); - periodicClamp(r.z, samples, iz, iZ, fz, fZ); + periodicClamp(r.x, samples, ix, iX); + periodicClamp(r.y, samples, iy, iY); + periodicClamp(r.z, samples, iz, iZ); + + // linear fraction to lower and upper neighbor + double fx = r.x - floor(r.x); + double fX = 1 - fx; + double fy = r.y - floor(r.y); + double fY = 1 - fy; + double fz = r.z - floor(r.z); + double fZ = 1 - fz; // trilinear interpolation // check: http://paulbourke.net/miscellaneous/interpolation/ - Vector3d b(0, 0, 0); + Vector3d b(0.); //V000 (1 - x) (1 - y) (1 - z) + b += get(ix, iy, iz) * fX * fY * fZ; //V100 x (1 - y) (1 - z) + @@ -80,12 +91,4 @@ Vector3d MagneticFieldGrid::getField(const Vector3d &position) const { return b; } -void MagneticFieldGrid::setGridOrigin(const Vector3d& origin) { - this->origin = origin; -} - -void MagneticFieldGrid::setGridSpacing(const double spacing) { - this->spacing = spacing; -} - } // namespace mpc diff --git a/src/magneticField/SPHTurbulentMagneticField.cpp b/src/magneticField/SPHTurbulentMagneticField.cpp index 51dc8a4a1..41f99c83d 100644 --- a/src/magneticField/SPHTurbulentMagneticField.cpp +++ b/src/magneticField/SPHTurbulentMagneticField.cpp @@ -4,37 +4,45 @@ namespace mpc { -void SPHTurbulentMagneticField::modulate(std::string filename) { +void SPHTurbulentMagneticField::modulate(std::string filename, double weight) { // create SPH Field to obtain baryon density - std::cout << "mpc::SPHTurbulentMagneticField: Loading SPH-field." << std::endl; - SPHMagneticField sph(origin, spacing * samples, 20, filename); + std::cout << "mpc::SPHTurbulentMagneticField: Loading SPH-field: " + << filename << std::endl; + // SPHMagneticField may fail on borders, choose minimally larger size + Vector3d safeOrigin = origin - Vector3d(1.); + double safeSize = size + 2; + SPHMagneticField sph(safeOrigin, safeSize, 20, filename); // modulate and calculate renormalization - std::cout << "mpc::SPHTurbulentMagneticField: Modulate turbulent field." << std::endl; + std::cout << "mpc::SPHTurbulentMagneticField: Modulate turbulent field." + << std::endl; double sumB2 = 0; - int n = 0; + int numB2 = 0; for (int ix = 0; ix < samples; ix++) for (int iy = 0; iy < samples; iy++) for (int iz = 0; iz < samples; iz++) { - Vector3d pos = Vector3d(ix, iy, iz) * spacing + origin; + Vector3d pos = origin + Vector3d(ix, iy, iz) * spacing; double rho = sph.getRho(pos); Vector3f &b = get(ix, iy, iz); - b *= pow(rho, 2. / 3); - double dist = (pos - Vector3d(120 * Mpc)).getMag(); - if (dist < 110 * Mpc) { + b *= pow(rho, weight); + double distance2center = (pos - Vector3d(120 * Mpc)).getMag(); + if (distance2center < 110 * Mpc) { sumB2 += b.getMag2(); - n++; + numB2++; } } // renormalize - std::cout << "mpc::SPHTurbulentMagneticField: Normalize turbulent field." << std::endl; - double norm = Brms / sqrt(sumB2 / n); + std::cout << "mpc::SPHTurbulentMagneticField: Normalize turbulent field." + << std::endl; + double norm = Brms / sqrt(sumB2 / numB2); + Brms = 0; for (int ix = 0; ix < samples; ix++) for (int iy = 0; iy < samples; iy++) for (int iz = 0; iz < samples; iz++) { Vector3f &b = get(ix, iy, iz); b *= norm; + Brms += b.getMag2(); } } diff --git a/src/magneticField/TurbulentMagneticField.cpp b/src/magneticField/TurbulentMagneticField.cpp index 29834dc25..c5d877acd 100644 --- a/src/magneticField/TurbulentMagneticField.cpp +++ b/src/magneticField/TurbulentMagneticField.cpp @@ -1,5 +1,7 @@ #include "mpc/magneticField/TurbulentMagneticField.h" + #include "fftw3.h" +#include namespace mpc { @@ -14,6 +16,13 @@ void TurbulentMagneticField::initialize(double lMin, double lMax, double Brms, this->Brms = Brms; this->powerSpectralIndex = powerSpectralIndex; + if (lMin < 2 * spacing) + throw std::runtime_error("mpc::TurbulentMagneticField: lMin < 2 * spacing"); + if (lMin >= lMax) + throw std::runtime_error("mpc::TurbulentMagneticField: lMin >= lMax"); + if (lMax > size / 2) + throw std::runtime_error("mpc::TurbulentMagneticField: lMax > size / 2"); + size_t n = samples; // size of array size_t n2 = (size_t) floor(n / 2) + 1; // size array in z-direction in configuration space @@ -118,7 +127,7 @@ void TurbulentMagneticField::initialize(double lMin, double lMax, double Brms, } double w = Brms / sqrt(sumB2 / (n * n * n)); - // normalize and save real component to the grid + // normalize and save to grid for (size_t ix = 0; ix < n; ix++) for (size_t iy = 0; iy < n; iy++) for (size_t iz = 0; iz < n; iz++) { diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index c99e8701d..33a81c56b 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -4,6 +4,7 @@ #include "mpc/Units.h" #include "gtest/gtest.h" +#include namespace mpc { @@ -15,42 +16,96 @@ TEST(testUniformMagneticField, SimpleTest) { EXPECT_DOUBLE_EQ(b.z, 3); } -TEST(testTurbulentMagneticFieldGrid, PeriodicBoundaries) { - // Test turbulent field for periodic boundaries: B(x+a*n) = B(x) - size_t n = 64; - TurbulentMagneticField bField(Vector3d(0, 0, 0), n, 1); - bField.initialize(2, 8, 1, -11. / 3.); +TEST(testMagneticFieldGrid, PeriodicClamp) { + // Test correct determination of lower and upper neighbor + int lo, hi; + + periodicClamp(23.12, 8, lo, hi); + EXPECT_EQ(7, lo); + EXPECT_EQ(0, hi); + + periodicClamp(-23.12, 8, lo, hi); + EXPECT_EQ(0, lo); + EXPECT_EQ(1, hi); +} + +TEST(testMagneticFieldGrid, SimpleTest) { + // Test construction and parameters + MagneticFieldGrid B(Vector3d(1., 2., 3.), 10, 4); + EXPECT_TRUE(Vector3d(1., 2., 3.) == B.getGridOrigin()); + EXPECT_EQ(4, B.getGridSamples()); + EXPECT_DOUBLE_EQ(10, B.getGridSize()); + EXPECT_DOUBLE_EQ(2.5, B.getGridSpacing()); +} - Vector3d pos(1.1, 2.1, 3.1); - Vector3d b = bField.getField(pos); - Vector3d b1 = bField.getField(pos + Vector3d(n, 0, 0)); - Vector3d b2 = bField.getField(pos + Vector3d(0, n, 0)); - Vector3d b3 = bField.getField(pos + Vector3d(0, 0, n)); +TEST(testMagneticFieldGrid, Interpolation) { + // Explicitly test trilinear interpolation + MagneticFieldGrid B(Vector3d(0.), 9, 3); + B.get(0, 0, 1) = Vector3f(1.7, 0., 0.); + + double spacing = B.getGridSpacing(); + EXPECT_FLOAT_EQ(1.7, B.getField(Vector3d(0, 0, 1) * spacing).x); + + EXPECT_FLOAT_EQ(1.7 * 0.9, B.getField(Vector3d(0, 0, 0.9) * spacing).x); + EXPECT_FLOAT_EQ(1.7 * 0.9, B.getField(Vector3d(0, 0, 1.1) * spacing).x); + + EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.85, B.getField(Vector3d(0, 0.15, 0.9) * spacing).x); + EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.15, B.getField(Vector3d(0, 2.15, 0.9) * spacing).x); +} + +TEST(testMagneticFieldGrid, Interpolation2) { + // If the field is uniform, (interpolated) field values should be the same everywhere + MagneticFieldGrid B(Vector3d(0.), 3, 3); + for (int ix = 0; ix < 3; ix++) + for (int iy = 0; iy < 3; iy++) + for (int iz = 0; iz < 3; iz++) + B.get(ix, iy, iz) = Vector3f(1, 0, 0); + + double spacing = B.getGridSpacing(); + EXPECT_FLOAT_EQ(1, B.getField(Vector3d(0.7, 0, 0.1)).x); + EXPECT_FLOAT_EQ(1, B.getField(Vector3d(0, 1.3, 0.9)).x); +} - EXPECT_FLOAT_EQ(b.x, b1.x); - EXPECT_FLOAT_EQ(b.y, b1.y); - EXPECT_FLOAT_EQ(b.z, b1.z); +TEST(testMagneticFieldGrid, Periodicity) { + // Test for periodic boundaries: B(x+a*n) = B(x) + MagneticFieldGrid B(Vector3d(0.), 9, 3); + for (int ix = 0; ix < 3; ix++) + for (int iy = 0; iy < 3; iy++) + for (int iz = 0; iz < 3; iz++) + B.get(ix, iy, iz) = Vector3f(iz + ix, iy * iz, ix - iz * iy); + + double size = B.getGridSize(); + Vector3d pos(1.2, 2.3, 0.7); + Vector3f b = B.getField(pos); + Vector3f b2 = B.getField(pos + Vector3d(1, 0, 0) * size); + EXPECT_FLOAT_EQ(b.x, b2.x); + EXPECT_FLOAT_EQ(b.y, b2.y); + EXPECT_FLOAT_EQ(b.z, b2.z); + + b2 = B.getField(pos + Vector3d(0, 5, 0) * size); EXPECT_FLOAT_EQ(b.x, b2.x); EXPECT_FLOAT_EQ(b.y, b2.y); EXPECT_FLOAT_EQ(b.z, b2.z); - EXPECT_FLOAT_EQ(b.x, b3.x); - EXPECT_FLOAT_EQ(b.y, b3.y); - EXPECT_FLOAT_EQ(b.z, b3.z); + b2 = B.getField(pos + Vector3d(0, 0, -2) * size); + EXPECT_FLOAT_EQ(b.x, b2.x); + EXPECT_FLOAT_EQ(b.y, b2.y); + EXPECT_FLOAT_EQ(b.z, b2.z); } -TEST(testTurbulentMagneticFieldGrid, ZeroMean) { - // Test turbulent field for zero mean: = 0 +TEST(testTurbulentMagneticField, Bmean) { + // Test for zero mean: = 0 size_t n = 64; - TurbulentMagneticField bField(Vector3d(0, 0, 0), n, 1); - bField.initialize(2, 8, 1, -11. / 3.); + TurbulentMagneticField B(Vector3d(0, 0, 0), 10 * Mpc, n); + double spacing = B.getGridSpacing(); + B.initialize(2 * spacing, 8 * spacing, 1, -11. / 3.); Vector3d b(0, 0, 0); for (int ix = 0; ix < n; ix++) for (int iy = 0; iy < n; iy++) for (int iz = 0; iz < n; iz++) - b += bField.getField(Vector3d(ix, iy, iz)); + b += B.getField(Vector3d(ix, iy, iz) * spacing); b /= n * n * n; double precision = 1e-7; @@ -59,23 +114,38 @@ TEST(testTurbulentMagneticFieldGrid, ZeroMean) { EXPECT_NEAR(b.z, 0, precision); } -TEST(testTurbulentMagneticFieldGrid, Brms) { - // Test turbulent field for correct RMS strength: = Brms^2 - size_t n = 64; - TurbulentMagneticField bField(Vector3d(0, 0, 0), n, 1); - bField.initialize(2, 8, 1, -11. / 3.); +TEST(testTurbulentMagneticField, Brms) { + // Test for correct RMS strength: = Brms^2 + size_t n = 100; + TurbulentMagneticField B(Vector3d(0, 0, 0), 10 * Mpc, n); + double spacing = B.getGridSpacing(); + B.initialize(2 * spacing, 8 * spacing, 1, -11. / 3.); double brms = 0; for (int ix = 0; ix < n; ix++) for (int iy = 0; iy < n; iy++) for (int iz = 0; iz < n; iz++) - brms += bField.getField(Vector3d(ix, iy, iz)).getMag2(); + brms += B.getField(Vector3d(ix, iy, iz) * spacing).getMag2(); brms = sqrt(brms / n / n / n); double precision = 1e-7; EXPECT_NEAR(brms, 1, precision); } +TEST(testTurbulentMagneticField, Exceptions) { + // Test exceptions + TurbulentMagneticField B(Vector3d(0, 0, 0), 10, 64); + double spacing = B.getGridSpacing(); + // should be fine + EXPECT_NO_THROW(B.initialize(2 * spacing, 8 * spacing, 1, -11. / 3.)); + // lMin too small + EXPECT_THROW(B.initialize(1.9 * spacing, 8 * spacing, 1, -11. / 3.), std::runtime_error); + // lMin > lMax + EXPECT_THROW(B.initialize(8.1 * spacing, 8 * spacing, 1, -11. / 3.), std::runtime_error); + // lMax too large + EXPECT_THROW(B.initialize(2 * spacing, 5.1, 1, -11. / 3.), std::runtime_error); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/test/testSPHField.cpp b/test/testSPHField.cpp index 1c3bceb5b..9082a2b7a 100644 --- a/test/testSPHField.cpp +++ b/test/testSPHField.cpp @@ -10,18 +10,22 @@ namespace mpc { TEST(testSPHMagneticField, simpleTest) { // Tests if a direct SPH field can be constructed and prints RMS and mean field strength Vector3d origin(80 * Mpc); - int n = 64; double size = 40 * Mpc; - double spacing = size / n; - SPHMagneticField bField(origin, 40 * Mpc, 20, getDataPath("SPH/mhd_z.db").c_str()); + // gadget::DirectField may throw if queried for magnetic fields on the borders + Vector3d safeOrigin = origin - Vector3d(1 * kpc); + double safeSize = size + 2 * kpc; + + SPHMagneticField B(safeOrigin, safeSize, 20, getDataPath("SPH/mhd_z.db").c_str()); + int n = 64; + double spacing = 40 * Mpc / (n - 1); double brms = 0; Vector3d bmean(0, 0, 0); for (int ix = 0; ix < n; ix++) for (int iy = 0; iy < n; iy++) for (int iz = 0; iz < n; iz++) { - Vector3d b = bField.getField(origin + Vector3d(ix, iy, iz) * spacing); + Vector3d b = B.getField(origin + Vector3d(ix, iy, iz) * spacing); brms += b.getMag2(); bmean += b; } @@ -36,23 +40,22 @@ TEST(testSPHMagneticField, simpleTest) { TEST(testSPHMagneticFieldGrid, simpleTest) { // Tests if a sampled SPH field can be constructed and prints RMS and mean field strength Vector3d origin(80 * Mpc); - Vector3d margin(1 * kpc); - int n = 64; + size_t n = 64; double size = 40 * Mpc; - double spacing = size / n; + double spacing = size / (n - 1); - // gadget::SampledField throws errors if queried for magnetic fields on the borders - Vector3d safeOrigin(80.001 * Mpc); - double safeSpacing = (size - 2 * kpc) / n; + // gadget::SampledField may throw if queried for magnetic fields on the borders + Vector3d safeOrigin = origin - Vector3d(1 * kpc); + double safeSize = size + 2 * kpc; - SPHMagneticFieldGrid bField(origin, 40 * Mpc, n, getDataPath("SPH/mhd_z.db").c_str()); + SPHMagneticFieldGrid B(safeOrigin, safeSize, n, getDataPath("SPH/mhd_z.db").c_str()); double brms = 0; Vector3d bmean(0, 0, 0); for (int ix = 0; ix < n; ix++) for (int iy = 0; iy < n; iy++) for (int iz = 0; iz < n; iz++) { - Vector3d b = bField.getField(safeOrigin + Vector3d(ix, iy, iz) * safeSpacing); + Vector3d b = B.getField(origin + Vector3d(ix, iy, iz) * spacing); brms += b.getMag2(); bmean += b; } @@ -65,26 +68,21 @@ TEST(testSPHMagneticFieldGrid, simpleTest) { } TEST(testSPHTurbulentMagneticField, modulatedField) { - // Test SPH modulated turbulent field for correct RMS strength: = Brms^2 and mean + // Test for correct rms and mean strength Vector3d origin(80 * Mpc); - double size = 40 * Mpc; // subvolume of the SPH field int n = 64; - double spacing = size / n; - double lMin = 2 * spacing; - double lMax = 16 * spacing; - double Brms = 1; - double alpha = -11./3; - SPHTurbulentMagneticField bField(origin, n, spacing); - bField.initialize(lMin, lMax, Brms, alpha); - bField.modulate(getDataPath("SPH/mhd_z.db").c_str()); + SPHTurbulentMagneticField B(origin, 40 * Mpc, n); + double spacing = B.getGridSpacing(); + B.initialize(2 * spacing, 8 * spacing, 1, -11./3); + B.modulate(getDataPath("SPH/mhd_z.db").c_str(), 2./3); double brms = 0; Vector3d bmean(0, 0, 0); for (int ix = 0; ix < n; ix++) for (int iy = 0; iy < n; iy++) for (int iz = 0; iz < n; iz++) { - Vector3d b = bField.getField(origin + Vector3d(ix, iy, iz) * spacing); + Vector3d b = B.getField(origin + Vector3d(ix, iy, iz) * spacing); brms += b.getMag2(); bmean += b; } @@ -93,9 +91,9 @@ TEST(testSPHTurbulentMagneticField, modulatedField) { bmean /= n * n * n; EXPECT_NEAR(brms, 1, 1e-7); - EXPECT_NEAR(bmean.x, 0, 1e-2); // compatible with 0 within 1% - EXPECT_NEAR(bmean.y, 0, 1e-2); - EXPECT_NEAR(bmean.z, 0, 1e-2); + EXPECT_NEAR(bmean.x, 0, 5e-3); // compatible with 0 within 0.5% + EXPECT_NEAR(bmean.y, 0, 5e-3); + EXPECT_NEAR(bmean.z, 0, 5e-3); } int main(int argc, char **argv) { From 94451e5e7cb0f5d4131ddcaae5ccffac9fc82b01 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 4 Jun 2012 17:38:28 +0200 Subject: [PATCH 0117/1298] add test script for SPHTurbulentField --- test/python/testSPHTurbulentField.py | 75 ++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 test/python/testSPHTurbulentField.py diff --git a/test/python/testSPHTurbulentField.py b/test/python/testSPHTurbulentField.py new file mode 100644 index 000000000..6c4d22687 --- /dev/null +++ b/test/python/testSPHTurbulentField.py @@ -0,0 +1,75 @@ +from mpc import * +from pylab import * + + +# parameters +lo = 80 +hi = 160 +origin = Vector3d(lo * Mpc) +N = 128 +size = (hi - lo) * Mpc +spacing = size / N +lMin = 2 * spacing +lMax = 16 * spacing +Brms = 1 +alpha = -11./3 + +# create field +field = SPHTurbulentMagneticField(origin, size, N) +print 'initialize' +field.initialize(lMin, lMax, Brms, alpha) +print 'modulate' +field.modulate(getDataPath("SPH/mhd_z.db"), 2./3) +print 'evaluate' + +# plot a slice +A = zeros((N,N)) +for ix in range(N): + for iy in range(N): + b = field.getField(origin + Vector3d(ix, iy, N/2) * spacing) + A[ix,iy] = b.getMag() + +figure() +im = imshow(log10(A), origin='lower', extent=[lo, hi, lo, hi], vmin=-2, vmax=2) +cbar = colorbar(im) +cbar.set_label('$\log_{10}(B/B_{rms})$') +xlabel('x [Mpc]') +ylabel('y [Mpc]') +savefig('SPHTurbulentField_slice.png', bbox_inches='tight') + +# sample the effective rms field strengths +brms = 0 +r = Random() +for i in range(1000): + x = Vector3d(r.rand(), r.rand(), r.rand()) * size + origin + brms += field.getField(x).getMag2() +brms = (brms / 1000)**.5 +print 'effective Brms =', brms, 'of nominal Brms' + +# sample the coherence length +def getCorrelationCurve(): + x = Vector3d(r.rand(), r.rand(), r.rand()) * size + origin + d = r.randUnitVectorOnSphere() + b = field.getField(x) + b.normalize() + c = zeros(nSteps) + for i in range(nSteps): + b2 = field.getField(x + Vector3d(d.x, d.y, d.z) * i * step) + b2.normalize() + c[i] = b.dot(b2) + return c + +nSteps = 100 +step = lMax / 2 / nSteps # choose so that lc_unmodulated < nStep * step < size + +cMean = zeros(nSteps) +for i in range(1000): + cMean += getCorrelationCurve() / 1000 +lc = (2 * sum(cMean[1:]) + cMean[0]) * step / Mpc + +plot(arange(0, nSteps) * step / Mpc, cMean) +xlabel('Linear Separation [Mpc]') +ylabel('Autocorrelation') +text(0.35, 0.95, 'Coherence Length %.1f Mpc'%lc, ha='left', va='top', transform=gca().transAxes) +savefig('SPHTurbulentField_coherenceLength.png', bbox_inches='tight') + From b50c6d82fdf37360560275f7dc9a5b5119672dc1 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 4 Jun 2012 17:38:52 +0200 Subject: [PATCH 0118/1298] add CompositeSource --- CMakeLists.txt | 4 ++ include/mpc/Nucleus.h | 4 ++ include/mpc/Source.h | 34 +++++++++- .../include/HepPID/ParticleIDMethods.hh | 4 +- src/Nucleus.cpp | 8 +++ src/Source.cpp | 64 +++++++++++++++++-- .../SPHTurbulentMagneticField.cpp | 2 +- test/python/testTurbulentField.py | 2 +- test/testBreakCondition.cpp | 4 -- 9 files changed, 112 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f26e7a912..3839fdcaa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -136,6 +136,10 @@ if(ENABLETESTING) target_link_libraries(testInteraction mpc gtest gtest_main pthread) add_test(testInteraction testInteraction) + add_executable(testSource test/testSource.cpp) + target_link_libraries(testSource mpc gtest gtest_main pthread) + add_test(testSource testSource) + if(GADGET_FOUND AND FFTW3F_FOUND) add_executable(testSPHField test/testSPHField.cpp) target_link_libraries(testSPHField mpc gtest gtest_main pthread) diff --git a/include/mpc/Nucleus.h b/include/mpc/Nucleus.h index 2ba108769..28b613beb 100644 --- a/include/mpc/Nucleus.h +++ b/include/mpc/Nucleus.h @@ -12,9 +12,13 @@ namespace mpc { // L is the total number of strange quarks. // I is the isomer number, with I=0 corresponding to the ground state. int getNucleusId(int a, int z); + void initNuclearMassTable(); double getNucleusMass(int id); +int getChargeNumberFromNucleusId(int id); +int getMassNumberFromNucleusId(int id); + } // namespace mpc #endif /* NUCLEUS_H_ */ diff --git a/include/mpc/Source.h b/include/mpc/Source.h index d95dee110..6d33bad5a 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -22,7 +22,7 @@ class Source: public Referenced { /** @class BasicSource - @brief Simple cosmic ray source + @brief Cosmic ray source with (broken) power law spectrum */ class BasicSource: public Source { public: @@ -30,13 +30,43 @@ class BasicSource: public Source { double index1, index2, breakpoint, Emin, Emax; int id; BasicSource(); - BasicSource(const Vector3d &sposition, int type, double Emin = 5 * EeV, + BasicSource(const Vector3d &sposition, int id, double Emin = 5 * EeV, double Emax = 1000 * EeV, double index1 = -1, double index2 = -1, double breakpoint = 1); virtual void prepare(ParticleState &state) const; }; +/** + @class CompositeSource + @brief Cosmic ray source with composition and power law spectrum + */ +class CompositeSource: public Source { +public: + /** + @class Isotope + @brief Source isotope + */ + struct Isotope { + public: + int id; + double abundance; + double probability; + Isotope(); + Isotope(int id, double abundance); + }; + + Vector3d position; + double index, Emin, Emax; + std::vector composition; + CompositeSource(); + CompositeSource(const Vector3d &sposition, double Emin = 5 * EeV, + double Emax = 1000 * EeV, double index = -1); + void addToComposition(int id, double abundance); + void normalize(); + virtual void prepare(ParticleState &state) const; +}; + } // namespace mpc #endif /* MPC_SOURCE_H */ diff --git a/libs/HepPID/include/HepPID/ParticleIDMethods.hh b/libs/HepPID/include/HepPID/ParticleIDMethods.hh index 42aef6065..9762e61ee 100644 --- a/libs/HepPID/include/HepPID/ParticleIDMethods.hh +++ b/libs/HepPID/include/HepPID/ParticleIDMethods.hh @@ -39,10 +39,10 @@ int Z(const int & pid ); int lambda( const int & pid ); /// absolute value of particle ID -int abspid( const int & pid ); +int abspid( const int & pid ); /// extract fundamental ID (1-100) if this is a "fundamental" particle -int fundamentalID( const int & pid ); +int fundamentalID( const int & pid ); /// if this is a fundamental particle, does it have a valid antiparticle? bool hasFundamentalAnti( const int & pid ); diff --git a/src/Nucleus.cpp b/src/Nucleus.cpp index 28576c5ce..913bb9f0e 100644 --- a/src/Nucleus.cpp +++ b/src/Nucleus.cpp @@ -62,4 +62,12 @@ double getNucleusMass(int id) { return mass; } +int getChargeNumberFromNucleusId(int id) { + return HepPID::Z(id); +} + +int getMassNumberFromNucleusId(int id) { + return HepPID::A(id); +} + } // namespace mpc diff --git a/src/Source.cpp b/src/Source.cpp index 17d658003..e607b6d96 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -1,23 +1,24 @@ #include "mpc/Source.h" - #include "mpc/Random.h" +#include "HepPID/ParticleIDMethods.hh" + +#include + namespace mpc { BasicSource::BasicSource() : position(Vector3d(0, 0, 0)), id(0), index1(-1), index2(-1), breakpoint( 10 * EeV), Emin(5 * EeV), Emax(1000 * EeV) { - } -BasicSource::BasicSource(const Vector3d &sposition, int type, double Emin, +BasicSource::BasicSource(const Vector3d &position, int id, double Emin, double Emax, double index1, double index2, double breakpoint) : position(position), id(id), index1(index1), index2(index2), breakpoint( breakpoint), Emin(Emin), Emax(Emax) { } void BasicSource::prepare(ParticleState &state) const { - state.setPosition(position); state.setId(id); double E = Random::instance().randBrokenPowerLaw(index1, index2, breakpoint, @@ -26,4 +27,59 @@ void BasicSource::prepare(ParticleState &state) const { state.setDirection(Random::instance().randUnitVectorOnSphere()); } +CompositeSource::CompositeSource() : + position(Vector3d(0, 0, 0)), Emin(5), Emax(1000), index(-1) { +} + +CompositeSource::CompositeSource(const Vector3d& position, double Emin, + double Emax, double index) : + position(position), Emin(Emin), Emax(Emax), index(index) { +} + +CompositeSource::Isotope::Isotope() : + id(getNucleusId(1, 1)), abundance(1), probability(0) { +} + +CompositeSource::Isotope::Isotope(int id, double abundance) : + id(id), abundance(abundance), probability(0) { +} + +void CompositeSource::addToComposition(int id, double abundance) { + Isotope iso(id, abundance); + composition.push_back(iso); + normalize(); +} + +void CompositeSource::normalize() { + double pSum = 0; + double a = 1 + index; + for (int i = 0; i < composition.size(); i++) { + Isotope &iso = composition[i]; + int Z = HepPID::Z(iso.id); + if (std::abs(a) < std::numeric_limits::min()) // index = -1 + pSum += iso.abundance * log(Z * Emax / Emin); + else + // index <> -1 + pSum += iso.abundance / a * (pow(Z * Emax, a) - pow(Emin, a)); + iso.probability = pSum; + } + for (int i = 0; i < composition.size(); i++) { + composition[i].probability /= pSum; + } +} + +void CompositeSource::prepare(ParticleState& state) const { + if (composition.size() == 0) + throw std::runtime_error("mpc::CompositeSource: No source isotope set"); + double r = Random().rand(); + int i = -1; + while (r < composition[i + 1].probability) + i++; + state.setId(composition[i].id); + double E = Random::instance().randPowerLaw(index, Emin, Emax); + state.setEnergy(E); + state.setPosition(position); + state.setDirection(Random::instance().randUnitVectorOnSphere()); +} + } // namespace mpc diff --git a/src/magneticField/SPHTurbulentMagneticField.cpp b/src/magneticField/SPHTurbulentMagneticField.cpp index 41f99c83d..ed5153c22 100644 --- a/src/magneticField/SPHTurbulentMagneticField.cpp +++ b/src/magneticField/SPHTurbulentMagneticField.cpp @@ -4,7 +4,7 @@ namespace mpc { -void SPHTurbulentMagneticField::modulate(std::string filename, double weight) { +void SPHTurbulentMagneticField::modulate(std::string filename, double weight = 2./3) { // create SPH Field to obtain baryon density std::cout << "mpc::SPHTurbulentMagneticField: Loading SPH-field: " << filename << std::endl; diff --git a/test/python/testTurbulentField.py b/test/python/testTurbulentField.py index 5579b157a..f2d116ad0 100644 --- a/test/python/testTurbulentField.py +++ b/test/python/testTurbulentField.py @@ -166,7 +166,7 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): grid() s = 'Correlation Length\n Nominal %.2f\n Simulated %.2f $\pm$ %.2f'%(Lc, mean(Lcs), std(Lcs)/(len(Lcs))**.5) text(0.5, 0.95, s, ha='left', va='top', transform=gca().transAxes) -savefig('TurbulentField_correlationCurves.png', bbox_inches='tight') +savefig('TurbulentField_coherenceLength.png', bbox_inches='tight') ### plot energy spectrum figure() diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index f363bcd45..84fe0d09f 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -5,10 +5,6 @@ namespace mpc { -class ModuleTest: public testing::Test { -protected: -}; - TEST(MinimumEnergy, Continue) { MinimumEnergy minEnergy(5); Candidate candidate; From aa01eb6d37a591baeb0ce49ff28697dd7fea95d1 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 5 Jun 2012 18:24:35 +0200 Subject: [PATCH 0119/1298] add testSource.py --- include/mpc/Source.h | 27 ++++++++-------- src/Source.cpp | 45 +++++++++++--------------- test/python/testSource.py | 61 +++++++++++++++++++++++++++++++++++ test/testSource.cpp | 67 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 41 deletions(-) create mode 100644 test/python/testSource.py create mode 100644 test/testSource.cpp diff --git a/include/mpc/Source.h b/include/mpc/Source.h index 6d33bad5a..b0d173421 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -43,27 +43,26 @@ class BasicSource: public Source { */ class CompositeSource: public Source { public: - /** - @class Isotope - @brief Source isotope - */ - struct Isotope { - public: - int id; - double abundance; - double probability; - Isotope(); - Isotope(int id, double abundance); - }; - + /** source position */ Vector3d position; + /** differential spectral index, minimum and maximum energy */ double index, Emin, Emax; - std::vector composition; + /** source isotopes ids */ + std::vector isotope; + /** relative abundance of source isotopes at equal energies */ + std::vector abundance; + /** cumulative probability of source isotopes */ + std::vector probability; + CompositeSource(); CompositeSource(const Vector3d &sposition, double Emin = 5 * EeV, double Emax = 1000 * EeV, double index = -1); + + /** add an isotope the source */ void addToComposition(int id, double abundance); + /** calculate the probability for each isotope */ void normalize(); + /** prepare a random particle */ virtual void prepare(ParticleState &state) const; }; diff --git a/src/Source.cpp b/src/Source.cpp index e607b6d96..1bebcdfa7 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -36,48 +36,39 @@ CompositeSource::CompositeSource(const Vector3d& position, double Emin, position(position), Emin(Emin), Emax(Emax), index(index) { } -CompositeSource::Isotope::Isotope() : - id(getNucleusId(1, 1)), abundance(1), probability(0) { -} - -CompositeSource::Isotope::Isotope(int id, double abundance) : - id(id), abundance(abundance), probability(0) { -} - -void CompositeSource::addToComposition(int id, double abundance) { - Isotope iso(id, abundance); - composition.push_back(iso); +void CompositeSource::addToComposition(int id, double a) { + isotope.push_back(id); + abundance.push_back(a); + probability.push_back(0); normalize(); } void CompositeSource::normalize() { double pSum = 0; double a = 1 + index; - for (int i = 0; i < composition.size(); i++) { - Isotope &iso = composition[i]; - int Z = HepPID::Z(iso.id); - if (std::abs(a) < std::numeric_limits::min()) // index = -1 - pSum += iso.abundance * log(Z * Emax / Emin); + for (int i = 0; i < isotope.size(); i++) { + int Z = HepPID::Z(isotope[i]); + if (std::abs(a) < std::numeric_limits::min()) + pSum += abundance[i] * log(Z * Emax / Emin); else - // index <> -1 - pSum += iso.abundance / a * (pow(Z * Emax, a) - pow(Emin, a)); - iso.probability = pSum; + pSum += abundance[i] / a * (pow(Z * Emax, a) - pow(Emin, a)); + probability[i] = pSum; } - for (int i = 0; i < composition.size(); i++) { - composition[i].probability /= pSum; + for (int i = 0; i < probability.size(); i++) { + probability[i] /= pSum; } } void CompositeSource::prepare(ParticleState& state) const { - if (composition.size() == 0) + if (isotope.size() == 0) throw std::runtime_error("mpc::CompositeSource: No source isotope set"); double r = Random().rand(); - int i = -1; - while (r < composition[i + 1].probability) + int i = 0; + while ((r > probability[i]) and (i < probability.size())) i++; - state.setId(composition[i].id); - double E = Random::instance().randPowerLaw(index, Emin, Emax); - state.setEnergy(E); + state.setId(isotope[i]); + int Z = HepPID::Z(isotope[i]); + state.setEnergy(Random::instance().randPowerLaw(index, Emin, Z * Emax)); state.setPosition(position); state.setDirection(Random::instance().randUnitVectorOnSphere()); } diff --git a/test/python/testSource.py b/test/python/testSource.py new file mode 100644 index 000000000..5da07410c --- /dev/null +++ b/test/python/testSource.py @@ -0,0 +1,61 @@ +from mpc import * +from pylab import * + +source = CompositeSource(Vector3d(0.), 10, 100, -1) + +def add(A, Z, w): + source.addToComposition(getNucleusId(A, Z), w * A) + +# DuVernois +add(1, 1, 92000) +add(4, 2, 13000) +add(12, 6, 447.4) +add(14, 7, 34.2) +add(16, 8, 526.3) +add(20, 10, 58.0) +add(23, 11, 3.2) +add(24, 12, 108.0) +add(27, 13, 7.8) +add(28, 14, 100) +add(32, 16, 13.1) +add(40, 18, 2.2) +add(40, 20, 6.5) +add(52, 24, 1.5) +add(55, 25, 1.1) +add(56, 26, 97) + +state = ParticleState() +N = 10000 +Etot = zeros(N) +E1, E2, E3, E4 = [], [], [], [] +for i in range(N): + source.prepare(state) + lE = log10(state.getEnergy()) + 18 + Z = state.getChargeNumber() + Etot[i] = lE + if Z == 1: + E1.append(lE) + elif Z == 2: + E2.append(lE) + elif Z <= 8: + E3.append(lE) + else: + E4.append(lE) + +E1 = array(E1) +E2 = array(E2) +E3 = array(E3) +E4 = array(E4) + +figure() +hist(E1, weights=ones(len(E1))*1./N, bins=20, range=[19, 21.5], histtype='step', lw=2, label='H') +hist(E2, weights=ones(len(E2))*1./N, bins=20, range=[19, 21.5], histtype='step', lw=2, label='He') +hist(E3, weights=ones(len(E3))*1./N, bins=20, range=[19, 21.5], histtype='step', lw=2, label='$Z \leq 8$') +hist(E4, weights=ones(len(E4))*1./N, bins=20, range=[19, 21.5], histtype='step', lw=2, label='$Z > 8$') +ylim(1e-4, 1) +xlabel('$\log_{10}(E/\mathrm{eV})$') +ylabel('Probability') +semilogy() +grid() +legend() +savefig('Source.png') diff --git a/test/testSource.cpp b/test/testSource.cpp new file mode 100644 index 000000000..cb18edb26 --- /dev/null +++ b/test/testSource.cpp @@ -0,0 +1,67 @@ +#include "mpc/Source.h" + +#include "gtest/gtest.h" + +#include + +namespace mpc { + +TEST(testBasicSource, simpleTest) { + Vector3d position(1, 2, 3); + int id = getNucleusId(4,2); + double Emin = 4 * EeV; + double Emax = 200 * EeV; + double breakpoint = 25 * EeV; + double index1 = -2.7; + double index2 = -4.2; + BasicSource source(position, id, Emin, Emax, index1, index2, breakpoint); + ParticleState ps; + source.prepare(ps); + EXPECT_EQ(4, ps.getMassNumber()); + EXPECT_EQ(2, ps.getChargeNumber()); + EXPECT_EQ(position, ps.getPosition()); + EXPECT_LE(Emin, ps.getEnergy()); + EXPECT_GE(Emax, ps.getEnergy()); +} + +TEST(testCompositeSource, simpleTest) { + Vector3d position(1, 2, 3); + double Emin = 10; + double Emax = 100; + double index = -2; + CompositeSource source(position, Emin, Emax, index); + source.addToComposition(getNucleusId(6, 3), 1); + ParticleState ps; + source.prepare(ps); + EXPECT_EQ(6, ps.getMassNumber()); + EXPECT_EQ(3, ps.getChargeNumber()); + EXPECT_EQ(position, ps.getPosition()); + EXPECT_LE(Emin, ps.getEnergy()); + EXPECT_GE(Emax, ps.getEnergy()); +} + +TEST(testCompositeSource, spectralIndexOne) { + Vector3d position(1, 2, 3); + double Emin = 10; + double Emax = 100; + double index = -1; + CompositeSource source(position, Emin, Emax, index); + source.addToComposition(getNucleusId(1, 1), 1); + ParticleState ps; + source.prepare(ps); + EXPECT_LE(Emin, ps.getEnergy()); + EXPECT_GE(Emax, ps.getEnergy()); +} + +TEST(testCompositeSource, throwNoIsotope) { + CompositeSource source; + ParticleState ps; + EXPECT_THROW(source.prepare(ps), std::runtime_error); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + +} // namespace mpc From b2a41cbbc4d0d8316d6819a6de29f82827320dd8 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 11 Jun 2012 11:17:30 +0200 Subject: [PATCH 0120/1298] ModuleList fix percentage, add test --- CMakeLists.txt | 4 +++ src/ModuleList.cpp | 36 ++++++++++---------------- test/testModuleList.cpp | 57 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 22 deletions(-) create mode 100644 test/testModuleList.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3839fdcaa..fa7e2523b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,6 +119,10 @@ if(ENABLETESTING) add_executable(testCore test/testCore.cpp) target_link_libraries(testCore mpc gtest gtest_main pthread) add_test(testCore testCore) + + add_executable(testModuleList test/testModuleList.cpp) + target_link_libraries(testModuleList mpc gtest gtest_main pthread) + add_test(testModuleList testModuleList) add_executable(testMagneticField test/testMagneticField.cpp) target_link_libraries(testMagneticField mpc gtest gtest_main pthread) diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 340b56f2e..db429367e 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -47,48 +47,40 @@ void ModuleList::run(Candidate *candidate, bool recursive) { void ModuleList::run(candidate_vector_t &candidates, bool recursive) { size_t count = candidates.size(); - size_t cent = count / 100; - if (cent == 0) - cent = 1; size_t pc = 0; -#pragma omp parallel for schedule(dynamic, 1000) - for (size_t i = 0; i < count; i++) { #if _OPENMP - if (i == 0) { - std::cout << "Number of Threads: " << omp_get_num_threads() - << std::endl; - } + std::cout << "mpc::ModuleList: Number of Threads: " << omp_get_max_threads() << std::endl; #endif - if (showProgress && (i % cent == 0)) { +#pragma omp parallel for schedule(dynamic, 1000) + for (size_t i = 0; i < count; i++) { + if (showProgress && ((i * 100) / count > pc)) { + pc += ceil(100. / count); std::cout << pc << "% - " << i << std::endl; - pc++; } run(candidates[i], recursive); } + if (showProgress) + std::cout << "100% - " << count << std::endl; } void ModuleList::run(Source *source, size_t count, bool recursive) { - size_t cent = count / 100; - if (cent == 0) - cent = 1; size_t pc = 0; -#pragma omp parallel for schedule(dynamic, 1000) - for (size_t i = 0; i < count; i++) { #if _OPENMP - if (i == 0) { - std::cout << "Number of Threads: " << omp_get_num_threads() - << std::endl; - } + std::cout << "mpc::ModuleList: Number of Threads: " << omp_get_max_threads() << std::endl; #endif - if (showProgress && (i % cent == 0)) { +#pragma omp parallel for schedule(dynamic, 1000) + for (size_t i = 0; i < count; i++) { + if (showProgress && ((i * 100) / count > pc)) { + pc += ceil(100. / count); std::cout << pc << "% - " << i << std::endl; - pc++; } ParticleState state; source->prepare(state); ref_ptr candidate = new Candidate(state); run(candidate, recursive); } + if (showProgress) + std::cout << "100% - " << count << std::endl; } ModuleList::module_list_t &ModuleList::getModules() { diff --git a/test/testModuleList.cpp b/test/testModuleList.cpp new file mode 100644 index 000000000..4610ce19f --- /dev/null +++ b/test/testModuleList.cpp @@ -0,0 +1,57 @@ +#include "mpc/ModuleList.h" +#include "mpc/module/SimplePropagation.h" +#include "mpc/module/BreakCondition.h" +#include "mpc/Source.h" + +#include "gtest/gtest.h" + +namespace mpc { + +TEST(ModuleList, process) { + ModuleList modules; + modules.add(new SimplePropagation()); + ParticleState initial; + ref_ptr candidate = new Candidate(initial); + modules.process(candidate); +} + +TEST(ModuleList, runCandidateList) { + ModuleList modules; + modules.add(new SimplePropagation()); + modules.add(new MaximumTrajectoryLength(1 * Mpc)); + ParticleState initial; + ref_ptr candidate = new Candidate(initial); + modules.run(candidate); + EXPECT_DOUBLE_EQ(1 * Mpc, candidate->getTrajectoryLength()); + EXPECT_TRUE(candidate->isActive() == false); +} + +TEST(ModuleList, runSource) { + ModuleList modules; + modules.add(new SimplePropagation()); + modules.add(new MaximumTrajectoryLength(1 * Mpc)); + CompositeSource source(Vector3d(0.), 10., 100., -1.); + source.addToComposition(getNucleusId(56, 26), 1); + modules.setShowProgress(true); + modules.run(&source, 100, false); +} + +#if _OPENMP +#include +TEST(ModuleList, runOpenMP) { + ModuleList modules; + modules.add(new SimplePropagation()); + modules.add(new MaximumTrajectoryLength(1 * Mpc)); + CompositeSource source(Vector3d(0.), 10., 100., -1.); + source.addToComposition(getNucleusId(56, 26), 1); + omp_set_num_threads(2); + modules.run(&source, 100, false); +} +#endif + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + +} // namespace mpc From 46f1968468563f1b44679fa84e271fc4a3854fd4 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 11 Jun 2012 23:36:21 +0200 Subject: [PATCH 0121/1298] major refactoring of MagneticFieldGrid small changes to user interface improved documentation --- include/mpc/magneticField/MagneticFieldGrid.h | 62 ++++++++++++--- .../magneticField/SPHTurbulentMagneticField.h | 17 +++- .../magneticField/TurbulentMagneticField.h | 70 +++++++++++------ src/magneticField/MagneticFieldGrid.cpp | 60 +++++++++++++- .../SPHTurbulentMagneticField.cpp | 44 +++-------- src/magneticField/TurbulentMagneticField.cpp | 78 +++++++++++-------- test/python/testTurbulentDeflection.py | 5 +- test/python/testTurbulentField.py | 62 ++++++++------- test/testMagneticField.cpp | 38 +++++---- test/testModuleList.cpp | 2 +- test/testSPHField.cpp | 6 +- 11 files changed, 293 insertions(+), 151 deletions(-) diff --git a/include/mpc/magneticField/MagneticFieldGrid.h b/include/mpc/magneticField/MagneticFieldGrid.h index e4c66b720..2f7d990d5 100644 --- a/include/mpc/magneticField/MagneticFieldGrid.h +++ b/include/mpc/magneticField/MagneticFieldGrid.h @@ -2,6 +2,7 @@ #define MPC_MAGNETICFIELDGRID_H_ #include "mpc/magneticField/MagneticField.h" + #include namespace mpc { @@ -11,34 +12,73 @@ namespace mpc { @brief Periodic, cubic, cartesian magnetic field grid with trilinear interpolation. This class provides a magnetic field grid. - The grid spacing is constant and equal along all three axes (cartesian). - The grid is of cubic shape. - Magnetic field values are calculated by trilinear interpolation of the surrounding 8 grid points. + The grid is of cubic shape and the spacing is constant and equal along all three axes. + Magnetic field values are calculated by trilinear interpolation of the surrounding 8 grid points. \n The grid is periodically extended. + Thus the field at opposite borders is assumed identical and does not need to be sampled twice. + The grid sample positions are hence at 0, size / samples, ... size * (samples - 1) / samples and the grid spacing is size / samples. */ class MagneticFieldGrid: public MagneticField { public: + /** + * Constructor + * @param origin Lower left front corner of the grid + * @param size Physical extension of the field grid + * @param samples Number of grid samples per edge + */ MagneticFieldGrid(Vector3d origin, double size, size_t samples); + + /** + * Multiply the field by a factor. + * @param norm Normalization factor + */ + void normalize(double norm); + + /** + * Modulate the magnetic field with a density field from a binary file. + * The field should be (re)normalized afterwards. + * The file has to contain the density values in float precision on a grid with N + 1 samples per edge, the last of which is disregarded due to periodicity. + * @param filename Path to the density grid file + * @param exp Exponent for the modulation + */ + void modulateWithDensityField(std::string filename, double exp = 2. / 3.); + + /** Return a reference to the grid point (ix, iy, iz). */ Vector3f &get(size_t ix, size_t iy, size_t iz); const Vector3f &get(size_t ix, size_t iy, size_t iz) const; + + /** Return the field vector at arbitrary position by trilinear interpolation. */ Vector3d getField(const Vector3d &position) const; + + /** Return the RMS field strength */ + double getRMSFieldStrength() const; + + /** + * Return the RMS field strength inside a spherical region + * @param center Center of the sphere + * @param radius Radius of the sphere + */ + double getRMSFieldStrengthInSphere(Vector3d center, double radius) const; + Vector3d getGridOrigin() const; size_t getGridSamples() const; double getGridSpacing() const; double getGridSize() const; + + /** Update the fields origin and size. */ virtual void updateSimulationVolume(const Vector3d &origin, double size); + protected: - /** Grid of magnetic field vectors. - * Since the grid is periodic the field at opposite borders is identical and does not need to be sampled twice. - * The field is thus sampled at 0, size / samples, ... size * (samples - 1) / samples. */ - std::vector grid; - Vector3d origin; /** Origin of the field */ - double size; /** Extension of the field */ - size_t samples; /** Number of grid points per edge */ - double spacing; /** Distance between two grid points (= size / samples) */ + std::vector grid; /**< Grid of magnetic field vectors */ + Vector3d origin; /**< Origin of the field */ + double size; /**< Extension of the field */ + size_t samples; /**< Number of grid points per edge */ + + double spacing; /**< Distance between two grid points (= size / samples) */ }; +/** Lower and upper neighbor in a periodically continued unit grid */ void periodicClamp(double x, int n, int &lo, int &hi); } // namespace mpc diff --git a/include/mpc/magneticField/SPHTurbulentMagneticField.h b/include/mpc/magneticField/SPHTurbulentMagneticField.h index 32f985f42..2334a0e48 100644 --- a/include/mpc/magneticField/SPHTurbulentMagneticField.h +++ b/include/mpc/magneticField/SPHTurbulentMagneticField.h @@ -13,10 +13,25 @@ namespace mpc { */ class SPHTurbulentMagneticField: public TurbulentMagneticField { public: + /** Constructor. Reimplementation of TurbulentMagneticField. */ SPHTurbulentMagneticField(Vector3d origin, double size, size_t samples) : TurbulentMagneticField(origin, size, samples) { } - void modulate(std::string filename, double weight); + + /** Constructor. Reimplementation of TurbulentMagneticField. */ + SPHTurbulentMagneticField(Vector3d origin, double size, size_t samples, + double lMin, double lMax, double spectralIndex, double Brms) : + TurbulentMagneticField(origin, size, samples, lMin, lMax, + spectralIndex, Brms) { + } + + /** + * Modulate the magnetic field with the baryon density from a gadget SPH field. + * The field should be (re)normalized afterwards. + * @param filename Path to the SPH database file + * @param exp Exponent for the modulation + */ + void modulate(std::string filename, double exp); }; } // namespace mpc diff --git a/include/mpc/magneticField/TurbulentMagneticField.h b/include/mpc/magneticField/TurbulentMagneticField.h index 8c87ea61b..5c49488b6 100644 --- a/include/mpc/magneticField/TurbulentMagneticField.h +++ b/include/mpc/magneticField/TurbulentMagneticField.h @@ -10,36 +10,58 @@ namespace mpc { @class TurbulentMagneticField @brief Random turbulent magnetic field on a cubic grid with trilinear interpolation. - This class creates a random magnetic field with the following properties. \n - mean and rms strength: \n - \f$ <\vec{B}> = 0 \f$ \n - \f$ = B_{rms}^2\f$ \n - turbulent range and spectrum: \n - \f$ \vec{B}(\vec{k}) \sim k^{-11/3} \f$ for \f$ k_{min} < k < k_{max} \f$ \n - \f$ \vec{B}(\vec{k}) = 0 \f$ otherwise \n - solenoidity: \n - \f$ \nabla \vec{B}(\vec{x}) = 0 \f$ \n - isotropy: \n - same coherence length in all directions + This class creates a random magnetic field with a turbulent spectrum. + The field is isotropic and homogeneous with a zero mean magnetic field and and divergence. */ class TurbulentMagneticField: public MagneticFieldGrid { public: - TurbulentMagneticField(Vector3d origin, double size, size_t samples) : - MagneticFieldGrid(origin, size, samples) { - } - void initialize(double lMin, double lMax, double Brms, - double powerSpectralIndex = -11. / 3.); - void setSeed(int seed); - double getRMSFieldStrength() const; - double getCorrelationLength() const; + /** + * Constructor + * @param origin Lower left front corner of the grid + * @param size Physical extension of the field grid + * @param samples Number of grid samples per edge + */ + TurbulentMagneticField(Vector3d origin, double size, size_t samples); + + /** + * Constructor, also performs initialization and normalization. + * @param origin Lower left front corner of the grid + * @param size Physical extension of the field grid + * @param samples Number of grid samples per edge + * @param lMin Minimum wavelength of the turbulence + * @param lMax Maximum wavelength of the turbulence + * @param spectralIndex Power spectral index of the turbulence + * @param Brms RMS field strength + */ + TurbulentMagneticField(Vector3d origin, double size, size_t samples, + double lMin, double lMax, double spectralIndex, double Brms); + + /** + * Define the properties of the turbulence. + * @param lMin Minimum wavelength of the turbulence + * @param lMax Maximum wavelength of the turbulence + * @param spectralIndex Power spectral index turbulence + */ + void setTurbulenceProperties(double lMin, double lMax, double spectralIndex); + + /** Create a random initialization of the turbulent field. */ + void initialize(); + + /** Create a random initialization from a given seed. */ + void initialize(int seed); + double getPowerSpectralIndex() const; + double getMinimumWavelength() const; + double getMaximumWavelength() const; + + /** Return the analytical calculation of the correlation length. */ + double getCorrelationLength() const; protected: - double Brms; /** RMS field strength */ - double lMin; /** minimum coherent length scale */ - double lMax; /** maximum coherent lenght scale */ - double powerSpectralIndex; /** turbulence spectral index */ - Random random; /** random number generator instance */ + double lMin; /**< Minimum wavelength of the turbulence */ + double lMax; /**< Maximum wavelength of the turbulence */ + double spectralIndex; /**< Power spectral index of the turbulence */ + Random random; /**< Random number generator instance */ }; } // namespace mpc diff --git a/src/magneticField/MagneticFieldGrid.cpp b/src/magneticField/MagneticFieldGrid.cpp index 4d7a7f582..b783ed90b 100644 --- a/src/magneticField/MagneticFieldGrid.cpp +++ b/src/magneticField/MagneticFieldGrid.cpp @@ -1,8 +1,10 @@ #include "mpc/magneticField/MagneticFieldGrid.h" +#include +#include + namespace mpc { -/** lower and upper neighbor in a periodically continued unit grid */ void periodicClamp(double x, int n, int &lo, int &hi) { lo = ( ( int(floor(x)) % n ) + n ) % n; hi = (lo + 1) % n; @@ -24,6 +26,35 @@ void MagneticFieldGrid::updateSimulationVolume(const Vector3d &origin, this->spacing = size / samples; } +void MagneticFieldGrid::normalize(double norm) { + for (int ix = 0; ix < samples; ix++) + for (int iy = 0; iy < samples; iy++) + for (int iz = 0; iz < samples; iz++) + get(ix, iy, iz) *= norm; +} + +void MagneticFieldGrid::modulateWithDensityField(std::string filename, + double exp) { + std::ifstream infile(filename.c_str(), std::ios::binary); + if (!infile) + throw std::runtime_error("mpc::MagneticFieldGrid: File not found"); + double sumB2 = 0; + int numB2 = 0; + float rho; + for (int ix = 0; ix < samples + 1; ix++) { + for (int iy = 0; iy < samples + 1; iy++) { + for (int iz = 0; iz < samples + 1; iz++) { + infile.read((char*) &rho, sizeof(float)); + if ((ix == samples) or (iy == samples) or (iz == samples)) + continue; // skip last grid points in each direction + Vector3d pos = origin + Vector3d(ix, iy, iz) * spacing; + Vector3f &b = get(ix, iy, iz); + b *= pow(rho, exp); + } + } + } +} + Vector3d MagneticFieldGrid::getGridOrigin() const { return origin; } @@ -40,6 +71,33 @@ double MagneticFieldGrid::getGridSize() const { return size; } +double MagneticFieldGrid::getRMSFieldStrength() const { + double sumB2 = 0; + for (int ix = 0; ix < samples; ix++) + for (int iy = 0; iy < samples; iy++) + for (int iz = 0; iz < samples; iz++) + sumB2 += get(ix, iy, iz).getMag2(); + return sqrt(sumB2 / samples / samples / samples); +} + +double MagneticFieldGrid::getRMSFieldStrengthInSphere(Vector3d center, + double radius) const { + int numB2 = 0; + double sumB2 = 0; + for (int ix = 0; ix < samples; ix++) { + for (int iy = 0; iy < samples; iy++) { + for (int iz = 0; iz < samples; iz++) { + Vector3d position = origin + Vector3d(ix, iy, iz) * spacing; + if (position.getDistanceTo(center) < radius) { + sumB2 += get(ix, iy, iz).getMag2(); + numB2++; + } + } + } + } + return sqrt(sumB2 / numB2); +} + Vector3f &MagneticFieldGrid::get(size_t ix, size_t iy, size_t iz) { int i = ix * samples * samples + iy * samples + iz; return grid[i]; diff --git a/src/magneticField/SPHTurbulentMagneticField.cpp b/src/magneticField/SPHTurbulentMagneticField.cpp index ed5153c22..846474bf5 100644 --- a/src/magneticField/SPHTurbulentMagneticField.cpp +++ b/src/magneticField/SPHTurbulentMagneticField.cpp @@ -4,46 +4,22 @@ namespace mpc { -void SPHTurbulentMagneticField::modulate(std::string filename, double weight = 2./3) { - // create SPH Field to obtain baryon density - std::cout << "mpc::SPHTurbulentMagneticField: Loading SPH-field: " - << filename << std::endl; - // SPHMagneticField may fail on borders, choose minimally larger size - Vector3d safeOrigin = origin - Vector3d(1.); - double safeSize = size + 2; +void SPHTurbulentMagneticField::modulate(std::string filename, double weight) { + // SPHMagneticField fails on borders, choose minimally larger size + Vector3d safeOrigin = origin - Vector3d(kpc); + double safeSize = size + 2 * kpc; SPHMagneticField sph(safeOrigin, safeSize, 20, filename); - // modulate and calculate renormalization - std::cout << "mpc::SPHTurbulentMagneticField: Modulate turbulent field." - << std::endl; - double sumB2 = 0; - int numB2 = 0; - for (int ix = 0; ix < samples; ix++) - for (int iy = 0; iy < samples; iy++) + // modulate + for (int ix = 0; ix < samples; ix++) { + for (int iy = 0; iy < samples; iy++) { for (int iz = 0; iz < samples; iz++) { Vector3d pos = origin + Vector3d(ix, iy, iz) * spacing; double rho = sph.getRho(pos); - Vector3f &b = get(ix, iy, iz); - b *= pow(rho, weight); - double distance2center = (pos - Vector3d(120 * Mpc)).getMag(); - if (distance2center < 110 * Mpc) { - sumB2 += b.getMag2(); - numB2++; - } - } - - // renormalize - std::cout << "mpc::SPHTurbulentMagneticField: Normalize turbulent field." - << std::endl; - double norm = Brms / sqrt(sumB2 / numB2); - Brms = 0; - for (int ix = 0; ix < samples; ix++) - for (int iy = 0; iy < samples; iy++) - for (int iz = 0; iz < samples; iz++) { - Vector3f &b = get(ix, iy, iz); - b *= norm; - Brms += b.getMag2(); + get(ix, iy, iz) *= pow(rho, weight); } + } + } } } // namespace mpc diff --git a/src/magneticField/TurbulentMagneticField.cpp b/src/magneticField/TurbulentMagneticField.cpp index c5d877acd..4490b0f18 100644 --- a/src/magneticField/TurbulentMagneticField.cpp +++ b/src/magneticField/TurbulentMagneticField.cpp @@ -1,27 +1,47 @@ #include "mpc/magneticField/TurbulentMagneticField.h" +#include "mpc/Units.h" #include "fftw3.h" -#include namespace mpc { -void TurbulentMagneticField::setSeed(int seed) { - random.seed(seed); +TurbulentMagneticField::TurbulentMagneticField(Vector3d origin, double size, + size_t samples) : + MagneticFieldGrid(origin, size, samples) { +} + +TurbulentMagneticField::TurbulentMagneticField(Vector3d origin, double size, + size_t samples, double lMin, double lMax, double spectralIndex, + double Brms) : + MagneticFieldGrid(origin, size, samples) { + this->lMin = lMin; + this->lMax = lMax; + this->spectralIndex = spectralIndex; + initialize(); + normalize(Brms / getRMSFieldStrength()); } -void TurbulentMagneticField::initialize(double lMin, double lMax, double Brms, - double powerSpectralIndex) { +void TurbulentMagneticField::setTurbulenceProperties(double lMin, double lMax, + double spectralIndex) { this->lMin = lMin; this->lMax = lMax; - this->Brms = Brms; - this->powerSpectralIndex = powerSpectralIndex; + this->spectralIndex = spectralIndex; +} +void TurbulentMagneticField::initialize(int seed) { + random.seed(seed); + initialize(); +} + +void TurbulentMagneticField::initialize() { if (lMin < 2 * spacing) - throw std::runtime_error("mpc::TurbulentMagneticField: lMin < 2 * spacing"); + throw std::runtime_error( + "mpc::TurbulentMagneticField: lMin < 2 * spacing"); if (lMin >= lMax) throw std::runtime_error("mpc::TurbulentMagneticField: lMin >= lMax"); if (lMax > size / 2) - throw std::runtime_error("mpc::TurbulentMagneticField: lMax > size / 2"); + throw std::runtime_error( + "mpc::TurbulentMagneticField: lMax > size / 2"); size_t n = samples; // size of array size_t n2 = (size_t) floor(n / 2) + 1; // size array in z-direction in configuration space @@ -83,7 +103,7 @@ void TurbulentMagneticField::initialize(double lMin, double lMax, double Brms, b = e1 * cos(theta) + e2 * sin(theta); // standard normal distributed amplitude weighted with k^alpha/2 - b *= random.randNorm() * pow(k, powerSpectralIndex / 2.); + b *= random.randNorm() * pow(k, spectralIndex / 2.); // uniform random phase phase = 2 * M_PI * random.rand(); @@ -117,43 +137,39 @@ void TurbulentMagneticField::initialize(double lMin, double lMax, double Brms, fftwf_execute(plan_z); fftwf_destroy_plan(plan_z); - // calculate normalization - double sumB2 = 0; - for (size_t ix = 0; ix < n; ix++) - for (size_t iy = 0; iy < n; iy++) - for (size_t iz = 0; iz < n; iz++) { - i = ix * n * 2 * n2 + iy * 2 * n2 + iz; - sumB2 += pow(Bx[i], 2) + pow(By[i], 2) + pow(Bz[i], 2); - } - double w = Brms / sqrt(sumB2 / (n * n * n)); - - // normalize and save to grid - for (size_t ix = 0; ix < n; ix++) - for (size_t iy = 0; iy < n; iy++) + // save to grid + for (size_t ix = 0; ix < n; ix++) { + for (size_t iy = 0; iy < n; iy++) { for (size_t iz = 0; iz < n; iz++) { i = ix * n * 2 * n2 + iy * 2 * n2 + iz; Vector3f &b = get(ix, iy, iz); - b.x = Bx[i] * w; - b.y = By[i] * w; - b.z = Bz[i] * w; + b.x = Bx[i]; + b.y = By[i]; + b.z = Bz[i]; } + } + } fftwf_free(Bkx); fftwf_free(Bky); fftwf_free(Bkz); } -double TurbulentMagneticField::getRMSFieldStrength() const { - return Brms; +double TurbulentMagneticField::getPowerSpectralIndex() const { + return spectralIndex; } -double TurbulentMagneticField::getPowerSpectralIndex() const { - return powerSpectralIndex; +double TurbulentMagneticField::getMinimumWavelength() const { + return lMin; +} + +double TurbulentMagneticField::getMaximumWavelength() const { + return lMax; } double TurbulentMagneticField::getCorrelationLength() const { double r = lMin / lMax; - double a = -powerSpectralIndex - 2; + double a = -spectralIndex - 2; return lMax / 2 * (a - 1) / a * (1 - pow(r, a)) / (1 - pow(r, a - 1)); } diff --git a/test/python/testTurbulentDeflection.py b/test/python/testTurbulentDeflection.py index 80a8afb11..971952029 100644 --- a/test/python/testTurbulentDeflection.py +++ b/test/python/testTurbulentDeflection.py @@ -8,15 +8,14 @@ nP = range(75) # sampling points for plot # create turbulent field with B_RMS = 1 nG and 0.5 Mpc correlation length -field = TurbulentMagneticField(Vector3d(0, 0, 0), 256 * 0.05 * Mpc, 256) -field.initialize(0.1 * Mpc, 2.2 * Mpc, 1 * nG, -11/3.) +field = TurbulentMagneticField(Vector3d(0, 0, 0), 256 * 0.05 * Mpc, 256, 0.1 * Mpc, 2.2 * Mpc, -11/3., 1 * nG) propa = DeflectionCK(field) age = linspace(1, 150, nS) distance, rms1, rms2 = zeros((3, nS)) for j in range(nT): - if j%(nT//10) == 0: + if j % (nT // 10) == 0: print j ps = ParticleState() diff --git a/test/python/testTurbulentField.py b/test/python/testTurbulentField.py index f2d116ad0..1eefa00fc 100644 --- a/test/python/testTurbulentField.py +++ b/test/python/testTurbulentField.py @@ -80,47 +80,64 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): ### create field n = 128 lMin, lMax = 2, 32 -Brms = 1 +Brms = 1. alpha = -11./3 field = TurbulentMagneticField(Vector3d(0, 0, 0), n, n) -field.initialize(lMin, lMax, Brms, alpha) +field.setTurbulenceProperties(lMin, lMax, alpha) +field.initialize() +field.normalize(Brms / field.getRMSFieldStrength()) Lc = field.getCorrelationLength() ### copy field grid to array(s) Bx, By, Bz = zeros((3, n, n, n)) for ix in range(n): + print ix for iy in range(n): for iz in range(n): - b = field.getField(Vector3d(ix, iy, iz)) + b = field.get(ix, iy, iz) Bx[ix, iy, iz] = b.x By[ix, iy, iz] = b.y Bz[ix, iy, iz] = b.z ### plot slice in position space -figure() -A = ((Bx**2 + By**2 + Bz**2)**.5)[:,:,n/2] -im = imshow(A, origin='lower', extent=[0,n,0,n], vmin=0, vmax=3) +figure(figsize=(8,6)) +A1 = (Bx[:,:,n/2]**2 + By[:,:,n/2]**2 + Bz[:,:,n/2]**2)**.5 +im = imshow(A1, origin='lower', extent=[0,n,0,n], vmin=0, vmax=3) cbar = colorbar(im) -cbar.set_label(r'$|\vec{B}(\vec{x})| / B_{rms}$') +cbar.set_label('$B/B_{rms}$') xlabel('$x$') ylabel('$y$') text(0.8, 1.05, '$z=%i$'%(n/2), transform=gca().transAxes) savefig('TurbulentField_slicePositionSpace.png', bbox_inches='tight') +### plot slice and periodical extension in position space +figure() +A2 = zeros((3*n,3*n)) +for i,j in ((0,1), (1,0), (1,1), (1,2), (2,1)): + A2[i*n:(i+1)*n, j*n:(j+1)*n] = A1 +im = imshow(ma.masked_array(A2, A2 == 0), origin='lower', extent=[-n,2*n,-n,2*n], vmin=0, vmax=3) +cbar = colorbar(im) +cbar.set_label(r'$|\vec{B_x}|/B_{rms}$') +xticks([-n, 0, n, 2*n]) +yticks([-n, 0, n, 2*n]) +xlabel('$x$') +ylabel('$y$') +text(0.8, 1.05, '$z=%i$'%(n/2), transform=gca().transAxes) +savefig('TurbulentField_slicePeriodicity.png', bbox_inches='tight') + ### plot slice in configuration space figure() Bkx = fftshift(fftn(Bx)) Bky = fftshift(fftn(By)) Bkz = fftshift(fftn(Bz)) -Bk = ((Bkx*Bkx.conjugate() + Bky*Bky.conjugate() + Bkz*Bkz.conjugate()).real)**.5 -A = log10(Bk[:,:,n/2]) -im = imshow(A, origin='lower', vmin=0) +Bk = (((Bkx*Bkx.conjugate() + Bky*Bky.conjugate() + Bkz*Bkz.conjugate()).real)**.5) +im = imshow(log10(Bk[:,:,n/2]), origin='lower', vmin=0) cbar = colorbar(im) -cbar.set_label(r'$log_{10}(|\vec{B}(\vec{k})| / B_{rms})$') +cbar.set_label(r'$\log_{10}(B/B_{rms})$') xlabel('$k_x$') ylabel('$k_y$') k = fftshift(fftfreq(n)) -idx = arange(0,n,n/4) +idx = arange(0, n, n/4) xticks(idx, k[idx]) yticks(idx, k[idx]) xlim(0,n) @@ -128,21 +145,6 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): text(0.8, 1.05, '$k_z=%.2f$'%k[n/2], transform=gca().transAxes) savefig('TurbulentField_sliceConfigurationSpace.png', bbox_inches='tight') -### plot slice and periodical extension in position space -figure() -A = zeros((3*n,3*n)) -for i,j in ((0,1), (1,0), (1,1), (1,2), (2,1)): - A[i*n:(i+1)*n, j*n:(j+1)*n] = Bx[:,:,n/2] -im = imshow(ma.masked_array(A, A == 0), origin='lower', extent=[-n,2*n,-n,2*n], vmin=0, vmax=3) -cbar = colorbar(im) -cbar.set_label(r'$|\vec{B_x}|/B_{rms}$') -xticks([-n, 0, n, 2*n]) -yticks([-n, 0, n, 2*n]) -xlabel('$x$') -ylabel('$y$') -text(0.8, 1.05, '$z=%i$'%(n/2), transform=gca().transAxes) -savefig('TurbulentField_slicePeriodicity.png', bbox_inches='tight') - ### plot (2pt-auto-)correlation curves for various directions figure() corr = VectorFieldAutoCorrelation(Bx,By,Bz) @@ -188,9 +190,9 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): Bx.resize(n**3) By.resize(n**3) Bz.resize(n**3) -hist(Bx, bins=40, range=(-3,3), histtype='step', normed=True, label='$B_x$', linewidth=2) -hist(By, bins=40, range=(-3,3), histtype='step', normed=True, label='$B_y$', linewidth=2) -hist(Bz, bins=40, range=(-3,3), histtype='step', normed=True, label='$B_z$', linewidth=2) +hist(log10(Bx), bins=40, range=(-3,3), histtype='step', normed=True, label='$B_x$', linewidth=2) +hist(log10(By), bins=40, range=(-3,3), histtype='step', normed=True, label='$B_y$', linewidth=2) +hist(log10(Bz), bins=40, range=(-3,3), histtype='step', normed=True, label='$B_z$', linewidth=2) legend() grid() xlabel('$B/B_{RMS}$') diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index 33a81c56b..31bfa02b2 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -53,7 +53,7 @@ TEST(testMagneticFieldGrid, Interpolation) { EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.15, B.getField(Vector3d(0, 2.15, 0.9) * spacing).x); } -TEST(testMagneticFieldGrid, Interpolation2) { +TEST(testMagneticFieldGrid, Normalization) { // If the field is uniform, (interpolated) field values should be the same everywhere MagneticFieldGrid B(Vector3d(0.), 3, 3); for (int ix = 0; ix < 3; ix++) @@ -61,9 +61,13 @@ TEST(testMagneticFieldGrid, Interpolation2) { for (int iz = 0; iz < 3; iz++) B.get(ix, iy, iz) = Vector3f(1, 0, 0); - double spacing = B.getGridSpacing(); EXPECT_FLOAT_EQ(1, B.getField(Vector3d(0.7, 0, 0.1)).x); EXPECT_FLOAT_EQ(1, B.getField(Vector3d(0, 1.3, 0.9)).x); + + B.normalize(2); + + EXPECT_FLOAT_EQ(2, B.getField(Vector3d(0.7, 0, 0.1)).x); + EXPECT_FLOAT_EQ(2, B.getField(Vector3d(0, 1.3, 0.9)).x); } TEST(testMagneticFieldGrid, Periodicity) { @@ -97,18 +101,17 @@ TEST(testMagneticFieldGrid, Periodicity) { TEST(testTurbulentMagneticField, Bmean) { // Test for zero mean: = 0 size_t n = 64; - TurbulentMagneticField B(Vector3d(0, 0, 0), 10 * Mpc, n); - double spacing = B.getGridSpacing(); - B.initialize(2 * spacing, 8 * spacing, 1, -11. / 3.); + double spacing = 10 * Mpc / n; + TurbulentMagneticField B(Vector3d(0, 0, 0), 10 * Mpc, n, 2 * spacing, 8 * spacing, -11. / 3., 1.); Vector3d b(0, 0, 0); for (int ix = 0; ix < n; ix++) for (int iy = 0; iy < n; iy++) for (int iz = 0; iz < n; iz++) b += B.getField(Vector3d(ix, iy, iz) * spacing); - b /= n * n * n; - double precision = 1e-7; + + double precision = 1e-9; EXPECT_NEAR(b.x, 0, precision); EXPECT_NEAR(b.y, 0, precision); EXPECT_NEAR(b.z, 0, precision); @@ -119,8 +122,9 @@ TEST(testTurbulentMagneticField, Brms) { size_t n = 100; TurbulentMagneticField B(Vector3d(0, 0, 0), 10 * Mpc, n); double spacing = B.getGridSpacing(); - B.initialize(2 * spacing, 8 * spacing, 1, -11. / 3.); - + B.setTurbulenceProperties(2 * spacing, 8 * spacing, -11./3.); + B.initialize(); + B.normalize(1. / B.getRMSFieldStrength()); double brms = 0; for (int ix = 0; ix < n; ix++) for (int iy = 0; iy < n; iy++) @@ -136,14 +140,22 @@ TEST(testTurbulentMagneticField, Exceptions) { // Test exceptions TurbulentMagneticField B(Vector3d(0, 0, 0), 10, 64); double spacing = B.getGridSpacing(); + // should be fine - EXPECT_NO_THROW(B.initialize(2 * spacing, 8 * spacing, 1, -11. / 3.)); + B.setTurbulenceProperties(2 * spacing, 8 * spacing, -11. / 3.); + EXPECT_NO_THROW(B.initialize()); + // lMin too small - EXPECT_THROW(B.initialize(1.9 * spacing, 8 * spacing, 1, -11. / 3.), std::runtime_error); + B.setTurbulenceProperties(1.5 * spacing, 8 * spacing, -11. / 3.); + EXPECT_THROW(B.initialize(), std::runtime_error); + // lMin > lMax - EXPECT_THROW(B.initialize(8.1 * spacing, 8 * spacing, 1, -11. / 3.), std::runtime_error); + B.setTurbulenceProperties(8.1 * spacing, 8 * spacing, -11. / 3.); + EXPECT_THROW(B.initialize(), std::runtime_error); + // lMax too large - EXPECT_THROW(B.initialize(2 * spacing, 5.1, 1, -11. / 3.), std::runtime_error); + B.setTurbulenceProperties(2 * spacing, 33 * spacing, -11. / 3.); + EXPECT_THROW(B.initialize(), std::runtime_error); } int main(int argc, char **argv) { diff --git a/test/testModuleList.cpp b/test/testModuleList.cpp index 4610ce19f..4c86dfeec 100644 --- a/test/testModuleList.cpp +++ b/test/testModuleList.cpp @@ -45,7 +45,7 @@ TEST(ModuleList, runOpenMP) { CompositeSource source(Vector3d(0.), 10., 100., -1.); source.addToComposition(getNucleusId(56, 26), 1); omp_set_num_threads(2); - modules.run(&source, 100, false); + modules.run(&source, 1000, false); } #endif diff --git a/test/testSPHField.cpp b/test/testSPHField.cpp index 9082a2b7a..7a35f7f8a 100644 --- a/test/testSPHField.cpp +++ b/test/testSPHField.cpp @@ -70,12 +70,14 @@ TEST(testSPHMagneticFieldGrid, simpleTest) { TEST(testSPHTurbulentMagneticField, modulatedField) { // Test for correct rms and mean strength Vector3d origin(80 * Mpc); - int n = 64; + size_t n = 64; SPHTurbulentMagneticField B(origin, 40 * Mpc, n); double spacing = B.getGridSpacing(); - B.initialize(2 * spacing, 8 * spacing, 1, -11./3); + B.setTurbulenceProperties(2 * spacing, 8 * spacing, -11./3); + B.initialize(); B.modulate(getDataPath("SPH/mhd_z.db").c_str(), 2./3); + B.normalize(1. / B.getRMSFieldStrengthInSphere(Vector3d(120 * Mpc), 105 * Mpc)); double brms = 0; Vector3d bmean(0, 0, 0); From c4394ff188825a9e6f25c5fac17f6556f190f502 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 12 Jun 2012 12:10:00 +0200 Subject: [PATCH 0122/1298] MagneticFieldGrid load and dump --- include/mpc/magneticField/MagneticFieldGrid.h | 12 ++++++ src/magneticField/MagneticFieldGrid.cpp | 37 ++++++++++++++++++- src/main.cpp | 4 +- test/testMagneticField.cpp | 25 +++++++++++++ 4 files changed, 75 insertions(+), 3 deletions(-) diff --git a/include/mpc/magneticField/MagneticFieldGrid.h b/include/mpc/magneticField/MagneticFieldGrid.h index 2f7d990d5..128f41a14 100644 --- a/include/mpc/magneticField/MagneticFieldGrid.h +++ b/include/mpc/magneticField/MagneticFieldGrid.h @@ -34,6 +34,18 @@ class MagneticFieldGrid: public MagneticField { */ void normalize(double norm); + /** + * Load the field from a binary file. + * The field is stored single precision numbers with the field components in xyz order and the grid z-index changing the fastest. + */ + void load(std::string filename); + + /** + * Dump the field to a binary file. + * The field is stored single precision numbers with the field components in xyz order and the grid z-index changing the fastest. + */ + void dump(std::string filename) const; + /** * Modulate the magnetic field with a density field from a binary file. * The field should be (re)normalized afterwards. diff --git a/src/magneticField/MagneticFieldGrid.cpp b/src/magneticField/MagneticFieldGrid.cpp index b783ed90b..50603371b 100644 --- a/src/magneticField/MagneticFieldGrid.cpp +++ b/src/magneticField/MagneticFieldGrid.cpp @@ -33,6 +33,40 @@ void MagneticFieldGrid::normalize(double norm) { get(ix, iy, iz) *= norm; } +void MagneticFieldGrid::load(std::string filename) { + std::ifstream infile(filename.c_str(), std::ios::binary); + if (!infile) + throw std::runtime_error("mpc::MagneticFieldGrid: File not found"); + for (int ix = 0; ix < samples; ix++) { + for (int iy = 0; iy < samples; iy++) { + for (int iz = 0; iz < samples; iz++) { + Vector3f &b = get(ix, iy, iz); + infile.read((char*) &(b.x), sizeof(float)); + infile.read((char*) &(b.y), sizeof(float)); + infile.read((char*) &(b.z), sizeof(float)); + } + } + } + infile.close(); +} + +void MagneticFieldGrid::dump(std::string filename) const { + std::ofstream outfile(filename.c_str(), std::ios::binary); + if (!outfile) + throw std::runtime_error("mpc::MagneticFieldGrid: Could not open file"); + for (int ix = 0; ix < samples; ix++) { + for (int iy = 0; iy < samples; iy++) { + for (int iz = 0; iz < samples; iz++) { + Vector3f b = get(ix, iy, iz); + outfile.write((char*) &(b.x), sizeof(float)); + outfile.write((char*) &(b.y), sizeof(float)); + outfile.write((char*) &(b.z), sizeof(float)); + } + } + } + outfile.close(); +} + void MagneticFieldGrid::modulateWithDensityField(std::string filename, double exp) { std::ifstream infile(filename.c_str(), std::ios::binary); @@ -53,6 +87,7 @@ void MagneticFieldGrid::modulateWithDensityField(std::string filename, } } } + infile.close(); } Vector3d MagneticFieldGrid::getGridOrigin() const { @@ -118,7 +153,7 @@ Vector3d MagneticFieldGrid::getField(const Vector3d &position) const { periodicClamp(r.y, samples, iy, iY); periodicClamp(r.z, samples, iz, iZ); - // linear fraction to lower and upper neighbor + // linear fraction to lower and upper neighbors double fx = r.x - floor(r.x); double fX = 1 - fx; double fy = r.y - floor(r.y); diff --git a/src/main.cpp b/src/main.cpp index ada116f82..8fc2e193e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,8 +16,8 @@ int main(int argc, char **argv) { ModuleList modules; // propagation -------------------------------------------------------- - TurbulentMagneticField *bField = new TurbulentMagneticField(Vector3d(0, 0, 0), 64, 1.); - bField->initialize(2., 8., 1e-12, -11. / 3.); + TurbulentMagneticField *bField = new TurbulentMagneticField(Vector3d(0, 0, 0), 64, 1., 2., 8., 1e-12, -11. / 3.); + bField->initialize(); modules.add(new DeflectionCK(bField)); // interactions ------------------------------------------------------- diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index 31bfa02b2..5ec0e1542 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -98,6 +98,31 @@ TEST(testMagneticFieldGrid, Periodicity) { EXPECT_FLOAT_EQ(b.z, b2.z); } +TEST(testMagneticFieldGrid, DumpLoad) { + // Dump and load a field grid + MagneticFieldGrid B1(Vector3d(0.), 3, 3); + for (int ix = 0; ix < 3; ix++) + for (int iy = 0; iy < 3; iy++) + for (int iz = 0; iz < 3; iz++) + B1.get(ix, iy, iz) = Vector3f(1, 2, 3); + B1.dump("testDump.raw"); + + MagneticFieldGrid B2(Vector3d(0.), 3, 3); + B2.load("testDump.raw"); + + for (int ix = 0; ix < 3; ix++) { + for (int iy = 0; iy < 3; iy++) { + for (int iz = 0; iz < 3; iz++) { + Vector3f b1 = B1.get(ix, iy, iz); + Vector3f b2 = B2.get(ix, iy, iz); + EXPECT_FLOAT_EQ(b1.x, b2.x); + EXPECT_FLOAT_EQ(b1.y, b2.y); + EXPECT_FLOAT_EQ(b1.z, b2.z); + } + } + } +} + TEST(testTurbulentMagneticField, Bmean) { // Test for zero mean: = 0 size_t n = 64; From 679d35cdb14200a715627a01e734462a4c291b67 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 19 Jun 2012 18:26:47 +0200 Subject: [PATCH 0123/1298] add get/set for BreakConditions --- include/mpc/module/BreakCondition.h | 20 ++++++++++++++++---- src/module/BreakCondition.cpp | 16 ++++++++++++++++ src/module/Output.cpp | 11 ++++++----- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/include/mpc/module/BreakCondition.h b/include/mpc/module/BreakCondition.h index 1f7731756..46f35c405 100644 --- a/include/mpc/module/BreakCondition.h +++ b/include/mpc/module/BreakCondition.h @@ -9,26 +9,38 @@ namespace mpc { /** @class MaximumTrajectoryLength - @brief Stops propagation after the set maximum trajectory length. + @brief Stops propagation after a maximum trajectory length. + + This modules deactivates the candidate at a given maximum trajectory length. + In that case the property ("Deactivated", module::description) is set. + It also limits the candidates next step size to ensure the maximum trajectory length is no exceeded. */ class MaximumTrajectoryLength: public Module { private: double maxLength; public: - MaximumTrajectoryLength(double length); + MaximumTrajectoryLength(double length = 0); + void setMaximumTrajectoryLength(double length); + double getMaximumTrajectoryLength() const; void process(Candidate *candidate) const; }; /** @class MinimumEnergy @brief Stops propagation if energy drops under the set minimum energy. + + This modules deactivates the candidate below a give minimum energy. + In that case the property ("Deactivated", module::description) is set. */ class MinimumEnergy: public Module { -public: +private: double minEnergy; - MinimumEnergy(double minEnergy); +public: + MinimumEnergy(double minEnergy = 0); + void setMinimumEnergy(double energy); + double getMinimumEnergy() const; void process(Candidate *candidate) const; }; diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp index 9aeaf437a..78dae6ae2 100644 --- a/src/module/BreakCondition.cpp +++ b/src/module/BreakCondition.cpp @@ -9,6 +9,14 @@ MaximumTrajectoryLength::MaximumTrajectoryLength(double length) : setDescription(s.str()); } +void MaximumTrajectoryLength::setMaximumTrajectoryLength(double length) { + maxLength = length; +} + +double MaximumTrajectoryLength::getMaximumTrajectoryLength() const { + return maxLength; +} + void MaximumTrajectoryLength::process(Candidate *candidate) const { double l = candidate->getTrajectoryLength(); if (l >= maxLength) { @@ -25,6 +33,14 @@ MinimumEnergy::MinimumEnergy(double minEnergy) : setDescription(s.str()); } +void MinimumEnergy::setMinimumEnergy(double energy) { + minEnergy = energy; +} + +double MinimumEnergy::getMinimumEnergy() const { + return minEnergy; +} + void MinimumEnergy::process(Candidate *candidate) const { if (candidate->current.getEnergy() <= minEnergy) { candidate->setActive(false); diff --git a/src/module/Output.cpp b/src/module/Output.cpp index d79186e46..3cc5a0179 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -45,7 +45,7 @@ ConditionalOutput::ConditionalOutput(std::string filename, propertyName = propName; outfile.open(filename.c_str()); outfile - << "id, x, y, z, E, phi, theta, distance, i_id, i_x, i_y, i_z, i_E, i_phi, i_theta" + << "# id, x, y, z, E, phi, theta, distance, i_id, i_x, i_y, i_z, i_E, i_phi, i_theta" << std::endl; } @@ -69,7 +69,8 @@ void ConditionalOutput::process(Candidate *candidate) const { const Vector3d &dir = candidate->current.getDirection(); p += ::sprintf(buffer + p, ", %f, %f, %f", - candidate->current.getEnergy() / EeV, dir.getPhi(), dir.getTheta()); + candidate->current.getEnergy() / EeV, dir.getPhi(), + dir.getTheta()); p += ::sprintf(buffer + p, ", %f", candidate->getTrajectoryLength() / Mpc); @@ -77,12 +78,12 @@ void ConditionalOutput::process(Candidate *candidate) const { p += ::sprintf(buffer + p, ", %d", candidate->initial.getId()); const Vector3d &ipos = candidate->initial.getPosition() / Mpc; - p += ::sprintf(buffer + p, ", %f, %f, %f", ipos.x, ipos.y, - ipos.z); + p += ::sprintf(buffer + p, ", %f, %f, %f", ipos.x, ipos.y, ipos.z); const Vector3d &idir = candidate->initial.getDirection(); p += ::sprintf(buffer + p, ", %f, %f, %f\n", - candidate->initial.getEnergy() / EeV, idir.getPhi(), idir.getTheta()); + candidate->initial.getEnergy() / EeV, idir.getPhi(), + idir.getTheta()); #pragma omp critical { From 6ba09c5c8c21a5ead4578f53f0e47897398944d9 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 26 Jun 2012 15:08:32 +0200 Subject: [PATCH 0124/1298] renamed TurbulentMagneticField to TurbulentMagneticFieldGrid renamed SPHTurbulentMagneticField to SPHTurbulentMagneticFieldGrid added TurbulentMagneticField (not working correctly yet) changed SPHTurbulentMagneticFieldGrid to modulate on the fly --- CMakeLists.txt | 5 +- include/mpc/magneticField/SPHMagneticField.h | 3 +- .../magneticField/SPHTurbulentMagneticField.h | 40 ---------- .../SPHTurbulentMagneticFieldGrid.h | 57 +++++++++++++++ ...icField.h => TurbulentMagneticFieldGrid.h} | 8 +- python/mpc.i | 6 +- src/magneticField/SPHMagneticField.cpp | 3 +- .../SPHTurbulentMagneticField.cpp | 25 ------- .../SPHTurbulentMagneticFieldGrid.cpp | 23 ++++++ ...eld.cpp => TurbulentMagneticFieldGrid.cpp} | 20 ++--- src/main.cpp | 4 +- test/python/testTurbulentDeflection.py | 2 +- ...lentField.py => testTurbulentFieldGrid.py} | 2 +- test/testMagneticField.cpp | 73 ++++++++++++++++--- test/testSPHField.cpp | 31 ++++---- 15 files changed, 190 insertions(+), 112 deletions(-) delete mode 100644 include/mpc/magneticField/SPHTurbulentMagneticField.h create mode 100644 include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h rename include/mpc/magneticField/{TurbulentMagneticField.h => TurbulentMagneticFieldGrid.h} (89%) delete mode 100644 src/magneticField/SPHTurbulentMagneticField.cpp create mode 100644 src/magneticField/SPHTurbulentMagneticFieldGrid.cpp rename src/magneticField/{TurbulentMagneticField.cpp => TurbulentMagneticFieldGrid.cpp} (86%) rename test/python/{testTurbulentField.py => testTurbulentFieldGrid.py} (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa7e2523b..cd5f05871 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,7 +44,7 @@ endif() # fftw3f (optional for turbulent magnetic fields) find_package(FFTW3F) if (FFTW3F_FOUND) - list(APPEND MPC_EXTRA_SOURCES src/magneticField/TurbulentMagneticField.cpp) + list(APPEND MPC_EXTRA_SOURCES src/magneticField/TurbulentMagneticFieldGrid.cpp) list(APPEND MPC_EXTRA_INCLUDES ${FFTW3F_INCLUDE_DIR}) list(APPEND MPC_EXTRA_LIBRARIES ${FFTW3F_LIBRARY}) endif (FFTW3F_FOUND) @@ -59,7 +59,7 @@ if (GADGET_FOUND) list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_GADGET) # fftw3f needed for SPHTurbulentMagneticField if (FFTW3F_FOUND) - list(APPEND MPC_EXTRA_SOURCES src/magneticField/SPHTurbulentMagneticField.cpp) + list(APPEND MPC_EXTRA_SOURCES src/magneticField/SPHTurbulentMagneticFieldGrid.cpp) endif (FFTW3F_FOUND) endif (GADGET_FOUND) @@ -98,6 +98,7 @@ add_library(mpc SHARED src/module/Output.cpp src/module/Tools.cpp src/magneticField/MagneticFieldGrid.cpp + src/magneticField/TurbulentMagneticField.cpp ${MPC_EXTRA_SOURCES} ) target_link_libraries(mpc ${MPC_EXTRA_LIBRARIES}) diff --git a/include/mpc/magneticField/SPHMagneticField.h b/include/mpc/magneticField/SPHMagneticField.h index 390f10ab2..23dd0083c 100644 --- a/include/mpc/magneticField/SPHMagneticField.h +++ b/include/mpc/magneticField/SPHMagneticField.h @@ -29,8 +29,9 @@ class SPHMagneticField: public MagneticField { SPHMagneticField(Vector3d origin, double size, size_t samples, std::string filename); SPHMagneticField(size_t samples, std::string filename); + Vector3d getField(const Vector3d &position) const; - double getRho(const Vector3d &position) const; + double getRho(const Vector3d &position) const; /*< Return the density in [kg / m^3] */ void updateSimulationVolume(const Vector3d &origin, double size); }; diff --git a/include/mpc/magneticField/SPHTurbulentMagneticField.h b/include/mpc/magneticField/SPHTurbulentMagneticField.h deleted file mode 100644 index 2334a0e48..000000000 --- a/include/mpc/magneticField/SPHTurbulentMagneticField.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef MPC_SPHTURBULENTMAGNETICFIELD_H_ -#define MPC_SPHTURBULENTMAGNETICFIELD_H_ - -#include "mpc/magneticField/TurbulentMagneticField.h" - -#ifdef MPC_HAVE_GADGET - -namespace mpc { - -/** - @class SPHTurbulentMagneticField - @brief Random turbulent magnetic field on a cubic grid modulated with large scale structure. - */ -class SPHTurbulentMagneticField: public TurbulentMagneticField { -public: - /** Constructor. Reimplementation of TurbulentMagneticField. */ - SPHTurbulentMagneticField(Vector3d origin, double size, size_t samples) : - TurbulentMagneticField(origin, size, samples) { - } - - /** Constructor. Reimplementation of TurbulentMagneticField. */ - SPHTurbulentMagneticField(Vector3d origin, double size, size_t samples, - double lMin, double lMax, double spectralIndex, double Brms) : - TurbulentMagneticField(origin, size, samples, lMin, lMax, - spectralIndex, Brms) { - } - - /** - * Modulate the magnetic field with the baryon density from a gadget SPH field. - * The field should be (re)normalized afterwards. - * @param filename Path to the SPH database file - * @param exp Exponent for the modulation - */ - void modulate(std::string filename, double exp); -}; - -} // namespace mpc - -#endif // MPC_HAVE_GADGET -#endif // MPC_SPHTURBULENTMAGNETICFIELD_H_ diff --git a/include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h b/include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h new file mode 100644 index 000000000..36cef5fdc --- /dev/null +++ b/include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h @@ -0,0 +1,57 @@ +#ifndef MPC_SPHTURBULENTMAGNETICFIELDGRID_H_ +#define MPC_SPHTURBULENTMAGNETICFIELDGRID_H_ + +#ifdef MPC_HAVE_GADGET + +#include "mpc/magneticField/TurbulentMagneticFieldGrid.h" +#include "mpc/magneticField/SPHMagneticField.h" + +#include + +namespace mpc { + +/** + @class SPHTurbulentMagneticFieldGrid + @brief Random turbulent magnetic field on a cubic grid modulated with an SPH density field. + */ +class SPHTurbulentMagneticFieldGrid: public TurbulentMagneticFieldGrid { +public: + /** Constructor. Reimplementation of TurbulentMagneticField. */ + SPHTurbulentMagneticFieldGrid(Vector3d origin, double size, size_t samples) : + TurbulentMagneticFieldGrid(origin, size, samples) { + } + + /** Constructor. Reimplementation of TurbulentMagneticField. */ + SPHTurbulentMagneticFieldGrid(Vector3d origin, double size, size_t samples, + double lMin, double lMax, double spectralIndex, double Brms) : + TurbulentMagneticFieldGrid(origin, size, samples, lMin, lMax, + spectralIndex, Brms) { + } + + /** + * Modulate the magnetic field with the baryon density from a gadget SPH field. + * @param filename Path to the SPH database file + * @param origin Origin of the SPH field + * @param size Size of the SPH field + * @param bins Number of bins of the SPH field + * @param exp Exponent for the density modulation + * @param norm Normalization of the field strength + */ + void setModulation(std::string filename, Vector3d origin, double size, + size_t samples, double exp, double norm); + + /** Get the density modulated magnetic field vector */ + Vector3d getField(const Vector3d &position) const; + + /** Get the density in [10^10 M_sol * h^2 / kpc^3] */ + double getRho(const Vector3d &position) const; + + double exponent; /**< Exponent of modulation with the density field */ + double normalization; /**< Normalization factor */ + std::auto_ptr sphField; /**< SPH (density) field */ +}; + +} // namespace mpc + +#endif // MPC_HAVE_GADGET +#endif // MPC_SPHTURBULENTMAGNETICFIELDGRID_H_ diff --git a/include/mpc/magneticField/TurbulentMagneticField.h b/include/mpc/magneticField/TurbulentMagneticFieldGrid.h similarity index 89% rename from include/mpc/magneticField/TurbulentMagneticField.h rename to include/mpc/magneticField/TurbulentMagneticFieldGrid.h index 5c49488b6..e639535c8 100644 --- a/include/mpc/magneticField/TurbulentMagneticField.h +++ b/include/mpc/magneticField/TurbulentMagneticFieldGrid.h @@ -7,13 +7,13 @@ namespace mpc { /** - @class TurbulentMagneticField + @class TurbulentMagneticFieldGrid @brief Random turbulent magnetic field on a cubic grid with trilinear interpolation. This class creates a random magnetic field with a turbulent spectrum. The field is isotropic and homogeneous with a zero mean magnetic field and and divergence. */ -class TurbulentMagneticField: public MagneticFieldGrid { +class TurbulentMagneticFieldGrid: public MagneticFieldGrid { public: /** * Constructor @@ -21,7 +21,7 @@ class TurbulentMagneticField: public MagneticFieldGrid { * @param size Physical extension of the field grid * @param samples Number of grid samples per edge */ - TurbulentMagneticField(Vector3d origin, double size, size_t samples); + TurbulentMagneticFieldGrid(Vector3d origin, double size, size_t samples); /** * Constructor, also performs initialization and normalization. @@ -33,7 +33,7 @@ class TurbulentMagneticField: public MagneticFieldGrid { * @param spectralIndex Power spectral index of the turbulence * @param Brms RMS field strength */ - TurbulentMagneticField(Vector3d origin, double size, size_t samples, + TurbulentMagneticFieldGrid(Vector3d origin, double size, size_t samples, double lMin, double lMax, double spectralIndex, double Brms); /** diff --git a/python/mpc.i b/python/mpc.i index ed0a59f6d..ed5c6360d 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -29,9 +29,10 @@ #include "mpc/magneticField/MagneticField.h" #include "mpc/magneticField/UniformMagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" +#include "mpc/magneticField/TurbulentMagneticFieldGrid.h" #include "mpc/magneticField/TurbulentMagneticField.h" #include "mpc/magneticField/SPHMagneticField.h" -#include "mpc/magneticField/SPHTurbulentMagneticField.h" +#include "mpc/magneticField/SPHTurbulentMagneticFieldGrid.h" #include "mpc/Referenced.h" #include "mpc/Candidate.h" @@ -105,9 +106,10 @@ %include "mpc/magneticField/MagneticField.h" %include "mpc/magneticField/UniformMagneticField.h" %include "mpc/magneticField/MagneticFieldGrid.h" +%include "mpc/magneticField/TurbulentMagneticFieldGrid.h" %include "mpc/magneticField/TurbulentMagneticField.h" %include "mpc/magneticField/SPHMagneticField.h" -%include "mpc/magneticField/SPHTurbulentMagneticField.h" +%include "mpc/magneticField/SPHTurbulentMagneticFieldGrid.h" %include "mpc/ExplicitRungeKutta.h" %include "mpc/PhasePoint.h" diff --git a/src/magneticField/SPHMagneticField.cpp b/src/magneticField/SPHMagneticField.cpp index 53bc796a5..88e55f7df 100644 --- a/src/magneticField/SPHMagneticField.cpp +++ b/src/magneticField/SPHMagneticField.cpp @@ -28,7 +28,8 @@ Vector3d SPHMagneticField::getField(const Vector3d &position) const { double SPHMagneticField::getRho(const Vector3d& position) const { gadget::Vector3f r = gadget::Vector3f(position.x, position.y, position.z); size_t overlaps = 0; - return (double) field.getRho(r / kpc, overlaps); + double rho = field.getRho(r / kpc, overlaps); + return rho * 1.98892e40 * kilogram * pow(0.7, 2) / pow(kpc, 3); } void SPHMagneticField::updateSimulationVolume(const Vector3d &origin, double size) { diff --git a/src/magneticField/SPHTurbulentMagneticField.cpp b/src/magneticField/SPHTurbulentMagneticField.cpp deleted file mode 100644 index 846474bf5..000000000 --- a/src/magneticField/SPHTurbulentMagneticField.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "mpc/magneticField/SPHTurbulentMagneticField.h" -#include "mpc/magneticField/SPHMagneticField.h" -#include "mpc/Units.h" - -namespace mpc { - -void SPHTurbulentMagneticField::modulate(std::string filename, double weight) { - // SPHMagneticField fails on borders, choose minimally larger size - Vector3d safeOrigin = origin - Vector3d(kpc); - double safeSize = size + 2 * kpc; - SPHMagneticField sph(safeOrigin, safeSize, 20, filename); - - // modulate - for (int ix = 0; ix < samples; ix++) { - for (int iy = 0; iy < samples; iy++) { - for (int iz = 0; iz < samples; iz++) { - Vector3d pos = origin + Vector3d(ix, iy, iz) * spacing; - double rho = sph.getRho(pos); - get(ix, iy, iz) *= pow(rho, weight); - } - } - } -} - -} // namespace mpc diff --git a/src/magneticField/SPHTurbulentMagneticFieldGrid.cpp b/src/magneticField/SPHTurbulentMagneticFieldGrid.cpp new file mode 100644 index 000000000..9b17fd072 --- /dev/null +++ b/src/magneticField/SPHTurbulentMagneticFieldGrid.cpp @@ -0,0 +1,23 @@ +#include "mpc/magneticField/SPHTurbulentMagneticFieldGrid.h" + +namespace mpc { + +void SPHTurbulentMagneticFieldGrid::setModulation(std::string filename, + Vector3d origin, double size, size_t samples, double exp, double norm) { + exponent = exp; + normalization = norm; + sphField.reset(new SPHMagneticField(origin, size, samples, filename)); +} + +Vector3d SPHTurbulentMagneticFieldGrid::getField( + const Vector3d &position) const { + Vector3d b = MagneticFieldGrid::getField(position); + double rho = sphField->getRho(position); + return b * pow(rho, exponent) * normalization; +} + +double SPHTurbulentMagneticFieldGrid::getRho(const Vector3d &position) const { + return sphField->getRho(position); +} + +} // namespace mpc diff --git a/src/magneticField/TurbulentMagneticField.cpp b/src/magneticField/TurbulentMagneticFieldGrid.cpp similarity index 86% rename from src/magneticField/TurbulentMagneticField.cpp rename to src/magneticField/TurbulentMagneticFieldGrid.cpp index 4490b0f18..7ff4df0c7 100644 --- a/src/magneticField/TurbulentMagneticField.cpp +++ b/src/magneticField/TurbulentMagneticFieldGrid.cpp @@ -1,16 +1,16 @@ -#include "mpc/magneticField/TurbulentMagneticField.h" +#include "mpc/magneticField/TurbulentMagneticFieldGrid.h" #include "mpc/Units.h" #include "fftw3.h" namespace mpc { -TurbulentMagneticField::TurbulentMagneticField(Vector3d origin, double size, +TurbulentMagneticFieldGrid::TurbulentMagneticFieldGrid(Vector3d origin, double size, size_t samples) : MagneticFieldGrid(origin, size, samples) { } -TurbulentMagneticField::TurbulentMagneticField(Vector3d origin, double size, +TurbulentMagneticFieldGrid::TurbulentMagneticFieldGrid(Vector3d origin, double size, size_t samples, double lMin, double lMax, double spectralIndex, double Brms) : MagneticFieldGrid(origin, size, samples) { @@ -21,19 +21,19 @@ TurbulentMagneticField::TurbulentMagneticField(Vector3d origin, double size, normalize(Brms / getRMSFieldStrength()); } -void TurbulentMagneticField::setTurbulenceProperties(double lMin, double lMax, +void TurbulentMagneticFieldGrid::setTurbulenceProperties(double lMin, double lMax, double spectralIndex) { this->lMin = lMin; this->lMax = lMax; this->spectralIndex = spectralIndex; } -void TurbulentMagneticField::initialize(int seed) { +void TurbulentMagneticFieldGrid::initialize(int seed) { random.seed(seed); initialize(); } -void TurbulentMagneticField::initialize() { +void TurbulentMagneticFieldGrid::initialize() { if (lMin < 2 * spacing) throw std::runtime_error( "mpc::TurbulentMagneticField: lMin < 2 * spacing"); @@ -155,19 +155,19 @@ void TurbulentMagneticField::initialize() { fftwf_free(Bkz); } -double TurbulentMagneticField::getPowerSpectralIndex() const { +double TurbulentMagneticFieldGrid::getPowerSpectralIndex() const { return spectralIndex; } -double TurbulentMagneticField::getMinimumWavelength() const { +double TurbulentMagneticFieldGrid::getMinimumWavelength() const { return lMin; } -double TurbulentMagneticField::getMaximumWavelength() const { +double TurbulentMagneticFieldGrid::getMaximumWavelength() const { return lMax; } -double TurbulentMagneticField::getCorrelationLength() const { +double TurbulentMagneticFieldGrid::getCorrelationLength() const { double r = lMin / lMax; double a = -spectralIndex - 2; return lMax / 2 * (a - 1) / a * (1 - pow(r, a)) / (1 - pow(r, a - 1)); diff --git a/src/main.cpp b/src/main.cpp index 8fc2e193e..9aaa99af3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,7 +8,7 @@ #include "mpc/module/PhotoDisintegration.h" #include "mpc/module/NuclearDecay.h" #include "mpc/magneticField/UniformMagneticField.h" -#include "mpc/magneticField/TurbulentMagneticField.h" +#include "mpc/magneticField/TurbulentMagneticFieldGrid.h" using namespace mpc; @@ -16,7 +16,7 @@ int main(int argc, char **argv) { ModuleList modules; // propagation -------------------------------------------------------- - TurbulentMagneticField *bField = new TurbulentMagneticField(Vector3d(0, 0, 0), 64, 1., 2., 8., 1e-12, -11. / 3.); + TurbulentMagneticFieldGrid *bField = new TurbulentMagneticFieldGrid(Vector3d(0, 0, 0), 64, 1., 2., 8., 1e-12, -11. / 3.); bField->initialize(); modules.add(new DeflectionCK(bField)); diff --git a/test/python/testTurbulentDeflection.py b/test/python/testTurbulentDeflection.py index 971952029..e832fa214 100644 --- a/test/python/testTurbulentDeflection.py +++ b/test/python/testTurbulentDeflection.py @@ -8,7 +8,7 @@ nP = range(75) # sampling points for plot # create turbulent field with B_RMS = 1 nG and 0.5 Mpc correlation length -field = TurbulentMagneticField(Vector3d(0, 0, 0), 256 * 0.05 * Mpc, 256, 0.1 * Mpc, 2.2 * Mpc, -11/3., 1 * nG) +field = TurbulentMagneticFieldGrid(Vector3d(0, 0, 0), 256 * 0.05 * Mpc, 256, 0.1 * Mpc, 2.2 * Mpc, -11/3., 1 * nG) propa = DeflectionCK(field) age = linspace(1, 150, nS) diff --git a/test/python/testTurbulentField.py b/test/python/testTurbulentFieldGrid.py similarity index 99% rename from test/python/testTurbulentField.py rename to test/python/testTurbulentFieldGrid.py index 1eefa00fc..2f650e39d 100644 --- a/test/python/testTurbulentField.py +++ b/test/python/testTurbulentFieldGrid.py @@ -82,7 +82,7 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): lMin, lMax = 2, 32 Brms = 1. alpha = -11./3 -field = TurbulentMagneticField(Vector3d(0, 0, 0), n, n) +field = TurbulentMagneticFieldGrid(Vector3d(0, 0, 0), n, n) field.setTurbulenceProperties(lMin, lMax, alpha) field.initialize() field.normalize(Brms / field.getRMSFieldStrength()) diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index 5ec0e1542..9f743242b 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -1,5 +1,6 @@ #include "mpc/magneticField/UniformMagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" +#include "mpc/magneticField/TurbulentMagneticFieldGrid.h" #include "mpc/magneticField/TurbulentMagneticField.h" #include "mpc/Units.h" @@ -49,8 +50,10 @@ TEST(testMagneticFieldGrid, Interpolation) { EXPECT_FLOAT_EQ(1.7 * 0.9, B.getField(Vector3d(0, 0, 0.9) * spacing).x); EXPECT_FLOAT_EQ(1.7 * 0.9, B.getField(Vector3d(0, 0, 1.1) * spacing).x); - EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.85, B.getField(Vector3d(0, 0.15, 0.9) * spacing).x); - EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.15, B.getField(Vector3d(0, 2.15, 0.9) * spacing).x); + EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.85, + B.getField(Vector3d(0, 0.15, 0.9) * spacing).x); + EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.15, + B.getField(Vector3d(0, 2.15, 0.9) * spacing).x); } TEST(testMagneticFieldGrid, Normalization) { @@ -123,11 +126,12 @@ TEST(testMagneticFieldGrid, DumpLoad) { } } -TEST(testTurbulentMagneticField, Bmean) { +TEST(testTurbulentMagneticFieldGrid, Bmean) { // Test for zero mean: = 0 size_t n = 64; double spacing = 10 * Mpc / n; - TurbulentMagneticField B(Vector3d(0, 0, 0), 10 * Mpc, n, 2 * spacing, 8 * spacing, -11. / 3., 1.); + TurbulentMagneticFieldGrid B(Vector3d(0, 0, 0), 10 * Mpc, n, 2 * spacing, + 8 * spacing, -11. / 3., 1.); Vector3d b(0, 0, 0); for (int ix = 0; ix < n; ix++) @@ -142,12 +146,12 @@ TEST(testTurbulentMagneticField, Bmean) { EXPECT_NEAR(b.z, 0, precision); } -TEST(testTurbulentMagneticField, Brms) { +TEST(testTurbulentMagneticFieldGrid, Brms) { // Test for correct RMS strength: = Brms^2 size_t n = 100; - TurbulentMagneticField B(Vector3d(0, 0, 0), 10 * Mpc, n); + TurbulentMagneticFieldGrid B(Vector3d(0, 0, 0), 10 * Mpc, n); double spacing = B.getGridSpacing(); - B.setTurbulenceProperties(2 * spacing, 8 * spacing, -11./3.); + B.setTurbulenceProperties(2 * spacing, 8 * spacing, -11. / 3.); B.initialize(); B.normalize(1. / B.getRMSFieldStrength()); double brms = 0; @@ -161,9 +165,9 @@ TEST(testTurbulentMagneticField, Brms) { EXPECT_NEAR(brms, 1, precision); } -TEST(testTurbulentMagneticField, Exceptions) { +TEST(testTurbulentMagneticFieldGrid, Exceptions) { // Test exceptions - TurbulentMagneticField B(Vector3d(0, 0, 0), 10, 64); + TurbulentMagneticFieldGrid B(Vector3d(0, 0, 0), 10, 64); double spacing = B.getGridSpacing(); // should be fine @@ -183,6 +187,57 @@ TEST(testTurbulentMagneticField, Exceptions) { EXPECT_THROW(B.initialize(), std::runtime_error); } +TEST(testTurbulentMagneticField, SimpleTest) { + TurbulentMagneticField B; + B.setTurbulenceProperties(1 * nG, 10 * parsec, 200 * parsec, -11./3., 1000); + B.initialize(); + Vector3d b1 = B.getField(Vector3d(0.)); + Vector3d b2 = B.getField(Vector3d(0.)); + EXPECT_DOUBLE_EQ(b1.x, b2.x); + EXPECT_DOUBLE_EQ(b1.y, b2.y); + EXPECT_DOUBLE_EQ(b1.z, b2.z); +} + +TEST(testTurbulentMagneticField, Brms) { + TurbulentMagneticField B; + B.setTurbulenceProperties(1, 0.1, 100); + B.initialize(); + double sumB2 = 0; + Vector3d Bmean, b; + int n = 20; + Random random; + for (int ix = 0; ix < n; ix++) { + for (int iy = 0; iy < n; iy++) { + for (int iz = 0; iz < n; iz++) { + b = B.getField(Vector3d(random.rand(), random.rand(), random.rand()) * 100000); + Bmean += b; + sumB2 = b.getMag2(); + } + } + } + Bmean /= pow(n, 3); + double Brms = sqrt(sumB2 / pow(n, 3)); + std::cout << Brms << std::endl; + std::cout << Bmean << std::endl; + +// EXPECT_NEAR(Bmean.x, 0, 1e-6); +// EXPECT_NEAR(Bmean.y, 0, 1e-6); +// EXPECT_NEAR(Bmean.z, 0, 1e-6); +// +// EXPECT_NEAR(Brms, 1, 1e-2); +} + +TEST(testTurbulentMagneticField, Exceptions) { + TurbulentMagneticField B; + + // Test exception if properties not set + EXPECT_THROW(B.initialize(), std::runtime_error); + + // Test exception for lMin > lMax + B.setTurbulenceProperties(1 * nG, 8.1, 8); + EXPECT_THROW(B.initialize(), std::runtime_error); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/test/testSPHField.cpp b/test/testSPHField.cpp index 7a35f7f8a..f895192bf 100644 --- a/test/testSPHField.cpp +++ b/test/testSPHField.cpp @@ -1,5 +1,5 @@ #include "mpc/magneticField/SPHMagneticField.h" -#include "mpc/magneticField/SPHTurbulentMagneticField.h" +#include "mpc/magneticField/SPHTurbulentMagneticFieldGrid.h" #include "mpc/Units.h" #include "mpc/Common.h" @@ -67,24 +67,29 @@ TEST(testSPHMagneticFieldGrid, simpleTest) { std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; } -TEST(testSPHTurbulentMagneticField, modulatedField) { - // Test for correct rms and mean strength - Vector3d origin(80 * Mpc); +TEST(testSPHTurbulentMagneticField, simpleTest) { + // Tests if a sampled SPH field can be constructed and prints RMS and mean field strength + Vector3d origin(100 * Mpc); size_t n = 64; + double size = 40 * Mpc; + double spacing = size / n; - SPHTurbulentMagneticField B(origin, 40 * Mpc, n); - double spacing = B.getGridSpacing(); - B.setTurbulenceProperties(2 * spacing, 8 * spacing, -11./3); + SPHTurbulentMagneticFieldGrid B(origin, size, n); + B.setTurbulenceProperties(2 * spacing, 8 * spacing, -11. / 3); B.initialize(); - B.modulate(getDataPath("SPH/mhd_z.db").c_str(), 2./3); - B.normalize(1. / B.getRMSFieldStrengthInSphere(Vector3d(120 * Mpc), 105 * Mpc)); + std::cout << "modulating" << std::endl; + B.setModulation(getDataPath("SPH/mhd_z.db").c_str(), Vector3d(99 * Mpc), + 42 * Mpc, 20, 2. / 3., 1.); + + std::cout << "sampling" << std::endl; double brms = 0; Vector3d bmean(0, 0, 0); for (int ix = 0; ix < n; ix++) for (int iy = 0; iy < n; iy++) for (int iz = 0; iz < n; iz++) { - Vector3d b = B.getField(origin + Vector3d(ix, iy, iz) * spacing); + Vector3d b = B.getField( + origin + Vector3d(ix, iy, iz) * spacing); brms += b.getMag2(); bmean += b; } @@ -92,10 +97,8 @@ TEST(testSPHTurbulentMagneticField, modulatedField) { brms = sqrt(brms / n / n / n); bmean /= n * n * n; - EXPECT_NEAR(brms, 1, 1e-7); - EXPECT_NEAR(bmean.x, 0, 5e-3); // compatible with 0 within 0.5% - EXPECT_NEAR(bmean.y, 0, 5e-3); - EXPECT_NEAR(bmean.z, 0, 5e-3); + std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; + std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; } int main(int argc, char **argv) { From 659985de8ce1d52344e9fc63fddb817672159351 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 2 Jul 2012 12:32:24 +0200 Subject: [PATCH 0125/1298] refactore Source --- include/mpc/Source.h | 71 ----------------------------------- src/Source.cpp | 76 -------------------------------------- src/main.cpp | 2 +- test/testMagneticField.cpp | 14 +++++++ test/testModuleList.cpp | 14 +++++-- test/testSource.cpp | 64 +++++++++++++++++++------------- 6 files changed, 63 insertions(+), 178 deletions(-) delete mode 100644 include/mpc/Source.h delete mode 100644 src/Source.cpp diff --git a/include/mpc/Source.h b/include/mpc/Source.h deleted file mode 100644 index b0d173421..000000000 --- a/include/mpc/Source.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef MPC_SOURCE_H -#define MPC_SOURCE_H - -#include "mpc/ParticleState.h" -#include "mpc/Referenced.h" - -#include - -namespace mpc { - -/** - @class Source - @brief Base cosmic ray source - */ -class Source: public Referenced { -public: - virtual ~Source() { - } - - virtual void prepare(ParticleState &state) const = 0; -}; - -/** - @class BasicSource - @brief Cosmic ray source with (broken) power law spectrum - */ -class BasicSource: public Source { -public: - Vector3d position; - double index1, index2, breakpoint, Emin, Emax; - int id; - BasicSource(); - BasicSource(const Vector3d &sposition, int id, double Emin = 5 * EeV, - double Emax = 1000 * EeV, double index1 = -1, double index2 = -1, - double breakpoint = 1); - - virtual void prepare(ParticleState &state) const; -}; - -/** - @class CompositeSource - @brief Cosmic ray source with composition and power law spectrum - */ -class CompositeSource: public Source { -public: - /** source position */ - Vector3d position; - /** differential spectral index, minimum and maximum energy */ - double index, Emin, Emax; - /** source isotopes ids */ - std::vector isotope; - /** relative abundance of source isotopes at equal energies */ - std::vector abundance; - /** cumulative probability of source isotopes */ - std::vector probability; - - CompositeSource(); - CompositeSource(const Vector3d &sposition, double Emin = 5 * EeV, - double Emax = 1000 * EeV, double index = -1); - - /** add an isotope the source */ - void addToComposition(int id, double abundance); - /** calculate the probability for each isotope */ - void normalize(); - /** prepare a random particle */ - virtual void prepare(ParticleState &state) const; -}; - -} // namespace mpc - -#endif /* MPC_SOURCE_H */ diff --git a/src/Source.cpp b/src/Source.cpp deleted file mode 100644 index 1bebcdfa7..000000000 --- a/src/Source.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "mpc/Source.h" -#include "mpc/Random.h" - -#include "HepPID/ParticleIDMethods.hh" - -#include - -namespace mpc { - -BasicSource::BasicSource() : - position(Vector3d(0, 0, 0)), id(0), index1(-1), index2(-1), breakpoint( - 10 * EeV), Emin(5 * EeV), Emax(1000 * EeV) { -} - -BasicSource::BasicSource(const Vector3d &position, int id, double Emin, - double Emax, double index1, double index2, double breakpoint) : - position(position), id(id), index1(index1), index2(index2), breakpoint( - breakpoint), Emin(Emin), Emax(Emax) { -} - -void BasicSource::prepare(ParticleState &state) const { - state.setPosition(position); - state.setId(id); - double E = Random::instance().randBrokenPowerLaw(index1, index2, breakpoint, - Emin, Emax); - state.setEnergy(E); - state.setDirection(Random::instance().randUnitVectorOnSphere()); -} - -CompositeSource::CompositeSource() : - position(Vector3d(0, 0, 0)), Emin(5), Emax(1000), index(-1) { -} - -CompositeSource::CompositeSource(const Vector3d& position, double Emin, - double Emax, double index) : - position(position), Emin(Emin), Emax(Emax), index(index) { -} - -void CompositeSource::addToComposition(int id, double a) { - isotope.push_back(id); - abundance.push_back(a); - probability.push_back(0); - normalize(); -} - -void CompositeSource::normalize() { - double pSum = 0; - double a = 1 + index; - for (int i = 0; i < isotope.size(); i++) { - int Z = HepPID::Z(isotope[i]); - if (std::abs(a) < std::numeric_limits::min()) - pSum += abundance[i] * log(Z * Emax / Emin); - else - pSum += abundance[i] / a * (pow(Z * Emax, a) - pow(Emin, a)); - probability[i] = pSum; - } - for (int i = 0; i < probability.size(); i++) { - probability[i] /= pSum; - } -} - -void CompositeSource::prepare(ParticleState& state) const { - if (isotope.size() == 0) - throw std::runtime_error("mpc::CompositeSource: No source isotope set"); - double r = Random().rand(); - int i = 0; - while ((r > probability[i]) and (i < probability.size())) - i++; - state.setId(isotope[i]); - int Z = HepPID::Z(isotope[i]); - state.setEnergy(Random::instance().randPowerLaw(index, Emin, Z * Emax)); - state.setPosition(position); - state.setDirection(Random::instance().randUnitVectorOnSphere()); -} - -} // namespace mpc diff --git a/src/main.cpp b/src/main.cpp index 9aaa99af3..6c1815de6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,7 +16,7 @@ int main(int argc, char **argv) { ModuleList modules; // propagation -------------------------------------------------------- - TurbulentMagneticFieldGrid *bField = new TurbulentMagneticFieldGrid(Vector3d(0, 0, 0), 64, 1., 2., 8., 1e-12, -11. / 3.); + TurbulentMagneticFieldGrid *bField = new TurbulentMagneticFieldGrid(Vector3d(0, 0, 0), 64., 64, 2., 8., -11. / 3., 1e-12); bField->initialize(); modules.add(new DeflectionCK(bField)); diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index 9f743242b..b9997de60 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -126,6 +126,20 @@ TEST(testMagneticFieldGrid, DumpLoad) { } } +TEST(testMagneticFieldGrid, Speed) { + // Dump and load a field grid + MagneticFieldGrid B(Vector3d(0.), 3, 3); + for (int ix = 0; ix < 3; ix++) + for (int iy = 0; iy < 3; iy++) + for (int iz = 0; iz < 3; iz++) + B.get(ix, iy, iz) = Vector3f(1, 2, 3); + + Vector3d b; + Vector3d pos(1.,1.,1.); + for (int i = 0; i < 1000000; i++) + b = B.getField(pos); +} + TEST(testTurbulentMagneticFieldGrid, Bmean) { // Test for zero mean: = 0 size_t n = 64; diff --git a/test/testModuleList.cpp b/test/testModuleList.cpp index 4c86dfeec..a301b4681 100644 --- a/test/testModuleList.cpp +++ b/test/testModuleList.cpp @@ -30,8 +30,11 @@ TEST(ModuleList, runSource) { ModuleList modules; modules.add(new SimplePropagation()); modules.add(new MaximumTrajectoryLength(1 * Mpc)); - CompositeSource source(Vector3d(0.), 10., 100., -1.); - source.addToComposition(getNucleusId(56, 26), 1); + Source source; + source.addProperty(new SourcePosition(Vector3d(10, 0, 0) * Mpc)); + source.addProperty(new SourceIsotropicEmission()); + source.addProperty(new SourcePowerLawSpectrum(5 * EeV, 100 * EeV, -2)); + source.addProperty(new SourceParticleType(getNucleusId(1, 1))); modules.setShowProgress(true); modules.run(&source, 100, false); } @@ -42,8 +45,11 @@ TEST(ModuleList, runOpenMP) { ModuleList modules; modules.add(new SimplePropagation()); modules.add(new MaximumTrajectoryLength(1 * Mpc)); - CompositeSource source(Vector3d(0.), 10., 100., -1.); - source.addToComposition(getNucleusId(56, 26), 1); + Source source; + source.addProperty(new SourcePosition(Vector3d(10, 0, 0) * Mpc)); + source.addProperty(new SourceIsotropicEmission()); + source.addProperty(new SourcePowerLawSpectrum(5 * EeV, 100 * EeV, -2)); + source.addProperty(new SourceParticleType(getNucleusId(1, 1))); omp_set_num_threads(2); modules.run(&source, 1000, false); } diff --git a/test/testSource.cpp b/test/testSource.cpp index cb18edb26..ce4c41f91 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -6,57 +6,69 @@ namespace mpc { -TEST(testBasicSource, simpleTest) { +TEST(testSourcePosition, simpleTest) { Vector3d position(1, 2, 3); - int id = getNucleusId(4,2); - double Emin = 4 * EeV; - double Emax = 200 * EeV; - double breakpoint = 25 * EeV; - double index1 = -2.7; - double index2 = -4.2; - BasicSource source(position, id, Emin, Emax, index1, index2, breakpoint); + SourcePosition source(position); ParticleState ps; source.prepare(ps); - EXPECT_EQ(4, ps.getMassNumber()); - EXPECT_EQ(2, ps.getChargeNumber()); EXPECT_EQ(position, ps.getPosition()); +} + +TEST(testSourceSphericalVolume, simpleTest) { + Vector3d center(0, 0, 0); + double radius = 110; + SourceSphericalVolume source(center, radius); + ParticleState ps; + source.prepare(ps); + double distance = ps.getPosition().getDistanceTo(center); + EXPECT_GE(radius, distance); +} + +TEST(testSourcePowerLawSpectrum, simpleTest) { + double Emin = 4 * EeV; + double Emax = 200 * EeV; + double index = -2.7; + SourcePowerLawSpectrum spectrum(Emin, Emax, index); + ParticleState ps; + spectrum.prepare(ps); EXPECT_LE(Emin, ps.getEnergy()); EXPECT_GE(Emax, ps.getEnergy()); } -TEST(testCompositeSource, simpleTest) { +TEST(testSourceComposition, simpleTest) { Vector3d position(1, 2, 3); double Emin = 10; double Emax = 100; double index = -2; - CompositeSource source(position, Emin, Emax, index); + SourceComposition source(Emin, Emax, index); source.addToComposition(getNucleusId(6, 3), 1); ParticleState ps; source.prepare(ps); EXPECT_EQ(6, ps.getMassNumber()); EXPECT_EQ(3, ps.getChargeNumber()); - EXPECT_EQ(position, ps.getPosition()); EXPECT_LE(Emin, ps.getEnergy()); EXPECT_GE(Emax, ps.getEnergy()); } -TEST(testCompositeSource, spectralIndexOne) { - Vector3d position(1, 2, 3); - double Emin = 10; - double Emax = 100; - double index = -1; - CompositeSource source(position, Emin, Emax, index); - source.addToComposition(getNucleusId(1, 1), 1); +TEST(testSourceComposition, throwNoIsotope) { + SourceComposition source(1, 10, -1); ParticleState ps; - source.prepare(ps); - EXPECT_LE(Emin, ps.getEnergy()); - EXPECT_GE(Emax, ps.getEnergy()); + EXPECT_THROW(source.prepare(ps), std::runtime_error); } -TEST(testCompositeSource, throwNoIsotope) { - CompositeSource source; +TEST(testSource, simpleTest) { + Source source; + source.addProperty(new SourcePosition(Vector3d(10, 0, 0) * Mpc)); + source.addProperty(new SourceIsotropicEmission()); + source.addProperty(new SourcePowerLawSpectrum(5 * EeV, 100 * EeV, -2)); + source.addProperty(new SourceParticleType(getNucleusId(8, 4))); ParticleState ps; - EXPECT_THROW(source.prepare(ps), std::runtime_error); + source.prepare(ps); + EXPECT_EQ(8, ps.getMassNumber()); + EXPECT_EQ(4, ps.getChargeNumber()); + EXPECT_LE(5 * EeV, ps.getEnergy()); + EXPECT_GE(100 * EeV , ps.getEnergy()); + EXPECT_EQ(Vector3d(10, 0, 0) * Mpc, ps.getPosition()); } int main(int argc, char **argv) { From ad412c662ff78b778d2a41cc8632a34ffd02e383 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 4 Jul 2012 12:55:51 +0200 Subject: [PATCH 0126/1298] update README --- README | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/README b/README index 1ef07934e..2a32a0f72 100644 --- a/README +++ b/README @@ -1,23 +1,30 @@ Installation from source -MPC is built using CMAKE - for more information see www.cmake.org +------------------------ +MPC is configured using CMAKE - for more information see www.cmake.org +1) $cd build +2) $cmake .. (or $ccmake ..) +3) $make +4) $make test (to run all unit tests) +5) Set the data path MPC_DATA_PATH=[path to mpc/data] +6) Retrieve additional data files from https://forge.physik.rwth-aachen.de/projects/mpc/files -1) $cd build/ -2) $cmake .. or $ccmake .. -3) make +Notes for Intel Compiler: + -DCMAKE_SHARED_LINKER_FLAGS="-lifcore" -DCMAKE_Fortran_COMPILER=ifort -Dependencies: + +Dependencies +------------ +Required: +C++ Compiler +Fortran Compiler GNU Scientific Library - for interpolation -Optional dependencies: +Provided: +SOPHIA - for photo-hadronic interactions +googletest - for unit-tests + +Optional: Python and SWIG - to use MPC from python OpenMP - for shared memory parallelization FFTW - for turbulent magnetic field Gadget - for smooth particle large scale structure -GTest - for unit-tests - -To use MPC from python the following environment variables have to be set. -PYTHONPATH=[path to mpc.py] -MPC_DATA_PATH=[path to mpc/data] - -Notes for Intel Compiler: - -DCMAKE_SHARED_LINKER_FLAGS="-lifcore" -DCMAKE_Fortran_COMPILER=ifort From 764a328394ef48fa5532fa247b2813ec042972c4 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 4 Jul 2012 12:56:26 +0200 Subject: [PATCH 0127/1298] add element-wise vector multiplication and division --- include/mpc/Vector3.h | 80 ++++++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 20 deletions(-) diff --git a/include/mpc/Vector3.h b/include/mpc/Vector3.h index 5ebfd71b7..d805d091a 100644 --- a/include/mpc/Vector3.h +++ b/include/mpc/Vector3.h @@ -191,12 +191,20 @@ class Vector3 { return true; } + Vector3 operator +(const Vector3 &v) const { + return Vector3(x + v.x, y + v.y, z + v.z); + } + + Vector3 operator +(const T &f) const { + return Vector3(x + f, y + f, z + f); + } + Vector3 operator -(const Vector3 &v) const { return Vector3(x - v.x, y - v.y, z - v.z); } - Vector3 operator +(const Vector3 &v) const { - return Vector3(x + v.x, y + v.y, z + v.z); + Vector3 operator -(const T &f) const { + return Vector3(x - f, y - f, z - f); } Vector3 operator *(const Vector3 &v) const { @@ -207,25 +215,50 @@ class Vector3 { return Vector3(x * v, y * v, z * v); } + Vector3 operator /(const Vector3 &v) const { + return Vector3(x / v.x, y / v.x, z / v.z); + } + Vector3 operator /(const T &f) const { return Vector3(x / f, y / f, z / f); } - Vector3 &operator /=(const T &f) { - x /= f; - y /= f; - z /= f; + Vector3 operator %(const T &f) const { + return Vector3(x % f, y % f, z % f); + } + + Vector3 &operator -=(const Vector3 &v) { + x -= v.x; + y -= v.y; + z -= v.z; return *this; } - Vector3 operator %(const T &f) const { - return Vector3(x % f, y % f, z % f); + Vector3 &operator -=(const T &f) { + x -= f; + y -= f; + z -= f; + return *this; } - Vector3 &operator %=(const T &f) { - x %= f; - y %= f; - z %= f; + Vector3 &operator +=(const Vector3 &v) { + x += v.x; + y += v.y; + z += v.z; + return *this; + } + + Vector3 &operator +=(const T &f) { + x += f; + y += f; + z += f; + return *this; + } + + Vector3 &operator *=(const Vector3 &v) { + x *= v.x; + y *= v.y; + z *= v.z; return *this; } @@ -236,17 +269,24 @@ class Vector3 { return *this; } - Vector3 &operator +=(const Vector3 &v) { - x += v.x; - y += v.y; - z += v.z; + Vector3 &operator /=(const Vector3 &v) { + x /= v.x; + y /= v.y; + z /= v.z; return *this; } - Vector3 &operator -=(const Vector3 &v) { - x -= v.x; - y -= v.y; - z -= v.z; + Vector3 &operator /=(const T &f) { + x /= f; + y /= f; + z /= f; + return *this; + } + + Vector3 &operator %=(const T &f) { + x %= f; + y %= f; + z %= f; return *this; } From 372dcaf7d20efa4714ef721e6bbe38c455b3c790 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 4 Jul 2012 12:57:22 +0200 Subject: [PATCH 0128/1298] implemend PeriodicBox for periodic boundaries --- include/mpc/module/BreakCondition.h | 16 +++++++++++++++ src/module/BreakCondition.cpp | 13 +++++++++++++ test/testBreakCondition.cpp | 30 +++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/include/mpc/module/BreakCondition.h b/include/mpc/module/BreakCondition.h index 46f35c405..6fe6a28ba 100644 --- a/include/mpc/module/BreakCondition.h +++ b/include/mpc/module/BreakCondition.h @@ -63,6 +63,22 @@ class SmallObserverSphere: public Module { void process(Candidate *candidate) const; }; +/** + @class PeriodicBox + @brief Box with periodic boundaries + + If a particle leaves the periodic box it is placed at the opposite side and its initial (source) position changed accordingly. + Particles can overshoot (be outside of the box during the step) since the step size is not limited by this module. + */ +class PeriodicBox: public Module { +public: + Vector3d origin; + Vector3d size; + + PeriodicBox(Vector3d origin, Vector3d size); + void process(Candidate *candidate) const; +}; + /** @class CubicBoundary @brief Flags a particle when exiting the cube. diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp index 78dae6ae2..f6a4f5494 100644 --- a/src/module/BreakCondition.cpp +++ b/src/module/BreakCondition.cpp @@ -83,6 +83,19 @@ void SmallObserverSphere::updateDescription() { setDescription(s.str()); } +PeriodicBox::PeriodicBox(Vector3d origin, Vector3d size) : + origin(origin), size(size) { +} + +void PeriodicBox::process(Candidate *candidate) const { + Vector3d position = candidate->current.getPosition(); + Vector3d n = ((position - origin) / size).floor(); // integers for translation + if ((n.x != 0) or (n.y != 0) or (n.z != 0)) { + candidate->current.setPosition(position - n * size); + candidate->initial.setPosition(candidate->initial.getPosition() - n * size); + } +} + CubicBoundary::CubicBoundary(Vector3d origin, double size, std::string flag, std::string flagValue) { this->origin = origin; diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index 84fe0d09f..a62ee807c 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -63,6 +63,36 @@ TEST(SmallObserverSphere, limitStep) { EXPECT_DOUBLE_EQ(candidate.getNextStep(), 1); } +TEST(PeriodicBox, high) { + // Tests if the periodical boundaries place the particle back inside the box and translate the initial position accordingly. + PeriodicBox box(Vector3d(2, 2, 2), Vector3d(2, 2, 2)); + Candidate candidate; + candidate.current.setPosition(Vector3d(4.5, 4.3, 4.4)); + candidate.initial.setPosition(Vector3d(3, 3, 3)); + box.process(&candidate); + EXPECT_DOUBLE_EQ(candidate.current.getPosition().x, 2.5); + EXPECT_DOUBLE_EQ(candidate.initial.getPosition().x, 1); + EXPECT_DOUBLE_EQ(candidate.current.getPosition().y, 2.3); + EXPECT_DOUBLE_EQ(candidate.initial.getPosition().y, 1); + EXPECT_DOUBLE_EQ(candidate.current.getPosition().z, 2.4); + EXPECT_DOUBLE_EQ(candidate.initial.getPosition().z, 1); +} + +TEST(PeriodicBox, low) { + // Tests if the periodical boundaries place the particle back inside the box and translate the initial position accordingly. + PeriodicBox box(Vector3d(0., 0., 0.), Vector3d(2., 2., 2.)); + Candidate candidate; + candidate.current.setPosition(Vector3d(-2.5, -0.3, -0.4)); + candidate.initial.setPosition(Vector3d(1, 1, 1)); + box.process(&candidate); + EXPECT_DOUBLE_EQ(candidate.current.getPosition().x, 1.5); + EXPECT_DOUBLE_EQ(candidate.initial.getPosition().x, 5); + EXPECT_DOUBLE_EQ(candidate.current.getPosition().y, 1.7); + EXPECT_DOUBLE_EQ(candidate.initial.getPosition().y, 3); + EXPECT_DOUBLE_EQ(candidate.current.getPosition().z, 1.6); + EXPECT_DOUBLE_EQ(candidate.initial.getPosition().z, 3); +} + TEST(CubicBoundary, inside) { CubicBoundary cube(Vector3d(0, 0, 0), 10); Candidate candidate; From f0bbd2e70075d88ac4762651d67353f85c9b08a2 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 5 Jul 2012 18:08:30 +0200 Subject: [PATCH 0129/1298] commit missing Source.cpp --- src/Source.cpp | 121 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 src/Source.cpp diff --git a/src/Source.cpp b/src/Source.cpp new file mode 100644 index 000000000..3b56c2a29 --- /dev/null +++ b/src/Source.cpp @@ -0,0 +1,121 @@ +#include "mpc/Source.h" +#include "mpc/Random.h" + +#include "HepPID/ParticleIDMethods.hh" +#include + +namespace mpc { + +void Source::addProperty(SourceProperty* property) { + properties.push_back(property); +} + +void Source::prepare(ParticleState& state) const { + for (int i = 0; i < properties.size(); i++) + (*properties[i]).prepare(state); +} + +SourceParticleType::SourceParticleType(int id) : + id(id) { +} + +void SourceParticleType::prepare(ParticleState &particle) const { + particle.setId(id); +} + +SourcePowerLawSpectrum::SourcePowerLawSpectrum(double Emin, double Emax, + double index) : + Emin(Emin), Emax(Emax), index(index) { +} + +void SourcePowerLawSpectrum::prepare(ParticleState &particle) const { + double E = Random().randPowerLaw(index, Emin, Emax); + particle.setEnergy(E); +} + +SourceComposition::SourceComposition(double Emin, double Rmax, double index) : + Emin(Emin), Rmax(Rmax), index(index) { +} + +double SourceComposition::getSpectrumIntegral(int Z) const { + double a = 1 + index; + double Emax = Z * Rmax; + if (std::abs(a) < std::numeric_limits::min()) + return log(Emax / Emin); + else + return (pow(Emax, a) - pow(Emin, a)) / a; +} + +void SourceComposition::addToComposition(int id, double a) { + isotope.push_back(id); + abundance.push_back(a); + probability.push_back(0); + normalize(); +} + +void SourceComposition::normalize() { + double pSum = 0; + for (int i = 0; i < isotope.size(); i++) { + int Z = HepPID::Z(isotope[i]); + pSum += abundance[i] * getSpectrumIntegral(Z); + probability[i] = pSum; + } + for (int i = 0; i < probability.size(); i++) { + probability[i] /= pSum; + } +} + +void SourceComposition::prepare(ParticleState& particle) const { + if (isotope.size() == 0) + throw std::runtime_error("PowerLawComposition: No source isotope set"); + double r = Random().rand(); + int i = 0; + while ((r > probability[i]) and (i < probability.size())) + i++; + int id = isotope[i]; + double E = Random().randPowerLaw(index, Emin, HepPID::Z(id) * Rmax); + particle.setId(id); + particle.setEnergy(E); +} + +SourcePosition::SourcePosition(Vector3d position) : + position(position) { +} + +void SourcePosition::prepare(ParticleState& state) const { + state.setPosition(position); +} + +SourceSphericalVolume::SourceSphericalVolume(Vector3d center, double radius) : + center(center), radius(radius) { +} + +void SourceSphericalVolume::prepare(ParticleState& particle) const { + double r = pow(Random().rand(), 1. / 3.) * radius; + Vector3d pos = Random().randUnitVectorOnSphere() * r; + particle.setPosition(pos); +} + +void SourceIsotropicEmission::prepare(ParticleState& particle) const { + Vector3d dir = Random().randUnitVectorOnSphere(); + particle.setDirection(dir); +} + +SourceDirection::SourceDirection(Vector3d direction) : + direction(direction) { +} + +void SourceDirection::prepare(ParticleState& particle) const { + particle.setDirection(direction); +} + +SourceEmissionCone::SourceEmissionCone(Vector3d direction, double aperture) : + direction(direction), aperture(aperture) { +} + +void SourceEmissionCone::prepare(ParticleState& particle) const { + Vector3d dir = Random().randConeVector(direction, aperture); + particle.setDirection(dir); +} + +} // namespace mpc From 8617c62b05fab0505d7f8eb699d8890d08ca7efe Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 5 Jul 2012 23:18:41 +0200 Subject: [PATCH 0130/1298] add missing files --- include/mpc/Source.h | 131 ++++++++++++++++++ .../SPHTurbulentMagneticFieldGrid.h | 2 +- .../magneticField/TurbulentMagneticField.h | 83 +++++++++++ .../TurbulentMagneticFieldGrid.h | 2 +- src/magneticField/TurbulentMagneticField.cpp | 113 +++++++++++++++ test/python/testSource.py | 10 +- 6 files changed, 336 insertions(+), 5 deletions(-) create mode 100644 include/mpc/Source.h create mode 100644 include/mpc/magneticField/TurbulentMagneticField.h create mode 100644 src/magneticField/TurbulentMagneticField.cpp diff --git a/include/mpc/Source.h b/include/mpc/Source.h new file mode 100644 index 000000000..54adb5713 --- /dev/null +++ b/include/mpc/Source.h @@ -0,0 +1,131 @@ +#ifndef MPC_SOURCE_H +#define MPC_SOURCE_H + +#include "mpc/ParticleState.h" +#include "mpc/Referenced.h" + +#include + +namespace mpc { + +/** + @class SourceProperty + @brief Abstract class for properties of cosmic ray sources + */ +class SourceProperty: public Referenced { +public: + virtual void prepare(ParticleState &state) const = 0; +}; + +/** + @class Source + @brief Abstract class for cosmic ray sources + */ +class Source: public Referenced { +public: + std::vector > properties; + void addProperty(SourceProperty *property); + void prepare(ParticleState &particle) const; +}; + +/** + @class SourceParticleType + @brief Particle type at the source + */ +class SourceParticleType: public SourceProperty { + double id; +public: + SourceParticleType(int id); + void prepare(ParticleState &particle) const; +}; + +/** + @class SourcePowerLawSpectrum + @brief Particle energy following a power law spectrum + */ +class SourcePowerLawSpectrum: public SourceProperty { + double Emin; + double Emax; + double index; +public: + SourcePowerLawSpectrum(double Emin, double Emax, double index); + void prepare(ParticleState &particle) const; +}; + +/** + @class SourceComposition + @brief Nuclei with given abundances and a uniform power law spectrum from Emin to Z * Rmax + */ +class SourceComposition: public SourceProperty { + double Emin; + double Rmax; + double index; + std::vector isotope; /**< isotope id */ + std::vector abundance; /**< relative abundance of source isotopes at equal energies */ + std::vector probability; /**< cumulative probability of source isotopes */ +public: + SourceComposition(double Emin, double Rmax, double index); + double getSpectrumIntegral(int Z = 1) const; + void addToComposition(int id, double abundance); + void normalize(); + void prepare(ParticleState &particle) const; +}; + +/** + @class SourcePosition + @brief Position of a point source + */ +class SourcePosition: public SourceProperty { + Vector3d position; +public: + SourcePosition(Vector3d position); + void prepare(ParticleState &state) const; +}; + +/** + @class SourceSphericalVolume + @brief Uniform random source positions inside a sphere + */ +class SourceSphericalVolume: public SourceProperty { + Vector3d center; + double radius; +public: + SourceSphericalVolume(Vector3d center, double radius); + void prepare(ParticleState &particle) const; +}; + +/** + @class SourceIsotropicEmission + @brief Isotropic emission from a source + */ +class SourceIsotropicEmission: public SourceProperty { +public: + void prepare(ParticleState &particle) const; +}; + +/** + @class SourceDirection + @brief Emission in a discrete direction + */ +class SourceDirection: public SourceProperty { + Vector3d direction; +public: + SourceDirection(Vector3d direction); + void prepare(ParticleState &particle) const; +}; + +/** + @class SourceEmissionCone + @brief Uniform random emission inside a cone + */ +class SourceEmissionCone: public SourceProperty { + Vector3d direction; + double aperture; +public: + SourceEmissionCone(Vector3d direction, double aperture); + void prepare(ParticleState &particle) const; +}; + +}// namespace mpc + +#endif /* MPC_SOURCE_H */ diff --git a/include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h b/include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h index 36cef5fdc..3d825f369 100644 --- a/include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h +++ b/include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h @@ -12,7 +12,7 @@ namespace mpc { /** @class SPHTurbulentMagneticFieldGrid - @brief Random turbulent magnetic field on a cubic grid modulated with an SPH density field. + @brief Turbulent magnetic field on a cubic grid modulated with an SPH density field. */ class SPHTurbulentMagneticFieldGrid: public TurbulentMagneticFieldGrid { public: diff --git a/include/mpc/magneticField/TurbulentMagneticField.h b/include/mpc/magneticField/TurbulentMagneticField.h new file mode 100644 index 000000000..331c125da --- /dev/null +++ b/include/mpc/magneticField/TurbulentMagneticField.h @@ -0,0 +1,83 @@ +#ifndef TURBULENTMAGNETICFIELD2_H_ +#define TURBULENTMAGNETICFIELD2_H_ + +#include "mpc/magneticField/MagneticField.h" +#include "mpc/Random.h" + +#include + +namespace mpc { + +/** + @class TurbulentMagneticField + @brief Turbulent magnetic field defined by a superposition of N random modes + + This class represents random magnetic field with a turbulent spectrum. + The field is calculated at any point with double precision from a number of random modes. + For reference see Giacinti 2011, DOI: 10.1016/j.astropartphys.2011.07.006 + Note that the normalization of the turbulent modes is not yet correct. + Note that this method is slow: O(0.1 ms) on a 2.1 GHz Centrino + */ +class TurbulentMagneticField: public MagneticField { +public: + TurbulentMagneticField() : + nModes(0), spectralIndex(0), Brms(0), lMin(0), lMax(0) { + } + + /** Constructor, also initializes the field. */ + TurbulentMagneticField(double Brms, double lMin, double lMax, + double spectralIndex = -11. / 3., int nModes = 1000); + + /** Calculates the magnetic field at position from the dialed random turbulent modes */ + Vector3d getField(const Vector3d &position) const; + + /** + * Define the properties of the turbulence. + * @param Brms RMS field strength + * @param lMin Minimum wavelength of the turbulence + * @param lMax Maximum wavelength of the turbulence + * @param spectralIndex Power spectral index turbulence + * @param modes Number of modes + */ + void setTurbulenceProperties(double Brms, double lMin, double lMax, + double spectralIndex = -11. / 3., int nModes = 1000); + + /** Create a random initialization of the turbulent field. */ + void initialize(); + + /** Create a random initialization from a given seed. */ + void initialize(int seed); + + double getPowerSpectralIndex() const; + double getMinimumWavelength() const; + double getMaximumWavelength() const; + double getRMSFieldStrength() const; + + /** Return the analytical calculation of the correlation length. */ + double getCorrelationLength() const; + + void updateSimulationVolume(const Vector3d &origin, double size); + +public: + double nModes; /**< Number of modes */ + double spectralIndex; /**< Power spectral index of the turbulence */ + double Brms; /**< RMS Field strength */ + double lMin; /**< Minimum wavelength */ + double lMax; /**< Maximum wavelength */ + + struct Mode { + public: + double amplitude; + double phase; + Vector3d e1; + Vector3d e2; + Vector3d k; + }; + std::vector modes; /**< List of random turbulent modes */ + + Random random; /**< Random number generator instance */ +}; + +} // mpc + +#endif /* TURBULENTMAGNETICFIELD2_H_ */ diff --git a/include/mpc/magneticField/TurbulentMagneticFieldGrid.h b/include/mpc/magneticField/TurbulentMagneticFieldGrid.h index e639535c8..d9fbfa54a 100644 --- a/include/mpc/magneticField/TurbulentMagneticFieldGrid.h +++ b/include/mpc/magneticField/TurbulentMagneticFieldGrid.h @@ -8,7 +8,7 @@ namespace mpc { /** @class TurbulentMagneticFieldGrid - @brief Random turbulent magnetic field on a cubic grid with trilinear interpolation. + @brief Turbulent magnetic field on a cubic grid with trilinear interpolation. This class creates a random magnetic field with a turbulent spectrum. The field is isotropic and homogeneous with a zero mean magnetic field and and divergence. diff --git a/src/magneticField/TurbulentMagneticField.cpp b/src/magneticField/TurbulentMagneticField.cpp new file mode 100644 index 000000000..4a61e493b --- /dev/null +++ b/src/magneticField/TurbulentMagneticField.cpp @@ -0,0 +1,113 @@ +#include "mpc/magneticField/TurbulentMagneticField.h" +#include "mpc/Units.h" + +namespace mpc { + +TurbulentMagneticField::TurbulentMagneticField(double Brms, double lMin, + double lMax, double spectralIndex, int nModes) { + setTurbulenceProperties(Brms, lMin, lMax, spectralIndex, nModes); + initialize(); +} + +Vector3d TurbulentMagneticField::getField(const Vector3d &position) const { + Vector3d b(0.); + double a; + for (int i = 0; i < nModes; i++) { + Mode mode = modes[i]; + a = mode.k.dot(position) + mode.phase; + b += mode.amplitude * (cos(a) * mode.e1 - sin(a) * mode.e2); + } + return b; +} + +void TurbulentMagneticField::setTurbulenceProperties(double Brms, double lMin, + double lMax, double spectralIndex, int nModes) { + this->nModes = nModes; + this->lMin = lMin; + this->lMax = lMax; + this->spectralIndex = spectralIndex; + this->Brms = Brms; +} + +void TurbulentMagneticField::initialize() { + if (lMin >= lMax) + throw std::runtime_error("mpc::TurbulentMagneticField: lMin >= lMax"); + + double lkMin = log10(2 * M_PI / lMax); + double lkMax = log10(2 * M_PI / lMin); + double dlk = (lkMax - lkMin) / (nModes - 1); + double Lc = getCorrelationLength(); + + Mode mode; + Vector3f ek, e1, e2; // orthogonal base + Vector3f n0(1, 1, 1); // arbitrary vector to construct orthogonal base + + double sumGk = 0; + for (int i = 0; i < nModes; i++) { + // construct an orthogonal base ek, e1, e2 + ek = random.randUnitVectorOnSphere(); + if (ek.getAngleTo(n0) < 1e-3) { + // ek parallel to (1,1,1) + e1.setXYZ(-1., 1., 0); + e2.setXYZ(1., 1., -2.); + } else { + // ek not parallel to (1,1,1) + e1 = n0.cross(ek); + e2 = ek.cross(e1); + } + double k = pow(10, lkMin + i * dlk); + mode.k = ek * k; + + // amplitude (this seems to be wrong) + double dk = k * dlk; + double Gk = k * k * dk / (1 + pow(k * Lc, spectralIndex)); + sumGk += Gk; + mode.amplitude = Brms * sqrt(Gk); + + // random orientation of b + double alpha = random.rand(2 * M_PI); + mode.e1 = e1 / e1.getMag() * cos(alpha); + mode.e2 = e2 / e2.getMag() * sin(alpha); + + // random phase + mode.phase = random.rand(2 * M_PI); + modes.push_back(mode); + } + + for (int i = 0; i < nModes; i++) + modes[i].amplitude /= sumGk; +} + +void TurbulentMagneticField::initialize(int seed) { + random.seed(seed); + initialize(); +} + +double TurbulentMagneticField::getPowerSpectralIndex() const { + return spectralIndex; +} + +double TurbulentMagneticField::getMinimumWavelength() const { + return lMin; +} + +double TurbulentMagneticField::getMaximumWavelength() const { + return lMax; +} + +double TurbulentMagneticField::getRMSFieldStrength() const { + return Brms; +} + +double TurbulentMagneticField::getCorrelationLength() const { + double r = lMin / lMax; + double a = -spectralIndex - 2; + return lMax / 2 * (a - 1) / a * (1 - pow(r, a)) / (1 - pow(r, a - 1)); +} + +void TurbulentMagneticField::updateSimulationVolume(const Vector3d &origin, + double size) { + return; +} + +} // namespace mpc diff --git a/test/python/testSource.py b/test/python/testSource.py index 5da07410c..210b6689e 100644 --- a/test/python/testSource.py +++ b/test/python/testSource.py @@ -1,10 +1,14 @@ from mpc import * from pylab import * -source = CompositeSource(Vector3d(0.), 10, 100, -1) + +Emin = 10 * EeV +Emax = 100 * EeV +index = -1 +composition = SourceComposition(Emin, Emax, index) def add(A, Z, w): - source.addToComposition(getNucleusId(A, Z), w * A) + composition.addToComposition(getNucleusId(A, Z), w * A) # DuVernois add(1, 1, 92000) @@ -29,7 +33,7 @@ def add(A, Z, w): Etot = zeros(N) E1, E2, E3, E4 = [], [], [], [] for i in range(N): - source.prepare(state) + composition.prepare(state) lE = log10(state.getEnergy()) + 18 Z = state.getChargeNumber() Etot[i] = lE From c4ae0011a13985e53b476b1ccc4fbd0966fd2cdb Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 6 Jul 2012 12:54:21 +0200 Subject: [PATCH 0131/1298] add Vector3 tests --- .../TurbulentMagneticFieldGrid.h | 6 +- .../mpc/magneticField/UniformMagneticField.h | 1 - test/testCore.cpp | 82 ++++++++++++++++++- 3 files changed, 81 insertions(+), 8 deletions(-) diff --git a/include/mpc/magneticField/TurbulentMagneticFieldGrid.h b/include/mpc/magneticField/TurbulentMagneticFieldGrid.h index d9fbfa54a..52aceb931 100644 --- a/include/mpc/magneticField/TurbulentMagneticFieldGrid.h +++ b/include/mpc/magneticField/TurbulentMagneticFieldGrid.h @@ -1,5 +1,5 @@ -#ifndef MPC_TURBULENTMAGNETICFIELD_H_ -#define MPC_TURBULENTMAGNETICFIELD_H_ +#ifndef MPC_TURBULENTMAGNETICFIELDGRID_H_ +#define MPC_TURBULENTMAGNETICFIELDGRID_H_ #include "mpc/magneticField/MagneticFieldGrid.h" #include "mpc/Random.h" @@ -66,4 +66,4 @@ class TurbulentMagneticFieldGrid: public MagneticFieldGrid { } // namespace mpc -#endif /* MPC_TURBULENTMAGNETICFIELD_H_ */ +#endif /* MPC_TURBULENTMAGNETICFIELDGRID_H_ */ diff --git a/include/mpc/magneticField/UniformMagneticField.h b/include/mpc/magneticField/UniformMagneticField.h index 359bfb78c..0111151e3 100644 --- a/include/mpc/magneticField/UniformMagneticField.h +++ b/include/mpc/magneticField/UniformMagneticField.h @@ -2,7 +2,6 @@ #define MPC_UNIFORMAGNETICFIELD_H_ #include "mpc/magneticField/MagneticField.h" -#include "mpc/Vector3.h" namespace mpc { diff --git a/test/testCore.cpp b/test/testCore.cpp index bb5363ac4..da19c310f 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -74,7 +74,8 @@ TEST(ParticleState, lorentzFactor) { ParticleState particle; particle.setId(getNucleusId(1, 1)); particle.setEnergy(1e12 * eV); - EXPECT_DOUBLE_EQ(particle.getLorentzFactor(), 1e12 * eV / mass_proton / c_squared); + EXPECT_DOUBLE_EQ(particle.getLorentzFactor(), + 1e12 * eV / mass_proton / c_squared); } TEST(Candidate, currentStep) { @@ -119,7 +120,7 @@ TEST(common, digit) { TEST(common, interpolate) { double xD[100]; double yD[100]; - for (int i=0; i<100; i++) { + for (int i = 0; i < 100; i++) { xD[i] = 1 + i * 0.02; yD[i] = pow(xD[i], 2); } @@ -131,7 +132,7 @@ TEST(common, interpolateVector) { std::vector xD, yD; xD.resize(100); yD.resize(100); - for (int i=0; i<100; i++) { + for (int i = 0; i < 100; i++) { xD[i] = 1 + i * 0.02; yD[i] = pow(xD[i], 2); } @@ -141,13 +142,86 @@ TEST(common, interpolateVector) { TEST(common, interpolateEquidistant) { double yD[100]; - for (int i=0; i<100; i++) { + for (int i = 0; i < 100; i++) { yD[i] = pow(1 + i * 0.02, 2); } double yInt = interpolateEquidistant(1.5001, 1, 0.02, yD); EXPECT_NEAR(pow(1.5001, 2), yInt, 1e-4); } +TEST(Vector3, division) { + Vector3d v(10); + v /= 10; + EXPECT_DOUBLE_EQ(v.x, 1); + EXPECT_DOUBLE_EQ(v.y, 1); + EXPECT_DOUBLE_EQ(v.z, 1); + v = Vector3d(10) / Vector3d(2); // element-wise division + EXPECT_DOUBLE_EQ(v.x, 5); + EXPECT_DOUBLE_EQ(v.y, 5); + EXPECT_DOUBLE_EQ(v.z, 5); +} + +TEST(Vector3, mod) { + Vector3d v(10.1, 10.2, 10.3); + v %= 10.2; + EXPECT_NEAR(v.x, 10.1, 1e-10); // mod doesn't preserve double precision + EXPECT_NEAR(v.y, 0, 1e-10); + EXPECT_NEAR(v.z, 0.1, 1e-10); +} + +TEST(Vector3, dot) { + double a = Vector3d(1, 0, 0).dot(Vector3d(0, 1, 0)); + EXPECT_DOUBLE_EQ(a, 0); + double b = Vector3d(-1, 10, 2).dot(Vector3d(5, 1, -3)); + EXPECT_DOUBLE_EQ(b, -1); +} + +TEST(Vector3, cross) { + Vector3d v = Vector3d(1, 0, 0).cross(Vector3d(0, 1, 0)); + EXPECT_DOUBLE_EQ(v.x, 0); + EXPECT_DOUBLE_EQ(v.y, 0); + EXPECT_DOUBLE_EQ(v.z, 1); +} + +TEST(Vector3, angle) { + double a = Vector3d(1, 1, 0).getAngleTo(Vector3d(1, 0, 0)); + EXPECT_DOUBLE_EQ(a, 45 * M_PI / 180); + double b = Vector3d(0, 0, 1).getAngleTo(Vector3d(0, 0, 1)); + EXPECT_DOUBLE_EQ(b, 0); +} + +TEST(Vector3, magnitude) { + Vector3d v = Vector3d(1, 2, -2); + EXPECT_DOUBLE_EQ(v.getMag(), 3); + EXPECT_DOUBLE_EQ(v.getMag2(), 9); +} + +TEST(Vector3, distance) { + double a = Vector3d(10, 0, 10).getDistanceTo(Vector3d(10, 0, 0)); + EXPECT_DOUBLE_EQ(a, 10); +} + +TEST(Vector3, rotation) { + Vector3d v(10, 0, 0); + v.rotate(Vector3d(0, 2, 0), M_PI); + EXPECT_NEAR(v.x, -10, 1e-9); + // rotation doesn't preserve double precision + EXPECT_NEAR(v.y, 0, 1e-9); + EXPECT_NEAR(v.z, 0, 1e-9); + + v = Vector3d(10, 0, 0); + v.rotate(Vector3d(1, 0, 0), M_PI); // no rotation + EXPECT_NEAR(v.x, 10, 1e-9); + EXPECT_NEAR(v.y, 0, 1e-9); + EXPECT_NEAR(v.z, 0, 1e-9); + + v = Vector3d(5, 2, 7); + v.rotate(Vector3d(1, 8, -4), 2 * M_PI); // full rotation + EXPECT_NEAR(v.x, 5, 1e-9); + EXPECT_NEAR(v.y, 2, 1e-9); + EXPECT_NEAR(v.z, 7, 1e-9); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); From e48fe575ffbc38c2d24b177239c37504f0fb81e3 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 9 Jul 2012 09:04:55 +0200 Subject: [PATCH 0132/1298] fix TurbulentMagneticField --- .../magneticField/TurbulentMagneticField.h | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/include/mpc/magneticField/TurbulentMagneticField.h b/include/mpc/magneticField/TurbulentMagneticField.h index 331c125da..dba0e2bca 100644 --- a/include/mpc/magneticField/TurbulentMagneticField.h +++ b/include/mpc/magneticField/TurbulentMagneticField.h @@ -1,5 +1,5 @@ -#ifndef TURBULENTMAGNETICFIELD2_H_ -#define TURBULENTMAGNETICFIELD2_H_ +#ifndef TURBULENTMAGNETICFIELD_H_ +#define TURBULENTMAGNETICFIELD_H_ #include "mpc/magneticField/MagneticField.h" #include "mpc/Random.h" @@ -58,15 +58,8 @@ class TurbulentMagneticField: public MagneticField { void updateSimulationVolume(const Vector3d &origin, double size); -public: - double nModes; /**< Number of modes */ - double spectralIndex; /**< Power spectral index of the turbulence */ - double Brms; /**< RMS Field strength */ - double lMin; /**< Minimum wavelength */ - double lMax; /**< Maximum wavelength */ - +private: struct Mode { - public: double amplitude; double phase; Vector3d e1; @@ -74,10 +67,14 @@ class TurbulentMagneticField: public MagneticField { Vector3d k; }; std::vector modes; /**< List of random turbulent modes */ - + int nModes; /**< Number of modes */ + double spectralIndex; /**< Power spectral index of the turbulence */ + double Brms; /**< RMS Field strength */ + double lMin; /**< Minimum wavelength */ + double lMax; /**< Maximum wavelength */ Random random; /**< Random number generator instance */ }; } // mpc -#endif /* TURBULENTMAGNETICFIELD2_H_ */ +#endif /* TURBULENTMAGNETICFIELD_H_ */ From e8038209f8e59630ac0149ac8b31b1fb166c7c7f Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 10 Jul 2012 11:52:42 +0200 Subject: [PATCH 0133/1298] modify source composition convention to take the abundance at equal energies per nucleon --- README | 1 + include/mpc/Source.h | 3 +- src/Source.cpp | 10 ++++- test/python/testSource.py | 91 +++++++++++++++++---------------------- test/testSource.cpp | 2 +- 5 files changed, 51 insertions(+), 56 deletions(-) diff --git a/README b/README index 2a32a0f72..3b0aa2db0 100644 --- a/README +++ b/README @@ -7,6 +7,7 @@ MPC is configured using CMAKE - for more information see www.cmake.org 4) $make test (to run all unit tests) 5) Set the data path MPC_DATA_PATH=[path to mpc/data] 6) Retrieve additional data files from https://forge.physik.rwth-aachen.de/projects/mpc/files + The photo-disintegration tables PDtable_XXX.txt have to be copied to mpc/data/PhotoDisintegration Notes for Intel Compiler: -DCMAKE_SHARED_LINKER_FLAGS="-lifcore" -DCMAKE_Fortran_COMPILER=ifort diff --git a/include/mpc/Source.h b/include/mpc/Source.h index 54adb5713..f3b49a726 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -66,7 +66,8 @@ class SourceComposition: public SourceProperty { public: SourceComposition(double Emin, double Rmax, double index); double getSpectrumIntegral(int Z = 1) const; - void addToComposition(int id, double abundance); + void add(int id, double abundance); + void add(int A, int Z, double abundance); void normalize(); void prepare(ParticleState &particle) const; }; diff --git a/src/Source.cpp b/src/Source.cpp index 3b56c2a29..c0a2987a3 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -46,13 +46,19 @@ double SourceComposition::getSpectrumIntegral(int Z) const { return (pow(Emax, a) - pow(Emin, a)) / a; } -void SourceComposition::addToComposition(int id, double a) { +void SourceComposition::add(int id, double a) { isotope.push_back(id); - abundance.push_back(a); + int A = getMassNumberFromNucleusId(id); + double weightedAbundance = a * pow(A, -index - 1); + abundance.push_back(weightedAbundance); probability.push_back(0); normalize(); } +void SourceComposition::add(int A, int Z, double a) { + add(getNucleusId(A, Z), a); +} + void SourceComposition::normalize() { double pSum = 0; for (int i = 0; i < isotope.size(); i++) { diff --git a/test/python/testSource.py b/test/python/testSource.py index 210b6689e..3a606a6e5 100644 --- a/test/python/testSource.py +++ b/test/python/testSource.py @@ -1,65 +1,52 @@ from mpc import * from pylab import * +# Simulates the integrated relative abundance from a source that accelerates +# particles up to a maximum rigidity. +# min. energy = 10 EeV +# max. rigidity = 100 EeV / Z -> max. energy = Z * 100 EeV +# composition = p, He, C, O, Si, Fe with relative abundances from Allard 2006, DOI: 10.1088/1475-7516/2006/09/005 -Emin = 10 * EeV -Emax = 100 * EeV -index = -1 -composition = SourceComposition(Emin, Emax, index) +nS = 5 # number of spectral indices between 2 and 3 +nP = 5000 # number of particles per spectral index -def add(A, Z, w): - composition.addToComposition(getNucleusId(A, Z), w * A) +d = {1:zeros(nS), 2:zeros(nS), 6:zeros(nS), 8:zeros(nS), 14:zeros(nS), 26:zeros(nS)} -# DuVernois -add(1, 1, 92000) -add(4, 2, 13000) -add(12, 6, 447.4) -add(14, 7, 34.2) -add(16, 8, 526.3) -add(20, 10, 58.0) -add(23, 11, 3.2) -add(24, 12, 108.0) -add(27, 13, 7.8) -add(28, 14, 100) -add(32, 16, 13.1) -add(40, 18, 2.2) -add(40, 20, 6.5) -add(52, 24, 1.5) -add(55, 25, 1.1) -add(56, 26, 97) +print 'simulating for spectral index' +for i in range(nS): + beta = 2 + i/float(nS - 1) + print beta -state = ParticleState() -N = 10000 -Etot = zeros(N) -E1, E2, E3, E4 = [], [], [], [] -for i in range(N): - composition.prepare(state) - lE = log10(state.getEnergy()) + 18 - Z = state.getChargeNumber() - Etot[i] = lE - if Z == 1: - E1.append(lE) - elif Z == 2: - E2.append(lE) - elif Z <= 8: - E3.append(lE) - else: - E4.append(lE) + composition = SourceComposition(10, 100, -beta) + composition.add(1, 1, 92000) + composition.add(4, 2, 13000) + composition.add(12, 6, 447.4) + composition.add(16, 8, 526.3) + composition.add(28, 14, 100) + composition.add(56, 26, 97) -E1 = array(E1) -E2 = array(E2) -E3 = array(E3) -E4 = array(E4) + state = ParticleState() + + for j in range(nP): + composition.prepare(state) + z = state.getChargeNumber() + d[z][i] += 1 + + norm = float(d[1][i]) + for z in d.keys(): + d[z][i] /= norm figure() -hist(E1, weights=ones(len(E1))*1./N, bins=20, range=[19, 21.5], histtype='step', lw=2, label='H') -hist(E2, weights=ones(len(E2))*1./N, bins=20, range=[19, 21.5], histtype='step', lw=2, label='He') -hist(E3, weights=ones(len(E3))*1./N, bins=20, range=[19, 21.5], histtype='step', lw=2, label='$Z \leq 8$') -hist(E4, weights=ones(len(E4))*1./N, bins=20, range=[19, 21.5], histtype='step', lw=2, label='$Z > 8$') -ylim(1e-4, 1) -xlabel('$\log_{10}(E/\mathrm{eV})$') -ylabel('Probability') +beta = linspace(2, 3, nS) +elements = {1:'H', 2:'He', 6:'C', 8:'O', 14:'Si', 26:'Fe'} +for z in d.keys(): + plot(beta, d[z], label=elements[z]) + +legend(loc = 'lower right') +xlabel(r'Source Spectral Index $\beta$') +ylabel('Relative Integrated Abundance') +xlim(2, 3) semilogy() grid() -legend() savefig('Source.png') +show() diff --git a/test/testSource.cpp b/test/testSource.cpp index ce4c41f91..0a3a87d69 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -41,7 +41,7 @@ TEST(testSourceComposition, simpleTest) { double Emax = 100; double index = -2; SourceComposition source(Emin, Emax, index); - source.addToComposition(getNucleusId(6, 3), 1); + source.add(getNucleusId(6, 3), 1); ParticleState ps; source.prepare(ps); EXPECT_EQ(6, ps.getMassNumber()); From 39cbf3b49e7f60d77ac84be939f3d5918570e11a Mon Sep 17 00:00:00 2001 From: geromueller Date: Tue, 10 Jul 2012 12:47:04 +0200 Subject: [PATCH 0134/1298] initial xml execution code --- CMakeLists.txt | 6 + include/mpc/ModuleList.h | 7 +- include/mpc/Referenced.h | 2 +- include/mpc/XmlExecute.h | 40 + include/mpc/module/DeflectionCK.h | 2 +- libs/pugixml/CMakeLists.txt | 9 + libs/pugixml/pugiconfig.hpp | 69 + libs/pugixml/pugixml.cpp | 10250 ++++++++++++++++++++++++++++ libs/pugixml/pugixml.hpp | 1265 ++++ src/ModuleList.cpp | 2 +- src/XmlExecute.cpp | 197 + src/main.cpp | 62 +- src/module/DeflectionCK.cpp | 9 +- src/module/Output.cpp | 8 +- 14 files changed, 11873 insertions(+), 55 deletions(-) create mode 100644 include/mpc/XmlExecute.h create mode 100644 libs/pugixml/CMakeLists.txt create mode 100644 libs/pugixml/pugiconfig.hpp create mode 100644 libs/pugixml/pugixml.cpp create mode 100644 libs/pugixml/pugixml.hpp create mode 100644 src/XmlExecute.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index cd5f05871..11374a1b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,11 @@ add_subdirectory(libs/kiss) list(APPEND MPC_EXTRA_LIBRARIES kiss) list(APPEND MPC_EXTRA_INCLUDES libs/kiss/include) +# pugixml (provided) +add_subdirectory(libs/pugixml) +list(APPEND MPC_EXTRA_LIBRARIES pugixml) +list(APPEND MPC_EXTRA_INCLUDES libs/pugixml) + # HepID (provided) add_subdirectory(libs/HepPID) list(APPEND MPC_EXTRA_LIBRARIES HepPID) @@ -86,6 +91,7 @@ add_library(mpc SHARED src/Source.cpp src/Common.cpp src/Nucleus.cpp + src/XmlExecute.cpp src/module/BreakCondition.cpp src/module/SimplePropagation.cpp src/module/DeflectionCK.cpp diff --git a/include/mpc/ModuleList.h b/include/mpc/ModuleList.h index fad119c5a..1e7e1928f 100644 --- a/include/mpc/ModuleList.h +++ b/include/mpc/ModuleList.h @@ -1,14 +1,15 @@ #ifndef MPC_MODULE_LIST_H_ #define MPC_MODULE_LIST_H_ -#include - #include "mpc/Candidate.h" #include "mpc/Module.h" #include "mpc/Source.h" #include "mpc/AssocVector.h" #include "mpc/Referenced.h" +#include +#include + namespace mpc { /** @@ -24,7 +25,7 @@ class ModuleList: public Referenced { virtual ~ModuleList(); void setShowProgress(bool show); - void add(Module *module); + void add(ref_ptr ); virtual void process(Candidate *candidate); void run(Candidate *candidate, bool recursive = true); void run(candidate_vector_t &candidates, bool recursive = true); diff --git a/include/mpc/Referenced.h b/include/mpc/Referenced.h index cfbfdb872..d2579561a 100644 --- a/include/mpc/Referenced.h +++ b/include/mpc/Referenced.h @@ -100,7 +100,7 @@ class ref_ptr { template ref_ptr(const ref_ptr& rp) : _ptr(rp._ptr) { if (_ptr) - _ptr->ref(); + _ptr->addReference(); } ~ref_ptr() { diff --git a/include/mpc/XmlExecute.h b/include/mpc/XmlExecute.h new file mode 100644 index 000000000..676d9a2d3 --- /dev/null +++ b/include/mpc/XmlExecute.h @@ -0,0 +1,40 @@ +#ifndef MPC_XML_EXECUTE_H +#define MPC_XML_EXECUTE_H + +#include "mpc/ModuleList.h" +#include "mpc/Source.h" +#include "mpc/magneticField/MagneticField.h" + +#include + +namespace pugi { +class xml_node; +} + +namespace mpc { + +class XmlExecute { + ModuleList modules; + ref_ptr magnetic_field; + std::vector sources; + + void loadCashKarp(pugi::xml_node &); + void loadLssGrid(pugi::xml_node &); + void loadSophia(pugi::xml_node &); + void loadSpheresAroundObserver(pugi::xml_node &); + void loadDiscreteSources(pugi::xml_node &); + void loadFullTrajectoryOutput(pugi::xml_node &); + + size_t trajectories; + double minEnergyEeV; + double maxTimeMpc; + size_t randomSeed; + +public: + bool load(const std::string &filename); + void run(); +}; + +} // namespace mpc + +#endif /* MPC_XML_EXECUTE_H */ diff --git a/include/mpc/module/DeflectionCK.h b/include/mpc/module/DeflectionCK.h index 6994b8be6..03f733931 100644 --- a/include/mpc/module/DeflectionCK.h +++ b/include/mpc/module/DeflectionCK.h @@ -22,7 +22,7 @@ class DeflectionCK: public SimulationVolumeDependentModule { ExplicitRungeKutta erk; double tolerance, minimumStep; - DeflectionCK(MagneticField *field, double tolerance = 1e-4, double minimumStep = 0.1 * kpc); + DeflectionCK(ref_ptr field, double tolerance = 1e-4, double minimumStep = 0.1 * kpc); std::string getDescription() const; void process(Candidate *candidate) const; void updateSimulationVolume(const Vector3d &origin, double size); diff --git a/libs/pugixml/CMakeLists.txt b/libs/pugixml/CMakeLists.txt new file mode 100644 index 000000000..9be323927 --- /dev/null +++ b/libs/pugixml/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 2.6) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +add_library(pugixml + pugixml +) + +SET_TARGET_PROPERTIES( pugixml PROPERTIES COMPILE_FLAGS -fPIC) diff --git a/libs/pugixml/pugiconfig.hpp b/libs/pugixml/pugiconfig.hpp new file mode 100644 index 000000000..4c787125a --- /dev/null +++ b/libs/pugixml/pugiconfig.hpp @@ -0,0 +1,69 @@ +/** + * pugixml parser - version 1.2 + * -------------------------------------------------------- + * Copyright (C) 2006-2012, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Report bugs and download new versions at http://pugixml.org/ + * + * This library is distributed under the MIT License. See notice at the end + * of this file. + * + * This work is based on the pugxml parser, which is: + * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) + */ + +#ifndef HEADER_PUGICONFIG_HPP +#define HEADER_PUGICONFIG_HPP + +// Uncomment this to enable wchar_t mode +// #define PUGIXML_WCHAR_MODE + +// Uncomment this to disable XPath +// #define PUGIXML_NO_XPATH + +// Uncomment this to disable STL +// #define PUGIXML_NO_STL + +// Uncomment this to disable exceptions +// #define PUGIXML_NO_EXCEPTIONS + +// Set this to control attributes for public classes/functions, i.e.: +// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL +// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL +// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall +// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead + +// Uncomment this to switch to header-only version +// #define PUGIXML_HEADER_ONLY +// #include "pugixml.cpp" + +// Tune these constants to adjust memory-related behavior +// #define PUGIXML_MEMORY_PAGE_SIZE 32768 +// #define PUGIXML_MEMORY_OUTPUT_STACK 10240 +// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096 + +#endif + +/** + * Copyright (c) 2006-2012 Arseny Kapoulkine + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ diff --git a/libs/pugixml/pugixml.cpp b/libs/pugixml/pugixml.cpp new file mode 100644 index 000000000..642d92d38 --- /dev/null +++ b/libs/pugixml/pugixml.cpp @@ -0,0 +1,10250 @@ +/** + * pugixml parser - version 1.2 + * -------------------------------------------------------- + * Copyright (C) 2006-2012, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Report bugs and download new versions at http://pugixml.org/ + * + * This library is distributed under the MIT License. See notice at the end + * of this file. + * + * This work is based on the pugxml parser, which is: + * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) + */ + +#ifndef SOURCE_PUGIXML_CPP +#define SOURCE_PUGIXML_CPP + +#include "pugixml.hpp" + +#include +#include +#include +#include +#include + +#ifndef PUGIXML_NO_XPATH +# include +# include +# ifdef PUGIXML_NO_EXCEPTIONS +# include +# endif +#endif + +#ifndef PUGIXML_NO_STL +# include +# include +# include +#endif + +// For placement new +#include + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4127) // conditional expression is constant +# pragma warning(disable: 4324) // structure was padded due to __declspec(align()) +# pragma warning(disable: 4611) // interaction between '_setjmp' and C++ object destruction is non-portable +# pragma warning(disable: 4702) // unreachable code +# pragma warning(disable: 4996) // this function or variable may be unsafe +# pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged +#endif + +#ifdef __INTEL_COMPILER +# pragma warning(disable: 177) // function was declared but never referenced +# pragma warning(disable: 279) // controlling expression is constant +# pragma warning(disable: 1478 1786) // function was declared "deprecated" +# pragma warning(disable: 1684) // conversion from pointer to same-sized integral type +#endif + +#if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY) +# pragma warn -8080 // symbol is declared but never used; disabling this inside push/pop bracket does not make the warning go away +#endif + +#ifdef __BORLANDC__ +# pragma option push +# pragma warn -8008 // condition is always false +# pragma warn -8066 // unreachable code +#endif + +#ifdef __SNC__ +// Using diag_push/diag_pop does not disable the warnings inside templates due to a compiler bug +# pragma diag_suppress=178 // function was declared but never referenced +# pragma diag_suppress=237 // controlling expression is constant +#endif + +// Inlining controls +#if defined(_MSC_VER) && _MSC_VER >= 1300 +# define PUGI__NO_INLINE __declspec(noinline) +#elif defined(__GNUC__) +# define PUGI__NO_INLINE __attribute__((noinline)) +#else +# define PUGI__NO_INLINE +#endif + +// Simple static assertion +#define PUGI__STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; } + +// Digital Mars C++ bug workaround for passing char loaded from memory via stack +#ifdef __DMC__ +# define PUGI__DMC_VOLATILE volatile +#else +# define PUGI__DMC_VOLATILE +#endif + +// Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy because some compilers don't have it at all) +#if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST) +using std::memcpy; +using std::memmove; +#endif + +// In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features +#if defined(_MSC_VER) && !defined(__S3E__) +# define PUGI__MSVC_CRT_VERSION _MSC_VER +#endif + +#ifdef PUGIXML_HEADER_ONLY +# define PUGI__NS_BEGIN namespace pugi { namespace impl { +# define PUGI__NS_END } } +# define PUGI__FN inline +# define PUGI__FN_NO_INLINE inline +#else +# if defined(_MSC_VER) && _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces +# define PUGI__NS_BEGIN namespace pugi { namespace impl { +# define PUGI__NS_END } } +# else +# define PUGI__NS_BEGIN namespace pugi { namespace impl { namespace { +# define PUGI__NS_END } } } +# endif +# define PUGI__FN +# define PUGI__FN_NO_INLINE PUGI__NO_INLINE +#endif + +// uintptr_t +#if !defined(_MSC_VER) || _MSC_VER >= 1600 +# include +#else +# ifndef _UINTPTR_T_DEFINED +// No native uintptr_t in MSVC6 and in some WinCE versions +typedef size_t uintptr_t; +#define _UINTPTR_T_DEFINED +# endif +PUGI__NS_BEGIN + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +PUGI__NS_END +#endif + +// Memory allocation +PUGI__NS_BEGIN + PUGI__FN void* default_allocate(size_t size) + { + return malloc(size); + } + + PUGI__FN void default_deallocate(void* ptr) + { + free(ptr); + } + + template + struct xml_memory_management_function_storage + { + static allocation_function allocate; + static deallocation_function deallocate; + }; + + template allocation_function xml_memory_management_function_storage::allocate = default_allocate; + template deallocation_function xml_memory_management_function_storage::deallocate = default_deallocate; + + typedef xml_memory_management_function_storage xml_memory; +PUGI__NS_END + +// String utilities +PUGI__NS_BEGIN + // Get string length + PUGI__FN size_t strlength(const char_t* s) + { + assert(s); + + #ifdef PUGIXML_WCHAR_MODE + return wcslen(s); + #else + return strlen(s); + #endif + } + + // Compare two strings + PUGI__FN bool strequal(const char_t* src, const char_t* dst) + { + assert(src && dst); + + #ifdef PUGIXML_WCHAR_MODE + return wcscmp(src, dst) == 0; + #else + return strcmp(src, dst) == 0; + #endif + } + + // Compare lhs with [rhs_begin, rhs_end) + PUGI__FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count) + { + for (size_t i = 0; i < count; ++i) + if (lhs[i] != rhs[i]) + return false; + + return lhs[count] == 0; + } + +#ifdef PUGIXML_WCHAR_MODE + // Convert string to wide string, assuming all symbols are ASCII + PUGI__FN void widen_ascii(wchar_t* dest, const char* source) + { + for (const char* i = source; *i; ++i) *dest++ = *i; + *dest = 0; + } +#endif +PUGI__NS_END + +#if !defined(PUGIXML_NO_STL) || !defined(PUGIXML_NO_XPATH) +// auto_ptr-like buffer holder for exception recovery +PUGI__NS_BEGIN + struct buffer_holder + { + void* data; + void (*deleter)(void*); + + buffer_holder(void* data_, void (*deleter_)(void*)): data(data_), deleter(deleter_) + { + } + + ~buffer_holder() + { + if (data) deleter(data); + } + + void* release() + { + void* result = data; + data = 0; + return result; + } + }; +PUGI__NS_END +#endif + +PUGI__NS_BEGIN + static const size_t xml_memory_page_size = + #ifdef PUGIXML_MEMORY_PAGE_SIZE + PUGIXML_MEMORY_PAGE_SIZE + #else + 32768 + #endif + ; + + static const uintptr_t xml_memory_page_alignment = 32; + static const uintptr_t xml_memory_page_pointer_mask = ~(xml_memory_page_alignment - 1); + static const uintptr_t xml_memory_page_name_allocated_mask = 16; + static const uintptr_t xml_memory_page_value_allocated_mask = 8; + static const uintptr_t xml_memory_page_type_mask = 7; + + struct xml_allocator; + + struct xml_memory_page + { + static xml_memory_page* construct(void* memory) + { + if (!memory) return 0; //$ redundant, left for performance + + xml_memory_page* result = static_cast(memory); + + result->allocator = 0; + result->memory = 0; + result->prev = 0; + result->next = 0; + result->busy_size = 0; + result->freed_size = 0; + + return result; + } + + xml_allocator* allocator; + + void* memory; + + xml_memory_page* prev; + xml_memory_page* next; + + size_t busy_size; + size_t freed_size; + + char data[1]; + }; + + struct xml_memory_string_header + { + uint16_t page_offset; // offset from page->data + uint16_t full_size; // 0 if string occupies whole page + }; + + struct xml_allocator + { + xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size) + { + } + + xml_memory_page* allocate_page(size_t data_size) + { + size_t size = offsetof(xml_memory_page, data) + data_size; + + // allocate block with some alignment, leaving memory for worst-case padding + void* memory = xml_memory::allocate(size + xml_memory_page_alignment); + if (!memory) return 0; + + // align upwards to page boundary + void* page_memory = reinterpret_cast((reinterpret_cast(memory) + (xml_memory_page_alignment - 1)) & ~(xml_memory_page_alignment - 1)); + + // prepare page structure + xml_memory_page* page = xml_memory_page::construct(page_memory); + + page->memory = memory; + page->allocator = _root->allocator; + + return page; + } + + static void deallocate_page(xml_memory_page* page) + { + xml_memory::deallocate(page->memory); + } + + void* allocate_memory_oob(size_t size, xml_memory_page*& out_page); + + void* allocate_memory(size_t size, xml_memory_page*& out_page) + { + if (_busy_size + size > xml_memory_page_size) return allocate_memory_oob(size, out_page); + + void* buf = _root->data + _busy_size; + + _busy_size += size; + + out_page = _root; + + return buf; + } + + void deallocate_memory(void* ptr, size_t size, xml_memory_page* page) + { + if (page == _root) page->busy_size = _busy_size; + + assert(ptr >= page->data && ptr < page->data + page->busy_size); + (void)!ptr; + + page->freed_size += size; + assert(page->freed_size <= page->busy_size); + + if (page->freed_size == page->busy_size) + { + if (page->next == 0) + { + assert(_root == page); + + // top page freed, just reset sizes + page->busy_size = page->freed_size = 0; + _busy_size = 0; + } + else + { + assert(_root != page); + assert(page->prev); + + // remove from the list + page->prev->next = page->next; + page->next->prev = page->prev; + + // deallocate + deallocate_page(page); + } + } + } + + char_t* allocate_string(size_t length) + { + // allocate memory for string and header block + size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t); + + // round size up to pointer alignment boundary + size_t full_size = (size + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1); + + xml_memory_page* page; + xml_memory_string_header* header = static_cast(allocate_memory(full_size, page)); + + if (!header) return 0; + + // setup header + ptrdiff_t page_offset = reinterpret_cast(header) - page->data; + + assert(page_offset >= 0 && page_offset < (1 << 16)); + header->page_offset = static_cast(page_offset); + + // full_size == 0 for large strings that occupy the whole page + assert(full_size < (1 << 16) || (page->busy_size == full_size && page_offset == 0)); + header->full_size = static_cast(full_size < (1 << 16) ? full_size : 0); + + // round-trip through void* to avoid 'cast increases required alignment of target type' warning + // header is guaranteed a pointer-sized alignment, which should be enough for char_t + return static_cast(static_cast(header + 1)); + } + + void deallocate_string(char_t* string) + { + // this function casts pointers through void* to avoid 'cast increases required alignment of target type' warnings + // we're guaranteed the proper (pointer-sized) alignment on the input string if it was allocated via allocate_string + + // get header + xml_memory_string_header* header = static_cast(static_cast(string)) - 1; + + // deallocate + size_t page_offset = offsetof(xml_memory_page, data) + header->page_offset; + xml_memory_page* page = reinterpret_cast(static_cast(reinterpret_cast(header) - page_offset)); + + // if full_size == 0 then this string occupies the whole page + size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size; + + deallocate_memory(header, full_size, page); + } + + xml_memory_page* _root; + size_t _busy_size; + }; + + PUGI__FN_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page) + { + const size_t large_allocation_threshold = xml_memory_page_size / 4; + + xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size); + out_page = page; + + if (!page) return 0; + + if (size <= large_allocation_threshold) + { + _root->busy_size = _busy_size; + + // insert page at the end of linked list + page->prev = _root; + _root->next = page; + _root = page; + + _busy_size = size; + } + else + { + // insert page before the end of linked list, so that it is deleted as soon as possible + // the last page is not deleted even if it's empty (see deallocate_memory) + assert(_root->prev); + + page->prev = _root->prev; + page->next = _root; + + _root->prev->next = page; + _root->prev = page; + } + + // allocate inside page + page->busy_size = size; + + return page->data; + } +PUGI__NS_END + +namespace pugi +{ + /// A 'name=value' XML attribute structure. + struct xml_attribute_struct + { + /// Default ctor + xml_attribute_struct(impl::xml_memory_page* page): header(reinterpret_cast(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0) + { + } + + uintptr_t header; + + char_t* name; ///< Pointer to attribute name. + char_t* value; ///< Pointer to attribute value. + + xml_attribute_struct* prev_attribute_c; ///< Previous attribute (cyclic list) + xml_attribute_struct* next_attribute; ///< Next attribute + }; + + /// An XML document tree node. + struct xml_node_struct + { + /// Default ctor + /// \param type - node type + xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(reinterpret_cast(page) | (type - 1)), parent(0), name(0), value(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0) + { + } + + uintptr_t header; + + xml_node_struct* parent; ///< Pointer to parent + + char_t* name; ///< Pointer to element name. + char_t* value; ///< Pointer to any associated string data. + + xml_node_struct* first_child; ///< First child + + xml_node_struct* prev_sibling_c; ///< Left brother (cyclic list) + xml_node_struct* next_sibling; ///< Right brother + + xml_attribute_struct* first_attribute; ///< First attribute + }; +} + +PUGI__NS_BEGIN + struct xml_document_struct: public xml_node_struct, public xml_allocator + { + xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0) + { + } + + const char_t* buffer; + }; + + inline xml_allocator& get_allocator(const xml_node_struct* node) + { + assert(node); + + return *reinterpret_cast(node->header & xml_memory_page_pointer_mask)->allocator; + } +PUGI__NS_END + +// Low-level DOM operations +PUGI__NS_BEGIN + inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc) + { + xml_memory_page* page; + void* memory = alloc.allocate_memory(sizeof(xml_attribute_struct), page); + + return new (memory) xml_attribute_struct(page); + } + + inline xml_node_struct* allocate_node(xml_allocator& alloc, xml_node_type type) + { + xml_memory_page* page; + void* memory = alloc.allocate_memory(sizeof(xml_node_struct), page); + + return new (memory) xml_node_struct(page, type); + } + + inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc) + { + uintptr_t header = a->header; + + if (header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(a->name); + if (header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(a->value); + + alloc.deallocate_memory(a, sizeof(xml_attribute_struct), reinterpret_cast(header & xml_memory_page_pointer_mask)); + } + + inline void destroy_node(xml_node_struct* n, xml_allocator& alloc) + { + uintptr_t header = n->header; + + if (header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(n->name); + if (header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(n->value); + + for (xml_attribute_struct* attr = n->first_attribute; attr; ) + { + xml_attribute_struct* next = attr->next_attribute; + + destroy_attribute(attr, alloc); + + attr = next; + } + + for (xml_node_struct* child = n->first_child; child; ) + { + xml_node_struct* next = child->next_sibling; + + destroy_node(child, alloc); + + child = next; + } + + alloc.deallocate_memory(n, sizeof(xml_node_struct), reinterpret_cast(header & xml_memory_page_pointer_mask)); + } + + PUGI__FN_NO_INLINE xml_node_struct* append_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element) + { + xml_node_struct* child = allocate_node(alloc, type); + if (!child) return 0; + + child->parent = node; + + xml_node_struct* first_child = node->first_child; + + if (first_child) + { + xml_node_struct* last_child = first_child->prev_sibling_c; + + last_child->next_sibling = child; + child->prev_sibling_c = last_child; + first_child->prev_sibling_c = child; + } + else + { + node->first_child = child; + child->prev_sibling_c = child; + } + + return child; + } + + PUGI__FN_NO_INLINE xml_attribute_struct* append_attribute_ll(xml_node_struct* node, xml_allocator& alloc) + { + xml_attribute_struct* a = allocate_attribute(alloc); + if (!a) return 0; + + xml_attribute_struct* first_attribute = node->first_attribute; + + if (first_attribute) + { + xml_attribute_struct* last_attribute = first_attribute->prev_attribute_c; + + last_attribute->next_attribute = a; + a->prev_attribute_c = last_attribute; + first_attribute->prev_attribute_c = a; + } + else + { + node->first_attribute = a; + a->prev_attribute_c = a; + } + + return a; + } +PUGI__NS_END + +// Helper classes for code generation +PUGI__NS_BEGIN + struct opt_false + { + enum { value = 0 }; + }; + + struct opt_true + { + enum { value = 1 }; + }; +PUGI__NS_END + +// Unicode utilities +PUGI__NS_BEGIN + inline uint16_t endian_swap(uint16_t value) + { + return static_cast(((value & 0xff) << 8) | (value >> 8)); + } + + inline uint32_t endian_swap(uint32_t value) + { + return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24); + } + + struct utf8_counter + { + typedef size_t value_type; + + static value_type low(value_type result, uint32_t ch) + { + // U+0000..U+007F + if (ch < 0x80) return result + 1; + // U+0080..U+07FF + else if (ch < 0x800) return result + 2; + // U+0800..U+FFFF + else return result + 3; + } + + static value_type high(value_type result, uint32_t) + { + // U+10000..U+10FFFF + return result + 4; + } + }; + + struct utf8_writer + { + typedef uint8_t* value_type; + + static value_type low(value_type result, uint32_t ch) + { + // U+0000..U+007F + if (ch < 0x80) + { + *result = static_cast(ch); + return result + 1; + } + // U+0080..U+07FF + else if (ch < 0x800) + { + result[0] = static_cast(0xC0 | (ch >> 6)); + result[1] = static_cast(0x80 | (ch & 0x3F)); + return result + 2; + } + // U+0800..U+FFFF + else + { + result[0] = static_cast(0xE0 | (ch >> 12)); + result[1] = static_cast(0x80 | ((ch >> 6) & 0x3F)); + result[2] = static_cast(0x80 | (ch & 0x3F)); + return result + 3; + } + } + + static value_type high(value_type result, uint32_t ch) + { + // U+10000..U+10FFFF + result[0] = static_cast(0xF0 | (ch >> 18)); + result[1] = static_cast(0x80 | ((ch >> 12) & 0x3F)); + result[2] = static_cast(0x80 | ((ch >> 6) & 0x3F)); + result[3] = static_cast(0x80 | (ch & 0x3F)); + return result + 4; + } + + static value_type any(value_type result, uint32_t ch) + { + return (ch < 0x10000) ? low(result, ch) : high(result, ch); + } + }; + + struct utf16_counter + { + typedef size_t value_type; + + static value_type low(value_type result, uint32_t) + { + return result + 1; + } + + static value_type high(value_type result, uint32_t) + { + return result + 2; + } + }; + + struct utf16_writer + { + typedef uint16_t* value_type; + + static value_type low(value_type result, uint32_t ch) + { + *result = static_cast(ch); + + return result + 1; + } + + static value_type high(value_type result, uint32_t ch) + { + uint32_t msh = static_cast(ch - 0x10000) >> 10; + uint32_t lsh = static_cast(ch - 0x10000) & 0x3ff; + + result[0] = static_cast(0xD800 + msh); + result[1] = static_cast(0xDC00 + lsh); + + return result + 2; + } + + static value_type any(value_type result, uint32_t ch) + { + return (ch < 0x10000) ? low(result, ch) : high(result, ch); + } + }; + + struct utf32_counter + { + typedef size_t value_type; + + static value_type low(value_type result, uint32_t) + { + return result + 1; + } + + static value_type high(value_type result, uint32_t) + { + return result + 1; + } + }; + + struct utf32_writer + { + typedef uint32_t* value_type; + + static value_type low(value_type result, uint32_t ch) + { + *result = ch; + + return result + 1; + } + + static value_type high(value_type result, uint32_t ch) + { + *result = ch; + + return result + 1; + } + + static value_type any(value_type result, uint32_t ch) + { + *result = ch; + + return result + 1; + } + }; + + struct latin1_writer + { + typedef uint8_t* value_type; + + static value_type low(value_type result, uint32_t ch) + { + *result = static_cast(ch > 255 ? '?' : ch); + + return result + 1; + } + + static value_type high(value_type result, uint32_t ch) + { + (void)ch; + + *result = '?'; + + return result + 1; + } + }; + + template struct wchar_selector; + + template <> struct wchar_selector<2> + { + typedef uint16_t type; + typedef utf16_counter counter; + typedef utf16_writer writer; + }; + + template <> struct wchar_selector<4> + { + typedef uint32_t type; + typedef utf32_counter counter; + typedef utf32_writer writer; + }; + + typedef wchar_selector::counter wchar_counter; + typedef wchar_selector::writer wchar_writer; + + template struct utf_decoder + { + static inline typename Traits::value_type decode_utf8_block(const uint8_t* data, size_t size, typename Traits::value_type result) + { + const uint8_t utf8_byte_mask = 0x3f; + + while (size) + { + uint8_t lead = *data; + + // 0xxxxxxx -> U+0000..U+007F + if (lead < 0x80) + { + result = Traits::low(result, lead); + data += 1; + size -= 1; + + // process aligned single-byte (ascii) blocks + if ((reinterpret_cast(data) & 3) == 0) + { + // round-trip through void* to silence 'cast increases required alignment of target type' warnings + while (size >= 4 && (*static_cast(static_cast(data)) & 0x80808080) == 0) + { + result = Traits::low(result, data[0]); + result = Traits::low(result, data[1]); + result = Traits::low(result, data[2]); + result = Traits::low(result, data[3]); + data += 4; + size -= 4; + } + } + } + // 110xxxxx -> U+0080..U+07FF + else if (static_cast(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80) + { + result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask)); + data += 2; + size -= 2; + } + // 1110xxxx -> U+0800-U+FFFF + else if (static_cast(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80) + { + result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask)); + data += 3; + size -= 3; + } + // 11110xxx -> U+10000..U+10FFFF + else if (static_cast(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80) + { + result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask)); + data += 4; + size -= 4; + } + // 10xxxxxx or 11111xxx -> invalid + else + { + data += 1; + size -= 1; + } + } + + return result; + } + + static inline typename Traits::value_type decode_utf16_block(const uint16_t* data, size_t size, typename Traits::value_type result) + { + const uint16_t* end = data + size; + + while (data < end) + { + uint16_t lead = opt_swap::value ? endian_swap(*data) : *data; + + // U+0000..U+D7FF + if (lead < 0xD800) + { + result = Traits::low(result, lead); + data += 1; + } + // U+E000..U+FFFF + else if (static_cast(lead - 0xE000) < 0x2000) + { + result = Traits::low(result, lead); + data += 1; + } + // surrogate pair lead + else if (static_cast(lead - 0xD800) < 0x400 && data + 1 < end) + { + uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1]; + + if (static_cast(next - 0xDC00) < 0x400) + { + result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff)); + data += 2; + } + else + { + data += 1; + } + } + else + { + data += 1; + } + } + + return result; + } + + static inline typename Traits::value_type decode_utf32_block(const uint32_t* data, size_t size, typename Traits::value_type result) + { + const uint32_t* end = data + size; + + while (data < end) + { + uint32_t lead = opt_swap::value ? endian_swap(*data) : *data; + + // U+0000..U+FFFF + if (lead < 0x10000) + { + result = Traits::low(result, lead); + data += 1; + } + // U+10000..U+10FFFF + else + { + result = Traits::high(result, lead); + data += 1; + } + } + + return result; + } + + static inline typename Traits::value_type decode_latin1_block(const uint8_t* data, size_t size, typename Traits::value_type result) + { + for (size_t i = 0; i < size; ++i) + { + result = Traits::low(result, data[i]); + } + + return result; + } + + static inline typename Traits::value_type decode_wchar_block_impl(const uint16_t* data, size_t size, typename Traits::value_type result) + { + return decode_utf16_block(data, size, result); + } + + static inline typename Traits::value_type decode_wchar_block_impl(const uint32_t* data, size_t size, typename Traits::value_type result) + { + return decode_utf32_block(data, size, result); + } + + static inline typename Traits::value_type decode_wchar_block(const wchar_t* data, size_t size, typename Traits::value_type result) + { + return decode_wchar_block_impl(reinterpret_cast::type*>(data), size, result); + } + }; + + template PUGI__FN void convert_utf_endian_swap(T* result, const T* data, size_t length) + { + for (size_t i = 0; i < length; ++i) result[i] = endian_swap(data[i]); + } + +#ifdef PUGIXML_WCHAR_MODE + PUGI__FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length) + { + for (size_t i = 0; i < length; ++i) result[i] = static_cast(endian_swap(static_cast::type>(data[i]))); + } +#endif +PUGI__NS_END + +PUGI__NS_BEGIN + enum chartype_t + { + ct_parse_pcdata = 1, // \0, &, \r, < + ct_parse_attr = 2, // \0, &, \r, ', " + ct_parse_attr_ws = 4, // \0, &, \r, ', ", \n, tab + ct_space = 8, // \r, \n, space, tab + ct_parse_cdata = 16, // \0, ], >, \r + ct_parse_comment = 32, // \0, -, >, \r + ct_symbol = 64, // Any symbol > 127, a-z, A-Z, 0-9, _, :, -, . + ct_start_symbol = 128 // Any symbol > 127, a-z, A-Z, _, : + }; + + static const unsigned char chartype_table[256] = + { + 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0, // 0-15 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31 + 8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0, // 32-47 + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0, // 48-63 + 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 64-79 + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192, // 80-95 + 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 96-111 + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0, // 112-127 + + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 128+ + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192 + }; + + enum chartypex_t + { + ctx_special_pcdata = 1, // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, > + ctx_special_attr = 2, // Any symbol >= 0 and < 32 (except \t), &, <, >, " + ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _ + ctx_digit = 8, // 0-9 + ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, . + }; + + static const unsigned char chartypex_table[256] = + { + 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3, // 0-15 + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31 + 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 16, 16, 0, // 32-47 + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 3, 0, // 48-63 + + 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 64-79 + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 20, // 80-95 + 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 96-111 + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, // 112-127 + + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 128+ + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 + }; + +#ifdef PUGIXML_WCHAR_MODE + #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast(c) < 128 ? table[static_cast(c)] : table[128]) & (ct)) +#else + #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast(c)] & (ct)) +#endif + + #define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table) + #define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table) + + PUGI__FN bool is_little_endian() + { + unsigned int ui = 1; + + return *reinterpret_cast(&ui) == 1; + } + + PUGI__FN xml_encoding get_wchar_encoding() + { + PUGI__STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); + + if (sizeof(wchar_t) == 2) + return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + else + return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + } + + PUGI__FN xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) + { + // look for BOM in first few bytes + if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be; + if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le; + if (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be; + if (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le; + if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf) return encoding_utf8; + + // look for <, (contents); + + PUGI__DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3]; + + return guess_buffer_encoding(d0, d1, d2, d3); + } + + PUGI__FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) + { + if (is_mutable) + { + out_buffer = static_cast(const_cast(contents)); + } + else + { + void* buffer = xml_memory::allocate(size > 0 ? size : 1); + if (!buffer) return false; + + memcpy(buffer, contents, size); + + out_buffer = static_cast(buffer); + } + + out_length = size / sizeof(char_t); + + return true; + } + +#ifdef PUGIXML_WCHAR_MODE + PUGI__FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re) + { + return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) || + (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be); + } + + PUGI__FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) + { + const char_t* data = static_cast(contents); + + if (is_mutable) + { + out_buffer = const_cast(data); + } + else + { + out_buffer = static_cast(xml_memory::allocate(size > 0 ? size : 1)); + if (!out_buffer) return false; + } + + out_length = size / sizeof(char_t); + + convert_wchar_endian_swap(out_buffer, data, out_length); + + return true; + } + + PUGI__FN bool convert_buffer_utf8(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size) + { + const uint8_t* data = static_cast(contents); + + // first pass: get length in wchar_t units + out_length = utf_decoder::decode_utf8_block(data, size, 0); + + // allocate buffer of suitable length + out_buffer = static_cast(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf8 input to wchar_t + wchar_writer::value_type out_begin = reinterpret_cast(out_buffer); + wchar_writer::value_type out_end = utf_decoder::decode_utf8_block(data, size, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + template PUGI__FN bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) + { + const uint16_t* data = static_cast(contents); + size_t length = size / sizeof(uint16_t); + + // first pass: get length in wchar_t units + out_length = utf_decoder::decode_utf16_block(data, length, 0); + + // allocate buffer of suitable length + out_buffer = static_cast(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf16 input to wchar_t + wchar_writer::value_type out_begin = reinterpret_cast(out_buffer); + wchar_writer::value_type out_end = utf_decoder::decode_utf16_block(data, length, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + template PUGI__FN bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) + { + const uint32_t* data = static_cast(contents); + size_t length = size / sizeof(uint32_t); + + // first pass: get length in wchar_t units + out_length = utf_decoder::decode_utf32_block(data, length, 0); + + // allocate buffer of suitable length + out_buffer = static_cast(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf32 input to wchar_t + wchar_writer::value_type out_begin = reinterpret_cast(out_buffer); + wchar_writer::value_type out_end = utf_decoder::decode_utf32_block(data, length, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size) + { + const uint8_t* data = static_cast(contents); + + // get length in wchar_t units + out_length = size; + + // allocate buffer of suitable length + out_buffer = static_cast(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // convert latin1 input to wchar_t + wchar_writer::value_type out_begin = reinterpret_cast(out_buffer); + wchar_writer::value_type out_end = utf_decoder::decode_latin1_block(data, size, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) + { + // get native encoding + xml_encoding wchar_encoding = get_wchar_encoding(); + + // fast path: no conversion required + if (encoding == wchar_encoding) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); + + // only endian-swapping is required + if (need_endian_swap_utf(encoding, wchar_encoding)) return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable); + + // source encoding is utf8 + if (encoding == encoding_utf8) return convert_buffer_utf8(out_buffer, out_length, contents, size); + + // source encoding is utf16 + if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) + { + xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + return (native_encoding == encoding) ? + convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) : + convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true()); + } + + // source encoding is utf32 + if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) + { + xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + return (native_encoding == encoding) ? + convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : + convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); + } + + // source encoding is latin1 + if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size); + + assert(!"Invalid encoding"); + return false; + } +#else + template PUGI__FN bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) + { + const uint16_t* data = static_cast(contents); + size_t length = size / sizeof(uint16_t); + + // first pass: get length in utf8 units + out_length = utf_decoder::decode_utf16_block(data, length, 0); + + // allocate buffer of suitable length + out_buffer = static_cast(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf16 input to utf8 + uint8_t* out_begin = reinterpret_cast(out_buffer); + uint8_t* out_end = utf_decoder::decode_utf16_block(data, length, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + template PUGI__FN bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) + { + const uint32_t* data = static_cast(contents); + size_t length = size / sizeof(uint32_t); + + // first pass: get length in utf8 units + out_length = utf_decoder::decode_utf32_block(data, length, 0); + + // allocate buffer of suitable length + out_buffer = static_cast(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf32 input to utf8 + uint8_t* out_begin = reinterpret_cast(out_buffer); + uint8_t* out_end = utf_decoder::decode_utf32_block(data, length, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size) + { + for (size_t i = 0; i < size; ++i) + if (data[i] > 127) + return i; + + return size; + } + + PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) + { + const uint8_t* data = static_cast(contents); + + // get size of prefix that does not need utf8 conversion + size_t prefix_length = get_latin1_7bit_prefix_length(data, size); + assert(prefix_length <= size); + + const uint8_t* postfix = data + prefix_length; + size_t postfix_length = size - prefix_length; + + // if no conversion is needed, just return the original buffer + if (postfix_length == 0) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); + + // first pass: get length in utf8 units + out_length = prefix_length + utf_decoder::decode_latin1_block(postfix, postfix_length, 0); + + // allocate buffer of suitable length + out_buffer = static_cast(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert latin1 input to utf8 + memcpy(out_buffer, data, prefix_length); + + uint8_t* out_begin = reinterpret_cast(out_buffer); + uint8_t* out_end = utf_decoder::decode_latin1_block(postfix, postfix_length, out_begin + prefix_length); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) + { + // fast path: no conversion required + if (encoding == encoding_utf8) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); + + // source encoding is utf16 + if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) + { + xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + return (native_encoding == encoding) ? + convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) : + convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true()); + } + + // source encoding is utf32 + if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) + { + xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + return (native_encoding == encoding) ? + convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : + convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); + } + + // source encoding is latin1 + if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable); + + assert(!"Invalid encoding"); + return false; + } +#endif + + PUGI__FN size_t as_utf8_begin(const wchar_t* str, size_t length) + { + // get length in utf8 characters + return utf_decoder::decode_wchar_block(str, length, 0); + } + + PUGI__FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length) + { + // convert to utf8 + uint8_t* begin = reinterpret_cast(buffer); + uint8_t* end = utf_decoder::decode_wchar_block(str, length, begin); + + assert(begin + size == end); + (void)!end; + + // zero-terminate + buffer[size] = 0; + } + +#ifndef PUGIXML_NO_STL + PUGI__FN std::string as_utf8_impl(const wchar_t* str, size_t length) + { + // first pass: get length in utf8 characters + size_t size = as_utf8_begin(str, length); + + // allocate resulting string + std::string result; + result.resize(size); + + // second pass: convert to utf8 + if (size > 0) as_utf8_end(&result[0], size, str, length); + + return result; + } + + PUGI__FN std::basic_string as_wide_impl(const char* str, size_t size) + { + const uint8_t* data = reinterpret_cast(str); + + // first pass: get length in wchar_t units + size_t length = utf_decoder::decode_utf8_block(data, size, 0); + + // allocate resulting string + std::basic_string result; + result.resize(length); + + // second pass: convert to wchar_t + if (length > 0) + { + wchar_writer::value_type begin = reinterpret_cast(&result[0]); + wchar_writer::value_type end = utf_decoder::decode_utf8_block(data, size, begin); + + assert(begin + length == end); + (void)!end; + } + + return result; + } +#endif + + inline bool strcpy_insitu_allow(size_t length, uintptr_t allocated, char_t* target) + { + assert(target); + size_t target_length = strlength(target); + + // always reuse document buffer memory if possible + if (!allocated) return target_length >= length; + + // reuse heap memory if waste is not too great + const size_t reuse_threshold = 32; + + return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2); + } + + PUGI__FN bool strcpy_insitu(char_t*& dest, uintptr_t& header, uintptr_t header_mask, const char_t* source) + { + size_t source_length = strlength(source); + + if (source_length == 0) + { + // empty string and null pointer are equivalent, so just deallocate old memory + xml_allocator* alloc = reinterpret_cast(header & xml_memory_page_pointer_mask)->allocator; + + if (header & header_mask) alloc->deallocate_string(dest); + + // mark the string as not allocated + dest = 0; + header &= ~header_mask; + + return true; + } + else if (dest && strcpy_insitu_allow(source_length, header & header_mask, dest)) + { + // we can reuse old buffer, so just copy the new data (including zero terminator) + memcpy(dest, source, (source_length + 1) * sizeof(char_t)); + + return true; + } + else + { + xml_allocator* alloc = reinterpret_cast(header & xml_memory_page_pointer_mask)->allocator; + + // allocate new buffer + char_t* buf = alloc->allocate_string(source_length + 1); + if (!buf) return false; + + // copy the string (including zero terminator) + memcpy(buf, source, (source_length + 1) * sizeof(char_t)); + + // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures) + if (header & header_mask) alloc->deallocate_string(dest); + + // the string is now allocated, so set the flag + dest = buf; + header |= header_mask; + + return true; + } + } + + struct gap + { + char_t* end; + size_t size; + + gap(): end(0), size(0) + { + } + + // Push new gap, move s count bytes further (skipping the gap). + // Collapse previous gap. + void push(char_t*& s, size_t count) + { + if (end) // there was a gap already; collapse it + { + // Move [old_gap_end, new_gap_start) to [old_gap_start, ...) + assert(s >= end); + memmove(end - size, end, reinterpret_cast(s) - reinterpret_cast(end)); + } + + s += count; // end of current gap + + // "merge" two gaps + end = s; + size += count; + } + + // Collapse all gaps, return past-the-end pointer + char_t* flush(char_t* s) + { + if (end) + { + // Move [old_gap_end, current_pos) to [old_gap_start, ...) + assert(s >= end); + memmove(end - size, end, reinterpret_cast(s) - reinterpret_cast(end)); + + return s - size; + } + else return s; + } + }; + + PUGI__FN char_t* strconv_escape(char_t* s, gap& g) + { + char_t* stre = s + 1; + + switch (*stre) + { + case '#': // &#... + { + unsigned int ucsc = 0; + + if (stre[1] == 'x') // &#x... (hex code) + { + stre += 2; + + char_t ch = *stre; + + if (ch == ';') return stre; + + for (;;) + { + if (static_cast(ch - '0') <= 9) + ucsc = 16 * ucsc + (ch - '0'); + else if (static_cast((ch | ' ') - 'a') <= 5) + ucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10); + else if (ch == ';') + break; + else // cancel + return stre; + + ch = *++stre; + } + + ++stre; + } + else // &#... (dec code) + { + char_t ch = *++stre; + + if (ch == ';') return stre; + + for (;;) + { + if (static_cast(ch - '0') <= 9) + ucsc = 10 * ucsc + (ch - '0'); + else if (ch == ';') + break; + else // cancel + return stre; + + ch = *++stre; + } + + ++stre; + } + + #ifdef PUGIXML_WCHAR_MODE + s = reinterpret_cast(wchar_writer::any(reinterpret_cast(s), ucsc)); + #else + s = reinterpret_cast(utf8_writer::any(reinterpret_cast(s), ucsc)); + #endif + + g.push(s, stre - s); + return stre; + } + + case 'a': // &a + { + ++stre; + + if (*stre == 'm') // &am + { + if (*++stre == 'p' && *++stre == ';') // & + { + *s++ = '&'; + ++stre; + + g.push(s, stre - s); + return stre; + } + } + else if (*stre == 'p') // &ap + { + if (*++stre == 'o' && *++stre == 's' && *++stre == ';') // ' + { + *s++ = '\''; + ++stre; + + g.push(s, stre - s); + return stre; + } + } + break; + } + + case 'g': // &g + { + if (*++stre == 't' && *++stre == ';') // > + { + *s++ = '>'; + ++stre; + + g.push(s, stre - s); + return stre; + } + break; + } + + case 'l': // &l + { + if (*++stre == 't' && *++stre == ';') // < + { + *s++ = '<'; + ++stre; + + g.push(s, stre - s); + return stre; + } + break; + } + + case 'q': // &q + { + if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // " + { + *s++ = '"'; + ++stre; + + g.push(s, stre - s); + return stre; + } + break; + } + + default: + break; + } + + return stre; + } + + // Utility macro for last character handling + #define ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e))) + + PUGI__FN char_t* strconv_comment(char_t* s, char_t endch) + { + gap g; + + while (true) + { + while (!PUGI__IS_CHARTYPE(*s, ct_parse_comment)) ++s; + + if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair + { + *s++ = '\n'; // replace first one with 0x0a + + if (*s == '\n') g.push(s, 1); + } + else if (s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')) // comment ends here + { + *g.flush(s) = 0; + + return s + (s[2] == '>' ? 3 : 2); + } + else if (*s == 0) + { + return 0; + } + else ++s; + } + } + + PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch) + { + gap g; + + while (true) + { + while (!PUGI__IS_CHARTYPE(*s, ct_parse_cdata)) ++s; + + if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair + { + *s++ = '\n'; // replace first one with 0x0a + + if (*s == '\n') g.push(s, 1); + } + else if (s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')) // CDATA ends here + { + *g.flush(s) = 0; + + return s + 1; + } + else if (*s == 0) + { + return 0; + } + else ++s; + } + } + + typedef char_t* (*strconv_pcdata_t)(char_t*); + + template struct strconv_pcdata_impl + { + static char_t* parse(char_t* s) + { + gap g; + + while (true) + { + while (!PUGI__IS_CHARTYPE(*s, ct_parse_pcdata)) ++s; + + if (*s == '<') // PCDATA ends here + { + *g.flush(s) = 0; + + return s + 1; + } + else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair + { + *s++ = '\n'; // replace first one with 0x0a + + if (*s == '\n') g.push(s, 1); + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (*s == 0) + { + return s; + } + else ++s; + } + } + }; + + PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask) + { + PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20); + + switch ((optmask >> 4) & 3) // get bitmask for flags (eol escapes) + { + case 0: return strconv_pcdata_impl::parse; + case 1: return strconv_pcdata_impl::parse; + case 2: return strconv_pcdata_impl::parse; + case 3: return strconv_pcdata_impl::parse; + default: return 0; // should not get here + } + } + + typedef char_t* (*strconv_attribute_t)(char_t*, char_t); + + template struct strconv_attribute_impl + { + static char_t* parse_wnorm(char_t* s, char_t end_quote) + { + gap g; + + // trim leading whitespaces + if (PUGI__IS_CHARTYPE(*s, ct_space)) + { + char_t* str = s; + + do ++str; + while (PUGI__IS_CHARTYPE(*str, ct_space)); + + g.push(s, str - s); + } + + while (true) + { + while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr_ws | ct_space)) ++s; + + if (*s == end_quote) + { + char_t* str = g.flush(s); + + do *str-- = 0; + while (PUGI__IS_CHARTYPE(*str, ct_space)); + + return s + 1; + } + else if (PUGI__IS_CHARTYPE(*s, ct_space)) + { + *s++ = ' '; + + if (PUGI__IS_CHARTYPE(*s, ct_space)) + { + char_t* str = s + 1; + while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str; + + g.push(s, str - s); + } + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (!*s) + { + return 0; + } + else ++s; + } + } + + static char_t* parse_wconv(char_t* s, char_t end_quote) + { + gap g; + + while (true) + { + while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr_ws)) ++s; + + if (*s == end_quote) + { + *g.flush(s) = 0; + + return s + 1; + } + else if (PUGI__IS_CHARTYPE(*s, ct_space)) + { + if (*s == '\r') + { + *s++ = ' '; + + if (*s == '\n') g.push(s, 1); + } + else *s++ = ' '; + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (!*s) + { + return 0; + } + else ++s; + } + } + + static char_t* parse_eol(char_t* s, char_t end_quote) + { + gap g; + + while (true) + { + while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr)) ++s; + + if (*s == end_quote) + { + *g.flush(s) = 0; + + return s + 1; + } + else if (*s == '\r') + { + *s++ = '\n'; + + if (*s == '\n') g.push(s, 1); + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (!*s) + { + return 0; + } + else ++s; + } + } + + static char_t* parse_simple(char_t* s, char_t end_quote) + { + gap g; + + while (true) + { + while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr)) ++s; + + if (*s == end_quote) + { + *g.flush(s) = 0; + + return s + 1; + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (!*s) + { + return 0; + } + else ++s; + } + } + }; + + PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask) + { + PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80); + + switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes) + { + case 0: return strconv_attribute_impl::parse_simple; + case 1: return strconv_attribute_impl::parse_simple; + case 2: return strconv_attribute_impl::parse_eol; + case 3: return strconv_attribute_impl::parse_eol; + case 4: return strconv_attribute_impl::parse_wconv; + case 5: return strconv_attribute_impl::parse_wconv; + case 6: return strconv_attribute_impl::parse_wconv; + case 7: return strconv_attribute_impl::parse_wconv; + case 8: return strconv_attribute_impl::parse_wnorm; + case 9: return strconv_attribute_impl::parse_wnorm; + case 10: return strconv_attribute_impl::parse_wnorm; + case 11: return strconv_attribute_impl::parse_wnorm; + case 12: return strconv_attribute_impl::parse_wnorm; + case 13: return strconv_attribute_impl::parse_wnorm; + case 14: return strconv_attribute_impl::parse_wnorm; + case 15: return strconv_attribute_impl::parse_wnorm; + default: return 0; // should not get here + } + } + + inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0) + { + xml_parse_result result; + result.status = status; + result.offset = offset; + + return result; + } + + struct xml_parser + { + xml_allocator alloc; + char_t* error_offset; + xml_parse_status error_status; + + // Parser utilities. + #define PUGI__SKIPWS() { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; } + #define PUGI__OPTSET(OPT) ( optmsk & (OPT) ) + #define PUGI__PUSHNODE(TYPE) { cursor = append_node(cursor, alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); } + #define PUGI__POPNODE() { cursor = cursor->parent; } + #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; } + #define PUGI__SCANWHILE(X) { while ((X)) ++s; } + #define PUGI__ENDSEG() { ch = *s; *s = 0; ++s; } + #define PUGI__THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast(0) + #define PUGI__CHECK_ERROR(err, m) { if (*s == 0) PUGI__THROW_ERROR(err, m); } + + xml_parser(const xml_allocator& alloc_): alloc(alloc_), error_offset(0), error_status(status_ok) + { + } + + // DOCTYPE consists of nested sections of the following possible types: + // , , "...", '...' + // + // + // First group can not contain nested groups + // Second group can contain nested groups of the same type + // Third group can contain all other groups + char_t* parse_doctype_primitive(char_t* s) + { + if (*s == '"' || *s == '\'') + { + // quoted string + char_t ch = *s++; + PUGI__SCANFOR(*s == ch); + if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); + + s++; + } + else if (s[0] == '<' && s[1] == '?') + { + // + s += 2; + PUGI__SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype + if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); + + s += 2; + } + else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-') + { + s += 4; + PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype + if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); + + s += 4; + } + else PUGI__THROW_ERROR(status_bad_doctype, s); + + return s; + } + + char_t* parse_doctype_ignore(char_t* s) + { + assert(s[0] == '<' && s[1] == '!' && s[2] == '['); + s++; + + while (*s) + { + if (s[0] == '<' && s[1] == '!' && s[2] == '[') + { + // nested ignore section + s = parse_doctype_ignore(s); + if (!s) return s; + } + else if (s[0] == ']' && s[1] == ']' && s[2] == '>') + { + // ignore section end + s += 3; + + return s; + } + else s++; + } + + PUGI__THROW_ERROR(status_bad_doctype, s); + } + + char_t* parse_doctype_group(char_t* s, char_t endch, bool toplevel) + { + assert(s[0] == '<' && s[1] == '!'); + s++; + + while (*s) + { + if (s[0] == '<' && s[1] == '!' && s[2] != '-') + { + if (s[2] == '[') + { + // ignore + s = parse_doctype_ignore(s); + if (!s) return s; + } + else + { + // some control group + s = parse_doctype_group(s, endch, false); + if (!s) return s; + } + } + else if (s[0] == '<' || s[0] == '"' || s[0] == '\'') + { + // unknown tag (forbidden), or some primitive group + s = parse_doctype_primitive(s); + if (!s) return s; + } + else if (*s == '>') + { + s++; + + return s; + } + else s++; + } + + if (!toplevel || endch != '>') PUGI__THROW_ERROR(status_bad_doctype, s); + + return s; + } + + char_t* parse_exclamation(char_t* s, xml_node_struct* cursor, unsigned int optmsk, char_t endch) + { + // parse node contents, starting with exclamation mark + ++s; + + if (*s == '-') // 'value = s; // Save the offset. + } + + if (PUGI__OPTSET(parse_eol) && PUGI__OPTSET(parse_comments)) + { + s = strconv_comment(s, endch); + + if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value); + } + else + { + // Scan for terminating '-->'. + PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')); + PUGI__CHECK_ERROR(status_bad_comment, s); + + if (PUGI__OPTSET(parse_comments)) + *s = 0; // Zero-terminate this segment at the first terminating '-'. + + s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'. + } + } + else PUGI__THROW_ERROR(status_bad_comment, s); + } + else if (*s == '[') + { + // 'value = s; // Save the offset. + + if (PUGI__OPTSET(parse_eol)) + { + s = strconv_cdata(s, endch); + + if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value); + } + else + { + // Scan for terminating ']]>'. + PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')); + PUGI__CHECK_ERROR(status_bad_cdata, s); + + *s++ = 0; // Zero-terminate this segment. + } + } + else // Flagged for discard, but we still have to scan for the terminator. + { + // Scan for terminating ']]>'. + PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')); + PUGI__CHECK_ERROR(status_bad_cdata, s); + + ++s; + } + + s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'. + } + else PUGI__THROW_ERROR(status_bad_cdata, s); + } + else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && ENDSWITH(s[6], 'E')) + { + s -= 2; + + if (cursor->parent) PUGI__THROW_ERROR(status_bad_doctype, s); + + char_t* mark = s + 9; + + s = parse_doctype_group(s, endch, true); + if (!s) return s; + + if (PUGI__OPTSET(parse_doctype)) + { + while (PUGI__IS_CHARTYPE(*mark, ct_space)) ++mark; + + PUGI__PUSHNODE(node_doctype); + + cursor->value = mark; + + assert((s[0] == 0 && endch == '>') || s[-1] == '>'); + s[*s == 0 ? 0 : -1] = 0; + + PUGI__POPNODE(); + } + } + else if (*s == 0 && endch == '-') PUGI__THROW_ERROR(status_bad_comment, s); + else if (*s == 0 && endch == '[') PUGI__THROW_ERROR(status_bad_cdata, s); + else PUGI__THROW_ERROR(status_unrecognized_tag, s); + + return s; + } + + char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor, unsigned int optmsk, char_t endch) + { + // load into registers + xml_node_struct* cursor = ref_cursor; + char_t ch = 0; + + // parse node contents, starting with question mark + ++s; + + // read PI target + char_t* target = s; + + if (!PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_pi, s); + + PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); + PUGI__CHECK_ERROR(status_bad_pi, s); + + // determine node type; stricmp / strcasecmp is not portable + bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s; + + if (declaration ? PUGI__OPTSET(parse_declaration) : PUGI__OPTSET(parse_pi)) + { + if (declaration) + { + // disallow non top-level declarations + if (cursor->parent) PUGI__THROW_ERROR(status_bad_pi, s); + + PUGI__PUSHNODE(node_declaration); + } + else + { + PUGI__PUSHNODE(node_pi); + } + + cursor->name = target; + + PUGI__ENDSEG(); + + // parse value/attributes + if (ch == '?') + { + // empty node + if (!ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_pi, s); + s += (*s == '>'); + + PUGI__POPNODE(); + } + else if (PUGI__IS_CHARTYPE(ch, ct_space)) + { + PUGI__SKIPWS(); + + // scan for tag end + char_t* value = s; + + PUGI__SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>')); + PUGI__CHECK_ERROR(status_bad_pi, s); + + if (declaration) + { + // replace ending ? with / so that 'element' terminates properly + *s = '/'; + + // we exit from this function with cursor at node_declaration, which is a signal to parse() to go to LOC_ATTRIBUTES + s = value; + } + else + { + // store value and step over > + cursor->value = value; + PUGI__POPNODE(); + + PUGI__ENDSEG(); + + s += (*s == '>'); + } + } + else PUGI__THROW_ERROR(status_bad_pi, s); + } + else + { + // scan for tag end + PUGI__SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>')); + PUGI__CHECK_ERROR(status_bad_pi, s); + + s += (s[1] == '>' ? 2 : 1); + } + + // store from registers + ref_cursor = cursor; + + return s; + } + + char_t* parse(char_t* s, xml_node_struct* xmldoc, unsigned int optmsk, char_t endch) + { + strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk); + strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk); + + char_t ch = 0; + xml_node_struct* cursor = xmldoc; + char_t* mark = s; + + while (*s != 0) + { + if (*s == '<') + { + ++s; + + LOC_TAG: + if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // '<#...' + { + PUGI__PUSHNODE(node_element); // Append a new node to the tree. + + cursor->name = s; + + PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator. + PUGI__ENDSEG(); // Save char in 'ch', terminate & step over. + + if (ch == '>') + { + // end of tag + } + else if (PUGI__IS_CHARTYPE(ch, ct_space)) + { + LOC_ATTRIBUTES: + while (true) + { + PUGI__SKIPWS(); // Eat any whitespace. + + if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #... + { + xml_attribute_struct* a = append_attribute_ll(cursor, alloc); // Make space for this attribute. + if (!a) PUGI__THROW_ERROR(status_out_of_memory, s); + + a->name = s; // Save the offset. + + PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator. + PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance + + PUGI__ENDSEG(); // Save char in 'ch', terminate & step over. + PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance + + if (PUGI__IS_CHARTYPE(ch, ct_space)) + { + PUGI__SKIPWS(); // Eat any whitespace. + PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance + + ch = *s; + ++s; + } + + if (ch == '=') // '<... #=...' + { + PUGI__SKIPWS(); // Eat any whitespace. + + if (*s == '"' || *s == '\'') // '<... #="...' + { + ch = *s; // Save quote char to avoid breaking on "''" -or- '""'. + ++s; // Step over the quote. + a->value = s; // Save the offset. + + s = strconv_attribute(s, ch); + + if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value); + + // After this line the loop continues from the start; + // Whitespaces, / and > are ok, symbols and EOF are wrong, + // everything else will be detected + if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_attribute, s); + } + else PUGI__THROW_ERROR(status_bad_attribute, s); + } + else PUGI__THROW_ERROR(status_bad_attribute, s); + } + else if (*s == '/') + { + ++s; + + if (*s == '>') + { + PUGI__POPNODE(); + s++; + break; + } + else if (*s == 0 && endch == '>') + { + PUGI__POPNODE(); + break; + } + else PUGI__THROW_ERROR(status_bad_start_element, s); + } + else if (*s == '>') + { + ++s; + + break; + } + else if (*s == 0 && endch == '>') + { + break; + } + else PUGI__THROW_ERROR(status_bad_start_element, s); + } + + // !!! + } + else if (ch == '/') // '<#.../' + { + if (!ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_start_element, s); + + PUGI__POPNODE(); // Pop. + + s += (*s == '>'); + } + else if (ch == 0) + { + // we stepped over null terminator, backtrack & handle closing tag + --s; + + if (endch != '>') PUGI__THROW_ERROR(status_bad_start_element, s); + } + else PUGI__THROW_ERROR(status_bad_start_element, s); + } + else if (*s == '/') + { + ++s; + + char_t* name = cursor->name; + if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, s); + + while (PUGI__IS_CHARTYPE(*s, ct_symbol)) + { + if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, s); + } + + if (*name) + { + if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s); + else PUGI__THROW_ERROR(status_end_element_mismatch, s); + } + + PUGI__POPNODE(); // Pop. + + PUGI__SKIPWS(); + + if (*s == 0) + { + if (endch != '>') PUGI__THROW_ERROR(status_bad_end_element, s); + } + else + { + if (*s != '>') PUGI__THROW_ERROR(status_bad_end_element, s); + ++s; + } + } + else if (*s == '?') // 'header & xml_memory_page_type_mask) + 1 == node_declaration) goto LOC_ATTRIBUTES; + } + else if (*s == '!') // 'first_child) continue; + } + } + + s = mark; + + if (cursor->parent) + { + PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree. + cursor->value = s; // Save the offset. + + s = strconv_pcdata(s); + + PUGI__POPNODE(); // Pop since this is a standalone. + + if (!*s) break; + } + else + { + PUGI__SCANFOR(*s == '<'); // '...<' + if (!*s) break; + + ++s; + } + + // We're after '<' + goto LOC_TAG; + } + } + + // check that last tag is closed + if (cursor != xmldoc) PUGI__THROW_ERROR(status_end_element_mismatch, s); + + return s; + } + + static xml_parse_result parse(char_t* buffer, size_t length, xml_node_struct* root, unsigned int optmsk) + { + xml_document_struct* xmldoc = static_cast(root); + + // store buffer for offset_debug + xmldoc->buffer = buffer; + + // early-out for empty documents + if (length == 0) return make_parse_result(status_ok); + + // create parser on stack + xml_parser parser(*xmldoc); + + // save last character and make buffer zero-terminated (speeds up parsing) + char_t endch = buffer[length - 1]; + buffer[length - 1] = 0; + + // perform actual parsing + parser.parse(buffer, xmldoc, optmsk, endch); + + xml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0); + assert(result.offset >= 0 && static_cast(result.offset) <= length); + + // update allocator state + *static_cast(xmldoc) = parser.alloc; + + // since we removed last character, we have to handle the only possible false positive + if (result && endch == '<') + { + // there's no possible well-formed document with < at the end + return make_parse_result(status_unrecognized_tag, length); + } + + return result; + } + }; + + // Output facilities + PUGI__FN xml_encoding get_write_native_encoding() + { + #ifdef PUGIXML_WCHAR_MODE + return get_wchar_encoding(); + #else + return encoding_utf8; + #endif + } + + PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding) + { + // replace wchar encoding with utf implementation + if (encoding == encoding_wchar) return get_wchar_encoding(); + + // replace utf16 encoding with utf16 with specific endianness + if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + // replace utf32 encoding with utf32 with specific endianness + if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + // only do autodetection if no explicit encoding is requested + if (encoding != encoding_auto) return encoding; + + // assume utf8 encoding + return encoding_utf8; + } + +#ifdef PUGIXML_WCHAR_MODE + PUGI__FN size_t get_valid_length(const char_t* data, size_t length) + { + assert(length > 0); + + // discard last character if it's the lead of a surrogate pair + return (sizeof(wchar_t) == 2 && static_cast(static_cast(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length; + } + + PUGI__FN size_t convert_buffer(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding) + { + // only endian-swapping is required + if (need_endian_swap_utf(encoding, get_wchar_encoding())) + { + convert_wchar_endian_swap(r_char, data, length); + + return length * sizeof(char_t); + } + + // convert to utf8 + if (encoding == encoding_utf8) + { + uint8_t* dest = r_u8; + uint8_t* end = utf_decoder::decode_wchar_block(data, length, dest); + + return static_cast(end - dest); + } + + // convert to utf16 + if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) + { + uint16_t* dest = r_u16; + + // convert to native utf16 + uint16_t* end = utf_decoder::decode_wchar_block(data, length, dest); + + // swap if necessary + xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); + + return static_cast(end - dest) * sizeof(uint16_t); + } + + // convert to utf32 + if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) + { + uint32_t* dest = r_u32; + + // convert to native utf32 + uint32_t* end = utf_decoder::decode_wchar_block(data, length, dest); + + // swap if necessary + xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); + + return static_cast(end - dest) * sizeof(uint32_t); + } + + // convert to latin1 + if (encoding == encoding_latin1) + { + uint8_t* dest = r_u8; + uint8_t* end = utf_decoder::decode_wchar_block(data, length, dest); + + return static_cast(end - dest); + } + + assert(!"Invalid encoding"); + return 0; + } +#else + PUGI__FN size_t get_valid_length(const char_t* data, size_t length) + { + assert(length > 4); + + for (size_t i = 1; i <= 4; ++i) + { + uint8_t ch = static_cast(data[length - i]); + + // either a standalone character or a leading one + if ((ch & 0xc0) != 0x80) return length - i; + } + + // there are four non-leading characters at the end, sequence tail is broken so might as well process the whole chunk + return length; + } + + PUGI__FN size_t convert_buffer(char_t* /* r_char */, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding) + { + if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) + { + uint16_t* dest = r_u16; + + // convert to native utf16 + uint16_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); + + // swap if necessary + xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); + + return static_cast(end - dest) * sizeof(uint16_t); + } + + if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) + { + uint32_t* dest = r_u32; + + // convert to native utf32 + uint32_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); + + // swap if necessary + xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); + + return static_cast(end - dest) * sizeof(uint32_t); + } + + if (encoding == encoding_latin1) + { + uint8_t* dest = r_u8; + uint8_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); + + return static_cast(end - dest); + } + + assert(!"Invalid encoding"); + return 0; + } +#endif + + class xml_buffered_writer + { + xml_buffered_writer(const xml_buffered_writer&); + xml_buffered_writer& operator=(const xml_buffered_writer&); + + public: + xml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding)) + { + PUGI__STATIC_ASSERT(bufcapacity >= 8); + } + + ~xml_buffered_writer() + { + flush(); + } + + void flush() + { + flush(buffer, bufsize); + bufsize = 0; + } + + void flush(const char_t* data, size_t size) + { + if (size == 0) return; + + // fast path, just write data + if (encoding == get_write_native_encoding()) + writer.write(data, size * sizeof(char_t)); + else + { + // convert chunk + size_t result = convert_buffer(scratch.data_char, scratch.data_u8, scratch.data_u16, scratch.data_u32, data, size, encoding); + assert(result <= sizeof(scratch)); + + // write data + writer.write(scratch.data_u8, result); + } + } + + void write(const char_t* data, size_t length) + { + if (bufsize + length > bufcapacity) + { + // flush the remaining buffer contents + flush(); + + // handle large chunks + if (length > bufcapacity) + { + if (encoding == get_write_native_encoding()) + { + // fast path, can just write data chunk + writer.write(data, length * sizeof(char_t)); + return; + } + + // need to convert in suitable chunks + while (length > bufcapacity) + { + // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer + // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary) + size_t chunk_size = get_valid_length(data, bufcapacity); + + // convert chunk and write + flush(data, chunk_size); + + // iterate + data += chunk_size; + length -= chunk_size; + } + + // small tail is copied below + bufsize = 0; + } + } + + memcpy(buffer + bufsize, data, length * sizeof(char_t)); + bufsize += length; + } + + void write(const char_t* data) + { + write(data, strlength(data)); + } + + void write(char_t d0) + { + if (bufsize + 1 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + bufsize += 1; + } + + void write(char_t d0, char_t d1) + { + if (bufsize + 2 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + bufsize += 2; + } + + void write(char_t d0, char_t d1, char_t d2) + { + if (bufsize + 3 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + buffer[bufsize + 2] = d2; + bufsize += 3; + } + + void write(char_t d0, char_t d1, char_t d2, char_t d3) + { + if (bufsize + 4 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + buffer[bufsize + 2] = d2; + buffer[bufsize + 3] = d3; + bufsize += 4; + } + + void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4) + { + if (bufsize + 5 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + buffer[bufsize + 2] = d2; + buffer[bufsize + 3] = d3; + buffer[bufsize + 4] = d4; + bufsize += 5; + } + + void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5) + { + if (bufsize + 6 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + buffer[bufsize + 2] = d2; + buffer[bufsize + 3] = d3; + buffer[bufsize + 4] = d4; + buffer[bufsize + 5] = d5; + bufsize += 6; + } + + // utf8 maximum expansion: x4 (-> utf32) + // utf16 maximum expansion: x2 (-> utf32) + // utf32 maximum expansion: x1 + enum + { + bufcapacitybytes = + #ifdef PUGIXML_MEMORY_OUTPUT_STACK + PUGIXML_MEMORY_OUTPUT_STACK + #else + 10240 + #endif + , + bufcapacity = bufcapacitybytes / (sizeof(char_t) + 4) + }; + + char_t buffer[bufcapacity]; + + union + { + uint8_t data_u8[4 * bufcapacity]; + uint16_t data_u16[2 * bufcapacity]; + uint32_t data_u32[bufcapacity]; + char_t data_char[bufcapacity]; + } scratch; + + xml_writer& writer; + size_t bufsize; + xml_encoding encoding; + }; + + PUGI__FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type) + { + while (*s) + { + const char_t* prev = s; + + // While *s is a usual symbol + while (!PUGI__IS_CHARTYPEX(*s, type)) ++s; + + writer.write(prev, static_cast(s - prev)); + + switch (*s) + { + case 0: break; + case '&': + writer.write('&', 'a', 'm', 'p', ';'); + ++s; + break; + case '<': + writer.write('&', 'l', 't', ';'); + ++s; + break; + case '>': + writer.write('&', 'g', 't', ';'); + ++s; + break; + case '"': + writer.write('&', 'q', 'u', 'o', 't', ';'); + ++s; + break; + default: // s is not a usual symbol + { + unsigned int ch = static_cast(*s++); + assert(ch < 32); + + writer.write('&', '#', static_cast((ch / 10) + '0'), static_cast((ch % 10) + '0'), ';'); + } + } + } + } + + PUGI__FN void text_output(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags) + { + if (flags & format_no_escapes) + writer.write(s); + else + text_output_escaped(writer, s, type); + } + + PUGI__FN void text_output_cdata(xml_buffered_writer& writer, const char_t* s) + { + do + { + writer.write('<', '!', '[', 'C', 'D'); + writer.write('A', 'T', 'A', '['); + + const char_t* prev = s; + + // look for ]]> sequence - we can't output it as is since it terminates CDATA + while (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>')) ++s; + + // skip ]] if we stopped at ]]>, > will go to the next CDATA section + if (*s) s += 2; + + writer.write(prev, static_cast(s - prev)); + + writer.write(']', ']', '>'); + } + while (*s); + } + + PUGI__FN void node_output_attributes(xml_buffered_writer& writer, const xml_node& node, unsigned int flags) + { + const char_t* default_name = PUGIXML_TEXT(":anonymous"); + + for (xml_attribute a = node.first_attribute(); a; a = a.next_attribute()) + { + writer.write(' '); + writer.write(a.name()[0] ? a.name() : default_name); + writer.write('=', '"'); + + text_output(writer, a.value(), ctx_special_attr, flags); + + writer.write('"'); + } + } + + PUGI__FN void node_output(xml_buffered_writer& writer, const xml_node& node, const char_t* indent, unsigned int flags, unsigned int depth) + { + const char_t* default_name = PUGIXML_TEXT(":anonymous"); + + if ((flags & format_indent) != 0 && (flags & format_raw) == 0) + for (unsigned int i = 0; i < depth; ++i) writer.write(indent); + + switch (node.type()) + { + case node_document: + { + for (xml_node n = node.first_child(); n; n = n.next_sibling()) + node_output(writer, n, indent, flags, depth); + break; + } + + case node_element: + { + const char_t* name = node.name()[0] ? node.name() : default_name; + + writer.write('<'); + writer.write(name); + + node_output_attributes(writer, node, flags); + + if (flags & format_raw) + { + if (!node.first_child()) + writer.write(' ', '/', '>'); + else + { + writer.write('>'); + + for (xml_node n = node.first_child(); n; n = n.next_sibling()) + node_output(writer, n, indent, flags, depth + 1); + + writer.write('<', '/'); + writer.write(name); + writer.write('>'); + } + } + else if (!node.first_child()) + writer.write(' ', '/', '>', '\n'); + else if (node.first_child() == node.last_child() && (node.first_child().type() == node_pcdata || node.first_child().type() == node_cdata)) + { + writer.write('>'); + + if (node.first_child().type() == node_pcdata) + text_output(writer, node.first_child().value(), ctx_special_pcdata, flags); + else + text_output_cdata(writer, node.first_child().value()); + + writer.write('<', '/'); + writer.write(name); + writer.write('>', '\n'); + } + else + { + writer.write('>', '\n'); + + for (xml_node n = node.first_child(); n; n = n.next_sibling()) + node_output(writer, n, indent, flags, depth + 1); + + if ((flags & format_indent) != 0 && (flags & format_raw) == 0) + for (unsigned int i = 0; i < depth; ++i) writer.write(indent); + + writer.write('<', '/'); + writer.write(name); + writer.write('>', '\n'); + } + + break; + } + + case node_pcdata: + text_output(writer, node.value(), ctx_special_pcdata, flags); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + case node_cdata: + text_output_cdata(writer, node.value()); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + case node_comment: + writer.write('<', '!', '-', '-'); + writer.write(node.value()); + writer.write('-', '-', '>'); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + case node_pi: + case node_declaration: + writer.write('<', '?'); + writer.write(node.name()[0] ? node.name() : default_name); + + if (node.type() == node_declaration) + { + node_output_attributes(writer, node, flags); + } + else if (node.value()[0]) + { + writer.write(' '); + writer.write(node.value()); + } + + writer.write('?', '>'); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + case node_doctype: + writer.write('<', '!', 'D', 'O', 'C'); + writer.write('T', 'Y', 'P', 'E'); + + if (node.value()[0]) + { + writer.write(' '); + writer.write(node.value()); + } + + writer.write('>'); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + default: + assert(!"Invalid node type"); + } + } + + inline bool has_declaration(const xml_node& node) + { + for (xml_node child = node.first_child(); child; child = child.next_sibling()) + { + xml_node_type type = child.type(); + + if (type == node_declaration) return true; + if (type == node_element) return false; + } + + return false; + } + + inline bool allow_insert_child(xml_node_type parent, xml_node_type child) + { + if (parent != node_document && parent != node_element) return false; + if (child == node_document || child == node_null) return false; + if (parent != node_document && (child == node_declaration || child == node_doctype)) return false; + + return true; + } + + PUGI__FN void recursive_copy_skip(xml_node& dest, const xml_node& source, const xml_node& skip) + { + assert(dest.type() == source.type()); + + switch (source.type()) + { + case node_element: + { + dest.set_name(source.name()); + + for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute()) + dest.append_attribute(a.name()).set_value(a.value()); + + for (xml_node c = source.first_child(); c; c = c.next_sibling()) + { + if (c == skip) continue; + + xml_node cc = dest.append_child(c.type()); + assert(cc); + + recursive_copy_skip(cc, c, skip); + } + + break; + } + + case node_pcdata: + case node_cdata: + case node_comment: + case node_doctype: + dest.set_value(source.value()); + break; + + case node_pi: + dest.set_name(source.name()); + dest.set_value(source.value()); + break; + + case node_declaration: + { + dest.set_name(source.name()); + + for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute()) + dest.append_attribute(a.name()).set_value(a.value()); + + break; + } + + default: + assert(!"Invalid node type"); + } + } + + inline bool is_text_node(xml_node_struct* node) + { + xml_node_type type = static_cast((node->header & impl::xml_memory_page_type_mask) + 1); + + return type == node_pcdata || type == node_cdata; + } + + // get value with conversion functions + PUGI__FN int get_value_int(const char_t* value, int def) + { + if (!value) return def; + + #ifdef PUGIXML_WCHAR_MODE + return static_cast(wcstol(value, 0, 10)); + #else + return static_cast(strtol(value, 0, 10)); + #endif + } + + PUGI__FN unsigned int get_value_uint(const char_t* value, unsigned int def) + { + if (!value) return def; + + #ifdef PUGIXML_WCHAR_MODE + return static_cast(wcstoul(value, 0, 10)); + #else + return static_cast(strtoul(value, 0, 10)); + #endif + } + + PUGI__FN double get_value_double(const char_t* value, double def) + { + if (!value) return def; + + #ifdef PUGIXML_WCHAR_MODE + return wcstod(value, 0); + #else + return strtod(value, 0); + #endif + } + + PUGI__FN float get_value_float(const char_t* value, float def) + { + if (!value) return def; + + #ifdef PUGIXML_WCHAR_MODE + return static_cast(wcstod(value, 0)); + #else + return static_cast(strtod(value, 0)); + #endif + } + + PUGI__FN bool get_value_bool(const char_t* value, bool def) + { + if (!value) return def; + + // only look at first char + char_t first = *value; + + // 1*, t* (true), T* (True), y* (yes), Y* (YES) + return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y'); + } + + // set value with conversion functions + PUGI__FN bool set_value_buffer(char_t*& dest, uintptr_t& header, uintptr_t header_mask, char (&buf)[128]) + { + #ifdef PUGIXML_WCHAR_MODE + char_t wbuf[128]; + impl::widen_ascii(wbuf, buf); + + return strcpy_insitu(dest, header, header_mask, wbuf); + #else + return strcpy_insitu(dest, header, header_mask, buf); + #endif + } + + PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, int value) + { + char buf[128]; + sprintf(buf, "%d", value); + + return set_value_buffer(dest, header, header_mask, buf); + } + + PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, unsigned int value) + { + char buf[128]; + sprintf(buf, "%u", value); + + return set_value_buffer(dest, header, header_mask, buf); + } + + PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, double value) + { + char buf[128]; + sprintf(buf, "%g", value); + + return set_value_buffer(dest, header, header_mask, buf); + } + + PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, bool value) + { + return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); + } + + // we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick + PUGI__FN xml_parse_status get_file_size(FILE* file, size_t& out_result) + { + #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE) + // there are 64-bit versions of fseek/ftell, let's use them + typedef __int64 length_type; + + _fseeki64(file, 0, SEEK_END); + length_type length = _ftelli64(file); + _fseeki64(file, 0, SEEK_SET); + #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && !defined(__STRICT_ANSI__) + // there are 64-bit versions of fseek/ftell, let's use them + typedef off64_t length_type; + + fseeko64(file, 0, SEEK_END); + length_type length = ftello64(file); + fseeko64(file, 0, SEEK_SET); + #else + // if this is a 32-bit OS, long is enough; if this is a unix system, long is 64-bit, which is enough; otherwise we can't do anything anyway. + typedef long length_type; + + fseek(file, 0, SEEK_END); + length_type length = ftell(file); + fseek(file, 0, SEEK_SET); + #endif + + // check for I/O errors + if (length < 0) return status_io_error; + + // check for overflow + size_t result = static_cast(length); + + if (static_cast(result) != length) return status_out_of_memory; + + // finalize + out_result = result; + + return status_ok; + } + + PUGI__FN xml_parse_result load_file_impl(xml_document& doc, FILE* file, unsigned int options, xml_encoding encoding) + { + if (!file) return make_parse_result(status_file_not_found); + + // get file size (can result in I/O errors) + size_t size = 0; + xml_parse_status size_status = get_file_size(file, size); + + if (size_status != status_ok) + { + fclose(file); + return make_parse_result(size_status); + } + + // allocate buffer for the whole file + char* contents = static_cast(xml_memory::allocate(size > 0 ? size : 1)); + + if (!contents) + { + fclose(file); + return make_parse_result(status_out_of_memory); + } + + // read file in memory + size_t read_size = fread(contents, 1, size, file); + fclose(file); + + if (read_size != size) + { + xml_memory::deallocate(contents); + return make_parse_result(status_io_error); + } + + return doc.load_buffer_inplace_own(contents, size, options, encoding); + } + +#ifndef PUGIXML_NO_STL + template struct xml_stream_chunk + { + static xml_stream_chunk* create() + { + void* memory = xml_memory::allocate(sizeof(xml_stream_chunk)); + + return new (memory) xml_stream_chunk(); + } + + static void destroy(void* ptr) + { + xml_stream_chunk* chunk = static_cast(ptr); + + // free chunk chain + while (chunk) + { + xml_stream_chunk* next = chunk->next; + xml_memory::deallocate(chunk); + chunk = next; + } + } + + xml_stream_chunk(): next(0), size(0) + { + } + + xml_stream_chunk* next; + size_t size; + + T data[xml_memory_page_size / sizeof(T)]; + }; + + template PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream& stream, void** out_buffer, size_t* out_size) + { + buffer_holder chunks(0, xml_stream_chunk::destroy); + + // read file to a chunk list + size_t total = 0; + xml_stream_chunk* last = 0; + + while (!stream.eof()) + { + // allocate new chunk + xml_stream_chunk* chunk = xml_stream_chunk::create(); + if (!chunk) return status_out_of_memory; + + // append chunk to list + if (last) last = last->next = chunk; + else chunks.data = last = chunk; + + // read data to chunk + stream.read(chunk->data, static_cast(sizeof(chunk->data) / sizeof(T))); + chunk->size = static_cast(stream.gcount()) * sizeof(T); + + // read may set failbit | eofbit in case gcount() is less than read length, so check for other I/O errors + if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error; + + // guard against huge files (chunk size is small enough to make this overflow check work) + if (total + chunk->size < total) return status_out_of_memory; + total += chunk->size; + } + + // copy chunk list to a contiguous buffer + char* buffer = static_cast(xml_memory::allocate(total)); + if (!buffer) return status_out_of_memory; + + char* write = buffer; + + for (xml_stream_chunk* chunk = static_cast*>(chunks.data); chunk; chunk = chunk->next) + { + assert(write + chunk->size <= buffer + total); + memcpy(write, chunk->data, chunk->size); + write += chunk->size; + } + + assert(write == buffer + total); + + // return buffer + *out_buffer = buffer; + *out_size = total; + + return status_ok; + } + + template PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream& stream, void** out_buffer, size_t* out_size) + { + // get length of remaining data in stream + typename std::basic_istream::pos_type pos = stream.tellg(); + stream.seekg(0, std::ios::end); + std::streamoff length = stream.tellg() - pos; + stream.seekg(pos); + + if (stream.fail() || pos < 0) return status_io_error; + + // guard against huge files + size_t read_length = static_cast(length); + + if (static_cast(read_length) != length || length < 0) return status_out_of_memory; + + // read stream data into memory (guard against stream exceptions with buffer holder) + buffer_holder buffer(xml_memory::allocate((read_length > 0 ? read_length : 1) * sizeof(T)), xml_memory::deallocate); + if (!buffer.data) return status_out_of_memory; + + stream.read(static_cast(buffer.data), static_cast(read_length)); + + // read may set failbit | eofbit in case gcount() is less than read_length (i.e. line ending conversion), so check for other I/O errors + if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error; + + // return buffer + size_t actual_length = static_cast(stream.gcount()); + assert(actual_length <= read_length); + + *out_buffer = buffer.release(); + *out_size = actual_length * sizeof(T); + + return status_ok; + } + + template PUGI__FN xml_parse_result load_stream_impl(xml_document& doc, std::basic_istream& stream, unsigned int options, xml_encoding encoding) + { + void* buffer = 0; + size_t size = 0; + + // load stream to memory (using seek-based implementation if possible, since it's faster and takes less memory) + xml_parse_status status = (stream.tellg() < 0) ? load_stream_data_noseek(stream, &buffer, &size) : load_stream_data_seek(stream, &buffer, &size); + if (status != status_ok) return make_parse_result(status); + + return doc.load_buffer_inplace_own(buffer, size, options, encoding); + } +#endif + +#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && !defined(__STRICT_ANSI__)) + PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) + { + return _wfopen(path, mode); + } +#else + PUGI__FN char* convert_path_heap(const wchar_t* str) + { + assert(str); + + // first pass: get length in utf8 characters + size_t length = wcslen(str); + size_t size = as_utf8_begin(str, length); + + // allocate resulting string + char* result = static_cast(xml_memory::allocate(size + 1)); + if (!result) return 0; + + // second pass: convert to utf8 + as_utf8_end(result, size, str, length); + + return result; + } + + PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) + { + // there is no standard function to open wide paths, so our best bet is to try utf8 path + char* path_utf8 = convert_path_heap(path); + if (!path_utf8) return 0; + + // convert mode to ASCII (we mirror _wfopen interface) + char mode_ascii[4] = {0}; + for (size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast(mode[i]); + + // try to open the utf8 path + FILE* result = fopen(path_utf8, mode_ascii); + + // free dummy buffer + xml_memory::deallocate(path_utf8); + + return result; + } +#endif + + PUGI__FN bool save_file_impl(const xml_document& doc, FILE* file, const char_t* indent, unsigned int flags, xml_encoding encoding) + { + if (!file) return false; + + xml_writer_file writer(file); + doc.save(writer, indent, flags, encoding); + + int result = ferror(file); + + fclose(file); + + return result == 0; + } +PUGI__NS_END + +namespace pugi +{ + PUGI__FN xml_writer_file::xml_writer_file(void* file_): file(file_) + { + } + + PUGI__FN void xml_writer_file::write(const void* data, size_t size) + { + size_t result = fwrite(data, 1, size, static_cast(file)); + (void)!result; // unfortunately we can't do proper error handling here + } + +#ifndef PUGIXML_NO_STL + PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream >& stream): narrow_stream(&stream), wide_stream(0) + { + } + + PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream >& stream): narrow_stream(0), wide_stream(&stream) + { + } + + PUGI__FN void xml_writer_stream::write(const void* data, size_t size) + { + if (narrow_stream) + { + assert(!wide_stream); + narrow_stream->write(reinterpret_cast(data), static_cast(size)); + } + else + { + assert(wide_stream); + assert(size % sizeof(wchar_t) == 0); + + wide_stream->write(reinterpret_cast(data), static_cast(size / sizeof(wchar_t))); + } + } +#endif + + PUGI__FN xml_tree_walker::xml_tree_walker(): _depth(0) + { + } + + PUGI__FN xml_tree_walker::~xml_tree_walker() + { + } + + PUGI__FN int xml_tree_walker::depth() const + { + return _depth; + } + + PUGI__FN bool xml_tree_walker::begin(xml_node&) + { + return true; + } + + PUGI__FN bool xml_tree_walker::end(xml_node&) + { + return true; + } + + PUGI__FN xml_attribute::xml_attribute(): _attr(0) + { + } + + PUGI__FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr) + { + } + + PUGI__FN static void unspecified_bool_xml_attribute(xml_attribute***) + { + } + + PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type() const + { + return _attr ? unspecified_bool_xml_attribute : 0; + } + + PUGI__FN bool xml_attribute::operator!() const + { + return !_attr; + } + + PUGI__FN bool xml_attribute::operator==(const xml_attribute& r) const + { + return (_attr == r._attr); + } + + PUGI__FN bool xml_attribute::operator!=(const xml_attribute& r) const + { + return (_attr != r._attr); + } + + PUGI__FN bool xml_attribute::operator<(const xml_attribute& r) const + { + return (_attr < r._attr); + } + + PUGI__FN bool xml_attribute::operator>(const xml_attribute& r) const + { + return (_attr > r._attr); + } + + PUGI__FN bool xml_attribute::operator<=(const xml_attribute& r) const + { + return (_attr <= r._attr); + } + + PUGI__FN bool xml_attribute::operator>=(const xml_attribute& r) const + { + return (_attr >= r._attr); + } + + PUGI__FN xml_attribute xml_attribute::next_attribute() const + { + return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute(); + } + + PUGI__FN xml_attribute xml_attribute::previous_attribute() const + { + return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute(); + } + + PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const + { + return (_attr && _attr->value) ? _attr->value : def; + } + + PUGI__FN int xml_attribute::as_int(int def) const + { + return impl::get_value_int(_attr ? _attr->value : 0, def); + } + + PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const + { + return impl::get_value_uint(_attr ? _attr->value : 0, def); + } + + PUGI__FN double xml_attribute::as_double(double def) const + { + return impl::get_value_double(_attr ? _attr->value : 0, def); + } + + PUGI__FN float xml_attribute::as_float(float def) const + { + return impl::get_value_float(_attr ? _attr->value : 0, def); + } + + PUGI__FN bool xml_attribute::as_bool(bool def) const + { + return impl::get_value_bool(_attr ? _attr->value : 0, def); + } + + PUGI__FN bool xml_attribute::empty() const + { + return !_attr; + } + + PUGI__FN const char_t* xml_attribute::name() const + { + return (_attr && _attr->name) ? _attr->name : PUGIXML_TEXT(""); + } + + PUGI__FN const char_t* xml_attribute::value() const + { + return (_attr && _attr->value) ? _attr->value : PUGIXML_TEXT(""); + } + + PUGI__FN size_t xml_attribute::hash_value() const + { + return static_cast(reinterpret_cast(_attr) / sizeof(xml_attribute_struct)); + } + + PUGI__FN xml_attribute_struct* xml_attribute::internal_object() const + { + return _attr; + } + + PUGI__FN xml_attribute& xml_attribute::operator=(const char_t* rhs) + { + set_value(rhs); + return *this; + } + + PUGI__FN xml_attribute& xml_attribute::operator=(int rhs) + { + set_value(rhs); + return *this; + } + + PUGI__FN xml_attribute& xml_attribute::operator=(unsigned int rhs) + { + set_value(rhs); + return *this; + } + + PUGI__FN xml_attribute& xml_attribute::operator=(double rhs) + { + set_value(rhs); + return *this; + } + + PUGI__FN xml_attribute& xml_attribute::operator=(bool rhs) + { + set_value(rhs); + return *this; + } + + PUGI__FN bool xml_attribute::set_name(const char_t* rhs) + { + if (!_attr) return false; + + return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs); + } + + PUGI__FN bool xml_attribute::set_value(const char_t* rhs) + { + if (!_attr) return false; + + return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + } + + PUGI__FN bool xml_attribute::set_value(int rhs) + { + if (!_attr) return false; + + return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + } + + PUGI__FN bool xml_attribute::set_value(unsigned int rhs) + { + if (!_attr) return false; + + return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + } + + PUGI__FN bool xml_attribute::set_value(double rhs) + { + if (!_attr) return false; + + return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + } + + PUGI__FN bool xml_attribute::set_value(bool rhs) + { + if (!_attr) return false; + + return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + } + +#ifdef __BORLANDC__ + PUGI__FN bool operator&&(const xml_attribute& lhs, bool rhs) + { + return (bool)lhs && rhs; + } + + PUGI__FN bool operator||(const xml_attribute& lhs, bool rhs) + { + return (bool)lhs || rhs; + } +#endif + + PUGI__FN xml_node::xml_node(): _root(0) + { + } + + PUGI__FN xml_node::xml_node(xml_node_struct* p): _root(p) + { + } + + PUGI__FN static void unspecified_bool_xml_node(xml_node***) + { + } + + PUGI__FN xml_node::operator xml_node::unspecified_bool_type() const + { + return _root ? unspecified_bool_xml_node : 0; + } + + PUGI__FN bool xml_node::operator!() const + { + return !_root; + } + + PUGI__FN xml_node::iterator xml_node::begin() const + { + return iterator(_root ? _root->first_child : 0, _root); + } + + PUGI__FN xml_node::iterator xml_node::end() const + { + return iterator(0, _root); + } + + PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin() const + { + return attribute_iterator(_root ? _root->first_attribute : 0, _root); + } + + PUGI__FN xml_node::attribute_iterator xml_node::attributes_end() const + { + return attribute_iterator(0, _root); + } + + PUGI__FN xml_object_range xml_node::children() const + { + return xml_object_range(begin(), end()); + } + + PUGI__FN xml_object_range xml_node::children(const char_t* name_) const + { + return xml_object_range(xml_named_node_iterator(child(name_), name_), xml_named_node_iterator()); + } + + PUGI__FN xml_object_range xml_node::attributes() const + { + return xml_object_range(attributes_begin(), attributes_end()); + } + + PUGI__FN bool xml_node::operator==(const xml_node& r) const + { + return (_root == r._root); + } + + PUGI__FN bool xml_node::operator!=(const xml_node& r) const + { + return (_root != r._root); + } + + PUGI__FN bool xml_node::operator<(const xml_node& r) const + { + return (_root < r._root); + } + + PUGI__FN bool xml_node::operator>(const xml_node& r) const + { + return (_root > r._root); + } + + PUGI__FN bool xml_node::operator<=(const xml_node& r) const + { + return (_root <= r._root); + } + + PUGI__FN bool xml_node::operator>=(const xml_node& r) const + { + return (_root >= r._root); + } + + PUGI__FN bool xml_node::empty() const + { + return !_root; + } + + PUGI__FN const char_t* xml_node::name() const + { + return (_root && _root->name) ? _root->name : PUGIXML_TEXT(""); + } + + PUGI__FN xml_node_type xml_node::type() const + { + return _root ? static_cast((_root->header & impl::xml_memory_page_type_mask) + 1) : node_null; + } + + PUGI__FN const char_t* xml_node::value() const + { + return (_root && _root->value) ? _root->value : PUGIXML_TEXT(""); + } + + PUGI__FN xml_node xml_node::child(const char_t* name_) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + if (i->name && impl::strequal(name_, i->name)) return xml_node(i); + + return xml_node(); + } + + PUGI__FN xml_attribute xml_node::attribute(const char_t* name_) const + { + if (!_root) return xml_attribute(); + + for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) + if (i->name && impl::strequal(name_, i->name)) + return xml_attribute(i); + + return xml_attribute(); + } + + PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) + if (i->name && impl::strequal(name_, i->name)) return xml_node(i); + + return xml_node(); + } + + PUGI__FN xml_node xml_node::next_sibling() const + { + if (!_root) return xml_node(); + + if (_root->next_sibling) return xml_node(_root->next_sibling); + else return xml_node(); + } + + PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) + if (i->name && impl::strequal(name_, i->name)) return xml_node(i); + + return xml_node(); + } + + PUGI__FN xml_node xml_node::previous_sibling() const + { + if (!_root) return xml_node(); + + if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c); + else return xml_node(); + } + + PUGI__FN xml_node xml_node::parent() const + { + return _root ? xml_node(_root->parent) : xml_node(); + } + + PUGI__FN xml_node xml_node::root() const + { + if (!_root) return xml_node(); + + impl::xml_memory_page* page = reinterpret_cast(_root->header & impl::xml_memory_page_pointer_mask); + + return xml_node(static_cast(page->allocator)); + } + + PUGI__FN xml_text xml_node::text() const + { + return xml_text(_root); + } + + PUGI__FN const char_t* xml_node::child_value() const + { + if (!_root) return PUGIXML_TEXT(""); + + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + if (i->value && impl::is_text_node(i)) + return i->value; + + return PUGIXML_TEXT(""); + } + + PUGI__FN const char_t* xml_node::child_value(const char_t* name_) const + { + return child(name_).child_value(); + } + + PUGI__FN xml_attribute xml_node::first_attribute() const + { + return _root ? xml_attribute(_root->first_attribute) : xml_attribute(); + } + + PUGI__FN xml_attribute xml_node::last_attribute() const + { + return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute(); + } + + PUGI__FN xml_node xml_node::first_child() const + { + return _root ? xml_node(_root->first_child) : xml_node(); + } + + PUGI__FN xml_node xml_node::last_child() const + { + return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node(); + } + + PUGI__FN bool xml_node::set_name(const char_t* rhs) + { + switch (type()) + { + case node_pi: + case node_declaration: + case node_element: + return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs); + + default: + return false; + } + } + + PUGI__FN bool xml_node::set_value(const char_t* rhs) + { + switch (type()) + { + case node_pi: + case node_cdata: + case node_pcdata: + case node_comment: + case node_doctype: + return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs); + + default: + return false; + } + } + + PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_) + { + if (type() != node_element && type() != node_declaration) return xml_attribute(); + + xml_attribute a(impl::append_attribute_ll(_root, impl::get_allocator(_root))); + a.set_name(name_); + + return a; + } + + PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_) + { + if (type() != node_element && type() != node_declaration) return xml_attribute(); + + xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root))); + if (!a) return xml_attribute(); + + a.set_name(name_); + + xml_attribute_struct* head = _root->first_attribute; + + if (head) + { + a._attr->prev_attribute_c = head->prev_attribute_c; + head->prev_attribute_c = a._attr; + } + else + a._attr->prev_attribute_c = a._attr; + + a._attr->next_attribute = head; + _root->first_attribute = a._attr; + + return a; + } + + PUGI__FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr) + { + if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute(); + + // check that attribute belongs to *this + xml_attribute_struct* cur = attr._attr; + + while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c; + + if (cur != _root->first_attribute) return xml_attribute(); + + xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root))); + if (!a) return xml_attribute(); + + a.set_name(name_); + + if (attr._attr->prev_attribute_c->next_attribute) + attr._attr->prev_attribute_c->next_attribute = a._attr; + else + _root->first_attribute = a._attr; + + a._attr->prev_attribute_c = attr._attr->prev_attribute_c; + a._attr->next_attribute = attr._attr; + attr._attr->prev_attribute_c = a._attr; + + return a; + } + + PUGI__FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr) + { + if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute(); + + // check that attribute belongs to *this + xml_attribute_struct* cur = attr._attr; + + while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c; + + if (cur != _root->first_attribute) return xml_attribute(); + + xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root))); + if (!a) return xml_attribute(); + + a.set_name(name_); + + if (attr._attr->next_attribute) + attr._attr->next_attribute->prev_attribute_c = a._attr; + else + _root->first_attribute->prev_attribute_c = a._attr; + + a._attr->next_attribute = attr._attr->next_attribute; + a._attr->prev_attribute_c = attr._attr; + attr._attr->next_attribute = a._attr; + + return a; + } + + PUGI__FN xml_attribute xml_node::append_copy(const xml_attribute& proto) + { + if (!proto) return xml_attribute(); + + xml_attribute result = append_attribute(proto.name()); + result.set_value(proto.value()); + + return result; + } + + PUGI__FN xml_attribute xml_node::prepend_copy(const xml_attribute& proto) + { + if (!proto) return xml_attribute(); + + xml_attribute result = prepend_attribute(proto.name()); + result.set_value(proto.value()); + + return result; + } + + PUGI__FN xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr) + { + if (!proto) return xml_attribute(); + + xml_attribute result = insert_attribute_after(proto.name(), attr); + result.set_value(proto.value()); + + return result; + } + + PUGI__FN xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr) + { + if (!proto) return xml_attribute(); + + xml_attribute result = insert_attribute_before(proto.name(), attr); + result.set_value(proto.value()); + + return result; + } + + PUGI__FN xml_node xml_node::append_child(xml_node_type type_) + { + if (!impl::allow_insert_child(this->type(), type_)) return xml_node(); + + xml_node n(impl::append_node(_root, impl::get_allocator(_root), type_)); + + if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + + return n; + } + + PUGI__FN xml_node xml_node::prepend_child(xml_node_type type_) + { + if (!impl::allow_insert_child(this->type(), type_)) return xml_node(); + + xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); + if (!n) return xml_node(); + + n._root->parent = _root; + + xml_node_struct* head = _root->first_child; + + if (head) + { + n._root->prev_sibling_c = head->prev_sibling_c; + head->prev_sibling_c = n._root; + } + else + n._root->prev_sibling_c = n._root; + + n._root->next_sibling = head; + _root->first_child = n._root; + + if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + + return n; + } + + PUGI__FN xml_node xml_node::insert_child_before(xml_node_type type_, const xml_node& node) + { + if (!impl::allow_insert_child(this->type(), type_)) return xml_node(); + if (!node._root || node._root->parent != _root) return xml_node(); + + xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); + if (!n) return xml_node(); + + n._root->parent = _root; + + if (node._root->prev_sibling_c->next_sibling) + node._root->prev_sibling_c->next_sibling = n._root; + else + _root->first_child = n._root; + + n._root->prev_sibling_c = node._root->prev_sibling_c; + n._root->next_sibling = node._root; + node._root->prev_sibling_c = n._root; + + if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + + return n; + } + + PUGI__FN xml_node xml_node::insert_child_after(xml_node_type type_, const xml_node& node) + { + if (!impl::allow_insert_child(this->type(), type_)) return xml_node(); + if (!node._root || node._root->parent != _root) return xml_node(); + + xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); + if (!n) return xml_node(); + + n._root->parent = _root; + + if (node._root->next_sibling) + node._root->next_sibling->prev_sibling_c = n._root; + else + _root->first_child->prev_sibling_c = n._root; + + n._root->next_sibling = node._root->next_sibling; + n._root->prev_sibling_c = node._root; + node._root->next_sibling = n._root; + + if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + + return n; + } + + PUGI__FN xml_node xml_node::append_child(const char_t* name_) + { + xml_node result = append_child(node_element); + + result.set_name(name_); + + return result; + } + + PUGI__FN xml_node xml_node::prepend_child(const char_t* name_) + { + xml_node result = prepend_child(node_element); + + result.set_name(name_); + + return result; + } + + PUGI__FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node) + { + xml_node result = insert_child_after(node_element, node); + + result.set_name(name_); + + return result; + } + + PUGI__FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node) + { + xml_node result = insert_child_before(node_element, node); + + result.set_name(name_); + + return result; + } + + PUGI__FN xml_node xml_node::append_copy(const xml_node& proto) + { + xml_node result = append_child(proto.type()); + + if (result) impl::recursive_copy_skip(result, proto, result); + + return result; + } + + PUGI__FN xml_node xml_node::prepend_copy(const xml_node& proto) + { + xml_node result = prepend_child(proto.type()); + + if (result) impl::recursive_copy_skip(result, proto, result); + + return result; + } + + PUGI__FN xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node) + { + xml_node result = insert_child_after(proto.type(), node); + + if (result) impl::recursive_copy_skip(result, proto, result); + + return result; + } + + PUGI__FN xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node) + { + xml_node result = insert_child_before(proto.type(), node); + + if (result) impl::recursive_copy_skip(result, proto, result); + + return result; + } + + PUGI__FN bool xml_node::remove_attribute(const char_t* name_) + { + return remove_attribute(attribute(name_)); + } + + PUGI__FN bool xml_node::remove_attribute(const xml_attribute& a) + { + if (!_root || !a._attr) return false; + + // check that attribute belongs to *this + xml_attribute_struct* attr = a._attr; + + while (attr->prev_attribute_c->next_attribute) attr = attr->prev_attribute_c; + + if (attr != _root->first_attribute) return false; + + if (a._attr->next_attribute) a._attr->next_attribute->prev_attribute_c = a._attr->prev_attribute_c; + else if (_root->first_attribute) _root->first_attribute->prev_attribute_c = a._attr->prev_attribute_c; + + if (a._attr->prev_attribute_c->next_attribute) a._attr->prev_attribute_c->next_attribute = a._attr->next_attribute; + else _root->first_attribute = a._attr->next_attribute; + + impl::destroy_attribute(a._attr, impl::get_allocator(_root)); + + return true; + } + + PUGI__FN bool xml_node::remove_child(const char_t* name_) + { + return remove_child(child(name_)); + } + + PUGI__FN bool xml_node::remove_child(const xml_node& n) + { + if (!_root || !n._root || n._root->parent != _root) return false; + + if (n._root->next_sibling) n._root->next_sibling->prev_sibling_c = n._root->prev_sibling_c; + else if (_root->first_child) _root->first_child->prev_sibling_c = n._root->prev_sibling_c; + + if (n._root->prev_sibling_c->next_sibling) n._root->prev_sibling_c->next_sibling = n._root->next_sibling; + else _root->first_child = n._root->next_sibling; + + impl::destroy_node(n._root, impl::get_allocator(_root)); + + return true; + } + + PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + if (i->name && impl::strequal(name_, i->name)) + { + for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) + if (impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value)) + return xml_node(i); + } + + return xml_node(); + } + + PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) + if (impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value)) + return xml_node(i); + + return xml_node(); + } + +#ifndef PUGIXML_NO_STL + PUGI__FN string_t xml_node::path(char_t delimiter) const + { + xml_node cursor = *this; // Make a copy. + + string_t result = cursor.name(); + + while (cursor.parent()) + { + cursor = cursor.parent(); + + string_t temp = cursor.name(); + temp += delimiter; + temp += result; + result.swap(temp); + } + + return result; + } +#endif + + PUGI__FN xml_node xml_node::first_element_by_path(const char_t* path_, char_t delimiter) const + { + xml_node found = *this; // Current search context. + + if (!_root || !path_ || !path_[0]) return found; + + if (path_[0] == delimiter) + { + // Absolute path; e.g. '/foo/bar' + found = found.root(); + ++path_; + } + + const char_t* path_segment = path_; + + while (*path_segment == delimiter) ++path_segment; + + const char_t* path_segment_end = path_segment; + + while (*path_segment_end && *path_segment_end != delimiter) ++path_segment_end; + + if (path_segment == path_segment_end) return found; + + const char_t* next_segment = path_segment_end; + + while (*next_segment == delimiter) ++next_segment; + + if (*path_segment == '.' && path_segment + 1 == path_segment_end) + return found.first_element_by_path(next_segment, delimiter); + else if (*path_segment == '.' && *(path_segment+1) == '.' && path_segment + 2 == path_segment_end) + return found.parent().first_element_by_path(next_segment, delimiter); + else + { + for (xml_node_struct* j = found._root->first_child; j; j = j->next_sibling) + { + if (j->name && impl::strequalrange(j->name, path_segment, static_cast(path_segment_end - path_segment))) + { + xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter); + + if (subsearch) return subsearch; + } + } + + return xml_node(); + } + } + + PUGI__FN bool xml_node::traverse(xml_tree_walker& walker) + { + walker._depth = -1; + + xml_node arg_begin = *this; + if (!walker.begin(arg_begin)) return false; + + xml_node cur = first_child(); + + if (cur) + { + ++walker._depth; + + do + { + xml_node arg_for_each = cur; + if (!walker.for_each(arg_for_each)) + return false; + + if (cur.first_child()) + { + ++walker._depth; + cur = cur.first_child(); + } + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + // Borland C++ workaround + while (!cur.next_sibling() && cur != *this && !cur.parent().empty()) + { + --walker._depth; + cur = cur.parent(); + } + + if (cur != *this) + cur = cur.next_sibling(); + } + } + while (cur && cur != *this); + } + + assert(walker._depth == -1); + + xml_node arg_end = *this; + return walker.end(arg_end); + } + + PUGI__FN size_t xml_node::hash_value() const + { + return static_cast(reinterpret_cast(_root) / sizeof(xml_node_struct)); + } + + PUGI__FN xml_node_struct* xml_node::internal_object() const + { + return _root; + } + + PUGI__FN void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const + { + if (!_root) return; + + impl::xml_buffered_writer buffered_writer(writer, encoding); + + impl::node_output(buffered_writer, *this, indent, flags, depth); + } + +#ifndef PUGIXML_NO_STL + PUGI__FN void xml_node::print(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const + { + xml_writer_stream writer(stream); + + print(writer, indent, flags, encoding, depth); + } + + PUGI__FN void xml_node::print(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, unsigned int depth) const + { + xml_writer_stream writer(stream); + + print(writer, indent, flags, encoding_wchar, depth); + } +#endif + + PUGI__FN ptrdiff_t xml_node::offset_debug() const + { + xml_node_struct* r = root()._root; + + if (!r) return -1; + + const char_t* buffer = static_cast(r)->buffer; + + if (!buffer) return -1; + + switch (type()) + { + case node_document: + return 0; + + case node_element: + case node_declaration: + case node_pi: + return (_root->header & impl::xml_memory_page_name_allocated_mask) ? -1 : _root->name - buffer; + + case node_pcdata: + case node_cdata: + case node_comment: + case node_doctype: + return (_root->header & impl::xml_memory_page_value_allocated_mask) ? -1 : _root->value - buffer; + + default: + return -1; + } + } + +#ifdef __BORLANDC__ + PUGI__FN bool operator&&(const xml_node& lhs, bool rhs) + { + return (bool)lhs && rhs; + } + + PUGI__FN bool operator||(const xml_node& lhs, bool rhs) + { + return (bool)lhs || rhs; + } +#endif + + PUGI__FN xml_text::xml_text(xml_node_struct* root): _root(root) + { + } + + PUGI__FN xml_node_struct* xml_text::_data() const + { + if (!_root || impl::is_text_node(_root)) return _root; + + for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling) + if (impl::is_text_node(node)) + return node; + + return 0; + } + + PUGI__FN xml_node_struct* xml_text::_data_new() + { + xml_node_struct* d = _data(); + if (d) return d; + + return xml_node(_root).append_child(node_pcdata).internal_object(); + } + + PUGI__FN xml_text::xml_text(): _root(0) + { + } + + PUGI__FN static void unspecified_bool_xml_text(xml_text***) + { + } + + PUGI__FN xml_text::operator xml_text::unspecified_bool_type() const + { + return _data() ? unspecified_bool_xml_text : 0; + } + + PUGI__FN bool xml_text::operator!() const + { + return !_data(); + } + + PUGI__FN bool xml_text::empty() const + { + return _data() == 0; + } + + PUGI__FN const char_t* xml_text::get() const + { + xml_node_struct* d = _data(); + + return (d && d->value) ? d->value : PUGIXML_TEXT(""); + } + + PUGI__FN const char_t* xml_text::as_string(const char_t* def) const + { + xml_node_struct* d = _data(); + + return (d && d->value) ? d->value : def; + } + + PUGI__FN int xml_text::as_int(int def) const + { + xml_node_struct* d = _data(); + + return impl::get_value_int(d ? d->value : 0, def); + } + + PUGI__FN unsigned int xml_text::as_uint(unsigned int def) const + { + xml_node_struct* d = _data(); + + return impl::get_value_uint(d ? d->value : 0, def); + } + + PUGI__FN double xml_text::as_double(double def) const + { + xml_node_struct* d = _data(); + + return impl::get_value_double(d ? d->value : 0, def); + } + + PUGI__FN float xml_text::as_float(float def) const + { + xml_node_struct* d = _data(); + + return impl::get_value_float(d ? d->value : 0, def); + } + + PUGI__FN bool xml_text::as_bool(bool def) const + { + xml_node_struct* d = _data(); + + return impl::get_value_bool(d ? d->value : 0, def); + } + + PUGI__FN bool xml_text::set(const char_t* rhs) + { + xml_node_struct* dn = _data_new(); + + return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + } + + PUGI__FN bool xml_text::set(int rhs) + { + xml_node_struct* dn = _data_new(); + + return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + } + + PUGI__FN bool xml_text::set(unsigned int rhs) + { + xml_node_struct* dn = _data_new(); + + return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + } + + PUGI__FN bool xml_text::set(double rhs) + { + xml_node_struct* dn = _data_new(); + + return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + } + + PUGI__FN bool xml_text::set(bool rhs) + { + xml_node_struct* dn = _data_new(); + + return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + } + + PUGI__FN xml_text& xml_text::operator=(const char_t* rhs) + { + set(rhs); + return *this; + } + + PUGI__FN xml_text& xml_text::operator=(int rhs) + { + set(rhs); + return *this; + } + + PUGI__FN xml_text& xml_text::operator=(unsigned int rhs) + { + set(rhs); + return *this; + } + + PUGI__FN xml_text& xml_text::operator=(double rhs) + { + set(rhs); + return *this; + } + + PUGI__FN xml_text& xml_text::operator=(bool rhs) + { + set(rhs); + return *this; + } + + PUGI__FN xml_node xml_text::data() const + { + return xml_node(_data()); + } + +#ifdef __BORLANDC__ + PUGI__FN bool operator&&(const xml_text& lhs, bool rhs) + { + return (bool)lhs && rhs; + } + + PUGI__FN bool operator||(const xml_text& lhs, bool rhs) + { + return (bool)lhs || rhs; + } +#endif + + PUGI__FN xml_node_iterator::xml_node_iterator() + { + } + + PUGI__FN xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent()) + { + } + + PUGI__FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) + { + } + + PUGI__FN bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const + { + return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; + } + + PUGI__FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const + { + return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; + } + + PUGI__FN xml_node& xml_node_iterator::operator*() const + { + assert(_wrap._root); + return _wrap; + } + + PUGI__FN xml_node* xml_node_iterator::operator->() const + { + assert(_wrap._root); + return const_cast(&_wrap); // BCC32 workaround + } + + PUGI__FN const xml_node_iterator& xml_node_iterator::operator++() + { + assert(_wrap._root); + _wrap._root = _wrap._root->next_sibling; + return *this; + } + + PUGI__FN xml_node_iterator xml_node_iterator::operator++(int) + { + xml_node_iterator temp = *this; + ++*this; + return temp; + } + + PUGI__FN const xml_node_iterator& xml_node_iterator::operator--() + { + _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child(); + return *this; + } + + PUGI__FN xml_node_iterator xml_node_iterator::operator--(int) + { + xml_node_iterator temp = *this; + --*this; + return temp; + } + + PUGI__FN xml_attribute_iterator::xml_attribute_iterator() + { + } + + PUGI__FN xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent) + { + } + + PUGI__FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) + { + } + + PUGI__FN bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const + { + return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root; + } + + PUGI__FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const + { + return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root; + } + + PUGI__FN xml_attribute& xml_attribute_iterator::operator*() const + { + assert(_wrap._attr); + return _wrap; + } + + PUGI__FN xml_attribute* xml_attribute_iterator::operator->() const + { + assert(_wrap._attr); + return const_cast(&_wrap); // BCC32 workaround + } + + PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator++() + { + assert(_wrap._attr); + _wrap._attr = _wrap._attr->next_attribute; + return *this; + } + + PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator++(int) + { + xml_attribute_iterator temp = *this; + ++*this; + return temp; + } + + PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator--() + { + _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute(); + return *this; + } + + PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator--(int) + { + xml_attribute_iterator temp = *this; + --*this; + return temp; + } + + PUGI__FN xml_named_node_iterator::xml_named_node_iterator(): _name(0) + { + } + + PUGI__FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, const char_t* name): _node(node), _name(name) + { + } + + PUGI__FN bool xml_named_node_iterator::operator==(const xml_named_node_iterator& rhs) const + { + return _node == rhs._node; + } + + PUGI__FN bool xml_named_node_iterator::operator!=(const xml_named_node_iterator& rhs) const + { + return _node != rhs._node; + } + + PUGI__FN xml_node& xml_named_node_iterator::operator*() const + { + assert(_node._root); + return _node; + } + + PUGI__FN xml_node* xml_named_node_iterator::operator->() const + { + assert(_node._root); + return const_cast(&_node); // BCC32 workaround + } + + PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator++() + { + assert(_node._root); + _node = _node.next_sibling(_name); + return *this; + } + + PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator++(int) + { + xml_named_node_iterator temp = *this; + ++*this; + return temp; + } + + PUGI__FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto) + { + } + + PUGI__FN xml_parse_result::operator bool() const + { + return status == status_ok; + } + + PUGI__FN const char* xml_parse_result::description() const + { + switch (status) + { + case status_ok: return "No error"; + + case status_file_not_found: return "File was not found"; + case status_io_error: return "Error reading from file/stream"; + case status_out_of_memory: return "Could not allocate memory"; + case status_internal_error: return "Internal error occurred"; + + case status_unrecognized_tag: return "Could not determine tag type"; + + case status_bad_pi: return "Error parsing document declaration/processing instruction"; + case status_bad_comment: return "Error parsing comment"; + case status_bad_cdata: return "Error parsing CDATA section"; + case status_bad_doctype: return "Error parsing document type declaration"; + case status_bad_pcdata: return "Error parsing PCDATA section"; + case status_bad_start_element: return "Error parsing start element tag"; + case status_bad_attribute: return "Error parsing element attribute"; + case status_bad_end_element: return "Error parsing end element tag"; + case status_end_element_mismatch: return "Start-end tags mismatch"; + + default: return "Unknown error"; + } + } + + PUGI__FN xml_document::xml_document(): _buffer(0) + { + create(); + } + + PUGI__FN xml_document::~xml_document() + { + destroy(); + } + + PUGI__FN void xml_document::reset() + { + destroy(); + create(); + } + + PUGI__FN void xml_document::reset(const xml_document& proto) + { + reset(); + + for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling()) + append_copy(cur); + } + + PUGI__FN void xml_document::create() + { + // initialize sentinel page + PUGI__STATIC_ASSERT(offsetof(impl::xml_memory_page, data) + sizeof(impl::xml_document_struct) + impl::xml_memory_page_alignment <= sizeof(_memory)); + + // align upwards to page boundary + void* page_memory = reinterpret_cast((reinterpret_cast(_memory) + (impl::xml_memory_page_alignment - 1)) & ~(impl::xml_memory_page_alignment - 1)); + + // prepare page structure + impl::xml_memory_page* page = impl::xml_memory_page::construct(page_memory); + + page->busy_size = impl::xml_memory_page_size; + + // allocate new root + _root = new (page->data) impl::xml_document_struct(page); + _root->prev_sibling_c = _root; + + // setup sentinel page + page->allocator = static_cast(_root); + } + + PUGI__FN void xml_document::destroy() + { + // destroy static storage + if (_buffer) + { + impl::xml_memory::deallocate(_buffer); + _buffer = 0; + } + + // destroy dynamic storage, leave sentinel page (it's in static memory) + if (_root) + { + impl::xml_memory_page* root_page = reinterpret_cast(_root->header & impl::xml_memory_page_pointer_mask); + assert(root_page && !root_page->prev && !root_page->memory); + + // destroy all pages + for (impl::xml_memory_page* page = root_page->next; page; ) + { + impl::xml_memory_page* next = page->next; + + impl::xml_allocator::deallocate_page(page); + + page = next; + } + + // cleanup root page + root_page->allocator = 0; + root_page->next = 0; + root_page->busy_size = root_page->freed_size = 0; + + _root = 0; + } + } + +#ifndef PUGIXML_NO_STL + PUGI__FN xml_parse_result xml_document::load(std::basic_istream >& stream, unsigned int options, xml_encoding encoding) + { + reset(); + + return impl::load_stream_impl(*this, stream, options, encoding); + } + + PUGI__FN xml_parse_result xml_document::load(std::basic_istream >& stream, unsigned int options) + { + reset(); + + return impl::load_stream_impl(*this, stream, options, encoding_wchar); + } +#endif + + PUGI__FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options) + { + // Force native encoding (skip autodetection) + #ifdef PUGIXML_WCHAR_MODE + xml_encoding encoding = encoding_wchar; + #else + xml_encoding encoding = encoding_utf8; + #endif + + return load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding); + } + + PUGI__FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding) + { + reset(); + + FILE* file = fopen(path_, "rb"); + + return impl::load_file_impl(*this, file, options, encoding); + } + + PUGI__FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding) + { + reset(); + + FILE* file = impl::open_file_wide(path_, L"rb"); + + return impl::load_file_impl(*this, file, options, encoding); + } + + PUGI__FN xml_parse_result xml_document::load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own) + { + reset(); + + // check input buffer + assert(contents || size == 0); + + // get actual encoding + xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size); + + // get private buffer + char_t* buffer = 0; + size_t length = 0; + + if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory); + + // delete original buffer if we performed a conversion + if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents); + + // parse + xml_parse_result res = impl::xml_parser::parse(buffer, length, _root, options); + + // remember encoding + res.encoding = buffer_encoding; + + // grab onto buffer if it's our buffer, user is responsible for deallocating contens himself + if (own || buffer != contents) _buffer = buffer; + + return res; + } + + PUGI__FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) + { + return load_buffer_impl(const_cast(contents), size, options, encoding, false, false); + } + + PUGI__FN xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding) + { + return load_buffer_impl(contents, size, options, encoding, true, false); + } + + PUGI__FN xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding) + { + return load_buffer_impl(contents, size, options, encoding, true, true); + } + + PUGI__FN void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const + { + impl::xml_buffered_writer buffered_writer(writer, encoding); + + if ((flags & format_write_bom) && encoding != encoding_latin1) + { + // BOM always represents the codepoint U+FEFF, so just write it in native encoding + #ifdef PUGIXML_WCHAR_MODE + unsigned int bom = 0xfeff; + buffered_writer.write(static_cast(bom)); + #else + buffered_writer.write('\xef', '\xbb', '\xbf'); + #endif + } + + if (!(flags & format_no_declaration) && !impl::has_declaration(*this)) + { + buffered_writer.write(PUGIXML_TEXT("'); + if (!(flags & format_raw)) buffered_writer.write('\n'); + } + + impl::node_output(buffered_writer, *this, indent, flags, 0); + } + +#ifndef PUGIXML_NO_STL + PUGI__FN void xml_document::save(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const + { + xml_writer_stream writer(stream); + + save(writer, indent, flags, encoding); + } + + PUGI__FN void xml_document::save(std::basic_ostream >& stream, const char_t* indent, unsigned int flags) const + { + xml_writer_stream writer(stream); + + save(writer, indent, flags, encoding_wchar); + } +#endif + + PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const + { + FILE* file = fopen(path_, (flags & format_save_file_text) ? "w" : "wb"); + return impl::save_file_impl(*this, file, indent, flags, encoding); + } + + PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const + { + FILE* file = impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"); + return impl::save_file_impl(*this, file, indent, flags, encoding); + } + + PUGI__FN xml_node xml_document::document_element() const + { + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + if ((i->header & impl::xml_memory_page_type_mask) + 1 == node_element) + return xml_node(i); + + return xml_node(); + } + +#ifndef PUGIXML_NO_STL + PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str) + { + assert(str); + + return impl::as_utf8_impl(str, wcslen(str)); + } + + PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string& str) + { + return impl::as_utf8_impl(str.c_str(), str.size()); + } + + PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const char* str) + { + assert(str); + + return impl::as_wide_impl(str, strlen(str)); + } + + PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const std::string& str) + { + return impl::as_wide_impl(str.c_str(), str.size()); + } +#endif + + PUGI__FN void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate) + { + impl::xml_memory::allocate = allocate; + impl::xml_memory::deallocate = deallocate; + } + + PUGI__FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function() + { + return impl::xml_memory::allocate; + } + + PUGI__FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function() + { + return impl::xml_memory::deallocate; + } +} + +#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) +namespace std +{ + // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) + PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&) + { + return std::bidirectional_iterator_tag(); + } + + PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&) + { + return std::bidirectional_iterator_tag(); + } + + PUGI__FN std::forward_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator&) + { + return std::forward_iterator_tag(); + } +} +#endif + +#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) +namespace std +{ + // Workarounds for (non-standard) iterator category detection + PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator&) + { + return std::bidirectional_iterator_tag(); + } + + PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator&) + { + return std::bidirectional_iterator_tag(); + } + + PUGI__FN std::forward_iterator_tag __iterator_category(const pugi::xml_named_node_iterator&) + { + return std::forward_iterator_tag(); + } +} +#endif + +#ifndef PUGIXML_NO_XPATH + +// STL replacements +PUGI__NS_BEGIN + struct equal_to + { + template bool operator()(const T& lhs, const T& rhs) const + { + return lhs == rhs; + } + }; + + struct not_equal_to + { + template bool operator()(const T& lhs, const T& rhs) const + { + return lhs != rhs; + } + }; + + struct less + { + template bool operator()(const T& lhs, const T& rhs) const + { + return lhs < rhs; + } + }; + + struct less_equal + { + template bool operator()(const T& lhs, const T& rhs) const + { + return lhs <= rhs; + } + }; + + template void swap(T& lhs, T& rhs) + { + T temp = lhs; + lhs = rhs; + rhs = temp; + } + + template I min_element(I begin, I end, const Pred& pred) + { + I result = begin; + + for (I it = begin + 1; it != end; ++it) + if (pred(*it, *result)) + result = it; + + return result; + } + + template void reverse(I begin, I end) + { + while (begin + 1 < end) swap(*begin++, *--end); + } + + template I unique(I begin, I end) + { + // fast skip head + while (begin + 1 < end && *begin != *(begin + 1)) begin++; + + if (begin == end) return begin; + + // last written element + I write = begin++; + + // merge unique elements + while (begin != end) + { + if (*begin != *write) + *++write = *begin++; + else + begin++; + } + + // past-the-end (write points to live element) + return write + 1; + } + + template void copy_backwards(I begin, I end, I target) + { + while (begin != end) *--target = *--end; + } + + template void insertion_sort(I begin, I end, const Pred& pred, T*) + { + assert(begin != end); + + for (I it = begin + 1; it != end; ++it) + { + T val = *it; + + if (pred(val, *begin)) + { + // move to front + copy_backwards(begin, it, it + 1); + *begin = val; + } + else + { + I hole = it; + + // move hole backwards + while (pred(val, *(hole - 1))) + { + *hole = *(hole - 1); + hole--; + } + + // fill hole with element + *hole = val; + } + } + } + + // std variant for elements with == + template void partition(I begin, I middle, I end, const Pred& pred, I* out_eqbeg, I* out_eqend) + { + I eqbeg = middle, eqend = middle + 1; + + // expand equal range + while (eqbeg != begin && *(eqbeg - 1) == *eqbeg) --eqbeg; + while (eqend != end && *eqend == *eqbeg) ++eqend; + + // process outer elements + I ltend = eqbeg, gtbeg = eqend; + + for (;;) + { + // find the element from the right side that belongs to the left one + for (; gtbeg != end; ++gtbeg) + if (!pred(*eqbeg, *gtbeg)) + { + if (*gtbeg == *eqbeg) swap(*gtbeg, *eqend++); + else break; + } + + // find the element from the left side that belongs to the right one + for (; ltend != begin; --ltend) + if (!pred(*(ltend - 1), *eqbeg)) + { + if (*eqbeg == *(ltend - 1)) swap(*(ltend - 1), *--eqbeg); + else break; + } + + // scanned all elements + if (gtbeg == end && ltend == begin) + { + *out_eqbeg = eqbeg; + *out_eqend = eqend; + return; + } + + // make room for elements by moving equal area + if (gtbeg == end) + { + if (--ltend != --eqbeg) swap(*ltend, *eqbeg); + swap(*eqbeg, *--eqend); + } + else if (ltend == begin) + { + if (eqend != gtbeg) swap(*eqbeg, *eqend); + ++eqend; + swap(*gtbeg++, *eqbeg++); + } + else swap(*gtbeg++, *--ltend); + } + } + + template void median3(I first, I middle, I last, const Pred& pred) + { + if (pred(*middle, *first)) swap(*middle, *first); + if (pred(*last, *middle)) swap(*last, *middle); + if (pred(*middle, *first)) swap(*middle, *first); + } + + template void median(I first, I middle, I last, const Pred& pred) + { + if (last - first <= 40) + { + // median of three for small chunks + median3(first, middle, last, pred); + } + else + { + // median of nine + size_t step = (last - first + 1) / 8; + + median3(first, first + step, first + 2 * step, pred); + median3(middle - step, middle, middle + step, pred); + median3(last - 2 * step, last - step, last, pred); + median3(first + step, middle, last - step, pred); + } + } + + template void sort(I begin, I end, const Pred& pred) + { + // sort large chunks + while (end - begin > 32) + { + // find median element + I middle = begin + (end - begin) / 2; + median(begin, middle, end - 1, pred); + + // partition in three chunks (< = >) + I eqbeg, eqend; + partition(begin, middle, end, pred, &eqbeg, &eqend); + + // loop on larger half + if (eqbeg - begin > end - eqend) + { + sort(eqend, end, pred); + end = eqbeg; + } + else + { + sort(begin, eqbeg, pred); + begin = eqend; + } + } + + // insertion sort small chunk + if (begin != end) insertion_sort(begin, end, pred, &*begin); + } +PUGI__NS_END + +// Allocator used for AST and evaluation stacks +PUGI__NS_BEGIN + struct xpath_memory_block + { + xpath_memory_block* next; + + char data[ + #ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE + PUGIXML_MEMORY_XPATH_PAGE_SIZE + #else + 4096 + #endif + ]; + }; + + class xpath_allocator + { + xpath_memory_block* _root; + size_t _root_size; + + public: + #ifdef PUGIXML_NO_EXCEPTIONS + jmp_buf* error_handler; + #endif + + xpath_allocator(xpath_memory_block* root, size_t root_size = 0): _root(root), _root_size(root_size) + { + #ifdef PUGIXML_NO_EXCEPTIONS + error_handler = 0; + #endif + } + + void* allocate_nothrow(size_t size) + { + const size_t block_capacity = sizeof(_root->data); + + // align size so that we're able to store pointers in subsequent blocks + size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); + + if (_root_size + size <= block_capacity) + { + void* buf = _root->data + _root_size; + _root_size += size; + return buf; + } + else + { + size_t block_data_size = (size > block_capacity) ? size : block_capacity; + size_t block_size = block_data_size + offsetof(xpath_memory_block, data); + + xpath_memory_block* block = static_cast(xml_memory::allocate(block_size)); + if (!block) return 0; + + block->next = _root; + + _root = block; + _root_size = size; + + return block->data; + } + } + + void* allocate(size_t size) + { + void* result = allocate_nothrow(size); + + if (!result) + { + #ifdef PUGIXML_NO_EXCEPTIONS + assert(error_handler); + longjmp(*error_handler, 1); + #else + throw std::bad_alloc(); + #endif + } + + return result; + } + + void* reallocate(void* ptr, size_t old_size, size_t new_size) + { + // align size so that we're able to store pointers in subsequent blocks + old_size = (old_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); + new_size = (new_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); + + // we can only reallocate the last object + assert(ptr == 0 || static_cast(ptr) + old_size == _root->data + _root_size); + + // adjust root size so that we have not allocated the object at all + bool only_object = (_root_size == old_size); + + if (ptr) _root_size -= old_size; + + // allocate a new version (this will obviously reuse the memory if possible) + void* result = allocate(new_size); + assert(result); + + // we have a new block + if (result != ptr && ptr) + { + // copy old data + assert(new_size > old_size); + memcpy(result, ptr, old_size); + + // free the previous page if it had no other objects + if (only_object) + { + assert(_root->data == result); + assert(_root->next); + + xpath_memory_block* next = _root->next->next; + + if (next) + { + // deallocate the whole page, unless it was the first one + xml_memory::deallocate(_root->next); + _root->next = next; + } + } + } + + return result; + } + + void revert(const xpath_allocator& state) + { + // free all new pages + xpath_memory_block* cur = _root; + + while (cur != state._root) + { + xpath_memory_block* next = cur->next; + + xml_memory::deallocate(cur); + + cur = next; + } + + // restore state + _root = state._root; + _root_size = state._root_size; + } + + void release() + { + xpath_memory_block* cur = _root; + assert(cur); + + while (cur->next) + { + xpath_memory_block* next = cur->next; + + xml_memory::deallocate(cur); + + cur = next; + } + } + }; + + struct xpath_allocator_capture + { + xpath_allocator_capture(xpath_allocator* alloc): _target(alloc), _state(*alloc) + { + } + + ~xpath_allocator_capture() + { + _target->revert(_state); + } + + xpath_allocator* _target; + xpath_allocator _state; + }; + + struct xpath_stack + { + xpath_allocator* result; + xpath_allocator* temp; + }; + + struct xpath_stack_data + { + xpath_memory_block blocks[2]; + xpath_allocator result; + xpath_allocator temp; + xpath_stack stack; + + #ifdef PUGIXML_NO_EXCEPTIONS + jmp_buf error_handler; + #endif + + xpath_stack_data(): result(blocks + 0), temp(blocks + 1) + { + blocks[0].next = blocks[1].next = 0; + + stack.result = &result; + stack.temp = &temp; + + #ifdef PUGIXML_NO_EXCEPTIONS + result.error_handler = temp.error_handler = &error_handler; + #endif + } + + ~xpath_stack_data() + { + result.release(); + temp.release(); + } + }; +PUGI__NS_END + +// String class +PUGI__NS_BEGIN + class xpath_string + { + const char_t* _buffer; + bool _uses_heap; + + static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc) + { + char_t* result = static_cast(alloc->allocate((length + 1) * sizeof(char_t))); + assert(result); + + memcpy(result, string, length * sizeof(char_t)); + result[length] = 0; + + return result; + } + + static char_t* duplicate_string(const char_t* string, xpath_allocator* alloc) + { + return duplicate_string(string, strlength(string), alloc); + } + + public: + xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false) + { + } + + explicit xpath_string(const char_t* str, xpath_allocator* alloc) + { + bool empty_ = (*str == 0); + + _buffer = empty_ ? PUGIXML_TEXT("") : duplicate_string(str, alloc); + _uses_heap = !empty_; + } + + explicit xpath_string(const char_t* str, bool use_heap): _buffer(str), _uses_heap(use_heap) + { + } + + xpath_string(const char_t* begin, const char_t* end, xpath_allocator* alloc) + { + assert(begin <= end); + + bool empty_ = (begin == end); + + _buffer = empty_ ? PUGIXML_TEXT("") : duplicate_string(begin, static_cast(end - begin), alloc); + _uses_heap = !empty_; + } + + void append(const xpath_string& o, xpath_allocator* alloc) + { + // skip empty sources + if (!*o._buffer) return; + + // fast append for constant empty target and constant source + if (!*_buffer && !_uses_heap && !o._uses_heap) + { + _buffer = o._buffer; + } + else + { + // need to make heap copy + size_t target_length = strlength(_buffer); + size_t source_length = strlength(o._buffer); + size_t result_length = target_length + source_length; + + // allocate new buffer + char_t* result = static_cast(alloc->reallocate(_uses_heap ? const_cast(_buffer) : 0, (target_length + 1) * sizeof(char_t), (result_length + 1) * sizeof(char_t))); + assert(result); + + // append first string to the new buffer in case there was no reallocation + if (!_uses_heap) memcpy(result, _buffer, target_length * sizeof(char_t)); + + // append second string to the new buffer + memcpy(result + target_length, o._buffer, source_length * sizeof(char_t)); + result[result_length] = 0; + + // finalize + _buffer = result; + _uses_heap = true; + } + } + + const char_t* c_str() const + { + return _buffer; + } + + size_t length() const + { + return strlength(_buffer); + } + + char_t* data(xpath_allocator* alloc) + { + // make private heap copy + if (!_uses_heap) + { + _buffer = duplicate_string(_buffer, alloc); + _uses_heap = true; + } + + return const_cast(_buffer); + } + + bool empty() const + { + return *_buffer == 0; + } + + bool operator==(const xpath_string& o) const + { + return strequal(_buffer, o._buffer); + } + + bool operator!=(const xpath_string& o) const + { + return !strequal(_buffer, o._buffer); + } + + bool uses_heap() const + { + return _uses_heap; + } + }; + + PUGI__FN xpath_string xpath_string_const(const char_t* str) + { + return xpath_string(str, false); + } +PUGI__NS_END + +PUGI__NS_BEGIN + PUGI__FN bool starts_with(const char_t* string, const char_t* pattern) + { + while (*pattern && *string == *pattern) + { + string++; + pattern++; + } + + return *pattern == 0; + } + + PUGI__FN const char_t* find_char(const char_t* s, char_t c) + { + #ifdef PUGIXML_WCHAR_MODE + return wcschr(s, c); + #else + return strchr(s, c); + #endif + } + + PUGI__FN const char_t* find_substring(const char_t* s, const char_t* p) + { + #ifdef PUGIXML_WCHAR_MODE + // MSVC6 wcsstr bug workaround (if s is empty it always returns 0) + return (*p == 0) ? s : wcsstr(s, p); + #else + return strstr(s, p); + #endif + } + + // Converts symbol to lower case, if it is an ASCII one + PUGI__FN char_t tolower_ascii(char_t ch) + { + return static_cast(ch - 'A') < 26 ? static_cast(ch | ' ') : ch; + } + + PUGI__FN xpath_string string_value(const xpath_node& na, xpath_allocator* alloc) + { + if (na.attribute()) + return xpath_string_const(na.attribute().value()); + else + { + const xml_node& n = na.node(); + + switch (n.type()) + { + case node_pcdata: + case node_cdata: + case node_comment: + case node_pi: + return xpath_string_const(n.value()); + + case node_document: + case node_element: + { + xpath_string result; + + xml_node cur = n.first_child(); + + while (cur && cur != n) + { + if (cur.type() == node_pcdata || cur.type() == node_cdata) + result.append(xpath_string_const(cur.value()), alloc); + + if (cur.first_child()) + cur = cur.first_child(); + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + while (!cur.next_sibling() && cur != n) + cur = cur.parent(); + + if (cur != n) cur = cur.next_sibling(); + } + } + + return result; + } + + default: + return xpath_string(); + } + } + } + + PUGI__FN unsigned int node_height(xml_node n) + { + unsigned int result = 0; + + while (n) + { + ++result; + n = n.parent(); + } + + return result; + } + + PUGI__FN bool node_is_before(xml_node ln, unsigned int lh, xml_node rn, unsigned int rh) + { + // normalize heights + for (unsigned int i = rh; i < lh; i++) ln = ln.parent(); + for (unsigned int j = lh; j < rh; j++) rn = rn.parent(); + + // one node is the ancestor of the other + if (ln == rn) return lh < rh; + + // find common ancestor + while (ln.parent() != rn.parent()) + { + ln = ln.parent(); + rn = rn.parent(); + } + + // there is no common ancestor (the shared parent is null), nodes are from different documents + if (!ln.parent()) return ln < rn; + + // determine sibling order + for (; ln; ln = ln.next_sibling()) + if (ln == rn) + return true; + + return false; + } + + PUGI__FN bool node_is_ancestor(xml_node parent, xml_node node) + { + while (node && node != parent) node = node.parent(); + + return parent && node == parent; + } + + PUGI__FN const void* document_order(const xpath_node& xnode) + { + xml_node_struct* node = xnode.node().internal_object(); + + if (node) + { + if (node->name && (node->header & xml_memory_page_name_allocated_mask) == 0) return node->name; + if (node->value && (node->header & xml_memory_page_value_allocated_mask) == 0) return node->value; + return 0; + } + + xml_attribute_struct* attr = xnode.attribute().internal_object(); + + if (attr) + { + if ((attr->header & xml_memory_page_name_allocated_mask) == 0) return attr->name; + if ((attr->header & xml_memory_page_value_allocated_mask) == 0) return attr->value; + return 0; + } + + return 0; + } + + struct document_order_comparator + { + bool operator()(const xpath_node& lhs, const xpath_node& rhs) const + { + // optimized document order based check + const void* lo = document_order(lhs); + const void* ro = document_order(rhs); + + if (lo && ro) return lo < ro; + + // slow comparison + xml_node ln = lhs.node(), rn = rhs.node(); + + // compare attributes + if (lhs.attribute() && rhs.attribute()) + { + // shared parent + if (lhs.parent() == rhs.parent()) + { + // determine sibling order + for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute()) + if (a == rhs.attribute()) + return true; + + return false; + } + + // compare attribute parents + ln = lhs.parent(); + rn = rhs.parent(); + } + else if (lhs.attribute()) + { + // attributes go after the parent element + if (lhs.parent() == rhs.node()) return false; + + ln = lhs.parent(); + } + else if (rhs.attribute()) + { + // attributes go after the parent element + if (rhs.parent() == lhs.node()) return true; + + rn = rhs.parent(); + } + + if (ln == rn) return false; + + unsigned int lh = node_height(ln); + unsigned int rh = node_height(rn); + + return node_is_before(ln, lh, rn, rh); + } + }; + + struct duplicate_comparator + { + bool operator()(const xpath_node& lhs, const xpath_node& rhs) const + { + if (lhs.attribute()) return rhs.attribute() ? lhs.attribute() < rhs.attribute() : true; + else return rhs.attribute() ? false : lhs.node() < rhs.node(); + } + }; + + PUGI__FN double gen_nan() + { + #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24)) + union { float f; uint32_t i; } u[sizeof(float) == sizeof(uint32_t) ? 1 : -1]; + u[0].i = 0x7fc00000; + return u[0].f; + #else + // fallback + const volatile double zero = 0.0; + return zero / zero; + #endif + } + + PUGI__FN bool is_nan(double value) + { + #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) + return !!_isnan(value); + #elif defined(fpclassify) && defined(FP_NAN) + return fpclassify(value) == FP_NAN; + #else + // fallback + const volatile double v = value; + return v != v; + #endif + } + + PUGI__FN const char_t* convert_number_to_string_special(double value) + { + #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) + if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0; + if (_isnan(value)) return PUGIXML_TEXT("NaN"); + return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); + #elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO) + switch (fpclassify(value)) + { + case FP_NAN: + return PUGIXML_TEXT("NaN"); + + case FP_INFINITE: + return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); + + case FP_ZERO: + return PUGIXML_TEXT("0"); + + default: + return 0; + } + #else + // fallback + const volatile double v = value; + + if (v == 0) return PUGIXML_TEXT("0"); + if (v != v) return PUGIXML_TEXT("NaN"); + if (v * 2 == v) return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); + return 0; + #endif + } + + PUGI__FN bool convert_number_to_boolean(double value) + { + return (value != 0 && !is_nan(value)); + } + + PUGI__FN void truncate_zeros(char* begin, char* end) + { + while (begin != end && end[-1] == '0') end--; + + *end = 0; + } + + // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent +#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE) + PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) + { + // get base values + int sign, exponent; + _ecvt_s(buffer, buffer_size, value, DBL_DIG + 1, &exponent, &sign); + + // truncate redundant zeros + truncate_zeros(buffer, buffer + strlen(buffer)); + + // fill results + *out_mantissa = buffer; + *out_exponent = exponent; + } +#else + PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) + { + // get a scientific notation value with IEEE DBL_DIG decimals + sprintf(buffer, "%.*e", DBL_DIG, value); + assert(strlen(buffer) < buffer_size); + (void)!buffer_size; + + // get the exponent (possibly negative) + char* exponent_string = strchr(buffer, 'e'); + assert(exponent_string); + + int exponent = atoi(exponent_string + 1); + + // extract mantissa string: skip sign + char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer; + assert(mantissa[0] != '0' && mantissa[1] == '.'); + + // divide mantissa by 10 to eliminate integer part + mantissa[1] = mantissa[0]; + mantissa++; + exponent++; + + // remove extra mantissa digits and zero-terminate mantissa + truncate_zeros(mantissa, exponent_string); + + // fill results + *out_mantissa = mantissa; + *out_exponent = exponent; + } +#endif + + PUGI__FN xpath_string convert_number_to_string(double value, xpath_allocator* alloc) + { + // try special number conversion + const char_t* special = convert_number_to_string_special(value); + if (special) return xpath_string_const(special); + + // get mantissa + exponent form + char mantissa_buffer[64]; + + char* mantissa; + int exponent; + convert_number_to_mantissa_exponent(value, mantissa_buffer, sizeof(mantissa_buffer), &mantissa, &exponent); + + // make the number! + char_t result[512]; + char_t* s = result; + + // sign + if (value < 0) *s++ = '-'; + + // integer part + if (exponent <= 0) + { + *s++ = '0'; + } + else + { + while (exponent > 0) + { + assert(*mantissa == 0 || static_cast(*mantissa - '0') <= 9); + *s++ = *mantissa ? *mantissa++ : '0'; + exponent--; + } + } + + // fractional part + if (*mantissa) + { + // decimal point + *s++ = '.'; + + // extra zeroes from negative exponent + while (exponent < 0) + { + *s++ = '0'; + exponent++; + } + + // extra mantissa digits + while (*mantissa) + { + assert(static_cast(*mantissa - '0') <= 9); + *s++ = *mantissa++; + } + } + + // zero-terminate + assert(s < result + sizeof(result) / sizeof(result[0])); + *s = 0; + + return xpath_string(result, alloc); + } + + PUGI__FN bool check_string_to_number_format(const char_t* string) + { + // parse leading whitespace + while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string; + + // parse sign + if (*string == '-') ++string; + + if (!*string) return false; + + // if there is no integer part, there should be a decimal part with at least one digit + if (!PUGI__IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI__IS_CHARTYPEX(string[1], ctx_digit))) return false; + + // parse integer part + while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string; + + // parse decimal part + if (*string == '.') + { + ++string; + + while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string; + } + + // parse trailing whitespace + while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string; + + return *string == 0; + } + + PUGI__FN double convert_string_to_number(const char_t* string) + { + // check string format + if (!check_string_to_number_format(string)) return gen_nan(); + + // parse string + #ifdef PUGIXML_WCHAR_MODE + return wcstod(string, 0); + #else + return atof(string); + #endif + } + + PUGI__FN bool convert_string_to_number(const char_t* begin, const char_t* end, double* out_result) + { + char_t buffer[32]; + + size_t length = static_cast(end - begin); + char_t* scratch = buffer; + + if (length >= sizeof(buffer) / sizeof(buffer[0])) + { + // need to make dummy on-heap copy + scratch = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); + if (!scratch) return false; + } + + // copy string to zero-terminated buffer and perform conversion + memcpy(scratch, begin, length * sizeof(char_t)); + scratch[length] = 0; + + *out_result = convert_string_to_number(scratch); + + // free dummy buffer + if (scratch != buffer) xml_memory::deallocate(scratch); + + return true; + } + + PUGI__FN double round_nearest(double value) + { + return floor(value + 0.5); + } + + PUGI__FN double round_nearest_nzero(double value) + { + // same as round_nearest, but returns -0 for [-0.5, -0] + // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0) + return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5); + } + + PUGI__FN const char_t* qualified_name(const xpath_node& node) + { + return node.attribute() ? node.attribute().name() : node.node().name(); + } + + PUGI__FN const char_t* local_name(const xpath_node& node) + { + const char_t* name = qualified_name(node); + const char_t* p = find_char(name, ':'); + + return p ? p + 1 : name; + } + + struct namespace_uri_predicate + { + const char_t* prefix; + size_t prefix_length; + + namespace_uri_predicate(const char_t* name) + { + const char_t* pos = find_char(name, ':'); + + prefix = pos ? name : 0; + prefix_length = pos ? static_cast(pos - name) : 0; + } + + bool operator()(const xml_attribute& a) const + { + const char_t* name = a.name(); + + if (!starts_with(name, PUGIXML_TEXT("xmlns"))) return false; + + return prefix ? name[5] == ':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0; + } + }; + + PUGI__FN const char_t* namespace_uri(const xml_node& node) + { + namespace_uri_predicate pred = node.name(); + + xml_node p = node; + + while (p) + { + xml_attribute a = p.find_attribute(pred); + + if (a) return a.value(); + + p = p.parent(); + } + + return PUGIXML_TEXT(""); + } + + PUGI__FN const char_t* namespace_uri(const xml_attribute& attr, const xml_node& parent) + { + namespace_uri_predicate pred = attr.name(); + + // Default namespace does not apply to attributes + if (!pred.prefix) return PUGIXML_TEXT(""); + + xml_node p = parent; + + while (p) + { + xml_attribute a = p.find_attribute(pred); + + if (a) return a.value(); + + p = p.parent(); + } + + return PUGIXML_TEXT(""); + } + + PUGI__FN const char_t* namespace_uri(const xpath_node& node) + { + return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node()); + } + + PUGI__FN void normalize_space(char_t* buffer) + { + char_t* write = buffer; + + for (char_t* it = buffer; *it; ) + { + char_t ch = *it++; + + if (PUGI__IS_CHARTYPE(ch, ct_space)) + { + // replace whitespace sequence with single space + while (PUGI__IS_CHARTYPE(*it, ct_space)) it++; + + // avoid leading spaces + if (write != buffer) *write++ = ' '; + } + else *write++ = ch; + } + + // remove trailing space + if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space)) write--; + + // zero-terminate + *write = 0; + } + + PUGI__FN void translate(char_t* buffer, const char_t* from, const char_t* to) + { + size_t to_length = strlength(to); + + char_t* write = buffer; + + while (*buffer) + { + PUGI__DMC_VOLATILE char_t ch = *buffer++; + + const char_t* pos = find_char(from, ch); + + if (!pos) + *write++ = ch; // do not process + else if (static_cast(pos - from) < to_length) + *write++ = to[pos - from]; // replace + } + + // zero-terminate + *write = 0; + } + + struct xpath_variable_boolean: xpath_variable + { + xpath_variable_boolean(): value(false) + { + } + + bool value; + char_t name[1]; + }; + + struct xpath_variable_number: xpath_variable + { + xpath_variable_number(): value(0) + { + } + + double value; + char_t name[1]; + }; + + struct xpath_variable_string: xpath_variable + { + xpath_variable_string(): value(0) + { + } + + ~xpath_variable_string() + { + if (value) xml_memory::deallocate(value); + } + + char_t* value; + char_t name[1]; + }; + + struct xpath_variable_node_set: xpath_variable + { + xpath_node_set value; + char_t name[1]; + }; + + static const xpath_node_set dummy_node_set; + + PUGI__FN unsigned int hash_string(const char_t* str) + { + // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time) + unsigned int result = 0; + + while (*str) + { + result += static_cast(*str++); + result += result << 10; + result ^= result >> 6; + } + + result += result << 3; + result ^= result >> 11; + result += result << 15; + + return result; + } + + template PUGI__FN T* new_xpath_variable(const char_t* name) + { + size_t length = strlength(name); + if (length == 0) return 0; // empty variable names are invalid + + // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters + void* memory = xml_memory::allocate(sizeof(T) + length * sizeof(char_t)); + if (!memory) return 0; + + T* result = new (memory) T(); + + memcpy(result->name, name, (length + 1) * sizeof(char_t)); + + return result; + } + + PUGI__FN xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name) + { + switch (type) + { + case xpath_type_node_set: + return new_xpath_variable(name); + + case xpath_type_number: + return new_xpath_variable(name); + + case xpath_type_string: + return new_xpath_variable(name); + + case xpath_type_boolean: + return new_xpath_variable(name); + + default: + return 0; + } + } + + template PUGI__FN void delete_xpath_variable(T* var) + { + var->~T(); + xml_memory::deallocate(var); + } + + PUGI__FN void delete_xpath_variable(xpath_value_type type, xpath_variable* var) + { + switch (type) + { + case xpath_type_node_set: + delete_xpath_variable(static_cast(var)); + break; + + case xpath_type_number: + delete_xpath_variable(static_cast(var)); + break; + + case xpath_type_string: + delete_xpath_variable(static_cast(var)); + break; + + case xpath_type_boolean: + delete_xpath_variable(static_cast(var)); + break; + + default: + assert(!"Invalid variable type"); + } + } + + PUGI__FN xpath_variable* get_variable(xpath_variable_set* set, const char_t* begin, const char_t* end) + { + char_t buffer[32]; + + size_t length = static_cast(end - begin); + char_t* scratch = buffer; + + if (length >= sizeof(buffer) / sizeof(buffer[0])) + { + // need to make dummy on-heap copy + scratch = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); + if (!scratch) return 0; + } + + // copy string to zero-terminated buffer and perform lookup + memcpy(scratch, begin, length * sizeof(char_t)); + scratch[length] = 0; + + xpath_variable* result = set->get(scratch); + + // free dummy buffer + if (scratch != buffer) xml_memory::deallocate(scratch); + + return result; + } +PUGI__NS_END + +// Internal node set class +PUGI__NS_BEGIN + PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev) + { + xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted; + + if (type == xpath_node_set::type_unsorted) + { + sort(begin, end, document_order_comparator()); + + type = xpath_node_set::type_sorted; + } + + if (type != order) reverse(begin, end); + + return order; + } + + PUGI__FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type) + { + if (begin == end) return xpath_node(); + + switch (type) + { + case xpath_node_set::type_sorted: + return *begin; + + case xpath_node_set::type_sorted_reverse: + return *(end - 1); + + case xpath_node_set::type_unsorted: + return *min_element(begin, end, document_order_comparator()); + + default: + assert(!"Invalid node set type"); + return xpath_node(); + } + } + + class xpath_node_set_raw + { + xpath_node_set::type_t _type; + + xpath_node* _begin; + xpath_node* _end; + xpath_node* _eos; + + public: + xpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0) + { + } + + xpath_node* begin() const + { + return _begin; + } + + xpath_node* end() const + { + return _end; + } + + bool empty() const + { + return _begin == _end; + } + + size_t size() const + { + return static_cast(_end - _begin); + } + + xpath_node first() const + { + return xpath_first(_begin, _end, _type); + } + + void push_back(const xpath_node& node, xpath_allocator* alloc) + { + if (_end == _eos) + { + size_t capacity = static_cast(_eos - _begin); + + // get new capacity (1.5x rule) + size_t new_capacity = capacity + capacity / 2 + 1; + + // reallocate the old array or allocate a new one + xpath_node* data = static_cast(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node))); + assert(data); + + // finalize + _begin = data; + _end = data + capacity; + _eos = data + new_capacity; + } + + *_end++ = node; + } + + void append(const xpath_node* begin_, const xpath_node* end_, xpath_allocator* alloc) + { + size_t size_ = static_cast(_end - _begin); + size_t capacity = static_cast(_eos - _begin); + size_t count = static_cast(end_ - begin_); + + if (size_ + count > capacity) + { + // reallocate the old array or allocate a new one + xpath_node* data = static_cast(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size_ + count) * sizeof(xpath_node))); + assert(data); + + // finalize + _begin = data; + _end = data + size_; + _eos = data + size_ + count; + } + + memcpy(_end, begin_, count * sizeof(xpath_node)); + _end += count; + } + + void sort_do() + { + _type = xpath_sort(_begin, _end, _type, false); + } + + void truncate(xpath_node* pos) + { + assert(_begin <= pos && pos <= _end); + + _end = pos; + } + + void remove_duplicates() + { + if (_type == xpath_node_set::type_unsorted) + sort(_begin, _end, duplicate_comparator()); + + _end = unique(_begin, _end); + } + + xpath_node_set::type_t type() const + { + return _type; + } + + void set_type(xpath_node_set::type_t value) + { + _type = value; + } + }; +PUGI__NS_END + +PUGI__NS_BEGIN + struct xpath_context + { + xpath_node n; + size_t position, size; + + xpath_context(const xpath_node& n_, size_t position_, size_t size_): n(n_), position(position_), size(size_) + { + } + }; + + enum lexeme_t + { + lex_none = 0, + lex_equal, + lex_not_equal, + lex_less, + lex_greater, + lex_less_or_equal, + lex_greater_or_equal, + lex_plus, + lex_minus, + lex_multiply, + lex_union, + lex_var_ref, + lex_open_brace, + lex_close_brace, + lex_quoted_string, + lex_number, + lex_slash, + lex_double_slash, + lex_open_square_brace, + lex_close_square_brace, + lex_string, + lex_comma, + lex_axis_attribute, + lex_dot, + lex_double_dot, + lex_double_colon, + lex_eof + }; + + struct xpath_lexer_string + { + const char_t* begin; + const char_t* end; + + xpath_lexer_string(): begin(0), end(0) + { + } + + bool operator==(const char_t* other) const + { + size_t length = static_cast(end - begin); + + return strequalrange(other, begin, length); + } + }; + + class xpath_lexer + { + const char_t* _cur; + const char_t* _cur_lexeme_pos; + xpath_lexer_string _cur_lexeme_contents; + + lexeme_t _cur_lexeme; + + public: + explicit xpath_lexer(const char_t* query): _cur(query) + { + next(); + } + + const char_t* state() const + { + return _cur; + } + + void next() + { + const char_t* cur = _cur; + + while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur; + + // save lexeme position for error reporting + _cur_lexeme_pos = cur; + + switch (*cur) + { + case 0: + _cur_lexeme = lex_eof; + break; + + case '>': + if (*(cur+1) == '=') + { + cur += 2; + _cur_lexeme = lex_greater_or_equal; + } + else + { + cur += 1; + _cur_lexeme = lex_greater; + } + break; + + case '<': + if (*(cur+1) == '=') + { + cur += 2; + _cur_lexeme = lex_less_or_equal; + } + else + { + cur += 1; + _cur_lexeme = lex_less; + } + break; + + case '!': + if (*(cur+1) == '=') + { + cur += 2; + _cur_lexeme = lex_not_equal; + } + else + { + _cur_lexeme = lex_none; + } + break; + + case '=': + cur += 1; + _cur_lexeme = lex_equal; + + break; + + case '+': + cur += 1; + _cur_lexeme = lex_plus; + + break; + + case '-': + cur += 1; + _cur_lexeme = lex_minus; + + break; + + case '*': + cur += 1; + _cur_lexeme = lex_multiply; + + break; + + case '|': + cur += 1; + _cur_lexeme = lex_union; + + break; + + case '$': + cur += 1; + + if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol)) + { + _cur_lexeme_contents.begin = cur; + + while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + + if (cur[0] == ':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // qname + { + cur++; // : + + while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + } + + _cur_lexeme_contents.end = cur; + + _cur_lexeme = lex_var_ref; + } + else + { + _cur_lexeme = lex_none; + } + + break; + + case '(': + cur += 1; + _cur_lexeme = lex_open_brace; + + break; + + case ')': + cur += 1; + _cur_lexeme = lex_close_brace; + + break; + + case '[': + cur += 1; + _cur_lexeme = lex_open_square_brace; + + break; + + case ']': + cur += 1; + _cur_lexeme = lex_close_square_brace; + + break; + + case ',': + cur += 1; + _cur_lexeme = lex_comma; + + break; + + case '/': + if (*(cur+1) == '/') + { + cur += 2; + _cur_lexeme = lex_double_slash; + } + else + { + cur += 1; + _cur_lexeme = lex_slash; + } + break; + + case '.': + if (*(cur+1) == '.') + { + cur += 2; + _cur_lexeme = lex_double_dot; + } + else if (PUGI__IS_CHARTYPEX(*(cur+1), ctx_digit)) + { + _cur_lexeme_contents.begin = cur; // . + + ++cur; + + while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; + + _cur_lexeme_contents.end = cur; + + _cur_lexeme = lex_number; + } + else + { + cur += 1; + _cur_lexeme = lex_dot; + } + break; + + case '@': + cur += 1; + _cur_lexeme = lex_axis_attribute; + + break; + + case '"': + case '\'': + { + char_t terminator = *cur; + + ++cur; + + _cur_lexeme_contents.begin = cur; + while (*cur && *cur != terminator) cur++; + _cur_lexeme_contents.end = cur; + + if (!*cur) + _cur_lexeme = lex_none; + else + { + cur += 1; + _cur_lexeme = lex_quoted_string; + } + + break; + } + + case ':': + if (*(cur+1) == ':') + { + cur += 2; + _cur_lexeme = lex_double_colon; + } + else + { + _cur_lexeme = lex_none; + } + break; + + default: + if (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) + { + _cur_lexeme_contents.begin = cur; + + while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; + + if (*cur == '.') + { + cur++; + + while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; + } + + _cur_lexeme_contents.end = cur; + + _cur_lexeme = lex_number; + } + else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol)) + { + _cur_lexeme_contents.begin = cur; + + while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + + if (cur[0] == ':') + { + if (cur[1] == '*') // namespace test ncname:* + { + cur += 2; // :* + } + else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname + { + cur++; // : + + while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + } + } + + _cur_lexeme_contents.end = cur; + + _cur_lexeme = lex_string; + } + else + { + _cur_lexeme = lex_none; + } + } + + _cur = cur; + } + + lexeme_t current() const + { + return _cur_lexeme; + } + + const char_t* current_pos() const + { + return _cur_lexeme_pos; + } + + const xpath_lexer_string& contents() const + { + assert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string); + + return _cur_lexeme_contents; + } + }; + + enum ast_type_t + { + ast_op_or, // left or right + ast_op_and, // left and right + ast_op_equal, // left = right + ast_op_not_equal, // left != right + ast_op_less, // left < right + ast_op_greater, // left > right + ast_op_less_or_equal, // left <= right + ast_op_greater_or_equal, // left >= right + ast_op_add, // left + right + ast_op_subtract, // left - right + ast_op_multiply, // left * right + ast_op_divide, // left / right + ast_op_mod, // left % right + ast_op_negate, // left - right + ast_op_union, // left | right + ast_predicate, // apply predicate to set; next points to next predicate + ast_filter, // select * from left where right + ast_filter_posinv, // select * from left where right; proximity position invariant + ast_string_constant, // string constant + ast_number_constant, // number constant + ast_variable, // variable + ast_func_last, // last() + ast_func_position, // position() + ast_func_count, // count(left) + ast_func_id, // id(left) + ast_func_local_name_0, // local-name() + ast_func_local_name_1, // local-name(left) + ast_func_namespace_uri_0, // namespace-uri() + ast_func_namespace_uri_1, // namespace-uri(left) + ast_func_name_0, // name() + ast_func_name_1, // name(left) + ast_func_string_0, // string() + ast_func_string_1, // string(left) + ast_func_concat, // concat(left, right, siblings) + ast_func_starts_with, // starts_with(left, right) + ast_func_contains, // contains(left, right) + ast_func_substring_before, // substring-before(left, right) + ast_func_substring_after, // substring-after(left, right) + ast_func_substring_2, // substring(left, right) + ast_func_substring_3, // substring(left, right, third) + ast_func_string_length_0, // string-length() + ast_func_string_length_1, // string-length(left) + ast_func_normalize_space_0, // normalize-space() + ast_func_normalize_space_1, // normalize-space(left) + ast_func_translate, // translate(left, right, third) + ast_func_boolean, // boolean(left) + ast_func_not, // not(left) + ast_func_true, // true() + ast_func_false, // false() + ast_func_lang, // lang(left) + ast_func_number_0, // number() + ast_func_number_1, // number(left) + ast_func_sum, // sum(left) + ast_func_floor, // floor(left) + ast_func_ceiling, // ceiling(left) + ast_func_round, // round(left) + ast_step, // process set left with step + ast_step_root // select root node + }; + + enum axis_t + { + axis_ancestor, + axis_ancestor_or_self, + axis_attribute, + axis_child, + axis_descendant, + axis_descendant_or_self, + axis_following, + axis_following_sibling, + axis_namespace, + axis_parent, + axis_preceding, + axis_preceding_sibling, + axis_self + }; + + enum nodetest_t + { + nodetest_none, + nodetest_name, + nodetest_type_node, + nodetest_type_comment, + nodetest_type_pi, + nodetest_type_text, + nodetest_pi, + nodetest_all, + nodetest_all_in_namespace + }; + + template struct axis_to_type + { + static const axis_t axis; + }; + + template const axis_t axis_to_type::axis = N; + + class xpath_ast_node + { + private: + // node type + char _type; + char _rettype; + + // for ast_step / ast_predicate + char _axis; + char _test; + + // tree node structure + xpath_ast_node* _left; + xpath_ast_node* _right; + xpath_ast_node* _next; + + union + { + // value for ast_string_constant + const char_t* string; + // value for ast_number_constant + double number; + // variable for ast_variable + xpath_variable* variable; + // node test for ast_step (node name/namespace/node type/pi target) + const char_t* nodetest; + } _data; + + xpath_ast_node(const xpath_ast_node&); + xpath_ast_node& operator=(const xpath_ast_node&); + + template static bool compare_eq(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) + { + xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); + + if (lt != xpath_type_node_set && rt != xpath_type_node_set) + { + if (lt == xpath_type_boolean || rt == xpath_type_boolean) + return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack)); + else if (lt == xpath_type_number || rt == xpath_type_number) + return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); + else if (lt == xpath_type_string || rt == xpath_type_string) + { + xpath_allocator_capture cr(stack.result); + + xpath_string ls = lhs->eval_string(c, stack); + xpath_string rs = rhs->eval_string(c, stack); + + return comp(ls, rs); + } + } + else if (lt == xpath_type_node_set && rt == xpath_type_node_set) + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ls = lhs->eval_node_set(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture cri(stack.result); + + if (comp(string_value(*li, stack.result), string_value(*ri, stack.result))) + return true; + } + + return false; + } + else + { + if (lt == xpath_type_node_set) + { + swap(lhs, rhs); + swap(lt, rt); + } + + if (lt == xpath_type_boolean) + return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack)); + else if (lt == xpath_type_number) + { + xpath_allocator_capture cr(stack.result); + + double l = lhs->eval_number(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture cri(stack.result); + + if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) + return true; + } + + return false; + } + else if (lt == xpath_type_string) + { + xpath_allocator_capture cr(stack.result); + + xpath_string l = lhs->eval_string(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture cri(stack.result); + + if (comp(l, string_value(*ri, stack.result))) + return true; + } + + return false; + } + } + + assert(!"Wrong types"); + return false; + } + + template static bool compare_rel(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) + { + xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); + + if (lt != xpath_type_node_set && rt != xpath_type_node_set) + return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); + else if (lt == xpath_type_node_set && rt == xpath_type_node_set) + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ls = lhs->eval_node_set(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) + { + xpath_allocator_capture cri(stack.result); + + double l = convert_string_to_number(string_value(*li, stack.result).c_str()); + + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture crii(stack.result); + + if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) + return true; + } + } + + return false; + } + else if (lt != xpath_type_node_set && rt == xpath_type_node_set) + { + xpath_allocator_capture cr(stack.result); + + double l = lhs->eval_number(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture cri(stack.result); + + if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) + return true; + } + + return false; + } + else if (lt == xpath_type_node_set && rt != xpath_type_node_set) + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ls = lhs->eval_node_set(c, stack); + double r = rhs->eval_number(c, stack); + + for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) + { + xpath_allocator_capture cri(stack.result); + + if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r)) + return true; + } + + return false; + } + else + { + assert(!"Wrong types"); + return false; + } + } + + void apply_predicate(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack) + { + assert(ns.size() >= first); + + size_t i = 1; + size_t size = ns.size() - first; + + xpath_node* last = ns.begin() + first; + + // remove_if... or well, sort of + for (xpath_node* it = last; it != ns.end(); ++it, ++i) + { + xpath_context c(*it, i, size); + + if (expr->rettype() == xpath_type_number) + { + if (expr->eval_number(c, stack) == i) + *last++ = *it; + } + else if (expr->eval_boolean(c, stack)) + *last++ = *it; + } + + ns.truncate(last); + } + + void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack) + { + if (ns.size() == first) return; + + for (xpath_ast_node* pred = _right; pred; pred = pred->_next) + { + apply_predicate(ns, first, pred->_left, stack); + } + } + + void step_push(xpath_node_set_raw& ns, const xml_attribute& a, const xml_node& parent, xpath_allocator* alloc) + { + if (!a) return; + + const char_t* name = a.name(); + + // There are no attribute nodes corresponding to attributes that declare namespaces + // That is, "xmlns:..." or "xmlns" + if (starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':')) return; + + switch (_test) + { + case nodetest_name: + if (strequal(name, _data.nodetest)) ns.push_back(xpath_node(a, parent), alloc); + break; + + case nodetest_type_node: + case nodetest_all: + ns.push_back(xpath_node(a, parent), alloc); + break; + + case nodetest_all_in_namespace: + if (starts_with(name, _data.nodetest)) + ns.push_back(xpath_node(a, parent), alloc); + break; + + default: + ; + } + } + + void step_push(xpath_node_set_raw& ns, const xml_node& n, xpath_allocator* alloc) + { + if (!n) return; + + switch (_test) + { + case nodetest_name: + if (n.type() == node_element && strequal(n.name(), _data.nodetest)) ns.push_back(n, alloc); + break; + + case nodetest_type_node: + ns.push_back(n, alloc); + break; + + case nodetest_type_comment: + if (n.type() == node_comment) + ns.push_back(n, alloc); + break; + + case nodetest_type_text: + if (n.type() == node_pcdata || n.type() == node_cdata) + ns.push_back(n, alloc); + break; + + case nodetest_type_pi: + if (n.type() == node_pi) + ns.push_back(n, alloc); + break; + + case nodetest_pi: + if (n.type() == node_pi && strequal(n.name(), _data.nodetest)) + ns.push_back(n, alloc); + break; + + case nodetest_all: + if (n.type() == node_element) + ns.push_back(n, alloc); + break; + + case nodetest_all_in_namespace: + if (n.type() == node_element && starts_with(n.name(), _data.nodetest)) + ns.push_back(n, alloc); + break; + + default: + assert(!"Unknown axis"); + } + } + + template void step_fill(xpath_node_set_raw& ns, const xml_node& n, xpath_allocator* alloc, T) + { + const axis_t axis = T::axis; + + switch (axis) + { + case axis_attribute: + { + for (xml_attribute a = n.first_attribute(); a; a = a.next_attribute()) + step_push(ns, a, n, alloc); + + break; + } + + case axis_child: + { + for (xml_node c = n.first_child(); c; c = c.next_sibling()) + step_push(ns, c, alloc); + + break; + } + + case axis_descendant: + case axis_descendant_or_self: + { + if (axis == axis_descendant_or_self) + step_push(ns, n, alloc); + + xml_node cur = n.first_child(); + + while (cur && cur != n) + { + step_push(ns, cur, alloc); + + if (cur.first_child()) + cur = cur.first_child(); + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + while (!cur.next_sibling() && cur != n) + cur = cur.parent(); + + if (cur != n) cur = cur.next_sibling(); + } + } + + break; + } + + case axis_following_sibling: + { + for (xml_node c = n.next_sibling(); c; c = c.next_sibling()) + step_push(ns, c, alloc); + + break; + } + + case axis_preceding_sibling: + { + for (xml_node c = n.previous_sibling(); c; c = c.previous_sibling()) + step_push(ns, c, alloc); + + break; + } + + case axis_following: + { + xml_node cur = n; + + // exit from this node so that we don't include descendants + while (cur && !cur.next_sibling()) cur = cur.parent(); + cur = cur.next_sibling(); + + for (;;) + { + step_push(ns, cur, alloc); + + if (cur.first_child()) + cur = cur.first_child(); + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + while (cur && !cur.next_sibling()) cur = cur.parent(); + cur = cur.next_sibling(); + + if (!cur) break; + } + } + + break; + } + + case axis_preceding: + { + xml_node cur = n; + + while (cur && !cur.previous_sibling()) cur = cur.parent(); + cur = cur.previous_sibling(); + + for (;;) + { + if (cur.last_child()) + cur = cur.last_child(); + else + { + // leaf node, can't be ancestor + step_push(ns, cur, alloc); + + if (cur.previous_sibling()) + cur = cur.previous_sibling(); + else + { + do + { + cur = cur.parent(); + if (!cur) break; + + if (!node_is_ancestor(cur, n)) step_push(ns, cur, alloc); + } + while (!cur.previous_sibling()); + + cur = cur.previous_sibling(); + + if (!cur) break; + } + } + } + + break; + } + + case axis_ancestor: + case axis_ancestor_or_self: + { + if (axis == axis_ancestor_or_self) + step_push(ns, n, alloc); + + xml_node cur = n.parent(); + + while (cur) + { + step_push(ns, cur, alloc); + + cur = cur.parent(); + } + + break; + } + + case axis_self: + { + step_push(ns, n, alloc); + + break; + } + + case axis_parent: + { + if (n.parent()) step_push(ns, n.parent(), alloc); + + break; + } + + default: + assert(!"Unimplemented axis"); + } + } + + template void step_fill(xpath_node_set_raw& ns, const xml_attribute& a, const xml_node& p, xpath_allocator* alloc, T v) + { + const axis_t axis = T::axis; + + switch (axis) + { + case axis_ancestor: + case axis_ancestor_or_self: + { + if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test + step_push(ns, a, p, alloc); + + xml_node cur = p; + + while (cur) + { + step_push(ns, cur, alloc); + + cur = cur.parent(); + } + + break; + } + + case axis_descendant_or_self: + case axis_self: + { + if (_test == nodetest_type_node) // reject attributes based on principal node type test + step_push(ns, a, p, alloc); + + break; + } + + case axis_following: + { + xml_node cur = p; + + for (;;) + { + if (cur.first_child()) + cur = cur.first_child(); + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + while (cur && !cur.next_sibling()) cur = cur.parent(); + cur = cur.next_sibling(); + + if (!cur) break; + } + + step_push(ns, cur, alloc); + } + + break; + } + + case axis_parent: + { + step_push(ns, p, alloc); + + break; + } + + case axis_preceding: + { + // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding + step_fill(ns, p, alloc, v); + break; + } + + default: + assert(!"Unimplemented axis"); + } + } + + template xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, T v) + { + const axis_t axis = T::axis; + bool attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self); + + xpath_node_set_raw ns; + ns.set_type((axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling) ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted); + + if (_left) + { + xpath_node_set_raw s = _left->eval_node_set(c, stack); + + // self axis preserves the original order + if (axis == axis_self) ns.set_type(s.type()); + + for (const xpath_node* it = s.begin(); it != s.end(); ++it) + { + size_t size = ns.size(); + + // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes + if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted); + + if (it->node()) + step_fill(ns, it->node(), stack.result, v); + else if (attributes) + step_fill(ns, it->attribute(), it->parent(), stack.result, v); + + apply_predicates(ns, size, stack); + } + } + else + { + if (c.n.node()) + step_fill(ns, c.n.node(), stack.result, v); + else if (attributes) + step_fill(ns, c.n.attribute(), c.n.parent(), stack.result, v); + + apply_predicates(ns, 0, stack); + } + + // child, attribute and self axes always generate unique set of nodes + // for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the same node twice + if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted) + ns.remove_duplicates(); + + return ns; + } + + public: + xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value): + _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) + { + assert(type == ast_string_constant); + _data.string = value; + } + + xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value): + _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) + { + assert(type == ast_number_constant); + _data.number = value; + } + + xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value): + _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) + { + assert(type == ast_variable); + _data.variable = value; + } + + xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = 0, xpath_ast_node* right = 0): + _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0) + { + } + + xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents): + _type(static_cast(type)), _rettype(xpath_type_node_set), _axis(static_cast(axis)), _test(static_cast(test)), _left(left), _right(0), _next(0) + { + _data.nodetest = contents; + } + + void set_next(xpath_ast_node* value) + { + _next = value; + } + + void set_right(xpath_ast_node* value) + { + _right = value; + } + + bool eval_boolean(const xpath_context& c, const xpath_stack& stack) + { + switch (_type) + { + case ast_op_or: + return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack); + + case ast_op_and: + return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack); + + case ast_op_equal: + return compare_eq(_left, _right, c, stack, equal_to()); + + case ast_op_not_equal: + return compare_eq(_left, _right, c, stack, not_equal_to()); + + case ast_op_less: + return compare_rel(_left, _right, c, stack, less()); + + case ast_op_greater: + return compare_rel(_right, _left, c, stack, less()); + + case ast_op_less_or_equal: + return compare_rel(_left, _right, c, stack, less_equal()); + + case ast_op_greater_or_equal: + return compare_rel(_right, _left, c, stack, less_equal()); + + case ast_func_starts_with: + { + xpath_allocator_capture cr(stack.result); + + xpath_string lr = _left->eval_string(c, stack); + xpath_string rr = _right->eval_string(c, stack); + + return starts_with(lr.c_str(), rr.c_str()); + } + + case ast_func_contains: + { + xpath_allocator_capture cr(stack.result); + + xpath_string lr = _left->eval_string(c, stack); + xpath_string rr = _right->eval_string(c, stack); + + return find_substring(lr.c_str(), rr.c_str()) != 0; + } + + case ast_func_boolean: + return _left->eval_boolean(c, stack); + + case ast_func_not: + return !_left->eval_boolean(c, stack); + + case ast_func_true: + return true; + + case ast_func_false: + return false; + + case ast_func_lang: + { + if (c.n.attribute()) return false; + + xpath_allocator_capture cr(stack.result); + + xpath_string lang = _left->eval_string(c, stack); + + for (xml_node n = c.n.node(); n; n = n.parent()) + { + xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang")); + + if (a) + { + const char_t* value = a.value(); + + // strnicmp / strncasecmp is not portable + for (const char_t* lit = lang.c_str(); *lit; ++lit) + { + if (tolower_ascii(*lit) != tolower_ascii(*value)) return false; + ++value; + } + + return *value == 0 || *value == '-'; + } + } + + return false; + } + + case ast_variable: + { + assert(_rettype == _data.variable->type()); + + if (_rettype == xpath_type_boolean) + return _data.variable->get_boolean(); + + // fallthrough to type conversion + } + + default: + { + switch (_rettype) + { + case xpath_type_number: + return convert_number_to_boolean(eval_number(c, stack)); + + case xpath_type_string: + { + xpath_allocator_capture cr(stack.result); + + return !eval_string(c, stack).empty(); + } + + case xpath_type_node_set: + { + xpath_allocator_capture cr(stack.result); + + return !eval_node_set(c, stack).empty(); + } + + default: + assert(!"Wrong expression for return type boolean"); + return false; + } + } + } + } + + double eval_number(const xpath_context& c, const xpath_stack& stack) + { + switch (_type) + { + case ast_op_add: + return _left->eval_number(c, stack) + _right->eval_number(c, stack); + + case ast_op_subtract: + return _left->eval_number(c, stack) - _right->eval_number(c, stack); + + case ast_op_multiply: + return _left->eval_number(c, stack) * _right->eval_number(c, stack); + + case ast_op_divide: + return _left->eval_number(c, stack) / _right->eval_number(c, stack); + + case ast_op_mod: + return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack)); + + case ast_op_negate: + return -_left->eval_number(c, stack); + + case ast_number_constant: + return _data.number; + + case ast_func_last: + return static_cast(c.size); + + case ast_func_position: + return static_cast(c.position); + + case ast_func_count: + { + xpath_allocator_capture cr(stack.result); + + return static_cast(_left->eval_node_set(c, stack).size()); + } + + case ast_func_string_length_0: + { + xpath_allocator_capture cr(stack.result); + + return static_cast(string_value(c.n, stack.result).length()); + } + + case ast_func_string_length_1: + { + xpath_allocator_capture cr(stack.result); + + return static_cast(_left->eval_string(c, stack).length()); + } + + case ast_func_number_0: + { + xpath_allocator_capture cr(stack.result); + + return convert_string_to_number(string_value(c.n, stack.result).c_str()); + } + + case ast_func_number_1: + return _left->eval_number(c, stack); + + case ast_func_sum: + { + xpath_allocator_capture cr(stack.result); + + double r = 0; + + xpath_node_set_raw ns = _left->eval_node_set(c, stack); + + for (const xpath_node* it = ns.begin(); it != ns.end(); ++it) + { + xpath_allocator_capture cri(stack.result); + + r += convert_string_to_number(string_value(*it, stack.result).c_str()); + } + + return r; + } + + case ast_func_floor: + { + double r = _left->eval_number(c, stack); + + return r == r ? floor(r) : r; + } + + case ast_func_ceiling: + { + double r = _left->eval_number(c, stack); + + return r == r ? ceil(r) : r; + } + + case ast_func_round: + return round_nearest_nzero(_left->eval_number(c, stack)); + + case ast_variable: + { + assert(_rettype == _data.variable->type()); + + if (_rettype == xpath_type_number) + return _data.variable->get_number(); + + // fallthrough to type conversion + } + + default: + { + switch (_rettype) + { + case xpath_type_boolean: + return eval_boolean(c, stack) ? 1 : 0; + + case xpath_type_string: + { + xpath_allocator_capture cr(stack.result); + + return convert_string_to_number(eval_string(c, stack).c_str()); + } + + case xpath_type_node_set: + { + xpath_allocator_capture cr(stack.result); + + return convert_string_to_number(eval_string(c, stack).c_str()); + } + + default: + assert(!"Wrong expression for return type number"); + return 0; + } + + } + } + } + + xpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack) + { + assert(_type == ast_func_concat); + + xpath_allocator_capture ct(stack.temp); + + // count the string number + size_t count = 1; + for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++; + + // gather all strings + xpath_string static_buffer[4]; + xpath_string* buffer = static_buffer; + + // allocate on-heap for large concats + if (count > sizeof(static_buffer) / sizeof(static_buffer[0])) + { + buffer = static_cast(stack.temp->allocate(count * sizeof(xpath_string))); + assert(buffer); + } + + // evaluate all strings to temporary stack + xpath_stack swapped_stack = {stack.temp, stack.result}; + + buffer[0] = _left->eval_string(c, swapped_stack); + + size_t pos = 1; + for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack); + assert(pos == count); + + // get total length + size_t length = 0; + for (size_t i = 0; i < count; ++i) length += buffer[i].length(); + + // create final string + char_t* result = static_cast(stack.result->allocate((length + 1) * sizeof(char_t))); + assert(result); + + char_t* ri = result; + + for (size_t j = 0; j < count; ++j) + for (const char_t* bi = buffer[j].c_str(); *bi; ++bi) + *ri++ = *bi; + + *ri = 0; + + return xpath_string(result, true); + } + + xpath_string eval_string(const xpath_context& c, const xpath_stack& stack) + { + switch (_type) + { + case ast_string_constant: + return xpath_string_const(_data.string); + + case ast_func_local_name_0: + { + xpath_node na = c.n; + + return xpath_string_const(local_name(na)); + } + + case ast_func_local_name_1: + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ns = _left->eval_node_set(c, stack); + xpath_node na = ns.first(); + + return xpath_string_const(local_name(na)); + } + + case ast_func_name_0: + { + xpath_node na = c.n; + + return xpath_string_const(qualified_name(na)); + } + + case ast_func_name_1: + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ns = _left->eval_node_set(c, stack); + xpath_node na = ns.first(); + + return xpath_string_const(qualified_name(na)); + } + + case ast_func_namespace_uri_0: + { + xpath_node na = c.n; + + return xpath_string_const(namespace_uri(na)); + } + + case ast_func_namespace_uri_1: + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ns = _left->eval_node_set(c, stack); + xpath_node na = ns.first(); + + return xpath_string_const(namespace_uri(na)); + } + + case ast_func_string_0: + return string_value(c.n, stack.result); + + case ast_func_string_1: + return _left->eval_string(c, stack); + + case ast_func_concat: + return eval_string_concat(c, stack); + + case ast_func_substring_before: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, swapped_stack); + xpath_string p = _right->eval_string(c, swapped_stack); + + const char_t* pos = find_substring(s.c_str(), p.c_str()); + + return pos ? xpath_string(s.c_str(), pos, stack.result) : xpath_string(); + } + + case ast_func_substring_after: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, swapped_stack); + xpath_string p = _right->eval_string(c, swapped_stack); + + const char_t* pos = find_substring(s.c_str(), p.c_str()); + if (!pos) return xpath_string(); + + const char_t* result = pos + p.length(); + + return s.uses_heap() ? xpath_string(result, stack.result) : xpath_string_const(result); + } + + case ast_func_substring_2: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, swapped_stack); + size_t s_length = s.length(); + + double first = round_nearest(_right->eval_number(c, stack)); + + if (is_nan(first)) return xpath_string(); // NaN + else if (first >= s_length + 1) return xpath_string(); + + size_t pos = first < 1 ? 1 : static_cast(first); + assert(1 <= pos && pos <= s_length + 1); + + const char_t* rbegin = s.c_str() + (pos - 1); + + return s.uses_heap() ? xpath_string(rbegin, stack.result) : xpath_string_const(rbegin); + } + + case ast_func_substring_3: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, swapped_stack); + size_t s_length = s.length(); + + double first = round_nearest(_right->eval_number(c, stack)); + double last = first + round_nearest(_right->_next->eval_number(c, stack)); + + if (is_nan(first) || is_nan(last)) return xpath_string(); + else if (first >= s_length + 1) return xpath_string(); + else if (first >= last) return xpath_string(); + else if (last < 1) return xpath_string(); + + size_t pos = first < 1 ? 1 : static_cast(first); + size_t end = last >= s_length + 1 ? s_length + 1 : static_cast(last); + + assert(1 <= pos && pos <= end && end <= s_length + 1); + const char_t* rbegin = s.c_str() + (pos - 1); + const char_t* rend = s.c_str() + (end - 1); + + return (end == s_length + 1 && !s.uses_heap()) ? xpath_string_const(rbegin) : xpath_string(rbegin, rend, stack.result); + } + + case ast_func_normalize_space_0: + { + xpath_string s = string_value(c.n, stack.result); + + normalize_space(s.data(stack.result)); + + return s; + } + + case ast_func_normalize_space_1: + { + xpath_string s = _left->eval_string(c, stack); + + normalize_space(s.data(stack.result)); + + return s; + } + + case ast_func_translate: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, stack); + xpath_string from = _right->eval_string(c, swapped_stack); + xpath_string to = _right->_next->eval_string(c, swapped_stack); + + translate(s.data(stack.result), from.c_str(), to.c_str()); + + return s; + } + + case ast_variable: + { + assert(_rettype == _data.variable->type()); + + if (_rettype == xpath_type_string) + return xpath_string_const(_data.variable->get_string()); + + // fallthrough to type conversion + } + + default: + { + switch (_rettype) + { + case xpath_type_boolean: + return xpath_string_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); + + case xpath_type_number: + return convert_number_to_string(eval_number(c, stack), stack.result); + + case xpath_type_node_set: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_node_set_raw ns = eval_node_set(c, swapped_stack); + return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result); + } + + default: + assert(!"Wrong expression for return type string"); + return xpath_string(); + } + } + } + } + + xpath_node_set_raw eval_node_set(const xpath_context& c, const xpath_stack& stack) + { + switch (_type) + { + case ast_op_union: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack); + xpath_node_set_raw rs = _right->eval_node_set(c, stack); + + // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother + rs.set_type(xpath_node_set::type_unsorted); + + rs.append(ls.begin(), ls.end(), stack.result); + rs.remove_duplicates(); + + return rs; + } + + case ast_filter: + case ast_filter_posinv: + { + xpath_node_set_raw set = _left->eval_node_set(c, stack); + + // either expression is a number or it contains position() call; sort by document order + if (_type == ast_filter) set.sort_do(); + + apply_predicate(set, 0, _right, stack); + + return set; + } + + case ast_func_id: + return xpath_node_set_raw(); + + case ast_step: + { + switch (_axis) + { + case axis_ancestor: + return step_do(c, stack, axis_to_type()); + + case axis_ancestor_or_self: + return step_do(c, stack, axis_to_type()); + + case axis_attribute: + return step_do(c, stack, axis_to_type()); + + case axis_child: + return step_do(c, stack, axis_to_type()); + + case axis_descendant: + return step_do(c, stack, axis_to_type()); + + case axis_descendant_or_self: + return step_do(c, stack, axis_to_type()); + + case axis_following: + return step_do(c, stack, axis_to_type()); + + case axis_following_sibling: + return step_do(c, stack, axis_to_type()); + + case axis_namespace: + // namespaced axis is not supported + return xpath_node_set_raw(); + + case axis_parent: + return step_do(c, stack, axis_to_type()); + + case axis_preceding: + return step_do(c, stack, axis_to_type()); + + case axis_preceding_sibling: + return step_do(c, stack, axis_to_type()); + + case axis_self: + return step_do(c, stack, axis_to_type()); + + default: + assert(!"Unknown axis"); + return xpath_node_set_raw(); + } + } + + case ast_step_root: + { + assert(!_right); // root step can't have any predicates + + xpath_node_set_raw ns; + + ns.set_type(xpath_node_set::type_sorted); + + if (c.n.node()) ns.push_back(c.n.node().root(), stack.result); + else if (c.n.attribute()) ns.push_back(c.n.parent().root(), stack.result); + + return ns; + } + + case ast_variable: + { + assert(_rettype == _data.variable->type()); + + if (_rettype == xpath_type_node_set) + { + const xpath_node_set& s = _data.variable->get_node_set(); + + xpath_node_set_raw ns; + + ns.set_type(s.type()); + ns.append(s.begin(), s.end(), stack.result); + + return ns; + } + + // fallthrough to type conversion + } + + default: + assert(!"Wrong expression for return type node set"); + return xpath_node_set_raw(); + } + } + + bool is_posinv() + { + switch (_type) + { + case ast_func_position: + return false; + + case ast_string_constant: + case ast_number_constant: + case ast_variable: + return true; + + case ast_step: + case ast_step_root: + return true; + + case ast_predicate: + case ast_filter: + case ast_filter_posinv: + return true; + + default: + if (_left && !_left->is_posinv()) return false; + + for (xpath_ast_node* n = _right; n; n = n->_next) + if (!n->is_posinv()) return false; + + return true; + } + } + + xpath_value_type rettype() const + { + return static_cast(_rettype); + } + }; + + struct xpath_parser + { + xpath_allocator* _alloc; + xpath_lexer _lexer; + + const char_t* _query; + xpath_variable_set* _variables; + + xpath_parse_result* _result; + + #ifdef PUGIXML_NO_EXCEPTIONS + jmp_buf _error_handler; + #endif + + void throw_error(const char* message) + { + _result->error = message; + _result->offset = _lexer.current_pos() - _query; + + #ifdef PUGIXML_NO_EXCEPTIONS + longjmp(_error_handler, 1); + #else + throw xpath_exception(*_result); + #endif + } + + void throw_error_oom() + { + #ifdef PUGIXML_NO_EXCEPTIONS + throw_error("Out of memory"); + #else + throw std::bad_alloc(); + #endif + } + + void* alloc_node() + { + void* result = _alloc->allocate_nothrow(sizeof(xpath_ast_node)); + + if (!result) throw_error_oom(); + + return result; + } + + const char_t* alloc_string(const xpath_lexer_string& value) + { + if (value.begin) + { + size_t length = static_cast(value.end - value.begin); + + char_t* c = static_cast(_alloc->allocate_nothrow((length + 1) * sizeof(char_t))); + if (!c) throw_error_oom(); + + memcpy(c, value.begin, length * sizeof(char_t)); + c[length] = 0; + + return c; + } + else return 0; + } + + xpath_ast_node* parse_function_helper(ast_type_t type0, ast_type_t type1, size_t argc, xpath_ast_node* args[2]) + { + assert(argc <= 1); + + if (argc == 1 && args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); + + return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]); + } + + xpath_ast_node* parse_function(const xpath_lexer_string& name, size_t argc, xpath_ast_node* args[2]) + { + switch (name.begin[0]) + { + case 'b': + if (name == PUGIXML_TEXT("boolean") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]); + + break; + + case 'c': + if (name == PUGIXML_TEXT("count") && argc == 1) + { + if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); + return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]); + } + else if (name == PUGIXML_TEXT("contains") && argc == 2) + return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("concat") && argc >= 2) + return new (alloc_node()) xpath_ast_node(ast_func_concat, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("ceiling") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]); + + break; + + case 'f': + if (name == PUGIXML_TEXT("false") && argc == 0) + return new (alloc_node()) xpath_ast_node(ast_func_false, xpath_type_boolean); + else if (name == PUGIXML_TEXT("floor") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]); + + break; + + case 'i': + if (name == PUGIXML_TEXT("id") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]); + + break; + + case 'l': + if (name == PUGIXML_TEXT("last") && argc == 0) + return new (alloc_node()) xpath_ast_node(ast_func_last, xpath_type_number); + else if (name == PUGIXML_TEXT("lang") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_lang, xpath_type_boolean, args[0]); + else if (name == PUGIXML_TEXT("local-name") && argc <= 1) + return parse_function_helper(ast_func_local_name_0, ast_func_local_name_1, argc, args); + + break; + + case 'n': + if (name == PUGIXML_TEXT("name") && argc <= 1) + return parse_function_helper(ast_func_name_0, ast_func_name_1, argc, args); + else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1) + return parse_function_helper(ast_func_namespace_uri_0, ast_func_namespace_uri_1, argc, args); + else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1) + return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("not") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_not, xpath_type_boolean, args[0]); + else if (name == PUGIXML_TEXT("number") && argc <= 1) + return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]); + + break; + + case 'p': + if (name == PUGIXML_TEXT("position") && argc == 0) + return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number); + + break; + + case 'r': + if (name == PUGIXML_TEXT("round") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_round, xpath_type_number, args[0]); + + break; + + case 's': + if (name == PUGIXML_TEXT("string") && argc <= 1) + return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]); + else if (name == PUGIXML_TEXT("string-length") && argc <= 1) + return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_string, args[0]); + else if (name == PUGIXML_TEXT("starts-with") && argc == 2) + return new (alloc_node()) xpath_ast_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]); + else if (name == PUGIXML_TEXT("substring-before") && argc == 2) + return new (alloc_node()) xpath_ast_node(ast_func_substring_before, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("substring-after") && argc == 2) + return new (alloc_node()) xpath_ast_node(ast_func_substring_after, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3)) + return new (alloc_node()) xpath_ast_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("sum") && argc == 1) + { + if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); + return new (alloc_node()) xpath_ast_node(ast_func_sum, xpath_type_number, args[0]); + } + + break; + + case 't': + if (name == PUGIXML_TEXT("translate") && argc == 3) + return new (alloc_node()) xpath_ast_node(ast_func_translate, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("true") && argc == 0) + return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean); + + break; + + default: + break; + } + + throw_error("Unrecognized function or wrong parameter count"); + + return 0; + } + + axis_t parse_axis_name(const xpath_lexer_string& name, bool& specified) + { + specified = true; + + switch (name.begin[0]) + { + case 'a': + if (name == PUGIXML_TEXT("ancestor")) + return axis_ancestor; + else if (name == PUGIXML_TEXT("ancestor-or-self")) + return axis_ancestor_or_self; + else if (name == PUGIXML_TEXT("attribute")) + return axis_attribute; + + break; + + case 'c': + if (name == PUGIXML_TEXT("child")) + return axis_child; + + break; + + case 'd': + if (name == PUGIXML_TEXT("descendant")) + return axis_descendant; + else if (name == PUGIXML_TEXT("descendant-or-self")) + return axis_descendant_or_self; + + break; + + case 'f': + if (name == PUGIXML_TEXT("following")) + return axis_following; + else if (name == PUGIXML_TEXT("following-sibling")) + return axis_following_sibling; + + break; + + case 'n': + if (name == PUGIXML_TEXT("namespace")) + return axis_namespace; + + break; + + case 'p': + if (name == PUGIXML_TEXT("parent")) + return axis_parent; + else if (name == PUGIXML_TEXT("preceding")) + return axis_preceding; + else if (name == PUGIXML_TEXT("preceding-sibling")) + return axis_preceding_sibling; + + break; + + case 's': + if (name == PUGIXML_TEXT("self")) + return axis_self; + + break; + + default: + break; + } + + specified = false; + return axis_child; + } + + nodetest_t parse_node_test_type(const xpath_lexer_string& name) + { + switch (name.begin[0]) + { + case 'c': + if (name == PUGIXML_TEXT("comment")) + return nodetest_type_comment; + + break; + + case 'n': + if (name == PUGIXML_TEXT("node")) + return nodetest_type_node; + + break; + + case 'p': + if (name == PUGIXML_TEXT("processing-instruction")) + return nodetest_type_pi; + + break; + + case 't': + if (name == PUGIXML_TEXT("text")) + return nodetest_type_text; + + break; + + default: + break; + } + + return nodetest_none; + } + + // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall + xpath_ast_node* parse_primary_expression() + { + switch (_lexer.current()) + { + case lex_var_ref: + { + xpath_lexer_string name = _lexer.contents(); + + if (!_variables) + throw_error("Unknown variable: variable set is not provided"); + + xpath_variable* var = get_variable(_variables, name.begin, name.end); + + if (!var) + throw_error("Unknown variable: variable set does not contain the given name"); + + _lexer.next(); + + return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), var); + } + + case lex_open_brace: + { + _lexer.next(); + + xpath_ast_node* n = parse_expression(); + + if (_lexer.current() != lex_close_brace) + throw_error("Unmatched braces"); + + _lexer.next(); + + return n; + } + + case lex_quoted_string: + { + const char_t* value = alloc_string(_lexer.contents()); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_string_constant, xpath_type_string, value); + _lexer.next(); + + return n; + } + + case lex_number: + { + double value = 0; + + if (!convert_string_to_number(_lexer.contents().begin, _lexer.contents().end, &value)) + throw_error_oom(); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_number_constant, xpath_type_number, value); + _lexer.next(); + + return n; + } + + case lex_string: + { + xpath_ast_node* args[2] = {0}; + size_t argc = 0; + + xpath_lexer_string function = _lexer.contents(); + _lexer.next(); + + xpath_ast_node* last_arg = 0; + + if (_lexer.current() != lex_open_brace) + throw_error("Unrecognized function call"); + _lexer.next(); + + if (_lexer.current() != lex_close_brace) + args[argc++] = parse_expression(); + + while (_lexer.current() != lex_close_brace) + { + if (_lexer.current() != lex_comma) + throw_error("No comma between function arguments"); + _lexer.next(); + + xpath_ast_node* n = parse_expression(); + + if (argc < 2) args[argc] = n; + else last_arg->set_next(n); + + argc++; + last_arg = n; + } + + _lexer.next(); + + return parse_function(function, argc, args); + } + + default: + throw_error("Unrecognizable primary expression"); + + return 0; + } + } + + // FilterExpr ::= PrimaryExpr | FilterExpr Predicate + // Predicate ::= '[' PredicateExpr ']' + // PredicateExpr ::= Expr + xpath_ast_node* parse_filter_expression() + { + xpath_ast_node* n = parse_primary_expression(); + + while (_lexer.current() == lex_open_square_brace) + { + _lexer.next(); + + xpath_ast_node* expr = parse_expression(); + + if (n->rettype() != xpath_type_node_set) throw_error("Predicate has to be applied to node set"); + + bool posinv = expr->rettype() != xpath_type_number && expr->is_posinv(); + + n = new (alloc_node()) xpath_ast_node(posinv ? ast_filter_posinv : ast_filter, xpath_type_node_set, n, expr); + + if (_lexer.current() != lex_close_square_brace) + throw_error("Unmatched square brace"); + + _lexer.next(); + } + + return n; + } + + // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep + // AxisSpecifier ::= AxisName '::' | '@'? + // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')' + // NameTest ::= '*' | NCName ':' '*' | QName + // AbbreviatedStep ::= '.' | '..' + xpath_ast_node* parse_step(xpath_ast_node* set) + { + if (set && set->rettype() != xpath_type_node_set) + throw_error("Step has to be applied to node set"); + + bool axis_specified = false; + axis_t axis = axis_child; // implied child axis + + if (_lexer.current() == lex_axis_attribute) + { + axis = axis_attribute; + axis_specified = true; + + _lexer.next(); + } + else if (_lexer.current() == lex_dot) + { + _lexer.next(); + + return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0); + } + else if (_lexer.current() == lex_double_dot) + { + _lexer.next(); + + return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0); + } + + nodetest_t nt_type = nodetest_none; + xpath_lexer_string nt_name; + + if (_lexer.current() == lex_string) + { + // node name test + nt_name = _lexer.contents(); + _lexer.next(); + + // was it an axis name? + if (_lexer.current() == lex_double_colon) + { + // parse axis name + if (axis_specified) throw_error("Two axis specifiers in one step"); + + axis = parse_axis_name(nt_name, axis_specified); + + if (!axis_specified) throw_error("Unknown axis"); + + // read actual node test + _lexer.next(); + + if (_lexer.current() == lex_multiply) + { + nt_type = nodetest_all; + nt_name = xpath_lexer_string(); + _lexer.next(); + } + else if (_lexer.current() == lex_string) + { + nt_name = _lexer.contents(); + _lexer.next(); + } + else throw_error("Unrecognized node test"); + } + + if (nt_type == nodetest_none) + { + // node type test or processing-instruction + if (_lexer.current() == lex_open_brace) + { + _lexer.next(); + + if (_lexer.current() == lex_close_brace) + { + _lexer.next(); + + nt_type = parse_node_test_type(nt_name); + + if (nt_type == nodetest_none) throw_error("Unrecognized node type"); + + nt_name = xpath_lexer_string(); + } + else if (nt_name == PUGIXML_TEXT("processing-instruction")) + { + if (_lexer.current() != lex_quoted_string) + throw_error("Only literals are allowed as arguments to processing-instruction()"); + + nt_type = nodetest_pi; + nt_name = _lexer.contents(); + _lexer.next(); + + if (_lexer.current() != lex_close_brace) + throw_error("Unmatched brace near processing-instruction()"); + _lexer.next(); + } + else + throw_error("Unmatched brace near node type test"); + + } + // QName or NCName:* + else + { + if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:* + { + nt_name.end--; // erase * + + nt_type = nodetest_all_in_namespace; + } + else nt_type = nodetest_name; + } + } + } + else if (_lexer.current() == lex_multiply) + { + nt_type = nodetest_all; + _lexer.next(); + } + else throw_error("Unrecognized node test"); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, alloc_string(nt_name)); + + xpath_ast_node* last = 0; + + while (_lexer.current() == lex_open_square_brace) + { + _lexer.next(); + + xpath_ast_node* expr = parse_expression(); + + xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, xpath_type_node_set, expr); + + if (_lexer.current() != lex_close_square_brace) + throw_error("Unmatched square brace"); + _lexer.next(); + + if (last) last->set_next(pred); + else n->set_right(pred); + + last = pred; + } + + return n; + } + + // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step + xpath_ast_node* parse_relative_location_path(xpath_ast_node* set) + { + xpath_ast_node* n = parse_step(set); + + while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) + { + lexeme_t l = _lexer.current(); + _lexer.next(); + + if (l == lex_double_slash) + n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); + + n = parse_step(n); + } + + return n; + } + + // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath + // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath + xpath_ast_node* parse_location_path() + { + if (_lexer.current() == lex_slash) + { + _lexer.next(); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); + + // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path + lexeme_t l = _lexer.current(); + + if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply) + return parse_relative_location_path(n); + else + return n; + } + else if (_lexer.current() == lex_double_slash) + { + _lexer.next(); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); + n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); + + return parse_relative_location_path(n); + } + + // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1 + return parse_relative_location_path(0); + } + + // PathExpr ::= LocationPath + // | FilterExpr + // | FilterExpr '/' RelativeLocationPath + // | FilterExpr '//' RelativeLocationPath + xpath_ast_node* parse_path_expression() + { + // Clarification. + // PathExpr begins with either LocationPath or FilterExpr. + // FilterExpr begins with PrimaryExpr + // PrimaryExpr begins with '$' in case of it being a variable reference, + // '(' in case of it being an expression, string literal, number constant or + // function call. + + if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || + _lexer.current() == lex_quoted_string || _lexer.current() == lex_number || + _lexer.current() == lex_string) + { + if (_lexer.current() == lex_string) + { + // This is either a function call, or not - if not, we shall proceed with location path + const char_t* state = _lexer.state(); + + while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state; + + if (*state != '(') return parse_location_path(); + + // This looks like a function call; however this still can be a node-test. Check it. + if (parse_node_test_type(_lexer.contents()) != nodetest_none) return parse_location_path(); + } + + xpath_ast_node* n = parse_filter_expression(); + + if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) + { + lexeme_t l = _lexer.current(); + _lexer.next(); + + if (l == lex_double_slash) + { + if (n->rettype() != xpath_type_node_set) throw_error("Step has to be applied to node set"); + + n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); + } + + // select from location path + return parse_relative_location_path(n); + } + + return n; + } + else return parse_location_path(); + } + + // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr + xpath_ast_node* parse_union_expression() + { + xpath_ast_node* n = parse_path_expression(); + + while (_lexer.current() == lex_union) + { + _lexer.next(); + + xpath_ast_node* expr = parse_union_expression(); + + if (n->rettype() != xpath_type_node_set || expr->rettype() != xpath_type_node_set) + throw_error("Union operator has to be applied to node sets"); + + n = new (alloc_node()) xpath_ast_node(ast_op_union, xpath_type_node_set, n, expr); + } + + return n; + } + + // UnaryExpr ::= UnionExpr | '-' UnaryExpr + xpath_ast_node* parse_unary_expression() + { + if (_lexer.current() == lex_minus) + { + _lexer.next(); + + xpath_ast_node* expr = parse_unary_expression(); + + return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr); + } + else return parse_union_expression(); + } + + // MultiplicativeExpr ::= UnaryExpr + // | MultiplicativeExpr '*' UnaryExpr + // | MultiplicativeExpr 'div' UnaryExpr + // | MultiplicativeExpr 'mod' UnaryExpr + xpath_ast_node* parse_multiplicative_expression() + { + xpath_ast_node* n = parse_unary_expression(); + + while (_lexer.current() == lex_multiply || (_lexer.current() == lex_string && + (_lexer.contents() == PUGIXML_TEXT("mod") || _lexer.contents() == PUGIXML_TEXT("div")))) + { + ast_type_t op = _lexer.current() == lex_multiply ? ast_op_multiply : + _lexer.contents().begin[0] == 'd' ? ast_op_divide : ast_op_mod; + _lexer.next(); + + xpath_ast_node* expr = parse_unary_expression(); + + n = new (alloc_node()) xpath_ast_node(op, xpath_type_number, n, expr); + } + + return n; + } + + // AdditiveExpr ::= MultiplicativeExpr + // | AdditiveExpr '+' MultiplicativeExpr + // | AdditiveExpr '-' MultiplicativeExpr + xpath_ast_node* parse_additive_expression() + { + xpath_ast_node* n = parse_multiplicative_expression(); + + while (_lexer.current() == lex_plus || _lexer.current() == lex_minus) + { + lexeme_t l = _lexer.current(); + + _lexer.next(); + + xpath_ast_node* expr = parse_multiplicative_expression(); + + n = new (alloc_node()) xpath_ast_node(l == lex_plus ? ast_op_add : ast_op_subtract, xpath_type_number, n, expr); + } + + return n; + } + + // RelationalExpr ::= AdditiveExpr + // | RelationalExpr '<' AdditiveExpr + // | RelationalExpr '>' AdditiveExpr + // | RelationalExpr '<=' AdditiveExpr + // | RelationalExpr '>=' AdditiveExpr + xpath_ast_node* parse_relational_expression() + { + xpath_ast_node* n = parse_additive_expression(); + + while (_lexer.current() == lex_less || _lexer.current() == lex_less_or_equal || + _lexer.current() == lex_greater || _lexer.current() == lex_greater_or_equal) + { + lexeme_t l = _lexer.current(); + _lexer.next(); + + xpath_ast_node* expr = parse_additive_expression(); + + n = new (alloc_node()) xpath_ast_node(l == lex_less ? ast_op_less : l == lex_greater ? ast_op_greater : + l == lex_less_or_equal ? ast_op_less_or_equal : ast_op_greater_or_equal, xpath_type_boolean, n, expr); + } + + return n; + } + + // EqualityExpr ::= RelationalExpr + // | EqualityExpr '=' RelationalExpr + // | EqualityExpr '!=' RelationalExpr + xpath_ast_node* parse_equality_expression() + { + xpath_ast_node* n = parse_relational_expression(); + + while (_lexer.current() == lex_equal || _lexer.current() == lex_not_equal) + { + lexeme_t l = _lexer.current(); + + _lexer.next(); + + xpath_ast_node* expr = parse_relational_expression(); + + n = new (alloc_node()) xpath_ast_node(l == lex_equal ? ast_op_equal : ast_op_not_equal, xpath_type_boolean, n, expr); + } + + return n; + } + + // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr + xpath_ast_node* parse_and_expression() + { + xpath_ast_node* n = parse_equality_expression(); + + while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT("and")) + { + _lexer.next(); + + xpath_ast_node* expr = parse_equality_expression(); + + n = new (alloc_node()) xpath_ast_node(ast_op_and, xpath_type_boolean, n, expr); + } + + return n; + } + + // OrExpr ::= AndExpr | OrExpr 'or' AndExpr + xpath_ast_node* parse_or_expression() + { + xpath_ast_node* n = parse_and_expression(); + + while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT("or")) + { + _lexer.next(); + + xpath_ast_node* expr = parse_and_expression(); + + n = new (alloc_node()) xpath_ast_node(ast_op_or, xpath_type_boolean, n, expr); + } + + return n; + } + + // Expr ::= OrExpr + xpath_ast_node* parse_expression() + { + return parse_or_expression(); + } + + xpath_parser(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result) + { + } + + xpath_ast_node* parse() + { + xpath_ast_node* result = parse_expression(); + + if (_lexer.current() != lex_eof) + { + // there are still unparsed tokens left, error + throw_error("Incorrect query"); + } + + return result; + } + + static xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result) + { + xpath_parser parser(query, variables, alloc, result); + + #ifdef PUGIXML_NO_EXCEPTIONS + int error = setjmp(parser._error_handler); + + return (error == 0) ? parser.parse() : 0; + #else + return parser.parse(); + #endif + } + }; + + struct xpath_query_impl + { + static xpath_query_impl* create() + { + void* memory = xml_memory::allocate(sizeof(xpath_query_impl)); + + return new (memory) xpath_query_impl(); + } + + static void destroy(void* ptr) + { + if (!ptr) return; + + // free all allocated pages + static_cast(ptr)->alloc.release(); + + // free allocator memory (with the first page) + xml_memory::deallocate(ptr); + } + + xpath_query_impl(): root(0), alloc(&block) + { + block.next = 0; + } + + xpath_ast_node* root; + xpath_allocator alloc; + xpath_memory_block block; + }; + + PUGI__FN xpath_string evaluate_string_impl(xpath_query_impl* impl, const xpath_node& n, xpath_stack_data& sd) + { + if (!impl) return xpath_string(); + + #ifdef PUGIXML_NO_EXCEPTIONS + if (setjmp(sd.error_handler)) return xpath_string(); + #endif + + xpath_context c(n, 1, 1); + + return impl->root->eval_string(c, sd.stack); + } +PUGI__NS_END + +namespace pugi +{ +#ifndef PUGIXML_NO_EXCEPTIONS + PUGI__FN xpath_exception::xpath_exception(const xpath_parse_result& result_): _result(result_) + { + assert(_result.error); + } + + PUGI__FN const char* xpath_exception::what() const throw() + { + return _result.error; + } + + PUGI__FN const xpath_parse_result& xpath_exception::result() const + { + return _result; + } +#endif + + PUGI__FN xpath_node::xpath_node() + { + } + + PUGI__FN xpath_node::xpath_node(const xml_node& node_): _node(node_) + { + } + + PUGI__FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_) + { + } + + PUGI__FN xml_node xpath_node::node() const + { + return _attribute ? xml_node() : _node; + } + + PUGI__FN xml_attribute xpath_node::attribute() const + { + return _attribute; + } + + PUGI__FN xml_node xpath_node::parent() const + { + return _attribute ? _node : _node.parent(); + } + + PUGI__FN static void unspecified_bool_xpath_node(xpath_node***) + { + } + + PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type() const + { + return (_node || _attribute) ? unspecified_bool_xpath_node : 0; + } + + PUGI__FN bool xpath_node::operator!() const + { + return !(_node || _attribute); + } + + PUGI__FN bool xpath_node::operator==(const xpath_node& n) const + { + return _node == n._node && _attribute == n._attribute; + } + + PUGI__FN bool xpath_node::operator!=(const xpath_node& n) const + { + return _node != n._node || _attribute != n._attribute; + } + +#ifdef __BORLANDC__ + PUGI__FN bool operator&&(const xpath_node& lhs, bool rhs) + { + return (bool)lhs && rhs; + } + + PUGI__FN bool operator||(const xpath_node& lhs, bool rhs) + { + return (bool)lhs || rhs; + } +#endif + + PUGI__FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_) + { + assert(begin_ <= end_); + + size_t size_ = static_cast(end_ - begin_); + + if (size_ <= 1) + { + // deallocate old buffer + if (_begin != &_storage) impl::xml_memory::deallocate(_begin); + + // use internal buffer + if (begin_ != end_) _storage = *begin_; + + _begin = &_storage; + _end = &_storage + size_; + } + else + { + // make heap copy + xpath_node* storage = static_cast(impl::xml_memory::allocate(size_ * sizeof(xpath_node))); + + if (!storage) + { + #ifdef PUGIXML_NO_EXCEPTIONS + return; + #else + throw std::bad_alloc(); + #endif + } + + memcpy(storage, begin_, size_ * sizeof(xpath_node)); + + // deallocate old buffer + if (_begin != &_storage) impl::xml_memory::deallocate(_begin); + + // finalize + _begin = storage; + _end = storage + size_; + } + } + + PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(&_storage), _end(&_storage) + { + } + + PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_), _begin(&_storage), _end(&_storage) + { + _assign(begin_, end_); + } + + PUGI__FN xpath_node_set::~xpath_node_set() + { + if (_begin != &_storage) impl::xml_memory::deallocate(_begin); + } + + PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(ns._type), _begin(&_storage), _end(&_storage) + { + _assign(ns._begin, ns._end); + } + + PUGI__FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns) + { + if (this == &ns) return *this; + + _type = ns._type; + _assign(ns._begin, ns._end); + + return *this; + } + + PUGI__FN xpath_node_set::type_t xpath_node_set::type() const + { + return _type; + } + + PUGI__FN size_t xpath_node_set::size() const + { + return _end - _begin; + } + + PUGI__FN bool xpath_node_set::empty() const + { + return _begin == _end; + } + + PUGI__FN const xpath_node& xpath_node_set::operator[](size_t index) const + { + assert(index < size()); + return _begin[index]; + } + + PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin() const + { + return _begin; + } + + PUGI__FN xpath_node_set::const_iterator xpath_node_set::end() const + { + return _end; + } + + PUGI__FN void xpath_node_set::sort(bool reverse) + { + _type = impl::xpath_sort(_begin, _end, _type, reverse); + } + + PUGI__FN xpath_node xpath_node_set::first() const + { + return impl::xpath_first(_begin, _end, _type); + } + + PUGI__FN xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0) + { + } + + PUGI__FN xpath_parse_result::operator bool() const + { + return error == 0; + } + + PUGI__FN const char* xpath_parse_result::description() const + { + return error ? error : "No error"; + } + + PUGI__FN xpath_variable::xpath_variable() + { + } + + PUGI__FN const char_t* xpath_variable::name() const + { + switch (_type) + { + case xpath_type_node_set: + return static_cast(this)->name; + + case xpath_type_number: + return static_cast(this)->name; + + case xpath_type_string: + return static_cast(this)->name; + + case xpath_type_boolean: + return static_cast(this)->name; + + default: + assert(!"Invalid variable type"); + return 0; + } + } + + PUGI__FN xpath_value_type xpath_variable::type() const + { + return _type; + } + + PUGI__FN bool xpath_variable::get_boolean() const + { + return (_type == xpath_type_boolean) ? static_cast(this)->value : false; + } + + PUGI__FN double xpath_variable::get_number() const + { + return (_type == xpath_type_number) ? static_cast(this)->value : impl::gen_nan(); + } + + PUGI__FN const char_t* xpath_variable::get_string() const + { + const char_t* value = (_type == xpath_type_string) ? static_cast(this)->value : 0; + return value ? value : PUGIXML_TEXT(""); + } + + PUGI__FN const xpath_node_set& xpath_variable::get_node_set() const + { + return (_type == xpath_type_node_set) ? static_cast(this)->value : impl::dummy_node_set; + } + + PUGI__FN bool xpath_variable::set(bool value) + { + if (_type != xpath_type_boolean) return false; + + static_cast(this)->value = value; + return true; + } + + PUGI__FN bool xpath_variable::set(double value) + { + if (_type != xpath_type_number) return false; + + static_cast(this)->value = value; + return true; + } + + PUGI__FN bool xpath_variable::set(const char_t* value) + { + if (_type != xpath_type_string) return false; + + impl::xpath_variable_string* var = static_cast(this); + + // duplicate string + size_t size = (impl::strlength(value) + 1) * sizeof(char_t); + + char_t* copy = static_cast(impl::xml_memory::allocate(size)); + if (!copy) return false; + + memcpy(copy, value, size); + + // replace old string + if (var->value) impl::xml_memory::deallocate(var->value); + var->value = copy; + + return true; + } + + PUGI__FN bool xpath_variable::set(const xpath_node_set& value) + { + if (_type != xpath_type_node_set) return false; + + static_cast(this)->value = value; + return true; + } + + PUGI__FN xpath_variable_set::xpath_variable_set() + { + for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _data[i] = 0; + } + + PUGI__FN xpath_variable_set::~xpath_variable_set() + { + for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) + { + xpath_variable* var = _data[i]; + + while (var) + { + xpath_variable* next = var->_next; + + impl::delete_xpath_variable(var->_type, var); + + var = next; + } + } + } + + PUGI__FN xpath_variable* xpath_variable_set::find(const char_t* name) const + { + const size_t hash_size = sizeof(_data) / sizeof(_data[0]); + size_t hash = impl::hash_string(name) % hash_size; + + // look for existing variable + for (xpath_variable* var = _data[hash]; var; var = var->_next) + if (impl::strequal(var->name(), name)) + return var; + + return 0; + } + + PUGI__FN xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type) + { + const size_t hash_size = sizeof(_data) / sizeof(_data[0]); + size_t hash = impl::hash_string(name) % hash_size; + + // look for existing variable + for (xpath_variable* var = _data[hash]; var; var = var->_next) + if (impl::strequal(var->name(), name)) + return var->type() == type ? var : 0; + + // add new variable + xpath_variable* result = impl::new_xpath_variable(type, name); + + if (result) + { + result->_type = type; + result->_next = _data[hash]; + + _data[hash] = result; + } + + return result; + } + + PUGI__FN bool xpath_variable_set::set(const char_t* name, bool value) + { + xpath_variable* var = add(name, xpath_type_boolean); + return var ? var->set(value) : false; + } + + PUGI__FN bool xpath_variable_set::set(const char_t* name, double value) + { + xpath_variable* var = add(name, xpath_type_number); + return var ? var->set(value) : false; + } + + PUGI__FN bool xpath_variable_set::set(const char_t* name, const char_t* value) + { + xpath_variable* var = add(name, xpath_type_string); + return var ? var->set(value) : false; + } + + PUGI__FN bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value) + { + xpath_variable* var = add(name, xpath_type_node_set); + return var ? var->set(value) : false; + } + + PUGI__FN xpath_variable* xpath_variable_set::get(const char_t* name) + { + return find(name); + } + + PUGI__FN const xpath_variable* xpath_variable_set::get(const char_t* name) const + { + return find(name); + } + + PUGI__FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0) + { + impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create(); + + if (!qimpl) + { + #ifdef PUGIXML_NO_EXCEPTIONS + _result.error = "Out of memory"; + #else + throw std::bad_alloc(); + #endif + } + else + { + impl::buffer_holder impl_holder(qimpl, impl::xpath_query_impl::destroy); + + qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result); + + if (qimpl->root) + { + _impl = static_cast(impl_holder.release()); + _result.error = 0; + } + } + } + + PUGI__FN xpath_query::~xpath_query() + { + impl::xpath_query_impl::destroy(_impl); + } + + PUGI__FN xpath_value_type xpath_query::return_type() const + { + if (!_impl) return xpath_type_none; + + return static_cast(_impl)->root->rettype(); + } + + PUGI__FN bool xpath_query::evaluate_boolean(const xpath_node& n) const + { + if (!_impl) return false; + + impl::xpath_context c(n, 1, 1); + impl::xpath_stack_data sd; + + #ifdef PUGIXML_NO_EXCEPTIONS + if (setjmp(sd.error_handler)) return false; + #endif + + return static_cast(_impl)->root->eval_boolean(c, sd.stack); + } + + PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const + { + if (!_impl) return impl::gen_nan(); + + impl::xpath_context c(n, 1, 1); + impl::xpath_stack_data sd; + + #ifdef PUGIXML_NO_EXCEPTIONS + if (setjmp(sd.error_handler)) return impl::gen_nan(); + #endif + + return static_cast(_impl)->root->eval_number(c, sd.stack); + } + +#ifndef PUGIXML_NO_STL + PUGI__FN string_t xpath_query::evaluate_string(const xpath_node& n) const + { + impl::xpath_stack_data sd; + + return impl::evaluate_string_impl(static_cast(_impl), n, sd).c_str(); + } +#endif + + PUGI__FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const + { + impl::xpath_stack_data sd; + + impl::xpath_string r = impl::evaluate_string_impl(static_cast(_impl), n, sd); + + size_t full_size = r.length() + 1; + + if (capacity > 0) + { + size_t size = (full_size < capacity) ? full_size : capacity; + assert(size > 0); + + memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t)); + buffer[size - 1] = 0; + } + + return full_size; + } + + PUGI__FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const + { + if (!_impl) return xpath_node_set(); + + impl::xpath_ast_node* root = static_cast(_impl)->root; + + if (root->rettype() != xpath_type_node_set) + { + #ifdef PUGIXML_NO_EXCEPTIONS + return xpath_node_set(); + #else + xpath_parse_result res; + res.error = "Expression does not evaluate to node set"; + + throw xpath_exception(res); + #endif + } + + impl::xpath_context c(n, 1, 1); + impl::xpath_stack_data sd; + + #ifdef PUGIXML_NO_EXCEPTIONS + if (setjmp(sd.error_handler)) return xpath_node_set(); + #endif + + impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack); + + return xpath_node_set(r.begin(), r.end(), r.type()); + } + + PUGI__FN const xpath_parse_result& xpath_query::result() const + { + return _result; + } + + PUGI__FN static void unspecified_bool_xpath_query(xpath_query***) + { + } + + PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type() const + { + return _impl ? unspecified_bool_xpath_query : 0; + } + + PUGI__FN bool xpath_query::operator!() const + { + return !_impl; + } + + PUGI__FN xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const + { + xpath_query q(query, variables); + return select_single_node(q); + } + + PUGI__FN xpath_node xml_node::select_single_node(const xpath_query& query) const + { + xpath_node_set s = query.evaluate_node_set(*this); + return s.empty() ? xpath_node() : s.first(); + } + + PUGI__FN xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const + { + xpath_query q(query, variables); + return select_nodes(q); + } + + PUGI__FN xpath_node_set xml_node::select_nodes(const xpath_query& query) const + { + return query.evaluate_node_set(*this); + } +} + +#endif + +#ifdef __BORLANDC__ +# pragma option pop +#endif + +// Intel C++ does not properly keep warning state for function templates, +// so popping warning state at the end of translation unit leads to warnings in the middle. +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) +# pragma warning(pop) +#endif + +// Undefine all local macros (makes sure we're not leaking macros in header-only mode) +#undef PUGI__NO_INLINE +#undef PUGI__STATIC_ASSERT +#undef PUGI__DMC_VOLATILE +#undef PUGI__MSVC_CRT_VERSION +#undef PUGI__NS_BEGIN +#undef PUGI__NS_END +#undef PUGI__FN +#undef PUGI__FN_NO_INLINE +#undef PUGI__IS_CHARTYPE_IMPL +#undef PUGI__IS_CHARTYPE +#undef PUGI__IS_CHARTYPEX +#undef PUGI__SKIPWS +#undef PUGI__OPTSET +#undef PUGI__PUSHNODE +#undef PUGI__POPNODE +#undef PUGI__SCANFOR +#undef PUGI__SCANWHILE +#undef PUGI__ENDSEG +#undef PUGI__THROW_ERROR +#undef PUGI__CHECK_ERROR + +#endif + +/** + * Copyright (c) 2006-2012 Arseny Kapoulkine + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ diff --git a/libs/pugixml/pugixml.hpp b/libs/pugixml/pugixml.hpp new file mode 100644 index 000000000..894c34dcb --- /dev/null +++ b/libs/pugixml/pugixml.hpp @@ -0,0 +1,1265 @@ +/** + * pugixml parser - version 1.2 + * -------------------------------------------------------- + * Copyright (C) 2006-2012, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Report bugs and download new versions at http://pugixml.org/ + * + * This library is distributed under the MIT License. See notice at the end + * of this file. + * + * This work is based on the pugxml parser, which is: + * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) + */ + +#ifndef PUGIXML_VERSION +// Define version macro; evaluates to major * 100 + minor so that it's safe to use in less-than comparisons +# define PUGIXML_VERSION 120 +#endif + +// Include user configuration file (this can define various configuration macros) +#include "pugiconfig.hpp" + +#ifndef HEADER_PUGIXML_HPP +#define HEADER_PUGIXML_HPP + +// Include stddef.h for size_t and ptrdiff_t +#include + +// Include exception header for XPath +#if !defined(PUGIXML_NO_XPATH) && !defined(PUGIXML_NO_EXCEPTIONS) +# include +#endif + +// Include STL headers +#ifndef PUGIXML_NO_STL +# include +# include +# include +#endif + +// Macro for deprecated features +#ifndef PUGIXML_DEPRECATED +# if defined(__GNUC__) +# define PUGIXML_DEPRECATED __attribute__((deprecated)) +# elif defined(_MSC_VER) && _MSC_VER >= 1300 +# define PUGIXML_DEPRECATED __declspec(deprecated) +# else +# define PUGIXML_DEPRECATED +# endif +#endif + +// If no API is defined, assume default +#ifndef PUGIXML_API +# define PUGIXML_API +#endif + +// If no API for classes is defined, assume default +#ifndef PUGIXML_CLASS +# define PUGIXML_CLASS PUGIXML_API +#endif + +// If no API for functions is defined, assume default +#ifndef PUGIXML_FUNCTION +# define PUGIXML_FUNCTION PUGIXML_API +#endif + +// Character interface macros +#ifdef PUGIXML_WCHAR_MODE +# define PUGIXML_TEXT(t) L ## t +# define PUGIXML_CHAR wchar_t +#else +# define PUGIXML_TEXT(t) t +# define PUGIXML_CHAR char +#endif + +namespace pugi +{ + // Character type used for all internal storage and operations; depends on PUGIXML_WCHAR_MODE + typedef PUGIXML_CHAR char_t; + +#ifndef PUGIXML_NO_STL + // String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE + typedef std::basic_string, std::allocator > string_t; +#endif +} + +// The PugiXML namespace +namespace pugi +{ + // Tree node types + enum xml_node_type + { + node_null, // Empty (null) node handle + node_document, // A document tree's absolute root + node_element, // Element tag, i.e. '' + node_pcdata, // Plain character data, i.e. 'text' + node_cdata, // Character data, i.e. '' + node_comment, // Comment tag, i.e. '' + node_pi, // Processing instruction, i.e. '' + node_declaration, // Document declaration, i.e. '' + node_doctype // Document type declaration, i.e. '' + }; + + // Parsing options + + // Minimal parsing mode (equivalent to turning all other flags off). + // Only elements and PCDATA sections are added to the DOM tree, no text conversions are performed. + const unsigned int parse_minimal = 0x0000; + + // This flag determines if processing instructions (node_pi) are added to the DOM tree. This flag is off by default. + const unsigned int parse_pi = 0x0001; + + // This flag determines if comments (node_comment) are added to the DOM tree. This flag is off by default. + const unsigned int parse_comments = 0x0002; + + // This flag determines if CDATA sections (node_cdata) are added to the DOM tree. This flag is on by default. + const unsigned int parse_cdata = 0x0004; + + // This flag determines if plain character data (node_pcdata) that consist only of whitespace are added to the DOM tree. + // This flag is off by default; turning it on usually results in slower parsing and more memory consumption. + const unsigned int parse_ws_pcdata = 0x0008; + + // This flag determines if character and entity references are expanded during parsing. This flag is on by default. + const unsigned int parse_escapes = 0x0010; + + // This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default. + const unsigned int parse_eol = 0x0020; + + // This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default. + const unsigned int parse_wconv_attribute = 0x0040; + + // This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default. + const unsigned int parse_wnorm_attribute = 0x0080; + + // This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default. + const unsigned int parse_declaration = 0x0100; + + // This flag determines if document type declaration (node_doctype) is added to the DOM tree. This flag is off by default. + const unsigned int parse_doctype = 0x0200; + + // This flag determines if plain character data (node_pcdata) that is the only child of the parent node and that consists only + // of whitespace is added to the DOM tree. + // This flag is off by default; turning it on may result in slower parsing and more memory consumption. + const unsigned int parse_ws_pcdata_single = 0x0400; + + // The default parsing mode. + // Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded, + // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. + const unsigned int parse_default = parse_cdata | parse_escapes | parse_wconv_attribute | parse_eol; + + // The full parsing mode. + // Nodes of all types are added to the DOM tree, character/reference entities are expanded, + // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. + const unsigned int parse_full = parse_default | parse_pi | parse_comments | parse_declaration | parse_doctype; + + // These flags determine the encoding of input data for XML document + enum xml_encoding + { + encoding_auto, // Auto-detect input encoding using BOM or < / class xml_object_range + { + public: + typedef It const_iterator; + + xml_object_range(It b, It e): _begin(b), _end(e) + { + } + + It begin() const { return _begin; } + It end() const { return _end; } + + private: + It _begin, _end; + }; + + // Writer interface for node printing (see xml_node::print) + class PUGIXML_CLASS xml_writer + { + public: + virtual ~xml_writer() {} + + // Write memory chunk into stream/file/whatever + virtual void write(const void* data, size_t size) = 0; + }; + + // xml_writer implementation for FILE* + class PUGIXML_CLASS xml_writer_file: public xml_writer + { + public: + // Construct writer from a FILE* object; void* is used to avoid header dependencies on stdio + xml_writer_file(void* file); + + virtual void write(const void* data, size_t size); + + private: + void* file; + }; + + #ifndef PUGIXML_NO_STL + // xml_writer implementation for streams + class PUGIXML_CLASS xml_writer_stream: public xml_writer + { + public: + // Construct writer from an output stream object + xml_writer_stream(std::basic_ostream >& stream); + xml_writer_stream(std::basic_ostream >& stream); + + virtual void write(const void* data, size_t size); + + private: + std::basic_ostream >* narrow_stream; + std::basic_ostream >* wide_stream; + }; + #endif + + // A light-weight handle for manipulating attributes in DOM tree + class PUGIXML_CLASS xml_attribute + { + friend class xml_attribute_iterator; + friend class xml_node; + + private: + xml_attribute_struct* _attr; + + typedef void (*unspecified_bool_type)(xml_attribute***); + + public: + // Default constructor. Constructs an empty attribute. + xml_attribute(); + + // Constructs attribute from internal pointer + explicit xml_attribute(xml_attribute_struct* attr); + + // Safe bool conversion operator + operator unspecified_bool_type() const; + + // Borland C++ workaround + bool operator!() const; + + // Comparison operators (compares wrapped attribute pointers) + bool operator==(const xml_attribute& r) const; + bool operator!=(const xml_attribute& r) const; + bool operator<(const xml_attribute& r) const; + bool operator>(const xml_attribute& r) const; + bool operator<=(const xml_attribute& r) const; + bool operator>=(const xml_attribute& r) const; + + // Check if attribute is empty + bool empty() const; + + // Get attribute name/value, or "" if attribute is empty + const char_t* name() const; + const char_t* value() const; + + // Get attribute value, or the default value if attribute is empty + const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; + + // Get attribute value as a number, or the default value if conversion did not succeed or attribute is empty + int as_int(int def = 0) const; + unsigned int as_uint(unsigned int def = 0) const; + double as_double(double def = 0) const; + float as_float(float def = 0) const; + + // Get attribute value as bool (returns true if first character is in '1tTyY' set), or the default value if attribute is empty + bool as_bool(bool def = false) const; + + // Set attribute name/value (returns false if attribute is empty or there is not enough memory) + bool set_name(const char_t* rhs); + bool set_value(const char_t* rhs); + + // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") + bool set_value(int rhs); + bool set_value(unsigned int rhs); + bool set_value(double rhs); + bool set_value(bool rhs); + + // Set attribute value (equivalent to set_value without error checking) + xml_attribute& operator=(const char_t* rhs); + xml_attribute& operator=(int rhs); + xml_attribute& operator=(unsigned int rhs); + xml_attribute& operator=(double rhs); + xml_attribute& operator=(bool rhs); + + // Get next/previous attribute in the attribute list of the parent node + xml_attribute next_attribute() const; + xml_attribute previous_attribute() const; + + // Get hash value (unique for handles to the same object) + size_t hash_value() const; + + // Get internal pointer + xml_attribute_struct* internal_object() const; + }; + +#ifdef __BORLANDC__ + // Borland C++ workaround + bool PUGIXML_FUNCTION operator&&(const xml_attribute& lhs, bool rhs); + bool PUGIXML_FUNCTION operator||(const xml_attribute& lhs, bool rhs); +#endif + + // A light-weight handle for manipulating nodes in DOM tree + class PUGIXML_CLASS xml_node + { + friend class xml_attribute_iterator; + friend class xml_node_iterator; + friend class xml_named_node_iterator; + + protected: + xml_node_struct* _root; + + typedef void (*unspecified_bool_type)(xml_node***); + + public: + // Default constructor. Constructs an empty node. + xml_node(); + + // Constructs node from internal pointer + explicit xml_node(xml_node_struct* p); + + // Safe bool conversion operator + operator unspecified_bool_type() const; + + // Borland C++ workaround + bool operator!() const; + + // Comparison operators (compares wrapped node pointers) + bool operator==(const xml_node& r) const; + bool operator!=(const xml_node& r) const; + bool operator<(const xml_node& r) const; + bool operator>(const xml_node& r) const; + bool operator<=(const xml_node& r) const; + bool operator>=(const xml_node& r) const; + + // Check if node is empty. + bool empty() const; + + // Get node type + xml_node_type type() const; + + // Get node name/value, or "" if node is empty or it has no name/value + const char_t* name() const; + const char_t* value() const; + + // Get attribute list + xml_attribute first_attribute() const; + xml_attribute last_attribute() const; + + // Get children list + xml_node first_child() const; + xml_node last_child() const; + + // Get next/previous sibling in the children list of the parent node + xml_node next_sibling() const; + xml_node previous_sibling() const; + + // Get parent node + xml_node parent() const; + + // Get root of DOM tree this node belongs to + xml_node root() const; + + // Get text object for the current node + xml_text text() const; + + // Get child, attribute or next/previous sibling with the specified name + xml_node child(const char_t* name) const; + xml_attribute attribute(const char_t* name) const; + xml_node next_sibling(const char_t* name) const; + xml_node previous_sibling(const char_t* name) const; + + // Get child value of current node; that is, value of the first child node of type PCDATA/CDATA + const char_t* child_value() const; + + // Get child value of child with specified name. Equivalent to child(name).child_value(). + const char_t* child_value(const char_t* name) const; + + // Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value) + bool set_name(const char_t* rhs); + bool set_value(const char_t* rhs); + + // Add attribute with specified name. Returns added attribute, or empty attribute on errors. + xml_attribute append_attribute(const char_t* name); + xml_attribute prepend_attribute(const char_t* name); + xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr); + xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr); + + // Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors. + xml_attribute append_copy(const xml_attribute& proto); + xml_attribute prepend_copy(const xml_attribute& proto); + xml_attribute insert_copy_after(const xml_attribute& proto, const xml_attribute& attr); + xml_attribute insert_copy_before(const xml_attribute& proto, const xml_attribute& attr); + + // Add child node with specified type. Returns added node, or empty node on errors. + xml_node append_child(xml_node_type type = node_element); + xml_node prepend_child(xml_node_type type = node_element); + xml_node insert_child_after(xml_node_type type, const xml_node& node); + xml_node insert_child_before(xml_node_type type, const xml_node& node); + + // Add child element with specified name. Returns added node, or empty node on errors. + xml_node append_child(const char_t* name); + xml_node prepend_child(const char_t* name); + xml_node insert_child_after(const char_t* name, const xml_node& node); + xml_node insert_child_before(const char_t* name, const xml_node& node); + + // Add a copy of the specified node as a child. Returns added node, or empty node on errors. + xml_node append_copy(const xml_node& proto); + xml_node prepend_copy(const xml_node& proto); + xml_node insert_copy_after(const xml_node& proto, const xml_node& node); + xml_node insert_copy_before(const xml_node& proto, const xml_node& node); + + // Remove specified attribute + bool remove_attribute(const xml_attribute& a); + bool remove_attribute(const char_t* name); + + // Remove specified child + bool remove_child(const xml_node& n); + bool remove_child(const char_t* name); + + // Find attribute using predicate. Returns first attribute for which predicate returned true. + template xml_attribute find_attribute(Predicate pred) const + { + if (!_root) return xml_attribute(); + + for (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute()) + if (pred(attrib)) + return attrib; + + return xml_attribute(); + } + + // Find child node using predicate. Returns first child for which predicate returned true. + template xml_node find_child(Predicate pred) const + { + if (!_root) return xml_node(); + + for (xml_node node = first_child(); node; node = node.next_sibling()) + if (pred(node)) + return node; + + return xml_node(); + } + + // Find node from subtree using predicate. Returns first node from subtree (depth-first), for which predicate returned true. + template xml_node find_node(Predicate pred) const + { + if (!_root) return xml_node(); + + xml_node cur = first_child(); + + while (cur._root && cur._root != _root) + { + if (pred(cur)) return cur; + + if (cur.first_child()) cur = cur.first_child(); + else if (cur.next_sibling()) cur = cur.next_sibling(); + else + { + while (!cur.next_sibling() && cur._root != _root) cur = cur.parent(); + + if (cur._root != _root) cur = cur.next_sibling(); + } + } + + return xml_node(); + } + + // Find child node by attribute name/value + xml_node find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const; + xml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const; + + #ifndef PUGIXML_NO_STL + // Get the absolute node path from root as a text string. + string_t path(char_t delimiter = '/') const; + #endif + + // Search for a node by path consisting of node names and . or .. elements. + xml_node first_element_by_path(const char_t* path, char_t delimiter = '/') const; + + // Recursively traverse subtree with xml_tree_walker + bool traverse(xml_tree_walker& walker); + + #ifndef PUGIXML_NO_XPATH + // Select single node by evaluating XPath query. Returns first node from the resulting node set. + xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const; + xpath_node select_single_node(const xpath_query& query) const; + + // Select node set by evaluating XPath query + xpath_node_set select_nodes(const char_t* query, xpath_variable_set* variables = 0) const; + xpath_node_set select_nodes(const xpath_query& query) const; + #endif + + // Print subtree using a writer object + void print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; + + #ifndef PUGIXML_NO_STL + // Print subtree to stream + void print(std::basic_ostream >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; + void print(std::basic_ostream >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, unsigned int depth = 0) const; + #endif + + // Child nodes iterators + typedef xml_node_iterator iterator; + + iterator begin() const; + iterator end() const; + + // Attribute iterators + typedef xml_attribute_iterator attribute_iterator; + + attribute_iterator attributes_begin() const; + attribute_iterator attributes_end() const; + + // Range-based for support + xml_object_range children() const; + xml_object_range children(const char_t* name) const; + xml_object_range attributes() const; + + // Get node offset in parsed file/string (in char_t units) for debugging purposes + ptrdiff_t offset_debug() const; + + // Get hash value (unique for handles to the same object) + size_t hash_value() const; + + // Get internal pointer + xml_node_struct* internal_object() const; + }; + +#ifdef __BORLANDC__ + // Borland C++ workaround + bool PUGIXML_FUNCTION operator&&(const xml_node& lhs, bool rhs); + bool PUGIXML_FUNCTION operator||(const xml_node& lhs, bool rhs); +#endif + + // A helper for working with text inside PCDATA nodes + class PUGIXML_CLASS xml_text + { + friend class xml_node; + + xml_node_struct* _root; + + typedef void (*unspecified_bool_type)(xml_text***); + + explicit xml_text(xml_node_struct* root); + + xml_node_struct* _data_new(); + xml_node_struct* _data() const; + + public: + // Default constructor. Constructs an empty object. + xml_text(); + + // Safe bool conversion operator + operator unspecified_bool_type() const; + + // Borland C++ workaround + bool operator!() const; + + // Check if text object is empty + bool empty() const; + + // Get text, or "" if object is empty + const char_t* get() const; + + // Get text, or the default value if object is empty + const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; + + // Get text as a number, or the default value if conversion did not succeed or object is empty + int as_int(int def = 0) const; + unsigned int as_uint(unsigned int def = 0) const; + double as_double(double def = 0) const; + float as_float(float def = 0) const; + + // Get text as bool (returns true if first character is in '1tTyY' set), or the default value if object is empty + bool as_bool(bool def = false) const; + + // Set text (returns false if object is empty or there is not enough memory) + bool set(const char_t* rhs); + + // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") + bool set(int rhs); + bool set(unsigned int rhs); + bool set(double rhs); + bool set(bool rhs); + + // Set text (equivalent to set without error checking) + xml_text& operator=(const char_t* rhs); + xml_text& operator=(int rhs); + xml_text& operator=(unsigned int rhs); + xml_text& operator=(double rhs); + xml_text& operator=(bool rhs); + + // Get the data node (node_pcdata or node_cdata) for this object + xml_node data() const; + }; + +#ifdef __BORLANDC__ + // Borland C++ workaround + bool PUGIXML_FUNCTION operator&&(const xml_text& lhs, bool rhs); + bool PUGIXML_FUNCTION operator||(const xml_text& lhs, bool rhs); +#endif + + // Child node iterator (a bidirectional iterator over a collection of xml_node) + class PUGIXML_CLASS xml_node_iterator + { + friend class xml_node; + + private: + mutable xml_node _wrap; + xml_node _parent; + + xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent); + + public: + // Iterator traits + typedef ptrdiff_t difference_type; + typedef xml_node value_type; + typedef xml_node* pointer; + typedef xml_node& reference; + + #ifndef PUGIXML_NO_STL + typedef std::bidirectional_iterator_tag iterator_category; + #endif + + // Default constructor + xml_node_iterator(); + + // Construct an iterator which points to the specified node + xml_node_iterator(const xml_node& node); + + // Iterator operators + bool operator==(const xml_node_iterator& rhs) const; + bool operator!=(const xml_node_iterator& rhs) const; + + xml_node& operator*() const; + xml_node* operator->() const; + + const xml_node_iterator& operator++(); + xml_node_iterator operator++(int); + + const xml_node_iterator& operator--(); + xml_node_iterator operator--(int); + }; + + // Attribute iterator (a bidirectional iterator over a collection of xml_attribute) + class PUGIXML_CLASS xml_attribute_iterator + { + friend class xml_node; + + private: + mutable xml_attribute _wrap; + xml_node _parent; + + xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent); + + public: + // Iterator traits + typedef ptrdiff_t difference_type; + typedef xml_attribute value_type; + typedef xml_attribute* pointer; + typedef xml_attribute& reference; + + #ifndef PUGIXML_NO_STL + typedef std::bidirectional_iterator_tag iterator_category; + #endif + + // Default constructor + xml_attribute_iterator(); + + // Construct an iterator which points to the specified attribute + xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent); + + // Iterator operators + bool operator==(const xml_attribute_iterator& rhs) const; + bool operator!=(const xml_attribute_iterator& rhs) const; + + xml_attribute& operator*() const; + xml_attribute* operator->() const; + + const xml_attribute_iterator& operator++(); + xml_attribute_iterator operator++(int); + + const xml_attribute_iterator& operator--(); + xml_attribute_iterator operator--(int); + }; + + // Named node range helper + class xml_named_node_iterator + { + public: + // Iterator traits + typedef ptrdiff_t difference_type; + typedef xml_node value_type; + typedef xml_node* pointer; + typedef xml_node& reference; + + #ifndef PUGIXML_NO_STL + typedef std::forward_iterator_tag iterator_category; + #endif + + // Default constructor + xml_named_node_iterator(); + + // Construct an iterator which points to the specified node + xml_named_node_iterator(const xml_node& node, const char_t* name); + + // Iterator operators + bool operator==(const xml_named_node_iterator& rhs) const; + bool operator!=(const xml_named_node_iterator& rhs) const; + + xml_node& operator*() const; + xml_node* operator->() const; + + const xml_named_node_iterator& operator++(); + xml_named_node_iterator operator++(int); + + private: + mutable xml_node _node; + const char_t* _name; + }; + + // Abstract tree walker class (see xml_node::traverse) + class PUGIXML_CLASS xml_tree_walker + { + friend class xml_node; + + private: + int _depth; + + protected: + // Get current traversal depth + int depth() const; + + public: + xml_tree_walker(); + virtual ~xml_tree_walker(); + + // Callback that is called when traversal begins + virtual bool begin(xml_node& node); + + // Callback that is called for each node traversed + virtual bool for_each(xml_node& node) = 0; + + // Callback that is called when traversal ends + virtual bool end(xml_node& node); + }; + + // Parsing status, returned as part of xml_parse_result object + enum xml_parse_status + { + status_ok = 0, // No error + + status_file_not_found, // File was not found during load_file() + status_io_error, // Error reading from file/stream + status_out_of_memory, // Could not allocate memory + status_internal_error, // Internal error occurred + + status_unrecognized_tag, // Parser could not determine tag type + + status_bad_pi, // Parsing error occurred while parsing document declaration/processing instruction + status_bad_comment, // Parsing error occurred while parsing comment + status_bad_cdata, // Parsing error occurred while parsing CDATA section + status_bad_doctype, // Parsing error occurred while parsing document type declaration + status_bad_pcdata, // Parsing error occurred while parsing PCDATA section + status_bad_start_element, // Parsing error occurred while parsing start element tag + status_bad_attribute, // Parsing error occurred while parsing element attribute + status_bad_end_element, // Parsing error occurred while parsing end element tag + status_end_element_mismatch // There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag) + }; + + // Parsing result + struct PUGIXML_CLASS xml_parse_result + { + // Parsing status (see xml_parse_status) + xml_parse_status status; + + // Last parsed offset (in char_t units from start of input data) + ptrdiff_t offset; + + // Source document encoding + xml_encoding encoding; + + // Default constructor, initializes object to failed state + xml_parse_result(); + + // Cast to bool operator + operator bool() const; + + // Get error description + const char* description() const; + }; + + // Document class (DOM tree root) + class PUGIXML_CLASS xml_document: public xml_node + { + private: + char_t* _buffer; + + char _memory[192]; + + // Non-copyable semantics + xml_document(const xml_document&); + const xml_document& operator=(const xml_document&); + + void create(); + void destroy(); + + xml_parse_result load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own); + + public: + // Default constructor, makes empty document + xml_document(); + + // Destructor, invalidates all node/attribute handles to this document + ~xml_document(); + + // Removes all nodes, leaving the empty document + void reset(); + + // Removes all nodes, then copies the entire contents of the specified document + void reset(const xml_document& proto); + + #ifndef PUGIXML_NO_STL + // Load document from stream. + xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default); + #endif + + // Load document from zero-terminated string. No encoding conversions are applied. + xml_parse_result load(const char_t* contents, unsigned int options = parse_default); + + // Load document from file + xml_parse_result load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + xml_parse_result load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + + // Load document from buffer. Copies/converts the buffer, so it may be deleted or changed after the function returns. + xml_parse_result load_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + + // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). + // You should ensure that buffer data will persist throughout the document's lifetime, and free the buffer memory manually once document is destroyed. + xml_parse_result load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + + // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). + // You should allocate the buffer with pugixml allocation function; document will free the buffer when it is no longer needed (you can't use it anymore). + xml_parse_result load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + + // Save XML document to writer (semantics is slightly different from xml_node::print, see documentation for details). + void save(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; + + #ifndef PUGIXML_NO_STL + // Save XML document to stream (semantics is slightly different from xml_node::print, see documentation for details). + void save(std::basic_ostream >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; + void save(std::basic_ostream >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default) const; + #endif + + // Save XML to file + bool save_file(const char* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; + bool save_file(const wchar_t* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; + + // Get document element + xml_node document_element() const; + }; + +#ifndef PUGIXML_NO_XPATH + // XPath query return type + enum xpath_value_type + { + xpath_type_none, // Unknown type (query failed to compile) + xpath_type_node_set, // Node set (xpath_node_set) + xpath_type_number, // Number + xpath_type_string, // String + xpath_type_boolean // Boolean + }; + + // XPath parsing result + struct PUGIXML_CLASS xpath_parse_result + { + // Error message (0 if no error) + const char* error; + + // Last parsed offset (in char_t units from string start) + ptrdiff_t offset; + + // Default constructor, initializes object to failed state + xpath_parse_result(); + + // Cast to bool operator + operator bool() const; + + // Get error description + const char* description() const; + }; + + // A single XPath variable + class PUGIXML_CLASS xpath_variable + { + friend class xpath_variable_set; + + protected: + xpath_value_type _type; + xpath_variable* _next; + + xpath_variable(); + + // Non-copyable semantics + xpath_variable(const xpath_variable&); + xpath_variable& operator=(const xpath_variable&); + + public: + // Get variable name + const char_t* name() const; + + // Get variable type + xpath_value_type type() const; + + // Get variable value; no type conversion is performed, default value (false, NaN, empty string, empty node set) is returned on type mismatch error + bool get_boolean() const; + double get_number() const; + const char_t* get_string() const; + const xpath_node_set& get_node_set() const; + + // Set variable value; no type conversion is performed, false is returned on type mismatch error + bool set(bool value); + bool set(double value); + bool set(const char_t* value); + bool set(const xpath_node_set& value); + }; + + // A set of XPath variables + class PUGIXML_CLASS xpath_variable_set + { + private: + xpath_variable* _data[64]; + + // Non-copyable semantics + xpath_variable_set(const xpath_variable_set&); + xpath_variable_set& operator=(const xpath_variable_set&); + + xpath_variable* find(const char_t* name) const; + + public: + // Default constructor/destructor + xpath_variable_set(); + ~xpath_variable_set(); + + // Add a new variable or get the existing one, if the types match + xpath_variable* add(const char_t* name, xpath_value_type type); + + // Set value of an existing variable; no type conversion is performed, false is returned if there is no such variable or if types mismatch + bool set(const char_t* name, bool value); + bool set(const char_t* name, double value); + bool set(const char_t* name, const char_t* value); + bool set(const char_t* name, const xpath_node_set& value); + + // Get existing variable by name + xpath_variable* get(const char_t* name); + const xpath_variable* get(const char_t* name) const; + }; + + // A compiled XPath query object + class PUGIXML_CLASS xpath_query + { + private: + void* _impl; + xpath_parse_result _result; + + typedef void (*unspecified_bool_type)(xpath_query***); + + // Non-copyable semantics + xpath_query(const xpath_query&); + xpath_query& operator=(const xpath_query&); + + public: + // Construct a compiled object from XPath expression. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on compilation errors. + explicit xpath_query(const char_t* query, xpath_variable_set* variables = 0); + + // Destructor + ~xpath_query(); + + // Get query expression return type + xpath_value_type return_type() const; + + // Evaluate expression as boolean value in the specified context; performs type conversion if necessary. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. + bool evaluate_boolean(const xpath_node& n) const; + + // Evaluate expression as double value in the specified context; performs type conversion if necessary. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. + double evaluate_number(const xpath_node& n) const; + + #ifndef PUGIXML_NO_STL + // Evaluate expression as string value in the specified context; performs type conversion if necessary. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. + string_t evaluate_string(const xpath_node& n) const; + #endif + + // Evaluate expression as string value in the specified context; performs type conversion if necessary. + // At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero). + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. + // If PUGIXML_NO_EXCEPTIONS is defined, returns empty set instead. + size_t evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const; + + // Evaluate expression as node set in the specified context. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors. + // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node set instead. + xpath_node_set evaluate_node_set(const xpath_node& n) const; + + // Get parsing result (used to get compilation errors in PUGIXML_NO_EXCEPTIONS mode) + const xpath_parse_result& result() const; + + // Safe bool conversion operator + operator unspecified_bool_type() const; + + // Borland C++ workaround + bool operator!() const; + }; + + #ifndef PUGIXML_NO_EXCEPTIONS + // XPath exception class + class PUGIXML_CLASS xpath_exception: public std::exception + { + private: + xpath_parse_result _result; + + public: + // Construct exception from parse result + explicit xpath_exception(const xpath_parse_result& result); + + // Get error message + virtual const char* what() const throw(); + + // Get parse result + const xpath_parse_result& result() const; + }; + #endif + + // XPath node class (either xml_node or xml_attribute) + class PUGIXML_CLASS xpath_node + { + private: + xml_node _node; + xml_attribute _attribute; + + typedef void (*unspecified_bool_type)(xpath_node***); + + public: + // Default constructor; constructs empty XPath node + xpath_node(); + + // Construct XPath node from XML node/attribute + xpath_node(const xml_node& node); + xpath_node(const xml_attribute& attribute, const xml_node& parent); + + // Get node/attribute, if any + xml_node node() const; + xml_attribute attribute() const; + + // Get parent of contained node/attribute + xml_node parent() const; + + // Safe bool conversion operator + operator unspecified_bool_type() const; + + // Borland C++ workaround + bool operator!() const; + + // Comparison operators + bool operator==(const xpath_node& n) const; + bool operator!=(const xpath_node& n) const; + }; + +#ifdef __BORLANDC__ + // Borland C++ workaround + bool PUGIXML_FUNCTION operator&&(const xpath_node& lhs, bool rhs); + bool PUGIXML_FUNCTION operator||(const xpath_node& lhs, bool rhs); +#endif + + // A fixed-size collection of XPath nodes + class PUGIXML_CLASS xpath_node_set + { + public: + // Collection type + enum type_t + { + type_unsorted, // Not ordered + type_sorted, // Sorted by document order (ascending) + type_sorted_reverse // Sorted by document order (descending) + }; + + // Constant iterator type + typedef const xpath_node* const_iterator; + + // Default constructor. Constructs empty set. + xpath_node_set(); + + // Constructs a set from iterator range; data is not checked for duplicates and is not sorted according to provided type, so be careful + xpath_node_set(const_iterator begin, const_iterator end, type_t type = type_unsorted); + + // Destructor + ~xpath_node_set(); + + // Copy constructor/assignment operator + xpath_node_set(const xpath_node_set& ns); + xpath_node_set& operator=(const xpath_node_set& ns); + + // Get collection type + type_t type() const; + + // Get collection size + size_t size() const; + + // Indexing operator + const xpath_node& operator[](size_t index) const; + + // Collection iterators + const_iterator begin() const; + const_iterator end() const; + + // Sort the collection in ascending/descending order by document order + void sort(bool reverse = false); + + // Get first node in the collection by document order + xpath_node first() const; + + // Check if collection is empty + bool empty() const; + + private: + type_t _type; + + xpath_node _storage; + + xpath_node* _begin; + xpath_node* _end; + + void _assign(const_iterator begin, const_iterator end); + }; +#endif + +#ifndef PUGIXML_NO_STL + // Convert wide string to UTF8 + std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const wchar_t* str); + std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const std::basic_string, std::allocator >& str); + + // Convert UTF8 to wide string + std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const char* str); + std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const std::basic_string, std::allocator >& str); +#endif + + // Memory allocation function interface; returns pointer to allocated memory or NULL on failure + typedef void* (*allocation_function)(size_t size); + + // Memory deallocation function interface + typedef void (*deallocation_function)(void* ptr); + + // Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions. + void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate); + + // Get current memory management functions + allocation_function PUGIXML_FUNCTION get_memory_allocation_function(); + deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function(); +} + +#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) +namespace std +{ + // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) + std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_node_iterator&); + std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_attribute_iterator&); + std::forward_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_named_node_iterator&); +} +#endif + +#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) +namespace std +{ + // Workarounds for (non-standard) iterator category detection + std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_node_iterator&); + std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_attribute_iterator&); + std::forward_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_named_node_iterator&); +} +#endif + +#endif + +/** + * Copyright (c) 2006-2012 Arseny Kapoulkine + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index db429367e..ddd49acc3 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -19,7 +19,7 @@ void ModuleList::setShowProgress(bool show) { showProgress = show; } -void ModuleList::add(Module *module) { +void ModuleList::add(ref_ptr module) { modules.push_back(module); } diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp new file mode 100644 index 000000000..a2eff8aac --- /dev/null +++ b/src/XmlExecute.cpp @@ -0,0 +1,197 @@ +#include "mpc/XmlExecute.h" +#include "mpc/magneticField/UniformMagneticField.h" +#include "mpc/magneticField/MagneticFieldGrid.h" +#include "mpc/module/DeflectionCK.h" +#include "mpc/module/SimplePropagation.h" +#include "mpc/module/Output.h" +#include "mpc/module/BreakCondition.h" +#include "mpc/ModuleList.h" + +#include "pugixml.hpp" + +#include + +using namespace pugi; +using namespace std; + +namespace mpc { + +bool XmlExecute::load(const string &filename) { + xml_document doc; + xml_parse_result result = doc.load_file(filename.c_str()); + + if (!result) { + cout << "Error description: " << result.description() << "\n"; + cout << "Error offset: " << result.offset << "\n"; + return false; + } + + xml_node root = doc.child("CRPropa"); + + trajectories = root.child("TrajNumber").attribute("value").as_int(); + cout << "Trajectories: " << trajectories << endl; + + randomSeed = root.child("RandomSeed").attribute("value").as_int(); + cout << "RandomSeed: " << randomSeed << endl; + + // setup MagneticField + xml_node field = root.child("MagneticField"); + if (field) { + string type = field.attribute("type").as_string(); + cout << "MagenticField: " << type << endl; + if (type == "LSS-Grid") { + loadLssGrid(field); + } else { + cout << " --> unknown, set zero field" << endl; + magnetic_field = new UniformMagneticField(Vector3f(0, 0, 0)); + } + } + + // setup Integrator + xml_node integrator = root.child("Integrator"); + if (integrator) { + string type = integrator.attribute("type").as_string(); + cout << "Integrator: " << type << endl; + if (type == "Cash-Karp RK") + loadCashKarp(integrator); + else + cout << " -> unknown" << endl; + } + + // setup Interactions + xml_node interactions = root.child("Interactions"); + if (interactions) { + string type = interactions.attribute("type").as_string(); + cout << "Interactions: " << type << endl; + if (type == "Sophia") + loadSophia(interactions); + else + cout << " -> unknown" << endl; + } + + // observers + xml_node observers = root.child("Observers"); + if (observers) { + string type = observers.attribute("type").as_string(); + cout << "Observers: " << type << endl; + if (type == "Spheres around Observers") + loadSpheresAroundObserver(observers); + else + cout << " -> unknown" << endl; + } + + // output + xml_node output = root.child("Output"); + if (output) { + string type = output.attribute("type").as_string(); + cout << "Output: " << type << endl; + if (type == "Full Trajectories") + loadFullTrajectoryOutput(output); + else + cout << " -> unknown" << endl; + } + + // sources + xml_node sources = root.child("Sources"); + if (sources) { + string type = sources.attribute("type").as_string(); + cout << "Sources: " << type << endl; + if (type == "Discrete") + loadDiscreteSources(sources); + else + cout << " -> unknown" << endl; + } + + minEnergyEeV = root.child("MinEnergy_EeV").attribute("value").as_double() + * EeV; + cout << "Minimum Energy: " << minEnergyEeV / EeV << " EeV" << endl; + modules.add(new MinimumEnergy(minEnergyEeV)); + + maxTimeMpc = root.child("MaxTime_Mpc").attribute("value").as_double() * Mpc; + cout << "Maximum Time: " << maxTimeMpc / Mpc << " Mpc" << endl; + modules.add(new MaximumTrajectoryLength(maxTimeMpc)); + + return true; +} + +void XmlExecute::loadCashKarp(xml_node &node) { + double epsilon = node.child("Epsilon").attribute("value").as_double(); + cout << " - Epsilon: " << epsilon << endl; + + double minstep = node.child("MinStep_Mpc").attribute("value").as_double() + * Mpc; + cout << " - Minimum Step: " << minstep / Mpc << " Mpc " << endl; + + ref_ptr deflection = new DeflectionCK(magnetic_field, epsilon, + minstep); + modules.add(deflection); +} + +void XmlExecute::loadLssGrid(xml_node &node) { + int nx = node.child("Nx").attribute("value").as_int(); + int ny = node.child("Ny").attribute("value").as_int(); + int nz = node.child("Nz").attribute("value").as_int(); + if (nx != ny || nx != nz) + throw runtime_error("Invalid grid size!"); + cout << " - Samples: " << nx << endl; + + double step = node.child("Step_Mpc").attribute("value").as_double() * Mpc; + double size = nx * step; + cout << " - Size: " << size / Mpc << " Mpc " << endl; + + xml_node origin_node = node.child("Origin"); + Vector3d origin; + origin.x = origin_node.child("X_Mpc").attribute("value").as_double(); + origin.y = origin_node.child("Y_Mpc").attribute("value").as_double(); + origin.z = origin_node.child("Z_Mpc").attribute("value").as_double(); + cout << " - Origin: " << origin << endl; + + magnetic_field = new MagneticFieldGrid(origin, size, nx); +} + +void XmlExecute::loadSophia(xml_node &) { + +} + +void XmlExecute::loadSpheresAroundObserver(xml_node &) { + +} + +void XmlExecute::loadDiscreteSources(xml_node &) { + +} + +void XmlExecute::loadFullTrajectoryOutput(xml_node &node) { + string filename = node.child("File").child_value(); + cout << " - Filename: " << filename << endl; + + string option = node.child("File").attribute("option").as_string(); + if (option != "force") { + ifstream ifile(filename.c_str()); + if (ifile) { + throw runtime_error("Outputfile already exists!"); + } + } + + ref_ptr output = new TrajectoryOutput(filename); + modules.add(output); +} + +void XmlExecute::run() { + //operator <<(cout, modules); + ParticleState initial; + initial.setId(getNucleusId(1, 1)); + initial.setEnergy(100 * EeV); + initial.setPosition(Vector3d(0, 0, 0)); + initial.setDirection(Vector3d(1, 0, 0)); + + for (size_t i = 0; i < trajectories; i++) { + ref_ptr candidate = new Candidate(initial); + if (i % (trajectories / 10) == 0) + std::cout << i << std::endl; + modules.run(candidate); + } + +} + +} // namespace mpc diff --git a/src/main.cpp b/src/main.cpp index 6c1815de6..19f08e726 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,49 +1,27 @@ -#include "mpc/ModuleList.h" -#include "mpc/module/SimplePropagation.h" -#include "mpc/module/DeflectionCK.h" -#include "mpc/module/BreakCondition.h" -#include "mpc/module/Output.h" -#include "mpc/module/ElectronPairProduction.h" -#include "mpc/module/PhotoPionProduction.h" -#include "mpc/module/PhotoDisintegration.h" -#include "mpc/module/NuclearDecay.h" -#include "mpc/magneticField/UniformMagneticField.h" -#include "mpc/magneticField/TurbulentMagneticFieldGrid.h" +#include "mpc/XmlExecute.h" + +#include +#include using namespace mpc; +using namespace std; int main(int argc, char **argv) { - ModuleList modules; - - // propagation -------------------------------------------------------- - TurbulentMagneticFieldGrid *bField = new TurbulentMagneticFieldGrid(Vector3d(0, 0, 0), 64., 64, 2., 8., -11. / 3., 1e-12); - bField->initialize(); - modules.add(new DeflectionCK(bField)); - - // interactions ------------------------------------------------------- - modules.add(new NuclearDecay()); - modules.add(new PhotoDisintegration()); - modules.add(new ElectronPairProduction()); - modules.add(new PhotoPionProduction()); - - // break conditions --------------------------------------------------- - modules.add(new MaximumTrajectoryLength(50 * Mpc)); - - // output ------------------------------------------------------------- - modules.add(new ShellOutput()); - - std::cout << modules << std::endl; - - ParticleState initial; - initial.setId(getNucleusId(56, 26)); - initial.setEnergy(100 * EeV); - initial.setPosition(Vector3d(0, 0, 0)); - initial.setDirection(Vector3d(1, 0, 0)); - - ref_ptr candidate = new Candidate(initial); - modules.process(candidate); - - std::cout << "done" << std::endl; + if (argc < 2) { + std::cout << "mpc-run " << std::endl; + return 1; + } + + try { + XmlExecute exe; + if (!exe.load(argv[1])) + return 1; + + exe.run(); + } catch (std::exception &e) { + cerr << e.what() << endl; + return 1; + } return 0; } diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index f5cf11d82..84dcd2750 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -2,6 +2,7 @@ #include #include +#include namespace mpc { @@ -14,9 +15,9 @@ namespace mpc { class LorentzForce: public ExplicitRungeKutta::F { public: ParticleState *particle; - MagneticField *field; + ref_ptr field; - LorentzForce(ParticleState *particle, MagneticField *field) { + LorentzForce(ParticleState *particle, ref_ptr field) { this->particle = particle; this->field = field; } @@ -37,8 +38,10 @@ class LorentzForce: public ExplicitRungeKutta::F { } }; -DeflectionCK::DeflectionCK(MagneticField *field, double tolerance, +DeflectionCK::DeflectionCK(ref_ptr field, double tolerance, double minimumStep) { + if (!field.valid()) + throw std::runtime_error("[mpc::DeflectionCK] No Magnetic field set!"); this->field = field; this->tolerance = tolerance; this->minimumStep = minimumStep; diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 3cc5a0179..11a12ea79 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -18,16 +18,16 @@ TrajectoryOutput::~TrajectoryOutput() { } void TrajectoryOutput::process(Candidate *candidate) const { - char buffer[128]; + char buffer[1024]; size_t pos = 0; - pos += ::sprintf(buffer + pos, "%f, %d, %f", + pos += ::sprintf(buffer + pos, "%.15g, %d, %.15g", candidate->getTrajectoryLength() / Mpc, candidate->current.getId(), candidate->current.getEnergy() / EeV); Vector3d position = candidate->current.getPosition() / Mpc; - pos += ::sprintf(buffer + pos, ", %f, %f, %f", position.x, position.y, + pos += ::sprintf(buffer + pos, ", %.15g, %.15g, %.15g", position.x, position.y, position.z); const Vector3d &dir = candidate->current.getDirection(); - pos += ::sprintf(buffer + pos, ", %f, %f, %f\n", dir.x, dir.y, dir.z); + pos += ::sprintf(buffer + pos, ", %.15g, %.15g, %.15g\n", dir.x, dir.y, dir.z); #pragma omp critical { From 49fc80b1cd08e44897883aa72a984f2108a25e74 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 10 Jul 2012 14:12:54 +0200 Subject: [PATCH 0135/1298] make NuclearMassTable OpenMP safe --- include/mpc/Nucleus.h | 19 ++++++++----- src/Nucleus.cpp | 66 +++++++++++++++++++++---------------------- 2 files changed, 45 insertions(+), 40 deletions(-) diff --git a/include/mpc/Nucleus.h b/include/mpc/Nucleus.h index 28b613beb..e4cd9496b 100644 --- a/include/mpc/Nucleus.h +++ b/include/mpc/Nucleus.h @@ -5,15 +5,20 @@ namespace mpc { -// This implements the 2006 Monte Carlo nuclear code scheme. -// Ion numbers are +/- 10LZZZAAAI. -// AAA is A - total baryon number -// ZZZ is Z - total charge -// L is the total number of strange quarks. -// I is the isomer number, with I=0 corresponding to the ground state. +/** This implements the 2006 Monte Carlo nuclear code scheme. + * Ion numbers are +/- 10LZZZAAAI. + * AAA is A - total baryon number + * ZZZ is Z - total charge + * L is the total number of strange quarks. + * I is the isomer number, with I=0 corresponding to the ground state. + */ int getNucleusId(int a, int z); -void initNuclearMassTable(); +/** Return the nucleus mass by lookup from a table. + * The masses are the atomic masses from the NIST database (http://www.nist.gov/pml/data/comp.cfm) minus electron masses, neglecting electron binding energies. + * Unmeasured atomic masses are taken to be A * amu minus electron masses. + * The data table is generated by mpc/data/NuclearMass/createNuclearMassTable. + */ double getNucleusMass(int id); int getChargeNumberFromNucleusId(int id); diff --git a/src/Nucleus.cpp b/src/Nucleus.cpp index 913bb9f0e..3f2750c6e 100644 --- a/src/Nucleus.cpp +++ b/src/Nucleus.cpp @@ -12,51 +12,51 @@ namespace mpc { int getNucleusId(int a, int z) { - if (z < 0) - throw std::runtime_error( - "mpc::Nucleus: no nucleus with Z < 0, A=" + kiss::str(a) + " Z=" - + kiss::str(z)); - if (a < 1) - throw std::runtime_error( - "mpc::Nucleus: no nucleus with A < 1, A=" + kiss::str(a) + " Z=" - + kiss::str(z)); - if (a < z) - throw std::runtime_error( - "mpc::Nucleus: no nucleus with A < Z, A=" + kiss::str(a) + " Z=" - + kiss::str(z)); - return 1000000000 + z * 10000 + a * 10; + if (z < 0) + throw std::runtime_error( + "mpc::Nucleus: no nucleus with Z < 0, A=" + kiss::str(a) + " Z=" + + kiss::str(z)); + if (a < 1) + throw std::runtime_error( + "mpc::Nucleus: no nucleus with A < 1, A=" + kiss::str(a) + " Z=" + + kiss::str(z)); + if (a < z) + throw std::runtime_error( + "mpc::Nucleus: no nucleus with A < Z, A=" + kiss::str(a) + " Z=" + + kiss::str(z)); + return 1000000000 + z * 10000 + a * 10; } +struct NuclearMassTable { + std::vector table; -static std::vector nuclearMassTable; + NuclearMassTable() { + std::string filename = getDataPath("/NuclearMass/nuclearMassTable.txt"); + std::ifstream infile(filename.c_str()); -void initNuclearMassTable() { - std::string filename = getDataPath("/NuclearMass/nuclearMassTable.txt"); - std::ifstream infile(filename.c_str()); + if (!infile.good()) + throw std::runtime_error("mpc: could not open file " + filename); - if (!infile.good()) - throw std::runtime_error("mpc: could not open file " + filename); - - int Z, N; - double mass; - while (infile.good()) { - if (infile.peek() != '#') { - infile >> Z >> N >> mass; - nuclearMassTable.push_back(mass); + int Z, N; + double mass; + while (infile.good()) { + if (infile.peek() != '#') { + infile >> Z >> N >> mass; + table.push_back(mass); + } + infile.ignore(std::numeric_limits::max(), '\n'); } - infile.ignore(std::numeric_limits::max(), '\n'); + + infile.close(); } +}; - infile.close(); -} +static NuclearMassTable nuclearMassTable; double getNucleusMass(int id) { - if (nuclearMassTable.size() == 0) - initNuclearMassTable(); - int Z = HepPID::Z(id); int N = HepPID::A(id) - Z; - double mass = nuclearMassTable[Z * 31 + N]; + double mass = nuclearMassTable.table[Z * 31 + N]; if (mass == 0) throw std::runtime_error("mpc: nucleus not found " + kiss::str(id)); return mass; From 5002b125551f5cf6a6c04007debf8a1bf0d1dedd Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 11 Jul 2012 14:30:27 +0200 Subject: [PATCH 0136/1298] update nuclear decay table --- include/mpc/Nucleus.h | 5 ++--- include/mpc/ParticleState.h | 6 +++--- src/ParticleState.cpp | 11 ++--------- test/testMagneticField.cpp | 4 ++-- 4 files changed, 9 insertions(+), 17 deletions(-) diff --git a/include/mpc/Nucleus.h b/include/mpc/Nucleus.h index e4cd9496b..16910d16d 100644 --- a/include/mpc/Nucleus.h +++ b/include/mpc/Nucleus.h @@ -13,6 +13,8 @@ namespace mpc { * I is the isomer number, with I=0 corresponding to the ground state. */ int getNucleusId(int a, int z); +int getChargeNumberFromNucleusId(int id); +int getMassNumberFromNucleusId(int id); /** Return the nucleus mass by lookup from a table. * The masses are the atomic masses from the NIST database (http://www.nist.gov/pml/data/comp.cfm) minus electron masses, neglecting electron binding energies. @@ -21,9 +23,6 @@ int getNucleusId(int a, int z); */ double getNucleusMass(int id); -int getChargeNumberFromNucleusId(int id); -int getMassNumberFromNucleusId(int id); - } // namespace mpc #endif /* NUCLEUS_H_ */ diff --git a/include/mpc/ParticleState.h b/include/mpc/ParticleState.h index c6d42dbce..b93051d53 100644 --- a/include/mpc/ParticleState.h +++ b/include/mpc/ParticleState.h @@ -1,5 +1,5 @@ -#ifndef PARTICLE_H_ -#define PARTICLE_H_ +#ifndef MPC_PARTICLE_STATE_H_ +#define MPC_PARTICLE_STATE_H_ #include "mpc/Vector3.h" #include "mpc/Units.h" @@ -52,4 +52,4 @@ class ParticleState { } // namespace mpc -#endif /* PARTICLE_H_ */ +#endif /* MPC_PARTICLE_STATE_H_ */ diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index 96d956fb4..7d0217e63 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -56,18 +56,11 @@ int ParticleState::getMassNumber() const { } double ParticleState::getMass() const { - if (HepPID::isNucleus(id)) - return pmass; - else - throw std::runtime_error( - "mpc::ParticleState::getMass only for nuclei/nucleons"); + return pmass; } bool ParticleState::isNucleus() const { - if (HepPID::isNucleus(id)) - return true; - else - return false; + return HepPID::isNucleus(id); } double ParticleState::getLorentzFactor() const { diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index b9997de60..c217583ec 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -108,10 +108,10 @@ TEST(testMagneticFieldGrid, DumpLoad) { for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) B1.get(ix, iy, iz) = Vector3f(1, 2, 3); - B1.dump("testDump.raw"); + B1.dump("test/testDump.raw"); MagneticFieldGrid B2(Vector3d(0.), 3, 3); - B2.load("testDump.raw"); + B2.load("test/testDump.raw"); for (int ix = 0; ix < 3; ix++) { for (int iy = 0; iy < 3; iy++) { From 1e6e8941b30f98a76927766d59e39c4adebc1bb9 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 12 Jul 2012 16:13:03 +0200 Subject: [PATCH 0137/1298] change back ref_ptr to pointer to restore python usage --- include/mpc/ModuleList.h | 2 +- include/mpc/Units.h | 22 ++++++++++++---------- include/mpc/module/DeflectionCK.h | 7 ++++--- src/ModuleList.cpp | 2 +- src/main.cpp | 3 +-- src/module/DeflectionCK.cpp | 18 ++++++++---------- 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/include/mpc/ModuleList.h b/include/mpc/ModuleList.h index 1e7e1928f..93f3f38bb 100644 --- a/include/mpc/ModuleList.h +++ b/include/mpc/ModuleList.h @@ -25,7 +25,7 @@ class ModuleList: public Referenced { virtual ~ModuleList(); void setShowProgress(bool show); - void add(ref_ptr ); + void add(Module* module); virtual void process(Candidate *candidate); void run(Candidate *candidate, bool recursive = true); void run(candidate_vector_t &candidates, bool recursive = true); diff --git a/include/mpc/Units.h b/include/mpc/Units.h index 05fee567a..66a0d57c7 100644 --- a/include/mpc/Units.h +++ b/include/mpc/Units.h @@ -30,20 +30,22 @@ static const double mass_electron = 9.10938291e-31 * kilogram; static const double h_planck = 6.62606957e-34 * joule * second; // other units +static const double gram = 1e-3 * kilogram; +static const double centimeter = 1e-2 * meter; // gauss -static const double gauss = 1.e-4 * tesla; -static const double nanogauss = 1.e-9 * gauss; +static const double gauss = 1e-4 * tesla; +static const double nanogauss = 1e-9 * gauss; static const double nG = nanogauss; // electron volt static const double electronvolt = eplus * joule; -static const double megaelectronvolt = 1.e6 * electronvolt; -static const double kiloelectronvolt = 1.e+3 * electronvolt; -static const double gigaelectronvolt = 1.e+9 * electronvolt; -static const double teraelectronvolt = 1.e+12 * electronvolt; -static const double petaelectronvolt = 1.e+15 * electronvolt; -static const double exaelectronvolt = 1.e+18 * electronvolt; +static const double megaelectronvolt = 1e6 * electronvolt; +static const double kiloelectronvolt = 1e+3 * electronvolt; +static const double gigaelectronvolt = 1e+9 * electronvolt; +static const double teraelectronvolt = 1e+12 * electronvolt; +static const double petaelectronvolt = 1e+15 * electronvolt; +static const double exaelectronvolt = 1e+18 * electronvolt; static const double eV = electronvolt; static const double keV = kiloelectronvolt; static const double MeV = megaelectronvolt; @@ -54,8 +56,8 @@ static const double EeV = exaelectronvolt; // parsec static const double parsec = 3.0856775807e+16 * meter; -static const double kiloparsec = 1.e3 * parsec; -static const double megaparsec = 1.e6 * parsec; +static const double kiloparsec = 1e3 * parsec; +static const double megaparsec = 1e6 * parsec; static const double kpc = kiloparsec; static const double Mpc = megaparsec; diff --git a/include/mpc/module/DeflectionCK.h b/include/mpc/module/DeflectionCK.h index 03f733931..c9ae81ad8 100644 --- a/include/mpc/module/DeflectionCK.h +++ b/include/mpc/module/DeflectionCK.h @@ -18,11 +18,12 @@ namespace mpc { */ class DeflectionCK: public SimulationVolumeDependentModule { public: - ref_ptr field; + MagneticField *field; ExplicitRungeKutta erk; - double tolerance, minimumStep; + double tolerance; + double minStep; - DeflectionCK(ref_ptr field, double tolerance = 1e-4, double minimumStep = 0.1 * kpc); + DeflectionCK(MagneticField *field, double tolerance = 1e-4, double minimumStep = 0.1 * kpc); std::string getDescription() const; void process(Candidate *candidate) const; void updateSimulationVolume(const Vector3d &origin, double size); diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index ddd49acc3..db429367e 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -19,7 +19,7 @@ void ModuleList::setShowProgress(bool show) { showProgress = show; } -void ModuleList::add(ref_ptr module) { +void ModuleList::add(Module *module) { modules.push_back(module); } diff --git a/src/main.cpp b/src/main.cpp index 19f08e726..acf6cace7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,7 +8,7 @@ using namespace std; int main(int argc, char **argv) { if (argc < 2) { - std::cout << "mpc-run " << std::endl; + cout << "mpc-run " << endl; return 1; } @@ -16,7 +16,6 @@ int main(int argc, char **argv) { XmlExecute exe; if (!exe.load(argv[1])) return 1; - exe.run(); } catch (std::exception &e) { cerr << e.what() << endl; diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index 84dcd2750..b4251cc34 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -15,7 +15,7 @@ namespace mpc { class LorentzForce: public ExplicitRungeKutta::F { public: ParticleState *particle; - ref_ptr field; + MagneticField *field; LorentzForce(ParticleState *particle, ref_ptr field) { this->particle = particle; @@ -38,13 +38,11 @@ class LorentzForce: public ExplicitRungeKutta::F { } }; -DeflectionCK::DeflectionCK(ref_ptr field, double tolerance, - double minimumStep) { - if (!field.valid()) - throw std::runtime_error("[mpc::DeflectionCK] No Magnetic field set!"); +DeflectionCK::DeflectionCK(MagneticField *field, double tolerance, + double minStep) { this->field = field; this->tolerance = tolerance; - this->minimumStep = minimumStep; + this->minStep = minStep; erk.loadCashKarp(); } @@ -52,14 +50,14 @@ std::string DeflectionCK::getDescription() const { std::stringstream sstr; sstr << "Propagation in magnetic fields using the Cash-Karp method. Tolerance: " - << tolerance << ", Minimum Step: " << minimumStep / kpc << " kpc"; + << tolerance << ", Minimum Step: " << minStep / kpc << " kpc"; return sstr.str(); } void DeflectionCK::process(Candidate *candidate) const { // rectlinear propagation in case of no charge if (candidate->current.getChargeNumber() == 0) { - double nextStep = std::max(minimumStep, candidate->getNextStep()); + double nextStep = std::max(minStep, candidate->getNextStep()); Vector3d pos = candidate->current.getPosition(); Vector3d dir = candidate->current.getDirection(); candidate->current.setPosition(pos + dir * nextStep); @@ -72,7 +70,7 @@ void DeflectionCK::process(Candidate *candidate) const { candidate->current.getMomentum()); PhasePoint yOut, yErr, yScale; LorentzForce dydt(&candidate->current, field); - double h = std::max(candidate->getNextStep(), minimumStep) / c_light; + double h = std::max(candidate->getNextStep(), minStep) / c_light; double hTry, r; // phase-point to compare with error for step size control @@ -97,7 +95,7 @@ void DeflectionCK::process(Candidate *candidate) const { // limit step change h = std::max(h, 0.1 * hTry); h = std::min(h, 5 * hTry); - } while (r > 1 && h >= minimumStep); + } while (r > 1 && h >= minStep); candidate->current.setPosition(yOut.a); candidate->current.setDirection(yOut.b.getUnitVector()); From 3aa261e89f122d4fb49c48f70dc62310336578a8 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 12 Jul 2012 16:13:45 +0200 Subject: [PATCH 0138/1298] implement profiles in SPHTurbulent... --- .../SPHTurbulentMagneticFieldGrid.h | 16 +-- .../SPHTurbulentMagneticFieldGrid.cpp | 34 +++-- test/testSPHField.cpp | 128 +++++++++--------- 3 files changed, 101 insertions(+), 77 deletions(-) diff --git a/include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h b/include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h index 3d825f369..ac8b1fb92 100644 --- a/include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h +++ b/include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h @@ -15,6 +15,10 @@ namespace mpc { @brief Turbulent magnetic field on a cubic grid modulated with an SPH density field. */ class SPHTurbulentMagneticFieldGrid: public TurbulentMagneticFieldGrid { + std::auto_ptr sphField; /**< SPH (density) field */ + double lRho[67]; + double lB[67]; + public: /** Constructor. Reimplementation of TurbulentMagneticField. */ SPHTurbulentMagneticFieldGrid(Vector3d origin, double size, size_t samples) : @@ -34,21 +38,17 @@ class SPHTurbulentMagneticFieldGrid: public TurbulentMagneticFieldGrid { * @param origin Origin of the SPH field * @param size Size of the SPH field * @param bins Number of bins of the SPH field - * @param exp Exponent for the density modulation - * @param norm Normalization of the field strength */ - void setModulation(std::string filename, Vector3d origin, double size, - size_t samples, double exp, double norm); + void setDensityField(std::string filename, Vector3d origin, double size, + size_t bins); + + void setModulation(std::string filename); /** Get the density modulated magnetic field vector */ Vector3d getField(const Vector3d &position) const; /** Get the density in [10^10 M_sol * h^2 / kpc^3] */ double getRho(const Vector3d &position) const; - - double exponent; /**< Exponent of modulation with the density field */ - double normalization; /**< Normalization factor */ - std::auto_ptr sphField; /**< SPH (density) field */ }; } // namespace mpc diff --git a/src/magneticField/SPHTurbulentMagneticFieldGrid.cpp b/src/magneticField/SPHTurbulentMagneticFieldGrid.cpp index 9b17fd072..2ab024b6d 100644 --- a/src/magneticField/SPHTurbulentMagneticFieldGrid.cpp +++ b/src/magneticField/SPHTurbulentMagneticFieldGrid.cpp @@ -1,19 +1,37 @@ #include "mpc/magneticField/SPHTurbulentMagneticFieldGrid.h" +#include "mpc/Common.h" +#include "mpc/Units.h" namespace mpc { -void SPHTurbulentMagneticFieldGrid::setModulation(std::string filename, - Vector3d origin, double size, size_t samples, double exp, double norm) { - exponent = exp; - normalization = norm; - sphField.reset(new SPHMagneticField(origin, size, samples, filename)); +void SPHTurbulentMagneticFieldGrid::setDensityField(std::string filename, + Vector3d origin, double size, size_t bins) { + sphField.reset(new SPHMagneticField(origin, size, bins, filename)); +} + +void SPHTurbulentMagneticFieldGrid::setModulation(std::string filename) { + // load modulation profile + std::ifstream infile(filename.c_str()); + if (!infile.good()) + throw std::runtime_error("mpc: could not open file " + filename); + for (int i = 0; i < 67; i++) { + infile >> lRho[i] >> lB[i]; + infile.ignore(std::numeric_limits::max(), '\n'); + } + infile.close(); } Vector3d SPHTurbulentMagneticFieldGrid::getField( const Vector3d &position) const { - Vector3d b = MagneticFieldGrid::getField(position); - double rho = sphField->getRho(position); - return b * pow(rho, exponent) * normalization; + double rho = log10(sphField->getRho(position) / 1000); // log10(density in [g/cm^3]) + double m; // strength in [G] + if (rho <= -32) + m = 206.404 + 12.9872 * rho + 0.193117 * rho * rho; + else if (rho >= -28) + m = -37.3625 - 2.74343 * rho - 0.0585562 * rho * rho; + else + m = interpolate(rho, lRho, lB); + return MagneticFieldGrid::getField(position) * pow(10, m) / 10000; // B-field in [T] } double SPHTurbulentMagneticFieldGrid::getRho(const Vector3d &position) const { diff --git a/test/testSPHField.cpp b/test/testSPHField.cpp index f895192bf..2231e90ff 100644 --- a/test/testSPHField.cpp +++ b/test/testSPHField.cpp @@ -7,65 +7,69 @@ namespace mpc { -TEST(testSPHMagneticField, simpleTest) { - // Tests if a direct SPH field can be constructed and prints RMS and mean field strength - Vector3d origin(80 * Mpc); - double size = 40 * Mpc; - - // gadget::DirectField may throw if queried for magnetic fields on the borders - Vector3d safeOrigin = origin - Vector3d(1 * kpc); - double safeSize = size + 2 * kpc; - - SPHMagneticField B(safeOrigin, safeSize, 20, getDataPath("SPH/mhd_z.db").c_str()); - - int n = 64; - double spacing = 40 * Mpc / (n - 1); - double brms = 0; - Vector3d bmean(0, 0, 0); - for (int ix = 0; ix < n; ix++) - for (int iy = 0; iy < n; iy++) - for (int iz = 0; iz < n; iz++) { - Vector3d b = B.getField(origin + Vector3d(ix, iy, iz) * spacing); - brms += b.getMag2(); - bmean += b; - } - - brms = sqrt(brms / n / n / n); - bmean /= n * n * n; - - std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; - std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; -} - -TEST(testSPHMagneticFieldGrid, simpleTest) { - // Tests if a sampled SPH field can be constructed and prints RMS and mean field strength - Vector3d origin(80 * Mpc); - size_t n = 64; - double size = 40 * Mpc; - double spacing = size / (n - 1); - - // gadget::SampledField may throw if queried for magnetic fields on the borders - Vector3d safeOrigin = origin - Vector3d(1 * kpc); - double safeSize = size + 2 * kpc; - - SPHMagneticFieldGrid B(safeOrigin, safeSize, n, getDataPath("SPH/mhd_z.db").c_str()); - - double brms = 0; - Vector3d bmean(0, 0, 0); - for (int ix = 0; ix < n; ix++) - for (int iy = 0; iy < n; iy++) - for (int iz = 0; iz < n; iz++) { - Vector3d b = B.getField(origin + Vector3d(ix, iy, iz) * spacing); - brms += b.getMag2(); - bmean += b; - } - - brms = sqrt(brms / n / n / n); - bmean /= n * n * n; - - std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; - std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; -} +//TEST(testSPHMagneticField, simpleTest) { +// // Tests if a direct SPH field can be constructed and prints RMS and mean field strength +// Vector3d origin(80 * Mpc); +// double size = 40 * Mpc; +// +// // gadget::DirectField may throw if queried for magnetic fields on the borders +// Vector3d safeOrigin = origin - Vector3d(1 * kpc); +// double safeSize = size + 2 * kpc; +// +// SPHMagneticField B(safeOrigin, safeSize, 20, +// getDataPath("SPH/mhd_z.db").c_str()); +// +// int n = 64; +// double spacing = 40 * Mpc / (n - 1); +// double brms = 0; +// Vector3d bmean(0, 0, 0); +// for (int ix = 0; ix < n; ix++) +// for (int iy = 0; iy < n; iy++) +// for (int iz = 0; iz < n; iz++) { +// Vector3d b = B.getField( +// origin + Vector3d(ix, iy, iz) * spacing); +// brms += b.getMag2(); +// bmean += b; +// } +// +// brms = sqrt(brms / n / n / n); +// bmean /= n * n * n; +// +// std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; +// std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; +//} +// +//TEST(testSPHMagneticFieldGrid, simpleTest) { +// // Tests if a sampled SPH field can be constructed and prints RMS and mean field strength +// Vector3d origin(80 * Mpc); +// size_t n = 64; +// double size = 40 * Mpc; +// double spacing = size / (n - 1); +// +// // gadget::SampledField may throw if queried for magnetic fields on the borders +// Vector3d safeOrigin = origin - Vector3d(1 * kpc); +// double safeSize = size + 2 * kpc; +// +// SPHMagneticFieldGrid B(safeOrigin, safeSize, n, +// getDataPath("SPH/mhd_z.db").c_str()); +// +// double brms = 0; +// Vector3d bmean(0, 0, 0); +// for (int ix = 0; ix < n; ix++) +// for (int iy = 0; iy < n; iy++) +// for (int iz = 0; iz < n; iz++) { +// Vector3d b = B.getField( +// origin + Vector3d(ix, iy, iz) * spacing); +// brms += b.getMag2(); +// bmean += b; +// } +// +// brms = sqrt(brms / n / n / n); +// bmean /= n * n * n; +// +// std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; +// std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; +//} TEST(testSPHTurbulentMagneticField, simpleTest) { // Tests if a sampled SPH field can be constructed and prints RMS and mean field strength @@ -77,10 +81,12 @@ TEST(testSPHTurbulentMagneticField, simpleTest) { SPHTurbulentMagneticFieldGrid B(origin, size, n); B.setTurbulenceProperties(2 * spacing, 8 * spacing, -11. / 3); B.initialize(); + B.normalize(1 / B.getRMSFieldStrength()); std::cout << "modulating" << std::endl; - B.setModulation(getDataPath("SPH/mhd_z.db").c_str(), Vector3d(99 * Mpc), - 42 * Mpc, 20, 2. / 3., 1.); + B.setDensityField(getDataPath("SPH/mhd_z.db").c_str(), Vector3d(99 * Mpc), + 42 * Mpc, 20); + B.setModulation(getDataPath("SPH/miniati-profile.txt")); std::cout << "sampling" << std::endl; double brms = 0; From 7e72d1f4837c4d5d217e32363adfbc7e2ae16b6a Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 16 Jul 2012 13:47:24 +0200 Subject: [PATCH 0139/1298] add Vector3 min, max --- include/mpc/Vector3.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/mpc/Vector3.h b/include/mpc/Vector3.h index d805d091a..1bea0c8db 100644 --- a/include/mpc/Vector3.h +++ b/include/mpc/Vector3.h @@ -166,6 +166,14 @@ class Vector3 { return Vector3(std::ceil(x), std::ceil(y), std::ceil(z)); } + T min() { + return std::min(x, std::min(y, z)); + } + + T max() { + return std::max(x, std::max(y, z)); + } + bool operator <(const Vector3 &v) const { if (x > v.x) return false; From 343d6eb3db1172fab26627461a3fb20b408eaa68 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 16 Jul 2012 13:47:47 +0200 Subject: [PATCH 0140/1298] improve break conditions --- include/mpc/module/BreakCondition.h | 46 ++++++++++++++++++------ src/module/BreakCondition.cpp | 55 +++++++++++++++++++---------- test/testBreakCondition.cpp | 24 +++++++++---- 3 files changed, 89 insertions(+), 36 deletions(-) diff --git a/include/mpc/module/BreakCondition.h b/include/mpc/module/BreakCondition.h index 6fe6a28ba..aaa8c5f90 100644 --- a/include/mpc/module/BreakCondition.h +++ b/include/mpc/module/BreakCondition.h @@ -18,6 +18,7 @@ namespace mpc { class MaximumTrajectoryLength: public Module { private: double maxLength; + void updateDescription(); public: MaximumTrajectoryLength(double length = 0); @@ -36,6 +37,7 @@ class MaximumTrajectoryLength: public Module { class MinimumEnergy: public Module { private: double minEnergy; + void updateDescription(); public: MinimumEnergy(double minEnergy = 0); @@ -47,16 +49,21 @@ class MinimumEnergy: public Module { /** @class SmallObserverSphere @brief Detects particles when entering the sphere. + + This module flags the candidate upon entering a sphere. + In this case the candidate is by default flagged "Detected" made inactive. + This module limits the next step size to prevent candidates from overshooting. */ class SmallObserverSphere: public Module { - void updateDescription(); -public: +private: double radius; Vector3d center; std::string flag; std::string flagValue; bool makeInactive; + void updateDescription(); +public: SmallObserverSphere(Vector3d center, double radius, std::string flag = "Detected", std::string flagValue = ""); void setMakeInactive(bool makeInactive); @@ -65,16 +72,18 @@ class SmallObserverSphere: public Module { /** @class PeriodicBox - @brief Box with periodic boundaries + @brief Box with periodic boundaries. - If a particle leaves the periodic box it is placed at the opposite side and its initial (source) position changed accordingly. - Particles can overshoot (be outside of the box during the step) since the step size is not limited by this module. + If a candidate leaves the periodic box it is placed at the opposite side and its initial (source) position changed accordingly. + Candidates can overshoot (be outside of the box during the step) since the step size is not limited by this module. */ class PeriodicBox: public Module { -public: +private: Vector3d origin; Vector3d size; + void updateDescription(); +public: PeriodicBox(Vector3d origin, Vector3d size); void process(Candidate *candidate) const; }; @@ -82,9 +91,13 @@ class PeriodicBox: public Module { /** @class CubicBoundary @brief Flags a particle when exiting the cube. + + This module flags the candidate when outside of a cube, which is defined by the cube's lower corner and edge length. + By default the candidate is flagged "OutOfBounds" and made inactive. + Optionally the module can ensure the candidate does not overshoot the boundary by more than a set margin. */ class CubicBoundary: public Module { -protected: +private: Vector3d origin; double size; double margin; @@ -93,9 +106,10 @@ class CubicBoundary: public Module { bool makeInactive; bool limitStep; void updateDescription(); + public: - CubicBoundary(Vector3d origin, double size, std::string flag = "OutOfBounds", - std::string flagValue = ""); + CubicBoundary(Vector3d origin, double size, + std::string flag = "OutOfBounds", std::string flagValue = ""); void setMakeInactive(bool makeInactive); void setLimitStep(bool limitStep, double margin); void process(Candidate *candidate) const; @@ -104,9 +118,13 @@ class CubicBoundary: public Module { /** @class SphericalBoundary @brief Flag a particle when leaving the sphere. + + This module flags the candidate when outside of a sphere, which is defined by the sphere's center and radius. + By default the candidate is flagged "OutOfBounds" and made inactive. + Optionally the module can ensure the candidate does not overshoot the boundary by more than a set margin. */ class SphericalBoundary: public Module { -protected: +private: Vector3d center; double radius; double margin; @@ -115,6 +133,7 @@ class SphericalBoundary: public Module { bool makeInactive; bool limitStep; void updateDescription(); + public: SphericalBoundary(Vector3d center, double radius, std::string flag = "OutOfBounds", std::string flagValue = ""); @@ -126,9 +145,13 @@ class SphericalBoundary: public Module { /** @class EllipsoidalBoundary @brief Flags a particle when leaving the ellipsoid. + + This module flags the candidate when outside of an ellipsoid, which is defined by the ellipsoids two focal points and major axis length. + By default the candidate is flagged "OutOfBounds" and made inactive. + Optionally the module can ensure the candidate does not overshoot the boundary by more than a set margin. */ class EllipsoidalBoundary: public Module { -protected: +private: Vector3d focalPoint1; Vector3d focalPoint2; double majorAxis; @@ -138,6 +161,7 @@ class EllipsoidalBoundary: public Module { bool makeInactive; bool limitStep; void updateDescription(); + public: EllipsoidalBoundary(Vector3d focalPoint1, Vector3d focalPoint2, double majorAxis, std::string flag = "OutOfBounds", diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp index f6a4f5494..672e0dd9a 100644 --- a/src/module/BreakCondition.cpp +++ b/src/module/BreakCondition.cpp @@ -2,15 +2,14 @@ namespace mpc { -MaximumTrajectoryLength::MaximumTrajectoryLength(double length) : - maxLength(length) { - std::stringstream s; - s << "Maximum trajectory length: " << maxLength / Mpc << " Mpc"; - setDescription(s.str()); +MaximumTrajectoryLength::MaximumTrajectoryLength(double maxLength) { + this->maxLength = maxLength; + updateDescription(); } void MaximumTrajectoryLength::setMaximumTrajectoryLength(double length) { maxLength = length; + updateDescription(); } double MaximumTrajectoryLength::getMaximumTrajectoryLength() const { @@ -22,19 +21,25 @@ void MaximumTrajectoryLength::process(Candidate *candidate) const { if (l >= maxLength) { candidate->setActive(false); candidate->setProperty("Deactivated", getDescription()); - } else + } else { candidate->limitNextStep(maxLength - l); + } } -MinimumEnergy::MinimumEnergy(double minEnergy) : - minEnergy(minEnergy) { +void MaximumTrajectoryLength::updateDescription() { std::stringstream s; - s << "Minimum energy: " << minEnergy / EeV << " EeV"; + s << "Maximum trajectory length: " << maxLength / Mpc << " Mpc"; setDescription(s.str()); } +MinimumEnergy::MinimumEnergy(double minEnergy) { + this->minEnergy = minEnergy; + updateDescription(); +} + void MinimumEnergy::setMinimumEnergy(double energy) { minEnergy = energy; + updateDescription(); } double MinimumEnergy::getMinimumEnergy() const { @@ -48,6 +53,12 @@ void MinimumEnergy::process(Candidate *candidate) const { } } +void MinimumEnergy::updateDescription() { + std::stringstream s; + s << "Minimum energy: " << minEnergy / EeV << " EeV"; + setDescription(s.str()); +} + SmallObserverSphere::SmallObserverSphere(Vector3d center, double radius, std::string flag, std::string flagValue) { this->center = center; @@ -83,8 +94,10 @@ void SmallObserverSphere::updateDescription() { setDescription(s.str()); } -PeriodicBox::PeriodicBox(Vector3d origin, Vector3d size) : - origin(origin), size(size) { +PeriodicBox::PeriodicBox(Vector3d origin, Vector3d size) { + this->origin = origin; + this->size = size; + updateDescription(); } void PeriodicBox::process(Candidate *candidate) const { @@ -92,10 +105,17 @@ void PeriodicBox::process(Candidate *candidate) const { Vector3d n = ((position - origin) / size).floor(); // integers for translation if ((n.x != 0) or (n.y != 0) or (n.z != 0)) { candidate->current.setPosition(position - n * size); - candidate->initial.setPosition(candidate->initial.getPosition() - n * size); + candidate->initial.setPosition( + candidate->initial.getPosition() - n * size); } } +void PeriodicBox::updateDescription() { + std::stringstream s; + s << "Periodic box: origin " << origin << ", size " << size; + setDescription(s.str()); +} + CubicBoundary::CubicBoundary(Vector3d origin, double size, std::string flag, std::string flagValue) { this->origin = origin; @@ -120,17 +140,16 @@ void CubicBoundary::setLimitStep(bool limitStep, double margin) { } void CubicBoundary::process(Candidate *candidate) const { - Vector3d relPos = candidate->current.getPosition() - origin; - double lo = std::min(relPos.x, std::min(relPos.y, relPos.z)); - double hi = std::max(relPos.x, std::max(relPos.y, relPos.z)); - if ((lo <= 0.) or (hi >= size)) { + Vector3d r = candidate->current.getPosition() - origin; + double lo = r.min(); + double hi = r.max(); + if ((lo <= 0) or (hi >= size)) { candidate->setProperty(flag, flagValue); if (makeInactive) { candidate->setActive(false); candidate->setProperty("Deactivated", getDescription()); } - } - if (limitStep) { + } else if (limitStep) { candidate->limitNextStep(lo + margin); candidate->limitNextStep(size - hi + margin); } diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index a62ee807c..330af27c4 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -116,14 +116,24 @@ TEST(CubicBoundary, outside) { EXPECT_FALSE(candidate.isActive()); } -TEST(CubicBoundary, limitStep) { - CubicBoundary cube(Vector3d(0, 0, 0), 10); +TEST(CubicBoundary, limitStepLower) { + CubicBoundary cube(Vector3d(10, 10, 10), 10); cube.setLimitStep(true, 1); Candidate candidate; - candidate.setNextStep(10); - candidate.current.setPosition(Vector3d(5, 5, 0.5)); + candidate.current.setPosition(Vector3d(15, 15, 10.5)); + candidate.setNextStep(100); cube.process(&candidate); - EXPECT_DOUBLE_EQ(candidate.getNextStep(), 1.5); + EXPECT_DOUBLE_EQ(1.5, candidate.getNextStep()); +} + +TEST(CubicBoundary, limitStepUpper) { + CubicBoundary cube(Vector3d(-10, -10, -10), 10); + cube.setLimitStep(true, 1); + Candidate candidate; + candidate.current.setPosition(Vector3d(-5, -5, -0.5)); + candidate.setNextStep(100); + cube.process(&candidate); + EXPECT_DOUBLE_EQ(1.5, candidate.getNextStep()); } TEST(SphericalBoundary, inside) { @@ -155,10 +165,10 @@ TEST(SphericalBoundary, limitStep) { SphericalBoundary sphere(Vector3d(0, 0, 0), 10); sphere.setLimitStep(true, 1); Candidate candidate; - candidate.setNextStep(2); + candidate.setNextStep(100); candidate.current.setPosition(Vector3d(0, 0, 9.5)); sphere.process(&candidate); - EXPECT_DOUBLE_EQ(candidate.getNextStep(), 1.5); + EXPECT_DOUBLE_EQ(1.5, candidate.getNextStep()); } TEST(EllipsoidalBoundary, inside) { From 98a4fdbc57ba26d8f8c4fa1df851e2f995c51ce3 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 16 Jul 2012 18:47:51 +0200 Subject: [PATCH 0141/1298] reduce output precision --- include/mpc/magneticField/UniformMagneticField.h | 8 ++++---- src/module/DeflectionCK.cpp | 13 +++++++------ src/module/Output.cpp | 16 ++++++++-------- test/testMagneticField.cpp | 5 +++-- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/include/mpc/magneticField/UniformMagneticField.h b/include/mpc/magneticField/UniformMagneticField.h index 0111151e3..d428e7c8c 100644 --- a/include/mpc/magneticField/UniformMagneticField.h +++ b/include/mpc/magneticField/UniformMagneticField.h @@ -2,6 +2,7 @@ #define MPC_UNIFORMAGNETICFIELD_H_ #include "mpc/magneticField/MagneticField.h" +#include namespace mpc { @@ -10,6 +11,9 @@ namespace mpc { @brief Magnetic field with one B-field vector. */ class UniformMagneticField: public MagneticField { +private: + Vector3d value; + public: UniformMagneticField(const Vector3d &value) : value(value) { @@ -19,11 +23,7 @@ class UniformMagneticField: public MagneticField { } void updateSimulationVolume(const Vector3d &origin, double size) { - } - -private: - Vector3d value; }; } // namespace mpc diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index b4251cc34..d07bbaa45 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -55,14 +55,15 @@ std::string DeflectionCK::getDescription() const { } void DeflectionCK::process(Candidate *candidate) const { + double step = std::max(minStep, candidate->getNextStep()); + // rectlinear propagation in case of no charge - if (candidate->current.getChargeNumber() == 0) { - double nextStep = std::max(minStep, candidate->getNextStep()); + if (candidate->current.getCharge() == 0) { Vector3d pos = candidate->current.getPosition(); Vector3d dir = candidate->current.getDirection(); - candidate->current.setPosition(pos + dir * nextStep); - candidate->setCurrentStep(nextStep); - candidate->setNextStep(nextStep * 5); + candidate->current.setPosition(pos + dir * step); + candidate->setCurrentStep(step); + candidate->setNextStep(step * 5); return; } @@ -70,7 +71,7 @@ void DeflectionCK::process(Candidate *candidate) const { candidate->current.getMomentum()); PhasePoint yOut, yErr, yScale; LorentzForce dydt(&candidate->current, field); - double h = std::max(candidate->getNextStep(), minStep) / c_light; + double h = step / c_light; double hTry, r; // phase-point to compare with error for step size control diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 11a12ea79..2b21ed32f 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -20,14 +20,14 @@ TrajectoryOutput::~TrajectoryOutput() { void TrajectoryOutput::process(Candidate *candidate) const { char buffer[1024]; size_t pos = 0; - pos += ::sprintf(buffer + pos, "%.15g, %d, %.15g", + pos += ::sprintf(buffer + pos, "%.4f, %d, %.4f", candidate->getTrajectoryLength() / Mpc, candidate->current.getId(), candidate->current.getEnergy() / EeV); Vector3d position = candidate->current.getPosition() / Mpc; - pos += ::sprintf(buffer + pos, ", %.15g, %.15g, %.15g", position.x, position.y, + pos += ::sprintf(buffer + pos, ", %.4f, %.4f, %.4f", position.x, position.y, position.z); const Vector3d &dir = candidate->current.getDirection(); - pos += ::sprintf(buffer + pos, ", %.15g, %.15g, %.15g\n", dir.x, dir.y, dir.z); + pos += ::sprintf(buffer + pos, ", %.4f, %.4f, %.4f\n", dir.x, dir.y, dir.z); #pragma omp critical { @@ -65,23 +65,23 @@ void ConditionalOutput::process(Candidate *candidate) const { p += ::sprintf(buffer + p, "%d", candidate->current.getId()); const Vector3d &pos = candidate->current.getPosition() / Mpc; - p += ::sprintf(buffer + p, ", %f, %f, %f", pos.x, pos.y, pos.z); + p += ::sprintf(buffer + p, ", %.4f, %.4f, %.4f", pos.x, pos.y, pos.z); const Vector3d &dir = candidate->current.getDirection(); - p += ::sprintf(buffer + p, ", %f, %f, %f", + p += ::sprintf(buffer + p, ", %.4f, %.4f, %.4f", candidate->current.getEnergy() / EeV, dir.getPhi(), dir.getTheta()); - p += ::sprintf(buffer + p, ", %f", + p += ::sprintf(buffer + p, ", %.4f", candidate->getTrajectoryLength() / Mpc); p += ::sprintf(buffer + p, ", %d", candidate->initial.getId()); const Vector3d &ipos = candidate->initial.getPosition() / Mpc; - p += ::sprintf(buffer + p, ", %f, %f, %f", ipos.x, ipos.y, ipos.z); + p += ::sprintf(buffer + p, ", %.4f, %.4f, %.4f", ipos.x, ipos.y, ipos.z); const Vector3d &idir = candidate->initial.getDirection(); - p += ::sprintf(buffer + p, ", %f, %f, %f\n", + p += ::sprintf(buffer + p, ", %.4f, %.4f, %.4f\n", candidate->initial.getEnergy() / EeV, idir.getPhi(), idir.getTheta()); diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index c217583ec..3d92a28c7 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -3,6 +3,7 @@ #include "mpc/magneticField/TurbulentMagneticFieldGrid.h" #include "mpc/magneticField/TurbulentMagneticField.h" #include "mpc/Units.h" +#include "mpc/Common.h" #include "gtest/gtest.h" #include @@ -108,10 +109,10 @@ TEST(testMagneticFieldGrid, DumpLoad) { for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) B1.get(ix, iy, iz) = Vector3f(1, 2, 3); - B1.dump("test/testDump.raw"); + B1.dump(getDataPath("../test/testDump.raw")); MagneticFieldGrid B2(Vector3d(0.), 3, 3); - B2.load("test/testDump.raw"); + B2.load(getDataPath("../test/testDump.raw")); for (int ix = 0; ix < 3; ix++) { for (int iy = 0; iy < 3; iy++) { From 3ca70ff73259c76b4f61a392ed97195f3300e8d0 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 17 Jul 2012 16:18:42 +0200 Subject: [PATCH 0142/1298] react to changed SPH field interface --- include/mpc/ExplicitRungeKutta.h | 3 --- src/magneticField/SPHMagneticField.cpp | 9 ++++++--- src/module/DeflectionCK.cpp | 16 +++++++--------- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/include/mpc/ExplicitRungeKutta.h b/include/mpc/ExplicitRungeKutta.h index ef7e2752d..77f6b019e 100644 --- a/include/mpc/ExplicitRungeKutta.h +++ b/include/mpc/ExplicitRungeKutta.h @@ -2,9 +2,6 @@ #define MPC_EXPLICITRUNGEKUTTA_H_ #include -#include -#include -#include namespace mpc { diff --git a/src/magneticField/SPHMagneticField.cpp b/src/magneticField/SPHMagneticField.cpp index 88e55f7df..c3e9cceab 100644 --- a/src/magneticField/SPHMagneticField.cpp +++ b/src/magneticField/SPHMagneticField.cpp @@ -20,7 +20,8 @@ SPHMagneticField::SPHMagneticField(size_t samples, std::string filename) : Vector3d SPHMagneticField::getField(const Vector3d &position) const { gadget::Vector3f r = gadget::Vector3f(position.x, position.y, position.z); - gadget::Vector3f b = field.getField(r / kpc); + gadget::Vector3f b; + bool isGood = field.getField(r / kpc, b); Vector3d bField = Vector3d(b.x, b.y, b.z) * gauss; return bField; } @@ -28,7 +29,8 @@ Vector3d SPHMagneticField::getField(const Vector3d &position) const { double SPHMagneticField::getRho(const Vector3d& position) const { gadget::Vector3f r = gadget::Vector3f(position.x, position.y, position.z); size_t overlaps = 0; - double rho = field.getRho(r / kpc, overlaps); + float rho; + bool isGood = field.getRho(r / kpc, overlaps, rho); return rho * 1.98892e40 * kilogram * pow(0.7, 2) / pow(kpc, 3); } @@ -53,7 +55,8 @@ SPHMagneticFieldGrid::SPHMagneticFieldGrid(const size_t samples, Vector3d SPHMagneticFieldGrid::getField(const Vector3d &position) const { gadget::Vector3f r = gadget::Vector3f(position.x, position.y, position.z); - gadget::Vector3f b = field.getField(r / kpc); + gadget::Vector3f b; + bool isGood = field.getField(r / kpc, b); Vector3d bField = Vector3d(b.x, b.y, b.z) * gauss; return bField; } diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index d07bbaa45..b0c558d81 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -8,9 +8,7 @@ namespace mpc { /** * @class LorentzForce - * @brief Time-derivative in SI-units of phase-point - * (position, momentum) -> (velocity, force) - * of a highly relativistic charged particle in magnetic field. + * @brief Time-derivative of the phase-point (position, momentum) of a highly relativistic particle in magnetic field. */ class LorentzForce: public ExplicitRungeKutta::F { public: @@ -57,7 +55,7 @@ std::string DeflectionCK::getDescription() const { void DeflectionCK::process(Candidate *candidate) const { double step = std::max(minStep, candidate->getNextStep()); - // rectlinear propagation in case of no charge + // rectlinear propagation for neutral particles if (candidate->current.getCharge() == 0) { Vector3d pos = candidate->current.getPosition(); Vector3d dir = candidate->current.getDirection(); @@ -77,11 +75,13 @@ void DeflectionCK::process(Candidate *candidate) const { // phase-point to compare with error for step size control yScale = (yIn.abs() + dydt(0., yIn).abs() * h) * tolerance; + // try performing a steps until the relative error is less than the desired tolerance + // or the minimum step size has been reached do { hTry = h; erk.step(0, yIn, yOut, yErr, hTry, dydt); - // maximum of ratio yErr(i) / yScale(i) + // determine maximum of relative errors yErr(i) / yScale(i) r = 0; if (yScale.b.x > std::numeric_limits::min()) r = std::max(r, fabs(yErr.b.x / yScale.b.x)); @@ -90,13 +90,11 @@ void DeflectionCK::process(Candidate *candidate) const { if (yScale.b.z > std::numeric_limits::min()) r = std::max(r, fabs(yErr.b.z / yScale.b.z)); - // for efficient integration try to keep r close to one + // change (next) step size to keep the relative error close to the tolerance h *= 0.95 * pow(r, -0.2); - - // limit step change h = std::max(h, 0.1 * hTry); h = std::min(h, 5 * hTry); - } while (r > 1 && h >= minStep); + } while (r > 1 && h > minStep); candidate->current.setPosition(yOut.a); candidate->current.setDirection(yOut.b.getUnitVector()); From fc9a4877c8b4e5a95148768c661e578b889bcacc Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 17 Jul 2012 17:18:23 +0200 Subject: [PATCH 0143/1298] fix modulated field --- .../SPHTurbulentMagneticFieldGrid.h | 4 ++-- src/ModuleList.cpp | 21 +++++++------------ src/magneticField/SPHMagneticField.cpp | 6 ++++++ .../SPHTurbulentMagneticFieldGrid.cpp | 17 ++++++++------- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h b/include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h index ac8b1fb92..4286b9005 100644 --- a/include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h +++ b/include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h @@ -16,8 +16,8 @@ namespace mpc { */ class SPHTurbulentMagneticFieldGrid: public TurbulentMagneticFieldGrid { std::auto_ptr sphField; /**< SPH (density) field */ - double lRho[67]; - double lB[67]; + double tabRho[67]; + double tabB[67]; public: /** Constructor. Reimplementation of TurbulentMagneticField. */ diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index db429367e..6afb931a7 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -1,6 +1,7 @@ #include "mpc/ModuleList.h" #include +#include using namespace std; @@ -47,40 +48,32 @@ void ModuleList::run(Candidate *candidate, bool recursive) { void ModuleList::run(candidate_vector_t &candidates, bool recursive) { size_t count = candidates.size(); - size_t pc = 0; + size_t pc = std::max(count / 100, size_t(1)); #if _OPENMP std::cout << "mpc::ModuleList: Number of Threads: " << omp_get_max_threads() << std::endl; #endif #pragma omp parallel for schedule(dynamic, 1000) for (size_t i = 0; i < count; i++) { - if (showProgress && ((i * 100) / count > pc)) { - pc += ceil(100. / count); - std::cout << pc << "% - " << i << std::endl; - } + if ((showProgress) && (i % pc == 0)) + std::cout << i / pc << "% - " << i << std::endl; run(candidates[i], recursive); } - if (showProgress) - std::cout << "100% - " << count << std::endl; } void ModuleList::run(Source *source, size_t count, bool recursive) { - size_t pc = 0; + size_t pc = std::max(count / 100, size_t(1)); #if _OPENMP std::cout << "mpc::ModuleList: Number of Threads: " << omp_get_max_threads() << std::endl; #endif #pragma omp parallel for schedule(dynamic, 1000) for (size_t i = 0; i < count; i++) { - if (showProgress && ((i * 100) / count > pc)) { - pc += ceil(100. / count); - std::cout << pc << "% - " << i << std::endl; - } + if ((showProgress) && (i % pc == 0)) + std::cout << i / pc << "% - " << i << std::endl; ParticleState state; source->prepare(state); ref_ptr candidate = new Candidate(state); run(candidate, recursive); } - if (showProgress) - std::cout << "100% - " << count << std::endl; } ModuleList::module_list_t &ModuleList::getModules() { diff --git a/src/magneticField/SPHMagneticField.cpp b/src/magneticField/SPHMagneticField.cpp index c3e9cceab..b2c03133b 100644 --- a/src/magneticField/SPHMagneticField.cpp +++ b/src/magneticField/SPHMagneticField.cpp @@ -22,6 +22,8 @@ Vector3d SPHMagneticField::getField(const Vector3d &position) const { gadget::Vector3f r = gadget::Vector3f(position.x, position.y, position.z); gadget::Vector3f b; bool isGood = field.getField(r / kpc, b); + if (!isGood) + std::cout << "mpc::SPHMagneticField invalid position : " << position << std::endl; Vector3d bField = Vector3d(b.x, b.y, b.z) * gauss; return bField; } @@ -31,6 +33,8 @@ double SPHMagneticField::getRho(const Vector3d& position) const { size_t overlaps = 0; float rho; bool isGood = field.getRho(r / kpc, overlaps, rho); + if (!isGood) + std::cout << "mpc::SPHMagneticField invalid position : " << position << std::endl; return rho * 1.98892e40 * kilogram * pow(0.7, 2) / pow(kpc, 3); } @@ -57,6 +61,8 @@ Vector3d SPHMagneticFieldGrid::getField(const Vector3d &position) const { gadget::Vector3f r = gadget::Vector3f(position.x, position.y, position.z); gadget::Vector3f b; bool isGood = field.getField(r / kpc, b); + if (!isGood) + std::cout << "mpc::SPHMagneticField invalid position : " << position << std::endl; Vector3d bField = Vector3d(b.x, b.y, b.z) * gauss; return bField; } diff --git a/src/magneticField/SPHTurbulentMagneticFieldGrid.cpp b/src/magneticField/SPHTurbulentMagneticFieldGrid.cpp index 2ab024b6d..0d6744188 100644 --- a/src/magneticField/SPHTurbulentMagneticFieldGrid.cpp +++ b/src/magneticField/SPHTurbulentMagneticFieldGrid.cpp @@ -15,7 +15,7 @@ void SPHTurbulentMagneticFieldGrid::setModulation(std::string filename) { if (!infile.good()) throw std::runtime_error("mpc: could not open file " + filename); for (int i = 0; i < 67; i++) { - infile >> lRho[i] >> lB[i]; + infile >> tabRho[i] >> tabB[i]; infile.ignore(std::numeric_limits::max(), '\n'); } infile.close(); @@ -23,14 +23,17 @@ void SPHTurbulentMagneticFieldGrid::setModulation(std::string filename) { Vector3d SPHTurbulentMagneticFieldGrid::getField( const Vector3d &position) const { - double rho = log10(sphField->getRho(position) / 1000); // log10(density in [g/cm^3]) + double rho = sphField->getRho(position); // density in [kg/m^3] + if (rho <= std::numeric_limits::min()) + return Vector3d(0.); + double x = log10(rho / 1000); // log10(density in [g/cm^3]) double m; // strength in [G] - if (rho <= -32) - m = 206.404 + 12.9872 * rho + 0.193117 * rho * rho; - else if (rho >= -28) - m = -37.3625 - 2.74343 * rho - 0.0585562 * rho * rho; + if (x <= -32) + m = 206.404 + 12.9872 * x + 0.193117 * x * x; + else if (x >= -28) + m = -37.3625 - 2.74343 * x - 0.0585562 * x * x; else - m = interpolate(rho, lRho, lB); + m = interpolate(x, tabRho, tabB); return MagneticFieldGrid::getField(position) * pow(10, m) / 10000; // B-field in [T] } From e055978f33209f45cf34e48944bec97591dedacb Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 20 Jul 2012 17:09:19 +0200 Subject: [PATCH 0144/1298] add SourceList + tests --- include/mpc/Source.h | 31 +++++++++++++++++++++++++++++-- src/Source.cpp | 39 ++++++++++++++++++++++++++++++++------- test/testSource.cpp | 42 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 102 insertions(+), 10 deletions(-) diff --git a/include/mpc/Source.h b/include/mpc/Source.h index f3b49a726..c80063526 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -19,15 +19,30 @@ class SourceProperty: public Referenced { /** @class Source - @brief Abstract class for cosmic ray sources + @brief General cosmic ray source + + This class is a container for source properties. + The source prepares a particle by passing it to all its source properties, who in turn modify it accordingly. */ class Source: public Referenced { -public: std::vector > properties; +public: void addProperty(SourceProperty *property); void prepare(ParticleState &particle) const; }; +/** + @class SourceList + @brief List of cosmic ray sources of individual total lumosities. + */ +class SourceList: public Source { + std::vector > sources; + std::vector luminosities; +public: + void addSource(Source *source, double luminosity = 1); + void prepare(ParticleState &particle) const; +}; + /** @class SourceParticleType @brief Particle type at the source @@ -39,6 +54,18 @@ class SourceParticleType: public SourceProperty { void prepare(ParticleState &particle) const; }; + +/** + @ class SourceEnergy + @ brief Sets the initial energy to a given value + */ +class SourceEnergy: public SourceProperty { + double E; +public: + SourceEnergy(double energy); + void prepare(ParticleState &particle) const; +}; + /** @class SourcePowerLawSpectrum @brief Particle energy following a power law spectrum diff --git a/src/Source.cpp b/src/Source.cpp index c0a2987a3..db60faf3e 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -6,13 +6,30 @@ namespace mpc { -void Source::addProperty(SourceProperty* property) { +void Source::addProperty(SourceProperty *property) { properties.push_back(property); } -void Source::prepare(ParticleState& state) const { +void Source::prepare(ParticleState &particle) const { for (int i = 0; i < properties.size(); i++) - (*properties[i]).prepare(state); + (*properties[i]).prepare(particle); +} + +void SourceList::addSource(Source *source, double lumi) { + sources.push_back(source); + if (luminosities.size() > 0) + lumi += luminosities.back(); + luminosities.push_back(lumi); +} + +void SourceList::prepare(ParticleState &particle) const { + if (sources.size() == 0) + throw std::runtime_error("SourceList: no sources set"); + double r = Random().rand() * luminosities.back(); + int i = 0; + while ((r > luminosities[i]) and (i < luminosities.size())) + i++; + (sources[i])->prepare(particle); } SourceParticleType::SourceParticleType(int id) : @@ -23,6 +40,14 @@ void SourceParticleType::prepare(ParticleState &particle) const { particle.setId(id); } +SourceEnergy::SourceEnergy(double energy) : + E(energy) { +} + +void SourceEnergy::prepare(ParticleState &particle) const { + particle.setEnergy(E); +} + SourcePowerLawSpectrum::SourcePowerLawSpectrum(double Emin, double Emax, double index) : Emin(Emin), Emax(Emax), index(index) { @@ -96,13 +121,13 @@ SourceSphericalVolume::SourceSphericalVolume(Vector3d center, double radius) : center(center), radius(radius) { } -void SourceSphericalVolume::prepare(ParticleState& particle) const { +void SourceSphericalVolume::prepare(ParticleState &particle) const { double r = pow(Random().rand(), 1. / 3.) * radius; Vector3d pos = Random().randUnitVectorOnSphere() * r; particle.setPosition(pos); } -void SourceIsotropicEmission::prepare(ParticleState& particle) const { +void SourceIsotropicEmission::prepare(ParticleState &particle) const { Vector3d dir = Random().randUnitVectorOnSphere(); particle.setDirection(dir); } @@ -111,7 +136,7 @@ SourceDirection::SourceDirection(Vector3d direction) : direction(direction) { } -void SourceDirection::prepare(ParticleState& particle) const { +void SourceDirection::prepare(ParticleState &particle) const { particle.setDirection(direction); } @@ -119,7 +144,7 @@ SourceEmissionCone::SourceEmissionCone(Vector3d direction, double aperture) : direction(direction), aperture(aperture) { } -void SourceEmissionCone::prepare(ParticleState& particle) const { +void SourceEmissionCone::prepare(ParticleState &particle) const { Vector3d dir = Random().randConeVector(direction, aperture); particle.setDirection(dir); } diff --git a/test/testSource.cpp b/test/testSource.cpp index 0a3a87d69..e12de2da7 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -56,7 +56,7 @@ TEST(testSourceComposition, throwNoIsotope) { EXPECT_THROW(source.prepare(ps), std::runtime_error); } -TEST(testSource, simpleTest) { +TEST(testSource, allPropertiesUsed) { Source source; source.addProperty(new SourcePosition(Vector3d(10, 0, 0) * Mpc)); source.addProperty(new SourceIsotropicEmission()); @@ -71,6 +71,46 @@ TEST(testSource, simpleTest) { EXPECT_EQ(Vector3d(10, 0, 0) * Mpc, ps.getPosition()); } +TEST(testSourceList, simpleTest) { + // test if source list works with one source + SourceList sourceList; + ref_ptr source = new Source; + source->addProperty(new SourcePosition(Vector3d(10, 0, 0))); + sourceList.addSource(source); + ParticleState p; + sourceList.prepare(p); + EXPECT_EQ(Vector3d(10, 0, 0), p.getPosition()); +} + +TEST(testSourceList, noSource) { + // test if an error is thrown when source list empty + SourceList sourceList; + ParticleState p; + EXPECT_THROW(sourceList.prepare(p), std::runtime_error); +} + +TEST(testSourceList, luminosity) { + // test if the sources are dialed according to their luminosities + SourceList sourceList; + ParticleState p; + + ref_ptr source1 = new Source; + source1->addProperty(new SourceEnergy(100)); + sourceList.addSource(source1, 80); + + ref_ptr source2 = new Source; + source2->addProperty(new SourceEnergy(0)); + sourceList.addSource(source2, 20); + + double meanE = 0; + for (int i = 0; i < 1000; i++) { + sourceList.prepare(p); + meanE += p.getEnergy(); + } + meanE /= 1000; + EXPECT_NEAR(80, meanE, 1); // this test can stochastically fail +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); From 6dde4978726a7ba0bec424c4cec28533e04e88e0 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 20 Jul 2012 17:54:29 +0200 Subject: [PATCH 0145/1298] implement loading MagneticFieldGrid from ASCII files --- include/mpc/magneticField/MagneticFieldGrid.h | 22 +++++- src/magneticField/MagneticFieldGrid.cpp | 68 +++++++++++++++---- test/testMagneticField.cpp | 25 +++++++ 3 files changed, 98 insertions(+), 17 deletions(-) diff --git a/include/mpc/magneticField/MagneticFieldGrid.h b/include/mpc/magneticField/MagneticFieldGrid.h index 128f41a14..6feafb16e 100644 --- a/include/mpc/magneticField/MagneticFieldGrid.h +++ b/include/mpc/magneticField/MagneticFieldGrid.h @@ -35,17 +35,35 @@ class MagneticFieldGrid: public MagneticField { void normalize(double norm); /** - * Load the field from a binary file. + * Load the field grid from a binary file. * The field is stored single precision numbers with the field components in xyz order and the grid z-index changing the fastest. */ void load(std::string filename); /** - * Dump the field to a binary file. + * Dump the field grid to a binary file. * The field is stored single precision numbers with the field components in xyz order and the grid z-index changing the fastest. */ void dump(std::string filename) const; + /** + * Load the field grid from a plain text file. + * The field is stored as one grid point per line from (0,0,0) to (nx, ny, nz) with the grid z-index changing the fastest. + * Within one line the magnetic field values are stored in xyz order separated by a blank or tab. + * Header lines must start with a #. + * @param unit conversion of the values in the file to SI + */ + void loadTxt(std::string filename, double unit); + + /** + * Dump the field grid to a plain text file. + * The field is stored as one grid point per line from (0,0,0) to (nx, ny, nz) with the grid z-index changing the fastest. + * Within one line the magnetic field values are stored in xyz order separated by a blank or tab. + * Header lines must start with a #. + * @param unit conversion of SI to the values in the file + */ + void dumpTxt(std::string filename, double unit); + /** * Modulate the magnetic field with a density field from a binary file. * The field should be (re)normalized afterwards. diff --git a/src/magneticField/MagneticFieldGrid.cpp b/src/magneticField/MagneticFieldGrid.cpp index 50603371b..5befc6a41 100644 --- a/src/magneticField/MagneticFieldGrid.cpp +++ b/src/magneticField/MagneticFieldGrid.cpp @@ -6,7 +6,7 @@ namespace mpc { void periodicClamp(double x, int n, int &lo, int &hi) { - lo = ( ( int(floor(x)) % n ) + n ) % n; + lo = ((int(floor(x)) % n) + n) % n; hi = (lo + 1) % n; } @@ -34,37 +34,75 @@ void MagneticFieldGrid::normalize(double norm) { } void MagneticFieldGrid::load(std::string filename) { - std::ifstream infile(filename.c_str(), std::ios::binary); - if (!infile) - throw std::runtime_error("mpc::MagneticFieldGrid: File not found"); + std::ifstream fin(filename.c_str(), std::ios::binary); + if (!fin) + throw std::runtime_error("MagneticFieldGrid: File not found"); for (int ix = 0; ix < samples; ix++) { for (int iy = 0; iy < samples; iy++) { for (int iz = 0; iz < samples; iz++) { Vector3f &b = get(ix, iy, iz); - infile.read((char*) &(b.x), sizeof(float)); - infile.read((char*) &(b.y), sizeof(float)); - infile.read((char*) &(b.z), sizeof(float)); + fin.read((char*) &(b.x), sizeof(float)); + fin.read((char*) &(b.y), sizeof(float)); + fin.read((char*) &(b.z), sizeof(float)); } } } - infile.close(); + fin.close(); } void MagneticFieldGrid::dump(std::string filename) const { - std::ofstream outfile(filename.c_str(), std::ios::binary); - if (!outfile) - throw std::runtime_error("mpc::MagneticFieldGrid: Could not open file"); + std::ofstream fout(filename.c_str(), std::ios::binary); + if (!fout) + throw std::runtime_error("MagneticFieldGrid: Could not open file"); for (int ix = 0; ix < samples; ix++) { for (int iy = 0; iy < samples; iy++) { for (int iz = 0; iz < samples; iz++) { Vector3f b = get(ix, iy, iz); - outfile.write((char*) &(b.x), sizeof(float)); - outfile.write((char*) &(b.y), sizeof(float)); - outfile.write((char*) &(b.z), sizeof(float)); + fout.write((char*) &(b.x), sizeof(float)); + fout.write((char*) &(b.y), sizeof(float)); + fout.write((char*) &(b.z), sizeof(float)); + } + } + } + fout.close(); +} + +void MagneticFieldGrid::loadTxt(std::string filename, double conversion) { + std::ifstream fin(filename.c_str()); + if (!fin) + throw std::runtime_error("MagneticFieldGrid: file not found"); + + // skip header lines + while (fin.peek() == '#') + fin.ignore(std::numeric_limits::max(), '\n'); + + for (int ix = 0; ix < samples; ix++) { + for (int iy = 0; iy < samples; iy++) { + for (int iz = 0; iz < samples; iz++) { + Vector3f &b = get(ix, iy, iz); + fin >> b.x >> b.y >> b.z; + b *= conversion; + if (fin.eof()) + throw std::runtime_error("MagneticFieldGrid: file too short"); + } + } + } + fin.close(); +} + +void MagneticFieldGrid::dumpTxt(std::string filename, double conversion) { + std::ofstream fout(filename.c_str()); + if (!fout) + throw std::runtime_error("MagneticFieldGrid: could not open file"); + for (int ix = 0; ix < samples; ix++) { + for (int iy = 0; iy < samples; iy++) { + for (int iz = 0; iz < samples; iz++) { + Vector3f b = get(ix, iy, iz) * conversion; + fout << b << "\n"; } } } - outfile.close(); + fout.close(); } void MagneticFieldGrid::modulateWithDensityField(std::string filename, diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index 3d92a28c7..52389dee3 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -127,6 +127,31 @@ TEST(testMagneticFieldGrid, DumpLoad) { } } +TEST(testMagneticFieldGrid, DumpLoadTxt) { + // Dump and load a field grid + MagneticFieldGrid B1(Vector3d(0.), 3, 3); + for (int ix = 0; ix < 3; ix++) + for (int iy = 0; iy < 3; iy++) + for (int iz = 0; iz < 3; iz++) + B1.get(ix, iy, iz) = Vector3f(ix, iy, iz) * nG; + B1.dumpTxt(getDataPath("../test/testDump.txt"), 1e4); + + MagneticFieldGrid B2(Vector3d(0.), 3, 3); + B2.loadTxt(getDataPath("../test/testDump.txt"), 1e-4); + + for (int ix = 0; ix < 3; ix++) { + for (int iy = 0; iy < 3; iy++) { + for (int iz = 0; iz < 3; iz++) { + Vector3f b1 = B1.get(ix, iy, iz); + Vector3f b2 = B2.get(ix, iy, iz); + EXPECT_FLOAT_EQ(b1.x, b2.x); + EXPECT_FLOAT_EQ(b1.y, b2.y); + EXPECT_FLOAT_EQ(b1.z, b2.z); + } + } + } +} + TEST(testMagneticFieldGrid, Speed) { // Dump and load a field grid MagneticFieldGrid B(Vector3d(0.), 3, 3); From a8b0979d5b19fb4206057ada22628322b919afb3 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 20 Jul 2012 17:55:00 +0200 Subject: [PATCH 0146/1298] add conversion to CRPropa2 nucleus scheme --- include/mpc/Nucleus.h | 4 ++++ src/Nucleus.cpp | 28 ++++++++++++++++++++-------- test/testCore.cpp | 5 +++++ 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/include/mpc/Nucleus.h b/include/mpc/Nucleus.h index 16910d16d..8768f4351 100644 --- a/include/mpc/Nucleus.h +++ b/include/mpc/Nucleus.h @@ -16,6 +16,10 @@ int getNucleusId(int a, int z); int getChargeNumberFromNucleusId(int id); int getMassNumberFromNucleusId(int id); +/* CRPropa2.0 code scheme */ +int convertFromCRPropaId(int id); +int convertToCRPropaId(int id); + /** Return the nucleus mass by lookup from a table. * The masses are the atomic masses from the NIST database (http://www.nist.gov/pml/data/comp.cfm) minus electron masses, neglecting electron binding energies. * Unmeasured atomic masses are taken to be A * amu minus electron masses. diff --git a/src/Nucleus.cpp b/src/Nucleus.cpp index 3f2750c6e..522164676 100644 --- a/src/Nucleus.cpp +++ b/src/Nucleus.cpp @@ -27,6 +27,26 @@ int getNucleusId(int a, int z) { return 1000000000 + z * 10000 + a * 10; } +int getChargeNumberFromNucleusId(int id) { + return HepPID::Z(id); +} + +int getMassNumberFromNucleusId(int id) { + return HepPID::A(id); +} + +int convertFromCRPropaId(int crp_id) { + int Z = crp_id / 1000; + int A = crp_id % 1000; + return getNucleusId(A, Z); +} + +int convertToCRPropaId(int id) { + int Z = getChargeNumberFromNucleusId(id); + int A = getMassNumberFromNucleusId(id); + return Z * 1000 + A; +} + struct NuclearMassTable { std::vector table; @@ -62,12 +82,4 @@ double getNucleusMass(int id) { return mass; } -int getChargeNumberFromNucleusId(int id) { - return HepPID::Z(id); -} - -int getMassNumberFromNucleusId(int id) { - return HepPID::A(id); -} - } // namespace mpc diff --git a/test/testCore.cpp b/test/testCore.cpp index da19c310f..ca5aea13c 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -222,6 +222,11 @@ TEST(Vector3, rotation) { EXPECT_NEAR(v.z, 7, 1e-9); } +TEST(NucleusId, crpropaScheme) { + EXPECT_EQ(getNucleusId(56, 26), convertFromCRPropaId(26056)); + EXPECT_EQ(26056, convertToCRPropaId(getNucleusId(56, 26))); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); From 54be6e6cf8128b950cdf4ef524e19104b08e373b Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sun, 22 Jul 2012 12:03:09 +0200 Subject: [PATCH 0147/1298] remove IO --- CMakeLists.txt | 1 - include/mpc/IO.h | 28 --------------------- src/IO.cpp | 65 ------------------------------------------------ 3 files changed, 94 deletions(-) delete mode 100644 include/mpc/IO.h delete mode 100644 src/IO.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 11374a1b5..88f8f889b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,7 +86,6 @@ add_library(mpc SHARED src/SpatialPartitioning.cpp src/Module.cpp src/Candidate.cpp - src/IO.cpp src/ParticleState.cpp src/Source.cpp src/Common.cpp diff --git a/include/mpc/IO.h b/include/mpc/IO.h deleted file mode 100644 index 5f43af4e2..000000000 --- a/include/mpc/IO.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef MPC_IO_H_ -#define MPC_IO_H_ - -#include "mpc/Candidate.h" - -#include - -namespace mpc { - -void write(kiss::Output &out, const mpc::Vector3d &vec3); - -void write(kiss::Output &out, const mpc::ParticleState &state); - -void write(kiss::Output &out, const mpc::InteractionState &s); - -void write(kiss::Output &out, const mpc::Candidate &candidate); - -bool read(kiss::Input &in, mpc::Vector3d &vec3); - -bool read(kiss::Input &in, mpc::ParticleState &state); - -bool read(kiss::Input &in, mpc::InteractionState &s); - -bool read(kiss::Input &in, mpc::Candidate &candidate); - -} // namespace mpc - -#endif /* MPC_IO_H_ */ diff --git a/src/IO.cpp b/src/IO.cpp deleted file mode 100644 index 5975e2220..000000000 --- a/src/IO.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "mpc/IO.h" - -namespace mpc { - -void write(kiss::Output &out, const mpc::Vector3d &vec3) { - write(out, vec3.x); - write(out, vec3.y); - write(out, vec3.z); -} - -void write(kiss::Output &out, const mpc::ParticleState &state) { - write(out, state.getId()); - write(out, state.getEnergy()); - write(out, state.getPosition()); - write(out, state.getDirection()); -} - -void write(kiss::Output &out, const mpc::InteractionState &s) { - write(out, s.distance); - write(out, s.channel); -} - -void write(kiss::Output &out, const mpc::Candidate &candidate) { - write(out, candidate.current); - write(out, candidate.initial); - write(out, candidate.getRedshift()); - write(out, candidate.getTrajectoryLength()); - write(out, candidate.getCurrentStep()); - write(out, candidate.getNextStep()); -} - -bool read(kiss::Input &in, mpc::Vector3d &vec3) { - kiss::read(in, vec3.x); - kiss::read(in, vec3.y); - kiss::read(in, vec3.z); - return (in); -} - -bool read(kiss::Input &in, mpc::ParticleState &state) { - state.setId(kiss::read(in)); - state.setEnergy(kiss::read(in)); - state.setPosition(kiss::read(in)); - state.setDirection(kiss::read(in)); - return (in); -} - -bool read(kiss::Input &in, mpc::InteractionState &s) { - kiss::read(in, s.distance); - kiss::read(in, s.channel); - return (in); -} - -bool read(kiss::Input &in, mpc::Candidate &candidate) { - read(in, candidate.current); - read(in, candidate.initial); - candidate.setRedshift(kiss::read(in)); - candidate.setTrajectoryLength(kiss::read(in)); - candidate.setCurrentStep(kiss::read(in)); - candidate.setNextStep(kiss::read(in)); -// candidate.setStatus((mpc::Candidate::Status) kiss::read(in)); -// read(in, candidate.getInteractionStates()); - return (in); -} - -} // namespace mpc From 3a385029bf9c51c8b97853701d2714a8163e91ef Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sun, 22 Jul 2012 12:18:49 +0200 Subject: [PATCH 0148/1298] remove spatial partioning --- CMakeLists.txt | 1 - include/mpc/Module.h | 5 - include/mpc/SpatialPartitioning.h | 62 ----- include/mpc/magneticField/MagneticField.h | 1 - include/mpc/magneticField/MagneticFieldGrid.h | 5 - include/mpc/magneticField/SPHMagneticField.h | 2 - .../magneticField/TurbulentMagneticField.h | 2 - .../mpc/magneticField/UniformMagneticField.h | 3 - include/mpc/module/DeflectionCK.h | 3 +- python/mpc.i | 6 +- src/SpatialPartitioning.cpp | 256 ------------------ src/magneticField/MagneticFieldGrid.cpp | 7 - src/magneticField/SPHMagneticField.cpp | 33 --- src/magneticField/TurbulentMagneticField.cpp | 5 - src/module/DeflectionCK.cpp | 4 - 15 files changed, 2 insertions(+), 393 deletions(-) delete mode 100644 include/mpc/SpatialPartitioning.h delete mode 100644 src/SpatialPartitioning.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 88f8f889b..e9397f08b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,7 +83,6 @@ add_library(mpc SHARED src/Random.cpp src/Clock.cpp src/ModuleList.cpp - src/SpatialPartitioning.cpp src/Module.cpp src/Candidate.cpp src/ParticleState.cpp diff --git a/include/mpc/Module.h b/include/mpc/Module.h index 1c8aa9852..ae0d70f27 100644 --- a/include/mpc/Module.h +++ b/include/mpc/Module.h @@ -31,11 +31,6 @@ class Module: public Referenced { } }; -class SimulationVolumeDependentModule: public Module { -public: - virtual void updateSimulationVolume(const Vector3d &origin, double size) = 0; -}; - } // namespace mpc #endif /* MPC_MODULE_H_ */ diff --git a/include/mpc/SpatialPartitioning.h b/include/mpc/SpatialPartitioning.h deleted file mode 100644 index 672815a1e..000000000 --- a/include/mpc/SpatialPartitioning.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef MPC_SPATIAL_PARTITIONING_H -#define MPC_SPATIAL_PARTITIONING_H - -#include "mpc/ModuleList.h" -#include "mpc/Candidate.h" - -#include -#include - -namespace mpc { - -struct Count { - size_t count; - Count(); -// operator size_t(); - void operator +=(size_t v); -}; - -struct Index { - int x, y, z; - Index(); - Index(Vector3d v); - bool operator<(const Index &rhs) const; -}; - -class SpatialPartitioning: public Referenced { - -public: - - typedef std::vector > candidate_vector_t; - - SpatialPartitioning(ModuleList *moduleList); - - void run(candidate_vector_t &candidates, bool recursive, - bool deleteInactive); - void run(Source *source, size_t count, bool recursive); - - void setPartitionOrigin(const Vector3d &origin); - void setPartitionSize(double size); - void setCurrentPartition(const Vector3d &offset); - void setPartitionMargin(double inner, double outer); - - void setVerbose(bool verbose); -private: - void run(Candidate *candidate, bool recursive, - Loki::AssocVector &partitions, bool deleteInactive); - Vector3d partitionOrigin, currentPartition; - double partitionSize, partitionMarginInner, partitionMarginOuter; - - void updateMargins(); - Vector3d currentPartitionInner, currentPartitionOuter; - double partitionSizeInner, partitionSizeOuter; - - bool verbose; - ref_ptr moduleList; -}; - -} // namespace mpc - -std::ostream &operator<<(std::ostream &out, const mpc::Index &idx); - -#endif // MPC_SPATIAL_PARTITIONING_H diff --git a/include/mpc/magneticField/MagneticField.h b/include/mpc/magneticField/MagneticField.h index 74becdcb1..8cb65c3ea 100644 --- a/include/mpc/magneticField/MagneticField.h +++ b/include/mpc/magneticField/MagneticField.h @@ -15,7 +15,6 @@ class MagneticField: public Referenced { virtual ~MagneticField() { } virtual Vector3d getField(const Vector3d &position) const = 0; - virtual void updateSimulationVolume(const Vector3d &origin, double size) = 0; }; } // namespace mpc diff --git a/include/mpc/magneticField/MagneticFieldGrid.h b/include/mpc/magneticField/MagneticFieldGrid.h index 6feafb16e..8414c5790 100644 --- a/include/mpc/magneticField/MagneticFieldGrid.h +++ b/include/mpc/magneticField/MagneticFieldGrid.h @@ -95,16 +95,11 @@ class MagneticFieldGrid: public MagneticField { double getGridSpacing() const; double getGridSize() const; - /** Update the fields origin and size. */ - virtual void updateSimulationVolume(const Vector3d &origin, double size); - - protected: std::vector grid; /**< Grid of magnetic field vectors */ Vector3d origin; /**< Origin of the field */ double size; /**< Extension of the field */ size_t samples; /**< Number of grid points per edge */ - double spacing; /**< Distance between two grid points (= size / samples) */ }; diff --git a/include/mpc/magneticField/SPHMagneticField.h b/include/mpc/magneticField/SPHMagneticField.h index 23dd0083c..cba165cb2 100644 --- a/include/mpc/magneticField/SPHMagneticField.h +++ b/include/mpc/magneticField/SPHMagneticField.h @@ -32,7 +32,6 @@ class SPHMagneticField: public MagneticField { Vector3d getField(const Vector3d &position) const; double getRho(const Vector3d &position) const; /*< Return the density in [kg / m^3] */ - void updateSimulationVolume(const Vector3d &origin, double size); }; /** @@ -50,7 +49,6 @@ class SPHMagneticFieldGrid: public MagneticField { std::string filename); SPHMagneticFieldGrid(size_t gridSize, std::string filename); Vector3d getField(const Vector3d &position) const; - void updateSimulationVolume(const Vector3d &origin, double size); void setCachePrefix(std::string prefix); void setCacheEnabled(bool enabled); }; diff --git a/include/mpc/magneticField/TurbulentMagneticField.h b/include/mpc/magneticField/TurbulentMagneticField.h index dba0e2bca..eb8e5b99e 100644 --- a/include/mpc/magneticField/TurbulentMagneticField.h +++ b/include/mpc/magneticField/TurbulentMagneticField.h @@ -56,8 +56,6 @@ class TurbulentMagneticField: public MagneticField { /** Return the analytical calculation of the correlation length. */ double getCorrelationLength() const; - void updateSimulationVolume(const Vector3d &origin, double size); - private: struct Mode { double amplitude; diff --git a/include/mpc/magneticField/UniformMagneticField.h b/include/mpc/magneticField/UniformMagneticField.h index d428e7c8c..7e6318019 100644 --- a/include/mpc/magneticField/UniformMagneticField.h +++ b/include/mpc/magneticField/UniformMagneticField.h @@ -21,9 +21,6 @@ class UniformMagneticField: public MagneticField { Vector3d getField(const Vector3d &position) const { return value; } - - void updateSimulationVolume(const Vector3d &origin, double size) { - } }; } // namespace mpc diff --git a/include/mpc/module/DeflectionCK.h b/include/mpc/module/DeflectionCK.h index c9ae81ad8..41637d9d6 100644 --- a/include/mpc/module/DeflectionCK.h +++ b/include/mpc/module/DeflectionCK.h @@ -16,7 +16,7 @@ namespace mpc { It uses the Runge-Kutta integration method with Cash-Karp coefficients.\n The step size control tries to keep the relative error close to, but smaller than the designated tolerance. */ -class DeflectionCK: public SimulationVolumeDependentModule { +class DeflectionCK: public Module { public: MagneticField *field; ExplicitRungeKutta erk; @@ -26,7 +26,6 @@ class DeflectionCK: public SimulationVolumeDependentModule { DeflectionCK(MagneticField *field, double tolerance = 1e-4, double minimumStep = 0.1 * kpc); std::string getDescription() const; void process(Candidate *candidate) const; - void updateSimulationVolume(const Vector3d &origin, double size); }; } // namespace mpc diff --git a/python/mpc.i b/python/mpc.i index ed5c6360d..07332dc69 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -40,7 +40,6 @@ #include "mpc/Nucleus.h" #include "mpc/Module.h" #include "mpc/ModuleList.h" -#include "mpc/SpatialPartitioning.h" #include "mpc/PhasePoint.h" #include "mpc/ExplicitRungeKutta.h" #include "mpc/Random.h" @@ -72,7 +71,6 @@ %ignore operator mpc::Module*; %ignore operator mpc::ModuleList*; %ignore operator mpc::MagneticField*; -%ignore operator mpc::SpatialPartitioning*; %feature("ref") mpc::Referenced "$this->addReference();" %feature("unref") mpc::Referenced "$this->removeReference();" @@ -126,6 +124,4 @@ %include "mpc/module/Redshift.h" %include "mpc/module/Tools.h" %template(ModuleListRefPtr) mpc::ref_ptr; -%include "mpc/ModuleList.h" -%template(SpatialPartitioningRefPtr) mpc::ref_ptr; -%include "mpc/SpatialPartitioning.h" +%include "mpc/ModuleList.h" \ No newline at end of file diff --git a/src/SpatialPartitioning.cpp b/src/SpatialPartitioning.cpp deleted file mode 100644 index a5c3eed5e..000000000 --- a/src/SpatialPartitioning.cpp +++ /dev/null @@ -1,256 +0,0 @@ -#include "mpc/SpatialPartitioning.h" - -namespace mpc { - -Count::Count() : - count(0) { - -} - -//operator Count::size_t () { -// return count; -//} - -void Count::operator +=(size_t v) { - count += v; -} - -Index::Index() : - x(0), y(0), z(0) { - -} -Index::Index(Vector3d v) : - x(floor(v.x)), y(floor(v.y)), z(floor(v.z)) { - -} - -bool Index::operator<(const Index &rhs) const { - if (x < rhs.x) - return true; - else if (x > rhs.x) - return false; - - if (y < rhs.y) - return true; - else if (y > rhs.y) - return false; - - if (z < rhs.z) - return true; - else - return false; - -} - -SpatialPartitioning::SpatialPartitioning(ModuleList *moduleList) : - partitionOrigin(0, 0, 0), partitionSize(10 * Mpc), partitionMarginInner( - 0.5 * Mpc), partitionMarginOuter(1 * Mpc), verbose(false), moduleList( - moduleList) { - updateMargins(); - -} - -bool findActivePosition(Candidate *candidate, bool recursive, - Vector3d &position) { - if (candidate->isActive()) { - position = candidate->current.getPosition(); - return true; - } - - if (recursive) { - for (size_t i = 0; i < candidate->secondaries.size(); i++) { - if (findActivePosition(candidate->secondaries[i], recursive, - position)) - return true; - } - } - - return false; -} - -bool toBeRemoved(ref_ptr &candidate) { - bool inactive = (candidate->isActive() == false); - bool nochild = (candidate->secondaries.size() == 0); - return (inactive && nochild); -} - -void SpatialPartitioning::run(candidate_vector_t &candidates, bool recursive, - bool deleteInactive) { - Loki::AssocVector partitions; - - for (size_t i = 0; i < candidates.size(); i++) { - if (candidates[i]->isActive()) { - Vector3d pos = candidates[i]->current.getPosition() - - partitionOrigin; - Index idx(pos / partitionSize); - partitions[idx] += 1; - } - } - - while (partitions.size() > 0) { - - Loki::AssocVector::iterator iPartition = - partitions.begin(); - Index nextPartition = iPartition->first; - size_t nextCount = iPartition->second.count; - for (iPartition = partitions.begin(); iPartition != partitions.end(); - iPartition++) { - if (iPartition->second.count > nextCount) { - nextPartition = iPartition->first; - nextCount = iPartition->second.count; - } - } - - Vector3d o(nextPartition.x, nextPartition.y, nextPartition.z); - setCurrentPartition(o * partitionSize); - - // do the loop - partitions.clear(); - size_t cent = std::max(1ul, candidates.size() / 100), pc = 0; - -#pragma omp parallel shared(partitions, pc) - { - Loki::AssocVector _partitions; -#pragma omp for schedule(dynamic, 1000) - for (size_t i = 0; i < candidates.size(); i++) { - if (verbose && (i % cent == 0)) { - std::cout << pc << "% - " << i << std::endl; - pc++; - } - run(candidates[i], recursive, _partitions, deleteInactive); - } - - Loki::AssocVector::iterator i; -#pragma omp critical - for (i = _partitions.begin(); i != _partitions.end(); i++) { - partitions[i->first] += i->second.count; - } - } - - if (deleteInactive) { - candidates.erase( - remove_if(candidates.begin(), candidates.end(), - toBeRemoved), candidates.end()); - } - } -} - -void SpatialPartitioning::run(Candidate *candidate, bool recursive, - Loki::AssocVector &partitions, bool deleteInactive) { - size_t active = 0; - - while (candidate->isActive()) { - Vector3d relPos = candidate->current.getPosition() - - currentPartitionInner; - double lo = std::min(relPos.x, std::min(relPos.y, relPos.z)); - double hi = std::max(relPos.x, std::max(relPos.y, relPos.z)); - if ((lo <= 0.) || (hi >= partitionSizeInner)) { - break; - } - candidate->limitNextStep(lo); - candidate->limitNextStep(partitionSizeInner - hi); - - moduleList->process(candidate); - } - - if (candidate->isActive()) { - Vector3d pos = candidate->current.getPosition() - partitionOrigin; - Index idx(pos / partitionSize); - partitions[idx] += 1; - } - -// propagate secondaries - if (recursive) { - for (size_t i = 0; i < candidate->secondaries.size(); i++) { - run(candidate->secondaries[i], recursive, partitions, - deleteInactive); - } - if (deleteInactive) { - candidate->secondaries.erase( - remove_if(candidate->secondaries.begin(), - candidate->secondaries.end(), toBeRemoved), - candidate->secondaries.end()); - } - } -} - -void SpatialPartitioning::run(Source *source, size_t count, bool recursive) { - candidate_vector_t candidates; - candidates.reserve(count); - for (size_t i = 0; i < count; i++) { - ParticleState state; - source->prepare(state); - ref_ptr candidate = new Candidate(state); - candidates.push_back(candidate); - } - - run(candidates, recursive, true); -} - -void SpatialPartitioning::setPartitionOrigin(const Vector3d &origin) { - partitionOrigin = origin; -} - -void SpatialPartitioning::setPartitionSize(double size) { - partitionSize = size; - updateMargins(); - -} - -void SpatialPartitioning::setPartitionMargin(double inner, double outer) { - partitionMarginInner = inner; - partitionMarginOuter = outer; - updateMargins(); -} - -struct _UpdateSimulationVolume { - Vector3d currentPartition; - double partitionSize; - _UpdateSimulationVolume(Vector3d currentPartition, double partitionSize) : - currentPartition(currentPartition), partitionSize(partitionSize) { - - } - - void operator()(ref_ptr &module) { - SimulationVolumeDependentModule *svm = - dynamic_cast(module.get()); - if (svm) - svm->updateSimulationVolume(currentPartition, partitionSize); - } -}; - -void SpatialPartitioning::setCurrentPartition(const Vector3d &offset) { - currentPartition = offset; - updateMargins(); - if (verbose) { - std::cout << "mpc::SpatialPartitioningExecutor::setCurrentPartition -> " - << offset / Mpc << std::endl; - } - - std::for_each(moduleList->getModules().begin(), - moduleList->getModules().end(), - _UpdateSimulationVolume(currentPartitionOuter, partitionSizeOuter)); -} - -void SpatialPartitioning::updateMargins() { - currentPartitionInner = currentPartition - - Vector3d(partitionMarginInner, partitionMarginInner, - partitionMarginInner); - partitionSizeInner = partitionSize + 2 * partitionMarginInner; - - currentPartitionOuter = currentPartition - - Vector3d(partitionMarginOuter, partitionMarginOuter, - partitionMarginOuter); - partitionSizeOuter = partitionSize + 2 * partitionMarginOuter; -} - -void SpatialPartitioning::setVerbose(bool verbose) { - this->verbose = verbose; -} - -} // namespace mpc - -std::ostream &operator<<(std::ostream &out, const mpc::Index &idx) { - out << idx.x << ", " << idx.y << ", " << idx.z; - return out; -} diff --git a/src/magneticField/MagneticFieldGrid.cpp b/src/magneticField/MagneticFieldGrid.cpp index 5befc6a41..be42e0d45 100644 --- a/src/magneticField/MagneticFieldGrid.cpp +++ b/src/magneticField/MagneticFieldGrid.cpp @@ -19,13 +19,6 @@ MagneticFieldGrid::MagneticFieldGrid(Vector3d origin, double size, grid.resize(samples * samples * samples); } -void MagneticFieldGrid::updateSimulationVolume(const Vector3d &origin, - double size) { - this->origin = origin; - this->size = size; - this->spacing = size / samples; -} - void MagneticFieldGrid::normalize(double norm) { for (int ix = 0; ix < samples; ix++) for (int iy = 0; iy < samples; iy++) diff --git a/src/magneticField/SPHMagneticField.cpp b/src/magneticField/SPHMagneticField.cpp index b2c03133b..9cbc196d3 100644 --- a/src/magneticField/SPHMagneticField.cpp +++ b/src/magneticField/SPHMagneticField.cpp @@ -38,11 +38,6 @@ double SPHMagneticField::getRho(const Vector3d& position) const { return rho * 1.98892e40 * kilogram * pow(0.7, 2) / pow(kpc, 3); } -void SPHMagneticField::updateSimulationVolume(const Vector3d &origin, double size) { - gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; - field.init(v, size / kpc, database); -} - SPHMagneticFieldGrid::SPHMagneticFieldGrid(Vector3d origin, double size, size_t samples, std::string filename) : samples(samples), field(samples), cacheEnabled(false) { @@ -67,34 +62,6 @@ Vector3d SPHMagneticFieldGrid::getField(const Vector3d &position) const { return bField; } -void SPHMagneticFieldGrid::updateSimulationVolume(const Vector3d &origin, - double size) { - gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; - float s = size / kpc; - if (cacheEnabled) { - std::stringstream path; - path << cachePrefix << samples << "_" << s << "_" << v.x << "_" << v.y - << "_" << v.z << ".cache"; - std::string filename = path.str(); - std::ifstream infile(filename.c_str()); - if (infile) { - std::cout << "load cache file " << filename << std::endl; - field.init(v, s); - field.restore(filename); - } else { - field.init(v, s, database); - path << "." << time(NULL) << clock(); - std::string filename_tmp = path.str(); - field.dump(filename_tmp); - int ren = rename(filename_tmp.c_str(), filename.c_str()); - if (ren != 0) - remove(filename_tmp.c_str()); - } - } else { - field.init(v, s, database); - } -} - void SPHMagneticFieldGrid::setCachePrefix(std::string prefix) { cachePrefix = prefix; } diff --git a/src/magneticField/TurbulentMagneticField.cpp b/src/magneticField/TurbulentMagneticField.cpp index 4a61e493b..a1153bd67 100644 --- a/src/magneticField/TurbulentMagneticField.cpp +++ b/src/magneticField/TurbulentMagneticField.cpp @@ -105,9 +105,4 @@ double TurbulentMagneticField::getCorrelationLength() const { return lMax / 2 * (a - 1) / a * (1 - pow(r, a)) / (1 - pow(r, a - 1)); } -void TurbulentMagneticField::updateSimulationVolume(const Vector3d &origin, - double size) { - return; -} - } // namespace mpc diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index b0c558d81..86138dbed 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -102,8 +102,4 @@ void DeflectionCK::process(Candidate *candidate) const { candidate->setNextStep(h * c_light); } -void DeflectionCK::updateSimulationVolume(const Vector3d &origin, double size) { - field->updateSimulationVolume(origin, size); -} - } /* namespace mpc */ From 743d6a7201b7b19deb8bda1699df8c57311779bc Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 23 Jul 2012 14:29:20 +0200 Subject: [PATCH 0149/1298] add several source properties --- include/mpc/Source.h | 28 ++++++++++++++++++++++++++-- src/Source.cpp | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/include/mpc/Source.h b/include/mpc/Source.h index c80063526..de7209377 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -56,8 +56,8 @@ class SourceParticleType: public SourceProperty { /** - @ class SourceEnergy - @ brief Sets the initial energy to a given value + @class SourceEnergy + @brief Sets the initial energy to a given value */ class SourceEnergy: public SourceProperty { double E; @@ -79,6 +79,18 @@ class SourcePowerLawSpectrum: public SourceProperty { void prepare(ParticleState &particle) const; }; +/** + @class SourceNuclei + @brief Nuclei with given total abundances + */ +class SourceNuclei: public SourceProperty { + std::vector ids; /**< nucleus id */ + std::vector abundances; /**< relative abundance of source isotopes at equal energies */ +public: + void add(int id, double abundance = 1); + void prepare(ParticleState &particle) const; +}; + /** @class SourceComposition @brief Nuclei with given abundances and a uniform power law spectrum from Emin to Z * Rmax @@ -110,6 +122,18 @@ class SourcePosition: public SourceProperty { void prepare(ParticleState &state) const; }; +/** + @class SourceMultiplePositions + @brief Multiple point source positions with individual luminosities + */ +class SourceMultiplePositions: public SourceProperty { + std::vector positions; + std::vector luminosities; +public: + void add(Vector3d position, double luminosity = 1); + void prepare(ParticleState &particle) const; +}; + /** @class SourceSphericalVolume @brief Uniform random source positions inside a sphere diff --git a/src/Source.cpp b/src/Source.cpp index db60faf3e..37bd0b87b 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -58,6 +58,23 @@ void SourcePowerLawSpectrum::prepare(ParticleState &particle) const { particle.setEnergy(E); } +void SourceNuclei::add(int id, double a) { + ids.push_back(id); + if (abundances.size() > 0) + a += abundances.back(); + abundances.push_back(a); +} + +void SourceNuclei::prepare(ParticleState &particle) const { + if (ids.size() == 0) + throw std::runtime_error("SourceNuclei: no nuclei set"); + double r = Random().rand() * abundances.back(); + int i = 0; + while ((r > abundances[i]) and (i < abundances.size())) + i++; + particle.setId(ids[i]); +} + SourceComposition::SourceComposition(double Emin, double Rmax, double index) : Emin(Emin), Rmax(Rmax), index(index) { } @@ -117,6 +134,23 @@ void SourcePosition::prepare(ParticleState& state) const { state.setPosition(position); } +void SourceMultiplePositions::add(Vector3d pos, double lumi) { + positions.push_back(pos); + if (luminosities.size() > 0) + lumi += luminosities.back(); + luminosities.push_back(lumi); +} + +void SourceMultiplePositions::prepare(ParticleState &particle) const { + if (positions.size() == 0) + throw std::runtime_error("SourceMultiplePositions: no position set"); + double r = Random().rand() * luminosities.back(); + int i = 0; + while ((r > luminosities[i]) and (i < luminosities.size())) + i++; + particle.setPosition(positions[i]); +} + SourceSphericalVolume::SourceSphericalVolume(Vector3d center, double radius) : center(center), radius(radius) { } From 4055a9e7c574e66674f2fdca462f5bfe020674dc Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 24 Jul 2012 11:12:48 +0200 Subject: [PATCH 0150/1298] add output in CRPropa2 format --- include/mpc/Module.h | 4 +- include/mpc/module/Output.h | 38 +++++++++--- src/Module.cpp | 6 +- src/module/Output.cpp | 120 +++++++++++++++++++++++++++++++----- 4 files changed, 139 insertions(+), 29 deletions(-) diff --git a/include/mpc/Module.h b/include/mpc/Module.h index ae0d70f27..133c0ef1e 100644 --- a/include/mpc/Module.h +++ b/include/mpc/Module.h @@ -16,15 +16,13 @@ class Candidate; @brief Abstract base class for modules */ class Module: public Referenced { -protected: std::string description; - public: Module(); virtual ~Module() { } virtual std::string getDescription() const; - virtual void setDescription(const std::string &description); + void setDescription(const std::string &description); virtual void process(Candidate *candidate) const = 0; inline void process(ref_ptr candidate) const { process(candidate.get()); diff --git a/include/mpc/module/Output.h b/include/mpc/module/Output.h index fa4aa5140..7ad030c83 100644 --- a/include/mpc/module/Output.h +++ b/include/mpc/module/Output.h @@ -6,19 +6,26 @@ namespace mpc { +/** + @class ShellOutput + @brief Write properties of the candidate to the shell. + */ +class ShellOutput: public Module { +public: + void process(Candidate *candidate) const; + std::string getDescription() const; +}; + /** @class TrajectoryOutput @brief Saves trajectories to CSV file. */ class TrajectoryOutput: public Module { -private: mutable std::ofstream outfile; - public: TrajectoryOutput(std::string name); ~TrajectoryOutput(); void process(Candidate *candidate) const; - std::string getDescription() const; }; /** @@ -26,7 +33,6 @@ class TrajectoryOutput: public Module { @brief Saves particles with a given property to a CSV file. */ class ConditionalOutput: public Module { -private: mutable std::ofstream outfile; std::string propertyName; bool removeProperty; @@ -35,19 +41,33 @@ class ConditionalOutput: public Module { ~ConditionalOutput(); void setRemoveProperty(bool removeProperty); void process(Candidate *candidate) const; - std::string getDescription() const; }; /** - @class ShellOutput - @brief Write properties of the candidate to the shell. + @class CRPropa2EventOutput + @brief Saves events in CRPropa2 format. */ -class ShellOutput: public Module { +class CRPropa2EventOutput: public Module { + mutable std::ofstream outfile; public: + CRPropa2EventOutput(std::string name); + ~CRPropa2EventOutput(); void process(Candidate *candidate) const; - std::string getDescription() const; }; +/** + @class CRPropa2TrajectoryOutput + @brief Saves trajectory in CRPropa2 format. + */ +class CRPropa2TrajectoryOutput: public Module { + mutable std::ofstream outfile; +public: + CRPropa2TrajectoryOutput(std::string name); + ~CRPropa2TrajectoryOutput(); + void process(Candidate *candidate) const; +}; + + } // namespace mpc #endif /* OUTPUT_H_ */ diff --git a/src/Module.cpp b/src/Module.cpp index 09657263c..794a99570 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -13,8 +13,8 @@ std::string Module::getDescription() const { return description; } -void Module::setDescription(const std::string &description) { - this->description = description; +void Module::setDescription(const std::string &d) { + description = d; } -} +} // namespace mpc diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 2b21ed32f..83863cfdc 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -9,6 +9,7 @@ namespace mpc { TrajectoryOutput::TrajectoryOutput(std::string name) { + setDescription("Trajectory output"); outfile.open(name.c_str()); outfile << "# Age, HepId, E, posX, posY, posZ, dirX, dirY, dirZ, event\n"; } @@ -35,12 +36,9 @@ void TrajectoryOutput::process(Candidate *candidate) const { } } -std::string TrajectoryOutput::getDescription() const { - return "Trajectory output"; -} - ConditionalOutput::ConditionalOutput(std::string filename, std::string propName) { + setDescription("ConditionalOutput, condition: " + propName); removeProperty = false; propertyName = propName; outfile.open(filename.c_str()); @@ -62,26 +60,26 @@ void ConditionalOutput::process(Candidate *candidate) const { char buffer[256]; size_t p = 0; - p += ::sprintf(buffer + p, "%d", candidate->current.getId()); + p += sprintf(buffer + p, "%i", candidate->current.getId()); const Vector3d &pos = candidate->current.getPosition() / Mpc; - p += ::sprintf(buffer + p, ", %.4f, %.4f, %.4f", pos.x, pos.y, pos.z); + p += sprintf(buffer + p, ", %.4f, %.4f, %.4f", pos.x, pos.y, pos.z); const Vector3d &dir = candidate->current.getDirection(); - p += ::sprintf(buffer + p, ", %.4f, %.4f, %.4f", + p += sprintf(buffer + p, ", %.4f, %.4f, %.4f", candidate->current.getEnergy() / EeV, dir.getPhi(), dir.getTheta()); - p += ::sprintf(buffer + p, ", %.4f", + p += sprintf(buffer + p, ", %.4f", candidate->getTrajectoryLength() / Mpc); - p += ::sprintf(buffer + p, ", %d", candidate->initial.getId()); + p += sprintf(buffer + p, ", %i", candidate->initial.getId()); const Vector3d &ipos = candidate->initial.getPosition() / Mpc; - p += ::sprintf(buffer + p, ", %.4f, %.4f, %.4f", ipos.x, ipos.y, ipos.z); + p += sprintf(buffer + p, ", %.4f, %.4f, %.4f", ipos.x, ipos.y, ipos.z); const Vector3d &idir = candidate->initial.getDirection(); - p += ::sprintf(buffer + p, ", %.4f, %.4f, %.4f\n", + p += sprintf(buffer + p, ", %.4f, %.4f, %.4f\n", candidate->initial.getEnergy() / EeV, idir.getPhi(), idir.getTheta()); @@ -96,8 +94,102 @@ void ConditionalOutput::process(Candidate *candidate) const { } } -std::string ConditionalOutput::getDescription() const { - return "ConditionalOutput, condition: " + propertyName; +// _fDataStream << "#CRPropa - Output data file" << endl ; +// if (lUnivType == "One Dimension" && lRecordType == "Events") { +// _fDataStream << "#Format - Particle_Type Initial_Particle_Type Initial_Position(Mpc) Initial_Energy(EeV) Time(Mpc) Energy(EeV)" << endl ; +// } else if (lUnivType == "One Dimension" && lRecordType == "Full Trajectories") { +// _fDataStream << "#Format - Particle_Type Initial_Particle_Type Time(Mpc) Position(Mpc) Energy(EeV)" << endl ; +// } else throw TCrpErr("Output format determination failed") ; + +CRPropa2EventOutput::CRPropa2EventOutput(std::string filename) { + setDescription("Event output in CRPropa2 format"); + outfile.open(filename.c_str()); + outfile << "#CRPropa - Output data file" << std::endl + << "#Format - Particle_Type Initial_Particle_Type Initial_Position[X,Y,Z](Mpc) Initial_Momentum[E,theta,phi](EeV) Time(Mpc) Position[X,Y,Z](Mpc) Momentum[E,theta,phi](EeV)" + << std::endl; +} + +CRPropa2EventOutput::~CRPropa2EventOutput() { + outfile.close(); +} + +void CRPropa2EventOutput::process(Candidate *candidate) const { + if (candidate->isActive()) + return; + if (candidate->hasProperty("Detected")) { + char buffer[256]; // max. 256 characters per line + size_t p = 0; // length of line + + int cid = convertToCRPropaId(candidate->current.getId()); + p += sprintf(buffer + p, "%i, ", cid); + + int iid = convertToCRPropaId(candidate->initial.getId()); + p += sprintf(buffer + p, "%i, ", iid); + + const Vector3d &ipos = candidate->initial.getPosition() / Mpc; + p += sprintf(buffer + p, ", %.4f, %.4f, %.4f", ipos.x, ipos.y, ipos.z); + + double iPhi = candidate->initial.getDirection().getPhi(); + double iTheta = candidate->initial.getDirection().getTheta(); + double iE = candidate->initial.getEnergy() / EeV; + p += sprintf(buffer + p, ", %.4f, %.4f, %.4f", iE, iPhi, iTheta); + + double t = candidate->getTrajectoryLength() / Mpc; + p += sprintf(buffer + p, ", %.4f", t); + + const Vector3d &pos = candidate->current.getPosition() / Mpc; + p += sprintf(buffer + p, ", %.4f, %.4f, %.4f", ipos.x, ipos.y, ipos.z); + + double phi = candidate->current.getDirection().getPhi(); + double theta = candidate->current.getDirection().getTheta(); + double E = candidate->current.getEnergy() / EeV; + p += sprintf(buffer + p, ", %.4f, %.4f, %.4f\n", E, phi, theta); + +#pragma omp critical + { + outfile.write(buffer, p); + } + } +} + +CRPropa2TrajectoryOutput::CRPropa2TrajectoryOutput(std::string filename) { + setDescription("Trajectory output in CRPropa2 format"); + outfile.open(filename.c_str()); + outfile << "#CRPropa - Output data file" << std::endl + << "#Format - Particle_Type Initial_Particle_Type Time(Mpc) Position[X,Y,Z](Mpc) Momentum[X,Y,Z](EeV) Energy(EeV)" + << std::endl; +} + +CRPropa2TrajectoryOutput::~CRPropa2TrajectoryOutput() { + outfile.close(); +} + +void CRPropa2TrajectoryOutput::process(Candidate *candidate) const { + char buffer[256]; + size_t p = 0; + + int cid = convertToCRPropaId(candidate->current.getId()); + p += sprintf(buffer + p, "%i", cid); + + int iid = convertToCRPropaId(candidate->initial.getId()); + p += sprintf(buffer + p, ", %i", iid); + + double t = candidate->getTrajectoryLength() / Mpc; + p += sprintf(buffer + p, ", %.4f", t); + + const Vector3d &pos = candidate->current.getPosition() / Mpc; + p += sprintf(buffer + p, ", %.4f, %.4f, %.4f", pos.x, pos.y, pos.z); + + const Vector3d &mom = candidate->current.getMomentum() / EeV; + p += sprintf(buffer + p, ", %.4g, %.4g, %.4g", mom.x, mom.y, mom.z); + + double E = candidate->current.getEnergy() / EeV; + p += sprintf(buffer + p, ", %.4f\n", E); + +#pragma omp critical + { + outfile.write(buffer, p); + } } void ShellOutput::process(Candidate *candidate) const { @@ -116,7 +208,7 @@ void ShellOutput::process(Candidate *candidate) const { } std::string ShellOutput::getDescription() const { - return "ShellOutput"; + return "Shell output"; } } // namespace mpc From 649c846220d4b6962b89196d7191e87696042a7d Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 24 Jul 2012 14:10:26 +0200 Subject: [PATCH 0151/1298] refactor MagneticFieldGrid --- CMakeLists.txt | 12 +- include/mpc/PhasePoint.h | 4 +- include/mpc/Referenced.h | 2 +- include/mpc/Vector3.h | 4 + include/mpc/magneticField/MagneticFieldGrid.h | 97 ++------- .../SPHTurbulentMagneticFieldGrid.h | 57 ------ .../TurbulentMagneticFieldGrid.h | 69 ------- python/mpc.i | 9 +- src/magneticField/MagneticFieldGrid.cpp | 185 ++++-------------- .../SPHTurbulentMagneticFieldGrid.cpp | 44 ----- .../TurbulentMagneticFieldGrid.cpp | 176 ----------------- src/openmp.cpp | 51 ----- test/python/testTurbulentDeflection.py | 16 +- test/python/testTurbulentFieldGrid.py | 11 +- test/testMagneticField.cpp | 179 +++++++++-------- test/testSPHField.cpp | 176 ++++++++--------- 16 files changed, 265 insertions(+), 827 deletions(-) delete mode 100644 include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h delete mode 100644 include/mpc/magneticField/TurbulentMagneticFieldGrid.h delete mode 100644 src/magneticField/SPHTurbulentMagneticFieldGrid.cpp delete mode 100644 src/magneticField/TurbulentMagneticFieldGrid.cpp delete mode 100644 src/openmp.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e9397f08b..84bd1c5e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,11 +48,12 @@ endif() # fftw3f (optional for turbulent magnetic fields) find_package(FFTW3F) -if (FFTW3F_FOUND) - list(APPEND MPC_EXTRA_SOURCES src/magneticField/TurbulentMagneticFieldGrid.cpp) +if(FFTW3F_FOUND) list(APPEND MPC_EXTRA_INCLUDES ${FFTW3F_INCLUDE_DIR}) list(APPEND MPC_EXTRA_LIBRARIES ${FFTW3F_LIBRARY}) -endif (FFTW3F_FOUND) + add_definitions(-DMPC_HAVE_FFTW3F) + list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_FFTW3F) +endif(FFTW3F_FOUND) # gadget (optional for SPH magnetic fields) find_package(Gadget) @@ -62,10 +63,6 @@ if (GADGET_FOUND) list(APPEND MPC_EXTRA_LIBRARIES ${GADGET_LIBRARY}) add_definitions (-DMPC_HAVE_GADGET) list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_GADGET) - # fftw3f needed for SPHTurbulentMagneticField - if (FFTW3F_FOUND) - list(APPEND MPC_EXTRA_SOURCES src/magneticField/SPHTurbulentMagneticFieldGrid.cpp) - endif (FFTW3F_FOUND) endif (GADGET_FOUND) # Google Performance Tools (optional as possible performance tweak) @@ -102,6 +99,7 @@ add_library(mpc SHARED src/module/Output.cpp src/module/Tools.cpp src/magneticField/MagneticFieldGrid.cpp + src/magneticField/MagneticFieldGridTools.cpp src/magneticField/TurbulentMagneticField.cpp ${MPC_EXTRA_SOURCES} ) diff --git a/include/mpc/PhasePoint.h b/include/mpc/PhasePoint.h index 1da519d69..dd1bfbdde 100644 --- a/include/mpc/PhasePoint.h +++ b/include/mpc/PhasePoint.h @@ -45,9 +45,7 @@ class PhasePoint { } PhasePoint abs() const { - Vector3d abs_a( fabs(a.x), fabs(a.y), fabs(a.z) ); - Vector3d abs_b( fabs(b.x), fabs(b.y), fabs(b.z) ); - return PhasePoint(abs_a, abs_b); + return PhasePoint(a.abs(), b.abs()); } }; diff --git a/include/mpc/Referenced.h b/include/mpc/Referenced.h index d2579561a..1947655c5 100644 --- a/include/mpc/Referenced.h +++ b/include/mpc/Referenced.h @@ -12,7 +12,7 @@ namespace mpc { @class Referenced @brief Base class for reference counting - A form of memory management is needed to prevent memory leaks when using MPC via SWIG. + A form of memory management is needed to prevent memory leaks when using MPC in Python via SWIG. This base class enables reference counting. Every reference increases the reference counter, every dereference decreases it. When the counter is decreased to 0, the object is deleted. diff --git a/include/mpc/Vector3.h b/include/mpc/Vector3.h index 1bea0c8db..0aae554d4 100644 --- a/include/mpc/Vector3.h +++ b/include/mpc/Vector3.h @@ -158,6 +158,10 @@ class Vector3 { z = std::max(lower, std::min(z, upper)); } + Vector3 abs() const { + return Vector3(std::abs(x), std::abs(y), std::abs(z)); + } + Vector3 floor() const { return Vector3(std::floor(x), std::floor(y), std::floor(z)); } diff --git a/include/mpc/magneticField/MagneticFieldGrid.h b/include/mpc/magneticField/MagneticFieldGrid.h index 8414c5790..f5cff9a44 100644 --- a/include/mpc/magneticField/MagneticFieldGrid.h +++ b/include/mpc/magneticField/MagneticFieldGrid.h @@ -2,105 +2,46 @@ #define MPC_MAGNETICFIELDGRID_H_ #include "mpc/magneticField/MagneticField.h" - #include namespace mpc { /** @class MagneticFieldGrid - @brief Periodic, cubic, cartesian magnetic field grid with trilinear interpolation. + @brief Magnetic field on a periodic, cartesian grid with trilinear interpolation. - This class provides a magnetic field grid. - The grid is of cubic shape and the spacing is constant and equal along all three axes. + This class provides a three-dimensional magnetic field grid. + The grid spacing is constant and equal along all three axes. Magnetic field values are calculated by trilinear interpolation of the surrounding 8 grid points. \n The grid is periodically extended. Thus the field at opposite borders is assumed identical and does not need to be sampled twice. The grid sample positions are hence at 0, size / samples, ... size * (samples - 1) / samples and the grid spacing is size / samples. */ class MagneticFieldGrid: public MagneticField { -public: - /** - * Constructor - * @param origin Lower left front corner of the grid - * @param size Physical extension of the field grid - * @param samples Number of grid samples per edge - */ - MagneticFieldGrid(Vector3d origin, double size, size_t samples); - - /** - * Multiply the field by a factor. - * @param norm Normalization factor - */ - void normalize(double norm); - - /** - * Load the field grid from a binary file. - * The field is stored single precision numbers with the field components in xyz order and the grid z-index changing the fastest. - */ - void load(std::string filename); - - /** - * Dump the field grid to a binary file. - * The field is stored single precision numbers with the field components in xyz order and the grid z-index changing the fastest. - */ - void dump(std::string filename) const; + std::vector grid; /**< Magnetic field vectors */ + Vector3d origin; /**< Lower left front corner of the grid */ + size_t Nx, Ny, Nz; /**< Number of grid points per edge */ + double spacing; /**< Distance between two grid points (= size / samples) */ - /** - * Load the field grid from a plain text file. - * The field is stored as one grid point per line from (0,0,0) to (nx, ny, nz) with the grid z-index changing the fastest. - * Within one line the magnetic field values are stored in xyz order separated by a blank or tab. - * Header lines must start with a #. - * @param unit conversion of the values in the file to SI - */ - void loadTxt(std::string filename, double unit); +public: + MagneticFieldGrid(Vector3d origin, size_t N, double spacing); + MagneticFieldGrid(Vector3d origin, size_t Nx, size_t Ny, size_t Nz, + double spacing); - /** - * Dump the field grid to a plain text file. - * The field is stored as one grid point per line from (0,0,0) to (nx, ny, nz) with the grid z-index changing the fastest. - * Within one line the magnetic field values are stored in xyz order separated by a blank or tab. - * Header lines must start with a #. - * @param unit conversion of SI to the values in the file - */ - void dumpTxt(std::string filename, double unit); + void setOrigin(Vector3d origin); + void setGridSize(size_t Nx, size_t Ny, size_t Nz); + void setSpacing(double spacing); - /** - * Modulate the magnetic field with a density field from a binary file. - * The field should be (re)normalized afterwards. - * The file has to contain the density values in float precision on a grid with N + 1 samples per edge, the last of which is disregarded due to periodicity. - * @param filename Path to the density grid file - * @param exp Exponent for the modulation - */ - void modulateWithDensityField(std::string filename, double exp = 2. / 3.); + Vector3d getOrigin() const; + size_t getNx() const; + size_t getNy() const; + size_t getNz() const; + double getSpacing() const; - /** Return a reference to the grid point (ix, iy, iz). */ Vector3f &get(size_t ix, size_t iy, size_t iz); const Vector3f &get(size_t ix, size_t iy, size_t iz) const; - /** Return the field vector at arbitrary position by trilinear interpolation. */ Vector3d getField(const Vector3d &position) const; - - /** Return the RMS field strength */ - double getRMSFieldStrength() const; - - /** - * Return the RMS field strength inside a spherical region - * @param center Center of the sphere - * @param radius Radius of the sphere - */ - double getRMSFieldStrengthInSphere(Vector3d center, double radius) const; - - Vector3d getGridOrigin() const; - size_t getGridSamples() const; - double getGridSpacing() const; - double getGridSize() const; - -protected: - std::vector grid; /**< Grid of magnetic field vectors */ - Vector3d origin; /**< Origin of the field */ - double size; /**< Extension of the field */ - size_t samples; /**< Number of grid points per edge */ - double spacing; /**< Distance between two grid points (= size / samples) */ }; /** Lower and upper neighbor in a periodically continued unit grid */ diff --git a/include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h b/include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h deleted file mode 100644 index 4286b9005..000000000 --- a/include/mpc/magneticField/SPHTurbulentMagneticFieldGrid.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef MPC_SPHTURBULENTMAGNETICFIELDGRID_H_ -#define MPC_SPHTURBULENTMAGNETICFIELDGRID_H_ - -#ifdef MPC_HAVE_GADGET - -#include "mpc/magneticField/TurbulentMagneticFieldGrid.h" -#include "mpc/magneticField/SPHMagneticField.h" - -#include - -namespace mpc { - -/** - @class SPHTurbulentMagneticFieldGrid - @brief Turbulent magnetic field on a cubic grid modulated with an SPH density field. - */ -class SPHTurbulentMagneticFieldGrid: public TurbulentMagneticFieldGrid { - std::auto_ptr sphField; /**< SPH (density) field */ - double tabRho[67]; - double tabB[67]; - -public: - /** Constructor. Reimplementation of TurbulentMagneticField. */ - SPHTurbulentMagneticFieldGrid(Vector3d origin, double size, size_t samples) : - TurbulentMagneticFieldGrid(origin, size, samples) { - } - - /** Constructor. Reimplementation of TurbulentMagneticField. */ - SPHTurbulentMagneticFieldGrid(Vector3d origin, double size, size_t samples, - double lMin, double lMax, double spectralIndex, double Brms) : - TurbulentMagneticFieldGrid(origin, size, samples, lMin, lMax, - spectralIndex, Brms) { - } - - /** - * Modulate the magnetic field with the baryon density from a gadget SPH field. - * @param filename Path to the SPH database file - * @param origin Origin of the SPH field - * @param size Size of the SPH field - * @param bins Number of bins of the SPH field - */ - void setDensityField(std::string filename, Vector3d origin, double size, - size_t bins); - - void setModulation(std::string filename); - - /** Get the density modulated magnetic field vector */ - Vector3d getField(const Vector3d &position) const; - - /** Get the density in [10^10 M_sol * h^2 / kpc^3] */ - double getRho(const Vector3d &position) const; -}; - -} // namespace mpc - -#endif // MPC_HAVE_GADGET -#endif // MPC_SPHTURBULENTMAGNETICFIELDGRID_H_ diff --git a/include/mpc/magneticField/TurbulentMagneticFieldGrid.h b/include/mpc/magneticField/TurbulentMagneticFieldGrid.h deleted file mode 100644 index 52aceb931..000000000 --- a/include/mpc/magneticField/TurbulentMagneticFieldGrid.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef MPC_TURBULENTMAGNETICFIELDGRID_H_ -#define MPC_TURBULENTMAGNETICFIELDGRID_H_ - -#include "mpc/magneticField/MagneticFieldGrid.h" -#include "mpc/Random.h" - -namespace mpc { - -/** - @class TurbulentMagneticFieldGrid - @brief Turbulent magnetic field on a cubic grid with trilinear interpolation. - - This class creates a random magnetic field with a turbulent spectrum. - The field is isotropic and homogeneous with a zero mean magnetic field and and divergence. - */ -class TurbulentMagneticFieldGrid: public MagneticFieldGrid { -public: - /** - * Constructor - * @param origin Lower left front corner of the grid - * @param size Physical extension of the field grid - * @param samples Number of grid samples per edge - */ - TurbulentMagneticFieldGrid(Vector3d origin, double size, size_t samples); - - /** - * Constructor, also performs initialization and normalization. - * @param origin Lower left front corner of the grid - * @param size Physical extension of the field grid - * @param samples Number of grid samples per edge - * @param lMin Minimum wavelength of the turbulence - * @param lMax Maximum wavelength of the turbulence - * @param spectralIndex Power spectral index of the turbulence - * @param Brms RMS field strength - */ - TurbulentMagneticFieldGrid(Vector3d origin, double size, size_t samples, - double lMin, double lMax, double spectralIndex, double Brms); - - /** - * Define the properties of the turbulence. - * @param lMin Minimum wavelength of the turbulence - * @param lMax Maximum wavelength of the turbulence - * @param spectralIndex Power spectral index turbulence - */ - void setTurbulenceProperties(double lMin, double lMax, double spectralIndex); - - /** Create a random initialization of the turbulent field. */ - void initialize(); - - /** Create a random initialization from a given seed. */ - void initialize(int seed); - - double getPowerSpectralIndex() const; - double getMinimumWavelength() const; - double getMaximumWavelength() const; - - /** Return the analytical calculation of the correlation length. */ - double getCorrelationLength() const; - -protected: - double lMin; /**< Minimum wavelength of the turbulence */ - double lMax; /**< Maximum wavelength of the turbulence */ - double spectralIndex; /**< Power spectral index of the turbulence */ - Random random; /**< Random number generator instance */ -}; - -} // namespace mpc - -#endif /* MPC_TURBULENTMAGNETICFIELDGRID_H_ */ diff --git a/python/mpc.i b/python/mpc.i index 07332dc69..ed8578f52 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -29,10 +29,8 @@ #include "mpc/magneticField/MagneticField.h" #include "mpc/magneticField/UniformMagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" -#include "mpc/magneticField/TurbulentMagneticFieldGrid.h" -#include "mpc/magneticField/TurbulentMagneticField.h" +#include "mpc/magneticField/MagneticFieldGridTools.h" #include "mpc/magneticField/SPHMagneticField.h" -#include "mpc/magneticField/SPHTurbulentMagneticFieldGrid.h" #include "mpc/Referenced.h" #include "mpc/Candidate.h" @@ -95,7 +93,6 @@ %include "mpc/Candidate.h" %template(ModuleRefPtr) mpc::ref_ptr; -%template(stdModuleVector) std::vector< mpc::ref_ptr >; %template(stdModuleList) std::list< mpc::ref_ptr >; %include "mpc/Module.h" @@ -104,10 +101,8 @@ %include "mpc/magneticField/MagneticField.h" %include "mpc/magneticField/UniformMagneticField.h" %include "mpc/magneticField/MagneticFieldGrid.h" -%include "mpc/magneticField/TurbulentMagneticFieldGrid.h" -%include "mpc/magneticField/TurbulentMagneticField.h" +%include "mpc/magneticField/MagneticFieldGridTools.h" %include "mpc/magneticField/SPHMagneticField.h" -%include "mpc/magneticField/SPHTurbulentMagneticFieldGrid.h" %include "mpc/ExplicitRungeKutta.h" %include "mpc/PhasePoint.h" diff --git a/src/magneticField/MagneticFieldGrid.cpp b/src/magneticField/MagneticFieldGrid.cpp index be42e0d45..feb2c655a 100644 --- a/src/magneticField/MagneticFieldGrid.cpp +++ b/src/magneticField/MagneticFieldGrid.cpp @@ -1,177 +1,63 @@ #include "mpc/magneticField/MagneticFieldGrid.h" - #include -#include namespace mpc { -void periodicClamp(double x, int n, int &lo, int &hi) { - lo = ((int(floor(x)) % n) + n) % n; - hi = (lo + 1) % n; -} - -MagneticFieldGrid::MagneticFieldGrid(Vector3d origin, double size, - size_t samples) { - this->origin = origin; - this->size = size; - this->samples = samples; - this->spacing = size / samples; - grid.resize(samples * samples * samples); -} - -void MagneticFieldGrid::normalize(double norm) { - for (int ix = 0; ix < samples; ix++) - for (int iy = 0; iy < samples; iy++) - for (int iz = 0; iz < samples; iz++) - get(ix, iy, iz) *= norm; -} - -void MagneticFieldGrid::load(std::string filename) { - std::ifstream fin(filename.c_str(), std::ios::binary); - if (!fin) - throw std::runtime_error("MagneticFieldGrid: File not found"); - for (int ix = 0; ix < samples; ix++) { - for (int iy = 0; iy < samples; iy++) { - for (int iz = 0; iz < samples; iz++) { - Vector3f &b = get(ix, iy, iz); - fin.read((char*) &(b.x), sizeof(float)); - fin.read((char*) &(b.y), sizeof(float)); - fin.read((char*) &(b.z), sizeof(float)); - } - } - } - fin.close(); +MagneticFieldGrid::MagneticFieldGrid(Vector3d origin, size_t N, + double spacing) { + setOrigin(origin); + setGridSize(N, N, N); + setSpacing(spacing); } -void MagneticFieldGrid::dump(std::string filename) const { - std::ofstream fout(filename.c_str(), std::ios::binary); - if (!fout) - throw std::runtime_error("MagneticFieldGrid: Could not open file"); - for (int ix = 0; ix < samples; ix++) { - for (int iy = 0; iy < samples; iy++) { - for (int iz = 0; iz < samples; iz++) { - Vector3f b = get(ix, iy, iz); - fout.write((char*) &(b.x), sizeof(float)); - fout.write((char*) &(b.y), sizeof(float)); - fout.write((char*) &(b.z), sizeof(float)); - } - } - } - fout.close(); +MagneticFieldGrid::MagneticFieldGrid(Vector3d origin, size_t Nx, size_t Ny, + size_t Nz, double spacing) { + setOrigin(origin); + setGridSize(Nx, Ny, Nz); + setSpacing(spacing); } -void MagneticFieldGrid::loadTxt(std::string filename, double conversion) { - std::ifstream fin(filename.c_str()); - if (!fin) - throw std::runtime_error("MagneticFieldGrid: file not found"); - - // skip header lines - while (fin.peek() == '#') - fin.ignore(std::numeric_limits::max(), '\n'); - - for (int ix = 0; ix < samples; ix++) { - for (int iy = 0; iy < samples; iy++) { - for (int iz = 0; iz < samples; iz++) { - Vector3f &b = get(ix, iy, iz); - fin >> b.x >> b.y >> b.z; - b *= conversion; - if (fin.eof()) - throw std::runtime_error("MagneticFieldGrid: file too short"); - } - } - } - fin.close(); +void MagneticFieldGrid::setOrigin(Vector3d origin) { + this->origin = origin; } -void MagneticFieldGrid::dumpTxt(std::string filename, double conversion) { - std::ofstream fout(filename.c_str()); - if (!fout) - throw std::runtime_error("MagneticFieldGrid: could not open file"); - for (int ix = 0; ix < samples; ix++) { - for (int iy = 0; iy < samples; iy++) { - for (int iz = 0; iz < samples; iz++) { - Vector3f b = get(ix, iy, iz) * conversion; - fout << b << "\n"; - } - } - } - fout.close(); +void MagneticFieldGrid::setGridSize(size_t Nx, size_t Ny, size_t Nz) { + this->Nx = Nx; + this->Ny = Ny; + this->Nz = Nz; + grid.resize(Nx * Ny * Nz); } -void MagneticFieldGrid::modulateWithDensityField(std::string filename, - double exp) { - std::ifstream infile(filename.c_str(), std::ios::binary); - if (!infile) - throw std::runtime_error("mpc::MagneticFieldGrid: File not found"); - double sumB2 = 0; - int numB2 = 0; - float rho; - for (int ix = 0; ix < samples + 1; ix++) { - for (int iy = 0; iy < samples + 1; iy++) { - for (int iz = 0; iz < samples + 1; iz++) { - infile.read((char*) &rho, sizeof(float)); - if ((ix == samples) or (iy == samples) or (iz == samples)) - continue; // skip last grid points in each direction - Vector3d pos = origin + Vector3d(ix, iy, iz) * spacing; - Vector3f &b = get(ix, iy, iz); - b *= pow(rho, exp); - } - } - } - infile.close(); +void MagneticFieldGrid::setSpacing(double spacing) { + this->spacing = spacing; } -Vector3d MagneticFieldGrid::getGridOrigin() const { +Vector3d MagneticFieldGrid::getOrigin() const { return origin; } -size_t MagneticFieldGrid::getGridSamples() const { - return samples; +size_t MagneticFieldGrid::getNx() const { + return Nx; } -double MagneticFieldGrid::getGridSpacing() const { - return spacing; +size_t MagneticFieldGrid::getNy() const { + return Ny; } -double MagneticFieldGrid::getGridSize() const { - return size; +size_t MagneticFieldGrid::getNz() const { + return Nz; } -double MagneticFieldGrid::getRMSFieldStrength() const { - double sumB2 = 0; - for (int ix = 0; ix < samples; ix++) - for (int iy = 0; iy < samples; iy++) - for (int iz = 0; iz < samples; iz++) - sumB2 += get(ix, iy, iz).getMag2(); - return sqrt(sumB2 / samples / samples / samples); -} - -double MagneticFieldGrid::getRMSFieldStrengthInSphere(Vector3d center, - double radius) const { - int numB2 = 0; - double sumB2 = 0; - for (int ix = 0; ix < samples; ix++) { - for (int iy = 0; iy < samples; iy++) { - for (int iz = 0; iz < samples; iz++) { - Vector3d position = origin + Vector3d(ix, iy, iz) * spacing; - if (position.getDistanceTo(center) < radius) { - sumB2 += get(ix, iy, iz).getMag2(); - numB2++; - } - } - } - } - return sqrt(sumB2 / numB2); +double MagneticFieldGrid::getSpacing() const { + return spacing; } Vector3f &MagneticFieldGrid::get(size_t ix, size_t iy, size_t iz) { - int i = ix * samples * samples + iy * samples + iz; - return grid[i]; + return grid[ix * Ny * Nz + iy * Ny + iz]; } const Vector3f &MagneticFieldGrid::get(size_t ix, size_t iy, size_t iz) const { - int i = ix * samples * samples + iy * samples + iz; - return grid[i]; + return grid[ix * Ny * Nz + iy * Ny + iz]; } Vector3d MagneticFieldGrid::getField(const Vector3d &position) const { @@ -180,9 +66,9 @@ Vector3d MagneticFieldGrid::getField(const Vector3d &position) const { // indices of lower and upper neighbors int ix, iX, iy, iY, iz, iZ; - periodicClamp(r.x, samples, ix, iX); - periodicClamp(r.y, samples, iy, iY); - periodicClamp(r.z, samples, iz, iZ); + periodicClamp(r.x, Nx, ix, iX); + periodicClamp(r.y, Ny, iy, iY); + periodicClamp(r.z, Nz, iz, iZ); // linear fraction to lower and upper neighbors double fx = r.x - floor(r.x); @@ -215,4 +101,9 @@ Vector3d MagneticFieldGrid::getField(const Vector3d &position) const { return b; } +void periodicClamp(double x, int n, int &lo, int &hi) { + lo = ((int(floor(x)) % n) + n) % n; + hi = (lo + 1) % n; +} + } // namespace mpc diff --git a/src/magneticField/SPHTurbulentMagneticFieldGrid.cpp b/src/magneticField/SPHTurbulentMagneticFieldGrid.cpp deleted file mode 100644 index 0d6744188..000000000 --- a/src/magneticField/SPHTurbulentMagneticFieldGrid.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "mpc/magneticField/SPHTurbulentMagneticFieldGrid.h" -#include "mpc/Common.h" -#include "mpc/Units.h" - -namespace mpc { - -void SPHTurbulentMagneticFieldGrid::setDensityField(std::string filename, - Vector3d origin, double size, size_t bins) { - sphField.reset(new SPHMagneticField(origin, size, bins, filename)); -} - -void SPHTurbulentMagneticFieldGrid::setModulation(std::string filename) { - // load modulation profile - std::ifstream infile(filename.c_str()); - if (!infile.good()) - throw std::runtime_error("mpc: could not open file " + filename); - for (int i = 0; i < 67; i++) { - infile >> tabRho[i] >> tabB[i]; - infile.ignore(std::numeric_limits::max(), '\n'); - } - infile.close(); -} - -Vector3d SPHTurbulentMagneticFieldGrid::getField( - const Vector3d &position) const { - double rho = sphField->getRho(position); // density in [kg/m^3] - if (rho <= std::numeric_limits::min()) - return Vector3d(0.); - double x = log10(rho / 1000); // log10(density in [g/cm^3]) - double m; // strength in [G] - if (x <= -32) - m = 206.404 + 12.9872 * x + 0.193117 * x * x; - else if (x >= -28) - m = -37.3625 - 2.74343 * x - 0.0585562 * x * x; - else - m = interpolate(x, tabRho, tabB); - return MagneticFieldGrid::getField(position) * pow(10, m) / 10000; // B-field in [T] -} - -double SPHTurbulentMagneticFieldGrid::getRho(const Vector3d &position) const { - return sphField->getRho(position); -} - -} // namespace mpc diff --git a/src/magneticField/TurbulentMagneticFieldGrid.cpp b/src/magneticField/TurbulentMagneticFieldGrid.cpp deleted file mode 100644 index 7ff4df0c7..000000000 --- a/src/magneticField/TurbulentMagneticFieldGrid.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include "mpc/magneticField/TurbulentMagneticFieldGrid.h" -#include "mpc/Units.h" - -#include "fftw3.h" - -namespace mpc { - -TurbulentMagneticFieldGrid::TurbulentMagneticFieldGrid(Vector3d origin, double size, - size_t samples) : - MagneticFieldGrid(origin, size, samples) { -} - -TurbulentMagneticFieldGrid::TurbulentMagneticFieldGrid(Vector3d origin, double size, - size_t samples, double lMin, double lMax, double spectralIndex, - double Brms) : - MagneticFieldGrid(origin, size, samples) { - this->lMin = lMin; - this->lMax = lMax; - this->spectralIndex = spectralIndex; - initialize(); - normalize(Brms / getRMSFieldStrength()); -} - -void TurbulentMagneticFieldGrid::setTurbulenceProperties(double lMin, double lMax, - double spectralIndex) { - this->lMin = lMin; - this->lMax = lMax; - this->spectralIndex = spectralIndex; -} - -void TurbulentMagneticFieldGrid::initialize(int seed) { - random.seed(seed); - initialize(); -} - -void TurbulentMagneticFieldGrid::initialize() { - if (lMin < 2 * spacing) - throw std::runtime_error( - "mpc::TurbulentMagneticField: lMin < 2 * spacing"); - if (lMin >= lMax) - throw std::runtime_error("mpc::TurbulentMagneticField: lMin >= lMax"); - if (lMax > size / 2) - throw std::runtime_error( - "mpc::TurbulentMagneticField: lMax > size / 2"); - - size_t n = samples; // size of array - size_t n2 = (size_t) floor(n / 2) + 1; // size array in z-direction in configuration space - - // arrays to hold the complex vector components of the B(k)-field - fftwf_complex *Bkx, *Bky, *Bkz; - Bkx = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * n * n * n2); - Bky = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * n * n * n2); - Bkz = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * n * n * n2); - - // calculate the n possible discrete wave numbers - double K[n]; - for (int i = 0; i < n; i++) - K[i] = (double) i / n - i / (n / 2); - - // construct the field in configuration space - int i; - double k, theta, phase, cosPhase, sinPhase; - double kMin = spacing / lMax; - double kMax = spacing / lMin; - Vector3f b; // real b-field vector - Vector3f ek, e1, e2; // orthogonal base - Vector3f n0(1, 1, 1); // arbitrary vector to construct orthogonal base - - for (size_t ix = 0; ix < n; ix++) { - for (size_t iy = 0; iy < n; iy++) { - for (size_t iz = 0; iz < n2; iz++) { - - i = ix * n * n2 + iy * n2 + iz; - ek.setXYZ(K[ix], K[iy], K[iz]); - k = ek.getMag(); - - // wave outside of turbulent range -> B(k) = 0 - if ((k < kMin) || (k > kMax)) { - Bkx[i][0] = 0; - Bkx[i][1] = 0; - Bky[i][0] = 0; - Bky[i][1] = 0; - Bkz[i][0] = 0; - Bkz[i][1] = 0; - continue; - } - - // construct an orthogonal base ek, e1, e2 - if (ek.getAngleTo(n0) < 1e-3) { - // ek parallel to (1,1,1) - e1.setXYZ(-1., 1., 0); - e2.setXYZ(1., 1., -2.); - } else { - // ek not parallel to (1,1,1) - e1 = n0.cross(ek); - e2 = ek.cross(e1); - } - e1 /= e1.getMag(); - e2 /= e2.getMag(); - - // random orientation perpendicular to k - theta = 2 * M_PI * random.rand(); - b = e1 * cos(theta) + e2 * sin(theta); - - // standard normal distributed amplitude weighted with k^alpha/2 - b *= random.randNorm() * pow(k, spectralIndex / 2.); - - // uniform random phase - phase = 2 * M_PI * random.rand(); - cosPhase = cos(phase); // real part - sinPhase = sin(phase); // imaginary part - - Bkx[i][0] = b.x * cosPhase; - Bkx[i][1] = b.x * sinPhase; - Bky[i][0] = b.y * cosPhase; - Bky[i][1] = b.y * sinPhase; - Bkz[i][0] = b.z * cosPhase; - Bkz[i][1] = b.z * sinPhase; - } - } - } - - // in-place, complex to real, inverse Fourier transformation on each component - // note that the last elements of B(x) are unused now - float *Bx = (float*) Bkx; - fftwf_plan plan_x = fftwf_plan_dft_c2r_3d(n, n, n, Bkx, Bx, FFTW_ESTIMATE); - fftwf_execute(plan_x); - fftwf_destroy_plan(plan_x); - - float *By = (float*) Bky; - fftwf_plan plan_y = fftwf_plan_dft_c2r_3d(n, n, n, Bky, By, FFTW_ESTIMATE); - fftwf_execute(plan_y); - fftwf_destroy_plan(plan_y); - - float *Bz = (float*) Bkz; - fftwf_plan plan_z = fftwf_plan_dft_c2r_3d(n, n, n, Bkz, Bz, FFTW_ESTIMATE); - fftwf_execute(plan_z); - fftwf_destroy_plan(plan_z); - - // save to grid - for (size_t ix = 0; ix < n; ix++) { - for (size_t iy = 0; iy < n; iy++) { - for (size_t iz = 0; iz < n; iz++) { - i = ix * n * 2 * n2 + iy * 2 * n2 + iz; - Vector3f &b = get(ix, iy, iz); - b.x = Bx[i]; - b.y = By[i]; - b.z = Bz[i]; - } - } - } - - fftwf_free(Bkx); - fftwf_free(Bky); - fftwf_free(Bkz); -} - -double TurbulentMagneticFieldGrid::getPowerSpectralIndex() const { - return spectralIndex; -} - -double TurbulentMagneticFieldGrid::getMinimumWavelength() const { - return lMin; -} - -double TurbulentMagneticFieldGrid::getMaximumWavelength() const { - return lMax; -} - -double TurbulentMagneticFieldGrid::getCorrelationLength() const { - double r = lMin / lMax; - double a = -spectralIndex - 2; - return lMax / 2 * (a - 1) / a * (1 - pow(r, a)) / (1 - pow(r, a - 1)); -} - -} // namespace mpc diff --git a/src/openmp.cpp b/src/openmp.cpp deleted file mode 100644 index 84f3c3eaa..000000000 --- a/src/openmp.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "mpc/magneticField/turbulentMagneticFieldGrid.h" -#include "mpc/magneticField/uniformMagneticField.h" -#include "mpc/module/DeflectionCK.h" -#include "mpc/module/NuclearDecay.h" -#include "mpc/module/PhotoDisintegration.h" -#include "mpc/module/ElectronPairProduction.h" -#include "mpc/module/PhotoPionProduction.h" -#include "mpc/module/BreakCondition.h" -#include "mpc/module/Output.h" -#include "mpc/ModuleList.h" - -#include - -using namespace mpc; -using namespace std; - -int main(int argc, char **argv) { - -// ref_ptr field = new TurbulentMagneticFieldGrid( -// Vector3(0, 0, 0), 64, 1., 2., 8., 1e-12, -11. / 3.); - ref_ptr field = new UniformMagneticField( - Vector3(0, 0, 1e-12)); - - ModuleList modules; - modules.add(new DeflectionCK(field)); - modules.add(new NuclearDecay()); - modules.add(new PhotoDisintegration()); - modules.add(new ElectronPairProduction()); - modules.add(new PhotoPionProduction()); - modules.add(new MaximumTrajectoryLength(50 * Mpc)); - modules.add(new MinimumEnergy(5 * EeV)); - - cout << modules << endl; - - ParticleState initial; - initial.setId(getNucleusId(56, 26)); - initial.setEnergy(100 * EeV); - initial.setPosition(Vector3(0, 0, 0)); - initial.setDirection(Vector3(1, 0, 0)); - -#pragma omp parallel for - for (size_t i = 0; i < 1000; i++) { - - ref_ptr candidate = new Candidate(initial); - modules.run(candidate, true); - } - - cout << "done" << endl; - - return 0; -} diff --git a/test/python/testTurbulentDeflection.py b/test/python/testTurbulentDeflection.py index e832fa214..dc9204bb0 100644 --- a/test/python/testTurbulentDeflection.py +++ b/test/python/testTurbulentDeflection.py @@ -3,14 +3,19 @@ E = 10 # proton energy [EeV] -nT = 1000 # number of trajectories -nS = 100 # number of sampling points to simulate -nP = range(75) # sampling points for plot +nT = 500 # number of trajectories +nS = 50 # number of sampling points to simulate +nP = range(30) # sampling points for plot # create turbulent field with B_RMS = 1 nG and 0.5 Mpc correlation length -field = TurbulentMagneticFieldGrid(Vector3d(0, 0, 0), 256 * 0.05 * Mpc, 256, 0.1 * Mpc, 2.2 * Mpc, -11/3., 1 * nG) +field = MagneticFieldGrid(Vector3d(0, 0, 0), 128, 0.05 * Mpc) +initTurbulence(field, 1 * nG, 0.1 * Mpc, 2.2 * Mpc, -11/3.) propa = DeflectionCK(field) +Lc = turbulentCorrelationLength(0.1 * Mpc, 2.2 * Mpc, -11/3.) / Mpc +Brms = 1 # nG +Rg = 1.08 * E / Brms # Mpc + age = linspace(1, 150, nS) distance, rms1, rms2 = zeros((3, nS)) @@ -46,9 +51,6 @@ rms1 = (rms1 / nT)**.5 rms2 = (rms2 / nT)**.5 -Lc = field.getCorrelationLength() / Mpc -Brms = field.getRMSFieldStrength() / nG -Rg = 1.08 * E / Brms # Mpc theory = 38 * (distance * Lc)**.5 * Brms / E * pi/180 figure() diff --git a/test/python/testTurbulentFieldGrid.py b/test/python/testTurbulentFieldGrid.py index 2f650e39d..56f0dd1c5 100644 --- a/test/python/testTurbulentFieldGrid.py +++ b/test/python/testTurbulentFieldGrid.py @@ -78,15 +78,16 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): ### create field +origin = Vector3d(0,0,0) n = 128 +spacing = 1 lMin, lMax = 2, 32 Brms = 1. alpha = -11./3 -field = TurbulentMagneticFieldGrid(Vector3d(0, 0, 0), n, n) -field.setTurbulenceProperties(lMin, lMax, alpha) -field.initialize() -field.normalize(Brms / field.getRMSFieldStrength()) -Lc = field.getCorrelationLength() +field = MagneticFieldGrid(origin, n, spacing) +initTurbulence(field, Brms, lMin, lMax, alpha) + +Lc = turbulentCorrelationLength(lMin, lMax, alpha) ### copy field grid to array(s) Bx, By, Bz = zeros((3, n, n, n)) diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index 52389dee3..a955621de 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -1,6 +1,6 @@ #include "mpc/magneticField/UniformMagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" -#include "mpc/magneticField/TurbulentMagneticFieldGrid.h" +#include "mpc/magneticField/MagneticFieldGridTools.h" #include "mpc/magneticField/TurbulentMagneticField.h" #include "mpc/Units.h" #include "mpc/Common.h" @@ -33,57 +33,63 @@ TEST(testMagneticFieldGrid, PeriodicClamp) { TEST(testMagneticFieldGrid, SimpleTest) { // Test construction and parameters - MagneticFieldGrid B(Vector3d(1., 2., 3.), 10, 4); - EXPECT_TRUE(Vector3d(1., 2., 3.) == B.getGridOrigin()); - EXPECT_EQ(4, B.getGridSamples()); - EXPECT_DOUBLE_EQ(10, B.getGridSize()); - EXPECT_DOUBLE_EQ(2.5, B.getGridSpacing()); + MagneticFieldGrid B(Vector3d(1., 2., 3.), 4, 2.5); + EXPECT_TRUE(Vector3d(1., 2., 3.) == B.getOrigin()); + EXPECT_EQ(4, B.getNx()); + EXPECT_EQ(4, B.getNy()); + EXPECT_EQ(4, B.getNz()); + EXPECT_DOUBLE_EQ(2.5, B.getSpacing()); } TEST(testMagneticFieldGrid, Interpolation) { // Explicitly test trilinear interpolation - MagneticFieldGrid B(Vector3d(0.), 9, 3); - B.get(0, 0, 1) = Vector3f(1.7, 0., 0.); + double spacing = 2.793; + MagneticFieldGrid B(Vector3d(0.), 3, spacing); - double spacing = B.getGridSpacing(); - EXPECT_FLOAT_EQ(1.7, B.getField(Vector3d(0, 0, 1) * spacing).x); + B.get(0, 0, 1) = Vector3f(1.7, 0., 0.); // set one value - EXPECT_FLOAT_EQ(1.7 * 0.9, B.getField(Vector3d(0, 0, 0.9) * spacing).x); - EXPECT_FLOAT_EQ(1.7 * 0.9, B.getField(Vector3d(0, 0, 1.1) * spacing).x); + Vector3d b = B.getField(Vector3d(0, 0, 1) * spacing); + EXPECT_FLOAT_EQ(1.7, b.x); - EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.85, - B.getField(Vector3d(0, 0.15, 0.9) * spacing).x); - EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.15, - B.getField(Vector3d(0, 2.15, 0.9) * spacing).x); + b = B.getField(Vector3d(0, 0, 0.9) * spacing); + EXPECT_FLOAT_EQ(1.7 * 0.9, b.x); + + b = B.getField(Vector3d(0, 0, 1.1) * spacing); + EXPECT_FLOAT_EQ(1.7 * 0.9, b.x); + + b = B.getField(Vector3d(0, 0.15, 0.9) * spacing); + EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.85, b.x); + + b = B.getField(Vector3d(0, 2.15, 0.9) * spacing); + EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.15, b.x); } -TEST(testMagneticFieldGrid, Normalization) { - // If the field is uniform, (interpolated) field values should be the same everywhere - MagneticFieldGrid B(Vector3d(0.), 3, 3); +TEST(testMagneticFieldGrid, Scale) { + // Test scaling a field + MagneticFieldGrid B(Vector3d(0.), 3, 1); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) B.get(ix, iy, iz) = Vector3f(1, 0, 0); - EXPECT_FLOAT_EQ(1, B.getField(Vector3d(0.7, 0, 0.1)).x); - EXPECT_FLOAT_EQ(1, B.getField(Vector3d(0, 1.3, 0.9)).x); - - B.normalize(2); - - EXPECT_FLOAT_EQ(2, B.getField(Vector3d(0.7, 0, 0.1)).x); - EXPECT_FLOAT_EQ(2, B.getField(Vector3d(0, 1.3, 0.9)).x); + scale(&B, 5); + for (int ix = 0; ix < 3; ix++) + for (int iy = 0; iy < 3; iy++) + for (int iz = 0; iz < 3; iz++) + EXPECT_FLOAT_EQ(5, B.getField(Vector3d(0.7, 0, 0.1)).x); } TEST(testMagneticFieldGrid, Periodicity) { // Test for periodic boundaries: B(x+a*n) = B(x) - MagneticFieldGrid B(Vector3d(0.), 9, 3); - + size_t n = 3; + double spacing = 3; + double size = n * spacing; + MagneticFieldGrid B(Vector3d(0.), n, spacing); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) B.get(ix, iy, iz) = Vector3f(iz + ix, iy * iz, ix - iz * iy); - double size = B.getGridSize(); Vector3d pos(1.2, 2.3, 0.7); Vector3f b = B.getField(pos); Vector3f b2 = B.getField(pos + Vector3d(1, 0, 0) * size); @@ -104,15 +110,15 @@ TEST(testMagneticFieldGrid, Periodicity) { TEST(testMagneticFieldGrid, DumpLoad) { // Dump and load a field grid - MagneticFieldGrid B1(Vector3d(0.), 3, 3); + MagneticFieldGrid B1(Vector3d(0.), 3, 1); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) B1.get(ix, iy, iz) = Vector3f(1, 2, 3); - B1.dump(getDataPath("../test/testDump.raw")); + dump(&B1, getDataPath("../test/testDump.raw")); - MagneticFieldGrid B2(Vector3d(0.), 3, 3); - B2.load(getDataPath("../test/testDump.raw")); + MagneticFieldGrid B2(Vector3d(0.), 3, 1); + load(&B2, getDataPath("../test/testDump.raw")); for (int ix = 0; ix < 3; ix++) { for (int iy = 0; iy < 3; iy++) { @@ -129,15 +135,15 @@ TEST(testMagneticFieldGrid, DumpLoad) { TEST(testMagneticFieldGrid, DumpLoadTxt) { // Dump and load a field grid - MagneticFieldGrid B1(Vector3d(0.), 3, 3); + MagneticFieldGrid B1(Vector3d(0.), 3, 1); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) B1.get(ix, iy, iz) = Vector3f(ix, iy, iz) * nG; - B1.dumpTxt(getDataPath("../test/testDump.txt"), 1e4); + dumpTxt(&B1, getDataPath("../test/testDump.txt"), 1e4); - MagneticFieldGrid B2(Vector3d(0.), 3, 3); - B2.loadTxt(getDataPath("../test/testDump.txt"), 1e-4); + MagneticFieldGrid B2(Vector3d(0.), 3, 1); + loadTxt(&B2, getDataPath("../test/testDump.txt"), 1e-4); for (int ix = 0; ix < 3; ix++) { for (int iy = 0; iy < 3; iy++) { @@ -161,75 +167,72 @@ TEST(testMagneticFieldGrid, Speed) { B.get(ix, iy, iz) = Vector3f(1, 2, 3); Vector3d b; - Vector3d pos(1.,1.,1.); - for (int i = 0; i < 1000000; i++) - b = B.getField(pos); + for (int i = 0; i < 100000; i++) + b = B.getField(Vector3d(i)); } -TEST(testTurbulentMagneticFieldGrid, Bmean) { +TEST(testMagneticFieldGrid, Turbulence_bmean_brms) { // Test for zero mean: = 0 size_t n = 64; double spacing = 10 * Mpc / n; - TurbulentMagneticFieldGrid B(Vector3d(0, 0, 0), 10 * Mpc, n, 2 * spacing, - 8 * spacing, -11. / 3., 1.); - - Vector3d b(0, 0, 0); - for (int ix = 0; ix < n; ix++) - for (int iy = 0; iy < n; iy++) - for (int iz = 0; iz < n; iz++) - b += B.getField(Vector3d(ix, iy, iz) * spacing); - b /= n * n * n; - - double precision = 1e-9; - EXPECT_NEAR(b.x, 0, precision); - EXPECT_NEAR(b.y, 0, precision); - EXPECT_NEAR(b.z, 0, precision); + double Brms = 1; + double lMin = 2 * spacing; + double lMax = 8 * spacing; + MagneticFieldGrid B(Vector3d(0, 0, 0), n, spacing); + initTurbulence(&B, Brms, lMin, lMax); + + double precision = 1e-7; + Vector3f bMean = meanFieldStrength(&B); + EXPECT_NEAR(0, bMean.x, precision); + EXPECT_NEAR(0, bMean.y, precision); + EXPECT_NEAR(0, bMean.z, precision); + EXPECT_NEAR(1, rmsFieldStrength(&B), precision); } -TEST(testTurbulentMagneticFieldGrid, Brms) { - // Test for correct RMS strength: = Brms^2 - size_t n = 100; - TurbulentMagneticFieldGrid B(Vector3d(0, 0, 0), 10 * Mpc, n); - double spacing = B.getGridSpacing(); - B.setTurbulenceProperties(2 * spacing, 8 * spacing, -11. / 3.); - B.initialize(); - B.normalize(1. / B.getRMSFieldStrength()); - double brms = 0; - for (int ix = 0; ix < n; ix++) - for (int iy = 0; iy < n; iy++) - for (int iz = 0; iz < n; iz++) - brms += B.getField(Vector3d(ix, iy, iz) * spacing).getMag2(); - brms = sqrt(brms / n / n / n); +TEST(testMagneticFieldGrid, Turbulence_seed) { + // Test if seeding produces 2 identical fields + size_t n = 64; + double spacing = 1 * Mpc; + double Brms = 1; + double lMin = 2 * spacing; + double lMax = 8 * spacing; + double index = -11. / 3.; + int seed = 753; - double precision = 1e-7; - EXPECT_NEAR(brms, 1, precision); + MagneticFieldGrid B1(Vector3d(0, 0, 0), n, spacing); + initTurbulence(&B1, Brms, lMin, lMax, index, seed); + + MagneticFieldGrid B2(Vector3d(0, 0, 0), n, spacing); + initTurbulence(&B2, Brms, lMin, lMax, index, seed); + + Vector3d pos(22 * Mpc); + EXPECT_FLOAT_EQ(B1.getField(pos).x, B2.getField(pos).x); } -TEST(testTurbulentMagneticFieldGrid, Exceptions) { +TEST(testMagneticFieldGrid, turbulence_Exceptions) { // Test exceptions - TurbulentMagneticFieldGrid B(Vector3d(0, 0, 0), 10, 64); - double spacing = B.getGridSpacing(); + size_t n = 64; + double spacing = 10 * Mpc / n; + double brms = 1; + MagneticFieldGrid B(Vector3d(0, 0, 0), n, spacing); // should be fine - B.setTurbulenceProperties(2 * spacing, 8 * spacing, -11. / 3.); - EXPECT_NO_THROW(B.initialize()); - + EXPECT_NO_THROW(initTurbulence(&B, brms, 2 * spacing, 8 * spacing)); // lMin too small - B.setTurbulenceProperties(1.5 * spacing, 8 * spacing, -11. / 3.); - EXPECT_THROW(B.initialize(), std::runtime_error); - + EXPECT_THROW(initTurbulence(&B, brms, 1.5 * spacing, 8 * spacing), + std::runtime_error); // lMin > lMax - B.setTurbulenceProperties(8.1 * spacing, 8 * spacing, -11. / 3.); - EXPECT_THROW(B.initialize(), std::runtime_error); - + EXPECT_THROW(initTurbulence(&B, brms, 8.1 * spacing, 8 * spacing), + std::runtime_error); // lMax too large - B.setTurbulenceProperties(2 * spacing, 33 * spacing, -11. / 3.); - EXPECT_THROW(B.initialize(), std::runtime_error); + EXPECT_THROW(initTurbulence(&B, brms, 2 * spacing, 33 * spacing), + std::runtime_error); } TEST(testTurbulentMagneticField, SimpleTest) { TurbulentMagneticField B; - B.setTurbulenceProperties(1 * nG, 10 * parsec, 200 * parsec, -11./3., 1000); + B.setTurbulenceProperties(1 * nG, 10 * parsec, 200 * parsec, -11. / 3., + 1000); B.initialize(); Vector3d b1 = B.getField(Vector3d(0.)); Vector3d b2 = B.getField(Vector3d(0.)); @@ -249,7 +252,9 @@ TEST(testTurbulentMagneticField, Brms) { for (int ix = 0; ix < n; ix++) { for (int iy = 0; iy < n; iy++) { for (int iz = 0; iz < n; iz++) { - b = B.getField(Vector3d(random.rand(), random.rand(), random.rand()) * 100000); + b = B.getField( + Vector3d(random.rand(), random.rand(), random.rand()) + * 100000); Bmean += b; sumB2 = b.getMag2(); } diff --git a/test/testSPHField.cpp b/test/testSPHField.cpp index 2231e90ff..c44389cd9 100644 --- a/test/testSPHField.cpp +++ b/test/testSPHField.cpp @@ -1,58 +1,94 @@ -#include "mpc/magneticField/SPHMagneticField.h" -#include "mpc/magneticField/SPHTurbulentMagneticFieldGrid.h" -#include "mpc/Units.h" -#include "mpc/Common.h" - -#include "gtest/gtest.h" - -namespace mpc { - -//TEST(testSPHMagneticField, simpleTest) { -// // Tests if a direct SPH field can be constructed and prints RMS and mean field strength -// Vector3d origin(80 * Mpc); -// double size = 40 * Mpc; +//#include "mpc/magneticField/SPHMagneticField.h" +//#include "mpc/magneticField/SPHTurbulentMagneticFieldGrid.h" +//#include "mpc/Units.h" +//#include "mpc/Common.h" // -// // gadget::DirectField may throw if queried for magnetic fields on the borders -// Vector3d safeOrigin = origin - Vector3d(1 * kpc); -// double safeSize = size + 2 * kpc; +//#include "gtest/gtest.h" // -// SPHMagneticField B(safeOrigin, safeSize, 20, -// getDataPath("SPH/mhd_z.db").c_str()); +//namespace mpc { // -// int n = 64; -// double spacing = 40 * Mpc / (n - 1); -// double brms = 0; -// Vector3d bmean(0, 0, 0); -// for (int ix = 0; ix < n; ix++) -// for (int iy = 0; iy < n; iy++) -// for (int iz = 0; iz < n; iz++) { -// Vector3d b = B.getField( -// origin + Vector3d(ix, iy, iz) * spacing); -// brms += b.getMag2(); -// bmean += b; -// } +////TEST(testSPHMagneticField, simpleTest) { +//// // Tests if a direct SPH field can be constructed and prints RMS and mean field strength +//// Vector3d origin(80 * Mpc); +//// double size = 40 * Mpc; +//// +//// // gadget::DirectField may throw if queried for magnetic fields on the borders +//// Vector3d safeOrigin = origin - Vector3d(1 * kpc); +//// double safeSize = size + 2 * kpc; +//// +//// SPHMagneticField B(safeOrigin, safeSize, 20, +//// getDataPath("SPH/mhd_z.db").c_str()); +//// +//// int n = 64; +//// double spacing = 40 * Mpc / (n - 1); +//// double brms = 0; +//// Vector3d bmean(0, 0, 0); +//// for (int ix = 0; ix < n; ix++) +//// for (int iy = 0; iy < n; iy++) +//// for (int iz = 0; iz < n; iz++) { +//// Vector3d b = B.getField( +//// origin + Vector3d(ix, iy, iz) * spacing); +//// brms += b.getMag2(); +//// bmean += b; +//// } +//// +//// brms = sqrt(brms / n / n / n); +//// bmean /= n * n * n; +//// +//// std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; +//// std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; +////} +//// +////TEST(testSPHMagneticFieldGrid, simpleTest) { +//// // Tests if a sampled SPH field can be constructed and prints RMS and mean field strength +//// Vector3d origin(80 * Mpc); +//// size_t n = 64; +//// double size = 40 * Mpc; +//// double spacing = size / (n - 1); +//// +//// // gadget::SampledField may throw if queried for magnetic fields on the borders +//// Vector3d safeOrigin = origin - Vector3d(1 * kpc); +//// double safeSize = size + 2 * kpc; +//// +//// SPHMagneticFieldGrid B(safeOrigin, safeSize, n, +//// getDataPath("SPH/mhd_z.db").c_str()); +//// +//// double brms = 0; +//// Vector3d bmean(0, 0, 0); +//// for (int ix = 0; ix < n; ix++) +//// for (int iy = 0; iy < n; iy++) +//// for (int iz = 0; iz < n; iz++) { +//// Vector3d b = B.getField( +//// origin + Vector3d(ix, iy, iz) * spacing); +//// brms += b.getMag2(); +//// bmean += b; +//// } +//// +//// brms = sqrt(brms / n / n / n); +//// bmean /= n * n * n; +//// +//// std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; +//// std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; +////} // -// brms = sqrt(brms / n / n / n); -// bmean /= n * n * n; -// -// std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; -// std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; -//} -// -//TEST(testSPHMagneticFieldGrid, simpleTest) { +//TEST(testSPHTurbulentMagneticField, simpleTest) { // // Tests if a sampled SPH field can be constructed and prints RMS and mean field strength -// Vector3d origin(80 * Mpc); +// Vector3d origin(100 * Mpc); // size_t n = 64; // double size = 40 * Mpc; -// double spacing = size / (n - 1); +// double spacing = size / n; // -// // gadget::SampledField may throw if queried for magnetic fields on the borders -// Vector3d safeOrigin = origin - Vector3d(1 * kpc); -// double safeSize = size + 2 * kpc; +// SPHTurbulentMagneticFieldGrid B(origin, size, n); +// B.setTurbulenceProperties(2 * spacing, 8 * spacing, -11. / 3); +// B.initialize(); +// B.scale(1 / B.getRMSFieldStrength()); // -// SPHMagneticFieldGrid B(safeOrigin, safeSize, n, -// getDataPath("SPH/mhd_z.db").c_str()); +// std::cout << "modulating" << std::endl; +// B.setDensityField(getDataPath("SPH/mhd_z.db").c_str(), Vector3d(99 * Mpc), +// 42 * Mpc, 20); +// B.setModulation(getDataPath("SPH/miniati-profile.txt")); // +// std::cout << "sampling" << std::endl; // double brms = 0; // Vector3d bmean(0, 0, 0); // for (int ix = 0; ix < n; ix++) @@ -70,46 +106,10 @@ namespace mpc { // std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; // std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; //} - -TEST(testSPHTurbulentMagneticField, simpleTest) { - // Tests if a sampled SPH field can be constructed and prints RMS and mean field strength - Vector3d origin(100 * Mpc); - size_t n = 64; - double size = 40 * Mpc; - double spacing = size / n; - - SPHTurbulentMagneticFieldGrid B(origin, size, n); - B.setTurbulenceProperties(2 * spacing, 8 * spacing, -11. / 3); - B.initialize(); - B.normalize(1 / B.getRMSFieldStrength()); - - std::cout << "modulating" << std::endl; - B.setDensityField(getDataPath("SPH/mhd_z.db").c_str(), Vector3d(99 * Mpc), - 42 * Mpc, 20); - B.setModulation(getDataPath("SPH/miniati-profile.txt")); - - std::cout << "sampling" << std::endl; - double brms = 0; - Vector3d bmean(0, 0, 0); - for (int ix = 0; ix < n; ix++) - for (int iy = 0; iy < n; iy++) - for (int iz = 0; iz < n; iz++) { - Vector3d b = B.getField( - origin + Vector3d(ix, iy, iz) * spacing); - brms += b.getMag2(); - bmean += b; - } - - brms = sqrt(brms / n / n / n); - bmean /= n * n * n; - - std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; - std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; -} - -int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} - -} // namespace mpc +// +//int main(int argc, char **argv) { +// ::testing::InitGoogleTest(&argc, argv); +// return RUN_ALL_TESTS(); +//} +// +//} // namespace mpc From 77e69f4c7dcb30585d776304e057be7f5ee24066 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 24 Jul 2012 14:11:40 +0200 Subject: [PATCH 0152/1298] XML loading for 3d mode --- include/mpc/ExplicitRungeKutta.h | 2 + include/mpc/XmlExecute.h | 27 +- src/XmlExecute.cpp | 408 +++++++++++++++++++++++-------- 3 files changed, 320 insertions(+), 117 deletions(-) diff --git a/include/mpc/ExplicitRungeKutta.h b/include/mpc/ExplicitRungeKutta.h index 77f6b019e..a841603a0 100644 --- a/include/mpc/ExplicitRungeKutta.h +++ b/include/mpc/ExplicitRungeKutta.h @@ -90,8 +90,10 @@ const double cash_karp_a[] = { 0., 0., 0., 0., 0., 0., 1. / 5., 0., 0., 0., 0., const double cash_karp_b[] = { 37. / 378., 0, 250. / 621., 125. / 594., 0., 512. / 1771. }; + const double cash_karp_bs[] = { 2825. / 27648., 0., 18575. / 48384., 13525. / 55296., 277. / 14336., 1. / 4. }; + const double cash_karp_c[] = { 0., 1. / 5., 3. / 10., 3. / 5., 1., 7. / 8. }; template diff --git a/include/mpc/XmlExecute.h b/include/mpc/XmlExecute.h index 676d9a2d3..51f8f1c16 100644 --- a/include/mpc/XmlExecute.h +++ b/include/mpc/XmlExecute.h @@ -16,19 +16,28 @@ namespace mpc { class XmlExecute { ModuleList modules; ref_ptr magnetic_field; - std::vector sources; + Source source; - void loadCashKarp(pugi::xml_node &); - void loadLssGrid(pugi::xml_node &); - void loadSophia(pugi::xml_node &); - void loadSpheresAroundObserver(pugi::xml_node &); - void loadDiscreteSources(pugi::xml_node &); - void loadFullTrajectoryOutput(pugi::xml_node &); + void loadUniformMagneticField(pugi::xml_node &node); + void loadGridMagneticField(pugi::xml_node &node); + void loadDeflectionCK(pugi::xml_node &node); + + void loadDiscreteSources(pugi::xml_node &node); + + void loadSophia(pugi::xml_node &node); + + void loadSpheresAroundObserver(pugi::xml_node &node); + void loadSpheresAroundSource(pugi::xml_node &node); + + void loadOutput(pugi::xml_node &node); + + bool is1D; size_t trajectories; - double minEnergyEeV; - double maxTimeMpc; size_t randomSeed; + double Emin; + Vector3d origin; + Vector3d size; public: bool load(const std::string &filename); diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index a2eff8aac..e6cb18be4 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -1,10 +1,15 @@ #include "mpc/XmlExecute.h" #include "mpc/magneticField/UniformMagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" +#include "mpc/magneticField/MagneticFieldGridTools.h" #include "mpc/module/DeflectionCK.h" #include "mpc/module/SimplePropagation.h" #include "mpc/module/Output.h" #include "mpc/module/BreakCondition.h" +#include "mpc/module/ElectronPairProduction.h" +#include "mpc/module/PhotoPionProduction.h" +#include "mpc/module/PhotoDisintegration.h" +#include "mpc/module/NuclearDecay.h" #include "mpc/ModuleList.h" #include "pugixml.hpp" @@ -23,145 +28,337 @@ bool XmlExecute::load(const string &filename) { if (!result) { cout << "Error description: " << result.description() << "\n"; cout << "Error offset: " << result.offset << "\n"; - return false; } xml_node root = doc.child("CRPropa"); + xml_node node; + std::string type; trajectories = root.child("TrajNumber").attribute("value").as_int(); cout << "Trajectories: " << trajectories << endl; + double maxTime = root.child("MaxTime_Mpc").attribute("value").as_double() * Mpc; + cout << "Maximum Time: " << maxTime / Mpc << " Mpc" << endl; + + Emin = root.child("MinEnergy_EeV").attribute("value").as_double() * EeV; + cout << "Minimum Energy: " << Emin / EeV << " EeV" << endl; + randomSeed = root.child("RandomSeed").attribute("value").as_int(); cout << "RandomSeed: " << randomSeed << endl; - // setup MagneticField - xml_node field = root.child("MagneticField"); - if (field) { - string type = field.attribute("type").as_string(); - cout << "MagenticField: " << type << endl; - if (type == "LSS-Grid") { - loadLssGrid(field); - } else { - cout << " --> unknown, set zero field" << endl; - magnetic_field = new UniformMagneticField(Vector3f(0, 0, 0)); - } + // environment + node = root.child("Environment"); + if (!node) + throw runtime_error("Environment not specified"); + type = node.attribute("type").as_string(); + cout << "Environment: " << type << endl; + if (type == "One Dimension") + throw runtime_error("One Dimension not supported"); + else if (type == "LSS") { + // will be overwritten if (re)defined by magnetic field + origin.x = node.child("Xmin_Mpc").attribute("value").as_double() * Mpc; + origin.y = node.child("Ymin_Mpc").attribute("value").as_double() * Mpc; + origin.z = node.child("Zmin_Mpc").attribute("value").as_double() * Mpc; + size.x = node.child("Xmax_Mpc").attribute("value").as_double() * Mpc; + size.y = node.child("Ymax_Mpc").attribute("value").as_double() * Mpc; + size.z = node.child("Zmax_Mpc").attribute("value").as_double() * Mpc; + size -= origin; + } else + throw runtime_error("Unknown environment"); + + // magnetic field + node = root.child("MagneticField"); + if (!node) + throw runtime_error("Magnetic field not specified"); + type = node.attribute("type").as_string(); + cout << "MagenticField: " << type << endl; + if (type == "Uniform") + loadUniformMagneticField(node); + else if ((type == "LSS") or (type == "Kolmogoroff")) + loadGridMagneticField(node); + else { + cout << " --> unknown, set zero field" << endl; + magnetic_field = new UniformMagneticField(Vector3d(0, 0, 0)); } - // setup Integrator - xml_node integrator = root.child("Integrator"); - if (integrator) { - string type = integrator.attribute("type").as_string(); - cout << "Integrator: " << type << endl; - if (type == "Cash-Karp RK") - loadCashKarp(integrator); - else - cout << " -> unknown" << endl; - } + // propagator + node = root.child("Integrator"); + if (!node) + throw runtime_error("Integrator not specified"); + type = node.attribute("type").as_string(); + cout << "Integrator: " << type << endl; + if (type == "Cash-Karp RK") + loadDeflectionCK(node); + else + throw runtime_error("Unknown integrator"); + + // interactions + node = root.child("Interactions"); + if (!node) + throw runtime_error("Interactions not specified"); + type = node.attribute("type").as_string(); + cout << "Interactions: " << type << endl; + if (type == "None") + ; + else if (type == "F77-proton") + cout << " -> not supported" << endl; + else if (type == "Sophia") + loadSophia(node); + else if (type == "Photon") + cout << " -> not supported" << endl; + else + cout << " -> unknown" << endl; + + // minimum energy + modules.add(new MinimumEnergy(Emin)); + + // maximum trajectory length + modules.add(new MaximumTrajectoryLength(maxTime)); + + // periodic boundaries + cout << "Periodic boundaries" << endl; + cout << " - Lower bounds: " << origin / Mpc << " Mpc" << endl; + cout << " - Upper bounds: " << (origin + size) / Mpc << " Mpc" << endl; + modules.add(new PeriodicBox(origin, size)); - // setup Interactions - xml_node interactions = root.child("Interactions"); - if (interactions) { - string type = interactions.attribute("type").as_string(); - cout << "Interactions: " << type << endl; - if (type == "Sophia") - loadSophia(interactions); - else - cout << " -> unknown" << endl; - } + // sources + node = root.child("Sources"); + if (!node) + throw runtime_error("Source(s) not specified"); + type = node.attribute("type").as_string(); + cout << "Sources: " << type << endl; + if (type == "Discrete") + loadDiscreteSources(node); + else if (type == "Continuous") + throw runtime_error("Continuous sources not implemented"); + else + throw runtime_error("Unknown source"); // observers - xml_node observers = root.child("Observers"); - if (observers) { - string type = observers.attribute("type").as_string(); + node = root.child("Observers"); + if (!node) + cout << "Observer(s) not specified" << endl; + else { + string type = node.attribute("type").as_string(); cout << "Observers: " << type << endl; if (type == "Spheres around Observers") - loadSpheresAroundObserver(observers); + loadSpheresAroundObserver(node); + else if (type == "Spheres around Source") + loadSpheresAroundSource(node); else - cout << " -> unknown" << endl; + cout << " -> unknown observer" << endl; } // output - xml_node output = root.child("Output"); - if (output) { - string type = output.attribute("type").as_string(); - cout << "Output: " << type << endl; - if (type == "Full Trajectories") - loadFullTrajectoryOutput(output); - else - cout << " -> unknown" << endl; - } - - // sources - xml_node sources = root.child("Sources"); - if (sources) { - string type = sources.attribute("type").as_string(); - cout << "Sources: " << type << endl; - if (type == "Discrete") - loadDiscreteSources(sources); - else - cout << " -> unknown" << endl; - } - - minEnergyEeV = root.child("MinEnergy_EeV").attribute("value").as_double() - * EeV; - cout << "Minimum Energy: " << minEnergyEeV / EeV << " EeV" << endl; - modules.add(new MinimumEnergy(minEnergyEeV)); - - maxTimeMpc = root.child("MaxTime_Mpc").attribute("value").as_double() * Mpc; - cout << "Maximum Time: " << maxTimeMpc / Mpc << " Mpc" << endl; - modules.add(new MaximumTrajectoryLength(maxTimeMpc)); + node = root.child("Output"); + if (!node) + cout << "No output" << endl; + else + loadOutput(node); return true; } -void XmlExecute::loadCashKarp(xml_node &node) { +void XmlExecute::loadDeflectionCK(xml_node &node) { double epsilon = node.child("Epsilon").attribute("value").as_double(); cout << " - Epsilon: " << epsilon << endl; - double minstep = node.child("MinStep_Mpc").attribute("value").as_double() * Mpc; cout << " - Minimum Step: " << minstep / Mpc << " Mpc " << endl; - - ref_ptr deflection = new DeflectionCK(magnetic_field, epsilon, - minstep); - modules.add(deflection); + modules.add(new DeflectionCK(magnetic_field, epsilon, minstep)); } -void XmlExecute::loadLssGrid(xml_node &node) { - int nx = node.child("Nx").attribute("value").as_int(); - int ny = node.child("Ny").attribute("value").as_int(); - int nz = node.child("Nz").attribute("value").as_int(); - if (nx != ny || nx != nz) - throw runtime_error("Invalid grid size!"); - cout << " - Samples: " << nx << endl; - - double step = node.child("Step_Mpc").attribute("value").as_double() * Mpc; - double size = nx * step; - cout << " - Size: " << size / Mpc << " Mpc " << endl; +void XmlExecute::loadUniformMagneticField(xml_node &node) { + Vector3d bField; + bField.x = node.child("Bx_nG").attribute("value").as_int() * nG; + bField.y = node.child("By_nG").attribute("value").as_int() * nG; + bField.z = node.child("Bz_nG").attribute("value").as_int() * nG; + cout << " - Bx, By, Bz: " << bField / nG << " nG" << endl; + magnetic_field = new UniformMagneticField(bField); +} +void XmlExecute::loadGridMagneticField(xml_node &node) { xml_node origin_node = node.child("Origin"); - Vector3d origin; - origin.x = origin_node.child("X_Mpc").attribute("value").as_double(); - origin.y = origin_node.child("Y_Mpc").attribute("value").as_double(); - origin.z = origin_node.child("Z_Mpc").attribute("value").as_double(); - cout << " - Origin: " << origin << endl; + origin.x = origin_node.child("X_Mpc").attribute("value").as_double() * Mpc; + origin.y = origin_node.child("Y_Mpc").attribute("value").as_double() * Mpc; + origin.z = origin_node.child("Z_Mpc").attribute("value").as_double() * Mpc; + cout << " - Origin: " << origin / Mpc << endl; + + int Nx = node.child("Nx").attribute("value").as_int(); + int Ny = node.child("Ny").attribute("value").as_int(); + int Nz = node.child("Nz").attribute("value").as_int(); + cout << " - Samples: " << Nx << " * " << Ny << " * " << Nz << endl; + + double spacing = node.child("Step_Mpc").attribute("value").as_double() * Mpc; + cout << " - Spacing: " << spacing / Mpc << " Mpc " << endl; + + size.x = Nx * spacing; + size.y = Ny * spacing; + size.z = Nz * spacing; + + MagneticFieldGrid *Bfield = new MagneticFieldGrid(origin, Nx, Ny, Nz, spacing); + + std::string type = node.attribute("type").as_string(); + if (type == "LSS-Grid") { + string filetype = node.child("File").attribute("type").as_string(); + cout << " - File type: " << filetype << endl; + if (filetype != "ASCII") + throw runtime_error("Only ASCII files supported"); + + string fname = node.child_value("File"); + cout << " - Loading file (values in [G]): " << fname << endl; + loadTxt(Bfield, fname, gauss); + } else { + double brms = node.child("RMS_muG").attribute("value").as_double() * 1e-6 * gauss; + cout << " - Brms : " << brms / nG << " nG" << endl; + + double kMin = node.child("Kmin").attribute("value").as_double(); + double kMax = node.child("Kmax").attribute("value").as_double(); + double lMin = spacing / kMax; + double lMax = spacing / kMin; + cout << " - Turbulent range: " << lMin / Mpc << " - " << lMax / Mpc << " Mpc" << endl; + + double alpha = node.child("SpectralIndex").attribute("value").as_double(); + cout << " - Turbulence spectral index: " << alpha << endl; + cout << " - Random seed: " << randomSeed << endl; + + initTurbulence(Bfield, brms, lMin, lMax, alpha, randomSeed); + } - magnetic_field = new MagneticFieldGrid(origin, size, nx); + magnetic_field = Bfield; } -void XmlExecute::loadSophia(xml_node &) { +void XmlExecute::loadSophia(xml_node &node) { + if (node.child("NoRedshift")) + cout << " - No redshift" << endl; +// else +// redshift + + if (node.child("NoPairProd")) + cout << " - No pair production" << endl; + else + modules.add(new ElectronPairProduction(CMB_IRB)); + + if (node.child("NoPionProd")) + cout << " - No pion production" << endl; + else { + modules.add(new ElectronPairProduction(CMB)); + if (!node.child("NoIRPionProd")) + modules.add(new ElectronPairProduction(IRB)); + } + if (node.child("NoPhotoDisintegration")) + cout << " - No photo disintegration" << endl; + else { + modules.add(new PhotoDisintegration(CMB)); + modules.add(new PhotoDisintegration(IRB)); + } + + if (node.child("NoDecay")) + cout << " - No decay" << endl; + else + modules.add(new NuclearDecay); } -void XmlExecute::loadSpheresAroundObserver(xml_node &) { +void XmlExecute::loadSpheresAroundObserver(xml_node &node) { + double r = node.child("Radius_Mpc").attribute("value").as_double() * Mpc; + cout << " - Radius: " << r / Mpc << " Mpc" << endl; + + int nObs = 0; + for (xml_node n = node.child("SphereObserver"); n; n = n.next_sibling("SphereObserver")) { + nObs += 1; + Vector3d pos; + pos.x = n.child("CoordX_Mpc").attribute("value").as_double() * Mpc; + pos.y = n.child("CoordY_Mpc").attribute("value").as_double() * Mpc; + pos.z = n.child("CoordZ_Mpc").attribute("value").as_double() * Mpc; + cout << " - Postion: " << pos / Mpc << " Mpc" << endl; + modules.add(new SmallObserverSphere(pos, r)); + } + if (nObs > 1) + cout << " -> Warning for multiple observers: propagation will stop after first detection." << endl; +} +void XmlExecute::loadSpheresAroundSource(pugi::xml_node &node) { + int nObs = 0; + for (xml_node n = node.child("Sphere"); n; n = n.next_sibling("Sphere")) { + nObs += 1; + Vector3d pos; + pos.x = n.child("CoordX_Mpc").attribute("value").as_double() * Mpc; + pos.y = n.child("CoordY_Mpc").attribute("value").as_double() * Mpc; + pos.z = n.child("CoordZ_Mpc").attribute("value").as_double() * Mpc; + double r = n.child("Radius_Mpc").attribute("value").as_double() * Mpc; + cout << " - Postion: " << pos / Mpc << " Mpc" << endl; + cout << " - Radius: " << r / Mpc << " Mpc" << endl; + SphericalBoundary *sphere = new SphericalBoundary(pos, r, "Detected"); + modules.add(sphere); + } + if (nObs > 1) + cout << " -> Warning for multiple observers: propagation will stop after first detection." << endl; } -void XmlExecute::loadDiscreteSources(xml_node &) { +void XmlExecute::loadDiscreteSources(xml_node &node) { + // source positions + SourceMultiplePositions *positions = new SourceMultiplePositions(); + for (xml_node n = node.child("PointSource"); n; n = n.next_sibling("PointSource")) { + Vector3d pos; + pos.x = n.child("CoordX_Mpc").attribute("value").as_double() * Mpc; + pos.y = n.child("CoordY_Mpc").attribute("value").as_double() * Mpc; + pos.z = n.child("CoordZ_Mpc").attribute("value").as_double() * Mpc; + cout << " - Position " << pos / Mpc << " Mpc" << endl; + positions->add(pos); + } + source.addProperty(positions); + + // source spectrum + xml_node spec = node.child("Spectrum"); + string spectrumType = spec.attribute("type").as_string(); + cout << " - Spectrum: " << spectrumType << endl; + + if (spectrumType == "Monochromatic") { + double E = spec.child("Energy_EeV").attribute("value").as_double() * EeV; + source.addProperty(new SourceEnergy(E)); + cout << " - Energy: " << E / EeV << " EeV" << endl; + + // source composition + SourceNuclei *composition = new SourceNuclei; + xml_node p = node.child("Particles"); + for (xml_node n = p.child("Species"); n; n = n.next_sibling("Species")) { + int A = n.child("MassNumber").attribute("value").as_int(); + int Z = n.child("ChargeNumber").attribute("value").as_int(); + double ab = n.child("Abundance").attribute("value").as_double(); + composition->add(getNucleusId(A, Z), ab); + cout << " - Species: Z = " << Z << ", A = " << A << ", abundance = " << ab << endl; + } + source.addProperty(composition); + + } else if (spectrumType == "Power Law") { + double alpha = spec.child("Alpha").attribute("value").as_double(); + double Rmax = spec.child("Rigidity_EeV").attribute("value").as_double() * EeV; + cout << " - Minimum energy: " << Emin / EeV << " EeV" << endl; + cout << " - Maximum rigidity: " << Rmax / EeV << " EeV" << endl; + cout << " - Power law index: " << alpha << endl; + + // source composition + SourceComposition *composition = new SourceComposition(Emin, Rmax, alpha); + xml_node p = node.child("Particles"); + for (xml_node n = p.child("Species"); n; n = n.next_sibling("Species")) { + int A = n.attribute("MassNumber").as_int(); + int Z = n.attribute("ChargeNumber").as_int(); + double ab = n.attribute("Abundance").as_double(); + cout << " - Species: Z = " << Z << ", A = " << A << ", abundance = " << ab << endl; + composition->add(getNucleusId(A, Z), ab); + } + source.addProperty(composition); + } else { + throw runtime_error(" --> unknown source"); + } } -void XmlExecute::loadFullTrajectoryOutput(xml_node &node) { +void XmlExecute::loadOutput(xml_node &node) { + string type = node.attribute("type").as_string(); + cout << "Output: " << type << endl; + string filename = node.child("File").child_value(); cout << " - Filename: " << filename << endl; @@ -173,25 +370,20 @@ void XmlExecute::loadFullTrajectoryOutput(xml_node &node) { } } - ref_ptr output = new TrajectoryOutput(filename); - modules.add(output); + if (type == "Full Trajectories") + modules.add(new CRPropa2TrajectoryOutput(filename)); + else if (type == "Events") + modules.add(new CRPropa2EventOutput(filename)); + else if (type == "None") + return; + else + cout << " -> unknown output" << endl; } void XmlExecute::run() { //operator <<(cout, modules); - ParticleState initial; - initial.setId(getNucleusId(1, 1)); - initial.setEnergy(100 * EeV); - initial.setPosition(Vector3d(0, 0, 0)); - initial.setDirection(Vector3d(1, 0, 0)); - - for (size_t i = 0; i < trajectories; i++) { - ref_ptr candidate = new Candidate(initial); - if (i % (trajectories / 10) == 0) - std::cout << i << std::endl; - modules.run(candidate); - } - + modules.setShowProgress(true); + modules.run(&source, trajectories, true); } } // namespace mpc From b3ac912af4dab58bf33e9fb8cc84c5317ca11c87 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 24 Jul 2012 18:18:39 +0200 Subject: [PATCH 0153/1298] implement template class for periodic grids refactore MagneticFieldGrid --- CMakeLists.txt | 31 +- include/mpc/Vector3.h | 3 +- include/mpc/magneticField/MagneticFieldGrid.h | 105 ++++-- src/XmlExecute.cpp | 9 +- src/magneticField/MagneticFieldGrid.cpp | 329 ++++++++++++++---- test/testMagneticField.cpp | 101 +++--- 6 files changed, 407 insertions(+), 171 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 84bd1c5e0..02d5cada7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,7 +99,6 @@ add_library(mpc SHARED src/module/Output.cpp src/module/Tools.cpp src/magneticField/MagneticFieldGrid.cpp - src/magneticField/MagneticFieldGridTools.cpp src/magneticField/TurbulentMagneticField.cpp ${MPC_EXTRA_SOURCES} ) @@ -157,18 +156,18 @@ endif(ENABLETESTING) # ---------------------------------------------------------------------------- # Python # ---------------------------------------------------------------------------- -include(python/Python.cmake) -include_directories(${PYTHON_INCLUDE_PATH}) - -file(GLOB_RECURSE MPC_INCLUDES include/*.h) -set_source_files_properties( ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx PROPERTIES GENERATED true ) -add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx - COMMAND swig -c++ -python ${MPC_SWIG_DEFINES} -I${CMAKE_SOURCE_DIR}/include -o ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx -outdir ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/python/mpc.i - DEPENDS ${CMAKE_SOURCE_DIR}/python/mpc.i ${MPC_INCLUDES} ) -add_library(mpc-swig MODULE ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx) -#set_source_file_properties( ${CMAKE_SOURCE_DIR}/python/mpc.i PROPERTIES OBJECT_DEPENDS ${MPC_INCLUDES}) -set_target_properties(mpc-swig PROPERTIES PREFIX "") -set_target_properties(mpc-swig PROPERTIES OUTPUT_NAME "_mpc") -target_link_libraries(mpc-swig mpc ${PYTHON_LIBRARIES}) -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/mpc.py" DESTINATION ${PYTHON_SITE_PACKAGES}) -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_mpc.so" DESTINATION ${PYTHON_SITE_PACKAGES}) +#include(python/Python.cmake) +#include_directories(${PYTHON_INCLUDE_PATH}) + +#file(GLOB_RECURSE MPC_INCLUDES include/*.h) +#set_source_files_properties( ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx PROPERTIES GENERATED true ) +#add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx +# COMMAND swig -c++ -python ${MPC_SWIG_DEFINES} -I${CMAKE_SOURCE_DIR}/include -o ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx -outdir ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/python/mpc.i +# DEPENDS ${CMAKE_SOURCE_DIR}/python/mpc.i ${MPC_INCLUDES} ) +#add_library(mpc-swig MODULE ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx) +##set_source_file_properties( ${CMAKE_SOURCE_DIR}/python/mpc.i PROPERTIES OBJECT_DEPENDS ${MPC_INCLUDES}) +#set_target_properties(mpc-swig PROPERTIES PREFIX "") +#set_target_properties(mpc-swig PROPERTIES OUTPUT_NAME "_mpc") +#target_link_libraries(mpc-swig mpc ${PYTHON_LIBRARIES}) +#install(FILES "${CMAKE_CURRENT_BINARY_DIR}/mpc.py" DESTINATION ${PYTHON_SITE_PACKAGES}) +#install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_mpc.so" DESTINATION ${PYTHON_SITE_PACKAGES}) diff --git a/include/mpc/Vector3.h b/include/mpc/Vector3.h index 0aae554d4..57f0ee076 100644 --- a/include/mpc/Vector3.h +++ b/include/mpc/Vector3.h @@ -17,6 +17,7 @@ class Vector3 { x(0), y(0), z(0) { } + // Provides implicit conversion Vector3 <--> Vector3 template Vector3(const Vector3 &v) : x(v.x), y(v.y), z(v.z) { @@ -349,7 +350,7 @@ inline std::istream &operator >>(std::istream &in, Vector3 &v) { } template -Vector3 operator *(T f, const Vector3 &v) { +inline Vector3 operator *(T f, const Vector3 &v) { return Vector3(v.x * f, v.y * f, v.z * f); } diff --git a/include/mpc/magneticField/MagneticFieldGrid.h b/include/mpc/magneticField/MagneticFieldGrid.h index f5cff9a44..901953fa9 100644 --- a/include/mpc/magneticField/MagneticFieldGrid.h +++ b/include/mpc/magneticField/MagneticFieldGrid.h @@ -2,7 +2,7 @@ #define MPC_MAGNETICFIELDGRID_H_ #include "mpc/magneticField/MagneticField.h" -#include +#include "mpc/magneticField/PeriodicGrid.h" namespace mpc { @@ -10,42 +10,93 @@ namespace mpc { @class MagneticFieldGrid @brief Magnetic field on a periodic, cartesian grid with trilinear interpolation. - This class provides a three-dimensional magnetic field grid. - The grid spacing is constant and equal along all three axes. - Magnetic field values are calculated by trilinear interpolation of the surrounding 8 grid points. \n - The grid is periodically extended. - Thus the field at opposite borders is assumed identical and does not need to be sampled twice. - The grid sample positions are hence at 0, size / samples, ... size * (samples - 1) / samples and the grid spacing is size / samples. + This class provides a container for a VectorFieldGrid (PeriodicGrid of type Vector3f) to serve as a MagneticField. */ class MagneticFieldGrid: public MagneticField { - std::vector grid; /**< Magnetic field vectors */ - Vector3d origin; /**< Lower left front corner of the grid */ - size_t Nx, Ny, Nz; /**< Number of grid points per edge */ - double spacing; /**< Distance between two grid points (= size / samples) */ + VectorFieldGrid *grid; public: - MagneticFieldGrid(Vector3d origin, size_t N, double spacing); - MagneticFieldGrid(Vector3d origin, size_t Nx, size_t Ny, size_t Nz, - double spacing); - - void setOrigin(Vector3d origin); - void setGridSize(size_t Nx, size_t Ny, size_t Nz); - void setSpacing(double spacing); + MagneticFieldGrid(VectorFieldGrid *grid); + void setGrid(VectorFieldGrid *grid); + VectorFieldGrid *getGrid(); + Vector3d getField(const Vector3d &position) const; +}; - Vector3d getOrigin() const; - size_t getNx() const; - size_t getNy() const; - size_t getNz() const; - double getSpacing() const; +/** + @class MagneticFieldGrid + @brief Modulated magnetic field on a periodic grid. - Vector3f &get(size_t ix, size_t iy, size_t iz); - const Vector3f &get(size_t ix, size_t iy, size_t iz) const; + The class + */ +class ModulatedMagneticFieldGrid: public MagneticField { + VectorFieldGrid *grid; + ScalarFieldGrid *modGrid; +public: + ModulatedMagneticFieldGrid(VectorFieldGrid *grid, ScalarFieldGrid *modGrid); + void setGrid(VectorFieldGrid *grid); + void setModulationGrid(ScalarFieldGrid *modGrid); + VectorFieldGrid *getGrid(); + ScalarFieldGrid *getModulationGrid(); Vector3d getField(const Vector3d &position) const; }; -/** Lower and upper neighbor in a periodically continued unit grid */ -void periodicClamp(double x, int n, int &lo, int &hi); +/** Calculate the mean field strength */ +Vector3f meanFieldStrength(VectorFieldGrid *m); + +/** Calculate the RMS field strength */ +double rmsFieldStrength(VectorFieldGrid *m); + +/** Multiply a magnetic field grid by a factor. */ +void scale(VectorFieldGrid *m, double a); + +#ifdef MPC_HAVE_FFTW3F +/** + * Create a random initialization of a turbulent field. + * @param lMin Minimum wavelength of the turbulence + * @param lMax Maximum wavelength of the turbulence + * @param spectralIndex Power spectral index of the turbulence (-11/3 corresponds to a Kolmogorov spectrum) + * @param Brms RMS field strength + * @param seed Random seed + */ +void initTurbulence(VectorFieldGrid *m, double Brms, double lMin, + double lMax, double spectralIndex = -11. / 3., int seed = 0); + +/** Analytically calculate the correlation length of a turbulent field */ +double turbulentCorrelationLength(double lMin, double lMax, double spectralIndex = -11. / 3.); +#endif // MPC_HAVE_FFTW3F + +/** + * Load a magnetic field grid from a binary file. + * The field is stored single precision numbers with the field components in xyz order and the grid z-index changing the fastest. + * @param c conversion of the values in the file to SI + */ +void load(VectorFieldGrid *m, std::string filename, double c = 1); + +/** + * Dump a magnetic field grid to a binary file. + * The field is stored single precision numbers with the field components in xyz order and the grid z-index changing the fastest. + * @param c conversion of the values in the file to SI + */ +void dump(VectorFieldGrid *m, std::string filename, double c = 1); + +/** + * Load a magnetic field grid from a plain text file. + * The field is stored as one grid point per line from (0,0,0) to (nx, ny, nz) with the grid z-index changing the fastest. + * Within one line the magnetic field values are stored in xyz order separated by a blank or tab. + * Header lines must start with a #. + * @param c conversion of the values in the file to SI + */ +void loadTxt(VectorFieldGrid *m, std::string filename, double c = 1); + +/** + * Dump a magnetic field grid to a plain text file. + * The field is stored as one grid point per line from (0,0,0) to (nx, ny, nz) with the grid z-index changing the fastest. + * Within one line the magnetic field values are stored in xyz order separated by a blank or tab. + * Header lines must start with a #. + * @param c conversion of SI to the values in the file + */ +void dumpTxt(VectorFieldGrid *m, std::string filename, double c = 1); } // namespace mpc diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index e6cb18be4..86d95b27f 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -1,7 +1,6 @@ #include "mpc/XmlExecute.h" #include "mpc/magneticField/UniformMagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" -#include "mpc/magneticField/MagneticFieldGridTools.h" #include "mpc/module/DeflectionCK.h" #include "mpc/module/SimplePropagation.h" #include "mpc/module/Output.h" @@ -196,7 +195,7 @@ void XmlExecute::loadGridMagneticField(xml_node &node) { size.y = Ny * spacing; size.z = Nz * spacing; - MagneticFieldGrid *Bfield = new MagneticFieldGrid(origin, Nx, Ny, Nz, spacing); + VectorFieldGrid *field = new VectorFieldGrid(origin, Nx, Ny, Nz, spacing); std::string type = node.attribute("type").as_string(); if (type == "LSS-Grid") { @@ -207,7 +206,7 @@ void XmlExecute::loadGridMagneticField(xml_node &node) { string fname = node.child_value("File"); cout << " - Loading file (values in [G]): " << fname << endl; - loadTxt(Bfield, fname, gauss); + loadTxt(field, fname, gauss); } else { double brms = node.child("RMS_muG").attribute("value").as_double() * 1e-6 * gauss; cout << " - Brms : " << brms / nG << " nG" << endl; @@ -222,10 +221,10 @@ void XmlExecute::loadGridMagneticField(xml_node &node) { cout << " - Turbulence spectral index: " << alpha << endl; cout << " - Random seed: " << randomSeed << endl; - initTurbulence(Bfield, brms, lMin, lMax, alpha, randomSeed); + initTurbulence(field, brms, lMin, lMax, alpha, randomSeed); } - magnetic_field = Bfield; + magnetic_field = new MagneticFieldGrid(field); } void XmlExecute::loadSophia(xml_node &node) { diff --git a/src/magneticField/MagneticFieldGrid.cpp b/src/magneticField/MagneticFieldGrid.cpp index feb2c655a..b3729c009 100644 --- a/src/magneticField/MagneticFieldGrid.cpp +++ b/src/magneticField/MagneticFieldGrid.cpp @@ -1,109 +1,294 @@ #include "mpc/magneticField/MagneticFieldGrid.h" -#include +#include "mpc/Random.h" +#include namespace mpc { -MagneticFieldGrid::MagneticFieldGrid(Vector3d origin, size_t N, - double spacing) { - setOrigin(origin); - setGridSize(N, N, N); - setSpacing(spacing); +MagneticFieldGrid::MagneticFieldGrid(VectorFieldGrid *grid) { + setGrid(grid); } -MagneticFieldGrid::MagneticFieldGrid(Vector3d origin, size_t Nx, size_t Ny, - size_t Nz, double spacing) { - setOrigin(origin); - setGridSize(Nx, Ny, Nz); - setSpacing(spacing); +void MagneticFieldGrid::setGrid(VectorFieldGrid *grid) { + this->grid = grid; } -void MagneticFieldGrid::setOrigin(Vector3d origin) { - this->origin = origin; +VectorFieldGrid *MagneticFieldGrid::getGrid() { + return grid; } -void MagneticFieldGrid::setGridSize(size_t Nx, size_t Ny, size_t Nz) { - this->Nx = Nx; - this->Ny = Ny; - this->Nz = Nz; - grid.resize(Nx * Ny * Nz); +Vector3d MagneticFieldGrid::getField(const Vector3d &pos) const { + return grid->interpolate(pos); } -void MagneticFieldGrid::setSpacing(double spacing) { - this->spacing = spacing; +void ModulatedMagneticFieldGrid::setGrid(VectorFieldGrid *g) { + grid = g; } -Vector3d MagneticFieldGrid::getOrigin() const { - return origin; +VectorFieldGrid *ModulatedMagneticFieldGrid::getGrid() { + return grid; } -size_t MagneticFieldGrid::getNx() const { - return Nx; +void ModulatedMagneticFieldGrid::setModulationGrid(ScalarFieldGrid *g) { + modGrid = g; } -size_t MagneticFieldGrid::getNy() const { - return Ny; +ScalarFieldGrid *ModulatedMagneticFieldGrid::getModulationGrid() { + return modGrid; } -size_t MagneticFieldGrid::getNz() const { - return Nz; +Vector3d ModulatedMagneticFieldGrid::getField(const Vector3d &pos) const { + float m = modGrid->interpolate(pos); + Vector3d b = grid->interpolate(pos); + return b * m; } -double MagneticFieldGrid::getSpacing() const { - return spacing; +Vector3f meanFieldStrength(VectorFieldGrid *m) { + size_t Nx = m->getNx(); + size_t Ny = m->getNy(); + size_t Nz = m->getNz(); + Vector3f mean(0.); + for (int ix = 0; ix < Nx; ix++) + for (int iy = 0; iy < Ny; iy++) + for (int iz = 0; iz < Nz; iz++) + mean += m->get(ix, iy, iz); + return mean / Nx / Ny / Nz; } -Vector3f &MagneticFieldGrid::get(size_t ix, size_t iy, size_t iz) { - return grid[ix * Ny * Nz + iy * Ny + iz]; +double rmsFieldStrength(VectorFieldGrid *m) { + size_t Nx = m->getNx(); + size_t Ny = m->getNy(); + size_t Nz = m->getNz(); + double sumB2 = 0; + for (int ix = 0; ix < Nx; ix++) + for (int iy = 0; iy < Ny; iy++) + for (int iz = 0; iz < Nz; iz++) + sumB2 += m->get(ix, iy, iz).getMag2(); + return sqrt(sumB2 / Nx / Ny / Nz); } -const Vector3f &MagneticFieldGrid::get(size_t ix, size_t iy, size_t iz) const { - return grid[ix * Ny * Nz + iy * Ny + iz]; +void scale(VectorFieldGrid *m, double a) { + for (int ix = 0; ix < m->getNx(); ix++) + for (int iy = 0; iy < m->getNy(); iy++) + for (int iz = 0; iz < m->getNz(); iz++) + m->get(ix, iy, iz) *= a; } -Vector3d MagneticFieldGrid::getField(const Vector3d &position) const { - // position on a unit grid - Vector3d r = (position - origin) / spacing; +#ifdef MPC_HAVE_FFTW3F +#include "fftw3.h" - // indices of lower and upper neighbors - int ix, iX, iy, iY, iz, iZ; - periodicClamp(r.x, Nx, ix, iX); - periodicClamp(r.y, Ny, iy, iY); - periodicClamp(r.z, Nz, iz, iZ); +void initTurbulence(VectorFieldGrid *m, double Brms, double lMin, double lMax, + double spectralIndex, int seed) { + size_t Nx = m->getNx(); + size_t Ny = m->getNy(); + size_t Nz = m->getNz(); + if ((Nx != Ny) or (Ny != Nz)) + throw std::runtime_error("turbulentField: only cubic grid supported"); - // linear fraction to lower and upper neighbors - double fx = r.x - floor(r.x); - double fX = 1 - fx; - double fy = r.y - floor(r.y); - double fY = 1 - fy; - double fz = r.z - floor(r.z); - double fZ = 1 - fz; + double spacing = m->getSpacing(); + if (lMin < 2 * spacing) + throw std::runtime_error("turbulentField: lMin < 2 * spacing"); + if (lMin >= lMax) + throw std::runtime_error("turbulentField: lMin >= lMax"); + if (lMax > Nx * spacing / 2) + throw std::runtime_error("turbulentField: lMax > size / 2"); - // trilinear interpolation - // check: http://paulbourke.net/miscellaneous/interpolation/ - Vector3d b(0.); - //V000 (1 - x) (1 - y) (1 - z) + - b += get(ix, iy, iz) * fX * fY * fZ; - //V100 x (1 - y) (1 - z) + - b += get(iX, iy, iz) * fx * fY * fZ; - //V010 (1 - x) y (1 - z) + - b += get(ix, iY, iz) * fX * fy * fZ; - //V001 (1 - x) (1 - y) z + - b += get(ix, iy, iZ) * fX * fY * fz; - //V101 x (1 - y) z + - b += get(iX, iy, iZ) * fx * fY * fz; - //V011 (1 - x) y z + - b += get(ix, iY, iZ) * fX * fy * fz; - //V110 x y (1 - z) + - b += get(iX, iY, iz) * fx * fy * fZ; - //V111 x y z - b += get(iX, iY, iZ) * fx * fy * fz; + size_t n = Nx; // size of array + size_t n2 = (size_t) floor(n / 2) + 1;// size array in z-direction in configuration space - return b; + // arrays to hold the complex vector components of the B(k)-field + fftwf_complex *Bkx, *Bky, *Bkz; + Bkx = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * n * n * n2); + Bky = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * n * n * n2); + Bkz = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * n * n * n2); + + Random random; + if (seed != 0) + random.seed(seed);// use given seed + + // calculate the n possible discrete wave numbers + double K[n]; + for (int i = 0; i < n; i++) + K[i] = (double) i / n - i / (n / 2); + + // construct the field in configuration space + int i; + double k, theta, phase, cosPhase, sinPhase; + double kMin = spacing / lMax; + double kMax = spacing / lMin; + Vector3f b;// real b-field vector + Vector3f ek, e1, e2;// orthogonal base + Vector3f n0(1, 1, 1);// arbitrary vector to construct orthogonal base + + for (size_t ix = 0; ix < n; ix++) { + for (size_t iy = 0; iy < n; iy++) { + for (size_t iz = 0; iz < n2; iz++) { + + i = ix * n * n2 + iy * n2 + iz; + ek.setXYZ(K[ix], K[iy], K[iz]); + k = ek.getMag(); + + // wave outside of turbulent range -> B(k) = 0 + if ((k < kMin) || (k > kMax)) { + Bkx[i][0] = 0; + Bkx[i][1] = 0; + Bky[i][0] = 0; + Bky[i][1] = 0; + Bkz[i][0] = 0; + Bkz[i][1] = 0; + continue; + } + + // construct an orthogonal base ek, e1, e2 + if (ek.getAngleTo(n0) < 1e-3) { + // ek parallel to (1,1,1) + e1.setXYZ(-1., 1., 0); + e2.setXYZ(1., 1., -2.); + } else { + // ek not parallel to (1,1,1) + e1 = n0.cross(ek); + e2 = ek.cross(e1); + } + e1 /= e1.getMag(); + e2 /= e2.getMag(); + + // random orientation perpendicular to k + theta = 2 * M_PI * random.rand(); + b = e1 * cos(theta) + e2 * sin(theta); + + // standard normal distributed amplitude weighted with k^alpha/2 + b *= random.randNorm() * pow(k, spectralIndex / 2.); + + // uniform random phase + phase = 2 * M_PI * random.rand(); + cosPhase = cos(phase);// real part + sinPhase = sin(phase);// imaginary part + + Bkx[i][0] = b.x * cosPhase; + Bkx[i][1] = b.x * sinPhase; + Bky[i][0] = b.y * cosPhase; + Bky[i][1] = b.y * sinPhase; + Bkz[i][0] = b.z * cosPhase; + Bkz[i][1] = b.z * sinPhase; + } + } + } + + // in-place, complex to real, inverse Fourier transformation on each component + // note that the last elements of B(x) are unused now + float *Bx = (float*) Bkx; + fftwf_plan plan_x = fftwf_plan_dft_c2r_3d(n, n, n, Bkx, Bx, FFTW_ESTIMATE); + fftwf_execute(plan_x); + fftwf_destroy_plan(plan_x); + + float *By = (float*) Bky; + fftwf_plan plan_y = fftwf_plan_dft_c2r_3d(n, n, n, Bky, By, FFTW_ESTIMATE); + fftwf_execute(plan_y); + fftwf_destroy_plan(plan_y); + + float *Bz = (float*) Bkz; + fftwf_plan plan_z = fftwf_plan_dft_c2r_3d(n, n, n, Bkz, Bz, FFTW_ESTIMATE); + fftwf_execute(plan_z); + fftwf_destroy_plan(plan_z); + + // save to grid + for (size_t ix = 0; ix < n; ix++) { + for (size_t iy = 0; iy < n; iy++) { + for (size_t iz = 0; iz < n; iz++) { + i = ix * n * 2 * n2 + iy * 2 * n2 + iz; + Vector3f &b = m->get(ix, iy, iz); + b.x = Bx[i]; + b.y = By[i]; + b.z = Bz[i]; + } + } + } + + fftwf_free(Bkx); + fftwf_free(Bky); + fftwf_free(Bkz); + + scale(m, Brms / rmsFieldStrength(m)); // normalize to Brms +} + +double turbulentCorrelationLength(double lMin, double lMax, double spectralIndex) { + double r = lMin / lMax; + double a = -spectralIndex - 2; + return lMax / 2 * (a - 1) / a * (1 - pow(r, a)) / (1 - pow(r, a - 1)); +} +#endif // MPC_HAVE_FFTW3F + +void load(VectorFieldGrid *m, std::string filename, double c) { + std::ifstream fin(filename.c_str(), std::ios::binary); + if (!fin) + throw std::runtime_error("MagneticFieldGrid: File not found"); + for (int ix = 0; ix < m->getNx(); ix++) { + for (int iy = 0; iy < m->getNy(); iy++) { + for (int iz = 0; iz < m->getNz(); iz++) { + Vector3f &b = m->get(ix, iy, iz); + fin.read((char*) &(b.x), sizeof(float)); + fin.read((char*) &(b.y), sizeof(float)); + fin.read((char*) &(b.z), sizeof(float)); + b *= c; + } + } + } + fin.close(); +} + +void dump(VectorFieldGrid *m, std::string filename, double c) { + std::ofstream fout(filename.c_str(), std::ios::binary); + if (!fout) + throw std::runtime_error("MagneticFieldGrid: Could not open file"); + for (int ix = 0; ix < m->getNx(); ix++) { + for (int iy = 0; iy < m->getNy(); iy++) { + for (int iz = 0; iz < m->getNz(); iz++) { + Vector3f b = m->get(ix, iy, iz) * c; + fout.write((char*) &(b.x), sizeof(float)); + fout.write((char*) &(b.y), sizeof(float)); + fout.write((char*) &(b.z), sizeof(float)); + } + } + } + fout.close(); +} + +void loadTxt(VectorFieldGrid *m, std::string filename, double unit) { + std::ifstream fin(filename.c_str()); + if (!fin) + throw std::runtime_error("MagneticFieldGrid: file not found"); + + // skip header lines + while (fin.peek() == '#') + fin.ignore(std::numeric_limits::max(), '\n'); + + for (int ix = 0; ix < m->getNx(); ix++) { + for (int iy = 0; iy < m->getNy(); iy++) { + for (int iz = 0; iz < m->getNz(); iz++) { + Vector3f &b = m->get(ix, iy, iz); + fin >> b.x >> b.y >> b.z; + b *= unit; + if (fin.eof()) + throw std::runtime_error( + "MagneticFieldGrid: file too short"); + } + } + } + fin.close(); } -void periodicClamp(double x, int n, int &lo, int &hi) { - lo = ((int(floor(x)) % n) + n) % n; - hi = (lo + 1) % n; +void dumpTxt(VectorFieldGrid *m, std::string filename, double unit) { + std::ofstream fout(filename.c_str()); + if (!fout) + throw std::runtime_error("MagneticFieldGrid: could not open file"); + for (int ix = 0; ix < m->getNx(); ix++) { + for (int iy = 0; iy < m->getNy(); iy++) { + for (int iz = 0; iz < m->getNz(); iz++) { + Vector3f b = m->get(ix, iy, iz) * unit; + fout << b << "\n"; + } + } + } + fout.close(); } } // namespace mpc diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index a955621de..75d30b3a2 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -1,6 +1,6 @@ #include "mpc/magneticField/UniformMagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" -#include "mpc/magneticField/MagneticFieldGridTools.h" +#include "mpc/magneticField/PeriodicGrid.h" #include "mpc/magneticField/TurbulentMagneticField.h" #include "mpc/Units.h" #include "mpc/Common.h" @@ -18,7 +18,7 @@ TEST(testUniformMagneticField, SimpleTest) { EXPECT_DOUBLE_EQ(b.z, 3); } -TEST(testMagneticFieldGrid, PeriodicClamp) { +TEST(testVectorFieldGrid, PeriodicClamp) { // Test correct determination of lower and upper neighbor int lo, hi; @@ -31,9 +31,9 @@ TEST(testMagneticFieldGrid, PeriodicClamp) { EXPECT_EQ(1, hi); } -TEST(testMagneticFieldGrid, SimpleTest) { +TEST(testVectorFieldGrid, SimpleTest) { // Test construction and parameters - MagneticFieldGrid B(Vector3d(1., 2., 3.), 4, 2.5); + VectorFieldGrid B(Vector3d(1., 2., 3.), 4, 2.5); EXPECT_TRUE(Vector3d(1., 2., 3.) == B.getOrigin()); EXPECT_EQ(4, B.getNx()); EXPECT_EQ(4, B.getNy()); @@ -41,83 +41,83 @@ TEST(testMagneticFieldGrid, SimpleTest) { EXPECT_DOUBLE_EQ(2.5, B.getSpacing()); } -TEST(testMagneticFieldGrid, Interpolation) { +TEST(testVectorFieldGrid, Interpolation) { // Explicitly test trilinear interpolation double spacing = 2.793; - MagneticFieldGrid B(Vector3d(0.), 3, spacing); + VectorFieldGrid grid(Vector3d(0.), 3, spacing); + grid.get(0, 0, 1) = Vector3f(1.7, 0., 0.); // set one value - B.get(0, 0, 1) = Vector3f(1.7, 0., 0.); // set one value - - Vector3d b = B.getField(Vector3d(0, 0, 1) * spacing); + Vector3d b; + b = grid.interpolate(Vector3d(0, 0, 1) * spacing); EXPECT_FLOAT_EQ(1.7, b.x); - b = B.getField(Vector3d(0, 0, 0.9) * spacing); + b = grid.interpolate(Vector3d(0, 0, 0.9) * spacing); EXPECT_FLOAT_EQ(1.7 * 0.9, b.x); - b = B.getField(Vector3d(0, 0, 1.1) * spacing); + b = grid.interpolate(Vector3d(0, 0, 1.1) * spacing); EXPECT_FLOAT_EQ(1.7 * 0.9, b.x); - b = B.getField(Vector3d(0, 0.15, 0.9) * spacing); + b = grid.interpolate(Vector3d(0, 0.15, 0.9) * spacing); EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.85, b.x); - b = B.getField(Vector3d(0, 2.15, 0.9) * spacing); + b = grid.interpolate(Vector3d(0, 2.15, 0.9) * spacing); EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.15, b.x); } -TEST(testMagneticFieldGrid, Scale) { +TEST(testVectorFieldGrid, Scale) { // Test scaling a field - MagneticFieldGrid B(Vector3d(0.), 3, 1); + VectorFieldGrid grid(Vector3d(0.), 3, 1); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) - B.get(ix, iy, iz) = Vector3f(1, 0, 0); + grid.get(ix, iy, iz) = Vector3f(1, 0, 0); - scale(&B, 5); + scale(&grid, 5); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) - EXPECT_FLOAT_EQ(5, B.getField(Vector3d(0.7, 0, 0.1)).x); + EXPECT_FLOAT_EQ(5, grid.interpolate(Vector3d(0.7, 0, 0.1)).x); } -TEST(testMagneticFieldGrid, Periodicity) { +TEST(testVectorFieldGrid, Periodicity) { // Test for periodic boundaries: B(x+a*n) = B(x) size_t n = 3; double spacing = 3; double size = n * spacing; - MagneticFieldGrid B(Vector3d(0.), n, spacing); + VectorFieldGrid grid(Vector3d(0.), n, spacing); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) - B.get(ix, iy, iz) = Vector3f(iz + ix, iy * iz, ix - iz * iy); + grid.get(ix, iy, iz) = Vector3f(iz + ix, iy * iz, ix - iz * iy); Vector3d pos(1.2, 2.3, 0.7); - Vector3f b = B.getField(pos); - Vector3f b2 = B.getField(pos + Vector3d(1, 0, 0) * size); + Vector3f b = grid.interpolate(pos); + Vector3f b2 = grid.interpolate(pos + Vector3d(1, 0, 0) * size); EXPECT_FLOAT_EQ(b.x, b2.x); EXPECT_FLOAT_EQ(b.y, b2.y); EXPECT_FLOAT_EQ(b.z, b2.z); - b2 = B.getField(pos + Vector3d(0, 5, 0) * size); + b2 = grid.interpolate(pos + Vector3d(0, 5, 0) * size); EXPECT_FLOAT_EQ(b.x, b2.x); EXPECT_FLOAT_EQ(b.y, b2.y); EXPECT_FLOAT_EQ(b.z, b2.z); - b2 = B.getField(pos + Vector3d(0, 0, -2) * size); + b2 = grid.interpolate(pos + Vector3d(0, 0, -2) * size); EXPECT_FLOAT_EQ(b.x, b2.x); EXPECT_FLOAT_EQ(b.y, b2.y); EXPECT_FLOAT_EQ(b.z, b2.z); } -TEST(testMagneticFieldGrid, DumpLoad) { +TEST(testVectorFieldGrid, DumpLoad) { // Dump and load a field grid - MagneticFieldGrid B1(Vector3d(0.), 3, 1); + VectorFieldGrid B1(Vector3d(0.), 3, 1); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) B1.get(ix, iy, iz) = Vector3f(1, 2, 3); dump(&B1, getDataPath("../test/testDump.raw")); - MagneticFieldGrid B2(Vector3d(0.), 3, 1); + VectorFieldGrid B2(Vector3d(0.), 3, 1); load(&B2, getDataPath("../test/testDump.raw")); for (int ix = 0; ix < 3; ix++) { @@ -133,16 +133,16 @@ TEST(testMagneticFieldGrid, DumpLoad) { } } -TEST(testMagneticFieldGrid, DumpLoadTxt) { +TEST(testVectorFieldGrid, DumpLoadTxt) { // Dump and load a field grid - MagneticFieldGrid B1(Vector3d(0.), 3, 1); + VectorFieldGrid B1(Vector3d(0.), 3, 1); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) B1.get(ix, iy, iz) = Vector3f(ix, iy, iz) * nG; dumpTxt(&B1, getDataPath("../test/testDump.txt"), 1e4); - MagneticFieldGrid B2(Vector3d(0.), 3, 1); + VectorFieldGrid B2(Vector3d(0.), 3, 1); loadTxt(&B2, getDataPath("../test/testDump.txt"), 1e-4); for (int ix = 0; ix < 3; ix++) { @@ -158,35 +158,35 @@ TEST(testMagneticFieldGrid, DumpLoadTxt) { } } -TEST(testMagneticFieldGrid, Speed) { +TEST(testVectorFieldGrid, Speed) { // Dump and load a field grid - MagneticFieldGrid B(Vector3d(0.), 3, 3); + VectorFieldGrid grid(Vector3d(0.), 3, 3); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) - B.get(ix, iy, iz) = Vector3f(1, 2, 3); + grid.get(ix, iy, iz) = Vector3f(1, 2, 3); Vector3d b; for (int i = 0; i < 100000; i++) - b = B.getField(Vector3d(i)); + b = grid.interpolate(Vector3d(i)); } -TEST(testMagneticFieldGrid, Turbulence_bmean_brms) { +TEST(testVectorFieldGrid, Turbulence_bmean_brms) { // Test for zero mean: = 0 size_t n = 64; double spacing = 10 * Mpc / n; double Brms = 1; double lMin = 2 * spacing; double lMax = 8 * spacing; - MagneticFieldGrid B(Vector3d(0, 0, 0), n, spacing); - initTurbulence(&B, Brms, lMin, lMax); + VectorFieldGrid grid(Vector3d(0, 0, 0), n, spacing); + initTurbulence(&grid, Brms, lMin, lMax); double precision = 1e-7; - Vector3f bMean = meanFieldStrength(&B); + Vector3f bMean = meanFieldStrength(&grid); EXPECT_NEAR(0, bMean.x, precision); EXPECT_NEAR(0, bMean.y, precision); EXPECT_NEAR(0, bMean.z, precision); - EXPECT_NEAR(1, rmsFieldStrength(&B), precision); + EXPECT_NEAR(1, rmsFieldStrength(&grid), precision); } TEST(testMagneticFieldGrid, Turbulence_seed) { @@ -199,14 +199,14 @@ TEST(testMagneticFieldGrid, Turbulence_seed) { double index = -11. / 3.; int seed = 753; - MagneticFieldGrid B1(Vector3d(0, 0, 0), n, spacing); - initTurbulence(&B1, Brms, lMin, lMax, index, seed); + VectorFieldGrid grid1(Vector3d(0, 0, 0), n, spacing); + initTurbulence(&grid1, Brms, lMin, lMax, index, seed); - MagneticFieldGrid B2(Vector3d(0, 0, 0), n, spacing); - initTurbulence(&B2, Brms, lMin, lMax, index, seed); + VectorFieldGrid grid2(Vector3d(0, 0, 0), n, spacing); + initTurbulence(&grid2, Brms, lMin, lMax, index, seed); Vector3d pos(22 * Mpc); - EXPECT_FLOAT_EQ(B1.getField(pos).x, B2.getField(pos).x); + EXPECT_FLOAT_EQ(grid1.interpolate(pos).x, grid2.interpolate(pos).x); } TEST(testMagneticFieldGrid, turbulence_Exceptions) { @@ -214,18 +214,18 @@ TEST(testMagneticFieldGrid, turbulence_Exceptions) { size_t n = 64; double spacing = 10 * Mpc / n; double brms = 1; - MagneticFieldGrid B(Vector3d(0, 0, 0), n, spacing); + VectorFieldGrid grid(Vector3d(0, 0, 0), n, spacing); // should be fine - EXPECT_NO_THROW(initTurbulence(&B, brms, 2 * spacing, 8 * spacing)); + EXPECT_NO_THROW(initTurbulence(&grid, brms, 2 * spacing, 8 * spacing)); // lMin too small - EXPECT_THROW(initTurbulence(&B, brms, 1.5 * spacing, 8 * spacing), + EXPECT_THROW(initTurbulence(&grid, brms, 1.5 * spacing, 8 * spacing), std::runtime_error); // lMin > lMax - EXPECT_THROW(initTurbulence(&B, brms, 8.1 * spacing, 8 * spacing), + EXPECT_THROW(initTurbulence(&grid, brms, 8.1 * spacing, 8 * spacing), std::runtime_error); // lMax too large - EXPECT_THROW(initTurbulence(&B, brms, 2 * spacing, 33 * spacing), + EXPECT_THROW(initTurbulence(&grid, brms, 2 * spacing, 33 * spacing), std::runtime_error); } @@ -265,6 +265,7 @@ TEST(testTurbulentMagneticField, Brms) { std::cout << Brms << std::endl; std::cout << Bmean << std::endl; + // this turbulent field realization is not working at the moment // EXPECT_NEAR(Bmean.x, 0, 1e-6); // EXPECT_NEAR(Bmean.y, 0, 1e-6); // EXPECT_NEAR(Bmean.z, 0, 1e-6); From b947c8c526632e124c5451f35494ee8c589570bc Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 25 Jul 2012 10:09:19 +0200 Subject: [PATCH 0154/1298] add missing file PeriodicGrid.h fix test fix cmake + python --- CMakeLists.txt | 37 +++-- README | 27 +++- include/mpc/magneticField/PeriodicGrid.h | 134 ++++++++++++++++ python/mpc.i | 8 +- src/magneticField/MagneticFieldGrid.cpp | 34 ++-- test/testMagneticField.cpp | 2 + test/testSPHField.cpp | 193 +++++++++-------------- 7 files changed, 279 insertions(+), 156 deletions(-) create mode 100644 include/mpc/magneticField/PeriodicGrid.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 02d5cada7..817df69cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,28 +146,31 @@ if(ENABLETESTING) target_link_libraries(testSource mpc gtest gtest_main pthread) add_test(testSource testSource) - if(GADGET_FOUND AND FFTW3F_FOUND) + if(GADGET_FOUND) add_executable(testSPHField test/testSPHField.cpp) target_link_libraries(testSPHField mpc gtest gtest_main pthread) add_test(testSPHField testSPHField) - endif() + endif(GADGET_FOUND) endif(ENABLETESTING) # ---------------------------------------------------------------------------- # Python # ---------------------------------------------------------------------------- -#include(python/Python.cmake) -#include_directories(${PYTHON_INCLUDE_PATH}) - -#file(GLOB_RECURSE MPC_INCLUDES include/*.h) -#set_source_files_properties( ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx PROPERTIES GENERATED true ) -#add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx -# COMMAND swig -c++ -python ${MPC_SWIG_DEFINES} -I${CMAKE_SOURCE_DIR}/include -o ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx -outdir ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/python/mpc.i -# DEPENDS ${CMAKE_SOURCE_DIR}/python/mpc.i ${MPC_INCLUDES} ) -#add_library(mpc-swig MODULE ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx) -##set_source_file_properties( ${CMAKE_SOURCE_DIR}/python/mpc.i PROPERTIES OBJECT_DEPENDS ${MPC_INCLUDES}) -#set_target_properties(mpc-swig PROPERTIES PREFIX "") -#set_target_properties(mpc-swig PROPERTIES OUTPUT_NAME "_mpc") -#target_link_libraries(mpc-swig mpc ${PYTHON_LIBRARIES}) -#install(FILES "${CMAKE_CURRENT_BINARY_DIR}/mpc.py" DESTINATION ${PYTHON_SITE_PACKAGES}) -#install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_mpc.so" DESTINATION ${PYTHON_SITE_PACKAGES}) +option(ENABLEPYTHON "Create python library via SWIG" OFF) +if(ENABLEPYTHON) + include(python/Python.cmake) + include_directories(${PYTHON_INCLUDE_PATH}) + + file(GLOB_RECURSE MPC_INCLUDES include/*.h) + set_source_files_properties( ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx PROPERTIES GENERATED true ) + add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx + COMMAND swig -c++ -python ${MPC_SWIG_DEFINES} -I${CMAKE_SOURCE_DIR}/include -o ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx -outdir ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/python/mpc.i + DEPENDS ${CMAKE_SOURCE_DIR}/python/mpc.i ${MPC_INCLUDES} ) + add_library(mpc-swig MODULE ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx) + #set_source_file_properties( ${CMAKE_SOURCE_DIR}/python/mpc.i PROPERTIES OBJECT_DEPENDS ${MPC_INCLUDES}) + set_target_properties(mpc-swig PROPERTIES PREFIX "") + set_target_properties(mpc-swig PROPERTIES OUTPUT_NAME "_mpc") + target_link_libraries(mpc-swig mpc ${PYTHON_LIBRARIES}) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/mpc.py" DESTINATION ${PYTHON_SITE_PACKAGES}) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_mpc.so" DESTINATION ${PYTHON_SITE_PACKAGES}) +endif(ENABLEPYTHON) \ No newline at end of file diff --git a/README b/README index 3b0aa2db0..4073d938d 100644 --- a/README +++ b/README @@ -17,15 +17,26 @@ Dependencies ------------ Required: C++ Compiler -Fortran Compiler -GNU Scientific Library - for interpolation +Fortran Compiler + -> to compile SOPHIA Provided: -SOPHIA - for photo-hadronic interactions -googletest - for unit-tests +SOPHIA + -> for photo-hadronic interactions +googletest + -> for unit-tests Optional: -Python and SWIG - to use MPC from python -OpenMP - for shared memory parallelization -FFTW - for turbulent magnetic field -Gadget - for smooth particle large scale structure +Python and SWIG + -> to use MPC from Python + tested for > Python 2.7 + tested for > SWIG 2.0 +FFTW3F + -> for turbulent magnetic field grids + MPC needs the FFTW3 library compiled with the single precision option +Gadget + -> for large scale structure using the smooth particle formalism +OpenMP + -> for shared memory parallelization +googleperftools + -> for performance optimizations regarding shared memory parallelization \ No newline at end of file diff --git a/include/mpc/magneticField/PeriodicGrid.h b/include/mpc/magneticField/PeriodicGrid.h new file mode 100644 index 000000000..345e5d3ee --- /dev/null +++ b/include/mpc/magneticField/PeriodicGrid.h @@ -0,0 +1,134 @@ +#ifndef MPC_PERIODICGRID_H_ +#define MPC_PERIODICGRID_H_ + +#include "mpc/Vector3.h" +#include + +namespace mpc { + +// Lower and upper neighbor in a periodically continued unit grid +inline void periodicClamp(double x, int n, int &lo, int &hi) { + lo = ((int(floor(x)) % n) + n) % n; + hi = (lo + 1) % n; +} + +/** + @class PeriodicGrid + @brief Template class for fields on a periodic grid with trilinear interpolation + + The grid spacing is constant and equal along all three axes. + Values are calculated by trilinear interpolation of the surrounding 8 grid points. + The grid is periodically extended. + The grid sample positions are at 0, size/N, ... (N-1) * size/N. + */ +template +class PeriodicGrid { + std::vector grid; + Vector3d origin; + size_t Nx, Ny, Nz; + double spacing; + +public: + PeriodicGrid(Vector3d origin, size_t N, double spacing) { + setOrigin(origin); + setGridSize(N, N, N); + setSpacing(spacing); + } + + PeriodicGrid(Vector3d origin, size_t Nx, size_t Ny, size_t Nz, + double spacing) { + setOrigin(origin); + setGridSize(Nx, Ny, Nz); + setSpacing(spacing); + } + + void setOrigin(Vector3d origin) { + this->origin = origin; + } + + void setGridSize(size_t Nx, size_t Ny, size_t Nz) { + this->Nx = Nx; + this->Ny = Ny; + this->Nz = Nz; + grid.resize(Nx * Ny * Nz); + } + + void setSpacing(double spacing) { + this->spacing = spacing; + } + + Vector3d getOrigin() const { + return origin; + } + size_t getNx() const { + return Nx; + } + + size_t getNy() const { + return Ny; + } + + size_t getNz() const { + return Nz; + } + + double getSpacing() const { + return spacing; + } + + T &get(size_t ix, size_t iy, size_t iz) { + return grid[ix * Ny * Nz + iy * Ny + iz]; + } + + const T &get(size_t ix, size_t iy, size_t iz) const { + return grid[ix * Ny * Nz + iy * Ny + iz]; + } + + T interpolate(const Vector3d &position) const { + // position on a unit grid + Vector3d r = (position - origin) / spacing; + + // indices of lower and upper neighbors + int ix, iX, iy, iY, iz, iZ; + periodicClamp(r.x, Nx, ix, iX); + periodicClamp(r.y, Ny, iy, iY); + periodicClamp(r.z, Nz, iz, iZ); + + // linear fraction to lower and upper neighbors + double fx = r.x - floor(r.x); + double fX = 1 - fx; + double fy = r.y - floor(r.y); + double fY = 1 - fy; + double fz = r.z - floor(r.z); + double fZ = 1 - fz; + + // trilinear interpolation + // check: http://paulbourke.net/miscellaneous/interpolation/ + T b(0.); + //V000 (1 - x) (1 - y) (1 - z) + + b += get(ix, iy, iz) * fX * fY * fZ; + //V100 x (1 - y) (1 - z) + + b += get(iX, iy, iz) * fx * fY * fZ; + //V010 (1 - x) y (1 - z) + + b += get(ix, iY, iz) * fX * fy * fZ; + //V001 (1 - x) (1 - y) z + + b += get(ix, iy, iZ) * fX * fY * fz; + //V101 x (1 - y) z + + b += get(iX, iy, iZ) * fx * fY * fz; + //V011 (1 - x) y z + + b += get(ix, iY, iZ) * fX * fy * fz; + //V110 x y (1 - z) + + b += get(iX, iY, iz) * fx * fy * fZ; + //V111 x y z + b += get(iX, iY, iZ) * fx * fy * fz; + + return b; + } +}; + +typedef PeriodicGrid VectorFieldGrid; +typedef PeriodicGrid ScalarFieldGrid; + +} // namespace mpc + +#endif /* MPC_PERIODICGRID_H_ */ diff --git a/python/mpc.i b/python/mpc.i index ed8578f52..a15b7d499 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -28,8 +28,8 @@ #include "mpc/magneticField/MagneticField.h" #include "mpc/magneticField/UniformMagneticField.h" +#include "mpc/magneticField/PeriodicGrid.h" #include "mpc/magneticField/MagneticFieldGrid.h" -#include "mpc/magneticField/MagneticFieldGridTools.h" #include "mpc/magneticField/SPHMagneticField.h" #include "mpc/Referenced.h" @@ -100,8 +100,12 @@ %template(MagneticFieldRefPtr) mpc::ref_ptr; %include "mpc/magneticField/MagneticField.h" %include "mpc/magneticField/UniformMagneticField.h" + +%include "mpc/magneticField/PeriodicGrid.h" +%template(VectorFieldGrid) mpc::PeriodicGrid >; +%template(ScalarFieldGrid) mpc::PeriodicGrid; + %include "mpc/magneticField/MagneticFieldGrid.h" -%include "mpc/magneticField/MagneticFieldGridTools.h" %include "mpc/magneticField/SPHMagneticField.h" %include "mpc/ExplicitRungeKutta.h" diff --git a/src/magneticField/MagneticFieldGrid.cpp b/src/magneticField/MagneticFieldGrid.cpp index b3729c009..904aa6371 100644 --- a/src/magneticField/MagneticFieldGrid.cpp +++ b/src/magneticField/MagneticFieldGrid.cpp @@ -20,6 +20,12 @@ Vector3d MagneticFieldGrid::getField(const Vector3d &pos) const { return grid->interpolate(pos); } +ModulatedMagneticFieldGrid::ModulatedMagneticFieldGrid(VectorFieldGrid *grid, + ScalarFieldGrid *modGrid) { + setGrid(grid); + setModulationGrid(modGrid); +} + void ModulatedMagneticFieldGrid::setGrid(VectorFieldGrid *g) { grid = g; } @@ -82,18 +88,18 @@ void initTurbulence(VectorFieldGrid *m, double Brms, double lMin, double lMax, size_t Ny = m->getNy(); size_t Nz = m->getNz(); if ((Nx != Ny) or (Ny != Nz)) - throw std::runtime_error("turbulentField: only cubic grid supported"); + throw std::runtime_error("turbulentField: only cubic grid supported"); double spacing = m->getSpacing(); if (lMin < 2 * spacing) - throw std::runtime_error("turbulentField: lMin < 2 * spacing"); + throw std::runtime_error("turbulentField: lMin < 2 * spacing"); if (lMin >= lMax) - throw std::runtime_error("turbulentField: lMin >= lMax"); + throw std::runtime_error("turbulentField: lMin >= lMax"); if (lMax > Nx * spacing / 2) - throw std::runtime_error("turbulentField: lMax > size / 2"); + throw std::runtime_error("turbulentField: lMax > size / 2"); size_t n = Nx; // size of array - size_t n2 = (size_t) floor(n / 2) + 1;// size array in z-direction in configuration space + size_t n2 = (size_t) floor(n / 2) + 1; // size array in z-direction in configuration space // arrays to hold the complex vector components of the B(k)-field fftwf_complex *Bkx, *Bky, *Bkz; @@ -103,21 +109,21 @@ void initTurbulence(VectorFieldGrid *m, double Brms, double lMin, double lMax, Random random; if (seed != 0) - random.seed(seed);// use given seed + random.seed(seed); // use given seed // calculate the n possible discrete wave numbers double K[n]; for (int i = 0; i < n; i++) - K[i] = (double) i / n - i / (n / 2); + K[i] = (double) i / n - i / (n / 2); // construct the field in configuration space int i; double k, theta, phase, cosPhase, sinPhase; double kMin = spacing / lMax; double kMax = spacing / lMin; - Vector3f b;// real b-field vector - Vector3f ek, e1, e2;// orthogonal base - Vector3f n0(1, 1, 1);// arbitrary vector to construct orthogonal base + Vector3f b; // real b-field vector + Vector3f ek, e1, e2; // orthogonal base + Vector3f n0(1, 1, 1); // arbitrary vector to construct orthogonal base for (size_t ix = 0; ix < n; ix++) { for (size_t iy = 0; iy < n; iy++) { @@ -160,8 +166,8 @@ void initTurbulence(VectorFieldGrid *m, double Brms, double lMin, double lMax, // uniform random phase phase = 2 * M_PI * random.rand(); - cosPhase = cos(phase);// real part - sinPhase = sin(phase);// imaginary part + cosPhase = cos(phase); // real part + sinPhase = sin(phase); // imaginary part Bkx[i][0] = b.x * cosPhase; Bkx[i][1] = b.x * sinPhase; @@ -210,13 +216,13 @@ void initTurbulence(VectorFieldGrid *m, double Brms, double lMin, double lMax, scale(m, Brms / rmsFieldStrength(m)); // normalize to Brms } -double turbulentCorrelationLength(double lMin, double lMax, double spectralIndex) { +double turbulentCorrelationLength(double lMin, double lMax, + double spectralIndex) { double r = lMin / lMax; double a = -spectralIndex - 2; return lMax / 2 * (a - 1) / a * (1 - pow(r, a)) / (1 - pow(r, a - 1)); } #endif // MPC_HAVE_FFTW3F - void load(VectorFieldGrid *m, std::string filename, double c) { std::ifstream fin(filename.c_str(), std::ios::binary); if (!fin) diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index 75d30b3a2..62a7b0806 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -171,6 +171,7 @@ TEST(testVectorFieldGrid, Speed) { b = grid.interpolate(Vector3d(i)); } +#ifdef MPC_HAVE_FFTW3F TEST(testVectorFieldGrid, Turbulence_bmean_brms) { // Test for zero mean: = 0 size_t n = 64; @@ -228,6 +229,7 @@ TEST(testMagneticFieldGrid, turbulence_Exceptions) { EXPECT_THROW(initTurbulence(&grid, brms, 2 * spacing, 33 * spacing), std::runtime_error); } +#endif // MPC_HAVE_FFTW3F TEST(testTurbulentMagneticField, SimpleTest) { TurbulentMagneticField B; diff --git a/test/testSPHField.cpp b/test/testSPHField.cpp index c44389cd9..27d948ae4 100644 --- a/test/testSPHField.cpp +++ b/test/testSPHField.cpp @@ -1,115 +1,78 @@ -//#include "mpc/magneticField/SPHMagneticField.h" -//#include "mpc/magneticField/SPHTurbulentMagneticFieldGrid.h" -//#include "mpc/Units.h" -//#include "mpc/Common.h" -// -//#include "gtest/gtest.h" -// -//namespace mpc { -// -////TEST(testSPHMagneticField, simpleTest) { -//// // Tests if a direct SPH field can be constructed and prints RMS and mean field strength -//// Vector3d origin(80 * Mpc); -//// double size = 40 * Mpc; -//// -//// // gadget::DirectField may throw if queried for magnetic fields on the borders -//// Vector3d safeOrigin = origin - Vector3d(1 * kpc); -//// double safeSize = size + 2 * kpc; -//// -//// SPHMagneticField B(safeOrigin, safeSize, 20, -//// getDataPath("SPH/mhd_z.db").c_str()); -//// -//// int n = 64; -//// double spacing = 40 * Mpc / (n - 1); -//// double brms = 0; -//// Vector3d bmean(0, 0, 0); -//// for (int ix = 0; ix < n; ix++) -//// for (int iy = 0; iy < n; iy++) -//// for (int iz = 0; iz < n; iz++) { -//// Vector3d b = B.getField( -//// origin + Vector3d(ix, iy, iz) * spacing); -//// brms += b.getMag2(); -//// bmean += b; -//// } -//// -//// brms = sqrt(brms / n / n / n); -//// bmean /= n * n * n; -//// -//// std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; -//// std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; -////} -//// -////TEST(testSPHMagneticFieldGrid, simpleTest) { -//// // Tests if a sampled SPH field can be constructed and prints RMS and mean field strength -//// Vector3d origin(80 * Mpc); -//// size_t n = 64; -//// double size = 40 * Mpc; -//// double spacing = size / (n - 1); -//// -//// // gadget::SampledField may throw if queried for magnetic fields on the borders -//// Vector3d safeOrigin = origin - Vector3d(1 * kpc); -//// double safeSize = size + 2 * kpc; -//// -//// SPHMagneticFieldGrid B(safeOrigin, safeSize, n, -//// getDataPath("SPH/mhd_z.db").c_str()); -//// -//// double brms = 0; -//// Vector3d bmean(0, 0, 0); -//// for (int ix = 0; ix < n; ix++) -//// for (int iy = 0; iy < n; iy++) -//// for (int iz = 0; iz < n; iz++) { -//// Vector3d b = B.getField( -//// origin + Vector3d(ix, iy, iz) * spacing); -//// brms += b.getMag2(); -//// bmean += b; -//// } -//// -//// brms = sqrt(brms / n / n / n); -//// bmean /= n * n * n; -//// -//// std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; -//// std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; -////} -// -//TEST(testSPHTurbulentMagneticField, simpleTest) { -// // Tests if a sampled SPH field can be constructed and prints RMS and mean field strength -// Vector3d origin(100 * Mpc); -// size_t n = 64; -// double size = 40 * Mpc; -// double spacing = size / n; -// -// SPHTurbulentMagneticFieldGrid B(origin, size, n); -// B.setTurbulenceProperties(2 * spacing, 8 * spacing, -11. / 3); -// B.initialize(); -// B.scale(1 / B.getRMSFieldStrength()); -// -// std::cout << "modulating" << std::endl; -// B.setDensityField(getDataPath("SPH/mhd_z.db").c_str(), Vector3d(99 * Mpc), -// 42 * Mpc, 20); -// B.setModulation(getDataPath("SPH/miniati-profile.txt")); -// -// std::cout << "sampling" << std::endl; -// double brms = 0; -// Vector3d bmean(0, 0, 0); -// for (int ix = 0; ix < n; ix++) -// for (int iy = 0; iy < n; iy++) -// for (int iz = 0; iz < n; iz++) { -// Vector3d b = B.getField( -// origin + Vector3d(ix, iy, iz) * spacing); -// brms += b.getMag2(); -// bmean += b; -// } -// -// brms = sqrt(brms / n / n / n); -// bmean /= n * n * n; -// -// std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; -// std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; -//} -// -//int main(int argc, char **argv) { -// ::testing::InitGoogleTest(&argc, argv); -// return RUN_ALL_TESTS(); -//} -// -//} // namespace mpc +#include "mpc/magneticField/SPHMagneticField.h" +#include "mpc/Units.h" +#include "mpc/Common.h" + +#include "gtest/gtest.h" + +namespace mpc { + +TEST(testSPHMagneticField, simpleTest) { + // Tests if a direct SPH field can be constructed and prints RMS and mean field strength + Vector3d origin(80 * Mpc); + double size = 40 * Mpc; + + // gadget::DirectField may throw if queried for magnetic fields on the borders + Vector3d safeOrigin = origin - Vector3d(1 * kpc); + double safeSize = size + 2 * kpc; + + SPHMagneticField B(safeOrigin, safeSize, 20, + getDataPath("SPH/mhd_z.db").c_str()); + + int n = 64; + double spacing = 40 * Mpc / (n - 1); + double brms = 0; + Vector3d bmean(0, 0, 0); + for (int ix = 0; ix < n; ix++) + for (int iy = 0; iy < n; iy++) + for (int iz = 0; iz < n; iz++) { + Vector3d b = B.getField( + origin + Vector3d(ix, iy, iz) * spacing); + brms += b.getMag2(); + bmean += b; + } + + brms = sqrt(brms / n / n / n); + bmean /= n * n * n; + + std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; + std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; +} + +TEST(testSPHMagneticFieldGrid, simpleTest) { + // Tests if a sampled SPH field can be constructed and prints RMS and mean field strength + Vector3d origin(80 * Mpc); + size_t n = 64; + double size = 40 * Mpc; + double spacing = size / (n - 1); + + // gadget::SampledField may throw if queried for magnetic fields on the borders + Vector3d safeOrigin = origin - Vector3d(1 * kpc); + double safeSize = size + 2 * kpc; + + SPHMagneticFieldGrid B(safeOrigin, safeSize, n, + getDataPath("SPH/mhd_z.db").c_str()); + + double brms = 0; + Vector3d bmean(0, 0, 0); + for (int ix = 0; ix < n; ix++) + for (int iy = 0; iy < n; iy++) + for (int iz = 0; iz < n; iz++) { + Vector3d b = B.getField( + origin + Vector3d(ix, iy, iz) * spacing); + brms += b.getMag2(); + bmean += b; + } + + brms = sqrt(brms / n / n / n); + bmean /= n * n * n; + + std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; + std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + +} // namespace mpc From 1ce5d1e8bd73cbffe4989ae9564b4a8d9981030f Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 25 Jul 2012 12:53:57 +0200 Subject: [PATCH 0155/1298] changed PeriodicGrid interface to ref_ptr --- include/mpc/magneticField/MagneticFieldGrid.h | 40 +++++----- include/mpc/magneticField/PeriodicGrid.h | 6 +- include/mpc/module/DeflectionCK.h | 4 +- python/mpc.i | 28 +++++-- src/XmlExecute.cpp | 2 +- src/magneticField/MagneticFieldGrid.cpp | 36 ++++----- src/module/DeflectionCK.cpp | 2 +- test/python/testSPHTurbulentField.py | 75 ------------------ test/python/testTurbulentDeflection.py | 8 +- test/python/testTurbulentFieldGrid.py | 8 +- test/testMagneticField.cpp | 79 ++++++++++--------- 11 files changed, 114 insertions(+), 174 deletions(-) delete mode 100644 test/python/testSPHTurbulentField.py diff --git a/include/mpc/magneticField/MagneticFieldGrid.h b/include/mpc/magneticField/MagneticFieldGrid.h index 901953fa9..00ccc0bf1 100644 --- a/include/mpc/magneticField/MagneticFieldGrid.h +++ b/include/mpc/magneticField/MagneticFieldGrid.h @@ -13,42 +13,40 @@ namespace mpc { This class provides a container for a VectorFieldGrid (PeriodicGrid of type Vector3f) to serve as a MagneticField. */ class MagneticFieldGrid: public MagneticField { - VectorFieldGrid *grid; + ref_ptr grid; public: - MagneticFieldGrid(VectorFieldGrid *grid); - void setGrid(VectorFieldGrid *grid); - VectorFieldGrid *getGrid(); + MagneticFieldGrid(ref_ptr grid); + void setGrid(ref_ptr grid); + ref_ptr getGrid(); Vector3d getField(const Vector3d &position) const; }; /** @class MagneticFieldGrid @brief Modulated magnetic field on a periodic grid. - - The class */ class ModulatedMagneticFieldGrid: public MagneticField { - VectorFieldGrid *grid; - ScalarFieldGrid *modGrid; + ref_ptr grid; + ref_ptr modGrid; public: - ModulatedMagneticFieldGrid(VectorFieldGrid *grid, ScalarFieldGrid *modGrid); - void setGrid(VectorFieldGrid *grid); - void setModulationGrid(ScalarFieldGrid *modGrid); - VectorFieldGrid *getGrid(); - ScalarFieldGrid *getModulationGrid(); + ModulatedMagneticFieldGrid(ref_ptr grid, ref_ptr modGrid); + void setGrid(ref_ptr grid); + void setModulationGrid(ref_ptr modGrid); + ref_ptr getGrid(); + ref_ptr getModulationGrid(); Vector3d getField(const Vector3d &position) const; }; /** Calculate the mean field strength */ -Vector3f meanFieldStrength(VectorFieldGrid *m); +Vector3f meanFieldStrength(ref_ptr m); /** Calculate the RMS field strength */ -double rmsFieldStrength(VectorFieldGrid *m); +double rmsFieldStrength(ref_ptr m); /** Multiply a magnetic field grid by a factor. */ -void scale(VectorFieldGrid *m, double a); +void scale(ref_ptr m, double a); #ifdef MPC_HAVE_FFTW3F /** @@ -59,7 +57,7 @@ void scale(VectorFieldGrid *m, double a); * @param Brms RMS field strength * @param seed Random seed */ -void initTurbulence(VectorFieldGrid *m, double Brms, double lMin, +void initTurbulence(ref_ptr m, double Brms, double lMin, double lMax, double spectralIndex = -11. / 3., int seed = 0); /** Analytically calculate the correlation length of a turbulent field */ @@ -71,14 +69,14 @@ double turbulentCorrelationLength(double lMin, double lMax, double spectralIndex * The field is stored single precision numbers with the field components in xyz order and the grid z-index changing the fastest. * @param c conversion of the values in the file to SI */ -void load(VectorFieldGrid *m, std::string filename, double c = 1); +void load(ref_ptr m, std::string filename, double c = 1); /** * Dump a magnetic field grid to a binary file. * The field is stored single precision numbers with the field components in xyz order and the grid z-index changing the fastest. * @param c conversion of the values in the file to SI */ -void dump(VectorFieldGrid *m, std::string filename, double c = 1); +void dump(ref_ptr m, std::string filename, double c = 1); /** * Load a magnetic field grid from a plain text file. @@ -87,7 +85,7 @@ void dump(VectorFieldGrid *m, std::string filename, double c = 1); * Header lines must start with a #. * @param c conversion of the values in the file to SI */ -void loadTxt(VectorFieldGrid *m, std::string filename, double c = 1); +void loadTxt(ref_ptr m, std::string filename, double c = 1); /** * Dump a magnetic field grid to a plain text file. @@ -96,7 +94,7 @@ void loadTxt(VectorFieldGrid *m, std::string filename, double c = 1); * Header lines must start with a #. * @param c conversion of SI to the values in the file */ -void dumpTxt(VectorFieldGrid *m, std::string filename, double c = 1); +void dumpTxt(ref_ptr m, std::string filename, double c = 1); } // namespace mpc diff --git a/include/mpc/magneticField/PeriodicGrid.h b/include/mpc/magneticField/PeriodicGrid.h index 345e5d3ee..55567281d 100644 --- a/include/mpc/magneticField/PeriodicGrid.h +++ b/include/mpc/magneticField/PeriodicGrid.h @@ -22,7 +22,7 @@ inline void periodicClamp(double x, int n, int &lo, int &hi) { The grid sample positions are at 0, size/N, ... (N-1) * size/N. */ template -class PeriodicGrid { +class PeriodicGrid : public Referenced { std::vector grid; Vector3d origin; size_t Nx, Ny, Nz; @@ -126,8 +126,8 @@ class PeriodicGrid { } }; -typedef PeriodicGrid VectorFieldGrid; -typedef PeriodicGrid ScalarFieldGrid; +typedef PeriodicGrid VectorGrid; +typedef PeriodicGrid ScalarGrid; } // namespace mpc diff --git a/include/mpc/module/DeflectionCK.h b/include/mpc/module/DeflectionCK.h index 41637d9d6..4b943500b 100644 --- a/include/mpc/module/DeflectionCK.h +++ b/include/mpc/module/DeflectionCK.h @@ -18,12 +18,12 @@ namespace mpc { */ class DeflectionCK: public Module { public: - MagneticField *field; + ref_ptr field; ExplicitRungeKutta erk; double tolerance; double minStep; - DeflectionCK(MagneticField *field, double tolerance = 1e-4, double minimumStep = 0.1 * kpc); + DeflectionCK(ref_ptr field, double tolerance = 1e-4, double minimumStep = 0.1 * kpc); std::string getDescription() const; void process(Candidate *candidate) const; }; diff --git a/python/mpc.i b/python/mpc.i index a15b7d499..c0165eacc 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -47,6 +47,7 @@ #include "mpc/Common.h" %} + %exception { try @@ -61,6 +62,7 @@ } } + %ignore operator<<; %ignore operator>>; @@ -73,18 +75,20 @@ %feature("ref") mpc::Referenced "$this->addReference();" %feature("unref") mpc::Referenced "$this->removeReference();" -%include "mpc/Referenced.h" -%include "mpc/Units.h" -%include "mpc/Nucleus.h" -%include "mpc/Common.h" %include "mpc/Vector3.h" %template(Vector3d) mpc::Vector3; %template(Vector3f) mpc::Vector3; + +%include "mpc/Referenced.h" +%include "mpc/Units.h" +%include "mpc/Nucleus.h" +%include "mpc/Common.h" %include "mpc/Random.h" %include "mpc/ParticleState.h" + %template(SourceRefPtr) mpc::ref_ptr; %include "mpc/Source.h" @@ -96,14 +100,21 @@ %template(stdModuleList) std::list< mpc::ref_ptr >; %include "mpc/Module.h" -%template(stdMagneticFieldVector) std::vector< mpc::ref_ptr >; + +%implicitconv mpc::ref_ptr; %template(MagneticFieldRefPtr) mpc::ref_ptr; %include "mpc/magneticField/MagneticField.h" %include "mpc/magneticField/UniformMagneticField.h" %include "mpc/magneticField/PeriodicGrid.h" -%template(VectorFieldGrid) mpc::PeriodicGrid >; -%template(ScalarFieldGrid) mpc::PeriodicGrid; + +%implicitconv mpc::ref_ptr > >; +%template(VectorGridRefPtr) mpc::ref_ptr > >; +%template(VectorGrid) mpc::PeriodicGrid >; + +%implicitconv mpc::ref_ptr >; +%template(ScalarGridRefPtr) mpc::ref_ptr >; +%template(ScalarGrid) mpc::PeriodicGrid; %include "mpc/magneticField/MagneticFieldGrid.h" %include "mpc/magneticField/SPHMagneticField.h" @@ -111,6 +122,7 @@ %include "mpc/ExplicitRungeKutta.h" %include "mpc/PhasePoint.h" + %include "mpc/module/BreakCondition.h" %include "mpc/module/SimplePropagation.h" %include "mpc/module/DeflectionCK.h" @@ -122,5 +134,7 @@ %include "mpc/module/PhotoDisintegration.h" %include "mpc/module/Redshift.h" %include "mpc/module/Tools.h" + + %template(ModuleListRefPtr) mpc::ref_ptr; %include "mpc/ModuleList.h" \ No newline at end of file diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 86d95b27f..68e5b6e05 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -195,7 +195,7 @@ void XmlExecute::loadGridMagneticField(xml_node &node) { size.y = Ny * spacing; size.z = Nz * spacing; - VectorFieldGrid *field = new VectorFieldGrid(origin, Nx, Ny, Nz, spacing); + ref_ptr field = new VectorGrid(origin, Nx, Ny, Nz, spacing); std::string type = node.attribute("type").as_string(); if (type == "LSS-Grid") { diff --git a/src/magneticField/MagneticFieldGrid.cpp b/src/magneticField/MagneticFieldGrid.cpp index 904aa6371..770437c70 100644 --- a/src/magneticField/MagneticFieldGrid.cpp +++ b/src/magneticField/MagneticFieldGrid.cpp @@ -4,15 +4,15 @@ namespace mpc { -MagneticFieldGrid::MagneticFieldGrid(VectorFieldGrid *grid) { +MagneticFieldGrid::MagneticFieldGrid(ref_ptr grid) { setGrid(grid); } -void MagneticFieldGrid::setGrid(VectorFieldGrid *grid) { +void MagneticFieldGrid::setGrid(ref_ptr grid) { this->grid = grid; } -VectorFieldGrid *MagneticFieldGrid::getGrid() { +ref_ptr MagneticFieldGrid::getGrid() { return grid; } @@ -20,25 +20,25 @@ Vector3d MagneticFieldGrid::getField(const Vector3d &pos) const { return grid->interpolate(pos); } -ModulatedMagneticFieldGrid::ModulatedMagneticFieldGrid(VectorFieldGrid *grid, - ScalarFieldGrid *modGrid) { +ModulatedMagneticFieldGrid::ModulatedMagneticFieldGrid(ref_ptr grid, + ref_ptr modGrid) { setGrid(grid); setModulationGrid(modGrid); } -void ModulatedMagneticFieldGrid::setGrid(VectorFieldGrid *g) { +void ModulatedMagneticFieldGrid::setGrid(ref_ptr g) { grid = g; } -VectorFieldGrid *ModulatedMagneticFieldGrid::getGrid() { +ref_ptr ModulatedMagneticFieldGrid::getGrid() { return grid; } -void ModulatedMagneticFieldGrid::setModulationGrid(ScalarFieldGrid *g) { +void ModulatedMagneticFieldGrid::setModulationGrid(ref_ptr g) { modGrid = g; } -ScalarFieldGrid *ModulatedMagneticFieldGrid::getModulationGrid() { +ref_ptr ModulatedMagneticFieldGrid::getModulationGrid() { return modGrid; } @@ -48,7 +48,7 @@ Vector3d ModulatedMagneticFieldGrid::getField(const Vector3d &pos) const { return b * m; } -Vector3f meanFieldStrength(VectorFieldGrid *m) { +Vector3f meanFieldStrength(ref_ptr m) { size_t Nx = m->getNx(); size_t Ny = m->getNy(); size_t Nz = m->getNz(); @@ -60,7 +60,7 @@ Vector3f meanFieldStrength(VectorFieldGrid *m) { return mean / Nx / Ny / Nz; } -double rmsFieldStrength(VectorFieldGrid *m) { +double rmsFieldStrength(ref_ptr m) { size_t Nx = m->getNx(); size_t Ny = m->getNy(); size_t Nz = m->getNz(); @@ -72,7 +72,7 @@ double rmsFieldStrength(VectorFieldGrid *m) { return sqrt(sumB2 / Nx / Ny / Nz); } -void scale(VectorFieldGrid *m, double a) { +void scale(ref_ptr m, double a) { for (int ix = 0; ix < m->getNx(); ix++) for (int iy = 0; iy < m->getNy(); iy++) for (int iz = 0; iz < m->getNz(); iz++) @@ -82,8 +82,8 @@ void scale(VectorFieldGrid *m, double a) { #ifdef MPC_HAVE_FFTW3F #include "fftw3.h" -void initTurbulence(VectorFieldGrid *m, double Brms, double lMin, double lMax, - double spectralIndex, int seed) { +void initTurbulence(ref_ptr m, double Brms, double lMin, + double lMax, double spectralIndex, int seed) { size_t Nx = m->getNx(); size_t Ny = m->getNy(); size_t Nz = m->getNz(); @@ -223,7 +223,7 @@ double turbulentCorrelationLength(double lMin, double lMax, return lMax / 2 * (a - 1) / a * (1 - pow(r, a)) / (1 - pow(r, a - 1)); } #endif // MPC_HAVE_FFTW3F -void load(VectorFieldGrid *m, std::string filename, double c) { +void load(ref_ptr m, std::string filename, double c) { std::ifstream fin(filename.c_str(), std::ios::binary); if (!fin) throw std::runtime_error("MagneticFieldGrid: File not found"); @@ -241,7 +241,7 @@ void load(VectorFieldGrid *m, std::string filename, double c) { fin.close(); } -void dump(VectorFieldGrid *m, std::string filename, double c) { +void dump(ref_ptr m, std::string filename, double c) { std::ofstream fout(filename.c_str(), std::ios::binary); if (!fout) throw std::runtime_error("MagneticFieldGrid: Could not open file"); @@ -258,7 +258,7 @@ void dump(VectorFieldGrid *m, std::string filename, double c) { fout.close(); } -void loadTxt(VectorFieldGrid *m, std::string filename, double unit) { +void loadTxt(ref_ptr m, std::string filename, double unit) { std::ifstream fin(filename.c_str()); if (!fin) throw std::runtime_error("MagneticFieldGrid: file not found"); @@ -282,7 +282,7 @@ void loadTxt(VectorFieldGrid *m, std::string filename, double unit) { fin.close(); } -void dumpTxt(VectorFieldGrid *m, std::string filename, double unit) { +void dumpTxt(ref_ptr m, std::string filename, double unit) { std::ofstream fout(filename.c_str()); if (!fout) throw std::runtime_error("MagneticFieldGrid: could not open file"); diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index 86138dbed..10444c3c1 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -36,7 +36,7 @@ class LorentzForce: public ExplicitRungeKutta::F { } }; -DeflectionCK::DeflectionCK(MagneticField *field, double tolerance, +DeflectionCK::DeflectionCK(ref_ptr field, double tolerance, double minStep) { this->field = field; this->tolerance = tolerance; diff --git a/test/python/testSPHTurbulentField.py b/test/python/testSPHTurbulentField.py deleted file mode 100644 index 6c4d22687..000000000 --- a/test/python/testSPHTurbulentField.py +++ /dev/null @@ -1,75 +0,0 @@ -from mpc import * -from pylab import * - - -# parameters -lo = 80 -hi = 160 -origin = Vector3d(lo * Mpc) -N = 128 -size = (hi - lo) * Mpc -spacing = size / N -lMin = 2 * spacing -lMax = 16 * spacing -Brms = 1 -alpha = -11./3 - -# create field -field = SPHTurbulentMagneticField(origin, size, N) -print 'initialize' -field.initialize(lMin, lMax, Brms, alpha) -print 'modulate' -field.modulate(getDataPath("SPH/mhd_z.db"), 2./3) -print 'evaluate' - -# plot a slice -A = zeros((N,N)) -for ix in range(N): - for iy in range(N): - b = field.getField(origin + Vector3d(ix, iy, N/2) * spacing) - A[ix,iy] = b.getMag() - -figure() -im = imshow(log10(A), origin='lower', extent=[lo, hi, lo, hi], vmin=-2, vmax=2) -cbar = colorbar(im) -cbar.set_label('$\log_{10}(B/B_{rms})$') -xlabel('x [Mpc]') -ylabel('y [Mpc]') -savefig('SPHTurbulentField_slice.png', bbox_inches='tight') - -# sample the effective rms field strengths -brms = 0 -r = Random() -for i in range(1000): - x = Vector3d(r.rand(), r.rand(), r.rand()) * size + origin - brms += field.getField(x).getMag2() -brms = (brms / 1000)**.5 -print 'effective Brms =', brms, 'of nominal Brms' - -# sample the coherence length -def getCorrelationCurve(): - x = Vector3d(r.rand(), r.rand(), r.rand()) * size + origin - d = r.randUnitVectorOnSphere() - b = field.getField(x) - b.normalize() - c = zeros(nSteps) - for i in range(nSteps): - b2 = field.getField(x + Vector3d(d.x, d.y, d.z) * i * step) - b2.normalize() - c[i] = b.dot(b2) - return c - -nSteps = 100 -step = lMax / 2 / nSteps # choose so that lc_unmodulated < nStep * step < size - -cMean = zeros(nSteps) -for i in range(1000): - cMean += getCorrelationCurve() / 1000 -lc = (2 * sum(cMean[1:]) + cMean[0]) * step / Mpc - -plot(arange(0, nSteps) * step / Mpc, cMean) -xlabel('Linear Separation [Mpc]') -ylabel('Autocorrelation') -text(0.35, 0.95, 'Coherence Length %.1f Mpc'%lc, ha='left', va='top', transform=gca().transAxes) -savefig('SPHTurbulentField_coherenceLength.png', bbox_inches='tight') - diff --git a/test/python/testTurbulentDeflection.py b/test/python/testTurbulentDeflection.py index dc9204bb0..9f0e7e626 100644 --- a/test/python/testTurbulentDeflection.py +++ b/test/python/testTurbulentDeflection.py @@ -8,9 +8,9 @@ nP = range(30) # sampling points for plot # create turbulent field with B_RMS = 1 nG and 0.5 Mpc correlation length -field = MagneticFieldGrid(Vector3d(0, 0, 0), 128, 0.05 * Mpc) -initTurbulence(field, 1 * nG, 0.1 * Mpc, 2.2 * Mpc, -11/3.) -propa = DeflectionCK(field) +vGrid = VectorGrid(Vector3d(0, 0, 0), 128, 0.05 * Mpc) +initTurbulence(vGrid, 1 * nG, 0.1 * Mpc, 2.2 * Mpc, -11/3.) +propa = DeflectionCK(MagneticFieldGrid(vGrid)) Lc = turbulentCorrelationLength(0.1 * Mpc, 2.2 * Mpc, -11/3.) / Mpc Brms = 1 # nG @@ -22,7 +22,7 @@ for j in range(nT): if j % (nT // 10) == 0: print j - + ps = ParticleState() ps.setId(getNucleusId(1, 1)) ps.setEnergy(E * EeV) diff --git a/test/python/testTurbulentFieldGrid.py b/test/python/testTurbulentFieldGrid.py index 56f0dd1c5..40dc4df96 100644 --- a/test/python/testTurbulentFieldGrid.py +++ b/test/python/testTurbulentFieldGrid.py @@ -84,18 +84,18 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): lMin, lMax = 2, 32 Brms = 1. alpha = -11./3 -field = MagneticFieldGrid(origin, n, spacing) -initTurbulence(field, Brms, lMin, lMax, alpha) - Lc = turbulentCorrelationLength(lMin, lMax, alpha) +vGrid = VectorGrid(origin, n, spacing) +initTurbulence(vGrid, Brms, lMin, lMax, alpha) + ### copy field grid to array(s) Bx, By, Bz = zeros((3, n, n, n)) for ix in range(n): print ix for iy in range(n): for iz in range(n): - b = field.get(ix, iy, iz) + b = vGrid.get(ix, iy, iz) Bx[ix, iy, iz] = b.x By[ix, iy, iz] = b.y Bz[ix, iy, iz] = b.z diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index 62a7b0806..65d8c1ef6 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -33,7 +33,7 @@ TEST(testVectorFieldGrid, PeriodicClamp) { TEST(testVectorFieldGrid, SimpleTest) { // Test construction and parameters - VectorFieldGrid B(Vector3d(1., 2., 3.), 4, 2.5); + VectorGrid B(Vector3d(1., 2., 3.), 4, 2.5); EXPECT_TRUE(Vector3d(1., 2., 3.) == B.getOrigin()); EXPECT_EQ(4, B.getNx()); EXPECT_EQ(4, B.getNy()); @@ -44,7 +44,7 @@ TEST(testVectorFieldGrid, SimpleTest) { TEST(testVectorFieldGrid, Interpolation) { // Explicitly test trilinear interpolation double spacing = 2.793; - VectorFieldGrid grid(Vector3d(0.), 3, spacing); + VectorGrid grid(Vector3d(0.), 3, spacing); grid.get(0, 0, 1) = Vector3f(1.7, 0., 0.); // set one value Vector3d b; @@ -66,17 +66,17 @@ TEST(testVectorFieldGrid, Interpolation) { TEST(testVectorFieldGrid, Scale) { // Test scaling a field - VectorFieldGrid grid(Vector3d(0.), 3, 1); + ref_ptr grid = new VectorGrid(Vector3d(0.), 3, 1); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) - grid.get(ix, iy, iz) = Vector3f(1, 0, 0); + grid->get(ix, iy, iz) = Vector3f(1, 0, 0); - scale(&grid, 5); + scale(grid, 5); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) - EXPECT_FLOAT_EQ(5, grid.interpolate(Vector3d(0.7, 0, 0.1)).x); + EXPECT_FLOAT_EQ(5, grid->interpolate(Vector3d(0.7, 0, 0.1)).x); } TEST(testVectorFieldGrid, Periodicity) { @@ -84,7 +84,7 @@ TEST(testVectorFieldGrid, Periodicity) { size_t n = 3; double spacing = 3; double size = n * spacing; - VectorFieldGrid grid(Vector3d(0.), n, spacing); + VectorGrid grid(Vector3d(0.), n, spacing); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) @@ -110,21 +110,22 @@ TEST(testVectorFieldGrid, Periodicity) { TEST(testVectorFieldGrid, DumpLoad) { // Dump and load a field grid - VectorFieldGrid B1(Vector3d(0.), 3, 1); + ref_ptr B1 = new VectorGrid(Vector3d(0.), 3, 1); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) - B1.get(ix, iy, iz) = Vector3f(1, 2, 3); - dump(&B1, getDataPath("../test/testDump.raw")); + B1->get(ix, iy, iz) = Vector3f(1, 2, 3); - VectorFieldGrid B2(Vector3d(0.), 3, 1); - load(&B2, getDataPath("../test/testDump.raw")); + dump(B1, "testDump.raw"); + + ref_ptr B2 = new VectorGrid(Vector3d(0.), 3, 1); + load(B2, "testDump.raw"); for (int ix = 0; ix < 3; ix++) { for (int iy = 0; iy < 3; iy++) { for (int iz = 0; iz < 3; iz++) { - Vector3f b1 = B1.get(ix, iy, iz); - Vector3f b2 = B2.get(ix, iy, iz); + Vector3f b1 = B1->get(ix, iy, iz); + Vector3f b2 = B2->get(ix, iy, iz); EXPECT_FLOAT_EQ(b1.x, b2.x); EXPECT_FLOAT_EQ(b1.y, b2.y); EXPECT_FLOAT_EQ(b1.z, b2.z); @@ -135,21 +136,22 @@ TEST(testVectorFieldGrid, DumpLoad) { TEST(testVectorFieldGrid, DumpLoadTxt) { // Dump and load a field grid - VectorFieldGrid B1(Vector3d(0.), 3, 1); + ref_ptr B1 = new VectorGrid(Vector3d(0.), 3, 1); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) - B1.get(ix, iy, iz) = Vector3f(ix, iy, iz) * nG; - dumpTxt(&B1, getDataPath("../test/testDump.txt"), 1e4); + B1->get(ix, iy, iz) = Vector3f(ix, iy, iz) * nG; + + dumpTxt(B1, "testDump.txt", 1e4); - VectorFieldGrid B2(Vector3d(0.), 3, 1); - loadTxt(&B2, getDataPath("../test/testDump.txt"), 1e-4); + ref_ptr B2 = new VectorGrid(Vector3d(0.), 3, 1); + loadTxt(B2, "testDump.txt", 1e-4); for (int ix = 0; ix < 3; ix++) { for (int iy = 0; iy < 3; iy++) { for (int iz = 0; iz < 3; iz++) { - Vector3f b1 = B1.get(ix, iy, iz); - Vector3f b2 = B2.get(ix, iy, iz); + Vector3f b1 = B1->get(ix, iy, iz); + Vector3f b2 = B2->get(ix, iy, iz); EXPECT_FLOAT_EQ(b1.x, b2.x); EXPECT_FLOAT_EQ(b1.y, b2.y); EXPECT_FLOAT_EQ(b1.z, b2.z); @@ -160,7 +162,7 @@ TEST(testVectorFieldGrid, DumpLoadTxt) { TEST(testVectorFieldGrid, Speed) { // Dump and load a field grid - VectorFieldGrid grid(Vector3d(0.), 3, 3); + VectorGrid grid(Vector3d(0.), 3, 3); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) @@ -179,18 +181,19 @@ TEST(testVectorFieldGrid, Turbulence_bmean_brms) { double Brms = 1; double lMin = 2 * spacing; double lMax = 8 * spacing; - VectorFieldGrid grid(Vector3d(0, 0, 0), n, spacing); - initTurbulence(&grid, Brms, lMin, lMax); + + ref_ptr grid = new VectorGrid(Vector3d(0, 0, 0), n, spacing); + initTurbulence(grid, Brms, lMin, lMax); double precision = 1e-7; - Vector3f bMean = meanFieldStrength(&grid); + Vector3f bMean = meanFieldStrength(grid); EXPECT_NEAR(0, bMean.x, precision); EXPECT_NEAR(0, bMean.y, precision); EXPECT_NEAR(0, bMean.z, precision); - EXPECT_NEAR(1, rmsFieldStrength(&grid), precision); + EXPECT_NEAR(1, rmsFieldStrength(grid), precision); } -TEST(testMagneticFieldGrid, Turbulence_seed) { +TEST(testVectorFieldGrid, Turbulence_seed) { // Test if seeding produces 2 identical fields size_t n = 64; double spacing = 1 * Mpc; @@ -200,33 +203,33 @@ TEST(testMagneticFieldGrid, Turbulence_seed) { double index = -11. / 3.; int seed = 753; - VectorFieldGrid grid1(Vector3d(0, 0, 0), n, spacing); - initTurbulence(&grid1, Brms, lMin, lMax, index, seed); + ref_ptr grid1 = new VectorGrid(Vector3d(0, 0, 0), n, spacing); + initTurbulence(grid1, Brms, lMin, lMax, index, seed); - VectorFieldGrid grid2(Vector3d(0, 0, 0), n, spacing); - initTurbulence(&grid2, Brms, lMin, lMax, index, seed); + ref_ptr grid2 = new VectorGrid(Vector3d(0, 0, 0), n, spacing); + initTurbulence(grid2, Brms, lMin, lMax, index, seed); Vector3d pos(22 * Mpc); - EXPECT_FLOAT_EQ(grid1.interpolate(pos).x, grid2.interpolate(pos).x); + EXPECT_FLOAT_EQ(grid1->interpolate(pos).x, grid2->interpolate(pos).x); } -TEST(testMagneticFieldGrid, turbulence_Exceptions) { +TEST(testVectorFieldGrid, turbulence_Exceptions) { // Test exceptions size_t n = 64; double spacing = 10 * Mpc / n; double brms = 1; - VectorFieldGrid grid(Vector3d(0, 0, 0), n, spacing); + ref_ptr grid = new VectorGrid(Vector3d(0, 0, 0), n, spacing); // should be fine - EXPECT_NO_THROW(initTurbulence(&grid, brms, 2 * spacing, 8 * spacing)); + EXPECT_NO_THROW(initTurbulence(grid, brms, 2 * spacing, 8 * spacing)); // lMin too small - EXPECT_THROW(initTurbulence(&grid, brms, 1.5 * spacing, 8 * spacing), + EXPECT_THROW(initTurbulence(grid, brms, 1.5 * spacing, 8 * spacing), std::runtime_error); // lMin > lMax - EXPECT_THROW(initTurbulence(&grid, brms, 8.1 * spacing, 8 * spacing), + EXPECT_THROW(initTurbulence(grid, brms, 8.1 * spacing, 8 * spacing), std::runtime_error); // lMax too large - EXPECT_THROW(initTurbulence(&grid, brms, 2 * spacing, 33 * spacing), + EXPECT_THROW(initTurbulence(grid, brms, 2 * spacing, 33 * spacing), std::runtime_error); } #endif // MPC_HAVE_FFTW3F From ba81d6410d3ac73f2287afb7b4e76959a154a757 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 25 Jul 2012 15:24:55 +0200 Subject: [PATCH 0156/1298] fix FTBFS when no FFTW3F --- include/mpc/magneticField/MagneticFieldGrid.h | 48 +++++++++---------- src/XmlExecute.cpp | 5 ++ src/magneticField/MagneticFieldGrid.cpp | 3 +- 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/include/mpc/magneticField/MagneticFieldGrid.h b/include/mpc/magneticField/MagneticFieldGrid.h index 00ccc0bf1..fdd2d00bc 100644 --- a/include/mpc/magneticField/MagneticFieldGrid.h +++ b/include/mpc/magneticField/MagneticFieldGrid.h @@ -50,49 +50,49 @@ void scale(ref_ptr m, double a); #ifdef MPC_HAVE_FFTW3F /** - * Create a random initialization of a turbulent field. - * @param lMin Minimum wavelength of the turbulence - * @param lMax Maximum wavelength of the turbulence - * @param spectralIndex Power spectral index of the turbulence (-11/3 corresponds to a Kolmogorov spectrum) - * @param Brms RMS field strength - * @param seed Random seed + Create a random initialization of a turbulent field. + @param lMin Minimum wavelength of the turbulence + @param lMax Maximum wavelength of the turbulence + @param index Power spectral index of the turbulence (-11/3 corresponds to a Kolmogorov spectrum) + @param Brms RMS field strength + @param seed Random seed */ void initTurbulence(ref_ptr m, double Brms, double lMin, - double lMax, double spectralIndex = -11. / 3., int seed = 0); + double lMax, double index = -11. / 3., int seed = 0); +#endif // MPC_HAVE_FFTW3F /** Analytically calculate the correlation length of a turbulent field */ double turbulentCorrelationLength(double lMin, double lMax, double spectralIndex = -11. / 3.); -#endif // MPC_HAVE_FFTW3F /** - * Load a magnetic field grid from a binary file. - * The field is stored single precision numbers with the field components in xyz order and the grid z-index changing the fastest. - * @param c conversion of the values in the file to SI + Load a magnetic field grid from a binary file. + The field is stored single precision numbers with the field components in xyz order and the grid z-index changing the fastest. + @param c conversion of the values in the file to SI */ void load(ref_ptr m, std::string filename, double c = 1); /** - * Dump a magnetic field grid to a binary file. - * The field is stored single precision numbers with the field components in xyz order and the grid z-index changing the fastest. - * @param c conversion of the values in the file to SI + Dump a magnetic field grid to a binary file. + The field is stored single precision numbers with the field components in xyz order and the grid z-index changing the fastest. + @param c conversion of the values in the file to SI */ void dump(ref_ptr m, std::string filename, double c = 1); /** - * Load a magnetic field grid from a plain text file. - * The field is stored as one grid point per line from (0,0,0) to (nx, ny, nz) with the grid z-index changing the fastest. - * Within one line the magnetic field values are stored in xyz order separated by a blank or tab. - * Header lines must start with a #. - * @param c conversion of the values in the file to SI + Load a magnetic field grid from a plain text file. + The field is stored as one grid point per line from (0,0,0) to (nx, ny, nz) with the grid z-index changing the fastest. + Within one line the magnetic field values are stored in xyz order separated by a blank or tab. + Header lines must start with a #. + @param c conversion of the values in the file to SI */ void loadTxt(ref_ptr m, std::string filename, double c = 1); /** - * Dump a magnetic field grid to a plain text file. - * The field is stored as one grid point per line from (0,0,0) to (nx, ny, nz) with the grid z-index changing the fastest. - * Within one line the magnetic field values are stored in xyz order separated by a blank or tab. - * Header lines must start with a #. - * @param c conversion of SI to the values in the file + Dump a magnetic field grid to a plain text file. + The field is stored as one grid point per line from (0,0,0) to (nx, ny, nz) with the grid z-index changing the fastest. + Within one line the magnetic field values are stored in xyz order separated by a blank or tab. + Header lines must start with a #. + @param c conversion of SI to the values in the file */ void dumpTxt(ref_ptr m, std::string filename, double c = 1); diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 68e5b6e05..fbbdc65bb 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -221,7 +221,12 @@ void XmlExecute::loadGridMagneticField(xml_node &node) { cout << " - Turbulence spectral index: " << alpha << endl; cout << " - Random seed: " << randomSeed << endl; +#ifdef MPC_HAVE_FFTW3F initTurbulence(field, brms, lMin, lMax, alpha, randomSeed); +#endif // MPC_HAVE_FFTW3F +#ifndef MPC_HAVE_FFTW3F + throw runtime_error("Turbulent field grid not available. Compile with FFTW3F."); +#endif // MPC_HAVE_FFTW3F } magnetic_field = new MagneticFieldGrid(field); diff --git a/src/magneticField/MagneticFieldGrid.cpp b/src/magneticField/MagneticFieldGrid.cpp index 770437c70..c1e5a518c 100644 --- a/src/magneticField/MagneticFieldGrid.cpp +++ b/src/magneticField/MagneticFieldGrid.cpp @@ -215,6 +215,7 @@ void initTurbulence(ref_ptr m, double Brms, double lMin, scale(m, Brms / rmsFieldStrength(m)); // normalize to Brms } +#endif // MPC_HAVE_FFTW3F double turbulentCorrelationLength(double lMin, double lMax, double spectralIndex) { @@ -222,7 +223,7 @@ double turbulentCorrelationLength(double lMin, double lMax, double a = -spectralIndex - 2; return lMax / 2 * (a - 1) / a * (1 - pow(r, a)) / (1 - pow(r, a - 1)); } -#endif // MPC_HAVE_FFTW3F + void load(ref_ptr m, std::string filename, double c) { std::ifstream fin(filename.c_str(), std::ios::binary); if (!fin) From edae0927b2d2c62733d9d7745498be827fece4fe Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 26 Jul 2012 10:30:32 +0200 Subject: [PATCH 0157/1298] refactored PeriodicGrid --- CMakeLists.txt | 1 + .../mpc/{magneticField => }/PeriodicGrid.h | 1 + include/mpc/Referenced.h | 2 + include/mpc/magneticField/MagneticFieldGrid.h | 65 +---- include/mpc/module/BreakCondition.h | 24 +- python/mpc.i | 6 +- src/XmlExecute.cpp | 1 + src/magneticField/MagneticFieldGrid.cpp | 252 ------------------ src/module/BreakCondition.cpp | 26 ++ test/testBreakCondition.cpp | 17 ++ test/testMagneticField.cpp | 3 +- 11 files changed, 81 insertions(+), 317 deletions(-) rename include/mpc/{magneticField => }/PeriodicGrid.h (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 817df69cf..5b8487522 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,6 +86,7 @@ add_library(mpc SHARED src/Source.cpp src/Common.cpp src/Nucleus.cpp + src/PeriodicGridTools.cpp src/XmlExecute.cpp src/module/BreakCondition.cpp src/module/SimplePropagation.cpp diff --git a/include/mpc/magneticField/PeriodicGrid.h b/include/mpc/PeriodicGrid.h similarity index 99% rename from include/mpc/magneticField/PeriodicGrid.h rename to include/mpc/PeriodicGrid.h index 55567281d..f4fe522ee 100644 --- a/include/mpc/magneticField/PeriodicGrid.h +++ b/include/mpc/PeriodicGrid.h @@ -1,6 +1,7 @@ #ifndef MPC_PERIODICGRID_H_ #define MPC_PERIODICGRID_H_ +#include "mpc/Referenced.h" #include "mpc/Vector3.h" #include diff --git a/include/mpc/Referenced.h b/include/mpc/Referenced.h index 1947655c5..cfd93124c 100644 --- a/include/mpc/Referenced.h +++ b/include/mpc/Referenced.h @@ -1,6 +1,8 @@ #ifndef MPC_REFERENCED_H #define MPC_REFERENCED_H +#include + #ifdef DEBUG #include #include diff --git a/include/mpc/magneticField/MagneticFieldGrid.h b/include/mpc/magneticField/MagneticFieldGrid.h index fdd2d00bc..c25e490c1 100644 --- a/include/mpc/magneticField/MagneticFieldGrid.h +++ b/include/mpc/magneticField/MagneticFieldGrid.h @@ -2,7 +2,7 @@ #define MPC_MAGNETICFIELDGRID_H_ #include "mpc/magneticField/MagneticField.h" -#include "mpc/magneticField/PeriodicGrid.h" +#include "mpc/PeriodicGrid.h" namespace mpc { @@ -10,7 +10,7 @@ namespace mpc { @class MagneticFieldGrid @brief Magnetic field on a periodic, cartesian grid with trilinear interpolation. - This class provides a container for a VectorFieldGrid (PeriodicGrid of type Vector3f) to serve as a MagneticField. + This class provides a container for a VectorGrid (PeriodicGrid of type Vector3f) to serve as a MagneticField. */ class MagneticFieldGrid: public MagneticField { ref_ptr grid; @@ -25,6 +25,10 @@ class MagneticFieldGrid: public MagneticField { /** @class MagneticFieldGrid @brief Modulated magnetic field on a periodic grid. + + This class provides a container for a VectorGrid to serve as a MagneticField. + The field is modulated on-the-fly with a ScalarGrid. + The VectorGrid and ScalarGrid do not need to share the same origin, spacing or size. */ class ModulatedMagneticFieldGrid: public MagneticField { ref_ptr grid; @@ -39,63 +43,6 @@ class ModulatedMagneticFieldGrid: public MagneticField { Vector3d getField(const Vector3d &position) const; }; -/** Calculate the mean field strength */ -Vector3f meanFieldStrength(ref_ptr m); - -/** Calculate the RMS field strength */ -double rmsFieldStrength(ref_ptr m); - -/** Multiply a magnetic field grid by a factor. */ -void scale(ref_ptr m, double a); - -#ifdef MPC_HAVE_FFTW3F -/** - Create a random initialization of a turbulent field. - @param lMin Minimum wavelength of the turbulence - @param lMax Maximum wavelength of the turbulence - @param index Power spectral index of the turbulence (-11/3 corresponds to a Kolmogorov spectrum) - @param Brms RMS field strength - @param seed Random seed - */ -void initTurbulence(ref_ptr m, double Brms, double lMin, - double lMax, double index = -11. / 3., int seed = 0); -#endif // MPC_HAVE_FFTW3F - -/** Analytically calculate the correlation length of a turbulent field */ -double turbulentCorrelationLength(double lMin, double lMax, double spectralIndex = -11. / 3.); - -/** - Load a magnetic field grid from a binary file. - The field is stored single precision numbers with the field components in xyz order and the grid z-index changing the fastest. - @param c conversion of the values in the file to SI - */ -void load(ref_ptr m, std::string filename, double c = 1); - -/** - Dump a magnetic field grid to a binary file. - The field is stored single precision numbers with the field components in xyz order and the grid z-index changing the fastest. - @param c conversion of the values in the file to SI - */ -void dump(ref_ptr m, std::string filename, double c = 1); - -/** - Load a magnetic field grid from a plain text file. - The field is stored as one grid point per line from (0,0,0) to (nx, ny, nz) with the grid z-index changing the fastest. - Within one line the magnetic field values are stored in xyz order separated by a blank or tab. - Header lines must start with a #. - @param c conversion of the values in the file to SI - */ -void loadTxt(ref_ptr m, std::string filename, double c = 1); - -/** - Dump a magnetic field grid to a plain text file. - The field is stored as one grid point per line from (0,0,0) to (nx, ny, nz) with the grid z-index changing the fastest. - Within one line the magnetic field values are stored in xyz order separated by a blank or tab. - Header lines must start with a #. - @param c conversion of SI to the values in the file - */ -void dumpTxt(ref_ptr m, std::string filename, double c = 1); - } // namespace mpc #endif /* MPC_MAGNETICFIELDGRID_H_ */ diff --git a/include/mpc/module/BreakCondition.h b/include/mpc/module/BreakCondition.h index aaa8c5f90..3bcdf24f0 100644 --- a/include/mpc/module/BreakCondition.h +++ b/include/mpc/module/BreakCondition.h @@ -72,10 +72,10 @@ class SmallObserverSphere: public Module { /** @class PeriodicBox - @brief Box with periodic boundaries. + @brief Rectangular box with periodic boundaries. - If a candidate leaves the periodic box it is placed at the opposite side and its initial (source) position changed accordingly. - Candidates can overshoot (be outside of the box during the step) since the step size is not limited by this module. + If a particle passes on of the sides it is placed at the opposite side and its initial (source) position changed accordingly. + Particles can overshoot (be outside of the box during the step) since the step size is not limited by this module. */ class PeriodicBox: public Module { private: @@ -88,6 +88,24 @@ class PeriodicBox: public Module { void process(Candidate *candidate) const; }; +/** + @class AntiperiodicBox + @brief Rectangular box with antiperiodic boundaries. + + If a particle passes on of the sides it is reflected back inside (position and velocity) and its initial position changed as if the particle had come from that side. + Particles can overshoot (be outside of the box during the step) since the step size is not limited by this module. + */ +class ReflectiveBox: public Module { +private: + Vector3d origin; + Vector3d size; + void updateDescription(); + +public: + ReflectiveBox(Vector3d origin, Vector3d size); + void process(Candidate *candidate) const; +}; + /** @class CubicBoundary @brief Flags a particle when exiting the cube. diff --git a/python/mpc.i b/python/mpc.i index c0165eacc..7da4478ce 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -25,10 +25,11 @@ #include "mpc/module/SimplePropagation.h" #include "mpc/module/DeflectionCK.h" #include "mpc/module/Tools.h" +#include "mpc/PeriodicGrid.h" +#include "mpc/PeriodicGridTools.h" #include "mpc/magneticField/MagneticField.h" #include "mpc/magneticField/UniformMagneticField.h" -#include "mpc/magneticField/PeriodicGrid.h" #include "mpc/magneticField/MagneticFieldGrid.h" #include "mpc/magneticField/SPHMagneticField.h" @@ -106,7 +107,8 @@ %include "mpc/magneticField/MagneticField.h" %include "mpc/magneticField/UniformMagneticField.h" -%include "mpc/magneticField/PeriodicGrid.h" +%include "mpc/PeriodicGrid.h" +%include "mpc/PeriodicGridTools.h" %implicitconv mpc::ref_ptr > >; %template(VectorGridRefPtr) mpc::ref_ptr > >; diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index fbbdc65bb..30d92df55 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -1,6 +1,7 @@ #include "mpc/XmlExecute.h" #include "mpc/magneticField/UniformMagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" +#include "mpc/PeriodicGridTools.h" #include "mpc/module/DeflectionCK.h" #include "mpc/module/SimplePropagation.h" #include "mpc/module/Output.h" diff --git a/src/magneticField/MagneticFieldGrid.cpp b/src/magneticField/MagneticFieldGrid.cpp index c1e5a518c..f1d618a49 100644 --- a/src/magneticField/MagneticFieldGrid.cpp +++ b/src/magneticField/MagneticFieldGrid.cpp @@ -1,6 +1,4 @@ #include "mpc/magneticField/MagneticFieldGrid.h" -#include "mpc/Random.h" -#include namespace mpc { @@ -48,254 +46,4 @@ Vector3d ModulatedMagneticFieldGrid::getField(const Vector3d &pos) const { return b * m; } -Vector3f meanFieldStrength(ref_ptr m) { - size_t Nx = m->getNx(); - size_t Ny = m->getNy(); - size_t Nz = m->getNz(); - Vector3f mean(0.); - for (int ix = 0; ix < Nx; ix++) - for (int iy = 0; iy < Ny; iy++) - for (int iz = 0; iz < Nz; iz++) - mean += m->get(ix, iy, iz); - return mean / Nx / Ny / Nz; -} - -double rmsFieldStrength(ref_ptr m) { - size_t Nx = m->getNx(); - size_t Ny = m->getNy(); - size_t Nz = m->getNz(); - double sumB2 = 0; - for (int ix = 0; ix < Nx; ix++) - for (int iy = 0; iy < Ny; iy++) - for (int iz = 0; iz < Nz; iz++) - sumB2 += m->get(ix, iy, iz).getMag2(); - return sqrt(sumB2 / Nx / Ny / Nz); -} - -void scale(ref_ptr m, double a) { - for (int ix = 0; ix < m->getNx(); ix++) - for (int iy = 0; iy < m->getNy(); iy++) - for (int iz = 0; iz < m->getNz(); iz++) - m->get(ix, iy, iz) *= a; -} - -#ifdef MPC_HAVE_FFTW3F -#include "fftw3.h" - -void initTurbulence(ref_ptr m, double Brms, double lMin, - double lMax, double spectralIndex, int seed) { - size_t Nx = m->getNx(); - size_t Ny = m->getNy(); - size_t Nz = m->getNz(); - if ((Nx != Ny) or (Ny != Nz)) - throw std::runtime_error("turbulentField: only cubic grid supported"); - - double spacing = m->getSpacing(); - if (lMin < 2 * spacing) - throw std::runtime_error("turbulentField: lMin < 2 * spacing"); - if (lMin >= lMax) - throw std::runtime_error("turbulentField: lMin >= lMax"); - if (lMax > Nx * spacing / 2) - throw std::runtime_error("turbulentField: lMax > size / 2"); - - size_t n = Nx; // size of array - size_t n2 = (size_t) floor(n / 2) + 1; // size array in z-direction in configuration space - - // arrays to hold the complex vector components of the B(k)-field - fftwf_complex *Bkx, *Bky, *Bkz; - Bkx = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * n * n * n2); - Bky = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * n * n * n2); - Bkz = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * n * n * n2); - - Random random; - if (seed != 0) - random.seed(seed); // use given seed - - // calculate the n possible discrete wave numbers - double K[n]; - for (int i = 0; i < n; i++) - K[i] = (double) i / n - i / (n / 2); - - // construct the field in configuration space - int i; - double k, theta, phase, cosPhase, sinPhase; - double kMin = spacing / lMax; - double kMax = spacing / lMin; - Vector3f b; // real b-field vector - Vector3f ek, e1, e2; // orthogonal base - Vector3f n0(1, 1, 1); // arbitrary vector to construct orthogonal base - - for (size_t ix = 0; ix < n; ix++) { - for (size_t iy = 0; iy < n; iy++) { - for (size_t iz = 0; iz < n2; iz++) { - - i = ix * n * n2 + iy * n2 + iz; - ek.setXYZ(K[ix], K[iy], K[iz]); - k = ek.getMag(); - - // wave outside of turbulent range -> B(k) = 0 - if ((k < kMin) || (k > kMax)) { - Bkx[i][0] = 0; - Bkx[i][1] = 0; - Bky[i][0] = 0; - Bky[i][1] = 0; - Bkz[i][0] = 0; - Bkz[i][1] = 0; - continue; - } - - // construct an orthogonal base ek, e1, e2 - if (ek.getAngleTo(n0) < 1e-3) { - // ek parallel to (1,1,1) - e1.setXYZ(-1., 1., 0); - e2.setXYZ(1., 1., -2.); - } else { - // ek not parallel to (1,1,1) - e1 = n0.cross(ek); - e2 = ek.cross(e1); - } - e1 /= e1.getMag(); - e2 /= e2.getMag(); - - // random orientation perpendicular to k - theta = 2 * M_PI * random.rand(); - b = e1 * cos(theta) + e2 * sin(theta); - - // standard normal distributed amplitude weighted with k^alpha/2 - b *= random.randNorm() * pow(k, spectralIndex / 2.); - - // uniform random phase - phase = 2 * M_PI * random.rand(); - cosPhase = cos(phase); // real part - sinPhase = sin(phase); // imaginary part - - Bkx[i][0] = b.x * cosPhase; - Bkx[i][1] = b.x * sinPhase; - Bky[i][0] = b.y * cosPhase; - Bky[i][1] = b.y * sinPhase; - Bkz[i][0] = b.z * cosPhase; - Bkz[i][1] = b.z * sinPhase; - } - } - } - - // in-place, complex to real, inverse Fourier transformation on each component - // note that the last elements of B(x) are unused now - float *Bx = (float*) Bkx; - fftwf_plan plan_x = fftwf_plan_dft_c2r_3d(n, n, n, Bkx, Bx, FFTW_ESTIMATE); - fftwf_execute(plan_x); - fftwf_destroy_plan(plan_x); - - float *By = (float*) Bky; - fftwf_plan plan_y = fftwf_plan_dft_c2r_3d(n, n, n, Bky, By, FFTW_ESTIMATE); - fftwf_execute(plan_y); - fftwf_destroy_plan(plan_y); - - float *Bz = (float*) Bkz; - fftwf_plan plan_z = fftwf_plan_dft_c2r_3d(n, n, n, Bkz, Bz, FFTW_ESTIMATE); - fftwf_execute(plan_z); - fftwf_destroy_plan(plan_z); - - // save to grid - for (size_t ix = 0; ix < n; ix++) { - for (size_t iy = 0; iy < n; iy++) { - for (size_t iz = 0; iz < n; iz++) { - i = ix * n * 2 * n2 + iy * 2 * n2 + iz; - Vector3f &b = m->get(ix, iy, iz); - b.x = Bx[i]; - b.y = By[i]; - b.z = Bz[i]; - } - } - } - - fftwf_free(Bkx); - fftwf_free(Bky); - fftwf_free(Bkz); - - scale(m, Brms / rmsFieldStrength(m)); // normalize to Brms -} -#endif // MPC_HAVE_FFTW3F - -double turbulentCorrelationLength(double lMin, double lMax, - double spectralIndex) { - double r = lMin / lMax; - double a = -spectralIndex - 2; - return lMax / 2 * (a - 1) / a * (1 - pow(r, a)) / (1 - pow(r, a - 1)); -} - -void load(ref_ptr m, std::string filename, double c) { - std::ifstream fin(filename.c_str(), std::ios::binary); - if (!fin) - throw std::runtime_error("MagneticFieldGrid: File not found"); - for (int ix = 0; ix < m->getNx(); ix++) { - for (int iy = 0; iy < m->getNy(); iy++) { - for (int iz = 0; iz < m->getNz(); iz++) { - Vector3f &b = m->get(ix, iy, iz); - fin.read((char*) &(b.x), sizeof(float)); - fin.read((char*) &(b.y), sizeof(float)); - fin.read((char*) &(b.z), sizeof(float)); - b *= c; - } - } - } - fin.close(); -} - -void dump(ref_ptr m, std::string filename, double c) { - std::ofstream fout(filename.c_str(), std::ios::binary); - if (!fout) - throw std::runtime_error("MagneticFieldGrid: Could not open file"); - for (int ix = 0; ix < m->getNx(); ix++) { - for (int iy = 0; iy < m->getNy(); iy++) { - for (int iz = 0; iz < m->getNz(); iz++) { - Vector3f b = m->get(ix, iy, iz) * c; - fout.write((char*) &(b.x), sizeof(float)); - fout.write((char*) &(b.y), sizeof(float)); - fout.write((char*) &(b.z), sizeof(float)); - } - } - } - fout.close(); -} - -void loadTxt(ref_ptr m, std::string filename, double unit) { - std::ifstream fin(filename.c_str()); - if (!fin) - throw std::runtime_error("MagneticFieldGrid: file not found"); - - // skip header lines - while (fin.peek() == '#') - fin.ignore(std::numeric_limits::max(), '\n'); - - for (int ix = 0; ix < m->getNx(); ix++) { - for (int iy = 0; iy < m->getNy(); iy++) { - for (int iz = 0; iz < m->getNz(); iz++) { - Vector3f &b = m->get(ix, iy, iz); - fin >> b.x >> b.y >> b.z; - b *= unit; - if (fin.eof()) - throw std::runtime_error( - "MagneticFieldGrid: file too short"); - } - } - } - fin.close(); -} - -void dumpTxt(ref_ptr m, std::string filename, double unit) { - std::ofstream fout(filename.c_str()); - if (!fout) - throw std::runtime_error("MagneticFieldGrid: could not open file"); - for (int ix = 0; ix < m->getNx(); ix++) { - for (int iy = 0; iy < m->getNy(); iy++) { - for (int iz = 0; iz < m->getNz(); iz++) { - Vector3f b = m->get(ix, iy, iz) * unit; - fout << b << "\n"; - } - } - } - fout.close(); -} - } // namespace mpc diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp index 672e0dd9a..5736058dd 100644 --- a/src/module/BreakCondition.cpp +++ b/src/module/BreakCondition.cpp @@ -116,6 +116,32 @@ void PeriodicBox::updateDescription() { setDescription(s.str()); } +ReflectiveBox::ReflectiveBox(Vector3d origin, Vector3d size) { + this->origin = origin; + this->size = size; + updateDescription(); +} + +void ReflectiveBox::process(Candidate *candidate) const { + Vector3d pos = candidate->current.getPosition(); + Vector3d n = ((pos - origin) / size).floor(); // integers for translation + if ((n.x != 0) or (n.y != 0) or (n.z != 0)) { + Vector3d dir = candidate->current.getDirection(); + dir.x *= pow(-1, n.x); + dir.y *= pow(-1, n.y); + dir.z *= pow(-1, n.z); + candidate->current.setDirection(dir); + candidate->current.setPosition(pos - n * size); + candidate->initial.setPosition(candidate->initial.getPosition() + n * size); + } +} + +void ReflectiveBox::updateDescription() { + std::stringstream s; + s << "Antiperiodic box: origin " << origin << ", size " << size; + setDescription(s.str()); +} + CubicBoundary::CubicBoundary(Vector3d origin, double size, std::string flag, std::string flagValue) { this->origin = origin; diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index 330af27c4..1cf97f6ae 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -93,6 +93,23 @@ TEST(PeriodicBox, low) { EXPECT_DOUBLE_EQ(candidate.initial.getPosition().z, 3); } +TEST(ReflectiveBox, high) { + // Tests if the reflective boundaries place the particle back inside the box and translate the initial position accordingly. + ReflectiveBox box(Vector3d(10, 10, 10), Vector3d(10, 20, 20)); + Candidate candidate; + candidate.current.setPosition(Vector3d(21, 31, 51)); + candidate.initial.setPosition(Vector3d(15, 15, 15)); + box.process(&candidate); + + EXPECT_DOUBLE_EQ(19, candidate.current.getPosition().x); + EXPECT_DOUBLE_EQ(29, candidate.current.getPosition().y); + EXPECT_DOUBLE_EQ(29, candidate.current.getPosition().z); + + EXPECT_DOUBLE_EQ(25, candidate.initial.getPosition().x); + EXPECT_DOUBLE_EQ(35, candidate.initial.getPosition().y); + EXPECT_DOUBLE_EQ(55, candidate.initial.getPosition().z); +} + TEST(CubicBoundary, inside) { CubicBoundary cube(Vector3d(0, 0, 0), 10); Candidate candidate; diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index 65d8c1ef6..0458c18ce 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -1,6 +1,7 @@ #include "mpc/magneticField/UniformMagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" -#include "mpc/magneticField/PeriodicGrid.h" +#include "mpc/PeriodicGrid.h" +#include "mpc/PeriodicGridTools.h" #include "mpc/magneticField/TurbulentMagneticField.h" #include "mpc/Units.h" #include "mpc/Common.h" From 05f36d369eb6d5050bf3f119275d9b8583910ed4 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 26 Jul 2012 14:03:10 +0200 Subject: [PATCH 0158/1298] add missing files --- include/mpc/PeriodicGridTools.h | 70 +++++++ src/PeriodicGridTools.cpp | 348 ++++++++++++++++++++++++++++++++ src/module/Output.cpp | 7 - 3 files changed, 418 insertions(+), 7 deletions(-) create mode 100644 include/mpc/PeriodicGridTools.h create mode 100644 src/PeriodicGridTools.cpp diff --git a/include/mpc/PeriodicGridTools.h b/include/mpc/PeriodicGridTools.h new file mode 100644 index 000000000..66b2cacca --- /dev/null +++ b/include/mpc/PeriodicGridTools.h @@ -0,0 +1,70 @@ +#ifndef MPC_PERIODICGRIDTOOLS_H_ +#define MPC_PERIODICGRIDTOOLS_H_ + +#include "mpc/PeriodicGrid.h" +#include + +namespace mpc { + +/** Calculate the mean field strength */ +Vector3f meanFieldStrength(ref_ptr m); + +/** Calculate the RMS field strength */ +double rmsFieldStrength(ref_ptr m); + +/** Multiply a magnetic field grid by a factor. */ +void scale(ref_ptr m, double a); + +#ifdef MPC_HAVE_FFTW3F +/** + Create a random initialization of a turbulent field. + @param lMin Minimum wavelength of the turbulence + @param lMax Maximum wavelength of the turbulence + @param index Power spectral index of the turbulence (-11/3 corresponds to a Kolmogorov spectrum) + @param Brms RMS field strength + @param seed Random seed + */ +void initTurbulence(ref_ptr m, double Brms, double lMin, + double lMax, double index = -11. / 3., int seed = 0); +#endif // MPC_HAVE_FFTW3F + +/** Analytically calculate the correlation length of a turbulent field */ +double turbulentCorrelationLength(double lMin, double lMax, double spectralIndex = -11. / 3.); + +/** + Dump / load functions for scalar / 3-vector grids and binary / plain text files. + The grid points are stored from (0, 0, 0) to (Nx, Ny, Nz) with the z-index changing the fastest. + Vector components are stored per grid point in xyz-order. + + In case of plain-text files the vector components are separated by a blank or tab and grid points are stored one per line. + Also there can be any number of comment lines at the beginning of the file, started with a #. + + All functions offer a conversion factor that is multiplied to all values. + */ +// Load a VectorGrid from a binary file with single precision. +void load(ref_ptr grid, std::string filename, double c = 1); + +// Load a ScalarGrid from a binary file with single precision. +void load(ref_ptr grid, std::string filename, double c = 1); + +// Dump a VectorGrid to a binary file. +void dump(ref_ptr grid, std::string filename, double c = 1); + +// Dump a ScalarGrid to a binary file with single precision. +void dump(ref_ptr grid, std::string filename, double c = 1); + +// Load a VectorGrid grid from a plain text file. +void loadTxt(ref_ptr grid, std::string filename, double c = 1); + +// Load a ScalarGrid from a plain text file. +void loadTxt(ref_ptr grid, std::string filename, double c = 1); + +// Dump a VectorGrid to a plain text file. +void dumpTxt(ref_ptr grid, std::string filename, double c = 1); + +// Dump a ScalarGrid to a plain text file. +void dumpTxt(ref_ptr grid, std::string filename, double c = 1); + +} // namespace mpc + +#endif /* MPC_PERIODICGRIDTOOLS_H_ */ diff --git a/src/PeriodicGridTools.cpp b/src/PeriodicGridTools.cpp new file mode 100644 index 000000000..5ff7c02f3 --- /dev/null +++ b/src/PeriodicGridTools.cpp @@ -0,0 +1,348 @@ +#include "mpc/PeriodicGridTools.h" +#include "mpc/Random.h" + +#include +#include + +namespace mpc { + +Vector3f meanFieldStrength(ref_ptr grid) { + size_t Nx = grid->getNx(); + size_t Ny = grid->getNy(); + size_t Nz = grid->getNz(); + Vector3f mean(0.); + for (int ix = 0; ix < Nx; ix++) + for (int iy = 0; iy < Ny; iy++) + for (int iz = 0; iz < Nz; iz++) + mean += grid->get(ix, iy, iz); + return mean / Nx / Ny / Nz; +} + +double rmsFieldStrength(ref_ptr grid) { + size_t Nx = grid->getNx(); + size_t Ny = grid->getNy(); + size_t Nz = grid->getNz(); + double sumB2 = 0; + for (int ix = 0; ix < Nx; ix++) + for (int iy = 0; iy < Ny; iy++) + for (int iz = 0; iz < Nz; iz++) + sumB2 += grid->get(ix, iy, iz).getMag2(); + return sqrt(sumB2 / Nx / Ny / Nz); +} + +void scale(ref_ptr grid, double a) { + for (int ix = 0; ix < grid->getNx(); ix++) + for (int iy = 0; iy < grid->getNy(); iy++) + for (int iz = 0; iz < grid->getNz(); iz++) + grid->get(ix, iy, iz) *= a; +} + +#ifdef MPC_HAVE_FFTW3F +#include "fftw3.h" + +void initTurbulence(ref_ptr grid, double Brms, double lMin, + double lMax, double spectralIndex, int seed) { + size_t Nx = grid->getNx(); + size_t Ny = grid->getNy(); + size_t Nz = grid->getNz(); + if ((Nx != Ny) or (Ny != Nz)) + throw std::runtime_error("turbulentField: only cubic grid supported"); + + double spacing = grid->getSpacing(); + if (lMin < 2 * spacing) + throw std::runtime_error("turbulentField: lMin < 2 * spacing"); + if (lMin >= lMax) + throw std::runtime_error("turbulentField: lMin >= lMax"); + if (lMax > Nx * spacing / 2) + throw std::runtime_error("turbulentField: lMax > size / 2"); + + size_t n = Nx; // size of array + size_t n2 = (size_t) floor(n / 2) + 1; // size array in z-direction in configuration space + + // arrays to hold the complex vector components of the B(k)-field + fftwf_complex *Bkx, *Bky, *Bkz; + Bkx = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * n * n * n2); + Bky = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * n * n * n2); + Bkz = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * n * n * n2); + + Random random; + if (seed != 0) + random.seed(seed); // use given seed + + // calculate the n possible discrete wave numbers + double K[n]; + for (int i = 0; i < n; i++) + K[i] = (double) i / n - i / (n / 2); + + // construct the field in configuration space + int i; + double k, theta, phase, cosPhase, sinPhase; + double kMin = spacing / lMax; + double kMax = spacing / lMin; + Vector3f b; // real b-field vector + Vector3f ek, e1, e2; // orthogonal base + Vector3f n0(1, 1, 1); // arbitrary vector to construct orthogonal base + + for (size_t ix = 0; ix < n; ix++) { + for (size_t iy = 0; iy < n; iy++) { + for (size_t iz = 0; iz < n2; iz++) { + + i = ix * n * n2 + iy * n2 + iz; + ek.setXYZ(K[ix], K[iy], K[iz]); + k = ek.getMag(); + + // wave outside of turbulent range -> B(k) = 0 + if ((k < kMin) || (k > kMax)) { + Bkx[i][0] = 0; + Bkx[i][1] = 0; + Bky[i][0] = 0; + Bky[i][1] = 0; + Bkz[i][0] = 0; + Bkz[i][1] = 0; + continue; + } + + // construct an orthogonal base ek, e1, e2 + if (ek.getAngleTo(n0) < 1e-3) { + // ek parallel to (1,1,1) + e1.setXYZ(-1., 1., 0); + e2.setXYZ(1., 1., -2.); + } else { + // ek not parallel to (1,1,1) + e1 = n0.cross(ek); + e2 = ek.cross(e1); + } + e1 /= e1.getMag(); + e2 /= e2.getMag(); + + // random orientation perpendicular to k + theta = 2 * M_PI * random.rand(); + b = e1 * cos(theta) + e2 * sin(theta); + + // standard normal distributed amplitude weighted with k^alpha/2 + b *= random.randNorm() * pow(k, spectralIndex / 2.); + + // uniform random phase + phase = 2 * M_PI * random.rand(); + cosPhase = cos(phase); // real part + sinPhase = sin(phase); // imaginary part + + Bkx[i][0] = b.x * cosPhase; + Bkx[i][1] = b.x * sinPhase; + Bky[i][0] = b.y * cosPhase; + Bky[i][1] = b.y * sinPhase; + Bkz[i][0] = b.z * cosPhase; + Bkz[i][1] = b.z * sinPhase; + } + } + } + + // in-place, complex to real, inverse Fourier transformation on each component + // note that the last elements of B(x) are unused now + float *Bx = (float*) Bkx; + fftwf_plan plan_x = fftwf_plan_dft_c2r_3d(n, n, n, Bkx, Bx, FFTW_ESTIMATE); + fftwf_execute(plan_x); + fftwf_destroy_plan(plan_x); + + float *By = (float*) Bky; + fftwf_plan plan_y = fftwf_plan_dft_c2r_3d(n, n, n, Bky, By, FFTW_ESTIMATE); + fftwf_execute(plan_y); + fftwf_destroy_plan(plan_y); + + float *Bz = (float*) Bkz; + fftwf_plan plan_z = fftwf_plan_dft_c2r_3d(n, n, n, Bkz, Bz, FFTW_ESTIMATE); + fftwf_execute(plan_z); + fftwf_destroy_plan(plan_z); + + // save to grid + for (size_t ix = 0; ix < n; ix++) { + for (size_t iy = 0; iy < n; iy++) { + for (size_t iz = 0; iz < n; iz++) { + i = ix * n * 2 * n2 + iy * 2 * n2 + iz; + Vector3f &b = grid->get(ix, iy, iz); + b.x = Bx[i]; + b.y = By[i]; + b.z = Bz[i]; + } + } + } + + fftwf_free(Bkx); + fftwf_free(Bky); + fftwf_free(Bkz); + + scale(grid, Brms / rmsFieldStrength(grid)); // normalize to Brms +} +#endif // MPC_HAVE_FFTW3F +double turbulentCorrelationLength(double lMin, double lMax, + double spectralIndex) { + double r = lMin / lMax; + double a = -spectralIndex - 2; + return lMax / 2 * (a - 1) / a * (1 - pow(r, a)) / (1 - pow(r, a - 1)); +} + +void load(ref_ptr grid, std::string filename, double c) { + std::ifstream fin(filename.c_str(), std::ios::binary); + if (!fin) { + std::stringstream ss; + ss << "load VectorGrid: " << filename << " not found"; + throw std::runtime_error(ss.str()); + } + for (int ix = 0; ix < grid->getNx(); ix++) { + for (int iy = 0; iy < grid->getNy(); iy++) { + for (int iz = 0; iz < grid->getNz(); iz++) { + Vector3f &b = grid->get(ix, iy, iz); + fin.read((char*) &(b.x), sizeof(float)); + fin.read((char*) &(b.y), sizeof(float)); + fin.read((char*) &(b.z), sizeof(float)); + b *= c; + } + } + } + fin.close(); +} + +void load(ref_ptr grid, std::string filename, double c) { + std::ifstream fin(filename.c_str(), std::ios::binary); + if (!fin) { + std::stringstream ss; + ss << "load ScalarGrid: " << filename << " not found"; + throw std::runtime_error(ss.str()); + } + for (int ix = 0; ix < grid->getNx(); ix++) { + for (int iy = 0; iy < grid->getNy(); iy++) { + for (int iz = 0; iz < grid->getNz(); iz++) { + float &b = grid->get(ix, iy, iz); + fin.read((char*) &b, sizeof(float)); + b *= c; + } + } + } + fin.close(); +} + +void dump(ref_ptr grid, std::string filename, double c) { + std::ofstream fout(filename.c_str(), std::ios::binary); + if (!fout) { + std::stringstream ss; + ss << "dump VectorGrid: " << filename << " not found"; + throw std::runtime_error(ss.str()); + } + for (int ix = 0; ix < grid->getNx(); ix++) { + for (int iy = 0; iy < grid->getNy(); iy++) { + for (int iz = 0; iz < grid->getNz(); iz++) { + Vector3f b = grid->get(ix, iy, iz) * c; + fout.write((char*) &(b.x), sizeof(float)); + fout.write((char*) &(b.y), sizeof(float)); + fout.write((char*) &(b.z), sizeof(float)); + } + } + } + fout.close(); +} + +void dump(ref_ptr grid, std::string filename, double c) { + std::ofstream fout(filename.c_str(), std::ios::binary); + if (!fout) { + std::stringstream ss; + ss << "dump ScalarGrid: " << filename << " not found"; + throw std::runtime_error(ss.str()); + } + for (int ix = 0; ix < grid->getNx(); ix++) { + for (int iy = 0; iy < grid->getNy(); iy++) { + for (int iz = 0; iz < grid->getNz(); iz++) { + float b = grid->get(ix, iy, iz) * c; + fout.write((char*) &b, sizeof(float)); + } + } + } + fout.close(); +} + +void loadTxt(ref_ptr grid, std::string filename, double c) { + std::ifstream fin(filename.c_str()); + if (!fin) { + std::stringstream ss; + ss << "load VectorGrid: " << filename << " not found"; + throw std::runtime_error(ss.str()); + } + // skip header lines + while (fin.peek() == '#') + fin.ignore(std::numeric_limits::max(), '\n'); + + for (int ix = 0; ix < grid->getNx(); ix++) { + for (int iy = 0; iy < grid->getNy(); iy++) { + for (int iz = 0; iz < grid->getNz(); iz++) { + Vector3f &b = grid->get(ix, iy, iz); + fin >> b.x >> b.y >> b.z; + b *= c; + if (fin.eof()) + throw std::runtime_error("load VectorGrid: file too short"); + } + } + } + fin.close(); +} + +void loadTxt(ref_ptr grid, std::string filename, double c) { + std::ifstream fin(filename.c_str()); + if (!fin) { + std::stringstream ss; + ss << "load ScalarGrid: " << filename << " not found"; + throw std::runtime_error(ss.str()); + } + // skip header lines + while (fin.peek() == '#') + fin.ignore(std::numeric_limits::max(), '\n'); + + for (int ix = 0; ix < grid->getNx(); ix++) { + for (int iy = 0; iy < grid->getNy(); iy++) { + for (int iz = 0; iz < grid->getNz(); iz++) { + float &b = grid->get(ix, iy, iz); + fin >> b; + b *= c; + if (fin.eof()) + throw std::runtime_error("load ScalarGrid: file too short"); + } + } + } + fin.close(); +} + +void dumpTxt(ref_ptr grid, std::string filename, double c) { + std::ofstream fout(filename.c_str()); + if (!fout) { + std::stringstream ss; + ss << "dump VectorGrid: " << filename << " not found"; + throw std::runtime_error(ss.str()); + } + for (int ix = 0; ix < grid->getNx(); ix++) { + for (int iy = 0; iy < grid->getNy(); iy++) { + for (int iz = 0; iz < grid->getNz(); iz++) { + Vector3f b = grid->get(ix, iy, iz) * c; + fout << b << "\n"; + } + } + } + fout.close(); +} + +void dumpTxt(ref_ptr grid, std::string filename, double c) { + std::ofstream fout(filename.c_str()); + if (!fout) { + std::stringstream ss; + ss << "dump ScalarGrid: " << filename << " not found"; + throw std::runtime_error(ss.str()); + } + for (int ix = 0; ix < grid->getNx(); ix++) { + for (int iy = 0; iy < grid->getNy(); iy++) { + for (int iz = 0; iz < grid->getNz(); iz++) { + float b = grid->get(ix, iy, iz) * c; + fout << b << "\n"; + } + } + } + fout.close(); +} + +} // namespace mpc diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 83863cfdc..7921d87de 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -94,13 +94,6 @@ void ConditionalOutput::process(Candidate *candidate) const { } } -// _fDataStream << "#CRPropa - Output data file" << endl ; -// if (lUnivType == "One Dimension" && lRecordType == "Events") { -// _fDataStream << "#Format - Particle_Type Initial_Particle_Type Initial_Position(Mpc) Initial_Energy(EeV) Time(Mpc) Energy(EeV)" << endl ; -// } else if (lUnivType == "One Dimension" && lRecordType == "Full Trajectories") { -// _fDataStream << "#Format - Particle_Type Initial_Particle_Type Time(Mpc) Position(Mpc) Energy(EeV)" << endl ; -// } else throw TCrpErr("Output format determination failed") ; - CRPropa2EventOutput::CRPropa2EventOutput(std::string filename) { setDescription("Event output in CRPropa2 format"); outfile.open(filename.c_str()); From 63c085b9a079ef7cd417c32428f5e1b63765f6aa Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 27 Jul 2012 14:35:53 +0200 Subject: [PATCH 0159/1298] fix Vector3, XmlExecute --- README | 22 +++++++++++- include/mpc/Vector3.h | 83 ++++++++++++++++++------------------------- python/mpc.i | 3 +- src/XmlExecute.cpp | 7 ++-- 4 files changed, 60 insertions(+), 55 deletions(-) diff --git a/README b/README index 4073d938d..b6d3cf1f8 100644 --- a/README +++ b/README @@ -39,4 +39,24 @@ Gadget OpenMP -> for shared memory parallelization googleperftools - -> for performance optimizations regarding shared memory parallelization \ No newline at end of file + -> for performance optimizations regarding shared memory parallelization + + +XML Steering +------------ +MPC can be steered via XML cards ($mpc-run some_steeringcard.xml) +The steeringcard layout is conform to the one CRPropa2. +However, CRPropa 2 does not fully enforce the XML-1.0 standard (http://www.w3.org/XML). +To comply with the standard a few modifications to exisisting steering cards might have to be made. +Modification are + 1) XML-cards can have only one root node. The root node is + + .... + + 2) All nodes including the optional header node need to be closed, e.g. + + ... or + + 3) Values need to be embraced by quotes, e.g. + or + diff --git a/include/mpc/Vector3.h b/include/mpc/Vector3.h index 57f0ee076..23f1ba918 100644 --- a/include/mpc/Vector3.h +++ b/include/mpc/Vector3.h @@ -17,7 +17,7 @@ class Vector3 { x(0), y(0), z(0) { } - // Provides implicit conversion Vector3 <--> Vector3 + // Provides implicit conversion template Vector3(const Vector3 &v) : x(v.x), y(v.y), z(v.z) { @@ -39,28 +39,28 @@ class Vector3 { x(t), y(t), z(t) { } - void setX(const T x) { - this->x = x; + void setX(const T X) { + x = X; } - void setY(const T x) { - this->y = y; + void setY(const T Y) { + y = Y; } - void setZ(const T x) { - this->z = z; + void setZ(const T Z) { + z = Z; } - void setXYZ(const T x, const T y, const T z) { - this->x = x; - this->y = y; - this->z = z; + void setXYZ(const T X, const T Y, const T Z) { + x = X; + y = Y; + z = Z; } void setRThetaPhi(const T r, const T theta, const T phi) { - this->x = r * sin(theta) * cos(phi); - this->y = r * sin(theta) * sin(phi); - this->z = r * cos(theta); + x = r * sin(theta) * cos(phi); + y = r * sin(theta) * sin(phi); + z = r * cos(theta); } T getX() const { @@ -129,13 +129,13 @@ class Vector3 { *this /= getMag(); } - T dot(const Vector3 & p) const { - return x * p.x + y * p.y + z * p.z; + T dot(const Vector3 &v) const { + return x * v.x + y * v.y + z * v.z; } - Vector3 cross(const Vector3 & p) const { - return Vector3(y * p.z - p.y * z, z * p.x - p.z * x, - x * p.y - p.x * y); + Vector3 cross(const Vector3 &v) const { + return Vector3(y * v.z - v.y * z, z * v.x - v.z * x, + x * v.y - v.x * y); } void rotate(const Vector3 &axis, T angle) { @@ -236,8 +236,12 @@ class Vector3 { return Vector3(x / f, y / f, z / f); } + Vector3 operator %(const Vector3 &v) const { + return Vector3(fmod(x, v.x), fmod(y, v.y), fmod(z, v.z)); + } + Vector3 operator %(const T &f) const { - return Vector3(x % f, y % f, z % f); + return Vector3(fmod(x, f), fmod(y, f), fmod(z, f)); } Vector3 &operator -=(const Vector3 &v) { @@ -297,9 +301,16 @@ class Vector3 { } Vector3 &operator %=(const T &f) { - x %= f; - y %= f; - z %= f; + x = fmod(x, f); + y = fmod(y, f); + z = fmod(z, f); + return *this; + } + + Vector3 &operator %=(const Vector3 &v) { + x = fmod(x, v.x); + y = fmod(y, v.y); + z = fmod(z, v.z); return *this; } @@ -311,32 +322,6 @@ class Vector3 { } }; -template<> -inline Vector3 Vector3::operator %(const float &f) const { - return Vector3(fmod(x, f), fmod(y, f), fmod(z, f)); -} - -template<> -inline Vector3 &Vector3::operator %=(const float &f) { - x = fmod(x, f); - y = fmod(y, f); - z = fmod(z, f); - return *this; -} - -template<> -inline Vector3 Vector3::operator %(const double &f) const { - return Vector3(fmod(x, f), fmod(y, f), fmod(z, f)); -} - -template<> -inline Vector3 &Vector3::operator %=(const double &f) { - x = fmod(x, f); - y = fmod(y, f); - z = fmod(z, f); - return *this; -} - template inline std::ostream &operator <<(std::ostream &out, const Vector3 &v) { out << v.x << " " << v.y << " " << v.z; diff --git a/python/mpc.i b/python/mpc.i index 7da4478ce..7016a55a2 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -63,10 +63,9 @@ } } - %ignore operator<<; %ignore operator>>; - +%ignore *::operator=; %ignore operator mpc::Source*; %ignore operator mpc::Candidate*; %ignore operator mpc::Module*; diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 30d92df55..fccb76819 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -26,8 +26,9 @@ bool XmlExecute::load(const string &filename) { xml_parse_result result = doc.load_file(filename.c_str()); if (!result) { - cout << "Error description: " << result.description() << "\n"; - cout << "Error offset: " << result.offset << "\n"; + cout << "Error reading XML card: " << result.description() << "\n"; + cout << "Error position: " << result.offset << "\n"; + return false; } xml_node root = doc.child("CRPropa"); @@ -74,7 +75,7 @@ bool XmlExecute::load(const string &filename) { cout << "MagenticField: " << type << endl; if (type == "Uniform") loadUniformMagneticField(node); - else if ((type == "LSS") or (type == "Kolmogoroff")) + else if ((type == "LSS-Grid") or (type == "Kolmogoroff")) loadGridMagneticField(node); else { cout << " --> unknown, set zero field" << endl; From e24ff5d4914ce4b5a53cbf36a0ce467195a26658 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 27 Jul 2012 14:41:12 +0200 Subject: [PATCH 0160/1298] add xml magneticfield option none --- src/XmlExecute.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index fccb76819..37225548c 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -73,7 +73,9 @@ bool XmlExecute::load(const string &filename) { throw runtime_error("Magnetic field not specified"); type = node.attribute("type").as_string(); cout << "MagenticField: " << type << endl; - if (type == "Uniform") + if (type == "None") + magnetic_field = new UniformMagneticField(Vector3d(0, 0, 0)); + else if (type == "Uniform") loadUniformMagneticField(node); else if ((type == "LSS-Grid") or (type == "Kolmogoroff")) loadGridMagneticField(node); From 2615e54968e21539443b014cc0105664c58c848f Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 27 Jul 2012 16:46:23 +0200 Subject: [PATCH 0161/1298] included maxStep in DeflectionCK added XML functionality: Ecut_EeV for power law spectra added XML examples --- include/mpc/module/DeflectionCK.h | 8 ++- src/XmlExecute.cpp | 71 +++++++++++++++------ src/module/BreakCondition.cpp | 100 ++++++++++++++++-------------- src/module/DeflectionCK.cpp | 7 ++- test/xml/traj3d_kolmogoroff.xml | 84 +++++++++++++++++++++++++ test/xml/traj3d_nofield.xml | 64 +++++++++++++++++++ test/xml/traj3d_uniform.xml | 72 +++++++++++++++++++++ 7 files changed, 333 insertions(+), 73 deletions(-) create mode 100644 test/xml/traj3d_kolmogoroff.xml create mode 100644 test/xml/traj3d_nofield.xml create mode 100644 test/xml/traj3d_uniform.xml diff --git a/include/mpc/module/DeflectionCK.h b/include/mpc/module/DeflectionCK.h index 4b943500b..e9cc1d418 100644 --- a/include/mpc/module/DeflectionCK.h +++ b/include/mpc/module/DeflectionCK.h @@ -17,13 +17,15 @@ namespace mpc { The step size control tries to keep the relative error close to, but smaller than the designated tolerance. */ class DeflectionCK: public Module { -public: ref_ptr field; ExplicitRungeKutta erk; double tolerance; - double minStep; + double minStep, maxStep; - DeflectionCK(ref_ptr field, double tolerance = 1e-4, double minimumStep = 0.1 * kpc); +public: + DeflectionCK(ref_ptr field, double tolerance = 1e-4, + double minStep = 0.1 * kpc, + double maxStep = std::numeric_limits::max()); std::string getDescription() const; void process(Candidate *candidate) const; }; diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 37225548c..43e0bbacc 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -323,9 +323,14 @@ void XmlExecute::loadDiscreteSources(xml_node &node) { cout << " - Spectrum: " << spectrumType << endl; if (spectrumType == "Monochromatic") { - double E = spec.child("Energy_EeV").attribute("value").as_double() * EeV; - source.addProperty(new SourceEnergy(E)); - cout << " - Energy: " << E / EeV << " EeV" << endl; + if (spec.child("Energy_EeV")) { + double E = spec.child("Energy_EeV").attribute("value").as_double() * EeV; + source.addProperty(new SourceEnergy(E)); + cout << " - Energy: " << E / EeV << " EeV" << endl; + } else if (spec.child("Rigidity_EeV")) + throw runtime_error("Fixed rigidity not implemented"); + else + throw runtime_error("Source energy missing"); // source composition SourceNuclei *composition = new SourceNuclei; @@ -340,27 +345,53 @@ void XmlExecute::loadDiscreteSources(xml_node &node) { source.addProperty(composition); } else if (spectrumType == "Power Law") { + if (!spec.child("Alpha")) + throw runtime_error(" --> source power law index missing"); + double alpha = spec.child("Alpha").attribute("value").as_double(); - double Rmax = spec.child("Rigidity_EeV").attribute("value").as_double() * EeV; - cout << " - Minimum energy: " << Emin / EeV << " EeV" << endl; - cout << " - Maximum rigidity: " << Rmax / EeV << " EeV" << endl; cout << " - Power law index: " << alpha << endl; + cout << " - Minimum energy: " << Emin / EeV << " EeV" << endl; - // source composition - SourceComposition *composition = new SourceComposition(Emin, Rmax, alpha); - xml_node p = node.child("Particles"); - for (xml_node n = p.child("Species"); n; n = n.next_sibling("Species")) { - int A = n.attribute("MassNumber").as_int(); - int Z = n.attribute("ChargeNumber").as_int(); - double ab = n.attribute("Abundance").as_double(); - cout << " - Species: Z = " << Z << ", A = " << A << ", abundance = " << ab << endl; - composition->add(getNucleusId(A, Z), ab); - } - source.addProperty(composition); + // if the source is accelerated + if (spec.child("Rigidity_EeV")) { + double Rmax = spec.child("Rigidity_EeV").attribute("value").as_double() * EeV; + cout << " - Maximum rigidity: " << Rmax / EeV << " EeV" << endl; + + // combined source spectrum / composition + SourceComposition *composition = new SourceComposition(Emin, Rmax, alpha); + xml_node p = node.child("Particles"); + for (xml_node n = p.child("Species"); n; n = n.next_sibling("Species")) { + int A = n.attribute("MassNumber").as_int(); + int Z = n.attribute("ChargeNumber").as_int(); + double ab = n.attribute("Abundance").as_double(); + cout << " - Species: Z = " << Z << ", A = " << A << ", abundance = " << ab << endl; + composition->add(getNucleusId(A, Z), ab); + } + source.addProperty(composition); + + } else if (spec.child("Ecut_EeV")) { + double Emax = spec.child("Ecut_EeV").attribute("value").as_double() * EeV; + cout << " - Maximum energy: " << Emax / EeV << " EeV" << endl; + + // source spectrum + source.addProperty(new SourcePowerLawSpectrum(Emin, Emax, alpha)); + + // source composition + SourceNuclei *composition = new SourceNuclei(); + xml_node p = node.child("Particles"); + for (xml_node n = p.child("Species"); n; n = n.next_sibling("Species")) { + int A = n.attribute("MassNumber").as_int(); + int Z = n.attribute("ChargeNumber").as_int(); + double ab = n.attribute("Abundance").as_double(); + cout << " - Species: Z = " << Z << ", A = " << A << ", abundance = " << ab << endl; + composition->add(getNucleusId(A, Z), ab); + } + source.addProperty(composition); + } else + throw runtime_error(" --> maximum source energy / rigidity missing"); - } else { - throw runtime_error(" --> unknown source"); - } + } else + throw runtime_error(" --> unknown source spectrum"); } void XmlExecute::loadOutput(xml_node &node) { diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp index 5736058dd..9ec968752 100644 --- a/src/module/BreakCondition.cpp +++ b/src/module/BreakCondition.cpp @@ -16,13 +16,13 @@ double MaximumTrajectoryLength::getMaximumTrajectoryLength() const { return maxLength; } -void MaximumTrajectoryLength::process(Candidate *candidate) const { - double l = candidate->getTrajectoryLength(); +void MaximumTrajectoryLength::process(Candidate *c) const { + double l = c->getTrajectoryLength(); if (l >= maxLength) { - candidate->setActive(false); - candidate->setProperty("Deactivated", getDescription()); + c->setActive(false); + c->setProperty("Deactivated", getDescription()); } else { - candidate->limitNextStep(maxLength - l); + c->limitNextStep(maxLength - l); } } @@ -46,10 +46,10 @@ double MinimumEnergy::getMinimumEnergy() const { return minEnergy; } -void MinimumEnergy::process(Candidate *candidate) const { - if (candidate->current.getEnergy() <= minEnergy) { - candidate->setActive(false); - candidate->setProperty("Deactivated", getDescription()); +void MinimumEnergy::process(Candidate *c) const { + if (c->current.getEnergy() <= minEnergy) { + c->setActive(false); + c->setProperty("Deactivated", getDescription()); } } @@ -74,16 +74,16 @@ void SmallObserverSphere::setMakeInactive(bool makeInactive) { updateDescription(); } -void SmallObserverSphere::process(Candidate *candidate) const { - double d = (candidate->current.getPosition() - center).getMag(); +void SmallObserverSphere::process(Candidate *c) const { + double d = (c->current.getPosition() - center).getMag(); if (d <= radius * 1.01) { - candidate->setProperty(flag, flagValue); + c->setProperty(flag, flagValue); if (makeInactive) { - candidate->setActive(false); - candidate->setProperty("Deactivated", getDescription()); + c->setActive(false); + c->setProperty("Deactivated", getDescription()); } } - candidate->limitNextStep((d - radius)); + c->limitNextStep((d - radius)); } void SmallObserverSphere::updateDescription() { @@ -100,13 +100,12 @@ PeriodicBox::PeriodicBox(Vector3d origin, Vector3d size) { updateDescription(); } -void PeriodicBox::process(Candidate *candidate) const { - Vector3d position = candidate->current.getPosition(); - Vector3d n = ((position - origin) / size).floor(); // integers for translation +void PeriodicBox::process(Candidate *c) const { + Vector3d relPos = c->current.getPosition() - origin; + Vector3d n = (relPos / size).floor(); // integers for translation if ((n.x != 0) or (n.y != 0) or (n.z != 0)) { - candidate->current.setPosition(position - n * size); - candidate->initial.setPosition( - candidate->initial.getPosition() - n * size); + c->initial.setPosition(c->initial.getPosition() - n * size); + c->current.setPosition(c->current.getPosition() - n * size); } } @@ -122,23 +121,28 @@ ReflectiveBox::ReflectiveBox(Vector3d origin, Vector3d size) { updateDescription(); } -void ReflectiveBox::process(Candidate *candidate) const { - Vector3d pos = candidate->current.getPosition(); - Vector3d n = ((pos - origin) / size).floor(); // integers for translation +void ReflectiveBox::process(Candidate *c) const { + Vector3d relPos = c->current.getPosition() - origin; + Vector3d n = (relPos / size).floor(); // integers for translation + std::cout << relPos << std::endl; + std::cout << n << std::endl; if ((n.x != 0) or (n.y != 0) or (n.z != 0)) { - Vector3d dir = candidate->current.getDirection(); + // flip direction + Vector3d dir = c->current.getDirection(); dir.x *= pow(-1, n.x); dir.y *= pow(-1, n.y); dir.z *= pow(-1, n.z); - candidate->current.setDirection(dir); - candidate->current.setPosition(pos - n * size); - candidate->initial.setPosition(candidate->initial.getPosition() + n * size); + c->current.setDirection(dir); + // translate into the box + Vector3d t = (relPos % size) * n; + c->initial.setPosition(c->initial.getPosition() + t); + c->current.setPosition(c->current.getPosition() + t); } } void ReflectiveBox::updateDescription() { std::stringstream s; - s << "Antiperiodic box: origin " << origin << ", size " << size; + s << "Reflective box: origin " << origin << ", size " << size; setDescription(s.str()); } @@ -165,19 +169,19 @@ void CubicBoundary::setLimitStep(bool limitStep, double margin) { updateDescription(); } -void CubicBoundary::process(Candidate *candidate) const { - Vector3d r = candidate->current.getPosition() - origin; +void CubicBoundary::process(Candidate *c) const { + Vector3d r = c->current.getPosition() - origin; double lo = r.min(); double hi = r.max(); if ((lo <= 0) or (hi >= size)) { - candidate->setProperty(flag, flagValue); + c->setProperty(flag, flagValue); if (makeInactive) { - candidate->setActive(false); - candidate->setProperty("Deactivated", getDescription()); + c->setActive(false); + c->setProperty("Deactivated", getDescription()); } } else if (limitStep) { - candidate->limitNextStep(lo + margin); - candidate->limitNextStep(size - hi + margin); + c->limitNextStep(lo + margin); + c->limitNextStep(size - hi + margin); } } @@ -211,17 +215,17 @@ void SphericalBoundary::setLimitStep(bool limitStep, double margin) { updateDescription(); } -void SphericalBoundary::process(Candidate *candidate) const { - double d = (candidate->current.getPosition() - center).getMag(); +void SphericalBoundary::process(Candidate *c) const { + double d = (c->current.getPosition() - center).getMag(); if (d >= radius) { - candidate->setProperty(flag, flagValue); + c->setProperty(flag, flagValue); if (makeInactive) { - candidate->setActive(false); - candidate->setProperty("Deactivated", getDescription()); + c->setActive(false); + c->setProperty("Deactivated", getDescription()); } } if (limitStep) - candidate->limitNextStep(radius - d + margin); + c->limitNextStep(radius - d + margin); } void SphericalBoundary::updateDescription() { @@ -256,18 +260,18 @@ void EllipsoidalBoundary::setLimitStep(bool limitStep, double margin) { updateDescription(); } -void EllipsoidalBoundary::process(Candidate *candidate) const { - Vector3d pos = candidate->current.getPosition(); +void EllipsoidalBoundary::process(Candidate *c) const { + Vector3d pos = c->current.getPosition(); double d = pos.getDistanceTo(focalPoint1) + pos.getDistanceTo(focalPoint2); if (d >= majorAxis) { - candidate->setProperty(flag, flagValue); + c->setProperty(flag, flagValue); if (makeInactive) { - candidate->setActive(false); - candidate->setProperty("Deactivated", getDescription()); + c->setActive(false); + c->setProperty("Deactivated", getDescription()); } } if (limitStep) - candidate->limitNextStep(majorAxis - d + margin); + c->limitNextStep(majorAxis - d + margin); } void EllipsoidalBoundary::updateDescription() { diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index 10444c3c1..d5621c51a 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -37,10 +37,11 @@ class LorentzForce: public ExplicitRungeKutta::F { }; DeflectionCK::DeflectionCK(ref_ptr field, double tolerance, - double minStep) { + double minStep, double maxStep) { this->field = field; this->tolerance = tolerance; this->minStep = minStep; + this->maxStep = maxStep; erk.loadCashKarp(); } @@ -53,7 +54,9 @@ std::string DeflectionCK::getDescription() const { } void DeflectionCK::process(Candidate *candidate) const { - double step = std::max(minStep, candidate->getNextStep()); + double step = candidate->getNextStep(); + step = std::max(step, minStep); + step = std::min(step, maxStep); // rectlinear propagation for neutral particles if (candidate->current.getCharge() == 0) { diff --git a/test/xml/traj3d_kolmogoroff.xml b/test/xml/traj3d_kolmogoroff.xml new file mode 100644 index 000000000..78ec22423 --- /dev/null +++ b/test/xml/traj3d_kolmogoroff.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + traj3d_kolmogoroff.txt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/xml/traj3d_nofield.xml b/test/xml/traj3d_nofield.xml new file mode 100644 index 000000000..5310a4604 --- /dev/null +++ b/test/xml/traj3d_nofield.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + "traj3d.txt" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/xml/traj3d_uniform.xml b/test/xml/traj3d_uniform.xml new file mode 100644 index 000000000..936964122 --- /dev/null +++ b/test/xml/traj3d_uniform.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + traj3d.txt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 00408aefe1707269177f3297e5ec490baedc106c Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 27 Jul 2012 17:24:51 +0200 Subject: [PATCH 0162/1298] finished reflective boundaries --- .hgignore | 18 ++---- include/mpc/Vector3.h | 14 ++--- include/mpc/module/BreakCondition.h | 4 +- src/module/BreakCondition.cpp | 21 ++++--- test/testBreakCondition.cpp | 95 ++++++++++++++++++----------- 5 files changed, 88 insertions(+), 64 deletions(-) diff --git a/.hgignore b/.hgignore index 0b3e15036..9f1c50e14 100644 --- a/.hgignore +++ b/.hgignore @@ -1,19 +1,13 @@ +syntax:glob -syntax: regexp -^build$ -syntax: regexp -^\.project$ -syntax: regexp -^\.cproject$ syntax: regexp ^doc$ -syntax: regexp +^build$ ^.settings$ -syntax: regexp .png$ -syntax: regexp +^\.cproject$ +^\.project$ ^data/NuclearDecay/bnl_z0-36\.txt$ -syntax: regexp ^data/PhotoDisintegration/CMB$ -syntax: regexp -^data/PhotoDisintegration/IRB$ \ No newline at end of file +^data/PhotoDisintegration/IRB$ +^data/SPH$ diff --git a/include/mpc/Vector3.h b/include/mpc/Vector3.h index 23f1ba918..f37e67d93 100644 --- a/include/mpc/Vector3.h +++ b/include/mpc/Vector3.h @@ -300,13 +300,6 @@ class Vector3 { return *this; } - Vector3 &operator %=(const T &f) { - x = fmod(x, f); - y = fmod(y, f); - z = fmod(z, f); - return *this; - } - Vector3 &operator %=(const Vector3 &v) { x = fmod(x, v.x); y = fmod(y, v.y); @@ -314,6 +307,13 @@ class Vector3 { return *this; } + Vector3 &operator %=(const T &f) { + x = fmod(x, f); + y = fmod(y, f); + z = fmod(z, f); + return *this; + } + Vector3 &operator =(const Vector3 &v) { x = v.x; y = v.y; diff --git a/include/mpc/module/BreakCondition.h b/include/mpc/module/BreakCondition.h index 3bcdf24f0..3116e407f 100644 --- a/include/mpc/module/BreakCondition.h +++ b/include/mpc/module/BreakCondition.h @@ -89,8 +89,8 @@ class PeriodicBox: public Module { }; /** - @class AntiperiodicBox - @brief Rectangular box with antiperiodic boundaries. + @class ReflectiveBox + @brief Rectangular box with reflective boundaries. If a particle passes on of the sides it is reflected back inside (position and velocity) and its initial position changed as if the particle had come from that side. Particles can overshoot (be outside of the box during the step) since the step size is not limited by this module. diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp index 9ec968752..37acb26ac 100644 --- a/src/module/BreakCondition.cpp +++ b/src/module/BreakCondition.cpp @@ -122,21 +122,26 @@ ReflectiveBox::ReflectiveBox(Vector3d origin, Vector3d size) { } void ReflectiveBox::process(Candidate *c) const { - Vector3d relPos = c->current.getPosition() - origin; - Vector3d n = (relPos / size).floor(); // integers for translation - std::cout << relPos << std::endl; - std::cout << n << std::endl; + Vector3d pos = c->current.getPosition(); + Vector3d n = ((pos - origin) / size).floor(); // integers for translation if ((n.x != 0) or (n.y != 0) or (n.z != 0)) { // flip direction + Vector3d idir = c->initial.getDirection(); + idir.x *= pow(-1, n.x); + idir.y *= pow(-1, n.y); + idir.z *= pow(-1, n.z); + c->initial.setDirection(idir); + Vector3d dir = c->current.getDirection(); dir.x *= pow(-1, n.x); dir.y *= pow(-1, n.y); dir.z *= pow(-1, n.z); c->current.setDirection(dir); - // translate into the box - Vector3d t = (relPos % size) * n; - c->initial.setPosition(c->initial.getPosition() + t); - c->current.setPosition(c->current.getPosition() + t); + + // translate back into the box + Vector3d ipos = c->initial.getPosition(); + c->initial.setPosition(ipos + (size - (ipos - origin)) * n * 2); + c->current.setPosition(pos - ((pos - origin) % size) * n * 2); } } diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index 1cf97f6ae..5fa0801c3 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -65,49 +65,74 @@ TEST(SmallObserverSphere, limitStep) { TEST(PeriodicBox, high) { // Tests if the periodical boundaries place the particle back inside the box and translate the initial position accordingly. - PeriodicBox box(Vector3d(2, 2, 2), Vector3d(2, 2, 2)); - Candidate candidate; - candidate.current.setPosition(Vector3d(4.5, 4.3, 4.4)); - candidate.initial.setPosition(Vector3d(3, 3, 3)); - box.process(&candidate); - EXPECT_DOUBLE_EQ(candidate.current.getPosition().x, 2.5); - EXPECT_DOUBLE_EQ(candidate.initial.getPosition().x, 1); - EXPECT_DOUBLE_EQ(candidate.current.getPosition().y, 2.3); - EXPECT_DOUBLE_EQ(candidate.initial.getPosition().y, 1); - EXPECT_DOUBLE_EQ(candidate.current.getPosition().z, 2.4); - EXPECT_DOUBLE_EQ(candidate.initial.getPosition().z, 1); + Vector3d origin(2, 2, 2); + Vector3d size(2, 2, 2); + PeriodicBox box(origin, size); + + Candidate c; + c.current.setPosition(Vector3d(4.5, 4.3, 4.4)); + c.initial.setPosition(Vector3d(3, 3, 3)); + + box.process(&c); + + EXPECT_DOUBLE_EQ(2.5, c.current.getPosition().x); + EXPECT_DOUBLE_EQ(1, c.initial.getPosition().x); + EXPECT_DOUBLE_EQ(2.3, c.current.getPosition().y); + EXPECT_DOUBLE_EQ(1, c.initial.getPosition().y); + EXPECT_DOUBLE_EQ(2.4, c.current.getPosition().z); + EXPECT_DOUBLE_EQ(1, c.initial.getPosition().z); } TEST(PeriodicBox, low) { // Tests if the periodical boundaries place the particle back inside the box and translate the initial position accordingly. - PeriodicBox box(Vector3d(0., 0., 0.), Vector3d(2., 2., 2.)); - Candidate candidate; - candidate.current.setPosition(Vector3d(-2.5, -0.3, -0.4)); - candidate.initial.setPosition(Vector3d(1, 1, 1)); - box.process(&candidate); - EXPECT_DOUBLE_EQ(candidate.current.getPosition().x, 1.5); - EXPECT_DOUBLE_EQ(candidate.initial.getPosition().x, 5); - EXPECT_DOUBLE_EQ(candidate.current.getPosition().y, 1.7); - EXPECT_DOUBLE_EQ(candidate.initial.getPosition().y, 3); - EXPECT_DOUBLE_EQ(candidate.current.getPosition().z, 1.6); - EXPECT_DOUBLE_EQ(candidate.initial.getPosition().z, 3); + Vector3d origin(0, 0, 0); + Vector3d size(2, 2, 2); + PeriodicBox box(origin, size); + + Candidate c; + c.current.setPosition(Vector3d(-2.5, -0.3, -0.4)); + c.initial.setPosition(Vector3d(1, 1, 1)); + + box.process(&c); + + EXPECT_DOUBLE_EQ(1.5, c.current.getPosition().x); + EXPECT_DOUBLE_EQ(5, c.initial.getPosition().x); + EXPECT_DOUBLE_EQ(1.7, c.current.getPosition().y); + EXPECT_DOUBLE_EQ(3, c.initial.getPosition().y); + EXPECT_DOUBLE_EQ(1.6, c.current.getPosition().z); + EXPECT_DOUBLE_EQ(3, c.initial.getPosition().z); } TEST(ReflectiveBox, high) { // Tests if the reflective boundaries place the particle back inside the box and translate the initial position accordingly. - ReflectiveBox box(Vector3d(10, 10, 10), Vector3d(10, 20, 20)); - Candidate candidate; - candidate.current.setPosition(Vector3d(21, 31, 51)); - candidate.initial.setPosition(Vector3d(15, 15, 15)); - box.process(&candidate); - - EXPECT_DOUBLE_EQ(19, candidate.current.getPosition().x); - EXPECT_DOUBLE_EQ(29, candidate.current.getPosition().y); - EXPECT_DOUBLE_EQ(29, candidate.current.getPosition().z); - - EXPECT_DOUBLE_EQ(25, candidate.initial.getPosition().x); - EXPECT_DOUBLE_EQ(35, candidate.initial.getPosition().y); - EXPECT_DOUBLE_EQ(55, candidate.initial.getPosition().z); + // Also the initial and final directions are to be reflected + Vector3d origin(10, 10, 10); + Vector3d size(10, 20, 20); + ReflectiveBox box(origin, size); + + Candidate c; + c.initial.setPosition(Vector3d(15, 15, 15)); + c.initial.setDirection(Vector3d(0, 0.6, 0.8)); + c.current.setPosition(Vector3d(15, 15, 31)); + c.current.setDirection(Vector3d(0, 0.6, 0.8)); + + box.process(&c); + + EXPECT_DOUBLE_EQ(15, c.initial.getPosition().x); + EXPECT_DOUBLE_EQ(15, c.initial.getPosition().y); + EXPECT_DOUBLE_EQ(45, c.initial.getPosition().z); + + EXPECT_DOUBLE_EQ(15, c.current.getPosition().x); + EXPECT_DOUBLE_EQ(15, c.current.getPosition().y); + EXPECT_DOUBLE_EQ(29, c.current.getPosition().z); + + EXPECT_DOUBLE_EQ(0, c.initial.getDirection().x); + EXPECT_DOUBLE_EQ(0.6, c.initial.getDirection().y); + EXPECT_DOUBLE_EQ(-0.8, c.initial.getDirection().z); + + EXPECT_DOUBLE_EQ(0, c.current.getDirection().x); + EXPECT_DOUBLE_EQ(0.6, c.current.getDirection().y); + EXPECT_DOUBLE_EQ(-0.8, c.current.getDirection().z); } TEST(CubicBoundary, inside) { From 8165d12425b05c0ab397a2aa9fc5bc252167f511 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Mon, 30 Jul 2012 10:24:52 +0200 Subject: [PATCH 0163/1298] Added fancy progressbar --- include/mpc/ProgressBar.h | 105 ++++++++++++++++++++++++++++++++++++++ src/ModuleList.cpp | 29 +++++++++-- 2 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 include/mpc/ProgressBar.h diff --git a/include/mpc/ProgressBar.h b/include/mpc/ProgressBar.h new file mode 100644 index 000000000..62e1e8336 --- /dev/null +++ b/include/mpc/ProgressBar.h @@ -0,0 +1,105 @@ +/*************************************************************************** + * ProgressBar.h implements a ProgressBar for calculations not * + * producing additional output * + * Copyright (C) 2010 by Tobias Winchen * + * * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + + + +#include +#include +#include +#include + +class ProgressBar +{ +private: + unsigned long _steps; + unsigned long _currentCount; + unsigned long _maxbarLength; + unsigned long _nextStep; + unsigned long _updateSteps; + time_t _startTime; + std::string stringTmpl; + std::string arrow; + +public: + /// Initialize a ProgressBar with [steps] number of steps, updated at [updateSteps] intervalls + ProgressBar(const std::string &title, unsigned long steps = 0, unsigned long updateSteps = 100) : + _steps(steps), _currentCount(0), _maxbarLength(10), _updateSteps(updateSteps), _nextStep(1) + { + if (_updateSteps > _steps) + _updateSteps = _steps; + _startTime = time(NULL); + std::string s = ctime(&_startTime); + s.erase(s.end()-1, s.end()); + stringTmpl = " Started "; + stringTmpl.append(s); + stringTmpl.append(" : [%-10s] %3i%% %s: %02i:%02is %s\r"); + arrow.append(">"); + std::cout << title << std::endl; + } + + /// update the progressbar + /// should be called steps times in a loop + void update() + { + _currentCount++; + if (_currentCount == _nextStep || _currentCount == _steps) + { + _nextStep+=long(_steps / float(_updateSteps)); + + int percentage = int(100*_currentCount/float(_steps)); + time_t currentTime = time(NULL); + if (_currentCount < _steps) + { + int j=0; + if (arrow.size() <= (_maxbarLength)*(_currentCount)/(_steps)) + arrow.insert(0, "="); + float tElapsed = currentTime - _startTime; + float tToGo = (_steps - _currentCount) * tElapsed / _currentCount; + printf(stringTmpl.c_str(), arrow.c_str(), percentage , "Finish in",int(tToGo/60), int(tToGo)%60, ""); + fflush(stdout); + } + else + { + float tElapsed = currentTime - _startTime; + std::string s = " - Finished at "; + s.append(ctime(¤tTime)); + char fs[255]; + sprintf(fs, "%c[%d;%dm Finished %c[%dm",27,1,32,27,0); + printf(stringTmpl.c_str(), fs, percentage, "Needed",int(tElapsed/60), int(tElapsed)%60, s.c_str()); + } + } + } + + /// Mark the progressbar with an error + void setError() + { + time_t currentTime = time(NULL); + _currentCount++; + float tElapsed = currentTime - _startTime; + std::string s = " - Finished at "; + s.append(ctime(¤tTime)); + char fs[255]; + sprintf(fs, "%c[%d;%dm ERROR %c[%dm",27,1,31,27,0); + printf(stringTmpl.c_str(), fs, _currentCount, "Needed",int(tElapsed/60), int(tElapsed)%60, s.c_str()); + } + +}; diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 6afb931a7..87d57e90f 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -1,4 +1,5 @@ #include "mpc/ModuleList.h" +#include "mpc/ProgressBar.h" #include #include @@ -52,27 +53,47 @@ void ModuleList::run(candidate_vector_t &candidates, bool recursive) { #if _OPENMP std::cout << "mpc::ModuleList: Number of Threads: " << omp_get_max_threads() << std::endl; #endif + + ProgressBar *progressbar = NULL; + if (showProgress) + { + progressbar = new ProgressBar("Run ModuleList", count); + } + #pragma omp parallel for schedule(dynamic, 1000) for (size_t i = 0; i < count; i++) { - if ((showProgress) && (i % pc == 0)) - std::cout << i / pc << "% - " << i << std::endl; + //if ((showProgress) && (i % pc == 0)) + // std::cout << i / pc << "% - " << i << std::endl; run(candidates[i], recursive); + + if (progressbar) + #pragma omp critical(progressbarUpdate) + progressbar->update(); } } void ModuleList::run(Source *source, size_t count, bool recursive) { size_t pc = std::max(count / 100, size_t(1)); + #if _OPENMP std::cout << "mpc::ModuleList: Number of Threads: " << omp_get_max_threads() << std::endl; #endif + + ProgressBar *progressbar = NULL; + if (showProgress) + { + progressbar = new ProgressBar("Run ModuleList", count); + } + #pragma omp parallel for schedule(dynamic, 1000) for (size_t i = 0; i < count; i++) { - if ((showProgress) && (i % pc == 0)) - std::cout << i / pc << "% - " << i << std::endl; ParticleState state; source->prepare(state); ref_ptr candidate = new Candidate(state); run(candidate, recursive); + if (progressbar) + #pragma omp critical(progressbarUpdate) + progressbar->update(); } } From 05f8614d176754b2d4c745f8cd9c338a2da82756 Mon Sep 17 00:00:00 2001 From: kuempel Date: Mon, 6 Aug 2012 11:43:34 +0200 Subject: [PATCH 0164/1298] Add whitespace --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cpp b/src/main.cpp index acf6cace7..6fee4999c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,7 @@ #include #include + using namespace mpc; using namespace std; From b03fe5d6285608e9d8713dfe55a00b297c528e45 Mon Sep 17 00:00:00 2001 From: kuempel Date: Mon, 6 Aug 2012 12:21:33 +0200 Subject: [PATCH 0165/1298] Add example with no boundaries. Should throw message that boundaries are not set. --- test/xml/traj3d_ThrowNoBoundary.xml | 62 +++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 test/xml/traj3d_ThrowNoBoundary.xml diff --git a/test/xml/traj3d_ThrowNoBoundary.xml b/test/xml/traj3d_ThrowNoBoundary.xml new file mode 100644 index 000000000..72c89a37a --- /dev/null +++ b/test/xml/traj3d_ThrowNoBoundary.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + traj3d_V3NoBound.txt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From d3bef1da3bab89d5492b6e18ce90f5b11587d8a1 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 6 Aug 2012 18:18:52 +0200 Subject: [PATCH 0166/1298] refactored XmlExectute catch missing xml entries by default --- include/mpc/Nucleus.h | 2 +- include/mpc/XmlExecute.h | 14 +-- src/XmlExecute.cpp | 176 ++++++++++++++++------------ test/xml/traj3d_ThrowNoBoundary.xml | 2 +- test/xml/traj3d_kolmogoroff.xml | 136 ++++++++++----------- test/xml/traj3d_nofield.xml | 11 +- test/xml/traj3d_uniform.xml | 121 ++++++++++--------- 7 files changed, 252 insertions(+), 210 deletions(-) diff --git a/include/mpc/Nucleus.h b/include/mpc/Nucleus.h index 8768f4351..84b4a3892 100644 --- a/include/mpc/Nucleus.h +++ b/include/mpc/Nucleus.h @@ -5,7 +5,7 @@ namespace mpc { -/** This implements the 2006 Monte Carlo nuclear code scheme. +/** This implements the 2012 Monte Carlo nuclear code scheme. * Ion numbers are +/- 10LZZZAAAI. * AAA is A - total baryon number * ZZZ is Z - total charge diff --git a/include/mpc/XmlExecute.h b/include/mpc/XmlExecute.h index 51f8f1c16..d9700dfe9 100644 --- a/include/mpc/XmlExecute.h +++ b/include/mpc/XmlExecute.h @@ -14,28 +14,24 @@ class xml_node; namespace mpc { class XmlExecute { - ModuleList modules; - ref_ptr magnetic_field; - Source source; - void loadUniformMagneticField(pugi::xml_node &node); void loadGridMagneticField(pugi::xml_node &node); - void loadDeflectionCK(pugi::xml_node &node); - + void loadPeriodicBoundaries(); void loadDiscreteSources(pugi::xml_node &node); - void loadSophia(pugi::xml_node &node); - void loadSpheresAroundObserver(pugi::xml_node &node); void loadSpheresAroundSource(pugi::xml_node &node); - void loadOutput(pugi::xml_node &node); + ModuleList modules; + ref_ptr magnetic_field; + Source source; bool is1D; size_t trajectories; size_t randomSeed; double Emin; + double maxStep; Vector3d origin; Vector3d size; diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 43e0bbacc..38addc9bb 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -15,12 +15,33 @@ #include "pugixml.hpp" #include +#include using namespace pugi; using namespace std; namespace mpc { +double childValue(xml_node parent, string name, bool throwIfEmpty = true) { + xml_node node = parent.child(name.c_str()); + if (!node and throwIfEmpty) { + stringstream ss; + ss << "Error reading XML card: " << name << " not found"; + throw runtime_error(ss.str()); + } + return node.attribute("value").as_double(); +} + +string childType(xml_node parent, string name, bool throwIfEmpty = true) { + xml_node node = parent.child(name.c_str()); + if (!node and throwIfEmpty) { + stringstream ss; + ss << "Error reading XML card: " << name << " not found"; + throw runtime_error(ss.str()); + } + return node.attribute("type").as_string(); +} + bool XmlExecute::load(const string &filename) { xml_document doc; xml_parse_result result = doc.load_file(filename.c_str()); @@ -32,21 +53,24 @@ bool XmlExecute::load(const string &filename) { } xml_node root = doc.child("CRPropa"); - xml_node node; - std::string type; + if (!root) + throw runtime_error("Error reading XML card: Root element not found"); - trajectories = root.child("TrajNumber").attribute("value").as_int(); + trajectories = (int)childValue(root, "TrajNumber"); cout << "Trajectories: " << trajectories << endl; - double maxTime = root.child("MaxTime_Mpc").attribute("value").as_double() * Mpc; + double maxTime = childValue(root, "MaxTime_Mpc") * Mpc; cout << "Maximum Time: " << maxTime / Mpc << " Mpc" << endl; - Emin = root.child("MinEnergy_EeV").attribute("value").as_double() * EeV; + Emin = childValue(root, "MinEnergy_EeV") * EeV; cout << "Minimum Energy: " << Emin / EeV << " EeV" << endl; - randomSeed = root.child("RandomSeed").attribute("value").as_int(); + randomSeed = (int)childValue(root, "RandomSeed"); cout << "RandomSeed: " << randomSeed << endl; + xml_node node; + std::string type; + // environment node = root.child("Environment"); if (!node) @@ -57,12 +81,12 @@ bool XmlExecute::load(const string &filename) { throw runtime_error("One Dimension not supported"); else if (type == "LSS") { // will be overwritten if (re)defined by magnetic field - origin.x = node.child("Xmin_Mpc").attribute("value").as_double() * Mpc; - origin.y = node.child("Ymin_Mpc").attribute("value").as_double() * Mpc; - origin.z = node.child("Zmin_Mpc").attribute("value").as_double() * Mpc; - size.x = node.child("Xmax_Mpc").attribute("value").as_double() * Mpc; - size.y = node.child("Ymax_Mpc").attribute("value").as_double() * Mpc; - size.z = node.child("Zmax_Mpc").attribute("value").as_double() * Mpc; + origin.x = childValue(node, "Xmin_Mpc", false) * Mpc; + origin.y = childValue(node, "Ymin_Mpc", false) * Mpc; + origin.z = childValue(node, "Zmin_Mpc", false) * Mpc; + size.x = childValue(node, "Xmax_Mpc", false) * Mpc; + size.y = childValue(node, "Ymax_Mpc", false) * Mpc; + size.z = childValue(node, "Zmax_Mpc", false) * Mpc; size -= origin; } else throw runtime_error("Unknown environment"); @@ -84,17 +108,6 @@ bool XmlExecute::load(const string &filename) { magnetic_field = new UniformMagneticField(Vector3d(0, 0, 0)); } - // propagator - node = root.child("Integrator"); - if (!node) - throw runtime_error("Integrator not specified"); - type = node.attribute("type").as_string(); - cout << "Integrator: " << type << endl; - if (type == "Cash-Karp RK") - loadDeflectionCK(node); - else - throw runtime_error("Unknown integrator"); - // interactions node = root.child("Interactions"); if (!node) @@ -112,6 +125,17 @@ bool XmlExecute::load(const string &filename) { else cout << " -> unknown" << endl; + // propagator + node = root.child("Integrator"); + if (!node) + throw runtime_error("Integrator not specified"); + type = node.attribute("type").as_string(); + cout << "Integrator: " << type << endl; + if (type == "Cash-Karp RK") + loadDeflectionCK(node); + else + throw runtime_error("Unknown integrator"); + // minimum energy modules.add(new MinimumEnergy(Emin)); @@ -119,10 +143,7 @@ bool XmlExecute::load(const string &filename) { modules.add(new MaximumTrajectoryLength(maxTime)); // periodic boundaries - cout << "Periodic boundaries" << endl; - cout << " - Lower bounds: " << origin / Mpc << " Mpc" << endl; - cout << " - Upper bounds: " << (origin + size) / Mpc << " Mpc" << endl; - modules.add(new PeriodicBox(origin, size)); + loadPeriodicBoundaries(); // sources node = root.child("Sources"); @@ -163,36 +184,38 @@ bool XmlExecute::load(const string &filename) { } void XmlExecute::loadDeflectionCK(xml_node &node) { - double epsilon = node.child("Epsilon").attribute("value").as_double(); + double epsilon = childValue(node, "MinStep_Mpc"); cout << " - Epsilon: " << epsilon << endl; - double minstep = node.child("MinStep_Mpc").attribute("value").as_double() - * Mpc; - cout << " - Minimum Step: " << minstep / Mpc << " Mpc " << endl; - modules.add(new DeflectionCK(magnetic_field, epsilon, minstep)); + double minStep = childValue(node, "MinStep_Mpc") * Mpc; + cout << " - Minimum Step: " << minStep / Mpc << " Mpc" << endl; + cout << " - Maximum Step: " << maxStep / Mpc << " Mpc" << endl; + if (minStep >= maxStep) + throw runtime_error("MaxStep must be larger than MinStep"); + modules.add(new DeflectionCK(magnetic_field, epsilon, minStep, maxStep)); } void XmlExecute::loadUniformMagneticField(xml_node &node) { Vector3d bField; - bField.x = node.child("Bx_nG").attribute("value").as_int() * nG; - bField.y = node.child("By_nG").attribute("value").as_int() * nG; - bField.z = node.child("Bz_nG").attribute("value").as_int() * nG; + bField.x = childValue(node, "Bx_nG") * nG; + bField.y = childValue(node, "By_nG") * nG; + bField.z = childValue(node, "Bz_nG") * nG; cout << " - Bx, By, Bz: " << bField / nG << " nG" << endl; magnetic_field = new UniformMagneticField(bField); } void XmlExecute::loadGridMagneticField(xml_node &node) { xml_node origin_node = node.child("Origin"); - origin.x = origin_node.child("X_Mpc").attribute("value").as_double() * Mpc; - origin.y = origin_node.child("Y_Mpc").attribute("value").as_double() * Mpc; - origin.z = origin_node.child("Z_Mpc").attribute("value").as_double() * Mpc; + origin.x = childValue(origin_node, "X_Mpc") * Mpc; + origin.y = childValue(origin_node, "Y_Mpc") * Mpc; + origin.z = childValue(origin_node, "Z_Mpc") * Mpc; cout << " - Origin: " << origin / Mpc << endl; - int Nx = node.child("Nx").attribute("value").as_int(); - int Ny = node.child("Ny").attribute("value").as_int(); - int Nz = node.child("Nz").attribute("value").as_int(); + int Nx = childValue(node, "Nx"); + int Ny = childValue(node, "Ny"); + int Nz = childValue(node, "Nz"); cout << " - Samples: " << Nx << " * " << Ny << " * " << Nz << endl; - double spacing = node.child("Step_Mpc").attribute("value").as_double() * Mpc; + double spacing = childValue(node, "Step_Mpc") * Mpc; cout << " - Spacing: " << spacing / Mpc << " Mpc " << endl; size.x = Nx * spacing; @@ -212,16 +235,16 @@ void XmlExecute::loadGridMagneticField(xml_node &node) { cout << " - Loading file (values in [G]): " << fname << endl; loadTxt(field, fname, gauss); } else { - double brms = node.child("RMS_muG").attribute("value").as_double() * 1e-6 * gauss; + double brms = childValue(node, "RMS_muG") * 1e-6 * gauss; cout << " - Brms : " << brms / nG << " nG" << endl; - double kMin = node.child("Kmin").attribute("value").as_double(); - double kMax = node.child("Kmax").attribute("value").as_double(); + double kMin = childValue(node, "Kmin"); + double kMax = childValue(node, "Kmax"); double lMin = spacing / kMax; double lMax = spacing / kMin; cout << " - Turbulent range: " << lMin / Mpc << " - " << lMax / Mpc << " Mpc" << endl; - double alpha = node.child("SpectralIndex").attribute("value").as_double(); + double alpha = childValue(node, "SpectralIndex"); cout << " - Turbulence spectral index: " << alpha << endl; cout << " - Random seed: " << randomSeed << endl; @@ -236,11 +259,22 @@ void XmlExecute::loadGridMagneticField(xml_node &node) { magnetic_field = new MagneticFieldGrid(field); } +void XmlExecute::loadPeriodicBoundaries() { + if ((size.x == 0) or (size.y == 0) or (size.z == 0)) + throw runtime_error("Environment boundaries not set."); + cout << "Periodic boundaries" << endl; + cout << " - Lower bounds: " << origin / Mpc << " Mpc" << endl; + cout << " - Upper bounds: " << (origin + size) / Mpc << " Mpc" << endl; + modules.add(new PeriodicBox(origin, size)); +} + void XmlExecute::loadSophia(xml_node &node) { + maxStep = childValue(node, "MaxStep_Mpc") * Mpc; + if (node.child("NoRedshift")) cout << " - No redshift" << endl; -// else -// redshift + else + cout << " - Redshift not implemented" << endl; if (node.child("NoPairProd")) cout << " - No pair production" << endl; @@ -255,7 +289,7 @@ void XmlExecute::loadSophia(xml_node &node) { modules.add(new ElectronPairProduction(IRB)); } - if (node.child("NoPhotoDisintegration")) + if (node.child("NoPhotodisintegration")) cout << " - No photo disintegration" << endl; else { modules.add(new PhotoDisintegration(CMB)); @@ -269,16 +303,16 @@ void XmlExecute::loadSophia(xml_node &node) { } void XmlExecute::loadSpheresAroundObserver(xml_node &node) { - double r = node.child("Radius_Mpc").attribute("value").as_double() * Mpc; + double r = childValue(node, "Radius_Mpc") * Mpc; cout << " - Radius: " << r / Mpc << " Mpc" << endl; int nObs = 0; for (xml_node n = node.child("SphereObserver"); n; n = n.next_sibling("SphereObserver")) { nObs += 1; Vector3d pos; - pos.x = n.child("CoordX_Mpc").attribute("value").as_double() * Mpc; - pos.y = n.child("CoordY_Mpc").attribute("value").as_double() * Mpc; - pos.z = n.child("CoordZ_Mpc").attribute("value").as_double() * Mpc; + pos.x = childValue(n, "CoordX_Mpc") * Mpc; + pos.y = childValue(n, "CoordY_Mpc") * Mpc; + pos.z = childValue(n, "CoordZ_Mpc") * Mpc; cout << " - Postion: " << pos / Mpc << " Mpc" << endl; modules.add(new SmallObserverSphere(pos, r)); } @@ -291,11 +325,11 @@ void XmlExecute::loadSpheresAroundSource(pugi::xml_node &node) { for (xml_node n = node.child("Sphere"); n; n = n.next_sibling("Sphere")) { nObs += 1; Vector3d pos; - pos.x = n.child("CoordX_Mpc").attribute("value").as_double() * Mpc; - pos.y = n.child("CoordY_Mpc").attribute("value").as_double() * Mpc; - pos.z = n.child("CoordZ_Mpc").attribute("value").as_double() * Mpc; - double r = n.child("Radius_Mpc").attribute("value").as_double() * Mpc; + pos.x = childValue(n, "CoordX_Mpc") * Mpc; + pos.y = childValue(n, "CoordY_Mpc") * Mpc; + pos.z = childValue(n, "CoordZ_Mpc") * Mpc; cout << " - Postion: " << pos / Mpc << " Mpc" << endl; + double r = childValue(n, "Radius_Mpc") * Mpc; cout << " - Radius: " << r / Mpc << " Mpc" << endl; SphericalBoundary *sphere = new SphericalBoundary(pos, r, "Detected"); modules.add(sphere); @@ -309,9 +343,9 @@ void XmlExecute::loadDiscreteSources(xml_node &node) { SourceMultiplePositions *positions = new SourceMultiplePositions(); for (xml_node n = node.child("PointSource"); n; n = n.next_sibling("PointSource")) { Vector3d pos; - pos.x = n.child("CoordX_Mpc").attribute("value").as_double() * Mpc; - pos.y = n.child("CoordY_Mpc").attribute("value").as_double() * Mpc; - pos.z = n.child("CoordZ_Mpc").attribute("value").as_double() * Mpc; + pos.x = childValue(n, "CoordX_Mpc") * Mpc; + pos.y = childValue(n, "CoordY_Mpc") * Mpc; + pos.z = childValue(n, "CoordZ_Mpc") * Mpc; cout << " - Position " << pos / Mpc << " Mpc" << endl; positions->add(pos); } @@ -324,9 +358,9 @@ void XmlExecute::loadDiscreteSources(xml_node &node) { if (spectrumType == "Monochromatic") { if (spec.child("Energy_EeV")) { - double E = spec.child("Energy_EeV").attribute("value").as_double() * EeV; - source.addProperty(new SourceEnergy(E)); + double E = childValue(spec, "Energy_EeV") * EeV; cout << " - Energy: " << E / EeV << " EeV" << endl; + source.addProperty(new SourceEnergy(E)); } else if (spec.child("Rigidity_EeV")) throw runtime_error("Fixed rigidity not implemented"); else @@ -336,25 +370,22 @@ void XmlExecute::loadDiscreteSources(xml_node &node) { SourceNuclei *composition = new SourceNuclei; xml_node p = node.child("Particles"); for (xml_node n = p.child("Species"); n; n = n.next_sibling("Species")) { - int A = n.child("MassNumber").attribute("value").as_int(); - int Z = n.child("ChargeNumber").attribute("value").as_int(); - double ab = n.child("Abundance").attribute("value").as_double(); + int A = (int)childValue(n, "MassNumber"); + int Z = (int)childValue(n, "ChargeNumber"); + double ab = childValue(n, "Abundance"); composition->add(getNucleusId(A, Z), ab); cout << " - Species: Z = " << Z << ", A = " << A << ", abundance = " << ab << endl; } source.addProperty(composition); } else if (spectrumType == "Power Law") { - if (!spec.child("Alpha")) - throw runtime_error(" --> source power law index missing"); - - double alpha = spec.child("Alpha").attribute("value").as_double(); + double alpha = childValue(spec, "Alpha"); cout << " - Power law index: " << alpha << endl; cout << " - Minimum energy: " << Emin / EeV << " EeV" << endl; - // if the source is accelerated + // if the source is accelerated to a maximum rigidity if (spec.child("Rigidity_EeV")) { - double Rmax = spec.child("Rigidity_EeV").attribute("value").as_double() * EeV; + double Rmax = childValue(spec, "Rigidity_EeV") * EeV; cout << " - Maximum rigidity: " << Rmax / EeV << " EeV" << endl; // combined source spectrum / composition @@ -370,7 +401,7 @@ void XmlExecute::loadDiscreteSources(xml_node &node) { source.addProperty(composition); } else if (spec.child("Ecut_EeV")) { - double Emax = spec.child("Ecut_EeV").attribute("value").as_double() * EeV; + double Emax = childValue(spec, "Ecut_EeV") * EeV; cout << " - Maximum energy: " << Emax / EeV << " EeV" << endl; // source spectrum @@ -387,6 +418,7 @@ void XmlExecute::loadDiscreteSources(xml_node &node) { composition->add(getNucleusId(A, Z), ab); } source.addProperty(composition); + } else throw runtime_error(" --> maximum source energy / rigidity missing"); diff --git a/test/xml/traj3d_ThrowNoBoundary.xml b/test/xml/traj3d_ThrowNoBoundary.xml index 72c89a37a..ee2dd1cdf 100644 --- a/test/xml/traj3d_ThrowNoBoundary.xml +++ b/test/xml/traj3d_ThrowNoBoundary.xml @@ -11,7 +11,7 @@ - traj3d_V3NoBound.txt + traj3d.txt diff --git a/test/xml/traj3d_kolmogoroff.xml b/test/xml/traj3d_kolmogoroff.xml index 78ec22423..25bc6d0b7 100644 --- a/test/xml/traj3d_kolmogoroff.xml +++ b/test/xml/traj3d_kolmogoroff.xml @@ -2,83 +2,83 @@ - - - - + + + + - - traj3d_kolmogoroff.txt - + + traj3d.txt + - - + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - + + + - - - - + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/test/xml/traj3d_nofield.xml b/test/xml/traj3d_nofield.xml index 5310a4604..32a382690 100644 --- a/test/xml/traj3d_nofield.xml +++ b/test/xml/traj3d_nofield.xml @@ -11,11 +11,18 @@ - "traj3d.txt" + traj3d.txt - + + + + + + + + diff --git a/test/xml/traj3d_uniform.xml b/test/xml/traj3d_uniform.xml index 936964122..f022c764f 100644 --- a/test/xml/traj3d_uniform.xml +++ b/test/xml/traj3d_uniform.xml @@ -3,70 +3,77 @@ - - - - - - - + + + + + + + - - - traj3d.txt - + + + traj3d.txt + - - + + + + + + + + + - - - - - - + + + + + + - - - - + + + + - - - - - - + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - + + + + + + - \ No newline at end of file + From 0a0963ce1b8c03150e750085d5813289e7ba85d2 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 6 Aug 2012 18:29:27 +0200 Subject: [PATCH 0167/1298] XmlExecute add missing isotropic emission --- src/XmlExecute.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 38addc9bb..0bb902d8d 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -339,6 +339,9 @@ void XmlExecute::loadSpheresAroundSource(pugi::xml_node &node) { } void XmlExecute::loadDiscreteSources(xml_node &node) { + // source isotropic emission + source.addProperty(new SourceIsotropicEmission()); + // source positions SourceMultiplePositions *positions = new SourceMultiplePositions(); for (xml_node n = node.child("PointSource"); n; n = n.next_sibling("PointSource")) { From ecf5c5bd3bdc3697647338eb5025428e43da1a76 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 6 Aug 2012 18:44:59 +0200 Subject: [PATCH 0168/1298] remove commata in CRPropaOutput add seeding random generator add maxStep to SimplePropagation --- include/mpc/module/SimplePropagation.h | 5 ++--- src/XmlExecute.cpp | 1 + src/module/DeflectionCK.cpp | 2 +- src/module/Output.cpp | 26 +++++++++++++------------- src/module/SimplePropagation.cpp | 15 +++++++++------ 5 files changed, 26 insertions(+), 23 deletions(-) diff --git a/include/mpc/module/SimplePropagation.h b/include/mpc/module/SimplePropagation.h index eb235ee88..b647d4324 100644 --- a/include/mpc/module/SimplePropagation.h +++ b/include/mpc/module/SimplePropagation.h @@ -11,11 +11,10 @@ namespace mpc { */ class SimplePropagation: public Module { private: - double acceleration; - double minimumStep; + double acceleration, minStep, maxStep; public: - SimplePropagation(double acceleration = 10, double minimumStep = 0.1 * kpc); + SimplePropagation(double acceleration = 10, double minStep = 0.1 * kpc, double maxStep = 4000 * Mpc); void process(Candidate *candidate) const; std::string getDescription() const; }; diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 0bb902d8d..6cffa4332 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -66,6 +66,7 @@ bool XmlExecute::load(const string &filename) { cout << "Minimum Energy: " << Emin / EeV << " EeV" << endl; randomSeed = (int)childValue(root, "RandomSeed"); + Random(randomSeed); cout << "RandomSeed: " << randomSeed << endl; xml_node node; diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index d5621c51a..0030d716c 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -64,7 +64,7 @@ void DeflectionCK::process(Candidate *candidate) const { Vector3d dir = candidate->current.getDirection(); candidate->current.setPosition(pos + dir * step); candidate->setCurrentStep(step); - candidate->setNextStep(step * 5); + candidate->setNextStep(maxStep); return; } diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 7921d87de..18a05d644 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -114,29 +114,29 @@ void CRPropa2EventOutput::process(Candidate *candidate) const { size_t p = 0; // length of line int cid = convertToCRPropaId(candidate->current.getId()); - p += sprintf(buffer + p, "%i, ", cid); + p += sprintf(buffer + p, "%i ", cid); int iid = convertToCRPropaId(candidate->initial.getId()); - p += sprintf(buffer + p, "%i, ", iid); + p += sprintf(buffer + p, "%i ", iid); const Vector3d &ipos = candidate->initial.getPosition() / Mpc; - p += sprintf(buffer + p, ", %.4f, %.4f, %.4f", ipos.x, ipos.y, ipos.z); + p += sprintf(buffer + p, "%.4f %.4f %.4f ", ipos.x, ipos.y, ipos.z); double iPhi = candidate->initial.getDirection().getPhi(); double iTheta = candidate->initial.getDirection().getTheta(); double iE = candidate->initial.getEnergy() / EeV; - p += sprintf(buffer + p, ", %.4f, %.4f, %.4f", iE, iPhi, iTheta); + p += sprintf(buffer + p, "%.4f %.4f %.4f ", iE, iPhi, iTheta); double t = candidate->getTrajectoryLength() / Mpc; - p += sprintf(buffer + p, ", %.4f", t); + p += sprintf(buffer + p, "%.4f ", t); const Vector3d &pos = candidate->current.getPosition() / Mpc; - p += sprintf(buffer + p, ", %.4f, %.4f, %.4f", ipos.x, ipos.y, ipos.z); + p += sprintf(buffer + p, "%.4f %.4f %.4f ", ipos.x, ipos.y, ipos.z); double phi = candidate->current.getDirection().getPhi(); double theta = candidate->current.getDirection().getTheta(); double E = candidate->current.getEnergy() / EeV; - p += sprintf(buffer + p, ", %.4f, %.4f, %.4f\n", E, phi, theta); + p += sprintf(buffer + p, "%.4f %.4f %.4f\n", E, phi, theta); #pragma omp critical { @@ -162,22 +162,22 @@ void CRPropa2TrajectoryOutput::process(Candidate *candidate) const { size_t p = 0; int cid = convertToCRPropaId(candidate->current.getId()); - p += sprintf(buffer + p, "%i", cid); + p += sprintf(buffer + p, "%i ", cid); int iid = convertToCRPropaId(candidate->initial.getId()); - p += sprintf(buffer + p, ", %i", iid); + p += sprintf(buffer + p, "%i ", iid); double t = candidate->getTrajectoryLength() / Mpc; - p += sprintf(buffer + p, ", %.4f", t); + p += sprintf(buffer + p, "%.4f ", t); const Vector3d &pos = candidate->current.getPosition() / Mpc; - p += sprintf(buffer + p, ", %.4f, %.4f, %.4f", pos.x, pos.y, pos.z); + p += sprintf(buffer + p, "%.4f %.4f %.4f ", pos.x, pos.y, pos.z); const Vector3d &mom = candidate->current.getMomentum() / EeV; - p += sprintf(buffer + p, ", %.4g, %.4g, %.4g", mom.x, mom.y, mom.z); + p += sprintf(buffer + p, "%.4g %.4g %.4g ", mom.x, mom.y, mom.z); double E = candidate->current.getEnergy() / EeV; - p += sprintf(buffer + p, ", %.4f\n", E); + p += sprintf(buffer + p, "%.4f\n", E); #pragma omp critical { diff --git a/src/module/SimplePropagation.cpp b/src/module/SimplePropagation.cpp index 29ed19933..1866ae44b 100644 --- a/src/module/SimplePropagation.cpp +++ b/src/module/SimplePropagation.cpp @@ -2,17 +2,20 @@ namespace mpc { -SimplePropagation::SimplePropagation(double acceleration, double minimumStep) : - acceleration(acceleration), minimumStep(minimumStep) { +SimplePropagation::SimplePropagation(double accel, double minStep, + double maxStep) : + acceleration(accel), minStep(minStep), maxStep(maxStep) { } void SimplePropagation::process(Candidate *candidate) const { - double nextStep = std::max(minimumStep, candidate->getNextStep()); + double step = candidate->getNextStep(); + step = std::max(step, minStep); + step = std::min(step, maxStep); Vector3d pos = candidate->current.getPosition(); Vector3d dir = candidate->current.getDirection(); - candidate->current.setPosition(pos + dir * nextStep); - candidate->setCurrentStep(nextStep); - candidate->setNextStep(nextStep * acceleration); + candidate->current.setPosition(pos + dir * step); + candidate->setCurrentStep(step); + candidate->setNextStep(maxStep); } std::string SimplePropagation::getDescription() const { From 21224387e96dee176adf3bd2f00fd7546dfab11e Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 6 Aug 2012 18:57:06 +0200 Subject: [PATCH 0169/1298] remove random seeding in XmlExecute --- src/XmlExecute.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 6cffa4332..0bb902d8d 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -66,7 +66,6 @@ bool XmlExecute::load(const string &filename) { cout << "Minimum Energy: " << Emin / EeV << " EeV" << endl; randomSeed = (int)childValue(root, "RandomSeed"); - Random(randomSeed); cout << "RandomSeed: " << randomSeed << endl; xml_node node; From f8d7d92bd3c53a5b88cd4fbaa42725ffdcf3a748 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 8 Aug 2012 12:18:20 +0200 Subject: [PATCH 0170/1298] fixed reflective boundaries, added test script --- include/mpc/module/BreakCondition.h | 3 + src/ModuleList.cpp | 10 ++- src/module/BreakCondition.cpp | 55 ++++++++-------- test/python/testBoundaries.py | 62 +++++++++++++++++++ ...testSource.py => testSourceComposition.py} | 2 +- 5 files changed, 99 insertions(+), 33 deletions(-) create mode 100644 test/python/testBoundaries.py rename test/python/{testSource.py => testSourceComposition.py} (97%) diff --git a/include/mpc/module/BreakCondition.h b/include/mpc/module/BreakCondition.h index 3116e407f..e7ab438cf 100644 --- a/include/mpc/module/BreakCondition.h +++ b/include/mpc/module/BreakCondition.h @@ -75,6 +75,7 @@ class SmallObserverSphere: public Module { @brief Rectangular box with periodic boundaries. If a particle passes on of the sides it is placed at the opposite side and its initial (source) position changed accordingly. + This realizes periodic boundaries, where the particle is kept inside the box and the source is moved away from the box. Particles can overshoot (be outside of the box during the step) since the step size is not limited by this module. */ class PeriodicBox: public Module { @@ -93,6 +94,8 @@ class PeriodicBox: public Module { @brief Rectangular box with reflective boundaries. If a particle passes on of the sides it is reflected back inside (position and velocity) and its initial position changed as if the particle had come from that side. + This realizes reflective boundaries, where the particle is kept inside the box and the source is moved away from the box. + The translation currently does not work correctly if the particle's distance to the box is larger than one box size. Particles can overshoot (be outside of the box during the step) since the step size is not limited by this module. */ class ReflectiveBox: public Module { diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 87d57e90f..1425e4cbb 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -55,8 +55,7 @@ void ModuleList::run(candidate_vector_t &candidates, bool recursive) { #endif ProgressBar *progressbar = NULL; - if (showProgress) - { + if (showProgress) { progressbar = new ProgressBar("Run ModuleList", count); } @@ -67,7 +66,7 @@ void ModuleList::run(candidate_vector_t &candidates, bool recursive) { run(candidates[i], recursive); if (progressbar) - #pragma omp critical(progressbarUpdate) +#pragma omp critical(progressbarUpdate) progressbar->update(); } } @@ -80,8 +79,7 @@ void ModuleList::run(Source *source, size_t count, bool recursive) { #endif ProgressBar *progressbar = NULL; - if (showProgress) - { + if (showProgress) { progressbar = new ProgressBar("Run ModuleList", count); } @@ -92,7 +90,7 @@ void ModuleList::run(Source *source, size_t count, bool recursive) { ref_ptr candidate = new Candidate(state); run(candidate, recursive); if (progressbar) - #pragma omp critical(progressbarUpdate) +#pragma omp critical(progressbarUpdate) progressbar->update(); } } diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp index 37acb26ac..594fe0446 100644 --- a/src/module/BreakCondition.cpp +++ b/src/module/BreakCondition.cpp @@ -101,12 +101,14 @@ PeriodicBox::PeriodicBox(Vector3d origin, Vector3d size) { } void PeriodicBox::process(Candidate *c) const { - Vector3d relPos = c->current.getPosition() - origin; - Vector3d n = (relPos / size).floor(); // integers for translation - if ((n.x != 0) or (n.y != 0) or (n.z != 0)) { - c->initial.setPosition(c->initial.getPosition() - n * size); - c->current.setPosition(c->current.getPosition() - n * size); - } + Vector3d pos = c->current.getPosition(); + Vector3d n = ((pos - origin) / size).floor(); + + if ((n.x == 0) and (n.y == 0) and (n.z == 0)) + return; // do nothing if candidate is inside the box + + c->initial.setPosition(c->initial.getPosition() - n * size); + c->current.setPosition(pos - n * size); } void PeriodicBox::updateDescription() { @@ -123,26 +125,27 @@ ReflectiveBox::ReflectiveBox(Vector3d origin, Vector3d size) { void ReflectiveBox::process(Candidate *c) const { Vector3d pos = c->current.getPosition(); - Vector3d n = ((pos - origin) / size).floor(); // integers for translation - if ((n.x != 0) or (n.y != 0) or (n.z != 0)) { - // flip direction - Vector3d idir = c->initial.getDirection(); - idir.x *= pow(-1, n.x); - idir.y *= pow(-1, n.y); - idir.z *= pow(-1, n.z); - c->initial.setDirection(idir); - - Vector3d dir = c->current.getDirection(); - dir.x *= pow(-1, n.x); - dir.y *= pow(-1, n.y); - dir.z *= pow(-1, n.z); - c->current.setDirection(dir); - - // translate back into the box - Vector3d ipos = c->initial.getPosition(); - c->initial.setPosition(ipos + (size - (ipos - origin)) * n * 2); - c->current.setPosition(pos - ((pos - origin) % size) * n * 2); - } + Vector3d n = ((pos - origin) / size).floor(); + + if ((n.x == 0) and (n.y == 0) and (n.z == 0)) + return; // do nothing if candidate is inside the box + + // flip direction + Vector3d nReflect(pow(-1, n.x), pow(-1, n.y), pow(-1, n.z)); + c->current.setDirection(c->current.getDirection() * nReflect); + c->initial.setDirection(c->initial.getDirection() * nReflect); + + Vector3d isOutside(n.x != 0, n.y != 0, n.z != 0); + Vector3d isHigh(n.x > 0, n.y > 0, n.z > 0); + + // translate current position + Vector3d dist = (origin + isHigh * size - pos); // distance to boundary + c->current.setPosition(pos + isOutside * dist * 2 ); + + // translate initial position + Vector3d ipos = c->initial.getPosition(); + Vector3d idist = (origin + isHigh * size - ipos); // distance to boundary + c->initial.setPosition(ipos + isOutside * idist * 2 ); } void ReflectiveBox::updateDescription() { diff --git a/test/python/testBoundaries.py b/test/python/testBoundaries.py new file mode 100644 index 000000000..0ffc0dd34 --- /dev/null +++ b/test/python/testBoundaries.py @@ -0,0 +1,62 @@ +import pylab as pl +import matplotlib.patches as mpatches +from mpc import * + + +p = ParticleState() +p.setPosition(Vector3d(-5, -5, 0)) +p.setDirection(Vector3d(1,0.25,0)) + +N = 45 +x, y, sx, sy = pl.zeros((4,N)) + + +# simulate periodic boundaries +m1 = ModuleList() +m1.add(SimplePropagation(10, 0, 1)) +m1.add(PeriodicBox(Vector3d(-10), Vector3d(20))) + +c = Candidate(p) +for i in range(N): + m1.process(c) + pos = c.current.getPosition() + x[i], y[i] = pos.x, pos.y + src = c.initial.getPosition() + sx[i], sy[i] = src.x, src.y + +pl.figure(figsize=(8,6)) +ax1 = pl.subplot(211, aspect='equal') +ax1.add_patch(mpatches.Rectangle((-10,-10), 20, 20, facecolor="lightskyblue")) +ax1.plot(x, y, 'b.', ms=5) +ax1.plot(sx, sy, 'r*', markeredgewidth=0, ms=10) +ax1.set_xlim((-51, 31)) +ax1.set_ylim((-11, 11)) +ax1.grid() +ax1.set_title('Periodic Boundaries') + + +# simulate reflective boundaries +m2 = ModuleList() +m2.add(SimplePropagation(10, 0, 1)) +m2.add(ReflectiveBox(Vector3d(-10), Vector3d(20))) + +c = Candidate(p) + +for i in range(N): + m2.process(c) + pos = c.current.getPosition() + x[i], y[i] = pos.x, pos.y + src = c.initial.getPosition() + sx[i], sy[i] = src.x, src.y + +ax2 = pl.subplot(212, aspect='equal') +ax2.add_patch(mpatches.Rectangle((-10,-10), 20, 20, facecolor="lightskyblue")) +ax2.plot(x, y, 'b.', ms=5) +ax2.plot(sx, sy, 'r*', markeredgewidth=0, ms=10) +ax2.set_xlim((-51, 31)) +ax2.set_ylim((-11, 11)) +ax2.grid() +ax2.set_title('Reflective Boundaries') + +pl.savefig('Boundaries.png', bbox_inches='tight') +pl.show() diff --git a/test/python/testSource.py b/test/python/testSourceComposition.py similarity index 97% rename from test/python/testSource.py rename to test/python/testSourceComposition.py index 3a606a6e5..bb52a87c6 100644 --- a/test/python/testSource.py +++ b/test/python/testSourceComposition.py @@ -48,5 +48,5 @@ xlim(2, 3) semilogy() grid() -savefig('Source.png') +savefig('SourceCompostion.png') show() From cd9f78a98d3ab3540f16a6219d5eaf69c15bd530 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 8 Aug 2012 12:49:28 +0200 Subject: [PATCH 0171/1298] changed format of TrajectoryOutput and ConditionalOutput --- src/module/Output.cpp | 73 +++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 41 deletions(-) diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 18a05d644..c6ba7b535 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -11,28 +11,29 @@ namespace mpc { TrajectoryOutput::TrajectoryOutput(std::string name) { setDescription("Trajectory output"); outfile.open(name.c_str()); - outfile << "# Age, HepId, E, posX, posY, posZ, dirX, dirY, dirZ, event\n"; + outfile + << "# Age[Mpc] PDG_Code Energy[EeV] Position(X,Y,Z)[Mpc] Direction(X,Y,Z)\n"; } TrajectoryOutput::~TrajectoryOutput() { outfile.close(); } -void TrajectoryOutput::process(Candidate *candidate) const { +void TrajectoryOutput::process(Candidate *c) const { char buffer[1024]; - size_t pos = 0; - pos += ::sprintf(buffer + pos, "%.4f, %d, %.4f", - candidate->getTrajectoryLength() / Mpc, candidate->current.getId(), - candidate->current.getEnergy() / EeV); - Vector3d position = candidate->current.getPosition() / Mpc; - pos += ::sprintf(buffer + pos, ", %.4f, %.4f, %.4f", position.x, position.y, - position.z); - const Vector3d &dir = candidate->current.getDirection(); - pos += ::sprintf(buffer + pos, ", %.4f, %.4f, %.4f\n", dir.x, dir.y, dir.z); + size_t p = 0; + + p += sprintf(buffer + p, "%9.4f\t", c->getTrajectoryLength() / Mpc); + p += sprintf(buffer + p, "%10i\t", c->current.getId()); + p += sprintf(buffer + p, "%8.4f\t", c->current.getEnergy() / EeV); + Vector3d pos = c->current.getPosition() / Mpc; + p += sprintf(buffer + p, "%8.4f\t%8.4f\t%8.4f\t", pos.x, pos.y, pos.z); + const Vector3d &dir = c->current.getDirection(); + p += sprintf(buffer + p, "%7.4f\t%7.4f\t%7.4f\n", dir.x, dir.y, dir.z); #pragma omp critical { - outfile.write(buffer, pos); + outfile.write(buffer, p); } } @@ -43,8 +44,7 @@ ConditionalOutput::ConditionalOutput(std::string filename, propertyName = propName; outfile.open(filename.c_str()); outfile - << "# id, x, y, z, E, phi, theta, distance, i_id, i_x, i_y, i_z, i_E, i_phi, i_theta" - << std::endl; + << "# PDG_Code Energy[EeV] Position(X,Y,Z)[Mpc] Direction(Phi,Theta) Age[Mpc] Initial_PDG_Code Initial_Energy[EeV] Initial_Position(X,Y,Z)[Mpc] Initial_Direction(Phi,Theta)\n"; } ConditionalOutput::~ConditionalOutput() { @@ -55,33 +55,24 @@ void ConditionalOutput::setRemoveProperty(bool removeProperty) { this->removeProperty = removeProperty; } -void ConditionalOutput::process(Candidate *candidate) const { - if (candidate->hasProperty(propertyName)) { +void ConditionalOutput::process(Candidate *c) const { + if (c->hasProperty(propertyName)) { char buffer[256]; size_t p = 0; - p += sprintf(buffer + p, "%i", candidate->current.getId()); - - const Vector3d &pos = candidate->current.getPosition() / Mpc; - p += sprintf(buffer + p, ", %.4f, %.4f, %.4f", pos.x, pos.y, pos.z); - - const Vector3d &dir = candidate->current.getDirection(); - p += sprintf(buffer + p, ", %.4f, %.4f, %.4f", - candidate->current.getEnergy() / EeV, dir.getPhi(), - dir.getTheta()); - - p += sprintf(buffer + p, ", %.4f", - candidate->getTrajectoryLength() / Mpc); - - p += sprintf(buffer + p, ", %i", candidate->initial.getId()); - - const Vector3d &ipos = candidate->initial.getPosition() / Mpc; - p += sprintf(buffer + p, ", %.4f, %.4f, %.4f", ipos.x, ipos.y, ipos.z); - - const Vector3d &idir = candidate->initial.getDirection(); - p += sprintf(buffer + p, ", %.4f, %.4f, %.4f\n", - candidate->initial.getEnergy() / EeV, idir.getPhi(), - idir.getTheta()); + p += sprintf(buffer + p, "%10i\t", c->current.getId()); + p += sprintf(buffer + p, "%8.4f\t", c->current.getEnergy() / EeV); + const Vector3d &pos = c->current.getPosition() / Mpc; + p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", pos.x, pos.y, pos.z); + const Vector3d &dir = c->current.getDirection(); + p += sprintf(buffer + p, "%6.4f\t%7.4f\t", dir.getPhi(), dir.getTheta()); + p += sprintf(buffer + p, "%9.4f\t", c->getTrajectoryLength() / Mpc); + p += sprintf(buffer + p, "%10i\t", c->initial.getId()); + p += sprintf(buffer + p, "%8.4f\t", c->initial.getEnergy() / EeV); + const Vector3d &ipos = c->initial.getPosition() / Mpc; + p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", ipos.x, ipos.y, ipos.z); + const Vector3d &idir = c->initial.getDirection(); + p += sprintf(buffer + p, "%6.4f\t%7.4f\n", idir.getPhi(), idir.getTheta()); #pragma omp critical { @@ -89,7 +80,7 @@ void ConditionalOutput::process(Candidate *candidate) const { } if (removeProperty) { - candidate->removeProperty(propertyName); + c->removeProperty(propertyName); } } } @@ -193,8 +184,8 @@ void ShellOutput::process(Candidate *candidate) const { std::cout << candidate->getTrajectoryLength() / Mpc << " Mpc, "; std::cout << candidate->current.getId() << ", "; std::cout << candidate->current.getEnergy() / EeV << " EeV, "; - std::cout << candidate->current.getPosition() / Mpc << " Mpc, "; - std::cout << candidate->current.getDirection().getPhi() << " / "; + std::cout << candidate->current.getPosition() / Mpc << " Mpc, "; + std::cout << candidate->current.getDirection().getPhi() << " "; std::cout << candidate->current.getDirection().getTheta(); std::cout << std::endl; } From 24c8432961c77153f0a2c8cf18909aa3679ae19a Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 8 Aug 2012 13:46:00 +0200 Subject: [PATCH 0172/1298] fixed propagation + tests --- CMakeLists.txt | 4 ++ include/mpc/module/DeflectionCK.h | 5 +- include/mpc/module/SimplePropagation.h | 7 +- src/module/SimplePropagation.cpp | 6 +- test/testCore.cpp | 95 ++++++-------------------- test/testPropagation.cpp | 46 +++---------- test/testSource.cpp | 2 +- test/testVector3.cpp | 84 +++++++++++++++++++++++ 8 files changed, 132 insertions(+), 117 deletions(-) create mode 100644 test/testVector3.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b8487522..470f6130b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,6 +123,10 @@ if(ENABLETESTING) target_link_libraries(testCore mpc gtest gtest_main pthread) add_test(testCore testCore) + add_executable(testVector3 test/testVector3.cpp) + target_link_libraries(testVector3 mpc gtest gtest_main pthread) + add_test(testVector3 testVector3) + add_executable(testModuleList test/testModuleList.cpp) target_link_libraries(testModuleList mpc gtest gtest_main pthread) add_test(testModuleList testModuleList) diff --git a/include/mpc/module/DeflectionCK.h b/include/mpc/module/DeflectionCK.h index e9cc1d418..04a2e6459 100644 --- a/include/mpc/module/DeflectionCK.h +++ b/include/mpc/module/DeflectionCK.h @@ -15,6 +15,8 @@ namespace mpc { This module solves the equations of motion of a charged particle when propagating through a magnetic field.\n It uses the Runge-Kutta integration method with Cash-Karp coefficients.\n The step size control tries to keep the relative error close to, but smaller than the designated tolerance. + Additionally a minimum and maximum size for the steps can be set. + For neutral particles a rectalinear propagation is applied and a next step of the maximum step size proposed. */ class DeflectionCK: public Module { ref_ptr field; @@ -24,8 +26,7 @@ class DeflectionCK: public Module { public: DeflectionCK(ref_ptr field, double tolerance = 1e-4, - double minStep = 0.1 * kpc, - double maxStep = std::numeric_limits::max()); + double minStep = 0.1 * kpc, double maxStep = 4000 * Mpc); std::string getDescription() const; void process(Candidate *candidate) const; }; diff --git a/include/mpc/module/SimplePropagation.h b/include/mpc/module/SimplePropagation.h index b647d4324..3566e5a52 100644 --- a/include/mpc/module/SimplePropagation.h +++ b/include/mpc/module/SimplePropagation.h @@ -8,13 +8,16 @@ namespace mpc { /** @class SimplePropagation @brief Simple rectalinear propagation in absence of magnetic fields. + + This module performs a rectalinear propagation. + It always proposes a next step of the maximum step size. */ class SimplePropagation: public Module { private: - double acceleration, minStep, maxStep; + double minStep, maxStep; public: - SimplePropagation(double acceleration = 10, double minStep = 0.1 * kpc, double maxStep = 4000 * Mpc); + SimplePropagation(double minStep = 0.1 * kpc, double maxStep = 4000 * Mpc); void process(Candidate *candidate) const; std::string getDescription() const; }; diff --git a/src/module/SimplePropagation.cpp b/src/module/SimplePropagation.cpp index 1866ae44b..2a2a31623 100644 --- a/src/module/SimplePropagation.cpp +++ b/src/module/SimplePropagation.cpp @@ -2,15 +2,13 @@ namespace mpc { -SimplePropagation::SimplePropagation(double accel, double minStep, - double maxStep) : - acceleration(accel), minStep(minStep), maxStep(maxStep) { +SimplePropagation::SimplePropagation(double minStep, double maxStep) : + minStep(minStep), maxStep(maxStep) { } void SimplePropagation::process(Candidate *candidate) const { double step = candidate->getNextStep(); step = std::max(step, minStep); - step = std::min(step, maxStep); Vector3d pos = candidate->current.getPosition(); Vector3d dir = candidate->current.getDirection(); candidate->current.setPosition(pos + dir * step); diff --git a/test/testCore.cpp b/test/testCore.cpp index ca5aea13c..5e7930bd4 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -110,6 +110,28 @@ TEST(Candidate, property) { EXPECT_EQ("bar", value); } +TEST(Candidate, addSecondary) { + Candidate c; + c.setRedshift(5); + c.setTrajectoryLength(23); + c.initial.setId(getNucleusId(56,26)); + c.initial.setEnergy(1000); + c.initial.setPosition(Vector3d(1,2,3)); + c.initial.setDirection(Vector3d(0,0,1)); + + c.addSecondary(getNucleusId(1,1), 200); + Candidate s = *c.secondaries[0]; + + EXPECT_EQ(getNucleusId(1,1), s.current.getId()); + EXPECT_EQ(200, s.current.getEnergy()); + + EXPECT_EQ(5, s.getRedshift()); + EXPECT_EQ(23, s.getTrajectoryLength()); + EXPECT_EQ(1000, s.initial.getEnergy()); + EXPECT_TRUE(Vector3d(1,2,3) == s.initial.getPosition()); + EXPECT_TRUE(Vector3d(0,0,1) == s.initial.getDirection()); +} + TEST(common, digit) { EXPECT_EQ(1, digit(1234, 1000)); EXPECT_EQ(2, digit(1234, 100)); @@ -149,79 +171,6 @@ TEST(common, interpolateEquidistant) { EXPECT_NEAR(pow(1.5001, 2), yInt, 1e-4); } -TEST(Vector3, division) { - Vector3d v(10); - v /= 10; - EXPECT_DOUBLE_EQ(v.x, 1); - EXPECT_DOUBLE_EQ(v.y, 1); - EXPECT_DOUBLE_EQ(v.z, 1); - v = Vector3d(10) / Vector3d(2); // element-wise division - EXPECT_DOUBLE_EQ(v.x, 5); - EXPECT_DOUBLE_EQ(v.y, 5); - EXPECT_DOUBLE_EQ(v.z, 5); -} - -TEST(Vector3, mod) { - Vector3d v(10.1, 10.2, 10.3); - v %= 10.2; - EXPECT_NEAR(v.x, 10.1, 1e-10); // mod doesn't preserve double precision - EXPECT_NEAR(v.y, 0, 1e-10); - EXPECT_NEAR(v.z, 0.1, 1e-10); -} - -TEST(Vector3, dot) { - double a = Vector3d(1, 0, 0).dot(Vector3d(0, 1, 0)); - EXPECT_DOUBLE_EQ(a, 0); - double b = Vector3d(-1, 10, 2).dot(Vector3d(5, 1, -3)); - EXPECT_DOUBLE_EQ(b, -1); -} - -TEST(Vector3, cross) { - Vector3d v = Vector3d(1, 0, 0).cross(Vector3d(0, 1, 0)); - EXPECT_DOUBLE_EQ(v.x, 0); - EXPECT_DOUBLE_EQ(v.y, 0); - EXPECT_DOUBLE_EQ(v.z, 1); -} - -TEST(Vector3, angle) { - double a = Vector3d(1, 1, 0).getAngleTo(Vector3d(1, 0, 0)); - EXPECT_DOUBLE_EQ(a, 45 * M_PI / 180); - double b = Vector3d(0, 0, 1).getAngleTo(Vector3d(0, 0, 1)); - EXPECT_DOUBLE_EQ(b, 0); -} - -TEST(Vector3, magnitude) { - Vector3d v = Vector3d(1, 2, -2); - EXPECT_DOUBLE_EQ(v.getMag(), 3); - EXPECT_DOUBLE_EQ(v.getMag2(), 9); -} - -TEST(Vector3, distance) { - double a = Vector3d(10, 0, 10).getDistanceTo(Vector3d(10, 0, 0)); - EXPECT_DOUBLE_EQ(a, 10); -} - -TEST(Vector3, rotation) { - Vector3d v(10, 0, 0); - v.rotate(Vector3d(0, 2, 0), M_PI); - EXPECT_NEAR(v.x, -10, 1e-9); - // rotation doesn't preserve double precision - EXPECT_NEAR(v.y, 0, 1e-9); - EXPECT_NEAR(v.z, 0, 1e-9); - - v = Vector3d(10, 0, 0); - v.rotate(Vector3d(1, 0, 0), M_PI); // no rotation - EXPECT_NEAR(v.x, 10, 1e-9); - EXPECT_NEAR(v.y, 0, 1e-9); - EXPECT_NEAR(v.z, 0, 1e-9); - - v = Vector3d(5, 2, 7); - v.rotate(Vector3d(1, 8, -4), 2 * M_PI); // full rotation - EXPECT_NEAR(v.x, 5, 1e-9); - EXPECT_NEAR(v.y, 2, 1e-9); - EXPECT_NEAR(v.z, 7, 1e-9); -} - TEST(NucleusId, crpropaScheme) { EXPECT_EQ(getNucleusId(56, 26), convertFromCRPropaId(26056)); EXPECT_EQ(26056, convertToCRPropaId(getNucleusId(56, 26))); diff --git a/test/testPropagation.cpp b/test/testPropagation.cpp index 73b4b009a..2dd6bb988 100644 --- a/test/testPropagation.cpp +++ b/test/testPropagation.cpp @@ -7,26 +7,11 @@ namespace mpc { -TEST(testSimplePropagation, noMinStep) { - ParticleState p; - p.setPosition(Vector3d(0, 0, 0)); - p.setDirection(Vector3d(0, 1, 0)); - - Candidate c(p); - c.setNextStep(10); - - double acceleration = 5; - double minStep = 0; - SimplePropagation propa(acceleration, minStep); - propa.process(&c); - - EXPECT_EQ(10, c.getCurrentStep()); - EXPECT_EQ(50, c.getNextStep()); - EXPECT_EQ(Vector3d(0,10,0), c.current.getPosition()); - EXPECT_EQ(Vector3d(0,1,0), c.current.getDirection()); -} +TEST(testSimplePropagation, step) { + double minStep = 20; + double maxStep = 100; + SimplePropagation propa(minStep, maxStep); -TEST(testSimplePropagation, withMinStep) { ParticleState p; p.setPosition(Vector3d(0, 0, 0)); p.setDirection(Vector3d(0, 1, 0)); @@ -34,31 +19,25 @@ TEST(testSimplePropagation, withMinStep) { Candidate c(p); c.setNextStep(10); - double acceleration = 5; - double minStep = 20; - SimplePropagation propa(acceleration, minStep); propa.process(&c); - EXPECT_EQ(20, c.getCurrentStep()); - EXPECT_EQ(100, c.getNextStep()); + EXPECT_EQ(minStep, c.getCurrentStep()); + EXPECT_EQ(maxStep, c.getNextStep()); EXPECT_EQ(Vector3d(0,20,0), c.current.getPosition()); EXPECT_EQ(Vector3d(0,1,0), c.current.getDirection()); } TEST(testDeflectionCK, proton) { + DeflectionCK propa(new UniformMagneticField(Vector3d(0, 0, 1 * nG))); + ParticleState p; p.setId(getNucleusId(1, 1)); p.setEnergy(100 * EeV); p.setPosition(Vector3d(0, 0, 0)); p.setDirection(Vector3d(0, 1, 0)); - Candidate c(p); c.setNextStep(0); - ref_ptr field = new UniformMagneticField( - Vector3d(0, 0, 1e-12)); - - DeflectionCK propa(field); propa.process(&c); EXPECT_DOUBLE_EQ(0.1 * kpc, c.getCurrentStep()); @@ -66,22 +45,19 @@ TEST(testDeflectionCK, proton) { } TEST(testDeflectionCK, neutron) { + DeflectionCK propa(new UniformMagneticField(Vector3d(0, 0, 1 * nG))); + ParticleState p; p.setId(getNucleusId(1, 0)); p.setEnergy(100 * EeV); p.setPosition(Vector3d(0, 0, 0)); p.setDirection(Vector3d(0, 1, 0)); - Candidate c(p); - ref_ptr field = new UniformMagneticField( - Vector3d(0, 0, 1e-12)); - - DeflectionCK propa(field); propa.process(&c); EXPECT_DOUBLE_EQ(0.1 * kpc, c.getCurrentStep()); - EXPECT_DOUBLE_EQ(0.5 * kpc, c.getNextStep()); + EXPECT_DOUBLE_EQ(4000 * Mpc, c.getNextStep()); EXPECT_EQ(Vector3d(0, 0.1 * kpc, 0), c.current.getPosition()); EXPECT_EQ(Vector3d(0, 1, 0), c.current.getDirection()); } diff --git a/test/testSource.cpp b/test/testSource.cpp index e12de2da7..8bb1b3b52 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -108,7 +108,7 @@ TEST(testSourceList, luminosity) { meanE += p.getEnergy(); } meanE /= 1000; - EXPECT_NEAR(80, meanE, 1); // this test can stochastically fail + EXPECT_NEAR(80, meanE, 2); // this test can stochastically fail } int main(int argc, char **argv) { diff --git a/test/testVector3.cpp b/test/testVector3.cpp new file mode 100644 index 000000000..dd2b1ad07 --- /dev/null +++ b/test/testVector3.cpp @@ -0,0 +1,84 @@ +#include "mpc/Vector3.h" +#include "gtest/gtest.h" + +namespace mpc { + +TEST(Vector3, division) { + Vector3d v(10); + v /= 10; + EXPECT_DOUBLE_EQ(v.x, 1); + EXPECT_DOUBLE_EQ(v.y, 1); + EXPECT_DOUBLE_EQ(v.z, 1); + v = Vector3d(10) / Vector3d(2); // element-wise division + EXPECT_DOUBLE_EQ(v.x, 5); + EXPECT_DOUBLE_EQ(v.y, 5); + EXPECT_DOUBLE_EQ(v.z, 5); +} + +TEST(Vector3, mod) { + Vector3d v(10.1, 10.2, 10.3); + v %= 10.2; + EXPECT_NEAR(v.x, 10.1, 1e-10); // mod doesn't preserve double precision + EXPECT_NEAR(v.y, 0, 1e-10); + EXPECT_NEAR(v.z, 0.1, 1e-10); +} + +TEST(Vector3, dot) { + double a = Vector3d(1, 0, 0).dot(Vector3d(0, 1, 0)); + EXPECT_DOUBLE_EQ(a, 0); + double b = Vector3d(-1, 10, 2).dot(Vector3d(5, 1, -3)); + EXPECT_DOUBLE_EQ(b, -1); +} + +TEST(Vector3, cross) { + Vector3d v = Vector3d(1, 0, 0).cross(Vector3d(0, 1, 0)); + EXPECT_DOUBLE_EQ(v.x, 0); + EXPECT_DOUBLE_EQ(v.y, 0); + EXPECT_DOUBLE_EQ(v.z, 1); +} + +TEST(Vector3, angle) { + double a = Vector3d(1, 1, 0).getAngleTo(Vector3d(1, 0, 0)); + EXPECT_DOUBLE_EQ(a, 45 * M_PI / 180); + double b = Vector3d(0, 0, 1).getAngleTo(Vector3d(0, 0, 1)); + EXPECT_DOUBLE_EQ(b, 0); +} + +TEST(Vector3, magnitude) { + Vector3d v = Vector3d(1, 2, -2); + EXPECT_DOUBLE_EQ(v.getMag(), 3); + EXPECT_DOUBLE_EQ(v.getMag2(), 9); +} + +TEST(Vector3, distance) { + double a = Vector3d(10, 0, 10).getDistanceTo(Vector3d(10, 0, 0)); + EXPECT_DOUBLE_EQ(a, 10); +} + +TEST(Vector3, rotation) { + Vector3d v(10, 0, 0); + v.rotate(Vector3d(0, 2, 0), M_PI); + EXPECT_NEAR(v.x, -10, 1e-9); + // rotation doesn't preserve double precision + EXPECT_NEAR(v.y, 0, 1e-9); + EXPECT_NEAR(v.z, 0, 1e-9); + + v = Vector3d(10, 0, 0); + v.rotate(Vector3d(1, 0, 0), M_PI); // no rotation + EXPECT_NEAR(v.x, 10, 1e-9); + EXPECT_NEAR(v.y, 0, 1e-9); + EXPECT_NEAR(v.z, 0, 1e-9); + + v = Vector3d(5, 2, 7); + v.rotate(Vector3d(1, 8, -4), 2 * M_PI); // full rotation + EXPECT_NEAR(v.x, 5, 1e-9); + EXPECT_NEAR(v.y, 2, 1e-9); + EXPECT_NEAR(v.z, 7, 1e-9); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + +} // namespace mpc From 2d6783b59afc0bba3a9e8fcd9213fefe5a83dd5b Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 13 Aug 2012 13:59:22 +0200 Subject: [PATCH 0173/1298] generalized reflective boundaries implemented "reflective" option for periodic grids --- include/mpc/PeriodicGrid.h | 45 ++++++++++++++++++++----- include/mpc/module/BreakCondition.h | 1 - src/magneticField/MagneticFieldGrid.cpp | 2 ++ src/module/BreakCondition.cpp | 29 ++++++++++------ src/module/Output.cpp | 4 +-- test/python/testBoundaries.py | 4 +-- 6 files changed, 60 insertions(+), 25 deletions(-) diff --git a/include/mpc/PeriodicGrid.h b/include/mpc/PeriodicGrid.h index f4fe522ee..7a0b44eac 100644 --- a/include/mpc/PeriodicGrid.h +++ b/include/mpc/PeriodicGrid.h @@ -13,6 +13,14 @@ inline void periodicClamp(double x, int n, int &lo, int &hi) { hi = (lo + 1) % n; } +// Lower and upper neighbor in a reflectively repeated unit grid +inline void reflectiveClamp(double x, int n, int &lo, int &hi) { + while ((x < 0) or (x > n)) + x = 2 * n * (x > n) - x; + lo = floor(x); + hi = lo + (lo < n-1); +} + /** @class PeriodicGrid @brief Template class for fields on a periodic grid with trilinear interpolation @@ -23,17 +31,19 @@ inline void periodicClamp(double x, int n, int &lo, int &hi) { The grid sample positions are at 0, size/N, ... (N-1) * size/N. */ template -class PeriodicGrid : public Referenced { +class PeriodicGrid: public Referenced { std::vector grid; - Vector3d origin; - size_t Nx, Ny, Nz; - double spacing; + size_t Nx, Ny, Nz; /**< Number of grid points */ + Vector3d origin; /**< Grid origin */ + double spacing; /**< Distance between grid points, determines the extension of the grid */ + bool reflective; /**< If set to true, the grid is repeated reflectively instead of periodically */ public: PeriodicGrid(Vector3d origin, size_t N, double spacing) { setOrigin(origin); setGridSize(N, N, N); setSpacing(spacing); + setReflective(false); } PeriodicGrid(Vector3d origin, size_t Nx, size_t Ny, size_t Nz, @@ -41,6 +51,7 @@ class PeriodicGrid : public Referenced { setOrigin(origin); setGridSize(Nx, Ny, Nz); setSpacing(spacing); + setReflective(false); } void setOrigin(Vector3d origin) { @@ -58,6 +69,10 @@ class PeriodicGrid : public Referenced { this->spacing = spacing; } + void setReflective(bool b) { + reflective = b; + } + Vector3d getOrigin() const { return origin; } @@ -77,23 +92,36 @@ class PeriodicGrid : public Referenced { return spacing; } + bool isReflective() const { + return reflective; + } + + /** Accessor / Mutator */ T &get(size_t ix, size_t iy, size_t iz) { return grid[ix * Ny * Nz + iy * Ny + iz]; } + /** Accessor */ const T &get(size_t ix, size_t iy, size_t iz) const { return grid[ix * Ny * Nz + iy * Ny + iz]; } + /** Interpolate the grid at a given position */ T interpolate(const Vector3d &position) const { // position on a unit grid Vector3d r = (position - origin) / spacing; // indices of lower and upper neighbors int ix, iX, iy, iY, iz, iZ; - periodicClamp(r.x, Nx, ix, iX); - periodicClamp(r.y, Ny, iy, iY); - periodicClamp(r.z, Nz, iz, iZ); + if (reflective) { + reflectiveClamp(r.x, Nx, ix, iX); + reflectiveClamp(r.y, Ny, iy, iY); + reflectiveClamp(r.z, Nz, iz, iZ); + } else { + periodicClamp(r.x, Nx, ix, iX); + periodicClamp(r.y, Ny, iy, iY); + periodicClamp(r.z, Nz, iz, iZ); + } // linear fraction to lower and upper neighbors double fx = r.x - floor(r.x); @@ -103,8 +131,7 @@ class PeriodicGrid : public Referenced { double fz = r.z - floor(r.z); double fZ = 1 - fz; - // trilinear interpolation - // check: http://paulbourke.net/miscellaneous/interpolation/ + // trilinear interpolation (see http://paulbourke.net/miscellaneous/interpolation) T b(0.); //V000 (1 - x) (1 - y) (1 - z) + b += get(ix, iy, iz) * fX * fY * fZ; diff --git a/include/mpc/module/BreakCondition.h b/include/mpc/module/BreakCondition.h index e7ab438cf..db8b0cb8c 100644 --- a/include/mpc/module/BreakCondition.h +++ b/include/mpc/module/BreakCondition.h @@ -95,7 +95,6 @@ class PeriodicBox: public Module { If a particle passes on of the sides it is reflected back inside (position and velocity) and its initial position changed as if the particle had come from that side. This realizes reflective boundaries, where the particle is kept inside the box and the source is moved away from the box. - The translation currently does not work correctly if the particle's distance to the box is larger than one box size. Particles can overshoot (be outside of the box during the step) since the step size is not limited by this module. */ class ReflectiveBox: public Module { diff --git a/src/magneticField/MagneticFieldGrid.cpp b/src/magneticField/MagneticFieldGrid.cpp index f1d618a49..31683333b 100644 --- a/src/magneticField/MagneticFieldGrid.cpp +++ b/src/magneticField/MagneticFieldGrid.cpp @@ -20,6 +20,8 @@ Vector3d MagneticFieldGrid::getField(const Vector3d &pos) const { ModulatedMagneticFieldGrid::ModulatedMagneticFieldGrid(ref_ptr grid, ref_ptr modGrid) { + grid->setReflective(true); + modGrid->setReflective(true); setGrid(grid); setModulationGrid(modGrid); } diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp index 594fe0446..100e66fc3 100644 --- a/src/module/BreakCondition.cpp +++ b/src/module/BreakCondition.cpp @@ -124,8 +124,8 @@ ReflectiveBox::ReflectiveBox(Vector3d origin, Vector3d size) { } void ReflectiveBox::process(Candidate *c) const { - Vector3d pos = c->current.getPosition(); - Vector3d n = ((pos - origin) / size).floor(); + Vector3d a = (c->current.getPosition() - origin) / size; // current position in unit cells + Vector3d n = a.floor(); if ((n.x == 0) and (n.y == 0) and (n.z == 0)) return; // do nothing if candidate is inside the box @@ -135,17 +135,24 @@ void ReflectiveBox::process(Candidate *c) const { c->current.setDirection(c->current.getDirection() * nReflect); c->initial.setDirection(c->initial.getDirection() * nReflect); - Vector3d isOutside(n.x != 0, n.y != 0, n.z != 0); - Vector3d isHigh(n.x > 0, n.y > 0, n.z > 0); + Vector3d b = (c->initial.getPosition() - origin) / size; // initial position in unit cells - // translate current position - Vector3d dist = (origin + isHigh * size - pos); // distance to boundary - c->current.setPosition(pos + isOutside * dist * 2 ); + // repeatedly translate until the current position is inside the cell + while ((a.x < 0) or (a.x > 1)) { + b.x = 2 * (a.x > 1) - b.x; + a.x = 2 * (a.x > 1) - a.x; + } + while ((a.y < 0) or (a.y > 1)) { + b.y = 2 * (a.y > 1) - b.y; + a.y = 2 * (a.y > 1) - a.y; + } + while ((a.z < 0) or (a.z > 1)) { + b.z = 2 * (a.z > 1) - b.z; + a.z = 2 * (a.z > 1) - a.z; + } - // translate initial position - Vector3d ipos = c->initial.getPosition(); - Vector3d idist = (origin + isHigh * size - ipos); // distance to boundary - c->initial.setPosition(ipos + isOutside * idist * 2 ); + c->current.setPosition(a * size + origin); + c->initial.setPosition(b * size + origin); } void ReflectiveBox::updateDescription() { diff --git a/src/module/Output.cpp b/src/module/Output.cpp index c6ba7b535..2446d014d 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -65,14 +65,14 @@ void ConditionalOutput::process(Candidate *c) const { const Vector3d &pos = c->current.getPosition() / Mpc; p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", pos.x, pos.y, pos.z); const Vector3d &dir = c->current.getDirection(); - p += sprintf(buffer + p, "%6.4f\t%7.4f\t", dir.getPhi(), dir.getTheta()); + p += sprintf(buffer + p, "%7.4f\t%7.4f\t", dir.getPhi(), dir.getTheta()); p += sprintf(buffer + p, "%9.4f\t", c->getTrajectoryLength() / Mpc); p += sprintf(buffer + p, "%10i\t", c->initial.getId()); p += sprintf(buffer + p, "%8.4f\t", c->initial.getEnergy() / EeV); const Vector3d &ipos = c->initial.getPosition() / Mpc; p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", ipos.x, ipos.y, ipos.z); const Vector3d &idir = c->initial.getDirection(); - p += sprintf(buffer + p, "%6.4f\t%7.4f\n", idir.getPhi(), idir.getTheta()); + p += sprintf(buffer + p, "%7.4f\t%7.4f\n", idir.getPhi(), idir.getTheta()); #pragma omp critical { diff --git a/test/python/testBoundaries.py b/test/python/testBoundaries.py index 0ffc0dd34..b534c79ba 100644 --- a/test/python/testBoundaries.py +++ b/test/python/testBoundaries.py @@ -13,7 +13,7 @@ # simulate periodic boundaries m1 = ModuleList() -m1.add(SimplePropagation(10, 0, 1)) +m1.add(SimplePropagation(0, 1)) m1.add(PeriodicBox(Vector3d(-10), Vector3d(20))) c = Candidate(p) @@ -37,7 +37,7 @@ # simulate reflective boundaries m2 = ModuleList() -m2.add(SimplePropagation(10, 0, 1)) +m2.add(SimplePropagation(0, 1)) m2.add(ReflectiveBox(Vector3d(-10), Vector3d(20))) c = Candidate(p) From cefc54889108e7b1b3b7b351a08ed68c33ab466a Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 14 Aug 2012 16:26:58 +0200 Subject: [PATCH 0174/1298] put sophia call inside critical region. Closes #1090 --- src/module/Output.cpp | 9 ++++++--- src/module/PhotoPionProduction.cpp | 7 +++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 2446d014d..6c85d6af1 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -65,14 +65,17 @@ void ConditionalOutput::process(Candidate *c) const { const Vector3d &pos = c->current.getPosition() / Mpc; p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", pos.x, pos.y, pos.z); const Vector3d &dir = c->current.getDirection(); - p += sprintf(buffer + p, "%7.4f\t%7.4f\t", dir.getPhi(), dir.getTheta()); + p += sprintf(buffer + p, "%7.4f\t%7.4f\t", dir.getPhi(), + dir.getTheta()); p += sprintf(buffer + p, "%9.4f\t", c->getTrajectoryLength() / Mpc); p += sprintf(buffer + p, "%10i\t", c->initial.getId()); p += sprintf(buffer + p, "%8.4f\t", c->initial.getEnergy() / EeV); const Vector3d &ipos = c->initial.getPosition() / Mpc; - p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", ipos.x, ipos.y, ipos.z); + p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", ipos.x, ipos.y, + ipos.z); const Vector3d &idir = c->initial.getDirection(); - p += sprintf(buffer + p, "%7.4f\t%7.4f\n", idir.getPhi(), idir.getTheta()); + p += sprintf(buffer + p, "%7.4f\t%7.4f\n", idir.getPhi(), + idir.getTheta()); #pragma omp critical { diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 3cfbb425b..a382dc77a 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -170,8 +170,11 @@ void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { int dummy1; double dummy2[2]; - sophiaevent_(nature, Ein, momentaList, particleList, nParticles, redshift, - background, maxRedshift, dummy1, dummy2, dummy2); +#pragma omp critical + { + sophiaevent_(nature, Ein, momentaList, particleList, nParticles, + redshift, background, maxRedshift, dummy1, dummy2, dummy2); + } for (int i = 0; i < nParticles; i++) { // loop over out-going particles double Eout = momentaList[3][i] * GeV; // only the energy is used; could be changed for more detail From 38d7e6ac31a568150e58f3fcee831f61c2795ca9 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 17 Aug 2012 14:18:15 +0200 Subject: [PATCH 0175/1298] fixed Vector3 bug added previous particle state to candidate moved observers and boundaries to seperate files improved SmallObserverSphere implemented LargeObserverSphere --- CMakeLists.txt | 2 + include/mpc/Candidate.h | 8 +- include/mpc/Units.h | 2 + include/mpc/Vector3.h | 2 +- include/mpc/module/Boundary.h | 125 +++++++++++++++ include/mpc/module/BreakCondition.h | 153 +----------------- include/mpc/module/Observer.h | 56 +++++++ python/mpc.i | 4 + src/Candidate.cpp | 4 +- src/XmlExecute.cpp | 8 +- src/module/Boundary.cpp | 164 +++++++++++++++++++ src/module/BreakCondition.cpp | 240 +--------------------------- src/module/DeflectionCK.cpp | 3 + src/module/Observer.cpp | 61 +++++++ src/module/SimplePropagation.cpp | 4 + test/testBreakCondition.cpp | 199 +++++++++++------------ 16 files changed, 535 insertions(+), 500 deletions(-) create mode 100644 include/mpc/module/Boundary.h create mode 100644 include/mpc/module/Observer.h create mode 100644 src/module/Boundary.cpp create mode 100644 src/module/Observer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 470f6130b..c62dabe63 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,6 +89,8 @@ add_library(mpc SHARED src/PeriodicGridTools.cpp src/XmlExecute.cpp src/module/BreakCondition.cpp + src/module/Boundary.cpp + src/module/Observer.cpp src/module/SimplePropagation.cpp src/module/DeflectionCK.cpp src/module/ElectronPairProduction.cpp diff --git a/include/mpc/Candidate.h b/include/mpc/Candidate.h index 95eaa72fe..81f62c511 100644 --- a/include/mpc/Candidate.h +++ b/include/mpc/Candidate.h @@ -34,9 +34,11 @@ struct InteractionState { */ class Candidate: public Referenced { public: - ParticleState current; - ParticleState initial; - std::vector > secondaries; + ParticleState initial; /**< Particle state at the beginning of propagation */ + ParticleState current; /**< Current particle state */ + ParticleState previous; /**< Particle state at the end of the previous step */ + + std::vector > secondaries; /**< Secondary particles created in interactions */ typedef Loki::AssocVector PropertyMap; typedef Loki::AssocVector InteractionStatesMap; diff --git a/include/mpc/Units.h b/include/mpc/Units.h index 66a0d57c7..d8b82b4fc 100644 --- a/include/mpc/Units.h +++ b/include/mpc/Units.h @@ -58,8 +58,10 @@ static const double EeV = exaelectronvolt; static const double parsec = 3.0856775807e+16 * meter; static const double kiloparsec = 1e3 * parsec; static const double megaparsec = 1e6 * parsec; +static const double gigaparsec = 1e9 * parsec; static const double kpc = kiloparsec; static const double Mpc = megaparsec; +static const double Gpc = gigaparsec; } // namespace mpc diff --git a/include/mpc/Vector3.h b/include/mpc/Vector3.h index f37e67d93..03d4886c8 100644 --- a/include/mpc/Vector3.h +++ b/include/mpc/Vector3.h @@ -229,7 +229,7 @@ class Vector3 { } Vector3 operator /(const Vector3 &v) const { - return Vector3(x / v.x, y / v.x, z / v.z); + return Vector3(x / v.x, y / v.y, z / v.z); } Vector3 operator /(const T &f) const { diff --git a/include/mpc/module/Boundary.h b/include/mpc/module/Boundary.h new file mode 100644 index 000000000..fdb12fc72 --- /dev/null +++ b/include/mpc/module/Boundary.h @@ -0,0 +1,125 @@ +#ifndef MPC_BOUNDARY_H_ +#define MPC_BOUNDARY_H_ + +#include "mpc/Module.h" + +namespace mpc { + +/** + @class PeriodicBox + @brief Rectangular box with periodic boundaries. + + If a particle passes on of the sides it is placed at the opposite side and its initial (source) position changed accordingly. + This realizes periodic boundaries, where the particle is kept inside the box and the source is moved away from the box. + Particles can overshoot (be outside of the box during the step) since the step size is not limited by this module. + */ +class PeriodicBox: public Module { +private: + Vector3d origin; + Vector3d size; + void updateDescription(); + +public: + PeriodicBox(Vector3d origin, Vector3d size); + void process(Candidate *candidate) const; +}; + +/** + @class ReflectiveBox + @brief Rectangular box with reflective boundaries. + + If a particle passes on of the sides it is reflected back inside (position and velocity) and its initial position changed as if the particle had come from that side. + This realizes reflective boundaries, where the particle is kept inside the box and the source is moved away from the box. + Particles can overshoot (be outside of the box during the step) since the step size is not limited by this module. + */ +class ReflectiveBox: public Module { +private: + Vector3d origin; + Vector3d size; + void updateDescription(); + +public: + ReflectiveBox(Vector3d origin, Vector3d size); + void process(Candidate *candidate) const; +}; + +/** + @class CubicBoundary + @brief Flags a particle when exiting the cube. + + This module flags particles when outside of the cube, defined by a lower corner and edge length. + The particle is made inactive and by default is flagged "OutOfBounds". + Optionally the module can ensure the candidate does not overshoot the boundary by more than a set margin. + */ +class CubicBoundary: public Module { +private: + Vector3d origin; + double size; + double margin; + std::string flag; + std::string flagValue; + bool limitStep; + void updateDescription(); + +public: + CubicBoundary(Vector3d origin, double size, + std::string flag = "OutOfBounds", std::string flagValue = ""); + void setLimitStep(bool limitStep, double margin); + void process(Candidate *candidate) const; +}; + +/** + @class SphericalBoundary + @brief Flag a particle when leaving the sphere. + + This module flags particles when outside of the sphere, defined by a center and radius. + The particle is made inactive and by default is flagged "OutOfBounds". + Optionally the module can ensure the candidate does not overshoot the boundary by more than a set margin. + */ +class SphericalBoundary: public Module { +private: + Vector3d center; + double radius; + double margin; + std::string flag; + std::string flagValue; + bool limitStep; + void updateDescription(); + +public: + SphericalBoundary(Vector3d center, double radius, std::string flag = + "OutOfBounds", std::string flagValue = ""); + void setLimitStep(bool limitStep, double margin); + void process(Candidate *candidate) const; +}; + +/** + @class EllipsoidalBoundary + @brief Flags a particle when leaving the ellipsoid. + + This module flags particles when outside of the ellipsoid, defined by two focal points and a major axis (length). + The particle is made inactive and by default is flagged "OutOfBounds". + Optionally the module can ensure the candidate does not overshoot the boundary by more than a set margin. + */ +class EllipsoidalBoundary: public Module { +private: + Vector3d focalPoint1; + Vector3d focalPoint2; + double majorAxis; + double margin; + std::string flag; + std::string flagValue; + bool limitStep; + void updateDescription(); + +public: + EllipsoidalBoundary(Vector3d focalPoint1, Vector3d focalPoint2, + double majorAxis, std::string flag = "OutOfBounds", + std::string flagValue = ""); + void setLimitStep(bool limitStep, double margin); + void process(Candidate *candidate) const; +}; + +} // namespace mpc + +#endif /* MPC_BOUNDARY_H_ */ diff --git a/include/mpc/module/BreakCondition.h b/include/mpc/module/BreakCondition.h index db8b0cb8c..8e75ca18c 100644 --- a/include/mpc/module/BreakCondition.h +++ b/include/mpc/module/BreakCondition.h @@ -1,9 +1,7 @@ -#ifndef BREAKCONDITION_H_ -#define BREAKCONDITION_H_ +#ifndef MPC_BREAKCONDITION_H_ +#define MPC_BREAKCONDITION_H_ #include "mpc/Module.h" -#include "mpc/Vector3.h" -#include namespace mpc { @@ -46,151 +44,6 @@ class MinimumEnergy: public Module { void process(Candidate *candidate) const; }; -/** - @class SmallObserverSphere - @brief Detects particles when entering the sphere. - - This module flags the candidate upon entering a sphere. - In this case the candidate is by default flagged "Detected" made inactive. - This module limits the next step size to prevent candidates from overshooting. - */ -class SmallObserverSphere: public Module { -private: - double radius; - Vector3d center; - std::string flag; - std::string flagValue; - bool makeInactive; - void updateDescription(); - -public: - SmallObserverSphere(Vector3d center, double radius, std::string flag = - "Detected", std::string flagValue = ""); - void setMakeInactive(bool makeInactive); - void process(Candidate *candidate) const; -}; - -/** - @class PeriodicBox - @brief Rectangular box with periodic boundaries. - - If a particle passes on of the sides it is placed at the opposite side and its initial (source) position changed accordingly. - This realizes periodic boundaries, where the particle is kept inside the box and the source is moved away from the box. - Particles can overshoot (be outside of the box during the step) since the step size is not limited by this module. - */ -class PeriodicBox: public Module { -private: - Vector3d origin; - Vector3d size; - void updateDescription(); - -public: - PeriodicBox(Vector3d origin, Vector3d size); - void process(Candidate *candidate) const; -}; - -/** - @class ReflectiveBox - @brief Rectangular box with reflective boundaries. - - If a particle passes on of the sides it is reflected back inside (position and velocity) and its initial position changed as if the particle had come from that side. - This realizes reflective boundaries, where the particle is kept inside the box and the source is moved away from the box. - Particles can overshoot (be outside of the box during the step) since the step size is not limited by this module. - */ -class ReflectiveBox: public Module { -private: - Vector3d origin; - Vector3d size; - void updateDescription(); - -public: - ReflectiveBox(Vector3d origin, Vector3d size); - void process(Candidate *candidate) const; -}; - -/** - @class CubicBoundary - @brief Flags a particle when exiting the cube. - - This module flags the candidate when outside of a cube, which is defined by the cube's lower corner and edge length. - By default the candidate is flagged "OutOfBounds" and made inactive. - Optionally the module can ensure the candidate does not overshoot the boundary by more than a set margin. - */ -class CubicBoundary: public Module { -private: - Vector3d origin; - double size; - double margin; - std::string flag; - std::string flagValue; - bool makeInactive; - bool limitStep; - void updateDescription(); - -public: - CubicBoundary(Vector3d origin, double size, - std::string flag = "OutOfBounds", std::string flagValue = ""); - void setMakeInactive(bool makeInactive); - void setLimitStep(bool limitStep, double margin); - void process(Candidate *candidate) const; -}; - -/** - @class SphericalBoundary - @brief Flag a particle when leaving the sphere. - - This module flags the candidate when outside of a sphere, which is defined by the sphere's center and radius. - By default the candidate is flagged "OutOfBounds" and made inactive. - Optionally the module can ensure the candidate does not overshoot the boundary by more than a set margin. - */ -class SphericalBoundary: public Module { -private: - Vector3d center; - double radius; - double margin; - std::string flag; - std::string flagValue; - bool makeInactive; - bool limitStep; - void updateDescription(); - -public: - SphericalBoundary(Vector3d center, double radius, std::string flag = - "OutOfBounds", std::string flagValue = ""); - void setMakeInactive(bool makeInactive); - void setLimitStep(bool limitStep, double margin); - void process(Candidate *candidate) const; -}; - -/** - @class EllipsoidalBoundary - @brief Flags a particle when leaving the ellipsoid. - - This module flags the candidate when outside of an ellipsoid, which is defined by the ellipsoids two focal points and major axis length. - By default the candidate is flagged "OutOfBounds" and made inactive. - Optionally the module can ensure the candidate does not overshoot the boundary by more than a set margin. - */ -class EllipsoidalBoundary: public Module { -private: - Vector3d focalPoint1; - Vector3d focalPoint2; - double majorAxis; - double margin; - std::string flag; - std::string flagValue; - bool makeInactive; - bool limitStep; - void updateDescription(); - -public: - EllipsoidalBoundary(Vector3d focalPoint1, Vector3d focalPoint2, - double majorAxis, std::string flag = "OutOfBounds", - std::string flagValue = ""); - void setMakeInactive(bool makeInactive); - void setLimitStep(bool limitStep, double margin); - void process(Candidate *candidate) const; -}; - } // namespace mpc -#endif /* BREAKCONDITION_H_ */ +#endif /* MPC_BREAKCONDITION_H_ */ diff --git a/include/mpc/module/Observer.h b/include/mpc/module/Observer.h new file mode 100644 index 000000000..be4765a78 --- /dev/null +++ b/include/mpc/module/Observer.h @@ -0,0 +1,56 @@ +#ifndef MPC_OBSERVER_H_ +#define MPC_OBSERVER_H_ + +#include "mpc/Module.h" + +namespace mpc { + +/** + @class SmallObserverSphere + @brief Flags particles when entering the sphere. + + Particles are detected when the current position is inside and the previous position outside the sphere. + In this case the candidate is by default flagged "Detected" made inactive. + This module limits the next step size to prevent candidates from overshooting. + */ +class SmallObserverSphere: public Module { +private: + Vector3d center; + double radius; + std::string flag; + std::string flagValue; + bool makeInactive; + void updateDescription(); + +public: + SmallObserverSphere(Vector3d center, double radius, std::string flag = + "Detected", std::string flagValue = "", bool makeInactive = true); + void process(Candidate *candidate) const; +}; + +/** + @class LargeObserverSphere + @brief Flags particles when leaving the sphere. + + Particles are detected when the current position is outside and the previous position inside the sphere. + In this case the candidate is by default flagged "Detected" made inactive. + This module limits the next step size to prevent candidates from overshooting. + */ +class LargeObserverSphere: public Module { +private: + Vector3d center; + double radius; + std::string flag; + std::string flagValue; + bool makeInactive; + void updateDescription(); + +public: + LargeObserverSphere(Vector3d center, double radius, std::string flag = + "Detected", std::string flagValue = "", bool makeInactive = true); + void process(Candidate *candidate) const; +}; + +} // namespace mpc + +#endif /* MPC_OBSERVER_H_ */ diff --git a/python/mpc.i b/python/mpc.i index 7016a55a2..f5165dcbd 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -21,6 +21,8 @@ #include "mpc/module/PhotoPionProduction.h" #include "mpc/module/Redshift.h" #include "mpc/module/BreakCondition.h" +#include "mpc/module/Boundary.h" +#include "mpc/module/Observer.h" #include "mpc/module/Output.h" #include "mpc/module/SimplePropagation.h" #include "mpc/module/DeflectionCK.h" @@ -125,6 +127,8 @@ %include "mpc/module/BreakCondition.h" +%include "mpc/module/Boundary.h" +%include "mpc/module/Observer.h" %include "mpc/module/SimplePropagation.h" %include "mpc/module/DeflectionCK.h" %include "mpc/module/Output.h" diff --git a/src/Candidate.cpp b/src/Candidate.cpp index 3299d002d..358ab3717 100644 --- a/src/Candidate.cpp +++ b/src/Candidate.cpp @@ -8,8 +8,8 @@ Candidate::Candidate() : } Candidate::Candidate(const ParticleState &state) : - current(state), initial(state), redshift(0), trajectoryLength(0), currentStep( - 0), nextStep(0), active(true) { + current(state), initial(state), previous(state), redshift(0), trajectoryLength( + 0), currentStep(0), nextStep(0), active(true) { } bool Candidate::isActive() const { diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 0bb902d8d..6dab0901c 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -2,14 +2,16 @@ #include "mpc/magneticField/UniformMagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" #include "mpc/PeriodicGridTools.h" -#include "mpc/module/DeflectionCK.h" #include "mpc/module/SimplePropagation.h" -#include "mpc/module/Output.h" -#include "mpc/module/BreakCondition.h" +#include "mpc/module/DeflectionCK.h" #include "mpc/module/ElectronPairProduction.h" #include "mpc/module/PhotoPionProduction.h" #include "mpc/module/PhotoDisintegration.h" #include "mpc/module/NuclearDecay.h" +#include "mpc/module/BreakCondition.h" +#include "mpc/module/Boundary.h" +#include "mpc/module/Observer.h" +#include "mpc/module/Output.h" #include "mpc/ModuleList.h" #include "pugixml.hpp" diff --git a/src/module/Boundary.cpp b/src/module/Boundary.cpp new file mode 100644 index 000000000..de053771c --- /dev/null +++ b/src/module/Boundary.cpp @@ -0,0 +1,164 @@ +#include "mpc/module/Boundary.h" + +#include + +namespace mpc { + +PeriodicBox::PeriodicBox(Vector3d o, Vector3d s) : + origin(o), size(s) { + updateDescription(); +} + +void PeriodicBox::process(Candidate *c) const { + Vector3d pos = c->current.getPosition(); + Vector3d n = ((pos - origin) / size).floor(); + + if ((n.x == 0) and (n.y == 0) and (n.z == 0)) + return; // do nothing if candidate is inside the box + + c->initial.setPosition(c->initial.getPosition() - n * size); + c->current.setPosition(pos - n * size); +} + +void PeriodicBox::updateDescription() { + std::stringstream s; + s << "Periodic box: origin " << origin << ", size " << size; + setDescription(s.str()); +} + +ReflectiveBox::ReflectiveBox(Vector3d o, Vector3d s) : + origin(o), size(s) { + updateDescription(); +} + +void ReflectiveBox::process(Candidate *c) const { + Vector3d cur = (c->current.getPosition() - origin) / size; // current position in unit cells + Vector3d n = cur.floor(); + + if ((n.x == 0) and (n.y == 0) and (n.z == 0)) + return; // do nothing if candidate is inside the box + + // flip direction + Vector3d nReflect(pow(-1, n.x), pow(-1, n.y), pow(-1, n.z)); + c->current.setDirection(c->current.getDirection() * nReflect); + c->initial.setDirection(c->initial.getDirection() * nReflect); + + Vector3d ini = (c->initial.getPosition() - origin) / size; // initial position in unit cells + + // repeatedly translate until the current position is inside the cell + while ((cur.x < 0) or (cur.x > 1)) { + ini.x = 2 * (cur.x > 1) - ini.x; + cur.x = 2 * (cur.x > 1) - cur.x; + } + while ((cur.y < 0) or (cur.y > 1)) { + ini.y = 2 * (cur.y > 1) - ini.y; + cur.y = 2 * (cur.y > 1) - cur.y; + } + while ((cur.z < 0) or (cur.z > 1)) { + ini.z = 2 * (cur.z > 1) - ini.z; + cur.z = 2 * (cur.z > 1) - cur.z; + } + + c->current.setPosition(cur * size + origin); + c->initial.setPosition(ini * size + origin); +} + +void ReflectiveBox::updateDescription() { + std::stringstream s; + s << "Reflective box: origin " << origin << ", size " << size; + setDescription(s.str()); +} + +CubicBoundary::CubicBoundary(Vector3d o, double s, std::string f, std::string v) : + origin(o), size(s), margin(0), flag(f), flagValue(v), limitStep(false) { + updateDescription(); +} + +void CubicBoundary::setLimitStep(bool limitStep, double margin) { + this->limitStep = limitStep; + this->margin = margin; + updateDescription(); +} + +void CubicBoundary::process(Candidate *c) const { + Vector3d r = c->current.getPosition() - origin; + double lo = r.min(); + double hi = r.max(); + if ((lo <= 0) or (hi >= size)) { + c->setActive(false); + c->setProperty(flag, flagValue); + } + if (limitStep) { + c->limitNextStep(lo + margin); + c->limitNextStep(size - hi + margin); + } +} + +void CubicBoundary::updateDescription() { + std::stringstream s; + s << "Cubic Boundary: origin " << origin << ", size " << size; + s << " Flag: " << flag << " -> " << flagValue; + setDescription(s.str()); +} + +SphericalBoundary::SphericalBoundary(Vector3d c, double r, std::string f, + std::string v) : + center(c), radius(r), flag(f), flagValue(v), limitStep(false), margin(0) { + updateDescription(); +} + +void SphericalBoundary::setLimitStep(bool limitStep, double margin) { + this->limitStep = limitStep; + this->margin = margin; + updateDescription(); +} + +void SphericalBoundary::process(Candidate *c) const { + double d = (c->current.getPosition() - center).getMag(); + if (d >= radius) { + c->setActive(false); + c->setProperty(flag, flagValue); + } + if (limitStep) + c->limitNextStep(radius - d + margin); +} + +void SphericalBoundary::updateDescription() { + std::stringstream s; + s << "Spherical Boundary: radius " << radius << " around " << center; + s << " Flag: " << flag << " -> " << flagValue; + setDescription(s.str()); +} + +EllipsoidalBoundary::EllipsoidalBoundary(Vector3d f1, + Vector3d f2, double a, std::string f, + std::string v) : focalPoint1(f1), focalPoint2(f2), majorAxis(a), flag(f), flagValue(v), limitStep(false), margin(0) { + updateDescription(); +} + +void EllipsoidalBoundary::setLimitStep(bool limitStep, double margin) { + this->limitStep = limitStep; + this->margin = margin; + updateDescription(); +} + +void EllipsoidalBoundary::process(Candidate *c) const { + Vector3d pos = c->current.getPosition(); + double d = pos.getDistanceTo(focalPoint1) + pos.getDistanceTo(focalPoint2); + if (d >= majorAxis) { + c->setActive(false); + c->setProperty(flag, flagValue); + } + if (limitStep) + c->limitNextStep(majorAxis - d + margin); +} + +void EllipsoidalBoundary::updateDescription() { + std::stringstream s; + s << "Ellipsoidal Boundary: F1 = " << focalPoint1 / Mpc << ", F2 = " + << focalPoint2 / Mpc << ", major axis = " << majorAxis / Mpc; + s << " Flag: " << flag << " -> " << flagValue; + setDescription(s.str()); +} + +} // namespace mpc diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp index 100e66fc3..ca059d432 100644 --- a/src/module/BreakCondition.cpp +++ b/src/module/BreakCondition.cpp @@ -1,5 +1,7 @@ #include "mpc/module/BreakCondition.h" +#include + namespace mpc { MaximumTrajectoryLength::MaximumTrajectoryLength(double maxLength) { @@ -59,242 +61,4 @@ void MinimumEnergy::updateDescription() { setDescription(s.str()); } -SmallObserverSphere::SmallObserverSphere(Vector3d center, double radius, - std::string flag, std::string flagValue) { - this->center = center; - this->radius = radius; - this->flag = flag; - this->flagValue = flagValue; - this->makeInactive = true; - updateDescription(); -} - -void SmallObserverSphere::setMakeInactive(bool makeInactive) { - this->makeInactive = makeInactive; - updateDescription(); -} - -void SmallObserverSphere::process(Candidate *c) const { - double d = (c->current.getPosition() - center).getMag(); - if (d <= radius * 1.01) { - c->setProperty(flag, flagValue); - if (makeInactive) { - c->setActive(false); - c->setProperty("Deactivated", getDescription()); - } - } - c->limitNextStep((d - radius)); -} - -void SmallObserverSphere::updateDescription() { - std::stringstream s; - s << "Small observer sphere: " << radius / Mpc << " Mpc radius around " - << center / Mpc; - s << " Mpc, Flag: '" << flag << "' -> '" << flagValue << "'"; - setDescription(s.str()); -} - -PeriodicBox::PeriodicBox(Vector3d origin, Vector3d size) { - this->origin = origin; - this->size = size; - updateDescription(); -} - -void PeriodicBox::process(Candidate *c) const { - Vector3d pos = c->current.getPosition(); - Vector3d n = ((pos - origin) / size).floor(); - - if ((n.x == 0) and (n.y == 0) and (n.z == 0)) - return; // do nothing if candidate is inside the box - - c->initial.setPosition(c->initial.getPosition() - n * size); - c->current.setPosition(pos - n * size); -} - -void PeriodicBox::updateDescription() { - std::stringstream s; - s << "Periodic box: origin " << origin << ", size " << size; - setDescription(s.str()); -} - -ReflectiveBox::ReflectiveBox(Vector3d origin, Vector3d size) { - this->origin = origin; - this->size = size; - updateDescription(); -} - -void ReflectiveBox::process(Candidate *c) const { - Vector3d a = (c->current.getPosition() - origin) / size; // current position in unit cells - Vector3d n = a.floor(); - - if ((n.x == 0) and (n.y == 0) and (n.z == 0)) - return; // do nothing if candidate is inside the box - - // flip direction - Vector3d nReflect(pow(-1, n.x), pow(-1, n.y), pow(-1, n.z)); - c->current.setDirection(c->current.getDirection() * nReflect); - c->initial.setDirection(c->initial.getDirection() * nReflect); - - Vector3d b = (c->initial.getPosition() - origin) / size; // initial position in unit cells - - // repeatedly translate until the current position is inside the cell - while ((a.x < 0) or (a.x > 1)) { - b.x = 2 * (a.x > 1) - b.x; - a.x = 2 * (a.x > 1) - a.x; - } - while ((a.y < 0) or (a.y > 1)) { - b.y = 2 * (a.y > 1) - b.y; - a.y = 2 * (a.y > 1) - a.y; - } - while ((a.z < 0) or (a.z > 1)) { - b.z = 2 * (a.z > 1) - b.z; - a.z = 2 * (a.z > 1) - a.z; - } - - c->current.setPosition(a * size + origin); - c->initial.setPosition(b * size + origin); -} - -void ReflectiveBox::updateDescription() { - std::stringstream s; - s << "Reflective box: origin " << origin << ", size " << size; - setDescription(s.str()); -} - -CubicBoundary::CubicBoundary(Vector3d origin, double size, std::string flag, - std::string flagValue) { - this->origin = origin; - this->size = size; - this->flag = flag; - this->flagValue = flagValue; - this->makeInactive = true; - this->limitStep = false; - this->margin = 0; - updateDescription(); -} - -void CubicBoundary::setMakeInactive(bool makeInactive) { - this->makeInactive = makeInactive; - updateDescription(); -} - -void CubicBoundary::setLimitStep(bool limitStep, double margin) { - this->limitStep = limitStep; - this->margin = margin; - updateDescription(); -} - -void CubicBoundary::process(Candidate *c) const { - Vector3d r = c->current.getPosition() - origin; - double lo = r.min(); - double hi = r.max(); - if ((lo <= 0) or (hi >= size)) { - c->setProperty(flag, flagValue); - if (makeInactive) { - c->setActive(false); - c->setProperty("Deactivated", getDescription()); - } - } else if (limitStep) { - c->limitNextStep(lo + margin); - c->limitNextStep(size - hi + margin); - } -} - -void CubicBoundary::updateDescription() { - std::stringstream s; - s << "Cubic Boundary: origin " << origin << ", size " << size; - s << " Flag: " << flag << " -> " << flagValue; - setDescription(s.str()); -} - -SphericalBoundary::SphericalBoundary(Vector3d center, double radius, - std::string flag, std::string flagValue) { - this->center = center; - this->radius = radius; - this->flag = flag; - this->flagValue = flagValue; - this->makeInactive = true; - this->limitStep = false; - this->margin = 0; - updateDescription(); -} - -void SphericalBoundary::setMakeInactive(bool makeInactive) { - this->makeInactive = makeInactive; - updateDescription(); -} - -void SphericalBoundary::setLimitStep(bool limitStep, double margin) { - this->limitStep = limitStep; - this->margin = margin; - updateDescription(); -} - -void SphericalBoundary::process(Candidate *c) const { - double d = (c->current.getPosition() - center).getMag(); - if (d >= radius) { - c->setProperty(flag, flagValue); - if (makeInactive) { - c->setActive(false); - c->setProperty("Deactivated", getDescription()); - } - } - if (limitStep) - c->limitNextStep(radius - d + margin); -} - -void SphericalBoundary::updateDescription() { - std::stringstream s; - s << "Spherical Boundary: radius " << radius << " around " << center; - s << " Flag: " << flag << " -> " << flagValue; - setDescription(s.str()); -} - -EllipsoidalBoundary::EllipsoidalBoundary(Vector3d focalPoint1, - Vector3d focalPoint2, double majorAxis, std::string flag, - std::string flagValue) { - this->focalPoint1 = focalPoint1; - this->focalPoint2 = focalPoint2; - this->majorAxis = majorAxis; - this->flag = flag; - this->flagValue = flagValue; - this->makeInactive = true; - this->limitStep = false; - this->margin = 0; - updateDescription(); -} - -void EllipsoidalBoundary::setMakeInactive(bool makeInactive) { - this->makeInactive = makeInactive; - updateDescription(); -} - -void EllipsoidalBoundary::setLimitStep(bool limitStep, double margin) { - this->limitStep = limitStep; - this->margin = margin; - updateDescription(); -} - -void EllipsoidalBoundary::process(Candidate *c) const { - Vector3d pos = c->current.getPosition(); - double d = pos.getDistanceTo(focalPoint1) + pos.getDistanceTo(focalPoint2); - if (d >= majorAxis) { - c->setProperty(flag, flagValue); - if (makeInactive) { - c->setActive(false); - c->setProperty("Deactivated", getDescription()); - } - } - if (limitStep) - c->limitNextStep(majorAxis - d + margin); -} - -void EllipsoidalBoundary::updateDescription() { - std::stringstream s; - s << "Ellipsoidal Boundary: F1 = " << focalPoint1 / Mpc << ", F2 = " - << focalPoint2 / Mpc << ", major axis = " << majorAxis / Mpc; - s << " Flag: " << flag << " -> " << flagValue; - setDescription(s.str()); -} - } // namespace mpc diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index 0030d716c..b526dbb25 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -54,6 +54,9 @@ std::string DeflectionCK::getDescription() const { } void DeflectionCK::process(Candidate *candidate) const { + // save the new previous particle state + candidate->previous = candidate->current; + double step = candidate->getNextStep(); step = std::max(step, minStep); step = std::min(step, maxStep); diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp new file mode 100644 index 000000000..faef7aa9f --- /dev/null +++ b/src/module/Observer.cpp @@ -0,0 +1,61 @@ +#include "mpc/module/Observer.h" + +#include + +namespace mpc { + +SmallObserverSphere::SmallObserverSphere(Vector3d c, double r, + std::string f, std::string v, bool b) : + center(c), radius(r), flag(f), flagValue(v), makeInactive(b) { + updateDescription(); +} + +void SmallObserverSphere::process(Candidate *c) const { + double d = (c->current.getPosition() - center).getMag(); + if (d <= radius) { + double dprev = (c->previous.getPosition() - center).getMag(); + if (dprev > radius) { + c->setProperty(flag, flagValue); + if (makeInactive) + c->setActive(false); + } + } + c->limitNextStep((d - radius)); +} + +void SmallObserverSphere::updateDescription() { + std::stringstream s; + s << "Small observer sphere: " << radius / Mpc; + s << " Mpc radius around " << center / Mpc; + s << " Mpc, Flag: '" << flag << "' -> '" << flagValue << "'"; + setDescription(s.str()); +} + +LargeObserverSphere::LargeObserverSphere(Vector3d c, double r, + std::string f, std::string v, bool b) : + center(c), radius(r), flag(f), flagValue(v), makeInactive(b) { + updateDescription(); +} + +void LargeObserverSphere::process(Candidate *c) const { + double d = (c->current.getPosition() - center).getMag(); + if (d >= radius) { + double dprev = (c->previous.getPosition() - center).getMag(); + if (dprev < radius) { + c->setProperty(flag, flagValue); + if (makeInactive) + c->setActive(false); + } + } + c->limitNextStep((d - radius)); +} + +void LargeObserverSphere::updateDescription() { + std::stringstream s; + s << "Large observer sphere: " << radius / Mpc; + s << " Mpc radius around " << center / Mpc; + s << " Mpc, Flag: '" << flag << "' -> '" << flagValue << "'"; + setDescription(s.str()); +} + +} // namespace mpc diff --git a/src/module/SimplePropagation.cpp b/src/module/SimplePropagation.cpp index 2a2a31623..cfa02db72 100644 --- a/src/module/SimplePropagation.cpp +++ b/src/module/SimplePropagation.cpp @@ -7,8 +7,12 @@ SimplePropagation::SimplePropagation(double minStep, double maxStep) : } void SimplePropagation::process(Candidate *candidate) const { + // save the new previous particle state + candidate->previous = candidate->current; + double step = candidate->getNextStep(); step = std::max(step, minStep); + Vector3d pos = candidate->current.getPosition(); Vector3d dir = candidate->current.getDirection(); candidate->current.setPosition(pos + dir * step); diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index 5fa0801c3..525155ff0 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -1,66 +1,77 @@ #include "mpc/module/BreakCondition.h" +#include "mpc/module/Boundary.h" +#include "mpc/module/Observer.h" #include "mpc/Candidate.h" #include "gtest/gtest.h" namespace mpc { -TEST(MinimumEnergy, Continue) { +TEST(MinimumEnergy, above) { MinimumEnergy minEnergy(5); - Candidate candidate; - candidate.current.setEnergy(5.1); - minEnergy.process(&candidate); - EXPECT_TRUE(candidate.isActive()); + Candidate c; + c.current.setEnergy(5.1); + minEnergy.process(&c); + EXPECT_TRUE(c.isActive()); } -TEST(MinimumEnergy, Stop) { +TEST(MinimumEnergy, below) { MinimumEnergy minEnergy(5); - Candidate candidate; - candidate.current.setEnergy(4.9); - minEnergy.process(&candidate); - EXPECT_FALSE(candidate.isActive()); + Candidate c; + c.current.setEnergy(4.9); + minEnergy.process(&c); + EXPECT_FALSE(c.isActive()); } -TEST(MaximumTrajectoryLength, Continue) { +TEST(MaximumTrajectoryLength, above) { MaximumTrajectoryLength maxLength(10); - Candidate candidate; - candidate.setTrajectoryLength(9.9); - maxLength.process(&candidate); - EXPECT_TRUE(candidate.isActive()); + Candidate c; + c.setTrajectoryLength(9.9); + maxLength.process(&c); + EXPECT_TRUE(c.isActive()); } -TEST(MaximumTrajectoryLength, stop) { +TEST(MaximumTrajectoryLength, below) { MaximumTrajectoryLength maxLength(10); - Candidate candidate; - candidate.setTrajectoryLength(10.1); - maxLength.process(&candidate); - EXPECT_FALSE(candidate.isActive()); + Candidate c; + c.setTrajectoryLength(10.1); + maxLength.process(&c); + EXPECT_FALSE(c.isActive()); } -TEST(SmallObserverSphere, Continue) { +TEST(SmallObserverSphere, outside) { SmallObserverSphere obs(Vector3d(0, 0, 0), 1); - Candidate candidate; - candidate.current.setPosition(Vector3d(2, 0, 0)); - obs.process(&candidate); - EXPECT_TRUE(candidate.isActive()); + Candidate c; + c.current.setPosition(Vector3d(2, 0, 0)); + obs.process(&c); + EXPECT_TRUE(c.isActive()); } -TEST(SmallObserverSphere, detect) { +TEST(SmallObserverSphere, inside) { + // detect if the current position is inside and the previous outside of the sphere SmallObserverSphere obs(Vector3d(0, 0, 0), 1); - Candidate candidate; - candidate.current.setPosition(Vector3d(0.1, 0.5, -0.1)); - obs.process(&candidate); - EXPECT_FALSE(candidate.isActive()); - EXPECT_TRUE(candidate.hasProperty("Detected")); + Candidate c; + + c.current.setPosition(Vector3d(0.9, 0, 0)); + c.previous.setPosition(Vector3d(0.95, 0, 0)); + obs.process(&c); + EXPECT_TRUE(c.isActive()); + EXPECT_FALSE(c.hasProperty("Detected")); + + c.current.setPosition(Vector3d(0.9, 0, 0)); + c.previous.setPosition(Vector3d(1.1, 0, 0)); + obs.process(&c); + EXPECT_FALSE(c.isActive()); + EXPECT_TRUE(c.hasProperty("Detected")); } TEST(SmallObserverSphere, limitStep) { SmallObserverSphere obs(Vector3d(0, 0, 0), 1); - Candidate candidate; - candidate.setNextStep(10); - candidate.current.setPosition(Vector3d(0, 0, 2)); - obs.process(&candidate); - EXPECT_DOUBLE_EQ(candidate.getNextStep(), 1); + Candidate c; + c.setNextStep(10); + c.current.setPosition(Vector3d(0, 0, 2)); + obs.process(&c); + EXPECT_DOUBLE_EQ(c.getNextStep(), 1); } TEST(PeriodicBox, high) { @@ -137,113 +148,95 @@ TEST(ReflectiveBox, high) { TEST(CubicBoundary, inside) { CubicBoundary cube(Vector3d(0, 0, 0), 10); - Candidate candidate; - candidate.current.setPosition(Vector3d(9, 5, 5)); - cube.process(&candidate); - EXPECT_TRUE(candidate.isActive()); + Candidate c; + c.current.setPosition(Vector3d(9, 5, 5)); + cube.process(&c); + EXPECT_TRUE(c.isActive()); } TEST(CubicBoundary, outside) { CubicBoundary cube(Vector3d(0, 0, 0), 10); - Candidate candidate; - candidate.current.setPosition(Vector3d(10.1, 5, 5)); - - cube.setMakeInactive(false); - cube.process(&candidate); - EXPECT_TRUE(candidate.isActive()); - EXPECT_TRUE(candidate.hasProperty("OutOfBounds")); - - cube.setMakeInactive(true); - cube.process(&candidate); - EXPECT_FALSE(candidate.isActive()); + Candidate c; + c.current.setPosition(Vector3d(10.1, 5, 5)); + cube.process(&c); + EXPECT_FALSE(c.isActive()); + EXPECT_TRUE(c.hasProperty("OutOfBounds")); } TEST(CubicBoundary, limitStepLower) { CubicBoundary cube(Vector3d(10, 10, 10), 10); cube.setLimitStep(true, 1); - Candidate candidate; - candidate.current.setPosition(Vector3d(15, 15, 10.5)); - candidate.setNextStep(100); - cube.process(&candidate); - EXPECT_DOUBLE_EQ(1.5, candidate.getNextStep()); + Candidate c; + c.current.setPosition(Vector3d(15, 15, 10.5)); + c.setNextStep(100); + cube.process(&c); + EXPECT_DOUBLE_EQ(1.5, c.getNextStep()); } TEST(CubicBoundary, limitStepUpper) { CubicBoundary cube(Vector3d(-10, -10, -10), 10); cube.setLimitStep(true, 1); - Candidate candidate; - candidate.current.setPosition(Vector3d(-5, -5, -0.5)); - candidate.setNextStep(100); - cube.process(&candidate); - EXPECT_DOUBLE_EQ(1.5, candidate.getNextStep()); + Candidate c; + c.current.setPosition(Vector3d(-5, -5, -0.5)); + c.setNextStep(100); + cube.process(&c); + EXPECT_DOUBLE_EQ(1.5, c.getNextStep()); } TEST(SphericalBoundary, inside) { SphericalBoundary sphere(Vector3d(0, 0, 0), 10); - Candidate candidate; - candidate.current.setPosition(Vector3d(9, 0, 0)); - sphere.process(&candidate); - EXPECT_TRUE(candidate.isActive()); - EXPECT_FALSE(candidate.hasProperty("OutOfBounds")); + Candidate c; + c.current.setPosition(Vector3d(9, 0, 0)); + sphere.process(&c); + EXPECT_TRUE(c.isActive()); + EXPECT_FALSE(c.hasProperty("OutOfBounds")); } TEST(SphericalBoundary, outside) { SphericalBoundary sphere(Vector3d(0, 0, 0), 10, "PassedGalacticBorder"); - - Candidate candidate; - candidate.current.setPosition(Vector3d(0, -10.1, 0)); - - sphere.setMakeInactive(false); - sphere.process(&candidate); - EXPECT_TRUE(candidate.isActive()); - EXPECT_TRUE(candidate.hasProperty("PassedGalacticBorder")); - - sphere.setMakeInactive(true); - sphere.process(&candidate); - EXPECT_FALSE(candidate.isActive()); + Candidate c; + c.current.setPosition(Vector3d(0, -10.1, 0)); + sphere.process(&c); + EXPECT_FALSE(c.isActive()); + EXPECT_TRUE(c.hasProperty("PassedGalacticBorder")); } TEST(SphericalBoundary, limitStep) { SphericalBoundary sphere(Vector3d(0, 0, 0), 10); sphere.setLimitStep(true, 1); - Candidate candidate; - candidate.setNextStep(100); - candidate.current.setPosition(Vector3d(0, 0, 9.5)); - sphere.process(&candidate); - EXPECT_DOUBLE_EQ(1.5, candidate.getNextStep()); + Candidate c; + c.setNextStep(100); + c.current.setPosition(Vector3d(0, 0, 9.5)); + sphere.process(&c); + EXPECT_DOUBLE_EQ(1.5, c.getNextStep()); } TEST(EllipsoidalBoundary, inside) { EllipsoidalBoundary ellipsoid(Vector3d(-5, 0, 0), Vector3d(5, 0, 0), 15); - Candidate candidate; - candidate.current.setPosition(Vector3d(3, 2, 0)); - ellipsoid.process(&candidate); - EXPECT_FALSE(candidate.hasProperty("OutOfBounds")); + Candidate c; + c.current.setPosition(Vector3d(3, 2, 0)); + ellipsoid.process(&c); + EXPECT_TRUE(c.isActive()); + EXPECT_FALSE(c.hasProperty("OutOfBounds")); } TEST(EllipsoidalBoundary, outside) { EllipsoidalBoundary ellipsoid(Vector3d(-5, 0, 0), Vector3d(5, 0, 0), 15); - Candidate candidate; - candidate.current.setPosition(Vector3d(0, 25, 0)); - - ellipsoid.setMakeInactive(false); - ellipsoid.process(&candidate); - EXPECT_TRUE(candidate.hasProperty("OutOfBounds")); - EXPECT_TRUE(candidate.isActive()); - - ellipsoid.setMakeInactive(true); - ellipsoid.process(&candidate); - EXPECT_FALSE(candidate.isActive()); + Candidate c; + c.current.setPosition(Vector3d(0, 25, 0)); + ellipsoid.process(&c); + EXPECT_FALSE(c.isActive()); + EXPECT_TRUE(c.hasProperty("OutOfBounds")); } TEST(EllipsoidalBoundary, limitStep) { EllipsoidalBoundary ellipsoid(Vector3d(-5, 0, 0), Vector3d(5, 0, 0), 15); ellipsoid.setLimitStep(true, 0.5); - Candidate candidate; - candidate.setNextStep(2); - candidate.current.setPosition(Vector3d(7, 0, 0)); - ellipsoid.process(&candidate); - EXPECT_DOUBLE_EQ(candidate.getNextStep(), 1.5); + Candidate c; + c.setNextStep(2); + c.current.setPosition(Vector3d(7, 0, 0)); + ellipsoid.process(&c); + EXPECT_DOUBLE_EQ(c.getNextStep(), 1.5); } int main(int argc, char **argv) { From 47fe25d83ec7d629d0fdc86b8b8077ada5169830 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 17 Aug 2012 14:35:51 +0200 Subject: [PATCH 0176/1298] extended PeriodicBox and ReflectiveBox for previous particle state --- src/module/Boundary.cpp | 28 +++++++++++++++++++--------- test/testBreakCondition.cpp | 14 ++++++++++++-- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/module/Boundary.cpp b/src/module/Boundary.cpp index de053771c..eb5ed6cfd 100644 --- a/src/module/Boundary.cpp +++ b/src/module/Boundary.cpp @@ -16,8 +16,9 @@ void PeriodicBox::process(Candidate *c) const { if ((n.x == 0) and (n.y == 0) and (n.z == 0)) return; // do nothing if candidate is inside the box - c->initial.setPosition(c->initial.getPosition() - n * size); c->current.setPosition(pos - n * size); + c->previous.setPosition(c->previous.getPosition() - n * size); + c->initial.setPosition(c->initial.getPosition() - n * size); } void PeriodicBox::updateDescription() { @@ -32,7 +33,7 @@ ReflectiveBox::ReflectiveBox(Vector3d o, Vector3d s) : } void ReflectiveBox::process(Candidate *c) const { - Vector3d cur = (c->current.getPosition() - origin) / size; // current position in unit cells + Vector3d cur = (c->current.getPosition() - origin) / size; // current position in cell units Vector3d n = cur.floor(); if ((n.x == 0) and (n.y == 0) and (n.z == 0)) @@ -41,26 +42,35 @@ void ReflectiveBox::process(Candidate *c) const { // flip direction Vector3d nReflect(pow(-1, n.x), pow(-1, n.y), pow(-1, n.z)); c->current.setDirection(c->current.getDirection() * nReflect); + c->previous.setDirection(c->previous.getDirection() * nReflect); c->initial.setDirection(c->initial.getDirection() * nReflect); - Vector3d ini = (c->initial.getPosition() - origin) / size; // initial position in unit cells + Vector3d ini = (c->initial.getPosition() - origin) / size; // initial position in cell units + Vector3d prv = (c->previous.getPosition() - origin) / size; // previous position in cell units // repeatedly translate until the current position is inside the cell while ((cur.x < 0) or (cur.x > 1)) { - ini.x = 2 * (cur.x > 1) - ini.x; - cur.x = 2 * (cur.x > 1) - cur.x; + double t = 2 * (cur.x > 1); + ini.x = t - ini.x; + prv.x = t - prv.x; + cur.x = t - cur.x; } while ((cur.y < 0) or (cur.y > 1)) { - ini.y = 2 * (cur.y > 1) - ini.y; - cur.y = 2 * (cur.y > 1) - cur.y; + double t = 2 * (cur.y > 1); + ini.y = t - ini.y; + prv.y = t - prv.y; + cur.y = t - cur.y; } while ((cur.z < 0) or (cur.z > 1)) { - ini.z = 2 * (cur.z > 1) - ini.z; - cur.z = 2 * (cur.z > 1) - cur.z; + double t = 2 * (cur.z > 1); + ini.z = t - ini.z; + prv.z = t - prv.z; + cur.z = t - cur.z; } c->current.setPosition(cur * size + origin); c->initial.setPosition(ini * size + origin); + c->previous.setPosition(prv * size + origin); } void ReflectiveBox::updateDescription() { diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index 525155ff0..4c64fcaa3 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -124,7 +124,9 @@ TEST(ReflectiveBox, high) { Candidate c; c.initial.setPosition(Vector3d(15, 15, 15)); c.initial.setDirection(Vector3d(0, 0.6, 0.8)); - c.current.setPosition(Vector3d(15, 15, 31)); + c.previous.setPosition(Vector3d(15, 15, 29.5)); + c.previous.setDirection(Vector3d(0, 0.6, 0.8)); + c.current.setPosition(Vector3d(15, 15, 30.5)); c.current.setDirection(Vector3d(0, 0.6, 0.8)); box.process(&c); @@ -133,14 +135,22 @@ TEST(ReflectiveBox, high) { EXPECT_DOUBLE_EQ(15, c.initial.getPosition().y); EXPECT_DOUBLE_EQ(45, c.initial.getPosition().z); + EXPECT_DOUBLE_EQ(15, c.previous.getPosition().x); + EXPECT_DOUBLE_EQ(15, c.previous.getPosition().y); + EXPECT_DOUBLE_EQ(30.5, c.previous.getPosition().z); + EXPECT_DOUBLE_EQ(15, c.current.getPosition().x); EXPECT_DOUBLE_EQ(15, c.current.getPosition().y); - EXPECT_DOUBLE_EQ(29, c.current.getPosition().z); + EXPECT_DOUBLE_EQ(29.5, c.current.getPosition().z); EXPECT_DOUBLE_EQ(0, c.initial.getDirection().x); EXPECT_DOUBLE_EQ(0.6, c.initial.getDirection().y); EXPECT_DOUBLE_EQ(-0.8, c.initial.getDirection().z); + EXPECT_DOUBLE_EQ(0, c.previous.getDirection().x); + EXPECT_DOUBLE_EQ(0.6, c.previous.getDirection().y); + EXPECT_DOUBLE_EQ(-0.8, c.previous.getDirection().z); + EXPECT_DOUBLE_EQ(0, c.current.getDirection().x); EXPECT_DOUBLE_EQ(0.6, c.current.getDirection().y); EXPECT_DOUBLE_EQ(-0.8, c.current.getDirection().z); From fb2a258495b33f695da723696764c4fbd9256a87 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 17 Aug 2012 15:15:17 +0200 Subject: [PATCH 0177/1298] added large observer spheres to xml steering --- src/XmlExecute.cpp | 125 +++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 73 deletions(-) diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 6dab0901c..883aabdb2 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -24,24 +24,24 @@ using namespace std; namespace mpc { -double childValue(xml_node parent, string name, bool throwIfEmpty = true) { - xml_node node = parent.child(name.c_str()); +double childValue(xml_node parent, string childName, bool throwIfEmpty = true) { + xml_node node = parent.child(childName.c_str()); if (!node and throwIfEmpty) { stringstream ss; - ss << "Error reading XML card: " << name << " not found"; + ss << "Error reading XML card: " << childName << " not specified"; throw runtime_error(ss.str()); } return node.attribute("value").as_double(); } -string childType(xml_node parent, string name, bool throwIfEmpty = true) { - xml_node node = parent.child(name.c_str()); +xml_node childNode(xml_node parent, string childName, bool throwIfEmpty = true) { + xml_node node = parent.child(childName.c_str()); if (!node and throwIfEmpty) { stringstream ss; - ss << "Error reading XML card: " << name << " not found"; + ss << "Error reading XML card: " << childName << " not specified"; throw runtime_error(ss.str()); } - return node.attribute("type").as_string(); + return node; } bool XmlExecute::load(const string &filename) { @@ -56,9 +56,10 @@ bool XmlExecute::load(const string &filename) { xml_node root = doc.child("CRPropa"); if (!root) - throw runtime_error("Error reading XML card: Root element not found"); + throw runtime_error("Error reading XML card: Root element CRPropa not found"); - trajectories = (int)childValue(root, "TrajNumber"); + // ----- general settings ----- + trajectories = (int) childValue(root, "TrajNumber"); cout << "Trajectories: " << trajectories << endl; double maxTime = childValue(root, "MaxTime_Mpc") * Mpc; @@ -67,18 +68,15 @@ bool XmlExecute::load(const string &filename) { Emin = childValue(root, "MinEnergy_EeV") * EeV; cout << "Minimum Energy: " << Emin / EeV << " EeV" << endl; - randomSeed = (int)childValue(root, "RandomSeed"); + randomSeed = (int) childValue(root, "RandomSeed"); cout << "RandomSeed: " << randomSeed << endl; + // ----- environment ----- xml_node node; - std::string type; - - // environment - node = root.child("Environment"); - if (!node) - throw runtime_error("Environment not specified"); - type = node.attribute("type").as_string(); + node = childNode(root, "Environment"); + std::string type = node.attribute("type").as_string(); cout << "Environment: " << type << endl; + if (type == "One Dimension") throw runtime_error("One Dimension not supported"); else if (type == "LSS") { @@ -93,10 +91,8 @@ bool XmlExecute::load(const string &filename) { } else throw runtime_error("Unknown environment"); - // magnetic field - node = root.child("MagneticField"); - if (!node) - throw runtime_error("Magnetic field not specified"); + // ----- magnetic field ----- + node = childNode(root, "MagneticField"); type = node.attribute("type").as_string(); cout << "MagenticField: " << type << endl; if (type == "None") @@ -110,27 +106,8 @@ bool XmlExecute::load(const string &filename) { magnetic_field = new UniformMagneticField(Vector3d(0, 0, 0)); } - // interactions - node = root.child("Interactions"); - if (!node) - throw runtime_error("Interactions not specified"); - type = node.attribute("type").as_string(); - cout << "Interactions: " << type << endl; - if (type == "None") - ; - else if (type == "F77-proton") - cout << " -> not supported" << endl; - else if (type == "Sophia") - loadSophia(node); - else if (type == "Photon") - cout << " -> not supported" << endl; - else - cout << " -> unknown" << endl; - - // propagator - node = root.child("Integrator"); - if (!node) - throw runtime_error("Integrator not specified"); + // ----- propagator ----- + node = childNode(root, "Integrator"); type = node.attribute("type").as_string(); cout << "Integrator: " << type << endl; if (type == "Cash-Karp RK") @@ -138,19 +115,17 @@ bool XmlExecute::load(const string &filename) { else throw runtime_error("Unknown integrator"); - // minimum energy + // ----- minimum energy ----- modules.add(new MinimumEnergy(Emin)); - // maximum trajectory length + // ----- maximum trajectory length ----- modules.add(new MaximumTrajectoryLength(maxTime)); - // periodic boundaries + // ----- periodic boundaries ----- loadPeriodicBoundaries(); - // sources - node = root.child("Sources"); - if (!node) - throw runtime_error("Source(s) not specified"); + // ----- sources ----- + node = childNode(root, "Sources"); type = node.attribute("type").as_string(); cout << "Sources: " << type << endl; if (type == "Discrete") @@ -160,7 +135,7 @@ bool XmlExecute::load(const string &filename) { else throw runtime_error("Unknown source"); - // observers + // ----- observers ----- node = root.child("Observers"); if (!node) cout << "Observer(s) not specified" << endl; @@ -175,7 +150,7 @@ bool XmlExecute::load(const string &filename) { cout << " -> unknown observer" << endl; } - // output + // ----- output ----- node = root.child("Output"); if (!node) cout << "No output" << endl; @@ -244,7 +219,8 @@ void XmlExecute::loadGridMagneticField(xml_node &node) { double kMax = childValue(node, "Kmax"); double lMin = spacing / kMax; double lMax = spacing / kMin; - cout << " - Turbulent range: " << lMin / Mpc << " - " << lMax / Mpc << " Mpc" << endl; + cout << " - Turbulent range: " << lMin / Mpc << " - " << lMax / Mpc + << " Mpc" << endl; double alpha = childValue(node, "SpectralIndex"); cout << " - Turbulence spectral index: " << alpha << endl; @@ -308,18 +284,15 @@ void XmlExecute::loadSpheresAroundObserver(xml_node &node) { double r = childValue(node, "Radius_Mpc") * Mpc; cout << " - Radius: " << r / Mpc << " Mpc" << endl; - int nObs = 0; - for (xml_node n = node.child("SphereObserver"); n; n = n.next_sibling("SphereObserver")) { - nObs += 1; + for (xml_node n = node.child("SphereObserver"); n; + n = n.next_sibling("SphereObserver")) { Vector3d pos; pos.x = childValue(n, "CoordX_Mpc") * Mpc; pos.y = childValue(n, "CoordY_Mpc") * Mpc; pos.z = childValue(n, "CoordZ_Mpc") * Mpc; cout << " - Postion: " << pos / Mpc << " Mpc" << endl; - modules.add(new SmallObserverSphere(pos, r)); + modules.add(new SmallObserverSphere(pos, r, "Detected", "", false)); } - if (nObs > 1) - cout << " -> Warning for multiple observers: propagation will stop after first detection." << endl; } void XmlExecute::loadSpheresAroundSource(pugi::xml_node &node) { @@ -333,11 +306,8 @@ void XmlExecute::loadSpheresAroundSource(pugi::xml_node &node) { cout << " - Postion: " << pos / Mpc << " Mpc" << endl; double r = childValue(n, "Radius_Mpc") * Mpc; cout << " - Radius: " << r / Mpc << " Mpc" << endl; - SphericalBoundary *sphere = new SphericalBoundary(pos, r, "Detected"); - modules.add(sphere); + modules.add(new LargeObserverSphere(pos, r, "Detected", "", false)); } - if (nObs > 1) - cout << " -> Warning for multiple observers: propagation will stop after first detection." << endl; } void XmlExecute::loadDiscreteSources(xml_node &node) { @@ -346,7 +316,8 @@ void XmlExecute::loadDiscreteSources(xml_node &node) { // source positions SourceMultiplePositions *positions = new SourceMultiplePositions(); - for (xml_node n = node.child("PointSource"); n; n = n.next_sibling("PointSource")) { + for (xml_node n = node.child("PointSource"); n; + n = n.next_sibling("PointSource")) { Vector3d pos; pos.x = childValue(n, "CoordX_Mpc") * Mpc; pos.y = childValue(n, "CoordY_Mpc") * Mpc; @@ -374,12 +345,14 @@ void XmlExecute::loadDiscreteSources(xml_node &node) { // source composition SourceNuclei *composition = new SourceNuclei; xml_node p = node.child("Particles"); - for (xml_node n = p.child("Species"); n; n = n.next_sibling("Species")) { - int A = (int)childValue(n, "MassNumber"); - int Z = (int)childValue(n, "ChargeNumber"); + for (xml_node n = p.child("Species"); n; + n = n.next_sibling("Species")) { + int A = (int) childValue(n, "MassNumber"); + int Z = (int) childValue(n, "ChargeNumber"); double ab = childValue(n, "Abundance"); composition->add(getNucleusId(A, Z), ab); - cout << " - Species: Z = " << Z << ", A = " << A << ", abundance = " << ab << endl; + cout << " - Species: Z = " << Z << ", A = " << A + << ", abundance = " << ab << endl; } source.addProperty(composition); @@ -394,13 +367,16 @@ void XmlExecute::loadDiscreteSources(xml_node &node) { cout << " - Maximum rigidity: " << Rmax / EeV << " EeV" << endl; // combined source spectrum / composition - SourceComposition *composition = new SourceComposition(Emin, Rmax, alpha); + SourceComposition *composition = new SourceComposition(Emin, Rmax, + alpha); xml_node p = node.child("Particles"); - for (xml_node n = p.child("Species"); n; n = n.next_sibling("Species")) { + for (xml_node n = p.child("Species"); n; + n = n.next_sibling("Species")) { int A = n.attribute("MassNumber").as_int(); int Z = n.attribute("ChargeNumber").as_int(); double ab = n.attribute("Abundance").as_double(); - cout << " - Species: Z = " << Z << ", A = " << A << ", abundance = " << ab << endl; + cout << " - Species: Z = " << Z << ", A = " << A + << ", abundance = " << ab << endl; composition->add(getNucleusId(A, Z), ab); } source.addProperty(composition); @@ -415,17 +391,20 @@ void XmlExecute::loadDiscreteSources(xml_node &node) { // source composition SourceNuclei *composition = new SourceNuclei(); xml_node p = node.child("Particles"); - for (xml_node n = p.child("Species"); n; n = n.next_sibling("Species")) { + for (xml_node n = p.child("Species"); n; + n = n.next_sibling("Species")) { int A = n.attribute("MassNumber").as_int(); int Z = n.attribute("ChargeNumber").as_int(); double ab = n.attribute("Abundance").as_double(); - cout << " - Species: Z = " << Z << ", A = " << A << ", abundance = " << ab << endl; + cout << " - Species: Z = " << Z << ", A = " << A + << ", abundance = " << ab << endl; composition->add(getNucleusId(A, Z), ab); } source.addProperty(composition); } else - throw runtime_error(" --> maximum source energy / rigidity missing"); + throw runtime_error( + " --> maximum source energy / rigidity missing"); } else throw runtime_error(" --> unknown source spectrum"); From afa4f8fdfd8af0295f2101e842642ac934e7f0ce Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 17 Aug 2012 15:15:45 +0200 Subject: [PATCH 0178/1298] add test for LargeObserverSphere and fixed bug --- src/module/Observer.cpp | 2 +- test/testBreakCondition.cpp | 39 +++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp index faef7aa9f..1b09a8e67 100644 --- a/src/module/Observer.cpp +++ b/src/module/Observer.cpp @@ -47,7 +47,7 @@ void LargeObserverSphere::process(Candidate *c) const { c->setActive(false); } } - c->limitNextStep((d - radius)); + c->limitNextStep((radius - d)); } void LargeObserverSphere::updateDescription() { diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index 4c64fcaa3..bb9d1f3d1 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -52,12 +52,14 @@ TEST(SmallObserverSphere, inside) { SmallObserverSphere obs(Vector3d(0, 0, 0), 1); Candidate c; + // no detection: particle was inside already c.current.setPosition(Vector3d(0.9, 0, 0)); c.previous.setPosition(Vector3d(0.95, 0, 0)); obs.process(&c); EXPECT_TRUE(c.isActive()); EXPECT_FALSE(c.hasProperty("Detected")); + // detection: particle just entered c.current.setPosition(Vector3d(0.9, 0, 0)); c.previous.setPosition(Vector3d(1.1, 0, 0)); obs.process(&c); @@ -74,6 +76,43 @@ TEST(SmallObserverSphere, limitStep) { EXPECT_DOUBLE_EQ(c.getNextStep(), 1); } +TEST(LargeObserverSphere, inside) { + LargeObserverSphere obs(Vector3d(0, 0, 0), 10); + Candidate c; + c.current.setPosition(Vector3d(0, 5, 5)); + obs.process(&c); + EXPECT_TRUE(c.isActive()); +} + +TEST(LargeObserverSphere, outside) { + // detect if the current position is outside and the previous inside of the sphere + LargeObserverSphere obs(Vector3d(0, 0, 0), 10); + Candidate c; + + // no detection: particle was outside already + c.current.setPosition(Vector3d(11, 0, 0)); + c.previous.setPosition(Vector3d(10.5, 0, 0)); + obs.process(&c); + EXPECT_TRUE(c.isActive()); + EXPECT_FALSE(c.hasProperty("Detected")); + + // detection: particle just left + c.current.setPosition(Vector3d(11, 0, 0)); + c.previous.setPosition(Vector3d(9.5, 0, 0)); + obs.process(&c); + EXPECT_FALSE(c.isActive()); + EXPECT_TRUE(c.hasProperty("Detected")); +} + +TEST(LargeObserverSphere, limitStep) { + LargeObserverSphere obs(Vector3d(0, 0, 0), 10); + Candidate c; + c.setNextStep(10); + c.current.setPosition(Vector3d(0, 0, 8)); + obs.process(&c); + EXPECT_DOUBLE_EQ(c.getNextStep(), 2); +} + TEST(PeriodicBox, high) { // Tests if the periodical boundaries place the particle back inside the box and translate the initial position accordingly. Vector3d origin(2, 2, 2); From 225a74e9d8da223cbdf997e694337ee545e763fb Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 17 Aug 2012 16:10:09 +0200 Subject: [PATCH 0179/1298] add homogeneous source distribution in box --- include/mpc/Source.h | 18 ++++++++++++++--- src/Source.cpp | 45 ++++++++++++++++++++++++++--------------- src/module/Boundary.cpp | 21 +++++++++++-------- 3 files changed, 57 insertions(+), 27 deletions(-) diff --git a/include/mpc/Source.h b/include/mpc/Source.h index de7209377..e3937ab89 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -135,14 +135,26 @@ class SourceMultiplePositions: public SourceProperty { }; /** - @class SourceSphericalVolume + @class SourceHomogeneousSphere @brief Uniform random source positions inside a sphere */ -class SourceSphericalVolume: public SourceProperty { +class SourceHomogeneousSphere: public SourceProperty { Vector3d center; double radius; public: - SourceSphericalVolume(Vector3d center, double radius); + SourceHomogeneousSphere(Vector3d center, double radius); + void prepare(ParticleState &particle) const; +}; + +/** + @class SourceHomogeneousBox + @brief Uniform random source positions inside a box + */ +class SourceHomogeneousBox: public SourceProperty { + Vector3d origin; + Vector3d size; +public: + SourceHomogeneousBox(Vector3d origin, Vector3d size); void prepare(ParticleState &particle) const; }; diff --git a/src/Source.cpp b/src/Source.cpp index 37bd0b87b..3c6eb374c 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -23,9 +23,10 @@ void SourceList::addSource(Source *source, double lumi) { } void SourceList::prepare(ParticleState &particle) const { + Random &random = Random::instance(); if (sources.size() == 0) throw std::runtime_error("SourceList: no sources set"); - double r = Random().rand() * luminosities.back(); + double r = random.rand() * luminosities.back(); int i = 0; while ((r > luminosities[i]) and (i < luminosities.size())) i++; @@ -54,7 +55,8 @@ SourcePowerLawSpectrum::SourcePowerLawSpectrum(double Emin, double Emax, } void SourcePowerLawSpectrum::prepare(ParticleState &particle) const { - double E = Random().randPowerLaw(index, Emin, Emax); + Random &random = Random::instance(); + double E = random.randPowerLaw(index, Emin, Emax); particle.setEnergy(E); } @@ -68,7 +70,8 @@ void SourceNuclei::add(int id, double a) { void SourceNuclei::prepare(ParticleState &particle) const { if (ids.size() == 0) throw std::runtime_error("SourceNuclei: no nuclei set"); - double r = Random().rand() * abundances.back(); + Random &random = Random::instance(); + double r = random.rand() * abundances.back(); int i = 0; while ((r > abundances[i]) and (i < abundances.size())) i++; @@ -116,14 +119,14 @@ void SourceComposition::normalize() { void SourceComposition::prepare(ParticleState& particle) const { if (isotope.size() == 0) throw std::runtime_error("PowerLawComposition: No source isotope set"); - double r = Random().rand(); + Random &random = Random::instance(); + double r = random.rand(); int i = 0; while ((r > probability[i]) and (i < probability.size())) i++; int id = isotope[i]; - double E = Random().randPowerLaw(index, Emin, HepPID::Z(id) * Rmax); particle.setId(id); - particle.setEnergy(E); + particle.setEnergy(random.randPowerLaw(index, Emin, HepPID::Z(id) * Rmax)); } SourcePosition::SourcePosition(Vector3d position) : @@ -151,19 +154,29 @@ void SourceMultiplePositions::prepare(ParticleState &particle) const { particle.setPosition(positions[i]); } -SourceSphericalVolume::SourceSphericalVolume(Vector3d center, double radius) : - center(center), radius(radius) { +SourceHomogeneousSphere::SourceHomogeneousSphere(Vector3d c, double r) : + center(c), radius(r) { +} + +void SourceHomogeneousSphere::prepare(ParticleState &particle) const { + Random &random = Random::instance(); + double r = pow(random.rand(), 1. / 3.) * radius; + particle.setPosition(random.randUnitVectorOnSphere() * r); +} + +SourceHomogeneousBox::SourceHomogeneousBox(Vector3d o, Vector3d s) : + origin(o), size(s) { } -void SourceSphericalVolume::prepare(ParticleState &particle) const { - double r = pow(Random().rand(), 1. / 3.) * radius; - Vector3d pos = Random().randUnitVectorOnSphere() * r; - particle.setPosition(pos); +void SourceHomogeneousBox::prepare(ParticleState &particle) const { + Random &random = Random::instance(); + Vector3d pos(random.rand(), random.rand(), random.rand()); + particle.setPosition(pos * size + origin); } void SourceIsotropicEmission::prepare(ParticleState &particle) const { - Vector3d dir = Random().randUnitVectorOnSphere(); - particle.setDirection(dir); + Random &random = Random::instance(); + particle.setDirection(random.randUnitVectorOnSphere()); } SourceDirection::SourceDirection(Vector3d direction) : @@ -179,8 +192,8 @@ SourceEmissionCone::SourceEmissionCone(Vector3d direction, double aperture) : } void SourceEmissionCone::prepare(ParticleState &particle) const { - Vector3d dir = Random().randConeVector(direction, aperture); - particle.setDirection(dir); + Random &random = Random::instance(); + particle.setDirection(random.randConeVector(direction, aperture)); } } // namespace mpc diff --git a/src/module/Boundary.cpp b/src/module/Boundary.cpp index eb5ed6cfd..5d1e764ba 100644 --- a/src/module/Boundary.cpp +++ b/src/module/Boundary.cpp @@ -23,7 +23,8 @@ void PeriodicBox::process(Candidate *c) const { void PeriodicBox::updateDescription() { std::stringstream s; - s << "Periodic box: origin " << origin << ", size " << size; + s << "Periodic box: origin " << origin / Mpc << "Mpc, "; + s << "size " << size / Mpc << " Mpc"; setDescription(s.str()); } @@ -75,7 +76,8 @@ void ReflectiveBox::process(Candidate *c) const { void ReflectiveBox::updateDescription() { std::stringstream s; - s << "Reflective box: origin " << origin << ", size " << size; + s << "Reflective box: origin " << origin / Mpc << "Mpc, "; + s << "size " << size / Mpc << " Mpc"; setDescription(s.str()); } @@ -106,8 +108,9 @@ void CubicBoundary::process(Candidate *c) const { void CubicBoundary::updateDescription() { std::stringstream s; - s << "Cubic Boundary: origin " << origin << ", size " << size; - s << " Flag: " << flag << " -> " << flagValue; + s << "Cubic Boundary: origin " << origin / Mpc << " Mpc, "; + s << "size " << size / Mpc << " Mpc; "; + s << "Flag: " << flag << " -> " << flagValue; setDescription(s.str()); } @@ -135,8 +138,9 @@ void SphericalBoundary::process(Candidate *c) const { void SphericalBoundary::updateDescription() { std::stringstream s; - s << "Spherical Boundary: radius " << radius << " around " << center; - s << " Flag: " << flag << " -> " << flagValue; + s << "Spherical Boundary: radius " << radius / Mpc << " Mpc "; + s << "around " << center / Mpc << " Mpc; "; + s << "Flag: " << flag << " -> " << flagValue; setDescription(s.str()); } @@ -165,8 +169,9 @@ void EllipsoidalBoundary::process(Candidate *c) const { void EllipsoidalBoundary::updateDescription() { std::stringstream s; - s << "Ellipsoidal Boundary: F1 = " << focalPoint1 / Mpc << ", F2 = " - << focalPoint2 / Mpc << ", major axis = " << majorAxis / Mpc; + s << "Ellipsoidal Boundary: F1 = " << focalPoint1 / Mpc << " Mpc, "; + s << "F2 = " << focalPoint2 / Mpc << " Mpc, "; + s << "major axis " << majorAxis / Mpc << " Mpc; "; s << " Flag: " << flag << " -> " << flagValue; setDescription(s.str()); } From ba3aa9c4acefea5f332b40ae51c4460d6cefd10d Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 17 Aug 2012 16:10:54 +0200 Subject: [PATCH 0180/1298] improved tests --- src/XmlExecute.cpp | 5 ++--- test/testCore.cpp | 13 +++++++++++++ test/testPropagation.cpp | 8 ++++++-- test/testSource.cpp | 36 +++++++++++++++++++++++++----------- 4 files changed, 46 insertions(+), 16 deletions(-) diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 883aabdb2..6f8733c35 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -420,9 +420,8 @@ void XmlExecute::loadOutput(xml_node &node) { string option = node.child("File").attribute("option").as_string(); if (option != "force") { ifstream ifile(filename.c_str()); - if (ifile) { - throw runtime_error("Outputfile already exists!"); - } + if (ifile) + throw runtime_error("Output file already exists!"); } if (type == "Full Trajectories") diff --git a/test/testCore.cpp b/test/testCore.cpp index 5e7930bd4..4eead50a8 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -1,4 +1,5 @@ #include "mpc/Candidate.h" +#include "mpc/Random.h" #include "gtest/gtest.h" @@ -176,6 +177,18 @@ TEST(NucleusId, crpropaScheme) { EXPECT_EQ(26056, convertToCRPropaId(getNucleusId(56, 26))); } +TEST(Random, speed1) { + for (int i = 0; i < 10000; i++) + double r = Random().rand(); +} + +TEST(Random, speed2) { + for (int i = 0; i < 10000; i++) { + Random &random = Random::instance(); + double r = random.rand(); + } +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/test/testPropagation.cpp b/test/testPropagation.cpp index 2dd6bb988..1227c3d77 100644 --- a/test/testPropagation.cpp +++ b/test/testPropagation.cpp @@ -23,8 +23,12 @@ TEST(testSimplePropagation, step) { EXPECT_EQ(minStep, c.getCurrentStep()); EXPECT_EQ(maxStep, c.getNextStep()); - EXPECT_EQ(Vector3d(0,20,0), c.current.getPosition()); - EXPECT_EQ(Vector3d(0,1,0), c.current.getDirection()); + EXPECT_EQ(Vector3d(0, 0, 0), c.initial.getPosition()); + EXPECT_EQ(Vector3d(0, 1, 0), c.initial.getDirection()); + EXPECT_EQ(Vector3d(0, 0, 0), c.previous.getPosition()); + EXPECT_EQ(Vector3d(0, 1, 0), c.previous.getDirection()); + EXPECT_EQ(Vector3d(0, 20, 0), c.current.getPosition()); + EXPECT_EQ(Vector3d(0, 1, 0), c.current.getDirection()); } TEST(testDeflectionCK, proton) { diff --git a/test/testSource.cpp b/test/testSource.cpp index 8bb1b3b52..aa4e9a5aa 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -1,12 +1,11 @@ #include "mpc/Source.h" #include "gtest/gtest.h" - #include namespace mpc { -TEST(testSourcePosition, simpleTest) { +TEST(SourcePosition, simpleTest) { Vector3d position(1, 2, 3); SourcePosition source(position); ParticleState ps; @@ -14,17 +13,32 @@ TEST(testSourcePosition, simpleTest) { EXPECT_EQ(position, ps.getPosition()); } -TEST(testSourceSphericalVolume, simpleTest) { +TEST(SourceHomogeneousSphere, simpleTest) { Vector3d center(0, 0, 0); double radius = 110; - SourceSphericalVolume source(center, radius); + SourceHomogeneousSphere source(center, radius); ParticleState ps; source.prepare(ps); double distance = ps.getPosition().getDistanceTo(center); EXPECT_GE(radius, distance); } -TEST(testSourcePowerLawSpectrum, simpleTest) { +TEST(SourceHomogeneousBox, simpleTest) { + Vector3d origin(-7, -2, 0); + Vector3d size(13, 55, 192); + SourceHomogeneousBox box(origin, size); + ParticleState p; + box.prepare(p); + Vector3d pos = p.getPosition(); + EXPECT_LE(origin.x, pos.x); + EXPECT_LE(origin.y, pos.y); + EXPECT_LE(origin.z, pos.z); + EXPECT_GE(size.x, pos.x); + EXPECT_GE(size.y, pos.y); + EXPECT_GE(size.z, pos.z); +} + +TEST(SourcePowerLawSpectrum, simpleTest) { double Emin = 4 * EeV; double Emax = 200 * EeV; double index = -2.7; @@ -35,7 +49,7 @@ TEST(testSourcePowerLawSpectrum, simpleTest) { EXPECT_GE(Emax, ps.getEnergy()); } -TEST(testSourceComposition, simpleTest) { +TEST(SourceComposition, simpleTest) { Vector3d position(1, 2, 3); double Emin = 10; double Emax = 100; @@ -50,13 +64,13 @@ TEST(testSourceComposition, simpleTest) { EXPECT_GE(Emax, ps.getEnergy()); } -TEST(testSourceComposition, throwNoIsotope) { +TEST(SourceComposition, throwNoIsotope) { SourceComposition source(1, 10, -1); ParticleState ps; EXPECT_THROW(source.prepare(ps), std::runtime_error); } -TEST(testSource, allPropertiesUsed) { +TEST(Source, allPropertiesUsed) { Source source; source.addProperty(new SourcePosition(Vector3d(10, 0, 0) * Mpc)); source.addProperty(new SourceIsotropicEmission()); @@ -71,7 +85,7 @@ TEST(testSource, allPropertiesUsed) { EXPECT_EQ(Vector3d(10, 0, 0) * Mpc, ps.getPosition()); } -TEST(testSourceList, simpleTest) { +TEST(SourceList, simpleTest) { // test if source list works with one source SourceList sourceList; ref_ptr source = new Source; @@ -82,14 +96,14 @@ TEST(testSourceList, simpleTest) { EXPECT_EQ(Vector3d(10, 0, 0), p.getPosition()); } -TEST(testSourceList, noSource) { +TEST(SourceList, noSource) { // test if an error is thrown when source list empty SourceList sourceList; ParticleState p; EXPECT_THROW(sourceList.prepare(p), std::runtime_error); } -TEST(testSourceList, luminosity) { +TEST(SourceList, luminosity) { // test if the sources are dialed according to their luminosities SourceList sourceList; ParticleState p; From 5ea4a88d20b8b46f0ebf7c8cc6cd67bbdcb369f9 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 27 Aug 2012 17:26:00 +0200 Subject: [PATCH 0181/1298] added xml support for continuous sources and discrete sources using continuous distributions --- include/mpc/PeriodicGrid.h | 12 + include/mpc/Source.h | 19 +- include/mpc/XmlExecute.h | 7 +- python/mpc.i | 6 +- src/Source.cpp | 34 +++ src/XmlExecute.cpp | 263 +++++++++++++----- test/testCore.cpp | 26 +- test/testSource.cpp | 73 ++++- ...goroff.xml => traj3d_kolmogorovBfield.xml} | 0 ...traj3d_nofield.xml => traj3d_noBfield.xml} | 0 ...d_uniform.xml => traj3d_uniformBfield.xml} | 0 11 files changed, 348 insertions(+), 92 deletions(-) rename test/xml/{traj3d_kolmogoroff.xml => traj3d_kolmogorovBfield.xml} (100%) rename test/xml/{traj3d_nofield.xml => traj3d_noBfield.xml} (100%) rename test/xml/{traj3d_uniform.xml => traj3d_uniformBfield.xml} (100%) diff --git a/include/mpc/PeriodicGrid.h b/include/mpc/PeriodicGrid.h index 7a0b44eac..a2f8218e5 100644 --- a/include/mpc/PeriodicGrid.h +++ b/include/mpc/PeriodicGrid.h @@ -106,6 +106,18 @@ class PeriodicGrid: public Referenced { return grid[ix * Ny * Nz + iy * Ny + iz]; } + std::vector &getGrid() { + return grid; + } + + // return the position corresponding to a given grid index + Vector3d getPosition(int index) const { + int ix = index / (Ny * Nz); + int iy = (index / Nz) % Ny; + int iz = index % Nz; + return Vector3d(ix, iy, iz) * spacing + origin; + } + /** Interpolate the grid at a given position */ T interpolate(const Vector3d &position) const { // position on a unit grid diff --git a/include/mpc/Source.h b/include/mpc/Source.h index e3937ab89..c3402cba5 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -1,8 +1,9 @@ #ifndef MPC_SOURCE_H #define MPC_SOURCE_H -#include "mpc/ParticleState.h" #include "mpc/Referenced.h" +#include "mpc/ParticleState.h" +#include "mpc/PeriodicGrid.h" #include @@ -158,6 +159,22 @@ class SourceHomogeneousBox: public SourceProperty { void prepare(ParticleState &particle) const; }; +/** + @class SourceDensityGrid + @brief Provides source positions from a density grid + + This module takes a density grid to compute random initial positions. + First a discrete bin is drawn following the density distribution. + Then a random position is drawn from a uniform distribution in the bin. + */ +class SourceDensityGrid: public SourceProperty { + ref_ptr grid; + float sumDensity; +public: + SourceDensityGrid(ref_ptr densityGrid); + void prepare(ParticleState &particle) const; +}; + /** @class SourceIsotropicEmission @brief Isotropic emission from a source diff --git a/include/mpc/XmlExecute.h b/include/mpc/XmlExecute.h index d9700dfe9..97a2c73b2 100644 --- a/include/mpc/XmlExecute.h +++ b/include/mpc/XmlExecute.h @@ -18,7 +18,10 @@ class XmlExecute { void loadGridMagneticField(pugi::xml_node &node); void loadDeflectionCK(pugi::xml_node &node); void loadPeriodicBoundaries(); + void loadSources(pugi::xml_node &node); void loadDiscreteSources(pugi::xml_node &node); + void loadContinuousSources(pugi::xml_node &node); + void loadSourceNuclei(pugi::xml_node &node); void loadSophia(pugi::xml_node &node); void loadSpheresAroundObserver(pugi::xml_node &node); void loadSpheresAroundSource(pugi::xml_node &node); @@ -28,14 +31,14 @@ class XmlExecute { ref_ptr magnetic_field; Source source; bool is1D; - size_t trajectories; - size_t randomSeed; + size_t nTrajectories; double Emin; double maxStep; Vector3d origin; Vector3d size; public: + XmlExecute(); bool load(const std::string &filename); void run(); }; diff --git a/python/mpc.i b/python/mpc.i index f5165dcbd..844f0cf85 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -91,9 +91,6 @@ %include "mpc/ParticleState.h" -%template(SourceRefPtr) mpc::ref_ptr; -%include "mpc/Source.h" - %template(CandidateVector) std::vector< mpc::ref_ptr >; %template(CandidateRefPtr) mpc::ref_ptr; %include "mpc/Candidate.h" @@ -125,6 +122,9 @@ %include "mpc/ExplicitRungeKutta.h" %include "mpc/PhasePoint.h" +%template(SourceRefPtr) mpc::ref_ptr; +%include "mpc/Source.h" + %include "mpc/module/BreakCondition.h" %include "mpc/module/Boundary.h" diff --git a/src/Source.cpp b/src/Source.cpp index 3c6eb374c..87c6e0f32 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -3,6 +3,7 @@ #include "HepPID/ParticleIDMethods.hh" #include +#include namespace mpc { @@ -174,6 +175,39 @@ void SourceHomogeneousBox::prepare(ParticleState &particle) const { particle.setPosition(pos * size + origin); } +SourceDensityGrid::SourceDensityGrid(ref_ptr g) { + float sum = 0; + for (int ix = 0; ix < g->getNx(); ix++) { + for (int iy = 0; iy < g->getNy(); iy++) { + for (int iz = 0; iz < g->getNz(); iz++) { + sum += g->get(ix, iy, iz); + g->get(ix, iy, iz) = sum; + } + } + } + grid = g; + sumDensity = sum; +} + +void SourceDensityGrid::prepare(ParticleState &particle) const { + Random &random = Random::instance(); + + // pick random bin; find bin using STL method + double r = random.rand(sumDensity); + std::vector &v = grid->getGrid(); + std::vector::iterator it = lower_bound(v.begin(), v.end(), r); + int i = it - v.begin(); + Vector3d pos = grid->getPosition(i); + + // draw uniform position within bin + double dx = random.rand() - 0.5; + double dy = random.rand() - 0.5; + double dz = random.rand() - 0.5; + pos += Vector3d(dx, dy, dz) * grid->getSpacing(); + + particle.setPosition(pos); +} + void SourceIsotropicEmission::prepare(ParticleState &particle) const { Random &random = Random::instance(); particle.setDirection(random.randUnitVectorOnSphere()); diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 6f8733c35..b1b4a8e98 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -18,6 +18,7 @@ #include #include +#include using namespace pugi; using namespace std; @@ -34,7 +35,8 @@ double childValue(xml_node parent, string childName, bool throwIfEmpty = true) { return node.attribute("value").as_double(); } -xml_node childNode(xml_node parent, string childName, bool throwIfEmpty = true) { +xml_node childNode(xml_node parent, string childName, + bool throwIfEmpty = true) { xml_node node = parent.child(childName.c_str()); if (!node and throwIfEmpty) { stringstream ss; @@ -44,6 +46,60 @@ xml_node childNode(xml_node parent, string childName, bool throwIfEmpty = true) return node; } +SourceHomogeneousBox* loadSourceHomogeneousBox(pugi::xml_node &node) { + Vector3d origin; + origin.x = childValue(node, "Xmin_Mpc") * Mpc; + origin.y = childValue(node, "Ymin_Mpc") * Mpc; + origin.z = childValue(node, "Zmin_Mpc") * Mpc; + cout << " - Origin: " << origin / Mpc << endl; + + Vector3d size; + size.x = childValue(node, "Xmax_Mpc") * Mpc; + size.y = childValue(node, "Ymax_Mpc") * Mpc; + size.z = childValue(node, "Zmax_Mpc") * Mpc; + size -= origin; + cout << " - Size: " << size / Mpc << endl; + + return (new SourceHomogeneousBox(origin, size)); +} + +SourceDensityGrid* loadSourceDensityGrid( + pugi::xml_node &node) { + int nx = childValue(node, "Nx"); + int ny = childValue(node, "Ny"); + int nz = childValue(node, "Nz"); + cout << " - Nx = " << nx << ", Ny = " << ny << ", Nz = " << nz << endl; + + double spacing = childValue(node, "Step_Mpc") * Mpc; + cout << " - Spacing = " << spacing / Mpc << " Mpc" << endl; + + xml_node origin_node = childNode(node, "Origin"); + Vector3d origin; + origin.x = childValue(origin_node, "X_Mpc") * Mpc; + origin.y = childValue(origin_node, "Y_Mpc") * Mpc; + origin.z = childValue(origin_node, "Z_Mpc") * Mpc; + cout << " - Origin = " << origin / Mpc << " Mpc" << endl; + + ScalarGrid* grid = new ScalarGrid(origin, nx, ny, nz, spacing); + + xml_node file_node = childNode(node, "File"); + string file_type = file_node.attribute("type").as_string(); + string file_name = file_node.child_value(); + cout << " - File = " << file_name << endl; + if (file_type == "ASCII") + loadTxt(grid, file_name); + else if (file_type == "FITS") + throw runtime_error(" --> FITS files not supported"); + else + throw runtime_error(" --> unknown file type"); + + return (new SourceDensityGrid(grid)); +} + +XmlExecute::XmlExecute() : + is1D(false), nTrajectories(0), Emin(0), maxStep(0) { +} + bool XmlExecute::load(const string &filename) { xml_document doc; xml_parse_result result = doc.load_file(filename.c_str()); @@ -56,20 +112,26 @@ bool XmlExecute::load(const string &filename) { xml_node root = doc.child("CRPropa"); if (!root) - throw runtime_error("Error reading XML card: Root element CRPropa not found"); + throw runtime_error( + "Error reading XML card: Root element CRPropa not found"); // ----- general settings ----- - trajectories = (int) childValue(root, "TrajNumber"); - cout << "Trajectories: " << trajectories << endl; + nTrajectories = (int) childValue(root, "TrajNumber"); + cout << "Trajectories: " << nTrajectories << endl; double maxTime = childValue(root, "MaxTime_Mpc") * Mpc; - cout << "Maximum Time: " << maxTime / Mpc << " Mpc" << endl; + cout << "Maximum time: " << maxTime / Mpc << " Mpc" << endl; Emin = childValue(root, "MinEnergy_EeV") * EeV; - cout << "Minimum Energy: " << Emin / EeV << " EeV" << endl; - - randomSeed = (int) childValue(root, "RandomSeed"); - cout << "RandomSeed: " << randomSeed << endl; + cout << "Minimum energy: " << Emin / EeV << " EeV" << endl; + + xml_node seed_node = root.child("RandomSeed"); + if (seed_node) { + int seed = seed_node.attribute("value").as_int(); + Random &random = Random::instance(); + random.seed(seed); + cout << "Random seed: " << seed << endl; + } // ----- environment ----- xml_node node; @@ -78,7 +140,7 @@ bool XmlExecute::load(const string &filename) { cout << "Environment: " << type << endl; if (type == "One Dimension") - throw runtime_error("One Dimension not supported"); + throw runtime_error(" --> one dimension not supported"); else if (type == "LSS") { // will be overwritten if (re)defined by magnetic field origin.x = childValue(node, "Xmin_Mpc", false) * Mpc; @@ -89,13 +151,13 @@ bool XmlExecute::load(const string &filename) { size.z = childValue(node, "Zmax_Mpc", false) * Mpc; size -= origin; } else - throw runtime_error("Unknown environment"); + throw runtime_error(" --> unknown environment"); // ----- magnetic field ----- node = childNode(root, "MagneticField"); type = node.attribute("type").as_string(); cout << "MagenticField: " << type << endl; - if (type == "None") + if (type == "Null") magnetic_field = new UniformMagneticField(Vector3d(0, 0, 0)); else if (type == "Uniform") loadUniformMagneticField(node); @@ -113,7 +175,7 @@ bool XmlExecute::load(const string &filename) { if (type == "Cash-Karp RK") loadDeflectionCK(node); else - throw runtime_error("Unknown integrator"); + throw runtime_error(" --> unknown integrator"); // ----- minimum energy ----- modules.add(new MinimumEnergy(Emin)); @@ -126,14 +188,7 @@ bool XmlExecute::load(const string &filename) { // ----- sources ----- node = childNode(root, "Sources"); - type = node.attribute("type").as_string(); - cout << "Sources: " << type << endl; - if (type == "Discrete") - loadDiscreteSources(node); - else if (type == "Continuous") - throw runtime_error("Continuous sources not implemented"); - else - throw runtime_error("Unknown source"); + loadSources(node); // ----- observers ----- node = root.child("Observers"); @@ -147,7 +202,7 @@ bool XmlExecute::load(const string &filename) { else if (type == "Spheres around Source") loadSpheresAroundSource(node); else - cout << " -> unknown observer" << endl; + cout << " --> unknown observer" << endl; } // ----- output ----- @@ -163,11 +218,17 @@ bool XmlExecute::load(const string &filename) { void XmlExecute::loadDeflectionCK(xml_node &node) { double epsilon = childValue(node, "MinStep_Mpc"); cout << " - Epsilon: " << epsilon << endl; + double minStep = childValue(node, "MinStep_Mpc") * Mpc; cout << " - Minimum Step: " << minStep / Mpc << " Mpc" << endl; + + if (maxStep == 0) + maxStep = numeric_limits::max(); cout << " - Maximum Step: " << maxStep / Mpc << " Mpc" << endl; + if (minStep >= maxStep) - throw runtime_error("MaxStep must be larger than MinStep"); + throw runtime_error(" --> MaxStep must be larger than MinStep"); + modules.add(new DeflectionCK(magnetic_field, epsilon, minStep, maxStep)); } @@ -224,10 +285,9 @@ void XmlExecute::loadGridMagneticField(xml_node &node) { double alpha = childValue(node, "SpectralIndex"); cout << " - Turbulence spectral index: " << alpha << endl; - cout << " - Random seed: " << randomSeed << endl; #ifdef MPC_HAVE_FFTW3F - initTurbulence(field, brms, lMin, lMax, alpha, randomSeed); + initTurbulence(field, brms, lMin, lMax, alpha); #endif // MPC_HAVE_FFTW3F #ifndef MPC_HAVE_FFTW3F throw runtime_error("Turbulent field grid not available. Compile with FFTW3F."); @@ -310,60 +370,46 @@ void XmlExecute::loadSpheresAroundSource(pugi::xml_node &node) { } } -void XmlExecute::loadDiscreteSources(xml_node &node) { +void XmlExecute::loadSources(xml_node &node) { // source isotropic emission source.addProperty(new SourceIsotropicEmission()); // source positions - SourceMultiplePositions *positions = new SourceMultiplePositions(); - for (xml_node n = node.child("PointSource"); n; - n = n.next_sibling("PointSource")) { - Vector3d pos; - pos.x = childValue(n, "CoordX_Mpc") * Mpc; - pos.y = childValue(n, "CoordY_Mpc") * Mpc; - pos.z = childValue(n, "CoordZ_Mpc") * Mpc; - cout << " - Position " << pos / Mpc << " Mpc" << endl; - positions->add(pos); - } - source.addProperty(positions); + string type = node.attribute("type").as_string(); + cout << "Source(s): " << type << endl; + if (type == "Discrete") + loadDiscreteSources(node); + else if (type == "Continuous") + loadContinuousSources(node); + else + throw runtime_error(" --> unknown source type"); // source spectrum - xml_node spec = node.child("Spectrum"); - string spectrumType = spec.attribute("type").as_string(); + xml_node spectrum_node = node.child("Spectrum"); + string spectrumType = spectrum_node.attribute("type").as_string(); cout << " - Spectrum: " << spectrumType << endl; if (spectrumType == "Monochromatic") { - if (spec.child("Energy_EeV")) { - double E = childValue(spec, "Energy_EeV") * EeV; + if (spectrum_node.child("Energy_EeV")) { + double E = childValue(spectrum_node, "Energy_EeV") * EeV; cout << " - Energy: " << E / EeV << " EeV" << endl; source.addProperty(new SourceEnergy(E)); - } else if (spec.child("Rigidity_EeV")) - throw runtime_error("Fixed rigidity not implemented"); + } else if (spectrum_node.child("Rigidity_EeV")) + throw runtime_error(" --> Fixed rigidity not implemented"); else - throw runtime_error("Source energy missing"); + throw runtime_error(" --> Source energy missing"); // source composition - SourceNuclei *composition = new SourceNuclei; - xml_node p = node.child("Particles"); - for (xml_node n = p.child("Species"); n; - n = n.next_sibling("Species")) { - int A = (int) childValue(n, "MassNumber"); - int Z = (int) childValue(n, "ChargeNumber"); - double ab = childValue(n, "Abundance"); - composition->add(getNucleusId(A, Z), ab); - cout << " - Species: Z = " << Z << ", A = " << A - << ", abundance = " << ab << endl; - } - source.addProperty(composition); + loadSourceNuclei(node); } else if (spectrumType == "Power Law") { - double alpha = childValue(spec, "Alpha"); + double alpha = childValue(spectrum_node, "Alpha"); cout << " - Power law index: " << alpha << endl; cout << " - Minimum energy: " << Emin / EeV << " EeV" << endl; // if the source is accelerated to a maximum rigidity - if (spec.child("Rigidity_EeV")) { - double Rmax = childValue(spec, "Rigidity_EeV") * EeV; + if (spectrum_node.child("Rigidity_EeV")) { + double Rmax = childValue(spectrum_node, "Rigidity_EeV") * EeV; cout << " - Maximum rigidity: " << Rmax / EeV << " EeV" << endl; // combined source spectrum / composition @@ -381,26 +427,15 @@ void XmlExecute::loadDiscreteSources(xml_node &node) { } source.addProperty(composition); - } else if (spec.child("Ecut_EeV")) { - double Emax = childValue(spec, "Ecut_EeV") * EeV; + } else if (spectrum_node.child("Ecut_EeV")) { + double Emax = childValue(spectrum_node, "Ecut_EeV") * EeV; cout << " - Maximum energy: " << Emax / EeV << " EeV" << endl; // source spectrum source.addProperty(new SourcePowerLawSpectrum(Emin, Emax, alpha)); // source composition - SourceNuclei *composition = new SourceNuclei(); - xml_node p = node.child("Particles"); - for (xml_node n = p.child("Species"); n; - n = n.next_sibling("Species")) { - int A = n.attribute("MassNumber").as_int(); - int Z = n.attribute("ChargeNumber").as_int(); - double ab = n.attribute("Abundance").as_double(); - cout << " - Species: Z = " << Z << ", A = " << A - << ", abundance = " << ab << endl; - composition->add(getNucleusId(A, Z), ab); - } - source.addProperty(composition); + loadSourceNuclei(node); } else throw runtime_error( @@ -410,6 +445,84 @@ void XmlExecute::loadDiscreteSources(xml_node &node) { throw runtime_error(" --> unknown source spectrum"); } +void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { + xml_node density_node = node.child("Density"); + if (density_node) { // draw positions from density distribution + string type = density_node.attribute("type").as_string(); + cout << " - Density: " << type << endl; + + int nSources = childValue(node, "Number"); + cout << " - Number = " << nSources << endl; + + SourceMultiplePositions* positions = + new SourceMultiplePositions(); + + if (type == "Uniform") { + SourceHomogeneousBox* box = loadSourceHomogeneousBox(density_node); + ParticleState p; + for (int i = 0; i < nSources; i++) { + box->prepare(p); + positions->add(p.getPosition()); + cout << " - Position = " << p.getPosition() / Mpc << " Mpc" << endl; + } + + } else if (type == "Grid") { + SourceDensityGrid* grid = loadSourceDensityGrid(density_node); + ParticleState p; + for (int i = 0; i < nSources; i++) { + grid->prepare(p); + positions->add(p.getPosition()); + cout << " - Position = " << p.getPosition() / Mpc << " Mpc" << endl; + } + + } else + throw runtime_error(" --> unknown source density type"); + + source.addProperty(positions); + + } else { // read positions from xml card + SourceMultiplePositions *positions = new SourceMultiplePositions(); + for (xml_node n = node.child("PointSource"); n; + n = n.next_sibling("PointSource")) { + Vector3d pos; + pos.x = childValue(n, "CoordX_Mpc") * Mpc; + pos.y = childValue(n, "CoordY_Mpc") * Mpc; + pos.z = childValue(n, "CoordZ_Mpc") * Mpc; + cout << " - Position " << pos / Mpc << " Mpc" << endl; + positions->add(pos); + } + source.addProperty(positions); + + } +} + +void XmlExecute::loadSourceNuclei(pugi::xml_node &node) { + SourceNuclei *composition = new SourceNuclei(); + xml_node p = node.child("Particles"); + for (xml_node n = p.child("Species"); n; n = n.next_sibling("Species")) { + int A = n.attribute("MassNumber").as_int(); + int Z = n.attribute("ChargeNumber").as_int(); + double ab = n.attribute("Abundance").as_double(); + cout << " - Species: Z = " << Z << ", A = " << A << ", abundance = " + << ab << endl; + composition->add(getNucleusId(A, Z), ab); + } + source.addProperty(composition); +} + +void XmlExecute::loadContinuousSources(pugi::xml_node &node) { + xml_node density_node = node.child("Density"); + string type = density_node.attribute("type").as_string(); + cout << " - Density: " << type << endl; + + if (type == "Uniform") + source.addProperty(loadSourceHomogeneousBox(density_node)); + else if (type == "Grid") + source.addProperty(loadSourceDensityGrid(density_node)); + else + throw runtime_error(" --> unknown source density type"); +} + void XmlExecute::loadOutput(xml_node &node) { string type = node.attribute("type").as_string(); cout << "Output: " << type << endl; @@ -435,9 +548,9 @@ void XmlExecute::loadOutput(xml_node &node) { } void XmlExecute::run() { - //operator <<(cout, modules); +//operator <<(cout, modules); modules.setShowProgress(true); - modules.run(&source, trajectories, true); + modules.run(&source, nTrajectories, true); } } // namespace mpc diff --git a/test/testCore.cpp b/test/testCore.cpp index 4eead50a8..86ac3cce2 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -177,16 +177,24 @@ TEST(NucleusId, crpropaScheme) { EXPECT_EQ(26056, convertToCRPropaId(getNucleusId(56, 26))); } -TEST(Random, speed1) { - for (int i = 0; i < 10000; i++) - double r = Random().rand(); -} +TEST(Random, seed) { + Random &a = Random::instance(); + Random &b = Random::instance(); -TEST(Random, speed2) { - for (int i = 0; i < 10000; i++) { - Random &random = Random::instance(); - double r = random.rand(); - } + a.seed(42); + double r1 = a.rand(); + + a.seed(42); + double r2 = a.rand(); + + a.seed(42); + double r3 = b.rand(); + + // seeding should give same random numbers + EXPECT_EQ(r1, r2); + + // seeding should work for all instances + EXPECT_EQ(r1, r3); } int main(int argc, char **argv) { diff --git a/test/testSource.cpp b/test/testSource.cpp index aa4e9a5aa..a9a6605a5 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -38,6 +38,72 @@ TEST(SourceHomogeneousBox, simpleTest) { EXPECT_GE(size.z, pos.z); } +TEST(SourceDensityGrid, simpleTest) { + // Create a grid with 10^3 cells ranging from (0, 0, 0) to (10, 10, 10) + Vector3d origin(0.5, 0.5, 0.5); + int cells = 10; + double spacing = 1; + ref_ptr grid = new ScalarGrid(origin, cells, spacing); + for (int ix = 0; ix < cells; ix++) + for (int iy = 0; iy < cells; iy++) + for (int iz = 0; iz < cells; iz++) + grid->get(ix, iy, iz) = ix * iy * iz; + + SourceDensityGrid source(grid); + ParticleState p; + + source.prepare(p); + Vector3d pos = p.getPosition(); + + // dialed positions should be within the volume (0, 0, 0) - (10, 10, 10) + EXPECT_LE(0, pos.x); + EXPECT_GE(10, pos.x); + EXPECT_LE(0, pos.y); + EXPECT_GE(10, pos.y); + EXPECT_LE(0, pos.z); + EXPECT_GE(10, pos.z); +} + +TEST(SourceDensityGrid, OneAllowedCell) { + // Create a grid with 2^3 cells ranging from (0, 0, 0) to (4, 4, 4) + Vector3d origin(1, 1, 1); + int cells = 2; + double spacing = 2; + ref_ptr grid = new ScalarGrid(origin, cells, spacing); + + // set all but one cells to 0 + for (int ix = 0; ix < cells; ix++) + for (int iy = 0; iy < cells; iy++) + for (int iz = 0; iz < cells; iz++) + grid->get(ix, iy, iz) = 0; + + // set the first cell ((0, 0, 0) to (2, 2, 2)) + grid->get(0, 0, 0) = 1; + + SourceDensityGrid source(grid); + ParticleState p; + + int nFalse = 0; + Vector3d mean(0, 0, 0); + for (int i = 0; i < 10000; i++) { + source.prepare(p); + Vector3d pos = p.getPosition(); + mean += pos; + if ((pos.x < 0) or (pos.x > 2) or (pos.y < 0) or (pos.y > 2) + or (pos.z < 0) or (pos.z > 2)) + nFalse++; + } + + // only the first bin should get dialed + EXPECT_EQ(0, nFalse); + + // mean should be close to (1, 1, 1) if random positions are uniform in (0, 0, 0) - (2, 2, 2) + mean /= 10000; + EXPECT_NEAR(1, mean.x, 0.1); + EXPECT_NEAR(1, mean.y, 0.1); + EXPECT_NEAR(1, mean.z, 0.1); +} + TEST(SourcePowerLawSpectrum, simpleTest) { double Emin = 4 * EeV; double Emax = 200 * EeV; @@ -45,6 +111,8 @@ TEST(SourcePowerLawSpectrum, simpleTest) { SourcePowerLawSpectrum spectrum(Emin, Emax, index); ParticleState ps; spectrum.prepare(ps); + + // energy should be within Emin - Emax EXPECT_LE(Emin, ps.getEnergy()); EXPECT_GE(Emax, ps.getEnergy()); } @@ -81,7 +149,7 @@ TEST(Source, allPropertiesUsed) { EXPECT_EQ(8, ps.getMassNumber()); EXPECT_EQ(4, ps.getChargeNumber()); EXPECT_LE(5 * EeV, ps.getEnergy()); - EXPECT_GE(100 * EeV , ps.getEnergy()); + EXPECT_GE(100 * EeV, ps.getEnergy()); EXPECT_EQ(Vector3d(10, 0, 0) * Mpc, ps.getPosition()); } @@ -122,7 +190,8 @@ TEST(SourceList, luminosity) { meanE += p.getEnergy(); } meanE /= 1000; - EXPECT_NEAR(80, meanE, 2); // this test can stochastically fail + EXPECT_NEAR(80, meanE, 2); + // this test can stochastically fail } int main(int argc, char **argv) { diff --git a/test/xml/traj3d_kolmogoroff.xml b/test/xml/traj3d_kolmogorovBfield.xml similarity index 100% rename from test/xml/traj3d_kolmogoroff.xml rename to test/xml/traj3d_kolmogorovBfield.xml diff --git a/test/xml/traj3d_nofield.xml b/test/xml/traj3d_noBfield.xml similarity index 100% rename from test/xml/traj3d_nofield.xml rename to test/xml/traj3d_noBfield.xml diff --git a/test/xml/traj3d_uniform.xml b/test/xml/traj3d_uniformBfield.xml similarity index 100% rename from test/xml/traj3d_uniform.xml rename to test/xml/traj3d_uniformBfield.xml From e79599fde9cd7f83cbdecd063b9a944788bfbd6e Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 4 Sep 2012 14:05:13 +0200 Subject: [PATCH 0182/1298] improved simple redshift module, started implementation of detailed redshift --- include/mpc/module/Redshift.h | 34 +++++++++++-- src/module/Redshift.cpp | 95 +++++++++++++++++++++++------------ test/testInteraction.cpp | 15 ++++++ 3 files changed, 106 insertions(+), 38 deletions(-) diff --git a/include/mpc/module/Redshift.h b/include/mpc/module/Redshift.h index 22a489d6d..a43103a15 100644 --- a/include/mpc/module/Redshift.h +++ b/include/mpc/module/Redshift.h @@ -3,24 +3,48 @@ #include "mpc/Module.h" +#include + namespace mpc { /** @class SimpleRedshift - @brief Simple redshift calculation and adiabatic energy loss + @brief Redshift and adiabatic energy loss using Hubble's law and the distance to an observer. - Uses the relation c*z = H(0)*D to approximately calculate small redshifts as function of distance to a given center. + Using Hubble's law v = H0*D and the the small redshift approximation v ~ c*z, the redshift is calculated as z ~ H0*D/c. + It is assumed that the particle starts with a redshift z, that corresponds to its distance to the observer. + This redshift is reduced with shrinking distance to the observer, and the particle loses energy accordingly. + Redshift and particle energy are not changed if the distance to the observer grows. */ -class SimpleRedshift { +class SimpleRedshift : public Module { private: - Vector3d center; + Vector3d observer; // observer position (z = 0) + double h; // dimension-free Hubble constant, H0 = h * 100 km/s/Mpc public: - SimpleRedshift(Vector3d center); + SimpleRedshift(Vector3d observer, double h = 0.7); void process(Candidate *candidate) const; std::string getDescription() const; }; +///** +// @class Redshift +// @brief Redshift and adiabatic energy loss +// */ +//class Redshift { +//private: +// std::vector z; +// std::vector D; +// +//public: +//// double h; // dimension-free Hubble constant, H0 = h * 100 km/s/Mpc +//// double omegaM; // density parameter +//// double omegaL; // vacuum energy parameter +// Redshift(double h = 0.7, double omegaM = 0.3, double omegaL = 0.7); +// void process(Candidate *candidate) const; +// std::string getDescription() const; +//}; + } // namespace mpc #endif /* REDSHIFT_H_ */ diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index b770476e6..f4fda00c9 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -1,50 +1,79 @@ #include "mpc/module/Redshift.h" #include "mpc/Units.h" +#include + namespace mpc { -SimpleRedshift::SimpleRedshift(Vector3d center) { - this->center = center; +SimpleRedshift::SimpleRedshift(Vector3d observer, double h) : + observer(observer), h(h) { } -void SimpleRedshift::process(Candidate *candidate) const { - double d = candidate->current.getPosition().getDistanceTo(center); - double z = 0.024 * d / 100 / Mpc; - double dz = candidate->getRedshift() - z; +void SimpleRedshift::process(Candidate *c) const { + double d = c->current.getPosition().getDistanceTo(observer); + double z = h * 1e5 / Mpc * d / c_light; + double dz = z - c->getRedshift(); + + if (dz > 0) + return; // do nothing if the new redshift is higher - // redshift can only decrease - if (dz < 0) - return; + c->setRedshift(z); - // using dE/dz=E/(1+z) - candidate->current.setEnergy( - candidate->current.getEnergy() * (1 - dz) / (1 + z)); - candidate->setRedshift(z); + double E = c->current.getEnergy(); + c->current.setEnergy(E * (1 + dz) / (1 + z)); // using dE/dz=E/(1+z) } std::string SimpleRedshift::getDescription() const { - return "Simple redshift"; + std::stringstream ss; + ss << "Simple redshift: observer " << observer / Mpc << "Mpc, h = " << h; + return ss.str(); } -} // namespace mpc - -// from CRPropa -//double omegaM = 0.3; -//double omegaL = 0.7; -//double H0 = 7e4 * meter / second; -//size_t nBins = 1000; -//double zMin = 0.0001; -//double zMax = 100; +//Redshift::Redshift(double h, double omegaM, double omegaL) { +// double H0 = h * 1e5 / Mpc; // -//std::vector z; -//std::vector R; -//std::vector D; -//z.push_back(0); -//R.push_back(1); -//D.push_back(0); +// const int n = 1000; +// double zMin = 0.0001; +// double zMax = 100; // -//for (size_t i=0; i<(nBins-1); i++) { -// z.push_back( zMin * pow( zMax/zMin, i / double(nBins-2) ) ); -// R.push_back( 1. / ( (1.+z[i]) * sqrt( omegaL + omegaM * pow(1.+z[i],3) ) ) ); -// D.push_back( D[i-1] + (z[i] - z[i-1]) / 2. * (R[i-1] + R[i]) * c_light/H0 ); +// std::vector H; +// +// z.resize(n); +// H.resize(n); +// D.resize(n); +// +// z[0] = 0; +// H[0] = H0; +// D[0] = 0; +// +// // Relation between comoving distance and redshift (see J.A. Peacock, Cosmological physics, p. 89 eq. 3.76) +// // R0 dr = c / H(z) dz +// // H(z) = H0 sqrt(omegaL + omegaM (1 + z)^3) +// // Integration with midpoint rule. +// for (int i = 1; i < n; i++) { +// z[i] = pow(10, zMin + (zMax - zMin) * i / (n - 1)); +// H[i] = H0 * sqrt(omegaL + omegaM * pow(1 + z[i], 3)); +// D[i] = D[i - 1] +// + c_light * (z[i] - z[i - 1]) * (1 / H[i - 1] + 1 / H[i]) / 2; +// } //} +// +//void Redshift::process(Candidate *c) const { +//} +// +//std::string Redshift::getDescription() const { +// std::stringstream ss; +// ss << "Redshift: h = "; +// return ss.str(); +//} + +//void TParticlePropa::RedshiftLoss() { +// if (_fpUniverse->Type() == UNIVERSE_ENV1D) { +// // Using the relations dE/dz=E/(1+z) and dz/dt=H_0(1+z)E(z) +// double lLoss = _fpUniverse->H0() * _fTimeStep * sqrt(_fpUniverse->OmegaLambda() + _fpUniverse->OmegaM() * pow(1 + _fRedshift, 3)); +// _fEnergy *= (1 - lLoss); +// _fMomentum.setMag(_fEnergy * inv_c_light); +// } +//} + +} // namespace mpc diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 2f6ab2356..fec081c64 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -3,6 +3,7 @@ #include "mpc/module/NuclearDecay.h" #include "mpc/module/PhotoDisintegration.h" #include "mpc/module/PhotoPionProduction.h" +#include "mpc/module/Redshift.h" #include "gtest/gtest.h" #include @@ -413,6 +414,20 @@ TEST(SophiaPhotoPionProduction, withSecondaries) { // secondaries turned on } +TEST(SimpleRedshift, test) { + // Test redshift approximation for small redshifts z << 1. + SimpleRedshift redshift(Vector3d(0.), 0.7); + + Candidate c; + c.setRedshift(0.024); // roughly corresponds to 100 Mpc + c.current.setEnergy(100 * EeV); + c.current.setPosition(Vector3d(0.)); + + redshift.process(&c); + EXPECT_EQ(0, c.getRedshift()); + EXPECT_EQ(97.6, c.current.getEnergy() / EeV); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); From c154ccc070cf25fb20fa755d941f46992f0fafa4 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 4 Sep 2012 14:06:00 +0200 Subject: [PATCH 0183/1298] minor fixes --- include/mpc/Units.h | 16 +++++++++------- include/mpc/Vector3.h | 4 ++-- src/module/NuclearDecay.cpp | 8 +++++--- src/module/PhotoDisintegration.cpp | 3 ++- src/module/PhotoPionProduction.cpp | 3 ++- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/include/mpc/Units.h b/include/mpc/Units.h index d8b82b4fc..adc061130 100644 --- a/include/mpc/Units.h +++ b/include/mpc/Units.h @@ -21,7 +21,7 @@ static const double coulomb = 1; // physical constants static const double eplus = 1.602176487e-19 * ampere * second; -static const double c_light = 2.99792458e+8 * meter / second; +static const double c_light = 2.99792458e8 * meter / second; static const double c_squared = c_light * c_light; static const double amu = 1.660538921e-27 * kilogram; static const double mass_proton = 1.67262158e-27 * kilogram; @@ -35,17 +35,19 @@ static const double centimeter = 1e-2 * meter; // gauss static const double gauss = 1e-4 * tesla; +static const double microgauss = 1e-6 * gauss; static const double nanogauss = 1e-9 * gauss; +static const double muG = microgauss; static const double nG = nanogauss; // electron volt static const double electronvolt = eplus * joule; +static const double kiloelectronvolt = 1e3 * electronvolt; static const double megaelectronvolt = 1e6 * electronvolt; -static const double kiloelectronvolt = 1e+3 * electronvolt; -static const double gigaelectronvolt = 1e+9 * electronvolt; -static const double teraelectronvolt = 1e+12 * electronvolt; -static const double petaelectronvolt = 1e+15 * electronvolt; -static const double exaelectronvolt = 1e+18 * electronvolt; +static const double gigaelectronvolt = 1e9 * electronvolt; +static const double teraelectronvolt = 1e12 * electronvolt; +static const double petaelectronvolt = 1e15 * electronvolt; +static const double exaelectronvolt = 1e18 * electronvolt; static const double eV = electronvolt; static const double keV = kiloelectronvolt; static const double MeV = megaelectronvolt; @@ -55,7 +57,7 @@ static const double PeV = petaelectronvolt; static const double EeV = exaelectronvolt; // parsec -static const double parsec = 3.0856775807e+16 * meter; +static const double parsec = 3.0856775807e16 * meter; static const double kiloparsec = 1e3 * parsec; static const double megaparsec = 1e6 * parsec; static const double gigaparsec = 1e9 * parsec; diff --git a/include/mpc/Vector3.h b/include/mpc/Vector3.h index 03d4886c8..a7be091cf 100644 --- a/include/mpc/Vector3.h +++ b/include/mpc/Vector3.h @@ -77,7 +77,7 @@ class Vector3 { T getPhi() const { T eps = std::numeric_limits::min(); - if (fabs(x) < eps && fabs(y) < eps) + if ((fabs(x) < eps) and (fabs(y) < eps)) return 0.0; else return std::atan2(y, x); @@ -85,7 +85,7 @@ class Vector3 { T getTheta() const { T eps = std::numeric_limits::min(); - if (fabs(x) < eps && fabs(y) < eps && fabs(z) < eps) + if ((fabs(x) < eps) and (fabs(y) < eps) and (fabs(z) < eps)) return 0.0; else return atan2((T) sqrt(x * x + y * y), z); diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index 5c753bc90..ab6e4ce26 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -59,9 +59,10 @@ bool NuclearDecay::setNextInteraction(Candidate *candidate, return false; // find interaction mode with minimum random decay distance + Random &random = Random::instance(); interaction.distance = std::numeric_limits::max(); for (size_t i = 0; i < decays.size(); i++) { - double d = -log(Random::instance().rand()) * decays[i].distance; + double d = -log(random.rand()) * decays[i].distance; if (d > interaction.distance) continue; interaction.distance = d; @@ -119,14 +120,15 @@ void NuclearDecay::betaDecay(Candidate *candidate, bool isBetaPlus) const { candidate->current.setLorentzFactor(gamma); // random kinetic energy of electron in neutron decay - double T = interpolate(Random::instance().rand(), cdfBeta, tBeta); + Random &random = Random::instance(); + double T = interpolate(random.rand(), cdfBeta, tBeta); double Q = (mass - candidate->current.getMass() - mass_electron) * c_squared; double Qneutron = (mass_neutron - mass_proton - mass_electron) * c_squared; // electron energy in this decay double E = T * Q / Qneutron + mass_electron * c_squared; double p = sqrt(E * E - pow(mass_electron * c_squared, 2)); - double cosTheta = 2 * Random::instance().rand() - 1; + double cosTheta = 2 * random.rand() - 1; if (haveElectrons) // add electron/positron boosted to lab frame diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index d67b09408..ef1b23035 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -83,10 +83,11 @@ bool PhotoDisintegration::setNextInteraction(Candidate *candidate, return false; // find channel with minimum random decay distance + Random &random = Random::instance(); interaction.distance = std::numeric_limits::max(); for (size_t i = 0; i < pdModes.size(); i++) { double rate = interpolateEquidistant(lg, 6., 8./200., pdModes[i].rate); - double d = -log(Random::instance().rand()) / rate; + double d = -log(random.rand()) / rate; if (d > interaction.distance) continue; interaction.distance = d; diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index a382dc77a..5f5096bb3 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -111,7 +111,8 @@ void PhotoPionProduction::performInteraction(Candidate *candidate) const { // final proton number of emitted nucleon int Zfinal = dZ; // 50% probability of isospin change p <-> n - if (Random::instance().rand() < 1. / 2.) + Random &random = Random::instance(); + if (random.rand() < 1. / 2.) Zfinal = abs(Zfinal - 1); double E = candidate->current.getEnergy(); From 596677c5f4bbe762cf6a1c15dd9003ab6cf5b544 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 4 Sep 2012 14:30:28 +0200 Subject: [PATCH 0184/1298] added JF2012 regular field --- CMakeLists.txt | 1 + include/mpc/magneticField/JF2012Field.h | 54 +++++++ python/mpc.i | 2 + src/magneticField/JF2012Field.cpp | 201 ++++++++++++++++++++++++ 4 files changed, 258 insertions(+) create mode 100644 include/mpc/magneticField/JF2012Field.h create mode 100644 src/magneticField/JF2012Field.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c62dabe63..92f471072 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,7 @@ add_library(mpc SHARED src/module/Tools.cpp src/magneticField/MagneticFieldGrid.cpp src/magneticField/TurbulentMagneticField.cpp + src/magneticField/JF2012Field.cpp ${MPC_EXTRA_SOURCES} ) target_link_libraries(mpc ${MPC_EXTRA_LIBRARIES}) diff --git a/include/mpc/magneticField/JF2012Field.h b/include/mpc/magneticField/JF2012Field.h new file mode 100644 index 000000000..9d9f896e7 --- /dev/null +++ b/include/mpc/magneticField/JF2012Field.h @@ -0,0 +1,54 @@ +#ifndef MPC_JF2012FIELD_H +#define MPC_JF2012FIELD_H + +#include "mpc/magneticField/MagneticField.h" +#include "mpc/PeriodicGrid.h" + +namespace mpc { + +class JF2012Field: public MagneticField { + // disk field + double bDisk[8]; // field strengths of arms at r=5 kpc, b8 is determined from other 7 + double rArms[8]; // radii where each arm crosses the negative x-axis + double pitch; // pitch angle + double sinPitch, cosPitch, tan90MinusPitch; + double bRing; // ring field strength 3 rXc, z = 0 + double sinThetaX0, cosThetaX0, tanThetaX0; + double rXc; // radius of varying elevation angle region + double rX; // exponential scale height + +public: + JF2012Field(); + Vector3d getField(const Vector3d& pos) const; +}; + +class JF2012TurbulentField: public MagneticField { + double b5; + double bDisk[8]; // field strengths of arms at r=5 kpc + double rArms[8]; // radii where each arm crosses the negative x-axis + double pitch; + double tan90MinusPitch; + double r0; // radial attenuation length + double z0; // vertical attenuation length + double z0S; // vertical attenuation length for spiral field + ref_ptr grid; + +public: + JF2012TurbulentField(); + double getModulation(const Vector3d& pos) const; + Vector3d getField(const Vector3d& pos) const; +}; + +} + +#endif // MPC_JF2012FIELD_H diff --git a/python/mpc.i b/python/mpc.i index 844f0cf85..f0bfee008 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -34,6 +34,7 @@ #include "mpc/magneticField/UniformMagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" #include "mpc/magneticField/SPHMagneticField.h" +#include "mpc/magneticField/JF2012Field.h" #include "mpc/Referenced.h" #include "mpc/Candidate.h" @@ -118,6 +119,7 @@ %include "mpc/magneticField/MagneticFieldGrid.h" %include "mpc/magneticField/SPHMagneticField.h" +%include "mpc/magneticField/JF2012Field.h" %include "mpc/ExplicitRungeKutta.h" %include "mpc/PhasePoint.h" diff --git a/src/magneticField/JF2012Field.cpp b/src/magneticField/JF2012Field.cpp new file mode 100644 index 000000000..a76bfdfaf --- /dev/null +++ b/src/magneticField/JF2012Field.cpp @@ -0,0 +1,201 @@ +#include "mpc/magneticField/JF2012Field.h" +#include "mpc/Units.h" + +namespace mpc { + +double logisticFunction(double x, double x0, double w) { + return 1. / (1. + exp(-2. * (fabs(x) - x0) / w)); +} + +JF2012Field::JF2012Field() { + pitch = 11.5 * M_PI / 180; + sinPitch = sin(pitch); + cosPitch = cos(pitch); + tan90MinusPitch = tan(M_PI / 2 - pitch); + + bRing = 0.1 * muG; + hDisk = 0.40 * kpc; + wDisk = 0.27 * kpc; + + bDisk[0] = 0.1 * muG; + bDisk[1] = 3.0 * muG; + bDisk[2] = -0.9 * muG; + bDisk[3] = -0.8 * muG; + bDisk[4] = -2.0 * muG; + bDisk[5] = -4.2 * muG; + bDisk[6] = 0.0 * muG; + bDisk[7] = 2.7 * muG; + + rArms[0] = 5.1 * kpc; + rArms[1] = 6.3 * kpc; + rArms[2] = 7.1 * kpc; + rArms[3] = 8.3 * kpc; + rArms[4] = 9.8 * kpc; + rArms[5] = 11.4 * kpc; + rArms[6] = 12.7 * kpc; + rArms[7] = 15.5 * kpc; + + bNorth = 1.4 * muG; + bSouth = -1.1 * muG; + rNorth = 9.22 * kpc; + rSouth = 17 * kpc; + wHalo = 0.20 * kpc; + z0 = 5.3 * kpc; + + bX = 4.6 * muG; + thetaX0 = 49.0 * M_PI / 180; + sinThetaX0 = sin(thetaX0); + cosThetaX0 = cos(thetaX0); + tanThetaX0 = tan(thetaX0); + rXc = 4.8 * kpc; + rX = 2.9 * kpc; +} + +Vector3d JF2012Field::getField(const Vector3d& pos) const { + Vector3d b(0.); + + if (pos.getMag() < 1 * kpc) + return b; // no field if distance to GC < 1 kpc + + double r = sqrt(pos.x * pos.x + pos.y * pos.y); // in-plane radius + if (r > 20 * kpc) + return b; // no field if in-plane distance to GC > 20 kpc + + double phi = pos.getPhi(); // azimuth + double sinPhi = sin(phi); + double cosPhi = cos(phi); + + double lfDisk = logisticFunction(pos.z, hDisk, wDisk); + + // disk field + if (r > 3 * kpc) { + if (r < 5 * kpc) { + // molecular ring + double bMagD = bRing * (5 * kpc / r) * (1 - lfDisk); + b.x += -bMagD * sinPhi; + b.y += bMagD * cosPhi; + + } else if (r < 20 * kpc) { + // spiral region + double r_negx = r * exp(-(phi - M_PI) / tan90MinusPitch); + if (r_negx > rArms[7]) + r_negx = r * exp(-(phi + M_PI) / tan90MinusPitch); + if (r_negx > rArms[7]) + r_negx = r * exp(-(phi + 3 * M_PI) / tan90MinusPitch); + + double bMagD; + for (int i = 7; i >= 0; i--) + if (r_negx < rArms[i]) + bMagD = bDisk[i]; + + bMagD *= (5 * kpc / r) * (1 - lfDisk); + b.x += bMagD * (sinPitch * cosPhi - cosPitch * sinPhi); + b.y += bMagD * (sinPitch * sinPhi + cosPitch * cosPhi); + } + } + + // toroidal halo field + double bMagH = exp(-fabs(pos.z) / z0) * lfDisk; + if (pos.z >= 0) + bMagH *= bNorth * (1 - logisticFunction(r, rNorth, wHalo)); + else + bMagH *= bSouth * (1 - logisticFunction(r, rSouth, wHalo)); + b.x += -bMagH * sinPhi; + b.y += bMagH * cosPhi; + + // X-halo field + double bMagX; + double sinThetaX, cosThetaX; + double rp; + double rc = rXc + fabs(pos.z) / tanThetaX0; + if (r < rc) { + // varying elevation region + rp = r * rXc / rc; + bMagX = bX * exp(-rp / rX) * pow(rp / r, 2.); + double thetaX = atan2(fabs(pos.z), (r - rp)); + sinThetaX = sin(thetaX); + cosThetaX = cos(thetaX); + } else { + // constant elevation region + rp = r - fabs(pos.z) / tanThetaX0; + bMagX = bX * exp(-rp / rX) * (rp / r); + sinThetaX = sinThetaX0; + cosThetaX = cosThetaX0; + } + double zsign = pos.z < 0 ? -1 : 1; + b.x += zsign * bMagX * cosThetaX * cosPhi; + b.y += zsign * bMagX * cosThetaX * sinPhi; + b.z += bMagX * sinThetaX; + + return b; +} + +JF2012TurbulentField::JF2012TurbulentField() { + // correlation length = 0.060 * kpc; + r0 = 10.65363798 * kpc; + z0 = 3.89915783 * kpc; + + pitch = 11.5 * M_PI / 180; + tan90MinusPitch = tan(M_PI / 2 - pitch); + + b5 = 5.35262527 * muG; + z0S = 0.58119582 * kpc; + + bDisk[0] = 7.94373074 * muG; + bDisk[1] = 4.4140519 * muG; + bDisk[2] = 6.72729298 * muG; + bDisk[3] = 4.69436688 * muG; + bDisk[4] = 1.35254503 * muG; + bDisk[5] = 10.91095824; + bDisk[6] = 24.74973782; + bDisk[7] = 6.86975446; + + rArms[0] = 5.1 * kpc; + rArms[1] = 6.3 * kpc; + rArms[2] = 7.1 * kpc; + rArms[3] = 8.3 * kpc; + rArms[4] = 9.8 * kpc; + rArms[5] = 11.4 * kpc; + rArms[6] = 12.7 * kpc; + rArms[7] = 15.5 * kpc; +} + +double JF2012TurbulentField::getModulation(const Vector3d& pos) const { + double r = sqrt(pos.x * pos.x + pos.y * pos.y); + if (r > 20 * kpc) + return 0; // no field if in-plane distance to GC > 20 kpc + + double phi = pos.getPhi(); // azimuth + + // disk field + double spiralNorm; + if (r < 5 * kpc) { + spiralNorm = b5; + } else if (r < 20 * kpc) { + double r_negx = r * exp(-(phi - M_PI) / tan90MinusPitch); + if (r_negx > rArms[7]) + r_negx = r * exp(-(phi + M_PI) / tan90MinusPitch); + if (r_negx > rArms[7]) + r_negx = r * exp(-(phi + 3 * M_PI) / tan90MinusPitch); + + for (int i = 7; i >= 0; i--) + if (r_negx < rArms[i]) + spiralNorm = bDisk[i]; + + spiralNorm *= (5 * kpc / r); + } + spiralNorm *= exp(-0.5 * pow(pos.z / z0S, 2)); + + double smoothNorm = 1; + smoothNorm *= exp(-1. * fabs(pos.z) / z0); + smoothNorm *= exp(-1. * fabs(r) / r0); + + return sqrt(smoothNorm * smoothNorm + spiralNorm * spiralNorm); +} + +Vector3d JF2012TurbulentField::getField(const Vector3d& pos) const { + Vector3d b = grid->interpolate(pos); + return b * getModulation(pos); +} + +} From 5da943b6a5bd0557ebaa681d1298b7b659cb9ead Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 4 Sep 2012 14:48:58 +0200 Subject: [PATCH 0185/1298] renamed PeriodicGrid to Grid as it can also incorporate reflective repetition --- CMakeLists.txt | 2 +- include/mpc/{PeriodicGrid.h => Grid.h} | 16 +++++++------- .../mpc/{PeriodicGridTools.h => GridTools.h} | 8 +++---- include/mpc/Source.h | 2 +- include/mpc/magneticField/JF2012Field.h | 4 ++-- include/mpc/magneticField/MagneticFieldGrid.h | 2 +- python/mpc.i | 22 ++++++++++--------- src/{PeriodicGridTools.cpp => GridTools.cpp} | 2 +- src/XmlExecute.cpp | 2 +- src/magneticField/JF2012Field.cpp | 1 + test/testMagneticField.cpp | 4 ++-- 11 files changed, 34 insertions(+), 31 deletions(-) rename include/mpc/{PeriodicGrid.h => Grid.h} (92%) rename include/mpc/{PeriodicGridTools.h => GridTools.h} (95%) rename src/{PeriodicGridTools.cpp => GridTools.cpp} (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 92f471072..c9d164c31 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,7 +86,7 @@ add_library(mpc SHARED src/Source.cpp src/Common.cpp src/Nucleus.cpp - src/PeriodicGridTools.cpp + src/GridTools.cpp src/XmlExecute.cpp src/module/BreakCondition.cpp src/module/Boundary.cpp diff --git a/include/mpc/PeriodicGrid.h b/include/mpc/Grid.h similarity index 92% rename from include/mpc/PeriodicGrid.h rename to include/mpc/Grid.h index a2f8218e5..b144f3adb 100644 --- a/include/mpc/PeriodicGrid.h +++ b/include/mpc/Grid.h @@ -1,5 +1,5 @@ -#ifndef MPC_PERIODICGRID_H_ -#define MPC_PERIODICGRID_H_ +#ifndef MPC_GRID_H_ +#define MPC_GRID_H_ #include "mpc/Referenced.h" #include "mpc/Vector3.h" @@ -31,7 +31,7 @@ inline void reflectiveClamp(double x, int n, int &lo, int &hi) { The grid sample positions are at 0, size/N, ... (N-1) * size/N. */ template -class PeriodicGrid: public Referenced { +class Grid: public Referenced { std::vector grid; size_t Nx, Ny, Nz; /**< Number of grid points */ Vector3d origin; /**< Grid origin */ @@ -39,14 +39,14 @@ class PeriodicGrid: public Referenced { bool reflective; /**< If set to true, the grid is repeated reflectively instead of periodically */ public: - PeriodicGrid(Vector3d origin, size_t N, double spacing) { + Grid(Vector3d origin, size_t N, double spacing) { setOrigin(origin); setGridSize(N, N, N); setSpacing(spacing); setReflective(false); } - PeriodicGrid(Vector3d origin, size_t Nx, size_t Ny, size_t Nz, + Grid(Vector3d origin, size_t Nx, size_t Ny, size_t Nz, double spacing) { setOrigin(origin); setGridSize(Nx, Ny, Nz); @@ -166,9 +166,9 @@ class PeriodicGrid: public Referenced { } }; -typedef PeriodicGrid VectorGrid; -typedef PeriodicGrid ScalarGrid; +typedef Grid VectorGrid; +typedef Grid ScalarGrid; } // namespace mpc -#endif /* MPC_PERIODICGRID_H_ */ +#endif /* MPC_GRID_H_ */ diff --git a/include/mpc/PeriodicGridTools.h b/include/mpc/GridTools.h similarity index 95% rename from include/mpc/PeriodicGridTools.h rename to include/mpc/GridTools.h index 66b2cacca..c50768053 100644 --- a/include/mpc/PeriodicGridTools.h +++ b/include/mpc/GridTools.h @@ -1,7 +1,7 @@ -#ifndef MPC_PERIODICGRIDTOOLS_H_ -#define MPC_PERIODICGRIDTOOLS_H_ +#ifndef MPC_GRIDTOOLS_H_ +#define MPC_GRIDTOOLS_H_ -#include "mpc/PeriodicGrid.h" +#include "mpc/Grid.h" #include namespace mpc { @@ -67,4 +67,4 @@ void dumpTxt(ref_ptr grid, std::string filename, double c = 1); } // namespace mpc -#endif /* MPC_PERIODICGRIDTOOLS_H_ */ +#endif /* MPC_GRIDTOOLS_H_ */ diff --git a/include/mpc/Source.h b/include/mpc/Source.h index c3402cba5..c5bc1546a 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -3,7 +3,7 @@ #include "mpc/Referenced.h" #include "mpc/ParticleState.h" -#include "mpc/PeriodicGrid.h" +#include "mpc/Grid.h" #include diff --git a/include/mpc/magneticField/JF2012Field.h b/include/mpc/magneticField/JF2012Field.h index 9d9f896e7..a60e0aed1 100644 --- a/include/mpc/magneticField/JF2012Field.h +++ b/include/mpc/magneticField/JF2012Field.h @@ -2,7 +2,7 @@ #define MPC_JF2012FIELD_H #include "mpc/magneticField/MagneticField.h" -#include "mpc/PeriodicGrid.h" +#include "mpc/Grid.h" namespace mpc { @@ -41,7 +41,7 @@ class JF2012TurbulentField: public MagneticField { double r0; // radial attenuation length double z0; // vertical attenuation length double z0S; // vertical attenuation length for spiral field - ref_ptr grid; + ref_ptr grid; // turbulent field grid public: JF2012TurbulentField(); diff --git a/include/mpc/magneticField/MagneticFieldGrid.h b/include/mpc/magneticField/MagneticFieldGrid.h index c25e490c1..2928ae14c 100644 --- a/include/mpc/magneticField/MagneticFieldGrid.h +++ b/include/mpc/magneticField/MagneticFieldGrid.h @@ -2,7 +2,7 @@ #define MPC_MAGNETICFIELDGRID_H_ #include "mpc/magneticField/MagneticField.h" -#include "mpc/PeriodicGrid.h" +#include "mpc/Grid.h" namespace mpc { diff --git a/python/mpc.i b/python/mpc.i index f0bfee008..1ba30afbd 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -27,8 +27,6 @@ #include "mpc/module/SimplePropagation.h" #include "mpc/module/DeflectionCK.h" #include "mpc/module/Tools.h" -#include "mpc/PeriodicGrid.h" -#include "mpc/PeriodicGridTools.h" #include "mpc/magneticField/MagneticField.h" #include "mpc/magneticField/UniformMagneticField.h" @@ -49,6 +47,8 @@ #include "mpc/Vector3.h" #include "mpc/Source.h" #include "mpc/Common.h" +#include "mpc/Grid.h" +#include "mpc/GridTools.h" %} @@ -106,16 +106,18 @@ %include "mpc/magneticField/MagneticField.h" %include "mpc/magneticField/UniformMagneticField.h" -%include "mpc/PeriodicGrid.h" -%include "mpc/PeriodicGridTools.h" -%implicitconv mpc::ref_ptr > >; -%template(VectorGridRefPtr) mpc::ref_ptr > >; -%template(VectorGrid) mpc::PeriodicGrid >; +%include "mpc/Grid.h" +%include "mpc/GridTools.h" + +%implicitconv mpc::ref_ptr > >; +%template(VectorGridRefPtr) mpc::ref_ptr > >; +%template(VectorGrid) mpc::Grid >; + +%implicitconv mpc::ref_ptr >; +%template(ScalarGridRefPtr) mpc::ref_ptr >; +%template(ScalarGrid) mpc::Grid; -%implicitconv mpc::ref_ptr >; -%template(ScalarGridRefPtr) mpc::ref_ptr >; -%template(ScalarGrid) mpc::PeriodicGrid; %include "mpc/magneticField/MagneticFieldGrid.h" %include "mpc/magneticField/SPHMagneticField.h" diff --git a/src/PeriodicGridTools.cpp b/src/GridTools.cpp similarity index 99% rename from src/PeriodicGridTools.cpp rename to src/GridTools.cpp index 5ff7c02f3..c369f034e 100644 --- a/src/PeriodicGridTools.cpp +++ b/src/GridTools.cpp @@ -1,4 +1,4 @@ -#include "mpc/PeriodicGridTools.h" +#include "mpc/GridTools.h" #include "mpc/Random.h" #include diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index b1b4a8e98..80f6615cb 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -1,7 +1,7 @@ #include "mpc/XmlExecute.h" #include "mpc/magneticField/UniformMagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" -#include "mpc/PeriodicGridTools.h" +#include "mpc/GridTools.h" #include "mpc/module/SimplePropagation.h" #include "mpc/module/DeflectionCK.h" #include "mpc/module/ElectronPairProduction.h" diff --git a/src/magneticField/JF2012Field.cpp b/src/magneticField/JF2012Field.cpp index a76bfdfaf..8c42e040e 100644 --- a/src/magneticField/JF2012Field.cpp +++ b/src/magneticField/JF2012Field.cpp @@ -1,5 +1,6 @@ #include "mpc/magneticField/JF2012Field.h" #include "mpc/Units.h" +#include "mpc/GridTools.h" namespace mpc { diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index 0458c18ce..9ed94d87f 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -1,7 +1,7 @@ #include "mpc/magneticField/UniformMagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" -#include "mpc/PeriodicGrid.h" -#include "mpc/PeriodicGridTools.h" +#include "mpc/Grid.h" +#include "mpc/GridTools.h" #include "mpc/magneticField/TurbulentMagneticField.h" #include "mpc/Units.h" #include "mpc/Common.h" From 726abef06ca43bad4a27d7f80766de5b951a76ab Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 4 Sep 2012 15:39:40 +0200 Subject: [PATCH 0186/1298] added MagneticFieldList as container for multiple fields --- CMakeLists.txt | 1 + include/mpc/Grid.h | 4 +- include/mpc/GridTools.h | 38 ++++++++++++------- include/mpc/magneticField/MagneticField.h | 30 +++++++++++++++ include/mpc/magneticField/MagneticFieldGrid.h | 6 +-- .../mpc/magneticField/UniformMagneticField.h | 28 -------------- python/mpc.i | 3 -- src/GridTools.cpp | 30 ++++++++++----- src/XmlExecute.cpp | 5 +-- src/magneticField/JF2012Field.cpp | 3 ++ test/testMagneticField.cpp | 33 +++++++++------- test/testPropagation.cpp | 1 - 12 files changed, 107 insertions(+), 75 deletions(-) delete mode 100644 include/mpc/magneticField/UniformMagneticField.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c9d164c31..6b75ce524 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,6 +101,7 @@ add_library(mpc SHARED src/module/Redshift.cpp src/module/Output.cpp src/module/Tools.cpp + src/magneticField/MagneticField.cpp src/magneticField/MagneticFieldGrid.cpp src/magneticField/TurbulentMagneticField.cpp src/magneticField/JF2012Field.cpp diff --git a/include/mpc/Grid.h b/include/mpc/Grid.h index b144f3adb..41430da31 100644 --- a/include/mpc/Grid.h +++ b/include/mpc/Grid.h @@ -22,12 +22,12 @@ inline void reflectiveClamp(double x, int n, int &lo, int &hi) { } /** - @class PeriodicGrid + @class Grid @brief Template class for fields on a periodic grid with trilinear interpolation The grid spacing is constant and equal along all three axes. Values are calculated by trilinear interpolation of the surrounding 8 grid points. - The grid is periodically extended. + The grid is periodically (default) or reflectively extended. The grid sample positions are at 0, size/N, ... (N-1) * size/N. */ template diff --git a/include/mpc/GridTools.h b/include/mpc/GridTools.h index c50768053..d10606ea7 100644 --- a/include/mpc/GridTools.h +++ b/include/mpc/GridTools.h @@ -6,14 +6,17 @@ namespace mpc { +/** Calculate the mean field vector */ +Vector3f meanFieldVector(ref_ptr grid); + /** Calculate the mean field strength */ -Vector3f meanFieldStrength(ref_ptr m); +double meanFieldStrength(ref_ptr grid); /** Calculate the RMS field strength */ -double rmsFieldStrength(ref_ptr m); +double rmsFieldStrength(ref_ptr grid); /** Multiply a magnetic field grid by a factor. */ -void scale(ref_ptr m, double a); +void scale(ref_ptr grid, double a); #ifdef MPC_HAVE_FFTW3F /** @@ -24,12 +27,13 @@ void scale(ref_ptr m, double a); @param Brms RMS field strength @param seed Random seed */ -void initTurbulence(ref_ptr m, double Brms, double lMin, +void initTurbulence(ref_ptr grid, double Brms, double lMin, double lMax, double index = -11. / 3., int seed = 0); #endif // MPC_HAVE_FFTW3F /** Analytically calculate the correlation length of a turbulent field */ -double turbulentCorrelationLength(double lMin, double lMax, double spectralIndex = -11. / 3.); +double turbulentCorrelationLength(double lMin, double lMax, + double spectralIndex = -11. / 3.); /** Dump / load functions for scalar / 3-vector grids and binary / plain text files. @@ -42,28 +46,36 @@ double turbulentCorrelationLength(double lMin, double lMax, double spectralIndex All functions offer a conversion factor that is multiplied to all values. */ // Load a VectorGrid from a binary file with single precision. -void load(ref_ptr grid, std::string filename, double c = 1); +void loadGrid(ref_ptr grid, std::string filename, + double conversion = 1); // Load a ScalarGrid from a binary file with single precision. -void load(ref_ptr grid, std::string filename, double c = 1); +void loadGrid(ref_ptr grid, std::string filename, + double conversion = 1); // Dump a VectorGrid to a binary file. -void dump(ref_ptr grid, std::string filename, double c = 1); +void dumpGrid(ref_ptr grid, std::string filename, + double conversion = 1); // Dump a ScalarGrid to a binary file with single precision. -void dump(ref_ptr grid, std::string filename, double c = 1); +void dumpGrid(ref_ptr grid, std::string filename, + double conversion = 1); // Load a VectorGrid grid from a plain text file. -void loadTxt(ref_ptr grid, std::string filename, double c = 1); +void loadGridFromTxt(ref_ptr grid, std::string filename, + double conversion = 1); // Load a ScalarGrid from a plain text file. -void loadTxt(ref_ptr grid, std::string filename, double c = 1); +void loadGridFromTxt(ref_ptr grid, std::string filename, + double conversion = 1); // Dump a VectorGrid to a plain text file. -void dumpTxt(ref_ptr grid, std::string filename, double c = 1); +void dumpGridToTxt(ref_ptr grid, std::string filename, + double conversion = 1); // Dump a ScalarGrid to a plain text file. -void dumpTxt(ref_ptr grid, std::string filename, double c = 1); +void dumpGridToTxt(ref_ptr grid, std::string filename, + double conversion = 1); } // namespace mpc diff --git a/include/mpc/magneticField/MagneticField.h b/include/mpc/magneticField/MagneticField.h index 8cb65c3ea..efc400de0 100644 --- a/include/mpc/magneticField/MagneticField.h +++ b/include/mpc/magneticField/MagneticField.h @@ -17,6 +17,36 @@ class MagneticField: public Referenced { virtual Vector3d getField(const Vector3d &position) const = 0; }; +/** + @class MagneticFieldList + @brief List of magnetic fields + + The field at a given position is the sum of all fields evaluated at that position. + */ +class MagneticFieldList: public MagneticField { + std::vector > fields; +public: + void addField(ref_ptr field); + Vector3d getField(const Vector3d &position) const; +}; + +/** + @class UniformMagneticField + @brief Magnetic field with one B-field vector. + */ +class UniformMagneticField: public MagneticField { +private: + Vector3d value; + +public: + UniformMagneticField(const Vector3d &value) : + value(value) { + } + Vector3d getField(const Vector3d &position) const { + return value; + } +}; + } // namespace mpc #endif /* MPC_MAGNETICFIELD_H_ */ diff --git a/include/mpc/magneticField/MagneticFieldGrid.h b/include/mpc/magneticField/MagneticFieldGrid.h index 2928ae14c..75aa7b6f9 100644 --- a/include/mpc/magneticField/MagneticFieldGrid.h +++ b/include/mpc/magneticField/MagneticFieldGrid.h @@ -8,9 +8,9 @@ namespace mpc { /** @class MagneticFieldGrid - @brief Magnetic field on a periodic, cartesian grid with trilinear interpolation. + @brief Magnetic field on a periodic (or reflective), cartesian grid with trilinear interpolation. - This class provides a container for a VectorGrid (PeriodicGrid of type Vector3f) to serve as a MagneticField. + This class wraps a VectorGrid to serve as a MagneticField. */ class MagneticFieldGrid: public MagneticField { ref_ptr grid; @@ -26,7 +26,7 @@ class MagneticFieldGrid: public MagneticField { @class MagneticFieldGrid @brief Modulated magnetic field on a periodic grid. - This class provides a container for a VectorGrid to serve as a MagneticField. + This class wraps a VectorGrid to serve as a MagneticField. The field is modulated on-the-fly with a ScalarGrid. The VectorGrid and ScalarGrid do not need to share the same origin, spacing or size. */ diff --git a/include/mpc/magneticField/UniformMagneticField.h b/include/mpc/magneticField/UniformMagneticField.h deleted file mode 100644 index 7e6318019..000000000 --- a/include/mpc/magneticField/UniformMagneticField.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef MPC_UNIFORMAGNETICFIELD_H_ -#define MPC_UNIFORMAGNETICFIELD_H_ - -#include "mpc/magneticField/MagneticField.h" -#include - -namespace mpc { - -/** - @class UniformMagneticField - @brief Magnetic field with one B-field vector. - */ -class UniformMagneticField: public MagneticField { -private: - Vector3d value; - -public: - UniformMagneticField(const Vector3d &value) : - value(value) { - } - Vector3d getField(const Vector3d &position) const { - return value; - } -}; - -} // namespace mpc - -#endif /* MPC_UNIFORMAGNETICFIELD_H_ */ diff --git a/python/mpc.i b/python/mpc.i index 1ba30afbd..688fb6b5b 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -29,7 +29,6 @@ #include "mpc/module/Tools.h" #include "mpc/magneticField/MagneticField.h" -#include "mpc/magneticField/UniformMagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" #include "mpc/magneticField/SPHMagneticField.h" #include "mpc/magneticField/JF2012Field.h" @@ -104,8 +103,6 @@ %implicitconv mpc::ref_ptr; %template(MagneticFieldRefPtr) mpc::ref_ptr; %include "mpc/magneticField/MagneticField.h" -%include "mpc/magneticField/UniformMagneticField.h" - %include "mpc/Grid.h" %include "mpc/GridTools.h" diff --git a/src/GridTools.cpp b/src/GridTools.cpp index c369f034e..159ed5ea3 100644 --- a/src/GridTools.cpp +++ b/src/GridTools.cpp @@ -6,7 +6,7 @@ namespace mpc { -Vector3f meanFieldStrength(ref_ptr grid) { +Vector3f meanFieldVector(ref_ptr grid) { size_t Nx = grid->getNx(); size_t Ny = grid->getNy(); size_t Nz = grid->getNz(); @@ -18,6 +18,18 @@ Vector3f meanFieldStrength(ref_ptr grid) { return mean / Nx / Ny / Nz; } +double meanFieldStrength(ref_ptr grid) { + size_t Nx = grid->getNx(); + size_t Ny = grid->getNy(); + size_t Nz = grid->getNz(); + double mean = 0; + for (int ix = 0; ix < Nx; ix++) + for (int iy = 0; iy < Ny; iy++) + for (int iz = 0; iz < Nz; iz++) + mean += grid->get(ix, iy, iz).getMag(); + return mean / Nx / Ny / Nz; +} + double rmsFieldStrength(ref_ptr grid) { size_t Nx = grid->getNx(); size_t Ny = grid->getNy(); @@ -181,7 +193,7 @@ double turbulentCorrelationLength(double lMin, double lMax, return lMax / 2 * (a - 1) / a * (1 - pow(r, a)) / (1 - pow(r, a - 1)); } -void load(ref_ptr grid, std::string filename, double c) { +void loadGrid(ref_ptr grid, std::string filename, double c) { std::ifstream fin(filename.c_str(), std::ios::binary); if (!fin) { std::stringstream ss; @@ -202,7 +214,7 @@ void load(ref_ptr grid, std::string filename, double c) { fin.close(); } -void load(ref_ptr grid, std::string filename, double c) { +void loadGrid(ref_ptr grid, std::string filename, double c) { std::ifstream fin(filename.c_str(), std::ios::binary); if (!fin) { std::stringstream ss; @@ -221,7 +233,7 @@ void load(ref_ptr grid, std::string filename, double c) { fin.close(); } -void dump(ref_ptr grid, std::string filename, double c) { +void dumpGrid(ref_ptr grid, std::string filename, double c) { std::ofstream fout(filename.c_str(), std::ios::binary); if (!fout) { std::stringstream ss; @@ -241,7 +253,7 @@ void dump(ref_ptr grid, std::string filename, double c) { fout.close(); } -void dump(ref_ptr grid, std::string filename, double c) { +void dumpGrid(ref_ptr grid, std::string filename, double c) { std::ofstream fout(filename.c_str(), std::ios::binary); if (!fout) { std::stringstream ss; @@ -259,7 +271,7 @@ void dump(ref_ptr grid, std::string filename, double c) { fout.close(); } -void loadTxt(ref_ptr grid, std::string filename, double c) { +void loadGridFromTxt(ref_ptr grid, std::string filename, double c) { std::ifstream fin(filename.c_str()); if (!fin) { std::stringstream ss; @@ -284,7 +296,7 @@ void loadTxt(ref_ptr grid, std::string filename, double c) { fin.close(); } -void loadTxt(ref_ptr grid, std::string filename, double c) { +void loadGridFromTxt(ref_ptr grid, std::string filename, double c) { std::ifstream fin(filename.c_str()); if (!fin) { std::stringstream ss; @@ -309,7 +321,7 @@ void loadTxt(ref_ptr grid, std::string filename, double c) { fin.close(); } -void dumpTxt(ref_ptr grid, std::string filename, double c) { +void dumpGridToTxt(ref_ptr grid, std::string filename, double c) { std::ofstream fout(filename.c_str()); if (!fout) { std::stringstream ss; @@ -327,7 +339,7 @@ void dumpTxt(ref_ptr grid, std::string filename, double c) { fout.close(); } -void dumpTxt(ref_ptr grid, std::string filename, double c) { +void dumpGridToTxt(ref_ptr grid, std::string filename, double c) { std::ofstream fout(filename.c_str()); if (!fout) { std::stringstream ss; diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 80f6615cb..99bcf767b 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -1,5 +1,4 @@ #include "mpc/XmlExecute.h" -#include "mpc/magneticField/UniformMagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" #include "mpc/GridTools.h" #include "mpc/module/SimplePropagation.h" @@ -87,7 +86,7 @@ SourceDensityGrid* loadSourceDensityGrid( string file_name = file_node.child_value(); cout << " - File = " << file_name << endl; if (file_type == "ASCII") - loadTxt(grid, file_name); + loadGridFromTxt(grid, file_name); else if (file_type == "FITS") throw runtime_error(" --> FITS files not supported"); else @@ -271,7 +270,7 @@ void XmlExecute::loadGridMagneticField(xml_node &node) { string fname = node.child_value("File"); cout << " - Loading file (values in [G]): " << fname << endl; - loadTxt(field, fname, gauss); + loadGridFromTxt(field, fname, gauss); } else { double brms = childValue(node, "RMS_muG") * 1e-6 * gauss; cout << " - Brms : " << brms / nG << " nG" << endl; diff --git a/src/magneticField/JF2012Field.cpp b/src/magneticField/JF2012Field.cpp index 8c42e040e..805cd3190 100644 --- a/src/magneticField/JF2012Field.cpp +++ b/src/magneticField/JF2012Field.cpp @@ -159,6 +159,9 @@ JF2012TurbulentField::JF2012TurbulentField() { rArms[5] = 11.4 * kpc; rArms[6] = 12.7 * kpc; rArms[7] = 15.5 * kpc; + + // create a turbulent field with Kolmogorov spectrum, B_rms = + grid = new VectorGrid(Vector3d(0.), 256, 8 * parsec); } double JF2012TurbulentField::getModulation(const Vector3d& pos) const { diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index 9ed94d87f..c033f36fe 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -1,13 +1,11 @@ -#include "mpc/magneticField/UniformMagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" +#include "mpc/magneticField/TurbulentMagneticField.h" #include "mpc/Grid.h" #include "mpc/GridTools.h" -#include "mpc/magneticField/TurbulentMagneticField.h" #include "mpc/Units.h" #include "mpc/Common.h" #include "gtest/gtest.h" -#include namespace mpc { @@ -19,6 +17,18 @@ TEST(testUniformMagneticField, SimpleTest) { EXPECT_DOUBLE_EQ(b.z, 3); } +TEST(testMagneticFieldList, SimpleTest) { + // Test a list of three magnetic fields + MagneticFieldList B; + B.addField(new UniformMagneticField(Vector3d(1, 0, 0))); + B.addField(new UniformMagneticField(Vector3d(0, 2, 0))); + B.addField(new UniformMagneticField(Vector3d(0, 0, 3))); + Vector3d b = B.getField(Vector3d(0.)); + EXPECT_DOUBLE_EQ(b.x, 1); + EXPECT_DOUBLE_EQ(b.y, 2); + EXPECT_DOUBLE_EQ(b.z, 3); +} + TEST(testVectorFieldGrid, PeriodicClamp) { // Test correct determination of lower and upper neighbor int lo, hi; @@ -117,10 +127,10 @@ TEST(testVectorFieldGrid, DumpLoad) { for (int iz = 0; iz < 3; iz++) B1->get(ix, iy, iz) = Vector3f(1, 2, 3); - dump(B1, "testDump.raw"); + dumpGrid(B1, "testDump.raw"); ref_ptr B2 = new VectorGrid(Vector3d(0.), 3, 1); - load(B2, "testDump.raw"); + loadGrid(B2, "testDump.raw"); for (int ix = 0; ix < 3; ix++) { for (int iy = 0; iy < 3; iy++) { @@ -143,10 +153,10 @@ TEST(testVectorFieldGrid, DumpLoadTxt) { for (int iz = 0; iz < 3; iz++) B1->get(ix, iy, iz) = Vector3f(ix, iy, iz) * nG; - dumpTxt(B1, "testDump.txt", 1e4); + dumpGridToTxt(B1, "testDump.txt", 1e4); ref_ptr B2 = new VectorGrid(Vector3d(0.), 3, 1); - loadTxt(B2, "testDump.txt", 1e-4); + loadGridFromTxt(B2, "testDump.txt", 1e-4); for (int ix = 0; ix < 3; ix++) { for (int iy = 0; iy < 3; iy++) { @@ -187,7 +197,7 @@ TEST(testVectorFieldGrid, Turbulence_bmean_brms) { initTurbulence(grid, Brms, lMin, lMax); double precision = 1e-7; - Vector3f bMean = meanFieldStrength(grid); + Vector3f bMean = meanFieldVector(grid); EXPECT_NEAR(0, bMean.x, precision); EXPECT_NEAR(0, bMean.y, precision); EXPECT_NEAR(0, bMean.z, precision); @@ -234,7 +244,6 @@ TEST(testVectorFieldGrid, turbulence_Exceptions) { std::runtime_error); } #endif // MPC_HAVE_FFTW3F - TEST(testTurbulentMagneticField, SimpleTest) { TurbulentMagneticField B; B.setTurbulenceProperties(1 * nG, 10 * parsec, 200 * parsec, -11. / 3., @@ -254,13 +263,11 @@ TEST(testTurbulentMagneticField, Brms) { double sumB2 = 0; Vector3d Bmean, b; int n = 20; - Random random; + Random &r = Random::instance(); for (int ix = 0; ix < n; ix++) { for (int iy = 0; iy < n; iy++) { for (int iz = 0; iz < n; iz++) { - b = B.getField( - Vector3d(random.rand(), random.rand(), random.rand()) - * 100000); + b = B.getField(Vector3d(r.rand(), r.rand(), r.rand()) * 100000); Bmean += b; sumB2 = b.getMag2(); } diff --git a/test/testPropagation.cpp b/test/testPropagation.cpp index 1227c3d77..7c86f0b11 100644 --- a/test/testPropagation.cpp +++ b/test/testPropagation.cpp @@ -1,7 +1,6 @@ #include "mpc/Candidate.h" #include "mpc/module/SimplePropagation.h" #include "mpc/module/DeflectionCK.h" -#include "mpc/magneticField/UniformMagneticField.h" #include "gtest/gtest.h" From 1afd80673f599fc6f8f9af405f58744edb13286d Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 4 Sep 2012 15:55:05 +0200 Subject: [PATCH 0187/1298] added some xml test cards --- src/magneticField/MagneticField.cpp | 16 ++ test/xml/traj3d.txt | 229 ++++++++++++++++++ .../traj3d_continuousHomogeneousSources.xml | 59 +++++ .../xml/traj3d_discreteHomogeneousSources.xml | 60 +++++ 4 files changed, 364 insertions(+) create mode 100644 src/magneticField/MagneticField.cpp create mode 100644 test/xml/traj3d.txt create mode 100644 test/xml/traj3d_continuousHomogeneousSources.xml create mode 100644 test/xml/traj3d_discreteHomogeneousSources.xml diff --git a/src/magneticField/MagneticField.cpp b/src/magneticField/MagneticField.cpp new file mode 100644 index 000000000..d1f19dd4a --- /dev/null +++ b/src/magneticField/MagneticField.cpp @@ -0,0 +1,16 @@ +#include "mpc/magneticField/MagneticField.h" + +namespace mpc { + +void MagneticFieldList::addField(ref_ptr field) { + fields.push_back(field); +} + +Vector3d MagneticFieldList::getField(const Vector3d &position) const { + Vector3d b; + for (int i = 0; i < fields.size(); i++) + b += fields[i]->getField(position); + return b; +} + +} // namespace mpc diff --git a/test/xml/traj3d.txt b/test/xml/traj3d.txt new file mode 100644 index 000000000..aa3bf7440 --- /dev/null +++ b/test/xml/traj3d.txt @@ -0,0 +1,229 @@ +#CRPropa - Output data file +#Format - Particle_Type Initial_Particle_Type Initial_Position[X,Y,Z](Mpc) Initial_Momentum[E,theta,phi](EeV) Time(Mpc) Position[X,Y,Z](Mpc) Momentum[E,theta,phi](EeV) +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1622 1.9313 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1622 1.9313 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.3498 2.0907 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3498 2.0907 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6067 1.9156 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6067 1.9156 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.9684 1.6679 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9684 1.6679 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.6814 1.5475 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6814 1.5475 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1102 1.9046 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1102 1.9046 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.3624 1.6402 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3624 1.6402 +12024 12024 -9.8620 -4.4750 2.8934 100.0000 0.5216 1.9093 10.0000 -9.8620 -4.4750 2.8934 100.0000 0.5216 1.9093 +26056 26056 10.1380 -4.4750 2.8934 100.0000 2.8036 1.8223 10.0001 10.1380 -4.4750 2.8934 100.0000 2.8036 1.8223 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.0710 1.5183 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0710 1.5183 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8910 1.6062 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8910 1.6062 +12024 12024 10.1380 -4.4750 2.8934 100.0000 2.7696 1.7901 10.0000 10.1380 -4.4750 2.8934 100.0000 2.7696 1.7901 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.7549 1.4615 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.7549 1.4615 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.3231 2.3721 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3231 2.3721 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7804 1.4389 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7804 1.4389 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4734 1.2998 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4734 1.2998 +26056 26056 -9.8620 -4.4750 2.8934 100.0000 0.5034 1.8415 10.0000 -9.8620 -4.4750 2.8934 100.0000 0.5034 1.8415 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8412 1.8481 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8412 1.8481 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.2623 1.7122 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2623 1.7122 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8862 1.8306 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8862 1.8306 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.9085 1.9239 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9085 1.9239 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.6828 1.5671 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.6828 1.5671 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4532 1.7549 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4532 1.7549 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1078 1.9195 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1078 1.9195 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.7209 2.2236 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7209 2.2236 +12024 12024 -9.8620 -4.4750 2.8934 100.0000 0.4901 1.7723 10.0001 -9.8620 -4.4750 2.8934 100.0000 0.4901 1.7723 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.2886 1.9300 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.2886 1.9300 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.9640 2.1873 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9640 2.1873 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.0325 1.8441 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.0325 1.8441 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1197 1.8078 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1197 1.8078 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.7088 1.9545 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7088 1.9545 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 3.0460 1.5867 10.0000 7.3068 -2.0813 -0.1961 100.0000 3.0460 1.5867 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6890 1.4244 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6890 1.4244 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4917 1.5184 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4917 1.5184 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7909 2.2111 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7909 2.2111 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.5947 1.7593 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5947 1.7593 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.9292 2.1155 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9292 2.1155 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8714 2.2720 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8714 2.2720 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.2346 1.7256 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2346 1.7256 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.9905 1.5820 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9905 1.5820 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.7461 1.4242 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.7461 1.4242 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.6477 1.5785 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.6477 1.5785 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.3251 1.8902 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3251 1.8902 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8475 1.8799 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8475 1.8799 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7257 2.0395 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7257 2.0395 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.0964 1.7469 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.0964 1.7469 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.1800 1.9056 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1800 1.9056 +12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.8979 1.6637 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.8979 1.6637 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.9833 1.4793 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9833 1.4793 +26056 26056 -9.8620 -4.4750 2.8934 100.0000 0.3819 1.7893 10.0000 -9.8620 -4.4750 2.8934 100.0000 0.3819 1.7893 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6571 2.3054 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6571 2.3054 +12024 12024 10.1380 -4.4750 2.8934 100.0000 2.7127 1.9121 10.0000 10.1380 -4.4750 2.8934 100.0000 2.7127 1.9121 +12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.7779 1.4658 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.7779 1.4658 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4184 1.5126 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4184 1.5126 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7484 2.2601 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7484 2.2601 +12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.9333 1.3521 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.9333 1.3521 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.9822 1.9035 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9822 1.9035 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.5028 1.5063 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5028 1.5063 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.9174 1.4319 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9174 1.4319 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.1085 1.7759 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1085 1.7759 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6990 2.3461 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6990 2.3461 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7126 1.2639 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7126 1.2639 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.7709 1.2410 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7709 1.2410 +12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.9862 1.4200 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.9862 1.4200 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1343 1.7591 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1343 1.7591 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.1179 1.8418 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1179 1.8418 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.9963 1.3867 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9963 1.3867 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.1709 1.5800 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1709 1.5800 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.1589 1.5374 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1589 1.5374 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.9760 1.7233 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.9760 1.7233 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4406 1.6710 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4406 1.6710 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.5028 1.3374 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5028 1.3374 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4313 2.3067 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4313 2.3067 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.7601 1.9234 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7601 1.9234 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.1637 1.5078 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1637 1.5078 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.0391 1.4285 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0391 1.4285 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.7434 2.1786 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7434 2.1786 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.6460 1.7627 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6460 1.7627 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1176 1.6915 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1176 1.6915 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.2298 2.1215 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2298 2.1215 +12024 12024 -9.8620 -4.4750 2.8934 100.0000 0.4300 1.6885 10.0001 -9.8620 -4.4750 2.8934 100.0000 0.4300 1.6885 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.2834 1.9576 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2834 1.9576 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.0322 2.0531 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0322 2.0531 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4939 1.9703 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4939 1.9703 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.3261 1.3594 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3261 1.3594 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4640 1.4945 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4640 1.4945 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.2941 1.4466 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2941 1.4466 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.6868 1.4838 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6868 1.4838 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.6515 1.5405 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.6515 1.5405 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.5002 2.0697 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5002 2.0697 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6285 1.5468 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6285 1.5468 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4595 1.5862 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4595 1.5862 +12024 12024 10.1380 -4.4750 2.8934 100.0000 2.7131 1.8505 10.0000 10.1380 -4.4750 2.8934 100.0000 2.7131 1.8505 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.9199 1.7673 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.9199 1.7673 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4006 1.4684 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4006 1.4684 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.2171 1.4576 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2171 1.4576 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.8653 1.6369 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.8653 1.6369 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.1531 2.1785 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1531 2.1785 +12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.9808 1.7639 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.9808 1.7639 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.1103 2.0645 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1103 2.0645 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.0751 1.8391 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.0751 1.8391 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.3217 2.0816 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3217 2.0816 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4091 2.3763 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4091 2.3763 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7875 1.3791 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7875 1.3791 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6738 1.4814 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6738 1.4814 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.8119 1.2897 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8119 1.2897 +26056 26056 10.1380 -4.4750 2.8934 100.0000 2.8407 1.8266 10.0000 10.1380 -4.4750 2.8934 100.0000 2.8407 1.8266 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8126 2.1891 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8126 2.1891 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7790 1.3571 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7790 1.3571 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.1580 2.0896 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1580 2.0896 +12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.6919 1.7055 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.6919 1.7055 +12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.8138 1.3639 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.8138 1.3639 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.0715 2.1640 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0715 2.1640 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7362 1.8350 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7362 1.8350 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 3.0751 1.5695 10.0000 7.3068 -2.0813 -0.1961 100.0000 3.0751 1.5695 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1261 2.1954 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1261 2.1954 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.1104 2.1131 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1104 2.1131 +12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.9804 1.5772 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.9804 1.5772 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1388 1.5700 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1388 1.5700 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.8569 1.5687 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.8569 1.5687 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7186 1.4636 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7186 1.4636 +26056 26056 -9.8620 -4.4750 2.8934 100.0000 0.4519 1.6904 10.0000 -9.8620 -4.4750 2.8934 100.0000 0.4519 1.6904 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.9332 2.2277 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9332 2.2277 +12024 12024 7.3068 -2.0813 -0.1961 100.0000 3.0948 1.5326 10.0000 7.3068 -2.0813 -0.1961 100.0000 3.0948 1.5326 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1828 1.7694 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1828 1.7694 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7646 1.8661 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7646 1.8661 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.9419 1.5557 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.9419 1.5557 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.1113 1.8929 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1113 1.8929 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.7035 2.4041 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7035 2.4041 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.1184 1.9202 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1184 1.9202 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.1359 1.4489 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1359 1.4489 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.7244 2.4670 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7244 2.4670 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.2744 1.7351 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2744 1.7351 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.6062 1.6856 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6062 1.6856 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8730 1.4908 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8730 1.4908 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.3786 1.5151 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3786 1.5151 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.3796 1.3764 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3796 1.3764 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4932 2.2932 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4932 2.2932 +12024 12024 7.3068 -2.0813 -0.1961 100.0000 3.0299 1.5399 10.0000 7.3068 -2.0813 -0.1961 100.0000 3.0299 1.5399 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.2265 1.8599 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2265 1.8599 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.0688 2.1296 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0688 2.1296 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.3935 1.5726 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3935 1.5726 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4801 1.9309 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4801 1.9309 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.0249 1.5108 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0249 1.5108 +26056 26056 -9.8620 -4.4750 2.8934 100.0000 0.3172 1.7619 10.0001 -9.8620 -4.4750 2.8934 100.0000 0.3172 1.7619 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4975 1.4686 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4975 1.4686 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.6060 1.8076 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6060 1.8076 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.8993 1.3121 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8993 1.3121 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7251 2.0082 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7251 2.0082 +26056 26056 -9.8620 -4.4750 2.8934 100.0000 0.3982 1.8046 10.0000 -9.8620 -4.4750 2.8934 100.0000 0.3982 1.8046 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6992 1.3259 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6992 1.3259 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.6289 1.4780 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.6289 1.4780 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8970 2.3741 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8970 2.3741 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.1597 1.7826 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1597 1.7826 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 3.1025 1.4763 10.0000 7.3068 -2.0813 -0.1961 100.0000 3.1025 1.4763 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8596 1.9905 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8596 1.9905 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.1828 2.0690 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1828 2.0690 +12024 12024 -9.8620 -4.4750 2.8934 100.0000 0.3054 1.8699 10.0001 -9.8620 -4.4750 2.8934 100.0000 0.3054 1.8699 +12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.6415 1.4083 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.6415 1.4083 +12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.8935 1.6142 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.8935 1.6142 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.3750 2.1701 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3750 2.1701 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.2096 1.7363 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.2096 1.7363 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.9567 1.9238 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9567 1.9238 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.9467 1.3105 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.9467 1.3105 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4563 1.9619 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4563 1.9619 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.5715 2.2863 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5715 2.2863 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.5079 1.3717 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5079 1.3717 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.7627 1.8147 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7627 1.8147 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.2311 1.5927 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2311 1.5927 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8339 1.5338 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8339 1.5338 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.5967 2.4435 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5967 2.4435 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.0380 2.0417 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.0380 2.0417 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.5866 1.4745 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5866 1.4745 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.2761 2.0689 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2761 2.0689 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.6997 1.6826 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.6997 1.6826 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.0862 1.9539 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0862 1.9539 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.3795 1.3923 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3795 1.3923 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1219 2.1920 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1219 2.1920 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.1979 1.6959 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1979 1.6959 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.1328 2.1604 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1328 2.1604 +12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.8759 1.4573 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.8759 1.4573 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.0329 2.0965 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0329 2.0965 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8468 1.8410 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8468 1.8410 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.1690 1.7352 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1690 1.7352 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8398 2.0366 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8398 2.0366 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.3391 1.6946 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3391 1.6946 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.2954 2.0088 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2954 2.0088 +12024 12024 10.1380 -4.4750 2.8934 100.0000 2.8010 1.7879 10.0001 10.1380 -4.4750 2.8934 100.0000 2.8010 1.7879 +12024 12024 -9.8620 -4.4750 2.8934 100.0000 0.4505 1.9146 10.0001 -9.8620 -4.4750 2.8934 100.0000 0.4505 1.9146 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.0170 1.6330 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0170 1.6330 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.3878 2.3649 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3878 2.3649 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.8741 2.4261 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8741 2.4261 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6459 1.9383 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6459 1.9383 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8452 2.2063 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8452 2.2063 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.1460 1.8963 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1460 1.8963 +12024 12024 -9.8620 -4.4750 2.8934 100.0000 0.4398 1.7965 10.0001 -9.8620 -4.4750 2.8934 100.0000 0.4398 1.7965 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.9813 1.3381 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9813 1.3381 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.1468 2.0255 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1468 2.0255 +12024 12024 7.3068 -2.0813 -0.1961 100.0000 3.1160 1.6232 10.0000 7.3068 -2.0813 -0.1961 100.0000 3.1160 1.6232 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.6544 2.1914 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6544 2.1914 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.2064 1.4724 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2064 1.4724 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.7113 1.7739 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7113 1.7739 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 3.0522 1.4619 10.0000 7.3068 -2.0813 -0.1961 100.0000 3.0522 1.4619 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.6378 2.4308 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6378 2.4308 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.3422 2.3037 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3422 2.3037 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4440 1.3151 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4440 1.3151 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6734 1.3403 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6734 1.3403 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8504 1.7907 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8504 1.7907 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4860 2.0177 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4860 2.0177 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.7156 1.3508 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.7156 1.3508 +12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.7979 1.6159 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.7979 1.6159 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.6821 2.0317 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6821 2.0317 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.5301 1.4448 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5301 1.4448 +12024 12024 -9.8620 -4.4750 2.8934 100.0000 0.4951 1.7900 10.0001 -9.8620 -4.4750 2.8934 100.0000 0.4951 1.7900 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4912 1.4909 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4912 1.4909 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.5935 1.2710 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5935 1.2710 +12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.8576 1.7454 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.8576 1.7454 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4314 1.6173 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4314 1.6173 +26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.7439 1.7456 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.7439 1.7456 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.0122 1.8080 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0122 1.8080 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.6310 1.9796 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6310 1.9796 +12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.9833 1.3801 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.9833 1.3801 +12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8248 1.9495 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8248 1.9495 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4987 2.1784 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4987 2.1784 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.0825 1.7856 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.0825 1.7856 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6585 1.6868 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6585 1.6868 +26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6040 1.8225 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6040 1.8225 diff --git a/test/xml/traj3d_continuousHomogeneousSources.xml b/test/xml/traj3d_continuousHomogeneousSources.xml new file mode 100644 index 000000000..e3bf98a28 --- /dev/null +++ b/test/xml/traj3d_continuousHomogeneousSources.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + traj3d.txt + + + diff --git a/test/xml/traj3d_discreteHomogeneousSources.xml b/test/xml/traj3d_discreteHomogeneousSources.xml new file mode 100644 index 000000000..90cf2c476 --- /dev/null +++ b/test/xml/traj3d_discreteHomogeneousSources.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + traj3d.txt + + + From e221a5781ffdcc3d7aeba2570d20de85994dc7fe Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 5 Sep 2012 16:37:41 +0200 Subject: [PATCH 0188/1298] fixed bug in CRPropa2EventOutput --- src/module/Output.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 6c85d6af1..f0c9181ed 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -125,7 +125,7 @@ void CRPropa2EventOutput::process(Candidate *candidate) const { p += sprintf(buffer + p, "%.4f ", t); const Vector3d &pos = candidate->current.getPosition() / Mpc; - p += sprintf(buffer + p, "%.4f %.4f %.4f ", ipos.x, ipos.y, ipos.z); + p += sprintf(buffer + p, "%.4f %.4f %.4f ", pos.x, pos.y, pos.z); double phi = candidate->current.getDirection().getPhi(); double theta = candidate->current.getDirection().getTheta(); From 94a173e4489c487755b7e513eeb519597e64b81b Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 6 Sep 2012 15:05:32 +0200 Subject: [PATCH 0189/1298] implemented Redshift changed Source interface to now return complete Candidates added SourceRedshift --- include/mpc/Candidate.h | 36 +-- include/mpc/ModuleList.h | 2 - include/mpc/Source.h | 26 ++- include/mpc/module/ElectronPairProduction.h | 2 +- include/mpc/module/Redshift.h | 37 ++-- src/ModuleList.cpp | 22 +- src/Source.cpp | 65 +++++- src/magneticField/JF2012Field.cpp | 4 +- src/module/ElectronPairProduction.cpp | 8 +- src/module/NuclearDecay.cpp | 5 + src/module/PhotoDisintegration.cpp | 2 + src/module/PhotoPionProduction.cpp | 6 +- src/module/Redshift.cpp | 71 +++--- src/module/StochasticInteraction.cpp | 1 + test/testInteraction.cpp | 13 ++ test/testSource.cpp | 50 +++-- test/xml/traj3d.txt | 229 -------------------- test/xml/traj3d_noBfield.xml | 2 +- test/xml/traj3d_uniformBfield.xml | 1 - 19 files changed, 211 insertions(+), 371 deletions(-) delete mode 100644 test/xml/traj3d.txt diff --git a/include/mpc/Candidate.h b/include/mpc/Candidate.h index 81f62c511..7e3a5227c 100644 --- a/include/mpc/Candidate.h +++ b/include/mpc/Candidate.h @@ -24,19 +24,21 @@ struct InteractionState { distance(distance), channel(channel) { } - double distance; - int channel; + double distance; /**< Free distance of the interaction in [m] comoving units */ + int channel; /**< Interaction ID */ }; /** @class Candidate - @brief All information about the the cosmic ray candidate. + @brief All information about the cosmic ray. + + The Candidate is a passive object, that holds all information about the initial and current state of the cosmic ray and the status of propagation. */ class Candidate: public Referenced { public: ParticleState initial; /**< Particle state at the beginning of propagation */ ParticleState current; /**< Current particle state */ - ParticleState previous; /**< Particle state at the end of the previous step */ + ParticleState previous; /**< Particle state at the end of the previous step */ std::vector > secondaries; /**< Secondary particles created in interactions */ @@ -44,34 +46,36 @@ class Candidate: public Referenced { typedef Loki::AssocVector InteractionStatesMap; private: - bool active; - double redshift, trajectoryLength; - double currentStep, nextStep; + bool active; /**< Active status */ + double redshift; /**< Current simulation time-point in terms of redshift z, z = 0 being the present */ + double trajectoryLength; /**< Comoving distance [m] the candidate has travelled so far */ + double currentStep; /**< Size of the currently performed step in [m] comoving units */ + double nextStep; /**< Proposed size of the next propagation step in [m] comoving units */ - PropertyMap properties; - InteractionStatesMap interactionStates; + PropertyMap properties; /**< Map of property names and their values. */ + InteractionStatesMap interactionStates; /**< Map of physical interactions that are scheduled to happen to the candidate. */ public: Candidate(); + /** Creates a candidate, initializing the initial, previous and current particle state with the argument. */ Candidate(const ParticleState &state); - virtual ~Candidate() { - - }; bool isActive() const; void setActive(bool b); + void setTrajectoryLength(double length); double getTrajectoryLength() const; - void setTrajectoryLength(double a); - double getRedshift() const; void setRedshift(double z); + double getRedshift() const; + /** Sets the current step and increases the trajectory length accordingly. Only the propagation module should use this. */ + void setCurrentStep(double step); double getCurrentStep() const; - void setCurrentStep(double lstep); - double getNextStep() const; + /** Sets the proposed next step. Only the propagation module should use this. */ void setNextStep(double step); + double getNextStep() const; void limitNextStep(double step); void setProperty(const std::string &name, const std::string &value); diff --git a/include/mpc/ModuleList.h b/include/mpc/ModuleList.h index 93f3f38bb..8e2327f50 100644 --- a/include/mpc/ModuleList.h +++ b/include/mpc/ModuleList.h @@ -4,8 +4,6 @@ #include "mpc/Candidate.h" #include "mpc/Module.h" #include "mpc/Source.h" -#include "mpc/AssocVector.h" -#include "mpc/Referenced.h" #include #include diff --git a/include/mpc/Source.h b/include/mpc/Source.h index c5bc1546a..89bfce7bd 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -2,7 +2,7 @@ #define MPC_SOURCE_H #include "mpc/Referenced.h" -#include "mpc/ParticleState.h" +#include "mpc/Candidate.h" #include "mpc/Grid.h" #include @@ -15,7 +15,8 @@ namespace mpc { */ class SourceProperty: public Referenced { public: - virtual void prepare(ParticleState &state) const = 0; + virtual void prepare(ParticleState &particle) const; + virtual void prepare(Candidate &candidate) const; }; /** @@ -23,25 +24,27 @@ class SourceProperty: public Referenced { @brief General cosmic ray source This class is a container for source properties. - The source prepares a particle by passing it to all its source properties, who in turn modify it accordingly. + The source prepares a new candidate by passing it to all its source properties to be modified accordingly. */ class Source: public Referenced { std::vector > properties; public: - void addProperty(SourceProperty *property); - void prepare(ParticleState &particle) const; + void addProperty(SourceProperty* property); + ref_ptr getCandidate() const; }; /** @class SourceList @brief List of cosmic ray sources of individual total lumosities. + + The SourceList is a source itself. It can be used if several UHECR sources are needed in one simulation. */ class SourceList: public Source { std::vector > sources; std::vector luminosities; public: void addSource(Source *source, double luminosity = 1); - void prepare(ParticleState &particle) const; + ref_ptr getCandidate() const; }; /** @@ -207,6 +210,17 @@ class SourceEmissionCone: public SourceProperty { void prepare(ParticleState &particle) const; }; +/** + @class SourceRedshift + @brief Redshift at the time of emission for particles that travel rectalinearly towards the observer + */ +class SourceRedshift: public SourceProperty { + double z; +public: + SourceRedshift(double distance, double h = 0.7, double omegaM = 0.3, double omegaL = 0.7); + void prepare(Candidate &candidate) const; +}; + }// namespace mpc #endif /* MPC_SOURCE_H */ diff --git a/include/mpc/module/ElectronPairProduction.h b/include/mpc/module/ElectronPairProduction.h index c1e4232f8..b8157fc11 100644 --- a/include/mpc/module/ElectronPairProduction.h +++ b/include/mpc/module/ElectronPairProduction.h @@ -11,7 +11,7 @@ namespace mpc { @brief Electron-pair production of charged nuclei with background photons. This module simulates electron-pair production as a continuous energy loss.\n - Several photon fields can be selected. They are considered as homogeneous and evolving as the CMB. + Several photon fields can be selected. They are considered homogeneous and evolving as the CMB. */ class ElectronPairProduction: public Module { private: diff --git a/include/mpc/module/Redshift.h b/include/mpc/module/Redshift.h index a43103a15..0fada03e7 100644 --- a/include/mpc/module/Redshift.h +++ b/include/mpc/module/Redshift.h @@ -1,5 +1,5 @@ -#ifndef REDSHIFT_H_ -#define REDSHIFT_H_ +#ifndef MPC_REDSHIFT_H_ +#define MPC_REDSHIFT_H_ #include "mpc/Module.h" @@ -27,24 +27,21 @@ class SimpleRedshift : public Module { std::string getDescription() const; }; -///** -// @class Redshift -// @brief Redshift and adiabatic energy loss -// */ -//class Redshift { -//private: -// std::vector z; -// std::vector D; -// -//public: -//// double h; // dimension-free Hubble constant, H0 = h * 100 km/s/Mpc -//// double omegaM; // density parameter -//// double omegaL; // vacuum energy parameter -// Redshift(double h = 0.7, double omegaM = 0.3, double omegaL = 0.7); -// void process(Candidate *candidate) const; -// std::string getDescription() const; -//}; +/** + @class Redshift + @brief Calculation of cosmological redshift and adiabatic energy loss + */ +class Redshift : public Module { +private: + double H0; // Hubble constant, H0 = h * 100 km/s/Mpc + double omegaM; // density parameter + double omegaL; // vacuum energy parameter + +public: + Redshift(double h = 0.7, double omegaM = 0.3, double omegaL = 0.7); + void process(Candidate *candidate) const; +}; } // namespace mpc -#endif /* REDSHIFT_H_ */ +#endif /* MPC_REDSHIFT_H_ */ diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 1425e4cbb..c0292a2c9 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -10,11 +10,9 @@ namespace mpc { ModuleList::ModuleList() : showProgress(false) { - } ModuleList::~ModuleList() { - } void ModuleList::setShowProgress(bool show) { @@ -35,34 +33,28 @@ void ModuleList::process(Candidate *candidate) { } void ModuleList::run(Candidate *candidate, bool recursive) { - while (candidate->isActive()) { + while (candidate->isActive()) process(candidate); - } // propagate secondaries - if (recursive) { + if (recursive) for (size_t i = 0; i < candidate->secondaries.size(); i++) run(candidate->secondaries[i], recursive); - } - } void ModuleList::run(candidate_vector_t &candidates, bool recursive) { size_t count = candidates.size(); - size_t pc = std::max(count / 100, size_t(1)); + #if _OPENMP std::cout << "mpc::ModuleList: Number of Threads: " << omp_get_max_threads() << std::endl; #endif ProgressBar *progressbar = NULL; - if (showProgress) { + if (showProgress) progressbar = new ProgressBar("Run ModuleList", count); - } #pragma omp parallel for schedule(dynamic, 1000) for (size_t i = 0; i < count; i++) { - //if ((showProgress) && (i % pc == 0)) - // std::cout << i / pc << "% - " << i << std::endl; run(candidates[i], recursive); if (progressbar) @@ -72,7 +64,6 @@ void ModuleList::run(candidate_vector_t &candidates, bool recursive) { } void ModuleList::run(Source *source, size_t count, bool recursive) { - size_t pc = std::max(count / 100, size_t(1)); #if _OPENMP std::cout << "mpc::ModuleList: Number of Threads: " << omp_get_max_threads() << std::endl; @@ -85,10 +76,9 @@ void ModuleList::run(Source *source, size_t count, bool recursive) { #pragma omp parallel for schedule(dynamic, 1000) for (size_t i = 0; i < count; i++) { - ParticleState state; - source->prepare(state); - ref_ptr candidate = new Candidate(state); + ref_ptr candidate = source->getCandidate(); run(candidate, recursive); + if (progressbar) #pragma omp critical(progressbarUpdate) progressbar->update(); diff --git a/src/Source.cpp b/src/Source.cpp index 87c6e0f32..71018c8c2 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -7,31 +7,42 @@ namespace mpc { -void Source::addProperty(SourceProperty *property) { +void SourceProperty::prepare(ParticleState &particle) const { +} + +void SourceProperty::prepare(Candidate &candidate) const { + ParticleState &initial = candidate.initial; + prepare(initial); + candidate.current = initial; + candidate.previous = initial; +} + +void Source::addProperty(SourceProperty* property) { properties.push_back(property); } -void Source::prepare(ParticleState &particle) const { +ref_ptr Source::getCandidate() const { + ref_ptr candidate = new Candidate(); for (int i = 0; i < properties.size(); i++) - (*properties[i]).prepare(particle); + (*properties[i]).prepare(*candidate); + return candidate; } -void SourceList::addSource(Source *source, double lumi) { +void SourceList::addSource(Source* source, double lumi) { sources.push_back(source); if (luminosities.size() > 0) lumi += luminosities.back(); luminosities.push_back(lumi); } -void SourceList::prepare(ParticleState &particle) const { - Random &random = Random::instance(); +ref_ptr SourceList::getCandidate() const { if (sources.size() == 0) throw std::runtime_error("SourceList: no sources set"); - double r = random.rand() * luminosities.back(); + double r = Random::instance().rand() * luminosities.back(); int i = 0; while ((r > luminosities[i]) and (i < luminosities.size())) i++; - (sources[i])->prepare(particle); + return (sources[i])->getCandidate(); } SourceParticleType::SourceParticleType(int id) : @@ -230,4 +241,42 @@ void SourceEmissionCone::prepare(ParticleState &particle) const { particle.setDirection(random.randConeVector(direction, aperture)); } +SourceRedshift::SourceRedshift(double d, double h, double omegaM, + double omegaL) { + double H0 = h * 1e5 / Mpc; + + const int n = 1000; + double zMin = 0.0001; + double zMax = 100; + + std::vector Z; // redshift + std::vector D; // comoving distance [m] + std::vector H; // Hubble rate [1/s] + + Z.resize(n); + H.resize(n); + D.resize(n); + + Z[0] = 0; + H[0] = H0; + D[0] = 0; + + // Relation between comoving distance and redshift (see J.A. Peacock, Cosmological physics, p. 89 eq. 3.76) + // R0 dr = c / H(z) dz + // H(z) = H0 sqrt(omegaL + omegaM (1 + z)^3) + // Integration with midpoint rule. + for (int i = 1; i < n; i++) { + Z[i] = pow(10, zMin + (zMax - zMin) * i / (n - 1)); + H[i] = H0 * sqrt(omegaL + omegaM * pow(1 + Z[i], 3)); + D[i] = D[i - 1] + + c_light * (Z[i] - Z[i - 1]) * (1 / H[i - 1] + 1 / H[i]) / 2; + } + + z = interpolate(d, &D[0], &Z[0]); +} + +void SourceRedshift::prepare(Candidate &candidate) const { + candidate.setRedshift(z); +} + } // namespace mpc diff --git a/src/magneticField/JF2012Field.cpp b/src/magneticField/JF2012Field.cpp index 805cd3190..d8943559d 100644 --- a/src/magneticField/JF2012Field.cpp +++ b/src/magneticField/JF2012Field.cpp @@ -160,8 +160,10 @@ JF2012TurbulentField::JF2012TurbulentField() { rArms[6] = 12.7 * kpc; rArms[7] = 15.5 * kpc; - // create a turbulent field with Kolmogorov spectrum, B_rms = + // create a turbulent field with Kolmogorov spectrum, B_rms = 1 and Lc = 60 parsec grid = new VectorGrid(Vector3d(0.), 256, 8 * parsec); + double seed = 42; + initTurbulence(grid, 1., 16 * parsec, 255.5 * parsec, -11/3., seed); } double JF2012TurbulentField::getModulation(const Vector3d& pos) const { diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index a88b588dc..29bd78082 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -67,12 +67,12 @@ void ElectronPairProduction::process(Candidate *candidate) const { if (EpA < energy.back()) rate = interpolate(EpA, &energy[0], &lossRate[0]); else - // extrapolation for higher energies - rate = lossRate.back() * pow(EpA / energy.back(), 0.4); + rate = lossRate.back() * pow(EpA / energy.back(), 0.4); // extrapolation - // dE(E) = Z^2 * loss_rate(E/A) * step - double step = candidate->getCurrentStep(); + double step = candidate->getCurrentStep() / (1 + z); double Z = candidate->current.getChargeNumber(); + + // dE(E) = Z^2 * loss_rate(E/A) * step double dE = Z * Z * rate * pow(1 + z, 3) * step; candidate->current.setEnergy(E - dE); } diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index ab6e4ce26..1a374343f 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -68,7 +68,12 @@ bool NuclearDecay::setNextInteraction(Candidate *candidate, interaction.distance = d; interaction.channel = decays[i].channel; } + + // special relativistic time dilation increases the decay distance by gamma interaction.distance *= candidate->current.getLorentzFactor(); + // convert to cosmological comoving units + interaction.distance *= (1 + candidate->getRedshift()); + candidate->setInteractionState(getDescription(), interaction); return true; } diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index ef1b23035..bf72962cd 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -96,6 +96,8 @@ bool PhotoDisintegration::setNextInteraction(Candidate *candidate, // CMB density increases with (1+z)^3 -> free distance decreases accordingly interaction.distance /= pow((1 + z), 3); + // convert to cosmological comoving units + interaction.distance *= (1 + z); candidate->setInteractionState(getDescription(), interaction); return true; diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 5f5096bb3..80382171a 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -92,10 +92,8 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, // CMB density increases with (1+z)^3 -> free distance decreases accordingly interaction.distance /= pow((1 + z), 3); - - if (std::isnan(interaction.distance)) { - return false; - } + // convert to cosmological comoving units + interaction.distance *= (1 + z); candidate->setInteractionState(getDescription(), interaction); return true; diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index f4fda00c9..fda02e284 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -1,5 +1,6 @@ #include "mpc/module/Redshift.h" #include "mpc/Units.h" +#include "mpc/Common.h" #include @@ -29,51 +30,31 @@ std::string SimpleRedshift::getDescription() const { return ss.str(); } -//Redshift::Redshift(double h, double omegaM, double omegaL) { -// double H0 = h * 1e5 / Mpc; -// -// const int n = 1000; -// double zMin = 0.0001; -// double zMax = 100; -// -// std::vector H; -// -// z.resize(n); -// H.resize(n); -// D.resize(n); -// -// z[0] = 0; -// H[0] = H0; -// D[0] = 0; -// -// // Relation between comoving distance and redshift (see J.A. Peacock, Cosmological physics, p. 89 eq. 3.76) -// // R0 dr = c / H(z) dz -// // H(z) = H0 sqrt(omegaL + omegaM (1 + z)^3) -// // Integration with midpoint rule. -// for (int i = 1; i < n; i++) { -// z[i] = pow(10, zMin + (zMax - zMin) * i / (n - 1)); -// H[i] = H0 * sqrt(omegaL + omegaM * pow(1 + z[i], 3)); -// D[i] = D[i - 1] -// + c_light * (z[i] - z[i - 1]) * (1 / H[i - 1] + 1 / H[i]) / 2; -// } -//} -// -//void Redshift::process(Candidate *c) const { -//} -// -//std::string Redshift::getDescription() const { -// std::stringstream ss; -// ss << "Redshift: h = "; -// return ss.str(); -//} +Redshift::Redshift(double h, double m, double l) { + H0 = h * 1e5 / Mpc; + omegaM = m; + omegaL = l; -//void TParticlePropa::RedshiftLoss() { -// if (_fpUniverse->Type() == UNIVERSE_ENV1D) { -// // Using the relations dE/dz=E/(1+z) and dz/dt=H_0(1+z)E(z) -// double lLoss = _fpUniverse->H0() * _fTimeStep * sqrt(_fpUniverse->OmegaLambda() + _fpUniverse->OmegaM() * pow(1 + _fRedshift, 3)); -// _fEnergy *= (1 - lLoss); -// _fMomentum.setMag(_fEnergy * inv_c_light); -// } -//} + std::stringstream ss; + ss << "Redshift for cosmological parameters: h = " << h << ", omegaL = " + << omegaL << ", omegaM = " << omegaM; + setDescription(ss.str()); +} + +void Redshift::process(Candidate *c) const { + double z = c->getRedshift(); + if (z == 0) + return; // nothing to do + + // small step approximation: dz = H(z) / c * dr + // an analytical form for the integral would be better + double H = H0 * sqrt(omegaL + omegaM * pow(1 + z, 3)); + double dz = H / c_light * c->getCurrentStep(); + dz = std::min(z, dz); // dz cannot be larger than z + + c->setRedshift(z - dz); + double E = c->current.getEnergy(); + c->current.setEnergy(E * (1 - dz) / (1 + z)); // using dE/dz=E/(1+z) +} } // namespace mpc diff --git a/src/module/StochasticInteraction.cpp b/src/module/StochasticInteraction.cpp index 34c320495..a2cd73383 100644 --- a/src/module/StochasticInteraction.cpp +++ b/src/module/StochasticInteraction.cpp @@ -3,6 +3,7 @@ namespace mpc { void StochasticInteraction::process(Candidate* candidate) const { + double z = candidate->getRedshift(); double step = candidate->getCurrentStep(); while (step >= 0) { diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index fec081c64..b28ca0e10 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -428,6 +428,19 @@ TEST(SimpleRedshift, test) { EXPECT_EQ(97.6, c.current.getEnergy() / EeV); } +TEST(Redshift, test) { + Redshift redshift(0.7, 0.3, 0.7); + + Candidate c; + c.setRedshift(0.024); // roughly corresponds to 100 Mpc + c.current.setEnergy(100 * EeV); + c.current.setPosition(Vector3d(0.)); + + redshift.process(&c); + EXPECT_LT(c.getRedshift(), 1); + EXPECT_LT(c.current.getEnergy() / EeV, 100); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/test/testSource.cpp b/test/testSource.cpp index a9a6605a5..7c596a27b 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -144,13 +144,29 @@ TEST(Source, allPropertiesUsed) { source.addProperty(new SourceIsotropicEmission()); source.addProperty(new SourcePowerLawSpectrum(5 * EeV, 100 * EeV, -2)); source.addProperty(new SourceParticleType(getNucleusId(8, 4))); - ParticleState ps; - source.prepare(ps); - EXPECT_EQ(8, ps.getMassNumber()); - EXPECT_EQ(4, ps.getChargeNumber()); - EXPECT_LE(5 * EeV, ps.getEnergy()); - EXPECT_GE(100 * EeV, ps.getEnergy()); - EXPECT_EQ(Vector3d(10, 0, 0) * Mpc, ps.getPosition()); + + Candidate c = *source.getCandidate(); + + ParticleState p = c.initial; + EXPECT_EQ(8, p.getMassNumber()); + EXPECT_EQ(4, p.getChargeNumber()); + EXPECT_LE(5 * EeV, p.getEnergy()); + EXPECT_GE(100 * EeV, p.getEnergy()); + EXPECT_EQ(Vector3d(10, 0, 0) * Mpc, p.getPosition()); + + p = c.previous; + EXPECT_EQ(8, p.getMassNumber()); + EXPECT_EQ(4, p.getChargeNumber()); + EXPECT_LE(5 * EeV, p.getEnergy()); + EXPECT_GE(100 * EeV, p.getEnergy()); + EXPECT_EQ(Vector3d(10, 0, 0) * Mpc, p.getPosition()); + + p = c.current; + EXPECT_EQ(8, p.getMassNumber()); + EXPECT_EQ(4, p.getChargeNumber()); + EXPECT_LE(5 * EeV, p.getEnergy()); + EXPECT_GE(100 * EeV, p.getEnergy()); + EXPECT_EQ(Vector3d(10, 0, 0) * Mpc, p.getPosition()); } TEST(SourceList, simpleTest) { @@ -159,22 +175,23 @@ TEST(SourceList, simpleTest) { ref_ptr source = new Source; source->addProperty(new SourcePosition(Vector3d(10, 0, 0))); sourceList.addSource(source); - ParticleState p; - sourceList.prepare(p); - EXPECT_EQ(Vector3d(10, 0, 0), p.getPosition()); + + ref_ptr c = sourceList.getCandidate(); + + EXPECT_EQ(Vector3d(10, 0, 0), c->initial.getPosition()); + EXPECT_EQ(Vector3d(10, 0, 0), c->previous.getPosition()); + EXPECT_EQ(Vector3d(10, 0, 0), c->current.getPosition()); } TEST(SourceList, noSource) { // test if an error is thrown when source list empty SourceList sourceList; - ParticleState p; - EXPECT_THROW(sourceList.prepare(p), std::runtime_error); + EXPECT_THROW(sourceList.getCandidate(), std::runtime_error); } TEST(SourceList, luminosity) { // test if the sources are dialed according to their luminosities SourceList sourceList; - ParticleState p; ref_ptr source1 = new Source; source1->addProperty(new SourceEnergy(100)); @@ -186,12 +203,11 @@ TEST(SourceList, luminosity) { double meanE = 0; for (int i = 0; i < 1000; i++) { - sourceList.prepare(p); - meanE += p.getEnergy(); + ref_ptr c = sourceList.getCandidate(); + meanE += c->initial.getEnergy(); } meanE /= 1000; - EXPECT_NEAR(80, meanE, 2); - // this test can stochastically fail + EXPECT_NEAR(80, meanE, 2); // this test can stochastically fail } int main(int argc, char **argv) { diff --git a/test/xml/traj3d.txt b/test/xml/traj3d.txt deleted file mode 100644 index aa3bf7440..000000000 --- a/test/xml/traj3d.txt +++ /dev/null @@ -1,229 +0,0 @@ -#CRPropa - Output data file -#Format - Particle_Type Initial_Particle_Type Initial_Position[X,Y,Z](Mpc) Initial_Momentum[E,theta,phi](EeV) Time(Mpc) Position[X,Y,Z](Mpc) Momentum[E,theta,phi](EeV) -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1622 1.9313 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1622 1.9313 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.3498 2.0907 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3498 2.0907 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6067 1.9156 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6067 1.9156 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.9684 1.6679 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9684 1.6679 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.6814 1.5475 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6814 1.5475 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1102 1.9046 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1102 1.9046 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.3624 1.6402 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3624 1.6402 -12024 12024 -9.8620 -4.4750 2.8934 100.0000 0.5216 1.9093 10.0000 -9.8620 -4.4750 2.8934 100.0000 0.5216 1.9093 -26056 26056 10.1380 -4.4750 2.8934 100.0000 2.8036 1.8223 10.0001 10.1380 -4.4750 2.8934 100.0000 2.8036 1.8223 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.0710 1.5183 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0710 1.5183 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8910 1.6062 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8910 1.6062 -12024 12024 10.1380 -4.4750 2.8934 100.0000 2.7696 1.7901 10.0000 10.1380 -4.4750 2.8934 100.0000 2.7696 1.7901 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.7549 1.4615 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.7549 1.4615 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.3231 2.3721 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3231 2.3721 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7804 1.4389 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7804 1.4389 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4734 1.2998 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4734 1.2998 -26056 26056 -9.8620 -4.4750 2.8934 100.0000 0.5034 1.8415 10.0000 -9.8620 -4.4750 2.8934 100.0000 0.5034 1.8415 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8412 1.8481 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8412 1.8481 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.2623 1.7122 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2623 1.7122 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8862 1.8306 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8862 1.8306 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.9085 1.9239 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9085 1.9239 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.6828 1.5671 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.6828 1.5671 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4532 1.7549 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4532 1.7549 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1078 1.9195 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1078 1.9195 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.7209 2.2236 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7209 2.2236 -12024 12024 -9.8620 -4.4750 2.8934 100.0000 0.4901 1.7723 10.0001 -9.8620 -4.4750 2.8934 100.0000 0.4901 1.7723 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.2886 1.9300 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.2886 1.9300 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.9640 2.1873 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9640 2.1873 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.0325 1.8441 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.0325 1.8441 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1197 1.8078 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1197 1.8078 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.7088 1.9545 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7088 1.9545 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 3.0460 1.5867 10.0000 7.3068 -2.0813 -0.1961 100.0000 3.0460 1.5867 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6890 1.4244 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6890 1.4244 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4917 1.5184 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4917 1.5184 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7909 2.2111 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7909 2.2111 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.5947 1.7593 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5947 1.7593 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.9292 2.1155 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9292 2.1155 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8714 2.2720 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8714 2.2720 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.2346 1.7256 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2346 1.7256 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.9905 1.5820 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9905 1.5820 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.7461 1.4242 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.7461 1.4242 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.6477 1.5785 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.6477 1.5785 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.3251 1.8902 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3251 1.8902 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8475 1.8799 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8475 1.8799 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7257 2.0395 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7257 2.0395 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.0964 1.7469 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.0964 1.7469 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.1800 1.9056 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1800 1.9056 -12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.8979 1.6637 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.8979 1.6637 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.9833 1.4793 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9833 1.4793 -26056 26056 -9.8620 -4.4750 2.8934 100.0000 0.3819 1.7893 10.0000 -9.8620 -4.4750 2.8934 100.0000 0.3819 1.7893 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6571 2.3054 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6571 2.3054 -12024 12024 10.1380 -4.4750 2.8934 100.0000 2.7127 1.9121 10.0000 10.1380 -4.4750 2.8934 100.0000 2.7127 1.9121 -12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.7779 1.4658 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.7779 1.4658 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4184 1.5126 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4184 1.5126 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7484 2.2601 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7484 2.2601 -12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.9333 1.3521 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.9333 1.3521 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.9822 1.9035 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9822 1.9035 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.5028 1.5063 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5028 1.5063 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.9174 1.4319 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9174 1.4319 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.1085 1.7759 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1085 1.7759 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6990 2.3461 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6990 2.3461 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7126 1.2639 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7126 1.2639 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.7709 1.2410 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7709 1.2410 -12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.9862 1.4200 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.9862 1.4200 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1343 1.7591 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1343 1.7591 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.1179 1.8418 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1179 1.8418 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.9963 1.3867 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9963 1.3867 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.1709 1.5800 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1709 1.5800 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.1589 1.5374 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1589 1.5374 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.9760 1.7233 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.9760 1.7233 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4406 1.6710 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4406 1.6710 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.5028 1.3374 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5028 1.3374 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4313 2.3067 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4313 2.3067 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.7601 1.9234 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7601 1.9234 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.1637 1.5078 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1637 1.5078 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.0391 1.4285 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0391 1.4285 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.7434 2.1786 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7434 2.1786 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.6460 1.7627 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6460 1.7627 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1176 1.6915 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1176 1.6915 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.2298 2.1215 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2298 2.1215 -12024 12024 -9.8620 -4.4750 2.8934 100.0000 0.4300 1.6885 10.0001 -9.8620 -4.4750 2.8934 100.0000 0.4300 1.6885 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.2834 1.9576 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2834 1.9576 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.0322 2.0531 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0322 2.0531 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4939 1.9703 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4939 1.9703 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.3261 1.3594 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3261 1.3594 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4640 1.4945 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4640 1.4945 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.2941 1.4466 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2941 1.4466 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.6868 1.4838 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6868 1.4838 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.6515 1.5405 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.6515 1.5405 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.5002 2.0697 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5002 2.0697 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6285 1.5468 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6285 1.5468 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4595 1.5862 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4595 1.5862 -12024 12024 10.1380 -4.4750 2.8934 100.0000 2.7131 1.8505 10.0000 10.1380 -4.4750 2.8934 100.0000 2.7131 1.8505 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.9199 1.7673 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.9199 1.7673 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4006 1.4684 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4006 1.4684 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.2171 1.4576 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2171 1.4576 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.8653 1.6369 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.8653 1.6369 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.1531 2.1785 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1531 2.1785 -12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.9808 1.7639 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.9808 1.7639 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.1103 2.0645 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1103 2.0645 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.0751 1.8391 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.0751 1.8391 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.3217 2.0816 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3217 2.0816 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4091 2.3763 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4091 2.3763 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7875 1.3791 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7875 1.3791 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6738 1.4814 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6738 1.4814 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.8119 1.2897 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8119 1.2897 -26056 26056 10.1380 -4.4750 2.8934 100.0000 2.8407 1.8266 10.0000 10.1380 -4.4750 2.8934 100.0000 2.8407 1.8266 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8126 2.1891 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8126 2.1891 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7790 1.3571 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7790 1.3571 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.1580 2.0896 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1580 2.0896 -12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.6919 1.7055 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.6919 1.7055 -12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.8138 1.3639 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.8138 1.3639 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.0715 2.1640 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0715 2.1640 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7362 1.8350 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7362 1.8350 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 3.0751 1.5695 10.0000 7.3068 -2.0813 -0.1961 100.0000 3.0751 1.5695 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1261 2.1954 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1261 2.1954 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.1104 2.1131 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1104 2.1131 -12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.9804 1.5772 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.9804 1.5772 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1388 1.5700 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1388 1.5700 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.8569 1.5687 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.8569 1.5687 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7186 1.4636 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7186 1.4636 -26056 26056 -9.8620 -4.4750 2.8934 100.0000 0.4519 1.6904 10.0000 -9.8620 -4.4750 2.8934 100.0000 0.4519 1.6904 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.9332 2.2277 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9332 2.2277 -12024 12024 7.3068 -2.0813 -0.1961 100.0000 3.0948 1.5326 10.0000 7.3068 -2.0813 -0.1961 100.0000 3.0948 1.5326 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1828 1.7694 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1828 1.7694 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7646 1.8661 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7646 1.8661 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.9419 1.5557 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.9419 1.5557 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.1113 1.8929 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1113 1.8929 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.7035 2.4041 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7035 2.4041 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.1184 1.9202 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1184 1.9202 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.1359 1.4489 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1359 1.4489 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.7244 2.4670 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7244 2.4670 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.2744 1.7351 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2744 1.7351 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.6062 1.6856 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6062 1.6856 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8730 1.4908 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8730 1.4908 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.3786 1.5151 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3786 1.5151 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.3796 1.3764 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3796 1.3764 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4932 2.2932 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4932 2.2932 -12024 12024 7.3068 -2.0813 -0.1961 100.0000 3.0299 1.5399 10.0000 7.3068 -2.0813 -0.1961 100.0000 3.0299 1.5399 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.2265 1.8599 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2265 1.8599 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.0688 2.1296 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0688 2.1296 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.3935 1.5726 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3935 1.5726 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4801 1.9309 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4801 1.9309 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.0249 1.5108 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0249 1.5108 -26056 26056 -9.8620 -4.4750 2.8934 100.0000 0.3172 1.7619 10.0001 -9.8620 -4.4750 2.8934 100.0000 0.3172 1.7619 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4975 1.4686 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4975 1.4686 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.6060 1.8076 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6060 1.8076 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.8993 1.3121 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8993 1.3121 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.7251 2.0082 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7251 2.0082 -26056 26056 -9.8620 -4.4750 2.8934 100.0000 0.3982 1.8046 10.0000 -9.8620 -4.4750 2.8934 100.0000 0.3982 1.8046 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6992 1.3259 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6992 1.3259 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.6289 1.4780 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.6289 1.4780 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8970 2.3741 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8970 2.3741 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.1597 1.7826 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1597 1.7826 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 3.1025 1.4763 10.0000 7.3068 -2.0813 -0.1961 100.0000 3.1025 1.4763 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8596 1.9905 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8596 1.9905 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.1828 2.0690 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1828 2.0690 -12024 12024 -9.8620 -4.4750 2.8934 100.0000 0.3054 1.8699 10.0001 -9.8620 -4.4750 2.8934 100.0000 0.3054 1.8699 -12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.6415 1.4083 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.6415 1.4083 -12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.8935 1.6142 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.8935 1.6142 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.3750 2.1701 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3750 2.1701 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.2096 1.7363 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.2096 1.7363 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.9567 1.9238 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9567 1.9238 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.9467 1.3105 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.9467 1.3105 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4563 1.9619 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4563 1.9619 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.5715 2.2863 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5715 2.2863 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.5079 1.3717 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5079 1.3717 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.7627 1.8147 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7627 1.8147 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.2311 1.5927 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2311 1.5927 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8339 1.5338 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8339 1.5338 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.5967 2.4435 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5967 2.4435 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.0380 2.0417 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.0380 2.0417 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.5866 1.4745 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5866 1.4745 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.2761 2.0689 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2761 2.0689 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.6997 1.6826 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.6997 1.6826 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.0862 1.9539 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0862 1.9539 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.3795 1.3923 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3795 1.3923 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.1219 2.1920 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1219 2.1920 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.1979 1.6959 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1979 1.6959 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.1328 2.1604 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.1328 2.1604 -12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.8759 1.4573 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.8759 1.4573 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.0329 2.0965 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0329 2.0965 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8468 1.8410 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8468 1.8410 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.1690 1.7352 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1690 1.7352 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8398 2.0366 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8398 2.0366 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.3391 1.6946 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3391 1.6946 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.2954 2.0088 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2954 2.0088 -12024 12024 10.1380 -4.4750 2.8934 100.0000 2.8010 1.7879 10.0001 10.1380 -4.4750 2.8934 100.0000 2.8010 1.7879 -12024 12024 -9.8620 -4.4750 2.8934 100.0000 0.4505 1.9146 10.0001 -9.8620 -4.4750 2.8934 100.0000 0.4505 1.9146 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.0170 1.6330 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0170 1.6330 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.3878 2.3649 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3878 2.3649 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.8741 2.4261 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8741 2.4261 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6459 1.9383 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6459 1.9383 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8452 2.2063 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8452 2.2063 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.1460 1.8963 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1460 1.8963 -12024 12024 -9.8620 -4.4750 2.8934 100.0000 0.4398 1.7965 10.0001 -9.8620 -4.4750 2.8934 100.0000 0.4398 1.7965 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.9813 1.3381 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.9813 1.3381 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 1.1468 2.0255 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.1468 2.0255 -12024 12024 7.3068 -2.0813 -0.1961 100.0000 3.1160 1.6232 10.0000 7.3068 -2.0813 -0.1961 100.0000 3.1160 1.6232 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.6544 2.1914 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6544 2.1914 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.2064 1.4724 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.2064 1.4724 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.7113 1.7739 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.7113 1.7739 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 3.0522 1.4619 10.0000 7.3068 -2.0813 -0.1961 100.0000 3.0522 1.4619 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.6378 2.4308 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6378 2.4308 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.3422 2.3037 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.3422 2.3037 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4440 1.3151 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4440 1.3151 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6734 1.3403 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6734 1.3403 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8504 1.7907 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8504 1.7907 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4860 2.0177 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4860 2.0177 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.7156 1.3508 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.7156 1.3508 -12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.7979 1.6159 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.7979 1.6159 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.6821 2.0317 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6821 2.0317 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.5301 1.4448 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5301 1.4448 -12024 12024 -9.8620 -4.4750 2.8934 100.0000 0.4951 1.7900 10.0001 -9.8620 -4.4750 2.8934 100.0000 0.4951 1.7900 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4912 1.4909 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4912 1.4909 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.5935 1.2710 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.5935 1.2710 -12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.8576 1.7454 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.8576 1.7454 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.4314 1.6173 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4314 1.6173 -26056 26056 7.3068 -2.0813 -0.1961 100.0000 2.7439 1.7456 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.7439 1.7456 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 1.0122 1.8080 10.0000 -2.5823 -2.0359 0.9329 100.0000 1.0122 1.8080 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.6310 1.9796 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6310 1.9796 -12024 12024 7.3068 -2.0813 -0.1961 100.0000 2.9833 1.3801 10.0000 7.3068 -2.0813 -0.1961 100.0000 2.9833 1.3801 -12024 12024 -2.5823 -2.0359 0.9329 100.0000 0.8248 1.9495 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.8248 1.9495 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.4987 2.1784 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.4987 2.1784 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.0825 1.7856 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.0825 1.7856 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6585 1.6868 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6585 1.6868 -26056 26056 -2.5823 -2.0359 0.9329 100.0000 0.6040 1.8225 10.0000 -2.5823 -2.0359 0.9329 100.0000 0.6040 1.8225 diff --git a/test/xml/traj3d_noBfield.xml b/test/xml/traj3d_noBfield.xml index 32a382690..f655e5679 100644 --- a/test/xml/traj3d_noBfield.xml +++ b/test/xml/traj3d_noBfield.xml @@ -24,7 +24,7 @@ - + diff --git a/test/xml/traj3d_uniformBfield.xml b/test/xml/traj3d_uniformBfield.xml index f022c764f..f4e5088ac 100644 --- a/test/xml/traj3d_uniformBfield.xml +++ b/test/xml/traj3d_uniformBfield.xml @@ -1,4 +1,3 @@ - From 55a618476721c871b4a734d2e34c4adccd4c9031 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 6 Sep 2012 15:37:41 +0200 Subject: [PATCH 0190/1298] fix adiabatic energy loss --- src/module/Redshift.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index fda02e284..b411e1f24 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -13,15 +13,14 @@ SimpleRedshift::SimpleRedshift(Vector3d observer, double h) : void SimpleRedshift::process(Candidate *c) const { double d = c->current.getPosition().getDistanceTo(observer); double z = h * 1e5 / Mpc * d / c_light; - double dz = z - c->getRedshift(); + double dz = c->getRedshift() - z; - if (dz > 0) + if (dz < 0) return; // do nothing if the new redshift is higher c->setRedshift(z); - double E = c->current.getEnergy(); - c->current.setEnergy(E * (1 + dz) / (1 + z)); // using dE/dz=E/(1+z) + c->current.setEnergy(E * (1 - dz / (1 + z)));// using dE/dz = E/(1+z) } std::string SimpleRedshift::getDescription() const { @@ -44,7 +43,7 @@ Redshift::Redshift(double h, double m, double l) { void Redshift::process(Candidate *c) const { double z = c->getRedshift(); if (z == 0) - return; // nothing to do + return; // nothing to do, redshift can't get smaller // small step approximation: dz = H(z) / c * dr // an analytical form for the integral would be better @@ -54,7 +53,7 @@ void Redshift::process(Candidate *c) const { c->setRedshift(z - dz); double E = c->current.getEnergy(); - c->current.setEnergy(E * (1 - dz) / (1 + z)); // using dE/dz=E/(1+z) + c->current.setEnergy(E * (1 - dz / (1 + z))); // using dE/dz = E/(1+z) } } // namespace mpc From c1e4e3ea1df46c26749be18726b9ea51bae67eb2 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 7 Sep 2012 15:26:39 +0200 Subject: [PATCH 0191/1298] added redshift test script --- test/python/testRedshift.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 test/python/testRedshift.py diff --git a/test/python/testRedshift.py b/test/python/testRedshift.py new file mode 100644 index 000000000..b1370d7a6 --- /dev/null +++ b/test/python/testRedshift.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +from mpc import * +import numpy as np +import matplotlib.pyplot as plt + + + +redshift = Redshift() + +# Redshift - comoving distance relation +N = 100 +Z = np.logspace(-4, 2, N) +D1 = np.zeros(N) +for i in range(N): + D1[i] = redshift.getDistance(Z[i]) / Mpc + +H0 = redshift.getHubbleRate(0) +D2 = c_light * Z / H0 / Mpc + +plt.figure() +plt.plot(Z, D1, label='Numerical Integration') +plt.plot(Z, D2, 'r--', label='Small Redshift Approximation') +plt.legend(loc='upper left', frameon=0) +plt.xlabel('Redshift z') +plt.ylabel('Comoving Distance [Mpc]') +plt.loglog() +plt.grid() +plt.savefig('Redshift.png', bbox_inches='tight') +plt.show() + From 0062cc563969082d4842eb785d1de88fad644b59 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 7 Sep 2012 17:49:13 +0200 Subject: [PATCH 0192/1298] fixed and moved redshift calculation from SourceRedshift to Redshift module --- include/mpc/Source.h | 4 +- include/mpc/module/Redshift.h | 14 ++++++- src/Source.cpp | 33 +-------------- src/module/Redshift.cpp | 75 ++++++++++++++++++++++++++++------- 4 files changed, 76 insertions(+), 50 deletions(-) diff --git a/include/mpc/Source.h b/include/mpc/Source.h index 89bfce7bd..277c08178 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -212,12 +212,12 @@ class SourceEmissionCone: public SourceProperty { /** @class SourceRedshift - @brief Redshift at the time of emission for particles that travel rectalinearly towards the observer + @brief Single redshift at the time of emission */ class SourceRedshift: public SourceProperty { double z; public: - SourceRedshift(double distance, double h = 0.7, double omegaM = 0.3, double omegaL = 0.7); + SourceRedshift(double z); void prepare(Candidate &candidate) const; }; diff --git a/include/mpc/module/Redshift.h b/include/mpc/module/Redshift.h index 0fada03e7..54571b7ce 100644 --- a/include/mpc/module/Redshift.h +++ b/include/mpc/module/Redshift.h @@ -33,13 +33,25 @@ class SimpleRedshift : public Module { */ class Redshift : public Module { private: - double H0; // Hubble constant, H0 = h * 100 km/s/Mpc + double H0; // Hubble rate at z=0 in [1/s], H0 = h * 100 km/s/Mpc double omegaM; // density parameter double omegaL; // vacuum energy parameter + static const int n = 1000; + static const double zmin = 0.0001; + static const double zmax = 100; + + std::vector Z; // redshift + std::vector D; // comoving distance [m] + public: Redshift(double h = 0.7, double omegaM = 0.3, double omegaL = 0.7); + void init(); + double getRedshift(double distance) const; + double getHubbleRate(double redshift) const; + double getDistance(double redshift) const; void process(Candidate *candidate) const; + std::string getDescription() const; }; } // namespace mpc diff --git a/src/Source.cpp b/src/Source.cpp index 71018c8c2..aa462d329 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -241,38 +241,7 @@ void SourceEmissionCone::prepare(ParticleState &particle) const { particle.setDirection(random.randConeVector(direction, aperture)); } -SourceRedshift::SourceRedshift(double d, double h, double omegaM, - double omegaL) { - double H0 = h * 1e5 / Mpc; - - const int n = 1000; - double zMin = 0.0001; - double zMax = 100; - - std::vector Z; // redshift - std::vector D; // comoving distance [m] - std::vector H; // Hubble rate [1/s] - - Z.resize(n); - H.resize(n); - D.resize(n); - - Z[0] = 0; - H[0] = H0; - D[0] = 0; - - // Relation between comoving distance and redshift (see J.A. Peacock, Cosmological physics, p. 89 eq. 3.76) - // R0 dr = c / H(z) dz - // H(z) = H0 sqrt(omegaL + omegaM (1 + z)^3) - // Integration with midpoint rule. - for (int i = 1; i < n; i++) { - Z[i] = pow(10, zMin + (zMax - zMin) * i / (n - 1)); - H[i] = H0 * sqrt(omegaL + omegaM * pow(1 + Z[i], 3)); - D[i] = D[i - 1] - + c_light * (Z[i] - Z[i - 1]) * (1 / H[i - 1] + 1 / H[i]) / 2; - } - - z = interpolate(d, &D[0], &Z[0]); +SourceRedshift::SourceRedshift(double z) : z(z) { } void SourceRedshift::prepare(Candidate &candidate) const { diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index b411e1f24..6d3059ea2 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -20,7 +20,7 @@ void SimpleRedshift::process(Candidate *c) const { c->setRedshift(z); double E = c->current.getEnergy(); - c->current.setEnergy(E * (1 - dz / (1 + z)));// using dE/dz = E/(1+z) + c->current.setEnergy(E * (1 - dz / (1 + z))); // using dE/dz = E/(1+z) } std::string SimpleRedshift::getDescription() const { @@ -29,15 +29,52 @@ std::string SimpleRedshift::getDescription() const { return ss.str(); } -Redshift::Redshift(double h, double m, double l) { - H0 = h * 1e5 / Mpc; - omegaM = m; - omegaL = l; +Redshift::Redshift(double h, double m, double l) : + H0(h * 1e5 / Mpc), omegaM(m), omegaL(l) { + init(); +} + +void Redshift::init() { + Z.resize(n); + D.resize(n); + std::vector H(n); - std::stringstream ss; - ss << "Redshift for cosmological parameters: h = " << h << ", omegaL = " - << omegaL << ", omegaM = " << omegaM; - setDescription(ss.str()); + Z[0] = 0; + D[0] = 0; + H[0] = H0; + + // Relation between comoving distance and redshift (see J.A. Peacock, Cosmological physics, p. 89 eq. 3.76) + // R0 dr = c / H(z) dz + // Integration with midpoint rule: R0 dr = (c/H(z+dz) + c/H(z)) / 2 * dz + double dlz = log10(zmax) - log10(zmin); + double dz, A; + for (int i = 1; i < n; i++) { + Z[i] = zmin * pow(10, i * dlz / (n - 1)); // logarithmic even spacing + H[i] = getHubbleRate(Z[i]); + D[i] = D[i - 1] + + (Z[i] - Z[i - 1]) * c_light * (1 / H[i] + 1 / H[i - 1]) / 2; + } +} + +double Redshift::getHubbleRate(double z) const { + return H0 * sqrt(omegaL + omegaM * pow(1 + z, 3)); +} + +double Redshift::getRedshift(double d) const { + if (d < 0) + throw std::runtime_error("Redshift: d < 0"); + if (d > D[n - 1]) + throw std::runtime_error("Redshift: d > dmax"); + return interpolate(d, D, Z); +} + +double Redshift::getDistance(double z) const { + if (z < 0) + throw std::runtime_error("Redshift: z < 0"); + if (z > zmax) + throw std::runtime_error("Redshift: z > zmax"); + double d = interpolate(z, Z, D); + return d; } void Redshift::process(Candidate *c) const { @@ -45,15 +82,23 @@ void Redshift::process(Candidate *c) const { if (z == 0) return; // nothing to do, redshift can't get smaller - // small step approximation: dz = H(z) / c * dr - // an analytical form for the integral would be better - double H = H0 * sqrt(omegaL + omegaM * pow(1 + z, 3)); - double dz = H / c_light * c->getCurrentStep(); - dz = std::min(z, dz); // dz cannot be larger than z + // use small step approximation to calculate redshift change + // dz = H(z) / c * dr + // dE/dz = E/(1+z) + double dz = getHubbleRate(z) / c_light * c->getCurrentStep(); + // update candidate c->setRedshift(z - dz); double E = c->current.getEnergy(); - c->current.setEnergy(E * (1 - dz / (1 + z))); // using dE/dz = E/(1+z) + c->current.setEnergy(E * (1 - dz / (1 + z))); +} + +std::string Redshift::getDescription() const { + std::stringstream ss; + ss << "Redshift for cosmological parameters: "; + ss << "H0 = " << H0 * 1e3 / Mpc << " km/s/Mpc, "; + ss << "omegaL = " << omegaL << ", omegaM = " << omegaM; + return ss.str(); } } // namespace mpc From be6fecfe4d85df0e4d400b0909c4c46aad2d5875 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 7 Sep 2012 17:50:03 +0200 Subject: [PATCH 0193/1298] refactored interpolate to work on vectors and catch out of range queries --- include/mpc/Common.h | 8 ++-- include/mpc/module/NuclearDecay.h | 10 ++--- include/mpc/module/PhotoDisintegration.h | 2 +- src/Common.cpp | 32 ++++++++++----- src/module/ElectronPairProduction.cpp | 4 +- src/module/NuclearDecay.cpp | 4 +- src/module/PhotoDisintegration.cpp | 4 +- src/module/PhotoPionProduction.cpp | 8 ++-- test/testCore.cpp | 51 ++++++++++++++---------- test/testInteraction.cpp | 8 ++-- 10 files changed, 77 insertions(+), 54 deletions(-) diff --git a/include/mpc/Common.h b/include/mpc/Common.h index ac2cc3673..17560b697 100644 --- a/include/mpc/Common.h +++ b/include/mpc/Common.h @@ -2,6 +2,7 @@ #define COMMON_H_ #include +#include namespace mpc { @@ -19,11 +20,12 @@ inline int digit(const int &value, const int &d) { } // Perform linear interpolation -double interpolate(const double x, const double *xD, const double *yD); +double interpolate(double x, const std::vector &X, + const std::vector &Y); // Perform linear interpolation on equidistant tabulated data -double interpolateEquidistant(const double x, const double xLo, const double dx, - const double *yD); +double interpolateEquidistant(double x, double lo, double hi, + const std::vector &Y); } // namespace mpc diff --git a/include/mpc/module/NuclearDecay.h b/include/mpc/module/NuclearDecay.h index ede6a9f1e..bd3b25001 100644 --- a/include/mpc/module/NuclearDecay.h +++ b/include/mpc/module/NuclearDecay.h @@ -1,5 +1,5 @@ -#ifndef DECAY_H_ -#define DECAY_H_ +#ifndef MPC_DECAY_H_ +#define MPC_DECAY_H_ #include "mpc/module/StochasticInteraction.h" @@ -21,8 +21,8 @@ class NuclearDecay: public StochasticInteraction { std::vector > decayTable; // InteractionState.channel is (#beta- #beta+ #alpha #proton #neutron) // InteractionState.distance is the mean free path [m] - double tBeta[50]; // electron kinetic energy [J] in neutron decays - double cdfBeta[50]; // cumulative distribution function for the electron kinetic energy [J] in neutron decays + std::vector tBeta; // electron kinetic energy [J] in neutron decays + std::vector cdfBeta; // cumulative distribution function for the electron kinetic energy [J] in neutron decays public: NuclearDecay(bool electrons = false, bool neutrinos = false); @@ -35,4 +35,4 @@ class NuclearDecay: public StochasticInteraction { } // namespace mpc -#endif /* DECAY_H_ */ +#endif /* MPC_DECAY_H_ */ diff --git a/include/mpc/module/PhotoDisintegration.h b/include/mpc/module/PhotoDisintegration.h index 65390d75f..437e10174 100644 --- a/include/mpc/module/PhotoDisintegration.h +++ b/include/mpc/module/PhotoDisintegration.h @@ -20,7 +20,7 @@ class PhotoDisintegration: public StochasticInteraction { int photonField; struct PDMode { int channel; // number of emitted (n, p, H2, H3, He3, He4) - double rate[200]; // disintegration rate [1/m] + std::vector rate; // disintegration rate [1/m] }; std::vector > pdTable; // pdTable[Z * 31 + N] = vector diff --git a/src/Common.cpp b/src/Common.cpp index 62b599b32..9db943a95 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace mpc { @@ -52,19 +53,28 @@ std::string getDataPath(std::string filename) { return concat_path(dataPath, filename); } -double interpolate(const double x, const double *xD, const double *yD) { - size_t i = 0; - while (x > xD[i]) - i++; - i--; - return yD[i] + (x - xD[i]) * (yD[i + 1] - yD[i]) / (xD[i + 1] - xD[i]); +double interpolate(double x, const std::vector &X, + const std::vector &Y) { + std::vector::const_iterator it = std::upper_bound(X.begin(), X.end(), x); + if (it == X.begin()) + return Y.front(); + if (it == X.end()) + return Y.back(); + + size_t i = it - X.begin() - 1; + return Y[i] + (x - X[i]) * (Y[i + 1] - Y[i]) / (X[i + 1] - X[i]); } -double interpolateEquidistant(const double x, const double xLo, const double dx, - const double *yD) { - double p = (x - xLo) / dx; - size_t i = (size_t) floor(p); - return yD[i] + (p - i) * (yD[i + 1] - yD[i]); +double interpolateEquidistant(double x, double lo, double hi, const std::vector &Y) { + if (x <= lo) + return Y.front(); + if (x >= hi) + return Y.back(); + + double dx = (hi - lo) / (Y.size() - 1); + double p = (x - lo) / dx; + size_t i = floor(p); + return Y[i] + (p - i) * (Y[i + 1] - Y[i]); } } // namespace mpc diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 29bd78082..3a47c2e95 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -58,14 +58,14 @@ void ElectronPairProduction::process(Candidate *candidate) const { double A = candidate->current.getMassNumber(); double E = candidate->current.getEnergy(); double z = candidate->getRedshift(); - double EpA = E / A * (1 + z); + if (EpA < energy.front()) return; double rate; if (EpA < energy.back()) - rate = interpolate(EpA, &energy[0], &lossRate[0]); + rate = interpolate(EpA, energy, lossRate); else rate = lossRate.back() * pow(EpA / energy.back(), 0.4); // extrapolation diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index 1a374343f..346923806 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -40,8 +40,8 @@ NuclearDecay::NuclearDecay(bool electrons, bool neutrinos) { for (int i = 0; i < 50; i++) { double E = mass_electron + i / 50. * (Q - mass_electron); cdf += sqrt(pow(E, 2) - pow(mass_electron, 2)) * pow(Q - E, 2) * E; - cdfBeta[i] = cdf; - tBeta[i] = (E - mass_electron) * c_squared; + cdfBeta.push_back(cdf); + tBeta.push_back((E - mass_electron) * c_squared); } for (int i = 0; i < 50; i++) { cdfBeta[i] /= cdf; diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index bf72962cd..32528e1a7 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -54,7 +54,7 @@ void PhotoDisintegration::init(std::string filename) { double r = 0; for (size_t i = 0; i < 200; i++) { lineStream >> r; - pd.rate[i] = r / Mpc; // disintegration rate in [1/m] + pd.rate.push_back(r / Mpc); // disintegration rate in [1/m] } pdTable[Z * 31 + N].push_back(pd); @@ -86,7 +86,7 @@ bool PhotoDisintegration::setNextInteraction(Candidate *candidate, Random &random = Random::instance(); interaction.distance = std::numeric_limits::max(); for (size_t i = 0; i < pdModes.size(); i++) { - double rate = interpolateEquidistant(lg, 6., 8./200., pdModes[i].rate); + double rate = interpolateEquidistant(lg, 6, 14, pdModes[i].rate); double d = -log(random.rand()) / rate; if (d > interaction.distance) continue; diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 80382171a..4297340d3 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -72,16 +72,16 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, interaction.distance = std::numeric_limits::max(); Random &random = Random::instance(); if (Z > 0) { - double rate = interpolate(EpA, &energy[0], &pRate[0]) * Z; - if (rate != 0) { + double rate = interpolate(EpA, energy, pRate) * Z; + if (rate > 0) { interaction.distance = -log(random.rand()) / rate; interaction.channel = 1; } } // check for interaction on neutrons if (N > 0) { - double rate = interpolate(EpA, &energy[0], &nRate[0]) * N; - if (rate != 0) { + double rate = interpolate(EpA, energy, nRate) * N; + if (rate > 0) { double d = -log(random.rand()) / rate; if (d < interaction.distance) { interaction.distance = -log(random.rand()) / rate; diff --git a/test/testCore.cpp b/test/testCore.cpp index 86ac3cce2..5595227b4 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -1,3 +1,10 @@ +/** Unit test for core features of MPC + Candidate + ParticleState + Random + Common functions + */ + #include "mpc/Candidate.h" #include "mpc/Random.h" @@ -141,38 +148,42 @@ TEST(common, digit) { } TEST(common, interpolate) { - double xD[100]; - double yD[100]; + std::vector xD(100), yD(100); for (int i = 0; i < 100; i++) { - xD[i] = 1 + i * 0.02; + xD[i] = 1 + i * 2. / 99.; yD[i] = pow(xD[i], 2); } - double yInt = interpolate(1.5001, xD, yD); - EXPECT_NEAR(pow(1.5001, 2), yInt, 1e-4); -} -TEST(common, interpolateVector) { - std::vector xD, yD; - xD.resize(100); - yD.resize(100); - for (int i = 0; i < 100; i++) { - xD[i] = 1 + i * 0.02; - yD[i] = pow(xD[i], 2); - } - double yInt = interpolate(1.5001, &xD[0], &yD[0]); - EXPECT_NEAR(pow(1.5001, 2), yInt, 1e-4); + // interpolated value should be close to computed + double y = interpolate(1.5001, xD, yD); + EXPECT_NEAR(pow(1.5001, 2), y, 1e-4); + + // value out of range, return lower bound + EXPECT_EQ(1, interpolate(0.9, xD, yD)); + + // value out of range, return lower bound + EXPECT_EQ(9, interpolate(3.1, xD, yD)); } TEST(common, interpolateEquidistant) { - double yD[100]; + std::vector yD(100); for (int i = 0; i < 100; i++) { - yD[i] = pow(1 + i * 0.02, 2); + yD[i] = pow(1 + i * 2. / 99., 2); } - double yInt = interpolateEquidistant(1.5001, 1, 0.02, yD); - EXPECT_NEAR(pow(1.5001, 2), yInt, 1e-4); + + // interpolated value should be close to computed + double y = interpolateEquidistant(1.5001, 1, 3, yD); + EXPECT_NEAR(pow(1.5001, 2), y, 1e-4); + + // value out of range, return lower bound + EXPECT_EQ(1, interpolateEquidistant(0.9, 1, 3, yD)); + + // value out of range, return lower bound + EXPECT_EQ(9, interpolateEquidistant(3.1, 1, 3, yD)); } TEST(NucleusId, crpropaScheme) { + // test conversion to and from the CRPropa2 naming scheme EXPECT_EQ(getNucleusId(56, 26), convertFromCRPropaId(26056)); EXPECT_EQ(26056, convertToCRPropaId(getNucleusId(56, 26))); } diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index b28ca0e10..d34b41cd0 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -425,7 +425,7 @@ TEST(SimpleRedshift, test) { redshift.process(&c); EXPECT_EQ(0, c.getRedshift()); - EXPECT_EQ(97.6, c.current.getEnergy() / EeV); + EXPECT_GT(100, c.current.getEnergy() / EeV); } TEST(Redshift, test) { @@ -434,11 +434,11 @@ TEST(Redshift, test) { Candidate c; c.setRedshift(0.024); // roughly corresponds to 100 Mpc c.current.setEnergy(100 * EeV); - c.current.setPosition(Vector3d(0.)); + c.setCurrentStep(100 * Mpc); redshift.process(&c); - EXPECT_LT(c.getRedshift(), 1); - EXPECT_LT(c.current.getEnergy() / EeV, 100); + EXPECT_GT(0.024, c.getRedshift()); + EXPECT_GT(100, c.current.getEnergy() / EeV); } int main(int argc, char **argv) { From cb5215788dfec59cac5f4ae5e4fa10a9f38e4d30 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sun, 9 Sep 2012 12:03:06 +0200 Subject: [PATCH 0194/1298] add MinimumRedshift module --- include/mpc/module/BreakCondition.h | 29 ++++++++++++++++++---- src/module/BreakCondition.cpp | 38 +++++++++++++++++++++++------ test/testBreakCondition.cpp | 32 ++++++++++++++++-------- 3 files changed, 76 insertions(+), 23 deletions(-) diff --git a/include/mpc/module/BreakCondition.h b/include/mpc/module/BreakCondition.h index 8e75ca18c..3ddbadd3b 100644 --- a/include/mpc/module/BreakCondition.h +++ b/include/mpc/module/BreakCondition.h @@ -7,7 +7,7 @@ namespace mpc { /** @class MaximumTrajectoryLength - @brief Stops propagation after a maximum trajectory length. + @brief Deactivates the candidate beyond a maximum trajectory length This modules deactivates the candidate at a given maximum trajectory length. In that case the property ("Deactivated", module::description) is set. @@ -16,32 +16,51 @@ namespace mpc { class MaximumTrajectoryLength: public Module { private: double maxLength; - void updateDescription(); public: MaximumTrajectoryLength(double length = 0); void setMaximumTrajectoryLength(double length); double getMaximumTrajectoryLength() const; void process(Candidate *candidate) const; + std::string getDescription() const; }; /** @class MinimumEnergy - @brief Stops propagation if energy drops under the set minimum energy. + @brief Deactivates the candidate below a minimum energy - This modules deactivates the candidate below a give minimum energy. + This modules deactivates the candidate below a given minimum energy. In that case the property ("Deactivated", module::description) is set. */ class MinimumEnergy: public Module { private: double minEnergy; - void updateDescription(); public: MinimumEnergy(double minEnergy = 0); void setMinimumEnergy(double energy); double getMinimumEnergy() const; void process(Candidate *candidate) const; + std::string getDescription() const; +}; + +/** + @class MinimumRedshift + @brief Deactivates the candidate below a minimum redshift + + This modules deactivates the candidate below a given minimum redshift. + In that case the property ("Deactivated", module::description) is set. + */ +class MinimumRedshift: public Module { +private: + double zmin; + +public: + MinimumRedshift(double zmin = 0); + void setMinimumRedshift(double z); + double getMinimumRedshift(); + void process(Candidate *candidate) const; + std::string getDescription() const; }; } // namespace mpc diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp index ca059d432..b67efdba4 100644 --- a/src/module/BreakCondition.cpp +++ b/src/module/BreakCondition.cpp @@ -6,12 +6,10 @@ namespace mpc { MaximumTrajectoryLength::MaximumTrajectoryLength(double maxLength) { this->maxLength = maxLength; - updateDescription(); } void MaximumTrajectoryLength::setMaximumTrajectoryLength(double length) { maxLength = length; - updateDescription(); } double MaximumTrajectoryLength::getMaximumTrajectoryLength() const { @@ -28,20 +26,18 @@ void MaximumTrajectoryLength::process(Candidate *c) const { } } -void MaximumTrajectoryLength::updateDescription() { +std::string MaximumTrajectoryLength::getDescription() const { std::stringstream s; s << "Maximum trajectory length: " << maxLength / Mpc << " Mpc"; - setDescription(s.str()); + return s.str(); } MinimumEnergy::MinimumEnergy(double minEnergy) { this->minEnergy = minEnergy; - updateDescription(); } void MinimumEnergy::setMinimumEnergy(double energy) { minEnergy = energy; - updateDescription(); } double MinimumEnergy::getMinimumEnergy() const { @@ -55,10 +51,36 @@ void MinimumEnergy::process(Candidate *c) const { } } -void MinimumEnergy::updateDescription() { +std::string MinimumEnergy::getDescription() const { std::stringstream s; s << "Minimum energy: " << minEnergy / EeV << " EeV"; - setDescription(s.str()); + return s.str(); +} + +MinimumRedshift::MinimumRedshift(double z) : + zmin(z) { +} + +void MinimumRedshift::setMinimumRedshift(double z) { + zmin = z; +} + +double MinimumRedshift::getMinimumRedshift() { + return zmin; +} + +void MinimumRedshift::process(Candidate* c) const { + double z = c->getRedshift(); + if (z <= zmin) { + c->setActive(false); + c->setProperty("Deactivated", getDescription()); + } +} + +std::string MinimumRedshift::getDescription() const { + std::stringstream s; + s << "Minimum redshift: " << zmin; + return s.str(); } } // namespace mpc diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index bb9d1f3d1..05f9f0f1a 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -1,3 +1,5 @@ +/** Unit tests for break condition and observer modules */ + #include "mpc/module/BreakCondition.h" #include "mpc/module/Boundary.h" #include "mpc/module/Observer.h" @@ -7,36 +9,46 @@ namespace mpc { -TEST(MinimumEnergy, above) { +TEST(MinimumEnergy, test) { MinimumEnergy minEnergy(5); Candidate c; + c.current.setEnergy(5.1); minEnergy.process(&c); EXPECT_TRUE(c.isActive()); -} -TEST(MinimumEnergy, below) { - MinimumEnergy minEnergy(5); - Candidate c; c.current.setEnergy(4.9); minEnergy.process(&c); EXPECT_FALSE(c.isActive()); + EXPECT_TRUE(c.hasProperty("Deactivated")); } -TEST(MaximumTrajectoryLength, above) { +TEST(MaximumTrajectoryLength, test) { MaximumTrajectoryLength maxLength(10); Candidate c; + c.setTrajectoryLength(9.9); maxLength.process(&c); EXPECT_TRUE(c.isActive()); -} -TEST(MaximumTrajectoryLength, below) { - MaximumTrajectoryLength maxLength(10); - Candidate c; c.setTrajectoryLength(10.1); maxLength.process(&c); EXPECT_FALSE(c.isActive()); + EXPECT_TRUE(c.hasProperty("Deactivated")); +} + +TEST(MinimumRedshift, test) { + MinimumRedshift minZ; // default minimum redshift of 0 + Candidate c; + + c.setRedshift(0.1); + minZ.process(&c); + EXPECT_TRUE(c.isActive()); + + c.setRedshift(0); + minZ.process(&c); + EXPECT_FALSE(c.isActive()); + EXPECT_TRUE(c.hasProperty("Deactivated")); } TEST(SmallObserverSphere, outside) { From 7b4f14ccf431a2921bdb6063ced9262a5b5634c8 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 12 Sep 2012 13:21:05 +0200 Subject: [PATCH 0195/1298] add SourceUniformRedshift improve module descriptions --- include/mpc/ModuleList.h | 2 ++ include/mpc/Source.h | 13 ++++++++++++- include/mpc/module/Output.h | 3 +-- src/ModuleList.cpp | 11 +++++++++++ src/Source.cpp | 12 +++++++++++- src/module/DeflectionCK.cpp | 11 ++++++----- src/module/ElectronPairProduction.cpp | 6 +++--- src/module/Output.cpp | 28 +++++++++++++++++++-------- src/module/PhotoDisintegration.cpp | 4 ++-- src/module/PhotoPionProduction.cpp | 4 ++-- test/testCore.cpp | 2 +- 11 files changed, 71 insertions(+), 25 deletions(-) diff --git a/include/mpc/ModuleList.h b/include/mpc/ModuleList.h index 8e2327f50..41c203a78 100644 --- a/include/mpc/ModuleList.h +++ b/include/mpc/ModuleList.h @@ -32,6 +32,8 @@ class ModuleList: public Referenced { module_list_t &getModules(); const module_list_t &getModules() const; + void showModules() const; + private: module_list_t modules; bool showProgress; diff --git a/include/mpc/Source.h b/include/mpc/Source.h index 277c08178..38d1926cd 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -212,7 +212,7 @@ class SourceEmissionCone: public SourceProperty { /** @class SourceRedshift - @brief Single redshift at the time of emission + @brief Discrete redshift (time of emission) */ class SourceRedshift: public SourceProperty { double z; @@ -221,6 +221,17 @@ class SourceRedshift: public SourceProperty { void prepare(Candidate &candidate) const; }; +/** + @class SourceUniformRedshift + @brief Uniform redshift distribution (time of emission) + */ +class SourceUniformRedshift: public SourceProperty { + double zmin, zmax; +public: + SourceUniformRedshift(double zmin, double zmax); + void prepare(Candidate &candidate) const; +}; + }// namespace mpc #endif /* MPC_SOURCE_H */ diff --git a/include/mpc/module/Output.h b/include/mpc/module/Output.h index 7ad030c83..8a31c67ad 100644 --- a/include/mpc/module/Output.h +++ b/include/mpc/module/Output.h @@ -37,7 +37,7 @@ class ConditionalOutput: public Module { std::string propertyName; bool removeProperty; public: - ConditionalOutput(std::string filename, std::string propName); + ConditionalOutput(std::string filename, std::string propName = "Detected"); ~ConditionalOutput(); void setRemoveProperty(bool removeProperty); void process(Candidate *candidate) const; @@ -67,7 +67,6 @@ class CRPropa2TrajectoryOutput: public Module { void process(Candidate *candidate) const; }; - } // namespace mpc #endif /* OUTPUT_H_ */ diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index c0292a2c9..eaa5fd87e 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -93,6 +93,17 @@ const ModuleList::module_list_t &ModuleList::getModules() const { return modules; } +void ModuleList::showModules() const { + mpc::ModuleList::module_list_t::const_iterator iEntry; + + iEntry = getModules().begin(); + while (iEntry != getModules().end()) { + const mpc::ref_ptr &entry = *iEntry; + iEntry++; + std::cout << " " << entry->getDescription() << "\n"; + } +} + } // namespace mpc std::ostream &operator<<(std::ostream &out, const mpc::ModuleList &list) { diff --git a/src/Source.cpp b/src/Source.cpp index aa462d329..1ab2df348 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -241,11 +241,21 @@ void SourceEmissionCone::prepare(ParticleState &particle) const { particle.setDirection(random.randConeVector(direction, aperture)); } -SourceRedshift::SourceRedshift(double z) : z(z) { +SourceRedshift::SourceRedshift(double z) : + z(z) { } void SourceRedshift::prepare(Candidate &candidate) const { candidate.setRedshift(z); } +SourceUniformRedshift::SourceUniformRedshift(double zmin, double zmax) : + zmin(zmin), zmax(zmax) { +} + +void SourceUniformRedshift::prepare(Candidate &candidate) const { + double z = Random::instance().randUniform(zmin, zmax); + candidate.setRedshift(z); +} + } // namespace mpc diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index b526dbb25..a9a3e9cdb 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -46,11 +46,12 @@ DeflectionCK::DeflectionCK(ref_ptr field, double tolerance, } std::string DeflectionCK::getDescription() const { - std::stringstream sstr; - sstr - << "Propagation in magnetic fields using the Cash-Karp method. Tolerance: " - << tolerance << ", Minimum Step: " << minStep / kpc << " kpc"; - return sstr.str(); + std::stringstream s; + s << "Propagation in magnetic fields using the Cash-Karp method."; + s << " Tolerance: " << tolerance; + s << ", Minimum Step: " << minStep / kpc << " kpc"; + s << ", Maximum Step: " << maxStep / kpc << " kpc"; + return s.str(); } void DeflectionCK::process(Candidate *candidate) const { diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 3a47c2e95..a0df37ffe 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -14,15 +14,15 @@ void ElectronPairProduction::init(int photonField) { this->photonField = photonField; switch (photonField) { case CMB: - setDescription("ElectronPairProduction:CMB"); + setDescription("ElectronPairProduction: CMB"); init(getDataPath("ElectronPairProduction/cmb.txt")); break; case IRB: - setDescription("ElectronPairProduction:IRB"); + setDescription("ElectronPairProduction: IRB"); init(getDataPath("ElectronPairProduction/ir.txt")); break; case CMB_IRB: - setDescription("ElectronPairProduction:CMB_IRB"); + setDescription("ElectronPairProduction: CMB and IRB"); init(getDataPath("ElectronPairProduction/cmbir.txt")); break; default: diff --git a/src/module/Output.cpp b/src/module/Output.cpp index f0c9181ed..81a3cc4fe 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -11,8 +11,11 @@ namespace mpc { TrajectoryOutput::TrajectoryOutput(std::string name) { setDescription("Trajectory output"); outfile.open(name.c_str()); - outfile - << "# Age[Mpc] PDG_Code Energy[EeV] Position(X,Y,Z)[Mpc] Direction(X,Y,Z)\n"; + outfile << "# Age[Mpc]\t"; + outfile << "PDG_Code\t"; + outfile << "Energy[EeV]\t"; + outfile << "Position(X,Y,Z)[Mpc]\t"; + outfile << "Direction(X,Y,Z)\n"; } TrajectoryOutput::~TrajectoryOutput() { @@ -39,12 +42,20 @@ void TrajectoryOutput::process(Candidate *c) const { ConditionalOutput::ConditionalOutput(std::string filename, std::string propName) { - setDescription("ConditionalOutput, condition: " + propName); + setDescription("Conditional output, condition: '" + propName + "'"); removeProperty = false; propertyName = propName; outfile.open(filename.c_str()); - outfile - << "# PDG_Code Energy[EeV] Position(X,Y,Z)[Mpc] Direction(Phi,Theta) Age[Mpc] Initial_PDG_Code Initial_Energy[EeV] Initial_Position(X,Y,Z)[Mpc] Initial_Direction(Phi,Theta)\n"; + outfile << "# PDG_Code\t"; + outfile << "Energy[EeV]\t"; + outfile << "Position(X,Y,Z)[Mpc]\t"; + outfile << "Direction(Phi,Theta)\t"; + outfile << "Age[Mpc]\t"; + outfile << "Redshift\t"; + outfile << "Initial_PDG_Code\t"; + outfile << "Initial_Energy[EeV]\t"; + outfile << "Initial_Position(X,Y,Z)[Mpc]\t"; + outfile << "Initial_Direction(Phi,Theta)\n"; } ConditionalOutput::~ConditionalOutput() { @@ -68,6 +79,7 @@ void ConditionalOutput::process(Candidate *c) const { p += sprintf(buffer + p, "%7.4f\t%7.4f\t", dir.getPhi(), dir.getTheta()); p += sprintf(buffer + p, "%9.4f\t", c->getTrajectoryLength() / Mpc); + p += sprintf(buffer + p, "%7.4f\t", c->getRedshift()); p += sprintf(buffer + p, "%10i\t", c->initial.getId()); p += sprintf(buffer + p, "%8.4f\t", c->initial.getEnergy() / EeV); const Vector3d &ipos = c->initial.getPosition() / Mpc; @@ -91,9 +103,9 @@ void ConditionalOutput::process(Candidate *c) const { CRPropa2EventOutput::CRPropa2EventOutput(std::string filename) { setDescription("Event output in CRPropa2 format"); outfile.open(filename.c_str()); - outfile << "#CRPropa - Output data file" << std::endl - << "#Format - Particle_Type Initial_Particle_Type Initial_Position[X,Y,Z](Mpc) Initial_Momentum[E,theta,phi](EeV) Time(Mpc) Position[X,Y,Z](Mpc) Momentum[E,theta,phi](EeV)" - << std::endl; + outfile << "#CRPropa - Output data file\n"; + outfile + << "#Format - Particle_Type Initial_Particle_Type Initial_Position[X,Y,Z](Mpc) Initial_Momentum[E,theta,phi](EeV) Time(Mpc) Position[X,Y,Z](Mpc) Momentum[E,theta,phi](EeV)\n"; } CRPropa2EventOutput::~CRPropa2EventOutput() { diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 32528e1a7..780f9b2bc 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -16,11 +16,11 @@ void PhotoDisintegration::init(int photonField) { this->photonField = photonField; switch (photonField) { case CMB: - setDescription("PhotoDisintegration:CMB"); + setDescription("PhotoDisintegration: CMB"); init(getDataPath("PhotoDisintegration/PDtable_CMB.txt")); break; case IRB: - setDescription("PhotoDisintegration:IRB"); + setDescription("PhotoDisintegration: IRB"); init(getDataPath("PhotoDisintegration/PDtable_IRB.txt")); break; default: diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 4297340d3..ae45d9fa0 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -19,11 +19,11 @@ void PhotoPionProduction::init(int photonField) { this->photonField = photonField; switch (photonField) { case CMB: - setDescription("PhotoPionProduction:CMB"); + setDescription("PhotoPionProduction: CMB"); init(getDataPath("PhotoPionProduction/PPtable_CMB.txt")); break; case IRB: - setDescription("PhotoPionProduction:IRB"); + setDescription("PhotoPionProduction: IRB"); init(getDataPath("PhotoPionProduction/PPtable_IRB.txt")); break; default: diff --git a/test/testCore.cpp b/test/testCore.cpp index 5595227b4..ee21c1163 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -1,4 +1,4 @@ -/** Unit test for core features of MPC +/** Unit tests for core features of MPC Candidate ParticleState Random From 44c195fa61c9823cd6fef64b62630b2ad0630203 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 14 Sep 2012 12:44:08 +0200 Subject: [PATCH 0196/1298] updated photopion production approximation for nuclei according to CRPropa2 (paper) --- src/module/PhotoPionProduction.cpp | 53 ++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index ae45d9fa0..1376f80bf 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -72,21 +72,39 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, interaction.distance = std::numeric_limits::max(); Random &random = Random::instance(); if (Z > 0) { - double rate = interpolate(EpA, energy, pRate) * Z; - if (rate > 0) { - interaction.distance = -log(random.rand()) / rate; - interaction.channel = 1; + double rate = interpolate(EpA, energy, pRate); + if (rate <= 0) + break; + + if (A > 1) { + rate *= 0.85; + if (A < 8) + rate *= pow(Z, 2. / 3.); + if (A >= 8) + rate *= Z; } + + interaction.distance = -log(random.rand()) / rate; + interaction.channel = 1; } // check for interaction on neutrons if (N > 0) { - double rate = interpolate(EpA, energy, nRate) * N; - if (rate > 0) { - double d = -log(random.rand()) / rate; - if (d < interaction.distance) { - interaction.distance = -log(random.rand()) / rate; - interaction.channel = 0; - } + double rate = interpolate(EpA, energy, nRate); + if (rate <= 0) + break; + + if (A > 1) { + rate *= 0.85; + if (A < 8) + rate *= pow(N, 2. / 3.); + if (A >= 8) + rate *= N; + } + + double d = -log(random.rand()) / rate; + if (d < interaction.distance) { + interaction.distance = -log(random.rand()) / rate; + interaction.channel = 0; } } @@ -156,15 +174,16 @@ void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { int particleList[2000]; // particle id list int nParticles; // number of outgoing particles double redshift = candidate->getRedshift(); + int background; // Photon background: 1 for CMB, 2 for Kneiske IRB - switch (photonField) { - case CMB: + if (photonField == CMB) background = 1; - break; - case IRB: + else if (photonField == IRB) background = 2; - break; - } + else + throw std::runtime_error( + "SophiaPhotoPionProduction: Only CMB an IRB provided"); + double maxRedshift = 100; // IR photon density is zero above this redshift int dummy1; double dummy2[2]; From 4a885373f5ed60f9f30596422c860f2e3160062b Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 17 Sep 2012 11:58:36 +0200 Subject: [PATCH 0197/1298] fix limit step size bug with observers --- src/module/Observer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp index 1b09a8e67..e830b0d94 100644 --- a/src/module/Observer.cpp +++ b/src/module/Observer.cpp @@ -20,7 +20,7 @@ void SmallObserverSphere::process(Candidate *c) const { c->setActive(false); } } - c->limitNextStep((d - radius)); + c->limitNextStep(fabs(d - radius)); } void SmallObserverSphere::updateDescription() { @@ -47,7 +47,7 @@ void LargeObserverSphere::process(Candidate *c) const { c->setActive(false); } } - c->limitNextStep((radius - d)); + c->limitNextStep(fabs(radius - d)); } void LargeObserverSphere::updateDescription() { From f42284f7395875b2d4dfdbf740e44327910157ed Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 17 Sep 2012 12:27:12 +0200 Subject: [PATCH 0198/1298] fix f2bfs in PhotoPionProduction --- src/module/PhotoPionProduction.cpp | 51 ++++++++++++++---------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 1376f80bf..0ddcea794 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -68,43 +68,40 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, return false; // find interaction with minimum random distance - // check for interaction on protons interaction.distance = std::numeric_limits::max(); Random &random = Random::instance(); + + // check for interaction on protons if (Z > 0) { double rate = interpolate(EpA, energy, pRate); - if (rate <= 0) - break; - - if (A > 1) { - rate *= 0.85; - if (A < 8) - rate *= pow(Z, 2. / 3.); - if (A >= 8) - rate *= Z; + if (rate > 0) { + if (A > 1) { + if (A < 8) + rate *= 0.85 * pow(Z, 2. / 3.); + if (A >= 8) + rate *= 0.85 * Z; + } + interaction.distance = -log(random.rand()) / rate; + interaction.channel = 1; } - - interaction.distance = -log(random.rand()) / rate; - interaction.channel = 1; } + // check for interaction on neutrons if (N > 0) { double rate = interpolate(EpA, energy, nRate); - if (rate <= 0) - break; - - if (A > 1) { - rate *= 0.85; - if (A < 8) - rate *= pow(N, 2. / 3.); - if (A >= 8) - rate *= N; - } + if (rate > 0) { + if (A > 1) { + if (A < 8) + rate *= 0.85 * pow(N, 2. / 3.); + if (A >= 8) + rate *= 0.85 * N; + } - double d = -log(random.rand()) / rate; - if (d < interaction.distance) { - interaction.distance = -log(random.rand()) / rate; - interaction.channel = 0; + double d = -log(random.rand()) / rate; + if (d < interaction.distance) { + interaction.distance = -log(random.rand()) / rate; + interaction.channel = 0; + } } } From 317f53fb25eb9a8690cb19184eeca269b0181c8b Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 17 Sep 2012 15:11:52 +0200 Subject: [PATCH 0199/1298] implement overall photon background scaling capability add data, script and implementation for the Kneiske IRB scaling factor --- README | 15 +++++++++++---- include/mpc/Common.h | 15 ++++++++++----- src/Common.cpp | 18 ++++++++++++++++-- src/module/ElectronPairProduction.cpp | 3 ++- src/module/NuclearDecay.cpp | 4 ++-- src/module/PhotoDisintegration.cpp | 6 +++--- src/module/PhotoPionProduction.cpp | 6 +++--- 7 files changed, 47 insertions(+), 20 deletions(-) diff --git a/README b/README index b6d3cf1f8..4f0d9184f 100644 --- a/README +++ b/README @@ -1,18 +1,25 @@ -Installation from source +Install from source ------------------------ MPC is configured using CMAKE - for more information see www.cmake.org 1) $cd build 2) $cmake .. (or $ccmake ..) 3) $make 4) $make test (to run all unit tests) -5) Set the data path MPC_DATA_PATH=[path to mpc/data] +5) Set the data path + export MPC_DATA_PATH=[path to mpc/data] 6) Retrieve additional data files from https://forge.physik.rwth-aachen.de/projects/mpc/files - The photo-disintegration tables PDtable_XXX.txt have to be copied to mpc/data/PhotoDisintegration - + The photo-disintegration tables PDtable_XXX.txt have to be copied to mpc/data/PhotoDisintegration + Notes for Intel Compiler: -DCMAKE_SHARED_LINKER_FLAGS="-lifcore" -DCMAKE_Fortran_COMPILER=ifort +Install with Python bindings +---------------------------- +To use mpc via python the CMAKE flag ENABLEPYTHON needs to be set to True. +Additionally the path to mpc.py needs to be added to PYTHONPATH + + Dependencies ------------ Required: diff --git a/include/mpc/Common.h b/include/mpc/Common.h index 17560b697..a782c0e1b 100644 --- a/include/mpc/Common.h +++ b/include/mpc/Common.h @@ -11,21 +11,26 @@ enum PhotonField { CMB, IRB, CMB_IRB }; +// Returns overall photon field scaling factor at redshift z +double photonFieldScaling(int photonField, double z); + // Returns the full path to a mpc data file std::string getDataPath(std::string filename); // Returns a certain digit from a given integer -inline int digit(const int &value, const int &d) { +inline int digit(const int& value, const int& d) { return (value % (d * 10)) / d; } -// Perform linear interpolation -double interpolate(double x, const std::vector &X, - const std::vector &Y); +// Perform linear interpolation on a set of n tabulated data points X[0 .. n-1] -> Y[0 .. n-1] +// Returns Y[0] if x < X[0] and Y[n-1] if x > X[n-1] +double interpolate(double x, const std::vector& X, + const std::vector& Y); // Perform linear interpolation on equidistant tabulated data +// Returns Y[0] if x < lo and Y[n-1] if x > hi double interpolateEquidistant(double x, double lo, double hi, - const std::vector &Y); + const std::vector& Y); } // namespace mpc diff --git a/src/Common.cpp b/src/Common.cpp index 9db943a95..8b568bf69 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -11,6 +11,18 @@ namespace mpc { +// Overall redshift scaling of the Kneiske IRB (see data/PhotonField/KneiskeIRB.py and Kneiske et al. 2004, astro-ph/0309141) +double a[9] = { 0, 0.2, 0.4, 0.6, 1, 2, 3, 4, 5 }; +static std::vector zKneiske(a, a + sizeof(a) / sizeof(double)); +double b[9] = { 1, 1.6937, 2.5885, 3.6178, 5.1980, 7.3871, 8.5471, 7.8605, 0 }; +static std::vector sKneiske(b, b + sizeof(b) / sizeof(double)); + +double photonFieldScaling(int photonField, double z) { + if (photonField == IRB) + return interpolate(z, zKneiske, sKneiske); + return pow(z + 1, 3); // CMB-like scaling +} + std::string getDataPath(std::string filename) { static std::string dataPath; if (dataPath.size()) @@ -55,7 +67,8 @@ std::string getDataPath(std::string filename) { double interpolate(double x, const std::vector &X, const std::vector &Y) { - std::vector::const_iterator it = std::upper_bound(X.begin(), X.end(), x); + std::vector::const_iterator it = std::upper_bound(X.begin(), + X.end(), x); if (it == X.begin()) return Y.front(); if (it == X.end()) @@ -65,7 +78,8 @@ double interpolate(double x, const std::vector &X, return Y[i] + (x - X[i]) * (Y[i + 1] - Y[i]) / (X[i + 1] - X[i]); } -double interpolateEquidistant(double x, double lo, double hi, const std::vector &Y) { +double interpolateEquidistant(double x, double lo, double hi, + const std::vector &Y) { if (x <= lo) return Y.front(); if (x >= hi) diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index a0df37ffe..9be493e87 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -69,11 +69,12 @@ void ElectronPairProduction::process(Candidate *candidate) const { else rate = lossRate.back() * pow(EpA / energy.back(), 0.4); // extrapolation + // step size in local frame double step = candidate->getCurrentStep() / (1 + z); double Z = candidate->current.getChargeNumber(); // dE(E) = Z^2 * loss_rate(E/A) * step - double dE = Z * Z * rate * pow(1 + z, 3) * step; + double dE = Z * Z * rate * photonFieldScaling(photonField, z) * step; candidate->current.setEnergy(E - dE); } diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index 346923806..5e2a573c3 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -69,9 +69,9 @@ bool NuclearDecay::setNextInteraction(Candidate *candidate, interaction.channel = decays[i].channel; } - // special relativistic time dilation increases the decay distance by gamma + // special relativistic time dilation interaction.distance *= candidate->current.getLorentzFactor(); - // convert to cosmological comoving units + // convert to comoving frame interaction.distance *= (1 + candidate->getRedshift()); candidate->setInteractionState(getDescription(), interaction); diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 780f9b2bc..c7b77e692 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -94,9 +94,9 @@ bool PhotoDisintegration::setNextInteraction(Candidate *candidate, interaction.channel = pdModes[i].channel; } - // CMB density increases with (1+z)^3 -> free distance decreases accordingly - interaction.distance /= pow((1 + z), 3); - // convert to cosmological comoving units + // interaction length is proportional to 1 / (photon density) + interaction.distance /= photonFieldScaling(photonField, z); + // convert to comoving frame interaction.distance *= (1 + z); candidate->setInteractionState(getDescription(), interaction); diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 0ddcea794..5e9a3d431 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -105,9 +105,9 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, } } - // CMB density increases with (1+z)^3 -> free distance decreases accordingly - interaction.distance /= pow((1 + z), 3); - // convert to cosmological comoving units + // interaction length is proportional to 1 / (photon density) + interaction.distance /= photonFieldScaling(photonField, z); + // convert to comoving frame interaction.distance *= (1 + z); candidate->setInteractionState(getDescription(), interaction); From cc3135ccad46220f844a5a15b2c5b6242bf1c7d0 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 17 Sep 2012 18:55:01 +0200 Subject: [PATCH 0200/1298] remove need for arguments and implement setters for most classes --- include/mpc/module/Boundary.h | 46 +++++-- include/mpc/module/DeflectionCK.h | 9 +- include/mpc/module/ElectronPairProduction.h | 9 +- include/mpc/module/NuclearDecay.h | 2 + include/mpc/module/Observer.h | 13 +- include/mpc/module/Output.h | 2 +- include/mpc/module/PhotoPionProduction.h | 23 ++-- src/module/Boundary.cpp | 138 +++++++++++++++----- src/module/DeflectionCK.cpp | 23 +++- src/module/ElectronPairProduction.cpp | 19 ++- src/module/NuclearDecay.cpp | 13 +- src/module/Observer.cpp | 62 +++++++-- src/module/Output.cpp | 4 +- src/module/PhotoPionProduction.cpp | 65 +++++---- test/testBreakCondition.cpp | 17 ++- 15 files changed, 323 insertions(+), 122 deletions(-) diff --git a/include/mpc/module/Boundary.h b/include/mpc/module/Boundary.h index fdb12fc72..d342e7519 100644 --- a/include/mpc/module/Boundary.h +++ b/include/mpc/module/Boundary.h @@ -17,11 +17,14 @@ class PeriodicBox: public Module { private: Vector3d origin; Vector3d size; - void updateDescription(); public: + PeriodicBox(); PeriodicBox(Vector3d origin, Vector3d size); void process(Candidate *candidate) const; + void setOrigin(Vector3d origin); + void setSize(Vector3d size); + std::string getDescription() const; }; /** @@ -36,11 +39,14 @@ class ReflectiveBox: public Module { private: Vector3d origin; Vector3d size; - void updateDescription(); public: + ReflectiveBox(); ReflectiveBox(Vector3d origin, Vector3d size); void process(Candidate *candidate) const; + void setOrigin(Vector3d origin); + void setSize(Vector3d size); + std::string getDescription() const; }; /** @@ -59,13 +65,17 @@ class CubicBoundary: public Module { std::string flag; std::string flagValue; bool limitStep; - void updateDescription(); public: - CubicBoundary(Vector3d origin, double size, - std::string flag = "OutOfBounds", std::string flagValue = ""); - void setLimitStep(bool limitStep, double margin); + CubicBoundary(); + CubicBoundary(Vector3d origin, double size); void process(Candidate *candidate) const; + void setOrigin(Vector3d origin); + void setSize(double size); + void setMargin(double margin); + void setLimitStep(bool limitStep); + void setFlag(std::string flag, std::string flagValue); + std::string getDescription() const; }; /** @@ -84,13 +94,17 @@ class SphericalBoundary: public Module { std::string flag; std::string flagValue; bool limitStep; - void updateDescription(); public: - SphericalBoundary(Vector3d center, double radius, std::string flag = - "OutOfBounds", std::string flagValue = ""); - void setLimitStep(bool limitStep, double margin); + SphericalBoundary(); + SphericalBoundary(Vector3d center, double radius); void process(Candidate *candidate) const; + void setCenter(Vector3d center); + void setRadius(double size); + void setMargin(double margin); + void setLimitStep(bool limitStep); + void setFlag(std::string flag, std::string flagValue); + std::string getDescription() const; }; /** @@ -110,14 +124,18 @@ class EllipsoidalBoundary: public Module { std::string flag; std::string flagValue; bool limitStep; - void updateDescription(); public: + EllipsoidalBoundary(); EllipsoidalBoundary(Vector3d focalPoint1, Vector3d focalPoint2, - double majorAxis, std::string flag = "OutOfBounds", - std::string flagValue = ""); - void setLimitStep(bool limitStep, double margin); + double majorAxis); void process(Candidate *candidate) const; + void setFocalPoints(Vector3d focalPoint1, Vector3d focalPoint2); + void setMajorAxis(double size); + void setMargin(double margin); + void setLimitStep(bool limitStep); + void setFlag(std::string flag, std::string flagValue); + std::string getDescription() const; }; } // namespace mpc diff --git a/include/mpc/module/DeflectionCK.h b/include/mpc/module/DeflectionCK.h index 04a2e6459..0bd47c9dd 100644 --- a/include/mpc/module/DeflectionCK.h +++ b/include/mpc/module/DeflectionCK.h @@ -22,11 +22,16 @@ class DeflectionCK: public Module { ref_ptr field; ExplicitRungeKutta erk; double tolerance; - double minStep, maxStep; + double minStep; + double maxStep; public: - DeflectionCK(ref_ptr field, double tolerance = 1e-4, + DeflectionCK(ref_ptr field = NULL, double tolerance = 1e-4, double minStep = 0.1 * kpc, double maxStep = 4000 * Mpc); + void setField(ref_ptr field); + void setTolerance(double tolerance); + void setMinimumStep(double minStep); + void setMaximumStep(double maxStep); std::string getDescription() const; void process(Candidate *candidate) const; }; diff --git a/include/mpc/module/ElectronPairProduction.h b/include/mpc/module/ElectronPairProduction.h index b8157fc11..fdfb69c3a 100644 --- a/include/mpc/module/ElectronPairProduction.h +++ b/include/mpc/module/ElectronPairProduction.h @@ -1,5 +1,5 @@ -#ifndef ELECTRONPAIRPRODUCTION_H_ -#define ELECTRONPAIRPRODUCTION_H_ +#ifndef MPC_ELECTRONPAIRPRODUCTION_H_ +#define MPC_ELECTRONPAIRPRODUCTION_H_ #include "mpc/Module.h" #include "mpc/Common.h" @@ -21,11 +21,12 @@ class ElectronPairProduction: public Module { public: ElectronPairProduction(int photonField = CMB_IRB); - void init(int photonField); + void setPhotonField(int photonField); + void init(); void init(std::string filename); void process(Candidate *candidate) const; }; } // namespace mpc -#endif /* ELECTRONPAIRPRODUCTION_H_ */ +#endif /* MPC_ELECTRONPAIRPRODUCTION_H_ */ diff --git a/include/mpc/module/NuclearDecay.h b/include/mpc/module/NuclearDecay.h index bd3b25001..c89b98fde 100644 --- a/include/mpc/module/NuclearDecay.h +++ b/include/mpc/module/NuclearDecay.h @@ -26,6 +26,8 @@ class NuclearDecay: public StochasticInteraction { public: NuclearDecay(bool electrons = false, bool neutrinos = false); + void setHaveElectrons(bool b); + void setHaveNeutrinos(bool b); bool setNextInteraction(Candidate *candidate, InteractionState &interaction) const; void performInteraction(Candidate *candidate) const; diff --git a/include/mpc/module/Observer.h b/include/mpc/module/Observer.h index be4765a78..b3d08f7e3 100644 --- a/include/mpc/module/Observer.h +++ b/include/mpc/module/Observer.h @@ -20,12 +20,17 @@ class SmallObserverSphere: public Module { std::string flag; std::string flagValue; bool makeInactive; - void updateDescription(); public: + SmallObserverSphere(); SmallObserverSphere(Vector3d center, double radius, std::string flag = "Detected", std::string flagValue = "", bool makeInactive = true); void process(Candidate *candidate) const; + void setCenter(Vector3d center); + void setRadius(double radius); + void setFlag(std::string flag, std::string flagValue); + void setMakeInactive(bool makeInactive); + std::string getDescription() const; }; /** @@ -46,9 +51,15 @@ class LargeObserverSphere: public Module { void updateDescription(); public: + LargeObserverSphere(); LargeObserverSphere(Vector3d center, double radius, std::string flag = "Detected", std::string flagValue = "", bool makeInactive = true); void process(Candidate *candidate) const; + void setCenter(Vector3d center); + void setRadius(double radius); + void setFlag(std::string flag, std::string flagValue); + void setMakeInactive(bool makeInactive); + std::string getDescription() const; }; } // namespace mpc diff --git a/include/mpc/module/Output.h b/include/mpc/module/Output.h index 8a31c67ad..8ad3d566d 100644 --- a/include/mpc/module/Output.h +++ b/include/mpc/module/Output.h @@ -37,7 +37,7 @@ class ConditionalOutput: public Module { std::string propertyName; bool removeProperty; public: - ConditionalOutput(std::string filename, std::string propName = "Detected"); + ConditionalOutput(std::string filename, std::string propName = "Detected", bool removeProperty = false); ~ConditionalOutput(); void setRemoveProperty(bool removeProperty); void process(Candidate *candidate) const; diff --git a/include/mpc/module/PhotoPionProduction.h b/include/mpc/module/PhotoPionProduction.h index 38e884b98..edd307c4d 100644 --- a/include/mpc/module/PhotoPionProduction.h +++ b/include/mpc/module/PhotoPionProduction.h @@ -1,5 +1,5 @@ -#ifndef PHOTOPIONPRODUCTION_H_ -#define PHOTOPIONPRODUCTION_H_ +#ifndef MPC_PHOTOPIONPRODUCTION_H_ +#define MPC_PHOTOPIONPRODUCTION_H_ #include "mpc/module/StochasticInteraction.h" #include "mpc/Random.h" @@ -24,11 +24,13 @@ class PhotoPionProduction: public StochasticInteraction { public: PhotoPionProduction(int photonField = CMB); - void init(int photonField); + void setPhotonField(int photonField); + void init(); void init(std::string filename); bool setNextInteraction(Candidate *candidate, InteractionState &interaction) const; void performInteraction(Candidate *candidate) const; + std::string getDescription() const; }; /** @@ -41,16 +43,21 @@ class PhotoPionProduction: public StochasticInteraction { Electromagnetic particles, neutrinos and antiparticles as secondaries from these interactions can be switched on independently. */ class SophiaPhotoPionProduction: public PhotoPionProduction { -protected: - bool havePhotonsElectrons; +private: + bool havePhotons; bool haveNeutrinos; bool haveAntiNucleons; + public: - SophiaPhotoPionProduction(int photonField = CMB, bool photonsElectrons = - false, bool neutrinos = false, bool antiNucleons = false); + SophiaPhotoPionProduction(int photonField = CMB, bool photons = false, + bool neutrinos = false, bool antiNucleons = false); + void setHavePhotons(bool b); + void setHaveNeutrinos(bool b); + void setHaveAntiNucleons(bool b); void performInteraction(Candidate *candidate) const; + std::string getDescription() const; }; } // namespace mpc -#endif /* PHOTOPIONPRODUCTION_H_ */ +#endif /* MPC_PHOTOPIONPRODUCTION_H_ */ diff --git a/src/module/Boundary.cpp b/src/module/Boundary.cpp index 5d1e764ba..a0e074411 100644 --- a/src/module/Boundary.cpp +++ b/src/module/Boundary.cpp @@ -4,9 +4,12 @@ namespace mpc { +PeriodicBox::PeriodicBox() : + origin(Vector3d(0, 0, 0)), size(Vector3d(0, 0, 0)) { +} + PeriodicBox::PeriodicBox(Vector3d o, Vector3d s) : origin(o), size(s) { - updateDescription(); } void PeriodicBox::process(Candidate *c) const { @@ -21,16 +24,26 @@ void PeriodicBox::process(Candidate *c) const { c->initial.setPosition(c->initial.getPosition() - n * size); } -void PeriodicBox::updateDescription() { +void PeriodicBox::setOrigin(Vector3d o) { + origin = o; +} +void PeriodicBox::setSize(Vector3d s) { + size = s; +} + +std::string PeriodicBox::getDescription() const { std::stringstream s; s << "Periodic box: origin " << origin / Mpc << "Mpc, "; s << "size " << size / Mpc << " Mpc"; - setDescription(s.str()); + return s.str(); +} + +ReflectiveBox::ReflectiveBox() : + origin(Vector3d(0, 0, 0)), size(Vector3d(0, 0, 0)) { } ReflectiveBox::ReflectiveBox(Vector3d o, Vector3d s) : origin(o), size(s) { - updateDescription(); } void ReflectiveBox::process(Candidate *c) const { @@ -74,22 +87,28 @@ void ReflectiveBox::process(Candidate *c) const { c->previous.setPosition(prv * size + origin); } -void ReflectiveBox::updateDescription() { +void ReflectiveBox::setOrigin(Vector3d o) { + origin = o; +} +void ReflectiveBox::setSize(Vector3d s) { + size = s; +} + +std::string ReflectiveBox::getDescription() const { std::stringstream s; s << "Reflective box: origin " << origin / Mpc << "Mpc, "; s << "size " << size / Mpc << " Mpc"; - setDescription(s.str()); + return s.str(); } -CubicBoundary::CubicBoundary(Vector3d o, double s, std::string f, std::string v) : - origin(o), size(s), margin(0), flag(f), flagValue(v), limitStep(false) { - updateDescription(); +CubicBoundary::CubicBoundary() : + origin(Vector3d(0, 0, 0)), size(0), margin(0), flag("OutOfBounds"), flagValue( + ""), limitStep(false) { } -void CubicBoundary::setLimitStep(bool limitStep, double margin) { - this->limitStep = limitStep; - this->margin = margin; - updateDescription(); +CubicBoundary::CubicBoundary(Vector3d o, double s) : + origin(o), size(s), margin(0), flag("OutOfBounds"), flagValue(""), limitStep( + false) { } void CubicBoundary::process(Candidate *c) const { @@ -106,24 +125,39 @@ void CubicBoundary::process(Candidate *c) const { } } -void CubicBoundary::updateDescription() { +void CubicBoundary::setOrigin(Vector3d o) { + origin = o; +} +void CubicBoundary::setSize(double s) { + size = s; +} +void CubicBoundary::setMargin(double m) { + margin = m; +} +void CubicBoundary::setLimitStep(bool b) { + limitStep = b; +} +void CubicBoundary::setFlag(std::string f, std::string v) { + flag = f; + flagValue = v; +} + +std::string CubicBoundary::getDescription() const { std::stringstream s; s << "Cubic Boundary: origin " << origin / Mpc << " Mpc, "; s << "size " << size / Mpc << " Mpc; "; s << "Flag: " << flag << " -> " << flagValue; - setDescription(s.str()); + return s.str(); } -SphericalBoundary::SphericalBoundary(Vector3d c, double r, std::string f, - std::string v) : - center(c), radius(r), flag(f), flagValue(v), limitStep(false), margin(0) { - updateDescription(); +SphericalBoundary::SphericalBoundary() : + center(Vector3d(0, 0, 0)), radius(0), flag("OutOfBounds"), flagValue( + ""), limitStep(false), margin(0) { } -void SphericalBoundary::setLimitStep(bool limitStep, double margin) { - this->limitStep = limitStep; - this->margin = margin; - updateDescription(); +SphericalBoundary::SphericalBoundary(Vector3d c, double r) : + center(c), radius(r), flag("OutOfBounds"), flagValue(""), limitStep( + false), margin(0) { } void SphericalBoundary::process(Candidate *c) const { @@ -136,24 +170,40 @@ void SphericalBoundary::process(Candidate *c) const { c->limitNextStep(radius - d + margin); } -void SphericalBoundary::updateDescription() { +void SphericalBoundary::setCenter(Vector3d c) { + center = c; +} +void SphericalBoundary::setRadius(double r) { + radius = r; +} +void SphericalBoundary::setMargin(double m) { + margin = m; +} +void SphericalBoundary::setLimitStep(bool b) { + limitStep = b; +} +void SphericalBoundary::setFlag(std::string f, std::string v) { + flag = f; + flagValue = v; +} + +std::string SphericalBoundary::getDescription() const { std::stringstream s; s << "Spherical Boundary: radius " << radius / Mpc << " Mpc "; s << "around " << center / Mpc << " Mpc; "; s << "Flag: " << flag << " -> " << flagValue; - setDescription(s.str()); + return s.str(); } -EllipsoidalBoundary::EllipsoidalBoundary(Vector3d f1, - Vector3d f2, double a, std::string f, - std::string v) : focalPoint1(f1), focalPoint2(f2), majorAxis(a), flag(f), flagValue(v), limitStep(false), margin(0) { - updateDescription(); +EllipsoidalBoundary::EllipsoidalBoundary() : + focalPoint1(Vector3d(0, 0, 0)), focalPoint2(Vector3d(0, 0, 0)), majorAxis( + 0), flag("OutOfBounds"), flagValue(""), limitStep(false), margin( + 0) { } -void EllipsoidalBoundary::setLimitStep(bool limitStep, double margin) { - this->limitStep = limitStep; - this->margin = margin; - updateDescription(); +EllipsoidalBoundary::EllipsoidalBoundary(Vector3d f1, Vector3d f2, double a) : + focalPoint1(f1), focalPoint2(f2), majorAxis(a), flag("OutOfBounds"), flagValue( + ""), limitStep(false), margin(0) { } void EllipsoidalBoundary::process(Candidate *c) const { @@ -167,13 +217,31 @@ void EllipsoidalBoundary::process(Candidate *c) const { c->limitNextStep(majorAxis - d + margin); } -void EllipsoidalBoundary::updateDescription() { +void EllipsoidalBoundary::setFocalPoints(Vector3d f1, Vector3d f2) { + focalPoint1 = f1; + focalPoint2 = f2; +} +void EllipsoidalBoundary::setMajorAxis(double a) { + majorAxis = a; +} +void EllipsoidalBoundary::setMargin(double m) { + margin = m; +} +void EllipsoidalBoundary::setLimitStep(bool b) { + limitStep = b; +} +void EllipsoidalBoundary::setFlag(std::string f, std::string v) { + flag = f; + flagValue = v; +} + +std::string EllipsoidalBoundary::getDescription() const { std::stringstream s; s << "Ellipsoidal Boundary: F1 = " << focalPoint1 / Mpc << " Mpc, "; s << "F2 = " << focalPoint2 / Mpc << " Mpc, "; s << "major axis " << majorAxis / Mpc << " Mpc; "; s << " Flag: " << flag << " -> " << flagValue; - setDescription(s.str()); + return s.str(); } } // namespace mpc diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index a9a3e9cdb..7fded6257 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -37,14 +37,27 @@ class LorentzForce: public ExplicitRungeKutta::F { }; DeflectionCK::DeflectionCK(ref_ptr field, double tolerance, - double minStep, double maxStep) { - this->field = field; - this->tolerance = tolerance; - this->minStep = minStep; - this->maxStep = maxStep; + double minStep, double maxStep) : + field(field), tolerance(tolerance), minStep(minStep), maxStep(maxStep) { erk.loadCashKarp(); } +void DeflectionCK::setField(ref_ptr f) { + field = f; +} + +void DeflectionCK::setTolerance(double t) { + tolerance = t; +} + +void DeflectionCK::setMinimumStep(double s) { + minStep = s; +} + +void DeflectionCK::setMaximumStep(double s) { + maxStep = s; +} + std::string DeflectionCK::getDescription() const { std::stringstream s; s << "Propagation in magnetic fields using the Cash-Karp method."; diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 9be493e87..90582d818 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -6,12 +6,17 @@ namespace mpc { -ElectronPairProduction::ElectronPairProduction(int photonField) { - init(photonField); +ElectronPairProduction::ElectronPairProduction(int p) : + photonField(p) { + init(); } -void ElectronPairProduction::init(int photonField) { - this->photonField = photonField; +void ElectronPairProduction::setPhotonField(int p) { + photonField = p; + init(); +} + +void ElectronPairProduction::init() { switch (photonField) { case CMB: setDescription("ElectronPairProduction: CMB"); @@ -27,7 +32,7 @@ void ElectronPairProduction::init(int photonField) { break; default: throw std::runtime_error( - "mpc::ElectronPairProduction: unknown photon background"); + "ElectronPairProduction: unknown photon background"); } } @@ -37,7 +42,7 @@ void ElectronPairProduction::init(std::string filename) { if (!infile.good()) throw std::runtime_error( - "mpc::ElectronPairProduction: could not open file " + filename); + "ElectronPairProduction: could not open file " + filename); std::vector x, y; while (infile.good()) { @@ -69,7 +74,7 @@ void ElectronPairProduction::process(Candidate *candidate) const { else rate = lossRate.back() * pow(EpA / energy.back(), 0.4); // extrapolation - // step size in local frame + // step size in local frame double step = candidate->getCurrentStep() / (1 + z); double Z = candidate->current.getChargeNumber(); diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index 5e2a573c3..fd16c6ec8 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -8,10 +8,9 @@ namespace mpc { -NuclearDecay::NuclearDecay(bool electrons, bool neutrinos) { +NuclearDecay::NuclearDecay(bool electrons, bool neutrinos) : + haveElectrons(electrons), haveNeutrinos(neutrinos) { setDescription("NuclearDecay"); - haveElectrons = electrons; - haveNeutrinos = neutrinos; // load decay table std::string filename = getDataPath("/NuclearDecay/decayTable.txt"); @@ -48,6 +47,14 @@ NuclearDecay::NuclearDecay(bool electrons, bool neutrinos) { } } +void NuclearDecay::setHaveElectrons(bool b) { + haveElectrons = b; +} + +void NuclearDecay::setHaveNeutrinos(bool b) { + haveNeutrinos = b; +} + bool NuclearDecay::setNextInteraction(Candidate *candidate, InteractionState &interaction) const { int A = candidate->current.getMassNumber(); diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp index e830b0d94..30d7db937 100644 --- a/src/module/Observer.cpp +++ b/src/module/Observer.cpp @@ -4,10 +4,14 @@ namespace mpc { -SmallObserverSphere::SmallObserverSphere(Vector3d c, double r, - std::string f, std::string v, bool b) : +SmallObserverSphere::SmallObserverSphere() : + center(Vector3d(0, 0, 0)), radius(0), flag("Detected"), flagValue(""), makeInactive( + true) { +} + +SmallObserverSphere::SmallObserverSphere(Vector3d c, double r, std::string f, + std::string v, bool b) : center(c), radius(r), flag(f), flagValue(v), makeInactive(b) { - updateDescription(); } void SmallObserverSphere::process(Candidate *c) const { @@ -23,18 +27,39 @@ void SmallObserverSphere::process(Candidate *c) const { c->limitNextStep(fabs(d - radius)); } -void SmallObserverSphere::updateDescription() { +void SmallObserverSphere::setCenter(Vector3d c) { + center = c; +} + +void SmallObserverSphere::setRadius(double r) { + radius = r; +} + +void SmallObserverSphere::setFlag(std::string f, std::string v) { + flag = f; + flagValue = v; +} + +void SmallObserverSphere::setMakeInactive(bool b) { + makeInactive = b; +} + +std::string SmallObserverSphere::getDescription() const { std::stringstream s; s << "Small observer sphere: " << radius / Mpc; s << " Mpc radius around " << center / Mpc; s << " Mpc, Flag: '" << flag << "' -> '" << flagValue << "'"; - setDescription(s.str()); + return s.str(); } -LargeObserverSphere::LargeObserverSphere(Vector3d c, double r, - std::string f, std::string v, bool b) : +LargeObserverSphere::LargeObserverSphere() : + center(Vector3d(0, 0, 0)), radius(0), flag("Detected"), flagValue(""), makeInactive( + true) { +} + +LargeObserverSphere::LargeObserverSphere(Vector3d c, double r, std::string f, + std::string v, bool b) : center(c), radius(r), flag(f), flagValue(v), makeInactive(b) { - updateDescription(); } void LargeObserverSphere::process(Candidate *c) const { @@ -50,12 +75,29 @@ void LargeObserverSphere::process(Candidate *c) const { c->limitNextStep(fabs(radius - d)); } -void LargeObserverSphere::updateDescription() { +void LargeObserverSphere::setCenter(Vector3d c) { + center = c; +} + +void LargeObserverSphere::setRadius(double r) { + radius = r; +} + +void LargeObserverSphere::setFlag(std::string f, std::string v) { + flag = f; + flagValue = v; +} + +void LargeObserverSphere::setMakeInactive(bool b) { + makeInactive = b; +} + +std::string LargeObserverSphere::getDescription() const { std::stringstream s; s << "Large observer sphere: " << radius / Mpc; s << " Mpc radius around " << center / Mpc; s << " Mpc, Flag: '" << flag << "' -> '" << flagValue << "'"; - setDescription(s.str()); + return s.str(); } } // namespace mpc diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 81a3cc4fe..41acdd7b3 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -41,9 +41,9 @@ void TrajectoryOutput::process(Candidate *c) const { } ConditionalOutput::ConditionalOutput(std::string filename, - std::string propName) { + std::string propName, bool b) { setDescription("Conditional output, condition: '" + propName + "'"); - removeProperty = false; + removeProperty = b; propertyName = propName; outfile.open(filename.c_str()); outfile << "# PDG_Code\t"; diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 5e9a3d431..49fcfecf4 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -11,32 +11,31 @@ namespace mpc { -PhotoPionProduction::PhotoPionProduction(int photonField) { - init(photonField); +PhotoPionProduction::PhotoPionProduction(int p) : + photonField(p) { + init(); } -void PhotoPionProduction::init(int photonField) { - this->photonField = photonField; - switch (photonField) { - case CMB: - setDescription("PhotoPionProduction: CMB"); +void PhotoPionProduction::setPhotonField(int p) { + photonField = p; + init(); +} + +void PhotoPionProduction::init() { + if (photonField == CMB) init(getDataPath("PhotoPionProduction/PPtable_CMB.txt")); - break; - case IRB: - setDescription("PhotoPionProduction: IRB"); + else if (photonField == IRB) init(getDataPath("PhotoPionProduction/PPtable_IRB.txt")); - break; - default: + else throw std::runtime_error( - "mpc::PhotoPionProduction: only CMB or IRB possible as photon background"); - } + "PhotoPionProduction: only CMB / IRB possible"); } void PhotoPionProduction::init(std::string filename) { std::ifstream infile(filename.c_str()); if (!infile.good()) throw std::runtime_error( - "mpc::PhotoPionProduction: could not open file " + filename); + "PhotoPionProduction: could not open file " + filename); while (infile.good()) { if (infile.peek() != '#') { @@ -54,6 +53,10 @@ void PhotoPionProduction::init(std::string filename) { infile.close(); } +std::string PhotoPionProduction::getDescription() const { + return "PhotoPionProduction on " + (photonField == CMB)? "CMB" : "IRB"; +} + bool PhotoPionProduction::setNextInteraction(Candidate *candidate, InteractionState &interaction) const { double z = candidate->getRedshift(); @@ -145,11 +148,21 @@ void PhotoPionProduction::performInteraction(Candidate *candidate) const { } SophiaPhotoPionProduction::SophiaPhotoPionProduction(int photonField, - bool photonsElectrons, bool neutrinos, bool antiNucleons) : - PhotoPionProduction(photonField) { - havePhotonsElectrons = photonsElectrons; - haveNeutrinos = neutrinos; - haveAntiNucleons = antiNucleons; + bool photons, bool neutrinos, bool antiNucleons) : + PhotoPionProduction(photonField), havePhotons(photons), haveNeutrinos( + neutrinos), haveAntiNucleons(antiNucleons) { +} + +void SophiaPhotoPionProduction::setHavePhotons(bool b) { + havePhotons = b; +} + +void SophiaPhotoPionProduction::setHaveNeutrinos(bool b) { + haveNeutrinos = b; +} + +void SophiaPhotoPionProduction::setHaveAntiNucleons(bool b) { + haveAntiNucleons = b; } void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { @@ -216,15 +229,15 @@ void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { candidate->addSecondary(-getNucleusId(1, 0), Eout); break; case 1: // photon - if (havePhotonsElectrons) + if (havePhotons) candidate->addSecondary(22, Eout); break; case 2: // positron - if (havePhotonsElectrons) + if (havePhotons) candidate->addSecondary(-11, Eout); break; case 3: // electron - if (havePhotonsElectrons) + if (havePhotons) candidate->addSecondary(11, Eout); break; case 15: // nu_e @@ -245,10 +258,14 @@ void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { break; default: throw std::runtime_error( - "mpc::PhotoPionProduction: unexpected particle " + "PhotoPionProduction: unexpected particle " + kiss::str(pType)); } } } +std::string SophiaPhotoPionProduction::getDescription() const { + return "SophiaPhotoPionProduction on " + (photonField == CMB)? "CMB" : "IRB"; +} + } // namespace mpc diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index 05f9f0f1a..144e044b5 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -226,7 +226,8 @@ TEST(CubicBoundary, outside) { TEST(CubicBoundary, limitStepLower) { CubicBoundary cube(Vector3d(10, 10, 10), 10); - cube.setLimitStep(true, 1); + cube.setLimitStep(true); + cube.setMargin(1); Candidate c; c.current.setPosition(Vector3d(15, 15, 10.5)); c.setNextStep(100); @@ -236,7 +237,8 @@ TEST(CubicBoundary, limitStepLower) { TEST(CubicBoundary, limitStepUpper) { CubicBoundary cube(Vector3d(-10, -10, -10), 10); - cube.setLimitStep(true, 1); + cube.setLimitStep(true); + cube.setMargin(1); Candidate c; c.current.setPosition(Vector3d(-5, -5, -0.5)); c.setNextStep(100); @@ -254,17 +256,19 @@ TEST(SphericalBoundary, inside) { } TEST(SphericalBoundary, outside) { - SphericalBoundary sphere(Vector3d(0, 0, 0), 10, "PassedGalacticBorder"); + SphericalBoundary sphere(Vector3d(0, 0, 0), 10); + sphere.setFlag("I passed the galactic border", "Nothing happened"); Candidate c; c.current.setPosition(Vector3d(0, -10.1, 0)); sphere.process(&c); EXPECT_FALSE(c.isActive()); - EXPECT_TRUE(c.hasProperty("PassedGalacticBorder")); + EXPECT_TRUE(c.hasProperty("I passed the galactic border")); } TEST(SphericalBoundary, limitStep) { SphericalBoundary sphere(Vector3d(0, 0, 0), 10); - sphere.setLimitStep(true, 1); + sphere.setLimitStep(true); + sphere.setMargin(1); Candidate c; c.setNextStep(100); c.current.setPosition(Vector3d(0, 0, 9.5)); @@ -292,7 +296,8 @@ TEST(EllipsoidalBoundary, outside) { TEST(EllipsoidalBoundary, limitStep) { EllipsoidalBoundary ellipsoid(Vector3d(-5, 0, 0), Vector3d(5, 0, 0), 15); - ellipsoid.setLimitStep(true, 0.5); + ellipsoid.setLimitStep(true); + ellipsoid.setMargin(0.5); Candidate c; c.setNextStep(2); c.current.setPosition(Vector3d(7, 0, 0)); From c85d7dc41f5801f386766e4fcc868b43157c0b28 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 25 Sep 2012 14:02:58 +0200 Subject: [PATCH 0201/1298] script for Kneiske et al 2004 IRB global redshift scaling --- include/mpc/Units.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/mpc/Units.h b/include/mpc/Units.h index adc061130..1d0d84b7f 100644 --- a/include/mpc/Units.h +++ b/include/mpc/Units.h @@ -28,6 +28,7 @@ static const double mass_proton = 1.67262158e-27 * kilogram; static const double mass_neutron = 1.67492735e-27 * kilogram; static const double mass_electron = 9.10938291e-31 * kilogram; static const double h_planck = 6.62606957e-34 * joule * second; +static const double k_boltzmann = 1.3806488e-23 * joule / kelvin; // other units static const double gram = 1e-3 * kilogram; From 0db6cb5972e095ecfaf63d765c24664eb0fbdb4e Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 25 Sep 2012 14:03:35 +0200 Subject: [PATCH 0202/1298] make redshift output optional for ConditionalOutput --- include/mpc/module/Output.h | 5 ++++- src/module/Output.cpp | 21 ++++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/include/mpc/module/Output.h b/include/mpc/module/Output.h index 8ad3d566d..1440499a3 100644 --- a/include/mpc/module/Output.h +++ b/include/mpc/module/Output.h @@ -36,10 +36,13 @@ class ConditionalOutput: public Module { mutable std::ofstream outfile; std::string propertyName; bool removeProperty; + bool showRedshift; public: - ConditionalOutput(std::string filename, std::string propName = "Detected", bool removeProperty = false); + ConditionalOutput(std::string filename, std::string propName = "Detected", + bool removeProperty = false, bool showRedshift = false); ~ConditionalOutput(); void setRemoveProperty(bool removeProperty); + void setShowRedshift(bool showRedshift); void process(Candidate *candidate) const; }; diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 41acdd7b3..89aba4eb7 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -40,10 +40,10 @@ void TrajectoryOutput::process(Candidate *c) const { } } -ConditionalOutput::ConditionalOutput(std::string filename, - std::string propName, bool b) { +ConditionalOutput::ConditionalOutput(std::string filename, std::string propName, + bool removeProperty, bool showRedshift) : + removeProperty(removeProperty), showRedshift(showRedshift) { setDescription("Conditional output, condition: '" + propName + "'"); - removeProperty = b; propertyName = propName; outfile.open(filename.c_str()); outfile << "# PDG_Code\t"; @@ -51,7 +51,7 @@ ConditionalOutput::ConditionalOutput(std::string filename, outfile << "Position(X,Y,Z)[Mpc]\t"; outfile << "Direction(Phi,Theta)\t"; outfile << "Age[Mpc]\t"; - outfile << "Redshift\t"; + outfile << "(Redshift)\t"; outfile << "Initial_PDG_Code\t"; outfile << "Initial_Energy[EeV]\t"; outfile << "Initial_Position(X,Y,Z)[Mpc]\t"; @@ -62,8 +62,12 @@ ConditionalOutput::~ConditionalOutput() { outfile.close(); } -void ConditionalOutput::setRemoveProperty(bool removeProperty) { - this->removeProperty = removeProperty; +void ConditionalOutput::setRemoveProperty(bool b) { + removeProperty = b; +} + +void ConditionalOutput::setShowRedshift(bool b) { + showRedshift = b; } void ConditionalOutput::process(Candidate *c) const { @@ -79,7 +83,10 @@ void ConditionalOutput::process(Candidate *c) const { p += sprintf(buffer + p, "%7.4f\t%7.4f\t", dir.getPhi(), dir.getTheta()); p += sprintf(buffer + p, "%9.4f\t", c->getTrajectoryLength() / Mpc); - p += sprintf(buffer + p, "%7.4f\t", c->getRedshift()); + + if (showRedshift) + p += sprintf(buffer + p, "%7.4f\t", c->getRedshift()); + p += sprintf(buffer + p, "%10i\t", c->initial.getId()); p += sprintf(buffer + p, "%8.4f\t", c->initial.getEnergy() / EeV); const Vector3d &ipos = c->initial.getPosition() / Mpc; From 15dbd007a3c179810456533082b116558b256ae5 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 9 Oct 2012 18:57:59 +0200 Subject: [PATCH 0203/1298] change data table location data tables are now in data/ (need to be downloaded from forge) data table scripts are in data-tools/ (uncommitted) --- CMakeLists.txt | 8 ++++++-- src/Nucleus.cpp | 2 +- src/module/ElectronPairProduction.cpp | 6 +++--- src/module/NuclearDecay.cpp | 2 +- src/module/PhotoDisintegration.cpp | 4 ++-- src/module/PhotoPionProduction.cpp | 4 ++-- 6 files changed, 15 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b75ce524..1501deee1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,7 +73,7 @@ if (GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) endif(GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) # ---------------------------------------------------------------------------- -# mpc and mpc-run +# Library and Binary # ---------------------------------------------------------------------------- include_directories(include ${MPC_EXTRA_INCLUDES}) add_library(mpc SHARED @@ -112,11 +112,15 @@ target_link_libraries(mpc ${MPC_EXTRA_LIBRARIES}) add_executable(mpc-run src/main.cpp) target_link_libraries(mpc-run mpc) + +# ---------------------------------------------------------------------------- +# Install +# ---------------------------------------------------------------------------- add_definitions(-DMPC_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") install(TARGETS mpc-run RUNTIME DESTINATION bin) install(TARGETS mpc DESTINATION lib) install(DIRECTORY include/ DESTINATION include FILES_MATCHING PATTERN "*.h") -install(DIRECTORY data/ DESTINATION share/mpc) +install(DIRECTORY data/ DESTINATION share/mpc/) # ---------------------------------------------------------------------------- # Testing diff --git a/src/Nucleus.cpp b/src/Nucleus.cpp index 522164676..1fae161b2 100644 --- a/src/Nucleus.cpp +++ b/src/Nucleus.cpp @@ -51,7 +51,7 @@ struct NuclearMassTable { std::vector table; NuclearMassTable() { - std::string filename = getDataPath("/NuclearMass/nuclearMassTable.txt"); + std::string filename = getDataPath("nuclear_mass.txt"); std::ifstream infile(filename.c_str()); if (!infile.good()) diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 90582d818..106a47626 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -20,15 +20,15 @@ void ElectronPairProduction::init() { switch (photonField) { case CMB: setDescription("ElectronPairProduction: CMB"); - init(getDataPath("ElectronPairProduction/cmb.txt")); + init(getDataPath("epair_CMB.txt")); break; case IRB: setDescription("ElectronPairProduction: IRB"); - init(getDataPath("ElectronPairProduction/ir.txt")); + init(getDataPath("epair_IRB.txt")); break; case CMB_IRB: setDescription("ElectronPairProduction: CMB and IRB"); - init(getDataPath("ElectronPairProduction/cmbir.txt")); + init(getDataPath("epair_CMB_IRB.txt")); break; default: throw std::runtime_error( diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index fd16c6ec8..0cc2a72c0 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -13,7 +13,7 @@ NuclearDecay::NuclearDecay(bool electrons, bool neutrinos) : setDescription("NuclearDecay"); // load decay table - std::string filename = getDataPath("/NuclearDecay/decayTable.txt"); + std::string filename = getDataPath("nuclear_decay.txt"); std::ifstream infile(filename.c_str()); if (!infile.good()) throw std::runtime_error( diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index c7b77e692..7ffb3320a 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -17,11 +17,11 @@ void PhotoDisintegration::init(int photonField) { switch (photonField) { case CMB: setDescription("PhotoDisintegration: CMB"); - init(getDataPath("PhotoDisintegration/PDtable_CMB.txt")); + init(getDataPath("photodis_CMB.txt")); break; case IRB: setDescription("PhotoDisintegration: IRB"); - init(getDataPath("PhotoDisintegration/PDtable_IRB.txt")); + init(getDataPath("photodis_IRB.txt")); break; default: throw std::runtime_error( diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 49fcfecf4..072419879 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -23,9 +23,9 @@ void PhotoPionProduction::setPhotonField(int p) { void PhotoPionProduction::init() { if (photonField == CMB) - init(getDataPath("PhotoPionProduction/PPtable_CMB.txt")); + init(getDataPath("photopion_CMB.txt")); else if (photonField == IRB) - init(getDataPath("PhotoPionProduction/PPtable_IRB.txt")); + init(getDataPath("photopion_IRB.txt")); else throw std::runtime_error( "PhotoPionProduction: only CMB / IRB possible"); From 04a444023c3eea299738320eb4c708c2d18d524e Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 10 Oct 2012 12:04:42 +0200 Subject: [PATCH 0204/1298] add 1D observer --- include/mpc/module/Observer.h | 27 ++++++++++++++++++ src/module/Observer.cpp | 52 +++++++++++++++++++++++++++++++++++ test/testBreakCondition.cpp | 25 +++++++++++++++-- 3 files changed, 102 insertions(+), 2 deletions(-) diff --git a/include/mpc/module/Observer.h b/include/mpc/module/Observer.h index b3d08f7e3..9b1cd481b 100644 --- a/include/mpc/module/Observer.h +++ b/include/mpc/module/Observer.h @@ -62,6 +62,33 @@ class LargeObserverSphere: public Module { std::string getDescription() const; }; +/** + @class OneDimensionalObserver + @brief Observer for 1D simulations + + Particles are detected once their x-position gets smaller than a given value. + In this case the candidate is by default flagged "Detected" made inactive. + This module limits the next step size to prevent candidates from overshooting. + */ +class OneDimensionalObserver: public Module { +private: + double xObs; + std::string flag; + std::string flagValue; + bool makeInactive; + void updateDescription(); + +public: + OneDimensionalObserver(); + OneDimensionalObserver(double x, std::string flag = + "Detected", std::string flagValue = "", bool makeInactive = true); + void process(Candidate *candidate) const; + void setPosition(double position); + void setFlag(std::string flag, std::string flagValue); + void setMakeInactive(bool makeInactive); + std::string getDescription() const; +}; + } // namespace mpc #endif /* MPC_OBSERVER_H_ */ diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp index 30d7db937..3b221daa5 100644 --- a/src/module/Observer.cpp +++ b/src/module/Observer.cpp @@ -49,6 +49,8 @@ std::string SmallObserverSphere::getDescription() const { s << "Small observer sphere: " << radius / Mpc; s << " Mpc radius around " << center / Mpc; s << " Mpc, Flag: '" << flag << "' -> '" << flagValue << "'"; + if (makeInactive) + s << ", Inactivate"; return s.str(); } @@ -97,6 +99,56 @@ std::string LargeObserverSphere::getDescription() const { s << "Large observer sphere: " << radius / Mpc; s << " Mpc radius around " << center / Mpc; s << " Mpc, Flag: '" << flag << "' -> '" << flagValue << "'"; + if (makeInactive) + s << ", Inactivate"; + return s.str(); +} + +OneDimensionalObserver::OneDimensionalObserver() : + xObs(0), flag("Detected"), flagValue(""), makeInactive(true) { +} + +OneDimensionalObserver::OneDimensionalObserver(double x, std::string f, + std::string v, bool b) : + xObs(x), flag(f), flagValue(v), makeInactive(b) { +} + +void OneDimensionalObserver::process(Candidate *c) const { + double x = c->current.getPosition().x; + if (x > xObs) { + c->limitNextStep(x - xObs); + return; // no detection yet + } + + double xprev = c->previous.getPosition().x; + if (xprev < xObs) + return; // particle already detected + + // else: detection + c->setProperty(flag, flagValue); + if (makeInactive) + c->setActive(false); +} + +void OneDimensionalObserver::setPosition(double x) { + xObs = x; +} + +void OneDimensionalObserver::setFlag(std::string f, std::string v) { + flag = f; + flagValue = v; +} + +void OneDimensionalObserver::setMakeInactive(bool b) { + makeInactive = b; +} + +std::string OneDimensionalObserver::getDescription() const { + std::stringstream s; + s << "1D observer at " << xObs / Mpc << " Mpc"; + s << ", Flag: '" << flag << "' -> '" << flagValue << "'"; + if (makeInactive) + s << ", Inactivate"; return s.str(); } diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index 144e044b5..7033bc638 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -1,14 +1,15 @@ -/** Unit tests for break condition and observer modules */ +/** Unit tests for break condition, observer and boundary modules */ #include "mpc/module/BreakCondition.h" -#include "mpc/module/Boundary.h" #include "mpc/module/Observer.h" +#include "mpc/module/Boundary.h" #include "mpc/Candidate.h" #include "gtest/gtest.h" namespace mpc { +//** ========================= Break conditions ============================= */ TEST(MinimumEnergy, test) { MinimumEnergy minEnergy(5); Candidate c; @@ -51,6 +52,7 @@ TEST(MinimumRedshift, test) { EXPECT_TRUE(c.hasProperty("Deactivated")); } +//** ============================= Observers ================================ */ TEST(SmallObserverSphere, outside) { SmallObserverSphere obs(Vector3d(0, 0, 0), 1); Candidate c; @@ -125,6 +127,25 @@ TEST(LargeObserverSphere, limitStep) { EXPECT_DOUBLE_EQ(c.getNextStep(), 2); } +TEST(OneDimensionalObserver, noDetection) { + OneDimensionalObserver obs; // observer at x = 0 + Candidate c; + c.current.setPosition(Vector3d(5, 0, 0)); + c.setNextStep(10); + obs.process(&c); + EXPECT_TRUE(c.isActive()); + EXPECT_DOUBLE_EQ(5, c.getNextStep()); +} + +TEST(OneDimensionalObserver, detection) { + OneDimensionalObserver obs; // observer at x = 0 + Candidate c; + c.current.setPosition(Vector3d(0, 0, 0)); + obs.process(&c); + EXPECT_FALSE(c.isActive()); +} + +//** ========================= Boundaries =================================== */ TEST(PeriodicBox, high) { // Tests if the periodical boundaries place the particle back inside the box and translate the initial position accordingly. Vector3d origin(2, 2, 2); From 5ebde051939cc525fcbe0ab4daa752e3474a87b9 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 10 Oct 2012 15:11:37 +0200 Subject: [PATCH 0205/1298] fix Redshift description --- src/module/Redshift.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index 6d3059ea2..76c41d283 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -95,9 +95,8 @@ void Redshift::process(Candidate *c) const { std::string Redshift::getDescription() const { std::stringstream ss; - ss << "Redshift for cosmological parameters: "; - ss << "H0 = " << H0 * 1e3 / Mpc << " km/s/Mpc, "; - ss << "omegaL = " << omegaL << ", omegaM = " << omegaM; + ss << "Redshift: " << "H0 = " << H0 / 1e3 * Mpc << " km/s/Mpc, "; + ss << "OmegaL = " << omegaL << ", OmegaM = " << omegaM; return ss.str(); } From e9a443564f36d0cd0141dd7b34157e75c3cd978c Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 11 Oct 2012 10:34:00 +0200 Subject: [PATCH 0206/1298] more changes for 1D propagation --- README | 21 ++++--- include/mpc/Source.h | 47 ++++++++++++---- include/mpc/module/Observer.h | 23 ++------ include/mpc/module/Output.h | 40 +++++++++++--- python/mpc.i | 6 +- src/Source.cpp | 80 +++++++++++++++++---------- src/XmlExecute.cpp | 6 +- src/module/Observer.cpp | 49 +++-------------- src/module/Output.cpp | 101 +++++++++++++++++++++++++--------- test/testBreakCondition.cpp | 8 +-- test/testSource.cpp | 8 +-- 11 files changed, 229 insertions(+), 160 deletions(-) diff --git a/README b/README index 4f0d9184f..f072a3057 100644 --- a/README +++ b/README @@ -1,17 +1,16 @@ Install from source ------------------------ MPC is configured using CMAKE - for more information see www.cmake.org -1) $cd build -2) $cmake .. (or $ccmake ..) -3) $make -4) $make test (to run all unit tests) -5) Set the data path - export MPC_DATA_PATH=[path to mpc/data] -6) Retrieve additional data files from https://forge.physik.rwth-aachen.de/projects/mpc/files - The photo-disintegration tables PDtable_XXX.txt have to be copied to mpc/data/PhotoDisintegration - +1) Download the data archive from https://forge.physik.rwth-aachen.de/projects/mpc/files extract to mpc/data +2) >> cd build +3) >> cmake .. + or >> ccmake .. +4) >> make +5) >> make test [to run all unit tests when gtest is available] +7) >> make install + Notes for Intel Compiler: - -DCMAKE_SHARED_LINKER_FLAGS="-lifcore" -DCMAKE_Fortran_COMPILER=ifort + use -DCMAKE_SHARED_LINKER_FLAGS="-lifcore" -DCMAKE_Fortran_COMPILER=ifort Install with Python bindings @@ -47,7 +46,7 @@ OpenMP -> for shared memory parallelization googleperftools -> for performance optimizations regarding shared memory parallelization - + XML Steering ------------ diff --git a/include/mpc/Source.h b/include/mpc/Source.h index 38d1926cd..8edfcb212 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -4,6 +4,7 @@ #include "mpc/Referenced.h" #include "mpc/Candidate.h" #include "mpc/Grid.h" +#include "mpc/module/Redshift.h" #include @@ -15,8 +16,8 @@ namespace mpc { */ class SourceProperty: public Referenced { public: - virtual void prepare(ParticleState &particle) const; - virtual void prepare(Candidate &candidate) const; + virtual void prepare(ParticleState& particle) const; + virtual void prepare(Candidate& candidate) const; }; /** @@ -43,7 +44,7 @@ class SourceList: public Source { std::vector > sources; std::vector luminosities; public: - void addSource(Source *source, double luminosity = 1); + void addSource(Source* source, double luminosity = 1); ref_ptr getCandidate() const; }; @@ -58,7 +59,6 @@ class SourceParticleType: public SourceProperty { void prepare(ParticleState &particle) const; }; - /** @class SourceEnergy @brief Sets the initial energy to a given value @@ -139,29 +139,40 @@ class SourceMultiplePositions: public SourceProperty { }; /** - @class SourceHomogeneousSphere + @class SourceUniformDistributionSphere @brief Uniform random source positions inside a sphere */ -class SourceHomogeneousSphere: public SourceProperty { +class SourceUniformDistributionSphere: public SourceProperty { Vector3d center; double radius; public: - SourceHomogeneousSphere(Vector3d center, double radius); + SourceUniformDistributionSphere(Vector3d center, double radius); void prepare(ParticleState &particle) const; }; /** - @class SourceHomogeneousBox + @class SourceUniformDistributionBox @brief Uniform random source positions inside a box */ -class SourceHomogeneousBox: public SourceProperty { +class SourceUniformDistributionBox: public SourceProperty { Vector3d origin; Vector3d size; public: - SourceHomogeneousBox(Vector3d origin, Vector3d size); + SourceUniformDistributionBox(Vector3d origin, Vector3d size); void prepare(ParticleState &particle) const; }; +/** + @class SourceUniformDistribution1D + @brief Uniform random source positions in for 1D simulations + */ +class SourceUniformDistribution1D: public SourceProperty { + double minDistance, maxDistance; +public: + SourceUniformDistribution1D(double minDistance, double maxDistance); + void prepare(ParticleState& particle) const; +}; + /** @class SourceDensityGrid @brief Provides source positions from a density grid @@ -194,7 +205,7 @@ class SourceIsotropicEmission: public SourceProperty { class SourceDirection: public SourceProperty { Vector3d direction; public: - SourceDirection(Vector3d direction); + SourceDirection(Vector3d direction = Vector3d(-1, 0, 0)); void prepare(ParticleState &particle) const; }; @@ -232,6 +243,20 @@ class SourceUniformRedshift: public SourceProperty { void prepare(Candidate &candidate) const; }; +/** + @class SourceRedshift1D + @brief Redshift according to the distance to 0 + + This source property sets the redshift according to the distance to 0. + It must be added after a position setting source property. + */ +class SourceRedshift1D: public SourceProperty { + ref_ptr redshift; +public: + SourceRedshift1D(Redshift* redshift); + void prepare(Candidate &candidate) const; +}; + }// namespace mpc #endif /* MPC_SOURCE_H */ diff --git a/include/mpc/module/Observer.h b/include/mpc/module/Observer.h index 9b1cd481b..91c14fc6a 100644 --- a/include/mpc/module/Observer.h +++ b/include/mpc/module/Observer.h @@ -63,30 +63,17 @@ class LargeObserverSphere: public Module { }; /** - @class OneDimensionalObserver + @class Observer1D @brief Observer for 1D simulations - Particles are detected once their x-position gets smaller than a given value. - In this case the candidate is by default flagged "Detected" made inactive. + Particles are detected once their x-position gets smaller than a 0. + In this case the candidate is by flagged "Detected" made inactive. This module limits the next step size to prevent candidates from overshooting. */ -class OneDimensionalObserver: public Module { -private: - double xObs; - std::string flag; - std::string flagValue; - bool makeInactive; - void updateDescription(); - +class Observer1D: public Module { public: - OneDimensionalObserver(); - OneDimensionalObserver(double x, std::string flag = - "Detected", std::string flagValue = "", bool makeInactive = true); + Observer1D(); void process(Candidate *candidate) const; - void setPosition(double position); - void setFlag(std::string flag, std::string flagValue); - void setMakeInactive(bool makeInactive); - std::string getDescription() const; }; } // namespace mpc diff --git a/include/mpc/module/Output.h b/include/mpc/module/Output.h index 1440499a3..a5b9b1a4c 100644 --- a/include/mpc/module/Output.h +++ b/include/mpc/module/Output.h @@ -18,7 +18,7 @@ class ShellOutput: public Module { /** @class TrajectoryOutput - @brief Saves trajectories to CSV file. + @brief Saves trajectories to plain text file. */ class TrajectoryOutput: public Module { mutable std::ofstream outfile; @@ -28,27 +28,49 @@ class TrajectoryOutput: public Module { void process(Candidate *candidate) const; }; +/** + @class TrajectoryOutput1D + @brief Saves 1D trajectories to plain text file. + */ +class TrajectoryOutput1D: public Module { + mutable std::ofstream outfile; +public: + TrajectoryOutput1D(std::string name); + ~TrajectoryOutput1D(); + void process(Candidate *candidate) const; +}; + /** @class ConditionalOutput - @brief Saves particles with a given property to a CSV file. + @brief Saves particles with a given property to a plain text file. */ class ConditionalOutput: public Module { mutable std::ofstream outfile; - std::string propertyName; + std::string condition; bool removeProperty; - bool showRedshift; public: - ConditionalOutput(std::string filename, std::string propName = "Detected", - bool removeProperty = false, bool showRedshift = false); + ConditionalOutput(std::string filename, std::string condition = "Detected", + bool removeProperty = false); ~ConditionalOutput(); void setRemoveProperty(bool removeProperty); - void setShowRedshift(bool showRedshift); + void process(Candidate *candidate) const; +}; + +/** + @class EventOutput1D + @brief Records particles that are inactive and have the property 'Detected' to a plain text file. + */ +class EventOutput1D: public Module { + mutable std::ofstream outfile; +public: + EventOutput1D(std::string filename); + ~EventOutput1D(); void process(Candidate *candidate) const; }; /** @class CRPropa2EventOutput - @brief Saves events in CRPropa2 format. + @brief Saves events to a plain text file in CRPropa2 format. */ class CRPropa2EventOutput: public Module { mutable std::ofstream outfile; @@ -60,7 +82,7 @@ class CRPropa2EventOutput: public Module { /** @class CRPropa2TrajectoryOutput - @brief Saves trajectory in CRPropa2 format. + @brief Saves trajectory to a plain text file in CRPropa2 format. */ class CRPropa2TrajectoryOutput: public Module { mutable std::ofstream outfile; diff --git a/python/mpc.i b/python/mpc.i index 688fb6b5b..bddb2591f 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -123,10 +123,6 @@ %include "mpc/ExplicitRungeKutta.h" %include "mpc/PhasePoint.h" -%template(SourceRefPtr) mpc::ref_ptr; -%include "mpc/Source.h" - - %include "mpc/module/BreakCondition.h" %include "mpc/module/Boundary.h" %include "mpc/module/Observer.h" @@ -141,6 +137,8 @@ %include "mpc/module/Redshift.h" %include "mpc/module/Tools.h" +%template(SourceRefPtr) mpc::ref_ptr; +%include "mpc/Source.h" %template(ModuleListRefPtr) mpc::ref_ptr; %include "mpc/ModuleList.h" \ No newline at end of file diff --git a/src/Source.cpp b/src/Source.cpp index 1ab2df348..902922964 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -7,10 +7,10 @@ namespace mpc { -void SourceProperty::prepare(ParticleState &particle) const { +void SourceProperty::prepare(ParticleState& particle) const { } -void SourceProperty::prepare(Candidate &candidate) const { +void SourceProperty::prepare(Candidate& candidate) const { ParticleState &initial = candidate.initial; prepare(initial); candidate.current = initial; @@ -49,7 +49,7 @@ SourceParticleType::SourceParticleType(int id) : id(id) { } -void SourceParticleType::prepare(ParticleState &particle) const { +void SourceParticleType::prepare(ParticleState& particle) const { particle.setId(id); } @@ -57,8 +57,8 @@ SourceEnergy::SourceEnergy(double energy) : E(energy) { } -void SourceEnergy::prepare(ParticleState &particle) const { - particle.setEnergy(E); +void SourceEnergy::prepare(ParticleState& p) const { + p.setEnergy(E); } SourcePowerLawSpectrum::SourcePowerLawSpectrum(double Emin, double Emax, @@ -66,7 +66,7 @@ SourcePowerLawSpectrum::SourcePowerLawSpectrum(double Emin, double Emax, Emin(Emin), Emax(Emax), index(index) { } -void SourcePowerLawSpectrum::prepare(ParticleState &particle) const { +void SourcePowerLawSpectrum::prepare(ParticleState& particle) const { Random &random = Random::instance(); double E = random.randPowerLaw(index, Emin, Emax); particle.setEnergy(E); @@ -79,7 +79,7 @@ void SourceNuclei::add(int id, double a) { abundances.push_back(a); } -void SourceNuclei::prepare(ParticleState &particle) const { +void SourceNuclei::prepare(ParticleState& particle) const { if (ids.size() == 0) throw std::runtime_error("SourceNuclei: no nuclei set"); Random &random = Random::instance(); @@ -145,8 +145,8 @@ SourcePosition::SourcePosition(Vector3d position) : position(position) { } -void SourcePosition::prepare(ParticleState& state) const { - state.setPosition(position); +void SourcePosition::prepare(ParticleState& particle) const { + particle.setPosition(position); } void SourceMultiplePositions::add(Vector3d pos, double lumi) { @@ -156,7 +156,7 @@ void SourceMultiplePositions::add(Vector3d pos, double lumi) { luminosities.push_back(lumi); } -void SourceMultiplePositions::prepare(ParticleState &particle) const { +void SourceMultiplePositions::prepare(ParticleState& particle) const { if (positions.size() == 0) throw std::runtime_error("SourceMultiplePositions: no position set"); double r = Random().rand() * luminosities.back(); @@ -166,41 +166,53 @@ void SourceMultiplePositions::prepare(ParticleState &particle) const { particle.setPosition(positions[i]); } -SourceHomogeneousSphere::SourceHomogeneousSphere(Vector3d c, double r) : - center(c), radius(r) { +SourceUniformDistributionSphere::SourceUniformDistributionSphere( + Vector3d center, double radius) : + center(center), radius(radius) { } -void SourceHomogeneousSphere::prepare(ParticleState &particle) const { +void SourceUniformDistributionSphere::prepare(ParticleState& particle) const { Random &random = Random::instance(); double r = pow(random.rand(), 1. / 3.) * radius; particle.setPosition(random.randUnitVectorOnSphere() * r); } -SourceHomogeneousBox::SourceHomogeneousBox(Vector3d o, Vector3d s) : - origin(o), size(s) { +SourceUniformDistributionBox::SourceUniformDistributionBox(Vector3d origin, + Vector3d size) : + origin(origin), size(size) { } -void SourceHomogeneousBox::prepare(ParticleState &particle) const { +void SourceUniformDistributionBox::prepare(ParticleState& particle) const { Random &random = Random::instance(); Vector3d pos(random.rand(), random.rand(), random.rand()); particle.setPosition(pos * size + origin); } -SourceDensityGrid::SourceDensityGrid(ref_ptr g) { +SourceUniformDistribution1D::SourceUniformDistribution1D(double lo, double hi) : + minDistance(lo), maxDistance(hi) { +} + +void SourceUniformDistribution1D::prepare(ParticleState& particle) const { + Random& random = Random::instance(); + double d = random.rand() * (maxDistance - minDistance) + minDistance; + particle.setPosition(Vector3d(d, 0, 0)); +} + +SourceDensityGrid::SourceDensityGrid(ref_ptr grid) : + grid(grid) { float sum = 0; - for (int ix = 0; ix < g->getNx(); ix++) { - for (int iy = 0; iy < g->getNy(); iy++) { - for (int iz = 0; iz < g->getNz(); iz++) { - sum += g->get(ix, iy, iz); - g->get(ix, iy, iz) = sum; + for (int ix = 0; ix < grid->getNx(); ix++) { + for (int iy = 0; iy < grid->getNy(); iy++) { + for (int iz = 0; iz < grid->getNz(); iz++) { + sum += grid->get(ix, iy, iz); + grid->get(ix, iy, iz) = sum; } } } - grid = g; sumDensity = sum; } -void SourceDensityGrid::prepare(ParticleState &particle) const { +void SourceDensityGrid::prepare(ParticleState& particle) const { Random &random = Random::instance(); // pick random bin; find bin using STL method @@ -219,7 +231,7 @@ void SourceDensityGrid::prepare(ParticleState &particle) const { particle.setPosition(pos); } -void SourceIsotropicEmission::prepare(ParticleState &particle) const { +void SourceIsotropicEmission::prepare(ParticleState& particle) const { Random &random = Random::instance(); particle.setDirection(random.randUnitVectorOnSphere()); } @@ -228,7 +240,7 @@ SourceDirection::SourceDirection(Vector3d direction) : direction(direction) { } -void SourceDirection::prepare(ParticleState &particle) const { +void SourceDirection::prepare(ParticleState& particle) const { particle.setDirection(direction); } @@ -236,7 +248,7 @@ SourceEmissionCone::SourceEmissionCone(Vector3d direction, double aperture) : direction(direction), aperture(aperture) { } -void SourceEmissionCone::prepare(ParticleState &particle) const { +void SourceEmissionCone::prepare(ParticleState& particle) const { Random &random = Random::instance(); particle.setDirection(random.randConeVector(direction, aperture)); } @@ -245,7 +257,7 @@ SourceRedshift::SourceRedshift(double z) : z(z) { } -void SourceRedshift::prepare(Candidate &candidate) const { +void SourceRedshift::prepare(Candidate& candidate) const { candidate.setRedshift(z); } @@ -253,9 +265,19 @@ SourceUniformRedshift::SourceUniformRedshift(double zmin, double zmax) : zmin(zmin), zmax(zmax) { } -void SourceUniformRedshift::prepare(Candidate &candidate) const { +void SourceUniformRedshift::prepare(Candidate& candidate) const { double z = Random::instance().randUniform(zmin, zmax); candidate.setRedshift(z); } +SourceRedshift1D::SourceRedshift1D(Redshift* redishift) : + redshift(redishift) { +} + +void SourceRedshift1D::prepare(Candidate& candidate) const { + double d = candidate.initial.getPosition().getMag(); + double z = redshift->getRedshift(d); + candidate.setRedshift(z); +} + } // namespace mpc diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 99bcf767b..9bc85ceeb 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -45,7 +45,7 @@ xml_node childNode(xml_node parent, string childName, return node; } -SourceHomogeneousBox* loadSourceHomogeneousBox(pugi::xml_node &node) { +SourceUniformDistributionBox* loadSourceHomogeneousBox(pugi::xml_node &node) { Vector3d origin; origin.x = childValue(node, "Xmin_Mpc") * Mpc; origin.y = childValue(node, "Ymin_Mpc") * Mpc; @@ -59,7 +59,7 @@ SourceHomogeneousBox* loadSourceHomogeneousBox(pugi::xml_node &node) { size -= origin; cout << " - Size: " << size / Mpc << endl; - return (new SourceHomogeneousBox(origin, size)); + return (new SourceUniformDistributionBox(origin, size)); } SourceDensityGrid* loadSourceDensityGrid( @@ -457,7 +457,7 @@ void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { new SourceMultiplePositions(); if (type == "Uniform") { - SourceHomogeneousBox* box = loadSourceHomogeneousBox(density_node); + SourceUniformDistributionBox* box = loadSourceHomogeneousBox(density_node); ParticleState p; for (int i = 0; i < nSources; i++) { box->prepare(p); diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp index 3b221daa5..d4c040bdf 100644 --- a/src/module/Observer.cpp +++ b/src/module/Observer.cpp @@ -104,52 +104,19 @@ std::string LargeObserverSphere::getDescription() const { return s.str(); } -OneDimensionalObserver::OneDimensionalObserver() : - xObs(0), flag("Detected"), flagValue(""), makeInactive(true) { +Observer1D::Observer1D() { + setDescription("1D observer"); } -OneDimensionalObserver::OneDimensionalObserver(double x, std::string f, - std::string v, bool b) : - xObs(x), flag(f), flagValue(v), makeInactive(b) { -} - -void OneDimensionalObserver::process(Candidate *c) const { +void Observer1D::process(Candidate *c) const { double x = c->current.getPosition().x; - if (x > xObs) { - c->limitNextStep(x - xObs); - return; // no detection yet + if (x > 0) { + c->limitNextStep(x); + return; } - - double xprev = c->previous.getPosition().x; - if (xprev < xObs) - return; // particle already detected - // else: detection - c->setProperty(flag, flagValue); - if (makeInactive) - c->setActive(false); -} - -void OneDimensionalObserver::setPosition(double x) { - xObs = x; -} - -void OneDimensionalObserver::setFlag(std::string f, std::string v) { - flag = f; - flagValue = v; -} - -void OneDimensionalObserver::setMakeInactive(bool b) { - makeInactive = b; -} - -std::string OneDimensionalObserver::getDescription() const { - std::stringstream s; - s << "1D observer at " << xObs / Mpc << " Mpc"; - s << ", Flag: '" << flag << "' -> '" << flagValue << "'"; - if (makeInactive) - s << ", Inactivate"; - return s.str(); + c->setProperty("Detected", ""); + c->setActive(false); } } // namespace mpc diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 89aba4eb7..2ec036360 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -40,18 +40,43 @@ void TrajectoryOutput::process(Candidate *c) const { } } +TrajectoryOutput1D::TrajectoryOutput1D(std::string filename) { + setDescription("Trajectory output"); + outfile.open(filename.c_str()); + outfile << "# Position(X)[Mpc]\t"; + outfile << "PDG_Code\t"; + outfile << "Energy[EeV]\n"; +} + +TrajectoryOutput1D::~TrajectoryOutput1D() { + outfile.close(); +} + +void TrajectoryOutput1D::process(Candidate *c) const { + char buffer[1024]; + size_t p = 0; + p += sprintf(buffer + p, "%8.4f\t", c->current.getPosition().x / Mpc); + p += sprintf(buffer + p, "%10i\t", c->current.getId()); + p += sprintf(buffer + p, "%8.4f\n", c->current.getEnergy() / EeV); +#pragma omp critical + { + outfile.write(buffer, p); + } +} + ConditionalOutput::ConditionalOutput(std::string filename, std::string propName, - bool removeProperty, bool showRedshift) : - removeProperty(removeProperty), showRedshift(showRedshift) { - setDescription("Conditional output, condition: '" + propName + "'"); - propertyName = propName; + bool removeProperty) : + removeProperty(removeProperty) { + setDescription( + "Conditional output, condition: " + propName + ", filename: " + + filename); + condition = propName; outfile.open(filename.c_str()); outfile << "# PDG_Code\t"; outfile << "Energy[EeV]\t"; outfile << "Position(X,Y,Z)[Mpc]\t"; outfile << "Direction(Phi,Theta)\t"; outfile << "Age[Mpc]\t"; - outfile << "(Redshift)\t"; outfile << "Initial_PDG_Code\t"; outfile << "Initial_Energy[EeV]\t"; outfile << "Initial_Position(X,Y,Z)[Mpc]\t"; @@ -66,12 +91,11 @@ void ConditionalOutput::setRemoveProperty(bool b) { removeProperty = b; } -void ConditionalOutput::setShowRedshift(bool b) { - showRedshift = b; -} - void ConditionalOutput::process(Candidate *c) const { - if (c->hasProperty(propertyName)) { + if (c->hasProperty(condition)) { + if (removeProperty) + c->removeProperty(condition); + char buffer[256]; size_t p = 0; @@ -83,10 +107,6 @@ void ConditionalOutput::process(Candidate *c) const { p += sprintf(buffer + p, "%7.4f\t%7.4f\t", dir.getPhi(), dir.getTheta()); p += sprintf(buffer + p, "%9.4f\t", c->getTrajectoryLength() / Mpc); - - if (showRedshift) - p += sprintf(buffer + p, "%7.4f\t", c->getRedshift()); - p += sprintf(buffer + p, "%10i\t", c->initial.getId()); p += sprintf(buffer + p, "%8.4f\t", c->initial.getEnergy() / EeV); const Vector3d &ipos = c->initial.getPosition() / Mpc; @@ -100,9 +120,39 @@ void ConditionalOutput::process(Candidate *c) const { { outfile.write(buffer, p); } + } +} + +EventOutput1D::EventOutput1D(std::string filename) { + setDescription("Conditional output, Filename: " + filename); + outfile.open(filename.c_str()); + outfile << "# PDG_Code\t"; + outfile << "Energy[EeV]\t"; + outfile << "Age[Mpc]"; + outfile << "Initial_PDG_Code\t"; + outfile << "Initial_Energy[EeV]\n"; +} + +EventOutput1D::~EventOutput1D() { + outfile.close(); +} - if (removeProperty) { - c->removeProperty(propertyName); +void EventOutput1D::process(Candidate *c) const { + if (c->isActive()) + return; + if (c->hasProperty("Detected")) { + char buffer[256]; + size_t p = 0; + + p += sprintf(buffer + p, "%10i\t", c->current.getId()); + p += sprintf(buffer + p, "%8.4f\t", c->current.getEnergy() / EeV); + p += sprintf(buffer + p, "%9.4f\t", c->getTrajectoryLength() / Mpc); + p += sprintf(buffer + p, "%10i\t", c->initial.getId()); + p += sprintf(buffer + p, "%8.4f\n", c->initial.getEnergy() / EeV); + +#pragma omp critical + { + outfile.write(buffer, p); } } } @@ -120,8 +170,6 @@ CRPropa2EventOutput::~CRPropa2EventOutput() { } void CRPropa2EventOutput::process(Candidate *candidate) const { - if (candidate->isActive()) - return; if (candidate->hasProperty("Detected")) { char buffer[256]; // max. 256 characters per line size_t p = 0; // length of line @@ -198,17 +246,18 @@ void CRPropa2TrajectoryOutput::process(Candidate *candidate) const { } } -void ShellOutput::process(Candidate *candidate) const { +void ShellOutput::process(Candidate* c) const { #pragma omp critical { - std::cout << std::fixed << std::showpoint << std::setprecision(2) + std::cout << std::fixed << std::showpoint << std::setprecision(3) << std::setw(6); - std::cout << candidate->getTrajectoryLength() / Mpc << " Mpc, "; - std::cout << candidate->current.getId() << ", "; - std::cout << candidate->current.getEnergy() / EeV << " EeV, "; - std::cout << candidate->current.getPosition() / Mpc << " Mpc, "; - std::cout << candidate->current.getDirection().getPhi() << " "; - std::cout << candidate->current.getDirection().getTheta(); + std::cout << c->getTrajectoryLength() / Mpc << " Mpc, "; + std::cout << c->getRedshift() << ", "; + std::cout << c->current.getId() << ", "; + std::cout << c->current.getEnergy() / EeV << " EeV, "; + std::cout << c->current.getPosition() / Mpc << " Mpc, "; + std::cout << c->current.getDirection().getPhi() << " "; + std::cout << c->current.getDirection().getTheta(); std::cout << std::endl; } } diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index 7033bc638..b21f79888 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -127,8 +127,8 @@ TEST(LargeObserverSphere, limitStep) { EXPECT_DOUBLE_EQ(c.getNextStep(), 2); } -TEST(OneDimensionalObserver, noDetection) { - OneDimensionalObserver obs; // observer at x = 0 +TEST(Observer1D, noDetection) { + Observer1D obs; // observer at x = 0 Candidate c; c.current.setPosition(Vector3d(5, 0, 0)); c.setNextStep(10); @@ -137,8 +137,8 @@ TEST(OneDimensionalObserver, noDetection) { EXPECT_DOUBLE_EQ(5, c.getNextStep()); } -TEST(OneDimensionalObserver, detection) { - OneDimensionalObserver obs; // observer at x = 0 +TEST(Observer1D, detection) { + Observer1D obs; // observer at x = 0 Candidate c; c.current.setPosition(Vector3d(0, 0, 0)); obs.process(&c); diff --git a/test/testSource.cpp b/test/testSource.cpp index 7c596a27b..d11227d3a 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -13,20 +13,20 @@ TEST(SourcePosition, simpleTest) { EXPECT_EQ(position, ps.getPosition()); } -TEST(SourceHomogeneousSphere, simpleTest) { +TEST(SourceUniformDistributionSphere, simpleTest) { Vector3d center(0, 0, 0); double radius = 110; - SourceHomogeneousSphere source(center, radius); + SourceUniformDistributionSphere source(center, radius); ParticleState ps; source.prepare(ps); double distance = ps.getPosition().getDistanceTo(center); EXPECT_GE(radius, distance); } -TEST(SourceHomogeneousBox, simpleTest) { +TEST(SourceUniformDistributionBox, simpleTest) { Vector3d origin(-7, -2, 0); Vector3d size(13, 55, 192); - SourceHomogeneousBox box(origin, size); + SourceUniformDistributionBox box(origin, size); ParticleState p; box.prepare(p); Vector3d pos = p.getPosition(); From dc07cb935100ffe7fd26024e3369c2fedefdc0ea Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 11 Oct 2012 10:34:48 +0200 Subject: [PATCH 0207/1298] fixed interaction test scripts for new data paths --- include/mpc/module/PhotoPionProduction.h | 2 - src/module/ElectronPairProduction.cpp | 5 +- src/module/PhotoPionProduction.cpp | 18 +++--- test/python/testElectronPairProduction.py | 6 +- test/python/testPhotoDisintegration.py | 2 +- test/python/testPhotoPionProduction.py | 16 ++--- test/testInteraction.cpp | 76 +++++++++++++++++++++-- 7 files changed, 93 insertions(+), 32 deletions(-) diff --git a/include/mpc/module/PhotoPionProduction.h b/include/mpc/module/PhotoPionProduction.h index edd307c4d..e12e70de2 100644 --- a/include/mpc/module/PhotoPionProduction.h +++ b/include/mpc/module/PhotoPionProduction.h @@ -30,7 +30,6 @@ class PhotoPionProduction: public StochasticInteraction { bool setNextInteraction(Candidate *candidate, InteractionState &interaction) const; void performInteraction(Candidate *candidate) const; - std::string getDescription() const; }; /** @@ -55,7 +54,6 @@ class SophiaPhotoPionProduction: public PhotoPionProduction { void setHaveNeutrinos(bool b); void setHaveAntiNucleons(bool b); void performInteraction(Candidate *candidate) const; - std::string getDescription() const; }; } // namespace mpc diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 106a47626..acd859103 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -60,6 +60,10 @@ void ElectronPairProduction::init(std::string filename) { } void ElectronPairProduction::process(Candidate *candidate) const { + double Z = candidate->current.getChargeNumber(); + if (Z < 1) + return; + double A = candidate->current.getMassNumber(); double E = candidate->current.getEnergy(); double z = candidate->getRedshift(); @@ -76,7 +80,6 @@ void ElectronPairProduction::process(Candidate *candidate) const { // step size in local frame double step = candidate->getCurrentStep() / (1 + z); - double Z = candidate->current.getChargeNumber(); // dE(E) = Z^2 * loss_rate(E/A) * step double dE = Z * Z * rate * photonFieldScaling(photonField, z) * step; diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 072419879..5855dfda5 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -22,13 +22,17 @@ void PhotoPionProduction::setPhotonField(int p) { } void PhotoPionProduction::init() { - if (photonField == CMB) + if (photonField == CMB) { init(getDataPath("photopion_CMB.txt")); - else if (photonField == IRB) + setDescription("PhotoPionProduction: CMB"); + } + else if (photonField == IRB) { init(getDataPath("photopion_IRB.txt")); + setDescription("PhotoPionProduction: IRB"); + } else throw std::runtime_error( - "PhotoPionProduction: only CMB / IRB possible"); + "PhotoPionProduction: unknown photon background"); } void PhotoPionProduction::init(std::string filename) { @@ -53,10 +57,6 @@ void PhotoPionProduction::init(std::string filename) { infile.close(); } -std::string PhotoPionProduction::getDescription() const { - return "PhotoPionProduction on " + (photonField == CMB)? "CMB" : "IRB"; -} - bool PhotoPionProduction::setNextInteraction(Candidate *candidate, InteractionState &interaction) const { double z = candidate->getRedshift(); @@ -264,8 +264,4 @@ void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { } } -std::string SophiaPhotoPionProduction::getDescription() const { - return "SophiaPhotoPionProduction on " + (photonField == CMB)? "CMB" : "IRB"; -} - } // namespace mpc diff --git a/test/python/testElectronPairProduction.py b/test/python/testElectronPairProduction.py index 3c247e291..8a98fcf30 100644 --- a/test/python/testElectronPairProduction.py +++ b/test/python/testElectronPairProduction.py @@ -33,6 +33,6 @@ def compare(dataFileName, photonField, plotFileName): savefig(plotFileName, bbox_inches='tight') -compare(getDataPath("/ElectronPairProduction/cmb.txt"), CMB, 'ElectronPairProduction_CMB.png') -compare(getDataPath("/ElectronPairProduction/ir.txt"), IRB, 'ElectronPairProduction_IRB.png') -compare(getDataPath("/ElectronPairProduction/cmbir.txt"), CMB_IRB, 'ElectronPairProduction_CMB_IRB.png') \ No newline at end of file +compare(getDataPath('epair_CMB.txt'), CMB, 'ElectronPairProduction_CMB.png') +compare(getDataPath('epair_IRB.txt'), IRB, 'ElectronPairProduction_IRB.png') +compare(getDataPath('epair_CMB_IRB.txt'), CMB_IRB, 'ElectronPairProduction_CMB_IRB.png') diff --git a/test/python/testPhotoDisintegration.py b/test/python/testPhotoDisintegration.py index 3603768b1..f47c7881f 100644 --- a/test/python/testPhotoDisintegration.py +++ b/test/python/testPhotoDisintegration.py @@ -48,7 +48,7 @@ def parse_channel(channel): candidate = Candidate() candidate.current.setId(pid) -table = genfromtxt(getDataPath('PhotoDisintegration/PDtable_CMB.txt')) +table = genfromtxt(getDataPath('photodis_CMB.txt')) pdModule = PhotoDisintegration(CMB) gamma = logspace(6, 14, 200) gamma2 = gamma[1::5] diff --git a/test/python/testPhotoPionProduction.py b/test/python/testPhotoPionProduction.py index da16587d6..0502b4402 100644 --- a/test/python/testPhotoPionProduction.py +++ b/test/python/testPhotoPionProduction.py @@ -15,17 +15,17 @@ def getRate(module, energy, charge): return 1 / l -def compare(type, name): - print "compare ", name - ppp = PhotoPionProduction(type) - E_data, P_data, N_data = genfromtxt(getDataPath('/PhotoPionProduction/PPtable_' + name + '.txt'), unpack=True) - +def compare(dataFileName, photonField, plotFileName): + E_data, P_data, N_data = genfromtxt(dataFileName, unpack=1) E = E_data[1:-1:5] p = zeros(len(E)) n = zeros(len(E)) + + ppp = PhotoPionProduction(photonField) for i,energy in enumerate(E*EeV): p[i] = getRate(ppp, energy, 1) n[i] = getRate(ppp, energy, 0) + figure() plot(E_data, P_data, "r", label="Proton Data") plot(E, p, 'k+', label="Proton Simulated") @@ -38,7 +38,7 @@ def compare(type, name): loglog() xlim(10, 1e5) ylim(1e-4, 1) - savefig('PhotoPionProduction_' + name + '.png', bbox_inches='tight') + savefig(plotFileName) -compare(CMB, "CMB") -compare(IRB, "IRB") +compare(getDataPath('photopion_CMB.txt'), CMB, 'PhotoPionProduction_CMB.png') +compare(getDataPath('photopion_IRB.txt'), IRB, 'PhotoPionProduction_IRB.png') diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index d34b41cd0..2b3a51397 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -52,11 +52,11 @@ TEST(ElectronPairProduction, BelowEnergyTreshold) { EXPECT_DOUBLE_EQ(c.current.getEnergy(), E); } -TEST(ElectronPairProduction, EnergyLossValues) { +TEST(ElectronPairProduction, valuesCMB) { // Test if energy loss corresponds to the data table. std::vector x; std::vector y; - std::ifstream infile(getDataPath("ElectronPairProduction/cmbir.txt").c_str()); + std::ifstream infile(getDataPath("epair_CMB.txt").c_str()); while (infile.good()) { if (infile.peek() != '#') { double a, b; @@ -74,7 +74,71 @@ TEST(ElectronPairProduction, EnergyLossValues) { c.setCurrentStep(1 * Mpc); c.current.setId(getNucleusId(1, 1)); // proton - ElectronPairProduction epp; + ElectronPairProduction epp(CMB); + for (int i = 0; i < x.size(); i++) { + c.current.setEnergy(x[i]); + epp.process(&c); + double dE = x[i] - c.current.getEnergy(); + double dE_table = y[i] * 1 * Mpc; + EXPECT_NEAR(dE, dE_table, 1e-12); + } +} + +TEST(ElectronPairProduction, valuesIRB) { + // Test if energy loss corresponds to the data table. + std::vector x; + std::vector y; + std::ifstream infile(getDataPath("epairIRB.txt").c_str()); + while (infile.good()) { + if (infile.peek() != '#') { + double a, b; + infile >> a >> b; + if (infile) { + x.push_back(a * eV); + y.push_back(b * eV / Mpc); + } + } + infile.ignore(std::numeric_limits::max(), '\n'); + } + infile.close(); + + Candidate c; + c.setCurrentStep(1 * Mpc); + c.current.setId(getNucleusId(1, 1)); // proton + + ElectronPairProduction epp(IRB); + for (int i = 0; i < x.size(); i++) { + c.current.setEnergy(x[i]); + epp.process(&c); + double dE = x[i] - c.current.getEnergy(); + double dE_table = y[i] * 1 * Mpc; + EXPECT_NEAR(dE, dE_table, 1e-12); + } +} + +TEST(ElectronPairProduction, valuesCMB_IRB) { + // Test if energy loss corresponds to the data table. + std::vector x; + std::vector y; + std::ifstream infile(getDataPath("epair_CMB_IRB.txt").c_str()); + while (infile.good()) { + if (infile.peek() != '#') { + double a, b; + infile >> a >> b; + if (infile) { + x.push_back(a * eV); + y.push_back(b * eV / Mpc); + } + } + infile.ignore(std::numeric_limits::max(), '\n'); + } + infile.close(); + + Candidate c; + c.setCurrentStep(1 * Mpc); + c.current.setId(getNucleusId(1, 1)); // proton + + ElectronPairProduction epp(CMB_IRB); for (int i = 0; i < x.size(); i++) { c.current.setEnergy(x[i]); epp.process(&c); @@ -178,7 +242,7 @@ TEST(NuclearDecay, AllWorking) { Candidate c; InteractionState interaction; - std::ifstream infile(getDataPath("/NuclearDecay/decayTable.txt").c_str()); + std::ifstream infile(getDataPath("nuclear_decay.txt").c_str()); while (infile.good()) { if (infile.peek() != '#') { int Z, N, channel, foo; @@ -276,7 +340,7 @@ TEST(PhotoDisintegration, AllWorkingCMB) { InteractionState interaction; std::ifstream infile( - getDataPath("PhotoDisintegration/PDtable_CMB.txt").c_str()); + getDataPath("photodis_CMB.txt").c_str()); std::string line; while (std::getline(infile, line)) { if (line[0] == '#') @@ -309,7 +373,7 @@ TEST(PhotoDisintegration, AllWorkingIRB) { InteractionState interaction; std::ifstream infile( - getDataPath("PhotoDisintegration/PDtable_IRB.txt").c_str()); + getDataPath("photodis_IRB.txt").c_str()); std::string line; while (std::getline(infile, line)) { if (line[0] == '#') From 09533f42a3a2d17167fb3c40d26440c932f4063f Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 11 Oct 2012 10:35:19 +0200 Subject: [PATCH 0208/1298] SimplePropagation improve description --- include/mpc/module/SimplePropagation.h | 4 +++- src/module/SimplePropagation.cpp | 13 ++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/mpc/module/SimplePropagation.h b/include/mpc/module/SimplePropagation.h index 3566e5a52..8677d39b8 100644 --- a/include/mpc/module/SimplePropagation.h +++ b/include/mpc/module/SimplePropagation.h @@ -17,8 +17,10 @@ class SimplePropagation: public Module { double minStep, maxStep; public: - SimplePropagation(double minStep = 0.1 * kpc, double maxStep = 4000 * Mpc); + SimplePropagation(double minStep = 0, double maxStep = 4000 * Mpc); void process(Candidate *candidate) const; + void setMinimumStep(double minStep); + void setMaximumStep(double maxStep); std::string getDescription() const; }; diff --git a/src/module/SimplePropagation.cpp b/src/module/SimplePropagation.cpp index cfa02db72..350152674 100644 --- a/src/module/SimplePropagation.cpp +++ b/src/module/SimplePropagation.cpp @@ -6,6 +6,14 @@ SimplePropagation::SimplePropagation(double minStep, double maxStep) : minStep(minStep), maxStep(maxStep) { } +void SimplePropagation::setMinimumStep(double s) { + minStep = s; +} + +void SimplePropagation::setMaximumStep(double s) { + maxStep = s; +} + void SimplePropagation::process(Candidate *candidate) const { // save the new previous particle state candidate->previous = candidate->current; @@ -21,7 +29,10 @@ void SimplePropagation::process(Candidate *candidate) const { } std::string SimplePropagation::getDescription() const { - return "Simple Propagation"; + std::stringstream s; + s << "Simple Propagation: Step size = " << minStep / Mpc + << " - " << maxStep / Mpc << " Mpc"; + return s.str(); } } // namespace mpc From 826cf3d73f54c4bd6e98851eb86e23dc6abbb5b3 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 11 Oct 2012 16:14:38 +0200 Subject: [PATCH 0209/1298] sane(r) defaults for SimplePropagation --- include/mpc/Random.h | 2 +- include/mpc/Source.h | 30 ++++++++++++++++++++++---- include/mpc/module/SimplePropagation.h | 2 +- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/include/mpc/Random.h b/include/mpc/Random.h index 107642dcd..0e4018346 100644 --- a/include/mpc/Random.h +++ b/include/mpc/Random.h @@ -141,7 +141,7 @@ class Random { /// Uniform distributed random vector inside a cone Vector3d randConeVector(const Vector3d &meanDirection, double angularRadius); - /// Power-Law distribution, not possible for index == -1 + /// Power-law distribution of a given differential spectral index double randPowerLaw(double index, double min, double max); /// Broken power-law distribution double randBrokenPowerLaw(double index1, double index2, double breakpoint, double min, double max ); diff --git a/include/mpc/Source.h b/include/mpc/Source.h index 8edfcb212..d9fe23436 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -79,7 +79,13 @@ class SourcePowerLawSpectrum: public SourceProperty { double Emax; double index; public: + /** Constructor + @param Emin minimum energy + @param Emax maximum energy + @param index differential spectral index + */ SourcePowerLawSpectrum(double Emin, double Emax, double index); + /** Set particle with a random energy from a power law distribtuition */ void prepare(ParticleState &particle) const; }; @@ -97,7 +103,7 @@ class SourceNuclei: public SourceProperty { /** @class SourceComposition - @brief Nuclei with given abundances and a uniform power law spectrum from Emin to Z * Rmax + @brief Nuclei with given abundances and a uniform power law spectrum between Emin and Z * Rmax */ class SourceComposition: public SourceProperty { double Emin; @@ -106,12 +112,28 @@ class SourceComposition: public SourceProperty { std::vector isotope; /**< isotope id */ std::vector abundance; /**< relative abundance of source isotopes at equal energies */ std::vector probability; /**< cumulative probability of source isotopes */ + void normalize(); + double getSpectrumIntegral(int Z) const; + public: + /** Constructor + @param Emin minimum energy for cosmic rays + @param Rmax maximum rigidity for cosmic rays + @param index differential spectral index + */ SourceComposition(double Emin, double Rmax, double index); - double getSpectrumIntegral(int Z = 1) const; + /** Add a species to the composition + @param id particle id + @param abundance absolute or relative abundance at a fixed value of energy/nucleons + */ void add(int id, double abundance); + /** Add a species to the composition + @param A mass number + @param Z charge number + @param abundance absolute or relative abundance at a fixed value of energy/nucleons + */ void add(int A, int Z, double abundance); - void normalize(); + /** Randomly select a species and energy */ void prepare(ParticleState &particle) const; }; @@ -120,7 +142,7 @@ class SourceComposition: public SourceProperty { @brief Position of a point source */ class SourcePosition: public SourceProperty { - Vector3d position; + Vector3d position; /**< Source position */ public: SourcePosition(Vector3d position); void prepare(ParticleState &state) const; diff --git a/include/mpc/module/SimplePropagation.h b/include/mpc/module/SimplePropagation.h index 8677d39b8..aed69442e 100644 --- a/include/mpc/module/SimplePropagation.h +++ b/include/mpc/module/SimplePropagation.h @@ -17,7 +17,7 @@ class SimplePropagation: public Module { double minStep, maxStep; public: - SimplePropagation(double minStep = 0, double maxStep = 4000 * Mpc); + SimplePropagation(double minStep = 0, double maxStep = 10 * Mpc); void process(Candidate *candidate) const; void setMinimumStep(double minStep); void setMaximumStep(double maxStep); From 2100c76e413b4fb06a3f7d0ff068883f171b72f6 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 24 Oct 2012 17:14:07 +0200 Subject: [PATCH 0210/1298] fixed bug in Grid --- include/mpc/Grid.h | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/include/mpc/Grid.h b/include/mpc/Grid.h index 41430da31..0e25862b2 100644 --- a/include/mpc/Grid.h +++ b/include/mpc/Grid.h @@ -7,13 +7,13 @@ namespace mpc { -// Lower and upper neighbor in a periodically continued unit grid +/** Lower and upper neighbor in a periodically continued unit grid */ inline void periodicClamp(double x, int n, int &lo, int &hi) { lo = ((int(floor(x)) % n) + n) % n; hi = (lo + 1) % n; } -// Lower and upper neighbor in a reflectively repeated unit grid +/** Lower and upper neighbor in a reflectively repeated unit grid */ inline void reflectiveClamp(double x, int n, int &lo, int &hi) { while ((x < 0) or (x > n)) x = 2 * n * (x > n) - x; @@ -39,6 +39,11 @@ class Grid: public Referenced { bool reflective; /**< If set to true, the grid is repeated reflectively instead of periodically */ public: + /** Constructor for cubic grid + @param origin Position of the lower, left, front grid point + @param N Number of grid points in one direction + @param spacing Spacing between grid points + */ Grid(Vector3d origin, size_t N, double spacing) { setOrigin(origin); setGridSize(N, N, N); @@ -46,6 +51,13 @@ class Grid: public Referenced { setReflective(false); } + /** Constructor for non-cubic grid + @param origin Position of the lower, left, front grid point + @param Nx Number of grid points in x-direction + @param Ny Number of grid points in y-direction + @param Nz Number of grid points in z-direction + @param spacing Spacing between grid points + */ Grid(Vector3d origin, size_t Nx, size_t Ny, size_t Nz, double spacing) { setOrigin(origin); @@ -58,6 +70,7 @@ class Grid: public Referenced { this->origin = origin; } + /** Resize grid */ void setGridSize(size_t Nx, size_t Ny, size_t Nz) { this->Nx = Nx; this->Ny = Ny; @@ -98,19 +111,20 @@ class Grid: public Referenced { /** Accessor / Mutator */ T &get(size_t ix, size_t iy, size_t iz) { - return grid[ix * Ny * Nz + iy * Ny + iz]; + return grid[ix * Ny * Nz + iy * Nz + iz]; } /** Accessor */ const T &get(size_t ix, size_t iy, size_t iz) const { - return grid[ix * Ny * Nz + iy * Ny + iz]; + return grid[ix * Ny * Nz + iy * Nz + iz]; } + /** Return a reference to the grid values */ std::vector &getGrid() { return grid; } - // return the position corresponding to a given grid index + /** Position of the grid point of a given index */ Vector3d getPosition(int index) const { int ix = index / (Ny * Nz); int iy = (index / Nz) % Ny; From e29934cd52990b28238f3ae33dc2301a658daa55 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 24 Oct 2012 17:48:24 +0200 Subject: [PATCH 0211/1298] improved Grid related tests and moved them to testCore --- test/testCore.cpp | 174 +++++++++++++++++++++++++++++++++++++ test/testMagneticField.cpp | 155 --------------------------------- 2 files changed, 174 insertions(+), 155 deletions(-) diff --git a/test/testCore.cpp b/test/testCore.cpp index ee21c1163..0721bb580 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -7,6 +7,8 @@ #include "mpc/Candidate.h" #include "mpc/Random.h" +#include "mpc/Grid.h" +#include "mpc/GridTools.h" #include "gtest/gtest.h" @@ -208,6 +210,178 @@ TEST(Random, seed) { EXPECT_EQ(r1, r3); } +TEST(Grid, PeriodicClamp) { + // Test correct determination of lower and upper neighbor + int lo, hi; + + periodicClamp(23.12, 8, lo, hi); + EXPECT_EQ(7, lo); + EXPECT_EQ(0, hi); + + periodicClamp(-23.12, 8, lo, hi); + EXPECT_EQ(0, lo); + EXPECT_EQ(1, hi); +} + +TEST(ScalarGrid, SimpleTest) { + // Test construction and parameters + size_t Nx = 5; + size_t Ny = 8; + size_t Nz = 10; + double spacing = 2.0; + Vector3d origin(1., 2., 3.); + + ScalarGrid grid(origin, Nx, Ny, Nz, spacing); + + EXPECT_TRUE(origin == grid.getOrigin()); + EXPECT_EQ(Nx, grid.getNx()); + EXPECT_EQ(Ny, grid.getNy()); + EXPECT_EQ(Nz, grid.getNz()); + EXPECT_DOUBLE_EQ(spacing, grid.getSpacing()); + EXPECT_EQ(5 * 8 * 10, grid.getGrid().size()); + + // Test index handling: get position of grid point (2, 3, 4) + size_t some_index = 2 * Ny * Nz + 3 * Nz + 4; + Vector3d position = origin + Vector3d(2, 3, 4) * spacing; + EXPECT_EQ(position, grid.getPosition(some_index)); + + grid.get(2, 3, 4) = 7; + EXPECT_FLOAT_EQ(7., grid.getGrid()[some_index]); + EXPECT_FLOAT_EQ(7., grid.interpolate(position)); +} + +TEST(VectorGrid, Interpolation) { + // Explicitly test trilinear interpolation + double spacing = 2.793; + VectorGrid grid(Vector3d(0.), 3, spacing); + grid.get(0, 0, 1) = Vector3f(1.7, 0., 0.); // set one value + + Vector3d b; + b = grid.interpolate(Vector3d(0, 0, 1) * spacing); + EXPECT_FLOAT_EQ(1.7, b.x); + + b = grid.interpolate(Vector3d(0, 0, 0.9) * spacing); + EXPECT_FLOAT_EQ(1.7 * 0.9, b.x); + + b = grid.interpolate(Vector3d(0, 0, 1.1) * spacing); + EXPECT_FLOAT_EQ(1.7 * 0.9, b.x); + + b = grid.interpolate(Vector3d(0, 0.15, 0.9) * spacing); + EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.85, b.x); + + b = grid.interpolate(Vector3d(0, 2.15, 0.9) * spacing); + EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.15, b.x); +} + +TEST(VectordGrid, Scale) { + // Test scaling a field + ref_ptr grid = new VectorGrid(Vector3d(0.), 3, 1); + for (int ix = 0; ix < 3; ix++) + for (int iy = 0; iy < 3; iy++) + for (int iz = 0; iz < 3; iz++) + grid->get(ix, iy, iz) = Vector3f(1, 0, 0); + + scale(grid, 5); + for (int ix = 0; ix < 3; ix++) + for (int iy = 0; iy < 3; iy++) + for (int iz = 0; iz < 3; iz++) + EXPECT_FLOAT_EQ(5, grid->interpolate(Vector3d(0.7, 0, 0.1)).x); +} + +TEST(VectorGrid, Periodicity) { + // Test for periodic boundaries: grid(x+a*n) = grid(x) + size_t n = 3; + double spacing = 3; + double size = n * spacing; + VectorGrid grid(Vector3d(0.), n, spacing); + for (int ix = 0; ix < 3; ix++) + for (int iy = 0; iy < 3; iy++) + for (int iz = 0; iz < 3; iz++) + grid.get(ix, iy, iz) = Vector3f(iz + ix, iy * iz, ix - iz * iy); + + Vector3d pos(1.2, 2.3, 0.7); + Vector3f b = grid.interpolate(pos); + Vector3f b2 = grid.interpolate(pos + Vector3d(1, 0, 0) * size); + EXPECT_FLOAT_EQ(b.x, b2.x); + EXPECT_FLOAT_EQ(b.y, b2.y); + EXPECT_FLOAT_EQ(b.z, b2.z); + + b2 = grid.interpolate(pos + Vector3d(0, 5, 0) * size); + EXPECT_FLOAT_EQ(b.x, b2.x); + EXPECT_FLOAT_EQ(b.y, b2.y); + EXPECT_FLOAT_EQ(b.z, b2.z); + + b2 = grid.interpolate(pos + Vector3d(0, 0, -2) * size); + EXPECT_FLOAT_EQ(b.x, b2.x); + EXPECT_FLOAT_EQ(b.y, b2.y); + EXPECT_FLOAT_EQ(b.z, b2.z); +} + +TEST(VectorGrid, DumpLoad) { + // Dump and load a field grid + ref_ptr grid1 = new VectorGrid(Vector3d(0.), 3, 1); + ref_ptr grid2 = new VectorGrid(Vector3d(0.), 3, 1); + + for (int ix = 0; ix < 3; ix++) + for (int iy = 0; iy < 3; iy++) + for (int iz = 0; iz < 3; iz++) + grid1->get(ix, iy, iz) = Vector3f(1, 2, 3); + + dumpGrid(grid1, "testDump.raw"); + loadGrid(grid2, "testDump.raw"); + + for (int ix = 0; ix < 3; ix++) { + for (int iy = 0; iy < 3; iy++) { + for (int iz = 0; iz < 3; iz++) { + Vector3f b1 = grid1->get(ix, iy, iz); + Vector3f b2 = grid2->get(ix, iy, iz); + EXPECT_FLOAT_EQ(b1.x, b2.x); + EXPECT_FLOAT_EQ(b1.y, b2.y); + EXPECT_FLOAT_EQ(b1.z, b2.z); + } + } + } +} + +TEST(VectorGrid, DumpLoadTxt) { + // Dump and load a field grid + ref_ptr grid1 = new VectorGrid(Vector3d(0.), 3, 1); + ref_ptr grid2 = new VectorGrid(Vector3d(0.), 3, 1); + + for (int ix = 0; ix < 3; ix++) + for (int iy = 0; iy < 3; iy++) + for (int iz = 0; iz < 3; iz++) + grid1->get(ix, iy, iz) = Vector3f(ix, iy, iz); + + dumpGridToTxt(grid1, "testDump.txt", 1e4); + loadGridFromTxt(grid2, "testDump.txt", 1e-4); + + for (int ix = 0; ix < 3; ix++) { + for (int iy = 0; iy < 3; iy++) { + for (int iz = 0; iz < 3; iz++) { + Vector3f b1 = grid1->get(ix, iy, iz); + Vector3f b2 = grid2->get(ix, iy, iz); + EXPECT_FLOAT_EQ(b1.x, b2.x); + EXPECT_FLOAT_EQ(b1.y, b2.y); + EXPECT_FLOAT_EQ(b1.z, b2.z); + } + } + } +} + +TEST(VectorGrid, Speed) { + // Dump and load a field grid + VectorGrid grid(Vector3d(0.), 3, 3); + for (int ix = 0; ix < 3; ix++) + for (int iy = 0; iy < 3; iy++) + for (int iz = 0; iz < 3; iz++) + grid.get(ix, iy, iz) = Vector3f(1, 2, 3); + + Vector3d b; + for (int i = 0; i < 100000; i++) + b = grid.interpolate(Vector3d(i)); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index c033f36fe..83a102d66 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -29,161 +29,6 @@ TEST(testMagneticFieldList, SimpleTest) { EXPECT_DOUBLE_EQ(b.z, 3); } -TEST(testVectorFieldGrid, PeriodicClamp) { - // Test correct determination of lower and upper neighbor - int lo, hi; - - periodicClamp(23.12, 8, lo, hi); - EXPECT_EQ(7, lo); - EXPECT_EQ(0, hi); - - periodicClamp(-23.12, 8, lo, hi); - EXPECT_EQ(0, lo); - EXPECT_EQ(1, hi); -} - -TEST(testVectorFieldGrid, SimpleTest) { - // Test construction and parameters - VectorGrid B(Vector3d(1., 2., 3.), 4, 2.5); - EXPECT_TRUE(Vector3d(1., 2., 3.) == B.getOrigin()); - EXPECT_EQ(4, B.getNx()); - EXPECT_EQ(4, B.getNy()); - EXPECT_EQ(4, B.getNz()); - EXPECT_DOUBLE_EQ(2.5, B.getSpacing()); -} - -TEST(testVectorFieldGrid, Interpolation) { - // Explicitly test trilinear interpolation - double spacing = 2.793; - VectorGrid grid(Vector3d(0.), 3, spacing); - grid.get(0, 0, 1) = Vector3f(1.7, 0., 0.); // set one value - - Vector3d b; - b = grid.interpolate(Vector3d(0, 0, 1) * spacing); - EXPECT_FLOAT_EQ(1.7, b.x); - - b = grid.interpolate(Vector3d(0, 0, 0.9) * spacing); - EXPECT_FLOAT_EQ(1.7 * 0.9, b.x); - - b = grid.interpolate(Vector3d(0, 0, 1.1) * spacing); - EXPECT_FLOAT_EQ(1.7 * 0.9, b.x); - - b = grid.interpolate(Vector3d(0, 0.15, 0.9) * spacing); - EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.85, b.x); - - b = grid.interpolate(Vector3d(0, 2.15, 0.9) * spacing); - EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.15, b.x); -} - -TEST(testVectorFieldGrid, Scale) { - // Test scaling a field - ref_ptr grid = new VectorGrid(Vector3d(0.), 3, 1); - for (int ix = 0; ix < 3; ix++) - for (int iy = 0; iy < 3; iy++) - for (int iz = 0; iz < 3; iz++) - grid->get(ix, iy, iz) = Vector3f(1, 0, 0); - - scale(grid, 5); - for (int ix = 0; ix < 3; ix++) - for (int iy = 0; iy < 3; iy++) - for (int iz = 0; iz < 3; iz++) - EXPECT_FLOAT_EQ(5, grid->interpolate(Vector3d(0.7, 0, 0.1)).x); -} - -TEST(testVectorFieldGrid, Periodicity) { - // Test for periodic boundaries: B(x+a*n) = B(x) - size_t n = 3; - double spacing = 3; - double size = n * spacing; - VectorGrid grid(Vector3d(0.), n, spacing); - for (int ix = 0; ix < 3; ix++) - for (int iy = 0; iy < 3; iy++) - for (int iz = 0; iz < 3; iz++) - grid.get(ix, iy, iz) = Vector3f(iz + ix, iy * iz, ix - iz * iy); - - Vector3d pos(1.2, 2.3, 0.7); - Vector3f b = grid.interpolate(pos); - Vector3f b2 = grid.interpolate(pos + Vector3d(1, 0, 0) * size); - EXPECT_FLOAT_EQ(b.x, b2.x); - EXPECT_FLOAT_EQ(b.y, b2.y); - EXPECT_FLOAT_EQ(b.z, b2.z); - - b2 = grid.interpolate(pos + Vector3d(0, 5, 0) * size); - EXPECT_FLOAT_EQ(b.x, b2.x); - EXPECT_FLOAT_EQ(b.y, b2.y); - EXPECT_FLOAT_EQ(b.z, b2.z); - - b2 = grid.interpolate(pos + Vector3d(0, 0, -2) * size); - EXPECT_FLOAT_EQ(b.x, b2.x); - EXPECT_FLOAT_EQ(b.y, b2.y); - EXPECT_FLOAT_EQ(b.z, b2.z); -} - -TEST(testVectorFieldGrid, DumpLoad) { - // Dump and load a field grid - ref_ptr B1 = new VectorGrid(Vector3d(0.), 3, 1); - for (int ix = 0; ix < 3; ix++) - for (int iy = 0; iy < 3; iy++) - for (int iz = 0; iz < 3; iz++) - B1->get(ix, iy, iz) = Vector3f(1, 2, 3); - - dumpGrid(B1, "testDump.raw"); - - ref_ptr B2 = new VectorGrid(Vector3d(0.), 3, 1); - loadGrid(B2, "testDump.raw"); - - for (int ix = 0; ix < 3; ix++) { - for (int iy = 0; iy < 3; iy++) { - for (int iz = 0; iz < 3; iz++) { - Vector3f b1 = B1->get(ix, iy, iz); - Vector3f b2 = B2->get(ix, iy, iz); - EXPECT_FLOAT_EQ(b1.x, b2.x); - EXPECT_FLOAT_EQ(b1.y, b2.y); - EXPECT_FLOAT_EQ(b1.z, b2.z); - } - } - } -} - -TEST(testVectorFieldGrid, DumpLoadTxt) { - // Dump and load a field grid - ref_ptr B1 = new VectorGrid(Vector3d(0.), 3, 1); - for (int ix = 0; ix < 3; ix++) - for (int iy = 0; iy < 3; iy++) - for (int iz = 0; iz < 3; iz++) - B1->get(ix, iy, iz) = Vector3f(ix, iy, iz) * nG; - - dumpGridToTxt(B1, "testDump.txt", 1e4); - - ref_ptr B2 = new VectorGrid(Vector3d(0.), 3, 1); - loadGridFromTxt(B2, "testDump.txt", 1e-4); - - for (int ix = 0; ix < 3; ix++) { - for (int iy = 0; iy < 3; iy++) { - for (int iz = 0; iz < 3; iz++) { - Vector3f b1 = B1->get(ix, iy, iz); - Vector3f b2 = B2->get(ix, iy, iz); - EXPECT_FLOAT_EQ(b1.x, b2.x); - EXPECT_FLOAT_EQ(b1.y, b2.y); - EXPECT_FLOAT_EQ(b1.z, b2.z); - } - } - } -} - -TEST(testVectorFieldGrid, Speed) { - // Dump and load a field grid - VectorGrid grid(Vector3d(0.), 3, 3); - for (int ix = 0; ix < 3; ix++) - for (int iy = 0; iy < 3; iy++) - for (int iz = 0; iz < 3; iz++) - grid.get(ix, iy, iz) = Vector3f(1, 2, 3); - - Vector3d b; - for (int i = 0; i < 100000; i++) - b = grid.interpolate(Vector3d(i)); -} - #ifdef MPC_HAVE_FFTW3F TEST(testVectorFieldGrid, Turbulence_bmean_brms) { // Test for zero mean: = 0 From f031a6ea51eaf4122995cf98e67771b5bbbf8b94 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 24 Oct 2012 18:10:37 +0200 Subject: [PATCH 0212/1298] added SourceDensityGrid1D + tests --- include/mpc/Source.h | 20 +++++++++++++++++++- src/Source.cpp | 32 ++++++++++++++++++++++++++++++++ test/testSource.cpp | 40 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 90 insertions(+), 2 deletions(-) diff --git a/include/mpc/Source.h b/include/mpc/Source.h index d9fe23436..f825dc756 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -200,7 +200,8 @@ class SourceUniformDistribution1D: public SourceProperty { @brief Provides source positions from a density grid This module takes a density grid to compute random initial positions. - First a discrete bin is drawn following the density distribution. + The positions of the grid points are interpreted as bin centers, the values as source density in the bin. + To dial a source position, first a bin is drawn following the density distribution. Then a random position is drawn from a uniform distribution in the bin. */ class SourceDensityGrid: public SourceProperty { @@ -211,6 +212,23 @@ class SourceDensityGrid: public SourceProperty { void prepare(ParticleState &particle) const; }; +/** + @class SourceDensityGrid1D + @brief Provides source positions from a 1D density grid + + This module takes a N*1*1 grid to compute random initial positions. + The positions of the grid points are interpreted as bin centers, the values as source density in the bin. + To dial a source position, first a bin is drawn following the density distribution. + Then a random position is drawn from a uniform distribution in the bin. + */ +class SourceDensityGrid1D: public SourceProperty { + ref_ptr grid; + float sumDensity; +public: + SourceDensityGrid1D(ref_ptr densityGrid); + void prepare(ParticleState &particle) const; +}; + /** @class SourceIsotropicEmission @brief Isotropic emission from a source diff --git a/src/Source.cpp b/src/Source.cpp index 902922964..60bac8c84 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -231,6 +231,38 @@ void SourceDensityGrid::prepare(ParticleState& particle) const { particle.setPosition(pos); } +SourceDensityGrid1D::SourceDensityGrid1D(ref_ptr grid) : + grid(grid) { + if (grid->getNy() != 1) + throw std::runtime_error("SourceDensityGrid1D: Ny != 1"); + if (grid->getNz() != 1) + throw std::runtime_error("SourceDensityGrid1D: Nz != 1"); + + float sum = 0; + for (int ix = 0; ix < grid->getNx(); ix++) { + sum += grid->get(ix, 0, 0); + grid->get(ix, 0, 0) = sum; + } + sumDensity = sum; +} + +void SourceDensityGrid1D::prepare(ParticleState& particle) const { + Random &random = Random::instance(); + + // pick random bin; find bin using STL method + double r = random.rand(sumDensity); + std::vector &v = grid->getGrid(); + std::vector::iterator it = lower_bound(v.begin(), v.end(), r); + int i = it - v.begin(); + Vector3d pos = grid->getPosition(i); + + // draw uniform position within bin + double dx = random.rand() - 0.5; + pos += Vector3d(dx, 0, 0) * grid->getSpacing(); + + particle.setPosition(pos); +} + void SourceIsotropicEmission::prepare(ParticleState& particle) const { Random &random = Random::instance(); particle.setDirection(random.randUnitVectorOnSphere()); diff --git a/test/testSource.cpp b/test/testSource.cpp index d11227d3a..e493e5cb2 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -38,7 +38,7 @@ TEST(SourceUniformDistributionBox, simpleTest) { EXPECT_GE(size.z, pos.z); } -TEST(SourceDensityGrid, simpleTest) { +TEST(SourceDensityGrid, withInRange) { // Create a grid with 10^3 cells ranging from (0, 0, 0) to (10, 10, 10) Vector3d origin(0.5, 0.5, 0.5); int cells = 10; @@ -104,6 +104,44 @@ TEST(SourceDensityGrid, OneAllowedCell) { EXPECT_NEAR(1, mean.z, 0.1); } +TEST(SourceDensityGrid1D, withInRange) { + // Create a grid with 10 cells ranging from 0 to 10 + Vector3d origin(0.5, 0, 0); + ref_ptr grid = new ScalarGrid(origin, 10, 1, 1, 1.0); + + for (int i = 0; i < 10; i++) { + grid->get(i, 0, 0) = 2; + } + + SourceDensityGrid1D source(grid); + ParticleState p; + + source.prepare(p); + Vector3d pos = p.getPosition(); + // dialed position should be within the range 0 - 10 + EXPECT_LE(0, pos.x); + EXPECT_GE(10, pos.x); +} + +TEST(SourceDensityGrid1D, OneAllowedCell) { + Vector3d origin(0.5, 0, 0); + ref_ptr grid = new ScalarGrid(origin, 10, 1, 1, 1.0); + for (int i = 0; i < 10; i++) { + grid->get(i, 0, 0) = 2; + } + + grid->get(5, 0, 0); + + SourceDensityGrid1D source(grid); + ParticleState p; + + source.prepare(p); + Vector3d pos = p.getPosition(); + // dialed position should be within the range 0 - 10 + EXPECT_LE(0, pos.x); + EXPECT_GE(10, pos.x); +} + TEST(SourcePowerLawSpectrum, simpleTest) { double Emin = 4 * EeV; double Emax = 200 * EeV; From 7baa097b3789d905b8daa3b2e1fbb2bca24d6b35 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 24 Oct 2012 18:14:49 +0200 Subject: [PATCH 0213/1298] fixed a test for SourceDensityGrid1D --- test/testSource.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/test/testSource.cpp b/test/testSource.cpp index e493e5cb2..278c13cca 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -127,19 +127,16 @@ TEST(SourceDensityGrid1D, OneAllowedCell) { Vector3d origin(0.5, 0, 0); ref_ptr grid = new ScalarGrid(origin, 10, 1, 1, 1.0); for (int i = 0; i < 10; i++) { - grid->get(i, 0, 0) = 2; + grid->get(i, 0, 0) = 0; } - - grid->get(5, 0, 0); - + grid->get(5, 0, 0) = 1; SourceDensityGrid1D source(grid); ParticleState p; - source.prepare(p); + // dialed position should be in range 5-6 Vector3d pos = p.getPosition(); - // dialed position should be within the range 0 - 10 - EXPECT_LE(0, pos.x); - EXPECT_GE(10, pos.x); + EXPECT_LE(5, pos.x); + EXPECT_GE(6, pos.x); } TEST(SourcePowerLawSpectrum, simpleTest) { From 6a293014a1a05881e3be3dd4ef079f5a961e2c9e Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 30 Oct 2012 12:16:21 +0100 Subject: [PATCH 0214/1298] energyLossLength for PhotoDisintegration --- include/mpc/module/PhotoDisintegration.h | 14 +++++++-- src/module/PhotoDisintegration.cpp | 39 ++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/include/mpc/module/PhotoDisintegration.h b/include/mpc/module/PhotoDisintegration.h index 437e10174..348922f55 100644 --- a/include/mpc/module/PhotoDisintegration.h +++ b/include/mpc/module/PhotoDisintegration.h @@ -17,7 +17,7 @@ namespace mpc { */ class PhotoDisintegration: public StochasticInteraction { private: - int photonField; + PhotonField photonField; struct PDMode { int channel; // number of emitted (n, p, H2, H3, He3, He4) std::vector rate; // disintegration rate [1/m] @@ -25,12 +25,20 @@ class PhotoDisintegration: public StochasticInteraction { std::vector > pdTable; // pdTable[Z * 31 + N] = vector public: - PhotoDisintegration(int photonField = CMB); - void init(int photonField); + PhotoDisintegration(PhotonField photonField = CMB); + void init(PhotonField photonField); void init(std::string filename); bool setNextInteraction(Candidate *candidate, InteractionState &interaction) const; void performInteraction(Candidate *candidate) const; + + + /** + Calculates the energy loss length 1/E dE/dx in [m] + @param id PDG particle id + @param energy particle energy [J] + */ + double energyLossLength(int id, double energy); }; } // namespace mpc diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 7ffb3320a..e6faecdd5 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -8,11 +8,11 @@ namespace mpc { -PhotoDisintegration::PhotoDisintegration(int photonField) { +PhotoDisintegration::PhotoDisintegration(PhotonField photonField) { init(photonField); } -void PhotoDisintegration::init(int photonField) { +void PhotoDisintegration::init(PhotonField photonField) { this->photonField = photonField; switch (photonField) { case CMB: @@ -147,4 +147,39 @@ void PhotoDisintegration::performInteraction(Candidate *candidate) const { candidate->addSecondary(getNucleusId(4, 2), EpA * 4); } +double PhotoDisintegration::energyLossLength(int id, double E) { + int A = getMassNumberFromNucleusId(id); + int Z = getChargeNumberFromNucleusId(id); + int N = A - Z; + + std::vector pdModes = pdTable[Z * 31 + N]; + if (pdModes.size() == 0) + return 0; + + // log10 of lorentz factor + double lg = log10(E / (getNucleusMass(id) * c_squared)); + if ((lg <= 6) or (lg >= 14)) + return 0; + + double lossRate = 0; + for (size_t i = 0; i < pdModes.size(); i++) { + double rate = interpolateEquidistant(lg, 6, 14, pdModes[i].rate); + + int channel = pdModes[i].channel; + int nN = digit(channel, 100000); + int nP = digit(channel, 10000); + int nH2 = digit(channel, 1000); + int nH3 = digit(channel, 100); + int nHe3 = digit(channel, 10); + int nHe4 = digit(channel, 1); + + double relativeEnergyLoss = double( + nN + nP + 2 * nH2 + 3 * nH3 + 3 * nHe3 + 4 * nHe4) / double(A); + + lossRate += rate * relativeEnergyLoss; + } + + return 1 / lossRate; +} + } // namespace mpc From 137038bbed16a5ef9a0754576e63864ee562a073 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 30 Oct 2012 14:55:15 +0100 Subject: [PATCH 0215/1298] energyLossLength for PhotoPionProduction --- include/mpc/module/PhotoPionProduction.h | 7 +++++ src/module/PhotoDisintegration.cpp | 4 +-- src/module/PhotoPionProduction.cpp | 35 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/include/mpc/module/PhotoPionProduction.h b/include/mpc/module/PhotoPionProduction.h index e12e70de2..9e67c6019 100644 --- a/include/mpc/module/PhotoPionProduction.h +++ b/include/mpc/module/PhotoPionProduction.h @@ -30,6 +30,13 @@ class PhotoPionProduction: public StochasticInteraction { bool setNextInteraction(Candidate *candidate, InteractionState &interaction) const; void performInteraction(Candidate *candidate) const; + + /** + Calculates the energy loss length 1/E dE/dx in [m] + @param id PDG particle id + @param energy particle energy [J] + */ + double energyLossLength(int id, double energy); }; /** diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index e6faecdd5..cdb545090 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -154,12 +154,12 @@ double PhotoDisintegration::energyLossLength(int id, double E) { std::vector pdModes = pdTable[Z * 31 + N]; if (pdModes.size() == 0) - return 0; + return std::numeric_limits::max(); // log10 of lorentz factor double lg = log10(E / (getNucleusMass(id) * c_squared)); if ((lg <= 6) or (lg >= 14)) - return 0; + return std::numeric_limits::max(); double lossRate = 0; for (size_t i = 0; i < pdModes.size(); i++) { diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 5855dfda5..828e07708 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -147,6 +147,41 @@ void PhotoPionProduction::performInteraction(Candidate *candidate) const { } } +double PhotoPionProduction::energyLossLength(int id, double E) { + int A = getMassNumberFromNucleusId(id); + int Z = getChargeNumberFromNucleusId(id); + int N = A - Z; + + double EpA = E / A; + if ((EpA < energy.front()) or (EpA > energy.back())) + return std::numeric_limits::max(); + + double lossRate = 0; + double relativeEnergyLoss = 1. / double(A); + + if (Z > 0) { + double rate = interpolate(EpA, energy, pRate); + if (A > 1) + if (A < 8) + rate *= 0.85 * pow(Z, 2. / 3.); + if (A >= 8) + rate *= 0.85 * Z; + lossRate += relativeEnergyLoss * rate; + } + + if (N > 0) { + double rate = interpolate(EpA, energy, nRate); + if (A > 1) + if (A < 8) + rate *= 0.85 * pow(N, 2. / 3.); + if (A >= 8) + rate *= 0.85 * N; + lossRate += relativeEnergyLoss * rate; + } + + return 1. / lossRate; +} + SophiaPhotoPionProduction::SophiaPhotoPionProduction(int photonField, bool photons, bool neutrinos, bool antiNucleons) : PhotoPionProduction(photonField), havePhotons(photons), haveNeutrinos( From d96caa9af3b3a98b659a098156d55cb8b63700e7 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 30 Oct 2012 15:06:31 +0100 Subject: [PATCH 0216/1298] energyLossLength for ElectronPairProduction --- include/mpc/module/ElectronPairProduction.h | 13 ++++++--- include/mpc/module/PhotoPionProduction.h | 10 +++---- src/module/ElectronPairProduction.cpp | 29 ++++++++++++++++++--- src/module/PhotoPionProduction.cpp | 10 +++---- 4 files changed, 45 insertions(+), 17 deletions(-) diff --git a/include/mpc/module/ElectronPairProduction.h b/include/mpc/module/ElectronPairProduction.h index fdfb69c3a..739bdb5cd 100644 --- a/include/mpc/module/ElectronPairProduction.h +++ b/include/mpc/module/ElectronPairProduction.h @@ -15,16 +15,23 @@ namespace mpc { */ class ElectronPairProduction: public Module { private: - int photonField; + PhotonField photonField; std::vector lossRate; // energy loss rate in [J/m] std::vector energy; public: - ElectronPairProduction(int photonField = CMB_IRB); - void setPhotonField(int photonField); + ElectronPairProduction(PhotonField photonField = CMB_IRB); + void setPhotonField(PhotonField photonField); void init(); void init(std::string filename); void process(Candidate *candidate) const; + + /** + Calculates the energy loss length 1/E dE/dx in [m] + @param id PDG particle id + @param energy particle energy [J] + */ + double energyLossLength(int id, double energy); }; } // namespace mpc diff --git a/include/mpc/module/PhotoPionProduction.h b/include/mpc/module/PhotoPionProduction.h index 9e67c6019..d13ccd8c0 100644 --- a/include/mpc/module/PhotoPionProduction.h +++ b/include/mpc/module/PhotoPionProduction.h @@ -17,14 +17,14 @@ namespace mpc { */ class PhotoPionProduction: public StochasticInteraction { protected: - int photonField; + PhotonField photonField; std::vector pRate; // interaction rate in [1/m] for protons std::vector nRate; // interaction rate in [1/m] for neutrons std::vector energy; // energy in [J] public: - PhotoPionProduction(int photonField = CMB); - void setPhotonField(int photonField); + PhotoPionProduction(PhotonField photonField = CMB); + void setPhotonField(PhotonField photonField); void init(); void init(std::string filename); bool setNextInteraction(Candidate *candidate, @@ -55,8 +55,8 @@ class SophiaPhotoPionProduction: public PhotoPionProduction { bool haveAntiNucleons; public: - SophiaPhotoPionProduction(int photonField = CMB, bool photons = false, - bool neutrinos = false, bool antiNucleons = false); + SophiaPhotoPionProduction(PhotonField photonField = CMB, bool photons = + false, bool neutrinos = false, bool antiNucleons = false); void setHavePhotons(bool b); void setHaveNeutrinos(bool b); void setHaveAntiNucleons(bool b); diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index acd859103..c188c3a8a 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -6,13 +6,13 @@ namespace mpc { -ElectronPairProduction::ElectronPairProduction(int p) : - photonField(p) { +ElectronPairProduction::ElectronPairProduction(PhotonField photonField) : + photonField(photonField) { init(); } -void ElectronPairProduction::setPhotonField(int p) { - photonField = p; +void ElectronPairProduction::setPhotonField(PhotonField photonField) { + this->photonField = photonField; init(); } @@ -86,4 +86,25 @@ void ElectronPairProduction::process(Candidate *candidate) const { candidate->current.setEnergy(E - dE); } +double ElectronPairProduction::energyLossLength(int id, double E) { + double A = getMassNumberFromNucleusId(id); + double Z = getChargeNumberFromNucleusId(id); + + if (Z < 1) + return std::numeric_limits::max(); + + double EpA = E / A; + if (EpA < energy.front()) + return std::numeric_limits::max(); + + double rate; + if (EpA < energy.back()) + rate = interpolate(EpA, energy, lossRate); + else + rate = lossRate.back() * pow(EpA / energy.back(), 0.4); + + double lossRate = Z * Z * rate / E; + return 1. / lossRate; +} + } // namespace mpc diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 828e07708..7dc408e62 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -11,13 +11,13 @@ namespace mpc { -PhotoPionProduction::PhotoPionProduction(int p) : - photonField(p) { +PhotoPionProduction::PhotoPionProduction(PhotonField photonField) : + photonField(photonField) { init(); } -void PhotoPionProduction::setPhotonField(int p) { - photonField = p; +void PhotoPionProduction::setPhotonField(PhotonField photonField) { + this->photonField = photonField; init(); } @@ -182,7 +182,7 @@ double PhotoPionProduction::energyLossLength(int id, double E) { return 1. / lossRate; } -SophiaPhotoPionProduction::SophiaPhotoPionProduction(int photonField, +SophiaPhotoPionProduction::SophiaPhotoPionProduction(PhotonField photonField, bool photons, bool neutrinos, bool antiNucleons) : PhotoPionProduction(photonField), havePhotons(photons), haveNeutrinos( neutrinos), haveAntiNucleons(antiNucleons) { From 8b9f386a42daf1e080c5dfdcb8c788ea80cf828d Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 30 Oct 2012 15:40:35 +0100 Subject: [PATCH 0217/1298] testEnergyLossLength.py --- test/python/testEnergyLossLength.py | 54 ++++++++++++++++++++++++++ test/python/testPhotoDisintegration.py | 2 +- 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 test/python/testEnergyLossLength.py diff --git a/test/python/testEnergyLossLength.py b/test/python/testEnergyLossLength.py new file mode 100644 index 000000000..5ae412fa9 --- /dev/null +++ b/test/python/testEnergyLossLength.py @@ -0,0 +1,54 @@ +from pylab import * +from mpc import * + +pd1 = PhotoDisintegration(CMB) +pd2 = PhotoDisintegration(IRB) +pp1 = PhotoPionProduction(CMB) +pp2 = PhotoPionProduction(IRB) +ep = ElectronPairProduction(CMB_IRB) + +def pdLoss(pid, E): + l1 = pd1.energyLossLength(pid, E) + l2 = pd2.energyLossLength(pid, E) + return 1/(1/l1 + 1/l2) + +def ppLoss(pid, E): + l1 = pp1.energyLossLength(pid, E) + l2 = pp2.energyLossLength(pid, E) + l = 1/(1./l1 + 1./l2) + if l > 1e4 * Mpc: + return nan + return l + +def parse_pid(pid): + return 'Z=%i, A=%i'%((pid//10000)%1000, (pid%10000)/10) + + + +pid = getNucleusId(56, 26) + +E = logspace(1, 4) * EeV +L = zeros((3, 50)) + +for i, energy in enumerate(E): + L[0,i] = pdLoss(pid, energy) + L[1,i] = ppLoss(pid, energy) + L[2,i] = ep.energyLossLength(pid, energy) + +E /= EeV +L /= Mpc + + + +figure() +plot(E, L[0], label='PDis') +plot(E, L[1], label='PPion') +plot(E, L[2], label='EPair') +legend(frameon=0, loc='lower left') +text(0.05, 0.25, parse_pid(pid), transform=gca().transAxes) +xlabel('Energy [EeV]') +ylabel('Energy Loss Length [Mpc]') +ylim(0.1, 1e4) +loglog() +savefig('EnergyLossLength_%i.png'%pid) +show() diff --git a/test/python/testPhotoDisintegration.py b/test/python/testPhotoDisintegration.py index f47c7881f..3019e7745 100644 --- a/test/python/testPhotoDisintegration.py +++ b/test/python/testPhotoDisintegration.py @@ -32,7 +32,7 @@ def get_data_rates(pid): return D def parse_pid(pid): - return str(pid%100//10) + ' ' + str(pid%100000//10000) + return 'Z=%i, A=%i'%((pid//10000)%1000, (pid%10000)/10) def parse_channel(channel): s = '%06d' % channel From 365bdfcaca7caeb619ae05145885dc6d331ee543 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 2 Nov 2012 10:50:39 +0100 Subject: [PATCH 0218/1298] added option CMB_IRB to photodisintegration, closes #1174 --- src/module/PhotoDisintegration.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index cdb545090..1a84c2b27 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -23,6 +23,10 @@ void PhotoDisintegration::init(PhotonField photonField) { setDescription("PhotoDisintegration: IRB"); init(getDataPath("photodis_IRB.txt")); break; + case CMB_IRB: + setDescription("PhotoDisintegration: CMB and IRB"); + init(getDataPath("photodis_CMB_IRB.txt")); + break; default: throw std::runtime_error( "mpc::PhotoDisintegration: unknown photon background"); From 7ffdd1bb6ac216881809b483141140c03246fad6 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 2 Nov 2012 16:10:09 +0100 Subject: [PATCH 0219/1298] refactored Redshift module --- include/mpc/module/Redshift.h | 27 ++++++++++++++++++++------- src/module/Redshift.cpp | 33 ++++++++++++++------------------- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/include/mpc/module/Redshift.h b/include/mpc/module/Redshift.h index 54571b7ce..3119a39c8 100644 --- a/include/mpc/module/Redshift.h +++ b/include/mpc/module/Redshift.h @@ -16,7 +16,7 @@ namespace mpc { This redshift is reduced with shrinking distance to the observer, and the particle loses energy accordingly. Redshift and particle energy are not changed if the distance to the observer grows. */ -class SimpleRedshift : public Module { +class SimpleRedshift: public Module { private: Vector3d observer; // observer position (z = 0) double h; // dimension-free Hubble constant, H0 = h * 100 km/s/Mpc @@ -30,11 +30,16 @@ class SimpleRedshift : public Module { /** @class Redshift @brief Calculation of cosmological redshift and adiabatic energy loss + + This module implements the calculation of cosmological redshift for a flat universe. + It provides two functionalities: + 1) In a simulation chain it reduces the candidate's redshift according to the propagation step and applies the adiabatic energy loss. + 2) It provides translations from redshift to comoving distance and vice versa. */ -class Redshift : public Module { +class Redshift: public Module { private: double H0; // Hubble rate at z=0 in [1/s], H0 = h * 100 km/s/Mpc - double omegaM; // density parameter + double omegaM; // matter density parameter double omegaL; // vacuum energy parameter static const int n = 1000; @@ -45,13 +50,21 @@ class Redshift : public Module { std::vector D; // comoving distance [m] public: + /** Constructor + @param h dimension-free Hubble constant, H0 = h * 100 km/s/Mpc + @param omegaM matter density parameter + @param omegaL vacuum energy parameter + */ Redshift(double h = 0.7, double omegaM = 0.3, double omegaL = 0.7); - void init(); - double getRedshift(double distance) const; - double getHubbleRate(double redshift) const; - double getDistance(double redshift) const; void process(Candidate *candidate) const; std::string getDescription() const; + + /** Hubble rate at given redshift */ + double hubbleRate(double redshift) const; + /** Redshift of a comoving object at a given comoving distance to the observer at z = 0 */ + double comovingDistance2Redshift(double distance) const; + /** Comoving distance between an observer at z = 0 and a comoving object at z */ + double redshift2ComovingDistance(double redshift) const; }; } // namespace mpc diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index 76c41d283..3c78922c4 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -31,10 +31,6 @@ std::string SimpleRedshift::getDescription() const { Redshift::Redshift(double h, double m, double l) : H0(h * 1e5 / Mpc), omegaM(m), omegaL(l) { - init(); -} - -void Redshift::init() { Z.resize(n); D.resize(n); std::vector H(n); @@ -43,24 +39,23 @@ void Redshift::init() { D[0] = 0; H[0] = H0; - // Relation between comoving distance and redshift (see J.A. Peacock, Cosmological physics, p. 89 eq. 3.76) - // R0 dr = c / H(z) dz - // Integration with midpoint rule: R0 dr = (c/H(z+dz) + c/H(z)) / 2 * dz + // Relation between comoving distance r and redshift z (cf. J.A. Peacock, Cosmological physics, p. 89 eq. 3.76) + // dr = c / H(z) dz, integration using midpoint rule double dlz = log10(zmax) - log10(zmin); - double dz, A; + double dz; for (int i = 1; i < n; i++) { Z[i] = zmin * pow(10, i * dlz / (n - 1)); // logarithmic even spacing - H[i] = getHubbleRate(Z[i]); - D[i] = D[i - 1] - + (Z[i] - Z[i - 1]) * c_light * (1 / H[i] + 1 / H[i - 1]) / 2; + dz = (Z[i] - Z[i - 1]); + H[i] = hubbleRate(Z[i]); + D[i] = D[i - 1] + c_light * (1 / H[i] + 1 / H[i - 1]) / 2 * dz; } } -double Redshift::getHubbleRate(double z) const { +double Redshift::hubbleRate(double z) const { return H0 * sqrt(omegaL + omegaM * pow(1 + z, 3)); } -double Redshift::getRedshift(double d) const { +double Redshift::comovingDistance2Redshift(double d) const { if (d < 0) throw std::runtime_error("Redshift: d < 0"); if (d > D[n - 1]) @@ -68,7 +63,7 @@ double Redshift::getRedshift(double d) const { return interpolate(d, D, Z); } -double Redshift::getDistance(double z) const { +double Redshift::redshift2ComovingDistance(double z) const { if (z < 0) throw std::runtime_error("Redshift: z < 0"); if (z > zmax) @@ -82,13 +77,13 @@ void Redshift::process(Candidate *c) const { if (z == 0) return; // nothing to do, redshift can't get smaller - // use small step approximation to calculate redshift change - // dz = H(z) / c * dr - // dE/dz = E/(1+z) - double dz = getHubbleRate(z) / c_light * c->getCurrentStep(); + // use small redshift approximation: dz = H(z) / c * dr + double dz = hubbleRate(z) / c_light * c->getCurrentStep(); - // update candidate + // update redshift c->setRedshift(z - dz); + + // adiabatic energy loss: dE / dz = E/(1+z) double E = c->current.getEnergy(); c->current.setEnergy(E * (1 - dz / (1 + z))); } From ec27fb6f9cdf8894f15ad8c825a3e4df9a728eae Mon Sep 17 00:00:00 2001 From: geromueller Date: Tue, 6 Nov 2012 09:17:26 +0100 Subject: [PATCH 0220/1298] use install target for swig so rpath is set --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1501deee1..cba674116 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -185,5 +185,5 @@ if(ENABLEPYTHON) set_target_properties(mpc-swig PROPERTIES OUTPUT_NAME "_mpc") target_link_libraries(mpc-swig mpc ${PYTHON_LIBRARIES}) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/mpc.py" DESTINATION ${PYTHON_SITE_PACKAGES}) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_mpc.so" DESTINATION ${PYTHON_SITE_PACKAGES}) -endif(ENABLEPYTHON) \ No newline at end of file + install(TARGETS mpc-swig LIBRARY DESTINATION ${PYTHON_SITE_PACKAGES}) +endif(ENABLEPYTHON) From eb9a46db5cbb260e7cfbde940a00909f362f7086 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 12 Nov 2012 15:55:27 +0100 Subject: [PATCH 0221/1298] add flush statement to all output modules to prevent multi processing confusion --- include/mpc/module/Output.h | 56 ++++++++++---- src/module/Output.cpp | 142 ++++++++++++++++++++++++++---------- 2 files changed, 144 insertions(+), 54 deletions(-) diff --git a/include/mpc/module/Output.h b/include/mpc/module/Output.h index a5b9b1a4c..012e504d8 100644 --- a/include/mpc/module/Output.h +++ b/include/mpc/module/Output.h @@ -23,23 +23,11 @@ class ShellOutput: public Module { class TrajectoryOutput: public Module { mutable std::ofstream outfile; public: - TrajectoryOutput(std::string name); + TrajectoryOutput(std::string filename); ~TrajectoryOutput(); void process(Candidate *candidate) const; }; -/** - @class TrajectoryOutput1D - @brief Saves 1D trajectories to plain text file. - */ -class TrajectoryOutput1D: public Module { - mutable std::ofstream outfile; -public: - TrajectoryOutput1D(std::string name); - ~TrajectoryOutput1D(); - void process(Candidate *candidate) const; -}; - /** @class ConditionalOutput @brief Saves particles with a given property to a plain text file. @@ -56,6 +44,18 @@ class ConditionalOutput: public Module { void process(Candidate *candidate) const; }; +/** + @class TrajectoryOutput1D + @brief Saves 1D trajectories to plain text file. + */ +class TrajectoryOutput1D: public Module { + mutable std::ofstream outfile; +public: + TrajectoryOutput1D(std::string filename); + ~TrajectoryOutput1D(); + void process(Candidate *candidate) const; +}; + /** @class EventOutput1D @brief Records particles that are inactive and have the property 'Detected' to a plain text file. @@ -75,23 +75,47 @@ class EventOutput1D: public Module { class CRPropa2EventOutput: public Module { mutable std::ofstream outfile; public: - CRPropa2EventOutput(std::string name); + CRPropa2EventOutput(std::string filename); ~CRPropa2EventOutput(); void process(Candidate *candidate) const; }; /** @class CRPropa2TrajectoryOutput - @brief Saves trajectory to a plain text file in CRPropa2 format. + @brief Saves trajectories to a plain text file in CRPropa2 format. */ class CRPropa2TrajectoryOutput: public Module { mutable std::ofstream outfile; public: - CRPropa2TrajectoryOutput(std::string name); + CRPropa2TrajectoryOutput(std::string filename); ~CRPropa2TrajectoryOutput(); void process(Candidate *candidate) const; }; +/** + @class CRPropa2EventOutput1D + @brief Saves 1D events to a plain text file in CRPropa2 format. + */ +class CRPropa2EventOutput1D: public Module { + mutable std::ofstream outfile; +public: + CRPropa2EventOutput1D(std::string filename); + ~CRPropa2EventOutput1D(); + void process(Candidate *candidate) const; +}; + +/** + @class CRPropa2TrajectoryOutput1D + @brief Saves 1D trajectories to a plain text file in CRPropa2 format. + */ +class CRPropa2TrajectoryOutput1D: public Module { + mutable std::ofstream outfile; +public: + CRPropa2TrajectoryOutput1D(std::string filename); + ~CRPropa2TrajectoryOutput1D(); + void process(Candidate *candidate) const; +}; + } // namespace mpc #endif /* OUTPUT_H_ */ diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 2ec036360..d4785558f 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -8,6 +8,26 @@ namespace mpc { +void ShellOutput::process(Candidate* c) const { +#pragma omp critical + { + std::cout << std::fixed << std::showpoint << std::setprecision(3) + << std::setw(6); + std::cout << c->getTrajectoryLength() / Mpc << " Mpc, "; + std::cout << c->getRedshift() << ", "; + std::cout << c->current.getId() << ", "; + std::cout << c->current.getEnergy() / EeV << " EeV, "; + std::cout << c->current.getPosition() / Mpc << " Mpc, "; + std::cout << c->current.getDirection().getPhi() << " "; + std::cout << c->current.getDirection().getTheta(); + std::cout << std::endl; + } +} + +std::string ShellOutput::getDescription() const { + return "Shell output"; +} + TrajectoryOutput::TrajectoryOutput(std::string name) { setDescription("Trajectory output"); outfile.open(name.c_str()); @@ -37,30 +57,7 @@ void TrajectoryOutput::process(Candidate *c) const { #pragma omp critical { outfile.write(buffer, p); - } -} - -TrajectoryOutput1D::TrajectoryOutput1D(std::string filename) { - setDescription("Trajectory output"); - outfile.open(filename.c_str()); - outfile << "# Position(X)[Mpc]\t"; - outfile << "PDG_Code\t"; - outfile << "Energy[EeV]\n"; -} - -TrajectoryOutput1D::~TrajectoryOutput1D() { - outfile.close(); -} - -void TrajectoryOutput1D::process(Candidate *c) const { - char buffer[1024]; - size_t p = 0; - p += sprintf(buffer + p, "%8.4f\t", c->current.getPosition().x / Mpc); - p += sprintf(buffer + p, "%10i\t", c->current.getId()); - p += sprintf(buffer + p, "%8.4f\n", c->current.getEnergy() / EeV); -#pragma omp critical - { - outfile.write(buffer, p); + outfile.flush(); } } @@ -76,7 +73,7 @@ ConditionalOutput::ConditionalOutput(std::string filename, std::string propName, outfile << "Energy[EeV]\t"; outfile << "Position(X,Y,Z)[Mpc]\t"; outfile << "Direction(Phi,Theta)\t"; - outfile << "Age[Mpc]\t"; + outfile << "Comoving distance [Mpc]\t"; outfile << "Initial_PDG_Code\t"; outfile << "Initial_Energy[EeV]\t"; outfile << "Initial_Position(X,Y,Z)[Mpc]\t"; @@ -119,10 +116,36 @@ void ConditionalOutput::process(Candidate *c) const { #pragma omp critical { outfile.write(buffer, p); + outfile.flush(); } } } +TrajectoryOutput1D::TrajectoryOutput1D(std::string filename) { + setDescription("Trajectory output"); + outfile.open(filename.c_str()); + outfile << "# Position(X)[Mpc]\t"; + outfile << "PDG_Code\t"; + outfile << "Energy[EeV]\n"; +} + +TrajectoryOutput1D::~TrajectoryOutput1D() { + outfile.close(); +} + +void TrajectoryOutput1D::process(Candidate *c) const { + char buffer[1024]; + size_t p = 0; + p += sprintf(buffer + p, "%8.4f\t", c->current.getPosition().x / Mpc); + p += sprintf(buffer + p, "%10i\t", c->current.getId()); + p += sprintf(buffer + p, "%8.4f\n", c->current.getEnergy() / EeV); +#pragma omp critical + { + outfile.write(buffer, p); + outfile.flush(); + } +} + EventOutput1D::EventOutput1D(std::string filename) { setDescription("Conditional output, Filename: " + filename); outfile.open(filename.c_str()); @@ -153,6 +176,7 @@ void EventOutput1D::process(Candidate *c) const { #pragma omp critical { outfile.write(buffer, p); + outfile.flush(); } } } @@ -202,6 +226,7 @@ void CRPropa2EventOutput::process(Candidate *candidate) const { #pragma omp critical { outfile.write(buffer, p); + outfile.flush(); } } } @@ -243,27 +268,68 @@ void CRPropa2TrajectoryOutput::process(Candidate *candidate) const { #pragma omp critical { outfile.write(buffer, p); + outfile.flush(); } } -void ShellOutput::process(Candidate* c) const { +CRPropa2TrajectoryOutput1D::CRPropa2TrajectoryOutput1D(std::string filename) { + setDescription("Trajectory output"); + outfile.open(filename.c_str()); + outfile << "# Position(X)[Mpc]\t"; + outfile << "PDG_Code\t"; + outfile << "Energy[EeV]\n"; +} + +CRPropa2TrajectoryOutput1D::~CRPropa2TrajectoryOutput1D() { + outfile.close(); +} + +void CRPropa2TrajectoryOutput1D::process(Candidate *c) const { + char buffer[1024]; + size_t p = 0; + p += sprintf(buffer + p, "%8.4f\t", c->current.getPosition().x / Mpc); + p += sprintf(buffer + p, "%10i\t", c->current.getId()); + p += sprintf(buffer + p, "%8.4f\n", c->current.getEnergy() / EeV); #pragma omp critical { - std::cout << std::fixed << std::showpoint << std::setprecision(3) - << std::setw(6); - std::cout << c->getTrajectoryLength() / Mpc << " Mpc, "; - std::cout << c->getRedshift() << ", "; - std::cout << c->current.getId() << ", "; - std::cout << c->current.getEnergy() / EeV << " EeV, "; - std::cout << c->current.getPosition() / Mpc << " Mpc, "; - std::cout << c->current.getDirection().getPhi() << " "; - std::cout << c->current.getDirection().getTheta(); - std::cout << std::endl; + outfile.write(buffer, p); + outfile.flush(); } } -std::string ShellOutput::getDescription() const { - return "Shell output"; +CRPropa2EventOutput1D::CRPropa2EventOutput1D(std::string filename) { + setDescription("Conditional output, Filename: " + filename); + outfile.open(filename.c_str()); + outfile << "# PDG_Code\t"; + outfile << "Energy[EeV]\t"; + outfile << "Age[Mpc]"; + outfile << "Initial_PDG_Code\t"; + outfile << "Initial_Energy[EeV]\n"; +} + +CRPropa2EventOutput1D::~CRPropa2EventOutput1D() { + outfile.close(); +} + +void CRPropa2EventOutput1D::process(Candidate *c) const { + if (c->isActive()) + return; + if (c->hasProperty("Detected")) { + char buffer[256]; + size_t p = 0; + + p += sprintf(buffer + p, "%10i\t", c->current.getId()); + p += sprintf(buffer + p, "%8.4f\t", c->current.getEnergy() / EeV); + p += sprintf(buffer + p, "%9.4f\t", c->getTrajectoryLength() / Mpc); + p += sprintf(buffer + p, "%10i\t", c->initial.getId()); + p += sprintf(buffer + p, "%8.4f\n", c->initial.getEnergy() / EeV); + +#pragma omp critical + { + outfile.write(buffer, p); + outfile.flush(); + } + } } } // namespace mpc From 3b29751cd8c51dd1815a40f9565a525cebc05419 Mon Sep 17 00:00:00 2001 From: geromueller Date: Mon, 12 Nov 2012 17:00:03 +0100 Subject: [PATCH 0222/1298] fix memory leak in modulelist, add ctrl-c handler --- include/mpc/ProgressBar.h | 61 +++++++++++++++++++-------------------- src/ModuleList.cpp | 47 ++++++++++++++++++++++-------- 2 files changed, 65 insertions(+), 43 deletions(-) diff --git a/include/mpc/ProgressBar.h b/include/mpc/ProgressBar.h index 62e1e8336..19e9335bb 100644 --- a/include/mpc/ProgressBar.h +++ b/include/mpc/ProgressBar.h @@ -20,15 +20,12 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ - - #include #include #include #include -class ProgressBar -{ +class ProgressBar { private: unsigned long _steps; unsigned long _currentCount; @@ -41,65 +38,67 @@ class ProgressBar public: /// Initialize a ProgressBar with [steps] number of steps, updated at [updateSteps] intervalls - ProgressBar(const std::string &title, unsigned long steps = 0, unsigned long updateSteps = 100) : - _steps(steps), _currentCount(0), _maxbarLength(10), _updateSteps(updateSteps), _nextStep(1) - { + ProgressBar(unsigned long steps = 0, unsigned long updateSteps = 100) : + _steps(steps), _currentCount(0), _maxbarLength(10), _updateSteps( + updateSteps), _nextStep(1), _startTime(0) { if (_updateSteps > _steps) _updateSteps = _steps; + arrow.append(">"); + } + + void start(const std::string &title) { _startTime = time(NULL); std::string s = ctime(&_startTime); - s.erase(s.end()-1, s.end()); + s.erase(s.end() - 1, s.end()); stringTmpl = " Started "; stringTmpl.append(s); stringTmpl.append(" : [%-10s] %3i%% %s: %02i:%02is %s\r"); - arrow.append(">"); std::cout << title << std::endl; - } + } /// update the progressbar /// should be called steps times in a loop - void update() - { + void update() { _currentCount++; - if (_currentCount == _nextStep || _currentCount == _steps) - { - _nextStep+=long(_steps / float(_updateSteps)); + if (_currentCount == _nextStep || _currentCount == _steps) { + _nextStep += long(_steps / float(_updateSteps)); - int percentage = int(100*_currentCount/float(_steps)); + int percentage = int(100 * _currentCount / float(_steps)); time_t currentTime = time(NULL); - if (_currentCount < _steps) - { - int j=0; - if (arrow.size() <= (_maxbarLength)*(_currentCount)/(_steps)) + if (_currentCount < _steps) { + int j = 0; + if (arrow.size() + <= (_maxbarLength) * (_currentCount) / (_steps)) arrow.insert(0, "="); float tElapsed = currentTime - _startTime; - float tToGo = (_steps - _currentCount) * tElapsed / _currentCount; - printf(stringTmpl.c_str(), arrow.c_str(), percentage , "Finish in",int(tToGo/60), int(tToGo)%60, ""); + float tToGo = (_steps - _currentCount) * tElapsed + / _currentCount; + printf(stringTmpl.c_str(), arrow.c_str(), percentage, + "Finish in", int(tToGo / 60), int(tToGo) % 60, ""); fflush(stdout); - } - else - { + } else { float tElapsed = currentTime - _startTime; std::string s = " - Finished at "; s.append(ctime(¤tTime)); char fs[255]; - sprintf(fs, "%c[%d;%dm Finished %c[%dm",27,1,32,27,0); - printf(stringTmpl.c_str(), fs, percentage, "Needed",int(tElapsed/60), int(tElapsed)%60, s.c_str()); + sprintf(fs, "%c[%d;%dm Finished %c[%dm", 27, 1, 32, 27, 0); + printf(stringTmpl.c_str(), fs, percentage, "Needed", + int(tElapsed / 60), int(tElapsed) % 60, s.c_str()); } } } /// Mark the progressbar with an error - void setError() - { + void setError() { time_t currentTime = time(NULL); _currentCount++; float tElapsed = currentTime - _startTime; std::string s = " - Finished at "; s.append(ctime(¤tTime)); char fs[255]; - sprintf(fs, "%c[%d;%dm ERROR %c[%dm",27,1,31,27,0); - printf(stringTmpl.c_str(), fs, _currentCount, "Needed",int(tElapsed/60), int(tElapsed)%60, s.c_str()); + sprintf(fs, "%c[%d;%dm ERROR %c[%dm", 27, 1, 31, 27, 0); + printf(stringTmpl.c_str(), fs, _currentCount, "Needed", + int(tElapsed / 60), int(tElapsed) % 60, s.c_str()); } }; diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index eaa5fd87e..bd15011df 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -2,12 +2,20 @@ #include "mpc/ProgressBar.h" #include +#include #include using namespace std; namespace mpc { +bool g_cancel_signal_flag = false; +sighandler_t g_cancel_signal_backup = NULL; +void g_cancel_signal_callback(int sig) { + g_cancel_signal_flag = true; + ::signal(SIGINT, SIG_DFL ); +} + ModuleList::ModuleList() : showProgress(false) { } @@ -33,7 +41,7 @@ void ModuleList::process(Candidate *candidate) { } void ModuleList::run(Candidate *candidate, bool recursive) { - while (candidate->isActive()) + while (candidate->isActive() && !g_cancel_signal_flag) process(candidate); // propagate secondaries @@ -49,18 +57,26 @@ void ModuleList::run(candidate_vector_t &candidates, bool recursive) { std::cout << "mpc::ModuleList: Number of Threads: " << omp_get_max_threads() << std::endl; #endif - ProgressBar *progressbar = NULL; - if (showProgress) - progressbar = new ProgressBar("Run ModuleList", count); + ProgressBar progressbar(count); + + if (showProgress) { + progressbar.start("Run ModuleList"); + } + + g_cancel_signal_flag = false; + g_cancel_signal_backup = ::signal(SIGINT, g_cancel_signal_callback); #pragma omp parallel for schedule(dynamic, 1000) for (size_t i = 0; i < count; i++) { - run(candidates[i], recursive); + if (!g_cancel_signal_flag) + run(candidates[i], recursive); - if (progressbar) + if (showProgress) #pragma omp critical(progressbarUpdate) - progressbar->update(); + progressbar.update(); } + + ::signal(SIGINT, g_cancel_signal_backup); } void ModuleList::run(Source *source, size_t count, bool recursive) { @@ -69,20 +85,27 @@ void ModuleList::run(Source *source, size_t count, bool recursive) { std::cout << "mpc::ModuleList: Number of Threads: " << omp_get_max_threads() << std::endl; #endif - ProgressBar *progressbar = NULL; + ProgressBar progressbar(count); + if (showProgress) { - progressbar = new ProgressBar("Run ModuleList", count); + progressbar.start("Run ModuleList"); } + g_cancel_signal_flag = false; + ::signal(SIGINT, g_cancel_signal_callback); + #pragma omp parallel for schedule(dynamic, 1000) for (size_t i = 0; i < count; i++) { ref_ptr candidate = source->getCandidate(); - run(candidate, recursive); + if (!g_cancel_signal_flag) + run(candidate, recursive); - if (progressbar) + if (showProgress) #pragma omp critical(progressbarUpdate) - progressbar->update(); + progressbar.update(); } + + ::signal(SIGINT, g_cancel_signal_backup); } ModuleList::module_list_t &ModuleList::getModules() { From a7996526812953868f259c9744143ef10cd06879 Mon Sep 17 00:00:00 2001 From: geromueller Date: Mon, 12 Nov 2012 17:03:53 +0100 Subject: [PATCH 0223/1298] correctly restore old signal handler --- src/ModuleList.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index bd15011df..fa2ff8fd7 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -10,10 +10,8 @@ using namespace std; namespace mpc { bool g_cancel_signal_flag = false; -sighandler_t g_cancel_signal_backup = NULL; void g_cancel_signal_callback(int sig) { g_cancel_signal_flag = true; - ::signal(SIGINT, SIG_DFL ); } ModuleList::ModuleList() : @@ -64,7 +62,8 @@ void ModuleList::run(candidate_vector_t &candidates, bool recursive) { } g_cancel_signal_flag = false; - g_cancel_signal_backup = ::signal(SIGINT, g_cancel_signal_callback); + sighandler_t old_signal_handler = ::signal(SIGINT, + g_cancel_signal_callback); #pragma omp parallel for schedule(dynamic, 1000) for (size_t i = 0; i < count; i++) { @@ -76,7 +75,7 @@ void ModuleList::run(candidate_vector_t &candidates, bool recursive) { progressbar.update(); } - ::signal(SIGINT, g_cancel_signal_backup); + ::signal(SIGINT, old_signal_handler); } void ModuleList::run(Source *source, size_t count, bool recursive) { @@ -92,7 +91,8 @@ void ModuleList::run(Source *source, size_t count, bool recursive) { } g_cancel_signal_flag = false; - ::signal(SIGINT, g_cancel_signal_callback); + sighandler_t old_signal_handler = ::signal(SIGINT, + g_cancel_signal_callback); #pragma omp parallel for schedule(dynamic, 1000) for (size_t i = 0; i < count; i++) { @@ -105,7 +105,7 @@ void ModuleList::run(Source *source, size_t count, bool recursive) { progressbar.update(); } - ::signal(SIGINT, g_cancel_signal_backup); + ::signal(SIGINT, old_signal_handler); } ModuleList::module_list_t &ModuleList::getModules() { From c72cb451a625ea5e438aa62903be98bfd885eac6 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 12 Nov 2012 21:00:02 +0100 Subject: [PATCH 0224/1298] removed CRPropa2-like output modules --- include/mpc/XmlExecute.h | 2 +- include/mpc/module/Output.h | 50 +----------- src/module/Output.cpp | 151 ------------------------------------ 3 files changed, 2 insertions(+), 201 deletions(-) diff --git a/include/mpc/XmlExecute.h b/include/mpc/XmlExecute.h index 97a2c73b2..019730554 100644 --- a/include/mpc/XmlExecute.h +++ b/include/mpc/XmlExecute.h @@ -18,9 +18,9 @@ class XmlExecute { void loadGridMagneticField(pugi::xml_node &node); void loadDeflectionCK(pugi::xml_node &node); void loadPeriodicBoundaries(); - void loadSources(pugi::xml_node &node); void loadDiscreteSources(pugi::xml_node &node); void loadContinuousSources(pugi::xml_node &node); + void loadSpectrumComposition(pugi::xml_node &node); void loadSourceNuclei(pugi::xml_node &node); void loadSophia(pugi::xml_node &node); void loadSpheresAroundObserver(pugi::xml_node &node); diff --git a/include/mpc/module/Output.h b/include/mpc/module/Output.h index 012e504d8..f7dec3a95 100644 --- a/include/mpc/module/Output.h +++ b/include/mpc/module/Output.h @@ -38,7 +38,7 @@ class ConditionalOutput: public Module { bool removeProperty; public: ConditionalOutput(std::string filename, std::string condition = "Detected", - bool removeProperty = false); + bool removeProperty = true); ~ConditionalOutput(); void setRemoveProperty(bool removeProperty); void process(Candidate *candidate) const; @@ -68,54 +68,6 @@ class EventOutput1D: public Module { void process(Candidate *candidate) const; }; -/** - @class CRPropa2EventOutput - @brief Saves events to a plain text file in CRPropa2 format. - */ -class CRPropa2EventOutput: public Module { - mutable std::ofstream outfile; -public: - CRPropa2EventOutput(std::string filename); - ~CRPropa2EventOutput(); - void process(Candidate *candidate) const; -}; - -/** - @class CRPropa2TrajectoryOutput - @brief Saves trajectories to a plain text file in CRPropa2 format. - */ -class CRPropa2TrajectoryOutput: public Module { - mutable std::ofstream outfile; -public: - CRPropa2TrajectoryOutput(std::string filename); - ~CRPropa2TrajectoryOutput(); - void process(Candidate *candidate) const; -}; - -/** - @class CRPropa2EventOutput1D - @brief Saves 1D events to a plain text file in CRPropa2 format. - */ -class CRPropa2EventOutput1D: public Module { - mutable std::ofstream outfile; -public: - CRPropa2EventOutput1D(std::string filename); - ~CRPropa2EventOutput1D(); - void process(Candidate *candidate) const; -}; - -/** - @class CRPropa2TrajectoryOutput1D - @brief Saves 1D trajectories to a plain text file in CRPropa2 format. - */ -class CRPropa2TrajectoryOutput1D: public Module { - mutable std::ofstream outfile; -public: - CRPropa2TrajectoryOutput1D(std::string filename); - ~CRPropa2TrajectoryOutput1D(); - void process(Candidate *candidate) const; -}; - } // namespace mpc #endif /* OUTPUT_H_ */ diff --git a/src/module/Output.cpp b/src/module/Output.cpp index d4785558f..eb8b1aec9 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -181,155 +181,4 @@ void EventOutput1D::process(Candidate *c) const { } } -CRPropa2EventOutput::CRPropa2EventOutput(std::string filename) { - setDescription("Event output in CRPropa2 format"); - outfile.open(filename.c_str()); - outfile << "#CRPropa - Output data file\n"; - outfile - << "#Format - Particle_Type Initial_Particle_Type Initial_Position[X,Y,Z](Mpc) Initial_Momentum[E,theta,phi](EeV) Time(Mpc) Position[X,Y,Z](Mpc) Momentum[E,theta,phi](EeV)\n"; -} - -CRPropa2EventOutput::~CRPropa2EventOutput() { - outfile.close(); -} - -void CRPropa2EventOutput::process(Candidate *candidate) const { - if (candidate->hasProperty("Detected")) { - char buffer[256]; // max. 256 characters per line - size_t p = 0; // length of line - - int cid = convertToCRPropaId(candidate->current.getId()); - p += sprintf(buffer + p, "%i ", cid); - - int iid = convertToCRPropaId(candidate->initial.getId()); - p += sprintf(buffer + p, "%i ", iid); - - const Vector3d &ipos = candidate->initial.getPosition() / Mpc; - p += sprintf(buffer + p, "%.4f %.4f %.4f ", ipos.x, ipos.y, ipos.z); - - double iPhi = candidate->initial.getDirection().getPhi(); - double iTheta = candidate->initial.getDirection().getTheta(); - double iE = candidate->initial.getEnergy() / EeV; - p += sprintf(buffer + p, "%.4f %.4f %.4f ", iE, iPhi, iTheta); - - double t = candidate->getTrajectoryLength() / Mpc; - p += sprintf(buffer + p, "%.4f ", t); - - const Vector3d &pos = candidate->current.getPosition() / Mpc; - p += sprintf(buffer + p, "%.4f %.4f %.4f ", pos.x, pos.y, pos.z); - - double phi = candidate->current.getDirection().getPhi(); - double theta = candidate->current.getDirection().getTheta(); - double E = candidate->current.getEnergy() / EeV; - p += sprintf(buffer + p, "%.4f %.4f %.4f\n", E, phi, theta); - -#pragma omp critical - { - outfile.write(buffer, p); - outfile.flush(); - } - } -} - -CRPropa2TrajectoryOutput::CRPropa2TrajectoryOutput(std::string filename) { - setDescription("Trajectory output in CRPropa2 format"); - outfile.open(filename.c_str()); - outfile << "#CRPropa - Output data file" << std::endl - << "#Format - Particle_Type Initial_Particle_Type Time(Mpc) Position[X,Y,Z](Mpc) Momentum[X,Y,Z](EeV) Energy(EeV)" - << std::endl; -} - -CRPropa2TrajectoryOutput::~CRPropa2TrajectoryOutput() { - outfile.close(); -} - -void CRPropa2TrajectoryOutput::process(Candidate *candidate) const { - char buffer[256]; - size_t p = 0; - - int cid = convertToCRPropaId(candidate->current.getId()); - p += sprintf(buffer + p, "%i ", cid); - - int iid = convertToCRPropaId(candidate->initial.getId()); - p += sprintf(buffer + p, "%i ", iid); - - double t = candidate->getTrajectoryLength() / Mpc; - p += sprintf(buffer + p, "%.4f ", t); - - const Vector3d &pos = candidate->current.getPosition() / Mpc; - p += sprintf(buffer + p, "%.4f %.4f %.4f ", pos.x, pos.y, pos.z); - - const Vector3d &mom = candidate->current.getMomentum() / EeV; - p += sprintf(buffer + p, "%.4g %.4g %.4g ", mom.x, mom.y, mom.z); - - double E = candidate->current.getEnergy() / EeV; - p += sprintf(buffer + p, "%.4f\n", E); - -#pragma omp critical - { - outfile.write(buffer, p); - outfile.flush(); - } -} - -CRPropa2TrajectoryOutput1D::CRPropa2TrajectoryOutput1D(std::string filename) { - setDescription("Trajectory output"); - outfile.open(filename.c_str()); - outfile << "# Position(X)[Mpc]\t"; - outfile << "PDG_Code\t"; - outfile << "Energy[EeV]\n"; -} - -CRPropa2TrajectoryOutput1D::~CRPropa2TrajectoryOutput1D() { - outfile.close(); -} - -void CRPropa2TrajectoryOutput1D::process(Candidate *c) const { - char buffer[1024]; - size_t p = 0; - p += sprintf(buffer + p, "%8.4f\t", c->current.getPosition().x / Mpc); - p += sprintf(buffer + p, "%10i\t", c->current.getId()); - p += sprintf(buffer + p, "%8.4f\n", c->current.getEnergy() / EeV); -#pragma omp critical - { - outfile.write(buffer, p); - outfile.flush(); - } -} - -CRPropa2EventOutput1D::CRPropa2EventOutput1D(std::string filename) { - setDescription("Conditional output, Filename: " + filename); - outfile.open(filename.c_str()); - outfile << "# PDG_Code\t"; - outfile << "Energy[EeV]\t"; - outfile << "Age[Mpc]"; - outfile << "Initial_PDG_Code\t"; - outfile << "Initial_Energy[EeV]\n"; -} - -CRPropa2EventOutput1D::~CRPropa2EventOutput1D() { - outfile.close(); -} - -void CRPropa2EventOutput1D::process(Candidate *c) const { - if (c->isActive()) - return; - if (c->hasProperty("Detected")) { - char buffer[256]; - size_t p = 0; - - p += sprintf(buffer + p, "%10i\t", c->current.getId()); - p += sprintf(buffer + p, "%8.4f\t", c->current.getEnergy() / EeV); - p += sprintf(buffer + p, "%9.4f\t", c->getTrajectoryLength() / Mpc); - p += sprintf(buffer + p, "%10i\t", c->initial.getId()); - p += sprintf(buffer + p, "%8.4f\n", c->initial.getEnergy() / EeV); - -#pragma omp critical - { - outfile.write(buffer, p); - outfile.flush(); - } - } -} - } // namespace mpc From c0533cfa08a96de5672f3270347e8f84a31f050a Mon Sep 17 00:00:00 2001 From: geromueller Date: Tue, 13 Nov 2012 10:13:57 +0100 Subject: [PATCH 0225/1298] improve cmake output --- cmake/FindFFTW3F.cmake | 9 +++++---- cmake/FindGadget.cmake | 12 +++++------- cmake/FindGooglePerfTools.cmake | 6 ++++-- python/Python.cmake | 11 ++++++----- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/cmake/FindFFTW3F.cmake b/cmake/FindFFTW3F.cmake index ac2082579..bd2debe78 100644 --- a/cmake/FindFFTW3F.cmake +++ b/cmake/FindFFTW3F.cmake @@ -9,11 +9,12 @@ find_library(FFTW3F_LIBRARY fftw3f) set(FFTW3F_FOUND FALSE) if(FFTW3F_INCLUDE_DIR AND FFTW3F_LIBRARY) set(FFTW3F_FOUND TRUE) - MESSAGE("-- Found FFTW3 with single precision (FFTW3F):\n" - "-- Include: ${FFTW3F_INCLUDE_DIR}\n" - "-- Library: ${FFTW3F_LIBRARY}") + MESSAGE(STATUS "FFTW3 with single precision (FFTW3F): Found!") else() - MESSAGE("-- Could not find FFTW3 with single precision (FFTW3F)") + MESSAGE(STATUS "FFTW3 with single precision (FFTW3F): NOT Found!") endif() +MESSAGE(STATUS " Include: ${FFTW3F_INCLUDE_DIR}") +MESSAGE(STATUS " Library: ${FFTW3F_LIBRARY}") + mark_as_advanced(FFTW3F_INCLUDE_DIR FFTW3F_LIBRARY FFTW3F_FOUND) diff --git a/cmake/FindGadget.cmake b/cmake/FindGadget.cmake index e2273a7c6..7604d4d89 100644 --- a/cmake/FindGadget.cmake +++ b/cmake/FindGadget.cmake @@ -8,14 +8,12 @@ find_library(GADGET_LIBRARY Gadget) set(GADGET_FOUND FALSE) if(GADGET_INCLUDE_DIR AND GADGET_LIBRARY) set(GADGET_FOUND TRUE) - MESSAGE(STATUS "Found Gadget") - MESSAGE(STATUS " Include: ${GADGET_INCLUDE_DIR}") - MESSAGE(STATUS " Library: ${GADGET_LIBRARY}") + MESSAGE(STATUS "Gadget: Found!") else() - IF (GADGET_FIND_REQUIRED) - MESSAGE(STATUS "Gadget NOT found") - ENDIF (GADGET_FIND_REQUIRED) - + MESSAGE(STATUS "Gadget: NOT Found!") endif() +MESSAGE(STATUS " Include: ${GADGET_INCLUDE_DIR}") +MESSAGE(STATUS " Library: ${GADGET_LIBRARY}") + mark_as_advanced(GADGET_INCLUDE_DIR GADGET_LIBRARY GADGET_FOUND) diff --git a/cmake/FindGooglePerfTools.cmake b/cmake/FindGooglePerfTools.cmake index 09d7526db..3d4ca76c5 100644 --- a/cmake/FindGooglePerfTools.cmake +++ b/cmake/FindGooglePerfTools.cmake @@ -35,15 +35,17 @@ ENDIF (PROFILER_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR) IF (GOOGLE_PERFTOOLS_FOUND) IF (NOT GOOGLE_PERFTOOLS_FIND_QUIETLY) - MESSAGE(STATUS "Found Google perftools: ${GOOGLE_PERFTOOLS_INCLUDE_DIR}") + MESSAGE(STATUS "Google perftools: Found!") ENDIF (NOT GOOGLE_PERFTOOLS_FIND_QUIETLY) ELSE (GOOGLE_PERFTOOLS_FOUND) - MESSAGE(STATUS "Could not find Google perftools library") + MESSAGE(STATUS "Google perftools: NOT Found!") IF (GOOGLE_PERFTOOLS_FIND_REQUIRED) MESSAGE(FATAL_ERROR "Could not find Google perftools library") ENDIF (GOOGLE_PERFTOOLS_FIND_REQUIRED) ENDIF (GOOGLE_PERFTOOLS_FOUND) +MESSAGE(STATUS " Include: ${GOOGLE_PERFTOOLS_INCLUDE_DIR}") + MARK_AS_ADVANCED( TCMALLOC_LIBRARY STACKTRACE_LIBRARY diff --git a/python/Python.cmake b/python/Python.cmake index 2b1c18032..7170bf48a 100644 --- a/python/Python.cmake +++ b/python/Python.cmake @@ -70,8 +70,9 @@ execute_process( OUTPUT_STRIP_TRAILING_WHITESPACE ) -MESSAGE(STATUS "Found Python executeable: " ${PYTHON_EXECUTABLE}) -MESSAGE(STATUS "Found Python include path: " ${PYTHON_INCLUDE_PATH}) -MESSAGE(STATUS "Found Python library: " ${PYTHON_LIBRARIES}) -MESSAGE(STATUS "Using Python site-package directory: " ${PYTHON_SITE_PACKAGES}) -MESSAGE(STATUS "Using Python Version: " ${PYTHON_DOT_VERSION} "/" ${PYTHON_VERSION}) +MESSAGE(STATUS "Python: Found!") +MESSAGE(STATUS " Version: " ${PYTHON_DOT_VERSION} "/" ${PYTHON_VERSION}) +MESSAGE(STATUS " Executeable: " ${PYTHON_EXECUTABLE}) +MESSAGE(STATUS " Include: " ${PYTHON_INCLUDE_PATH}) +MESSAGE(STATUS " Library: " ${PYTHON_LIBRARIES}) +MESSAGE(STATUS " Site-package directory: " ${PYTHON_SITE_PACKAGES}) From 80f89ce88677ff933f9fa6adc9f82847275cc70a Mon Sep 17 00:00:00 2001 From: geromueller Date: Tue, 13 Nov 2012 10:18:43 +0100 Subject: [PATCH 0226/1298] always links libs statically --- libs/kiss/CMakeLists.txt | 2 +- libs/pugixml/CMakeLists.txt | 2 +- libs/sophia/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/kiss/CMakeLists.txt b/libs/kiss/CMakeLists.txt index 82a497eb0..a57ddd9d4 100644 --- a/libs/kiss/CMakeLists.txt +++ b/libs/kiss/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.6) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) -add_library(kiss +add_library(kiss STATIC src/logger src/path src/string diff --git a/libs/pugixml/CMakeLists.txt b/libs/pugixml/CMakeLists.txt index 9be323927..0c4bf7634 100644 --- a/libs/pugixml/CMakeLists.txt +++ b/libs/pugixml/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.6) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -add_library(pugixml +add_library(pugixml STATIC pugixml ) diff --git a/libs/sophia/CMakeLists.txt b/libs/sophia/CMakeLists.txt index 1e85f5d90..150c07579 100644 --- a/libs/sophia/CMakeLists.txt +++ b/libs/sophia/CMakeLists.txt @@ -4,7 +4,7 @@ enable_language(Fortran) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -add_library(sophia +add_library(sophia STATIC sophia_interface.f ) From 25a49524405549f05bf8e016333268bbac18dd0f Mon Sep 17 00:00:00 2001 From: geromueller Date: Tue, 13 Nov 2012 10:20:31 +0100 Subject: [PATCH 0227/1298] ignore data file --- .hgignore | 6 ++-- include/mpc/magneticField/SPHMagneticField.h | 5 +-- src/magneticField/SPHMagneticField.cpp | 36 ++++++++++++++++++-- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/.hgignore b/.hgignore index 9f1c50e14..3a1cf0d41 100644 --- a/.hgignore +++ b/.hgignore @@ -7,7 +7,5 @@ syntax: regexp .png$ ^\.cproject$ ^\.project$ -^data/NuclearDecay/bnl_z0-36\.txt$ -^data/PhotoDisintegration/CMB$ -^data/PhotoDisintegration/IRB$ -^data/SPH$ +^data/.*$ + diff --git a/include/mpc/magneticField/SPHMagneticField.h b/include/mpc/magneticField/SPHMagneticField.h index cba165cb2..804c696ac 100644 --- a/include/mpc/magneticField/SPHMagneticField.h +++ b/include/mpc/magneticField/SPHMagneticField.h @@ -12,8 +12,8 @@ #include namespace gadget { -class DirectMagneticField; -class SampledMagneticField; + class DirectMagneticField; + class SampledMagneticField; } namespace mpc { @@ -48,6 +48,7 @@ class SPHMagneticFieldGrid: public MagneticField { SPHMagneticFieldGrid(Vector3d origin, double size, size_t gridSize, std::string filename); SPHMagneticFieldGrid(size_t gridSize, std::string filename); + void init(const Vector3d &origin, double size); Vector3d getField(const Vector3d &position) const; void setCachePrefix(std::string prefix); void setCacheEnabled(bool enabled); diff --git a/src/magneticField/SPHMagneticField.cpp b/src/magneticField/SPHMagneticField.cpp index 9cbc196d3..33dc605b5 100644 --- a/src/magneticField/SPHMagneticField.cpp +++ b/src/magneticField/SPHMagneticField.cpp @@ -23,7 +23,8 @@ Vector3d SPHMagneticField::getField(const Vector3d &position) const { gadget::Vector3f b; bool isGood = field.getField(r / kpc, b); if (!isGood) - std::cout << "mpc::SPHMagneticField invalid position : " << position << std::endl; + std::cout << "mpc::SPHMagneticField invalid position : " << position + << std::endl; Vector3d bField = Vector3d(b.x, b.y, b.z) * gauss; return bField; } @@ -34,7 +35,8 @@ double SPHMagneticField::getRho(const Vector3d& position) const { float rho; bool isGood = field.getRho(r / kpc, overlaps, rho); if (!isGood) - std::cout << "mpc::SPHMagneticField invalid position : " << position << std::endl; + std::cout << "mpc::SPHMagneticField invalid position : " << position + << std::endl; return rho * 1.98892e40 * kilogram * pow(0.7, 2) / pow(kpc, 3); } @@ -57,11 +59,39 @@ Vector3d SPHMagneticFieldGrid::getField(const Vector3d &position) const { gadget::Vector3f b; bool isGood = field.getField(r / kpc, b); if (!isGood) - std::cout << "mpc::SPHMagneticField invalid position : " << position << std::endl; + std::cout << "mpc::SPHMagneticField invalid position : " << position + << std::endl; Vector3d bField = Vector3d(b.x, b.y, b.z) * gauss; return bField; } +void SPHMagneticFieldGrid::init(const Vector3d &origin, double size) { + gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; + float s = size / kpc; + if (cacheEnabled) { + std::stringstream path; + path << cachePrefix << samples << "_" << s << "_" << v.x << "_" << v.y + << "_" << v.z << ".cache"; + std::string filename = path.str(); + std::ifstream infile(filename.c_str()); + if (infile) { + std::cout << "load cache file " << filename << std::endl; + field.init(v, s); + field.restore(filename); + } else { + field.init(v, s, database); + path << "." << time(NULL) << clock(); + std::string filename_tmp = path.str(); + field.dump(filename_tmp); + int ren = rename(filename_tmp.c_str(), filename.c_str()); + if (ren != 0) + remove(filename_tmp.c_str()); + } + } else { + field.init(v, s, database); + } +} + void SPHMagneticFieldGrid::setCachePrefix(std::string prefix) { cachePrefix = prefix; } From 2e82cf3e6b52e4391503ff63aee3a812fb623697 Mon Sep 17 00:00:00 2001 From: geromueller Date: Tue, 13 Nov 2012 10:21:38 +0100 Subject: [PATCH 0228/1298] always links libs statically --- libs/HepPID/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/HepPID/CMakeLists.txt b/libs/HepPID/CMakeLists.txt index d9e31fd8b..4017027f7 100644 --- a/libs/HepPID/CMakeLists.txt +++ b/libs/HepPID/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.6) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) -add_library(HepPID +add_library(HepPID STATIC src/ParticleIDMethods.cc src/ParticleName.cc src/Version.cc From 032d4b21ddb222c11201398656af57206f67057e Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 14 Nov 2012 11:12:23 +0100 Subject: [PATCH 0229/1298] 1D mode via xml steering --- include/mpc/XmlExecute.h | 2 + src/Nucleus.cpp | 2 +- src/Source.cpp | 2 +- src/XmlExecute.cpp | 380 ++++++++++++++++++++++++--------------- 4 files changed, 240 insertions(+), 146 deletions(-) diff --git a/include/mpc/XmlExecute.h b/include/mpc/XmlExecute.h index 019730554..77bcb571d 100644 --- a/include/mpc/XmlExecute.h +++ b/include/mpc/XmlExecute.h @@ -31,6 +31,8 @@ class XmlExecute { ref_ptr magnetic_field; Source source; bool is1D; + bool hasRedshift; + ref_ptr redshift; size_t nTrajectories; double Emin; double maxStep; diff --git a/src/Nucleus.cpp b/src/Nucleus.cpp index 1fae161b2..5a9d763d3 100644 --- a/src/Nucleus.cpp +++ b/src/Nucleus.cpp @@ -78,7 +78,7 @@ double getNucleusMass(int id) { int N = HepPID::A(id) - Z; double mass = nuclearMassTable.table[Z * 31 + N]; if (mass == 0) - throw std::runtime_error("mpc: nucleus not found " + kiss::str(id)); + throw std::runtime_error("getNucleusMass: nucleus not found " + kiss::str(id)); return mass; } diff --git a/src/Source.cpp b/src/Source.cpp index 60bac8c84..9e65f1603 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -308,7 +308,7 @@ SourceRedshift1D::SourceRedshift1D(Redshift* redishift) : void SourceRedshift1D::prepare(Candidate& candidate) const { double d = candidate.initial.getPosition().getMag(); - double z = redshift->getRedshift(d); + double z = redshift->comovingDistance2Redshift(d); candidate.setRedshift(z); } diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 9bc85ceeb..723fc5ebe 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -62,8 +62,7 @@ SourceUniformDistributionBox* loadSourceHomogeneousBox(pugi::xml_node &node) { return (new SourceUniformDistributionBox(origin, size)); } -SourceDensityGrid* loadSourceDensityGrid( - pugi::xml_node &node) { +SourceDensityGrid* loadSourceDensityGrid(pugi::xml_node &node) { int nx = childValue(node, "Nx"); int ny = childValue(node, "Ny"); int nz = childValue(node, "Nz"); @@ -95,6 +94,29 @@ SourceDensityGrid* loadSourceDensityGrid( return (new SourceDensityGrid(grid)); } +SourceDensityGrid1D* loadSourceDensityGrid1D(pugi::xml_node &node) { + int nx = childValue(node, "Nx"); + cout << " - Nx = " << nx << endl; + + double spacing = childValue(node, "Step_Mpc") * Mpc; + cout << " - Spacing = " << spacing / Mpc << " Mpc" << endl; + + ScalarGrid* grid = new ScalarGrid(Vector3d(0, 0, 0), nx, 1, 1, spacing); + + xml_node file_node = childNode(node, "File"); + string file_type = file_node.attribute("type").as_string(); + string file_name = file_node.child_value(); + cout << " - File = " << file_name << endl; + if (file_type == "ASCII") + loadGridFromTxt(grid, file_name); + else if (file_type == "FITS") + throw runtime_error(" --> FITS files not supported"); + else + throw runtime_error(" --> unknown file type"); + + return (new SourceDensityGrid1D(grid)); +} + XmlExecute::XmlExecute() : is1D(false), nTrajectories(0), Emin(0), maxStep(0) { } @@ -116,7 +138,7 @@ bool XmlExecute::load(const string &filename) { // ----- general settings ----- nTrajectories = (int) childValue(root, "TrajNumber"); - cout << "Trajectories: " << nTrajectories << endl; + cout << "Number of particles: " << nTrajectories << endl; double maxTime = childValue(root, "MaxTime_Mpc") * Mpc; cout << "Maximum time: " << maxTime / Mpc << " Mpc" << endl; @@ -130,7 +152,8 @@ bool XmlExecute::load(const string &filename) { Random &random = Random::instance(); random.seed(seed); cout << "Random seed: " << seed << endl; - } + } else + cout << "No random seed given. Using random random seed." << endl; // ----- environment ----- xml_node node; @@ -139,7 +162,7 @@ bool XmlExecute::load(const string &filename) { cout << "Environment: " << type << endl; if (type == "One Dimension") - throw runtime_error(" --> one dimension not supported"); + is1D = true; else if (type == "LSS") { // will be overwritten if (re)defined by magnetic field origin.x = childValue(node, "Xmin_Mpc", false) * Mpc; @@ -153,28 +176,74 @@ bool XmlExecute::load(const string &filename) { throw runtime_error(" --> unknown environment"); // ----- magnetic field ----- - node = childNode(root, "MagneticField"); - type = node.attribute("type").as_string(); - cout << "MagenticField: " << type << endl; - if (type == "Null") - magnetic_field = new UniformMagneticField(Vector3d(0, 0, 0)); - else if (type == "Uniform") - loadUniformMagneticField(node); - else if ((type == "LSS-Grid") or (type == "Kolmogoroff")) - loadGridMagneticField(node); - else { - cout << " --> unknown, set zero field" << endl; - magnetic_field = new UniformMagneticField(Vector3d(0, 0, 0)); + node = childNode(root, "MagneticField", false); + if (node) { + type = node.attribute("type").as_string(); + cout << "MagenticField: " << type << endl; + if ((type == "Null") or (type == "None")) + magnetic_field = new UniformMagneticField(Vector3d(0, 0, 0)); + else if (type == "Uniform") + loadUniformMagneticField(node); + else if ((type == "LSS-Grid") or (type == "Kolmogoroff")) + loadGridMagneticField(node); + else if (type == "1D") + cout << " --> not implemented" << endl; + else { + cout << " --> unknown, set zero field" << endl; + magnetic_field = new UniformMagneticField(Vector3d(0, 0, 0)); + } + } else { + if (!is1D) + throw runtime_error(" --> magnetic field not specified"); } // ----- propagator ----- - node = childNode(root, "Integrator"); - type = node.attribute("type").as_string(); - cout << "Integrator: " << type << endl; - if (type == "Cash-Karp RK") - loadDeflectionCK(node); - else - throw runtime_error(" --> unknown integrator"); + xml_node interaction_node = childNode(root, "Interactions"); + maxStep = childValue(interaction_node, "MaxStep_Mpc", false) * Mpc; + + if (is1D) { + cout << "Propagator: 1D" << endl; + modules.add(new SimplePropagation()); + + bool noRedshift = interaction_node.child("NoRedshift"); + hasRedshift = !(noRedshift); + + if (hasRedshift) { + double omegaM = 0.3; + if (root.child("OmegaM")) + omegaM = childValue(root, "OmegaM"); + + double omegaL = 0.7; + if (root.child("OmegaLambda")) + childValue(root, "OmegaLambda"); + + double H0 = 70.; + if (root.child("H0_km_s_Mpc")) + childValue(root, "H0_km_s_Mpc"); + + cout << "Redshift: OmegaM = " << omegaM << ", OmegaLambda = " + << omegaL << ", H0 = " << H0 << " km/s/Mpc" << endl; + + redshift = new Redshift(H0 / 100, omegaM, omegaL); + modules.add(redshift); + } else { + cout << " - No redshift" << endl; + } + } else { + node = childNode(root, "Integrator"); + type = node.attribute("type").as_string(); + cout << "Propagator: " << type << endl; + if (type == "Cash-Karp RK") + loadDeflectionCK(node); + else + throw runtime_error(" --> unknown integrator"); + } + + // ----- interactions ----- + type = interaction_node.attribute("type").as_string(); + cout << "Interactions: " << type << endl; + if (type == "Sophia") + loadSophia(interaction_node); // ----- minimum energy ----- modules.add(new MinimumEnergy(Emin)); @@ -183,25 +252,53 @@ bool XmlExecute::load(const string &filename) { modules.add(new MaximumTrajectoryLength(maxTime)); // ----- periodic boundaries ----- - loadPeriodicBoundaries(); + if (!is1D) + loadPeriodicBoundaries(); // ----- sources ----- node = childNode(root, "Sources"); - loadSources(node); + + // emission direction + if (is1D) + source.addProperty(new SourceDirection()); + else + source.addProperty(new SourceIsotropicEmission()); + + // position + type = node.attribute("type").as_string(); + cout << "Source(s): " << type << endl; + if (type == "Discrete") + loadDiscreteSources(node); + else if (type == "Continuous") + loadContinuousSources(node); + else + throw runtime_error(" --> unknown source type"); + + if (is1D and hasRedshift) { + cout << " - Redshift according to source distance" << endl; + source.addProperty(new SourceRedshift1D(redshift)); + } + + // spectrum + composition + loadSpectrumComposition(node); // ----- observers ----- - node = root.child("Observers"); - if (!node) - cout << "Observer(s) not specified" << endl; - else { - string type = node.attribute("type").as_string(); - cout << "Observers: " << type << endl; - if (type == "Spheres around Observers") - loadSpheresAroundObserver(node); - else if (type == "Spheres around Source") - loadSpheresAroundSource(node); - else - cout << " --> unknown observer" << endl; + if (is1D) { + modules.add(new Observer1D()); + } else { + node = root.child("Observers"); + if (!node) { + cout << "Observer(s) not specified" << endl; + } else { + string type = node.attribute("type").as_string(); + cout << "Observers: " << type << endl; + if (type == "Spheres around Observers") + loadSpheresAroundObserver(node); + else if (type == "Spheres around Source") + loadSpheresAroundSource(node); + else + cout << " --> unknown observer" << endl; + } } // ----- output ----- @@ -219,14 +316,15 @@ void XmlExecute::loadDeflectionCK(xml_node &node) { cout << " - Epsilon: " << epsilon << endl; double minStep = childValue(node, "MinStep_Mpc") * Mpc; - cout << " - Minimum Step: " << minStep / Mpc << " Mpc" << endl; + cout << " - Minimum step: " << minStep / Mpc << " Mpc" << endl; if (maxStep == 0) maxStep = numeric_limits::max(); - cout << " - Maximum Step: " << maxStep / Mpc << " Mpc" << endl; + cout << " - Maximum step: " << maxStep / Mpc << " Mpc" << endl; if (minStep >= maxStep) - throw runtime_error(" --> MaxStep must be larger than MinStep"); + throw runtime_error( + " --> Maximum step must be larger than minimum step"); modules.add(new DeflectionCK(magnetic_field, epsilon, minStep, maxStep)); } @@ -289,7 +387,8 @@ void XmlExecute::loadGridMagneticField(xml_node &node) { initTurbulence(field, brms, lMin, lMax, alpha); #endif // MPC_HAVE_FFTW3F #ifndef MPC_HAVE_FFTW3F - throw runtime_error("Turbulent field grid not available. Compile with FFTW3F."); + throw runtime_error( + "Turbulent field grid not available. Compile with FFTW3F."); #endif // MPC_HAVE_FFTW3F } @@ -298,7 +397,7 @@ void XmlExecute::loadGridMagneticField(xml_node &node) { void XmlExecute::loadPeriodicBoundaries() { if ((size.x == 0) or (size.y == 0) or (size.z == 0)) - throw runtime_error("Environment boundaries not set."); + throw runtime_error(" --> Environment boundaries not set"); cout << "Periodic boundaries" << endl; cout << " - Lower bounds: " << origin / Mpc << " Mpc" << endl; cout << " - Upper bounds: " << (origin + size) / Mpc << " Mpc" << endl; @@ -306,29 +405,22 @@ void XmlExecute::loadPeriodicBoundaries() { } void XmlExecute::loadSophia(xml_node &node) { - maxStep = childValue(node, "MaxStep_Mpc") * Mpc; - - if (node.child("NoRedshift")) - cout << " - No redshift" << endl; - else - cout << " - Redshift not implemented" << endl; - if (node.child("NoPairProd")) cout << " - No pair production" << endl; else modules.add(new ElectronPairProduction(CMB_IRB)); - if (node.child("NoPionProd")) + if (node.child("NoPionProd")) { cout << " - No pion production" << endl; - else { - modules.add(new ElectronPairProduction(CMB)); + } else { + modules.add(new SophiaPhotoPionProduction(CMB)); if (!node.child("NoIRPionProd")) - modules.add(new ElectronPairProduction(IRB)); + modules.add(new SophiaPhotoPionProduction(IRB)); } - if (node.child("NoPhotodisintegration")) + if (node.child("NoPhotodisintegration")) { cout << " - No photo disintegration" << endl; - else { + } else { modules.add(new PhotoDisintegration(CMB)); modules.add(new PhotoDisintegration(IRB)); } @@ -369,21 +461,82 @@ void XmlExecute::loadSpheresAroundSource(pugi::xml_node &node) { } } -void XmlExecute::loadSources(xml_node &node) { - // source isotropic emission - source.addProperty(new SourceIsotropicEmission()); +void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { + SourceMultiplePositions* sourcePositions = new SourceMultiplePositions(); - // source positions - string type = node.attribute("type").as_string(); - cout << "Source(s): " << type << endl; - if (type == "Discrete") - loadDiscreteSources(node); - else if (type == "Continuous") - loadContinuousSources(node); - else - throw runtime_error(" --> unknown source type"); + xml_node density_node = node.child("Density"); + if (density_node) { // draw positions from density distribution + string type = density_node.attribute("type").as_string(); + cout << " - Density: " << type << endl; + + int nSources = childValue(node, "Number"); + cout << " - Number = " << nSources << endl; + + SourceProperty* sourceDistribution = new SourceProperty(); + if (type == "Uniform") { + if (is1D) { + double xmin = childValue(density_node, "Xmin_Mpc") * Mpc; + double xmax = childValue(density_node, "Xmax_Mpc") * Mpc; + sourceDistribution = new SourceUniformDistribution1D(xmin, + xmax); + } else { + sourceDistribution = loadSourceHomogeneousBox(density_node); + } + } else if (type == "Grid") { + if (is1D) + sourceDistribution = loadSourceDensityGrid1D(density_node); + else + sourceDistribution = loadSourceDensityGrid(density_node); + } else { + throw runtime_error(" --> unknown source density type"); + } + ParticleState p; + for (int i = 0; i < nSources; i++) { + sourceDistribution->prepare(p); + sourcePositions->add(p.getPosition()); + cout << " - Position = " << p.getPosition() / Mpc << " Mpc" + << endl; + } + delete sourceDistribution; + } else { // read individual positions from xml + for (xml_node n = node.child("PointSource"); n; + n = n.next_sibling("PointSource")) { + Vector3d pos; + pos.x = childValue(n, "CoordX_Mpc") * Mpc; + pos.y = childValue(n, "CoordY_Mpc") * Mpc; + pos.z = childValue(n, "CoordZ_Mpc") * Mpc; + cout << " - Position " << pos / Mpc << " Mpc" << endl; + sourcePositions->add(pos); + } + } + source.addProperty(sourcePositions); +} - // source spectrum +void XmlExecute::loadContinuousSources(pugi::xml_node &node) { + xml_node density_node = node.child("Density"); + string type = density_node.attribute("type").as_string(); + cout << " - Density: " << type << endl; + if (type == "Uniform") + if (is1D) { + double minD = childValue(density_node, "Xmin_Mpc") * Mpc; + double maxD = childValue(density_node, "Xmax_Mpc") * Mpc; + cout << " - Minimum distance: " << minD / Mpc << " Mpc" << endl; + cout << " - Maximum distance: " << maxD / Mpc << " Mpc" << endl; + source.addProperty(new SourceUniformDistribution1D(minD, maxD)); + } else { + source.addProperty(loadSourceHomogeneousBox(density_node)); + } + else if (type == "Grid") { + if (is1D) { + source.addProperty(loadSourceDensityGrid1D(density_node)); + } else + source.addProperty(loadSourceDensityGrid(density_node)); + } else { + throw runtime_error(" --> unknown source density type"); + } +} + +void XmlExecute::loadSpectrumComposition(pugi::xml_node &node) { xml_node spectrum_node = node.child("Spectrum"); string spectrumType = spectrum_node.attribute("type").as_string(); cout << " - Spectrum: " << spectrumType << endl; @@ -395,12 +548,10 @@ void XmlExecute::loadSources(xml_node &node) { source.addProperty(new SourceEnergy(E)); } else if (spectrum_node.child("Rigidity_EeV")) throw runtime_error(" --> Fixed rigidity not implemented"); - else + else { throw runtime_error(" --> Source energy missing"); - - // source composition + } loadSourceNuclei(node); - } else if (spectrumType == "Power Law") { double alpha = childValue(spectrum_node, "Alpha"); cout << " - Power law index: " << alpha << endl; @@ -425,7 +576,6 @@ void XmlExecute::loadSources(xml_node &node) { composition->add(getNucleusId(A, Z), ab); } source.addProperty(composition); - } else if (spectrum_node.child("Ecut_EeV")) { double Emax = childValue(spectrum_node, "Ecut_EeV") * EeV; cout << " - Maximum energy: " << Emax / EeV << " EeV" << endl; @@ -435,63 +585,12 @@ void XmlExecute::loadSources(xml_node &node) { // source composition loadSourceNuclei(node); - - } else + } else { throw runtime_error( " --> maximum source energy / rigidity missing"); - - } else - throw runtime_error(" --> unknown source spectrum"); -} - -void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { - xml_node density_node = node.child("Density"); - if (density_node) { // draw positions from density distribution - string type = density_node.attribute("type").as_string(); - cout << " - Density: " << type << endl; - - int nSources = childValue(node, "Number"); - cout << " - Number = " << nSources << endl; - - SourceMultiplePositions* positions = - new SourceMultiplePositions(); - - if (type == "Uniform") { - SourceUniformDistributionBox* box = loadSourceHomogeneousBox(density_node); - ParticleState p; - for (int i = 0; i < nSources; i++) { - box->prepare(p); - positions->add(p.getPosition()); - cout << " - Position = " << p.getPosition() / Mpc << " Mpc" << endl; - } - - } else if (type == "Grid") { - SourceDensityGrid* grid = loadSourceDensityGrid(density_node); - ParticleState p; - for (int i = 0; i < nSources; i++) { - grid->prepare(p); - positions->add(p.getPosition()); - cout << " - Position = " << p.getPosition() / Mpc << " Mpc" << endl; - } - - } else - throw runtime_error(" --> unknown source density type"); - - source.addProperty(positions); - - } else { // read positions from xml card - SourceMultiplePositions *positions = new SourceMultiplePositions(); - for (xml_node n = node.child("PointSource"); n; - n = n.next_sibling("PointSource")) { - Vector3d pos; - pos.x = childValue(n, "CoordX_Mpc") * Mpc; - pos.y = childValue(n, "CoordY_Mpc") * Mpc; - pos.z = childValue(n, "CoordZ_Mpc") * Mpc; - cout << " - Position " << pos / Mpc << " Mpc" << endl; - positions->add(pos); } - source.addProperty(positions); - + } else { + throw runtime_error(" --> unknown source spectrum"); } } @@ -509,19 +608,6 @@ void XmlExecute::loadSourceNuclei(pugi::xml_node &node) { source.addProperty(composition); } -void XmlExecute::loadContinuousSources(pugi::xml_node &node) { - xml_node density_node = node.child("Density"); - string type = density_node.attribute("type").as_string(); - cout << " - Density: " << type << endl; - - if (type == "Uniform") - source.addProperty(loadSourceHomogeneousBox(density_node)); - else if (type == "Grid") - source.addProperty(loadSourceDensityGrid(density_node)); - else - throw runtime_error(" --> unknown source density type"); -} - void XmlExecute::loadOutput(xml_node &node) { string type = node.attribute("type").as_string(); cout << "Output: " << type << endl; @@ -537,13 +623,19 @@ void XmlExecute::loadOutput(xml_node &node) { } if (type == "Full Trajectories") - modules.add(new CRPropa2TrajectoryOutput(filename)); + if (is1D) + modules.add(new TrajectoryOutput1D(filename)); + else + modules.add(new TrajectoryOutput(filename)); else if (type == "Events") - modules.add(new CRPropa2EventOutput(filename)); + if (is1D) + modules.add(new EventOutput1D(filename)); + else + modules.add(new ConditionalOutput(filename)); else if (type == "None") return; else - cout << " -> unknown output" << endl; + cout << " --> unknown output" << endl; } void XmlExecute::run() { From 233a7dafc81829583f609121a3f1259768e11635 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 14 Nov 2012 11:12:46 +0100 Subject: [PATCH 0230/1298] renamed test xml files --- test/xml/1D.xml | 59 +++++++++++++++ ...ml => 3D_continuousHomogeneousSources.xml} | 0 ....xml => 3D_discreteHomogeneousSources.xml} | 0 ...orovBfield.xml => 3D_kolmogorovBfield.xml} | 0 test/xml/3D_noBfield.xml | 68 ++++++++++++++++++ ...uniformBfield.xml => 3D_uniformBfield.xml} | 0 test/xml/traj3d_ThrowNoBoundary.xml | 62 ---------------- test/xml/traj3d_noBfield.xml | 71 ------------------- 8 files changed, 127 insertions(+), 133 deletions(-) create mode 100644 test/xml/1D.xml rename test/xml/{traj3d_continuousHomogeneousSources.xml => 3D_continuousHomogeneousSources.xml} (100%) rename test/xml/{traj3d_discreteHomogeneousSources.xml => 3D_discreteHomogeneousSources.xml} (100%) rename test/xml/{traj3d_kolmogorovBfield.xml => 3D_kolmogorovBfield.xml} (100%) create mode 100644 test/xml/3D_noBfield.xml rename test/xml/{traj3d_uniformBfield.xml => 3D_uniformBfield.xml} (100%) delete mode 100644 test/xml/traj3d_ThrowNoBoundary.xml delete mode 100644 test/xml/traj3d_noBfield.xml diff --git a/test/xml/1D.xml b/test/xml/1D.xml new file mode 100644 index 000000000..5ac857ca7 --- /dev/null +++ b/test/xml/1D.xml @@ -0,0 +1,59 @@ + + + + + + + + + + output.txt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/xml/traj3d_continuousHomogeneousSources.xml b/test/xml/3D_continuousHomogeneousSources.xml similarity index 100% rename from test/xml/traj3d_continuousHomogeneousSources.xml rename to test/xml/3D_continuousHomogeneousSources.xml diff --git a/test/xml/traj3d_discreteHomogeneousSources.xml b/test/xml/3D_discreteHomogeneousSources.xml similarity index 100% rename from test/xml/traj3d_discreteHomogeneousSources.xml rename to test/xml/3D_discreteHomogeneousSources.xml diff --git a/test/xml/traj3d_kolmogorovBfield.xml b/test/xml/3D_kolmogorovBfield.xml similarity index 100% rename from test/xml/traj3d_kolmogorovBfield.xml rename to test/xml/3D_kolmogorovBfield.xml diff --git a/test/xml/3D_noBfield.xml b/test/xml/3D_noBfield.xml new file mode 100644 index 000000000..86627063d --- /dev/null +++ b/test/xml/3D_noBfield.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + output.txt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/xml/traj3d_uniformBfield.xml b/test/xml/3D_uniformBfield.xml similarity index 100% rename from test/xml/traj3d_uniformBfield.xml rename to test/xml/3D_uniformBfield.xml diff --git a/test/xml/traj3d_ThrowNoBoundary.xml b/test/xml/traj3d_ThrowNoBoundary.xml deleted file mode 100644 index ee2dd1cdf..000000000 --- a/test/xml/traj3d_ThrowNoBoundary.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - traj3d.txt - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/xml/traj3d_noBfield.xml b/test/xml/traj3d_noBfield.xml deleted file mode 100644 index f655e5679..000000000 --- a/test/xml/traj3d_noBfield.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - - - - - - - traj3d.txt - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From dcd6dbba3ee9f56e80322e53978a4280aaa12624 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 14 Nov 2012 11:17:06 +0100 Subject: [PATCH 0231/1298] add data-tools scripts to version control --- .../generate_epairTable.py | 83 +++++ data-tools/NuclearDecay/nuclear_decay.py | 300 ++++++++++++++++++ data-tools/NuclearMass/nuclear_mass.py | 62 ++++ .../PhotoDisintegration/photodis_combine.py | 51 +++ .../PhotoDisintegration/photodis_reformat.py | 101 ++++++ data-tools/PhotoPionProduction/photopion.py | 46 +++ data-tools/PhotonField/photonField.py | 78 +++++ data-tools/SPH/createModulationField.py | 120 +++++++ 8 files changed, 841 insertions(+) create mode 100644 data-tools/ElectronPairProduction/generate_epairTable.py create mode 100644 data-tools/NuclearDecay/nuclear_decay.py create mode 100644 data-tools/NuclearMass/nuclear_mass.py create mode 100644 data-tools/PhotoDisintegration/photodis_combine.py create mode 100644 data-tools/PhotoDisintegration/photodis_reformat.py create mode 100644 data-tools/PhotoPionProduction/photopion.py create mode 100644 data-tools/PhotonField/photonField.py create mode 100644 data-tools/SPH/createModulationField.py diff --git a/data-tools/ElectronPairProduction/generate_epairTable.py b/data-tools/ElectronPairProduction/generate_epairTable.py new file mode 100644 index 000000000..3cb0c7868 --- /dev/null +++ b/data-tools/ElectronPairProduction/generate_epairTable.py @@ -0,0 +1,83 @@ +from pylab import * +from mpc import * +from scipy import interpolate, integrate + + + +def densityCMB(eps): + # CMB spectral number density [1/m^3/J] at photon energy eps [J] + return 8 * pi * eps**2 / h_planck**3 / c_light**3 / (exp(eps / k_boltzmann / 2.725) - 1) + +xKneiske, yKneiske = genfromtxt('KneiskeIRB_z0.txt', unpack=1) +def densityIRB(eps): + # IRB (Kneiske et al. 2004) spectral number density [1/m^3/J] at photon energy eps [J] + x = h_planck * c_light / eps # wavelength [m] + y = interp(x * 1e6, xKneiske, yKneiske, 0, 0) * 1e-9 # lambda * I_lambda [W/m^2/sr] + y /= x # remove scaling with lambda; I_lambda [W/m^3/sr] + y *= x**2 / h_planck / c_light # convert to I_eps (using I_eps = - dlambda / deps * I_lambda, deps = - h*c / lambda^2 dlambda) + y *= 4 * pi / c_light # convert to energy density + y /= eps # convert to number density + return y + + + +### Calculate the energy loss -dE/dx due to electron pair production +# c.f. Blumenthal 1970, Phys. Rev. D Volume 1, Number 6, Page 1596-1602 + +# Tabulated values for equation (14) taken from figure 2 +# xi = 2 * gamma * eps / (me*c^2), where eps is the photon energy, gamma the nucleus lorentz factor +# phi(xi) integral over differential cross sections +# This could be replaced with an explicit calculation of the integral +x, y = genfromtxt('Blumenthal_phi.txt', comments='#', unpack=1) +phi = interpolate.interp1d(10**x, 10**y) +xiMin = 10**x[0] +xiMax = 10**x[-1] + +# prefactor of equation (13) +r0 = 2.817940e-15 # classical electron radius [m] +alpha = 7.297352e-3 # fine-structure constant +c = alpha * r0**2 * 1**2 * mass_electron**2 * c_light**4 + + + +### generate CMB table +# integrand of equation (13) with CMB +def f(xi, gamma): + eps = xi * mass_electron * c_light**2 / 2 / gamma + return densityCMB(eps) * phi(xi) / xi**2 + +N = 21 +A1 = zeros((N, 2)) + +for i, g in enumerate(linspace(8.5, 12.5, N)): + F, err = integrate.quad(f, xiMin, xiMax, 10**g) + A1[i,1] = c * F + A1[i,0] = g + +savetxt('epair_CMB.txt', A1, header='log10(lorentzFactor) dE/dx [J/m]', fmt=['%.1f','%.6e'], delimiter='\t') + + + +### generate IRB table +def f(xi, gamma): + eps = xi * mass_electron * c_light**2 / 2 / gamma + return densityIRB(eps) * phi(xi) / xi**2 + +N = 31 +A2 = zeros((N, 2)) + +for i, g in enumerate(linspace(6.5, 12.5, N)): + F, err = integrate.quad(f, xiMin, xiMax, 10**g) + A2[i,1] = c * F + A2[i,0] = g + +savetxt('epair_IRB.txt', A2, header='log10(lorentzFactor) dE/dx [J/m]', fmt=['%.1f','%.6e'], delimiter='\t') + + + +### generate combined table +A3 = A2.copy() +A3[10:,1] += A1[:,1] + +savetxt('epair_CMB_IRB.txt', A3, header='log10(lorentzFactor) dE/dx [J/m]', fmt=['%.1f','%.6e'], delimiter='\t') + diff --git a/data-tools/NuclearDecay/nuclear_decay.py b/data-tools/NuclearDecay/nuclear_decay.py new file mode 100644 index 000000000..a4e6aba2a --- /dev/null +++ b/data-tools/NuclearDecay/nuclear_decay.py @@ -0,0 +1,300 @@ +from numpy import * +import mpc + +# Script to preprocess the nuclear decay data table from the BNL NuDat2 database +# See http://www.nndc.bnl.gov/nudat2/indx_sigma.jsp +# Query settings: +# Z: 0-36, output: formatted file + +class Decay: + def __init__(self): + pass + + def __repr__(self): + return 'Z=%i N=%i mode=%s tau=%.1e br=%.2f'%(self.Z, self.N, self.mode, self.tau, self.br) + + def load(self, s): + l = s.split('\t') + + # Z, N, id + self.Z = int(l[2]) + self.N = int(l[3]) + self.id = self.Z * 1000 + self.N + + # decay time + s = l[9].strip() + if s == 'infinity': + self.tau = inf + elif s == '': + self.tau = 0 + else: + self.tau = float(s) / log(2) + + # mode + self.mode = l[12].strip() + + # branching ratio + s = ''.join(c for c in l[13] if c not in ('>','<','=','~','%',' ','?','\n')) + self.brString = s + if s == '': + self.br = 0. + else: + self.br = float(s) / 100. + + def isStable(self): + return self.tau == inf + + def isBetaPlus(self): + return self.mode.find('E') > -1 + + def isBetaMinus(self): + return self.mode.find('B') > -1 + + +### parse data file +print '\nParsing data file' +print '-------------------------------------' +fin = open('NuDat2.txt','r') +lines = fin.readlines() +fin.close() + +decayTable = [[[] for n in range(31)] for z in range(27)] + +for line in lines[1:-3]: + d = Decay() + d.load(line) + # skip if Z > 26 (Fe-56) + if d.Z > 26: + continue + # skip if N > 30 (Fe-56) + if d.N > 30: + continue + # skip if isomeric transition + if d.mode == 'IT': + print d, '<- skip (isomeric transition)' + continue + # skip if lifetime missing + if d.tau == 0: + print d, '<- skip (missing lifetime)' + continue + # skip if decay mode missing + if d.mode == '': + if not(d.isStable()): + print d, '<- skip (missing decay mode)' + continue + # else store in decay table + decayTable[d.Z][d.N].append(d) + + +### remove duplicate decays +print '\n\nRemoving duplicates' +print '-------------------------------------' +for z in range(27): + for n in range(31): + dList = decayTable[z][n] + + if len(dList) < 2: + continue + + for i, d1 in enumerate(dList): + for d2 in dList[i+1:]: + if d1.mode == d2.mode: + print d1 + print d2, ' <- remove \n' + dList.remove(d2) + + +### explicitly edit some entries +print '\nExplicitly editing certain entries' +print '-------------------------------------' + +# remove Li-5 alpha decay (equivalent to existing proton emission) +d0 = decayTable[3][2][0] +d1 = decayTable[3][2][1] +print d0 +print d1, ' <- remove (equivalent to neutron emission)\n' +decayTable[3][2].remove(d1) + +# remove He-5 alpha decay (equivalent to existing neutron emission) +d0 = decayTable[2][3][0] +d1 = decayTable[2][3][1] +print d1 +print d0, ' <- remove (equivalent to neutron emission)\n' +decayTable[2][3].remove(d0) + +# modify B-12 "B3A" decay to "B2A" as it would leave an empty nucleus +d = decayTable[5][7][1] +print d, ' <- change decay mode to B2A\n' +d.mode = 'B2A' + +# Fe-45: to make beta+ decays exclusive +d = decayTable[26][19][0] +print d, ' <- set branching ratio to 0 (ratio equal to sum of following ratios)' +d.br = 0 +brSum = 0 +for d in decayTable[26][19][1:]: + print d + brSum += d.br +for d in decayTable[26][19][1:]: + d.br /= brSum + + +### calculate exclusive mean life times +print '\n\nCalculating exclusive life times' +print '-------------------------------------' +for z in range(27): + for n in range(31): + dList = decayTable[z][n] + + # skip for 0 or 1 entry + if len(dList) < 2: + continue + + # get sum of branching ratios + brSum = 0 + for d in dList: + brSum += d.br + + # if sum is 0, set branching ratios to equal values + if brSum == 0: + for d in dList: + d.br = 1. / len(dList) + + # else if sum not 1, search for an inclusive decay and/or normalize the branching ratios + elif brSum != 1.: + dInclusive = None + brSumExclusive = 0 + for i,d in enumerate(dList): + if d.br == 1.0: + dInclusive = d # inclusive decay found + else: + brSumExclusive += d.br # add exclusive branching ratio + + if dInclusive != None: + if dInclusive.br <= brSumExclusive: + dList.remove(dInclusive) # remove if purely inclusive + else: + dInclusive.br -= brSumExclusive # else make exclusive + + # normalize all branching ratios + for d in dList: + d.br /= brSum + + # finally, calculate exclusive decay time by dividing with branching ratio, while removing zeros + for d in dList: + if d.br == 0: + print d, ' <- remove (branching ratio 0)' + dList.remove(d) + else: + d.tau /= d.br + + +### correct for electron capture contribution in beta+ decays +print '\nBeta+ correction' +print '-------------------------------------' +a0 = 5.29177e-11 # Bohr radius [m] +a0 /= mpc.c_light * (mpc.h_planck / 2 / pi) / mpc.eplus # convert to [1/eV] +Qe = mpc.mass_electron * mpc.c_squared / mpc.eV # [eV] + +def I1(Q): + x = Q / Qe + return Qe**5 * ((2*x**4 - 9*x**2 - 8) * sqrt(x**2-1) + x*log(x+sqrt(x**2-1))) / 15 + +for z in range(27): + for n in range(31): + for d in decayTable[z][n]: + if not(d.isBetaPlus()): + continue + + m1 = mpc.getNucleusMass(mpc.getNucleusId(z+n, z)) + m2 = mpc.getNucleusMass(mpc.getNucleusId(z+n, z - 1)) + Q = (m1 - m2) * mpc.c_squared / mpc.eV + + Qbeta = (Q - Qe) # [eV] + Qec = (Q + Qe) # [eV] + + # check if energetically possible + if Qbeta < 0: + print d, ' <- make stable (beta+ decay not possible)' + d.tau = inf + continue + + # see Basdevant, Fundamentals in Nuclear Physics, 4.3.2 and 4.3.3 + # ratio tau_beta+ / tau_ec +# f = 2 / pi**2 * (z/a0)**3 * Qec**2 / Q**5 * 30 + f = 2 / pi**2 * (z/a0)**3 * Qec**2 / I1(Q) + print d, ' <- beta+ correction %.1e'%f + d.tau *= 1 + f + + +### set proton / neutron dripping with very short life time for all other isotopes +print '\n\nSet proton / neutron dripping for all other isotopes' +print '-------------------------------------' +for z in range(0,27): + for n in range(0,31): + if (z + n)==0: + continue + + dList = decayTable[z][n] + + if len(dList) > 0: + continue + + # else set p/n dripping + d = Decay() + d.Z = z + d.N = n + d.tau = 1e-99 + d.br = 1. + if z > n: # proton dripping + d.mode = 'P' + else: # neutron dripping + d.mode = 'N' + dList.append(d) + + +### write to file +print '\n\nWrite to file' +print '-------------------------------------' +fout = open('nuclear_decay.txt','w') +fout.write('# Z, N, Mean Life Time [s], Decay Mode (#beta- #beta+ #alpha #p #n), dE\n') + +# decay mode codes: #beta- #beta+ #alpha #p #n +modeDict = {'STABLE' : '0', + 'N' : '00001', + '2N' : '00002', + 'P' : '00010', + '2P' : '00020', + 'A' : '00100', + '2A' : '00200', + 'B-' : '10000', + '2B-': '20000', + 'BN' : '10001', + 'B2N': '10002', + 'B3N': '10003', + 'B4N': '10004', + 'BNA': '10101', + 'BA' : '10100', + 'B2A': '10200', + 'B3A': '10300', + 'EC' : '01000', + '2EC': '02000', + 'EA' : '01100', + 'EP' : '01010', + 'E2P': '01020', + 'E3P': '01030'} + +for z in range(0,27): + for n in range(0,31): + if (z + n)==0: + continue + + for d in decayTable[z][n]: + # skip stable + if d.tau == inf: + continue + fout.write('%i %i %s %e\n'%(d.Z, d.N, modeDict[d.mode], d.tau)) + +fout.close() +print 'done' + diff --git a/data-tools/NuclearMass/nuclear_mass.py b/data-tools/NuclearMass/nuclear_mass.py new file mode 100644 index 000000000..1da8c7f6f --- /dev/null +++ b/data-tools/NuclearMass/nuclear_mass.py @@ -0,0 +1,62 @@ +from pylab import * +import mpc + +# This script generates a table of nuclear mass for all combinations (Z,N) Z=0..26, N=0..30 +# For measured atoms, the NIST data table is used. +# All other atomic masses are taken to be A * amu +# The nuclear mass is then approximated as atomic mass minus electron mass. +# Here, electron binding energies (~keV) can be neglected compared to nuclear binding energies (~MeV) and nucleon and electron masses (~GeV, ~MeV). + +### read NIST data +# See: http://www.nist.gov/pml/data/comp.cfm +# All Isotopes, Linearized ASCII Output +# http://physics.nist.gov/cgi-bin/Compositions/stand_alone.pl?ele=&ascii=ascii2&isotype=all +fin = open('NIST.txt', 'r') +D = zeros((27, 31)) + +for i in range(4): + fin.readline() # skip header + +for line in fin.readlines(): + if line.startswith('Atomic Number'): + z = int(line.strip('Atomic Number = ')) + continue + + if line.startswith('Mass Number'): + a = int(line.strip('Mass Number = ')) + continue + + if line.startswith('Relative Atomic Mass'): + line = line.strip('Relative Atomic Mass = ') + relAtomicMass = line.translate(None, '()#\n') + + n = a - z + if a == 1: + continue # skip H-1 + if z > 26: + continue # skip isotopes with Z > 26 + if n > 30: + continue # skip isotopes with N > 30 + + # mass in [kg] minus mass of electrons + D[z, n] = float(relAtomicMass) * mpc.amu - z * mpc.mass_electron + + +### add neutron and proton mass +D[1, 0] = mpc.mass_proton +D[0, 1] = mpc.mass_neutron + +### fill empty entries in table with A * amu - Z * m_e approximation +for z in range(27): + for n in range(31): + if D[z, n] == 0: + D[z, n] = (z + n) * mpc.amu - z * mpc.mass_electron + +## Write to file +fout = open('nuclear_mass.txt', 'w') +fout.write('# Nuclear Mass of Isotopes Z < 26 and A < 56\n') +for z in range(27): + for n in range(31): + fout.write(str(z) + ' ' + str(n) + ' ' + str(D[z, n]) + '\n') + +fout.close() diff --git a/data-tools/PhotoDisintegration/photodis_combine.py b/data-tools/PhotoDisintegration/photodis_combine.py new file mode 100644 index 000000000..9016e1913 --- /dev/null +++ b/data-tools/PhotoDisintegration/photodis_combine.py @@ -0,0 +1,51 @@ +# This script combines the photodisintegration rate tables for CMB and IRB. + +from numpy import * + + +fout = open('photodis_CMB_IRB.txt', 'w') +fout.write('#Z, N, disintegration channel (#n#p#H2#H3#He3#He4), disintegration rate [1/Mpc] (200 samples for log10(gamma) = 6-14)\n') + + +data1 = genfromtxt('photodis_CMB.txt', skip_header=1, unpack=True) +Z1, N1, channel1 = data1[0], data1[1], data1[2] + +data2 = genfromtxt('photodis_IRB.txt', skip_header=1, unpack=True) +Z2, N2, channel2 = data2[0], data2[1], data2[2] + +# Create unique identifiers for each species + channel +ID1 = Z1 * 1e8 + N1 * 1e6 + channel1 +ID2 = Z2 * 1e8 + N2 * 1e6 + channel2 + + +# Create a dictionary (id -> index) of ID1 for lookups +d = {} +for i, id1 in enumerate(ID1): + d[id1] = i + + +# loop over and save all IRB data while adding the corresponding CMB data +for i, id2 in enumerate(ID2): + rate = data2[3:, i] + + # find the CMB rate for the same channel if available + if d.has_key(id2): + j = d.pop(id2) # get and remove the dictionary entry + rate += data1[3:, j] # add up the inverse mean free paths + + fout.write('%i\t%i\t%i'%(Z2[i], N2[i], channel2[i])) + for r in rate: + fout.write('\t'+str(r)) + fout.write('\n') + + +# write the remaining CMB rates +keys = d.keys() +keys.sort() +for id1 in keys: + i = d[id1] + fout.write('%i\t%i\t%i'%(Z1[i], N1[i], channel1[i])) + rate = data1[3:, i] + for r in rate: + fout.write('\t'+str(r)) + fout.write('\n') diff --git a/data-tools/PhotoDisintegration/photodis_reformat.py b/data-tools/PhotoDisintegration/photodis_reformat.py new file mode 100644 index 000000000..81ea2f9d0 --- /dev/null +++ b/data-tools/PhotoDisintegration/photodis_reformat.py @@ -0,0 +1,101 @@ +from numpy import * + +# This script reformats the exclusive mean free path data files from CRPropa2. +# - The four CRPropa2 files are merged into one, +# - nuclides with Z>26 or N>30 are omitted and +# - disintegration rates < 1e-6/Mpc are set to 0. +# +# The folders with the date files being used, are found in [CRPropa2 source]/TabulatedTALYSMeanFreePath/. +# Copy the content or execute the script from within this folder. +# +# The used files are +# 'PDInitNucleusId.cmt' : Particle ID (Z*1000+A) and corresponding line numbers in 'PDExclTabMnFrPthCrossId.cmt' +# 'PDExclTabMnFrPthCrossId.cmt' : Disintegration channel (#n #p #H2 #H3 #He3 #He4) and data index in 'PDExclTabMnFrPthCross.cmt' +# 'PDExclTabMnFrPthCross.cmt' : Inverse mean free path in [1/Mpc] for 200 equidistant Lorentz-factors gamma = 10^6 - 10^14 +# +# CMB, IRB (Kneiske) + + +def getAZ(s): + # returns A, Z from the particle id (Z*1000+A) + pid = int(s) + return pid % 1000, pid // 1000 + + +def getDigit(number, d): + # returns the d-th digit, counted from the back + return number % (10**d) // (10**(d-1)) + + +def isBogus(Z, A, channel, j): + # checks if the disintegration channel is impossible or leaves an empty nucleus + nN = getDigit(channel, 6) + nP = getDigit(channel, 5) + nH2 = getDigit(channel, 4) + nH3 = getDigit(channel, 3) + nHe3 = getDigit(channel, 2) + nHe4 = getDigit(channel, 1) + + N = A - Z + + dZ = nP + nH2 + nH3 + 2*nHe3 + 2*nHe4 + dA = nN + nP + 2*nH2 + 3*nH3 + 3*nHe3 + 4*nHe4 + dN = dA - dZ + + if (Z - dZ < 0): + print 'Z\' < 0: skipping line', j + print 'Z=%i N=%i dZ=%i dN=%i channel=%i'%(Z,N,dZ,dN,channel)+'\n' + return True + if (N - dN < 0): + print 'N\' < 0: skipping line', j + print 'Z=%i N=%i dZ=%i dN=%i channel=%i'%(Z,N,dZ,dN,channel)+'\n' + return True + if (A - dA <= 0): + print 'A\' <= 0: skipping line', j + print 'Z=%i N=%i dZ=%i dN=%i channel=%i'%(Z,N,dZ,dN,channel)+'\n' + return True + + +def reformat(photonField): + # input files + data1 = genfromtxt(photonField+'/PDInitNucleusId.cmt', skip_header=1) + data2 = genfromtxt(photonField+'/PDExclTabMnFrPthCrossId.cmt') + data3 = genfromtxt(photonField+'/PDExclTabMnFrPthCross.cmt') + # output file + fout = open('photodis_'+photonField+'.txt','w') + fout.write('#Z, N, disintegration channel (#n#p#H2#H3#He3#He4), disintegration rate [1/Mpc] (200 samples for log10(gamma) = 6-14)') + + for i in range(size(data1, 0)): + pid = data1[i, 0] + + A, Z = getAZ(pid) # get particle charge- and mass number + N = A - Z + + if Z>26 or N>30: # skip isotopes heavier than Fe-56 + continue + + j0 = int(data1[i, 1]) # start index in for channels in 'PDExclTabMnFrPthCrossId.cmt' + j1 = int(data1[i, 2]) # end index + + for j in range(j0, j1): + channel = int(data2[j, 0]) + + if isBogus(Z,A,channel,j): + continue + + fout.write('\n') + fout.write(str(Z)+'\t'+str(N)+'\t') # write the particle's Z, A + fout.write(str(channel)) # write disintegration channel + + k0 = int(data2[j, 1]) # start index in 'PDExclTabMnFrPthCross.cmt' + + for rate in data3[k0:k0 + 200]: + if rate < 1e-6: + fout.write('\t0') # replace values < 1e-6 [1/Mpc] with 0 + else: + fout.write('\t'+str(rate)) + + +reformat('CMB') +reformat('IRB') + diff --git a/data-tools/PhotoPionProduction/photopion.py b/data-tools/PhotoPionProduction/photopion.py new file mode 100644 index 000000000..82ae5fd35 --- /dev/null +++ b/data-tools/PhotoPionProduction/photopion.py @@ -0,0 +1,46 @@ +from numpy import * + +# This script reformats the pion production rate data files from CRPropa2. +# Mean free pathes larger than the Hubble length are omitted +lHubble = 4300. # Mpc +# +# The data files used are found in CRPropa/src/Interactions/proton_sophia/ +# Copy the content or execute the script from within this folder. +# +# The used files are +# 'pionprodrate_n' : pion production rates of neutrons against the CMB +# 'pionprodrate_n_ir_y0' : pion production rates of neutrons against the IRB (Kneiske) +# 'pionprodrate_p' : pion production rates of protons against the CMB +# 'pionprodrate_p_ir_y0' : pion production rates of protons against the IRB (Kneiske) + + +# pion production rate on the CMB +eCMB, nCMB = genfromtxt('pionprodrate_n.txt', comments='#', unpack=True) +pCMB = genfromtxt('pionprodrate_p.txt', usecols=(1), comments='#') + +fout1 = open('photopion_CMB.txt', 'w') +fout1.write('# Pion production rate for protons and neutrons on the CMB\n') +fout1.write('# Energy [EeV], Rate [1/Mpc]\n') + +for E, p, n in zip(eCMB, pCMB, nCMB): + if (p < 1/lHubble) and (n < 1/lHubble): + continue + fout1.write('%.5f %.5f %.5f\n'%( E, p, n )) + +fout1.close() + + +# pion production rate on the IRB (Kneiske 2002) +eIRB, nIRB = genfromtxt('pionprodrate_n_ir_y0.txt', comments='#', unpack=True) +pIRB = genfromtxt('pionprodrate_p_ir_y0.txt', usecols=(1), comments='#') + +fout2 = open('photopion_IRB.txt', 'w') +fout2.write('# Pion production rate for protons and neutrons on IRB\n') +fout2.write('# Energy [EeV], Rate [1/Mpc]\n') + +for E, p, n in zip(eIRB, pIRB, nIRB): + if (p < 1/lHubble) and (n < 1/lHubble): + continue + fout2.write('%.5f %.5f %.5f\n'%( E, p, n )) + +fout2.close() diff --git a/data-tools/PhotonField/photonField.py b/data-tools/PhotonField/photonField.py new file mode 100644 index 000000000..60335da8c --- /dev/null +++ b/data-tools/PhotonField/photonField.py @@ -0,0 +1,78 @@ +from pylab import * +from mpc import h_planck, c_light, k_boltzmann, eV + + +def CMBSpectralRadiance(nu): + # CMB spectral radiance [W/sr/m^2/Hz] at frequency nu [1/s], see http://en.wikipedia.org/wiki/Planck%27s_law + return 2 * nu**3 * h_planck / c_light**2 / ( exp(nu * h_planck / k_boltzmann / 2.725) - 1 ) + +def CMBSpectralEnergyDensity(nu): + # CMB spectral energy density [J/m^3/Hz] at frequency nu [1/s] + return CMBSpectralRadiance(nu) * 4 * pi / c_light + +def CMBSpectralDensity(nu): + # CMB spectral number density [1/m^3/Hz] at frequency nu [1/s] + return CMBSpectralEnergyDensity(nu) / (nu * h_planck) + + +def IRBSpectralRadiance(nu): + # IRB (Kneiske et al. 2004) spectral radiance [W/sr/m^2/Hz] at frequency nu [1/s] + + # calculate wavelength [m] + x = c_light / nu + + # load data points + xKneiske, yKneiske = genfromtxt('Kneiske2004_IRB/z0.txt', unpack=1) + y = interp(x * 1e6, xKneiske, yKneiske, 0, 0) * 1e-9 # lambda * I_lambda [W/m^2/sr] + + # remove scaling with lambda; I_lambda [W/m^3/sr] + y /= x + + # convert to I_nu (using I_nu = - dlambda / dnu * I_lambda, dnu = - c / lambda^2 dlambda) + y *= x**2 / c_light + return y + +def IRBSpectralEnergyDensity(nu): + # IRB (Kneiske et al. 2004) spectral energy density [J/m^3/Hz] at frequency nu [1/s] + return IRBSpectralRadiance(nu) * 4 * pi / c_light + +def IRBSpectralDensity(nu): + # IRB (Kneiske et al. 2004) spectral density [1/m^3/Hz] at frequency nu [1/s] + return IRBSpectralEnergyDensity(nu) / (nu * h_planck) + + +if __name__ == "__main__": + nu1 = logspace(-5, -2.3) * eV / h_planck + sed1 = CMBSpectralEnergyDensity(nu1) + snd1 = CMBSpectralDensity(nu1) + + nu2 = logspace(-5, 1.5) * eV / h_planck + sed2 = IRBSpectralEnergyDensity(nu2) + snd2 = IRBSpectralDensity(nu2) + + # number of photons per m^3 = integral over spectral number density + # integration using midpoint rule + N1 = sum( (snd1[1:] + snd1[:-1]) / 2 * (nu1[1:] - nu1[:-1]) ) + N2 = sum( (snd2[1:] + snd2[:-1]) / 2 * (nu2[1:] - nu2[:-1]) ) + print N1 / 1e6, 'CMB-photons per cubic centimeter' + print N2 / 1e6, 'IRB-photons per cubic centimeter' + + # plotting + figure() + plot(nu1, sed1, label='CMB') + plot(nu2, sed2, label='IRB Kneiske') + xlabel('Frequency [Hz]') + ylabel('Spectral Energy Density [J/m$^{3}$/Hz]') + loglog() + legend(frameon=0) + savefig('spectralEnergyDensity.png', bbox_inches='tight') + + figure() + plot(nu1, snd1, label='CMB') + plot(nu2, snd2, label='IRB Kneiske') + xlabel('Frequency [Hz]') + ylabel('Spectral Density [1/m$^{3}$/Hz]') + loglog() + legend(frameon=0) + savefig('spectralDensity.png', bbox_inches='tight') + diff --git a/data-tools/SPH/createModulationField.py b/data-tools/SPH/createModulationField.py new file mode 100644 index 000000000..573b642c1 --- /dev/null +++ b/data-tools/SPH/createModulationField.py @@ -0,0 +1,120 @@ +from pylab import * +from scipy.interpolate import interp1d +from cStringIO import StringIO +import struct +from mpc import * + + +profile = StringIO(""" +# Profile of magnetic field strength vs baryonic density in the Minati box +# Lower extrapolation B = 206.404 + 12.9872 * rho + 0.193117 * rho**2 +# Higher extrapolation B = -37.3625 -2.74343 * rho -0.0585562 * rho**2 +# +# log10(rho/[g/cm^3]), log10(B/[G]) +-32.00000 -11.43459 +-31.97993 -11.42361 +-31.91850 -11.37153 +-31.85708 -11.33202 +-31.79566 -11.28935 +-31.73424 -11.25074 +-31.67281 -11.20560 +-31.61139 -11.16113 +-31.54997 -11.11273 +-31.48854 -11.06385 +-31.42712 -11.01348 +-31.36570 -10.96107 +-31.30427 -10.90346 +-31.24285 -10.83643 +-31.18143 -10.76371 +-31.12001 -10.67964 +-31.05858 -10.58822 +-30.99716 -10.48548 +-30.93574 -10.37223 +-30.87431 -10.24660 +-30.81289 -10.11632 +-30.75147 -9.96395 +-30.69004 -9.80515 +-30.62862 -9.63804 +-30.56720 -9.46599 +-30.50578 -9.28175 +-30.44435 -9.09687 +-30.38293 -8.91053 +-30.32151 -8.73668 +-30.26008 -8.56165 +-30.19866 -8.39986 +-30.13724 -8.24704 +-30.07581 -8.10704 +-30.01439 -7.98537 +-29.95297 -7.86703 +-29.89155 -7.76893 +-29.83012 -7.67947 +-29.76870 -7.59368 +-29.70728 -7.51493 +-29.64585 -7.45123 +-29.58443 -7.39008 +-29.52301 -7.33190 +-29.46158 -7.28033 +-29.40016 -7.22940 +-29.33874 -7.18511 +-29.27732 -7.14020 +-29.21589 -7.09864 +-29.15447 -7.05942 +-29.09305 -7.01471 +-29.03162 -6.96864 +-28.97020 -6.93470 +-28.90878 -6.90071 +-28.84735 -6.86472 +-28.78593 -6.81636 +-28.72451 -6.80306 +-28.66309 -6.75334 +-28.60166 -6.74123 +-28.54024 -6.70163 +-28.47882 -6.65852 +-28.41739 -6.64615 +-28.35597 -6.62567 +-28.29455 -6.57452 +-28.23312 -6.56336 +-28.17170 -6.51866 +-28.11028 -6.48613 +-28.04886 -6.47825 +-28.00000 -6.45452 +""") + +tablgRho, tablgB = genfromtxt(profile, unpack=True, comments='#') +f = interp1d(tablgRho, tablgB) + +def modulation(x): + if (x <= -32): + return 206.404 + 12.9872 * x + 0.193117 * x * x + elif (x >= -28): + return -37.3625 - 2.74343 * x - 0.0585562 * x * x + else: + return f(x) + +#gadget mass -db mhd_z.db -ox 54000 -oy 54000 -oz 54000 -size 132000 -bins 257 -o density_54-186Mpc_257bins.raw -dump +#gadget mass -db mhd_z.db -ox 54000 -oy 54000 -oz 54000 -size 132000 -bins 513 -o density_54-186Mpc_513bins.raw -dump + +# takes a N+1 grid, the last entry is skipped to be conform with a periodic grid +fin = open('density_54-186Mpc_513bins.raw', 'rb') +fout = open('mod_MiniatiProfile_DolagDensity_54-186Mpc_512bins.raw', 'wb') +N = 513 + +sumb2 = 0 +for ix in range(N): + print ix + for iy in range(N): + for iz in range(N): + rho = struct.unpack('f',fin.read(4))[0] + rho *= 1.98892e40 * 0.7**2 / kpc**3 # density [kg/m^3] + x = log10(rho) - 3 # log10(density [g/cm^3]) + b = 10**modulation(x) # field strength [G] + b *= gauss # field strength [T] + sumb2 += b**2 + fout.write(struct.pack('f', b)) + fin.read(4) + fin.read(4 * (N + 1)) + +print 'Brms =', (sumb2 / N**3)**.5, "T" + +fin.close() +fout.close() From 37e5b8a2c34307a0a0547006726148001a7e745d Mon Sep 17 00:00:00 2001 From: geromueller Date: Tue, 13 Nov 2012 12:15:52 +0100 Subject: [PATCH 0232/1298] print invalid position to cerr --- src/magneticField/SPHMagneticField.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/magneticField/SPHMagneticField.cpp b/src/magneticField/SPHMagneticField.cpp index 33dc605b5..da7856900 100644 --- a/src/magneticField/SPHMagneticField.cpp +++ b/src/magneticField/SPHMagneticField.cpp @@ -23,7 +23,7 @@ Vector3d SPHMagneticField::getField(const Vector3d &position) const { gadget::Vector3f b; bool isGood = field.getField(r / kpc, b); if (!isGood) - std::cout << "mpc::SPHMagneticField invalid position : " << position + std::cerr << "mpc::SPHMagneticField invalid position : " << position << std::endl; Vector3d bField = Vector3d(b.x, b.y, b.z) * gauss; return bField; @@ -35,7 +35,7 @@ double SPHMagneticField::getRho(const Vector3d& position) const { float rho; bool isGood = field.getRho(r / kpc, overlaps, rho); if (!isGood) - std::cout << "mpc::SPHMagneticField invalid position : " << position + std::cerr << "mpc::SPHMagneticField invalid position : " << position << std::endl; return rho * 1.98892e40 * kilogram * pow(0.7, 2) / pow(kpc, 3); } @@ -59,7 +59,7 @@ Vector3d SPHMagneticFieldGrid::getField(const Vector3d &position) const { gadget::Vector3f b; bool isGood = field.getField(r / kpc, b); if (!isGood) - std::cout << "mpc::SPHMagneticField invalid position : " << position + std::cerr << "mpc::SPHMagneticField invalid position : " << position << std::endl; Vector3d bField = Vector3d(b.x, b.y, b.z) * gauss; return bField; From 037d2c2d2b8e7afa832e9352a13df1dd8c0e04aa Mon Sep 17 00:00:00 2001 From: geromueller Date: Tue, 20 Nov 2012 09:59:51 +0100 Subject: [PATCH 0233/1298] make Referenced thread safe --- include/mpc/Referenced.h | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/include/mpc/Referenced.h b/include/mpc/Referenced.h index cfd93124c..d754d3c94 100644 --- a/include/mpc/Referenced.h +++ b/include/mpc/Referenced.h @@ -36,7 +36,17 @@ class Referenced { } inline size_t addReference() const { - return ++_referenceCount; + int newRef; +#if defined(OPENMP_3_1) + #pragma omp atomic capture + {newRef = _referenceCount++;} +#elif defined(GCC_EXTENSION) + newRef = __sync_add_and_fetch(&_referenceCount, 1); +#else + #pragma omp critical + {newRef = _referenceCount++;} +#endif + return newRef; } inline size_t removeReference() const { @@ -46,7 +56,17 @@ class Referenced { << "WARNING: Remove reference from Object with NO references: " << typeid(*this).name() << std::endl; #endif - int newRef = --_referenceCount; + int newRef; +#if defined(OPENMP_3_1) + #pragma omp atomic capture + {newRef = _referenceCount--;} +#elif defined(GCC_EXTENSION) + newRef = __sync_add_and_fetch(&_referenceCount, -1); +#else + #pragma omp critical + {newRef = _referenceCount--;} +#endif + if (newRef == 0) { delete this; } From 55643fae2078efb87ec352e1af42221af19ba2bc Mon Sep 17 00:00:00 2001 From: geromueller Date: Thu, 22 Nov 2012 17:12:45 +0100 Subject: [PATCH 0234/1298] fix signal handling on non gnu systems --- src/ModuleList.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index fa2ff8fd7..7da8c686a 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -2,8 +2,11 @@ #include "mpc/ProgressBar.h" #include -#include #include +#include +#ifndef sighandler_t +typedef void (*sighandler_t)(int); +#endif using namespace std; From 04ff1f620a10882d073263744ac44c86c30a5357 Mon Sep 17 00:00:00 2001 From: geromueller Date: Thu, 22 Nov 2012 17:19:58 +0100 Subject: [PATCH 0235/1298] improve performance in DeflectionCK, use atomic operation on gcc --- include/mpc/Referenced.h | 6 +++--- src/module/DeflectionCK.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mpc/Referenced.h b/include/mpc/Referenced.h index d754d3c94..5a42ae564 100644 --- a/include/mpc/Referenced.h +++ b/include/mpc/Referenced.h @@ -40,7 +40,7 @@ class Referenced { #if defined(OPENMP_3_1) #pragma omp atomic capture {newRef = _referenceCount++;} -#elif defined(GCC_EXTENSION) +#elif defined(__GNUC__) newRef = __sync_add_and_fetch(&_referenceCount, 1); #else #pragma omp critical @@ -60,8 +60,8 @@ class Referenced { #if defined(OPENMP_3_1) #pragma omp atomic capture {newRef = _referenceCount--;} -#elif defined(GCC_EXTENSION) - newRef = __sync_add_and_fetch(&_referenceCount, -1); +#elif defined(__GNUC__) + newRef = __sync_sub_and_fetch(&_referenceCount, 1); #else #pragma omp critical {newRef = _referenceCount--;} diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index 7fded6257..fc71b1210 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -15,7 +15,7 @@ class LorentzForce: public ExplicitRungeKutta::F { ParticleState *particle; MagneticField *field; - LorentzForce(ParticleState *particle, ref_ptr field) { + LorentzForce(ParticleState *particle, MagneticField *field) { this->particle = particle; this->field = field; } From b389fccd8349d7364dd6d930213bdb75dc04ee13 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 30 Nov 2012 17:48:52 +0100 Subject: [PATCH 0236/1298] Full JF2012 field (regular, striated and turbulent) --- include/mpc/Grid.h | 28 +++- include/mpc/magneticField/JF2012Field.h | 72 +++++---- src/Source.cpp | 4 +- src/magneticField/JF2012Field.cpp | 203 +++++++++++++++--------- test/testCore.cpp | 20 ++- 5 files changed, 217 insertions(+), 110 deletions(-) diff --git a/include/mpc/Grid.h b/include/mpc/Grid.h index 0e25862b2..3acfe1e7b 100644 --- a/include/mpc/Grid.h +++ b/include/mpc/Grid.h @@ -21,6 +21,11 @@ inline void reflectiveClamp(double x, int n, int &lo, int &hi) { hi = lo + (lo < n-1); } +/** Symmetrical round */ +inline double round(double r) { + return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); +} + /** @class Grid @brief Template class for fields on a periodic grid with trilinear interpolation @@ -125,13 +130,34 @@ class Grid: public Referenced { } /** Position of the grid point of a given index */ - Vector3d getPosition(int index) const { + Vector3d positionFromIndex(int index) const { int ix = index / (Ny * Nz); int iy = (index / Nz) % Ny; int iz = index % Nz; return Vector3d(ix, iy, iz) * spacing + origin; } + /** Value of a grid point that is closest to a given position */ + T closestValue(const Vector3d &position) const { + Vector3d r = (position - origin) / spacing; + int ix = round(r.x); + int iy = round(r.y); + int iz = round(r.z); + if (reflective) { + while ((ix < 0) or (ix > Nx)) + ix = 2 * Nx * (ix > Nx) - ix; + while ((iy < 0) or (iy > Ny)) + iy = 2 * Ny * (iy > Ny) - iy; + while ((iz < 0) or (iz > Nz)) + iz = 2 * Nz * (iz > Nz) - iz; + } else { + ix = ((ix % Nx) + Nx) % Nx; + iy = ((iy % Ny) + Ny) % Ny; + iz = ((iz % Nz) + Nz) % Nz; + } + return get(ix, iy, iz); + } + /** Interpolate the grid at a given position */ T interpolate(const Vector3d &position) const { // position on a unit grid diff --git a/include/mpc/magneticField/JF2012Field.h b/include/mpc/magneticField/JF2012Field.h index a60e0aed1..80c209d99 100644 --- a/include/mpc/magneticField/JF2012Field.h +++ b/include/mpc/magneticField/JF2012Field.h @@ -7,48 +7,64 @@ namespace mpc { class JF2012Field: public MagneticField { - // disk field - double bDisk[8]; // field strengths of arms at r=5 kpc, b8 is determined from other 7 - double rArms[8]; // radii where each arm crosses the negative x-axis - double pitch; // pitch angle + bool useStriated; + bool useTurbulent; + + // disk spiral arms + double rArms[8]; // radii where each arm crosses the negative x-axis + double pitch; // pitch angle double sinPitch, cosPitch, tan90MinusPitch; - double bRing; // ring field strength 3 rXc, z = 0 + // poloidal halo + double bX; // field strength at origin + double thetaX0; // constant elevation angle at r > rXc, z = 0 double sinThetaX0, cosThetaX0, tanThetaX0; - double rXc; // radius of varying elevation angle region - double rX; // exponential scale height + double rXc; // radius of varying elevation angle region + double rX; // exponential scale height + + // Striated field -------------------------------------------------------- + double sqrtbeta; // relative strength of striated field + ref_ptr striatedGrid; + + // Small-scale turbulent field ------------------------------------------- + ref_ptr turbulentGrid; + // disk + double bDiskTurb[8]; // field strengths in arms at r=5 kpc + double bDiskTurb5; // field strength at r<5kpc + double zDiskTurb; // Gaussian scale height of disk + // halo + double bHaloTurb; // halo field strength + double rHaloTurb; // exponential scale length + double zHaloTurb; // Gaussian scale height public: JF2012Field(); - Vector3d getField(const Vector3d& pos) const; -}; -class JF2012TurbulentField: public MagneticField { - double b5; - double bDisk[8]; // field strengths of arms at r=5 kpc - double rArms[8]; // radii where each arm crosses the negative x-axis - double pitch; - double tan90MinusPitch; - double r0; // radial attenuation length - double z0; // vertical attenuation length - double z0S; // vertical attenuation length for spiral field - ref_ptr grid; // turbulent field grid + void randomStriated(int seed = 0); + void randomTurbulent(int seed = 0); + + void setStriatedGrid(ref_ptr grid); + void setTurbulentGrid(ref_ptr grid); + + ref_ptr getStriatedGrid(); + ref_ptr getTurbulentGrid(); + + Vector3d getRegularField(const Vector3d& pos) const; + Vector3d getStriatedField(const Vector3d& pos) const; + Vector3d getTurbulentField(const Vector3d& pos) const; -public: - JF2012TurbulentField(); - double getModulation(const Vector3d& pos) const; Vector3d getField(const Vector3d& pos) const; }; -} +} // namespace mpc #endif // MPC_JF2012FIELD_H diff --git a/src/Source.cpp b/src/Source.cpp index 9e65f1603..c14ae4d6f 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -220,7 +220,7 @@ void SourceDensityGrid::prepare(ParticleState& particle) const { std::vector &v = grid->getGrid(); std::vector::iterator it = lower_bound(v.begin(), v.end(), r); int i = it - v.begin(); - Vector3d pos = grid->getPosition(i); + Vector3d pos = grid->positionFromIndex(i); // draw uniform position within bin double dx = random.rand() - 0.5; @@ -254,7 +254,7 @@ void SourceDensityGrid1D::prepare(ParticleState& particle) const { std::vector &v = grid->getGrid(); std::vector::iterator it = lower_bound(v.begin(), v.end(), r); int i = it - v.begin(); - Vector3d pos = grid->getPosition(i); + Vector3d pos = grid->positionFromIndex(i); // draw uniform position within bin double dx = random.rand() - 0.5; diff --git a/src/magneticField/JF2012Field.cpp b/src/magneticField/JF2012Field.cpp index d8943559d..f09d2d10f 100644 --- a/src/magneticField/JF2012Field.cpp +++ b/src/magneticField/JF2012Field.cpp @@ -1,6 +1,7 @@ #include "mpc/magneticField/JF2012Field.h" #include "mpc/Units.h" #include "mpc/GridTools.h" +#include "mpc/Random.h" namespace mpc { @@ -9,11 +10,25 @@ double logisticFunction(double x, double x0, double w) { } JF2012Field::JF2012Field() { + useStriated = false; + useTurbulent = false; + + // spiral arms pitch = 11.5 * M_PI / 180; sinPitch = sin(pitch); cosPitch = cos(pitch); tan90MinusPitch = tan(M_PI / 2 - pitch); + rArms[0] = 5.1 * kpc; + rArms[1] = 6.3 * kpc; + rArms[2] = 7.1 * kpc; + rArms[3] = 8.3 * kpc; + rArms[4] = 9.8 * kpc; + rArms[5] = 11.4 * kpc; + rArms[6] = 12.7 * kpc; + rArms[7] = 15.5 * kpc; + + // regular field bRing = 0.1 * muG; hDisk = 0.40 * kpc; wDisk = 0.27 * kpc; @@ -27,15 +42,6 @@ JF2012Field::JF2012Field() { bDisk[6] = 0.0 * muG; bDisk[7] = 2.7 * muG; - rArms[0] = 5.1 * kpc; - rArms[1] = 6.3 * kpc; - rArms[2] = 7.1 * kpc; - rArms[3] = 8.3 * kpc; - rArms[4] = 9.8 * kpc; - rArms[5] = 11.4 * kpc; - rArms[6] = 12.7 * kpc; - rArms[7] = 15.5 * kpc; - bNorth = 1.4 * muG; bSouth = -1.1 * muG; rNorth = 9.22 * kpc; @@ -50,17 +56,78 @@ JF2012Field::JF2012Field() { tanThetaX0 = tan(thetaX0); rXc = 4.8 * kpc; rX = 2.9 * kpc; + + // striated field + sqrtbeta = sqrt(1.36); + + // turbulent field + bDiskTurb[0] = 10.81 * muG; + bDiskTurb[1] = 6.96 * muG; + bDiskTurb[2] = 9.59 * muG; + bDiskTurb[3] = 6.96 * muG; + bDiskTurb[4] = 1.96 * muG; + bDiskTurb[5] = 16.34 * muG; + bDiskTurb[6] = 37.29 * muG; + bDiskTurb[7] = 10.35 * muG; + + bDiskTurb5 = 7.63 * muG; + zDiskTurb = 0.61 * kpc; + + bHaloTurb = 4.68 * muG; + rHaloTurb = 10.97 * kpc; + zHaloTurb = 2.84 * kpc; } -Vector3d JF2012Field::getField(const Vector3d& pos) const { - Vector3d b(0.); +void JF2012Field::randomStriated(int seed) { + useStriated = true; + int N = 100; + striatedGrid = new ScalarGrid(Vector3d(0.), N, 0.1 * kpc); + + Random random; + if (seed != 0) + random.seed(seed); + + for (int ix = 0; ix < N; ix++) + for (int iy = 0; iy < N; iy++) + for (int iz = 0; iz < N; iz++) { + float &f = striatedGrid->get(ix, iy, iz); + f = round(random.rand()) * 2 - 1; + } +} + +void JF2012Field::randomTurbulent(int seed) { + useTurbulent = true; + // turbulent field with Kolmogorov spectrum, B_rms = 1 and Lc = 60 parsec + turbulentGrid = new VectorGrid(Vector3d(0.), 256, 4 * parsec); + initTurbulence(turbulentGrid, 1., 16 * parsec, 255.5 * parsec, -11. / 3., + seed); +} + +void JF2012Field::setStriatedGrid(ref_ptr grid) { + useStriated = true; + striatedGrid = grid; +} + +void JF2012Field::setTurbulentGrid(ref_ptr grid) { + useTurbulent = true; + turbulentGrid = grid; +} + +ref_ptr JF2012Field::getStriatedGrid() { + return striatedGrid; +} - if (pos.getMag() < 1 * kpc) - return b; // no field if distance to GC < 1 kpc +ref_ptr JF2012Field::getTurbulentGrid() { + return turbulentGrid; +} + +Vector3d JF2012Field::getRegularField(const Vector3d& pos) const { + Vector3d b(0.); double r = sqrt(pos.x * pos.x + pos.y * pos.y); // in-plane radius - if (r > 20 * kpc) - return b; // no field if in-plane distance to GC > 20 kpc + double d = pos.getMag(); // distance to galactic center + if ((d < 1 * kpc) or (d > 20 * kpc)) + return b; double phi = pos.getPhi(); // azimuth double sinPhi = sin(phi); @@ -70,13 +137,14 @@ Vector3d JF2012Field::getField(const Vector3d& pos) const { // disk field if (r > 3 * kpc) { + double bMag; if (r < 5 * kpc) { // molecular ring - double bMagD = bRing * (5 * kpc / r) * (1 - lfDisk); - b.x += -bMagD * sinPhi; - b.y += bMagD * cosPhi; + bMag = bRing * (5 * kpc / r) * (1 - lfDisk); + b.x += -bMag * sinPhi; + b.y += bMag * cosPhi; - } else if (r < 20 * kpc) { + } else { // spiral region double r_negx = r * exp(-(phi - M_PI) / tan90MinusPitch); if (r_negx > rArms[7]) @@ -84,14 +152,13 @@ Vector3d JF2012Field::getField(const Vector3d& pos) const { if (r_negx > rArms[7]) r_negx = r * exp(-(phi + 3 * M_PI) / tan90MinusPitch); - double bMagD; for (int i = 7; i >= 0; i--) if (r_negx < rArms[i]) - bMagD = bDisk[i]; + bMag = bDisk[i]; - bMagD *= (5 * kpc / r) * (1 - lfDisk); - b.x += bMagD * (sinPitch * cosPhi - cosPitch * sinPhi); - b.y += bMagD * (sinPitch * sinPhi + cosPitch * cosPhi); + bMag *= (5 * kpc / r) * (1 - lfDisk); + b.x += bMag * (sinPitch * cosPhi - cosPitch * sinPhi); + b.y += bMag * (sinPitch * sinPhi + cosPitch * cosPhi); } } @@ -104,7 +171,7 @@ Vector3d JF2012Field::getField(const Vector3d& pos) const { b.x += -bMagH * sinPhi; b.y += bMagH * cosPhi; - // X-halo field + // poloidal halo field double bMagX; double sinThetaX, cosThetaX; double rp; @@ -131,53 +198,27 @@ Vector3d JF2012Field::getField(const Vector3d& pos) const { return b; } -JF2012TurbulentField::JF2012TurbulentField() { - // correlation length = 0.060 * kpc; - r0 = 10.65363798 * kpc; - z0 = 3.89915783 * kpc; - - pitch = 11.5 * M_PI / 180; - tan90MinusPitch = tan(M_PI / 2 - pitch); - - b5 = 5.35262527 * muG; - z0S = 0.58119582 * kpc; - - bDisk[0] = 7.94373074 * muG; - bDisk[1] = 4.4140519 * muG; - bDisk[2] = 6.72729298 * muG; - bDisk[3] = 4.69436688 * muG; - bDisk[4] = 1.35254503 * muG; - bDisk[5] = 10.91095824; - bDisk[6] = 24.74973782; - bDisk[7] = 6.86975446; - - rArms[0] = 5.1 * kpc; - rArms[1] = 6.3 * kpc; - rArms[2] = 7.1 * kpc; - rArms[3] = 8.3 * kpc; - rArms[4] = 9.8 * kpc; - rArms[5] = 11.4 * kpc; - rArms[6] = 12.7 * kpc; - rArms[7] = 15.5 * kpc; - - // create a turbulent field with Kolmogorov spectrum, B_rms = 1 and Lc = 60 parsec - grid = new VectorGrid(Vector3d(0.), 256, 8 * parsec); - double seed = 42; - initTurbulence(grid, 1., 16 * parsec, 255.5 * parsec, -11/3., seed); +Vector3d JF2012Field::getStriatedField(const Vector3d& pos) const { + Vector3d b = getRegularField(pos); + return b * (1. + sqrtbeta * striatedGrid->closestValue(pos)); } -double JF2012TurbulentField::getModulation(const Vector3d& pos) const { - double r = sqrt(pos.x * pos.x + pos.y * pos.y); - if (r > 20 * kpc) - return 0; // no field if in-plane distance to GC > 20 kpc +Vector3d JF2012Field::getTurbulentField(const Vector3d& pos) const { + Vector3d b(0.); + + if (pos.getMag() > 20 * kpc) + return b; + double r = sqrt(pos.x * pos.x + pos.y * pos.y); // in-plane radius double phi = pos.getPhi(); // azimuth - // disk field - double spiralNorm; + double bMag; + + // disk if (r < 5 * kpc) { - spiralNorm = b5; - } else if (r < 20 * kpc) { + bMag = bDiskTurb5; + } else { + // spiral region double r_negx = r * exp(-(phi - M_PI) / tan90MinusPitch); if (r_negx > rArms[7]) r_negx = r * exp(-(phi + M_PI) / tan90MinusPitch); @@ -186,22 +227,28 @@ double JF2012TurbulentField::getModulation(const Vector3d& pos) const { for (int i = 7; i >= 0; i--) if (r_negx < rArms[i]) - spiralNorm = bDisk[i]; - - spiralNorm *= (5 * kpc / r); + bMag = bDiskTurb[i]; } - spiralNorm *= exp(-0.5 * pow(pos.z / z0S, 2)); + bMag *= exp(-0.5 * pow(pos.z / zDiskTurb, 2)); - double smoothNorm = 1; - smoothNorm *= exp(-1. * fabs(pos.z) / z0); - smoothNorm *= exp(-1. * fabs(r) / r0); + // halo + bMag += bHaloTurb * exp(-1. * (r / rHaloTurb)) + * exp(-0.5 * pow(pos.z / zHaloTurb, 2)); - return sqrt(smoothNorm * smoothNorm + spiralNorm * spiralNorm); + // modulate turbulent field + b = turbulentGrid->interpolate(pos) * bMag; + return b; } -Vector3d JF2012TurbulentField::getField(const Vector3d& pos) const { - Vector3d b = grid->interpolate(pos); - return b * getModulation(pos); +Vector3d JF2012Field::getField(const Vector3d& pos) const { + Vector3d b(0.); + if (useStriated) + b += getStriatedField(pos); + else + b += getRegularField(pos); + if (useTurbulent) + b += getTurbulentField(pos); + return b; } -} +} // namespace mpc diff --git a/test/testCore.cpp b/test/testCore.cpp index 0721bb580..e6d3ad91d 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -243,13 +243,31 @@ TEST(ScalarGrid, SimpleTest) { // Test index handling: get position of grid point (2, 3, 4) size_t some_index = 2 * Ny * Nz + 3 * Nz + 4; Vector3d position = origin + Vector3d(2, 3, 4) * spacing; - EXPECT_EQ(position, grid.getPosition(some_index)); + EXPECT_EQ(position, grid.positionFromIndex(some_index)); grid.get(2, 3, 4) = 7; EXPECT_FLOAT_EQ(7., grid.getGrid()[some_index]); EXPECT_FLOAT_EQ(7., grid.interpolate(position)); } +TEST(ScalarGrid, ClosestValue) { + ScalarGrid grid(Vector3d(0.), 2, 1); + grid.get(0, 0, 0) = 1; + grid.get(0, 0, 1) = 2; + grid.get(0, 1, 0) = 3; + grid.get(0, 1, 1) = 4; + grid.get(1, 0, 0) = 5; + grid.get(1, 0, 1) = 6; + grid.get(1, 1, 0) = 7; + grid.get(1, 1, 1) = 8; + + // Closest value + EXPECT_FLOAT_EQ(1, grid.closestValue(Vector3d(-0.2, 0, 0.4))); + EXPECT_FLOAT_EQ(2, grid.closestValue(Vector3d(0.2, 0.1, 0.9))); + EXPECT_FLOAT_EQ(3, grid.closestValue(Vector3d(0.3, 1.2, 0.2))); + EXPECT_FLOAT_EQ(7, grid.closestValue(Vector3d(0.6, 0.7, 0.4))); +} + TEST(VectorGrid, Interpolation) { // Explicitly test trilinear interpolation double spacing = 2.793; From fce0c8aba16701781fc93b0af2c4c5a9bdbcaec6 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 30 Nov 2012 17:49:45 +0100 Subject: [PATCH 0237/1298] add createModulationField.py --- data-tools/SPH/createModulationField.py | 120 ------------------------ 1 file changed, 120 deletions(-) delete mode 100644 data-tools/SPH/createModulationField.py diff --git a/data-tools/SPH/createModulationField.py b/data-tools/SPH/createModulationField.py deleted file mode 100644 index 573b642c1..000000000 --- a/data-tools/SPH/createModulationField.py +++ /dev/null @@ -1,120 +0,0 @@ -from pylab import * -from scipy.interpolate import interp1d -from cStringIO import StringIO -import struct -from mpc import * - - -profile = StringIO(""" -# Profile of magnetic field strength vs baryonic density in the Minati box -# Lower extrapolation B = 206.404 + 12.9872 * rho + 0.193117 * rho**2 -# Higher extrapolation B = -37.3625 -2.74343 * rho -0.0585562 * rho**2 -# -# log10(rho/[g/cm^3]), log10(B/[G]) --32.00000 -11.43459 --31.97993 -11.42361 --31.91850 -11.37153 --31.85708 -11.33202 --31.79566 -11.28935 --31.73424 -11.25074 --31.67281 -11.20560 --31.61139 -11.16113 --31.54997 -11.11273 --31.48854 -11.06385 --31.42712 -11.01348 --31.36570 -10.96107 --31.30427 -10.90346 --31.24285 -10.83643 --31.18143 -10.76371 --31.12001 -10.67964 --31.05858 -10.58822 --30.99716 -10.48548 --30.93574 -10.37223 --30.87431 -10.24660 --30.81289 -10.11632 --30.75147 -9.96395 --30.69004 -9.80515 --30.62862 -9.63804 --30.56720 -9.46599 --30.50578 -9.28175 --30.44435 -9.09687 --30.38293 -8.91053 --30.32151 -8.73668 --30.26008 -8.56165 --30.19866 -8.39986 --30.13724 -8.24704 --30.07581 -8.10704 --30.01439 -7.98537 --29.95297 -7.86703 --29.89155 -7.76893 --29.83012 -7.67947 --29.76870 -7.59368 --29.70728 -7.51493 --29.64585 -7.45123 --29.58443 -7.39008 --29.52301 -7.33190 --29.46158 -7.28033 --29.40016 -7.22940 --29.33874 -7.18511 --29.27732 -7.14020 --29.21589 -7.09864 --29.15447 -7.05942 --29.09305 -7.01471 --29.03162 -6.96864 --28.97020 -6.93470 --28.90878 -6.90071 --28.84735 -6.86472 --28.78593 -6.81636 --28.72451 -6.80306 --28.66309 -6.75334 --28.60166 -6.74123 --28.54024 -6.70163 --28.47882 -6.65852 --28.41739 -6.64615 --28.35597 -6.62567 --28.29455 -6.57452 --28.23312 -6.56336 --28.17170 -6.51866 --28.11028 -6.48613 --28.04886 -6.47825 --28.00000 -6.45452 -""") - -tablgRho, tablgB = genfromtxt(profile, unpack=True, comments='#') -f = interp1d(tablgRho, tablgB) - -def modulation(x): - if (x <= -32): - return 206.404 + 12.9872 * x + 0.193117 * x * x - elif (x >= -28): - return -37.3625 - 2.74343 * x - 0.0585562 * x * x - else: - return f(x) - -#gadget mass -db mhd_z.db -ox 54000 -oy 54000 -oz 54000 -size 132000 -bins 257 -o density_54-186Mpc_257bins.raw -dump -#gadget mass -db mhd_z.db -ox 54000 -oy 54000 -oz 54000 -size 132000 -bins 513 -o density_54-186Mpc_513bins.raw -dump - -# takes a N+1 grid, the last entry is skipped to be conform with a periodic grid -fin = open('density_54-186Mpc_513bins.raw', 'rb') -fout = open('mod_MiniatiProfile_DolagDensity_54-186Mpc_512bins.raw', 'wb') -N = 513 - -sumb2 = 0 -for ix in range(N): - print ix - for iy in range(N): - for iz in range(N): - rho = struct.unpack('f',fin.read(4))[0] - rho *= 1.98892e40 * 0.7**2 / kpc**3 # density [kg/m^3] - x = log10(rho) - 3 # log10(density [g/cm^3]) - b = 10**modulation(x) # field strength [G] - b *= gauss # field strength [T] - sumb2 += b**2 - fout.write(struct.pack('f', b)) - fin.read(4) - fin.read(4 * (N + 1)) - -print 'Brms =', (sumb2 / N**3)**.5, "T" - -fin.close() -fout.close() From 454e395a8d44259a1a262dee6dbfb3cb2382db5b Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 30 Nov 2012 18:27:27 +0100 Subject: [PATCH 0238/1298] add testJF12Field.py --- test/python/testJF12Field.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 test/python/testJF12Field.py diff --git a/test/python/testJF12Field.py b/test/python/testJF12Field.py new file mode 100644 index 000000000..526262823 --- /dev/null +++ b/test/python/testJF12Field.py @@ -0,0 +1,32 @@ +from mpc import * +from pylab import * +from matplotlib.colors import LogNorm + + +bField = JF2012Field() +#bField.randomStriated() +#bField.randomTurbulent() + +N = 241 +x = (linspace(-20, 20, N, endpoint=True)) * kpc +y = (linspace(-20, 20, N, endpoint=True)) * kpc +z = 0 * kpc + +B = zeros((N,N)) +for ix in range(N): + for iy in range(N): + b = bField.getField(Vector3d(x[ix], y[iy], z)) + B[iy, ix] = b.getMag() / gauss # B in [G], rows = y, columns = x + +maB = ma.masked_array(B, B==0) +X, Y = meshgrid(x / kpc, y / kpc) + +figure() +pc = pcolor(X, Y, maB, norm=LogNorm(), vmin=1e-9, vmax=1e-4) +gca().set_aspect(1) +cbar = colorbar(pc, shrink=0.8) +cbar.set_label(r'$\vert \vec{B} \vert$ [G]') +xlabel('x [kpx]') +ylabel('y [kpx]') +show() +savefig('JF12.png', bbox_inches='tight') From 440bcca8bcfc0c78cca62de507efe924ba07948c Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 3 Dec 2012 11:16:02 +0100 Subject: [PATCH 0239/1298] removed "get" prefix from nucleusId methods as they are no getters --- include/mpc/Nucleus.h | 12 ++--- include/mpc/ParticleState.h | 3 +- src/Nucleus.cpp | 14 ++--- src/ParticleState.cpp | 3 +- src/Source.cpp | 4 +- src/XmlExecute.cpp | 4 +- src/module/ElectronPairProduction.cpp | 4 +- src/module/NuclearDecay.cpp | 6 +-- src/module/PhotoDisintegration.cpp | 20 +++---- src/module/PhotoPionProduction.cpp | 20 +++---- src/module/Redshift.cpp | 1 + test/python/testElectronPairProduction.py | 2 +- test/python/testEnergyLossLength.py | 2 +- test/python/testNuclearMass.py | 2 +- test/python/testPhotoDisintegration.py | 4 +- test/python/testPhotoPionProduction.py | 2 +- .../python/testPhotoPionProduction_pnRatio.py | 6 +-- test/python/testSourceComposition.py | 2 +- test/python/testTurbulentDeflection.py | 2 +- test/testCore.cpp | 22 ++++---- test/testInteraction.cpp | 52 +++++++++---------- test/testModuleList.cpp | 4 +- test/testPropagation.cpp | 4 +- test/testSource.cpp | 4 +- 24 files changed, 100 insertions(+), 99 deletions(-) diff --git a/include/mpc/Nucleus.h b/include/mpc/Nucleus.h index 84b4a3892..8d99fb5ae 100644 --- a/include/mpc/Nucleus.h +++ b/include/mpc/Nucleus.h @@ -1,8 +1,6 @@ #ifndef NUCLEUS_H_ #define NUCLEUS_H_ -#include - namespace mpc { /** This implements the 2012 Monte Carlo nuclear code scheme. @@ -12,9 +10,9 @@ namespace mpc { * L is the total number of strange quarks. * I is the isomer number, with I=0 corresponding to the ground state. */ -int getNucleusId(int a, int z); -int getChargeNumberFromNucleusId(int id); -int getMassNumberFromNucleusId(int id); +int nucleusId(int a, int z); +int chargeNumberFromNucleusId(int id); +int massNumberFromNucleusId(int id); /* CRPropa2.0 code scheme */ int convertFromCRPropaId(int id); @@ -23,9 +21,9 @@ int convertToCRPropaId(int id); /** Return the nucleus mass by lookup from a table. * The masses are the atomic masses from the NIST database (http://www.nist.gov/pml/data/comp.cfm) minus electron masses, neglecting electron binding energies. * Unmeasured atomic masses are taken to be A * amu minus electron masses. - * The data table is generated by mpc/data/NuclearMass/createNuclearMassTable. + * The data table is generated by mpc/data-tools/NuclearMass/createNuclearMassTable. */ -double getNucleusMass(int id); +double nucleusMass(int id); } // namespace mpc diff --git a/include/mpc/ParticleState.h b/include/mpc/ParticleState.h index b93051d53..de74cb51a 100644 --- a/include/mpc/ParticleState.h +++ b/include/mpc/ParticleState.h @@ -15,11 +15,12 @@ namespace mpc { class ParticleState { private: int id; - double pmass; double energy; Vector3d position; Vector3d direction; + double pmass; + public: ParticleState(); void setPosition(const Vector3d &pos); diff --git a/src/Nucleus.cpp b/src/Nucleus.cpp index 5a9d763d3..ac8b37482 100644 --- a/src/Nucleus.cpp +++ b/src/Nucleus.cpp @@ -11,7 +11,7 @@ namespace mpc { -int getNucleusId(int a, int z) { +int nucleusId(int a, int z) { if (z < 0) throw std::runtime_error( "mpc::Nucleus: no nucleus with Z < 0, A=" + kiss::str(a) + " Z=" @@ -27,23 +27,23 @@ int getNucleusId(int a, int z) { return 1000000000 + z * 10000 + a * 10; } -int getChargeNumberFromNucleusId(int id) { +int chargeNumberFromNucleusId(int id) { return HepPID::Z(id); } -int getMassNumberFromNucleusId(int id) { +int massNumberFromNucleusId(int id) { return HepPID::A(id); } int convertFromCRPropaId(int crp_id) { int Z = crp_id / 1000; int A = crp_id % 1000; - return getNucleusId(A, Z); + return nucleusId(A, Z); } int convertToCRPropaId(int id) { - int Z = getChargeNumberFromNucleusId(id); - int A = getMassNumberFromNucleusId(id); + int Z = chargeNumberFromNucleusId(id); + int A = massNumberFromNucleusId(id); return Z * 1000 + A; } @@ -73,7 +73,7 @@ struct NuclearMassTable { static NuclearMassTable nuclearMassTable; -double getNucleusMass(int id) { +double nucleusMass(int id) { int Z = HepPID::Z(id); int N = HepPID::A(id) - Z; double mass = nuclearMassTable.table[Z * 31 + N]; diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index 7d0217e63..d9e72e0cd 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -1,6 +1,7 @@ #include "mpc/ParticleState.h" #include +#include namespace mpc { @@ -36,7 +37,7 @@ double ParticleState::getEnergy() const { void ParticleState::setId(const int newId) { id = newId; if (HepPID::isNucleus(id)) - pmass = getNucleusMass(id); + pmass = nucleusMass(id); } int ParticleState::getId() const { diff --git a/src/Source.cpp b/src/Source.cpp index c14ae4d6f..d0b74b1e4 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -105,7 +105,7 @@ double SourceComposition::getSpectrumIntegral(int Z) const { void SourceComposition::add(int id, double a) { isotope.push_back(id); - int A = getMassNumberFromNucleusId(id); + int A = massNumberFromNucleusId(id); double weightedAbundance = a * pow(A, -index - 1); abundance.push_back(weightedAbundance); probability.push_back(0); @@ -113,7 +113,7 @@ void SourceComposition::add(int id, double a) { } void SourceComposition::add(int A, int Z, double a) { - add(getNucleusId(A, Z), a); + add(nucleusId(A, Z), a); } void SourceComposition::normalize() { diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 723fc5ebe..b04760d29 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -573,7 +573,7 @@ void XmlExecute::loadSpectrumComposition(pugi::xml_node &node) { double ab = n.attribute("Abundance").as_double(); cout << " - Species: Z = " << Z << ", A = " << A << ", abundance = " << ab << endl; - composition->add(getNucleusId(A, Z), ab); + composition->add(nucleusId(A, Z), ab); } source.addProperty(composition); } else if (spectrum_node.child("Ecut_EeV")) { @@ -603,7 +603,7 @@ void XmlExecute::loadSourceNuclei(pugi::xml_node &node) { double ab = n.attribute("Abundance").as_double(); cout << " - Species: Z = " << Z << ", A = " << A << ", abundance = " << ab << endl; - composition->add(getNucleusId(A, Z), ab); + composition->add(nucleusId(A, Z), ab); } source.addProperty(composition); } diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index c188c3a8a..a7f77bc34 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -87,8 +87,8 @@ void ElectronPairProduction::process(Candidate *candidate) const { } double ElectronPairProduction::energyLossLength(int id, double E) { - double A = getMassNumberFromNucleusId(id); - double Z = getChargeNumberFromNucleusId(id); + double A = massNumberFromNucleusId(id); + double Z = chargeNumberFromNucleusId(id); if (Z < 1) return std::numeric_limits::max(); diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index 0cc2a72c0..432a01350 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -128,7 +128,7 @@ void NuclearDecay::betaDecay(Candidate *candidate, bool isBetaPlus) const { } // update candidate - candidate->current.setId(getNucleusId(A, Z + dZ)); + candidate->current.setId(nucleusId(A, Z + dZ)); candidate->current.setLorentzFactor(gamma); // random kinetic energy of electron in neutron decay @@ -156,9 +156,9 @@ void NuclearDecay::nucleonEmission(Candidate *candidate, int dA, int dZ) const { int A = candidate->current.getMassNumber(); double EpA = candidate->current.getEnergy() / double(candidate->current.getMassNumber()); - candidate->current.setId(getNucleusId(A - dA, Z - dZ)); + candidate->current.setId(nucleusId(A - dA, Z - dZ)); candidate->current.setEnergy(EpA * (A - dA)); - candidate->addSecondary(getNucleusId(dA, dZ), EpA * dA); + candidate->addSecondary(nucleusId(dA, dZ), EpA * dA); } } // namespace mpc diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 1a84c2b27..06384ee21 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -130,7 +130,7 @@ void PhotoDisintegration::performInteraction(Candidate *candidate) const { // update particle int nA = A + dA; if (nA > 0) { - candidate->current.setId(getNucleusId(A + dA, Z + dZ)); + candidate->current.setId(nucleusId(A + dA, Z + dZ)); candidate->current.setEnergy(EpA * (A + dA)); } else { candidate->setActive(false); @@ -138,22 +138,22 @@ void PhotoDisintegration::performInteraction(Candidate *candidate) const { // create secondaries for (size_t i = 0; i < nNeutron; i++) - candidate->addSecondary(getNucleusId(1, 0), EpA); + candidate->addSecondary(nucleusId(1, 0), EpA); for (size_t i = 0; i < nProton; i++) - candidate->addSecondary(getNucleusId(1, 1), EpA); + candidate->addSecondary(nucleusId(1, 1), EpA); for (size_t i = 0; i < nH2; i++) - candidate->addSecondary(getNucleusId(2, 1), EpA * 2); + candidate->addSecondary(nucleusId(2, 1), EpA * 2); for (size_t i = 0; i < nH3; i++) - candidate->addSecondary(getNucleusId(3, 1), EpA * 3); + candidate->addSecondary(nucleusId(3, 1), EpA * 3); for (size_t i = 0; i < nHe3; i++) - candidate->addSecondary(getNucleusId(3, 2), EpA * 3); + candidate->addSecondary(nucleusId(3, 2), EpA * 3); for (size_t i = 0; i < nHe4; i++) - candidate->addSecondary(getNucleusId(4, 2), EpA * 4); + candidate->addSecondary(nucleusId(4, 2), EpA * 4); } double PhotoDisintegration::energyLossLength(int id, double E) { - int A = getMassNumberFromNucleusId(id); - int Z = getChargeNumberFromNucleusId(id); + int A = massNumberFromNucleusId(id); + int Z = chargeNumberFromNucleusId(id); int N = A - Z; std::vector pdModes = pdTable[Z * 31 + N]; @@ -161,7 +161,7 @@ double PhotoDisintegration::energyLossLength(int id, double E) { return std::numeric_limits::max(); // log10 of lorentz factor - double lg = log10(E / (getNucleusMass(id) * c_squared)); + double lg = log10(E / (nucleusMass(id) * c_squared)); if ((lg <= 6) or (lg >= 14)) return std::numeric_limits::max(); diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 7dc408e62..4523880a5 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -138,18 +138,18 @@ void PhotoPionProduction::performInteraction(Candidate *candidate) const { if (A == 1) { // interaction on single nucleon candidate->current.setEnergy(E * 938. / 1232.); - candidate->current.setId(getNucleusId(1, Zfinal)); + candidate->current.setId(nucleusId(1, Zfinal)); } else { // interaction on nucleus, update nucleus and emit nucleon candidate->current.setEnergy(E * (A - 1) / A); - candidate->current.setId(getNucleusId(A - 1, Z - dZ)); - candidate->addSecondary(getNucleusId(1, Zfinal), E / A * 938. / 1232.); + candidate->current.setId(nucleusId(A - 1, Z - dZ)); + candidate->addSecondary(nucleusId(1, Zfinal), E / A * 938. / 1232.); } } double PhotoPionProduction::energyLossLength(int id, double E) { - int A = getMassNumberFromNucleusId(id); - int Z = getChargeNumberFromNucleusId(id); + int A = massNumberFromNucleusId(id); + int Z = chargeNumberFromNucleusId(id); int N = A - Z; double EpA = E / A; @@ -248,20 +248,20 @@ void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { case 14: // neutron if (A == 1) { // in-going particle was a nucleon: update its properties candidate->current.setEnergy(Eout); - candidate->current.setId(getNucleusId(1, 14 - pType)); + candidate->current.setId(nucleusId(1, 14 - pType)); } else { // in-going particle was a nucleus: update nucleus and emit nucleon candidate->current.setEnergy(E - Eout); - candidate->current.setId(getNucleusId(A - 1, Z - channel)); - candidate->addSecondary(getNucleusId(1, 14 - pType), Eout); + candidate->current.setId(nucleusId(A - 1, Z - channel)); + candidate->addSecondary(nucleusId(1, 14 - pType), Eout); } break; case -13: // anti-proton if (haveAntiNucleons) - candidate->addSecondary(-getNucleusId(1, 1), Eout); + candidate->addSecondary(-nucleusId(1, 1), Eout); break; case -14: // anti-neutron if (haveAntiNucleons) - candidate->addSecondary(-getNucleusId(1, 0), Eout); + candidate->addSecondary(-nucleusId(1, 0), Eout); break; case 1: // photon if (havePhotons) diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index 3c78922c4..264feb8ba 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -3,6 +3,7 @@ #include "mpc/Common.h" #include +#include namespace mpc { diff --git a/test/python/testElectronPairProduction.py b/test/python/testElectronPairProduction.py index 8a98fcf30..44c81a53a 100644 --- a/test/python/testElectronPairProduction.py +++ b/test/python/testElectronPairProduction.py @@ -10,7 +10,7 @@ def compare(dataFileName, photonField, plotFileName): epp = ElectronPairProduction(photonField) c = Candidate() - c.current.setId(getNucleusId(1,1)) + c.current.setId(nucleusId(1,1)) c.setCurrentStep(1 * Mpc) N = 50 diff --git a/test/python/testEnergyLossLength.py b/test/python/testEnergyLossLength.py index 5ae412fa9..594230fa8 100644 --- a/test/python/testEnergyLossLength.py +++ b/test/python/testEnergyLossLength.py @@ -25,7 +25,7 @@ def parse_pid(pid): -pid = getNucleusId(56, 26) +pid = nucleusId(56, 26) E = logspace(1, 4) * EeV L = zeros((3, 50)) diff --git a/test/python/testNuclearMass.py b/test/python/testNuclearMass.py index c8117d0f9..f2a8cd3e4 100644 --- a/test/python/testNuclearMass.py +++ b/test/python/testNuclearMass.py @@ -7,7 +7,7 @@ for z in range(0, 27): for n in range(0, 31): try: - D[z, n] = getNucleusMass(getNucleusId(n + z, z)) / amu + D[z, n] = nucleusMass(nucleusId(n + z, z)) / amu D2[z, n] = D[z, n] - (z + n) - z * mass_electron / amu except: continue diff --git a/test/python/testPhotoDisintegration.py b/test/python/testPhotoDisintegration.py index 3019e7745..57f045501 100644 --- a/test/python/testPhotoDisintegration.py +++ b/test/python/testPhotoDisintegration.py @@ -24,7 +24,7 @@ def get_data_rates(pid): D = {} for i in range(len(table)): z, n = int(table[i][0]), int(table[i][1]) - if getNucleusId(z+n, z) != pid: + if nucleusId(z+n, z) != pid: continue channel = table[i][2] rates = table[i][3:] @@ -43,7 +43,7 @@ def parse_channel(channel): ### nucleus to test -pid = getNucleusId(4,2) +pid = nucleusId(4,2) candidate = Candidate() candidate.current.setId(pid) diff --git a/test/python/testPhotoPionProduction.py b/test/python/testPhotoPionProduction.py index 0502b4402..9542cbc73 100644 --- a/test/python/testPhotoPionProduction.py +++ b/test/python/testPhotoPionProduction.py @@ -3,7 +3,7 @@ def getRate(module, energy, charge): c = Candidate() - c.current.setId(getNucleusId(1, charge)) + c.current.setId(nucleusId(1, charge)) c.current.setEnergy(energy) N = 5000 diff --git a/test/python/testPhotoPionProduction_pnRatio.py b/test/python/testPhotoPionProduction_pnRatio.py index 85ddb3add..5da1c4204 100644 --- a/test/python/testPhotoPionProduction_pnRatio.py +++ b/test/python/testPhotoPionProduction_pnRatio.py @@ -11,13 +11,13 @@ def getPNRatio(E): nP, nN = 0, 0 for i in range(2000): - c.current.setId(getNucleusId(1, 1)) + c.current.setId(nucleusId(1, 1)) c.current.setEnergy(E * EeV) spp.setNextInteraction(c, s) spp.performInteraction(c) - if c.current.getId() == getNucleusId(1,1): + if c.current.getId() == nucleusId(1,1): nP += 1. - if c.current.getId() == getNucleusId(1,0): + if c.current.getId() == nucleusId(1,0): nN += 1. return nP / nN diff --git a/test/python/testSourceComposition.py b/test/python/testSourceComposition.py index bb52a87c6..d8b6891e3 100644 --- a/test/python/testSourceComposition.py +++ b/test/python/testSourceComposition.py @@ -29,7 +29,7 @@ for j in range(nP): composition.prepare(state) - z = state.getChargeNumber() + z = state.chargeNumber() d[z][i] += 1 norm = float(d[1][i]) diff --git a/test/python/testTurbulentDeflection.py b/test/python/testTurbulentDeflection.py index 9f0e7e626..2c2d166c4 100644 --- a/test/python/testTurbulentDeflection.py +++ b/test/python/testTurbulentDeflection.py @@ -24,7 +24,7 @@ print j ps = ParticleState() - ps.setId(getNucleusId(1, 1)) + ps.setId(nucleusId(1, 1)) ps.setEnergy(E * EeV) ps.setDirection(Random.instance().randUnitVectorOnSphere()) ps.setPosition(Vector3d(0, 0, 0)) diff --git a/test/testCore.cpp b/test/testCore.cpp index e6d3ad91d..52e86ca01 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -51,38 +51,38 @@ TEST(ParticleState, momentum) { TEST(ParticleState, id) { ParticleState particle; - particle.setId(getNucleusId(12, 6)); + particle.setId(nucleusId(12, 6)); EXPECT_EQ(particle.getId(), 1000060120); } TEST(ParticleState, idException) { - EXPECT_THROW(getNucleusId(5, 6), std::runtime_error); + EXPECT_THROW(nucleusId(5, 6), std::runtime_error); } TEST(ParticleState, charge) { ParticleState particle; - particle.setId(getNucleusId(56, 26)); + particle.setId(nucleusId(56, 26)); EXPECT_EQ(particle.getChargeNumber(), 26); EXPECT_DOUBLE_EQ(particle.getCharge(), 26 * eplus); } TEST(ParticleState, massProton) { ParticleState particle; - particle.setId(getNucleusId(1, 1)); + particle.setId(nucleusId(1, 1)); EXPECT_EQ(particle.getMassNumber(), 1); EXPECT_DOUBLE_EQ(particle.getMass(), mass_proton); } TEST(ParticleState, massNeutron) { ParticleState particle; - particle.setId(getNucleusId(1, 0)); + particle.setId(nucleusId(1, 0)); EXPECT_EQ(particle.getMassNumber(), 1); EXPECT_DOUBLE_EQ(particle.getMass(), mass_neutron); } TEST(ParticleState, lorentzFactor) { ParticleState particle; - particle.setId(getNucleusId(1, 1)); + particle.setId(nucleusId(1, 1)); particle.setEnergy(1e12 * eV); EXPECT_DOUBLE_EQ(particle.getLorentzFactor(), 1e12 * eV / mass_proton / c_squared); @@ -124,15 +124,15 @@ TEST(Candidate, addSecondary) { Candidate c; c.setRedshift(5); c.setTrajectoryLength(23); - c.initial.setId(getNucleusId(56,26)); + c.initial.setId(nucleusId(56,26)); c.initial.setEnergy(1000); c.initial.setPosition(Vector3d(1,2,3)); c.initial.setDirection(Vector3d(0,0,1)); - c.addSecondary(getNucleusId(1,1), 200); + c.addSecondary(nucleusId(1,1), 200); Candidate s = *c.secondaries[0]; - EXPECT_EQ(getNucleusId(1,1), s.current.getId()); + EXPECT_EQ(nucleusId(1,1), s.current.getId()); EXPECT_EQ(200, s.current.getEnergy()); EXPECT_EQ(5, s.getRedshift()); @@ -186,8 +186,8 @@ TEST(common, interpolateEquidistant) { TEST(NucleusId, crpropaScheme) { // test conversion to and from the CRPropa2 naming scheme - EXPECT_EQ(getNucleusId(56, 26), convertFromCRPropaId(26056)); - EXPECT_EQ(26056, convertToCRPropaId(getNucleusId(56, 26))); + EXPECT_EQ(nucleusId(56, 26), convertFromCRPropaId(26056)); + EXPECT_EQ(26056, convertToCRPropaId(nucleusId(56, 26))); } TEST(Random, seed) { diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 2b3a51397..d2530589f 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -14,7 +14,7 @@ TEST(ElectronPairProduction, EnergyDecreasing) { // Test if energy loss occurs for protons with energies from 1e15 - 1e23 eV Candidate c; c.setCurrentStep(1 * Mpc); - c.current.setId(getNucleusId(1, 1)); // proton + c.current.setId(nucleusId(1, 1)); // proton ElectronPairProduction epp1(CMB); for (int i = 0; i < 80; i++) { @@ -45,7 +45,7 @@ TEST(ElectronPairProduction, BelowEnergyTreshold) { // Test if nothing happens below 1e15 eV ElectronPairProduction epp(CMB); Candidate c; - c.current.setId(getNucleusId(1, 1)); // proton + c.current.setId(nucleusId(1, 1)); // proton double E = 1e14 * eV; c.current.setEnergy(E); epp.process(&c); @@ -72,7 +72,7 @@ TEST(ElectronPairProduction, valuesCMB) { Candidate c; c.setCurrentStep(1 * Mpc); - c.current.setId(getNucleusId(1, 1)); // proton + c.current.setId(nucleusId(1, 1)); // proton ElectronPairProduction epp(CMB); for (int i = 0; i < x.size(); i++) { @@ -104,7 +104,7 @@ TEST(ElectronPairProduction, valuesIRB) { Candidate c; c.setCurrentStep(1 * Mpc); - c.current.setId(getNucleusId(1, 1)); // proton + c.current.setId(nucleusId(1, 1)); // proton ElectronPairProduction epp(IRB); for (int i = 0; i < x.size(); i++) { @@ -136,7 +136,7 @@ TEST(ElectronPairProduction, valuesCMB_IRB) { Candidate c; c.setCurrentStep(1 * Mpc); - c.current.setId(getNucleusId(1, 1)); // proton + c.current.setId(nucleusId(1, 1)); // proton ElectronPairProduction epp(CMB_IRB); for (int i = 0; i < x.size(); i++) { @@ -153,7 +153,7 @@ TEST(NuclearDecay, Neutron) { // The mean decay time is expected to be within 1% of the literature value. // This test can stochastically fail. Candidate candidate; - candidate.current.setId(getNucleusId(1, 0)); + candidate.current.setId(nucleusId(1, 0)); candidate.current.setEnergy(mass_neutron * c_squared); NuclearDecay decay; InteractionState state; @@ -172,12 +172,12 @@ TEST(NuclearDecay, Scandium44) { NuclearDecay d(true, true); Candidate c; c.setCurrentStep(1 * Mpc); - c.current.setId(getNucleusId(44, 21)); + c.current.setId(nucleusId(44, 21)); c.current.setEnergy(1 * EeV); double gamma = c.current.getLorentzFactor(); d.process(&c); // primary - EXPECT_EQ(getNucleusId(44,20), c.current.getId()); + EXPECT_EQ(nucleusId(44,20), c.current.getId()); EXPECT_DOUBLE_EQ(gamma, c.current.getLorentzFactor()); // secondaries EXPECT_EQ(2, c.secondaries.size()); @@ -195,15 +195,15 @@ TEST(NuclearDecay, Li4) { NuclearDecay d; Candidate c; c.setCurrentStep(1 * kpc); - c.current.setId(getNucleusId(4, 3)); + c.current.setId(nucleusId(4, 3)); c.current.setEnergy(4 * EeV); d.process(&c); // primary - EXPECT_EQ(getNucleusId(3,2), c.current.getId()); + EXPECT_EQ(nucleusId(3,2), c.current.getId()); EXPECT_EQ(1, c.secondaries.size()); // secondary Candidate c1 = *c.secondaries[0]; - EXPECT_EQ(getNucleusId(1,1), c1.current.getId()); + EXPECT_EQ(nucleusId(1,1), c1.current.getId()); EXPECT_EQ(1, c1.current.getEnergy() / EeV); } @@ -213,15 +213,15 @@ TEST(NuclearDecay, He5) { NuclearDecay d; Candidate c; c.setCurrentStep(1 * Mpc); - c.current.setId(getNucleusId(5, 2)); + c.current.setId(nucleusId(5, 2)); c.current.setEnergy(5 * EeV); d.process(&c); // primary - EXPECT_EQ(getNucleusId(4,2), c.current.getId()); + EXPECT_EQ(nucleusId(4,2), c.current.getId()); EXPECT_EQ(4, c.current.getEnergy() / EeV); // secondary Candidate c2 = *c.secondaries[0]; - EXPECT_EQ(getNucleusId(1,0), c2.current.getId()); + EXPECT_EQ(nucleusId(1,0), c2.current.getId()); EXPECT_EQ(1, c2.current.getEnergy() / EeV); } @@ -230,7 +230,7 @@ TEST(NuclearDecay, LimitNextStep) { NuclearDecay d; Candidate c; c.setNextStep(std::numeric_limits::max()); - c.current.setId(getNucleusId(1, 0)); + c.current.setId(nucleusId(1, 0)); c.current.setEnergy(10 * EeV); d.process(&c); EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); @@ -248,7 +248,7 @@ TEST(NuclearDecay, AllWorking) { int Z, N, channel, foo; infile >> Z >> N >> interaction.channel >> foo; - c.current.setId(getNucleusId(Z + N, Z)); + c.current.setId(nucleusId(Z + N, Z)); c.current.setEnergy(80 * EeV); c.setInteractionState(d.getDescription(), interaction); d.performInteraction(&c); @@ -263,7 +263,7 @@ TEST(PhotoDisintegration, Carbon) { // This test can stochastically fail if no interaction occurs over 50 Mpc. PhotoDisintegration pd; Candidate c; - c.current.setId(getNucleusId(12, 6)); + c.current.setId(nucleusId(12, 6)); c.current.setEnergy(100 * EeV); c.setCurrentStep(50 * Mpc); pd.process(&c); @@ -295,7 +295,7 @@ TEST(PhotoDisintegration, Iron) { // This test can stochastically fail if no interaction occurs over 50 Mpc. PhotoDisintegration pd(IRB); Candidate c; - c.current.setId(getNucleusId(56, 26)); + c.current.setId(nucleusId(56, 26)); c.current.setEnergy(100 * EeV); c.setCurrentStep(50 * Mpc); pd.process(&c); @@ -327,7 +327,7 @@ TEST(PhotoDisintegration, LimitNextStep) { PhotoDisintegration pd; Candidate c; c.setNextStep(std::numeric_limits::max()); - c.current.setId(getNucleusId(4, 2)); + c.current.setId(nucleusId(4, 2)); c.current.setEnergy(200 * EeV); pd.process(&c); EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); @@ -358,7 +358,7 @@ TEST(PhotoDisintegration, AllWorkingCMB) { // test if all 200 entries are present } - c.current.setId(getNucleusId(Z + N, Z)); + c.current.setId(nucleusId(Z + N, Z)); c.current.setEnergy(80 * EeV); c.setInteractionState(pd.getDescription(), interaction); pd.performInteraction(&c); @@ -391,7 +391,7 @@ TEST(PhotoDisintegration, AllWorkingIRB) { // test if all 200 entries are present } - c.current.setId(getNucleusId(Z + N, Z)); + c.current.setId(nucleusId(Z + N, Z)); c.current.setEnergy(80 * EeV); c.setInteractionState(pd.getDescription(), interaction); pd.performInteraction(&c); @@ -411,7 +411,7 @@ TEST(PhotoPionProduction, Proton) { PhotoPionProduction ppp; Candidate c; c.setCurrentStep(100 * Mpc); - c.current.setId(getNucleusId(1, 1)); + c.current.setId(nucleusId(1, 1)); c.current.setEnergy(100 * EeV); ppp.process(&c); EXPECT_TRUE(c.current.getEnergy() / EeV < 100); @@ -428,7 +428,7 @@ TEST(PhotoPionProduction, Helium) { PhotoPionProduction ppp; Candidate c; c.setCurrentStep(100 * Mpc); - c.current.setId(getNucleusId(4, 2)); + c.current.setId(nucleusId(4, 2)); c.current.setEnergy(400 * EeV); ppp.process(&c); EXPECT_LT(c.current.getEnergy(), 400 * EeV); @@ -441,7 +441,7 @@ TEST(PhotoPionProduction, LimitNextStep) { PhotoPionProduction ppp; Candidate c; c.setNextStep(std::numeric_limits::max()); - c.current.setId(getNucleusId(1, 1)); + c.current.setId(nucleusId(1, 1)); c.current.setEnergy(200 * EeV); ppp.process(&c); EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); @@ -453,7 +453,7 @@ TEST(SophiaPhotoPionProduction, withoutSecondaries) { SophiaPhotoPionProduction ppp; Candidate c; c.setCurrentStep(100 * Mpc); - c.current.setId(getNucleusId(1, 1)); + c.current.setId(nucleusId(1, 1)); c.current.setEnergy(100 * EeV); ppp.process(&c); EXPECT_GT(100 * EeV, c.current.getEnergy()); @@ -469,7 +469,7 @@ TEST(SophiaPhotoPionProduction, withSecondaries) { // This test can stochastically fail if no interaction occurs over 100 Mpc. SophiaPhotoPionProduction ppp(CMB, true, true, true); Candidate c; - c.current.setId(getNucleusId(1, 1)); + c.current.setId(nucleusId(1, 1)); c.current.setEnergy(100 * EeV); InteractionState interaction; ppp.setNextInteraction(&c, interaction); diff --git a/test/testModuleList.cpp b/test/testModuleList.cpp index a301b4681..1ab24b48d 100644 --- a/test/testModuleList.cpp +++ b/test/testModuleList.cpp @@ -34,7 +34,7 @@ TEST(ModuleList, runSource) { source.addProperty(new SourcePosition(Vector3d(10, 0, 0) * Mpc)); source.addProperty(new SourceIsotropicEmission()); source.addProperty(new SourcePowerLawSpectrum(5 * EeV, 100 * EeV, -2)); - source.addProperty(new SourceParticleType(getNucleusId(1, 1))); + source.addProperty(new SourceParticleType(nucleusId(1, 1))); modules.setShowProgress(true); modules.run(&source, 100, false); } @@ -49,7 +49,7 @@ TEST(ModuleList, runOpenMP) { source.addProperty(new SourcePosition(Vector3d(10, 0, 0) * Mpc)); source.addProperty(new SourceIsotropicEmission()); source.addProperty(new SourcePowerLawSpectrum(5 * EeV, 100 * EeV, -2)); - source.addProperty(new SourceParticleType(getNucleusId(1, 1))); + source.addProperty(new SourceParticleType(nucleusId(1, 1))); omp_set_num_threads(2); modules.run(&source, 1000, false); } diff --git a/test/testPropagation.cpp b/test/testPropagation.cpp index 7c86f0b11..80494af2d 100644 --- a/test/testPropagation.cpp +++ b/test/testPropagation.cpp @@ -34,7 +34,7 @@ TEST(testDeflectionCK, proton) { DeflectionCK propa(new UniformMagneticField(Vector3d(0, 0, 1 * nG))); ParticleState p; - p.setId(getNucleusId(1, 1)); + p.setId(nucleusId(1, 1)); p.setEnergy(100 * EeV); p.setPosition(Vector3d(0, 0, 0)); p.setDirection(Vector3d(0, 1, 0)); @@ -51,7 +51,7 @@ TEST(testDeflectionCK, neutron) { DeflectionCK propa(new UniformMagneticField(Vector3d(0, 0, 1 * nG))); ParticleState p; - p.setId(getNucleusId(1, 0)); + p.setId(nucleusId(1, 0)); p.setEnergy(100 * EeV); p.setPosition(Vector3d(0, 0, 0)); p.setDirection(Vector3d(0, 1, 0)); diff --git a/test/testSource.cpp b/test/testSource.cpp index 278c13cca..b56e89026 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -158,7 +158,7 @@ TEST(SourceComposition, simpleTest) { double Emax = 100; double index = -2; SourceComposition source(Emin, Emax, index); - source.add(getNucleusId(6, 3), 1); + source.add(nucleusId(6, 3), 1); ParticleState ps; source.prepare(ps); EXPECT_EQ(6, ps.getMassNumber()); @@ -178,7 +178,7 @@ TEST(Source, allPropertiesUsed) { source.addProperty(new SourcePosition(Vector3d(10, 0, 0) * Mpc)); source.addProperty(new SourceIsotropicEmission()); source.addProperty(new SourcePowerLawSpectrum(5 * EeV, 100 * EeV, -2)); - source.addProperty(new SourceParticleType(getNucleusId(8, 4))); + source.addProperty(new SourceParticleType(nucleusId(8, 4))); Candidate c = *source.getCandidate(); From 4ae205a8dc6577f037186ba2572db14698548d98 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 3 Dec 2012 12:06:28 +0100 Subject: [PATCH 0240/1298] have all interaction modules for nuclei check if they are given a nuclei added corresponding test cases --- src/module/ElectronPairProduction.cpp | 11 +++--- src/module/NuclearDecay.cpp | 3 ++ src/module/PhotoDisintegration.cpp | 3 ++ src/module/PhotoPionProduction.cpp | 3 ++ src/module/StochasticInteraction.cpp | 8 ++--- test/testInteraction.cpp | 50 +++++++++++++++++++++++++++ 6 files changed, 69 insertions(+), 9 deletions(-) diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index a7f77bc34..7944c6bad 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -60,17 +60,20 @@ void ElectronPairProduction::init(std::string filename) { } void ElectronPairProduction::process(Candidate *candidate) const { - double Z = candidate->current.getChargeNumber(); - if (Z < 1) - return; + if (not(candidate->current.isNucleus())) + return; // this module only handles nucleons / nuclei + double Z = candidate->current.getChargeNumber(); double A = candidate->current.getMassNumber(); double E = candidate->current.getEnergy(); double z = candidate->getRedshift(); double EpA = E / A * (1 + z); + if (Z < 1) + return; // no electron pair production on uncharged particles + if (EpA < energy.front()) - return; + return; // below energy threshold double rate; if (EpA < energy.back()) diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index 432a01350..645a5f265 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -57,6 +57,9 @@ void NuclearDecay::setHaveNeutrinos(bool b) { bool NuclearDecay::setNextInteraction(Candidate *candidate, InteractionState &interaction) const { + if (not(candidate->current.isNucleus())) + return false; // accept only nuclei + int A = candidate->current.getMassNumber(); int Z = candidate->current.getChargeNumber(); int N = A - Z; diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 06384ee21..74e4b44bf 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -69,6 +69,9 @@ void PhotoDisintegration::init(std::string filename) { bool PhotoDisintegration::setNextInteraction(Candidate *candidate, InteractionState &interaction) const { + if (not(candidate->current.isNucleus())) + return false; // accept only nuclei + int A = candidate->current.getMassNumber(); int Z = candidate->current.getChargeNumber(); int N = A - Z; diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 4523880a5..2f7caaf12 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -59,6 +59,9 @@ void PhotoPionProduction::init(std::string filename) { bool PhotoPionProduction::setNextInteraction(Candidate *candidate, InteractionState &interaction) const { + if (not(candidate->current.isNucleus())) + return false; // accept only nuclei + double z = candidate->getRedshift(); double E = candidate->current.getEnergy(); int A = candidate->current.getMassNumber(); diff --git a/src/module/StochasticInteraction.cpp b/src/module/StochasticInteraction.cpp index a2cd73383..e63a8dc3a 100644 --- a/src/module/StochasticInteraction.cpp +++ b/src/module/StochasticInteraction.cpp @@ -3,20 +3,18 @@ namespace mpc { void StochasticInteraction::process(Candidate* candidate) const { - double z = candidate->getRedshift(); double step = candidate->getCurrentStep(); - while (step >= 0) { // get the interaction state, if there is one InteractionState interaction; - bool noState = !candidate->getInteractionState(getDescription(), interaction); + bool noState = !candidate->getInteractionState(getDescription(), + interaction); // if no interaction state, set a new one if (noState) { bool noNewState = !setNextInteraction(candidate, interaction); - // no new interaction; return if (noNewState) - return; + return; // no new interaction; return } // if interaction distance not reached, reduce it and return diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index d2530589f..1e1131973 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -52,6 +52,17 @@ TEST(ElectronPairProduction, BelowEnergyTreshold) { EXPECT_DOUBLE_EQ(c.current.getEnergy(), E); } +TEST(ElectronPairProduction, NoNucleus) { + // Test if non-nuclei are skipped + ElectronPairProduction epp(CMB); + Candidate c; + c.current.setId(11); // electron + double E = 1e20 * eV; + c.current.setEnergy(E); + epp.process(&c); + EXPECT_DOUBLE_EQ(c.current.getEnergy(), E); +} + TEST(ElectronPairProduction, valuesCMB) { // Test if energy loss corresponds to the data table. std::vector x; @@ -258,6 +269,19 @@ TEST(NuclearDecay, AllWorking) { infile.close(); } +TEST(NuclearDecay, NoNucleus) { + // Test if non-nuclei are skipped + Candidate c; + c.setNextStep(std::numeric_limits::max()); + c.current.setId(11); // electron + c.current.setEnergy(10 * EeV); + + NuclearDecay d; + InteractionState state; + EXPECT_FALSE(d.setNextInteraction(&c, state)); + EXPECT_EQ(0, state.channel); +} + TEST(PhotoDisintegration, Carbon) { // Test if a 100 EeV C-12 nucleus photo-disintegrates (at least once) over a distance of 50 Mpc. // This test can stochastically fail if no interaction occurs over 50 Mpc. @@ -322,6 +346,19 @@ TEST(PhotoDisintegration, Iron) { // energy conserved } +TEST(PhotoDisintegration, NoNucleus) { + // Test if non-nuclei are skipped + Candidate c; + c.setNextStep(std::numeric_limits::max()); + c.current.setId(11); // electron + c.current.setEnergy(10 * EeV); + + PhotoDisintegration module; + InteractionState state; + EXPECT_FALSE(module.setNextInteraction(&c, state)); + EXPECT_EQ(0, state.channel); +} + TEST(PhotoDisintegration, LimitNextStep) { // Test if the interaction limits the next propagation step. PhotoDisintegration pd; @@ -436,6 +473,19 @@ TEST(PhotoPionProduction, Helium) { EXPECT_TRUE(c.secondaries.size() > 0); } +TEST(PhotoPionProduction, NoNucleus) { + // Test if non-nuclei are skipped + Candidate c; + c.setNextStep(std::numeric_limits::max()); + c.current.setId(11); // electron + c.current.setEnergy(10 * EeV); + + PhotoPionProduction module; + InteractionState state; + EXPECT_FALSE(module.setNextInteraction(&c, state)); + EXPECT_EQ(0, state.channel); +} + TEST(PhotoPionProduction, LimitNextStep) { // Test if the interaction limits the next propagation step. PhotoPionProduction ppp; From d97f3ec211f074eecaa4ed0b93fb730d74cd37ee Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 3 Dec 2012 12:13:49 +0100 Subject: [PATCH 0241/1298] correct charges for antiparticles --- include/mpc/ParticleState.h | 12 ++++++------ src/ParticleState.cpp | 15 ++++++++------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/include/mpc/ParticleState.h b/include/mpc/ParticleState.h index de74cb51a..c2eed26b4 100644 --- a/include/mpc/ParticleState.h +++ b/include/mpc/ParticleState.h @@ -20,6 +20,7 @@ class ParticleState { Vector3d direction; double pmass; + double charge; public: ParticleState(); @@ -35,20 +36,19 @@ class ParticleState { void setId(const int); int getId() const; - int getChargeNumber() const; + // convenience functions double getCharge() const; - - int getMassNumber() const; double getMass() const; - // convenience functions - bool isNucleus() const; - void setLorentzFactor(const double gamma); double getLorentzFactor() const; Vector3d getVelocity() const; Vector3d getMomentum() const; + + bool isNucleus() const; + int getChargeNumber() const; + int getMassNumber() const; }; } // namespace mpc diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index d9e72e0cd..a94a1394b 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -38,26 +38,27 @@ void ParticleState::setId(const int newId) { id = newId; if (HepPID::isNucleus(id)) pmass = nucleusMass(id); + charge = HepPID::charge(id) * eplus; } int ParticleState::getId() const { return id; } -int ParticleState::getChargeNumber() const { - return HepPID::Z(id); +double ParticleState::getMass() const { + return pmass; } double ParticleState::getCharge() const { - return HepPID::Z(id) * eplus; + return charge; } -int ParticleState::getMassNumber() const { - return HepPID::A(id); +int ParticleState::getChargeNumber() const { + return HepPID::Z(id); } -double ParticleState::getMass() const { - return pmass; +int ParticleState::getMassNumber() const { + return HepPID::A(id); } bool ParticleState::isNucleus() const { From 436d90037a3f12fc4472c868972648b3df6efb0a Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 3 Dec 2012 13:01:28 +0100 Subject: [PATCH 0242/1298] fix charges for antiparticles --- src/ParticleState.cpp | 8 +++++-- test/testCore.cpp | 52 +++++++++++++++++++++++++++++++------------ 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index a94a1394b..fc307ab33 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -36,9 +36,13 @@ double ParticleState::getEnergy() const { void ParticleState::setId(const int newId) { id = newId; - if (HepPID::isNucleus(id)) + if (HepPID::isNucleus(id)) { pmass = nucleusMass(id); - charge = HepPID::charge(id) * eplus; + charge = HepPID::Z(id) * eplus; + if (id < 0) + charge *= -1; // HepPID::Z returns positive charge numbers for anti-nuclei + } else + charge = HepPID::charge(id) * eplus; } int ParticleState::getId() const { diff --git a/test/testCore.cpp b/test/testCore.cpp index 52e86ca01..c423b4f6a 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -59,25 +59,49 @@ TEST(ParticleState, idException) { EXPECT_THROW(nucleusId(5, 6), std::runtime_error); } -TEST(ParticleState, charge) { +TEST(ParticleState, Charge) { ParticleState particle; - particle.setId(nucleusId(56, 26)); - EXPECT_EQ(particle.getChargeNumber(), 26); - EXPECT_DOUBLE_EQ(particle.getCharge(), 26 * eplus); -} -TEST(ParticleState, massProton) { - ParticleState particle; - particle.setId(nucleusId(1, 1)); - EXPECT_EQ(particle.getMassNumber(), 1); - EXPECT_DOUBLE_EQ(particle.getMass(), mass_proton); + particle.setId(nucleusId(56, 26)); // iron + EXPECT_EQ(26, particle.getChargeNumber()); + EXPECT_DOUBLE_EQ(26 * eplus, particle.getCharge()); + + particle.setId(-nucleusId(56, 26)); // anti-iron + EXPECT_EQ(26, particle.getChargeNumber()); + EXPECT_DOUBLE_EQ(-26 * eplus, particle.getCharge()); + + particle.setId(11); // electron + EXPECT_DOUBLE_EQ(-1 * eplus, particle.getCharge()); + + particle.setId(-11); // positron + EXPECT_DOUBLE_EQ(1 * eplus, particle.getCharge()); + + particle.setId(12); // electron neutrino + EXPECT_DOUBLE_EQ(0, particle.getCharge()); + + particle.setId(-12); // electron anti-neutrino + EXPECT_DOUBLE_EQ(0, particle.getCharge()); } -TEST(ParticleState, massNeutron) { +TEST(ParticleState, Mass) { ParticleState particle; - particle.setId(nucleusId(1, 0)); - EXPECT_EQ(particle.getMassNumber(), 1); - EXPECT_DOUBLE_EQ(particle.getMass(), mass_neutron); + + particle.setId(nucleusId(1, 1)); // proton + EXPECT_EQ(1, particle.getMassNumber()); + EXPECT_DOUBLE_EQ(mass_proton, particle.getMass()); + + particle.setId(nucleusId(1, 0)); // neutron + EXPECT_EQ(1, particle.getMassNumber()); + EXPECT_DOUBLE_EQ(mass_neutron, particle.getMass()); + + int id = nucleusId(56, 26); + particle.setId(id); // iron + EXPECT_EQ(56, particle.getMassNumber()); + EXPECT_DOUBLE_EQ(nucleusMass(id), particle.getMass()); + + particle.setId(-id); // anti-iron + EXPECT_EQ(56, particle.getMassNumber()); + EXPECT_DOUBLE_EQ(nucleusMass(-id), particle.getMass()); } TEST(ParticleState, lorentzFactor) { From 69a2d762f9b2d13ff3e097c0557eaa7b404f7e4e Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 12 Dec 2012 11:02:35 +0100 Subject: [PATCH 0243/1298] fixes for JF12 --- include/mpc/magneticField/JF2012Field.h | 30 +++++++++++- src/magneticField/JF2012Field.cpp | 62 ++++++++++++++++++++----- 2 files changed, 79 insertions(+), 13 deletions(-) diff --git a/include/mpc/magneticField/JF2012Field.h b/include/mpc/magneticField/JF2012Field.h index 80c209d99..646b4401f 100644 --- a/include/mpc/magneticField/JF2012Field.h +++ b/include/mpc/magneticField/JF2012Field.h @@ -6,7 +6,18 @@ namespace mpc { +/** + @class JF2012 + @brief JF2012 galactic magnetic field model + + Implements the JF2012 magnetic field model, consisting of a large-scale regular + and random (striated) field and a small-scale random (turbulent) field. + The field is described in + Jansson 2012a, ApJ. 757, A New Model of the Galactic Magnetic Field + Jansson 2012b, arXiv:1210.7820, The Galactic Magnetic Field + */ class JF2012Field: public MagneticField { + bool useRegular; bool useStriated; bool useTurbulent; @@ -35,7 +46,7 @@ class JF2012Field: public MagneticField { double sqrtbeta; // relative strength of striated field ref_ptr striatedGrid; - // Small-scale turbulent field ------------------------------------------- + // Turbulent field ------------------------------------------- ref_ptr turbulentGrid; // disk double bDiskTurb[8]; // field strengths in arms at r=5 kpc @@ -49,7 +60,10 @@ class JF2012Field: public MagneticField { public: JF2012Field(); + // Create and set a random realization for the striated field void randomStriated(int seed = 0); + + // Create a random realization for the turbulent field void randomTurbulent(int seed = 0); void setStriatedGrid(ref_ptr grid); @@ -58,10 +72,24 @@ class JF2012Field: public MagneticField { ref_ptr getStriatedGrid(); ref_ptr getTurbulentGrid(); + void setUseRegular(bool use); + void setUseStriated(bool use); + void setUseTurbulent(bool use); + + bool isUsingRegular(); + bool isUsingStriated(); + bool isUsingTurbulent(); + + // Regular field component Vector3d getRegularField(const Vector3d& pos) const; + + // Regular and striated field component Vector3d getStriatedField(const Vector3d& pos) const; + + // Turbulent field component Vector3d getTurbulentField(const Vector3d& pos) const; + // All set field components Vector3d getField(const Vector3d& pos) const; }; diff --git a/src/magneticField/JF2012Field.cpp b/src/magneticField/JF2012Field.cpp index f09d2d10f..243cf21a5 100644 --- a/src/magneticField/JF2012Field.cpp +++ b/src/magneticField/JF2012Field.cpp @@ -3,6 +3,8 @@ #include "mpc/GridTools.h" #include "mpc/Random.h" +#include + namespace mpc { double logisticFunction(double x, double x0, double w) { @@ -10,6 +12,7 @@ double logisticFunction(double x, double x0, double w) { } JF2012Field::JF2012Field() { + useRegular = true; useStriated = false; useTurbulent = false; @@ -121,13 +124,45 @@ ref_ptr JF2012Field::getTurbulentGrid() { return turbulentGrid; } +void JF2012Field::setUseRegular(bool use) { + useRegular = use; +} + +void JF2012Field::setUseStriated(bool use) { + if ((use) and (striatedGrid)) { + std::cout << "JF12Field: No striated field set: ignored" << std::endl; + return; + } + useStriated = use; +} + +void JF2012Field::setUseTurbulent(bool use) { + if ((use) and (turbulentGrid)) { + std::cout << "JF12Field: No turbulent field set: ignored" << std::endl; + return; + } + useTurbulent = use; +} + +bool JF2012Field::isUsingRegular() { + return useRegular; +} + +bool JF2012Field::isUsingStriated() { + return useStriated; +} + +bool JF2012Field::isUsingTurbulent() { + return useTurbulent; +} + Vector3d JF2012Field::getRegularField(const Vector3d& pos) const { Vector3d b(0.); double r = sqrt(pos.x * pos.x + pos.y * pos.y); // in-plane radius double d = pos.getMag(); // distance to galactic center if ((d < 1 * kpc) or (d > 20 * kpc)) - return b; + return b; // 0 field for d < 1 kpc or d > 20 kpc double phi = pos.getPhi(); // azimuth double sinPhi = sin(phi); @@ -179,8 +214,10 @@ Vector3d JF2012Field::getRegularField(const Vector3d& pos) const { if (r < rc) { // varying elevation region rp = r * rXc / rc; - bMagX = bX * exp(-rp / rX) * pow(rp / r, 2.); + bMagX = bX * exp(-1 * rp / rX) * pow(rp / r, 2.); double thetaX = atan2(fabs(pos.z), (r - rp)); + if (pos.z == 0) + thetaX = M_PI / 2.; sinThetaX = sin(thetaX); cosThetaX = cos(thetaX); } else { @@ -212,11 +249,10 @@ Vector3d JF2012Field::getTurbulentField(const Vector3d& pos) const { double r = sqrt(pos.x * pos.x + pos.y * pos.y); // in-plane radius double phi = pos.getPhi(); // azimuth - double bMag; - // disk + double bDisk = 0; if (r < 5 * kpc) { - bMag = bDiskTurb5; + bDisk = bDiskTurb5; } else { // spiral region double r_negx = r * exp(-(phi - M_PI) / tan90MinusPitch); @@ -227,27 +263,29 @@ Vector3d JF2012Field::getTurbulentField(const Vector3d& pos) const { for (int i = 7; i >= 0; i--) if (r_negx < rArms[i]) - bMag = bDiskTurb[i]; + bDisk = bDiskTurb[i]; + + bDisk *= (5 * kpc) / r; } - bMag *= exp(-0.5 * pow(pos.z / zDiskTurb, 2)); + bDisk *= exp(-0.5 * pow(pos.z / zDiskTurb, 2)); // halo - bMag += bHaloTurb * exp(-1. * (r / rHaloTurb)) + double bHalo = bHaloTurb * exp(-1. * (r / rHaloTurb)) * exp(-0.5 * pow(pos.z / zHaloTurb, 2)); // modulate turbulent field - b = turbulentGrid->interpolate(pos) * bMag; + b = turbulentGrid->interpolate(pos) * sqrt(bDisk * bDisk + bHalo * bHalo); return b; } Vector3d JF2012Field::getField(const Vector3d& pos) const { Vector3d b(0.); + if (useTurbulent) + b += getTurbulentField(pos); if (useStriated) b += getStriatedField(pos); - else + else if (useRegular) b += getRegularField(pos); - if (useTurbulent) - b += getTurbulentField(pos); return b; } From 2647f20f0c8c38f891a25aa0d9b0c23c05a238a9 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 9 Jan 2013 19:15:26 +0100 Subject: [PATCH 0244/1298] rename scaleGrid --- include/mpc/GridTools.h | 2 +- src/GridTools.cpp | 4 ++-- test/testCore.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mpc/GridTools.h b/include/mpc/GridTools.h index d10606ea7..b5888f789 100644 --- a/include/mpc/GridTools.h +++ b/include/mpc/GridTools.h @@ -16,7 +16,7 @@ double meanFieldStrength(ref_ptr grid); double rmsFieldStrength(ref_ptr grid); /** Multiply a magnetic field grid by a factor. */ -void scale(ref_ptr grid, double a); +void scaleGrid(ref_ptr grid, double a); #ifdef MPC_HAVE_FFTW3F /** diff --git a/src/GridTools.cpp b/src/GridTools.cpp index 159ed5ea3..fcbee0002 100644 --- a/src/GridTools.cpp +++ b/src/GridTools.cpp @@ -42,7 +42,7 @@ double rmsFieldStrength(ref_ptr grid) { return sqrt(sumB2 / Nx / Ny / Nz); } -void scale(ref_ptr grid, double a) { +void scaleGrid(ref_ptr grid, double a) { for (int ix = 0; ix < grid->getNx(); ix++) for (int iy = 0; iy < grid->getNy(); iy++) for (int iz = 0; iz < grid->getNz(); iz++) @@ -183,7 +183,7 @@ void initTurbulence(ref_ptr grid, double Brms, double lMin, fftwf_free(Bky); fftwf_free(Bkz); - scale(grid, Brms / rmsFieldStrength(grid)); // normalize to Brms + scaleGrid(grid, Brms / rmsFieldStrength(grid)); // normalize to Brms } #endif // MPC_HAVE_FFTW3F double turbulentCorrelationLength(double lMin, double lMax, diff --git a/test/testCore.cpp b/test/testCore.cpp index c423b4f6a..43d4189b7 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -323,7 +323,7 @@ TEST(VectordGrid, Scale) { for (int iz = 0; iz < 3; iz++) grid->get(ix, iy, iz) = Vector3f(1, 0, 0); - scale(grid, 5); + scaleGrid(grid, 5); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) From 67bcac825c92c565aaff46f9c71af0ee8c704744 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 9 Jan 2013 19:15:47 +0100 Subject: [PATCH 0245/1298] refactor JF12 --- include/mpc/magneticField/JF2012Field.h | 12 ++++++++++++ src/magneticField/JF2012Field.cpp | 20 ++++++++++---------- test/python/testJF12Field.py | 18 +++++++++--------- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/include/mpc/magneticField/JF2012Field.h b/include/mpc/magneticField/JF2012Field.h index 646b4401f..2e90a255c 100644 --- a/include/mpc/magneticField/JF2012Field.h +++ b/include/mpc/magneticField/JF2012Field.h @@ -66,7 +66,16 @@ class JF2012Field: public MagneticField { // Create a random realization for the turbulent field void randomTurbulent(int seed = 0); + /** + * Set a striated grid and activate the striated field component + * @param grid scalar grid containing random +1/-1 values, 100 parsec grid spacing + */ void setStriatedGrid(ref_ptr grid); + + /** + * Set a turbulent grid and activate the turbulent field component + * @param grid vector grid containing a random field of Brms = 1 + */ void setTurbulentGrid(ref_ptr grid); ref_ptr getStriatedGrid(); @@ -86,6 +95,9 @@ class JF2012Field: public MagneticField { // Regular and striated field component Vector3d getStriatedField(const Vector3d& pos) const; + // Brms of the turbulent field + double getTurbulentStrength(const Vector3d& pos) const; + // Turbulent field component Vector3d getTurbulentField(const Vector3d& pos) const; diff --git a/src/magneticField/JF2012Field.cpp b/src/magneticField/JF2012Field.cpp index 243cf21a5..82ce92492 100644 --- a/src/magneticField/JF2012Field.cpp +++ b/src/magneticField/JF2012Field.cpp @@ -236,15 +236,13 @@ Vector3d JF2012Field::getRegularField(const Vector3d& pos) const { } Vector3d JF2012Field::getStriatedField(const Vector3d& pos) const { - Vector3d b = getRegularField(pos); - return b * (1. + sqrtbeta * striatedGrid->closestValue(pos)); + return (getRegularField(pos) + * (1. + sqrtbeta * striatedGrid->closestValue(pos))); } -Vector3d JF2012Field::getTurbulentField(const Vector3d& pos) const { - Vector3d b(0.); - +double JF2012Field::getTurbulentStrength(const Vector3d& pos) const { if (pos.getMag() > 20 * kpc) - return b; + return 0; double r = sqrt(pos.x * pos.x + pos.y * pos.y); // in-plane radius double phi = pos.getPhi(); // azimuth @@ -270,12 +268,14 @@ Vector3d JF2012Field::getTurbulentField(const Vector3d& pos) const { bDisk *= exp(-0.5 * pow(pos.z / zDiskTurb, 2)); // halo - double bHalo = bHaloTurb * exp(-1. * (r / rHaloTurb)) - * exp(-0.5 * pow(pos.z / zHaloTurb, 2)); + double bHalo = bHaloTurb * exp(-r / rHaloTurb) * exp(-0.5 * pow(pos.z / zHaloTurb, 2)); // modulate turbulent field - b = turbulentGrid->interpolate(pos) * sqrt(bDisk * bDisk + bHalo * bHalo); - return b; + return sqrt(pow(bDisk, 2) + pow(bHalo, 2)); +} + +Vector3d JF2012Field::getTurbulentField(const Vector3d& pos) const { + return (turbulentGrid->interpolate(pos) * getTurbulentStrength(pos)); } Vector3d JF2012Field::getField(const Vector3d& pos) const { diff --git a/test/python/testJF12Field.py b/test/python/testJF12Field.py index 526262823..54a52ea29 100644 --- a/test/python/testJF12Field.py +++ b/test/python/testJF12Field.py @@ -8,24 +8,24 @@ #bField.randomTurbulent() N = 241 -x = (linspace(-20, 20, N, endpoint=True)) * kpc -y = (linspace(-20, 20, N, endpoint=True)) * kpc -z = 0 * kpc +lx = (linspace(-20, 20, N, endpoint=True)) +z = 0 +B, X, Y = zeros((3, N,N)) -B = zeros((N,N)) for ix in range(N): for iy in range(N): - b = bField.getField(Vector3d(x[ix], y[iy], z)) - B[iy, ix] = b.getMag() / gauss # B in [G], rows = y, columns = x - -maB = ma.masked_array(B, B==0) -X, Y = meshgrid(x / kpc, y / kpc) + b = bField.getField(Vector3d(lx[ix], lx[iy], z) * kpc) + B[ix, iy] = b.getMag() / gauss # B in [G] + X[ix, iy] = lx[ix] + Y[ix, iy] = lx[iy] figure() +maB = ma.masked_array(B, B==0) pc = pcolor(X, Y, maB, norm=LogNorm(), vmin=1e-9, vmax=1e-4) gca().set_aspect(1) cbar = colorbar(pc, shrink=0.8) cbar.set_label(r'$\vert \vec{B} \vert$ [G]') +plot(-8.5, 0, 'wo') xlabel('x [kpx]') ylabel('y [kpx]') show() From 41e3fc46e8f0f735a679269c0e79810b61faaecd Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 11 Jan 2013 16:45:14 +0100 Subject: [PATCH 0246/1298] fix optionality of FFTW enable python by default as it is the main steering --- CMakeLists.txt | 2 +- include/mpc/magneticField/JF2012Field.h | 2 ++ src/magneticField/JF2012Field.cpp | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cba674116..fdaa8b2b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -169,7 +169,7 @@ endif(ENABLETESTING) # ---------------------------------------------------------------------------- # Python # ---------------------------------------------------------------------------- -option(ENABLEPYTHON "Create python library via SWIG" OFF) +option(ENABLEPYTHON "Create python library via SWIG" ON) if(ENABLEPYTHON) include(python/Python.cmake) include_directories(${PYTHON_INCLUDE_PATH}) diff --git a/include/mpc/magneticField/JF2012Field.h b/include/mpc/magneticField/JF2012Field.h index 2e90a255c..0c2176bfe 100644 --- a/include/mpc/magneticField/JF2012Field.h +++ b/include/mpc/magneticField/JF2012Field.h @@ -63,8 +63,10 @@ class JF2012Field: public MagneticField { // Create and set a random realization for the striated field void randomStriated(int seed = 0); +#ifdef MPC_HAVE_FFTW3F // Create a random realization for the turbulent field void randomTurbulent(int seed = 0); +#endif /** * Set a striated grid and activate the striated field component diff --git a/src/magneticField/JF2012Field.cpp b/src/magneticField/JF2012Field.cpp index 82ce92492..fcf654ab0 100644 --- a/src/magneticField/JF2012Field.cpp +++ b/src/magneticField/JF2012Field.cpp @@ -98,6 +98,7 @@ void JF2012Field::randomStriated(int seed) { } } +#ifdef MPC_HAVE_FFTW3F void JF2012Field::randomTurbulent(int seed) { useTurbulent = true; // turbulent field with Kolmogorov spectrum, B_rms = 1 and Lc = 60 parsec @@ -105,6 +106,7 @@ void JF2012Field::randomTurbulent(int seed) { initTurbulence(turbulentGrid, 1., 16 * parsec, 255.5 * parsec, -11. / 3., seed); } +#endif void JF2012Field::setStriatedGrid(ref_ptr grid) { useStriated = true; From 00cc41640fb948534293d4516be204f55b054f8f Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 11 Jan 2013 16:57:15 +0100 Subject: [PATCH 0247/1298] default direction (-1, 0, 0) for particle states this way direction does not need to be explicitly set when in 1d mode, where the observer is at 0 and sources at positive coordinates --- src/ParticleState.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index fc307ab33..5188498c5 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -6,7 +6,7 @@ namespace mpc { ParticleState::ParticleState() : - id(0), pmass(0), energy(0), position(0, 0, 0), direction(1, 0, 0) { + id(0), pmass(0), energy(0), position(0, 0, 0), direction(-1, 0, 0) { } From a17c226c6f0b5c795884a2a3578dfa110d0c630b Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 15 Jan 2013 15:21:54 +0100 Subject: [PATCH 0248/1298] renamed SourceNuclei to SourceMultipleParticleTypes to reflect its generality --- include/mpc/Source.h | 24 ++++++++++++------------ src/Source.cpp | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/mpc/Source.h b/include/mpc/Source.h index f825dc756..8ed1e8ed6 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -59,6 +59,18 @@ class SourceParticleType: public SourceProperty { void prepare(ParticleState &particle) const; }; +/** + @class SourceMultipleParticleTypes + @brief Multiple particle types with individual (relative) total abundances + */ +class SourceMultipleParticleTypes: public SourceProperty { + std::vector ids; /**< particle ids */ + std::vector abundances; /**< (relative) total abundances */ +public: + void add(int id, double abundance = 1); + void prepare(ParticleState &particle) const; +}; + /** @class SourceEnergy @brief Sets the initial energy to a given value @@ -89,18 +101,6 @@ class SourcePowerLawSpectrum: public SourceProperty { void prepare(ParticleState &particle) const; }; -/** - @class SourceNuclei - @brief Nuclei with given total abundances - */ -class SourceNuclei: public SourceProperty { - std::vector ids; /**< nucleus id */ - std::vector abundances; /**< relative abundance of source isotopes at equal energies */ -public: - void add(int id, double abundance = 1); - void prepare(ParticleState &particle) const; -}; - /** @class SourceComposition @brief Nuclei with given abundances and a uniform power law spectrum between Emin and Z * Rmax diff --git a/src/Source.cpp b/src/Source.cpp index d0b74b1e4..7ababce9b 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -72,14 +72,14 @@ void SourcePowerLawSpectrum::prepare(ParticleState& particle) const { particle.setEnergy(E); } -void SourceNuclei::add(int id, double a) { +void SourceMultipleParticleTypes::add(int id, double a) { ids.push_back(id); if (abundances.size() > 0) a += abundances.back(); abundances.push_back(a); } -void SourceNuclei::prepare(ParticleState& particle) const { +void SourceMultipleParticleTypes::prepare(ParticleState& particle) const { if (ids.size() == 0) throw std::runtime_error("SourceNuclei: no nuclei set"); Random &random = Random::instance(); From 00d6a61961aab31e2a6b250538273e350152c172 Mon Sep 17 00:00:00 2001 From: kuempel Date: Wed, 16 Jan 2013 15:37:58 +0100 Subject: [PATCH 0249/1298] Added first version of ROOT output --- CMakeLists.txt | 21 +++++ cmake/FindROOT.cmake | 15 ++++ include/mpc/module/OutputROOT.h | 80 ++++++++++++++++++ python/mpc.i | 4 +- src/module/OutputROOT.cpp | 138 ++++++++++++++++++++++++++++++++ 5 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 cmake/FindROOT.cmake create mode 100644 include/mpc/module/OutputROOT.h create mode 100644 src/module/OutputROOT.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fdaa8b2b3..5d7c701cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,26 @@ if (GADGET_FOUND) list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_GADGET) endif (GADGET_FOUND) +# ROOT (optional for ROOT output) +find_package(ROOT) +if (ROOT_FOUND) + FIND_PROGRAM(ROOT_CONFIG root-config REQUIRED ROOT_CONFIG_PATH) + execute_process(COMMAND ${ROOT_CONFIG} "--cflags" OUTPUT_VARIABLE ROOT_CFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + message(STATUS "ROOT cflags: ${ROOT_CFLAGS}") + + execute_process(COMMAND ${ROOT_CONFIG} "--libs" OUTPUT_VARIABLE ROOT_LIBS OUTPUT_STRIP_TRAILING_WHITESPACE) + message(STATUS "ROOT libs: ${ROOT_LIBS}") + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ROOT_CFLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") + + add_definitions(-DMPC_HAVE_ROOT) +endif() + + + + # Google Performance Tools (optional as possible performance tweak) find_package(GooglePerfTools) set(TCMALLOC) @@ -100,6 +120,7 @@ add_library(mpc SHARED src/module/PhotoDisintegration.cpp src/module/Redshift.cpp src/module/Output.cpp + src/module/OutputROOT.cpp src/module/Tools.cpp src/magneticField/MagneticField.cpp src/magneticField/MagneticFieldGrid.cpp diff --git a/cmake/FindROOT.cmake b/cmake/FindROOT.cmake new file mode 100644 index 000000000..18a696ca9 --- /dev/null +++ b/cmake/FindROOT.cmake @@ -0,0 +1,15 @@ +# - Finds ROOT instalation +# This module sets up ROOT information +# It defines: +# ROOT_FOUND If the ROOT is found + +find_program(ROOT_CONFIG_EXECUTABLE root-config + PATHS $ENV{ROOTSYS}/bin) + +if(NOT ROOT_CONFIG_EXECUTABLE) + set(ROOT_FOUND FALSE) + MESSAGE(STATUS "ROOT: NOT Found!") +else() + set(ROOT_FOUND TRUE) + MESSAGE(STATUS "ROOT: Found!") +endif() \ No newline at end of file diff --git a/include/mpc/module/OutputROOT.h b/include/mpc/module/OutputROOT.h new file mode 100644 index 000000000..d45ce2be3 --- /dev/null +++ b/include/mpc/module/OutputROOT.h @@ -0,0 +1,80 @@ +#ifndef OUTPUTROOT_H_ +#define OUTPUTROOT_H_ + +#include "mpc/Module.h" +#include + +#ifdef MPC_HAVE_ROOT +#include +#include + +namespace mpc { + +/** + @class EventOutput 1D ROOT + @brief Records particles that are inactive and have the property 'Detected' to a ROOT file. + */ +class ROOTEventOutput1D: public Module { + mutable TFile *ROOTFile; + mutable TNtuple *Ntuple; + +public: + ROOTEventOutput1D(std::string filename); + ~ROOTEventOutput1D(); + void process(Candidate *candidate) const; +}; + + +/** + @class TrajectoryOutput 1D ROOT + @brief Saves trajectories to root file. + */ +class ROOTTrajectoryOutput1D: public Module { + mutable TFile *ROOTFile; + mutable TNtuple *Ntuple; + +public: + ROOTTrajectoryOutput1D(std::string filename); + ~ROOTTrajectoryOutput1D(); + void process(Candidate *candidate) const; +}; + + +/** + @class EventOutput 3D ROOT + @brief Records particles that are inactive and have the property 'Detected' to a ROOT file in 3D. + */ +class ROOTEventOutput3D: public Module { + mutable TFile *ROOTFile; + mutable TNtuple *Ntuple; + +public: + ROOTEventOutput3D(std::string filename); + ~ROOTEventOutput3D(); + void process(Candidate *candidate) const; +}; + + +/** + @class TrajectoryOutput 3D ROOT + @brief Saves trajectories to root file in 3D. + */ +class ROOTTrajectoryOutput3D: public Module { + mutable TFile *ROOTFile; + mutable TNtuple *Ntuple; + +public: + ROOTTrajectoryOutput3D(std::string filename); + ~ROOTTrajectoryOutput3D(); + void process(Candidate *candidate) const; +}; + + + + + +} // namespace mpc + + +#endif // MPC_HAVE_ROOT +#endif /* OUTPUTROOT_H_ */ diff --git a/python/mpc.i b/python/mpc.i index bddb2591f..b6899e742 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -24,6 +24,7 @@ #include "mpc/module/Boundary.h" #include "mpc/module/Observer.h" #include "mpc/module/Output.h" +#include "mpc/module/OutputROOT.h" #include "mpc/module/SimplePropagation.h" #include "mpc/module/DeflectionCK.h" #include "mpc/module/Tools.h" @@ -129,6 +130,7 @@ %include "mpc/module/SimplePropagation.h" %include "mpc/module/DeflectionCK.h" %include "mpc/module/Output.h" +%include "mpc/module/OutputROOT.h" %include "mpc/module/ElectronPairProduction.h" %include "mpc/module/StochasticInteraction.h" %include "mpc/module/NuclearDecay.h" @@ -141,4 +143,4 @@ %include "mpc/Source.h" %template(ModuleListRefPtr) mpc::ref_ptr; -%include "mpc/ModuleList.h" \ No newline at end of file +%include "mpc/ModuleList.h" diff --git a/src/module/OutputROOT.cpp b/src/module/OutputROOT.cpp new file mode 100644 index 000000000..9187b814e --- /dev/null +++ b/src/module/OutputROOT.cpp @@ -0,0 +1,138 @@ +#include "mpc/module/OutputROOT.h" + +#include +#include +#include +#include +#include + + +#ifdef MPC_HAVE_ROOT + +namespace mpc { + +/////////////////////// ROOT EVENT OUTPUT 1D ////////////////////////////////// +ROOTEventOutput1D::ROOTEventOutput1D(std::string filename) { + ROOTFile = new TFile(filename.c_str(),"RECREATE","CRPropa output data file"); + Ntuple = new TNtuple("events","CRPropa 1D events","Particle_Type:Initial_Type:Initial_Position_Mpc:Inital_Redshift:Initial_Energy_EeV:Time_Mpc:Energy_EeV"); +} + +ROOTEventOutput1D::~ROOTEventOutput1D() { + ROOTFile->Write() ; + ROOTFile->Close() ; +} + +void ROOTEventOutput1D::process(Candidate *c) const { + if (c->isActive()) + return; + if (c->hasProperty("Detected")) { + #pragma omp critical + { + Ntuple->Fill(c->current.getId(), + c->initial.getId(), + c->initial.getPosition().getX() / Mpc, + c->getRedshift(), + c->initial.getEnergy() / EeV, + c->getTrajectoryLength() / Mpc, + c->current.getEnergy() / EeV); + } + } +} +//////////////////////////////////////////////////////////////////////////////// + + + +/////////////////////// ROOT TRAJECTORY OUTPUT 1D ////////////////////////////// +ROOTTrajectoryOutput1D::ROOTTrajectoryOutput1D(std::string filename) { + ROOTFile = new TFile(filename.c_str(),"RECREATE","CRPropa output data file"); + // Ntuple = new TNtuple("traj","CRPropa 1D trajectories","Particle_Type:Initial_Type:Time_Mpc:Position_Mpc:Energy_EeV"); + Ntuple = new TNtuple("traj","CRPropa 1D trajectories","Particle_Type:Initial_Type:Time_Mpc:Position_Mpc:Energy_EeV"); +} + +ROOTTrajectoryOutput1D::~ROOTTrajectoryOutput1D() { + ROOTFile->Write() ; + ROOTFile->Close() ; +} + +void ROOTTrajectoryOutput1D::process(Candidate *c) const { + #pragma omp critical + { + Ntuple->Fill(c->current.getId(), + c->initial.getId(), + c->getTrajectoryLength() / Mpc, + c->current.getPosition().getX() / Mpc, + c->current.getEnergy() / EeV); + } +} +//////////////////////////////////////////////////////////////////////////////// + + + +/////////////////////// ROOT EVENT OUTPUT 3D ////////////////////////////////// +ROOTEventOutput3D::ROOTEventOutput3D(std::string filename) { + ROOTFile = new TFile(filename.c_str(),"RECREATE","CRPropa output data file"); + Ntuple = new TNtuple("events","CRPropa 3D events","Particle_Type:Initial_Type:Initial_Position_X_Mpc:Initial_Position_Y_Mpc:Initial_Position_Z_Mpc:Initial_Momentum_E_EeV:Initial_Momentum_theta:Initial_Momentum_phi:Time_Mpc:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Momentum_E_EeV:Momentum_theta:Momentum_phi"); +} + +ROOTEventOutput3D::~ROOTEventOutput3D() { + ROOTFile->Write() ; + ROOTFile->Close() ; +} + +void ROOTEventOutput3D::process(Candidate *c) const { + if (c->isActive()) + return; + if (c->hasProperty("Detected")) { + #pragma omp critical + { + Ntuple->Fill(c->current.getId(), + c->initial.getId(), + c->initial.getPosition().getX() / Mpc, + c->initial.getPosition().getY() / Mpc, + c->initial.getPosition().getZ() / Mpc, + c->initial.getEnergy() / EeV, + c->initial.getDirection().getTheta(), + c->initial.getDirection().getPhi(), + c->getTrajectoryLength() / Mpc, + c->current.getPosition().getX() / Mpc, + c->current.getPosition().getY() / Mpc, + c->current.getPosition().getZ() / Mpc, + c->current.getEnergy() / EeV, + c->current.getDirection().getTheta(), + c->current.getDirection().getPhi()); + } + } +} +//////////////////////////////////////////////////////////////////////////////// + + +/////////////////////// ROOT TRAJECTORY OUTPUT 3D ////////////////////////////// +ROOTTrajectoryOutput3D::ROOTTrajectoryOutput3D(std::string filename) { + ROOTFile = new TFile(filename.c_str(),"RECREATE","CRPropa output data file"); + Ntuple = new TNtuple("traj","CRPropa 3D trajectories","Particle_Type:Initial_Type:Time_Mpc:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Direction_X:Direction_Y:Direction_Z:Energy_EeV"); +} + +ROOTTrajectoryOutput3D::~ROOTTrajectoryOutput3D() { + ROOTFile->Write() ; + ROOTFile->Close() ; +} + +void ROOTTrajectoryOutput3D::process(Candidate *c) const { + #pragma omp critical + { + Ntuple->Fill(c->current.getId(), + c->initial.getId(), + c->getTrajectoryLength() / Mpc, + c->current.getPosition().getX() / Mpc, + c->current.getPosition().getY() / Mpc, + c->current.getPosition().getZ() / Mpc, + c->current.getDirection().getX(), + c->current.getDirection().getY(), + c->current.getDirection().getZ(), + c->current.getEnergy() / EeV); + } +} +//////////////////////////////////////////////////////////////////////////////// + +} // namespace mpc +#endif // MPC_HAVE_ROOT From 66d630caf4ca9c3781260836684ee738a789efaa Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 16 Jan 2013 16:05:02 +0100 Subject: [PATCH 0250/1298] missing change from renaming SourceNuclei to SourceMultiple... --- src/XmlExecute.cpp | 2 +- test/python/testEnergyLossLength.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index b04760d29..c1d76880f 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -595,7 +595,7 @@ void XmlExecute::loadSpectrumComposition(pugi::xml_node &node) { } void XmlExecute::loadSourceNuclei(pugi::xml_node &node) { - SourceNuclei *composition = new SourceNuclei(); + SourceMultipleParticleTypes *composition = new SourceMultipleParticleTypes(); xml_node p = node.child("Particles"); for (xml_node n = p.child("Species"); n; n = n.next_sibling("Species")) { int A = n.attribute("MassNumber").as_int(); diff --git a/test/python/testEnergyLossLength.py b/test/python/testEnergyLossLength.py index 594230fa8..de401bbc0 100644 --- a/test/python/testEnergyLossLength.py +++ b/test/python/testEnergyLossLength.py @@ -50,5 +50,5 @@ def parse_pid(pid): ylabel('Energy Loss Length [Mpc]') ylim(0.1, 1e4) loglog() -savefig('EnergyLossLength_%i.png'%pid) +savefig('EnergyLossLength_%i.png'%pid, bbox_inches='tight') show() From 31868b6ed41c0420f8071ca5d39f4d87efb6046d Mon Sep 17 00:00:00 2001 From: kuempel Date: Wed, 16 Jan 2013 16:43:07 +0100 Subject: [PATCH 0251/1298] Fix problem with ROOT output using python ; minor change in ROOT output --- CMakeLists.txt | 1 + src/module/OutputROOT.cpp | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d7c701cc..4bcc22fbc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,7 @@ if (ROOT_FOUND) set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") add_definitions(-DMPC_HAVE_ROOT) + list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_ROOT) endif() diff --git a/src/module/OutputROOT.cpp b/src/module/OutputROOT.cpp index 9187b814e..14d679915 100644 --- a/src/module/OutputROOT.cpp +++ b/src/module/OutputROOT.cpp @@ -80,8 +80,6 @@ ROOTEventOutput3D::~ROOTEventOutput3D() { } void ROOTEventOutput3D::process(Candidate *c) const { - if (c->isActive()) - return; if (c->hasProperty("Detected")) { #pragma omp critical { From 805013575ea1a9cdeebe24b8552ebb8194889533 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 16 Jan 2013 17:16:04 +0100 Subject: [PATCH 0252/1298] have Doxygen expand the optional FFTW, Gadget and ROOT includes --- doc/Doxyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Doxyfile b/doc/Doxyfile index 523809b86..1eec30197 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -1447,7 +1447,7 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = +PREDEFINED = MPC_HAVE_ROOT MPC_HAVE_GADGET MPC_HAVE_FFTW3F # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. From 52ffc730acf53017d877d644facec67db1a2cd6a Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 16 Jan 2013 17:23:25 +0100 Subject: [PATCH 0253/1298] ROOTOutput: update Doxygen documentation, apply autoformat, remove extra includes --- CMakeLists.txt | 8 -- cmake/FindROOT.cmake | 2 +- include/mpc/module/OutputROOT.h | 41 ++++----- src/module/OutputROOT.cpp | 155 +++++++++++++++----------------- 4 files changed, 91 insertions(+), 115 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bcc22fbc..cfc66b55c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,22 +70,14 @@ find_package(ROOT) if (ROOT_FOUND) FIND_PROGRAM(ROOT_CONFIG root-config REQUIRED ROOT_CONFIG_PATH) execute_process(COMMAND ${ROOT_CONFIG} "--cflags" OUTPUT_VARIABLE ROOT_CFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) - message(STATUS "ROOT cflags: ${ROOT_CFLAGS}") - execute_process(COMMAND ${ROOT_CONFIG} "--libs" OUTPUT_VARIABLE ROOT_LIBS OUTPUT_STRIP_TRAILING_WHITESPACE) - message(STATUS "ROOT libs: ${ROOT_LIBS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ROOT_CFLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") - add_definitions(-DMPC_HAVE_ROOT) list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_ROOT) endif() - - - # Google Performance Tools (optional as possible performance tweak) find_package(GooglePerfTools) set(TCMALLOC) diff --git a/cmake/FindROOT.cmake b/cmake/FindROOT.cmake index 18a696ca9..dd7810c23 100644 --- a/cmake/FindROOT.cmake +++ b/cmake/FindROOT.cmake @@ -1,7 +1,7 @@ # - Finds ROOT instalation # This module sets up ROOT information # It defines: -# ROOT_FOUND If the ROOT is found +# ROOT_FOUND If ROOT is found find_program(ROOT_CONFIG_EXECUTABLE root-config PATHS $ENV{ROOTSYS}/bin) diff --git a/include/mpc/module/OutputROOT.h b/include/mpc/module/OutputROOT.h index d45ce2be3..00b98adf1 100644 --- a/include/mpc/module/OutputROOT.h +++ b/include/mpc/module/OutputROOT.h @@ -1,8 +1,7 @@ -#ifndef OUTPUTROOT_H_ -#define OUTPUTROOT_H_ +#ifndef MPC_OUTPUTROOT_H_ +#define MPC_OUTPUTROOT_H_ #include "mpc/Module.h" -#include #ifdef MPC_HAVE_ROOT #include @@ -11,12 +10,12 @@ namespace mpc { /** - @class EventOutput 1D ROOT + @class ROOTEventOutput1D @brief Records particles that are inactive and have the property 'Detected' to a ROOT file. */ class ROOTEventOutput1D: public Module { - mutable TFile *ROOTFile; - mutable TNtuple *Ntuple; + mutable TFile *ROOTFile; + mutable TNtuple *Ntuple; public: ROOTEventOutput1D(std::string filename); @@ -24,14 +23,13 @@ class ROOTEventOutput1D: public Module { void process(Candidate *candidate) const; }; - /** - @class TrajectoryOutput 1D ROOT + @class ROOTTrajectoryOutput1D @brief Saves trajectories to root file. */ class ROOTTrajectoryOutput1D: public Module { - mutable TFile *ROOTFile; - mutable TNtuple *Ntuple; + mutable TFile *ROOTFile; + mutable TNtuple *Ntuple; public: ROOTTrajectoryOutput1D(std::string filename); @@ -39,14 +37,13 @@ class ROOTTrajectoryOutput1D: public Module { void process(Candidate *candidate) const; }; - /** - @class EventOutput 3D ROOT - @brief Records particles that are inactive and have the property 'Detected' to a ROOT file in 3D. + @class ROOTEventOutput3D + @brief Records particles that have the property 'Detected' to a ROOT file in 3D. */ class ROOTEventOutput3D: public Module { - mutable TFile *ROOTFile; - mutable TNtuple *Ntuple; + mutable TFile *ROOTFile; + mutable TNtuple *Ntuple; public: ROOTEventOutput3D(std::string filename); @@ -54,14 +51,13 @@ class ROOTEventOutput3D: public Module { void process(Candidate *candidate) const; }; - /** - @class TrajectoryOutput 3D ROOT + @class ROOTTrajectoryOutput3D @brief Saves trajectories to root file in 3D. */ class ROOTTrajectoryOutput3D: public Module { - mutable TFile *ROOTFile; - mutable TNtuple *Ntuple; + mutable TFile *ROOTFile; + mutable TNtuple *Ntuple; public: ROOTTrajectoryOutput3D(std::string filename); @@ -69,12 +65,7 @@ class ROOTTrajectoryOutput3D: public Module { void process(Candidate *candidate) const; }; - - - - } // namespace mpc - #endif // MPC_HAVE_ROOT -#endif /* OUTPUTROOT_H_ */ +#endif // MPC_OUTPUTROOT_H_ diff --git a/src/module/OutputROOT.cpp b/src/module/OutputROOT.cpp index 14d679915..2077a0f78 100644 --- a/src/module/OutputROOT.cpp +++ b/src/module/OutputROOT.cpp @@ -1,136 +1,129 @@ #include "mpc/module/OutputROOT.h" -#include -#include -#include -#include -#include - - #ifdef MPC_HAVE_ROOT namespace mpc { /////////////////////// ROOT EVENT OUTPUT 1D ////////////////////////////////// ROOTEventOutput1D::ROOTEventOutput1D(std::string filename) { - ROOTFile = new TFile(filename.c_str(),"RECREATE","CRPropa output data file"); - Ntuple = new TNtuple("events","CRPropa 1D events","Particle_Type:Initial_Type:Initial_Position_Mpc:Inital_Redshift:Initial_Energy_EeV:Time_Mpc:Energy_EeV"); + ROOTFile = new TFile(filename.c_str(), "RECREATE", + "CRPropa output data file"); + Ntuple = + new TNtuple("events", "CRPropa 1D events", + "Particle_Type:Initial_Type:Initial_Position_Mpc:Inital_Redshift:Initial_Energy_EeV:Time_Mpc:Energy_EeV"); } ROOTEventOutput1D::~ROOTEventOutput1D() { - ROOTFile->Write() ; - ROOTFile->Close() ; + ROOTFile->Write(); + ROOTFile->Close(); } void ROOTEventOutput1D::process(Candidate *c) const { if (c->isActive()) return; if (c->hasProperty("Detected")) { - #pragma omp critical - { - Ntuple->Fill(c->current.getId(), - c->initial.getId(), - c->initial.getPosition().getX() / Mpc, - c->getRedshift(), - c->initial.getEnergy() / EeV, - c->getTrajectoryLength() / Mpc, - c->current.getEnergy() / EeV); - } +#pragma omp critical + { + Ntuple->Fill(c->current.getId(), c->initial.getId(), + c->initial.getPosition().getX() / Mpc, c->getRedshift(), + c->initial.getEnergy() / EeV, + c->getTrajectoryLength() / Mpc, + c->current.getEnergy() / EeV); + } } } //////////////////////////////////////////////////////////////////////////////// - - /////////////////////// ROOT TRAJECTORY OUTPUT 1D ////////////////////////////// ROOTTrajectoryOutput1D::ROOTTrajectoryOutput1D(std::string filename) { - ROOTFile = new TFile(filename.c_str(),"RECREATE","CRPropa output data file"); - // Ntuple = new TNtuple("traj","CRPropa 1D trajectories","Particle_Type:Initial_Type:Time_Mpc:Position_Mpc:Energy_EeV"); - Ntuple = new TNtuple("traj","CRPropa 1D trajectories","Particle_Type:Initial_Type:Time_Mpc:Position_Mpc:Energy_EeV"); + ROOTFile = new TFile(filename.c_str(), "RECREATE", + "CRPropa output data file"); + // Ntuple = new TNtuple("traj","CRPropa 1D trajectories","Particle_Type:Initial_Type:Time_Mpc:Position_Mpc:Energy_EeV"); + Ntuple = new TNtuple("traj", "CRPropa 1D trajectories", + "Particle_Type:Initial_Type:Time_Mpc:Position_Mpc:Energy_EeV"); } ROOTTrajectoryOutput1D::~ROOTTrajectoryOutput1D() { - ROOTFile->Write() ; - ROOTFile->Close() ; + ROOTFile->Write(); + ROOTFile->Close(); } void ROOTTrajectoryOutput1D::process(Candidate *c) const { - #pragma omp critical - { - Ntuple->Fill(c->current.getId(), - c->initial.getId(), - c->getTrajectoryLength() / Mpc, - c->current.getPosition().getX() / Mpc, - c->current.getEnergy() / EeV); - } -} +#pragma omp critical + { + Ntuple->Fill(c->current.getId(), c->initial.getId(), + c->getTrajectoryLength() / Mpc, + c->current.getPosition().getX() / Mpc, + c->current.getEnergy() / EeV); + } +} //////////////////////////////////////////////////////////////////////////////// - - /////////////////////// ROOT EVENT OUTPUT 3D ////////////////////////////////// ROOTEventOutput3D::ROOTEventOutput3D(std::string filename) { - ROOTFile = new TFile(filename.c_str(),"RECREATE","CRPropa output data file"); - Ntuple = new TNtuple("events","CRPropa 3D events","Particle_Type:Initial_Type:Initial_Position_X_Mpc:Initial_Position_Y_Mpc:Initial_Position_Z_Mpc:Initial_Momentum_E_EeV:Initial_Momentum_theta:Initial_Momentum_phi:Time_Mpc:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Momentum_E_EeV:Momentum_theta:Momentum_phi"); + ROOTFile = new TFile(filename.c_str(), "RECREATE", + "CRPropa output data file"); + Ntuple = + new TNtuple("events", "CRPropa 3D events", + "Particle_Type:Initial_Type:Initial_Position_X_Mpc:Initial_Position_Y_Mpc:Initial_Position_Z_Mpc:Initial_Momentum_E_EeV:Initial_Momentum_theta:Initial_Momentum_phi:Time_Mpc:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Momentum_E_EeV:Momentum_theta:Momentum_phi"); } ROOTEventOutput3D::~ROOTEventOutput3D() { - ROOTFile->Write() ; - ROOTFile->Close() ; + ROOTFile->Write(); + ROOTFile->Close(); } void ROOTEventOutput3D::process(Candidate *c) const { if (c->hasProperty("Detected")) { - #pragma omp critical - { - Ntuple->Fill(c->current.getId(), - c->initial.getId(), - c->initial.getPosition().getX() / Mpc, - c->initial.getPosition().getY() / Mpc, - c->initial.getPosition().getZ() / Mpc, - c->initial.getEnergy() / EeV, - c->initial.getDirection().getTheta(), - c->initial.getDirection().getPhi(), - c->getTrajectoryLength() / Mpc, - c->current.getPosition().getX() / Mpc, - c->current.getPosition().getY() / Mpc, - c->current.getPosition().getZ() / Mpc, - c->current.getEnergy() / EeV, - c->current.getDirection().getTheta(), - c->current.getDirection().getPhi()); - } +#pragma omp critical + { + Ntuple->Fill(c->current.getId(), c->initial.getId(), + c->initial.getPosition().getX() / Mpc, + c->initial.getPosition().getY() / Mpc, + c->initial.getPosition().getZ() / Mpc, + c->initial.getEnergy() / EeV, + c->initial.getDirection().getTheta(), + c->initial.getDirection().getPhi(), + c->getTrajectoryLength() / Mpc, + c->current.getPosition().getX() / Mpc, + c->current.getPosition().getY() / Mpc, + c->current.getPosition().getZ() / Mpc, + c->current.getEnergy() / EeV, + c->current.getDirection().getTheta(), + c->current.getDirection().getPhi()); + } } } //////////////////////////////////////////////////////////////////////////////// - /////////////////////// ROOT TRAJECTORY OUTPUT 3D ////////////////////////////// ROOTTrajectoryOutput3D::ROOTTrajectoryOutput3D(std::string filename) { - ROOTFile = new TFile(filename.c_str(),"RECREATE","CRPropa output data file"); - Ntuple = new TNtuple("traj","CRPropa 3D trajectories","Particle_Type:Initial_Type:Time_Mpc:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Direction_X:Direction_Y:Direction_Z:Energy_EeV"); + ROOTFile = new TFile(filename.c_str(), "RECREATE", + "CRPropa output data file"); + Ntuple = + new TNtuple("traj", "CRPropa 3D trajectories", + "Particle_Type:Initial_Type:Time_Mpc:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Direction_X:Direction_Y:Direction_Z:Energy_EeV"); } ROOTTrajectoryOutput3D::~ROOTTrajectoryOutput3D() { - ROOTFile->Write() ; - ROOTFile->Close() ; + ROOTFile->Write(); + ROOTFile->Close(); } void ROOTTrajectoryOutput3D::process(Candidate *c) const { - #pragma omp critical - { - Ntuple->Fill(c->current.getId(), - c->initial.getId(), - c->getTrajectoryLength() / Mpc, - c->current.getPosition().getX() / Mpc, - c->current.getPosition().getY() / Mpc, - c->current.getPosition().getZ() / Mpc, - c->current.getDirection().getX(), - c->current.getDirection().getY(), - c->current.getDirection().getZ(), - c->current.getEnergy() / EeV); - } -} +#pragma omp critical + { + Ntuple->Fill(c->current.getId(), c->initial.getId(), + c->getTrajectoryLength() / Mpc, + c->current.getPosition().getX() / Mpc, + c->current.getPosition().getY() / Mpc, + c->current.getPosition().getZ() / Mpc, + c->current.getDirection().getX(), + c->current.getDirection().getY(), + c->current.getDirection().getZ(), c->current.getEnergy() / EeV); + } +} //////////////////////////////////////////////////////////////////////////////// -} // namespace mpc +}// namespace mpc #endif // MPC_HAVE_ROOT From e01be95eef435ea2a02698f34d01cfabd81e975b Mon Sep 17 00:00:00 2001 From: kuempel Date: Wed, 16 Jan 2013 17:28:27 +0100 Subject: [PATCH 0254/1298] Added ROOT output functionality to xml steering --- src/XmlExecute.cpp | 49 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index c1d76880f..804051360 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -11,6 +11,7 @@ #include "mpc/module/Boundary.h" #include "mpc/module/Observer.h" #include "mpc/module/Output.h" +#include "mpc/module/OutputROOT.h" #include "mpc/ModuleList.h" #include "pugixml.hpp" @@ -612,6 +613,10 @@ void XmlExecute::loadOutput(xml_node &node) { string type = node.attribute("type").as_string(); cout << "Output: " << type << endl; + xml_node file_node = node.child("File"); + string format = file_node.attribute("type").as_string(); + cout << " - Filetype: " << format << endl; + string filename = node.child("File").child_value(); cout << " - Filename: " << filename << endl; @@ -622,20 +627,38 @@ void XmlExecute::loadOutput(xml_node &node) { throw runtime_error("Output file already exists!"); } - if (type == "Full Trajectories") - if (is1D) - modules.add(new TrajectoryOutput1D(filename)); - else - modules.add(new TrajectoryOutput(filename)); - else if (type == "Events") - if (is1D) - modules.add(new EventOutput1D(filename)); - else - modules.add(new ConditionalOutput(filename)); - else if (type == "None") - return; + if (format == "ASCII") + if (type == "Full Trajectories") + if (is1D) + modules.add(new TrajectoryOutput1D(filename)); + else + modules.add(new TrajectoryOutput(filename)); + else if (type == "Events") + if (is1D) + modules.add(new EventOutput1D(filename)); + else + modules.add(new ConditionalOutput(filename)); + else if (type == "None") + return; + else + cout << " --> unknown output" << endl; + else if (format == "ROOT") + if (type == "Full Trajectories") + if (is1D) + modules.add(new ROOTTrajectoryOutput1D(filename)); + else + modules.add(new ROOTTrajectoryOutput3D(filename)); + else if (type == "Events") + if (is1D) + modules.add(new ROOTEventOutput1D(filename)); + else + modules.add(new ROOTEventOutput3D(filename)); + else if (type == "None") + return; + else + cout << " --> unknown output" << endl; else - cout << " --> unknown output" << endl; + cout << " --> unknown output format (should be 'ASCII' or 'ROOT')" << endl; } void XmlExecute::run() { From 1d64f286edea1ae2f0b2e202a7f916b9fbe56529 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 17 Jan 2013 16:13:18 +0100 Subject: [PATCH 0255/1298] CRPropa2-like ASCII output these replace the standard ASCII output in XML steering added test xml cards for these outputs --- CMakeLists.txt | 1 + include/mpc/Nucleus.h | 6 +- include/mpc/module/Output.h | 6 +- python/mpc.i | 9 +++ src/XmlExecute.cpp | 79 ++++++++++++++----------- src/module/Output.cpp | 3 - test/xml/CRPropa2EventOutput1D.xml | 35 +++++++++++ test/xml/CRPropa2EventOutput3D.xml | 58 ++++++++++++++++++ test/xml/CRPropa2TrajectoryOutput1D.xml | 35 +++++++++++ test/xml/CRPropa2TrajectoryOutput3D.xml | 58 ++++++++++++++++++ 10 files changed, 246 insertions(+), 44 deletions(-) create mode 100644 test/xml/CRPropa2EventOutput1D.xml create mode 100644 test/xml/CRPropa2EventOutput3D.xml create mode 100644 test/xml/CRPropa2TrajectoryOutput1D.xml create mode 100644 test/xml/CRPropa2TrajectoryOutput3D.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index cfc66b55c..95deb5d54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,6 +114,7 @@ add_library(mpc SHARED src/module/Redshift.cpp src/module/Output.cpp src/module/OutputROOT.cpp + src/module/OutputCRPropa2.cpp src/module/Tools.cpp src/magneticField/MagneticField.cpp src/magneticField/MagneticFieldGrid.cpp diff --git a/include/mpc/Nucleus.h b/include/mpc/Nucleus.h index 8d99fb5ae..2aa02479e 100644 --- a/include/mpc/Nucleus.h +++ b/include/mpc/Nucleus.h @@ -1,5 +1,5 @@ -#ifndef NUCLEUS_H_ -#define NUCLEUS_H_ +#ifndef MPC_NUCLEUS_H_ +#define MPC_NUCLEUS_H_ namespace mpc { @@ -27,4 +27,4 @@ double nucleusMass(int id); } // namespace mpc -#endif /* NUCLEUS_H_ */ +#endif // MPC_NUCLEUS_H_ diff --git a/include/mpc/module/Output.h b/include/mpc/module/Output.h index f7dec3a95..97e8488b9 100644 --- a/include/mpc/module/Output.h +++ b/include/mpc/module/Output.h @@ -1,5 +1,5 @@ -#ifndef OUTPUT_H_ -#define OUTPUT_H_ +#ifndef MPC_OUTPUT_H_ +#define MPC_OUTPUT_H_ #include "mpc/Module.h" #include @@ -70,4 +70,4 @@ class EventOutput1D: public Module { } // namespace mpc -#endif /* OUTPUT_H_ */ +#endif // MPC_OUTPUT_H_ diff --git a/python/mpc.i b/python/mpc.i index b6899e742..46995ee38 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -25,6 +25,7 @@ #include "mpc/module/Observer.h" #include "mpc/module/Output.h" #include "mpc/module/OutputROOT.h" +#include "mpc/module/OutputCRPropa2.h" #include "mpc/module/SimplePropagation.h" #include "mpc/module/DeflectionCK.h" #include "mpc/module/Tools.h" @@ -83,6 +84,13 @@ %template(Vector3d) mpc::Vector3; %template(Vector3f) mpc::Vector3; +%pythoncode %{ +def Vector3__str__(self): + return "(%.4e, %.4e, %.4e)" % (self.x, self.y, self.z) +Vector3d.__str__ = Vector3__str__ +Vector3f.__str__ = Vector3__str__ +%} + %include "mpc/Referenced.h" %include "mpc/Units.h" @@ -131,6 +139,7 @@ %include "mpc/module/DeflectionCK.h" %include "mpc/module/Output.h" %include "mpc/module/OutputROOT.h" +#include "mpc/module/OutputCRPropa2.h" %include "mpc/module/ElectronPairProduction.h" %include "mpc/module/StochasticInteraction.h" %include "mpc/module/NuclearDecay.h" diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 804051360..8b49a9c4c 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -12,6 +12,7 @@ #include "mpc/module/Observer.h" #include "mpc/module/Output.h" #include "mpc/module/OutputROOT.h" +#include "mpc/module/OutputCRPropa2.h" #include "mpc/ModuleList.h" #include "pugixml.hpp" @@ -298,7 +299,8 @@ bool XmlExecute::load(const string &filename) { else if (type == "Spheres around Source") loadSpheresAroundSource(node); else - cout << " --> unknown observer" << endl; + cout << " --> unknown observer ('Spheres around Source' or " + << "'Spheres around Observer')" << endl; } } @@ -458,8 +460,11 @@ void XmlExecute::loadSpheresAroundSource(pugi::xml_node &node) { cout << " - Postion: " << pos / Mpc << " Mpc" << endl; double r = childValue(n, "Radius_Mpc") * Mpc; cout << " - Radius: " << r / Mpc << " Mpc" << endl; - modules.add(new LargeObserverSphere(pos, r, "Detected", "", false)); + modules.add(new LargeObserverSphere(pos, r, "Detected", "", true)); } + if (nObs > 1) + cout << " --> Warning! More than one observer currently not supported. " + << endl; } void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { @@ -596,7 +601,8 @@ void XmlExecute::loadSpectrumComposition(pugi::xml_node &node) { } void XmlExecute::loadSourceNuclei(pugi::xml_node &node) { - SourceMultipleParticleTypes *composition = new SourceMultipleParticleTypes(); + SourceMultipleParticleTypes *composition = + new SourceMultipleParticleTypes(); xml_node p = node.child("Particles"); for (xml_node n = p.child("Species"); n; n = n.next_sibling("Species")) { int A = n.attribute("MassNumber").as_int(); @@ -627,38 +633,41 @@ void XmlExecute::loadOutput(xml_node &node) { throw runtime_error("Output file already exists!"); } - if (format == "ASCII") - if (type == "Full Trajectories") - if (is1D) - modules.add(new TrajectoryOutput1D(filename)); - else - modules.add(new TrajectoryOutput(filename)); - else if (type == "Events") - if (is1D) - modules.add(new EventOutput1D(filename)); - else - modules.add(new ConditionalOutput(filename)); - else if (type == "None") - return; - else - cout << " --> unknown output" << endl; - else if (format == "ROOT") - if (type == "Full Trajectories") - if (is1D) - modules.add(new ROOTTrajectoryOutput1D(filename)); - else - modules.add(new ROOTTrajectoryOutput3D(filename)); - else if (type == "Events") - if (is1D) - modules.add(new ROOTEventOutput1D(filename)); - else - modules.add(new ROOTEventOutput3D(filename)); - else if (type == "None") - return; - else - cout << " --> unknown output" << endl; - else - cout << " --> unknown output format (should be 'ASCII' or 'ROOT')" << endl; + if (format == "ASCII") { + if (type == "Full Trajectories") + if (is1D) + modules.add(new CRPropa2TrajectoryOutput1D(filename)); + else + modules.add(new CRPropa2TrajectoryOutput3D(filename)); + else if (type == "Events") + if (is1D) + modules.add(new CRPropa2EventOutput1D(filename)); + else + modules.add(new CRPropa2EventOutput3D(filename)); + else if (type == "None") + return; + else + cout << " --> unknown output type " + << "('Events', 'Full Trajectories' or 'None')" << endl; + } else if (format == "ROOT") { + if (type == "Full Trajectories") + if (is1D) + modules.add(new ROOTTrajectoryOutput1D(filename)); + else + modules.add(new ROOTTrajectoryOutput3D(filename)); + else if (type == "Events") + if (is1D) + modules.add(new ROOTEventOutput1D(filename)); + else + modules.add(new ROOTEventOutput3D(filename)); + else if (type == "None") + return; + else + cout << " --> unknown output type " + << "('Events', 'Full Trajectories' or 'None')" << endl; + } else { + cout << " --> unknown output format " << "('ASCII' or 'ROOT')" << endl; + } } void XmlExecute::run() { diff --git a/src/module/Output.cpp b/src/module/Output.cpp index eb8b1aec9..1127e6d09 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -1,9 +1,6 @@ #include "mpc/module/Output.h" -#include #include -#include -#include #include namespace mpc { diff --git a/test/xml/CRPropa2EventOutput1D.xml b/test/xml/CRPropa2EventOutput1D.xml new file mode 100644 index 000000000..27fbd1b06 --- /dev/null +++ b/test/xml/CRPropa2EventOutput1D.xml @@ -0,0 +1,35 @@ + + + + + + + + output.txt + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/xml/CRPropa2EventOutput3D.xml b/test/xml/CRPropa2EventOutput3D.xml new file mode 100644 index 000000000..af86d7c31 --- /dev/null +++ b/test/xml/CRPropa2EventOutput3D.xml @@ -0,0 +1,58 @@ + + + + + + + + output.txt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/xml/CRPropa2TrajectoryOutput1D.xml b/test/xml/CRPropa2TrajectoryOutput1D.xml new file mode 100644 index 000000000..f764093bb --- /dev/null +++ b/test/xml/CRPropa2TrajectoryOutput1D.xml @@ -0,0 +1,35 @@ + + + + + + + + output.txt + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/xml/CRPropa2TrajectoryOutput3D.xml b/test/xml/CRPropa2TrajectoryOutput3D.xml new file mode 100644 index 000000000..ebed0fceb --- /dev/null +++ b/test/xml/CRPropa2TrajectoryOutput3D.xml @@ -0,0 +1,58 @@ + + + + + + + + output.txt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From a60375ca3a7274ba290ceb9913090021b0fd8e24 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 17 Jan 2013 16:47:53 +0100 Subject: [PATCH 0256/1298] moved PhotonField to separate file --- CMakeLists.txt | 1 + include/mpc/Common.h | 14 +++----------- include/mpc/XmlExecute.h | 6 +++--- include/mpc/module/ElectronPairProduction.h | 4 ++-- include/mpc/module/PhotoDisintegration.h | 8 ++++---- include/mpc/module/PhotoPionProduction.h | 4 ++-- python/mpc.i | 4 +++- src/Common.cpp | 12 ------------ src/XmlExecute.cpp | 3 +++ src/module/PhotoDisintegration.cpp | 1 + src/module/PhotoPionProduction.cpp | 1 + 11 files changed, 23 insertions(+), 35 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 95deb5d54..f658694cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,6 +98,7 @@ add_library(mpc SHARED src/ParticleState.cpp src/Source.cpp src/Common.cpp + src/PhotonBackground.cpp src/Nucleus.cpp src/GridTools.cpp src/XmlExecute.cpp diff --git a/include/mpc/Common.h b/include/mpc/Common.h index a782c0e1b..a11f48a84 100644 --- a/include/mpc/Common.h +++ b/include/mpc/Common.h @@ -1,19 +1,11 @@ -#ifndef COMMON_H_ -#define COMMON_H_ +#ifndef MPC_COMMON_H_ +#define MPC_COMMON_H_ #include #include namespace mpc { -// Photon fields -enum PhotonField { - CMB, IRB, CMB_IRB -}; - -// Returns overall photon field scaling factor at redshift z -double photonFieldScaling(int photonField, double z); - // Returns the full path to a mpc data file std::string getDataPath(std::string filename); @@ -34,4 +26,4 @@ double interpolateEquidistant(double x, double lo, double hi, } // namespace mpc -#endif /* COMMON_H_ */ +#endif // MPC_COMMON_H_ diff --git a/include/mpc/XmlExecute.h b/include/mpc/XmlExecute.h index 77bcb571d..94d03f900 100644 --- a/include/mpc/XmlExecute.h +++ b/include/mpc/XmlExecute.h @@ -1,5 +1,5 @@ -#ifndef MPC_XML_EXECUTE_H -#define MPC_XML_EXECUTE_H +#ifndef MPC_XMLEXECUTE_H_ +#define MPC_XMLEXECUTE_H_ #include "mpc/ModuleList.h" #include "mpc/Source.h" @@ -47,4 +47,4 @@ class XmlExecute { } // namespace mpc -#endif /* MPC_XML_EXECUTE_H */ +#endif // MPC_XMLEXECUTE_H_ diff --git a/include/mpc/module/ElectronPairProduction.h b/include/mpc/module/ElectronPairProduction.h index 739bdb5cd..66ef60da5 100644 --- a/include/mpc/module/ElectronPairProduction.h +++ b/include/mpc/module/ElectronPairProduction.h @@ -2,7 +2,7 @@ #define MPC_ELECTRONPAIRPRODUCTION_H_ #include "mpc/Module.h" -#include "mpc/Common.h" +#include "mpc/PhotonBackground.h" namespace mpc { @@ -36,4 +36,4 @@ class ElectronPairProduction: public Module { } // namespace mpc -#endif /* MPC_ELECTRONPAIRPRODUCTION_H_ */ +#endif // MPC_ELECTRONPAIRPRODUCTION_H_ diff --git a/include/mpc/module/PhotoDisintegration.h b/include/mpc/module/PhotoDisintegration.h index 348922f55..29a2898c9 100644 --- a/include/mpc/module/PhotoDisintegration.h +++ b/include/mpc/module/PhotoDisintegration.h @@ -1,8 +1,8 @@ -#ifndef PHOTODISINTEGRATION_H_ -#define PHOTODISINTEGRATION_H_ +#ifndef MPC_PHOTODISINTEGRATION_H_ +#define MPC_PHOTODISINTEGRATION_H_ #include "mpc/module/StochasticInteraction.h" -#include "mpc/Random.h" +#include "mpc/PhotonBackground.h" #include @@ -43,4 +43,4 @@ class PhotoDisintegration: public StochasticInteraction { } // namespace mpc -#endif /* PHOTODISINTEGRATION_H_ */ +#endif // MPC_PHOTODISINTEGRATION_H_ diff --git a/include/mpc/module/PhotoPionProduction.h b/include/mpc/module/PhotoPionProduction.h index d13ccd8c0..3ecd832d5 100644 --- a/include/mpc/module/PhotoPionProduction.h +++ b/include/mpc/module/PhotoPionProduction.h @@ -2,7 +2,7 @@ #define MPC_PHOTOPIONPRODUCTION_H_ #include "mpc/module/StochasticInteraction.h" -#include "mpc/Random.h" +#include "mpc/PhotonBackground.h" #include @@ -65,4 +65,4 @@ class SophiaPhotoPionProduction: public PhotoPionProduction { } // namespace mpc -#endif /* MPC_PHOTOPIONPRODUCTION_H_ */ +#endif // MPC_PHOTOPIONPRODUCTION_H_ diff --git a/python/mpc.i b/python/mpc.i index 46995ee38..04f570b0c 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -48,6 +48,7 @@ #include "mpc/Vector3.h" #include "mpc/Source.h" #include "mpc/Common.h" +#include "mpc/PhotonBackground.h" #include "mpc/Grid.h" #include "mpc/GridTools.h" %} @@ -96,6 +97,7 @@ Vector3f.__str__ = Vector3__str__ %include "mpc/Units.h" %include "mpc/Nucleus.h" %include "mpc/Common.h" +%include "mpc/PhotonBackground.h" %include "mpc/Random.h" %include "mpc/ParticleState.h" @@ -139,7 +141,7 @@ Vector3f.__str__ = Vector3__str__ %include "mpc/module/DeflectionCK.h" %include "mpc/module/Output.h" %include "mpc/module/OutputROOT.h" -#include "mpc/module/OutputCRPropa2.h" +%include "mpc/module/OutputCRPropa2.h" %include "mpc/module/ElectronPairProduction.h" %include "mpc/module/StochasticInteraction.h" %include "mpc/module/NuclearDecay.h" diff --git a/src/Common.cpp b/src/Common.cpp index 8b568bf69..008e089e3 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -11,18 +11,6 @@ namespace mpc { -// Overall redshift scaling of the Kneiske IRB (see data/PhotonField/KneiskeIRB.py and Kneiske et al. 2004, astro-ph/0309141) -double a[9] = { 0, 0.2, 0.4, 0.6, 1, 2, 3, 4, 5 }; -static std::vector zKneiske(a, a + sizeof(a) / sizeof(double)); -double b[9] = { 1, 1.6937, 2.5885, 3.6178, 5.1980, 7.3871, 8.5471, 7.8605, 0 }; -static std::vector sKneiske(b, b + sizeof(b) / sizeof(double)); - -double photonFieldScaling(int photonField, double z) { - if (photonField == IRB) - return interpolate(z, zKneiske, sKneiske); - return pow(z + 1, 3); // CMB-like scaling -} - std::string getDataPath(std::string filename) { static std::string dataPath; if (dataPath.size()) diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 8b49a9c4c..b481f977a 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -1,6 +1,8 @@ #include "mpc/XmlExecute.h" #include "mpc/magneticField/MagneticFieldGrid.h" #include "mpc/GridTools.h" +#include "mpc/PhotonBackground.h" +#include "mpc/Random.h" #include "mpc/module/SimplePropagation.h" #include "mpc/module/DeflectionCK.h" #include "mpc/module/ElectronPairProduction.h" @@ -20,6 +22,7 @@ #include #include #include +#include using namespace pugi; using namespace std; diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 74e4b44bf..c623a3d66 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -1,4 +1,5 @@ #include "mpc/module/PhotoDisintegration.h" +#include "mpc/Random.h" #include #include diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 2f7caaf12..1f7aa118f 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -1,4 +1,5 @@ #include "mpc/module/PhotoPionProduction.h" +#include "mpc/Random.h" #include #include "sophia.h" From a0cd3eb538ebc998fb8e85a7e6dfada9784243b4 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 17 Jan 2013 17:09:05 +0100 Subject: [PATCH 0257/1298] add missing file --- src/module/OutputCRPropa2.cpp | 150 ++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 src/module/OutputCRPropa2.cpp diff --git a/src/module/OutputCRPropa2.cpp b/src/module/OutputCRPropa2.cpp new file mode 100644 index 000000000..55c81cd97 --- /dev/null +++ b/src/module/OutputCRPropa2.cpp @@ -0,0 +1,150 @@ +#include "mpc/module/OutputCRPropa2.h" + +namespace mpc { + +CRPropa2EventOutput3D::CRPropa2EventOutput3D(std::string filename) { + setDescription("Event output in CRPropa2 format"); + outfile.open(filename.c_str()); + outfile << "#CRPropa - Output data file\n" + << "#Format - Particle_Type Initial_Particle_Type " + << "Initial_Position[X,Y,Z](Mpc) " + << "Initial_Momentum[E(EeV),theta,phi] " + << "Time(Mpc) Position[X,Y,Z](Mpc) Momentum[E(EeV),theta,phi]\n"; +} + +CRPropa2EventOutput3D::~CRPropa2EventOutput3D() { + outfile.close(); +} + +void CRPropa2EventOutput3D::process(Candidate *c) const { + if (not (c->hasProperty("Detected"))) + return; + + char buffer[256]; // max. 256 characters per line + size_t p = 0; // length of line + + p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->current.getId())); + p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->initial.getId())); + + const Vector3d &ipos = c->initial.getPosition() / Mpc; + p += sprintf(buffer + p, "%.4f %.4f %.4f ", ipos.x, ipos.y, ipos.z); + + double iPhi = c->initial.getDirection().getPhi(); + double iTheta = c->initial.getDirection().getTheta(); + double iE = c->initial.getEnergy() / EeV; + p += sprintf(buffer + p, "%.4f %.4f %.4f ", iE, iPhi, iTheta); + + double t = c->getTrajectoryLength() / Mpc; + p += sprintf(buffer + p, "%.4f ", t); + + const Vector3d &pos = c->current.getPosition() / Mpc; + p += sprintf(buffer + p, "%.4f %.4f %.4f ", pos.x, pos.y, pos.z); + + double phi = c->current.getDirection().getPhi(); + double theta = c->current.getDirection().getTheta(); + double E = c->current.getEnergy() / EeV; + p += sprintf(buffer + p, "%.4f %.4f %.4f\n", E, phi, theta); + +#pragma omp critical + { + outfile.write(buffer, p); + outfile.flush(); + } +} + +CRPropa2TrajectoryOutput3D::CRPropa2TrajectoryOutput3D(std::string filename) { + setDescription("Trajectory output in CRPropa2 format"); + outfile.open(filename.c_str()); + outfile << "#CRPropa - Output data file\n" + << "#Format - Particle_Type Initial_Particle_Type Time(Mpc) " + << "Position[X,Y,Z](Mpc) Momentum[X(EeV),Y,Z] Energy(EeV)\n"; +} + +CRPropa2TrajectoryOutput3D::~CRPropa2TrajectoryOutput3D() { + outfile.close(); +} + +void CRPropa2TrajectoryOutput3D::process(Candidate *c) const { + char buffer[256]; + size_t p = 0; + + p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->current.getId())); + p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->initial.getId())); + p += sprintf(buffer + p, "%.4f ", c->getTrajectoryLength() / Mpc); + + const Vector3d &pos = c->current.getPosition() / Mpc; + p += sprintf(buffer + p, "%.4f %.4f %.4f ", pos.x, pos.y, pos.z); + + const Vector3d &mom = c->current.getMomentum() / EeV; + p += sprintf(buffer + p, "%.4g %.4g %.4g ", mom.x, mom.y, mom.z); + + p += sprintf(buffer + p, "%.4f\n", c->current.getEnergy() / EeV); + +#pragma omp critical + { + outfile.write(buffer, p); + outfile.flush(); + } +} + +CRPropa2TrajectoryOutput1D::CRPropa2TrajectoryOutput1D(std::string filename) { + setDescription("Trajectory output"); + outfile.open(filename.c_str()); + outfile << "#CRPropa - Output data file\n" + << "#Format - Position(Mpc) Particle_Type Energy(EeV)\n"; +} + +CRPropa2TrajectoryOutput1D::~CRPropa2TrajectoryOutput1D() { + outfile.close(); +} + +void CRPropa2TrajectoryOutput1D::process(Candidate *c) const { + char buffer[256]; + size_t p = 0; + + p += sprintf(buffer + p, "%.4f ", c->current.getPosition().x / Mpc); + p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->current.getId())); + p += sprintf(buffer + p, "%.4f\n", c->current.getEnergy() / EeV); + +#pragma omp critical + { + outfile.write(buffer, p); + outfile.flush(); + } +} + +CRPropa2EventOutput1D::CRPropa2EventOutput1D(std::string filename) { + setDescription("Conditional output, Filename: " + filename); + outfile.open(filename.c_str()); + outfile << "#CRPropa - Output data file\n" + << "#Format - Energy(EeV) Time(Mpc) Initial_Particle_Type " + << "Initial_Energy(EeV)\n"; +} + +CRPropa2EventOutput1D::~CRPropa2EventOutput1D() { + outfile.close(); +} + +void CRPropa2EventOutput1D::process(Candidate *c) const { + if (c->isActive()) + return; + if (not (c->hasProperty("Detected"))) + return; + + char buffer[256]; + size_t p = 0; + + p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->current.getId())); + p += sprintf(buffer + p, "%.4f ", c->current.getEnergy() / EeV); + p += sprintf(buffer + p, "%.4f ", c->getTrajectoryLength() / Mpc); + p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->initial.getId())); + p += sprintf(buffer + p, "%.4f\n", c->initial.getEnergy() / EeV); + +#pragma omp critical + { + outfile.write(buffer, p); + outfile.flush(); + } +} + +} // namespace mpc From af8fd177bf29e19ffbedeee6f46a62eb03f3636f Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 17 Jan 2013 17:10:53 +0100 Subject: [PATCH 0258/1298] add missing files --- include/mpc/PhotonBackground.h | 16 ++++++++ include/mpc/module/OutputCRPropa2.h | 59 +++++++++++++++++++++++++++++ src/PhotonBackground.cpp | 21 ++++++++++ 3 files changed, 96 insertions(+) create mode 100644 include/mpc/PhotonBackground.h create mode 100644 include/mpc/module/OutputCRPropa2.h create mode 100644 src/PhotonBackground.cpp diff --git a/include/mpc/PhotonBackground.h b/include/mpc/PhotonBackground.h new file mode 100644 index 000000000..1df8be5fc --- /dev/null +++ b/include/mpc/PhotonBackground.h @@ -0,0 +1,16 @@ +#ifndef MPC_PHOTONBACKGROUND_H_ +#define MPC_PHOTONBACKGROUND_H_ + +namespace mpc { + +// Photon fields +enum PhotonField { + CMB, IRB, CMB_IRB +}; + +// Returns overall photon field scaling factor at redshift z +double photonFieldScaling(int photonField, double z); + +} // namespace mpc + +#endif // MPC_PHOTONBACKGROUND_H_ diff --git a/include/mpc/module/OutputCRPropa2.h b/include/mpc/module/OutputCRPropa2.h new file mode 100644 index 000000000..d0044f40c --- /dev/null +++ b/include/mpc/module/OutputCRPropa2.h @@ -0,0 +1,59 @@ +#ifndef MPC_OUTPUTCRPROPA2_H_ +#define MPC_OUTPUTCRPROPA2_H_ + +#include "mpc/Module.h" +#include + +namespace mpc { + +/** + @class CRPropa2EventOutput3D + @brief Saves events to a plain text file in CRPropa2 format. + */ +class CRPropa2EventOutput3D: public Module { + mutable std::ofstream outfile; +public: + CRPropa2EventOutput3D(std::string filename); + ~CRPropa2EventOutput3D(); + void process(Candidate *candidate) const; +}; + +/** + @class CRPropa2TrajectoryOutput3D + @brief Saves trajectories to a plain text file in CRPropa2 format. + */ +class CRPropa2TrajectoryOutput3D: public Module { + mutable std::ofstream outfile; +public: + CRPropa2TrajectoryOutput3D(std::string filename); + ~CRPropa2TrajectoryOutput3D(); + void process(Candidate *candidate) const; +}; + +/** + @class CRPropa2EventOutput1D + @brief Saves 1D events to a plain text file in CRPropa2 format. + */ +class CRPropa2EventOutput1D: public Module { + mutable std::ofstream outfile; +public: + CRPropa2EventOutput1D(std::string filename); + ~CRPropa2EventOutput1D(); + void process(Candidate *candidate) const; +}; + +/** + @class CRPropa2TrajectoryOutput1D + @brief Saves 1D trajectories to a plain text file in CRPropa2 format. + */ +class CRPropa2TrajectoryOutput1D: public Module { + mutable std::ofstream outfile; +public: + CRPropa2TrajectoryOutput1D(std::string filename); + ~CRPropa2TrajectoryOutput1D(); + void process(Candidate *candidate) const; +}; + +} // namespace mpc + +#endif // MPC_OUTPUTCRPROPA2_H_ diff --git a/src/PhotonBackground.cpp b/src/PhotonBackground.cpp new file mode 100644 index 000000000..010c58efb --- /dev/null +++ b/src/PhotonBackground.cpp @@ -0,0 +1,21 @@ +#include "mpc/PhotonBackground.h" +#include "mpc/Common.h" + +#include +#include + +namespace mpc { + +// Overall redshift scaling of the Kneiske IRB (see data/PhotonField/KneiskeIRB.py and Kneiske et al. 2004, astro-ph/0309141) +double a[9] = { 0, 0.2, 0.4, 0.6, 1, 2, 3, 4, 5 }; +static std::vector zKneiske(a, a + sizeof(a) / sizeof(double)); +double b[9] = { 1, 1.6937, 2.5885, 3.6178, 5.1980, 7.3871, 8.5471, 7.8605, 0 }; +static std::vector sKneiske(b, b + sizeof(b) / sizeof(double)); + +double photonFieldScaling(int photonField, double z) { + if (photonField == IRB) + return interpolate(z, zKneiske, sKneiske); + return pow(z + 1, 3); // CMB-like scaling +} + +} // namespace mpc From 156110791564f8ca05aa934ff95bf1ae5bb0acf0 Mon Sep 17 00:00:00 2001 From: kuempel Date: Mon, 21 Jan 2013 23:55:07 +0100 Subject: [PATCH 0259/1298] Prevent problem with xml ROOT output if ROOT is not set --- src/XmlExecute.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index b481f977a..7e9e3cc28 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -652,7 +652,9 @@ void XmlExecute::loadOutput(xml_node &node) { else cout << " --> unknown output type " << "('Events', 'Full Trajectories' or 'None')" << endl; - } else if (format == "ROOT") { + } +#ifdef MPC_HAVE_ROOT + else if (format == "ROOT") { if (type == "Full Trajectories") if (is1D) modules.add(new ROOTTrajectoryOutput1D(filename)); @@ -668,8 +670,10 @@ void XmlExecute::loadOutput(xml_node &node) { else cout << " --> unknown output type " << "('Events', 'Full Trajectories' or 'None')" << endl; - } else { - cout << " --> unknown output format " << "('ASCII' or 'ROOT')" << endl; + } +#endif // MPC_HAVE_ROOT + else { + cout << " --> unknown output format. " << " Use 'ASCII' or 'ROOT' (if ROOT is set)" << endl; } } From 8a7f006cf437d9c1c6c6b7e11610686a133fb1ff Mon Sep 17 00:00:00 2001 From: kuempel Date: Tue, 22 Jan 2013 13:00:37 +0100 Subject: [PATCH 0260/1298] Making ROOT output threadsave --- include/mpc/module/OutputROOT.h | 2 ++ src/module/OutputROOT.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/include/mpc/module/OutputROOT.h b/include/mpc/module/OutputROOT.h index 00b98adf1..5b1feeba2 100644 --- a/include/mpc/module/OutputROOT.h +++ b/include/mpc/module/OutputROOT.h @@ -6,6 +6,8 @@ #ifdef MPC_HAVE_ROOT #include #include +#include + namespace mpc { diff --git a/src/module/OutputROOT.cpp b/src/module/OutputROOT.cpp index 2077a0f78..fe8830533 100644 --- a/src/module/OutputROOT.cpp +++ b/src/module/OutputROOT.cpp @@ -6,22 +6,27 @@ namespace mpc { /////////////////////// ROOT EVENT OUTPUT 1D ////////////////////////////////// ROOTEventOutput1D::ROOTEventOutput1D(std::string filename) { + TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); Ntuple = new TNtuple("events", "CRPropa 1D events", "Particle_Type:Initial_Type:Initial_Position_Mpc:Inital_Redshift:Initial_Energy_EeV:Time_Mpc:Energy_EeV"); + TThread::UnLock(); } ROOTEventOutput1D::~ROOTEventOutput1D() { + TThread::Lock(); ROOTFile->Write(); ROOTFile->Close(); + TThread::UnLock(); } void ROOTEventOutput1D::process(Candidate *c) const { if (c->isActive()) return; if (c->hasProperty("Detected")) { + TThread::Lock(); #pragma omp critical { Ntuple->Fill(c->current.getId(), c->initial.getId(), @@ -30,25 +35,31 @@ void ROOTEventOutput1D::process(Candidate *c) const { c->getTrajectoryLength() / Mpc, c->current.getEnergy() / EeV); } + TThread::UnLock(); } } //////////////////////////////////////////////////////////////////////////////// /////////////////////// ROOT TRAJECTORY OUTPUT 1D ////////////////////////////// ROOTTrajectoryOutput1D::ROOTTrajectoryOutput1D(std::string filename) { + TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); // Ntuple = new TNtuple("traj","CRPropa 1D trajectories","Particle_Type:Initial_Type:Time_Mpc:Position_Mpc:Energy_EeV"); Ntuple = new TNtuple("traj", "CRPropa 1D trajectories", "Particle_Type:Initial_Type:Time_Mpc:Position_Mpc:Energy_EeV"); + TThread::UnLock(); } ROOTTrajectoryOutput1D::~ROOTTrajectoryOutput1D() { + TThread::Lock(); ROOTFile->Write(); ROOTFile->Close(); + TThread::UnLock(); } void ROOTTrajectoryOutput1D::process(Candidate *c) const { + TThread::Lock(); #pragma omp critical { Ntuple->Fill(c->current.getId(), c->initial.getId(), @@ -56,25 +67,31 @@ void ROOTTrajectoryOutput1D::process(Candidate *c) const { c->current.getPosition().getX() / Mpc, c->current.getEnergy() / EeV); } + TThread::UnLock(); } //////////////////////////////////////////////////////////////////////////////// /////////////////////// ROOT EVENT OUTPUT 3D ////////////////////////////////// ROOTEventOutput3D::ROOTEventOutput3D(std::string filename) { + TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); Ntuple = new TNtuple("events", "CRPropa 3D events", "Particle_Type:Initial_Type:Initial_Position_X_Mpc:Initial_Position_Y_Mpc:Initial_Position_Z_Mpc:Initial_Momentum_E_EeV:Initial_Momentum_theta:Initial_Momentum_phi:Time_Mpc:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Momentum_E_EeV:Momentum_theta:Momentum_phi"); + TThread::UnLock(); } ROOTEventOutput3D::~ROOTEventOutput3D() { + TThread::Lock(); ROOTFile->Write(); ROOTFile->Close(); + TThread::UnLock(); } void ROOTEventOutput3D::process(Candidate *c) const { if (c->hasProperty("Detected")) { + TThread::Lock(); #pragma omp critical { Ntuple->Fill(c->current.getId(), c->initial.getId(), @@ -92,25 +109,31 @@ void ROOTEventOutput3D::process(Candidate *c) const { c->current.getDirection().getTheta(), c->current.getDirection().getPhi()); } + TThread::UnLock(); } } //////////////////////////////////////////////////////////////////////////////// /////////////////////// ROOT TRAJECTORY OUTPUT 3D ////////////////////////////// ROOTTrajectoryOutput3D::ROOTTrajectoryOutput3D(std::string filename) { + TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); Ntuple = new TNtuple("traj", "CRPropa 3D trajectories", "Particle_Type:Initial_Type:Time_Mpc:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Direction_X:Direction_Y:Direction_Z:Energy_EeV"); + TThread::UnLock(); } ROOTTrajectoryOutput3D::~ROOTTrajectoryOutput3D() { + TThread::Lock(); ROOTFile->Write(); ROOTFile->Close(); + TThread::UnLock(); } void ROOTTrajectoryOutput3D::process(Candidate *c) const { + TThread::Lock(); #pragma omp critical { Ntuple->Fill(c->current.getId(), c->initial.getId(), @@ -122,6 +145,7 @@ void ROOTTrajectoryOutput3D::process(Candidate *c) const { c->current.getDirection().getY(), c->current.getDirection().getZ(), c->current.getEnergy() / EeV); } + TThread::UnLock(); } //////////////////////////////////////////////////////////////////////////////// From 713ad1ba63ee027c23b5a5d69eaaf970f6da7832 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 22 Jan 2013 14:34:08 +0100 Subject: [PATCH 0261/1298] fix DeflectionCK for backtracking add documentation for the ParticleState --- include/mpc/Candidate.h | 7 +++++-- include/mpc/ParticleState.h | 31 ++++++++++++++++++++++--------- src/ParticleState.cpp | 11 ++++++----- src/module/DeflectionCK.cpp | 3 +-- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/include/mpc/Candidate.h b/include/mpc/Candidate.h index 7e3a5227c..eb723374a 100644 --- a/include/mpc/Candidate.h +++ b/include/mpc/Candidate.h @@ -32,7 +32,10 @@ struct InteractionState { @class Candidate @brief All information about the cosmic ray. - The Candidate is a passive object, that holds all information about the initial and current state of the cosmic ray and the status of propagation. + The Candidate is a passive object, that holds the information about the state + of the cosmic ray at the beginning of propagation and in the current and + previous propagation step. + It holds status information about the cosmic ray and the simulation itself. */ class Candidate: public Referenced { public: @@ -53,7 +56,7 @@ class Candidate: public Referenced { double nextStep; /**< Proposed size of the next propagation step in [m] comoving units */ PropertyMap properties; /**< Map of property names and their values. */ - InteractionStatesMap interactionStates; /**< Map of physical interactions that are scheduled to happen to the candidate. */ + InteractionStatesMap interactionStates; /**< Map of interactions that are scheduled to happen to the candidate. */ public: Candidate(); diff --git a/include/mpc/ParticleState.h b/include/mpc/ParticleState.h index c2eed26b4..9ca1b2291 100644 --- a/include/mpc/ParticleState.h +++ b/include/mpc/ParticleState.h @@ -11,46 +11,59 @@ namespace mpc { /** @class ParticleState @brief State of the particle: ID, energy, position, direction + + The ParticleState defines the state of an ultra-high energy cosmic ray, which + is assumed to be flying at the exact speed of light. The cosmic ray state is + uniquely defined by particle ID, energy and position and direction vector. + For faster lookup mass and charge of the particle are stored as members. */ class ParticleState { private: - int id; - double energy; - Vector3d position; - Vector3d direction; + int id; /*< particle ID (Particle Data Group numbering scheme) */ + double energy; /*< total energy */ + Vector3d position; /*< position vector in comoving coordinates */ + Vector3d direction; /*< unit vector of velocity or momentum */ double pmass; double charge; public: ParticleState(); + /* Set position in comoving coordinates */ void setPosition(const Vector3d &pos); + /* Get position in comoving coordinates */ const Vector3d &getPosition() const; + /* Set direction unit vector. Non unit-vectors are normalized */ void setDirection(const Vector3d &dir); const Vector3d &getDirection() const; - void setEnergy(const double newEnergy); + void setEnergy(double newEnergy); double getEnergy() const; - void setId(const int); + void setId(int); int getId() const; - // convenience functions double getCharge() const; double getMass() const; - void setLorentzFactor(const double gamma); + /* Set Lorentz factor, which modifies the particles energy */ + void setLorentzFactor(double gamma); double getLorentzFactor() const; + /* Velocity: direction times the speed of light */ Vector3d getVelocity() const; + /* Momentum: direction times energy divided by the speed of light */ Vector3d getMomentum() const; + /* Check if the particle is a (anti-)nucleus */ bool isNucleus() const; + /* If nucleus, return the charge number Z (apositive for anti-nuclei) */ int getChargeNumber() const; + /* If nucleus, return the mass number A (also positive for anti-nuclei) */ int getMassNumber() const; }; } // namespace mpc -#endif /* MPC_PARTICLE_STATE_H_ */ +#endif // MPC_PARTICLE_STATE_H_ diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index 5188498c5..c2ea88b01 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -26,7 +26,7 @@ const Vector3d &ParticleState::getDirection() const { return direction; } -void ParticleState::setEnergy(const double newEnergy) { +void ParticleState::setEnergy(double newEnergy) { energy = newEnergy; } @@ -34,15 +34,16 @@ double ParticleState::getEnergy() const { return energy; } -void ParticleState::setId(const int newId) { +void ParticleState::setId(int newId) { id = newId; if (HepPID::isNucleus(id)) { pmass = nucleusMass(id); - charge = HepPID::Z(id) * eplus; + charge = HepPID::Z(id) * eplus; // HepPID::charge doesn't work for nuclei if (id < 0) charge *= -1; // HepPID::Z returns positive charge numbers for anti-nuclei - } else + } else { charge = HepPID::charge(id) * eplus; + } } int ParticleState::getId() const { @@ -77,7 +78,7 @@ double ParticleState::getLorentzFactor() const { "mpc::ParticleState::getLorentzFactor only for nuclei/nucleons"); } -void ParticleState::setLorentzFactor(const double gamma) { +void ParticleState::setLorentzFactor(double gamma) { if (HepPID::isNucleus(id)) energy = gamma * pmass * c_squared; else diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index fc71b1210..1de97ae2b 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -30,8 +30,7 @@ class LorentzForce: public ExplicitRungeKutta::F { << std::endl; std::cerr << e.what() << std::endl; } - Vector3d force = (double) particle->getChargeNumber() * eplus - * velocity.cross(B); + Vector3d force = (double) particle->getCharge() * velocity.cross(B); return PhasePoint(velocity, force); } }; From 20a2d1c07086605b3eaeec037c690f34acd9e753 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 22 Jan 2013 16:01:12 +0100 Subject: [PATCH 0262/1298] added fix (ptrdiff_t does not name a type) for combindation of SWIG < 2.0.5 and GCC > 4.6 --- python/mpc.i | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/python/mpc.i b/python/mpc.i index 04f570b0c..6caf440ce 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -1,5 +1,11 @@ %module(directors="1") mpc +%{ +// workaround for swig +#include +using std::ptrdiff_t; +%} + %include stl.i %include std_set.i %include std_multiset.i @@ -51,6 +57,7 @@ #include "mpc/PhotonBackground.h" #include "mpc/Grid.h" #include "mpc/GridTools.h" + %} From f58d2db0566d7dc778d15956358d901d7d1f3d40 Mon Sep 17 00:00:00 2001 From: kuempel Date: Thu, 24 Jan 2013 18:21:19 +0100 Subject: [PATCH 0263/1298] Fix wrong sign in spectral index when using xml-steering --- src/XmlExecute.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 7e9e3cc28..b98059030 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -572,8 +572,7 @@ void XmlExecute::loadSpectrumComposition(pugi::xml_node &node) { cout << " - Maximum rigidity: " << Rmax / EeV << " EeV" << endl; // combined source spectrum / composition - SourceComposition *composition = new SourceComposition(Emin, Rmax, - alpha); + SourceComposition *composition = new SourceComposition(Emin, Rmax, -alpha); xml_node p = node.child("Particles"); for (xml_node n = p.child("Species"); n; n = n.next_sibling("Species")) { @@ -590,7 +589,7 @@ void XmlExecute::loadSpectrumComposition(pugi::xml_node &node) { cout << " - Maximum energy: " << Emax / EeV << " EeV" << endl; // source spectrum - source.addProperty(new SourcePowerLawSpectrum(Emin, Emax, alpha)); + source.addProperty(new SourcePowerLawSpectrum(Emin, Emax, -alpha)); // source composition loadSourceNuclei(node); From 2cfe7a0eb136f0b623805f353d7d2ca21b093d1a Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 25 Jan 2013 11:10:12 +0100 Subject: [PATCH 0264/1298] include check for SOPHIA's energy threshold --- include/mpc/Candidate.h | 7 +- include/mpc/module/PhotoPionProduction.h | 2 +- src/Candidate.cpp | 19 +- src/module/PhotoPionProduction.cpp | 61 +- test/testInteraction.cpp | 1050 +++++++++++----------- 5 files changed, 595 insertions(+), 544 deletions(-) diff --git a/include/mpc/Candidate.h b/include/mpc/Candidate.h index eb723374a..6eebc5184 100644 --- a/include/mpc/Candidate.h +++ b/include/mpc/Candidate.h @@ -86,11 +86,12 @@ class Candidate: public Referenced { bool getProperty(const std::string &name, std::string &value) const; bool hasProperty(const std::string &name) const; - bool getInteractionState(const std::string &moduleName, + bool getInteractionState(const std::string &name, InteractionState &state) const; - void setInteractionState(const std::string &moduleName, + void setInteractionState(const std::string &name, const InteractionState &state); const InteractionStatesMap getInteractionStates() const; + void removeInteractionState(const std::string &name); void clearInteractionStates(); void addSecondary(int id, double energy); @@ -99,4 +100,4 @@ class Candidate: public Referenced { } // namespace mpc -#endif /* MPC_CANDIDATE_H_ */ +#endif // MPC_CANDIDATE_H_ diff --git a/include/mpc/module/PhotoPionProduction.h b/include/mpc/module/PhotoPionProduction.h index 3ecd832d5..28bd5230e 100644 --- a/include/mpc/module/PhotoPionProduction.h +++ b/include/mpc/module/PhotoPionProduction.h @@ -32,7 +32,7 @@ class PhotoPionProduction: public StochasticInteraction { void performInteraction(Candidate *candidate) const; /** - Calculates the energy loss length 1/E dE/dx in [m] + Calculates the energy loss length 1/E dE/dx in [m]. This is not used in the simulation. @param id PDG particle id @param energy particle energy [J] */ diff --git a/src/Candidate.cpp b/src/Candidate.cpp index 358ab3717..bade50c3f 100644 --- a/src/Candidate.cpp +++ b/src/Candidate.cpp @@ -57,22 +57,29 @@ void Candidate::limitNextStep(double step) { nextStep = std::min(nextStep, step); } -bool Candidate::getInteractionState(const std::string &moduleName, +bool Candidate::getInteractionState(const std::string &name, InteractionState &state) const { - InteractionStatesMap::const_iterator i = interactionStates.find(moduleName); + InteractionStatesMap::const_iterator i = interactionStates.find(name); if (i == interactionStates.end()) return false; state = i->second; return true; } -void Candidate::setInteractionState(const std::string &moduleName, +const Candidate::InteractionStatesMap Candidate::getInteractionStates() const { + return interactionStates; +} + +void Candidate::setInteractionState(const std::string &name, const InteractionState &state) { - interactionStates[moduleName] = state; + interactionStates[name] = state; } -const Candidate::InteractionStatesMap Candidate::getInteractionStates() const { - return interactionStates; +void Candidate::removeInteractionState(const std::string &name) { + InteractionStatesMap::iterator i = interactionStates.find(name); + if (i == interactionStates.end()) + return; + interactionStates.erase(i); } void Candidate::clearInteractionStates() { diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 1f7aa118f..75b7d7ad5 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -26,12 +26,10 @@ void PhotoPionProduction::init() { if (photonField == CMB) { init(getDataPath("photopion_CMB.txt")); setDescription("PhotoPionProduction: CMB"); - } - else if (photonField == IRB) { + } else if (photonField == IRB) { init(getDataPath("photopion_IRB.txt")); setDescription("PhotoPionProduction: IRB"); - } - else + } else throw std::runtime_error( "PhotoPionProduction: unknown photon background"); } @@ -52,7 +50,7 @@ void PhotoPionProduction::init(std::string filename) { nRate.push_back(c / Mpc); } } - infile.ignore(std::numeric_limits::max(), '\n'); + infile.ignore(std::numeric_limits < std::streamsize > ::max(), '\n'); } infile.close(); @@ -60,7 +58,7 @@ void PhotoPionProduction::init(std::string filename) { bool PhotoPionProduction::setNextInteraction(Candidate *candidate, InteractionState &interaction) const { - if (not(candidate->current.isNucleus())) + if (not (candidate->current.isNucleus())) return false; // accept only nuclei double z = candidate->getRedshift(); @@ -160,26 +158,27 @@ double PhotoPionProduction::energyLossLength(int id, double E) { if ((EpA < energy.front()) or (EpA > energy.back())) return std::numeric_limits::max(); - double lossRate = 0; - double relativeEnergyLoss = 1. / double(A); + // protons / neutrons keep as energy the fraction of mass to delta-resonance mass (crude approximation) + // nuclei approximately lose the energy that the interacting nucleon is carrying + double relativeEnergyLoss = (A == 1) ? 1 - 938. / 1232. : 1. / A; + double lossRate = 0; if (Z > 0) { double rate = interpolate(EpA, energy, pRate); if (A > 1) if (A < 8) rate *= 0.85 * pow(Z, 2. / 3.); - if (A >= 8) - rate *= 0.85 * Z; + if (A >= 8) + rate *= 0.85 * Z; lossRate += relativeEnergyLoss * rate; } - if (N > 0) { double rate = interpolate(EpA, energy, nRate); if (A > 1) if (A < 8) rate *= 0.85 * pow(N, 2. / 3.); - if (A >= 8) - rate *= 0.85 * N; + if (A >= 8) + rate *= 0.85 * N; lossRate += relativeEnergyLoss * rate; } @@ -205,37 +204,37 @@ void SophiaPhotoPionProduction::setHaveAntiNucleons(bool b) { } void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { + double E = candidate->current.getEnergy(); + int A = candidate->current.getMassNumber(); + int Z = candidate->current.getChargeNumber(); + double EpA = E / A; + double redshift = candidate->getRedshift(); + + // check if energy, shifted by *(1+z), is still above SOPHIA's threshold + // if below the threshold, remove interaction state and return + double Eth = (photonField == CMB) ? 3.75 * EeV : 0.01 * EeV; + if (EpA * (1 + redshift) < Eth) { + candidate->removeInteractionState(getDescription()); + return; + } + + // else continue InteractionState interaction; candidate->getInteractionState(getDescription(), interaction); candidate->clearInteractionStates(); int channel = interaction.channel; // 1 for interaction proton, 0 for neutron - double E = candidate->current.getEnergy(); - int A = candidate->current.getMassNumber(); - int Z = candidate->current.getChargeNumber(); - double EpA = E / A; - // arguments for sophia int nature = 1 - channel; // interacting particle: 0 for proton, 1 for neutron double Ein = EpA / GeV; // energy of in-going nucleon in GeV double momentaList[5][2000]; // momentum list, what are the five components? int particleList[2000]; // particle id list int nParticles; // number of outgoing particles - double redshift = candidate->getRedshift(); - - int background; // Photon background: 1 for CMB, 2 for Kneiske IRB - if (photonField == CMB) - background = 1; - else if (photonField == IRB) - background = 2; - else - throw std::runtime_error( - "SophiaPhotoPionProduction: Only CMB an IRB provided"); - double maxRedshift = 100; // IR photon density is zero above this redshift - int dummy1; - double dummy2[2]; + int dummy1; // unneeded + double dummy2[2]; // unneeded + int background = (photonField == CMB) ? 1 : 2; // photon background: 1 for CMB, 2 for Kneiske IRB #pragma omp critical { diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 1e1131973..e72d10583 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -10,522 +10,566 @@ namespace mpc { -TEST(ElectronPairProduction, EnergyDecreasing) { - // Test if energy loss occurs for protons with energies from 1e15 - 1e23 eV - Candidate c; - c.setCurrentStep(1 * Mpc); - c.current.setId(nucleusId(1, 1)); // proton - - ElectronPairProduction epp1(CMB); - for (int i = 0; i < 80; i++) { - double E = pow(10, 15 + i * 0.1) * eV; - c.current.setEnergy(E); - epp1.process(&c); - EXPECT_TRUE(c.current.getEnergy() <= E); - } - - ElectronPairProduction epp2(IRB); - for (int i = 0; i < 80; i++) { - double E = pow(10, 15 + i * 0.1) * eV; - c.current.setEnergy(E); - epp2.process(&c); - EXPECT_TRUE(c.current.getEnergy() < E); - } - - ElectronPairProduction epp3(CMB_IRB); - for (int i = 0; i < 80; i++) { - double E = pow(10, 15 + i * 0.1) * eV; - c.current.setEnergy(E); - epp3.process(&c); - EXPECT_TRUE(c.current.getEnergy() < E); - } -} - -TEST(ElectronPairProduction, BelowEnergyTreshold) { - // Test if nothing happens below 1e15 eV - ElectronPairProduction epp(CMB); - Candidate c; - c.current.setId(nucleusId(1, 1)); // proton - double E = 1e14 * eV; - c.current.setEnergy(E); - epp.process(&c); - EXPECT_DOUBLE_EQ(c.current.getEnergy(), E); -} - -TEST(ElectronPairProduction, NoNucleus) { - // Test if non-nuclei are skipped - ElectronPairProduction epp(CMB); - Candidate c; - c.current.setId(11); // electron - double E = 1e20 * eV; - c.current.setEnergy(E); - epp.process(&c); - EXPECT_DOUBLE_EQ(c.current.getEnergy(), E); -} - -TEST(ElectronPairProduction, valuesCMB) { - // Test if energy loss corresponds to the data table. - std::vector x; - std::vector y; - std::ifstream infile(getDataPath("epair_CMB.txt").c_str()); - while (infile.good()) { - if (infile.peek() != '#') { - double a, b; - infile >> a >> b; - if (infile) { - x.push_back(a * eV); - y.push_back(b * eV / Mpc); - } - } - infile.ignore(std::numeric_limits::max(), '\n'); - } - infile.close(); - - Candidate c; - c.setCurrentStep(1 * Mpc); - c.current.setId(nucleusId(1, 1)); // proton - - ElectronPairProduction epp(CMB); - for (int i = 0; i < x.size(); i++) { - c.current.setEnergy(x[i]); - epp.process(&c); - double dE = x[i] - c.current.getEnergy(); - double dE_table = y[i] * 1 * Mpc; - EXPECT_NEAR(dE, dE_table, 1e-12); - } -} - -TEST(ElectronPairProduction, valuesIRB) { - // Test if energy loss corresponds to the data table. - std::vector x; - std::vector y; - std::ifstream infile(getDataPath("epairIRB.txt").c_str()); - while (infile.good()) { - if (infile.peek() != '#') { - double a, b; - infile >> a >> b; - if (infile) { - x.push_back(a * eV); - y.push_back(b * eV / Mpc); - } - } - infile.ignore(std::numeric_limits::max(), '\n'); - } - infile.close(); - - Candidate c; - c.setCurrentStep(1 * Mpc); - c.current.setId(nucleusId(1, 1)); // proton - - ElectronPairProduction epp(IRB); - for (int i = 0; i < x.size(); i++) { - c.current.setEnergy(x[i]); - epp.process(&c); - double dE = x[i] - c.current.getEnergy(); - double dE_table = y[i] * 1 * Mpc; - EXPECT_NEAR(dE, dE_table, 1e-12); - } -} - -TEST(ElectronPairProduction, valuesCMB_IRB) { - // Test if energy loss corresponds to the data table. - std::vector x; - std::vector y; - std::ifstream infile(getDataPath("epair_CMB_IRB.txt").c_str()); - while (infile.good()) { - if (infile.peek() != '#') { - double a, b; - infile >> a >> b; - if (infile) { - x.push_back(a * eV); - y.push_back(b * eV / Mpc); - } - } - infile.ignore(std::numeric_limits::max(), '\n'); - } - infile.close(); - - Candidate c; - c.setCurrentStep(1 * Mpc); - c.current.setId(nucleusId(1, 1)); // proton - - ElectronPairProduction epp(CMB_IRB); - for (int i = 0; i < x.size(); i++) { - c.current.setEnergy(x[i]); - epp.process(&c); - double dE = x[i] - c.current.getEnergy(); - double dE_table = y[i] * 1 * Mpc; - EXPECT_NEAR(dE, dE_table, 1e-12); - } -} +//TEST(ElectronPairProduction, EnergyDecreasing) { +// // Test if energy loss occurs for protons with energies from 1e15 - 1e23 eV +// Candidate c; +// c.setCurrentStep(1 * Mpc); +// c.current.setId(nucleusId(1, 1)); // proton +// +// ElectronPairProduction epp1(CMB); +// for (int i = 0; i < 80; i++) { +// double E = pow(10, 15 + i * 0.1) * eV; +// c.current.setEnergy(E); +// epp1.process(&c); +// EXPECT_TRUE(c.current.getEnergy() <= E); +// } +// +// ElectronPairProduction epp2(IRB); +// for (int i = 0; i < 80; i++) { +// double E = pow(10, 15 + i * 0.1) * eV; +// c.current.setEnergy(E); +// epp2.process(&c); +// EXPECT_TRUE(c.current.getEnergy() < E); +// } +// +// ElectronPairProduction epp3(CMB_IRB); +// for (int i = 0; i < 80; i++) { +// double E = pow(10, 15 + i * 0.1) * eV; +// c.current.setEnergy(E); +// epp3.process(&c); +// EXPECT_TRUE(c.current.getEnergy() < E); +// } +//} + +//TEST(ElectronPairProduction, BelowEnergyTreshold) { +// // Test if nothing happens below 1e15 eV +// ElectronPairProduction epp(CMB); +// Candidate c; +// c.current.setId(nucleusId(1, 1)); // proton +// double E = 1e14 * eV; +// c.current.setEnergy(E); +// epp.process(&c); +// EXPECT_DOUBLE_EQ(c.current.getEnergy(), E); +//} +// +//TEST(ElectronPairProduction, NoNucleus) { +// // Test if non-nuclei are skipped +// ElectronPairProduction epp(CMB); +// Candidate c; +// c.current.setId(11); // electron +// double E = 1e20 * eV; +// c.current.setEnergy(E); +// epp.process(&c); +// EXPECT_DOUBLE_EQ(c.current.getEnergy(), E); +//} +// +//TEST(ElectronPairProduction, valuesCMB) { +// // Test if energy loss corresponds to the data table. +// std::vector x; +// std::vector y; +// std::ifstream infile(getDataPath("epair_CMB.txt").c_str()); +// while (infile.good()) { +// if (infile.peek() != '#') { +// double a, b; +// infile >> a >> b; +// if (infile) { +// x.push_back(a * eV); +// y.push_back(b * eV / Mpc); +// } +// } +// infile.ignore(std::numeric_limits::max(), '\n'); +// } +// infile.close(); +// +// Candidate c; +// c.setCurrentStep(1 * Mpc); +// c.current.setId(nucleusId(1, 1)); // proton +// +// ElectronPairProduction epp(CMB); +// for (int i = 0; i < x.size(); i++) { +// c.current.setEnergy(x[i]); +// epp.process(&c); +// double dE = x[i] - c.current.getEnergy(); +// double dE_table = y[i] * 1 * Mpc; +// EXPECT_NEAR(dE, dE_table, 1e-12); +// } +//} +// +//TEST(ElectronPairProduction, valuesIRB) { +// // Test if energy loss corresponds to the data table. +// std::vector x; +// std::vector y; +// std::ifstream infile(getDataPath("epairIRB.txt").c_str()); +// while (infile.good()) { +// if (infile.peek() != '#') { +// double a, b; +// infile >> a >> b; +// if (infile) { +// x.push_back(a * eV); +// y.push_back(b * eV / Mpc); +// } +// } +// infile.ignore(std::numeric_limits::max(), '\n'); +// } +// infile.close(); +// +// Candidate c; +// c.setCurrentStep(1 * Mpc); +// c.current.setId(nucleusId(1, 1)); // proton +// +// ElectronPairProduction epp(IRB); +// for (int i = 0; i < x.size(); i++) { +// c.current.setEnergy(x[i]); +// epp.process(&c); +// double dE = x[i] - c.current.getEnergy(); +// double dE_table = y[i] * 1 * Mpc; +// EXPECT_NEAR(dE, dE_table, 1e-12); +// } +//} +// +//TEST(ElectronPairProduction, valuesCMB_IRB) { +// // Test if energy loss corresponds to the data table. +// std::vector x; +// std::vector y; +// std::ifstream infile(getDataPath("epair_CMB_IRB.txt").c_str()); +// while (infile.good()) { +// if (infile.peek() != '#') { +// double a, b; +// infile >> a >> b; +// if (infile) { +// x.push_back(a * eV); +// y.push_back(b * eV / Mpc); +// } +// } +// infile.ignore(std::numeric_limits::max(), '\n'); +// } +// infile.close(); +// +// Candidate c; +// c.setCurrentStep(1 * Mpc); +// c.current.setId(nucleusId(1, 1)); // proton +// +// ElectronPairProduction epp(CMB_IRB); +// for (int i = 0; i < x.size(); i++) { +// c.current.setEnergy(x[i]); +// epp.process(&c); +// double dE = x[i] - c.current.getEnergy(); +// double dE_table = y[i] * 1 * Mpc; +// EXPECT_NEAR(dE, dE_table, 1e-12); +// } +//} +// +//TEST(NuclearDecay, Neutron) { +// // Quantitative test of decaying neutrons at rest. +// // The mean decay time is expected to be within 1% of the literature value. +// // This test can stochastically fail. +// Candidate candidate; +// candidate.current.setId(nucleusId(1, 0)); +// candidate.current.setEnergy(mass_neutron * c_squared); +// NuclearDecay decay; +// InteractionState state; +// double tau = 0; +// for (int i = 0; i < 100000; i++) { +// decay.setNextInteraction(&candidate, state); +// tau += state.distance; +// } +// tau /= c_light * 100000; +// EXPECT_NEAR(tau, 881.46, 8.8); +//} +// +//TEST(NuclearDecay, Scandium44) { +// // Test beta+ decay of 44Sc 44Ca. +// // This test can stochastically fail. +// NuclearDecay d(true, true); +// Candidate c; +// c.setCurrentStep(1 * Mpc); +// c.current.setId(nucleusId(44, 21)); +// c.current.setEnergy(1 * EeV); +// double gamma = c.current.getLorentzFactor(); +// d.process(&c); +// // primary +// EXPECT_EQ(nucleusId(44,20), c.current.getId()); +// EXPECT_DOUBLE_EQ(gamma, c.current.getLorentzFactor()); +// // secondaries +// EXPECT_EQ(2, c.secondaries.size()); +// Candidate c1 = *c.secondaries[0]; +// Candidate c2 = *c.secondaries[1]; +// EXPECT_EQ(-11, c1.current.getId()); +// // positron +// EXPECT_EQ( 12, c2.current.getId()); +// // electron neutrino +//} +// +//TEST(NuclearDecay, Li4) { +// // Test proton dripping of Li-4 to He-3. +// // This test can stochastically fail. +// NuclearDecay d; +// Candidate c; +// c.setCurrentStep(1 * kpc); +// c.current.setId(nucleusId(4, 3)); +// c.current.setEnergy(4 * EeV); +// d.process(&c); +// // primary +// EXPECT_EQ(nucleusId(3,2), c.current.getId()); +// EXPECT_EQ(1, c.secondaries.size()); +// // secondary +// Candidate c1 = *c.secondaries[0]; +// EXPECT_EQ(nucleusId(1,1), c1.current.getId()); +// EXPECT_EQ(1, c1.current.getEnergy() / EeV); +//} +// +//TEST(NuclearDecay, He5) { +// // Test neturon dripping of He-5 to He-4. +// // This test can stochastically fail if no interaction occurs over 1 Mpc. +// NuclearDecay d; +// Candidate c; +// c.setCurrentStep(1 * Mpc); +// c.current.setId(nucleusId(5, 2)); +// c.current.setEnergy(5 * EeV); +// d.process(&c); +// // primary +// EXPECT_EQ(nucleusId(4,2), c.current.getId()); +// EXPECT_EQ(4, c.current.getEnergy() / EeV); +// // secondary +// Candidate c2 = *c.secondaries[0]; +// EXPECT_EQ(nucleusId(1,0), c2.current.getId()); +// EXPECT_EQ(1, c2.current.getEnergy() / EeV); +//} +// +//TEST(NuclearDecay, LimitNextStep) { +// // Test if next step is limited. +// NuclearDecay d; +// Candidate c; +// c.setNextStep(std::numeric_limits::max()); +// c.current.setId(nucleusId(1, 0)); +// c.current.setEnergy(10 * EeV); +// d.process(&c); +// EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); +//} +// +//TEST(NuclearDecay, AllWorking) { +// // Test if all nuclear decays are working. +// NuclearDecay d; +// Candidate c; +// InteractionState interaction; +// +// std::ifstream infile(getDataPath("nuclear_decay.txt").c_str()); +// while (infile.good()) { +// if (infile.peek() != '#') { +// int Z, N, channel, foo; +// infile >> Z >> N >> interaction.channel >> foo; +// +// c.current.setId(nucleusId(Z + N, Z)); +// c.current.setEnergy(80 * EeV); +// c.setInteractionState(d.getDescription(), interaction); +// d.performInteraction(&c); +// } +// infile.ignore(std::numeric_limits::max(), '\n'); +// } +// infile.close(); +//} +// +//TEST(NuclearDecay, NoNucleus) { +// // Test if non-nuclei are skipped +// Candidate c; +// c.setNextStep(std::numeric_limits::max()); +// c.current.setId(11); // electron +// c.current.setEnergy(10 * EeV); +// +// NuclearDecay d; +// InteractionState state; +// EXPECT_FALSE(d.setNextInteraction(&c, state)); +// EXPECT_EQ(0, state.channel); +//} +// +//TEST(PhotoDisintegration, Carbon) { +// // Test if a 100 EeV C-12 nucleus photo-disintegrates (at least once) over a distance of 50 Mpc. +// // This test can stochastically fail if no interaction occurs over 50 Mpc. +// PhotoDisintegration pd; +// Candidate c; +// c.current.setId(nucleusId(12, 6)); +// c.current.setEnergy(100 * EeV); +// c.setCurrentStep(50 * Mpc); +// pd.process(&c); +// +// EXPECT_TRUE(c.current.getEnergy() < 100 * EeV); +// // energy loss +// EXPECT_TRUE(c.secondaries.size() > 0); +// // secondaries produced +// +// int A = c.current.getMassNumber(); +// int Z = c.current.getChargeNumber(); +// double E = c.current.getEnergy(); +// +// for (int i = 0; i < c.secondaries.size(); i++) { +// A += (*c.secondaries[i]).current.getMassNumber(); +// Z += (*c.secondaries[i]).current.getChargeNumber(); +// E += (*c.secondaries[i]).current.getEnergy(); +// } +// EXPECT_EQ(12, A); +// // nucleon number conserved +// EXPECT_EQ(6, Z); +// // proton number conserved +// EXPECT_DOUBLE_EQ(100 * EeV, E); +// // energy conserved +//} +// +//TEST(PhotoDisintegration, Iron) { +// // Test if a 100 EeV Fe-56 nucleus photo-disintegrates (at least once) over a distance of 50 Mpc. +// // This test can stochastically fail if no interaction occurs over 50 Mpc. +// PhotoDisintegration pd(IRB); +// Candidate c; +// c.current.setId(nucleusId(56, 26)); +// c.current.setEnergy(100 * EeV); +// c.setCurrentStep(50 * Mpc); +// pd.process(&c); +// +// EXPECT_TRUE(c.current.getEnergy() < 100 * EeV); +// // energy loss +// EXPECT_TRUE(c.secondaries.size() > 0); +// // secondaries produced +// +// int A = c.current.getMassNumber(); +// int Z = c.current.getChargeNumber(); +// double E = c.current.getEnergy(); +// +// for (int i = 0; i < c.secondaries.size(); i++) { +// A += (*c.secondaries[i]).current.getMassNumber(); +// Z += (*c.secondaries[i]).current.getChargeNumber(); +// E += (*c.secondaries[i]).current.getEnergy(); +// } +// EXPECT_EQ(56, A); +// // nucleon number conserved +// EXPECT_EQ(26, Z); +// // proton number conserved +// EXPECT_DOUBLE_EQ(100 * EeV, E); +// // energy conserved +//} +// +//TEST(PhotoDisintegration, NoNucleus) { +// // Test if non-nuclei are skipped +// Candidate c; +// c.setNextStep(std::numeric_limits::max()); +// c.current.setId(11); // electron +// c.current.setEnergy(10 * EeV); +// +// PhotoDisintegration module; +// InteractionState state; +// EXPECT_FALSE(module.setNextInteraction(&c, state)); +// EXPECT_EQ(0, state.channel); +//} +// +//TEST(PhotoDisintegration, LimitNextStep) { +// // Test if the interaction limits the next propagation step. +// PhotoDisintegration pd; +// Candidate c; +// c.setNextStep(std::numeric_limits::max()); +// c.current.setId(nucleusId(4, 2)); +// c.current.setEnergy(200 * EeV); +// pd.process(&c); +// EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); +//} +// +//TEST(PhotoDisintegration, AllWorkingCMB) { +// // Test if all photo-disintegrations are working. +// PhotoDisintegration pd(CMB); +// Candidate c; +// InteractionState interaction; +// +// std::ifstream infile( +// getDataPath("photodis_CMB.txt").c_str()); +// std::string line; +// while (std::getline(infile, line)) { +// if (line[0] == '#') +// continue; +// std::stringstream lineStream(line); +// int Z, N; +// lineStream >> Z; +// lineStream >> N; +// lineStream >> interaction.channel; +// +// double y; +// for (size_t i = 0; i < 200; i++) { +// lineStream >> y; +// EXPECT_TRUE(lineStream); +// // test if all 200 entries are present +// } +// +// c.current.setId(nucleusId(Z + N, Z)); +// c.current.setEnergy(80 * EeV); +// c.setInteractionState(pd.getDescription(), interaction); +// pd.performInteraction(&c); +// } +// infile.close(); +//} +// +//TEST(PhotoDisintegration, AllWorkingIRB) { +// // Test if all photo-disintegrations are working. +// PhotoDisintegration pd(IRB); +// Candidate c; +// InteractionState interaction; +// +// std::ifstream infile( +// getDataPath("photodis_IRB.txt").c_str()); +// std::string line; +// while (std::getline(infile, line)) { +// if (line[0] == '#') +// continue; +// std::stringstream lineStream(line); +// int Z, N; +// lineStream >> Z; +// lineStream >> N; +// lineStream >> interaction.channel; +// +// double y; +// for (size_t i = 0; i < 200; i++) { +// lineStream >> y; +// EXPECT_TRUE(lineStream); +// // test if all 200 entries are present +// } +// +// c.current.setId(nucleusId(Z + N, Z)); +// c.current.setEnergy(80 * EeV); +// c.setInteractionState(pd.getDescription(), interaction); +// pd.performInteraction(&c); +// } +// infile.close(); +//} +// +//TEST(PhotoPionProduction, Backgrounds) { +// // Test if interaction data files are loaded. +// PhotoPionProduction ppp1(CMB); +// PhotoPionProduction ppp2(IRB); +//} +// +//TEST(PhotoPionProduction, Proton) { +// // Test photo-pion interaction for 100 EeV proton. +// // This test can stochastically fail if no interaction occurs over 100 Mpc. +// PhotoPionProduction ppp; +// Candidate c; +// c.setCurrentStep(100 * Mpc); +// c.current.setId(nucleusId(1, 1)); +// c.current.setEnergy(100 * EeV); +// ppp.process(&c); +// EXPECT_TRUE(c.current.getEnergy() / EeV < 100); +// // energy loss +// EXPECT_EQ(1, c.current.getMassNumber()); +// // nucleon number conserved +// EXPECT_EQ(0, c.secondaries.size()); +// // no (nucleonic) secondaries +//} +// +//TEST(PhotoPionProduction, Helium) { +// // Test photo-pion interaction for 400 EeV He nucleus. +// // This test can stochastically fail if no interaction occurs over 100 Mpc. +// PhotoPionProduction ppp; +// Candidate c; +// c.setCurrentStep(100 * Mpc); +// c.current.setId(nucleusId(4, 2)); +// c.current.setEnergy(400 * EeV); +// ppp.process(&c); +// EXPECT_LT(c.current.getEnergy(), 400 * EeV); +// EXPECT_TRUE(c.current.getMassNumber() < 4); +// EXPECT_TRUE(c.secondaries.size() > 0); +//} +// +//TEST(PhotoPionProduction, NoNucleus) { +// // Test if non-nuclei are skipped +// Candidate c; +// c.setNextStep(std::numeric_limits::max()); +// c.current.setId(11); // electron +// c.current.setEnergy(10 * EeV); +// +// PhotoPionProduction module; +// InteractionState state; +// EXPECT_FALSE(module.setNextInteraction(&c, state)); +// EXPECT_EQ(0, state.channel); +//} +// +//TEST(PhotoPionProduction, LimitNextStep) { +// // Test if the interaction limits the next propagation step. +// PhotoPionProduction ppp; +// Candidate c; +// c.setNextStep(std::numeric_limits::max()); +// c.current.setId(nucleusId(1, 1)); +// c.current.setEnergy(200 * EeV); +// ppp.process(&c); +// EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); +//} +// +//TEST(SophiaPhotoPionProduction, withoutSecondaries) { +// // Test photo-pion (SOPHIA) interaction for 100 EeV proton. +// // This test can stochastically fail if no interaction occurs over 100 Mpc. +// SophiaPhotoPionProduction ppp; +// Candidate c; +// c.setCurrentStep(100 * Mpc); +// c.current.setId(nucleusId(1, 1)); +// c.current.setEnergy(100 * EeV); +// ppp.process(&c); +// EXPECT_GT(100 * EeV, c.current.getEnergy()); +// // energy loss +// EXPECT_EQ(1, c.current.getMassNumber()); +// // nucleon number conserved +// EXPECT_EQ(0, c.secondaries.size()); +// // secondaries turned off +//} +// +//TEST(SophiaPhotoPionProduction, withSecondaries) { +// // Test photo-pion interaction for 100 EeV proton. +// // This test can stochastically fail if no interaction occurs over 100 Mpc. +// SophiaPhotoPionProduction ppp(CMB, true, true, true); +// Candidate c; +// c.current.setId(nucleusId(1, 1)); +// c.current.setEnergy(100 * EeV); +// InteractionState interaction; +// ppp.setNextInteraction(&c, interaction); +// ppp.performInteraction(&c); +// EXPECT_GT(c.secondaries.size(), 1); +// // secondaries turned on +//} + +TEST(SophiaPhotoPionProduction, belowSophiaEnergyThreshold_CMB) { + // The minimum nucleon energy for SOPHIA interactions is ~3.75 EeV against the CMB. + // This needs to be caught + SophiaPhotoPionProduction ppp(CMB); -TEST(NuclearDecay, Neutron) { - // Quantitative test of decaying neutrons at rest. - // The mean decay time is expected to be within 1% of the literature value. - // This test can stochastically fail. - Candidate candidate; - candidate.current.setId(nucleusId(1, 0)); - candidate.current.setEnergy(mass_neutron * c_squared); - NuclearDecay decay; - InteractionState state; - double tau = 0; - for (int i = 0; i < 100000; i++) { - decay.setNextInteraction(&candidate, state); - tau += state.distance; - } - tau /= c_light * 100000; - EXPECT_NEAR(tau, 881.46, 8.8); -} - -TEST(NuclearDecay, Scandium44) { - // Test beta+ decay of 44Sc 44Ca. - // This test can stochastically fail. - NuclearDecay d(true, true); - Candidate c; - c.setCurrentStep(1 * Mpc); - c.current.setId(nucleusId(44, 21)); - c.current.setEnergy(1 * EeV); - double gamma = c.current.getLorentzFactor(); - d.process(&c); - // primary - EXPECT_EQ(nucleusId(44,20), c.current.getId()); - EXPECT_DOUBLE_EQ(gamma, c.current.getLorentzFactor()); - // secondaries - EXPECT_EQ(2, c.secondaries.size()); - Candidate c1 = *c.secondaries[0]; - Candidate c2 = *c.secondaries[1]; - EXPECT_EQ(-11, c1.current.getId()); - // positron - EXPECT_EQ( 12, c2.current.getId()); - // electron neutrino -} - -TEST(NuclearDecay, Li4) { - // Test proton dripping of Li-4 to He-3. - // This test can stochastically fail. - NuclearDecay d; - Candidate c; - c.setCurrentStep(1 * kpc); - c.current.setId(nucleusId(4, 3)); - c.current.setEnergy(4 * EeV); - d.process(&c); - // primary - EXPECT_EQ(nucleusId(3,2), c.current.getId()); - EXPECT_EQ(1, c.secondaries.size()); - // secondary - Candidate c1 = *c.secondaries[0]; - EXPECT_EQ(nucleusId(1,1), c1.current.getId()); - EXPECT_EQ(1, c1.current.getEnergy() / EeV); -} - -TEST(NuclearDecay, He5) { - // Test neturon dripping of He-5 to He-4. - // This test can stochastically fail if no interaction occurs over 1 Mpc. - NuclearDecay d; - Candidate c; - c.setCurrentStep(1 * Mpc); - c.current.setId(nucleusId(5, 2)); - c.current.setEnergy(5 * EeV); - d.process(&c); - // primary - EXPECT_EQ(nucleusId(4,2), c.current.getId()); - EXPECT_EQ(4, c.current.getEnergy() / EeV); - // secondary - Candidate c2 = *c.secondaries[0]; - EXPECT_EQ(nucleusId(1,0), c2.current.getId()); - EXPECT_EQ(1, c2.current.getEnergy() / EeV); -} - -TEST(NuclearDecay, LimitNextStep) { - // Test if next step is limited. - NuclearDecay d; - Candidate c; - c.setNextStep(std::numeric_limits::max()); - c.current.setId(nucleusId(1, 0)); - c.current.setEnergy(10 * EeV); - d.process(&c); - EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); -} - -TEST(NuclearDecay, AllWorking) { - // Test if all nuclear decays are working. - NuclearDecay d; Candidate c; - InteractionState interaction; - - std::ifstream infile(getDataPath("nuclear_decay.txt").c_str()); - while (infile.good()) { - if (infile.peek() != '#') { - int Z, N, channel, foo; - infile >> Z >> N >> interaction.channel >> foo; - - c.current.setId(nucleusId(Z + N, Z)); - c.current.setEnergy(80 * EeV); - c.setInteractionState(d.getDescription(), interaction); - d.performInteraction(&c); - } - infile.ignore(std::numeric_limits::max(), '\n'); - } - infile.close(); -} - -TEST(NuclearDecay, NoNucleus) { - // Test if non-nuclei are skipped - Candidate c; - c.setNextStep(std::numeric_limits::max()); - c.current.setId(11); // electron - c.current.setEnergy(10 * EeV); - - NuclearDecay d; - InteractionState state; - EXPECT_FALSE(d.setNextInteraction(&c, state)); - EXPECT_EQ(0, state.channel); -} - -TEST(PhotoDisintegration, Carbon) { - // Test if a 100 EeV C-12 nucleus photo-disintegrates (at least once) over a distance of 50 Mpc. - // This test can stochastically fail if no interaction occurs over 50 Mpc. - PhotoDisintegration pd; - Candidate c; - c.current.setId(nucleusId(12, 6)); - c.current.setEnergy(100 * EeV); - c.setCurrentStep(50 * Mpc); - pd.process(&c); - - EXPECT_TRUE(c.current.getEnergy() < 100 * EeV); - // energy loss - EXPECT_TRUE(c.secondaries.size() > 0); - // secondaries produced - - int A = c.current.getMassNumber(); - int Z = c.current.getChargeNumber(); - double E = c.current.getEnergy(); - - for (int i = 0; i < c.secondaries.size(); i++) { - A += (*c.secondaries[i]).current.getMassNumber(); - Z += (*c.secondaries[i]).current.getChargeNumber(); - E += (*c.secondaries[i]).current.getEnergy(); - } - EXPECT_EQ(12, A); - // nucleon number conserved - EXPECT_EQ(6, Z); - // proton number conserved - EXPECT_DOUBLE_EQ(100 * EeV, E); - // energy conserved -} - -TEST(PhotoDisintegration, Iron) { - // Test if a 100 EeV Fe-56 nucleus photo-disintegrates (at least once) over a distance of 50 Mpc. - // This test can stochastically fail if no interaction occurs over 50 Mpc. - PhotoDisintegration pd(IRB); - Candidate c; - c.current.setId(nucleusId(56, 26)); - c.current.setEnergy(100 * EeV); - c.setCurrentStep(50 * Mpc); - pd.process(&c); - - EXPECT_TRUE(c.current.getEnergy() < 100 * EeV); - // energy loss - EXPECT_TRUE(c.secondaries.size() > 0); - // secondaries produced - - int A = c.current.getMassNumber(); - int Z = c.current.getChargeNumber(); - double E = c.current.getEnergy(); - - for (int i = 0; i < c.secondaries.size(); i++) { - A += (*c.secondaries[i]).current.getMassNumber(); - Z += (*c.secondaries[i]).current.getChargeNumber(); - E += (*c.secondaries[i]).current.getEnergy(); - } - EXPECT_EQ(56, A); - // nucleon number conserved - EXPECT_EQ(26, Z); - // proton number conserved - EXPECT_DOUBLE_EQ(100 * EeV, E); - // energy conserved -} - -TEST(PhotoDisintegration, NoNucleus) { - // Test if non-nuclei are skipped - Candidate c; - c.setNextStep(std::numeric_limits::max()); - c.current.setId(11); // electron - c.current.setEnergy(10 * EeV); - - PhotoDisintegration module; - InteractionState state; - EXPECT_FALSE(module.setNextInteraction(&c, state)); - EXPECT_EQ(0, state.channel); -} - -TEST(PhotoDisintegration, LimitNextStep) { - // Test if the interaction limits the next propagation step. - PhotoDisintegration pd; - Candidate c; - c.setNextStep(std::numeric_limits::max()); - c.current.setId(nucleusId(4, 2)); - c.current.setEnergy(200 * EeV); - pd.process(&c); - EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); -} - -TEST(PhotoDisintegration, AllWorkingCMB) { - // Test if all photo-disintegrations are working. - PhotoDisintegration pd(CMB); - Candidate c; - InteractionState interaction; - - std::ifstream infile( - getDataPath("photodis_CMB.txt").c_str()); - std::string line; - while (std::getline(infile, line)) { - if (line[0] == '#') - continue; - std::stringstream lineStream(line); - int Z, N; - lineStream >> Z; - lineStream >> N; - lineStream >> interaction.channel; - - double y; - for (size_t i = 0; i < 200; i++) { - lineStream >> y; - EXPECT_TRUE(lineStream); - // test if all 200 entries are present - } - - c.current.setId(nucleusId(Z + N, Z)); - c.current.setEnergy(80 * EeV); - c.setInteractionState(pd.getDescription(), interaction); - pd.performInteraction(&c); - } - infile.close(); -} - -TEST(PhotoDisintegration, AllWorkingIRB) { - // Test if all photo-disintegrations are working. - PhotoDisintegration pd(IRB); - Candidate c; - InteractionState interaction; - - std::ifstream infile( - getDataPath("photodis_IRB.txt").c_str()); - std::string line; - while (std::getline(infile, line)) { - if (line[0] == '#') - continue; - std::stringstream lineStream(line); - int Z, N; - lineStream >> Z; - lineStream >> N; - lineStream >> interaction.channel; - - double y; - for (size_t i = 0; i < 200; i++) { - lineStream >> y; - EXPECT_TRUE(lineStream); - // test if all 200 entries are present - } - - c.current.setId(nucleusId(Z + N, Z)); - c.current.setEnergy(80 * EeV); - c.setInteractionState(pd.getDescription(), interaction); - pd.performInteraction(&c); - } - infile.close(); -} - -TEST(PhotoPionProduction, Backgrounds) { - // Test if interaction data files are loaded. - PhotoPionProduction ppp1(CMB); - PhotoPionProduction ppp2(IRB); -} - -TEST(PhotoPionProduction, Proton) { - // Test photo-pion interaction for 100 EeV proton. - // This test can stochastically fail if no interaction occurs over 100 Mpc. - PhotoPionProduction ppp; - Candidate c; - c.setCurrentStep(100 * Mpc); c.current.setId(nucleusId(1, 1)); - c.current.setEnergy(100 * EeV); - ppp.process(&c); - EXPECT_TRUE(c.current.getEnergy() / EeV < 100); - // energy loss - EXPECT_EQ(1, c.current.getMassNumber()); - // nucleon number conserved - EXPECT_EQ(0, c.secondaries.size()); - // no (nucleonic) secondaries -} + c.current.setEnergy(2 * EeV); + InteractionState state(1 * Mpc, 1); -TEST(PhotoPionProduction, Helium) { - // Test photo-pion interaction for 400 EeV He nucleus. - // This test can stochastically fail if no interaction occurs over 100 Mpc. - PhotoPionProduction ppp; - Candidate c; - c.setCurrentStep(100 * Mpc); - c.current.setId(nucleusId(4, 2)); - c.current.setEnergy(400 * EeV); - ppp.process(&c); - EXPECT_LT(c.current.getEnergy(), 400 * EeV); - EXPECT_TRUE(c.current.getMassNumber() < 4); - EXPECT_TRUE(c.secondaries.size() > 0); -} + c.setInteractionState(ppp.getDescription(), state); + ppp.performInteraction(&c); -TEST(PhotoPionProduction, NoNucleus) { - // Test if non-nuclei are skipped - Candidate c; - c.setNextStep(std::numeric_limits::max()); - c.current.setId(11); // electron - c.current.setEnergy(10 * EeV); + // no interaction should have happened + EXPECT_DOUBLE_EQ(2, c.current.getEnergy() / EeV); - PhotoPionProduction module; - InteractionState state; - EXPECT_FALSE(module.setNextInteraction(&c, state)); - EXPECT_EQ(0, state.channel); + // the scheduled photo-pion interaction better be deleted + InteractionState dummy; + bool hasInteraction = c.getInteractionState(ppp.getDescription(), dummy); + EXPECT_FALSE(hasInteraction); } -TEST(PhotoPionProduction, LimitNextStep) { - // Test if the interaction limits the next propagation step. - PhotoPionProduction ppp; - Candidate c; - c.setNextStep(std::numeric_limits::max()); - c.current.setId(nucleusId(1, 1)); - c.current.setEnergy(200 * EeV); - ppp.process(&c); - EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); -} +TEST(SophiaPhotoPionProduction, belowSophiaEnergyThreshold_IRB) { + // The minimum nucleon energy for SOPHIA interactions is ~0.01 EeV against the IRB. + // This needs to be caught. + SophiaPhotoPionProduction ppp(IRB); -TEST(SophiaPhotoPionProduction, withoutSecondaries) { - // Test photo-pion (SOPHIA) interaction for 100 EeV proton. - // This test can stochastically fail if no interaction occurs over 100 Mpc. - SophiaPhotoPionProduction ppp; Candidate c; - c.setCurrentStep(100 * Mpc); c.current.setId(nucleusId(1, 1)); - c.current.setEnergy(100 * EeV); - ppp.process(&c); - EXPECT_GT(100 * EeV, c.current.getEnergy()); - // energy loss - EXPECT_EQ(1, c.current.getMassNumber()); - // nucleon number conserved - EXPECT_EQ(0, c.secondaries.size()); - // secondaries turned off -} + c.current.setEnergy(0.005 * EeV); + InteractionState state(1 * Mpc, 1); -TEST(SophiaPhotoPionProduction, withSecondaries) { - // Test photo-pion interaction for 100 EeV proton. - // This test can stochastically fail if no interaction occurs over 100 Mpc. - SophiaPhotoPionProduction ppp(CMB, true, true, true); - Candidate c; - c.current.setId(nucleusId(1, 1)); - c.current.setEnergy(100 * EeV); - InteractionState interaction; - ppp.setNextInteraction(&c, interaction); + c.setInteractionState(ppp.getDescription(), state); ppp.performInteraction(&c); - EXPECT_GT(c.secondaries.size(), 1); - // secondaries turned on + + // no interaction should have happened + EXPECT_DOUBLE_EQ(0.005, c.current.getEnergy() / EeV); + + // the scheduled photo-pion interaction better be deleted + InteractionState dummy; + bool hasInteraction = c.getInteractionState(ppp.getDescription(), dummy); + EXPECT_FALSE(hasInteraction); } TEST(SimpleRedshift, test) { From 52bb8644d252667f5be9cd257229c2326fd8554a Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 25 Jan 2013 11:08:53 +0100 Subject: [PATCH 0265/1298] add options for ROOT and FFTW --- CMakeLists.txt | 79 +++++++++++++++++++++++++++----------------------- python/mpc.i | 3 +- 2 files changed, 44 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f658694cb..0eaed9117 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,11 +12,11 @@ set(MPC_SWIG_DEFINES) # Dependencies # ---------------------------------------------------------------------------- # googletest (provided) -option(ENABLETESTING "Build tests and enable test target" ON) -if(ENABLETESTING) +option(ENABLE_TESTING "Build tests and enable test target" OFF) +if(ENABLE_TESTING) include_directories(libs/gtest/include) add_subdirectory(libs/gtest) -endif(ENABLETESTING) +endif(ENABLE_TESTING) # kiss (provided) add_subdirectory(libs/kiss) @@ -39,49 +39,58 @@ list(APPEND MPC_EXTRA_LIBRARIES sophia gfortran) list(APPEND MPC_EXTRA_INCLUDES libs/sophia) # OpenMP (optional for shared memory multiprocessing) +option(ENABLE_OPENMP "OpenMP for multithreading" ON) +if(ENABLE_OPENMP) include(FindOpenMP) -if(OPENMP_FOUND) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") -endif() + if(OPENMP_FOUND) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") + endif(OPENMP_FOUND) +endif(ENABLE_OPENMP) # fftw3f (optional for turbulent magnetic fields) -find_package(FFTW3F) -if(FFTW3F_FOUND) - list(APPEND MPC_EXTRA_INCLUDES ${FFTW3F_INCLUDE_DIR}) - list(APPEND MPC_EXTRA_LIBRARIES ${FFTW3F_LIBRARY}) - add_definitions(-DMPC_HAVE_FFTW3F) - list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_FFTW3F) -endif(FFTW3F_FOUND) +option(ENABLE_FFTW3F "FFTW3F to create turbulent fields" OFF) +if(ENABLE_FFTW3F) + find_package(FFTW3F) + if(FFTW3F_FOUND) + list(APPEND MPC_EXTRA_INCLUDES ${FFTW3F_INCLUDE_DIR}) + list(APPEND MPC_EXTRA_LIBRARIES ${FFTW3F_LIBRARY}) + add_definitions(-DMPC_HAVE_FFTW3F) + list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_FFTW3F) + endif(FFTW3F_FOUND) +endif(ENABLE_FFTW3F) # gadget (optional for SPH magnetic fields) find_package(Gadget) -if (GADGET_FOUND) +if(GADGET_FOUND) list(APPEND MPC_EXTRA_SOURCES src/magneticField/SPHMagneticField.cpp) list(APPEND MPC_EXTRA_INCLUDES ${GADGET_INCLUDE_DIR}) list(APPEND MPC_EXTRA_LIBRARIES ${GADGET_LIBRARY}) add_definitions (-DMPC_HAVE_GADGET) list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_GADGET) -endif (GADGET_FOUND) +endif(GADGET_FOUND) # ROOT (optional for ROOT output) -find_package(ROOT) -if (ROOT_FOUND) - FIND_PROGRAM(ROOT_CONFIG root-config REQUIRED ROOT_CONFIG_PATH) - execute_process(COMMAND ${ROOT_CONFIG} "--cflags" OUTPUT_VARIABLE ROOT_CFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process(COMMAND ${ROOT_CONFIG} "--libs" OUTPUT_VARIABLE ROOT_LIBS OUTPUT_STRIP_TRAILING_WHITESPACE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ROOT_CFLAGS}") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") - add_definitions(-DMPC_HAVE_ROOT) - list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_ROOT) -endif() +option(ENABLE_ROOT "ROOT Output" OFF) +if(ENABLE_ROOT) + find_package(ROOT) + if(ROOT_FOUND) + FIND_PROGRAM(ROOT_CONFIG root-config REQUIRED ROOT_CONFIG_PATH) + execute_process(COMMAND ${ROOT_CONFIG} "--cflags" OUTPUT_VARIABLE ROOT_CFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${ROOT_CONFIG} "--libs" OUTPUT_VARIABLE ROOT_LIBS OUTPUT_STRIP_TRAILING_WHITESPACE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ROOT_CFLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") + add_definitions(-DMPC_HAVE_ROOT) + list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_ROOT) + endif(ROOT_FOUND) +endif(ENABLE_ROOT) # Google Performance Tools (optional as possible performance tweak) find_package(GooglePerfTools) set(TCMALLOC) -if (GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) +if(GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) set(TCMALLOC ${TCMALLOC_LIBRARY}) endif(GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) @@ -128,7 +137,6 @@ target_link_libraries(mpc ${MPC_EXTRA_LIBRARIES}) add_executable(mpc-run src/main.cpp) target_link_libraries(mpc-run mpc) - # ---------------------------------------------------------------------------- # Install # ---------------------------------------------------------------------------- @@ -141,7 +149,7 @@ install(DIRECTORY data/ DESTINATION share/mpc/) # ---------------------------------------------------------------------------- # Testing # ---------------------------------------------------------------------------- -if(ENABLETESTING) +if(ENABLE_TESTING) enable_testing() add_executable(testCore test/testCore.cpp) target_link_libraries(testCore mpc gtest gtest_main pthread) @@ -180,13 +188,13 @@ if(ENABLETESTING) target_link_libraries(testSPHField mpc gtest gtest_main pthread) add_test(testSPHField testSPHField) endif(GADGET_FOUND) -endif(ENABLETESTING) +endif(ENABLE_TESTING) # ---------------------------------------------------------------------------- # Python # ---------------------------------------------------------------------------- -option(ENABLEPYTHON "Create python library via SWIG" ON) -if(ENABLEPYTHON) +option(ENABLE_PYTHON "Create python library via SWIG" OFF) +if(ENABLE_PYTHON) include(python/Python.cmake) include_directories(${PYTHON_INCLUDE_PATH}) @@ -196,10 +204,9 @@ if(ENABLEPYTHON) COMMAND swig -c++ -python ${MPC_SWIG_DEFINES} -I${CMAKE_SOURCE_DIR}/include -o ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx -outdir ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/python/mpc.i DEPENDS ${CMAKE_SOURCE_DIR}/python/mpc.i ${MPC_INCLUDES} ) add_library(mpc-swig MODULE ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx) - #set_source_file_properties( ${CMAKE_SOURCE_DIR}/python/mpc.i PROPERTIES OBJECT_DEPENDS ${MPC_INCLUDES}) set_target_properties(mpc-swig PROPERTIES PREFIX "") set_target_properties(mpc-swig PROPERTIES OUTPUT_NAME "_mpc") target_link_libraries(mpc-swig mpc ${PYTHON_LIBRARIES}) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/mpc.py" DESTINATION ${PYTHON_SITE_PACKAGES}) install(TARGETS mpc-swig LIBRARY DESTINATION ${PYTHON_SITE_PACKAGES}) -endif(ENABLEPYTHON) +endif(ENABLE_PYTHON) diff --git a/python/mpc.i b/python/mpc.i index 6caf440ce..a59a73545 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -1,7 +1,7 @@ %module(directors="1") mpc %{ -// workaround for swig +// workaround for SWIG < 2.0.5 with GCC >= 4.7 #include using std::ptrdiff_t; %} @@ -57,7 +57,6 @@ using std::ptrdiff_t; #include "mpc/PhotonBackground.h" #include "mpc/Grid.h" #include "mpc/GridTools.h" - %} From 309bdb0b6fe5253e8959f3251ac125de435913cb Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 29 Jan 2013 12:54:34 +0100 Subject: [PATCH 0266/1298] SimplePropagation: catch minStep > maxStep and add getter --- include/mpc/module/SimplePropagation.h | 7 ++-- src/module/SimplePropagation.cpp | 46 ++++++++++++++++++-------- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/include/mpc/module/SimplePropagation.h b/include/mpc/module/SimplePropagation.h index aed69442e..95de6be0c 100644 --- a/include/mpc/module/SimplePropagation.h +++ b/include/mpc/module/SimplePropagation.h @@ -10,7 +10,8 @@ namespace mpc { @brief Simple rectalinear propagation in absence of magnetic fields. This module performs a rectalinear propagation. - It always proposes a next step of the maximum step size. + The step size is guaranteed to be larger than minStep and smaller than maxStep. + It always proposes a next step size of maxStep. */ class SimplePropagation: public Module { private: @@ -21,10 +22,12 @@ class SimplePropagation: public Module { void process(Candidate *candidate) const; void setMinimumStep(double minStep); void setMaximumStep(double maxStep); + double getMinimumStep() const; + double getMaximumStep() const; std::string getDescription() const; }; } // namespace mpc -#endif /* SIMPLEPROPAGATION_H_ */ +#endif // SIMPLEPROPAGATION_H_ diff --git a/src/module/SimplePropagation.cpp b/src/module/SimplePropagation.cpp index 350152674..4dc25307e 100644 --- a/src/module/SimplePropagation.cpp +++ b/src/module/SimplePropagation.cpp @@ -1,31 +1,49 @@ #include "mpc/module/SimplePropagation.h" +#include +#include + namespace mpc { SimplePropagation::SimplePropagation(double minStep, double maxStep) : minStep(minStep), maxStep(maxStep) { + if (minStep > maxStep) + throw std::runtime_error("SimplePropagation: minStep > maxStep"); } -void SimplePropagation::setMinimumStep(double s) { - minStep = s; +void SimplePropagation::process(Candidate *c) const { + c->previous = c->current; + + double step = std::max(minStep, c->getNextStep()); + c->setCurrentStep(step); + + Vector3d pos = c->current.getPosition(); + Vector3d dir = c->current.getDirection(); + c->current.setPosition(pos + dir * step); + + c->setNextStep(maxStep); } -void SimplePropagation::setMaximumStep(double s) { - maxStep = s; +void SimplePropagation::setMinimumStep(double step) { + if (step > maxStep) + throw std::runtime_error("SimplePropagation: minStep > maxStep"); + else + minStep = step; } -void SimplePropagation::process(Candidate *candidate) const { - // save the new previous particle state - candidate->previous = candidate->current; +void SimplePropagation::setMaximumStep(double step) { + if (minStep > step) + throw std::runtime_error("SimplePropagation: minStep > maxStep"); + else + maxStep = step; +} - double step = candidate->getNextStep(); - step = std::max(step, minStep); +double SimplePropagation::getMinimumStep() const { + return minStep; +} - Vector3d pos = candidate->current.getPosition(); - Vector3d dir = candidate->current.getDirection(); - candidate->current.setPosition(pos + dir * step); - candidate->setCurrentStep(step); - candidate->setNextStep(maxStep); +double SimplePropagation::getMaximumStep() const { + return maxStep; } std::string SimplePropagation::getDescription() const { From 52d527ce149bb5049e887ce5516eac6ce517b340 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 29 Jan 2013 14:44:18 +0100 Subject: [PATCH 0267/1298] DeflectionCK: add getters and checks for parameters --- include/mpc/module/DeflectionCK.h | 16 +- src/module/DeflectionCK.cpp | 79 ++- src/module/SimplePropagation.cpp | 6 +- test/testInteraction.cpp | 1034 ++++++++++++++--------------- 4 files changed, 580 insertions(+), 555 deletions(-) diff --git a/include/mpc/module/DeflectionCK.h b/include/mpc/module/DeflectionCK.h index 0bd47c9dd..775b40931 100644 --- a/include/mpc/module/DeflectionCK.h +++ b/include/mpc/module/DeflectionCK.h @@ -12,31 +12,35 @@ namespace mpc { @class DeflectionCK @brief Propagation through magnetic fields using the Cash-Karp integrator. - This module solves the equations of motion of a charged particle when propagating through a magnetic field.\n + This module solves the equations of motion of a relativistic charged particle when propagating through a magnetic field.\n It uses the Runge-Kutta integration method with Cash-Karp coefficients.\n The step size control tries to keep the relative error close to, but smaller than the designated tolerance. Additionally a minimum and maximum size for the steps can be set. For neutral particles a rectalinear propagation is applied and a next step of the maximum step size proposed. */ class DeflectionCK: public Module { +private: ref_ptr field; ExplicitRungeKutta erk; - double tolerance; - double minStep; - double maxStep; + double tolerance; /*< target relative error of the numerical integration */ + double minStep; /*< minimum step size of the propagation */ + double maxStep; /*< maximum step size of the propagation */ public: DeflectionCK(ref_ptr field = NULL, double tolerance = 1e-4, double minStep = 0.1 * kpc, double maxStep = 4000 * Mpc); + void process(Candidate *candidate) const; void setField(ref_ptr field); void setTolerance(double tolerance); void setMinimumStep(double minStep); void setMaximumStep(double maxStep); + double getTolerance() const; + double getMinimumStep() const; + double getMaximumStep() const; std::string getDescription() const; - void process(Candidate *candidate) const; }; } // namespace mpc -#endif /* MPC_DEFLECTION_H_ */ +#endif // MPC_DEFLECTION_H_ diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index 1de97ae2b..418962315 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -26,8 +26,7 @@ class LorentzForce: public ExplicitRungeKutta::F { try { B = field->getField(v.a); } catch (std::exception &e) { - std::cerr << "mpc::LorentzForce: Exception in getField." - << std::endl; + std::cerr << "LorentzForce: Exception in getField." << std::endl; std::cerr << e.what() << std::endl; } Vector3d force = (double) particle->getCharge() * velocity.cross(B); @@ -38,34 +37,14 @@ class LorentzForce: public ExplicitRungeKutta::F { DeflectionCK::DeflectionCK(ref_ptr field, double tolerance, double minStep, double maxStep) : field(field), tolerance(tolerance), minStep(minStep), maxStep(maxStep) { + if ((tolerance > 1) or (tolerance < 0)) + throw std::runtime_error( + "DeflectionCK: target relative error not in range 0-1"); + if (minStep > maxStep) + throw std::runtime_error("DeflectionCK: minStep > maxStep"); erk.loadCashKarp(); } -void DeflectionCK::setField(ref_ptr f) { - field = f; -} - -void DeflectionCK::setTolerance(double t) { - tolerance = t; -} - -void DeflectionCK::setMinimumStep(double s) { - minStep = s; -} - -void DeflectionCK::setMaximumStep(double s) { - maxStep = s; -} - -std::string DeflectionCK::getDescription() const { - std::stringstream s; - s << "Propagation in magnetic fields using the Cash-Karp method."; - s << " Tolerance: " << tolerance; - s << ", Minimum Step: " << minStep / kpc << " kpc"; - s << ", Maximum Step: " << maxStep / kpc << " kpc"; - return s.str(); -} - void DeflectionCK::process(Candidate *candidate) const { // save the new previous particle state candidate->previous = candidate->current; @@ -121,4 +100,48 @@ void DeflectionCK::process(Candidate *candidate) const { candidate->setNextStep(h * c_light); } -} /* namespace mpc */ +void DeflectionCK::setField(ref_ptr f) { + field = f; +} + +void DeflectionCK::setTolerance(double tol) { + if ((tol > 1) or (tol < 0)) + throw std::runtime_error( + "DeflectionCK: target relative error not in range 0-1"); + tolerance = tol; +} + +void DeflectionCK::setMinimumStep(double min) { + if (min > maxStep) + throw std::runtime_error("DeflectionCK: minStep > maxStep"); + minStep = min; +} + +void DeflectionCK::setMaximumStep(double min) { + if (minStep > min) + throw std::runtime_error("DeflectionCK: minStep > maxStep"); + maxStep = min; +} + +double DeflectionCK::getTolerance() const { + return tolerance; +} + +double DeflectionCK::getMinimumStep() const { + return minStep; +} + +double DeflectionCK::getMaximumStep() const { + return maxStep; +} + +std::string DeflectionCK::getDescription() const { + std::stringstream s; + s << "Propagation in magnetic fields using the Cash-Karp method."; + s << " Target error: " << tolerance; + s << ", Minimum Step: " << minStep / kpc << " kpc"; + s << ", Maximum Step: " << maxStep / kpc << " kpc"; + return s.str(); +} + +} // namespace mpc diff --git a/src/module/SimplePropagation.cpp b/src/module/SimplePropagation.cpp index 4dc25307e..b29f11149 100644 --- a/src/module/SimplePropagation.cpp +++ b/src/module/SimplePropagation.cpp @@ -27,15 +27,13 @@ void SimplePropagation::process(Candidate *c) const { void SimplePropagation::setMinimumStep(double step) { if (step > maxStep) throw std::runtime_error("SimplePropagation: minStep > maxStep"); - else - minStep = step; + minStep = step; } void SimplePropagation::setMaximumStep(double step) { if (minStep > step) throw std::runtime_error("SimplePropagation: minStep > maxStep"); - else - maxStep = step; + maxStep = step; } double SimplePropagation::getMinimumStep() const { diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index e72d10583..363fc3c33 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -10,523 +10,523 @@ namespace mpc { -//TEST(ElectronPairProduction, EnergyDecreasing) { -// // Test if energy loss occurs for protons with energies from 1e15 - 1e23 eV -// Candidate c; -// c.setCurrentStep(1 * Mpc); -// c.current.setId(nucleusId(1, 1)); // proton -// -// ElectronPairProduction epp1(CMB); -// for (int i = 0; i < 80; i++) { -// double E = pow(10, 15 + i * 0.1) * eV; -// c.current.setEnergy(E); -// epp1.process(&c); -// EXPECT_TRUE(c.current.getEnergy() <= E); -// } -// -// ElectronPairProduction epp2(IRB); -// for (int i = 0; i < 80; i++) { -// double E = pow(10, 15 + i * 0.1) * eV; -// c.current.setEnergy(E); -// epp2.process(&c); -// EXPECT_TRUE(c.current.getEnergy() < E); -// } -// -// ElectronPairProduction epp3(CMB_IRB); -// for (int i = 0; i < 80; i++) { -// double E = pow(10, 15 + i * 0.1) * eV; -// c.current.setEnergy(E); -// epp3.process(&c); -// EXPECT_TRUE(c.current.getEnergy() < E); -// } -//} - -//TEST(ElectronPairProduction, BelowEnergyTreshold) { -// // Test if nothing happens below 1e15 eV -// ElectronPairProduction epp(CMB); -// Candidate c; -// c.current.setId(nucleusId(1, 1)); // proton -// double E = 1e14 * eV; -// c.current.setEnergy(E); -// epp.process(&c); -// EXPECT_DOUBLE_EQ(c.current.getEnergy(), E); -//} -// -//TEST(ElectronPairProduction, NoNucleus) { -// // Test if non-nuclei are skipped -// ElectronPairProduction epp(CMB); -// Candidate c; -// c.current.setId(11); // electron -// double E = 1e20 * eV; -// c.current.setEnergy(E); -// epp.process(&c); -// EXPECT_DOUBLE_EQ(c.current.getEnergy(), E); -//} -// -//TEST(ElectronPairProduction, valuesCMB) { -// // Test if energy loss corresponds to the data table. -// std::vector x; -// std::vector y; -// std::ifstream infile(getDataPath("epair_CMB.txt").c_str()); -// while (infile.good()) { -// if (infile.peek() != '#') { -// double a, b; -// infile >> a >> b; -// if (infile) { -// x.push_back(a * eV); -// y.push_back(b * eV / Mpc); -// } -// } -// infile.ignore(std::numeric_limits::max(), '\n'); -// } -// infile.close(); -// -// Candidate c; -// c.setCurrentStep(1 * Mpc); -// c.current.setId(nucleusId(1, 1)); // proton -// -// ElectronPairProduction epp(CMB); -// for (int i = 0; i < x.size(); i++) { -// c.current.setEnergy(x[i]); -// epp.process(&c); -// double dE = x[i] - c.current.getEnergy(); -// double dE_table = y[i] * 1 * Mpc; -// EXPECT_NEAR(dE, dE_table, 1e-12); -// } -//} -// -//TEST(ElectronPairProduction, valuesIRB) { -// // Test if energy loss corresponds to the data table. -// std::vector x; -// std::vector y; -// std::ifstream infile(getDataPath("epairIRB.txt").c_str()); -// while (infile.good()) { -// if (infile.peek() != '#') { -// double a, b; -// infile >> a >> b; -// if (infile) { -// x.push_back(a * eV); -// y.push_back(b * eV / Mpc); -// } -// } -// infile.ignore(std::numeric_limits::max(), '\n'); -// } -// infile.close(); -// -// Candidate c; -// c.setCurrentStep(1 * Mpc); -// c.current.setId(nucleusId(1, 1)); // proton -// -// ElectronPairProduction epp(IRB); -// for (int i = 0; i < x.size(); i++) { -// c.current.setEnergy(x[i]); -// epp.process(&c); -// double dE = x[i] - c.current.getEnergy(); -// double dE_table = y[i] * 1 * Mpc; -// EXPECT_NEAR(dE, dE_table, 1e-12); -// } -//} -// -//TEST(ElectronPairProduction, valuesCMB_IRB) { -// // Test if energy loss corresponds to the data table. -// std::vector x; -// std::vector y; -// std::ifstream infile(getDataPath("epair_CMB_IRB.txt").c_str()); -// while (infile.good()) { -// if (infile.peek() != '#') { -// double a, b; -// infile >> a >> b; -// if (infile) { -// x.push_back(a * eV); -// y.push_back(b * eV / Mpc); -// } -// } -// infile.ignore(std::numeric_limits::max(), '\n'); -// } -// infile.close(); -// -// Candidate c; -// c.setCurrentStep(1 * Mpc); -// c.current.setId(nucleusId(1, 1)); // proton -// -// ElectronPairProduction epp(CMB_IRB); -// for (int i = 0; i < x.size(); i++) { -// c.current.setEnergy(x[i]); -// epp.process(&c); -// double dE = x[i] - c.current.getEnergy(); -// double dE_table = y[i] * 1 * Mpc; -// EXPECT_NEAR(dE, dE_table, 1e-12); -// } -//} -// -//TEST(NuclearDecay, Neutron) { -// // Quantitative test of decaying neutrons at rest. -// // The mean decay time is expected to be within 1% of the literature value. -// // This test can stochastically fail. -// Candidate candidate; -// candidate.current.setId(nucleusId(1, 0)); -// candidate.current.setEnergy(mass_neutron * c_squared); -// NuclearDecay decay; -// InteractionState state; -// double tau = 0; -// for (int i = 0; i < 100000; i++) { -// decay.setNextInteraction(&candidate, state); -// tau += state.distance; -// } -// tau /= c_light * 100000; -// EXPECT_NEAR(tau, 881.46, 8.8); -//} -// -//TEST(NuclearDecay, Scandium44) { -// // Test beta+ decay of 44Sc 44Ca. -// // This test can stochastically fail. -// NuclearDecay d(true, true); -// Candidate c; -// c.setCurrentStep(1 * Mpc); -// c.current.setId(nucleusId(44, 21)); -// c.current.setEnergy(1 * EeV); -// double gamma = c.current.getLorentzFactor(); -// d.process(&c); -// // primary -// EXPECT_EQ(nucleusId(44,20), c.current.getId()); -// EXPECT_DOUBLE_EQ(gamma, c.current.getLorentzFactor()); -// // secondaries -// EXPECT_EQ(2, c.secondaries.size()); -// Candidate c1 = *c.secondaries[0]; -// Candidate c2 = *c.secondaries[1]; -// EXPECT_EQ(-11, c1.current.getId()); -// // positron -// EXPECT_EQ( 12, c2.current.getId()); -// // electron neutrino -//} -// -//TEST(NuclearDecay, Li4) { -// // Test proton dripping of Li-4 to He-3. -// // This test can stochastically fail. -// NuclearDecay d; -// Candidate c; -// c.setCurrentStep(1 * kpc); -// c.current.setId(nucleusId(4, 3)); -// c.current.setEnergy(4 * EeV); -// d.process(&c); -// // primary -// EXPECT_EQ(nucleusId(3,2), c.current.getId()); -// EXPECT_EQ(1, c.secondaries.size()); -// // secondary -// Candidate c1 = *c.secondaries[0]; -// EXPECT_EQ(nucleusId(1,1), c1.current.getId()); -// EXPECT_EQ(1, c1.current.getEnergy() / EeV); -//} -// -//TEST(NuclearDecay, He5) { -// // Test neturon dripping of He-5 to He-4. -// // This test can stochastically fail if no interaction occurs over 1 Mpc. -// NuclearDecay d; -// Candidate c; -// c.setCurrentStep(1 * Mpc); -// c.current.setId(nucleusId(5, 2)); -// c.current.setEnergy(5 * EeV); -// d.process(&c); -// // primary -// EXPECT_EQ(nucleusId(4,2), c.current.getId()); -// EXPECT_EQ(4, c.current.getEnergy() / EeV); -// // secondary -// Candidate c2 = *c.secondaries[0]; -// EXPECT_EQ(nucleusId(1,0), c2.current.getId()); -// EXPECT_EQ(1, c2.current.getEnergy() / EeV); -//} -// -//TEST(NuclearDecay, LimitNextStep) { -// // Test if next step is limited. -// NuclearDecay d; -// Candidate c; -// c.setNextStep(std::numeric_limits::max()); -// c.current.setId(nucleusId(1, 0)); -// c.current.setEnergy(10 * EeV); -// d.process(&c); -// EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); -//} -// -//TEST(NuclearDecay, AllWorking) { -// // Test if all nuclear decays are working. -// NuclearDecay d; -// Candidate c; -// InteractionState interaction; -// -// std::ifstream infile(getDataPath("nuclear_decay.txt").c_str()); -// while (infile.good()) { -// if (infile.peek() != '#') { -// int Z, N, channel, foo; -// infile >> Z >> N >> interaction.channel >> foo; -// -// c.current.setId(nucleusId(Z + N, Z)); -// c.current.setEnergy(80 * EeV); -// c.setInteractionState(d.getDescription(), interaction); -// d.performInteraction(&c); -// } -// infile.ignore(std::numeric_limits::max(), '\n'); -// } -// infile.close(); -//} -// -//TEST(NuclearDecay, NoNucleus) { -// // Test if non-nuclei are skipped -// Candidate c; -// c.setNextStep(std::numeric_limits::max()); -// c.current.setId(11); // electron -// c.current.setEnergy(10 * EeV); -// -// NuclearDecay d; -// InteractionState state; -// EXPECT_FALSE(d.setNextInteraction(&c, state)); -// EXPECT_EQ(0, state.channel); -//} -// -//TEST(PhotoDisintegration, Carbon) { -// // Test if a 100 EeV C-12 nucleus photo-disintegrates (at least once) over a distance of 50 Mpc. -// // This test can stochastically fail if no interaction occurs over 50 Mpc. -// PhotoDisintegration pd; -// Candidate c; -// c.current.setId(nucleusId(12, 6)); -// c.current.setEnergy(100 * EeV); -// c.setCurrentStep(50 * Mpc); -// pd.process(&c); -// -// EXPECT_TRUE(c.current.getEnergy() < 100 * EeV); -// // energy loss -// EXPECT_TRUE(c.secondaries.size() > 0); -// // secondaries produced -// -// int A = c.current.getMassNumber(); -// int Z = c.current.getChargeNumber(); -// double E = c.current.getEnergy(); -// -// for (int i = 0; i < c.secondaries.size(); i++) { -// A += (*c.secondaries[i]).current.getMassNumber(); -// Z += (*c.secondaries[i]).current.getChargeNumber(); -// E += (*c.secondaries[i]).current.getEnergy(); -// } -// EXPECT_EQ(12, A); -// // nucleon number conserved -// EXPECT_EQ(6, Z); -// // proton number conserved -// EXPECT_DOUBLE_EQ(100 * EeV, E); -// // energy conserved -//} -// -//TEST(PhotoDisintegration, Iron) { -// // Test if a 100 EeV Fe-56 nucleus photo-disintegrates (at least once) over a distance of 50 Mpc. -// // This test can stochastically fail if no interaction occurs over 50 Mpc. -// PhotoDisintegration pd(IRB); -// Candidate c; -// c.current.setId(nucleusId(56, 26)); -// c.current.setEnergy(100 * EeV); -// c.setCurrentStep(50 * Mpc); -// pd.process(&c); -// -// EXPECT_TRUE(c.current.getEnergy() < 100 * EeV); -// // energy loss -// EXPECT_TRUE(c.secondaries.size() > 0); -// // secondaries produced -// -// int A = c.current.getMassNumber(); -// int Z = c.current.getChargeNumber(); -// double E = c.current.getEnergy(); -// -// for (int i = 0; i < c.secondaries.size(); i++) { -// A += (*c.secondaries[i]).current.getMassNumber(); -// Z += (*c.secondaries[i]).current.getChargeNumber(); -// E += (*c.secondaries[i]).current.getEnergy(); -// } -// EXPECT_EQ(56, A); -// // nucleon number conserved -// EXPECT_EQ(26, Z); -// // proton number conserved -// EXPECT_DOUBLE_EQ(100 * EeV, E); -// // energy conserved -//} -// -//TEST(PhotoDisintegration, NoNucleus) { -// // Test if non-nuclei are skipped -// Candidate c; -// c.setNextStep(std::numeric_limits::max()); -// c.current.setId(11); // electron -// c.current.setEnergy(10 * EeV); -// -// PhotoDisintegration module; -// InteractionState state; -// EXPECT_FALSE(module.setNextInteraction(&c, state)); -// EXPECT_EQ(0, state.channel); -//} -// -//TEST(PhotoDisintegration, LimitNextStep) { -// // Test if the interaction limits the next propagation step. -// PhotoDisintegration pd; -// Candidate c; -// c.setNextStep(std::numeric_limits::max()); -// c.current.setId(nucleusId(4, 2)); -// c.current.setEnergy(200 * EeV); -// pd.process(&c); -// EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); -//} -// -//TEST(PhotoDisintegration, AllWorkingCMB) { -// // Test if all photo-disintegrations are working. -// PhotoDisintegration pd(CMB); -// Candidate c; -// InteractionState interaction; -// -// std::ifstream infile( -// getDataPath("photodis_CMB.txt").c_str()); -// std::string line; -// while (std::getline(infile, line)) { -// if (line[0] == '#') -// continue; -// std::stringstream lineStream(line); -// int Z, N; -// lineStream >> Z; -// lineStream >> N; -// lineStream >> interaction.channel; -// -// double y; -// for (size_t i = 0; i < 200; i++) { -// lineStream >> y; -// EXPECT_TRUE(lineStream); -// // test if all 200 entries are present -// } -// -// c.current.setId(nucleusId(Z + N, Z)); -// c.current.setEnergy(80 * EeV); -// c.setInteractionState(pd.getDescription(), interaction); -// pd.performInteraction(&c); -// } -// infile.close(); -//} -// -//TEST(PhotoDisintegration, AllWorkingIRB) { -// // Test if all photo-disintegrations are working. -// PhotoDisintegration pd(IRB); -// Candidate c; -// InteractionState interaction; -// -// std::ifstream infile( -// getDataPath("photodis_IRB.txt").c_str()); -// std::string line; -// while (std::getline(infile, line)) { -// if (line[0] == '#') -// continue; -// std::stringstream lineStream(line); -// int Z, N; -// lineStream >> Z; -// lineStream >> N; -// lineStream >> interaction.channel; -// -// double y; -// for (size_t i = 0; i < 200; i++) { -// lineStream >> y; -// EXPECT_TRUE(lineStream); -// // test if all 200 entries are present -// } -// -// c.current.setId(nucleusId(Z + N, Z)); -// c.current.setEnergy(80 * EeV); -// c.setInteractionState(pd.getDescription(), interaction); -// pd.performInteraction(&c); -// } -// infile.close(); -//} -// -//TEST(PhotoPionProduction, Backgrounds) { -// // Test if interaction data files are loaded. -// PhotoPionProduction ppp1(CMB); -// PhotoPionProduction ppp2(IRB); -//} -// -//TEST(PhotoPionProduction, Proton) { -// // Test photo-pion interaction for 100 EeV proton. -// // This test can stochastically fail if no interaction occurs over 100 Mpc. -// PhotoPionProduction ppp; -// Candidate c; -// c.setCurrentStep(100 * Mpc); -// c.current.setId(nucleusId(1, 1)); -// c.current.setEnergy(100 * EeV); -// ppp.process(&c); -// EXPECT_TRUE(c.current.getEnergy() / EeV < 100); -// // energy loss -// EXPECT_EQ(1, c.current.getMassNumber()); -// // nucleon number conserved -// EXPECT_EQ(0, c.secondaries.size()); -// // no (nucleonic) secondaries -//} -// -//TEST(PhotoPionProduction, Helium) { -// // Test photo-pion interaction for 400 EeV He nucleus. -// // This test can stochastically fail if no interaction occurs over 100 Mpc. -// PhotoPionProduction ppp; -// Candidate c; -// c.setCurrentStep(100 * Mpc); -// c.current.setId(nucleusId(4, 2)); -// c.current.setEnergy(400 * EeV); -// ppp.process(&c); -// EXPECT_LT(c.current.getEnergy(), 400 * EeV); -// EXPECT_TRUE(c.current.getMassNumber() < 4); -// EXPECT_TRUE(c.secondaries.size() > 0); -//} -// -//TEST(PhotoPionProduction, NoNucleus) { -// // Test if non-nuclei are skipped -// Candidate c; -// c.setNextStep(std::numeric_limits::max()); -// c.current.setId(11); // electron -// c.current.setEnergy(10 * EeV); -// -// PhotoPionProduction module; -// InteractionState state; -// EXPECT_FALSE(module.setNextInteraction(&c, state)); -// EXPECT_EQ(0, state.channel); -//} -// -//TEST(PhotoPionProduction, LimitNextStep) { -// // Test if the interaction limits the next propagation step. -// PhotoPionProduction ppp; -// Candidate c; -// c.setNextStep(std::numeric_limits::max()); -// c.current.setId(nucleusId(1, 1)); -// c.current.setEnergy(200 * EeV); -// ppp.process(&c); -// EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); -//} -// -//TEST(SophiaPhotoPionProduction, withoutSecondaries) { -// // Test photo-pion (SOPHIA) interaction for 100 EeV proton. -// // This test can stochastically fail if no interaction occurs over 100 Mpc. -// SophiaPhotoPionProduction ppp; -// Candidate c; -// c.setCurrentStep(100 * Mpc); -// c.current.setId(nucleusId(1, 1)); -// c.current.setEnergy(100 * EeV); -// ppp.process(&c); -// EXPECT_GT(100 * EeV, c.current.getEnergy()); -// // energy loss -// EXPECT_EQ(1, c.current.getMassNumber()); -// // nucleon number conserved -// EXPECT_EQ(0, c.secondaries.size()); -// // secondaries turned off -//} -// -//TEST(SophiaPhotoPionProduction, withSecondaries) { -// // Test photo-pion interaction for 100 EeV proton. -// // This test can stochastically fail if no interaction occurs over 100 Mpc. -// SophiaPhotoPionProduction ppp(CMB, true, true, true); -// Candidate c; -// c.current.setId(nucleusId(1, 1)); -// c.current.setEnergy(100 * EeV); -// InteractionState interaction; -// ppp.setNextInteraction(&c, interaction); -// ppp.performInteraction(&c); -// EXPECT_GT(c.secondaries.size(), 1); -// // secondaries turned on -//} +TEST(ElectronPairProduction, EnergyDecreasing) { + // Test if energy loss occurs for protons with energies from 1e15 - 1e23 eV + Candidate c; + c.setCurrentStep(1 * Mpc); + c.current.setId(nucleusId(1, 1)); // proton + + ElectronPairProduction epp1(CMB); + for (int i = 0; i < 80; i++) { + double E = pow(10, 15 + i * 0.1) * eV; + c.current.setEnergy(E); + epp1.process(&c); + EXPECT_TRUE(c.current.getEnergy() <= E); + } + + ElectronPairProduction epp2(IRB); + for (int i = 0; i < 80; i++) { + double E = pow(10, 15 + i * 0.1) * eV; + c.current.setEnergy(E); + epp2.process(&c); + EXPECT_TRUE(c.current.getEnergy() < E); + } + + ElectronPairProduction epp3(CMB_IRB); + for (int i = 0; i < 80; i++) { + double E = pow(10, 15 + i * 0.1) * eV; + c.current.setEnergy(E); + epp3.process(&c); + EXPECT_TRUE(c.current.getEnergy() < E); + } +} + +TEST(ElectronPairProduction, BelowEnergyTreshold) { + // Test if nothing happens below 1e15 eV + ElectronPairProduction epp(CMB); + Candidate c; + c.current.setId(nucleusId(1, 1)); // proton + double E = 1e14 * eV; + c.current.setEnergy(E); + epp.process(&c); + EXPECT_DOUBLE_EQ(c.current.getEnergy(), E); +} + +TEST(ElectronPairProduction, NoNucleus) { + // Test if non-nuclei are skipped + ElectronPairProduction epp(CMB); + Candidate c; + c.current.setId(11); // electron + double E = 1e20 * eV; + c.current.setEnergy(E); + epp.process(&c); + EXPECT_DOUBLE_EQ(c.current.getEnergy(), E); +} + +TEST(ElectronPairProduction, valuesCMB) { + // Test if energy loss corresponds to the data table. + std::vector x; + std::vector y; + std::ifstream infile(getDataPath("epair_CMB.txt").c_str()); + while (infile.good()) { + if (infile.peek() != '#') { + double a, b; + infile >> a >> b; + if (infile) { + x.push_back(a * eV); + y.push_back(b * eV / Mpc); + } + } + infile.ignore(std::numeric_limits::max(), '\n'); + } + infile.close(); + + Candidate c; + c.setCurrentStep(1 * Mpc); + c.current.setId(nucleusId(1, 1)); // proton + + ElectronPairProduction epp(CMB); + for (int i = 0; i < x.size(); i++) { + c.current.setEnergy(x[i]); + epp.process(&c); + double dE = x[i] - c.current.getEnergy(); + double dE_table = y[i] * 1 * Mpc; + EXPECT_NEAR(dE, dE_table, 1e-12); + } +} + +TEST(ElectronPairProduction, valuesIRB) { + // Test if energy loss corresponds to the data table. + std::vector x; + std::vector y; + std::ifstream infile(getDataPath("epairIRB.txt").c_str()); + while (infile.good()) { + if (infile.peek() != '#') { + double a, b; + infile >> a >> b; + if (infile) { + x.push_back(a * eV); + y.push_back(b * eV / Mpc); + } + } + infile.ignore(std::numeric_limits::max(), '\n'); + } + infile.close(); + + Candidate c; + c.setCurrentStep(1 * Mpc); + c.current.setId(nucleusId(1, 1)); // proton + + ElectronPairProduction epp(IRB); + for (int i = 0; i < x.size(); i++) { + c.current.setEnergy(x[i]); + epp.process(&c); + double dE = x[i] - c.current.getEnergy(); + double dE_table = y[i] * 1 * Mpc; + EXPECT_NEAR(dE, dE_table, 1e-12); + } +} + +TEST(ElectronPairProduction, valuesCMB_IRB) { + // Test if energy loss corresponds to the data table. + std::vector x; + std::vector y; + std::ifstream infile(getDataPath("epair_CMB_IRB.txt").c_str()); + while (infile.good()) { + if (infile.peek() != '#') { + double a, b; + infile >> a >> b; + if (infile) { + x.push_back(a * eV); + y.push_back(b * eV / Mpc); + } + } + infile.ignore(std::numeric_limits::max(), '\n'); + } + infile.close(); + + Candidate c; + c.setCurrentStep(1 * Mpc); + c.current.setId(nucleusId(1, 1)); // proton + + ElectronPairProduction epp(CMB_IRB); + for (int i = 0; i < x.size(); i++) { + c.current.setEnergy(x[i]); + epp.process(&c); + double dE = x[i] - c.current.getEnergy(); + double dE_table = y[i] * 1 * Mpc; + EXPECT_NEAR(dE, dE_table, 1e-12); + } +} + +TEST(NuclearDecay, Neutron) { + // Quantitative test of decaying neutrons at rest. + // The mean decay time is expected to be within 1% of the literature value. + // This test can stochastically fail. + Candidate candidate; + candidate.current.setId(nucleusId(1, 0)); + candidate.current.setEnergy(mass_neutron * c_squared); + NuclearDecay decay; + InteractionState state; + double tau = 0; + for (int i = 0; i < 100000; i++) { + decay.setNextInteraction(&candidate, state); + tau += state.distance; + } + tau /= c_light * 100000; + EXPECT_NEAR(tau, 881.46, 8.8); +} + +TEST(NuclearDecay, Scandium44) { + // Test beta+ decay of 44Sc 44Ca. + // This test can stochastically fail. + NuclearDecay d(true, true); + Candidate c; + c.setCurrentStep(1 * Mpc); + c.current.setId(nucleusId(44, 21)); + c.current.setEnergy(1 * EeV); + double gamma = c.current.getLorentzFactor(); + d.process(&c); + // primary + EXPECT_EQ(nucleusId(44,20), c.current.getId()); + EXPECT_DOUBLE_EQ(gamma, c.current.getLorentzFactor()); + // secondaries + EXPECT_EQ(2, c.secondaries.size()); + Candidate c1 = *c.secondaries[0]; + Candidate c2 = *c.secondaries[1]; + EXPECT_EQ(-11, c1.current.getId()); + // positron + EXPECT_EQ( 12, c2.current.getId()); + // electron neutrino +} + +TEST(NuclearDecay, Li4) { + // Test proton dripping of Li-4 to He-3. + // This test can stochastically fail. + NuclearDecay d; + Candidate c; + c.setCurrentStep(1 * kpc); + c.current.setId(nucleusId(4, 3)); + c.current.setEnergy(4 * EeV); + d.process(&c); + // primary + EXPECT_EQ(nucleusId(3,2), c.current.getId()); + EXPECT_EQ(1, c.secondaries.size()); + // secondary + Candidate c1 = *c.secondaries[0]; + EXPECT_EQ(nucleusId(1,1), c1.current.getId()); + EXPECT_EQ(1, c1.current.getEnergy() / EeV); +} + +TEST(NuclearDecay, He5) { + // Test neturon dripping of He-5 to He-4. + // This test can stochastically fail if no interaction occurs over 1 Mpc. + NuclearDecay d; + Candidate c; + c.setCurrentStep(1 * Mpc); + c.current.setId(nucleusId(5, 2)); + c.current.setEnergy(5 * EeV); + d.process(&c); + // primary + EXPECT_EQ(nucleusId(4,2), c.current.getId()); + EXPECT_EQ(4, c.current.getEnergy() / EeV); + // secondary + Candidate c2 = *c.secondaries[0]; + EXPECT_EQ(nucleusId(1,0), c2.current.getId()); + EXPECT_EQ(1, c2.current.getEnergy() / EeV); +} + +TEST(NuclearDecay, LimitNextStep) { + // Test if next step is limited. + NuclearDecay d; + Candidate c; + c.setNextStep(std::numeric_limits::max()); + c.current.setId(nucleusId(1, 0)); + c.current.setEnergy(10 * EeV); + d.process(&c); + EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); +} + +TEST(NuclearDecay, AllWorking) { + // Test if all nuclear decays are working. + NuclearDecay d; + Candidate c; + InteractionState interaction; + + std::ifstream infile(getDataPath("nuclear_decay.txt").c_str()); + while (infile.good()) { + if (infile.peek() != '#') { + int Z, N, channel, foo; + infile >> Z >> N >> interaction.channel >> foo; + + c.current.setId(nucleusId(Z + N, Z)); + c.current.setEnergy(80 * EeV); + c.setInteractionState(d.getDescription(), interaction); + d.performInteraction(&c); + } + infile.ignore(std::numeric_limits::max(), '\n'); + } + infile.close(); +} + +TEST(NuclearDecay, NoNucleus) { + // Test if non-nuclei are skipped + Candidate c; + c.setNextStep(std::numeric_limits::max()); + c.current.setId(11); // electron + c.current.setEnergy(10 * EeV); + + NuclearDecay d; + InteractionState state; + EXPECT_FALSE(d.setNextInteraction(&c, state)); + EXPECT_EQ(0, state.channel); +} + +TEST(PhotoDisintegration, Carbon) { + // Test if a 100 EeV C-12 nucleus photo-disintegrates (at least once) over a distance of 50 Mpc. + // This test can stochastically fail if no interaction occurs over 50 Mpc. + PhotoDisintegration pd; + Candidate c; + c.current.setId(nucleusId(12, 6)); + c.current.setEnergy(100 * EeV); + c.setCurrentStep(50 * Mpc); + pd.process(&c); + + EXPECT_TRUE(c.current.getEnergy() < 100 * EeV); + // energy loss + EXPECT_TRUE(c.secondaries.size() > 0); + // secondaries produced + + int A = c.current.getMassNumber(); + int Z = c.current.getChargeNumber(); + double E = c.current.getEnergy(); + + for (int i = 0; i < c.secondaries.size(); i++) { + A += (*c.secondaries[i]).current.getMassNumber(); + Z += (*c.secondaries[i]).current.getChargeNumber(); + E += (*c.secondaries[i]).current.getEnergy(); + } + EXPECT_EQ(12, A); + // nucleon number conserved + EXPECT_EQ(6, Z); + // proton number conserved + EXPECT_DOUBLE_EQ(100 * EeV, E); + // energy conserved +} + +TEST(PhotoDisintegration, Iron) { + // Test if a 100 EeV Fe-56 nucleus photo-disintegrates (at least once) over a distance of 50 Mpc. + // This test can stochastically fail if no interaction occurs over 50 Mpc. + PhotoDisintegration pd(IRB); + Candidate c; + c.current.setId(nucleusId(56, 26)); + c.current.setEnergy(100 * EeV); + c.setCurrentStep(50 * Mpc); + pd.process(&c); + + EXPECT_TRUE(c.current.getEnergy() < 100 * EeV); + // energy loss + EXPECT_TRUE(c.secondaries.size() > 0); + // secondaries produced + + int A = c.current.getMassNumber(); + int Z = c.current.getChargeNumber(); + double E = c.current.getEnergy(); + + for (int i = 0; i < c.secondaries.size(); i++) { + A += (*c.secondaries[i]).current.getMassNumber(); + Z += (*c.secondaries[i]).current.getChargeNumber(); + E += (*c.secondaries[i]).current.getEnergy(); + } + EXPECT_EQ(56, A); + // nucleon number conserved + EXPECT_EQ(26, Z); + // proton number conserved + EXPECT_DOUBLE_EQ(100 * EeV, E); + // energy conserved +} + +TEST(PhotoDisintegration, NoNucleus) { + // Test if non-nuclei are skipped + Candidate c; + c.setNextStep(std::numeric_limits::max()); + c.current.setId(11); // electron + c.current.setEnergy(10 * EeV); + + PhotoDisintegration module; + InteractionState state; + EXPECT_FALSE(module.setNextInteraction(&c, state)); + EXPECT_EQ(0, state.channel); +} + +TEST(PhotoDisintegration, LimitNextStep) { + // Test if the interaction limits the next propagation step. + PhotoDisintegration pd; + Candidate c; + c.setNextStep(std::numeric_limits::max()); + c.current.setId(nucleusId(4, 2)); + c.current.setEnergy(200 * EeV); + pd.process(&c); + EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); +} + +TEST(PhotoDisintegration, AllWorkingCMB) { + // Test if all photo-disintegrations are working. + PhotoDisintegration pd(CMB); + Candidate c; + InteractionState interaction; + + std::ifstream infile( + getDataPath("photodis_CMB.txt").c_str()); + std::string line; + while (std::getline(infile, line)) { + if (line[0] == '#') + continue; + std::stringstream lineStream(line); + int Z, N; + lineStream >> Z; + lineStream >> N; + lineStream >> interaction.channel; + + double y; + for (size_t i = 0; i < 200; i++) { + lineStream >> y; + EXPECT_TRUE(lineStream); + // test if all 200 entries are present + } + + c.current.setId(nucleusId(Z + N, Z)); + c.current.setEnergy(80 * EeV); + c.setInteractionState(pd.getDescription(), interaction); + pd.performInteraction(&c); + } + infile.close(); +} + +TEST(PhotoDisintegration, AllWorkingIRB) { + // Test if all photo-disintegrations are working. + PhotoDisintegration pd(IRB); + Candidate c; + InteractionState interaction; + + std::ifstream infile( + getDataPath("photodis_IRB.txt").c_str()); + std::string line; + while (std::getline(infile, line)) { + if (line[0] == '#') + continue; + std::stringstream lineStream(line); + int Z, N; + lineStream >> Z; + lineStream >> N; + lineStream >> interaction.channel; + + double y; + for (size_t i = 0; i < 200; i++) { + lineStream >> y; + EXPECT_TRUE(lineStream); + // test if all 200 entries are present + } + + c.current.setId(nucleusId(Z + N, Z)); + c.current.setEnergy(80 * EeV); + c.setInteractionState(pd.getDescription(), interaction); + pd.performInteraction(&c); + } + infile.close(); +} + +TEST(PhotoPionProduction, Backgrounds) { + // Test if interaction data files are loaded. + PhotoPionProduction ppp1(CMB); + PhotoPionProduction ppp2(IRB); +} + +TEST(PhotoPionProduction, Proton) { + // Test photo-pion interaction for 100 EeV proton. + // This test can stochastically fail if no interaction occurs over 100 Mpc. + PhotoPionProduction ppp; + Candidate c; + c.setCurrentStep(100 * Mpc); + c.current.setId(nucleusId(1, 1)); + c.current.setEnergy(100 * EeV); + ppp.process(&c); + EXPECT_TRUE(c.current.getEnergy() / EeV < 100); + // energy loss + EXPECT_EQ(1, c.current.getMassNumber()); + // nucleon number conserved + EXPECT_EQ(0, c.secondaries.size()); + // no (nucleonic) secondaries +} + +TEST(PhotoPionProduction, Helium) { + // Test photo-pion interaction for 400 EeV He nucleus. + // This test can stochastically fail if no interaction occurs over 100 Mpc. + PhotoPionProduction ppp; + Candidate c; + c.setCurrentStep(100 * Mpc); + c.current.setId(nucleusId(4, 2)); + c.current.setEnergy(400 * EeV); + ppp.process(&c); + EXPECT_LT(c.current.getEnergy(), 400 * EeV); + EXPECT_TRUE(c.current.getMassNumber() < 4); + EXPECT_TRUE(c.secondaries.size() > 0); +} + +TEST(PhotoPionProduction, NoNucleus) { + // Test if non-nuclei are skipped + Candidate c; + c.setNextStep(std::numeric_limits::max()); + c.current.setId(11); // electron + c.current.setEnergy(10 * EeV); + + PhotoPionProduction module; + InteractionState state; + EXPECT_FALSE(module.setNextInteraction(&c, state)); + EXPECT_EQ(0, state.channel); +} + +TEST(PhotoPionProduction, LimitNextStep) { + // Test if the interaction limits the next propagation step. + PhotoPionProduction ppp; + Candidate c; + c.setNextStep(std::numeric_limits::max()); + c.current.setId(nucleusId(1, 1)); + c.current.setEnergy(200 * EeV); + ppp.process(&c); + EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); +} + +TEST(SophiaPhotoPionProduction, withoutSecondaries) { + // Test photo-pion (SOPHIA) interaction for 100 EeV proton. + // This test can stochastically fail if no interaction occurs over 100 Mpc. + SophiaPhotoPionProduction ppp; + Candidate c; + c.setCurrentStep(100 * Mpc); + c.current.setId(nucleusId(1, 1)); + c.current.setEnergy(100 * EeV); + ppp.process(&c); + EXPECT_GT(100 * EeV, c.current.getEnergy()); + // energy loss + EXPECT_EQ(1, c.current.getMassNumber()); + // nucleon number conserved + EXPECT_EQ(0, c.secondaries.size()); + // secondaries turned off +} + +TEST(SophiaPhotoPionProduction, withSecondaries) { + // Test photo-pion interaction for 100 EeV proton. + // This test can stochastically fail if no interaction occurs over 100 Mpc. + SophiaPhotoPionProduction ppp(CMB, true, true, true); + Candidate c; + c.current.setId(nucleusId(1, 1)); + c.current.setEnergy(100 * EeV); + InteractionState interaction; + ppp.setNextInteraction(&c, interaction); + ppp.performInteraction(&c); + EXPECT_GT(c.secondaries.size(), 1); + // secondaries turned on +} TEST(SophiaPhotoPionProduction, belowSophiaEnergyThreshold_CMB) { // The minimum nucleon energy for SOPHIA interactions is ~3.75 EeV against the CMB. From 8a136bd5c2091f11997588b1ee0c03348167b3d0 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 29 Jan 2013 16:30:17 +0100 Subject: [PATCH 0268/1298] python: automated docstring and nice print for modules --- python/mpc.i | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/python/mpc.i b/python/mpc.i index a59a73545..2e1c78bf6 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -1,4 +1,5 @@ %module(directors="1") mpc +%feature("autodoc", "1"); // automatic docstrings %{ // workaround for SWIG < 2.0.5 with GCC >= 4.7 @@ -91,14 +92,6 @@ using std::ptrdiff_t; %template(Vector3d) mpc::Vector3; %template(Vector3f) mpc::Vector3; -%pythoncode %{ -def Vector3__str__(self): - return "(%.4e, %.4e, %.4e)" % (self.x, self.y, self.z) -Vector3d.__str__ = Vector3__str__ -Vector3f.__str__ = Vector3__str__ -%} - - %include "mpc/Referenced.h" %include "mpc/Units.h" %include "mpc/Nucleus.h" @@ -107,7 +100,6 @@ Vector3f.__str__ = Vector3__str__ %include "mpc/Random.h" %include "mpc/ParticleState.h" - %template(CandidateVector) std::vector< mpc::ref_ptr >; %template(CandidateRefPtr) mpc::ref_ptr; %include "mpc/Candidate.h" @@ -116,7 +108,6 @@ Vector3f.__str__ = Vector3__str__ %template(stdModuleList) std::list< mpc::ref_ptr >; %include "mpc/Module.h" - %implicitconv mpc::ref_ptr; %template(MagneticFieldRefPtr) mpc::ref_ptr; %include "mpc/magneticField/MagneticField.h" @@ -132,7 +123,6 @@ Vector3f.__str__ = Vector3__str__ %template(ScalarGridRefPtr) mpc::ref_ptr >; %template(ScalarGrid) mpc::Grid; - %include "mpc/magneticField/MagneticFieldGrid.h" %include "mpc/magneticField/SPHMagneticField.h" %include "mpc/magneticField/JF2012Field.h" @@ -161,3 +151,13 @@ Vector3f.__str__ = Vector3__str__ %template(ModuleListRefPtr) mpc::ref_ptr; %include "mpc/ModuleList.h" + + +// nice python print +%pythoncode %{ +Module.__str__ = Module.getDescription +def Vector3__str__(self): + return "(%.4e, %.4e, %.4e)" % (self.x, self.y, self.z) +Vector3d.__str__ = Vector3__str__ +Vector3f.__str__ = Vector3__str__ +%} From 0b1247c1084b036ec43624fa6751a0bde650bd9f Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 30 Jan 2013 09:28:37 +0100 Subject: [PATCH 0269/1298] changed observer mode in xml steering to be more compliant with CRPropa2 * small observer spheres now always inactivate * large observer sphere are usually given in order of increasing radius and with the same center, though neither is enforced. the first sphere thus inactivates the candidate, all other spheres do not --- src/XmlExecute.cpp | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index b98059030..562a79839 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -447,8 +447,10 @@ void XmlExecute::loadSpheresAroundObserver(xml_node &node) { pos.x = childValue(n, "CoordX_Mpc") * Mpc; pos.y = childValue(n, "CoordY_Mpc") * Mpc; pos.z = childValue(n, "CoordZ_Mpc") * Mpc; - cout << " - Postion: " << pos / Mpc << " Mpc" << endl; - modules.add(new SmallObserverSphere(pos, r, "Detected", "", false)); + cout << " - Postion: " << pos / Mpc << " Mpc"; + cout << ", Detection stops propagation" << endl; + + modules.add(new SmallObserverSphere(pos, r, "Detected", "", true)); } } @@ -456,6 +458,8 @@ void XmlExecute::loadSpheresAroundSource(pugi::xml_node &node) { int nObs = 0; for (xml_node n = node.child("Sphere"); n; n = n.next_sibling("Sphere")) { nObs += 1; + bool makeInactive = (nObs == 1) ? true : false; + Vector3d pos; pos.x = childValue(n, "CoordX_Mpc") * Mpc; pos.y = childValue(n, "CoordY_Mpc") * Mpc; @@ -463,11 +467,15 @@ void XmlExecute::loadSpheresAroundSource(pugi::xml_node &node) { cout << " - Postion: " << pos / Mpc << " Mpc" << endl; double r = childValue(n, "Radius_Mpc") * Mpc; cout << " - Radius: " << r / Mpc << " Mpc" << endl; - modules.add(new LargeObserverSphere(pos, r, "Detected", "", true)); + + if (makeInactive) + cout << " - Detection stops propagation" << endl; + else + cout << " - Detection does not stop propagation" << endl; + + modules.add( + new LargeObserverSphere(pos, r, "Detected", "", makeInactive)); } - if (nObs > 1) - cout << " --> Warning! More than one observer currently not supported. " - << endl; } void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { @@ -572,7 +580,8 @@ void XmlExecute::loadSpectrumComposition(pugi::xml_node &node) { cout << " - Maximum rigidity: " << Rmax / EeV << " EeV" << endl; // combined source spectrum / composition - SourceComposition *composition = new SourceComposition(Emin, Rmax, -alpha); + SourceComposition *composition = new SourceComposition(Emin, Rmax, + -alpha); xml_node p = node.child("Particles"); for (xml_node n = p.child("Species"); n; n = n.next_sibling("Species")) { @@ -651,9 +660,9 @@ void XmlExecute::loadOutput(xml_node &node) { else cout << " --> unknown output type " << "('Events', 'Full Trajectories' or 'None')" << endl; - } + } #ifdef MPC_HAVE_ROOT - else if (format == "ROOT") { + else if (format == "ROOT") { if (type == "Full Trajectories") if (is1D) modules.add(new ROOTTrajectoryOutput1D(filename)); @@ -669,10 +678,11 @@ void XmlExecute::loadOutput(xml_node &node) { else cout << " --> unknown output type " << "('Events', 'Full Trajectories' or 'None')" << endl; - } + } #endif // MPC_HAVE_ROOT - else { - cout << " --> unknown output format. " << " Use 'ASCII' or 'ROOT' (if ROOT is set)" << endl; + else { + cout << " --> unknown output format. " + << " Use 'ASCII' or 'ROOT' (if ROOT is set)" << endl; } } From 1a53a3dcd8c7df50e04f602023952dcda0636562 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 30 Jan 2013 16:00:44 +0100 Subject: [PATCH 0270/1298] fix output bug: CRPropa2 - like and ROOT output modules did not remove the "Detected" flag leading to output in each step changed XML steering behaviour back: Spheres around source do not inactivate candidates refactored observer code --- include/mpc/module/Observer.h | 12 ++-- include/mpc/module/OutputROOT.h | 1 - src/XmlExecute.cpp | 4 +- src/module/Observer.cpp | 96 +++++++++++++++++------------- src/module/Output.cpp | 79 ++++++++++++------------- src/module/OutputCRPropa2.cpp | 8 ++- src/module/OutputROOT.cpp | 102 +++++++++++++++++--------------- test/testBreakCondition.cpp | 20 +------ 8 files changed, 163 insertions(+), 159 deletions(-) diff --git a/include/mpc/module/Observer.h b/include/mpc/module/Observer.h index 91c14fc6a..eac2fe48a 100644 --- a/include/mpc/module/Observer.h +++ b/include/mpc/module/Observer.h @@ -22,9 +22,9 @@ class SmallObserverSphere: public Module { bool makeInactive; public: - SmallObserverSphere(); - SmallObserverSphere(Vector3d center, double radius, std::string flag = - "Detected", std::string flagValue = "", bool makeInactive = true); + SmallObserverSphere(Vector3d center = Vector3d(0.), double radius = 0, + std::string flag = "Detected", std::string flagValue = "", + bool makeInactive = true); void process(Candidate *candidate) const; void setCenter(Vector3d center); void setRadius(double radius); @@ -51,9 +51,9 @@ class LargeObserverSphere: public Module { void updateDescription(); public: - LargeObserverSphere(); - LargeObserverSphere(Vector3d center, double radius, std::string flag = - "Detected", std::string flagValue = "", bool makeInactive = true); + LargeObserverSphere(Vector3d center = Vector3d(0.), double radius = 0, + std::string flag = "Detected", std::string flagValue = "", + bool makeInactive = true); void process(Candidate *candidate) const; void setCenter(Vector3d center); void setRadius(double radius); diff --git a/include/mpc/module/OutputROOT.h b/include/mpc/module/OutputROOT.h index 5b1feeba2..c524ded5f 100644 --- a/include/mpc/module/OutputROOT.h +++ b/include/mpc/module/OutputROOT.h @@ -8,7 +8,6 @@ #include #include - namespace mpc { /** diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 562a79839..f4fdb8558 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -448,9 +448,9 @@ void XmlExecute::loadSpheresAroundObserver(xml_node &node) { pos.y = childValue(n, "CoordY_Mpc") * Mpc; pos.z = childValue(n, "CoordZ_Mpc") * Mpc; cout << " - Postion: " << pos / Mpc << " Mpc"; - cout << ", Detection stops propagation" << endl; + cout << ", Detection does not stop propagation" << endl; - modules.add(new SmallObserverSphere(pos, r, "Detected", "", true)); + modules.add(new SmallObserverSphere(pos, r, "Detected", "", false)); } } diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp index d4c040bdf..3c105fb24 100644 --- a/src/module/Observer.cpp +++ b/src/module/Observer.cpp @@ -4,27 +4,34 @@ namespace mpc { -SmallObserverSphere::SmallObserverSphere() : - center(Vector3d(0, 0, 0)), radius(0), flag("Detected"), flagValue(""), makeInactive( - true) { +SmallObserverSphere::SmallObserverSphere(Vector3d center, double radius, + std::string flag, std::string flagValue, bool makeInactive) : + center(center), radius(radius), flag(flag), flagValue(flagValue), makeInactive( + makeInactive) { } -SmallObserverSphere::SmallObserverSphere(Vector3d c, double r, std::string f, - std::string v, bool b) : - center(c), radius(r), flag(f), flagValue(v), makeInactive(b) { -} +void SmallObserverSphere::process(Candidate *candidate) const { + // current distance to observer sphere center + double d = (candidate->current.getPosition() - center).getMag(); -void SmallObserverSphere::process(Candidate *c) const { - double d = (c->current.getPosition() - center).getMag(); - if (d <= radius) { - double dprev = (c->previous.getPosition() - center).getMag(); - if (dprev > radius) { - c->setProperty(flag, flagValue); - if (makeInactive) - c->setActive(false); - } - } - c->limitNextStep(fabs(d - radius)); + // conservatively limit next step to prevent overshooting + candidate->limitNextStep(fabs(d - radius)); + + // no detection if outside of observer sphere + if (d > radius) + return; + + // previous distance to observer sphere center + double dprev = (candidate->previous.getPosition() - center).getMag(); + + // if particle was inside of sphere in previous step it has already been detected + if (dprev <= radius) + return; + + // else: detection + candidate->setProperty(flag, flagValue); + if (makeInactive) + candidate->setActive(false); } void SmallObserverSphere::setCenter(Vector3d c) { @@ -54,27 +61,34 @@ std::string SmallObserverSphere::getDescription() const { return s.str(); } -LargeObserverSphere::LargeObserverSphere() : - center(Vector3d(0, 0, 0)), radius(0), flag("Detected"), flagValue(""), makeInactive( - true) { +LargeObserverSphere::LargeObserverSphere(Vector3d center, double radius, + std::string flag, std::string flagValue, bool makeInactive) : + center(center), radius(radius), flag(flag), flagValue(flagValue), makeInactive( + makeInactive) { } -LargeObserverSphere::LargeObserverSphere(Vector3d c, double r, std::string f, - std::string v, bool b) : - center(c), radius(r), flag(f), flagValue(v), makeInactive(b) { -} +void LargeObserverSphere::process(Candidate *candidate) const { + // current distance to observer sphere center + double d = (candidate->current.getPosition() - center).getMag(); -void LargeObserverSphere::process(Candidate *c) const { - double d = (c->current.getPosition() - center).getMag(); - if (d >= radius) { - double dprev = (c->previous.getPosition() - center).getMag(); - if (dprev < radius) { - c->setProperty(flag, flagValue); - if (makeInactive) - c->setActive(false); - } - } - c->limitNextStep(fabs(radius - d)); + // conservatively limit next step size to prevent overshooting + candidate->limitNextStep(fabs(radius - d)); + + // no detection if inside observer sphere + if (d < radius) + return; + + // previous distance to observer sphere center + double dprev = (candidate->previous.getPosition() - center).getMag(); + + // if particle was outside of sphere in previous step it has already been detected + if (dprev >= radius) + return; + + // else: detection + candidate->setProperty(flag, flagValue); + if (makeInactive) + candidate->setActive(false); } void LargeObserverSphere::setCenter(Vector3d c) { @@ -108,15 +122,15 @@ Observer1D::Observer1D() { setDescription("1D observer"); } -void Observer1D::process(Candidate *c) const { - double x = c->current.getPosition().x; +void Observer1D::process(Candidate *candidate) const { + double x = candidate->current.getPosition().x; if (x > 0) { - c->limitNextStep(x); + candidate->limitNextStep(x); return; } // else: detection - c->setProperty("Detected", ""); - c->setActive(false); + candidate->setProperty("Detected", ""); + candidate->setActive(false); } } // namespace mpc diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 1127e6d09..4adc72405 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -86,35 +86,33 @@ void ConditionalOutput::setRemoveProperty(bool b) { } void ConditionalOutput::process(Candidate *c) const { - if (c->hasProperty(condition)) { - if (removeProperty) - c->removeProperty(condition); - - char buffer[256]; - size_t p = 0; - - p += sprintf(buffer + p, "%10i\t", c->current.getId()); - p += sprintf(buffer + p, "%8.4f\t", c->current.getEnergy() / EeV); - const Vector3d &pos = c->current.getPosition() / Mpc; - p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", pos.x, pos.y, pos.z); - const Vector3d &dir = c->current.getDirection(); - p += sprintf(buffer + p, "%7.4f\t%7.4f\t", dir.getPhi(), - dir.getTheta()); - p += sprintf(buffer + p, "%9.4f\t", c->getTrajectoryLength() / Mpc); - p += sprintf(buffer + p, "%10i\t", c->initial.getId()); - p += sprintf(buffer + p, "%8.4f\t", c->initial.getEnergy() / EeV); - const Vector3d &ipos = c->initial.getPosition() / Mpc; - p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", ipos.x, ipos.y, - ipos.z); - const Vector3d &idir = c->initial.getDirection(); - p += sprintf(buffer + p, "%7.4f\t%7.4f\n", idir.getPhi(), - idir.getTheta()); + if (not (c->hasProperty(condition))) + return; + + if (removeProperty) + c->removeProperty(condition); + + char buffer[256]; + size_t p = 0; + + p += sprintf(buffer + p, "%10i\t", c->current.getId()); + p += sprintf(buffer + p, "%8.4f\t", c->current.getEnergy() / EeV); + const Vector3d &pos = c->current.getPosition() / Mpc; + p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", pos.x, pos.y, pos.z); + const Vector3d &dir = c->current.getDirection(); + p += sprintf(buffer + p, "%7.4f\t%7.4f\t", dir.getPhi(), dir.getTheta()); + p += sprintf(buffer + p, "%9.4f\t", c->getTrajectoryLength() / Mpc); + p += sprintf(buffer + p, "%10i\t", c->initial.getId()); + p += sprintf(buffer + p, "%8.4f\t", c->initial.getEnergy() / EeV); + const Vector3d &ipos = c->initial.getPosition() / Mpc; + p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", ipos.x, ipos.y, ipos.z); + const Vector3d &idir = c->initial.getDirection(); + p += sprintf(buffer + p, "%7.4f\t%7.4f\n", idir.getPhi(), idir.getTheta()); #pragma omp critical - { - outfile.write(buffer, p); - outfile.flush(); - } + { + outfile.write(buffer, p); + outfile.flush(); } } @@ -158,23 +156,24 @@ EventOutput1D::~EventOutput1D() { } void EventOutput1D::process(Candidate *c) const { - if (c->isActive()) + if (not (c->hasProperty("Detected"))) return; - if (c->hasProperty("Detected")) { - char buffer[256]; - size_t p = 0; - p += sprintf(buffer + p, "%10i\t", c->current.getId()); - p += sprintf(buffer + p, "%8.4f\t", c->current.getEnergy() / EeV); - p += sprintf(buffer + p, "%9.4f\t", c->getTrajectoryLength() / Mpc); - p += sprintf(buffer + p, "%10i\t", c->initial.getId()); - p += sprintf(buffer + p, "%8.4f\n", c->initial.getEnergy() / EeV); + c->removeProperty("Detected"); + + char buffer[256]; + size_t p = 0; + + p += sprintf(buffer + p, "%10i\t", c->current.getId()); + p += sprintf(buffer + p, "%8.4f\t", c->current.getEnergy() / EeV); + p += sprintf(buffer + p, "%9.4f\t", c->getTrajectoryLength() / Mpc); + p += sprintf(buffer + p, "%10i\t", c->initial.getId()); + p += sprintf(buffer + p, "%8.4f\n", c->initial.getEnergy() / EeV); #pragma omp critical - { - outfile.write(buffer, p); - outfile.flush(); - } + { + outfile.write(buffer, p); + outfile.flush(); } } diff --git a/src/module/OutputCRPropa2.cpp b/src/module/OutputCRPropa2.cpp index 55c81cd97..bc7af36ec 100644 --- a/src/module/OutputCRPropa2.cpp +++ b/src/module/OutputCRPropa2.cpp @@ -20,6 +20,9 @@ void CRPropa2EventOutput3D::process(Candidate *c) const { if (not (c->hasProperty("Detected"))) return; + // remove flag so that the particle is not written to output again in the next step + c->removeProperty("Detected"); + char buffer[256]; // max. 256 characters per line size_t p = 0; // length of line @@ -126,11 +129,12 @@ CRPropa2EventOutput1D::~CRPropa2EventOutput1D() { } void CRPropa2EventOutput1D::process(Candidate *c) const { - if (c->isActive()) - return; if (not (c->hasProperty("Detected"))) return; + // remove flag so that the particle is not written to output again in the next step + c->removeProperty("Detected"); + char buffer[256]; size_t p = 0; diff --git a/src/module/OutputROOT.cpp b/src/module/OutputROOT.cpp index fe8830533..69f14c856 100644 --- a/src/module/OutputROOT.cpp +++ b/src/module/OutputROOT.cpp @@ -6,7 +6,7 @@ namespace mpc { /////////////////////// ROOT EVENT OUTPUT 1D ////////////////////////////////// ROOTEventOutput1D::ROOTEventOutput1D(std::string filename) { - TThread::Lock(); + TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); Ntuple = @@ -16,50 +16,50 @@ ROOTEventOutput1D::ROOTEventOutput1D(std::string filename) { } ROOTEventOutput1D::~ROOTEventOutput1D() { - TThread::Lock(); + TThread::Lock(); ROOTFile->Write(); ROOTFile->Close(); - TThread::UnLock(); + TThread::UnLock(); } void ROOTEventOutput1D::process(Candidate *c) const { - if (c->isActive()) + if (not (c->hasProperty("Detected"))) return; - if (c->hasProperty("Detected")) { - TThread::Lock(); + + c->removeProperty("Detected"); + + TThread::Lock(); #pragma omp critical - { - Ntuple->Fill(c->current.getId(), c->initial.getId(), - c->initial.getPosition().getX() / Mpc, c->getRedshift(), - c->initial.getEnergy() / EeV, - c->getTrajectoryLength() / Mpc, - c->current.getEnergy() / EeV); - } - TThread::UnLock(); + { + Ntuple->Fill(c->current.getId(), c->initial.getId(), + c->initial.getPosition().getX() / Mpc, c->getRedshift(), + c->initial.getEnergy() / EeV, c->getTrajectoryLength() / Mpc, + c->current.getEnergy() / EeV); } + TThread::UnLock(); } //////////////////////////////////////////////////////////////////////////////// /////////////////////// ROOT TRAJECTORY OUTPUT 1D ////////////////////////////// ROOTTrajectoryOutput1D::ROOTTrajectoryOutput1D(std::string filename) { - TThread::Lock(); + TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); // Ntuple = new TNtuple("traj","CRPropa 1D trajectories","Particle_Type:Initial_Type:Time_Mpc:Position_Mpc:Energy_EeV"); Ntuple = new TNtuple("traj", "CRPropa 1D trajectories", "Particle_Type:Initial_Type:Time_Mpc:Position_Mpc:Energy_EeV"); - TThread::UnLock(); + TThread::UnLock(); } ROOTTrajectoryOutput1D::~ROOTTrajectoryOutput1D() { - TThread::Lock(); + TThread::Lock(); ROOTFile->Write(); ROOTFile->Close(); - TThread::UnLock(); + TThread::UnLock(); } void ROOTTrajectoryOutput1D::process(Candidate *c) const { - TThread::Lock(); + TThread::Lock(); #pragma omp critical { Ntuple->Fill(c->current.getId(), c->initial.getId(), @@ -67,73 +67,76 @@ void ROOTTrajectoryOutput1D::process(Candidate *c) const { c->current.getPosition().getX() / Mpc, c->current.getEnergy() / EeV); } - TThread::UnLock(); + TThread::UnLock(); } //////////////////////////////////////////////////////////////////////////////// /////////////////////// ROOT EVENT OUTPUT 3D ////////////////////////////////// ROOTEventOutput3D::ROOTEventOutput3D(std::string filename) { - TThread::Lock(); + TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); Ntuple = new TNtuple("events", "CRPropa 3D events", "Particle_Type:Initial_Type:Initial_Position_X_Mpc:Initial_Position_Y_Mpc:Initial_Position_Z_Mpc:Initial_Momentum_E_EeV:Initial_Momentum_theta:Initial_Momentum_phi:Time_Mpc:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Momentum_E_EeV:Momentum_theta:Momentum_phi"); - TThread::UnLock(); + TThread::UnLock(); } ROOTEventOutput3D::~ROOTEventOutput3D() { - TThread::Lock(); + TThread::Lock(); ROOTFile->Write(); ROOTFile->Close(); - TThread::UnLock(); + TThread::UnLock(); } void ROOTEventOutput3D::process(Candidate *c) const { - if (c->hasProperty("Detected")) { - TThread::Lock(); + if (not (c->hasProperty("Detected"))) + return; + + c->removeProperty("Detected"); + + TThread::Lock(); #pragma omp critical - { - Ntuple->Fill(c->current.getId(), c->initial.getId(), - c->initial.getPosition().getX() / Mpc, - c->initial.getPosition().getY() / Mpc, - c->initial.getPosition().getZ() / Mpc, - c->initial.getEnergy() / EeV, - c->initial.getDirection().getTheta(), - c->initial.getDirection().getPhi(), - c->getTrajectoryLength() / Mpc, - c->current.getPosition().getX() / Mpc, - c->current.getPosition().getY() / Mpc, - c->current.getPosition().getZ() / Mpc, - c->current.getEnergy() / EeV, - c->current.getDirection().getTheta(), - c->current.getDirection().getPhi()); - } - TThread::UnLock(); + { + Ntuple->Fill(c->current.getId(), c->initial.getId(), + c->initial.getPosition().getX() / Mpc, + c->initial.getPosition().getY() / Mpc, + c->initial.getPosition().getZ() / Mpc, + c->initial.getEnergy() / EeV, + c->initial.getDirection().getTheta(), + c->initial.getDirection().getPhi(), + c->getTrajectoryLength() / Mpc, + c->current.getPosition().getX() / Mpc, + c->current.getPosition().getY() / Mpc, + c->current.getPosition().getZ() / Mpc, + c->current.getEnergy() / EeV, + c->current.getDirection().getTheta(), + c->current.getDirection().getPhi()); } + TThread::UnLock(); } //////////////////////////////////////////////////////////////////////////////// /////////////////////// ROOT TRAJECTORY OUTPUT 3D ////////////////////////////// ROOTTrajectoryOutput3D::ROOTTrajectoryOutput3D(std::string filename) { - TThread::Lock(); + TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); Ntuple = new TNtuple("traj", "CRPropa 3D trajectories", "Particle_Type:Initial_Type:Time_Mpc:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Direction_X:Direction_Y:Direction_Z:Energy_EeV"); - TThread::UnLock(); + TThread::UnLock(); } ROOTTrajectoryOutput3D::~ROOTTrajectoryOutput3D() { - TThread::Lock(); + TThread::Lock(); ROOTFile->Write(); ROOTFile->Close(); - TThread::UnLock(); + TThread::UnLock(); } void ROOTTrajectoryOutput3D::process(Candidate *c) const { - TThread::Lock(); + TThread::Lock(); #pragma omp critical { Ntuple->Fill(c->current.getId(), c->initial.getId(), @@ -145,9 +148,10 @@ void ROOTTrajectoryOutput3D::process(Candidate *c) const { c->current.getDirection().getY(), c->current.getDirection().getZ(), c->current.getEnergy() / EeV); } - TThread::UnLock(); + TThread::UnLock(); } //////////////////////////////////////////////////////////////////////////////// }// namespace mpc + #endif // MPC_HAVE_ROOT diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index b21f79888..ca4e509ee 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -53,15 +53,7 @@ TEST(MinimumRedshift, test) { } //** ============================= Observers ================================ */ -TEST(SmallObserverSphere, outside) { - SmallObserverSphere obs(Vector3d(0, 0, 0), 1); - Candidate c; - c.current.setPosition(Vector3d(2, 0, 0)); - obs.process(&c); - EXPECT_TRUE(c.isActive()); -} - -TEST(SmallObserverSphere, inside) { +TEST(SmallObserverSphere, detection) { // detect if the current position is inside and the previous outside of the sphere SmallObserverSphere obs(Vector3d(0, 0, 0), 1); Candidate c; @@ -90,15 +82,7 @@ TEST(SmallObserverSphere, limitStep) { EXPECT_DOUBLE_EQ(c.getNextStep(), 1); } -TEST(LargeObserverSphere, inside) { - LargeObserverSphere obs(Vector3d(0, 0, 0), 10); - Candidate c; - c.current.setPosition(Vector3d(0, 5, 5)); - obs.process(&c); - EXPECT_TRUE(c.isActive()); -} - -TEST(LargeObserverSphere, outside) { +TEST(LargeObserverSphere, detection) { // detect if the current position is outside and the previous inside of the sphere LargeObserverSphere obs(Vector3d(0, 0, 0), 10); Candidate c; From 11f369e2f6dfa3412082a8bfc3c6e4a3f998c87f Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Thu, 7 Feb 2013 09:59:53 +0100 Subject: [PATCH 0271/1298] Fixed typo in README --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index f072a3057..c254a2e2b 100644 --- a/README +++ b/README @@ -15,7 +15,7 @@ Notes for Intel Compiler: Install with Python bindings ---------------------------- -To use mpc via python the CMAKE flag ENABLEPYTHON needs to be set to True. +To use mpc via python the CMAKE flag ENABLE_PYTHON needs to be set to True. Additionally the path to mpc.py needs to be added to PYTHONPATH From c232d563ef2e4e3f6fcdb2baacdf468337363a91 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 12 Feb 2013 15:11:22 +0100 Subject: [PATCH 0272/1298] SourceUniformDistributionOnSphere --- include/mpc/Source.h | 13 +++++++++++++ src/Source.cpp | 10 ++++++++++ 2 files changed, 23 insertions(+) diff --git a/include/mpc/Source.h b/include/mpc/Source.h index 8ed1e8ed6..f6df88df1 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -172,6 +172,19 @@ class SourceUniformDistributionSphere: public SourceProperty { void prepare(ParticleState &particle) const; }; +/** + @class SourceUniformDistributionOnSphere + @brief Uniform random source positions on a sphere + */ +class SourceUniformDistributionOnSphere: public SourceProperty { + Vector3d center; + double radius; +public: + SourceUniformDistributionOnSphere(Vector3d center, double radius); + void prepare(ParticleState &particle) const; +}; + + /** @class SourceUniformDistributionBox @brief Uniform random source positions inside a box diff --git a/src/Source.cpp b/src/Source.cpp index 7ababce9b..ae2358829 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -177,6 +177,16 @@ void SourceUniformDistributionSphere::prepare(ParticleState& particle) const { particle.setPosition(random.randUnitVectorOnSphere() * r); } +SourceUniformDistributionOnSphere::SourceUniformDistributionOnSphere( + Vector3d center, double radius) : + center(center), radius(radius) { +} + +void SourceUniformDistributionOnSphere::prepare(ParticleState& particle) const { + Random &random = Random::instance(); + particle.setPosition(random.randUnitVectorOnSphere() * radius); +} + SourceUniformDistributionBox::SourceUniformDistributionBox(Vector3d origin, Vector3d size) : origin(origin), size(size) { From 68d1bddba45d14b13ab6141a595e7f43eb1b26e4 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 1 Feb 2013 15:16:15 +0100 Subject: [PATCH 0273/1298] first unit tests for the output modules --- CMakeLists.txt | 4 +++ include/mpc/module/Output.h | 2 +- src/module/Output.cpp | 8 ++++-- test/testBreakCondition.cpp | 1 - test/testOutput.cpp | 57 +++++++++++++++++++++++++++++++++++++ 5 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 test/testOutput.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0eaed9117..20489aec8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -175,6 +175,10 @@ if(ENABLE_TESTING) target_link_libraries(testBreakCondition mpc gtest gtest_main pthread) add_test(testBreakCondition testBreakCondition) + add_executable(testOutput test/testOutput.cpp) + target_link_libraries(testOutput mpc gtest gtest_main pthread) + add_test(testOutput testOutput) + add_executable(testInteraction test/testInteraction.cpp) target_link_libraries(testInteraction mpc gtest gtest_main pthread) add_test(testInteraction testInteraction) diff --git a/include/mpc/module/Output.h b/include/mpc/module/Output.h index 97e8488b9..965fac025 100644 --- a/include/mpc/module/Output.h +++ b/include/mpc/module/Output.h @@ -40,8 +40,8 @@ class ConditionalOutput: public Module { ConditionalOutput(std::string filename, std::string condition = "Detected", bool removeProperty = true); ~ConditionalOutput(); - void setRemoveProperty(bool removeProperty); void process(Candidate *candidate) const; + void setRemoveProperty(bool removeProperty); }; /** diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 4adc72405..efb047400 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -60,12 +60,14 @@ void TrajectoryOutput::process(Candidate *c) const { ConditionalOutput::ConditionalOutput(std::string filename, std::string propName, bool removeProperty) : - removeProperty(removeProperty) { + removeProperty(removeProperty), condition(propName) { + setDescription( - "Conditional output, condition: " + propName + ", filename: " + "ConditionalOutput, condition: " + propName + ", filename: " + filename); - condition = propName; + outfile.open(filename.c_str()); + outfile << "# PDG_Code\t"; outfile << "Energy[EeV]\t"; outfile << "Position(X,Y,Z)[Mpc]\t"; diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index ca4e509ee..93f8b5ef6 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -3,7 +3,6 @@ #include "mpc/module/BreakCondition.h" #include "mpc/module/Observer.h" #include "mpc/module/Boundary.h" -#include "mpc/Candidate.h" #include "gtest/gtest.h" diff --git a/test/testOutput.cpp b/test/testOutput.cpp new file mode 100644 index 000000000..cf5fac145 --- /dev/null +++ b/test/testOutput.cpp @@ -0,0 +1,57 @@ +/** Unit tests for output modules */ + +#include "mpc/module/Output.h" +#include "mpc/module/OutputCRPropa2.h" +#include "mpc/module/OutputROOT.h" + +#include "gtest/gtest.h" + +using namespace mpc; + +TEST(ConditionalOutput, removeProperty) { + ConditionalOutput output("", "Detected"); + Candidate c; + c.setProperty("Dected", ""); + output.process(&c); + EXPECT_FALSE(c.hasProperty("Detected")); +} + +TEST(EventOutput1D, removeProperty) { + EventOutput1D output(""); + Candidate c; + c.setProperty("Dected", ""); + output.process(&c); + EXPECT_FALSE(c.hasProperty("Detected")); +} + +TEST(CRPropa2EventOutput3D, removeProperty) { + CRPropa2EventOutput3D output(""); + Candidate c; + c.setProperty("Dected", ""); + output.process(&c); + EXPECT_FALSE(c.hasProperty("Detected")); +} + +TEST(CRPropa2EventOutput1D, removeProperty) { + CRPropa2EventOutput1D output(""); + Candidate c; + c.setProperty("Dected", ""); + output.process(&c); + EXPECT_FALSE(c.hasProperty("Detected")); +} + +TEST(ROOTEventOutput3D, removeProperty) { + ROOTEventOutput3D output(""); + Candidate c; + c.setProperty("Dected", ""); + output.process(&c); + EXPECT_FALSE(c.hasProperty("Detected")); +} + +TEST(ROOTEventOutput1D, removeProperty) { + ROOTEventOutput1D output(""); + Candidate c; + c.setProperty("Dected", ""); + output.process(&c); + EXPECT_FALSE(c.hasProperty("Detected")); +} From 2a413676d967883750be28e2612774335a2a2f75 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 8 Feb 2013 14:11:48 +0100 Subject: [PATCH 0274/1298] new headers for mpc ASCII output modules --- include/mpc/module/Output.h | 13 ++--- src/module/Output.cpp | 111 ++++++++++++++++++------------------ 2 files changed, 61 insertions(+), 63 deletions(-) diff --git a/include/mpc/module/Output.h b/include/mpc/module/Output.h index 965fac025..0f8392528 100644 --- a/include/mpc/module/Output.h +++ b/include/mpc/module/Output.h @@ -21,7 +21,7 @@ class ShellOutput: public Module { @brief Saves trajectories to plain text file. */ class TrajectoryOutput: public Module { - mutable std::ofstream outfile; + mutable std::ofstream fout; public: TrajectoryOutput(std::string filename); ~TrajectoryOutput(); @@ -33,15 +33,12 @@ class TrajectoryOutput: public Module { @brief Saves particles with a given property to a plain text file. */ class ConditionalOutput: public Module { - mutable std::ofstream outfile; + mutable std::ofstream fout; std::string condition; - bool removeProperty; public: - ConditionalOutput(std::string filename, std::string condition = "Detected", - bool removeProperty = true); + ConditionalOutput(std::string filename, std::string condition = "Detected"); ~ConditionalOutput(); void process(Candidate *candidate) const; - void setRemoveProperty(bool removeProperty); }; /** @@ -49,7 +46,7 @@ class ConditionalOutput: public Module { @brief Saves 1D trajectories to plain text file. */ class TrajectoryOutput1D: public Module { - mutable std::ofstream outfile; + mutable std::ofstream fout; public: TrajectoryOutput1D(std::string filename); ~TrajectoryOutput1D(); @@ -61,7 +58,7 @@ class TrajectoryOutput1D: public Module { @brief Records particles that are inactive and have the property 'Detected' to a plain text file. */ class EventOutput1D: public Module { - mutable std::ofstream outfile; + mutable std::ofstream fout; public: EventOutput1D(std::string filename); ~EventOutput1D(); diff --git a/src/module/Output.cpp b/src/module/Output.cpp index efb047400..b31b772f6 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -27,16 +27,18 @@ std::string ShellOutput::getDescription() const { TrajectoryOutput::TrajectoryOutput(std::string name) { setDescription("Trajectory output"); - outfile.open(name.c_str()); - outfile << "# Age[Mpc]\t"; - outfile << "PDG_Code\t"; - outfile << "Energy[EeV]\t"; - outfile << "Position(X,Y,Z)[Mpc]\t"; - outfile << "Direction(X,Y,Z)\n"; + fout.open(name.c_str()); + fout << "# D\tID\E\tX\tY\tZ\tPhi\tTheta\n"; + fout << "#\n"; + fout << "# D Comoving trajectory length\n"; + fout << "# ID Particle type\n"; + fout << "# E Energy [EeV]\n"; + fout << "# X, Y, Z Position [Mpc]\n"; + fout << "# Phi, Theta Direction\n"; } TrajectoryOutput::~TrajectoryOutput() { - outfile.close(); + fout.close(); } void TrajectoryOutput::process(Candidate *c) const { @@ -49,50 +51,45 @@ void TrajectoryOutput::process(Candidate *c) const { Vector3d pos = c->current.getPosition() / Mpc; p += sprintf(buffer + p, "%8.4f\t%8.4f\t%8.4f\t", pos.x, pos.y, pos.z); const Vector3d &dir = c->current.getDirection(); - p += sprintf(buffer + p, "%7.4f\t%7.4f\t%7.4f\n", dir.x, dir.y, dir.z); + p += sprintf(buffer + p, "%7.4f\t%7.4f\n", dir.getPhi(), dir.getTheta()); #pragma omp critical { - outfile.write(buffer, p); - outfile.flush(); + fout.write(buffer, p); + fout.flush(); } } -ConditionalOutput::ConditionalOutput(std::string filename, std::string propName, - bool removeProperty) : - removeProperty(removeProperty), condition(propName) { - +ConditionalOutput::ConditionalOutput(std::string fname, std::string cond) : + condition(cond) { setDescription( - "ConditionalOutput, condition: " + propName + ", filename: " - + filename); - - outfile.open(filename.c_str()); - - outfile << "# PDG_Code\t"; - outfile << "Energy[EeV]\t"; - outfile << "Position(X,Y,Z)[Mpc]\t"; - outfile << "Direction(Phi,Theta)\t"; - outfile << "Comoving distance [Mpc]\t"; - outfile << "Initial_PDG_Code\t"; - outfile << "Initial_Energy[EeV]\t"; - outfile << "Initial_Position(X,Y,Z)[Mpc]\t"; - outfile << "Initial_Direction(Phi,Theta)\n"; + "Conditional output, condition: " + cond + ", filename: " + fname); + fout.open(fname.c_str()); + fout << "# ID\tE\tY\tY\tZ\tPhi\tTheta\tD\tID0\tE0\tX0\tY0\tZ0\tPhi0\tTheta0\n"; + fout << "#\n"; + fout << "# Final state:\n"; + fout << "# ID Particle type\n"; + fout << "# E Energy [EeV]\n"; + fout << "# X, Y, Z Position [Mpc]\n"; + fout << "# Phi, Theta Direction\n"; + fout << "# D Comoving trajectory length [Mpc]\n"; + fout << "#\n"; + fout << "# Initial state:\n"; + fout << "# I0 Particle type\n"; + fout << "# E0 Energy [EeV]\n"; + fout << "# X0, Y0, Z0 Position [Mpc]\n"; + fout << "# Phi0, Theta0 Direction\n"; } ConditionalOutput::~ConditionalOutput() { - outfile.close(); -} - -void ConditionalOutput::setRemoveProperty(bool b) { - removeProperty = b; + fout.close(); } void ConditionalOutput::process(Candidate *c) const { if (not (c->hasProperty(condition))) return; - if (removeProperty) - c->removeProperty(condition); + c->removeProperty(condition); char buffer[256]; size_t p = 0; @@ -113,21 +110,23 @@ void ConditionalOutput::process(Candidate *c) const { #pragma omp critical { - outfile.write(buffer, p); - outfile.flush(); + fout.write(buffer, p); + fout.flush(); } } TrajectoryOutput1D::TrajectoryOutput1D(std::string filename) { - setDescription("Trajectory output"); - outfile.open(filename.c_str()); - outfile << "# Position(X)[Mpc]\t"; - outfile << "PDG_Code\t"; - outfile << "Energy[EeV]\n"; + setDescription("TrajectoryOutput, filename: " + filename); + fout.open(filename.c_str()); + fout << "#X\tID\tE\n"; + fout << "#\n"; + fout << "# X Position [Mpc]\n"; + fout << "# ID Particle type\n"; + fout << "# E Energy [EeV]\n"; } TrajectoryOutput1D::~TrajectoryOutput1D() { - outfile.close(); + fout.close(); } void TrajectoryOutput1D::process(Candidate *c) const { @@ -138,23 +137,25 @@ void TrajectoryOutput1D::process(Candidate *c) const { p += sprintf(buffer + p, "%8.4f\n", c->current.getEnergy() / EeV); #pragma omp critical { - outfile.write(buffer, p); - outfile.flush(); + fout.write(buffer, p); + fout.flush(); } } EventOutput1D::EventOutput1D(std::string filename) { - setDescription("Conditional output, Filename: " + filename); - outfile.open(filename.c_str()); - outfile << "# PDG_Code\t"; - outfile << "Energy[EeV]\t"; - outfile << "Age[Mpc]"; - outfile << "Initial_PDG_Code\t"; - outfile << "Initial_Energy[EeV]\n"; + setDescription("Conditional output, filename: " + filename); + fout.open(filename.c_str()); + fout << "#ID\tE\tD\tID0\tE0\n"; + fout << "#\n"; + fout << "# ID Particle type\n"; + fout << "# E Energy [EeV]\n"; + fout << "# D Comoving trajectory length [Mpc]\n"; + fout << "# ID0 Initial particle type\n"; + fout << "# E0 Initial energy [EeV]\n"; } EventOutput1D::~EventOutput1D() { - outfile.close(); + fout.close(); } void EventOutput1D::process(Candidate *c) const { @@ -174,8 +175,8 @@ void EventOutput1D::process(Candidate *c) const { #pragma omp critical { - outfile.write(buffer, p); - outfile.flush(); + fout.write(buffer, p); + fout.flush(); } } From 15388b3a1baab39652520c763c5b3db87e8b7493 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 12 Feb 2013 15:01:46 +0100 Subject: [PATCH 0275/1298] ASCII Output: output of direction as cartesian coordinates instead of angles --- src/module/Output.cpp | 54 ++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/src/module/Output.cpp b/src/module/Output.cpp index b31b772f6..e761caecb 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -28,13 +28,14 @@ std::string ShellOutput::getDescription() const { TrajectoryOutput::TrajectoryOutput(std::string name) { setDescription("Trajectory output"); fout.open(name.c_str()); - fout << "# D\tID\E\tX\tY\tZ\tPhi\tTheta\n"; + fout << "# D\tID\tE\tX\tY\tZ\tPx\tPy\tPz\n"; + fout << "#\n"; + fout << "# D Trajectory length\n"; + fout << "# ID Particle type (PDG MC numbering scheme)\n"; + fout << "# E Energy [EeV]\n"; + fout << "# X, Y, Z Position [Mpc]\n"; + fout << "# Px, Py, Pz Heading (unit vector of momentum)\n"; fout << "#\n"; - fout << "# D Comoving trajectory length\n"; - fout << "# ID Particle type\n"; - fout << "# E Energy [EeV]\n"; - fout << "# X, Y, Z Position [Mpc]\n"; - fout << "# Phi, Theta Direction\n"; } TrajectoryOutput::~TrajectoryOutput() { @@ -45,13 +46,13 @@ void TrajectoryOutput::process(Candidate *c) const { char buffer[1024]; size_t p = 0; - p += sprintf(buffer + p, "%9.4f\t", c->getTrajectoryLength() / Mpc); + p += sprintf(buffer + p, "%8.3f\t", c->getTrajectoryLength() / Mpc); p += sprintf(buffer + p, "%10i\t", c->current.getId()); p += sprintf(buffer + p, "%8.4f\t", c->current.getEnergy() / EeV); Vector3d pos = c->current.getPosition() / Mpc; p += sprintf(buffer + p, "%8.4f\t%8.4f\t%8.4f\t", pos.x, pos.y, pos.z); const Vector3d &dir = c->current.getDirection(); - p += sprintf(buffer + p, "%7.4f\t%7.4f\n", dir.getPhi(), dir.getTheta()); + p += sprintf(buffer + p, "%8.5f\t%8.5f\t%8.5f\n", dir.x, dir.y, dir.z); #pragma omp critical { @@ -65,20 +66,15 @@ ConditionalOutput::ConditionalOutput(std::string fname, std::string cond) : setDescription( "Conditional output, condition: " + cond + ", filename: " + fname); fout.open(fname.c_str()); - fout << "# ID\tE\tY\tY\tZ\tPhi\tTheta\tD\tID0\tE0\tX0\tY0\tZ0\tPhi0\tTheta0\n"; + fout << "# D\tID\tID0\tE\tE0\tX\tY\tZ\tX0\tY0\tZ0\tPx\tPy\tPz\tP0x\tP0y\tP0z\n"; fout << "#\n"; - fout << "# Final state:\n"; - fout << "# ID Particle type\n"; - fout << "# E Energy [EeV]\n"; - fout << "# X, Y, Z Position [Mpc]\n"; - fout << "# Phi, Theta Direction\n"; - fout << "# D Comoving trajectory length [Mpc]\n"; + fout << "# D Trajectory length [Mpc]\n"; + fout << "# ID Particle type (PDG MC numbering scheme)\n"; + fout << "# E Energy [EeV]\n"; + fout << "# X, Y, Z Position [Mpc]\n"; + fout << "# Px, Py, Pz Heading (unit vector of momentum)\n"; + fout << "# Initial state: ID0, E0, ...\n"; fout << "#\n"; - fout << "# Initial state:\n"; - fout << "# I0 Particle type\n"; - fout << "# E0 Energy [EeV]\n"; - fout << "# X0, Y0, Z0 Position [Mpc]\n"; - fout << "# Phi0, Theta0 Direction\n"; } ConditionalOutput::~ConditionalOutput() { @@ -94,19 +90,19 @@ void ConditionalOutput::process(Candidate *c) const { char buffer[256]; size_t p = 0; + p += sprintf(buffer + p, "%8.3f\t", c->getTrajectoryLength() / Mpc); p += sprintf(buffer + p, "%10i\t", c->current.getId()); - p += sprintf(buffer + p, "%8.4f\t", c->current.getEnergy() / EeV); - const Vector3d &pos = c->current.getPosition() / Mpc; - p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", pos.x, pos.y, pos.z); - const Vector3d &dir = c->current.getDirection(); - p += sprintf(buffer + p, "%7.4f\t%7.4f\t", dir.getPhi(), dir.getTheta()); - p += sprintf(buffer + p, "%9.4f\t", c->getTrajectoryLength() / Mpc); p += sprintf(buffer + p, "%10i\t", c->initial.getId()); + p += sprintf(buffer + p, "%8.4f\t", c->current.getEnergy() / EeV); p += sprintf(buffer + p, "%8.4f\t", c->initial.getEnergy() / EeV); - const Vector3d &ipos = c->initial.getPosition() / Mpc; + Vector3d pos = c->current.getPosition() / Mpc; + p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", pos.x, pos.y, pos.z); + Vector3d ipos = c->initial.getPosition() / Mpc; p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", ipos.x, ipos.y, ipos.z); - const Vector3d &idir = c->initial.getDirection(); - p += sprintf(buffer + p, "%7.4f\t%7.4f\n", idir.getPhi(), idir.getTheta()); + Vector3d dir = c->current.getDirection(); + p += sprintf(buffer + p, "%8.5f\t%8.5f\t%8.5f\t", dir.x, dir.y, dir.z); + Vector3d idir = c->initial.getDirection(); + p += sprintf(buffer + p, "%8.5f\t%8.5f\t%8.5f\n", idir.x, idir.y, idir.z); #pragma omp critical { From 778d65eecd60f6b7164d15927bb5fdc5ea4774ee Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 12 Feb 2013 15:24:29 +0100 Subject: [PATCH 0276/1298] missing #ifdef MPC_HAVE_ROOT in ROOTOutput --- test/testOutput.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/testOutput.cpp b/test/testOutput.cpp index cf5fac145..e99c50109 100644 --- a/test/testOutput.cpp +++ b/test/testOutput.cpp @@ -40,6 +40,7 @@ TEST(CRPropa2EventOutput1D, removeProperty) { EXPECT_FALSE(c.hasProperty("Detected")); } +#ifdef MPC_HAVE_ROOT TEST(ROOTEventOutput3D, removeProperty) { ROOTEventOutput3D output(""); Candidate c; @@ -55,3 +56,4 @@ TEST(ROOTEventOutput1D, removeProperty) { output.process(&c); EXPECT_FALSE(c.hasProperty("Detected")); } +#endif From 372b159620d7bad2141e965c2f737a7bb5423af4 Mon Sep 17 00:00:00 2001 From: geromueller Date: Tue, 12 Feb 2013 17:24:58 +0100 Subject: [PATCH 0277/1298] add GadgetMagneticField --- CMakeLists.txt | 3 +++ include/mpc/magneticField/SPHMagneticField.h | 21 ++++++++++++++++++++ libs/kiss/CMakeLists.txt | 4 ++-- python/mpc.i | 3 +++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 20489aec8..f0c4a1ad8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,6 +69,9 @@ if(GADGET_FOUND) list(APPEND MPC_EXTRA_LIBRARIES ${GADGET_LIBRARY}) add_definitions (-DMPC_HAVE_GADGET) list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_GADGET) + list(APPEND MPC_SWIG_DEFINES -I${GADGET_INCLUDE_DIR}/../share/gadget ) + list(APPEND MPC_SWIG_DEFINES -I${GADGET_INCLUDE_DIR} ) + endif(GADGET_FOUND) # ROOT (optional for ROOT output) diff --git a/include/mpc/magneticField/SPHMagneticField.h b/include/mpc/magneticField/SPHMagneticField.h index 804c696ac..acbc67646 100644 --- a/include/mpc/magneticField/SPHMagneticField.h +++ b/include/mpc/magneticField/SPHMagneticField.h @@ -4,6 +4,7 @@ #ifdef MPC_HAVE_GADGET #include "mpc/magneticField/MagneticFieldGrid.h" +#include "mpc/Units.h" #include "gadget/Database.h" #include "gadget/MagneticField.h" @@ -54,6 +55,26 @@ class SPHMagneticFieldGrid: public MagneticField { void setCacheEnabled(bool enabled); }; +/** + @class GadgetMagneticField + @brief Wrapper for gadget::MagneticField + */ +class GadgetMagneticField: public MagneticField { + gadget::ref_ptr field; +public: + GadgetMagneticField(gadget::ref_ptr field) : field(field) { + + } + Vector3d getField(const Vector3d &position) const { + gadget::Vector3f b, r = gadget::Vector3f(position.x, position.y, position.z); + bool isGood = field->getField(r / kpc, b); + if (!isGood) + std::cerr << "mpc::SPHMagneticField invalid position : " << position + << std::endl; + return Vector3d(b.x, b.y, b.z) * gauss; + } +}; + } // namespace mpc #endif // MPC_HAVE_GADGET diff --git a/libs/kiss/CMakeLists.txt b/libs/kiss/CMakeLists.txt index a57ddd9d4..2752f6bb0 100644 --- a/libs/kiss/CMakeLists.txt +++ b/libs/kiss/CMakeLists.txt @@ -12,8 +12,8 @@ add_library(kiss STATIC SET_TARGET_PROPERTIES( kiss PROPERTIES COMPILE_FLAGS -fPIC) # testing -if(ENABLETESTING) +if(ENABLE_TESTING) add_executable(test_uuid test/test_uuid.cpp) target_link_libraries(test_uuid kiss gtest gtest_main pthread) add_test(test_uuid test_uuid) -endif(ENABLETESTING) +endif(ENABLE_TESTING) diff --git a/python/mpc.i b/python/mpc.i index 2e1c78bf6..8ee63834a 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -20,6 +20,8 @@ using std::ptrdiff_t; %include std_container.i %include "exception.i" +%import (module="gadget") gadget.i + %{ #include "mpc/module/NuclearDecay.h" #include "mpc/module/ElectronPairProduction.h" @@ -106,6 +108,7 @@ using std::ptrdiff_t; %template(ModuleRefPtr) mpc::ref_ptr; %template(stdModuleList) std::list< mpc::ref_ptr >; +%feature("director") Module; %include "mpc/Module.h" %implicitconv mpc::ref_ptr; From 4256228130dc08662586989c0c15e849caafb484 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 14 Feb 2013 18:24:41 +0100 Subject: [PATCH 0278/1298] split Nucleus.h to ParticleID.h and ParticleMass.h add ParticleSelector module add particleID lists for neutrinos and leptons --- CMakeLists.txt | 3 +- include/mpc/{Nucleus.h => ParticleID.h} | 19 ++++----- include/mpc/ParticleMass.h | 15 +++++++ include/mpc/Source.h | 2 +- include/mpc/module/Tools.h | 24 +++++++++-- python/mpc.i | 6 ++- src/ParticleID.cpp | 56 +++++++++++++++++++++++++ src/{Nucleus.cpp => ParticleMass.cpp} | 46 +++----------------- src/ParticleState.cpp | 4 +- src/XmlExecute.cpp | 2 +- src/module/Tools.cpp | 26 ++++++++++-- test/testBreakCondition.cpp | 23 +++++++++- 12 files changed, 160 insertions(+), 66 deletions(-) rename include/mpc/{Nucleus.h => ParticleID.h} (52%) create mode 100644 include/mpc/ParticleMass.h create mode 100644 src/ParticleID.cpp rename src/{Nucleus.cpp => ParticleMass.cpp} (50%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 20489aec8..bdd17d8d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,10 +105,11 @@ add_library(mpc SHARED src/Module.cpp src/Candidate.cpp src/ParticleState.cpp + src/ParticleID.cpp + src/ParticleMass.cpp src/Source.cpp src/Common.cpp src/PhotonBackground.cpp - src/Nucleus.cpp src/GridTools.cpp src/XmlExecute.cpp src/module/BreakCondition.cpp diff --git a/include/mpc/Nucleus.h b/include/mpc/ParticleID.h similarity index 52% rename from include/mpc/Nucleus.h rename to include/mpc/ParticleID.h index 2aa02479e..f2beab645 100644 --- a/include/mpc/Nucleus.h +++ b/include/mpc/ParticleID.h @@ -1,8 +1,14 @@ -#ifndef MPC_NUCLEUS_H_ -#define MPC_NUCLEUS_H_ +#ifndef MPC_PARTICLE_ID_H_ +#define MPC_PARTICLE_ID_H_ + +#include +#include namespace mpc { +std::vector neutrinos(); +std::vector leptons(); + /** This implements the 2012 Monte Carlo nuclear code scheme. * Ion numbers are +/- 10LZZZAAAI. * AAA is A - total baryon number @@ -18,13 +24,6 @@ int massNumberFromNucleusId(int id); int convertFromCRPropaId(int id); int convertToCRPropaId(int id); -/** Return the nucleus mass by lookup from a table. - * The masses are the atomic masses from the NIST database (http://www.nist.gov/pml/data/comp.cfm) minus electron masses, neglecting electron binding energies. - * Unmeasured atomic masses are taken to be A * amu minus electron masses. - * The data table is generated by mpc/data-tools/NuclearMass/createNuclearMassTable. - */ -double nucleusMass(int id); - } // namespace mpc -#endif // MPC_NUCLEUS_H_ +#endif /* MPC_PARTICLE_ID_H_ */ diff --git a/include/mpc/ParticleMass.h b/include/mpc/ParticleMass.h new file mode 100644 index 000000000..0caa06b0d --- /dev/null +++ b/include/mpc/ParticleMass.h @@ -0,0 +1,15 @@ +#ifndef MPC_PARTICLE_MASS_H_ +#define MPC_PARTICLE_MASS_H_ + +namespace mpc { + +/** Return the nucleus mass by lookup from a table. + * The masses are the atomic masses from the NIST database (http://www.nist.gov/pml/data/comp.cfm) minus electron masses, neglecting electron binding energies. + * Unmeasured atomic masses are taken to be A * amu minus electron masses. + * The data table is generated by mpc/data-tools/NuclearMass/createNuclearMassTable. + */ +double nucleusMass(int id); + +} // namespace mpc + +#endif // MPC_PARTICLE_MASS_H_ diff --git a/include/mpc/Source.h b/include/mpc/Source.h index f6df88df1..940c37fc3 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -96,7 +96,7 @@ class SourcePowerLawSpectrum: public SourceProperty { @param Emax maximum energy @param index differential spectral index */ - SourcePowerLawSpectrum(double Emin, double Emax, double index); + SourcePowerLawSpectrum(double Emin, double Emax, double differentialIndex); /** Set particle with a random energy from a power law distribtuition */ void prepare(ParticleState &particle) const; }; diff --git a/include/mpc/module/Tools.h b/include/mpc/module/Tools.h index 5f5ab84e0..891e7b3dc 100644 --- a/include/mpc/module/Tools.h +++ b/include/mpc/module/Tools.h @@ -4,6 +4,8 @@ #include "mpc/Module.h" #include "mpc/AssocVector.h" +#include + namespace mpc { class PerformanceModule: public Module { @@ -17,10 +19,9 @@ class PerformanceModule: public Module { mutable size_t calls; public: - PerformanceModule(); ~PerformanceModule(); - void add(Module *module); - void process(Candidate *candidate) const; + void add(Module* module); + void process(Candidate* candidate) const; std::string getDescription() const; }; @@ -35,6 +36,23 @@ class PropertyStatistics: public Module { void process(Candidate *candidate) const; }; +/** + @class ParticleSelector + @brief Wraps a module and only executes it for certain particle types + */ +class ParticleSelector: public Module { +private: + std::vector ids; + ref_ptr module; + +public: + ParticleSelector(Module* module); + ParticleSelector(Module* module, std::vector particleIDs); + void add(int particleId); + void process(Candidate *candidate) const; + std::string getDescription() const; +}; + } // namespace mpc #endif /* MPC_MODULE_TOOLS_H_ */ diff --git a/python/mpc.i b/python/mpc.i index 2e1c78bf6..26e5fcb39 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -45,7 +45,8 @@ using std::ptrdiff_t; #include "mpc/Referenced.h" #include "mpc/Candidate.h" #include "mpc/ParticleState.h" -#include "mpc/Nucleus.h" +#include "mpc/ParticleID.h" +#include "mpc/ParticleMass.h" #include "mpc/Module.h" #include "mpc/ModuleList.h" #include "mpc/PhasePoint.h" @@ -94,11 +95,12 @@ using std::ptrdiff_t; %include "mpc/Referenced.h" %include "mpc/Units.h" -%include "mpc/Nucleus.h" %include "mpc/Common.h" %include "mpc/PhotonBackground.h" %include "mpc/Random.h" %include "mpc/ParticleState.h" +%include "mpc/ParticleID.h" +%include "mpc/ParticleMass.h" %template(CandidateVector) std::vector< mpc::ref_ptr >; %template(CandidateRefPtr) mpc::ref_ptr; diff --git a/src/ParticleID.cpp b/src/ParticleID.cpp new file mode 100644 index 000000000..6d47867bc --- /dev/null +++ b/src/ParticleID.cpp @@ -0,0 +1,56 @@ +#include "mpc/ParticleID.h" + +#include +#include + +namespace mpc { + +std::vector neutrinos() { + int a[] = { 12, -12, 14, -14, 16, -16 }; + std::vector v(a, a + sizeof(a) / sizeof(int)); + return v; +} + +std::vector leptons() { + int a[] = { 11, -11, 12, -12, 13, -13, 14, -14, 15, -15, 16, -16 }; + std::vector v(a, a + sizeof(a) / sizeof(int)); + return v; +} + +int nucleusId(int a, int z) { + if (z < 0) + throw std::runtime_error( + "mpc::Nucleus: no nucleus with Z < 0, A=" + kiss::str(a) + " Z=" + + kiss::str(z)); + if (a < 1) + throw std::runtime_error( + "mpc::Nucleus: no nucleus with A < 1, A=" + kiss::str(a) + " Z=" + + kiss::str(z)); + if (a < z) + throw std::runtime_error( + "mpc::Nucleus: no nucleus with A < Z, A=" + kiss::str(a) + " Z=" + + kiss::str(z)); + return 1000000000 + z * 10000 + a * 10; +} + +int chargeNumberFromNucleusId(int id) { + return HepPID::Z(id); +} + +int massNumberFromNucleusId(int id) { + return HepPID::A(id); +} + +int convertFromCRPropaId(int crp_id) { + int Z = crp_id / 1000; + int A = crp_id % 1000; + return nucleusId(A, Z); +} + +int convertToCRPropaId(int id) { + int Z = chargeNumberFromNucleusId(id); + int A = massNumberFromNucleusId(id); + return Z * 1000 + A; +} + +} diff --git a/src/Nucleus.cpp b/src/ParticleMass.cpp similarity index 50% rename from src/Nucleus.cpp rename to src/ParticleMass.cpp index ac8b37482..abbb19b07 100644 --- a/src/Nucleus.cpp +++ b/src/ParticleMass.cpp @@ -1,52 +1,16 @@ -#include "mpc/Nucleus.h" +#include "mpc/ParticleMass.h" +#include "mpc/ParticleID.h" #include "mpc/Common.h" #include -#include #include #include -#include #include +#include namespace mpc { -int nucleusId(int a, int z) { - if (z < 0) - throw std::runtime_error( - "mpc::Nucleus: no nucleus with Z < 0, A=" + kiss::str(a) + " Z=" - + kiss::str(z)); - if (a < 1) - throw std::runtime_error( - "mpc::Nucleus: no nucleus with A < 1, A=" + kiss::str(a) + " Z=" - + kiss::str(z)); - if (a < z) - throw std::runtime_error( - "mpc::Nucleus: no nucleus with A < Z, A=" + kiss::str(a) + " Z=" - + kiss::str(z)); - return 1000000000 + z * 10000 + a * 10; -} - -int chargeNumberFromNucleusId(int id) { - return HepPID::Z(id); -} - -int massNumberFromNucleusId(int id) { - return HepPID::A(id); -} - -int convertFromCRPropaId(int crp_id) { - int Z = crp_id / 1000; - int A = crp_id % 1000; - return nucleusId(A, Z); -} - -int convertToCRPropaId(int id) { - int Z = chargeNumberFromNucleusId(id); - int A = massNumberFromNucleusId(id); - return Z * 1000 + A; -} - struct NuclearMassTable { std::vector table; @@ -74,8 +38,8 @@ struct NuclearMassTable { static NuclearMassTable nuclearMassTable; double nucleusMass(int id) { - int Z = HepPID::Z(id); - int N = HepPID::A(id) - Z; + int Z = chargeNumberFromNucleusId(id); + int N = massNumberFromNucleusId(id) - Z; double mass = nuclearMassTable.table[Z * 31 + N]; if (mass == 0) throw std::runtime_error("getNucleusMass: nucleus not found " + kiss::str(id)); diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index c2ea88b01..2a5f2d7d2 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -6,8 +6,8 @@ namespace mpc { ParticleState::ParticleState() : - id(0), pmass(0), energy(0), position(0, 0, 0), direction(-1, 0, 0) { - + id(0), charge(0), pmass(0), energy(0), position(0, 0, 0), direction(-1, + 0, 0) { } void ParticleState::setPosition(const Vector3d &pos) { diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index f4fdb8558..abbde3e0c 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -123,7 +123,7 @@ SourceDensityGrid1D* loadSourceDensityGrid1D(pugi::xml_node &node) { } XmlExecute::XmlExecute() : - is1D(false), nTrajectories(0), Emin(0), maxStep(0) { + is1D(false), hasRedshift(false), nTrajectories(0), Emin(0), maxStep(0) { } bool XmlExecute::load(const string &filename) { diff --git a/src/module/Tools.cpp b/src/module/Tools.cpp index 98d7468c9..7e28073f0 100644 --- a/src/module/Tools.cpp +++ b/src/module/Tools.cpp @@ -8,10 +8,6 @@ using namespace std; namespace mpc { -PerformanceModule::PerformanceModule() { - -} - PerformanceModule::~PerformanceModule() { double total = 0; for (size_t i = 0; i < modules.size(); i++) { @@ -96,4 +92,26 @@ void PropertyStatistics::process(Candidate *candidate) const { } } +ParticleSelector::ParticleSelector(Module *m) : + module(m) { +} + +ParticleSelector::ParticleSelector(Module *m, std::vector particleIDs) : + module(m), ids(particleIDs) { +} + +void ParticleSelector::add(int particleID) { + ids.push_back(particleID); +} + +void ParticleSelector::process(Candidate* candidate) const { + int id = candidate->current.getId(); + if (std::find(ids.begin(), ids.end(), id) != ids.end()) + module->process(candidate); +} + +std::string ParticleSelector::getDescription() const { + return "ParticleSelector"; +} + } // namespace mpc diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index 93f8b5ef6..115301ea3 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -1,8 +1,10 @@ -/** Unit tests for break condition, observer and boundary modules */ +/** Unit tests for break condition, observer, boundary and tool modules */ #include "mpc/module/BreakCondition.h" #include "mpc/module/Observer.h" #include "mpc/module/Boundary.h" +#include "mpc/module/Tools.h" +#include "mpc/ParticleID.h" #include "gtest/gtest.h" @@ -309,6 +311,25 @@ TEST(EllipsoidalBoundary, limitStep) { EXPECT_DOUBLE_EQ(c.getNextStep(), 1.5); } +//** ============================ Tools ===================================== */ +TEST(ParticleSelector, neutrinos) { + // Test if ParticleSelector only activates for neutrinos + // Use MaximumTrajectoryLength as test module + ParticleSelector selector(new MaximumTrajectoryLength(1 * Mpc), neutrinos()); + + Candidate c1; + c1.current.setId(12); // electron neutrino + c1.setTrajectoryLength(5 * Mpc); // should be deactivated by MaximumTrajectoryLength + selector.process(&c1); + EXPECT_FALSE(c1.isActive()); + + Candidate c2; + c2.current.setId(nucleusId(1, 1)); // proton + c2.setTrajectoryLength(5 * Mpc); // should be deactivated by MaximumTrajectoryLength + selector.process(&c2); + EXPECT_TRUE(c2.isActive()); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); From 94e433984e90db85730b66ab3de2c3df1471d1e9 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 14 Feb 2013 18:54:12 +0100 Subject: [PATCH 0279/1298] add DetectAll module --- include/mpc/module/Observer.h | 20 ++++++++++++++++++++ src/module/Observer.cpp | 22 ++++++++++++++++++++-- test/testBreakCondition.cpp | 17 +++++++++++++---- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/include/mpc/module/Observer.h b/include/mpc/module/Observer.h index eac2fe48a..4438f2b03 100644 --- a/include/mpc/module/Observer.h +++ b/include/mpc/module/Observer.h @@ -76,6 +76,26 @@ class Observer1D: public Module { void process(Candidate *candidate) const; }; +/** + @class DetectAll + @brief Flags all + + Module that flags every particle it processes. + Optionally inactivates the particle. + */ +class DetectAll: public Module { +private: + std::string flag; + std::string flagValue; + bool makeInactive; + +public: + DetectAll(std::string flag = "Detected", std::string flagValue = "", + bool makeInactive = true); + void process(Candidate *candidate) const; + std::string getDescription() const; +}; + } // namespace mpc #endif /* MPC_OBSERVER_H_ */ diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp index 3c105fb24..876682b65 100644 --- a/src/module/Observer.cpp +++ b/src/module/Observer.cpp @@ -57,7 +57,7 @@ std::string SmallObserverSphere::getDescription() const { s << " Mpc radius around " << center / Mpc; s << " Mpc, Flag: '" << flag << "' -> '" << flagValue << "'"; if (makeInactive) - s << ", Inactivate"; + s << ", render inactivate"; return s.str(); } @@ -114,7 +114,7 @@ std::string LargeObserverSphere::getDescription() const { s << " Mpc radius around " << center / Mpc; s << " Mpc, Flag: '" << flag << "' -> '" << flagValue << "'"; if (makeInactive) - s << ", Inactivate"; + s << ", render inactivates"; return s.str(); } @@ -133,4 +133,22 @@ void Observer1D::process(Candidate *candidate) const { candidate->setActive(false); } +DetectAll::DetectAll(std::string f, std::string v, bool m) : + flag(f), flagValue(v), makeInactive(m) { +} + +void DetectAll::process(Candidate *candidate) const { + candidate->setProperty(flag, flagValue); + if (makeInactive) + candidate->setActive(false); +} + +std::string DetectAll::getDescription() const { + std::stringstream s; + s << "DetectAll: Flag: " << flag << " -> " << flagValue; + if (makeInactive) + s << ", render inactive"; + return s.str(); +} + } // namespace mpc diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index 115301ea3..50362ded6 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -130,6 +130,15 @@ TEST(Observer1D, detection) { EXPECT_FALSE(c.isActive()); } +TEST(DetectAll, detection) { + // DetectAll should detect all candidates + DetectAll obs("Wait", "You forgot your lunchbox"); + Candidate c; + obs.process(&c); + EXPECT_FALSE(c.isActive()); + EXPECT_TRUE(c.hasProperty("Wait")); +} + //** ========================= Boundaries =================================== */ TEST(PeriodicBox, high) { // Tests if the periodical boundaries place the particle back inside the box and translate the initial position accordingly. @@ -314,18 +323,18 @@ TEST(EllipsoidalBoundary, limitStep) { //** ============================ Tools ===================================== */ TEST(ParticleSelector, neutrinos) { // Test if ParticleSelector only activates for neutrinos - // Use MaximumTrajectoryLength as test module - ParticleSelector selector(new MaximumTrajectoryLength(1 * Mpc), neutrinos()); + // Use DetectAll as test module + ParticleSelector selector(new DetectAll(), neutrinos()); Candidate c1; c1.current.setId(12); // electron neutrino - c1.setTrajectoryLength(5 * Mpc); // should be deactivated by MaximumTrajectoryLength + c1.setTrajectoryLength(5 * Mpc); selector.process(&c1); EXPECT_FALSE(c1.isActive()); Candidate c2; c2.current.setId(nucleusId(1, 1)); // proton - c2.setTrajectoryLength(5 * Mpc); // should be deactivated by MaximumTrajectoryLength + c2.setTrajectoryLength(5 * Mpc); selector.process(&c2); EXPECT_TRUE(c2.isActive()); } From 8a315da200a6a0c93fc4e543a6391de23c48597e Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 15 Feb 2013 14:42:27 +0100 Subject: [PATCH 0280/1298] minor updates to python scripts --- test/python/testDeflectionCK.py | 3 +- test/python/testElectronPairProduction.py | 6 ++-- test/python/testJF12Field.py | 11 ++++-- test/python/testNuclearDecay.py | 4 ++- test/python/testNuclearMass.py | 2 ++ test/python/testPhotoPionProduction.py | 10 +++--- .../python/testPhotoPionProduction_pnRatio.py | 9 ++--- test/python/testRedshift.py | 34 +++++++++---------- test/python/testSourceComposition.py | 6 ++-- test/python/testTurbulentDeflection.py | 4 ++- test/python/testTurbulentFieldGrid.py | 3 +- 11 files changed, 54 insertions(+), 38 deletions(-) diff --git a/test/python/testDeflectionCK.py b/test/python/testDeflectionCK.py index b18b5449b..32ff11e55 100644 --- a/test/python/testDeflectionCK.py +++ b/test/python/testDeflectionCK.py @@ -4,7 +4,7 @@ # 100 EeV proton c = Candidate() -c.current.setId(getNucleusId(1,1)) +c.current.setId(nucleusId(1,1)) c.current.setEnergy(100 * EeV) c.current.setDirection(Vector3d(1, 0, 0)) @@ -101,4 +101,5 @@ def propagate(tolerance): ylim(1e-8,1e-1) savefig('DeflectionCK_xdeviation.png',bbox_inches='tight') +show() diff --git a/test/python/testElectronPairProduction.py b/test/python/testElectronPairProduction.py index 44c81a53a..faa4239e8 100644 --- a/test/python/testElectronPairProduction.py +++ b/test/python/testElectronPairProduction.py @@ -5,7 +5,7 @@ def compare(dataFileName, photonField, plotFileName): A = genfromtxt(dataFileName, comments="#", unpack=True) figure() - plot(A[0], A[1], label='data') + plot(A[0], A[1], label='Datatable') epp = ElectronPairProduction(photonField) @@ -22,7 +22,7 @@ def compare(dataFileName, photonField, plotFileName): epp.process(c) dE[i] = (E[i] - c.current.getEnergy() / eV) - plot(E, dE,'k+', label='simulated', linewidth=2, markeredgewidth=2) + plot(E, dE,'k+', label='Simulated using datatable', linewidth=2, markeredgewidth=2) xlabel('Energy [eV]') ylabel('Energy Loss Rate [eV / Mpc]') @@ -36,3 +36,5 @@ def compare(dataFileName, photonField, plotFileName): compare(getDataPath('epair_CMB.txt'), CMB, 'ElectronPairProduction_CMB.png') compare(getDataPath('epair_IRB.txt'), IRB, 'ElectronPairProduction_IRB.png') compare(getDataPath('epair_CMB_IRB.txt'), CMB_IRB, 'ElectronPairProduction_CMB_IRB.png') + +show() diff --git a/test/python/testJF12Field.py b/test/python/testJF12Field.py index 54a52ea29..63169b9fc 100644 --- a/test/python/testJF12Field.py +++ b/test/python/testJF12Field.py @@ -3,13 +3,15 @@ from matplotlib.colors import LogNorm +# Components of JF12 model bField = JF2012Field() #bField.randomStriated() #bField.randomTurbulent() -N = 241 +z = 0 # z position [kpc] of slice to plot +N = 241 # resolution in one direction + lx = (linspace(-20, 20, N, endpoint=True)) -z = 0 B, X, Y = zeros((3, N,N)) for ix in range(N): @@ -28,5 +30,8 @@ plot(-8.5, 0, 'wo') xlabel('x [kpx]') ylabel('y [kpx]') -show() +xlim(-20, 20) +ylim(-20, 20) savefig('JF12.png', bbox_inches='tight') + +show() diff --git a/test/python/testNuclearDecay.py b/test/python/testNuclearDecay.py index 7604c6030..5fd0e2764 100644 --- a/test/python/testNuclearDecay.py +++ b/test/python/testNuclearDecay.py @@ -2,6 +2,7 @@ from pylab import * from matplotlib.colors import LogNorm + # color values of decay modes vS = 0.5 # stable vP = 0.9 # proton emission @@ -13,7 +14,7 @@ ### read and evaluate decay tables -data = genfromtxt(getDataPath('NuclearDecay/decayTable.txt'), comments='#') +data = genfromtxt(getDataPath('nuclear_decay.txt'), comments='#') modes = zeros((27, 31)) times = zeros((27, 31)) multi = zeros((27, 31)) @@ -74,3 +75,4 @@ ax.grid() fig.savefig('NuclearDecay_multiplicity.png',bbox_inches='tight') +show() diff --git a/test/python/testNuclearMass.py b/test/python/testNuclearMass.py index f2a8cd3e4..e436db3c4 100644 --- a/test/python/testNuclearMass.py +++ b/test/python/testNuclearMass.py @@ -30,3 +30,5 @@ ylabel('Protons') grid() savefig('NuclearMass_difference.png', bbox_inches='tight') + +show() diff --git a/test/python/testPhotoPionProduction.py b/test/python/testPhotoPionProduction.py index 9542cbc73..eb6af8705 100644 --- a/test/python/testPhotoPionProduction.py +++ b/test/python/testPhotoPionProduction.py @@ -27,10 +27,10 @@ def compare(dataFileName, photonField, plotFileName): n[i] = getRate(ppp, energy, 0) figure() - plot(E_data, P_data, "r", label="Proton Data") - plot(E, p, 'k+', label="Proton Simulated") - plot(E_data, N_data, "b", label="Neutron Data") - plot(E, n, 'k.', label="Neutron Simulated") + plot(E_data, P_data, "r", label="Proton data table") + plot(E, p, 'k+', label="Proton") + plot(E_data, N_data, "b", label="Neutron data table") + plot(E, n, 'k.', label="Neutron") xlabel('Energy [EeV]') ylabel('Rate [1/Mpc]') legend(loc='center right') @@ -42,3 +42,5 @@ def compare(dataFileName, photonField, plotFileName): compare(getDataPath('photopion_CMB.txt'), CMB, 'PhotoPionProduction_CMB.png') compare(getDataPath('photopion_IRB.txt'), IRB, 'PhotoPionProduction_IRB.png') + +show() diff --git a/test/python/testPhotoPionProduction_pnRatio.py b/test/python/testPhotoPionProduction_pnRatio.py index 5da1c4204..33f1996c5 100644 --- a/test/python/testPhotoPionProduction_pnRatio.py +++ b/test/python/testPhotoPionProduction_pnRatio.py @@ -1,9 +1,9 @@ -''' -Simulate the p/n-ratio of the final baryon states in SOPHIA photo-pion interactions -''' from mpc import * from pylab import * + +# Simulate the p/n-ratio of the final baryon states in SOPHIA photo-pion interactions + spp = SophiaPhotoPionProduction() c = Candidate() s = InteractionState() @@ -24,7 +24,6 @@ def getPNRatio(E): E = logspace(log10(50), 4, 20) Rpn = zeros(20) for i in range(20): - print i Rpn[i] = getPNRatio(E[i]) figure() @@ -34,3 +33,5 @@ def getPNRatio(E): ylabel('Proton / Neutron Ratio') semilogx() savefig('PhotoPionProduction_pnRatio.png', bbox_inches='tight') + +show() diff --git a/test/python/testRedshift.py b/test/python/testRedshift.py index b1370d7a6..c6b7c9949 100644 --- a/test/python/testRedshift.py +++ b/test/python/testRedshift.py @@ -1,30 +1,28 @@ #!/usr/bin/env python from mpc import * -import numpy as np -import matplotlib.pyplot as plt - +from pylab import * +# Redshift - comoving distance relation redshift = Redshift() -# Redshift - comoving distance relation N = 100 -Z = np.logspace(-4, 2, N) -D1 = np.zeros(N) +Z = logspace(-4, 2, N) +D1 = zeros(N) for i in range(N): - D1[i] = redshift.getDistance(Z[i]) / Mpc + D1[i] = redshift.redshift2ComovingDistance(Z[i]) / Mpc -H0 = redshift.getHubbleRate(0) +H0 = redshift.hubbleRate(0) D2 = c_light * Z / H0 / Mpc -plt.figure() -plt.plot(Z, D1, label='Numerical Integration') -plt.plot(Z, D2, 'r--', label='Small Redshift Approximation') -plt.legend(loc='upper left', frameon=0) -plt.xlabel('Redshift z') -plt.ylabel('Comoving Distance [Mpc]') -plt.loglog() -plt.grid() -plt.savefig('Redshift.png', bbox_inches='tight') -plt.show() +figure() +plot(Z, D1, label='Numerical Integration') +plot(Z, D2, 'r--', label='Small Redshift Approximation') +legend(loc='upper left', frameon=0) +xlabel('Redshift z') +ylabel('Comoving Distance [Mpc]') +loglog() +grid() +savefig('Redshift.png', bbox_inches='tight') +show() diff --git a/test/python/testSourceComposition.py b/test/python/testSourceComposition.py index d8b6891e3..cd2a4e013 100644 --- a/test/python/testSourceComposition.py +++ b/test/python/testSourceComposition.py @@ -1,6 +1,7 @@ from mpc import * from pylab import * + # Simulates the integrated relative abundance from a source that accelerates # particles up to a maximum rigidity. # min. energy = 10 EeV @@ -15,7 +16,6 @@ print 'simulating for spectral index' for i in range(nS): beta = 2 + i/float(nS - 1) - print beta composition = SourceComposition(10, 100, -beta) composition.add(1, 1, 92000) @@ -29,7 +29,7 @@ for j in range(nP): composition.prepare(state) - z = state.chargeNumber() + z = chargeNumberFromNucleusId(state.getId()) d[z][i] += 1 norm = float(d[1][i]) @@ -40,7 +40,7 @@ beta = linspace(2, 3, nS) elements = {1:'H', 2:'He', 6:'C', 8:'O', 14:'Si', 26:'Fe'} for z in d.keys(): - plot(beta, d[z], label=elements[z]) + plt.plot(beta, d[z], label=elements[z]) legend(loc = 'lower right') xlabel(r'Source Spectral Index $\beta$') diff --git a/test/python/testTurbulentDeflection.py b/test/python/testTurbulentDeflection.py index 2c2d166c4..a93b6f5aa 100644 --- a/test/python/testTurbulentDeflection.py +++ b/test/python/testTurbulentDeflection.py @@ -57,7 +57,7 @@ plot(distance[nP], rms1[nP], label='position, final direction') plot(distance[nP], theory[nP] / 3**.5, 'k--') plot(distance[nP], rms2[nP], label='initial, final direction') -plot(distance[nP], theory[nP], 'k--', label='Harari') +plot(distance[nP], theory[nP], 'k--', label='Harari et al.') xlabel('Distance [Mpc]') ylabel('RMS(Deflection) [rad]') legend(loc='lower right', frameon=False) @@ -65,3 +65,5 @@ text(0.05, 0.95, s, ha='left', va='top', transform=gca().transAxes) savefig('TurbulentDeflection.png', bbox_inches='tight') +show() + diff --git a/test/python/testTurbulentFieldGrid.py b/test/python/testTurbulentFieldGrid.py index 40dc4df96..9f4bfb806 100644 --- a/test/python/testTurbulentFieldGrid.py +++ b/test/python/testTurbulentFieldGrid.py @@ -92,7 +92,6 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): ### copy field grid to array(s) Bx, By, Bz = zeros((3, n, n, n)) for ix in range(n): - print ix for iy in range(n): for iz in range(n): b = vGrid.get(ix, iy, iz) @@ -202,3 +201,5 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): bmean = abs(mean(Bx + By + Bz)) text(0.95, 0.7, '$RMS$ = %.2f\nMean = %.2f'%(brms, bmean), ha='right', va='top', transform=gca().transAxes) savefig('TurbulentField_amplitude.png', bbox_inches='tight') + +show() From 84d8430c9de783c22a7e396548272be2bb0398f1 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sat, 16 Feb 2013 07:25:21 +0100 Subject: [PATCH 0281/1298] missing rename Nucleus.h -> ParticleID.h / ParticleMass.h --- include/mpc/ParticleState.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/mpc/ParticleState.h b/include/mpc/ParticleState.h index 9ca1b2291..aa348c42b 100644 --- a/include/mpc/ParticleState.h +++ b/include/mpc/ParticleState.h @@ -4,7 +4,8 @@ #include "mpc/Vector3.h" #include "mpc/Units.h" #include "mpc/Common.h" -#include "mpc/Nucleus.h" +#include "mpc/ParticleID.h" +#include "mpc/ParticleMass.h" namespace mpc { From 2d9a07d6a97373d27ed8ca2c594fe9cfb3700d9f Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 21 Feb 2013 16:44:53 +0100 Subject: [PATCH 0282/1298] extended Redshift module for luminosity distance and light travel distance --- include/mpc/ParticleState.h | 4 ++- include/mpc/module/Redshift.h | 47 ++++++++++++++++++++++--- src/module/Redshift.cpp | 66 ++++++++++++++++++++++++++++------- test/python/testRedshift.py | 20 +++++++---- 4 files changed, 113 insertions(+), 24 deletions(-) diff --git a/include/mpc/ParticleState.h b/include/mpc/ParticleState.h index aa348c42b..90bc381fb 100644 --- a/include/mpc/ParticleState.h +++ b/include/mpc/ParticleState.h @@ -45,10 +45,12 @@ class ParticleState { void setId(int); int getId() const; + /* Electrical charge of the particle */ double getCharge() const; + /* Mass of the particle */ double getMass() const; - /* Set Lorentz factor, which modifies the particles energy */ + /* Set Lorentz factor and modify the particles energy accordingly */ void setLorentzFactor(double gamma); double getLorentzFactor() const; diff --git a/include/mpc/module/Redshift.h b/include/mpc/module/Redshift.h index 3119a39c8..e3f5d662b 100644 --- a/include/mpc/module/Redshift.h +++ b/include/mpc/module/Redshift.h @@ -47,7 +47,9 @@ class Redshift: public Module { static const double zmax = 100; std::vector Z; // redshift - std::vector D; // comoving distance [m] + std::vector Dc; // comoving distance [m] + std::vector Dl; // luminosity distance [m] + std::vector Dt; // light travel distance [m] public: /** Constructor @@ -59,12 +61,49 @@ class Redshift: public Module { void process(Candidate *candidate) const; std::string getDescription() const; - /** Hubble rate at given redshift */ + /** + Hubble rate at given redshift + H(z) = H0 * sqrt(omegaM * (1 + z)^3 + omegaL) + */ double hubbleRate(double redshift) const; - /** Redshift of a comoving object at a given comoving distance to the observer at z = 0 */ + /** + Dimensionless Hubble parameter at given redshift + E(z) = sqrt(omegaM * (1 + z)^3 + omegaL) + */ + double hubbleParameter(double redshift) const; + + /** + Redshift of a comoving object at a given comoving distance to an observer at z = 0. + d_comoving(z) = c/H0 * int_0^z dz' / E(z') + */ double comovingDistance2Redshift(double distance) const; - /** Comoving distance between an observer at z = 0 and a comoving object at z */ + /** + Comoving distance between an observer at z = 0 and a comoving object at z. + d_comoving(z) = c/H0 * int_0^z dz' / E(z') + */ double redshift2ComovingDistance(double redshift) const; + + /** + Redshift of a comoving object at a given luminosity distance to an observer at z = 0. + d_luminosity(z) = (1 + z) * d_comoving(z) + */ + double luminosityDistance2Redshift(double distance) const; + /** + Luminosity distance between an observer at z = 0 and a comoving object at z. + d_luminosity(z) = (1 + z) * d_comoving(z) + */ + double redshift2LuminosityDistance(double redshift) const; + + /** + Redshift of a comoving object at a given light travel distance to an observer at z = 0. + d_lighttravel(z) = c/H0 * int_0^z dz' / ((1 + z') * E(z')) + */ + double lightTravelDistance2Redshift(double distance) const; + /** + Light travel distance between an observer at z = 0 and a comoving object at z. + d_lighttravel(z) = c/H0 * int_0^z dz' / ((1 + z') * E(z')) + */ + double redshift2LightTravelDistance(double redshift) const; }; } // namespace mpc diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index 264feb8ba..65a7ea418 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -33,12 +33,17 @@ std::string SimpleRedshift::getDescription() const { Redshift::Redshift(double h, double m, double l) : H0(h * 1e5 / Mpc), omegaM(m), omegaL(l) { Z.resize(n); - D.resize(n); - std::vector H(n); + Dc.resize(n); + Dl.resize(n); + Dt.resize(n); + std::vector E(n); // dimensionless Hubble parameter + double dH = c_light / H0; // Hubble distance Z[0] = 0; - D[0] = 0; - H[0] = H0; + Dc[0] = 0; + Dl[0] = 0; + Dt[0] = 0; + E[0] = 1; // Relation between comoving distance r and redshift z (cf. J.A. Peacock, Cosmological physics, p. 89 eq. 3.76) // dr = c / H(z) dz, integration using midpoint rule @@ -46,22 +51,28 @@ Redshift::Redshift(double h, double m, double l) : double dz; for (int i = 1; i < n; i++) { Z[i] = zmin * pow(10, i * dlz / (n - 1)); // logarithmic even spacing - dz = (Z[i] - Z[i - 1]); - H[i] = hubbleRate(Z[i]); - D[i] = D[i - 1] + c_light * (1 / H[i] + 1 / H[i - 1]) / 2 * dz; + dz = (Z[i] - Z[i - 1]); // redshift step + E[i] = hubbleParameter(Z[i]); + Dc[i] = Dc[i - 1] + dH / 2 * dz * (1 / E[i] + 1 / E[i - 1]); + Dl[i] = (1 + Z[i]) * Dc[i]; + Dt[i] = Dt[i - 1] + dH / 2 * dz * (1 / ((1 + Z[i]) * E[i]) + 1 / ((1 + Z[i - 1]) * E[i - 1])); } } double Redshift::hubbleRate(double z) const { - return H0 * sqrt(omegaL + omegaM * pow(1 + z, 3)); + return H0 * hubbleParameter(z); +} + +double Redshift::hubbleParameter(double z) const { + return sqrt(omegaL + omegaM * pow(1 + z, 3)); } double Redshift::comovingDistance2Redshift(double d) const { if (d < 0) throw std::runtime_error("Redshift: d < 0"); - if (d > D[n - 1]) + if (d > Dc[n - 1]) throw std::runtime_error("Redshift: d > dmax"); - return interpolate(d, D, Z); + return interpolate(d, Dc, Z); } double Redshift::redshift2ComovingDistance(double z) const { @@ -69,8 +80,39 @@ double Redshift::redshift2ComovingDistance(double z) const { throw std::runtime_error("Redshift: z < 0"); if (z > zmax) throw std::runtime_error("Redshift: z > zmax"); - double d = interpolate(z, Z, D); - return d; + return interpolate(z, Z, Dc); +} + +double Redshift::luminosityDistance2Redshift(double d) const { + if (d < 0) + throw std::runtime_error("Redshift: d < 0"); + if (d > Dl[n - 1]) + throw std::runtime_error("Redshift: d > dmax"); + return interpolate(d, Dl, Z); +} + +double Redshift::redshift2LuminosityDistance(double z) const { + if (z < 0) + throw std::runtime_error("Redshift: z < 0"); + if (z > zmax) + throw std::runtime_error("Redshift: z > zmax"); + return interpolate(z, Z, Dl); +} + +double Redshift::lightTravelDistance2Redshift(double d) const { + if (d < 0) + throw std::runtime_error("Redshift: d < 0"); + if (d > Dt[n - 1]) + throw std::runtime_error("Redshift: d > dmax"); + return interpolate(d, Dt, Z); +} + +double Redshift::redshift2LightTravelDistance(double z) const { + if (z < 0) + throw std::runtime_error("Redshift: z < 0"); + if (z > zmax) + throw std::runtime_error("Redshift: z > zmax"); + return interpolate(z, Z, Dt); } void Redshift::process(Candidate *c) const { diff --git a/test/python/testRedshift.py b/test/python/testRedshift.py index c6b7c9949..58959c585 100644 --- a/test/python/testRedshift.py +++ b/test/python/testRedshift.py @@ -3,24 +3,30 @@ from pylab import * -# Redshift - comoving distance relation redshift = Redshift() N = 100 Z = logspace(-4, 2, N) -D1 = zeros(N) +Dc = zeros(N) # comoving distance +Dl = zeros(N) # comoving distance +Dt = zeros(N) # light travel distance for i in range(N): - D1[i] = redshift.redshift2ComovingDistance(Z[i]) / Mpc + Dc[i] = redshift.redshift2ComovingDistance(Z[i]) / Mpc + Dl[i] = redshift.redshift2LuminosityDistance(Z[i]) / Mpc + Dt[i] = redshift.redshift2LightTravelDistance(Z[i]) / Mpc H0 = redshift.hubbleRate(0) -D2 = c_light * Z / H0 / Mpc +Dlin = c_light * Z / H0 / Mpc # Hubble's law figure() -plot(Z, D1, label='Numerical Integration') -plot(Z, D2, 'r--', label='Small Redshift Approximation') +plot(Z, Dc, 'b', label="Comoving distance") +plot(Z, Dl, 'g', label="Luminosity distance") +plot(Z, Dt, 'r', label="Light travel distance") +plot(Z, Dlin, 'k--', label="Naive Hubble") + legend(loc='upper left', frameon=0) xlabel('Redshift z') -ylabel('Comoving Distance [Mpc]') +ylabel('Distance [Mpc]') loglog() grid() savefig('Redshift.png', bbox_inches='tight') From 977c013554e210bdd8c42684fff794356ea39d54 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 25 Feb 2013 14:42:02 +0100 Subject: [PATCH 0283/1298] xml-steering: make Y and Z coordinates optional in 1D mode --- src/XmlExecute.cpp | 8 +++-- test/xml/1D_discreteSource.xml | 50 +++++++++++++++++++++++++++ test/xml/3D_throwNoBoundary.xml | 61 +++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 test/xml/1D_discreteSource.xml create mode 100644 test/xml/3D_throwNoBoundary.xml diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index abbde3e0c..06f6eeb36 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -518,10 +518,12 @@ void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { } else { // read individual positions from xml for (xml_node n = node.child("PointSource"); n; n = n.next_sibling("PointSource")) { - Vector3d pos; + Vector3d pos(0.); pos.x = childValue(n, "CoordX_Mpc") * Mpc; - pos.y = childValue(n, "CoordY_Mpc") * Mpc; - pos.z = childValue(n, "CoordZ_Mpc") * Mpc; + if (not(is1D)) { + pos.y = childValue(n, "CoordY_Mpc") * Mpc; + pos.z = childValue(n, "CoordZ_Mpc") * Mpc; + } cout << " - Position " << pos / Mpc << " Mpc" << endl; sourcePositions->add(pos); } diff --git a/test/xml/1D_discreteSource.xml b/test/xml/1D_discreteSource.xml new file mode 100644 index 000000000..48beedc6f --- /dev/null +++ b/test/xml/1D_discreteSource.xml @@ -0,0 +1,50 @@ + + + + + + + + + + output.txt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/xml/3D_throwNoBoundary.xml b/test/xml/3D_throwNoBoundary.xml new file mode 100644 index 000000000..1cd645e95 --- /dev/null +++ b/test/xml/3D_throwNoBoundary.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + output.txt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From bcca2d9c24a04f2119ae4db546250da0e4dc55c8 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 5 Mar 2013 15:10:38 +0100 Subject: [PATCH 0284/1298] changed grid implementation: the grid points are now at 1/2, 3/2 ... (2N-1)/2 --- include/mpc/Grid.h | 20 ++++++++++++-------- test/testCore.cpp | 32 ++++++++++++++++++-------------- test/testSource.cpp | 37 +++++++++++++++++++++++++------------ 3 files changed, 55 insertions(+), 34 deletions(-) diff --git a/include/mpc/Grid.h b/include/mpc/Grid.h index 3acfe1e7b..2f213f1e3 100644 --- a/include/mpc/Grid.h +++ b/include/mpc/Grid.h @@ -33,19 +33,20 @@ inline double round(double r) { The grid spacing is constant and equal along all three axes. Values are calculated by trilinear interpolation of the surrounding 8 grid points. The grid is periodically (default) or reflectively extended. - The grid sample positions are at 0, size/N, ... (N-1) * size/N. + The grid sample positions are at 1/2 * size/N, 3/2 * size/N ... (2N-1)/2 * size/N. */ template class Grid: public Referenced { std::vector grid; size_t Nx, Ny, Nz; /**< Number of grid points */ - Vector3d origin; /**< Grid origin */ + Vector3d origin; /**< Origin of the volume that is represented by the grid. */ + Vector3d gridOrigin; /**< Grid origin */ double spacing; /**< Distance between grid points, determines the extension of the grid */ bool reflective; /**< If set to true, the grid is repeated reflectively instead of periodically */ public: /** Constructor for cubic grid - @param origin Position of the lower, left, front grid point + @param origin Position of the lower left front corner of the volume @param N Number of grid points in one direction @param spacing Spacing between grid points */ @@ -57,7 +58,7 @@ class Grid: public Referenced { } /** Constructor for non-cubic grid - @param origin Position of the lower, left, front grid point + @param origin Position of the lower left front corner of the volume @param Nx Number of grid points in x-direction @param Ny Number of grid points in y-direction @param Nz Number of grid points in z-direction @@ -73,18 +74,21 @@ class Grid: public Referenced { void setOrigin(Vector3d origin) { this->origin = origin; + this->gridOrigin = origin + Vector3d(spacing/2); } - /** Resize grid */ + /** Resize grid, also enlarges the volume as the spacing stays constant */ void setGridSize(size_t Nx, size_t Ny, size_t Nz) { this->Nx = Nx; this->Ny = Ny; this->Nz = Nz; grid.resize(Nx * Ny * Nz); + setOrigin(origin); } void setSpacing(double spacing) { this->spacing = spacing; + setOrigin(origin); } void setReflective(bool b) { @@ -134,12 +138,12 @@ class Grid: public Referenced { int ix = index / (Ny * Nz); int iy = (index / Nz) % Ny; int iz = index % Nz; - return Vector3d(ix, iy, iz) * spacing + origin; + return Vector3d(ix, iy, iz) * spacing + gridOrigin; } /** Value of a grid point that is closest to a given position */ T closestValue(const Vector3d &position) const { - Vector3d r = (position - origin) / spacing; + Vector3d r = (position - gridOrigin) / spacing; int ix = round(r.x); int iy = round(r.y); int iz = round(r.z); @@ -161,7 +165,7 @@ class Grid: public Referenced { /** Interpolate the grid at a given position */ T interpolate(const Vector3d &position) const { // position on a unit grid - Vector3d r = (position - origin) / spacing; + Vector3d r = (position - gridOrigin) / spacing; // indices of lower and upper neighbors int ix, iX, iy, iY, iz, iZ; diff --git a/test/testCore.cpp b/test/testCore.cpp index 43d4189b7..a4d2e6d47 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -266,16 +266,17 @@ TEST(ScalarGrid, SimpleTest) { // Test index handling: get position of grid point (2, 3, 4) size_t some_index = 2 * Ny * Nz + 3 * Nz + 4; - Vector3d position = origin + Vector3d(2, 3, 4) * spacing; - EXPECT_EQ(position, grid.positionFromIndex(some_index)); + Vector3d some_grid_point = origin + Vector3d(2, 3, 4) * spacing + Vector3d(spacing / 2.); + EXPECT_EQ(some_grid_point, grid.positionFromIndex(some_index)); grid.get(2, 3, 4) = 7; EXPECT_FLOAT_EQ(7., grid.getGrid()[some_index]); - EXPECT_FLOAT_EQ(7., grid.interpolate(position)); + EXPECT_FLOAT_EQ(7., grid.interpolate(some_grid_point)); } TEST(ScalarGrid, ClosestValue) { - ScalarGrid grid(Vector3d(0.), 2, 1); + // Check some closest values + ScalarGrid grid(Vector3d(0.), 2, 2, 2, 1.); grid.get(0, 0, 0) = 1; grid.get(0, 0, 1) = 2; grid.get(0, 1, 0) = 3; @@ -285,33 +286,36 @@ TEST(ScalarGrid, ClosestValue) { grid.get(1, 1, 0) = 7; grid.get(1, 1, 1) = 8; - // Closest value - EXPECT_FLOAT_EQ(1, grid.closestValue(Vector3d(-0.2, 0, 0.4))); - EXPECT_FLOAT_EQ(2, grid.closestValue(Vector3d(0.2, 0.1, 0.9))); + // grid points are at 0.5 and 1.5 + EXPECT_FLOAT_EQ(1, grid.closestValue(Vector3d(0.1, 0.2, 0.6))); + EXPECT_FLOAT_EQ(2, grid.closestValue(Vector3d(0.2, 0.1, 1.3))); EXPECT_FLOAT_EQ(3, grid.closestValue(Vector3d(0.3, 1.2, 0.2))); - EXPECT_FLOAT_EQ(7, grid.closestValue(Vector3d(0.6, 0.7, 0.4))); + EXPECT_FLOAT_EQ(7, grid.closestValue(Vector3d(1.7, 1.8, 0.4))); } TEST(VectorGrid, Interpolation) { // Explicitly test trilinear interpolation double spacing = 2.793; - VectorGrid grid(Vector3d(0.), 3, spacing); + int n = 3; + VectorGrid grid(Vector3d(0.), n, n, n, spacing); grid.get(0, 0, 1) = Vector3f(1.7, 0., 0.); // set one value Vector3d b; - b = grid.interpolate(Vector3d(0, 0, 1) * spacing); + + // grid points are at (0.5, 1.5, 2.5) * spacing + b = grid.interpolate(Vector3d(0.5, 0.5, 1.5) * spacing); EXPECT_FLOAT_EQ(1.7, b.x); - b = grid.interpolate(Vector3d(0, 0, 0.9) * spacing); + b = grid.interpolate(Vector3d(0.5, 0.5, 1.4) * spacing); EXPECT_FLOAT_EQ(1.7 * 0.9, b.x); - b = grid.interpolate(Vector3d(0, 0, 1.1) * spacing); + b = grid.interpolate(Vector3d(0.5, 0.5, 1.6) * spacing); EXPECT_FLOAT_EQ(1.7 * 0.9, b.x); - b = grid.interpolate(Vector3d(0, 0.15, 0.9) * spacing); + b = grid.interpolate(Vector3d(0.5, 0.35, 1.6) * spacing); EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.85, b.x); - b = grid.interpolate(Vector3d(0, 2.15, 0.9) * spacing); + b = grid.interpolate(Vector3d(0.5, 2.65, 1.6) * spacing); EXPECT_FLOAT_EQ(1.7 * 0.9 * 0.15, b.x); } diff --git a/test/testSource.cpp b/test/testSource.cpp index b56e89026..148d567e1 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -40,7 +40,7 @@ TEST(SourceUniformDistributionBox, simpleTest) { TEST(SourceDensityGrid, withInRange) { // Create a grid with 10^3 cells ranging from (0, 0, 0) to (10, 10, 10) - Vector3d origin(0.5, 0.5, 0.5); + Vector3d origin(0, 0, 0); int cells = 10; double spacing = 1; ref_ptr grid = new ScalarGrid(origin, cells, spacing); @@ -66,7 +66,7 @@ TEST(SourceDensityGrid, withInRange) { TEST(SourceDensityGrid, OneAllowedCell) { // Create a grid with 2^3 cells ranging from (0, 0, 0) to (4, 4, 4) - Vector3d origin(1, 1, 1); + Vector3d origin(0, 0, 0); int cells = 2; double spacing = 2; ref_ptr grid = new ScalarGrid(origin, cells, spacing); @@ -106,9 +106,12 @@ TEST(SourceDensityGrid, OneAllowedCell) { TEST(SourceDensityGrid1D, withInRange) { // Create a grid with 10 cells ranging from 0 to 10 - Vector3d origin(0.5, 0, 0); - ref_ptr grid = new ScalarGrid(origin, 10, 1, 1, 1.0); + Vector3d origin(0, 0, 0); + int nCells = 10; + double spacing = 1.; + ref_ptr grid = new ScalarGrid(origin, nCells, 1, 1, spacing); + // set some values for (int i = 0; i < 10; i++) { grid->get(i, 0, 0) = 2; } @@ -124,19 +127,28 @@ TEST(SourceDensityGrid1D, withInRange) { } TEST(SourceDensityGrid1D, OneAllowedCell) { - Vector3d origin(0.5, 0, 0); - ref_ptr grid = new ScalarGrid(origin, 10, 1, 1, 1.0); + // Test if the only allowed cells is repeatedly selected + Vector3d origin(0, 0, 0); + int nCells = 10; + double spacing = 1.; + ref_ptr grid = new ScalarGrid(origin, nCells, 1, 1, spacing); + + // set some values for (int i = 0; i < 10; i++) { grid->get(i, 0, 0) = 0; } grid->get(5, 0, 0) = 1; + SourceDensityGrid1D source(grid); ParticleState p; - source.prepare(p); - // dialed position should be in range 5-6 - Vector3d pos = p.getPosition(); - EXPECT_LE(5, pos.x); - EXPECT_GE(6, pos.x); + + for (int i = 0; i < 100; i++) { + source.prepare(p); + // dialed position should be in range 5-6 + Vector3d pos = p.getPosition(); + EXPECT_LE(5, pos.x); + EXPECT_GE(6, pos.x); + } } TEST(SourcePowerLawSpectrum, simpleTest) { @@ -242,7 +254,8 @@ TEST(SourceList, luminosity) { meanE += c->initial.getEnergy(); } meanE /= 1000; - EXPECT_NEAR(80, meanE, 2); // this test can stochastically fail + EXPECT_NEAR(80, meanE, 2); + // this test can stochastically fail } int main(int argc, char **argv) { From acdecb58000ce859cd1b27f31bf78b7d76074d85 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sat, 9 Mar 2013 10:23:11 +0100 Subject: [PATCH 0285/1298] ElectronPairProduction: limit the fractional energy loss dE / E to 1 --- src/PhotonBackground.cpp | 2 +- src/module/Boundary.cpp | 4 ++-- src/module/ElectronPairProduction.cpp | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/PhotonBackground.cpp b/src/PhotonBackground.cpp index 010c58efb..1bc7dcf3a 100644 --- a/src/PhotonBackground.cpp +++ b/src/PhotonBackground.cpp @@ -15,7 +15,7 @@ static std::vector sKneiske(b, b + sizeof(b) / sizeof(double)); double photonFieldScaling(int photonField, double z) { if (photonField == IRB) return interpolate(z, zKneiske, sKneiske); - return pow(z + 1, 3); // CMB-like scaling + return pow(1 + z, 3); // CMB-like scaling } } // namespace mpc diff --git a/src/module/Boundary.cpp b/src/module/Boundary.cpp index a0e074411..4a4abca73 100644 --- a/src/module/Boundary.cpp +++ b/src/module/Boundary.cpp @@ -33,7 +33,7 @@ void PeriodicBox::setSize(Vector3d s) { std::string PeriodicBox::getDescription() const { std::stringstream s; - s << "Periodic box: origin " << origin / Mpc << "Mpc, "; + s << "Periodic box: origin " << origin / Mpc << " Mpc, "; s << "size " << size / Mpc << " Mpc"; return s.str(); } @@ -96,7 +96,7 @@ void ReflectiveBox::setSize(Vector3d s) { std::string ReflectiveBox::getDescription() const { std::stringstream s; - s << "Reflective box: origin " << origin / Mpc << "Mpc, "; + s << "Reflective box: origin " << origin / Mpc << " Mpc, "; s << "size " << size / Mpc << " Mpc"; return s.str(); } diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 7944c6bad..427a6d0b8 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -86,6 +86,9 @@ void ElectronPairProduction::process(Candidate *candidate) const { // dE(E) = Z^2 * loss_rate(E/A) * step double dE = Z * Z * rate * photonFieldScaling(photonField, z) * step; + + // prevent the energy loss from exceeding the actual energy + dE = std::min(E, dE); candidate->current.setEnergy(E - dE); } From c464f3a33c0234585a432a25f18779abe9382db1 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 12 Mar 2013 16:42:37 +0100 Subject: [PATCH 0286/1298] removed deprecated gadget wrappers --- CMakeLists.txt | 12 +- README | 2 +- .../mpc/magneticField/GadgetMagneticField.h | 36 ++++++ include/mpc/magneticField/SPHMagneticField.h | 81 -------------- python/mpc.i | 4 +- src/magneticField/SPHMagneticField.cpp | 104 ------------------ test/testSPHField.cpp | 78 ------------- 7 files changed, 41 insertions(+), 276 deletions(-) create mode 100644 include/mpc/magneticField/GadgetMagneticField.h delete mode 100644 include/mpc/magneticField/SPHMagneticField.h delete mode 100644 src/magneticField/SPHMagneticField.cpp delete mode 100644 test/testSPHField.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index baaa7bf03..0414ddd93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,14 +64,12 @@ endif(ENABLE_FFTW3F) # gadget (optional for SPH magnetic fields) find_package(Gadget) if(GADGET_FOUND) - list(APPEND MPC_EXTRA_SOURCES src/magneticField/SPHMagneticField.cpp) list(APPEND MPC_EXTRA_INCLUDES ${GADGET_INCLUDE_DIR}) list(APPEND MPC_EXTRA_LIBRARIES ${GADGET_LIBRARY}) add_definitions (-DMPC_HAVE_GADGET) list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_GADGET) - list(APPEND MPC_SWIG_DEFINES -I${GADGET_INCLUDE_DIR}/../share/gadget ) - list(APPEND MPC_SWIG_DEFINES -I${GADGET_INCLUDE_DIR} ) - + list(APPEND MPC_SWIG_DEFINES -I${GADGET_INCLUDE_DIR}/../share/gadget) + list(APPEND MPC_SWIG_DEFINES -I${GADGET_INCLUDE_DIR}) endif(GADGET_FOUND) # ROOT (optional for ROOT output) @@ -190,12 +188,6 @@ if(ENABLE_TESTING) add_executable(testSource test/testSource.cpp) target_link_libraries(testSource mpc gtest gtest_main pthread) add_test(testSource testSource) - - if(GADGET_FOUND) - add_executable(testSPHField test/testSPHField.cpp) - target_link_libraries(testSPHField mpc gtest gtest_main pthread) - add_test(testSPHField testSPHField) - endif(GADGET_FOUND) endif(ENABLE_TESTING) # ---------------------------------------------------------------------------- diff --git a/README b/README index c254a2e2b..f00c0d4c2 100644 --- a/README +++ b/README @@ -41,7 +41,7 @@ FFTW3F -> for turbulent magnetic field grids MPC needs the FFTW3 library compiled with the single precision option Gadget - -> for large scale structure using the smooth particle formalism + -> Magnetic fields for large scale structure data OpenMP -> for shared memory parallelization googleperftools diff --git a/include/mpc/magneticField/GadgetMagneticField.h b/include/mpc/magneticField/GadgetMagneticField.h new file mode 100644 index 000000000..6ce680c6e --- /dev/null +++ b/include/mpc/magneticField/GadgetMagneticField.h @@ -0,0 +1,36 @@ +#ifndef MPC_GADGETMAGNETICFIELD_H_ +#define MPC_GADGETMAGNETICFIELD_H_ + +#ifdef MPC_HAVE_GADGET + +#include "mpc/Units.h" +#include "mpc/magneticField/MagneticField.h" + +#include "gadget/MagneticField.h" + +namespace mpc { + +/** + @class GadgetMagneticField + @brief Wrapper for gadget::MagneticField + */ +class GadgetMagneticField: public MagneticField { + gadget::ref_ptr field; +public: + GadgetMagneticField(gadget::ref_ptr field) : field(field) { + + } + Vector3d getField(const Vector3d &position) const { + gadget::Vector3f b, r = gadget::Vector3f(position.x, position.y, position.z); + bool isGood = field->getField(r / kpc, b); + if (!isGood) + std::cerr << "mpc::SPHMagneticField invalid position : " << position + << std::endl; + return Vector3d(b.x, b.y, b.z) * gauss; + } +}; + +} // namespace mpc + +#endif // MPC_HAVE_GADGET +#endif // MPC_GADGETMAGNETICFIELD_H_ diff --git a/include/mpc/magneticField/SPHMagneticField.h b/include/mpc/magneticField/SPHMagneticField.h deleted file mode 100644 index acbc67646..000000000 --- a/include/mpc/magneticField/SPHMagneticField.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef MPC_SPHMAGNETICFIELD_H_ -#define MPC_SPHMAGNETICFIELD_H_ - -#ifdef MPC_HAVE_GADGET - -#include "mpc/magneticField/MagneticFieldGrid.h" -#include "mpc/Units.h" - -#include "gadget/Database.h" -#include "gadget/MagneticField.h" - -#include -#include - -namespace gadget { - class DirectMagneticField; - class SampledMagneticField; -} - -namespace mpc { - -/** - @class SPHMagneticField - @brief Wrapper for gadget::DirectMagneticField - */ -class SPHMagneticField: public MagneticField { - gadget::DirectMagneticField field; - gadget::FileDatabase database; -public: - SPHMagneticField(Vector3d origin, double size, size_t samples, - std::string filename); - SPHMagneticField(size_t samples, std::string filename); - - Vector3d getField(const Vector3d &position) const; - double getRho(const Vector3d &position) const; /*< Return the density in [kg / m^3] */ -}; - -/** - @class SPHMagneticFieldGrid - @brief Wrapper for gadget::SampledMagneticField - */ -class SPHMagneticFieldGrid: public MagneticField { - gadget::SampledMagneticField field; - gadget::FileDatabase database; - size_t samples; - std::string cachePrefix; - bool cacheEnabled; -public: - SPHMagneticFieldGrid(Vector3d origin, double size, size_t gridSize, - std::string filename); - SPHMagneticFieldGrid(size_t gridSize, std::string filename); - void init(const Vector3d &origin, double size); - Vector3d getField(const Vector3d &position) const; - void setCachePrefix(std::string prefix); - void setCacheEnabled(bool enabled); -}; - -/** - @class GadgetMagneticField - @brief Wrapper for gadget::MagneticField - */ -class GadgetMagneticField: public MagneticField { - gadget::ref_ptr field; -public: - GadgetMagneticField(gadget::ref_ptr field) : field(field) { - - } - Vector3d getField(const Vector3d &position) const { - gadget::Vector3f b, r = gadget::Vector3f(position.x, position.y, position.z); - bool isGood = field->getField(r / kpc, b); - if (!isGood) - std::cerr << "mpc::SPHMagneticField invalid position : " << position - << std::endl; - return Vector3d(b.x, b.y, b.z) * gauss; - } -}; - -} // namespace mpc - -#endif // MPC_HAVE_GADGET -#endif // MPC_SPHMAGNETICFIELD_H_ diff --git a/python/mpc.i b/python/mpc.i index 43a0a4fe3..6bc59cd4f 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -41,7 +41,7 @@ using std::ptrdiff_t; #include "mpc/magneticField/MagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" -#include "mpc/magneticField/SPHMagneticField.h" +#include "mpc/magneticField/GadgetMagneticField.h" #include "mpc/magneticField/JF2012Field.h" #include "mpc/Referenced.h" @@ -129,7 +129,7 @@ using std::ptrdiff_t; %template(ScalarGrid) mpc::Grid; %include "mpc/magneticField/MagneticFieldGrid.h" -%include "mpc/magneticField/SPHMagneticField.h" +%include "mpc/magneticField/GadgetMagneticField.h" %include "mpc/magneticField/JF2012Field.h" %include "mpc/ExplicitRungeKutta.h" diff --git a/src/magneticField/SPHMagneticField.cpp b/src/magneticField/SPHMagneticField.cpp deleted file mode 100644 index da7856900..000000000 --- a/src/magneticField/SPHMagneticField.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include "mpc/magneticField/SPHMagneticField.h" -#include "mpc/Units.h" - -#include "kiss/logger.h" - -namespace mpc { - -SPHMagneticField::SPHMagneticField(Vector3d origin, double size, size_t samples, - std::string filename) : - field(samples) { - database.open(filename); - gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; - field.init(v, size / kpc, database); -} - -SPHMagneticField::SPHMagneticField(size_t samples, std::string filename) : - field(samples) { - database.open(filename); -} - -Vector3d SPHMagneticField::getField(const Vector3d &position) const { - gadget::Vector3f r = gadget::Vector3f(position.x, position.y, position.z); - gadget::Vector3f b; - bool isGood = field.getField(r / kpc, b); - if (!isGood) - std::cerr << "mpc::SPHMagneticField invalid position : " << position - << std::endl; - Vector3d bField = Vector3d(b.x, b.y, b.z) * gauss; - return bField; -} - -double SPHMagneticField::getRho(const Vector3d& position) const { - gadget::Vector3f r = gadget::Vector3f(position.x, position.y, position.z); - size_t overlaps = 0; - float rho; - bool isGood = field.getRho(r / kpc, overlaps, rho); - if (!isGood) - std::cerr << "mpc::SPHMagneticField invalid position : " << position - << std::endl; - return rho * 1.98892e40 * kilogram * pow(0.7, 2) / pow(kpc, 3); -} - -SPHMagneticFieldGrid::SPHMagneticFieldGrid(Vector3d origin, double size, - size_t samples, std::string filename) : - samples(samples), field(samples), cacheEnabled(false) { - database.open(filename); - gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; - field.init(v, size / kpc, database); -} - -SPHMagneticFieldGrid::SPHMagneticFieldGrid(const size_t samples, - const std::string filename) : - samples(samples), field(samples) { - database.open(filename); -} - -Vector3d SPHMagneticFieldGrid::getField(const Vector3d &position) const { - gadget::Vector3f r = gadget::Vector3f(position.x, position.y, position.z); - gadget::Vector3f b; - bool isGood = field.getField(r / kpc, b); - if (!isGood) - std::cerr << "mpc::SPHMagneticField invalid position : " << position - << std::endl; - Vector3d bField = Vector3d(b.x, b.y, b.z) * gauss; - return bField; -} - -void SPHMagneticFieldGrid::init(const Vector3d &origin, double size) { - gadget::Vector3f v = gadget::Vector3f(origin.x, origin.y, origin.z) / kpc; - float s = size / kpc; - if (cacheEnabled) { - std::stringstream path; - path << cachePrefix << samples << "_" << s << "_" << v.x << "_" << v.y - << "_" << v.z << ".cache"; - std::string filename = path.str(); - std::ifstream infile(filename.c_str()); - if (infile) { - std::cout << "load cache file " << filename << std::endl; - field.init(v, s); - field.restore(filename); - } else { - field.init(v, s, database); - path << "." << time(NULL) << clock(); - std::string filename_tmp = path.str(); - field.dump(filename_tmp); - int ren = rename(filename_tmp.c_str(), filename.c_str()); - if (ren != 0) - remove(filename_tmp.c_str()); - } - } else { - field.init(v, s, database); - } -} - -void SPHMagneticFieldGrid::setCachePrefix(std::string prefix) { - cachePrefix = prefix; -} - -void SPHMagneticFieldGrid::setCacheEnabled(bool enabled) { - cacheEnabled = enabled; -} - -} // namespace mpc - diff --git a/test/testSPHField.cpp b/test/testSPHField.cpp deleted file mode 100644 index 27d948ae4..000000000 --- a/test/testSPHField.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "mpc/magneticField/SPHMagneticField.h" -#include "mpc/Units.h" -#include "mpc/Common.h" - -#include "gtest/gtest.h" - -namespace mpc { - -TEST(testSPHMagneticField, simpleTest) { - // Tests if a direct SPH field can be constructed and prints RMS and mean field strength - Vector3d origin(80 * Mpc); - double size = 40 * Mpc; - - // gadget::DirectField may throw if queried for magnetic fields on the borders - Vector3d safeOrigin = origin - Vector3d(1 * kpc); - double safeSize = size + 2 * kpc; - - SPHMagneticField B(safeOrigin, safeSize, 20, - getDataPath("SPH/mhd_z.db").c_str()); - - int n = 64; - double spacing = 40 * Mpc / (n - 1); - double brms = 0; - Vector3d bmean(0, 0, 0); - for (int ix = 0; ix < n; ix++) - for (int iy = 0; iy < n; iy++) - for (int iz = 0; iz < n; iz++) { - Vector3d b = B.getField( - origin + Vector3d(ix, iy, iz) * spacing); - brms += b.getMag2(); - bmean += b; - } - - brms = sqrt(brms / n / n / n); - bmean /= n * n * n; - - std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; - std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; -} - -TEST(testSPHMagneticFieldGrid, simpleTest) { - // Tests if a sampled SPH field can be constructed and prints RMS and mean field strength - Vector3d origin(80 * Mpc); - size_t n = 64; - double size = 40 * Mpc; - double spacing = size / (n - 1); - - // gadget::SampledField may throw if queried for magnetic fields on the borders - Vector3d safeOrigin = origin - Vector3d(1 * kpc); - double safeSize = size + 2 * kpc; - - SPHMagneticFieldGrid B(safeOrigin, safeSize, n, - getDataPath("SPH/mhd_z.db").c_str()); - - double brms = 0; - Vector3d bmean(0, 0, 0); - for (int ix = 0; ix < n; ix++) - for (int iy = 0; iy < n; iy++) - for (int iz = 0; iz < n; iz++) { - Vector3d b = B.getField( - origin + Vector3d(ix, iy, iz) * spacing); - brms += b.getMag2(); - bmean += b; - } - - brms = sqrt(brms / n / n / n); - bmean /= n * n * n; - - std::cout << "Mean B-Field: " << bmean / nG << " nG" << std::endl; - std::cout << "RMS B-Field: " << brms / nG << " nG" << std::endl; -} - -int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} - -} // namespace mpc From f29b707b1fc04c20d7d3807f6ae407bfa16fa2e6 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 14 Mar 2013 15:42:16 +0100 Subject: [PATCH 0287/1298] fix: make gadget optional in SWIG --- python/mpc.i | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/mpc.i b/python/mpc.i index 6bc59cd4f..4fd280a92 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -20,7 +20,9 @@ using std::ptrdiff_t; %include std_container.i %include "exception.i" +#ifdef MPC_HAVE_GADGET %import (module="gadget") gadget.i +#endif %{ #include "mpc/module/NuclearDecay.h" From a610c7db958102b93f63f0c393970e08fc22aca9 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 3 Apr 2013 15:50:00 +0200 Subject: [PATCH 0288/1298] moved cosmology calculations out of Redshift module removed SimpleRedshift --- CMakeLists.txt | 9 +- include/mpc/Cosmology.h | 56 +++++++ include/mpc/Source.h | 28 ++-- include/mpc/XmlExecute.h | 1 - include/mpc/module/Redshift.h | 96 +----------- python/mpc.i | 2 + src/Cosmology.cpp | 137 ++++++++++++++++++ src/Source.cpp | 23 ++- src/XmlExecute.cpp | 26 ++-- src/main.cpp | 10 +- src/module/Redshift.cpp | 121 +--------------- .../{testRedshift.py => testCosmology.py} | 10 +- test/testInteraction.cpp | 16 +- test/testSource.cpp | 8 +- 14 files changed, 252 insertions(+), 291 deletions(-) create mode 100644 include/mpc/Cosmology.h create mode 100644 src/Cosmology.cpp rename test/python/{testRedshift.py => testCosmology.py} (72%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0414ddd93..421c900e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ set(MPC_SWIG_DEFINES) # Dependencies # ---------------------------------------------------------------------------- # googletest (provided) -option(ENABLE_TESTING "Build tests and enable test target" OFF) +option(ENABLE_TESTING "Build tests and enable test target" ON) if(ENABLE_TESTING) include_directories(libs/gtest/include) add_subdirectory(libs/gtest) @@ -50,7 +50,7 @@ include(FindOpenMP) endif(ENABLE_OPENMP) # fftw3f (optional for turbulent magnetic fields) -option(ENABLE_FFTW3F "FFTW3F to create turbulent fields" OFF) +option(ENABLE_FFTW3F "FFTW3F to create turbulent fields" ON) if(ENABLE_FFTW3F) find_package(FFTW3F) if(FFTW3F_FOUND) @@ -73,7 +73,7 @@ if(GADGET_FOUND) endif(GADGET_FOUND) # ROOT (optional for ROOT output) -option(ENABLE_ROOT "ROOT Output" OFF) +option(ENABLE_ROOT "ROOT Output" ON) if(ENABLE_ROOT) find_package(ROOT) if(ROOT_FOUND) @@ -108,6 +108,7 @@ add_library(mpc SHARED src/ParticleState.cpp src/ParticleID.cpp src/ParticleMass.cpp + src/Cosmology.cpp src/Source.cpp src/Common.cpp src/PhotonBackground.cpp @@ -193,7 +194,7 @@ endif(ENABLE_TESTING) # ---------------------------------------------------------------------------- # Python # ---------------------------------------------------------------------------- -option(ENABLE_PYTHON "Create python library via SWIG" OFF) +option(ENABLE_PYTHON "Create python library via SWIG" ON) if(ENABLE_PYTHON) include(python/Python.cmake) include_directories(${PYTHON_INCLUDE_PATH}) diff --git a/include/mpc/Cosmology.h b/include/mpc/Cosmology.h new file mode 100644 index 000000000..17fe449f1 --- /dev/null +++ b/include/mpc/Cosmology.h @@ -0,0 +1,56 @@ +#ifndef MPC_COSMOLOGY_H_ +#define MPC_COSMOLOGY_H_ + +namespace mpc { + +/** + Set the cosmological parameters for a flat universe. + */ +void setCosmologyParameters(double hubbleParameter, double omegaMatter, + double omegaVacuum); + +/** + Hubble rate at given redshift + H(z) = H0 * sqrt(omegaM * (1 + z)^3 + omegaL) + */ +double hubbleRate(double redshift = 0); + +/** + Redshift of a comoving object at a given comoving distance to an observer at z = 0. + d_comoving(z) = c/H0 * int_0^z dz' / E(z') + */ +double comovingDistance2Redshift(double distance); + +/** + Comoving distance between an observer at z = 0 and a comoving object at z. + d_comoving(z) = c/H0 * int_0^z dz' / E(z') + */ +double redshift2ComovingDistance(double redshift); + +/** + Redshift of a comoving object at a given luminosity distance to an observer at z = 0. + d_luminosity(z) = (1 + z) * d_comoving(z) + */ +double luminosityDistance2Redshift(double distance); + +/** + Luminosity distance between an observer at z = 0 and a comoving object at z. + d_luminosity(z) = (1 + z) * d_comoving(z) + */ +double redshift2LuminosityDistance(double redshift); + +/** + Redshift of a comoving object at a given light travel distance to an observer at z = 0. + d_lighttravel(z) = c/H0 * int_0^z dz' / ((1 + z') * E(z')) + */ +double lightTravelDistance2Redshift(double distance); + +/** + Light travel distance between an observer at z = 0 and a comoving object at z. + d_lighttravel(z) = c/H0 * int_0^z dz' / ((1 + z') * E(z')) + */ +double redshift2LightTravelDistance(double redshift); + +} // namespace mpc + +#endif // MPC_COSMOLOGY_H_ diff --git a/include/mpc/Source.h b/include/mpc/Source.h index 940c37fc3..1c47db879 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -4,7 +4,6 @@ #include "mpc/Referenced.h" #include "mpc/Candidate.h" #include "mpc/Grid.h" -#include "mpc/module/Redshift.h" #include @@ -161,50 +160,49 @@ class SourceMultiplePositions: public SourceProperty { }; /** - @class SourceUniformDistributionSphere + @class SourceUniformSphere @brief Uniform random source positions inside a sphere */ -class SourceUniformDistributionSphere: public SourceProperty { +class SourceUniformSphere: public SourceProperty { Vector3d center; double radius; public: - SourceUniformDistributionSphere(Vector3d center, double radius); + SourceUniformSphere(Vector3d center, double radius); void prepare(ParticleState &particle) const; }; /** - @class SourceUniformDistributionOnSphere + @class SourceUniformShell @brief Uniform random source positions on a sphere */ -class SourceUniformDistributionOnSphere: public SourceProperty { +class SourceUniformShell: public SourceProperty { Vector3d center; double radius; public: - SourceUniformDistributionOnSphere(Vector3d center, double radius); + SourceUniformShell(Vector3d center, double radius); void prepare(ParticleState &particle) const; }; - /** - @class SourceUniformDistributionBox + @class SourceUniformBox @brief Uniform random source positions inside a box */ -class SourceUniformDistributionBox: public SourceProperty { +class SourceUniformBox: public SourceProperty { Vector3d origin; Vector3d size; public: - SourceUniformDistributionBox(Vector3d origin, Vector3d size); + SourceUniformBox(Vector3d origin, Vector3d size); void prepare(ParticleState &particle) const; }; /** - @class SourceUniformDistribution1D + @class SourceUniform1D @brief Uniform random source positions in for 1D simulations */ -class SourceUniformDistribution1D: public SourceProperty { +class SourceUniform1D: public SourceProperty { double minDistance, maxDistance; public: - SourceUniformDistribution1D(double minDistance, double maxDistance); + SourceUniform1D(double minDistance, double maxDistance); void prepare(ParticleState& particle) const; }; @@ -304,9 +302,7 @@ class SourceUniformRedshift: public SourceProperty { It must be added after a position setting source property. */ class SourceRedshift1D: public SourceProperty { - ref_ptr redshift; public: - SourceRedshift1D(Redshift* redshift); void prepare(Candidate &candidate) const; }; diff --git a/include/mpc/XmlExecute.h b/include/mpc/XmlExecute.h index 94d03f900..bd87a229a 100644 --- a/include/mpc/XmlExecute.h +++ b/include/mpc/XmlExecute.h @@ -32,7 +32,6 @@ class XmlExecute { Source source; bool is1D; bool hasRedshift; - ref_ptr redshift; size_t nTrajectories; double Emin; double maxStep; diff --git a/include/mpc/module/Redshift.h b/include/mpc/module/Redshift.h index e3f5d662b..99423454c 100644 --- a/include/mpc/module/Redshift.h +++ b/include/mpc/module/Redshift.h @@ -3,109 +3,17 @@ #include "mpc/Module.h" -#include - namespace mpc { -/** - @class SimpleRedshift - @brief Redshift and adiabatic energy loss using Hubble's law and the distance to an observer. - - Using Hubble's law v = H0*D and the the small redshift approximation v ~ c*z, the redshift is calculated as z ~ H0*D/c. - It is assumed that the particle starts with a redshift z, that corresponds to its distance to the observer. - This redshift is reduced with shrinking distance to the observer, and the particle loses energy accordingly. - Redshift and particle energy are not changed if the distance to the observer grows. - */ -class SimpleRedshift: public Module { -private: - Vector3d observer; // observer position (z = 0) - double h; // dimension-free Hubble constant, H0 = h * 100 km/s/Mpc - -public: - SimpleRedshift(Vector3d observer, double h = 0.7); - void process(Candidate *candidate) const; - std::string getDescription() const; -}; - /** @class Redshift - @brief Calculation of cosmological redshift and adiabatic energy loss - - This module implements the calculation of cosmological redshift for a flat universe. - It provides two functionalities: - 1) In a simulation chain it reduces the candidate's redshift according to the propagation step and applies the adiabatic energy loss. - 2) It provides translations from redshift to comoving distance and vice versa. + @brief Updates redshift and applies adiabatic energy loss according to the travelled distance. */ class Redshift: public Module { -private: - double H0; // Hubble rate at z=0 in [1/s], H0 = h * 100 km/s/Mpc - double omegaM; // matter density parameter - double omegaL; // vacuum energy parameter - - static const int n = 1000; - static const double zmin = 0.0001; - static const double zmax = 100; - - std::vector Z; // redshift - std::vector Dc; // comoving distance [m] - std::vector Dl; // luminosity distance [m] - std::vector Dt; // light travel distance [m] - public: - /** Constructor - @param h dimension-free Hubble constant, H0 = h * 100 km/s/Mpc - @param omegaM matter density parameter - @param omegaL vacuum energy parameter - */ - Redshift(double h = 0.7, double omegaM = 0.3, double omegaL = 0.7); void process(Candidate *candidate) const; - std::string getDescription() const; - - /** - Hubble rate at given redshift - H(z) = H0 * sqrt(omegaM * (1 + z)^3 + omegaL) - */ - double hubbleRate(double redshift) const; - /** - Dimensionless Hubble parameter at given redshift - E(z) = sqrt(omegaM * (1 + z)^3 + omegaL) - */ - double hubbleParameter(double redshift) const; - - /** - Redshift of a comoving object at a given comoving distance to an observer at z = 0. - d_comoving(z) = c/H0 * int_0^z dz' / E(z') - */ - double comovingDistance2Redshift(double distance) const; - /** - Comoving distance between an observer at z = 0 and a comoving object at z. - d_comoving(z) = c/H0 * int_0^z dz' / E(z') - */ - double redshift2ComovingDistance(double redshift) const; - - /** - Redshift of a comoving object at a given luminosity distance to an observer at z = 0. - d_luminosity(z) = (1 + z) * d_comoving(z) - */ - double luminosityDistance2Redshift(double distance) const; - /** - Luminosity distance between an observer at z = 0 and a comoving object at z. - d_luminosity(z) = (1 + z) * d_comoving(z) - */ - double redshift2LuminosityDistance(double redshift) const; - - /** - Redshift of a comoving object at a given light travel distance to an observer at z = 0. - d_lighttravel(z) = c/H0 * int_0^z dz' / ((1 + z') * E(z')) - */ - double lightTravelDistance2Redshift(double distance) const; - /** - Light travel distance between an observer at z = 0 and a comoving object at z. - d_lighttravel(z) = c/H0 * int_0^z dz' / ((1 + z') * E(z')) - */ - double redshift2LightTravelDistance(double redshift) const; }; } // namespace mpc -#endif /* MPC_REDSHIFT_H_ */ +#endif // MPC_REDSHIFT_H_ diff --git a/python/mpc.i b/python/mpc.i index 4fd280a92..19d57ab96 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -60,6 +60,7 @@ using std::ptrdiff_t; #include "mpc/Vector3.h" #include "mpc/Source.h" #include "mpc/Common.h" +#include "mpc/Cosmology.h" #include "mpc/PhotonBackground.h" #include "mpc/Grid.h" #include "mpc/GridTools.h" @@ -100,6 +101,7 @@ using std::ptrdiff_t; %include "mpc/Referenced.h" %include "mpc/Units.h" %include "mpc/Common.h" +%include "mpc/Cosmology.h" %include "mpc/PhotonBackground.h" %include "mpc/Random.h" %include "mpc/ParticleState.h" diff --git a/src/Cosmology.cpp b/src/Cosmology.cpp new file mode 100644 index 000000000..7825440cf --- /dev/null +++ b/src/Cosmology.cpp @@ -0,0 +1,137 @@ +#include "mpc/Cosmology.h" +#include "mpc/Units.h" +#include "mpc/Common.h" + +#include +#include +#include + +namespace mpc { + +/** + @class Cosmology + @brief Cosmology calculations + */ +struct Cosmology { + double H0; // Hubble parameter at z=0 + double omegaM; // matter density parameter + double omegaL; // vacuum energy parameter + + static const int n = 1000; + static const double zmin = 0.0001; + static const double zmax = 100; + + std::vector Z; // redshift + std::vector Dc; // comoving distance [m] + std::vector Dl; // luminosity distance [m] + std::vector Dt; // light travel distance [m] + + void update() { + double dH = c_light / H0; // Hubble distance + + std::vector E(n); + E[0] = 1; + + // Relation between comoving distance r and redshift z (cf. J.A. Peacock, Cosmological physics, p. 89 eq. 3.76) + // dr = c / H(z) dz, integration using midpoint rule + double dlz = log10(zmax) - log10(zmin); + double dz; + for (int i = 1; i < n; i++) { + Z[i] = zmin * pow(10, i * dlz / (n - 1)); // logarithmic even spacing + dz = (Z[i] - Z[i - 1]); // redshift step + E[i] = sqrt(omegaL + omegaM * pow(1 + Z[i], 3)); + Dc[i] = Dc[i - 1] + dH * dz * (1 / E[i] + 1 / E[i - 1]) / 2; + Dl[i] = (1 + Z[i]) * Dc[i]; + Dt[i] = Dt[i - 1] + dH * dz + * (1 / ((1 + Z[i]) * E[i]) + 1 / ((1 + Z[i - 1]) * E[i - 1])) / 2; + } + } + + Cosmology() { + H0 = 7e4 / Mpc; + omegaM = 0.3; + omegaL = 0.7; + + Z.resize(n); + Dc.resize(n); + Dl.resize(n); + Dt.resize(n); + + Z[0] = 0; + Dc[0] = 0; + Dl[0] = 0; + Dt[0] = 0; + + update(); + } + + void setParameters(double h, double oM, double oL) { + H0 = h * 1e5 / Mpc; + omegaM = oM; + omegaL = oL; + update(); + } +}; + +static Cosmology cosmology; // instance is created at runtime + + + +void setCosmologyParameters(double h, double oM, double oL) { + cosmology.setParameters(h, oM, oL); +} + +double hubbleRate(double z) { + return cosmology.H0 + * sqrt(cosmology.omegaL + cosmology.omegaM * pow(1 + z, 3)); +} + +double comovingDistance2Redshift(double d) { + if (d < 0) + throw std::runtime_error("Cosmology: d < 0"); + if (d > cosmology.Dc.back()) + throw std::runtime_error("Cosmology: d > dmax"); + return interpolate(d, cosmology.Dc, cosmology.Z); +} + +double redshift2ComovingDistance(double z) { + if (z < 0) + throw std::runtime_error("Cosmology: z < 0"); + if (z > cosmology.zmax) + throw std::runtime_error("Cosmology: z > zmax"); + return interpolate(z, cosmology.Z, cosmology.Dc); +} + +double luminosityDistance2Redshift(double d) { + if (d < 0) + throw std::runtime_error("Cosmology: d < 0"); + if (d > cosmology.Dl.back()) + throw std::runtime_error("Cosmology: d > dmax"); + return interpolate(d, cosmology.Dl, cosmology.Z); +} + +double redshift2LuminosityDistance(double z) { + if (z < 0) + throw std::runtime_error("Cosmology: z < 0"); + if (z > cosmology.zmax) + throw std::runtime_error("Cosmology: z > zmax"); + return interpolate(z, cosmology.Z, cosmology.Dl); +} + +double lightTravelDistance2Redshift(double d) { + if (d < 0) + throw std::runtime_error("Cosmology: d < 0"); + if (d > cosmology.Dt.back()) + throw std::runtime_error("Cosmology: d > dmax"); + return interpolate(d, cosmology.Dt, cosmology.Z); +} + +double redshift2LightTravelDistance(double z) { + if (z < 0) + throw std::runtime_error("Cosmology: z < 0"); + if (z > cosmology.zmax) + throw std::runtime_error("Cosmology: z > zmax"); + return interpolate(z, cosmology.Z, cosmology.Dt); +} + +} // namespace mpc diff --git a/src/Source.cpp b/src/Source.cpp index ae2358829..64372a1db 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -1,5 +1,6 @@ #include "mpc/Source.h" #include "mpc/Random.h" +#include "mpc/Cosmology.h" #include "HepPID/ParticleIDMethods.hh" #include @@ -166,43 +167,43 @@ void SourceMultiplePositions::prepare(ParticleState& particle) const { particle.setPosition(positions[i]); } -SourceUniformDistributionSphere::SourceUniformDistributionSphere( +SourceUniformSphere::SourceUniformSphere( Vector3d center, double radius) : center(center), radius(radius) { } -void SourceUniformDistributionSphere::prepare(ParticleState& particle) const { +void SourceUniformSphere::prepare(ParticleState& particle) const { Random &random = Random::instance(); double r = pow(random.rand(), 1. / 3.) * radius; particle.setPosition(random.randUnitVectorOnSphere() * r); } -SourceUniformDistributionOnSphere::SourceUniformDistributionOnSphere( +SourceUniformShell::SourceUniformShell( Vector3d center, double radius) : center(center), radius(radius) { } -void SourceUniformDistributionOnSphere::prepare(ParticleState& particle) const { +void SourceUniformShell::prepare(ParticleState& particle) const { Random &random = Random::instance(); particle.setPosition(random.randUnitVectorOnSphere() * radius); } -SourceUniformDistributionBox::SourceUniformDistributionBox(Vector3d origin, +SourceUniformBox::SourceUniformBox(Vector3d origin, Vector3d size) : origin(origin), size(size) { } -void SourceUniformDistributionBox::prepare(ParticleState& particle) const { +void SourceUniformBox::prepare(ParticleState& particle) const { Random &random = Random::instance(); Vector3d pos(random.rand(), random.rand(), random.rand()); particle.setPosition(pos * size + origin); } -SourceUniformDistribution1D::SourceUniformDistribution1D(double lo, double hi) : +SourceUniform1D::SourceUniform1D(double lo, double hi) : minDistance(lo), maxDistance(hi) { } -void SourceUniformDistribution1D::prepare(ParticleState& particle) const { +void SourceUniform1D::prepare(ParticleState& particle) const { Random& random = Random::instance(); double d = random.rand() * (maxDistance - minDistance) + minDistance; particle.setPosition(Vector3d(d, 0, 0)); @@ -312,13 +313,9 @@ void SourceUniformRedshift::prepare(Candidate& candidate) const { candidate.setRedshift(z); } -SourceRedshift1D::SourceRedshift1D(Redshift* redishift) : - redshift(redishift) { -} - void SourceRedshift1D::prepare(Candidate& candidate) const { double d = candidate.initial.getPosition().getMag(); - double z = redshift->comovingDistance2Redshift(d); + double z = comovingDistance2Redshift(d); candidate.setRedshift(z); } diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 06f6eeb36..90fef439a 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -1,10 +1,12 @@ #include "mpc/XmlExecute.h" #include "mpc/magneticField/MagneticFieldGrid.h" #include "mpc/GridTools.h" -#include "mpc/PhotonBackground.h" #include "mpc/Random.h" +#include "mpc/PhotonBackground.h" +#include "mpc/Cosmology.h" #include "mpc/module/SimplePropagation.h" #include "mpc/module/DeflectionCK.h" +#include "mpc/module/Redshift.h" #include "mpc/module/ElectronPairProduction.h" #include "mpc/module/PhotoPionProduction.h" #include "mpc/module/PhotoDisintegration.h" @@ -50,7 +52,7 @@ xml_node childNode(xml_node parent, string childName, return node; } -SourceUniformDistributionBox* loadSourceHomogeneousBox(pugi::xml_node &node) { +SourceUniformBox* loadSourceHomogeneousBox(pugi::xml_node &node) { Vector3d origin; origin.x = childValue(node, "Xmin_Mpc") * Mpc; origin.y = childValue(node, "Ymin_Mpc") * Mpc; @@ -64,7 +66,7 @@ SourceUniformDistributionBox* loadSourceHomogeneousBox(pugi::xml_node &node) { size -= origin; cout << " - Size: " << size / Mpc << endl; - return (new SourceUniformDistributionBox(origin, size)); + return (new SourceUniformBox(origin, size)); } SourceDensityGrid* loadSourceDensityGrid(pugi::xml_node &node) { @@ -163,7 +165,7 @@ bool XmlExecute::load(const string &filename) { // ----- environment ----- xml_node node; node = childNode(root, "Environment"); - std::string type = node.attribute("type").as_string(); + string type = node.attribute("type").as_string(); cout << "Environment: " << type << endl; if (type == "One Dimension") @@ -214,6 +216,8 @@ bool XmlExecute::load(const string &filename) { hasRedshift = !(noRedshift); if (hasRedshift) { + modules.add(new Redshift()); + double omegaM = 0.3; if (root.child("OmegaM")) omegaM = childValue(root, "OmegaM"); @@ -226,11 +230,9 @@ bool XmlExecute::load(const string &filename) { if (root.child("H0_km_s_Mpc")) childValue(root, "H0_km_s_Mpc"); - cout << "Redshift: OmegaM = " << omegaM << ", OmegaLambda = " + cout << "Cosmology: OmegaM = " << omegaM << ", OmegaLambda = " << omegaL << ", H0 = " << H0 << " km/s/Mpc" << endl; - - redshift = new Redshift(H0 / 100, omegaM, omegaL); - modules.add(redshift); + setCosmologyParameters(H0 / 100, omegaM, omegaL); } else { cout << " - No redshift" << endl; } @@ -281,7 +283,7 @@ bool XmlExecute::load(const string &filename) { if (is1D and hasRedshift) { cout << " - Redshift according to source distance" << endl; - source.addProperty(new SourceRedshift1D(redshift)); + source.addProperty(new SourceRedshift1D()); } // spectrum + composition @@ -365,7 +367,7 @@ void XmlExecute::loadGridMagneticField(xml_node &node) { ref_ptr field = new VectorGrid(origin, Nx, Ny, Nz, spacing); - std::string type = node.attribute("type").as_string(); + string type = node.attribute("type").as_string(); if (type == "LSS-Grid") { string filetype = node.child("File").attribute("type").as_string(); cout << " - File type: " << filetype << endl; @@ -494,7 +496,7 @@ void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { if (is1D) { double xmin = childValue(density_node, "Xmin_Mpc") * Mpc; double xmax = childValue(density_node, "Xmax_Mpc") * Mpc; - sourceDistribution = new SourceUniformDistribution1D(xmin, + sourceDistribution = new SourceUniform1D(xmin, xmax); } else { sourceDistribution = loadSourceHomogeneousBox(density_node); @@ -541,7 +543,7 @@ void XmlExecute::loadContinuousSources(pugi::xml_node &node) { double maxD = childValue(density_node, "Xmax_Mpc") * Mpc; cout << " - Minimum distance: " << minD / Mpc << " Mpc" << endl; cout << " - Maximum distance: " << maxD / Mpc << " Mpc" << endl; - source.addProperty(new SourceUniformDistribution1D(minD, maxD)); + source.addProperty(new SourceUniform1D(minD, maxD)); } else { source.addProperty(loadSourceHomogeneousBox(density_node)); } diff --git a/src/main.cpp b/src/main.cpp index 6fee4999c..735b497bc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,23 +3,19 @@ #include #include - -using namespace mpc; -using namespace std; - int main(int argc, char **argv) { if (argc < 2) { - cout << "mpc-run " << endl; + std::cout << "mpc-run " << std::endl; return 1; } try { - XmlExecute exe; + mpc::XmlExecute exe; if (!exe.load(argv[1])) return 1; exe.run(); } catch (std::exception &e) { - cerr << e.what() << endl; + std::cerr << e.what() << std::endl; return 1; } diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index 65a7ea418..8b7134148 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -1,120 +1,8 @@ #include "mpc/module/Redshift.h" -#include "mpc/Units.h" -#include "mpc/Common.h" - -#include -#include +#include "mpc/Cosmology.h" namespace mpc { -SimpleRedshift::SimpleRedshift(Vector3d observer, double h) : - observer(observer), h(h) { -} - -void SimpleRedshift::process(Candidate *c) const { - double d = c->current.getPosition().getDistanceTo(observer); - double z = h * 1e5 / Mpc * d / c_light; - double dz = c->getRedshift() - z; - - if (dz < 0) - return; // do nothing if the new redshift is higher - - c->setRedshift(z); - double E = c->current.getEnergy(); - c->current.setEnergy(E * (1 - dz / (1 + z))); // using dE/dz = E/(1+z) -} - -std::string SimpleRedshift::getDescription() const { - std::stringstream ss; - ss << "Simple redshift: observer " << observer / Mpc << "Mpc, h = " << h; - return ss.str(); -} - -Redshift::Redshift(double h, double m, double l) : - H0(h * 1e5 / Mpc), omegaM(m), omegaL(l) { - Z.resize(n); - Dc.resize(n); - Dl.resize(n); - Dt.resize(n); - std::vector E(n); // dimensionless Hubble parameter - double dH = c_light / H0; // Hubble distance - - Z[0] = 0; - Dc[0] = 0; - Dl[0] = 0; - Dt[0] = 0; - E[0] = 1; - - // Relation between comoving distance r and redshift z (cf. J.A. Peacock, Cosmological physics, p. 89 eq. 3.76) - // dr = c / H(z) dz, integration using midpoint rule - double dlz = log10(zmax) - log10(zmin); - double dz; - for (int i = 1; i < n; i++) { - Z[i] = zmin * pow(10, i * dlz / (n - 1)); // logarithmic even spacing - dz = (Z[i] - Z[i - 1]); // redshift step - E[i] = hubbleParameter(Z[i]); - Dc[i] = Dc[i - 1] + dH / 2 * dz * (1 / E[i] + 1 / E[i - 1]); - Dl[i] = (1 + Z[i]) * Dc[i]; - Dt[i] = Dt[i - 1] + dH / 2 * dz * (1 / ((1 + Z[i]) * E[i]) + 1 / ((1 + Z[i - 1]) * E[i - 1])); - } -} - -double Redshift::hubbleRate(double z) const { - return H0 * hubbleParameter(z); -} - -double Redshift::hubbleParameter(double z) const { - return sqrt(omegaL + omegaM * pow(1 + z, 3)); -} - -double Redshift::comovingDistance2Redshift(double d) const { - if (d < 0) - throw std::runtime_error("Redshift: d < 0"); - if (d > Dc[n - 1]) - throw std::runtime_error("Redshift: d > dmax"); - return interpolate(d, Dc, Z); -} - -double Redshift::redshift2ComovingDistance(double z) const { - if (z < 0) - throw std::runtime_error("Redshift: z < 0"); - if (z > zmax) - throw std::runtime_error("Redshift: z > zmax"); - return interpolate(z, Z, Dc); -} - -double Redshift::luminosityDistance2Redshift(double d) const { - if (d < 0) - throw std::runtime_error("Redshift: d < 0"); - if (d > Dl[n - 1]) - throw std::runtime_error("Redshift: d > dmax"); - return interpolate(d, Dl, Z); -} - -double Redshift::redshift2LuminosityDistance(double z) const { - if (z < 0) - throw std::runtime_error("Redshift: z < 0"); - if (z > zmax) - throw std::runtime_error("Redshift: z > zmax"); - return interpolate(z, Z, Dl); -} - -double Redshift::lightTravelDistance2Redshift(double d) const { - if (d < 0) - throw std::runtime_error("Redshift: d < 0"); - if (d > Dt[n - 1]) - throw std::runtime_error("Redshift: d > dmax"); - return interpolate(d, Dt, Z); -} - -double Redshift::redshift2LightTravelDistance(double z) const { - if (z < 0) - throw std::runtime_error("Redshift: z < 0"); - if (z > zmax) - throw std::runtime_error("Redshift: z > zmax"); - return interpolate(z, Z, Dt); -} - void Redshift::process(Candidate *c) const { double z = c->getRedshift(); if (z == 0) @@ -131,11 +19,4 @@ void Redshift::process(Candidate *c) const { c->current.setEnergy(E * (1 - dz / (1 + z))); } -std::string Redshift::getDescription() const { - std::stringstream ss; - ss << "Redshift: " << "H0 = " << H0 / 1e3 * Mpc << " km/s/Mpc, "; - ss << "OmegaL = " << omegaL << ", OmegaM = " << omegaM; - return ss.str(); -} - } // namespace mpc diff --git a/test/python/testRedshift.py b/test/python/testCosmology.py similarity index 72% rename from test/python/testRedshift.py rename to test/python/testCosmology.py index 58959c585..939848ea9 100644 --- a/test/python/testRedshift.py +++ b/test/python/testCosmology.py @@ -3,7 +3,7 @@ from pylab import * -redshift = Redshift() +setCosmologyParameters(0.71, 0.27, 0.73) N = 100 Z = logspace(-4, 2, N) @@ -11,11 +11,11 @@ Dl = zeros(N) # comoving distance Dt = zeros(N) # light travel distance for i in range(N): - Dc[i] = redshift.redshift2ComovingDistance(Z[i]) / Mpc - Dl[i] = redshift.redshift2LuminosityDistance(Z[i]) / Mpc - Dt[i] = redshift.redshift2LightTravelDistance(Z[i]) / Mpc + Dc[i] = redshift2ComovingDistance(Z[i]) / Mpc + Dl[i] = redshift2LuminosityDistance(Z[i]) / Mpc + Dt[i] = redshift2LightTravelDistance(Z[i]) / Mpc -H0 = redshift.hubbleRate(0) +H0 = hubbleRate(0) Dlin = c_light * Z / H0 / Mpc # Hubble's law figure() diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 363fc3c33..9fdf34afb 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -572,22 +572,8 @@ TEST(SophiaPhotoPionProduction, belowSophiaEnergyThreshold_IRB) { EXPECT_FALSE(hasInteraction); } -TEST(SimpleRedshift, test) { - // Test redshift approximation for small redshifts z << 1. - SimpleRedshift redshift(Vector3d(0.), 0.7); - - Candidate c; - c.setRedshift(0.024); // roughly corresponds to 100 Mpc - c.current.setEnergy(100 * EeV); - c.current.setPosition(Vector3d(0.)); - - redshift.process(&c); - EXPECT_EQ(0, c.getRedshift()); - EXPECT_GT(100, c.current.getEnergy() / EeV); -} - TEST(Redshift, test) { - Redshift redshift(0.7, 0.3, 0.7); + Redshift redshift; Candidate c; c.setRedshift(0.024); // roughly corresponds to 100 Mpc diff --git a/test/testSource.cpp b/test/testSource.cpp index 148d567e1..13c1cfa75 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -13,20 +13,20 @@ TEST(SourcePosition, simpleTest) { EXPECT_EQ(position, ps.getPosition()); } -TEST(SourceUniformDistributionSphere, simpleTest) { +TEST(SourceUniformSphere, simpleTest) { Vector3d center(0, 0, 0); double radius = 110; - SourceUniformDistributionSphere source(center, radius); + SourceUniformSphere source(center, radius); ParticleState ps; source.prepare(ps); double distance = ps.getPosition().getDistanceTo(center); EXPECT_GE(radius, distance); } -TEST(SourceUniformDistributionBox, simpleTest) { +TEST(SourceUniformBox, simpleTest) { Vector3d origin(-7, -2, 0); Vector3d size(13, 55, 192); - SourceUniformDistributionBox box(origin, size); + SourceUniformBox box(origin, size); ParticleState p; box.prepare(p); Vector3d pos = p.getPosition(); From ac8e107b62c863cc6a0b31705778903a354a44be Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 3 Apr 2013 16:58:16 +0200 Subject: [PATCH 0289/1298] SourceUniform1D now realizes a uniform source distribution in an expanding universe --- include/mpc/Cosmology.h | 6 ++++++ include/mpc/Source.h | 26 +++++++++++++++++--------- src/Cosmology.cpp | 16 ++++++++++++++++ src/Source.cpp | 8 +++++--- src/XmlExecute.cpp | 4 +--- 5 files changed, 45 insertions(+), 15 deletions(-) diff --git a/include/mpc/Cosmology.h b/include/mpc/Cosmology.h index 17fe449f1..26fa978c3 100644 --- a/include/mpc/Cosmology.h +++ b/include/mpc/Cosmology.h @@ -51,6 +51,12 @@ double lightTravelDistance2Redshift(double distance); */ double redshift2LightTravelDistance(double redshift); +// Conversion from comoving distance to light travel distance. +double comoving2LightTravelDistance(double distance); + +// Conversion from light travel distance to comoving distance. +double lightTravel2ComovingDistance(double distance); + } // namespace mpc #endif // MPC_COSMOLOGY_H_ diff --git a/include/mpc/Source.h b/include/mpc/Source.h index 1c47db879..4415001fb 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -197,21 +197,30 @@ class SourceUniformBox: public SourceProperty { /** @class SourceUniform1D - @brief Uniform random source positions in for 1D simulations + @brief 1D-Positions from a uniform source distribution in an expanding universe + + This source property sets random x-coordinates according to a uniform source + distribution in a given comoving distance interval. + This is done by drawing a light travel distance from a flat distribution and + converting to a comoving distance. */ class SourceUniform1D: public SourceProperty { - double minDistance, maxDistance; + double minDt; // minimum light travel distance [m] + double maxDt; // maximum light travel distance [m] public: - SourceUniform1D(double minDistance, double maxDistance); + /** + @param minD minimum comoving distance [m] + @param maxD maximum comoving distance [m] + */ + SourceUniform1D(double minD, double maxD); void prepare(ParticleState& particle) const; }; /** @class SourceDensityGrid - @brief Provides source positions from a density grid + @brief Random source positions from a density grid - This module takes a density grid to compute random initial positions. - The positions of the grid points are interpreted as bin centers, the values as source density in the bin. + This source property takes a density grid to compute random initial positions. To dial a source position, first a bin is drawn following the density distribution. Then a random position is drawn from a uniform distribution in the bin. */ @@ -225,10 +234,9 @@ class SourceDensityGrid: public SourceProperty { /** @class SourceDensityGrid1D - @brief Provides source positions from a 1D density grid + @brief Random source positions from a 1D density grid - This module takes a N*1*1 grid to compute random initial positions. - The positions of the grid points are interpreted as bin centers, the values as source density in the bin. + This source property takes a N*1*1 grid to compute random initial positions. To dial a source position, first a bin is drawn following the density distribution. Then a random position is drawn from a uniform distribution in the bin. */ diff --git a/src/Cosmology.cpp b/src/Cosmology.cpp index 7825440cf..d90c500d1 100644 --- a/src/Cosmology.cpp +++ b/src/Cosmology.cpp @@ -134,4 +134,20 @@ double redshift2LightTravelDistance(double z) { return interpolate(z, cosmology.Z, cosmology.Dt); } +double comoving2LightTravelDistance(double d) { + if (d < 0) + throw std::runtime_error("Cosmology: d < 0"); + if (d > cosmology.Dc.back()) + throw std::runtime_error("Cosmology: d > dmax"); + return interpolate(d, cosmology.Dc, cosmology.Dt); +} + +double lightTravel2ComovingDistance(double d) { + if (d < 0) + throw std::runtime_error("Cosmology: d < 0"); + if (d > cosmology.Dt.back()) + throw std::runtime_error("Cosmology: d > dmax"); + return interpolate(d, cosmology.Dt, cosmology.Dc); +} + } // namespace mpc diff --git a/src/Source.cpp b/src/Source.cpp index 64372a1db..065d484ca 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -199,13 +199,15 @@ void SourceUniformBox::prepare(ParticleState& particle) const { particle.setPosition(pos * size + origin); } -SourceUniform1D::SourceUniform1D(double lo, double hi) : - minDistance(lo), maxDistance(hi) { +SourceUniform1D::SourceUniform1D(double minD, double maxD) { + minDt = comoving2LightTravelDistance(minD); + maxDt = comoving2LightTravelDistance(maxD); } void SourceUniform1D::prepare(ParticleState& particle) const { Random& random = Random::instance(); - double d = random.rand() * (maxDistance - minDistance) + minDistance; + double d = random.rand() * (maxDt - minDt) + minDt; + d = lightTravel2ComovingDistance(d); particle.setPosition(Vector3d(d, 0, 0)); } diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 90fef439a..60a8adf30 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -266,9 +266,7 @@ bool XmlExecute::load(const string &filename) { node = childNode(root, "Sources"); // emission direction - if (is1D) - source.addProperty(new SourceDirection()); - else + if (!is1D) source.addProperty(new SourceIsotropicEmission()); // position From ae2db1591a16ba40683faf08c170b1648281bcb0 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 3 Apr 2013 17:12:16 +0200 Subject: [PATCH 0290/1298] XML steering: 1D uniform sources behave as in CRPropa2 --- src/XmlExecute.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 60a8adf30..959f0016c 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -147,12 +147,6 @@ bool XmlExecute::load(const string &filename) { nTrajectories = (int) childValue(root, "TrajNumber"); cout << "Number of particles: " << nTrajectories << endl; - double maxTime = childValue(root, "MaxTime_Mpc") * Mpc; - cout << "Maximum time: " << maxTime / Mpc << " Mpc" << endl; - - Emin = childValue(root, "MinEnergy_EeV") * EeV; - cout << "Minimum energy: " << Emin / EeV << " EeV" << endl; - xml_node seed_node = root.child("RandomSeed"); if (seed_node) { int seed = seed_node.attribute("value").as_int(); @@ -253,9 +247,15 @@ bool XmlExecute::load(const string &filename) { loadSophia(interaction_node); // ----- minimum energy ----- + Emin = childValue(root, "MinEnergy_EeV") * EeV; + cout << "Minimum energy: " << Emin / EeV << " EeV" << endl; modules.add(new MinimumEnergy(Emin)); // ----- maximum trajectory length ----- + double maxTime = childValue(root, "MaxTime_Mpc") * Mpc; + cout << "Maximum time: " << maxTime / Mpc << " Mpc" << endl; + if (is1D) + maxTime = lightTravel2ComovingDistance(maxTime); // convert to comoving distance modules.add(new MaximumTrajectoryLength(maxTime)); // ----- periodic boundaries ----- @@ -494,8 +494,9 @@ void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { if (is1D) { double xmin = childValue(density_node, "Xmin_Mpc") * Mpc; double xmax = childValue(density_node, "Xmax_Mpc") * Mpc; - sourceDistribution = new SourceUniform1D(xmin, - xmax); + xmin = lightTravel2ComovingDistance(xmin); + xmax = lightTravel2ComovingDistance(xmax); + sourceDistribution = new SourceUniform1D(xmin, xmax); } else { sourceDistribution = loadSourceHomogeneousBox(density_node); } @@ -539,8 +540,10 @@ void XmlExecute::loadContinuousSources(pugi::xml_node &node) { if (is1D) { double minD = childValue(density_node, "Xmin_Mpc") * Mpc; double maxD = childValue(density_node, "Xmax_Mpc") * Mpc; - cout << " - Minimum distance: " << minD / Mpc << " Mpc" << endl; - cout << " - Maximum distance: " << maxD / Mpc << " Mpc" << endl; + cout << " - Minimum light travel distance: " << minD / Mpc << " Mpc" << endl; + cout << " - Maximum light travel distance: " << maxD / Mpc << " Mpc" << endl; + minD = lightTravel2ComovingDistance(minD); + maxD = lightTravel2ComovingDistance(maxD); source.addProperty(new SourceUniform1D(minD, maxD)); } else { source.addProperty(loadSourceHomogeneousBox(density_node)); From addea93e39cadac2f561f426e4ff40f62486f31a Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 5 Apr 2013 11:03:23 +0200 Subject: [PATCH 0291/1298] changed Hubble default value to CRPropa 2 default --- include/mpc/module/Redshift.h | 1 + src/Cosmology.cpp | 2 +- src/module/Redshift.cpp | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/mpc/module/Redshift.h b/include/mpc/module/Redshift.h index 99423454c..453b78cfd 100644 --- a/include/mpc/module/Redshift.h +++ b/include/mpc/module/Redshift.h @@ -11,6 +11,7 @@ namespace mpc { */ class Redshift: public Module { public: + Redshift(); void process(Candidate *candidate) const; }; diff --git a/src/Cosmology.cpp b/src/Cosmology.cpp index d90c500d1..e74b489d8 100644 --- a/src/Cosmology.cpp +++ b/src/Cosmology.cpp @@ -48,7 +48,7 @@ struct Cosmology { } Cosmology() { - H0 = 7e4 / Mpc; + H0 = 71 * 1000 * meter / second / Mpc; // default values omegaM = 0.3; omegaL = 0.7; diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index 8b7134148..fd128bfed 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -3,6 +3,10 @@ namespace mpc { +Redshift::Redshift() { + setDescription("Redshift"); +} + void Redshift::process(Candidate *c) const { double z = c->getRedshift(); if (z == 0) From 104f8b6f68dfb772a0d6e4add19d2a99175445a3 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 8 Apr 2013 10:49:32 +0200 Subject: [PATCH 0292/1298] add "no cosmology" option to SourceUniform1D --- include/mpc/Source.h | 7 ++++--- src/Source.cpp | 26 +++++++++++++++----------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/include/mpc/Source.h b/include/mpc/Source.h index 4415001fb..bee8613e8 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -205,14 +205,15 @@ class SourceUniformBox: public SourceProperty { converting to a comoving distance. */ class SourceUniform1D: public SourceProperty { - double minDt; // minimum light travel distance [m] - double maxDt; // maximum light travel distance [m] + double minD; // minimum light travel distance [m] + double maxD; // maximum light travel distance [m] + bool withCosmology; public: /** @param minD minimum comoving distance [m] @param maxD maximum comoving distance [m] */ - SourceUniform1D(double minD, double maxD); + SourceUniform1D(double minD, double maxD, bool withCosmology=true); void prepare(ParticleState& particle) const; }; diff --git a/src/Source.cpp b/src/Source.cpp index 065d484ca..130df476f 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -167,8 +167,7 @@ void SourceMultiplePositions::prepare(ParticleState& particle) const { particle.setPosition(positions[i]); } -SourceUniformSphere::SourceUniformSphere( - Vector3d center, double radius) : +SourceUniformSphere::SourceUniformSphere(Vector3d center, double radius) : center(center), radius(radius) { } @@ -178,8 +177,7 @@ void SourceUniformSphere::prepare(ParticleState& particle) const { particle.setPosition(random.randUnitVectorOnSphere() * r); } -SourceUniformShell::SourceUniformShell( - Vector3d center, double radius) : +SourceUniformShell::SourceUniformShell(Vector3d center, double radius) : center(center), radius(radius) { } @@ -188,8 +186,7 @@ void SourceUniformShell::prepare(ParticleState& particle) const { particle.setPosition(random.randUnitVectorOnSphere() * radius); } -SourceUniformBox::SourceUniformBox(Vector3d origin, - Vector3d size) : +SourceUniformBox::SourceUniformBox(Vector3d origin, Vector3d size) : origin(origin), size(size) { } @@ -199,15 +196,22 @@ void SourceUniformBox::prepare(ParticleState& particle) const { particle.setPosition(pos * size + origin); } -SourceUniform1D::SourceUniform1D(double minD, double maxD) { - minDt = comoving2LightTravelDistance(minD); - maxDt = comoving2LightTravelDistance(maxD); +SourceUniform1D::SourceUniform1D(double minD, double maxD, bool withCosmology) { + this->withCosmology = withCosmology; + if (withCosmology) { + this->minD = comoving2LightTravelDistance(minD); + this->maxD = comoving2LightTravelDistance(maxD); + } else { + this->minD = minD; + this->maxD = maxD; + } } void SourceUniform1D::prepare(ParticleState& particle) const { Random& random = Random::instance(); - double d = random.rand() * (maxDt - minDt) + minDt; - d = lightTravel2ComovingDistance(d); + double d = random.rand() * (maxD - minD) + minD; + if (withCosmology) + d = lightTravel2ComovingDistance(d); particle.setPosition(Vector3d(d, 0, 0)); } From 5cfc0a8736b5b1d8a16fcad056673f1eec2c7f6c Mon Sep 17 00:00:00 2001 From: geromueller Date: Tue, 9 Apr 2013 16:51:32 +0200 Subject: [PATCH 0293/1298] add initial 3d photon propagation using dint --- CMakeLists.txt | 6 + include/mpc/Vector3.h | 10 + include/mpc/module/PhotonOutput.h | 30 + libs/dint/CMakeLists.txt | 31 + libs/dint/include/dint/advance.h | 167 ++++ libs/dint/include/dint/background.h | 61 ++ libs/dint/include/dint/binfread.h | 25 + libs/dint/include/dint/check.h | 10 + libs/dint/include/dint/const.h | 59 ++ libs/dint/include/dint/cvector.h | 31 + libs/dint/include/dint/decay.h | 10 + libs/dint/include/dint/deriv.h | 100 +++ libs/dint/include/dint/error.h | 9 + libs/dint/include/dint/final.h | 15 + libs/dint/include/dint/fold.h | 153 ++++ libs/dint/include/dint/frag.h | 17 + libs/dint/include/dint/gauleg.h | 7 + libs/dint/include/dint/inject.h | 12 + libs/dint/include/dint/io_util.h | 8 + libs/dint/include/dint/load.h | 81 ++ libs/dint/include/dint/math_util.h | 9 + libs/dint/include/dint/prepare.h | 48 ++ libs/dint/include/dint/prop_second.h | 94 +++ libs/dint/include/dint/rate.h | 102 +++ libs/dint/include/dint/spectrum.h | 48 ++ libs/dint/include/dint/sync.h | 23 + libs/dint/include/dint/utilities.h | 10 + libs/dint/include/dint/vector.h | 31 + libs/dint/src/advance.cpp | 845 ++++++++++++++++++++ libs/dint/src/background.cpp | 365 +++++++++ libs/dint/src/binfread.cpp | 64 ++ libs/dint/src/check.cpp | 27 + libs/dint/src/cvector.cpp | 36 + libs/dint/src/decay.cpp | 150 ++++ libs/dint/src/deriv.cpp | 477 ++++++++++++ libs/dint/src/error.cpp | 9 + libs/dint/src/final.cpp | 71 ++ libs/dint/src/fold.cpp | 826 ++++++++++++++++++++ libs/dint/src/frag.cpp | 582 ++++++++++++++ libs/dint/src/gauleg.cpp | 46 ++ libs/dint/src/inject.cpp | 55 ++ libs/dint/src/io_util.cpp | 15 + libs/dint/src/load.cpp | 330 ++++++++ libs/dint/src/math_util.cpp | 34 + libs/dint/src/prepare.cpp | 409 ++++++++++ libs/dint/src/prop_second.cpp | 1079 ++++++++++++++++++++++++++ libs/dint/src/rate.cpp | 909 ++++++++++++++++++++++ libs/dint/src/spectrum.cpp | 206 +++++ libs/dint/src/sync.cpp | 128 +++ libs/dint/src/vector.cpp | 224 ++++++ python/mpc.i | 15 +- src/module/PhotonOutput.cpp | 144 ++++ 52 files changed, 8248 insertions(+), 5 deletions(-) create mode 100644 include/mpc/module/PhotonOutput.h create mode 100644 libs/dint/CMakeLists.txt create mode 100644 libs/dint/include/dint/advance.h create mode 100644 libs/dint/include/dint/background.h create mode 100644 libs/dint/include/dint/binfread.h create mode 100644 libs/dint/include/dint/check.h create mode 100644 libs/dint/include/dint/const.h create mode 100644 libs/dint/include/dint/cvector.h create mode 100644 libs/dint/include/dint/decay.h create mode 100644 libs/dint/include/dint/deriv.h create mode 100644 libs/dint/include/dint/error.h create mode 100644 libs/dint/include/dint/final.h create mode 100644 libs/dint/include/dint/fold.h create mode 100644 libs/dint/include/dint/frag.h create mode 100644 libs/dint/include/dint/gauleg.h create mode 100644 libs/dint/include/dint/inject.h create mode 100644 libs/dint/include/dint/io_util.h create mode 100644 libs/dint/include/dint/load.h create mode 100644 libs/dint/include/dint/math_util.h create mode 100644 libs/dint/include/dint/prepare.h create mode 100644 libs/dint/include/dint/prop_second.h create mode 100644 libs/dint/include/dint/rate.h create mode 100644 libs/dint/include/dint/spectrum.h create mode 100644 libs/dint/include/dint/sync.h create mode 100644 libs/dint/include/dint/utilities.h create mode 100644 libs/dint/include/dint/vector.h create mode 100644 libs/dint/src/advance.cpp create mode 100644 libs/dint/src/background.cpp create mode 100644 libs/dint/src/binfread.cpp create mode 100644 libs/dint/src/check.cpp create mode 100644 libs/dint/src/cvector.cpp create mode 100644 libs/dint/src/decay.cpp create mode 100644 libs/dint/src/deriv.cpp create mode 100644 libs/dint/src/error.cpp create mode 100644 libs/dint/src/final.cpp create mode 100644 libs/dint/src/fold.cpp create mode 100644 libs/dint/src/frag.cpp create mode 100644 libs/dint/src/gauleg.cpp create mode 100644 libs/dint/src/inject.cpp create mode 100644 libs/dint/src/io_util.cpp create mode 100644 libs/dint/src/load.cpp create mode 100644 libs/dint/src/math_util.cpp create mode 100644 libs/dint/src/prepare.cpp create mode 100644 libs/dint/src/prop_second.cpp create mode 100644 libs/dint/src/rate.cpp create mode 100644 libs/dint/src/spectrum.cpp create mode 100644 libs/dint/src/sync.cpp create mode 100644 libs/dint/src/vector.cpp create mode 100644 src/module/PhotonOutput.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 421c900e6..faba4f40a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,11 @@ add_subdirectory(libs/sophia) list(APPEND MPC_EXTRA_LIBRARIES sophia gfortran) list(APPEND MPC_EXTRA_INCLUDES libs/sophia) +# dint (provided) +add_subdirectory(libs/dint) +list(APPEND MPC_EXTRA_LIBRARIES dint) +list(APPEND MPC_EXTRA_INCLUDES libs/dint/include) + # OpenMP (optional for shared memory multiprocessing) option(ENABLE_OPENMP "OpenMP for multithreading" ON) if(ENABLE_OPENMP) @@ -128,6 +133,7 @@ add_library(mpc SHARED src/module/Output.cpp src/module/OutputROOT.cpp src/module/OutputCRPropa2.cpp + src/module/PhotonOutput.cpp src/module/Tools.cpp src/magneticField/MagneticField.cpp src/magneticField/MagneticFieldGrid.cpp diff --git a/include/mpc/Vector3.h b/include/mpc/Vector3.h index a7be091cf..684d2d9b4 100644 --- a/include/mpc/Vector3.h +++ b/include/mpc/Vector3.h @@ -138,6 +138,16 @@ class Vector3 { x * v.y - v.x * y); } + double perp2(const Vector3 & p) const { + double tot = p.getMag2(); + double ss = dot(p); + return tot > 0.0 ? getMag2() - ss * ss / tot : getMag2(); + } + + double perp(const Vector3 & p) const { + return std::sqrt(perp2(p)); + } + void rotate(const Vector3 &axis, T angle) { T ux = axis.getX() / axis.getMag(); T uy = axis.getY() / axis.getMag(); diff --git a/include/mpc/module/PhotonOutput.h b/include/mpc/module/PhotonOutput.h new file mode 100644 index 000000000..b91cd2753 --- /dev/null +++ b/include/mpc/module/PhotonOutput.h @@ -0,0 +1,30 @@ +#ifndef MPC_MODULE_PHOTON_OUTPUT_H_ +#define MPC_MODULE_PHOTON_OUTPUT_H_ + +#include "mpc/Module.h" +#include "mpc/magneticField/MagneticField.h" + +#include + +namespace mpc { + +class PhotonOutput: public Module { +private: + std::string filename, dataPath; + mutable std::ofstream fout; + ref_ptr field; + + int IRFlag, RadioFlag; + double H0, OmegaLambda, OmegaM; + double Zmax, Cutcascade_Magfield; + +public: + PhotonOutput(const std::string &filename, ref_ptr field); + ~PhotonOutput(); + void process(Candidate *candidate) const; + std::string getDescription() const; +}; + +} // namespace mpc + +#endif /* MPC_MODULE_PHOTON_OUTPUT_H_ */ diff --git a/libs/dint/CMakeLists.txt b/libs/dint/CMakeLists.txt new file mode 100644 index 000000000..29ed421e3 --- /dev/null +++ b/libs/dint/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 2.6) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) + +add_library(dint STATIC + src/advance.cpp + src/background.cpp + src/binfread.cpp + src/check.cpp + src/cvector.cpp + src/decay.cpp + src/deriv.cpp + src/error.cpp + src/final.cpp + src/fold.cpp + src/frag.cpp + src/gauleg.cpp + src/inject.cpp + src/io_util.cpp + src/load.cpp + src/math_util.cpp + src/prepare.cpp + src/prop_second.cpp + src/rate.cpp + src/spectrum.cpp + src/sync.cpp + src/vector.cpp +) + +SET_TARGET_PROPERTIES(dint PROPERTIES COMPILE_FLAGS -fPIC) + diff --git a/libs/dint/include/dint/advance.h b/libs/dint/include/dint/advance.h new file mode 100644 index 000000000..01f52a53b --- /dev/null +++ b/libs/dint/include/dint/advance.h @@ -0,0 +1,167 @@ +#ifndef _ADVANCE_H_ +#define _ADVANCE_H_ + +#include +#include "dint/spectrum.h" +#include "dint/rate.h" +#include "dint/cvector.h" +#include "dint/const.h" +#include "dint/deriv.h" +#include "dint/error.h" + +const double EPSILON = 1.e-18; + +void ComputeRedshifts(const int sourceTypeSwitch, const double leftRedshift, + double* pDeltaRedshift, double* pRightRedshift, + double* pCentralRedshift, int* pLastIndex); +void AdvanceNucleonStep(const int sourceTypeSwitch, + const int PPPSwitch, const int NPPSwitch, + const int neutronDecaySwitch, + const int neutrinoNeutrinoSwitch, + const double smallDistanceStep, + const double evolutionFactor, + const double convergeParameter, + const double bkgFactor, + const Spectrum* pQ_0, + const DiffRate* elNeutProtonRate, + const DiffRate* muonNeutProtonRate, + const DiffRate* tauNeutProtonRate, + const TotalRate* protonTotalRate, + const TotalRate* neutronTotalRate, + const TotalRate* neutronDecayRate, + const DiffRate* protonScatRate, + const DiffRate* protonNeutronRate, + const DiffRate* neutronProtonRate, + const DiffRate* neutronDecayProtonRate, + const dCVector* protonContinuousLoss, + const dCVector* deltaG, const Spectrum* pSpectrum, + Spectrum* pSpectrumNew); +void AdvanceNeutrinoStep(const int sourceTypeSwitch, + const int neutrinoNeutrinoSwitch, + const int PPPSwitch, const int neutronDecaySwitch, + const int nucleonToSecondarySwitch, + const double smallDistanceStep, + const double evolutionFactor, + const double convergeParameter, + const double bkgFactor, + const Spectrum* pQ_0, + const DiffRate* protonMuonNeutrinoRate, + const DiffRate* neutronAntiMuonNeutrinoRate, + const DiffRate* protonAntiMuonNeutrinoRate, + const DiffRate* neutronMuonNeutrinoRate, + const DiffRate* protonElectronNeutrinoRate, + const DiffRate* neutronAntiElectronNeutrinoRate, + const DiffRate* protonAntiElectronNeutrinoRate, + const DiffRate* neutronDecayElectronRate, + const TotalRate* elNeutTotalRate, + const TotalRate* muonNeutTotalRate, + const TotalRate* tauNeutTotalRate, + const DiffRate* elNeutScatRate, + const DiffRate* elNeutMuonNeutRate, + const DiffRate* elNeutTauNeutRate, + const DiffRate* muonNeutElNeutRate, + const DiffRate* muonNeutScatRate, + const DiffRate* muonNeutTauNeutRate, + const DiffRate* tauNeutElNeutRate, + const DiffRate* tauNeutMuonNeutRate, + const DiffRate* tauNeutScatRate, + const Spectrum* pSpectrum, Spectrum* pSpectrumNew); +void AdvanceNucNeutStep(const int sourceTypeSwitch, + const int PPPSwitch, const int NPPSwitch, + const int neutronDecaySwitch, + const int nucleonToSecondarySwitch, + const int neutrinoNeutrinoSwitch, + const double smallDistanceStep, + const double evolutionFactor, + const double convergeParameter, + const double bkgFactor, + const Spectrum* pQ_0, + const DiffRate* elNeutProtonRate, + const DiffRate* muonNeutProtonRate, + const DiffRate* tauNeutProtonRate, + const TotalRate* protonTotalRate, + const TotalRate* neutronTotalRate, + const TotalRate* neutronDecayRate, + const DiffRate* protonScatRate, + const DiffRate* protonNeutronRate, + const DiffRate* neutronProtonRate, + const DiffRate* neutronDecayProtonRate, + const DiffRate* protonMuonNeutrinoRate, + const DiffRate* neutronAntiMuonNeutrinoRate, + const DiffRate* protonAntiMuonNeutrinoRate, + const DiffRate* neutronMuonNeutrinoRate, + const DiffRate* protonElectronNeutrinoRate, + const DiffRate* neutronAntiElectronNeutrinoRate, + const DiffRate* protonAntiElectronNeutrinoRate, + const DiffRate* neutronDecayElectronRate, + const TotalRate* elNeutTotalRate, + const TotalRate* muonNeutTotalRate, + const TotalRate* tauNeutTotalRate, + const DiffRate* elNeutScatRate, + const DiffRate* elNeutMuonNeutRate, + const DiffRate* elNeutTauNeutRate, + const DiffRate* muonNeutElNeutRate, + const DiffRate* muonNeutScatRate, + const DiffRate* muonNeutTauNeutRate, + const DiffRate* tauNeutElNeutRate, + const DiffRate* tauNeutMuonNeutRate, + const DiffRate* tauNeutScatRate, + const dCVector* protonContinuousLoss, + const dCVector* deltaG, const Spectrum* pSpectrum, + Spectrum* pSpectrumNew); +void AdvanceEMStep(const int sourceTypeSwitch, const int PPSwitch, + const int ICSSwitch, const int TPPSwitch, + const int DPPSwitch, const int synchrotronSwitch, + const int PPPSwitch, const int NPPSwitch, + const int neutronDecaySwitch, + const int nucleonToSecondarySwitch, + const int neutrinoNeutrinoSwitch, + const double smallDistanceStep, + const double evolutionFactor, + const double convergeParameter, const double bkgFactor, + const Spectrum* pQ_0, + const DiffRate* photonLeptonRate, + const DiffRate* protonElectronRate, + const DiffRate* neutronPositronRate, + const DiffRate* protonPositronRate, + const DiffRate* neutronElectronRate, + const DiffRate* neutronDecayElectronRate, + const DiffRate* elNeutElectronRate, + const DiffRate* muonNeutElectronRate, + const DiffRate* tauNeutElectronRate, + const DiffRate* protonPhotonRate, + const DiffRate* elNeutPhotonRate, + const DiffRate* muonNeutPhotonRate, + const DiffRate* tauNeutPhotonRate, + const TotalRate* leptonTotalRate, + const DiffRate* leptonScatRate, + const DiffRate* leptonExchRate, + const dCVector* continuousLoss, const dCVector* deltaG, + const TotalRate* photonTotalRate, + const DiffRate* leptonPhotonRate, + const DiffRate* syncRate, const Spectrum* pSpectrum, + Spectrum* pSpectrumNew); +void RedshiftDown(const int lastIndex, const double redshiftRatio, + const dCVector* pEnergy, Spectrum* pSpectrum, + Spectrum* pSpectrumNew); +void RedshiftBinsDown(const int lastIndex, const double evolutionFactor, + const dCVector* pEnergy, double* pSpectrum, + double* pSpectrumNew); +void GetExternalFlux(const int sourceTypeSwitch, const double evolutionFactor, + const PARTICLE particle, const Spectrum* pQ_0, + Spectrum* pInfluxExt); +void ImplicitEquation(const double smallDistanceStep, + const PARTICLE particle, const Spectrum* pInflux, + const Spectrum* pInflux0, const Spectrum* pInfluxExt, + const Spectrum* pOutflux, const Spectrum* pSpectrum, + Spectrum* pSpectrumNew); +void ExplicitEquation(const double smallDistanceStep, + const PARTICLE particle, const Spectrum* pInflux, + const Spectrum* pInflux0, const Spectrum* pInfluxExt, + const Spectrum* pOutflux, const Spectrum* pSpectrum, + const Spectrum* pSpectrumNew); +void ComputeChange(const Spectrum* pSpectrumTemp, + const Spectrum* pSpectrumNew, + const PARTICLE particle, double* pChangeMax); + +#endif diff --git a/libs/dint/include/dint/background.h b/libs/dint/include/dint/background.h new file mode 100644 index 000000000..4b17fa3e0 --- /dev/null +++ b/libs/dint/include/dint/background.h @@ -0,0 +1,61 @@ + +#ifndef _BACKGROUND_H_ +#define _BACKGROUND_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "dint/cvector.h" +#include "dint/error.h" +#include "dint/utilities.h" +#include "dint/const.h" +#include "dint/gauleg.h" + +#define GAULEG_POINTS 31 // number of gaussian quadrature points for integration + +using namespace std; + +void LoadPhotonBackground(const double redshift, + dCVector* pBgEnergy, dCVector* pBgEnergyWidth, + dCVector* pBgPhotonDensity, const int aIRFlag, + const double aZmax_IR, const int aRadioFlag, + const double aH0, const double aOmegaM, const double aOmegaLambda); +void LoadCMB(const double redshift, const dCVector* pBgEnergy, + const dCVector* pBgEnergyWidth, dCVector* pBgPhotonDensity); +void LoadIR(const double redshift, const dCVector* pBgEnergy, + const dCVector* pBgEnergyWidth, dCVector* pBgPhotonDensity, + const int aIRFlag, const double aZmax_IR); +double IR2(const double redshift, const double BgEnergy); +double HighIR(const double zTarget, const double zObserve, + const double energy0, const double deltaO, + const double deltaD); +double LowIR(const double zTarget, const double zObserve, + const double energy0, const double deltaO, + const double deltaD); +double OpticalIR(const double energy); +double DustIR(const double energy); +void LoadRadio(const double redshift, const dCVector* pBgEnergy, + const dCVector* pBgEnergyWidth, dCVector* pBgPhotonDensity, + const int aRadioFlag, const double aH0, const double aOmegaM, + const double aOmegaLambda); +double HighRadio(const double zTarget, const double zObserve, + const double energy0, const double aH0, + const double aOmegaM, const double aOmegaLambda); +double MedRadio(const double zTarget, const double zObserve, + const double energy0, const double aH0, const double aOmegaM, + const double aOmegaLambda); +double ObsRadio(const double zTarget, const double zObserve, + const double energy0, const double aH0, + const double aOmegaM, const double aOmegaLambda); +/* +// Routine added by Gunter (July 2005) : +void DumpBgSpectrum(const dCVector* pBgEnergy, const dCVector* pBgEnergyWidth, + const dCVector* pBgPhotonDensity, const char* filename); +*/ + +#endif diff --git a/libs/dint/include/dint/binfread.h b/libs/dint/include/dint/binfread.h new file mode 100644 index 000000000..f713e78a0 --- /dev/null +++ b/libs/dint/include/dint/binfread.h @@ -0,0 +1,25 @@ + +#ifndef _BINFREAD_H_ +#define _BINFREAD_H_ + +// T. Beau 2005 + +// Allow to deal with big / little endian machines. +// Data have been written on a Intel Machine... + +#include +#include +#include + +#if HAVE_ARPA_INET_H +#include +#endif + +#if HAVE_NETINET_IN_H +#include +#endif + +size_t binfread(void *, size_t, size_t, FILE *); + +#endif + diff --git a/libs/dint/include/dint/check.h b/libs/dint/include/dint/check.h new file mode 100644 index 000000000..e70cb038c --- /dev/null +++ b/libs/dint/include/dint/check.h @@ -0,0 +1,10 @@ +#ifndef _CHECK_H_ +#define _CHECK_H_ + +#include "dint/cvector.h" + +void CheckIndex(const int lowerLimit, const int upperLimit, const int i, + const char* functionName); +void DumpArray(const dCVector* pVector); + +#endif diff --git a/libs/dint/include/dint/const.h b/libs/dint/include/dint/const.h new file mode 100644 index 000000000..ddbf8cb5a --- /dev/null +++ b/libs/dint/include/dint/const.h @@ -0,0 +1,59 @@ + +#ifndef _CONST_H_ +#define _CONST_H_ + + +#define ELECTRON_MASS 5.110e5 +#define DISTANCE_UNIT 3.0856e18 +#define VOLUME_UNIT 6.652448e-25*3.0856e18 +#define PI 3.141592 +#define C 3.e10 +#define H_0 71. +// Added July 2005 : cosmological parameters +#define OMEGA_M 0.3// NOW THEY ARE NOT defined like this, but taken as input parameters. +#define OMEGA_LAMBDA 0.7 // if not specified as parameters, take these values + +// CHANGE (Guenter; 7/20/1998) +#define DMAX 1.e6 +#define CLUSTER_DISTANCE 100. +#define CLUSTER_FACTOR 1. +#define SOURCE_CLUSTER_DISTANCE 0.1 +#define SOURCE_CLUSTER_FACTOR 1. + +#define NUM_IP_ELEMENTS 1309125 +#define NUM_IS_ELEMENTS 571200 +#define NUM_PP_ELEMENTS 558050 +#define NUM_TPP_ELEMENTS 548250 +// photopion production +#define NUM_PPP_PROTON_SCAT_ELEMENTS 111541 +#define NUM_PPP_PROTON_NEUTRON_ELEMENTS 111541 +#define NUM_PPP_PROTON_PHOTON_ELEMENTS 20000 +#define NUM_PPP_PROTON_ELECTRON_ELEMENTS 20000 +#define NUM_PPP_PROTON_POSITRON_ELEMENTS 20000 +// nucleon pair production +#define NUM_NPP_ELEMENTS 20000 +// neutrino production from PPP +#define NUM_PPP_PROTON_ANTI_ELECTRON_NEUTRINO_ELEMENTS 20000 +#define NUM_PPP_PROTON_MUON_NEUTRINO_ELEMENTS 20000 +#define NUM_PPP_PROTON_ANTI_MUON_NEUTRINO_ELEMENTS 20000 + +// Parameters used in the code +// Warning : those cannot be changed unless various parts of CRPropa are also changed! +#define BINS_PER_DECADE 10 // number of bins per decade +#define MIN_ENERGY_EXP 7 // minimum spectrum energy = 10 MeV +#define MAX_ENERGY_EXP (MIN_ENERGY_EXP + 17) // maximum spectrum energy + +#define BG_MIN_ENERGY_EXP (-8 - MIN_ENERGY_EXP + 7) +#define BG_MAX_ENERGY_EXP (2 - MIN_ENERGY_EXP + 7) +#define EM_MIN_ENERGY_EXP (MIN_ENERGY_EXP) +#define NUC_MIN_ENERGY_EXP (14 + MIN_ENERGY_EXP - 7) +#define NEUT_MIN_ENERGY_EXP (17 + MIN_ENERGY_EXP - 7) +#define NUM_MAIN_BINS ((MAX_ENERGY_EXP - MIN_ENERGY_EXP)*BINS_PER_DECADE) +#define NUM_BG_BINS ((BG_MAX_ENERGY_EXP - BG_MIN_ENERGY_EXP)*BINS_PER_DECADE) + +#define EM_NUM_MAIN_BINS ((MAX_ENERGY_EXP - EM_MIN_ENERGY_EXP)*BINS_PER_DECADE) +#define NUC_NUM_MAIN_BINS ((MAX_ENERGY_EXP - NUC_MIN_ENERGY_EXP)*BINS_PER_DECADE) +#define NEUT_NUM_MAIN_BINS ((MAX_ENERGY_EXP - NEUT_MIN_ENERGY_EXP)*BINS_PER_DECADE) + + +#endif diff --git a/libs/dint/include/dint/cvector.h b/libs/dint/include/dint/cvector.h new file mode 100644 index 000000000..bec1bcede --- /dev/null +++ b/libs/dint/include/dint/cvector.h @@ -0,0 +1,31 @@ + +#ifndef _CVECTOR_H_ +#define _CVECTOR_H_ + +#include "dint/vector.h" +#include + +// these are variants of structs defined in vector.h; they have dimensional +// info built-in, and they are initialized when assigned memory +typedef struct +{ + int dimension; + dVector vector; +} dCVector; + +typedef struct +{ + int dimension1; + int dimension2; + iMatrix matrix; +} iCMatrix; + +void New_dCVector(dCVector* pVector, const int n); +void Delete_dCVector(dCVector* pVector); +void Initialize_dCVector(dCVector* pVector); + +void New_iCMatrix(iCMatrix* pMatrix, const int n1, const int n2); +void Delete_iCMatrix(iCMatrix* pMatrix); +void Initialize_iCMatrix(iCMatrix* pMatrix); + +#endif diff --git a/libs/dint/include/dint/decay.h b/libs/dint/include/dint/decay.h new file mode 100644 index 000000000..0a39f63c0 --- /dev/null +++ b/libs/dint/include/dint/decay.h @@ -0,0 +1,10 @@ +#ifndef _DECAY_H_ +#define _DECAY_H_ + +double PionToPhoton(const int iPhoton, const int iPion); +double PionToLepton(const double leptonEnergy, const double pionEnergy); +double PionToElectronNeutrino(const double neutrinoEnergy, + const double pionEnergy); +double PionToMuonNeutrino(const int iNeutrino, const int iPion); + +#endif diff --git a/libs/dint/include/dint/deriv.h b/libs/dint/include/dint/deriv.h new file mode 100644 index 000000000..5559f4d55 --- /dev/null +++ b/libs/dint/include/dint/deriv.h @@ -0,0 +1,100 @@ +#ifndef _DERIV_H_ +#define _DERIV_H_ + +#include "dint/rate.h" +#include "dint/spectrum.h" +#include "dint/cvector.h" + + +void GetLeptonInfluxFromPhotons(const DiffRate* photonLeptonRate, + const Spectrum* pSpectrumNew, + Spectrum* pInflux); +void GetLeptonFluxFromLeptons(const TotalRate* leptonTotalRate, + const DiffRate* leptonScatRate, + const DiffRate* leptonExchRate, + const dCVector* continuousLoss, + const dCVector* deltaG, + const Spectrum* pSpectrumNew, Spectrum* pInflux, + Spectrum* pOutflux); +void GetPhotonInfluxFromLeptons(const DiffRate* leptonPhotonRate, + const int synchrotronSwitch, + const DiffRate* syncRate, + const Spectrum* pSpectrumNew, + Spectrum* pInflux); +void GetPhotonFluxFromPhotons(const TotalRate* photonTotalRate, + Spectrum* pOutflux); +void GetLeptonInfluxFromNucleons(const int neutronDecaySwitch, + const DiffRate* protonElectronRate, + const DiffRate* neutronPositronRate, + const DiffRate* protonPositronRate, + const DiffRate* neutronElectronRate, + const DiffRate* neutronDecayElectronRate, + const Spectrum* pSpectrumNew, + Spectrum* pInflux); +void GetPhotonInfluxFromNucleons(const DiffRate* protonPhotonRate, + const Spectrum* pSpectrumNew, + Spectrum* pInflux); +void GetLeptonInfluxFromNeutrinos(const double bkgFactor, + const DiffRate* elNeutElectronRate, + const DiffRate* muonNeutElectronRate, + const DiffRate* tauNeutElectronRate, + const Spectrum* pSpectrumNew, + Spectrum* pInflux0); +void GetPhotonInfluxFromNeutrinos(const double bkgFactor, + const DiffRate* elNeutPhotonRate, + const DiffRate* muonNeutPhotonRate, + const DiffRate* tauNeutPhotonRate, + const Spectrum* pSpectrumNew, + Spectrum* pInflux0); +void GetNucleonFluxFromNucleons(const int neutronDecaySwitch, + const TotalRate* protonTotalRate, + const TotalRate* neutronTotalRate, + const TotalRate* neutronDecayRate, + const DiffRate* protonScatRate, + const DiffRate* neutronProtonRate, + const DiffRate* protonNeutronRate, + const DiffRate* neutronDecayProtonRate, + const dCVector* protonContinuousLoss, + const dCVector* deltaG, + const Spectrum* pSpectrumNew, + Spectrum* pInflux, Spectrum* pOutflux); +void GetNeutrinoInfluxFromNucleons(const int neutronDecaySwitch, + const DiffRate* protonMuonNeutrinoRate, + const DiffRate* neutronAntiMuonNeutrinoRate, + const DiffRate* neutronMuonNeutrinoRate, + const DiffRate* protonAntiMuonNeutrinoRate, + const DiffRate* protonElectronNeutrinoRate, + const DiffRate* neutronAntiElectronNeutrinoRate, + const DiffRate* protonAntiElectronNeutrinoRate, + const DiffRate* neutronDecayElectronRate, + const Spectrum* pSpectrumNew, + Spectrum* pInflux0); +void GetNucleonInfluxFromNeutrinos(const double bkgFactor, + const DiffRate* elNeutProtonRate, + const DiffRate* muonNeutProtonRate, + const DiffRate* tauNeutProtonRate, + const Spectrum* pSpectrumNew, + Spectrum* pInflux0); +void GetNeutrinoFluxFromNeutrinos(const double bkgFactor, + const TotalRate* elNeutTotalRate, + const TotalRate* muonNeutTotalRate, + const TotalRate* tauNeutTotalRate, + const DiffRate* elNeutScatRate, + const DiffRate* elNeutMuonNeutRate, + const DiffRate* elNeutTauNeutRate, + const DiffRate* muonNeutElNeutRate, + const DiffRate* muonNeutScatRate, + const DiffRate* muonNeutTauNeutRate, + const DiffRate* tauNeutElNeutRate, + const DiffRate* tauNeutMuonNeutRate, + const DiffRate* tauNeutScatRate, + const Spectrum* pSpectrumNew, + Spectrum* pInflux, Spectrum* pOutflux); + +void ComputeOutflux(const double bkgFactor, const TotalRate* pRate, + const PARTICLE parent, Spectrum* pOutflux); +void ComputeInflux(const double bkgFactor, const DiffRate* pRate, + const PARTICLE parent, const PARTICLE daughter, + const Spectrum* pSpectrum, Spectrum* pInflux); + +#endif diff --git a/libs/dint/include/dint/error.h b/libs/dint/include/dint/error.h new file mode 100644 index 000000000..efca50cf0 --- /dev/null +++ b/libs/dint/include/dint/error.h @@ -0,0 +1,9 @@ +#ifndef _ERROR_H_ +#define _ERROR_H_ + +typedef enum {NO_ERROR = 0, ARRAY_ERROR = 1, IO_ERROR = 2, PROGRAM_ERROR = 3} +ErrorCode; + +void Error(const char* errorMessage, const ErrorCode errorCode); + +#endif diff --git a/libs/dint/include/dint/final.h b/libs/dint/include/dint/final.h new file mode 100644 index 000000000..03f2228d8 --- /dev/null +++ b/libs/dint/include/dint/final.h @@ -0,0 +1,15 @@ +#ifndef _FINAL_H_ +#define _FINAL_H_ + +#include "dint/spectrum.h" +#include "dint/cvector.h" + +void CheckEnergy(const int sourceTypeSwitch, const double brightPhaseExp, + const double startingRedshift, + const double rightRedshift, const Spectrum* pSpectrum, + const dCVector* pEnergy, const double initialTotalEnergy); +void FinalPrintOutToTheScreen(const double distance, + const double startingRedshift, + const double propagatingDistance); + +#endif diff --git a/libs/dint/include/dint/fold.h b/libs/dint/include/dint/fold.h new file mode 100644 index 000000000..d34fee4c1 --- /dev/null +++ b/libs/dint/include/dint/fold.h @@ -0,0 +1,153 @@ +#ifndef _FOLD_H_ +#define _FOLD_H_ + +#include "dint/rate.h" +#include "dint/cvector.h" + +void InitializeLeptonCoefficients(TotalRate* leptonTotalRate, + DiffRate* leptonScatRate, + DiffRate* leptonExchRate, + DiffRate* leptonPhotonRate); +void InitializePhotonCoefficients(TotalRate* photonTotalRate, + DiffRate* photonLeptonRate); +void InitializeNucleonCoefficients(TotalRate* protonTotalRate, + TotalRate* neutronTotalRate, + DiffRate* protonScatRate, + DiffRate* protonNeutronRate, + DiffRate* neutronProtonRate, + DiffRate* protonPhotonRate, + DiffRate* protonElectronRate, + DiffRate* protonPositronRate, + DiffRate* neutronElectronRate, + DiffRate* neutronPositronRate, + DiffRate* protonElectronNeutrinoRate, + DiffRate* protonAntiElectronNeutrinoRate, + DiffRate* protonMuonNeutrinoRate, + DiffRate* protonAntiMuonNeutrinoRate, + DiffRate* neutronAntiElectronNeutrinoRate, + DiffRate* neutronMuonNeutrinoRate, + DiffRate* neutronAntiMuonNeutrinoRate); +void InitializeNeutrinoCoefficients(TotalRate* elNeutTotalRate, + TotalRate* muonNeutTotalRate, + TotalRate* tauNeutTotalRate, + DiffRate* elNeutScatRate, + DiffRate* elNeutMuonNeutRate, + DiffRate* elNeutTauNeutRate, + DiffRate* elNeutElectronRate, + DiffRate* elNeutPhotonRate, + DiffRate* elNeutProtonRate, + DiffRate* muonNeutElNeutRate, + DiffRate* muonNeutScatRate, + DiffRate* muonNeutTauNeutRate, + DiffRate* muonNeutElectronRate, + DiffRate* muonNeutPhotonRate, + DiffRate* muonNeutProtonRate, + DiffRate* tauNeutElNeutRate, + DiffRate* tauNeutMuonNeutRate, + DiffRate* tauNeutScatRate, + DiffRate* tauNeutElectronRate, + DiffRate* tauNeutPhotonRate, + DiffRate* tauNeutProtonRate); +void FoldTotalRate(const dCVector* pBgPhotonDensity, + const RawTotalRate* pRawTotalRate, TotalRate* pTotalRate); +void FoldDiffRate(const dCVector* pBgPhotonDensity, + const RawDiffRate* pRawDiffRate, + DiffRate* pDiffRate, const int scatSwitch, ...); +void FoldICS(const dCVector* pBgPhotonDensity, + const RawTotalRate* ICSTotalRate, + const RawDiffRate* ICSPhotonRate, const RawDiffRate* ICSScatRate, + TotalRate* leptonTotalRate, DiffRate* leptonPhotonRate, + DiffRate* leptonScatRate); +void FoldTPP(const dCVector* pBgPhotonDensity, const dCVector* pEnergy, + const RawTotalRate* TPPTotalRate, const RawDiffRate* TPPDiffRate, + TotalRate* leptonTotalRate, DiffRate* leptonScatRate, + DiffRate* leptonExchRate, dCVector* otherLoss); +void FoldPP(const dCVector* pBgPhotonDensity, const RawTotalRate* PPTotalRate, + const RawDiffRate* PPDiffRate, TotalRate* photonTotalRate, + DiffRate* photonLeptonRate); +void FoldDPP(const dCVector* pBgPhotonDensity, const RawTotalRate* DPPRate, + TotalRate* photonTotalRate, DiffRate* photonLeptonRate); +void FoldPPPNucleon(const dCVector* pBgPhotonDensity, + const RawTotalRate* PPPProtonLossRate, + const RawTotalRate* PPPNeutronLossRate, + const RawDiffRate* PPPProtonScatRate, + const RawDiffRate* PPPProtonNeutronRate, + const RawDiffRate* PPPNeutronProtonRate, + TotalRate* protonTotalRate, TotalRate* neutronTotalRate, + DiffRate* protonScatRate, DiffRate* protonNeutronRate, + DiffRate* neutronProtonRate); +void FoldPPPSecondary(const dCVector* pBgPhotonDensity, + const RawDiffRate* PPPProtonPhotonRate, + const RawDiffRate* PPPProtonElectronRate, + const RawDiffRate* PPPProtonPositronRate, + const RawDiffRate* PPPNeutronElectronRate, + const RawDiffRate* PPPProtonElectronNeutrinoRate, + const RawDiffRate* PPPProtonAntiElectronNeutrinoRate, + const RawDiffRate* PPPProtonMuonNeutrinoRate, + const RawDiffRate* PPPProtonAntiMuonNeutrinoRate, + const RawDiffRate* PPPNeutronAntiElectronNeutrinoRate, + const RawDiffRate* PPPNeutronMuonNeutrinoRate, + const RawDiffRate* PPPNeutronAntiMuonNeutrinoRate, + DiffRate* protonPhotonRate, + DiffRate* protonElectronRate, + DiffRate* protonPositronRate, + DiffRate* neutronElectronRate, + DiffRate* neutronPositronRate, + DiffRate* protonElectronNeutrinoRate, + DiffRate* protonAntiElectronNeutrinoRate, + DiffRate* protonMuonNeutrinoRate, + DiffRate* protonAntiMuonNeutrinoRate, + DiffRate* neutronAntiElectronNeutrinoRate, + DiffRate* neutronMuonNeutrinoRate, + DiffRate* neutronAntiMuonNeutrinoRate); +void FoldNPPNucleon(const dCVector* pBgPhotonDensity, const dCVector* pEnergy, + const RawTotalRate* NPPTotalRate, + dCVector* protonContinuousLoss); +void FoldNPPSecondary(const dCVector* pBgPhotonDensity, + const RawDiffRate* NPPDiffRate, + DiffRate* protonPositronRate, + DiffRate* protonElectronRate); + +void MapNeutTotalRate(const double redshift, const int lastIndex, + const int tauNeutrinoMassSwitch, + const TotalRate* NNTotalRate, + TotalRate* totalRate); +void MapNeutDiffRate(const double redshift, const int lastIndex, + const int tauNeutrinoMassSwitch, + const DiffRate* NNDiffRate, + DiffRate* diffRate); +void MapNeutRates(const double redshift, const int lastIndex, + const int tauNeutrinoMassSwitch, + const TotalRate* NNElNeutTotalRate, + const TotalRate* NNMuonNeutTotalRate, + const TotalRate* NNTauNeutTotalRate, + const DiffRate* NNElNeutScatRate, + const DiffRate* NNElNeutMuonNeutRate, + const DiffRate* NNElNeutTauNeutRate, + const DiffRate* NNElNeutElectronRate, + const DiffRate* NNElNeutPhotonRate, + const DiffRate* NNElNeutProtonRate, + const DiffRate* NNMuonNeutElNeutRate, + const DiffRate* NNMuonNeutScatRate, + const DiffRate* NNMuonNeutTauNeutRate, + const DiffRate* NNMuonNeutElectronRate, + const DiffRate* NNMuonNeutPhotonRate, + const DiffRate* NNMuonNeutProtonRate, + const DiffRate* NNTauNeutElNeutRate, + const DiffRate* NNTauNeutMuonNeutRate, + const DiffRate* NNTauNeutScatRate, + const DiffRate* NNTauNeutElectronRate, + const DiffRate* NNTauNeutPhotonRate, + const DiffRate* NNTauNeutProtonRate, + TotalRate* elNeutTotalRate, TotalRate* muonNeutTotalRate, + TotalRate* tauNeutTotalRate, DiffRate* elNeutScatRate, + DiffRate* elNeutMuonNeutRate, DiffRate* elNeutTauNeutRate, + DiffRate* elNeutElectronRate, DiffRate* elNeutPhotonRate, + DiffRate* elNeutProtonRate, DiffRate* muonNeutElNeutRate, + DiffRate* muonNeutScatRate, DiffRate* muonNeutTauNeutRate, + DiffRate* muonNeutElectronRate, DiffRate* muonNeutPhotonRate, + DiffRate* muonNeutProtonRate, DiffRate* tauNeutElNeutRate, + DiffRate* tauNeutMuonNeutRate, DiffRate* tauNeutScatRate, + DiffRate* tauNeutElectronRate, DiffRate* tauNeutPhotonRate, + DiffRate* tauNeutProtonRate); +#endif diff --git a/libs/dint/include/dint/frag.h b/libs/dint/include/dint/frag.h new file mode 100644 index 000000000..d04636c7d --- /dev/null +++ b/libs/dint/include/dint/frag.h @@ -0,0 +1,17 @@ +#ifndef _FRAG_H_ +#define _FRAG_H_ + +double OldFrag(const double x); +double HillFrag(const double x); +double TestFrag(const double x); +double MLLA_25(const double x); +double MLLA_24(const double x); +double MLLA_23(const double x); +double MLLA_22(const double x); +double Susy_MLLA_25(const double x); +double Susy_MLLA_24(const double x); +double Susy_MLLA_23(const double x); +double Susy_MLLA_22(const double x); +double TDFolded(const double x); + +#endif diff --git a/libs/dint/include/dint/gauleg.h b/libs/dint/include/dint/gauleg.h new file mode 100644 index 000000000..c23f09d8a --- /dev/null +++ b/libs/dint/include/dint/gauleg.h @@ -0,0 +1,7 @@ +#ifndef _GAULEG_H_ +#define _GAULEG_H_ + +void Gauleg(const double x1, const double x2, double x[], double w[], + const int n); + +#endif diff --git a/libs/dint/include/dint/inject.h b/libs/dint/include/dint/inject.h new file mode 100644 index 000000000..4945a8f7f --- /dev/null +++ b/libs/dint/include/dint/inject.h @@ -0,0 +1,12 @@ +#ifndef _INJECT_H_ +#define _INJECT_H_ + +#include "dint/cvector.h" +#include "dint/spectrum.h" + +void SetInjectionSpectrum(const PARTICLE part, const double InjEnergy, + const double HInjEnergy, const double deltaE_hadron, + const dCVector* pEnergy, + const dCVector* pEnergyWidth, Spectrum* pQ_0); + +#endif diff --git a/libs/dint/include/dint/io_util.h b/libs/dint/include/dint/io_util.h new file mode 100644 index 000000000..b89a43069 --- /dev/null +++ b/libs/dint/include/dint/io_util.h @@ -0,0 +1,8 @@ +#ifndef _IO_UTIL_H_ +#define _IO_UTIL_H_ + +#include + +FILE* SafeFOpen(const char* filename, const char* mode); + +#endif diff --git a/libs/dint/include/dint/load.h b/libs/dint/include/dint/load.h new file mode 100644 index 000000000..29aa59c60 --- /dev/null +++ b/libs/dint/include/dint/load.h @@ -0,0 +1,81 @@ +#ifndef _LOAD_H_ +#define _LOAD_H_ + +#include "dint/rate.h" +#include "dint/utilities.h" +#include "dint/const.h" + +#include +#include +#include +#include +#include + +#include "binfread.h" + +using namespace std; + +void LoadICSTables(RawTotalRate* ICSTotalRate, RawDiffRate* ICSPhotonRate, + RawDiffRate* ICSScatRate, const int num_main_bins, + string aDirTables); +void LoadPPTables(RawTotalRate* PPTotalRate, RawDiffRate* PPDiffRate, + const int num_main_bins, + string aDirTables); +void LoadTPPTables(RawTotalRate* TPPTotalRate, RawDiffRate* TPPDiffRate, + const int num_main_bins, string aDirTables); +void LoadDPPTables(RawTotalRate* DPPRate, const int num_main_bins, + string aDirTables); +void LoadPPPNucleonTables(RawTotalRate* PPPProtonLossRate, + RawTotalRate* PPPNeutronLossRate, + RawDiffRate* PPPProtonScatRate, + RawDiffRate* PPPProtonNeutronRate, + RawDiffRate* PPPNeutronProtonRate, + const int num_main_bins, string aDirTables); +void LoadPPPEMTables(RawDiffRate* PPPProtonPhotonRate, + RawDiffRate* PPPProtonElectronRate, + RawDiffRate* PPPProtonPositronRate, + RawDiffRate* PPPNeutronElectronRate, + const int num_main_bins, string aDirTables); +void LoadNPPNucleonTables(RawTotalRate* NPPTotalRate, const int num_main_bins, + string aDirTables); +void LoadNPPSecondaryTables(RawDiffRate* NPPDiffRate, const int num_main_bins, + string aDirTables); +void LoadPPPNeutrinoTables(RawDiffRate* PPPProtonElectronNeutrinoRate, + RawDiffRate* PPPProtonAntiElectronNeutrinoRate, + RawDiffRate* PPPProtonMuonNeutrinoRate, + RawDiffRate* PPPProtonAntiMuonNeutrinoRate, + RawDiffRate* PPPNeutronAntiElectronNeutrinoRate, + RawDiffRate* PPPNeutronMuonNeutrinoRate, + RawDiffRate* PPPNeutronAntiMuonNeutrinoRate, + const int num_main_bins, string aDirTables); +void LoadNeutronDecayNucleonTables(TotalRate* neutronDecayRate, + DiffRate* neutronDecayProtonRate, + const int num_main_bins, string aDirTables); +void LoadNeutronDecaySecondaryTables(DiffRate* neutronDecayElectronRate, + const int num_main_bins, + string aDirTables); +void LoadNeutrinoTables(const int tauNeutrinoMassSwitch, + TotalRate* NNElNeutTotalRate, + TotalRate* NNMuonNeutTotalRate, + TotalRate* NNTauNeutTotalRate, + DiffRate* NNElNeutScatRate, + DiffRate* NNElNeutMuonNeutRate, + DiffRate* NNElNeutTauNeutRate, + DiffRate* NNElNeutElectronRate, + DiffRate* NNElNeutPhotonRate, + DiffRate* NNElNeutProtonRate, + DiffRate* NNMuonNeutScatRate, + DiffRate* NNMuonNeutElNeutRate, + DiffRate* NNMuonNeutTauNeutRate, + DiffRate* NNMuonNeutElectronRate, + DiffRate* NNMuonNeutPhotonRate, + DiffRate* NNMuonNeutProtonRate, + DiffRate* NNTauNeutScatRate, + DiffRate* NNTauNeutElNeutRate, + DiffRate* NNTauNeutMuonNeutRate, + DiffRate* NNTauNeutElectronRate, + DiffRate* NNTauNeutPhotonRate, + DiffRate* NNTauNeutProtonRate, + const int num_main_bins, string aDirTables); + +#endif diff --git a/libs/dint/include/dint/math_util.h b/libs/dint/include/dint/math_util.h new file mode 100644 index 000000000..e83ef41c9 --- /dev/null +++ b/libs/dint/include/dint/math_util.h @@ -0,0 +1,9 @@ +#ifndef _MATH_UTIL_H_ +#define _MATH_UTIL_H_ + +double DMax(const double double1, const double double2); +double DMin(const double double1, const double double2); +int IMax(const int integer1, const int integer2); +int IMin(const int integer1, const int integer2); + +#endif diff --git a/libs/dint/include/dint/prepare.h b/libs/dint/include/dint/prepare.h new file mode 100644 index 000000000..be18a65f4 --- /dev/null +++ b/libs/dint/include/dint/prepare.h @@ -0,0 +1,48 @@ +#ifndef _PREPARE_H_ +#define _PREPARE_H_ + +#include +#include "dint/spectrum.h" +#include "dint/cvector.h" + +void SetEnergyBins(const int min_energy_exp, dCVector* pEnergy, + dCVector* pEnergyWidth); +void SetDeltaG(const dCVector* pEnergy, dCVector* pDeltaG); +void GetModeOfInput(FILE* input, int* pInputMethodSwitch); +void BasicParameterInput(FILE* input, const int argc, int* pMinEnergyExp, + int* pNumSmallSteps, + double* pConvergeParameter, + double* pStartingRedshift, + double* pStartingDistanceInMpc); +void InteractionParameterInput(FILE* input, const int argc, + int* pSynchrotronSwitch, double* pB_0, + int* pTauNeutrinoMassSwitch, int* pICSSwitch, + int* pPPSwitch, int* pTPPSwitch, + int* pDPPSwitch, int* pPPPSwitch, + int* pNPPSwitch, int* pNeutronDecaySwitch, + int* pNucleonToSecondarySwitch, + int* pNeutrinoNeutrinoSwitch); +void ModelParameterInput(FILE* input, const int argc, + int* pSourceTypeSwitch, double* pMinDistance, + double* pBrightPhaseExp, int* pModelTypeSwitch); +/* CHANGE (Guenter; 7/20/1998): BrightPhaseExp added */ +void PrepareSpectra(const int sourceTypeSwitch, const Spectrum* pQ_0, + Spectrum* pSpectrum, Spectrum* pSpectrumNew, + Spectrum* pDerivative); +void ComputeTotalInitialContent(const dCVector* pEnergy, const Spectrum* pQ_0, + double* initialPhotonEnergy, + double* initialLeptonEnergy, + double* initialNucleonEnergy, + double* initialNeutrinoEnergy, + double* initialTotalEnergy, + double* initialPhotonNumber, + double* initialLeptonNumber, + double* initialNucleonNumber, + double* initialNeutrinoNumber, + double* initialTotalNumber); +void ComputeContinuousEnergyLoss(const int synchrotronSwitch, + const dCVector* synchrotronLoss, + const dCVector* otherLoss, + dCVector* continuousLoss); + +#endif diff --git a/libs/dint/include/dint/prop_second.h b/libs/dint/include/dint/prop_second.h new file mode 100644 index 000000000..08f61b338 --- /dev/null +++ b/libs/dint/include/dint/prop_second.h @@ -0,0 +1,94 @@ + +#ifndef _PROPSECOND_H_ +#define _PROPSECOND_H_ + +#include "dint/cvector.h" + +#include +#include +#include "dint/rate.h" +#include "dint/const.h" +#include "dint/spectrum.h" +#include "dint/cvector.h" +#include "dint/load.h" +#include "dint/prepare.h" +#include "dint/sync.h" +#include "dint/inject.h" +#include "dint/background.h" +#include "dint/fold.h" +#include "dint/advance.h" +#include "dint/final.h" +#include "dint/utilities.h" +#include +#include +#include +#include +#include + +/*-------------------------------------------------------------------------- + prop_second + Main routine for the dint package + E. Armengaud - Jan 2006 +--------------------------------------------------------------------------*/ + +/* + Arguments : + + dist_observer : in Mpc + pB_field : in Gauss + pEnergy, pEnergyWidth : in ELECTRON_MASS*eV + apInjectionSpectrum : INPUT mean number of particles per energy bin + pSpectrum : OUTPUT mean number of particles per energy bin + aDirTables : directory for cascade tables + Photon background flags : + aIRFlag = 0 (High IR), 1 (Low IR) or 2 (Primack IR) + aZmax_IR = max redshift of the infrared background + aRadioFlag = 0 (High Radio), 1 (Low Radio), 2 (Obs Radio) or 3 (Null Radio) + Cosmological parameters : H0, Omega_M/Lambda. The unit of H0 is km/s/Mpc + aCutcascade_Magfield : flag to "cut" of the e+/- cascade by the magnetic deflections. +*/ + +/*-------------------------------------------------------------------------- + The routine prop_second, used in CRPropa, propagates an electromagnetic cascade + in the extragalactic medium over a given distance (redshifts taken into account) + + Propagation takes place in redshift space. The energy unit used in dint is m_e (~511 keV). + The distance unit is in cm. + The magnetic field perpendicular to the trajectory must be specified. It can be + inhomogeneous, allowing to take into account probable B field concentrations inside the + clusters. 3 models of homogeneous cosmic IR background and 3 models of cosmic radio + background are implemented. + + The redshift evolution of radio background is consistent with its model (see background.cpp). + The redshift evolution of IR background is the same as for CMB until aZmax_IR. + + The input spectrum must have the same format as the output : + The output is a spectrum, computed for 170 values of energy ranging from 10^7 to 10^24 eV. + + If the aCutcascade_Magfield flag is set : at each step, we define a critical energy E_c + based on the comparison between Larmor, synchrotron and ICS time scales. + Only the electrons with r_Larmor > aCutcascade_Magfield) * min(t_synchrotron,t_ICS) are kept: + this mimics the loss of the cascade due to the deflections (useful for the study of a "point" + source; allows to test roughly the effect of B fields on the 1D approximation for the cascade). +--------------------------------------------------------------------------*/ + +void prop_second(const double dist_observer, + //const double InjEnergy, + //const PARTICLE part, + //const double HInjEnergy, const double deltaE_hadron, + const dCVector* pB_field, + const dCVector* pEnergy, + const dCVector* pEnergyWidth, + Spectrum* apInjectionSpectrum, + Spectrum* pSpectrum, string aDirTables, + const int aIRFlag, const double aZmax_IR, const int aRadioFlag, + const double aH0, const double aOmegaM, const double aOmegaLambda, + const double aCutcascade_Magfield); + +void BuildRedshiftTable(double aH0, double aOmegaM, double aOmegaLambda, + dCVector* pRedshiftArray, dCVector* pDistanceArray); + +double getRedshift(dCVector RedshiftArray, dCVector DistanceArray, double distance) ; +double getDistance(dCVector RedshiftArray, dCVector DistanceArray, double redshift) ; + +#endif diff --git a/libs/dint/include/dint/rate.h b/libs/dint/include/dint/rate.h new file mode 100644 index 000000000..abfa6c2b3 --- /dev/null +++ b/libs/dint/include/dint/rate.h @@ -0,0 +1,102 @@ +#ifndef _RATE_H_ +#define _RATE_H_ + +#include "dint/vector.h" +#include "dint/binfread.h" + +typedef struct +{ + int mainDimension; + int bgDimension; + // int mainDimension2; /* number of daughter bins */ + int numberOfElements; + i3Tensor bound; + dVector diffRate; +} RawDiffRate; +/* although RawDiffRate is really a 3-dimensional matrix, I "serialize" + the matrix to tighten up the memory: instead of using the full + 3-dimensional matrix with lots of zeros, I replace it by a serialized + 1-dimensional array with non-zero elements and with appropriate lower + and upper bounds (bound) */ + +typedef struct +{ + int mainDimension; + int bgDimension; + dMatrix totalRate; +} RawTotalRate; + +typedef struct +{ + int mainDimension; + iMatrix bound; + dMatrix diffRate; +} DiffRate; + +typedef struct +{ + int mainDimension; + dVector totalRate; +} TotalRate; +/* NOTE: all rates are initialized when assigned memory. All bounds are + properly invalidated. */ + + +void NewRawTotalRate(RawTotalRate* pRate, const int num_main_bins, + const int num_bg_bins); +void DeleteRawTotalRate(RawTotalRate* pRate); +void InitializeRawTotalRate(RawTotalRate* pRate); +void CopyRawTotalRate(RawTotalRate* pLRate, const RawTotalRate* pRRate); +void ClipRawTotalRate(RawTotalRate* pRate, const int newSize); +void EnlargeRawTotalRate(RawTotalRate* pRate, const int newSize); +void ModifyRawTotalRate(RawTotalRate* pRate, const int newSize); +void ReadRawTotalRate(RawTotalRate* pRate, const char* filename); + + +void NewRawDiffRate(RawDiffRate* pRate, const int num_main_bins, + const int num_bg_bins, const int num_elements); +void DeleteRawDiffRate(RawDiffRate* pRate); +void InitializeRawDiffRate(RawDiffRate* pRate); +void CheckRawDiffRate(RawDiffRate* pRate); +#ifdef DEBUG +double RawDiffRateElement(const RawDiffRate* pRate, const int i, const int j, + const int k); +/* although this is a very good and safe way of getting the element + it is a very expensive call: it is recommended only for checking */ +#endif +void CopyRawDiffRate(RawDiffRate* pLRate, const RawDiffRate* pRRate); +void CopyRawDiffRateBound(RawDiffRate* pLRate, const RawDiffRate* pRRate); +void ClipRawDiffRate(RawDiffRate* pRate, const int newSize); +void EnlargeRawDiffRate(RawDiffRate* pRate, const int newSize); +void ModifyRawDiffRate(RawDiffRate* pRate, const int newSize); +void ReadRawDiffRate(RawDiffRate* pRate, const char* filename); + + +void NewTotalRate(TotalRate* pRate, const int num_main_bins); +void DeleteTotalRate(TotalRate* pRate); +void InitializeTotalRate(TotalRate* pRate); +void CopyTotalRate(TotalRate* pLRate, const TotalRate* pRRate); +void ClipTotalRate(TotalRate* pRate, const int newSize); +void EnlargeTotalRate(TotalRate* pRate, const int newSize); +void ModifyTotalRate(TotalRate* pRate, const int newSize); +void ReadTotalRate(TotalRate* pRate, const char* filename); + + +void NewDiffRate(DiffRate* pRate, const int num_main_bins); +void DeleteDiffRate(DiffRate* pRate); +void InitializeDiffRate(DiffRate* pRate); +void CopyDiffRate(DiffRate* pLRate, const DiffRate* pRRate); +void ClipDiffRate(DiffRate* pRate, const int newSize); +void EnlargeDiffRate(DiffRate* pRate, const int newSize); +void ModifyDiffRate(DiffRate* pRate, const int newSize); +void ReadDiffRate(DiffRate* pRate, const char* filename); +void CopyDiffRateBound(DiffRate* pLRate, const DiffRate* pRRate); +void SetStandardDiffRateBound(DiffRate* pRate); +/* sets DiffRate bound to 0 <= k <= i */ +void InvalidateDiffRateBound(DiffRate* pRate); + +#endif +/* Copy*Rate: perform real deep copies; i.e. they reformat the dimensions + according to the size of the rate being copied. + Copy*DiffRateBound: copy bounds without altering size. +*/ diff --git a/libs/dint/include/dint/spectrum.h b/libs/dint/include/dint/spectrum.h new file mode 100644 index 000000000..b55805082 --- /dev/null +++ b/libs/dint/include/dint/spectrum.h @@ -0,0 +1,48 @@ +#ifndef _SPECTRUM_H_ +#define _SPECTRUM_H_ + +#include "dint/vector.h" +#include "dint/cvector.h" + + +#define NUM_SPECIES 11 +typedef enum + {PHOTON = 0, ELECTRON = 1, POSITRON = 2, PROTON = 3, NEUTRON = 4, + ELECTRON_NEUTRINO = 5, ANTI_ELECTRON_NEUTRINO = 6, MUON_NEUTRINO = 7, + ANTI_MUON_NEUTRINO = 8, TAU_NEUTRINO = 9, ANTI_TAU_NEUTRINO = 10, + NOTHING = 11} +PARTICLE; + +// NOTHING type added by Gunter (2005) for secondary from pair production + +/* Spectrum is a struct that corresponds to the total spectrum. It + has all particle spectra in it. Since particle data is more or less + fixed and independent, we do not specify the number of particle species. */ +typedef struct +{ + int numberOfMainBins; + dMatrix spectrum; +} Spectrum; + +void NewSpectrum(Spectrum* pSpectrum, const int num_bins); +void DeleteSpectrum(Spectrum* pSpectrum); +void InitializeSpectrum(Spectrum* pSpectrum); +void InitializeEMSpectrum(Spectrum* pSpectrum); +void InitializeNucleonSpectrum(Spectrum* pSpectrum); +void InitializeNeutrinoSpectrum(Spectrum* pSpectrum); +void SetSpectrum(Spectrum* pSpectrum1, const Spectrum* pSpectrum2); +void SetEMSpectrum(Spectrum* pSpectrum1, const Spectrum* pSpectrum2); +void SetNucleonSpectrum(Spectrum* pSpectrum1, const Spectrum* pSpectrum2); +void SetNeutrinoSpectrum(Spectrum* pSpectrum1, const Spectrum* pSpectrum2); +double GetNumber(const Spectrum* pSpectrum); +double GetEMNumber(const Spectrum* pSpectrum); +double GetNucleonNumber(const Spectrum* pSpectrum); +double GetNeutrinoNumber(const Spectrum* pSpectrum); +double GetEnergy(const Spectrum* pSpectrum, const dCVector* pEnergy); +double GetEMEnergy(const Spectrum* pSpectrum, const dCVector* pEnergy); +double GetNucleonEnergy(const Spectrum* pSpectrum, const dCVector* pEnergy); +double GetNeutrinoEnergy(const Spectrum* pSpectrum, const dCVector* pEnergy); +void DumpSpectrum(const dCVector* pEnergy, const dCVector* pEnergyWidth, + const Spectrum* pSpectrum, const char* filename); + +#endif diff --git a/libs/dint/include/dint/sync.h b/libs/dint/include/dint/sync.h new file mode 100644 index 000000000..91d6c4abd --- /dev/null +++ b/libs/dint/include/dint/sync.h @@ -0,0 +1,23 @@ + +#ifndef _SYNC_H_ +#define _SYNC_H_ + +#include "dint/rate.h" +#include "dint/cvector.h" +#include +#include +#include "dint/utilities.h" +#include "dint/const.h" +#include +#include +#include +#include +using namespace std; + +void LoadSyncTable(dCVector* syncTable, string aDirTables); +void InitializeSynchrotron(const double B_0, const dCVector* pEnergy, + const dCVector* pEnergyWidth, + dCVector* synchrotronLoss, DiffRate* syncRate, + string aDirTables); + +#endif diff --git a/libs/dint/include/dint/utilities.h b/libs/dint/include/dint/utilities.h new file mode 100644 index 000000000..85085ea28 --- /dev/null +++ b/libs/dint/include/dint/utilities.h @@ -0,0 +1,10 @@ +#ifndef _UTILITIES_H_ +#define _UTILITIES_H_ + +#include "dint/error.h" +#include "dint/io_util.h" +#include "dint/math_util.h" + +#include "dint/check.h" + +#endif diff --git a/libs/dint/include/dint/vector.h b/libs/dint/include/dint/vector.h new file mode 100644 index 000000000..1a8dc5f26 --- /dev/null +++ b/libs/dint/include/dint/vector.h @@ -0,0 +1,31 @@ +#ifndef _VECTOR_H_ +#define _VECTOR_H_ + +/* Vectors, matrices, and tensors defined here are very simple, dynamic + objects. They do not provide any bound checking nor has extra data + structure, but have very little overhead because of that. For structs + that have dimensional data built-in, see "cvector.h". +*/ + +typedef double* dVector; +typedef int* iVector; +typedef double** dMatrix; +typedef int** iMatrix; +typedef double*** d3Tensor; +typedef int*** i3Tensor; + + +dVector New_dVector(const int n); +iVector New_iVector(const int n); +dMatrix New_dMatrix(const int n1, const int n2); +iMatrix New_iMatrix(const int n1, const int n2); +d3Tensor New_d3Tensor(const int n1, const int n2, const int n3); +i3Tensor New_i3Tensor(const int n1, const int n2, const int n3); +void Delete_dVector(dVector vector); +void Delete_iVector(iVector vector); +void Delete_dMatrix(dMatrix matrix); +void Delete_iMatrix(iMatrix matrix); +void Delete_d3Tensor(d3Tensor tensor); +void Delete_i3Tensor(i3Tensor tensor); + +#endif diff --git a/libs/dint/src/advance.cpp b/libs/dint/src/advance.cpp new file mode 100644 index 000000000..fdecf1248 --- /dev/null +++ b/libs/dint/src/advance.cpp @@ -0,0 +1,845 @@ + +#include "dint/advance.h" + +#ifdef DEBUG +void PrintEnergy(const dCVector* pArray, const dCVector* pEnergy) +{ + double temp = 0.; + int i; + + if (pArray->dimension != pEnergy->dimension) + { + Error("PrintEnergy: inconsistent dimensions", PROGRAM_ERROR); + } + + for (i = 0; i < pEnergy->dimension; i++) + { + temp += (pArray->vector)[i]*(pEnergy->vector)[i]; + } + + printf("%15.6E\n", temp); +} +#endif + +void ComputeRedshifts(const int sourceTypeSwitch, const double leftRedshift, + double* pDeltaRedshift, double* pRightRedshift, + double* pCentralRedshift, int* pLastIndex) { + double clusterRedshift,localRedshift,minRedshift,maxRedshift; + + clusterRedshift = pow(1.-1.5e5*H_0/C*CLUSTER_DISTANCE,-2./3.)-1.; + localRedshift = pow(1.-1.5e5*H_0/C*SOURCE_CLUSTER_DISTANCE,-2./3.)-1.; + maxRedshift = localRedshift; + minRedshift = maxRedshift; + if (clusterRedshift > maxRedshift) + maxRedshift = clusterRedshift; + else + minRedshift = clusterRedshift; + if (sourceTypeSwitch == 0) + minRedshift = maxRedshift; + + if ((*pLastIndex == 0) && (leftRedshift < 0.6)) { + *pDeltaRedshift /= 2.; + *pLastIndex = 3; + } + *pRightRedshift = leftRedshift - (1. + leftRedshift)*(*pDeltaRedshift); + if (*pRightRedshift < 0.) { + *pRightRedshift = 0.; + *pLastIndex = 1; + } + *pCentralRedshift = (leftRedshift + *pRightRedshift)/2.; + if ((*pLastIndex == 1) && (*pCentralRedshift > maxRedshift)) { + *pRightRedshift = maxRedshift; + *pCentralRedshift = (leftRedshift + *pRightRedshift)/2.; + *pLastIndex = 2; + } + + if ((*pLastIndex == 1) && (*pCentralRedshift > minRedshift)) { + *pRightRedshift = minRedshift; + *pCentralRedshift = (leftRedshift + *pRightRedshift)/2.; + *pLastIndex = 2; + } + +} + +void AdvanceNucleonStep(const int sourceTypeSwitch, + const int PPPSwitch, const int NPPSwitch, + const int neutronDecaySwitch, + const int neutrinoNeutrinoSwitch, + const double smallDistanceStep, + const double evolutionFactor, + const double convergeParameter, + const double bkgFactor, + const Spectrum* pQ_0, + const DiffRate* elNeutProtonRate, + const DiffRate* muonNeutProtonRate, + const DiffRate* tauNeutProtonRate, + const TotalRate* protonTotalRate, + const TotalRate* neutronTotalRate, + const TotalRate* neutronDecayRate, + const DiffRate* protonScatRate, + const DiffRate* protonNeutronRate, + const DiffRate* neutronProtonRate, + const DiffRate* neutronDecayProtonRate, + const dCVector* protonContinuousLoss, + const dCVector* deltaG, const Spectrum* pSpectrum, + Spectrum* pSpectrumNew) { + Spectrum spectrumTemp; + Spectrum influx; + Spectrum influx0; + Spectrum influxExt; + Spectrum outflux; + int num_main_bins; + double changeMax; + + num_main_bins = pSpectrum->numberOfMainBins; + + NewSpectrum(&spectrumTemp, num_main_bins); + NewSpectrum(&influx, num_main_bins); + NewSpectrum(&influx0, num_main_bins); + NewSpectrum(&influxExt, num_main_bins); + NewSpectrum(&outflux, num_main_bins); + + GetExternalFlux(sourceTypeSwitch, evolutionFactor, PROTON, pQ_0, + &influxExt); + GetExternalFlux(sourceTypeSwitch, evolutionFactor, NEUTRON, pQ_0, + &influxExt); + + if (neutrinoNeutrinoSwitch == 1) + GetNucleonInfluxFromNeutrinos(bkgFactor, elNeutProtonRate, + muonNeutProtonRate, tauNeutProtonRate, + pSpectrumNew, &influx0); + + do { + SetNucleonSpectrum(&spectrumTemp, pSpectrumNew); + + InitializeSpectrum(&influx); + InitializeSpectrum(&outflux); + + if ((PPPSwitch == 1) || (NPPSwitch == 1) || + (neutronDecaySwitch == 1)) { + // call all the processes that produce nucleons from nucleons + GetNucleonFluxFromNucleons(neutronDecaySwitch, protonTotalRate, + neutronTotalRate, neutronDecayRate, protonScatRate, + neutronProtonRate, protonNeutronRate, + neutronDecayProtonRate, protonContinuousLoss, + deltaG, pSpectrumNew, &influx, &outflux); + } + + ImplicitEquation(smallDistanceStep, PROTON, &influx, &influx0, + &influxExt, &outflux, pSpectrum, pSpectrumNew); + ImplicitEquation(smallDistanceStep, NEUTRON, &influx, &influx0, + &influxExt, &outflux, pSpectrum, pSpectrumNew); + + changeMax = 0.; + ComputeChange(&spectrumTemp, pSpectrumNew, PROTON, &changeMax); + ComputeChange(&spectrumTemp, pSpectrumNew, NEUTRON, &changeMax); + } while (changeMax > convergeParameter); + + DeleteSpectrum(&spectrumTemp); + DeleteSpectrum(&influx); + DeleteSpectrum(&influx0); + DeleteSpectrum(&influxExt); + DeleteSpectrum(&outflux); +} + + +void AdvanceNeutrinoStep(const int sourceTypeSwitch, + const int neutrinoNeutrinoSwitch, + const int PPPSwitch, + const int neutronDecaySwitch, + const int nucleonToSecondarySwitch, + const double smallDistanceStep, + const double evolutionFactor, + const double convergeParameter, + const double bkgFactor, + const Spectrum* pQ_0, + const DiffRate* protonMuonNeutrinoRate, + const DiffRate* neutronAntiMuonNeutrinoRate, + const DiffRate* protonAntiMuonNeutrinoRate, + const DiffRate* neutronMuonNeutrinoRate, + const DiffRate* protonElectronNeutrinoRate, + const DiffRate* neutronAntiElectronNeutrinoRate, + const DiffRate* protonAntiElectronNeutrinoRate, + const DiffRate* neutronDecayElectronRate, + const TotalRate* elNeutTotalRate, + const TotalRate* muonNeutTotalRate, + const TotalRate* tauNeutTotalRate, + const DiffRate* elNeutScatRate, + const DiffRate* elNeutMuonNeutRate, + const DiffRate* elNeutTauNeutRate, + const DiffRate* muonNeutElNeutRate, + const DiffRate* muonNeutScatRate, + const DiffRate* muonNeutTauNeutRate, + const DiffRate* tauNeutElNeutRate, + const DiffRate* tauNeutMuonNeutRate, + const DiffRate* tauNeutScatRate, + const Spectrum* pSpectrum, Spectrum* pSpectrumNew) { + double changeMax; + int num_main_bins; + Spectrum spectrumTemp; + Spectrum influx; + Spectrum influx0; + Spectrum influxExt; + Spectrum outflux; + + num_main_bins = pSpectrum->numberOfMainBins; + + NewSpectrum(&spectrumTemp, num_main_bins); + NewSpectrum(&influx, num_main_bins); + NewSpectrum(&influx0, num_main_bins); + NewSpectrum(&influxExt, num_main_bins); + NewSpectrum(&outflux, num_main_bins); + + // SetNeutrinoSpectrum(spectrumNew, spectrum); + + GetExternalFlux(sourceTypeSwitch, evolutionFactor, MUON_NEUTRINO, pQ_0, + &influxExt); + GetExternalFlux(sourceTypeSwitch, evolutionFactor, ANTI_MUON_NEUTRINO, + pQ_0, &influxExt); + GetExternalFlux(sourceTypeSwitch, evolutionFactor, ELECTRON_NEUTRINO, pQ_0, + &influxExt); + GetExternalFlux(sourceTypeSwitch, evolutionFactor, ANTI_ELECTRON_NEUTRINO, + pQ_0, &influxExt); + GetExternalFlux(sourceTypeSwitch, evolutionFactor, TAU_NEUTRINO, pQ_0, + &influxExt); + GetExternalFlux(sourceTypeSwitch, evolutionFactor, ANTI_TAU_NEUTRINO, pQ_0, + &influxExt); + + InitializeSpectrum(&influx0); + /* this is not really necessary but will keep it for redundancy */ + + /* neutrino influx from nucleons */ + if (nucleonToSecondarySwitch == 1) + { + if ((PPPSwitch == 1) || (neutronDecaySwitch == 1)) + { + GetNeutrinoInfluxFromNucleons(neutronDecaySwitch, + protonMuonNeutrinoRate, neutronAntiMuonNeutrinoRate, + neutronMuonNeutrinoRate, protonAntiMuonNeutrinoRate, + protonElectronNeutrinoRate, neutronAntiElectronNeutrinoRate, + protonAntiElectronNeutrinoRate, neutronDecayElectronRate, + pSpectrumNew, &influx0); + } + } + + do { + SetNeutrinoSpectrum(&spectrumTemp, pSpectrumNew); + + InitializeSpectrum(&influx); + InitializeSpectrum(&outflux); + + /* call processes that produce neutrinos from neutrinos */ + if (neutrinoNeutrinoSwitch == 1) + { + GetNeutrinoFluxFromNeutrinos(bkgFactor, elNeutTotalRate, + muonNeutTotalRate, + tauNeutTotalRate, elNeutScatRate, elNeutMuonNeutRate, + elNeutTauNeutRate, muonNeutElNeutRate, muonNeutScatRate, + muonNeutTauNeutRate, tauNeutElNeutRate, tauNeutMuonNeutRate, + tauNeutScatRate, pSpectrumNew, &influx, &outflux); + } + + ImplicitEquation(smallDistanceStep, MUON_NEUTRINO, &influx, + &influx0, &influxExt, &outflux, pSpectrum, pSpectrumNew); + ImplicitEquation(smallDistanceStep, ANTI_MUON_NEUTRINO, &influx, + &influx0, &influxExt, &outflux, pSpectrum, pSpectrumNew); + ImplicitEquation(smallDistanceStep, ELECTRON_NEUTRINO, &influx, + &influx0, &influxExt, &outflux, pSpectrum, pSpectrumNew); + ImplicitEquation(smallDistanceStep, ANTI_ELECTRON_NEUTRINO, &influx, + &influx0, &influxExt, &outflux, pSpectrum, pSpectrumNew); + ImplicitEquation(smallDistanceStep, TAU_NEUTRINO, &influx, + &influx0, &influxExt, &outflux, pSpectrum, pSpectrumNew); + ImplicitEquation(smallDistanceStep, ANTI_TAU_NEUTRINO, &influx, + &influx0, &influxExt, &outflux, pSpectrum, pSpectrumNew); + + changeMax = 0.; + ComputeChange(&spectrumTemp, pSpectrumNew, ELECTRON_NEUTRINO, + &changeMax); + ComputeChange(&spectrumTemp, pSpectrumNew, ANTI_ELECTRON_NEUTRINO, + &changeMax); + ComputeChange(&spectrumTemp, pSpectrumNew, MUON_NEUTRINO, + &changeMax); + ComputeChange(&spectrumTemp, pSpectrumNew, ANTI_MUON_NEUTRINO, + &changeMax); + ComputeChange(&spectrumTemp, pSpectrumNew, TAU_NEUTRINO, + &changeMax); + ComputeChange(&spectrumTemp, pSpectrumNew, ANTI_TAU_NEUTRINO, + &changeMax); + } while (changeMax > convergeParameter); + + DeleteSpectrum(&spectrumTemp); + DeleteSpectrum(&influx); + DeleteSpectrum(&influx0); + DeleteSpectrum(&influxExt); + DeleteSpectrum(&outflux); +} + +void AdvanceNucNeutStep(const int sourceTypeSwitch, + const int PPPSwitch, const int NPPSwitch, + const int neutronDecaySwitch, + const int nucleonToSecondarySwitch, + const int neutrinoNeutrinoSwitch, + const double smallDistanceStep, + const double evolutionFactor, + const double convergeParameter, + const double bkgFactor, + const Spectrum* pQ_0, + const DiffRate* elNeutProtonRate, + const DiffRate* muonNeutProtonRate, + const DiffRate* tauNeutProtonRate, + const TotalRate* protonTotalRate, + const TotalRate* neutronTotalRate, + const TotalRate* neutronDecayRate, + const DiffRate* protonScatRate, + const DiffRate* protonNeutronRate, + const DiffRate* neutronProtonRate, + const DiffRate* neutronDecayProtonRate, + const DiffRate* protonMuonNeutrinoRate, + const DiffRate* neutronAntiMuonNeutrinoRate, + const DiffRate* protonAntiMuonNeutrinoRate, + const DiffRate* neutronMuonNeutrinoRate, + const DiffRate* protonElectronNeutrinoRate, + const DiffRate* neutronAntiElectronNeutrinoRate, + const DiffRate* protonAntiElectronNeutrinoRate, + const DiffRate* neutronDecayElectronRate, + const TotalRate* elNeutTotalRate, + const TotalRate* muonNeutTotalRate, + const TotalRate* tauNeutTotalRate, + const DiffRate* elNeutScatRate, + const DiffRate* elNeutMuonNeutRate, + const DiffRate* elNeutTauNeutRate, + const DiffRate* muonNeutElNeutRate, + const DiffRate* muonNeutScatRate, + const DiffRate* muonNeutTauNeutRate, + const DiffRate* tauNeutElNeutRate, + const DiffRate* tauNeutMuonNeutRate, + const DiffRate* tauNeutScatRate, + const dCVector* protonContinuousLoss, + const dCVector* deltaG, const Spectrum* pSpectrum, + Spectrum* pSpectrumNew) +{ + Spectrum spectrumGlobalTemp; + /* temporary spectrum used in swapping spectra */ + double changeGlobal; + int num_main_bins; + + num_main_bins = pSpectrum->numberOfMainBins; + + NewSpectrum(&spectrumGlobalTemp, num_main_bins); + + do { + SetNucleonSpectrum(&spectrumGlobalTemp, pSpectrumNew); + SetNeutrinoSpectrum(&spectrumGlobalTemp, pSpectrumNew); + + + AdvanceNucleonStep(sourceTypeSwitch, PPPSwitch, NPPSwitch, + neutronDecaySwitch, neutrinoNeutrinoSwitch, smallDistanceStep, + evolutionFactor, convergeParameter, bkgFactor, pQ_0, + elNeutProtonRate, muonNeutProtonRate, tauNeutProtonRate, + protonTotalRate, neutronTotalRate, neutronDecayRate, + protonScatRate, protonNeutronRate, neutronProtonRate, + neutronDecayProtonRate, protonContinuousLoss, deltaG, pSpectrum, + pSpectrumNew); + + AdvanceNeutrinoStep(sourceTypeSwitch, neutrinoNeutrinoSwitch, + PPPSwitch, neutronDecaySwitch, nucleonToSecondarySwitch, + smallDistanceStep, evolutionFactor, convergeParameter, bkgFactor, + pQ_0, protonMuonNeutrinoRate, neutronAntiMuonNeutrinoRate, + protonAntiMuonNeutrinoRate, neutronMuonNeutrinoRate, + protonElectronNeutrinoRate, neutronAntiElectronNeutrinoRate, + protonAntiElectronNeutrinoRate, neutronDecayElectronRate, + elNeutTotalRate, muonNeutTotalRate, tauNeutTotalRate, + elNeutScatRate, elNeutMuonNeutRate, elNeutTauNeutRate, + muonNeutElNeutRate, muonNeutScatRate, muonNeutTauNeutRate, + tauNeutElNeutRate, tauNeutMuonNeutRate, tauNeutScatRate, + pSpectrum, pSpectrumNew); + + /*global convergence */ + changeGlobal = 0.; + ComputeChange(&spectrumGlobalTemp, pSpectrumNew, PROTON, + &changeGlobal); + ComputeChange(&spectrumGlobalTemp, pSpectrumNew, NEUTRON, + &changeGlobal); + ComputeChange(&spectrumGlobalTemp, pSpectrumNew, ELECTRON_NEUTRINO, + &changeGlobal); + ComputeChange(&spectrumGlobalTemp, pSpectrumNew, + ANTI_ELECTRON_NEUTRINO, &changeGlobal); + ComputeChange(&spectrumGlobalTemp, pSpectrumNew, MUON_NEUTRINO, + &changeGlobal); + ComputeChange(&spectrumGlobalTemp, pSpectrumNew, ANTI_MUON_NEUTRINO, + &changeGlobal); + ComputeChange(&spectrumGlobalTemp, pSpectrumNew, TAU_NEUTRINO, + &changeGlobal); + ComputeChange(&spectrumGlobalTemp, pSpectrumNew, ANTI_TAU_NEUTRINO, + &changeGlobal); + } while (changeGlobal > convergeParameter); + + + DeleteSpectrum(&spectrumGlobalTemp); +} + + +void AdvanceEMStep(const int sourceTypeSwitch, const int PPSwitch, + const int ICSSwitch, const int TPPSwitch, + const int DPPSwitch, const int synchrotronSwitch, + const int PPPSwitch, const int NPPSwitch, + const int neutronDecaySwitch, + const int nucleonToSecondarySwitch, + const int neutrinoNeutrinoSwitch, + const double smallDistanceStep, + const double evolutionFactor, + const double convergeParameter, const double bkgFactor, + const Spectrum* pQ_0, + const DiffRate* photonLeptonRate, + const DiffRate* protonElectronRate, + const DiffRate* neutronPositronRate, + const DiffRate* protonPositronRate, + const DiffRate* neutronElectronRate, + const DiffRate* neutronDecayElectronRate, + const DiffRate* elNeutElectronRate, + const DiffRate* muonNeutElectronRate, + const DiffRate* tauNeutElectronRate, + const DiffRate* protonPhotonRate, + const DiffRate* elNeutPhotonRate, + const DiffRate* muonNeutPhotonRate, + const DiffRate* tauNeutPhotonRate, + const TotalRate* leptonTotalRate, + const DiffRate* leptonScatRate, + const DiffRate* leptonExchRate, + const dCVector* continuousLoss, const dCVector* deltaG, + const TotalRate* photonTotalRate, + const DiffRate* leptonPhotonRate, + const DiffRate* syncRate, const Spectrum* pSpectrum, + Spectrum* pSpectrumNew) +{ + int i; + Spectrum spectrumTemp; + Spectrum spectrumGlobalTemp; + /* temporary spectra used in swapping spectra */ + Spectrum influx; + Spectrum influx0; + Spectrum influxExt; + Spectrum outflux; + double changeMax; + /* maximum difference by advance: diff in FORTRAN */ + double changeGlobal; + int num_main_bins; + + num_main_bins = pSpectrum->numberOfMainBins; + + NewSpectrum(&spectrumTemp, num_main_bins); + NewSpectrum(&spectrumGlobalTemp, num_main_bins); + NewSpectrum(&influx, num_main_bins); + NewSpectrum(&influx0, num_main_bins); + NewSpectrum(&influxExt, num_main_bins); + NewSpectrum(&outflux, num_main_bins); + + do { + SetEMSpectrum(&spectrumGlobalTemp, pSpectrumNew); + + // for (i = 0; i < NUM_MAIN_BINS; i++) + // spectrumOld[PHOTON][i] = spectrumNew[PHOTON][i]; + /* I don't think I need it here... */ + + /*---- Converge e+/- first ----*/ + InitializeSpectrum(&influxExt); + + /* external injection */ + GetExternalFlux(sourceTypeSwitch, evolutionFactor, ELECTRON, pQ_0, + &influxExt); + GetExternalFlux(sourceTypeSwitch, evolutionFactor, POSITRON, pQ_0, + &influxExt); + + + InitializeSpectrum(&influx0); + + /* influx from pair production/double pair production */ + if ((PPSwitch == 1) || (DPPSwitch == 1)) + { + GetLeptonInfluxFromPhotons(photonLeptonRate, pSpectrumNew, + &influx0); + } + + /* influx from nucleons */ + if (nucleonToSecondarySwitch == 1) /* secondary tables included */ + { + if ((PPPSwitch == 1) || (NPPSwitch == 1) || + (neutronDecaySwitch == 1)) + { + GetLeptonInfluxFromNucleons(neutronDecaySwitch, + protonElectronRate, neutronPositronRate, + protonPositronRate, neutronElectronRate, + neutronDecayElectronRate, pSpectrumNew, &influx0); + } + } + + /* influx from neutrinos */ + if (neutrinoNeutrinoSwitch == 1) + { + GetLeptonInfluxFromNeutrinos(bkgFactor, elNeutElectronRate, + muonNeutElectronRate, tauNeutElectronRate, pSpectrumNew, + &influx0); + } + + do { + for (i = 0; i < num_main_bins; i++) + { + spectrumTemp.spectrum[ELECTRON][i] = + (pSpectrumNew->spectrum)[ELECTRON][i]; + spectrumTemp.spectrum[POSITRON][i] = + (pSpectrumNew->spectrum)[POSITRON][i]; + } + + InitializeSpectrum(&influx); + InitializeSpectrum(&outflux); + + /* influx & outflux from inverse Compton scattering/synchrotron + radiation */ + if ((ICSSwitch == 1) || (TPPSwitch == 1) || + (synchrotronSwitch == 1)) + { + GetLeptonFluxFromLeptons(leptonTotalRate, leptonScatRate, + leptonExchRate, continuousLoss, deltaG, pSpectrumNew, + &influx, &outflux); + } + + ImplicitEquation(smallDistanceStep, ELECTRON, &influx, &influx0, + &influxExt, &outflux, pSpectrum, pSpectrumNew); + ImplicitEquation(smallDistanceStep, POSITRON, &influx, &influx0, + &influxExt, &outflux, pSpectrum, pSpectrumNew); + /* main difference equation part */ + + changeMax = 0.; + ComputeChange(&spectrumTemp, pSpectrumNew, ELECTRON, &changeMax); + ComputeChange(&spectrumTemp, pSpectrumNew, POSITRON, &changeMax); + } while (changeMax > convergeParameter); + + + /*---- Converge photons ----*/ + /* external influx */ + InitializeSpectrum(&influxExt); + + GetExternalFlux(sourceTypeSwitch, evolutionFactor, PHOTON, pQ_0, + &influxExt); + + InitializeSpectrum(&influx0); + + /* influx from electrons (ICS/synchrotron) */ + if ((ICSSwitch == 1) || (synchrotronSwitch == 1)) + { + GetPhotonInfluxFromLeptons(leptonPhotonRate, synchrotronSwitch, + syncRate, pSpectrumNew, &influx0); + } + + /* influx from nucleons */ + if ((nucleonToSecondarySwitch == 1) && (PPPSwitch == 1)) + { + GetPhotonInfluxFromNucleons(protonPhotonRate, pSpectrumNew, + &influx0); + } + if (neutrinoNeutrinoSwitch == 1) + { + GetPhotonInfluxFromNeutrinos(bkgFactor, elNeutPhotonRate, + muonNeutPhotonRate, tauNeutPhotonRate, pSpectrumNew, &influx0); + } + + do { + for (i = 0; i < num_main_bins; i++) + { + spectrumTemp.spectrum[PHOTON][i] = + (pSpectrumNew->spectrum)[PHOTON][i]; + } + + /* loss (and zero gain) by PP/DPP */ + InitializeSpectrum(&outflux); + if ((PPSwitch == 1) || (DPPSwitch == 1)) + { + GetPhotonFluxFromPhotons(photonTotalRate, &outflux); + } + + ImplicitEquation(smallDistanceStep, PHOTON, &influx, &influx0, + &influxExt, &outflux, pSpectrum, pSpectrumNew); + /* main difference equation */ + + changeMax = 0.; /* reset it for photons */ + ComputeChange(&spectrumTemp, pSpectrumNew, PHOTON, &changeMax); + } while (changeMax > convergeParameter); + + /*global convergence */ + changeGlobal = 0.; + ComputeChange(&spectrumGlobalTemp, pSpectrumNew, ELECTRON, + &changeGlobal); + ComputeChange(&spectrumGlobalTemp, pSpectrumNew, POSITRON, + &changeGlobal); + ComputeChange(&spectrumGlobalTemp, pSpectrumNew, PHOTON, + &changeGlobal); + } while (changeGlobal > convergeParameter); + + DeleteSpectrum(&spectrumTemp); + DeleteSpectrum(&spectrumGlobalTemp); + DeleteSpectrum(&influx); + DeleteSpectrum(&influx0); + DeleteSpectrum(&influxExt); + DeleteSpectrum(&outflux); +} + + +void RedshiftDown(const int lastIndex, const double redshiftRatio, + const dCVector* pEnergy, Spectrum* pSpectrum, + Spectrum* pSpectrumNew) +{ + int i; + + if (pEnergy->dimension != pSpectrum->numberOfMainBins) + { + Error("RedshiftDown: inconsistent dimensions", PROGRAM_ERROR); + } + for (i = 0; i < NUM_SPECIES; i++) + { + RedshiftBinsDown(lastIndex, redshiftRatio, pEnergy, + pSpectrum->spectrum[i], pSpectrumNew->spectrum[i]); + } +} + + +void RedshiftBinsDown(const int lastIndex, const double redshiftRatio, + const dCVector* pEnergy, double* pSpectrum, + double* pSpectrumNew) +/* redshift particle distributions at the end of a big dx */ +{ + int i; + int num_main_bins; + double averaging_factor; + + averaging_factor = (pow(10., 1./2./BINS_PER_DECADE) + + pow(10., -1./2./BINS_PER_DECADE))/2.; + + num_main_bins = pEnergy->dimension; + + if (lastIndex == 0) /* normal steps far from end */ + { + for (i = 0; i < num_main_bins-1; i++) + { + pSpectrum[i] = pSpectrum[i+1]*redshiftRatio* + redshiftRatio*redshiftRatio; + } + pSpectrum[num_main_bins-1] = 0.; + } + else + /* if it's close to z = 0, need some fine tuning because redshift + steps are taken more finely */ + { + // double spectrumTemp[NUM_MAIN_BINS]; + dCVector spectrumTemp; + double energyTemp; + double inflow; + int iMod; + int iMod2; + double tempFraction; + double tempExponent; + + New_dCVector(&spectrumTemp, num_main_bins); + + for (i = 0; i < num_main_bins; i++) + { + energyTemp = (pEnergy->vector)[i]/redshiftRatio; + if (energyTemp > (pEnergy->vector)[num_main_bins-1]/ + averaging_factor*pow(10., 1./2./BINS_PER_DECADE)) + { + inflow = 0.; + } + else + { + iMod = (int)(BINS_PER_DECADE*(log10(energyTemp*ELECTRON_MASS) - + MAX_ENERGY_EXP) + (num_main_bins + 0.5)); +#ifdef DEBUG + CheckIndex(0, num_main_bins, iMod, "RedshiftBinsDown"); +#endif + if ((pEnergy->vector)[iMod] > energyTemp) + { + iMod--; + } + if (iMod < 0) + { + Error("RedshiftBinsDown: iMod became negative.", + PROGRAM_ERROR); /* get the hell out of here! */ + } + iMod2 = iMod + 1; + if (iMod2 >= num_main_bins) + { + inflow = pSpectrum[num_main_bins-1]; + } + else if ((pSpectrum[iMod] < 1.e-40) || + (pSpectrum[iMod2] < 1.e-40)) + { +#ifdef DEBUG + CheckIndex(0, num_main_bins, iMod2, "RedshiftBinsDown"); +#endif + tempFraction = (energyTemp - (pEnergy->vector)[iMod])/ + ((pEnergy->vector)[iMod2] - (pEnergy->vector)[iMod]); + if (tempFraction < 0.) + { + tempFraction = 0.; + } + inflow = pSpectrum[iMod]*(1. - tempFraction) + + pSpectrum[iMod2]*tempFraction; + } + else + { + tempExponent = log(energyTemp/(pEnergy->vector)[iMod])/ + log((pEnergy->vector)[iMod2]/(pEnergy->vector)[iMod]); + inflow = pSpectrum[iMod]*pow(pSpectrum[iMod2]/ + pSpectrum[iMod], tempExponent); + } + } + spectrumTemp.vector[i] = inflow*redshiftRatio*redshiftRatio* + redshiftRatio; + } + +#ifdef DEBUG + if (spectrumTemp.vector[num_main_bins-1] > pSpectrum[num_main_bins-1]) + printf("Auch!!!\n"); +#endif + + for (i = 0; i < num_main_bins; i++) + { + if (spectrumTemp.vector[i] < 0.) + { + Error("RedshiftBinsDown: spectrumTemp negative.", + PROGRAM_ERROR); + } + pSpectrum[i] = spectrumTemp.vector[i]; + pSpectrumNew[i] = pSpectrum[i]; + } + Delete_dCVector(&spectrumTemp); + } +} + + +void GetExternalFlux(const int sourceTypeSwitch, const double evolutionFactor, + const PARTICLE particle, const Spectrum* pQ_0, + Spectrum* pInfluxExt) +{ + int i; + + if (pQ_0->numberOfMainBins != pInfluxExt->numberOfMainBins) + { + Error("GetExternalFlux: inconsistent dimensions", PROGRAM_ERROR); + } + + for (i = 0; i < pQ_0->numberOfMainBins; i++) + { + if (sourceTypeSwitch == 0) /* single source */ + { + (pInfluxExt->spectrum)[particle][i] = 0.; + } + else + { + (pInfluxExt->spectrum)[particle][i] = + (pQ_0->spectrum)[particle][i]*evolutionFactor; + } + } +} + +void ImplicitEquation(const double smallDistanceStep, + const PARTICLE particle, const Spectrum* pInflux, + const Spectrum* pInflux0, const Spectrum* pInfluxExt, + const Spectrum* pOutflux, const Spectrum* pSpectrum, + Spectrum* pSpectrumNew) +{ + /* influx: influx from the same KIND of species (e-: e+/-, p: p/n, etc.) + influx0: influx from other species + influxExt: external influx + NOTE: there is no fundamental distinction between influx and influx0 */ + int i; + int num_main_bins; + + num_main_bins = pSpectrum->numberOfMainBins; + + if ((pInflux->numberOfMainBins != num_main_bins) || + (pInflux0->numberOfMainBins != num_main_bins) || + (pInfluxExt->numberOfMainBins != num_main_bins) || + (pOutflux->numberOfMainBins != num_main_bins) || + (pSpectrumNew->numberOfMainBins != num_main_bins)) + { + Error("ImplicitEquation: inconsistent dimensions", PROGRAM_ERROR); + } + + for (i = 0; i < num_main_bins; i++) + { + (pSpectrumNew->spectrum)[particle][i] = + ((pInflux->spectrum)[particle][i] + + (pInflux0->spectrum)[particle][i] + + (pInfluxExt->spectrum)[particle][i] + + (pSpectrum->spectrum)[particle][i]/smallDistanceStep)/ + ((pOutflux->spectrum)[particle][i] + 1./smallDistanceStep); + /* main difference equation */ + + if ((pSpectrumNew->spectrum)[particle][i] < 0.) + { + (pSpectrumNew->spectrum)[particle][i] = 0.; + } + /* reset if it passes below zero */ + } +} + +void ExplicitEquation(const double smallDistanceStep, + const PARTICLE particle, const Spectrum* pInflux, + const Spectrum* pInflux0, const Spectrum* pInfluxExt, + const Spectrum* pOutflux, const Spectrum* pSpectrum, + const Spectrum* pSpectrumNew) +{ + int i; + int num_main_bins; + + num_main_bins = pSpectrum->numberOfMainBins; + + if ((pInflux->numberOfMainBins != num_main_bins) || + (pInflux0->numberOfMainBins != num_main_bins) || + (pInfluxExt->numberOfMainBins != num_main_bins) || + (pOutflux->numberOfMainBins != num_main_bins) || + (pSpectrumNew->numberOfMainBins != num_main_bins)) + { + Error("ImplicitEquation: inconsistent dimensions", PROGRAM_ERROR); + } + + for (i = 0; i < num_main_bins; i++) + { + (pSpectrumNew->spectrum)[particle][i] = + (pSpectrum->spectrum)[particle][i] + smallDistanceStep* + ((pInflux->spectrum)[particle][i] + + (pInflux0->spectrum)[particle][i] + + (pInfluxExt->spectrum)[particle][i] - + (pSpectrum->spectrum)[particle][i]* + (pOutflux->spectrum)[particle][i]); + + if ((pSpectrumNew->spectrum)[particle][i] < 0.) + { + (pSpectrumNew->spectrum)[particle][i] = 0.; + } + } +} + +void ComputeChange(const Spectrum* pSpectrumTemp, + const Spectrum* pSpectrumNew, + const PARTICLE particle, double* pChangeMax) +{ + double change; + int i; + + if (pSpectrumTemp->numberOfMainBins != pSpectrumNew->numberOfMainBins) + { + Error("ComputeChange: inconsistent dimensions", PROGRAM_ERROR); + } + + for (i = 0; i < pSpectrumNew->numberOfMainBins; i++) + { + change = fabs((pSpectrumNew->spectrum)[particle][i] - + (pSpectrumTemp->spectrum)[particle][i])/ + (fabs((pSpectrumTemp->spectrum)[particle][i]) + EPSILON); + if (change > *pChangeMax) + { + *pChangeMax = change; + } + } +} diff --git a/libs/dint/src/background.cpp b/libs/dint/src/background.cpp new file mode 100644 index 000000000..9dce2ae69 --- /dev/null +++ b/libs/dint/src/background.cpp @@ -0,0 +1,365 @@ + +#include "dint/background.h" + +void LoadPhotonBackground(const double redshift, + dCVector* pBgEnergy, dCVector* pBgEnergyWidth, + dCVector* pBgPhotonDensity, + const int aIRFlag, const double aZmax_IR, const int aRadioFlag, + const double aH0, const double aOmegaM, const double aOmegaLambda) { + if ((pBgEnergy->dimension != pBgEnergyWidth->dimension) || + (pBgEnergyWidth->dimension != pBgPhotonDensity->dimension)) + Error("LoadPhotonBackground: inconsistent dimensions", PROGRAM_ERROR); + + LoadCMB(redshift, pBgEnergy, pBgEnergyWidth, pBgPhotonDensity); + LoadIR(redshift, pBgEnergy, pBgEnergyWidth, pBgPhotonDensity, aIRFlag, aZmax_IR); + LoadRadio(redshift, pBgEnergy, pBgEnergyWidth, pBgPhotonDensity, aRadioFlag, + aH0, aOmegaM, aOmegaLambda); + + for (int i=0; idimension; i++) + (pBgPhotonDensity->vector)[i] *= VOLUME_UNIT; // normalization + +#ifdef PRINT_PHOTON_BACKGROUND // Output the density and exit (July 2005) + cout << "z=" << redshift << endl; + for (int i=0; idimension; i++) + cout << (pBgEnergy->vector)[i] << " " << (pBgPhotonDensity->vector)[i] << endl; + exit(-1) ; +#endif + +} + + +void LoadCMB(const double redshift, const dCVector* pBgEnergy, + const dCVector* pBgEnergyWidth, dCVector* pBgPhotonDensity) { + double numberDensity = 0.; // to test CMB was computed correctly + const double PRESENT_TEMPERATURE = 2.73; // present CMB temperature (K) + double exponent; + double tempNumber; + double temperature; + + temperature = 1.6863e-10*PRESENT_TEMPERATURE*(1. + redshift); + //temperature at redshift (K) + + for (int i=0; idimension; i++) { + exponent = (pBgEnergy->vector)[i]/temperature; + if (exponent < 550.) { + tempNumber = (pBgEnergy->vector)[i]*(pBgEnergy->vector)[i]/ + (exp(exponent) - 1.); // thermal distribution + } else tempNumber = 0.; + (pBgPhotonDensity->vector)[i] = tempNumber* + (pBgEnergyWidth->vector)[i]*1.75586e30; + numberDensity += (pBgPhotonDensity->vector)[i]; + } + +#ifdef TEST_CMB + printf("Computed CMB number density: %g\n", numberDensity); + numberDensity = 20.2417*PRESENT_TEMPERATURE*PRESENT_TEMPERATURE* + PRESENT_TEMPERATURE*(1. + redshift)*(1. + redshift)* + (1. + redshift); + printf("Predicted CMB number density: %g\n", numberDensity); +#endif + +} + + +void LoadIR(const double redshift, const dCVector* pBgEnergy, + const dCVector* pBgEnergyWidth, dCVector* pBgPhotonDensity, + const int aIRFlag, const double aZmax_IR) { + + double IRStartRedshift = aZmax_IR ; // Primack CDM + // const double IRStartRedshift = 4.3; // Primack CHDM + // parameters from Franceschini, Yoshi, and Takahara burst of both components + const double deltaO = 7.; + const double deltaD = 7.; + double (*IRFunction)(const double zTarget, const double zObserve, + const double energy0, const double deltaO, + const double deltaD); + if (aIRFlag == 0) IRFunction = HighIR ; + else if (aIRFlag == 1) IRFunction = LowIR ; + else if (aIRFlag == 2) IRFunction = NULL ; + else Error("LoadIR : Uncorrect IR flag",IO_ERROR) ; + + if (redshift <= IRStartRedshift) { + double z[GAULEG_POINTS]; + double w[GAULEG_POINTS]; + double observeRedshift; + for (int i=0; idimension; i++) { + if (aIRFlag == 2) { + (pBgPhotonDensity->vector)[i] += + IR2(redshift,(pBgEnergy->vector)[i])*(pBgEnergyWidth->vector)[i]*ELECTRON_MASS; + } else { + double temp = 0; + Gauleg(redshift, IRStartRedshift, z, w, GAULEG_POINTS); //find integration points + observeRedshift = redshift; + for (int j=0; jvector)[i], deltaO, deltaD)*w[j]; + (pBgPhotonDensity->vector)[i] += temp*(pBgEnergyWidth->vector)[i]; + } + } + } + +} + + +double IR2(const double redshift, const double BgEnergy) { + + // Primack et al. (1999) CIB parameters + + const double flux_conversion = 2.9979e10/4./PI*1.602e-19*1.e9*1.e4; + // xData is log10(wavelength/micrometers) + // yData is log10(\nu I_\nu/[nW m^-2 sr^-1]) + + // Redshift effect : we assume the following evolution of photon number density : + // n(e,z) = (1+z)**2 * n_0(e/(1+z)) + // It's the same as for CMB (pysically no injection of photons) and therefore the total + // number density evolves as (1+z)**3 + + // Changed to Kneiske Background for consistency with CRPropa interactions, JK + // Kneiske et al. Astron.\ Astrophys.\ {\bf 413} (2004) 807 + const double xData[15] = {-1.00000, -0.750000, -0.500000, -0.250000, 0.00000, 0.250000, 0.500000, 0.750000, + 1.00000, 1.25000, 1.50000, 1.75000, 2.00000, 2.25000, 2.50000}; + const double yData[15] = { -0.214401, 0.349313, 0.720354, 0.890389, 1.16042, 1.24692, 1.06525, 0.668659, 0.536312, 0.595859, 0.457456, + 0.623521, 1.20208, 1.33657, 1.04461}; + +// const double xData[15] = {-1., -0.75, -0.5, -0.25, 0., 0.25, 0.5, +// 0.75, 1., 1.25, 1.5, 1.75, 2., 2.25, 2.5}; +// const double yData[15] = {0.8, 1.1, 1.15, 1.2, 1.3, 1.2, 1.05, 0.7, +// 0.4, 0.3, 0.5, 0.8, 1.1, 1.3, 1.}; + + double result; + double lLocalEnergy = BgEnergy / (1.+redshift) ; // Redshift effect + double x = C/(lLocalEnergy*ELECTRON_MASS*2.42e14)*1.e4; // convert energy into microns + if (x > 500. || log10(x) <= xData[0]) { + result = 0.; + } else if (log10(x) >= xData[14]) { + result = (yData[14] - yData[13])/(xData[14] - xData[13])* + (log10(x) - xData[13]) + yData[13]; + result = pow(10., result); + } else { + int index = 1; + while (xData[index] < log10(x)) index++; + result = (yData[index] - yData[index-1])/ + (xData[index] - xData[index-1])*(log10(x) - xData[index-1]) + + yData[index-1]; + result = pow(10., result); + } + result *= pow(1.+redshift,2.)/pow(lLocalEnergy*ELECTRON_MASS, 2.)/ + flux_conversion; // Redshift effect + + return result; +} + + +double HighIR(const double zTarget, const double zObserve, + const double energy0, const double deltaO, + const double deltaD) { + const double normalization = 2./125.*1.e-5; + // high norm: this is the only difference from LowIR + + double coefficient = 1./pow(1. + zTarget, 4.5)/H_0*4.*PI* + (1. + zObserve)*(1. + zObserve); + double energyTarget = energy0*(1. + zTarget)/(1. + zObserve); + + double function = OpticalIR(energyTarget)*pow(1. + zTarget, deltaO)/30. + + DustIR(energyTarget)/300.*pow(1. + zTarget, deltaD)/2.; + // for no evolution for both (i.e. initial burst) + + return (normalization*coefficient*function) ; +} + + +double LowIR(const double zTarget, const double zObserve, + const double energy0, const double deltaO, + const double deltaD) { + const double normalization = 0.4/125.*1.e-5; + // low norm: this is the only difference from HighIR + + double coefficient = 1./pow(1. + zTarget, 4.5)/H_0*4.*PI* + (1. + zObserve)*(1. + zObserve); + double energyTarget = energy0*(1. + zTarget)/(1. + zObserve); + + double function = OpticalIR(energyTarget)*pow(1. + zTarget, deltaO)/30. + + DustIR(energyTarget)/300.*pow(1. + zTarget, deltaD)/2.; + // for no evolution for both (i.e. initial burst) + + return (normalization*coefficient*function) ; +} + + +double OpticalIR(const double energy) { + const double xData[9] = {-1.0402, -0.9, -0.7, -0.63, -0.4, -0.1, 0.1, 0.6, + 1.}; + const double yData[9] = {-30., -1.45, -1.65, -1.74, -0.33, 0.1, 0.2, -0.6, + -2.6}; + double result; + double x = C/(energy*ELECTRON_MASS*2.42e14)*1.e4; // convert energy into microns + // cut off far IR excess completely + + if (x > 100. || log10(x) <= xData[0]) { + result = 0.; + } else if (log10(x) >= xData[8]) { + result = (yData[8] - yData[7])/(xData[8] - xData[7])* + (log10(x) - xData[7]) + yData[7]; + result = pow(10., result)/energy/energy; + } else { + int index = 1 ; + while (xData[index] < log10(x)) index++; + result = (yData[index] - yData[index-1])/ + (xData[index] - xData[index-1])*(log10(x) - xData[index-1]) + + yData[index-1]; + result = pow(10., result)/energy/energy; + } + + return result; +} + + +double DustIR(const double energy) { + const double xData[6] = {-0.18, 0.54, 1.06, 1.4, 1.8, 2.9}; + const double yData[6] = {-3.0, 0.77, 0.6, 1.37, 1.5, -3.0}; + double result; + double x = C/(energy*ELECTRON_MASS*2.42e14)*1.e4; + + if (log10(x) <= xData[0]) result = 0.; + else if (log10(x) >= xData[5]) { + result = (yData[5] - yData[4])/(xData[5] - xData[4])* + (log10(x) - xData[4]) + yData[4]; + result = pow(10., result)/energy/energy; + } else { + int index = 1 ; + while (xData[index] < log10(x)) index++; + result = (yData[index] - yData[index-1])/ + (xData[index] - xData[index-1])*(log10(x) - xData[index-1]) + + yData[index-1]; + result = pow(10., result)/energy/energy; + } + + return result; +} + + +void LoadRadio(const double redshift, const dCVector* pBgEnergy, + const dCVector* pBgEnergyWidth, dCVector* pBgPhotonDensity, + const int aRadioFlag, const double aH0, const double aOmegaM, + const double aOmegaLambda) { + const double radioStartRedshift = 5.; + // although the source distribution does not vanish at high redshift, + // one might as well cut it off effectively + // (5 is 6 sigma away from peak) + double (*RadioFunction)(const double zObserve, const double zTarget, + const double energy0, const double H, + const double OM, const double OL); + const double B = 2.58734e-28; + if (aRadioFlag != 3) { + // aRadioFlag == 3 : Null radio, so do nothing + if (aRadioFlag == 0) { + RadioFunction = HighRadio ; + } else if (aRadioFlag == 1) { + RadioFunction = MedRadio ; + } else if (aRadioFlag == 2) { + RadioFunction = ObsRadio ; + } else Error("LoadRadio : Uncorrect Radio flag",IO_ERROR) ; + + if (redshift <= radioStartRedshift) { + double z[GAULEG_POINTS]; + double w[GAULEG_POINTS]; + double cutoffFactor; // cutoffFactor removed from function + + for (int i=0; idimension; i++) { + double temp = 0 ; + Gauleg(redshift, radioStartRedshift, z, w, GAULEG_POINTS); + double observeRedshift = redshift; + for (int j=0; jvector)[i], aH0, aOmegaM, aOmegaLambda)*w[j]; + if (RadioFunction == ObsRadio) + cutoffFactor = exp(-B/(pBgEnergy->vector)[i]/ + (pBgEnergy->vector)[i]); + // this is a cutoff of the spectrum due to ISM absorption + else cutoffFactor = 1.; + (pBgPhotonDensity->vector)[i] += cutoffFactor*temp* + (pBgEnergyWidth->vector)[i]; + } + } + } +} + + +double HighRadio(const double zTarget, const double zObserve, + const double energy0, const double aH0, + const double aOmegaM, const double aOmegaLambda) { + double B0 = 25.26*log(10.); + double B1 = 1.18*log(10.); + double B2 = 0.28*log(10.); + double H_z,coefficient,function,energyTarget; + + H_z = aH0*sqrt(aOmegaM*pow(1.+zTarget,3.)+aOmegaLambda); + energyTarget = energy0*(1. + zTarget)/(1. + zObserve); + coefficient = 4.*PI/H_z*DISTANCE_UNIT*1.e6/1.e5*4.2458e-56* + pow(1. + zObserve, 2.)/(1.40576e-28 + 1.81075e-45/energyTarget + + 6.38227e-8*pow(energyTarget, 1.3) + pow(energyTarget, 1.8)); + function = exp(B0 + B1*zTarget - B2*zTarget*zTarget); + + return (1.e0*coefficient*function); +} + + +double MedRadio(const double zTarget, const double zObserve, + const double energy0, const double aH0, + const double aOmegaM, const double aOmegaLambda) { + + return (HighRadio(zTarget,zObserve,energy0,aH0,aOmegaM,aOmegaLambda)/pow(10.,0.7)); +} + + +double ObsRadio(const double zTarget, const double zObserve, + const double energy0, const double aH0, + const double aOmegaM, const double aOmegaLambda) { + double B0 = 25.26*log(10.); + double B1 = 1.18*log(10.); + double B2 = 0.28*log(10.); + double H_z,coefficient,function,energyTarget; + + H_z = aH0*sqrt(aOmegaM*pow(1.+zTarget,3.)+aOmegaLambda); + energyTarget = energy0*(1. + zTarget)/(1. + zObserve); + coefficient = 4.*PI/H_z*DISTANCE_UNIT*1.e6/1.e5*4.2458e-56* + pow(1. + zObserve, 2.)*pow(energyTarget, -1.8); + function = exp(B0 + B1*zTarget - B2*zTarget*zTarget); + + return (coefficient*function); +} + + +/* +// Routine to "dump" the spectrum. +// Not needed +void DumpBgSpectrum(const dCVector* pBgEnergy, const dCVector* pBgEnergyWidth, + const dCVector* pBgPhotonDensity, const char* filename) +{ + int i; + int j; + FILE* dumpFile; + char f1[80] = "datafiles/"; + + if ((pBgEnergy->dimension != pBgEnergyWidth->dimension) || + (pBgEnergyWidth->dimension != pBgPhotonDensity->dimension)) + { + Error("DumpBgSpectrum: inconsistent dimensions", PROGRAM_ERROR); + } + + strncat(f1, filename, 79 - strlen(filename)); + dumpFile = SafeFOpen(f1, "w"); +// this is to send the dump file to a different directory (datafiles) +// by Guenter (7/20/1998) + + for (i = 0; i < pBgEnergy->dimension; i++) + { + fprintf(dumpFile, "%15.4E %15.4E\n", + ELECTRON_MASS*(pBgEnergy->vector)[i], + (pBgPhotonDensity->vector)[i]/ELECTRON_MASS/ + (pBgEnergyWidth->vector)[i]/VOLUME_UNIT); +// proper unit conversion for energy + } + fclose(dumpFile); +} +*/ diff --git a/libs/dint/src/binfread.cpp b/libs/dint/src/binfread.cpp new file mode 100644 index 000000000..83a108945 --- /dev/null +++ b/libs/dint/src/binfread.cpp @@ -0,0 +1,64 @@ + +#include "dint/binfread.h" + +#include + +static int ToSwap() { + static int ToSwap = -1 ; + if ( ToSwap != -1 ) goto endToSwap ; + else { + if ( ntohs(1234) != ntohs(1234) ) ToSwap = 1; + else ToSwap = 0; + } + +endToSwap: + //cerr << "ToSwap = " << ToSwap << endl; + return ToSwap ; +} + +static int16_t Swap2(int16_t a) { + return ( ((a >> 8)&0xff) | ((a << 8)&0xff00) ) ; +} + +static int32_t Swap4(int32_t a) { + return ( ((a >> 24)&0xff) | ((a >> 8 )&0xff00 ) | + ((a << 8 )&0xff0000 ) | ((a << 24)&0xff000000) ) ; +} + +static int64_t Swap8(int64_t a) { + return ( ((a >> 56)&0xff) | ((a >> 40 )&0xff00 ) | + ((a >> 24)&0xff0000) | ((a >> 8 )&0xff000000) | + ((a << 8 )&(((int64_t)(0xff))<<32)) | + ((a << 24)&(((int64_t)(0xff))<<40)) | + ((a << 40)&(((int64_t)(0xff))<<48)) | + ((a << 56)&(((int64_t)(0xff))<<56)) ) ; +} + +size_t binfread(void *ptr, size_t size, size_t nmemb, FILE *stream) { + size_t i; + size_t s = fread(ptr, size, nmemb, stream); + + if ( ToSwap() && size>1 ) { + if ( size == 2 ) { + int16_t *temp = (int16_t*)ptr; + for ( i=0; i +#include +#include "dint/error.h" +#include "dint/cvector.h" +#include "dint/const.h" + + +void DumpArray(const dCVector* pVector) +{ + int i; + for (i = 0; i < pVector->dimension; i++) + { + printf("%15.6E\n", pVector->vector[i]*ELECTRON_MASS); + } +} + +void CheckIndex(const int lowerLimit, const int upperLimit, const int i, + const char* functionName) +{ + if (i < lowerLimit || i >= upperLimit) + { + printf("%s: index out of bounds!!!\n", functionName); + printf("Should have satisfied %i <= %i < %i.\n", lowerLimit, i, + upperLimit); + exit (ARRAY_ERROR); + } +} diff --git a/libs/dint/src/cvector.cpp b/libs/dint/src/cvector.cpp new file mode 100644 index 000000000..9bf664ef2 --- /dev/null +++ b/libs/dint/src/cvector.cpp @@ -0,0 +1,36 @@ + +#include "dint/cvector.h" + +void New_dCVector(dCVector* pVector, const int n) { + pVector->dimension = n; + pVector->vector = New_dVector(n); + + Initialize_dCVector(pVector); +} + +void Delete_dCVector(dCVector* pVector) { + Delete_dVector(pVector->vector); +} + +void Initialize_dCVector(dCVector* pVector) { + for (int i = 0; idimension; i++) pVector->vector[i] = 0.; +} + + +void New_iCMatrix(iCMatrix* pMatrix, const int n1, const int n2) { + pMatrix->dimension1 = n1; + pMatrix->dimension2 = n2; + pMatrix->matrix = New_iMatrix(n1, n2); + + Initialize_iCMatrix(pMatrix); +} + +void Delete_iCMatrix(iCMatrix* pMatrix) { + Delete_iMatrix(pMatrix->matrix); +} + +void Initialize_iCMatrix(iCMatrix* pMatrix) { + for (int i=0; idimension1; i++) { + for (int j=0; jdimension2; j++) pMatrix->matrix[i][j] = 0; + } +} diff --git a/libs/dint/src/decay.cpp b/libs/dint/src/decay.cpp new file mode 100644 index 000000000..3eb5c275b --- /dev/null +++ b/libs/dint/src/decay.cpp @@ -0,0 +1,150 @@ +#include +#include "dint/const.h" +#include "dint/utilities.h" + + +/* NOTE: note that these functions use MIN_ENERGY_EXP, etc. instead of + NUC_MIN_ENERGY_EXP, etc. Thus these functions are tied with the main + routine only. */ +double PionToPhoton(const int iPhoton, const int iPion) +{ + double piEnergyRight; + double piEnergyLeft; + double deltaPiE; + double result; + + piEnergyRight = pow(10., MIN_ENERGY_EXP + (iPion+0.5)/BINS_PER_DECADE)/ + ELECTRON_MASS; + piEnergyLeft = pow(10., MIN_ENERGY_EXP + (iPion-0.5)/BINS_PER_DECADE)/ + ELECTRON_MASS; + deltaPiE = piEnergyRight - piEnergyLeft; + + if (iPhoton < iPion) + result = 2./deltaPiE/BINS_PER_DECADE*log(10.); + else if (iPhoton == iPion) + { + result = 2.*(1./deltaPiE - piEnergyLeft/deltaPiE/deltaPiE/ + BINS_PER_DECADE*log(10.)); + } + else + result = 0.; + + if (result < 0.) + Error("PionToPhoton: decay spectrum negative.", PROGRAM_ERROR); + + return result; +} + + +double PionToLepton(const double leptonEnergy, const double pionEnergy) +{ + const double r = (1.056595e8/1.39567e8)*(1.056595e8/1.39567e8); + const double A0 = 0.94486e0; + const double A2 = -2.7892e0; + const double A3 = 1.2397e0; + const double B0 = -2.4126e0; + const double B0p = -2.8951e0; + const double B2 = 4.3426e0; + const double B3 = -1.9300e0; + + double ratio; + double result; + + ratio = leptonEnergy/pionEnergy; + if (leptonEnergy < r*pionEnergy) + { + result = 1./(1.0 - r)/pionEnergy*(A0 + A2*ratio*ratio + A3*ratio* + ratio*ratio); + } + else + { + result = 1./(1.0 - r)/pionEnergy*(B0 + B0p*log(ratio) + + B2*ratio*ratio + B3*ratio*ratio*ratio); + } + if (result < 0.) + result = 0.; + + return result; +} + +double PionToElectronNeutrino(const double neutrinoEnergy, + const double pionEnergy) +{ + const double r = (1.056595e8/1.39567e8)*(1.056595e8/1.39567e8); + const double C0 = 1.1053e0; + const double C2 = -4.46883e0; + const double C3 = 3.71887e0; + const double D0 = 13.846e0; + const double D0p = 5.37053e0; + const double D1 = -28.1116e0; + const double D2 = 20.0558e0; + const double D3 = -5.7902e0; + + double ratio; + double result; + + ratio = neutrinoEnergy/pionEnergy; + if (neutrinoEnergy < r*pionEnergy) + { + result = 1./(1. - r)/pionEnergy*(C0 + C2*ratio*ratio + C3*ratio*ratio + *ratio); + } + else + { + result = 1./(1. - r)/pionEnergy*(D0 + D0p*log(ratio) + D1*ratio + + D2*ratio*ratio + D3*ratio*ratio*ratio); + } + if (result < 0.) + result = 0.; + + return result; +} + +double PionToMuonNeutrino(const int iNeutrino, const int iPion) +{ + const double r = (1.056595e8/1.39567e8)*(1.056595e8/1.39567e8); + + double neutEnergyLeft; + double neutEnergyRight; + double piEnergyLeft; + double piEnergyRight; + double deltaNeutE; + double deltaPiE; + double result; + + neutEnergyRight = pow(10., MIN_ENERGY_EXP + (iNeutrino+0.5)/ + BINS_PER_DECADE)/ELECTRON_MASS; + neutEnergyLeft = pow(10., MIN_ENERGY_EXP + (iNeutrino-0.5)/ + BINS_PER_DECADE)/ELECTRON_MASS; + deltaNeutE = neutEnergyRight - neutEnergyLeft; + + piEnergyRight = pow(10., MIN_ENERGY_EXP + (iPion+0.5)/BINS_PER_DECADE)/ + ELECTRON_MASS; + piEnergyLeft = pow(10., MIN_ENERGY_EXP + (iPion-0.5)/BINS_PER_DECADE)/ + ELECTRON_MASS; + deltaPiE = piEnergyRight - piEnergyLeft; + + if (neutEnergyRight < piEnergyLeft*(1.-r)) + result = log(piEnergyRight/piEnergyLeft)/(1. - r)/deltaPiE; + else if (neutEnergyLeft < piEnergyLeft*(1.-r)) + { + result = (deltaNeutE/(1. - r)*log(piEnergyRight*(1. - r)/ + neutEnergyRight) + neutEnergyRight/(1. - r) - piEnergyLeft - + neutEnergyLeft/(1. - r)*log(neutEnergyRight/(piEnergyLeft* + (1. - r))))/deltaPiE/deltaNeutE; + } + else if ((neutEnergyLeft < piEnergyRight*(1.-r)) && + (neutEnergyRight > piEnergyRight*(1.-r))) + { + result = (piEnergyRight - neutEnergyLeft/(1. - r) - neutEnergyLeft/ + (1. - r)*log(piEnergyRight*(1. - r)/neutEnergyLeft))/deltaPiE/ + deltaNeutE; + } + else + result = 0.; + + if (result < 0.) + result = 0.; + + return result; +} diff --git a/libs/dint/src/deriv.cpp b/libs/dint/src/deriv.cpp new file mode 100644 index 000000000..07976f216 --- /dev/null +++ b/libs/dint/src/deriv.cpp @@ -0,0 +1,477 @@ +#include "dint/deriv.h" +#include "dint/rate.h" +#include "dint/spectrum.h" +#include "dint/error.h" +#include "dint/check.h" +#include "dint/cvector.h" + + +void GetLeptonInfluxFromPhotons(const DiffRate* photonLeptonRate, + const Spectrum* pSpectrumNew, + Spectrum* pInflux0) +{ + ComputeInflux(1., photonLeptonRate, PHOTON, ELECTRON, pSpectrumNew, + pInflux0); + ComputeInflux(1., photonLeptonRate, PHOTON, POSITRON, pSpectrumNew, + pInflux0); +} + +void GetLeptonInfluxFromNucleons(const int neutronDecaySwitch, + const DiffRate* protonElectronRate, + const DiffRate* neutronPositronRate, + const DiffRate* protonPositronRate, + const DiffRate* neutronElectronRate, + const DiffRate* neutronDecayElectronRate, + const Spectrum* pSpectrumNew, + Spectrum* pInflux0) +{ + /* lepton influx from nucleons */ + ComputeInflux(1., protonElectronRate, PROTON, ELECTRON, pSpectrumNew, + pInflux0); + ComputeInflux(1., neutronPositronRate, NEUTRON, POSITRON, pSpectrumNew, + pInflux0); + ComputeInflux(1., protonPositronRate, PROTON, POSITRON, pSpectrumNew, + pInflux0); + ComputeInflux(1., neutronElectronRate, NEUTRON, ELECTRON, pSpectrumNew, + pInflux0); + if (neutronDecaySwitch == 1) + { + ComputeInflux(1., neutronDecayElectronRate, NEUTRON, ELECTRON, + pSpectrumNew, pInflux0); + } +} + +void GetLeptonInfluxFromNeutrinos(const double bkgFactor, + const DiffRate* elNeutElectronRate, + const DiffRate* muonNeutElectronRate, + const DiffRate* tauNeutElectronRate, + const Spectrum* pSpectrumNew, + Spectrum* pInflux0) +{ + ComputeInflux(bkgFactor, elNeutElectronRate, ELECTRON_NEUTRINO, ELECTRON, + pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, elNeutElectronRate, ANTI_ELECTRON_NEUTRINO, + ELECTRON, pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, elNeutElectronRate, ELECTRON_NEUTRINO, POSITRON, + pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, elNeutElectronRate, ANTI_ELECTRON_NEUTRINO, + POSITRON, pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, muonNeutElectronRate, MUON_NEUTRINO, ELECTRON, + pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, muonNeutElectronRate, ANTI_MUON_NEUTRINO, + ELECTRON, pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, muonNeutElectronRate, MUON_NEUTRINO, POSITRON, + pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, muonNeutElectronRate, ANTI_MUON_NEUTRINO, + POSITRON, pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, tauNeutElectronRate, TAU_NEUTRINO, ELECTRON, + pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, tauNeutElectronRate, ANTI_TAU_NEUTRINO, ELECTRON, + pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, tauNeutElectronRate, TAU_NEUTRINO, POSITRON, + pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, tauNeutElectronRate, ANTI_TAU_NEUTRINO, POSITRON, + pSpectrumNew, pInflux0); +} + +void GetLeptonFluxFromLeptons(const TotalRate* leptonTotalRate, + const DiffRate* leptonScatRate, + const DiffRate* leptonExchRate, + const dCVector* continuousLoss, + const dCVector* deltaG, + const Spectrum* pSpectrumNew, Spectrum* pInflux, + Spectrum* pOutflux) +{ + int i; + int num_main_bins; + + num_main_bins = pOutflux->numberOfMainBins; + if ((continuousLoss->dimension != num_main_bins) || + (deltaG->dimension != num_main_bins)) + { + Error("GetLeptonFluxFromLeptons: inconsistent dimensions", + PROGRAM_ERROR); + } + + /* ICS & TPP (differential) */ + ComputeOutflux(1., leptonTotalRate, ELECTRON, pOutflux); + ComputeOutflux(1., leptonTotalRate, POSITRON, pOutflux); + /* outflux */ + + ComputeInflux(1., leptonScatRate, ELECTRON, ELECTRON, pSpectrumNew, + pInflux); + ComputeInflux(1., leptonScatRate, POSITRON, POSITRON, pSpectrumNew, + pInflux); + ComputeInflux(1., leptonExchRate, ELECTRON, POSITRON, pSpectrumNew, + pInflux); + ComputeInflux(1., leptonExchRate, POSITRON, ELECTRON, pSpectrumNew, + pInflux); + /* this is for TPP */ + + /* continuous energy loss (synchrotron & TPP) */ + for (i = 0; i < num_main_bins; i++) + { + double fraction; + + fraction = (continuousLoss->vector)[i]/(deltaG->vector)[i]; + (pOutflux->spectrum)[ELECTRON][i] += -fraction; + (pOutflux->spectrum)[POSITRON][i] += -fraction; + if (i != num_main_bins - 1) + { + (pInflux->spectrum)[ELECTRON][i] += + -(continuousLoss->vector)[i+1]/(deltaG->vector)[i+1]* + (pSpectrumNew->spectrum)[ELECTRON][i+1]; + (pInflux->spectrum)[POSITRON][i] += + -(continuousLoss->vector)[i+1]/(deltaG->vector)[i+1]* + (pSpectrumNew->spectrum)[POSITRON][i+1]; + } + } +} + + +void GetPhotonInfluxFromLeptons(const DiffRate* leptonPhotonRate, + const int synchrotronSwitch, + const DiffRate* syncRate, + const Spectrum* pSpectrumNew, + Spectrum* pInflux0) +{ + int i; + int num_main_bins; + + num_main_bins = pInflux0->numberOfMainBins; + if (synchrotronSwitch == 1) + { + if (syncRate->mainDimension != num_main_bins) + { + Error("GetPhotonInfluxFromLeptons: inconsistent dimensions", + PROGRAM_ERROR); + } + } + + ComputeInflux(1., leptonPhotonRate, ELECTRON, PHOTON, pSpectrumNew, + pInflux0); + ComputeInflux(1., leptonPhotonRate, POSITRON, PHOTON, pSpectrumNew, + pInflux0); + /* influx from ICS */ + + /* influx from synchrotron */ + if (synchrotronSwitch == 1) + { + for (i = 0; i < num_main_bins; i++) + { + if (((syncRate->bound)[i][0] != num_main_bins - 1) || + (syncRate->bound)[i][1] != 0) + { + int j; + + for (j = (syncRate->bound)[i][0]; j <= (syncRate->bound)[i][1]; + j++) + { + (pInflux0->spectrum)[PHOTON][j] += + (syncRate->diffRate)[i][j]* + ((pSpectrumNew->spectrum)[ELECTRON][i] + + (pSpectrumNew->spectrum)[POSITRON][i]); + } + } + } + } +} + +void GetPhotonInfluxFromNucleons(const DiffRate* protonPhotonRate, + const Spectrum* pSpectrumNew, + Spectrum* pInflux0) +{ + ComputeInflux(1., protonPhotonRate, PROTON, PHOTON, pSpectrumNew, + pInflux0); + ComputeInflux(1., protonPhotonRate, NEUTRON, PHOTON, pSpectrumNew, + pInflux0); +} + +void GetPhotonInfluxFromNeutrinos(const double bkgFactor, + const DiffRate* elNeutPhotonRate, + const DiffRate* muonNeutPhotonRate, + const DiffRate* tauNeutPhotonRate, + const Spectrum* pSpectrumNew, + Spectrum* pInflux0) +{ + ComputeInflux(bkgFactor, elNeutPhotonRate, ELECTRON_NEUTRINO, PHOTON, + pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, elNeutPhotonRate, ANTI_ELECTRON_NEUTRINO, PHOTON, + pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, muonNeutPhotonRate, MUON_NEUTRINO, PHOTON, + pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, muonNeutPhotonRate, ANTI_MUON_NEUTRINO, PHOTON, + pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, tauNeutPhotonRate, TAU_NEUTRINO, PHOTON, + pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, tauNeutPhotonRate, ANTI_TAU_NEUTRINO, PHOTON, + pSpectrumNew, pInflux0); +} + + +void GetPhotonFluxFromPhotons(const TotalRate* photonTotalRate, + Spectrum* pOutflux) +{ + ComputeOutflux(1., photonTotalRate, PHOTON, pOutflux); +} + +void GetNucleonFluxFromNucleons(const int neutronDecaySwitch, + const TotalRate* protonTotalRate, + const TotalRate* neutronTotalRate, + const TotalRate* neutronDecayRate, + const DiffRate* protonScatRate, + const DiffRate* neutronProtonRate, + const DiffRate* protonNeutronRate, + const DiffRate* neutronDecayProtonRate, + const dCVector* protonContinuousLoss, + const dCVector* deltaG, + const Spectrum* pSpectrumNew, + Spectrum* pInflux, Spectrum* pOutflux) +{ + int i; + int num_main_bins; + + num_main_bins = pInflux->numberOfMainBins; + if ((protonContinuousLoss->dimension != num_main_bins) || + (deltaG->dimension != num_main_bins)) + { + Error("GetNucleonFluxFromNucleons: inconsistent dimensions", + PROGRAM_ERROR); + } + + ComputeOutflux(1., protonTotalRate, PROTON, pOutflux); + ComputeOutflux(1., neutronTotalRate, NEUTRON, pOutflux); + if (neutronDecaySwitch == 1) + { + ComputeOutflux(1., neutronDecayRate, NEUTRON, pOutflux); + } + /* compute outflux */ + + ComputeInflux(1., protonScatRate, PROTON, PROTON, pSpectrumNew, pInflux); + ComputeInflux(1., neutronProtonRate, NEUTRON, PROTON, pSpectrumNew, + pInflux); + ComputeInflux(1., protonScatRate, NEUTRON, NEUTRON, pSpectrumNew, pInflux); + ComputeInflux(1., protonNeutronRate, PROTON, NEUTRON, pSpectrumNew, + pInflux); + /* compute influx by PPP */ + + if (neutronDecaySwitch == 1) + { + /*ComputeInflux(1., neutronDecayProtonRate, NEUTRON, PROTON, pSpectrumNew, + pInflux);*/ + + for (i = 0; i < neutronDecayRate->mainDimension; i++) + { + pInflux->spectrum[PROTON][i] += (neutronDecayRate->totalRate[i])* + (pSpectrumNew->spectrum)[NEUTRON][i]; + } + + } + /* add proton influx by neutron decay */ + + for (i = 0; i < num_main_bins; i++) + { + double fraction; + + fraction = (protonContinuousLoss->vector)[i]/(deltaG->vector)[i]; + (pOutflux->spectrum)[PROTON][i] += -fraction; + if (i != num_main_bins - 1) + { + (pInflux->spectrum)[PROTON][i] += -fraction* + (pSpectrumNew->spectrum)[PROTON][i+1]; + } + } +} + +void GetNeutrinoInfluxFromNucleons(const int neutronDecaySwitch, + const DiffRate* protonMuonNeutrinoRate, + const DiffRate* neutronAntiMuonNeutrinoRate, + const DiffRate* neutronMuonNeutrinoRate, + const DiffRate* protonAntiMuonNeutrinoRate, + const DiffRate* protonElectronNeutrinoRate, + const DiffRate* neutronAntiElectronNeutrinoRate, + const DiffRate* protonAntiElectronNeutrinoRate, + const DiffRate* neutronDecayElectronRate, + const Spectrum* pSpectrumNew, + Spectrum* pInflux0) +{ + ComputeInflux(1., protonMuonNeutrinoRate, PROTON, MUON_NEUTRINO, + pSpectrumNew, pInflux0); + ComputeInflux(1., neutronAntiMuonNeutrinoRate, NEUTRON, + ANTI_MUON_NEUTRINO, pSpectrumNew, pInflux0); + ComputeInflux(1., protonAntiMuonNeutrinoRate, PROTON, ANTI_MUON_NEUTRINO, + pSpectrumNew, pInflux0); + ComputeInflux(1., neutronMuonNeutrinoRate, NEUTRON, MUON_NEUTRINO, + pSpectrumNew, pInflux0); + ComputeInflux(1., protonElectronNeutrinoRate, PROTON, ELECTRON_NEUTRINO, + pSpectrumNew, pInflux0); + ComputeInflux(1., neutronAntiElectronNeutrinoRate, NEUTRON, + ANTI_ELECTRON_NEUTRINO, pSpectrumNew, pInflux0); + ComputeInflux(1., protonAntiElectronNeutrinoRate, PROTON, + ANTI_ELECTRON_NEUTRINO, pSpectrumNew, pInflux0); + ComputeInflux(1., protonAntiElectronNeutrinoRate, NEUTRON, + ELECTRON_NEUTRINO, pSpectrumNew, pInflux0); + + if (neutronDecaySwitch == 1) + { + ComputeInflux(1., neutronDecayElectronRate, NEUTRON, + ANTI_ELECTRON_NEUTRINO, pSpectrumNew, pInflux0); + } +} + +void GetNucleonInfluxFromNeutrinos(const double bkgFactor, + const DiffRate* elNeutProtonRate, + const DiffRate* muonNeutProtonRate, + const DiffRate* tauNeutProtonRate, + const Spectrum* pSpectrumNew, + Spectrum* pInflux0) +{ + ComputeInflux(bkgFactor, elNeutProtonRate, ELECTRON_NEUTRINO, PROTON, + pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, elNeutProtonRate, ANTI_ELECTRON_NEUTRINO, PROTON, + pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, muonNeutProtonRate, MUON_NEUTRINO, PROTON, + pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, muonNeutProtonRate, ANTI_MUON_NEUTRINO, PROTON, + pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, tauNeutProtonRate, TAU_NEUTRINO, PROTON, + pSpectrumNew, pInflux0); + ComputeInflux(bkgFactor, tauNeutProtonRate, ANTI_TAU_NEUTRINO, PROTON, + pSpectrumNew, pInflux0); + + /* neutron is unchanged: this has to be replaced after proton-antiproton + symmetry is solved */ +} + +void GetNeutrinoFluxFromNeutrinos(const double bkgFactor, + const TotalRate* elNeutTotalRate, + const TotalRate* muonNeutTotalRate, + const TotalRate* tauNeutTotalRate, + const DiffRate* elNeutScatRate, + const DiffRate* elNeutMuonNeutRate, + const DiffRate* elNeutTauNeutRate, + const DiffRate* muonNeutElNeutRate, + const DiffRate* muonNeutScatRate, + const DiffRate* muonNeutTauNeutRate, + const DiffRate* tauNeutElNeutRate, + const DiffRate* tauNeutMuonNeutRate, + const DiffRate* tauNeutScatRate, + const Spectrum* pSpectrumNew, + Spectrum* pInflux, Spectrum* pOutflux) +{ + int i; + int k; + int num_main_bins; + + num_main_bins = pInflux->numberOfMainBins; + + ComputeOutflux(bkgFactor, elNeutTotalRate, ELECTRON_NEUTRINO, pOutflux); + ComputeOutflux(bkgFactor, elNeutTotalRate, ANTI_ELECTRON_NEUTRINO, + pOutflux); + ComputeOutflux(bkgFactor, muonNeutTotalRate, MUON_NEUTRINO, pOutflux); + ComputeOutflux(bkgFactor, muonNeutTotalRate, ANTI_MUON_NEUTRINO, pOutflux); + ComputeOutflux(bkgFactor, tauNeutTotalRate, TAU_NEUTRINO, pOutflux); + ComputeOutflux(bkgFactor, tauNeutTotalRate, ANTI_TAU_NEUTRINO, pOutflux); + + + ComputeInflux(bkgFactor, elNeutScatRate, ELECTRON_NEUTRINO, + ELECTRON_NEUTRINO, pSpectrumNew, pInflux); + ComputeInflux(bkgFactor, elNeutScatRate, ANTI_ELECTRON_NEUTRINO, + ELECTRON_NEUTRINO, pSpectrumNew, pInflux); + ComputeInflux(bkgFactor, muonNeutElNeutRate, MUON_NEUTRINO, + ELECTRON_NEUTRINO, pSpectrumNew, pInflux); + ComputeInflux(bkgFactor, muonNeutElNeutRate, ANTI_MUON_NEUTRINO, + ELECTRON_NEUTRINO, pSpectrumNew, pInflux); + ComputeInflux(bkgFactor, tauNeutElNeutRate, TAU_NEUTRINO, + ELECTRON_NEUTRINO, pSpectrumNew, pInflux); + ComputeInflux(bkgFactor, tauNeutElNeutRate, ANTI_TAU_NEUTRINO, + ELECTRON_NEUTRINO, pSpectrumNew, pInflux); + + ComputeInflux(bkgFactor, elNeutMuonNeutRate, ELECTRON_NEUTRINO, + MUON_NEUTRINO, pSpectrumNew, pInflux); + ComputeInflux(bkgFactor, elNeutMuonNeutRate, ANTI_ELECTRON_NEUTRINO, + MUON_NEUTRINO, pSpectrumNew, pInflux); + ComputeInflux(bkgFactor, muonNeutScatRate, MUON_NEUTRINO, MUON_NEUTRINO, + pSpectrumNew, pInflux); + ComputeInflux(bkgFactor, muonNeutScatRate, ANTI_MUON_NEUTRINO, + MUON_NEUTRINO, pSpectrumNew, pInflux); + ComputeInflux(bkgFactor, tauNeutMuonNeutRate, TAU_NEUTRINO, MUON_NEUTRINO, + pSpectrumNew, pInflux); + ComputeInflux(bkgFactor, tauNeutMuonNeutRate, ANTI_TAU_NEUTRINO, + MUON_NEUTRINO, pSpectrumNew, pInflux); + + ComputeInflux(bkgFactor, elNeutTauNeutRate, ELECTRON_NEUTRINO, + TAU_NEUTRINO, pSpectrumNew, pInflux); + ComputeInflux(bkgFactor, elNeutTauNeutRate, ANTI_ELECTRON_NEUTRINO, + TAU_NEUTRINO, pSpectrumNew, pInflux); + ComputeInflux(bkgFactor, muonNeutTauNeutRate, MUON_NEUTRINO, TAU_NEUTRINO, + pSpectrumNew, pInflux); + ComputeInflux(bkgFactor, muonNeutTauNeutRate, ANTI_MUON_NEUTRINO, + TAU_NEUTRINO, pSpectrumNew, pInflux); + ComputeInflux(bkgFactor, tauNeutScatRate, TAU_NEUTRINO, TAU_NEUTRINO, + pSpectrumNew, pInflux); + ComputeInflux(bkgFactor, tauNeutScatRate, ANTI_TAU_NEUTRINO, TAU_NEUTRINO, + pSpectrumNew, pInflux); + + /* ??? */ + for (i = 0; i < num_main_bins; i++) + { + for (k = 0; k <= i; k++) + { + (pInflux->spectrum)[ANTI_ELECTRON_NEUTRINO][k] = + (pInflux->spectrum)[ELECTRON_NEUTRINO][k]; + (pInflux->spectrum)[ANTI_MUON_NEUTRINO][k] = + (pInflux->spectrum)[MUON_NEUTRINO][k]; + (pInflux->spectrum)[ANTI_TAU_NEUTRINO][k] = + (pInflux->spectrum)[TAU_NEUTRINO][k]; + } + } +} + +void ComputeOutflux(const double bkgFactor, const TotalRate* pRate, + const PARTICLE parent, Spectrum* pOutflux) +{ + int i; + + if (pRate->mainDimension != pOutflux->numberOfMainBins) + { + Error("ComputeOutflux: inconsistent dimension", PROGRAM_ERROR); + } + + for (i = 0; i < pRate->mainDimension; i++) + { + pOutflux->spectrum[parent][i] += bkgFactor*(pRate->totalRate[i]); + } +} + +void ComputeInflux(const double bkgFactor, const DiffRate* pRate, + const PARTICLE parent, const PARTICLE daughter, + const Spectrum* pSpectrum, Spectrum* pInflux) +{ + int i; + int k; + + if ((pRate->mainDimension != pSpectrum->numberOfMainBins) || + (pSpectrum->numberOfMainBins != pInflux->numberOfMainBins)) + { + Error("ComputeInflux: inconsistent dimensions", PROGRAM_ERROR); + } + + for (i = 0; i < pRate->mainDimension; i++) + { + if ((pRate->bound[i][0] != pRate->mainDimension - 1) || + (pRate->bound[i][1] != 0)) + /* bound is valid */ + { + for (k = pRate->bound[i][0]; k <= pRate->bound[i][1]; k++) + { +#ifdef DEBUG + CheckIndex(0, i+1, k, "ComputeInflux"); +#endif + pInflux->spectrum[daughter][k] += bkgFactor* + (pRate->diffRate)[i][k]* + (pSpectrum->spectrum)[parent][i]; + } + } + } +} diff --git a/libs/dint/src/error.cpp b/libs/dint/src/error.cpp new file mode 100644 index 000000000..90dfb063f --- /dev/null +++ b/libs/dint/src/error.cpp @@ -0,0 +1,9 @@ +#include +#include +#include "dint/error.h" + +void Error(const char* errorMessage, const ErrorCode errorCode) +{ + printf("%s\n", errorMessage); + exit (errorCode); +} diff --git a/libs/dint/src/final.cpp b/libs/dint/src/final.cpp new file mode 100644 index 000000000..e50887e76 --- /dev/null +++ b/libs/dint/src/final.cpp @@ -0,0 +1,71 @@ +#include +#include +#include "dint/spectrum.h" +#include "dint/const.h" + +void CheckEnergy(const int sourceTypeSwitch, const double brightPhaseExp, + const double startingRedshift, + const double rightRedshift, const Spectrum* pSpectrum, + const dCVector* pEnergy, const double initialTotalEnergy) +{ + int i; + double tempFraction; + double photonNumber = 0.; + double leptonNumber = 0.; + double nucleonNumber = 0.; + double neutrinoNumber = 0.; + double totalNumber = 0.; + double photonEnergy = 0.; + double leptonEnergy = 0.; + double nucleonEnergy = 0.; + double neutrinoEnergy = 0.; + double totalEnergy = 0.; + double energyRedshiftFactor; + + tempFraction = (1. + startingRedshift)/(1. + rightRedshift); + for (i = 0; i < pEnergy->dimension; i++) + { + photonNumber += (pSpectrum->spectrum)[PHOTON][i]; + photonEnergy += (pSpectrum->spectrum)[PHOTON][i]*(pEnergy->vector)[i]; + leptonNumber += (pSpectrum->spectrum)[ELECTRON][i] + + (pSpectrum->spectrum)[POSITRON][i]; + leptonEnergy += (pEnergy->vector)[i]* + ((pSpectrum->spectrum)[ELECTRON][i] + + (pSpectrum->spectrum)[POSITRON][i]); + } + + nucleonNumber = GetNucleonNumber(pSpectrum); + nucleonEnergy = GetNucleonEnergy(pSpectrum, pEnergy); + neutrinoNumber = GetNeutrinoNumber(pSpectrum); + neutrinoEnergy = GetNeutrinoEnergy(pSpectrum, pEnergy); + totalNumber = photonNumber + leptonNumber + nucleonNumber + neutrinoNumber; + totalEnergy = photonEnergy + leptonEnergy + nucleonEnergy + neutrinoEnergy; + + if (sourceTypeSwitch == 0) /* single source */ + energyRedshiftFactor = 1./pow(tempFraction, 4); + else + { + energyRedshiftFactor = C/H_0*1.e6/1.e5*pow(1. + startingRedshift, + -1.5)/pow(tempFraction,1.5+brightPhaseExp)/(brightPhaseExp-2.5)* + (pow(tempFraction,brightPhaseExp-2.5) - 1.); + } + + // printf(" Total energy = %15.6E (arbitrary units)\n", totalEnergy); + // printf(" (total energy)/(injected energy) = %g\n", + // totalEnergy/initialTotalEnergy/energyRedshiftFactor); +} + + +void FinalPrintOutToTheScreen(const double distance, + const double startingRedshift, + const double propagatingDistance) +{ + double analyticalDistance; + + printf("\n\nTotal distance was %g Mpc ", + distance/DISTANCE_UNIT/1.e6); + analyticalDistance = 2./3.*C*1.e-5/H_0*(1. - + pow(1. + startingRedshift, -3./2.)); + printf("vs. real distance %g Mpc.\n", analyticalDistance); + printf("And total x was %g pc\n", propagatingDistance); +} diff --git a/libs/dint/src/fold.cpp b/libs/dint/src/fold.cpp new file mode 100644 index 000000000..7fb4dfd9c --- /dev/null +++ b/libs/dint/src/fold.cpp @@ -0,0 +1,826 @@ +#include +#include +#include "dint/rate.h" +#include "dint/const.h" +#include "dint/cvector.h" +#include "dint/check.h" +#include "dint/utilities.h" + + +void InitializeLeptonCoefficients(TotalRate* leptonTotalRate, + DiffRate* leptonScatRate, + DiffRate* leptonExchRate, + DiffRate* leptonPhotonRate) +{ + InitializeTotalRate(leptonTotalRate); + InitializeDiffRate(leptonScatRate); + InitializeDiffRate(leptonExchRate); + InitializeDiffRate(leptonPhotonRate); +} + + +void InitializePhotonCoefficients(TotalRate* photonTotalRate, + DiffRate* photonLeptonRate) +{ + InitializeTotalRate(photonTotalRate); + InitializeDiffRate(photonLeptonRate); +} + +void InitializeNucleonCoefficients(TotalRate* protonTotalRate, + TotalRate* neutronTotalRate, + DiffRate* protonScatRate, + DiffRate* protonNeutronRate, + DiffRate* neutronProtonRate, + DiffRate* protonPhotonRate, + DiffRate* protonElectronRate, + DiffRate* protonPositronRate, + DiffRate* neutronElectronRate, + DiffRate* neutronPositronRate, + DiffRate* protonElectronNeutrinoRate, + DiffRate* protonAntiElectronNeutrinoRate, + DiffRate* protonMuonNeutrinoRate, + DiffRate* protonAntiMuonNeutrinoRate, + DiffRate* neutronAntiElectronNeutrinoRate, + DiffRate* neutronMuonNeutrinoRate, + DiffRate* neutronAntiMuonNeutrinoRate) +{ + InitializeTotalRate(protonTotalRate); + InitializeTotalRate(neutronTotalRate); + + InitializeDiffRate(protonScatRate); + InitializeDiffRate(protonNeutronRate); + InitializeDiffRate(neutronProtonRate); + InitializeDiffRate(protonPhotonRate); + InitializeDiffRate(protonElectronRate); + InitializeDiffRate(protonPositronRate); + InitializeDiffRate(neutronElectronRate); + InitializeDiffRate(neutronPositronRate); + InitializeDiffRate(protonElectronNeutrinoRate); + InitializeDiffRate(protonAntiElectronNeutrinoRate); + InitializeDiffRate(protonMuonNeutrinoRate); + InitializeDiffRate(protonAntiMuonNeutrinoRate); + InitializeDiffRate(neutronAntiElectronNeutrinoRate); + InitializeDiffRate(neutronMuonNeutrinoRate); + InitializeDiffRate(neutronAntiMuonNeutrinoRate); +} + +void InitializeNeutrinoCoefficients(TotalRate* elNeutTotalRate, + TotalRate* muonNeutTotalRate, + TotalRate* tauNeutTotalRate, + DiffRate* elNeutScatRate, + DiffRate* elNeutMuonNeutRate, + DiffRate* elNeutTauNeutRate, + DiffRate* elNeutElectronRate, + DiffRate* elNeutPhotonRate, + DiffRate* elNeutProtonRate, + DiffRate* muonNeutElNeutRate, + DiffRate* muonNeutScatRate, + DiffRate* muonNeutTauNeutRate, + DiffRate* muonNeutElectronRate, + DiffRate* muonNeutPhotonRate, + DiffRate* muonNeutProtonRate, + DiffRate* tauNeutElNeutRate, + DiffRate* tauNeutMuonNeutRate, + DiffRate* tauNeutScatRate, + DiffRate* tauNeutElectronRate, + DiffRate* tauNeutPhotonRate, + DiffRate* tauNeutProtonRate) +{ + InitializeTotalRate(elNeutTotalRate); + InitializeTotalRate(muonNeutTotalRate); + InitializeTotalRate(tauNeutTotalRate); + + InitializeDiffRate(elNeutScatRate); + InitializeDiffRate(elNeutMuonNeutRate); + InitializeDiffRate(elNeutTauNeutRate); + InitializeDiffRate(elNeutElectronRate); + InitializeDiffRate(elNeutPhotonRate); + InitializeDiffRate(elNeutProtonRate); + InitializeDiffRate(muonNeutElNeutRate); + InitializeDiffRate(muonNeutScatRate); + InitializeDiffRate(muonNeutTauNeutRate); + InitializeDiffRate(muonNeutElectronRate); + InitializeDiffRate(muonNeutPhotonRate); + InitializeDiffRate(muonNeutProtonRate); + InitializeDiffRate(tauNeutElNeutRate); + InitializeDiffRate(tauNeutMuonNeutRate); + InitializeDiffRate(tauNeutScatRate); + InitializeDiffRate(tauNeutElectronRate); + InitializeDiffRate(tauNeutPhotonRate); + InitializeDiffRate(tauNeutProtonRate); +} + + +void FoldTotalRate(const dCVector* pBgPhotonDensity, + const RawTotalRate* pRawTotalRate, TotalRate* pTotalRate) +{ + int i; + int j; + + if ((pBgPhotonDensity->dimension != pRawTotalRate->bgDimension) || + (pRawTotalRate->mainDimension != pTotalRate->mainDimension)) + { + Error("FoldTotalRate: inconsistent dimensions", PROGRAM_ERROR); + } + + for (i = 0; i < pRawTotalRate->mainDimension; i++) + { + for (j = 0; j < pRawTotalRate->bgDimension; j++) + { + (pTotalRate->totalRate)[i] += (pBgPhotonDensity->vector)[j]* + (pRawTotalRate->totalRate)[i][j]; + } + } +} + +void FoldDiffRate(const dCVector* pBgPhotonDensity, + const RawDiffRate* pRawDiffRate, + DiffRate* pDiffRate, const int scatSwitch, ...) +{ + int i; + int j; + int k; + int offset = 0; + int jLower; + int jUpper; + int num_main_bins; + int num_bg_bins; + + num_main_bins = pRawDiffRate->mainDimension; + num_bg_bins = pRawDiffRate->bgDimension; + + if ((pBgPhotonDensity->dimension != num_bg_bins) || + (num_main_bins != pDiffRate->mainDimension)) + { + Error("FoldDiffRate: inconsistent dimensions", PROGRAM_ERROR); + } + + if (scatSwitch != 0) + /* scattering type: adjustment of total rate(s) needed */ + { + va_list pArg; +// TotalRate* totalRateArray[scatSwitch]; + TotalRate* totalRateArray[3]; + + va_start(pArg, scatSwitch); + for (i = 0; i < scatSwitch; i++) + totalRateArray[i] = va_arg(pArg, TotalRate*); + /* Let totalRateArray[i] point to the totalRate* we will modify; we do + not need to update the arguments later + (i.e. va_arg(...) = totalRateArray[i];) because the actual values + they point to have been properly updated */ + + for (i = 0; i < num_main_bins; i++) + { + jLower = num_main_bins - 1; + jUpper = 0; + for (j = 0; j < num_bg_bins; j++) + { + if (pRawDiffRate->bound[i][j][0] != -1) + /* above threshold */ + { + offset += -(pRawDiffRate->bound)[i][j][0]; + jLower = IMin(jLower, (pRawDiffRate->bound)[i][j][0]); + jUpper = IMax(jUpper, (pRawDiffRate->bound)[i][j][1]); + for (k = (pRawDiffRate->bound)[i][j][0]; + k <= (pRawDiffRate->bound)[i][j][1]; k++) + { +#ifdef DEBUG + CheckIndex(0, i+1, k, "FoldDiffRate"); + CheckIndex(0, pRawDiffRate->numberOfElements, k+offset, + "FoldDiffRate"); +#endif + (pDiffRate->diffRate)[i][k] += + (pBgPhotonDensity->vector)[j]* + (pRawDiffRate->diffRate)[k+offset]; + } + /* these lines take care of the appropriate subtractions + made in the main implicit formula */ + if ((pRawDiffRate->bound)[i][j][1] == i) + /* if (((pRawDiffRate->bound)[i][j][0] <= i) && + ((pRawDiffRate->bound)[i][j][1] >= i)) */ + { + int l; + + for (l = 0; l < scatSwitch; l++) + { + (totalRateArray[l]->totalRate)[i] += + -(pRawDiffRate->diffRate)[i+offset]* + (pBgPhotonDensity->vector)[j]; + } + (pDiffRate->diffRate)[i][i] += + -(pRawDiffRate->diffRate)[i+offset]* + (pBgPhotonDensity->vector)[j]; + } + offset += (pRawDiffRate->bound)[i][j][1] + 1; + /* reset the offset index */ + } + } + (pDiffRate->bound)[i][0] = IMin((pDiffRate->bound)[i][0], jLower); + (pDiffRate->bound)[i][1] = IMax((pDiffRate->bound)[i][1], jUpper); + } + va_end(pArg); + } + else + { + for (i = 0; i < num_main_bins; i++) + { + jLower = num_main_bins - 1; + jUpper = 0; + for (j = 0; j < num_bg_bins; j++) + { + if (pRawDiffRate->bound[i][j][0] != -1) + /* if no threshold or above threshold */ + { + offset += -(pRawDiffRate->bound)[i][j][0]; + jLower = IMin(jLower, (pRawDiffRate->bound)[i][j][0]); + jUpper = IMax(jUpper, (pRawDiffRate->bound)[i][j][1]); + for (k = (pRawDiffRate->bound)[i][j][0]; + k <= (pRawDiffRate->bound)[i][j][1]; k++) + { +#ifdef DEBUG + CheckIndex(0, i+1, k, "FoldDiffRate"); + CheckIndex(0, pRawDiffRate->numberOfElements, k+offset, + "FoldDiffRate"); +#endif + (pDiffRate->diffRate)[i][k] += + (pBgPhotonDensity->vector)[j]* + (pRawDiffRate->diffRate)[k+offset]; + } + offset += (pRawDiffRate->bound)[i][j][1] + 1; + /* reset the offset index */ + } + } + (pDiffRate->bound)[i][0] = IMin((pDiffRate->bound)[i][0], jLower); + (pDiffRate->bound)[i][1] = IMax((pDiffRate->bound)[i][1], jUpper); + } + } +} + + +void FoldICS(const dCVector* pBgPhotonDensity, + const RawTotalRate* ICSTotalRate, + const RawDiffRate* ICSPhotonRate, const RawDiffRate* ICSScatRate, + TotalRate* leptonTotalRate, DiffRate* leptonPhotonRate, + DiffRate* leptonScatRate) +{ + FoldTotalRate(pBgPhotonDensity, ICSTotalRate, leptonTotalRate); + FoldDiffRate(pBgPhotonDensity, ICSScatRate, leptonScatRate, 1, + leptonTotalRate); + FoldDiffRate(pBgPhotonDensity, ICSPhotonRate, leptonPhotonRate, 0); +} + + +void FoldTPP(const dCVector* pBgPhotonDensity, const dCVector* pEnergy, + const RawTotalRate* TPPTotalRate, const RawDiffRate* TPPDiffRate, + TotalRate* leptonTotalRate, DiffRate* leptonScatRate, + DiffRate* leptonExchRate, dCVector* otherLoss) +{ + int i; + int j; + + if ((pEnergy->dimension != TPPTotalRate->mainDimension) || + (TPPTotalRate->bgDimension != pBgPhotonDensity->dimension) || + (otherLoss->dimension != pEnergy->dimension)) + { + Error("FoldTPP: inconsistent dimensions", PROGRAM_ERROR); + } + + /* add TPP total rates in continuous energy loss */ + for (i = 0; i < TPPTotalRate->mainDimension; i++) + { + (otherLoss->vector)[i] = 0.; + for (j = 0; j < TPPTotalRate->bgDimension; j++) + { + (otherLoss->vector)[i] += -(pEnergy->vector)[i]* + (pBgPhotonDensity->vector)[j]* + (TPPTotalRate->totalRate)[i][j]; + } + } + + FoldDiffRate(pBgPhotonDensity, TPPDiffRate, leptonScatRate, 1, + leptonTotalRate); + FoldDiffRate(pBgPhotonDensity, TPPDiffRate, leptonExchRate, 0); +} + + +void FoldPP(const dCVector* pBgPhotonDensity, const RawTotalRate* PPTotalRate, + const RawDiffRate* PPDiffRate, TotalRate* photonTotalRate, + DiffRate* photonLeptonRate) +{ + FoldTotalRate(pBgPhotonDensity, PPTotalRate, photonTotalRate); + FoldDiffRate(pBgPhotonDensity, PPDiffRate, photonLeptonRate, 0); +} + + +void FoldDPP(const dCVector* pBgPhotonDensity, const RawTotalRate* DPPRate, + TotalRate* photonTotalRate, DiffRate* photonLeptonRate) +/* I adopt a simple model where one pair of e-/e+ gets all the energy + equally (1/2); see PRD paper */ +{ + int i; + int j; + int jLower; + int jUpper; + int num_main_bins; + int num_bg_bins; + + double averaging_factor; + int offset; + double ratio; + + + num_main_bins = DPPRate->mainDimension; + num_bg_bins = DPPRate->bgDimension; + + if ((pBgPhotonDensity->dimension != num_bg_bins) || + (photonTotalRate->mainDimension != num_main_bins) || + (photonLeptonRate->mainDimension != num_main_bins)) + { + Error("FoldDPP: inconsistent dimensions", PROGRAM_ERROR); + } + + averaging_factor = (pow(10., 1./2./BINS_PER_DECADE) + + pow(10., -1./2./BINS_PER_DECADE))/2.; + /* although this could be supplied through arguments, I provide a local + version to keep the modality */ + offset = -(int)(BINS_PER_DECADE*log10(averaging_factor/2.) + 0.5); + ratio = offset/BINS_PER_DECADE - log10(2.); + + for (i = 0; i < num_main_bins; i++) + { + jLower = photonLeptonRate->bound[i][0]; + jUpper = photonLeptonRate->bound[i][1]; + for (j = 0; j < num_bg_bins; j++) + { + (photonTotalRate->totalRate)[i] += (pBgPhotonDensity->vector)[j]* + (DPPRate->totalRate)[i][j]; + if ((DPPRate->totalRate)[i][j] > 0.) + { + /* this is supplanted by the new implementation... + (photonLeptonRate->diffRate)[i][i-6] += + (pBgPhotonDensity->vector)[j]* + (DPPRate->totalRate)[i][j]*(1. - alpha); + (photonLeptonRate->diffRate)[i][i-7] += + (pBgPhotonDensity->vector)[j]* + (DPPRate->totalRate)[i][j]*alpha; + jLower = IMin((photonLeptonRate->bound)[i][0], i-7); + jUpper = IMax((photonLeptonRate->bound)[i][1], i-6); + */ + if (ratio < 1.) + { + if (i-offset >= 0) + { +#ifdef DEBUG + CheckIndex(0, num_main_bins, i-offset, "FoldDPP"); +#endif + (photonLeptonRate->diffRate)[i][i-offset] += + (pBgPhotonDensity->vector)[j]* + (DPPRate->totalRate)[i][j]*ratio; + + jLower = IMin(jLower, i-offset); + jUpper = IMax(jUpper, i-offset); + } + if (i-offset-1 >= 0) + { +#ifdef DEBUG + CheckIndex(0, num_main_bins, i-offset-1, "FoldDPP"); +#endif + (photonLeptonRate->diffRate)[i][i-offset-1] += + (pBgPhotonDensity->vector)[j]* + (DPPRate->totalRate)[i][j]*(1. - ratio); + + jLower = IMin(jLower, i-offset-1); + } + } + else + { + if (i-offset >= 0) + { +#ifdef DEBUG + CheckIndex(0, num_main_bins, i-offset, "FoldDPP"); +#endif + (photonLeptonRate->diffRate)[i][i-offset] += + (pBgPhotonDensity->vector)[j]* + (DPPRate->totalRate)[i][j]*(2. - ratio); + + jLower = IMin(jLower, i-offset); + jUpper = IMax(jUpper, i-offset); + } + if (i-offset+1 >= 0) + { +#ifdef DEBUG + CheckIndex(0, num_main_bins, i-offset+1, "FoldDPP"); +#endif + (photonLeptonRate->diffRate)[i][i-offset+1] += + (pBgPhotonDensity->vector)[j]* + (DPPRate->totalRate)[i][j]*(ratio - 1.); + + jUpper = IMax(jUpper, i-offset+1); + } + } + } + } + (photonLeptonRate->bound)[i][0] = jLower; + (photonLeptonRate->bound)[i][1] = jUpper; + /* update bounds */ + } +} + + +void FoldPPPNucleon(const dCVector* pBgPhotonDensity, + const RawTotalRate* PPPProtonLossRate, + const RawTotalRate* PPPNeutronLossRate, + const RawDiffRate* PPPProtonScatRate, + const RawDiffRate* PPPProtonNeutronRate, + const RawDiffRate* PPPNeutronProtonRate, + TotalRate* protonTotalRate, TotalRate* neutronTotalRate, + DiffRate* protonScatRate, DiffRate* protonNeutronRate, + DiffRate* neutronProtonRate) +{ + FoldTotalRate(pBgPhotonDensity, PPPProtonLossRate, protonTotalRate); + FoldTotalRate(pBgPhotonDensity, PPPNeutronLossRate, neutronTotalRate); + + /*---- nucleon -> nucleon from PPP ----*/ + FoldDiffRate(pBgPhotonDensity, PPPProtonScatRate, protonScatRate, + 2, protonTotalRate, neutronTotalRate); + FoldDiffRate(pBgPhotonDensity, PPPProtonNeutronRate, protonNeutronRate, + 0); + FoldDiffRate(pBgPhotonDensity, PPPNeutronProtonRate, neutronProtonRate, + 0); +} + + +void FoldPPPSecondary(const dCVector* pBgPhotonDensity, + const RawDiffRate* PPPProtonPhotonRate, + const RawDiffRate* PPPProtonElectronRate, + const RawDiffRate* PPPProtonPositronRate, + const RawDiffRate* PPPNeutronElectronRate, + const RawDiffRate* PPPProtonElectronNeutrinoRate, + const RawDiffRate* PPPProtonAntiElectronNeutrinoRate, + const RawDiffRate* PPPProtonMuonNeutrinoRate, + const RawDiffRate* PPPProtonAntiMuonNeutrinoRate, + const RawDiffRate* PPPNeutronAntiElectronNeutrinoRate, + const RawDiffRate* PPPNeutronMuonNeutrinoRate, + const RawDiffRate* PPPNeutronAntiMuonNeutrinoRate, + DiffRate* protonPhotonRate, + DiffRate* protonElectronRate, + DiffRate* protonPositronRate, + DiffRate* neutronElectronRate, + DiffRate* neutronPositronRate, + DiffRate* protonElectronNeutrinoRate, + DiffRate* protonAntiElectronNeutrinoRate, + DiffRate* protonMuonNeutrinoRate, + DiffRate* protonAntiMuonNeutrinoRate, + DiffRate* neutronAntiElectronNeutrinoRate, + DiffRate* neutronMuonNeutrinoRate, + DiffRate* neutronAntiMuonNeutrinoRate) +{ + /*---- nucleon -> EM species (gamma, e+/-) from PPP ----*/ + FoldDiffRate(pBgPhotonDensity, PPPProtonPhotonRate, protonPhotonRate, + 0); + FoldDiffRate(pBgPhotonDensity, PPPProtonPositronRate, protonPositronRate, + 0); + FoldDiffRate(pBgPhotonDensity, PPPNeutronElectronRate, + neutronElectronRate, 0); + FoldDiffRate(pBgPhotonDensity, PPPProtonElectronRate, protonElectronRate, + 0); + FoldDiffRate(pBgPhotonDensity, PPPProtonElectronRate, neutronPositronRate, + 0); + + /*---- nucleons -> neutrinos from PPP ----*/ + FoldDiffRate(pBgPhotonDensity, PPPProtonMuonNeutrinoRate, + protonMuonNeutrinoRate, 0); + FoldDiffRate(pBgPhotonDensity, PPPNeutronAntiMuonNeutrinoRate, + neutronAntiMuonNeutrinoRate, 0); + FoldDiffRate(pBgPhotonDensity, PPPProtonAntiMuonNeutrinoRate, + protonAntiMuonNeutrinoRate, 0); + FoldDiffRate(pBgPhotonDensity, PPPNeutronMuonNeutrinoRate, + neutronMuonNeutrinoRate, 0); + FoldDiffRate(pBgPhotonDensity, PPPProtonElectronNeutrinoRate, + protonElectronNeutrinoRate, 0); + FoldDiffRate(pBgPhotonDensity, PPPNeutronAntiElectronNeutrinoRate, + neutronAntiElectronNeutrinoRate, 0); + FoldDiffRate(pBgPhotonDensity, PPPProtonAntiElectronNeutrinoRate, + protonAntiElectronNeutrinoRate, 0); +} + +void FoldNPPNucleon(const dCVector* pBgPhotonDensity, const dCVector* pEnergy, + const RawTotalRate* NPPTotalRate, + dCVector* protonContinuousLoss) +{ + int i; + int j; + int num_main_bins; + int num_bg_bins; + + num_main_bins = pEnergy->dimension; + num_bg_bins = pBgPhotonDensity->dimension; + + if ((NPPTotalRate->mainDimension != num_main_bins) || + (NPPTotalRate->bgDimension != num_bg_bins) || + (protonContinuousLoss->dimension != num_main_bins)) + { + Error("FoldNPP: inconsistent dimensions", PROGRAM_ERROR); + } + + /*---- continuous energy loss ----*/ + for (i = 0; i < num_main_bins; i++) + { + (protonContinuousLoss->vector)[i] = 0.; + /* this is very important! */ + for (j = 0; j < num_bg_bins; j++) + { + (protonContinuousLoss->vector)[i] += -(pEnergy->vector)[i]* + (pBgPhotonDensity->vector)[j]* + (NPPTotalRate->totalRate)[i][j]; + } + } +} + +void FoldNPPSecondary(const dCVector* pBgPhotonDensity, + const RawDiffRate* NPPDiffRate, + DiffRate* protonPositronRate, + DiffRate* protonElectronRate) +{ + FoldDiffRate(pBgPhotonDensity, NPPDiffRate, protonPositronRate, 0); + FoldDiffRate(pBgPhotonDensity, NPPDiffRate, protonElectronRate, 0); +} + + +void MapNeutTotalRate(const double redshift, const int lastIndex, + const int tauNeutrinoMassSwitch, + const TotalRate* NNTotalRate, TotalRate* pRate) +/* This is for m_nu = 0 */ +{ + double redshiftFactor; + int i; + int offset; + int iNew; + int num_main_bins; + + num_main_bins = pRate->mainDimension; + + if (NNTotalRate->mainDimension != pRate->mainDimension) + { + Error("ManNeutTotalRate: inconsistent dimensions", PROGRAM_ERROR); + } + redshiftFactor = (1. + redshift)*(1. + redshift)*(1. + redshift); + + if (tauNeutrinoMassSwitch == 2) /* massless case */ + { + if (lastIndex == 0) /* away from z = 0 (simple sliding applies) */ + { + offset = (int)(BINS_PER_DECADE*log10(1. + redshift)); + for (i = 0; i < num_main_bins; i++) + { + iNew = i + offset; + /* map to the right index */ + if (iNew >= num_main_bins) + iNew = num_main_bins - 1; + /* if the index is beyond range, simply set it to maximum + (unsatisfactory?) */ +#ifdef DEBUG + CheckIndex(0, num_main_bins, iNew, "MapNeutTotalRate"); +#endif + (pRate->totalRate)[i] = redshiftFactor* + (NNTotalRate->totalRate)[iNew]; + } + } + else + { + double fraction; + + fraction = BINS_PER_DECADE*log10(1. + redshift); + offset = (int)fraction; + for (i = 0; i < num_main_bins; i++) + { + iNew = i + offset; + if (iNew < num_main_bins - 1) + { +#ifdef DEBUG + CheckIndex(0, num_main_bins, iNew, "MapNeutTotalRate"); +#endif + (pRate->totalRate)[i] = redshiftFactor* + ((NNTotalRate->totalRate)[iNew]* + (1. - fraction) + (NNTotalRate->totalRate)[iNew+1]* + fraction); + } + else + { + (pRate->totalRate)[i] = redshiftFactor* + (NNTotalRate->totalRate)[num_main_bins-1]; + } + } + } + } + else /* massive neutrinos */ + { + for (i = 0; i < num_main_bins; i++) + { + (pRate->totalRate)[i] = redshiftFactor* + (NNTotalRate->totalRate)[i]; + } + } +} + +void MapNeutDiffRate(const double redshift, const int lastIndex, + const int tauNeutrinoMassSwitch, + const DiffRate* NNDiffRate, DiffRate* pRate) +{ + int i; + int j; + int offset; + int iNew; + int jNew; + double redshiftFactor; + int num_main_bins; + + num_main_bins = pRate->mainDimension; + + if (NNDiffRate->mainDimension != pRate->mainDimension) + { + Error("ManNeutDiffRate: inconsistent dimensions", PROGRAM_ERROR); + } + + redshiftFactor = (1. + redshift)*(1. + redshift)*(1. + redshift); + + if (tauNeutrinoMassSwitch == 2) /* massless case */ + { + if (lastIndex == 0) /* away from z = 0 (simple sliding applies) */ + { + offset = (int)(BINS_PER_DECADE*log10(1. + redshift)); + for (i = 0; i < num_main_bins; i++) + { + iNew = i + offset; + /* map to the right index */ + if (iNew >= num_main_bins) + iNew = num_main_bins - 1; + /* if the index is beyond range, simply set it to maximum + (unsatisfactory?) */ + for (j = 0; j < num_main_bins; j++) + { + jNew = j + offset; + if (jNew >= num_main_bins) + jNew = num_main_bins - 1; + +#ifdef DEBUG + CheckIndex(0, num_main_bins, iNew, "MapNeutDiffRate"); + CheckIndex(0, num_main_bins, jNew, "MapNeutDiffRate"); +#endif + (pRate->diffRate)[i][j] = redshiftFactor* + (NNDiffRate->diffRate)[iNew][jNew]; + } + } + } + else + { + double fraction; + + fraction = BINS_PER_DECADE*log10(1. + redshift); + offset = (int)fraction; + for (i = 0; i < num_main_bins; i++) + { + iNew = i + offset; + for (j = 0; j < num_main_bins; j++) + { + jNew = j + offset; + if (iNew < num_main_bins - 1) + { +#ifdef DEBUG + CheckIndex(0, num_main_bins, iNew, "MapNeutDiffRate"); + CheckIndex(0, num_main_bins, jNew, "MapNeutDiffRate"); + CheckIndex(0, num_main_bins, iNew+1, + "MapNeutDiffRate"); + CheckIndex(0, num_main_bins, jNew+1, + "MapNeutDiffRate"); +#endif + (pRate->diffRate)[i][j] = redshiftFactor* + ((NNDiffRate->diffRate)[iNew][jNew]* + (1. - fraction)*(1. - fraction) + + ((NNDiffRate->diffRate)[iNew+1][jNew] + + (NNDiffRate->diffRate)[iNew][jNew+1])*fraction* + (1. - fraction) + + (NNDiffRate->diffRate)[iNew+1][jNew+1]*fraction* + fraction); + } + else if (jNew < num_main_bins - 1) + { +#ifdef DEBUG + CheckIndex(0, num_main_bins, jNew, "MapNeutDiffRate"); + CheckIndex(0, num_main_bins, jNew+1, + "MapNeutDiffRate"); +#endif + (pRate->diffRate)[i][j] = redshiftFactor* + ((NNDiffRate->diffRate)[num_main_bins-1][jNew]* + (1. - fraction) + + (NNDiffRate->diffRate)[num_main_bins-1][jNew+1]* + fraction); + } + else + { + (pRate->diffRate)[i][j] = redshiftFactor* + (NNDiffRate->diffRate)[num_main_bins-1][num_main_bins-1]; + } + } + } + } + } + else /* massive neutrino: simply multiply by redshift factor */ + { + for (i = 0; i < num_main_bins; i++) + { + for (j = 0; j < num_main_bins; j++) + { + (pRate->diffRate)[i][j] = redshiftFactor* + (NNDiffRate->diffRate)[i][j]; + } + } + } + + /* take care of bounds: simply make it standard (0 <= k <= i) */ + for (i = 0; i < pRate->mainDimension; i++) + { + pRate->bound[i][0] = 0; + pRate->bound[i][1] = i; + } +} + +void MapNeutRates(const double redshift, const int lastIndex, + const int tauNeutrinoMassSwitch, + const TotalRate* NNElNeutTotalRate, + const TotalRate* NNMuonNeutTotalRate, + const TotalRate* NNTauNeutTotalRate, + const DiffRate* NNElNeutScatRate, + const DiffRate* NNElNeutMuonNeutRate, + const DiffRate* NNElNeutTauNeutRate, + const DiffRate* NNElNeutElectronRate, + const DiffRate* NNElNeutPhotonRate, + const DiffRate* NNElNeutProtonRate, + const DiffRate* NNMuonNeutElNeutRate, + const DiffRate* NNMuonNeutScatRate, + const DiffRate* NNMuonNeutTauNeutRate, + const DiffRate* NNMuonNeutElectronRate, + const DiffRate* NNMuonNeutPhotonRate, + const DiffRate* NNMuonNeutProtonRate, + const DiffRate* NNTauNeutElNeutRate, + const DiffRate* NNTauNeutMuonNeutRate, + const DiffRate* NNTauNeutScatRate, + const DiffRate* NNTauNeutElectronRate, + const DiffRate* NNTauNeutPhotonRate, + const DiffRate* NNTauNeutProtonRate, + TotalRate* elNeutTotalRate, TotalRate* muonNeutTotalRate, + TotalRate* tauNeutTotalRate, DiffRate* elNeutScatRate, + DiffRate* elNeutMuonNeutRate, DiffRate* elNeutTauNeutRate, + DiffRate* elNeutElectronRate, DiffRate* elNeutPhotonRate, + DiffRate* elNeutProtonRate, DiffRate* muonNeutElNeutRate, + DiffRate* muonNeutScatRate, DiffRate* muonNeutTauNeutRate, + DiffRate* muonNeutElectronRate, DiffRate* muonNeutPhotonRate, + DiffRate* muonNeutProtonRate, DiffRate* tauNeutElNeutRate, + DiffRate* tauNeutMuonNeutRate, DiffRate* tauNeutScatRate, + DiffRate* tauNeutElectronRate, DiffRate* tauNeutPhotonRate, + DiffRate* tauNeutProtonRate) +{ + MapNeutTotalRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNElNeutTotalRate, elNeutTotalRate); + MapNeutTotalRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNMuonNeutTotalRate, muonNeutTotalRate); + MapNeutTotalRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNTauNeutTotalRate, tauNeutTotalRate); + MapNeutDiffRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNElNeutScatRate, elNeutScatRate); + MapNeutDiffRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNElNeutMuonNeutRate, elNeutMuonNeutRate); + MapNeutDiffRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNElNeutTauNeutRate, elNeutTauNeutRate); + MapNeutDiffRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNElNeutElectronRate, elNeutElectronRate); + MapNeutDiffRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNElNeutPhotonRate, elNeutPhotonRate); + MapNeutDiffRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNElNeutProtonRate, elNeutProtonRate); + MapNeutDiffRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNMuonNeutElNeutRate, muonNeutElNeutRate); + MapNeutDiffRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNMuonNeutScatRate, muonNeutScatRate); + MapNeutDiffRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNMuonNeutTauNeutRate, muonNeutTauNeutRate); + MapNeutDiffRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNMuonNeutElectronRate, muonNeutElectronRate); + MapNeutDiffRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNMuonNeutPhotonRate, muonNeutPhotonRate); + MapNeutDiffRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNMuonNeutProtonRate, muonNeutProtonRate); + MapNeutDiffRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNTauNeutElNeutRate, tauNeutElNeutRate); + MapNeutDiffRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNTauNeutMuonNeutRate, tauNeutMuonNeutRate); + MapNeutDiffRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNTauNeutScatRate, tauNeutScatRate); + MapNeutDiffRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNTauNeutElectronRate, tauNeutElectronRate); + MapNeutDiffRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNTauNeutPhotonRate, tauNeutPhotonRate); + MapNeutDiffRate(redshift, lastIndex, tauNeutrinoMassSwitch, + NNTauNeutProtonRate, tauNeutProtonRate); +} diff --git a/libs/dint/src/frag.cpp b/libs/dint/src/frag.cpp new file mode 100644 index 000000000..ba2394cf1 --- /dev/null +++ b/libs/dint/src/frag.cpp @@ -0,0 +1,582 @@ +#include +#include +#include "dint/utilities.h" + +double OldFrag(const double x) +{ + double result; + + if ((x > 1.) || (x < 0.)) + Error("OldFrag: invalid x in FragFunction.", PROGRAM_ERROR); + + result = 15./16.*pow(x, -1.5)*(1. - x)*(1. - x); + return result; +} + +double HillFrag(const double x) +{ + double result; + + if ((x > 1.) || (x < 0.)) + Error("HillFrag: invalid x in FragFunction.", PROGRAM_ERROR); + + result = 0.08*exp(2.6*pow(log(1./x),0.5))*pow(1.-x,2.)/ + (x*pow(log(1./x),0.5)); + return result; +} + +double TestFrag(const double x) +{ + double result,dum; + + if ((x > 1.) || (x < 0.)) + Error("TestFrag: invalid x in FragFunction.", PROGRAM_ERROR); + + dum=log(1.e16*x); + result=pow(10.,16.40245282549585 + (0.972599977555579 + + (-0.437688709005956 + (0.07127838644906224 + + (-0.0096795444540692 + + (0.001074648803851362 + + (-0.0001017698959101458 + + (8.29188862155849e-6 + + (-6.028775483570168e-7 + + (3.722893226065044e-8 - + 5.328241092075332e-9* + (-14.27185163534489 + + 0.4342944819032517*dum))* + (-12.58946076125045 + + 0.4342944819032517*dum))* + (-10.90706988715602 + + 0.4342944819032517*dum))* + (-9.22467901306159 + + 0.4342944819032517*dum))* + (-7.542288138967164 + 0.4342944819032517*dum)) + *(-5.859897264872732 + 0.4342944819032517*dum))* + (-4.1775063907783 + 0.4342944819032517*dum))* + (-2.495115516683869 + 0.4342944819032517*dum))* + (-0.812724642589438 + 0.4342944819032517*dum))* + (0.869666231504994 + 0.4342944819032517*dum)); + + return result; +} + +double MLLA_25(const double x) +{ + double result,dum; + + if ((x > 1.) || (x < 0.)) + Error("MLLA_25: invalid x in FragFunction.", PROGRAM_ERROR); + + dum=log(5.e15*x); + result=pow(2.,15.40458956729789 + (0.985611314574832 + + (-0.4486531617591206 + (0.07437713380769515 + + (-0.01028351361441756 + + (0.001162396465975171 + + (-0.0001120792654142042 + + (9.29759848042302e-6 + + (-6.883087600199417e-7 + + (4.326958021115784e-8 - + 6.309347416082323e-9* + (-14.0009246392473 + + 0.4342944819032517*dum))* + (-12.34863676471927 + + 0.4342944819032517*dum))* + (-10.69634889019124 + + 0.4342944819032517*dum))* + (-9.04406101566321 + + 0.4342944819032517*dum))* + (-7.391773141135174 + + 0.4342944819032517*dum))* + (-5.73948526660714 + 0.4342944819032517*dum))* + (-4.087197392079107 + 0.4342944819032517*dum))* + (-2.434909517551073 + 0.4342944819032517*dum))* + (-0.78262164302304 + 0.4342944819032517*dum))* + (0.869666231504994 + 0.4342944819032517*dum))* + pow(5.,16.40458956729789 + (0.985611314574832 + + (-0.4486531617591206 + (0.07437713380769515 + + (-0.01028351361441756 + + (0.001162396465975171 + + (-0.0001120792654142042 + + (9.29759848042302e-6 + + (-6.883087600199417e-7 + + (4.326958021115784e-8 - + 6.309347416082323e-9* + (-14.0009246392473 + + 0.4342944819032517*dum))* + (-12.34863676471927 + + 0.4342944819032517*dum))* + (-10.69634889019124 + + 0.4342944819032517*dum))* + (-9.04406101566321 + + 0.4342944819032517*dum))* + (-7.391773141135174 + + 0.4342944819032517*dum))* + (-5.73948526660714 + 0.4342944819032517*dum))* + (-4.087197392079107 + 0.4342944819032517*dum))* + (-2.434909517551073 + 0.4342944819032517*dum))* + (-0.78262164302304 + 0.4342944819032517*dum))* + (0.869666231504994 + 0.4342944819032517*dum)); + + return result; +} + +double MLLA_24(const double x) +{ + double result,dum; + + if ((x > 1.) || (x < 0.)) + Error("MLLA_24: invalid x in FragFunction.", PROGRAM_ERROR); + + dum=log(5.e14*x); + result=pow(2.,14.41151551291054 + (1.031272826827779 + + (-0.4887554084149168 + (0.0861742231419955 + + (-0.01267862267956894 + + (0.001524972879202349 + + (-0.0001564836567815242 + + (0.00001381420881469393 + + (-1.088524574431424e-6 + + (7.278270707633613e-8 - + 1.131740588420111e-8* + (-13.1009246392473 + + 0.4342944819032517*dum))* + (-11.54863676471927 + + 0.4342944819032517*dum))* + (-9.99634889019124 + + 0.4342944819032517*dum))* + (-8.44406101566321 + + 0.4342944819032517*dum))* + (-6.891773141135172 + + 0.4342944819032517*dum))* + (-5.339485266607138 + 0.4342944819032517*dum))* + (-3.787197392079105 + 0.4342944819032517*dum))* + (-2.234909517551072 + 0.4342944819032517*dum))* + (-0.6826216430230394 + 0.4342944819032517*dum))* + (0.869666231504994 + 0.4342944819032517*dum))* + pow(5.,15.41151551291054 + (1.031272826827779 + + (-0.4887554084149168 + (0.0861742231419955 + + (-0.01267862267956894 + + (0.001524972879202349 + + (-0.0001564836567815242 + + (0.00001381420881469393 + + (-1.088524574431424e-6 + + (7.278270707633613e-8 - + 1.131740588420111e-8* + (-13.1009246392473 + + 0.4342944819032517*dum))* + (-11.54863676471927 + + 0.4342944819032517*dum))* + (-9.99634889019124 + + 0.4342944819032517*dum))* + (-8.44406101566321 + + 0.4342944819032517*dum))* + (-6.891773141135172 + + 0.4342944819032517*dum))* + (-5.339485266607138 + 0.4342944819032517*dum))* + (-3.787197392079105 + 0.4342944819032517*dum))* + (-2.234909517551072 + 0.4342944819032517*dum))* + (-0.6826216430230394 + 0.4342944819032517*dum))* + (0.869666231504994 + 0.4342944819032517*dum)); + + return result; +} + +double MLLA_23(const double x) +{ + double result,dum; + + if ((x > 1.) || (x < 0.)) + Error("MLLA_23: invalid x in FragFunction.", PROGRAM_ERROR); + + dum=log(5.e13*x); + result=pow(2.,13.41903621081451 + (1.080543174351792 + + (-0.5353344158025766 + (0.1007918200125547 + + (-0.01584522550357778 + + (0.00203634282994057 + + (-0.0002232988627851284 + + (0.00002106422871935973 + + (-1.774021976209115e-6 + + (1.26678984354972e-7 - + 2.109673764365339e-8* + (-12.2009246392473 + + 0.4342944819032517*dum))* + (-10.74863676471927 + + 0.4342944819032517*dum))* + (-9.29634889019124 + + 0.4342944819032517*dum))* + (-7.844061015663205 + + 0.4342944819032517*dum))* + (-6.391773141135174 + + 0.4342944819032517*dum))* + (-4.93948526660714 + 0.4342944819032517*dum))* + (-3.487197392079106 + 0.4342944819032517*dum))* + (-2.034909517551073 + 0.4342944819032517*dum))* + (-0.5826216430230398 + 0.4342944819032517*dum))* + (0.869666231504994 + 0.4342944819032517*dum))* + pow(5.,14.4190362108145 + (1.080543174351792 + + (-0.5353344158025766 + (0.1007918200125547 + + (-0.01584522550357778 + + (0.00203634282994057 + + (-0.0002232988627851284 + + (0.00002106422871935973 + + (-1.774021976209115e-6 + + (1.26678984354972e-7 - + 2.109673764365339e-8* + (-12.2009246392473 + + 0.4342944819032517*dum))* + (-10.74863676471927 + + 0.4342944819032517*dum))* + (-9.29634889019124 + + 0.4342944819032517*dum))* + (-7.844061015663205 + + 0.4342944819032517*dum))* + (-6.391773141135174 + + 0.4342944819032517*dum))* + (-4.93948526660714 + 0.4342944819032517*dum))* + (-3.487197392079106 + 0.4342944819032517*dum))* + (-2.034909517551073 + 0.4342944819032517*dum))* + (-0.5826216430230398 + 0.4342944819032517*dum))* + (0.869666231504994 + 0.4342944819032517*dum)); + + return result; +} + +double MLLA_22(const double x) +{ + double result,dum; + + if ((x > 1.) || (x < 0.)) + Error("MLLA_22: invalid x in FragFunction.", PROGRAM_ERROR); + + dum=log(5.e12*x); + result=pow(2.,12.42700515451375 + (1.13410597810389 + + (-0.5900360565767645 + (0.1191811135998055 + + (-0.02011422129768237 + + (0.002774985316661523 + + (-0.000326719986276957 + + (0.00003308906432045379 + + (-2.992669826664713e-6 + + (2.292869774886544e-7 - + 4.109421051511541e-8* + (-11.3009246392473 + + 0.4342944819032517*dum))* + (-9.94863676471927 + + 0.4342944819032517*dum))* + (-8.59634889019124 + + 0.4342944819032517*dum))* + (-7.244061015663207 + + 0.4342944819032517*dum))* + (-5.891773141135173 + + 0.4342944819032517*dum))* + (-4.539485266607139 + 0.4342944819032517*dum))* + (-3.187197392079106 + 0.4342944819032517*dum))* + (-1.834909517551073 + 0.4342944819032517*dum))* + (-0.4826216430230396 + 0.4342944819032517*dum))* + (0.869666231504994 + 0.4342944819032517*dum))* + pow(5.,13.42700515451375 + (1.13410597810389 + + (-0.5900360565767645 + (0.1191811135998055 + + (-0.02011422129768237 + + (0.002774985316661523 + + (-0.000326719986276957 + + (0.00003308906432045379 + + (-2.992669826664713e-6 + + (2.292869774886544e-7 - + 4.109421051511541e-8* + (-11.3009246392473 + + 0.4342944819032517*dum))* + (-9.94863676471927 + + 0.4342944819032517*dum))* + (-8.59634889019124 + + 0.4342944819032517*dum))* + (-7.244061015663207 + + 0.4342944819032517*dum))* + (-5.891773141135173 + + 0.4342944819032517*dum))* + (-4.539485266607139 + 0.4342944819032517*dum))* + (-3.187197392079106 + 0.4342944819032517*dum))* + (-1.834909517551073 + 0.4342944819032517*dum))* + (-0.4826216430230396 + 0.4342944819032517*dum))* + (0.869666231504994 + 0.4342944819032517*dum)); + + return result; +} + +double Susy_MLLA_25(const double x) +{ + double result,dum; + + if ((x > 1.) || (x < 0.)) + Error("SUSY_MLLA_25: invalid x in FragFunction.", PROGRAM_ERROR); + + dum=log(5.e15*x); + result=pow(2.,17.80939867175655 + (0.2839116910462308 + + (-0.2356852044900653 + (0.02811959068440033 + + (-0.003372920093046873 + + (0.0003286208445235064 + + (-0.00002939777800753709 + + (2.158754018629821e-6 + + (-1.695451594928554e-7 + + 1.096396916569957e-9* + (-12.9950665059705 + + 0.4342944819032517*dum))* + (-11.3649635064041 + + 0.4342944819032517*dum))* + (-9.73486050683771 + + 0.4342944819032517*dum))* + (-8.10475750727131 + + 0.4342944819032517*dum))* + (-6.474654507704915 + 0.4342944819032517*dum))* + (-4.844551508138517 + 0.4342944819032517*dum))* + (-3.214448508572119 + 0.4342944819032517*dum))* + (-1.584345509005722 + 0.4342944819032517*dum))* + (0.04575749056067511 + 0.4342944819032517*dum))* + pow(5.,18.80939867175655 + (0.2839116910462308 + + (-0.2356852044900653 + (0.02811959068440033 + + (-0.003372920093046873 + + (0.0003286208445235064 + + (-0.00002939777800753709 + + (2.158754018629821e-6 + + (-1.695451594928554e-7 + + 1.096396916569957e-9* + (-12.9950665059705 + + 0.4342944819032517*dum))* + (-11.3649635064041 + + 0.4342944819032517*dum))* + (-9.73486050683771 + + 0.4342944819032517*dum))* + (-8.10475750727131 + 0.4342944819032517*dum))* + (-6.474654507704915 + 0.4342944819032517*dum))* + (-4.844551508138517 + 0.4342944819032517*dum))* + (-3.214448508572119 + 0.4342944819032517*dum))* + (-1.584345509005722 + 0.4342944819032517*dum))* + (0.04575749056067511 + 0.4342944819032517*dum)); + + return result; +} + +double Susy_MLLA_24(const double x) +{ + double result,dum; + + if ((x > 1.) || (x < 0.)) + Error("SUSY_MLLA_24: invalid x in FragFunction.", PROGRAM_ERROR); + + dum=log(5.e14*x); + result=pow(2.,16.77113060518843 + (0.2757875825414864 + + (-0.2492517918211629 + (0.03115785196336573 + + (-0.003960507732763939 + + (0.0004075768109015362 + + (-0.00003875082087547734 + + (3.001698672664923e-6 + + (-2.54680759800193e-7 - + 6.061017668092866e-10* + (-12.1950665059705 + + 0.4342944819032517*dum))* + (-10.6649635064041 + + 0.4342944819032517*dum))* + (-9.13486050683771 + + 0.4342944819032517*dum))* + (-7.604757507271312 + + 0.4342944819032517*dum))* + (-6.074654507704915 + 0.4342944819032517*dum))* + (-4.544551508138517 + 0.4342944819032517*dum))* + (-3.01444850857212 + 0.4342944819032517*dum))* + (-1.484345509005722 + 0.4342944819032517*dum))* + (0.04575749056067511 + 0.4342944819032517*dum))* + pow(5.,17.77113060518843 + (0.2757875825414864 + + (-0.2492517918211629 + (0.03115785196336573 + + (-0.003960507732763939 + + (0.0004075768109015362 + + (-0.00003875082087547734 + + (3.001698672664923e-6 + + (-2.54680759800193e-7 - + 6.061017668092866e-10* + (-12.1950665059705 + + 0.4342944819032517*dum))* + (-10.6649635064041 + + 0.4342944819032517*dum))* + (-9.13486050683771 + + 0.4342944819032517*dum))* + (-7.604757507271312 + + 0.4342944819032517*dum))* + (-6.074654507704915 + 0.4342944819032517*dum))* + (-4.544551508138517 + 0.4342944819032517*dum))* + (-3.01444850857212 + 0.4342944819032517*dum))* + (-1.484345509005722 + 0.4342944819032517*dum))* + (0.04575749056067511 + 0.4342944819032517*dum)); + + return result; +} + +double Susy_MLLA_23(const double x) +{ + double result,dum; + + if ((x > 1.) || (x < 0.)) + Error("SUSY_MLLA_23: invalid x in FragFunction.", PROGRAM_ERROR); + + dum=log(5.e13*x); + result=pow(2.,15.72966406841544 + (0.2650394265463622 + + (-0.2643461911608049 + (0.03469445588689251 + + (-0.004691489477251425 + + (0.0005115097120944895 + + (-0.00005190898995160702 + + (4.25132297772461e-6 + + (-3.930251977808645e-7 - + 6.036368834076273e-9* + (-11.3950665059705 + + 0.4342944819032517*dum))* + (-9.96496350640411 + + 0.4342944819032517*dum))* + (-8.53486050683771 + + 0.4342944819032517*dum))* + (-7.104757507271313 + + 0.4342944819032517*dum))* + (-5.674654507704915 + 0.4342944819032517*dum))* + (-4.244551508138518 + 0.4342944819032517*dum))* + (-2.81444850857212 + 0.4342944819032517*dum))* + (-1.384345509005722 + 0.4342944819032517*dum))* + (0.04575749056067511 + 0.4342944819032517*dum))* + pow(5.,16.72966406841544 + (0.2650394265463622 + + (-0.2643461911608049 + (0.03469445588689251 + + (-0.004691489477251425 + + (0.0005115097120944895 + + (-0.00005190898995160702 + + (4.25132297772461e-6 + + (-3.930251977808645e-7 - + 6.036368834076273e-9* + (-11.3950665059705 + + 0.4342944819032517*dum))* + (-9.96496350640411 + + 0.4342944819032517*dum))* + (-8.53486050683771 + + 0.4342944819032517*dum))* + (-7.104757507271313 + + 0.4342944819032517*dum))* + (-5.674654507704915 + 0.4342944819032517*dum))* + (-4.244551508138518 + 0.4342944819032517*dum))* + (-2.81444850857212 + 0.4342944819032517*dum))* + (-1.384345509005722 + 0.4342944819032517*dum))* + (0.04575749056067511 + 0.4342944819032517*dum)); + + return result; +} + +double Susy_MLLA_22(const double x) +{ + double result,dum; + + if ((x > 1.) || (x < 0.)) + Error("SUSY_MLLA_22: invalid x in FragFunction.", PROGRAM_ERROR); + + dum=log(5.e12*x); + result=pow(2.,14.684456999313 + (0.2510136065483903 + + (-0.2812473861506196 + (0.03884100532808183 + + (-0.005612423127059197 + + (0.0006504629731684842 + + (-0.00007081237970893412 + + (6.145415483685166e-6 + + (-6.258855246298706e-7 - + 2.175481457118431e-8* + (-10.5950665059705 + + 0.4342944819032517*dum))* + (-9.26496350640411 + + 0.4342944819032517*dum))* + (-7.934860506837712 + + 0.4342944819032517*dum))* + (-6.604757507271314 + + 0.4342944819032517*dum))* + (-5.274654507704916 + 0.4342944819032517*dum))* + (-3.944551508138518 + 0.4342944819032517*dum))* + (-2.61444850857212 + 0.4342944819032517*dum))* + (-1.284345509005722 + 0.4342944819032517*dum))* + (0.04575749056067511 + 0.4342944819032517*dum))* + pow(5.,15.68445699931301 + (0.2510136065483903 + + (-0.2812473861506196 + (0.03884100532808183 + + (-0.005612423127059197 + + (0.0006504629731684842 + + (-0.00007081237970893412 + + (6.145415483685166e-6 + + (-6.258855246298706e-7 - + 2.175481457118431e-8* + (-10.5950665059705 + + 0.4342944819032517*dum))* + (-9.26496350640411 + + 0.4342944819032517*dum))* + (-7.934860506837712 + + 0.4342944819032517*dum))* + (-6.604757507271314 + + 0.4342944819032517*dum))* + (-5.274654507704916 + 0.4342944819032517*dum))* + (-3.944551508138518 + 0.4342944819032517*dum))* + (-2.61444850857212 + 0.4342944819032517*dum))* + (-1.284345509005722 + 0.4342944819032517*dum))* + (0.04575749056067511 + 0.4342944819032517*dum)); + + return result; +} + +double TDFolded(const double x) +{ + double result,dum; + + if ((x > 1.) || (x < 0.)) + Error("TDFolded: invalid x in FragFunction.", PROGRAM_ERROR); + + dum=log(1.e16*x); + result=pow(10.,16.40245282549585 + (2.006465566761043 + + (-1.2290432682737338 + (0.4053297476358819 + + (-0.10906672734507838 + + (0.02423162048512474 + + (-0.004566321632592419 + + (0.0007455136443033367 + + (-0.00010727374780647999 + + (0.000013791254716212407 + + (-1.6018349553861322e-6 + + (1.6963430526506736e-7 + + (-1.6505676370801003e-8 + + (1.4852680477947195e-9 + + (-1.2429947252576973e-10 + + (9.721275964488186e-12 + + (-7.135988486015182e-13 + + (4.933475574027309e-14 + + (-3.2288896623602718e-15 + + (1.9690047616867213e-16 - + 2.6034108179793842e-17* + (-15.113047072392108 + + 0.43429448190325176*dum))* + (-14.271851635344891 + + 0.43429448190325176*dum))* + (-13.430656198297674 + + 0.43429448190325176*dum))* + (-12.589460761250459 + + 0.43429448190325176*dum))* + (-11.748265324203246 + + 0.43429448190325176*dum))* + (-10.907069887156027 + + 0.43429448190325176*dum))* + (-10.065874450108813 + + 0.43429448190325176*dum))* + (-9.224679013061595 + + 0.43429448190325176*dum))* + (-8.383483576014381 + + 0.43429448190325176*dum))* + (-7.542288138967164 + + 0.43429448190325176*dum))* + (-6.701092701919949 + + 0.43429448190325176*dum))* + (-5.859897264872733 + + 0.43429448190325176*dum))* + (-5.018701827825517 + + 0.43429448190325176*dum))* + (-4.1775063907783005 + + 0.43429448190325176*dum))* + (-3.3363109537310853 + + 0.43429448190325176*dum))* + (-2.4951155166838697 + 0.43429448190325176*dum))* + (-1.6539200796366536 + 0.43429448190325176*dum))* + (-0.812724642589438 + 0.43429448190325176*dum))* + (0.028470794457777927 + 0.43429448190325176*dum))* + (0.8696662315049937 + 0.43429448190325176*dum)); + + return result; +} diff --git a/libs/dint/src/gauleg.cpp b/libs/dint/src/gauleg.cpp new file mode 100644 index 000000000..62e06c324 --- /dev/null +++ b/libs/dint/src/gauleg.cpp @@ -0,0 +1,46 @@ +#include + +void Gauleg(const double x1, const double x2, double x[], double w[], + const int n) +{ + int m; + int j; + int i; + double z1; + double z; + double xm; + double xl; + double pp; + double p3; + double p2; + double p1; + const double EPS = 3.0e-11; /* precision parameter */ + + m = (n + 1)/2; + xm = 0.5*(x2 + x1); + xl = 0.5*(x2 - x1); + for (i = 0; i < m; i++) + { + z = cos(3.141592654*(i+0.75)/(n+0.5)); + do + { + p1 = 1.0; + p2 = 0.0; + for (j = 0; j < n; j++) + { + p3 = p2; + p2 = p1; + p1 = ((2.0*j + 1.0)*z*p2 - j*p3)/(j+1); + } + pp = n*(z*p1 - p2)/(z*z - 1.0); + z1 = z; + z = z1 - p1/pp; + } while (fabs(z - z1) > EPS); + + x[i] = xm - xl*z; + x[n-1-i] = xm + x1*z; + w[i] = 2.0*xl/((1.0 - z*z)*pp*pp); + w[n-1-i] = w[i]; + } +} + diff --git a/libs/dint/src/inject.cpp b/libs/dint/src/inject.cpp new file mode 100644 index 000000000..7e6a4236d --- /dev/null +++ b/libs/dint/src/inject.cpp @@ -0,0 +1,55 @@ +#include +#include "dint/cvector.h" +#include "dint/spectrum.h" +#include "dint/const.h" +#include "dint/frag.h" +#include "dint/decay.h" +#include "dint/utilities.h" +#include "dint/inject.h" + +// E.Armengaud - Dec 2005 +// This routine is not used anymore : +// the injection spectrum must now be computed within CRPropa. + +void SetInjectionSpectrum(const PARTICLE part, const double InjEnergy, + const double HInjEnergy, const double deltaE_hadron, + const dCVector* pEnergy, + const dCVector* pEnergyWidth, Spectrum* pQ_0) { + int num_main_bins, maxBin, i; + double criticalEnergy; + + InitializeSpectrum(pQ_0); + num_main_bins = pEnergy->dimension; + + if ((pEnergyWidth->dimension != num_main_bins) || + (pQ_0->numberOfMainBins != num_main_bins)) + Error("PhotonMonoInjection: inconsistent dimensions", PROGRAM_ERROR); + + if (part != NOTHING) { + criticalEnergy = InjEnergy/ELECTRON_MASS; + maxBin = (int)((log10(criticalEnergy*ELECTRON_MASS) - + MAX_ENERGY_EXP)*BINS_PER_DECADE + num_main_bins); + (pQ_0->spectrum)[part][maxBin] = 1.; + + } else { + // In this case, we model the injection spectrum created by pair production + // with a power law of index -7/4 + if (deltaE_hadron == 0.e0) Error("DeltaE_Hadron = 0 !", PROGRAM_ERROR); + double sum=0.; + criticalEnergy = HInjEnergy/ELECTRON_MASS; + for (i = 0; i < num_main_bins; i++) { + if (pEnergy->vector[i] < criticalEnergy) { + (pQ_0->spectrum)[ELECTRON][i] = pow(pEnergy->vector[i],-7./4.)* + (pEnergyWidth->vector)[i]; + sum += (pQ_0->spectrum)[ELECTRON][i]*(pEnergy->vector)[i]; + } + } + sum *= ELECTRON_MASS; + sum = deltaE_hadron/sum/2.; + for (i = 0; i < num_main_bins; i++) { + (pQ_0->spectrum)[ELECTRON][i] *= sum; + (pQ_0->spectrum)[POSITRON][i] = (pQ_0->spectrum)[ELECTRON][i]; + } + + } +} diff --git a/libs/dint/src/io_util.cpp b/libs/dint/src/io_util.cpp new file mode 100644 index 000000000..7798cf3ae --- /dev/null +++ b/libs/dint/src/io_util.cpp @@ -0,0 +1,15 @@ +#include +#include +#include "dint/error.h" + +FILE* SafeFOpen(const char* filename, const char* mode) +{ + FILE* file; + if ((file = fopen(filename, mode)) == NULL) + { + printf("SafeFOpen: cannot open %s\n", filename); + exit (IO_ERROR); + } + + return file; +} diff --git a/libs/dint/src/load.cpp b/libs/dint/src/load.cpp new file mode 100644 index 000000000..6dc1f569c --- /dev/null +++ b/libs/dint/src/load.cpp @@ -0,0 +1,330 @@ + +#include "dint/load.h" + +// Modified Apr 2005 : aDirTable argument + +void LoadICSTables(RawTotalRate* ICSTotalRate, RawDiffRate* ICSPhotonRate, + RawDiffRate* ICSScatRate, const int num_main_bins, + string aDirTables) +{ + ReadRawTotalRate(ICSTotalRate, (aDirTables+"/ICSLoss.dat").c_str()); + ModifyRawTotalRate(ICSTotalRate, num_main_bins); + + ReadRawDiffRate(ICSPhotonRate, (aDirTables+"/ICSLP.dat").c_str()); + ModifyRawDiffRate(ICSPhotonRate, num_main_bins); + + ReadRawDiffRate(ICSScatRate, (aDirTables+"/ICSLS.dat").c_str()); + ModifyRawDiffRate(ICSScatRate, num_main_bins); +} + + +void LoadPPTables(RawTotalRate* PPTotalRate, RawDiffRate* PPDiffRate, + const int num_main_bins, string aDirTables) +{ + ReadRawTotalRate(PPTotalRate, (aDirTables+"/PPLoss.dat").c_str()); + ModifyRawTotalRate(PPTotalRate, num_main_bins); + + ReadRawDiffRate(PPDiffRate, (aDirTables+"/PPPL.dat").c_str()); + ModifyRawDiffRate(PPDiffRate, num_main_bins); +} + + +void LoadTPPTables(RawTotalRate* TPPTotalRate, RawDiffRate* TPPDiffRate, + const int num_main_bins, string aDirTables) +{ + ReadRawTotalRate(TPPTotalRate, (aDirTables+"/TPPLoss.dat").c_str()); + ModifyRawTotalRate(TPPTotalRate, num_main_bins); + + ReadRawDiffRate(TPPDiffRate, (aDirTables+"/TPPDiff.dat").c_str()); + ModifyRawDiffRate(TPPDiffRate, num_main_bins); +} + +void LoadDPPTables(RawTotalRate* DPPRate, const int num_main_bins, + string aDirTables) +{ + ReadRawTotalRate(DPPRate, (aDirTables+"/DPP.dat").c_str()); + ModifyRawTotalRate(DPPRate, num_main_bins); +} + +void LoadPPPNucleonTables(RawTotalRate* PPPProtonLossRate, + RawTotalRate* PPPNeutronLossRate, + RawDiffRate* PPPProtonScatRate, + RawDiffRate* PPPProtonNeutronRate, + RawDiffRate* PPPNeutronProtonRate, + const int num_main_bins, + string aDirTables) +{ + FILE* PPPLoss; + + PPPLoss = SafeFOpen((aDirTables+"/PPPLoss.dat").c_str(), "r"); + binfread(PPPProtonLossRate->totalRate[0], sizeof(double), + (PPPProtonLossRate->mainDimension)*(PPPProtonLossRate->bgDimension), + PPPLoss); + binfread(PPPNeutronLossRate->totalRate[0], sizeof(double), + (PPPNeutronLossRate->mainDimension)*(PPPNeutronLossRate->bgDimension), + PPPLoss); + fclose(PPPLoss); + ModifyRawTotalRate(PPPProtonLossRate, num_main_bins); + ModifyRawTotalRate(PPPNeutronLossRate, num_main_bins); + /* this is treated a little differently because the file contains both + tables */ + + + ReadRawDiffRate(PPPProtonScatRate, (aDirTables+"/PPPPrS.dat").c_str()); + ModifyRawDiffRate(PPPProtonScatRate, num_main_bins); + + ReadRawDiffRate(PPPProtonNeutronRate, (aDirTables+"/PPPPrN.dat").c_str()); + ModifyRawDiffRate(PPPProtonNeutronRate, num_main_bins); + + ReadRawDiffRate(PPPNeutronProtonRate, (aDirTables+"/PPPNPr.dat").c_str()); + ModifyRawDiffRate(PPPNeutronProtonRate, num_main_bins); +} + + +void LoadPPPEMTables(RawDiffRate* PPPProtonPhotonRate, + RawDiffRate* PPPProtonElectronRate, + RawDiffRate* PPPProtonPositronRate, + RawDiffRate* PPPNeutronElectronRate, + const int num_main_bins, + string aDirTables) +{ + FILE* PPPNE; + + ReadRawDiffRate(PPPProtonPhotonRate, (aDirTables+"/PPPPrPh.dat").c_str()); + ModifyRawDiffRate(PPPProtonPhotonRate, num_main_bins); + + ReadRawDiffRate(PPPProtonElectronRate, (aDirTables+"/PPPPrE.dat").c_str()); + ModifyRawDiffRate(PPPProtonElectronRate, num_main_bins); + + ReadRawDiffRate(PPPProtonPositronRate, (aDirTables+"/PPPPrPos.dat").c_str()); + + PPPNE = SafeFOpen((aDirTables+"/PPPNE.dat").c_str(), "r"); + if (PPPNeutronElectronRate->numberOfElements != + PPPProtonPositronRate->numberOfElements) + { + Error("LoadPPPTables: inconsistent dimensions", PROGRAM_ERROR); + } + binfread(PPPNeutronElectronRate->diffRate, sizeof(double), + PPPProtonPositronRate->numberOfElements, PPPNE); + fclose(PPPNE); + CopyRawDiffRate(PPPNeutronElectronRate, PPPProtonPositronRate); + ModifyRawDiffRate(PPPProtonPositronRate, num_main_bins); + ModifyRawDiffRate(PPPNeutronElectronRate, num_main_bins); +} + + +void LoadNPPNucleonTables(RawTotalRate* NPPTotalRate, const int num_main_bins, + string aDirTables) +{ + ReadRawTotalRate(NPPTotalRate, (aDirTables+"/NPPLoss.dat").c_str()); + ModifyRawTotalRate(NPPTotalRate, num_main_bins); +} + +void LoadNPPSecondaryTables(RawDiffRate* NPPDiffRate, const int num_main_bins, + string aDirTables) +{ + ReadRawDiffRate(NPPDiffRate, (aDirTables+"/NPPDiff.dat").c_str()); + ModifyRawDiffRate(NPPDiffRate, num_main_bins); +} + +void LoadPPPNeutrinoTables(RawDiffRate* PPPProtonElectronNeutrinoRate, + RawDiffRate* PPPProtonAntiElectronNeutrinoRate, + RawDiffRate* PPPProtonMuonNeutrinoRate, + RawDiffRate* PPPProtonAntiMuonNeutrinoRate, + RawDiffRate* PPPNeutronAntiElectronNeutrinoRate, + RawDiffRate* PPPNeutronMuonNeutrinoRate, + RawDiffRate* PPPNeutronAntiMuonNeutrinoRate, + const int num_main_bins, string aDirTables) +{ + FILE* PPPPrEN; + FILE* PPPNAEN; + FILE* PPPNMN; + FILE* PPPNAMN; + + + /* these 4 rates share the same bound */ + ReadRawDiffRate(PPPProtonAntiMuonNeutrinoRate, (aDirTables+"/PPPPrAMN.dat").c_str()); + + if (PPPProtonElectronNeutrinoRate->numberOfElements != + PPPProtonAntiMuonNeutrinoRate->numberOfElements) + { + Error("LoadPPPTables: inconsistent dimensions", PROGRAM_ERROR); + } + PPPPrEN = SafeFOpen((aDirTables+"/PPPPrEN.dat").c_str(), "r"); + binfread(PPPProtonElectronNeutrinoRate->diffRate, sizeof(double), + PPPProtonAntiMuonNeutrinoRate->numberOfElements, PPPPrEN); + fclose(PPPPrEN); + CopyRawDiffRateBound(PPPProtonElectronNeutrinoRate, + PPPProtonAntiMuonNeutrinoRate); + + if (PPPNeutronAntiElectronNeutrinoRate->numberOfElements != + PPPProtonAntiMuonNeutrinoRate->numberOfElements) + { + Error("LoadPPPTables: inconsistent dimensions", PROGRAM_ERROR); + } + PPPNAEN = SafeFOpen((aDirTables+"/PPPNAEN.dat").c_str(), "r"); + binfread(PPPNeutronAntiElectronNeutrinoRate->diffRate, sizeof(double), + PPPProtonAntiMuonNeutrinoRate->numberOfElements, PPPNAEN); + fclose(PPPNAEN); + CopyRawDiffRateBound(PPPNeutronAntiElectronNeutrinoRate, + PPPProtonAntiMuonNeutrinoRate); + + if (PPPNeutronMuonNeutrinoRate->numberOfElements != + PPPProtonAntiMuonNeutrinoRate->numberOfElements) + { + Error("LoadPPPTables: inconsistent dimensions", PROGRAM_ERROR); + } + PPPNMN = SafeFOpen((aDirTables+"/PPPNMN.dat").c_str(), "r"); + binfread(PPPNeutronMuonNeutrinoRate->diffRate, sizeof(double), + PPPProtonAntiMuonNeutrinoRate->numberOfElements, PPPNMN); + fclose(PPPNMN); + CopyRawDiffRateBound(PPPNeutronMuonNeutrinoRate, + PPPProtonAntiMuonNeutrinoRate); + + ModifyRawDiffRate(PPPProtonAntiMuonNeutrinoRate, num_main_bins); + ModifyRawDiffRate(PPPProtonElectronNeutrinoRate, num_main_bins); + ModifyRawDiffRate(PPPNeutronAntiElectronNeutrinoRate, num_main_bins); + ModifyRawDiffRate(PPPNeutronMuonNeutrinoRate, num_main_bins); + + + + ReadRawDiffRate(PPPProtonAntiElectronNeutrinoRate, + (aDirTables+"/PPPPrAEN.dat").c_str()); + ModifyRawDiffRate(PPPProtonAntiElectronNeutrinoRate, num_main_bins); + + /* these 2 share bound */ + ReadRawDiffRate(PPPProtonMuonNeutrinoRate, (aDirTables+"/PPPPrMN.dat").c_str()); + + if (PPPNeutronAntiMuonNeutrinoRate->numberOfElements != + PPPProtonMuonNeutrinoRate->numberOfElements) + { + Error("LoadPPPTables: inconsistent dimensions", PROGRAM_ERROR); + } + PPPNAMN = SafeFOpen((aDirTables+"/PPPNAMN.dat").c_str(), "r"); + binfread(PPPNeutronAntiMuonNeutrinoRate->diffRate, sizeof(double), + PPPProtonMuonNeutrinoRate->numberOfElements, PPPNAMN); + fclose(PPPNAMN); + CopyRawDiffRateBound(PPPNeutronAntiMuonNeutrinoRate, + PPPProtonMuonNeutrinoRate); + + ModifyRawDiffRate(PPPProtonMuonNeutrinoRate, num_main_bins); + ModifyRawDiffRate(PPPNeutronAntiMuonNeutrinoRate, num_main_bins); +} + +void LoadNeutronDecayNucleonTables(TotalRate* neutronDecayRate, + DiffRate* neutronDecayProtonRate, + const int num_main_bins, + string aDirTables) +{ + ReadTotalRate(neutronDecayRate, (aDirTables+"/neutronDecayLoss.dat").c_str()); + ModifyTotalRate(neutronDecayRate, num_main_bins); + + ReadDiffRate(neutronDecayProtonRate, (aDirTables+"/neutronDecayProton.dat").c_str()); + ModifyDiffRate(neutronDecayProtonRate, num_main_bins); +} + +void LoadNeutronDecaySecondaryTables(DiffRate* neutronDecayElectronRate, + const int num_main_bins, + string aDirTables) +{ + ReadDiffRate(neutronDecayElectronRate, (aDirTables+"/neutronDecayElectron.dat").c_str()); + ModifyDiffRate(neutronDecayElectronRate, num_main_bins); +} + +void LoadNeutrinoTables(const int tauNeutrinoMassSwitch, + TotalRate* NNElNeutTotalRate, + TotalRate* NNMuonNeutTotalRate, + TotalRate* NNTauNeutTotalRate, + DiffRate* NNElNeutScatRate, + DiffRate* NNElNeutMuonNeutRate, + DiffRate* NNElNeutTauNeutRate, + DiffRate* NNElNeutElectronRate, + DiffRate* NNElNeutPhotonRate, + DiffRate* NNElNeutProtonRate, + DiffRate* NNMuonNeutScatRate, + DiffRate* NNMuonNeutElNeutRate, + DiffRate* NNMuonNeutTauNeutRate, + DiffRate* NNMuonNeutElectronRate, + DiffRate* NNMuonNeutPhotonRate, + DiffRate* NNMuonNeutProtonRate, + DiffRate* NNTauNeutScatRate, + DiffRate* NNTauNeutElNeutRate, + DiffRate* NNTauNeutMuonNeutRate, + DiffRate* NNTauNeutElectronRate, + DiffRate* NNTauNeutPhotonRate, + DiffRate* NNTauNeutProtonRate, + const int num_main_bins, + string aDirTables) +{ + if (tauNeutrinoMassSwitch == 0) + { + ReadTotalRate(NNElNeutTotalRate, (aDirTables+"/ENT_0.dat").c_str()); + ReadTotalRate(NNMuonNeutTotalRate, (aDirTables+"/MNT_0.dat").c_str()); + ReadTotalRate(NNTauNeutTotalRate, (aDirTables+"/TNT_0.dat").c_str()); + + ReadDiffRate(NNElNeutScatRate, (aDirTables+"/ENS_0.dat").c_str()); + ReadDiffRate(NNElNeutMuonNeutRate, (aDirTables+"/ENMN_0.dat").c_str()); + ReadDiffRate(NNElNeutTauNeutRate, (aDirTables+"/ENTN_0.dat").c_str()); + ReadDiffRate(NNElNeutElectronRate, (aDirTables+"/ENE_0.dat").c_str()); + ReadDiffRate(NNElNeutPhotonRate, (aDirTables+"/ENPh_0.dat").c_str()); + ReadDiffRate(NNElNeutProtonRate, (aDirTables+"/ENPr_0.dat").c_str()); + ReadDiffRate(NNMuonNeutElNeutRate, (aDirTables+"/MNEN_0.dat").c_str()); + ReadDiffRate(NNMuonNeutScatRate, (aDirTables+"/MNS_0.dat").c_str()); + ReadDiffRate(NNMuonNeutTauNeutRate, (aDirTables+"/MNTN_0.dat").c_str()); + ReadDiffRate(NNMuonNeutElectronRate, (aDirTables+"/MNE_0.dat").c_str()); + ReadDiffRate(NNMuonNeutPhotonRate, (aDirTables+"/MNPh_0.dat").c_str()); + ReadDiffRate(NNMuonNeutProtonRate, (aDirTables+"/MNPr_0.dat").c_str()); + ReadDiffRate(NNTauNeutElNeutRate, (aDirTables+"/TNEN_0.dat").c_str()); + ReadDiffRate(NNTauNeutMuonNeutRate, (aDirTables+"/TNMN_0.dat").c_str()); + ReadDiffRate(NNTauNeutScatRate, (aDirTables+"/TNS_0.dat").c_str()); + ReadDiffRate(NNTauNeutElectronRate, (aDirTables+"/TNE_0.dat").c_str()); + ReadDiffRate(NNTauNeutPhotonRate, (aDirTables+"/TNPh_0.dat").c_str()); + ReadDiffRate(NNTauNeutProtonRate, (aDirTables+"/TNPr_0.dat").c_str()); + } + else + { + ReadTotalRate(NNElNeutTotalRate, (aDirTables+"/ENT_10.dat").c_str()); + ReadTotalRate(NNMuonNeutTotalRate, (aDirTables+"/MNT_10.dat").c_str()); + ReadTotalRate(NNTauNeutTotalRate, (aDirTables+"/TNT_10.dat").c_str()); + ReadDiffRate(NNElNeutScatRate, (aDirTables+"/ENS_10.dat").c_str()); + ReadDiffRate(NNElNeutMuonNeutRate, (aDirTables+"/ENMN_10.dat").c_str()); + ReadDiffRate(NNElNeutTauNeutRate, (aDirTables+"/ENTN_10.dat").c_str()); + ReadDiffRate(NNElNeutElectronRate, (aDirTables+"/ENE_10.dat").c_str()); + ReadDiffRate(NNElNeutPhotonRate, (aDirTables+"/ENPh_10.dat").c_str()); + ReadDiffRate(NNElNeutProtonRate, (aDirTables+"/ENPr_10.dat").c_str()); + ReadDiffRate(NNMuonNeutElNeutRate, (aDirTables+"/MNEN_10.dat").c_str()); + ReadDiffRate(NNMuonNeutScatRate, (aDirTables+"/MNS_10.dat").c_str()); + ReadDiffRate(NNMuonNeutTauNeutRate, (aDirTables+"/MNTN_10.dat").c_str()); + ReadDiffRate(NNMuonNeutElectronRate, (aDirTables+"/MNE_10.dat").c_str()); + ReadDiffRate(NNMuonNeutPhotonRate, (aDirTables+"/MNPh_10.dat").c_str()); + ReadDiffRate(NNMuonNeutProtonRate, (aDirTables+"/MNPr_10.dat").c_str()); + ReadDiffRate(NNTauNeutElNeutRate, (aDirTables+"/TNEN_10.dat").c_str()); + ReadDiffRate(NNTauNeutMuonNeutRate, (aDirTables+"/TNMN_10.dat").c_str()); + ReadDiffRate(NNTauNeutScatRate, (aDirTables+"/TNS_10.dat").c_str()); + ReadDiffRate(NNTauNeutElectronRate, (aDirTables+"/TNE_10.dat").c_str()); + ReadDiffRate(NNTauNeutPhotonRate, (aDirTables+"/TNPh_10.dat").c_str()); + ReadDiffRate(NNTauNeutProtonRate, (aDirTables+"/TNPr_10.dat").c_str()); + } + + ModifyTotalRate(NNElNeutTotalRate, num_main_bins); + ModifyTotalRate(NNMuonNeutTotalRate, num_main_bins); + ModifyTotalRate(NNTauNeutTotalRate, num_main_bins); + ModifyDiffRate(NNElNeutScatRate, num_main_bins); + ModifyDiffRate(NNElNeutMuonNeutRate, num_main_bins); + ModifyDiffRate(NNElNeutTauNeutRate, num_main_bins); + ModifyDiffRate(NNElNeutElectronRate, num_main_bins); + ModifyDiffRate(NNElNeutPhotonRate, num_main_bins); + ModifyDiffRate(NNElNeutProtonRate, num_main_bins); + ModifyDiffRate(NNMuonNeutElNeutRate, num_main_bins); + ModifyDiffRate(NNMuonNeutScatRate, num_main_bins); + ModifyDiffRate(NNMuonNeutTauNeutRate, num_main_bins); + ModifyDiffRate(NNMuonNeutElectronRate, num_main_bins); + ModifyDiffRate(NNMuonNeutPhotonRate, num_main_bins); + ModifyDiffRate(NNMuonNeutProtonRate, num_main_bins); + ModifyDiffRate(NNTauNeutElNeutRate, num_main_bins); + ModifyDiffRate(NNTauNeutMuonNeutRate, num_main_bins); + ModifyDiffRate(NNTauNeutScatRate, num_main_bins); + ModifyDiffRate(NNTauNeutElectronRate, num_main_bins); + ModifyDiffRate(NNTauNeutPhotonRate, num_main_bins); + ModifyDiffRate(NNTauNeutProtonRate, num_main_bins); +} diff --git a/libs/dint/src/math_util.cpp b/libs/dint/src/math_util.cpp new file mode 100644 index 000000000..545cf262e --- /dev/null +++ b/libs/dint/src/math_util.cpp @@ -0,0 +1,34 @@ +double DMax(const double double1, const double double2) +{ + if (double1 >= double2) + return double1; + else + return double2; +} + + +double DMin(const double double1, const double double2) +{ + if (double1 <= double2) + return double1; + else + return double2; +} + + +int IMax(const int integer1, const int integer2) +{ + if (integer1 >= integer2) + return integer1; + else + return integer2; +} + + +int IMin(const int integer1, const int integer2) +{ + if (integer1 <= integer2) + return integer1; + else + return integer2; +} diff --git a/libs/dint/src/prepare.cpp b/libs/dint/src/prepare.cpp new file mode 100644 index 000000000..645cb4284 --- /dev/null +++ b/libs/dint/src/prepare.cpp @@ -0,0 +1,409 @@ + +#include +#include +#include +#include +#include "dint/const.h" +#include "dint/cvector.h" +#include "dint/utilities.h" +#include "dint/spectrum.h" +#include "dint/frag.h" +#include "dint/decay.h" + + +void SetEnergyBins(const int min_energy_exp, dCVector* pEnergy, + dCVector* pEnergyWidth) +{ + int i; + double exponent; + double temp; + int num_bins; + double averaging_factor; + double binning_factor; + + num_bins = pEnergy->dimension; + averaging_factor = (pow(10., 1./2./BINS_PER_DECADE) + + pow(10., -1./2./BINS_PER_DECADE))/2.; + binning_factor = pow(10., 1./2./BINS_PER_DECADE) - + pow(10., -1./2./BINS_PER_DECADE); + + if (num_bins != pEnergyWidth->dimension) + { + Error("SetEnergyBins: inconsistent dimensions", PROGRAM_ERROR); + } + + for (i = 0; i < num_bins; i++) + { + exponent = (double)min_energy_exp + (double)i/BINS_PER_DECADE; + temp = pow(10., exponent)/ELECTRON_MASS; + (pEnergy->vector)[i] = temp*averaging_factor; + (pEnergyWidth->vector)[i] = temp*binning_factor; + } +} + +void SetDeltaG(const dCVector* pEnergy, dCVector* pDeltaG) +{ + int i; + int num_main_bins; + + num_main_bins = pEnergy->dimension; + + if (pDeltaG->dimension != num_main_bins) + { + Error("SetDeltaG: inconsistent dimensions", PROGRAM_ERROR); + } + + for (i = 0; i < num_main_bins - 1; i++) + { + (pDeltaG->vector)[i] = (pEnergy->vector)[i+1] - (pEnergy->vector)[i]; + } + (pDeltaG->vector)[num_main_bins-1] = (pEnergy->vector)[num_main_bins-1]* + pow(10., 1./BINS_PER_DECADE); +} + +/* NOTE: this function is not used any more... */ +void GetModeOfInput(FILE* input, int* pInputMethodSwitch) +{ + /* give a choice between manually entering the data and reading it + from a data file */ + printf(" -----------------< Enter Model Parameters >"); + printf("-----------------\n\n"); + printf("1. Read from a file (1)/Manually enter parameters (0): "); + scanf("%i", pInputMethodSwitch); + + if (*pInputMethodSwitch == 1) + /* From data file */ + { + char fileName[20]; + + /* get the name of the file */ + printf("2. Name of parameter file: "); + scanf("%s", fileName); + input = SafeFOpen(fileName, "r"); + } +} + +void BasicParameterInput(FILE* input, const int argc, int* pMinEnergyExp, + int* pNumSmallSteps, + double* pConvergeParameter, + double* pStartingRedshift, + double* pStartingDistanceInMpc) +{ + if (argc == 3) + /* From data file */ + { + printf("\n[Parameters read from the file]\n"); + /* read in parameters */ + fscanf(input, "%i", pMinEnergyExp); + printf("1. Minimum energy: 10^%i eV\n", *pMinEnergyExp); + fscanf(input, "%i", pNumSmallSteps); + printf("2. Number of small steps: %i\n", *pNumSmallSteps); + fscanf(input, "%lf", pConvergeParameter); + printf("3. Delta (convergence parameter): %12.3E\n", + *pConvergeParameter); + fscanf(input, "%lf", pStartingRedshift); + if (*pStartingRedshift != 0.) + { + printf("4. Maximal redshift: %10.3f\n", *pStartingRedshift); + } + fscanf(input, "%lf", pStartingDistanceInMpc); + if (*pStartingDistanceInMpc >= 2.*C/3./H_0*1.e-5) + { + Error("BasicParameterInput: distance larger than horizon", + PROGRAM_ERROR); + } + if (*pStartingDistanceInMpc != 0.) + { + printf("4. Maximal distance (Mpc): %10.3f\n", + *pStartingDistanceInMpc); + } + } + else if (argc == 2) + /* Enter manually */ + { + printf("1. Minimum energy exponent (e.g. 10^8 eV: 8): "); + scanf("%i", pMinEnergyExp); + printf("2. Number of small steps (suggestion: 6): "); + scanf("%i", pNumSmallSteps); + printf("3. Delta (convergence parameter) (suggestion: 1.e-6): "); + scanf("%lf", pConvergeParameter); + printf("4. Maximal redshift "); + printf("(enter 0 if you will type in distance): "); + scanf("%lf", pStartingRedshift); + printf("5. Maximal distance in Mpc "); + printf("(enter 0 if you typed in redshift): "); + scanf("%lf", pStartingDistanceInMpc); + if (*pStartingDistanceInMpc >= 2.*C/3./H_0*1.e-5) + { + Error("BasicParameterInput: distance larger than horizon", + PROGRAM_ERROR); + } + } + + if (*pStartingDistanceInMpc == 0.) + { + *pStartingDistanceInMpc = 2.*C/3./H_0/1.e5*(1. - + pow(1. + *pStartingRedshift, -3./2.)); + printf("\n"); + printf("Maximal distance (Mpc): %12.6f\n", *pStartingDistanceInMpc); + } + if (*pStartingRedshift == 0.) + { + *pStartingRedshift = + pow(1. - 3.*H_0*1.e5*(*pStartingDistanceInMpc)/2./C, -2./3.) - 1.; + printf("\n"); + printf("Maximal redshift: %12.6f\n", *pStartingRedshift); + } +} + +void InteractionParameterInput(FILE* input, const int argc, + int* pSynchrotronSwitch, double* pB_0, + int* pTauNeutrinoMassSwitch, int* pICSSwitch, + int* pPPSwitch, int* pTPPSwitch, + int* pDPPSwitch, int* pPPPSwitch, + int* pNPPSwitch, int* pNeutronDecaySwitch, + int* pNucleonToSecondarySwitch, + int* pNeutrinoNeutrinoSwitch) +{ + if (argc == 3) + /* From data file */ + { + fscanf(input, "%i", pSynchrotronSwitch); + fscanf(input, "%lf", pB_0); + if (*pSynchrotronSwitch == 1) + { + printf("5. Synchrotron loss on -> B_0: %12.3E\n", *pB_0); + } + else + { + *pB_0 = 0; + printf("5. Synchrotron loss off\n"); + } + fscanf(input, "%i", pTauNeutrinoMassSwitch); + if (*pTauNeutrinoMassSwitch == 0) + printf("6. m_tau = m_e = m_nu = 1 eV\n"); + else + printf("6. m_tau = m_nu = 1 eV, m_e = 0.1 eV\n"); + + /* read in interaction switches */ + printf("\n7. "); + fscanf(input, "%i", pICSSwitch); + if (*pICSSwitch != 0) + printf("ICS on... "); + fscanf(input, "%i", pPPSwitch); + if (*pPPSwitch != 0) + printf("PP on... "); + fscanf(input, "%i", pTPPSwitch); + if (*pTPPSwitch != 0) + printf("TPP on... "); + fscanf(input, "%i", pDPPSwitch); + if (*pDPPSwitch != 0) + printf("DPP on... "); + fscanf(input, "%i", pPPPSwitch); + if (*pPPPSwitch != 0) + printf("Photopion production on... "); + fscanf(input, "%i", pNPPSwitch); + if (*pNPPSwitch != 0) + printf("Proton pair production on... "); + fscanf(input, "%i", pNeutronDecaySwitch); + if (*pNeutronDecaySwitch != 0) + printf("Neutron decay on... "); + fscanf(input, "%i", pNucleonToSecondarySwitch); + if (*pNucleonToSecondarySwitch != 0) + printf("Nucleon secondary tables included... "); + fscanf(input, "%i", pNeutrinoNeutrinoSwitch); + if (*pNeutrinoNeutrinoSwitch != 0) + printf("Neutrino-neutrino interaction on... "); + printf("\n"); + } + else if (argc == 2) + /* Enter manually */ + { + printf("6. Synchrotron on/off? (on = 1, off = 0) "); + scanf("%i", pSynchrotronSwitch); + if (*pSynchrotronSwitch == 1) + { + printf(" 6-1. Magnetic field (G): "); + scanf("%lf", pB_0); + } + else + { + *pB_0 = 0; + } + + printf("7. Neutrino mass (0: equally massive (1 eV), 1: tau = nu = 1, e = 0.1 eV): "); + scanf("%lf", pTauNeutrinoMassSwitch); + + // printf("\n\nNow turning to individual interactions...\n"); + printf("\n"); + printf("8-1. Inverse Compton scattering (ICS) on? (on = 1, off = 0) "); + scanf("%i", pICSSwitch); + printf("8-2. Pair production (PP) on? "); + scanf("%i", pPPSwitch); + printf("8-3. Triplet pair production (TPP) on? "); + scanf("%i", pTPPSwitch); + printf("8-4. Double pair production (DPP) on? "); + scanf("%i", pDPPSwitch); + printf("8-5. Photopion production on? "); + scanf("%i", pPPPSwitch); + printf("8-6. Proton pair production on? "); + scanf("%i", pNPPSwitch); + printf("8-7. Neutron decay on? "); + scanf("%i", pNeutronDecaySwitch); + printf("8-8. Nucleon secondary tables included? "); + scanf("%i", pNucleonToSecondarySwitch); + printf("8-9. Neutrino-neutrino interaction on? "); + scanf("%i", pNeutrinoNeutrinoSwitch); + } + + /* quick check whether secondary table switch is consistent */ + if (*pNucleonToSecondarySwitch == 1) + { + if ((*pPPPSwitch == 0) && (*pNPPSwitch == 0) && + (*pNeutronDecaySwitch == 0)) + { + printf("WARNING: secondary table on when all interactions off?\n"); + } + } +} + +void ModelParameterInput(FILE* input, const int argc, + int* pSourceTypeSwitch, double* pMinDistance, + double* pBrightPhaseExp, int* pModelTypeSwitch) +{ + if (argc == 3) + /* From data file */ + { + fscanf(input, "%i", pSourceTypeSwitch); + fscanf(input, "%lf", pMinDistance); + fscanf(input, "%lf", pBrightPhaseExp); + if (*pSourceTypeSwitch == 1) + { + printf("8. Source type: diffuse\n"); + printf("8-1. Minimal distance: %12.6f\n", *pMinDistance); + printf("8-2. Bright phase exponent: %12.6f\n", *pBrightPhaseExp); + } + else + printf("8. Source type: single\n"); + + fscanf(input, "%i", pModelTypeSwitch); + if (*pModelTypeSwitch == 0) + printf("9. Injection model: photon monoenergetic injection\n"); + else if (*pModelTypeSwitch == 1) + printf("9. Injection model: electron monoenergetic injection\n"); + else if (*pModelTypeSwitch == 2) + printf("9. Injection model: positron monoenergetic injection\n"); + } + else if (argc == 2) + /* Enter manually */ + { + printf("9. Single source or diffuse sources? "); + printf("(single = 0, diffuse = 1) "); + scanf("%i", pSourceTypeSwitch); + *pMinDistance = 0.; + *pBrightPhaseExp = 1.5; + if (*pSourceTypeSwitch == 1) + { + printf("9-1. Minimal distance: "); + scanf("%lf", pMinDistance); + printf("9-2. Bright phase exponent: "); + scanf("%lf", pBrightPhaseExp); + } + printf("10. Injection model\n"); + printf("(photon = 0, electron = 1,\n"); + printf(" positron = 2; monoenergetic injection ? "); + scanf("%i", pModelTypeSwitch); + } + + printf("\n\nParameter input complete.\n"); +} + +void PrepareSpectra(const int sourceTypeSwitch, const Spectrum* pQ_0, + Spectrum* pSpectrum, Spectrum* pSpectrumNew, + Spectrum* pDerivative) +{ + if (pSpectrumNew->numberOfMainBins != pDerivative->numberOfMainBins) + { + Error("PrepareSpectra: inconsistent dimensions", PROGRAM_ERROR); + } + + // InitializeSpectrum(spectrumOld); + if (sourceTypeSwitch == 0) /* single source */ + SetSpectrum(pSpectrum, pQ_0); + else /* diffuse sources */ + InitializeSpectrum(pSpectrum); + + SetSpectrum(pSpectrumNew, pSpectrum); + InitializeSpectrum(pDerivative); +} + + +void ComputeTotalInitialContent(const dCVector* pEnergy, const Spectrum* pQ_0, + double* initialPhotonEnergy, + double* initialLeptonEnergy, + double* initialNucleonEnergy, + double* initialNeutrinoEnergy, + double* initialTotalEnergy, + double* initialPhotonNumber, + double* initialLeptonNumber, + double* initialNucleonNumber, + double* initialNeutrinoNumber, + double* initialTotalNumber) +{ + int i; + + *initialPhotonEnergy = 0; + *initialLeptonEnergy = 0.; + *initialNucleonEnergy = 0.; + *initialNeutrinoEnergy = 0.; + *initialTotalEnergy = 0.; + *initialPhotonNumber = 0; + *initialLeptonNumber = 0.; + *initialNucleonNumber = 0.; + *initialNeutrinoNumber = 0.; + *initialTotalNumber = 0.; + + for (i = 0; i < pEnergy->dimension; i++) + { + *initialPhotonEnergy += (pQ_0->spectrum)[PHOTON][i]* + (pEnergy->vector)[i]; + *initialPhotonNumber += (pQ_0->spectrum)[PHOTON][i]; + *initialLeptonEnergy += ((pQ_0->spectrum)[ELECTRON][i] + + (pQ_0->spectrum)[POSITRON][i])*(pEnergy->vector)[i]; + *initialLeptonNumber += (pQ_0->spectrum)[ELECTRON][i] + + (pQ_0->spectrum)[POSITRON][i]; + } + *initialNucleonEnergy += GetNucleonEnergy(pQ_0, pEnergy); + *initialNucleonNumber += GetNucleonNumber(pQ_0); + *initialNeutrinoEnergy += GetNeutrinoEnergy(pQ_0, pEnergy); + *initialNeutrinoNumber += GetNeutrinoNumber(pQ_0); + *initialTotalEnergy = *initialPhotonEnergy + *initialLeptonEnergy + + *initialNucleonEnergy + *initialNeutrinoEnergy; + *initialTotalNumber = *initialPhotonNumber + *initialLeptonNumber + + *initialNucleonNumber + *initialNeutrinoNumber; +} + + +void ComputeContinuousEnergyLoss(const int synchrotronSwitch, + const dCVector* synchrotronLoss, + const dCVector* otherLoss, + dCVector* continuousLoss) +{ + int i; + + if ((synchrotronLoss->dimension != otherLoss->dimension) || + (otherLoss->dimension != continuousLoss->dimension)) + { + Error("ComputeContinuousEnergyLoss: inconsistent dimensions", + PROGRAM_ERROR); + } + + for (i = 0; i < continuousLoss->dimension; i++) + { + (continuousLoss->vector)[i] = (otherLoss->vector)[i]; + if (synchrotronSwitch == 1) /* synchrotron on */ + { + (continuousLoss->vector)[i] += (synchrotronLoss->vector)[i]; + } + } +} diff --git a/libs/dint/src/prop_second.cpp b/libs/dint/src/prop_second.cpp new file mode 100644 index 000000000..3e605cdf3 --- /dev/null +++ b/libs/dint/src/prop_second.cpp @@ -0,0 +1,1079 @@ + +#include "dint/prop_second.h" + +#ifdef DEBUG +void DumpEnergy(const Spectrum* pSpectrum, const dCVector* pEnergy) { + printf("Initial energy: %15.6E\n", GetEnergy(pSpectrum, pEnergy)); + printf("Nucleon fraction: %15.6E\n", + GetNucleonEnergy(pSpectrum, pEnergy)/GetEnergy(pSpectrum, pEnergy)); + printf("electromagnetic fraction: %15.6E\n", + GetEMEnergy(pSpectrum, pEnergy)/GetEnergy(pSpectrum, pEnergy)); +} +#endif + +//-------------------------------------------------------------------------- +// Prop_second : see the file prop_second.h for explanations +//-------------------------------------------------------------------------- + +// Switches to read 1) the folded interaction rates : total pair production and +// total energy losses by photons; 2) the photon background density +//#define EXTRACT_PAIR_PROD_RATE +//#define EXTRACT_PHOTON_TOTAL_RATE +//#define PRINT_PHOTON_BACKGROUND +//#define EXTRACT_LEPTON_RATE + +// Parameters of the redshift table (used for distance-redshift conversion) +#define NBINS_REDSHIFTTABLE 1000 +#define ZMIN_REDSHIFTTABLE 0.0001 +#define ZMAX_REDSHIFTTABLE 100 + +void prop_second(const double dist_observer, + //const double InjEnergy, + //const PARTICLE part, + //const double HInjEnergy, const double deltaE_hadron, + const dCVector* pB_field, + const dCVector* pEnergy, + const dCVector* pEnergyWidth, + Spectrum* apInjectionSpectrum, + Spectrum* pSpectrum, + string aDirTables, + const int aIRFlag, const double aZmax_IR, const int aRadioFlag, + const double aH0 = H_0, const double aOmegaM = OMEGA_M, + const double aOmegaLambda = OMEGA_LAMBDA, + const double aCutcascade_Magfield = 0) { +clock_t start = clock(); + //-------- Declaration of main variables -------- + //---- Interaction table coefficients ---- + RawTotalRate ICSTotalRate; + RawTotalRate PPTotalRate; + RawTotalRate TPPTotalRate; + RawTotalRate DPPRate; + + RawTotalRate PPPProtonLossRate; + RawTotalRate PPPNeutronLossRate; + RawTotalRate NPPTotalRate; + // total (interaction) rates before being folded into the background + + RawDiffRate ICSPhotonRate; + RawDiffRate ICSScatRate; + RawDiffRate PPDiffRate; + RawDiffRate TPPDiffRate; + + RawDiffRate PPPProtonScatRate; + RawDiffRate PPPProtonNeutronRate; + RawDiffRate PPPNeutronProtonRate; + RawDiffRate PPPProtonPhotonRate; + RawDiffRate PPPProtonElectronRate; + RawDiffRate PPPProtonPositronRate; + RawDiffRate PPPNeutronElectronRate; + RawDiffRate NPPDiffRate; + RawDiffRate PPPProtonElectronNeutrinoRate; + RawDiffRate PPPProtonAntiElectronNeutrinoRate; + RawDiffRate PPPProtonMuonNeutrinoRate; + RawDiffRate PPPProtonAntiMuonNeutrinoRate; + RawDiffRate PPPNeutronAntiElectronNeutrinoRate; + RawDiffRate PPPNeutronMuonNeutrinoRate; + RawDiffRate PPPNeutronAntiMuonNeutrinoRate; + // differential rates before being folded into the background + + TotalRate neutronDecayRate; + DiffRate neutronDecayElectronRate; + DiffRate neutronDecayProtonRate; + + TotalRate NNElNeutTotalRate; + TotalRate NNMuonNeutTotalRate; + TotalRate NNTauNeutTotalRate; + // These total rates are net rates; i.e. scattered flux into same bin is subtracted + DiffRate NNElNeutScatRate; + DiffRate NNElNeutMuonNeutRate; + DiffRate NNElNeutTauNeutRate; + DiffRate NNElNeutElectronRate; + DiffRate NNElNeutPhotonRate; + DiffRate NNElNeutProtonRate; + DiffRate NNMuonNeutScatRate; + DiffRate NNMuonNeutElNeutRate; + DiffRate NNMuonNeutTauNeutRate; + DiffRate NNMuonNeutElectronRate; + DiffRate NNMuonNeutPhotonRate; + DiffRate NNMuonNeutProtonRate; + DiffRate NNTauNeutScatRate; + DiffRate NNTauNeutElNeutRate; + DiffRate NNTauNeutMuonNeutRate; + DiffRate NNTauNeutElectronRate; + DiffRate NNTauNeutPhotonRate; + DiffRate NNTauNeutProtonRate; + // rates from neutrino-neutrino interaction + + + //---- Main parameter variables ---- + int B_bin, B_bins; // bin numbers for B-field array + + dCVector deltaG; // dg used in continuous energy loss calculation + + dCVector bgEnergy; + dCVector bgEnergyWidth; + dCVector bgPhotonDensity; + + double distance; // main distance variable (cm) + + int numSmallSteps; // number of small steps in one redshift step + double convergeParameter; // redshift increment + + int synchrotronSwitch; + double B_loc; // local strength of extragalactic magnetic field (gauss) + DiffRate syncRate; + + int sourceTypeSwitch; // source type: single (0) or diffuse (1) + double brightPhaseExp; // bright phase exponent + double startingRedshift; // zsource in FORTRAN + double minDistance; // minimal distance to sources + double bkgFactor; // local background enhancement factor + double totalEnergyInput; // einj0 in FORTRAN + + Spectrum Q_0; // standard injection function + Spectrum spectrumNew; + Spectrum derivative; + + double initialPhotonEnergy; // totpe in FORTRAN + double initialLeptonEnergy; // totee + double initialNucleonEnergy; + double initialNeutrinoEnergy; + double initialTotalEnergy; // tote + double initialPhotonNumber; // totpn + double initialLeptonNumber; // toten + double initialNucleonNumber; + double initialNeutrinoNumber; + double initialTotalNumber; // totn + + int iterationCounter; // niter in FORTRAN + int firstIndex; // ifirst + double leftRedshift; // zi + double deltaRedshift; //zdelt + int lastIndex; // ilast + double propagatingDistance; + // totalx: total propagating distance (pc) + double rightRedshift; // zf + double centralRedshift; // zt + double redshiftRatio; // erat + // double tempCoefficient; // coeff + double distanceStep; // tzdist*tdz (cm) + double rightDistance; // d1 (Mpc) + double leftDistance; // d2 (Mpc) + double evolutionFactor,evolutionFactor1; // zfact + double smallDistanceStep; // dx (pc) + double x; // x (pc) + + // Energy below which the 1D approximation is not a priori correct : + bool lEcFlag ; + int lIndex ; + double lEnergy, t_sync, t_larmor, t_ics = 0 ; + double a_ics = (3.-log10(4.))/4. ; + double b_ics = pow(10.,8.-7.*a_ics) ; + // (used if the flag aCutcascade_Magfield is set) + + // FILE* input; + int tauNeutrinoMassSwitch; + + // interaction switches + int ICSSwitch; + int PPSwitch; + int TPPSwitch; + int DPPSwitch; + + int PPPSwitch; + int NPPSwitch; + int neutronDecaySwitch; + int nucleonToSecondarySwitch; + + int neutrinoNeutrinoSwitch; + + //---- interaction rates folded with photon background ---- + TotalRate leptonTotalRate; + TotalRate photonTotalRate; + TotalRate protonTotalRate; + TotalRate neutronTotalRate; + + DiffRate leptonScatRate; + DiffRate leptonExchRate; + DiffRate leptonPhotonRate; + DiffRate photonLeptonRate; + + DiffRate protonScatRate; + DiffRate protonNeutronRate; + DiffRate neutronProtonRate; + DiffRate protonPhotonRate; + DiffRate protonElectronRate; + DiffRate protonPositronRate; + DiffRate neutronElectronRate; + DiffRate neutronPositronRate; + DiffRate protonElectronNeutrinoRate; + DiffRate protonAntiElectronNeutrinoRate; + DiffRate protonMuonNeutrinoRate; + DiffRate protonAntiMuonNeutrinoRate; + DiffRate neutronAntiElectronNeutrinoRate; + DiffRate neutronMuonNeutrinoRate; + DiffRate neutronAntiMuonNeutrinoRate; + + TotalRate elNeutTotalRate; + TotalRate muonNeutTotalRate; + TotalRate tauNeutTotalRate; + + DiffRate elNeutScatRate; + DiffRate elNeutMuonNeutRate; + DiffRate elNeutTauNeutRate; + DiffRate elNeutElectronRate; + DiffRate elNeutPhotonRate; + DiffRate elNeutProtonRate; + DiffRate muonNeutScatRate; + DiffRate muonNeutElNeutRate; + DiffRate muonNeutTauNeutRate; + DiffRate muonNeutElectronRate; + DiffRate muonNeutPhotonRate; + DiffRate muonNeutProtonRate; + DiffRate tauNeutScatRate; + DiffRate tauNeutElNeutRate; + DiffRate tauNeutMuonNeutRate; + DiffRate tauNeutElectronRate; + DiffRate tauNeutPhotonRate; + DiffRate tauNeutProtonRate; + // rates from neutrino-neutrino interaction + + dCVector synchrotronLoss; // sgdot + dCVector otherLoss; // tgdot + dCVector continuousLoss; // gdot + dCVector protonContinuousLoss; // pgdot + + int loopCounter; + //-------- End of variable declaration -------- + + // numSmallSteps = 100; + convergeParameter = 1.e-8; + + // -------- Redshift Estimation --------------- + // startingRedshift = pow(1. - 3.*H_0*1.e5*dist_observer/2./C, -2./3.) - 1.; + // This was the old analytic redshift computation. + dCVector RedshiftArray ; + dCVector DistanceArray ; + BuildRedshiftTable(aH0, aOmegaM, aOmegaLambda, &RedshiftArray, &DistanceArray) ; + startingRedshift = getRedshift(RedshiftArray, DistanceArray, dist_observer) ; + // printf("distance/Mpc: %15.6E\n", dist_observer); + // printf("particle type: %d\n", part); + // printf("injection energy/eV: %15.6E\n", InjEnergy); + + B_bins = pB_field->dimension; + + synchrotronSwitch = 1; + tauNeutrinoMassSwitch = 1; + ICSSwitch = 1; + PPSwitch = 1; + TPPSwitch = 1; + DPPSwitch = 1; + // PPPSwitch = 1; + PPPSwitch = 0; + NPPSwitch = 0; + // synchrotronSwitch = 0; + // tauNeutrinoMassSwitch = 0; + // ICSSwitch = 0; + // PPSwitch = 0; + // TPPSwitch = 0; + // DPPSwitch = 0; + // PPPSwitch = 1; + PPPSwitch = 0; + NPPSwitch = 0; + // printf("DINT modified!!\n"); +#ifdef EXTRACT_PAIR_PROD_RATE + NPPSwitch = 1; // (allows to compute new pair prod rate) +#endif + + // neutronDecaySwitch = 1; + neutronDecaySwitch = 0; + nucleonToSecondarySwitch = 0; + neutrinoNeutrinoSwitch = 1; + sourceTypeSwitch = 0; + minDistance = 0.; + brightPhaseExp = 0.; + + //-------- Set up energy bins -------- + New_dCVector(&deltaG, NUM_MAIN_BINS); + New_dCVector(&bgEnergy, NUM_BG_BINS); + New_dCVector(&bgEnergyWidth, NUM_BG_BINS); + New_dCVector(&bgPhotonDensity, NUM_BG_BINS); + + // set energy bins + SetDeltaG(pEnergy, &deltaG); + + SetEnergyBins(BG_MIN_ENERGY_EXP, &bgEnergy, &bgEnergyWidth); + + NewSpectrum(&Q_0, NUM_MAIN_BINS); + NewSpectrum(&spectrumNew, NUM_MAIN_BINS); + NewSpectrum(&derivative, NUM_MAIN_BINS); + + New_dCVector(&synchrotronLoss, NUM_MAIN_BINS); + New_dCVector(&otherLoss, NUM_MAIN_BINS); + New_dCVector(&continuousLoss, NUM_MAIN_BINS); + New_dCVector(&protonContinuousLoss, NUM_MAIN_BINS); + + + //---- Select injection model ---- + // SetInjectionSpectrum(part, InjEnergy, HInjEnergy, deltaE_hadron, + // pEnergy, pEnergyWidth, &Q_0); + // SetInjectionSpectrum(part, pEnergy, pEnergyWidth, &Q_0, InjEnergy); + + SetSpectrum(&Q_0, apInjectionSpectrum) ; + // No call anymore to SetInjectionSpectrum, which is not useful anymore. + totalEnergyInput = GetEnergy(&Q_0, pEnergy); +#ifdef DEBUG + DumpEnergy(&Q_0, pEnergy); +#endif + + //-------- Create arrays -------- + // NOTE: I first make them table size; they will be "clipped" after reading in tables + if (ICSSwitch == 1) { + NewRawTotalRate(&ICSTotalRate, EM_NUM_MAIN_BINS, NUM_BG_BINS); + NewRawDiffRate(&ICSPhotonRate, EM_NUM_MAIN_BINS, NUM_BG_BINS, + NUM_IP_ELEMENTS); + NewRawDiffRate(&ICSScatRate, EM_NUM_MAIN_BINS, NUM_BG_BINS, + NUM_IS_ELEMENTS); + } + + if (PPSwitch == 1) { + NewRawTotalRate(&PPTotalRate, EM_NUM_MAIN_BINS, NUM_BG_BINS); + NewRawDiffRate(&PPDiffRate, EM_NUM_MAIN_BINS, NUM_BG_BINS, + NUM_PP_ELEMENTS); + } + + if (TPPSwitch == 1) { + NewRawTotalRate(&TPPTotalRate, EM_NUM_MAIN_BINS, NUM_BG_BINS); + NewRawDiffRate(&TPPDiffRate, EM_NUM_MAIN_BINS, NUM_BG_BINS, + NUM_TPP_ELEMENTS); + } + + if (DPPSwitch == 1) + NewRawTotalRate(&DPPRate, EM_NUM_MAIN_BINS, NUM_BG_BINS); + + if (PPPSwitch == 1) { + NewRawTotalRate(&PPPProtonLossRate, NUC_NUM_MAIN_BINS, NUM_BG_BINS); + NewRawTotalRate(&PPPNeutronLossRate, NUC_NUM_MAIN_BINS, NUM_BG_BINS); + + NewRawDiffRate(&PPPProtonScatRate, NUC_NUM_MAIN_BINS, NUM_BG_BINS, + NUM_PPP_PROTON_SCAT_ELEMENTS); + NewRawDiffRate(&PPPProtonNeutronRate, NUC_NUM_MAIN_BINS, NUM_BG_BINS, + NUM_PPP_PROTON_NEUTRON_ELEMENTS); + NewRawDiffRate(&PPPNeutronProtonRate, NUC_NUM_MAIN_BINS, NUM_BG_BINS, + NUM_PPP_PROTON_NEUTRON_ELEMENTS); + + if (nucleonToSecondarySwitch == 1) { + NewRawDiffRate(&PPPProtonPhotonRate, NUC_NUM_MAIN_BINS, + NUM_BG_BINS, NUM_PPP_PROTON_PHOTON_ELEMENTS); + NewRawDiffRate(&PPPProtonElectronRate, NUC_NUM_MAIN_BINS, + NUM_BG_BINS, NUM_PPP_PROTON_ELECTRON_ELEMENTS); + NewRawDiffRate(&PPPProtonPositronRate, NUC_NUM_MAIN_BINS, + NUM_BG_BINS, NUM_PPP_PROTON_POSITRON_ELEMENTS); + NewRawDiffRate(&PPPNeutronElectronRate, NUC_NUM_MAIN_BINS, + NUM_BG_BINS, NUM_PPP_PROTON_POSITRON_ELEMENTS); + NewRawDiffRate(&PPPProtonElectronNeutrinoRate, NUC_NUM_MAIN_BINS, + NUM_BG_BINS, NUM_PPP_PROTON_ANTI_MUON_NEUTRINO_ELEMENTS); + NewRawDiffRate(&PPPProtonAntiElectronNeutrinoRate, + NUC_NUM_MAIN_BINS, NUM_BG_BINS, + NUM_PPP_PROTON_ANTI_ELECTRON_NEUTRINO_ELEMENTS); + NewRawDiffRate(&PPPProtonMuonNeutrinoRate, NUC_NUM_MAIN_BINS, + NUM_BG_BINS, NUM_PPP_PROTON_MUON_NEUTRINO_ELEMENTS); + NewRawDiffRate(&PPPProtonAntiMuonNeutrinoRate, NUC_NUM_MAIN_BINS, + NUM_BG_BINS, NUM_PPP_PROTON_ANTI_MUON_NEUTRINO_ELEMENTS); + NewRawDiffRate(&PPPNeutronAntiElectronNeutrinoRate, + NUC_NUM_MAIN_BINS, NUM_BG_BINS, + NUM_PPP_PROTON_ANTI_MUON_NEUTRINO_ELEMENTS); + NewRawDiffRate(&PPPNeutronMuonNeutrinoRate, NUC_NUM_MAIN_BINS, + NUM_BG_BINS, NUM_PPP_PROTON_ANTI_MUON_NEUTRINO_ELEMENTS); + NewRawDiffRate(&PPPNeutronAntiMuonNeutrinoRate, NUC_NUM_MAIN_BINS, + NUM_BG_BINS, NUM_PPP_PROTON_MUON_NEUTRINO_ELEMENTS); + } + } + + if (NPPSwitch == 1) { + NewRawTotalRate(&NPPTotalRate, NUC_NUM_MAIN_BINS, NUM_BG_BINS); + + if (nucleonToSecondarySwitch == 1) + NewRawDiffRate(&NPPDiffRate, NUC_NUM_MAIN_BINS, NUM_BG_BINS, + NUM_NPP_ELEMENTS); + } + + // neutron decay does not fit the general category because it is not + // really an interaction (with background) + if (neutronDecaySwitch == 1) { + NewTotalRate(&neutronDecayRate, NUC_NUM_MAIN_BINS); + NewDiffRate(&neutronDecayProtonRate, NUC_NUM_MAIN_BINS); + + if (nucleonToSecondarySwitch == 1) + NewDiffRate(&neutronDecayElectronRate, NUC_NUM_MAIN_BINS); + } + + // neutrino-neutrino rates are already folded w/ neutrino background + if (neutrinoNeutrinoSwitch == 1) { + NewTotalRate(&NNElNeutTotalRate, NEUT_NUM_MAIN_BINS); + NewTotalRate(&NNMuonNeutTotalRate, NEUT_NUM_MAIN_BINS); + NewTotalRate(&NNTauNeutTotalRate, NEUT_NUM_MAIN_BINS); + + NewDiffRate(&NNElNeutScatRate, NEUT_NUM_MAIN_BINS); + NewDiffRate(&NNElNeutMuonNeutRate, NEUT_NUM_MAIN_BINS); + NewDiffRate(&NNElNeutTauNeutRate, NEUT_NUM_MAIN_BINS); + NewDiffRate(&NNElNeutElectronRate, NEUT_NUM_MAIN_BINS); + NewDiffRate(&NNElNeutPhotonRate, NEUT_NUM_MAIN_BINS); + NewDiffRate(&NNElNeutProtonRate, NEUT_NUM_MAIN_BINS); + NewDiffRate(&NNMuonNeutScatRate, NEUT_NUM_MAIN_BINS); + NewDiffRate(&NNMuonNeutElNeutRate, NEUT_NUM_MAIN_BINS); + NewDiffRate(&NNMuonNeutTauNeutRate, NEUT_NUM_MAIN_BINS); + NewDiffRate(&NNMuonNeutElectronRate, NEUT_NUM_MAIN_BINS); + NewDiffRate(&NNMuonNeutPhotonRate, NEUT_NUM_MAIN_BINS); + NewDiffRate(&NNMuonNeutProtonRate, NEUT_NUM_MAIN_BINS); + NewDiffRate(&NNTauNeutScatRate, NEUT_NUM_MAIN_BINS); + NewDiffRate(&NNTauNeutElNeutRate, NEUT_NUM_MAIN_BINS); + NewDiffRate(&NNTauNeutMuonNeutRate, NEUT_NUM_MAIN_BINS); + NewDiffRate(&NNTauNeutElectronRate, NEUT_NUM_MAIN_BINS); + NewDiffRate(&NNTauNeutPhotonRate, NEUT_NUM_MAIN_BINS); + NewDiffRate(&NNTauNeutProtonRate, NEUT_NUM_MAIN_BINS); + } + + //---- read in coefficient tables; clipping is done here if necessary ---- + if (ICSSwitch == 1) + LoadICSTables(&ICSTotalRate, &ICSPhotonRate, &ICSScatRate, + NUM_MAIN_BINS, aDirTables); + if (PPSwitch == 1) + LoadPPTables(&PPTotalRate, &PPDiffRate, NUM_MAIN_BINS, aDirTables); + if (TPPSwitch == 1) + LoadTPPTables(&TPPTotalRate, &TPPDiffRate, NUM_MAIN_BINS, aDirTables); + if (DPPSwitch == 1) + LoadDPPTables(&DPPRate, NUM_MAIN_BINS, aDirTables); + if (PPPSwitch == 1) { + LoadPPPNucleonTables(&PPPProtonLossRate, &PPPNeutronLossRate, + &PPPProtonScatRate, &PPPProtonNeutronRate, &PPPNeutronProtonRate, + NUM_MAIN_BINS, aDirTables); + + if (nucleonToSecondarySwitch == 1) { + LoadPPPEMTables(&PPPProtonPhotonRate, &PPPProtonElectronRate, + &PPPProtonPositronRate, &PPPNeutronElectronRate, + NUM_MAIN_BINS, aDirTables); + LoadPPPNeutrinoTables(&PPPProtonElectronNeutrinoRate, + &PPPProtonAntiElectronNeutrinoRate, &PPPProtonMuonNeutrinoRate, + &PPPProtonAntiMuonNeutrinoRate, + &PPPNeutronAntiElectronNeutrinoRate, + &PPPNeutronMuonNeutrinoRate, &PPPNeutronAntiMuonNeutrinoRate, + NUM_MAIN_BINS, aDirTables); + } + } + if (NPPSwitch == 1) { + LoadNPPNucleonTables(&NPPTotalRate, NUM_MAIN_BINS, aDirTables); + + if (nucleonToSecondarySwitch == 1) + LoadNPPSecondaryTables(&NPPDiffRate, NUM_MAIN_BINS, aDirTables); + } + + if (neutronDecaySwitch == 1) { + LoadNeutronDecayNucleonTables(&neutronDecayRate, + &neutronDecayProtonRate, NUM_MAIN_BINS, aDirTables); + + if (nucleonToSecondarySwitch == 1) + LoadNeutronDecaySecondaryTables(&neutronDecayElectronRate, + NUM_MAIN_BINS, aDirTables); + } + + if (neutrinoNeutrinoSwitch == 1) + LoadNeutrinoTables(tauNeutrinoMassSwitch, &NNElNeutTotalRate, + &NNMuonNeutTotalRate, &NNTauNeutTotalRate, &NNElNeutScatRate, + &NNElNeutMuonNeutRate, &NNElNeutTauNeutRate, + &NNElNeutElectronRate, &NNElNeutPhotonRate, &NNElNeutProtonRate, + &NNMuonNeutScatRate, &NNMuonNeutElNeutRate, + &NNMuonNeutTauNeutRate, &NNMuonNeutElectronRate, + &NNMuonNeutPhotonRate, &NNMuonNeutProtonRate, &NNTauNeutScatRate, + &NNTauNeutElNeutRate, &NNTauNeutMuonNeutRate, + &NNTauNeutElectronRate, &NNTauNeutPhotonRate, + &NNTauNeutProtonRate, NUM_MAIN_BINS, aDirTables); + +#ifdef DEBUG + printf("Starting computations...\n\n"); +#endif + +clock_t start_comp = clock(); + + //---- Initialize distance ---- + distance = 0.; // distance variable: dist in FORTRAN + + PrepareSpectra(sourceTypeSwitch, &Q_0, pSpectrum, &spectrumNew, + &derivative); + // NOTE: suspect derivative is never used??? + + // if (sourceTypeSwitch == 0) // single source + // DumpSpectrum(pEnergy, pEnergyWidth, &Q_0, "InitialSpectrumDump.dat"); + + ComputeTotalInitialContent(pEnergy, &Q_0, &initialPhotonEnergy, + &initialLeptonEnergy, &initialNucleonEnergy, + &initialNeutrinoEnergy, &initialTotalEnergy, + &initialPhotonNumber, &initialLeptonNumber, + &initialNucleonNumber, &initialNeutrinoNumber, + &initialTotalNumber); + + //--------- START of actual computation -------- + //---- initialize indices and parameters ---- + iterationCounter = 1; + firstIndex = 0; + leftRedshift = startingRedshift; + deltaRedshift = 1. - (pEnergy->vector)[2]/(pEnergy->vector)[3]; + lastIndex = 0; + propagatingDistance = 0.; + + + NewTotalRate(&leptonTotalRate, NUM_MAIN_BINS); + NewTotalRate(&photonTotalRate, NUM_MAIN_BINS); + + NewTotalRate(&protonTotalRate, NUM_MAIN_BINS); + NewTotalRate(&neutronTotalRate, NUM_MAIN_BINS); + + + NewDiffRate(&leptonScatRate, NUM_MAIN_BINS); + NewDiffRate(&leptonExchRate, NUM_MAIN_BINS); + NewDiffRate(&leptonPhotonRate, NUM_MAIN_BINS); + NewDiffRate(&photonLeptonRate, NUM_MAIN_BINS); + + NewDiffRate(&protonScatRate, NUM_MAIN_BINS); + NewDiffRate(&protonNeutronRate, NUM_MAIN_BINS); + NewDiffRate(&neutronProtonRate, NUM_MAIN_BINS); + NewDiffRate(&protonPhotonRate, NUM_MAIN_BINS); + NewDiffRate(&protonElectronRate, NUM_MAIN_BINS); + NewDiffRate(&protonPositronRate, NUM_MAIN_BINS); + NewDiffRate(&neutronElectronRate, NUM_MAIN_BINS); + NewDiffRate(&neutronPositronRate, NUM_MAIN_BINS); + NewDiffRate(&protonElectronNeutrinoRate, NUM_MAIN_BINS); + NewDiffRate(&protonAntiElectronNeutrinoRate, NUM_MAIN_BINS); + NewDiffRate(&protonMuonNeutrinoRate, NUM_MAIN_BINS); + NewDiffRate(&protonAntiMuonNeutrinoRate, NUM_MAIN_BINS); + NewDiffRate(&neutronAntiElectronNeutrinoRate, NUM_MAIN_BINS); + NewDiffRate(&neutronMuonNeutrinoRate, NUM_MAIN_BINS); + NewDiffRate(&neutronAntiMuonNeutrinoRate, NUM_MAIN_BINS); + + + NewTotalRate(&elNeutTotalRate, NUM_MAIN_BINS); + NewTotalRate(&muonNeutTotalRate, NUM_MAIN_BINS); + NewTotalRate(&tauNeutTotalRate, NUM_MAIN_BINS); + + NewDiffRate(&elNeutScatRate, NUM_MAIN_BINS); + NewDiffRate(&elNeutMuonNeutRate, NUM_MAIN_BINS); + NewDiffRate(&elNeutTauNeutRate, NUM_MAIN_BINS); + NewDiffRate(&elNeutElectronRate, NUM_MAIN_BINS); + NewDiffRate(&elNeutPhotonRate, NUM_MAIN_BINS); + NewDiffRate(&elNeutProtonRate, NUM_MAIN_BINS); + NewDiffRate(&muonNeutElNeutRate, NUM_MAIN_BINS); + NewDiffRate(&muonNeutScatRate, NUM_MAIN_BINS); + NewDiffRate(&muonNeutTauNeutRate, NUM_MAIN_BINS); + NewDiffRate(&muonNeutElectronRate, NUM_MAIN_BINS); + NewDiffRate(&muonNeutPhotonRate, NUM_MAIN_BINS); + NewDiffRate(&muonNeutProtonRate, NUM_MAIN_BINS); + NewDiffRate(&tauNeutElNeutRate, NUM_MAIN_BINS); + NewDiffRate(&tauNeutMuonNeutRate, NUM_MAIN_BINS); + NewDiffRate(&tauNeutScatRate, NUM_MAIN_BINS); + NewDiffRate(&tauNeutElectronRate, NUM_MAIN_BINS); + NewDiffRate(&tauNeutPhotonRate, NUM_MAIN_BINS); + NewDiffRate(&tauNeutProtonRate, NUM_MAIN_BINS); + /* I created all folded rates because I didn't want to pass all the + switches to the subsequent functions, and these allocations are + not so expensive anyway */ + + //-------- This is where propagation takes place -------- + do { + + // this firstIndex & lastIndex pair is used to bin redshift finer + // near the end of propagation (z close to 0) + ComputeRedshifts(sourceTypeSwitch, leftRedshift, &deltaRedshift, + &rightRedshift, ¢ralRedshift, &lastIndex); + + //---- compute various distance parameters ---- + redshiftRatio = (1. + rightRedshift)/(1. + leftRedshift); + // tempCoefficient = pow(OMEGA_M*pow(1. + centralRedshift,3.)+ + // OMEGA_LAMBDA, -1./2.)/(1.+centralRedshift); + // tempCoefficient = pow(1. + centralRedshift, -5./2.); + // distanceStep = (leftRedshift - rightRedshift)*tempCoefficient*C/ + // (H_0*1.e5/1.e6/DISTANCE_UNIT); + + // (cosmological parameters added July 2005) + leftDistance = getDistance(RedshiftArray,DistanceArray,leftRedshift) ; + rightDistance = getDistance(RedshiftArray,DistanceArray,rightRedshift) ; + distanceStep = leftDistance - rightDistance ; + distance += distanceStep; + // rightDistance = distance - distanceStep/2.; + // leftDistance = distance + distanceStep/2.; + // rightDistance = 2./3.*C/1.e5/H_0*(1. - pow(1. + rightRedshift, -1.5)); + // leftDistance = 2./3.*C/1.e5/H_0*(1. - pow(1. + leftRedshift, -1.5)); + + evolutionFactor1 = pow((1. + centralRedshift)/(1. + startingRedshift), + brightPhaseExp+3.); // redshift evolution + numSmallSteps = (int)(ceil(distanceStep/DISTANCE_UNIT/DMAX)); + smallDistanceStep = distanceStep/DISTANCE_UNIT/numSmallSteps; + x = 0.; + // printf("small stepsize: %15.6E\n", smallDistanceStep); + + //---- compute the photon background at given redshift ---- + LoadPhotonBackground(centralRedshift, &bgEnergy, &bgEnergyWidth, + &bgPhotonDensity, aIRFlag, aZmax_IR, aRadioFlag, + aH0, aOmegaM, aOmegaLambda); + + // if (rightRedshift < 1.e-5) + // DumpBgSpectrum(&bgEnergy, &bgEnergyWidth, &bgPhotonDensity,"~/"); + + //---- initialize rates ---- + InitializeLeptonCoefficients(&leptonTotalRate, &leptonScatRate, + &leptonExchRate, &leptonPhotonRate); + InitializePhotonCoefficients(&photonTotalRate, &photonLeptonRate); + InitializeNucleonCoefficients(&protonTotalRate, &neutronTotalRate, + &protonScatRate, &protonNeutronRate, + &neutronProtonRate, &protonPhotonRate, + &protonElectronRate, &protonPositronRate, + &neutronElectronRate, &neutronPositronRate, + &protonElectronNeutrinoRate, + &protonAntiElectronNeutrinoRate, + &protonMuonNeutrinoRate, &protonAntiMuonNeutrinoRate, + &neutronAntiElectronNeutrinoRate, &neutronMuonNeutrinoRate, + &neutronAntiMuonNeutrinoRate); + InitializeNeutrinoCoefficients(&elNeutTotalRate, &muonNeutTotalRate, + &tauNeutTotalRate, &elNeutScatRate, &elNeutMuonNeutRate, + &elNeutTauNeutRate, &elNeutElectronRate, + &elNeutPhotonRate, &elNeutProtonRate, + &muonNeutElNeutRate, &muonNeutScatRate, + &muonNeutTauNeutRate, &muonNeutElectronRate, + &muonNeutPhotonRate, &muonNeutProtonRate, + &tauNeutElNeutRate, &tauNeutMuonNeutRate, + &tauNeutScatRate, &tauNeutElectronRate, + &tauNeutPhotonRate, &tauNeutProtonRate); + + Initialize_dCVector(&continuousLoss); + + Initialize_dCVector(&otherLoss); + Initialize_dCVector(&protonContinuousLoss); + + //---- fold interaction rates w/ photon background ---- + if (ICSSwitch == 1) + FoldICS(&bgPhotonDensity, &ICSTotalRate, &ICSPhotonRate, + &ICSScatRate, &leptonTotalRate, &leptonPhotonRate, + &leptonScatRate); + if (TPPSwitch == 1) + FoldTPP(&bgPhotonDensity, pEnergy, &TPPTotalRate, &TPPDiffRate, + &leptonTotalRate, &leptonScatRate, &leptonExchRate, + &otherLoss); + if (PPSwitch == 1) + FoldPP(&bgPhotonDensity, &PPTotalRate, &PPDiffRate, + &photonTotalRate, &photonLeptonRate); + if (DPPSwitch == 1) + FoldDPP(&bgPhotonDensity, &DPPRate, &photonTotalRate, + &photonLeptonRate); + if (PPPSwitch == 1) { + FoldPPPNucleon(&bgPhotonDensity, &PPPProtonLossRate, + &PPPNeutronLossRate, &PPPProtonScatRate, &PPPProtonNeutronRate, + &PPPNeutronProtonRate, &protonTotalRate, &neutronTotalRate, + &protonScatRate, &protonNeutronRate, &neutronProtonRate); + + if (nucleonToSecondarySwitch == 1) + FoldPPPSecondary(&bgPhotonDensity, &PPPProtonPhotonRate, + &PPPProtonElectronRate, &PPPProtonPositronRate, + &PPPNeutronElectronRate, &PPPProtonElectronNeutrinoRate, + &PPPProtonAntiElectronNeutrinoRate, + &PPPProtonMuonNeutrinoRate, &PPPProtonAntiMuonNeutrinoRate, + &PPPNeutronAntiElectronNeutrinoRate, + &PPPNeutronMuonNeutrinoRate, + &PPPNeutronAntiMuonNeutrinoRate, &protonPhotonRate, + &protonElectronRate, &protonPositronRate, + &neutronElectronRate, &neutronPositronRate, + &protonElectronNeutrinoRate, + &protonAntiElectronNeutrinoRate, + &protonMuonNeutrinoRate, &protonAntiMuonNeutrinoRate, + &neutronAntiElectronNeutrinoRate, &neutronMuonNeutrinoRate, + &neutronAntiMuonNeutrinoRate); + } + + +#ifdef EXTRACT_PHOTON_TOTAL_RATE + // Add - E.A. Dec. 2005 + // Extract photon total energy loss rate + for (int i=0; idimension; i++) cout << (pEnergy->vector)[i] << " " + << (photonTotalRate.totalRate)[i] + << endl; + exit(0) ; +#endif +#ifdef EXTRACT_LEPTON_RATE + for (int i=0; idimension; i++) cout << (pEnergy->vector)[i] << " " + << (leptonTotalRate.totalRate)[i] + << endl; + exit(0) ; +#endif + + if (NPPSwitch == 1) { + + FoldNPPNucleon(&bgPhotonDensity, pEnergy, &NPPTotalRate, + &protonContinuousLoss); + +#ifdef EXTRACT_PAIR_PROD_RATE + // Slight add - E.A. July 2005 . + // To extract the pair production tables of protons on photon backgrounds. + // (need to switch NPPSwitch!) + for (int i=0; idimension; i++) cout << (pEnergy->vector)[i] << " " + << (protonContinuousLoss.vector)[i] + << endl; + exit(0) ; +#endif + + if (nucleonToSecondarySwitch == 1) + FoldNPPSecondary(&bgPhotonDensity, &NPPDiffRate, + &protonPositronRate, &protonElectronRate); + } + + if (neutrinoNeutrinoSwitch == 1) + MapNeutRates(centralRedshift, lastIndex, tauNeutrinoMassSwitch, + &NNElNeutTotalRate, &NNMuonNeutTotalRate, &NNTauNeutTotalRate, + &NNElNeutScatRate, &NNElNeutMuonNeutRate, + &NNElNeutTauNeutRate, &NNElNeutElectronRate, + &NNElNeutPhotonRate, &NNElNeutProtonRate, + &NNMuonNeutElNeutRate, &NNMuonNeutScatRate, + &NNMuonNeutTauNeutRate, &NNMuonNeutElectronRate, + &NNMuonNeutPhotonRate, &NNMuonNeutProtonRate, + &NNTauNeutElNeutRate, &NNTauNeutMuonNeutRate, + &NNTauNeutScatRate, &NNTauNeutElectronRate, + &NNTauNeutPhotonRate, &NNTauNeutProtonRate, &elNeutTotalRate, + &muonNeutTotalRate, &tauNeutTotalRate, &elNeutScatRate, + &elNeutMuonNeutRate, &elNeutTauNeutRate, &elNeutElectronRate, + &elNeutPhotonRate, &elNeutProtonRate, &muonNeutElNeutRate, + &muonNeutScatRate, &muonNeutTauNeutRate, &muonNeutElectronRate, + &muonNeutPhotonRate, &muonNeutProtonRate, &tauNeutElNeutRate, + &tauNeutMuonNeutRate, &tauNeutScatRate, &tauNeutElectronRate, + &tauNeutPhotonRate, &tauNeutProtonRate); + + //---- main iteration (convergence) block ---- + + for (loopCounter = 0; loopCounter < numSmallSteps; loopCounter++) { + + if (synchrotronSwitch == 1) { // synchrotron == true (on) + + NewDiffRate(&syncRate, NUM_MAIN_BINS); + + B_bin = (int)((double)(B_bins)*(propagatingDistance+x)/1.e6/ + dist_observer); + B_loc=(pB_field->vector)[B_bin]; + InitializeSynchrotron(B_loc, pEnergy, pEnergyWidth, + &synchrotronLoss, &syncRate, + aDirTables); + } + //---- compute continuous energy loss for electrons ---- + ComputeContinuousEnergyLoss(synchrotronSwitch, &synchrotronLoss, + &otherLoss, &continuousLoss); + + evolutionFactor = evolutionFactor1; + if ((leftDistance - x/1.e6) < minDistance) + evolutionFactor = 0.; + if ((leftDistance - x/1.e6) < SOURCE_CLUSTER_DISTANCE) + evolutionFactor = SOURCE_CLUSTER_FACTOR*evolutionFactor1; + if ((leftDistance - x/1.e6) < CLUSTER_DISTANCE) + bkgFactor = CLUSTER_FACTOR; + else + bkgFactor = 1.; + + AdvanceNucNeutStep(sourceTypeSwitch, PPPSwitch, NPPSwitch, + neutronDecaySwitch, nucleonToSecondarySwitch, + neutrinoNeutrinoSwitch, smallDistanceStep, + evolutionFactor, convergeParameter, bkgFactor, &Q_0, + &elNeutProtonRate, + &muonNeutProtonRate, &tauNeutProtonRate, &protonTotalRate, + &neutronTotalRate, &neutronDecayRate, &protonScatRate, + &protonNeutronRate, &neutronProtonRate, + &neutronDecayProtonRate, &protonMuonNeutrinoRate, + &neutronAntiMuonNeutrinoRate, &protonAntiMuonNeutrinoRate, + &neutronMuonNeutrinoRate, &protonElectronNeutrinoRate, + &neutronAntiElectronNeutrinoRate, + &protonAntiElectronNeutrinoRate, &neutronDecayElectronRate, + &elNeutTotalRate, &muonNeutTotalRate, &tauNeutTotalRate, + &elNeutScatRate, &elNeutMuonNeutRate, &elNeutTauNeutRate, + &muonNeutElNeutRate, &muonNeutScatRate, &muonNeutTauNeutRate, + &tauNeutElNeutRate, &tauNeutMuonNeutRate, &tauNeutScatRate, + &protonContinuousLoss, &deltaG, pSpectrum, &spectrumNew); + + SetNucleonSpectrum(pSpectrum, &spectrumNew); + SetNeutrinoSpectrum(pSpectrum, &spectrumNew); + + AdvanceEMStep(sourceTypeSwitch, PPSwitch, ICSSwitch, + TPPSwitch, DPPSwitch, synchrotronSwitch, PPPSwitch, + NPPSwitch, neutronDecaySwitch, nucleonToSecondarySwitch, + neutrinoNeutrinoSwitch, smallDistanceStep, evolutionFactor, + convergeParameter, bkgFactor, &Q_0, &photonLeptonRate, + &protonElectronRate, &neutronPositronRate, + &protonPositronRate, &neutronElectronRate, + &neutronDecayElectronRate, &elNeutElectronRate, + &muonNeutElectronRate, &tauNeutElectronRate, + &protonPhotonRate, &elNeutPhotonRate, &muonNeutPhotonRate, + &tauNeutPhotonRate, &leptonTotalRate, &leptonScatRate, + &leptonExchRate, &continuousLoss, &deltaG, &photonTotalRate, + &leptonPhotonRate, &syncRate, pSpectrum, &spectrumNew); + + SetEMSpectrum(pSpectrum, &spectrumNew); + // update spectrum + + if (aCutcascade_Magfield != 0 && B_loc != 0 ) { + // Estimate the effect of B field on the 1D approximation (added E.A. June 2006) + lEcFlag = 0 ; + lIndex = 0; + while (!lEcFlag) { + lEnergy = (pEnergy->vector)[lIndex] ; + // Time scales are computed in parsec + t_sync = 3.84e6/(lEnergy*B_loc*B_loc*ELECTRON_MASS) ; + t_larmor = (1.1e-21)*ELECTRON_MASS*lEnergy/(B_loc*aCutcascade_Magfield) ; + if (lEnergy <= 1.e15/ELECTRON_MASS) { + t_ics = 4.e2*1.e15/(ELECTRON_MASS*lEnergy) ; + } else if (lEnergy <= 1.e18/ELECTRON_MASS) { + t_ics = 4.e2*lEnergy*ELECTRON_MASS/1.e15 ; + } else if (lEnergy <= 1.e22/ELECTRON_MASS) { + t_ics = b_ics*pow(lEnergy*ELECTRON_MASS/1.e15,a_ics) ; + } else t_ics = 1.e8*lEnergy*ELECTRON_MASS/1.e22 ; + if (t_larmor >= t_sync || t_larmor >= t_ics) lEcFlag = 1 ; + // defines the "critical" energy : the e+/- spectrum is set to 0 for Espectrum)[ELECTRON][lIndex]=0 ; + (pSpectrum->spectrum)[POSITRON][lIndex]=0 ; + lIndex++ ; + } + } + + if (synchrotronSwitch == 1) // synchrotron == true (on) + DeleteDiffRate(&syncRate); + + x += smallDistanceStep; + iterationCounter++; + } + + + propagatingDistance += x; // increment distance + + //---- redshift bins down ---- + RedshiftDown(lastIndex, redshiftRatio, pEnergy, pSpectrum, + &spectrumNew); + + // printf("\nz = %g -> %g", leftRedshift, rightRedshift); + // printf("; d/Mpc = %g -> %g:\n", leftDistance, rightDistance); + // printf("%g, %g:\n", propagatingDistance, distance); + CheckEnergy(sourceTypeSwitch, brightPhaseExp, startingRedshift, + rightRedshift, pSpectrum, pEnergy, initialTotalEnergy); + + //---- prepare for new step ---- + leftRedshift = rightRedshift; + } while (lastIndex != 1); + +clock_t end_comp = clock(); + + //---- I am done with the rates ---- + DeleteDiffRate(&leptonScatRate); + DeleteDiffRate(&leptonExchRate); + DeleteDiffRate(&leptonPhotonRate); + DeleteDiffRate(&photonLeptonRate); + DeleteDiffRate(&protonScatRate); + DeleteDiffRate(&protonNeutronRate); + DeleteDiffRate(&neutronProtonRate); + DeleteDiffRate(&protonPhotonRate); + DeleteDiffRate(&protonElectronRate); + DeleteDiffRate(&protonPositronRate); + DeleteDiffRate(&neutronElectronRate); + DeleteDiffRate(&neutronPositronRate); + DeleteDiffRate(&protonElectronNeutrinoRate); + DeleteDiffRate(&protonAntiElectronNeutrinoRate); + DeleteDiffRate(&protonMuonNeutrinoRate); + DeleteDiffRate(&protonAntiMuonNeutrinoRate); + DeleteDiffRate(&neutronAntiElectronNeutrinoRate); + DeleteDiffRate(&neutronMuonNeutrinoRate); + DeleteDiffRate(&neutronAntiMuonNeutrinoRate); + + DeleteDiffRate(&elNeutScatRate); + DeleteDiffRate(&elNeutMuonNeutRate); + DeleteDiffRate(&elNeutTauNeutRate); + DeleteDiffRate(&elNeutElectronRate); + DeleteDiffRate(&elNeutPhotonRate); + DeleteDiffRate(&elNeutProtonRate); + DeleteDiffRate(&muonNeutElNeutRate); + DeleteDiffRate(&muonNeutScatRate); + DeleteDiffRate(&muonNeutTauNeutRate); + DeleteDiffRate(&muonNeutElectronRate); + DeleteDiffRate(&muonNeutPhotonRate); + DeleteDiffRate(&muonNeutProtonRate); + DeleteDiffRate(&tauNeutElNeutRate); + DeleteDiffRate(&tauNeutMuonNeutRate); + DeleteDiffRate(&tauNeutScatRate); + DeleteDiffRate(&tauNeutElectronRate); + DeleteDiffRate(&tauNeutPhotonRate); + DeleteDiffRate(&tauNeutProtonRate); + + DeleteTotalRate(&leptonTotalRate); + DeleteTotalRate(&photonTotalRate); + DeleteTotalRate(&protonTotalRate); + DeleteTotalRate(&neutronTotalRate); + DeleteTotalRate(&elNeutTotalRate); + DeleteTotalRate(&muonNeutTotalRate); + DeleteTotalRate(&tauNeutTotalRate); + + + if (ICSSwitch == 1) { + DeleteRawDiffRate(&ICSPhotonRate); + DeleteRawDiffRate(&ICSScatRate); + DeleteRawTotalRate(&ICSTotalRate); + } + if (PPSwitch == 1) { + DeleteRawDiffRate(&PPDiffRate); + DeleteRawTotalRate(&PPTotalRate); + } + if (TPPSwitch == 1) { + DeleteRawDiffRate(&TPPDiffRate); + DeleteRawTotalRate(&TPPTotalRate); + } + if (PPPSwitch == 1) { + DeleteRawDiffRate(&PPPProtonScatRate); + DeleteRawDiffRate(&PPPProtonNeutronRate); + DeleteRawDiffRate(&PPPNeutronProtonRate); + + DeleteRawTotalRate(&PPPProtonLossRate); + DeleteRawTotalRate(&PPPNeutronLossRate); + + if (nucleonToSecondarySwitch == 1) { + DeleteRawDiffRate(&PPPProtonPhotonRate); + DeleteRawDiffRate(&PPPProtonElectronRate); + DeleteRawDiffRate(&PPPProtonPositronRate); + DeleteRawDiffRate(&PPPNeutronElectronRate); + DeleteRawDiffRate(&PPPProtonElectronNeutrinoRate); + DeleteRawDiffRate(&PPPProtonAntiElectronNeutrinoRate); + DeleteRawDiffRate(&PPPProtonMuonNeutrinoRate); + DeleteRawDiffRate(&PPPProtonAntiMuonNeutrinoRate); + DeleteRawDiffRate(&PPPNeutronAntiElectronNeutrinoRate); + DeleteRawDiffRate(&PPPNeutronMuonNeutrinoRate); + DeleteRawDiffRate(&PPPNeutronAntiMuonNeutrinoRate); + } + } + if (NPPSwitch == 1) { + if (nucleonToSecondarySwitch == 1) + DeleteRawDiffRate(&NPPDiffRate); + DeleteRawTotalRate(&NPPTotalRate); + } + if (DPPSwitch == 1) + DeleteRawTotalRate(&DPPRate); + + if (neutronDecaySwitch == 1) { + if (nucleonToSecondarySwitch == 1) + DeleteDiffRate(&neutronDecayElectronRate); + DeleteDiffRate(&neutronDecayProtonRate); + DeleteTotalRate(&neutronDecayRate); + } + + + if (neutrinoNeutrinoSwitch == 1) { + DeleteDiffRate(&NNElNeutScatRate); + DeleteDiffRate(&NNElNeutMuonNeutRate); + DeleteDiffRate(&NNElNeutTauNeutRate); + DeleteDiffRate(&NNElNeutElectronRate); + DeleteDiffRate(&NNElNeutPhotonRate); + DeleteDiffRate(&NNElNeutProtonRate); + DeleteDiffRate(&NNMuonNeutElNeutRate); + DeleteDiffRate(&NNMuonNeutScatRate); + DeleteDiffRate(&NNMuonNeutTauNeutRate); + DeleteDiffRate(&NNMuonNeutElectronRate); + DeleteDiffRate(&NNMuonNeutPhotonRate); + DeleteDiffRate(&NNMuonNeutProtonRate); + DeleteDiffRate(&NNTauNeutElNeutRate); + DeleteDiffRate(&NNTauNeutMuonNeutRate); + DeleteDiffRate(&NNTauNeutScatRate); + DeleteDiffRate(&NNTauNeutElectronRate); + DeleteDiffRate(&NNTauNeutPhotonRate); + DeleteDiffRate(&NNTauNeutProtonRate); + + DeleteTotalRate(&NNElNeutTotalRate); + DeleteTotalRate(&NNMuonNeutTotalRate); + DeleteTotalRate(&NNTauNeutTotalRate); + } + + // FinalPrintOutToTheScreen(distance, startingRedshift, propagatingDistance); + + DeleteSpectrum(&Q_0); + DeleteSpectrum(&spectrumNew); + DeleteSpectrum(&derivative); + + Delete_dCVector(&synchrotronLoss); + Delete_dCVector(&continuousLoss); + Delete_dCVector(&otherLoss); + Delete_dCVector(&protonContinuousLoss); + + Delete_dCVector(&deltaG); + Delete_dCVector(&bgEnergy); + Delete_dCVector(&bgEnergyWidth); + Delete_dCVector(&bgPhotonDensity); + + Delete_dCVector(&RedshiftArray) ; + Delete_dCVector(&DistanceArray) ; +clock_t end = clock(); + +clock_t total = end -start; +clock_t comp = end_comp -start_comp; +printf("Comptime: %f\n", float(comp)/float(total)); + +} + +void BuildRedshiftTable(double aH0, double aOmegaM, double aOmegaLambda, + dCVector* pRedshiftArray, dCVector* pDistanceArray) { + + // Routine added Jan 2006 - E.A. + + // aH0 in km/s/Mpc + // C is in cm/s, distances in Mpc + int lNbBins = NBINS_REDSHIFTTABLE ; + double lZmin = ZMIN_REDSHIFTTABLE ; + double lZmax = ZMAX_REDSHIFTTABLE ; + New_dCVector(pRedshiftArray, lNbBins) ; + New_dCVector(pDistanceArray, lNbBins) ; + + pRedshiftArray->vector[0] = 0 ; + for (int i=0; i < lNbBins - 1; i++) { + double kk = i/(lNbBins-2.) ; + pRedshiftArray->vector[i+1] = lZmin*pow(lZmax/lZmin,kk) ; + } + dCVector lpEvolutionFactor ; + New_dCVector(&lpEvolutionFactor, lNbBins) ; + lpEvolutionFactor.vector[0] = 1 ; + pDistanceArray->vector[0] = 0 ; + for (int i=1; i < lNbBins; i++) { + double lZ = pRedshiftArray->vector[i] ; + lpEvolutionFactor.vector[i] = 1./((1.+lZ)*sqrt(aOmegaLambda+aOmegaM*pow(1.+lZ,3))) ; + pDistanceArray->vector[i] = pDistanceArray->vector[i-1]+ + (lZ-pRedshiftArray->vector[i-1])*0.5* + (lpEvolutionFactor.vector[i-1]+lpEvolutionFactor.vector[i])*C/(aH0*1.e5) ; + } + Delete_dCVector(&lpEvolutionFactor) ; + +} + +double getRedshift(dCVector RedshiftArray, dCVector DistanceArray, double distance) { + + // Routine added Jan 2006 - E.A. + + unsigned int i0 = 0 ; + while (DistanceArray.vector[i0+1] <= distance) i0 += 1 ; + double lRedshift = RedshiftArray.vector[i0] + (RedshiftArray.vector[i0+1]-RedshiftArray.vector[i0]) + *(distance-DistanceArray.vector[i0]) + /(DistanceArray.vector[i0+1]-DistanceArray.vector[i0]) ; + if ( distance <= 0 ) lRedshift = 0 ; + + return lRedshift ; +} + +double getDistance(dCVector RedshiftArray, dCVector DistanceArray, double redshift) { + + // Routine added Jan 2006 - E.A. + + unsigned int i0 = 0 ; + while (RedshiftArray.vector[i0+1] <= redshift) i0 += 1 ; + double lDistance = DistanceArray.vector[i0] + (DistanceArray.vector[i0+1]-DistanceArray.vector[i0]) + *(redshift-RedshiftArray.vector[i0]) + /(RedshiftArray.vector[i0+1]-RedshiftArray.vector[i0]) ; + if ( redshift <= 0 ) lDistance = 0 ; + + // At that level lDistance is in Mpc --> we convert it into cm. + lDistance *= 1.e6 ; // in pc + lDistance *= DISTANCE_UNIT ; // in cm + + return lDistance ; +} + diff --git a/libs/dint/src/rate.cpp b/libs/dint/src/rate.cpp new file mode 100644 index 000000000..a156b2b33 --- /dev/null +++ b/libs/dint/src/rate.cpp @@ -0,0 +1,909 @@ +#include +#include "dint/rate.h" +#include "dint/vector.h" +#include "dint/utilities.h" + + +/* this is actually the class constructor for RawTotalRate */ +void NewRawTotalRate(RawTotalRate* pRate, const int num_main_bins, + const int num_bg_bins) +{ + pRate->mainDimension = num_main_bins; + pRate->bgDimension = num_bg_bins; + pRate->totalRate = New_dMatrix(num_main_bins, num_bg_bins); + + InitializeRawTotalRate(pRate); +} + +void DeleteRawTotalRate(RawTotalRate* pRate) +{ + Delete_dMatrix(pRate->totalRate); +} + +void InitializeRawTotalRate(RawTotalRate* pRate) +{ + int i; + int j; + + for (i = 0; i < pRate->mainDimension; i++) + { + for (j = 0; j < pRate->bgDimension; j++) + { + pRate->totalRate[i][j] = 0.; + } + } +} + +void CopyRawTotalRate(RawTotalRate* pLRate, const RawTotalRate* pRRate) +{ + int i; + int j; + + pLRate->mainDimension = pRRate->mainDimension; + pLRate->bgDimension = pRRate->bgDimension; + + Delete_dMatrix(pLRate->totalRate); + + pLRate->totalRate = New_dMatrix(pRRate->mainDimension, + pRRate->bgDimension); + + for (i = 0; i < pRRate->mainDimension; i++) + { + for (j = 0; j < pRRate->bgDimension; j++) + { + pLRate->totalRate[i][j] = pRRate->totalRate[i][j]; + } + } + /* deep copy */ +} + +void ClipRawTotalRate(RawTotalRate* pRate, const int newSize) +{ + int i; + int j; + int clip; + RawTotalRate tempRate; + + printf("Clipping RawTotalRate. From %5i... ", pRate->mainDimension); + /* let user know */ + + clip = pRate->mainDimension - newSize; + NewRawTotalRate(&tempRate, newSize, pRate->bgDimension); + + for (i = 0; i < newSize; i++) + { + int iOld = i + clip; + for (j = 0; j < pRate->bgDimension; j++) + { +#ifdef DEBUG + CheckIndex(0, pRate->mainDimension, iOld, "ClipRawTotalRate"); +#endif + tempRate.totalRate[i][j] = pRate->totalRate[iOld][j]; + } + } + + CopyRawTotalRate(pRate, &tempRate); + DeleteRawTotalRate(&tempRate); + + printf("to %5i.\n", pRate->mainDimension); +} + +void EnlargeRawTotalRate(RawTotalRate* pRate, const int newSize) +{ + int i; + int j; + RawTotalRate tempRate; + int numAddedCells; + + + numAddedCells = newSize - pRate->mainDimension; + NewRawTotalRate(&tempRate, newSize, pRate->bgDimension); + + for (i = 0; i < newSize; i++) + { + int iOld = i - numAddedCells; + for (j = 0; j < pRate->bgDimension; j++) + { + if (iOld >= 0) /* range where original matrix is */ + { +#ifdef DEBUG + CheckIndex(0, pRate->mainDimension, iOld, + "EnlargeRawTotalRate"); +#endif + tempRate.totalRate[i][j] = pRate->totalRate[iOld][j]; + } + else /* enlarged area is filled with 0 for convenience */ + { + tempRate.totalRate[i][j] = 0.; + } + } + } + + CopyRawTotalRate(pRate, &tempRate); + DeleteRawTotalRate(&tempRate); +} + +void ModifyRawTotalRate(RawTotalRate* pRate, const int newSize) +{ + if (pRate->mainDimension > newSize) + { + ClipRawTotalRate(pRate, newSize); + } + else if (pRate->mainDimension < newSize) + { + EnlargeRawTotalRate(pRate, newSize); + } + else + { + /* do nothing */ + } +} + +void ReadRawTotalRate(RawTotalRate* pRate, const char* filename) +{ + FILE* file; + + file = SafeFOpen(filename, "r"); + binfread((pRate->totalRate)[0], sizeof(double), (pRate->mainDimension)* + (pRate->bgDimension), file); + fclose(file); +} + + + +/* this is actually the class constructor for RawDiffRate */ +void NewRawDiffRate(RawDiffRate* pRate, const int num_main_bins, + const int num_bg_bins, const int num_elements) +{ + pRate->mainDimension = num_main_bins; + pRate->bgDimension = num_bg_bins; + pRate->numberOfElements = num_elements; + pRate->bound = New_i3Tensor(num_main_bins, num_bg_bins, 2); + pRate->diffRate = New_dVector(num_elements); + + InitializeRawDiffRate(pRate); +} + +void DeleteRawDiffRate(RawDiffRate* pRate) +{ + Delete_dVector(pRate->diffRate); + Delete_i3Tensor(pRate->bound); +} + +void InitializeRawDiffRate(RawDiffRate* pRate) +{ + int i; + int j; + + for (i = 0; i < pRate->mainDimension; i++) + { + for (j = 0; j < pRate->bgDimension; j++) + { + pRate->bound[i][j][0] = -1; + pRate->bound[i][j][1] = -1; + } + } + /* note how the bounds are invalidated */ + + for (i = 0; i < pRate->numberOfElements; i++) + { + pRate->diffRate[i] = 0.; + } +} + +void CheckRawDiffRate(RawDiffRate* pRate) +{ + int i; + int j; + int counter; + + for (counter = 0, i = 0; i < pRate->mainDimension; i++) + { + for (j = 0; j < pRate->bgDimension; j++) + { + if (pRate->bound[i][j][0] != -1) + { + counter += pRate->bound[i][j][1] - pRate->bound[i][j][0] + 1; + } + } + } + + if (counter != pRate->numberOfElements) + { + Error("CheckRawDiffRate: inconsistent rate", PROGRAM_ERROR); + } +} + +#ifdef DEBUG +double RawDiffRateElement(const RawDiffRate* pRate, const int i, const int j, + const int k) +{ + int n; + int p; + int offset; + + + if ((i < 0) || (j < 0) || (i >= pRate->mainDimension) || + (j >= pRate->bgDimension)) + { + printf("i: %3i, j: %3i\n", i, j); + Error("RawDiffRateElement: i or j out of bounds", PROGRAM_ERROR); + } + if ((pRate->bound)[i][j][0] == -1) /* out of range */ + { + printf("i: %3i, j: %3i\n", i, j); + Error("RawDiffRateElement: i or j out of range", PROGRAM_ERROR); + } + else + { + if ((k < (pRate->bound)[i][j][0]) || (k > (pRate->bound)[i][j][1])) + { + printf("i, j, k: %3i %3i %3i\n", k); + Error("RawDiffRateElement: k out of range", PROGRAM_ERROR); + } + } + + offset = 0; + for (n = 0; n < i; n++) + { + for (p = 0; p < pRate->bgDimension; p++) + { + if ((pRate->bound)[n][p][0] != -1) + { + offset += ((pRate->bound)[n][p][1] - (pRate->bound)[n][p][0] + + 1); + } + } + } + for (p = 0; p < j; p++) + { + offset += ((pRate->bound)[i][p][1] - (pRate->bound)[i][p][0] + 1); + } + offset += -(pRate->bound)[i][j][0] + k; + if (offset >= pRate->numberOfElements || offset < 0) + { + printf("offset: %7i, number of elements: %7i\n", offset, + pRate->numberOfElements); + Error("RawDiffRateElement: main index out of range", PROGRAM_ERROR); + } + + return (pRate->diffRate)[offset]; +} +#endif + +void CopyRawDiffRate(RawDiffRate* pLRate, const RawDiffRate* pRRate) +{ + int i; + int j; + + pLRate->mainDimension = pRRate->mainDimension; + pLRate->bgDimension = pRRate->bgDimension; + pLRate->numberOfElements = pRRate->numberOfElements; + + Delete_dVector(pLRate->diffRate); + Delete_i3Tensor(pLRate->bound); + + pLRate->bound = New_i3Tensor(pRRate->mainDimension, pRRate->bgDimension, + 2); + pLRate->diffRate = New_dVector(pRRate->numberOfElements); + + for (i = 0; i < pRRate->mainDimension; i++) + { + for (j = 0; j < pRRate->bgDimension; j++) + { + pLRate->bound[i][j][0] = pRRate->bound[i][j][0]; + pLRate->bound[i][j][1] = pRRate->bound[i][j][1]; + } + } + for (i = 0; i < pRRate->numberOfElements; i++) + { + pLRate->diffRate[i] = pRRate->diffRate[i]; + } +} + +void CopyRawDiffRateBound(RawDiffRate* pLRate, const RawDiffRate* pRRate) +{ + int i; + int j; + + if ((pLRate->mainDimension != pRRate->mainDimension) || + (pLRate->bgDimension != pRRate->bgDimension) || + (pLRate->numberOfElements != pRRate->numberOfElements)) + { + Error("CopyRawDiffRateBound: inconsistent dimensions", PROGRAM_ERROR); + } + + for (i = 0; i < pLRate->mainDimension; i++) + { + for (j = 0; j < pLRate->bgDimension; j++) + { + pLRate->bound[i][j][0] = pRRate->bound[i][j][0]; + pLRate->bound[i][j][1] = pRRate->bound[i][j][1]; + } + } +} + +void ClipRawDiffRate(RawDiffRate* pRate, const int newSize) +{ + int clip; + int newNumberOfElements; + RawDiffRate tempRate; + int i; + int j; + int k; + int counter; + int newCounter; + + + printf("Clipping RawDiffRate. From %8i... ", pRate->numberOfElements); + + clip = pRate->mainDimension - newSize; + + for (newNumberOfElements = 0, i = clip; i < pRate->mainDimension; i++) + { + for (j = 0; j < pRate->bgDimension; j++) + { + if ((pRate->bound[i][j][0] != -1) && + (pRate->bound[i][j][1] >= clip)) + /* not empty AND within range */ + { + int newLowerBound; + newLowerBound = IMax(pRate->bound[i][j][0], clip); + /* new lower bound cannot be smaller than the lower clip */ + newNumberOfElements += pRate->bound[i][j][1] - + newLowerBound + 1; + } + } + } + /* determine new number of elements */ + + NewRawDiffRate(&tempRate, newSize, pRate->bgDimension, + newNumberOfElements); + + for (i = 0; i < newSize; i++) + { + int iOld = i + clip; /* (old) index for old rate */ + for (j = 0; j < pRate->bgDimension; j++) + { +#ifdef DEBUG + CheckIndex(0, pRate->mainDimension, iOld, "ClipRawDiffRate"); +#endif + if ((pRate->bound[iOld][j][0] != -1) && + (pRate->bound[iOld][j][1] >= clip)) + { + tempRate.bound[i][j][0] = + IMax(pRate->bound[iOld][j][0], clip) - clip; + tempRate.bound[i][j][1] = + pRate->bound[iOld][j][1] - clip; + } + else + { + tempRate.bound[i][j][0] = -1; + tempRate.bound[i][j][1] = -1; + } + } + } + /* set the bounds */ + + /* fast-forward the index */ + for (counter = 0, newCounter = 0, i = 0; i < pRate->mainDimension; i++) + { + int iNew = i - clip; /* (new) index for new rate */ + for (j = 0; j < pRate->bgDimension; j++) + { + if (pRate->bound[i][j][0] != -1) + { + for (k = pRate->bound[i][j][0]; + k <= pRate->bound[i][j][1]; k++, counter++) + { + int kNew = k - clip; /* (new) k index */ + +#ifdef DEBUG + CheckIndex(0, pRate->numberOfElements, counter, + "ClipRawDiffRate"); +#endif + /* i must be within clips */ + if (i >= clip) + { + /* its own bound must not be empty && + k must be within range: + comparison w/ upper bound is not necessary + because it is automatically satisfied */ +#ifdef DEBUG + CheckIndex(0, tempRate.mainDimension, iNew, + "ClipRawDiffRate"); +#endif + if ((tempRate.bound[iNew][j][0] != -1) && + (kNew >= tempRate.bound[iNew][j][0])) + { +#ifdef DEBUG + CheckIndex(0, tempRate.numberOfElements, + newCounter, "ClipRawDiffRate"); +#endif + tempRate.diffRate[newCounter] = + pRate->diffRate[counter]; + newCounter++; + } + } + } + } + } + } + if ((counter != pRate->numberOfElements) || + (newCounter != tempRate.numberOfElements)) + { + Error("ClipRawDiffRate: counting does not match", PROGRAM_ERROR); + } + /* redundant checking, but comes cheap so why not */ + + CopyRawDiffRate(pRate, &tempRate); + /* this is where real copy takes place */ + DeleteRawDiffRate(&tempRate); + + printf("to %8i.\n", pRate->numberOfElements); +} + +void EnlargeRawDiffRate(RawDiffRate* pRate, const int newSize) +{ + int i; + int j; + int numAddedCells; + RawDiffRate tempRate; + + numAddedCells = newSize - pRate->mainDimension; + + NewRawDiffRate(&tempRate, newSize, pRate->bgDimension, + pRate->numberOfElements); + + for (i = 0; i < newSize; i++) + { + int iOld = i - numAddedCells; + for (j = 0; j < pRate->bgDimension; j++) + { + if (iOld >= 0) /* area where the original tensor is */ + { + if (pRate->bound[iOld][j][0] != -1) + { +#ifdef DEBUG + CheckIndex(0, pRate->mainDimension, iOld, + "EnlargeRawDiffRate"); +#endif + tempRate.bound[i][j][0] = pRate->bound[iOld][j][0] + + numAddedCells; + tempRate.bound[i][j][1] = pRate->bound[iOld][j][1] + + numAddedCells; + } + else + { + tempRate.bound[i][j][0] = -1; + tempRate.bound[i][j][1] = -1; + } + } + else /* outside the original tensor */ + { + tempRate.bound[i][j][0] = -1; + tempRate.bound[i][j][1] = -1; + } + } + } + + for (i = 0; i < pRate->numberOfElements; i++) + { + tempRate.diffRate[i] = pRate->diffRate[i]; + /* the rate itself does not change */ + } + + CopyRawDiffRate(pRate, &tempRate); + DeleteRawDiffRate(&tempRate); +} + +void ModifyRawDiffRate(RawDiffRate* pRate, const int newSize) +{ + if (pRate->mainDimension > newSize) + { + ClipRawDiffRate(pRate, newSize); + } + else if (pRate->mainDimension < newSize) + { + EnlargeRawDiffRate(pRate, newSize); + } + else + { + /* do nothing */ + } +} + +void ReadRawDiffRate(RawDiffRate* pRate, const char* filename) +{ + FILE* file; + + file = SafeFOpen(filename, "r"); + binfread((pRate->bound)[0][0], sizeof(int), (pRate->mainDimension)* + (pRate->bgDimension)*2, file); + binfread(pRate->diffRate, sizeof(double), pRate->numberOfElements, file); + fclose(file); + + CheckRawDiffRate(pRate); +} + + + +void NewTotalRate(TotalRate* pRate, const int num_main_bins) +{ + pRate->mainDimension = num_main_bins; + pRate->totalRate = New_dVector(num_main_bins); + + InitializeTotalRate(pRate); +} + +void DeleteTotalRate(TotalRate* pRate) +{ + Delete_dVector(pRate->totalRate); +} + +void InitializeTotalRate(TotalRate* pRate) +{ + int i; + + for (i = 0; i < pRate->mainDimension; i++) + { + pRate->totalRate[i] = 0.; + } +} + +void CopyTotalRate(TotalRate* pLRate, const TotalRate* pRRate) +{ + int i; + + pLRate->mainDimension = pRRate->mainDimension; + + Delete_dVector(pLRate->totalRate); + pLRate->totalRate = New_dVector(pRRate->mainDimension); + + for (i = 0; i < pRRate->mainDimension; i++) + { + pLRate->totalRate[i] = pRRate->totalRate[i]; + } +} + +void ClipTotalRate(TotalRate* pRate, const int newSize) +{ + int i; + int clip; + TotalRate tempRate; + + + printf("Clipping TotalRate. From %5i... ", pRate->mainDimension); + /* let user know */ + + clip = pRate->mainDimension - newSize; + NewTotalRate(&tempRate, newSize); + + for (i = 0; i < newSize; i++) + { + int iOld = i + clip; +#ifdef DEBUG + CheckIndex(0, pRate->mainDimension, iOld, "ClipTotalRate"); +#endif + tempRate.totalRate[i] = pRate->totalRate[iOld]; + } + + CopyTotalRate(pRate, &tempRate); + DeleteTotalRate(&tempRate); + + printf("to %5i.\n", pRate->mainDimension); +} + +void EnlargeTotalRate(TotalRate* pRate, const int newSize) +{ + int i; + int numAddedCells; + TotalRate tempRate; + + numAddedCells = newSize - pRate->mainDimension; + + NewTotalRate(&tempRate, newSize); + + for (i = 0; i < newSize; i++) + { + int iOld = i - numAddedCells; + if (iOld >= 0) + { +#ifdef DEBUG + CheckIndex(0, pRate->mainDimension, iOld, "EnlargeTotalRate"); +#endif + tempRate.totalRate[i] = pRate->totalRate[iOld]; + } + else + { + tempRate.totalRate[i] = 0.; + } + } + + CopyTotalRate(pRate, &tempRate); + DeleteTotalRate(&tempRate); +} + +void ModifyTotalRate(TotalRate* pRate, const int newSize) +{ + if (pRate->mainDimension > newSize) + { + ClipTotalRate(pRate, newSize); + } + else if (pRate->mainDimension < newSize) + { + EnlargeTotalRate(pRate, newSize); + } + else + { + /* do nothing */ + } +} + +void ReadTotalRate(TotalRate* pRate, const char* filename) +{ + FILE* file; + + file = SafeFOpen(filename, "r"); + binfread(pRate->totalRate, sizeof(double), (pRate->mainDimension), file); + fclose(file); +} + + + +void NewDiffRate(DiffRate* pRate, const int num_main_bins) +{ + pRate->mainDimension = num_main_bins; + pRate->bound = New_iMatrix(num_main_bins, 2); + pRate->diffRate = New_dMatrix(num_main_bins, num_main_bins); + + InitializeDiffRate(pRate); +} + + +void DeleteDiffRate(DiffRate* pRate) +{ + Delete_dMatrix(pRate->diffRate); + Delete_iMatrix(pRate->bound); +} + + +void InitializeDiffRate(DiffRate* pRate) +{ + int i; + int j; + + for (i = 0; i < pRate->mainDimension; i++) + { + pRate->bound[i][0] = pRate->mainDimension - 1; + pRate->bound[i][1] = 0; + /* note that the invalidation here is different from RawDiffRate */ + for (j = 0; j < pRate->mainDimension; j++) + { + pRate->diffRate[i][j] = 0.; + } + } +} + +void CopyDiffRate(DiffRate* pLRate, const DiffRate* pRRate) +{ + int i; + int j; + + pLRate->mainDimension = pRRate->mainDimension; + + Delete_dMatrix(pLRate->diffRate); + Delete_iMatrix(pLRate->bound); + + pLRate->bound = New_iMatrix(pRRate->mainDimension, 2); + pLRate->diffRate = New_dMatrix(pRRate->mainDimension, + pRRate->mainDimension); + + for (i = 0; i < pRRate->mainDimension; i++) + { + pLRate->bound[i][0] = pRRate->bound[i][0]; + pLRate->bound[i][1] = pRRate->bound[i][1]; + for (j = 0; j < pRRate->mainDimension; j++) + { + pLRate->diffRate[i][j] = pRRate->diffRate[i][j]; + } + } +} + +void CopyDiffRateBound(DiffRate* pLRate, const DiffRate* pRRate) +{ + int i; + + if (pLRate->mainDimension != pRRate->mainDimension) + { + Error("CopyDiffRateBound: inconsistent dimensions", PROGRAM_ERROR); + } + + for (i = 0; i < pLRate->mainDimension; i++) + { + pLRate->bound[i][0] = pRRate->bound[i][0]; + pLRate->bound[i][1] = pRRate->bound[i][1]; + } +} + +void SetStandardDiffRateBound(DiffRate* pRate) +{ + int i; + + InvalidateDiffRateBound(pRate); + + for (i = 0; i < pRate->mainDimension; i++) + { + if ((pRate->bound[i][0] != pRate->mainDimension - 1) || + (pRate->bound[i][1] != 0)) + { + pRate->bound[i][0] = 0; + pRate->bound[i][1] = i; + } + } +} + +void ClipDiffRate(DiffRate* pRate, const int newSize) +{ + int clip; + DiffRate tempRate; + int i; + int j; + + printf("Clipping DiffRate. From %5i... ", pRate->mainDimension); + + clip = pRate->mainDimension - newSize; + + NewDiffRate(&tempRate, newSize); + + for (i = 0; i < newSize; i++) + { + int iOld = i + clip; /* (old) index for old rate */ + +#ifdef DEBUG + CheckIndex(0, pRate->mainDimension, iOld, "ClipDiffRate"); +#endif + if ((pRate->bound[iOld][0] != pRate->mainDimension - 1) || + (pRate->bound[iOld][1] != 0)) + /* bound is valid */ + { + if (pRate->bound[iOld][1] >= clip) + { + tempRate.bound[i][0] = IMax(pRate->bound[iOld][0], clip) - + clip; + tempRate.bound[i][1] = pRate->bound[iOld][1] - clip; + } + else + { + tempRate.bound[i][0] = newSize - 1; + tempRate.bound[i][1] = 0; + } + } + else /* bound is invalid to begin with */ + { + tempRate.bound[i][0] = newSize - 1; + tempRate.bound[i][1] = 0; + } + + for (j = 0; j < newSize; j++) + { + int jOld = j + clip; /* (old) j-index */ + +#ifdef DEBUG + CheckIndex(0, pRate->mainDimension, jOld, "ClipDiffRate"); +#endif + tempRate.diffRate[i][j] = pRate->diffRate[iOld][jOld]; + } + } + + CopyDiffRate(pRate, &tempRate); + DeleteDiffRate(&tempRate); + + printf("to %5i.\n", pRate->mainDimension); +} + +void EnlargeDiffRate(DiffRate* pRate, const int newSize) +{ + int i; + int j; + int numAddedCells; + DiffRate tempRate; + + numAddedCells = newSize - pRate->mainDimension; + + NewDiffRate(&tempRate, newSize); + + for (i = 0; i < newSize; i++) + { + int iOld = i - numAddedCells; + if (iOld >= 0) + { +#ifdef DEBUG + CheckIndex(0, pRate->mainDimension, iOld, "EnlargeDiffRate"); +#endif + if ((pRate->bound[iOld][0] != pRate->mainDimension - 1) || + (pRate->bound[iOld][1] != 0)) + /* old bound is valid */ + { + tempRate.bound[i][0] = pRate->bound[iOld][0] + numAddedCells; + tempRate.bound[i][1] = pRate->bound[iOld][1] + numAddedCells; + } + else /* old bound is invalild */ + { + tempRate.bound[i][0] = newSize - 1; + tempRate.bound[i][1] = 0; + } + } + else + { + tempRate.bound[i][0] = newSize - 1; + tempRate.bound[i][1] = 0; + } + + for (j = 0; j < newSize; j++) + { + int jOld = j - numAddedCells; + if (iOld >= 0 && jOld >= 0) + { +#ifdef DEBUG + CheckIndex(0, pRate->mainDimension, jOld, "EnlargeDiffRate"); +#endif + tempRate.diffRate[i][j] = pRate->diffRate[iOld][jOld]; + } + else + { + tempRate.diffRate[i][j] = 0.; + } + } + } + + CopyDiffRate(pRate, &tempRate); + DeleteDiffRate(&tempRate); +} + +void ModifyDiffRate(DiffRate* pRate, const int newSize) +{ + if (pRate->mainDimension > newSize) + { + ClipDiffRate(pRate, newSize); + } + else if (pRate->mainDimension < newSize) + { + EnlargeDiffRate(pRate, newSize); + } + else + { + /* do nothing */ + } +} + +void ReadDiffRate(DiffRate* pRate, const char* filename) +{ + FILE* file; + + file = SafeFOpen(filename, "r"); + binfread((pRate->bound)[0], sizeof(int), (pRate->mainDimension)*2, file); + binfread((pRate->diffRate)[0], sizeof(double), (pRate->mainDimension)* + (pRate->mainDimension), file); + fclose(file); + + InvalidateDiffRateBound(pRate); + /* make sure invalid bounds are properly invalidated */ +} + +void InvalidateDiffRateBound(DiffRate* pRate) +{ + int i; + + for (i = 0; i < pRate->mainDimension; i++) + { + if ((pRate->bound[i][0] == -1) || ((pRate->bound[i][0] == + pRate->mainDimension - 1) && (pRate->bound[i][0] == 0))) + /* picks up invalid bound data however they are formatted */ + { + pRate->bound[i][0] = pRate->mainDimension - 1; + pRate->bound[i][1] = 0; + } + } +} + diff --git a/libs/dint/src/spectrum.cpp b/libs/dint/src/spectrum.cpp new file mode 100644 index 000000000..63ca5ef20 --- /dev/null +++ b/libs/dint/src/spectrum.cpp @@ -0,0 +1,206 @@ +#include +#include +#include "dint/spectrum.h" +#include "dint/vector.h" +#include "dint/cvector.h" +#include "dint/const.h" +#include "dint/utilities.h" + + +void NewSpectrum(Spectrum* pSpectrum, const int num_bins) { + pSpectrum->numberOfMainBins = num_bins; + pSpectrum->spectrum = New_dMatrix(NUM_SPECIES, num_bins); + + InitializeSpectrum(pSpectrum); // always initialize! +} + +void DeleteSpectrum(Spectrum* pSpectrum) { + Delete_dMatrix(pSpectrum->spectrum); +} + +void InitializeSpectrum(Spectrum* pSpectrum) { + for (int i=0; inumberOfMainBins; j++) + pSpectrum->spectrum[i][j] = 0.; + } +} + +void InitializeEMSpectrum(Spectrum* pSpectrum) { + for (int i=0; i<3; i++) { + for (int j=0; jnumberOfMainBins; j++) + pSpectrum->spectrum[i][j] = 0.; + } +} + +void InitializeNucleonSpectrum(Spectrum* pSpectrum) { + for (int i=3; i<5; i++) { + for (int j=0; jnumberOfMainBins; j++) + pSpectrum->spectrum[i][j] = 0.; + } +} + +void InitializeNeutrinoSpectrum(Spectrum* pSpectrum) { + for (int i=5; inumberOfMainBins; j++) + pSpectrum->spectrum[i][j] = 0.; + } +} + + +void SetSpectrum(Spectrum* pSpectrum1, const Spectrum* pSpectrum2) { + if (pSpectrum1->numberOfMainBins != pSpectrum2->numberOfMainBins) + Error("SetSpectrum: inconsistent dimensions", PROGRAM_ERROR); + + for (int i=0; inumberOfMainBins; j++) + pSpectrum1->spectrum[i][j] = pSpectrum2->spectrum[i][j]; + } +} + +void SetEMSpectrum(Spectrum* pSpectrum1, const Spectrum* pSpectrum2) { + if (pSpectrum1->numberOfMainBins != pSpectrum2->numberOfMainBins) + Error("SetEMSpectrum: inconsistent dimension", PROGRAM_ERROR); + + for (int i=0; i<3; i++) { + for (int j=0; jnumberOfMainBins; j++) + pSpectrum1->spectrum[i][j] = pSpectrum2->spectrum[i][j]; + } +} + +void SetNucleonSpectrum(Spectrum* pSpectrum1, const Spectrum* pSpectrum2) { + if (pSpectrum1->numberOfMainBins != pSpectrum2->numberOfMainBins) + Error("SetSpectrum: inconsistent dimension", PROGRAM_ERROR); + + for (int i=3; i<5; i++) { + for (int j=0; jnumberOfMainBins; j++) + pSpectrum1->spectrum[i][j] = pSpectrum2->spectrum[i][j]; + } +} + +void SetNeutrinoSpectrum(Spectrum* pSpectrum1, const Spectrum* pSpectrum2) { + if (pSpectrum1->numberOfMainBins != pSpectrum2->numberOfMainBins) + Error("SetSpectrum: inconsistent dimension", PROGRAM_ERROR); + + for (int i=5; inumberOfMainBins; j++) + pSpectrum1->spectrum[i][j] = pSpectrum2->spectrum[i][j]; + } +} + +double GetNumber(const Spectrum* pSpectrum) { + double number = 0.; + + for (int i=0; inumberOfMainBins; j++) + number += pSpectrum->spectrum[i][j]; + } + return number; +} + +double GetEMNumber(const Spectrum* pSpectrum) { + double number = 0.; + + for (int i=0; i<3; i++) { + for (int j=0; jnumberOfMainBins; j++) + number += pSpectrum->spectrum[i][j]; + } + return number; +} + +double GetNucleonNumber(const Spectrum* pSpectrum) { + double number = 0.; + + for (int i=3; i<5; i++) { + for (int j=0; jnumberOfMainBins; j++) + number += pSpectrum->spectrum[i][j]; + } + return number; +} + +double GetNeutrinoNumber(const Spectrum* pSpectrum) { + double number = 0.; + + for (int i=5; inumberOfMainBins; j++) + number += pSpectrum->spectrum[i][j]; + } + return number; +} + +double GetEnergy(const Spectrum* pSpectrum, const dCVector* pEnergy) { + double totalEnergy = 0.; + + if (pSpectrum->numberOfMainBins != pEnergy->dimension) + Error("GetEnergy: inconsistent dimensions", PROGRAM_ERROR); + + for (int i=0; inumberOfMainBins; j++) + totalEnergy += (pSpectrum->spectrum)[i][j]*(pEnergy->vector)[j]; + } + return totalEnergy; +} + +double GetEMEnergy(const Spectrum* pSpectrum, const dCVector* pEnergy) { + double totalEnergy = 0.; + + if (pSpectrum->numberOfMainBins != pEnergy->dimension) + Error("GetEnergy: inconsistent dimensions", PROGRAM_ERROR); + + for (int i=0; i<3; i++) { + for (int j=0; jnumberOfMainBins; j++) + totalEnergy += (pSpectrum->spectrum)[i][j]*(pEnergy->vector)[j]; + } + return totalEnergy; +} + +double GetNucleonEnergy(const Spectrum* pSpectrum, const dCVector* pEnergy) { + double totalEnergy = 0.; + + if (pSpectrum->numberOfMainBins != pEnergy->dimension) + Error("GetEnergy: inconsistent dimensions", PROGRAM_ERROR); + + for (int i=3; i<5; i++) { + for (int j=0; jnumberOfMainBins; j++) + totalEnergy += (pSpectrum->spectrum)[i][j]*(pEnergy->vector)[j]; + } + return totalEnergy; +} + +double GetNeutrinoEnergy(const Spectrum* pSpectrum, const dCVector* pEnergy) { + double totalEnergy = 0.; + + if (pSpectrum->numberOfMainBins != pEnergy->dimension) + Error("GetEnergy: inconsistent dimensions", PROGRAM_ERROR); + + for (int i=5; inumberOfMainBins; j++) + totalEnergy += (pSpectrum->spectrum)[i][j]*(pEnergy->vector)[j]; + } + return totalEnergy; +} + +void DumpSpectrum(const dCVector* pEnergy, const dCVector* pEnergyWidth, + const Spectrum* pSpectrum, const char* filename) { + FILE* dumpFile; + char f1[80] = "datafiles/"; + + if ((pEnergy->dimension != pEnergyWidth->dimension) || + (pEnergyWidth->dimension != pSpectrum->numberOfMainBins)) + Error("DumpSpectrum: inconsistent dimensions", PROGRAM_ERROR); + + strncat(f1, filename, 79 - strlen(filename)); + dumpFile = SafeFOpen(f1, "w"); + // this is to send the dump file to a different directory (datafiles) + // by Guenter (7/20/1998) + + for (int i=0; inumberOfMainBins; j++) { + fprintf(dumpFile, "%15.4E %15.4E\n", + ELECTRON_MASS*(pEnergy->vector)[j], + (pSpectrum->spectrum)[i][j]/(pEnergyWidth->vector)[j]* + (pEnergy->vector)[j]*(pEnergy->vector)[j]); + // proper unit conversion for energy + } + } + fclose(dumpFile); +} diff --git a/libs/dint/src/sync.cpp b/libs/dint/src/sync.cpp new file mode 100644 index 000000000..72a74699b --- /dev/null +++ b/libs/dint/src/sync.cpp @@ -0,0 +1,128 @@ + +#include "dint/sync.h" + +void LoadSyncTable(dCVector* syncTable, string aDirTables) +{ + FILE* syncData; + double temporary; + int i; + + syncData = SafeFOpen((aDirTables+"/syncTable.dat").c_str(), "r"); + for (i = 0; i < syncTable->dimension; i++) { + fscanf(syncData, "%lf %lf", &temporary, &((syncTable->vector)[i])); + } + fclose(syncData) ; // added June 2005 - E.A. + +} + + +void InitializeSynchrotron(const double B_0, const dCVector* pEnergy, + const dCVector* pEnergyWidth, + dCVector* synchrotronLoss, DiffRate* syncRate, + string aDirTables) +/* this function calculates the synchrotron loss rate for the electron + and the synchrotron radiation spectrum for photons + The radom direction of the magnetic field requires me to do an + average over the pitch angle, and it results in an extra factor of + 2/3, and slightly modifies the functional form of F(x) from the + purely perpendicular case */ +/* The above comment is from the stand alone version. Compared to this version the constants seem to be fixed to correct for a perpendicular field as input. JK, 2011*/ +{ + const int SYNC_TABLE_SIZE = 161; + int i; + double offset; /* parameter to compute bounds correctly */ + dCVector syncTable; + double x0; + + double ECrit; + double EMin; + double EMax; + int jMin; + int jMax; + int j; + double xx; + double function; + int iTable; + double eLower; + double eUpper; + int num_main_bins; + + num_main_bins = pEnergy->dimension; + + if ((num_main_bins != pEnergyWidth->dimension) || + (num_main_bins != syncRate->mainDimension) || + (num_main_bins != synchrotronLoss->dimension)) + { + Error("InitializeSynchrotron: inconsistent dimensions", PROGRAM_ERROR); + } + + New_dCVector(&syncTable, SYNC_TABLE_SIZE); + + /* read in table */ + + LoadSyncTable(&syncTable, aDirTables); + + /* calculate the rates */ + offset = BINS_PER_DECADE*(log10(ELECTRON_MASS) - MAX_ENERGY_EXP) + + num_main_bins + 0.5; + x0 = B_0*5.86667629e-4*DISTANCE_UNIT; + /* x0: eB/m_e in inverse pc */ + + for (i = 0; i < num_main_bins; i++) + { + /* electron loss rate */ + (synchrotronLoss->vector)[i] = -B_0*B_0*(pEnergy->vector)[i]* + (pEnergy->vector)[i]*2.*4.86037e4*VOLUME_UNIT; + + /* calculate the radiation spectrum */ + ECrit = 3./2.*B_0/4.414034e13*(pEnergy->vector)[i]* + (pEnergy->vector)[i]; + /* ECrit: critical energy in electron mass */ + + EMin = 2./3./((pEnergy->vector)[i]*(pEnergy->vector)[i]* + (pEnergy->vector)[i])*ECrit; + EMax = 5.*ECrit; + /* EMin/EMax: useful range for x (in electron mass) */ + + /* set up the range for photons -> determine bounds */ + jMin = IMax((int)(BINS_PER_DECADE*log10(EMin) + offset), 0); + jMax = IMin((int)(BINS_PER_DECADE*log10(EMax) + offset), + num_main_bins - 1); + if (jMax >= 0) /* normal case */ + { + (syncRate->bound)[i][0] = jMin; + (syncRate->bound)[i][1] = jMax; + + for (j = (syncRate->bound)[i][0]; + j <= (syncRate->bound)[i][1]; j++) + { + xx = (pEnergy->vector)[j]/ECrit; + + if (log10(xx) < -7.) + { + function = pow(xx, 1./3.)*2.1809736; + /* use an approximation for x below 10^-7 */ + } + else + { + /* compute F(x) at given photon energy by linear + extrapolation in logarithm */ + iTable = (int)(log10(xx)*20. + 140); + eLower = (double)(iTable - 140)/20.; + eUpper = (double)(iTable - 139)/20.; + /* numbers 140, 139, and 20 are properties of table */ + function = exp(log(syncTable.vector[iTable]) + (log10(xx) - + eLower)/(eUpper - eLower)* + (log(syncTable.vector[iTable+1]) - + log(syncTable.vector[iTable]))); + } + (syncRate->diffRate)[i][j] = 2.756644477e-1/137.036*x0* + function/(pEnergy->vector)[j]*(pEnergyWidth->vector)[j]; + /* 2.7566...: sqtr(3)/(2pi), 1/137: e^2, x0: eB/m_e */ + } + } + } + + Delete_dCVector(&syncTable) ; + +} diff --git a/libs/dint/src/vector.cpp b/libs/dint/src/vector.cpp new file mode 100644 index 000000000..58e9700d4 --- /dev/null +++ b/libs/dint/src/vector.cpp @@ -0,0 +1,224 @@ + +#include +#include + +#include "dint/vector.h" +#include "dint/error.h" + + +dVector New_dVector(const int n) +{ + dVector vector; + + vector = (double*)malloc((size_t)(n*sizeof(double))); + if (vector == NULL) + { + Error("New_dVector: allocation failure", ARRAY_ERROR); + } + + return vector; +} + +iVector New_iVector(const int n) +{ + iVector vector; + + vector = (int*)malloc((size_t)(n*sizeof(int))); + if (vector == NULL) + { + Error("New_iVector: allocation failure", ARRAY_ERROR); + } + + return vector; +} + + +dMatrix New_dMatrix(const int n1, const int n2) +{ + int i; + dMatrix matrix; + + matrix = (double**)malloc((size_t)(n1*sizeof(double*))); + if (matrix == NULL) + { + Error("New_dMatrix: allocation failure level 1", ARRAY_ERROR); + } + + matrix[0] = (double*)malloc((size_t)(n1*n2*sizeof(double))); + if (matrix[0] == NULL) + { + Error("New_dMatrix: allocation failure level 2", ARRAY_ERROR); + } + + for (i = 1; i < n1; i++) + { + matrix[i] = matrix[i-1] + n2; + } + + return matrix; +} + + +iMatrix New_iMatrix(const int n1, const int n2) +{ + int i; + iMatrix matrix; + + matrix = (int**)malloc((size_t)(n1*sizeof(int*))); + if (matrix == NULL) + { + Error("New_iMatrix: allocation failure level 1", ARRAY_ERROR); + } + + matrix[0] = (int*)malloc((size_t)(n1*n2*sizeof(int))); + if (matrix[0] == NULL) + { + Error("New_iMatrix: allocation failure level 2", ARRAY_ERROR); + } + + for (i = 1; i < n1; i++) + { + matrix[i] = matrix[i-1] + n2; + } + + return matrix; +} + + +d3Tensor New_d3Tensor(const int n1, const int n2, const int n3) +{ + int i; + int j; + d3Tensor tensor; + + tensor = (double***)malloc((size_t)(n1*sizeof(double**))); + if (tensor == NULL) + { + Error("d3Tensor: allocation failure level 1", ARRAY_ERROR); + } + + tensor[0] = (double**)malloc((size_t)(n1*n2*sizeof(double*))); + if (tensor[0] == NULL) + { + Error("d3Tensor: allocation failure level 2", ARRAY_ERROR); + } + + tensor[0][0] = (double*)malloc((size_t)(n1*n2*n3*sizeof(double))); + if (tensor[0][0] == NULL) + { + Error("d3Tensor: allocation failure level 3", ARRAY_ERROR); + } + + for (j = 1; j < n2; j++) + { + tensor[0][j] = tensor[0][j-1] + n3; + } + for (i = 1; i < n1; i++) + { + tensor[i] = tensor[i-1] + n2; + tensor[i][0] = tensor[i-1][0] + n2*n3; + for (j = 1; j < n2; j++) + { + tensor[i][j] = tensor[i][j-1] + n3; + } + } + + return tensor; +} + + +i3Tensor New_i3Tensor(const int n1, const int n2, const int n3) +{ + int i; + int j; + i3Tensor tensor; + + tensor = (int***)malloc((size_t)(n1*sizeof(int**))); + if (tensor == NULL) + { + Error("New_i3Tensor: allocation failure level 1", ARRAY_ERROR); + } + + tensor[0] = (int**)malloc((size_t)(n1*n2*sizeof(int*))); + if (tensor[0] == NULL) + { + Error("New_i3Tensor: allocation failure level 2", ARRAY_ERROR); + } + + tensor[0][0] = (int*)malloc((size_t)(n1*n2*n3*sizeof(int))); + if (tensor[0][0] == NULL) + { + Error("New_i3Tensor: allocation failure level 3", ARRAY_ERROR); + } + + + for (j = 1; j < n2; j++) + { + tensor[0][j] = tensor[0][j-1] + n3; + } + for (i = 1; i < n1; i++) + { + tensor[i] = tensor[i-1] + n2; + tensor[i][0] = tensor[i-1][0] + n2*n3; + for (j = 1; j < n2; j++) + { + tensor[i][j] = tensor[i][j-1] + n3; + } + } + + return tensor; +} + + +void Delete_dVector(dVector vector) +{ + free(vector); + vector = NULL; +} + + +void Delete_iVector(iVector vector) +{ + free(vector); + vector = NULL; +} + + +void Delete_dMatrix(dMatrix matrix) +{ + free(matrix[0]); + matrix[0] = NULL; + free(matrix); + matrix = NULL; +} + + +void Delete_iMatrix(iMatrix matrix) +{ + free(matrix[0]); + matrix[0] = NULL; + free(matrix); + matrix = NULL; +} + + +void Delete_d3Tensor(d3Tensor tensor) +{ + free(tensor[0][0]); + tensor[0][0] = NULL; + free(tensor[0]); + tensor[0] = NULL; + free(tensor); + tensor = NULL; +} + + +void Delete_i3Tensor(i3Tensor tensor) +{ + free(tensor[0][0]); + tensor[0][0] = NULL; + free(tensor[0]); + tensor[0] = NULL; + free(tensor); + tensor = NULL; +} diff --git a/python/mpc.i b/python/mpc.i index 19d57ab96..ff7a5be2a 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -37,6 +37,7 @@ using std::ptrdiff_t; #include "mpc/module/Output.h" #include "mpc/module/OutputROOT.h" #include "mpc/module/OutputCRPropa2.h" +#include "mpc/module/PhotonOutput.h" #include "mpc/module/SimplePropagation.h" #include "mpc/module/DeflectionCK.h" #include "mpc/module/Tools.h" @@ -73,12 +74,15 @@ using std::ptrdiff_t; { $action } - catch (const std::runtime_error& e) { + catch (const std::exception& e) { SWIG_exception(SWIG_RuntimeError, e.what()); } - catch (...) { - SWIG_exception(SWIG_RuntimeError, "unknown exception"); - } + catch (const char *e) { + SWIG_exception(SWIG_RuntimeError, e); + } + catch (Swig::DirectorException &e) { + SWIG_exception(SWIG_RuntimeError, e.getMessage()); + } } %ignore operator<<; @@ -114,7 +118,7 @@ using std::ptrdiff_t; %template(ModuleRefPtr) mpc::ref_ptr; %template(stdModuleList) std::list< mpc::ref_ptr >; -%feature("director") Module; +%feature("director") mpc::Module; %include "mpc/Module.h" %implicitconv mpc::ref_ptr; @@ -147,6 +151,7 @@ using std::ptrdiff_t; %include "mpc/module/Output.h" %include "mpc/module/OutputROOT.h" %include "mpc/module/OutputCRPropa2.h" +%include "mpc/module/PhotonOutput.h" %include "mpc/module/ElectronPairProduction.h" %include "mpc/module/StochasticInteraction.h" %include "mpc/module/NuclearDecay.h" diff --git a/src/module/PhotonOutput.cpp b/src/module/PhotonOutput.cpp new file mode 100644 index 000000000..1966cc841 --- /dev/null +++ b/src/module/PhotonOutput.cpp @@ -0,0 +1,144 @@ +#include "mpc/module/PhotonOutput.h" + +#include +#include + +#include "dint/prop_second.h" + +// Default cosmological parameters +#define DEFAULT_OMEGA_M 0.3 /**< Default value for _fOmegaM */ +#define DEFAULT_OMEGA_LAMBDA 0.7 /**< Default value for _fOmegaLambda */ +#define DEFAULT_H_0_KM_S_MPC 71. /**< Default value for _fH0 */ + +using namespace std; + +namespace mpc { + +PhotonOutput::PhotonOutput(const string &filename, ref_ptr field) : + filename(filename), fout(filename.c_str()), field(field), IRFlag(0), RadioFlag( + 0), H0(DEFAULT_H_0_KM_S_MPC), OmegaLambda(DEFAULT_OMEGA_LAMBDA), OmegaM( + DEFAULT_OMEGA_M), Zmax(5), Cutcascade_Magfield(0) { + dataPath = getDataPath("dint"); + +//TODO: implement ir and radio flags +#if 0 + if (_fpUniverse->Infrared()->Type() == IR_UNIFORM_HIGH) + IRFlag = 0; + if (_fpUniverse->Infrared()->Type() == IR_UNIFORM_LOW) + IRFlag = 1; + if (_fpUniverse->Infrared()->Type() == IR_UNIFORM_PRIMACK) + IRFlag = 2; +// if (lIRFlag != 2) cerr << "Warning : Low/high IR for dint not available otherwise.." << endl; + if (_fpUniverse->RadioBackground() == "High") + RadioFlag = 0; + if (_fpUniverse->RadioBackground() == "Med") + RadioFlag = 1; + if (_fpUniverse->RadioBackground() == "Obs") + RadioFlag = 2; + if (_fpUniverse->RadioBackground() == "Null") + RadioFlag = 3; +#endif +} + +PhotonOutput::~PhotonOutput() { +} + +void PhotonOutput::process(Candidate *candidate) const { + if (candidate->current.getId() != 22) + return; + + if (!candidate->hasProperty("Detected")) + return; + + // Initialize the energy grids for dint + dCVector energyGrid, energyWidth; + New_dCVector(&energyGrid, NUM_MAIN_BINS); + New_dCVector(&energyWidth, NUM_MAIN_BINS); + SetEnergyBins(MIN_ENERGY_EXP, &energyGrid, &energyWidth); + + // Initialize the spectrum + Spectrum inputSpectrum; + NewSpectrum(&inputSpectrum, NUM_MAIN_BINS); + string spectrum_string; + if (candidate->getProperty("PhotonSpectrum", spectrum_string)) { + stringstream spectrum_stream(spectrum_string); + for (size_t iSp = 0; iSp < NUM_SPECIES; iSp++) { + for (size_t iB = 0; iB < NUM_MAIN_BINS; iB++) { + spectrum_stream >> inputSpectrum.spectrum[iSp][iB]; + } + } + } else { + double criticalEnergy = candidate->current.getEnergy() + / (eV * ELECTRON_MASS); // units of dint + int maxBin = (int) ((log10(criticalEnergy * ELECTRON_MASS) + - MAX_ENERGY_EXP)*BINS_PER_DECADE + NUM_MAIN_BINS); + inputSpectrum.spectrum[PHOTON][maxBin] = 1.; + } + + // Initialize the positions + Vector3d position = candidate->current.getPosition(); + Vector3d initialPosition = candidate->initial.getPosition(); + string initial_string; + if (candidate->getProperty("PhotonInitialPosition", initial_string)) { + stringstream initial_stream(initial_string); + initial_stream >> initialPosition.x >> initialPosition.y + >> initialPosition.z; + } + + string initialType = "photon"; + candidate->getProperty("PhotonInitialType", initialType); + + double showerPropDistance = (initialPosition - position).getMag(); + + // Initialize the bField + dCVector bField; + //TODO: use resolution dependent step size + int bFieldSteps = showerPropDistance / (0.1 * Mpc); + New_dCVector(&bField, bFieldSteps); + Vector3d direction = (initialPosition - position).getUnitVector(); + for (int i = 0; i < bFieldSteps; i++) { + Vector3d p = initialPosition + + direction * showerPropDistance * (i + 0.5) / bFieldSteps; + Vector3d B = field->getField(p); + bField.vector[i] = B.perp(direction) / gauss; + } + + // Initialize output spectrum + Spectrum outputSpectrum; + NewSpectrum(&outputSpectrum, NUM_MAIN_BINS); + + prop_second(showerPropDistance / Mpc, &bField, &energyGrid, &energyWidth, + &inputSpectrum, &outputSpectrum, dataPath, IRFlag, Zmax, RadioFlag, + H0, OmegaM, OmegaLambda, Cutcascade_Magfield); + +#pragma omp critical + { + fout << 22 << " " << initialType << " " + << candidate->initial.getPosition() / Mpc << " " + << initialPosition / Mpc << " " << position / Mpc << " " + << candidate->current.getEnergy() << " " + << candidate->current.getDirection().x << " " + << candidate->current.getDirection().y << " " + << candidate->current.getDirection().z << " " + << candidate->initial.getEnergy() / Mpc << endl; + + for (int j = 0; j < outputSpectrum.numberOfMainBins; j++) { + fout << outputSpectrum.spectrum[0][j] << " "; // spectrum: mean number of particles per energy bin + } + fout << endl; + } + + DeleteSpectrum(&outputSpectrum); + DeleteSpectrum(&inputSpectrum); + Delete_dCVector(&bField); + Delete_dCVector(&energyGrid); + Delete_dCVector(&energyWidth); +} + +string PhotonOutput::getDescription() const { + std::stringstream s; + s << "PhotonModule: Output file = " << filename; + return s.str(); +} + +} // namespace mpc From 2227d91098720a302f67218d9b47d8b4e00f4748 Mon Sep 17 00:00:00 2001 From: geromueller Date: Tue, 9 Apr 2013 17:24:50 +0200 Subject: [PATCH 0294/1298] rename candidate->initial to source, add candidate created --- include/mpc/Candidate.h | 3 ++- src/Candidate.cpp | 8 +++++--- src/Source.cpp | 11 ++++++----- src/module/Boundary.cpp | 21 ++++++++++++++------- src/module/Output.cpp | 12 ++++++------ src/module/OutputCRPropa2.cpp | 16 ++++++++-------- src/module/PhotonOutput.cpp | 8 ++++---- 7 files changed, 45 insertions(+), 34 deletions(-) diff --git a/include/mpc/Candidate.h b/include/mpc/Candidate.h index 6eebc5184..c409312a1 100644 --- a/include/mpc/Candidate.h +++ b/include/mpc/Candidate.h @@ -39,7 +39,8 @@ struct InteractionState { */ class Candidate: public Referenced { public: - ParticleState initial; /**< Particle state at the beginning of propagation */ + ParticleState source; /**< Particle state at the source */ + ParticleState created; /**< Particle state at the creation */ ParticleState current; /**< Current particle state */ ParticleState previous; /**< Particle state at the end of the previous step */ diff --git a/src/Candidate.cpp b/src/Candidate.cpp index bade50c3f..f27e07138 100644 --- a/src/Candidate.cpp +++ b/src/Candidate.cpp @@ -8,8 +8,9 @@ Candidate::Candidate() : } Candidate::Candidate(const ParticleState &state) : - current(state), initial(state), previous(state), redshift(0), trajectoryLength( - 0), currentStep(0), nextStep(0), active(true) { + source(state), created(state), current(state), previous(state), redshift( + 0), trajectoryLength(0), currentStep(0), nextStep(0), active( + true) { } bool Candidate::isActive() const { @@ -117,7 +118,8 @@ void Candidate::addSecondary(int id, double energy) { ref_ptr secondary = new Candidate; secondary->setRedshift(redshift); secondary->setTrajectoryLength(trajectoryLength); - secondary->initial = initial; + secondary->source = source; + secondary->created = current; secondary->current = current; secondary->current.setId(id); secondary->current.setEnergy(energy); diff --git a/src/Source.cpp b/src/Source.cpp index 130df476f..68d04bf67 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -12,10 +12,11 @@ void SourceProperty::prepare(ParticleState& particle) const { } void SourceProperty::prepare(Candidate& candidate) const { - ParticleState &initial = candidate.initial; - prepare(initial); - candidate.current = initial; - candidate.previous = initial; + ParticleState &source = candidate.source; + prepare(source); + candidate.created = source; + candidate.current = source; + candidate.previous = source; } void Source::addProperty(SourceProperty* property) { @@ -320,7 +321,7 @@ void SourceUniformRedshift::prepare(Candidate& candidate) const { } void SourceRedshift1D::prepare(Candidate& candidate) const { - double d = candidate.initial.getPosition().getMag(); + double d = candidate.source.getPosition().getMag(); double z = comovingDistance2Redshift(d); candidate.setRedshift(z); } diff --git a/src/module/Boundary.cpp b/src/module/Boundary.cpp index 4a4abca73..3f29d34b6 100644 --- a/src/module/Boundary.cpp +++ b/src/module/Boundary.cpp @@ -21,7 +21,8 @@ void PeriodicBox::process(Candidate *c) const { c->current.setPosition(pos - n * size); c->previous.setPosition(c->previous.getPosition() - n * size); - c->initial.setPosition(c->initial.getPosition() - n * size); + c->source.setPosition(c->source.getPosition() - n * size); + c->created.setPosition(c->created.getPosition() - n * size); } void PeriodicBox::setOrigin(Vector3d o) { @@ -57,33 +58,39 @@ void ReflectiveBox::process(Candidate *c) const { Vector3d nReflect(pow(-1, n.x), pow(-1, n.y), pow(-1, n.z)); c->current.setDirection(c->current.getDirection() * nReflect); c->previous.setDirection(c->previous.getDirection() * nReflect); - c->initial.setDirection(c->initial.getDirection() * nReflect); + c->created.setDirection(c->created.getDirection() * nReflect); + c->source.setDirection(c->source.getDirection() * nReflect); - Vector3d ini = (c->initial.getPosition() - origin) / size; // initial position in cell units + Vector3d src = (c->source.getPosition() - origin) / size; // initial position in cell units + Vector3d cre = (c->created.getPosition() - origin) / size; // initial position in cell units Vector3d prv = (c->previous.getPosition() - origin) / size; // previous position in cell units // repeatedly translate until the current position is inside the cell while ((cur.x < 0) or (cur.x > 1)) { double t = 2 * (cur.x > 1); - ini.x = t - ini.x; + src.x = t - src.x; + cre.x = t - cre.x; prv.x = t - prv.x; cur.x = t - cur.x; } while ((cur.y < 0) or (cur.y > 1)) { double t = 2 * (cur.y > 1); - ini.y = t - ini.y; + src.y = t - src.y; + cre.y = t - cre.y; prv.y = t - prv.y; cur.y = t - cur.y; } while ((cur.z < 0) or (cur.z > 1)) { double t = 2 * (cur.z > 1); - ini.z = t - ini.z; + src.z = t - src.z; + cre.z = t - cre.z; prv.z = t - prv.z; cur.z = t - cur.z; } c->current.setPosition(cur * size + origin); - c->initial.setPosition(ini * size + origin); + c->source.setPosition(src * size + origin); + c->created.setPosition(cre * size + origin); c->previous.setPosition(prv * size + origin); } diff --git a/src/module/Output.cpp b/src/module/Output.cpp index e761caecb..a7d905143 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -92,16 +92,16 @@ void ConditionalOutput::process(Candidate *c) const { p += sprintf(buffer + p, "%8.3f\t", c->getTrajectoryLength() / Mpc); p += sprintf(buffer + p, "%10i\t", c->current.getId()); - p += sprintf(buffer + p, "%10i\t", c->initial.getId()); + p += sprintf(buffer + p, "%10i\t", c->source.getId()); p += sprintf(buffer + p, "%8.4f\t", c->current.getEnergy() / EeV); - p += sprintf(buffer + p, "%8.4f\t", c->initial.getEnergy() / EeV); + p += sprintf(buffer + p, "%8.4f\t", c->source.getEnergy() / EeV); Vector3d pos = c->current.getPosition() / Mpc; p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", pos.x, pos.y, pos.z); - Vector3d ipos = c->initial.getPosition() / Mpc; + Vector3d ipos = c->source.getPosition() / Mpc; p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", ipos.x, ipos.y, ipos.z); Vector3d dir = c->current.getDirection(); p += sprintf(buffer + p, "%8.5f\t%8.5f\t%8.5f\t", dir.x, dir.y, dir.z); - Vector3d idir = c->initial.getDirection(); + Vector3d idir = c->source.getDirection(); p += sprintf(buffer + p, "%8.5f\t%8.5f\t%8.5f\n", idir.x, idir.y, idir.z); #pragma omp critical @@ -166,8 +166,8 @@ void EventOutput1D::process(Candidate *c) const { p += sprintf(buffer + p, "%10i\t", c->current.getId()); p += sprintf(buffer + p, "%8.4f\t", c->current.getEnergy() / EeV); p += sprintf(buffer + p, "%9.4f\t", c->getTrajectoryLength() / Mpc); - p += sprintf(buffer + p, "%10i\t", c->initial.getId()); - p += sprintf(buffer + p, "%8.4f\n", c->initial.getEnergy() / EeV); + p += sprintf(buffer + p, "%10i\t", c->source.getId()); + p += sprintf(buffer + p, "%8.4f\n", c->source.getEnergy() / EeV); #pragma omp critical { diff --git a/src/module/OutputCRPropa2.cpp b/src/module/OutputCRPropa2.cpp index bc7af36ec..16599f114 100644 --- a/src/module/OutputCRPropa2.cpp +++ b/src/module/OutputCRPropa2.cpp @@ -27,14 +27,14 @@ void CRPropa2EventOutput3D::process(Candidate *c) const { size_t p = 0; // length of line p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->current.getId())); - p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->initial.getId())); + p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->source.getId())); - const Vector3d &ipos = c->initial.getPosition() / Mpc; + const Vector3d &ipos = c->source.getPosition() / Mpc; p += sprintf(buffer + p, "%.4f %.4f %.4f ", ipos.x, ipos.y, ipos.z); - double iPhi = c->initial.getDirection().getPhi(); - double iTheta = c->initial.getDirection().getTheta(); - double iE = c->initial.getEnergy() / EeV; + double iPhi = c->source.getDirection().getPhi(); + double iTheta = c->source.getDirection().getTheta(); + double iE = c->source.getEnergy() / EeV; p += sprintf(buffer + p, "%.4f %.4f %.4f ", iE, iPhi, iTheta); double t = c->getTrajectoryLength() / Mpc; @@ -72,7 +72,7 @@ void CRPropa2TrajectoryOutput3D::process(Candidate *c) const { size_t p = 0; p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->current.getId())); - p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->initial.getId())); + p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->source.getId())); p += sprintf(buffer + p, "%.4f ", c->getTrajectoryLength() / Mpc); const Vector3d &pos = c->current.getPosition() / Mpc; @@ -141,8 +141,8 @@ void CRPropa2EventOutput1D::process(Candidate *c) const { p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->current.getId())); p += sprintf(buffer + p, "%.4f ", c->current.getEnergy() / EeV); p += sprintf(buffer + p, "%.4f ", c->getTrajectoryLength() / Mpc); - p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->initial.getId())); - p += sprintf(buffer + p, "%.4f\n", c->initial.getEnergy() / EeV); + p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->source.getId())); + p += sprintf(buffer + p, "%.4f\n", c->source.getEnergy() / EeV); #pragma omp critical { diff --git a/src/module/PhotonOutput.cpp b/src/module/PhotonOutput.cpp index 1966cc841..fdbde7829 100644 --- a/src/module/PhotonOutput.cpp +++ b/src/module/PhotonOutput.cpp @@ -71,13 +71,13 @@ void PhotonOutput::process(Candidate *candidate) const { double criticalEnergy = candidate->current.getEnergy() / (eV * ELECTRON_MASS); // units of dint int maxBin = (int) ((log10(criticalEnergy * ELECTRON_MASS) - - MAX_ENERGY_EXP)*BINS_PER_DECADE + NUM_MAIN_BINS); + - MAX_ENERGY_EXP) * BINS_PER_DECADE + NUM_MAIN_BINS); inputSpectrum.spectrum[PHOTON][maxBin] = 1.; } // Initialize the positions Vector3d position = candidate->current.getPosition(); - Vector3d initialPosition = candidate->initial.getPosition(); + Vector3d initialPosition = candidate->created.getPosition(); string initial_string; if (candidate->getProperty("PhotonInitialPosition", initial_string)) { stringstream initial_stream(initial_string); @@ -114,13 +114,13 @@ void PhotonOutput::process(Candidate *candidate) const { #pragma omp critical { fout << 22 << " " << initialType << " " - << candidate->initial.getPosition() / Mpc << " " + << candidate->source.getPosition() / Mpc << " " << initialPosition / Mpc << " " << position / Mpc << " " << candidate->current.getEnergy() << " " << candidate->current.getDirection().x << " " << candidate->current.getDirection().y << " " << candidate->current.getDirection().z << " " - << candidate->initial.getEnergy() / Mpc << endl; + << candidate->source.getEnergy() / Mpc << endl; for (int j = 0; j < outputSpectrum.numberOfMainBins; j++) { fout << outputSpectrum.spectrum[0][j] << " "; // spectrum: mean number of particles per energy bin From baf7cf4542c609b00d8bec64887aba16f1923511 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 12 Apr 2013 09:21:44 +0200 Subject: [PATCH 0295/1298] fix bug that, for SWIG, included the install dir before the source dir --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 421c900e6..e3a454b9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -202,7 +202,7 @@ if(ENABLE_PYTHON) file(GLOB_RECURSE MPC_INCLUDES include/*.h) set_source_files_properties( ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx PROPERTIES GENERATED true ) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx - COMMAND swig -c++ -python ${MPC_SWIG_DEFINES} -I${CMAKE_SOURCE_DIR}/include -o ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx -outdir ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/python/mpc.i + COMMAND swig -c++ -python -I${CMAKE_SOURCE_DIR}/include ${MPC_SWIG_DEFINES} -o ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx -outdir ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/python/mpc.i DEPENDS ${CMAKE_SOURCE_DIR}/python/mpc.i ${MPC_INCLUDES} ) add_library(mpc-swig MODULE ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx) set_target_properties(mpc-swig PROPERTIES PREFIX "") From d1cff81205ea3d37b26bd2d01b100ec529c1f554 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 12 Apr 2013 11:13:41 +0200 Subject: [PATCH 0296/1298] enforce flatness of universe in cosmology --- include/mpc/Cosmology.h | 7 ++++--- src/Cosmology.cpp | 10 +++++----- src/XmlExecute.cpp | 4 ++-- test/python/testCosmology.py | 2 +- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/include/mpc/Cosmology.h b/include/mpc/Cosmology.h index 26fa978c3..fa441dff8 100644 --- a/include/mpc/Cosmology.h +++ b/include/mpc/Cosmology.h @@ -4,10 +4,11 @@ namespace mpc { /** - Set the cosmological parameters for a flat universe. + Set the cosmological parameters for a flat universe. To ensure flatness omegaL is set to 1 - omegaMatter + @param hubbleParameter dimensionless Hubble parameter, default = 0.7 + @param omegaMatter matter parameter, default = 0.3 */ -void setCosmologyParameters(double hubbleParameter, double omegaMatter, - double omegaVacuum); +void setCosmologyParameters(double hubbleParameter, double omegaMatter); /** Hubble rate at given redshift diff --git a/src/Cosmology.cpp b/src/Cosmology.cpp index e74b489d8..47a4c19fd 100644 --- a/src/Cosmology.cpp +++ b/src/Cosmology.cpp @@ -50,7 +50,7 @@ struct Cosmology { Cosmology() { H0 = 71 * 1000 * meter / second / Mpc; // default values omegaM = 0.3; - omegaL = 0.7; + omegaL = 1 - omegaM; Z.resize(n); Dc.resize(n); @@ -65,10 +65,10 @@ struct Cosmology { update(); } - void setParameters(double h, double oM, double oL) { + void setParameters(double h, double oM) { H0 = h * 1e5 / Mpc; omegaM = oM; - omegaL = oL; + omegaL = 1 - oM; update(); } }; @@ -77,8 +77,8 @@ static Cosmology cosmology; // instance is created at runtime -void setCosmologyParameters(double h, double oM, double oL) { - cosmology.setParameters(h, oM, oL); +void setCosmologyParameters(double h, double oM) { + cosmology.setParameters(h, oM); } double hubbleRate(double z) { diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 959f0016c..432d6b21b 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -225,8 +225,8 @@ bool XmlExecute::load(const string &filename) { childValue(root, "H0_km_s_Mpc"); cout << "Cosmology: OmegaM = " << omegaM << ", OmegaLambda = " - << omegaL << ", H0 = " << H0 << " km/s/Mpc" << endl; - setCosmologyParameters(H0 / 100, omegaM, omegaL); + << 1 - omegaM << ", H0 = " << H0 << " km/s/Mpc" << endl; + setCosmologyParameters(H0 / 100, omegaM); } else { cout << " - No redshift" << endl; } diff --git a/test/python/testCosmology.py b/test/python/testCosmology.py index 939848ea9..af31e16ef 100644 --- a/test/python/testCosmology.py +++ b/test/python/testCosmology.py @@ -3,7 +3,7 @@ from pylab import * -setCosmologyParameters(0.71, 0.27, 0.73) +setCosmologyParameters(0.71, 0.27) N = 100 Z = logspace(-4, 2, N) From 3ba6ed3781c1effa6ea784db09b128e7b7439859 Mon Sep 17 00:00:00 2001 From: geromueller Date: Tue, 16 Apr 2013 08:49:48 +0200 Subject: [PATCH 0297/1298] fix tests --- test/testBreakCondition.cpp | 38 +++++++++++++++++++++---------------- test/testCore.cpp | 14 +++++++------- test/testPropagation.cpp | 4 ++-- test/testSource.cpp | 6 +++--- 4 files changed, 34 insertions(+), 28 deletions(-) diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index 50362ded6..8c519abb7 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -148,16 +148,16 @@ TEST(PeriodicBox, high) { Candidate c; c.current.setPosition(Vector3d(4.5, 4.3, 4.4)); - c.initial.setPosition(Vector3d(3, 3, 3)); + c.created.setPosition(Vector3d(3, 3, 3)); box.process(&c); EXPECT_DOUBLE_EQ(2.5, c.current.getPosition().x); - EXPECT_DOUBLE_EQ(1, c.initial.getPosition().x); + EXPECT_DOUBLE_EQ(1, c.created.getPosition().x); EXPECT_DOUBLE_EQ(2.3, c.current.getPosition().y); - EXPECT_DOUBLE_EQ(1, c.initial.getPosition().y); + EXPECT_DOUBLE_EQ(1, c.created.getPosition().y); EXPECT_DOUBLE_EQ(2.4, c.current.getPosition().z); - EXPECT_DOUBLE_EQ(1, c.initial.getPosition().z); + EXPECT_DOUBLE_EQ(1, c.created.getPosition().z); } TEST(PeriodicBox, low) { @@ -168,16 +168,16 @@ TEST(PeriodicBox, low) { Candidate c; c.current.setPosition(Vector3d(-2.5, -0.3, -0.4)); - c.initial.setPosition(Vector3d(1, 1, 1)); + c.created.setPosition(Vector3d(1, 1, 1)); box.process(&c); EXPECT_DOUBLE_EQ(1.5, c.current.getPosition().x); - EXPECT_DOUBLE_EQ(5, c.initial.getPosition().x); + EXPECT_DOUBLE_EQ(5, c.created.getPosition().x); EXPECT_DOUBLE_EQ(1.7, c.current.getPosition().y); - EXPECT_DOUBLE_EQ(3, c.initial.getPosition().y); + EXPECT_DOUBLE_EQ(3, c.created.getPosition().y); EXPECT_DOUBLE_EQ(1.6, c.current.getPosition().z); - EXPECT_DOUBLE_EQ(3, c.initial.getPosition().z); + EXPECT_DOUBLE_EQ(3, c.created.getPosition().z); } TEST(ReflectiveBox, high) { @@ -188,8 +188,10 @@ TEST(ReflectiveBox, high) { ReflectiveBox box(origin, size); Candidate c; - c.initial.setPosition(Vector3d(15, 15, 15)); - c.initial.setDirection(Vector3d(0, 0.6, 0.8)); + c.source.setPosition(Vector3d(16, 17, 18)); + c.source.setDirection(Vector3d(1, 1.6, 1.8)); + c.created.setPosition(Vector3d(15, 15, 15)); + c.created.setDirection(Vector3d(0, 0.6, 0.8)); c.previous.setPosition(Vector3d(15, 15, 29.5)); c.previous.setDirection(Vector3d(0, 0.6, 0.8)); c.current.setPosition(Vector3d(15, 15, 30.5)); @@ -197,9 +199,13 @@ TEST(ReflectiveBox, high) { box.process(&c); - EXPECT_DOUBLE_EQ(15, c.initial.getPosition().x); - EXPECT_DOUBLE_EQ(15, c.initial.getPosition().y); - EXPECT_DOUBLE_EQ(45, c.initial.getPosition().z); + EXPECT_DOUBLE_EQ(16, c.source.getPosition().x); + EXPECT_DOUBLE_EQ(17, c.source.getPosition().y); + EXPECT_DOUBLE_EQ(42, c.source.getPosition().z); + + EXPECT_DOUBLE_EQ(15, c.created.getPosition().x); + EXPECT_DOUBLE_EQ(15, c.created.getPosition().y); + EXPECT_DOUBLE_EQ(45, c.created.getPosition().z); EXPECT_DOUBLE_EQ(15, c.previous.getPosition().x); EXPECT_DOUBLE_EQ(15, c.previous.getPosition().y); @@ -209,9 +215,9 @@ TEST(ReflectiveBox, high) { EXPECT_DOUBLE_EQ(15, c.current.getPosition().y); EXPECT_DOUBLE_EQ(29.5, c.current.getPosition().z); - EXPECT_DOUBLE_EQ(0, c.initial.getDirection().x); - EXPECT_DOUBLE_EQ(0.6, c.initial.getDirection().y); - EXPECT_DOUBLE_EQ(-0.8, c.initial.getDirection().z); + EXPECT_DOUBLE_EQ(0, c.created.getDirection().x); + EXPECT_DOUBLE_EQ(0.6, c.created.getDirection().y); + EXPECT_DOUBLE_EQ(-0.8, c.created.getDirection().z); EXPECT_DOUBLE_EQ(0, c.previous.getDirection().x); EXPECT_DOUBLE_EQ(0.6, c.previous.getDirection().y); diff --git a/test/testCore.cpp b/test/testCore.cpp index a4d2e6d47..a99e937ea 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -148,10 +148,10 @@ TEST(Candidate, addSecondary) { Candidate c; c.setRedshift(5); c.setTrajectoryLength(23); - c.initial.setId(nucleusId(56,26)); - c.initial.setEnergy(1000); - c.initial.setPosition(Vector3d(1,2,3)); - c.initial.setDirection(Vector3d(0,0,1)); + c.current.setId(nucleusId(56,26)); + c.current.setEnergy(1000); + c.current.setPosition(Vector3d(1,2,3)); + c.current.setDirection(Vector3d(0,0,1)); c.addSecondary(nucleusId(1,1), 200); Candidate s = *c.secondaries[0]; @@ -161,9 +161,9 @@ TEST(Candidate, addSecondary) { EXPECT_EQ(5, s.getRedshift()); EXPECT_EQ(23, s.getTrajectoryLength()); - EXPECT_EQ(1000, s.initial.getEnergy()); - EXPECT_TRUE(Vector3d(1,2,3) == s.initial.getPosition()); - EXPECT_TRUE(Vector3d(0,0,1) == s.initial.getDirection()); + EXPECT_EQ(1000, s.created.getEnergy()); + EXPECT_TRUE(Vector3d(1,2,3) == s.created.getPosition()); + EXPECT_TRUE(Vector3d(0,0,1) == s.created.getDirection()); } TEST(common, digit) { diff --git a/test/testPropagation.cpp b/test/testPropagation.cpp index 80494af2d..b21d481b2 100644 --- a/test/testPropagation.cpp +++ b/test/testPropagation.cpp @@ -22,8 +22,8 @@ TEST(testSimplePropagation, step) { EXPECT_EQ(minStep, c.getCurrentStep()); EXPECT_EQ(maxStep, c.getNextStep()); - EXPECT_EQ(Vector3d(0, 0, 0), c.initial.getPosition()); - EXPECT_EQ(Vector3d(0, 1, 0), c.initial.getDirection()); + EXPECT_EQ(Vector3d(0, 0, 0), c.created.getPosition()); + EXPECT_EQ(Vector3d(0, 1, 0), c.created.getDirection()); EXPECT_EQ(Vector3d(0, 0, 0), c.previous.getPosition()); EXPECT_EQ(Vector3d(0, 1, 0), c.previous.getDirection()); EXPECT_EQ(Vector3d(0, 20, 0), c.current.getPosition()); diff --git a/test/testSource.cpp b/test/testSource.cpp index 13c1cfa75..6302d2074 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -194,7 +194,7 @@ TEST(Source, allPropertiesUsed) { Candidate c = *source.getCandidate(); - ParticleState p = c.initial; + ParticleState p = c.created; EXPECT_EQ(8, p.getMassNumber()); EXPECT_EQ(4, p.getChargeNumber()); EXPECT_LE(5 * EeV, p.getEnergy()); @@ -225,7 +225,7 @@ TEST(SourceList, simpleTest) { ref_ptr c = sourceList.getCandidate(); - EXPECT_EQ(Vector3d(10, 0, 0), c->initial.getPosition()); + EXPECT_EQ(Vector3d(10, 0, 0), c->created.getPosition()); EXPECT_EQ(Vector3d(10, 0, 0), c->previous.getPosition()); EXPECT_EQ(Vector3d(10, 0, 0), c->current.getPosition()); } @@ -251,7 +251,7 @@ TEST(SourceList, luminosity) { double meanE = 0; for (int i = 0; i < 1000; i++) { ref_ptr c = sourceList.getCandidate(); - meanE += c->initial.getEnergy(); + meanE += c->created.getEnergy(); } meanE /= 1000; EXPECT_NEAR(80, meanE, 2); From d0f5e9b530bbbf322333384bffe918e4837ecfa7 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 16 Apr 2013 09:29:09 +0200 Subject: [PATCH 0298/1298] PhotonOutput takes the global cosmology parameters --- include/mpc/Cosmology.h | 6 ++++++ include/mpc/module/PhotonOutput.h | 1 - src/Cosmology.cpp | 8 ++++++++ src/module/PhotonOutput.cpp | 15 ++++++--------- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/include/mpc/Cosmology.h b/include/mpc/Cosmology.h index fa441dff8..fd4df9ab9 100644 --- a/include/mpc/Cosmology.h +++ b/include/mpc/Cosmology.h @@ -16,6 +16,12 @@ void setCosmologyParameters(double hubbleParameter, double omegaMatter); */ double hubbleRate(double redshift = 0); +// Returns the dark energy density parameter +double omegaL(); + +// Returns the matter density parameter +double omegaM(); + /** Redshift of a comoving object at a given comoving distance to an observer at z = 0. d_comoving(z) = c/H0 * int_0^z dz' / E(z') diff --git a/include/mpc/module/PhotonOutput.h b/include/mpc/module/PhotonOutput.h index b91cd2753..d72230d32 100644 --- a/include/mpc/module/PhotonOutput.h +++ b/include/mpc/module/PhotonOutput.h @@ -15,7 +15,6 @@ class PhotonOutput: public Module { ref_ptr field; int IRFlag, RadioFlag; - double H0, OmegaLambda, OmegaM; double Zmax, Cutcascade_Magfield; public: diff --git a/src/Cosmology.cpp b/src/Cosmology.cpp index 47a4c19fd..1daea625f 100644 --- a/src/Cosmology.cpp +++ b/src/Cosmology.cpp @@ -86,6 +86,14 @@ double hubbleRate(double z) { * sqrt(cosmology.omegaL + cosmology.omegaM * pow(1 + z, 3)); } +double omegaL() { + return cosmology.omegaL; +} + +double omegaM() { + return cosmology.omegaM; +} + double comovingDistance2Redshift(double d) { if (d < 0) throw std::runtime_error("Cosmology: d < 0"); diff --git a/src/module/PhotonOutput.cpp b/src/module/PhotonOutput.cpp index fdbde7829..58cd9e856 100644 --- a/src/module/PhotonOutput.cpp +++ b/src/module/PhotonOutput.cpp @@ -1,23 +1,18 @@ #include "mpc/module/PhotonOutput.h" +#include "mpc/Cosmology.h" #include #include #include "dint/prop_second.h" -// Default cosmological parameters -#define DEFAULT_OMEGA_M 0.3 /**< Default value for _fOmegaM */ -#define DEFAULT_OMEGA_LAMBDA 0.7 /**< Default value for _fOmegaLambda */ -#define DEFAULT_H_0_KM_S_MPC 71. /**< Default value for _fH0 */ - using namespace std; namespace mpc { PhotonOutput::PhotonOutput(const string &filename, ref_ptr field) : filename(filename), fout(filename.c_str()), field(field), IRFlag(0), RadioFlag( - 0), H0(DEFAULT_H_0_KM_S_MPC), OmegaLambda(DEFAULT_OMEGA_LAMBDA), OmegaM( - DEFAULT_OMEGA_M), Zmax(5), Cutcascade_Magfield(0) { + 0), Zmax(5), Cutcascade_Magfield(0) { dataPath = getDataPath("dint"); //TODO: implement ir and radio flags @@ -71,7 +66,7 @@ void PhotonOutput::process(Candidate *candidate) const { double criticalEnergy = candidate->current.getEnergy() / (eV * ELECTRON_MASS); // units of dint int maxBin = (int) ((log10(criticalEnergy * ELECTRON_MASS) - - MAX_ENERGY_EXP) * BINS_PER_DECADE + NUM_MAIN_BINS); + - MAX_ENERGY_EXP)* BINS_PER_DECADE + NUM_MAIN_BINS); inputSpectrum.spectrum[PHOTON][maxBin] = 1.; } @@ -107,9 +102,11 @@ void PhotonOutput::process(Candidate *candidate) const { Spectrum outputSpectrum; NewSpectrum(&outputSpectrum, NUM_MAIN_BINS); + double H0 = hubbleRate(0) * Mpc / 1000; // Hubble constant in [km/s/Mpc] + prop_second(showerPropDistance / Mpc, &bField, &energyGrid, &energyWidth, &inputSpectrum, &outputSpectrum, dataPath, IRFlag, Zmax, RadioFlag, - H0, OmegaM, OmegaLambda, Cutcascade_Magfield); + H0, omegaL(), omegaM(), Cutcascade_Magfield); #pragma omp critical { From 04e9ded2c6ba0fd3c2db62dfc40793cc40ddeb9e Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 3 May 2013 12:13:21 +0200 Subject: [PATCH 0299/1298] cosmetic changes in JF12Field --- CMakeLists.txt | 2 +- .../{JF2012Field.h => JF12Field.h} | 31 ++++++++----- .../{JF2012Field.cpp => JF12Field.cpp} | 46 +++++++++---------- 3 files changed, 44 insertions(+), 35 deletions(-) rename include/mpc/magneticField/{JF2012Field.h => JF12Field.h} (82%) rename src/magneticField/{JF2012Field.cpp => JF12Field.cpp} (85%) diff --git a/CMakeLists.txt b/CMakeLists.txt index fb4748adc..3463cc317 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,7 +138,7 @@ add_library(mpc SHARED src/magneticField/MagneticField.cpp src/magneticField/MagneticFieldGrid.cpp src/magneticField/TurbulentMagneticField.cpp - src/magneticField/JF2012Field.cpp + src/magneticField/JF12Field.cpp ${MPC_EXTRA_SOURCES} ) target_link_libraries(mpc ${MPC_EXTRA_LIBRARIES}) diff --git a/include/mpc/magneticField/JF2012Field.h b/include/mpc/magneticField/JF12Field.h similarity index 82% rename from include/mpc/magneticField/JF2012Field.h rename to include/mpc/magneticField/JF12Field.h index 0c2176bfe..75af1be50 100644 --- a/include/mpc/magneticField/JF2012Field.h +++ b/include/mpc/magneticField/JF12Field.h @@ -1,5 +1,5 @@ -#ifndef MPC_JF2012FIELD_H -#define MPC_JF2012FIELD_H +#ifndef MPC_JF12FIELD_H +#define MPC_JF12FIELD_H #include "mpc/magneticField/MagneticField.h" #include "mpc/Grid.h" @@ -7,16 +7,25 @@ namespace mpc { /** - @class JF2012 - @brief JF2012 galactic magnetic field model + @class JF12Field + @brief JF12Field galactic magnetic field model Implements the JF2012 magnetic field model, consisting of a large-scale regular and random (striated) field and a small-scale random (turbulent) field. - The field is described in + See: Jansson 2012a, ApJ. 757, A New Model of the Galactic Magnetic Field Jansson 2012b, arXiv:1210.7820, The Galactic Magnetic Field + + All three components may individually turned on and off. + Currently only best fit values of the field paramaters are implemented and + cannot be changed. + + The field is defined in the usual galactocentric coordinate system with the + Galactic center at the origin, the x-axis pointing in the opposite direction of + the Sun, and the z-axis pointing towards Galactic north. */ -class JF2012Field: public MagneticField { +class JF12Field: public MagneticField { +private: bool useRegular; bool useStriated; bool useTurbulent; @@ -26,7 +35,7 @@ class JF2012Field: public MagneticField { double pitch; // pitch angle double sinPitch, cosPitch, tan90MinusPitch; - // Regular field --------------------------------------------------------- + // Regular field ---------------------------------------------------------- // disk double bDisk[8]; // field strengths of arms at r=5 kpc double bRing; // ring field strength 3 striatedGrid; - // Turbulent field ------------------------------------------- + // Turbulent field -------------------------------------------------------- ref_ptr turbulentGrid; // disk double bDiskTurb[8]; // field strengths in arms at r=5 kpc @@ -58,7 +67,7 @@ class JF2012Field: public MagneticField { double zHaloTurb; // Gaussian scale height public: - JF2012Field(); + JF12Field(); // Create and set a random realization for the striated field void randomStriated(int seed = 0); @@ -109,4 +118,4 @@ class JF2012Field: public MagneticField { } // namespace mpc -#endif // MPC_JF2012FIELD_H +#endif // MPC_JF12FIELD_H diff --git a/src/magneticField/JF2012Field.cpp b/src/magneticField/JF12Field.cpp similarity index 85% rename from src/magneticField/JF2012Field.cpp rename to src/magneticField/JF12Field.cpp index fcf654ab0..dd4ecf69d 100644 --- a/src/magneticField/JF2012Field.cpp +++ b/src/magneticField/JF12Field.cpp @@ -1,4 +1,4 @@ -#include "mpc/magneticField/JF2012Field.h" +#include "mpc/magneticField/JF12Field.h" #include "mpc/Units.h" #include "mpc/GridTools.h" #include "mpc/Random.h" @@ -11,12 +11,12 @@ double logisticFunction(double x, double x0, double w) { return 1. / (1. + exp(-2. * (fabs(x) - x0) / w)); } -JF2012Field::JF2012Field() { +JF12Field::JF12Field() { useRegular = true; useStriated = false; useTurbulent = false; - // spiral arms + // spiral arm parameters pitch = 11.5 * M_PI / 180; sinPitch = sin(pitch); cosPitch = cos(pitch); @@ -31,7 +31,7 @@ JF2012Field::JF2012Field() { rArms[6] = 12.7 * kpc; rArms[7] = 15.5 * kpc; - // regular field + // regular field parameters bRing = 0.1 * muG; hDisk = 0.40 * kpc; wDisk = 0.27 * kpc; @@ -60,10 +60,10 @@ JF2012Field::JF2012Field() { rXc = 4.8 * kpc; rX = 2.9 * kpc; - // striated field + // striated field parameter sqrtbeta = sqrt(1.36); - // turbulent field + // turbulent field parameters bDiskTurb[0] = 10.81 * muG; bDiskTurb[1] = 6.96 * muG; bDiskTurb[2] = 9.59 * muG; @@ -81,7 +81,7 @@ JF2012Field::JF2012Field() { zHaloTurb = 2.84 * kpc; } -void JF2012Field::randomStriated(int seed) { +void JF12Field::randomStriated(int seed) { useStriated = true; int N = 100; striatedGrid = new ScalarGrid(Vector3d(0.), N, 0.1 * kpc); @@ -99,7 +99,7 @@ void JF2012Field::randomStriated(int seed) { } #ifdef MPC_HAVE_FFTW3F -void JF2012Field::randomTurbulent(int seed) { +void JF12Field::randomTurbulent(int seed) { useTurbulent = true; // turbulent field with Kolmogorov spectrum, B_rms = 1 and Lc = 60 parsec turbulentGrid = new VectorGrid(Vector3d(0.), 256, 4 * parsec); @@ -108,29 +108,29 @@ void JF2012Field::randomTurbulent(int seed) { } #endif -void JF2012Field::setStriatedGrid(ref_ptr grid) { +void JF12Field::setStriatedGrid(ref_ptr grid) { useStriated = true; striatedGrid = grid; } -void JF2012Field::setTurbulentGrid(ref_ptr grid) { +void JF12Field::setTurbulentGrid(ref_ptr grid) { useTurbulent = true; turbulentGrid = grid; } -ref_ptr JF2012Field::getStriatedGrid() { +ref_ptr JF12Field::getStriatedGrid() { return striatedGrid; } -ref_ptr JF2012Field::getTurbulentGrid() { +ref_ptr JF12Field::getTurbulentGrid() { return turbulentGrid; } -void JF2012Field::setUseRegular(bool use) { +void JF12Field::setUseRegular(bool use) { useRegular = use; } -void JF2012Field::setUseStriated(bool use) { +void JF12Field::setUseStriated(bool use) { if ((use) and (striatedGrid)) { std::cout << "JF12Field: No striated field set: ignored" << std::endl; return; @@ -138,7 +138,7 @@ void JF2012Field::setUseStriated(bool use) { useStriated = use; } -void JF2012Field::setUseTurbulent(bool use) { +void JF12Field::setUseTurbulent(bool use) { if ((use) and (turbulentGrid)) { std::cout << "JF12Field: No turbulent field set: ignored" << std::endl; return; @@ -146,19 +146,19 @@ void JF2012Field::setUseTurbulent(bool use) { useTurbulent = use; } -bool JF2012Field::isUsingRegular() { +bool JF12Field::isUsingRegular() { return useRegular; } -bool JF2012Field::isUsingStriated() { +bool JF12Field::isUsingStriated() { return useStriated; } -bool JF2012Field::isUsingTurbulent() { +bool JF12Field::isUsingTurbulent() { return useTurbulent; } -Vector3d JF2012Field::getRegularField(const Vector3d& pos) const { +Vector3d JF12Field::getRegularField(const Vector3d& pos) const { Vector3d b(0.); double r = sqrt(pos.x * pos.x + pos.y * pos.y); // in-plane radius @@ -237,12 +237,12 @@ Vector3d JF2012Field::getRegularField(const Vector3d& pos) const { return b; } -Vector3d JF2012Field::getStriatedField(const Vector3d& pos) const { +Vector3d JF12Field::getStriatedField(const Vector3d& pos) const { return (getRegularField(pos) * (1. + sqrtbeta * striatedGrid->closestValue(pos))); } -double JF2012Field::getTurbulentStrength(const Vector3d& pos) const { +double JF12Field::getTurbulentStrength(const Vector3d& pos) const { if (pos.getMag() > 20 * kpc) return 0; @@ -276,11 +276,11 @@ double JF2012Field::getTurbulentStrength(const Vector3d& pos) const { return sqrt(pow(bDisk, 2) + pow(bHalo, 2)); } -Vector3d JF2012Field::getTurbulentField(const Vector3d& pos) const { +Vector3d JF12Field::getTurbulentField(const Vector3d& pos) const { return (turbulentGrid->interpolate(pos) * getTurbulentStrength(pos)); } -Vector3d JF2012Field::getField(const Vector3d& pos) const { +Vector3d JF12Field::getField(const Vector3d& pos) const { Vector3d b(0.); if (useTurbulent) b += getTurbulentField(pos); From 021c33df57bd2cd5a71f01a01ebe26e39e1f62c3 Mon Sep 17 00:00:00 2001 From: geromueller Date: Fri, 3 May 2013 16:14:58 +0200 Subject: [PATCH 0300/1298] switch from gadget to quimby --- CMakeLists.txt | 20 +++++------ cmake/FindGadget.cmake | 19 ---------- cmake/FindQuimby.cmake | 19 ++++++++++ .../mpc/magneticField/GadgetMagneticField.h | 36 ------------------- .../mpc/magneticField/QuimbyMagneticField.h | 36 +++++++++++++++++++ python/mpc.i | 8 ++--- 6 files changed, 69 insertions(+), 69 deletions(-) delete mode 100644 cmake/FindGadget.cmake create mode 100644 cmake/FindQuimby.cmake delete mode 100644 include/mpc/magneticField/GadgetMagneticField.h create mode 100644 include/mpc/magneticField/QuimbyMagneticField.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fb4748adc..a6e46c2c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,16 +66,16 @@ if(ENABLE_FFTW3F) endif(FFTW3F_FOUND) endif(ENABLE_FFTW3F) -# gadget (optional for SPH magnetic fields) -find_package(Gadget) -if(GADGET_FOUND) - list(APPEND MPC_EXTRA_INCLUDES ${GADGET_INCLUDE_DIR}) - list(APPEND MPC_EXTRA_LIBRARIES ${GADGET_LIBRARY}) - add_definitions (-DMPC_HAVE_GADGET) - list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_GADGET) - list(APPEND MPC_SWIG_DEFINES -I${GADGET_INCLUDE_DIR}/../share/gadget) - list(APPEND MPC_SWIG_DEFINES -I${GADGET_INCLUDE_DIR}) -endif(GADGET_FOUND) +# Quimby (optional for SPH magnetic fields) +find_package(Quimby) +if(QUIMBY_FOUND) + list(APPEND MPC_EXTRA_INCLUDES ${QUIMBY_INCLUDE_DIR}) + list(APPEND MPC_EXTRA_LIBRARIES ${QUIMBY_LIBRARY}) + add_definitions (-DMPC_HAVE_QUIMBY) + list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_QUIMBY) + list(APPEND MPC_SWIG_DEFINES -I${QUIMBY_INCLUDE_DIR}/../share/quimby) + list(APPEND MPC_SWIG_DEFINES -I${QUIMBY_INCLUDE_DIR}) +endif(QUIMBY_FOUND) # ROOT (optional for ROOT output) option(ENABLE_ROOT "ROOT Output" ON) diff --git a/cmake/FindGadget.cmake b/cmake/FindGadget.cmake deleted file mode 100644 index 7604d4d89..000000000 --- a/cmake/FindGadget.cmake +++ /dev/null @@ -1,19 +0,0 @@ -# GADGET_INCLUDE_DIR = path to gadget directory -# GADGET_LIBRARY = libGadget.a -# GADGET_FOUND = true if gadget is found - -find_path(GADGET_INCLUDE_DIR gadget/SmoothParticle.h) -find_library(GADGET_LIBRARY Gadget) - -set(GADGET_FOUND FALSE) -if(GADGET_INCLUDE_DIR AND GADGET_LIBRARY) - set(GADGET_FOUND TRUE) - MESSAGE(STATUS "Gadget: Found!") -else() - MESSAGE(STATUS "Gadget: NOT Found!") -endif() - -MESSAGE(STATUS " Include: ${GADGET_INCLUDE_DIR}") -MESSAGE(STATUS " Library: ${GADGET_LIBRARY}") - -mark_as_advanced(GADGET_INCLUDE_DIR GADGET_LIBRARY GADGET_FOUND) diff --git a/cmake/FindQuimby.cmake b/cmake/FindQuimby.cmake new file mode 100644 index 000000000..d29201a56 --- /dev/null +++ b/cmake/FindQuimby.cmake @@ -0,0 +1,19 @@ +# QUIMBY_INCLUDE_DIR = path to Quimby directory +# QUIMBY_LIBRARY = libQuimby.a +# QUIMBY_FOUND = true if Quimby is found + +find_path(QUIMBY_INCLUDE_DIR quimby/SmoothParticle.h) +find_library(QUIMBY_LIBRARY Quimby) + +set(QUIMBY_FOUND FALSE) +if(QUIMBY_INCLUDE_DIR AND QUIMBY_LIBRARY) + set(QUIMBY_FOUND TRUE) + MESSAGE(STATUS "Quimby: Found!") +else() + MESSAGE(STATUS "Quimby: NOT Found!") +endif() + +MESSAGE(STATUS " Include: ${QUIMBY_INCLUDE_DIR}") +MESSAGE(STATUS " Library: ${QUIMBY_LIBRARY}") + +mark_as_advanced(QUIMBY_INCLUDE_DIR QUIMBY_LIBRARY QUIMBY_FOUND) diff --git a/include/mpc/magneticField/GadgetMagneticField.h b/include/mpc/magneticField/GadgetMagneticField.h deleted file mode 100644 index 6ce680c6e..000000000 --- a/include/mpc/magneticField/GadgetMagneticField.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef MPC_GADGETMAGNETICFIELD_H_ -#define MPC_GADGETMAGNETICFIELD_H_ - -#ifdef MPC_HAVE_GADGET - -#include "mpc/Units.h" -#include "mpc/magneticField/MagneticField.h" - -#include "gadget/MagneticField.h" - -namespace mpc { - -/** - @class GadgetMagneticField - @brief Wrapper for gadget::MagneticField - */ -class GadgetMagneticField: public MagneticField { - gadget::ref_ptr field; -public: - GadgetMagneticField(gadget::ref_ptr field) : field(field) { - - } - Vector3d getField(const Vector3d &position) const { - gadget::Vector3f b, r = gadget::Vector3f(position.x, position.y, position.z); - bool isGood = field->getField(r / kpc, b); - if (!isGood) - std::cerr << "mpc::SPHMagneticField invalid position : " << position - << std::endl; - return Vector3d(b.x, b.y, b.z) * gauss; - } -}; - -} // namespace mpc - -#endif // MPC_HAVE_GADGET -#endif // MPC_GADGETMAGNETICFIELD_H_ diff --git a/include/mpc/magneticField/QuimbyMagneticField.h b/include/mpc/magneticField/QuimbyMagneticField.h new file mode 100644 index 000000000..07926cc86 --- /dev/null +++ b/include/mpc/magneticField/QuimbyMagneticField.h @@ -0,0 +1,36 @@ +#ifndef MPC_QUIMBYMAGNETICFIELD_H_ +#define MPC_QUIMBYMAGNETICFIELD_H_ + +#ifdef MPC_HAVE_QUIMBY + +#include "mpc/Units.h" +#include "mpc/magneticField/MagneticField.h" + +#include "quimby/MagneticField.h" + +namespace mpc { + +/** + @class QuimbyMagneticField + @brief Wrapper for quimby::MagneticField + */ +class QuimbyMagneticField: public MagneticField { + quimby::ref_ptr field; +public: + QuimbyMagneticField(quimby::ref_ptr field) : field(field) { + + } + Vector3d getField(const Vector3d &position) const { + quimby::Vector3f b, r = quimby::Vector3f(position.x, position.y, position.z); + bool isGood = field->getField(r / kpc, b); + if (!isGood) + std::cerr << "mpc::SPHMagneticField invalid position : " << position + << std::endl; + return Vector3d(b.x, b.y, b.z) * gauss; + } +}; + +} // namespace mpc + +#endif // MPC_HAVE_QUIMBY +#endif // MPC_QUIMBYMAGNETICFIELD_H_ diff --git a/python/mpc.i b/python/mpc.i index ff7a5be2a..15cb8d0d2 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -20,8 +20,8 @@ using std::ptrdiff_t; %include std_container.i %include "exception.i" -#ifdef MPC_HAVE_GADGET -%import (module="gadget") gadget.i +#ifdef MPC_HAVE_QUIMBY +%import (module="quimby") quimby.i #endif %{ @@ -44,7 +44,7 @@ using std::ptrdiff_t; #include "mpc/magneticField/MagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" -#include "mpc/magneticField/GadgetMagneticField.h" +#include "mpc/magneticField/QuimbyMagneticField.h" #include "mpc/magneticField/JF2012Field.h" #include "mpc/Referenced.h" @@ -137,7 +137,7 @@ using std::ptrdiff_t; %template(ScalarGrid) mpc::Grid; %include "mpc/magneticField/MagneticFieldGrid.h" -%include "mpc/magneticField/GadgetMagneticField.h" +%include "mpc/magneticField/QuimbyMagneticField.h" %include "mpc/magneticField/JF2012Field.h" %include "mpc/ExplicitRungeKutta.h" From 5a9c6fc2d43e48dbfeaa9ff6cc59dfc09cd3a2d0 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 3 May 2013 18:10:26 +0200 Subject: [PATCH 0301/1298] added GMF models: TorroidalHaloField and LogarithmicSpiralField --- .../mpc/magneticField/GalacticMagneticField.h | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 include/mpc/magneticField/GalacticMagneticField.h diff --git a/include/mpc/magneticField/GalacticMagneticField.h b/include/mpc/magneticField/GalacticMagneticField.h new file mode 100644 index 000000000..6a0d7d24c --- /dev/null +++ b/include/mpc/magneticField/GalacticMagneticField.h @@ -0,0 +1,96 @@ +#ifndef MPC_GALACTICMAGNETICFIELD_H_ +#define MPC_GALACTICMAGNETICFIELD_H_ + +#include "mpc/magneticField/MagneticField.h" +#include + +namespace mpc { + +/** + @class TorroidalHaloField + @brief Galactic halo field model from Prouza & Smida 2003 and Sun et al. 2008 + */ +class TorroidalHaloField: public MagneticField { + double b0; // halo field strength + double z0; // vertical position + double z1; // vertical scale + double r0; // radial scale + +public: + void setParameters(double b0, double z0, double z1, double r0) { + this->b0 = b0; + this->z0 = z0; + this->z1 = z1; + this->r0 = r0; + } + + Vector3d getField(Vector3d pos) { + double r = sqrt(pos.x * pos.x + pos.y * pos.y) / r0; // in-plane radius in units of the radial scale + double b = b0 / (1 + pow((abs(pos.z) - z0) / z1, 2)) * r * exp(1 - r); + double phi = pos.getPhi(); // azimuth + return Vector3d(cos(phi), sin(phi), 0) * b; + } +}; + +/** + @class LogarithmicSpiralField + @brief Galactic disk field model of axisymmetric (ASS) or bisymmetric (BSS) logarithmic spiral shape + */ +class LogarithmicSpiralField: public MagneticField { +private: + bool isBSS; // true for BSS, false for ASS + double b0; // field strength + double pitch; // pitch angle [rad] + double rsol; // distance of sun to galactic center + double rc; // radius of central region with constant field strength + double d; // distance to the first field reversal + double z0; // vertical attenuation length + + double phase; // phase of the spiral arms + double cosPhase; + double sinPitch; + double cosPitch; + double tanPitch; + + void updatePitchAngle() { + sinPitch = sin(pitch); + cosPitch = cos(pitch); + tanPitch = tan(pitch); + } + + void updatePhase() { + phase = log(1 + d / rsol) / tanPitch - M_PI / 2; + cosPhase = cos(phase); + } + +public: + void setParameters(bool isBSS, double b0, double pitch, double rsol, + double rc, double d, double z0) { + this->isBSS = isBSS; + this->b0 = b0; + this->pitch = pitch; + this->rsol = rsol; + this->rc = rc; + this->d = d; + this->z0 = z0; + updatePitchAngle(); + updatePhase(); + } + + Vector3d getField(Vector3d pos) const { + double r = sqrt(pos.x * pos.x + pos.y * pos.y); // in-plane radius + double b = b0 / cosPhase * rsol / std::max(r, rc); + + double phi = pos.getPhi(); + double c = cos(phi - log(r / rsol) / tanPitch + phase); + if (isBSS) + c = fabs(c); + b *= c * exp(fabs(pos.z) / z0); + + return Vector3d(cosPitch * cos(phi), sinPitch * sin(phi), 0) * b; + } +}; + +}// namespace mpc + +#endif /* MPC_GALACTICMAGNETICFIELD_H_ */ From 26ea1b91a2c1e7774f76c1e6cb397092b655d8cb Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 3 May 2013 18:16:01 +0200 Subject: [PATCH 0302/1298] fix OutputROOT --- python/mpc.i | 4 ++-- src/module/OutputROOT.cpp | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/python/mpc.i b/python/mpc.i index 15cb8d0d2..511f1a2c7 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -45,7 +45,7 @@ using std::ptrdiff_t; #include "mpc/magneticField/MagneticField.h" #include "mpc/magneticField/MagneticFieldGrid.h" #include "mpc/magneticField/QuimbyMagneticField.h" -#include "mpc/magneticField/JF2012Field.h" +#include "mpc/magneticField/JF12Field.h" #include "mpc/Referenced.h" #include "mpc/Candidate.h" @@ -138,7 +138,7 @@ using std::ptrdiff_t; %include "mpc/magneticField/MagneticFieldGrid.h" %include "mpc/magneticField/QuimbyMagneticField.h" -%include "mpc/magneticField/JF2012Field.h" +%include "mpc/magneticField/JF12Field.h" %include "mpc/ExplicitRungeKutta.h" %include "mpc/PhasePoint.h" diff --git a/src/module/OutputROOT.cpp b/src/module/OutputROOT.cpp index 69f14c856..eefce6a50 100644 --- a/src/module/OutputROOT.cpp +++ b/src/module/OutputROOT.cpp @@ -31,9 +31,9 @@ void ROOTEventOutput1D::process(Candidate *c) const { TThread::Lock(); #pragma omp critical { - Ntuple->Fill(c->current.getId(), c->initial.getId(), - c->initial.getPosition().getX() / Mpc, c->getRedshift(), - c->initial.getEnergy() / EeV, c->getTrajectoryLength() / Mpc, + Ntuple->Fill(c->current.getId(), c->source.getId(), + c->source.getPosition().getX() / Mpc, c->getRedshift(), + c->source.getEnergy() / EeV, c->getTrajectoryLength() / Mpc, c->current.getEnergy() / EeV); } TThread::UnLock(); @@ -62,7 +62,7 @@ void ROOTTrajectoryOutput1D::process(Candidate *c) const { TThread::Lock(); #pragma omp critical { - Ntuple->Fill(c->current.getId(), c->initial.getId(), + Ntuple->Fill(c->current.getId(), c->source.getId(), c->getTrajectoryLength() / Mpc, c->current.getPosition().getX() / Mpc, c->current.getEnergy() / EeV); @@ -98,13 +98,13 @@ void ROOTEventOutput3D::process(Candidate *c) const { TThread::Lock(); #pragma omp critical { - Ntuple->Fill(c->current.getId(), c->initial.getId(), - c->initial.getPosition().getX() / Mpc, - c->initial.getPosition().getY() / Mpc, - c->initial.getPosition().getZ() / Mpc, - c->initial.getEnergy() / EeV, - c->initial.getDirection().getTheta(), - c->initial.getDirection().getPhi(), + Ntuple->Fill(c->current.getId(), c->source.getId(), + c->source.getPosition().getX() / Mpc, + c->source.getPosition().getY() / Mpc, + c->source.getPosition().getZ() / Mpc, + c->source.getEnergy() / EeV, + c->source.getDirection().getTheta(), + c->source.getDirection().getPhi(), c->getTrajectoryLength() / Mpc, c->current.getPosition().getX() / Mpc, c->current.getPosition().getY() / Mpc, @@ -139,7 +139,7 @@ void ROOTTrajectoryOutput3D::process(Candidate *c) const { TThread::Lock(); #pragma omp critical { - Ntuple->Fill(c->current.getId(), c->initial.getId(), + Ntuple->Fill(c->current.getId(), c->source.getId(), c->getTrajectoryLength() / Mpc, c->current.getPosition().getX() / Mpc, c->current.getPosition().getY() / Mpc, From e4a30f27f86c49dfd5d793e5ad68ab19aabe8b9d Mon Sep 17 00:00:00 2001 From: geromueller Date: Fri, 10 May 2013 18:06:44 +0200 Subject: [PATCH 0303/1298] add periodic magnetic field decorator --- include/mpc/magneticField/MagneticField.h | 22 +++++++++ src/magneticField/MagneticField.cpp | 55 +++++++++++++++++++++++ test/testMagneticField.cpp | 36 +++++++++++++-- 3 files changed, 110 insertions(+), 3 deletions(-) diff --git a/include/mpc/magneticField/MagneticField.h b/include/mpc/magneticField/MagneticField.h index efc400de0..74f9633ba 100644 --- a/include/mpc/magneticField/MagneticField.h +++ b/include/mpc/magneticField/MagneticField.h @@ -17,6 +17,28 @@ class MagneticField: public Referenced { virtual Vector3d getField(const Vector3d &position) const = 0; }; +/** + @class PeriodicMagneticField + @brief Magnetic field decorator to implement periodic magnetic fields. + */ +class PeriodicMagneticField: public MagneticField { + ref_ptr field; + Vector3d origin, extends; + bool reflective; +public: + PeriodicMagneticField(ref_ptr field, + const Vector3d &extends); + PeriodicMagneticField(ref_ptr field, const Vector3d &extends, + const Vector3d &origin, bool reflective); + Vector3d &getOrigin(); + void setOrigin(const Vector3d &origin); + Vector3d &getExtends(); + void setExtends(const Vector3d &origin); + bool isReflective(); + void setReflective(bool reflective); + Vector3d getField(const Vector3d &position) const; +}; + /** @class MagneticFieldList @brief List of magnetic fields diff --git a/src/magneticField/MagneticField.cpp b/src/magneticField/MagneticField.cpp index d1f19dd4a..28864fc02 100644 --- a/src/magneticField/MagneticField.cpp +++ b/src/magneticField/MagneticField.cpp @@ -2,6 +2,61 @@ namespace mpc { +PeriodicMagneticField::PeriodicMagneticField(ref_ptr field, + const Vector3d &extends) : + field(field), extends(extends), origin(0, 0, 0), reflective(false) { + +} + +PeriodicMagneticField::PeriodicMagneticField(ref_ptr field, + const Vector3d &extends, const Vector3d &origin, bool reflective) : + field(field), extends(extends), origin(origin), reflective(reflective) { + +} + +Vector3d &PeriodicMagneticField::getOrigin() { + return origin; +} + +void PeriodicMagneticField::setOrigin(const Vector3d &origin) { + this->origin = origin; +} + +Vector3d &PeriodicMagneticField::getExtends() { + return extends; +} + +void PeriodicMagneticField::setExtends(const Vector3d &origin) { + this->extends = extends; +} + +bool PeriodicMagneticField::isReflective() { + return reflective; +} + +void PeriodicMagneticField::setReflective(bool reflective) { + this->reflective = reflective; +} + +Vector3d PeriodicMagneticField::getField(const Vector3d &position) const { + Vector3d n = ((position - origin) / extends).floor(); + Vector3d p = position - origin - n * extends; + + if (reflective) { + long mx = (long) ::fabs(n.x) % 2; + if (mx == 1) + p.x = extends.x - p.x; + long my = (long) ::fabs(n.y) % 2; + if (my == 1) + p.y = extends.y - p.y; + long mz = (long) ::fabs(n.z) % 2; + if (mz == 1) + p.z = extends.z - p.z; + } + + return field->getField(p); +} + void MagneticFieldList::addField(ref_ptr field) { fields.push_back(field); } diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index 83a102d66..539fe9c00 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -7,7 +7,7 @@ #include "gtest/gtest.h" -namespace mpc { +using namespace mpc; TEST(testUniformMagneticField, SimpleTest) { UniformMagneticField B(Vector3d(-1, 5, 3)); @@ -142,9 +142,39 @@ TEST(testTurbulentMagneticField, Exceptions) { EXPECT_THROW(B.initialize(), std::runtime_error); } +class EchoMagneticField: public MagneticField { +public: + Vector3d getField(const Vector3d &position) const { + return position; + } +}; + +TEST(testPeriodicMagneticField, Exceptions) { + ref_ptr f = new EchoMagneticField(); + ref_ptr p = new PeriodicMagneticField(f, + Vector3d(10000, 10000, 10000), Vector3d(1000, 1000, 1000), true); + + // box 0, 0, 0 + Vector3d v = p->getField(Vector3d(1000, 2000, 3000)); + EXPECT_DOUBLE_EQ(0, v.x); + EXPECT_DOUBLE_EQ(1000, v.y); + EXPECT_DOUBLE_EQ(2000, v.z); + + // box 1, 2, 3 + v = p->getField(Vector3d(12000, 23000, 34000)); + EXPECT_DOUBLE_EQ(9000, v.x); + EXPECT_DOUBLE_EQ(2000, v.y); + EXPECT_DOUBLE_EQ(7000, v.z); + + // box -1, -2, -3 + v = p->getField(Vector3d(0, -10000, -20000)); + EXPECT_DOUBLE_EQ(1000, v.x); + EXPECT_DOUBLE_EQ(9000, v.y); + EXPECT_DOUBLE_EQ(1000, v.z); + +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } - -} // namespace mpc From 8e1b1bdfc6d642f802063ccb2f5bb96ef377da1e Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 8 May 2013 10:15:29 +0200 Subject: [PATCH 0304/1298] minor "fix" to turbulent field grid spectral index + scripts --- include/mpc/GridTools.h | 6 +- src/GridTools.cpp | 12 +- src/XmlExecute.cpp | 17 +-- src/magneticField/JF12Field.cpp | 3 +- test/python/testTurbulentDeflection.py | 54 +++---- test/python/testTurbulentFieldGrid.py | 204 ++++++++++++------------- 6 files changed, 145 insertions(+), 151 deletions(-) diff --git a/include/mpc/GridTools.h b/include/mpc/GridTools.h index b5888f789..3c7daa575 100644 --- a/include/mpc/GridTools.h +++ b/include/mpc/GridTools.h @@ -23,17 +23,17 @@ void scaleGrid(ref_ptr grid, double a); Create a random initialization of a turbulent field. @param lMin Minimum wavelength of the turbulence @param lMax Maximum wavelength of the turbulence - @param index Power spectral index of the turbulence (-11/3 corresponds to a Kolmogorov spectrum) + @param alpha Power law index of ~ k^alpha (alpha = -11/3 corresponds to a Kolmogorov spectrum) @param Brms RMS field strength @param seed Random seed */ void initTurbulence(ref_ptr grid, double Brms, double lMin, - double lMax, double index = -11. / 3., int seed = 0); + double lMax, double alpha = -11./3., int seed = 0); #endif // MPC_HAVE_FFTW3F /** Analytically calculate the correlation length of a turbulent field */ double turbulentCorrelationLength(double lMin, double lMax, - double spectralIndex = -11. / 3.); + double alpha = -11./3.); /** Dump / load functions for scalar / 3-vector grids and binary / plain text files. diff --git a/src/GridTools.cpp b/src/GridTools.cpp index fcbee0002..6edf37477 100644 --- a/src/GridTools.cpp +++ b/src/GridTools.cpp @@ -53,7 +53,7 @@ void scaleGrid(ref_ptr grid, double a) { #include "fftw3.h" void initTurbulence(ref_ptr grid, double Brms, double lMin, - double lMax, double spectralIndex, int seed) { + double lMax, double alpha, int seed) { size_t Nx = grid->getNx(); size_t Ny = grid->getNy(); size_t Nz = grid->getNz(); @@ -131,8 +131,8 @@ void initTurbulence(ref_ptr grid, double Brms, double lMin, theta = 2 * M_PI * random.rand(); b = e1 * cos(theta) + e2 * sin(theta); - // standard normal distributed amplitude weighted with k^alpha/2 - b *= random.randNorm() * pow(k, spectralIndex / 2.); + // normal distributed amplitude with mean = 0 and sigma = k^alpha/2 + b *= random.randNorm() * pow(k, alpha / 2); // uniform random phase phase = 2 * M_PI * random.rand(); @@ -186,10 +186,10 @@ void initTurbulence(ref_ptr grid, double Brms, double lMin, scaleGrid(grid, Brms / rmsFieldStrength(grid)); // normalize to Brms } #endif // MPC_HAVE_FFTW3F -double turbulentCorrelationLength(double lMin, double lMax, - double spectralIndex) { + +double turbulentCorrelationLength(double lMin, double lMax, double alpha) { double r = lMin / lMax; - double a = -spectralIndex - 2; + double a = -alpha - 2; return lMax / 2 * (a - 1) / a * (1 - pow(r, a)) / (1 - pow(r, a - 1)); } diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 432d6b21b..b593444af 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -377,7 +377,7 @@ void XmlExecute::loadGridMagneticField(xml_node &node) { loadGridFromTxt(field, fname, gauss); } else { double brms = childValue(node, "RMS_muG") * 1e-6 * gauss; - cout << " - Brms : " << brms / nG << " nG" << endl; + cout << " - Brms: " << brms / nG << " nG" << endl; double kMin = childValue(node, "Kmin"); double kMax = childValue(node, "Kmax"); @@ -387,7 +387,7 @@ void XmlExecute::loadGridMagneticField(xml_node &node) { << " Mpc" << endl; double alpha = childValue(node, "SpectralIndex"); - cout << " - Turbulence spectral index: " << alpha << endl; + cout << " - Spectral index, ~ k^n, n: " << alpha << endl; #ifdef MPC_HAVE_FFTW3F initTurbulence(field, brms, lMin, lMax, alpha); @@ -575,8 +575,8 @@ void XmlExecute::loadSpectrumComposition(pugi::xml_node &node) { } loadSourceNuclei(node); } else if (spectrumType == "Power Law") { - double alpha = childValue(spectrum_node, "Alpha"); - cout << " - Power law index: " << alpha << endl; + double alpha = -childValue(spectrum_node, "Alpha"); + cout << " - Power law index E^a, a:" << alpha << endl; cout << " - Minimum energy: " << Emin / EeV << " EeV" << endl; // if the source is accelerated to a maximum rigidity @@ -585,8 +585,7 @@ void XmlExecute::loadSpectrumComposition(pugi::xml_node &node) { cout << " - Maximum rigidity: " << Rmax / EeV << " EeV" << endl; // combined source spectrum / composition - SourceComposition *composition = new SourceComposition(Emin, Rmax, - -alpha); + SourceComposition *comp = new SourceComposition(Emin, Rmax, alpha); xml_node p = node.child("Particles"); for (xml_node n = p.child("Species"); n; n = n.next_sibling("Species")) { @@ -595,15 +594,15 @@ void XmlExecute::loadSpectrumComposition(pugi::xml_node &node) { double ab = n.attribute("Abundance").as_double(); cout << " - Species: Z = " << Z << ", A = " << A << ", abundance = " << ab << endl; - composition->add(nucleusId(A, Z), ab); + comp->add(nucleusId(A, Z), ab); } - source.addProperty(composition); + source.addProperty(comp); } else if (spectrum_node.child("Ecut_EeV")) { double Emax = childValue(spectrum_node, "Ecut_EeV") * EeV; cout << " - Maximum energy: " << Emax / EeV << " EeV" << endl; // source spectrum - source.addProperty(new SourcePowerLawSpectrum(Emin, Emax, -alpha)); + source.addProperty(new SourcePowerLawSpectrum(Emin, Emax, alpha)); // source composition loadSourceNuclei(node); diff --git a/src/magneticField/JF12Field.cpp b/src/magneticField/JF12Field.cpp index dd4ecf69d..e4f18d006 100644 --- a/src/magneticField/JF12Field.cpp +++ b/src/magneticField/JF12Field.cpp @@ -103,8 +103,7 @@ void JF12Field::randomTurbulent(int seed) { useTurbulent = true; // turbulent field with Kolmogorov spectrum, B_rms = 1 and Lc = 60 parsec turbulentGrid = new VectorGrid(Vector3d(0.), 256, 4 * parsec); - initTurbulence(turbulentGrid, 1., 16 * parsec, 255.5 * parsec, -11. / 3., - seed); + initTurbulence(turbulentGrid, 1, 16 * parsec, 255.5 * parsec, -11./3., seed); } #endif diff --git a/test/python/testTurbulentDeflection.py b/test/python/testTurbulentDeflection.py index a93b6f5aa..5dbaa36e2 100644 --- a/test/python/testTurbulentDeflection.py +++ b/test/python/testTurbulentDeflection.py @@ -9,10 +9,10 @@ # create turbulent field with B_RMS = 1 nG and 0.5 Mpc correlation length vGrid = VectorGrid(Vector3d(0, 0, 0), 128, 0.05 * Mpc) -initTurbulence(vGrid, 1 * nG, 0.1 * Mpc, 2.2 * Mpc, -11/3.) +initTurbulence(vGrid, 1 * nG, 0.1 * Mpc, 2.2 * Mpc) propa = DeflectionCK(MagneticFieldGrid(vGrid)) -Lc = turbulentCorrelationLength(0.1 * Mpc, 2.2 * Mpc, -11/3.) / Mpc +Lc = turbulentCorrelationLength(0.1, 2.2) # in [Mpc] Brms = 1 # nG Rg = 1.08 * E / Brms # Mpc @@ -20,31 +20,31 @@ distance, rms1, rms2 = zeros((3, nS)) for j in range(nT): - if j % (nT // 10) == 0: - print j - - ps = ParticleState() - ps.setId(nucleusId(1, 1)) - ps.setEnergy(E * EeV) - ps.setDirection(Random.instance().randUnitVectorOnSphere()) - ps.setPosition(Vector3d(0, 0, 0)) - c = Candidate(ps) - - for i in range(nS): - maxLen = MaximumTrajectoryLength(age[i] * Mpc) - c.setNextStep(c.getNextStep() * 0.99) - c.setActive(True) - - while c.isActive(): - propa.process(c) - maxLen.process(c) - - x = c.current.getPosition() / Mpc - p = c.current.getDirection() - p0 = c.initial.getDirection() - distance[i] += x.getMag() - rms1[i] += (x.getAngleTo(p))**2 - rms2[i] += (p0.getAngleTo(p))**2 + if j % (nT // 10) == 0: + print j + + ps = ParticleState() + ps.setId(nucleusId(1, 1)) + ps.setEnergy(E * EeV) + ps.setDirection(Random.instance().randUnitVectorOnSphere()) + ps.setPosition(Vector3d(0, 0, 0)) + c = Candidate(ps) + + for i in range(nS): + maxLen = MaximumTrajectoryLength(age[i] * Mpc) + c.setNextStep(c.getNextStep() * 0.99) + c.setActive(True) + + while c.isActive(): + propa.process(c) + maxLen.process(c) + + x = c.current.getPosition() / Mpc + p = c.current.getDirection() + p0 = c.source.getDirection() + distance[i] += x.getMag() + rms1[i] += (x.getAngleTo(p))**2 + rms2[i] += (p0.getAngleTo(p))**2 distance /= nT diff --git a/test/python/testTurbulentFieldGrid.py b/test/python/testTurbulentFieldGrid.py index 9f4bfb806..3be52073a 100644 --- a/test/python/testTurbulentFieldGrid.py +++ b/test/python/testTurbulentFieldGrid.py @@ -3,77 +3,70 @@ from mpc import * def fftAutoCorrelation(a): - ''' - calculate 2point-autocorrelation for an n-dimensional array of real input - ''' - b = rfftn(a) - return irfftn(b * b.conjugate()).real + ''' + Two-point autocorrelation for an n-dimensional array of real input + ''' + b = rfftn(a) + return irfftn(b * b.conjugate()).real class VectorFieldAutoCorrelation(): - ''' - 2point-autocorrelation for a field of 3-vectors - ''' - def __init__(self, Bx, By, Bz): - self.n = shape(Bx)[0] - self.Rx = fftAutoCorrelation(Bx) - self.Ry = fftAutoCorrelation(By) - self.Rz = fftAutoCorrelation(Bz) - - def getCorrelationCurve(self, step=(1, 1, 1)): - ''' - returns the correlation curve in the direction of [step], summed over all field components - ''' - step = array(step) - # number of steps that can be walked accross the field - nSteps = int(self.n / 2 / max(abs(step))) - x = arange(0, nSteps) * norm(step) - y = zeros(nSteps) - for i in range(nSteps): - y[i] += self.Rx[ i * step[0], i * step[1], i * step[2] ] - y[i] += self.Ry[ i * step[0], i * step[1], i * step[2] ] - y[i] += self.Rz[ i * step[0], i * step[1], i * step[2] ] - y /= y[0] - return x, y - - def getIntegralLengthscale(self, step=(1, 1, 1)): - ''' - returns the integral lengthscale in the direction of [step] - ''' - x, y = self.getCorrelationCurve(step) - # use symmetry: Lc = \int_{-inf}^{inf} R/R_0 dx = 2*\int_{0}^{inf} R/R_0 dx - return (2 * sum(y[1:]) + y[0]) * norm(step) - -def fftEnergySpectralDensity(a): - ''' - calculate the energy spectral density for an n-dimensional array - ''' - b = fftn(a) - return (b * conjugate(b)).real - -def getVectorFieldEnergySpectralDensity(Bx, By, Bz): - ''' - calculate the energy spectral density for an 3-dimensional Vector field - ''' - E = fftEnergySpectralDensity(Bx) - E += fftEnergySpectralDensity(By) - E += fftEnergySpectralDensity(Bz) - n = shape(Bx)[0] - K = fftfreq(n) - # project E(kx,ky,kz) -> E(k) - d = {} - for ix in range(n): - for iy in range(n): - for iz in range(n): - magK = (K[ix]**2 + K[iy]**2 + K[iz]**2)**.5 - energy = E[ix,iy,iz] - d.setdefault(magK, [energy]).append(energy) - k = d.keys() - k.sort() - k = array(k) - Ek = zeros(len(k)) - for i,key in enumerate(k): - Ek[i] = mean(d[key]) - return k, Ek + ''' + 2point-autocorrelation for a field of 3-vectors + ''' + def __init__(self, Bx, By, Bz): + self.n = shape(Bx)[0] + self.Rx = fftAutoCorrelation(Bx) + self.Ry = fftAutoCorrelation(By) + self.Rz = fftAutoCorrelation(Bz) + + def getCorrelationCurve(self, step=(1, 1, 1)): + ''' + returns the correlation curve in the direction of [step], summed over all field components + ''' + step = array(step) + # number of steps that can be walked accross the field + nSteps = int(self.n / 2 / max(abs(step))) + x = arange(0, nSteps) * norm(step) + y = zeros(nSteps) + for i in range(nSteps): + y[i] += self.Rx[ i * step[0], i * step[1], i * step[2] ] + y[i] += self.Ry[ i * step[0], i * step[1], i * step[2] ] + y[i] += self.Rz[ i * step[0], i * step[1], i * step[2] ] + y /= y[0] + return x, y + + def getIntegralLengthscale(self, step=(1, 1, 1)): + ''' + returns the integral lengthscale in the direction of [step] + ''' + x, y = self.getCorrelationCurve(step) + # use symmetry: Lc = \int_{-inf}^{inf} R/R_0 dx = 2*\int_{0}^{inf} R/R_0 dx + return (2 * sum(y[1:]) + y[0]) * norm(step) + +def fftESD(a): + ''' + Energy spectral density for an n-dimensional array + ''' + b = fftn(a) + return (b * conjugate(b)).real + +#def meanVectorFieldESD(Bx, By, Bz): +# ''' +# calculate the energy spectral density for an 3-dimensional Vector field +# ''' +# n = shape(Bx)[0] + +# E = fftEnergySpectralDensity(Bx) +# E += fftEnergySpectralDensity(By) +# E += fftEnergySpectralDensity(Bz) + +# k = fftfreq(n) +# kx, ky, kz = meshgrid(k, k, k) +# k2 = kx**2 + ky**2 + kz**2 + +# E.resize(n**3) +# k2.resize(n**3) +# dig = digitize(k2, ) @@ -82,22 +75,24 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): n = 128 spacing = 1 lMin, lMax = 2, 32 -Brms = 1. -alpha = -11./3 +Brms = 1 +alpha = -11./3. +seed = 42 + Lc = turbulentCorrelationLength(lMin, lMax, alpha) vGrid = VectorGrid(origin, n, spacing) -initTurbulence(vGrid, Brms, lMin, lMax, alpha) +initTurbulence(vGrid, Brms, lMin, lMax, alpha, seed) ### copy field grid to array(s) Bx, By, Bz = zeros((3, n, n, n)) for ix in range(n): - for iy in range(n): - for iz in range(n): - b = vGrid.get(ix, iy, iz) - Bx[ix, iy, iz] = b.x - By[ix, iy, iz] = b.y - Bz[ix, iy, iz] = b.z + for iy in range(n): + for iz in range(n): + b = vGrid.get(ix, iy, iz) + Bx[ix, iy, iz] = b.x + By[ix, iy, iz] = b.y + Bz[ix, iy, iz] = b.z ### plot slice in position space figure(figsize=(8,6)) @@ -114,7 +109,7 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): figure() A2 = zeros((3*n,3*n)) for i,j in ((0,1), (1,0), (1,1), (1,2), (2,1)): - A2[i*n:(i+1)*n, j*n:(j+1)*n] = A1 + A2[i*n:(i+1)*n, j*n:(j+1)*n] = A1 im = imshow(ma.masked_array(A2, A2 == 0), origin='lower', extent=[-n,2*n,-n,2*n], vmin=0, vmax=3) cbar = colorbar(im) cbar.set_label(r'$|\vec{B_x}|/B_{rms}$') @@ -151,17 +146,17 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): Lcs = [] steps = [] for ix in arange(-2,3): - for iy in arange(-2,3): - for iz in arange(-2,3): - if ix == 0 and iy == 0 and iz == 0: - continue - if (-ix,-iy,-iz) in steps: - continue - step = (ix,iy,iz) - # steps.append(step) - Lcs.append( corr.getIntegralLengthscale(step) ) - x,y = corr.getCorrelationCurve(step) - plot(x,y,label=str(step)) + for iy in arange(-2,3): + for iz in arange(-2,3): + if ix == 0 and iy == 0 and iz == 0: + continue + if (-ix,-iy,-iz) in steps: + continue + step = (ix,iy,iz) + # steps.append(step) + Lcs.append( corr.getIntegralLengthscale(step) ) + x,y = corr.getCorrelationCurve(step) + plot(x,y,label=str(step)) xlabel('Distance') ylabel('Normalized Autocorrelation') xlim(0,32) @@ -170,20 +165,21 @@ def getVectorFieldEnergySpectralDensity(Bx, By, Bz): text(0.5, 0.95, s, ha='left', va='top', transform=gca().transAxes) savefig('TurbulentField_coherenceLength.png', bbox_inches='tight') -### plot energy spectrum -figure() -k, Ek = getVectorFieldEnergySpectralDensity(Bx, By, Bz) -plot(k, Ek, label='Turbulent Spectrum') -i = k.searchsorted(1./lMax) + 2 -plot(k, Ek[i]/k[i]**alpha * k**alpha, label='Slope $k^{-11/3}$') -axvline(1./lMax, color='r', linestyle='--', label='$k_{min}=1/%.1f$'%lMax) -axvline(1./lMin, color='r', linestyle='--', label='$k_{max}=1/%.1f$'%lMin) -loglog() -legend(loc='center left') -xlabel('Wavenumber $k$') -ylabel('Energy Spectral Density $E(k) [a.u.]$') -grid() -savefig('TurbulentField_spectrum.png', bbox_inches='tight') +#### plot energy spectrum +#figure() +#k, Ek = getVectorFieldEnergySpectralDensity(Bx, By, Bz) +#plot(k, Ek, label='Turbulent Spectrum') +#i = k.searchsorted(1./lMax) + 2 +#c = Ek[i]/k[i] +##plot(k, (c*k)**alpha, label='Slope $k^{-11/3}$') +#axvline(1./lMax, color='r', linestyle='--', label='$k_{min}=1/%.1f$'%lMax) +#axvline(1./lMin, color='r', linestyle='--', label='$k_{max}=1/%.1f$'%lMin) +#loglog() +#legend(loc='center left') +#xlabel('Wavenumber $k$') +#ylabel('Energy Spectral Density $E(k) [a.u.]$') +#grid() +#savefig('TurbulentField_spectrum.png', bbox_inches='tight') ### plot histogram of field strengths figure() From 81f0b34cdd5346d11f295e216b7b39ab8323476f Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 14 May 2013 00:18:36 +0200 Subject: [PATCH 0305/1298] fix bug in Photopionproduction --- src/module/PhotoPionProduction.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 75b7d7ad5..2f646daaf 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -79,11 +79,11 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, // check for interaction on protons if (Z > 0) { double rate = interpolate(EpA, energy, pRate); - if (rate > 0) { + if (rate > 0) { if (A > 1) { if (A < 8) rate *= 0.85 * pow(Z, 2. / 3.); - if (A >= 8) + else rate *= 0.85 * Z; } interaction.distance = -log(random.rand()) / rate; @@ -98,13 +98,13 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, if (A > 1) { if (A < 8) rate *= 0.85 * pow(N, 2. / 3.); - if (A >= 8) + else rate *= 0.85 * N; } double d = -log(random.rand()) / rate; if (d < interaction.distance) { - interaction.distance = -log(random.rand()) / rate; + interaction.distance = d; interaction.channel = 0; } } @@ -165,20 +165,22 @@ double PhotoPionProduction::energyLossLength(int id, double E) { double lossRate = 0; if (Z > 0) { double rate = interpolate(EpA, energy, pRate); - if (A > 1) + if (A > 1) { if (A < 8) rate *= 0.85 * pow(Z, 2. / 3.); - if (A >= 8) - rate *= 0.85 * Z; + else + rate *= 0.85 * Z; + } lossRate += relativeEnergyLoss * rate; } if (N > 0) { double rate = interpolate(EpA, energy, nRate); - if (A > 1) + if (A > 1) { if (A < 8) rate *= 0.85 * pow(N, 2. / 3.); - if (A >= 8) - rate *= 0.85 * N; + else + rate *= 0.85 * N; + } lossRate += relativeEnergyLoss * rate; } From 618918dd2a65632d53d8bd0e738c42e2271aa369 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 17 May 2013 16:00:07 +0200 Subject: [PATCH 0306/1298] preprocessing scripts for photon field: i.e. IRB redshift scaling of Kneiske et al. 2004 --- data-tools/PhotonField/IRB_redshiftScaling.py | 65 ++++++++++ .../PhotonField/Kneiske2004_IRB/z0.2.txt | 64 ++++++++++ .../PhotonField/Kneiske2004_IRB/z0.4.txt | 58 +++++++++ .../PhotonField/Kneiske2004_IRB/z0.6.txt | 48 ++++++++ data-tools/PhotonField/Kneiske2004_IRB/z0.txt | 52 ++++++++ data-tools/PhotonField/Kneiske2004_IRB/z1.txt | 62 ++++++++++ data-tools/PhotonField/Kneiske2004_IRB/z2.txt | 65 ++++++++++ data-tools/PhotonField/Kneiske2004_IRB/z3.txt | 62 ++++++++++ data-tools/PhotonField/Kneiske2004_IRB/z4.txt | 57 +++++++++ data-tools/PhotonField/photonField.py | 113 +++++++++--------- include/mpc/Random.h | 2 +- include/mpc/magneticField/MagneticField.h | 6 +- include/mpc/magneticField/MagneticFieldGrid.h | 5 +- src/Random.cpp | 4 +- src/Source.cpp | 6 +- src/magneticField/MagneticFieldGrid.cpp | 8 +- src/magneticField/TurbulentMagneticField.cpp | 2 +- 17 files changed, 607 insertions(+), 72 deletions(-) create mode 100644 data-tools/PhotonField/IRB_redshiftScaling.py create mode 100644 data-tools/PhotonField/Kneiske2004_IRB/z0.2.txt create mode 100644 data-tools/PhotonField/Kneiske2004_IRB/z0.4.txt create mode 100644 data-tools/PhotonField/Kneiske2004_IRB/z0.6.txt create mode 100644 data-tools/PhotonField/Kneiske2004_IRB/z0.txt create mode 100644 data-tools/PhotonField/Kneiske2004_IRB/z1.txt create mode 100644 data-tools/PhotonField/Kneiske2004_IRB/z2.txt create mode 100644 data-tools/PhotonField/Kneiske2004_IRB/z3.txt create mode 100644 data-tools/PhotonField/Kneiske2004_IRB/z4.txt diff --git a/data-tools/PhotonField/IRB_redshiftScaling.py b/data-tools/PhotonField/IRB_redshiftScaling.py new file mode 100644 index 000000000..28ebafd47 --- /dev/null +++ b/data-tools/PhotonField/IRB_redshiftScaling.py @@ -0,0 +1,65 @@ +from pylab import * +from scipy.interpolate import interp1d +from scipy.integrate import quad +from mpc import h_planck, c_light + +# This script plots and calculates the integral of the cosmic infrared background (IRB) for different redshifts as given in Kneiske et al. 2004 (astro-ph/0309141) +# This integral can be used as an overall scaling factor for said background + + +def process1(fin): + x,y = genfromtxt(fin, unpack=True) + y[y < 1.01e-1] = 0 + return sum( (y[1:] + y[:-1]) / 2 * (x[1:] - x[:-1]) ) + + +def numberDensity(fin='Kneiske2004_IRB/z0.txt'): + """IRB (Kneiske et al. 2004) number density""" + # read file + # wavelength lambda [mu m] and wavelength scaled spectral radiance lambda * I_lambda [nW/m^2/sr] + x, y = genfromtxt(fin, unpack=True) + y[y < 1.01e-1] = 0 # cut off values that are artefacts from parsing the plots from the paper + + x *= 1e-6 # [mu m] -> [m] + y *= 1e-9 # [nW/m^2/sr] -> [W/m^2/sr] + + # remove wavelength scaling + y /= x # [W/m^2/sr] -> [W/m^3/sr] + + # convert to spectral energy density dEdV_lambda + y *= 4 * pi / c_light # [W/m^3/sr] -> [J/m^3/m] + + # convert to spectral number density: divide by photon energy + y /= h_planck * c_light / x # [J/m^3/m] -> [1/m^3/m] + + # integrate over wavelength spectrum + f = interp1d(x, y) + n = quad(f, x[0], x[-1]) # numerical integral from x_min to x_max + print n + return n[0] + + +files = ['z0.txt', 'z0.2.txt', 'z0.4.txt', 'z0.6.txt', 'z1.txt', 'z2.txt', 'z3.txt', 'z4.txt'] + +s = zeros(8) +s2 = zeros(8) +for i,f in enumerate(files): + s[i] = numberDensity('Kneiske2004_IRB/'+f) + s2[i] = process1('Kneiske2004_IRB/'+f) +s /= s[0] +s2 /= s2[0] + +z = array([0, 0.2, 0.4, 0.6, 1, 2, 3, 4]) +s *= (1+z)**3 +s2 *= (1+z)**3 + +figure() +plot(z, s, 'k') +plot(z, s2, 'r--') + +xlim(0, 5) +xlabel('Redshift z') +ylabel('Overall Scaling') + +#savefig('Kneiske2004_IRB_scaling.png',bbox_inches='tight') +show() diff --git a/data-tools/PhotonField/Kneiske2004_IRB/z0.2.txt b/data-tools/PhotonField/Kneiske2004_IRB/z0.2.txt new file mode 100644 index 000000000..909aec376 --- /dev/null +++ b/data-tools/PhotonField/Kneiske2004_IRB/z0.2.txt @@ -0,0 +1,64 @@ +# IRB spectrum at z=0.2 from Kneiske et al. 2004 (astro-ph/0309141) +# lambda [micrometer] lambda I_lambda [nW/m^2/sr] +0.00985395 0.1 +0.099995 0.0984353 +0.102355 0.14601 +0.105923 0.209854 +0.112089 0.326361 +0.117307 0.499609 +0.122731 0.69577 +0.12847 1.13447 +0.132901 1.4601 +0.14532 2.03338 +0.158908 2.87676 +0.171851 4.00627 +0.191997 4.69065 +0.224162 5.32142 +0.247655 5.94255 +0.292235 5.94255 +0.360437 6.13298 +0.434854 6.32951 +0.513441 7.64824 +0.619853 9.6895 +0.808412 12.2756 +1.07753 14.1477 +1.32921 15.3085 +1.79064 15.5518 +2.18354 14.3726 +2.63277 12.2756 +3.10434 9.6895 +3.66001 7.41076 +4.50919 5.40601 +5.55624 4.13465 +6.69967 3.58752 +7.73194 3.42174 +9.53837 3.76134 +12.2972 4.06995 +14.039 4.13465 +17.3111 3.94358 +21.3405 3.47613 +27.8015 3.1128 +32.4394 2.92249 +37.4451 2.96895 +45.1943 3.47613 +50.5076 4.47389 +56.4399 5.57924 +62.3863 7.29481 +68.9662 9.84353 +73.7352 12.0835 +85.1733 15.3085 +94.1327 19.0907 +107.515 22.3519 +131.185 24.9609 +169.043 23.0682 +203.8 19.0907 +240.316 15.3085 +274.161 12.4707 +326.74 8.81466 +376.703 6.13298 +443.93 4.06995 +540.492 2.30682 +629.928 1.50689 +717.957 0.909712 +836.422 0.523815 +963.886 0.316228 diff --git a/data-tools/PhotonField/Kneiske2004_IRB/z0.4.txt b/data-tools/PhotonField/Kneiske2004_IRB/z0.4.txt new file mode 100644 index 000000000..db6792f2b --- /dev/null +++ b/data-tools/PhotonField/Kneiske2004_IRB/z0.4.txt @@ -0,0 +1,58 @@ +# IRB spectrum at z=0.4 from Kneiske et al. 2004 (astro-ph/0309141) +# lambda [micrometer] lambda I_lambda [nW/m^2/sr] +0.0102228 0.0979217 +0.1 0.101591 +0.101108 0.185114 +0.110424 0.434323 +0.133169 2.28033 +0.177339 5.52437 +0.23616 6.57652 +0.284804 6.37481 +0.351119 6.27795 +0.428133 6.38076 +0.499533 7.83733 +0.595826 9.7801 +0.7427 11.2791 +0.946404 13.426 +1.21934 13.8647 +1.65995 14.0953 +2.04647 12.8274 +2.52298 11.1335 +2.97635 8.5158 +3.43467 6.93785 +4.14214 5.14192 +4.88647 4.25602 +5.57714 3.69335 +6.95193 3.58034 +8.11131 3.75534 +10 4.19621 +12.3285 4.13245 +15.5377 3.94336 +19.7993 3.5327 +23.8776 3.26593 +29.1149 3.11625 +32.1497 2.97276 +41.8803 3.48332 +48.3293 5.17087 +53.9582 6.8723 +60.2427 9.5766 +67.2591 12.332 +73.4562 16.6498 +81.1131 19.1964 +90.5603 22.4854 +102.228 26.3386 +121.934 27.6274 +142.269 25.9456 +164.177 23.6082 +189.458 19.8508 +231.013 14.7126 +269.539 10.5643 +325.059 7.35044 +383.471 4.65179 +452.379 2.99078 +522.039 1.83381 +609.101 1.07242 +702.894 0.657561 +793.454 0.416101 +936.035 0.214468 +989.043 0.177473 diff --git a/data-tools/PhotonField/Kneiske2004_IRB/z0.6.txt b/data-tools/PhotonField/Kneiske2004_IRB/z0.6.txt new file mode 100644 index 000000000..f64e79d1a --- /dev/null +++ b/data-tools/PhotonField/Kneiske2004_IRB/z0.6.txt @@ -0,0 +1,48 @@ +# IRB spectrum at z=0.6 from Kneiske et al. 2004 (astro-ph/0309141) +# lambda [micrometer] lambda I_lambda [nW/m^2/sr] +0.01 0.1 +0.0989043 0.0984246 +0.1 0.263445 +0.104505 0.431005 +0.111647 0.727895 +0.120598 1.39581 +0.133169 3.34301 +0.157099 4.44914 +0.175396 5.73615 +0.223502 6.83098 +0.311045 6.30957 +0.383471 6.21017 +0.432876 6.41057 +0.53367 8.26497 +0.695193 10 +0.967489 11.3546 +1.30266 12.2929 +1.75396 11.9086 +2.23502 10.1601 +2.94374 7.05141 +3.71003 4.97224 +4.52379 3.91835 +5.89298 3.45089 +8.20117 3.79586 +11.0424 4.0448 +16.2378 3.6772 +21.3867 3.23851 +31.1045 2.8978 +40.5187 3.85662 +52.2039 8.0066 +65.0724 14.4086 +73.4562 19.7948 +86.6561 24.3336 +101.108 27.6299 +127.427 27.6299 +153.675 23.9503 +195.824 17.4333 +231.013 13.0991 +284.804 8.13476 +343.467 4.97224 +400.747 3.0392 +467.581 1.88739 +557.714 1.06558 +665.222 0.538313 +820.117 0.243336 +956.888 0.130991 diff --git a/data-tools/PhotonField/Kneiske2004_IRB/z0.txt b/data-tools/PhotonField/Kneiske2004_IRB/z0.txt new file mode 100644 index 000000000..9f953c29d --- /dev/null +++ b/data-tools/PhotonField/Kneiske2004_IRB/z0.txt @@ -0,0 +1,52 @@ +# IRB spectrum at z=0 from Kneiske et al. 2004 (astro-ph/0309141) +# lambda [micrometer] lambda I_lambda [nW/m^2/sr] +#0.0106042 0.100515 +0.108004 0.0999824 +0.131465 0.59631 +0.172908 2.01281 +0.243002 4.72253 +0.357061 5.7039 +0.425743 6.17053 +0.536264 7.94205 +0.682947 10.2219 +0.84152 13.1572 +1.01444 15.1623 +1.26395 16.9278 +1.64574 17.7392 +2.23948 16.3795 +2.82198 12.7125 +3.59536 9.71151 +4.43228 6.85565 +5.46395 4.91673 +6.51661 3.87727 +7.27515 3.36227 +8.48614 3.46904 +9.68368 3.4136 +10.8092 3.57848 +12.608 3.87142 +15.0338 3.99416 +17.5367 3.99275 +20.6839 3.68794 +25.7758 3.29997 +31.7706 2.861 +37.4707 2.77091 +44.1891 3.04543 +51.5369 3.79845 +60.1011 5.29198 +67.8134 7.37332 +79.9551 10.6022 +93.2417 14.7709 +109.949 18.4226 +126.838 20.8992 +149.583 22.2549 +194.794 19.5994 +237.481 16.2057 +283.23 12.9832 +334.122 9.46058 +377.168 7.46144 +449.894 4.9449 +530.785 3.17522 +640.183 1.91385 +763.711 1.10017 +931.467 0.531461 +984.255 0.453697 diff --git a/data-tools/PhotonField/Kneiske2004_IRB/z1.txt b/data-tools/PhotonField/Kneiske2004_IRB/z1.txt new file mode 100644 index 000000000..7a50f9300 --- /dev/null +++ b/data-tools/PhotonField/Kneiske2004_IRB/z1.txt @@ -0,0 +1,62 @@ +# IRB spectrum at z=1 from Kneiske et al. 2004 (astro-ph/0309141) +# lambda [micrometer] lambda I_lambda [nW/m^2/sr] +0.0101483 0.0984299 +0.0905746 0.1 +0.0945105 0.158239 +0.0954499 0.224138 +0.0963792 0.338228 +0.0983741 0.543745 +0.099387 0.689426 +0.103722 1.04036 +0.113137 1.47362 +0.121995 2.44521 +0.132982 4.25467 +0.156758 4.98419 +0.182782 5.65688 +0.217955 5.65688 +0.268684 5.22653 +0.310065 4.82891 +0.382097 4.98419 +0.431177 5.22653 +0.52532 6.12268 +0.647195 6.83993 +0.833336 7.2869 +1.04961 7.88692 +1.36665 8.01272 +1.74099 7.76309 +2.12336 6.52278 +2.42432 5.48064 +2.86151 4.25467 +3.64826 3.20003 +4.96664 2.73166 +6.46616 2.86447 +8.99049 3.25108 +11.0813 3.14979 +15.2488 2.91016 +19.0077 2.605 +27.3314 2.44521 +31.8832 2.40682 +37.152 3.35562 +41.8987 4.25467 +46.2076 6.02655 +51.5257 8.40231 +58.0827 12.2842 +64.7839 15.8239 +77.1764 21.3745 +95.0718 24.6463 +121.138 22.4138 +146.119 19.1332 +174.404 14.1645 +217.582 9.68845 +251.359 6.42037 +296.808 4.39149 +350.599 2.68877 +409.628 1.6204 +452.825 1.09094 +511.789 0.700424 +578.431 0.449698 +646.404 0.317481 +714.822 0.191332 +781.559 0.128815 +844.796 0.1 +985.441 0.1 diff --git a/data-tools/PhotonField/Kneiske2004_IRB/z2.txt b/data-tools/PhotonField/Kneiske2004_IRB/z2.txt new file mode 100644 index 000000000..0db035ae3 --- /dev/null +++ b/data-tools/PhotonField/Kneiske2004_IRB/z2.txt @@ -0,0 +1,65 @@ +# IRB spectrum at z=2 from Kneiske et al. 2004 (astro-ph/0309141) +# lambda [micrometer] lambda I_lambda [nW/m^2/sr] +0.0098556 0.105395 +0.0925665 0.100018 +0.0958171 0.155455 +0.0992666 0.315818 +0.1074 0.506529 +0.118811 0.851675 +0.125696 1.22341 +0.13592 1.65 +0.155211 1.81302 +0.175303 2.02382 +0.209154 2.023 +0.241404 1.99073 +0.291083 1.72685 +0.328599 1.64668 +0.379286 1.64614 +0.428278 1.69836 +0.500001 1.89569 +0.564642 2.01843 +0.711959 2.08193 +0.948682 2.18126 +1.23652 2.28543 +1.59384 2.32038 +1.90104 2.11026 +2.21784 1.88926 +2.61496 1.46779 +3.01635 1.19559 +3.29373 1.08755 +3.88526 0.973629 +4.19663 0.928523 +4.89918 1.02021 +5.91215 1.13866 +7.29561 1.37494 +8.8023 1.44086 +10.5026 1.46315 +12.6658 1.33062 +15.9623 1.17244 +21.259 1.04934 +25.9301 1.04887 +30.9403 1.082 +34.5691 1.2864 +38.6332 1.65474 +42.6906 1.96738 +46.1536 2.49134 +49.9077 3.36004 +55.1796 4.7507 +59.6498 5.82935 +65.921 7.15255 +74.4959 9.49482 +86.976 10.7663 +100.417 11.6448 +117.163 10.759 +135.174 9.33372 +155.931 7.72352 +183.824 5.72353 +223.876 3.56635 +263.75 2.15344 +314.142 1.25994 +370 0.703155 +435.702 0.368457 +496.565 0.219022 +572.151 0.126152 +604.15 0.0995907 +970.987 0.099483 diff --git a/data-tools/PhotonField/Kneiske2004_IRB/z3.txt b/data-tools/PhotonField/Kneiske2004_IRB/z3.txt new file mode 100644 index 000000000..02102bb22 --- /dev/null +++ b/data-tools/PhotonField/Kneiske2004_IRB/z3.txt @@ -0,0 +1,62 @@ +# IRB spectrum at z=3 from Kneiske et al. 2004 (astro-ph/0309141) +# lambda [micrometer] lambda I_lambda [nW/m^2/sr] +0.01 0.0994467 +0.0956888 0.0999894 +0.1 0.173203 +0.106834 0.241658 +0.116677 0.385215 +0.130266 0.634872 +0.134644 0.737533 +0.153675 0.828938 +0.177339 0.916316 +0.218632 0.843567 +0.263665 0.726533 +0.321497 0.636256 +0.371003 0.636475 +0.447422 0.64745 +0.527823 0.703921 +0.602427 0.7402 +0.759246 0.704538 +0.946404 0.753444 +1.1797 0.779362 +1.43845 0.833417 +1.73474 0.862018 +2.00187 0.742345 +2.25978 0.683263 +2.60776 0.523691 +2.94374 0.421916 +3.32301 0.388337 +3.96357 0.401653 +4.52379 0.459008 +5.27823 0.551442 +6.29569 0.651589 +7.427 0.744694 +8.85867 0.77023 +10.5663 0.720923 +12.8839 0.60059 +17.7339 0.517431 +23.616 0.526479 +30.7637 0.572536 +35.1119 0.735148 +39.2014 0.975846 +41.8803 1.15276 +44.7422 1.45551 +48.8647 1.96438 +52.2039 2.48028 +55.7714 3.23767 +63.6543 4.08861 +71.0681 5.24958 +82.0117 5.90034 +97.8207 6.52281 +116.677 5.61771 +136.135 4.52631 +158.839 3.41204 +183.298 2.36662 +211.524 1.58776 +238.776 1.06516 +278.597 0.636036 +325.059 0.349464 +371.003 0.226772 +414.214 0.137669 +452.379 0.102049 +1000 0.100556 diff --git a/data-tools/PhotonField/Kneiske2004_IRB/z4.txt b/data-tools/PhotonField/Kneiske2004_IRB/z4.txt new file mode 100644 index 000000000..fb18281f2 --- /dev/null +++ b/data-tools/PhotonField/Kneiske2004_IRB/z4.txt @@ -0,0 +1,57 @@ +# IRB spectrum at z=4 from Kneiske et al. 2004 (astro-ph/0309141) +# lambda [micrometer] lambda I_lambda [nW/m^2/sr] +0.0101108 0.1 +0.101108 0.101664 +0.111647 0.164079 +0.120598 0.239844 +0.128839 0.333655 +0.139168 0.406742 +0.165995 0.406742 +0.213867 0.36236 +0.255093 0.312337 +0.307637 0.264813 +0.347272 0.252019 +0.437672 0.247894 +0.53367 0.256214 +0.650724 0.239844 +0.759246 0.235917 +0.925779 0.264813 +1.1797 0.287595 +1.64177 0.32282 +1.77339 0.317535 +2.04647 0.273701 +2.44096 0.213673 +2.87959 0.164079 +3.14491 0.139113 +3.62918 0.16681 +4.28133 0.206734 +4.9406 0.256214 +5.63892 0.32282 +6.72591 0.36236 +7.67657 0.380755 +9.15635 0.356428 +11.4134 0.292381 +13.7644 0.247894 +17.7339 0.239844 +23.1013 0.26922 +28.4804 0.278256 +31.7975 0.287595 +35.1119 0.400083 +40.0747 0.565833 +45.2379 0.813569 +51.0663 1.24961 +55.1603 1.68192 +63.6543 2.30148 +73.4562 2.89978 +83.8388 3.0977 +96.7489 3.14926 +114.134 2.58337 +133.169 2.11917 +153.675 1.4984 +181.29 0.991781 +206.914 0.645708 +241.421 0.400083 +272.525 0.256214 +304.266 0.16681 +351.119 0.101664 +989.043 0.0983629 diff --git a/data-tools/PhotonField/photonField.py b/data-tools/PhotonField/photonField.py index 60335da8c..ae494651f 100644 --- a/data-tools/PhotonField/photonField.py +++ b/data-tools/PhotonField/photonField.py @@ -3,76 +3,75 @@ def CMBSpectralRadiance(nu): - # CMB spectral radiance [W/sr/m^2/Hz] at frequency nu [1/s], see http://en.wikipedia.org/wiki/Planck%27s_law - return 2 * nu**3 * h_planck / c_light**2 / ( exp(nu * h_planck / k_boltzmann / 2.725) - 1 ) + """CMB spectral radiance [W/sr/m^2/Hz] at frequency nu [1/s], see http://en.wikipedia.org/wiki/Planck%27s_law""" + return 2 * nu**3 * h_planck / c_light**2 / ( exp(nu * h_planck / k_boltzmann / 2.725) - 1 ) def CMBSpectralEnergyDensity(nu): - # CMB spectral energy density [J/m^3/Hz] at frequency nu [1/s] - return CMBSpectralRadiance(nu) * 4 * pi / c_light + """CMB spectral energy density [J/m^3/Hz] at frequency nu [1/s]""" + return CMBSpectralRadiance(nu) * 4 * pi / c_light -def CMBSpectralDensity(nu): - # CMB spectral number density [1/m^3/Hz] at frequency nu [1/s] - return CMBSpectralEnergyDensity(nu) / (nu * h_planck) +def CMBSpectralNumberDensity(nu): + """CMB spectral number density [1/m^3/Hz] at frequency nu [1/s]""" + return CMBSpectralEnergyDensity(nu) / (nu * h_planck) -def IRBSpectralRadiance(nu): - # IRB (Kneiske et al. 2004) spectral radiance [W/sr/m^2/Hz] at frequency nu [1/s] - - # calculate wavelength [m] - x = c_light / nu - - # load data points - xKneiske, yKneiske = genfromtxt('Kneiske2004_IRB/z0.txt', unpack=1) - y = interp(x * 1e6, xKneiske, yKneiske, 0, 0) * 1e-9 # lambda * I_lambda [W/m^2/sr] - - # remove scaling with lambda; I_lambda [W/m^3/sr] - y /= x - - # convert to I_nu (using I_nu = - dlambda / dnu * I_lambda, dnu = - c / lambda^2 dlambda) - y *= x**2 / c_light - return y +def IRBSpectralRadiance(nu, fin='Kneiske2004_IRB/z0.txt'): + """IRB (Kneiske et al. 2004) spectral radiance [W/sr/m^2/Hz] at frequency nu [1/s] and z=0""" + # convert frequency [Hz] to wavelength [m] + x = c_light / nu + + # load data points + xKneiske, yKneiske = genfromtxt(fin, unpack=True) + y = interp(x * 1e6, xKneiske, yKneiske, 0, 0) * 1e-9 # lambda * I_lambda [W/m^2/sr] + + # remove scaling with lambda; I_lambda [W/m^3/sr] + y /= x + + # convert to I_nu (using I_nu = - dlambda / dnu * I_lambda, dnu = - c / lambda^2 dlambda) + y *= x**2 / c_light + return y def IRBSpectralEnergyDensity(nu): - # IRB (Kneiske et al. 2004) spectral energy density [J/m^3/Hz] at frequency nu [1/s] - return IRBSpectralRadiance(nu) * 4 * pi / c_light + """IRB (Kneiske et al. 2004) spectral energy density [J/m^3/Hz] at frequency nu [1/s]""" + return IRBSpectralRadiance(nu) * 4 * pi / c_light -def IRBSpectralDensity(nu): - # IRB (Kneiske et al. 2004) spectral density [1/m^3/Hz] at frequency nu [1/s] - return IRBSpectralEnergyDensity(nu) / (nu * h_planck) +def IRBSpectralNumberDensity(nu): + """IRB (Kneiske et al. 2004) spectral number density [1/m^3/Hz] at frequency nu [1/s]""" + return IRBSpectralEnergyDensity(nu) / (nu * h_planck) if __name__ == "__main__": - nu1 = logspace(-5, -2.3) * eV / h_planck - sed1 = CMBSpectralEnergyDensity(nu1) - snd1 = CMBSpectralDensity(nu1) + nu1 = logspace(-5, -2.3) * eV / h_planck + sed1 = CMBSpectralEnergyDensity(nu1) + snd1 = CMBSpectralNumberDensity(nu1) - nu2 = logspace(-5, 1.5) * eV / h_planck - sed2 = IRBSpectralEnergyDensity(nu2) - snd2 = IRBSpectralDensity(nu2) + nu2 = logspace(-5, 1.5) * eV / h_planck + sed2 = IRBSpectralEnergyDensity(nu2) + snd2 = IRBSpectralNumberDensity(nu2) - # number of photons per m^3 = integral over spectral number density - # integration using midpoint rule - N1 = sum( (snd1[1:] + snd1[:-1]) / 2 * (nu1[1:] - nu1[:-1]) ) - N2 = sum( (snd2[1:] + snd2[:-1]) / 2 * (nu2[1:] - nu2[:-1]) ) - print N1 / 1e6, 'CMB-photons per cubic centimeter' - print N2 / 1e6, 'IRB-photons per cubic centimeter' + # number of photons per m^3 = integral over spectral number density + # integration using midpoint rule + N1 = sum( (snd1[1:] + snd1[:-1]) / 2 * (nu1[1:] - nu1[:-1]) ) + N2 = sum( (snd2[1:] + snd2[:-1]) / 2 * (nu2[1:] - nu2[:-1]) ) + print N1 / 1e6, 'CMB-photons per cubic centimeter' + print N2 / 1e6, 'IRB-photons per cubic centimeter' - # plotting - figure() - plot(nu1, sed1, label='CMB') - plot(nu2, sed2, label='IRB Kneiske') - xlabel('Frequency [Hz]') - ylabel('Spectral Energy Density [J/m$^{3}$/Hz]') - loglog() - legend(frameon=0) - savefig('spectralEnergyDensity.png', bbox_inches='tight') + # plotting + figure() + plot(nu1, sed1, label='CMB') + plot(nu2, sed2, label='IRB Kneiske') + xlabel('Frequency [Hz]') + ylabel('Spectral Energy Density [J/m$^{3}$/Hz]') + loglog() + legend(frameon=0) +# savefig('spectralEnergyDensity.png', bbox_inches='tight') - figure() - plot(nu1, snd1, label='CMB') - plot(nu2, snd2, label='IRB Kneiske') - xlabel('Frequency [Hz]') - ylabel('Spectral Density [1/m$^{3}$/Hz]') - loglog() - legend(frameon=0) - savefig('spectralDensity.png', bbox_inches='tight') + figure() + plot(nu1, snd1, label='CMB') + plot(nu2, snd2, label='IRB Kneiske') + xlabel('Frequency [Hz]') + ylabel('Spectral Density [1/m$^{3}$/Hz]') + loglog() + legend(frameon=0) +# savefig('spectralNumberDensity.png', bbox_inches='tight') diff --git a/include/mpc/Random.h b/include/mpc/Random.h index 0e4018346..9451285b5 100644 --- a/include/mpc/Random.h +++ b/include/mpc/Random.h @@ -133,7 +133,7 @@ class Random { double randFisher(double k); /// Random point on a unit-sphere - Vector3d randUnitVectorOnSphere(); + Vector3d randVector(); /// Random vector with given angular separation around mean direction Vector3d randVectorAroundMean(const Vector3d &meanDirection, double angle); /// Fisher distributed random vector diff --git a/include/mpc/magneticField/MagneticField.h b/include/mpc/magneticField/MagneticField.h index 74f9633ba..af30787f4 100644 --- a/include/mpc/magneticField/MagneticField.h +++ b/include/mpc/magneticField/MagneticField.h @@ -41,9 +41,7 @@ class PeriodicMagneticField: public MagneticField { /** @class MagneticFieldList - @brief List of magnetic fields - - The field at a given position is the sum of all fields evaluated at that position. + @brief Magnetic field decorator implementing a superposition of fields. */ class MagneticFieldList: public MagneticField { std::vector > fields; @@ -57,9 +55,7 @@ class MagneticFieldList: public MagneticField { @brief Magnetic field with one B-field vector. */ class UniformMagneticField: public MagneticField { -private: Vector3d value; - public: UniformMagneticField(const Vector3d &value) : value(value) { diff --git a/include/mpc/magneticField/MagneticFieldGrid.h b/include/mpc/magneticField/MagneticFieldGrid.h index 75aa7b6f9..183fc2e74 100644 --- a/include/mpc/magneticField/MagneticFieldGrid.h +++ b/include/mpc/magneticField/MagneticFieldGrid.h @@ -14,7 +14,6 @@ namespace mpc { */ class MagneticFieldGrid: public MagneticField { ref_ptr grid; - public: MagneticFieldGrid(ref_ptr grid); void setGrid(ref_ptr grid); @@ -33,13 +32,15 @@ class MagneticFieldGrid: public MagneticField { class ModulatedMagneticFieldGrid: public MagneticField { ref_ptr grid; ref_ptr modGrid; - public: + ModulatedMagneticFieldGrid() { + } ModulatedMagneticFieldGrid(ref_ptr grid, ref_ptr modGrid); void setGrid(ref_ptr grid); void setModulationGrid(ref_ptr modGrid); ref_ptr getGrid(); ref_ptr getModulationGrid(); + void setReflective(bool gridReflective, bool modGridReflective); Vector3d getField(const Vector3d &position) const; }; diff --git a/src/Random.cpp b/src/Random.cpp index 7941c4dc0..742b90dbd 100644 --- a/src/Random.cpp +++ b/src/Random.cpp @@ -122,7 +122,7 @@ double Random::randFisher(double kappa) { return acos(1. + 1. / kappa * log(1 - rand() * (1 - exp(-2 * kappa)))); } -Vector3d Random::randUnitVectorOnSphere() { +Vector3d Random::randVector() { double z = randUniform(-1.0, 1.0); double t = randUniform(-1.0 * M_PI, M_PI); double r = sqrt(1 - z * z); @@ -130,7 +130,7 @@ Vector3d Random::randUnitVectorOnSphere() { } Vector3d Random::randVectorAroundMean(const Vector3d &meanDirection, double angle) { - Vector3d rotAxis = meanDirection.cross(randUnitVectorOnSphere()); + Vector3d rotAxis = meanDirection.cross(randVector()); rotAxis.normalize(); Vector3d v = meanDirection; v.rotate(rotAxis, angle); diff --git a/src/Source.cpp b/src/Source.cpp index 68d04bf67..fbede8cef 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -175,7 +175,7 @@ SourceUniformSphere::SourceUniformSphere(Vector3d center, double radius) : void SourceUniformSphere::prepare(ParticleState& particle) const { Random &random = Random::instance(); double r = pow(random.rand(), 1. / 3.) * radius; - particle.setPosition(random.randUnitVectorOnSphere() * r); + particle.setPosition(random.randVector() * r); } SourceUniformShell::SourceUniformShell(Vector3d center, double radius) : @@ -184,7 +184,7 @@ SourceUniformShell::SourceUniformShell(Vector3d center, double radius) : void SourceUniformShell::prepare(ParticleState& particle) const { Random &random = Random::instance(); - particle.setPosition(random.randUnitVectorOnSphere() * radius); + particle.setPosition(random.randVector() * radius); } SourceUniformBox::SourceUniformBox(Vector3d origin, Vector3d size) : @@ -283,7 +283,7 @@ void SourceDensityGrid1D::prepare(ParticleState& particle) const { void SourceIsotropicEmission::prepare(ParticleState& particle) const { Random &random = Random::instance(); - particle.setDirection(random.randUnitVectorOnSphere()); + particle.setDirection(random.randVector()); } SourceDirection::SourceDirection(Vector3d direction) : diff --git a/src/magneticField/MagneticFieldGrid.cpp b/src/magneticField/MagneticFieldGrid.cpp index 31683333b..e09afc19f 100644 --- a/src/magneticField/MagneticFieldGrid.cpp +++ b/src/magneticField/MagneticFieldGrid.cpp @@ -20,7 +20,7 @@ Vector3d MagneticFieldGrid::getField(const Vector3d &pos) const { ModulatedMagneticFieldGrid::ModulatedMagneticFieldGrid(ref_ptr grid, ref_ptr modGrid) { - grid->setReflective(true); + grid->setReflective(false); modGrid->setReflective(true); setGrid(grid); setModulationGrid(modGrid); @@ -42,6 +42,12 @@ ref_ptr ModulatedMagneticFieldGrid::getModulationGrid() { return modGrid; } +void ModulatedMagneticFieldGrid::setReflective(bool gridReflective, + bool modGridReflective) { + grid->setReflective(gridReflective); + modGrid->setReflective(modGridReflective); +} + Vector3d ModulatedMagneticFieldGrid::getField(const Vector3d &pos) const { float m = modGrid->interpolate(pos); Vector3d b = grid->interpolate(pos); diff --git a/src/magneticField/TurbulentMagneticField.cpp b/src/magneticField/TurbulentMagneticField.cpp index a1153bd67..3d86e9520 100644 --- a/src/magneticField/TurbulentMagneticField.cpp +++ b/src/magneticField/TurbulentMagneticField.cpp @@ -45,7 +45,7 @@ void TurbulentMagneticField::initialize() { double sumGk = 0; for (int i = 0; i < nModes; i++) { // construct an orthogonal base ek, e1, e2 - ek = random.randUnitVectorOnSphere(); + ek = random.randVector(); if (ek.getAngleTo(n0) < 1e-3) { // ek parallel to (1,1,1) e1.setXYZ(-1., 1., 0); From 74e287c98bd7e99ea3330ff7f3d63fa9e46f1b55 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 24 May 2013 14:57:18 +0400 Subject: [PATCH 0307/1298] add capability for custom flags to break condition modules --- include/mpc/Source.h | 2 +- include/mpc/module/BreakCondition.h | 28 ++++++----- src/module/BreakCondition.cpp | 73 +++++++++++++++++++---------- 3 files changed, 66 insertions(+), 37 deletions(-) diff --git a/include/mpc/Source.h b/include/mpc/Source.h index bee8613e8..e1f411487 100644 --- a/include/mpc/Source.h +++ b/include/mpc/Source.h @@ -96,7 +96,7 @@ class SourcePowerLawSpectrum: public SourceProperty { @param index differential spectral index */ SourcePowerLawSpectrum(double Emin, double Emax, double differentialIndex); - /** Set particle with a random energy from a power law distribtuition */ + /** Set particle with a random energy from a power law distribution */ void prepare(ParticleState &particle) const; }; diff --git a/include/mpc/module/BreakCondition.h b/include/mpc/module/BreakCondition.h index 3ddbadd3b..85ff28c8c 100644 --- a/include/mpc/module/BreakCondition.h +++ b/include/mpc/module/BreakCondition.h @@ -14,15 +14,17 @@ namespace mpc { It also limits the candidates next step size to ensure the maximum trajectory length is no exceeded. */ class MaximumTrajectoryLength: public Module { -private: double maxLength; - + std::string flag; public: - MaximumTrajectoryLength(double length = 0); + MaximumTrajectoryLength(double length = 0, + std::string flag = "Deactivated"); void setMaximumTrajectoryLength(double length); double getMaximumTrajectoryLength() const; - void process(Candidate *candidate) const; + void setFlag(std::string flag); + std::string getFlag() const; std::string getDescription() const; + void process(Candidate *candidate) const; }; /** @@ -33,15 +35,16 @@ class MaximumTrajectoryLength: public Module { In that case the property ("Deactivated", module::description) is set. */ class MinimumEnergy: public Module { -private: double minEnergy; - + std::string flag; public: - MinimumEnergy(double minEnergy = 0); + MinimumEnergy(double minEnergy = 0, std::string flag = "Deactivated"); void setMinimumEnergy(double energy); double getMinimumEnergy() const; - void process(Candidate *candidate) const; + void setFlag(std::string flag); + std::string getFlag() const; std::string getDescription() const; + void process(Candidate *candidate) const; }; /** @@ -52,15 +55,16 @@ class MinimumEnergy: public Module { In that case the property ("Deactivated", module::description) is set. */ class MinimumRedshift: public Module { -private: double zmin; - + std::string flag; public: - MinimumRedshift(double zmin = 0); + MinimumRedshift(double zmin = 0, std::string flag = "Deactivated"); void setMinimumRedshift(double z); double getMinimumRedshift(); - void process(Candidate *candidate) const; + void setFlag(std::string flag); + std::string getFlag() const; std::string getDescription() const; + void process(Candidate *candidate) const; }; } // namespace mpc diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp index b67efdba4..222e3e0a3 100644 --- a/src/module/BreakCondition.cpp +++ b/src/module/BreakCondition.cpp @@ -4,8 +4,9 @@ namespace mpc { -MaximumTrajectoryLength::MaximumTrajectoryLength(double maxLength) { - this->maxLength = maxLength; +MaximumTrajectoryLength::MaximumTrajectoryLength(double maxLength, + std::string flag) : + maxLength(maxLength), flag(flag) { } void MaximumTrajectoryLength::setMaximumTrajectoryLength(double length) { @@ -16,24 +17,33 @@ double MaximumTrajectoryLength::getMaximumTrajectoryLength() const { return maxLength; } +void MaximumTrajectoryLength::setFlag(std::string f) { + flag = f; +} + +std::string MaximumTrajectoryLength::getFlag() const { + return flag; +} + +std::string MaximumTrajectoryLength::getDescription() const { + std::stringstream s; + s << "Maximum trajectory length: " << maxLength / Mpc << " Mpc, flag: " + << flag; + return s.str(); +} + void MaximumTrajectoryLength::process(Candidate *c) const { double l = c->getTrajectoryLength(); if (l >= maxLength) { c->setActive(false); - c->setProperty("Deactivated", getDescription()); + c->setProperty(flag, getDescription()); } else { c->limitNextStep(maxLength - l); } } -std::string MaximumTrajectoryLength::getDescription() const { - std::stringstream s; - s << "Maximum trajectory length: " << maxLength / Mpc << " Mpc"; - return s.str(); -} - -MinimumEnergy::MinimumEnergy(double minEnergy) { - this->minEnergy = minEnergy; +MinimumEnergy::MinimumEnergy(double minEnergy, std::string flag) : + minEnergy(minEnergy), flag(flag) { } void MinimumEnergy::setMinimumEnergy(double energy) { @@ -44,21 +54,29 @@ double MinimumEnergy::getMinimumEnergy() const { return minEnergy; } +void MinimumEnergy::setFlag(std::string f) { + flag = f; +} + +std::string MinimumEnergy::getFlag() const { + return flag; +} + void MinimumEnergy::process(Candidate *c) const { - if (c->current.getEnergy() <= minEnergy) { - c->setActive(false); - c->setProperty("Deactivated", getDescription()); - } + if (c->current.getEnergy() > minEnergy) + return; + c->setActive(false); + c->setProperty(flag, getDescription()); } std::string MinimumEnergy::getDescription() const { std::stringstream s; - s << "Minimum energy: " << minEnergy / EeV << " EeV"; + s << "Minimum energy: " << minEnergy / EeV << " EeV, flag: " << flag; return s.str(); } -MinimumRedshift::MinimumRedshift(double z) : - zmin(z) { +MinimumRedshift::MinimumRedshift(double zmin, std::string flag) : + zmin(zmin), flag(flag) { } void MinimumRedshift::setMinimumRedshift(double z) { @@ -69,17 +87,24 @@ double MinimumRedshift::getMinimumRedshift() { return zmin; } +void MinimumRedshift::setFlag(std::string f) { + flag = f; +} + +std::string MinimumRedshift::getFlag() const { + return flag; +} + void MinimumRedshift::process(Candidate* c) const { - double z = c->getRedshift(); - if (z <= zmin) { - c->setActive(false); - c->setProperty("Deactivated", getDescription()); - } + if (c->getRedshift() > zmin) + return; + c->setActive(false); + c->setProperty(flag, getDescription()); } std::string MinimumRedshift::getDescription() const { std::stringstream s; - s << "Minimum redshift: " << zmin; + s << "Minimum redshift: " << zmin << ", flag: " << flag; return s.str(); } From 57a562f5c3155e8bf7c0edfeb9137d9c93ab1a8d Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 19 Jun 2013 14:07:44 +0200 Subject: [PATCH 0308/1298] renamed PhotonOutput -> PhotonDINT added template PhotonEleCa --- CMakeLists.txt | 10 ++++++-- .../module/{PhotonOutput.h => PhotonDINT.h} | 12 +++++----- include/mpc/module/PhotonEleCa.h | 22 +++++++++++++++++ python/mpc.i | 6 +++-- .../{PhotonOutput.cpp => PhotonDINT.cpp} | 12 +++++----- src/module/PhotonEleCa.cpp | 24 +++++++++++++++++++ 6 files changed, 70 insertions(+), 16 deletions(-) rename include/mpc/module/{PhotonOutput.h => PhotonDINT.h} (61%) create mode 100644 include/mpc/module/PhotonEleCa.h rename src/module/{PhotonOutput.cpp => PhotonDINT.cpp} (93%) create mode 100644 src/module/PhotonEleCa.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 406b8a307..01f7c414c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,11 +38,16 @@ add_subdirectory(libs/sophia) list(APPEND MPC_EXTRA_LIBRARIES sophia gfortran) list(APPEND MPC_EXTRA_INCLUDES libs/sophia) -# dint (provided) +# DINT (provided) add_subdirectory(libs/dint) list(APPEND MPC_EXTRA_LIBRARIES dint) list(APPEND MPC_EXTRA_INCLUDES libs/dint/include) +# EleCa (provided) +#add_subdirectory(libs/eleca) +#list(APPEND MPC_EXTRA_LIBRARIES eleca) +#list(APPEND MPC_EXTRA_INCLUDES libs/eleca/include) + # OpenMP (optional for shared memory multiprocessing) option(ENABLE_OPENMP "OpenMP for multithreading" ON) if(ENABLE_OPENMP) @@ -133,7 +138,8 @@ add_library(mpc SHARED src/module/Output.cpp src/module/OutputROOT.cpp src/module/OutputCRPropa2.cpp - src/module/PhotonOutput.cpp + src/module/PhotonDINT.cpp + src/module/PhotonEleCa.cpp src/module/Tools.cpp src/magneticField/MagneticField.cpp src/magneticField/MagneticFieldGrid.cpp diff --git a/include/mpc/module/PhotonOutput.h b/include/mpc/module/PhotonDINT.h similarity index 61% rename from include/mpc/module/PhotonOutput.h rename to include/mpc/module/PhotonDINT.h index d72230d32..313b8478e 100644 --- a/include/mpc/module/PhotonOutput.h +++ b/include/mpc/module/PhotonDINT.h @@ -1,5 +1,5 @@ -#ifndef MPC_MODULE_PHOTON_OUTPUT_H_ -#define MPC_MODULE_PHOTON_OUTPUT_H_ +#ifndef MPC_MODULE_PHOTON_DINT_H_ +#define MPC_MODULE_PHOTON_DINT_H_ #include "mpc/Module.h" #include "mpc/magneticField/MagneticField.h" @@ -8,7 +8,7 @@ namespace mpc { -class PhotonOutput: public Module { +class PhotonDINT: public Module { private: std::string filename, dataPath; mutable std::ofstream fout; @@ -18,12 +18,12 @@ class PhotonOutput: public Module { double Zmax, Cutcascade_Magfield; public: - PhotonOutput(const std::string &filename, ref_ptr field); - ~PhotonOutput(); + PhotonDINT(const std::string &filename, ref_ptr field); + ~PhotonDINT(); void process(Candidate *candidate) const; std::string getDescription() const; }; } // namespace mpc -#endif /* MPC_MODULE_PHOTON_OUTPUT_H_ */ +#endif /* MPC_MODULE_PHOTON_DINT_H_ */ diff --git a/include/mpc/module/PhotonEleCa.h b/include/mpc/module/PhotonEleCa.h new file mode 100644 index 000000000..8dc68315e --- /dev/null +++ b/include/mpc/module/PhotonEleCa.h @@ -0,0 +1,22 @@ +#ifndef MPC_PHOTON_ELECA_H_ +#define MPC_PHOTON_ELECA_H_ + +#include "mpc/Module.h" +#include "mpc/magneticField/MagneticField.h" + +namespace mpc { + +class PhotonEleCa: public Module { +private: + ref_ptr field; + +public: + PhotonEleCa(ref_ptr field); + ~PhotonEleCa(); + void process(Candidate *candidate) const; + std::string getDescription() const; +}; + +} // namespace mpc + +#endif /* MPC_PHOTON_ELECA_H_ */ diff --git a/python/mpc.i b/python/mpc.i index 511f1a2c7..21b8cedbb 100644 --- a/python/mpc.i +++ b/python/mpc.i @@ -37,7 +37,8 @@ using std::ptrdiff_t; #include "mpc/module/Output.h" #include "mpc/module/OutputROOT.h" #include "mpc/module/OutputCRPropa2.h" -#include "mpc/module/PhotonOutput.h" +#include "mpc/module/PhotonDINT.h" +#include "mpc/module/PhotonEleCa.h" #include "mpc/module/SimplePropagation.h" #include "mpc/module/DeflectionCK.h" #include "mpc/module/Tools.h" @@ -151,7 +152,8 @@ using std::ptrdiff_t; %include "mpc/module/Output.h" %include "mpc/module/OutputROOT.h" %include "mpc/module/OutputCRPropa2.h" -%include "mpc/module/PhotonOutput.h" +%include "mpc/module/PhotonDINT.h" +%include "mpc/module/PhotonEleCa.h" %include "mpc/module/ElectronPairProduction.h" %include "mpc/module/StochasticInteraction.h" %include "mpc/module/NuclearDecay.h" diff --git a/src/module/PhotonOutput.cpp b/src/module/PhotonDINT.cpp similarity index 93% rename from src/module/PhotonOutput.cpp rename to src/module/PhotonDINT.cpp index 58cd9e856..d71642712 100644 --- a/src/module/PhotonOutput.cpp +++ b/src/module/PhotonDINT.cpp @@ -1,4 +1,4 @@ -#include "mpc/module/PhotonOutput.h" +#include "mpc/module/PhotonDINT.h" #include "mpc/Cosmology.h" #include @@ -10,7 +10,7 @@ using namespace std; namespace mpc { -PhotonOutput::PhotonOutput(const string &filename, ref_ptr field) : +PhotonDINT::PhotonDINT(const string &filename, ref_ptr field) : filename(filename), fout(filename.c_str()), field(field), IRFlag(0), RadioFlag( 0), Zmax(5), Cutcascade_Magfield(0) { dataPath = getDataPath("dint"); @@ -35,10 +35,10 @@ PhotonOutput::PhotonOutput(const string &filename, ref_ptr field) #endif } -PhotonOutput::~PhotonOutput() { +PhotonDINT::~PhotonDINT() { } -void PhotonOutput::process(Candidate *candidate) const { +void PhotonDINT::process(Candidate *candidate) const { if (candidate->current.getId() != 22) return; @@ -132,9 +132,9 @@ void PhotonOutput::process(Candidate *candidate) const { Delete_dCVector(&energyWidth); } -string PhotonOutput::getDescription() const { +string PhotonDINT::getDescription() const { std::stringstream s; - s << "PhotonModule: Output file = " << filename; + s << "PhotonDINT: Output file = " << filename; return s.str(); } diff --git a/src/module/PhotonEleCa.cpp b/src/module/PhotonEleCa.cpp new file mode 100644 index 000000000..8076235fe --- /dev/null +++ b/src/module/PhotonEleCa.cpp @@ -0,0 +1,24 @@ +#include "mpc/module/PhotonEleCa.h" + +namespace mpc { + +PhotonEleCa::PhotonEleCa(ref_ptr field) { +} + +PhotonEleCa::~PhotonEleCa() { +} + +void PhotonEleCa::process(Candidate *candidate) const { + if (candidate->current.getId() != 22) + return; // do nothing if not a photon + + return; +} + +std::string PhotonEleCa::getDescription() const { + std::stringstream s; + s << "PhotonEleCa"; + return s.str(); +} + +} // namespace mpc From 67eef46a990f78a9dd693dd0b5d016bd4725eb27 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 19 Jun 2013 14:15:08 +0200 Subject: [PATCH 0309/1298] removed provisionary eleca line --- CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 01f7c414c..66a623f8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,11 +43,6 @@ add_subdirectory(libs/dint) list(APPEND MPC_EXTRA_LIBRARIES dint) list(APPEND MPC_EXTRA_INCLUDES libs/dint/include) -# EleCa (provided) -#add_subdirectory(libs/eleca) -#list(APPEND MPC_EXTRA_LIBRARIES eleca) -#list(APPEND MPC_EXTRA_INCLUDES libs/eleca/include) - # OpenMP (optional for shared memory multiprocessing) option(ENABLE_OPENMP "OpenMP for multithreading" ON) if(ENABLE_OPENMP) From 3964d6300d82ceacb973edcffa5a2cb70fc1b011 Mon Sep 17 00:00:00 2001 From: geromueller Date: Thu, 20 Jun 2013 17:44:54 +0200 Subject: [PATCH 0310/1298] add doxyfile for slim public documentation --- doc/Doxyfile | 1854 +++++++++++++++++++++++------------------- doc/Doxyfile.public | 1884 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2895 insertions(+), 843 deletions(-) create mode 100644 doc/Doxyfile.public diff --git a/doc/Doxyfile b/doc/Doxyfile index 1eec30197..0aea38d3a 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -1,783 +1,833 @@ -# Doxyfile 1.7.4 +# Doxyfile 1.8.4 # This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project. +# doxygen (www.doxygen.org) for a project # -# All text after a hash (#) is considered a comment and will be ignored. +# All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" "). +# Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. -PROJECT_NAME = MPC +PROJECT_NAME = "CRPropa 3.0" -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = +PROJECT_NUMBER = -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = Cosmic Ray Tracking +PROJECT_BRIEF = Tracking -# With the PROJECT_LOGO tag one can specify an logo or icon that is -# included in the documentation. The maximum height of the logo should not -# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. -PROJECT_LOGO = +PROJECT_LOGO = -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. -OUTPUT_DIRECTORY = +OUTPUT_DIRECTORY = -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, -# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English -# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, -# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, -# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian, +# Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, +# Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" -ABBREVIATE_BRIEF = +ABBREVIATE_BRIEF = -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. -INLINE_INHERITED_MEMB = NO +INLINE_INHERITED_MEMB = YES -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = ../include -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful if your file system +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO -# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. -ALIASES = +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given extension. -# Doxygen has a built-in mapping, but you can override or extend it using this -# tag. The format is ext=language, where ext is a file extension, and language -# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, -# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions -# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. - -EXTENSION_MAPPING = - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also makes the inheritance and collaboration +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = YES -# If you use Microsoft's C++/CLI language, you should set this option to YES to +# If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and -# unions are shown inside the group in which they are included (e.g. using -# @ingroup) instead of on a separate page (for HTML and Man pages) or +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or # section (for LaTeX and RTF). INLINE_GROUPED_CLASSES = NO -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields or simple typedef fields will be shown +# inline in the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO (the default), structs, classes, and unions are shown on a separate +# page (for HTML and Man pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penalty. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will roughly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols - -SYMBOL_CACHE_SIZE = 0 +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can +# be an expensive process and often the same symbol appear multiple times in +# the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too +# small doxygen will become slower. If the cache is too large, memory is wasted. +# The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid +# range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536 +# symbols. + +LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO -# If the EXTRACT_STATIC tag is set to YES all static members of a file +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. -EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_CLASSES = NO -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default # anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = NO -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. -HIDE_SCOPE_NAMES = NO +HIDE_SCOPE_NAMES = YES -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation # of that file. -SHOW_INCLUDE_FILES = YES +SHOW_INCLUDE_FILES = NO -# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen -# will list include files with double quotes in the documentation +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen -# will sort the (brief and detailed) documentation of class members so that -# constructors and destructors are listed first. If set to NO (the default) -# the constructors will appear in the respective orders defined by -# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. -# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to -# do proper type resolution of all parameters of a function it will reject a -# match between the prototype and the implementation of a member function even -# if there is only one candidate or it is obvious which candidate to choose -# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen # will still accept a match between prototype and implementation in such cases. STRICT_PROTO_MATCHING = NO -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. -GENERATE_TODOLIST = YES +GENERATE_TODOLIST = NO -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test # commands in the documentation. -GENERATE_TESTLIST = YES +GENERATE_TESTLIST = NO -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. -GENERATE_BUGLIST = YES +GENERATE_BUGLIST = NO -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. -GENERATE_DEPRECATEDLIST= YES +GENERATE_DEPRECATEDLIST= NO -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if section-label ... \endif +# and \cond section-label ... \endcond blocks. -ENABLED_SECTIONS = +ENABLED_SECTIONS = -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or macro consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and macros in the -# documentation can be controlled using \showinitializer or \hideinitializer +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. -SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. +SHOW_USED_FILES = NO -SHOW_DIRECTORIES = NO - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. -SHOW_FILES = YES +SHOW_FILES = NO -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. -# This will remove the Namespaces entry from the Quick Index +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. -SHOW_NAMESPACES = YES +SHOW_NAMESPACES = NO -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. -FILE_VERSION_FILTER = +FILE_VERSION_FILTER = -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. The create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. -# You can optionally specify a file name after the option, if omitted +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. -LAYOUT_FILE = +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. Do not use +# file names with spaces, bibtex cannot handle them. + +CITE_BIB_FILES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- -# The QUIET tag can be used to turn on/off the messages that are generated +# The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES -# The WARN_NO_PARAMDOC option can be enabled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written # to stderr. -WARN_LOGFILE = +WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = "../include" -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh -# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl -FILE_PATTERNS = +FILE_PATTERNS = -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. EXCLUDE = -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = Loki::* \ + ProgressBar* -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = Loki::* \ + ProgressBar -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see # the \include command). -EXAMPLE_PATH = +EXAMPLE_PATH = -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left # blank all files are included. -EXAMPLE_PATTERNS = +EXAMPLE_PATTERNS = -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see # the \image command). -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. -# If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. -# Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. -# The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty or if +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be ignored. +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. -FILTER_PATTERNS = +FILTER_PATTERNS = -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) -# and it is also possible to disable source filtering for a specific pattern -# using *.ext= (so without naming a filter). This option only has effect when +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when # FILTER_SOURCE_FILES is enabled. -FILTER_SOURCE_PATTERNS = +FILTER_SOURCE_PATTERNS = + +# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO -# Setting the INLINE_SOURCES tag to YES will include the body +# Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. STRIP_CODE_COMMENTS = YES -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. -# Otherwise they will link to the documentation. +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES @@ -786,157 +836,171 @@ VERBATIM_HEADERS = YES # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. -IGNORE_PREFIX = +IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. Note that when using a custom header you are responsible -# for the proper inclusion of any scripts and style sheets that doxygen -# needs, which is dependent on the configuration options used. -# It is adviced to generate a default header using "doxygen -w html -# header.html footer.html stylesheet.css YourConfigFile" and then modify -# that header. Note that the header is subject to change so you typically -# have to redo this when upgrading to a newer version of doxygen or when changing the value of configuration settings such as GENERATE_TREEVIEW! +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. -HTML_HEADER = +HTML_FOOTER = -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. -HTML_FOOTER = +HTML_STYLESHEET = -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. -HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. -HTML_EXTRA_FILES = +HTML_EXTRA_FILES = -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. -# Doxygen will adjust the colors in the stylesheet and background images -# according to this color. Hue is specified as an angle on a colorwheel, -# see http://en.wikipedia.org/wiki/Hue for more information. -# For instance the value 0 represents red, 60 is yellow, 120 is green, -# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of -# the colors in the HTML output. For a value of 0 the output will use +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to -# the luminance component of the colors in the HTML output. Values below -# 100 gradually make the output lighter, whereas values above 100 make -# the output darker. The value divided by 100 is the actual gamma applied, -# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. HTML_DYNAMIC_SECTIONS = NO -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project -# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher @@ -944,374 +1008,443 @@ DOCSET_PUBLISHER_ID = org.doxygen.Publisher DOCSET_PUBLISHER_NAME = Publisher -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be # written to the html output directory. -CHM_FILE = +CHM_FILE = -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. -HHC_LOCATION = +HHC_LOCATION = -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. -CHM_INDEX_ENCODING = +CHM_INDEX_ENCODING = -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO -# The TOC_EXPAND flag can be set to YES to add extra items for group members +# The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated -# that can be used as input for Qt's qhelpgenerator to generate a +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. -QCH_FILE = +QCH_FILE = -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to -# add. For more information please see +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters -QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_NAME = -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see -# +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# # Qt Help Project / Custom Filters. -QHP_CUST_FILTER_ATTRS = +QHP_CUST_FILTER_ATTRS = -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's -# filter section matches. -# +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# # Qt Help Project / Filter Attributes. -QHP_SECT_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. -QHG_LOCATION = +QHG_LOCATION = -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files -# will be generated, which together with the HTML files, form an Eclipse help -# plugin. To install this plugin and make it available under the help contents -# menu in Eclipse, the contents of the directory containing the HTML and XML -# files needs to be copied into the plugins directory of eclipse. The name of -# the directory within the plugins directory should be the same as -# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO -# A unique identifier for the eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. DISABLE_INDEX = NO -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values -# (range [0,1..20]) that doxygen will group on one line in the generated HTML -# documentation. Note that a value of 0 will completely suppress the enum -# values from appearing in the overview section. - -ENUM_VALUES_PER_LINE = 4 - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to YES, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). -# Windows users are probably better off using the HTML help feature. +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. GENERATE_TREEVIEW = NO -# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, -# and Class Hierarchy pages using a tree view instead of an ordered list. +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. -USE_INLINE_TREES = NO +ENUM_VALUES_PER_LINE = 4 -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are -# not supported properly for IE 6.0, but are supported on all modern browsers. -# Note that when changing this option you need to delete any form_*.png files +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax -# (see http://www.mathjax.org) which uses client side Javascript for the -# rendering instead of using prerendered bitmaps. Use this if you do not -# have LaTeX installed or if you want to formulas look prettier in the HTML -# output. When enabled you also need to install MathJax separately and +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and # configure the path to it using the MATHJAX_RELPATH option. USE_MATHJAX = NO -# When MathJax is enabled you need to specify the location relative to the -# HTML output directory using the MATHJAX_RELPATH option. The destination -# directory should contain the MathJax.js script. For instance, if the mathjax -# directory is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to the -# mathjax.org site, so you can quickly see the result without installing -# MathJax, but it is strongly recommended to install a local copy of MathJax -# before deployment. +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and +# SVG. The default value is HTML-CSS, which is slower, but has the best +# compatibility. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. MATHJAX_RELPATH = http://www.mathjax.org/mathjax -# When the SEARCHENGINE tag is enabled doxygen will generate a search box -# for the HTML output. The underlying search engine uses javascript -# and DHTML and should work on any modern browser. Note that when using -# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets -# (GENERATE_DOCSET) there is already a search function so this one should -# typically be disabled. For large projects the javascript based search engine +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript +# pieces of code that will be used on startup of the MathJax code. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = YES -# When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a PHP enabled web server instead of at the web client -# using Javascript. Doxygen will generate the search PHP script and index -# file to put on the web server. The advantage of the server -# based approach is that it scales better to large projects and allows -# full text search. The disadvantages are that it is more difficult to setup -# and does not have live searching capabilities. +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. +# There are two flavours of web server based search depending on the +# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for +# searching and an index file used by the script. When EXTERNAL_SEARCH is +# enabled the indexing and searching needs to be provided by external tools. +# See the manual for details. SERVER_BASED_SEARCH = NO +# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain +# the search results. Doxygen ships with an example indexer (doxyindexer) and +# search engine (doxysearch.cgi) which are based on the open source search +# engine library Xapian. See the manual for configuration details. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will returned the search results when EXTERNAL_SEARCH is enabled. +# Doxygen ships with an example search engine (doxysearch) which is based on +# the open source search engine library Xapian. See the manual for configuration +# details. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id +# of to a relative location where the documentation can be found. +# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ... + +EXTRA_SEARCH_MAPPINGS = + #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. -# Note that when enabling USE_PDFLATEX this option is only used for -# generating bitmaps for formulas in the HTML output, but not in the +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, letter, legal and -# executive. If left blank a4wide will be used. +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4 will be used. PAPER_TYPE = a4 -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. -EXTRA_PACKAGES = +EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! -LATEX_HEADER = +LATEX_HEADER = -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for -# the generated latex document. The footer should contain everything after -# the last chapter. If it is left blank doxygen will generate a +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a # standard footer. Notice: only use this tag if you know what you are doing! -LATEX_FOOTER = +LATEX_FOOTER = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images +# or other source files which should be copied to the LaTeX output directory. +# Note that the files will be copied as-is; there are no commands or markers +# available. -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO -# If LATEX_SOURCE_CODE is set to YES then doxygen will include -# source code with syntax highlighting in the LaTeX output. -# Note that which sources are shown also depends on other settings +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. -RTF_STYLESHEET_FILE = +RTF_STYLESHEET_FILE = -# Set optional variables used in the generation of an rtf document. +# Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. -RTF_EXTENSIONS_FILE = +RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man -# The MAN_EXTENSION tag determines the extension that is added to +# The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO @@ -1320,45 +1453,60 @@ MAN_LINKS = NO # configuration options related to the XML output #--------------------------------------------------------------------------- -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = YES -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the # syntax of the XML files. -XML_SCHEMA = +XML_SCHEMA = -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the # syntax of the XML files. -XML_DTD = +XML_DTD = -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = NO +#--------------------------------------------------------------------------- +# configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files +# that can be used to generate PDF. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. If left blank docbook will be used as the default path. + +DOCBOOK_OUTPUT = docbook + #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO @@ -1367,99 +1515,101 @@ GENERATE_AUTOGEN_DEF = NO # configuration options related to the Perl module output #--------------------------------------------------------------------------- -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. -# This is useful -# if you want to understand what is going on. -# On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. -PERLMOD_MAKEVAR_PREFIX = +PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. -MACRO_EXPANSION = NO +MACRO_EXPANSION = YES -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. -EXPAND_ONLY_PREDEF = NO +EXPAND_ONLY_PREDEF = YES -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by # the preprocessor. -INCLUDE_PATH = +INCLUDE_PATH = -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. -INCLUDE_FILE_PATTERNS = +INCLUDE_FILE_PATTERNS = -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = MPC_HAVE_ROOT MPC_HAVE_GADGET MPC_HAVE_FFTW3F +PREDEFINED = MPC_HAVE_ROOT \ + MPC_HAVE_GADGET \ + MPC_HAVE_FFTW3F \ + "protected=private +" -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition that +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that # overrules the definition found in the source code. -EXPAND_AS_DEFINED = +EXPAND_AS_DEFINED = -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all references to function-like macros -# that are alone on a line, have an all uppercase name, and do not end with a +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a # semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES @@ -1468,43 +1618,43 @@ SKIP_FUNCTION_MACROS = YES # Configuration::additions related to external references #--------------------------------------------------------------------------- -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. -GENERATE_TAGFILE = +GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES -# The PERL_PATH should be the absolute path and name of the perl script +# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed +# in the related pages index. If set to NO, only the current project's +# pages will be listed. + +EXTERNAL_PAGES = YES + +# The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl @@ -1513,204 +1663,222 @@ PERL_PATH = /usr/bin/perl # Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option also works with HAVE_DOT disabled, but it is recommended to +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to # install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. -MSCGEN_PATH = +MSCGEN_PATH = -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO -# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is -# allowed to run in parallel. When set to 0 (the default) doxygen will -# base this on the number of processors available in the system. You can set it -# explicitly to a value larger than 0 to get control over the balance +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 -# By default doxygen will write a font called Helvetica to the output -# directory and reference it in all dot files that doxygen generates. -# When you want a differently looking font you can specify the font name -# using DOT_FONTNAME. You need to make sure dot is able to find the font, -# which can be done by putting it in a standard location or by setting the -# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory -# containing the font. +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. DOT_FONTNAME = Helvetica -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 -# By default doxygen will tell dot to use the output directory to look for the -# FreeSans.ttf font (which doxygen will put there itself). If you specify a -# different font using DOT_FONTNAME you can set the path where dot -# can find it using this tag. +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. -DOT_FONTPATH = +DOT_FONTPATH = -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO -# If set to YES, the inheritance and collaboration graphs will show the +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# manageable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are svg, png, jpg, or gif. -# If left blank png will be used. +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). DOT_IMAGE_FORMAT = png -# The tag DOT_PATH can be used to specify the path where the dot tool can be +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. -DOT_PATH = +DOT_PATH = -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the # \dotfile command). -DOTFILE_DIRS = +DOTFILE_DIRS = -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the # \mscfile command). -MSCFILE_DIRS = +MSCFILE_DIRS = -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = YES -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES diff --git a/doc/Doxyfile.public b/doc/Doxyfile.public new file mode 100644 index 000000000..0aea38d3a --- /dev/null +++ b/doc/Doxyfile.public @@ -0,0 +1,1884 @@ +# Doxyfile 1.8.4 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = "CRPropa 3.0" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = Tracking + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian, +# Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, +# Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = ../include + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields or simple typedef fields will be shown +# inline in the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO (the default), structs, classes, and unions are shown on a separate +# page (for HTML and Man pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can +# be an expensive process and often the same symbol appear multiple times in +# the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too +# small doxygen will become slower. If the cache is too large, memory is wasted. +# The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid +# range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536 +# symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = NO + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = NO + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= NO + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if section-label ... \endif +# and \cond section-label ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = NO + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. Do not use +# file names with spaces, bibtex cannot handle them. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = "../include" + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = Loki::* \ + ProgressBar* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = Loki::* \ + ProgressBar + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be ignored. +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and +# SVG. The default value is HTML-CSS, which is slower, but has the best +# compatibility. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript +# pieces of code that will be used on startup of the MathJax code. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. +# There are two flavours of web server based search depending on the +# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for +# searching and an index file used by the script. When EXTERNAL_SEARCH is +# enabled the indexing and searching needs to be provided by external tools. +# See the manual for details. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain +# the search results. Doxygen ships with an example indexer (doxyindexer) and +# search engine (doxysearch.cgi) which are based on the open source search +# engine library Xapian. See the manual for configuration details. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will returned the search results when EXTERNAL_SEARCH is enabled. +# Doxygen ships with an example search engine (doxysearch) which is based on +# the open source search engine library Xapian. See the manual for configuration +# details. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id +# of to a relative location where the documentation can be found. +# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ... + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4 will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images +# or other source files which should be copied to the LaTeX output directory. +# Note that the files will be copied as-is; there are no commands or markers +# available. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = YES + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = NO + +#--------------------------------------------------------------------------- +# configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files +# that can be used to generate PDF. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. If left blank docbook will be used as the default path. + +DOCBOOK_OUTPUT = docbook + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = YES + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = MPC_HAVE_ROOT \ + MPC_HAVE_GADGET \ + MPC_HAVE_FFTW3F \ + "protected=private +" + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed +# in the related pages index. If set to NO, only the current project's +# pages will be listed. + +EXTERNAL_PAGES = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# manageable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES From 918f3bf6d82c5ad19ba5dd95eb0a2fd1d45d3d7a Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 24 Jun 2013 17:54:09 +0200 Subject: [PATCH 0311/1298] renamed project, namespace, etc to crpropa --- CMakeLists.txt | 116 ++++++------ README | 14 +- include/{mpc => crpropa}/AssocVector.h | 0 include/{mpc => crpropa}/Candidate.h | 16 +- include/{mpc => crpropa}/Clock.h | 10 +- include/{mpc => crpropa}/Common.h | 12 +- include/{mpc => crpropa}/Cosmology.h | 10 +- include/{mpc => crpropa}/ExplicitRungeKutta.h | 10 +- include/{mpc => crpropa}/Grid.h | 14 +- include/{mpc => crpropa}/GridTools.h | 16 +- include/{mpc => crpropa}/Module.h | 16 +- include/{mpc => crpropa}/ModuleList.h | 18 +- include/{mpc => crpropa}/ParticleID.h | 10 +- include/{mpc => crpropa}/ParticleMass.h | 10 +- include/{mpc => crpropa}/ParticleState.h | 20 +- include/{mpc => crpropa}/PhasePoint.h | 12 +- include/{mpc => crpropa}/PhotonBackground.h | 10 +- include/{mpc => crpropa}/ProgressBar.h | 29 +-- include/{mpc => crpropa}/Random.h | 12 +- include/{mpc => crpropa}/Referenced.h | 10 +- include/{mpc => crpropa}/Source.h | 16 +- include/{mpc => crpropa}/Units.h | 10 +- include/{mpc => crpropa}/Vector3.h | 10 +- include/{mpc => crpropa}/XmlExecute.h | 16 +- .../magneticField/GalacticMagneticField.h | 12 +- .../magneticField/JF12Field.h | 16 +- .../magneticField/MagneticField.h | 14 +- .../magneticField/MagneticFieldGrid.h | 14 +- .../magneticField/QuimbyMagneticField.h | 18 +- .../magneticField/TurbulentMagneticField.h | 12 +- include/{mpc => crpropa}/module/Boundary.h | 12 +- .../{mpc => crpropa}/module/BreakCondition.h | 12 +- .../{mpc => crpropa}/module/DeflectionCK.h | 18 +- .../module/ElectronPairProduction.h | 14 +- .../{mpc => crpropa}/module/NuclearDecay.h | 12 +- include/{mpc => crpropa}/module/Observer.h | 12 +- include/{mpc => crpropa}/module/Output.h | 12 +- .../{mpc => crpropa}/module/OutputCRPropa2.h | 12 +- include/{mpc => crpropa}/module/OutputROOT.h | 16 +- .../module/PhotoDisintegration.h | 14 +- .../module/PhotoPionProduction.h | 14 +- include/{mpc => crpropa}/module/PhotonDINT.h | 14 +- include/{mpc => crpropa}/module/PhotonEleCa.h | 14 +- include/{mpc => crpropa}/module/Redshift.h | 12 +- .../module/SimplePropagation.h | 12 +- .../module/StochasticInteraction.h | 12 +- include/{mpc => crpropa}/module/Tools.h | 14 +- libs/dint/include/dint/advance.h | 4 +- libs/dint/include/dint/background.h | 4 +- libs/dint/include/dint/binfread.h | 4 +- libs/dint/include/dint/check.h | 4 +- libs/dint/include/dint/const.h | 4 +- libs/dint/include/dint/cvector.h | 4 +- libs/dint/include/dint/decay.h | 4 +- libs/dint/include/dint/deriv.h | 4 +- libs/dint/include/dint/error.h | 4 +- libs/dint/include/dint/final.h | 4 +- libs/dint/include/dint/fold.h | 4 +- libs/dint/include/dint/frag.h | 4 +- libs/dint/include/dint/gauleg.h | 4 +- libs/dint/include/dint/inject.h | 4 +- libs/dint/include/dint/io_util.h | 4 +- libs/dint/include/dint/load.h | 4 +- libs/dint/include/dint/math_util.h | 4 +- libs/dint/include/dint/prepare.h | 4 +- libs/dint/include/dint/prop_second.h | 4 +- libs/dint/include/dint/rate.h | 4 +- libs/dint/include/dint/spectrum.h | 4 +- libs/dint/include/dint/sync.h | 4 +- libs/dint/include/dint/utilities.h | 4 +- libs/dint/include/dint/vector.h | 4 +- libs/gtest/include/gtest/gtest-death-test.h | 6 +- libs/gtest/include/gtest/gtest-message.h | 6 +- libs/gtest/include/gtest/gtest-param-test.h | 6 +- libs/gtest/include/gtest/gtest-printers.h | 6 +- libs/gtest/include/gtest/gtest-spi.h | 6 +- libs/gtest/include/gtest/gtest-test-part.h | 6 +- libs/gtest/include/gtest/gtest-typed-test.h | 6 +- libs/gtest/include/gtest/gtest.h | 6 +- libs/gtest/include/gtest/gtest_pred_impl.h | 10 +- libs/gtest/include/gtest/gtest_prod.h | 6 +- .../internal/gtest-death-test-internal.h | 6 +- .../include/gtest/internal/gtest-filepath.h | 6 +- .../include/gtest/internal/gtest-internal.h | 6 +- .../include/gtest/internal/gtest-linked_ptr.h | 6 +- .../internal/gtest-param-util-generated.h | 6 +- .../include/gtest/internal/gtest-param-util.h | 6 +- .../gtest/include/gtest/internal/gtest-port.h | 6 +- .../include/gtest/internal/gtest-string.h | 6 +- .../include/gtest/internal/gtest-tuple.h | 6 +- .../include/gtest/internal/gtest-type-util.h | 6 +- libs/gtest/src/gtest-internal-inl.h | 6 +- libs/kiss/include/kiss/convert.h | 6 +- libs/kiss/include/kiss/io.h | 6 +- libs/kiss/include/kiss/logger.h | 6 +- libs/kiss/include/kiss/path.h | 2 +- libs/kiss/include/kiss/string.h | 6 +- libs/sophia/sophia.h | 4 +- python/crpropa.i | 179 ++++++++++++++++++ python/mpc.i | 179 ------------------ src/Candidate.cpp | 6 +- src/Clock.cpp | 4 +- src/Common.cpp | 6 +- src/Cosmology.cpp | 10 +- src/GridTools.cpp | 12 +- src/Module.cpp | 6 +- src/ModuleList.cpp | 18 +- src/ParticleID.cpp | 4 +- src/ParticleMass.cpp | 10 +- src/ParticleState.cpp | 6 +- src/PhotonBackground.cpp | 8 +- src/Random.cpp | 6 +- src/Source.cpp | 10 +- src/XmlExecute.cpp | 52 ++--- src/magneticField/JF12Field.cpp | 14 +- src/magneticField/MagneticField.cpp | 6 +- src/magneticField/MagneticFieldGrid.cpp | 6 +- src/magneticField/TurbulentMagneticField.cpp | 8 +- src/main.cpp | 4 +- src/module/Boundary.cpp | 6 +- src/module/BreakCondition.cpp | 6 +- src/module/DeflectionCK.cpp | 6 +- src/module/ElectronPairProduction.cpp | 6 +- src/module/NuclearDecay.cpp | 8 +- src/module/Observer.cpp | 6 +- src/module/Output.cpp | 6 +- src/module/OutputCRPropa2.cpp | 6 +- src/module/OutputROOT.cpp | 6 +- src/module/PhotoDisintegration.cpp | 8 +- src/module/PhotoPionProduction.cpp | 8 +- src/module/PhotonDINT.cpp | 8 +- src/module/PhotonEleCa.cpp | 6 +- src/module/Redshift.cpp | 8 +- src/module/SimplePropagation.cpp | 6 +- src/module/StochasticInteraction.cpp | 6 +- src/module/Tools.cpp | 8 +- test/testBreakCondition.cpp | 14 +- test/testCore.cpp | 12 +- test/testInteraction.cpp | 16 +- test/testMagneticField.cpp | 14 +- test/testModuleList.cpp | 12 +- test/testOutput.cpp | 8 +- test/testPropagation.cpp | 10 +- test/testSource.cpp | 6 +- test/testVector3.cpp | 6 +- 145 files changed, 870 insertions(+), 881 deletions(-) rename include/{mpc => crpropa}/AssocVector.h (100%) rename include/{mpc => crpropa}/Candidate.h (93%) rename include/{mpc => crpropa}/Clock.h (59%) rename include/{mpc => crpropa}/Common.h (79%) rename include/{mpc => crpropa}/Cosmology.h (93%) rename include/{mpc => crpropa}/ExplicitRungeKutta.h (93%) rename include/{mpc => crpropa}/Grid.h (96%) rename include/{mpc => crpropa}/GridTools.h (92%) rename include/{mpc => crpropa}/Module.h (68%) rename include/{mpc => crpropa}/ModuleList.h (71%) rename include/{mpc => crpropa}/ParticleID.h (80%) rename include/{mpc => crpropa}/ParticleMass.h (74%) rename include/{mpc => crpropa}/ParticleState.h (86%) rename include/{mpc => crpropa}/PhasePoint.h (84%) rename include/{mpc => crpropa}/PhotonBackground.h (54%) rename include/{mpc => crpropa}/ProgressBar.h (60%) rename include/{mpc => crpropa}/Random.h (96%) rename include/{mpc => crpropa}/Referenced.h (96%) rename include/{mpc => crpropa}/Source.h (97%) rename include/{mpc => crpropa}/Units.h (96%) rename include/{mpc => crpropa}/Vector3.h (98%) rename include/{mpc => crpropa}/XmlExecute.h (79%) rename include/{mpc => crpropa}/magneticField/GalacticMagneticField.h (91%) rename include/{mpc => crpropa}/magneticField/JF12Field.h (94%) rename include/{mpc => crpropa}/magneticField/MagneticField.h (88%) rename include/{mpc => crpropa}/magneticField/MagneticFieldGrid.h (84%) rename include/{mpc => crpropa}/magneticField/QuimbyMagneticField.h (68%) rename include/{mpc => crpropa}/magneticField/TurbulentMagneticField.h (92%) rename include/{mpc => crpropa}/module/Boundary.h (96%) rename include/{mpc => crpropa}/module/BreakCondition.h (92%) rename include/{mpc => crpropa}/module/DeflectionCK.h (83%) rename include/{mpc => crpropa}/module/ElectronPairProduction.h (78%) rename include/{mpc => crpropa}/module/NuclearDecay.h (86%) rename include/{mpc => crpropa}/module/Observer.h (94%) rename include/{mpc => crpropa}/module/Output.h (90%) rename include/{mpc => crpropa}/module/OutputCRPropa2.h (88%) rename include/{mpc => crpropa}/module/OutputROOT.h (86%) rename include/{mpc => crpropa}/module/PhotoDisintegration.h (81%) rename include/{mpc => crpropa}/module/PhotoPionProduction.h (89%) rename include/{mpc => crpropa}/module/PhotonDINT.h (65%) rename include/{mpc => crpropa}/module/PhotonEleCa.h (52%) rename include/{mpc => crpropa}/module/Redshift.h (59%) rename include/{mpc => crpropa}/module/SimplePropagation.h (80%) rename include/{mpc => crpropa}/module/StochasticInteraction.h (64%) rename include/{mpc => crpropa}/module/Tools.h (83%) create mode 100644 python/crpropa.i delete mode 100644 python/mpc.i diff --git a/CMakeLists.txt b/CMakeLists.txt index 66a623f8a..172633424 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,12 @@ cmake_minimum_required(VERSION 2.6) -project(ModularPropagationCode Fortran C CXX) +project(CRPropa Fortran C CXX) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) -set(MPC_EXTRA_SOURCES) -set(MPC_EXTRA_INCLUDES) -set(MPC_EXTRA_LIBRARIES) -set(MPC_SWIG_DEFINES) +set(CRPROPA_EXTRA_SOURCES) +set(CRPROPA_EXTRA_INCLUDES) +set(CRPROPA_EXTRA_LIBRARIES) +set(CRPROPA_SWIG_DEFINES) # ---------------------------------------------------------------------------- # Dependencies @@ -20,28 +20,28 @@ endif(ENABLE_TESTING) # kiss (provided) add_subdirectory(libs/kiss) -list(APPEND MPC_EXTRA_LIBRARIES kiss) -list(APPEND MPC_EXTRA_INCLUDES libs/kiss/include) +list(APPEND CRPROPA_EXTRA_LIBRARIES kiss) +list(APPEND CRPROPA_EXTRA_INCLUDES libs/kiss/include) # pugixml (provided) add_subdirectory(libs/pugixml) -list(APPEND MPC_EXTRA_LIBRARIES pugixml) -list(APPEND MPC_EXTRA_INCLUDES libs/pugixml) +list(APPEND CRPROPA_EXTRA_LIBRARIES pugixml) +list(APPEND CRPROPA_EXTRA_INCLUDES libs/pugixml) # HepID (provided) add_subdirectory(libs/HepPID) -list(APPEND MPC_EXTRA_LIBRARIES HepPID) -list(APPEND MPC_EXTRA_INCLUDES libs/HepPID/include) +list(APPEND CRPROPA_EXTRA_LIBRARIES HepPID) +list(APPEND CRPROPA_EXTRA_INCLUDES libs/HepPID/include) # SOPHIA (provided) add_subdirectory(libs/sophia) -list(APPEND MPC_EXTRA_LIBRARIES sophia gfortran) -list(APPEND MPC_EXTRA_INCLUDES libs/sophia) +list(APPEND CRPROPA_EXTRA_LIBRARIES sophia gfortran) +list(APPEND CRPROPA_EXTRA_INCLUDES libs/sophia) # DINT (provided) add_subdirectory(libs/dint) -list(APPEND MPC_EXTRA_LIBRARIES dint) -list(APPEND MPC_EXTRA_INCLUDES libs/dint/include) +list(APPEND CRPROPA_EXTRA_LIBRARIES dint) +list(APPEND CRPROPA_EXTRA_INCLUDES libs/dint/include) # OpenMP (optional for shared memory multiprocessing) option(ENABLE_OPENMP "OpenMP for multithreading" ON) @@ -59,22 +59,22 @@ option(ENABLE_FFTW3F "FFTW3F to create turbulent fields" ON) if(ENABLE_FFTW3F) find_package(FFTW3F) if(FFTW3F_FOUND) - list(APPEND MPC_EXTRA_INCLUDES ${FFTW3F_INCLUDE_DIR}) - list(APPEND MPC_EXTRA_LIBRARIES ${FFTW3F_LIBRARY}) - add_definitions(-DMPC_HAVE_FFTW3F) - list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_FFTW3F) + list(APPEND CRPROPA_EXTRA_INCLUDES ${FFTW3F_INCLUDE_DIR}) + list(APPEND CRPROPA_EXTRA_LIBRARIES ${FFTW3F_LIBRARY}) + add_definitions(-DCRPROPA_HAVE_FFTW3F) + list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_FFTW3F) endif(FFTW3F_FOUND) endif(ENABLE_FFTW3F) # Quimby (optional for SPH magnetic fields) find_package(Quimby) if(QUIMBY_FOUND) - list(APPEND MPC_EXTRA_INCLUDES ${QUIMBY_INCLUDE_DIR}) - list(APPEND MPC_EXTRA_LIBRARIES ${QUIMBY_LIBRARY}) - add_definitions (-DMPC_HAVE_QUIMBY) - list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_QUIMBY) - list(APPEND MPC_SWIG_DEFINES -I${QUIMBY_INCLUDE_DIR}/../share/quimby) - list(APPEND MPC_SWIG_DEFINES -I${QUIMBY_INCLUDE_DIR}) + list(APPEND CRPROPA_EXTRA_INCLUDES ${QUIMBY_INCLUDE_DIR}) + list(APPEND CRPROPA_EXTRA_LIBRARIES ${QUIMBY_LIBRARY}) + add_definitions (-DCRPROPA_HAVE_QUIMBY) + list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_QUIMBY) + list(APPEND CRPROPA_SWIG_DEFINES -I${QUIMBY_INCLUDE_DIR}/../share/quimby) + list(APPEND CRPROPA_SWIG_DEFINES -I${QUIMBY_INCLUDE_DIR}) endif(QUIMBY_FOUND) # ROOT (optional for ROOT output) @@ -88,8 +88,8 @@ if(ENABLE_ROOT) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ROOT_CFLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") - add_definitions(-DMPC_HAVE_ROOT) - list(APPEND MPC_SWIG_DEFINES -DMPC_HAVE_ROOT) + add_definitions(-DCRPROPA_HAVE_ROOT) + list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_ROOT) endif(ROOT_FOUND) endif(ENABLE_ROOT) @@ -103,8 +103,8 @@ endif(GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) # ---------------------------------------------------------------------------- # Library and Binary # ---------------------------------------------------------------------------- -include_directories(include ${MPC_EXTRA_INCLUDES}) -add_library(mpc SHARED +include_directories(include ${CRPROPA_EXTRA_INCLUDES}) +add_library(crpropa SHARED src/Random.cpp src/Clock.cpp src/ModuleList.cpp @@ -140,21 +140,21 @@ add_library(mpc SHARED src/magneticField/MagneticFieldGrid.cpp src/magneticField/TurbulentMagneticField.cpp src/magneticField/JF12Field.cpp - ${MPC_EXTRA_SOURCES} + ${CRPROPA_EXTRA_SOURCES} ) -target_link_libraries(mpc ${MPC_EXTRA_LIBRARIES}) +target_link_libraries(crpropa ${CRPROPA_EXTRA_LIBRARIES}) -add_executable(mpc-run src/main.cpp) -target_link_libraries(mpc-run mpc) +add_executable(crpropa-xmlrun src/main.cpp) +target_link_libraries(crpropa-xmlrun crpropa) # ---------------------------------------------------------------------------- # Install # ---------------------------------------------------------------------------- -add_definitions(-DMPC_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") -install(TARGETS mpc-run RUNTIME DESTINATION bin) -install(TARGETS mpc DESTINATION lib) +add_definitions(-DCRPROPA_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") +install(TARGETS crpropa-xmlrun RUNTIME DESTINATION bin) +install(TARGETS crpropa DESTINATION lib) install(DIRECTORY include/ DESTINATION include FILES_MATCHING PATTERN "*.h") -install(DIRECTORY data/ DESTINATION share/mpc/) +install(DIRECTORY data/ DESTINATION share/crpropa/) # ---------------------------------------------------------------------------- # Testing @@ -162,39 +162,39 @@ install(DIRECTORY data/ DESTINATION share/mpc/) if(ENABLE_TESTING) enable_testing() add_executable(testCore test/testCore.cpp) - target_link_libraries(testCore mpc gtest gtest_main pthread) + target_link_libraries(testCore crpropa gtest gtest_main pthread) add_test(testCore testCore) add_executable(testVector3 test/testVector3.cpp) - target_link_libraries(testVector3 mpc gtest gtest_main pthread) + target_link_libraries(testVector3 crpropa gtest gtest_main pthread) add_test(testVector3 testVector3) add_executable(testModuleList test/testModuleList.cpp) - target_link_libraries(testModuleList mpc gtest gtest_main pthread) + target_link_libraries(testModuleList crpropa gtest gtest_main pthread) add_test(testModuleList testModuleList) add_executable(testMagneticField test/testMagneticField.cpp) - target_link_libraries(testMagneticField mpc gtest gtest_main pthread) + target_link_libraries(testMagneticField crpropa gtest gtest_main pthread) add_test(testMagneticField testMagneticField) add_executable(testPropagation test/testPropagation.cpp) - target_link_libraries(testPropagation mpc gtest gtest_main pthread) + target_link_libraries(testPropagation crpropa gtest gtest_main pthread) add_test(testPropagation testPropagation) add_executable(testBreakCondition test/testBreakCondition.cpp) - target_link_libraries(testBreakCondition mpc gtest gtest_main pthread) + target_link_libraries(testBreakCondition crpropa gtest gtest_main pthread) add_test(testBreakCondition testBreakCondition) add_executable(testOutput test/testOutput.cpp) - target_link_libraries(testOutput mpc gtest gtest_main pthread) + target_link_libraries(testOutput crpropa gtest gtest_main pthread) add_test(testOutput testOutput) add_executable(testInteraction test/testInteraction.cpp) - target_link_libraries(testInteraction mpc gtest gtest_main pthread) + target_link_libraries(testInteraction crpropa gtest gtest_main pthread) add_test(testInteraction testInteraction) add_executable(testSource test/testSource.cpp) - target_link_libraries(testSource mpc gtest gtest_main pthread) + target_link_libraries(testSource crpropa gtest gtest_main pthread) add_test(testSource testSource) endif(ENABLE_TESTING) @@ -206,15 +206,17 @@ if(ENABLE_PYTHON) include(python/Python.cmake) include_directories(${PYTHON_INCLUDE_PATH}) - file(GLOB_RECURSE MPC_INCLUDES include/*.h) - set_source_files_properties( ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx PROPERTIES GENERATED true ) - add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx - COMMAND swig -c++ -python -I${CMAKE_SOURCE_DIR}/include ${MPC_SWIG_DEFINES} -o ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx -outdir ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/python/mpc.i - DEPENDS ${CMAKE_SOURCE_DIR}/python/mpc.i ${MPC_INCLUDES} ) - add_library(mpc-swig MODULE ${CMAKE_CURRENT_BINARY_DIR}/mpc_wrap.cxx) - set_target_properties(mpc-swig PROPERTIES PREFIX "") - set_target_properties(mpc-swig PROPERTIES OUTPUT_NAME "_mpc") - target_link_libraries(mpc-swig mpc ${PYTHON_LIBRARIES}) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/mpc.py" DESTINATION ${PYTHON_SITE_PACKAGES}) - install(TARGETS mpc-swig LIBRARY DESTINATION ${PYTHON_SITE_PACKAGES}) + file(GLOB_RECURSE CRPROPA_INCLUDES include/*.h) + set_source_files_properties( ${CMAKE_CURRENT_BINARY_DIR}/crpropa_wrap.cxx PROPERTIES GENERATED true ) + add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/crpropa_wrap.cxx + COMMAND swig -c++ -python -I${CMAKE_SOURCE_DIR}/include ${CRPROPA_SWIG_DEFINES} -o ${CMAKE_CURRENT_BINARY_DIR}/crpropa_wrap.cxx -outdir ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/python/crpropa.i + DEPENDS ${CMAKE_SOURCE_DIR}/python/crpropa.i ${CRPROPA_INCLUDES} ) + + add_library(crpropa-swig MODULE ${CMAKE_CURRENT_BINARY_DIR}/crpropa_wrap.cxx) + set_target_properties(crpropa-swig PROPERTIES PREFIX "") + set_target_properties(crpropa-swig PROPERTIES OUTPUT_NAME "_crpropa") + target_link_libraries(crpropa-swig crpropa ${PYTHON_LIBRARIES}) + + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/crpropa.py" DESTINATION ${PYTHON_SITE_PACKAGES}) + install(TARGETS crpropa-swig LIBRARY DESTINATION ${PYTHON_SITE_PACKAGES}) endif(ENABLE_PYTHON) diff --git a/README b/README index f00c0d4c2..9e11c97d3 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ Install from source ------------------------ -MPC is configured using CMAKE - for more information see www.cmake.org -1) Download the data archive from https://forge.physik.rwth-aachen.de/projects/mpc/files extract to mpc/data +CRPropa is configured using CMAKE - for more information see www.cmake.org +1) Download the data archive from https://forge.physik.rwth-aachen.de/projects/mpc/files extract to crpropa/data 2) >> cd build 3) >> cmake .. or >> ccmake .. @@ -15,8 +15,8 @@ Notes for Intel Compiler: Install with Python bindings ---------------------------- -To use mpc via python the CMAKE flag ENABLE_PYTHON needs to be set to True. -Additionally the path to mpc.py needs to be added to PYTHONPATH +To use CRPropa via python the CMAKE flag ENABLE_PYTHON needs to be set to True. +Additionally the path to crpropa.py needs to be added to PYTHONPATH Dependencies @@ -34,12 +34,12 @@ googletest Optional: Python and SWIG - -> to use MPC from Python + -> to use CRPropa from Python tested for > Python 2.7 tested for > SWIG 2.0 FFTW3F -> for turbulent magnetic field grids - MPC needs the FFTW3 library compiled with the single precision option + CRPropa needs the FFTW3 library compiled with the single precision option Gadget -> Magnetic fields for large scale structure data OpenMP @@ -50,7 +50,7 @@ googleperftools XML Steering ------------ -MPC can be steered via XML cards ($mpc-run some_steeringcard.xml) +CRPropa can be steered via XML cards ($cropra-xmlrun some_steeringcard.xml) The steeringcard layout is conform to the one CRPropa2. However, CRPropa 2 does not fully enforce the XML-1.0 standard (http://www.w3.org/XML). To comply with the standard a few modifications to exisisting steering cards might have to be made. diff --git a/include/mpc/AssocVector.h b/include/crpropa/AssocVector.h similarity index 100% rename from include/mpc/AssocVector.h rename to include/crpropa/AssocVector.h diff --git a/include/mpc/Candidate.h b/include/crpropa/Candidate.h similarity index 93% rename from include/mpc/Candidate.h rename to include/crpropa/Candidate.h index c409312a1..12ae14f77 100644 --- a/include/mpc/Candidate.h +++ b/include/crpropa/Candidate.h @@ -1,15 +1,15 @@ -#ifndef MPC_CANDIDATE_H_ -#define MPC_CANDIDATE_H_ +#ifndef CRPROPA_CANDIDATE_H +#define CRPROPA_CANDIDATE_H -#include "mpc/ParticleState.h" -#include "mpc/Referenced.h" -#include "mpc/AssocVector.h" +#include "crpropa/ParticleState.h" +#include "crpropa/Referenced.h" +#include "crpropa/AssocVector.h" #include #include #include -namespace mpc { +namespace crpropa { /** @class InteractionState @@ -99,6 +99,6 @@ class Candidate: public Referenced { void clearSecondaries(); }; -} // namespace mpc +} // namespace crpropa -#endif // MPC_CANDIDATE_H_ +#endif // CRPROPA_CANDIDATE_H diff --git a/include/mpc/Clock.h b/include/crpropa/Clock.h similarity index 59% rename from include/mpc/Clock.h rename to include/crpropa/Clock.h index a91bcd065..caebac8ae 100644 --- a/include/mpc/Clock.h +++ b/include/crpropa/Clock.h @@ -1,7 +1,7 @@ -#ifndef CLOCK_H_ -#define CLOCK_H_ +#ifndef CRPROPA_CLOCK_H +#define CRPROPA_CLOCK_H -namespace mpc { +namespace crpropa { //class ClockImpl; @@ -19,5 +19,5 @@ class Clock { static Clock &getInstance(); }; -} /* namespace scs */ -#endif /* CLOCK_H_ */ +} // namespace crpropa +#endif // CRPROPA_CLOCK_H diff --git a/include/mpc/Common.h b/include/crpropa/Common.h similarity index 79% rename from include/mpc/Common.h rename to include/crpropa/Common.h index a11f48a84..d6ea7c48c 100644 --- a/include/mpc/Common.h +++ b/include/crpropa/Common.h @@ -1,12 +1,12 @@ -#ifndef MPC_COMMON_H_ -#define MPC_COMMON_H_ +#ifndef CRPROPA_COMMON_H +#define CRPROPA_COMMON_H #include #include -namespace mpc { +namespace crpropa { -// Returns the full path to a mpc data file +// Returns the full path to a CRPropa data file std::string getDataPath(std::string filename); // Returns a certain digit from a given integer @@ -24,6 +24,6 @@ double interpolate(double x, const std::vector& X, double interpolateEquidistant(double x, double lo, double hi, const std::vector& Y); -} // namespace mpc +} // namespace crpropa -#endif // MPC_COMMON_H_ +#endif // CRPROPA_COMMON_H diff --git a/include/mpc/Cosmology.h b/include/crpropa/Cosmology.h similarity index 93% rename from include/mpc/Cosmology.h rename to include/crpropa/Cosmology.h index fd4df9ab9..74e0cec9c 100644 --- a/include/mpc/Cosmology.h +++ b/include/crpropa/Cosmology.h @@ -1,7 +1,7 @@ -#ifndef MPC_COSMOLOGY_H_ -#define MPC_COSMOLOGY_H_ +#ifndef CRPROPA_COSMOLOGY_H +#define CRPROPA_COSMOLOGY_H -namespace mpc { +namespace crpropa { /** Set the cosmological parameters for a flat universe. To ensure flatness omegaL is set to 1 - omegaMatter @@ -64,6 +64,6 @@ double comoving2LightTravelDistance(double distance); // Conversion from light travel distance to comoving distance. double lightTravel2ComovingDistance(double distance); -} // namespace mpc +} // namespace crpropa -#endif // MPC_COSMOLOGY_H_ +#endif // CRPROPA_COSMOLOGY_H diff --git a/include/mpc/ExplicitRungeKutta.h b/include/crpropa/ExplicitRungeKutta.h similarity index 93% rename from include/mpc/ExplicitRungeKutta.h rename to include/crpropa/ExplicitRungeKutta.h index a841603a0..5b2aea8cb 100644 --- a/include/mpc/ExplicitRungeKutta.h +++ b/include/crpropa/ExplicitRungeKutta.h @@ -1,9 +1,9 @@ -#ifndef MPC_EXPLICITRUNGEKUTTA_H_ -#define MPC_EXPLICITRUNGEKUTTA_H_ +#ifndef CRPROPA_EXPLICITRUNGEKUTTA_H +#define CRPROPA_EXPLICITRUNGEKUTTA_H #include -namespace mpc { +namespace crpropa { template class ExplicitRungeKutta { @@ -105,6 +105,6 @@ inline void ExplicitRungeKutta::loadCashKarp() { c.assign(cash_karp_c, cash_karp_c + 6); } -} // namespace mpc +} // namespace crpropa -#endif /* MPC_EXPLICITRUNGEKUTTA_H_ */ +#endif /* CRPROPA_EXPLICITRUNGEKUTTA_H */ diff --git a/include/mpc/Grid.h b/include/crpropa/Grid.h similarity index 96% rename from include/mpc/Grid.h rename to include/crpropa/Grid.h index 2f213f1e3..8f03e27ab 100644 --- a/include/mpc/Grid.h +++ b/include/crpropa/Grid.h @@ -1,11 +1,11 @@ -#ifndef MPC_GRID_H_ -#define MPC_GRID_H_ +#ifndef CRPROPA_GRID_H +#define CRPROPA_GRID_H -#include "mpc/Referenced.h" -#include "mpc/Vector3.h" +#include "crpropa/Referenced.h" +#include "crpropa/Vector3.h" #include -namespace mpc { +namespace crpropa { /** Lower and upper neighbor in a periodically continued unit grid */ inline void periodicClamp(double x, int n, int &lo, int &hi) { @@ -213,6 +213,6 @@ class Grid: public Referenced { typedef Grid VectorGrid; typedef Grid ScalarGrid; -} // namespace mpc +} // namespace crpropa -#endif /* MPC_GRID_H_ */ +#endif /* CRPROPA_GRID_H */ diff --git a/include/mpc/GridTools.h b/include/crpropa/GridTools.h similarity index 92% rename from include/mpc/GridTools.h rename to include/crpropa/GridTools.h index 3c7daa575..380af3459 100644 --- a/include/mpc/GridTools.h +++ b/include/crpropa/GridTools.h @@ -1,10 +1,10 @@ -#ifndef MPC_GRIDTOOLS_H_ -#define MPC_GRIDTOOLS_H_ +#ifndef CRPROPA_GRIDTOOLS_H +#define CRPROPA_GRIDTOOLS_H -#include "mpc/Grid.h" +#include "crpropa/Grid.h" #include -namespace mpc { +namespace crpropa { /** Calculate the mean field vector */ Vector3f meanFieldVector(ref_ptr grid); @@ -18,7 +18,7 @@ double rmsFieldStrength(ref_ptr grid); /** Multiply a magnetic field grid by a factor. */ void scaleGrid(ref_ptr grid, double a); -#ifdef MPC_HAVE_FFTW3F +#ifdef CRPROPA_HAVE_FFTW3F /** Create a random initialization of a turbulent field. @param lMin Minimum wavelength of the turbulence @@ -29,7 +29,7 @@ void scaleGrid(ref_ptr grid, double a); */ void initTurbulence(ref_ptr grid, double Brms, double lMin, double lMax, double alpha = -11./3., int seed = 0); -#endif // MPC_HAVE_FFTW3F +#endif // CRPROPA_HAVE_FFTW3F /** Analytically calculate the correlation length of a turbulent field */ double turbulentCorrelationLength(double lMin, double lMax, @@ -77,6 +77,6 @@ void dumpGridToTxt(ref_ptr grid, std::string filename, void dumpGridToTxt(ref_ptr grid, std::string filename, double conversion = 1); -} // namespace mpc +} // namespace crpropa -#endif /* MPC_GRIDTOOLS_H_ */ +#endif // CRPROPA_GRIDTOOLS_H diff --git a/include/mpc/Module.h b/include/crpropa/Module.h similarity index 68% rename from include/mpc/Module.h rename to include/crpropa/Module.h index 133c0ef1e..9a1abad73 100644 --- a/include/mpc/Module.h +++ b/include/crpropa/Module.h @@ -1,13 +1,13 @@ -#ifndef MPC_MODULE_H_ -#define MPC_MODULE_H_ +#ifndef CRPROPA_MODULE_H +#define CRPROPA_MODULE_H -#include "mpc/Candidate.h" -#include "mpc/Referenced.h" -#include "mpc/Common.h" +#include "crpropa/Candidate.h" +#include "crpropa/Referenced.h" +#include "crpropa/Common.h" #include -namespace mpc { +namespace crpropa { class Candidate; @@ -29,6 +29,6 @@ class Module: public Referenced { } }; -} // namespace mpc +} // namespace crpropa -#endif /* MPC_MODULE_H_ */ +#endif /* CRPROPA_MODULE_H */ diff --git a/include/mpc/ModuleList.h b/include/crpropa/ModuleList.h similarity index 71% rename from include/mpc/ModuleList.h rename to include/crpropa/ModuleList.h index 41c203a78..72fd247de 100644 --- a/include/mpc/ModuleList.h +++ b/include/crpropa/ModuleList.h @@ -1,14 +1,14 @@ -#ifndef MPC_MODULE_LIST_H_ -#define MPC_MODULE_LIST_H_ +#ifndef CRPROPA_MODULE_LIST_H +#define CRPROPA_MODULE_LIST_H -#include "mpc/Candidate.h" -#include "mpc/Module.h" -#include "mpc/Source.h" +#include "crpropa/Candidate.h" +#include "crpropa/Module.h" +#include "crpropa/Source.h" #include #include -namespace mpc { +namespace crpropa { /** @class ModuleList @@ -39,8 +39,8 @@ class ModuleList: public Referenced { bool showProgress; }; -} // namespace mpc +} // namespace crpropa -std::ostream &operator<<(std::ostream &out, const mpc::ModuleList &list); +std::ostream &operator<<(std::ostream &out, const crpropa::ModuleList &list); -#endif /* MPC_MODULE_LIST_H_ */ +#endif /* CRPROPA_MODULE_LIST_H */ diff --git a/include/mpc/ParticleID.h b/include/crpropa/ParticleID.h similarity index 80% rename from include/mpc/ParticleID.h rename to include/crpropa/ParticleID.h index f2beab645..378ad01bf 100644 --- a/include/mpc/ParticleID.h +++ b/include/crpropa/ParticleID.h @@ -1,10 +1,10 @@ -#ifndef MPC_PARTICLE_ID_H_ -#define MPC_PARTICLE_ID_H_ +#ifndef CRPROPA_PARTICLE_ID_H +#define CRPROPA_PARTICLE_ID_H #include #include -namespace mpc { +namespace crpropa { std::vector neutrinos(); std::vector leptons(); @@ -24,6 +24,6 @@ int massNumberFromNucleusId(int id); int convertFromCRPropaId(int id); int convertToCRPropaId(int id); -} // namespace mpc +} // namespace crpropa -#endif /* MPC_PARTICLE_ID_H_ */ +#endif /* CRPROPA_PARTICLE_ID_H */ diff --git a/include/mpc/ParticleMass.h b/include/crpropa/ParticleMass.h similarity index 74% rename from include/mpc/ParticleMass.h rename to include/crpropa/ParticleMass.h index 0caa06b0d..b707f80d6 100644 --- a/include/mpc/ParticleMass.h +++ b/include/crpropa/ParticleMass.h @@ -1,7 +1,7 @@ -#ifndef MPC_PARTICLE_MASS_H_ -#define MPC_PARTICLE_MASS_H_ +#ifndef CRPROPA_PARTICLE_MASS_H +#define CRPROPA_PARTICLE_MASS_H -namespace mpc { +namespace crpropa { /** Return the nucleus mass by lookup from a table. * The masses are the atomic masses from the NIST database (http://www.nist.gov/pml/data/comp.cfm) minus electron masses, neglecting electron binding energies. @@ -10,6 +10,6 @@ namespace mpc { */ double nucleusMass(int id); -} // namespace mpc +} // namespace crpropa -#endif // MPC_PARTICLE_MASS_H_ +#endif // CRPROPA_PARTICLE_MASS_H diff --git a/include/mpc/ParticleState.h b/include/crpropa/ParticleState.h similarity index 86% rename from include/mpc/ParticleState.h rename to include/crpropa/ParticleState.h index 90bc381fb..abd546d14 100644 --- a/include/mpc/ParticleState.h +++ b/include/crpropa/ParticleState.h @@ -1,13 +1,13 @@ -#ifndef MPC_PARTICLE_STATE_H_ -#define MPC_PARTICLE_STATE_H_ +#ifndef CRPROPA_PARTICLE_STATE_H +#define CRPROPA_PARTICLE_STATE_H -#include "mpc/Vector3.h" -#include "mpc/Units.h" -#include "mpc/Common.h" -#include "mpc/ParticleID.h" -#include "mpc/ParticleMass.h" +#include "crpropa/Vector3.h" +#include "crpropa/Units.h" +#include "crpropa/Common.h" +#include "crpropa/ParticleID.h" +#include "crpropa/ParticleMass.h" -namespace mpc { +namespace crpropa { /** @class ParticleState @@ -67,6 +67,6 @@ class ParticleState { int getMassNumber() const; }; -} // namespace mpc +} // namespace crpropa -#endif // MPC_PARTICLE_STATE_H_ +#endif // CRPROPA_PARTICLE_STATE_H diff --git a/include/mpc/PhasePoint.h b/include/crpropa/PhasePoint.h similarity index 84% rename from include/mpc/PhasePoint.h rename to include/crpropa/PhasePoint.h index dd1bfbdde..5eef1467e 100644 --- a/include/mpc/PhasePoint.h +++ b/include/crpropa/PhasePoint.h @@ -1,9 +1,9 @@ -#ifndef PHASEPOINT_H_ -#define PHASEPOINT_H_ +#ifndef PHASEPOINT_H +#define PHASEPOINT_H -#include "mpc/Vector3.h" +#include "crpropa/Vector3.h" -namespace mpc { +namespace crpropa { /** @class PhasePoint @@ -49,6 +49,6 @@ class PhasePoint { } }; -} // namespace mpc +} // namespace crpropa -#endif /* PHASEPOINT_H_ */ +#endif /* PHASEPOINT_H */ diff --git a/include/mpc/PhotonBackground.h b/include/crpropa/PhotonBackground.h similarity index 54% rename from include/mpc/PhotonBackground.h rename to include/crpropa/PhotonBackground.h index 1df8be5fc..ce1b3a791 100644 --- a/include/mpc/PhotonBackground.h +++ b/include/crpropa/PhotonBackground.h @@ -1,7 +1,7 @@ -#ifndef MPC_PHOTONBACKGROUND_H_ -#define MPC_PHOTONBACKGROUND_H_ +#ifndef CRPROPA_PHOTONBACKGROUND_H +#define CRPROPA_PHOTONBACKGROUND_H -namespace mpc { +namespace crpropa { // Photon fields enum PhotonField { @@ -11,6 +11,6 @@ enum PhotonField { // Returns overall photon field scaling factor at redshift z double photonFieldScaling(int photonField, double z); -} // namespace mpc +} // namespace crpropa -#endif // MPC_PHOTONBACKGROUND_H_ +#endif // CRPROPA_PHOTONBACKGROUND_H diff --git a/include/mpc/ProgressBar.h b/include/crpropa/ProgressBar.h similarity index 60% rename from include/mpc/ProgressBar.h rename to include/crpropa/ProgressBar.h index 19e9335bb..9f403fc42 100644 --- a/include/mpc/ProgressBar.h +++ b/include/crpropa/ProgressBar.h @@ -1,30 +1,13 @@ -/*************************************************************************** - * ProgressBar.h implements a ProgressBar for calculations not * - * producing additional output * - * Copyright (C) 2010 by Tobias Winchen * - * * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ +#ifndef CRPROPA_PROGRESSBAR_H +#define CRPROPA_PROGRESSBAR_H #include #include #include #include +namespace crpropa { + class ProgressBar { private: unsigned long _steps; @@ -102,3 +85,7 @@ class ProgressBar { } }; + +} // namespace crpropa + +#endif // CRPROPA_PROGRESSBAR_H diff --git a/include/mpc/Random.h b/include/crpropa/Random.h similarity index 96% rename from include/mpc/Random.h rename to include/crpropa/Random.h index 9451285b5..dc60bc259 100644 --- a/include/mpc/Random.h +++ b/include/crpropa/Random.h @@ -57,12 +57,12 @@ // Parts of this file are modified beginning in 29.10.09 for adaption in PXL. // Parts of this file are modified beginning in 10.02.12 for adaption in MPC. -#ifndef RANDOM_H_ -#define RANDOM_H_ +#ifndef RANDOM_H +#define RANDOM_H // Not thread safe (unless auto-initialization is avoided and each thread has // its own Random object) -#include "mpc/Vector3.h" +#include "crpropa/Vector3.h" #include #include #include @@ -75,7 +75,7 @@ #define M_PI 3.14159265358979323846 #endif -namespace mpc { +namespace crpropa { /** @class Random @@ -200,6 +200,6 @@ class Random { static uint32 hash( time_t t, clock_t c ); }; -} //namespace mpc +} //namespace crpropa -#endif // RANDOM_H_ +#endif // RANDOM_H diff --git a/include/mpc/Referenced.h b/include/crpropa/Referenced.h similarity index 96% rename from include/mpc/Referenced.h rename to include/crpropa/Referenced.h index 5a42ae564..84dd95d65 100644 --- a/include/mpc/Referenced.h +++ b/include/crpropa/Referenced.h @@ -1,5 +1,5 @@ -#ifndef MPC_REFERENCED_H -#define MPC_REFERENCED_H +#ifndef CRPROPA_REFERENCED_H +#define CRPROPA_REFERENCED_H #include @@ -8,7 +8,7 @@ #include #endif -namespace mpc { +namespace crpropa { /** @class Referenced @@ -230,6 +230,6 @@ template inline ref_ptr const_pointer_cast( return const_cast(rp.get()); } -} // namespace mpc +} // namespace crpropa -#endif +#endif // CRPROPA_REFERENCED_H diff --git a/include/mpc/Source.h b/include/crpropa/Source.h similarity index 97% rename from include/mpc/Source.h rename to include/crpropa/Source.h index e1f411487..69462b485 100644 --- a/include/mpc/Source.h +++ b/include/crpropa/Source.h @@ -1,13 +1,13 @@ -#ifndef MPC_SOURCE_H -#define MPC_SOURCE_H +#ifndef CRPROPA_SOURCE_H +#define CRPROPA_SOURCE_H -#include "mpc/Referenced.h" -#include "mpc/Candidate.h" -#include "mpc/Grid.h" +#include "crpropa/Referenced.h" +#include "crpropa/Candidate.h" +#include "crpropa/Grid.h" #include -namespace mpc { +namespace crpropa { /** @class SourceProperty @@ -315,6 +315,6 @@ class SourceRedshift1D: public SourceProperty { void prepare(Candidate &candidate) const; }; -}// namespace mpc +}// namespace crpropa -#endif /* MPC_SOURCE_H */ +#endif // CRPROPA_SOURCE_H diff --git a/include/mpc/Units.h b/include/crpropa/Units.h similarity index 96% rename from include/mpc/Units.h rename to include/crpropa/Units.h index 1d0d84b7f..df95d56db 100644 --- a/include/mpc/Units.h +++ b/include/crpropa/Units.h @@ -1,7 +1,7 @@ -#ifndef UNITS_H_ -#define UNITS_H_ +#ifndef UNITS_H +#define UNITS_H -namespace mpc { +namespace crpropa { // SI units static const double meter = 1; @@ -66,6 +66,6 @@ static const double kpc = kiloparsec; static const double Mpc = megaparsec; static const double Gpc = gigaparsec; -} // namespace mpc +} // namespace crpropa -#endif /* UNITS_H_ */ +#endif /* UNITS_H */ diff --git a/include/mpc/Vector3.h b/include/crpropa/Vector3.h similarity index 98% rename from include/mpc/Vector3.h rename to include/crpropa/Vector3.h index 684d2d9b4..efb5d1c14 100644 --- a/include/mpc/Vector3.h +++ b/include/crpropa/Vector3.h @@ -1,12 +1,12 @@ -#ifndef _MPC_VECTOR3_H_ -#define _MPC_VECTOR3_H_ +#ifndef CRPROPA_VECTOR3_H +#define CRPROPA_VECTOR3_H #include #include #include #include -namespace mpc { +namespace crpropa { template class Vector3 { @@ -352,6 +352,6 @@ inline Vector3 operator *(T f, const Vector3 &v) { typedef Vector3 Vector3d; typedef Vector3 Vector3f; -} // namespace mpc +} // namespace crpropa -#endif /* _MPC_VECTOR3_H_ */ +#endif // CRPROPA_VECTOR3_H diff --git a/include/mpc/XmlExecute.h b/include/crpropa/XmlExecute.h similarity index 79% rename from include/mpc/XmlExecute.h rename to include/crpropa/XmlExecute.h index bd87a229a..1832e4bfc 100644 --- a/include/mpc/XmlExecute.h +++ b/include/crpropa/XmlExecute.h @@ -1,9 +1,9 @@ -#ifndef MPC_XMLEXECUTE_H_ -#define MPC_XMLEXECUTE_H_ +#ifndef CRPROPA_XMLEXECUTE_H +#define CRPROPA_XMLEXECUTE_H -#include "mpc/ModuleList.h" -#include "mpc/Source.h" -#include "mpc/magneticField/MagneticField.h" +#include "crpropa/ModuleList.h" +#include "crpropa/Source.h" +#include "crpropa/magneticField/MagneticField.h" #include @@ -11,7 +11,7 @@ namespace pugi { class xml_node; } -namespace mpc { +namespace crpropa { class XmlExecute { void loadUniformMagneticField(pugi::xml_node &node); @@ -44,6 +44,6 @@ class XmlExecute { void run(); }; -} // namespace mpc +} // namespace crpropa -#endif // MPC_XMLEXECUTE_H_ +#endif // CRPROPA_XMLEXECUTE_H diff --git a/include/mpc/magneticField/GalacticMagneticField.h b/include/crpropa/magneticField/GalacticMagneticField.h similarity index 91% rename from include/mpc/magneticField/GalacticMagneticField.h rename to include/crpropa/magneticField/GalacticMagneticField.h index 6a0d7d24c..2cf7ac159 100644 --- a/include/mpc/magneticField/GalacticMagneticField.h +++ b/include/crpropa/magneticField/GalacticMagneticField.h @@ -1,10 +1,10 @@ -#ifndef MPC_GALACTICMAGNETICFIELD_H_ -#define MPC_GALACTICMAGNETICFIELD_H_ +#ifndef CRPROPA_GALACTICMAGNETICFIELD_H +#define CRPROPA_GALACTICMAGNETICFIELD_H -#include "mpc/magneticField/MagneticField.h" +#include "crpropa/magneticField/MagneticField.h" #include -namespace mpc { +namespace crpropa { /** @class TorroidalHaloField @@ -91,6 +91,6 @@ class LogarithmicSpiralField: public MagneticField { } }; -}// namespace mpc +}// namespace crpropa -#endif /* MPC_GALACTICMAGNETICFIELD_H_ */ +#endif // CRPROPA_GALACTICMAGNETICFIELD_H diff --git a/include/mpc/magneticField/JF12Field.h b/include/crpropa/magneticField/JF12Field.h similarity index 94% rename from include/mpc/magneticField/JF12Field.h rename to include/crpropa/magneticField/JF12Field.h index 75af1be50..2fa0d5c1c 100644 --- a/include/mpc/magneticField/JF12Field.h +++ b/include/crpropa/magneticField/JF12Field.h @@ -1,10 +1,10 @@ -#ifndef MPC_JF12FIELD_H -#define MPC_JF12FIELD_H +#ifndef CRPROPA_JF12FIELD_H +#define CRPROPA_JF12FIELD_H -#include "mpc/magneticField/MagneticField.h" -#include "mpc/Grid.h" +#include "crpropa/magneticField/MagneticField.h" +#include "crpropa/Grid.h" -namespace mpc { +namespace crpropa { /** @class JF12Field @@ -72,7 +72,7 @@ class JF12Field: public MagneticField { // Create and set a random realization for the striated field void randomStriated(int seed = 0); -#ifdef MPC_HAVE_FFTW3F +#ifdef CRPROPA_HAVE_FFTW3F // Create a random realization for the turbulent field void randomTurbulent(int seed = 0); #endif @@ -116,6 +116,6 @@ class JF12Field: public MagneticField { Vector3d getField(const Vector3d& pos) const; }; -} // namespace mpc +} // namespace crpropa -#endif // MPC_JF12FIELD_H +#endif // CRPROPA_JF12FIELD_H diff --git a/include/mpc/magneticField/MagneticField.h b/include/crpropa/magneticField/MagneticField.h similarity index 88% rename from include/mpc/magneticField/MagneticField.h rename to include/crpropa/magneticField/MagneticField.h index af30787f4..f1447a44e 100644 --- a/include/mpc/magneticField/MagneticField.h +++ b/include/crpropa/magneticField/MagneticField.h @@ -1,10 +1,10 @@ -#ifndef MPC_MAGNETICFIELD_H_ -#define MPC_MAGNETICFIELD_H_ +#ifndef CRPROPA_MAGNETICFIELD_H +#define CRPROPA_MAGNETICFIELD_H -#include "mpc/Vector3.h" -#include "mpc/Referenced.h" +#include "crpropa/Vector3.h" +#include "crpropa/Referenced.h" -namespace mpc { +namespace crpropa { /** @class MagneticField @@ -65,6 +65,6 @@ class UniformMagneticField: public MagneticField { } }; -} // namespace mpc +} // namespace crpropa -#endif /* MPC_MAGNETICFIELD_H_ */ +#endif // CRPROPA_MAGNETICFIELD_H diff --git a/include/mpc/magneticField/MagneticFieldGrid.h b/include/crpropa/magneticField/MagneticFieldGrid.h similarity index 84% rename from include/mpc/magneticField/MagneticFieldGrid.h rename to include/crpropa/magneticField/MagneticFieldGrid.h index 183fc2e74..2d75f9a07 100644 --- a/include/mpc/magneticField/MagneticFieldGrid.h +++ b/include/crpropa/magneticField/MagneticFieldGrid.h @@ -1,10 +1,10 @@ -#ifndef MPC_MAGNETICFIELDGRID_H_ -#define MPC_MAGNETICFIELDGRID_H_ +#ifndef CRPROPA_MAGNETICFIELDGRID_H +#define CRPROPA_MAGNETICFIELDGRID_H -#include "mpc/magneticField/MagneticField.h" -#include "mpc/Grid.h" +#include "crpropa/magneticField/MagneticField.h" +#include "crpropa/Grid.h" -namespace mpc { +namespace crpropa { /** @class MagneticFieldGrid @@ -44,6 +44,6 @@ class ModulatedMagneticFieldGrid: public MagneticField { Vector3d getField(const Vector3d &position) const; }; -} // namespace mpc +} // namespace crpropa -#endif /* MPC_MAGNETICFIELDGRID_H_ */ +#endif // CRPROPA_MAGNETICFIELDGRID_H diff --git a/include/mpc/magneticField/QuimbyMagneticField.h b/include/crpropa/magneticField/QuimbyMagneticField.h similarity index 68% rename from include/mpc/magneticField/QuimbyMagneticField.h rename to include/crpropa/magneticField/QuimbyMagneticField.h index 07926cc86..0b1a5bf3a 100644 --- a/include/mpc/magneticField/QuimbyMagneticField.h +++ b/include/crpropa/magneticField/QuimbyMagneticField.h @@ -1,14 +1,14 @@ -#ifndef MPC_QUIMBYMAGNETICFIELD_H_ -#define MPC_QUIMBYMAGNETICFIELD_H_ +#ifndef CRPROPA_QUIMBYMAGNETICFIELD_H +#define CRPROPA_QUIMBYMAGNETICFIELD_H -#ifdef MPC_HAVE_QUIMBY +#ifdef CRPROPA_HAVE_QUIMBY -#include "mpc/Units.h" -#include "mpc/magneticField/MagneticField.h" +#include "crpropa/Units.h" +#include "crpropa/magneticField/MagneticField.h" #include "quimby/MagneticField.h" -namespace mpc { +namespace crpropa { /** @class QuimbyMagneticField @@ -30,7 +30,7 @@ class QuimbyMagneticField: public MagneticField { } }; -} // namespace mpc +} // namespace crpropaCRPROPA -#endif // MPC_HAVE_QUIMBY -#endif // MPC_QUIMBYMAGNETICFIELD_H_ +#endif // CRPROPA_HAVE_QUIMBY +#endif // CRPROPA_QUIMBYMAGNETICFIELD_H diff --git a/include/mpc/magneticField/TurbulentMagneticField.h b/include/crpropa/magneticField/TurbulentMagneticField.h similarity index 92% rename from include/mpc/magneticField/TurbulentMagneticField.h rename to include/crpropa/magneticField/TurbulentMagneticField.h index eb8e5b99e..0301d3e0f 100644 --- a/include/mpc/magneticField/TurbulentMagneticField.h +++ b/include/crpropa/magneticField/TurbulentMagneticField.h @@ -1,12 +1,12 @@ -#ifndef TURBULENTMAGNETICFIELD_H_ -#define TURBULENTMAGNETICFIELD_H_ +#ifndef TURBULENTMAGNETICFIELD_H +#define TURBULENTMAGNETICFIELD_H -#include "mpc/magneticField/MagneticField.h" -#include "mpc/Random.h" +#include "crpropa/magneticField/MagneticField.h" +#include "crpropa/Random.h" #include -namespace mpc { +namespace crpropa { /** @class TurbulentMagneticField @@ -75,4 +75,4 @@ class TurbulentMagneticField: public MagneticField { } // mpc -#endif /* TURBULENTMAGNETICFIELD_H_ */ +#endif // TURBULENTMAGNETICFIELD_H diff --git a/include/mpc/module/Boundary.h b/include/crpropa/module/Boundary.h similarity index 96% rename from include/mpc/module/Boundary.h rename to include/crpropa/module/Boundary.h index d342e7519..240119eaa 100644 --- a/include/mpc/module/Boundary.h +++ b/include/crpropa/module/Boundary.h @@ -1,9 +1,9 @@ -#ifndef MPC_BOUNDARY_H_ -#define MPC_BOUNDARY_H_ +#ifndef CRPROPA_BOUNDARY_H +#define CRPROPA_BOUNDARY_H -#include "mpc/Module.h" +#include "crpropa/Module.h" -namespace mpc { +namespace crpropa { /** @class PeriodicBox @@ -138,6 +138,6 @@ class EllipsoidalBoundary: public Module { std::string getDescription() const; }; -} // namespace mpc +} // namespace crpropa -#endif /* MPC_BOUNDARY_H_ */ +#endif // CRPROPA_BOUNDARY_H diff --git a/include/mpc/module/BreakCondition.h b/include/crpropa/module/BreakCondition.h similarity index 92% rename from include/mpc/module/BreakCondition.h rename to include/crpropa/module/BreakCondition.h index 85ff28c8c..a58da42a0 100644 --- a/include/mpc/module/BreakCondition.h +++ b/include/crpropa/module/BreakCondition.h @@ -1,9 +1,9 @@ -#ifndef MPC_BREAKCONDITION_H_ -#define MPC_BREAKCONDITION_H_ +#ifndef CRPROPA_BREAKCONDITION_H +#define CRPROPA_BREAKCONDITION_H -#include "mpc/Module.h" +#include "crpropa/Module.h" -namespace mpc { +namespace crpropa { /** @class MaximumTrajectoryLength @@ -67,6 +67,6 @@ class MinimumRedshift: public Module { void process(Candidate *candidate) const; }; -} // namespace mpc +} // namespace crpropa -#endif /* MPC_BREAKCONDITION_H_ */ +#endif // CRPROPA_BREAKCONDITION_H diff --git a/include/mpc/module/DeflectionCK.h b/include/crpropa/module/DeflectionCK.h similarity index 83% rename from include/mpc/module/DeflectionCK.h rename to include/crpropa/module/DeflectionCK.h index 775b40931..705db99fa 100644 --- a/include/mpc/module/DeflectionCK.h +++ b/include/crpropa/module/DeflectionCK.h @@ -1,12 +1,12 @@ -#ifndef MPC_DEFLECTION_H_ -#define MPC_DEFLECTION_H_ +#ifndef CRPROPA_DEFLECTION_H +#define CRPROPA_DEFLECTION_H -#include "mpc/Module.h" -#include "mpc/magneticField/MagneticField.h" -#include "mpc/ExplicitRungeKutta.h" -#include "mpc/PhasePoint.h" +#include "crpropa/Module.h" +#include "crpropa/magneticField/MagneticField.h" +#include "crpropa/ExplicitRungeKutta.h" +#include "crpropa/PhasePoint.h" -namespace mpc { +namespace crpropa { /** @class DeflectionCK @@ -40,7 +40,7 @@ class DeflectionCK: public Module { std::string getDescription() const; }; -} // namespace mpc +} // namespace crpropa -#endif // MPC_DEFLECTION_H_ +#endif // CRPROPA_DEFLECTION_H diff --git a/include/mpc/module/ElectronPairProduction.h b/include/crpropa/module/ElectronPairProduction.h similarity index 78% rename from include/mpc/module/ElectronPairProduction.h rename to include/crpropa/module/ElectronPairProduction.h index 66ef60da5..88b76ec35 100644 --- a/include/mpc/module/ElectronPairProduction.h +++ b/include/crpropa/module/ElectronPairProduction.h @@ -1,10 +1,10 @@ -#ifndef MPC_ELECTRONPAIRPRODUCTION_H_ -#define MPC_ELECTRONPAIRPRODUCTION_H_ +#ifndef CRPROPA_ELECTRONPAIRPRODUCTION_H +#define CRPROPA_ELECTRONPAIRPRODUCTION_H -#include "mpc/Module.h" -#include "mpc/PhotonBackground.h" +#include "crpropa/Module.h" +#include "crpropa/PhotonBackground.h" -namespace mpc { +namespace crpropa { /** @class ElectronPairProduction @@ -34,6 +34,6 @@ class ElectronPairProduction: public Module { double energyLossLength(int id, double energy); }; -} // namespace mpc +} // namespace crpropa -#endif // MPC_ELECTRONPAIRPRODUCTION_H_ +#endif // CRPROPA_ELECTRONPAIRPRODUCTION_H diff --git a/include/mpc/module/NuclearDecay.h b/include/crpropa/module/NuclearDecay.h similarity index 86% rename from include/mpc/module/NuclearDecay.h rename to include/crpropa/module/NuclearDecay.h index c89b98fde..6527b12be 100644 --- a/include/mpc/module/NuclearDecay.h +++ b/include/crpropa/module/NuclearDecay.h @@ -1,11 +1,11 @@ -#ifndef MPC_DECAY_H_ -#define MPC_DECAY_H_ +#ifndef CRPROPA_DECAY_H +#define CRPROPA_DECAY_H -#include "mpc/module/StochasticInteraction.h" +#include "crpropa/module/StochasticInteraction.h" #include -namespace mpc { +namespace crpropa { /** @class NuclearDecay @@ -35,6 +35,6 @@ class NuclearDecay: public StochasticInteraction { void nucleonEmission(Candidate *candidate, int dA, int dZ) const; }; -} // namespace mpc +} // namespace crpropa -#endif /* MPC_DECAY_H_ */ +#endif // CRPROPA_DECAY_H diff --git a/include/mpc/module/Observer.h b/include/crpropa/module/Observer.h similarity index 94% rename from include/mpc/module/Observer.h rename to include/crpropa/module/Observer.h index 4438f2b03..503769017 100644 --- a/include/mpc/module/Observer.h +++ b/include/crpropa/module/Observer.h @@ -1,9 +1,9 @@ -#ifndef MPC_OBSERVER_H_ -#define MPC_OBSERVER_H_ +#ifndef CRPROPA_OBSERVER_H +#define CRPROPA_OBSERVER_H -#include "mpc/Module.h" +#include "crpropa/Module.h" -namespace mpc { +namespace crpropa { /** @class SmallObserverSphere @@ -96,6 +96,6 @@ class DetectAll: public Module { std::string getDescription() const; }; -} // namespace mpc +} // namespace crpropa -#endif /* MPC_OBSERVER_H_ */ +#endif // CRPROPA_OBSERVER_H diff --git a/include/mpc/module/Output.h b/include/crpropa/module/Output.h similarity index 90% rename from include/mpc/module/Output.h rename to include/crpropa/module/Output.h index 0f8392528..9d07aefa4 100644 --- a/include/mpc/module/Output.h +++ b/include/crpropa/module/Output.h @@ -1,10 +1,10 @@ -#ifndef MPC_OUTPUT_H_ -#define MPC_OUTPUT_H_ +#ifndef CRPROPA_OUTPUT_H +#define CRPROPA_OUTPUT_H -#include "mpc/Module.h" +#include "crpropa/Module.h" #include -namespace mpc { +namespace crpropa { /** @class ShellOutput @@ -65,6 +65,6 @@ class EventOutput1D: public Module { void process(Candidate *candidate) const; }; -} // namespace mpc +} // namespace crpropa -#endif // MPC_OUTPUT_H_ +#endif // CRPROPA_OUTPUT_H diff --git a/include/mpc/module/OutputCRPropa2.h b/include/crpropa/module/OutputCRPropa2.h similarity index 88% rename from include/mpc/module/OutputCRPropa2.h rename to include/crpropa/module/OutputCRPropa2.h index d0044f40c..10a23eb79 100644 --- a/include/mpc/module/OutputCRPropa2.h +++ b/include/crpropa/module/OutputCRPropa2.h @@ -1,10 +1,10 @@ -#ifndef MPC_OUTPUTCRPROPA2_H_ -#define MPC_OUTPUTCRPROPA2_H_ +#ifndef CRPROPA_OUTPUTCRPROPA2_H +#define CRPROPA_OUTPUTCRPROPA2_H -#include "mpc/Module.h" +#include "crpropa/Module.h" #include -namespace mpc { +namespace crpropa { /** @class CRPropa2EventOutput3D @@ -54,6 +54,6 @@ class CRPropa2TrajectoryOutput1D: public Module { void process(Candidate *candidate) const; }; -} // namespace mpc +} // namespace crpropa -#endif // MPC_OUTPUTCRPROPA2_H_ +#endif // CRPROPA_OUTPUTCRPROPA2_H diff --git a/include/mpc/module/OutputROOT.h b/include/crpropa/module/OutputROOT.h similarity index 86% rename from include/mpc/module/OutputROOT.h rename to include/crpropa/module/OutputROOT.h index c524ded5f..63a9e58bc 100644 --- a/include/mpc/module/OutputROOT.h +++ b/include/crpropa/module/OutputROOT.h @@ -1,14 +1,14 @@ -#ifndef MPC_OUTPUTROOT_H_ -#define MPC_OUTPUTROOT_H_ +#ifndef CRPROPA_OUTPUTROOT_H +#define CRPROPA_OUTPUTROOT_H -#include "mpc/Module.h" +#include "crpropa/Module.h" -#ifdef MPC_HAVE_ROOT +#ifdef CRPROPA_HAVE_ROOT #include #include #include -namespace mpc { +namespace crpropa { /** @class ROOTEventOutput1D @@ -66,7 +66,7 @@ class ROOTTrajectoryOutput3D: public Module { void process(Candidate *candidate) const; }; -} // namespace mpc +} // namespace crpropa -#endif // MPC_HAVE_ROOT -#endif // MPC_OUTPUTROOT_H_ +#endif // CRPROPA_HAVE_ROOT +#endif // CRPROPA_OUTPUTROOT_H diff --git a/include/mpc/module/PhotoDisintegration.h b/include/crpropa/module/PhotoDisintegration.h similarity index 81% rename from include/mpc/module/PhotoDisintegration.h rename to include/crpropa/module/PhotoDisintegration.h index 29a2898c9..3e7c42734 100644 --- a/include/mpc/module/PhotoDisintegration.h +++ b/include/crpropa/module/PhotoDisintegration.h @@ -1,12 +1,12 @@ -#ifndef MPC_PHOTODISINTEGRATION_H_ -#define MPC_PHOTODISINTEGRATION_H_ +#ifndef CRPROPA_PHOTODISINTEGRATION_H +#define CRPROPA_PHOTODISINTEGRATION_H -#include "mpc/module/StochasticInteraction.h" -#include "mpc/PhotonBackground.h" +#include "crpropa/module/StochasticInteraction.h" +#include "crpropa/PhotonBackground.h" #include -namespace mpc { +namespace crpropa { /** @class PhotoDisintegration @@ -41,6 +41,6 @@ class PhotoDisintegration: public StochasticInteraction { double energyLossLength(int id, double energy); }; -} // namespace mpc +} // namespace crpropa -#endif // MPC_PHOTODISINTEGRATION_H_ +#endif // CRPROPA_PHOTODISINTEGRATION_H diff --git a/include/mpc/module/PhotoPionProduction.h b/include/crpropa/module/PhotoPionProduction.h similarity index 89% rename from include/mpc/module/PhotoPionProduction.h rename to include/crpropa/module/PhotoPionProduction.h index 28bd5230e..39470c63f 100644 --- a/include/mpc/module/PhotoPionProduction.h +++ b/include/crpropa/module/PhotoPionProduction.h @@ -1,12 +1,12 @@ -#ifndef MPC_PHOTOPIONPRODUCTION_H_ -#define MPC_PHOTOPIONPRODUCTION_H_ +#ifndef CRPROPA_PHOTOPIONPRODUCTION_H +#define CRPROPA_PHOTOPIONPRODUCTION_H -#include "mpc/module/StochasticInteraction.h" -#include "mpc/PhotonBackground.h" +#include "crpropa/module/StochasticInteraction.h" +#include "crpropa/PhotonBackground.h" #include -namespace mpc { +namespace crpropa { /** @class PhotoPionProduction @@ -63,6 +63,6 @@ class SophiaPhotoPionProduction: public PhotoPionProduction { void performInteraction(Candidate *candidate) const; }; -} // namespace mpc +} // namespace crpropa -#endif // MPC_PHOTOPIONPRODUCTION_H_ +#endif // CRPROPA_PHOTOPIONPRODUCTION_H diff --git a/include/mpc/module/PhotonDINT.h b/include/crpropa/module/PhotonDINT.h similarity index 65% rename from include/mpc/module/PhotonDINT.h rename to include/crpropa/module/PhotonDINT.h index 313b8478e..4563efb61 100644 --- a/include/mpc/module/PhotonDINT.h +++ b/include/crpropa/module/PhotonDINT.h @@ -1,12 +1,12 @@ -#ifndef MPC_MODULE_PHOTON_DINT_H_ -#define MPC_MODULE_PHOTON_DINT_H_ +#ifndef CRPROPA_PHOTONDINT_H +#define CRPROPA_PHOTONDINT_H -#include "mpc/Module.h" -#include "mpc/magneticField/MagneticField.h" +#include "crpropa/Module.h" +#include "crpropa/magneticField/MagneticField.h" #include -namespace mpc { +namespace crpropa { class PhotonDINT: public Module { private: @@ -24,6 +24,6 @@ class PhotonDINT: public Module { std::string getDescription() const; }; -} // namespace mpc +} // namespace crpropa -#endif /* MPC_MODULE_PHOTON_DINT_H_ */ +#endif // CRPROPA_PHOTONDINT_H diff --git a/include/mpc/module/PhotonEleCa.h b/include/crpropa/module/PhotonEleCa.h similarity index 52% rename from include/mpc/module/PhotonEleCa.h rename to include/crpropa/module/PhotonEleCa.h index 8dc68315e..c364716e8 100644 --- a/include/mpc/module/PhotonEleCa.h +++ b/include/crpropa/module/PhotonEleCa.h @@ -1,10 +1,10 @@ -#ifndef MPC_PHOTON_ELECA_H_ -#define MPC_PHOTON_ELECA_H_ +#ifndef CRPROPA_PHOTONELECA_H +#define CRPROPA_PHOTONELECA_H -#include "mpc/Module.h" -#include "mpc/magneticField/MagneticField.h" +#include "crpropa/Module.h" +#include "crpropa/magneticField/MagneticField.h" -namespace mpc { +namespace crpropa { class PhotonEleCa: public Module { private: @@ -17,6 +17,6 @@ class PhotonEleCa: public Module { std::string getDescription() const; }; -} // namespace mpc +} // namespace crpropa -#endif /* MPC_PHOTON_ELECA_H_ */ +#endif // CRPROPA_PHOTONELECA_H diff --git a/include/mpc/module/Redshift.h b/include/crpropa/module/Redshift.h similarity index 59% rename from include/mpc/module/Redshift.h rename to include/crpropa/module/Redshift.h index 453b78cfd..647d89ed9 100644 --- a/include/mpc/module/Redshift.h +++ b/include/crpropa/module/Redshift.h @@ -1,9 +1,9 @@ -#ifndef MPC_REDSHIFT_H_ -#define MPC_REDSHIFT_H_ +#ifndef CRPROPA_REDSHIFT_H +#define CRPROPA_REDSHIFT_H -#include "mpc/Module.h" +#include "crpropa/Module.h" -namespace mpc { +namespace crpropa { /** @class Redshift @@ -15,6 +15,6 @@ class Redshift: public Module { void process(Candidate *candidate) const; }; -} // namespace mpc +} // namespace crpropa -#endif // MPC_REDSHIFT_H_ +#endif // CRPROPA_REDSHIFT_H diff --git a/include/mpc/module/SimplePropagation.h b/include/crpropa/module/SimplePropagation.h similarity index 80% rename from include/mpc/module/SimplePropagation.h rename to include/crpropa/module/SimplePropagation.h index 95de6be0c..a81003d4d 100644 --- a/include/mpc/module/SimplePropagation.h +++ b/include/crpropa/module/SimplePropagation.h @@ -1,9 +1,9 @@ -#ifndef SIMPLEPROPAGATION_H_ -#define SIMPLEPROPAGATION_H_ +#ifndef SIMPLEPROPAGATION_H +#define SIMPLEPROPAGATION_H -#include "mpc/Module.h" +#include "crpropa/Module.h" -namespace mpc { +namespace crpropa { /** @class SimplePropagation @@ -27,7 +27,7 @@ class SimplePropagation: public Module { std::string getDescription() const; }; -} // namespace mpc +} // namespace crpropa -#endif // SIMPLEPROPAGATION_H_ +#endif // SIMPLEPROPAGATION_H diff --git a/include/mpc/module/StochasticInteraction.h b/include/crpropa/module/StochasticInteraction.h similarity index 64% rename from include/mpc/module/StochasticInteraction.h rename to include/crpropa/module/StochasticInteraction.h index 6b0f82c4e..0dbb61fb5 100644 --- a/include/mpc/module/StochasticInteraction.h +++ b/include/crpropa/module/StochasticInteraction.h @@ -1,9 +1,9 @@ -#ifndef STOCHASTICINTERACTION_H_ -#define STOCHASTICINTERACTION_H_ +#ifndef CRPROPA_STOCHASTICINTERACTION_H +#define CRPROPA_STOCHASTICINTERACTION_H -#include "mpc/Module.h" +#include "crpropa/Module.h" -namespace mpc { +namespace crpropa { /** @class StochasticInteraction @@ -17,6 +17,6 @@ class StochasticInteraction: public Module { virtual void performInteraction(Candidate *candidate) const = 0; }; -} // namespace mpc +} // namespace crpropa -#endif /* STOCHASTICINTERACTION_H_ */ +#endif // CRPROPA_STOCHASTICINTERACTION_H diff --git a/include/mpc/module/Tools.h b/include/crpropa/module/Tools.h similarity index 83% rename from include/mpc/module/Tools.h rename to include/crpropa/module/Tools.h index 891e7b3dc..525d39ae4 100644 --- a/include/mpc/module/Tools.h +++ b/include/crpropa/module/Tools.h @@ -1,12 +1,12 @@ -#ifndef MPC_MODULE_TOOLS_H_ -#define MPC_MODULE_TOOLS_H_ +#ifndef CRPROPA_MODULETOOLS_H +#define CRPROPA_MODULETOOLS_H -#include "mpc/Module.h" -#include "mpc/AssocVector.h" +#include "crpropa/Module.h" +#include "crpropa/AssocVector.h" #include -namespace mpc { +namespace crpropa { class PerformanceModule: public Module { private: @@ -53,6 +53,6 @@ class ParticleSelector: public Module { std::string getDescription() const; }; -} // namespace mpc +} // namespace crpropa -#endif /* MPC_MODULE_TOOLS_H_ */ +#endif // CRPROPA_MODULETOOLS_H diff --git a/libs/dint/include/dint/advance.h b/libs/dint/include/dint/advance.h index 01f52a53b..8e3919046 100644 --- a/libs/dint/include/dint/advance.h +++ b/libs/dint/include/dint/advance.h @@ -1,5 +1,5 @@ -#ifndef _ADVANCE_H_ -#define _ADVANCE_H_ +#ifndef _ADVANCE_H +#define _ADVANCE_H #include #include "dint/spectrum.h" diff --git a/libs/dint/include/dint/background.h b/libs/dint/include/dint/background.h index 4b17fa3e0..7368581a9 100644 --- a/libs/dint/include/dint/background.h +++ b/libs/dint/include/dint/background.h @@ -1,6 +1,6 @@ -#ifndef _BACKGROUND_H_ -#define _BACKGROUND_H_ +#ifndef _BACKGROUND_H +#define _BACKGROUND_H #include #include diff --git a/libs/dint/include/dint/binfread.h b/libs/dint/include/dint/binfread.h index f713e78a0..0e3c2c60e 100644 --- a/libs/dint/include/dint/binfread.h +++ b/libs/dint/include/dint/binfread.h @@ -1,6 +1,6 @@ -#ifndef _BINFREAD_H_ -#define _BINFREAD_H_ +#ifndef _BINFREAD_H +#define _BINFREAD_H // T. Beau 2005 diff --git a/libs/dint/include/dint/check.h b/libs/dint/include/dint/check.h index e70cb038c..161e3d2eb 100644 --- a/libs/dint/include/dint/check.h +++ b/libs/dint/include/dint/check.h @@ -1,5 +1,5 @@ -#ifndef _CHECK_H_ -#define _CHECK_H_ +#ifndef _CHECK_H +#define _CHECK_H #include "dint/cvector.h" diff --git a/libs/dint/include/dint/const.h b/libs/dint/include/dint/const.h index ddbf8cb5a..0f0f3caee 100644 --- a/libs/dint/include/dint/const.h +++ b/libs/dint/include/dint/const.h @@ -1,6 +1,6 @@ -#ifndef _CONST_H_ -#define _CONST_H_ +#ifndef _CONST_H +#define _CONST_H #define ELECTRON_MASS 5.110e5 diff --git a/libs/dint/include/dint/cvector.h b/libs/dint/include/dint/cvector.h index bec1bcede..d5e4af931 100644 --- a/libs/dint/include/dint/cvector.h +++ b/libs/dint/include/dint/cvector.h @@ -1,6 +1,6 @@ -#ifndef _CVECTOR_H_ -#define _CVECTOR_H_ +#ifndef _CVECTOR_H +#define _CVECTOR_H #include "dint/vector.h" #include diff --git a/libs/dint/include/dint/decay.h b/libs/dint/include/dint/decay.h index 0a39f63c0..cf3f95dfd 100644 --- a/libs/dint/include/dint/decay.h +++ b/libs/dint/include/dint/decay.h @@ -1,5 +1,5 @@ -#ifndef _DECAY_H_ -#define _DECAY_H_ +#ifndef _DECAY_H +#define _DECAY_H double PionToPhoton(const int iPhoton, const int iPion); double PionToLepton(const double leptonEnergy, const double pionEnergy); diff --git a/libs/dint/include/dint/deriv.h b/libs/dint/include/dint/deriv.h index 5559f4d55..f56bb2e55 100644 --- a/libs/dint/include/dint/deriv.h +++ b/libs/dint/include/dint/deriv.h @@ -1,5 +1,5 @@ -#ifndef _DERIV_H_ -#define _DERIV_H_ +#ifndef _DERIV_H +#define _DERIV_H #include "dint/rate.h" #include "dint/spectrum.h" diff --git a/libs/dint/include/dint/error.h b/libs/dint/include/dint/error.h index efca50cf0..de86a3c8b 100644 --- a/libs/dint/include/dint/error.h +++ b/libs/dint/include/dint/error.h @@ -1,5 +1,5 @@ -#ifndef _ERROR_H_ -#define _ERROR_H_ +#ifndef _ERROR_H +#define _ERROR_H typedef enum {NO_ERROR = 0, ARRAY_ERROR = 1, IO_ERROR = 2, PROGRAM_ERROR = 3} ErrorCode; diff --git a/libs/dint/include/dint/final.h b/libs/dint/include/dint/final.h index 03f2228d8..4f05c2832 100644 --- a/libs/dint/include/dint/final.h +++ b/libs/dint/include/dint/final.h @@ -1,5 +1,5 @@ -#ifndef _FINAL_H_ -#define _FINAL_H_ +#ifndef _FINAL_H +#define _FINAL_H #include "dint/spectrum.h" #include "dint/cvector.h" diff --git a/libs/dint/include/dint/fold.h b/libs/dint/include/dint/fold.h index d34fee4c1..64f7b367f 100644 --- a/libs/dint/include/dint/fold.h +++ b/libs/dint/include/dint/fold.h @@ -1,5 +1,5 @@ -#ifndef _FOLD_H_ -#define _FOLD_H_ +#ifndef _FOLD_H +#define _FOLD_H #include "dint/rate.h" #include "dint/cvector.h" diff --git a/libs/dint/include/dint/frag.h b/libs/dint/include/dint/frag.h index d04636c7d..8d820031c 100644 --- a/libs/dint/include/dint/frag.h +++ b/libs/dint/include/dint/frag.h @@ -1,5 +1,5 @@ -#ifndef _FRAG_H_ -#define _FRAG_H_ +#ifndef _FRAG_H +#define _FRAG_H double OldFrag(const double x); double HillFrag(const double x); diff --git a/libs/dint/include/dint/gauleg.h b/libs/dint/include/dint/gauleg.h index c23f09d8a..a0c84e638 100644 --- a/libs/dint/include/dint/gauleg.h +++ b/libs/dint/include/dint/gauleg.h @@ -1,5 +1,5 @@ -#ifndef _GAULEG_H_ -#define _GAULEG_H_ +#ifndef _GAULEG_H +#define _GAULEG_H void Gauleg(const double x1, const double x2, double x[], double w[], const int n); diff --git a/libs/dint/include/dint/inject.h b/libs/dint/include/dint/inject.h index 4945a8f7f..92ed2ce45 100644 --- a/libs/dint/include/dint/inject.h +++ b/libs/dint/include/dint/inject.h @@ -1,5 +1,5 @@ -#ifndef _INJECT_H_ -#define _INJECT_H_ +#ifndef _INJECT_H +#define _INJECT_H #include "dint/cvector.h" #include "dint/spectrum.h" diff --git a/libs/dint/include/dint/io_util.h b/libs/dint/include/dint/io_util.h index b89a43069..77bcc2c03 100644 --- a/libs/dint/include/dint/io_util.h +++ b/libs/dint/include/dint/io_util.h @@ -1,5 +1,5 @@ -#ifndef _IO_UTIL_H_ -#define _IO_UTIL_H_ +#ifndef _IO_UTIL_H +#define _IO_UTIL_H #include diff --git a/libs/dint/include/dint/load.h b/libs/dint/include/dint/load.h index 29aa59c60..7a1531ed8 100644 --- a/libs/dint/include/dint/load.h +++ b/libs/dint/include/dint/load.h @@ -1,5 +1,5 @@ -#ifndef _LOAD_H_ -#define _LOAD_H_ +#ifndef _LOAD_H +#define _LOAD_H #include "dint/rate.h" #include "dint/utilities.h" diff --git a/libs/dint/include/dint/math_util.h b/libs/dint/include/dint/math_util.h index e83ef41c9..4c0e557b5 100644 --- a/libs/dint/include/dint/math_util.h +++ b/libs/dint/include/dint/math_util.h @@ -1,5 +1,5 @@ -#ifndef _MATH_UTIL_H_ -#define _MATH_UTIL_H_ +#ifndef _MATH_UTIL_H +#define _MATH_UTIL_H double DMax(const double double1, const double double2); double DMin(const double double1, const double double2); diff --git a/libs/dint/include/dint/prepare.h b/libs/dint/include/dint/prepare.h index be18a65f4..144ca7f05 100644 --- a/libs/dint/include/dint/prepare.h +++ b/libs/dint/include/dint/prepare.h @@ -1,5 +1,5 @@ -#ifndef _PREPARE_H_ -#define _PREPARE_H_ +#ifndef _PREPARE_H +#define _PREPARE_H #include #include "dint/spectrum.h" diff --git a/libs/dint/include/dint/prop_second.h b/libs/dint/include/dint/prop_second.h index 08f61b338..8b01292c4 100644 --- a/libs/dint/include/dint/prop_second.h +++ b/libs/dint/include/dint/prop_second.h @@ -1,6 +1,6 @@ -#ifndef _PROPSECOND_H_ -#define _PROPSECOND_H_ +#ifndef _PROPSECOND_H +#define _PROPSECOND_H #include "dint/cvector.h" diff --git a/libs/dint/include/dint/rate.h b/libs/dint/include/dint/rate.h index abfa6c2b3..a9f43b92e 100644 --- a/libs/dint/include/dint/rate.h +++ b/libs/dint/include/dint/rate.h @@ -1,5 +1,5 @@ -#ifndef _RATE_H_ -#define _RATE_H_ +#ifndef _RATE_H +#define _RATE_H #include "dint/vector.h" #include "dint/binfread.h" diff --git a/libs/dint/include/dint/spectrum.h b/libs/dint/include/dint/spectrum.h index b55805082..dee58c937 100644 --- a/libs/dint/include/dint/spectrum.h +++ b/libs/dint/include/dint/spectrum.h @@ -1,5 +1,5 @@ -#ifndef _SPECTRUM_H_ -#define _SPECTRUM_H_ +#ifndef _SPECTRUM_H +#define _SPECTRUM_H #include "dint/vector.h" #include "dint/cvector.h" diff --git a/libs/dint/include/dint/sync.h b/libs/dint/include/dint/sync.h index 91d6c4abd..3d5c2b9ad 100644 --- a/libs/dint/include/dint/sync.h +++ b/libs/dint/include/dint/sync.h @@ -1,6 +1,6 @@ -#ifndef _SYNC_H_ -#define _SYNC_H_ +#ifndef _SYNC_H +#define _SYNC_H #include "dint/rate.h" #include "dint/cvector.h" diff --git a/libs/dint/include/dint/utilities.h b/libs/dint/include/dint/utilities.h index 85085ea28..b57ae1f03 100644 --- a/libs/dint/include/dint/utilities.h +++ b/libs/dint/include/dint/utilities.h @@ -1,5 +1,5 @@ -#ifndef _UTILITIES_H_ -#define _UTILITIES_H_ +#ifndef _UTILITIES_H +#define _UTILITIES_H #include "dint/error.h" #include "dint/io_util.h" diff --git a/libs/dint/include/dint/vector.h b/libs/dint/include/dint/vector.h index 1a8dc5f26..111f046c6 100644 --- a/libs/dint/include/dint/vector.h +++ b/libs/dint/include/dint/vector.h @@ -1,5 +1,5 @@ -#ifndef _VECTOR_H_ -#define _VECTOR_H_ +#ifndef _VECTOR_H +#define _VECTOR_H /* Vectors, matrices, and tensors defined here are very simple, dynamic objects. They do not provide any bound checking nor has extra data diff --git a/libs/gtest/include/gtest/gtest-death-test.h b/libs/gtest/include/gtest/gtest-death-test.h index a27883f0a..b2bcbd5cc 100644 --- a/libs/gtest/include/gtest/gtest-death-test.h +++ b/libs/gtest/include/gtest/gtest-death-test.h @@ -35,8 +35,8 @@ // #included by gtest.h so a user doesn't need to include this // directly. -#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H +#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H #include "gtest/internal/gtest-death-test-internal.h" @@ -280,4 +280,4 @@ class GTEST_API_ KilledBySignal { } // namespace testing -#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H diff --git a/libs/gtest/include/gtest/gtest-message.h b/libs/gtest/include/gtest/gtest-message.h index 9b7142f32..3de08cada 100644 --- a/libs/gtest/include/gtest/gtest-message.h +++ b/libs/gtest/include/gtest/gtest-message.h @@ -43,8 +43,8 @@ // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user // program! -#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ -#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H +#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H #include @@ -227,4 +227,4 @@ inline std::ostream& operator <<(std::ostream& os, const Message& sb) { } // namespace testing -#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H diff --git a/libs/gtest/include/gtest/gtest-param-test.h b/libs/gtest/include/gtest/gtest-param-test.h index 6407cfd68..77492cb45 100644 --- a/libs/gtest/include/gtest/gtest-param-test.h +++ b/libs/gtest/include/gtest/gtest-param-test.h @@ -38,8 +38,8 @@ // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // -#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H +#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H // Value-parameterized tests allow you to test your code with different @@ -1418,4 +1418,4 @@ internal::CartesianProductHolder10 // NOLINT #include @@ -793,4 +793,4 @@ ::std::string PrintToString(const T& value) { } // namespace testing -#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ +#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H diff --git a/libs/gtest/include/gtest/gtest-spi.h b/libs/gtest/include/gtest/gtest-spi.h index b226e5504..292966104 100644 --- a/libs/gtest/include/gtest/gtest-spi.h +++ b/libs/gtest/include/gtest/gtest-spi.h @@ -32,8 +32,8 @@ // Utilities for testing Google Test itself and code that uses Google Test // (e.g. frameworks built on top of Google Test). -#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ -#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ +#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H +#define GTEST_INCLUDE_GTEST_GTEST_SPI_H #include "gtest/gtest.h" @@ -229,4 +229,4 @@ class GTEST_API_ SingleFailureChecker { }\ } while (::testing::internal::AlwaysFalse()) -#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ +#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H diff --git a/libs/gtest/include/gtest/gtest-test-part.h b/libs/gtest/include/gtest/gtest-test-part.h index 8aeea1498..0db55ece7 100644 --- a/libs/gtest/include/gtest/gtest-test-part.h +++ b/libs/gtest/include/gtest/gtest-test-part.h @@ -30,8 +30,8 @@ // Author: mheule@google.com (Markus Heule) // -#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ -#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ +#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H +#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H #include #include @@ -173,4 +173,4 @@ class GTEST_API_ HasNewFatalFailureHelper } // namespace testing -#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ +#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H diff --git a/libs/gtest/include/gtest/gtest-typed-test.h b/libs/gtest/include/gtest/gtest-typed-test.h index fe1e83b27..4ce0437e1 100644 --- a/libs/gtest/include/gtest/gtest-typed-test.h +++ b/libs/gtest/include/gtest/gtest-typed-test.h @@ -29,8 +29,8 @@ // // Author: wan@google.com (Zhanyong Wan) -#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ +#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H +#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H // This header implements typed tests and type-parameterized tests. @@ -256,4 +256,4 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); #endif // GTEST_HAS_TYPED_TEST_P -#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ +#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H diff --git a/libs/gtest/include/gtest/gtest.h b/libs/gtest/include/gtest/gtest.h index cd01c7ba7..c9038c7eb 100644 --- a/libs/gtest/include/gtest/gtest.h +++ b/libs/gtest/include/gtest/gtest.h @@ -48,8 +48,8 @@ // registration from Barthelemy Dagenais' (barthelemy@prologique.com) // easyUnit framework. -#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_H_ +#ifndef GTEST_INCLUDE_GTEST_GTEST_H +#define GTEST_INCLUDE_GTEST_GTEST_H #include #include @@ -2152,4 +2152,4 @@ bool StaticAssertTypeEq() { } // namespace testing -#endif // GTEST_INCLUDE_GTEST_GTEST_H_ +#endif // GTEST_INCLUDE_GTEST_GTEST_H diff --git a/libs/gtest/include/gtest/gtest_pred_impl.h b/libs/gtest/include/gtest/gtest_pred_impl.h index 3805f85bd..2a7ae0b51 100644 --- a/libs/gtest/include/gtest/gtest_pred_impl.h +++ b/libs/gtest/include/gtest/gtest_pred_impl.h @@ -32,13 +32,13 @@ // // Implements a family of generic predicate assertion macros. -#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H +#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H // Makes sure this header is not included before gtest.h. -#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ +#ifndef GTEST_INCLUDE_GTEST_GTEST_H # error Do not include gtest_pred_impl.h directly. Include gtest.h instead. -#endif // GTEST_INCLUDE_GTEST_GTEST_H_ +#endif // GTEST_INCLUDE_GTEST_GTEST_H // This header implements a family of generic predicate assertion // macros: @@ -355,4 +355,4 @@ AssertionResult AssertPred5Helper(const char* pred_text, -#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H diff --git a/libs/gtest/include/gtest/gtest_prod.h b/libs/gtest/include/gtest/gtest_prod.h index da80ddc6c..50b85d6f0 100644 --- a/libs/gtest/include/gtest/gtest_prod.h +++ b/libs/gtest/include/gtest/gtest_prod.h @@ -31,8 +31,8 @@ // // Google C++ Testing Framework definitions useful in production code. -#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ +#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H +#define GTEST_INCLUDE_GTEST_GTEST_PROD_H // When you need to test the private or protected members of a class, // use the FRIEND_TEST macro to declare your tests as friends of the @@ -55,4 +55,4 @@ #define FRIEND_TEST(test_case_name, test_name)\ friend class test_case_name##_##test_name##_Test -#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ +#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H diff --git a/libs/gtest/include/gtest/internal/gtest-death-test-internal.h b/libs/gtest/include/gtest/internal/gtest-death-test-internal.h index 1d9f83b65..8db46a296 100644 --- a/libs/gtest/include/gtest/internal/gtest-death-test-internal.h +++ b/libs/gtest/include/gtest/internal/gtest-death-test-internal.h @@ -34,8 +34,8 @@ // This header file defines internal utilities needed for implementing // death tests. They are subject to change without notice. -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H #include "gtest/internal/gtest-internal.h" @@ -305,4 +305,4 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); } // namespace internal } // namespace testing -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H diff --git a/libs/gtest/include/gtest/internal/gtest-filepath.h b/libs/gtest/include/gtest/internal/gtest-filepath.h index b36b3cf21..099d2067d 100644 --- a/libs/gtest/include/gtest/internal/gtest-filepath.h +++ b/libs/gtest/include/gtest/internal/gtest-filepath.h @@ -37,8 +37,8 @@ // This file is #included in . // Do not include this header file separately! -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H #include "gtest/internal/gtest-string.h" @@ -207,4 +207,4 @@ class GTEST_API_ FilePath { } // namespace internal } // namespace testing -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H diff --git a/libs/gtest/include/gtest/internal/gtest-internal.h b/libs/gtest/include/gtest/internal/gtest-internal.h index 7aa1197f1..04f9f9ec6 100644 --- a/libs/gtest/include/gtest/internal/gtest-internal.h +++ b/libs/gtest/include/gtest/internal/gtest-internal.h @@ -34,8 +34,8 @@ // This header file declares functions and macros used internally by // Google Test. They are subject to change without notice. -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H #include "gtest/internal/gtest-port.h" @@ -1223,4 +1223,4 @@ ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H diff --git a/libs/gtest/include/gtest/internal/gtest-linked_ptr.h b/libs/gtest/include/gtest/internal/gtest-linked_ptr.h index 57147b4e8..7beb7b6f6 100644 --- a/libs/gtest/include/gtest/internal/gtest-linked_ptr.h +++ b/libs/gtest/include/gtest/internal/gtest-linked_ptr.h @@ -65,8 +65,8 @@ // TODO(wan@google.com): rename this to safe_linked_ptr to avoid // confusion with normal linked_ptr. -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H #include #include @@ -230,4 +230,4 @@ linked_ptr make_linked_ptr(T* ptr) { } // namespace internal } // namespace testing -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H diff --git a/libs/gtest/include/gtest/internal/gtest-param-util-generated.h b/libs/gtest/include/gtest/internal/gtest-param-util-generated.h index 258267500..642b71de3 100644 --- a/libs/gtest/include/gtest/internal/gtest-param-util-generated.h +++ b/libs/gtest/include/gtest/internal/gtest-param-util-generated.h @@ -43,8 +43,8 @@ // by the maximum arity of the implementation of tr1::tuple which is // currently set at 10. -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved @@ -4819,4 +4819,4 @@ CartesianProductHolder10(const Generator1& g1, const Generator2& g2, #endif // GTEST_HAS_PARAM_TEST -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H diff --git a/libs/gtest/include/gtest/internal/gtest-param-util.h b/libs/gtest/include/gtest/internal/gtest-param-util.h index 0ef9718cf..c49b807dc 100644 --- a/libs/gtest/include/gtest/internal/gtest-param-util.h +++ b/libs/gtest/include/gtest/internal/gtest-param-util.h @@ -31,8 +31,8 @@ // Type and function utilities for implementing parameterized tests. -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H #include #include @@ -616,4 +616,4 @@ class ParameterizedTestCaseRegistry { #endif // GTEST_HAS_PARAM_TEST -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H diff --git a/libs/gtest/include/gtest/internal/gtest-port.h b/libs/gtest/include/gtest/internal/gtest-port.h index 157b47f86..993021a87 100644 --- a/libs/gtest/include/gtest/internal/gtest-port.h +++ b/libs/gtest/include/gtest/internal/gtest-port.h @@ -33,8 +33,8 @@ // platforms. They are subject to change without notice. DO NOT USE // THEM IN USER CODE. -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H // The user can define the following macros in the build script to // control Google Test's behavior. If the user doesn't define a macro @@ -1772,4 +1772,4 @@ const char* StringFromGTestEnv(const char* flag, const char* default_val); } // namespace internal } // namespace testing -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H diff --git a/libs/gtest/include/gtest/internal/gtest-string.h b/libs/gtest/include/gtest/internal/gtest-string.h index dc3a07be8..034ecd4dc 100644 --- a/libs/gtest/include/gtest/internal/gtest-string.h +++ b/libs/gtest/include/gtest/internal/gtest-string.h @@ -38,8 +38,8 @@ // This header file is #included by . // It should not be #included by other files. -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H #ifdef __BORLANDC__ // string.h is not guaranteed to provide strcpy on C++ Builder. @@ -347,4 +347,4 @@ String StreamableToString(const T& streamable); } // namespace internal } // namespace testing -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H diff --git a/libs/gtest/include/gtest/internal/gtest-tuple.h b/libs/gtest/include/gtest/internal/gtest-tuple.h index d1af50e18..bf14becba 100644 --- a/libs/gtest/include/gtest/internal/gtest-tuple.h +++ b/libs/gtest/include/gtest/internal/gtest-tuple.h @@ -33,8 +33,8 @@ // Implements a subset of TR1 tuple needed by Google Test and Google Mock. -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H #include // For ::std::pair. @@ -965,4 +965,4 @@ inline bool operator!=(const GTEST_10_TUPLE_(T)& t, #undef GTEST_ADD_REF_ #undef GTEST_TUPLE_ELEMENT_ -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H diff --git a/libs/gtest/include/gtest/internal/gtest-type-util.h b/libs/gtest/include/gtest/internal/gtest-type-util.h index b7b01b094..ec21dd0ce 100644 --- a/libs/gtest/include/gtest/internal/gtest-type-util.h +++ b/libs/gtest/include/gtest/internal/gtest-type-util.h @@ -41,8 +41,8 @@ // Please contact googletestframework@googlegroups.com if you need // more. -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H #include "gtest/internal/gtest-port.h" #include "gtest/internal/gtest-string.h" @@ -3327,4 +3327,4 @@ struct TypeList #include @@ -71,4 +71,4 @@ inline T convertTo(std::string const& s, bool failIfLeftoverChars = true) { } // namespace kiss -#endif /* KISSCONVERT_H_ */ +#endif /* KISSCONVERT_H */ diff --git a/libs/kiss/include/kiss/io.h b/libs/kiss/include/kiss/io.h index 0b13ac2ff..78b05d345 100644 --- a/libs/kiss/include/kiss/io.h +++ b/libs/kiss/include/kiss/io.h @@ -1,5 +1,5 @@ -#ifndef KISS_IO_H_ -#define KISS_IO_H_ +#ifndef KISS_IO_H +#define KISS_IO_H #include #include @@ -170,4 +170,4 @@ inline bool read(Input &in, std::vector &m) { } // namespace kiss -#endif /* KISS_IO_H_ */ +#endif /* KISS_IO_H */ diff --git a/libs/kiss/include/kiss/logger.h b/libs/kiss/include/kiss/logger.h index 9655e3f91..702b15b9f 100644 --- a/libs/kiss/include/kiss/logger.h +++ b/libs/kiss/include/kiss/logger.h @@ -1,5 +1,5 @@ -#ifndef KISS_LOG_H_ -#define KISS_LOG_H_ +#ifndef KISS_LOG_H +#define KISS_LOG_H #include @@ -46,4 +46,4 @@ class Logger { #define KISS_LOG_INFO if (kiss::Logger::getLogLevel() < kiss::LOG_LEVEL_INFO) {} else kiss::Logger(kiss::LOG_LEVEL_INFO) #define KISS_LOG_DEBUG if (kiss::Logger::getLogLevel() < kiss::LOG_LEVEL_DEBUG) {} else kiss::Logger(kiss::LOG_LEVEL_DEBUG) -#endif /* KISSLOG_H_ */ +#endif /* KISSLOG_H */ diff --git a/libs/kiss/include/kiss/path.h b/libs/kiss/include/kiss/path.h index f28682e48..ca025e568 100644 --- a/libs/kiss/include/kiss/path.h +++ b/libs/kiss/include/kiss/path.h @@ -37,4 +37,4 @@ void append_file(const std::string &target, const std::string &source, bool bina std::string executable_path(); -#endif /* FILEUTILS_H_ */ +#endif /* FILEUTILS_H */ diff --git a/libs/kiss/include/kiss/string.h b/libs/kiss/include/kiss/string.h index cf960e5cd..695b9c6b9 100644 --- a/libs/kiss/include/kiss/string.h +++ b/libs/kiss/include/kiss/string.h @@ -1,5 +1,5 @@ -#ifndef KISS_STRING_H_ -#define KISS_STRING_H_ +#ifndef KISS_STRING_H +#define KISS_STRING_H #include #include @@ -19,4 +19,4 @@ bool starts_with(const std::string &s, const std::string &w); } // namespace kiss -#endif /* KISS_STRING_H_ */ +#endif /* KISS_STRING_H */ diff --git a/libs/sophia/sophia.h b/libs/sophia/sophia.h index 548c11dba..10f978a95 100644 --- a/libs/sophia/sophia.h +++ b/libs/sophia/sophia.h @@ -1,5 +1,5 @@ -#ifndef _SOPHIA_H_ -#define _SOPHIA_H_ +#ifndef _SOPHIA_H +#define _SOPHIA_H extern "C" { void sophiaevent_(int&, double&, double[][2000], int[], int&, double&, int&, diff --git a/python/crpropa.i b/python/crpropa.i new file mode 100644 index 000000000..b3d9ab46e --- /dev/null +++ b/python/crpropa.i @@ -0,0 +1,179 @@ +%module(directors="1") crpropa +%feature("autodoc", "1"); // automatic docstrings + +%{ +// workaround for SWIG < 2.0.5 with GCC >= 4.7 +#include +using std::ptrdiff_t; +%} + +%include stl.i +%include std_set.i +%include std_multiset.i +%include std_map.i +%include std_pair.i +%include std_multimap.i +%include std_vector.i +%include std_string.i +%include std_list.i +%include stdint.i +%include std_container.i +%include "exception.i" + +#ifdef CRPROPA_HAVE_QUIMBY +%import (module="quimby") quimby.i +#endif + +%{ +#include "crpropa/module/NuclearDecay.h" +#include "crpropa/module/ElectronPairProduction.h" +#include "crpropa/module/StochasticInteraction.h" +#include "crpropa/module/PhotoDisintegration.h" +#include "crpropa/module/PhotoPionProduction.h" +#include "crpropa/module/Redshift.h" +#include "crpropa/module/BreakCondition.h" +#include "crpropa/module/Boundary.h" +#include "crpropa/module/Observer.h" +#include "crpropa/module/Output.h" +#include "crpropa/module/OutputROOT.h" +#include "crpropa/module/OutputCRPropa2.h" +#include "crpropa/module/PhotonDINT.h" +#include "crpropa/module/PhotonEleCa.h" +#include "crpropa/module/SimplePropagation.h" +#include "crpropa/module/DeflectionCK.h" +#include "crpropa/module/Tools.h" + +#include "crpropa/magneticField/MagneticField.h" +#include "crpropa/magneticField/MagneticFieldGrid.h" +#include "crpropa/magneticField/QuimbyMagneticField.h" +#include "crpropa/magneticField/JF12Field.h" + +#include "crpropa/Referenced.h" +#include "crpropa/Candidate.h" +#include "crpropa/ParticleState.h" +#include "crpropa/ParticleID.h" +#include "crpropa/ParticleMass.h" +#include "crpropa/Module.h" +#include "crpropa/ModuleList.h" +#include "crpropa/PhasePoint.h" +#include "crpropa/ExplicitRungeKutta.h" +#include "crpropa/Random.h" +#include "crpropa/Units.h" +#include "crpropa/Vector3.h" +#include "crpropa/Source.h" +#include "crpropa/Common.h" +#include "crpropa/Cosmology.h" +#include "crpropa/PhotonBackground.h" +#include "crpropa/Grid.h" +#include "crpropa/GridTools.h" +%} + + +%exception +{ + try + { + $action + } + catch (const std::exception& e) { + SWIG_exception(SWIG_RuntimeError, e.what()); + } + catch (const char *e) { + SWIG_exception(SWIG_RuntimeError, e); + } + catch (Swig::DirectorException &e) { + SWIG_exception(SWIG_RuntimeError, e.getMessage()); + } +} + +%ignore operator<<; +%ignore operator>>; +%ignore *::operator=; +%ignore operator crpropa::Source*; +%ignore operator crpropa::Candidate*; +%ignore operator crpropa::Module*; +%ignore operator crpropa::ModuleList*; +%ignore operator crpropa::MagneticField*; + +%feature("ref") crpropa::Referenced "$this->addReference();" +%feature("unref") crpropa::Referenced "$this->removeReference();" + + +%include "crpropa/Vector3.h" +%template(Vector3d) crpropa::Vector3; +%template(Vector3f) crpropa::Vector3; + +%include "crpropa/Referenced.h" +%include "crpropa/Units.h" +%include "crpropa/Common.h" +%include "crpropa/Cosmology.h" +%include "crpropa/PhotonBackground.h" +%include "crpropa/Random.h" +%include "crpropa/ParticleState.h" +%include "crpropa/ParticleID.h" +%include "crpropa/ParticleMass.h" + +%template(CandidateVector) std::vector< crpropa::ref_ptr >; +%template(CandidateRefPtr) crpropa::ref_ptr; +%include "crpropa/Candidate.h" + +%template(ModuleRefPtr) crpropa::ref_ptr; +%template(stdModuleList) std::list< crpropa::ref_ptr >; +%feature("director") crpropa::Module; +%include "crpropa/Module.h" + +%implicitconv crpropa::ref_ptr; +%template(MagneticFieldRefPtr) crpropa::ref_ptr; +%include "crpropa/magneticField/MagneticField.h" + +%include "crpropa/Grid.h" +%include "crpropa/GridTools.h" + +%implicitconv crpropa::ref_ptr > >; +%template(VectorGridRefPtr) crpropa::ref_ptr > >; +%template(VectorGrid) crpropa::Grid >; + +%implicitconv crpropa::ref_ptr >; +%template(ScalarGridRefPtr) crpropa::ref_ptr >; +%template(ScalarGrid) crpropa::Grid; + +%include "crpropa/magneticField/MagneticFieldGrid.h" +%include "crpropa/magneticField/QuimbyMagneticField.h" +%include "crpropa/magneticField/JF12Field.h" + +%include "crpropa/ExplicitRungeKutta.h" +%include "crpropa/PhasePoint.h" + +%include "crpropa/module/BreakCondition.h" +%include "crpropa/module/Boundary.h" +%include "crpropa/module/Observer.h" +%include "crpropa/module/SimplePropagation.h" +%include "crpropa/module/DeflectionCK.h" +%include "crpropa/module/Output.h" +%include "crpropa/module/OutputROOT.h" +%include "crpropa/module/OutputCRPropa2.h" +%include "crpropa/module/PhotonDINT.h" +%include "crpropa/module/PhotonEleCa.h" +%include "crpropa/module/ElectronPairProduction.h" +%include "crpropa/module/StochasticInteraction.h" +%include "crpropa/module/NuclearDecay.h" +%include "crpropa/module/PhotoPionProduction.h" +%include "crpropa/module/PhotoDisintegration.h" +%include "crpropa/module/Redshift.h" +%include "crpropa/module/Tools.h" + +%template(SourceRefPtr) crpropa::ref_ptr; +%include "crpropa/Source.h" + +%template(ModuleListRefPtr) crpropa::ref_ptr; +%include "crpropa/ModuleList.h" + + +// nice python print +%pythoncode %{ +Module.__str__ = Module.getDescription +def Vector3__str__(self): + return "(%.4e, %.4e, %.4e)" % (self.x, self.y, self.z) +Vector3d.__str__ = Vector3__str__ +Vector3f.__str__ = Vector3__str__ +%} diff --git a/python/mpc.i b/python/mpc.i deleted file mode 100644 index 21b8cedbb..000000000 --- a/python/mpc.i +++ /dev/null @@ -1,179 +0,0 @@ -%module(directors="1") mpc -%feature("autodoc", "1"); // automatic docstrings - -%{ -// workaround for SWIG < 2.0.5 with GCC >= 4.7 -#include -using std::ptrdiff_t; -%} - -%include stl.i -%include std_set.i -%include std_multiset.i -%include std_map.i -%include std_pair.i -%include std_multimap.i -%include std_vector.i -%include std_string.i -%include std_list.i -%include stdint.i -%include std_container.i -%include "exception.i" - -#ifdef MPC_HAVE_QUIMBY -%import (module="quimby") quimby.i -#endif - -%{ -#include "mpc/module/NuclearDecay.h" -#include "mpc/module/ElectronPairProduction.h" -#include "mpc/module/StochasticInteraction.h" -#include "mpc/module/PhotoDisintegration.h" -#include "mpc/module/PhotoPionProduction.h" -#include "mpc/module/Redshift.h" -#include "mpc/module/BreakCondition.h" -#include "mpc/module/Boundary.h" -#include "mpc/module/Observer.h" -#include "mpc/module/Output.h" -#include "mpc/module/OutputROOT.h" -#include "mpc/module/OutputCRPropa2.h" -#include "mpc/module/PhotonDINT.h" -#include "mpc/module/PhotonEleCa.h" -#include "mpc/module/SimplePropagation.h" -#include "mpc/module/DeflectionCK.h" -#include "mpc/module/Tools.h" - -#include "mpc/magneticField/MagneticField.h" -#include "mpc/magneticField/MagneticFieldGrid.h" -#include "mpc/magneticField/QuimbyMagneticField.h" -#include "mpc/magneticField/JF12Field.h" - -#include "mpc/Referenced.h" -#include "mpc/Candidate.h" -#include "mpc/ParticleState.h" -#include "mpc/ParticleID.h" -#include "mpc/ParticleMass.h" -#include "mpc/Module.h" -#include "mpc/ModuleList.h" -#include "mpc/PhasePoint.h" -#include "mpc/ExplicitRungeKutta.h" -#include "mpc/Random.h" -#include "mpc/Units.h" -#include "mpc/Vector3.h" -#include "mpc/Source.h" -#include "mpc/Common.h" -#include "mpc/Cosmology.h" -#include "mpc/PhotonBackground.h" -#include "mpc/Grid.h" -#include "mpc/GridTools.h" -%} - - -%exception -{ - try - { - $action - } - catch (const std::exception& e) { - SWIG_exception(SWIG_RuntimeError, e.what()); - } - catch (const char *e) { - SWIG_exception(SWIG_RuntimeError, e); - } - catch (Swig::DirectorException &e) { - SWIG_exception(SWIG_RuntimeError, e.getMessage()); - } -} - -%ignore operator<<; -%ignore operator>>; -%ignore *::operator=; -%ignore operator mpc::Source*; -%ignore operator mpc::Candidate*; -%ignore operator mpc::Module*; -%ignore operator mpc::ModuleList*; -%ignore operator mpc::MagneticField*; - -%feature("ref") mpc::Referenced "$this->addReference();" -%feature("unref") mpc::Referenced "$this->removeReference();" - - -%include "mpc/Vector3.h" -%template(Vector3d) mpc::Vector3; -%template(Vector3f) mpc::Vector3; - -%include "mpc/Referenced.h" -%include "mpc/Units.h" -%include "mpc/Common.h" -%include "mpc/Cosmology.h" -%include "mpc/PhotonBackground.h" -%include "mpc/Random.h" -%include "mpc/ParticleState.h" -%include "mpc/ParticleID.h" -%include "mpc/ParticleMass.h" - -%template(CandidateVector) std::vector< mpc::ref_ptr >; -%template(CandidateRefPtr) mpc::ref_ptr; -%include "mpc/Candidate.h" - -%template(ModuleRefPtr) mpc::ref_ptr; -%template(stdModuleList) std::list< mpc::ref_ptr >; -%feature("director") mpc::Module; -%include "mpc/Module.h" - -%implicitconv mpc::ref_ptr; -%template(MagneticFieldRefPtr) mpc::ref_ptr; -%include "mpc/magneticField/MagneticField.h" - -%include "mpc/Grid.h" -%include "mpc/GridTools.h" - -%implicitconv mpc::ref_ptr > >; -%template(VectorGridRefPtr) mpc::ref_ptr > >; -%template(VectorGrid) mpc::Grid >; - -%implicitconv mpc::ref_ptr >; -%template(ScalarGridRefPtr) mpc::ref_ptr >; -%template(ScalarGrid) mpc::Grid; - -%include "mpc/magneticField/MagneticFieldGrid.h" -%include "mpc/magneticField/QuimbyMagneticField.h" -%include "mpc/magneticField/JF12Field.h" - -%include "mpc/ExplicitRungeKutta.h" -%include "mpc/PhasePoint.h" - -%include "mpc/module/BreakCondition.h" -%include "mpc/module/Boundary.h" -%include "mpc/module/Observer.h" -%include "mpc/module/SimplePropagation.h" -%include "mpc/module/DeflectionCK.h" -%include "mpc/module/Output.h" -%include "mpc/module/OutputROOT.h" -%include "mpc/module/OutputCRPropa2.h" -%include "mpc/module/PhotonDINT.h" -%include "mpc/module/PhotonEleCa.h" -%include "mpc/module/ElectronPairProduction.h" -%include "mpc/module/StochasticInteraction.h" -%include "mpc/module/NuclearDecay.h" -%include "mpc/module/PhotoPionProduction.h" -%include "mpc/module/PhotoDisintegration.h" -%include "mpc/module/Redshift.h" -%include "mpc/module/Tools.h" - -%template(SourceRefPtr) mpc::ref_ptr; -%include "mpc/Source.h" - -%template(ModuleListRefPtr) mpc::ref_ptr; -%include "mpc/ModuleList.h" - - -// nice python print -%pythoncode %{ -Module.__str__ = Module.getDescription -def Vector3__str__(self): - return "(%.4e, %.4e, %.4e)" % (self.x, self.y, self.z) -Vector3d.__str__ = Vector3__str__ -Vector3f.__str__ = Vector3__str__ -%} diff --git a/src/Candidate.cpp b/src/Candidate.cpp index f27e07138..1bd0b8bae 100644 --- a/src/Candidate.cpp +++ b/src/Candidate.cpp @@ -1,6 +1,6 @@ -#include "mpc/Candidate.h" +#include "crpropa/Candidate.h" -namespace mpc { +namespace crpropa { Candidate::Candidate() : redshift(0), trajectoryLength(0), currentStep(0), nextStep(0), active( @@ -130,4 +130,4 @@ void Candidate::clearSecondaries() { secondaries.clear(); } -} // namespace mpc +} // namespace crpropa diff --git a/src/Clock.cpp b/src/Clock.cpp index ccd353718..27a7503a4 100644 --- a/src/Clock.cpp +++ b/src/Clock.cpp @@ -1,4 +1,4 @@ -#include "mpc/Clock.h" +#include "crpropa/Clock.h" #if defined(WIN32) || defined(_WIN32) @@ -24,7 +24,7 @@ #include #endif -namespace mpc { +namespace crpropa { #ifdef WIN32 class Clock::Impl { diff --git a/src/Common.cpp b/src/Common.cpp index 008e089e3..14a186df7 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -1,4 +1,4 @@ -#include "mpc/Common.h" +#include "crpropa/Common.h" #include "kiss/path.h" #include "kiss/logger.h" @@ -9,7 +9,7 @@ #include #include -namespace mpc { +namespace crpropa { std::string getDataPath(std::string filename) { static std::string dataPath; @@ -79,5 +79,5 @@ double interpolateEquidistant(double x, double lo, double hi, return Y[i] + (p - i) * (Y[i + 1] - Y[i]); } -} // namespace mpc +} // namespace crpropa diff --git a/src/Cosmology.cpp b/src/Cosmology.cpp index 1daea625f..ed5c6d92a 100644 --- a/src/Cosmology.cpp +++ b/src/Cosmology.cpp @@ -1,12 +1,12 @@ -#include "mpc/Cosmology.h" -#include "mpc/Units.h" -#include "mpc/Common.h" +#include "crpropa/Cosmology.h" +#include "crpropa/Units.h" +#include "crpropa/Common.h" #include #include #include -namespace mpc { +namespace crpropa { /** @class Cosmology @@ -158,4 +158,4 @@ double lightTravel2ComovingDistance(double d) { return interpolate(d, cosmology.Dt, cosmology.Dc); } -} // namespace mpc +} // namespace crpropa diff --git a/src/GridTools.cpp b/src/GridTools.cpp index 6edf37477..81f1cb7c3 100644 --- a/src/GridTools.cpp +++ b/src/GridTools.cpp @@ -1,10 +1,10 @@ -#include "mpc/GridTools.h" -#include "mpc/Random.h" +#include "crpropa/GridTools.h" +#include "crpropa/Random.h" #include #include -namespace mpc { +namespace crpropa { Vector3f meanFieldVector(ref_ptr grid) { size_t Nx = grid->getNx(); @@ -49,7 +49,7 @@ void scaleGrid(ref_ptr grid, double a) { grid->get(ix, iy, iz) *= a; } -#ifdef MPC_HAVE_FFTW3F +#ifdef CRPROPA_HAVE_FFTW3F #include "fftw3.h" void initTurbulence(ref_ptr grid, double Brms, double lMin, @@ -185,7 +185,7 @@ void initTurbulence(ref_ptr grid, double Brms, double lMin, scaleGrid(grid, Brms / rmsFieldStrength(grid)); // normalize to Brms } -#endif // MPC_HAVE_FFTW3F +#endif // CRPROPA_HAVE_FFTW3F double turbulentCorrelationLength(double lMin, double lMax, double alpha) { double r = lMin / lMax; @@ -357,4 +357,4 @@ void dumpGridToTxt(ref_ptr grid, std::string filename, double c) { fout.close(); } -} // namespace mpc +} // namespace crpropa diff --git a/src/Module.cpp b/src/Module.cpp index 794a99570..bd87d264f 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -1,8 +1,8 @@ -#include "mpc/Module.h" +#include "crpropa/Module.h" #include -namespace mpc { +namespace crpropa { Module::Module() { const std::type_info &info = typeid(*this); @@ -17,4 +17,4 @@ void Module::setDescription(const std::string &d) { description = d; } -} // namespace mpc +} // namespace crpropa diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 7da8c686a..fd0d33109 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -1,5 +1,5 @@ -#include "mpc/ModuleList.h" -#include "mpc/ProgressBar.h" +#include "crpropa/ModuleList.h" +#include "crpropa/ProgressBar.h" #include #include @@ -10,7 +10,7 @@ typedef void (*sighandler_t)(int); using namespace std; -namespace mpc { +namespace crpropa { bool g_cancel_signal_flag = false; void g_cancel_signal_callback(int sig) { @@ -120,24 +120,24 @@ const ModuleList::module_list_t &ModuleList::getModules() const { } void ModuleList::showModules() const { - mpc::ModuleList::module_list_t::const_iterator iEntry; + crpropa::ModuleList::module_list_t::const_iterator iEntry; iEntry = getModules().begin(); while (iEntry != getModules().end()) { - const mpc::ref_ptr &entry = *iEntry; + const crpropa::ref_ptr &entry = *iEntry; iEntry++; std::cout << " " << entry->getDescription() << "\n"; } } -} // namespace mpc +} // namespace crpropa -std::ostream &operator<<(std::ostream &out, const mpc::ModuleList &list) { - mpc::ModuleList::module_list_t::const_iterator iEntry; +std::ostream &operator<<(std::ostream &out, const crpropa::ModuleList &list) { + crpropa::ModuleList::module_list_t::const_iterator iEntry; iEntry = list.getModules().begin(); while (iEntry != list.getModules().end()) { - const mpc::ref_ptr &entry = *iEntry; + const crpropa::ref_ptr &entry = *iEntry; iEntry++; out << " " << entry->getDescription() << "\n"; } diff --git a/src/ParticleID.cpp b/src/ParticleID.cpp index 6d47867bc..fb4ed22a4 100644 --- a/src/ParticleID.cpp +++ b/src/ParticleID.cpp @@ -1,9 +1,9 @@ -#include "mpc/ParticleID.h" +#include "crpropa/ParticleID.h" #include #include -namespace mpc { +namespace crpropa { std::vector neutrinos() { int a[] = { 12, -12, 14, -14, 16, -16 }; diff --git a/src/ParticleMass.cpp b/src/ParticleMass.cpp index abbb19b07..70f316ced 100644 --- a/src/ParticleMass.cpp +++ b/src/ParticleMass.cpp @@ -1,6 +1,6 @@ -#include "mpc/ParticleMass.h" -#include "mpc/ParticleID.h" -#include "mpc/Common.h" +#include "crpropa/ParticleMass.h" +#include "crpropa/ParticleID.h" +#include "crpropa/Common.h" #include @@ -9,7 +9,7 @@ #include #include -namespace mpc { +namespace crpropa { struct NuclearMassTable { std::vector table; @@ -46,4 +46,4 @@ double nucleusMass(int id) { return mass; } -} // namespace mpc +} // namespace crpropa diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index 2a5f2d7d2..f5956aa37 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -1,9 +1,9 @@ -#include "mpc/ParticleState.h" +#include "crpropa/ParticleState.h" #include #include -namespace mpc { +namespace crpropa { ParticleState::ParticleState() : id(0), charge(0), pmass(0), energy(0), position(0, 0, 0), direction(-1, @@ -94,4 +94,4 @@ Vector3d ParticleState::getMomentum() const { return direction * (energy / c_light); } -} // namespace mpc +} // namespace crpropa diff --git a/src/PhotonBackground.cpp b/src/PhotonBackground.cpp index 1bc7dcf3a..7c30967ba 100644 --- a/src/PhotonBackground.cpp +++ b/src/PhotonBackground.cpp @@ -1,10 +1,10 @@ -#include "mpc/PhotonBackground.h" -#include "mpc/Common.h" +#include "crpropa/PhotonBackground.h" +#include "crpropa/Common.h" #include #include -namespace mpc { +namespace crpropa { // Overall redshift scaling of the Kneiske IRB (see data/PhotonField/KneiskeIRB.py and Kneiske et al. 2004, astro-ph/0309141) double a[9] = { 0, 0.2, 0.4, 0.6, 1, 2, 3, 4, 5 }; @@ -18,4 +18,4 @@ double photonFieldScaling(int photonField, double z) { return pow(1 + z, 3); // CMB-like scaling } -} // namespace mpc +} // namespace crpropa diff --git a/src/Random.cpp b/src/Random.cpp index 742b90dbd..8e2faf3fc 100644 --- a/src/Random.cpp +++ b/src/Random.cpp @@ -57,9 +57,9 @@ // Parts of this file are modified beginning in 29.10.09 for adaption in PXL. // Parts of this file are modified beginning in 10.02.12 for adaption in MPC. -#include "mpc/Random.h" +#include "crpropa/Random.h" -namespace mpc { +namespace crpropa { Random::Random(const uint32& oneSeed) { seed(oneSeed); @@ -406,5 +406,5 @@ Random &Random::instance() { } #endif -} // namespace mpc +} // namespace crpropa diff --git a/src/Source.cpp b/src/Source.cpp index fbede8cef..a118bdaa6 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -1,12 +1,12 @@ -#include "mpc/Source.h" -#include "mpc/Random.h" -#include "mpc/Cosmology.h" +#include "crpropa/Source.h" +#include "crpropa/Random.h" +#include "crpropa/Cosmology.h" #include "HepPID/ParticleIDMethods.hh" #include #include -namespace mpc { +namespace crpropa { void SourceProperty::prepare(ParticleState& particle) const { } @@ -326,4 +326,4 @@ void SourceRedshift1D::prepare(Candidate& candidate) const { candidate.setRedshift(z); } -} // namespace mpc +} // namespace crpropa diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index b593444af..ea8e1a2d0 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -1,23 +1,23 @@ -#include "mpc/XmlExecute.h" -#include "mpc/magneticField/MagneticFieldGrid.h" -#include "mpc/GridTools.h" -#include "mpc/Random.h" -#include "mpc/PhotonBackground.h" -#include "mpc/Cosmology.h" -#include "mpc/module/SimplePropagation.h" -#include "mpc/module/DeflectionCK.h" -#include "mpc/module/Redshift.h" -#include "mpc/module/ElectronPairProduction.h" -#include "mpc/module/PhotoPionProduction.h" -#include "mpc/module/PhotoDisintegration.h" -#include "mpc/module/NuclearDecay.h" -#include "mpc/module/BreakCondition.h" -#include "mpc/module/Boundary.h" -#include "mpc/module/Observer.h" -#include "mpc/module/Output.h" -#include "mpc/module/OutputROOT.h" -#include "mpc/module/OutputCRPropa2.h" -#include "mpc/ModuleList.h" +#include "crpropa/XmlExecute.h" +#include "crpropa/magneticField/MagneticFieldGrid.h" +#include "crpropa/GridTools.h" +#include "crpropa/Random.h" +#include "crpropa/PhotonBackground.h" +#include "crpropa/Cosmology.h" +#include "crpropa/module/SimplePropagation.h" +#include "crpropa/module/DeflectionCK.h" +#include "crpropa/module/Redshift.h" +#include "crpropa/module/ElectronPairProduction.h" +#include "crpropa/module/PhotoPionProduction.h" +#include "crpropa/module/PhotoDisintegration.h" +#include "crpropa/module/NuclearDecay.h" +#include "crpropa/module/BreakCondition.h" +#include "crpropa/module/Boundary.h" +#include "crpropa/module/Observer.h" +#include "crpropa/module/Output.h" +#include "crpropa/module/OutputROOT.h" +#include "crpropa/module/OutputCRPropa2.h" +#include "crpropa/ModuleList.h" #include "pugixml.hpp" @@ -29,7 +29,7 @@ using namespace pugi; using namespace std; -namespace mpc { +namespace crpropa { double childValue(xml_node parent, string childName, bool throwIfEmpty = true) { xml_node node = parent.child(childName.c_str()); @@ -389,13 +389,13 @@ void XmlExecute::loadGridMagneticField(xml_node &node) { double alpha = childValue(node, "SpectralIndex"); cout << " - Spectral index, ~ k^n, n: " << alpha << endl; -#ifdef MPC_HAVE_FFTW3F +#ifdef CRPROPA_HAVE_FFTW3F initTurbulence(field, brms, lMin, lMax, alpha); -#endif // MPC_HAVE_FFTW3F -#ifndef MPC_HAVE_FFTW3F +#endif +#ifndef CRPROPA_HAVE_FFTW3F throw runtime_error( "Turbulent field grid not available. Compile with FFTW3F."); -#endif // MPC_HAVE_FFTW3F +#endif } magnetic_field = new MagneticFieldGrid(field); @@ -696,4 +696,4 @@ void XmlExecute::run() { modules.run(&source, nTrajectories, true); } -} // namespace mpc +} // namespace crpropa diff --git a/src/magneticField/JF12Field.cpp b/src/magneticField/JF12Field.cpp index e4f18d006..cb7a55612 100644 --- a/src/magneticField/JF12Field.cpp +++ b/src/magneticField/JF12Field.cpp @@ -1,11 +1,11 @@ -#include "mpc/magneticField/JF12Field.h" -#include "mpc/Units.h" -#include "mpc/GridTools.h" -#include "mpc/Random.h" +#include "crpropa/magneticField/JF12Field.h" +#include "crpropa/Units.h" +#include "crpropa/GridTools.h" +#include "crpropa/Random.h" #include -namespace mpc { +namespace crpropa { double logisticFunction(double x, double x0, double w) { return 1. / (1. + exp(-2. * (fabs(x) - x0) / w)); @@ -98,7 +98,7 @@ void JF12Field::randomStriated(int seed) { } } -#ifdef MPC_HAVE_FFTW3F +#ifdef CRPROPA_HAVE_FFTW3F void JF12Field::randomTurbulent(int seed) { useTurbulent = true; // turbulent field with Kolmogorov spectrum, B_rms = 1 and Lc = 60 parsec @@ -290,4 +290,4 @@ Vector3d JF12Field::getField(const Vector3d& pos) const { return b; } -} // namespace mpc +} // namespace crpropa diff --git a/src/magneticField/MagneticField.cpp b/src/magneticField/MagneticField.cpp index 28864fc02..9d012e488 100644 --- a/src/magneticField/MagneticField.cpp +++ b/src/magneticField/MagneticField.cpp @@ -1,6 +1,6 @@ -#include "mpc/magneticField/MagneticField.h" +#include "crpropa/magneticField/MagneticField.h" -namespace mpc { +namespace crpropa { PeriodicMagneticField::PeriodicMagneticField(ref_ptr field, const Vector3d &extends) : @@ -68,4 +68,4 @@ Vector3d MagneticFieldList::getField(const Vector3d &position) const { return b; } -} // namespace mpc +} // namespace crpropa diff --git a/src/magneticField/MagneticFieldGrid.cpp b/src/magneticField/MagneticFieldGrid.cpp index e09afc19f..8fb8651aa 100644 --- a/src/magneticField/MagneticFieldGrid.cpp +++ b/src/magneticField/MagneticFieldGrid.cpp @@ -1,6 +1,6 @@ -#include "mpc/magneticField/MagneticFieldGrid.h" +#include "crpropa/magneticField/MagneticFieldGrid.h" -namespace mpc { +namespace crpropa { MagneticFieldGrid::MagneticFieldGrid(ref_ptr grid) { setGrid(grid); @@ -54,4 +54,4 @@ Vector3d ModulatedMagneticFieldGrid::getField(const Vector3d &pos) const { return b * m; } -} // namespace mpc +} // namespace crpropa diff --git a/src/magneticField/TurbulentMagneticField.cpp b/src/magneticField/TurbulentMagneticField.cpp index 3d86e9520..d63b6d1e1 100644 --- a/src/magneticField/TurbulentMagneticField.cpp +++ b/src/magneticField/TurbulentMagneticField.cpp @@ -1,7 +1,7 @@ -#include "mpc/magneticField/TurbulentMagneticField.h" -#include "mpc/Units.h" +#include "crpropa/magneticField/TurbulentMagneticField.h" +#include "crpropa/Units.h" -namespace mpc { +namespace crpropa { TurbulentMagneticField::TurbulentMagneticField(double Brms, double lMin, double lMax, double spectralIndex, int nModes) { @@ -105,4 +105,4 @@ double TurbulentMagneticField::getCorrelationLength() const { return lMax / 2 * (a - 1) / a * (1 - pow(r, a)) / (1 - pow(r, a - 1)); } -} // namespace mpc +} // namespace crpropa diff --git a/src/main.cpp b/src/main.cpp index 735b497bc..72f88cfce 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,4 @@ -#include "mpc/XmlExecute.h" +#include "crpropa/XmlExecute.h" #include #include @@ -10,7 +10,7 @@ int main(int argc, char **argv) { } try { - mpc::XmlExecute exe; + crpropa::XmlExecute exe; if (!exe.load(argv[1])) return 1; exe.run(); diff --git a/src/module/Boundary.cpp b/src/module/Boundary.cpp index 3f29d34b6..87e7c6c56 100644 --- a/src/module/Boundary.cpp +++ b/src/module/Boundary.cpp @@ -1,8 +1,8 @@ -#include "mpc/module/Boundary.h" +#include "crpropa/module/Boundary.h" #include -namespace mpc { +namespace crpropa { PeriodicBox::PeriodicBox() : origin(Vector3d(0, 0, 0)), size(Vector3d(0, 0, 0)) { @@ -251,4 +251,4 @@ std::string EllipsoidalBoundary::getDescription() const { return s.str(); } -} // namespace mpc +} // namespace crpropa diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp index 222e3e0a3..299b48af8 100644 --- a/src/module/BreakCondition.cpp +++ b/src/module/BreakCondition.cpp @@ -1,8 +1,8 @@ -#include "mpc/module/BreakCondition.h" +#include "crpropa/module/BreakCondition.h" #include -namespace mpc { +namespace crpropa { MaximumTrajectoryLength::MaximumTrajectoryLength(double maxLength, std::string flag) : @@ -108,4 +108,4 @@ std::string MinimumRedshift::getDescription() const { return s.str(); } -} // namespace mpc +} // namespace crpropa diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index 418962315..14b7be4e2 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -1,10 +1,10 @@ -#include "mpc/module/DeflectionCK.h" +#include "crpropa/module/DeflectionCK.h" #include #include #include -namespace mpc { +namespace crpropa { /** * @class LorentzForce @@ -144,4 +144,4 @@ std::string DeflectionCK::getDescription() const { return s.str(); } -} // namespace mpc +} // namespace crpropa diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 427a6d0b8..6c9696a7f 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -1,10 +1,10 @@ -#include "mpc/module/ElectronPairProduction.h" +#include "crpropa/module/ElectronPairProduction.h" #include #include #include -namespace mpc { +namespace crpropa { ElectronPairProduction::ElectronPairProduction(PhotonField photonField) : photonField(photonField) { @@ -113,4 +113,4 @@ double ElectronPairProduction::energyLossLength(int id, double E) { return 1. / lossRate; } -} // namespace mpc +} // namespace crpropa diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index 645a5f265..fb9ada1f9 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -1,12 +1,12 @@ -#include "mpc/module/NuclearDecay.h" -#include "mpc/Random.h" +#include "crpropa/module/NuclearDecay.h" +#include "crpropa/Random.h" #include #include #include #include -namespace mpc { +namespace crpropa { NuclearDecay::NuclearDecay(bool electrons, bool neutrinos) : haveElectrons(electrons), haveNeutrinos(neutrinos) { @@ -164,4 +164,4 @@ void NuclearDecay::nucleonEmission(Candidate *candidate, int dA, int dZ) const { candidate->addSecondary(nucleusId(dA, dZ), EpA * dA); } -} // namespace mpc +} // namespace crpropa diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp index 876682b65..a8f453afa 100644 --- a/src/module/Observer.cpp +++ b/src/module/Observer.cpp @@ -1,8 +1,8 @@ -#include "mpc/module/Observer.h" +#include "crpropa/module/Observer.h" #include -namespace mpc { +namespace crpropa { SmallObserverSphere::SmallObserverSphere(Vector3d center, double radius, std::string flag, std::string flagValue, bool makeInactive) : @@ -151,4 +151,4 @@ std::string DetectAll::getDescription() const { return s.str(); } -} // namespace mpc +} // namespace crpropa diff --git a/src/module/Output.cpp b/src/module/Output.cpp index a7d905143..c5256d4ff 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -1,9 +1,9 @@ -#include "mpc/module/Output.h" +#include "crpropa/module/Output.h" #include #include -namespace mpc { +namespace crpropa { void ShellOutput::process(Candidate* c) const { #pragma omp critical @@ -176,4 +176,4 @@ void EventOutput1D::process(Candidate *c) const { } } -} // namespace mpc +} // namespace crpropa diff --git a/src/module/OutputCRPropa2.cpp b/src/module/OutputCRPropa2.cpp index 16599f114..0d93ff507 100644 --- a/src/module/OutputCRPropa2.cpp +++ b/src/module/OutputCRPropa2.cpp @@ -1,6 +1,6 @@ -#include "mpc/module/OutputCRPropa2.h" +#include "crpropa/module/OutputCRPropa2.h" -namespace mpc { +namespace crpropa { CRPropa2EventOutput3D::CRPropa2EventOutput3D(std::string filename) { setDescription("Event output in CRPropa2 format"); @@ -151,4 +151,4 @@ void CRPropa2EventOutput1D::process(Candidate *c) const { } } -} // namespace mpc +} // namespace crpropa diff --git a/src/module/OutputROOT.cpp b/src/module/OutputROOT.cpp index eefce6a50..7aad5f7de 100644 --- a/src/module/OutputROOT.cpp +++ b/src/module/OutputROOT.cpp @@ -1,8 +1,8 @@ -#include "mpc/module/OutputROOT.h" +#include "crpropa/module/OutputROOT.h" #ifdef MPC_HAVE_ROOT -namespace mpc { +namespace crpropa { /////////////////////// ROOT EVENT OUTPUT 1D ////////////////////////////////// ROOTEventOutput1D::ROOTEventOutput1D(std::string filename) { @@ -152,6 +152,6 @@ void ROOTTrajectoryOutput3D::process(Candidate *c) const { } //////////////////////////////////////////////////////////////////////////////// -}// namespace mpc +}// namespace crpropa #endif // MPC_HAVE_ROOT diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index c623a3d66..0849b5482 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -1,5 +1,5 @@ -#include "mpc/module/PhotoDisintegration.h" -#include "mpc/Random.h" +#include "crpropa/module/PhotoDisintegration.h" +#include "crpropa/Random.h" #include #include @@ -7,7 +7,7 @@ #include #include -namespace mpc { +namespace crpropa { PhotoDisintegration::PhotoDisintegration(PhotonField photonField) { init(photonField); @@ -190,4 +190,4 @@ double PhotoDisintegration::energyLossLength(int id, double E) { return 1 / lossRate; } -} // namespace mpc +} // namespace crpropa diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 2f646daaf..ffc3f075d 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -1,5 +1,5 @@ -#include "mpc/module/PhotoPionProduction.h" -#include "mpc/Random.h" +#include "crpropa/module/PhotoPionProduction.h" +#include "crpropa/Random.h" #include #include "sophia.h" @@ -10,7 +10,7 @@ #include #include -namespace mpc { +namespace crpropa { PhotoPionProduction::PhotoPionProduction(PhotonField photonField) : photonField(photonField) { @@ -304,4 +304,4 @@ void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { } } -} // namespace mpc +} // namespace crpropa diff --git a/src/module/PhotonDINT.cpp b/src/module/PhotonDINT.cpp index d71642712..8dc4b13e7 100644 --- a/src/module/PhotonDINT.cpp +++ b/src/module/PhotonDINT.cpp @@ -1,5 +1,5 @@ -#include "mpc/module/PhotonDINT.h" -#include "mpc/Cosmology.h" +#include "crpropa/module/PhotonDINT.h" +#include "crpropa/Cosmology.h" #include #include @@ -8,7 +8,7 @@ using namespace std; -namespace mpc { +namespace crpropa { PhotonDINT::PhotonDINT(const string &filename, ref_ptr field) : filename(filename), fout(filename.c_str()), field(field), IRFlag(0), RadioFlag( @@ -138,4 +138,4 @@ string PhotonDINT::getDescription() const { return s.str(); } -} // namespace mpc +} // namespace crpropa diff --git a/src/module/PhotonEleCa.cpp b/src/module/PhotonEleCa.cpp index 8076235fe..5c3f8fd6b 100644 --- a/src/module/PhotonEleCa.cpp +++ b/src/module/PhotonEleCa.cpp @@ -1,6 +1,6 @@ -#include "mpc/module/PhotonEleCa.h" +#include "crpropa/module/PhotonEleCa.h" -namespace mpc { +namespace crpropa { PhotonEleCa::PhotonEleCa(ref_ptr field) { } @@ -21,4 +21,4 @@ std::string PhotonEleCa::getDescription() const { return s.str(); } -} // namespace mpc +} // namespace crpropa diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index fd128bfed..90bbd2f08 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -1,7 +1,7 @@ -#include "mpc/module/Redshift.h" -#include "mpc/Cosmology.h" +#include "crpropa/module/Redshift.h" +#include "crpropa/Cosmology.h" -namespace mpc { +namespace crpropa { Redshift::Redshift() { setDescription("Redshift"); @@ -23,4 +23,4 @@ void Redshift::process(Candidate *c) const { c->current.setEnergy(E * (1 - dz / (1 + z))); } -} // namespace mpc +} // namespace crpropa diff --git a/src/module/SimplePropagation.cpp b/src/module/SimplePropagation.cpp index b29f11149..8be437ae9 100644 --- a/src/module/SimplePropagation.cpp +++ b/src/module/SimplePropagation.cpp @@ -1,9 +1,9 @@ -#include "mpc/module/SimplePropagation.h" +#include "crpropa/module/SimplePropagation.h" #include #include -namespace mpc { +namespace crpropa { SimplePropagation::SimplePropagation(double minStep, double maxStep) : minStep(minStep), maxStep(maxStep) { @@ -51,4 +51,4 @@ std::string SimplePropagation::getDescription() const { return s.str(); } -} // namespace mpc +} // namespace crpropa diff --git a/src/module/StochasticInteraction.cpp b/src/module/StochasticInteraction.cpp index e63a8dc3a..b92acbe8c 100644 --- a/src/module/StochasticInteraction.cpp +++ b/src/module/StochasticInteraction.cpp @@ -1,6 +1,6 @@ -#include "mpc/module/StochasticInteraction.h" +#include "crpropa/module/StochasticInteraction.h" -namespace mpc { +namespace crpropa { void StochasticInteraction::process(Candidate* candidate) const { double step = candidate->getCurrentStep(); @@ -31,4 +31,4 @@ void StochasticInteraction::process(Candidate* candidate) const { } } -} // namespace mpc +} // namespace crpropa diff --git a/src/module/Tools.cpp b/src/module/Tools.cpp index 7e28073f0..9d0246934 100644 --- a/src/module/Tools.cpp +++ b/src/module/Tools.cpp @@ -1,12 +1,12 @@ -#include "mpc/module/Tools.h" -#include "mpc/Clock.h" +#include "crpropa/module/Tools.h" +#include "crpropa/Clock.h" #include #include using namespace std; -namespace mpc { +namespace crpropa { PerformanceModule::~PerformanceModule() { double total = 0; @@ -114,4 +114,4 @@ std::string ParticleSelector::getDescription() const { return "ParticleSelector"; } -} // namespace mpc +} // namespace crpropa diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index 8c519abb7..9d36b52ce 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -1,14 +1,14 @@ /** Unit tests for break condition, observer, boundary and tool modules */ -#include "mpc/module/BreakCondition.h" -#include "mpc/module/Observer.h" -#include "mpc/module/Boundary.h" -#include "mpc/module/Tools.h" -#include "mpc/ParticleID.h" +#include "crpropa/module/BreakCondition.h" +#include "crpropa/module/Observer.h" +#include "crpropa/module/Boundary.h" +#include "crpropa/module/Tools.h" +#include "crpropa/ParticleID.h" #include "gtest/gtest.h" -namespace mpc { +namespace crpropa { //** ========================= Break conditions ============================= */ TEST(MinimumEnergy, test) { @@ -350,4 +350,4 @@ int main(int argc, char **argv) { return RUN_ALL_TESTS(); } -} // namespace mpc +} // namespace crpropa diff --git a/test/testCore.cpp b/test/testCore.cpp index a99e937ea..1125f8ef4 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -5,14 +5,14 @@ Common functions */ -#include "mpc/Candidate.h" -#include "mpc/Random.h" -#include "mpc/Grid.h" -#include "mpc/GridTools.h" +#include "crpropa/Candidate.h" +#include "crpropa/Random.h" +#include "crpropa/Grid.h" +#include "crpropa/GridTools.h" #include "gtest/gtest.h" -namespace mpc { +namespace crpropa { TEST(ParticleState, position) { ParticleState particle; @@ -433,4 +433,4 @@ int main(int argc, char **argv) { return RUN_ALL_TESTS(); } -} // namespace mpc +} // namespace crpropa diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 9fdf34afb..911da4d9f 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -1,14 +1,14 @@ -#include "mpc/Candidate.h" -#include "mpc/module/ElectronPairProduction.h" -#include "mpc/module/NuclearDecay.h" -#include "mpc/module/PhotoDisintegration.h" -#include "mpc/module/PhotoPionProduction.h" -#include "mpc/module/Redshift.h" +#include "crpropa/Candidate.h" +#include "crpropa/module/ElectronPairProduction.h" +#include "crpropa/module/NuclearDecay.h" +#include "crpropa/module/PhotoDisintegration.h" +#include "crpropa/module/PhotoPionProduction.h" +#include "crpropa/module/Redshift.h" #include "gtest/gtest.h" #include -namespace mpc { +namespace crpropa { TEST(ElectronPairProduction, EnergyDecreasing) { // Test if energy loss occurs for protons with energies from 1e15 - 1e23 eV @@ -590,4 +590,4 @@ int main(int argc, char **argv) { return RUN_ALL_TESTS(); } -} // namespace mpc +} // namespace crpropa diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index 539fe9c00..485f83d46 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -1,13 +1,13 @@ -#include "mpc/magneticField/MagneticFieldGrid.h" -#include "mpc/magneticField/TurbulentMagneticField.h" -#include "mpc/Grid.h" -#include "mpc/GridTools.h" -#include "mpc/Units.h" -#include "mpc/Common.h" +#include "crpropa/magneticField/MagneticFieldGrid.h" +#include "crpropa/magneticField/TurbulentMagneticField.h" +#include "crpropa/Grid.h" +#include "crpropa/GridTools.h" +#include "crpropa/Units.h" +#include "crpropa/Common.h" #include "gtest/gtest.h" -using namespace mpc; +using namespace crpropa; TEST(testUniformMagneticField, SimpleTest) { UniformMagneticField B(Vector3d(-1, 5, 3)); diff --git a/test/testModuleList.cpp b/test/testModuleList.cpp index 1ab24b48d..efe9a6b4f 100644 --- a/test/testModuleList.cpp +++ b/test/testModuleList.cpp @@ -1,11 +1,11 @@ -#include "mpc/ModuleList.h" -#include "mpc/module/SimplePropagation.h" -#include "mpc/module/BreakCondition.h" -#include "mpc/Source.h" +#include "crpropa/ModuleList.h" +#include "crpropa/module/SimplePropagation.h" +#include "crpropa/module/BreakCondition.h" +#include "crpropa/Source.h" #include "gtest/gtest.h" -namespace mpc { +namespace crpropa { TEST(ModuleList, process) { ModuleList modules; @@ -60,4 +60,4 @@ int main(int argc, char **argv) { return RUN_ALL_TESTS(); } -} // namespace mpc +} // namespace crpropa diff --git a/test/testOutput.cpp b/test/testOutput.cpp index e99c50109..a72d9ea27 100644 --- a/test/testOutput.cpp +++ b/test/testOutput.cpp @@ -1,12 +1,12 @@ /** Unit tests for output modules */ -#include "mpc/module/Output.h" -#include "mpc/module/OutputCRPropa2.h" -#include "mpc/module/OutputROOT.h" +#include "crpropa/module/Output.h" +#include "crpropa/module/OutputCRPropa2.h" +#include "crpropa/module/OutputROOT.h" #include "gtest/gtest.h" -using namespace mpc; +using namespace crpropa; TEST(ConditionalOutput, removeProperty) { ConditionalOutput output("", "Detected"); diff --git a/test/testPropagation.cpp b/test/testPropagation.cpp index b21d481b2..aaaef86e8 100644 --- a/test/testPropagation.cpp +++ b/test/testPropagation.cpp @@ -1,10 +1,10 @@ -#include "mpc/Candidate.h" -#include "mpc/module/SimplePropagation.h" -#include "mpc/module/DeflectionCK.h" +#include "crpropa/Candidate.h" +#include "crpropa/module/SimplePropagation.h" +#include "crpropa/module/DeflectionCK.h" #include "gtest/gtest.h" -namespace mpc { +namespace crpropa { TEST(testSimplePropagation, step) { double minStep = 20; @@ -70,4 +70,4 @@ int main(int argc, char **argv) { return RUN_ALL_TESTS(); } -} // namespace mpc +} // namespace crpropa diff --git a/test/testSource.cpp b/test/testSource.cpp index 6302d2074..5fd4b149d 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -1,9 +1,9 @@ -#include "mpc/Source.h" +#include "crpropa/Source.h" #include "gtest/gtest.h" #include -namespace mpc { +namespace crpropa { TEST(SourcePosition, simpleTest) { Vector3d position(1, 2, 3); @@ -263,4 +263,4 @@ int main(int argc, char **argv) { return RUN_ALL_TESTS(); } -} // namespace mpc +} // namespace crpropa diff --git a/test/testVector3.cpp b/test/testVector3.cpp index dd2b1ad07..5fa9068dd 100644 --- a/test/testVector3.cpp +++ b/test/testVector3.cpp @@ -1,7 +1,7 @@ -#include "mpc/Vector3.h" +#include "crpropa/Vector3.h" #include "gtest/gtest.h" -namespace mpc { +namespace crpropa { TEST(Vector3, division) { Vector3d v(10); @@ -81,4 +81,4 @@ int main(int argc, char **argv) { return RUN_ALL_TESTS(); } -} // namespace mpc +} // namespace crpropa From 07adcfdf999a2b0fd85abf194f52467a638a1d24 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 24 Jun 2013 18:03:58 +0200 Subject: [PATCH 0312/1298] execute missing name changes for data paths --- src/Common.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Common.cpp b/src/Common.cpp index 14a186df7..08a84acae 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -16,7 +16,7 @@ std::string getDataPath(std::string filename) { if (dataPath.size()) return concat_path(dataPath, filename); - const char *env_path = getenv("MPC_DATA_PATH"); + const char *env_path = getenv("CRPROPA_DATA_PATH"); if (env_path) { if (is_directory(env_path)) { dataPath = env_path; @@ -26,9 +26,9 @@ std::string getDataPath(std::string filename) { } } -#ifdef MPC_INSTALL_PREFIX +#ifdef CRPROPA_INSTALL_PREFIX { - std::string _path = MPC_INSTALL_PREFIX "/share/mpc"; + std::string _path = CRPROPA_INSTALL_PREFIX "/share/crpropa"; if (is_directory(_path)) { dataPath = _path; KISS_LOG_INFO From 5f0e4ffda3e85b30b8891f45b8a3eab0afff27a8 Mon Sep 17 00:00:00 2001 From: geromueller Date: Tue, 25 Jun 2013 12:51:42 +0200 Subject: [PATCH 0313/1298] fix ROOT config --- CMakeLists.txt | 8 +++----- cmake/FindROOT.cmake | 8 +++++++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 172633424..c3067a076 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,12 +82,10 @@ option(ENABLE_ROOT "ROOT Output" ON) if(ENABLE_ROOT) find_package(ROOT) if(ROOT_FOUND) - FIND_PROGRAM(ROOT_CONFIG root-config REQUIRED ROOT_CONFIG_PATH) - execute_process(COMMAND ${ROOT_CONFIG} "--cflags" OUTPUT_VARIABLE ROOT_CFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process(COMMAND ${ROOT_CONFIG} "--libs" OUTPUT_VARIABLE ROOT_LIBS OUTPUT_STRIP_TRAILING_WHITESPACE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ROOT_CFLAGS}") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${ROOT_LIBS}") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${ROOT_LIBS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") add_definitions(-DCRPROPA_HAVE_ROOT) list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_ROOT) endif(ROOT_FOUND) diff --git a/cmake/FindROOT.cmake b/cmake/FindROOT.cmake index dd7810c23..676adb691 100644 --- a/cmake/FindROOT.cmake +++ b/cmake/FindROOT.cmake @@ -6,10 +6,16 @@ find_program(ROOT_CONFIG_EXECUTABLE root-config PATHS $ENV{ROOTSYS}/bin) + + if(NOT ROOT_CONFIG_EXECUTABLE) set(ROOT_FOUND FALSE) MESSAGE(STATUS "ROOT: NOT Found!") else() set(ROOT_FOUND TRUE) - MESSAGE(STATUS "ROOT: Found!") + execute_process(COMMAND ${ROOT_CONFIG_EXECUTABLE} "--cflags" OUTPUT_VARIABLE ROOT_CFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${ROOT_CONFIG_EXECUTABLE} "--libs" OUTPUT_VARIABLE ROOT_LIBS OUTPUT_STRIP_TRAILING_WHITESPACE) + message(STATUS "ROOT: Found!") + message(STATUS " CFlags: " ${ROOT_CFLAGS}) + message(STATUS " Libs: " ${ROOT_LIBS}) endif() \ No newline at end of file From a5e146fa2172059761eb23f6377125c8c6b57fe9 Mon Sep 17 00:00:00 2001 From: geromueller Date: Tue, 25 Jun 2013 13:13:05 +0200 Subject: [PATCH 0314/1298] fix dint include guards, avoid conflicts --- libs/dint/include/dint/advance.h | 4 ++-- libs/dint/include/dint/background.h | 5 ++--- libs/dint/include/dint/binfread.h | 5 ++--- libs/dint/include/dint/check.h | 4 ++-- libs/dint/include/dint/const.h | 5 ++--- libs/dint/include/dint/cvector.h | 5 ++--- libs/dint/include/dint/decay.h | 4 ++-- libs/dint/include/dint/deriv.h | 4 ++-- libs/dint/include/dint/error.h | 4 ++-- libs/dint/include/dint/final.h | 4 ++-- libs/dint/include/dint/fold.h | 4 ++-- libs/dint/include/dint/frag.h | 4 ++-- libs/dint/include/dint/gauleg.h | 4 ++-- libs/dint/include/dint/inject.h | 4 ++-- libs/dint/include/dint/io_util.h | 4 ++-- libs/dint/include/dint/load.h | 4 ++-- libs/dint/include/dint/math_util.h | 4 ++-- libs/dint/include/dint/prepare.h | 4 ++-- libs/dint/include/dint/prop_second.h | 5 ++--- libs/dint/include/dint/rate.h | 4 ++-- libs/dint/include/dint/spectrum.h | 4 ++-- libs/dint/include/dint/sync.h | 5 ++--- libs/dint/include/dint/utilities.h | 4 ++-- libs/dint/include/dint/vector.h | 4 ++-- 24 files changed, 48 insertions(+), 54 deletions(-) diff --git a/libs/dint/include/dint/advance.h b/libs/dint/include/dint/advance.h index 8e3919046..ca8d03e74 100644 --- a/libs/dint/include/dint/advance.h +++ b/libs/dint/include/dint/advance.h @@ -1,5 +1,5 @@ -#ifndef _ADVANCE_H -#define _ADVANCE_H +#ifndef DINT_ADVANCE_H +#define DINT__ADVANCE_H #include #include "dint/spectrum.h" diff --git a/libs/dint/include/dint/background.h b/libs/dint/include/dint/background.h index 7368581a9..17b67f7c2 100644 --- a/libs/dint/include/dint/background.h +++ b/libs/dint/include/dint/background.h @@ -1,6 +1,5 @@ - -#ifndef _BACKGROUND_H -#define _BACKGROUND_H +#ifndef DINT__BACKGROUND_H +#define DINT__BACKGROUND_H #include #include diff --git a/libs/dint/include/dint/binfread.h b/libs/dint/include/dint/binfread.h index 0e3c2c60e..da5f8b8ce 100644 --- a/libs/dint/include/dint/binfread.h +++ b/libs/dint/include/dint/binfread.h @@ -1,6 +1,5 @@ - -#ifndef _BINFREAD_H -#define _BINFREAD_H +#ifndef DINT__BINFREAD_H +#define DINT__BINFREAD_H // T. Beau 2005 diff --git a/libs/dint/include/dint/check.h b/libs/dint/include/dint/check.h index 161e3d2eb..b7550b614 100644 --- a/libs/dint/include/dint/check.h +++ b/libs/dint/include/dint/check.h @@ -1,5 +1,5 @@ -#ifndef _CHECK_H -#define _CHECK_H +#ifndef DINT__CHECK_H +#define DINT__CHECK_H #include "dint/cvector.h" diff --git a/libs/dint/include/dint/const.h b/libs/dint/include/dint/const.h index 0f0f3caee..d43c7630d 100644 --- a/libs/dint/include/dint/const.h +++ b/libs/dint/include/dint/const.h @@ -1,6 +1,5 @@ - -#ifndef _CONST_H -#define _CONST_H +#ifndef DINT__CONST_H +#define DINT__CONST_H #define ELECTRON_MASS 5.110e5 diff --git a/libs/dint/include/dint/cvector.h b/libs/dint/include/dint/cvector.h index d5e4af931..ce9c5e9a1 100644 --- a/libs/dint/include/dint/cvector.h +++ b/libs/dint/include/dint/cvector.h @@ -1,6 +1,5 @@ - -#ifndef _CVECTOR_H -#define _CVECTOR_H +#ifndef DINT__CVECTOR_H +#define DINT__CVECTOR_H #include "dint/vector.h" #include diff --git a/libs/dint/include/dint/decay.h b/libs/dint/include/dint/decay.h index cf3f95dfd..78351824b 100644 --- a/libs/dint/include/dint/decay.h +++ b/libs/dint/include/dint/decay.h @@ -1,5 +1,5 @@ -#ifndef _DECAY_H -#define _DECAY_H +#ifndef DINT__DECAY_H +#define DINT__DECAY_H double PionToPhoton(const int iPhoton, const int iPion); double PionToLepton(const double leptonEnergy, const double pionEnergy); diff --git a/libs/dint/include/dint/deriv.h b/libs/dint/include/dint/deriv.h index f56bb2e55..2055d7f28 100644 --- a/libs/dint/include/dint/deriv.h +++ b/libs/dint/include/dint/deriv.h @@ -1,5 +1,5 @@ -#ifndef _DERIV_H -#define _DERIV_H +#ifndef DINT__DERIV_H +#define DINT__DERIV_H #include "dint/rate.h" #include "dint/spectrum.h" diff --git a/libs/dint/include/dint/error.h b/libs/dint/include/dint/error.h index de86a3c8b..f619c0bcf 100644 --- a/libs/dint/include/dint/error.h +++ b/libs/dint/include/dint/error.h @@ -1,5 +1,5 @@ -#ifndef _ERROR_H -#define _ERROR_H +#ifndef DINT__ERROR_H +#define DINT__ERROR_H typedef enum {NO_ERROR = 0, ARRAY_ERROR = 1, IO_ERROR = 2, PROGRAM_ERROR = 3} ErrorCode; diff --git a/libs/dint/include/dint/final.h b/libs/dint/include/dint/final.h index 4f05c2832..95245f5b9 100644 --- a/libs/dint/include/dint/final.h +++ b/libs/dint/include/dint/final.h @@ -1,5 +1,5 @@ -#ifndef _FINAL_H -#define _FINAL_H +#ifndef DINT__FINAL_H +#define DINT__FINAL_H #include "dint/spectrum.h" #include "dint/cvector.h" diff --git a/libs/dint/include/dint/fold.h b/libs/dint/include/dint/fold.h index 64f7b367f..883134abc 100644 --- a/libs/dint/include/dint/fold.h +++ b/libs/dint/include/dint/fold.h @@ -1,5 +1,5 @@ -#ifndef _FOLD_H -#define _FOLD_H +#ifndef DINT__FOLD_H +#define DINT__FOLD_H #include "dint/rate.h" #include "dint/cvector.h" diff --git a/libs/dint/include/dint/frag.h b/libs/dint/include/dint/frag.h index 8d820031c..3dc172932 100644 --- a/libs/dint/include/dint/frag.h +++ b/libs/dint/include/dint/frag.h @@ -1,5 +1,5 @@ -#ifndef _FRAG_H -#define _FRAG_H +#ifndef DINT__FRAG_H +#define DINT__FRAG_H double OldFrag(const double x); double HillFrag(const double x); diff --git a/libs/dint/include/dint/gauleg.h b/libs/dint/include/dint/gauleg.h index a0c84e638..9915e2492 100644 --- a/libs/dint/include/dint/gauleg.h +++ b/libs/dint/include/dint/gauleg.h @@ -1,5 +1,5 @@ -#ifndef _GAULEG_H -#define _GAULEG_H +#ifndef DINT__GAULEG_H +#define DINT__GAULEG_H void Gauleg(const double x1, const double x2, double x[], double w[], const int n); diff --git a/libs/dint/include/dint/inject.h b/libs/dint/include/dint/inject.h index 92ed2ce45..9b521c166 100644 --- a/libs/dint/include/dint/inject.h +++ b/libs/dint/include/dint/inject.h @@ -1,5 +1,5 @@ -#ifndef _INJECT_H -#define _INJECT_H +#ifndef DINT__INJECT_H +#define DINT__INJECT_H #include "dint/cvector.h" #include "dint/spectrum.h" diff --git a/libs/dint/include/dint/io_util.h b/libs/dint/include/dint/io_util.h index 77bcc2c03..31df6e4cb 100644 --- a/libs/dint/include/dint/io_util.h +++ b/libs/dint/include/dint/io_util.h @@ -1,5 +1,5 @@ -#ifndef _IO_UTIL_H -#define _IO_UTIL_H +#ifndef DINT__IO_UTIL_H +#define DINT__IO_UTIL_H #include diff --git a/libs/dint/include/dint/load.h b/libs/dint/include/dint/load.h index 7a1531ed8..88bfa4e49 100644 --- a/libs/dint/include/dint/load.h +++ b/libs/dint/include/dint/load.h @@ -1,5 +1,5 @@ -#ifndef _LOAD_H -#define _LOAD_H +#ifndef DINT__LOAD_H +#define DINT__LOAD_H #include "dint/rate.h" #include "dint/utilities.h" diff --git a/libs/dint/include/dint/math_util.h b/libs/dint/include/dint/math_util.h index 4c0e557b5..436b201a3 100644 --- a/libs/dint/include/dint/math_util.h +++ b/libs/dint/include/dint/math_util.h @@ -1,5 +1,5 @@ -#ifndef _MATH_UTIL_H -#define _MATH_UTIL_H +#ifndef DINT__MATH_UTIL_H +#define DINT__MATH_UTIL_H double DMax(const double double1, const double double2); double DMin(const double double1, const double double2); diff --git a/libs/dint/include/dint/prepare.h b/libs/dint/include/dint/prepare.h index 144ca7f05..55b0e7a8b 100644 --- a/libs/dint/include/dint/prepare.h +++ b/libs/dint/include/dint/prepare.h @@ -1,5 +1,5 @@ -#ifndef _PREPARE_H -#define _PREPARE_H +#ifndef DINT__PREPARE_H +#define DINT__PREPARE_H #include #include "dint/spectrum.h" diff --git a/libs/dint/include/dint/prop_second.h b/libs/dint/include/dint/prop_second.h index 8b01292c4..afe4c1400 100644 --- a/libs/dint/include/dint/prop_second.h +++ b/libs/dint/include/dint/prop_second.h @@ -1,6 +1,5 @@ - -#ifndef _PROPSECOND_H -#define _PROPSECOND_H +#ifndef DINT__PROPSECOND_H +#define DINT__PROPSECOND_H #include "dint/cvector.h" diff --git a/libs/dint/include/dint/rate.h b/libs/dint/include/dint/rate.h index a9f43b92e..fb3c47f10 100644 --- a/libs/dint/include/dint/rate.h +++ b/libs/dint/include/dint/rate.h @@ -1,5 +1,5 @@ -#ifndef _RATE_H -#define _RATE_H +#ifndef DINT__RATE_H +#define DINT__RATE_H #include "dint/vector.h" #include "dint/binfread.h" diff --git a/libs/dint/include/dint/spectrum.h b/libs/dint/include/dint/spectrum.h index dee58c937..772522e93 100644 --- a/libs/dint/include/dint/spectrum.h +++ b/libs/dint/include/dint/spectrum.h @@ -1,5 +1,5 @@ -#ifndef _SPECTRUM_H -#define _SPECTRUM_H +#ifndef DINT__SPECTRUM_H +#define DINT__SPECTRUM_H #include "dint/vector.h" #include "dint/cvector.h" diff --git a/libs/dint/include/dint/sync.h b/libs/dint/include/dint/sync.h index 3d5c2b9ad..043f68f36 100644 --- a/libs/dint/include/dint/sync.h +++ b/libs/dint/include/dint/sync.h @@ -1,6 +1,5 @@ - -#ifndef _SYNC_H -#define _SYNC_H +#ifndef DINT__SYNC_H +#define DINT__SYNC_H #include "dint/rate.h" #include "dint/cvector.h" diff --git a/libs/dint/include/dint/utilities.h b/libs/dint/include/dint/utilities.h index b57ae1f03..fc30d0c4c 100644 --- a/libs/dint/include/dint/utilities.h +++ b/libs/dint/include/dint/utilities.h @@ -1,5 +1,5 @@ -#ifndef _UTILITIES_H -#define _UTILITIES_H +#ifndef DINT__UTILITIES_H +#define DINT__UTILITIES_H #include "dint/error.h" #include "dint/io_util.h" diff --git a/libs/dint/include/dint/vector.h b/libs/dint/include/dint/vector.h index 111f046c6..efa6098f5 100644 --- a/libs/dint/include/dint/vector.h +++ b/libs/dint/include/dint/vector.h @@ -1,5 +1,5 @@ -#ifndef _VECTOR_H -#define _VECTOR_H +#ifndef DINT__VECTOR_H +#define DINT__VECTOR_H /* Vectors, matrices, and tensors defined here are very simple, dynamic objects. They do not provide any bound checking nor has extra data From a346b497e89fc4eb99ee96d24d43f02183b7bf8f Mon Sep 17 00:00:00 2001 From: geromueller Date: Tue, 25 Jun 2013 13:27:32 +0200 Subject: [PATCH 0315/1298] fix mpc -> crpropa bugs --- src/Clock.cpp | 2 +- src/ModuleList.cpp | 4 ++-- src/ParticleID.cpp | 6 +++--- src/ParticleState.cpp | 4 ++-- src/Random.cpp | 4 ++-- src/XmlExecute.cpp | 4 ++-- src/magneticField/TurbulentMagneticField.cpp | 2 +- src/module/NuclearDecay.cpp | 2 +- src/module/OutputROOT.cpp | 4 ++-- src/module/PhotoDisintegration.cpp | 4 ++-- test/testCore.cpp | 2 +- test/testMagneticField.cpp | 4 ++-- test/testOutput.cpp | 2 +- 13 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Clock.cpp b/src/Clock.cpp index 27a7503a4..e0a429a18 100644 --- a/src/Clock.cpp +++ b/src/Clock.cpp @@ -142,7 +142,7 @@ Clock &Clock::getInstance() { #endif int i = omp_get_thread_num(); if (i >= MAX_THREAD) - throw std::runtime_error("mpc::Clock: more than MAX_THREAD threads!"); + throw std::runtime_error("crpropa::Clock: more than MAX_THREAD threads!"); return tls[i].r; } #else diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index fd0d33109..0c11ef268 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -55,7 +55,7 @@ void ModuleList::run(candidate_vector_t &candidates, bool recursive) { size_t count = candidates.size(); #if _OPENMP - std::cout << "mpc::ModuleList: Number of Threads: " << omp_get_max_threads() << std::endl; + std::cout << "crpropa::ModuleList: Number of Threads: " << omp_get_max_threads() << std::endl; #endif ProgressBar progressbar(count); @@ -84,7 +84,7 @@ void ModuleList::run(candidate_vector_t &candidates, bool recursive) { void ModuleList::run(Source *source, size_t count, bool recursive) { #if _OPENMP - std::cout << "mpc::ModuleList: Number of Threads: " << omp_get_max_threads() << std::endl; + std::cout << "crpropa::ModuleList: Number of Threads: " << omp_get_max_threads() << std::endl; #endif ProgressBar progressbar(count); diff --git a/src/ParticleID.cpp b/src/ParticleID.cpp index fb4ed22a4..0d67c52e3 100644 --- a/src/ParticleID.cpp +++ b/src/ParticleID.cpp @@ -20,15 +20,15 @@ std::vector leptons() { int nucleusId(int a, int z) { if (z < 0) throw std::runtime_error( - "mpc::Nucleus: no nucleus with Z < 0, A=" + kiss::str(a) + " Z=" + "crpropa::Nucleus: no nucleus with Z < 0, A=" + kiss::str(a) + " Z=" + kiss::str(z)); if (a < 1) throw std::runtime_error( - "mpc::Nucleus: no nucleus with A < 1, A=" + kiss::str(a) + " Z=" + "crpropa::Nucleus: no nucleus with A < 1, A=" + kiss::str(a) + " Z=" + kiss::str(z)); if (a < z) throw std::runtime_error( - "mpc::Nucleus: no nucleus with A < Z, A=" + kiss::str(a) + " Z=" + "crpropa::Nucleus: no nucleus with A < Z, A=" + kiss::str(a) + " Z=" + kiss::str(z)); return 1000000000 + z * 10000 + a * 10; } diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index f5956aa37..943892f65 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -75,7 +75,7 @@ double ParticleState::getLorentzFactor() const { return energy / (pmass * c_squared); else throw std::runtime_error( - "mpc::ParticleState::getLorentzFactor only for nuclei/nucleons"); + "crpropa::ParticleState::getLorentzFactor only for nuclei/nucleons"); } void ParticleState::setLorentzFactor(double gamma) { @@ -83,7 +83,7 @@ void ParticleState::setLorentzFactor(double gamma) { energy = gamma * pmass * c_squared; else throw std::runtime_error( - "mpc::ParticleState::setLorentzFactor only for nuclei/nucleons"); + "crpropa::ParticleState::setLorentzFactor only for nuclei/nucleons"); } Vector3d ParticleState::getVelocity() const { diff --git a/src/Random.cpp b/src/Random.cpp index 8e2faf3fc..a791e05d1 100644 --- a/src/Random.cpp +++ b/src/Random.cpp @@ -55,7 +55,7 @@ // when you write. // Parts of this file are modified beginning in 29.10.09 for adaption in PXL. -// Parts of this file are modified beginning in 10.02.12 for adaption in MPC. +// Parts of this file are modified beginning in 10.02.12 for adaption in CRPROPA. #include "crpropa/Random.h" @@ -396,7 +396,7 @@ Random &Random::instance() { #endif int i = omp_get_thread_num(); if (i >= MAX_THREAD) - throw std::runtime_error("mpc::Random: more than MAX_THREAD threads!"); + throw std::runtime_error("crpropa::Random: more than MAX_THREAD threads!"); return tls[i].r; } #else diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index ea8e1a2d0..59d23c14c 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -665,7 +665,7 @@ void XmlExecute::loadOutput(xml_node &node) { cout << " --> unknown output type " << "('Events', 'Full Trajectories' or 'None')" << endl; } -#ifdef MPC_HAVE_ROOT +#ifdef CRPROPA_HAVE_ROOT else if (format == "ROOT") { if (type == "Full Trajectories") if (is1D) @@ -683,7 +683,7 @@ void XmlExecute::loadOutput(xml_node &node) { cout << " --> unknown output type " << "('Events', 'Full Trajectories' or 'None')" << endl; } -#endif // MPC_HAVE_ROOT +#endif // CRPROPA_HAVE_ROOT else { cout << " --> unknown output format. " << " Use 'ASCII' or 'ROOT' (if ROOT is set)" << endl; diff --git a/src/magneticField/TurbulentMagneticField.cpp b/src/magneticField/TurbulentMagneticField.cpp index d63b6d1e1..39d3fe404 100644 --- a/src/magneticField/TurbulentMagneticField.cpp +++ b/src/magneticField/TurbulentMagneticField.cpp @@ -31,7 +31,7 @@ void TurbulentMagneticField::setTurbulenceProperties(double Brms, double lMin, void TurbulentMagneticField::initialize() { if (lMin >= lMax) - throw std::runtime_error("mpc::TurbulentMagneticField: lMin >= lMax"); + throw std::runtime_error("crpropa::TurbulentMagneticField: lMin >= lMax"); double lkMin = log10(2 * M_PI / lMax); double lkMax = log10(2 * M_PI / lMin); diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index fb9ada1f9..be665fe2e 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -17,7 +17,7 @@ NuclearDecay::NuclearDecay(bool electrons, bool neutrinos) : std::ifstream infile(filename.c_str()); if (!infile.good()) throw std::runtime_error( - "mpc::NuclearDecay: could not open file " + filename); + "crpropa::NuclearDecay: could not open file " + filename); decayTable.resize(27 * 31); while (infile.good()) { diff --git a/src/module/OutputROOT.cpp b/src/module/OutputROOT.cpp index 7aad5f7de..faa48e96a 100644 --- a/src/module/OutputROOT.cpp +++ b/src/module/OutputROOT.cpp @@ -1,6 +1,6 @@ #include "crpropa/module/OutputROOT.h" -#ifdef MPC_HAVE_ROOT +#ifdef CRPROPA_HAVE_ROOT namespace crpropa { @@ -154,4 +154,4 @@ void ROOTTrajectoryOutput3D::process(Candidate *c) const { }// namespace crpropa -#endif // MPC_HAVE_ROOT +#endif // CRPROPA_HAVE_ROOT diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 0849b5482..136c058b6 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -30,7 +30,7 @@ void PhotoDisintegration::init(PhotonField photonField) { break; default: throw std::runtime_error( - "mpc::PhotoDisintegration: unknown photon background"); + "crpropa::PhotoDisintegration: unknown photon background"); } } @@ -41,7 +41,7 @@ void PhotoDisintegration::init(std::string filename) { std::ifstream infile(filename.c_str()); if (!infile.good()) throw std::runtime_error( - "mpc::PhotoDisintegration: could not open file " + filename); + "crpropa::PhotoDisintegration: could not open file " + filename); std::string line; while (std::getline(infile, line)) { diff --git a/test/testCore.cpp b/test/testCore.cpp index 1125f8ef4..d0b888ff0 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -1,4 +1,4 @@ -/** Unit tests for core features of MPC +/** Unit tests for core features of CRPropa Candidate ParticleState Random diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index 485f83d46..de985725f 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -29,7 +29,7 @@ TEST(testMagneticFieldList, SimpleTest) { EXPECT_DOUBLE_EQ(b.z, 3); } -#ifdef MPC_HAVE_FFTW3F +#ifdef CRPROPA_HAVE_FFTW3F TEST(testVectorFieldGrid, Turbulence_bmean_brms) { // Test for zero mean: = 0 size_t n = 64; @@ -88,7 +88,7 @@ TEST(testVectorFieldGrid, turbulence_Exceptions) { EXPECT_THROW(initTurbulence(grid, brms, 2 * spacing, 33 * spacing), std::runtime_error); } -#endif // MPC_HAVE_FFTW3F +#endif // CRPROPA_HAVE_FFTW3F TEST(testTurbulentMagneticField, SimpleTest) { TurbulentMagneticField B; B.setTurbulenceProperties(1 * nG, 10 * parsec, 200 * parsec, -11. / 3., diff --git a/test/testOutput.cpp b/test/testOutput.cpp index a72d9ea27..3cf3d04be 100644 --- a/test/testOutput.cpp +++ b/test/testOutput.cpp @@ -40,7 +40,7 @@ TEST(CRPropa2EventOutput1D, removeProperty) { EXPECT_FALSE(c.hasProperty("Detected")); } -#ifdef MPC_HAVE_ROOT +#ifdef CRPROPA_HAVE_ROOT TEST(ROOTEventOutput3D, removeProperty) { ROOTEventOutput3D output(""); Candidate c; From 2d46aa2aecca8ab5bc77da1a5b5959ffae7622c5 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 25 Jun 2013 15:06:24 +0200 Subject: [PATCH 0316/1298] updated all python test and example scripts --- include/crpropa/Units.h | 6 +- test/python/testBoundaries.py | 52 ++--- test/python/testCosmology.py | 6 +- test/python/testDeflectionCK.py | 9 +- test/python/testElectronPairProduction.py | 5 +- test/python/testEnergyLossLength.py | 14 +- test/python/testJF12Field.py | 25 ++- test/python/testNuclearDecay.py | 5 +- test/python/testNuclearMass.py | 6 +- test/python/testPhotoDisintegration.py | 17 +- test/python/testPhotoPionProduction.py | 6 +- .../python/testPhotoPionProduction_pnRatio.py | 7 +- test/python/testSourceComposition.py | 17 +- test/python/testTurbulentDeflection.py | 23 +- test/python/testTurbulentFieldGrid.py | 201 ------------------ test/python/testTurbulentGrid.py | 78 +++++++ 16 files changed, 190 insertions(+), 287 deletions(-) delete mode 100644 test/python/testTurbulentFieldGrid.py create mode 100644 test/python/testTurbulentGrid.py diff --git a/include/crpropa/Units.h b/include/crpropa/Units.h index df95d56db..0c256ee04 100644 --- a/include/crpropa/Units.h +++ b/include/crpropa/Units.h @@ -1,5 +1,5 @@ -#ifndef UNITS_H -#define UNITS_H +#ifndef CRPROPA_UNITS_H +#define CRPROPA_UNITS_H namespace crpropa { @@ -68,4 +68,4 @@ static const double Gpc = gigaparsec; } // namespace crpropa -#endif /* UNITS_H */ +#endif // CRPROPA_UNITS_H diff --git a/test/python/testBoundaries.py b/test/python/testBoundaries.py index b534c79ba..141c944f9 100644 --- a/test/python/testBoundaries.py +++ b/test/python/testBoundaries.py @@ -1,6 +1,9 @@ -import pylab as pl -import matplotlib.patches as mpatches -from mpc import * +# CRPropa test script +# Tests and visualizes how periodic and reflective boundaries work. +# +from crpropa import * +from pylab import * +from matplotlib.patches import Rectangle p = ParticleState() @@ -8,25 +11,24 @@ p.setDirection(Vector3d(1,0.25,0)) N = 45 -x, y, sx, sy = pl.zeros((4,N)) +x, y, sx, sy = zeros((4,N)) - -# simulate periodic boundaries -m1 = ModuleList() -m1.add(SimplePropagation(0, 1)) -m1.add(PeriodicBox(Vector3d(-10), Vector3d(20))) +# Periodic boundaries +m = ModuleList() +m.add(SimplePropagation(0, 1)) +m.add(PeriodicBox(Vector3d(-10), Vector3d(20))) c = Candidate(p) for i in range(N): - m1.process(c) + m.process(c) pos = c.current.getPosition() x[i], y[i] = pos.x, pos.y - src = c.initial.getPosition() + src = c.source.getPosition() sx[i], sy[i] = src.x, src.y -pl.figure(figsize=(8,6)) -ax1 = pl.subplot(211, aspect='equal') -ax1.add_patch(mpatches.Rectangle((-10,-10), 20, 20, facecolor="lightskyblue")) +figure(figsize=(8,6)) +ax1 = subplot(211, aspect='equal') +ax1.add_patch(Rectangle((-10,-10), 20, 20, facecolor="lightskyblue")) ax1.plot(x, y, 'b.', ms=5) ax1.plot(sx, sy, 'r*', markeredgewidth=0, ms=10) ax1.set_xlim((-51, 31)) @@ -34,23 +36,21 @@ ax1.grid() ax1.set_title('Periodic Boundaries') - -# simulate reflective boundaries -m2 = ModuleList() -m2.add(SimplePropagation(0, 1)) -m2.add(ReflectiveBox(Vector3d(-10), Vector3d(20))) +# Reflective boundaries +m = ModuleList() +m.add(SimplePropagation(0, 1)) +m.add(ReflectiveBox(Vector3d(-10), Vector3d(20))) c = Candidate(p) - for i in range(N): - m2.process(c) + m.process(c) pos = c.current.getPosition() x[i], y[i] = pos.x, pos.y - src = c.initial.getPosition() + src = c.source.getPosition() sx[i], sy[i] = src.x, src.y -ax2 = pl.subplot(212, aspect='equal') -ax2.add_patch(mpatches.Rectangle((-10,-10), 20, 20, facecolor="lightskyblue")) +ax2 = subplot(212, aspect='equal') +ax2.add_patch(Rectangle((-10,-10), 20, 20, facecolor="lightskyblue")) ax2.plot(x, y, 'b.', ms=5) ax2.plot(sx, sy, 'r*', markeredgewidth=0, ms=10) ax2.set_xlim((-51, 31)) @@ -58,5 +58,5 @@ ax2.grid() ax2.set_title('Reflective Boundaries') -pl.savefig('Boundaries.png', bbox_inches='tight') -pl.show() +savefig('Boundaries.png', bbox_inches='tight') +show() diff --git a/test/python/testCosmology.py b/test/python/testCosmology.py index af31e16ef..43970cab3 100644 --- a/test/python/testCosmology.py +++ b/test/python/testCosmology.py @@ -1,5 +1,7 @@ -#!/usr/bin/env python -from mpc import * +# CRPropa test script +# Plots the different cosmological distance measures available in CRPropa. +# +from crpropa import * from pylab import * diff --git a/test/python/testDeflectionCK.py b/test/python/testDeflectionCK.py index 32ff11e55..fba47d24d 100644 --- a/test/python/testDeflectionCK.py +++ b/test/python/testDeflectionCK.py @@ -1,5 +1,8 @@ +# CRPropa test script +# Tests the accuracy of the Cash-Karp numerical integration method in CRPropa +# +from crpropa import * from pylab import * -from mpc import * # 100 EeV proton @@ -9,10 +12,10 @@ c.current.setDirection(Vector3d(1, 0, 0)) # uniform perpendicular magnetic field of 10 nG -field = UniformMagneticField(Vector3d(0,0,1e-12)) +field = UniformMagneticField(Vector3d(0, 0, 10 * nG)) # resulting gyroradius -R = c.current.getMomentum().getMag() / c.current.getCharge() / 1e-12 +R = c.current.getMomentum().getMag() / c.current.getCharge() / (10 * nG) def propagate(tolerance): diff --git a/test/python/testElectronPairProduction.py b/test/python/testElectronPairProduction.py index faa4239e8..728d1b560 100644 --- a/test/python/testElectronPairProduction.py +++ b/test/python/testElectronPairProduction.py @@ -1,4 +1,7 @@ -from mpc import * +# CRPRopa test script +# Plot and self consistency test for electron pair production. +# +from crpropa import * from pylab import * diff --git a/test/python/testEnergyLossLength.py b/test/python/testEnergyLossLength.py index de401bbc0..0b11c60b7 100644 --- a/test/python/testEnergyLossLength.py +++ b/test/python/testEnergyLossLength.py @@ -1,5 +1,8 @@ +# CRPRopa test script +# Shows how to use the energy loss length method, provided by the interaction modules +# +from crpropa import * from pylab import * -from mpc import * pd1 = PhotoDisintegration(CMB) pd2 = PhotoDisintegration(IRB) @@ -24,22 +27,17 @@ def parse_pid(pid): return 'Z=%i, A=%i'%((pid//10000)%1000, (pid%10000)/10) - pid = nucleusId(56, 26) - -E = logspace(1, 4) * EeV +E = logspace(1, 4, 50) L = zeros((3, 50)) -for i, energy in enumerate(E): +for i, energy in enumerate(E * EeV): L[0,i] = pdLoss(pid, energy) L[1,i] = ppLoss(pid, energy) L[2,i] = ep.energyLossLength(pid, energy) - -E /= EeV L /= Mpc - figure() plot(E, L[0], label='PDis') plot(E, L[1], label='PPion') diff --git a/test/python/testJF12Field.py b/test/python/testJF12Field.py index 63169b9fc..12ebaa5f6 100644 --- a/test/python/testJF12Field.py +++ b/test/python/testJF12Field.py @@ -1,25 +1,28 @@ -from mpc import * +# CRPropa test script +# Plots a sclice of the JF12 field +# +from crpropa import * from pylab import * from matplotlib.colors import LogNorm # Components of JF12 model -bField = JF2012Field() +# To plot also striated and/or turbulent component, remove the comment +bField = JF12Field() #bField.randomStriated() #bField.randomTurbulent() z = 0 # z position [kpc] of slice to plot -N = 241 # resolution in one direction +N = 241 # samples per direction +samples = (linspace(-20, 20, N, endpoint=True)) -lx = (linspace(-20, 20, N, endpoint=True)) -B, X, Y = zeros((3, N,N)) +B = zeros((N,N)) +X, Y = meshgrid(samples, samples) -for ix in range(N): - for iy in range(N): - b = bField.getField(Vector3d(lx[ix], lx[iy], z) * kpc) - B[ix, iy] = b.getMag() / gauss # B in [G] - X[ix, iy] = lx[ix] - Y[ix, iy] = lx[iy] +for i,x in enumerate(samples): + for j,y in enumerate(samples): + pos = Vector3d(x, y, z) * kpc + B[i, j] = bField.getField(pos).getMag() / gauss # B in [G] figure() maB = ma.masked_array(B, B==0) diff --git a/test/python/testNuclearDecay.py b/test/python/testNuclearDecay.py index 5fd0e2764..7138ed292 100644 --- a/test/python/testNuclearDecay.py +++ b/test/python/testNuclearDecay.py @@ -1,4 +1,7 @@ -from mpc import * +# CRPRopa test script +# Visualizes the nuclear decay tables in CRPropa +# +from crpropa import * from pylab import * from matplotlib.colors import LogNorm diff --git a/test/python/testNuclearMass.py b/test/python/testNuclearMass.py index e436db3c4..f0f6e11d1 100644 --- a/test/python/testNuclearMass.py +++ b/test/python/testNuclearMass.py @@ -1,6 +1,10 @@ -from mpc import * +# CRPRopa test script +# Visualizes the nuclear masses in CRPropa +# +from crpropa import * from pylab import * + D = zeros((27, 31)) D2 = zeros((27, 31)) diff --git a/test/python/testPhotoDisintegration.py b/test/python/testPhotoDisintegration.py index 57f045501..cd900e5ee 100644 --- a/test/python/testPhotoDisintegration.py +++ b/test/python/testPhotoDisintegration.py @@ -1,7 +1,13 @@ -from mpc import * +# CRPRopa test script +# Plot and self consistency check for photo disintegration +# +from crpropa import * from pylab import * +pid = nucleusId(4,2) # nucleus to test + + def get_rates(candidate, N=5000): # perform N interactions D = {} @@ -41,10 +47,6 @@ def parse_channel(channel): return s[0:-2] - -### nucleus to test -pid = nucleusId(4,2) - candidate = Candidate() candidate.current.setId(pid) @@ -62,7 +64,7 @@ def parse_channel(channel): Ddata = get_data_rates(pid) -# plot + for k in Dsim.keys(): figure() plot(gamma2, Dsim[k], 'k+') @@ -77,6 +79,3 @@ def parse_channel(channel): savefig('PhotoDisintegration_' + str(pid) + '_' + str(k) + '.png', bbox_inches='tight') show() - - - diff --git a/test/python/testPhotoPionProduction.py b/test/python/testPhotoPionProduction.py index eb6af8705..c289618ff 100644 --- a/test/python/testPhotoPionProduction.py +++ b/test/python/testPhotoPionProduction.py @@ -1,6 +1,10 @@ -from mpc import * +# CRPRopa test script +# Plot and self consistency check for photo pion production +# +from crpropa import * from pylab import * + def getRate(module, energy, charge): c = Candidate() c.current.setId(nucleusId(1, charge)) diff --git a/test/python/testPhotoPionProduction_pnRatio.py b/test/python/testPhotoPionProduction_pnRatio.py index 33f1996c5..be8791aba 100644 --- a/test/python/testPhotoPionProduction_pnRatio.py +++ b/test/python/testPhotoPionProduction_pnRatio.py @@ -1,9 +1,10 @@ -from mpc import * +# CRPRopa test script +# Simulate the p/n-ratio of the final baryon states in SOPHIA photo-pion interactions +# +from crpropa import * from pylab import * -# Simulate the p/n-ratio of the final baryon states in SOPHIA photo-pion interactions - spp = SophiaPhotoPionProduction() c = Candidate() s = InteractionState() diff --git a/test/python/testSourceComposition.py b/test/python/testSourceComposition.py index cd2a4e013..3c9fb4ece 100644 --- a/test/python/testSourceComposition.py +++ b/test/python/testSourceComposition.py @@ -1,13 +1,14 @@ -from mpc import * +# CRPropa test script +# Simulates the integrated relative abundance from a source, +# accelerationg particles up to a maximum rigidity. +# Minimum energy = 10 EeV +# Maximum rigidity = 100 EeV / Z -> max. energy = Z * 100 EeV +# Composition = p, He, C, O, Si, Fe with relative abundances +# from Allard 2006, DOI: 10.1088/1475-7516/2006/09/005 +# +from crpropa import * from pylab import * - -# Simulates the integrated relative abundance from a source that accelerates -# particles up to a maximum rigidity. -# min. energy = 10 EeV -# max. rigidity = 100 EeV / Z -> max. energy = Z * 100 EeV -# composition = p, He, C, O, Si, Fe with relative abundances from Allard 2006, DOI: 10.1088/1475-7516/2006/09/005 - nS = 5 # number of spectral indices between 2 and 3 nP = 5000 # number of particles per spectral index diff --git a/test/python/testTurbulentDeflection.py b/test/python/testTurbulentDeflection.py index 5dbaa36e2..982d81a78 100644 --- a/test/python/testTurbulentDeflection.py +++ b/test/python/testTurbulentDeflection.py @@ -1,4 +1,7 @@ -from mpc import * +# CRPropa test script +# Simulate the propagation through a turbulent field and compare to theoretical predictions +# +from crpropa import * from pylab import * @@ -7,18 +10,20 @@ nS = 50 # number of sampling points to simulate nP = range(30) # sampling points for plot -# create turbulent field with B_RMS = 1 nG and 0.5 Mpc correlation length +Lmin = 0.1 # Minimum turbulent scale +Lmax = 2.2 # Maximum turbulent scale +Lc = turbulentCorrelationLength(Lmin, Lmax) # coherence length in [Mpc] +Brms = 1 # RMS field strength sqrt() in [nG] +Rg = 1.08 * E / Brms # Gyroradius in [Mpc] + vGrid = VectorGrid(Vector3d(0, 0, 0), 128, 0.05 * Mpc) -initTurbulence(vGrid, 1 * nG, 0.1 * Mpc, 2.2 * Mpc) +initTurbulence(vGrid, Brms * nG, Lmin * Mpc, Lmax * Mpc) propa = DeflectionCK(MagneticFieldGrid(vGrid)) -Lc = turbulentCorrelationLength(0.1, 2.2) # in [Mpc] -Brms = 1 # nG -Rg = 1.08 * E / Brms # Mpc - age = linspace(1, 150, nS) distance, rms1, rms2 = zeros((3, nS)) +R = Random.instance() for j in range(nT): if j % (nT // 10) == 0: print j @@ -26,7 +31,7 @@ ps = ParticleState() ps.setId(nucleusId(1, 1)) ps.setEnergy(E * EeV) - ps.setDirection(Random.instance().randUnitVectorOnSphere()) + ps.setDirection(R.randVector()) ps.setPosition(Vector3d(0, 0, 0)) c = Candidate(ps) @@ -61,7 +66,7 @@ xlabel('Distance [Mpc]') ylabel('RMS(Deflection) [rad]') legend(loc='lower right', frameon=False) -s = 'Gyroradius $r_g=%.2f$ Mpc\nCorr. Length $L_c=%.2f$ Mpc'%(Rg, Lc) +s = 'Gyroradius $r_g=%.2f$ Mpc\nCoh. Length $L_c=%.2f$ Mpc'%(Rg, Lc) text(0.05, 0.95, s, ha='left', va='top', transform=gca().transAxes) savefig('TurbulentDeflection.png', bbox_inches='tight') diff --git a/test/python/testTurbulentFieldGrid.py b/test/python/testTurbulentFieldGrid.py deleted file mode 100644 index 3be52073a..000000000 --- a/test/python/testTurbulentFieldGrid.py +++ /dev/null @@ -1,201 +0,0 @@ -# evaluating functions for the turbulentField module -from pylab import * -from mpc import * - -def fftAutoCorrelation(a): - ''' - Two-point autocorrelation for an n-dimensional array of real input - ''' - b = rfftn(a) - return irfftn(b * b.conjugate()).real - -class VectorFieldAutoCorrelation(): - ''' - 2point-autocorrelation for a field of 3-vectors - ''' - def __init__(self, Bx, By, Bz): - self.n = shape(Bx)[0] - self.Rx = fftAutoCorrelation(Bx) - self.Ry = fftAutoCorrelation(By) - self.Rz = fftAutoCorrelation(Bz) - - def getCorrelationCurve(self, step=(1, 1, 1)): - ''' - returns the correlation curve in the direction of [step], summed over all field components - ''' - step = array(step) - # number of steps that can be walked accross the field - nSteps = int(self.n / 2 / max(abs(step))) - x = arange(0, nSteps) * norm(step) - y = zeros(nSteps) - for i in range(nSteps): - y[i] += self.Rx[ i * step[0], i * step[1], i * step[2] ] - y[i] += self.Ry[ i * step[0], i * step[1], i * step[2] ] - y[i] += self.Rz[ i * step[0], i * step[1], i * step[2] ] - y /= y[0] - return x, y - - def getIntegralLengthscale(self, step=(1, 1, 1)): - ''' - returns the integral lengthscale in the direction of [step] - ''' - x, y = self.getCorrelationCurve(step) - # use symmetry: Lc = \int_{-inf}^{inf} R/R_0 dx = 2*\int_{0}^{inf} R/R_0 dx - return (2 * sum(y[1:]) + y[0]) * norm(step) - -def fftESD(a): - ''' - Energy spectral density for an n-dimensional array - ''' - b = fftn(a) - return (b * conjugate(b)).real - -#def meanVectorFieldESD(Bx, By, Bz): -# ''' -# calculate the energy spectral density for an 3-dimensional Vector field -# ''' -# n = shape(Bx)[0] - -# E = fftEnergySpectralDensity(Bx) -# E += fftEnergySpectralDensity(By) -# E += fftEnergySpectralDensity(Bz) - -# k = fftfreq(n) -# kx, ky, kz = meshgrid(k, k, k) -# k2 = kx**2 + ky**2 + kz**2 - -# E.resize(n**3) -# k2.resize(n**3) -# dig = digitize(k2, ) - - - -### create field -origin = Vector3d(0,0,0) -n = 128 -spacing = 1 -lMin, lMax = 2, 32 -Brms = 1 -alpha = -11./3. -seed = 42 - -Lc = turbulentCorrelationLength(lMin, lMax, alpha) - -vGrid = VectorGrid(origin, n, spacing) -initTurbulence(vGrid, Brms, lMin, lMax, alpha, seed) - -### copy field grid to array(s) -Bx, By, Bz = zeros((3, n, n, n)) -for ix in range(n): - for iy in range(n): - for iz in range(n): - b = vGrid.get(ix, iy, iz) - Bx[ix, iy, iz] = b.x - By[ix, iy, iz] = b.y - Bz[ix, iy, iz] = b.z - -### plot slice in position space -figure(figsize=(8,6)) -A1 = (Bx[:,:,n/2]**2 + By[:,:,n/2]**2 + Bz[:,:,n/2]**2)**.5 -im = imshow(A1, origin='lower', extent=[0,n,0,n], vmin=0, vmax=3) -cbar = colorbar(im) -cbar.set_label('$B/B_{rms}$') -xlabel('$x$') -ylabel('$y$') -text(0.8, 1.05, '$z=%i$'%(n/2), transform=gca().transAxes) -savefig('TurbulentField_slicePositionSpace.png', bbox_inches='tight') - -### plot slice and periodical extension in position space -figure() -A2 = zeros((3*n,3*n)) -for i,j in ((0,1), (1,0), (1,1), (1,2), (2,1)): - A2[i*n:(i+1)*n, j*n:(j+1)*n] = A1 -im = imshow(ma.masked_array(A2, A2 == 0), origin='lower', extent=[-n,2*n,-n,2*n], vmin=0, vmax=3) -cbar = colorbar(im) -cbar.set_label(r'$|\vec{B_x}|/B_{rms}$') -xticks([-n, 0, n, 2*n]) -yticks([-n, 0, n, 2*n]) -xlabel('$x$') -ylabel('$y$') -text(0.8, 1.05, '$z=%i$'%(n/2), transform=gca().transAxes) -savefig('TurbulentField_slicePeriodicity.png', bbox_inches='tight') - -### plot slice in configuration space -figure() -Bkx = fftshift(fftn(Bx)) -Bky = fftshift(fftn(By)) -Bkz = fftshift(fftn(Bz)) -Bk = (((Bkx*Bkx.conjugate() + Bky*Bky.conjugate() + Bkz*Bkz.conjugate()).real)**.5) -im = imshow(log10(Bk[:,:,n/2]), origin='lower', vmin=0) -cbar = colorbar(im) -cbar.set_label(r'$\log_{10}(B/B_{rms})$') -xlabel('$k_x$') -ylabel('$k_y$') -k = fftshift(fftfreq(n)) -idx = arange(0, n, n/4) -xticks(idx, k[idx]) -yticks(idx, k[idx]) -xlim(0,n) -ylim(0,n) -text(0.8, 1.05, '$k_z=%.2f$'%k[n/2], transform=gca().transAxes) -savefig('TurbulentField_sliceConfigurationSpace.png', bbox_inches='tight') - -### plot (2pt-auto-)correlation curves for various directions -figure() -corr = VectorFieldAutoCorrelation(Bx,By,Bz) -Lcs = [] -steps = [] -for ix in arange(-2,3): - for iy in arange(-2,3): - for iz in arange(-2,3): - if ix == 0 and iy == 0 and iz == 0: - continue - if (-ix,-iy,-iz) in steps: - continue - step = (ix,iy,iz) - # steps.append(step) - Lcs.append( corr.getIntegralLengthscale(step) ) - x,y = corr.getCorrelationCurve(step) - plot(x,y,label=str(step)) -xlabel('Distance') -ylabel('Normalized Autocorrelation') -xlim(0,32) -grid() -s = 'Correlation Length\n Nominal %.2f\n Simulated %.2f $\pm$ %.2f'%(Lc, mean(Lcs), std(Lcs)/(len(Lcs))**.5) -text(0.5, 0.95, s, ha='left', va='top', transform=gca().transAxes) -savefig('TurbulentField_coherenceLength.png', bbox_inches='tight') - -#### plot energy spectrum -#figure() -#k, Ek = getVectorFieldEnergySpectralDensity(Bx, By, Bz) -#plot(k, Ek, label='Turbulent Spectrum') -#i = k.searchsorted(1./lMax) + 2 -#c = Ek[i]/k[i] -##plot(k, (c*k)**alpha, label='Slope $k^{-11/3}$') -#axvline(1./lMax, color='r', linestyle='--', label='$k_{min}=1/%.1f$'%lMax) -#axvline(1./lMin, color='r', linestyle='--', label='$k_{max}=1/%.1f$'%lMin) -#loglog() -#legend(loc='center left') -#xlabel('Wavenumber $k$') -#ylabel('Energy Spectral Density $E(k) [a.u.]$') -#grid() -#savefig('TurbulentField_spectrum.png', bbox_inches='tight') - -### plot histogram of field strengths -figure() -Bx.resize(n**3) -By.resize(n**3) -Bz.resize(n**3) -hist(log10(Bx), bins=40, range=(-3,3), histtype='step', normed=True, label='$B_x$', linewidth=2) -hist(log10(By), bins=40, range=(-3,3), histtype='step', normed=True, label='$B_y$', linewidth=2) -hist(log10(Bz), bins=40, range=(-3,3), histtype='step', normed=True, label='$B_z$', linewidth=2) -legend() -grid() -xlabel('$B/B_{RMS}$') -ylabel('Frequency') -brms = (mean( Bx**2 + By**2 + Bz**2 ))**.5 -bmean = abs(mean(Bx + By + Bz)) -text(0.95, 0.7, '$RMS$ = %.2f\nMean = %.2f'%(brms, bmean), ha='right', va='top', transform=gca().transAxes) -savefig('TurbulentField_amplitude.png', bbox_inches='tight') - -show() diff --git a/test/python/testTurbulentGrid.py b/test/python/testTurbulentGrid.py new file mode 100644 index 000000000..efea22333 --- /dev/null +++ b/test/python/testTurbulentGrid.py @@ -0,0 +1,78 @@ +# CRPropa test script +# Evaluates and plots the turbulent fields generated by CRPropa +# +from crpropa import * +from pylab import * + + +# Create turbulent field +origin = Vector3d(0,0,0) +n = 128 +spacing = 1 +lMin, lMax = 2, 32 +Brms = 1 +alpha = -11./3. +seed = 42 +Lc = turbulentCorrelationLength(lMin, lMax, alpha) +vGrid = VectorGrid(origin, n, spacing) +initTurbulence(vGrid, Brms, lMin, lMax, alpha, seed) + +# Copy field grid to array(s) +Bx, By, Bz = zeros((3, n, n, n)) +for ix in range(n): + for iy in range(n): + for iz in range(n): + b = vGrid.get(ix, iy, iz) + Bx[ix, iy, iz] = b.x + By[ix, iy, iz] = b.y + Bz[ix, iy, iz] = b.z + +# Plot slice in position space +figure(figsize=(8,6)) +A1 = (Bx[:,:,n/2]**2 + By[:,:,n/2]**2 + Bz[:,:,n/2]**2)**.5 +im = imshow(A1, origin='lower', extent=[0,n,0,n], vmin=0, vmax=3) +cbar = colorbar(im) +cbar.set_label('$B/B_{rms}$') +xlabel('$x$') +ylabel('$y$') +text(0.8, 1.05, '$z=%i$'%(n/2), transform=gca().transAxes) +savefig('TurbulentGrid_slicePositionSpace.png', bbox_inches='tight') + +# Plot slice in configuration space +figure() +Bkx = fftshift(fftn(Bx)) +Bky = fftshift(fftn(By)) +Bkz = fftshift(fftn(Bz)) +Bk = (((Bkx*Bkx.conjugate() + Bky*Bky.conjugate() + Bkz*Bkz.conjugate()).real)**.5) +im = imshow(log10(Bk[:,:,n/2]), origin='lower', vmin=0) +cbar = colorbar(im) +cbar.set_label(r'$\log_{10}(B/B_{rms})$') +xlabel('$k_x$') +ylabel('$k_y$') +k = fftshift(fftfreq(n)) +idx = arange(0, n, n/4) +xticks(idx, k[idx]) +yticks(idx, k[idx]) +xlim(0,n) +ylim(0,n) +text(0.8, 1.05, '$k_z=%.2f$'%k[n/2], transform=gca().transAxes) +savefig('TurbulentGrid_sliceConfigurationSpace.png', bbox_inches='tight') + +# Histogram of field strengths +figure() +Bx.resize(n**3) +By.resize(n**3) +Bz.resize(n**3) +hist(log10(Bx), bins=40, range=(-3,3), histtype='step', normed=True, label='$B_x$', linewidth=2) +hist(log10(By), bins=40, range=(-3,3), histtype='step', normed=True, label='$B_y$', linewidth=2) +hist(log10(Bz), bins=40, range=(-3,3), histtype='step', normed=True, label='$B_z$', linewidth=2) +legend() +grid() +xlabel('$\log_{10}(B/B_{RMS}$)') +ylabel('Rel. Frequency') +brms = (mean( Bx**2 + By**2 + Bz**2 ))**.5 +bmean = abs(mean(Bx + By + Bz)) +text(0.95, 0.7, 'RMS = %.2f\nMean = %.2f'%(brms, bmean), ha='right', va='top', transform=gca().transAxes) +savefig('TurbulentGrid_amplitude.png', bbox_inches='tight') + +show() From 66f0639ad005465e144b0c8b8b3d26eb0a41c3f1 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 28 Jun 2013 11:48:28 +0200 Subject: [PATCH 0317/1298] add empty data folder --- include/crpropa/Clock.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/crpropa/Clock.h b/include/crpropa/Clock.h index caebac8ae..fb270e0c5 100644 --- a/include/crpropa/Clock.h +++ b/include/crpropa/Clock.h @@ -20,4 +20,5 @@ class Clock { }; } // namespace crpropa + #endif // CRPROPA_CLOCK_H From 3613eda0fd0d5208e26561b8ab940879578b431d Mon Sep 17 00:00:00 2001 From: geromueller Date: Mon, 1 Jul 2013 08:57:50 +0200 Subject: [PATCH 0318/1298] fix ref_ptr usage --- src/XmlExecute.cpp | 52 +++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 59d23c14c..65e42a8e3 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -52,7 +52,7 @@ xml_node childNode(xml_node parent, string childName, return node; } -SourceUniformBox* loadSourceHomogeneousBox(pugi::xml_node &node) { +ref_ptr loadSourceHomogeneousBox(pugi::xml_node &node) { Vector3d origin; origin.x = childValue(node, "Xmin_Mpc") * Mpc; origin.y = childValue(node, "Ymin_Mpc") * Mpc; @@ -69,7 +69,7 @@ SourceUniformBox* loadSourceHomogeneousBox(pugi::xml_node &node) { return (new SourceUniformBox(origin, size)); } -SourceDensityGrid* loadSourceDensityGrid(pugi::xml_node &node) { +ref_ptr loadSourceDensityGrid(pugi::xml_node &node) { int nx = childValue(node, "Nx"); int ny = childValue(node, "Ny"); int nz = childValue(node, "Nz"); @@ -85,7 +85,7 @@ SourceDensityGrid* loadSourceDensityGrid(pugi::xml_node &node) { origin.z = childValue(origin_node, "Z_Mpc") * Mpc; cout << " - Origin = " << origin / Mpc << " Mpc" << endl; - ScalarGrid* grid = new ScalarGrid(origin, nx, ny, nz, spacing); + ref_ptr grid = new ScalarGrid(origin, nx, ny, nz, spacing); xml_node file_node = childNode(node, "File"); string file_type = file_node.attribute("type").as_string(); @@ -101,14 +101,15 @@ SourceDensityGrid* loadSourceDensityGrid(pugi::xml_node &node) { return (new SourceDensityGrid(grid)); } -SourceDensityGrid1D* loadSourceDensityGrid1D(pugi::xml_node &node) { +ref_ptr loadSourceDensityGrid1D(pugi::xml_node &node) { int nx = childValue(node, "Nx"); cout << " - Nx = " << nx << endl; double spacing = childValue(node, "Step_Mpc") * Mpc; cout << " - Spacing = " << spacing / Mpc << " Mpc" << endl; - ScalarGrid* grid = new ScalarGrid(Vector3d(0, 0, 0), nx, 1, 1, spacing); + ref_ptr grid = new ScalarGrid(Vector3d(0, 0, 0), nx, 1, 1, + spacing); xml_node file_node = childNode(node, "File"); string file_type = file_node.attribute("type").as_string(); @@ -479,7 +480,8 @@ void XmlExecute::loadSpheresAroundSource(pugi::xml_node &node) { } void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { - SourceMultiplePositions* sourcePositions = new SourceMultiplePositions(); + ref_ptr sourcePositions = + new SourceMultiplePositions(); xml_node density_node = node.child("Density"); if (density_node) { // draw positions from density distribution @@ -489,7 +491,7 @@ void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { int nSources = childValue(node, "Number"); cout << " - Number = " << nSources << endl; - SourceProperty* sourceDistribution = new SourceProperty(); + ref_ptr sourceDistribution = new SourceProperty(); if (type == "Uniform") { if (is1D) { double xmin = childValue(density_node, "Xmin_Mpc") * Mpc; @@ -515,13 +517,12 @@ void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { cout << " - Position = " << p.getPosition() / Mpc << " Mpc" << endl; } - delete sourceDistribution; } else { // read individual positions from xml for (xml_node n = node.child("PointSource"); n; n = n.next_sibling("PointSource")) { Vector3d pos(0.); pos.x = childValue(n, "CoordX_Mpc") * Mpc; - if (not(is1D)) { + if (not (is1D)) { pos.y = childValue(n, "CoordY_Mpc") * Mpc; pos.z = childValue(n, "CoordZ_Mpc") * Mpc; } @@ -540,8 +541,10 @@ void XmlExecute::loadContinuousSources(pugi::xml_node &node) { if (is1D) { double minD = childValue(density_node, "Xmin_Mpc") * Mpc; double maxD = childValue(density_node, "Xmax_Mpc") * Mpc; - cout << " - Minimum light travel distance: " << minD / Mpc << " Mpc" << endl; - cout << " - Maximum light travel distance: " << maxD / Mpc << " Mpc" << endl; + cout << " - Minimum light travel distance: " << minD / Mpc + << " Mpc" << endl; + cout << " - Maximum light travel distance: " << maxD / Mpc + << " Mpc" << endl; minD = lightTravel2ComovingDistance(minD); maxD = lightTravel2ComovingDistance(maxD); source.addProperty(new SourceUniform1D(minD, maxD)); @@ -585,7 +588,8 @@ void XmlExecute::loadSpectrumComposition(pugi::xml_node &node) { cout << " - Maximum rigidity: " << Rmax / EeV << " EeV" << endl; // combined source spectrum / composition - SourceComposition *comp = new SourceComposition(Emin, Rmax, alpha); + ref_ptr comp = new SourceComposition(Emin, Rmax, + alpha); xml_node p = node.child("Particles"); for (xml_node n = p.child("Species"); n; n = n.next_sibling("Species")) { @@ -616,7 +620,7 @@ void XmlExecute::loadSpectrumComposition(pugi::xml_node &node) { } void XmlExecute::loadSourceNuclei(pugi::xml_node &node) { - SourceMultipleParticleTypes *composition = + ref_ptr composition = new SourceMultipleParticleTypes(); xml_node p = node.child("Particles"); for (xml_node n = p.child("Species"); n; n = n.next_sibling("Species")) { @@ -668,20 +672,20 @@ void XmlExecute::loadOutput(xml_node &node) { #ifdef CRPROPA_HAVE_ROOT else if (format == "ROOT") { if (type == "Full Trajectories") - if (is1D) - modules.add(new ROOTTrajectoryOutput1D(filename)); - else - modules.add(new ROOTTrajectoryOutput3D(filename)); + if (is1D) + modules.add(new ROOTTrajectoryOutput1D(filename)); + else + modules.add(new ROOTTrajectoryOutput3D(filename)); else if (type == "Events") - if (is1D) - modules.add(new ROOTEventOutput1D(filename)); - else - modules.add(new ROOTEventOutput3D(filename)); + if (is1D) + modules.add(new ROOTEventOutput1D(filename)); + else + modules.add(new ROOTEventOutput3D(filename)); else if (type == "None") - return; + return; else - cout << " --> unknown output type " - << "('Events', 'Full Trajectories' or 'None')" << endl; + cout << " --> unknown output type " + << "('Events', 'Full Trajectories' or 'None')" << endl; } #endif // CRPROPA_HAVE_ROOT else { From e1b3bfe906a366ca9fe9139f4255b9e483a13e71 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 3 Jul 2013 07:51:38 +0200 Subject: [PATCH 0319/1298] trim whitespaces in filenames in xml steering --- include/crpropa/Grid.h | 2 +- include/crpropa/ParticleID.h | 2 +- libs/kiss/include/kiss/string.h | 4 +++- libs/kiss/src/string.cpp | 8 +++----- src/XmlExecute.cpp | 3 ++- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/include/crpropa/Grid.h b/include/crpropa/Grid.h index 8f03e27ab..b3df58c16 100644 --- a/include/crpropa/Grid.h +++ b/include/crpropa/Grid.h @@ -215,4 +215,4 @@ typedef Grid ScalarGrid; } // namespace crpropa -#endif /* CRPROPA_GRID_H */ +#endif // CRPROPA_GRID_H diff --git a/include/crpropa/ParticleID.h b/include/crpropa/ParticleID.h index 378ad01bf..7adec8d77 100644 --- a/include/crpropa/ParticleID.h +++ b/include/crpropa/ParticleID.h @@ -26,4 +26,4 @@ int convertToCRPropaId(int id); } // namespace crpropa -#endif /* CRPROPA_PARTICLE_ID_H */ +#endif // CRPROPA_PARTICLE_ID_H diff --git a/libs/kiss/include/kiss/string.h b/libs/kiss/include/kiss/string.h index 695b9c6b9..ba495949c 100644 --- a/libs/kiss/include/kiss/string.h +++ b/libs/kiss/include/kiss/string.h @@ -7,10 +7,12 @@ namespace kiss { +#define SPACES " \t\r\n" + std::string trim_right(const std::string &s, const std::string &t); std::string trim_left(const std::string &s, const std::string &t); -std::string trim(const std::string &s, const std::string &t); +std::string trim(const std::string &s, const std::string &t = SPACES); void explode(const std::string &s, std::vector &v, const bool trim_spaces, const std::string &t); std::string implode(const std::vector &v, const std::string &t); diff --git a/libs/kiss/src/string.cpp b/libs/kiss/src/string.cpp index 3d79c54df..b1aab0549 100644 --- a/libs/kiss/src/string.cpp +++ b/libs/kiss/src/string.cpp @@ -6,8 +6,6 @@ namespace kiss { -#define SPACES " \t\r\n" - std::string trim_right(const std::string &s, const std::string &t) { std::string::size_type i(s.find_last_not_of(t)); @@ -21,9 +19,9 @@ std::string trim_left(const std::string &s, const std::string &t) { return std::string(s, s.find_first_not_of(t)); } -std::string trim(const std::string &s, const std::string &t = SPACES) { - std::string::size_type a = s.find_first_not_of(t), b = s.find_last_not_of( - t); +std::string trim(const std::string &s, const std::string &t) { + std::string::size_type a = s.find_first_not_of(t); + std::string::size_type b = s.find_last_not_of(t); if (a == std::string::npos || b == std::string::npos) return ""; diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 65e42a8e3..72ccc37b6 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -20,6 +20,7 @@ #include "crpropa/ModuleList.h" #include "pugixml.hpp" +#include "kiss/string.h" #include #include @@ -642,7 +643,7 @@ void XmlExecute::loadOutput(xml_node &node) { string format = file_node.attribute("type").as_string(); cout << " - Filetype: " << format << endl; - string filename = node.child("File").child_value(); + string filename = kiss::trim( node.child("File").child_value() ); cout << " - Filename: " << filename << endl; string option = node.child("File").attribute("option").as_string(); From 422e2b2ed107ced6b275312a10fc504336536e26 Mon Sep 17 00:00:00 2001 From: geromueller Date: Thu, 4 Jul 2013 15:32:51 +0200 Subject: [PATCH 0320/1298] add threadsafe seeding --- include/crpropa/Random.h | 3 ++- src/ModuleList.cpp | 4 ++-- src/Random.cpp | 21 +++++++++++++++------ src/XmlExecute.cpp | 3 +-- test/xml/1D.xml | 4 ++-- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/include/crpropa/Random.h b/include/crpropa/Random.h index dc60bc259..5a2de0c41 100644 --- a/include/crpropa/Random.h +++ b/include/crpropa/Random.h @@ -166,7 +166,8 @@ class Random { friend std::istream& operator>>( std::istream& is, Random& mtrand ); static Random &instance(); - + static void seedThreads(const uint32 oneSeed); + protected: /// Initialize generator state with seed /// See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier. diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 0c11ef268..49c892aaa 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -68,7 +68,7 @@ void ModuleList::run(candidate_vector_t &candidates, bool recursive) { sighandler_t old_signal_handler = ::signal(SIGINT, g_cancel_signal_callback); -#pragma omp parallel for schedule(dynamic, 1000) +#pragma omp parallel for schedule(static, 1000) for (size_t i = 0; i < count; i++) { if (!g_cancel_signal_flag) run(candidates[i], recursive); @@ -97,7 +97,7 @@ void ModuleList::run(Source *source, size_t count, bool recursive) { sighandler_t old_signal_handler = ::signal(SIGINT, g_cancel_signal_callback); -#pragma omp parallel for schedule(dynamic, 1000) +#pragma omp parallel for schedule(static, 1000) for (size_t i = 0; i < count; i++) { ref_ptr candidate = source->getCandidate(); if (!g_cancel_signal_flag) diff --git a/src/Random.cpp b/src/Random.cpp index a791e05d1..8e8602ae5 100644 --- a/src/Random.cpp +++ b/src/Random.cpp @@ -388,21 +388,30 @@ struct RANDOM_TLS_ITEM { char padding[80*64 - sizeof(Random)]; }; -Random &Random::instance() { #ifdef _MSC_VER - __declspec(align(64)) static RANDOM_TLS_ITEM tls[MAX_THREAD]; + __declspec(align(64)) static RANDOM_TLS_ITEM _tls[MAX_THREAD]; #else - __attribute__ ((aligned(64))) static RANDOM_TLS_ITEM tls[MAX_THREAD]; + __attribute__ ((aligned(64))) static RANDOM_TLS_ITEM _tls[MAX_THREAD]; #endif + +Random &Random::instance() { int i = omp_get_thread_num(); if (i >= MAX_THREAD) throw std::runtime_error("crpropa::Random: more than MAX_THREAD threads!"); - return tls[i].r; + return _tls[i].r; +} + +void Random::seedThreads(const uint32 oneSeed) { + for(size_t i = 0; i < MAX_THREAD; ++i) + _tls[i].r.seed(oneSeed + i); } #else +static Random _random; Random &Random::instance() { - static Random r; - return r; + return _random; +} +void Random::seedThreads(const uint32 oneSeed) { + _random.seed(oneSeed); } #endif diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 72ccc37b6..d6d5c3dd7 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -152,8 +152,7 @@ bool XmlExecute::load(const string &filename) { xml_node seed_node = root.child("RandomSeed"); if (seed_node) { int seed = seed_node.attribute("value").as_int(); - Random &random = Random::instance(); - random.seed(seed); + Random::seedThreads(seed); cout << "Random seed: " << seed << endl; } else cout << "No random seed given. Using random random seed." << endl; diff --git a/test/xml/1D.xml b/test/xml/1D.xml index 5ac857ca7..43f08cfa3 100644 --- a/test/xml/1D.xml +++ b/test/xml/1D.xml @@ -1,9 +1,9 @@ - + - + From 9e877f13823f520f324aa015b56686d30bd281f3 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 5 Jul 2013 15:43:14 +0200 Subject: [PATCH 0321/1298] Redshift::getDescription outputs cosmology parameters --- include/crpropa/Source.h | 15 ++++++++++----- include/crpropa/module/Redshift.h | 2 +- src/module/Redshift.cpp | 11 +++++++---- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/include/crpropa/Source.h b/include/crpropa/Source.h index 69462b485..b817cc07f 100644 --- a/include/crpropa/Source.h +++ b/include/crpropa/Source.h @@ -191,6 +191,10 @@ class SourceUniformBox: public SourceProperty { Vector3d origin; Vector3d size; public: + /** Constructor + @param origin lower box corner + @param size upper box corner + */ SourceUniformBox(Vector3d origin, Vector3d size); void prepare(ParticleState &particle) const; }; @@ -205,13 +209,14 @@ class SourceUniformBox: public SourceProperty { converting to a comoving distance. */ class SourceUniform1D: public SourceProperty { - double minD; // minimum light travel distance [m] - double maxD; // maximum light travel distance [m] + double minD; // minimum light travel distance + double maxD; // maximum light travel distance bool withCosmology; public: - /** - @param minD minimum comoving distance [m] - @param maxD maximum comoving distance [m] + /** Constructor + @param minD minimum comoving distance + @param maxD maximum comoving distance + @param withCosmology specify if universe expanding */ SourceUniform1D(double minD, double maxD, bool withCosmology=true); void prepare(ParticleState& particle) const; diff --git a/include/crpropa/module/Redshift.h b/include/crpropa/module/Redshift.h index 647d89ed9..96f06d42c 100644 --- a/include/crpropa/module/Redshift.h +++ b/include/crpropa/module/Redshift.h @@ -11,8 +11,8 @@ namespace crpropa { */ class Redshift: public Module { public: - Redshift(); void process(Candidate *candidate) const; + std::string getDescription() const; }; } // namespace crpropa diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index 90bbd2f08..4012b858d 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -3,10 +3,6 @@ namespace crpropa { -Redshift::Redshift() { - setDescription("Redshift"); -} - void Redshift::process(Candidate *c) const { double z = c->getRedshift(); if (z == 0) @@ -23,4 +19,11 @@ void Redshift::process(Candidate *c) const { c->current.setEnergy(E * (1 - dz / (1 + z))); } +std::string Redshift::getDescription() const { + std::stringstream s; + s << "Redshift: h0 = " << hubbleRate() / 1e5 * Mpc << ", omegaL = " + << omegaL() << ", omegaM = " << omegaM(); + return s.str(); +} + } // namespace crpropa From df37f5e59457019a0c84b983a8b944db045ef6d0 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 10 Jul 2013 13:08:29 +0200 Subject: [PATCH 0322/1298] Fix redshift falling below 0. Add unit test. --- include/crpropa/ModuleList.h | 2 +- src/module/Redshift.cpp | 9 +++++++-- test/testInteraction.cpp | 23 ++++++++++++++++++----- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/include/crpropa/ModuleList.h b/include/crpropa/ModuleList.h index 72fd247de..3a2532fa2 100644 --- a/include/crpropa/ModuleList.h +++ b/include/crpropa/ModuleList.h @@ -43,4 +43,4 @@ class ModuleList: public Referenced { std::ostream &operator<<(std::ostream &out, const crpropa::ModuleList &list); -#endif /* CRPROPA_MODULE_LIST_H */ +#endif // CRPROPA_MODULE_LIST_H diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index 4012b858d..ef2775cdd 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -1,16 +1,21 @@ #include "crpropa/module/Redshift.h" #include "crpropa/Cosmology.h" +#include + namespace crpropa { void Redshift::process(Candidate *c) const { double z = c->getRedshift(); - if (z == 0) + if (z <= 0) return; // nothing to do, redshift can't get smaller - // use small redshift approximation: dz = H(z) / c * dr + // use small step approximation: dz = H(z) / c * ds double dz = hubbleRate(z) / c_light * c->getCurrentStep(); + // prevent dz > z + dz = std::min(dz, z); + // update redshift c->setRedshift(z - dz); diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 911da4d9f..38899b8a6 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -572,17 +572,30 @@ TEST(SophiaPhotoPionProduction, belowSophiaEnergyThreshold_IRB) { EXPECT_FALSE(hasInteraction); } -TEST(Redshift, test) { +TEST(Redshift, simpleTest) { + // Test if redshift is decreased and adiabatic energy loss is applied. Redshift redshift; Candidate c; - c.setRedshift(0.024); // roughly corresponds to 100 Mpc + c.setRedshift(0.024); c.current.setEnergy(100 * EeV); - c.setCurrentStep(100 * Mpc); + c.setCurrentStep(1 * Mpc); + + redshift.process(&c); + EXPECT_GT(0.024, c.getRedshift()); // expect redshift decrease + EXPECT_GT(100, c.current.getEnergy() / EeV); // expect energy loss +} + +TEST(Redshift, limitRedshiftDecrease) { + // Test if the redshift decrease is limited to z_updated >= 0. + Redshift redshift; + + Candidate c; + c.setRedshift(0.024); // roughly corresponds to 100 Mpc + c.setCurrentStep(150 * Mpc); redshift.process(&c); - EXPECT_GT(0.024, c.getRedshift()); - EXPECT_GT(100, c.current.getEnergy() / EeV); + EXPECT_DOUBLE_EQ(0, c.getRedshift()); } int main(int argc, char **argv) { From 13f0cdb2c536453b6671ed1e3df2a81cbe892725 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 11 Jul 2013 07:39:57 +0200 Subject: [PATCH 0323/1298] Add NoIRO flag in XML steering --- .hgignore | 1 + src/XmlExecute.cpp | 61 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/.hgignore b/.hgignore index 3a1cf0d41..d9fa5e0dc 100644 --- a/.hgignore +++ b/.hgignore @@ -8,4 +8,5 @@ syntax: regexp ^\.cproject$ ^\.project$ ^data/.*$ +^data-tools/.*$ diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index d6d5c3dd7..9c07fc72f 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -412,29 +412,62 @@ void XmlExecute::loadPeriodicBoundaries() { } void XmlExecute::loadSophia(xml_node &node) { - if (node.child("NoPairProd")) + bool pairprodCMB = true; + bool pairprodIRB = true; + bool pionprodCMB = true; + bool pionprodIRB = true; + bool photodisCMB = true; + bool photodisIRB = true; + bool decay = true; + + if (node.child("NoPairProd")) { cout << " - No pair production" << endl; - else - modules.add(new ElectronPairProduction(CMB_IRB)); - + pairprodCMB = false; + pairprodIRB = false; + } if (node.child("NoPionProd")) { cout << " - No pion production" << endl; - } else { - modules.add(new SophiaPhotoPionProduction(CMB)); - if (!node.child("NoIRPionProd")) - modules.add(new SophiaPhotoPionProduction(IRB)); + pionprodCMB = false; + pionprodIRB = false; } - if (node.child("NoPhotodisintegration")) { cout << " - No photo disintegration" << endl; - } else { - modules.add(new PhotoDisintegration(CMB)); - modules.add(new PhotoDisintegration(IRB)); + photodisCMB = false; + photodisIRB = false; } - - if (node.child("NoDecay")) + if (node.child("NoIRO")) { + cout << " - No interactions on IRB" << endl; + pairprodIRB = false; + pionprodIRB = false; + photodisIRB = false; + } + if (node.child("NoIRPionProd")) { + cout << " - No pion production on IRB" << endl; + pionprodIRB = false; + } + if (node.child("NoDecay")) { cout << " - No decay" << endl; + decay = false; + } + + if (pairprodCMB and pairprodIRB) + modules.add(new ElectronPairProduction(CMB_IRB)); else + if (pairprodCMB) + modules.add(new ElectronPairProduction(CMB)); + + if (pionprodCMB) + modules.add(new SophiaPhotoPionProduction(CMB)); + if (pionprodIRB) + modules.add(new SophiaPhotoPionProduction(IRB)); + + if (photodisCMB and photodisIRB) + modules.add(new PhotoDisintegration(CMB_IRB)); + else + if (photodisCMB) + modules.add(new PhotoDisintegration(CMB)); + + if (decay) modules.add(new NuclearDecay); } From 1be743c9a60710a124b2debb3fef4ee36cdb1080 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 11 Jul 2013 07:45:30 +0200 Subject: [PATCH 0324/1298] Add output of active modules to xmlrun --- src/XmlExecute.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 9c07fc72f..2bd9aec6c 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -728,7 +728,8 @@ void XmlExecute::loadOutput(xml_node &node) { } void XmlExecute::run() { -//operator <<(cout, modules); + cout << endl << "Active modules:" << endl; + modules.showModules(); modules.setShowProgress(true); modules.run(&source, nTrajectories, true); } From 6ebac2780900272411b6e15ca5d3ab27821359d5 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 12 Jul 2013 10:54:56 +0200 Subject: [PATCH 0325/1298] fix xml-steering bug: 1D source discrete source distances are now interpreted as light travel distances --- src/XmlExecute.cpp | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 2bd9aec6c..3d2765694 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -109,6 +109,9 @@ ref_ptr loadSourceDensityGrid1D(pugi::xml_node &node) { double spacing = childValue(node, "Step_Mpc") * Mpc; cout << " - Spacing = " << spacing / Mpc << " Mpc" << endl; + // convert to comoving spacing + spacing = lightTravel2ComovingDistance(spacing); + ref_ptr grid = new ScalarGrid(Vector3d(0, 0, 0), nx, 1, 1, spacing); @@ -517,12 +520,12 @@ void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { new SourceMultiplePositions(); xml_node density_node = node.child("Density"); - if (density_node) { // draw positions from density distribution + if (density_node) { + // draw positions from density distribution string type = density_node.attribute("type").as_string(); cout << " - Density: " << type << endl; - int nSources = childValue(node, "Number"); - cout << " - Number = " << nSources << endl; + cout << " - Number of sources = " << nSources << endl; ref_ptr sourceDistribution = new SourceProperty(); if (type == "Uniform") { @@ -550,16 +553,23 @@ void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { cout << " - Position = " << p.getPosition() / Mpc << " Mpc" << endl; } - } else { // read individual positions from xml + } else { + // loop over point sources for (xml_node n = node.child("PointSource"); n; n = n.next_sibling("PointSource")) { Vector3d pos(0.); - pos.x = childValue(n, "CoordX_Mpc") * Mpc; - if (not (is1D)) { + if (is1D) { + // 1D + double dlt = childValue(n, "CoordX_Mpc") * Mpc; + pos.x = lightTravel2ComovingDistance(dlt); + cout << " - Light travel distance = " << dlt << " Mpc" << endl; + } else { + // 3D + pos.x = childValue(n, "CoordX_Mpc") * Mpc; pos.y = childValue(n, "CoordY_Mpc") * Mpc; pos.z = childValue(n, "CoordZ_Mpc") * Mpc; + cout << " - Position = " << pos / Mpc << " Mpc" << endl; } - cout << " - Position " << pos / Mpc << " Mpc" << endl; sourcePositions->add(pos); } } @@ -686,21 +696,22 @@ void XmlExecute::loadOutput(xml_node &node) { } if (format == "ASCII") { - if (type == "Full Trajectories") + if (type == "Full Trajectories") { if (is1D) modules.add(new CRPropa2TrajectoryOutput1D(filename)); else modules.add(new CRPropa2TrajectoryOutput3D(filename)); - else if (type == "Events") + } else if (type == "Events") { if (is1D) modules.add(new CRPropa2EventOutput1D(filename)); else modules.add(new CRPropa2EventOutput3D(filename)); - else if (type == "None") + } else if (type == "None") { return; - else + } else { cout << " --> unknown output type " << "('Events', 'Full Trajectories' or 'None')" << endl; + } } #ifdef CRPROPA_HAVE_ROOT else if (format == "ROOT") { From bd7589eb1b1ff62555bafce34ee86437751f0838 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 26 Jul 2013 16:45:08 +0200 Subject: [PATCH 0326/1298] changed "Time (Mpc)" to light travel distance in CRPropa2Output modules --- src/module/OutputCRPropa2.cpp | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/module/OutputCRPropa2.cpp b/src/module/OutputCRPropa2.cpp index 0d93ff507..cd035f0ca 100644 --- a/src/module/OutputCRPropa2.cpp +++ b/src/module/OutputCRPropa2.cpp @@ -1,4 +1,5 @@ #include "crpropa/module/OutputCRPropa2.h" +#include "crpropa/Cosmology.h" namespace crpropa { @@ -6,10 +7,13 @@ CRPropa2EventOutput3D::CRPropa2EventOutput3D(std::string filename) { setDescription("Event output in CRPropa2 format"); outfile.open(filename.c_str()); outfile << "#CRPropa - Output data file\n" - << "#Format - Particle_Type Initial_Particle_Type " + << "#Format - Particle_Type " + << "Initial_Particle_Type " << "Initial_Position[X,Y,Z](Mpc) " << "Initial_Momentum[E(EeV),theta,phi] " - << "Time(Mpc) Position[X,Y,Z](Mpc) Momentum[E(EeV),theta,phi]\n"; + << "Time(Mpc, light travel distance) " + << "Position[X,Y,Z](Mpc) " + << "Momentum[E(EeV),theta,phi]\n"; } CRPropa2EventOutput3D::~CRPropa2EventOutput3D() { @@ -37,7 +41,7 @@ void CRPropa2EventOutput3D::process(Candidate *c) const { double iE = c->source.getEnergy() / EeV; p += sprintf(buffer + p, "%.4f %.4f %.4f ", iE, iPhi, iTheta); - double t = c->getTrajectoryLength() / Mpc; + double t = comoving2LightTravelDistance(c->getTrajectoryLength()) / Mpc; p += sprintf(buffer + p, "%.4f ", t); const Vector3d &pos = c->current.getPosition() / Mpc; @@ -59,8 +63,12 @@ CRPropa2TrajectoryOutput3D::CRPropa2TrajectoryOutput3D(std::string filename) { setDescription("Trajectory output in CRPropa2 format"); outfile.open(filename.c_str()); outfile << "#CRPropa - Output data file\n" - << "#Format - Particle_Type Initial_Particle_Type Time(Mpc) " - << "Position[X,Y,Z](Mpc) Momentum[X(EeV),Y,Z] Energy(EeV)\n"; + << "#Format - Particle_Type " + << "Initial_Particle_Type " + << "Time(Mpc, light travel distance) " + << "Position[X,Y,Z](Mpc) " + << "Momentum[X(EeV),Y,Z] " + << "Energy(EeV)\n"; } CRPropa2TrajectoryOutput3D::~CRPropa2TrajectoryOutput3D() { @@ -73,7 +81,9 @@ void CRPropa2TrajectoryOutput3D::process(Candidate *c) const { p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->current.getId())); p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->source.getId())); - p += sprintf(buffer + p, "%.4f ", c->getTrajectoryLength() / Mpc); + + double t = comoving2LightTravelDistance(c->getTrajectoryLength()) / Mpc; + p += sprintf(buffer + p, "%.4f ", t); const Vector3d &pos = c->current.getPosition() / Mpc; p += sprintf(buffer + p, "%.4f %.4f %.4f ", pos.x, pos.y, pos.z); @@ -94,7 +104,9 @@ CRPropa2TrajectoryOutput1D::CRPropa2TrajectoryOutput1D(std::string filename) { setDescription("Trajectory output"); outfile.open(filename.c_str()); outfile << "#CRPropa - Output data file\n" - << "#Format - Position(Mpc) Particle_Type Energy(EeV)\n"; + << "#Format - Position(Mpc) " + << "Particle_Type " + << "Energy(EeV)\n"; } CRPropa2TrajectoryOutput1D::~CRPropa2TrajectoryOutput1D() { @@ -120,7 +132,9 @@ CRPropa2EventOutput1D::CRPropa2EventOutput1D(std::string filename) { setDescription("Conditional output, Filename: " + filename); outfile.open(filename.c_str()); outfile << "#CRPropa - Output data file\n" - << "#Format - Energy(EeV) Time(Mpc) Initial_Particle_Type " + << "#Format - Energy(EeV) " + << "Time(Mpc, light travel distance) " + << "Initial_Particle_Type " << "Initial_Energy(EeV)\n"; } @@ -140,7 +154,8 @@ void CRPropa2EventOutput1D::process(Candidate *c) const { p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->current.getId())); p += sprintf(buffer + p, "%.4f ", c->current.getEnergy() / EeV); - p += sprintf(buffer + p, "%.4f ", c->getTrajectoryLength() / Mpc); + double t = comoving2LightTravelDistance(c->getTrajectoryLength()) / Mpc; + p += sprintf(buffer + p, "%.4f ", t); p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->source.getId())); p += sprintf(buffer + p, "%.4f\n", c->source.getEnergy() / EeV); From be34065145ebcd0b983e9a0f42ddc6cd94f9ae8c Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 29 Jul 2013 17:50:03 +0200 Subject: [PATCH 0327/1298] remove "Time_Mpc" field in ROOTEventOutput1D --- .../generate_epairTable.py | 2 +- src/module/OutputROOT.cpp | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/data-tools/ElectronPairProduction/generate_epairTable.py b/data-tools/ElectronPairProduction/generate_epairTable.py index 3cb0c7868..d15a6a8b7 100644 --- a/data-tools/ElectronPairProduction/generate_epairTable.py +++ b/data-tools/ElectronPairProduction/generate_epairTable.py @@ -1,5 +1,5 @@ from pylab import * -from mpc import * +from crpropa import * from scipy import interpolate, integrate diff --git a/src/module/OutputROOT.cpp b/src/module/OutputROOT.cpp index faa48e96a..157223a02 100644 --- a/src/module/OutputROOT.cpp +++ b/src/module/OutputROOT.cpp @@ -11,7 +11,7 @@ ROOTEventOutput1D::ROOTEventOutput1D(std::string filename) { "CRPropa output data file"); Ntuple = new TNtuple("events", "CRPropa 1D events", - "Particle_Type:Initial_Type:Initial_Position_Mpc:Inital_Redshift:Initial_Energy_EeV:Time_Mpc:Energy_EeV"); + "Particle_Type:Initial_Type:Initial_Position_Mpc:Inital_Redshift:Initial_Energy_EeV:Energy_EeV"); TThread::UnLock(); } @@ -31,9 +31,11 @@ void ROOTEventOutput1D::process(Candidate *c) const { TThread::Lock(); #pragma omp critical { - Ntuple->Fill(c->current.getId(), c->source.getId(), - c->source.getPosition().getX() / Mpc, c->getRedshift(), - c->source.getEnergy() / EeV, c->getTrajectoryLength() / Mpc, + Ntuple->Fill(c->current.getId(), + c->source.getId(), + c->source.getPosition().getX() / Mpc, + c->source.getEnergy() / EeV, + c->getTrajectoryLength() / Mpc, c->current.getEnergy() / EeV); } TThread::UnLock(); @@ -45,7 +47,6 @@ ROOTTrajectoryOutput1D::ROOTTrajectoryOutput1D(std::string filename) { TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); - // Ntuple = new TNtuple("traj","CRPropa 1D trajectories","Particle_Type:Initial_Type:Time_Mpc:Position_Mpc:Energy_EeV"); Ntuple = new TNtuple("traj", "CRPropa 1D trajectories", "Particle_Type:Initial_Type:Time_Mpc:Position_Mpc:Energy_EeV"); TThread::UnLock(); @@ -139,14 +140,16 @@ void ROOTTrajectoryOutput3D::process(Candidate *c) const { TThread::Lock(); #pragma omp critical { - Ntuple->Fill(c->current.getId(), c->source.getId(), + Ntuple->Fill(c->current.getId(), + c->source.getId(), c->getTrajectoryLength() / Mpc, c->current.getPosition().getX() / Mpc, c->current.getPosition().getY() / Mpc, c->current.getPosition().getZ() / Mpc, c->current.getDirection().getX(), c->current.getDirection().getY(), - c->current.getDirection().getZ(), c->current.getEnergy() / EeV); + c->current.getDirection().getZ(), + c->current.getEnergy() / EeV); } TThread::UnLock(); } From fc0c2d4a3dc55b40b6dd08ba440c30a4febd8f2f Mon Sep 17 00:00:00 2001 From: kuempel Date: Tue, 30 Jul 2013 15:16:25 +0200 Subject: [PATCH 0328/1298] Renamed ROOT output classes to indicate CRPropa2 style --- include/crpropa/module/OutputROOT.h | 32 ++++++++++++++--------------- src/XmlExecute.cpp | 8 ++++---- src/module/OutputROOT.cpp | 32 ++++++++++++++--------------- test/testOutput.cpp | 8 ++++---- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/include/crpropa/module/OutputROOT.h b/include/crpropa/module/OutputROOT.h index 63a9e58bc..da2174319 100644 --- a/include/crpropa/module/OutputROOT.h +++ b/include/crpropa/module/OutputROOT.h @@ -11,58 +11,58 @@ namespace crpropa { /** - @class ROOTEventOutput1D + @class CRPropa2ROOTEventOutput1D @brief Records particles that are inactive and have the property 'Detected' to a ROOT file. */ -class ROOTEventOutput1D: public Module { +class CRPropa2ROOTEventOutput1D: public Module { mutable TFile *ROOTFile; mutable TNtuple *Ntuple; public: - ROOTEventOutput1D(std::string filename); - ~ROOTEventOutput1D(); + CRPropa2ROOTEventOutput1D(std::string filename); + ~CRPropa2ROOTEventOutput1D(); void process(Candidate *candidate) const; }; /** - @class ROOTTrajectoryOutput1D + @class CRPropa2ROOTTrajectoryOutput1D @brief Saves trajectories to root file. */ -class ROOTTrajectoryOutput1D: public Module { +class CRPropa2ROOTTrajectoryOutput1D: public Module { mutable TFile *ROOTFile; mutable TNtuple *Ntuple; public: - ROOTTrajectoryOutput1D(std::string filename); - ~ROOTTrajectoryOutput1D(); + CRPropa2ROOTTrajectoryOutput1D(std::string filename); + ~CRPropa2ROOTTrajectoryOutput1D(); void process(Candidate *candidate) const; }; /** - @class ROOTEventOutput3D + @class CRPropa2ROOTEventOutput3D @brief Records particles that have the property 'Detected' to a ROOT file in 3D. */ -class ROOTEventOutput3D: public Module { +class CRPropa2ROOTEventOutput3D: public Module { mutable TFile *ROOTFile; mutable TNtuple *Ntuple; public: - ROOTEventOutput3D(std::string filename); - ~ROOTEventOutput3D(); + CRPropa2ROOTEventOutput3D(std::string filename); + ~CRPropa2ROOTEventOutput3D(); void process(Candidate *candidate) const; }; /** - @class ROOTTrajectoryOutput3D + @class CRPropa2ROOTTrajectoryOutput3D @brief Saves trajectories to root file in 3D. */ -class ROOTTrajectoryOutput3D: public Module { +class CRPropa2ROOTTrajectoryOutput3D: public Module { mutable TFile *ROOTFile; mutable TNtuple *Ntuple; public: - ROOTTrajectoryOutput3D(std::string filename); - ~ROOTTrajectoryOutput3D(); + CRPropa2ROOTTrajectoryOutput3D(std::string filename); + ~CRPropa2ROOTTrajectoryOutput3D(); void process(Candidate *candidate) const; }; diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 3d2765694..e846e27e0 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -717,14 +717,14 @@ void XmlExecute::loadOutput(xml_node &node) { else if (format == "ROOT") { if (type == "Full Trajectories") if (is1D) - modules.add(new ROOTTrajectoryOutput1D(filename)); + modules.add(new CRPropa2ROOTTrajectoryOutput1D(filename)); else - modules.add(new ROOTTrajectoryOutput3D(filename)); + modules.add(new CRPropa2ROOTTrajectoryOutput3D(filename)); else if (type == "Events") if (is1D) - modules.add(new ROOTEventOutput1D(filename)); + modules.add(new CRPropa2ROOTEventOutput1D(filename)); else - modules.add(new ROOTEventOutput3D(filename)); + modules.add(new CRPropa2ROOTEventOutput3D(filename)); else if (type == "None") return; else diff --git a/src/module/OutputROOT.cpp b/src/module/OutputROOT.cpp index 157223a02..4f6a62d31 100644 --- a/src/module/OutputROOT.cpp +++ b/src/module/OutputROOT.cpp @@ -4,8 +4,8 @@ namespace crpropa { -/////////////////////// ROOT EVENT OUTPUT 1D ////////////////////////////////// -ROOTEventOutput1D::ROOTEventOutput1D(std::string filename) { +/////////////////////// CRPropa2ROOT EVENT OUTPUT 1D ////////////////////////////////// +CRPropa2ROOTEventOutput1D::CRPropa2ROOTEventOutput1D(std::string filename) { TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); @@ -15,14 +15,14 @@ ROOTEventOutput1D::ROOTEventOutput1D(std::string filename) { TThread::UnLock(); } -ROOTEventOutput1D::~ROOTEventOutput1D() { +CRPropa2ROOTEventOutput1D::~CRPropa2ROOTEventOutput1D() { TThread::Lock(); ROOTFile->Write(); ROOTFile->Close(); TThread::UnLock(); } -void ROOTEventOutput1D::process(Candidate *c) const { +void CRPropa2ROOTEventOutput1D::process(Candidate *c) const { if (not (c->hasProperty("Detected"))) return; @@ -42,8 +42,8 @@ void ROOTEventOutput1D::process(Candidate *c) const { } //////////////////////////////////////////////////////////////////////////////// -/////////////////////// ROOT TRAJECTORY OUTPUT 1D ////////////////////////////// -ROOTTrajectoryOutput1D::ROOTTrajectoryOutput1D(std::string filename) { +/////////////////////// CRPropa2ROOT TRAJECTORY OUTPUT 1D ////////////////////////////// +CRPropa2ROOTTrajectoryOutput1D::CRPropa2ROOTTrajectoryOutput1D(std::string filename) { TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); @@ -52,14 +52,14 @@ ROOTTrajectoryOutput1D::ROOTTrajectoryOutput1D(std::string filename) { TThread::UnLock(); } -ROOTTrajectoryOutput1D::~ROOTTrajectoryOutput1D() { +CRPropa2ROOTTrajectoryOutput1D::~CRPropa2ROOTTrajectoryOutput1D() { TThread::Lock(); ROOTFile->Write(); ROOTFile->Close(); TThread::UnLock(); } -void ROOTTrajectoryOutput1D::process(Candidate *c) const { +void CRPropa2ROOTTrajectoryOutput1D::process(Candidate *c) const { TThread::Lock(); #pragma omp critical { @@ -72,8 +72,8 @@ void ROOTTrajectoryOutput1D::process(Candidate *c) const { } //////////////////////////////////////////////////////////////////////////////// -/////////////////////// ROOT EVENT OUTPUT 3D ////////////////////////////////// -ROOTEventOutput3D::ROOTEventOutput3D(std::string filename) { +/////////////////////// CRPropa2ROOT EVENT OUTPUT 3D ////////////////////////////////// +CRPropa2ROOTEventOutput3D::CRPropa2ROOTEventOutput3D(std::string filename) { TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); @@ -83,14 +83,14 @@ ROOTEventOutput3D::ROOTEventOutput3D(std::string filename) { TThread::UnLock(); } -ROOTEventOutput3D::~ROOTEventOutput3D() { +CRPropa2ROOTEventOutput3D::~CRPropa2ROOTEventOutput3D() { TThread::Lock(); ROOTFile->Write(); ROOTFile->Close(); TThread::UnLock(); } -void ROOTEventOutput3D::process(Candidate *c) const { +void CRPropa2ROOTEventOutput3D::process(Candidate *c) const { if (not (c->hasProperty("Detected"))) return; @@ -118,8 +118,8 @@ void ROOTEventOutput3D::process(Candidate *c) const { } //////////////////////////////////////////////////////////////////////////////// -/////////////////////// ROOT TRAJECTORY OUTPUT 3D ////////////////////////////// -ROOTTrajectoryOutput3D::ROOTTrajectoryOutput3D(std::string filename) { +/////////////////////// CRPropa2ROOT TRAJECTORY OUTPUT 3D ////////////////////////////// +CRPropa2ROOTTrajectoryOutput3D::CRPropa2ROOTTrajectoryOutput3D(std::string filename) { TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); @@ -129,14 +129,14 @@ ROOTTrajectoryOutput3D::ROOTTrajectoryOutput3D(std::string filename) { TThread::UnLock(); } -ROOTTrajectoryOutput3D::~ROOTTrajectoryOutput3D() { +CRPropa2ROOTTrajectoryOutput3D::~CRPropa2ROOTTrajectoryOutput3D() { TThread::Lock(); ROOTFile->Write(); ROOTFile->Close(); TThread::UnLock(); } -void ROOTTrajectoryOutput3D::process(Candidate *c) const { +void CRPropa2ROOTTrajectoryOutput3D::process(Candidate *c) const { TThread::Lock(); #pragma omp critical { diff --git a/test/testOutput.cpp b/test/testOutput.cpp index 3cf3d04be..bc7fcd758 100644 --- a/test/testOutput.cpp +++ b/test/testOutput.cpp @@ -41,16 +41,16 @@ TEST(CRPropa2EventOutput1D, removeProperty) { } #ifdef CRPROPA_HAVE_ROOT -TEST(ROOTEventOutput3D, removeProperty) { - ROOTEventOutput3D output(""); +TEST(CRPropa2ROOTEventOutput3D, removeProperty) { + CRPropa2ROOTEventOutput3D output(""); Candidate c; c.setProperty("Dected", ""); output.process(&c); EXPECT_FALSE(c.hasProperty("Detected")); } -TEST(ROOTEventOutput1D, removeProperty) { - ROOTEventOutput1D output(""); +TEST(CRPropa2ROOTEventOutput1D, removeProperty) { + CRPropa2ROOTEventOutput1D output(""); Candidate c; c.setProperty("Dected", ""); output.process(&c); From 68e7f69c14f2540935e5457ff7480be4542d0f2e Mon Sep 17 00:00:00 2001 From: kuempel Date: Wed, 31 Jul 2013 11:22:35 +0200 Subject: [PATCH 0329/1298] CRPropa 2 ROOT output in light travel distance. Added CRPropa 3 ROOT output as ascii output. Events3D not filled yet. --- include/crpropa/module/OutputROOT.h | 62 ++++++++ src/module/OutputROOT.cpp | 238 +++++++++++++++++++++++----- test/testOutput.cpp | 1 + 3 files changed, 260 insertions(+), 41 deletions(-) diff --git a/include/crpropa/module/OutputROOT.h b/include/crpropa/module/OutputROOT.h index da2174319..af4b2a87e 100644 --- a/include/crpropa/module/OutputROOT.h +++ b/include/crpropa/module/OutputROOT.h @@ -24,6 +24,21 @@ class CRPropa2ROOTEventOutput1D: public Module { void process(Candidate *candidate) const; }; +/** + @class ROOTEventOutput1D + @brief Records particles that are inactive and have the property 'Detected' to a ROOT file. + */ +class ROOTEventOutput1D: public Module { + mutable TFile *ROOTFile; + mutable TNtuple *Ntuple; + +public: + ROOTEventOutput1D(std::string filename); + ~ROOTEventOutput1D(); + void process(Candidate *candidate) const; +}; + + /** @class CRPropa2ROOTTrajectoryOutput1D @brief Saves trajectories to root file. @@ -38,6 +53,23 @@ class CRPropa2ROOTTrajectoryOutput1D: public Module { void process(Candidate *candidate) const; }; + +/** + @class ROOTTrajectoryOutput1D + @brief Saves trajectories to root file. + */ +class ROOTTrajectoryOutput1D: public Module { + mutable TFile *ROOTFile; + mutable TNtuple *Ntuple; + +public: + ROOTTrajectoryOutput1D(std::string filename); + ~ROOTTrajectoryOutput1D(); + void process(Candidate *candidate) const; +}; + + + /** @class CRPropa2ROOTEventOutput3D @brief Records particles that have the property 'Detected' to a ROOT file in 3D. @@ -52,6 +84,21 @@ class CRPropa2ROOTEventOutput3D: public Module { void process(Candidate *candidate) const; }; +/** + @class ROOTEventOutput3D + @brief Records particles that have the property 'Detected' to a ROOT file in 3D. + */ +class ROOTEventOutput3D: public Module { + mutable TFile *ROOTFile; + mutable TNtuple *Ntuple; + +public: + ROOTEventOutput3D(std::string filename); + ~ROOTEventOutput3D(); + void process(Candidate *candidate) const; +}; + + /** @class CRPropa2ROOTTrajectoryOutput3D @brief Saves trajectories to root file in 3D. @@ -66,6 +113,21 @@ class CRPropa2ROOTTrajectoryOutput3D: public Module { void process(Candidate *candidate) const; }; +/** + @class ROOTTrajectoryOutput3D + @brief Saves trajectories to root file in 3D. + */ +class ROOTTrajectoryOutput3D: public Module { + mutable TFile *ROOTFile; + mutable TNtuple *Ntuple; + +public: + ROOTTrajectoryOutput3D(std::string filename); + ~ROOTTrajectoryOutput3D(); + void process(Candidate *candidate) const; +}; + + } // namespace crpropa #endif // CRPROPA_HAVE_ROOT diff --git a/src/module/OutputROOT.cpp b/src/module/OutputROOT.cpp index 4f6a62d31..49aeafe59 100644 --- a/src/module/OutputROOT.cpp +++ b/src/module/OutputROOT.cpp @@ -1,4 +1,5 @@ #include "crpropa/module/OutputROOT.h" +#include "crpropa/Cosmology.h" #ifdef CRPROPA_HAVE_ROOT @@ -8,10 +9,9 @@ namespace crpropa { CRPropa2ROOTEventOutput1D::CRPropa2ROOTEventOutput1D(std::string filename) { TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", - "CRPropa output data file"); - Ntuple = - new TNtuple("events", "CRPropa 1D events", - "Particle_Type:Initial_Type:Initial_Position_Mpc:Inital_Redshift:Initial_Energy_EeV:Energy_EeV"); + "CRPropa 2 output data file"); + Ntuple = new TNtuple("events", "CRPropa 1D events", + "Particle_Type:Initial_Type:Initial_Position_Mpc:Initial_Energy_EeV:Energy_EeV"); TThread::UnLock(); } @@ -31,24 +31,24 @@ void CRPropa2ROOTEventOutput1D::process(Candidate *c) const { TThread::Lock(); #pragma omp critical { - Ntuple->Fill(c->current.getId(), - c->source.getId(), - c->source.getPosition().getX() / Mpc, - c->source.getEnergy() / EeV, - c->getTrajectoryLength() / Mpc, - c->current.getEnergy() / EeV); + Ntuple->Fill(convertToCRPropaId(c->current.getId()), + convertToCRPropaId(c->source.getId()), + comoving2LightTravelDistance(c->source.getPosition().getX() / Mpc), + c->source.getEnergy() / EeV, + c->current.getEnergy() / EeV); } TThread::UnLock(); } //////////////////////////////////////////////////////////////////////////////// + /////////////////////// CRPropa2ROOT TRAJECTORY OUTPUT 1D ////////////////////////////// CRPropa2ROOTTrajectoryOutput1D::CRPropa2ROOTTrajectoryOutput1D(std::string filename) { TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", - "CRPropa output data file"); + "CRPropa 2 output data file"); Ntuple = new TNtuple("traj", "CRPropa 1D trajectories", - "Particle_Type:Initial_Type:Time_Mpc:Position_Mpc:Energy_EeV"); + "Particle_Type:Initial_Type:Position_Mpc:Energy_EeV"); TThread::UnLock(); } @@ -63,10 +63,10 @@ void CRPropa2ROOTTrajectoryOutput1D::process(Candidate *c) const { TThread::Lock(); #pragma omp critical { - Ntuple->Fill(c->current.getId(), c->source.getId(), - c->getTrajectoryLength() / Mpc, - c->current.getPosition().getX() / Mpc, - c->current.getEnergy() / EeV); + Ntuple->Fill(convertToCRPropaId(c->current.getId()), + convertToCRPropaId(c->source.getId()), + comoving2LightTravelDistance(c->current.getPosition().getX() / Mpc), + c->current.getEnergy() / EeV); } TThread::UnLock(); } @@ -76,7 +76,7 @@ void CRPropa2ROOTTrajectoryOutput1D::process(Candidate *c) const { CRPropa2ROOTEventOutput3D::CRPropa2ROOTEventOutput3D(std::string filename) { TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", - "CRPropa output data file"); + "CRPropa 2 output data file"); Ntuple = new TNtuple("events", "CRPropa 3D events", "Particle_Type:Initial_Type:Initial_Position_X_Mpc:Initial_Position_Y_Mpc:Initial_Position_Z_Mpc:Initial_Momentum_E_EeV:Initial_Momentum_theta:Initial_Momentum_phi:Time_Mpc:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Momentum_E_EeV:Momentum_theta:Momentum_phi"); @@ -99,20 +99,21 @@ void CRPropa2ROOTEventOutput3D::process(Candidate *c) const { TThread::Lock(); #pragma omp critical { - Ntuple->Fill(c->current.getId(), c->source.getId(), - c->source.getPosition().getX() / Mpc, - c->source.getPosition().getY() / Mpc, - c->source.getPosition().getZ() / Mpc, - c->source.getEnergy() / EeV, - c->source.getDirection().getTheta(), - c->source.getDirection().getPhi(), - c->getTrajectoryLength() / Mpc, - c->current.getPosition().getX() / Mpc, - c->current.getPosition().getY() / Mpc, - c->current.getPosition().getZ() / Mpc, - c->current.getEnergy() / EeV, - c->current.getDirection().getTheta(), - c->current.getDirection().getPhi()); + Ntuple->Fill(convertToCRPropaId(c->current.getId()), + convertToCRPropaId(c->source.getId()), + comoving2LightTravelDistance(c->source.getPosition().getX() / Mpc), + comoving2LightTravelDistance(c->source.getPosition().getY() / Mpc), + comoving2LightTravelDistance(c->source.getPosition().getZ() / Mpc), + c->source.getEnergy() / EeV, + c->source.getDirection().getTheta(), + c->source.getDirection().getPhi(), + comoving2LightTravelDistance(c->getTrajectoryLength() / Mpc), + comoving2LightTravelDistance(c->current.getPosition().getX() / Mpc), + comoving2LightTravelDistance(c->current.getPosition().getY() / Mpc), + comoving2LightTravelDistance(c->current.getPosition().getZ() / Mpc), + c->current.getEnergy() / EeV, + c->current.getDirection().getTheta(), + c->current.getDirection().getPhi()); } TThread::UnLock(); } @@ -122,7 +123,7 @@ void CRPropa2ROOTEventOutput3D::process(Candidate *c) const { CRPropa2ROOTTrajectoryOutput3D::CRPropa2ROOTTrajectoryOutput3D(std::string filename) { TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", - "CRPropa output data file"); + "CRPropa 2 output data file"); Ntuple = new TNtuple("traj", "CRPropa 3D trajectories", "Particle_Type:Initial_Type:Time_Mpc:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Direction_X:Direction_Y:Direction_Z:Energy_EeV"); @@ -141,20 +142,175 @@ void CRPropa2ROOTTrajectoryOutput3D::process(Candidate *c) const { #pragma omp critical { Ntuple->Fill(c->current.getId(), - c->source.getId(), - c->getTrajectoryLength() / Mpc, - c->current.getPosition().getX() / Mpc, - c->current.getPosition().getY() / Mpc, - c->current.getPosition().getZ() / Mpc, - c->current.getDirection().getX(), - c->current.getDirection().getY(), - c->current.getDirection().getZ(), - c->current.getEnergy() / EeV); + c->source.getId(), + comoving2LightTravelDistance(c->getTrajectoryLength() / Mpc), + comoving2LightTravelDistance(c->current.getPosition().getX() / Mpc), + comoving2LightTravelDistance(c->current.getPosition().getY() / Mpc), + comoving2LightTravelDistance(c->current.getPosition().getZ() / Mpc), + c->current.getDirection().getX(), + c->current.getDirection().getY(), + c->current.getDirection().getZ(), + c->current.getEnergy() / EeV); } TThread::UnLock(); } //////////////////////////////////////////////////////////////////////////////// + + + + +/////////////////////// ROOT EVENT OUTPUT 1D ////////////////////////////////// +ROOTEventOutput1D::ROOTEventOutput1D(std::string filename) { + TThread::Lock(); + ROOTFile = new TFile(filename.c_str(), "RECREATE", + "CRPropa output data file"); + Ntuple = new TNtuple("events", "CRPropa 1D events", + "Particle_Type:Energy_EeV:TrajectoryLength_Mpc:Initial_Type:Initial_Energy_EeV"); + TThread::UnLock(); +} + + +ROOTEventOutput1D::~ROOTEventOutput1D() { + TThread::Lock(); + ROOTFile->Write(); + ROOTFile->Close(); + TThread::UnLock(); +} + +void ROOTEventOutput1D::process(Candidate *c) const { + if (not (c->hasProperty("Detected"))) + return; + + c->removeProperty("Detected"); + + TThread::Lock(); +#pragma omp critical + { + Ntuple->Fill(c->current.getId(), + c->current.getEnergy() / EeV, + c->getTrajectoryLength() / Mpc, + c->source.getId(), + c->source.getEnergy() / EeV); + } + TThread::UnLock(); +} +//////////////////////////////////////////////////////////////////////////////// + + +/////////////////////// ROOT TRAJECTORY OUTPUT 1D ////////////////////////////// +ROOTTrajectoryOutput1D::ROOTTrajectoryOutput1D(std::string filename) { + TThread::Lock(); + ROOTFile = new TFile(filename.c_str(), "RECREATE", + "CRPropa output data file"); + Ntuple = new TNtuple("traj", "CRPropa 1D trajectories", + "Position_Mpc:Particle_Type:Energy_EeV"); + TThread::UnLock(); +} + +ROOTTrajectoryOutput1D::~ROOTTrajectoryOutput1D() { + TThread::Lock(); + ROOTFile->Write(); + ROOTFile->Close(); + TThread::UnLock(); +} + +void ROOTTrajectoryOutput1D::process(Candidate *c) const { + TThread::Lock(); +#pragma omp critical + { + Ntuple->Fill(c->current.getPosition().getX() / Mpc, + c->current.getId(), + c->current.getEnergy() / EeV); + } + TThread::UnLock(); +} +//////////////////////////////////////////////////////////////////////////////// + +/////////////////////// ROOT EVENT OUTPUT 3D ////////////////////////////////// +ROOTEventOutput3D::ROOTEventOutput3D(std::string filename) { + TThread::Lock(); + ROOTFile = new TFile(filename.c_str(), "RECREATE", + "CRPropa output data file"); + Ntuple = new TNtuple("events", "CRPropa 3D events", + "TrajectoryLength_Mpc:Particle_Type:Initial_Type:Momentum_E_EeV:Initial_Momentum_E_EeV:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Initial_Position_X_Mpc:Initial_Position_Y_Mpc:Initial_Position_Z_Mpc:Direction_X_Mpc:Direction_Y_Mpc:Direction_Z_Mpc:Initial_Direction_X_Mpc:Initial_Direction_Y_Mpc:Initial_Direction_Z_Mpc"); + TThread::UnLock(); +} + +ROOTEventOutput3D::~ROOTEventOutput3D() { + TThread::Lock(); + ROOTFile->Write(); + ROOTFile->Close(); + TThread::UnLock(); +} + +void ROOTEventOutput3D::process(Candidate *c) const { + if (not (c->hasProperty("Detected"))) + return; + + c->removeProperty("Detected"); + + TThread::Lock(); +#pragma omp critical + { + // Ntuple->Fill(c->getTrajectoryLength() / Mpc, + // c->current.getId(), + // c->source.getId(), + // c->current.getEnergy() / EeV, + // c->source.getEnergy() / EeV, + // c->current.getPosition().getX() / Mpc, + // c->current.getPosition().getY() / Mpc, + // c->current.getPosition().getZ() / Mpc, + // c->source.getPosition().getX() / Mpc, + // c->source.getPosition().getY() / Mpc, + // c->source.getPosition().getZ() / Mpc, + // c->current.getDirection().getX() / Mpc, + // c->current.getDirection().getY() / Mpc, + // c->current.getDirection().getZ() / Mpc, + // c->source.getDirection().getX() / Mpc, + // c->source.getDirection().getY() / Mpc, + // c->source.getDirection().getZ() / Mpc); + } + TThread::UnLock(); +} +//////////////////////////////////////////////////////////////////////////////// + +/////////////////////// ROOT TRAJECTORY OUTPUT 3D ////////////////////////////// +ROOTTrajectoryOutput3D::ROOTTrajectoryOutput3D(std::string filename) { + TThread::Lock(); + ROOTFile = new TFile(filename.c_str(), "RECREATE", + "CRPropa output data file"); + Ntuple = new TNtuple("traj", "CRPropa 3D trajectories", + "TrajectoryLength_Mpc:Particle_Type:Energy_EeV:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Direction_X_Mpc:Direction_Y_Mpc:Direction_Z_Mpc"); + TThread::UnLock(); +} + +ROOTTrajectoryOutput3D::~ROOTTrajectoryOutput3D() { + TThread::Lock(); + ROOTFile->Write(); + ROOTFile->Close(); + TThread::UnLock(); +} + +void ROOTTrajectoryOutput3D::process(Candidate *c) const { + TThread::Lock(); +#pragma omp critical + { + Ntuple->Fill(c->getTrajectoryLength() / Mpc, + c->current.getId(), + c->current.getEnergy() / EeV, + c->current.getPosition().getX() / Mpc, + c->current.getPosition().getY() / Mpc, + c->current.getPosition().getZ() / Mpc, + c->current.getDirection().getX(), + c->current.getDirection().getY(), + c->current.getDirection().getZ()); + } + TThread::UnLock(); +} +//////////////////////////////////////////////////////////////////////////////// + + }// namespace crpropa #endif // CRPROPA_HAVE_ROOT diff --git a/test/testOutput.cpp b/test/testOutput.cpp index bc7fcd758..bad4ba5dc 100644 --- a/test/testOutput.cpp +++ b/test/testOutput.cpp @@ -55,5 +55,6 @@ TEST(CRPropa2ROOTEventOutput1D, removeProperty) { c.setProperty("Dected", ""); output.process(&c); EXPECT_FALSE(c.hasProperty("Detected")); + } #endif From 97b15df814c8c4685eacd2cf00e3cafaa0fcb015 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 31 Jul 2013 17:19:49 +0200 Subject: [PATCH 0330/1298] changed InterationState.distance to light travel distance and updated stochastic interactions accordingly --- include/crpropa/Candidate.h | 2 +- include/crpropa/PhotonBackground.h | 2 +- src/PhotonBackground.cpp | 2 +- src/module/ElectronPairProduction.cpp | 4 ++-- src/module/NuclearDecay.cpp | 2 -- src/module/PhotoDisintegration.cpp | 4 +--- src/module/PhotoPionProduction.cpp | 6 ++---- src/module/Redshift.cpp | 2 +- src/module/StochasticInteraction.cpp | 7 +++++-- 9 files changed, 14 insertions(+), 17 deletions(-) diff --git a/include/crpropa/Candidate.h b/include/crpropa/Candidate.h index 12ae14f77..57441e724 100644 --- a/include/crpropa/Candidate.h +++ b/include/crpropa/Candidate.h @@ -24,7 +24,7 @@ struct InteractionState { distance(distance), channel(channel) { } - double distance; /**< Free distance of the interaction in [m] comoving units */ + double distance; /**< Free distance of the interaction in [m] as light travel distance */ int channel; /**< Interaction ID */ }; diff --git a/include/crpropa/PhotonBackground.h b/include/crpropa/PhotonBackground.h index ce1b3a791..c00085ffa 100644 --- a/include/crpropa/PhotonBackground.h +++ b/include/crpropa/PhotonBackground.h @@ -9,7 +9,7 @@ enum PhotonField { }; // Returns overall photon field scaling factor at redshift z -double photonFieldScaling(int photonField, double z); +double photonDensityScaling(int photonField, double z); } // namespace crpropa diff --git a/src/PhotonBackground.cpp b/src/PhotonBackground.cpp index 7c30967ba..1eb71ef8f 100644 --- a/src/PhotonBackground.cpp +++ b/src/PhotonBackground.cpp @@ -12,7 +12,7 @@ static std::vector zKneiske(a, a + sizeof(a) / sizeof(double)); double b[9] = { 1, 1.6937, 2.5885, 3.6178, 5.1980, 7.3871, 8.5471, 7.8605, 0 }; static std::vector sKneiske(b, b + sizeof(b) / sizeof(double)); -double photonFieldScaling(int photonField, double z) { +double photonDensityScaling(int photonField, double z) { if (photonField == IRB) return interpolate(z, zKneiske, sKneiske); return pow(1 + z, 3); // CMB-like scaling diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 6c9696a7f..0ed1d495f 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -81,11 +81,11 @@ void ElectronPairProduction::process(Candidate *candidate) const { else rate = lossRate.back() * pow(EpA / energy.back(), 0.4); // extrapolation - // step size in local frame + // convert step size to local frame: dx = dx_com / (1 + z) double step = candidate->getCurrentStep() / (1 + z); // dE(E) = Z^2 * loss_rate(E/A) * step - double dE = Z * Z * rate * photonFieldScaling(photonField, z) * step; + double dE = Z * Z * rate * photonDensityScaling(photonField, z) * step; // prevent the energy loss from exceeding the actual energy dE = std::min(E, dE); diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index be665fe2e..2a7678d3b 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -81,8 +81,6 @@ bool NuclearDecay::setNextInteraction(Candidate *candidate, // special relativistic time dilation interaction.distance *= candidate->current.getLorentzFactor(); - // convert to comoving frame - interaction.distance *= (1 + candidate->getRedshift()); candidate->setInteractionState(getDescription(), interaction); return true; diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 136c058b6..9e9e00572 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -103,9 +103,7 @@ bool PhotoDisintegration::setNextInteraction(Candidate *candidate, } // interaction length is proportional to 1 / (photon density) - interaction.distance /= photonFieldScaling(photonField, z); - // convert to comoving frame - interaction.distance *= (1 + z); + interaction.distance /= photonDensityScaling(photonField, z); candidate->setInteractionState(getDescription(), interaction); return true; diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index ffc3f075d..a91896279 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -66,7 +66,7 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, int A = candidate->current.getMassNumber(); int Z = candidate->current.getChargeNumber(); int N = A - Z; - double EpA = E / A * (1 + z); // CMB energies increase with (1+z)^3 + double EpA = E / A * (1 + z); // CMB photon energies increase with (1+z) // check if out of energy range if ((EpA < energy.front()) or (EpA > energy.back())) @@ -111,9 +111,7 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, } // interaction length is proportional to 1 / (photon density) - interaction.distance /= photonFieldScaling(photonField, z); - // convert to comoving frame - interaction.distance *= (1 + z); + interaction.distance /= photonDensityScaling(photonField, z); candidate->setInteractionState(getDescription(), interaction); return true; diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index ef2775cdd..4119e000e 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -19,7 +19,7 @@ void Redshift::process(Candidate *c) const { // update redshift c->setRedshift(z - dz); - // adiabatic energy loss: dE / dz = E/(1+z) + // adiabatic energy loss: dE / dz = E / (1+z) double E = c->current.getEnergy(); c->current.setEnergy(E * (1 - dz / (1 + z))); } diff --git a/src/module/StochasticInteraction.cpp b/src/module/StochasticInteraction.cpp index b92acbe8c..5c9ef98bc 100644 --- a/src/module/StochasticInteraction.cpp +++ b/src/module/StochasticInteraction.cpp @@ -3,7 +3,10 @@ namespace crpropa { void StochasticInteraction::process(Candidate* candidate) const { - double step = candidate->getCurrentStep(); + // interaction distances are in physical distances --> get physical step size: dx = dx_comoving / (1 + z) + double z = candidate->getRedshift(); + double step = candidate->getCurrentStep() / (1 + z); + while (step >= 0) { // get the interaction state, if there is one InteractionState interaction; @@ -20,7 +23,7 @@ void StochasticInteraction::process(Candidate* candidate) const { // if interaction distance not reached, reduce it and return if (interaction.distance > step) { interaction.distance -= step; - candidate->limitNextStep(interaction.distance); + candidate->limitNextStep(interaction.distance * (1 + z)); candidate->setInteractionState(getDescription(), interaction); return; } From 7db88d3a27439d4c4a53a7d2d619ce3709dd1d8f Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 31 Jul 2013 18:26:24 +0200 Subject: [PATCH 0331/1298] some fixes to CRPropa2 Output --- src/module/OutputCRPropa2.cpp | 2 +- src/module/OutputROOT.cpp | 120 ++++++++++++++++------------------ 2 files changed, 59 insertions(+), 63 deletions(-) diff --git a/src/module/OutputCRPropa2.cpp b/src/module/OutputCRPropa2.cpp index cd035f0ca..41cd63ce7 100644 --- a/src/module/OutputCRPropa2.cpp +++ b/src/module/OutputCRPropa2.cpp @@ -117,7 +117,7 @@ void CRPropa2TrajectoryOutput1D::process(Candidate *c) const { char buffer[256]; size_t p = 0; - p += sprintf(buffer + p, "%.4f ", c->current.getPosition().x / Mpc); + p += sprintf(buffer + p, "%.4f ", comoving2LightTravelDistance(c->current.getPosition().x) / Mpc); p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->current.getId())); p += sprintf(buffer + p, "%.4f\n", c->current.getEnergy() / EeV); diff --git a/src/module/OutputROOT.cpp b/src/module/OutputROOT.cpp index 49aeafe59..613a34eba 100644 --- a/src/module/OutputROOT.cpp +++ b/src/module/OutputROOT.cpp @@ -5,7 +5,7 @@ namespace crpropa { -/////////////////////// CRPropa2ROOT EVENT OUTPUT 1D ////////////////////////////////// +/////////////////////// CRPropa2ROOT EVENT OUTPUT 1D /////////////////////////// CRPropa2ROOTEventOutput1D::CRPropa2ROOTEventOutput1D(std::string filename) { TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", @@ -33,7 +33,7 @@ void CRPropa2ROOTEventOutput1D::process(Candidate *c) const { { Ntuple->Fill(convertToCRPropaId(c->current.getId()), convertToCRPropaId(c->source.getId()), - comoving2LightTravelDistance(c->source.getPosition().getX() / Mpc), + comoving2LightTravelDistance(c->source.getPosition().x) / Mpc, c->source.getEnergy() / EeV, c->current.getEnergy() / EeV); } @@ -41,8 +41,7 @@ void CRPropa2ROOTEventOutput1D::process(Candidate *c) const { } //////////////////////////////////////////////////////////////////////////////// - -/////////////////////// CRPropa2ROOT TRAJECTORY OUTPUT 1D ////////////////////////////// +/////////////////////// CRPropa2ROOT TRAJECTORY OUTPUT 1D ////////////////////// CRPropa2ROOTTrajectoryOutput1D::CRPropa2ROOTTrajectoryOutput1D(std::string filename) { TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", @@ -65,21 +64,20 @@ void CRPropa2ROOTTrajectoryOutput1D::process(Candidate *c) const { { Ntuple->Fill(convertToCRPropaId(c->current.getId()), convertToCRPropaId(c->source.getId()), - comoving2LightTravelDistance(c->current.getPosition().getX() / Mpc), + comoving2LightTravelDistance(c->current.getPosition().x) / Mpc, c->current.getEnergy() / EeV); } TThread::UnLock(); } //////////////////////////////////////////////////////////////////////////////// -/////////////////////// CRPropa2ROOT EVENT OUTPUT 3D ////////////////////////////////// +/////////////////////// CRPropa2ROOT EVENT OUTPUT 3D /////////////////////////// CRPropa2ROOTEventOutput3D::CRPropa2ROOTEventOutput3D(std::string filename) { TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa 2 output data file"); - Ntuple = - new TNtuple("events", "CRPropa 3D events", - "Particle_Type:Initial_Type:Initial_Position_X_Mpc:Initial_Position_Y_Mpc:Initial_Position_Z_Mpc:Initial_Momentum_E_EeV:Initial_Momentum_theta:Initial_Momentum_phi:Time_Mpc:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Momentum_E_EeV:Momentum_theta:Momentum_phi"); + Ntuple = new TNtuple("events", "CRPropa 3D events", + "Particle_Type:Initial_Type:Initial_Position_X_Mpc:Initial_Position_Y_Mpc:Initial_Position_Z_Mpc:Initial_Momentum_E_EeV:Initial_Momentum_theta:Initial_Momentum_phi:Time_Mpc:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Momentum_E_EeV:Momentum_theta:Momentum_phi"); TThread::UnLock(); } @@ -96,21 +94,23 @@ void CRPropa2ROOTEventOutput3D::process(Candidate *c) const { c->removeProperty("Detected"); + Vector3d ipos = c->source.getPosition(); + Vector3d pos = c->current.getPosition(); TThread::Lock(); #pragma omp critical { - Ntuple->Fill(convertToCRPropaId(c->current.getId()), + Ntuple->Fill(convertToCRPropaId(c->current.getId()), convertToCRPropaId(c->source.getId()), - comoving2LightTravelDistance(c->source.getPosition().getX() / Mpc), - comoving2LightTravelDistance(c->source.getPosition().getY() / Mpc), - comoving2LightTravelDistance(c->source.getPosition().getZ() / Mpc), + comoving2LightTravelDistance(ipos.x) / Mpc, + comoving2LightTravelDistance(ipos.y) / Mpc, + comoving2LightTravelDistance(ipos.z) / Mpc, c->source.getEnergy() / EeV, c->source.getDirection().getTheta(), c->source.getDirection().getPhi(), - comoving2LightTravelDistance(c->getTrajectoryLength() / Mpc), - comoving2LightTravelDistance(c->current.getPosition().getX() / Mpc), - comoving2LightTravelDistance(c->current.getPosition().getY() / Mpc), - comoving2LightTravelDistance(c->current.getPosition().getZ() / Mpc), + comoving2LightTravelDistance(c->getTrajectoryLength()) / Mpc, + comoving2LightTravelDistance(pos.x) / Mpc, + comoving2LightTravelDistance(pos.y) / Mpc, + comoving2LightTravelDistance(pos.z) / Mpc, c->current.getEnergy() / EeV, c->current.getDirection().getTheta(), c->current.getDirection().getPhi()); @@ -119,14 +119,13 @@ void CRPropa2ROOTEventOutput3D::process(Candidate *c) const { } //////////////////////////////////////////////////////////////////////////////// -/////////////////////// CRPropa2ROOT TRAJECTORY OUTPUT 3D ////////////////////////////// +/////////////////////// CRPropa2ROOT TRAJECTORY OUTPUT 3D ////////////////////// CRPropa2ROOTTrajectoryOutput3D::CRPropa2ROOTTrajectoryOutput3D(std::string filename) { TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa 2 output data file"); - Ntuple = - new TNtuple("traj", "CRPropa 3D trajectories", - "Particle_Type:Initial_Type:Time_Mpc:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Direction_X:Direction_Y:Direction_Z:Energy_EeV"); + Ntuple = new TNtuple("traj", "CRPropa 3D trajectories", + "Particle_Type:Initial_Type:Time_Mpc:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Direction_X:Direction_Y:Direction_Z:Energy_EeV"); TThread::UnLock(); } @@ -138,35 +137,33 @@ CRPropa2ROOTTrajectoryOutput3D::~CRPropa2ROOTTrajectoryOutput3D() { } void CRPropa2ROOTTrajectoryOutput3D::process(Candidate *c) const { + Vector3d pos = c->current.getPosition(); + Vector3d dir = c->current.getDirection(); TThread::Lock(); #pragma omp critical { Ntuple->Fill(c->current.getId(), c->source.getId(), - comoving2LightTravelDistance(c->getTrajectoryLength() / Mpc), - comoving2LightTravelDistance(c->current.getPosition().getX() / Mpc), - comoving2LightTravelDistance(c->current.getPosition().getY() / Mpc), - comoving2LightTravelDistance(c->current.getPosition().getZ() / Mpc), - c->current.getDirection().getX(), - c->current.getDirection().getY(), - c->current.getDirection().getZ(), + comoving2LightTravelDistance(c->getTrajectoryLength()) / Mpc, + comoving2LightTravelDistance(pos.x) / Mpc, + comoving2LightTravelDistance(pos.y) / Mpc, + comoving2LightTravelDistance(pos.z) / Mpc, + dir.x, + dir.y, + dir.z, c->current.getEnergy() / EeV); } TThread::UnLock(); } //////////////////////////////////////////////////////////////////////////////// - - - - /////////////////////// ROOT EVENT OUTPUT 1D ////////////////////////////////// ROOTEventOutput1D::ROOTEventOutput1D(std::string filename) { TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); Ntuple = new TNtuple("events", "CRPropa 1D events", - "Particle_Type:Energy_EeV:TrajectoryLength_Mpc:Initial_Type:Initial_Energy_EeV"); + "Particle_Type:Energy_EeV:TrajectoryLength_Mpc:Initial_Type:Initial_Energy_EeV"); TThread::UnLock(); } @@ -197,7 +194,6 @@ void ROOTEventOutput1D::process(Candidate *c) const { } //////////////////////////////////////////////////////////////////////////////// - /////////////////////// ROOT TRAJECTORY OUTPUT 1D ////////////////////////////// ROOTTrajectoryOutput1D::ROOTTrajectoryOutput1D(std::string filename) { TThread::Lock(); @@ -227,13 +223,14 @@ void ROOTTrajectoryOutput1D::process(Candidate *c) const { } //////////////////////////////////////////////////////////////////////////////// -/////////////////////// ROOT EVENT OUTPUT 3D ////////////////////////////////// +/////////////////////// ROOT EVENT OUTPUT 3D /////////////////////////////////// ROOTEventOutput3D::ROOTEventOutput3D(std::string filename) { TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); Ntuple = new TNtuple("events", "CRPropa 3D events", - "TrajectoryLength_Mpc:Particle_Type:Initial_Type:Momentum_E_EeV:Initial_Momentum_E_EeV:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Initial_Position_X_Mpc:Initial_Position_Y_Mpc:Initial_Position_Z_Mpc:Direction_X_Mpc:Direction_Y_Mpc:Direction_Z_Mpc:Initial_Direction_X_Mpc:Initial_Direction_Y_Mpc:Initial_Direction_Z_Mpc"); + "TrajectoryLength_Mpc:Particle_Type:Initial_Type:Momentum_E_EeV:Initial_Momentum_E_EeV:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Initial_Position_X_Mpc:Initial_Position_Y_Mpc:Initial_Position_Z_Mpc:Direction_X_Mpc:Direction_Y_Mpc:Direction_Z_Mpc"); + // Initial_Direction_X_Mpc:Initial_Direction_Y_Mpc:Initial_Direction_Z_Mpc TThread::UnLock(); } @@ -253,23 +250,23 @@ void ROOTEventOutput3D::process(Candidate *c) const { TThread::Lock(); #pragma omp critical { - // Ntuple->Fill(c->getTrajectoryLength() / Mpc, - // c->current.getId(), - // c->source.getId(), - // c->current.getEnergy() / EeV, - // c->source.getEnergy() / EeV, - // c->current.getPosition().getX() / Mpc, - // c->current.getPosition().getY() / Mpc, - // c->current.getPosition().getZ() / Mpc, - // c->source.getPosition().getX() / Mpc, - // c->source.getPosition().getY() / Mpc, - // c->source.getPosition().getZ() / Mpc, - // c->current.getDirection().getX() / Mpc, - // c->current.getDirection().getY() / Mpc, - // c->current.getDirection().getZ() / Mpc, - // c->source.getDirection().getX() / Mpc, - // c->source.getDirection().getY() / Mpc, - // c->source.getDirection().getZ() / Mpc); + Ntuple->Fill(c->getTrajectoryLength() / Mpc, // TrajectoryLength_Mpc + c->current.getId(), // Particle_Type + c->source.getId(), // Initial_Type + c->current.getEnergy() / EeV, // Momentum_E_EeV + c->source.getEnergy() / EeV, // Initial_Momentum_E_EeV + c->current.getPosition().x / Mpc, // Position_X_Mpc + c->current.getPosition().y / Mpc, // Position_Y_Mpc + c->current.getPosition().z / Mpc, // Position_Z_Mpc + c->source.getPosition().x / Mpc, // Initial_Position_X_Mpc + c->source.getPosition().y / Mpc, // Initial_Position_Y_Mpc + c->source.getPosition().z / Mpc, // Initial_Position_Z_Mpc + c->current.getDirection().x, // Direction_X_Mpc + c->current.getDirection().y, // Direction_Y_Mpc + c->current.getDirection().z); // Direction_Z_Mpc +// c->source.getDirection().x, // Initial_Direction_X_Mpc +// c->source.getDirection().y, // Initial_Direction_Y_Mpc +// c->source.getDirection().z); // Initial_Direction_Z_Mpc } TThread::UnLock(); } @@ -281,7 +278,7 @@ ROOTTrajectoryOutput3D::ROOTTrajectoryOutput3D(std::string filename) { ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); Ntuple = new TNtuple("traj", "CRPropa 3D trajectories", - "TrajectoryLength_Mpc:Particle_Type:Energy_EeV:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Direction_X_Mpc:Direction_Y_Mpc:Direction_Z_Mpc"); + "TrajectoryLength_Mpc:Particle_Type:Energy_EeV:Position_X_Mpc:Position_Y_Mpc:Position_Z_Mpc:Direction_X_Mpc:Direction_Y_Mpc:Direction_Z_Mpc"); TThread::UnLock(); } @@ -299,18 +296,17 @@ void ROOTTrajectoryOutput3D::process(Candidate *c) const { Ntuple->Fill(c->getTrajectoryLength() / Mpc, c->current.getId(), c->current.getEnergy() / EeV, - c->current.getPosition().getX() / Mpc, - c->current.getPosition().getY() / Mpc, - c->current.getPosition().getZ() / Mpc, - c->current.getDirection().getX(), - c->current.getDirection().getY(), - c->current.getDirection().getZ()); + c->current.getPosition().x / Mpc, + c->current.getPosition().y / Mpc, + c->current.getPosition().z / Mpc, + c->current.getDirection().x, + c->current.getDirection().y, + c->current.getDirection().z); } TThread::UnLock(); } //////////////////////////////////////////////////////////////////////////////// - -}// namespace crpropa +} // namespace crpropa #endif // CRPROPA_HAVE_ROOT From 22b9829949d877dcb91afb5d1c03e082ecab8407 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 31 Jul 2013 18:38:38 +0200 Subject: [PATCH 0332/1298] fixes in xml execute --- src/XmlExecute.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index e846e27e0..eb925bc50 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -222,11 +222,11 @@ bool XmlExecute::load(const string &filename) { double omegaL = 0.7; if (root.child("OmegaLambda")) - childValue(root, "OmegaLambda"); + omegaL = childValue(root, "OmegaLambda"); double H0 = 70.; if (root.child("H0_km_s_Mpc")) - childValue(root, "H0_km_s_Mpc"); + H0 = childValue(root, "H0_km_s_Mpc"); cout << "Cosmology: OmegaM = " << omegaM << ", OmegaLambda = " << 1 - omegaM << ", H0 = " << H0 << " km/s/Mpc" << endl; @@ -562,7 +562,7 @@ void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { // 1D double dlt = childValue(n, "CoordX_Mpc") * Mpc; pos.x = lightTravel2ComovingDistance(dlt); - cout << " - Light travel distance = " << dlt << " Mpc" << endl; + cout << " - Light travel distance = " << dlt / Mpc << " Mpc" << endl; } else { // 3D pos.x = childValue(n, "CoordX_Mpc") * Mpc; From 10da8f00adc962c18be8b55e0c3af10dba38d2df Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 31 Jul 2013 18:46:54 +0200 Subject: [PATCH 0333/1298] add descriptions to ROOT Output --- src/module/OutputROOT.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/module/OutputROOT.cpp b/src/module/OutputROOT.cpp index 613a34eba..ff2176a40 100644 --- a/src/module/OutputROOT.cpp +++ b/src/module/OutputROOT.cpp @@ -7,11 +7,12 @@ namespace crpropa { /////////////////////// CRPropa2ROOT EVENT OUTPUT 1D /////////////////////////// CRPropa2ROOTEventOutput1D::CRPropa2ROOTEventOutput1D(std::string filename) { + setDescription("CRPropa2ROOTEventOutput1D, filename: " + filename); TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa 2 output data file"); Ntuple = new TNtuple("events", "CRPropa 1D events", - "Particle_Type:Initial_Type:Initial_Position_Mpc:Initial_Energy_EeV:Energy_EeV"); + "Particle_Type:Initial_Type:Initial_Position_Mpc:Initial_Energy_EeV:Energy_EeV"); TThread::UnLock(); } @@ -43,6 +44,7 @@ void CRPropa2ROOTEventOutput1D::process(Candidate *c) const { /////////////////////// CRPropa2ROOT TRAJECTORY OUTPUT 1D ////////////////////// CRPropa2ROOTTrajectoryOutput1D::CRPropa2ROOTTrajectoryOutput1D(std::string filename) { + setDescription("CRPropa2ROOTTrajectoryOutput1D, filename: " + filename); TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa 2 output data file"); @@ -73,6 +75,7 @@ void CRPropa2ROOTTrajectoryOutput1D::process(Candidate *c) const { /////////////////////// CRPropa2ROOT EVENT OUTPUT 3D /////////////////////////// CRPropa2ROOTEventOutput3D::CRPropa2ROOTEventOutput3D(std::string filename) { + setDescription("CRPropa2ROOTEventOutput3D, filename: " + filename); TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa 2 output data file"); @@ -121,6 +124,7 @@ void CRPropa2ROOTEventOutput3D::process(Candidate *c) const { /////////////////////// CRPropa2ROOT TRAJECTORY OUTPUT 3D ////////////////////// CRPropa2ROOTTrajectoryOutput3D::CRPropa2ROOTTrajectoryOutput3D(std::string filename) { + setDescription("CRPropa2ROOTTrajectoryOutput3D, filename: " + filename); TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa 2 output data file"); @@ -159,6 +163,7 @@ void CRPropa2ROOTTrajectoryOutput3D::process(Candidate *c) const { /////////////////////// ROOT EVENT OUTPUT 1D ////////////////////////////////// ROOTEventOutput1D::ROOTEventOutput1D(std::string filename) { + setDescription("ROOTEventOutput1D, filename: " + filename); TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); @@ -196,6 +201,7 @@ void ROOTEventOutput1D::process(Candidate *c) const { /////////////////////// ROOT TRAJECTORY OUTPUT 1D ////////////////////////////// ROOTTrajectoryOutput1D::ROOTTrajectoryOutput1D(std::string filename) { + setDescription("ROOTTrajectoryOutput1D, filename: " + filename); TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); @@ -225,6 +231,7 @@ void ROOTTrajectoryOutput1D::process(Candidate *c) const { /////////////////////// ROOT EVENT OUTPUT 3D /////////////////////////////////// ROOTEventOutput3D::ROOTEventOutput3D(std::string filename) { + setDescription("ROOTEventOutput3D, filename: " + filename); TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); @@ -274,6 +281,7 @@ void ROOTEventOutput3D::process(Candidate *c) const { /////////////////////// ROOT TRAJECTORY OUTPUT 3D ////////////////////////////// ROOTTrajectoryOutput3D::ROOTTrajectoryOutput3D(std::string filename) { + setDescription("ROOTTrajectoryOutput3D, filename: " + filename); TThread::Lock(); ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); From 1f3afdb21d1f6671e1a4b65ff6346d016b5a896d Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 27 Aug 2013 16:26:04 +0200 Subject: [PATCH 0334/1298] doxygen SOURCE_BROWSER=YES --- doc/Doxyfile | 4 ++-- src/module/ElectronPairProduction.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/Doxyfile b/doc/Doxyfile index 0aea38d3a..f486c0bb6 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -786,7 +786,7 @@ USE_MDFILE_AS_MAINPAGE = # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. -SOURCE_BROWSER = NO +SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. @@ -830,7 +830,7 @@ USE_HTAGS = NO # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. -VERBATIM_HEADERS = YES +VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 0ed1d495f..5af3292eb 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -85,7 +85,8 @@ void ElectronPairProduction::process(Candidate *candidate) const { double step = candidate->getCurrentStep() / (1 + z); // dE(E) = Z^2 * loss_rate(E/A) * step - double dE = Z * Z * rate * photonDensityScaling(photonField, z) * step; +// double dE = Z * Z * rate * photonDensityScaling(photonField, z) * step; + double dE = Z * Z * rate * pow(1 + z, 2) * step; // prevent the energy loss from exceeding the actual energy dE = std::min(E, dE); From aecf10d7ea267a32e3ce384c5cc35f25910f91d8 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 27 Aug 2013 17:19:10 +0200 Subject: [PATCH 0335/1298] renamed convertToCRPropaId to convertToCRPropa2NucleusId added comment on -DCMAKE_INSTALL_PREFIX in README --- README | 1 + include/crpropa/ParticleID.h | 4 ++-- src/ParticleID.cpp | 6 ++++-- src/module/OutputCRPropa2.cpp | 14 +++++++------- src/module/OutputROOT.cpp | 12 ++++++------ test/testCore.cpp | 4 ++-- 6 files changed, 22 insertions(+), 19 deletions(-) diff --git a/README b/README index 9e11c97d3..421c0f2a4 100644 --- a/README +++ b/README @@ -9,6 +9,7 @@ CRPropa is configured using CMAKE - for more information see www.cmake.org 5) >> make test [to run all unit tests when gtest is available] 7) >> make install +The install path can be set with -DCMAKE_INSTALL_PREFIX=/my/path or with the option browser when using ccmake. Notes for Intel Compiler: use -DCMAKE_SHARED_LINKER_FLAGS="-lifcore" -DCMAKE_Fortran_COMPILER=ifort diff --git a/include/crpropa/ParticleID.h b/include/crpropa/ParticleID.h index 7adec8d77..687a05901 100644 --- a/include/crpropa/ParticleID.h +++ b/include/crpropa/ParticleID.h @@ -21,8 +21,8 @@ int chargeNumberFromNucleusId(int id); int massNumberFromNucleusId(int id); /* CRPropa2.0 code scheme */ -int convertFromCRPropaId(int id); -int convertToCRPropaId(int id); +int convertFromCRPropa2NucleusId(int id); +int convertToCRPropa2NucleusId(int id); } // namespace crpropa diff --git a/src/ParticleID.cpp b/src/ParticleID.cpp index 0d67c52e3..2b49675ee 100644 --- a/src/ParticleID.cpp +++ b/src/ParticleID.cpp @@ -41,13 +41,15 @@ int massNumberFromNucleusId(int id) { return HepPID::A(id); } -int convertFromCRPropaId(int crp_id) { +int convertFromCRPropa2NucleusId(int crp_id) { int Z = crp_id / 1000; int A = crp_id % 1000; return nucleusId(A, Z); } -int convertToCRPropaId(int id) { +int convertToCRPropa2NucleusId(int id) { + if (not HepPID::isNucleus(id)) // if not nucleus, just return the id + return id; int Z = chargeNumberFromNucleusId(id); int A = massNumberFromNucleusId(id); return Z * 1000 + A; diff --git a/src/module/OutputCRPropa2.cpp b/src/module/OutputCRPropa2.cpp index 41cd63ce7..36f808424 100644 --- a/src/module/OutputCRPropa2.cpp +++ b/src/module/OutputCRPropa2.cpp @@ -30,8 +30,8 @@ void CRPropa2EventOutput3D::process(Candidate *c) const { char buffer[256]; // max. 256 characters per line size_t p = 0; // length of line - p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->current.getId())); - p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->source.getId())); + p += sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->current.getId())); + p += sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->source.getId())); const Vector3d &ipos = c->source.getPosition() / Mpc; p += sprintf(buffer + p, "%.4f %.4f %.4f ", ipos.x, ipos.y, ipos.z); @@ -79,8 +79,8 @@ void CRPropa2TrajectoryOutput3D::process(Candidate *c) const { char buffer[256]; size_t p = 0; - p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->current.getId())); - p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->source.getId())); + p += sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->current.getId())); + p += sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->source.getId())); double t = comoving2LightTravelDistance(c->getTrajectoryLength()) / Mpc; p += sprintf(buffer + p, "%.4f ", t); @@ -118,7 +118,7 @@ void CRPropa2TrajectoryOutput1D::process(Candidate *c) const { size_t p = 0; p += sprintf(buffer + p, "%.4f ", comoving2LightTravelDistance(c->current.getPosition().x) / Mpc); - p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->current.getId())); + p += sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->current.getId())); p += sprintf(buffer + p, "%.4f\n", c->current.getEnergy() / EeV); #pragma omp critical @@ -152,11 +152,11 @@ void CRPropa2EventOutput1D::process(Candidate *c) const { char buffer[256]; size_t p = 0; - p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->current.getId())); + p += sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->current.getId())); p += sprintf(buffer + p, "%.4f ", c->current.getEnergy() / EeV); double t = comoving2LightTravelDistance(c->getTrajectoryLength()) / Mpc; p += sprintf(buffer + p, "%.4f ", t); - p += sprintf(buffer + p, "%i ", convertToCRPropaId(c->source.getId())); + p += sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->source.getId())); p += sprintf(buffer + p, "%.4f\n", c->source.getEnergy() / EeV); #pragma omp critical diff --git a/src/module/OutputROOT.cpp b/src/module/OutputROOT.cpp index ff2176a40..8de322072 100644 --- a/src/module/OutputROOT.cpp +++ b/src/module/OutputROOT.cpp @@ -32,8 +32,8 @@ void CRPropa2ROOTEventOutput1D::process(Candidate *c) const { TThread::Lock(); #pragma omp critical { - Ntuple->Fill(convertToCRPropaId(c->current.getId()), - convertToCRPropaId(c->source.getId()), + Ntuple->Fill(convertToCRPropa2NucleusId(c->current.getId()), + convertToCRPropa2NucleusId(c->source.getId()), comoving2LightTravelDistance(c->source.getPosition().x) / Mpc, c->source.getEnergy() / EeV, c->current.getEnergy() / EeV); @@ -64,8 +64,8 @@ void CRPropa2ROOTTrajectoryOutput1D::process(Candidate *c) const { TThread::Lock(); #pragma omp critical { - Ntuple->Fill(convertToCRPropaId(c->current.getId()), - convertToCRPropaId(c->source.getId()), + Ntuple->Fill(convertToCRPropa2NucleusId(c->current.getId()), + convertToCRPropa2NucleusId(c->source.getId()), comoving2LightTravelDistance(c->current.getPosition().x) / Mpc, c->current.getEnergy() / EeV); } @@ -102,8 +102,8 @@ void CRPropa2ROOTEventOutput3D::process(Candidate *c) const { TThread::Lock(); #pragma omp critical { - Ntuple->Fill(convertToCRPropaId(c->current.getId()), - convertToCRPropaId(c->source.getId()), + Ntuple->Fill(convertToCRPropa2NucleusId(c->current.getId()), + convertToCRPropa2NucleusId(c->source.getId()), comoving2LightTravelDistance(ipos.x) / Mpc, comoving2LightTravelDistance(ipos.y) / Mpc, comoving2LightTravelDistance(ipos.z) / Mpc, diff --git a/test/testCore.cpp b/test/testCore.cpp index d0b888ff0..e82446601 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -210,8 +210,8 @@ TEST(common, interpolateEquidistant) { TEST(NucleusId, crpropaScheme) { // test conversion to and from the CRPropa2 naming scheme - EXPECT_EQ(nucleusId(56, 26), convertFromCRPropaId(26056)); - EXPECT_EQ(26056, convertToCRPropaId(nucleusId(56, 26))); + EXPECT_EQ(nucleusId(56, 26), convertFromCRPropa2NucleusId(26056)); + EXPECT_EQ(26056, convertToCRPropa2NucleusId(nucleusId(56, 26))); } TEST(Random, seed) { From 5eb557931b448b4c745cea363613fdc1619f318d Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 23 Sep 2013 14:15:21 +0200 Subject: [PATCH 0336/1298] ParticleState: prevent negative energies --- src/ParticleState.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index 943892f65..18ec7f228 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -1,7 +1,9 @@ #include "crpropa/ParticleState.h" #include + #include +#include namespace crpropa { @@ -27,7 +29,7 @@ const Vector3d &ParticleState::getDirection() const { } void ParticleState::setEnergy(double newEnergy) { - energy = newEnergy; + energy = std::max(0, newEnergy); // prevent negative energies } double ParticleState::getEnergy() const { From 5732d39fdb4ef502ffd614b676d72f9dce6e8a9d Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 23 Sep 2013 14:40:17 +0200 Subject: [PATCH 0337/1298] ElectronPairProduction: rate_A,Z ~ rate_p * Z*Z/A --- src/module/ElectronPairProduction.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 5af3292eb..cc2a5c924 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -61,7 +61,7 @@ void ElectronPairProduction::init(std::string filename) { void ElectronPairProduction::process(Candidate *candidate) const { if (not(candidate->current.isNucleus())) - return; // this module only handles nucleons / nuclei + return; // this module only handles nucleons and nuclei double Z = candidate->current.getChargeNumber(); double A = candidate->current.getMassNumber(); @@ -75,21 +75,25 @@ void ElectronPairProduction::process(Candidate *candidate) const { if (EpA < energy.front()) return; // below energy threshold + // evaluate energy loss rate for proton double rate; if (EpA < energy.back()) - rate = interpolate(EpA, energy, lossRate); + rate = interpolate(EpA, energy, lossRate); // interpolation else rate = lossRate.back() * pow(EpA / energy.back(), 0.4); // extrapolation + // modify loss rate for nuclei + // cf. Kampert et al. 2013, eq. 5 + // http://dx.doi.org/10.1016/j.astropartphys.2012.12.001 + rate *= Z * Z / A; + + // effect of photon evolution on loss rate + rate *= photonDensityScaling(photonField, z); + // convert step size to local frame: dx = dx_com / (1 + z) double step = candidate->getCurrentStep() / (1 + z); - // dE(E) = Z^2 * loss_rate(E/A) * step -// double dE = Z * Z * rate * photonDensityScaling(photonField, z) * step; - double dE = Z * Z * rate * pow(1 + z, 2) * step; - - // prevent the energy loss from exceeding the actual energy - dE = std::min(E, dE); + double dE = rate * step; candidate->current.setEnergy(E - dE); } @@ -110,7 +114,7 @@ double ElectronPairProduction::energyLossLength(int id, double E) { else rate = lossRate.back() * pow(EpA / energy.back(), 0.4); - double lossRate = Z * Z * rate / E; + double lossRate = Z * Z / A * rate / E; return 1. / lossRate; } From fc0ad3977d19c0f0d9929da2670e3c9111df1b87 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 24 Sep 2013 17:16:25 +0200 Subject: [PATCH 0338/1298] Refactored electron pair production --- include/crpropa/ParticleState.h | 4 +- include/crpropa/PhotonBackground.h | 3 + .../crpropa/module/ElectronPairProduction.h | 25 +++++-- src/ParticleState.cpp | 2 +- src/PhotonBackground.cpp | 8 +- src/module/ElectronPairProduction.cpp | 73 ++++++------------- 6 files changed, 55 insertions(+), 60 deletions(-) diff --git a/include/crpropa/ParticleState.h b/include/crpropa/ParticleState.h index abd546d14..34bf698ea 100644 --- a/include/crpropa/ParticleState.h +++ b/include/crpropa/ParticleState.h @@ -25,8 +25,8 @@ class ParticleState { Vector3d position; /*< position vector in comoving coordinates */ Vector3d direction; /*< unit vector of velocity or momentum */ - double pmass; - double charge; + double pmass; /*< particle rest mass */ + double charge; /*< particle charge */ public: ParticleState(); diff --git a/include/crpropa/PhotonBackground.h b/include/crpropa/PhotonBackground.h index c00085ffa..9a5bb1901 100644 --- a/include/crpropa/PhotonBackground.h +++ b/include/crpropa/PhotonBackground.h @@ -11,6 +11,9 @@ enum PhotonField { // Returns overall photon field scaling factor at redshift z double photonDensityScaling(int photonField, double z); +// Returns overall scaling factor for loss rates dE/dt at redshift z +double lossRateScaling(PhotonField photonField, double z); + } // namespace crpropa #endif // CRPROPA_PHOTONBACKGROUND_H diff --git a/include/crpropa/module/ElectronPairProduction.h b/include/crpropa/module/ElectronPairProduction.h index 88b76ec35..0f2a99214 100644 --- a/include/crpropa/module/ElectronPairProduction.h +++ b/include/crpropa/module/ElectronPairProduction.h @@ -11,13 +11,14 @@ namespace crpropa { @brief Electron-pair production of charged nuclei with background photons. This module simulates electron-pair production as a continuous energy loss.\n - Several photon fields can be selected. They are considered homogeneous and evolving as the CMB. + Several photon fields can be selected. + Secondary electrons are not created. */ class ElectronPairProduction: public Module { private: PhotonField photonField; - std::vector lossRate; // energy loss rate in [J/m] - std::vector energy; + std::vector tabLossRate; /*< tabulated energy loss rate in [J/m] for protons at z = 0*/ + std::vector tabEnergy; /*< tabulated proton energy [J] */ public: ElectronPairProduction(PhotonField photonField = CMB_IRB); @@ -27,11 +28,23 @@ class ElectronPairProduction: public Module { void process(Candidate *candidate) const; /** - Calculates the energy loss length 1/E dE/dx in [m] + Calculates the energy loss rate dE/dx in [J/m] @param id PDG particle id - @param energy particle energy [J] + @param E energy [J] + @param z redshift + + The energy loss rate b(E) = -dE/dt is tabulated for protons against + CMB, IRB and CMB+IRB photon backgrounds. + + For nuclei this loss rate is modified as (cf. 10.1016/j.astropartphys.2012.07.010, eq. 5) + b_A,Z(E) = Z^2/A * b_p(E/A). + + Cosmological evolution of the photon background is considered with (cf. 10.1103/PhysRevD.74.043005, eq. 5) + b(E,z) = (1+z)^2 b((1+z)E). + Note that the energy loss length beta(E) = -1/E dE/dt evolves as + beta(E,z) = (1+z)^3 beta((1+z)E). */ - double energyLossLength(int id, double energy); + double lossRate(int id, double E, double z) const; }; } // namespace crpropa diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index 18ec7f228..d3dd37580 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -29,7 +29,7 @@ const Vector3d &ParticleState::getDirection() const { } void ParticleState::setEnergy(double newEnergy) { - energy = std::max(0, newEnergy); // prevent negative energies + energy = std::max(0., newEnergy); // prevent negative energies } double ParticleState::getEnergy() const { diff --git a/src/PhotonBackground.cpp b/src/PhotonBackground.cpp index 1eb71ef8f..6d48da2f2 100644 --- a/src/PhotonBackground.cpp +++ b/src/PhotonBackground.cpp @@ -15,7 +15,13 @@ static std::vector sKneiske(b, b + sizeof(b) / sizeof(double)); double photonDensityScaling(int photonField, double z) { if (photonField == IRB) return interpolate(z, zKneiske, sKneiske); - return pow(1 + z, 3); // CMB-like scaling + return pow(1 + z, 2); // CMB-like scaling +} + +double lossRateScaling(PhotonField photonField, double z) { + if (photonField == IRB) + return interpolate(z, zKneiske, sKneiske); + return pow(1 + z, 2); // CMB-like scaling } } // namespace crpropa diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index cc2a5c924..33a8147ff 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -1,4 +1,5 @@ #include "crpropa/module/ElectronPairProduction.h" +#include "crpropa/ParticleID.h" #include #include @@ -37,21 +38,19 @@ void ElectronPairProduction::init() { } void ElectronPairProduction::init(std::string filename) { - // load energy loss rate table std::ifstream infile(filename.c_str()); if (!infile.good()) throw std::runtime_error( "ElectronPairProduction: could not open file " + filename); - std::vector x, y; while (infile.good()) { if (infile.peek() != '#') { double a, b; infile >> a >> b; if (infile) { - energy.push_back(a * eV); - lossRate.push_back(b * eV / Mpc); + tabEnergy.push_back(a * eV); + tabLossRate.push_back(b * eV / Mpc); } } infile.ignore(std::numeric_limits::max(), '\n'); @@ -59,63 +58,37 @@ void ElectronPairProduction::init(std::string filename) { infile.close(); } -void ElectronPairProduction::process(Candidate *candidate) const { - if (not(candidate->current.isNucleus())) - return; // this module only handles nucleons and nuclei - - double Z = candidate->current.getChargeNumber(); - double A = candidate->current.getMassNumber(); - double E = candidate->current.getEnergy(); - double z = candidate->getRedshift(); - double EpA = E / A * (1 + z); +double ElectronPairProduction::lossRate(int id, double E, double z) const { + double A = massNumberFromNucleusId(id); + double Z = chargeNumberFromNucleusId(id); if (Z < 1) - return; // no electron pair production on uncharged particles + return 0; // no pair production on uncharged particles - if (EpA < energy.front()) - return; // below energy threshold + double Eeff = E / A * (1 + z); + if (Eeff < tabEnergy.front()) + return 0; // below energy threshold - // evaluate energy loss rate for proton double rate; - if (EpA < energy.back()) - rate = interpolate(EpA, energy, lossRate); // interpolation + if (Eeff < tabEnergy.back()) + rate = interpolate(Eeff, tabEnergy, tabLossRate);// interpolation else - rate = lossRate.back() * pow(EpA / energy.back(), 0.4); // extrapolation + rate = tabLossRate.back() * pow(Eeff / tabEnergy.back(), 0.4); // extrapolation - // modify loss rate for nuclei - // cf. Kampert et al. 2013, eq. 5 - // http://dx.doi.org/10.1016/j.astropartphys.2012.12.001 - rate *= Z * Z / A; - - // effect of photon evolution on loss rate - rate *= photonDensityScaling(photonField, z); - - // convert step size to local frame: dx = dx_com / (1 + z) - double step = candidate->getCurrentStep() / (1 + z); - - double dE = rate * step; - candidate->current.setEnergy(E - dE); + return rate * Z * Z / A * lossRateScaling(photonField, z); } -double ElectronPairProduction::energyLossLength(int id, double E) { - double A = massNumberFromNucleusId(id); - double Z = chargeNumberFromNucleusId(id); - - if (Z < 1) - return std::numeric_limits::max(); - - double EpA = E / A; - if (EpA < energy.front()) - return std::numeric_limits::max(); +void ElectronPairProduction::process(Candidate *c) const { + if (not(c->current.isNucleus())) + return; // this module only handles nucleons and nuclei - double rate; - if (EpA < energy.back()) - rate = interpolate(EpA, energy, lossRate); - else - rate = lossRate.back() * pow(EpA / energy.back(), 0.4); + int id = c->current.getId(); + double E = c->current.getEnergy(); + double z = c->getRedshift(); + double step = c->getCurrentStep() / (1 + z); // step size in local frame + double dE = lossRate(id, E, z) * step; - double lossRate = Z * Z / A * rate / E; - return 1. / lossRate; + c->current.setEnergy(E - dE); } } // namespace crpropa From ff0d60713f462c260a44c616ae4b0980dd8eebbe Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 24 Sep 2013 17:51:11 +0200 Subject: [PATCH 0339/1298] refactored ParticleState: removed mass and charge number methods --- include/crpropa/ParticleID.h | 1 + include/crpropa/ParticleState.h | 7 ---- src/ParticleID.cpp | 4 +++ src/ParticleState.cpp | 12 ------- src/module/ElectronPairProduction.cpp | 4 +-- src/module/NuclearDecay.cpp | 21 ++++++----- src/module/PhotoDisintegration.cpp | 13 ++++--- src/module/PhotoPionProduction.cpp | 42 +++++++++++----------- test/testCore.cpp | 6 ---- test/testInteraction.cpp | 50 +++++++++++++++------------ test/testSource.cpp | 20 +++++------ 11 files changed, 84 insertions(+), 96 deletions(-) diff --git a/include/crpropa/ParticleID.h b/include/crpropa/ParticleID.h index 687a05901..9722d520e 100644 --- a/include/crpropa/ParticleID.h +++ b/include/crpropa/ParticleID.h @@ -19,6 +19,7 @@ std::vector leptons(); int nucleusId(int a, int z); int chargeNumberFromNucleusId(int id); int massNumberFromNucleusId(int id); +bool isNucleus(int id); /* CRPropa2.0 code scheme */ int convertFromCRPropa2NucleusId(int id); diff --git a/include/crpropa/ParticleState.h b/include/crpropa/ParticleState.h index 34bf698ea..900686a50 100644 --- a/include/crpropa/ParticleState.h +++ b/include/crpropa/ParticleState.h @@ -58,13 +58,6 @@ class ParticleState { Vector3d getVelocity() const; /* Momentum: direction times energy divided by the speed of light */ Vector3d getMomentum() const; - - /* Check if the particle is a (anti-)nucleus */ - bool isNucleus() const; - /* If nucleus, return the charge number Z (apositive for anti-nuclei) */ - int getChargeNumber() const; - /* If nucleus, return the mass number A (also positive for anti-nuclei) */ - int getMassNumber() const; }; } // namespace crpropa diff --git a/src/ParticleID.cpp b/src/ParticleID.cpp index 2b49675ee..ae9b19e8b 100644 --- a/src/ParticleID.cpp +++ b/src/ParticleID.cpp @@ -41,6 +41,10 @@ int massNumberFromNucleusId(int id) { return HepPID::A(id); } +bool isNucleus(int id) { + return HepPID::isNucleus(id); +} + int convertFromCRPropa2NucleusId(int crp_id) { int Z = crp_id / 1000; int A = crp_id % 1000; diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index d3dd37580..d99735697 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -60,18 +60,6 @@ double ParticleState::getCharge() const { return charge; } -int ParticleState::getChargeNumber() const { - return HepPID::Z(id); -} - -int ParticleState::getMassNumber() const { - return HepPID::A(id); -} - -bool ParticleState::isNucleus() const { - return HepPID::isNucleus(id); -} - double ParticleState::getLorentzFactor() const { if (HepPID::isNucleus(id)) return energy / (pmass * c_squared); diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 33a8147ff..6bb579a39 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -79,10 +79,10 @@ double ElectronPairProduction::lossRate(int id, double E, double z) const { } void ElectronPairProduction::process(Candidate *c) const { - if (not(c->current.isNucleus())) + int id = c->current.getId(); + if (not(isNucleus(id))) return; // this module only handles nucleons and nuclei - int id = c->current.getId(); double E = c->current.getEnergy(); double z = c->getRedshift(); double step = c->getCurrentStep() / (1 + z); // step size in local frame diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index 2a7678d3b..02383a2ce 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -1,4 +1,5 @@ #include "crpropa/module/NuclearDecay.h" +#include "crpropa/ParticleID.h" #include "crpropa/Random.h" #include @@ -57,11 +58,12 @@ void NuclearDecay::setHaveNeutrinos(bool b) { bool NuclearDecay::setNextInteraction(Candidate *candidate, InteractionState &interaction) const { - if (not(candidate->current.isNucleus())) + int id = candidate->current.getId(); + if (not(isNucleus(id))) return false; // accept only nuclei - int A = candidate->current.getMassNumber(); - int Z = candidate->current.getChargeNumber(); + int A = massNumberFromNucleusId(id); + int Z = chargeNumberFromNucleusId(id); int N = A - Z; std::vector decays = decayTable[Z * 31 + N]; @@ -113,8 +115,9 @@ void NuclearDecay::performInteraction(Candidate *candidate) const { void NuclearDecay::betaDecay(Candidate *candidate, bool isBetaPlus) const { double gamma = candidate->current.getLorentzFactor(); - int Z = candidate->current.getChargeNumber(); - int A = candidate->current.getMassNumber(); + int id = candidate->current.getId(); + int A = massNumberFromNucleusId(id); + int Z = chargeNumberFromNucleusId(id); double mass = candidate->current.getMass(); // beta- decay @@ -153,10 +156,10 @@ void NuclearDecay::betaDecay(Candidate *candidate, bool isBetaPlus) const { } void NuclearDecay::nucleonEmission(Candidate *candidate, int dA, int dZ) const { - int Z = candidate->current.getChargeNumber(); - int A = candidate->current.getMassNumber(); - double EpA = candidate->current.getEnergy() - / double(candidate->current.getMassNumber()); + int id = candidate->current.getId(); + int A = massNumberFromNucleusId(id); + int Z = chargeNumberFromNucleusId(id); + double EpA = candidate->current.getEnergy() / double(A); candidate->current.setId(nucleusId(A - dA, Z - dZ)); candidate->current.setEnergy(EpA * (A - dA)); candidate->addSecondary(nucleusId(dA, dZ), EpA * dA); diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 9e9e00572..0951d1933 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -1,4 +1,5 @@ #include "crpropa/module/PhotoDisintegration.h" +#include "crpropa/ParticleID.h" #include "crpropa/Random.h" #include @@ -70,11 +71,12 @@ void PhotoDisintegration::init(std::string filename) { bool PhotoDisintegration::setNextInteraction(Candidate *candidate, InteractionState &interaction) const { - if (not(candidate->current.isNucleus())) + int id = candidate->current.getId(); + if (not(isNucleus(id))) return false; // accept only nuclei - int A = candidate->current.getMassNumber(); - int Z = candidate->current.getChargeNumber(); + int A = massNumberFromNucleusId(id); + int Z = chargeNumberFromNucleusId(id); int N = A - Z; // check if disintegration data available @@ -125,8 +127,9 @@ void PhotoDisintegration::performInteraction(Candidate *candidate) const { int dA = -nNeutron - nProton - 2 * nH2 - 3 * nH3 - 3 * nHe3 - 4 * nHe4; int dZ = -nProton - nH2 - nH3 - 2 * nHe3 - 2 * nHe4; - int A = candidate->current.getMassNumber(); - int Z = candidate->current.getChargeNumber(); + int id = candidate->current.getId(); + int A = massNumberFromNucleusId(id); + int Z = chargeNumberFromNucleusId(id); double EpA = candidate->current.getEnergy() / double(A); // update particle diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index a91896279..6b81f13b7 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -1,4 +1,5 @@ #include "crpropa/module/PhotoPionProduction.h" +#include "crpropa/ParticleID.h" #include "crpropa/Random.h" #include @@ -58,18 +59,19 @@ void PhotoPionProduction::init(std::string filename) { bool PhotoPionProduction::setNextInteraction(Candidate *candidate, InteractionState &interaction) const { - if (not (candidate->current.isNucleus())) + int id = candidate->current.getId(); + if (not(isNucleus(id))) return false; // accept only nuclei double z = candidate->getRedshift(); double E = candidate->current.getEnergy(); - int A = candidate->current.getMassNumber(); - int Z = candidate->current.getChargeNumber(); + int A = massNumberFromNucleusId(id); + int Z = chargeNumberFromNucleusId(id); int N = A - Z; - double EpA = E / A * (1 + z); // CMB photon energies increase with (1+z) + double Eeff = E / A * (1 + z); // effective energy per nucleon at redshift z // check if out of energy range - if ((EpA < energy.front()) or (EpA > energy.back())) + if ((Eeff < energy.front()) or (Eeff > energy.back())) return false; // find interaction with minimum random distance @@ -78,7 +80,7 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, // check for interaction on protons if (Z > 0) { - double rate = interpolate(EpA, energy, pRate); + double rate = interpolate(Eeff, energy, pRate); if (rate > 0) { if (A > 1) { if (A < 8) @@ -93,7 +95,7 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, // check for interaction on neutrons if (N > 0) { - double rate = interpolate(EpA, energy, nRate); + double rate = interpolate(Eeff, energy, nRate); if (rate > 0) { if (A > 1) { if (A < 8) @@ -132,8 +134,9 @@ void PhotoPionProduction::performInteraction(Candidate *candidate) const { Zfinal = abs(Zfinal - 1); double E = candidate->current.getEnergy(); - int A = candidate->current.getMassNumber(); - int Z = candidate->current.getChargeNumber(); + int id = candidate->current.getId(); + int A = massNumberFromNucleusId(id); + int Z = chargeNumberFromNucleusId(id); if (A == 1) { // interaction on single nucleon @@ -204,9 +207,10 @@ void SophiaPhotoPionProduction::setHaveAntiNucleons(bool b) { } void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { + int id = candidate->current.getId(); + int A = massNumberFromNucleusId(id); + int Z = chargeNumberFromNucleusId(id); double E = candidate->current.getEnergy(); - int A = candidate->current.getMassNumber(); - int Z = candidate->current.getChargeNumber(); double EpA = E / A; double redshift = candidate->getRedshift(); @@ -232,8 +236,8 @@ void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { int particleList[2000]; // particle id list int nParticles; // number of outgoing particles double maxRedshift = 100; // IR photon density is zero above this redshift - int dummy1; // unneeded - double dummy2[2]; // unneeded + int dummy1; // not needed + double dummy2[2]; // not needed int background = (photonField == CMB) ? 1 : 2; // photon background: 1 for CMB, 2 for Kneiske IRB #pragma omp critical @@ -249,22 +253,20 @@ void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { switch (pType) { case 13: // proton case 14: // neutron - if (A == 1) { // in-going particle was a nucleon: update its properties + if (A == 1) { // single interacting nucleon candidate->current.setEnergy(Eout); candidate->current.setId(nucleusId(1, 14 - pType)); - } else { // in-going particle was a nucleus: update nucleus and emit nucleon - candidate->current.setEnergy(E - Eout); + } else { // interacting nucleon is part of nucleus: it is emitted from the nucleus + candidate->current.setEnergy(E - EpA); candidate->current.setId(nucleusId(A - 1, Z - channel)); candidate->addSecondary(nucleusId(1, 14 - pType), Eout); } break; case -13: // anti-proton - if (haveAntiNucleons) - candidate->addSecondary(-nucleusId(1, 1), Eout); - break; case -14: // anti-neutron + std::cout << "Antiproton/-neutron produced" << std::endl; if (haveAntiNucleons) - candidate->addSecondary(-nucleusId(1, 0), Eout); + candidate->addSecondary(-nucleusId(1, 14 - pType), Eout); break; case 1: // photon if (havePhotons) diff --git a/test/testCore.cpp b/test/testCore.cpp index e82446601..5700a765a 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -63,11 +63,9 @@ TEST(ParticleState, Charge) { ParticleState particle; particle.setId(nucleusId(56, 26)); // iron - EXPECT_EQ(26, particle.getChargeNumber()); EXPECT_DOUBLE_EQ(26 * eplus, particle.getCharge()); particle.setId(-nucleusId(56, 26)); // anti-iron - EXPECT_EQ(26, particle.getChargeNumber()); EXPECT_DOUBLE_EQ(-26 * eplus, particle.getCharge()); particle.setId(11); // electron @@ -87,20 +85,16 @@ TEST(ParticleState, Mass) { ParticleState particle; particle.setId(nucleusId(1, 1)); // proton - EXPECT_EQ(1, particle.getMassNumber()); EXPECT_DOUBLE_EQ(mass_proton, particle.getMass()); particle.setId(nucleusId(1, 0)); // neutron - EXPECT_EQ(1, particle.getMassNumber()); EXPECT_DOUBLE_EQ(mass_neutron, particle.getMass()); int id = nucleusId(56, 26); particle.setId(id); // iron - EXPECT_EQ(56, particle.getMassNumber()); EXPECT_DOUBLE_EQ(nucleusMass(id), particle.getMass()); particle.setId(-id); // anti-iron - EXPECT_EQ(56, particle.getMassNumber()); EXPECT_DOUBLE_EQ(nucleusMass(-id), particle.getMass()); } diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 38899b8a6..c22dfcdc8 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -4,6 +4,7 @@ #include "crpropa/module/PhotoDisintegration.h" #include "crpropa/module/PhotoPionProduction.h" #include "crpropa/module/Redshift.h" +#include "crpropa/ParticleID.h" #include "gtest/gtest.h" #include @@ -287,7 +288,8 @@ TEST(PhotoDisintegration, Carbon) { // This test can stochastically fail if no interaction occurs over 50 Mpc. PhotoDisintegration pd; Candidate c; - c.current.setId(nucleusId(12, 6)); + int id = nucleusId(12, 6); + c.current.setId(id); c.current.setEnergy(100 * EeV); c.setCurrentStep(50 * Mpc); pd.process(&c); @@ -297,14 +299,16 @@ TEST(PhotoDisintegration, Carbon) { EXPECT_TRUE(c.secondaries.size() > 0); // secondaries produced - int A = c.current.getMassNumber(); - int Z = c.current.getChargeNumber(); double E = c.current.getEnergy(); + id = c.current.getId(); + int A = massNumberFromNucleusId(id); + int Z = chargeNumberFromNucleusId(id); for (int i = 0; i < c.secondaries.size(); i++) { - A += (*c.secondaries[i]).current.getMassNumber(); - Z += (*c.secondaries[i]).current.getChargeNumber(); E += (*c.secondaries[i]).current.getEnergy(); + id = (*c.secondaries[i]).current.getId(); + A += massNumberFromNucleusId(id); + Z += chargeNumberFromNucleusId(id); } EXPECT_EQ(12, A); // nucleon number conserved @@ -319,7 +323,8 @@ TEST(PhotoDisintegration, Iron) { // This test can stochastically fail if no interaction occurs over 50 Mpc. PhotoDisintegration pd(IRB); Candidate c; - c.current.setId(nucleusId(56, 26)); + int id = nucleusId(56, 26); + c.current.setId(id); c.current.setEnergy(100 * EeV); c.setCurrentStep(50 * Mpc); pd.process(&c); @@ -329,14 +334,16 @@ TEST(PhotoDisintegration, Iron) { EXPECT_TRUE(c.secondaries.size() > 0); // secondaries produced - int A = c.current.getMassNumber(); - int Z = c.current.getChargeNumber(); double E = c.current.getEnergy(); + id = c.current.getId(); + int A = massNumberFromNucleusId(id); + int Z = chargeNumberFromNucleusId(id); for (int i = 0; i < c.secondaries.size(); i++) { - A += (*c.secondaries[i]).current.getMassNumber(); - Z += (*c.secondaries[i]).current.getChargeNumber(); E += (*c.secondaries[i]).current.getEnergy(); + id = (*c.secondaries[i]).current.getId(); + A += massNumberFromNucleusId(id); + Z += chargeNumberFromNucleusId(id); } EXPECT_EQ(56, A); // nucleon number conserved @@ -451,12 +458,10 @@ TEST(PhotoPionProduction, Proton) { c.current.setId(nucleusId(1, 1)); c.current.setEnergy(100 * EeV); ppp.process(&c); - EXPECT_TRUE(c.current.getEnergy() / EeV < 100); - // energy loss - EXPECT_EQ(1, c.current.getMassNumber()); - // nucleon number conserved - EXPECT_EQ(0, c.secondaries.size()); - // no (nucleonic) secondaries + EXPECT_TRUE(c.current.getEnergy() / EeV < 100); // energy loss + int id = c.current.getId(); + EXPECT_EQ(1, massNumberFromNucleusId(id)); // nucleon number conserved + EXPECT_EQ(0, c.secondaries.size()); // no (nucleonic) secondaries } TEST(PhotoPionProduction, Helium) { @@ -469,7 +474,8 @@ TEST(PhotoPionProduction, Helium) { c.current.setEnergy(400 * EeV); ppp.process(&c); EXPECT_LT(c.current.getEnergy(), 400 * EeV); - EXPECT_TRUE(c.current.getMassNumber() < 4); + int id = c.current.getId(); + EXPECT_TRUE(massNumberFromNucleusId(id) < 4); EXPECT_TRUE(c.secondaries.size() > 0); } @@ -506,12 +512,10 @@ TEST(SophiaPhotoPionProduction, withoutSecondaries) { c.current.setId(nucleusId(1, 1)); c.current.setEnergy(100 * EeV); ppp.process(&c); - EXPECT_GT(100 * EeV, c.current.getEnergy()); - // energy loss - EXPECT_EQ(1, c.current.getMassNumber()); - // nucleon number conserved - EXPECT_EQ(0, c.secondaries.size()); - // secondaries turned off + EXPECT_GT(100 * EeV, c.current.getEnergy()); // energy loss + int id = c.current.getId(); + EXPECT_EQ(1, massNumberFromNucleusId(id)); // nucleon number conserved + EXPECT_EQ(0, c.secondaries.size()); // secondaries turned off } TEST(SophiaPhotoPionProduction, withSecondaries) { diff --git a/test/testSource.cpp b/test/testSource.cpp index 5fd4b149d..9f653b4ab 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -171,12 +171,11 @@ TEST(SourceComposition, simpleTest) { double index = -2; SourceComposition source(Emin, Emax, index); source.add(nucleusId(6, 3), 1); - ParticleState ps; - source.prepare(ps); - EXPECT_EQ(6, ps.getMassNumber()); - EXPECT_EQ(3, ps.getChargeNumber()); - EXPECT_LE(Emin, ps.getEnergy()); - EXPECT_GE(Emax, ps.getEnergy()); + ParticleState p; + source.prepare(p); + EXPECT_EQ(nucleusId(6, 3), p.getId()); + EXPECT_LE(Emin, p.getEnergy()); + EXPECT_GE(Emax, p.getEnergy()); } TEST(SourceComposition, throwNoIsotope) { @@ -195,22 +194,19 @@ TEST(Source, allPropertiesUsed) { Candidate c = *source.getCandidate(); ParticleState p = c.created; - EXPECT_EQ(8, p.getMassNumber()); - EXPECT_EQ(4, p.getChargeNumber()); + EXPECT_EQ(nucleusId(8, 4), p.getId()); EXPECT_LE(5 * EeV, p.getEnergy()); EXPECT_GE(100 * EeV, p.getEnergy()); EXPECT_EQ(Vector3d(10, 0, 0) * Mpc, p.getPosition()); p = c.previous; - EXPECT_EQ(8, p.getMassNumber()); - EXPECT_EQ(4, p.getChargeNumber()); + EXPECT_EQ(nucleusId(8, 4), p.getId()); EXPECT_LE(5 * EeV, p.getEnergy()); EXPECT_GE(100 * EeV, p.getEnergy()); EXPECT_EQ(Vector3d(10, 0, 0) * Mpc, p.getPosition()); p = c.current; - EXPECT_EQ(8, p.getMassNumber()); - EXPECT_EQ(4, p.getChargeNumber()); + EXPECT_EQ(nucleusId(8, 4), p.getId()); EXPECT_LE(5 * EeV, p.getEnergy()); EXPECT_GE(100 * EeV, p.getEnergy()); EXPECT_EQ(Vector3d(10, 0, 0) * Mpc, p.getPosition()); From 2fbe5ebd3560bf1d65000d3ed987065de597dc1b Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 25 Sep 2013 09:18:03 +0200 Subject: [PATCH 0340/1298] renamed functions to charge- and massNumber --- include/crpropa/ParticleID.h | 4 ++-- src/ParticleID.cpp | 8 ++++---- src/ParticleMass.cpp | 4 ++-- src/ParticleState.cpp | 16 +++++----------- src/Source.cpp | 2 +- src/module/NuclearDecay.cpp | 12 ++++++------ src/module/PhotoDisintegration.cpp | 15 +++++++-------- src/module/PhotoPionProduction.cpp | 19 +++++++++---------- test/testInteraction.cpp | 30 +++++++++++++++--------------- 9 files changed, 51 insertions(+), 59 deletions(-) diff --git a/include/crpropa/ParticleID.h b/include/crpropa/ParticleID.h index 9722d520e..986f4b369 100644 --- a/include/crpropa/ParticleID.h +++ b/include/crpropa/ParticleID.h @@ -17,8 +17,8 @@ std::vector leptons(); * I is the isomer number, with I=0 corresponding to the ground state. */ int nucleusId(int a, int z); -int chargeNumberFromNucleusId(int id); -int massNumberFromNucleusId(int id); +int chargeNumber(int id); +int massNumber(int id); bool isNucleus(int id); /* CRPropa2.0 code scheme */ diff --git a/src/ParticleID.cpp b/src/ParticleID.cpp index ae9b19e8b..05b7bdcf5 100644 --- a/src/ParticleID.cpp +++ b/src/ParticleID.cpp @@ -33,11 +33,11 @@ int nucleusId(int a, int z) { return 1000000000 + z * 10000 + a * 10; } -int chargeNumberFromNucleusId(int id) { +int chargeNumber(int id) { return HepPID::Z(id); } -int massNumberFromNucleusId(int id) { +int massNumber(int id) { return HepPID::A(id); } @@ -54,8 +54,8 @@ int convertFromCRPropa2NucleusId(int crp_id) { int convertToCRPropa2NucleusId(int id) { if (not HepPID::isNucleus(id)) // if not nucleus, just return the id return id; - int Z = chargeNumberFromNucleusId(id); - int A = massNumberFromNucleusId(id); + int Z = chargeNumber(id); + int A = massNumber(id); return Z * 1000 + A; } diff --git a/src/ParticleMass.cpp b/src/ParticleMass.cpp index 70f316ced..3be2ba77c 100644 --- a/src/ParticleMass.cpp +++ b/src/ParticleMass.cpp @@ -38,8 +38,8 @@ struct NuclearMassTable { static NuclearMassTable nuclearMassTable; double nucleusMass(int id) { - int Z = chargeNumberFromNucleusId(id); - int N = massNumberFromNucleusId(id) - Z; + int Z = chargeNumber(id); + int N = massNumber(id) - Z; double mass = nuclearMassTable.table[Z * 31 + N]; if (mass == 0) throw std::runtime_error("getNucleusMass: nucleus not found " + kiss::str(id)); diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index d99735697..5cd3e81e5 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -44,6 +44,7 @@ void ParticleState::setId(int newId) { if (id < 0) charge *= -1; // HepPID::Z returns positive charge numbers for anti-nuclei } else { + // pmass missing for non-nuclei charge = HepPID::charge(id) * eplus; } } @@ -61,19 +62,12 @@ double ParticleState::getCharge() const { } double ParticleState::getLorentzFactor() const { - if (HepPID::isNucleus(id)) - return energy / (pmass * c_squared); - else - throw std::runtime_error( - "crpropa::ParticleState::getLorentzFactor only for nuclei/nucleons"); + return energy / (pmass * c_squared); } -void ParticleState::setLorentzFactor(double gamma) { - if (HepPID::isNucleus(id)) - energy = gamma * pmass * c_squared; - else - throw std::runtime_error( - "crpropa::ParticleState::setLorentzFactor only for nuclei/nucleons"); +void ParticleState::setLorentzFactor(double lf) { + lf = std::max(0., lf); // prevent negative Lorentz factors + energy = lf * pmass * c_squared; } Vector3d ParticleState::getVelocity() const { diff --git a/src/Source.cpp b/src/Source.cpp index a118bdaa6..2e9c196c2 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -107,7 +107,7 @@ double SourceComposition::getSpectrumIntegral(int Z) const { void SourceComposition::add(int id, double a) { isotope.push_back(id); - int A = massNumberFromNucleusId(id); + int A = massNumber(id); double weightedAbundance = a * pow(A, -index - 1); abundance.push_back(weightedAbundance); probability.push_back(0); diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index 02383a2ce..c1b79ad75 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -62,8 +62,8 @@ bool NuclearDecay::setNextInteraction(Candidate *candidate, if (not(isNucleus(id))) return false; // accept only nuclei - int A = massNumberFromNucleusId(id); - int Z = chargeNumberFromNucleusId(id); + int A = massNumber(id); + int Z = chargeNumber(id); int N = A - Z; std::vector decays = decayTable[Z * 31 + N]; @@ -116,8 +116,8 @@ void NuclearDecay::performInteraction(Candidate *candidate) const { void NuclearDecay::betaDecay(Candidate *candidate, bool isBetaPlus) const { double gamma = candidate->current.getLorentzFactor(); int id = candidate->current.getId(); - int A = massNumberFromNucleusId(id); - int Z = chargeNumberFromNucleusId(id); + int A = massNumber(id); + int Z = chargeNumber(id); double mass = candidate->current.getMass(); // beta- decay @@ -157,8 +157,8 @@ void NuclearDecay::betaDecay(Candidate *candidate, bool isBetaPlus) const { void NuclearDecay::nucleonEmission(Candidate *candidate, int dA, int dZ) const { int id = candidate->current.getId(); - int A = massNumberFromNucleusId(id); - int Z = chargeNumberFromNucleusId(id); + int A = massNumber(id); + int Z = chargeNumber(id); double EpA = candidate->current.getEnergy() / double(A); candidate->current.setId(nucleusId(A - dA, Z - dZ)); candidate->current.setEnergy(EpA * (A - dA)); diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 0951d1933..a6c0f30f1 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -75,8 +75,8 @@ bool PhotoDisintegration::setNextInteraction(Candidate *candidate, if (not(isNucleus(id))) return false; // accept only nuclei - int A = massNumberFromNucleusId(id); - int Z = chargeNumberFromNucleusId(id); + int A = massNumber(id); + int Z = chargeNumber(id); int N = A - Z; // check if disintegration data available @@ -104,8 +104,7 @@ bool PhotoDisintegration::setNextInteraction(Candidate *candidate, interaction.channel = pdModes[i].channel; } - // interaction length is proportional to 1 / (photon density) - interaction.distance /= photonDensityScaling(photonField, z); + interaction.distance /= photonFieldScaling(photonField, z); candidate->setInteractionState(getDescription(), interaction); return true; @@ -128,8 +127,8 @@ void PhotoDisintegration::performInteraction(Candidate *candidate) const { int dZ = -nProton - nH2 - nH3 - 2 * nHe3 - 2 * nHe4; int id = candidate->current.getId(); - int A = massNumberFromNucleusId(id); - int Z = chargeNumberFromNucleusId(id); + int A = massNumber(id); + int Z = chargeNumber(id); double EpA = candidate->current.getEnergy() / double(A); // update particle @@ -157,8 +156,8 @@ void PhotoDisintegration::performInteraction(Candidate *candidate) const { } double PhotoDisintegration::energyLossLength(int id, double E) { - int A = massNumberFromNucleusId(id); - int Z = chargeNumberFromNucleusId(id); + int A = massNumber(id); + int Z = chargeNumber(id); int N = A - Z; std::vector pdModes = pdTable[Z * 31 + N]; diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 6b81f13b7..ee72d325e 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -65,8 +65,8 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, double z = candidate->getRedshift(); double E = candidate->current.getEnergy(); - int A = massNumberFromNucleusId(id); - int Z = chargeNumberFromNucleusId(id); + int A = massNumber(id); + int Z = chargeNumber(id); int N = A - Z; double Eeff = E / A * (1 + z); // effective energy per nucleon at redshift z @@ -112,8 +112,7 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, } } - // interaction length is proportional to 1 / (photon density) - interaction.distance /= photonDensityScaling(photonField, z); + interaction.distance /= photonFieldScaling(photonField, z); candidate->setInteractionState(getDescription(), interaction); return true; @@ -135,8 +134,8 @@ void PhotoPionProduction::performInteraction(Candidate *candidate) const { double E = candidate->current.getEnergy(); int id = candidate->current.getId(); - int A = massNumberFromNucleusId(id); - int Z = chargeNumberFromNucleusId(id); + int A = massNumber(id); + int Z = chargeNumber(id); if (A == 1) { // interaction on single nucleon @@ -151,8 +150,8 @@ void PhotoPionProduction::performInteraction(Candidate *candidate) const { } double PhotoPionProduction::energyLossLength(int id, double E) { - int A = massNumberFromNucleusId(id); - int Z = chargeNumberFromNucleusId(id); + int A = massNumber(id); + int Z = chargeNumber(id); int N = A - Z; double EpA = E / A; @@ -208,8 +207,8 @@ void SophiaPhotoPionProduction::setHaveAntiNucleons(bool b) { void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { int id = candidate->current.getId(); - int A = massNumberFromNucleusId(id); - int Z = chargeNumberFromNucleusId(id); + int A = massNumber(id); + int Z = chargeNumber(id); double E = candidate->current.getEnergy(); double EpA = E / A; double redshift = candidate->getRedshift(); diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index c22dfcdc8..800ffaf4e 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -14,7 +14,7 @@ namespace crpropa { TEST(ElectronPairProduction, EnergyDecreasing) { // Test if energy loss occurs for protons with energies from 1e15 - 1e23 eV Candidate c; - c.setCurrentStep(1 * Mpc); + c.setCurrentStep(2 * Mpc); c.current.setId(nucleusId(1, 1)); // proton ElectronPairProduction epp1(CMB); @@ -22,7 +22,7 @@ TEST(ElectronPairProduction, EnergyDecreasing) { double E = pow(10, 15 + i * 0.1) * eV; c.current.setEnergy(E); epp1.process(&c); - EXPECT_TRUE(c.current.getEnergy() <= E); + EXPECT_LE(c.current.getEnergy(), E); } ElectronPairProduction epp2(IRB); @@ -30,7 +30,7 @@ TEST(ElectronPairProduction, EnergyDecreasing) { double E = pow(10, 15 + i * 0.1) * eV; c.current.setEnergy(E); epp2.process(&c); - EXPECT_TRUE(c.current.getEnergy() < E); + EXPECT_LE(c.current.getEnergy(), E); } ElectronPairProduction epp3(CMB_IRB); @@ -38,7 +38,7 @@ TEST(ElectronPairProduction, EnergyDecreasing) { double E = pow(10, 15 + i * 0.1) * eV; c.current.setEnergy(E); epp3.process(&c); - EXPECT_TRUE(c.current.getEnergy() < E); + EXPECT_LE(c.current.getEnergy(), E); } } @@ -301,14 +301,14 @@ TEST(PhotoDisintegration, Carbon) { double E = c.current.getEnergy(); id = c.current.getId(); - int A = massNumberFromNucleusId(id); - int Z = chargeNumberFromNucleusId(id); + int A = massNumber(id); + int Z = chargeNumber(id); for (int i = 0; i < c.secondaries.size(); i++) { E += (*c.secondaries[i]).current.getEnergy(); id = (*c.secondaries[i]).current.getId(); - A += massNumberFromNucleusId(id); - Z += chargeNumberFromNucleusId(id); + A += massNumber(id); + Z += chargeNumber(id); } EXPECT_EQ(12, A); // nucleon number conserved @@ -336,14 +336,14 @@ TEST(PhotoDisintegration, Iron) { double E = c.current.getEnergy(); id = c.current.getId(); - int A = massNumberFromNucleusId(id); - int Z = chargeNumberFromNucleusId(id); + int A = massNumber(id); + int Z = chargeNumber(id); for (int i = 0; i < c.secondaries.size(); i++) { E += (*c.secondaries[i]).current.getEnergy(); id = (*c.secondaries[i]).current.getId(); - A += massNumberFromNucleusId(id); - Z += chargeNumberFromNucleusId(id); + A += massNumber(id); + Z += chargeNumber(id); } EXPECT_EQ(56, A); // nucleon number conserved @@ -460,7 +460,7 @@ TEST(PhotoPionProduction, Proton) { ppp.process(&c); EXPECT_TRUE(c.current.getEnergy() / EeV < 100); // energy loss int id = c.current.getId(); - EXPECT_EQ(1, massNumberFromNucleusId(id)); // nucleon number conserved + EXPECT_EQ(1, massNumber(id)); // nucleon number conserved EXPECT_EQ(0, c.secondaries.size()); // no (nucleonic) secondaries } @@ -475,7 +475,7 @@ TEST(PhotoPionProduction, Helium) { ppp.process(&c); EXPECT_LT(c.current.getEnergy(), 400 * EeV); int id = c.current.getId(); - EXPECT_TRUE(massNumberFromNucleusId(id) < 4); + EXPECT_TRUE(massNumber(id) < 4); EXPECT_TRUE(c.secondaries.size() > 0); } @@ -514,7 +514,7 @@ TEST(SophiaPhotoPionProduction, withoutSecondaries) { ppp.process(&c); EXPECT_GT(100 * EeV, c.current.getEnergy()); // energy loss int id = c.current.getId(); - EXPECT_EQ(1, massNumberFromNucleusId(id)); // nucleon number conserved + EXPECT_EQ(1, massNumber(id)); // nucleon number conserved EXPECT_EQ(0, c.secondaries.size()); // secondaries turned off } From 363490c09d14b89c286c993f25a67d62fd42abc2 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 25 Sep 2013 09:37:00 +0200 Subject: [PATCH 0341/1298] refactored and fixed epair production --- include/crpropa/PhotonBackground.h | 7 +--- .../crpropa/module/ElectronPairProduction.h | 26 +++++------- src/PhotonBackground.cpp | 10 +---- src/module/ElectronPairProduction.cpp | 41 ++++++++++--------- 4 files changed, 36 insertions(+), 48 deletions(-) diff --git a/include/crpropa/PhotonBackground.h b/include/crpropa/PhotonBackground.h index 9a5bb1901..8e6d38075 100644 --- a/include/crpropa/PhotonBackground.h +++ b/include/crpropa/PhotonBackground.h @@ -8,11 +8,8 @@ enum PhotonField { CMB, IRB, CMB_IRB }; -// Returns overall photon field scaling factor at redshift z -double photonDensityScaling(int photonField, double z); - -// Returns overall scaling factor for loss rates dE/dt at redshift z -double lossRateScaling(PhotonField photonField, double z); +// Returns overall comoving scaling factor +double photonFieldScaling(PhotonField photonField, double z); } // namespace crpropa diff --git a/include/crpropa/module/ElectronPairProduction.h b/include/crpropa/module/ElectronPairProduction.h index 0f2a99214..4a55c8ed4 100644 --- a/include/crpropa/module/ElectronPairProduction.h +++ b/include/crpropa/module/ElectronPairProduction.h @@ -17,8 +17,8 @@ namespace crpropa { class ElectronPairProduction: public Module { private: PhotonField photonField; - std::vector tabLossRate; /*< tabulated energy loss rate in [J/m] for protons at z = 0*/ - std::vector tabEnergy; /*< tabulated proton energy [J] */ + std::vector tabLossLength; /*< tabulated energy loss rate in [J/m] for protons at z = 0*/ + std::vector tabLorentzFactor; /*< tabulated proton energy [J] */ public: ElectronPairProduction(PhotonField photonField = CMB_IRB); @@ -28,23 +28,19 @@ class ElectronPairProduction: public Module { void process(Candidate *candidate) const; /** - Calculates the energy loss rate dE/dx in [J/m] - @param id PDG particle id - @param E energy [J] + Calculates the inverse energy loss length beta = -1/E dE/dx in [1/m] + @param id PDG particle ID + @param lf Lorentz factor @param z redshift - The energy loss rate b(E) = -dE/dt is tabulated for protons against - CMB, IRB and CMB+IRB photon backgrounds. - - For nuclei this loss rate is modified as (cf. 10.1016/j.astropartphys.2012.07.010, eq. 5) - b_A,Z(E) = Z^2/A * b_p(E/A). - - Cosmological evolution of the photon background is considered with (cf. 10.1103/PhysRevD.74.043005, eq. 5) - b(E,z) = (1+z)^2 b((1+z)E). - Note that the energy loss length beta(E) = -1/E dE/dt evolves as + The energy loss length is tabulated for protons against CMB, IRB and + CMB+IRB photon backgrounds. + Modification for nuclei and cosmological evolution of the photon background + is considered with (cf. 10.1016/j.astropartphys.2012.07.010, eq. 3 and 5) + beta_A,Z(E) = Z^2 / A * beta_p(E/A) beta(E,z) = (1+z)^3 beta((1+z)E). */ - double lossRate(int id, double E, double z) const; + double invLossLength(int id, double lf, double z) const; }; } // namespace crpropa diff --git a/src/PhotonBackground.cpp b/src/PhotonBackground.cpp index 6d48da2f2..fa79f66d6 100644 --- a/src/PhotonBackground.cpp +++ b/src/PhotonBackground.cpp @@ -12,16 +12,10 @@ static std::vector zKneiske(a, a + sizeof(a) / sizeof(double)); double b[9] = { 1, 1.6937, 2.5885, 3.6178, 5.1980, 7.3871, 8.5471, 7.8605, 0 }; static std::vector sKneiske(b, b + sizeof(b) / sizeof(double)); -double photonDensityScaling(int photonField, double z) { +double photonFieldScaling(PhotonField photonField, double z) { if (photonField == IRB) return interpolate(z, zKneiske, sKneiske); - return pow(1 + z, 2); // CMB-like scaling -} - -double lossRateScaling(PhotonField photonField, double z) { - if (photonField == IRB) - return interpolate(z, zKneiske, sKneiske); - return pow(1 + z, 2); // CMB-like scaling + return 1.; // CMB-like scaling } } // namespace crpropa diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 6bb579a39..61a4a771e 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -49,46 +49,47 @@ void ElectronPairProduction::init(std::string filename) { double a, b; infile >> a >> b; if (infile) { - tabEnergy.push_back(a * eV); - tabLossRate.push_back(b * eV / Mpc); + tabLorentzFactor.push_back(a * eV / mass_proton / c_squared); + tabLossLength.push_back(b / a / Mpc); } } - infile.ignore(std::numeric_limits::max(), '\n'); + infile.ignore(std::numeric_limits < std::streamsize > ::max(), '\n'); } infile.close(); } -double ElectronPairProduction::lossRate(int id, double E, double z) const { - double A = massNumberFromNucleusId(id); - double Z = chargeNumberFromNucleusId(id); - - if (Z < 1) +double ElectronPairProduction::invLossLength(int id, double lf, + double z) const { + double Z = chargeNumber(id); + if (Z == 0) return 0; // no pair production on uncharged particles - double Eeff = E / A * (1 + z); - if (Eeff < tabEnergy.front()) + lf *= (1 + z); + if (lf < tabLorentzFactor.front()) return 0; // below energy threshold - double rate; - if (Eeff < tabEnergy.back()) - rate = interpolate(Eeff, tabEnergy, tabLossRate);// interpolation + double length; + if (lf < tabLorentzFactor.back()) + length = interpolate(lf, tabLorentzFactor, tabLossLength); // interpolation else - rate = tabLossRate.back() * pow(Eeff / tabEnergy.back(), 0.4); // extrapolation + length = tabLossLength.back() * pow(lf / tabLorentzFactor.back(), -0.6); // extrapolation - return rate * Z * Z / A * lossRateScaling(photonField, z); + double A = nucleusMass(id) / mass_proton; // more accurate than massNumber(Id) + return length * Z * Z / A * pow(1 + z, 3) + * photonFieldScaling(photonField, z); } void ElectronPairProduction::process(Candidate *c) const { int id = c->current.getId(); - if (not(isNucleus(id))) - return; // this module only handles nucleons and nuclei + if (not (isNucleus(id))) + return; // only nuclei - double E = c->current.getEnergy(); + double lf = c->current.getLorentzFactor(); double z = c->getRedshift(); double step = c->getCurrentStep() / (1 + z); // step size in local frame - double dE = lossRate(id, E, z) * step; + double loss = invLossLength(id, lf, z) * step; - c->current.setEnergy(E - dE); + c->current.setLorentzFactor(lf * (1 - loss)); } } // namespace crpropa From 29a28c09b85157b5e3f44acc17ffddfeb1c0ba17 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 25 Sep 2013 18:23:42 +0200 Subject: [PATCH 0342/1298] removed constraint for minimum rate in photodisintegration channels --- data-tools/PhotoDisintegration/photodis_reformat.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/data-tools/PhotoDisintegration/photodis_reformat.py b/data-tools/PhotoDisintegration/photodis_reformat.py index 81ea2f9d0..4fb2cc61f 100644 --- a/data-tools/PhotoDisintegration/photodis_reformat.py +++ b/data-tools/PhotoDisintegration/photodis_reformat.py @@ -3,7 +3,6 @@ # This script reformats the exclusive mean free path data files from CRPropa2. # - The four CRPropa2 files are merged into one, # - nuclides with Z>26 or N>30 are omitted and -# - disintegration rates < 1e-6/Mpc are set to 0. # # The folders with the date files being used, are found in [CRPropa2 source]/TabulatedTALYSMeanFreePath/. # Copy the content or execute the script from within this folder. @@ -74,7 +73,7 @@ def reformat(photonField): if Z>26 or N>30: # skip isotopes heavier than Fe-56 continue - j0 = int(data1[i, 1]) # start index in for channels in 'PDExclTabMnFrPthCrossId.cmt' + j0 = int(data1[i, 1]) # start index for channels in 'PDExclTabMnFrPthCrossId.cmt' j1 = int(data1[i, 2]) # end index for j in range(j0, j1): @@ -90,10 +89,7 @@ def reformat(photonField): k0 = int(data2[j, 1]) # start index in 'PDExclTabMnFrPthCross.cmt' for rate in data3[k0:k0 + 200]: - if rate < 1e-6: - fout.write('\t0') # replace values < 1e-6 [1/Mpc] with 0 - else: - fout.write('\t'+str(rate)) + fout.write('\t'+str(rate)) reformat('CMB') From 0522f43b7742b550898954787b148ea935fd54e6 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 25 Sep 2013 18:25:27 +0200 Subject: [PATCH 0343/1298] update scaling of the Kneiske IRB to match CRPropa 2 --- data-tools/PhotonField/IRB_redshiftScaling.py | 65 ------------- .../PhotonField/Kneiske2004_IRB_scaling.py | 91 +++++++++++++++++++ data-tools/PhotonField/photonField.py | 2 +- src/PhotonBackground.cpp | 5 +- 4 files changed, 95 insertions(+), 68 deletions(-) delete mode 100644 data-tools/PhotonField/IRB_redshiftScaling.py create mode 100644 data-tools/PhotonField/Kneiske2004_IRB_scaling.py diff --git a/data-tools/PhotonField/IRB_redshiftScaling.py b/data-tools/PhotonField/IRB_redshiftScaling.py deleted file mode 100644 index 28ebafd47..000000000 --- a/data-tools/PhotonField/IRB_redshiftScaling.py +++ /dev/null @@ -1,65 +0,0 @@ -from pylab import * -from scipy.interpolate import interp1d -from scipy.integrate import quad -from mpc import h_planck, c_light - -# This script plots and calculates the integral of the cosmic infrared background (IRB) for different redshifts as given in Kneiske et al. 2004 (astro-ph/0309141) -# This integral can be used as an overall scaling factor for said background - - -def process1(fin): - x,y = genfromtxt(fin, unpack=True) - y[y < 1.01e-1] = 0 - return sum( (y[1:] + y[:-1]) / 2 * (x[1:] - x[:-1]) ) - - -def numberDensity(fin='Kneiske2004_IRB/z0.txt'): - """IRB (Kneiske et al. 2004) number density""" - # read file - # wavelength lambda [mu m] and wavelength scaled spectral radiance lambda * I_lambda [nW/m^2/sr] - x, y = genfromtxt(fin, unpack=True) - y[y < 1.01e-1] = 0 # cut off values that are artefacts from parsing the plots from the paper - - x *= 1e-6 # [mu m] -> [m] - y *= 1e-9 # [nW/m^2/sr] -> [W/m^2/sr] - - # remove wavelength scaling - y /= x # [W/m^2/sr] -> [W/m^3/sr] - - # convert to spectral energy density dEdV_lambda - y *= 4 * pi / c_light # [W/m^3/sr] -> [J/m^3/m] - - # convert to spectral number density: divide by photon energy - y /= h_planck * c_light / x # [J/m^3/m] -> [1/m^3/m] - - # integrate over wavelength spectrum - f = interp1d(x, y) - n = quad(f, x[0], x[-1]) # numerical integral from x_min to x_max - print n - return n[0] - - -files = ['z0.txt', 'z0.2.txt', 'z0.4.txt', 'z0.6.txt', 'z1.txt', 'z2.txt', 'z3.txt', 'z4.txt'] - -s = zeros(8) -s2 = zeros(8) -for i,f in enumerate(files): - s[i] = numberDensity('Kneiske2004_IRB/'+f) - s2[i] = process1('Kneiske2004_IRB/'+f) -s /= s[0] -s2 /= s2[0] - -z = array([0, 0.2, 0.4, 0.6, 1, 2, 3, 4]) -s *= (1+z)**3 -s2 *= (1+z)**3 - -figure() -plot(z, s, 'k') -plot(z, s2, 'r--') - -xlim(0, 5) -xlabel('Redshift z') -ylabel('Overall Scaling') - -#savefig('Kneiske2004_IRB_scaling.png',bbox_inches='tight') -show() diff --git a/data-tools/PhotonField/Kneiske2004_IRB_scaling.py b/data-tools/PhotonField/Kneiske2004_IRB_scaling.py new file mode 100644 index 000000000..6f277da59 --- /dev/null +++ b/data-tools/PhotonField/Kneiske2004_IRB_scaling.py @@ -0,0 +1,91 @@ +from pylab import * +from scipy.interpolate import interp1d +from scipy.integrate import quad +from scipy.optimize import brentq +from crpropa import h_planck, c_light, k_boltzmann + +# This script plots and calculates the integral of the cosmic infrared background (IRB) for different redshifts as given in Kneiske et al. 2004 (astro-ph/0309141) +# This integral can be used as an overall scaling factor for said background + +def CMBSpectralRadiance(nu, z): + """CMB spectral radiance [W/sr/m^2/Hz] at frequency nu [1/s], see http://en.wikipedia.org/wiki/Planck%27s_law""" + return 2 * nu**3 * h_planck / c_light**2 / ( exp(nu * h_planck / k_boltzmann / 2.725 / (1 + z)) - 1 ) + +def CMBSpectralEnergyDensity(nu, z): + """CMB spectral energy density [J/m^3/Hz] at frequency nu [1/s]""" + return CMBSpectralRadiance(nu, z) * 4 * pi / c_light + +def CMBSpectralNumberDensity(nu, z): + """CMB spectral number density [1/m^3/Hz] at frequency nu [1/s]""" + return CMBSpectralEnergyDensity(nu, z) / (nu * h_planck) + +def process(fname, z): + # read file + # wavelength lambda [mu m] and wavelength scaled spectral radiance lambda * I_lambda [nW/m^2/sr] + x, y = genfromtxt(fname, unpack=True) + y[y < 1.01e-1] = 0 # cut off values that are artefacts from parsing the plots from the paper + + x *= 1e-6 # [mu m] -> [m] + y *= 1e-9 # [nW/m^2/sr] -> [W/m^2/sr] + + # remove wavelength scaling + y /= x # [W/m^2/sr] -> [W/m^3/sr] + + # convert to spectral energy density dEdV_lambda + y *= 4 * pi / c_light # [W/m^3/sr] -> [J/m^3/m] + + # convert to spectral number density: divide by photon energy + y /= h_planck * c_light / x # [J/m^3/m] -> [1/m^3/m] + + # change to frequency as spectral variable: B_nu = lambda^2 / h * B_lambda + nu = c_light / x # [m] -> [Hz] + ynu = y * x**2 / c_light # [1/m^3/Hz] + + # find frequency nu0 above which the IRB number density exceeds the CMB + nu = nu[::-1] + ynu = ynu[::-1] + ynu_interp = interp1d(nu, ynu) + def objective(nu): + return CMBSpectralNumberDensity(nu, z) - ynu_interp(nu) + nu0 = brentq(objective, 3.5e11, 1e13) # frequency of intersection + + # integral of spectral number density from nu0 to nuMax + I1 = quad(ynu_interp, nu[0], nu[-1])[0] + I2 = quad(ynu_interp, nu0, nu[-1])[0] + + # plot + figure() + nuCMB = logspace(9, 14) + plot(nuCMB, CMBSpectralNumberDensity(nuCMB, z), label='CMB') + plot(nu, ynu, label='IRB Kneiske') + xlabel('Frequency [Hz]') + ylabel('Number Density [1/m$^{3}$/Hz]') + ylim(1e-16, 1) + xlim(1e9, 1e16) + text(5e14, 0.1, 'z = %.1f'%z) + loglog() + axvline(nu0, lw=1, ls='--', color='k') + savefig('z%.1f.png'%z, bbox_inches='tight') + + print z, nu0, I1, I2 + return I1, I2 + + +fnames = ['z0.txt', 'z0.2.txt', 'z0.4.txt', 'z0.6.txt', 'z1.txt', 'z2.txt', 'z3.txt', 'z4.txt'] +z = array([0, 0.2, 0.4, 0.6, 1, 2, 3, 4, 5]) + +s1, s2 = zeros(9), zeros(9) +for i in range(8): + s1[i], s2[i] = process('Kneiske2004_IRB/'+fnames[i], z[i]) + +s1 /= s1[0] +s2 /= s2[0] + +figure() +plot(z, s1) +plot(z, s2) +xlim(0, 5) +xlabel('Redshift z') +ylabel('Overall Scaling') +savefig('Kneiske2004_IRB_scaling.png',bbox_inches='tight') +show() diff --git a/data-tools/PhotonField/photonField.py b/data-tools/PhotonField/photonField.py index ae494651f..98e6dfda1 100644 --- a/data-tools/PhotonField/photonField.py +++ b/data-tools/PhotonField/photonField.py @@ -1,5 +1,5 @@ from pylab import * -from mpc import h_planck, c_light, k_boltzmann, eV +from crpropa import h_planck, c_light, k_boltzmann, eV def CMBSpectralRadiance(nu): diff --git a/src/PhotonBackground.cpp b/src/PhotonBackground.cpp index fa79f66d6..6fcbfc641 100644 --- a/src/PhotonBackground.cpp +++ b/src/PhotonBackground.cpp @@ -6,10 +6,11 @@ namespace crpropa { -// Overall redshift scaling of the Kneiske IRB (see data/PhotonField/KneiskeIRB.py and Kneiske et al. 2004, astro-ph/0309141) +// Overall redshift scaling of the Kneiske et al. 2004 IRB, astro-ph/0309141 +// The scaling is calculated in data-tools/PhotonField/Kneiske2004_IRB_scaling.py double a[9] = { 0, 0.2, 0.4, 0.6, 1, 2, 3, 4, 5 }; static std::vector zKneiske(a, a + sizeof(a) / sizeof(double)); -double b[9] = { 1, 1.6937, 2.5885, 3.6178, 5.1980, 7.3871, 8.5471, 7.8605, 0 }; +double b[9] = {1., 0.9749867, 0.93999977, 0.88430409, 0.64952017, 0.27170436, 0.130244, 0.05971749, 0.}; static std::vector sKneiske(b, b + sizeof(b) / sizeof(double)); double photonFieldScaling(PhotonField photonField, double z) { From e81b5ce7db8acb301057681140038d617f6eb412 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 25 Sep 2013 18:49:22 +0200 Subject: [PATCH 0344/1298] some refactoring on pion production and disintegration --- include/crpropa/module/PhotoPionProduction.h | 2 + src/module/PhotoDisintegration.cpp | 3 +- src/module/PhotoPionProduction.cpp | 46 ++++++++------------ 3 files changed, 21 insertions(+), 30 deletions(-) diff --git a/include/crpropa/module/PhotoPionProduction.h b/include/crpropa/module/PhotoPionProduction.h index 39470c63f..1ff6513e3 100644 --- a/include/crpropa/module/PhotoPionProduction.h +++ b/include/crpropa/module/PhotoPionProduction.h @@ -31,6 +31,8 @@ class PhotoPionProduction: public StochasticInteraction { InteractionState &interaction) const; void performInteraction(Candidate *candidate) const; + double nucleiModification(int A, int X) const; + /** Calculates the energy loss length 1/E dE/dx in [m]. This is not used in the simulation. @param id PDG particle id diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index a6c0f30f1..452419ea5 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -97,6 +97,7 @@ bool PhotoDisintegration::setNextInteraction(Candidate *candidate, interaction.distance = std::numeric_limits::max(); for (size_t i = 0; i < pdModes.size(); i++) { double rate = interpolateEquidistant(lg, 6, 14, pdModes[i].rate); +// std::cout << pdModes[i].channel << " " << rate * Mpc << std::endl; double d = -log(random.rand()) / rate; if (d > interaction.distance) continue; @@ -104,7 +105,7 @@ bool PhotoDisintegration::setNextInteraction(Candidate *candidate, interaction.channel = pdModes[i].channel; } - interaction.distance /= photonFieldScaling(photonField, z); + interaction.distance /= pow(1 + z, 3) * photonFieldScaling(photonField, z); candidate->setInteractionState(getDescription(), interaction); return true; diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index ee72d325e..053464d20 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -57,10 +57,20 @@ void PhotoPionProduction::init(std::string filename) { infile.close(); } +double PhotoPionProduction::nucleiModification(int A, int X) const { + ; + if (A == 1) + return 1.; + if (A < 8) + return 0.85 * pow(X, 2. / 3.); + else + return 0.85 * X; +} + bool PhotoPionProduction::setNextInteraction(Candidate *candidate, InteractionState &interaction) const { int id = candidate->current.getId(); - if (not(isNucleus(id))) + if (not (isNucleus(id))) return false; // accept only nuclei double z = candidate->getRedshift(); @@ -81,13 +91,8 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, // check for interaction on protons if (Z > 0) { double rate = interpolate(Eeff, energy, pRate); - if (rate > 0) { - if (A > 1) { - if (A < 8) - rate *= 0.85 * pow(Z, 2. / 3.); - else - rate *= 0.85 * Z; - } + if (rate > 0) { + rate *= nucleiModification(A, Z); interaction.distance = -log(random.rand()) / rate; interaction.channel = 1; } @@ -97,13 +102,7 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, if (N > 0) { double rate = interpolate(Eeff, energy, nRate); if (rate > 0) { - if (A > 1) { - if (A < 8) - rate *= 0.85 * pow(N, 2. / 3.); - else - rate *= 0.85 * N; - } - + rate *= nucleiModification(A, N); double d = -log(random.rand()) / rate; if (d < interaction.distance) { interaction.distance = d; @@ -112,7 +111,7 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, } } - interaction.distance /= photonFieldScaling(photonField, z); + interaction.distance /= pow(1 + z, 3) * photonFieldScaling(photonField, z); candidate->setInteractionState(getDescription(), interaction); return true; @@ -165,22 +164,12 @@ double PhotoPionProduction::energyLossLength(int id, double E) { double lossRate = 0; if (Z > 0) { double rate = interpolate(EpA, energy, pRate); - if (A > 1) { - if (A < 8) - rate *= 0.85 * pow(Z, 2. / 3.); - else - rate *= 0.85 * Z; - } + rate *= nucleiModification(A, Z); lossRate += relativeEnergyLoss * rate; } if (N > 0) { double rate = interpolate(EpA, energy, nRate); - if (A > 1) { - if (A < 8) - rate *= 0.85 * pow(N, 2. / 3.); - else - rate *= 0.85 * N; - } + rate *= nucleiModification(A, N); lossRate += relativeEnergyLoss * rate; } @@ -263,7 +252,6 @@ void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { break; case -13: // anti-proton case -14: // anti-neutron - std::cout << "Antiproton/-neutron produced" << std::endl; if (haveAntiNucleons) candidate->addSecondary(-nucleusId(1, 14 - pType), Eout); break; From a226075523ab8c792a2bc259a2127e7fa5ef57c8 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 7 Oct 2013 19:49:20 +0200 Subject: [PATCH 0345/1298] more shell output --- CMakeLists.txt | 1 + include/crpropa/module/Output.h | 11 +--- include/crpropa/module/OutputShell.h | 53 ++++++++++++++++++++ python/crpropa.i | 2 + src/module/Output.cpp | 21 -------- src/module/OutputShell.cpp | 75 ++++++++++++++++++++++++++++ 6 files changed, 132 insertions(+), 31 deletions(-) create mode 100644 include/crpropa/module/OutputShell.h create mode 100644 src/module/OutputShell.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c3067a076..a11ffd5fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -129,6 +129,7 @@ add_library(crpropa SHARED src/module/PhotoDisintegration.cpp src/module/Redshift.cpp src/module/Output.cpp + src/module/OutputShell.cpp src/module/OutputROOT.cpp src/module/OutputCRPropa2.cpp src/module/PhotonDINT.cpp diff --git a/include/crpropa/module/Output.h b/include/crpropa/module/Output.h index 9d07aefa4..74ccdb068 100644 --- a/include/crpropa/module/Output.h +++ b/include/crpropa/module/Output.h @@ -2,20 +2,11 @@ #define CRPROPA_OUTPUT_H #include "crpropa/Module.h" +#include "crpropa/AssocVector.h" #include namespace crpropa { -/** - @class ShellOutput - @brief Write properties of the candidate to the shell. - */ -class ShellOutput: public Module { -public: - void process(Candidate *candidate) const; - std::string getDescription() const; -}; - /** @class TrajectoryOutput @brief Saves trajectories to plain text file. diff --git a/include/crpropa/module/OutputShell.h b/include/crpropa/module/OutputShell.h new file mode 100644 index 000000000..ccbc13b22 --- /dev/null +++ b/include/crpropa/module/OutputShell.h @@ -0,0 +1,53 @@ +#ifndef CRPROPA_OUTPUTSHELL_H +#define CRPROPA_OUTPUTSHELL_H + +#include "crpropa/Module.h" +#include "crpropa/AssocVector.h" + +namespace crpropa { + +/** + @class ShellOutput + @brief Show the trajectory in the shell. + */ +class ShellOutput: public Module { +public: + void process(Candidate *candidate) const; + std::string getDescription() const; +}; + +/** + @class ShellOutput1D + @brief Show the trajectory in the shell. + */ +class ShellOutput1D: public Module { +public: + void process(Candidate *candidate) const; + std::string getDescription() const; +}; + +/** + @class ShellInteractionOutput + @brief Show the interaction states in the shell. + */ +class ShellInteractionOutput: public Module { +public: + typedef Loki::AssocVector InteractionStatesMap; + void process(Candidate *candidate) const; + std::string getDescription() const; +}; + +/** + @class ShellPropertyOutput + @brief Show the candidate properties in the shell. + */ +class ShellPropertyOutput: public Module { +public: + typedef Loki::AssocVector PropertyMap; + void process(Candidate *candidate) const; + std::string getDescription() const; +}; + +} // namespace cprpropa + +#endif // CRPROPA_OUTPUTSHELL_H diff --git a/python/crpropa.i b/python/crpropa.i index b3d9ab46e..eef23b9fd 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -35,6 +35,7 @@ using std::ptrdiff_t; #include "crpropa/module/Boundary.h" #include "crpropa/module/Observer.h" #include "crpropa/module/Output.h" +#include "crpropa/module/OutputShell.h" #include "crpropa/module/OutputROOT.h" #include "crpropa/module/OutputCRPropa2.h" #include "crpropa/module/PhotonDINT.h" @@ -150,6 +151,7 @@ using std::ptrdiff_t; %include "crpropa/module/SimplePropagation.h" %include "crpropa/module/DeflectionCK.h" %include "crpropa/module/Output.h" +%include "crpropa/module/OutputShell.h" %include "crpropa/module/OutputROOT.h" %include "crpropa/module/OutputCRPropa2.h" %include "crpropa/module/PhotonDINT.h" diff --git a/src/module/Output.cpp b/src/module/Output.cpp index c5256d4ff..05df1b299 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -1,30 +1,9 @@ #include "crpropa/module/Output.h" -#include #include namespace crpropa { -void ShellOutput::process(Candidate* c) const { -#pragma omp critical - { - std::cout << std::fixed << std::showpoint << std::setprecision(3) - << std::setw(6); - std::cout << c->getTrajectoryLength() / Mpc << " Mpc, "; - std::cout << c->getRedshift() << ", "; - std::cout << c->current.getId() << ", "; - std::cout << c->current.getEnergy() / EeV << " EeV, "; - std::cout << c->current.getPosition() / Mpc << " Mpc, "; - std::cout << c->current.getDirection().getPhi() << " "; - std::cout << c->current.getDirection().getTheta(); - std::cout << std::endl; - } -} - -std::string ShellOutput::getDescription() const { - return "Shell output"; -} - TrajectoryOutput::TrajectoryOutput(std::string name) { setDescription("Trajectory output"); fout.open(name.c_str()); diff --git a/src/module/OutputShell.cpp b/src/module/OutputShell.cpp new file mode 100644 index 000000000..edc60d54d --- /dev/null +++ b/src/module/OutputShell.cpp @@ -0,0 +1,75 @@ +#include "crpropa/module/OutputShell.h" + +#include + +namespace crpropa { + +void ShellOutput::process(Candidate* c) const { +#pragma omp critical + { + std::cout << std::fixed << std::showpoint << std::setprecision(3) + << std::setw(6); + std::cout << c->getTrajectoryLength() / Mpc << " Mpc, "; + std::cout << c->getRedshift() << ", "; + std::cout << c->current.getId() << ", "; + std::cout << c->current.getEnergy() / EeV << " EeV, "; + std::cout << c->current.getPosition() / Mpc << " Mpc, "; + std::cout << c->current.getDirection(); + std::cout << std::endl; + } +} + +std::string ShellOutput::getDescription() const { + return "Shell output"; +} + +void ShellOutput1D::process(Candidate* c) const { +#pragma omp critical + { + std::cout << std::fixed << std::showpoint << std::setprecision(3) + << std::setw(6); + std::cout << c->current.getPosition().x / Mpc << " Mpc, "; + std::cout << c->getRedshift() << ", "; + std::cout << c->current.getId() << ", "; + std::cout << c->current.getEnergy() / EeV << " EeV"; + std::cout << std::endl; + } +} + +std::string ShellOutput1D::getDescription() const { + return "Shell output for 1D"; +} + +void ShellInteractionOutput::process(Candidate* c) const { + InteractionStatesMap states = c->getInteractionStates(); + InteractionStatesMap::const_iterator i = states.begin(); +#pragma omp critical + { + for (i; i != states.end(); i++) { + std::cout << " " << i->first << ", "; + std::cout << "distance: " << i->second.distance / Mpc << " Mpc, "; + std::cout << "channel: " << i->second.channel << std::endl; + } + } +} + +std::string ShellInteractionOutput::getDescription() const { + return "Shell interaction output"; +} + +void ShellPropertyOutput::process(Candidate* c) const { + PropertyMap properties = c->getProperties(); + PropertyMap::const_iterator i = properties.begin(); +#pragma omp critical + { + for (i; i != properties.end(); i++) { + std::cout << " " << i->first << ", " << i->second << std::endl; + } + } +} + +std::string ShellPropertyOutput::getDescription() const { + return "Shell property output"; +} + +} // namespace crpropa From a9726f4a8ce5140c2660fb5c9be0fcc8a5655e50 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 8 Oct 2013 08:51:50 +0200 Subject: [PATCH 0346/1298] renamed Output -> OutputASCII --- CMakeLists.txt | 2 +- include/crpropa/module/{Output.h => OutputASCII.h} | 6 +++--- python/crpropa.i | 4 ++-- src/XmlExecute.cpp | 2 +- src/module/{Output.cpp => OutputASCII.cpp} | 2 +- test/testOutput.cpp | 3 +-- 6 files changed, 9 insertions(+), 10 deletions(-) rename include/crpropa/module/{Output.h => OutputASCII.h} (93%) rename src/module/{Output.cpp => OutputASCII.cpp} (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index a11ffd5fb..661fd1547 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,7 +128,7 @@ add_library(crpropa SHARED src/module/PhotoPionProduction.cpp src/module/PhotoDisintegration.cpp src/module/Redshift.cpp - src/module/Output.cpp + src/module/OutputASCII.cpp src/module/OutputShell.cpp src/module/OutputROOT.cpp src/module/OutputCRPropa2.cpp diff --git a/include/crpropa/module/Output.h b/include/crpropa/module/OutputASCII.h similarity index 93% rename from include/crpropa/module/Output.h rename to include/crpropa/module/OutputASCII.h index 74ccdb068..fed92c735 100644 --- a/include/crpropa/module/Output.h +++ b/include/crpropa/module/OutputASCII.h @@ -1,5 +1,5 @@ -#ifndef CRPROPA_OUTPUT_H -#define CRPROPA_OUTPUT_H +#ifndef CRPROPA_OUTPUTASCII_H +#define CRPROPA_OUTPUTASCII_H #include "crpropa/Module.h" #include "crpropa/AssocVector.h" @@ -58,4 +58,4 @@ class EventOutput1D: public Module { } // namespace crpropa -#endif // CRPROPA_OUTPUT_H +#endif // CRPROPA_OUTPUTASCII_H diff --git a/python/crpropa.i b/python/crpropa.i index eef23b9fd..74629e550 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -34,7 +34,7 @@ using std::ptrdiff_t; #include "crpropa/module/BreakCondition.h" #include "crpropa/module/Boundary.h" #include "crpropa/module/Observer.h" -#include "crpropa/module/Output.h" +#include "crpropa/module/OutputASCII.h" #include "crpropa/module/OutputShell.h" #include "crpropa/module/OutputROOT.h" #include "crpropa/module/OutputCRPropa2.h" @@ -150,7 +150,7 @@ using std::ptrdiff_t; %include "crpropa/module/Observer.h" %include "crpropa/module/SimplePropagation.h" %include "crpropa/module/DeflectionCK.h" -%include "crpropa/module/Output.h" +%include "crpropa/module/OutputASCII.h" %include "crpropa/module/OutputShell.h" %include "crpropa/module/OutputROOT.h" %include "crpropa/module/OutputCRPropa2.h" diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index eb925bc50..586204120 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -14,7 +14,7 @@ #include "crpropa/module/BreakCondition.h" #include "crpropa/module/Boundary.h" #include "crpropa/module/Observer.h" -#include "crpropa/module/Output.h" +#include "crpropa/module/OutputASCII.h" #include "crpropa/module/OutputROOT.h" #include "crpropa/module/OutputCRPropa2.h" #include "crpropa/ModuleList.h" diff --git a/src/module/Output.cpp b/src/module/OutputASCII.cpp similarity index 99% rename from src/module/Output.cpp rename to src/module/OutputASCII.cpp index 05df1b299..7d6139cad 100644 --- a/src/module/Output.cpp +++ b/src/module/OutputASCII.cpp @@ -1,4 +1,4 @@ -#include "crpropa/module/Output.h" +#include "crpropa/module/OutputASCII.h" #include diff --git a/test/testOutput.cpp b/test/testOutput.cpp index bad4ba5dc..97002eb97 100644 --- a/test/testOutput.cpp +++ b/test/testOutput.cpp @@ -1,6 +1,6 @@ /** Unit tests for output modules */ -#include "crpropa/module/Output.h" +#include "crpropa/module/OutputASCII.h" #include "crpropa/module/OutputCRPropa2.h" #include "crpropa/module/OutputROOT.h" @@ -55,6 +55,5 @@ TEST(CRPropa2ROOTEventOutput1D, removeProperty) { c.setProperty("Dected", ""); output.process(&c); EXPECT_FALSE(c.hasProperty("Detected")); - } #endif From 43bf3cb6e15a2ec6ae203bb28716e3194081215d Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 8 Oct 2013 15:17:25 +0200 Subject: [PATCH 0347/1298] ... and to OutputTXT --- CMakeLists.txt | 2 +- include/crpropa/module/{OutputASCII.h => OutputTXT.h} | 6 +++--- python/crpropa.i | 4 ++-- src/XmlExecute.cpp | 2 +- src/module/{OutputASCII.cpp => OutputTXT.cpp} | 2 +- test/testOutput.cpp | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) rename include/crpropa/module/{OutputASCII.h => OutputTXT.h} (93%) rename src/module/{OutputASCII.cpp => OutputTXT.cpp} (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 661fd1547..3d8d36269 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,7 +128,7 @@ add_library(crpropa SHARED src/module/PhotoPionProduction.cpp src/module/PhotoDisintegration.cpp src/module/Redshift.cpp - src/module/OutputASCII.cpp + src/module/OutputTXT.cpp src/module/OutputShell.cpp src/module/OutputROOT.cpp src/module/OutputCRPropa2.cpp diff --git a/include/crpropa/module/OutputASCII.h b/include/crpropa/module/OutputTXT.h similarity index 93% rename from include/crpropa/module/OutputASCII.h rename to include/crpropa/module/OutputTXT.h index fed92c735..ac8218f22 100644 --- a/include/crpropa/module/OutputASCII.h +++ b/include/crpropa/module/OutputTXT.h @@ -1,5 +1,5 @@ -#ifndef CRPROPA_OUTPUTASCII_H -#define CRPROPA_OUTPUTASCII_H +#ifndef CRPROPA_OUTPUTTXT_H +#define CRPROPA_OUTPUTTXT_H #include "crpropa/Module.h" #include "crpropa/AssocVector.h" @@ -58,4 +58,4 @@ class EventOutput1D: public Module { } // namespace crpropa -#endif // CRPROPA_OUTPUTASCII_H +#endif // CRPROPA_OUTPUTTXT_H diff --git a/python/crpropa.i b/python/crpropa.i index 74629e550..631efbc54 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -34,7 +34,7 @@ using std::ptrdiff_t; #include "crpropa/module/BreakCondition.h" #include "crpropa/module/Boundary.h" #include "crpropa/module/Observer.h" -#include "crpropa/module/OutputASCII.h" +#include "crpropa/module/OutputTXT.h" #include "crpropa/module/OutputShell.h" #include "crpropa/module/OutputROOT.h" #include "crpropa/module/OutputCRPropa2.h" @@ -150,7 +150,7 @@ using std::ptrdiff_t; %include "crpropa/module/Observer.h" %include "crpropa/module/SimplePropagation.h" %include "crpropa/module/DeflectionCK.h" -%include "crpropa/module/OutputASCII.h" +%include "crpropa/module/OutputTXT.h" %include "crpropa/module/OutputShell.h" %include "crpropa/module/OutputROOT.h" %include "crpropa/module/OutputCRPropa2.h" diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 586204120..9fed88f27 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -14,7 +14,7 @@ #include "crpropa/module/BreakCondition.h" #include "crpropa/module/Boundary.h" #include "crpropa/module/Observer.h" -#include "crpropa/module/OutputASCII.h" +#include "crpropa/module/OutputTXT.h" #include "crpropa/module/OutputROOT.h" #include "crpropa/module/OutputCRPropa2.h" #include "crpropa/ModuleList.h" diff --git a/src/module/OutputASCII.cpp b/src/module/OutputTXT.cpp similarity index 99% rename from src/module/OutputASCII.cpp rename to src/module/OutputTXT.cpp index 7d6139cad..ed6dc04c9 100644 --- a/src/module/OutputASCII.cpp +++ b/src/module/OutputTXT.cpp @@ -1,4 +1,4 @@ -#include "crpropa/module/OutputASCII.h" +#include "crpropa/module/OutputTXT.h" #include diff --git a/test/testOutput.cpp b/test/testOutput.cpp index 97002eb97..cbc78111f 100644 --- a/test/testOutput.cpp +++ b/test/testOutput.cpp @@ -1,6 +1,6 @@ /** Unit tests for output modules */ -#include "crpropa/module/OutputASCII.h" +#include "crpropa/module/OutputTXT.h" #include "crpropa/module/OutputCRPropa2.h" #include "crpropa/module/OutputROOT.h" From c684fb5b53f5a5a018955da5b96c2702147f3be2 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 8 Oct 2013 15:22:07 +0200 Subject: [PATCH 0348/1298] lots of refactoring commit before change in stochastic interactions --- include/crpropa/Candidate.h | 17 +++---- include/crpropa/module/NuclearDecay.h | 5 +- include/crpropa/module/PhotoDisintegration.h | 6 +-- include/crpropa/module/PhotoPionProduction.h | 14 +++--- .../crpropa/module/StochasticInteraction.h | 5 +- src/Candidate.cpp | 34 +++++++------ src/module/NuclearDecay.cpp | 12 ++--- src/module/PhotoDisintegration.cpp | 13 +++-- src/module/PhotoPionProduction.cpp | 50 ++++++++++++------- src/module/StochasticInteraction.cpp | 31 ++++++------ test/testInteraction.cpp | 49 +++++++++--------- 11 files changed, 126 insertions(+), 110 deletions(-) diff --git a/include/crpropa/Candidate.h b/include/crpropa/Candidate.h index 57441e724..d8da32523 100644 --- a/include/crpropa/Candidate.h +++ b/include/crpropa/Candidate.h @@ -13,18 +13,16 @@ namespace crpropa { /** @class InteractionState - @brief Candidate state for stochastic interactions. + @brief State for stochastic interactions. */ struct InteractionState { InteractionState() : distance(0), channel(0) { - } InteractionState(double distance, int channel) : distance(distance), channel(channel) { - } - double distance; /**< Free distance of the interaction in [m] as light travel distance */ + double distance; /**< Comoving distance [m] to the next interaction */ int channel; /**< Interaction ID */ }; @@ -51,7 +49,7 @@ class Candidate: public Referenced { private: bool active; /**< Active status */ - double redshift; /**< Current simulation time-point in terms of redshift z, z = 0 being the present */ + double redshift; /**< Current simulation time-point in terms of redshift z */ double trajectoryLength; /**< Comoving distance [m] the candidate has travelled so far */ double currentStep; /**< Size of the currently performed step in [m] comoving units */ double nextStep; /**< Proposed size of the next propagation step in [m] comoving units */ @@ -83,17 +81,18 @@ class Candidate: public Referenced { void limitNextStep(double step); void setProperty(const std::string &name, const std::string &value); - bool removeProperty(const std::string &name); bool getProperty(const std::string &name, std::string &value) const; + bool removeProperty(const std::string &name); bool hasProperty(const std::string &name) const; + const PropertyMap getProperties() const; + void setInteractionState(const std::string &name, + const InteractionState &state); bool getInteractionState(const std::string &name, InteractionState &state) const; - void setInteractionState(const std::string &name, - const InteractionState &state); - const InteractionStatesMap getInteractionStates() const; void removeInteractionState(const std::string &name); void clearInteractionStates(); + const InteractionStatesMap getInteractionStates() const; void addSecondary(int id, double energy); void clearSecondaries(); diff --git a/include/crpropa/module/NuclearDecay.h b/include/crpropa/module/NuclearDecay.h index 6527b12be..9d3bcf92e 100644 --- a/include/crpropa/module/NuclearDecay.h +++ b/include/crpropa/module/NuclearDecay.h @@ -28,9 +28,10 @@ class NuclearDecay: public StochasticInteraction { NuclearDecay(bool electrons = false, bool neutrinos = false); void setHaveElectrons(bool b); void setHaveNeutrinos(bool b); - bool setNextInteraction(Candidate *candidate, + bool randomInteraction(Candidate *candidate, + InteractionState &interaction) const; + void performInteraction(Candidate *candidate, InteractionState &interaction) const; - void performInteraction(Candidate *candidate) const; void betaDecay(Candidate *candidate, bool isBetaPlus) const; void nucleonEmission(Candidate *candidate, int dA, int dZ) const; }; diff --git a/include/crpropa/module/PhotoDisintegration.h b/include/crpropa/module/PhotoDisintegration.h index 3e7c42734..c50d54a06 100644 --- a/include/crpropa/module/PhotoDisintegration.h +++ b/include/crpropa/module/PhotoDisintegration.h @@ -28,10 +28,10 @@ class PhotoDisintegration: public StochasticInteraction { PhotoDisintegration(PhotonField photonField = CMB); void init(PhotonField photonField); void init(std::string filename); - bool setNextInteraction(Candidate *candidate, + bool randomInteraction(Candidate *candidate, + InteractionState &interaction) const; + void performInteraction(Candidate *candidate, InteractionState &interaction) const; - void performInteraction(Candidate *candidate) const; - /** Calculates the energy loss length 1/E dE/dx in [m] diff --git a/include/crpropa/module/PhotoPionProduction.h b/include/crpropa/module/PhotoPionProduction.h index 1ff6513e3..512521081 100644 --- a/include/crpropa/module/PhotoPionProduction.h +++ b/include/crpropa/module/PhotoPionProduction.h @@ -11,9 +11,6 @@ namespace crpropa { /** @class PhotoPionProduction @brief Photo-pion interactions of nuclei with background photons. - - This module simulates photo-hadronic interactions of nuclei with background photons.\n - Several photon fields can be selected. They are considered as homogeneous and evolving as the CMB.\n */ class PhotoPionProduction: public StochasticInteraction { protected: @@ -27,9 +24,12 @@ class PhotoPionProduction: public StochasticInteraction { void setPhotonField(PhotonField photonField); void init(); void init(std::string filename); - bool setNextInteraction(Candidate *candidate, + + bool randomInteraction(Candidate *candidate, + InteractionState &interaction) const; + + void performInteraction(Candidate *candidate, InteractionState &interaction) const; - void performInteraction(Candidate *candidate) const; double nucleiModification(int A, int X) const; @@ -46,7 +46,6 @@ class PhotoPionProduction: public StochasticInteraction { @brief Photo-pion interactions of nuclei with background photons using SOPHIA. This module simulates photo-hadronic interactions of nuclei with background photons.\n - Several photon fields can be selected. They are considered as homogeneous and evolving as the CMB.\n The interaction itself is simulated with SOPHIA.\n Electromagnetic particles, neutrinos and antiparticles as secondaries from these interactions can be switched on independently. */ @@ -62,7 +61,8 @@ class SophiaPhotoPionProduction: public PhotoPionProduction { void setHavePhotons(bool b); void setHaveNeutrinos(bool b); void setHaveAntiNucleons(bool b); - void performInteraction(Candidate *candidate) const; + void performInteraction(Candidate *candidate, + InteractionState &interaction) const; }; } // namespace crpropa diff --git a/include/crpropa/module/StochasticInteraction.h b/include/crpropa/module/StochasticInteraction.h index 0dbb61fb5..3cc9ed357 100644 --- a/include/crpropa/module/StochasticInteraction.h +++ b/include/crpropa/module/StochasticInteraction.h @@ -12,9 +12,10 @@ namespace crpropa { class StochasticInteraction: public Module { public: void process(Candidate *candidate) const; - virtual bool setNextInteraction(Candidate *candidate, + virtual bool randomInteraction(Candidate *candidate, + InteractionState &interaction) const = 0; + virtual void performInteraction(Candidate *candidate, InteractionState &interaction) const = 0; - virtual void performInteraction(Candidate *candidate) const = 0; }; } // namespace crpropa diff --git a/src/Candidate.cpp b/src/Candidate.cpp index 1bd0b8bae..2d45174fd 100644 --- a/src/Candidate.cpp +++ b/src/Candidate.cpp @@ -58,6 +58,11 @@ void Candidate::limitNextStep(double step) { nextStep = std::min(nextStep, step); } +void Candidate::setInteractionState(const std::string &name, + const InteractionState &state) { + interactionStates[name] = state; +} + bool Candidate::getInteractionState(const std::string &name, InteractionState &state) const { InteractionStatesMap::const_iterator i = interactionStates.find(name); @@ -67,15 +72,6 @@ bool Candidate::getInteractionState(const std::string &name, return true; } -const Candidate::InteractionStatesMap Candidate::getInteractionStates() const { - return interactionStates; -} - -void Candidate::setInteractionState(const std::string &name, - const InteractionState &state) { - interactionStates[name] = state; -} - void Candidate::removeInteractionState(const std::string &name) { InteractionStatesMap::iterator i = interactionStates.find(name); if (i == interactionStates.end()) @@ -87,23 +83,27 @@ void Candidate::clearInteractionStates() { interactionStates.clear(); } +const Candidate::InteractionStatesMap Candidate::getInteractionStates() const { + return interactionStates; +} + void Candidate::setProperty(const std::string &name, const std::string &value) { properties[name] = value; } -bool Candidate::removeProperty(const std::string& name) { - PropertyMap::iterator i = properties.find(name); +bool Candidate::getProperty(const std::string &name, std::string &value) const { + PropertyMap::const_iterator i = properties.find(name); if (i == properties.end()) return false; - properties.erase(i); + value = i->second; return true; } -bool Candidate::getProperty(const std::string &name, std::string &value) const { - PropertyMap::const_iterator i = properties.find(name); +bool Candidate::removeProperty(const std::string& name) { + PropertyMap::iterator i = properties.find(name); if (i == properties.end()) return false; - value = i->second; + properties.erase(i); return true; } @@ -114,6 +114,10 @@ bool Candidate::hasProperty(const std::string &name) const { return true; } +const Candidate::PropertyMap Candidate::getProperties() const { + return properties; +} + void Candidate::addSecondary(int id, double energy) { ref_ptr secondary = new Candidate; secondary->setRedshift(redshift); diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index c1b79ad75..0ee05e0f3 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -30,7 +30,7 @@ NuclearDecay::NuclearDecay(bool electrons, bool neutrinos) : if (infile) decayTable[Z * 31 + N].push_back(decay); } - infile.ignore(std::numeric_limits::max(), '\n'); + infile.ignore(std::numeric_limits < std::streamsize > ::max(), '\n'); } infile.close(); @@ -56,10 +56,10 @@ void NuclearDecay::setHaveNeutrinos(bool b) { haveNeutrinos = b; } -bool NuclearDecay::setNextInteraction(Candidate *candidate, +bool NuclearDecay::randomInteraction(Candidate *candidate, InteractionState &interaction) const { int id = candidate->current.getId(); - if (not(isNucleus(id))) + if (not (isNucleus(id))) return false; // accept only nuclei int A = massNumber(id); @@ -88,10 +88,8 @@ bool NuclearDecay::setNextInteraction(Candidate *candidate, return true; } -void NuclearDecay::performInteraction(Candidate *candidate) const { - InteractionState decay; - candidate->getInteractionState(getDescription(), decay); - candidate->clearInteractionStates(); +void NuclearDecay::performInteraction(Candidate *candidate, + InteractionState &decay) const { // parse decay channels int nBetaMinus = digit(decay.channel, 10000); diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 452419ea5..aec70643c 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -42,7 +42,8 @@ void PhotoDisintegration::init(std::string filename) { std::ifstream infile(filename.c_str()); if (!infile.good()) throw std::runtime_error( - "crpropa::PhotoDisintegration: could not open file " + filename); + "crpropa::PhotoDisintegration: could not open file " + + filename); std::string line; while (std::getline(infile, line)) { @@ -69,10 +70,10 @@ void PhotoDisintegration::init(std::string filename) { infile.close(); } -bool PhotoDisintegration::setNextInteraction(Candidate *candidate, +bool PhotoDisintegration::randomInteraction(Candidate *candidate, InteractionState &interaction) const { int id = candidate->current.getId(); - if (not(isNucleus(id))) + if (not (isNucleus(id))) return false; // accept only nuclei int A = massNumber(id); @@ -111,10 +112,8 @@ bool PhotoDisintegration::setNextInteraction(Candidate *candidate, return true; } -void PhotoDisintegration::performInteraction(Candidate *candidate) const { - InteractionState interaction; - candidate->getInteractionState(getDescription(), interaction); - candidate->clearInteractionStates(); +void PhotoDisintegration::performInteraction(Candidate *candidate, + InteractionState &interaction) const { // parse disintegration channel int nNeutron = digit(interaction.channel, 100000); diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 053464d20..778ad0ef9 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -30,9 +30,10 @@ void PhotoPionProduction::init() { } else if (photonField == IRB) { init(getDataPath("photopion_IRB.txt")); setDescription("PhotoPionProduction: IRB"); - } else + } else { throw std::runtime_error( "PhotoPionProduction: unknown photon background"); + } } void PhotoPionProduction::init(std::string filename) { @@ -58,7 +59,6 @@ void PhotoPionProduction::init(std::string filename) { } double PhotoPionProduction::nucleiModification(int A, int X) const { - ; if (A == 1) return 1.; if (A < 8) @@ -67,8 +67,9 @@ double PhotoPionProduction::nucleiModification(int A, int X) const { return 0.85 * X; } -bool PhotoPionProduction::setNextInteraction(Candidate *candidate, +bool PhotoPionProduction::randomInteraction(Candidate *candidate, InteractionState &interaction) const { + int id = candidate->current.getId(); if (not (isNucleus(id))) return false; // accept only nuclei @@ -80,9 +81,10 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, int N = A - Z; double Eeff = E / A * (1 + z); // effective energy per nucleon at redshift z - // check if out of energy range - if ((Eeff < energy.front()) or (Eeff > energy.back())) + // check if outside tabulated energy range + if (Eeff < energy.front() or (Eeff > energy.back())) { return false; + } // find interaction with minimum random distance interaction.distance = std::numeric_limits::max(); @@ -90,7 +92,14 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, // check for interaction on protons if (Z > 0) { - double rate = interpolate(Eeff, energy, pRate); +// double rate = interpolate(Eeff, energy, pRate); + + // FIXME temporary wrong interpolation + std::vector::const_iterator it = std::upper_bound( + energy.begin(), energy.end(), Eeff); + size_t i = it - energy.begin() - 1; + double rate = pRate[i]; + if (rate > 0) { rate *= nucleiModification(A, Z); interaction.distance = -log(random.rand()) / rate; @@ -100,7 +109,14 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, // check for interaction on neutrons if (N > 0) { - double rate = interpolate(Eeff, energy, nRate); +// double rate = interpolate(Eeff, energy, nRate); + + // FIXME temporary wrong interpolation + std::vector::const_iterator it = std::upper_bound( + energy.begin(), energy.end(), Eeff); + size_t i = it - energy.begin() - 1; + double rate = nRate[i]; + if (rate > 0) { rate *= nucleiModification(A, N); double d = -log(random.rand()) / rate; @@ -112,15 +128,12 @@ bool PhotoPionProduction::setNextInteraction(Candidate *candidate, } interaction.distance /= pow(1 + z, 3) * photonFieldScaling(photonField, z); - - candidate->setInteractionState(getDescription(), interaction); + interaction.distance *= (1 + z); return true; } -void PhotoPionProduction::performInteraction(Candidate *candidate) const { - InteractionState interaction; - candidate->getInteractionState(getDescription(), interaction); - candidate->clearInteractionStates(); +void PhotoPionProduction::performInteraction(Candidate *candidate, + InteractionState &interaction) const { // charge number loss of interaction nucleus int dZ = interaction.channel; @@ -194,7 +207,8 @@ void SophiaPhotoPionProduction::setHaveAntiNucleons(bool b) { haveAntiNucleons = b; } -void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { +void SophiaPhotoPionProduction::performInteraction(Candidate *candidate, + InteractionState &interaction) const { int id = candidate->current.getId(); int A = massNumber(id); int Z = chargeNumber(id); @@ -202,19 +216,19 @@ void SophiaPhotoPionProduction::performInteraction(Candidate *candidate) const { double EpA = E / A; double redshift = candidate->getRedshift(); + candidate->current.setEnergy(E * 0.5); // FIXME + return; // FIXME + // check if energy, shifted by *(1+z), is still above SOPHIA's threshold // if below the threshold, remove interaction state and return double Eth = (photonField == CMB) ? 3.75 * EeV : 0.01 * EeV; if (EpA * (1 + redshift) < Eth) { candidate->removeInteractionState(getDescription()); +// std::cout << "performInteraction: below threshold" << std::endl; return; } // else continue - InteractionState interaction; - candidate->getInteractionState(getDescription(), interaction); - candidate->clearInteractionStates(); - int channel = interaction.channel; // 1 for interaction proton, 0 for neutron // arguments for sophia diff --git a/src/module/StochasticInteraction.cpp b/src/module/StochasticInteraction.cpp index 5c9ef98bc..e16456572 100644 --- a/src/module/StochasticInteraction.cpp +++ b/src/module/StochasticInteraction.cpp @@ -2,34 +2,33 @@ namespace crpropa { -void StochasticInteraction::process(Candidate* candidate) const { - // interaction distances are in physical distances --> get physical step size: dx = dx_comoving / (1 + z) - double z = candidate->getRedshift(); - double step = candidate->getCurrentStep() / (1 + z); +void StochasticInteraction::process(Candidate* c) const { + double step = c->getCurrentStep(); while (step >= 0) { - // get the interaction state, if there is one + // get the interaction, if there is one InteractionState interaction; - bool noState = !candidate->getInteractionState(getDescription(), - interaction); + bool hasOne = c->getInteractionState(getDescription(), interaction); - // if no interaction state, set a new one - if (noState) { - bool noNewState = !setNextInteraction(candidate, interaction); - if (noNewState) - return; // no new interaction; return + // if no interaction, try to set a new one + if (not hasOne) { + bool hasOneNow = randomInteraction(c, interaction); + if (not hasOneNow) { + return; // no new interaction, nothing more to do + } } // if interaction distance not reached, reduce it and return if (interaction.distance > step) { interaction.distance -= step; - candidate->limitNextStep(interaction.distance * (1 + z)); - candidate->setInteractionState(getDescription(), interaction); + c->limitNextStep(interaction.distance); + c->setInteractionState(getDescription(), interaction); return; } - // else: interaction distance reached; interact and repeat with remaining step - performInteraction(candidate); + // if interaction distance reached, interact and repeat with remaining step + performInteraction(c, interaction); + c->clearInteractionStates(); step -= interaction.distance; } } diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 800ffaf4e..927dade7c 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -171,7 +171,7 @@ TEST(NuclearDecay, Neutron) { InteractionState state; double tau = 0; for (int i = 0; i < 100000; i++) { - decay.setNextInteraction(&candidate, state); + decay.randomInteraction(&candidate, state); tau += state.distance; } tau /= c_light * 100000; @@ -262,8 +262,7 @@ TEST(NuclearDecay, AllWorking) { c.current.setId(nucleusId(Z + N, Z)); c.current.setEnergy(80 * EeV); - c.setInteractionState(d.getDescription(), interaction); - d.performInteraction(&c); + d.performInteraction(&c, interaction); } infile.ignore(std::numeric_limits::max(), '\n'); } @@ -279,7 +278,7 @@ TEST(NuclearDecay, NoNucleus) { NuclearDecay d; InteractionState state; - EXPECT_FALSE(d.setNextInteraction(&c, state)); + EXPECT_FALSE(d.randomInteraction(&c, state)); EXPECT_EQ(0, state.channel); } @@ -362,7 +361,7 @@ TEST(PhotoDisintegration, NoNucleus) { PhotoDisintegration module; InteractionState state; - EXPECT_FALSE(module.setNextInteraction(&c, state)); + EXPECT_FALSE(module.randomInteraction(&c, state)); EXPECT_EQ(0, state.channel); } @@ -404,8 +403,7 @@ TEST(PhotoDisintegration, AllWorkingCMB) { c.current.setId(nucleusId(Z + N, Z)); c.current.setEnergy(80 * EeV); - c.setInteractionState(pd.getDescription(), interaction); - pd.performInteraction(&c); + pd.performInteraction(&c, interaction); } infile.close(); } @@ -437,8 +435,7 @@ TEST(PhotoDisintegration, AllWorkingIRB) { c.current.setId(nucleusId(Z + N, Z)); c.current.setEnergy(80 * EeV); - c.setInteractionState(pd.getDescription(), interaction); - pd.performInteraction(&c); + pd.performInteraction(&c, interaction); } infile.close(); } @@ -488,7 +485,7 @@ TEST(PhotoPionProduction, NoNucleus) { PhotoPionProduction module; InteractionState state; - EXPECT_FALSE(module.setNextInteraction(&c, state)); + EXPECT_FALSE(module.randomInteraction(&c, state)); EXPECT_EQ(0, state.channel); } @@ -512,10 +509,16 @@ TEST(SophiaPhotoPionProduction, withoutSecondaries) { c.current.setId(nucleusId(1, 1)); c.current.setEnergy(100 * EeV); ppp.process(&c); - EXPECT_GT(100 * EeV, c.current.getEnergy()); // energy loss + + // energy loss + EXPECT_GT(100 * EeV, c.current.getEnergy()); + + // nucleon number conserved int id = c.current.getId(); - EXPECT_EQ(1, massNumber(id)); // nucleon number conserved - EXPECT_EQ(0, c.secondaries.size()); // secondaries turned off + EXPECT_EQ(1, massNumber(id)); + + // secondaries turned off + EXPECT_EQ(0, c.secondaries.size()); } TEST(SophiaPhotoPionProduction, withSecondaries) { @@ -526,10 +529,10 @@ TEST(SophiaPhotoPionProduction, withSecondaries) { c.current.setId(nucleusId(1, 1)); c.current.setEnergy(100 * EeV); InteractionState interaction; - ppp.setNextInteraction(&c, interaction); - ppp.performInteraction(&c); + ppp.performInteraction(&c, interaction); + + // there should be secondaries secondaries turned on EXPECT_GT(c.secondaries.size(), 1); - // secondaries turned on } TEST(SophiaPhotoPionProduction, belowSophiaEnergyThreshold_CMB) { @@ -540,10 +543,9 @@ TEST(SophiaPhotoPionProduction, belowSophiaEnergyThreshold_CMB) { Candidate c; c.current.setId(nucleusId(1, 1)); c.current.setEnergy(2 * EeV); - InteractionState state(1 * Mpc, 1); - - c.setInteractionState(ppp.getDescription(), state); - ppp.performInteraction(&c); + InteractionState interaction(1 * Mpc, 1); + c.setInteractionState(ppp.getDescription(), interaction); + ppp.performInteraction(&c, interaction); // no interaction should have happened EXPECT_DOUBLE_EQ(2, c.current.getEnergy() / EeV); @@ -562,10 +564,9 @@ TEST(SophiaPhotoPionProduction, belowSophiaEnergyThreshold_IRB) { Candidate c; c.current.setId(nucleusId(1, 1)); c.current.setEnergy(0.005 * EeV); - InteractionState state(1 * Mpc, 1); - - c.setInteractionState(ppp.getDescription(), state); - ppp.performInteraction(&c); + InteractionState interaction(1 * Mpc, 1); + c.setInteractionState(ppp.getDescription(), interaction); + ppp.performInteraction(&c, interaction); // no interaction should have happened EXPECT_DOUBLE_EQ(0.005, c.current.getEnergy() / EeV); From e49991a0f3211e21f0a67fa26cc1a0a730c56177 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 9 Oct 2013 18:10:22 +0200 Subject: [PATCH 0349/1298] change process method in PhotoPionProduction --- include/crpropa/module/PhotoPionProduction.h | 54 ++--- src/module/PhotoPionProduction.cpp | 231 +++++++------------ test/testInteraction.cpp | 2 + 3 files changed, 97 insertions(+), 190 deletions(-) diff --git a/include/crpropa/module/PhotoPionProduction.h b/include/crpropa/module/PhotoPionProduction.h index 512521081..4f17aea4a 100644 --- a/include/crpropa/module/PhotoPionProduction.h +++ b/include/crpropa/module/PhotoPionProduction.h @@ -1,7 +1,7 @@ #ifndef CRPROPA_PHOTOPIONPRODUCTION_H #define CRPROPA_PHOTOPIONPRODUCTION_H -#include "crpropa/module/StochasticInteraction.h" +#include "crpropa/Module.h" #include "crpropa/PhotonBackground.h" #include @@ -12,57 +12,31 @@ namespace crpropa { @class PhotoPionProduction @brief Photo-pion interactions of nuclei with background photons. */ -class PhotoPionProduction: public StochasticInteraction { -protected: +class PhotoPionProduction: public Module { +private: PhotonField photonField; std::vector pRate; // interaction rate in [1/m] for protons std::vector nRate; // interaction rate in [1/m] for neutrons std::vector energy; // energy in [J] - -public: - PhotoPionProduction(PhotonField photonField = CMB); - void setPhotonField(PhotonField photonField); - void init(); - void init(std::string filename); - - bool randomInteraction(Candidate *candidate, - InteractionState &interaction) const; - - void performInteraction(Candidate *candidate, - InteractionState &interaction) const; - - double nucleiModification(int A, int X) const; - - /** - Calculates the energy loss length 1/E dE/dx in [m]. This is not used in the simulation. - @param id PDG particle id - @param energy particle energy [J] - */ - double energyLossLength(int id, double energy); -}; - -/** - @class SophiaPhotoPionProduction - @brief Photo-pion interactions of nuclei with background photons using SOPHIA. - - This module simulates photo-hadronic interactions of nuclei with background photons.\n - The interaction itself is simulated with SOPHIA.\n - Electromagnetic particles, neutrinos and antiparticles as secondaries from these interactions can be switched on independently. - */ -class SophiaPhotoPionProduction: public PhotoPionProduction { -private: + double limit; // fraction of mean free path to limit the next step bool havePhotons; bool haveNeutrinos; bool haveAntiNucleons; public: - SophiaPhotoPionProduction(PhotonField photonField = CMB, bool photons = - false, bool neutrinos = false, bool antiNucleons = false); + PhotoPionProduction(PhotonField photonField = CMB, + bool photons = false, bool neutrinos = false, bool antiNucleons = + false, double limit = 0.1); + void setPhotonField(PhotonField photonField); void setHavePhotons(bool b); void setHaveNeutrinos(bool b); void setHaveAntiNucleons(bool b); - void performInteraction(Candidate *candidate, - InteractionState &interaction) const; + void setLimit(double limit); + void init(); + void init(std::string filename); + void process(Candidate *candidate) const; + void performInteraction(Candidate *candidate, int channel) const; + double nucleiModification(int A, int X) const; }; } // namespace crpropa diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 778ad0ef9..3eac5c51c 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -13,8 +13,13 @@ namespace crpropa { -PhotoPionProduction::PhotoPionProduction(PhotonField photonField) : - photonField(photonField) { +PhotoPionProduction::PhotoPionProduction(PhotonField field, + bool photons, bool neutrinos, bool antiNucleons, double l) { + photonField = field; + havePhotons = photons; + haveNeutrinos = neutrinos; + haveAntiNucleons = antiNucleons; + limit = l; init(); } @@ -23,6 +28,22 @@ void PhotoPionProduction::setPhotonField(PhotonField photonField) { init(); } +void PhotoPionProduction::setHavePhotons(bool b) { + havePhotons = b; +} + +void PhotoPionProduction::setHaveNeutrinos(bool b) { + haveNeutrinos = b; +} + +void PhotoPionProduction::setHaveAntiNucleons(bool b) { + haveAntiNucleons = b; +} + +void PhotoPionProduction::setLimit(double l) { + limit = l; +} + void PhotoPionProduction::init() { if (photonField == CMB) { init(getDataPath("photopion_CMB.txt")); @@ -67,169 +88,79 @@ double PhotoPionProduction::nucleiModification(int A, int X) const { return 0.85 * X; } -bool PhotoPionProduction::randomInteraction(Candidate *candidate, - InteractionState &interaction) const { - - int id = candidate->current.getId(); - if (not (isNucleus(id))) - return false; // accept only nuclei - - double z = candidate->getRedshift(); - double E = candidate->current.getEnergy(); - int A = massNumber(id); - int Z = chargeNumber(id); - int N = A - Z; - double Eeff = E / A * (1 + z); // effective energy per nucleon at redshift z - - // check if outside tabulated energy range - if (Eeff < energy.front() or (Eeff > energy.back())) { - return false; - } - - // find interaction with minimum random distance - interaction.distance = std::numeric_limits::max(); - Random &random = Random::instance(); - - // check for interaction on protons - if (Z > 0) { -// double rate = interpolate(Eeff, energy, pRate); - - // FIXME temporary wrong interpolation - std::vector::const_iterator it = std::upper_bound( - energy.begin(), energy.end(), Eeff); - size_t i = it - energy.begin() - 1; - double rate = pRate[i]; - - if (rate > 0) { +void PhotoPionProduction::process(Candidate *candidate) const { + // the loop should be processed at least once for limiting the next step + double step = candidate->getCurrentStep(); + do { + // check if nucleus + int id = candidate->current.getId(); + if (not (isNucleus(id))) + return; + + double z = candidate->getRedshift(); + double E = candidate->current.getEnergy(); + int A = massNumber(id); + int Z = chargeNumber(id); + int N = A - Z; + double Eeff = E / A * (1 + z); // effective energy per nucleon + + // check if in tabulated energy range + if (Eeff < energy.front() or (Eeff > energy.back())) + return; + + // find interaction with minimum random distance + Random &random = Random::instance(); + double randDistance = std::numeric_limits::max(); + int channel; // interacting particle: 1 for proton, 0 for neutron + double totalRate = 0; + + // comological scaling of interaction distance (comoving) + double scaling = pow(1 + z, 2) * photonFieldScaling(photonField, z); + + // check for interaction on protons + if (Z > 0) { + double rate = interpolate(Eeff, energy, pRate); rate *= nucleiModification(A, Z); - interaction.distance = -log(random.rand()) / rate; - interaction.channel = 1; + rate *= scaling; + totalRate += rate; + channel = 1; + randDistance = -log(random.rand()) / rate; } - } - - // check for interaction on neutrons - if (N > 0) { -// double rate = interpolate(Eeff, energy, nRate); - // FIXME temporary wrong interpolation - std::vector::const_iterator it = std::upper_bound( - energy.begin(), energy.end(), Eeff); - size_t i = it - energy.begin() - 1; - double rate = nRate[i]; - - if (rate > 0) { + // check for interaction on neutrons + if (N > 0) { + double rate = interpolate(Eeff, energy, nRate); rate *= nucleiModification(A, N); + rate *= scaling; + totalRate += rate; double d = -log(random.rand()) / rate; - if (d < interaction.distance) { - interaction.distance = d; - interaction.channel = 0; + if (d < randDistance) { + randDistance = d; + channel = 0; } } - } - - interaction.distance /= pow(1 + z, 3) * photonFieldScaling(photonField, z); - interaction.distance *= (1 + z); - return true; -} -void PhotoPionProduction::performInteraction(Candidate *candidate, - InteractionState &interaction) const { - - // charge number loss of interaction nucleus - int dZ = interaction.channel; - // final proton number of emitted nucleon - int Zfinal = dZ; - // 50% probability of isospin change p <-> n - Random &random = Random::instance(); - if (random.rand() < 1. / 2.) - Zfinal = abs(Zfinal - 1); - - double E = candidate->current.getEnergy(); - int id = candidate->current.getId(); - int A = massNumber(id); - int Z = chargeNumber(id); - - if (A == 1) { - // interaction on single nucleon - candidate->current.setEnergy(E * 938. / 1232.); - candidate->current.setId(nucleusId(1, Zfinal)); - } else { - // interaction on nucleus, update nucleus and emit nucleon - candidate->current.setEnergy(E * (A - 1) / A); - candidate->current.setId(nucleusId(A - 1, Z - dZ)); - candidate->addSecondary(nucleusId(1, Zfinal), E / A * 938. / 1232.); - } -} - -double PhotoPionProduction::energyLossLength(int id, double E) { - int A = massNumber(id); - int Z = chargeNumber(id); - int N = A - Z; - - double EpA = E / A; - if ((EpA < energy.front()) or (EpA > energy.back())) - return std::numeric_limits::max(); - - // protons / neutrons keep as energy the fraction of mass to delta-resonance mass (crude approximation) - // nuclei approximately lose the energy that the interacting nucleon is carrying - double relativeEnergyLoss = (A == 1) ? 1 - 938. / 1232. : 1. / A; - - double lossRate = 0; - if (Z > 0) { - double rate = interpolate(EpA, energy, pRate); - rate *= nucleiModification(A, Z); - lossRate += relativeEnergyLoss * rate; - } - if (N > 0) { - double rate = interpolate(EpA, energy, nRate); - rate *= nucleiModification(A, N); - lossRate += relativeEnergyLoss * rate; - } - - return 1. / lossRate; -} - -SophiaPhotoPionProduction::SophiaPhotoPionProduction(PhotonField photonField, - bool photons, bool neutrinos, bool antiNucleons) : - PhotoPionProduction(photonField), havePhotons(photons), haveNeutrinos( - neutrinos), haveAntiNucleons(antiNucleons) { -} - -void SophiaPhotoPionProduction::setHavePhotons(bool b) { - havePhotons = b; -} + // check if interaction doesn't happen + if (step < randDistance) { + candidate->limitNextStep(limit / totalRate); + return; + } -void SophiaPhotoPionProduction::setHaveNeutrinos(bool b) { - haveNeutrinos = b; + // interact and repeat with remaining step + performInteraction(candidate, channel); + step -= randDistance; + } while (step > 0); } -void SophiaPhotoPionProduction::setHaveAntiNucleons(bool b) { - haveAntiNucleons = b; -} +void PhotoPionProduction::performInteraction(Candidate *candidate, + int channel) const { -void SophiaPhotoPionProduction::performInteraction(Candidate *candidate, - InteractionState &interaction) const { int id = candidate->current.getId(); int A = massNumber(id); int Z = chargeNumber(id); double E = candidate->current.getEnergy(); double EpA = E / A; - double redshift = candidate->getRedshift(); - - candidate->current.setEnergy(E * 0.5); // FIXME - return; // FIXME - - // check if energy, shifted by *(1+z), is still above SOPHIA's threshold - // if below the threshold, remove interaction state and return - double Eth = (photonField == CMB) ? 3.75 * EeV : 0.01 * EeV; - if (EpA * (1 + redshift) < Eth) { - candidate->removeInteractionState(getDescription()); -// std::cout << "performInteraction: below threshold" << std::endl; - return; - } - - // else continue - int channel = interaction.channel; // 1 for interaction proton, 0 for neutron + double z = candidate->getRedshift(); // arguments for sophia int nature = 1 - channel; // interacting particle: 0 for proton, 1 for neutron @@ -244,8 +175,8 @@ void SophiaPhotoPionProduction::performInteraction(Candidate *candidate, #pragma omp critical { - sophiaevent_(nature, Ein, momentaList, particleList, nParticles, - redshift, background, maxRedshift, dummy1, dummy2, dummy2); + sophiaevent_(nature, Ein, momentaList, particleList, nParticles, z, + background, maxRedshift, dummy1, dummy2, dummy2); } for (int i = 0; i < nParticles; i++) { // loop over out-going particles diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 927dade7c..6d108a971 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -440,6 +440,7 @@ TEST(PhotoDisintegration, AllWorkingIRB) { infile.close(); } +/** TEST(PhotoPionProduction, Backgrounds) { // Test if interaction data files are loaded. PhotoPionProduction ppp1(CMB); @@ -576,6 +577,7 @@ TEST(SophiaPhotoPionProduction, belowSophiaEnergyThreshold_IRB) { bool hasInteraction = c.getInteractionState(ppp.getDescription(), dummy); EXPECT_FALSE(hasInteraction); } +**/ TEST(Redshift, simpleTest) { // Test if redshift is decreased and adiabatic energy loss is applied. From ae14f3b57b04dc2b7baeb56085e1c17697bd36b5 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 9 Oct 2013 18:11:02 +0200 Subject: [PATCH 0350/1298] change process method in photodisintegration --- include/crpropa/module/PhotoDisintegration.h | 17 ++- src/module/PhotoDisintegration.cpp | 118 +++++++++++-------- 2 files changed, 75 insertions(+), 60 deletions(-) diff --git a/include/crpropa/module/PhotoDisintegration.h b/include/crpropa/module/PhotoDisintegration.h index c50d54a06..5a4a84dc3 100644 --- a/include/crpropa/module/PhotoDisintegration.h +++ b/include/crpropa/module/PhotoDisintegration.h @@ -1,7 +1,7 @@ #ifndef CRPROPA_PHOTODISINTEGRATION_H #define CRPROPA_PHOTODISINTEGRATION_H -#include "crpropa/module/StochasticInteraction.h" +#include "crpropa/Module.h" #include "crpropa/PhotonBackground.h" #include @@ -11,13 +11,11 @@ namespace crpropa { /** @class PhotoDisintegration @brief Photo-disintegration of nuclei with background photons. - - This module simulates photo-disintegration of nuclei with background photons.\n - Background photon fields are considered as homogeneous and evolving as the CMB.\n */ -class PhotoDisintegration: public StochasticInteraction { +class PhotoDisintegration: public Module { private: PhotonField photonField; + double limit; struct PDMode { int channel; // number of emitted (n, p, H2, H3, He3, He4) std::vector rate; // disintegration rate [1/m] @@ -25,13 +23,12 @@ class PhotoDisintegration: public StochasticInteraction { std::vector > pdTable; // pdTable[Z * 31 + N] = vector public: - PhotoDisintegration(PhotonField photonField = CMB); + PhotoDisintegration(PhotonField photonField = CMB, double limit = 0.1); + void setLimit(double l); void init(PhotonField photonField); void init(std::string filename); - bool randomInteraction(Candidate *candidate, - InteractionState &interaction) const; - void performInteraction(Candidate *candidate, - InteractionState &interaction) const; + void process(Candidate *candidate) const; + void performInteraction(Candidate *candidate, int channel) const; /** Calculates the energy loss length 1/E dE/dx in [m] diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index aec70643c..983723e86 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -10,10 +10,15 @@ namespace crpropa { -PhotoDisintegration::PhotoDisintegration(PhotonField photonField) { +PhotoDisintegration::PhotoDisintegration(PhotonField photonField, double l) { + limit = l; init(photonField); } +void PhotoDisintegration::setLimit(double l) { + limit = l; +} + void PhotoDisintegration::init(PhotonField photonField) { this->photonField = photonField; switch (photonField) { @@ -70,58 +75,72 @@ void PhotoDisintegration::init(std::string filename) { infile.close(); } -bool PhotoDisintegration::randomInteraction(Candidate *candidate, - InteractionState &interaction) const { - int id = candidate->current.getId(); - if (not (isNucleus(id))) - return false; // accept only nuclei - - int A = massNumber(id); - int Z = chargeNumber(id); - int N = A - Z; - - // check if disintegration data available - std::vector pdModes = pdTable[Z * 31 + N]; - if (pdModes.size() == 0) - return false; - - // CMB energy increases with (1+z), increase nucleus energy accordingly - double z = candidate->getRedshift(); - double lg = log10(candidate->current.getLorentzFactor() * (1 + z)); - - // check if out of energy range - if ((lg <= 6) or (lg >= 14)) - return false; - - // find channel with minimum random decay distance - Random &random = Random::instance(); - interaction.distance = std::numeric_limits::max(); - for (size_t i = 0; i < pdModes.size(); i++) { - double rate = interpolateEquidistant(lg, 6, 14, pdModes[i].rate); -// std::cout << pdModes[i].channel << " " << rate * Mpc << std::endl; - double d = -log(random.rand()) / rate; - if (d > interaction.distance) - continue; - interaction.distance = d; - interaction.channel = pdModes[i].channel; - } +void PhotoDisintegration::process(Candidate *candidate) const { + // the loop should be processed at least once for limiting the next step + double step = candidate->getCurrentStep(); + do { + // check if nucleus + int id = candidate->current.getId(); + if (not (isNucleus(id))) + return; + + int A = massNumber(id); + int Z = chargeNumber(id); + int N = A - Z; + + // check if disintegration data available + std::vector pdModes = pdTable[Z * 31 + N]; + if (pdModes.size() == 0) + return; + + // check if in tabulated energy range + double z = candidate->getRedshift(); + double lg = log10(candidate->current.getLorentzFactor() * (1 + z)); + if ((lg <= 6) or (lg >= 14)) + return; + + // find disintegration channel with minimum random decay distance + Random &random = Random::instance(); + double randDistance = std::numeric_limits::max(); + int channel; + double totalRate = 0; + + // comological scaling of interaction distance (comoving) + double scaling = pow(1 + z, 2) * photonFieldScaling(photonField, z); + + for (size_t i = 0; i < pdModes.size(); i++) { + double rate = interpolateEquidistant(lg, 6, 14, pdModes[i].rate); + rate *= scaling; + totalRate += rate; + double d = -log(random.rand()) / rate; + if (d > randDistance) + continue; + randDistance = d; + channel = pdModes[i].channel; + } - interaction.distance /= pow(1 + z, 3) * photonFieldScaling(photonField, z); + // check if interaction doesn't happen + if (step < randDistance) { + // limit next step to a fraction of the mean free path + candidate->limitNextStep(limit / totalRate); + return; + } - candidate->setInteractionState(getDescription(), interaction); - return true; + // interact and repeat with remaining step + performInteraction(candidate, channel); + step -= randDistance; + } while (step > 0); } void PhotoDisintegration::performInteraction(Candidate *candidate, - InteractionState &interaction) const { - - // parse disintegration channel - int nNeutron = digit(interaction.channel, 100000); - int nProton = digit(interaction.channel, 10000); - int nH2 = digit(interaction.channel, 1000); - int nH3 = digit(interaction.channel, 100); - int nHe3 = digit(interaction.channel, 10); - int nHe4 = digit(interaction.channel, 1); + int channel) const { + // interpret disintegration channel + int nNeutron = digit(channel, 100000); + int nProton = digit(channel, 10000); + int nH2 = digit(channel, 1000); + int nH3 = digit(channel, 100); + int nHe3 = digit(channel, 10); + int nHe4 = digit(channel, 1); int dA = -nNeutron - nProton - 2 * nH2 - 3 * nH3 - 3 * nHe3 - 4 * nHe4; int dZ = -nProton - nH2 - nH3 - 2 * nHe3 - 2 * nHe4; @@ -129,7 +148,7 @@ void PhotoDisintegration::performInteraction(Candidate *candidate, int id = candidate->current.getId(); int A = massNumber(id); int Z = chargeNumber(id); - double EpA = candidate->current.getEnergy() / double(A); + double EpA = candidate->current.getEnergy() / A; // update particle int nA = A + dA; @@ -164,7 +183,6 @@ double PhotoDisintegration::energyLossLength(int id, double E) { if (pdModes.size() == 0) return std::numeric_limits::max(); - // log10 of lorentz factor double lg = log10(E / (nucleusMass(id) * c_squared)); if ((lg <= 6) or (lg >= 14)) return std::numeric_limits::max(); From 8c2895eeec009695cd1f3f2733637530e2e4c888 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 9 Oct 2013 18:11:34 +0200 Subject: [PATCH 0351/1298] change process method in nuclear decay --- include/crpropa/module/NuclearDecay.h | 30 ++++---- src/module/NuclearDecay.cpp | 103 ++++++++++++++++---------- 2 files changed, 78 insertions(+), 55 deletions(-) diff --git a/include/crpropa/module/NuclearDecay.h b/include/crpropa/module/NuclearDecay.h index 9d3bcf92e..a9407e837 100644 --- a/include/crpropa/module/NuclearDecay.h +++ b/include/crpropa/module/NuclearDecay.h @@ -1,7 +1,7 @@ -#ifndef CRPROPA_DECAY_H -#define CRPROPA_DECAY_H +#ifndef CRPROPA_NUCLEARDECAY_H +#define CRPROPA_NUCLEARDECAY_H -#include "crpropa/module/StochasticInteraction.h" +#include "crpropa/Module.h" #include @@ -13,29 +13,31 @@ namespace crpropa { This module simulates the nuclear decay of unstable nuclei using data from NuDat2. */ -class NuclearDecay: public StochasticInteraction { +class NuclearDecay: public Module { private: + double limit; bool haveElectrons; bool haveNeutrinos; - - std::vector > decayTable; - // InteractionState.channel is (#beta- #beta+ #alpha #proton #neutron) - // InteractionState.distance is the mean free path [m] + struct DecayMode { + int channel; // (#beta- #beta+ #alpha #proton #neutron) + double rate; // decay rate in [1/m] + }; + std::vector > decayTable; // decayTable[Z * 31 + N] = vector std::vector tBeta; // electron kinetic energy [J] in neutron decays std::vector cdfBeta; // cumulative distribution function for the electron kinetic energy [J] in neutron decays public: - NuclearDecay(bool electrons = false, bool neutrinos = false); + NuclearDecay(bool electrons = false, bool neutrinos = false, double limit = + 0.1); + void setLimit(double limit); void setHaveElectrons(bool b); void setHaveNeutrinos(bool b); - bool randomInteraction(Candidate *candidate, - InteractionState &interaction) const; - void performInteraction(Candidate *candidate, - InteractionState &interaction) const; + void process(Candidate *candidate) const; + void performInteraction(Candidate *candidate, int channel) const; void betaDecay(Candidate *candidate, bool isBetaPlus) const; void nucleonEmission(Candidate *candidate, int dA, int dZ) const; }; } // namespace crpropa -#endif // CRPROPA_DECAY_H +#endif // CRPROPA_NUCLEARDECAY_H diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index 0ee05e0f3..dcba0d568 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -9,8 +9,10 @@ namespace crpropa { -NuclearDecay::NuclearDecay(bool electrons, bool neutrinos) : - haveElectrons(electrons), haveNeutrinos(neutrinos) { +NuclearDecay::NuclearDecay(bool electrons, bool neutrinos, double l) { + haveElectrons = electrons; + haveNeutrinos = neutrinos; + limit = l; setDescription("NuclearDecay"); // load decay table @@ -23,10 +25,11 @@ NuclearDecay::NuclearDecay(bool electrons, bool neutrinos) : decayTable.resize(27 * 31); while (infile.good()) { if (infile.peek() != '#') { - InteractionState decay; + DecayMode decay; int Z, N; - infile >> Z >> N >> decay.channel >> decay.distance; - decay.distance *= c_light; // mean decay distance [m] + double lifetime; + infile >> Z >> N >> decay.channel >> lifetime; + decay.rate = 1. / lifetime / c_light; // decay rate in [1/m] if (infile) decayTable[Z * 31 + N].push_back(decay); } @@ -56,47 +59,65 @@ void NuclearDecay::setHaveNeutrinos(bool b) { haveNeutrinos = b; } -bool NuclearDecay::randomInteraction(Candidate *candidate, - InteractionState &interaction) const { - int id = candidate->current.getId(); - if (not (isNucleus(id))) - return false; // accept only nuclei - - int A = massNumber(id); - int Z = chargeNumber(id); - int N = A - Z; - - std::vector decays = decayTable[Z * 31 + N]; - if (decays.size() == 0) - return false; +void NuclearDecay::setLimit(double l) { + limit = l; +} - // find interaction mode with minimum random decay distance - Random &random = Random::instance(); - interaction.distance = std::numeric_limits::max(); - for (size_t i = 0; i < decays.size(); i++) { - double d = -log(random.rand()) * decays[i].distance; - if (d > interaction.distance) - continue; - interaction.distance = d; - interaction.channel = decays[i].channel; - } +void NuclearDecay::process(Candidate *candidate) const { + // the loop should be processed at least once for limiting the next step + double step = candidate->getCurrentStep(); + do { + // check if nucleus + int id = candidate->current.getId(); + if (not (isNucleus(id))) + return; + + int A = massNumber(id); + int Z = chargeNumber(id); + int N = A - Z; + + // check if particle can decay + std::vector decays = decayTable[Z * 31 + N]; + if (decays.size() == 0) + return; + + // find interaction mode with minimum random decay distance + Random &random = Random::instance(); + double randDistance = std::numeric_limits::max(); + int channel; + double totalRate = 0; + + for (size_t i = 0; i < decays.size(); i++) { + double rate = decays[i].rate; + rate *= candidate->current.getLorentzFactor(); + totalRate += rate; + double d = -log(random.rand()) / rate; + if (d > randDistance) + continue; + randDistance = d; + channel = decays[i].channel; + } - // special relativistic time dilation - interaction.distance *= candidate->current.getLorentzFactor(); + // check if interaction doesn't happen + if (step < randDistance) { + // limit next step to a fraction of the mean free path + candidate->limitNextStep(limit / totalRate); + return; + } - candidate->setInteractionState(getDescription(), interaction); - return true; + // interact and repeat with remaining step + performInteraction(candidate, channel); + step -= randDistance; + } while (step > 0); } -void NuclearDecay::performInteraction(Candidate *candidate, - InteractionState &decay) const { - - // parse decay channels - int nBetaMinus = digit(decay.channel, 10000); - int nBetaPlus = digit(decay.channel, 1000); - int nAlpha = digit(decay.channel, 100); - int nProton = digit(decay.channel, 10); - int nNeutron = digit(decay.channel, 1); +void NuclearDecay::performInteraction(Candidate *candidate, int channel) const { + // interpret decay channel + int nBetaMinus = digit(channel, 10000); + int nBetaPlus = digit(channel, 1000); + int nAlpha = digit(channel, 100); + int nProton = digit(channel, 10); + int nNeutron = digit(channel, 1); // perform decays for (size_t i = 0; i < nBetaMinus; i++) From 3f36d889fc49878adc64414dfd12647321b42c48 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 9 Oct 2013 18:12:33 +0200 Subject: [PATCH 0352/1298] remove StochasticInteraction --- CMakeLists.txt | 1 - include/crpropa/Candidate.h | 44 +++---------------- include/crpropa/module/OutputShell.h | 11 ----- .../crpropa/module/StochasticInteraction.h | 23 ---------- python/crpropa.i | 2 - src/Candidate.cpp | 33 -------------- src/module/OutputShell.cpp | 22 +--------- src/module/StochasticInteraction.cpp | 36 --------------- 8 files changed, 8 insertions(+), 164 deletions(-) delete mode 100644 include/crpropa/module/StochasticInteraction.h delete mode 100644 src/module/StochasticInteraction.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d8d36269..9280b9022 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,7 +123,6 @@ add_library(crpropa SHARED src/module/SimplePropagation.cpp src/module/DeflectionCK.cpp src/module/ElectronPairProduction.cpp - src/module/StochasticInteraction.cpp src/module/NuclearDecay.cpp src/module/PhotoPionProduction.cpp src/module/PhotoDisintegration.cpp diff --git a/include/crpropa/Candidate.h b/include/crpropa/Candidate.h index d8da32523..923f856c2 100644 --- a/include/crpropa/Candidate.h +++ b/include/crpropa/Candidate.h @@ -11,29 +11,12 @@ namespace crpropa { -/** - @class InteractionState - @brief State for stochastic interactions. - */ -struct InteractionState { - InteractionState() : - distance(0), channel(0) { - } - InteractionState(double distance, int channel) : - distance(distance), channel(channel) { - } - double distance; /**< Comoving distance [m] to the next interaction */ - int channel; /**< Interaction ID */ -}; - /** @class Candidate @brief All information about the cosmic ray. The Candidate is a passive object, that holds the information about the state - of the cosmic ray at the beginning of propagation and in the current and - previous propagation step. - It holds status information about the cosmic ray and the simulation itself. + of the cosmic ray and the simulation itself. */ class Candidate: public Referenced { public: @@ -42,10 +25,10 @@ class Candidate: public Referenced { ParticleState current; /**< Current particle state */ ParticleState previous; /**< Particle state at the end of the previous step */ - std::vector > secondaries; /**< Secondary particles created in interactions */ + std::vector > secondaries; /**< Secondary particles from interactions */ typedef Loki::AssocVector PropertyMap; - typedef Loki::AssocVector InteractionStatesMap; + PropertyMap properties; /**< Map of property names and their values. */ private: bool active; /**< Active status */ @@ -54,13 +37,9 @@ class Candidate: public Referenced { double currentStep; /**< Size of the currently performed step in [m] comoving units */ double nextStep; /**< Proposed size of the next propagation step in [m] comoving units */ - PropertyMap properties; /**< Map of property names and their values. */ - InteractionStatesMap interactionStates; /**< Map of interactions that are scheduled to happen to the candidate. */ - public: Candidate(); - /** Creates a candidate, initializing the initial, previous and current particle state with the argument. */ - Candidate(const ParticleState &state); + Candidate(const ParticleState &state); /**< Creates a candidate, initializing the initial, previous and current particle state with the argument. */ bool isActive() const; void setActive(bool b); @@ -71,12 +50,10 @@ class Candidate: public Referenced { void setRedshift(double z); double getRedshift() const; - /** Sets the current step and increases the trajectory length accordingly. Only the propagation module should use this. */ - void setCurrentStep(double step); + void setCurrentStep(double step); /**< Sets the current step and increases the trajectory length accordingly. Only the propagation module should use this. */ double getCurrentStep() const; - /** Sets the proposed next step. Only the propagation module should use this. */ - void setNextStep(double step); + void setNextStep(double step); /**< Sets the proposed next step. Only the propagation module should use this. */ double getNextStep() const; void limitNextStep(double step); @@ -84,15 +61,6 @@ class Candidate: public Referenced { bool getProperty(const std::string &name, std::string &value) const; bool removeProperty(const std::string &name); bool hasProperty(const std::string &name) const; - const PropertyMap getProperties() const; - - void setInteractionState(const std::string &name, - const InteractionState &state); - bool getInteractionState(const std::string &name, - InteractionState &state) const; - void removeInteractionState(const std::string &name); - void clearInteractionStates(); - const InteractionStatesMap getInteractionStates() const; void addSecondary(int id, double energy); void clearSecondaries(); diff --git a/include/crpropa/module/OutputShell.h b/include/crpropa/module/OutputShell.h index ccbc13b22..f9a248f1e 100644 --- a/include/crpropa/module/OutputShell.h +++ b/include/crpropa/module/OutputShell.h @@ -26,17 +26,6 @@ class ShellOutput1D: public Module { std::string getDescription() const; }; -/** - @class ShellInteractionOutput - @brief Show the interaction states in the shell. - */ -class ShellInteractionOutput: public Module { -public: - typedef Loki::AssocVector InteractionStatesMap; - void process(Candidate *candidate) const; - std::string getDescription() const; -}; - /** @class ShellPropertyOutput @brief Show the candidate properties in the shell. diff --git a/include/crpropa/module/StochasticInteraction.h b/include/crpropa/module/StochasticInteraction.h deleted file mode 100644 index 3cc9ed357..000000000 --- a/include/crpropa/module/StochasticInteraction.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef CRPROPA_STOCHASTICINTERACTION_H -#define CRPROPA_STOCHASTICINTERACTION_H - -#include "crpropa/Module.h" - -namespace crpropa { - -/** - @class StochasticInteraction - @brief Base class for stochastic interactions - */ -class StochasticInteraction: public Module { -public: - void process(Candidate *candidate) const; - virtual bool randomInteraction(Candidate *candidate, - InteractionState &interaction) const = 0; - virtual void performInteraction(Candidate *candidate, - InteractionState &interaction) const = 0; -}; - -} // namespace crpropa - -#endif // CRPROPA_STOCHASTICINTERACTION_H diff --git a/python/crpropa.i b/python/crpropa.i index 631efbc54..307d04769 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -27,7 +27,6 @@ using std::ptrdiff_t; %{ #include "crpropa/module/NuclearDecay.h" #include "crpropa/module/ElectronPairProduction.h" -#include "crpropa/module/StochasticInteraction.h" #include "crpropa/module/PhotoDisintegration.h" #include "crpropa/module/PhotoPionProduction.h" #include "crpropa/module/Redshift.h" @@ -157,7 +156,6 @@ using std::ptrdiff_t; %include "crpropa/module/PhotonDINT.h" %include "crpropa/module/PhotonEleCa.h" %include "crpropa/module/ElectronPairProduction.h" -%include "crpropa/module/StochasticInteraction.h" %include "crpropa/module/NuclearDecay.h" %include "crpropa/module/PhotoPionProduction.h" %include "crpropa/module/PhotoDisintegration.h" diff --git a/src/Candidate.cpp b/src/Candidate.cpp index 2d45174fd..436473558 100644 --- a/src/Candidate.cpp +++ b/src/Candidate.cpp @@ -58,35 +58,6 @@ void Candidate::limitNextStep(double step) { nextStep = std::min(nextStep, step); } -void Candidate::setInteractionState(const std::string &name, - const InteractionState &state) { - interactionStates[name] = state; -} - -bool Candidate::getInteractionState(const std::string &name, - InteractionState &state) const { - InteractionStatesMap::const_iterator i = interactionStates.find(name); - if (i == interactionStates.end()) - return false; - state = i->second; - return true; -} - -void Candidate::removeInteractionState(const std::string &name) { - InteractionStatesMap::iterator i = interactionStates.find(name); - if (i == interactionStates.end()) - return; - interactionStates.erase(i); -} - -void Candidate::clearInteractionStates() { - interactionStates.clear(); -} - -const Candidate::InteractionStatesMap Candidate::getInteractionStates() const { - return interactionStates; -} - void Candidate::setProperty(const std::string &name, const std::string &value) { properties[name] = value; } @@ -114,10 +85,6 @@ bool Candidate::hasProperty(const std::string &name) const { return true; } -const Candidate::PropertyMap Candidate::getProperties() const { - return properties; -} - void Candidate::addSecondary(int id, double energy) { ref_ptr secondary = new Candidate; secondary->setRedshift(redshift); diff --git a/src/module/OutputShell.cpp b/src/module/OutputShell.cpp index edc60d54d..4affc36c3 100644 --- a/src/module/OutputShell.cpp +++ b/src/module/OutputShell.cpp @@ -40,29 +40,11 @@ std::string ShellOutput1D::getDescription() const { return "Shell output for 1D"; } -void ShellInteractionOutput::process(Candidate* c) const { - InteractionStatesMap states = c->getInteractionStates(); - InteractionStatesMap::const_iterator i = states.begin(); -#pragma omp critical - { - for (i; i != states.end(); i++) { - std::cout << " " << i->first << ", "; - std::cout << "distance: " << i->second.distance / Mpc << " Mpc, "; - std::cout << "channel: " << i->second.channel << std::endl; - } - } -} - -std::string ShellInteractionOutput::getDescription() const { - return "Shell interaction output"; -} - void ShellPropertyOutput::process(Candidate* c) const { - PropertyMap properties = c->getProperties(); - PropertyMap::const_iterator i = properties.begin(); + PropertyMap::const_iterator i = c->properties.begin(); #pragma omp critical { - for (i; i != properties.end(); i++) { + for (i; i != c->properties.end(); i++) { std::cout << " " << i->first << ", " << i->second << std::endl; } } diff --git a/src/module/StochasticInteraction.cpp b/src/module/StochasticInteraction.cpp deleted file mode 100644 index e16456572..000000000 --- a/src/module/StochasticInteraction.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "crpropa/module/StochasticInteraction.h" - -namespace crpropa { - -void StochasticInteraction::process(Candidate* c) const { - double step = c->getCurrentStep(); - - while (step >= 0) { - // get the interaction, if there is one - InteractionState interaction; - bool hasOne = c->getInteractionState(getDescription(), interaction); - - // if no interaction, try to set a new one - if (not hasOne) { - bool hasOneNow = randomInteraction(c, interaction); - if (not hasOneNow) { - return; // no new interaction, nothing more to do - } - } - - // if interaction distance not reached, reduce it and return - if (interaction.distance > step) { - interaction.distance -= step; - c->limitNextStep(interaction.distance); - c->setInteractionState(getDescription(), interaction); - return; - } - - // if interaction distance reached, interact and repeat with remaining step - performInteraction(c, interaction); - c->clearInteractionStates(); - step -= interaction.distance; - } -} - -} // namespace crpropa From 92939c1bdf98c8d9b17bc43c2439553c2163365e Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 9 Oct 2013 18:13:09 +0200 Subject: [PATCH 0353/1298] update interaction unit tests --- include/crpropa/module/OutputTXT.h | 1 + src/XmlExecute.cpp | 4 +- test/testInteraction.cpp | 191 +++++++++-------------------- 3 files changed, 60 insertions(+), 136 deletions(-) diff --git a/include/crpropa/module/OutputTXT.h b/include/crpropa/module/OutputTXT.h index ac8218f22..f094205bf 100644 --- a/include/crpropa/module/OutputTXT.h +++ b/include/crpropa/module/OutputTXT.h @@ -3,6 +3,7 @@ #include "crpropa/Module.h" #include "crpropa/AssocVector.h" + #include namespace crpropa { diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 9fed88f27..decb5d7cb 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -460,9 +460,9 @@ void XmlExecute::loadSophia(xml_node &node) { modules.add(new ElectronPairProduction(CMB)); if (pionprodCMB) - modules.add(new SophiaPhotoPionProduction(CMB)); + modules.add(new PhotoPionProduction(CMB)); if (pionprodIRB) - modules.add(new SophiaPhotoPionProduction(IRB)); + modules.add(new PhotoPionProduction(IRB)); if (photodisCMB and photodisIRB) modules.add(new PhotoDisintegration(CMB_IRB)); diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 6d108a971..62b93f413 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -1,17 +1,17 @@ #include "crpropa/Candidate.h" +#include "crpropa/ParticleID.h" #include "crpropa/module/ElectronPairProduction.h" #include "crpropa/module/NuclearDecay.h" #include "crpropa/module/PhotoDisintegration.h" #include "crpropa/module/PhotoPionProduction.h" #include "crpropa/module/Redshift.h" -#include "crpropa/ParticleID.h" - #include "gtest/gtest.h" + #include namespace crpropa { -TEST(ElectronPairProduction, EnergyDecreasing) { +TEST(ElectronPairProduction, energyDecreasing) { // Test if energy loss occurs for protons with energies from 1e15 - 1e23 eV Candidate c; c.setCurrentStep(2 * Mpc); @@ -42,7 +42,7 @@ TEST(ElectronPairProduction, EnergyDecreasing) { } } -TEST(ElectronPairProduction, BelowEnergyTreshold) { +TEST(ElectronPairProduction, belowEnergyTreshold) { // Test if nothing happens below 1e15 eV ElectronPairProduction epp(CMB); Candidate c; @@ -53,7 +53,7 @@ TEST(ElectronPairProduction, BelowEnergyTreshold) { EXPECT_DOUBLE_EQ(c.current.getEnergy(), E); } -TEST(ElectronPairProduction, NoNucleus) { +TEST(ElectronPairProduction, thisIsNotNucleonic) { // Test if non-nuclei are skipped ElectronPairProduction epp(CMB); Candidate c; @@ -160,25 +160,7 @@ TEST(ElectronPairProduction, valuesCMB_IRB) { } } -TEST(NuclearDecay, Neutron) { - // Quantitative test of decaying neutrons at rest. - // The mean decay time is expected to be within 1% of the literature value. - // This test can stochastically fail. - Candidate candidate; - candidate.current.setId(nucleusId(1, 0)); - candidate.current.setEnergy(mass_neutron * c_squared); - NuclearDecay decay; - InteractionState state; - double tau = 0; - for (int i = 0; i < 100000; i++) { - decay.randomInteraction(&candidate, state); - tau += state.distance; - } - tau /= c_light * 100000; - EXPECT_NEAR(tau, 881.46, 8.8); -} - -TEST(NuclearDecay, Scandium44) { +TEST(NuclearDecay, scandium44) { // Test beta+ decay of 44Sc 44Ca. // This test can stochastically fail. NuclearDecay d(true, true); @@ -201,7 +183,7 @@ TEST(NuclearDecay, Scandium44) { // electron neutrino } -TEST(NuclearDecay, Li4) { +TEST(NuclearDecay, lithium4) { // Test proton dripping of Li-4 to He-3. // This test can stochastically fail. NuclearDecay d; @@ -219,7 +201,7 @@ TEST(NuclearDecay, Li4) { EXPECT_EQ(1, c1.current.getEnergy() / EeV); } -TEST(NuclearDecay, He5) { +TEST(NuclearDecay, helium5) { // Test neturon dripping of He-5 to He-4. // This test can stochastically fail if no interaction occurs over 1 Mpc. NuclearDecay d; @@ -237,52 +219,49 @@ TEST(NuclearDecay, He5) { EXPECT_EQ(1, c2.current.getEnergy() / EeV); } -TEST(NuclearDecay, LimitNextStep) { - // Test if next step is limited. - NuclearDecay d; +TEST(NuclearDecay, limitNextStep) { + // Test if next step is limited in case of a neutron. + NuclearDecay decay; Candidate c; c.setNextStep(std::numeric_limits::max()); c.current.setId(nucleusId(1, 0)); c.current.setEnergy(10 * EeV); - d.process(&c); + decay.process(&c); EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); } -TEST(NuclearDecay, AllWorking) { +TEST(NuclearDecay, allWorking) { // Test if all nuclear decays are working. NuclearDecay d; Candidate c; - InteractionState interaction; std::ifstream infile(getDataPath("nuclear_decay.txt").c_str()); while (infile.good()) { if (infile.peek() != '#') { int Z, N, channel, foo; - infile >> Z >> N >> interaction.channel >> foo; - + infile >> Z >> N >> channel >> foo; c.current.setId(nucleusId(Z + N, Z)); c.current.setEnergy(80 * EeV); - d.performInteraction(&c, interaction); + d.performInteraction(&c, channel); } infile.ignore(std::numeric_limits::max(), '\n'); } infile.close(); } -TEST(NuclearDecay, NoNucleus) { - // Test if non-nuclei are skipped +TEST(NuclearDecay, thisIsNotNucleonic) { + // Test if noting happens to an electron + NuclearDecay decay; Candidate c; c.setNextStep(std::numeric_limits::max()); c.current.setId(11); // electron c.current.setEnergy(10 * EeV); - - NuclearDecay d; - InteractionState state; - EXPECT_FALSE(d.randomInteraction(&c, state)); - EXPECT_EQ(0, state.channel); + decay.process(&c); + EXPECT_EQ(11, c.current.getId()); + EXPECT_EQ(10 * EeV, c.current.getEnergy()); } -TEST(PhotoDisintegration, Carbon) { +TEST(PhotoDisintegration, carbon) { // Test if a 100 EeV C-12 nucleus photo-disintegrates (at least once) over a distance of 50 Mpc. // This test can stochastically fail if no interaction occurs over 50 Mpc. PhotoDisintegration pd; @@ -317,7 +296,7 @@ TEST(PhotoDisintegration, Carbon) { // energy conserved } -TEST(PhotoDisintegration, Iron) { +TEST(PhotoDisintegration, iron) { // Test if a 100 EeV Fe-56 nucleus photo-disintegrates (at least once) over a distance of 50 Mpc. // This test can stochastically fail if no interaction occurs over 50 Mpc. PhotoDisintegration pd(IRB); @@ -352,20 +331,19 @@ TEST(PhotoDisintegration, Iron) { // energy conserved } -TEST(PhotoDisintegration, NoNucleus) { - // Test if non-nuclei are skipped +TEST(PhotoDisintegration, thisIsNotNucleonic) { + // Test if noting happens to an electron + PhotoDisintegration pd; Candidate c; - c.setNextStep(std::numeric_limits::max()); + c.setCurrentStep(1 * Mpc); c.current.setId(11); // electron c.current.setEnergy(10 * EeV); - - PhotoDisintegration module; - InteractionState state; - EXPECT_FALSE(module.randomInteraction(&c, state)); - EXPECT_EQ(0, state.channel); + pd.process(&c); + EXPECT_EQ(11, c.current.getId()); + EXPECT_EQ(10 * EeV, c.current.getEnergy()); } -TEST(PhotoDisintegration, LimitNextStep) { +TEST(PhotoDisintegration, limitNextStep) { // Test if the interaction limits the next propagation step. PhotoDisintegration pd; Candidate c; @@ -380,19 +358,15 @@ TEST(PhotoDisintegration, AllWorkingCMB) { // Test if all photo-disintegrations are working. PhotoDisintegration pd(CMB); Candidate c; - InteractionState interaction; - std::ifstream infile( - getDataPath("photodis_CMB.txt").c_str()); + std::ifstream infile(getDataPath("photodis_CMB.txt").c_str()); std::string line; while (std::getline(infile, line)) { if (line[0] == '#') continue; std::stringstream lineStream(line); - int Z, N; - lineStream >> Z; - lineStream >> N; - lineStream >> interaction.channel; + int Z, N, channel; + lineStream >> Z >> N >> channel; double y; for (size_t i = 0; i < 200; i++) { @@ -403,7 +377,7 @@ TEST(PhotoDisintegration, AllWorkingCMB) { c.current.setId(nucleusId(Z + N, Z)); c.current.setEnergy(80 * EeV); - pd.performInteraction(&c, interaction); + pd.process(&c); } infile.close(); } @@ -412,19 +386,15 @@ TEST(PhotoDisintegration, AllWorkingIRB) { // Test if all photo-disintegrations are working. PhotoDisintegration pd(IRB); Candidate c; - InteractionState interaction; - std::ifstream infile( - getDataPath("photodis_IRB.txt").c_str()); + std::ifstream infile(getDataPath("photodis_IRB.txt").c_str()); std::string line; while (std::getline(infile, line)) { if (line[0] == '#') continue; std::stringstream lineStream(line); - int Z, N; - lineStream >> Z; - lineStream >> N; - lineStream >> interaction.channel; + int Z, N, channel; + lineStream >> Z >> N >> channel; double y; for (size_t i = 0; i < 200; i++) { @@ -435,19 +405,18 @@ TEST(PhotoDisintegration, AllWorkingIRB) { c.current.setId(nucleusId(Z + N, Z)); c.current.setEnergy(80 * EeV); - pd.performInteraction(&c, interaction); + pd.process(&c); } infile.close(); } -/** -TEST(PhotoPionProduction, Backgrounds) { +TEST(PhotoPionProduction, backgrounds) { // Test if interaction data files are loaded. PhotoPionProduction ppp1(CMB); PhotoPionProduction ppp2(IRB); } -TEST(PhotoPionProduction, Proton) { +TEST(PhotoPionProduction, proton) { // Test photo-pion interaction for 100 EeV proton. // This test can stochastically fail if no interaction occurs over 100 Mpc. PhotoPionProduction ppp; @@ -462,7 +431,7 @@ TEST(PhotoPionProduction, Proton) { EXPECT_EQ(0, c.secondaries.size()); // no (nucleonic) secondaries } -TEST(PhotoPionProduction, Helium) { +TEST(PhotoPionProduction, helium) { // Test photo-pion interaction for 400 EeV He nucleus. // This test can stochastically fail if no interaction occurs over 100 Mpc. PhotoPionProduction ppp; @@ -477,20 +446,20 @@ TEST(PhotoPionProduction, Helium) { EXPECT_TRUE(c.secondaries.size() > 0); } -TEST(PhotoPionProduction, NoNucleus) { - // Test if non-nuclei are skipped +TEST(PhotoPionProduction, thisIsNotNucleonic) { + // Test if noting happens to an electron + PhotoPionProduction ppp; Candidate c; + c.setCurrentStep(1 * Mpc); c.setNextStep(std::numeric_limits::max()); c.current.setId(11); // electron c.current.setEnergy(10 * EeV); - - PhotoPionProduction module; - InteractionState state; - EXPECT_FALSE(module.randomInteraction(&c, state)); - EXPECT_EQ(0, state.channel); + ppp.process(&c); + EXPECT_EQ(11, c.current.getId()); + EXPECT_EQ(10 * EeV, c.current.getEnergy()); } -TEST(PhotoPionProduction, LimitNextStep) { +TEST(PhotoPionProduction, limitNextStep) { // Test if the interaction limits the next propagation step. PhotoPionProduction ppp; Candidate c; @@ -501,10 +470,10 @@ TEST(PhotoPionProduction, LimitNextStep) { EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); } -TEST(SophiaPhotoPionProduction, withoutSecondaries) { +TEST(PhotoPionProduction, withoutSecondaries) { // Test photo-pion (SOPHIA) interaction for 100 EeV proton. // This test can stochastically fail if no interaction occurs over 100 Mpc. - SophiaPhotoPionProduction ppp; + PhotoPionProduction ppp; Candidate c; c.setCurrentStep(100 * Mpc); c.current.setId(nucleusId(1, 1)); @@ -513,72 +482,26 @@ TEST(SophiaPhotoPionProduction, withoutSecondaries) { // energy loss EXPECT_GT(100 * EeV, c.current.getEnergy()); - // nucleon number conserved int id = c.current.getId(); EXPECT_EQ(1, massNumber(id)); - // secondaries turned off EXPECT_EQ(0, c.secondaries.size()); } -TEST(SophiaPhotoPionProduction, withSecondaries) { +TEST(PhotoPionProduction, withSecondaries) { // Test photo-pion interaction for 100 EeV proton. // This test can stochastically fail if no interaction occurs over 100 Mpc. - SophiaPhotoPionProduction ppp(CMB, true, true, true); + PhotoPionProduction ppp(CMB, true, true, true); Candidate c; c.current.setId(nucleusId(1, 1)); c.current.setEnergy(100 * EeV); - InteractionState interaction; - ppp.performInteraction(&c, interaction); - - // there should be secondaries secondaries turned on + c.setCurrentStep(100 * Mpc); + ppp.process(&c); + // there should be secondaries EXPECT_GT(c.secondaries.size(), 1); } -TEST(SophiaPhotoPionProduction, belowSophiaEnergyThreshold_CMB) { - // The minimum nucleon energy for SOPHIA interactions is ~3.75 EeV against the CMB. - // This needs to be caught - SophiaPhotoPionProduction ppp(CMB); - - Candidate c; - c.current.setId(nucleusId(1, 1)); - c.current.setEnergy(2 * EeV); - InteractionState interaction(1 * Mpc, 1); - c.setInteractionState(ppp.getDescription(), interaction); - ppp.performInteraction(&c, interaction); - - // no interaction should have happened - EXPECT_DOUBLE_EQ(2, c.current.getEnergy() / EeV); - - // the scheduled photo-pion interaction better be deleted - InteractionState dummy; - bool hasInteraction = c.getInteractionState(ppp.getDescription(), dummy); - EXPECT_FALSE(hasInteraction); -} - -TEST(SophiaPhotoPionProduction, belowSophiaEnergyThreshold_IRB) { - // The minimum nucleon energy for SOPHIA interactions is ~0.01 EeV against the IRB. - // This needs to be caught. - SophiaPhotoPionProduction ppp(IRB); - - Candidate c; - c.current.setId(nucleusId(1, 1)); - c.current.setEnergy(0.005 * EeV); - InteractionState interaction(1 * Mpc, 1); - c.setInteractionState(ppp.getDescription(), interaction); - ppp.performInteraction(&c, interaction); - - // no interaction should have happened - EXPECT_DOUBLE_EQ(0.005, c.current.getEnergy() / EeV); - - // the scheduled photo-pion interaction better be deleted - InteractionState dummy; - bool hasInteraction = c.getInteractionState(ppp.getDescription(), dummy); - EXPECT_FALSE(hasInteraction); -} -**/ - TEST(Redshift, simpleTest) { // Test if redshift is decreased and adiabatic energy loss is applied. Redshift redshift; From 28e4c96a5e25c520e4ca6ecc0aea5d29c3496912 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 10 Oct 2013 11:53:47 +0200 Subject: [PATCH 0354/1298] readd energyLossLength method for photopion --- include/crpropa/module/PhotoPionProduction.h | 6 ++++ src/module/PhotoPionProduction.cpp | 29 ++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/include/crpropa/module/PhotoPionProduction.h b/include/crpropa/module/PhotoPionProduction.h index 4f17aea4a..928e49242 100644 --- a/include/crpropa/module/PhotoPionProduction.h +++ b/include/crpropa/module/PhotoPionProduction.h @@ -37,6 +37,12 @@ class PhotoPionProduction: public Module { void process(Candidate *candidate) const; void performInteraction(Candidate *candidate, int channel) const; double nucleiModification(int A, int X) const; + /** + Calculates the energy loss length 1/E dE/dx in [m]. This is not used in the simulation. + @param id PDG particle id + @param energy particle energy [J] + */ + double energyLossLength(int id, double energy); }; } // namespace crpropa diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 3eac5c51c..14b9f3156 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -236,4 +236,33 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, } } +double PhotoPionProduction::energyLossLength(int id, double E) { + int A = massNumber(id); + int Z = chargeNumber(id); + int N = A - Z; + + double Eeff = E / A; + if ((Eeff < energy.front()) or (Eeff > energy.back())) + return std::numeric_limits::max(); + + // protons / neutrons keep as energy the fraction of mass to delta-resonance mass + // nuclei approximately lose the energy that the interacting nucleon is carrying + double relativeEnergyLoss = (A == 1) ? 1 - 938. / 1232. : 1. / A; + + double lossRate = 0; + if (Z > 0) { + double rate = interpolate(Eeff, energy, pRate); + rate *= nucleiModification(A, Z); + lossRate += relativeEnergyLoss * rate; + } + + if (N > 0) { + double rate = interpolate(Eeff, energy, nRate); + rate *= nucleiModification(A, N); + lossRate += relativeEnergyLoss * rate; + } + + return 1. / lossRate; +} + } // namespace crpropa From 7fbc3e63a8523b6ed92f22a60ea6aa67b2b61474 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 14 Oct 2013 11:18:27 +0200 Subject: [PATCH 0355/1298] update formating script for photopion production --- data-tools/PhotoPionProduction/photopion.py | 39 +++++++++++++-------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/data-tools/PhotoPionProduction/photopion.py b/data-tools/PhotoPionProduction/photopion.py index 82ae5fd35..82f54e27f 100644 --- a/data-tools/PhotoPionProduction/photopion.py +++ b/data-tools/PhotoPionProduction/photopion.py @@ -1,46 +1,55 @@ from numpy import * # This script reformats the pion production rate data files from CRPropa2. -# Mean free pathes larger than the Hubble length are omitted -lHubble = 4300. # Mpc # # The data files used are found in CRPropa/src/Interactions/proton_sophia/ # Copy the content or execute the script from within this folder. -# # The used files are # 'pionprodrate_n' : pion production rates of neutrons against the CMB # 'pionprodrate_n_ir_y0' : pion production rates of neutrons against the IRB (Kneiske) # 'pionprodrate_p' : pion production rates of protons against the CMB # 'pionprodrate_p_ir_y0' : pion production rates of protons against the IRB (Kneiske) +# Interaction rates smaller than 1 / 1000 Gpc are not tabulated for the CMB. +# Even when accounting for cosmology these will not influence typical simulation results. +# For symmetry with the CMB rates, and for performance reasons the threshold is also applied to the IRB rates. +threshold = 1e-6 # pion production rate on the CMB -eCMB, nCMB = genfromtxt('pionprodrate_n.txt', comments='#', unpack=True) -pCMB = genfromtxt('pionprodrate_p.txt', usecols=(1), comments='#') +energies, nRate = genfromtxt('pionprodrate_n.txt', comments='#', unpack=True) +energies2, pRate = genfromtxt('pionprodrate_p.txt', comments='#', unpack=True) +if any(energies != energies2): + print 'Mismatch of tabulated energies' +# save to one file, skip 0 entries fout1 = open('photopion_CMB.txt', 'w') fout1.write('# Pion production rate for protons and neutrons on the CMB\n') fout1.write('# Energy [EeV], Rate [1/Mpc]\n') -for E, p, n in zip(eCMB, pCMB, nCMB): - if (p < 1/lHubble) and (n < 1/lHubble): - continue - fout1.write('%.5f %.5f %.5f\n'%( E, p, n )) +for E, p, n in zip(energies, pRate, nRate): + if (p < threshold) and (n < threshold): + print 'CMB: skip', E, 'EeV:', p, n + continue + fout1.write('%7g %.6f %.6f\n'%( E, p, n )) fout1.close() # pion production rate on the IRB (Kneiske 2002) -eIRB, nIRB = genfromtxt('pionprodrate_n_ir_y0.txt', comments='#', unpack=True) -pIRB = genfromtxt('pionprodrate_p_ir_y0.txt', usecols=(1), comments='#') +energies, nRate = genfromtxt('pionprodrate_n_ir_y0.txt', comments='#', unpack=True) +energies2, pRate = genfromtxt('pionprodrate_p_ir_y0.txt', comments='#', unpack=True) +if any(energies != energies2): + print 'Mismatch of tabulated energies' +# save to one file, skip 0 entries fout2 = open('photopion_IRB.txt', 'w') fout2.write('# Pion production rate for protons and neutrons on IRB\n') fout2.write('# Energy [EeV], Rate [1/Mpc]\n') -for E, p, n in zip(eIRB, pIRB, nIRB): - if (p < 1/lHubble) and (n < 1/lHubble): - continue - fout2.write('%.5f %.5f %.5f\n'%( E, p, n )) +for E, p, n in zip(energies, pRate, nRate): + if (p < threshold) and (n < threshold): + print 'IRB: skip', E, 'EeV:', p, n + continue + fout2.write('%8.6g %.6f %.6f\n'%( E, p, n )) fout2.close() From 9976e7cb3dd2a4994930470240fc9d9c94f37cb0 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 21 Oct 2013 14:58:17 +0200 Subject: [PATCH 0356/1298] photodis: reduce map size and add check for Z>26 and N>30 --- include/crpropa/module/PhotoDisintegration.h | 8 +--- src/module/PhotoDisintegration.cpp | 44 ++++++++++---------- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/include/crpropa/module/PhotoDisintegration.h b/include/crpropa/module/PhotoDisintegration.h index 5a4a84dc3..5d72ff881 100644 --- a/include/crpropa/module/PhotoDisintegration.h +++ b/include/crpropa/module/PhotoDisintegration.h @@ -29,13 +29,7 @@ class PhotoDisintegration: public Module { void init(std::string filename); void process(Candidate *candidate) const; void performInteraction(Candidate *candidate, int channel) const; - - /** - Calculates the energy loss length 1/E dE/dx in [m] - @param id PDG particle id - @param energy particle energy [J] - */ - double energyLossLength(int id, double energy); + double interactionRate(int id, double E, double z); }; } // namespace crpropa diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 983723e86..b524dc76c 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -41,7 +41,7 @@ void PhotoDisintegration::init(PhotonField photonField) { } void PhotoDisintegration::init(std::string filename) { - pdTable.resize(31 * 57); + pdTable.resize(27 * 31); // create spline x-axis std::ifstream infile(filename.c_str()); @@ -57,8 +57,8 @@ void PhotoDisintegration::init(std::string filename) { std::stringstream lineStream(line); int Z, N; - lineStream >> Z; // charge number - lineStream >> N; // mass number + lineStream >> Z; // proton number + lineStream >> N; // neutron number PDMode pd; lineStream >> pd.channel; // disintegration channel @@ -89,6 +89,8 @@ void PhotoDisintegration::process(Candidate *candidate) const { int N = A - Z; // check if disintegration data available + if ((Z > 26) or (N > 30)) + return; std::vector pdModes = pdTable[Z * 31 + N]; if (pdModes.size() == 0) return; @@ -174,38 +176,36 @@ void PhotoDisintegration::performInteraction(Candidate *candidate, candidate->addSecondary(nucleusId(4, 2), EpA * 4); } -double PhotoDisintegration::energyLossLength(int id, double E) { +double PhotoDisintegration::interactionRate(int id, double E, double z) { + // check if nucleus + if (not (isNucleus(id))) + return 0; + int A = massNumber(id); int Z = chargeNumber(id); int N = A - Z; + // check if disintegration data available + if ((Z > 26) or (N > 30)) + return 0; std::vector pdModes = pdTable[Z * 31 + N]; if (pdModes.size() == 0) - return std::numeric_limits::max(); + return 0; + // check if in tabulated energy range double lg = log10(E / (nucleusMass(id) * c_squared)); if ((lg <= 6) or (lg >= 14)) - return std::numeric_limits::max(); + return 0; - double lossRate = 0; + // total rate from all disintegration channels + double rate = 0; for (size_t i = 0; i < pdModes.size(); i++) { - double rate = interpolateEquidistant(lg, 6, 14, pdModes[i].rate); - - int channel = pdModes[i].channel; - int nN = digit(channel, 100000); - int nP = digit(channel, 10000); - int nH2 = digit(channel, 1000); - int nH3 = digit(channel, 100); - int nHe3 = digit(channel, 10); - int nHe4 = digit(channel, 1); - - double relativeEnergyLoss = double( - nN + nP + 2 * nH2 + 3 * nH3 + 3 * nHe3 + 4 * nHe4) / double(A); - - lossRate += rate * relativeEnergyLoss; + rate += interpolateEquidistant(lg, 6, 14, pdModes[i].rate); } - return 1 / lossRate; + // comological scaling of interaction distance (in physical units) + rate *= pow(1 + z, 3) * photonFieldScaling(photonField, z); + return rate; } } // namespace crpropa From 1c78cf0963fc47a2447e247bf42f2a5a93e747d0 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 25 Oct 2013 10:49:10 +0200 Subject: [PATCH 0357/1298] PhotoDisintegration: fix tabulated energies --- .../PhotoDisintegration/photodis_reformat.py | 7 +++-- include/crpropa/module/PhotoDisintegration.h | 4 ++- src/module/PhotoDisintegration.cpp | 28 ++++++++++--------- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/data-tools/PhotoDisintegration/photodis_reformat.py b/data-tools/PhotoDisintegration/photodis_reformat.py index 4fb2cc61f..0a4470ce9 100644 --- a/data-tools/PhotoDisintegration/photodis_reformat.py +++ b/data-tools/PhotoDisintegration/photodis_reformat.py @@ -26,7 +26,7 @@ def getDigit(number, d): return number % (10**d) // (10**(d-1)) -def isBogus(Z, A, channel, j): +def isBogus(Z, A, channel): # checks if the disintegration channel is impossible or leaves an empty nucleus nN = getDigit(channel, 6) nP = getDigit(channel, 5) @@ -79,11 +79,12 @@ def reformat(photonField): for j in range(j0, j1): channel = int(data2[j, 0]) - if isBogus(Z,A,channel,j): + if isBogus(Z,A,channel): + print ' .. in line', j continue fout.write('\n') - fout.write(str(Z)+'\t'+str(N)+'\t') # write the particle's Z, A + fout.write(str(Z)+'\t'+str(N)+'\t') # write the particle's Z, N fout.write(str(channel)) # write disintegration channel k0 = int(data2[j, 1]) # start index in 'PDExclTabMnFrPthCross.cmt' diff --git a/include/crpropa/module/PhotoDisintegration.h b/include/crpropa/module/PhotoDisintegration.h index 5d72ff881..5035dc228 100644 --- a/include/crpropa/module/PhotoDisintegration.h +++ b/include/crpropa/module/PhotoDisintegration.h @@ -15,12 +15,14 @@ namespace crpropa { class PhotoDisintegration: public Module { private: PhotonField photonField; - double limit; + double limit; // fraction of mean free path for limiting the next step struct PDMode { int channel; // number of emitted (n, p, H2, H3, He3, He4) std::vector rate; // disintegration rate [1/m] }; std::vector > pdTable; // pdTable[Z * 31 + N] = vector + double lgmin; // minimum log10(Lorentz-factor) + double lgmax; // maximum log10(Lorentz-factor) public: PhotoDisintegration(PhotonField photonField = CMB, double limit = 0.1); diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index b524dc76c..b8ce45926 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -41,11 +41,12 @@ void PhotoDisintegration::init(PhotonField photonField) { } void PhotoDisintegration::init(std::string filename) { + lgmin = 6; + lgmax = 13.96; pdTable.resize(27 * 31); - // create spline x-axis std::ifstream infile(filename.c_str()); - if (!infile.good()) + if (not infile.good()) throw std::runtime_error( "crpropa::PhotoDisintegration: could not open file " + filename); @@ -57,16 +58,16 @@ void PhotoDisintegration::init(std::string filename) { std::stringstream lineStream(line); int Z, N; - lineStream >> Z; // proton number - lineStream >> N; // neutron number + lineStream >> Z; + lineStream >> N; PDMode pd; - lineStream >> pd.channel; // disintegration channel + lineStream >> pd.channel; double r = 0; for (size_t i = 0; i < 200; i++) { lineStream >> r; - pd.rate.push_back(r / Mpc); // disintegration rate in [1/m] + pd.rate.push_back(r / Mpc); } pdTable[Z * 31 + N].push_back(pd); @@ -76,7 +77,7 @@ void PhotoDisintegration::init(std::string filename) { } void PhotoDisintegration::process(Candidate *candidate) const { - // the loop should be processed at least once for limiting the next step + // the loop will be executed at least once for limiting the next step double step = candidate->getCurrentStep(); do { // check if nucleus @@ -98,7 +99,7 @@ void PhotoDisintegration::process(Candidate *candidate) const { // check if in tabulated energy range double z = candidate->getRedshift(); double lg = log10(candidate->current.getLorentzFactor() * (1 + z)); - if ((lg <= 6) or (lg >= 14)) + if ((lg <= lgmin) or (lg >= lgmax)) return; // find disintegration channel with minimum random decay distance @@ -107,11 +108,12 @@ void PhotoDisintegration::process(Candidate *candidate) const { int channel; double totalRate = 0; - // comological scaling of interaction distance (comoving) + // comological scaling of interaction distance (comoving units) double scaling = pow(1 + z, 2) * photonFieldScaling(photonField, z); for (size_t i = 0; i < pdModes.size(); i++) { - double rate = interpolateEquidistant(lg, 6, 14, pdModes[i].rate); + double rate = interpolateEquidistant(lg, lgmin, lgmax, + pdModes[i].rate); rate *= scaling; totalRate += rate; double d = -log(random.rand()) / rate; @@ -193,14 +195,14 @@ double PhotoDisintegration::interactionRate(int id, double E, double z) { return 0; // check if in tabulated energy range - double lg = log10(E / (nucleusMass(id) * c_squared)); - if ((lg <= 6) or (lg >= 14)) + double lg = log10(E / (nucleusMass(id) * c_squared)) * (1 + z); + if ((lg <= lgmin) or (lg >= lgmax)) return 0; // total rate from all disintegration channels double rate = 0; for (size_t i = 0; i < pdModes.size(); i++) { - rate += interpolateEquidistant(lg, 6, 14, pdModes[i].rate); + rate += interpolateEquidistant(lg, lgmin, lgmax, pdModes[i].rate); } // comological scaling of interaction distance (in physical units) From c9a6b3bbd974d8dcb86e591f3972866e8df1ed58 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 28 Oct 2013 18:00:56 +0100 Subject: [PATCH 0358/1298] initial git commit purged mercurial repository for data/* and converted to git added markdown README and .gitignore --- .gitignore | 8 +++++++ .hgignore | 12 ---------- README | 69 ------------------------------------------------------ README.md | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 81 deletions(-) create mode 100644 .gitignore delete mode 100644 .hgignore delete mode 100644 README create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..272c438a4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.* + +doc/* +build/* +data/* +data-tools/* + +*.png \ No newline at end of file diff --git a/.hgignore b/.hgignore deleted file mode 100644 index d9fa5e0dc..000000000 --- a/.hgignore +++ /dev/null @@ -1,12 +0,0 @@ -syntax:glob - -syntax: regexp -^doc$ -^build$ -^.settings$ -.png$ -^\.cproject$ -^\.project$ -^data/.*$ -^data-tools/.*$ - diff --git a/README b/README deleted file mode 100644 index 421c0f2a4..000000000 --- a/README +++ /dev/null @@ -1,69 +0,0 @@ -Install from source ------------------------- -CRPropa is configured using CMAKE - for more information see www.cmake.org -1) Download the data archive from https://forge.physik.rwth-aachen.de/projects/mpc/files extract to crpropa/data -2) >> cd build -3) >> cmake .. - or >> ccmake .. -4) >> make -5) >> make test [to run all unit tests when gtest is available] -7) >> make install - -The install path can be set with -DCMAKE_INSTALL_PREFIX=/my/path or with the option browser when using ccmake. -Notes for Intel Compiler: - use -DCMAKE_SHARED_LINKER_FLAGS="-lifcore" -DCMAKE_Fortran_COMPILER=ifort - - -Install with Python bindings ----------------------------- -To use CRPropa via python the CMAKE flag ENABLE_PYTHON needs to be set to True. -Additionally the path to crpropa.py needs to be added to PYTHONPATH - - -Dependencies ------------- -Required: -C++ Compiler -Fortran Compiler - -> to compile SOPHIA - -Provided: -SOPHIA - -> for photo-hadronic interactions -googletest - -> for unit-tests - -Optional: -Python and SWIG - -> to use CRPropa from Python - tested for > Python 2.7 - tested for > SWIG 2.0 -FFTW3F - -> for turbulent magnetic field grids - CRPropa needs the FFTW3 library compiled with the single precision option -Gadget - -> Magnetic fields for large scale structure data -OpenMP - -> for shared memory parallelization -googleperftools - -> for performance optimizations regarding shared memory parallelization - - -XML Steering ------------- -CRPropa can be steered via XML cards ($cropra-xmlrun some_steeringcard.xml) -The steeringcard layout is conform to the one CRPropa2. -However, CRPropa 2 does not fully enforce the XML-1.0 standard (http://www.w3.org/XML). -To comply with the standard a few modifications to exisisting steering cards might have to be made. -Modification are - 1) XML-cards can have only one root node. The root node is - - .... - - 2) All nodes including the optional header node need to be closed, e.g. - - ... or - - 3) Values need to be embraced by quotes, e.g. - or - diff --git a/README.md b/README.md new file mode 100644 index 000000000..b4ea025c4 --- /dev/null +++ b/README.md @@ -0,0 +1,69 @@ +CRPropa3 +======== + +Development version of CRPropa. Use on your own risk. + +Install from source +------------------------ +1. Download the data archive from https://forge.physik.rwth-aachen.de/projects/mpc/files extract to crpropa/data +1. CRPropa uses CMAKE to configure. From the build directory call ccmake or cmake + + cd build + ccmake .. + +2. Afterward configuring run make and make install as usual + + make + make install + +The install path can be set with -DCMAKE_INSTALL_PREFIX=/my/path or with the option browser when using ccmake. + +Notes for Intel Compiler: +use -DCMAKE_SHARED_LINKER_FLAGS="-lifcore" -DCMAKE_Fortran_COMPILER=ifort + +Provided Dependencies +--------------------- ++ SOPHIA + + for photo-hadronic interactions ++ googletest + + for unit-tests + +Optional Dependencies +--------------------- ++ Python and SWIG + + to use CRPropa from Python + + tested for > Python 2.7 + + tested for > SWIG 2.0 ++ FFTW3F + + for turbulent magnetic field grids + + CRPropa needs the FFTW3 library compiled with the single precision option ++ Gadget + + Magnetic fields for large scale structure data ++ OpenMP + + for shared memory parallelization ++ googleperftools + + for performance optimizations regarding shared memory parallelization + + +XML Steering +------------ +For backwards compatibility CRPropa 3 can be steered via XML cards ($cropra-xmlrun some_steeringcard.xml) +However, CRPropa 2 does not fully enforce the XML-1.0 standard (http://www.w3.org/XML). +To comply with the standard a few modifications to exisisting steering cards might have to be made. +Modification are + +1. XML-cards can have only one root node. The root node is + + + ... + + +2. All nodes including the optional header node need to be closed, e.g. + + + ... or + + +3. Values need to be embraced by quotes, e.g. + + \ No newline at end of file From a1d244d33544f955c83202de7606e3288c5b6eb8 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 28 Oct 2013 19:53:06 +0100 Subject: [PATCH 0359/1298] SourceMultiplePositions: speed improvement and test --- src/Source.cpp | 10 ++++++---- test/testSource.cpp | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/Source.cpp b/src/Source.cpp index 2e9c196c2..bb72fdbae 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -161,10 +161,12 @@ void SourceMultiplePositions::add(Vector3d pos, double lumi) { void SourceMultiplePositions::prepare(ParticleState& particle) const { if (positions.size() == 0) throw std::runtime_error("SourceMultiplePositions: no position set"); - double r = Random().rand() * luminosities.back(); - int i = 0; - while ((r > luminosities[i]) and (i < luminosities.size())) - i++; + + Random &random = Random::instance(); + double r = random.rand(); + std::vector::const_iterator it = std::upper_bound( + luminosities.begin(), luminosities.end(), r * luminosities.back()); + size_t i = it - luminosities.begin(); particle.setPosition(positions[i]); } diff --git a/test/testSource.cpp b/test/testSource.cpp index 9f653b4ab..849c5f133 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -13,6 +13,26 @@ TEST(SourcePosition, simpleTest) { EXPECT_EQ(position, ps.getPosition()); } +TEST(SourceMultiplePositions, simpleTest) { + SourceMultiplePositions source; + source.add(Vector3d(1, 0, 0), 0.25); + source.add(Vector3d(2, 0, 0), 0.75); + ParticleState ps; + int n1 = 0; + int n2 = 0; + for (int i = 0; i < 10000; i++) { + source.prepare(ps); + if (ps.getPosition().x == 1) + n1++; + else if (ps.getPosition().x == 2) + n2++; + } + std::cout << n1 << std::endl; + std::cout << n2 << std::endl; + EXPECT_NEAR(n1, 2500, 2 * sqrt(2500)); + EXPECT_NEAR(n2, 7500, 2 * sqrt(7500)); +} + TEST(SourceUniformSphere, simpleTest) { Vector3d center(0, 0, 0); double radius = 110; From 24a29ba866d528c35c6b19c86153a83b476aa21c Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 31 Oct 2013 11:02:16 +0100 Subject: [PATCH 0360/1298] add randBin method --- include/crpropa/Random.h | 3 +++ src/Random.cpp | 21 +++++++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/include/crpropa/Random.h b/include/crpropa/Random.h index 5a2de0c41..da125c075 100644 --- a/include/crpropa/Random.h +++ b/include/crpropa/Random.h @@ -132,6 +132,9 @@ class Random { /// Fisher distributed random number double randFisher(double k); + /// Draw a random bin from a (unnormalized) cumulative distribution function + size_t randBin(const std::vector& cdf); + /// Random point on a unit-sphere Vector3d randVector(); /// Random vector with given angular separation around mean direction diff --git a/src/Random.cpp b/src/Random.cpp index 8e8602ae5..1ce5a7592 100644 --- a/src/Random.cpp +++ b/src/Random.cpp @@ -122,6 +122,12 @@ double Random::randFisher(double kappa) { return acos(1. + 1. / kappa * log(1 - rand() * (1 - exp(-2 * kappa)))); } +size_t randBin(const std::vector& cdf) { + std::vector::const_iterator it = std::lower_bound(cdf.begin(), + cdf.end(), rand() * cdf.back()); + return it - cdf.begin(); +} + Vector3d Random::randVector() { double z = randUniform(-1.0, 1.0); double t = randUniform(-1.0 * M_PI, M_PI); @@ -129,7 +135,8 @@ Vector3d Random::randVector() { return Vector3d(r * cos(t), r * sin(t), z); } -Vector3d Random::randVectorAroundMean(const Vector3d &meanDirection, double angle) { +Vector3d Random::randVectorAroundMean(const Vector3d &meanDirection, + double angle) { Vector3d rotAxis = meanDirection.cross(randVector()); rotAxis.normalize(); Vector3d v = meanDirection; @@ -141,7 +148,8 @@ Vector3d Random::randFisherVector(const Vector3d &meanDirection, double kappa) { return randVectorAroundMean(meanDirection, randFisher(kappa)); } -Vector3d Random::randConeVector(const Vector3d &meanDirection, double angularRadius) { +Vector3d Random::randConeVector(const Vector3d &meanDirection, + double angularRadius) { double theta = 2 * M_PI; while (theta > angularRadius) theta = acos(2 * rand() - 1); @@ -296,7 +304,8 @@ void Random::seed() { } // Was not successful, so use time() and clock() instead - seed (hash(time (NULL), clock()));} + seed(hash(time(NULL), clock())); +} void Random::initialize(const uint32 seed) { register uint32 *s = state; @@ -389,9 +398,9 @@ struct RANDOM_TLS_ITEM { }; #ifdef _MSC_VER - __declspec(align(64)) static RANDOM_TLS_ITEM _tls[MAX_THREAD]; +__declspec(align(64)) static RANDOM_TLS_ITEM _tls[MAX_THREAD]; #else - __attribute__ ((aligned(64))) static RANDOM_TLS_ITEM _tls[MAX_THREAD]; +__attribute__ ((aligned(64))) static RANDOM_TLS_ITEM _tls[MAX_THREAD]; #endif Random &Random::instance() { @@ -403,7 +412,7 @@ Random &Random::instance() { void Random::seedThreads(const uint32 oneSeed) { for(size_t i = 0; i < MAX_THREAD; ++i) - _tls[i].r.seed(oneSeed + i); + _tls[i].r.seed(oneSeed + i); } #else static Random _random; From 735821905b01e6569c903bd257ceccdfb0fa96ef Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 31 Oct 2013 11:49:20 +0100 Subject: [PATCH 0361/1298] use of randBin to simplify several SourceProperties --- include/crpropa/Source.h | 67 ++++++---------------- src/Source.cpp | 121 +++++++++++++++------------------------ 2 files changed, 64 insertions(+), 124 deletions(-) diff --git a/include/crpropa/Source.h b/include/crpropa/Source.h index b817cc07f..65c0475cc 100644 --- a/include/crpropa/Source.h +++ b/include/crpropa/Source.h @@ -24,7 +24,8 @@ class SourceProperty: public Referenced { @brief General cosmic ray source This class is a container for source properties. - The source prepares a new candidate by passing it to all its source properties to be modified accordingly. + The source prepares a new candidate by passing it to all its source properties + to be modified accordingly. */ class Source: public Referenced { std::vector > properties; @@ -37,13 +38,14 @@ class Source: public Referenced { @class SourceList @brief List of cosmic ray sources of individual total lumosities. - The SourceList is a source itself. It can be used if several UHECR sources are needed in one simulation. + The SourceList is a source itself. It can be used if several sources are + needed in one simulation. */ class SourceList: public Source { std::vector > sources; - std::vector luminosities; + std::vector cdf; public: - void addSource(Source* source, double luminosity = 1); + void addSource(Source* source, double weight = 1); ref_ptr getCandidate() const; }; @@ -60,13 +62,13 @@ class SourceParticleType: public SourceProperty { /** @class SourceMultipleParticleTypes - @brief Multiple particle types with individual (relative) total abundances + @brief Multiple particle types with individual relative abundances */ class SourceMultipleParticleTypes: public SourceProperty { - std::vector ids; /**< particle ids */ - std::vector abundances; /**< (relative) total abundances */ + std::vector particleTypes; + std::vector cdf; public: - void add(int id, double abundance = 1); + void add(int id, double weight = 1); void prepare(ParticleState &particle) const; }; @@ -90,49 +92,26 @@ class SourcePowerLawSpectrum: public SourceProperty { double Emax; double index; public: - /** Constructor - @param Emin minimum energy - @param Emax maximum energy - @param index differential spectral index - */ - SourcePowerLawSpectrum(double Emin, double Emax, double differentialIndex); - /** Set particle with a random energy from a power law distribution */ + SourcePowerLawSpectrum(double Emin, double Emax, double index); void prepare(ParticleState &particle) const; }; /** @class SourceComposition - @brief Nuclei with given abundances and a uniform power law spectrum between Emin and Z * Rmax + @brief Multiple nuclei with power law spectrum between Emin and Z * Rmax + + See Allard et al. 2006, DOI 10.1088/1475-7516/2006/09/005 */ class SourceComposition: public SourceProperty { double Emin; double Rmax; double index; - std::vector isotope; /**< isotope id */ - std::vector abundance; /**< relative abundance of source isotopes at equal energies */ - std::vector probability; /**< cumulative probability of source isotopes */ - void normalize(); - double getSpectrumIntegral(int Z) const; - + std::vector nuclei; + std::vector cdf; public: - /** Constructor - @param Emin minimum energy for cosmic rays - @param Rmax maximum rigidity for cosmic rays - @param index differential spectral index - */ SourceComposition(double Emin, double Rmax, double index); - /** Add a species to the composition - @param id particle id - @param abundance absolute or relative abundance at a fixed value of energy/nucleons - */ void add(int id, double abundance); - /** Add a species to the composition - @param A mass number - @param Z charge number - @param abundance absolute or relative abundance at a fixed value of energy/nucleons - */ void add(int A, int Z, double abundance); - /** Randomly select a species and energy */ void prepare(ParticleState &particle) const; }; @@ -153,9 +132,9 @@ class SourcePosition: public SourceProperty { */ class SourceMultiplePositions: public SourceProperty { std::vector positions; - std::vector luminosities; + std::vector cdf; public: - void add(Vector3d position, double luminosity = 1); + void add(Vector3d position, double weight = 1); void prepare(ParticleState &particle) const; }; @@ -225,14 +204,9 @@ class SourceUniform1D: public SourceProperty { /** @class SourceDensityGrid @brief Random source positions from a density grid - - This source property takes a density grid to compute random initial positions. - To dial a source position, first a bin is drawn following the density distribution. - Then a random position is drawn from a uniform distribution in the bin. */ class SourceDensityGrid: public SourceProperty { ref_ptr grid; - float sumDensity; public: SourceDensityGrid(ref_ptr densityGrid); void prepare(ParticleState &particle) const; @@ -241,14 +215,9 @@ class SourceDensityGrid: public SourceProperty { /** @class SourceDensityGrid1D @brief Random source positions from a 1D density grid - - This source property takes a N*1*1 grid to compute random initial positions. - To dial a source position, first a bin is drawn following the density distribution. - Then a random position is drawn from a uniform distribution in the bin. */ class SourceDensityGrid1D: public SourceProperty { ref_ptr grid; - float sumDensity; public: SourceDensityGrid1D(ref_ptr densityGrid); void prepare(ParticleState &particle) const; diff --git a/src/Source.cpp b/src/Source.cpp index bb72fdbae..c37b71faf 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -30,20 +30,17 @@ ref_ptr Source::getCandidate() const { return candidate; } -void SourceList::addSource(Source* source, double lumi) { +void SourceList::addSource(Source* source, double weight) { sources.push_back(source); - if (luminosities.size() > 0) - lumi += luminosities.back(); - luminosities.push_back(lumi); + if (cdf.size() > 0) + weight += cdf.back(); + cdf.push_back(weight); } ref_ptr SourceList::getCandidate() const { if (sources.size() == 0) throw std::runtime_error("SourceList: no sources set"); - double r = Random::instance().rand() * luminosities.back(); - int i = 0; - while ((r > luminosities[i]) and (i < luminosities.size())) - i++; + size_t i = Random::instance().randBin(cdf); return (sources[i])->getCandidate(); } @@ -75,72 +72,59 @@ void SourcePowerLawSpectrum::prepare(ParticleState& particle) const { } void SourceMultipleParticleTypes::add(int id, double a) { - ids.push_back(id); - if (abundances.size() > 0) - a += abundances.back(); - abundances.push_back(a); + particleTypes.push_back(id); + if (cdf.size() > 0) + a += cdf.back(); + cdf.push_back(a); } void SourceMultipleParticleTypes::prepare(ParticleState& particle) const { - if (ids.size() == 0) - throw std::runtime_error("SourceNuclei: no nuclei set"); - Random &random = Random::instance(); - double r = random.rand() * abundances.back(); - int i = 0; - while ((r > abundances[i]) and (i < abundances.size())) - i++; - particle.setId(ids[i]); + if (particleTypes.size() == 0) + throw std::runtime_error("SourceMultipleParticleTypes: no nuclei set"); + size_t i = Random::instance().randBin(cdf); + particle.setId(particleTypes[i]); } SourceComposition::SourceComposition(double Emin, double Rmax, double index) : Emin(Emin), Rmax(Rmax), index(index) { } -double SourceComposition::getSpectrumIntegral(int Z) const { +void SourceComposition::add(int id, double weight) { + nuclei.push_back(id); + int A = massNumber(id); + int Z = chargeNumber(id); + double a = 1 + index; - double Emax = Z * Rmax; if (std::abs(a) < std::numeric_limits::min()) - return log(Emax / Emin); + weight *= log(Z * Rmax / Emin); else - return (pow(Emax, a) - pow(Emin, a)) / a; -} + weight *= (pow(Z * Rmax, a) - pow(Emin, a)) / a; -void SourceComposition::add(int id, double a) { - isotope.push_back(id); - int A = massNumber(id); - double weightedAbundance = a * pow(A, -index - 1); - abundance.push_back(weightedAbundance); - probability.push_back(0); - normalize(); + weight *= pow(A, -a); + + if (cdf.size() > 0) + weight += cdf.back(); + cdf.push_back(weight); } void SourceComposition::add(int A, int Z, double a) { add(nucleusId(A, Z), a); } -void SourceComposition::normalize() { - double pSum = 0; - for (int i = 0; i < isotope.size(); i++) { - int Z = HepPID::Z(isotope[i]); - pSum += abundance[i] * getSpectrumIntegral(Z); - probability[i] = pSum; - } - for (int i = 0; i < probability.size(); i++) { - probability[i] /= pSum; - } -} - void SourceComposition::prepare(ParticleState& particle) const { - if (isotope.size() == 0) - throw std::runtime_error("PowerLawComposition: No source isotope set"); + if (nuclei.size() == 0) + throw std::runtime_error("SourceComposition: No source isotope set"); + Random &random = Random::instance(); - double r = random.rand(); - int i = 0; - while ((r > probability[i]) and (i < probability.size())) - i++; - int id = isotope[i]; + + // draw random particle type + size_t i = random.randBin(cdf); + int id = nuclei[i]; particle.setId(id); - particle.setEnergy(random.randPowerLaw(index, Emin, HepPID::Z(id) * Rmax)); + + // random energy from power law + int Z = chargeNumber(id); + particle.setEnergy(random.randPowerLaw(index, Emin, Z * Rmax)); } SourcePosition::SourcePosition(Vector3d position) : @@ -151,22 +135,17 @@ void SourcePosition::prepare(ParticleState& particle) const { particle.setPosition(position); } -void SourceMultiplePositions::add(Vector3d pos, double lumi) { +void SourceMultiplePositions::add(Vector3d pos, double weight) { positions.push_back(pos); - if (luminosities.size() > 0) - lumi += luminosities.back(); - luminosities.push_back(lumi); + if (cdf.size() > 0) + weight += cdf.back(); + cdf.push_back(weight); } void SourceMultiplePositions::prepare(ParticleState& particle) const { if (positions.size() == 0) throw std::runtime_error("SourceMultiplePositions: no position set"); - - Random &random = Random::instance(); - double r = random.rand(); - std::vector::const_iterator it = std::upper_bound( - luminosities.begin(), luminosities.end(), r * luminosities.back()); - size_t i = it - luminosities.begin(); + size_t i = Random::instance().randBin(cdf); particle.setPosition(positions[i]); } @@ -229,17 +208,13 @@ SourceDensityGrid::SourceDensityGrid(ref_ptr grid) : } } } - sumDensity = sum; } void SourceDensityGrid::prepare(ParticleState& particle) const { Random &random = Random::instance(); - // pick random bin; find bin using STL method - double r = random.rand(sumDensity); - std::vector &v = grid->getGrid(); - std::vector::iterator it = lower_bound(v.begin(), v.end(), r); - int i = it - v.begin(); + // draw random bin + size_t i = random.randBin(grid->getGrid()); Vector3d pos = grid->positionFromIndex(i); // draw uniform position within bin @@ -263,22 +238,18 @@ SourceDensityGrid1D::SourceDensityGrid1D(ref_ptr grid) : sum += grid->get(ix, 0, 0); grid->get(ix, 0, 0) = sum; } - sumDensity = sum; } void SourceDensityGrid1D::prepare(ParticleState& particle) const { Random &random = Random::instance(); - // pick random bin; find bin using STL method - double r = random.rand(sumDensity); - std::vector &v = grid->getGrid(); - std::vector::iterator it = lower_bound(v.begin(), v.end(), r); - int i = it - v.begin(); + // draw random bin + size_t i = random.randBin(grid->getGrid()); Vector3d pos = grid->positionFromIndex(i); // draw uniform position within bin double dx = random.rand() - 0.5; - pos += Vector3d(dx, 0, 0) * grid->getSpacing(); + pos.x += dx * grid->getSpacing(); particle.setPosition(pos); } From 28d3ced9ef76b5d7d383627eb3c74f7831b72feb Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 1 Nov 2013 17:45:47 +0100 Subject: [PATCH 0362/1298] add missing include and fix randBin --- include/crpropa/Random.h | 9 ++++++--- include/crpropa/Source.h | 3 +-- include/crpropa/XmlExecute.h | 2 -- src/Random.cpp | 10 ++++++++-- src/Source.cpp | 1 - test/testSource.cpp | 12 +++++------- 6 files changed, 20 insertions(+), 17 deletions(-) diff --git a/include/crpropa/Random.h b/include/crpropa/Random.h index da125c075..2dc6636f5 100644 --- a/include/crpropa/Random.h +++ b/include/crpropa/Random.h @@ -37,7 +37,7 @@ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -55,7 +55,7 @@ // when you write. // Parts of this file are modified beginning in 29.10.09 for adaption in PXL. -// Parts of this file are modified beginning in 10.02.12 for adaption in MPC. +// Parts of this file are modified beginning in 10.02.12 for adaption in CRPropa. #ifndef RANDOM_H #define RANDOM_H @@ -63,12 +63,14 @@ // Not thread safe (unless auto-initialization is avoided and each thread has // its own Random object) #include "crpropa/Vector3.h" + #include #include #include #include #include #include +#include //necessary for win32 #ifndef M_PI @@ -133,7 +135,8 @@ class Random { double randFisher(double k); /// Draw a random bin from a (unnormalized) cumulative distribution function - size_t randBin(const std::vector& cdf); + size_t randBin(const std::vector &cdf); + size_t randBin(const std::vector &cdf); /// Random point on a unit-sphere Vector3d randVector(); diff --git a/include/crpropa/Source.h b/include/crpropa/Source.h index 65c0475cc..df8346041 100644 --- a/include/crpropa/Source.h +++ b/include/crpropa/Source.h @@ -1,7 +1,6 @@ #ifndef CRPROPA_SOURCE_H #define CRPROPA_SOURCE_H -#include "crpropa/Referenced.h" #include "crpropa/Candidate.h" #include "crpropa/Grid.h" @@ -36,7 +35,7 @@ class Source: public Referenced { /** @class SourceList - @brief List of cosmic ray sources of individual total lumosities. + @brief List of cosmic ray sources of individual lumosities. The SourceList is a source itself. It can be used if several sources are needed in one simulation. diff --git a/include/crpropa/XmlExecute.h b/include/crpropa/XmlExecute.h index 1832e4bfc..50c403ba5 100644 --- a/include/crpropa/XmlExecute.h +++ b/include/crpropa/XmlExecute.h @@ -5,8 +5,6 @@ #include "crpropa/Source.h" #include "crpropa/magneticField/MagneticField.h" -#include - namespace pugi { class xml_node; } diff --git a/src/Random.cpp b/src/Random.cpp index 1ce5a7592..fc30628ca 100644 --- a/src/Random.cpp +++ b/src/Random.cpp @@ -55,7 +55,7 @@ // when you write. // Parts of this file are modified beginning in 29.10.09 for adaption in PXL. -// Parts of this file are modified beginning in 10.02.12 for adaption in CRPROPA. +// Parts of this file are modified beginning in 10.02.12 for adaption in CRPropa. #include "crpropa/Random.h" @@ -122,7 +122,13 @@ double Random::randFisher(double kappa) { return acos(1. + 1. / kappa * log(1 - rand() * (1 - exp(-2 * kappa)))); } -size_t randBin(const std::vector& cdf) { +size_t Random::randBin(const std::vector &cdf) { + std::vector::const_iterator it = std::lower_bound(cdf.begin(), + cdf.end(), rand() * cdf.back()); + return it - cdf.begin(); +} + +size_t Random::randBin(const std::vector &cdf) { std::vector::const_iterator it = std::lower_bound(cdf.begin(), cdf.end(), rand() * cdf.back()); return it - cdf.begin(); diff --git a/src/Source.cpp b/src/Source.cpp index c37b71faf..14ef0b78f 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -4,7 +4,6 @@ #include "HepPID/ParticleIDMethods.hh" #include -#include namespace crpropa { diff --git a/test/testSource.cpp b/test/testSource.cpp index 849c5f133..248a8874a 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -185,17 +185,16 @@ TEST(SourcePowerLawSpectrum, simpleTest) { } TEST(SourceComposition, simpleTest) { - Vector3d position(1, 2, 3); double Emin = 10; - double Emax = 100; - double index = -2; - SourceComposition source(Emin, Emax, index); + double Rmax = 100; + double index = -1; + SourceComposition source(Emin, Rmax, index); source.add(nucleusId(6, 3), 1); ParticleState p; source.prepare(p); EXPECT_EQ(nucleusId(6, 3), p.getId()); EXPECT_LE(Emin, p.getEnergy()); - EXPECT_GE(Emax, p.getEnergy()); + EXPECT_GE(6 * Rmax, p.getEnergy()); } TEST(SourceComposition, throwNoIsotope) { @@ -270,8 +269,7 @@ TEST(SourceList, luminosity) { meanE += c->created.getEnergy(); } meanE /= 1000; - EXPECT_NEAR(80, meanE, 2); - // this test can stochastically fail + EXPECT_NEAR(80, meanE, 4); // this test can stochastically fail } int main(int argc, char **argv) { From defa0cef25ce04be7a5ec82eda333ff9b80e7516 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 1 Nov 2013 18:12:06 +0100 Subject: [PATCH 0363/1298] update README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b4ea025c4..c2fba7068 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,13 @@ Development version of CRPropa. Use on your own risk. Install from source ------------------------ -1. Download the data archive from https://forge.physik.rwth-aachen.de/projects/mpc/files extract to crpropa/data -1. CRPropa uses CMAKE to configure. From the build directory call ccmake or cmake +1. Download the latest data archive from https://crpropa.desy.de/Interaction_data and extract to CRPropa3/data +2. CRPropa uses CMAKE to configure. From the build directory call ccmake or cmake cd build ccmake .. -2. Afterward configuring run make and make install as usual +3. Afterward configuring run make and make install as usual make make install From 52f6e7db270ae0ea8a5bcbbce9eb3636b3e20cdf Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 18 Nov 2013 12:59:39 -0300 Subject: [PATCH 0364/1298] Vector3: add spherical unit vectors and tests --- include/crpropa/Vector3.h | 17 ++++++++++++++--- test/testVector3.cpp | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/include/crpropa/Vector3.h b/include/crpropa/Vector3.h index efb5d1c14..4b2c94505 100644 --- a/include/crpropa/Vector3.h +++ b/include/crpropa/Vector3.h @@ -76,7 +76,7 @@ class Vector3 { } T getPhi() const { - T eps = std::numeric_limits::min(); + T eps = std::numeric_limits < T > ::min(); if ((fabs(x) < eps) and (fabs(y) < eps)) return 0.0; else @@ -84,7 +84,7 @@ class Vector3 { } T getTheta() const { - T eps = std::numeric_limits::min(); + T eps = std::numeric_limits < T > ::min(); if ((fabs(x) < eps) and (fabs(y) < eps) and (fabs(z) < eps)) return 0.0; else @@ -122,7 +122,18 @@ class Vector3 { } Vector3 getUnitVector() const { - return Vector3(x, y, z) / getMag(); + return *this / getMag(); + } + + Vector3 getUnitVectorTheta() const { + T theta = getTheta(); + T phi = getPhi(); + return Vector3(cos(theta) * cos(phi), cos(theta) * sin(phi), + -sin(theta)); + } + + Vector3 getUnitVectorPhi() const { + return Vector3(-sin(getPhi()), cos(getPhi()), 0); } void normalize() { diff --git a/test/testVector3.cpp b/test/testVector3.cpp index 5fa9068dd..3f44384d1 100644 --- a/test/testVector3.cpp +++ b/test/testVector3.cpp @@ -3,6 +3,18 @@ namespace crpropa { +TEST(Vector3, multiplication) { + Vector3d v(1); + v *= 10; + EXPECT_DOUBLE_EQ(v.x, 10); + EXPECT_DOUBLE_EQ(v.y, 10); + EXPECT_DOUBLE_EQ(v.z, 10); + v = Vector3d(1) * Vector3d(2); // element-wise multiplication + EXPECT_DOUBLE_EQ(v.x, 2); + EXPECT_DOUBLE_EQ(v.y, 2); + EXPECT_DOUBLE_EQ(v.z, 2); +} + TEST(Vector3, division) { Vector3d v(10); v /= 10; @@ -44,6 +56,32 @@ TEST(Vector3, angle) { EXPECT_DOUBLE_EQ(b, 0); } +TEST(Vector3, comparison) { + EXPECT_TRUE(Vector3d(1, 2, 3) == Vector3d(1, 2, 3)); + EXPECT_TRUE(Vector3d(1, 2, 3) < Vector3d(2, 3, 4)); +} + +TEST(Vector3, unitVectors) { + Vector3d v = Vector3d(2, 0, 0); + Vector3d er = v.getUnitVector(); + Vector3d et = v.getUnitVectorTheta(); + Vector3d ep = v.getUnitVectorPhi(); + + // trigonometrical functions don't preserve double precision + double eps = 1e-16; + EXPECT_NEAR(er.x, 1, eps); + EXPECT_NEAR(er.y, 0, eps); + EXPECT_NEAR(er.z, 0, eps); + + EXPECT_NEAR(ep.x, 0, eps); + EXPECT_NEAR(ep.y, 1, eps); + EXPECT_NEAR(ep.z, 0, eps); + + EXPECT_NEAR(et.x, 0, eps); + EXPECT_NEAR(et.y, 0, eps); + EXPECT_NEAR(et.z, -1, eps); +} + TEST(Vector3, magnitude) { Vector3d v = Vector3d(1, 2, -2); EXPECT_DOUBLE_EQ(v.getMag(), 3); From 76dd2ec8266ae42d17feecc6f82aa02d82c3f83d Mon Sep 17 00:00:00 2001 From: Rafael Alves Batista Date: Mon, 18 Nov 2013 18:46:49 +0100 Subject: [PATCH 0365/1298] Handling AMR grids. --- cmake/FindSAGA.cmake | 19 +++++ cmake/FindSQLite3.cmake | 19 +++++ .../crpropa/magneticField/AMRMagneticField.h | 77 +++++++++++++++++++ python/crpropa.i | 2 + 4 files changed, 117 insertions(+) create mode 100644 cmake/FindSAGA.cmake create mode 100644 cmake/FindSQLite3.cmake create mode 100644 include/crpropa/magneticField/AMRMagneticField.h diff --git a/cmake/FindSAGA.cmake b/cmake/FindSAGA.cmake new file mode 100644 index 000000000..7886e2dae --- /dev/null +++ b/cmake/FindSAGA.cmake @@ -0,0 +1,19 @@ +# SAGA_INCLUDE_DIR = path to SAGA directory +# SAGA_LIBRARY libsaga.a +# SAGA_FOUND = true if SAGA is found + +find_path(SAGA_INCLUDE_DIR AMRgrid.h) +find_library(SAGA_LIBRARY libSAGA) + +set(SAGA_FOUND FALSE) +if(SAGA_INCLUDE_DIR AND SAGA_LIBRARY) + set(SAGA_FOUND TRUE) + MESSAGE(STATUS "SAGA: Found!") +else() + MESSAGE(STATUS "SAGA: NOT Found!") +endif() + +MESSAGE(STATUS " Include: ${SAGA_INCLUDE_DIR}") +MESSAGE(STATUS " Library: ${SAGA_LIBRARY}") + +mark_as_advanced(SAGA_INCLUDE_DIR SAGA_LIBRARY SAGA_FOUND) diff --git a/cmake/FindSQLite3.cmake b/cmake/FindSQLite3.cmake new file mode 100644 index 000000000..852f7294d --- /dev/null +++ b/cmake/FindSQLite3.cmake @@ -0,0 +1,19 @@ +# SQLITE3_INCLUDE_DIR = path to Quimby directory +# SQLITE3_LIBRARY = libQuimby.a +# SQLITE3_FOUND = true if Quimby is found + +find_path(SQLITE3_INCLUDE_DIR sqlite3.h) +find_library(SQLITE3_LIBRARY libsqlite3) + +set(SQLITE3_FOUND FALSE) +if(SQLITE3_INCLUDE_DIR AND SQLITE3_LIBRARY) + set(QUIMBY_FOUND TRUE) + MESSAGE(STATUS "SQLite3: Found!") +else() + MESSAGE(STATUS "SQLite3: NOT Found!") +endif() + +MESSAGE(STATUS " Include: ${SQLITE3_INCLUDE_DIR}") +MESSAGE(STATUS " Library: ${SQLITE3_LIBRARY}") + +mark_as_advanced(SQLITE3_INCLUDE_DIR SQLITE3_LIBRARY QUIMBY_FOUND) diff --git a/include/crpropa/magneticField/AMRMagneticField.h b/include/crpropa/magneticField/AMRMagneticField.h new file mode 100644 index 000000000..3d3939ba3 --- /dev/null +++ b/include/crpropa/magneticField/AMRMagneticField.h @@ -0,0 +1,77 @@ +#ifndef CRPROPA_AMRMAGNETICFIELD_H +#define CRPROPA_AMRMAGNETICFIELD_H + +#ifdef CRPROPA_HAVE_SAGA + +#include +#include +#include + +#ifdef _OPENMP + #include "omp.h" +#endif + +#include "crpropa/Units.h" +#include "crpropa/magneticField/MagneticField.h" +#include "crpropa/Vector3.h" + +#include "saga/LocalProperties.h" +#include "saga/AMRgrid.h" +#include "saga/MagneticField.h" +#include "saga/Referenced.h" + + + +namespace crpropa { + +/** + @class AMRMagneticField + @brief Wrapper for saga::MagneticField + */ +class AMRMagneticField: public MagneticField { + +private: + saga::ref_ptr field; + double cfLength; + double cfDensity; + double cfMagneticField; + +public: + + AMRMagneticField(saga::ref_ptr field_, double convLength, double convDensity, double convMagneticField) + { + field = field_; + cfLength = convLength; + cfDensity = convDensity; + cfMagneticField = convMagneticField; + } + + Vector3d getField(const Vector3d &position) const { + + double x = position.x/cfLength; + double y = position.y/cfLength; + double z = position.z/cfLength; + + std::vector b; + #ifdef _OPENMP + #pragma omp critical + { + b = field->getField(x, y, z); + } + #else + b = field->getField(x, y, z); + #endif + + for(int i=0; i<3; i++) + b[i]*=cfMagneticField; + //std::cout << x*cfLength/Mpc << " " << y*cfLength/Mpc << " " << z*cfLength/Mpc << " || " << b[0] << " " << b[1] << " " << b[0] << std::endl; + + return Vector3d(b[0], b[1], b[2]) * tesla; + } + +}; + +} // namespace crpropa + +#endif // CRPROPA_HAVE_SAGA +#endif // CRPROPA_AMRMAGNETICFIELD_H diff --git a/python/crpropa.i b/python/crpropa.i index 307d04769..846b8341f 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -46,6 +46,7 @@ using std::ptrdiff_t; #include "crpropa/magneticField/MagneticField.h" #include "crpropa/magneticField/MagneticFieldGrid.h" #include "crpropa/magneticField/QuimbyMagneticField.h" +#include "crpropa/magneticField/AMRMagneticField.h" #include "crpropa/magneticField/JF12Field.h" #include "crpropa/Referenced.h" @@ -139,6 +140,7 @@ using std::ptrdiff_t; %include "crpropa/magneticField/MagneticFieldGrid.h" %include "crpropa/magneticField/QuimbyMagneticField.h" +%include "crpropa/magneticField/AMRMagneticField.h" %include "crpropa/magneticField/JF12Field.h" %include "crpropa/ExplicitRungeKutta.h" From d1de7e9e03751d188a84693b45140ef8a7e8db1c Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 18 Nov 2013 15:20:03 -0300 Subject: [PATCH 0366/1298] refactored Vector3 class: made method naming scheme consistent made methods work with return values --- include/crpropa/Vector3.h | 166 ++++++++++++------- src/GridTools.cpp | 14 +- src/ParticleState.cpp | 2 +- src/Random.cpp | 6 +- src/Source.cpp | 2 +- src/magneticField/JF12Field.cpp | 7 +- src/magneticField/TurbulentMagneticField.cpp | 4 +- src/module/Boundary.cpp | 2 +- src/module/Observer.cpp | 8 +- src/module/PhotonDINT.cpp | 4 +- test/testMagneticField.cpp | 2 +- test/testVector3.cpp | 75 +++++---- 12 files changed, 177 insertions(+), 115 deletions(-) diff --git a/include/crpropa/Vector3.h b/include/crpropa/Vector3.h index 4b2c94505..bcd62c2f5 100644 --- a/include/crpropa/Vector3.h +++ b/include/crpropa/Vector3.h @@ -8,6 +8,17 @@ namespace crpropa { +/** + @class Vector3 + @brief Template class for 3-vectors of type float, double, ... + + Allows accessing and changing the elements x, y, z directly or through the + corresponding get and set methods. + + Angle definitions are + phi [-pi, pi]: azimuthal angle in the x-y plane, 0 pointing in x-direction + theta [0, pi]: zenith angle towards the z axis, 0 pointing in z-direction + */ template class Vector3 { public: @@ -57,6 +68,10 @@ class Vector3 { z = Z; } + void setR(const T r) { + *this *= r / getR(); + } + void setRThetaPhi(const T r, const T theta, const T phi) { x = r * sin(theta) * cos(phi); y = r * sin(theta) * sin(phi); @@ -75,6 +90,17 @@ class Vector3 { return z; } + // magnitude (2-norm) of the vector + T getR() const { + return std::sqrt(x * x + y * y + z * z); + } + + // square of magnitude of the vector + T getR2() const { + return x * x + y * y + z * z; + } + + // return the azimuth angle T getPhi() const { T eps = std::numeric_limits < T > ::min(); if ((fabs(x) < eps) and (fabs(y) < eps)) @@ -83,6 +109,7 @@ class Vector3 { return std::atan2(y, x); } + // return the zenith angle T getTheta() const { T eps = std::numeric_limits < T > ::min(); if ((fabs(x) < eps) and (fabs(y) < eps) and (fabs(z) < eps)) @@ -91,40 +118,12 @@ class Vector3 { return atan2((T) sqrt(x * x + y * y), z); } - T getAngleTo(const Vector3 &v) const { - T cosdistance = this->dot(v) / this->getMag() / v.getMag(); - // In some directions cosdistance is > 1 on some compilers - // This ensures that the correct result is returned - if (cosdistance >= 1.) - return 0; - if (cosdistance <= -1.) - return M_PI; - else - return acos(cosdistance); - } - - bool isParallelTo(const Vector3 &v, T maxAngle) const { - T angle = this->getAngleTo(v); - return angle < maxAngle; - } - - T getDistanceTo(const Vector3 &point) const { - Vector3 d = *this - point; - return d.getMag(); - } - - T getMag() const { - return std::sqrt(x * x + y * y + z * z); - } - - T getMag2() const { - return x * x + y * y + z * z; - } - + // return the unit-vector e_r Vector3 getUnitVector() const { - return *this / getMag(); + return *this / getR(); } + // return the unit-vector e_theta Vector3 getUnitVectorTheta() const { T theta = getTheta(); T phi = getPhi(); @@ -132,74 +131,112 @@ class Vector3 { -sin(theta)); } + // return the unit-vector e_phi Vector3 getUnitVectorPhi() const { return Vector3(-sin(getPhi()), cos(getPhi()), 0); } - void normalize() { - *this /= getMag(); + // return the angle [0, pi] between the vectors + T getAngleTo(const Vector3 &v) const { + T cosdistance = dot(v) / v.getR() / getR(); + // In some directions cosdistance is > 1 on some compilers + // This ensures that the correct result is returned + if (cosdistance >= 1.) + return 0; + else if (cosdistance <= -1.) + return M_PI; + else + return acos(cosdistance); } - T dot(const Vector3 &v) const { - return x * v.x + y * v.y + z * v.z; + // return true if the angle between the vectors is smaller than a threshold + bool isParallelTo(const Vector3 &v, T maxAngle) const { + return getAngleTo(v) < maxAngle; } - Vector3 cross(const Vector3 &v) const { - return Vector3(y * v.z - v.y * z, z * v.x - v.z * x, - x * v.y - v.x * y); + // linear distance to a given vector + T getDistanceTo(const Vector3 &point) const { + Vector3 d = *this - point; + return d.getR(); } - double perp2(const Vector3 & p) const { - double tot = p.getMag2(); - double ss = dot(p); - return tot > 0.0 ? getMag2() - ss * ss / tot : getMag2(); + // return the component parallel to a second vector + // 0 if the second vector has 0 magnitude + Vector3 getParallelTo(const Vector3 &v) const { + T vmag = v.getR(); + if (vmag == std::numeric_limits < T > ::min()) + return Vector3(0.); + return v * dot(v) / vmag; } - double perp(const Vector3 & p) const { - return std::sqrt(perp2(p)); + // return the component perpendicular to a second vector + // 0 if the second vector has 0 magnitude + Vector3 getPerpendicularTo(const Vector3 &v) const { + if (v.getR() == std::numeric_limits < T > ::min()) + return Vector3(0.); + return (*this) - getParallelTo(v); } - void rotate(const Vector3 &axis, T angle) { - T ux = axis.getX() / axis.getMag(); - T uy = axis.getY() / axis.getMag(); - T uz = axis.getZ() / axis.getMag(); + // rotate the vector around a given axis by a given a angle + Vector3 getRotated(const Vector3 &axis, T angle) const { + Vector3 u = axis / axis.getR(); T c = cos(angle); T s = sin(angle); - Vector3 Rx(c + ux * ux * (1 - c), ux * uy * (1 - c) - uz * s, - ux * uz * (1 - c) + uy * s); - Vector3 Ry(uy * ux * (1 - c) + uz * s, c + uy * uy * (1 - c), - uy * uz * (1 - c) - ux * s); - Vector3 Rz(uz * ux * (1 - c) - uy * s, uz * uy * (1 - c) + ux * s, - c + uz * uz * (1 - c)); - this->setXYZ(Rx.dot(*this), Ry.dot(*this), Rz.dot(*this)); + Vector3 Rx(c + u.x * u.x * (1 - c), u.x * u.y * (1 - c) - u.z * s, + u.x * u.z * (1 - c) + u.y * s); + Vector3 Ry(u.y * u.x * (1 - c) + u.z * s, c + u.y * u.y * (1 - c), + u.y * u.z * (1 - c) - u.x * s); + Vector3 Rz(u.z * u.x * (1 - c) - u.y * s, + u.z * u.y * (1 - c) + u.x * s, c + u.z * u.z * (1 - c)); + return Vector3(dot(Rx), dot(Ry), dot(Rz)); } - void clamp(T lower, T upper) { - x = std::max(lower, std::min(x, upper)); - y = std::max(lower, std::min(y, upper)); - z = std::max(lower, std::min(z, upper)); + // return vector with values limited to the range [lower, upper] + Vector3 clip(T lower, T upper) const { + Vector3 out; + out.x = std::max(lower, std::min(x, upper)); + out.y = std::max(lower, std::min(y, upper)); + out.z = std::max(lower, std::min(z, upper)); + return out; } + // return vector with absolute values Vector3 abs() const { return Vector3(std::abs(x), std::abs(y), std::abs(z)); } + // return vector with floored values Vector3 floor() const { return Vector3(std::floor(x), std::floor(y), std::floor(z)); } + // return vector with ceiled values Vector3 ceil() const { return Vector3(std::ceil(x), std::ceil(y), std::ceil(z)); } - T min() { + // minimum element + T min() const { return std::min(x, std::min(y, z)); } - T max() { + // maximum element + T max() const { return std::max(x, std::max(y, z)); } + // dot product + T dot(const Vector3 &v) const { + return x * v.x + y * v.y + z * v.z; + } + + // cross product + Vector3 cross(const Vector3 &v) const { + return Vector3(y * v.z - v.y * z, z * v.x - v.z * x, + x * v.y - v.x * y); + } + + // returns true if all elements of the first vector are smaller than those in the second vector bool operator <(const Vector3 &v) const { if (x > v.x) return false; @@ -215,6 +252,7 @@ class Vector3 { return true; } + // returns true if all elements of the two vectors are equal bool operator ==(const Vector3 &v) const { if (x != v.x) return false; @@ -241,6 +279,7 @@ class Vector3 { return Vector3(x - f, y - f, z - f); } + // element-wise multiplication Vector3 operator *(const Vector3 &v) const { return Vector3(x * v.x, y * v.y, z * v.z); } @@ -249,6 +288,7 @@ class Vector3 { return Vector3(x * v, y * v, z * v); } + // element-wise division Vector3 operator /(const Vector3 &v) const { return Vector3(x / v.x, y / v.y, z / v.z); } @@ -257,6 +297,7 @@ class Vector3 { return Vector3(x / f, y / f, z / f); } + // element-wise modulo operation Vector3 operator %(const Vector3 &v) const { return Vector3(fmod(x, v.x), fmod(y, v.y), fmod(z, v.z)); } @@ -293,6 +334,7 @@ class Vector3 { return *this; } + // element-wise multiplication Vector3 &operator *=(const Vector3 &v) { x *= v.x; y *= v.y; @@ -307,6 +349,7 @@ class Vector3 { return *this; } + // element-wise division Vector3 &operator /=(const Vector3 &v) { x /= v.x; y /= v.y; @@ -321,6 +364,7 @@ class Vector3 { return *this; } + // element-wise modulo operation Vector3 &operator %=(const Vector3 &v) { x = fmod(x, v.x); y = fmod(y, v.y); diff --git a/src/GridTools.cpp b/src/GridTools.cpp index 81f1cb7c3..cd69515e8 100644 --- a/src/GridTools.cpp +++ b/src/GridTools.cpp @@ -26,7 +26,7 @@ double meanFieldStrength(ref_ptr grid) { for (int ix = 0; ix < Nx; ix++) for (int iy = 0; iy < Ny; iy++) for (int iz = 0; iz < Nz; iz++) - mean += grid->get(ix, iy, iz).getMag(); + mean += grid->get(ix, iy, iz).getR(); return mean / Nx / Ny / Nz; } @@ -38,8 +38,8 @@ double rmsFieldStrength(ref_ptr grid) { for (int ix = 0; ix < Nx; ix++) for (int iy = 0; iy < Ny; iy++) for (int iz = 0; iz < Nz; iz++) - sumB2 += grid->get(ix, iy, iz).getMag2(); - return sqrt(sumB2 / Nx / Ny / Nz); + sumB2 += grid->get(ix, iy, iz).getR2(); + return std::sqrt(sumB2 / Nx / Ny / Nz); } void scaleGrid(ref_ptr grid, double a) { @@ -101,7 +101,7 @@ void initTurbulence(ref_ptr grid, double Brms, double lMin, i = ix * n * n2 + iy * n2 + iz; ek.setXYZ(K[ix], K[iy], K[iz]); - k = ek.getMag(); + k = ek.getR(); // wave outside of turbulent range -> B(k) = 0 if ((k < kMin) || (k > kMax)) { @@ -115,7 +115,7 @@ void initTurbulence(ref_ptr grid, double Brms, double lMin, } // construct an orthogonal base ek, e1, e2 - if (ek.getAngleTo(n0) < 1e-3) { + if (ek.isParallelTo(n0, float(1e-3))) { // ek parallel to (1,1,1) e1.setXYZ(-1., 1., 0); e2.setXYZ(1., 1., -2.); @@ -124,8 +124,8 @@ void initTurbulence(ref_ptr grid, double Brms, double lMin, e1 = n0.cross(ek); e2 = ek.cross(e1); } - e1 /= e1.getMag(); - e2 /= e2.getMag(); + e1 /= e1.getR(); + e2 /= e2.getR(); // random orientation perpendicular to k theta = 2 * M_PI * random.rand(); diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index 5cd3e81e5..0f7e1f78e 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -21,7 +21,7 @@ const Vector3d &ParticleState::getPosition() const { } void ParticleState::setDirection(const Vector3d &dir) { - direction = dir / dir.getMag(); + direction = dir / dir.getR(); } const Vector3d &ParticleState::getDirection() const { diff --git a/src/Random.cpp b/src/Random.cpp index fc30628ca..e3f5da9e5 100644 --- a/src/Random.cpp +++ b/src/Random.cpp @@ -143,11 +143,9 @@ Vector3d Random::randVector() { Vector3d Random::randVectorAroundMean(const Vector3d &meanDirection, double angle) { - Vector3d rotAxis = meanDirection.cross(randVector()); - rotAxis.normalize(); + Vector3d axis = meanDirection.cross(randVector()); Vector3d v = meanDirection; - v.rotate(rotAxis, angle); - return v; + return v.getRotated(axis, angle); } Vector3d Random::randFisherVector(const Vector3d &meanDirection, double kappa) { diff --git a/src/Source.cpp b/src/Source.cpp index 14ef0b78f..3ea9c553e 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -293,7 +293,7 @@ void SourceUniformRedshift::prepare(Candidate& candidate) const { } void SourceRedshift1D::prepare(Candidate& candidate) const { - double d = candidate.source.getPosition().getMag(); + double d = candidate.source.getPosition().getR(); double z = comovingDistance2Redshift(d); candidate.setRedshift(z); } diff --git a/src/magneticField/JF12Field.cpp b/src/magneticField/JF12Field.cpp index cb7a55612..507593542 100644 --- a/src/magneticField/JF12Field.cpp +++ b/src/magneticField/JF12Field.cpp @@ -161,7 +161,7 @@ Vector3d JF12Field::getRegularField(const Vector3d& pos) const { Vector3d b(0.); double r = sqrt(pos.x * pos.x + pos.y * pos.y); // in-plane radius - double d = pos.getMag(); // distance to galactic center + double d = pos.getR(); // distance to galactic center if ((d < 1 * kpc) or (d > 20 * kpc)) return b; // 0 field for d < 1 kpc or d > 20 kpc @@ -242,7 +242,7 @@ Vector3d JF12Field::getStriatedField(const Vector3d& pos) const { } double JF12Field::getTurbulentStrength(const Vector3d& pos) const { - if (pos.getMag() > 20 * kpc) + if (pos.getR() > 20 * kpc) return 0; double r = sqrt(pos.x * pos.x + pos.y * pos.y); // in-plane radius @@ -269,7 +269,8 @@ double JF12Field::getTurbulentStrength(const Vector3d& pos) const { bDisk *= exp(-0.5 * pow(pos.z / zDiskTurb, 2)); // halo - double bHalo = bHaloTurb * exp(-r / rHaloTurb) * exp(-0.5 * pow(pos.z / zHaloTurb, 2)); + double bHalo = bHaloTurb * exp(-r / rHaloTurb) + * exp(-0.5 * pow(pos.z / zHaloTurb, 2)); // modulate turbulent field return sqrt(pow(bDisk, 2) + pow(bHalo, 2)); diff --git a/src/magneticField/TurbulentMagneticField.cpp b/src/magneticField/TurbulentMagneticField.cpp index 39d3fe404..489d1ddc7 100644 --- a/src/magneticField/TurbulentMagneticField.cpp +++ b/src/magneticField/TurbulentMagneticField.cpp @@ -66,8 +66,8 @@ void TurbulentMagneticField::initialize() { // random orientation of b double alpha = random.rand(2 * M_PI); - mode.e1 = e1 / e1.getMag() * cos(alpha); - mode.e2 = e2 / e2.getMag() * sin(alpha); + mode.e1 = e1 / e1.getR() * cos(alpha); + mode.e2 = e2 / e2.getR() * sin(alpha); // random phase mode.phase = random.rand(2 * M_PI); diff --git a/src/module/Boundary.cpp b/src/module/Boundary.cpp index 87e7c6c56..ba65c7512 100644 --- a/src/module/Boundary.cpp +++ b/src/module/Boundary.cpp @@ -168,7 +168,7 @@ SphericalBoundary::SphericalBoundary(Vector3d c, double r) : } void SphericalBoundary::process(Candidate *c) const { - double d = (c->current.getPosition() - center).getMag(); + double d = (c->current.getPosition() - center).getR(); if (d >= radius) { c->setActive(false); c->setProperty(flag, flagValue); diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp index a8f453afa..0aeeb52de 100644 --- a/src/module/Observer.cpp +++ b/src/module/Observer.cpp @@ -12,7 +12,7 @@ SmallObserverSphere::SmallObserverSphere(Vector3d center, double radius, void SmallObserverSphere::process(Candidate *candidate) const { // current distance to observer sphere center - double d = (candidate->current.getPosition() - center).getMag(); + double d = (candidate->current.getPosition() - center).getR(); // conservatively limit next step to prevent overshooting candidate->limitNextStep(fabs(d - radius)); @@ -22,7 +22,7 @@ void SmallObserverSphere::process(Candidate *candidate) const { return; // previous distance to observer sphere center - double dprev = (candidate->previous.getPosition() - center).getMag(); + double dprev = (candidate->previous.getPosition() - center).getR(); // if particle was inside of sphere in previous step it has already been detected if (dprev <= radius) @@ -69,7 +69,7 @@ LargeObserverSphere::LargeObserverSphere(Vector3d center, double radius, void LargeObserverSphere::process(Candidate *candidate) const { // current distance to observer sphere center - double d = (candidate->current.getPosition() - center).getMag(); + double d = (candidate->current.getPosition() - center).getR(); // conservatively limit next step size to prevent overshooting candidate->limitNextStep(fabs(radius - d)); @@ -79,7 +79,7 @@ void LargeObserverSphere::process(Candidate *candidate) const { return; // previous distance to observer sphere center - double dprev = (candidate->previous.getPosition() - center).getMag(); + double dprev = (candidate->previous.getPosition() - center).getR(); // if particle was outside of sphere in previous step it has already been detected if (dprev >= radius) diff --git a/src/module/PhotonDINT.cpp b/src/module/PhotonDINT.cpp index 8dc4b13e7..879964091 100644 --- a/src/module/PhotonDINT.cpp +++ b/src/module/PhotonDINT.cpp @@ -83,7 +83,7 @@ void PhotonDINT::process(Candidate *candidate) const { string initialType = "photon"; candidate->getProperty("PhotonInitialType", initialType); - double showerPropDistance = (initialPosition - position).getMag(); + double showerPropDistance = (initialPosition - position).getR(); // Initialize the bField dCVector bField; @@ -95,7 +95,7 @@ void PhotonDINT::process(Candidate *candidate) const { Vector3d p = initialPosition + direction * showerPropDistance * (i + 0.5) / bFieldSteps; Vector3d B = field->getField(p); - bField.vector[i] = B.perp(direction) / gauss; + bField.vector[i] = B.getPerpendicularTo(direction).getR() / gauss; } // Initialize output spectrum diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index de985725f..c53f105ad 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -114,7 +114,7 @@ TEST(testTurbulentMagneticField, Brms) { for (int iz = 0; iz < n; iz++) { b = B.getField(Vector3d(r.rand(), r.rand(), r.rand()) * 100000); Bmean += b; - sumB2 = b.getMag2(); + sumB2 = b.getR2(); } } } diff --git a/test/testVector3.cpp b/test/testVector3.cpp index 3f44384d1..1b2bb3802 100644 --- a/test/testVector3.cpp +++ b/test/testVector3.cpp @@ -3,6 +3,11 @@ namespace crpropa { +TEST(Vector3, comparison) { + EXPECT_TRUE(Vector3d(1, 2, 3) == Vector3d(1, 2, 3)); + EXPECT_TRUE(Vector3d(1, 2, 3) < Vector3d(2, 3, 4)); +} + TEST(Vector3, multiplication) { Vector3d v(1); v *= 10; @@ -44,23 +49,18 @@ TEST(Vector3, dot) { TEST(Vector3, cross) { Vector3d v = Vector3d(1, 0, 0).cross(Vector3d(0, 1, 0)); - EXPECT_DOUBLE_EQ(v.x, 0); - EXPECT_DOUBLE_EQ(v.y, 0); - EXPECT_DOUBLE_EQ(v.z, 1); + EXPECT_TRUE(v == Vector3d(0, 0, 1)); } TEST(Vector3, angle) { + // 45 degrees double a = Vector3d(1, 1, 0).getAngleTo(Vector3d(1, 0, 0)); EXPECT_DOUBLE_EQ(a, 45 * M_PI / 180); + // perpendicular vectors double b = Vector3d(0, 0, 1).getAngleTo(Vector3d(0, 0, 1)); EXPECT_DOUBLE_EQ(b, 0); } -TEST(Vector3, comparison) { - EXPECT_TRUE(Vector3d(1, 2, 3) == Vector3d(1, 2, 3)); - EXPECT_TRUE(Vector3d(1, 2, 3) < Vector3d(2, 3, 4)); -} - TEST(Vector3, unitVectors) { Vector3d v = Vector3d(2, 0, 0); Vector3d er = v.getUnitVector(); @@ -73,19 +73,19 @@ TEST(Vector3, unitVectors) { EXPECT_NEAR(er.y, 0, eps); EXPECT_NEAR(er.z, 0, eps); - EXPECT_NEAR(ep.x, 0, eps); - EXPECT_NEAR(ep.y, 1, eps); - EXPECT_NEAR(ep.z, 0, eps); - EXPECT_NEAR(et.x, 0, eps); EXPECT_NEAR(et.y, 0, eps); EXPECT_NEAR(et.z, -1, eps); + + EXPECT_NEAR(ep.x, 0, eps); + EXPECT_NEAR(ep.y, 1, eps); + EXPECT_NEAR(ep.z, 0, eps); } TEST(Vector3, magnitude) { Vector3d v = Vector3d(1, 2, -2); - EXPECT_DOUBLE_EQ(v.getMag(), 3); - EXPECT_DOUBLE_EQ(v.getMag2(), 9); + EXPECT_DOUBLE_EQ(v.getR(), 3); + EXPECT_DOUBLE_EQ(v.getR2(), 9); } TEST(Vector3, distance) { @@ -94,24 +94,43 @@ TEST(Vector3, distance) { } TEST(Vector3, rotation) { - Vector3d v(10, 0, 0); - v.rotate(Vector3d(0, 2, 0), M_PI); - EXPECT_NEAR(v.x, -10, 1e-9); - // rotation doesn't preserve double precision - EXPECT_NEAR(v.y, 0, 1e-9); - EXPECT_NEAR(v.z, 0, 1e-9); + Vector3d v, w; + // rotation by 180 degrees v = Vector3d(10, 0, 0); - v.rotate(Vector3d(1, 0, 0), M_PI); // no rotation - EXPECT_NEAR(v.x, 10, 1e-9); - EXPECT_NEAR(v.y, 0, 1e-9); - EXPECT_NEAR(v.z, 0, 1e-9); + w = v.getRotated(Vector3d(0, 2, 0), M_PI); + EXPECT_NEAR(w.x, -10, 1e-9); + EXPECT_NEAR(w.y, 0, 1e-9); + EXPECT_NEAR(w.z, 0, 1e-9); + // rotation axis parallel to vector --> no rotation + v = Vector3d(10, 0, 0); + w = v.getRotated(Vector3d(1, 0, 0), M_PI); + EXPECT_NEAR(w.x, 10, 1e-9); + EXPECT_NEAR(w.y, 0, 1e-9); + EXPECT_NEAR(w.z, 0, 1e-9); + + // rotation by 360 degrees v = Vector3d(5, 2, 7); - v.rotate(Vector3d(1, 8, -4), 2 * M_PI); // full rotation - EXPECT_NEAR(v.x, 5, 1e-9); - EXPECT_NEAR(v.y, 2, 1e-9); - EXPECT_NEAR(v.z, 7, 1e-9); + w = v.getRotated(Vector3d(1, 8, -4), 2 * M_PI); + EXPECT_NEAR(w.x, 5, 1e-9); + EXPECT_NEAR(w.y, 2, 1e-9); + EXPECT_NEAR(w.z, 7, 1e-9); +} + +TEST(Vector3, parallelPerpendicular) { + Vector3d v(3, 2, 1); + Vector3d w(0, 1, 0); + + Vector3d vpara = v.getParallelTo(w); + Vector3d vperp = v.getPerpendicularTo(w); + + EXPECT_DOUBLE_EQ(vpara.x, 0); + EXPECT_DOUBLE_EQ(vpara.y, 2); + EXPECT_DOUBLE_EQ(vpara.z, 0); + EXPECT_DOUBLE_EQ(vperp.x, 3); + EXPECT_DOUBLE_EQ(vperp.y, 0); + EXPECT_DOUBLE_EQ(vperp.z, 1); } int main(int argc, char **argv) { From 08317187cc4a5db79815c1c8b5df504171adeb7c Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 10 Dec 2013 11:48:17 +0100 Subject: [PATCH 0367/1298] python module for galactic magnetic lenses --- contrib/gamale.py | 229 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 contrib/gamale.py diff --git a/contrib/gamale.py b/contrib/gamale.py new file mode 100644 index 000000000..66cf0b9c3 --- /dev/null +++ b/contrib/gamale.py @@ -0,0 +1,229 @@ +""" +Galactic Magnetic Lens class + +A Python reimplementation of the magnetic field lens technique from PARSEC. +PARSEC: A Parametrized Simulation Engine for Ultra-High Energy Cosmic Ray Protons +arXiv:1302.3761 +http://web.physik.rwth-aachen.de/Auger_MagneticFields/PARSEC/ +""" + +from struct import pack, unpack +from bisect import bisect_left +from os import path + +import numpy as np +import healpy +from scipy import sparse + + +def maxColumnSum(M): + """ + Return the 1-norm (maximum of absolute sums of columns) of the given matrix. + The absolute value can be omitted, since the matrix elements are all positive. + """ + return M.sum(axis=0).max() + +def maxRowSum(M): + """ + Return the infinity-norm (maximum of sums of absolute rows) of the given matrix. + The absolute value can be omitted, since the matrix elements are all positive. + """ + return M.sum(axis=1).max() + +def normalizeRowSum(Mcsc): + """ + Normalize each row of a CSC matrix to a row sum of 1. + """ + rowSum = np.array(Mcsc.sum(axis=1).transpose())[0] + Mcsc.data /= rowSum[Mcsc.indices] + +def generateLensPart(fname, nside=64): + """ + Generate a lens part from the given CRPropa 3 simulation. + """ + f = np.genfromtxt(fname, names=True) + row = healpy.vec2pix(nside, f['P0x'], f['P0y'], f['P0z']) # earth + col = healpy.vec2pix(nside, f['Px'], f['Py'], f['Pz'] ) # galaxy + npix = healpy.nside2npix(nside) + data = np.ones(len(row)) + M = sparse.coo_matrix((data, (row, col)), shape=(npix, npix)) + M = M.tocsc() + normalizeRowSum(M) + return M + +def saveLensPart(Mcsc, fname): + """ + Save the lens part in coordinate type sparse format. + This format is compatible with PARSEC. + """ + M = Mcsc.tocoo() + fout = open(fname, 'wb') + fout.write(pack('i4', M.nnz)) + fout.write(pack('i4', M.shape[0])) + fout.write(pack('i4', M.shape[1])) + data = np.zeros((M.nnz,), dtype=np.dtype([('row', 'i4'), ('col','i4'),('data','f8')])) + data['row'] = M.row + data['col'] = M.col + data['data'] = M.data + data.tofile(fout) + fout.close() + +def loadLensPart(fname): + """ + Load a lens part from the given PARSEC file. + """ + fin = open(fname, 'rb') + nnz = unpack('i', fin.read(4))[0] + nrows = unpack('i', fin.read(4))[0] + ncols = unpack('i', fin.read(4))[0] + data = np.fromfile(fin, dtype=np.dtype([('row','i4'), ('col','i4'), ('data','f8')])) + fin.close() + M = sparse.coo_matrix((data['data'],(data['row'], data['col'])), shape=(nrows, ncols)) + return M.tocsc() + +def randVecInPix(nside, ipix, nest=False): + """ + Draw vectors from a uniform distribution within a HEALpixel. + nside : healpix nside parameter + ipix : pixel number(s) + """ + if not(nest): + ipix = healpy.ring2nest(nside, ipix=ipix) + + norder = nside2norder(nside) + nUp = 29 - norder + iUp = ipix * 4**nUp + + if np.iterable(ipix): + iUp += np.random.randint(0, 4**nUp, size=np.size(ipix)) + else: + iUp += np.random.randint(0, 4**nUp) + vec = healpy.pix2vec(nside=2**29, ipix=iUp, nest=True) + return vec + +class Lens: + """ + Galactic magnetic field lens class with the following conventions: + - the lens maps directions at the galactic border (pointing outwards back to the source) to observed directions on Earth (pointing outwards) + - the Galactic coordinate system is used + - spherical coordinates are avoided + - for each logarithmic energy bin there is a lens part represented by a matrix + - energies are given in EeV + - the matrices (lensParts) are in compressed sparse column format (scipy.sparse.csc) + - for each matrix M_ij + - the row number i indexes the observed direction + - the column number j the direction at the Galactic edge + - indices are HEALpixel in ring scheme. + """ + lensParts = [] # list of matrices in order of ascending energy + lRmins = [] # lower rigidity bounds per lens (log10(E/Z/[eV])) + lRmax = 0 # upper rigidity bound of last lens (log10(E/Z/[eV])) + nside = None # HEALpix nside parameter + neutralLensPart = None # matrix for neutral particles + maxColumnSum = 1 # maximum of column sums of all matrices + + def __init__(self, cfname=None): + """ + If a configuration file is given, the lens will be loaded and normalized. + Otherwise an empty lens is created. + """ + if cfname == None: + pass + else: + self.load(cfname) + self.updateMaxColumnSum() + + def load(self, cfname): + """ + Load and configure the lens from a config file + filename minR maxR ... in order of ascending rigidity + """ + dirname = path.dirname(cfname) + data = np.genfromtxt(cfname, dtype=[('fname','S1000'),('E0','f'),('E1','f')]) + for fname, lR0, lR1 in data: + M = loadLensPart(path.join(dirname, fname)) + self.checkLensPart(M) + self.lensParts.append(M) + self.lRmins.append(lR0) + self.lRmax = max(self.lRmax, lR1) + self.neutralLensPart = sparse.identity(healpy.nside2npix(self.nside), format='csc') + + def checkLensPart(self, M): + """ + Perform sanity checks and set HEALpix nside parameter. + """ + nrows, ncols = M.get_shape() + if nrows != ncols: + raise Exception("Matrix not square %i x %i"%(nrows, ncols)) + nside = healpy.npix2nside(nrows) + if self.nside == None: + self.nside = nside + elif self.nside != int(nside): + raise Exception("Matrix have different HEALpix schemes") + + def updateMaxColumnSum(self): + """ + Update the maximum column sum + """ + m = 0 + for M in self.lensParts: + m = max(m, maxColumnSum(M)) + self.maxColumnSum = m + + def getLensPart(self, E, Z=1): + """ + Return the matrix corresponding to a given energy E [EeV] and charge number Z + """ + if Z == 0: + return self.neutralLensPart + if len(self.lensParts) == 0: + raise Exception("Lens empty") + lR = np.log10(E / Z) + 18 + if (lR < self.lRmins[0]) or (lR > self.lRmax): + raise ValueError("Rigidity %f/%i EeV not covered"%(E, Z)) + i = bisect_left(self.lRmins, lR) - 1 + return self.lensParts[i] + + def transformPix(self, j, E, Z=1): + """ + Attempt to transform a pixel (ring scheme), given an energy E [EeV] and charge number Z. + Returns a pixel (ring scheme) if successful or None if not. + """ + M = self.getLensPart(E, Z) + cmp_val = np.random.rand() * self.maxColumnSum + sum_val = 0 + for i in range(M.indptr[j], M.indptr[j+1]): + sum_val += M.data[i] + if cmp_val < sum_val: + return M.indices[i] + return None + + def transformVec(self, x, y, z, E, Z=1): + """ + Attempt to transform a galactic direction, given an energy E [EeV] and charge number Z. + Returns a triple (x,y,z) if successful or None if not. + """ + j = healpy.vec2pix(self.nside, x, y, z) + i = self.transformPix(j, E, Z) + if i == None: + return None + v = healpytools.randVecInPix(self.nside, i) + return v + + def extragalacticVector(self, i, E, Z=1): + """ + Return the HEALpix vector of extragalactic directions + for a given observed pixel i, energy E [EeV] and charge number Z. + """ + M = self.getLensPart(E, Z) + row = M.getrow(i) + return np.array( row.todense() )[0] + + def observedVector(self, j, E, Z=1): + """ + Return the HEALpix vector of observed directions + for a given extragalactic pixel j, energy E [EeV] and charge number Z. + """ + M = self.getLensPart(E, Z) + col = M.getcol(j) + return np.array( col.transpose().todense() )[0] \ No newline at end of file From 2dcdc9db63886ccb56c5c23db548a043d1f046c8 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 6 Jan 2014 12:45:15 +0100 Subject: [PATCH 0368/1298] update description --- include/crpropa/GridTools.h | 8 ++++---- include/crpropa/magneticField/MagneticField.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/crpropa/GridTools.h b/include/crpropa/GridTools.h index 380af3459..316547c17 100644 --- a/include/crpropa/GridTools.h +++ b/include/crpropa/GridTools.h @@ -6,16 +6,16 @@ namespace crpropa { -/** Calculate the mean field vector */ +/** Evaluate the mean field vector of all grid points. */ Vector3f meanFieldVector(ref_ptr grid); -/** Calculate the mean field strength */ +/** Evaluate the mean field strength of all grid points. */ double meanFieldStrength(ref_ptr grid); -/** Calculate the RMS field strength */ +/** Evaluate the RMS field strength of all grid points. */ double rmsFieldStrength(ref_ptr grid); -/** Multiply a magnetic field grid by a factor. */ +/** Multiply all grid values by a given factor. */ void scaleGrid(ref_ptr grid, double a); #ifdef CRPROPA_HAVE_FFTW3F diff --git a/include/crpropa/magneticField/MagneticField.h b/include/crpropa/magneticField/MagneticField.h index f1447a44e..4eb98ce74 100644 --- a/include/crpropa/magneticField/MagneticField.h +++ b/include/crpropa/magneticField/MagneticField.h @@ -19,7 +19,7 @@ class MagneticField: public Referenced { /** @class PeriodicMagneticField - @brief Magnetic field decorator to implement periodic magnetic fields. + @brief Magnetic field decorator implementing periodic fields. */ class PeriodicMagneticField: public MagneticField { ref_ptr field; From 25f41cfdd37520eff98cbda08508d4181c60f4c0 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 6 Jan 2014 12:47:41 +0100 Subject: [PATCH 0369/1298] magnetic field in xml steering: - include reading from raw files - add whitespace trimming of filename --- src/XmlExecute.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index decb5d7cb..7610b9b25 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -371,15 +371,24 @@ void XmlExecute::loadGridMagneticField(xml_node &node) { string type = node.attribute("type").as_string(); if (type == "LSS-Grid") { + cout << " - Loading field from file" << endl; + string filetype = node.child("File").attribute("type").as_string(); cout << " - File type: " << filetype << endl; - if (filetype != "ASCII") - throw runtime_error("Only ASCII files supported"); - string fname = node.child_value("File"); - cout << " - Loading file (values in [G]): " << fname << endl; - loadGridFromTxt(field, fname, gauss); - } else { + string filename = kiss::trim(node.child_value("File")); + cout << " - File name: " << filename << endl; + + if (filetype == "ASCII") + loadGridFromTxt(field, filename, gauss); + else if (filetype == "RAW") + loadGrid(field, filename, gauss); + else + throw runtime_error("Unsupported file type"); + + } else if (type == "Kolmogoroff") { + cout << " - Creating random turbulent field" << endl; + double brms = childValue(node, "RMS_muG") * 1e-6 * gauss; cout << " - Brms: " << brms / nG << " nG" << endl; @@ -398,8 +407,10 @@ void XmlExecute::loadGridMagneticField(xml_node &node) { #endif #ifndef CRPROPA_HAVE_FFTW3F throw runtime_error( - "Turbulent field grid not available. Compile with FFTW3F."); + "Turbulent field not available: Compile with FFTW3F."); #endif + } else { + throw runtime_error("Unknown field type"); } magnetic_field = new MagneticFieldGrid(field); From 43188d9da7902d5d99c0b4fa5c0bb679769947ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Fri, 10 Jan 2014 11:11:32 +0100 Subject: [PATCH 0370/1298] fix remaining mpc -> crpropa renaming --- data-tools/NuclearDecay/nuclear_decay.py | 12 ++++++------ data-tools/NuclearMass/nuclear_mass.py | 10 +++++----- include/crpropa/ParticleMass.h | 2 +- include/crpropa/magneticField/QuimbyMagneticField.h | 4 ++-- .../crpropa/magneticField/TurbulentMagneticField.h | 6 +++--- src/ParticleMass.cpp | 2 +- src/main.cpp | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/data-tools/NuclearDecay/nuclear_decay.py b/data-tools/NuclearDecay/nuclear_decay.py index a4e6aba2a..24cdc52de 100644 --- a/data-tools/NuclearDecay/nuclear_decay.py +++ b/data-tools/NuclearDecay/nuclear_decay.py @@ -1,5 +1,5 @@ from numpy import * -import mpc +import crpropa # Script to preprocess the nuclear decay data table from the BNL NuDat2 database # See http://www.nndc.bnl.gov/nudat2/indx_sigma.jsp @@ -193,8 +193,8 @@ def isBetaMinus(self): print '\nBeta+ correction' print '-------------------------------------' a0 = 5.29177e-11 # Bohr radius [m] -a0 /= mpc.c_light * (mpc.h_planck / 2 / pi) / mpc.eplus # convert to [1/eV] -Qe = mpc.mass_electron * mpc.c_squared / mpc.eV # [eV] +a0 /= crpropa.c_light * (crpropa.h_planck / 2 / pi) / crpropa.eplus # convert to [1/eV] +Qe = crpropa.mass_electron * crpropa.c_squared / crpropa.eV # [eV] def I1(Q): x = Q / Qe @@ -206,9 +206,9 @@ def I1(Q): if not(d.isBetaPlus()): continue - m1 = mpc.getNucleusMass(mpc.getNucleusId(z+n, z)) - m2 = mpc.getNucleusMass(mpc.getNucleusId(z+n, z - 1)) - Q = (m1 - m2) * mpc.c_squared / mpc.eV + m1 = crpropa.getNucleusMass(crpropa.getNucleusId(z+n, z)) + m2 = crpropa.getNucleusMass(crpropa.getNucleusId(z+n, z - 1)) + Q = (m1 - m2) * crpropa.c_squared / crpropa.eV Qbeta = (Q - Qe) # [eV] Qec = (Q + Qe) # [eV] diff --git a/data-tools/NuclearMass/nuclear_mass.py b/data-tools/NuclearMass/nuclear_mass.py index 1da8c7f6f..1a959bf42 100644 --- a/data-tools/NuclearMass/nuclear_mass.py +++ b/data-tools/NuclearMass/nuclear_mass.py @@ -1,5 +1,5 @@ from pylab import * -import mpc +import crpropa # This script generates a table of nuclear mass for all combinations (Z,N) Z=0..26, N=0..30 # For measured atoms, the NIST data table is used. @@ -39,18 +39,18 @@ continue # skip isotopes with N > 30 # mass in [kg] minus mass of electrons - D[z, n] = float(relAtomicMass) * mpc.amu - z * mpc.mass_electron + D[z, n] = float(relAtomicMass) * crpropa.amu - z * crpropa.mass_electron ### add neutron and proton mass -D[1, 0] = mpc.mass_proton -D[0, 1] = mpc.mass_neutron +D[1, 0] = crpropa.mass_proton +D[0, 1] = crpropa.mass_neutron ### fill empty entries in table with A * amu - Z * m_e approximation for z in range(27): for n in range(31): if D[z, n] == 0: - D[z, n] = (z + n) * mpc.amu - z * mpc.mass_electron + D[z, n] = (z + n) * crpropa.amu - z * crpropa.mass_electron ## Write to file fout = open('nuclear_mass.txt', 'w') diff --git a/include/crpropa/ParticleMass.h b/include/crpropa/ParticleMass.h index b707f80d6..0fcb3d617 100644 --- a/include/crpropa/ParticleMass.h +++ b/include/crpropa/ParticleMass.h @@ -6,7 +6,7 @@ namespace crpropa { /** Return the nucleus mass by lookup from a table. * The masses are the atomic masses from the NIST database (http://www.nist.gov/pml/data/comp.cfm) minus electron masses, neglecting electron binding energies. * Unmeasured atomic masses are taken to be A * amu minus electron masses. - * The data table is generated by mpc/data-tools/NuclearMass/createNuclearMassTable. + * The data table is generated by data-tools/NuclearMass/createNuclearMassTable. */ double nucleusMass(int id); diff --git a/include/crpropa/magneticField/QuimbyMagneticField.h b/include/crpropa/magneticField/QuimbyMagneticField.h index 0b1a5bf3a..36e9d07f1 100644 --- a/include/crpropa/magneticField/QuimbyMagneticField.h +++ b/include/crpropa/magneticField/QuimbyMagneticField.h @@ -24,13 +24,13 @@ class QuimbyMagneticField: public MagneticField { quimby::Vector3f b, r = quimby::Vector3f(position.x, position.y, position.z); bool isGood = field->getField(r / kpc, b); if (!isGood) - std::cerr << "mpc::SPHMagneticField invalid position : " << position + std::cerr << "crpropa::SPHMagneticField invalid position : " << position << std::endl; return Vector3d(b.x, b.y, b.z) * gauss; } }; -} // namespace crpropaCRPROPA +} // namespace crpropa #endif // CRPROPA_HAVE_QUIMBY #endif // CRPROPA_QUIMBYMAGNETICFIELD_H diff --git a/include/crpropa/magneticField/TurbulentMagneticField.h b/include/crpropa/magneticField/TurbulentMagneticField.h index 0301d3e0f..38c2809e9 100644 --- a/include/crpropa/magneticField/TurbulentMagneticField.h +++ b/include/crpropa/magneticField/TurbulentMagneticField.h @@ -1,5 +1,5 @@ -#ifndef TURBULENTMAGNETICFIELD_H -#define TURBULENTMAGNETICFIELD_H +#ifndef CRPROPA_TURBULENTMAGNETICFIELD_H +#define CRPROPA_TURBULENTMAGNETICFIELD_H #include "crpropa/magneticField/MagneticField.h" #include "crpropa/Random.h" @@ -73,6 +73,6 @@ class TurbulentMagneticField: public MagneticField { Random random; /**< Random number generator instance */ }; -} // mpc +} // crpropa #endif // TURBULENTMAGNETICFIELD_H diff --git a/src/ParticleMass.cpp b/src/ParticleMass.cpp index 3be2ba77c..568701fb5 100644 --- a/src/ParticleMass.cpp +++ b/src/ParticleMass.cpp @@ -19,7 +19,7 @@ struct NuclearMassTable { std::ifstream infile(filename.c_str()); if (!infile.good()) - throw std::runtime_error("mpc: could not open file " + filename); + throw std::runtime_error("crpropa: could not open file " + filename); int Z, N; double mass; diff --git a/src/main.cpp b/src/main.cpp index 72f88cfce..eefd249fe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,7 +5,7 @@ int main(int argc, char **argv) { if (argc < 2) { - std::cout << "mpc-run " << std::endl; + std::cout << "crpropa-run " << std::endl; return 1; } From 98751cf47c091a0da7572b62252b35fa749d020b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Fri, 10 Jan 2014 12:20:44 +0100 Subject: [PATCH 0371/1298] add EleCa photon propagation code --- CMakeLists.txt | 3 + include/crpropa/module/PhotonEleCa.h | 11 +- libs/EleCa/EleCa/Common.h | 40 ++ libs/EleCa/EleCa/Constants.h | 81 +++ libs/EleCa/EleCa/EnergyLoss.h | 571 +++++++++++++++++++++ libs/EleCa/EleCa/Particle.h | 128 +++++ libs/EleCa/EleCa/Process.h | 270 ++++++++++ libs/EleCa/EleCa/Propagation.h | 725 +++++++++++++++++++++++++++ libs/EleCa/EleCa/XLoss_CBR.h | 315 ++++++++++++ src/module/PhotonEleCa.cpp | 34 +- 10 files changed, 2175 insertions(+), 3 deletions(-) create mode 100644 libs/EleCa/EleCa/Common.h create mode 100644 libs/EleCa/EleCa/Constants.h create mode 100644 libs/EleCa/EleCa/EnergyLoss.h create mode 100644 libs/EleCa/EleCa/Particle.h create mode 100644 libs/EleCa/EleCa/Process.h create mode 100644 libs/EleCa/EleCa/Propagation.h create mode 100644 libs/EleCa/EleCa/XLoss_CBR.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9280b9022..175b835c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,9 @@ add_subdirectory(libs/dint) list(APPEND CRPROPA_EXTRA_LIBRARIES dint) list(APPEND CRPROPA_EXTRA_INCLUDES libs/dint/include) +# EleCa (provided) +list(APPEND CRPROPA_EXTRA_INCLUDES libs/EleCa) + # OpenMP (optional for shared memory multiprocessing) option(ENABLE_OPENMP "OpenMP for multithreading" ON) if(ENABLE_OPENMP) diff --git a/include/crpropa/module/PhotonEleCa.h b/include/crpropa/module/PhotonEleCa.h index c364716e8..882221edd 100644 --- a/include/crpropa/module/PhotonEleCa.h +++ b/include/crpropa/module/PhotonEleCa.h @@ -4,14 +4,21 @@ #include "crpropa/Module.h" #include "crpropa/magneticField/MagneticField.h" +#include + +// forward declaration +namespace eleca { +class Propagation; +} + namespace crpropa { class PhotonEleCa: public Module { private: - ref_ptr field; + std::auto_ptr propagation; public: - PhotonEleCa(ref_ptr field); + PhotonEleCa(); ~PhotonEleCa(); void process(Candidate *candidate) const; std::string getDescription() const; diff --git a/libs/EleCa/EleCa/Common.h b/libs/EleCa/EleCa/Common.h new file mode 100644 index 000000000..7f3857248 --- /dev/null +++ b/libs/EleCa/EleCa/Common.h @@ -0,0 +1,40 @@ +#ifndef ELECA_COMMON_H_ +#define ELECA_COMMON_H_ + +#include "Constants.h" +#include "crpropa/Random.h" + +#include +#include + +namespace eleca { + +double z2Mpc(double z) { + if (z < 0.4) { + return ((double) C_speed / 1000. / H0) * z; + } else { + // AV Uryson, Physics Particles and Nuclei, 2006, Vol. 37, No. 3, pp. 347 67 + // Assuming flat-matter-dominated cosmology. Error is negligible + return ((double) C_speed / 1000. / H0) * (2. / 3.) + * (1 - pow(1. + z, -1.5)); + } +} + +double Mpc2z(double D) { + if (D < 1700.) { + return (double) D / ((double) C_speed / 1000. / H0); + } else { + // AV Uryson, Physics Particles and Nuclei, 2006, Vol. 37, No. 3, pp. 347 67 + // Assuming flat-matter-dominated cosmology. Error is negligible + return pow(1 - (double) D / ((2. / 3.) * (double) C_speed / 1000. / H0), + -2. / 3.) - 1; + } +} + +double Uniform(double min, double max) { + return crpropa::Random::instance().randUniform(min, max); +} + +} // namespace eleca + +#endif // ELECA_COMMON_H_ diff --git a/libs/EleCa/EleCa/Constants.h b/libs/EleCa/EleCa/Constants.h new file mode 100644 index 000000000..7e40b5db4 --- /dev/null +++ b/libs/EleCa/EleCa/Constants.h @@ -0,0 +1,81 @@ +#ifndef ELECA_CONSTANTS_H_ +#define ELECA_CONSTANTS_H_ + +#include + +namespace eleca { + +static const double cPI = M_PI; + +static const int POINTS_VERY_FEW = 100; + +static const double M2MPC = 3.240779e-17 / 1.0e6; +static const double KM2MPC = 3.240779e-20; +static const double S2YR = 3.168808781403e-08; +static const double H0 = 70.4; +static const double H0y = H0 * (double) KM2MPC / S2YR; // H0 per years +static const double OC = 0.227; // Dark matter density +static const double OB = 0.0456; // Baryon density +static const double OM = OB + OC; // Matter density +static const double OL = 0.728; // Dark energy density + +static const double K_CBR = 1.318684673251832e+13; // =1/pi**2/hbarc**3 [eV^-3 cm^-3] +static const double eV2J = 1.602176487e-19; // from eV to J +static const double ElectronMass = 0.510998918e6; // [eV/c^2] +static const double K_boltz = 8.617342294984e-5; // [eV/K ] Boltzman constant +static const double C_speed = 299792458; // [m/s] speed of light +static const double SigmaThompson = 6.6524e-25; + +static const double T_CMB = 2.725; // [K] // evolution 2.725*(1-z) 1012.3164 +static const double T_COB = 5270; // [K] // Visible [380 - 760] nm. Scelgo 550 +static const double T_CIB = 1.45e+02; // [k] Middle IR 5 to (25-40) µm according to Nasa. scelgo 20e-6 m +static const double T_CRB = 3e-03; // [k] ~ cm - 10m. scelgo ~1 m + +static const double CMB_en = K_boltz * T_CMB; //2.348e-4; // [eV] +static const double CRB_en = K_boltz * T_CRB; +static const double COB_en = K_boltz * T_COB; +static const double CIB_en = K_boltz * T_CIB; +static const double CIOB_en = CIB_en + COB_en; // [eV] + +static const double h_Planck = 4.135667e-15; // [eV s]// +static const double hcut_Planck = h_Planck / 2 / cPI; // [eV s] hcut = h/2Pi [Js] +static const double LambdaCompton = hcut_Planck / (ElectronMass / C_speed); + +static const double eps_ph_inf_urb = 4.1e-12; // [eV] +static const double eps_ph_inf_cmb = 0.825e-6; // [eV] +static const double eps_ph_inf_cib = 2e-3; // [eV] +static const double eps_ph_inf_cob = 5e-2; // [eV] +static const double eps_ph_inf_ciob = 2e-3; // [eV] + +static const double eps_ph_sup_urb = eps_ph_inf_cmb; //4e-5; // [eV] +static const double eps_ph_sup_cmb = eps_ph_inf_cob; // [eV] +static const double eps_ph_sup_cob = 9.9; // [eV] +static const double eps_ph_sup_cib = 0.8; // [eV] +static const double eps_ph_sup_ciob = 9.9; // [eV] + +static const double eps_ph_sup_global = eps_ph_sup_cob; // [eV] *global +static const double eps_ph_inf_global = eps_ph_inf_urb; // [eV] *global + +static const int NsecG = 0; + +static const double z0ph = 0; +static const double E0ph = 0; + +static const int particle_type = 0; +static const double EnergyCM = 0; +static const double GammaEnergy = 0; +static const double BackGamma = 0; +static const double PPxsection = 0; +static const double DPPxsection = 0; +static const double TPPxsection = 0; +static const double ICSxsection = 0; +static const double PPlength = 0; +static const double DPPlength = 0; +static const double TPPlength = 0; +static const double ICSlength = 0; +static const double n_eps2 = 0; +static const double eps2 = 0; + +} // namespace eleca + +#endif // ELECA_CONSTANTS_H_ diff --git a/libs/EleCa/EleCa/EnergyLoss.h b/libs/EleCa/EleCa/EnergyLoss.h new file mode 100644 index 000000000..1dd708c4e --- /dev/null +++ b/libs/EleCa/EleCa/EnergyLoss.h @@ -0,0 +1,571 @@ +#ifndef ELECA_ENERGY_LOSS_H_ +#define ELECA_ENERGY_LOSS_H_ + +#include "Common.h" + +#include + +namespace eleca { + +static const int MC_SAMPLING = 1000; + +double dTdZ(double z) { + // See High Energy Cosmic Rays, Todor Stanev, Pag. 232 (2009) + return -1. + / ((1 + z) * H0y + * sqrt( + pow(1. + z, 3.) * OM + OL + + (1 - OM - OL) * pow(1. + z, 2.))); +} + +double betaRsh(double z) { + // Energy loss term due to cosmological redshift + return H0y + * sqrt(pow(1. + z, 3.) * OM + OL + (1 - OM - OL) * pow(1. + z, 2.)); +} + +double fLossAdiabatic(double E, double z) { + return -dTdZ(z) * betaRsh(z) * E; +} + +double AdiabaticELoss(double z0, double z, double E0) { + return E0 * (double) (1. + z) / (1. + z0); +} + +// ################################################## +// # Synchrotron rate of Energy loss averaged over angles +// ################################################## +// for an ensemble of electrons that are scattered randomly in all directions: +double MeanRateSynchrotronLoss(double E, double B) { + double dEdt = 0; + if (B > 0) + dEdt = 3.79e-6 * pow(E / 1e9 * B, 2) * 1e9 / E; + + return dEdt; +} + +// #################################### +// # Synchrotron Energy loss +// #################################### + +double ESynchrotronAdiabaticLoss(double z, double E, double B) { + double dEdt = MeanRateSynchrotronLoss(E, B); + + return E * (-dTdZ(z) * (dEdt + betaRsh(z))); +} + +static const int RK_ORDER = 6; +static double gRKa[RK_ORDER + 1]; +static double gRKc[RK_ORDER + 1]; +static double gRKcs[RK_ORDER + 1]; +static double gRKb[RK_ORDER + 1][RK_ORDER]; +static bool gRKInitialized = false; + +void InitRK() { + if (gRKInitialized) + return; + + // Current Runge-Kutta method for solving ODE + gRKa[0] = 0; + gRKa[1] = 0; + gRKa[2] = 1. / 5.; + gRKa[3] = 3. / 10.; + gRKa[4] = 3. / 5.; + gRKa[5] = 1.; + gRKa[6] = 7. / 8.; + + for (int i = 0; i < RK_ORDER; i++) { + for (int j = 0; j < RK_ORDER + 1; j++) + gRKb[i][j] = 0.; + } + + gRKb[2][1] = 1. / 5.; + gRKb[3][1] = 3. / 40.; + gRKb[3][2] = 9. / 40.; + gRKb[4][1] = 3. / 10.; + gRKb[4][2] = -9. / 10.; + gRKb[4][3] = 6. / 5.; + gRKb[5][1] = -11. / 54.; + gRKb[5][2] = 5. / 2.; + gRKb[5][3] = -70. / 27.; + gRKb[5][4] = 35. / 27.; + gRKb[6][1] = 1631. / 55296.; + gRKb[6][2] = 175. / 512.; + gRKb[6][3] = 575. / 13824.; + gRKb[6][4] = 44275. / 110592.; + gRKb[6][5] = 253. / 4096.; + + gRKc[0] = 0.; + gRKc[1] = 37. / 378.; + gRKc[2] = 0.; + gRKc[3] = 250. / 621.; + gRKc[4] = 125. / 594.; + gRKc[5] = 0.; + gRKc[6] = 512. / 1771.; + + gRKcs[0] = 0.; + gRKcs[1] = 2825. / 27648.; + gRKcs[2] = 0.; + gRKcs[3] = 18575. / 48384.; + gRKcs[4] = 13525. / 55296.; + gRKcs[5] = 277. / 14336.; + gRKcs[6] = 1. / 4.; + + gRKInitialized = true; +} + +//=================================== + +double EnergyLoss1D(double Energy, double z0, double zfin, double B) { + + double zStep = 2.5e-5; + +#pragma omp critical + { + InitRK(); + } + double k1, k2, k3, k4, k5, k6; + + bool FLAG_PROPAG = 1; + + while (z0 > zfin && FLAG_PROPAG) { + + k1 = -zStep * ESynchrotronAdiabaticLoss(z0 - zStep, Energy, B); + k2 = -zStep + * ESynchrotronAdiabaticLoss(z0 - zStep * gRKa[2], + Energy + k1 * gRKb[2][1], B); + + k3 = -zStep + * ESynchrotronAdiabaticLoss(z0 - zStep * gRKa[3], + Energy + k1 * gRKb[3][1] + k2 * gRKb[3][2], B); + k4 = -zStep + * ESynchrotronAdiabaticLoss(z0 - zStep * gRKa[4], + Energy + k1 * gRKb[4][1] + k2 * gRKb[4][2] + + k3 * gRKb[4][3], B); + k5 = -zStep + * ESynchrotronAdiabaticLoss(z0 - zStep * gRKa[5], + Energy + k1 * gRKb[5][1] + k2 * gRKb[5][2] + + k3 * gRKb[5][3] + k4 * gRKb[5][4], B); + k6 = -zStep + * ESynchrotronAdiabaticLoss(z0 - zStep * gRKa[6], + Energy + k1 * gRKb[6][2] + k2 * gRKb[6][2] + + k3 * gRKb[6][3] + k4 * gRKb[6][4] + + k5 * gRKb[6][5], B); + + Energy = Energy + + (k1 * gRKc[1] + k2 * gRKc[2] + k3 * gRKc[3] + k4 * gRKc[4] + + k5 * gRKc[5] + k6 * gRKc[6]); + + z0 -= zStep; + + if (fabs(z0) < 1e-8 || z0 < 0) { + z0 = 0.; + FLAG_PROPAG = 0; + } + if (fabs(z0 - zfin) < 1e-8 || z0 < zfin) + z0 = zfin; + + if (Energy < 1e9) { + FLAG_PROPAG = 0; + } + + if (isnan(Energy)) + return 0; + } + + return Energy; +} + +double dSigmadE_ICS(double Ee, double Eer, double s, double theta) { + /*! + Differential cross-section for inverse Compton scattering. from lee, eq. 23 + */ + + double beta = (s - ElectronMass * ElectronMass) + / (s + ElectronMass * ElectronMass); + + if (Eer / Ee < (1 - beta) / (1 + beta) || Eer / Ee > 1) { + std::cerr << "ERROR, Energy outside limits for ICS [Lee96]! " + << std::endl; + return 0.; + } else { + double q = ((1 - beta) / beta) * (1 - Ee / Eer); + double A = Eer / Ee + Ee / Eer; + double k = (3.0 / 8.0) * (SigmaThompson * ElectronMass * ElectronMass) + / (s * Ee); + double dsigmadE = k * ((1 + beta) / beta) * (A + 2 * q + q * q); + + return dsigmadE; + } +} + +double dSigmadE_PP(double Ee, double E0, double eps, double theta) { + /*! + Differential cross-section for pair production. + */ + double s = ElectronMass * ElectronMass + 2 * eps * E0 * (1 - cos(theta)); + double beta = sqrt(1 - 4 * ElectronMass * ElectronMass / s); + + if (Ee / E0 <= 0.5 * (1 - beta) || Ee / E0 >= 0.5 * (1 + beta)) { + std::cerr << "ERROR, Energy outside limits for PP [Lee96]! " + << std::endl; + return 0.; + } else { + double q = E0 - Ee; + double k = (3.0 / 4.0) * (SigmaThompson * ElectronMass * ElectronMass) + / (s * E0); + double A = Ee / q + q / Ee; + double B = E0 * (1 - beta * beta) * (1. / Ee + 1. / q); + double C = -((1 - beta * beta) * (1 - beta * beta) * E0 * E0 / 4.0) + * pow(1. / Ee + 1. / q, 2); + + double dsigmadE = k * (A + B + C); + + return dsigmadE; + } +} + +double ExtractPPSecondariesEnergy(Particle &pi, Particle &pt) { + /*! + Input: incident gamma Energy E0, background photon energy eps, + incidence angle theta. + Returns the energy of the produced e+ (e-) + */ + double E0 = pi.GetEnergy(); + double eps = pt.GetEnergy(); + double beta = pi.GetBeta(); + double theta = cPI; + double s2 = ElectronMass * ElectronMass + + 2 * eps * E0 * (1 - (beta) * cos(theta)); + + bool failed = 1; + + double MC_Sampling_Hist[MC_SAMPLING][3]; + for (int i = 0; i < MC_SAMPLING; i++) { + for (int j = 0; j < 3; j++) + MC_Sampling_Hist[i][j] = 0.; + } + + double f = pow((double) (1 + beta) / (1 - beta), + (double) 1. / (double) MC_SAMPLING); + int cnt = 0; + double NormFactor = 0; + + for (double Ee = f * 0.5 * (1 - beta) * E0; Ee < 0.5 * (1 + beta) * E0; + Ee *= f) { + MC_Sampling_Hist[cnt][0] = Ee; + MC_Sampling_Hist[cnt][1] = dSigmadE_PP(Ee, E0, eps, theta); + + NormFactor += MC_Sampling_Hist[cnt][1]; + MC_Sampling_Hist[cnt][2] = NormFactor; + + if (MC_Sampling_Hist[cnt][1] > 0.) { + cnt++; + } else { + break; + } + } + + NormFactor = (double) 1. / (double) NormFactor; + + for (int i = 0; i < cnt; i++) + MC_Sampling_Hist[i][2] *= NormFactor; + + double rnd; + double Ee = 0; + int k = 0; + while (failed) { + k++; + + rnd = Uniform(0, 1); + Ee = 0; + for (int i = 0; i < cnt - 1; i++) { + if (MC_Sampling_Hist[i][2] <= rnd <= MC_Sampling_Hist[i + 1][2]) { + Ee = MC_Sampling_Hist[i][0]; + failed = 0; + break; + } + if (failed) + std::cout << "cnt: " << cnt << " failed " << k << std::endl; + } + + } //end while + + if (Uniform(0, 1) < 0.5) + return Ee; + else + return E0 - Ee; +} + +double ExtractPPSecondariesEnergy(Process &proc) { + /*! + Input: incident gamma Energy E0, background photon energy eps, + incidence angle theta. + Returns the energy of the produced e+ (e-) + */ + + double E0 = proc.GetIncidentParticle().GetEnergy(); + double s = proc.GetCMEnergy(); + double eps = proc.GetTargetParticle().GetEnergy(); + double theta = M_PI; + + double beta = sqrt(1. - 4.0 * ElectronMass * ElectronMass / s); + double s2 = ElectronMass * ElectronMass + + 2 * eps * E0 * (1 - (beta) * cos(theta)); + + bool failed = 1; + + double MC_Sampling_Hist[MC_SAMPLING][3]; + for (int i = 0; i < MC_SAMPLING; i++) { + for (int j = 0; j < 3; j++) + MC_Sampling_Hist[i][j] = 0.; + } + + double f = pow((double) (1 + beta) / (1 - beta), + (double) 1. / (double) MC_SAMPLING); + int cnt = 0; + double NormFactor = 0; + + for (double Ee = f * 0.5 * (1 - beta) * E0; Ee < 0.5 * (1 + beta) * E0; + Ee *= f) { + MC_Sampling_Hist[cnt][0] = Ee; + MC_Sampling_Hist[cnt][1] = dSigmadE_PP(Ee, E0, eps, theta); + NormFactor += MC_Sampling_Hist[cnt][1]; + MC_Sampling_Hist[cnt][2] = NormFactor; + + if (MC_Sampling_Hist[cnt][1] > 0.) { + cnt++; + } else { + break; + } + } + + NormFactor = (double) 1. / (double) NormFactor; + + for (int i = 0; i < cnt; i++) + MC_Sampling_Hist[i][2] *= NormFactor; + + double rnd; + double Ee = 0; + int k = 0; + + while (failed) { + rnd = Uniform(0., 1.0); + Ee = 0; + k++; + double min = 1e6; + double max = -1; + + for (int i = 0; i < cnt - 1; i++) { + + if (MC_Sampling_Hist[i][2] < min) + min = MC_Sampling_Hist[i][2]; + if (MC_Sampling_Hist[i + 1][2] > max) + max = MC_Sampling_Hist[i + 1][2]; + + if (MC_Sampling_Hist[i][2] <= rnd <= MC_Sampling_Hist[i + 1][2]) { + Ee = MC_Sampling_Hist[i][0]; + failed = 0; + break; + } + } + if (failed) { + std::cout << "failed in extractPP " << Ee << " " << beta << " * s: " + << s << " E: " << E0 << " eps : " << eps << " me: " + << ElectronMass * ElectronMass / E0 << " ) " << " cnt : " + << cnt << std::endl; + std::cout << " Limits " << proc.GetMin() << std::endl; + if (cnt == 0) + exit(0); + } + + } //end while + + if (Uniform(0, 1.0) < 0.5) + return Ee; + else + return E0 - Ee; +} + +double ExtractICSSecondariesEnergy(Particle &pi, Particle &pt) { + /*! + Input: incident electron energy Ee, background photon energy eps, + incidence angle theta. + Returns the energy of the recoiled e+ (e-) + */ + if (abs(pi.GetType()) != 11) { + std::cerr << "something wrong in type ExtractICSEnergy " << std::endl; + return 0.; + } + + double Ee = pi.GetEnergy(); + double eps = pt.GetEnergy(); + double theta = M_PI; + double s = 2 * Ee * eps * (1 - pi.GetBeta() * cos(cPI)) + + pi.GetMass() * pi.GetMass(); + double beta = (s - ElectronMass * ElectronMass) + / (s + ElectronMass * ElectronMass); + bool failed = 1; + + double MC_Sampling_Hist[MC_SAMPLING][3]; + for (int i = 0; i < MC_SAMPLING; i++) { + for (int j = 0; j < 3; j++) + MC_Sampling_Hist[i][j] = 0.; + } + + double f = pow((double) (1 + beta) / (1 - beta), (double) 1. / MC_SAMPLING); + int cnt = 0; + double NormFactor = 0; + + for (double Eer = f * ((1 - beta) / (1 + beta)) * Ee; Eer <= Ee; Eer *= f) { + MC_Sampling_Hist[cnt][0] = Eer; + MC_Sampling_Hist[cnt][1] = dSigmadE_ICS(Ee, Eer, s, theta); + + NormFactor += MC_Sampling_Hist[cnt][1]; + MC_Sampling_Hist[cnt][2] = NormFactor; + + if (MC_Sampling_Hist[cnt][1] > 0.) { + cnt++; + } else { + break; + } + } + + NormFactor = (double) 1. / (double) NormFactor; + + for (int i = 0; i < cnt; i++) + MC_Sampling_Hist[i][2] *= NormFactor; + + double rnd = 0; + double Eer = 0; + + while (failed) { + rnd = Uniform(0, 1); + Eer = 0; + for (int i = 0; i < cnt - 1; i++) { + if (MC_Sampling_Hist[i][2] <= rnd <= MC_Sampling_Hist[i + 1][2]) { + Eer = MC_Sampling_Hist[i][0]; + failed = 0; + break; + } + } + + } + return Eer; +} + +double ExtractICSSecondariesEnergy(Process &proc) { + /*! + Input: incident electron energy Ee, background photon energy eps, + incidence angle theta. + Returns the energy of the recoiled e+ (e-) + */ + double Ee = proc.GetIncidentParticle().GetEnergy(); + double s = proc.GetCMEnergy(); + double theta = proc.GetInteractionAngle(); + double beta = (s - ElectronMass * ElectronMass) + / (s + ElectronMass * ElectronMass); + bool failed = 1; + + // reInitialization to zero.. + double MC_Sampling_Hist[MC_SAMPLING][3]; + for (int i = 0; i < MC_SAMPLING; i++) { + for (int j = 0; j < 3; j++) + MC_Sampling_Hist[i][j] = 0.; + } + + double f = pow((double) (1 + beta) / (1 - beta), (double) 1. / MC_SAMPLING); + int cnt = 0; + double NormFactor = 0; + + for (double Eer = f * ((1 - beta) / (1 + beta)) * Ee; Eer <= Ee; Eer *= f) { + MC_Sampling_Hist[cnt][0] = Eer; + MC_Sampling_Hist[cnt][1] = dSigmadE_ICS(Ee, Eer, s, theta); + + NormFactor += MC_Sampling_Hist[cnt][1]; + MC_Sampling_Hist[cnt][2] = NormFactor; + + if (MC_Sampling_Hist[cnt][1] > 0.) { + cnt++; + } else { + break; + } + } + + NormFactor = (double) 1. / (double) NormFactor; + + for (int i = 0; i < cnt; i++) + MC_Sampling_Hist[i][2] *= NormFactor; + + double rnd = 0; + double Eer = 0; + + while (failed) { + rnd = Uniform(0, 1.0); + Eer = 0; + for (int i = 0; i < cnt - 1; i++) { + if (MC_Sampling_Hist[i][2] <= rnd <= MC_Sampling_Hist[i + 1][2]) { + Eer = MC_Sampling_Hist[i][0]; + failed = 0; + break; + } + } + + } + return Eer; +} + +double ExtractTPPSecondariesEnergy(Particle &pi, Particle &pt) { + /* approximation based on A. Mastichiadis et al., + Astroph. Journ. 300:178-189 (1986), eq. 30. + This approx is valid only for alpha >=100 + where alpha = p0*eps*costheta - E0*eps; + for our purposes, me << E0 --> p0~ E0 --> + alpha = E0*eps*(costheta - 1) >= 100; + */ + + double E0 = pi.GetEnergy(); + double eps = pt.GetEnergy(); + double s = 2 * E0 * eps * (1 - pi.GetBeta() * cos(M_PI)) + + pi.GetMass() * pi.GetMass(); + double Epp = 5.7e-1 * pow(eps, -0.56) * pow(E0, 0.44); + double Epp2 = E0 + * (1 - 1.768 * pow(s / ElectronMass / ElectronMass, -3.0 / 4.0)) + / 2.0; + //return the energy of each e+/e- in the pair. + return Epp; + +} + +double ExtractTPPSecondariesEnergy(Process &proc) { + /* approximation based on A. Mastichiadis et al., + Astroph. Journ. 300:178-189 (1986), eq. 30. + This approx is valid only for alpha >=100 + where alpha = p0*eps*costheta - E0*eps; + for our purposes, me << E0 --> p0~ E0 --> + alpha = E0*eps*(costheta - 1) >= 100; + */ + + double E0 = proc.GetIncidentParticle().GetEnergy(); + double eps = proc.GetTargetParticle().GetEnergy(); + double Epp = 5.7e-1 * pow(eps, -0.56) * pow(E0, 0.44); + double s = proc.GetCMEnergy(); + double Epp2 = E0 + * (1 - 1.768 * pow(s / ElectronMass / ElectronMass, -3.0 / 4.0)) + / 2.0; + return Epp; +} + +double ExtractDPPSecondariesEnergy(double E0) { + /* + we use the same assumption of lee (i.e., all the energy goes equaly shared between only 1 couple of e+e-. + In DPPpaper has been shown that this approximation is valid within -1.5% + */ + if (E0 == 0) + std::cout << "error in extracting DPP: can not be =0 " << std::endl; + return (double) E0 / 2.0; +} + +} // namespace eleca + +#endif // ELECA_ENERGY_LOSS_H_ diff --git a/libs/EleCa/EleCa/Particle.h b/libs/EleCa/EleCa/Particle.h new file mode 100644 index 000000000..162d4a342 --- /dev/null +++ b/libs/EleCa/EleCa/Particle.h @@ -0,0 +1,128 @@ +#ifndef ELECA_PARTICLE_H_ +#define ELECA_PARTICLE_H_ + +#include "Constants.h" + +namespace eleca { + +class Particle { +private: + int ftype; + double fE0ph; + double fz0ph; + double fbeta; + double fmass; + bool fIsGood; + int fwi; + double fB; + +public: + Particle(); + Particle(int _ft, double _fE, double fz); +// Particle(Candidate candidate); + ~ Particle() { + } + + bool IsGood() { + double zmax_prop0 = 0.91425; + double zmax_prop1 = -0.101717; + double zmax_prop2 = 0.002855; + double Eloc = log10(fE0ph); + if (Eloc < 18) + Eloc = 18; + if (fz0ph > zmax_prop0 + zmax_prop1 * Eloc + zmax_prop2 * Eloc * Eloc) + return 0; + return 1; + } + + int GetType() { + return ftype; + } + + void SetType(int _ft) { + ftype = _ft; + } + + int GetWeigth() { + return fwi; + } + + void SetWeigth(int _wi) { + fwi = _wi; + } + + double GetEnergy() { + return fE0ph; + } + + void SetEnergy(double _fE) { + fE0ph = _fE; + SetBetaAndMass(); + } + + double Getz() { + return fz0ph; + } + + void Setz(double _fz) { + fz0ph = _fz; + } + + double GetMass() { + return fmass; + } + + double GetBeta() { + return fbeta; + } + + bool GetStatus() { + fIsGood = IsGood(); + return fIsGood; + } + + void SetBetaAndMass() { + if (ftype == 22) { + fbeta = 1.0; + fmass = 0; + } + if (abs(ftype) == 11) { + fmass = ElectronMass; + fbeta = (double) sqrt(1 - fmass * fmass / (fE0ph * fE0ph)); + + } + } + + void SetB(double B) { + fB = B; + } + double GetB() { + return fB; + } + +}; + +Particle::Particle(int _ft, double _fE, double _fz) { + ftype = _ft; + fE0ph = _fE; + fz0ph = _fz; + SetBetaAndMass(); + fIsGood = IsGood(); + fB = 0; + fwi = 1; +} + +Particle::Particle() { + ftype = 22; + fE0ph = 0; + fz0ph = 0; + fmass = 0; + fbeta = 0; + fIsGood = 0; + fB = 0; + fwi = 1; +} + +} // namespace eleca + +#endif // ELECA_PARTICLE_H_ diff --git a/libs/EleCa/EleCa/Process.h b/libs/EleCa/EleCa/Process.h new file mode 100644 index 000000000..06a03a649 --- /dev/null +++ b/libs/EleCa/EleCa/Process.h @@ -0,0 +1,270 @@ +#ifndef ELECA_PROCESS_H_ +#define ELECA_PROCESS_H_ + +#include "Particle.h" + +#include +#include + +namespace eleca { + +class Process { + +public: + + std::string fname; + double flambda; + double fsmin; + double fsmax; + double fCMEnergy; + double fInteractionAngle; + double feps_inf; + double feps_sup; + Particle fPi; + Particle fPt; + + std::string fback; + double fbackdensity; + + Process(); + Process(Process&); + Process(Particle&, Particle&); + Process(Particle&, Particle&, std::string); + + ~Process(); + + void SetName(std::string nm) { + fname = nm; + } + std::string &GetName() { + return fname; + } + + void SetInteractionAngle(double a) { + fInteractionAngle = a; + } + double GetInteractionAngle() { + return fInteractionAngle; + } + + void SetLambda(double le) { + flambda = le; + } + double GetLambda() { + return flambda; + } + + void SetLimits(double smin, double smax) { + fsmin = smin; + fsmax = smax; + } + void SetLimits(Particle& p1, std::string nameproc); + void SetLimits() { + SetLimits(fPi, fname); + } + + void SetMax(double smax) { + fsmax = smax; + } + void SetMin(double smin) { + fsmin = smin; + } + double GetMin() { + return fsmin; + } + double GetMax() { + return fsmax; + } + + void SetCMEnergy(double s) { + fCMEnergy = s; + } + + void SetCMEnergy(Particle p1, Particle pb) { + fCMEnergy = 2 * p1.GetEnergy() * pb.GetEnergy() + * (1 - p1.GetBeta() * cos(fInteractionAngle)) + + p1.GetMass() * p1.GetMass() + pb.GetMass() * pb.GetMass(); + } + + void SetCMEnergy() { + fCMEnergy = 2 * fPi.GetEnergy() * fPt.GetEnergy() + * (1 - fPi.GetBeta() * cos(fInteractionAngle)) + + fPi.GetMass() * fPi.GetMass() + fPt.GetMass() * fPt.GetMass(); + + } + + double GetCMEnergy() { + return fCMEnergy; + } + + void SetIncidentParticle(Particle& p1) { + fPi = p1; + SetLimits(); + } + void SetTargetParticle(Particle& p1) { + fPt = p1; + SetLimits(); + } + + Particle &GetIncidentParticle() { + return fPi; + } + Particle &GetTargetParticle() { + return fPt; + } + + std::string GetBackground() { + return fback; + } + void SetBackground(std::string BackRad); + +private: + +}; + +//-------------- explicit definitions + +Process::Process() { + fname = ""; + SetLimits(0.0, 1.0e23); + flambda = 0; + fCMEnergy = 0; + fInteractionAngle = cPI; + fback = "ALL"; + fbackdensity = 0; + feps_inf = eps_ph_inf_global; + feps_sup = eps_ph_sup_global; +} + +Process::Process(Particle& p1, Particle& p2) { + fPi = p1; + fPt = p2; + if (p1.GetType() == 22) + fname = "PP"; + else if (abs(p1.GetType()) == 11) { + std::cerr << "NB: by default process set to ICS" << std::endl; + fname = "ICS"; + } else + fname = "NONE"; + SetCMEnergy(p1, p2); + flambda = 0; + fInteractionAngle = cPI; + fback = "ALL"; + SetLimits(p1, fname); + fbackdensity = 0; + feps_inf = eps_ph_inf_global; + feps_sup = eps_ph_sup_global; +} + +Process::Process(Particle& p1, Particle& p2, std::string name) { + fname = name; + SetCMEnergy(p1, p2); + flambda = 0; + fInteractionAngle = cPI; + fPi = p1; + fPt = p2; + fback = "ALL"; + SetLimits(p1, fname); + fbackdensity = 0; + feps_inf = eps_ph_inf_global; + feps_sup = eps_ph_sup_global; +} + +Process::Process(Process& proc2) { + fname = proc2.GetName(); + SetLimits(proc2.GetMin(), proc2.GetMax()); + fCMEnergy = proc2.GetCMEnergy(); + fInteractionAngle = proc2.GetInteractionAngle(); + fPi = proc2.GetIncidentParticle(); + fPt = proc2.GetTargetParticle(); + fback = proc2.GetBackground(); + fbackdensity = 0; + feps_inf = eps_ph_inf_global; + feps_sup = eps_ph_sup_global; +} + +Process::~Process() { +} + +//----------- + +void Process::SetBackground(std::string BackRad) { + + fback = BackRad; + + double eps_min = eps_ph_inf_global; + double eps_max = eps_ph_sup_global; + + if (BackRad == "CMB") { + eps_min = eps_ph_inf_cmb; + eps_max = eps_ph_sup_cmb; + std::cout << "eps range setted to " << eps_min << " , " << eps_max + << std::endl; + } else if (BackRad == "COB") { + eps_min = eps_ph_inf_cob; + eps_max = eps_ph_sup_cob; + std::cout << "eps range setted to " << eps_min << " , " << eps_max + << std::endl; + } else if (BackRad == "CIB") { + eps_min = eps_ph_inf_cib; + eps_max = eps_ph_sup_cib; + std::cout << "eps range setted to " << eps_min << " , " << eps_max + << std::endl; + } else if (BackRad == "CIOB") { + eps_min = eps_ph_inf_ciob; + eps_max = eps_ph_sup_ciob; + std::cout << "eps range setted to " << eps_min << " , " << eps_max + << std::endl; + } else if (BackRad == "URB") { + eps_min = eps_ph_inf_urb; + eps_max = eps_ph_sup_urb; + std::cout << "eps range setted to " << eps_min << " , " << eps_max + << std::endl; + } + + feps_inf = eps_min; + feps_sup = eps_max; + +} + +void Process::SetLimits(Particle& p1, std::string nameproc) { + if (p1.GetType() != 22 && p1.GetType() != 11 && p1.GetType() != -11) + std::cout << "error in type " << p1.GetType() << " != 11 and !=22 " + << std::endl; + + if (nameproc == "PP") { + if (abs(p1.GetType()) == 11) + std::cout << "\nERROR!! wrong particle or process!! " << nameproc + << p1.GetType() << "\n" << std::endl; + fsmin = 4 * ElectronMass * ElectronMass; //min per theta = 0; + fsmax = 4 * p1.GetEnergy() * feps_sup * 2.0; //(1.0-cos(fInteractionAngle)); //max per theta=3.14 + } + if (nameproc == "DPP") { + if (abs(p1.GetType()) == 11) + std::cout << "\nERROR!! wrong particle or process!! " << nameproc + << p1.GetType() << "\n" << std::endl; + fsmin = 16 * ElectronMass * ElectronMass; + fsmax = 4 * p1.GetEnergy() * feps_sup * 2.0; + } + if (nameproc == "ICS") { + if (p1.GetType() == 22 || p1.GetType() == 9) + std::cout << "\nERROR!! wrong particle or process!! " << nameproc + << p1.GetType() << "\n" << std::endl; + fsmin = p1.GetMass() * p1.GetMass() + + 2 * p1.GetEnergy() * feps_inf * (1 - p1.GetBeta()); + fsmax = p1.GetMass() * p1.GetMass() + + 2 * p1.GetEnergy() * feps_sup * (1 + p1.GetBeta()); + } + if (nameproc == "TPP") { + if (p1.GetType() == 22 || p1.GetType() == 9) + std::cout << "\nERROR!! wrong particle or process!! " << nameproc + << p1.GetType() << "\n" << std::endl; + fsmin = 10 * ElectronMass * ElectronMass; + fsmax = 2 * p1.GetEnergy() * feps_sup * (1 + p1.GetBeta()) + + p1.GetMass() * p1.GetMass(); + } +} + +} + +#endif diff --git a/libs/EleCa/EleCa/Propagation.h b/libs/EleCa/EleCa/Propagation.h new file mode 100644 index 000000000..969d9d82b --- /dev/null +++ b/libs/EleCa/EleCa/Propagation.h @@ -0,0 +1,725 @@ +#ifndef ELECA_PROPAGATION_H +#define ELECA_PROPAGATION_H + +#include "Particle.h" +#include "Process.h" +#include "Common.h" +#include "XLoss_CBR.h" +#include "EnergyLoss.h" +#include "Constants.h" + +#include +#include +#include + +namespace eleca { + +class Propagation { + +private: + + double vPPle[1101]; + double vDPPle[1101]; + double vTPPle[1101]; + double vICSle[1101]; + double vEtab[1101]; + + double BkgArray[POINTS_VERY_FEW][2]; + double fEthr; + +public: + + Propagation(); + + void SetEthr(double eth) { + fEthr = eth; + } + + double GetEthr() { + return fEthr; + } + + ~Propagation() { + } + + void WriteOutput(Particle &p1, std::vector &part, bool spectropt = + 0) const; + + void ReadTables(const std::string &file); + void InitBkgArray(const std::string &BackRad); + + double GetMeanThetaBFDeflection(double Bin, double Ein, int ptype, + double Lin) const; + double GetLambdaTab(Process proc, std::string procName) const; + double ExtractMinDist(Process &proc, int type, double R, double R2, + std::vector Etarget) const; + std::vector GetEtarget(Process &proc, Particle &particle) const; + void Propagate(Particle &curr_particle, + std::vector &ParticleAtMatrix, + std::vector &ParticleAtGround) const; + double ExtractPhotonEnergyMC(double z, Process &proc) const; + double ShootPhotonEnergyMC(double z) const; + void SetInitVar(std::vector > bk, + std::vector > *le) const; + +}; + +Propagation::Propagation() { + fEthr = 1e16; +} + +void Propagation::ReadTables(const std::string &filename) { + +#ifdef DEBUG_ELECA + std::cout << filename << std::endl; +#endif + + std::ifstream fin(filename.c_str()); + + if (!fin.is_open()) { + std::cerr << "Unable to open lambda_table file: " << filename + << " ! exiting... "; + return; + } + + int k = 0; + double Etab, PPle, ICSle, DPPle, TPPle; + while (fin.good()) { + fin >> Etab >> PPle >> ICSle >> DPPle >> TPPle; + vEtab[k] = Etab; + vPPle[k] = PPle; + vICSle[k] = Etab; + vDPPle[k] = DPPle; + vTPPle[k] = TPPle; + k++; + } + + if (k != 1101) + std::cerr << "Failed to read lambda_table file: " << filename + << "! only " << k << " entries, expected 1101!"; +} + +void Propagation::InitBkgArray(const std::string &BackRad) { + // Routine to build the array of cumulative distribution of + // background photons + + std::vector > BkgArray0; + + int i = 0; + double epsinf = 0; + double epssup = 0; + std::vector tmp; + tmp.resize(2); + if (BackRad == "CMB") { + double de = pow((double) eps_ph_sup_cmb / eps_ph_inf_cmb, 1. / 100.); + for (double e = eps_ph_inf_cmb; e <= eps_ph_sup_cmb; e *= de) { + tmp.at(0) = e; + if (i == 0) + tmp.at(1) = CMBR(e); + else + tmp.at(1) = BkgArray0.at(i - 1).at(1) + CMBR(e); + + BkgArray0.push_back(tmp); + i++; + } + } + + if (BackRad == "CIOB") { + double de = pow((double) eps_ph_sup_ciob / eps_ph_inf_ciob, 1. / 100.); + + for (double e = eps_ph_inf_ciob; e <= eps_ph_sup_ciob; e *= de) { + tmp.clear(); + tmp.push_back(e); + if (i == 0) + tmp.push_back(CIOBR(e)); + else + tmp.push_back(BkgArray0.at(i - 1).at(1) + CIOBR(e)); + + BkgArray0.push_back(tmp); + i++; + } + } + + if (BackRad == "URB") { + double de = pow((double) eps_ph_sup_urb / eps_ph_inf_urb, 1. / 100.); + for (double e = eps_ph_inf_urb; e <= eps_ph_sup_urb; e *= de) { + tmp.clear(); + tmp.push_back(e); + + if (i == 0) + tmp.push_back(URB(e)); + else + tmp.push_back(BkgArray0.at(i - 1).at(1) + URB(e)); + + BkgArray0.push_back(tmp); + i++; + } + } + + if (BackRad != "CMB" && BackRad != "CIOB") { + double de = pow((double) eps_ph_sup_global / eps_ph_inf_global, + (double) 1. / POINTS_VERY_FEW); + for (double e = eps_ph_inf_global; e <= eps_ph_sup_global; e *= de) { + tmp.at(0) = e; + if (i == 0) + tmp.at(1) = CBR(e); + else + tmp.at(1) = BkgArray0.at(i - 1).at(1) + CBR(e); + BkgArray0.push_back(tmp); + i++; + } + } + + double a = 1.0 / BkgArray0.at(i - 1).at(1); + + for (i = 0; i < POINTS_VERY_FEW; i++) + BkgArray0.at(i).at(1) *= a; + + for (int k = 0; k < POINTS_VERY_FEW; k++) { + BkgArray[k][0] = BkgArray0[k][0]; + BkgArray[k][1] = BkgArray0[k][1]; + } +} + +double Propagation::GetMeanThetaBFDeflection(double Bin, double Ein, int ptype, + double Lin) const { + //from D. Hooper, S. Sarkar, M. Taylor, arXiv: 0608085, 2006 + + if (Bin == 0 || Ein == 0) + return 0; + if (ptype == 22) + return 0; + + double lcoher = 1; + + return 0.8 * (1.0e20 / Ein) * sqrt(Lin / 10 * lcoher) * (Bin / 1.0e-9) + / 180.0 * 3.1415927; +} + +double Propagation::ExtractMinDist(Process &proc, int type, double R, double R2, + std::vector Etarget) const { + + double min_dist1 = 0; + double min_dist2 = 0; + Process proc1(proc); + Process proc2(proc); + double tmp_lambda1 = 0; + double tmp_lambda2 = 0; + Particle pt; + pt.SetType(0); + pt.Setz(proc.GetIncidentParticle().Getz()); + + if (type == 22) { + + proc1.SetName("PP"); + pt.SetEnergy(Etarget[0]); + proc1.SetTargetParticle(pt); + proc1.SetCMEnergy(); + + tmp_lambda1 = GetLambdaTab(proc1, "PP"); + + min_dist1 = -tmp_lambda1 * log(R); + + proc2.SetName("DPP"); + pt.SetEnergy(Etarget[1]); + proc2.SetTargetParticle(pt); + proc2.SetCMEnergy(); + tmp_lambda2 = GetLambdaTab(proc2, "DPP"); + min_dist2 = -tmp_lambda2 * log(R2); + +#ifdef DEBUG_ELECA + std::cerr << "comparing 2 mindists: " << min_dist1 << "(" + << tmp_lambda1 << ") vs " << min_dist2 << " ( " + << tmp_lambda2 << ") " << std::endl; +#endif + + if (min_dist2 < min_dist1) { + min_dist1 = min_dist2; + proc.SetName("DPP"); + pt.SetEnergy(Etarget[1]); + proc.SetTargetParticle(pt); + proc.SetCMEnergy(); + } else { + proc.SetName("PP"); + pt.SetEnergy(Etarget[0]); + proc.SetTargetParticle(pt); + proc.SetCMEnergy(); + } + } //end if type 0 + else if (abs(type) == 11) { + + proc1.SetName("ICS"); + pt.SetEnergy(Etarget[0]); + proc1.SetTargetParticle(pt); + tmp_lambda1 = GetLambdaTab(proc1, "ICS"); + min_dist1 = -tmp_lambda1 * log(R); + + proc2.SetName("TPP"); + pt.SetEnergy(Etarget[1]); + proc2.SetTargetParticle(pt); + tmp_lambda2 = GetLambdaTab(proc2, "TPP"); + min_dist2 = -tmp_lambda2 * log(R2); + + if (min_dist2 < min_dist1) { + min_dist1 = min_dist2; + proc.SetName("TPP"); + pt.SetEnergy(Etarget[1]); + proc.SetTargetParticle(pt); + proc.SetCMEnergy(); + } else { + proc.SetName("ICS"); + pt.SetEnergy(Etarget[0]); + proc.SetTargetParticle(pt); + proc.SetCMEnergy(); + } + } //else e+/e- + else + std::cerr << "something wrong in particle type ( " << type + << ". Propagation of photons and e+/e- is the only allowed.)" + << std::endl; + + return min_dist1; +} + +double Propagation::GetLambdaTab(Process proc, std::string procName) const { + + double E1 = proc.GetIncidentParticle().GetEnergy(); + double z = proc.GetIncidentParticle().Getz(); + double res = 0; + + double E0taborg = vEtab[0]; + + double dEtab = log10(vEtab[0]) - log10(vEtab[1]); + double evolution = GetEvolution(proc.GetTargetParticle().GetEnergy(), z); + int i = (int) ((log10(E0taborg) - log10(E1 * (1 + z))) / dEtab); + + if (i < 0) { + std::cout << "WARNING!! GetLambdaTab in " << procName << " : i= " << i + << " <0! E1*(1+z) = " << E1 << "* (1 + " << z << ") < " + << E0taborg << ".. returning lambda[0];" << std::endl; + } + + else if (i >= 1001) { + std::cout << "WARNING!! GetLambdaTab in " << procName << " : i>= " + << 1001 << " ! E1*(1+z) = " << E1 << "* (1 + " << z + << ") .. returning lambda[nentries];" << std::endl; + + } else { + if (procName == "PP") + res = vPPle[i]; + else if (procName == "DPP") + res = vDPPle[i]; + else if (procName == "ICS") + res = vICSle[i]; + else if (procName == "TPP") + res = vTPPle[i]; + } + + if (evolution != 0) { + if (res / evolution < 0) + std::cerr + << "ERROR UNPHYSICAL SOLUTION!! CHECK HERE LAMBDA OR EVOLUTION!!" + << std::endl; + return res / evolution; + } + std::cerr << "warning!! evolution ==0 " << std::endl; + return 0; +} + +double Propagation::ShootPhotonEnergyMC(double z) const { + // Routine for the MC sampling of background photon energy + + double h = Uniform(0, 1); + for (int i = 0; i < POINTS_VERY_FEW; i++) { + if (h < BkgArray[i][1]) { + return BkgArray[i][0] * (1. + z); + break; + } + } + + std::cout << "ShootPhotonEnergyMC. z = " << z << " h: " << h << " => 0" + << std::endl; + return 0.; +} + +std::vector Propagation::GetEtarget(Process &proc, + Particle &particle) const { + + std::vector Etarget; + double Etarget_tmp = 0; + double smintmp = 0; + double z_curr = particle.Getz(); + double Energy = particle.GetEnergy(); + int pType = particle.GetType(); + if (pType == 22) { + proc.SetName("PP"); + proc.SetLimits(); + smintmp = proc.GetMin(); + Etarget_tmp = 0; + while (Etarget_tmp < ElectronMass * ElectronMass / Energy) { + std::cout << "smintmp" << std::endl; + Etarget_tmp = ShootPhotonEnergyMC(z_curr); + } + Etarget.push_back(Etarget_tmp); + + proc.SetName("DPP"); + proc.SetLimits(); + smintmp = proc.GetMin(); + Etarget_tmp = 0; + + while (Etarget_tmp < smintmp / (4.0 * Energy)) { + std::cout << "smintmp" << std::endl; + Etarget_tmp = ShootPhotonEnergyMC(z_curr); + } + Etarget.push_back(Etarget_tmp); + } + + else if (abs(pType) == 11) { + proc.SetName("ICS"); + proc.SetLimits(); + smintmp = proc.GetMin(); + Etarget_tmp = 0; + while (Etarget_tmp < smintmp / (4.0 * Energy)) { + Etarget_tmp = ShootPhotonEnergyMC(z_curr); + } + Etarget.push_back(Etarget_tmp); + + proc.SetName("TPP"); + proc.SetLimits(); + smintmp = proc.GetMin(); + Etarget_tmp = 0; + + while (Etarget_tmp < smintmp / (4.0 * Energy)) { + Etarget_tmp = ShootPhotonEnergyMC(z_curr); + } + Etarget.push_back(Etarget_tmp); + } //end e/e + else + std::cerr << "something wrong in particle type ( " << pType + << ". Propagation of photons and e+/e- is the only allowed.)" + << std::endl; + + if (Etarget.size() != 2) { + std::cout << "something wrong with the Etarget!! " << std::endl; + exit(0); + } + + return Etarget; +} + +double Propagation::ExtractPhotonEnergyMC(double z, Process &proc) const { + double esoft = 0; + double snew = 0; + double emin = proc.GetMin(); + Particle pi = proc.GetIncidentParticle(); + Particle pb = proc.GetTargetParticle(); + + double Epi = pi.GetEnergy(); + double m = pi.GetMass(); + while (esoft < emin / (4.0 * Epi)) { + + double h = Uniform(0, 1); + + for (int i = 0; i < POINTS_VERY_FEW; i++) { + if (h < BkgArray[i][1]) { + esoft = BkgArray[i][0] * (1. + z); + break; + } + } + + snew = 4 * Epi * esoft + m * m; + } + pb.SetEnergy(esoft); + proc.SetTargetParticle(pb); + proc.SetCMEnergy(); + return esoft; +} + +void Propagation::WriteOutput(Particle & p1, + std::vector &ParticleAtGround, bool spectrum) const { + double Ethr = 1e16; + double Bfield = 0; + double E0nucl = p1.GetEnergy(); + double z0nucl = p1.Getz(); + + int NsecG = ParticleAtGround.size(); + std::vector EGround; + std::vector wGround; + std::vector typeGround; + int cpart = 0; + + for (int ig = 0; ig < NsecG; ++ig) { + EGround.push_back(ParticleAtGround.at(ig).GetEnergy()); + typeGround.push_back(ParticleAtGround.at(ig).GetType()); + wGround.push_back(ParticleAtGround.at(ig).GetWeigth()); + + cpart += wGround.at(ig); + } + + std::vector fdN; + + std::ofstream outfile("eleca_output.txt", std::ios::app); + if (spectrum) { + double emin = 7.0; + double dE = (24.0 - 7.0) / 170.0; + int ipos = 0; + + for (int h = 0; h < NsecG; ++h) { + ipos = (int) ((log10(EGround.at(h)) - emin) / dE); + if (typeGround.at(h) == 22) + fdN[ipos] += wGround.at(h); + } + } //end opt_spectrum + else { + outfile << Ethr << " " << Bfield / 1e-9 << " " << E0nucl << " " + << z0nucl << " " << NsecG << " "; + for (int h = 0; h < NsecG; ++h) { + + outfile << wGround.at(h) << " " << EGround.at(h) << " " + << typeGround.at(h) << " "; + } + } + outfile << std::endl; +} + +void Propagation::Propagate(Particle &curr_particle, + std::vector &ParticleAtMatrix, + std::vector &ParticleAtGround) const { + + double Ethr = fEthr; + double theta_deflBF = 0.0; + double BNorm = curr_particle.GetB(); + + double zin = curr_particle.Getz(); + double Ein = curr_particle.GetEnergy(); + int type = curr_particle.Getz(); + + int wi_last = curr_particle.GetWeigth(); + + double z_curr = zin; + double Ecurr = Ein; + + bool interacted = 0; + double min_dist = 1e12; + double walkdone = 0; + + double E1 = 0; + double E2 = 0; + double E3 = 0; + + double stepsize = 0; + double Elast = 0; + + double R = Uniform(0.0, 1.0); + double R2 = Uniform(0.0, 1.0); + bool fast = 1; + + Process proc; + proc.SetIncidentParticle(curr_particle); + +#ifdef DEBUG_ELECA + std::cout << "GetEtarget " << std::endl; +#endif + std::vector EtargetAll = GetEtarget(proc, curr_particle); +#ifdef DEBUG_ELECA + std::cout << "ExtractMinDist " << std::endl; +#endif + min_dist = ExtractMinDist(proc, curr_particle.GetType(), R, R2, EtargetAll); + + interacted = 0; + double dz = 0; + double zpos = zin; + + double corrB_factor = 0; + double realpath = 0; + + double min_dist_last = min_dist; +#ifdef DEBUG_ELECA + std::cout << "starting propagation... min_dist_last: " << min_dist_last + << std::endl; +#endif + + while (!interacted) { + + proc.SetInteractionAngle(cPI); + theta_deflBF = 0; + realpath = 0.1 * min_dist; + + theta_deflBF = GetMeanThetaBFDeflection(BNorm, + curr_particle.GetEnergy(), curr_particle.GetType(), min_dist); + corrB_factor = cos(theta_deflBF); + + stepsize = realpath * corrB_factor; + dz = Mpc2z(stepsize); + +#ifdef DEBUG_ELECA + if (BNorm > 0) + std::cout << "z_curr " << z_curr << ", type: " + << curr_particle.GetType() << ", Ecurr " + << curr_particle.GetEnergy() << " = " << min_dist + << " Mpc --> theta: " << theta_deflBF * 180.0 / 3.1415927 + << " " << corrB_factor << std::endl; + + std::cout << "done : " << walkdone << " + " << realpath << " = " + << walkdone + realpath << " has to be: " << min_dist + << " Mpc. Now @ z= " << zpos << " vs nexz = " + << zpos - Mpc2z(stepsize) << std::endl; +#endif + + if ((walkdone + realpath) > min_dist) { +#ifdef DEBUG_ELECA + std::cout + << " walkdone + realpath > min_dist: correcting realpath from" + << realpath << " to " << min_dist - walkdone + << " and the stepsize is changed from " << dz << " to "; +#endif + realpath = min_dist - walkdone; + stepsize = realpath * corrB_factor; + dz = Mpc2z(stepsize); +#ifdef DEBUG_ELECA + std::cout << dz << std::endl; +#endif + interacted = 1; + } + + if (zpos - dz <= 0) { + dz = zpos; + stepsize = z2Mpc(dz); + realpath = stepsize / corrB_factor; + } + + zpos -= dz; + walkdone += realpath; + Elast = Ecurr; + + double adiab = Ecurr + - AdiabaticELoss(zpos + Mpc2z(realpath), zpos + dz, Ecurr); + + if (type == 0 || type == 22) + Ecurr = EnergyLoss1D(Ecurr, zpos + Mpc2z(realpath), zpos, 0); + else + Ecurr = EnergyLoss1D(Ecurr, zpos + Mpc2z(realpath), zpos, BNorm); + + z_curr = zpos; + + curr_particle.Setz(z_curr); + curr_particle.SetEnergy(Ecurr); + + if (z_curr > 0 && Ecurr < Ethr) { + return; + } + if (z_curr <= 0) { + ParticleAtGround.push_back(curr_particle); + return; + } + + proc.SetIncidentParticle(curr_particle); + proc.SetCMEnergy(); + proc.SetLimits(); + // std::vector EtargetAll=GetEtarget(proc,curr_particle); + min_dist = ExtractMinDist(proc, curr_particle.GetType(), R, R2, + EtargetAll); + } //end while + + if (interacted == 1) { +#ifdef DEBUG_ELECA + std::cerr << "******** producing secondary particles according to " + << proc.GetName() << " process *********** " << std::endl; +#endif + if (proc.GetName() == "PP") { + + E1 = ExtractPPSecondariesEnergy(proc); + + if (E1 == 0 || E1 == Ecurr) + std::cerr << "ERROR in PP process: E : " << Ecurr << " " << E1 + << " " << std::endl; + + if (E1 > Ethr) { + Particle pp(11, E1, z_curr); + pp.SetWeigth(wi_last); + ParticleAtMatrix.push_back(pp); + } + if (Ecurr - E1 > Ethr) { + Particle pe(-11, Ecurr - E1, z_curr); + pe.SetWeigth(wi_last); + ParticleAtMatrix.push_back(pe); + } + + return; + } //if PP + else if (proc.GetName() == "DPP") { + E1 = (Ecurr - 2 * ElectronMass) / 2.0; + if (E1 == 0) + std::cerr << "ERROR in DPP process E : " << E1 << std::endl; + + if (E1 > Ethr) { + Particle pp(11, E1, z_curr); + if (fast == 1) + pp.SetWeigth(wi_last * 2); + else { + pp.SetWeigth(wi_last); + Particle pe(-11, E1, z_curr); + pe.SetWeigth(wi_last); + ParticleAtMatrix.push_back(pe); + } + ParticleAtMatrix.push_back(pp); + } + + return; + } //end if DPP + else if (proc.GetName() == "ICS") { + + E1 = ExtractICSSecondariesEnergy(proc); + E2 = Ecurr - E1; + if (E1 == 0 || E2 == 0) + std::cerr << "ERROR in ICS process E : " << E1 << " " << E2 + << std::endl; + + if (E1 > Ethr) { + Particle pp(curr_particle.GetType(), E1, z_curr); + pp.SetWeigth(wi_last); + ParticleAtMatrix.push_back(pp); + } + if (E2 > Ethr) { + Particle pg(22, E2, z_curr); + pg.SetWeigth(wi_last); + ParticleAtMatrix.push_back(pg); + } + + return; + } //if ics + else if (proc.GetName() == "TPP") { + E1 = E2 = ExtractTPPSecondariesEnergy(proc); + E3 = Ecurr - E1 - E2; + if (E1 == 0 || E2 == 0 || E3 == 0) + std::cerr << "ERROR in TPP process E : " << E1 << " " << E2 + << std::endl; + + if (E1 > Ethr) { + Particle pp(11, E1, z_curr); + if (fast == 1) + pp.SetWeigth(wi_last * 2); + else { + pp.SetWeigth(wi_last); + Particle pe(-11, E1, z_curr); + pe.SetWeigth(wi_last); + ParticleAtMatrix.push_back(pe); + } + ParticleAtMatrix.push_back(pp); + } + if (E3 > Ethr) { + Particle psc(curr_particle.GetType(), E3, z_curr); + psc.SetWeigth(wi_last); + ParticleAtMatrix.push_back(psc); + } + return; + } + } + + return; + +} + +} // namespace eleca + +#endif // ELECA_PROPAGATION_H diff --git a/libs/EleCa/EleCa/XLoss_CBR.h b/libs/EleCa/EleCa/XLoss_CBR.h new file mode 100644 index 000000000..61b0d2e06 --- /dev/null +++ b/libs/EleCa/EleCa/XLoss_CBR.h @@ -0,0 +1,315 @@ +#ifndef ELECA_XLOSS_CBR_H +#define ELECA_XLOSS_CBR_H + +namespace eleca { +/*===================================================================== + + License + ======= + + This file is part of xHERMES () and EleCa packages for + multi messenger data analysis. + + (C) Copyright 2009, 2010, 2011 Manlio De Domenico and Mariangela Settimo + + Author: Manlio De Domenico + Lab. for Complex Systems, Scuola Superiore di Catania + Universita' degli Studi di Catania, Italy + Mail: manlio.dedomenico@ct.infn.it + + (C) Copyright 2011, 2012 Mariangela Settimo + Author: Mariangela Settimo + Universaat Siegen, Germany, now at LPNHE Paris + Mail: mariangela.settimo@gmail.com + + =====================================================================*/ + +//########################################################################## +//# Cosmic Background Radiations +//########################################################################## +double CIB_Evolution_Baseline(double z) { + // Function for the CIB baseline evolution. + // Stecker, Malkan, Scully (2006) arXiv:astro-ph/0510449v4 + + double tmp = 0; + double m = 3.1; + double z_flat = 1.3; + + if (z <= z_flat) + tmp = pow(1. + z, m); + if (z_flat < z && z < 6) + tmp = pow(1. + z_flat, m); + if (z > 6) + tmp = 0; + + return tmp; +} + +double CIB_Evolution_Fast(double z) { + // Function for the CIB fast evolution. + // Stecker, Malkan, Scully (2006) arXiv:astro-ph/0510449v4 + + double tmp = 0; + double m = 4.; + double z_flat = 1.; + + if (z <= z_flat) + tmp = pow(1. + z, m); + if (z_flat < z && z < 6) + tmp = pow(1. + z_flat, m); + if (z > 6) + tmp = 0; + + return tmp; +} + +double CMB_Evolution(double z) { + return pow(1. + z, 3.); +} + +double CIB_Evolution(double z) { + return CIB_Evolution_Fast(z); +} + +double CIOB_Evolution(double z) { + return CIB_Evolution_Fast(z); +} + +double COB_Evolution(double z) { + return pow(1. + z, 3.); +} + +double URB_Evolution(double z) { + //from Protheroe - Bierman astro-ph:9605119 + if (z < 0.8) + return pow(1. + z, 4.); + return pow(1 + 0.8, 4); // z>= z0 +} + +double CMBR(double eps) { + double tmp = 0; + + if (eps > eps_ph_inf_cmb && eps < eps_ph_sup_cmb) { + tmp = (K_CBR * eps * eps) / (exp((double) eps / (K_boltz * T_CMB)) - 1); + } else { + tmp = 0; + } + + if (isnan(tmp)) + tmp = 0; + + return tmp; +} + +double CIBR(double eps) { + double tmp = 0; + + if (eps > eps_ph_inf_cib && eps <= eps_ph_sup_cib) { + tmp = 5e-1 + * ((2.2e-6 * K_CBR * eps * eps) + / (exp((double) eps / (K_boltz * T_CMB) / 9.17) - 1) + + (2.e-11 * K_CBR * eps * eps) + / (exp( + (double) eps / (K_boltz * T_CMB) + / 128.44) - 1)); + } else { + tmp = 0; + } + + if (isnan(tmp)) + tmp = 0; + + return tmp; +} + +double CIOBR(double eps) { + // parametrization for infrared/optical by + // Hopkins, A. M. & Beacom, J. F. 2006, ApJ, 651, 142 + // See Model D Finke et al, arXiv:0905.1115v2 + + double tmp = 0; + + if (eps > eps_ph_inf_ciob && eps < eps_ph_sup_ciob) { + double x = log(eps); + tmp = -5.32524895349885 - 0.0741140642891119 * x + - 0.252586527659431 * pow(x, 2.) + + 0.234971297531891 * pow(x, 3.) + - 0.217014471117521 * pow(x, 4.) + - 0.364936722063572 * pow(x, 5.) + + 0.0880702191711222 * pow(x, 6.) + + 0.221947767409286 * pow(x, 7.) + + 0.0445499623085708 * pow(x, 8.) + - 0.0517435600939147 * pow(x, 9.) + - 0.0295646851279071 * pow(x, 10.) + - 0.00011943632049331 * pow(x, 11.) + + 0.00461621589174355 * pow(x, 12.) + + 0.00150906100702171 * pow(x, 13.) + + 1.91459088023263e-05 * pow(x, 14.) + - 0.000110272619218937 * pow(x, 15.) + - 3.45221358079085e-05 * pow(x, 16.) + - 5.42000122025042e-06 * pow(x, 17.) + - 4.90862622314226e-07 * pow(x, 18.) + - 2.45145316799091e-08 * pow(x, 19.) + - 5.25792204884819e-10 * pow(x, 20.); + tmp = 0.4 * (double) exp(tmp) / eps / eps; + } else { + tmp = 0; + } + + if (isnan(tmp)) + tmp = 0; + + return tmp; +} + +double COBR(double eps) { + double tmp = 0; + + if (eps > eps_ph_inf_cob && eps < eps_ph_sup_cob) { + tmp = 1.2e-15 * (K_CBR * eps * eps) + / (exp((double) eps / (K_boltz * T_COB)) - 1); + } else { + tmp = 0; + } + + if (isnan(tmp)) + tmp = 0; + + return tmp; +} + +// Universal Radio Background from Protheroe, Bierman 1996. + +double URB(double eps) { + if (eps < eps_ph_inf_urb || eps > eps_ph_sup_urb) + return 0; + + double v = eps / h_Planck; + double x = log10(v / 1e9); + + double p0 = -2.23791e+01; + double p1 = -2.59696e-01; + double p2 = 3.51067e-01; + double p3 = -6.80104e-02; + double p4 = 5.82003e-01; + double p5 = 2.00075e+00; + double p6 = 1.35259e+00; + double p7 = -7.12112e-01; //xbreak + + double intensity = 0; + if (x > p7) + intensity = p0 + p1 * x + p2 * x * x + + p3 * x * x * x / (exp(p4 * x) - 1) + p6 + p5 * x; + else + intensity = p0 + p1 * x + p2 * x * x + + p3 * x * x * x / (exp(p4 * x) - 1); + intensity = pow(10, intensity); + double n_eps = 0; + n_eps = 4 * M_PI / (h_Planck * C_speed) * (intensity / eps); + return n_eps / eV2J / 1.0e6; + +} + +double CMIBR(double eps) { + /*! + Cosmic background radiation photon number density (eV^-1 cm^-3) + as a function of ambient photon energy (eV), from CMB to Optical (COB) + + Ref: + + Funk et al, Astropart.Phys. 9 (1998) 97-103 + J.L. Puget, F.W. Stecker and J. Bredekamp, Astroph. J. 205 (1976) 638–654. + */ + return CMBR(eps) + CIBR(eps); +} + +double CMIOBR(double eps) { + /*! + Cosmic background radiation photon number density (eV^-1 cm^-3) + as a function of ambient photon energy (eV), from CMB to Optical (COB) + + Ref: + + Funk et al, Astropart.Phys. 9 (1998) 97-103 + J.L. Puget, F.W. Stecker and J. Bredekamp, Astroph. J. 205 (1976) 638–654. + */ + return CMBR(eps) + CIOBR(eps); +} + +double CBR(double eps, double z) { + /*! + Cosmic background radiation photon number density (eV^-1 cm^-3) + as a function of ambient photon energy (eV), from CMB to Optical (COB) + + Ref: + + Funk et al, Astropart.Phys. 9 (1998) 97-103 + J.L. Puget, F.W. Stecker and J. Bredekamp, Astroph. J. 205 (1976) 638–654. + */ + return CMBR(eps) * CMB_Evolution(z) + CIOBR(eps) * CIOB_Evolution(z) + + URB(eps) * URB_Evolution(z); +} + +double CBR(double eps) { + return CMBR(eps) + CIOBR(eps) + URB(eps); +} + +double GetEvolution(double eps, double z) { + + if (eps >= eps_ph_inf_urb && eps <= eps_ph_sup_urb) + return URB_Evolution(z); + if (eps >= eps_ph_inf_ciob && eps <= eps_ph_sup_ciob) + return CIOB_Evolution(z); + if (eps >= eps_ph_inf_cmb && eps <= eps_ph_sup_cmb) + return CMB_Evolution(z); + return 1; +} + +double GetEvolution(double z, std::string background) { + if (background == "CMB") + return CMB_Evolution(z); + if (background == "CIB") + return CIB_Evolution(z); + if (background == "CMIOB") + return CIOB_Evolution(z); + if (background == "CIOB") + return CIOB_Evolution(z); + if (background == "COB") + return COB_Evolution(z); + if (background == "URB") + return URB_Evolution(z); + + if (background == "ALL") { // come trattare questo caso???? + return CMB_Evolution(z); + } + return 1; +} + +//------ + +double CBR(double eps, double z, std::string background) { + double evolution = 1; + if (z == 0) + evolution = 1; + else + evolution = GetEvolution(eps, z); + + if (background == "CMB") + return CMBR(eps) * evolution; + else if (background == "URB") + return URB(eps) * evolution; + else if (background == "CIOB") + return CIOBR(eps) * evolution; + else if (background == "CMIB") + return CMIBR(eps) * evolution; + else if (background == "CMIOB") + return CMIOBR(eps) * evolution; + else + return (CMBR(eps) * CMB_Evolution(z) + CIOBR(eps) * CIOB_Evolution(z) + + URB(eps) * URB_Evolution(z)); +} + +} // namespace eleca + +#endif // ELECA_XLOSS_CBR_H + diff --git a/src/module/PhotonEleCa.cpp b/src/module/PhotonEleCa.cpp index 5c3f8fd6b..1c038712f 100644 --- a/src/module/PhotonEleCa.cpp +++ b/src/module/PhotonEleCa.cpp @@ -1,8 +1,17 @@ #include "crpropa/module/PhotonEleCa.h" +#include "EleCa/Propagation.h" +#include "EleCa/Particle.h" +#include "EleCa/Common.h" + +#include + namespace crpropa { -PhotonEleCa::PhotonEleCa(ref_ptr field) { +PhotonEleCa::PhotonEleCa() : + propagation(new eleca::Propagation) { + propagation->ReadTables(getDataPath("eleca_lee.txt")); + propagation->InitBkgArray("CMB"); } PhotonEleCa::~PhotonEleCa() { @@ -12,6 +21,29 @@ void PhotonEleCa::process(Candidate *candidate) const { if (candidate->current.getId() != 22) return; // do nothing if not a photon + eleca::Particle p0(candidate->current.getId(), + candidate->current.getEnergy() / eV, candidate->getRedshift()); + + std::vector ParticleAtMatrix; + std::vector ParticleAtGround; + ParticleAtMatrix.push_back(p0); + + while (ParticleAtMatrix.size() > 0) { + + eleca::Particle p1 = ParticleAtMatrix.back(); + ParticleAtMatrix.pop_back(); + + if (p1.IsGood()) { + propagation->Propagate(p1, ParticleAtMatrix, ParticleAtGround); + } + } + +#pragma omp critical + { + propagation->WriteOutput(p0, ParticleAtGround, 0); + } + + candidate->setActive(false); return; } From 31b3e93bb7084e0cd765081e18ce95ce89978e28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Fri, 10 Jan 2014 12:34:46 +0100 Subject: [PATCH 0372/1298] fix openmp dependency --- src/ModuleList.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 49c892aaa..34b09ad2f 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -1,7 +1,10 @@ #include "crpropa/ModuleList.h" #include "crpropa/ProgressBar.h" +#if _OPENMP #include +#endif + #include #include #ifndef sighandler_t From 74b42759d814a5f8d19e3bafc2fdf84481061cef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Fri, 10 Jan 2014 12:41:45 +0100 Subject: [PATCH 0373/1298] fix cosmology static members --- src/Cosmology.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Cosmology.cpp b/src/Cosmology.cpp index ed5c6d92a..b28f0f376 100644 --- a/src/Cosmology.cpp +++ b/src/Cosmology.cpp @@ -17,9 +17,9 @@ struct Cosmology { double omegaM; // matter density parameter double omegaL; // vacuum energy parameter - static const int n = 1000; - static const double zmin = 0.0001; - static const double zmax = 100; + static const int n; + static const double zmin; + static const double zmax; std::vector Z; // redshift std::vector Dc; // comoving distance [m] @@ -42,8 +42,10 @@ struct Cosmology { E[i] = sqrt(omegaL + omegaM * pow(1 + Z[i], 3)); Dc[i] = Dc[i - 1] + dH * dz * (1 / E[i] + 1 / E[i - 1]) / 2; Dl[i] = (1 + Z[i]) * Dc[i]; - Dt[i] = Dt[i - 1] + dH * dz - * (1 / ((1 + Z[i]) * E[i]) + 1 / ((1 + Z[i - 1]) * E[i - 1])) / 2; + Dt[i] = Dt[i - 1] + + dH * dz + * (1 / ((1 + Z[i]) * E[i]) + + 1 / ((1 + Z[i - 1]) * E[i - 1])) / 2; } } @@ -73,9 +75,11 @@ struct Cosmology { } }; -static Cosmology cosmology; // instance is created at runtime - +const int Cosmology::n = 1000; +const double Cosmology::zmin = 0.0001; +const double Cosmology::zmax = 100; +static Cosmology cosmology; // instance is created at runtime void setCosmologyParameters(double h, double oM) { cosmology.setParameters(h, oM); From 02d7384a7750d54d03787db824a59e3d534610d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Fri, 10 Jan 2014 12:45:06 +0100 Subject: [PATCH 0374/1298] fix gtest on Apple --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 175b835c9..11cdbfaa1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,9 @@ option(ENABLE_TESTING "Build tests and enable test target" ON) if(ENABLE_TESTING) include_directories(libs/gtest/include) add_subdirectory(libs/gtest) + if( APPLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_USE_OWN_TR1_TUPLE=1") + endif(APPLE) endif(ENABLE_TESTING) # kiss (provided) From 057fc60f352578e9ec30cd508bc4d90d19c1db2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Fri, 10 Jan 2014 12:51:55 +0100 Subject: [PATCH 0375/1298] fix gtest src on Apple --- libs/gtest/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/gtest/CMakeLists.txt b/libs/gtest/CMakeLists.txt index ad98748df..2669f53ff 100644 --- a/libs/gtest/CMakeLists.txt +++ b/libs/gtest/CMakeLists.txt @@ -23,6 +23,10 @@ if (COMMAND set_up_hermetic_build) set_up_hermetic_build() endif() +if(APPLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_USE_OWN_TR1_TUPLE=1") +endif(APPLE) + # Define helper functions and macros used by Google Test. include(cmake/internal_utils.cmake) From 8519bdd68d8ef1e4a412b9a36b5579f5cba97d9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Fri, 10 Jan 2014 15:43:46 +0100 Subject: [PATCH 0376/1298] refactor eleca output --- CMakeLists.txt | 2 +- include/crpropa/module/PhotonEleCa.h | 5 +- libs/EleCa/EleCa/Propagation.h | 109 +++++++++++++-------------- src/module/PhotonEleCa.cpp | 8 +- 4 files changed, 60 insertions(+), 64 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 11cdbfaa1..7dd6715ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ option(ENABLE_TESTING "Build tests and enable test target" ON) if(ENABLE_TESTING) include_directories(libs/gtest/include) add_subdirectory(libs/gtest) - if( APPLE) + if(APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_USE_OWN_TR1_TUPLE=1") endif(APPLE) endif(ENABLE_TESTING) diff --git a/include/crpropa/module/PhotonEleCa.h b/include/crpropa/module/PhotonEleCa.h index 882221edd..4ce3aaed0 100644 --- a/include/crpropa/module/PhotonEleCa.h +++ b/include/crpropa/module/PhotonEleCa.h @@ -5,6 +5,7 @@ #include "crpropa/magneticField/MagneticField.h" #include +#include // forward declaration namespace eleca { @@ -16,9 +17,9 @@ namespace crpropa { class PhotonEleCa: public Module { private: std::auto_ptr propagation; - + mutable std::ofstream output; public: - PhotonEleCa(); + PhotonEleCa(const std::string background, const std::string &filename); ~PhotonEleCa(); void process(Candidate *candidate) const; std::string getDescription() const; diff --git a/libs/EleCa/EleCa/Propagation.h b/libs/EleCa/EleCa/Propagation.h index 969d9d82b..6bf1d1c18 100644 --- a/libs/EleCa/EleCa/Propagation.h +++ b/libs/EleCa/EleCa/Propagation.h @@ -42,8 +42,8 @@ class Propagation { ~Propagation() { } - void WriteOutput(Particle &p1, std::vector &part, bool spectropt = - 0) const; + void WriteOutput(std::ostream &out, Particle &p1, + std::vector &part) const; void ReadTables(const std::string &file); void InitBkgArray(const std::string &BackRad); @@ -336,9 +336,11 @@ double Propagation::ShootPhotonEnergyMC(double z) const { break; } } - +#ifdef DEBUG_ELECA std::cout << "ShootPhotonEnergyMC. z = " << z << " h: " << h << " => 0" - << std::endl; + << std::endl; +#endif + return 0.; } @@ -357,7 +359,6 @@ std::vector Propagation::GetEtarget(Process &proc, smintmp = proc.GetMin(); Etarget_tmp = 0; while (Etarget_tmp < ElectronMass * ElectronMass / Energy) { - std::cout << "smintmp" << std::endl; Etarget_tmp = ShootPhotonEnergyMC(z_curr); } Etarget.push_back(Etarget_tmp); @@ -368,7 +369,6 @@ std::vector Propagation::GetEtarget(Process &proc, Etarget_tmp = 0; while (Etarget_tmp < smintmp / (4.0 * Energy)) { - std::cout << "smintmp" << std::endl; Etarget_tmp = ShootPhotonEnergyMC(z_curr); } Etarget.push_back(Etarget_tmp); @@ -435,58 +435,51 @@ double Propagation::ExtractPhotonEnergyMC(double z, Process &proc) const { return esoft; } -void Propagation::WriteOutput(Particle & p1, - std::vector &ParticleAtGround, bool spectrum) const { - double Ethr = 1e16; +void Propagation::WriteOutput(std::ostream &out, Particle &p1, + std::vector &ParticleAtGround) const { double Bfield = 0; - double E0nucl = p1.GetEnergy(); - double z0nucl = p1.Getz(); - - int NsecG = ParticleAtGround.size(); - std::vector EGround; - std::vector wGround; - std::vector typeGround; - int cpart = 0; - - for (int ig = 0; ig < NsecG; ++ig) { - EGround.push_back(ParticleAtGround.at(ig).GetEnergy()); - typeGround.push_back(ParticleAtGround.at(ig).GetType()); - wGround.push_back(ParticleAtGround.at(ig).GetWeigth()); - - cpart += wGround.at(ig); - } - - std::vector fdN; - - std::ofstream outfile("eleca_output.txt", std::ios::app); - if (spectrum) { - double emin = 7.0; - double dE = (24.0 - 7.0) / 170.0; - int ipos = 0; - - for (int h = 0; h < NsecG; ++h) { - ipos = (int) ((log10(EGround.at(h)) - emin) / dE); - if (typeGround.at(h) == 22) - fdN[ipos] += wGround.at(h); - } - } //end opt_spectrum - else { - outfile << Ethr << " " << Bfield / 1e-9 << " " << E0nucl << " " - << z0nucl << " " << NsecG << " "; - for (int h = 0; h < NsecG; ++h) { - - outfile << wGround.at(h) << " " << EGround.at(h) << " " - << typeGround.at(h) << " "; - } + size_t NsecG = ParticleAtGround.size(); + + out << fEthr << " " << Bfield / 1e-9 << " " << p1.GetEnergy() << " " + << p1.Getz() << " " << NsecG; + for (int i = 0; i < NsecG; ++i) { + Particle &p = ParticleAtGround[i]; + out << " " << p.GetWeigth() << " " << p.GetEnergy() << " " + << p.GetType(); } - outfile << std::endl; + out << std::endl; } +// +//void Propagation::Spectrum(std::vector &spectrum) const { +// double emin = 7.0; +// double dE = (24.0 - 7.0) / 170.0; +// size_t ipos = 0; +// size_t NsecG = ParticleAtGround.size(); +// +// for (int h = 0; h < NsecG; ++h) { +// ipos = (int) ((log10(EGround.at(h)) - emin) / dE); +// if (typeGround.at(h) == 22) +// fdN[ipos] += wGround.at(h); +// } +//} +// +//void Propagation::AddSpectrum(std::vector &spectrum) const { +// double emin = 7.0; +// double dE = (24.0 - 7.0) / 170.0; +// size_t ipos = 0; +// size_t NsecG = ParticleAtGround.size(); +// +// for (int h = 0; h < NsecG; ++h) { +// ipos = (int) ((log10(EGround.at(h)) - emin) / dE); +// if (typeGround.at(h) == 22) +// fdN[ipos] += wGround.at(h); +// } +//} void Propagation::Propagate(Particle &curr_particle, std::vector &ParticleAtMatrix, std::vector &ParticleAtGround) const { - double Ethr = fEthr; double theta_deflBF = 0.0; double BNorm = curr_particle.GetB(); @@ -605,7 +598,7 @@ void Propagation::Propagate(Particle &curr_particle, curr_particle.Setz(z_curr); curr_particle.SetEnergy(Ecurr); - if (z_curr > 0 && Ecurr < Ethr) { + if (z_curr > 0 && Ecurr < fEthr) { return; } if (z_curr <= 0) { @@ -634,12 +627,12 @@ void Propagation::Propagate(Particle &curr_particle, std::cerr << "ERROR in PP process: E : " << Ecurr << " " << E1 << " " << std::endl; - if (E1 > Ethr) { + if (E1 > fEthr) { Particle pp(11, E1, z_curr); pp.SetWeigth(wi_last); ParticleAtMatrix.push_back(pp); } - if (Ecurr - E1 > Ethr) { + if (Ecurr - E1 > fEthr) { Particle pe(-11, Ecurr - E1, z_curr); pe.SetWeigth(wi_last); ParticleAtMatrix.push_back(pe); @@ -652,7 +645,7 @@ void Propagation::Propagate(Particle &curr_particle, if (E1 == 0) std::cerr << "ERROR in DPP process E : " << E1 << std::endl; - if (E1 > Ethr) { + if (E1 > fEthr) { Particle pp(11, E1, z_curr); if (fast == 1) pp.SetWeigth(wi_last * 2); @@ -675,12 +668,12 @@ void Propagation::Propagate(Particle &curr_particle, std::cerr << "ERROR in ICS process E : " << E1 << " " << E2 << std::endl; - if (E1 > Ethr) { + if (E1 > fEthr) { Particle pp(curr_particle.GetType(), E1, z_curr); pp.SetWeigth(wi_last); ParticleAtMatrix.push_back(pp); } - if (E2 > Ethr) { + if (E2 > fEthr) { Particle pg(22, E2, z_curr); pg.SetWeigth(wi_last); ParticleAtMatrix.push_back(pg); @@ -695,7 +688,7 @@ void Propagation::Propagate(Particle &curr_particle, std::cerr << "ERROR in TPP process E : " << E1 << " " << E2 << std::endl; - if (E1 > Ethr) { + if (E1 > fEthr) { Particle pp(11, E1, z_curr); if (fast == 1) pp.SetWeigth(wi_last * 2); @@ -707,7 +700,7 @@ void Propagation::Propagate(Particle &curr_particle, } ParticleAtMatrix.push_back(pp); } - if (E3 > Ethr) { + if (E3 > fEthr) { Particle psc(curr_particle.GetType(), E3, z_curr); psc.SetWeigth(wi_last); ParticleAtMatrix.push_back(psc); diff --git a/src/module/PhotonEleCa.cpp b/src/module/PhotonEleCa.cpp index 1c038712f..90d1fd515 100644 --- a/src/module/PhotonEleCa.cpp +++ b/src/module/PhotonEleCa.cpp @@ -8,10 +8,12 @@ namespace crpropa { -PhotonEleCa::PhotonEleCa() : +PhotonEleCa::PhotonEleCa(const std::string background, + const std::string &filename) : propagation(new eleca::Propagation) { propagation->ReadTables(getDataPath("eleca_lee.txt")); - propagation->InitBkgArray("CMB"); + propagation->InitBkgArray(background); + output.open(filename.c_str()); } PhotonEleCa::~PhotonEleCa() { @@ -40,7 +42,7 @@ void PhotonEleCa::process(Candidate *candidate) const { #pragma omp critical { - propagation->WriteOutput(p0, ParticleAtGround, 0); + propagation->WriteOutput(output, p0, ParticleAtGround); } candidate->setActive(false); From 26eb330ac64f860744fe139849d0fe957d248a0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Fri, 10 Jan 2014 18:54:28 +0100 Subject: [PATCH 0377/1298] improve EleCa module --- include/crpropa/module/PhotonEleCa.h | 4 + libs/EleCa/EleCa/Constants.h | 20 +-- libs/EleCa/EleCa/Particle.h | 24 +-- libs/EleCa/EleCa/Process.h | 39 ++--- libs/EleCa/EleCa/Propagation.h | 225 ++++++++++++++------------- src/module/PhotonEleCa.cpp | 29 +++- 6 files changed, 177 insertions(+), 164 deletions(-) diff --git a/include/crpropa/module/PhotonEleCa.h b/include/crpropa/module/PhotonEleCa.h index 4ce3aaed0..cf3e4033d 100644 --- a/include/crpropa/module/PhotonEleCa.h +++ b/include/crpropa/module/PhotonEleCa.h @@ -18,11 +18,15 @@ class PhotonEleCa: public Module { private: std::auto_ptr propagation; mutable std::ofstream output; + Vector3d observer; + bool saveOnlyPhotonEnergies; public: PhotonEleCa(const std::string background, const std::string &filename); ~PhotonEleCa(); void process(Candidate *candidate) const; std::string getDescription() const; + void setObserver(const Vector3d &position); + void setSaveOnlyPhotonEnergies(bool photonsOnly); }; } // namespace crpropa diff --git a/libs/EleCa/EleCa/Constants.h b/libs/EleCa/EleCa/Constants.h index 7e40b5db4..0dce7c815 100644 --- a/libs/EleCa/EleCa/Constants.h +++ b/libs/EleCa/EleCa/Constants.h @@ -56,25 +56,7 @@ static const double eps_ph_sup_ciob = 9.9; // [eV] static const double eps_ph_sup_global = eps_ph_sup_cob; // [eV] *global static const double eps_ph_inf_global = eps_ph_inf_urb; // [eV] *global -static const int NsecG = 0; - -static const double z0ph = 0; -static const double E0ph = 0; - -static const int particle_type = 0; -static const double EnergyCM = 0; -static const double GammaEnergy = 0; -static const double BackGamma = 0; -static const double PPxsection = 0; -static const double DPPxsection = 0; -static const double TPPxsection = 0; -static const double ICSxsection = 0; -static const double PPlength = 0; -static const double DPPlength = 0; -static const double TPPlength = 0; -static const double ICSlength = 0; -static const double n_eps2 = 0; -static const double eps2 = 0; + } // namespace eleca diff --git a/libs/EleCa/EleCa/Particle.h b/libs/EleCa/EleCa/Particle.h index 162d4a342..d312ea677 100644 --- a/libs/EleCa/EleCa/Particle.h +++ b/libs/EleCa/EleCa/Particle.h @@ -35,7 +35,7 @@ class Particle { return 1; } - int GetType() { + int GetType() const { return ftype; } @@ -43,7 +43,7 @@ class Particle { ftype = _ft; } - int GetWeigth() { + int GetWeigth() const { return fwi; } @@ -51,7 +51,7 @@ class Particle { fwi = _wi; } - double GetEnergy() { + double GetEnergy() const { return fE0ph; } @@ -60,7 +60,7 @@ class Particle { SetBetaAndMass(); } - double Getz() { + double Getz() const { return fz0ph; } @@ -68,18 +68,18 @@ class Particle { fz0ph = _fz; } - double GetMass() { + double GetMass() const { return fmass; } - double GetBeta() { + double GetBeta() const { return fbeta; } - - bool GetStatus() { - fIsGood = IsGood(); - return fIsGood; - } +// +// bool GetStatus() { +// fIsGood = IsGood(); +// return fIsGood; +// } void SetBetaAndMass() { if (ftype == 22) { @@ -96,7 +96,7 @@ class Particle { void SetB(double B) { fB = B; } - double GetB() { + double GetB() const { return fB; } diff --git a/libs/EleCa/EleCa/Process.h b/libs/EleCa/EleCa/Process.h index 06a03a649..a2ae8a056 100644 --- a/libs/EleCa/EleCa/Process.h +++ b/libs/EleCa/EleCa/Process.h @@ -27,7 +27,7 @@ class Process { double fbackdensity; Process(); - Process(Process&); + Process(const Process&); Process(Particle&, Particle&); Process(Particle&, Particle&, std::string); @@ -36,21 +36,21 @@ class Process { void SetName(std::string nm) { fname = nm; } - std::string &GetName() { + const std::string &GetName() const { return fname; } void SetInteractionAngle(double a) { fInteractionAngle = a; } - double GetInteractionAngle() { + double GetInteractionAngle() const { return fInteractionAngle; } void SetLambda(double le) { flambda = le; } - double GetLambda() { + double GetLambda() const { return flambda; } @@ -69,10 +69,10 @@ class Process { void SetMin(double smin) { fsmin = smin; } - double GetMin() { + double GetMin() const { return fsmin; } - double GetMax() { + double GetMax() const { return fsmax; } @@ -93,11 +93,11 @@ class Process { } - double GetCMEnergy() { + double GetCMEnergy() const { return fCMEnergy; } - void SetIncidentParticle(Particle& p1) { + void SetIncidentParticle(const Particle& p1) { fPi = p1; SetLimits(); } @@ -106,14 +106,14 @@ class Process { SetLimits(); } - Particle &GetIncidentParticle() { + const Particle &GetIncidentParticle() const { return fPi; } - Particle &GetTargetParticle() { + const Particle &GetTargetParticle() const { return fPt; } - std::string GetBackground() { + const std::string &GetBackground() const { return fback; } void SetBackground(std::string BackRad); @@ -170,7 +170,7 @@ Process::Process(Particle& p1, Particle& p2, std::string name) { feps_sup = eps_ph_sup_global; } -Process::Process(Process& proc2) { +Process::Process(const Process& proc2) { fname = proc2.GetName(); SetLimits(proc2.GetMin(), proc2.GetMax()); fCMEnergy = proc2.GetCMEnergy(); @@ -198,33 +198,28 @@ void Process::SetBackground(std::string BackRad) { if (BackRad == "CMB") { eps_min = eps_ph_inf_cmb; eps_max = eps_ph_sup_cmb; - std::cout << "eps range setted to " << eps_min << " , " << eps_max - << std::endl; } else if (BackRad == "COB") { eps_min = eps_ph_inf_cob; eps_max = eps_ph_sup_cob; - std::cout << "eps range setted to " << eps_min << " , " << eps_max - << std::endl; } else if (BackRad == "CIB") { eps_min = eps_ph_inf_cib; eps_max = eps_ph_sup_cib; - std::cout << "eps range setted to " << eps_min << " , " << eps_max - << std::endl; } else if (BackRad == "CIOB") { eps_min = eps_ph_inf_ciob; eps_max = eps_ph_sup_ciob; - std::cout << "eps range setted to " << eps_min << " , " << eps_max - << std::endl; } else if (BackRad == "URB") { eps_min = eps_ph_inf_urb; eps_max = eps_ph_sup_urb; - std::cout << "eps range setted to " << eps_min << " , " << eps_max - << std::endl; } feps_inf = eps_min; feps_sup = eps_max; +#ifdef DEBUG_ELECA + std::cout << "eps range set to " << eps_min << " , " << eps_max + << std::endl; +#endif + } void Process::SetLimits(Particle& p1, std::string nameproc) { diff --git a/libs/EleCa/EleCa/Propagation.h b/libs/EleCa/EleCa/Propagation.h index 6bf1d1c18..f8b76b4fd 100644 --- a/libs/EleCa/EleCa/Propagation.h +++ b/libs/EleCa/EleCa/Propagation.h @@ -24,7 +24,8 @@ class Propagation { double vICSle[1101]; double vEtab[1101]; - double BkgArray[POINTS_VERY_FEW][2]; + std::vector BkgE, BkgA; + std::string Bkg; double fEthr; public: @@ -50,15 +51,17 @@ class Propagation { double GetMeanThetaBFDeflection(double Bin, double Ein, int ptype, double Lin) const; - double GetLambdaTab(Process proc, std::string procName) const; + double GetLambdaTab(const Process &proc, const std::string &procName) const; double ExtractMinDist(Process &proc, int type, double R, double R2, - std::vector Etarget) const; - std::vector GetEtarget(Process &proc, Particle &particle) const; + std::vector &Etarget) const; + std::vector GetEtarget(Process &proc, + const Particle &particle) const; void Propagate(Particle &curr_particle, std::vector &ParticleAtMatrix, std::vector &ParticleAtGround) const; double ExtractPhotonEnergyMC(double z, Process &proc) const; double ShootPhotonEnergyMC(double z) const; + double ShootPhotonEnergyMC(double Emin, double z) const; void SetInitVar(std::vector > bk, std::vector > *le) const; @@ -88,7 +91,7 @@ void Propagation::ReadTables(const std::string &filename) { fin >> Etab >> PPle >> ICSle >> DPPle >> TPPle; vEtab[k] = Etab; vPPle[k] = PPle; - vICSle[k] = Etab; + vICSle[k] = ICSle; vDPPle[k] = DPPle; vTPPle[k] = TPPle; k++; @@ -103,81 +106,66 @@ void Propagation::InitBkgArray(const std::string &BackRad) { // Routine to build the array of cumulative distribution of // background photons - std::vector > BkgArray0; + Bkg = BackRad; + BkgE.resize(POINTS_VERY_FEW); + BkgA.resize(POINTS_VERY_FEW); - int i = 0; - double epsinf = 0; - double epssup = 0; - std::vector tmp; - tmp.resize(2); if (BackRad == "CMB") { - double de = pow((double) eps_ph_sup_cmb / eps_ph_inf_cmb, 1. / 100.); - for (double e = eps_ph_inf_cmb; e <= eps_ph_sup_cmb; e *= de) { - tmp.at(0) = e; - if (i == 0) - tmp.at(1) = CMBR(e); - else - tmp.at(1) = BkgArray0.at(i - 1).at(1) + CMBR(e); - - BkgArray0.push_back(tmp); - i++; + double de = pow((double) eps_ph_sup_cmb / eps_ph_inf_cmb, + 1. / POINTS_VERY_FEW); + double e = eps_ph_inf_cmb; + for (size_t i = 0; i < POINTS_VERY_FEW; i++) { + BkgE[i] = e; + BkgA[i] = CMBR(e); + e *= de; } } if (BackRad == "CIOB") { - double de = pow((double) eps_ph_sup_ciob / eps_ph_inf_ciob, 1. / 100.); - - for (double e = eps_ph_inf_ciob; e <= eps_ph_sup_ciob; e *= de) { - tmp.clear(); - tmp.push_back(e); - if (i == 0) - tmp.push_back(CIOBR(e)); - else - tmp.push_back(BkgArray0.at(i - 1).at(1) + CIOBR(e)); - - BkgArray0.push_back(tmp); - i++; + double de = pow((double) eps_ph_sup_ciob / eps_ph_inf_ciob, + 1. / POINTS_VERY_FEW); + double e = eps_ph_inf_ciob; + for (size_t i = 0; i < POINTS_VERY_FEW; i++) { + BkgE[i] = e; + BkgA[i] = CIOBR(e); + e *= de; } } if (BackRad == "URB") { - double de = pow((double) eps_ph_sup_urb / eps_ph_inf_urb, 1. / 100.); - for (double e = eps_ph_inf_urb; e <= eps_ph_sup_urb; e *= de) { - tmp.clear(); - tmp.push_back(e); - - if (i == 0) - tmp.push_back(URB(e)); - else - tmp.push_back(BkgArray0.at(i - 1).at(1) + URB(e)); - - BkgArray0.push_back(tmp); - i++; + double de = pow((double) eps_ph_sup_urb / eps_ph_inf_urb, + 1. / POINTS_VERY_FEW); + double e = eps_ph_inf_urb; + for (size_t i = 0; i < POINTS_VERY_FEW; i++) { + BkgE[i] = e; + BkgA[i] = URB(e); + e *= de; } } - if (BackRad != "CMB" && BackRad != "CIOB") { + if (BackRad == "URB") { double de = pow((double) eps_ph_sup_global / eps_ph_inf_global, (double) 1. / POINTS_VERY_FEW); - for (double e = eps_ph_inf_global; e <= eps_ph_sup_global; e *= de) { - tmp.at(0) = e; - if (i == 0) - tmp.at(1) = CBR(e); - else - tmp.at(1) = BkgArray0.at(i - 1).at(1) + CBR(e); - BkgArray0.push_back(tmp); - i++; + double e = eps_ph_inf_global; + for (size_t i = 0; i < POINTS_VERY_FEW; i++) { + BkgE[i] = e; + BkgA[i] = CBR(e); + e *= de; } } - double a = 1.0 / BkgArray0.at(i - 1).at(1); - - for (i = 0; i < POINTS_VERY_FEW; i++) - BkgArray0.at(i).at(1) *= a; + // cumulate + for (size_t i = 1; i < POINTS_VERY_FEW; i++) { + BkgA[i] += BkgA[i - 1]; + } - for (int k = 0; k < POINTS_VERY_FEW; k++) { - BkgArray[k][0] = BkgArray0[k][0]; - BkgArray[k][1] = BkgArray0[k][1]; + // normalize + double a = 1.0 / BkgA[POINTS_VERY_FEW - 1]; + for (size_t i = 0; i < POINTS_VERY_FEW; i++) { + BkgA[i] *= a; +#ifdef DEBUG_ELECA + std::cout << BkgE[i] << " - " << BkgA[i] << std::endl; +#endif } } @@ -197,7 +185,7 @@ double Propagation::GetMeanThetaBFDeflection(double Bin, double Ein, int ptype, } double Propagation::ExtractMinDist(Process &proc, int type, double R, double R2, - std::vector Etarget) const { + std::vector &Etarget) const { double min_dist1 = 0; double min_dist2 = 0; @@ -260,6 +248,12 @@ double Propagation::ExtractMinDist(Process &proc, int type, double R, double R2, tmp_lambda2 = GetLambdaTab(proc2, "TPP"); min_dist2 = -tmp_lambda2 * log(R2); +#ifdef DEBUG_ELECA + std::cerr << "comparing 2 mindists: " << min_dist1 << "(" + << tmp_lambda1 << ") vs " << min_dist2 << " ( " + << tmp_lambda2 << ") " << std::endl; +#endif + if (min_dist2 < min_dist1) { min_dist1 = min_dist2; proc.SetName("TPP"); @@ -281,7 +275,8 @@ double Propagation::ExtractMinDist(Process &proc, int type, double R, double R2, return min_dist1; } -double Propagation::GetLambdaTab(Process proc, std::string procName) const { +double Propagation::GetLambdaTab(const Process &proc, + const std::string &procName) const { double E1 = proc.GetIncidentParticle().GetEnergy(); double z = proc.GetIncidentParticle().Getz(); @@ -329,10 +324,23 @@ double Propagation::GetLambdaTab(Process proc, std::string procName) const { double Propagation::ShootPhotonEnergyMC(double z) const { // Routine for the MC sampling of background photon energy +// double interpolate(double x, const std::vector &X, +// const std::vector &Y) { +// std::vector::const_iterator it = std::upper_bound(X.begin(), +// X.end(), x); +// if (it == X.begin()) +// return Y.front(); +// if (it == X.end()) +// return Y.back(); +// +// size_t i = it - X.begin() - 1; +// return Y[i] + (x - X[i]) * (Y[i + 1] - Y[i]) / (X[i + 1] - X[i]); +// } + double h = Uniform(0, 1); for (int i = 0; i < POINTS_VERY_FEW; i++) { - if (h < BkgArray[i][1]) { - return BkgArray[i][0] * (1. + z); + if (h < BkgA[i]) { + return BkgE[i] * (1. + z); break; } } @@ -344,8 +352,36 @@ double Propagation::ShootPhotonEnergyMC(double z) const { return 0.; } +double Propagation::ShootPhotonEnergyMC(double Emin, double z) const { + // Routine for the MC sampling of background photon energy + std::vector::const_iterator it; + + // find lowest energy bin + + it = std::lower_bound(BkgE.begin(), BkgE.end(), Emin); + size_t iE; + if (it == BkgE.begin()) + iE = 0; + else if (it == BkgE.end()) + iE = BkgE.size() - 1; + else + iE = it - BkgE.begin(); + + // random number in selected range + double h = Uniform(BkgA[iE], 1); + + // find energy for random number + it = std::upper_bound(BkgA.begin(), BkgA.end(), h); + if (it == BkgA.begin()) + return BkgE.front(); + else if (it == BkgA.end()) + return BkgE.back(); + else + return BkgE[it - BkgA.begin()]; +} + std::vector Propagation::GetEtarget(Process &proc, - Particle &particle) const { + const Particle &particle) const { std::vector Etarget; double Etarget_tmp = 0; @@ -357,20 +393,14 @@ std::vector Propagation::GetEtarget(Process &proc, proc.SetName("PP"); proc.SetLimits(); smintmp = proc.GetMin(); - Etarget_tmp = 0; - while (Etarget_tmp < ElectronMass * ElectronMass / Energy) { - Etarget_tmp = ShootPhotonEnergyMC(z_curr); - } + Etarget_tmp = ShootPhotonEnergyMC(ElectronMass * ElectronMass / Energy, + z_curr); Etarget.push_back(Etarget_tmp); proc.SetName("DPP"); proc.SetLimits(); smintmp = proc.GetMin(); - Etarget_tmp = 0; - - while (Etarget_tmp < smintmp / (4.0 * Energy)) { - Etarget_tmp = ShootPhotonEnergyMC(z_curr); - } + Etarget_tmp = ShootPhotonEnergyMC(smintmp / (4.0 * Energy), z_curr); Etarget.push_back(Etarget_tmp); } @@ -378,20 +408,13 @@ std::vector Propagation::GetEtarget(Process &proc, proc.SetName("ICS"); proc.SetLimits(); smintmp = proc.GetMin(); - Etarget_tmp = 0; - while (Etarget_tmp < smintmp / (4.0 * Energy)) { - Etarget_tmp = ShootPhotonEnergyMC(z_curr); - } + Etarget_tmp = ShootPhotonEnergyMC(smintmp / (4.0 * Energy), z_curr); Etarget.push_back(Etarget_tmp); proc.SetName("TPP"); proc.SetLimits(); smintmp = proc.GetMin(); - Etarget_tmp = 0; - - while (Etarget_tmp < smintmp / (4.0 * Energy)) { - Etarget_tmp = ShootPhotonEnergyMC(z_curr); - } + Etarget_tmp = ShootPhotonEnergyMC(smintmp / (4.0 * Energy), z_curr); Etarget.push_back(Etarget_tmp); } //end e/e else @@ -409,26 +432,15 @@ std::vector Propagation::GetEtarget(Process &proc, double Propagation::ExtractPhotonEnergyMC(double z, Process &proc) const { double esoft = 0; - double snew = 0; +//double snew = 0; double emin = proc.GetMin(); Particle pi = proc.GetIncidentParticle(); Particle pb = proc.GetTargetParticle(); double Epi = pi.GetEnergy(); double m = pi.GetMass(); - while (esoft < emin / (4.0 * Epi)) { - - double h = Uniform(0, 1); - - for (int i = 0; i < POINTS_VERY_FEW; i++) { - if (h < BkgArray[i][1]) { - esoft = BkgArray[i][0] * (1. + z); - break; - } - } - - snew = 4 * Epi * esoft + m * m; - } + esoft = ShootPhotonEnergyMC(emin / (4.0 * Epi), z); + //snew = 4 * Epi * esoft + m * m; pb.SetEnergy(esoft); proc.SetTargetParticle(pb); proc.SetCMEnergy(); @@ -505,19 +517,21 @@ void Propagation::Propagate(Particle &curr_particle, double R = Uniform(0.0, 1.0); double R2 = Uniform(0.0, 1.0); - bool fast = 1; + bool fast = 0; Process proc; proc.SetIncidentParticle(curr_particle); + proc.SetBackground(Bkg); -#ifdef DEBUG_ELECA - std::cout << "GetEtarget " << std::endl; -#endif std::vector EtargetAll = GetEtarget(proc, curr_particle); #ifdef DEBUG_ELECA - std::cout << "ExtractMinDist " << std::endl; + std::cout << "GetEtarget: " << EtargetAll[0] << " " << EtargetAll[1] << std::endl; #endif + min_dist = ExtractMinDist(proc, curr_particle.GetType(), R, R2, EtargetAll); +#ifdef DEBUG_ELECA + std::cout << "ExtractMinDist " << min_dist << std::endl; +#endif interacted = 0; double dz = 0; @@ -528,8 +542,7 @@ void Propagation::Propagate(Particle &curr_particle, double min_dist_last = min_dist; #ifdef DEBUG_ELECA - std::cout << "starting propagation... min_dist_last: " << min_dist_last - << std::endl; + std::cout << "starting propagation... min_dist_last: " << min_dist_last << std::endl; #endif while (!interacted) { @@ -565,11 +578,9 @@ void Propagation::Propagate(Particle &curr_particle, << " walkdone + realpath > min_dist: correcting realpath from" << realpath << " to " << min_dist - walkdone << " and the stepsize is changed from " << dz << " to "; -#endif realpath = min_dist - walkdone; stepsize = realpath * corrB_factor; dz = Mpc2z(stepsize); -#ifdef DEBUG_ELECA std::cout << dz << std::endl; #endif interacted = 1; diff --git a/src/module/PhotonEleCa.cpp b/src/module/PhotonEleCa.cpp index 90d1fd515..b3c10659f 100644 --- a/src/module/PhotonEleCa.cpp +++ b/src/module/PhotonEleCa.cpp @@ -10,7 +10,7 @@ namespace crpropa { PhotonEleCa::PhotonEleCa(const std::string background, const std::string &filename) : - propagation(new eleca::Propagation) { + propagation(new eleca::Propagation), saveOnlyPhotonEnergies(false) { propagation->ReadTables(getDataPath("eleca_lee.txt")); propagation->InitBkgArray(background); output.open(filename.c_str()); @@ -23,9 +23,13 @@ void PhotonEleCa::process(Candidate *candidate) const { if (candidate->current.getId() != 22) return; // do nothing if not a photon + double z = candidate->getRedshift(); + if (z == 0) + z = eleca::Mpc2z( + (candidate->current.getPosition() - observer).getR() / Mpc); eleca::Particle p0(candidate->current.getId(), - candidate->current.getEnergy() / eV, candidate->getRedshift()); - + candidate->current.getEnergy() / eV, z); + p0.SetB(1e-9); std::vector ParticleAtMatrix; std::vector ParticleAtGround; ParticleAtMatrix.push_back(p0); @@ -42,13 +46,30 @@ void PhotonEleCa::process(Candidate *candidate) const { #pragma omp critical { - propagation->WriteOutput(output, p0, ParticleAtGround); + if (saveOnlyPhotonEnergies) { + for (int i = 0; i < ParticleAtGround.size(); ++i) { + eleca::Particle &p = ParticleAtGround[i]; + if (p.GetType() != 22) + continue; + output << p.GetEnergy() << "\n"; + } + } else { + propagation->WriteOutput(output, p0, ParticleAtGround); + } } candidate->setActive(false); return; } +void PhotonEleCa::setObserver(const Vector3d &position) { + observer = position; +} + +void PhotonEleCa::setSaveOnlyPhotonEnergies(bool photonsOnly) { + saveOnlyPhotonEnergies = photonsOnly; +} + std::string PhotonEleCa::getDescription() const { std::stringstream s; s << "PhotonEleCa"; From 232e0f0dee0a5ca012db419d931da7a06d3cc680 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 13 Jan 2014 17:55:51 +0100 Subject: [PATCH 0378/1298] add *.pyc to .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 272c438a4..65e818346 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ build/* data/* data-tools/* -*.png \ No newline at end of file +*.png +*.pyc From 2da6cf03c95b56864c8ff0b23fbb0bdd49ccd68b Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 13 Jan 2014 18:09:27 +0100 Subject: [PATCH 0379/1298] fixed broken python test still broken are: testEnergyLossLength testPhotoDisintegration testPhotoPionProduction testPhotoPionProduction_pnRatio --- test/python/testDeflectionCK.py | 57 +++++++++++++------------- test/python/testJF12Field.py | 2 +- test/python/testSourceComposition.py | 36 ++++++++-------- test/python/testTurbulentDeflection.py | 2 +- 4 files changed, 48 insertions(+), 49 deletions(-) diff --git a/test/python/testDeflectionCK.py b/test/python/testDeflectionCK.py index fba47d24d..0a69b44c4 100644 --- a/test/python/testDeflectionCK.py +++ b/test/python/testDeflectionCK.py @@ -15,38 +15,38 @@ field = UniformMagneticField(Vector3d(0, 0, 10 * nG)) # resulting gyroradius -R = c.current.getMomentum().getMag() / c.current.getCharge() / (10 * nG) +R = c.current.getMomentum().getR() / c.current.getCharge() / (10 * nG) def propagate(tolerance): - prop = DeflectionCK(field, tolerance, 0.1 * kpc) - maxLen = MaximumTrajectoryLength(2 * pi * R) + prop = DeflectionCK(field, tolerance, 0.1 * kpc) + maxLen = MaximumTrajectoryLength(2 * pi * R) - c.setTrajectoryLength(0) - c.setCurrentStep(0) - c.setNextStep(1 * Mpc) # set a large initial step, so that an initial acceleration is uneccessary - c.current.setPosition(Vector3d(0, R, 0)) - c.current.setDirection(Vector3d(1, 0, 0)) - c.setActive(True) + c.setTrajectoryLength(0) + c.setCurrentStep(0) + c.setNextStep(1 * Mpc) # set a large initial step, so that an initial acceleration is uneccessary + c.current.setPosition(Vector3d(0, R, 0)) + c.current.setDirection(Vector3d(1, 0, 0)) + c.setActive(True) - posX, posY, dirX, dirY, dirDeviation, theta = [], [], [], [], [], [] - nSteps = 0 - while c.isActive(): - prop.process(c) - maxLen.process(c) - nSteps +=1 + posX, posY, dirX, dirY, dirDeviation, theta = [], [], [], [], [], [] + nSteps = 0 + while c.isActive(): + prop.process(c) + maxLen.process(c) + nSteps +=1 - posX.append(c.current.getPosition().x) - posY.append(c.current.getPosition().y) + posX.append(c.current.getPosition().x) + posY.append(c.current.getPosition().y) - dirX.append(c.current.getDirection().x) - dirY.append(c.current.getDirection().y) + dirX.append(c.current.getDirection().x) + dirY.append(c.current.getDirection().y) - t = c.getTrajectoryLength() / R - theta.append(t) - dirDeviation.append(c.current.getDirection().dot(Vector3d(cos(t), -sin(t), 0))) + t = c.getTrajectoryLength() / R + theta.append(t) + dirDeviation.append(c.current.getDirection().dot(Vector3d(cos(t), -sin(t), 0))) - return array(posX), array(posY), array(dirX), array(dirY), array(dirDeviation), array(theta), nSteps + return array(posX), array(posY), array(dirX), array(dirY), array(dirDeviation), array(theta), nSteps @@ -81,8 +81,8 @@ def propagate(tolerance): ### Directional error as function of distance for different tolerances figure() for tolerance in [1e-3, 1e-4, 1e-5, 1e-6]: - posX, posY, dirX, dirY, dirDev, theta, n = propagate(tolerance) - plot(theta/2/pi, arccos(dirDev)*180/pi, label='%.0e, %i'%(tolerance, n)) + posX, posY, dirX, dirY, dirDev, theta, n = propagate(tolerance) + plot(theta/2/pi, arccos(dirDev)*180/pi, label='%.0e, %i'%(tolerance, n)) legend(title='Tolerance, Steps', loc='upper left') xlabel(r'Travelled Distance / $2 \pi R_L$') ylabel(r'Direction Error [$^\circ$]') @@ -93,9 +93,9 @@ def propagate(tolerance): ### Positional error as function of distance for different tolerances figure() for tolerance in [1e-3, 1e-4, 1e-5, 1e-6]: - posX, posY, dirX, dirY, dirDev, theta, n = propagate(tolerance) - displacement = ((posX/R - sin(theta))**2 + (posY/R - cos(theta))**2 )**.5 - plot(theta/2/pi, displacement, label='%.0e, %i'%(tolerance, n)) + posX, posY, dirX, dirY, dirDev, theta, n = propagate(tolerance) + displacement = ((posX/R - sin(theta))**2 + (posY/R - cos(theta))**2 )**.5 + plot(theta/2/pi, displacement, label='%.0e, %i'%(tolerance, n)) legend(title='Tolerance, Steps', loc='upper left') xlabel(r'Travelled Distance / $2 \pi R_L$') ylabel(r'Position Error / $R_L$') @@ -105,4 +105,3 @@ def propagate(tolerance): savefig('DeflectionCK_xdeviation.png',bbox_inches='tight') show() - diff --git a/test/python/testJF12Field.py b/test/python/testJF12Field.py index 12ebaa5f6..b8cc77bb2 100644 --- a/test/python/testJF12Field.py +++ b/test/python/testJF12Field.py @@ -22,7 +22,7 @@ for i,x in enumerate(samples): for j,y in enumerate(samples): pos = Vector3d(x, y, z) * kpc - B[i, j] = bField.getField(pos).getMag() / gauss # B in [G] + B[i, j] = bField.getField(pos).getR() / gauss # B in [G] figure() maB = ma.masked_array(B, B==0) diff --git a/test/python/testSourceComposition.py b/test/python/testSourceComposition.py index 3c9fb4ece..454b45392 100644 --- a/test/python/testSourceComposition.py +++ b/test/python/testSourceComposition.py @@ -1,5 +1,5 @@ # CRPropa test script -# Simulates the integrated relative abundance from a source, +# Simulates the integrated relative abundance from a source, # accelerationg particles up to a maximum rigidity. # Minimum energy = 10 EeV # Maximum rigidity = 100 EeV / Z -> max. energy = Z * 100 EeV @@ -16,32 +16,32 @@ print 'simulating for spectral index' for i in range(nS): - beta = 2 + i/float(nS - 1) + beta = 2 + i/float(nS - 1) - composition = SourceComposition(10, 100, -beta) - composition.add(1, 1, 92000) - composition.add(4, 2, 13000) - composition.add(12, 6, 447.4) - composition.add(16, 8, 526.3) - composition.add(28, 14, 100) - composition.add(56, 26, 97) + composition = SourceComposition(10, 100, -beta) + composition.add(1, 1, 92000) + composition.add(4, 2, 13000) + composition.add(12, 6, 447.4) + composition.add(16, 8, 526.3) + composition.add(28, 14, 100) + composition.add(56, 26, 97) - state = ParticleState() + ps = ParticleState() - for j in range(nP): - composition.prepare(state) - z = chargeNumberFromNucleusId(state.getId()) - d[z][i] += 1 + for j in range(nP): + composition.prepare(ps) + z = chargeNumber(ps.getId()) + d[z][i] += 1 - norm = float(d[1][i]) - for z in d.keys(): - d[z][i] /= norm + norm = float(d[1][i]) + for z in d.keys(): + d[z][i] /= norm figure() beta = linspace(2, 3, nS) elements = {1:'H', 2:'He', 6:'C', 8:'O', 14:'Si', 26:'Fe'} for z in d.keys(): - plt.plot(beta, d[z], label=elements[z]) + plt.plot(beta, d[z], label=elements[z]) legend(loc = 'lower right') xlabel(r'Source Spectral Index $\beta$') diff --git a/test/python/testTurbulentDeflection.py b/test/python/testTurbulentDeflection.py index 982d81a78..db9a1ced5 100644 --- a/test/python/testTurbulentDeflection.py +++ b/test/python/testTurbulentDeflection.py @@ -47,7 +47,7 @@ x = c.current.getPosition() / Mpc p = c.current.getDirection() p0 = c.source.getDirection() - distance[i] += x.getMag() + distance[i] += x.getR() rms1[i] += (x.getAngleTo(p))**2 rms2[i] += (p0.getAngleTo(p))**2 From 78a2264ef7d672052183932d1af70f715c3c512b Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 13 Jan 2014 18:31:06 +0100 Subject: [PATCH 0380/1298] fix script for testing photo-pion pn-ratio remove testPhotoPionProduction.py and testPhotoDisintegration.py which were using a circular argument for the test and are not easily adapted to new stochastic interaction interface. --- test/python/testPhotoDisintegration.py | 81 ------------------- test/python/testPhotoPionProduction.py | 50 ------------ .../python/testPhotoPionProduction_pnRatio.py | 26 +++--- 3 files changed, 12 insertions(+), 145 deletions(-) delete mode 100644 test/python/testPhotoDisintegration.py delete mode 100644 test/python/testPhotoPionProduction.py diff --git a/test/python/testPhotoDisintegration.py b/test/python/testPhotoDisintegration.py deleted file mode 100644 index cd900e5ee..000000000 --- a/test/python/testPhotoDisintegration.py +++ /dev/null @@ -1,81 +0,0 @@ -# CRPRopa test script -# Plot and self consistency check for photo disintegration -# -from crpropa import * -from pylab import * - - -pid = nucleusId(4,2) # nucleus to test - - -def get_rates(candidate, N=5000): - # perform N interactions - D = {} - for i in range(N): - interaction = InteractionState() - pdModule.setNextInteraction(candidate, interaction) - if interaction.channel == 0: - continue - D.setdefault(interaction.channel, []).append(interaction.distance) - - # calculte exclusive mean interaction lengths - for k in D.keys(): - l = array(D[k]) - p = len(l) / float(N) # probability for channel - l = mean(l) / p / Mpc # exclusive decay length in Mpc - D[k] = 1 / l # exclusive decay rate in 1/Mpc - return D - -def get_data_rates(pid): - D = {} - for i in range(len(table)): - z, n = int(table[i][0]), int(table[i][1]) - if nucleusId(z+n, z) != pid: - continue - channel = table[i][2] - rates = table[i][3:] - D[channel] = rates - return D - -def parse_pid(pid): - return 'Z=%i, A=%i'%((pid//10000)%1000, (pid%10000)/10) - -def parse_channel(channel): - s = '%06d' % channel - d = list(map(int, s)) - s = 'n, ' * d[0] + 'p, ' * d[1] + 'H$^2$, ' * d[2] + 'H$^3$, ' * d[3] + 'He$^3$, ' * d[4] + 'He$^4$, ' * d[5] - return s[0:-2] - - -candidate = Candidate() -candidate.current.setId(pid) - -table = genfromtxt(getDataPath('photodis_CMB.txt')) -pdModule = PhotoDisintegration(CMB) -gamma = logspace(6, 14, 200) -gamma2 = gamma[1::5] - -Dsim = {} -for i,g in enumerate(gamma2): - candidate.current.setLorentzFactor(g) - D = get_rates(candidate) - for k in D.keys(): - Dsim.setdefault(k, zeros(len(gamma2)))[i] = D[k] - -Ddata = get_data_rates(pid) - - -for k in Dsim.keys(): - figure() - plot(gamma2, Dsim[k], 'k+') - plot(gamma, Ddata[k], 'b') - s = 'Nucleus ' + parse_pid(pid) + '\nDisintegration Channel ' + parse_channel(k) - text(0.1, 0.85, s, transform=gca().transAxes) - xlabel('Lorentzfactor $\gamma$') - ylabel('Rate [1/Mpc]') - ylim(1e-6, 1e3) - loglog() - grid() - savefig('PhotoDisintegration_' + str(pid) + '_' + str(k) + '.png', bbox_inches='tight') - show() - diff --git a/test/python/testPhotoPionProduction.py b/test/python/testPhotoPionProduction.py deleted file mode 100644 index c289618ff..000000000 --- a/test/python/testPhotoPionProduction.py +++ /dev/null @@ -1,50 +0,0 @@ -# CRPRopa test script -# Plot and self consistency check for photo pion production -# -from crpropa import * -from pylab import * - - -def getRate(module, energy, charge): - c = Candidate() - c.current.setId(nucleusId(1, charge)) - c.current.setEnergy(energy) - - N = 5000 - l = 0 - for i in range(N): - s = InteractionState() - module.setNextInteraction(c, s) - l += s.distance / Mpc / N - - return 1 / l - -def compare(dataFileName, photonField, plotFileName): - E_data, P_data, N_data = genfromtxt(dataFileName, unpack=1) - E = E_data[1:-1:5] - p = zeros(len(E)) - n = zeros(len(E)) - - ppp = PhotoPionProduction(photonField) - for i,energy in enumerate(E*EeV): - p[i] = getRate(ppp, energy, 1) - n[i] = getRate(ppp, energy, 0) - - figure() - plot(E_data, P_data, "r", label="Proton data table") - plot(E, p, 'k+', label="Proton") - plot(E_data, N_data, "b", label="Neutron data table") - plot(E, n, 'k.', label="Neutron") - xlabel('Energy [EeV]') - ylabel('Rate [1/Mpc]') - legend(loc='center right') - grid() - loglog() - xlim(10, 1e5) - ylim(1e-4, 1) - savefig(plotFileName) - -compare(getDataPath('photopion_CMB.txt'), CMB, 'PhotoPionProduction_CMB.png') -compare(getDataPath('photopion_IRB.txt'), IRB, 'PhotoPionProduction_IRB.png') - -show() diff --git a/test/python/testPhotoPionProduction_pnRatio.py b/test/python/testPhotoPionProduction_pnRatio.py index be8791aba..cd077acf8 100644 --- a/test/python/testPhotoPionProduction_pnRatio.py +++ b/test/python/testPhotoPionProduction_pnRatio.py @@ -5,27 +5,25 @@ from pylab import * -spp = SophiaPhotoPionProduction() +ppp = PhotoPionProduction() c = Candidate() -s = InteractionState() def getPNRatio(E): - nP, nN = 0, 0 - for i in range(2000): - c.current.setId(nucleusId(1, 1)) - c.current.setEnergy(E * EeV) - spp.setNextInteraction(c, s) - spp.performInteraction(c) - if c.current.getId() == nucleusId(1,1): - nP += 1. - if c.current.getId() == nucleusId(1,0): - nN += 1. - return nP / nN + nP, nN = 0., 0. + for i in range(2000): + c.current.setId(nucleusId(1, 1)) + c.current.setEnergy(E * EeV) + ppp.performInteraction(c, 1) + if c.current.getId() == nucleusId(1,1): + nP += 1 + if c.current.getId() == nucleusId(1,0): + nN += 1 + return nP / nN E = logspace(log10(50), 4, 20) Rpn = zeros(20) for i in range(20): - Rpn[i] = getPNRatio(E[i]) + Rpn[i] = getPNRatio(E[i]) figure() plot(E, Rpn) From 9aab7305115079eb43e54a71b68c0315a914baf4 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 13 Jan 2014 19:03:27 +0100 Subject: [PATCH 0381/1298] small refactoring of epair-production --- .../crpropa/module/ElectronPairProduction.h | 6 +++--- src/module/ElectronPairProduction.cpp | 21 +++++++++---------- test/testInteraction.cpp | 6 +++--- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/include/crpropa/module/ElectronPairProduction.h b/include/crpropa/module/ElectronPairProduction.h index 4a55c8ed4..0143c3a02 100644 --- a/include/crpropa/module/ElectronPairProduction.h +++ b/include/crpropa/module/ElectronPairProduction.h @@ -17,7 +17,7 @@ namespace crpropa { class ElectronPairProduction: public Module { private: PhotonField photonField; - std::vector tabLossLength; /*< tabulated energy loss rate in [J/m] for protons at z = 0*/ + std::vector tabLossRate; /*< tabulated energy loss rate in [J/m] for protons at z = 0*/ std::vector tabLorentzFactor; /*< tabulated proton energy [J] */ public: @@ -28,7 +28,7 @@ class ElectronPairProduction: public Module { void process(Candidate *candidate) const; /** - Calculates the inverse energy loss length beta = -1/E dE/dx in [1/m] + Calculates the energy loss length 1/beta = -E dx/dE in [m] @param id PDG particle ID @param lf Lorentz factor @param z redshift @@ -40,7 +40,7 @@ class ElectronPairProduction: public Module { beta_A,Z(E) = Z^2 / A * beta_p(E/A) beta(E,z) = (1+z)^3 beta((1+z)E). */ - double invLossLength(int id, double lf, double z) const; + double lossLength(int id, double lf, double z) const; }; } // namespace crpropa diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 61a4a771e..f655bcce9 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -50,7 +50,7 @@ void ElectronPairProduction::init(std::string filename) { infile >> a >> b; if (infile) { tabLorentzFactor.push_back(a * eV / mass_proton / c_squared); - tabLossLength.push_back(b / a / Mpc); + tabLossRate.push_back(b / a / Mpc); } } infile.ignore(std::numeric_limits < std::streamsize > ::max(), '\n'); @@ -58,25 +58,24 @@ void ElectronPairProduction::init(std::string filename) { infile.close(); } -double ElectronPairProduction::invLossLength(int id, double lf, - double z) const { +double ElectronPairProduction::lossLength(int id, double lf, double z) const { double Z = chargeNumber(id); if (Z == 0) - return 0; // no pair production on uncharged particles + return std::numeric_limits::max(); // no pair production on uncharged particles lf *= (1 + z); if (lf < tabLorentzFactor.front()) - return 0; // below energy threshold + return std::numeric_limits::max(); // below energy threshold - double length; + double rate; if (lf < tabLorentzFactor.back()) - length = interpolate(lf, tabLorentzFactor, tabLossLength); // interpolation + rate = interpolate(lf, tabLorentzFactor, tabLossRate); // interpolation else - length = tabLossLength.back() * pow(lf / tabLorentzFactor.back(), -0.6); // extrapolation + rate = tabLossRate.back() * pow(lf / tabLorentzFactor.back(), -0.6); // extrapolation double A = nucleusMass(id) / mass_proton; // more accurate than massNumber(Id) - return length * Z * Z / A * pow(1 + z, 3) - * photonFieldScaling(photonField, z); + rate *= Z * Z / A * pow(1 + z, 3) * photonFieldScaling(photonField, z); + return 1. / rate; } void ElectronPairProduction::process(Candidate *c) const { @@ -87,7 +86,7 @@ void ElectronPairProduction::process(Candidate *c) const { double lf = c->current.getLorentzFactor(); double z = c->getRedshift(); double step = c->getCurrentStep() / (1 + z); // step size in local frame - double loss = invLossLength(id, lf, z) * step; + double loss = step / lossLength(id, lf, z); c->current.setLorentzFactor(lf * (1 - loss)); } diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 62b93f413..f74e88468 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -50,7 +50,7 @@ TEST(ElectronPairProduction, belowEnergyTreshold) { double E = 1e14 * eV; c.current.setEnergy(E); epp.process(&c); - EXPECT_DOUBLE_EQ(c.current.getEnergy(), E); + EXPECT_DOUBLE_EQ(E, c.current.getEnergy()); } TEST(ElectronPairProduction, thisIsNotNucleonic) { @@ -61,7 +61,7 @@ TEST(ElectronPairProduction, thisIsNotNucleonic) { double E = 1e20 * eV; c.current.setEnergy(E); epp.process(&c); - EXPECT_DOUBLE_EQ(c.current.getEnergy(), E); + EXPECT_DOUBLE_EQ(E, c.current.getEnergy()); } TEST(ElectronPairProduction, valuesCMB) { @@ -92,7 +92,7 @@ TEST(ElectronPairProduction, valuesCMB) { epp.process(&c); double dE = x[i] - c.current.getEnergy(); double dE_table = y[i] * 1 * Mpc; - EXPECT_NEAR(dE, dE_table, 1e-12); + EXPECT_NEAR(dE_table, dE, 1e-12); } } From 5b71700743c473fdbb6d57c6f98375d0856dbc45 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 22 Jan 2014 14:15:32 +0100 Subject: [PATCH 0382/1298] update readme --- README.md | 97 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 65 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index c2fba7068..c40df251b 100644 --- a/README.md +++ b/README.md @@ -1,56 +1,89 @@ CRPropa3 ======== -Development version of CRPropa. Use on your own risk. - -Install from source ------------------------- -1. Download the latest data archive from https://crpropa.desy.de/Interaction_data and extract to CRPropa3/data +This is the development version of [CRPropa](https://crpropa.desy.de/Main_Page). +It features a very flexible setup of simulation, support for specialized extragalactic magnetic fields, galactic lensing, python - steering and parallelization. + +## Install from source +1. Download the data repository +``` +cd CRPropa3 +git clone https://github.com/CRPropa/CRPropa3-data.git data +``` 2. CRPropa uses CMAKE to configure. From the build directory call ccmake or cmake - - cd build - ccmake .. - +``` +cd build +ccmake .. +``` 3. Afterward configuring run make and make install as usual +``` +make +make install +``` - make - make install - -The install path can be set with -DCMAKE_INSTALL_PREFIX=/my/path or with the option browser when using ccmake. +The install path can be set with -DCMAKE_INSTALL_PREFIX=/my/path or with the option browser when using ccmake. -Notes for Intel Compiler: -use -DCMAKE_SHARED_LINKER_FLAGS="-lifcore" -DCMAKE_Fortran_COMPILER=ifort +Notes for Intel Compiler: +use -DCMAKE_SHARED_LINKER_FLAGS="-lifcore" -DCMAKE_Fortran_COMPILER=ifort -Provided Dependencies ---------------------- +#### Provided dependencies + SOPHIA - + for photo-hadronic interactions -+ googletest - + for unit-tests + + for photo-hadronic interactions ++ googletest + + for unit-tests -Optional Dependencies ---------------------- -+ Python and SWIG +#### Optional dependencies ++ Python and SWIG + to use CRPropa from Python + tested for > Python 2.7 + tested for > SWIG 2.0 -+ FFTW3F ++ FFTW3F + for turbulent magnetic field grids - + CRPropa needs the FFTW3 library compiled with the single precision option -+ Gadget + + CRPropa needs the FFTW3 library compiled with the single precision option ++ Gadget + Magnetic fields for large scale structure data + OpenMP + for shared memory parallelization -+ googleperftools ++ googleperftools + for performance optimizations regarding shared memory parallelization -XML Steering ------------- +## Getting started +We recommend using CRPropa via python. The documentation can be found on the [CRPropa wiki](https://crpropa.desy.de/CRPropa3]). +For a 1D simulation try + + ```python + from crpropa import * + + # simulation setup + m = ModuleList() + m.add(SimplePropagation(0, 10 * Mpc)) + m.add(PhotoPionProduction(CMB)) + m.add(PhotoPionProduction(IRB)) + m.add(PhotoDisintegration(CMB)) + m.add(PhotoDisintegration(IRB)) + m.add(ElectronPairProduction(CMB_IRB)) + m.add(NuclearDecay()) + m.add(MinimumEnergy(1 * EeV)) + m.add(Observer1D()) + m.add(EventOutput1D('events.txt')) + + # source setup + source = Source() + source.addProperty(SourceParticleType(nucleusId(56, 26))) + source.addProperty(SourcePowerLawSpectrum(1 * EeV, 500 * EeV, -2)) + source.addProperty(SourceUniform1D(3 * Mpc, 2000 * Mpc)) + + # run simulation + m.setShowProgress(True) + m.run(source, 1000, True) + ``` + +## CRPropa 2 compatibility For backwards compatibility CRPropa 3 can be steered via XML cards ($cropra-xmlrun some_steeringcard.xml) However, CRPropa 2 does not fully enforce the XML-1.0 standard (http://www.w3.org/XML). To comply with the standard a few modifications to exisisting steering cards might have to be made. -Modification are +Modification are 1. XML-cards can have only one root node. The root node is @@ -64,6 +97,6 @@ Modification are ... or -3. Values need to be embraced by quotes, e.g. +3. Values need to be embraced by quotes, e.g. - \ No newline at end of file + From dcd9074e45eb17139e539dc6f2ec69cc7f0044bd Mon Sep 17 00:00:00 2001 From: geromueller Date: Wed, 22 Jan 2014 17:55:36 +0100 Subject: [PATCH 0383/1298] add dint 1d module --- CMakeLists.txt | 2 + include/crpropa/Cosmology.h | 3 + include/crpropa/module/PhotonDINT1D.h | 46 ++++++++ python/crpropa.i | 2 + src/Cosmology.cpp | 4 + src/module/PhotonDINT1D.cpp | 155 ++++++++++++++++++++++++++ 6 files changed, 212 insertions(+) create mode 100644 include/crpropa/module/PhotonDINT1D.h create mode 100644 src/module/PhotonDINT1D.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7dd6715ba..a7b9c2a9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,6 +102,7 @@ find_package(GooglePerfTools) set(TCMALLOC) if(GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) set(TCMALLOC ${TCMALLOC_LIBRARY}) + list(APPEND CRPROPA_EXTRA_LIBRARIES profiler) endif(GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) # ---------------------------------------------------------------------------- @@ -138,6 +139,7 @@ add_library(crpropa SHARED src/module/OutputROOT.cpp src/module/OutputCRPropa2.cpp src/module/PhotonDINT.cpp + src/module/PhotonDINT1D.cpp src/module/PhotonEleCa.cpp src/module/Tools.cpp src/magneticField/MagneticField.cpp diff --git a/include/crpropa/Cosmology.h b/include/crpropa/Cosmology.h index 74e0cec9c..9dbd4a0bc 100644 --- a/include/crpropa/Cosmology.h +++ b/include/crpropa/Cosmology.h @@ -22,6 +22,9 @@ double omegaL(); // Returns the matter density parameter double omegaM(); +// Returns the hubble parameter +double H0(); + /** Redshift of a comoving object at a given comoving distance to an observer at z = 0. d_comoving(z) = c/H0 * int_0^z dz' / E(z') diff --git a/include/crpropa/module/PhotonDINT1D.h b/include/crpropa/module/PhotonDINT1D.h new file mode 100644 index 000000000..6aee5e652 --- /dev/null +++ b/include/crpropa/module/PhotonDINT1D.h @@ -0,0 +1,46 @@ +#ifndef CRPROPA_PHOTONDINT1D_H +#define CRPROPA_PHOTONDINT1D_H + +#include "crpropa/Module.h" +#include "crpropa/magneticField/MagneticField.h" + +#include + +namespace crpropa { + +class PhotonDINT1DImpl; + +class PhotonDINT1D: public Module { +private: + std::string filename, dataPath; + int IRFlag, RadioFlag; + double Zmax, Cutcascade_Magfield; + + mutable PhotonDINT1DImpl *impl; +public: + PhotonDINT1D(const std::string &filename); + ~PhotonDINT1D(); + void process(Candidate *candidate) const; + std::string getDescription() const; + + /* Possible values: + * 0 -> IR_UNIFORM_HIGH (default) + * 1 -> IR_UNIFORM_LOW + * 2 -> IR_UNIFORM_PRIMACK + */ + void setIRFlag(int ir); + + /* Possible values: + * 0 -> High (default) + * 1 -> Med + * 2 -> Obs + * 3 -> Null + */ + void setRadioFlag(int radio); + + void setZmax(double zmax); +}; + +} // namespace crpropa + +#endif // CRPROPA_PHOTONDINT1D_H diff --git a/python/crpropa.i b/python/crpropa.i index 846b8341f..47f404002 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -38,6 +38,7 @@ using std::ptrdiff_t; #include "crpropa/module/OutputROOT.h" #include "crpropa/module/OutputCRPropa2.h" #include "crpropa/module/PhotonDINT.h" +#include "crpropa/module/PhotonDINT1D.h" #include "crpropa/module/PhotonEleCa.h" #include "crpropa/module/SimplePropagation.h" #include "crpropa/module/DeflectionCK.h" @@ -156,6 +157,7 @@ using std::ptrdiff_t; %include "crpropa/module/OutputROOT.h" %include "crpropa/module/OutputCRPropa2.h" %include "crpropa/module/PhotonDINT.h" +%include "crpropa/module/PhotonDINT1D.h" %include "crpropa/module/PhotonEleCa.h" %include "crpropa/module/ElectronPairProduction.h" %include "crpropa/module/NuclearDecay.h" diff --git a/src/Cosmology.cpp b/src/Cosmology.cpp index b28f0f376..19b8edd4a 100644 --- a/src/Cosmology.cpp +++ b/src/Cosmology.cpp @@ -98,6 +98,10 @@ double omegaM() { return cosmology.omegaM; } +double H0() { + return cosmology.H0; +} + double comovingDistance2Redshift(double d) { if (d < 0) throw std::runtime_error("Cosmology: d < 0"); diff --git a/src/module/PhotonDINT1D.cpp b/src/module/PhotonDINT1D.cpp new file mode 100644 index 000000000..cb694521a --- /dev/null +++ b/src/module/PhotonDINT1D.cpp @@ -0,0 +1,155 @@ +#include "crpropa/module/PhotonDINT1D.h" +#include "crpropa/Cosmology.h" + +#include +#include + +#include "dint/prop_second.h" + +using namespace std; + +namespace crpropa { + +class PhotonDINT1DImpl { +public: + PhotonDINT1DImpl() { + // Initialize the energy grids for dint + New_dCVector(&energyGrid, NUM_MAIN_BINS); + New_dCVector(&energyWidth, NUM_MAIN_BINS); + SetEnergyBins(MIN_ENERGY_EXP, &energyGrid, &energyWidth); + } + + virtual ~PhotonDINT1DImpl() { + Delete_dCVector(&energyGrid); + Delete_dCVector(&energyWidth); + } + + dCVector energyGrid, energyWidth; + virtual void saveSpectrum(Spectrum *spectrum) = 0; +}; + +class PhotonDINT1DAsciiImpl: public PhotonDINT1DImpl { + mutable std::ofstream fout; +public: + PhotonDINT1DAsciiImpl(const std::string &filename) : + PhotonDINT1DImpl(), fout(filename.c_str()) { + for (int j = 0; j < energyGrid.dimension; j++) { + fout << (energyGrid.vector[j] * ELECTRON_MASS) << " "; + } + fout << std::endl; + } + + void saveSpectrum(Spectrum *spectrum) { + for (int j = 0; j < spectrum->numberOfMainBins; j++) { + fout << spectrum->spectrum[PHOTON][j] << " "; // spectrum: mean number of particles per energy bin + } + fout << endl; + } +}; + +#ifdef CRPROPA_HAVE_ROOT +class PhotonDINT1DROOTImpl: public PhotonDINT1DImpl { +public: + PhotonDINT1DROOTImpl(const std::string &filename) : + PhotonDINT1DImpl() { + //TODO: new histogram + } + + ~PhotonDINT1DROOTImpl() { + //TODO: delete histogram + } + + void saveSpectrum(Spectrum *spectrum) { + //TODO: add to histogram + } +}; +#endif + +PhotonDINT1D::PhotonDINT1D(const string &filename) : + filename(filename), IRFlag(1), RadioFlag(1), Zmax(5), Cutcascade_Magfield( + 0), impl(0) { + dataPath = getDataPath("dint"); + + std::string::size_type i = filename.find_last_of('.'); + std::string ext = filename.substr(i); + if (ext == "root") { +#ifdef CRPROPA_HAVE_ROOT + impl = new PhotonDINT1DROOTImpl(filename); +#else + throw std::runtime_error("ROOT not compiled!"); +#endif + } else { + impl = new PhotonDINT1DAsciiImpl(filename); + } + +} + +PhotonDINT1D::~PhotonDINT1D() { + delete impl; +} + +void PhotonDINT1D::setIRFlag(int ir) { + IRFlag = ir; +} + +void PhotonDINT1D::setRadioFlag(int radio) { + RadioFlag = radio; +} + +void PhotonDINT1D::setZmax(double zmax) { + Zmax = zmax; +} + +void PhotonDINT1D::process(Candidate *candidate) const { + if (candidate->current.getId() != 22) + return; + +// Initialize the spectrum + Spectrum inputSpectrum; + NewSpectrum(&inputSpectrum, NUM_MAIN_BINS); + + double criticalEnergy = candidate->current.getEnergy() + / (eV * ELECTRON_MASS); // units of dint + int maxBin = (int) ((log10(criticalEnergy * ELECTRON_MASS) - MAX_ENERGY_EXP) + * BINS_PER_DECADE + NUM_MAIN_BINS); + inputSpectrum.spectrum[PHOTON][maxBin] = 1.; + +// Initialize the bField + dCVector bField; + New_dCVector(&bField, 0); + +// Initialize output spectrum + Spectrum outputSpectrum; + NewSpectrum(&outputSpectrum, NUM_MAIN_BINS); + + double h = H0() * Mpc / 1e5; + double showerPropDistance = candidate->current.getPosition().getR(); + double z = candidate->getRedshift(); + if (z == 0) { + //TODO: use z value for distance calculation + } + + prop_second(showerPropDistance / Mpc, &bField, &impl->energyGrid, + &impl->energyWidth, &inputSpectrum, &outputSpectrum, dataPath, + IRFlag, Zmax, RadioFlag, h, omegaL(), omegaM(), + Cutcascade_Magfield); + +#pragma omp critical + { + impl->saveSpectrum(&outputSpectrum); + } + + DeleteSpectrum(&outputSpectrum); + DeleteSpectrum(&inputSpectrum); + Delete_dCVector(&bField); + + candidate->setActive(false); +} + +string PhotonDINT1D::getDescription() const { + std::stringstream s; + s << "PhotonDINT1D: Output file = " << filename; + return s.str(); +} + +} // namespace crpropa From e2fcfa827f1a41d3c781bca3df565932cbd03f6b Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 24 Jan 2014 08:42:41 +0100 Subject: [PATCH 0384/1298] implement energy loss length methods for photodisintegration and photopionproduction update testEnergyLossLength.py --- include/crpropa/module/PhotoDisintegration.h | 9 ++++- include/crpropa/module/PhotoPionProduction.h | 13 ++++--- src/module/PhotoDisintegration.cpp | 25 ++++++++---- src/module/PhotoPionProduction.cpp | 26 ++++++------- test/python/testEnergyLossLength.py | 40 ++++++++------------ 5 files changed, 60 insertions(+), 53 deletions(-) diff --git a/include/crpropa/module/PhotoDisintegration.h b/include/crpropa/module/PhotoDisintegration.h index 5035dc228..6b102fcca 100644 --- a/include/crpropa/module/PhotoDisintegration.h +++ b/include/crpropa/module/PhotoDisintegration.h @@ -31,7 +31,14 @@ class PhotoDisintegration: public Module { void init(std::string filename); void process(Candidate *candidate) const; void performInteraction(Candidate *candidate, int channel) const; - double interactionRate(int id, double E, double z); + + /** + Calculates the loss length E dx/dE in [m]. This is not used in the simulation. + @param id PDG particle id + @param energy particle energy [J] + @param z redshift + */ + double lossLength(int id, double E, double z = 0); }; } // namespace crpropa diff --git a/include/crpropa/module/PhotoPionProduction.h b/include/crpropa/module/PhotoPionProduction.h index 928e49242..75ec1bb5a 100644 --- a/include/crpropa/module/PhotoPionProduction.h +++ b/include/crpropa/module/PhotoPionProduction.h @@ -24,9 +24,9 @@ class PhotoPionProduction: public Module { bool haveAntiNucleons; public: - PhotoPionProduction(PhotonField photonField = CMB, - bool photons = false, bool neutrinos = false, bool antiNucleons = - false, double limit = 0.1); + PhotoPionProduction(PhotonField photonField = CMB, bool photons = false, + bool neutrinos = false, bool antiNucleons = false, double limit = + 0.1); void setPhotonField(PhotonField photonField); void setHavePhotons(bool b); void setHaveNeutrinos(bool b); @@ -37,12 +37,15 @@ class PhotoPionProduction: public Module { void process(Candidate *candidate) const; void performInteraction(Candidate *candidate, int channel) const; double nucleiModification(int A, int X) const; + /** - Calculates the energy loss length 1/E dE/dx in [m]. This is not used in the simulation. + Calculates the loss length E dx/dE in [m]. + This is not used in the simulation. @param id PDG particle id @param energy particle energy [J] + @param z redshift */ - double energyLossLength(int id, double energy); + double lossLength(int id, double energy, double z = 0); }; } // namespace crpropa diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index b8ce45926..402b3cf10 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -178,7 +178,7 @@ void PhotoDisintegration::performInteraction(Candidate *candidate, candidate->addSecondary(nucleusId(4, 2), EpA * 4); } -double PhotoDisintegration::interactionRate(int id, double E, double z) { +double PhotoDisintegration::lossLength(int id, double E, double z) { // check if nucleus if (not (isNucleus(id))) return 0; @@ -189,25 +189,34 @@ double PhotoDisintegration::interactionRate(int id, double E, double z) { // check if disintegration data available if ((Z > 26) or (N > 30)) - return 0; + return std::numeric_limits::max(); std::vector pdModes = pdTable[Z * 31 + N]; if (pdModes.size() == 0) - return 0; + return std::numeric_limits::max(); // check if in tabulated energy range double lg = log10(E / (nucleusMass(id) * c_squared)) * (1 + z); if ((lg <= lgmin) or (lg >= lgmax)) - return 0; + return std::numeric_limits::max(); // total rate from all disintegration channels - double rate = 0; + double lossRate = 0; for (size_t i = 0; i < pdModes.size(); i++) { - rate += interpolateEquidistant(lg, lgmin, lgmax, pdModes[i].rate); + int dA = 0; + dA += 1 * digit(pdModes[i].channel, 100000); + dA += 1 * digit(pdModes[i].channel, 10000); + dA += 2 * digit(pdModes[i].channel, 1000); + dA += 3 * digit(pdModes[i].channel, 100); + dA += 3 * digit(pdModes[i].channel, 10); + dA += 4 * digit(pdModes[i].channel, 1); + + double rate = interpolateEquidistant(lg, lgmin, lgmax, pdModes[i].rate); + lossRate += rate * dA / A; } // comological scaling of interaction distance (in physical units) - rate *= pow(1 + z, 3) * photonFieldScaling(photonField, z); - return rate; + lossRate *= pow(1 + z, 3) * photonFieldScaling(photonField, z); + return 1. / lossRate; } } // namespace crpropa diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 14b9f3156..ef583cd06 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -236,32 +236,28 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, } } -double PhotoPionProduction::energyLossLength(int id, double E) { +double PhotoPionProduction::lossLength(int id, double E, double z) { int A = massNumber(id); int Z = chargeNumber(id); int N = A - Z; - double Eeff = E / A; + double Eeff = E / A * (1 + z); if ((Eeff < energy.front()) or (Eeff > energy.back())) return std::numeric_limits::max(); + double lossRate = 0; + if (Z > 0) + lossRate += interpolate(Eeff, energy, pRate) * nucleiModification(A, Z); + if (N > 0) + lossRate += interpolate(Eeff, energy, nRate) * nucleiModification(N, Z); + // protons / neutrons keep as energy the fraction of mass to delta-resonance mass // nuclei approximately lose the energy that the interacting nucleon is carrying double relativeEnergyLoss = (A == 1) ? 1 - 938. / 1232. : 1. / A; + lossRate *= relativeEnergyLoss; - double lossRate = 0; - if (Z > 0) { - double rate = interpolate(Eeff, energy, pRate); - rate *= nucleiModification(A, Z); - lossRate += relativeEnergyLoss * rate; - } - - if (N > 0) { - double rate = interpolate(Eeff, energy, nRate); - rate *= nucleiModification(A, N); - lossRate += relativeEnergyLoss * rate; - } - + // cosmological scaling of photon density + lossRate *= pow(1 + z, 3) * photonFieldScaling(photonField, z); return 1. / lossRate; } diff --git a/test/python/testEnergyLossLength.py b/test/python/testEnergyLossLength.py index 0b11c60b7..948d03cd5 100644 --- a/test/python/testEnergyLossLength.py +++ b/test/python/testEnergyLossLength.py @@ -10,43 +10,35 @@ pp2 = PhotoPionProduction(IRB) ep = ElectronPairProduction(CMB_IRB) -def pdLoss(pid, E): - l1 = pd1.energyLossLength(pid, E) - l2 = pd2.energyLossLength(pid, E) - return 1/(1/l1 + 1/l2) - -def ppLoss(pid, E): - l1 = pp1.energyLossLength(pid, E) - l2 = pp2.energyLossLength(pid, E) - l = 1/(1./l1 + 1./l2) - if l > 1e4 * Mpc: - return nan - return l - def parse_pid(pid): - return 'Z=%i, A=%i'%((pid//10000)%1000, (pid%10000)/10) + return 'Z=%i, A=%i'%((pid//10000)%1000, (pid%10000)/10) +def invAdd(x1, x2): + return 1. / (1. / x1 + 1. / x2) -pid = nucleusId(56, 26) -E = logspace(1, 4, 50) +pid = nucleusId(4, 2) +mass = nucleusMass(pid) +energies = logspace(1, 4, 50) L = zeros((3, 50)) +z = 0. -for i, energy in enumerate(E * EeV): - L[0,i] = pdLoss(pid, energy) - L[1,i] = ppLoss(pid, energy) - L[2,i] = ep.energyLossLength(pid, energy) +for i, E in enumerate(energies * EeV): + L[0,i] = invAdd(pd1.lossLength(pid, E, z), pd2.lossLength(pid, E, z)) + L[1,i] = invAdd(pp1.lossLength(pid, E, z), pp2.lossLength(pid, E, z)) + lorentzfactor = E / (mass * c_squared) + L[2,i] = ep.lossLength(pid, lorentzfactor, z) L /= Mpc figure() -plot(E, L[0], label='PDis') -plot(E, L[1], label='PPion') -plot(E, L[2], label='EPair') +plot(energies, L[0], label='PDis') +plot(energies, L[1], label='PPion') +plot(energies, L[2], label='EPair') legend(frameon=0, loc='lower left') text(0.05, 0.25, parse_pid(pid), transform=gca().transAxes) xlabel('Energy [EeV]') ylabel('Energy Loss Length [Mpc]') -ylim(0.1, 1e4) +ylim(1, 1e4) loglog() savefig('EnergyLossLength_%i.png'%pid, bbox_inches='tight') show() From 414652a24f53664e9a9f9eaf518c5ef8d2f90fc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Mon, 27 Jan 2014 10:04:43 +0100 Subject: [PATCH 0385/1298] fix dint propagation length --- src/module/PhotonDINT.cpp | 6 +++--- src/module/PhotonDINT1D.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/module/PhotonDINT.cpp b/src/module/PhotonDINT.cpp index 879964091..10dc633ed 100644 --- a/src/module/PhotonDINT.cpp +++ b/src/module/PhotonDINT.cpp @@ -102,11 +102,11 @@ void PhotonDINT::process(Candidate *candidate) const { Spectrum outputSpectrum; NewSpectrum(&outputSpectrum, NUM_MAIN_BINS); - double H0 = hubbleRate(0) * Mpc / 1000; // Hubble constant in [km/s/Mpc] + double h = H0() * Mpc / 1e5; - prop_second(showerPropDistance / Mpc, &bField, &energyGrid, &energyWidth, + prop_second(showerPropDistance / centimeter, &bField, &energyGrid, &energyWidth, &inputSpectrum, &outputSpectrum, dataPath, IRFlag, Zmax, RadioFlag, - H0, omegaL(), omegaM(), Cutcascade_Magfield); + h, omegaL(), omegaM(), Cutcascade_Magfield); #pragma omp critical { diff --git a/src/module/PhotonDINT1D.cpp b/src/module/PhotonDINT1D.cpp index cb694521a..e5157a45c 100644 --- a/src/module/PhotonDINT1D.cpp +++ b/src/module/PhotonDINT1D.cpp @@ -123,13 +123,13 @@ void PhotonDINT1D::process(Candidate *candidate) const { NewSpectrum(&outputSpectrum, NUM_MAIN_BINS); double h = H0() * Mpc / 1e5; - double showerPropDistance = candidate->current.getPosition().getR(); + double showerPropDistance = candidate->current.getPosition().getR() / centimeter; double z = candidate->getRedshift(); if (z == 0) { //TODO: use z value for distance calculation } - prop_second(showerPropDistance / Mpc, &bField, &impl->energyGrid, + prop_second(showerPropDistance, &bField, &impl->energyGrid, &impl->energyWidth, &inputSpectrum, &outputSpectrum, dataPath, IRFlag, Zmax, RadioFlag, h, omegaL(), omegaM(), Cutcascade_Magfield); From 52f50faba6b81cb584fe12c78924ccb87799adc7 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 27 Jan 2014 10:07:03 +0100 Subject: [PATCH 0386/1298] extend testCore interpolation test --- test/testCore.cpp | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/test/testCore.cpp b/test/testCore.cpp index 5700a765a..4329c1df8 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -168,21 +168,40 @@ TEST(common, digit) { } TEST(common, interpolate) { - std::vector xD(100), yD(100); - for (int i = 0; i < 100; i++) { - xD[i] = 1 + i * 2. / 99.; - yD[i] = pow(xD[i], 2); + // create vectors x = (0, 0.02, ... 2) and y = 2x + 3 = (3, ... 7) + std::vector xD(101), yD(101); + for (int i = 0; i <= 100; i++) { + xD[i] = i * 0.02; + yD[i] = 2 * xD[i] + 3; } - // interpolated value should be close to computed - double y = interpolate(1.5001, xD, yD); - EXPECT_NEAR(pow(1.5001, 2), y, 1e-4); + // interpolating tabulated values of a linear function should produce exact results + Random &R = Random::instance(); + double x, ytrue, yinterp; + for (int i = 0; i < 10000; i++) { + x = R.rand() * 2; // random value between 0 and 2 + ytrue = 2 * x + 3; + yinterp = interpolate(x, xD, yD); + EXPECT_DOUBLE_EQ(ytrue, yinterp); + } - // value out of range, return lower bound - EXPECT_EQ(1, interpolate(0.9, xD, yD)); + // test interpolation in first bin + x = 0.01; + ytrue = 2 * x + 3; + yinterp = interpolate(x, xD, yD); + EXPECT_DOUBLE_EQ(ytrue, yinterp); + + // test interpolation in last bin + x = 1.99; + ytrue = 2 * x + 3; + yinterp = interpolate(x, xD, yD); + EXPECT_DOUBLE_EQ(ytrue, yinterp); // value out of range, return lower bound - EXPECT_EQ(9, interpolate(3.1, xD, yD)); + EXPECT_EQ(3, interpolate(-0.001, xD, yD)); + + // value out of range, return upper bound + EXPECT_EQ(7, interpolate(2.001, xD, yD)); } TEST(common, interpolateEquidistant) { From a230c08f70f5f6d1d8cd881f33988c8132bd8ac6 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 27 Jan 2014 10:47:07 +0100 Subject: [PATCH 0387/1298] exclude data/.git from install --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a7b9c2a9b..beedbe1ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,7 +160,7 @@ add_definitions(-DCRPROPA_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") install(TARGETS crpropa-xmlrun RUNTIME DESTINATION bin) install(TARGETS crpropa DESTINATION lib) install(DIRECTORY include/ DESTINATION include FILES_MATCHING PATTERN "*.h") -install(DIRECTORY data/ DESTINATION share/crpropa/) +install(DIRECTORY data/ DESTINATION share/crpropa/ PATTERN ".git" EXCLUDE) # ---------------------------------------------------------------------------- # Testing From 8edce0e757d5380b50f22cc27173695d959d4b85 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 27 Jan 2014 11:45:51 +0100 Subject: [PATCH 0388/1298] fix photopion nuclei correction for A=8 --- src/module/PhotoPionProduction.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index ef583cd06..995ae82f0 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -82,10 +82,9 @@ void PhotoPionProduction::init(std::string filename) { double PhotoPionProduction::nucleiModification(int A, int X) const { if (A == 1) return 1.; - if (A < 8) + if (A <= 8) return 0.85 * pow(X, 2. / 3.); - else - return 0.85 * X; + return 0.85 * X; } void PhotoPionProduction::process(Candidate *candidate) const { From 70b6739d20863bf5f74aad7c7f934a82da1fb0b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Mon, 27 Jan 2014 12:51:04 +0100 Subject: [PATCH 0389/1298] revert to Mpc distance dor dint --- src/module/PhotonDINT.cpp | 2 +- src/module/PhotonDINT1D.cpp | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/module/PhotonDINT.cpp b/src/module/PhotonDINT.cpp index 10dc633ed..2d68b7391 100644 --- a/src/module/PhotonDINT.cpp +++ b/src/module/PhotonDINT.cpp @@ -104,7 +104,7 @@ void PhotonDINT::process(Candidate *candidate) const { double h = H0() * Mpc / 1e5; - prop_second(showerPropDistance / centimeter, &bField, &energyGrid, &energyWidth, + prop_second(showerPropDistance / Mpc, &bField, &energyGrid, &energyWidth, &inputSpectrum, &outputSpectrum, dataPath, IRFlag, Zmax, RadioFlag, h, omegaL(), omegaM(), Cutcascade_Magfield); diff --git a/src/module/PhotonDINT1D.cpp b/src/module/PhotonDINT1D.cpp index e5157a45c..813132518 100644 --- a/src/module/PhotonDINT1D.cpp +++ b/src/module/PhotonDINT1D.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "dint/prop_second.h" @@ -51,7 +52,7 @@ class PhotonDINT1DAsciiImpl: public PhotonDINT1DImpl { class PhotonDINT1DROOTImpl: public PhotonDINT1DImpl { public: PhotonDINT1DROOTImpl(const std::string &filename) : - PhotonDINT1DImpl() { + PhotonDINT1DImpl() { //TODO: new histogram } @@ -104,7 +105,7 @@ void PhotonDINT1D::process(Candidate *candidate) const { if (candidate->current.getId() != 22) return; -// Initialize the spectrum + // Initialize the spectrum Spectrum inputSpectrum; NewSpectrum(&inputSpectrum, NUM_MAIN_BINS); @@ -114,16 +115,16 @@ void PhotonDINT1D::process(Candidate *candidate) const { * BINS_PER_DECADE + NUM_MAIN_BINS); inputSpectrum.spectrum[PHOTON][maxBin] = 1.; -// Initialize the bField + // Initialize the bField dCVector bField; - New_dCVector(&bField, 0); + New_dCVector(&bField, 1); -// Initialize output spectrum + // Initialize output spectrum Spectrum outputSpectrum; NewSpectrum(&outputSpectrum, NUM_MAIN_BINS); double h = H0() * Mpc / 1e5; - double showerPropDistance = candidate->current.getPosition().getR() / centimeter; + double showerPropDistance = candidate->current.getPosition().getR() / Mpc; double z = candidate->getRedshift(); if (z == 0) { //TODO: use z value for distance calculation From d61261085693350d17e409609e7e0d4ae4a6bffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Mon, 27 Jan 2014 12:53:16 +0100 Subject: [PATCH 0390/1298] add dint test --- CMakeLists.txt | 4 ++++ test/testDINT.cpp | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 test/testDINT.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index beedbe1ec..f2c008d53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,6 +186,10 @@ if(ENABLE_TESTING) add_executable(testPropagation test/testPropagation.cpp) target_link_libraries(testPropagation crpropa gtest gtest_main pthread) add_test(testPropagation testPropagation) + + add_executable(testDINT test/testDINT.cpp) + target_link_libraries(testDINT crpropa gtest gtest_main pthread) + add_test(testPropagation testDINT) add_executable(testBreakCondition test/testBreakCondition.cpp) target_link_libraries(testBreakCondition crpropa gtest gtest_main pthread) diff --git a/test/testDINT.cpp b/test/testDINT.cpp new file mode 100644 index 000000000..0c5e70fdf --- /dev/null +++ b/test/testDINT.cpp @@ -0,0 +1,23 @@ +#include "crpropa/Candidate.h" +#include "crpropa/module/PhotonDINT1D.h" + +#include "gtest/gtest.h" + +namespace crpropa { + +TEST(testDINT, step) { + PhotonDINT1D mod("dint1d_output.txt"); + Candidate c; + c.current.setId(22); + c.current.setPosition(Vector3d(0.0001 * Mpc, 0, 0)); + c.current.setEnergy(10 * EeV); + c.setActive(true); + mod.process(&c); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + +} // namespace crpropa From 6f55ac6db23a7db656fd6b02958e692009227922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Mon, 27 Jan 2014 12:56:30 +0100 Subject: [PATCH 0391/1298] hide dint output --- libs/dint/src/prop_second.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/dint/src/prop_second.cpp b/libs/dint/src/prop_second.cpp index 3e605cdf3..5f71f6909 100644 --- a/libs/dint/src/prop_second.cpp +++ b/libs/dint/src/prop_second.cpp @@ -1008,8 +1008,10 @@ clock_t end = clock(); clock_t total = end -start; clock_t comp = end_comp -start_comp; -printf("Comptime: %f\n", float(comp)/float(total)); +#ifdef DEBUG +printf("Dint Comptime: %f\n", float(comp)/float(total)); +#endif } void BuildRedshiftTable(double aH0, double aOmegaM, double aOmegaLambda, From 198c5c058d016619450c615dbfac817c05597648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Mon, 27 Jan 2014 13:49:18 +0100 Subject: [PATCH 0392/1298] fix dint1d default values to match crpropa2 --- include/crpropa/module/PhotonDINT1D.h | 11 +++++++---- src/module/PhotonDINT.cpp | 2 +- src/module/PhotonDINT1D.cpp | 8 +++++--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/include/crpropa/module/PhotonDINT1D.h b/include/crpropa/module/PhotonDINT1D.h index 6aee5e652..30275aa65 100644 --- a/include/crpropa/module/PhotonDINT1D.h +++ b/include/crpropa/module/PhotonDINT1D.h @@ -24,20 +24,23 @@ class PhotonDINT1D: public Module { std::string getDescription() const; /* Possible values: - * 0 -> IR_UNIFORM_HIGH (default) + * 0 -> IR_UNIFORM_HIGH * 1 -> IR_UNIFORM_LOW - * 2 -> IR_UNIFORM_PRIMACK + * 2 -> IR_UNIFORM_PRIMACK (default) */ void setIRFlag(int ir); /* Possible values: - * 0 -> High (default) + * 0 -> High * 1 -> Med - * 2 -> Obs + * 2 -> Obs (default) * 3 -> Null */ void setRadioFlag(int radio); + /* + * default: 5 + */ void setZmax(double zmax); }; diff --git a/src/module/PhotonDINT.cpp b/src/module/PhotonDINT.cpp index 2d68b7391..bd1aa9dce 100644 --- a/src/module/PhotonDINT.cpp +++ b/src/module/PhotonDINT.cpp @@ -102,7 +102,7 @@ void PhotonDINT::process(Candidate *candidate) const { Spectrum outputSpectrum; NewSpectrum(&outputSpectrum, NUM_MAIN_BINS); - double h = H0() * Mpc / 1e5; + double h = H0() * Mpc / 1000; prop_second(showerPropDistance / Mpc, &bField, &energyGrid, &energyWidth, &inputSpectrum, &outputSpectrum, dataPath, IRFlag, Zmax, RadioFlag, diff --git a/src/module/PhotonDINT1D.cpp b/src/module/PhotonDINT1D.cpp index 813132518..7d09f8f8e 100644 --- a/src/module/PhotonDINT1D.cpp +++ b/src/module/PhotonDINT1D.cpp @@ -67,7 +67,7 @@ class PhotonDINT1DROOTImpl: public PhotonDINT1DImpl { #endif PhotonDINT1D::PhotonDINT1D(const string &filename) : - filename(filename), IRFlag(1), RadioFlag(1), Zmax(5), Cutcascade_Magfield( + filename(filename), IRFlag(2), RadioFlag(2), Zmax(5), Cutcascade_Magfield( 0), impl(0) { dataPath = getDataPath("dint"); @@ -123,7 +123,9 @@ void PhotonDINT1D::process(Candidate *candidate) const { Spectrum outputSpectrum; NewSpectrum(&outputSpectrum, NUM_MAIN_BINS); - double h = H0() * Mpc / 1e5; + double h = H0() * Mpc / 1000; + double ol = omegaL(); + double om = omegaM(); double showerPropDistance = candidate->current.getPosition().getR() / Mpc; double z = candidate->getRedshift(); if (z == 0) { @@ -132,7 +134,7 @@ void PhotonDINT1D::process(Candidate *candidate) const { prop_second(showerPropDistance, &bField, &impl->energyGrid, &impl->energyWidth, &inputSpectrum, &outputSpectrum, dataPath, - IRFlag, Zmax, RadioFlag, h, omegaL(), omegaM(), + IRFlag, Zmax, RadioFlag, h, ol, om, Cutcascade_Magfield); #pragma omp critical From ee28bd036d8d6aa9c4d55028dba32a8e0578b502 Mon Sep 17 00:00:00 2001 From: kuempel Date: Mon, 27 Jan 2014 18:28:08 +0100 Subject: [PATCH 0393/1298] corrected order of omegaM and omegaL when passing to DINT --- src/module/PhotonDINT1D.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/module/PhotonDINT1D.cpp b/src/module/PhotonDINT1D.cpp index 7d09f8f8e..24c9a238c 100644 --- a/src/module/PhotonDINT1D.cpp +++ b/src/module/PhotonDINT1D.cpp @@ -133,9 +133,9 @@ void PhotonDINT1D::process(Candidate *candidate) const { } prop_second(showerPropDistance, &bField, &impl->energyGrid, - &impl->energyWidth, &inputSpectrum, &outputSpectrum, dataPath, - IRFlag, Zmax, RadioFlag, h, ol, om, - Cutcascade_Magfield); + &impl->energyWidth, &inputSpectrum, &outputSpectrum, dataPath, + IRFlag, Zmax, RadioFlag, h, om, ol, + Cutcascade_Magfield); #pragma omp critical { From 46b6724d80cbf09787ef341fd06a09560b726305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Fri, 31 Jan 2014 14:27:00 +0100 Subject: [PATCH 0394/1298] DINT3D: corrected order of omegaM and omegaL, set defaults to match CRPRopa2 --- src/module/PhotonDINT.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/module/PhotonDINT.cpp b/src/module/PhotonDINT.cpp index bd1aa9dce..be9160412 100644 --- a/src/module/PhotonDINT.cpp +++ b/src/module/PhotonDINT.cpp @@ -11,8 +11,8 @@ using namespace std; namespace crpropa { PhotonDINT::PhotonDINT(const string &filename, ref_ptr field) : - filename(filename), fout(filename.c_str()), field(field), IRFlag(0), RadioFlag( - 0), Zmax(5), Cutcascade_Magfield(0) { + filename(filename), fout(filename.c_str()), field(field), IRFlag(2), RadioFlag( + 2), Zmax(5), Cutcascade_Magfield(0) { dataPath = getDataPath("dint"); //TODO: implement ir and radio flags @@ -66,7 +66,7 @@ void PhotonDINT::process(Candidate *candidate) const { double criticalEnergy = candidate->current.getEnergy() / (eV * ELECTRON_MASS); // units of dint int maxBin = (int) ((log10(criticalEnergy * ELECTRON_MASS) - - MAX_ENERGY_EXP)* BINS_PER_DECADE + NUM_MAIN_BINS); + - MAX_ENERGY_EXP) * BINS_PER_DECADE + NUM_MAIN_BINS); inputSpectrum.spectrum[PHOTON][maxBin] = 1.; } @@ -106,7 +106,7 @@ void PhotonDINT::process(Candidate *candidate) const { prop_second(showerPropDistance / Mpc, &bField, &energyGrid, &energyWidth, &inputSpectrum, &outputSpectrum, dataPath, IRFlag, Zmax, RadioFlag, - h, omegaL(), omegaM(), Cutcascade_Magfield); + h, omegaM(), omegaL(), Cutcascade_Magfield); #pragma omp critical { From bfdddd9b1f5c6f7305e2838cf9f3561a5a6ed650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Wed, 5 Feb 2014 12:09:25 +0100 Subject: [PATCH 0395/1298] Fixes #3, unresolved symbols in on ubuntu --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index f2c008d53..bfb6b7d96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,10 @@ set(CRPROPA_EXTRA_INCLUDES) set(CRPROPA_EXTRA_LIBRARIES) set(CRPROPA_SWIG_DEFINES) +set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--as-needed") +set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--as-needed") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") + # ---------------------------------------------------------------------------- # Dependencies # ---------------------------------------------------------------------------- @@ -94,6 +98,7 @@ if(ENABLE_ROOT) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") add_definitions(-DCRPROPA_HAVE_ROOT) list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_ROOT) + list(APPEND CRPROPA_EXTRA_LIBRARIES Core RIO Tree) endif(ROOT_FOUND) endif(ENABLE_ROOT) @@ -140,6 +145,7 @@ add_library(crpropa SHARED src/module/OutputCRPropa2.cpp src/module/PhotonDINT.cpp src/module/PhotonDINT1D.cpp + src/module/PhotonOutput1D.cpp src/module/PhotonEleCa.cpp src/module/Tools.cpp src/magneticField/MagneticField.cpp From f5c9320e433e3b2ecbcc56f87c9670d7056af411 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Wed, 5 Feb 2014 12:15:07 +0100 Subject: [PATCH 0396/1298] Fixes #3, unresolved symbols in on ubuntu --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bfb6b7d96..d20191080 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -145,7 +145,6 @@ add_library(crpropa SHARED src/module/OutputCRPropa2.cpp src/module/PhotonDINT.cpp src/module/PhotonDINT1D.cpp - src/module/PhotonOutput1D.cpp src/module/PhotonEleCa.cpp src/module/Tools.cpp src/magneticField/MagneticField.cpp From 520bbca901249c0ad8b65252cde5977a4cd40c6b Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 28 Feb 2014 12:45:51 +0100 Subject: [PATCH 0397/1298] New scheme for observers: Observer provides a container class for ObserverFeatures, similar to Source Added ObserverSmallSphere, -LargeSphere, -Position, -RedshiftWindow, -Output1D and -Output3D Both output option include the CRPropa2 format as legacy mode --- include/crpropa/module/Observer.h | 109 +++++++++++++- src/module/Observer.cpp | 229 +++++++++++++++++++++++++++++- 2 files changed, 331 insertions(+), 7 deletions(-) diff --git a/include/crpropa/module/Observer.h b/include/crpropa/module/Observer.h index 503769017..293bc874d 100644 --- a/include/crpropa/module/Observer.h +++ b/include/crpropa/module/Observer.h @@ -3,16 +3,115 @@ #include "crpropa/Module.h" +#include +#include + namespace crpropa { /** - @class SmallObserverSphere - @brief Flags particles when entering the sphere. + @class ObserverFeature + @brief Abstract base class for features of cosmic ray observers + */ +class ObserverFeature: public Referenced { +public: + virtual bool process(Candidate &candidate) const = 0; +}; - Particles are detected when the current position is inside and the previous position outside the sphere. - In this case the candidate is by default flagged "Detected" made inactive. - This module limits the next step size to prevent candidates from overshooting. +/** + @class Observer + @brief General cosmic ray observer + */ +class Observer: public Referenced { +private: + std::vector > features; + bool makeInactive; +public: + Observer(bool makeInactive = false) : + makeInactive(makeInactive) { + } + void add(ObserverFeature *property); + void process(Candidate *candidate) const; +}; + +/** + @class ObserverSmallSphere + @brief Detects particles upon entering a sphere + */ +class ObserverSmallSphere: public ObserverFeature { +private: + Vector3d center; + double radius; +public: + ObserverSmallSphere(Vector3d center = Vector3d(0.), double radius = 0); + bool process(Candidate &candidate) const; +}; + +/** + @class ObserverSmallSphere + @brief Detects particles upon exiting a sphere + */ +class ObserverLargeSphere: public ObserverFeature { +private: + Vector3d center; + double radius; +public: + ObserverLargeSphere(Vector3d center = Vector3d(0.), double radius = 0); + bool process(Candidate &candidate) const; +}; + +/** + @class ObserverSmallSphere + @brief Detects particles upon exiting a sphere + */ +class ObserverRedshiftWindow: public ObserverFeature { +private: + double zmin, zmax; +public: + ObserverRedshiftWindow(double zmin = 0, double zmax = 0.1); + bool process(Candidate &candidate) const; +}; + +/** + @class ObserverPoint + @brief Detects particles when reaching x = 0 + + Should be renamed to Observer1D */ +class ObserverPoint: public ObserverFeature { +public: + bool process(Candidate &candidate) const; +}; + +/** + @class ObserverOutput3D + @brief Plain text output of 3D properties + */ +class ObserverOutput3D: public ObserverFeature { +private: + mutable std::ofstream fout; + bool legacy; // toggle CRPropa 2 output format +public: + ObserverOutput3D(std::string filename, bool legacy = false); + ~ObserverOutput3D(); + bool process(Candidate &candidate) const; +}; + +/** + @class ObserverOutput1D + @brief Plain text output of 1D properties + */ +class ObserverOutput1D: public ObserverFeature { +private: + mutable std::ofstream fout; + bool legacy; // toggle CRPropa 2 output format +public: + ObserverOutput1D(std::string filename, bool legacy = false); + ~ObserverOutput1D(); + bool process(Candidate &candidate) const; +}; + +//////////////////////////////////////////////////////////////////////////////// + class SmallObserverSphere: public Module { private: Vector3d center; diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp index 0aeeb52de..33060a784 100644 --- a/src/module/Observer.cpp +++ b/src/module/Observer.cpp @@ -1,9 +1,234 @@ #include "crpropa/module/Observer.h" - -#include +#include "crpropa/Cosmology.h" namespace crpropa { +void Observer::add(ObserverFeature *feature) { + features.push_back(feature); +} + +void Observer::process(Candidate *candidate) const { + // loop over all features and have them check the particle + for (int i = 0; i < features.size(); i++) { + bool b = (*features[i]).process(*candidate); + if (not (b)) + return; // not detected + } + if (makeInactive) + candidate->setActive(false); +} + +ObserverSmallSphere::ObserverSmallSphere(Vector3d center, double radius) : + center(center), radius(radius) { +} + +bool ObserverSmallSphere::process(Candidate &candidate) const { + // current distance to observer sphere center + double d = (candidate.current.getPosition() - center).getR(); + + // conservatively limit next step to prevent overshooting + candidate.limitNextStep(fabs(d - radius)); + + // no detection if outside of observer sphere + if (d > radius) + return false; + + // previous distance to observer sphere center + double dprev = (candidate.previous.getPosition() - center).getR(); + + // if particle was inside of sphere in previous step it has already been detected + if (dprev <= radius) + return false; + + // else detection + return true; +} + +ObserverLargeSphere::ObserverLargeSphere(Vector3d center, double radius) : + center(center), radius(radius) { +} + +bool ObserverLargeSphere::process(Candidate &candidate) const { + // current distance to observer sphere center + double d = (candidate.current.getPosition() - center).getR(); + + // conservatively limit next step size to prevent overshooting + candidate.limitNextStep(fabs(radius - d)); + + // no detection if inside observer sphere + if (d < radius) + return false; + + // previous distance to observer sphere center + double dprev = (candidate.previous.getPosition() - center).getR(); + + // if particle was outside of sphere in previous step it has already been detected + if (dprev >= radius) + return false; + + // else: detection + return true; +} + +bool ObserverPoint::process(Candidate &candidate) const { + double x = candidate.current.getPosition().x; + if (x > 0) { + candidate.limitNextStep(x); + return false; + } + return true; +} + +ObserverRedshiftWindow::ObserverRedshiftWindow(double zmin, double zmax) : + zmin(zmin), zmax(zmax) { +} + +bool ObserverRedshiftWindow::process(Candidate & candidate) const { + double z = candidate.getRedshift(); + if (z > zmax) + return false; + if (z < zmin) + return false; + return true; +} + +ObserverOutput3D::ObserverOutput3D(std::string fname, bool legacy) : + legacy(legacy) { + fout.open(fname.c_str()); + + if (legacy) { + fout << "#CRPropa - Output data file\n"; + fout << "#Format - Particle_Type "; + fout << "Initial_Particle_Type "; + fout << "Initial_Position[X,Y,Z](Mpc) "; + fout << "Initial_Momentum[E(EeV),theta,phi] "; + fout << "Time(Mpc, light travel distance) "; + fout << "Position[X,Y,Z](Mpc) "; + fout << "Momentum[E(EeV),theta,phi]\n"; + } else { + fout + << "# D\tID\tID0\tE\tE0\tX\tY\tZ\tX0\tY0\tZ0\tPx\tPy\tPz\tP0x\tP0y\tP0z\n"; + fout << "#\n"; + fout << "# D Trajectory length [Mpc]\n"; + fout << "# ID Particle type (PDG MC numbering scheme)\n"; + fout << "# E Energy [EeV]\n"; + fout << "# X, Y, Z Position [Mpc]\n"; + fout << "# Px, Py, Pz Heading (unit vector of momentum)\n"; + fout << "# Initial state: ID0, E0, ...\n"; + fout << "#\n"; + } +} + +ObserverOutput3D::~ObserverOutput3D() { + fout.close(); +} + +bool ObserverOutput3D::process(Candidate &c) const { + char buffer[256]; + size_t p = 0; + + if (legacy) { + p += sprintf(buffer + p, "%i ", + convertToCRPropa2NucleusId(c.current.getId())); + p += sprintf(buffer + p, "%i ", + convertToCRPropa2NucleusId(c.source.getId())); + Vector3d ipos = c.source.getPosition() / Mpc; + p += sprintf(buffer + p, "%.4f %.4f %.4f ", ipos.x, ipos.y, ipos.z); + double iPhi = c.source.getDirection().getPhi(); + double iTheta = c.source.getDirection().getTheta(); + double iE = c.source.getEnergy() / EeV; + p += sprintf(buffer + p, "%.4f %.4f %.4f ", iE, iPhi, iTheta); + double t = comoving2LightTravelDistance(c.getTrajectoryLength()) / Mpc; + p += sprintf(buffer + p, "%.4f ", t); + Vector3d pos = c.current.getPosition() / Mpc; + p += sprintf(buffer + p, "%.4f %.4f %.4f ", pos.x, pos.y, pos.z); + double phi = c.current.getDirection().getPhi(); + double theta = c.current.getDirection().getTheta(); + double E = c.current.getEnergy() / EeV; + p += sprintf(buffer + p, "%.4f %.4f %.4f\n", E, phi, theta); + } else { + p += sprintf(buffer + p, "%8.3f\t", c.getTrajectoryLength() / Mpc); + p += sprintf(buffer + p, "%10i\t", c.current.getId()); + p += sprintf(buffer + p, "%10i\t", c.source.getId()); + p += sprintf(buffer + p, "%8.4f\t", c.current.getEnergy() / EeV); + p += sprintf(buffer + p, "%8.4f\t", c.source.getEnergy() / EeV); + Vector3d pos = c.current.getPosition() / Mpc; + p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", pos.x, pos.y, pos.z); + Vector3d ipos = c.source.getPosition() / Mpc; + p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", ipos.x, ipos.y, + ipos.z); + Vector3d dir = c.current.getDirection(); + p += sprintf(buffer + p, "%8.5f\t%8.5f\t%8.5f\t", dir.x, dir.y, dir.z); + Vector3d idir = c.source.getDirection(); + p += sprintf(buffer + p, "%8.5f\t%8.5f\t%8.5f\n", idir.x, idir.y, + idir.z); + } + +#pragma omp critical + { + fout.write(buffer, p); + fout.flush(); + } + + return true; +} + +ObserverOutput1D::ObserverOutput1D(std::string filename, bool legacy) : + legacy(legacy) { + fout.open(filename.c_str()); + + if (legacy) { + fout << "#CRPropa - Output data file\n"; + fout << "#Format - Energy(EeV) "; + fout << "Time(Mpc, light travel distance) "; + fout << "Initial_Particle_Type "; + fout << "Initial_Energy(EeV)\n"; + } else { + fout << "#ID\tE\tD\tID0\tE0\n"; + fout << "#\n"; + fout << "# ID Particle type\n"; + fout << "# E Energy [EeV]\n"; + fout << "# D Comoving trajectory length [Mpc]\n"; + fout << "# ID0 Initial particle type\n"; + fout << "# E0 Initial energy [EeV]\n"; + } +} + +ObserverOutput1D::~ObserverOutput1D() { + fout.close(); +} + +bool ObserverOutput1D::process(Candidate& c) const { + char buffer[256]; + size_t p = 0; + + if (legacy) { + p += sprintf(buffer + p, "%i ", + convertToCRPropa2NucleusId(c.current.getId())); + p += sprintf(buffer + p, "%.4f ", c.current.getEnergy() / EeV); + double t = comoving2LightTravelDistance(c.getTrajectoryLength()) / Mpc; + p += sprintf(buffer + p, "%.4f ", t); + p += sprintf(buffer + p, "%i ", + convertToCRPropa2NucleusId(c.source.getId())); + p += sprintf(buffer + p, "%.4f\n", c.source.getEnergy() / EeV); + } else { + p += sprintf(buffer + p, "%10i\t", c.current.getId()); + p += sprintf(buffer + p, "%8.4f\t", c.current.getEnergy() / EeV); + p += sprintf(buffer + p, "%9.4f\t", c.getTrajectoryLength() / Mpc); + p += sprintf(buffer + p, "%10i\t", c.source.getId()); + p += sprintf(buffer + p, "%8.4f\n", c.source.getEnergy() / EeV); + } + +#pragma omp critical + { + fout.write(buffer, p); + fout.flush(); + } + return true; +} + +//////////////////////////////////////////////////////////////////////////////// + SmallObserverSphere::SmallObserverSphere(Vector3d center, double radius, std::string flag, std::string flagValue, bool makeInactive) : center(center), radius(radius), flag(flag), flagValue(flagValue), makeInactive( From eb17cb3995529229827921e1e33c59eec1d27748 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 4 Mar 2014 23:38:06 +0100 Subject: [PATCH 0398/1298] add redshift to ConditionalOutput --- src/module/OutputTXT.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/module/OutputTXT.cpp b/src/module/OutputTXT.cpp index ed6dc04c9..f03dacebe 100644 --- a/src/module/OutputTXT.cpp +++ b/src/module/OutputTXT.cpp @@ -45,13 +45,14 @@ ConditionalOutput::ConditionalOutput(std::string fname, std::string cond) : setDescription( "Conditional output, condition: " + cond + ", filename: " + fname); fout.open(fname.c_str()); - fout << "# D\tID\tID0\tE\tE0\tX\tY\tZ\tX0\tY0\tZ0\tPx\tPy\tPz\tP0x\tP0y\tP0z\n"; + fout << "# D\tID\tID0\tE\tE0\tX\tY\tZ\tX0\tY0\tZ0\tPx\tPy\tPz\tP0x\tP0y\tP0z\tz\n"; fout << "#\n"; fout << "# D Trajectory length [Mpc]\n"; fout << "# ID Particle type (PDG MC numbering scheme)\n"; fout << "# E Energy [EeV]\n"; fout << "# X, Y, Z Position [Mpc]\n"; fout << "# Px, Py, Pz Heading (unit vector of momentum)\n"; + fout << "# z Current redshift\n"; fout << "# Initial state: ID0, E0, ...\n"; fout << "#\n"; } @@ -81,7 +82,8 @@ void ConditionalOutput::process(Candidate *c) const { Vector3d dir = c->current.getDirection(); p += sprintf(buffer + p, "%8.5f\t%8.5f\t%8.5f\t", dir.x, dir.y, dir.z); Vector3d idir = c->source.getDirection(); - p += sprintf(buffer + p, "%8.5f\t%8.5f\t%8.5f\n", idir.x, idir.y, idir.z); + p += sprintf(buffer + p, "%8.5f\t%8.5f\t%8.5f\t", idir.x, idir.y, idir.z); + p += sprintf(buffer + p, "%1.3f\n", c->getRedshift()); #pragma omp critical { From 15314e206a53f9e932d4e8ef9704b1bc8d0cb8c6 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 6 Mar 2014 00:01:10 +0100 Subject: [PATCH 0399/1298] add Grid::getValue to allow access to scalar grid values from python --- include/crpropa/Grid.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/crpropa/Grid.h b/include/crpropa/Grid.h index b3df58c16..b891d6549 100644 --- a/include/crpropa/Grid.h +++ b/include/crpropa/Grid.h @@ -128,6 +128,10 @@ class Grid: public Referenced { return grid[ix * Ny * Nz + iy * Nz + iz]; } + T getValue(size_t ix, size_t iy, size_t iz) { + return grid[ix * Ny * Nz + iy * Nz + iz]; + } + /** Return a reference to the grid values */ std::vector &getGrid() { return grid; From 0bb79abe6fcac9806bbf2ae164722d8ecf7fd588 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 3 Apr 2014 09:24:56 +0200 Subject: [PATCH 0400/1298] testOutput: specify filename for ROOT output to avoid confusion when running the unit test Fixes #5 --- test/testOutput.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/testOutput.cpp b/test/testOutput.cpp index cbc78111f..7425b2423 100644 --- a/test/testOutput.cpp +++ b/test/testOutput.cpp @@ -42,7 +42,7 @@ TEST(CRPropa2EventOutput1D, removeProperty) { #ifdef CRPROPA_HAVE_ROOT TEST(CRPropa2ROOTEventOutput3D, removeProperty) { - CRPropa2ROOTEventOutput3D output(""); + CRPropa2ROOTEventOutput3D output("testOutput.root"); Candidate c; c.setProperty("Dected", ""); output.process(&c); @@ -50,7 +50,7 @@ TEST(CRPropa2ROOTEventOutput3D, removeProperty) { } TEST(CRPropa2ROOTEventOutput1D, removeProperty) { - CRPropa2ROOTEventOutput1D output(""); + CRPropa2ROOTEventOutput1D output("testOutput.root"); Candidate c; c.setProperty("Dected", ""); output.process(&c); From 61cead320ee81aca1b35e6e585e231513aa14444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Mon, 7 Apr 2014 12:44:55 +0200 Subject: [PATCH 0401/1298] fix python bindings --- include/crpropa/Vector3.h | 2 + python/Python.cmake | 177 +++++++++++++++++++++----------------- python/crpropa.i | 6 +- 3 files changed, 104 insertions(+), 81 deletions(-) diff --git a/include/crpropa/Vector3.h b/include/crpropa/Vector3.h index bcd62c2f5..7b62fb57b 100644 --- a/include/crpropa/Vector3.h +++ b/include/crpropa/Vector3.h @@ -387,6 +387,7 @@ class Vector3 { } }; +#ifndef SWIG template inline std::ostream &operator <<(std::ostream &out, const Vector3 &v) { out << v.x << " " << v.y << " " << v.z; @@ -398,6 +399,7 @@ inline std::istream &operator >>(std::istream &in, Vector3 &v) { in >> v.x >> v.y >> v.z; return in; } +#endif template inline Vector3 operator *(T f, const Vector3 &v) { diff --git a/python/Python.cmake b/python/Python.cmake index 7170bf48a..c7a1f7b58 100644 --- a/python/Python.cmake +++ b/python/Python.cmake @@ -1,78 +1,99 @@ -# SETUP PYTHON - -# get default python inerpreter -FIND_PROGRAM( PYTHON_EXECUTABLE python REQUIRED - PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.7\\InstallPath] [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath] [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath] -) - -# find python include path -execute_process( - COMMAND ${PYTHON_EXECUTABLE} -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_inc())" - OUTPUT_VARIABLE PYTHON_INCLUDE_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE -) - -FIND_FILE(PYTHON_H_FOUND Python.h ${PYTHON_INCLUDE_PATH}) -IF(NOT PYTHON_H_FOUND) - MESSAGE(SEND_ERROR "Python.h not found") -ENDIF() - -# use python framework mechanism on apple for the libs -IF(APPLE) - INCLUDE(CMakeFindFrameworks) - # Search for the python framework on Apple. - MESSAGE(INFO "Looking for python framework as on apple system" ) - CMAKE_FIND_FRAMEWORKS(Python) - - SET (PYTHON_LIBRARIES "-framework Python" CACHE FILEPATH "Python Framework" FORCE) -ENDIF(APPLE) - -IF(MSVC) - execute_process( - COMMAND ${PYTHON_EXECUTABLE} -c "import sys; from distutils import sysconfig; import os; prefix= sysconfig.get_config_var('prefix'); ver = sysconfig.get_python_version().replace('.', ''); lib = os.path.join(prefix,'libs\\python'+ver+'.lib'); sys.stdout.write(lib)" - OUTPUT_VARIABLE PYTHON_LIBRARIES - OUTPUT_STRIP_TRAILING_WHITESPACE - ) -ENDIF(MSVC) - -IF (MINGW) - execute_process( - COMMAND ${PYTHON_EXECUTABLE} -c "import sys; from distutils import sysconfig; import os; prefix= sysconfig.get_config_var('prefix'); ver = sysconfig.get_python_version().replace('.', ''); lib = os.path.join(prefix,'libs\\libpython'+ver+'.a'); sys.stdout.write(lib)" - OUTPUT_VARIABLE PYTHON_LIBRARIES - OUTPUT_STRIP_TRAILING_WHITESPACE - ) -ENDIF(MINGW) - -IF(NOT APPLE AND NOT MSVC AND NOT MINGW) - execute_process( - COMMAND ${PYTHON_EXECUTABLE} -c "import sys; from distutils import sysconfig; import os; libname = sysconfig.get_config_var('LDLIBRARY'); libdir= sysconfig.get_config_var('LIBDIR'); lib = os.path.join(libdir,libname); sys.stdout.write(lib)" - OUTPUT_VARIABLE PYTHON_LIBRARIES - OUTPUT_STRIP_TRAILING_WHITESPACE - ) -ENDIF(NOT APPLE AND NOT MSVC AND NOT MINGW) - -#find the site package destinaton -execute_process( - COMMAND ${PYTHON_EXECUTABLE} -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(1,0,prefix='${CMAKE_INSTALL_PREFIX}'))" - OUTPUT_VARIABLE PYTHON_SITE_PACKAGES - OUTPUT_STRIP_TRAILING_WHITESPACE -) - -execute_process( - COMMAND ${PYTHON_EXECUTABLE} -c "import sys; sys.stdout.write(str(sys.version_info[0]) + str(sys.version_info[1]))" - OUTPUT_VARIABLE PYTHON_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE -) - -execute_process( - COMMAND ${PYTHON_EXECUTABLE} -c "import sys; sys.stdout.write(str(sys.version_info[0]) + str('.') + str(sys.version_info[1]))" - OUTPUT_VARIABLE PYTHON_DOT_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE -) - -MESSAGE(STATUS "Python: Found!") -MESSAGE(STATUS " Version: " ${PYTHON_DOT_VERSION} "/" ${PYTHON_VERSION}) -MESSAGE(STATUS " Executeable: " ${PYTHON_EXECUTABLE}) -MESSAGE(STATUS " Include: " ${PYTHON_INCLUDE_PATH}) -MESSAGE(STATUS " Library: " ${PYTHON_LIBRARIES}) -MESSAGE(STATUS " Site-package directory: " ${PYTHON_SITE_PACKAGES}) +# SETUP PYTHON + +# get default python inerpreter +FIND_PROGRAM( PYTHON_EXECUTABLE python REQUIRED + PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.7\\InstallPath] [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath] [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath] +) + +SET(PYTHONINTERP_FOUND TRUE) + +# find python include path +execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_inc())" + OUTPUT_VARIABLE PYTHON_INCLUDE_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +FIND_FILE(PYTHON_H_FOUND Python.h ${PYTHON_INCLUDE_PATH}) +IF(NOT PYTHON_H_FOUND) + MESSAGE(SEND_ERROR "Python.h not found") +ENDIF() + +IF(APPLE) + + # apple changed linking to Python in OS X 10.9 (Mavericks) + # until 10.8: use Python.framework as part of the SDK (-framework Python) + # since 10.9: link to Python like any other UNIX + + # extract (minor) version number from SDK name (major version always 10 for OS X) + STRING(REGEX REPLACE ".*MacOSX([0-9]+)[.]([0-9]+)[.]sdk" "\\2" OSX_SDK_MINOR_VERSION "${CMAKE_OSX_SYSROOT}" ) + # MESSAGE("Found OS X SDK minor version: ${OSX_SDK_MINOR_VERSION}") + + IF(OSX_SDK_MINOR_VERSION GREATER 8) + SET(OSX_USE_PYTHON_FRAMEWORK "False") + MESSAGE(STATUS "Running on Mac OS X >= 10.9: Linking to Python in UNIX default way") + ELSE(OSX_SDK_MINOR_VERSION GREATER 8) + MESSAGE(STATUS "Running on Mac OS X < 10.9: Linking to Python as framework") + SET(OSX_USE_PYTHON_FRAMEWORK "True") + + INCLUDE(CMakeFindFrameworks) + # Search for the python framework on Apple. + MESSAGE(INFO "Looking for python framework as on apple system" ) + CMAKE_FIND_FRAMEWORKS(Python) + SET (PYTHON_LIBRARIES "-framework Python" CACHE FILEPATH "Python Framework" FORCE) + ENDIF(OSX_SDK_MINOR_VERSION GREATER 8) + +ENDIF(APPLE) + +IF(MSVC) + execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "import sys; from distutils import sysconfig; import os; prefix= sysconfig.get_config_var('prefix'); ver = sysconfig.get_python_version().replace('.', ''); lib = os.path.join(prefix,'libs\\python'+ver+'.lib'); sys.stdout.write(lib)" + OUTPUT_VARIABLE PYTHON_LIBRARIES + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +ENDIF(MSVC) + +IF (MINGW) + execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "import sys; from distutils import sysconfig; import os; prefix= sysconfig.get_config_var('prefix'); ver = sysconfig.get_python_version().replace('.', ''); lib = os.path.join(prefix,'libs\\libpython'+ver+'.a'); sys.stdout.write(lib)" + OUTPUT_VARIABLE PYTHON_LIBRARIES + OUTPUT_STRIP_TRAILING_WHITESPACEsysconfig.get_config_var('LIBDIR') + ) +ENDIF(MINGW) + +IF(NOT OSX_USE_PYTHON_FRAMEWORK AND NOT MSVC AND NOT MINGW) + execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "import sys; from distutils import sysconfig; import os; libname = sysconfig.get_config_var('LDLIBRARY'); libdir = sysconfig.get_config_var('LIBPL'); lib = os.path.join(libdir,libname); out = lib if os.path.exists(lib) else os.path.join(libdir, sysconfig.get_config_var('LIBRARY')); sys.stdout.write(out);" + OUTPUT_VARIABLE PYTHON_LIBRARIES + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +ENDIF(NOT OSX_USE_PYTHON_FRAMEWORK AND NOT MSVC AND NOT MINGW) + +#find the site package destinaton +execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(1,0,prefix='${CMAKE_INSTALL_PREFIX}'))" + OUTPUT_VARIABLE PYTHON_SITE_PACKAGES + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "import sys; sys.stdout.write(str(sys.version_info[0]))" + OUTPUT_VARIABLE PYTHON_MAJOR_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "import sys; sys.stdout.write(str(sys.version_info[1]))" + OUTPUT_VARIABLE PYTHON_MINOR_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +SET(PYTHON_VERSION "${PYTHON_MAJOR_VERSION}${PYTHON_MINOR_VERSION}") +SET(PYTHON_DOT_VERSION "${PYTHON_MAJOR_VERSION}.${PYTHON_MINOR_VERSION}") + +MESSAGE(STATUS "Python: Found!") +MESSAGE(STATUS " Version: " ${PYTHON_DOT_VERSION} "/" ${PYTHON_VERSION}) +MESSAGE(STATUS " Executeable: " ${PYTHON_EXECUTABLE}) +MESSAGE(STATUS " Include: " ${PYTHON_INCLUDE_PATH}) +MESSAGE(STATUS " Library: " ${PYTHON_LIBRARIES}) +MESSAGE(STATUS " Site-package directory: " ${PYTHON_SITE_PACKAGES}) diff --git a/python/crpropa.i b/python/crpropa.i index 47f404002..55afa6768 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -77,15 +77,15 @@ using std::ptrdiff_t; { $action } + catch (Swig::DirectorException &e) { + SWIG_exception(SWIG_RuntimeError, e.getMessage()); + } catch (const std::exception& e) { SWIG_exception(SWIG_RuntimeError, e.what()); } catch (const char *e) { SWIG_exception(SWIG_RuntimeError, e); } - catch (Swig::DirectorException &e) { - SWIG_exception(SWIG_RuntimeError, e.getMessage()); - } } %ignore operator<<; From 499c7f67395e350273a1831be95e49035ba968c5 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sat, 19 Apr 2014 15:40:04 +0200 Subject: [PATCH 0402/1298] SourceProperty: remove method overloading for better python compatibility improve testSource --- include/crpropa/Source.h | 42 ++++++++++++++++++------------------ src/Source.cpp | 46 ++++++++++++++++++++-------------------- src/XmlExecute.cpp | 2 +- test/testSource.cpp | 37 ++++++++++++++++++++------------ 4 files changed, 68 insertions(+), 59 deletions(-) diff --git a/include/crpropa/Source.h b/include/crpropa/Source.h index df8346041..eaaeefdb7 100644 --- a/include/crpropa/Source.h +++ b/include/crpropa/Source.h @@ -14,8 +14,8 @@ namespace crpropa { */ class SourceProperty: public Referenced { public: - virtual void prepare(ParticleState& particle) const; - virtual void prepare(Candidate& candidate) const; + virtual void prepareParticle(ParticleState& particle) const; + virtual void prepareCandidate(Candidate& candidate) const; }; /** @@ -56,7 +56,7 @@ class SourceParticleType: public SourceProperty { double id; public: SourceParticleType(int id); - void prepare(ParticleState &particle) const; + void prepareParticle(ParticleState &particle) const; }; /** @@ -68,7 +68,7 @@ class SourceMultipleParticleTypes: public SourceProperty { std::vector cdf; public: void add(int id, double weight = 1); - void prepare(ParticleState &particle) const; + void prepareParticle(ParticleState &particle) const; }; /** @@ -79,7 +79,7 @@ class SourceEnergy: public SourceProperty { double E; public: SourceEnergy(double energy); - void prepare(ParticleState &particle) const; + void prepareParticle(ParticleState &particle) const; }; /** @@ -92,7 +92,7 @@ class SourcePowerLawSpectrum: public SourceProperty { double index; public: SourcePowerLawSpectrum(double Emin, double Emax, double index); - void prepare(ParticleState &particle) const; + void prepareParticle(ParticleState &particle) const; }; /** @@ -111,7 +111,7 @@ class SourceComposition: public SourceProperty { SourceComposition(double Emin, double Rmax, double index); void add(int id, double abundance); void add(int A, int Z, double abundance); - void prepare(ParticleState &particle) const; + void prepareParticle(ParticleState &particle) const; }; /** @@ -122,7 +122,7 @@ class SourcePosition: public SourceProperty { Vector3d position; /**< Source position */ public: SourcePosition(Vector3d position); - void prepare(ParticleState &state) const; + void prepareParticle(ParticleState &state) const; }; /** @@ -134,7 +134,7 @@ class SourceMultiplePositions: public SourceProperty { std::vector cdf; public: void add(Vector3d position, double weight = 1); - void prepare(ParticleState &particle) const; + void prepareParticle(ParticleState &particle) const; }; /** @@ -146,7 +146,7 @@ class SourceUniformSphere: public SourceProperty { double radius; public: SourceUniformSphere(Vector3d center, double radius); - void prepare(ParticleState &particle) const; + void prepareParticle(ParticleState &particle) const; }; /** @@ -158,7 +158,7 @@ class SourceUniformShell: public SourceProperty { double radius; public: SourceUniformShell(Vector3d center, double radius); - void prepare(ParticleState &particle) const; + void prepareParticle(ParticleState &particle) const; }; /** @@ -174,7 +174,7 @@ class SourceUniformBox: public SourceProperty { @param size upper box corner */ SourceUniformBox(Vector3d origin, Vector3d size); - void prepare(ParticleState &particle) const; + void prepareParticle(ParticleState &particle) const; }; /** @@ -197,7 +197,7 @@ class SourceUniform1D: public SourceProperty { @param withCosmology specify if universe expanding */ SourceUniform1D(double minD, double maxD, bool withCosmology=true); - void prepare(ParticleState& particle) const; + void prepareParticle(ParticleState& particle) const; }; /** @@ -208,7 +208,7 @@ class SourceDensityGrid: public SourceProperty { ref_ptr grid; public: SourceDensityGrid(ref_ptr densityGrid); - void prepare(ParticleState &particle) const; + void prepareParticle(ParticleState &particle) const; }; /** @@ -219,7 +219,7 @@ class SourceDensityGrid1D: public SourceProperty { ref_ptr grid; public: SourceDensityGrid1D(ref_ptr densityGrid); - void prepare(ParticleState &particle) const; + void prepareParticle(ParticleState &particle) const; }; /** @@ -228,7 +228,7 @@ class SourceDensityGrid1D: public SourceProperty { */ class SourceIsotropicEmission: public SourceProperty { public: - void prepare(ParticleState &particle) const; + void prepareParticle(ParticleState &particle) const; }; /** @@ -239,7 +239,7 @@ class SourceDirection: public SourceProperty { Vector3d direction; public: SourceDirection(Vector3d direction = Vector3d(-1, 0, 0)); - void prepare(ParticleState &particle) const; + void prepareParticle(ParticleState &particle) const; }; /** @@ -251,7 +251,7 @@ class SourceEmissionCone: public SourceProperty { double aperture; public: SourceEmissionCone(Vector3d direction, double aperture); - void prepare(ParticleState &particle) const; + void prepareParticle(ParticleState &particle) const; }; /** @@ -262,7 +262,7 @@ class SourceRedshift: public SourceProperty { double z; public: SourceRedshift(double z); - void prepare(Candidate &candidate) const; + void prepareCandidate(Candidate &candidate) const; }; /** @@ -273,7 +273,7 @@ class SourceUniformRedshift: public SourceProperty { double zmin, zmax; public: SourceUniformRedshift(double zmin, double zmax); - void prepare(Candidate &candidate) const; + void prepareCandidate(Candidate &candidate) const; }; /** @@ -285,7 +285,7 @@ class SourceUniformRedshift: public SourceProperty { */ class SourceRedshift1D: public SourceProperty { public: - void prepare(Candidate &candidate) const; + void prepareCandidate(Candidate &candidate) const; }; }// namespace crpropa diff --git a/src/Source.cpp b/src/Source.cpp index 3ea9c553e..39de1ffc2 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -7,12 +7,12 @@ namespace crpropa { -void SourceProperty::prepare(ParticleState& particle) const { +void SourceProperty::prepareParticle(ParticleState& particle) const { } -void SourceProperty::prepare(Candidate& candidate) const { +void SourceProperty::prepareCandidate(Candidate& candidate) const { ParticleState &source = candidate.source; - prepare(source); + prepareParticle(source); candidate.created = source; candidate.current = source; candidate.previous = source; @@ -25,7 +25,7 @@ void Source::addProperty(SourceProperty* property) { ref_ptr Source::getCandidate() const { ref_ptr candidate = new Candidate(); for (int i = 0; i < properties.size(); i++) - (*properties[i]).prepare(*candidate); + (*properties[i]).prepareCandidate(*candidate); return candidate; } @@ -47,7 +47,7 @@ SourceParticleType::SourceParticleType(int id) : id(id) { } -void SourceParticleType::prepare(ParticleState& particle) const { +void SourceParticleType::prepareParticle(ParticleState& particle) const { particle.setId(id); } @@ -55,7 +55,7 @@ SourceEnergy::SourceEnergy(double energy) : E(energy) { } -void SourceEnergy::prepare(ParticleState& p) const { +void SourceEnergy::prepareParticle(ParticleState& p) const { p.setEnergy(E); } @@ -64,7 +64,7 @@ SourcePowerLawSpectrum::SourcePowerLawSpectrum(double Emin, double Emax, Emin(Emin), Emax(Emax), index(index) { } -void SourcePowerLawSpectrum::prepare(ParticleState& particle) const { +void SourcePowerLawSpectrum::prepareParticle(ParticleState& particle) const { Random &random = Random::instance(); double E = random.randPowerLaw(index, Emin, Emax); particle.setEnergy(E); @@ -77,7 +77,7 @@ void SourceMultipleParticleTypes::add(int id, double a) { cdf.push_back(a); } -void SourceMultipleParticleTypes::prepare(ParticleState& particle) const { +void SourceMultipleParticleTypes::prepareParticle(ParticleState& particle) const { if (particleTypes.size() == 0) throw std::runtime_error("SourceMultipleParticleTypes: no nuclei set"); size_t i = Random::instance().randBin(cdf); @@ -110,7 +110,7 @@ void SourceComposition::add(int A, int Z, double a) { add(nucleusId(A, Z), a); } -void SourceComposition::prepare(ParticleState& particle) const { +void SourceComposition::prepareParticle(ParticleState& particle) const { if (nuclei.size() == 0) throw std::runtime_error("SourceComposition: No source isotope set"); @@ -130,7 +130,7 @@ SourcePosition::SourcePosition(Vector3d position) : position(position) { } -void SourcePosition::prepare(ParticleState& particle) const { +void SourcePosition::prepareParticle(ParticleState& particle) const { particle.setPosition(position); } @@ -141,7 +141,7 @@ void SourceMultiplePositions::add(Vector3d pos, double weight) { cdf.push_back(weight); } -void SourceMultiplePositions::prepare(ParticleState& particle) const { +void SourceMultiplePositions::prepareParticle(ParticleState& particle) const { if (positions.size() == 0) throw std::runtime_error("SourceMultiplePositions: no position set"); size_t i = Random::instance().randBin(cdf); @@ -152,7 +152,7 @@ SourceUniformSphere::SourceUniformSphere(Vector3d center, double radius) : center(center), radius(radius) { } -void SourceUniformSphere::prepare(ParticleState& particle) const { +void SourceUniformSphere::prepareParticle(ParticleState& particle) const { Random &random = Random::instance(); double r = pow(random.rand(), 1. / 3.) * radius; particle.setPosition(random.randVector() * r); @@ -162,7 +162,7 @@ SourceUniformShell::SourceUniformShell(Vector3d center, double radius) : center(center), radius(radius) { } -void SourceUniformShell::prepare(ParticleState& particle) const { +void SourceUniformShell::prepareParticle(ParticleState& particle) const { Random &random = Random::instance(); particle.setPosition(random.randVector() * radius); } @@ -171,7 +171,7 @@ SourceUniformBox::SourceUniformBox(Vector3d origin, Vector3d size) : origin(origin), size(size) { } -void SourceUniformBox::prepare(ParticleState& particle) const { +void SourceUniformBox::prepareParticle(ParticleState& particle) const { Random &random = Random::instance(); Vector3d pos(random.rand(), random.rand(), random.rand()); particle.setPosition(pos * size + origin); @@ -188,7 +188,7 @@ SourceUniform1D::SourceUniform1D(double minD, double maxD, bool withCosmology) { } } -void SourceUniform1D::prepare(ParticleState& particle) const { +void SourceUniform1D::prepareParticle(ParticleState& particle) const { Random& random = Random::instance(); double d = random.rand() * (maxD - minD) + minD; if (withCosmology) @@ -209,7 +209,7 @@ SourceDensityGrid::SourceDensityGrid(ref_ptr grid) : } } -void SourceDensityGrid::prepare(ParticleState& particle) const { +void SourceDensityGrid::prepareParticle(ParticleState& particle) const { Random &random = Random::instance(); // draw random bin @@ -239,7 +239,7 @@ SourceDensityGrid1D::SourceDensityGrid1D(ref_ptr grid) : } } -void SourceDensityGrid1D::prepare(ParticleState& particle) const { +void SourceDensityGrid1D::prepareParticle(ParticleState& particle) const { Random &random = Random::instance(); // draw random bin @@ -253,7 +253,7 @@ void SourceDensityGrid1D::prepare(ParticleState& particle) const { particle.setPosition(pos); } -void SourceIsotropicEmission::prepare(ParticleState& particle) const { +void SourceIsotropicEmission::prepareParticle(ParticleState& particle) const { Random &random = Random::instance(); particle.setDirection(random.randVector()); } @@ -262,7 +262,7 @@ SourceDirection::SourceDirection(Vector3d direction) : direction(direction) { } -void SourceDirection::prepare(ParticleState& particle) const { +void SourceDirection::prepareParticle(ParticleState& particle) const { particle.setDirection(direction); } @@ -270,7 +270,7 @@ SourceEmissionCone::SourceEmissionCone(Vector3d direction, double aperture) : direction(direction), aperture(aperture) { } -void SourceEmissionCone::prepare(ParticleState& particle) const { +void SourceEmissionCone::prepareParticle(ParticleState& particle) const { Random &random = Random::instance(); particle.setDirection(random.randConeVector(direction, aperture)); } @@ -279,7 +279,7 @@ SourceRedshift::SourceRedshift(double z) : z(z) { } -void SourceRedshift::prepare(Candidate& candidate) const { +void SourceRedshift::prepareCandidate(Candidate& candidate) const { candidate.setRedshift(z); } @@ -287,12 +287,12 @@ SourceUniformRedshift::SourceUniformRedshift(double zmin, double zmax) : zmin(zmin), zmax(zmax) { } -void SourceUniformRedshift::prepare(Candidate& candidate) const { +void SourceUniformRedshift::prepareCandidate(Candidate& candidate) const { double z = Random::instance().randUniform(zmin, zmax); candidate.setRedshift(z); } -void SourceRedshift1D::prepare(Candidate& candidate) const { +void SourceRedshift1D::prepareCandidate(Candidate& candidate) const { double d = candidate.source.getPosition().getR(); double z = comovingDistance2Redshift(d); candidate.setRedshift(z); diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 7610b9b25..9ed2b2979 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -559,7 +559,7 @@ void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { } ParticleState p; for (int i = 0; i < nSources; i++) { - sourceDistribution->prepare(p); + sourceDistribution->prepareParticle(p); sourcePositions->add(p.getPosition()); cout << " - Position = " << p.getPosition() / Mpc << " Mpc" << endl; diff --git a/test/testSource.cpp b/test/testSource.cpp index 248a8874a..08e3cdd21 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -9,7 +9,7 @@ TEST(SourcePosition, simpleTest) { Vector3d position(1, 2, 3); SourcePosition source(position); ParticleState ps; - source.prepare(ps); + source.prepareParticle(ps); EXPECT_EQ(position, ps.getPosition()); } @@ -21,14 +21,12 @@ TEST(SourceMultiplePositions, simpleTest) { int n1 = 0; int n2 = 0; for (int i = 0; i < 10000; i++) { - source.prepare(ps); + source.prepareParticle(ps); if (ps.getPosition().x == 1) n1++; else if (ps.getPosition().x == 2) n2++; } - std::cout << n1 << std::endl; - std::cout << n2 << std::endl; EXPECT_NEAR(n1, 2500, 2 * sqrt(2500)); EXPECT_NEAR(n2, 7500, 2 * sqrt(7500)); } @@ -38,7 +36,7 @@ TEST(SourceUniformSphere, simpleTest) { double radius = 110; SourceUniformSphere source(center, radius); ParticleState ps; - source.prepare(ps); + source.prepareParticle(ps); double distance = ps.getPosition().getDistanceTo(center); EXPECT_GE(radius, distance); } @@ -48,7 +46,7 @@ TEST(SourceUniformBox, simpleTest) { Vector3d size(13, 55, 192); SourceUniformBox box(origin, size); ParticleState p; - box.prepare(p); + box.prepareParticle(p); Vector3d pos = p.getPosition(); EXPECT_LE(origin.x, pos.x); EXPECT_LE(origin.y, pos.y); @@ -72,7 +70,7 @@ TEST(SourceDensityGrid, withInRange) { SourceDensityGrid source(grid); ParticleState p; - source.prepare(p); + source.prepareParticle(p); Vector3d pos = p.getPosition(); // dialed positions should be within the volume (0, 0, 0) - (10, 10, 10) @@ -106,7 +104,7 @@ TEST(SourceDensityGrid, OneAllowedCell) { int nFalse = 0; Vector3d mean(0, 0, 0); for (int i = 0; i < 10000; i++) { - source.prepare(p); + source.prepareParticle(p); Vector3d pos = p.getPosition(); mean += pos; if ((pos.x < 0) or (pos.x > 2) or (pos.y < 0) or (pos.y > 2) @@ -139,7 +137,7 @@ TEST(SourceDensityGrid1D, withInRange) { SourceDensityGrid1D source(grid); ParticleState p; - source.prepare(p); + source.prepareParticle(p); Vector3d pos = p.getPosition(); // dialed position should be within the range 0 - 10 EXPECT_LE(0, pos.x); @@ -163,7 +161,7 @@ TEST(SourceDensityGrid1D, OneAllowedCell) { ParticleState p; for (int i = 0; i < 100; i++) { - source.prepare(p); + source.prepareParticle(p); // dialed position should be in range 5-6 Vector3d pos = p.getPosition(); EXPECT_LE(5, pos.x); @@ -177,7 +175,7 @@ TEST(SourcePowerLawSpectrum, simpleTest) { double index = -2.7; SourcePowerLawSpectrum spectrum(Emin, Emax, index); ParticleState ps; - spectrum.prepare(ps); + spectrum.prepareParticle(ps); // energy should be within Emin - Emax EXPECT_LE(Emin, ps.getEnergy()); @@ -191,7 +189,7 @@ TEST(SourceComposition, simpleTest) { SourceComposition source(Emin, Rmax, index); source.add(nucleusId(6, 3), 1); ParticleState p; - source.prepare(p); + source.prepareParticle(p); EXPECT_EQ(nucleusId(6, 3), p.getId()); EXPECT_LE(Emin, p.getEnergy()); EXPECT_GE(6 * Rmax, p.getEnergy()); @@ -200,7 +198,7 @@ TEST(SourceComposition, simpleTest) { TEST(SourceComposition, throwNoIsotope) { SourceComposition source(1, 10, -1); ParticleState ps; - EXPECT_THROW(source.prepare(ps), std::runtime_error); + EXPECT_THROW(source.prepareParticle(ps), std::runtime_error); } TEST(Source, allPropertiesUsed) { @@ -209,10 +207,21 @@ TEST(Source, allPropertiesUsed) { source.addProperty(new SourceIsotropicEmission()); source.addProperty(new SourcePowerLawSpectrum(5 * EeV, 100 * EeV, -2)); source.addProperty(new SourceParticleType(nucleusId(8, 4))); + source.addProperty(new SourceRedshift(2)); Candidate c = *source.getCandidate(); - ParticleState p = c.created; + EXPECT_EQ(2, c.getRedshift()); + + ParticleState p; + + p = c.source; + EXPECT_EQ(nucleusId(8, 4), p.getId()); + EXPECT_LE(5 * EeV, p.getEnergy()); + EXPECT_GE(100 * EeV, p.getEnergy()); + EXPECT_EQ(Vector3d(10, 0, 0) * Mpc, p.getPosition()); + + p = c.created; EXPECT_EQ(nucleusId(8, 4), p.getId()); EXPECT_LE(5 * EeV, p.getEnergy()); EXPECT_GE(100 * EeV, p.getEnergy()); From 42f83ecaee086c62b0f23f7d2954d65dc600ff3f Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sat, 19 Apr 2014 15:55:26 +0200 Subject: [PATCH 0403/1298] add SWIG directors for Source and SourceProperty remove currently unneeded? SWIG templates for SourceRefPtr and SourcePropertyRefPtr --- python/crpropa.i | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/python/crpropa.i b/python/crpropa.i index 55afa6768..959ce9fe1 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -121,7 +121,7 @@ using std::ptrdiff_t; %template(ModuleRefPtr) crpropa::ref_ptr; %template(stdModuleList) std::list< crpropa::ref_ptr >; -%feature("director") crpropa::Module; +%feature("director") crpropa::Module; %include "crpropa/Module.h" %implicitconv crpropa::ref_ptr; @@ -166,18 +166,20 @@ using std::ptrdiff_t; %include "crpropa/module/Redshift.h" %include "crpropa/module/Tools.h" -%template(SourceRefPtr) crpropa::ref_ptr; -%include "crpropa/Source.h" - %template(ModuleListRefPtr) crpropa::ref_ptr; %include "crpropa/ModuleList.h" +%feature("director") Source; +%feature("director") SourceProperty; +%include "crpropa/Source.h" // nice python print %pythoncode %{ Module.__str__ = Module.getDescription + def Vector3__str__(self): return "(%.4e, %.4e, %.4e)" % (self.x, self.y, self.z) + Vector3d.__str__ = Vector3__str__ Vector3f.__str__ = Vector3__str__ %} From ad7c9282ce33d69d227a703c5edcbcaacce7a68e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Tue, 29 Apr 2014 21:50:14 +0200 Subject: [PATCH 0404/1298] add SourceGenericComposition, use muParser for generic expressions for energy sprectrum --- CMakeLists.txt | 10 +++++ cmake/FindmuParser.cmake | 32 +++++++++++++++ include/crpropa/Source.h | 26 +++++++++++++ python/crpropa.i | 12 ++++-- src/Source.cpp | 84 ++++++++++++++++++++++++++++++++++++++++ test/testSource.cpp | 33 ++++++++++++++++ 6 files changed, 193 insertions(+), 4 deletions(-) create mode 100644 cmake/FindmuParser.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index d20191080..3f98413b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,6 +102,16 @@ if(ENABLE_ROOT) endif(ROOT_FOUND) endif(ENABLE_ROOT) +find_package(muParser) +if(MUPARSER_FOUND) + list(APPEND CRPROPA_EXTRA_INCLUDES ${MUPARSER_INCLUDE_DIR}) + list(APPEND CRPROPA_EXTRA_LIBRARIES ${MUPARSER_LIBRARY}) + add_definitions (-DCRPROPA_HAVE_MUPARSER) + list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_MUPARSER) + list(APPEND CRPROPA_SWIG_DEFINES -I${MUPARSER_INCLUDE_DIR}) +endif(MUPARSER_FOUND) + + # Google Performance Tools (optional as possible performance tweak) find_package(GooglePerfTools) set(TCMALLOC) diff --git a/cmake/FindmuParser.cmake b/cmake/FindmuParser.cmake new file mode 100644 index 000000000..628ab90ab --- /dev/null +++ b/cmake/FindmuParser.cmake @@ -0,0 +1,32 @@ +# - Try to find muParser +# Once done this will define +# MUPARSER_FOUND - System has LibXml2 +# MUPARSER_INCLUDE_DIRS - The LibXml2 include directories +# MUPARSER_LIBRARIES - The libraries needed to use LibXml2 +# MUPARSER_DEFINITIONS - Compiler switches required for using LibXml2 + +find_package(PkgConfig) +pkg_check_modules(PC_MUPARSER QUIET muparser) +set(MUPARSER_DEFINITIONS ${PC_MUPARSER_CFLAGS_OTHER}) + +find_path(MUPARSER_INCLUDE_DIR muParser.h + HINTS ${PC_MUPARSER_INCLUDEDIR} ${PC_MUPARSER_INCLUDE_DIRS}) + +find_library(MUPARSER_LIBRARY NAMES muparser libmuparser + HINTS ${PC_MUPARSER_LIBDIR} ${PC_MUPARSER_LIBRARY_DIRS} ) + +set(MUPARSER_LIBRARIES ${MUPARSER_LIBRARY} ) +set(MUPARSER_INCLUDE_DIRS ${MUPARSER_INCLUDE_DIR} ) + +set(MUPARSER_FOUND FALSE) +if(MUPARSER_INCLUDE_DIR AND MUPARSER_LIBRARY) + set(MUPARSER_FOUND TRUE) + MESSAGE(STATUS "muParser: Found!") +else() + MESSAGE(STATUS "muParser: NOT Found!") +endif() + +MESSAGE(STATUS " Include: ${MUPARSER_INCLUDE_DIR}") +MESSAGE(STATUS " Library: ${MUPARSER_LIBRARY}") + +mark_as_advanced(MUPARSER_INCLUDE_DIR MUPARSER_LIBRARY ) diff --git a/include/crpropa/Source.h b/include/crpropa/Source.h index eaaeefdb7..542403647 100644 --- a/include/crpropa/Source.h +++ b/include/crpropa/Source.h @@ -114,6 +114,32 @@ class SourceComposition: public SourceProperty { void prepareParticle(ParticleState &particle) const; }; +#ifdef CRPROPA_HAVE_MUPARSER +/** + @class SourceGenericComposition + @brief Multiple nuclei with energies described by an expression string + */ +class SourceGenericComposition: public SourceProperty { + struct Nucleus { + int id; + std::vector cdf; + }; + + double Emin, Emax; + size_t steps; + std::string expression; + std::vector energy; + + std::vector nuclei; + std::vector cdf; +public: + SourceGenericComposition(double Emin, double Emax, std::string expression, size_t steps = 1024); + void add(int id, double abundance); + void add(int A, int Z, double abundance); + void prepareParticle(ParticleState &particle) const; +}; +#endif + /** @class SourcePosition @brief Position of a point source diff --git a/python/crpropa.i b/python/crpropa.i index 959ce9fe1..0e7ba3853 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -92,6 +92,7 @@ using std::ptrdiff_t; %ignore operator>>; %ignore *::operator=; %ignore operator crpropa::Source*; +%ignore operator crpropa::SourceProperty*; %ignore operator crpropa::Candidate*; %ignore operator crpropa::Module*; %ignore operator crpropa::ModuleList*; @@ -166,13 +167,16 @@ using std::ptrdiff_t; %include "crpropa/module/Redshift.h" %include "crpropa/module/Tools.h" +%template(SourceRefPtr) crpropa::ref_ptr; +%feature("director") crpropa::Source; +%template(SourcePropertyRefPtr) crpropa::ref_ptr; +%feature("director") crpropa::SourceProperty; +%include "crpropa/Source.h" + + %template(ModuleListRefPtr) crpropa::ref_ptr; %include "crpropa/ModuleList.h" -%feature("director") Source; -%feature("director") SourceProperty; -%include "crpropa/Source.h" - // nice python print %pythoncode %{ Module.__str__ = Module.getDescription diff --git a/src/Source.cpp b/src/Source.cpp index 39de1ffc2..6c9445e53 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -3,6 +3,11 @@ #include "crpropa/Cosmology.h" #include "HepPID/ParticleIDMethods.hh" + +#ifdef CRPROPA_HAVE_MUPARSER +#include "muParser.h" +#endif + #include namespace crpropa { @@ -59,6 +64,85 @@ void SourceEnergy::prepareParticle(ParticleState& p) const { p.setEnergy(E); } +#ifdef CRPROPA_HAVE_MUPARSER +SourceGenericComposition::SourceGenericComposition(double Emin, double Emax, std::string expression, size_t steps) : + Emin(Emin), Emax(Emax), expression(expression), steps(steps) { + + // precalculate energy bins + double logEmin = ::log10(Emin); + double logEmax = ::log10(Emax); + double logStep = (logEmax - logEmin) / (steps-1); + energy.resize(steps); + for (size_t i = 0; i < steps; i++) { + energy[i] = ::pow(10, logEmin + i * logStep); + } +} + +void SourceGenericComposition::add(int id, double weight) { + int A = massNumber(id); + int Z = chargeNumber(id); + + Nucleus n; + n.id = id; + + // calculate nuclei cdf + mu::Parser p; + double E; + p.DefineVar("E", &E); + p.DefineConst("Emin", Emin); + p.DefineConst("Emax", Emax); + p.DefineConst("steps", steps); + p.DefineConst("A", (double)A); + p.DefineConst("Z", (double)Z); + p.SetExpr(expression); + + // calculate pdf + n.cdf.resize(steps); + for (std::size_t i=0; i 0) + weight += cdf.back(); + cdf.push_back(weight); +} + +void SourceGenericComposition::add(int A, int Z, double a) { + add(nucleusId(A, Z), a); +} + +void SourceGenericComposition::prepareParticle(ParticleState& particle) const { + if (nuclei.size() == 0) + throw std::runtime_error("SourceComposition: No source isotope set"); + + Random &random = Random::instance(); + + + // draw random particle type + size_t iN = random.randBin(cdf); + const Nucleus &n = nuclei[iN]; + particle.setId(n.id); + + // random energy + double E = interpolate(random.rand() * n.cdf.back(), n.cdf, energy); + particle.setEnergy(E); +} +#endif + SourcePowerLawSpectrum::SourcePowerLawSpectrum(double Emin, double Emax, double index) : Emin(Emin), Emax(Emax), index(index) { diff --git a/test/testSource.cpp b/test/testSource.cpp index 08e3cdd21..d094dc82c 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -195,6 +195,39 @@ TEST(SourceComposition, simpleTest) { EXPECT_GE(6 * Rmax, p.getEnergy()); } +#ifdef CRPROPA_HAVE_MUPARSER +TEST(SourceGenericComposition, simpleTest) { + double Emin = 10; + double Emax = 100; + SourceGenericComposition source(Emin, Emax, "E^-2"); + int id1 = nucleusId(6, 3); + int id2 = nucleusId(12, 6); + source.add(id1, 1); + source.add(id2, 10); + ParticleState p; + size_t id1Count = 0, id2Count = 0; + size_t ElowCount = 0, EhighCount = 0; + size_t n = 100000; + for (size_t i = 0; i < n; i++) { + source.prepareParticle(p); + if (p.getId() == id1) + id1Count++; + if (p.getId() == id2) + id2Count++; + double e = p.getEnergy(); + if ( (e >= Emin) && (e < 20)) + ElowCount++; + if ( (e >= 20) && (e <= Emax)) + EhighCount++; + + } + EXPECT_EQ(n, id1Count + id2Count); + EXPECT_EQ(n, ElowCount + EhighCount); + EXPECT_NEAR((float)id1Count/(float)id2Count, 0.1, 0.01); + EXPECT_NEAR((float)ElowCount/(float)EhighCount, 1.25, 0.1); +} +#endif + TEST(SourceComposition, throwNoIsotope) { SourceComposition source(1, 10, -1); ParticleState ps; From 9f540b2a845017c767781045d8fc26eb64c4bd10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Wed, 30 Apr 2014 15:23:22 +0200 Subject: [PATCH 0405/1298] add PhotonOutput1D module --- CMakeLists.txt | 5 +-- include/crpropa/Candidate.h | 2 +- include/crpropa/module/PhotonOutput1D.h | 24 +++++++++++ python/crpropa.i | 2 + src/module/PhotonOutput1D.cpp | 57 +++++++++++++++++++++++++ 5 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 include/crpropa/module/PhotonOutput1D.h create mode 100644 src/module/PhotonOutput1D.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f98413b2..661bb41a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,6 +153,7 @@ add_library(crpropa SHARED src/module/OutputShell.cpp src/module/OutputROOT.cpp src/module/OutputCRPropa2.cpp + src/module/PhotonOutput1D.cpp src/module/PhotonDINT.cpp src/module/PhotonDINT1D.cpp src/module/PhotonEleCa.cpp @@ -201,10 +202,6 @@ if(ENABLE_TESTING) add_executable(testPropagation test/testPropagation.cpp) target_link_libraries(testPropagation crpropa gtest gtest_main pthread) add_test(testPropagation testPropagation) - - add_executable(testDINT test/testDINT.cpp) - target_link_libraries(testDINT crpropa gtest gtest_main pthread) - add_test(testPropagation testDINT) add_executable(testBreakCondition test/testBreakCondition.cpp) target_link_libraries(testBreakCondition crpropa gtest gtest_main pthread) diff --git a/include/crpropa/Candidate.h b/include/crpropa/Candidate.h index 923f856c2..ba81ac0b7 100644 --- a/include/crpropa/Candidate.h +++ b/include/crpropa/Candidate.h @@ -21,7 +21,7 @@ namespace crpropa { class Candidate: public Referenced { public: ParticleState source; /**< Particle state at the source */ - ParticleState created; /**< Particle state at the creation */ + ParticleState created; /**< Particle state of parent particle at the time of creation */ ParticleState current; /**< Current particle state */ ParticleState previous; /**< Particle state at the end of the previous step */ diff --git a/include/crpropa/module/PhotonOutput1D.h b/include/crpropa/module/PhotonOutput1D.h new file mode 100644 index 000000000..39237bc74 --- /dev/null +++ b/include/crpropa/module/PhotonOutput1D.h @@ -0,0 +1,24 @@ +#ifndef CRPROPA_PHOTON_OUTPUT_H +#define CRPROPA_PHOTON_OUTPUT_H + +#include "crpropa/Module.h" + +#include +#include + +namespace crpropa { + +class PhotonOutput1D: public Module { +private: + std::string filename; + mutable std::ofstream output; +public: + PhotonOutput1D(const std::string &filename); + ~PhotonOutput1D(); + void process(Candidate *candidate) const; + std::string getDescription() const; +}; + +} // namespace crpropa + +#endif // CRPROPA_PHOTON_OUTPUT_H diff --git a/python/crpropa.i b/python/crpropa.i index 0e7ba3853..a0c19f569 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -40,6 +40,7 @@ using std::ptrdiff_t; #include "crpropa/module/PhotonDINT.h" #include "crpropa/module/PhotonDINT1D.h" #include "crpropa/module/PhotonEleCa.h" +#include "crpropa/module/PhotonOutput1D.h" #include "crpropa/module/SimplePropagation.h" #include "crpropa/module/DeflectionCK.h" #include "crpropa/module/Tools.h" @@ -160,6 +161,7 @@ using std::ptrdiff_t; %include "crpropa/module/PhotonDINT.h" %include "crpropa/module/PhotonDINT1D.h" %include "crpropa/module/PhotonEleCa.h" +%include "crpropa/module/PhotonOutput1D.h" %include "crpropa/module/ElectronPairProduction.h" %include "crpropa/module/NuclearDecay.h" %include "crpropa/module/PhotoPionProduction.h" diff --git a/src/module/PhotonOutput1D.cpp b/src/module/PhotonOutput1D.cpp new file mode 100644 index 000000000..087186f14 --- /dev/null +++ b/src/module/PhotonOutput1D.cpp @@ -0,0 +1,57 @@ +#include "crpropa/module/PhotonOutput1D.h" + +#include +#include +#include + +using namespace std; + +namespace crpropa { + +PhotonOutput1D::PhotonOutput1D(const string &filename) : + filename(filename), output(filename.c_str()) { + output << "# iE\tiID\tE\tID\tR\tz\n"; + output << "#\n"; + output << "# iE Energy [EeV] of parent particle\n"; + output << "# iID Id of parent particle\n"; + output << "# E Energy [EeV]\n"; + output << "# R Distance [Mpc]\n"; + output << "# z Redshift\n"; + output << "#\n"; +} + +PhotonOutput1D::~PhotonOutput1D() { +} + +void PhotonOutput1D::process(Candidate *candidate) const { + if (candidate->current.getId() != 22) + return; + + char buffer[1024]; + size_t p = 0; + + p += sprintf(buffer + p, "%8.4f\t", candidate->created.getEnergy() / EeV); + p += sprintf(buffer + p, "%10i\t", candidate->created.getId()); + + p += sprintf(buffer + p, "%8.4f\t", candidate->current.getEnergy() / EeV); + p += sprintf(buffer + p, "%10i\t", candidate->current.getId()); + p += sprintf(buffer + p, "%8.4f\t", + candidate->current.getPosition().getR() / Mpc); + p += sprintf(buffer + p, "%8.4f\n", candidate->getRedshift()); + +#pragma omp critical + { + output.write(buffer, p); + //output.flush(); + } + + candidate->setActive(false); +} + +string PhotonOutput1D::getDescription() const { + std::stringstream s; + s << "PhotonOutput1D: Output file = " << filename; + return s.str(); +} + +} // namespace crpropa From 376c710f48a605019fdb6af280827134b41efa6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Wed, 30 Apr 2014 16:21:11 +0200 Subject: [PATCH 0406/1298] fix cmakelists for llvm --- CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 661bb41a3..aa968f088 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,9 +8,11 @@ set(CRPROPA_EXTRA_INCLUDES) set(CRPROPA_EXTRA_LIBRARIES) set(CRPROPA_SWIG_DEFINES) -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--as-needed") -set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--as-needed") -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") +if(CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--as-needed") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--as-needed") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") +endif(CMAKE_COMPILER_IS_GNUCXX) # ---------------------------------------------------------------------------- # Dependencies From 87f367c8664bd08104cca595fc2131ed81def1e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Wed, 30 Apr 2014 16:47:20 +0200 Subject: [PATCH 0407/1298] add source particle properties to PhotonOutput1D --- src/module/PhotonOutput1D.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/module/PhotonOutput1D.cpp b/src/module/PhotonOutput1D.cpp index 087186f14..4fc490c29 100644 --- a/src/module/PhotonOutput1D.cpp +++ b/src/module/PhotonOutput1D.cpp @@ -10,12 +10,14 @@ namespace crpropa { PhotonOutput1D::PhotonOutput1D(const string &filename) : filename(filename), output(filename.c_str()) { - output << "# iE\tiID\tE\tID\tR\tz\n"; + output << "# sE\tsID\tpE\tpID\tE\tR\tz\n"; output << "#\n"; - output << "# iE Energy [EeV] of parent particle\n"; - output << "# iID Id of parent particle\n"; + output << "# iE Energy [EeV] of source particle\n"; + output << "# iID Id of source particle\n"; + output << "# pE Energy [EeV] of parent particle\n"; + output << "# pID Id of parent particle\n"; output << "# E Energy [EeV]\n"; - output << "# R Distance [Mpc]\n"; + output << "# R Distance point of creation [Mpc]\n"; output << "# z Redshift\n"; output << "#\n"; } @@ -30,11 +32,13 @@ void PhotonOutput1D::process(Candidate *candidate) const { char buffer[1024]; size_t p = 0; + p += sprintf(buffer + p, "%8.4f\t", candidate->source.getEnergy() / EeV); + p += sprintf(buffer + p, "%10i\t", candidate->source.getId()); + p += sprintf(buffer + p, "%8.4f\t", candidate->created.getEnergy() / EeV); p += sprintf(buffer + p, "%10i\t", candidate->created.getId()); p += sprintf(buffer + p, "%8.4f\t", candidate->current.getEnergy() / EeV); - p += sprintf(buffer + p, "%10i\t", candidate->current.getId()); p += sprintf(buffer + p, "%8.4f\t", candidate->current.getPosition().getR() / Mpc); p += sprintf(buffer + p, "%8.4f\n", candidate->getRedshift()); From cc47d2ce0ca874386ae8e1f3efaf5c48a5e4c394 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 5 May 2014 12:47:09 +0200 Subject: [PATCH 0408/1298] add clip function to Common --- include/crpropa/Common.h | 6 ++++++ src/module/DeflectionCK.cpp | 33 ++++++++++++++++----------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/include/crpropa/Common.h b/include/crpropa/Common.h index d6ea7c48c..735ab2c04 100644 --- a/include/crpropa/Common.h +++ b/include/crpropa/Common.h @@ -14,6 +14,12 @@ inline int digit(const int& value, const int& d) { return (value % (d * 10)) / d; } +// Return value xclip which is the closest to x, so that lower <= xclip <= upper +template +T clip(const T& x, const T& lower, const T& upper) { + return std::max(lower, std::min(x, upper)); +} + // Perform linear interpolation on a set of n tabulated data points X[0 .. n-1] -> Y[0 .. n-1] // Returns Y[0] if x < X[0] and Y[n-1] if x > X[n-1] double interpolate(double x, const std::vector& X, diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index 14b7be4e2..dd575f9f4 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -49,9 +49,7 @@ void DeflectionCK::process(Candidate *candidate) const { // save the new previous particle state candidate->previous = candidate->current; - double step = candidate->getNextStep(); - step = std::max(step, minStep); - step = std::min(step, maxStep); + double step = clip(candidate->getNextStep(), minStep, maxStep); // rectlinear propagation for neutral particles if (candidate->current.getCharge() == 0) { @@ -67,17 +65,17 @@ void DeflectionCK::process(Candidate *candidate) const { candidate->current.getMomentum()); PhasePoint yOut, yErr, yScale; LorentzForce dydt(&candidate->current, field); - double h = step / c_light; - double hTry, r; + double t = step / c_light; + double tTry, r; // phase-point to compare with error for step size control - yScale = (yIn.abs() + dydt(0., yIn).abs() * h) * tolerance; + yScale = (yIn.abs() + dydt(0., yIn).abs() * t) * tolerance; - // try performing a steps until the relative error is less than the desired tolerance - // or the minimum step size has been reached + // try performing a steps until the relative error is less than the desired + // tolerance or the minimum step size has been reached do { - hTry = h; - erk.step(0, yIn, yOut, yErr, hTry, dydt); + tTry = t; + erk.step(0, yIn, yOut, yErr, tTry, dydt); // determine maximum of relative errors yErr(i) / yScale(i) r = 0; @@ -88,16 +86,17 @@ void DeflectionCK::process(Candidate *candidate) const { if (yScale.b.z > std::numeric_limits::min()) r = std::max(r, fabs(yErr.b.z / yScale.b.z)); - // change (next) step size to keep the relative error close to the tolerance - h *= 0.95 * pow(r, -0.2); - h = std::max(h, 0.1 * hTry); - h = std::min(h, 5 * hTry); - } while (r > 1 && h > minStep); + // new step size to keep the relative error close to the tolerance + t *= 0.95 * pow(r, -0.2); + // limit change of new step size + t = clip(t, 0.1 * tTry, 5 * tTry); + + } while (r > 1 && t > minStep); candidate->current.setPosition(yOut.a); candidate->current.setDirection(yOut.b.getUnitVector()); - candidate->setCurrentStep(hTry * c_light); - candidate->setNextStep(h * c_light); + candidate->setCurrentStep(tTry * c_light); + candidate->setNextStep(t * c_light); } void DeflectionCK::setField(ref_ptr f) { From 7f5f032fc44d9dccc8883db7bde05275c1a8e67d Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 6 May 2014 15:55:04 +0200 Subject: [PATCH 0409/1298] Use cosmology parameters from Planck as default --- src/Cosmology.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Cosmology.cpp b/src/Cosmology.cpp index 19b8edd4a..3adcda3ed 100644 --- a/src/Cosmology.cpp +++ b/src/Cosmology.cpp @@ -50,8 +50,8 @@ struct Cosmology { } Cosmology() { - H0 = 71 * 1000 * meter / second / Mpc; // default values - omegaM = 0.3; + H0 = 70.4 * 1000 * meter / second / Mpc; // default values + omegaM = 0.272; omegaL = 1 - omegaM; Z.resize(n); From dd2df63e43f592f22976c8396b62dc24b31e8cfe Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 6 May 2014 15:56:15 +0200 Subject: [PATCH 0410/1298] fix DeflectionCK.setMaximumStep --- src/module/DeflectionCK.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp index dd575f9f4..e35477d4e 100644 --- a/src/module/DeflectionCK.cpp +++ b/src/module/DeflectionCK.cpp @@ -116,10 +116,10 @@ void DeflectionCK::setMinimumStep(double min) { minStep = min; } -void DeflectionCK::setMaximumStep(double min) { - if (minStep > min) +void DeflectionCK::setMaximumStep(double max) { + if (max > minStep) throw std::runtime_error("DeflectionCK: minStep > maxStep"); - maxStep = min; + maxStep = max; } double DeflectionCK::getTolerance() const { From 88e8e3d691494bc9344827dfc9b3621349ec5b68 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 6 May 2014 21:45:49 +0200 Subject: [PATCH 0411/1298] Merge ExplicitRungeKutta, PhasePoint and DeflectionCK into PropagationCK --- CMakeLists.txt | 1 + include/crpropa/Vector3.h | 7 ++ include/crpropa/module/PropagationCK.h | 79 ++++++++++++ python/crpropa.i | 2 + src/module/PropagationCK.cpp | 164 +++++++++++++++++++++++++ 5 files changed, 253 insertions(+) create mode 100644 include/crpropa/module/PropagationCK.h create mode 100644 src/module/PropagationCK.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index aa968f088..1e1b3f47c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,6 +146,7 @@ add_library(crpropa SHARED src/module/Observer.cpp src/module/SimplePropagation.cpp src/module/DeflectionCK.cpp + src/module/PropagationCK.cpp src/module/ElectronPairProduction.cpp src/module/NuclearDecay.cpp src/module/PhotoPionProduction.cpp diff --git a/include/crpropa/Vector3.h b/include/crpropa/Vector3.h index 7b62fb57b..36fa02971 100644 --- a/include/crpropa/Vector3.h +++ b/include/crpropa/Vector3.h @@ -385,6 +385,13 @@ class Vector3 { z = v.z; return *this; } + + Vector3 &operator =(const T &f) { + x = f; + y = f; + z = f; + return *this; + } }; #ifndef SWIG diff --git a/include/crpropa/module/PropagationCK.h b/include/crpropa/module/PropagationCK.h new file mode 100644 index 000000000..30d2215b5 --- /dev/null +++ b/include/crpropa/module/PropagationCK.h @@ -0,0 +1,79 @@ +#ifndef CRPROPA_PROPAGATIONCK_H +#define CRPROPA_PROPAGATIONCK_H + +#include "crpropa/Module.h" +#include "crpropa/magneticField/MagneticField.h" + +namespace crpropa { + +/** + @class PropagationCK + @brief Propagation through magnetic fields using the Cash-Karp method. + + This module solves the equations of motion of a relativistic charged particle when propagating through a magnetic field.\n + It uses the Runge-Kutta integration method with Cash-Karp coefficients.\n + The step size control tries to keep the relative error close to, but smaller than the designated tolerance. + Additionally a minimum and maximum size for the steps can be set. + For neutral particles a rectilinear propagation is applied and a next step of the maximum step size proposed. + */ +class PropagationCK: public Module { +public: + class Y { + public: + Vector3d x, u; /*< phase-point: position and direction */ + + Y() { + } + + Y(const Vector3d &x, const Vector3d &u) : + x(x), u(u) { + } + + Y(double f) : + x(Vector3d(f, f, f)), u(Vector3d(f, f, f)) { + } + + Y operator *(double f) const { + return Y(x * f, u * f); + } + + Y &operator +=(const Y &y) { + x += y.x; + u += y.u; + return *this; + } + }; + +private: + std::vector a, b, bs; /*< Cash-Karp coefficients */ + ref_ptr field; + double tolerance; /*< target relative error of the numerical integration */ + double minStep; /*< minimum step size of the propagation */ + double maxStep; /*< maximum step size of the propagation */ + +public: + PropagationCK(ref_ptr field = NULL, double tolerance = 1e-4, + double minStep = 0.1 * kpc, double maxStep = 1 * Gpc); + void process(Candidate *candidate) const; + + // derivative of phase point, dY/dt = d/dt(x, u) = (v, du/dt) + // du/dt = q*c^2/E * (u x B) + Y dYdt(const Y &y, ParticleState &p) const; + + void tryStep(const Y &y, Y &out, Y &error, double t, + ParticleState &p) const; + + void setField(ref_ptr field); + void setTolerance(double tolerance); + void setMinimumStep(double minStep); + void setMaximumStep(double maxStep); + + double getTolerance() const; + double getMinimumStep() const; + double getMaximumStep() const; + std::string getDescription() const; +}; + +} // namespace crpropa + +#endif // CRPROPA_PROPAGATIONCK_H diff --git a/python/crpropa.i b/python/crpropa.i index a0c19f569..62cd1a28b 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -43,6 +43,7 @@ using std::ptrdiff_t; #include "crpropa/module/PhotonOutput1D.h" #include "crpropa/module/SimplePropagation.h" #include "crpropa/module/DeflectionCK.h" +#include "crpropa/module/PropagationCK.h" #include "crpropa/module/Tools.h" #include "crpropa/magneticField/MagneticField.h" @@ -154,6 +155,7 @@ using std::ptrdiff_t; %include "crpropa/module/Observer.h" %include "crpropa/module/SimplePropagation.h" %include "crpropa/module/DeflectionCK.h" +%include "crpropa/module/PropagationCK.h" %include "crpropa/module/OutputTXT.h" %include "crpropa/module/OutputShell.h" %include "crpropa/module/OutputROOT.h" diff --git a/src/module/PropagationCK.cpp b/src/module/PropagationCK.cpp new file mode 100644 index 000000000..74a764882 --- /dev/null +++ b/src/module/PropagationCK.cpp @@ -0,0 +1,164 @@ +#include "crpropa/module/PropagationCK.h" + +#include +#include +#include +#include + +namespace crpropa { + +// Cash-Karp coefficients +const double cash_karp_a[] = { 0., 0., 0., 0., 0., 0., 1. / 5., 0., 0., 0., 0., + 0., 3. / 40., 9. / 40., 0., 0., 0., 0., 3. / 10., -9. / 10., 6. / 5., + 0., 0., 0., -11. / 54., 5. / 2., -70. / 27., 35. / 27., 0., 0., 1631. + / 55296., 175. / 512., 575. / 13824., 44275. / 110592., 253. + / 4096., 0. }; + +const double cash_karp_b[] = { 37. / 378., 0, 250. / 621., 125. / 594., 0., 512. + / 1771. }; + +const double cash_karp_bs[] = { 2825. / 27648., 0., 18575. / 48384., 13525. + / 55296., 277. / 14336., 1. / 4. }; + +void PropagationCK::tryStep(const Y &y, Y &out, Y &error, double h, + ParticleState &particle) const { + std::vector k; + k.reserve(6); + + out = y; + error = Y(0); + + // calculate the sum of b_i * k_i + for (size_t i = 0; i < 6; i++) { + + Y y_n = y; + for (size_t j = 0; j < i; j++) + y_n += k[j] * a[i * 6 + j] * h; + + // update k_i + k[i] = dYdt(y_n, particle); + + out += k[i] * b[i] * h; + error += k[i] * (b[i] - bs[i]) * h; + } +} + +PropagationCK::Y PropagationCK::dYdt(const Y &y, ParticleState &p) const { + // normalize direction vector to prevent numerical losses + Vector3d velocity = y.u.getUnitVector() * c_light; + Vector3d B(0, 0, 0); + try { + B = field->getField(y.x); + } catch (std::exception &e) { + std::cerr << "PropagationCK: Exception in getField." << std::endl; + std::cerr << e.what() << std::endl; + } + // Lorentz force: du/dt = q*c/E * (v x B) + Vector3d dudt = p.getCharge() * c_light / p.getEnergy() * velocity.cross(B); + return Y(velocity, dudt); +} + +PropagationCK::PropagationCK(ref_ptr field, double tolerance, + double minStep, double maxStep) : + minStep(0) { + setField(field); + setTolerance(tolerance); + setMaximumStep(maxStep); + setMinimumStep(minStep); + + // load Cash-Karp coefficients + a.assign(cash_karp_a, cash_karp_a + 36); + b.assign(cash_karp_b, cash_karp_b + 6); + bs.assign(cash_karp_bs, cash_karp_bs + 6); +} + +void PropagationCK::process(Candidate *candidate) const { + // save the new previous particle state + ParticleState ¤t = candidate->current; + candidate->previous = current; + + double step = clip(candidate->getNextStep(), minStep, maxStep); + + // rectilinear propagation for neutral particles + if (current.getCharge() == 0) { + Vector3d pos = current.getPosition(); + Vector3d dir = current.getDirection(); + current.setPosition(pos + dir * step); + candidate->setCurrentStep(step); + candidate->setNextStep(maxStep); + return; + } + + Y yIn(current.getPosition(), current.getDirection()); + Y yOut, yErr; + double h = step / c_light; + double hTry, r; + + // try performing a steps until the relative error is less than the desired + // tolerance or the minimum step size has been reached + do { + hTry = h; + tryStep(yIn, yOut, yErr, hTry, current); + + // determine absolute direction error relative to tolerance + r = yErr.u.getR() / tolerance; + // new step size to keep the error close to the tolerance + h *= 0.95 * pow(r, -0.2); + // limit change of new step size + h = clip(h, 0.1 * hTry, 5 * hTry); + + } while (r > 1 && h > minStep); + + current.setPosition(yOut.x); + current.setDirection(yOut.u.getUnitVector()); + candidate->setCurrentStep(hTry * c_light); + candidate->setNextStep(h * c_light); +} + +void PropagationCK::setField(ref_ptr f) { + field = f; +} + +void PropagationCK::setTolerance(double tol) { + if ((tol > 1) or (tol < 0)) + throw std::runtime_error( + "PropagationCK: target error not in range 0-1"); + tolerance = tol; +} + +void PropagationCK::setMinimumStep(double min) { + if (min < 0) + throw std::runtime_error("PropagationCK: minStep < 0 "); + if (min > maxStep) + throw std::runtime_error("PropagationCK: minStep > maxStep"); + minStep = min; +} + +void PropagationCK::setMaximumStep(double max) { + if (max < minStep) + throw std::runtime_error("PropagationCK: maxStep < minStep"); + maxStep = max; +} + +double PropagationCK::getTolerance() const { + return tolerance; +} + +double PropagationCK::getMinimumStep() const { + return minStep; +} + +double PropagationCK::getMaximumStep() const { + return maxStep; +} + +std::string PropagationCK::getDescription() const { + std::stringstream s; + s << "Propagation in magnetic fields using the Cash-Karp method."; + s << " Target error: " << tolerance; + s << ", Minimum Step: " << minStep / kpc << " kpc"; + s << ", Maximum Step: " << maxStep / kpc << " kpc"; + return s.str(); +} + +} // namespace crpropa From 409b46ca9e1d69fabef9b7f714d335f23efa45af Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 6 May 2014 21:55:04 +0200 Subject: [PATCH 0412/1298] update tests to PropagationCK --- test/python/testPropagationCK.py | 107 +++++++++++++++++++++++++ test/python/testTurbulentDeflection.py | 2 +- test/testPropagation.cpp | 18 +++-- 3 files changed, 118 insertions(+), 9 deletions(-) create mode 100644 test/python/testPropagationCK.py diff --git a/test/python/testPropagationCK.py b/test/python/testPropagationCK.py new file mode 100644 index 000000000..4f41e869e --- /dev/null +++ b/test/python/testPropagationCK.py @@ -0,0 +1,107 @@ +# CRPropa test script +# Tests the accuracy of the Cash-Karp numerical integration method in CRPropa +# +from crpropa import * +from pylab import * + + +# 100 EeV proton +c = Candidate() +c.current.setId(nucleusId(1,1)) +c.current.setEnergy(100 * EeV) +c.current.setDirection(Vector3d(1, 0, 0)) + +# uniform perpendicular magnetic field of 10 nG +field = UniformMagneticField(Vector3d(0, 0, 10 * nG)) + +# resulting gyroradius +R = c.current.getMomentum().getR() / c.current.getCharge() / (10 * nG) + + +def propagate(tolerance): + prop = PropagationCK(field, tolerance, 0.1 * kpc) + maxLen = MaximumTrajectoryLength(2 * pi * R) + + c.setTrajectoryLength(0) + c.setCurrentStep(0) + c.setNextStep(1 * Mpc) # set a large initial step, so that an initial acceleration is uneccessary + c.current.setPosition(Vector3d(0, R, 0)) + c.current.setDirection(Vector3d(1, 0, 0)) + c.setActive(True) + + posX, posY, dirX, dirY, dirDeviation, theta = [], [], [], [], [], [] + nSteps = 0 + while c.isActive(): + prop.process(c) + maxLen.process(c) + nSteps +=1 + + posX.append(c.current.getPosition().x) + posY.append(c.current.getPosition().y) + + dirX.append(c.current.getDirection().x) + dirY.append(c.current.getDirection().y) + + t = c.getTrajectoryLength() / R + theta.append(t) + dirDeviation.append(c.current.getDirection().dot(Vector3d(cos(t), -sin(t), 0))) + + return array(posX), array(posY), array(dirX), array(dirY), array(dirDeviation), array(theta), nSteps + + + +### Plot trajectory in x-space with 1e-4 tolerance +figure() +posX, posY, dirX, dirY, dirDev, theta, n = propagate(1e-4) +plot(posX/R, posY/R, "o", label='Simulated') +plot(sin(linspace(0,2*pi)), cos(linspace(0,2*pi)),'k--',label='True') +legend() +xlim(-1.5,1.5) +ylim(-1.5,1.5) +xlabel(r'$x / R_L$') +ylabel(r'$y / R_L$') +grid() +text(0.05, 0.95, 'Tolerance 1e-4', ha='left', transform=gca().transAxes) +savefig('PropagationCK_xtrajectory', bbox_inches='tight') + +### Plot trajectory in p-space with 1e-4 tolerance +figure() +posX, posY, dirX, dirY, dirDev, theta, n = propagate(1e-4) +plot(dirX, dirY, "o", label='Simulated') +plot(sin(linspace(0,2*pi)), cos(linspace(0,2*pi)),'k--',label='True') +legend() +xlim(-1.5,1.5) +ylim(-1.5,1.5) +xlabel(r'$p_x / |p_x|$') +ylabel(r'$p_y / |p_y|$') +grid() +text(0.05, 0.95, 'Tolerance 1e-4', ha='left', transform=gca().transAxes) +savefig('PropagationCK_ptrajectory', bbox_inches='tight') + +### Directional error as function of distance for different tolerances +figure() +for tolerance in [1e-3, 1e-4, 1e-5, 1e-6]: + posX, posY, dirX, dirY, dirDev, theta, n = propagate(tolerance) + plot(theta/2/pi, arccos(dirDev)*180/pi, label='%.0e, %i'%(tolerance, n)) +legend(title='Tolerance, Steps', loc='upper left') +xlabel(r'Travelled Distance / $2 \pi R_L$') +ylabel(r'Direction Error [$^\circ$]') +grid() +semilogy() +savefig('PropagationCK_pdeviation.png',bbox_inches='tight') + +### Positional error as function of distance for different tolerances +figure() +for tolerance in [1e-3, 1e-4, 1e-5, 1e-6]: + posX, posY, dirX, dirY, dirDev, theta, n = propagate(tolerance) + displacement = ((posX/R - sin(theta))**2 + (posY/R - cos(theta))**2 )**.5 + plot(theta/2/pi, displacement, label='%.0e, %i'%(tolerance, n)) +legend(title='Tolerance, Steps', loc='upper left') +xlabel(r'Travelled Distance / $2 \pi R_L$') +ylabel(r'Position Error / $R_L$') +grid() +semilogy() +ylim(1e-8,1e-1) +savefig('PropagationCK_xdeviation.png',bbox_inches='tight') + +show() diff --git a/test/python/testTurbulentDeflection.py b/test/python/testTurbulentDeflection.py index db9a1ced5..34b0c4f43 100644 --- a/test/python/testTurbulentDeflection.py +++ b/test/python/testTurbulentDeflection.py @@ -18,7 +18,7 @@ vGrid = VectorGrid(Vector3d(0, 0, 0), 128, 0.05 * Mpc) initTurbulence(vGrid, Brms * nG, Lmin * Mpc, Lmax * Mpc) -propa = DeflectionCK(MagneticFieldGrid(vGrid)) +propa = PropagationCK(MagneticFieldGrid(vGrid)) age = linspace(1, 150, nS) distance, rms1, rms2 = zeros((3, nS)) diff --git a/test/testPropagation.cpp b/test/testPropagation.cpp index aaaef86e8..4bd54956b 100644 --- a/test/testPropagation.cpp +++ b/test/testPropagation.cpp @@ -1,6 +1,6 @@ #include "crpropa/Candidate.h" #include "crpropa/module/SimplePropagation.h" -#include "crpropa/module/DeflectionCK.h" +#include "crpropa/module/PropagationCK.h" #include "gtest/gtest.h" @@ -30,8 +30,8 @@ TEST(testSimplePropagation, step) { EXPECT_EQ(Vector3d(0, 1, 0), c.current.getDirection()); } -TEST(testDeflectionCK, proton) { - DeflectionCK propa(new UniformMagneticField(Vector3d(0, 0, 1 * nG))); +TEST(testPropagationCK, proton) { + PropagationCK propa(new UniformMagneticField(Vector3d(0, 0, 1 * nG))); ParticleState p; p.setId(nucleusId(1, 1)); @@ -47,8 +47,10 @@ TEST(testDeflectionCK, proton) { EXPECT_DOUBLE_EQ(0.5 * kpc, c.getNextStep()); } -TEST(testDeflectionCK, neutron) { - DeflectionCK propa(new UniformMagneticField(Vector3d(0, 0, 1 * nG))); +TEST(testPropagationCK, neutron) { + PropagationCK propa(new UniformMagneticField(Vector3d(0, 0, 1 * nG))); + propa.setMinimumStep(1 * kpc); + propa.setMaximumStep(42 * Mpc); ParticleState p; p.setId(nucleusId(1, 0)); @@ -59,9 +61,9 @@ TEST(testDeflectionCK, neutron) { propa.process(&c); - EXPECT_DOUBLE_EQ(0.1 * kpc, c.getCurrentStep()); - EXPECT_DOUBLE_EQ(4000 * Mpc, c.getNextStep()); - EXPECT_EQ(Vector3d(0, 0.1 * kpc, 0), c.current.getPosition()); + EXPECT_DOUBLE_EQ(1 * kpc, c.getCurrentStep()); + EXPECT_DOUBLE_EQ(42 * Mpc, c.getNextStep()); + EXPECT_EQ(Vector3d(0, 1 * kpc, 0), c.current.getPosition()); EXPECT_EQ(Vector3d(0, 1, 0), c.current.getDirection()); } From cbbf7e1c816886d4c6f42fcb60890b007e023d77 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 6 May 2014 22:23:51 +0200 Subject: [PATCH 0413/1298] Remove DeflectionCK, in python add typedef from DeflectionCK to PropagationCK --- CMakeLists.txt | 1 - include/crpropa/ExplicitRungeKutta.h | 110 ------------------- include/crpropa/PhasePoint.h | 54 ---------- include/crpropa/module/DeflectionCK.h | 46 -------- python/crpropa.i | 15 +-- src/XmlExecute.cpp | 4 +- src/module/DeflectionCK.cpp | 146 -------------------------- test/python/testDeflectionCK.py | 107 ------------------- 8 files changed, 6 insertions(+), 477 deletions(-) delete mode 100644 include/crpropa/ExplicitRungeKutta.h delete mode 100644 include/crpropa/PhasePoint.h delete mode 100644 include/crpropa/module/DeflectionCK.h delete mode 100644 src/module/DeflectionCK.cpp delete mode 100644 test/python/testDeflectionCK.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e1b3f47c..05af273c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -145,7 +145,6 @@ add_library(crpropa SHARED src/module/Boundary.cpp src/module/Observer.cpp src/module/SimplePropagation.cpp - src/module/DeflectionCK.cpp src/module/PropagationCK.cpp src/module/ElectronPairProduction.cpp src/module/NuclearDecay.cpp diff --git a/include/crpropa/ExplicitRungeKutta.h b/include/crpropa/ExplicitRungeKutta.h deleted file mode 100644 index 5b2aea8cb..000000000 --- a/include/crpropa/ExplicitRungeKutta.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef CRPROPA_EXPLICITRUNGEKUTTA_H -#define CRPROPA_EXPLICITRUNGEKUTTA_H - -#include - -namespace crpropa { - -template -class ExplicitRungeKutta { -public: - std::vector c, b, bs, a; - unsigned int s; - class F { - public: - virtual ~F() { - } - virtual Y operator()(double t, const Y &v) = 0; - }; - void step(double t, const Y &initial, Y &result, double stepsize, - F &f) const; - void step(double t, const Y &initial, Y &result, Y &error, double stepsize, - F &f) const; - void loadCashKarp(); -}; - -template -inline void ExplicitRungeKutta::step(double t, const Y &y, Y &result, - double stepsize, F &f) const { - std::vector k; - k.reserve(s); - - Y r = y; - - // calculate the sum of b_i * k_i - for (unsigned int i = 0; i < s; i++) { - // first parameter of f - double t_n = t + c[i] * stepsize; - - // second parameter of f - Y y_n = y; - for (unsigned int j = 0; j < i; j++) { - y_n += k[j] * a[i * s + j] * stepsize; - } - - // update k_i - k[i] = f(t_n, y_n); - - r += k[i] * b[i] * stepsize; - } - - result = r; -} - -template -inline void ExplicitRungeKutta::step(double t, const Y &y, Y &result, - Y &error, double stepsize, F &f) const { - std::vector k; - k.reserve(s); - - Y r = y; - error = 0; - - // calculate the sum of b_i * k_i - for (unsigned int i = 0; i < s; i++) { - // first parameter of f - double t_n = t + c[i] * stepsize; - - // second parameter of f - Y y_n = y; - for (unsigned int j = 0; j < i; j++) { - y_n += k[j] * a[i * s + j] * stepsize; - } - - // update k_i - k[i] = f(t_n, y_n); - - r += k[i] * b[i] * stepsize; - error += k[i] * (b[i] - bs[i]) * stepsize; - } - - result = r; -} - -// Cash-Karp coefficients -const double cash_karp_a[] = { 0., 0., 0., 0., 0., 0., 1. / 5., 0., 0., 0., 0., - 0., 3. / 40., 9. / 40., 0., 0., 0., 0., 3. / 10., -9. / 10., 6. / 5., - 0., 0., 0., -11. / 54., 5. / 2., -70. / 27., 35. / 27., 0., 0., 1631. - / 55296., 175. / 512., 575. / 13824., 44275. / 110592., 253. - / 4096., 0. }; - -const double cash_karp_b[] = { 37. / 378., 0, 250. / 621., 125. / 594., 0., 512. - / 1771. }; - -const double cash_karp_bs[] = { 2825. / 27648., 0., 18575. / 48384., 13525. - / 55296., 277. / 14336., 1. / 4. }; - -const double cash_karp_c[] = { 0., 1. / 5., 3. / 10., 3. / 5., 1., 7. / 8. }; - -template -inline void ExplicitRungeKutta::loadCashKarp() { - s = 6; - a.assign(cash_karp_a, cash_karp_a + 36); - b.assign(cash_karp_b, cash_karp_b + 6); - bs.assign(cash_karp_bs, cash_karp_bs + 6); - c.assign(cash_karp_c, cash_karp_c + 6); -} - -} // namespace crpropa - -#endif /* CRPROPA_EXPLICITRUNGEKUTTA_H */ diff --git a/include/crpropa/PhasePoint.h b/include/crpropa/PhasePoint.h deleted file mode 100644 index 5eef1467e..000000000 --- a/include/crpropa/PhasePoint.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef PHASEPOINT_H -#define PHASEPOINT_H - -#include "crpropa/Vector3.h" - -namespace crpropa { - -/** - @class PhasePoint - @brief 6D point in (position - momentum) phase space - */ -class PhasePoint { -public: - Vector3d a, b; - - PhasePoint() { - } - - PhasePoint(const Vector3d &a, const Vector3d &b) : - a(a), b(b) { - } - - PhasePoint(double f) : - a(Vector3d(f, f, f)), b(Vector3d(f, f, f)) { - } - - PhasePoint operator *(double f) const { - return PhasePoint(a * f, b * f); - } - - PhasePoint &operator =(double f) { - a = Vector3d(f, f, f); - b = Vector3d(f, f, f); - return *this; - } - - PhasePoint &operator +=(const PhasePoint &p) { - a += p.a; - b += p.b; - return *this; - } - - PhasePoint operator +(const PhasePoint &p) const { - return PhasePoint(a + p.a, b + p.b); - } - - PhasePoint abs() const { - return PhasePoint(a.abs(), b.abs()); - } -}; - -} // namespace crpropa - -#endif /* PHASEPOINT_H */ diff --git a/include/crpropa/module/DeflectionCK.h b/include/crpropa/module/DeflectionCK.h deleted file mode 100644 index 705db99fa..000000000 --- a/include/crpropa/module/DeflectionCK.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef CRPROPA_DEFLECTION_H -#define CRPROPA_DEFLECTION_H - -#include "crpropa/Module.h" -#include "crpropa/magneticField/MagneticField.h" -#include "crpropa/ExplicitRungeKutta.h" -#include "crpropa/PhasePoint.h" - -namespace crpropa { - -/** - @class DeflectionCK - @brief Propagation through magnetic fields using the Cash-Karp integrator. - - This module solves the equations of motion of a relativistic charged particle when propagating through a magnetic field.\n - It uses the Runge-Kutta integration method with Cash-Karp coefficients.\n - The step size control tries to keep the relative error close to, but smaller than the designated tolerance. - Additionally a minimum and maximum size for the steps can be set. - For neutral particles a rectalinear propagation is applied and a next step of the maximum step size proposed. - */ -class DeflectionCK: public Module { -private: - ref_ptr field; - ExplicitRungeKutta erk; - double tolerance; /*< target relative error of the numerical integration */ - double minStep; /*< minimum step size of the propagation */ - double maxStep; /*< maximum step size of the propagation */ - -public: - DeflectionCK(ref_ptr field = NULL, double tolerance = 1e-4, - double minStep = 0.1 * kpc, double maxStep = 4000 * Mpc); - void process(Candidate *candidate) const; - void setField(ref_ptr field); - void setTolerance(double tolerance); - void setMinimumStep(double minStep); - void setMaximumStep(double maxStep); - double getTolerance() const; - double getMinimumStep() const; - double getMaximumStep() const; - std::string getDescription() const; -}; - -} // namespace crpropa - -#endif // CRPROPA_DEFLECTION_H - diff --git a/python/crpropa.i b/python/crpropa.i index 62cd1a28b..dcb3fa195 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -42,7 +42,6 @@ using std::ptrdiff_t; #include "crpropa/module/PhotonEleCa.h" #include "crpropa/module/PhotonOutput1D.h" #include "crpropa/module/SimplePropagation.h" -#include "crpropa/module/DeflectionCK.h" #include "crpropa/module/PropagationCK.h" #include "crpropa/module/Tools.h" @@ -59,8 +58,6 @@ using std::ptrdiff_t; #include "crpropa/ParticleMass.h" #include "crpropa/Module.h" #include "crpropa/ModuleList.h" -#include "crpropa/PhasePoint.h" -#include "crpropa/ExplicitRungeKutta.h" #include "crpropa/Random.h" #include "crpropa/Units.h" #include "crpropa/Vector3.h" @@ -147,14 +144,10 @@ using std::ptrdiff_t; %include "crpropa/magneticField/AMRMagneticField.h" %include "crpropa/magneticField/JF12Field.h" -%include "crpropa/ExplicitRungeKutta.h" -%include "crpropa/PhasePoint.h" - %include "crpropa/module/BreakCondition.h" %include "crpropa/module/Boundary.h" %include "crpropa/module/Observer.h" %include "crpropa/module/SimplePropagation.h" -%include "crpropa/module/DeflectionCK.h" %include "crpropa/module/PropagationCK.h" %include "crpropa/module/OutputTXT.h" %include "crpropa/module/OutputShell.h" @@ -176,18 +169,18 @@ using std::ptrdiff_t; %template(SourcePropertyRefPtr) crpropa::ref_ptr; %feature("director") crpropa::SourceProperty; %include "crpropa/Source.h" - - %template(ModuleListRefPtr) crpropa::ref_ptr; %include "crpropa/ModuleList.h" -// nice python print %pythoncode %{ +# nice python print Module.__str__ = Module.getDescription def Vector3__str__(self): return "(%.4e, %.4e, %.4e)" % (self.x, self.y, self.z) - Vector3d.__str__ = Vector3__str__ Vector3f.__str__ = Vector3__str__ + +# expose PropagationCK under its former name Deflection +DeflectionCK = PropagationCK %} diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 9ed2b2979..f57351220 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -5,7 +5,7 @@ #include "crpropa/PhotonBackground.h" #include "crpropa/Cosmology.h" #include "crpropa/module/SimplePropagation.h" -#include "crpropa/module/DeflectionCK.h" +#include "crpropa/module/PropagationCK.h" #include "crpropa/module/Redshift.h" #include "crpropa/module/ElectronPairProduction.h" #include "crpropa/module/PhotoPionProduction.h" @@ -336,7 +336,7 @@ void XmlExecute::loadDeflectionCK(xml_node &node) { throw runtime_error( " --> Maximum step must be larger than minimum step"); - modules.add(new DeflectionCK(magnetic_field, epsilon, minStep, maxStep)); + modules.add(new PropagationCK(magnetic_field, epsilon, minStep, maxStep)); } void XmlExecute::loadUniformMagneticField(xml_node &node) { diff --git a/src/module/DeflectionCK.cpp b/src/module/DeflectionCK.cpp deleted file mode 100644 index e35477d4e..000000000 --- a/src/module/DeflectionCK.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include "crpropa/module/DeflectionCK.h" - -#include -#include -#include - -namespace crpropa { - -/** - * @class LorentzForce - * @brief Time-derivative of the phase-point (position, momentum) of a highly relativistic particle in magnetic field. - */ -class LorentzForce: public ExplicitRungeKutta::F { -public: - ParticleState *particle; - MagneticField *field; - - LorentzForce(ParticleState *particle, MagneticField *field) { - this->particle = particle; - this->field = field; - } - - PhasePoint operator()(double t, const PhasePoint &v) { - Vector3d velocity = v.b.getUnitVector() * c_light; - Vector3d B(0, 0, 0); - try { - B = field->getField(v.a); - } catch (std::exception &e) { - std::cerr << "LorentzForce: Exception in getField." << std::endl; - std::cerr << e.what() << std::endl; - } - Vector3d force = (double) particle->getCharge() * velocity.cross(B); - return PhasePoint(velocity, force); - } -}; - -DeflectionCK::DeflectionCK(ref_ptr field, double tolerance, - double minStep, double maxStep) : - field(field), tolerance(tolerance), minStep(minStep), maxStep(maxStep) { - if ((tolerance > 1) or (tolerance < 0)) - throw std::runtime_error( - "DeflectionCK: target relative error not in range 0-1"); - if (minStep > maxStep) - throw std::runtime_error("DeflectionCK: minStep > maxStep"); - erk.loadCashKarp(); -} - -void DeflectionCK::process(Candidate *candidate) const { - // save the new previous particle state - candidate->previous = candidate->current; - - double step = clip(candidate->getNextStep(), minStep, maxStep); - - // rectlinear propagation for neutral particles - if (candidate->current.getCharge() == 0) { - Vector3d pos = candidate->current.getPosition(); - Vector3d dir = candidate->current.getDirection(); - candidate->current.setPosition(pos + dir * step); - candidate->setCurrentStep(step); - candidate->setNextStep(maxStep); - return; - } - - PhasePoint yIn(candidate->current.getPosition(), - candidate->current.getMomentum()); - PhasePoint yOut, yErr, yScale; - LorentzForce dydt(&candidate->current, field); - double t = step / c_light; - double tTry, r; - - // phase-point to compare with error for step size control - yScale = (yIn.abs() + dydt(0., yIn).abs() * t) * tolerance; - - // try performing a steps until the relative error is less than the desired - // tolerance or the minimum step size has been reached - do { - tTry = t; - erk.step(0, yIn, yOut, yErr, tTry, dydt); - - // determine maximum of relative errors yErr(i) / yScale(i) - r = 0; - if (yScale.b.x > std::numeric_limits::min()) - r = std::max(r, fabs(yErr.b.x / yScale.b.x)); - if (yScale.b.y > std::numeric_limits::min()) - r = std::max(r, fabs(yErr.b.y / yScale.b.y)); - if (yScale.b.z > std::numeric_limits::min()) - r = std::max(r, fabs(yErr.b.z / yScale.b.z)); - - // new step size to keep the relative error close to the tolerance - t *= 0.95 * pow(r, -0.2); - // limit change of new step size - t = clip(t, 0.1 * tTry, 5 * tTry); - - } while (r > 1 && t > minStep); - - candidate->current.setPosition(yOut.a); - candidate->current.setDirection(yOut.b.getUnitVector()); - candidate->setCurrentStep(tTry * c_light); - candidate->setNextStep(t * c_light); -} - -void DeflectionCK::setField(ref_ptr f) { - field = f; -} - -void DeflectionCK::setTolerance(double tol) { - if ((tol > 1) or (tol < 0)) - throw std::runtime_error( - "DeflectionCK: target relative error not in range 0-1"); - tolerance = tol; -} - -void DeflectionCK::setMinimumStep(double min) { - if (min > maxStep) - throw std::runtime_error("DeflectionCK: minStep > maxStep"); - minStep = min; -} - -void DeflectionCK::setMaximumStep(double max) { - if (max > minStep) - throw std::runtime_error("DeflectionCK: minStep > maxStep"); - maxStep = max; -} - -double DeflectionCK::getTolerance() const { - return tolerance; -} - -double DeflectionCK::getMinimumStep() const { - return minStep; -} - -double DeflectionCK::getMaximumStep() const { - return maxStep; -} - -std::string DeflectionCK::getDescription() const { - std::stringstream s; - s << "Propagation in magnetic fields using the Cash-Karp method."; - s << " Target error: " << tolerance; - s << ", Minimum Step: " << minStep / kpc << " kpc"; - s << ", Maximum Step: " << maxStep / kpc << " kpc"; - return s.str(); -} - -} // namespace crpropa diff --git a/test/python/testDeflectionCK.py b/test/python/testDeflectionCK.py deleted file mode 100644 index 0a69b44c4..000000000 --- a/test/python/testDeflectionCK.py +++ /dev/null @@ -1,107 +0,0 @@ -# CRPropa test script -# Tests the accuracy of the Cash-Karp numerical integration method in CRPropa -# -from crpropa import * -from pylab import * - - -# 100 EeV proton -c = Candidate() -c.current.setId(nucleusId(1,1)) -c.current.setEnergy(100 * EeV) -c.current.setDirection(Vector3d(1, 0, 0)) - -# uniform perpendicular magnetic field of 10 nG -field = UniformMagneticField(Vector3d(0, 0, 10 * nG)) - -# resulting gyroradius -R = c.current.getMomentum().getR() / c.current.getCharge() / (10 * nG) - - -def propagate(tolerance): - prop = DeflectionCK(field, tolerance, 0.1 * kpc) - maxLen = MaximumTrajectoryLength(2 * pi * R) - - c.setTrajectoryLength(0) - c.setCurrentStep(0) - c.setNextStep(1 * Mpc) # set a large initial step, so that an initial acceleration is uneccessary - c.current.setPosition(Vector3d(0, R, 0)) - c.current.setDirection(Vector3d(1, 0, 0)) - c.setActive(True) - - posX, posY, dirX, dirY, dirDeviation, theta = [], [], [], [], [], [] - nSteps = 0 - while c.isActive(): - prop.process(c) - maxLen.process(c) - nSteps +=1 - - posX.append(c.current.getPosition().x) - posY.append(c.current.getPosition().y) - - dirX.append(c.current.getDirection().x) - dirY.append(c.current.getDirection().y) - - t = c.getTrajectoryLength() / R - theta.append(t) - dirDeviation.append(c.current.getDirection().dot(Vector3d(cos(t), -sin(t), 0))) - - return array(posX), array(posY), array(dirX), array(dirY), array(dirDeviation), array(theta), nSteps - - - -### Plot trajectory in x-space with 1e-4 tolerance -figure() -posX, posY, dirX, dirY, dirDev, theta, n = propagate(1e-4) -plot(posX/R, posY/R, "o", label='Simulated') -plot(sin(linspace(0,2*pi)), cos(linspace(0,2*pi)),'k--',label='True') -legend() -xlim(-1.5,1.5) -ylim(-1.5,1.5) -xlabel(r'$x / R_L$') -ylabel(r'$y / R_L$') -grid() -text(0.05, 0.95, 'Tolerance 1e-4', ha='left', transform=gca().transAxes) -savefig('DeflectionCK_xtrajectory', bbox_inches='tight') - -### Plot trajectory in p-space with 1e-4 tolerance -figure() -posX, posY, dirX, dirY, dirDev, theta, n = propagate(1e-4) -plot(dirX, dirY, "o", label='Simulated') -plot(sin(linspace(0,2*pi)), cos(linspace(0,2*pi)),'k--',label='True') -legend() -xlim(-1.5,1.5) -ylim(-1.5,1.5) -xlabel(r'$p_x / |p_x|$') -ylabel(r'$p_y / |p_y|$') -grid() -text(0.05, 0.95, 'Tolerance 1e-4', ha='left', transform=gca().transAxes) -savefig('DeflectionCK_ptrajectory', bbox_inches='tight') - -### Directional error as function of distance for different tolerances -figure() -for tolerance in [1e-3, 1e-4, 1e-5, 1e-6]: - posX, posY, dirX, dirY, dirDev, theta, n = propagate(tolerance) - plot(theta/2/pi, arccos(dirDev)*180/pi, label='%.0e, %i'%(tolerance, n)) -legend(title='Tolerance, Steps', loc='upper left') -xlabel(r'Travelled Distance / $2 \pi R_L$') -ylabel(r'Direction Error [$^\circ$]') -grid() -semilogy() -savefig('DeflectionCK_pdeviation.png',bbox_inches='tight') - -### Positional error as function of distance for different tolerances -figure() -for tolerance in [1e-3, 1e-4, 1e-5, 1e-6]: - posX, posY, dirX, dirY, dirDev, theta, n = propagate(tolerance) - displacement = ((posX/R - sin(theta))**2 + (posY/R - cos(theta))**2 )**.5 - plot(theta/2/pi, displacement, label='%.0e, %i'%(tolerance, n)) -legend(title='Tolerance, Steps', loc='upper left') -xlabel(r'Travelled Distance / $2 \pi R_L$') -ylabel(r'Position Error / $R_L$') -grid() -semilogy() -ylim(1e-8,1e-1) -savefig('DeflectionCK_xdeviation.png',bbox_inches='tight') - -show() From b498b88fc4747bdada3b4df4215e23cc4427d351 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 8 May 2014 15:27:35 +0200 Subject: [PATCH 0414/1298] PhotonOutput1D: output electrons and positrons as well --- src/module/PhotonOutput1D.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/module/PhotonOutput1D.cpp b/src/module/PhotonOutput1D.cpp index 4fc490c29..b3228aa6f 100644 --- a/src/module/PhotonOutput1D.cpp +++ b/src/module/PhotonOutput1D.cpp @@ -10,15 +10,15 @@ namespace crpropa { PhotonOutput1D::PhotonOutput1D(const string &filename) : filename(filename), output(filename.c_str()) { - output << "# sE\tsID\tpE\tpID\tE\tR\tz\n"; + output << "#ID\tE\tz\tiE\tiID\tpE\tpID\n"; output << "#\n"; + output << "# ID Id of particle (photon, electron, positron)\n"; + output << "# E Energy [EeV]\n"; + output << "# z Redshift\n"; output << "# iE Energy [EeV] of source particle\n"; output << "# iID Id of source particle\n"; output << "# pE Energy [EeV] of parent particle\n"; output << "# pID Id of parent particle\n"; - output << "# E Energy [EeV]\n"; - output << "# R Distance point of creation [Mpc]\n"; - output << "# z Redshift\n"; output << "#\n"; } @@ -26,23 +26,23 @@ PhotonOutput1D::~PhotonOutput1D() { } void PhotonOutput1D::process(Candidate *candidate) const { - if (candidate->current.getId() != 22) + int pid = candidate->current.getId(); + if ((pid != 22) and (abs(pid) != 11)) return; char buffer[1024]; size_t p = 0; + p += sprintf(buffer + p, "%4i\t", pid); + p += sprintf(buffer + p, "%8.4f\t", candidate->current.getEnergy() / EeV); + p += sprintf(buffer + p, "%8.4f\n", candidate->getRedshift()); + p += sprintf(buffer + p, "%8.4f\t", candidate->source.getEnergy() / EeV); p += sprintf(buffer + p, "%10i\t", candidate->source.getId()); p += sprintf(buffer + p, "%8.4f\t", candidate->created.getEnergy() / EeV); p += sprintf(buffer + p, "%10i\t", candidate->created.getId()); - p += sprintf(buffer + p, "%8.4f\t", candidate->current.getEnergy() / EeV); - p += sprintf(buffer + p, "%8.4f\t", - candidate->current.getPosition().getR() / Mpc); - p += sprintf(buffer + p, "%8.4f\n", candidate->getRedshift()); - #pragma omp critical { output.write(buffer, p); From 7ea5ca51a466f7e93b64acc0f5621ec561259b9a Mon Sep 17 00:00:00 2001 From: kuempel Date: Thu, 8 May 2014 15:53:04 +0200 Subject: [PATCH 0415/1298] Changed order of photon output + small bug fix in output --- src/module/PhotonOutput1D.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/module/PhotonOutput1D.cpp b/src/module/PhotonOutput1D.cpp index b3228aa6f..3f1348016 100644 --- a/src/module/PhotonOutput1D.cpp +++ b/src/module/PhotonOutput1D.cpp @@ -10,15 +10,15 @@ namespace crpropa { PhotonOutput1D::PhotonOutput1D(const string &filename) : filename(filename), output(filename.c_str()) { - output << "#ID\tE\tz\tiE\tiID\tpE\tpID\n"; + output << "#ID\tE\tz\tpE\tpID\tiE\tiID\n"; output << "#\n"; output << "# ID Id of particle (photon, electron, positron)\n"; output << "# E Energy [EeV]\n"; output << "# z Redshift\n"; - output << "# iE Energy [EeV] of source particle\n"; - output << "# iID Id of source particle\n"; output << "# pE Energy [EeV] of parent particle\n"; output << "# pID Id of parent particle\n"; + output << "# iE Energy [EeV] of source particle\n"; + output << "# iID Id of source particle\n"; output << "#\n"; } @@ -35,14 +35,15 @@ void PhotonOutput1D::process(Candidate *candidate) const { p += sprintf(buffer + p, "%4i\t", pid); p += sprintf(buffer + p, "%8.4f\t", candidate->current.getEnergy() / EeV); - p += sprintf(buffer + p, "%8.4f\n", candidate->getRedshift()); - - p += sprintf(buffer + p, "%8.4f\t", candidate->source.getEnergy() / EeV); - p += sprintf(buffer + p, "%10i\t", candidate->source.getId()); + p += sprintf(buffer + p, "%8.4f\t", candidate->getRedshift()); p += sprintf(buffer + p, "%8.4f\t", candidate->created.getEnergy() / EeV); p += sprintf(buffer + p, "%10i\t", candidate->created.getId()); + p += sprintf(buffer + p, "%8.4f\t", candidate->source.getEnergy() / EeV); + p += sprintf(buffer + p, "%10i\n", candidate->source.getId()); + + #pragma omp critical { output.write(buffer, p); From 9ff8c5fc87e004f8bde6ce9cd255365ba398d4fc Mon Sep 17 00:00:00 2001 From: kuempel Date: Thu, 15 May 2014 15:14:30 +0200 Subject: [PATCH 0416/1298] minor change in photon text output + photon ROOT output 1D --- include/crpropa/module/OutputROOT.h | 17 ++++++++++++ src/module/OutputROOT.cpp | 41 +++++++++++++++++++++++++++++ src/module/PhotonOutput1D.cpp | 12 ++++----- 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/include/crpropa/module/OutputROOT.h b/include/crpropa/module/OutputROOT.h index af4b2a87e..ade5581fe 100644 --- a/include/crpropa/module/OutputROOT.h +++ b/include/crpropa/module/OutputROOT.h @@ -39,6 +39,23 @@ class ROOTEventOutput1D: public Module { }; + +/** + @class ROOTPhotonOutput1D + @brief Records EM-particles that are inactive and have the property 'Detected' to a ROOT file. + */ +class ROOTPhotonOutput1D: public Module { + mutable TFile *ROOTFile; + mutable TNtuple *Ntuple; + +public: + ROOTPhotonOutput1D(std::string filename); + ~ROOTPhotonOutput1D(); + void process(Candidate *candidate) const; +}; + + + /** @class CRPropa2ROOTTrajectoryOutput1D @brief Saves trajectories to root file. diff --git a/src/module/OutputROOT.cpp b/src/module/OutputROOT.cpp index 8de322072..2d9256d88 100644 --- a/src/module/OutputROOT.cpp +++ b/src/module/OutputROOT.cpp @@ -199,6 +199,47 @@ void ROOTEventOutput1D::process(Candidate *c) const { } //////////////////////////////////////////////////////////////////////////////// + +/////////////////////// ROOT PHOTON OUTPUT 1D ////////////////////////////////// +ROOTPhotonOutput1D::ROOTPhotonOutput1D(std::string filename) { + setDescription("ROOTPHOTONOutput1D, filename: " + filename); + TThread::Lock(); + ROOTFile = new TFile(filename.c_str(), "RECREATE", + "CRPropa output data file"); + Ntuple = new TNtuple("photons", "CRPropa 1D photons", + "Particle_Type:Energy_EeV:Redshift:Parent_Type:Parent_Energy_EeV:Initial_Type:Initial_Energy_EeV"); + TThread::UnLock(); +} + + +ROOTPhotonOutput1D::~ROOTPhotonOutput1D() { + TThread::Lock(); + ROOTFile->Write(); + ROOTFile->Close(); + TThread::UnLock(); +} + +void ROOTPhotonOutput1D::process(Candidate *c) const { + int pid = c->current.getId(); + if ((pid != 22) and (abs(pid) != 11)) + return; + + TThread::Lock(); +#pragma omp critical + { + Ntuple->Fill(pid, + c->current.getEnergy() / EeV, + c->getRedshift(), + c->created.getId(), + c->created.getEnergy(), + c->source.getId(), + c->source.getEnergy()); + } + TThread::UnLock(); +} +//////////////////////////////////////////////////////////////////////////////// + + /////////////////////// ROOT TRAJECTORY OUTPUT 1D ////////////////////////////// ROOTTrajectoryOutput1D::ROOTTrajectoryOutput1D(std::string filename) { setDescription("ROOTTrajectoryOutput1D, filename: " + filename); diff --git a/src/module/PhotonOutput1D.cpp b/src/module/PhotonOutput1D.cpp index 3f1348016..fa5b869ca 100644 --- a/src/module/PhotonOutput1D.cpp +++ b/src/module/PhotonOutput1D.cpp @@ -10,15 +10,15 @@ namespace crpropa { PhotonOutput1D::PhotonOutput1D(const string &filename) : filename(filename), output(filename.c_str()) { - output << "#ID\tE\tz\tpE\tpID\tiE\tiID\n"; + output << "#ID\tE\tz\tpID\tpE\tiID\tiE\n"; output << "#\n"; output << "# ID Id of particle (photon, electron, positron)\n"; output << "# E Energy [EeV]\n"; output << "# z Redshift\n"; - output << "# pE Energy [EeV] of parent particle\n"; output << "# pID Id of parent particle\n"; - output << "# iE Energy [EeV] of source particle\n"; + output << "# pE Energy [EeV] of parent particle\n"; output << "# iID Id of source particle\n"; + output << "# iE Energy [EeV] of source particle\n"; output << "#\n"; } @@ -37,11 +37,11 @@ void PhotonOutput1D::process(Candidate *candidate) const { p += sprintf(buffer + p, "%8.4f\t", candidate->current.getEnergy() / EeV); p += sprintf(buffer + p, "%8.4f\t", candidate->getRedshift()); - p += sprintf(buffer + p, "%8.4f\t", candidate->created.getEnergy() / EeV); p += sprintf(buffer + p, "%10i\t", candidate->created.getId()); + p += sprintf(buffer + p, "%8.4f\t", candidate->created.getEnergy() / EeV); - p += sprintf(buffer + p, "%8.4f\t", candidate->source.getEnergy() / EeV); - p += sprintf(buffer + p, "%10i\n", candidate->source.getId()); + p += sprintf(buffer + p, "%10i\t", candidate->source.getId()); + p += sprintf(buffer + p, "%8.4f\n", candidate->source.getEnergy() / EeV); #pragma omp critical From dde91302bb2cc110ddfd603e7763bfe17c5e38d0 Mon Sep 17 00:00:00 2001 From: kuempel Date: Fri, 16 May 2014 11:11:59 +0200 Subject: [PATCH 0417/1298] changed redshift to comoving distance in photon output --- src/module/OutputROOT.cpp | 4 ++-- src/module/PhotonOutput1D.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/module/OutputROOT.cpp b/src/module/OutputROOT.cpp index 2d9256d88..aa988f48c 100644 --- a/src/module/OutputROOT.cpp +++ b/src/module/OutputROOT.cpp @@ -207,7 +207,7 @@ ROOTPhotonOutput1D::ROOTPhotonOutput1D(std::string filename) { ROOTFile = new TFile(filename.c_str(), "RECREATE", "CRPropa output data file"); Ntuple = new TNtuple("photons", "CRPropa 1D photons", - "Particle_Type:Energy_EeV:Redshift:Parent_Type:Parent_Energy_EeV:Initial_Type:Initial_Energy_EeV"); + "Particle_Type:Energy_EeV:ComovingDistance_Mpc:Parent_Type:Parent_Energy_EeV:Initial_Type:Initial_Energy_EeV"); TThread::UnLock(); } @@ -229,7 +229,7 @@ void ROOTPhotonOutput1D::process(Candidate *c) const { { Ntuple->Fill(pid, c->current.getEnergy() / EeV, - c->getRedshift(), + c->created.getPosition().getR() / Mpc, c->created.getId(), c->created.getEnergy(), c->source.getId(), diff --git a/src/module/PhotonOutput1D.cpp b/src/module/PhotonOutput1D.cpp index fa5b869ca..a433e2031 100644 --- a/src/module/PhotonOutput1D.cpp +++ b/src/module/PhotonOutput1D.cpp @@ -10,11 +10,11 @@ namespace crpropa { PhotonOutput1D::PhotonOutput1D(const string &filename) : filename(filename), output(filename.c_str()) { - output << "#ID\tE\tz\tpID\tpE\tiID\tiE\n"; + output << "#ID\tE\tD\tpID\tpE\tiID\tiE\n"; output << "#\n"; output << "# ID Id of particle (photon, electron, positron)\n"; output << "# E Energy [EeV]\n"; - output << "# z Redshift\n"; + output << "# D Comoving trajectory length [Mpc]\n"; output << "# pID Id of parent particle\n"; output << "# pE Energy [EeV] of parent particle\n"; output << "# iID Id of source particle\n"; @@ -35,7 +35,7 @@ void PhotonOutput1D::process(Candidate *candidate) const { p += sprintf(buffer + p, "%4i\t", pid); p += sprintf(buffer + p, "%8.4f\t", candidate->current.getEnergy() / EeV); - p += sprintf(buffer + p, "%8.4f\t", candidate->getRedshift()); + p += sprintf(buffer + p, "%8.4f\t", candidate->created.getPosition().getR() / Mpc); p += sprintf(buffer + p, "%10i\t", candidate->created.getId()); p += sprintf(buffer + p, "%8.4f\t", candidate->created.getEnergy() / EeV); From 77f8a72840845b1f4a028705e6f7deb7ac368663 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 19 May 2014 18:50:44 +0200 Subject: [PATCH 0418/1298] Improve documentation of Candidate addSecondary now sets the secandaries previous state to the previous state of its parent to allow for usage in the same progagation step. --- include/crpropa/Candidate.h | 35 ++++++++++++++++++++++++++++++++--- src/Candidate.cpp | 1 + 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/include/crpropa/Candidate.h b/include/crpropa/Candidate.h index ba81ac0b7..8c3a1b658 100644 --- a/include/crpropa/Candidate.h +++ b/include/crpropa/Candidate.h @@ -39,7 +39,11 @@ class Candidate: public Referenced { public: Candidate(); - Candidate(const ParticleState &state); /**< Creates a candidate, initializing the initial, previous and current particle state with the argument. */ + /** + Creates a candidate, initializing the Candidate::source, Candidate::created, + Candidate::previous and Candidate::current state with the argument. + */ + Candidate(const ParticleState &state); bool isActive() const; void setActive(bool b); @@ -50,11 +54,23 @@ class Candidate: public Referenced { void setRedshift(double z); double getRedshift() const; - void setCurrentStep(double step); /**< Sets the current step and increases the trajectory length accordingly. Only the propagation module should use this. */ + /** + Sets the current step and increases the trajectory length accordingly. + Only the propagation module should use this. + */ + void setCurrentStep(double step); double getCurrentStep() const; - void setNextStep(double step); /**< Sets the proposed next step. Only the propagation module should use this. */ + /** + Sets the proposed next step. + Only the propagation module should use this. + */ + void setNextStep(double step); double getNextStep() const; + + /** + Make a bid for the next step size: the lowest wins. + */ void limitNextStep(double step); void setProperty(const std::string &name, const std::string &value); @@ -62,6 +78,19 @@ class Candidate: public Referenced { bool removeProperty(const std::string &name); bool hasProperty(const std::string &name) const; + /** + Add a new candidate to the list of secondaries. + @param id particle ID of the secondary + @param energy energy of the secondary + + Adds a new candidate to the list of secondaries of this candidate. + The secondaries Candidate::source and Candidate::previous state are set to + the _source_ and _previous_ state of its parent. + The secondaries Candidate::created and Candidate::current state are set to + the _current_ state its parent, except for the secondaries current energy + and particle id. + Trajectory length and redshift are copied from the parent. + */ void addSecondary(int id, double energy); void clearSecondaries(); }; diff --git a/src/Candidate.cpp b/src/Candidate.cpp index 436473558..90bbd7f71 100644 --- a/src/Candidate.cpp +++ b/src/Candidate.cpp @@ -90,6 +90,7 @@ void Candidate::addSecondary(int id, double energy) { secondary->setRedshift(redshift); secondary->setTrajectoryLength(trajectoryLength); secondary->source = source; + secondary->previous = previous; secondary->created = current; secondary->current = current; secondary->current.setId(id); From ba8c19371b2c538bafa816397e04f1168cf91a25 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 20 May 2014 00:12:27 +0200 Subject: [PATCH 0419/1298] add production of secondaries to electron pair production requires updating CRPropa3/data --- .../crpropa/module/ElectronPairProduction.h | 19 +++- src/module/ElectronPairProduction.cpp | 93 +++++++++++++++++-- 2 files changed, 99 insertions(+), 13 deletions(-) diff --git a/include/crpropa/module/ElectronPairProduction.h b/include/crpropa/module/ElectronPairProduction.h index 0143c3a02..6b91f152a 100644 --- a/include/crpropa/module/ElectronPairProduction.h +++ b/include/crpropa/module/ElectronPairProduction.h @@ -17,14 +17,24 @@ namespace crpropa { class ElectronPairProduction: public Module { private: PhotonField photonField; - std::vector tabLossRate; /*< tabulated energy loss rate in [J/m] for protons at z = 0*/ - std::vector tabLorentzFactor; /*< tabulated proton energy [J] */ + + std::vector tabLossRate; /*< tabulated energy loss rate in [J/m] for protons at z = 0 */ + std::vector tabLorentzFactor; /*< tabulated Lorentz factor */ + + std::vector > tabSpectrum; /*< tabulated electron spectrum dN/dE in [a.u.] */ + std::vector tabE; /*< tabulated proton energy in [J], 70 steps from 10^15 - 10^22 eV */ + std::vector tabEe; /*< edges of electron energy bins in [J], 171 steps from 10^6.95 - 10^23.95 eV */ + std::vector tabEeWidth; /*< electron energy bin width in [J], 170 steps */ + bool haveElectrons; public: - ElectronPairProduction(PhotonField photonField = CMB_IRB); + ElectronPairProduction(PhotonField photonField = CMB, bool haveElectrons = + false); void setPhotonField(PhotonField photonField); + void setHaveElectrons(bool haveElectrons); void init(); - void init(std::string filename); + void initRate(std::string filename); + void initSpectrum(std::string filename); void process(Candidate *candidate) const; /** @@ -41,6 +51,7 @@ class ElectronPairProduction: public Module { beta(E,z) = (1+z)^3 beta((1+z)E). */ double lossLength(int id, double lf, double z) const; + void addElectrons(Candidate *candidate, double loss) const; }; } // namespace crpropa diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index f655bcce9..acd6c2883 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -1,5 +1,6 @@ #include "crpropa/module/ElectronPairProduction.h" #include "crpropa/ParticleID.h" +#include "crpropa/Random.h" #include #include @@ -7,8 +8,10 @@ namespace crpropa { -ElectronPairProduction::ElectronPairProduction(PhotonField photonField) : - photonField(photonField) { +ElectronPairProduction::ElectronPairProduction(PhotonField photonField, + bool haveElectrons) { + this->photonField = photonField; + this->haveElectrons = haveElectrons; init(); } @@ -17,19 +20,21 @@ void ElectronPairProduction::setPhotonField(PhotonField photonField) { init(); } +void ElectronPairProduction::setHaveElectrons(bool haveElectrons) { + this->haveElectrons = haveElectrons; +} + void ElectronPairProduction::init() { switch (photonField) { case CMB: setDescription("ElectronPairProduction: CMB"); - init(getDataPath("epair_CMB.txt")); + initRate(getDataPath("pair_rate_CMB.txt")); + initSpectrum(getDataPath("pair_spectrum_CMB.txt")); break; case IRB: setDescription("ElectronPairProduction: IRB"); - init(getDataPath("epair_IRB.txt")); - break; - case CMB_IRB: - setDescription("ElectronPairProduction: CMB and IRB"); - init(getDataPath("epair_CMB_IRB.txt")); + initRate(getDataPath("pair_rate_IRB.txt")); + initSpectrum(getDataPath("pair_spectrum_IRB.txt")); break; default: throw std::runtime_error( @@ -37,7 +42,7 @@ void ElectronPairProduction::init() { } } -void ElectronPairProduction::init(std::string filename) { +void ElectronPairProduction::initRate(std::string filename) { std::ifstream infile(filename.c_str()); if (!infile.good()) @@ -58,6 +63,37 @@ void ElectronPairProduction::init(std::string filename) { infile.close(); } +void ElectronPairProduction::initSpectrum(std::string filename) { + // proton energies: 70 energies from 10^15 - 10^22 eV + for (size_t i = 0; i < 70; i++) + tabE.push_back(pow(10, 15 + i * 7. / 69.) * eV); + // electron energies: 171 energies from 10^6.95 - 10^23.95 eV + for (size_t j = 0; j < 171; j++) + tabEe.push_back(pow(10, 6.95 + 0.1 * j) * eV); + for (size_t j = 0; j < 170; j++) + tabEeWidth.push_back(tabEe[j+1] - tabEe[j]); + + std::ifstream infile(filename.c_str()); + if (!infile.good()) + throw std::runtime_error( + "ElectronPairProduction: could not open file " + filename); + + double dNdE; + tabSpectrum.resize(70); + for (size_t i = 0; i < 70; i++) { + tabSpectrum[i].resize(170); + for (size_t j = 0; j < 170; j++) { + infile >> dNdE; + tabSpectrum[i][j] = dNdE * tabEe[j]; // read in spectrum: f(E) ~ dN/dE * E + } + for (size_t j = 1; j < 170; j++) { + tabSpectrum[i][j] += tabSpectrum[i][j - 1]; // cumulate F(E), this does not need to be normalized + } + } + + infile.close(); +} + double ElectronPairProduction::lossLength(int id, double lf, double z) const { double Z = chargeNumber(id); if (Z == 0) @@ -78,6 +114,42 @@ double ElectronPairProduction::lossLength(int id, double lf, double z) const { return 1. / rate; } +void ElectronPairProduction::addElectrons(Candidate *c, double loss) const { + double E = c->current.getEnergy(); + double dE = E * loss; // energy loss + double z = c->getRedshift(); + double Eeff = E / massNumber(c->current.getId()) * (1 + z); + + // interpolate spectrum in the Eff + size_t i = std::upper_bound(tabE.begin(), tabE.end(), Eeff) - tabE.begin() - 1; + double a = (Eeff - tabE[i]) / (tabE[i + 1] - tabE[i]); + + std::vector spectrum(170); + for (size_t j = 0; j < 170; j++) + spectrum[j] = tabSpectrum[i][j] + + a * (tabSpectrum[i + 1][j] - tabSpectrum[i][j]); + + // draw pairs as long as their energy is smaller than the pair production energy loss + Random &random = Random::instance(); + while (dE > 0) { + size_t i = random.randBin(spectrum); // draw random bin + double Ee = tabEe[i] + random.rand() * tabEeWidth[i]; // draw random uniform energy in bin + Ee /= (1 + z); // dN/dE(Ep,Ee,z) = (1+z)^4 * dN/dE(Ep*(1+z),Ee*(1+z),0) + + double Epair = 2 * Ee; + + // if the remaining energy is not sufficient check for random accepting + if (Epair > dE) + if (random.rand() > (dE / Epair)) + break; // not accepted + + // create pair and repeat with remaining energy + dE -= Epair; + c->addSecondary(11, Ee); + c->addSecondary(-11, Ee); + } +} + void ElectronPairProduction::process(Candidate *c) const { int id = c->current.getId(); if (not (isNucleus(id))) @@ -88,6 +160,9 @@ void ElectronPairProduction::process(Candidate *c) const { double step = c->getCurrentStep() / (1 + z); // step size in local frame double loss = step / lossLength(id, lf, z); + if (haveElectrons) + addElectrons(c, loss); + c->current.setLorentzFactor(lf * (1 - loss)); } From f80aca99e6e751d4815fb7d136dc4b96b76c50de Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 20 May 2014 14:52:09 +0200 Subject: [PATCH 0420/1298] update unit test and python tests for change in electron pair production --- test/python/testElectronPairProduction.py | 19 +++++----- test/python/testEnergyLossLength.py | 5 +-- test/testInteraction.cpp | 44 ++--------------------- 3 files changed, 14 insertions(+), 54 deletions(-) diff --git a/test/python/testElectronPairProduction.py b/test/python/testElectronPairProduction.py index 728d1b560..f7761125a 100644 --- a/test/python/testElectronPairProduction.py +++ b/test/python/testElectronPairProduction.py @@ -9,35 +9,34 @@ def compare(dataFileName, photonField, plotFileName): A = genfromtxt(dataFileName, comments="#", unpack=True) figure() plot(A[0], A[1], label='Datatable') - + epp = ElectronPairProduction(photonField) - + c = Candidate() c.current.setId(nucleusId(1,1)) c.setCurrentStep(1 * Mpc) - + N = 50 E = logspace(16,23,N) dE = zeros(N) - + for i in range(N): c.current.setEnergy(E[i] * eV) epp.process(c) dE[i] = (E[i] - c.current.getEnergy() / eV) - + plot(E, dE,'k+', label='Simulated using datatable', linewidth=2, markeredgewidth=2) - + xlabel('Energy [eV]') ylabel('Energy Loss Rate [eV / Mpc]') legend(loc='lower right') grid() loglog() - + savefig(plotFileName, bbox_inches='tight') -compare(getDataPath('epair_CMB.txt'), CMB, 'ElectronPairProduction_CMB.png') -compare(getDataPath('epair_IRB.txt'), IRB, 'ElectronPairProduction_IRB.png') -compare(getDataPath('epair_CMB_IRB.txt'), CMB_IRB, 'ElectronPairProduction_CMB_IRB.png') +compare(getDataPath('pair_rate_CMB.txt'), CMB, 'ElectronPairProduction_CMB.png') +compare(getDataPath('pair_rate_IRB.txt'), IRB, 'ElectronPairProduction_IRB.png') show() diff --git a/test/python/testEnergyLossLength.py b/test/python/testEnergyLossLength.py index 948d03cd5..766f02cd8 100644 --- a/test/python/testEnergyLossLength.py +++ b/test/python/testEnergyLossLength.py @@ -8,7 +8,8 @@ pd2 = PhotoDisintegration(IRB) pp1 = PhotoPionProduction(CMB) pp2 = PhotoPionProduction(IRB) -ep = ElectronPairProduction(CMB_IRB) +ep1 = ElectronPairProduction(CMB) +ep2 = ElectronPairProduction(IRB) def parse_pid(pid): return 'Z=%i, A=%i'%((pid//10000)%1000, (pid%10000)/10) @@ -26,7 +27,7 @@ def invAdd(x1, x2): L[0,i] = invAdd(pd1.lossLength(pid, E, z), pd2.lossLength(pid, E, z)) L[1,i] = invAdd(pp1.lossLength(pid, E, z), pp2.lossLength(pid, E, z)) lorentzfactor = E / (mass * c_squared) - L[2,i] = ep.lossLength(pid, lorentzfactor, z) + L[2,i] = invAdd(ep1.lossLength(pid, lorentzfactor, z), ep2.lossLength(pid, lorentzfactor, z)) L /= Mpc diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index f74e88468..6fd81787b 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -32,14 +32,6 @@ TEST(ElectronPairProduction, energyDecreasing) { epp2.process(&c); EXPECT_LE(c.current.getEnergy(), E); } - - ElectronPairProduction epp3(CMB_IRB); - for (int i = 0; i < 80; i++) { - double E = pow(10, 15 + i * 0.1) * eV; - c.current.setEnergy(E); - epp3.process(&c); - EXPECT_LE(c.current.getEnergy(), E); - } } TEST(ElectronPairProduction, belowEnergyTreshold) { @@ -68,7 +60,7 @@ TEST(ElectronPairProduction, valuesCMB) { // Test if energy loss corresponds to the data table. std::vector x; std::vector y; - std::ifstream infile(getDataPath("epair_CMB.txt").c_str()); + std::ifstream infile(getDataPath("pair_CMB.txt").c_str()); while (infile.good()) { if (infile.peek() != '#') { double a, b; @@ -100,7 +92,7 @@ TEST(ElectronPairProduction, valuesIRB) { // Test if energy loss corresponds to the data table. std::vector x; std::vector y; - std::ifstream infile(getDataPath("epairIRB.txt").c_str()); + std::ifstream infile(getDataPath("pairIRB.txt").c_str()); while (infile.good()) { if (infile.peek() != '#') { double a, b; @@ -128,38 +120,6 @@ TEST(ElectronPairProduction, valuesIRB) { } } -TEST(ElectronPairProduction, valuesCMB_IRB) { - // Test if energy loss corresponds to the data table. - std::vector x; - std::vector y; - std::ifstream infile(getDataPath("epair_CMB_IRB.txt").c_str()); - while (infile.good()) { - if (infile.peek() != '#') { - double a, b; - infile >> a >> b; - if (infile) { - x.push_back(a * eV); - y.push_back(b * eV / Mpc); - } - } - infile.ignore(std::numeric_limits::max(), '\n'); - } - infile.close(); - - Candidate c; - c.setCurrentStep(1 * Mpc); - c.current.setId(nucleusId(1, 1)); // proton - - ElectronPairProduction epp(CMB_IRB); - for (int i = 0; i < x.size(); i++) { - c.current.setEnergy(x[i]); - epp.process(&c); - double dE = x[i] - c.current.getEnergy(); - double dE_table = y[i] * 1 * Mpc; - EXPECT_NEAR(dE, dE_table, 1e-12); - } -} - TEST(NuclearDecay, scandium44) { // Test beta+ decay of 44Sc 44Ca. // This test can stochastically fail. From ac0bda9c67f6c76480c4b89f51f3c2f9742af049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Mon, 26 May 2014 10:11:43 +0200 Subject: [PATCH 0421/1298] change EleCa to static libarary --- CMakeLists.txt | 4 +- libs/EleCa/CMakeLists.txt | 13 ++ libs/EleCa/EleCa/Particle.h | 128 ------------ libs/EleCa/include/EleCa/Common.h | 14 ++ libs/EleCa/{ => include}/EleCa/Constants.h | 0 libs/EleCa/include/EleCa/EnergyLoss.h | 30 +++ libs/EleCa/include/EleCa/Particle.h | 58 ++++++ libs/EleCa/include/EleCa/Process.h | 75 ++++++++ libs/EleCa/include/EleCa/Propagation.h | 60 ++++++ libs/EleCa/{EleCa/Common.h => src/Common.cpp} | 21 +- .../EnergyLoss.h => src/EnergyLoss.cpp} | 10 +- libs/EleCa/src/Particle.cpp | 102 ++++++++++ .../{EleCa/Process.h => src/Process.cpp} | 182 +++++++----------- .../Propagation.h => src/Propagation.cpp} | 72 +------ libs/EleCa/{EleCa => src}/XLoss_CBR.h | 0 python/crpropa.i | 2 + 16 files changed, 461 insertions(+), 310 deletions(-) create mode 100644 libs/EleCa/CMakeLists.txt delete mode 100644 libs/EleCa/EleCa/Particle.h create mode 100644 libs/EleCa/include/EleCa/Common.h rename libs/EleCa/{ => include}/EleCa/Constants.h (100%) create mode 100644 libs/EleCa/include/EleCa/EnergyLoss.h create mode 100644 libs/EleCa/include/EleCa/Particle.h create mode 100644 libs/EleCa/include/EleCa/Process.h create mode 100644 libs/EleCa/include/EleCa/Propagation.h rename libs/EleCa/{EleCa/Common.h => src/Common.cpp} (68%) rename libs/EleCa/{EleCa/EnergyLoss.h => src/EnergyLoss.cpp} (98%) create mode 100644 libs/EleCa/src/Particle.cpp rename libs/EleCa/{EleCa/Process.h => src/Process.cpp} (63%) rename libs/EleCa/{EleCa/Propagation.h => src/Propagation.cpp} (91%) rename libs/EleCa/{EleCa => src}/XLoss_CBR.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 05af273c6..cf7f8ee51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,7 +53,9 @@ list(APPEND CRPROPA_EXTRA_LIBRARIES dint) list(APPEND CRPROPA_EXTRA_INCLUDES libs/dint/include) # EleCa (provided) -list(APPEND CRPROPA_EXTRA_INCLUDES libs/EleCa) +add_subdirectory(libs/EleCa) +list(APPEND CRPROPA_EXTRA_LIBRARIES eleca) +list(APPEND CRPROPA_EXTRA_INCLUDES libs/EleCa/include) # OpenMP (optional for shared memory multiprocessing) option(ENABLE_OPENMP "OpenMP for multithreading" ON) diff --git a/libs/EleCa/CMakeLists.txt b/libs/EleCa/CMakeLists.txt new file mode 100644 index 000000000..07cb8608a --- /dev/null +++ b/libs/EleCa/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 2.6) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) + +add_library(eleca STATIC + src/Common + src/EnergyLoss + src/Particle + src/Process + src/Propagation +) + +SET_TARGET_PROPERTIES( eleca PROPERTIES COMPILE_FLAGS -fPIC) diff --git a/libs/EleCa/EleCa/Particle.h b/libs/EleCa/EleCa/Particle.h deleted file mode 100644 index d312ea677..000000000 --- a/libs/EleCa/EleCa/Particle.h +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef ELECA_PARTICLE_H_ -#define ELECA_PARTICLE_H_ - -#include "Constants.h" - -namespace eleca { - -class Particle { -private: - int ftype; - double fE0ph; - double fz0ph; - double fbeta; - double fmass; - bool fIsGood; - int fwi; - double fB; - -public: - Particle(); - Particle(int _ft, double _fE, double fz); -// Particle(Candidate candidate); - ~ Particle() { - } - - bool IsGood() { - double zmax_prop0 = 0.91425; - double zmax_prop1 = -0.101717; - double zmax_prop2 = 0.002855; - double Eloc = log10(fE0ph); - if (Eloc < 18) - Eloc = 18; - if (fz0ph > zmax_prop0 + zmax_prop1 * Eloc + zmax_prop2 * Eloc * Eloc) - return 0; - return 1; - } - - int GetType() const { - return ftype; - } - - void SetType(int _ft) { - ftype = _ft; - } - - int GetWeigth() const { - return fwi; - } - - void SetWeigth(int _wi) { - fwi = _wi; - } - - double GetEnergy() const { - return fE0ph; - } - - void SetEnergy(double _fE) { - fE0ph = _fE; - SetBetaAndMass(); - } - - double Getz() const { - return fz0ph; - } - - void Setz(double _fz) { - fz0ph = _fz; - } - - double GetMass() const { - return fmass; - } - - double GetBeta() const { - return fbeta; - } -// -// bool GetStatus() { -// fIsGood = IsGood(); -// return fIsGood; -// } - - void SetBetaAndMass() { - if (ftype == 22) { - fbeta = 1.0; - fmass = 0; - } - if (abs(ftype) == 11) { - fmass = ElectronMass; - fbeta = (double) sqrt(1 - fmass * fmass / (fE0ph * fE0ph)); - - } - } - - void SetB(double B) { - fB = B; - } - double GetB() const { - return fB; - } - -}; - -Particle::Particle(int _ft, double _fE, double _fz) { - ftype = _ft; - fE0ph = _fE; - fz0ph = _fz; - SetBetaAndMass(); - fIsGood = IsGood(); - fB = 0; - fwi = 1; -} - -Particle::Particle() { - ftype = 22; - fE0ph = 0; - fz0ph = 0; - fmass = 0; - fbeta = 0; - fIsGood = 0; - fB = 0; - fwi = 1; -} - -} // namespace eleca - -#endif // ELECA_PARTICLE_H_ diff --git a/libs/EleCa/include/EleCa/Common.h b/libs/EleCa/include/EleCa/Common.h new file mode 100644 index 000000000..0b9895e6f --- /dev/null +++ b/libs/EleCa/include/EleCa/Common.h @@ -0,0 +1,14 @@ +#ifndef ELECA_COMMON_H_ +#define ELECA_COMMON_H_ + +namespace eleca { + +double z2Mpc(double z); +double Mpc2z(double D); +double Uniform(double min, double max); + +void setUniformCallback(double (*Uniform)(double min, double max)); + +} // namespace eleca + +#endif // ELECA_COMMON_H_ diff --git a/libs/EleCa/EleCa/Constants.h b/libs/EleCa/include/EleCa/Constants.h similarity index 100% rename from libs/EleCa/EleCa/Constants.h rename to libs/EleCa/include/EleCa/Constants.h diff --git a/libs/EleCa/include/EleCa/EnergyLoss.h b/libs/EleCa/include/EleCa/EnergyLoss.h new file mode 100644 index 000000000..a647b1374 --- /dev/null +++ b/libs/EleCa/include/EleCa/EnergyLoss.h @@ -0,0 +1,30 @@ +#ifndef ELECA_ENERGY_LOSS_H_ +#define ELECA_ENERGY_LOSS_H_ + +namespace eleca { + +class Particle; +class Process; + +double dTdZ(double z); +double betaRsh(double z); +double fLossAdiabatic(double E, double z); +double AdiabaticELoss(double z0, double z, double E0); +double MeanRateSynchrotronLoss(double E, double B); +double ESynchrotronAdiabaticLoss(double z, double E, double B); + +void InitRK(); +double EnergyLoss1D(double Energy, double z0, double zfin, double B); +double dSigmadE_ICS(double Ee, double Eer, double s, double theta); +double dSigmadE_PP(double Ee, double E0, double eps, double theta); +double ExtractPPSecondariesEnergy(Particle &pi, Particle &pt); +double ExtractPPSecondariesEnergy(Process &proc); +double ExtractICSSecondariesEnergy(Particle &pi, Particle &pt); +double ExtractICSSecondariesEnergy(Process &proc); +double ExtractTPPSecondariesEnergy(Particle &pi, Particle &pt); +double ExtractTPPSecondariesEnergy(Process &proc); +double ExtractDPPSecondariesEnergy(double E0); + +} // namespace eleca + +#endif // ELECA_ENERGY_LOSS_H_ diff --git a/libs/EleCa/include/EleCa/Particle.h b/libs/EleCa/include/EleCa/Particle.h new file mode 100644 index 000000000..eeb366d4d --- /dev/null +++ b/libs/EleCa/include/EleCa/Particle.h @@ -0,0 +1,58 @@ +#ifndef ELECA_PARTICLE_H_ +#define ELECA_PARTICLE_H_ + +#include "Constants.h" + +namespace eleca { + +class Particle { +private: + int ftype; + double fE0ph; + double fz0ph; + double fbeta; + double fmass; + bool fIsGood; + int fwi; + double fB; + +public: + Particle(); + Particle(int _ft, double _fE, double fz); + ~ Particle(); + bool IsGood(); + int GetType() const; + + void SetType(int _ft); + + int GetWeigth() const; + + void SetWeigth(int _wi); + + double GetEnergy() const; + + void SetEnergy(double _fE); + + double Getz() const; + + void Setz(double _fz); + + double GetMass() const; + + double GetBeta() const; +// +// bool GetStatus() { +// fIsGood = IsGood(); +// return fIsGood; +// } + + void SetBetaAndMass(); + + void SetB(double B); + double GetB() const; + +}; + +} // namespace eleca + +#endif // ELECA_PARTICLE_H_ diff --git a/libs/EleCa/include/EleCa/Process.h b/libs/EleCa/include/EleCa/Process.h new file mode 100644 index 000000000..1a0e2cf6c --- /dev/null +++ b/libs/EleCa/include/EleCa/Process.h @@ -0,0 +1,75 @@ +#ifndef ELECA_PROCESS_H_ +#define ELECA_PROCESS_H_ + +#include "Particle.h" + +#include +#include + +namespace eleca { + +class Process { + +public: + + std::string fname; + double flambda; + double fsmin; + double fsmax; + double fCMEnergy; + double fInteractionAngle; + double feps_inf; + double feps_sup; + Particle fPi; + Particle fPt; + + std::string fback; + double fbackdensity; + + Process(); + Process(const Process&); + Process(Particle&, Particle&); + Process(Particle&, Particle&, std::string); + + ~Process(); + + void SetName(std::string nm); + const std::string &GetName() const; + + void SetInteractionAngle(double a); + double GetInteractionAngle() const; + + void SetLambda(double le); + double GetLambda() const; + + void SetLimits(double smin, double smax); + void SetLimits(Particle& p1, std::string nameproc); + void SetLimits(); + + void SetMax(double smax); + void SetMin(double smin); + double GetMin() const; + double GetMax() const; + + void SetCMEnergy(double s); + + void SetCMEnergy(Particle p1, Particle pb); + + void SetCMEnergy(); + double GetCMEnergy() const; + + void SetIncidentParticle(const Particle& p1); + void SetTargetParticle(Particle& p1); + const Particle &GetIncidentParticle() const; + const Particle &GetTargetParticle() const; + + const std::string &GetBackground() const; + void SetBackground(std::string BackRad); + +private: + +}; + +} // namespace + +#endif diff --git a/libs/EleCa/include/EleCa/Propagation.h b/libs/EleCa/include/EleCa/Propagation.h new file mode 100644 index 000000000..0f04f17a8 --- /dev/null +++ b/libs/EleCa/include/EleCa/Propagation.h @@ -0,0 +1,60 @@ +#ifndef ELECA_PROPAGATION_H +#define ELECA_PROPAGATION_H + +#include "EleCa/Particle.h" + +#include +#include + +namespace eleca { + +class Process; +class Propagation { + +private: + + double vPPle[1101]; + double vDPPle[1101]; + double vTPPle[1101]; + double vICSle[1101]; + double vEtab[1101]; + + std::vector BkgE, BkgA; + std::string Bkg; + double fEthr; + +public: + + Propagation(); + + void SetEthr(double eth); + double GetEthr(); + ~Propagation(); + + void WriteOutput(std::ostream &out, Particle &p1, + std::vector &part) const; + + void ReadTables(const std::string &file); + void InitBkgArray(const std::string &BackRad); + + double GetMeanThetaBFDeflection(double Bin, double Ein, int ptype, + double Lin) const; + double GetLambdaTab(const Process &proc, const std::string &procName) const; + double ExtractMinDist(Process &proc, int type, double R, double R2, + std::vector &Etarget) const; + std::vector GetEtarget(Process &proc, + const Particle &particle) const; + void Propagate(Particle &curr_particle, + std::vector &ParticleAtMatrix, + std::vector &ParticleAtGround) const; + double ExtractPhotonEnergyMC(double z, Process &proc) const; + double ShootPhotonEnergyMC(double z) const; + double ShootPhotonEnergyMC(double Emin, double z) const; + void SetInitVar(std::vector > bk, + std::vector > *le) const; + +}; + +} // namespace eleca + +#endif // ELECA_PROPAGATION_H diff --git a/libs/EleCa/EleCa/Common.h b/libs/EleCa/src/Common.cpp similarity index 68% rename from libs/EleCa/EleCa/Common.h rename to libs/EleCa/src/Common.cpp index 7f3857248..47362d375 100644 --- a/libs/EleCa/EleCa/Common.h +++ b/libs/EleCa/src/Common.cpp @@ -1,11 +1,9 @@ -#ifndef ELECA_COMMON_H_ -#define ELECA_COMMON_H_ - -#include "Constants.h" -#include "crpropa/Random.h" +#include "EleCa/Common.h" +#include "EleCa/Constants.h" #include #include +#include namespace eleca { @@ -31,10 +29,19 @@ double Mpc2z(double D) { } } +static double (*_Uniform)(double min, double max) = 0; + +void setUniformCallback(double (*uniform)(double min, double max)) { + _Uniform = uniform; +} + double Uniform(double min, double max) { - return crpropa::Random::instance().randUniform(min, max); + if (_Uniform) + return _Uniform(min, max); + else + //return crpropa::Random::instance().randUniform(min, max); + return min + (max - min) * ::drand48(); } } // namespace eleca -#endif // ELECA_COMMON_H_ diff --git a/libs/EleCa/EleCa/EnergyLoss.h b/libs/EleCa/src/EnergyLoss.cpp similarity index 98% rename from libs/EleCa/EleCa/EnergyLoss.h rename to libs/EleCa/src/EnergyLoss.cpp index 1dd708c4e..12d58006d 100644 --- a/libs/EleCa/EleCa/EnergyLoss.h +++ b/libs/EleCa/src/EnergyLoss.cpp @@ -1,9 +1,13 @@ #ifndef ELECA_ENERGY_LOSS_H_ #define ELECA_ENERGY_LOSS_H_ -#include "Common.h" +#include "EleCa/EnergyLoss.h" +#include "EleCa/Process.h" +#include "EleCa/Common.h" #include +#include +#include namespace eleca { @@ -376,7 +380,7 @@ double ExtractPPSecondariesEnergy(Process &proc) { << cnt << std::endl; std::cout << " Limits " << proc.GetMin() << std::endl; if (cnt == 0) - exit(0); + throw std::runtime_error("failed in extractPP"); } } //end while @@ -393,7 +397,7 @@ double ExtractICSSecondariesEnergy(Particle &pi, Particle &pt) { incidence angle theta. Returns the energy of the recoiled e+ (e-) */ - if (abs(pi.GetType()) != 11) { + if (::abs(pi.GetType()) != 11) { std::cerr << "something wrong in type ExtractICSEnergy " << std::endl; return 0.; } diff --git a/libs/EleCa/src/Particle.cpp b/libs/EleCa/src/Particle.cpp new file mode 100644 index 000000000..2013544f1 --- /dev/null +++ b/libs/EleCa/src/Particle.cpp @@ -0,0 +1,102 @@ +#include "EleCa/Particle.h" +#include + +namespace eleca { + +Particle::~Particle() { +} + +bool Particle::IsGood() { + double zmax_prop0 = 0.91425; + double zmax_prop1 = -0.101717; + double zmax_prop2 = 0.002855; + double Eloc = log10(fE0ph); + if (Eloc < 18) + Eloc = 18; + if (fz0ph > zmax_prop0 + zmax_prop1 * Eloc + zmax_prop2 * Eloc * Eloc) + return 0; + return 1; +} + +int Particle::GetType() const { + return ftype; +} + +void Particle::SetType(int _ft) { + ftype = _ft; +} + +int Particle::GetWeigth() const { + return fwi; +} + +void Particle::SetWeigth(int _wi) { + fwi = _wi; +} + +double Particle::GetEnergy() const { + return fE0ph; +} + +void Particle::SetEnergy(double _fE) { + fE0ph = _fE; + SetBetaAndMass(); +} + +double Particle::Getz() const { + return fz0ph; +} + +void Particle::Setz(double _fz) { + fz0ph = _fz; +} + +double Particle::GetMass() const { + return fmass; +} + +double Particle::GetBeta() const { + return fbeta; +} + +void Particle::SetBetaAndMass() { + if (ftype == 22) { + fbeta = 1.0; + fmass = 0; + } + if (abs(ftype) == 11) { + fmass = ElectronMass; + fbeta = (double) sqrt(1 - fmass * fmass / (fE0ph * fE0ph)); + + } +} + +void Particle::SetB(double B) { + fB = B; +} +double Particle::GetB() const { + return fB; +} + +Particle::Particle(int _ft, double _fE, double _fz) { + ftype = _ft; + fE0ph = _fE; + fz0ph = _fz; + SetBetaAndMass(); + fIsGood = IsGood(); + fB = 0; + fwi = 1; +} + +Particle::Particle() { + ftype = 22; + fE0ph = 0; + fz0ph = 0; + fmass = 0; + fbeta = 0; + fIsGood = 0; + fB = 0; + fwi = 1; +} + +} // namespace eleca diff --git a/libs/EleCa/EleCa/Process.h b/libs/EleCa/src/Process.cpp similarity index 63% rename from libs/EleCa/EleCa/Process.h rename to libs/EleCa/src/Process.cpp index a2ae8a056..701730fa6 100644 --- a/libs/EleCa/EleCa/Process.h +++ b/libs/EleCa/src/Process.cpp @@ -1,128 +1,94 @@ -#ifndef ELECA_PROCESS_H_ -#define ELECA_PROCESS_H_ - -#include "Particle.h" +#include "EleCa/Process.h" #include #include +#include namespace eleca { -class Process { - -public: - - std::string fname; - double flambda; - double fsmin; - double fsmax; - double fCMEnergy; - double fInteractionAngle; - double feps_inf; - double feps_sup; - Particle fPi; - Particle fPt; - - std::string fback; - double fbackdensity; - - Process(); - Process(const Process&); - Process(Particle&, Particle&); - Process(Particle&, Particle&, std::string); - - ~Process(); - - void SetName(std::string nm) { - fname = nm; - } - const std::string &GetName() const { - return fname; - } - - void SetInteractionAngle(double a) { - fInteractionAngle = a; - } - double GetInteractionAngle() const { - return fInteractionAngle; - } - - void SetLambda(double le) { - flambda = le; - } - double GetLambda() const { - return flambda; - } +void Process::SetName(std::string nm) { + fname = nm; +} +const std::string &Process::GetName() const { + return fname; +} - void SetLimits(double smin, double smax) { - fsmin = smin; - fsmax = smax; - } - void SetLimits(Particle& p1, std::string nameproc); - void SetLimits() { - SetLimits(fPi, fname); - } +void Process::SetInteractionAngle(double a) { + fInteractionAngle = a; +} +double Process::GetInteractionAngle() const { + return fInteractionAngle; +} - void SetMax(double smax) { - fsmax = smax; - } - void SetMin(double smin) { - fsmin = smin; - } - double GetMin() const { - return fsmin; - } - double GetMax() const { - return fsmax; - } +void Process::SetLambda(double le) { + flambda = le; +} +double Process::GetLambda() const { + return flambda; +} - void SetCMEnergy(double s) { - fCMEnergy = s; - } +void Process::SetLimits(double smin, double smax) { + fsmin = smin; + fsmax = smax; +} - void SetCMEnergy(Particle p1, Particle pb) { - fCMEnergy = 2 * p1.GetEnergy() * pb.GetEnergy() - * (1 - p1.GetBeta() * cos(fInteractionAngle)) - + p1.GetMass() * p1.GetMass() + pb.GetMass() * pb.GetMass(); - } +void Process::SetLimits() { + SetLimits(fPi, fname); +} - void SetCMEnergy() { - fCMEnergy = 2 * fPi.GetEnergy() * fPt.GetEnergy() - * (1 - fPi.GetBeta() * cos(fInteractionAngle)) - + fPi.GetMass() * fPi.GetMass() + fPt.GetMass() * fPt.GetMass(); +void Process::SetMax(double smax) { + fsmax = smax; +} +void Process::SetMin(double smin) { + fsmin = smin; +} +double Process::GetMin() const { + return fsmin; +} +double Process::GetMax() const { + return fsmax; +} - } +void Process::SetCMEnergy(double s) { + fCMEnergy = s; +} - double GetCMEnergy() const { - return fCMEnergy; - } +void Process::SetCMEnergy(Particle p1, Particle pb) { + fCMEnergy = 2 * p1.GetEnergy() * pb.GetEnergy() + * (1 - p1.GetBeta() * cos(fInteractionAngle)) + + p1.GetMass() * p1.GetMass() + pb.GetMass() * pb.GetMass(); +} - void SetIncidentParticle(const Particle& p1) { - fPi = p1; - SetLimits(); - } - void SetTargetParticle(Particle& p1) { - fPt = p1; - SetLimits(); - } +void Process::SetCMEnergy() { + fCMEnergy = 2 * fPi.GetEnergy() * fPt.GetEnergy() + * (1 - fPi.GetBeta() * cos(fInteractionAngle)) + + fPi.GetMass() * fPi.GetMass() + fPt.GetMass() * fPt.GetMass(); - const Particle &GetIncidentParticle() const { - return fPi; - } - const Particle &GetTargetParticle() const { - return fPt; - } +} - const std::string &GetBackground() const { - return fback; - } - void SetBackground(std::string BackRad); +double Process::GetCMEnergy() const { + return fCMEnergy; +} -private: +void Process::SetIncidentParticle(const Particle& p1) { + fPi = p1; + SetLimits(); +} +void Process::SetTargetParticle(Particle& p1) { + fPt = p1; + SetLimits(); +} -}; +const Particle &Process::GetIncidentParticle() const { + return fPi; +} +const Particle &Process::GetTargetParticle() const { + return fPt; +} -//-------------- explicit definitions +const std::string &Process::GetBackground() const { + return fback; +} Process::Process() { fname = ""; @@ -260,6 +226,4 @@ void Process::SetLimits(Particle& p1, std::string nameproc) { } } -} - -#endif +} // namespace diff --git a/libs/EleCa/EleCa/Propagation.h b/libs/EleCa/src/Propagation.cpp similarity index 91% rename from libs/EleCa/EleCa/Propagation.h rename to libs/EleCa/src/Propagation.cpp index f8b76b4fd..a053ce9b0 100644 --- a/libs/EleCa/EleCa/Propagation.h +++ b/libs/EleCa/src/Propagation.cpp @@ -1,76 +1,26 @@ -#ifndef ELECA_PROPAGATION_H -#define ELECA_PROPAGATION_H +#include "EleCa/Propagation.h" +#include "EleCa/Particle.h" +#include "EleCa/Process.h" +#include "EleCa/Common.h" +#include "EleCa/EnergyLoss.h" +#include "EleCa/Constants.h" -#include "Particle.h" -#include "Process.h" -#include "Common.h" #include "XLoss_CBR.h" -#include "EnergyLoss.h" -#include "Constants.h" #include #include #include +#include namespace eleca { -class Propagation { - -private: - - double vPPle[1101]; - double vDPPle[1101]; - double vTPPle[1101]; - double vICSle[1101]; - double vEtab[1101]; - - std::vector BkgE, BkgA; - std::string Bkg; - double fEthr; - -public: - - Propagation(); - - void SetEthr(double eth) { - fEthr = eth; - } - - double GetEthr() { - return fEthr; - } - - ~Propagation() { - } - - void WriteOutput(std::ostream &out, Particle &p1, - std::vector &part) const; - - void ReadTables(const std::string &file); - void InitBkgArray(const std::string &BackRad); - - double GetMeanThetaBFDeflection(double Bin, double Ein, int ptype, - double Lin) const; - double GetLambdaTab(const Process &proc, const std::string &procName) const; - double ExtractMinDist(Process &proc, int type, double R, double R2, - std::vector &Etarget) const; - std::vector GetEtarget(Process &proc, - const Particle &particle) const; - void Propagate(Particle &curr_particle, - std::vector &ParticleAtMatrix, - std::vector &ParticleAtGround) const; - double ExtractPhotonEnergyMC(double z, Process &proc) const; - double ShootPhotonEnergyMC(double z) const; - double ShootPhotonEnergyMC(double Emin, double z) const; - void SetInitVar(std::vector > bk, - std::vector > *le) const; - -}; - Propagation::Propagation() { fEthr = 1e16; } +Propagation::~Propagation() { +} + void Propagation::ReadTables(const std::string &filename) { #ifdef DEBUG_ELECA @@ -725,5 +675,3 @@ void Propagation::Propagate(Particle &curr_particle, } } // namespace eleca - -#endif // ELECA_PROPAGATION_H diff --git a/libs/EleCa/EleCa/XLoss_CBR.h b/libs/EleCa/src/XLoss_CBR.h similarity index 100% rename from libs/EleCa/EleCa/XLoss_CBR.h rename to libs/EleCa/src/XLoss_CBR.h diff --git a/python/crpropa.i b/python/crpropa.i index dcb3fa195..81fd765b2 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -65,6 +65,7 @@ using std::ptrdiff_t; #include "crpropa/Common.h" #include "crpropa/Cosmology.h" #include "crpropa/PhotonBackground.h" +#include "crpropa/PhotonPropagation.h" #include "crpropa/Grid.h" #include "crpropa/GridTools.h" %} @@ -110,6 +111,7 @@ using std::ptrdiff_t; %include "crpropa/Common.h" %include "crpropa/Cosmology.h" %include "crpropa/PhotonBackground.h" +%include "crpropa/PhotonPropagation.h" %include "crpropa/Random.h" %include "crpropa/ParticleState.h" %include "crpropa/ParticleID.h" From c3eb37fee6e430a307822fa8011bb94f1705ed6c Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 26 May 2014 14:40:18 +0200 Subject: [PATCH 0422/1298] crpropa-xmlrun: treat CMB and IRB seperately for all interactions --- src/XmlExecute.cpp | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index f57351220..2e75b6ac1 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -464,22 +464,20 @@ void XmlExecute::loadSophia(xml_node &node) { decay = false; } - if (pairprodCMB and pairprodIRB) - modules.add(new ElectronPairProduction(CMB_IRB)); - else - if (pairprodCMB) - modules.add(new ElectronPairProduction(CMB)); + if (pairprodCMB) + modules.add(new ElectronPairProduction(CMB)); + if (pairprodIRB) + modules.add(new ElectronPairProduction(IRB)); if (pionprodCMB) modules.add(new PhotoPionProduction(CMB)); if (pionprodIRB) modules.add(new PhotoPionProduction(IRB)); - if (photodisCMB and photodisIRB) - modules.add(new PhotoDisintegration(CMB_IRB)); - else - if (photodisCMB) - modules.add(new PhotoDisintegration(CMB)); + if (photodisCMB) + modules.add(new PhotoDisintegration(CMB)); + if (photodisIRB) + modules.add(new PhotoDisintegration(IRB)); if (decay) modules.add(new NuclearDecay); @@ -573,7 +571,8 @@ void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { // 1D double dlt = childValue(n, "CoordX_Mpc") * Mpc; pos.x = lightTravel2ComovingDistance(dlt); - cout << " - Light travel distance = " << dlt / Mpc << " Mpc" << endl; + cout << " - Light travel distance = " << dlt / Mpc << " Mpc" + << endl; } else { // 3D pos.x = childValue(n, "CoordX_Mpc") * Mpc; @@ -696,7 +695,7 @@ void XmlExecute::loadOutput(xml_node &node) { string format = file_node.attribute("type").as_string(); cout << " - Filetype: " << format << endl; - string filename = kiss::trim( node.child("File").child_value() ); + string filename = kiss::trim(node.child("File").child_value()); cout << " - Filename: " << filename << endl; string option = node.child("File").attribute("option").as_string(); @@ -727,20 +726,20 @@ void XmlExecute::loadOutput(xml_node &node) { #ifdef CRPROPA_HAVE_ROOT else if (format == "ROOT") { if (type == "Full Trajectories") - if (is1D) - modules.add(new CRPropa2ROOTTrajectoryOutput1D(filename)); - else - modules.add(new CRPropa2ROOTTrajectoryOutput3D(filename)); + if (is1D) + modules.add(new CRPropa2ROOTTrajectoryOutput1D(filename)); + else + modules.add(new CRPropa2ROOTTrajectoryOutput3D(filename)); else if (type == "Events") - if (is1D) - modules.add(new CRPropa2ROOTEventOutput1D(filename)); - else - modules.add(new CRPropa2ROOTEventOutput3D(filename)); + if (is1D) + modules.add(new CRPropa2ROOTEventOutput1D(filename)); + else + modules.add(new CRPropa2ROOTEventOutput3D(filename)); else if (type == "None") - return; + return; else - cout << " --> unknown output type " - << "('Events', 'Full Trajectories' or 'None')" << endl; + cout << " --> unknown output type " + << "('Events', 'Full Trajectories' or 'None')" << endl; } #endif // CRPROPA_HAVE_ROOT else { From 3bd5d4defe861a6c0479a103b3c0fc26737588af Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 26 May 2014 15:23:14 +0200 Subject: [PATCH 0423/1298] Photodisintegration: Remove CMB_IRB --- include/crpropa/PhotonBackground.h | 2 +- src/module/PhotoDisintegration.cpp | 4 --- test/python/testEnergyLossLength.py | 50 +++++++++++++++++------------ 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/include/crpropa/PhotonBackground.h b/include/crpropa/PhotonBackground.h index 8e6d38075..2628bcc54 100644 --- a/include/crpropa/PhotonBackground.h +++ b/include/crpropa/PhotonBackground.h @@ -5,7 +5,7 @@ namespace crpropa { // Photon fields enum PhotonField { - CMB, IRB, CMB_IRB + CMB, IRB }; // Returns overall comoving scaling factor diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 402b3cf10..2102b674c 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -30,10 +30,6 @@ void PhotoDisintegration::init(PhotonField photonField) { setDescription("PhotoDisintegration: IRB"); init(getDataPath("photodis_IRB.txt")); break; - case CMB_IRB: - setDescription("PhotoDisintegration: CMB and IRB"); - init(getDataPath("photodis_CMB_IRB.txt")); - break; default: throw std::runtime_error( "crpropa::PhotoDisintegration: unknown photon background"); diff --git a/test/python/testEnergyLossLength.py b/test/python/testEnergyLossLength.py index 766f02cd8..73a540929 100644 --- a/test/python/testEnergyLossLength.py +++ b/test/python/testEnergyLossLength.py @@ -4,6 +4,12 @@ from crpropa import * from pylab import * +z = 0 +pid = nucleusId(4, 2) +mass = nucleusMass(pid) +energies = logspace(1, 4, 50) + + pd1 = PhotoDisintegration(CMB) pd2 = PhotoDisintegration(IRB) pp1 = PhotoPionProduction(CMB) @@ -11,32 +17,36 @@ ep1 = ElectronPairProduction(CMB) ep2 = ElectronPairProduction(IRB) -def parse_pid(pid): - return 'Z=%i, A=%i'%((pid//10000)%1000, (pid%10000)/10) - -def invAdd(x1, x2): - return 1. / (1. / x1 + 1. / x2) - -pid = nucleusId(4, 2) -mass = nucleusMass(pid) -energies = logspace(1, 4, 50) -L = zeros((3, 50)) -z = 0. +pp1Loss, pp2Loss = zeros(50), zeros(50) +pd1Loss, pd2Loss = zeros(50), zeros(50) +ep1Loss, ep2Loss = zeros(50), zeros(50) for i, E in enumerate(energies * EeV): - L[0,i] = invAdd(pd1.lossLength(pid, E, z), pd2.lossLength(pid, E, z)) - L[1,i] = invAdd(pp1.lossLength(pid, E, z), pp2.lossLength(pid, E, z)) - lorentzfactor = E / (mass * c_squared) - L[2,i] = invAdd(ep1.lossLength(pid, lorentzfactor, z), ep2.lossLength(pid, lorentzfactor, z)) -L /= Mpc + # pion production + pp1Loss[i] = pp1.lossLength(pid, E, z) + pp2Loss[i] = pp2.lossLength(pid, E, z) + # disintegration + pd1Loss[i] = pd1.lossLength(pid, E, z) + pd2Loss[i] = pd2.lossLength(pid, E, z) + # pair production + lf = E / (mass * c_squared) # Lorentz factor + ep1Loss[i] = ep1.lossLength(pid, lf, z) + ep2Loss[i] = ep2.lossLength(pid, lf, z) + +# inversely add loss lengths +ppLoss = 1/(1/pp1Loss + 1/pp2Loss) / Mpc +pdLoss = 1/(1/pd1Loss + 1/pd2Loss) / Mpc +epLoss = 1/(1/ep1Loss + 1/ep2Loss) / Mpc figure() -plot(energies, L[0], label='PDis') -plot(energies, L[1], label='PPion') -plot(energies, L[2], label='EPair') +plot(energies, pdLoss, label='PDis') +plot(energies, ppLoss, label='PPion') +plot(energies, epLoss, label='EPair') legend(frameon=0, loc='lower left') -text(0.05, 0.25, parse_pid(pid), transform=gca().transAxes) +text(0.05, 0.25, + 'Z=%i, A=%i'%(chargeNumber(pid), massNumber(pid)), + transform=gca().transAxes) xlabel('Energy [EeV]') ylabel('Energy Loss Length [Mpc]') ylim(1, 1e4) From f970568846a401587b2a42e4f82856e9355ee703 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 6 Jun 2014 10:37:55 +0200 Subject: [PATCH 0424/1298] fix anti-nucleon bug in PhotoPionProduction --- src/module/PhotoPionProduction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 995ae82f0..4690ed7a3 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -197,7 +197,7 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, case -13: // anti-proton case -14: // anti-neutron if (haveAntiNucleons) - candidate->addSecondary(-nucleusId(1, 14 - pType), Eout); + candidate->addSecondary(-nucleusId(1, 14 + pType), Eout); break; case 1: // photon if (havePhotons) From 6aff01b32300d3a821f100700b0d6a9ee87f167a Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 6 Jun 2014 10:38:37 +0200 Subject: [PATCH 0425/1298] add handling of incoming anti-nucleons in PhotoPionProduction --- src/module/PhotoPionProduction.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 4690ed7a3..1b9efa50d 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -161,6 +161,11 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, double EpA = E / A; double z = candidate->getRedshift(); + // SOPHIA simulates interactions for protons / neutrons + // for anti-protons / neutrons assume charge symmetry and change all + // interaction products from particle <--> anti-particle + int sign = (id > 0)? 1: -1; + // arguments for sophia int nature = 1 - channel; // interacting particle: 0 for proton, 1 for neutron double Ein = EpA / GeV; // energy of in-going nucleon in GeV @@ -181,14 +186,15 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, for (int i = 0; i < nParticles; i++) { // loop over out-going particles double Eout = momentaList[3][i] * GeV; // only the energy is used; could be changed for more detail int pType = particleList[i]; - switch (pType) { case 13: // proton case 14: // neutron - if (A == 1) { // single interacting nucleon + if (A == 1) { + // single interacting nucleon candidate->current.setEnergy(Eout); - candidate->current.setId(nucleusId(1, 14 - pType)); - } else { // interacting nucleon is part of nucleus: it is emitted from the nucleus + candidate->current.setId(sign * nucleusId(1, 14 - pType)); + } else { + // interacting nucleon is part of nucleus: it is emitted from the nucleus candidate->current.setEnergy(E - EpA); candidate->current.setId(nucleusId(A - 1, Z - channel)); candidate->addSecondary(nucleusId(1, 14 - pType), Eout); @@ -197,7 +203,7 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, case -13: // anti-proton case -14: // anti-neutron if (haveAntiNucleons) - candidate->addSecondary(-nucleusId(1, 14 + pType), Eout); + candidate->addSecondary(-sign * nucleusId(1, 14 + pType), Eout); break; case 1: // photon if (havePhotons) @@ -205,27 +211,27 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, break; case 2: // positron if (havePhotons) - candidate->addSecondary(-11, Eout); + candidate->addSecondary(sign * -11, Eout); break; case 3: // electron if (havePhotons) - candidate->addSecondary(11, Eout); + candidate->addSecondary(sign * 11, Eout); break; case 15: // nu_e if (haveNeutrinos) - candidate->addSecondary(12, Eout); + candidate->addSecondary(sign * 12, Eout); break; case 16: // antinu_e if (haveNeutrinos) - candidate->addSecondary(-12, Eout); + candidate->addSecondary(sign * -12, Eout); break; case 17: // nu_muon if (haveNeutrinos) - candidate->addSecondary(14, Eout); + candidate->addSecondary(sign * 14, Eout); break; case 18: // antinu_muon if (haveNeutrinos) - candidate->addSecondary(-14, Eout); + candidate->addSecondary(sign * -14, Eout); break; default: throw std::runtime_error( From 05e2cd98ffffb186f95f3cba673855bd5bd57717 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 6 Jun 2014 12:36:24 +0200 Subject: [PATCH 0426/1298] improve documentation of sophia interface --- libs/sophia/sophia.h | 37 +++++++++++++++--------------- src/module/PhotoPionProduction.cpp | 6 ++--- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/libs/sophia/sophia.h b/libs/sophia/sophia.h index 10f978a95..fe7e1b6dd 100644 --- a/libs/sophia/sophia.h +++ b/libs/sophia/sophia.h @@ -2,35 +2,36 @@ #define _SOPHIA_H extern "C" { -void sophiaevent_(int&, double&, double[][2000], int[], int&, double&, int&, - double&, int&, double[], double[]); +void sophiaevent_(int& channel, double& inputenergy, double momentum[][2000], + int id[], int& n, double& redshift, int& photonbackground, double& maxz, + int&, double[], double[]); } /* The arguments are the following - - nature: 0 -> p, 1 -> n + - channel: 0 -> p, 1 -> n - input energy of nucleon in GeV - list of 4-momenta + masses of output particles (in GeV) - 13 proton - 14 neutron - -13 antiproton - -14 antineutron - 1 photon - 2 e+ - 3 e- - 15 nu_e - 16 antinu_e - 17 nu_muon - 18 antinu_muon - list of output particle ids + 13 proton + 14 neutron + -13 antiproton + -14 antineutron + 1 photon + 2 e+ + 3 e- + 15 nu_e + 16 antinu_e + 17 nu_muon + 18 antinu_muon - number of output particles - redshift - photon background flag: 1 -> CMB, 2 -> IRB Kneiske - (Primack et al. (1999) IRB is outcommented in sophia_interface.f on line 16320 + (Primack et al. (1999) IRB is outcommented in sophia_interface.f on line 16320 - maximum redshift: the photon density of IRB is null above this redshift - - - - - - + - dummy1 + - dummy2 + - dummy3 */ #endif diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 1b9efa50d..dfc21b95e 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -161,7 +161,7 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, double EpA = E / A; double z = candidate->getRedshift(); - // SOPHIA simulates interactions for protons / neutrons + // SOPHIA simulates interactions only for protons / neutrons // for anti-protons / neutrons assume charge symmetry and change all // interaction products from particle <--> anti-particle int sign = (id > 0)? 1: -1; @@ -196,8 +196,8 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, } else { // interacting nucleon is part of nucleus: it is emitted from the nucleus candidate->current.setEnergy(E - EpA); - candidate->current.setId(nucleusId(A - 1, Z - channel)); - candidate->addSecondary(nucleusId(1, 14 - pType), Eout); + candidate->current.setId(sign * nucleusId(A - 1, Z - channel)); + candidate->addSecondary(sign * nucleusId(1, 14 - pType), Eout); } break; case -13: // anti-proton From 61b47fb9d82899852582c456fc9a2567015a6c47 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 6 Jun 2014 15:22:30 +0200 Subject: [PATCH 0427/1298] allow for reloading of interaction rate tables in EPP, PPP and PD --- src/module/ElectronPairProduction.cpp | 4 ++++ src/module/PhotoDisintegration.cpp | 11 +++++++---- src/module/PhotoPionProduction.cpp | 5 +++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index acd6c2883..d80a8b1f1 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -49,6 +49,10 @@ void ElectronPairProduction::initRate(std::string filename) { throw std::runtime_error( "ElectronPairProduction: could not open file " + filename); + // clear previously loaded interaction rates + tabLorentzFactor.clear(); + tabLossRate.clear(); + while (infile.good()) { if (infile.peek() != '#') { double a, b; diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 2102b674c..f15f203f4 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -37,16 +37,19 @@ void PhotoDisintegration::init(PhotonField photonField) { } void PhotoDisintegration::init(std::string filename) { - lgmin = 6; - lgmax = 13.96; - pdTable.resize(27 * 31); - std::ifstream infile(filename.c_str()); if (not infile.good()) throw std::runtime_error( "crpropa::PhotoDisintegration: could not open file " + filename); + lgmin = 6; + lgmax = 13.96; + + // clear previously loaded interaction rates + pdTable.clear(); + pdTable.resize(27 * 31); + std::string line; while (std::getline(infile, line)) { if (line[0] == '#') diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index dfc21b95e..e42a757bb 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -63,6 +63,11 @@ void PhotoPionProduction::init(std::string filename) { throw std::runtime_error( "PhotoPionProduction: could not open file " + filename); + // clear previously loaded tables + energy.clear(); + pRate.clear(); + nRate.clear(); + while (infile.good()) { if (infile.peek() != '#') { double a, b, c; From bf4ea789445c60b297ccb9c0c3727da88e5d4384 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 23 Jun 2014 23:42:33 +0200 Subject: [PATCH 0428/1298] Improve ParticleState documentation --- include/crpropa/ParticleState.h | 40 ++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/include/crpropa/ParticleState.h b/include/crpropa/ParticleState.h index 900686a50..56284f504 100644 --- a/include/crpropa/ParticleState.h +++ b/include/crpropa/ParticleState.h @@ -6,6 +6,7 @@ #include "crpropa/Common.h" #include "crpropa/ParticleID.h" #include "crpropa/ParticleMass.h" +#include "crpropa/UUID.h" namespace crpropa { @@ -20,43 +21,52 @@ namespace crpropa { */ class ParticleState { private: - int id; /*< particle ID (Particle Data Group numbering scheme) */ - double energy; /*< total energy */ - Vector3d position; /*< position vector in comoving coordinates */ - Vector3d direction; /*< unit vector of velocity or momentum */ - - double pmass; /*< particle rest mass */ - double charge; /*< particle charge */ + int id; ///< particle ID (Particle Data Group numbering scheme) + double energy; ///< total energy + Vector3d position; ///< position vector in comoving coordinates + Vector3d direction; ///< unit vector of velocity or momentum + double pmass; ///< particle rest mass + double charge; ///< particle charge public: + /// Constructor: Create a particle at (0,0,0) pointing at (-1,0,0) ParticleState(); - /* Set position in comoving coordinates */ + + /// Set position in comoving coordinates void setPosition(const Vector3d &pos); - /* Get position in comoving coordinates */ + /// Get position in comoving coordinates const Vector3d &getPosition() const; - /* Set direction unit vector. Non unit-vectors are normalized */ + /// Set direction unit vector, non unit-vectors are normalized void setDirection(const Vector3d &dir); + /// Get direction unit vector const Vector3d &getDirection() const; + /// Set energy in [J] void setEnergy(double newEnergy); + /// Get energy in [J] double getEnergy() const; + /// Set particle ID void setId(int); + /// Get particle ID int getId() const; - /* Electrical charge of the particle */ + // ======== Helper methods ======== + + /// Electrical charge of the particle in [A] double getCharge() const; - /* Mass of the particle */ + /// Mass of the particle in [kg] double getMass() const; - /* Set Lorentz factor and modify the particles energy accordingly */ + /// Set Lorentz factor and modify the particle's energy accordingly void setLorentzFactor(double gamma); + /// Get Lorentz factor double getLorentzFactor() const; - /* Velocity: direction times the speed of light */ + /// Velocity: direction times the speed of light in [m/s] Vector3d getVelocity() const; - /* Momentum: direction times energy divided by the speed of light */ + /// Momentum: direction times energy divided by the speed of light [kg m/s] Vector3d getMomentum() const; }; From 7e1864e4443a637a2eb645150cb0658a16c662ae Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 25 Jun 2014 16:51:21 +0200 Subject: [PATCH 0429/1298] EventOutput1D: Save source distance instead of trajectory length (due to rounding errors in the latter) --- include/crpropa/ParticleState.h | 6 +++--- src/module/OutputTXT.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/crpropa/ParticleState.h b/include/crpropa/ParticleState.h index 56284f504..4f7b5c511 100644 --- a/include/crpropa/ParticleState.h +++ b/include/crpropa/ParticleState.h @@ -6,7 +6,6 @@ #include "crpropa/Common.h" #include "crpropa/ParticleID.h" #include "crpropa/ParticleMass.h" -#include "crpropa/UUID.h" namespace crpropa { @@ -15,8 +14,9 @@ namespace crpropa { @brief State of the particle: ID, energy, position, direction The ParticleState defines the state of an ultra-high energy cosmic ray, which - is assumed to be flying at the exact speed of light. The cosmic ray state is - uniquely defined by particle ID, energy and position and direction vector. + is assumed to be travelling at the exact speed of light. + The cosmic ray state is defined by particle ID, energy and position and + direction vector. For faster lookup mass and charge of the particle are stored as members. */ class ParticleState { diff --git a/src/module/OutputTXT.cpp b/src/module/OutputTXT.cpp index f03dacebe..4f12ff996 100644 --- a/src/module/OutputTXT.cpp +++ b/src/module/OutputTXT.cpp @@ -126,7 +126,7 @@ EventOutput1D::EventOutput1D(std::string filename) { fout << "#\n"; fout << "# ID Particle type\n"; fout << "# E Energy [EeV]\n"; - fout << "# D Comoving trajectory length [Mpc]\n"; + fout << "# D Comoving source distance [Mpc]\n"; fout << "# ID0 Initial particle type\n"; fout << "# E0 Initial energy [EeV]\n"; } @@ -146,7 +146,7 @@ void EventOutput1D::process(Candidate *c) const { p += sprintf(buffer + p, "%10i\t", c->current.getId()); p += sprintf(buffer + p, "%8.4f\t", c->current.getEnergy() / EeV); - p += sprintf(buffer + p, "%9.4f\t", c->getTrajectoryLength() / Mpc); + p += sprintf(buffer + p, "%9.4f\t", c->source.getPosition().x / Mpc); p += sprintf(buffer + p, "%10i\t", c->source.getId()); p += sprintf(buffer + p, "%8.4f\n", c->source.getEnergy() / EeV); From ab8c9e376dab3be7333f5fa3892fa80abde135fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Thu, 3 Jul 2014 10:39:36 +0200 Subject: [PATCH 0430/1298] Add initial PhotonPropagation using EleCa --- CMakeLists.txt | 1 + include/crpropa/PhotonPropagation.h | 17 ++++++ src/PhotonPropagation.cpp | 93 +++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 include/crpropa/PhotonPropagation.h create mode 100644 src/PhotonPropagation.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index cf7f8ee51..4fb7cdcb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,6 +141,7 @@ add_library(crpropa SHARED src/Source.cpp src/Common.cpp src/PhotonBackground.cpp + src/PhotonPropagation.cpp src/GridTools.cpp src/XmlExecute.cpp src/module/BreakCondition.cpp diff --git a/include/crpropa/PhotonPropagation.h b/include/crpropa/PhotonPropagation.h new file mode 100644 index 000000000..cfb09231f --- /dev/null +++ b/include/crpropa/PhotonPropagation.h @@ -0,0 +1,17 @@ +#ifndef CRPROPA_PHOTON_PROPAGATION_H +#define CRPROPA_PHOTON_PROPAGATION_H + +#include +#include + +namespace crpropa { + +void EleCaPropagation(const std::string &background, + const std::string &inputfile, std::vector &energy, + std::vector &spectrum); +void EleCaPropagation(const std::string &background, + const std::string &inputfile, const std::string &outputfile); + +} // namespace crpropa + +#endif // CRPROPA_PHOTON_PROPAGATION_H diff --git a/src/PhotonPropagation.cpp b/src/PhotonPropagation.cpp new file mode 100644 index 000000000..144717b92 --- /dev/null +++ b/src/PhotonPropagation.cpp @@ -0,0 +1,93 @@ +#include "crpropa/PhotonPropagation.h" +#include "crpropa/Common.h" + +#include "EleCa/Propagation.h" +#include "EleCa/Particle.h" +#include "EleCa/Common.h" + +#include +#include +#include +#include + +namespace crpropa { + +void EleCaPropagation(const std::string &background, + const std::string &inputfile, std::vector &energy, + std::vector &spectrum) { + std::ifstream infile(inputfile.c_str()); + + const double emin = 16, emax = 22, step = 0.2; + const size_t steps = (emax - emin) / step; + energy.clear(); + energy.resize(steps); + spectrum.resize(steps); + for (size_t i = 0; i < steps; i++) { + energy[i] = 16 + i * step; + spectrum[i] = 0; + } + + if (!infile.good()) + throw std::runtime_error( + "EleCaPropagation: could not open file " + inputfile); + + eleca::Propagation propagation; + propagation.ReadTables(getDataPath("EleCa/eleca.dat")); + propagation.InitBkgArray(background); + + while (infile.good()) { + if (infile.peek() != '#') { + double E, D, pE, iE; + int Id, pId, iId; + infile >> Id >> E >> D >> pId >> pE >> iId >> iE; + if (infile) { + double z = eleca::Mpc2z(D); + eleca::Particle p0(Id, E * 1e18, z); + + // TODO: find a motivated value! + p0.SetB(1e-9); + + std::vector ParticleAtMatrix; + std::vector ParticleAtGround; + ParticleAtMatrix.push_back(p0); + + while (ParticleAtMatrix.size() > 0) { + + eleca::Particle p1 = ParticleAtMatrix.back(); + ParticleAtMatrix.pop_back(); + + if (p1.IsGood()) { + propagation.Propagate(p1, ParticleAtMatrix, + ParticleAtGround); + } + } + + //propagation.WriteOutput(output, p0, ParticleAtGround); + for (int i = 0; i < ParticleAtGround.size(); ++i) { + eleca::Particle &p = ParticleAtGround[i]; + if (p.GetType() != 22) + continue; + size_t idx = (::log10(p.GetEnergy()) - emin) / step; + spectrum.at(idx) += 1; + } + } + } + + infile.ignore(std::numeric_limits::max(), '\n'); + } + infile.close(); +} + +void EleCaPropagation(const std::string &background, + const std::string &inputfile, const std::string &outputfile) { + std::vector energy, spectrum; + EleCaPropagation(background, inputfile, energy, spectrum); + std::ofstream output(outputfile.c_str()); + output << "# E N\n"; + for (size_t i = 0; i < energy.size(); i++) { + output << energy[i] << " " << spectrum[i] << "\n"; + } +} + +} // namespace crpropa + From 9a6cad87bb920082ece16c9a9e8637e715002662 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 4 Jul 2014 10:34:37 +0200 Subject: [PATCH 0431/1298] Change photo-pion production to work with Lorentz factor instead of energy, needs updated interaction rate tables from CRPropa3-data --- include/crpropa/module/PhotoPionProduction.h | 12 ++--- src/module/PhotoPionProduction.cpp | 54 ++++++++++---------- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/include/crpropa/module/PhotoPionProduction.h b/include/crpropa/module/PhotoPionProduction.h index 75ec1bb5a..22fc57a17 100644 --- a/include/crpropa/module/PhotoPionProduction.h +++ b/include/crpropa/module/PhotoPionProduction.h @@ -15,10 +15,10 @@ namespace crpropa { class PhotoPionProduction: public Module { private: PhotonField photonField; - std::vector pRate; // interaction rate in [1/m] for protons - std::vector nRate; // interaction rate in [1/m] for neutrons - std::vector energy; // energy in [J] - double limit; // fraction of mean free path to limit the next step + std::vector tabLorentz; ///< Lorentz factor of nucleus + std::vector tabProtonRate; ///< interaction rate in [1/m] for protons + std::vector tabNeutronRate; ///< interaction rate in [1/m] for neutrons + double limit; ///< fraction of mean free path to limit the next step bool havePhotons; bool haveNeutrinos; bool haveAntiNucleons; @@ -42,10 +42,10 @@ class PhotoPionProduction: public Module { Calculates the loss length E dx/dE in [m]. This is not used in the simulation. @param id PDG particle id - @param energy particle energy [J] + @param gamma Lorentz factor of particle @param z redshift */ - double lossLength(int id, double energy, double z = 0); + double lossLength(int id, double gamma, double z = 0); }; } // namespace crpropa diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index e42a757bb..d9ca2cf12 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -13,8 +13,8 @@ namespace crpropa { -PhotoPionProduction::PhotoPionProduction(PhotonField field, - bool photons, bool neutrinos, bool antiNucleons, double l) { +PhotoPionProduction::PhotoPionProduction(PhotonField field, bool photons, + bool neutrinos, bool antiNucleons, double l) { photonField = field; havePhotons = photons; haveNeutrinos = neutrinos; @@ -49,7 +49,7 @@ void PhotoPionProduction::init() { init(getDataPath("photopion_CMB.txt")); setDescription("PhotoPionProduction: CMB"); } else if (photonField == IRB) { - init(getDataPath("photopion_IRB.txt")); + init(getDataPath("photopion_KneiskeIRB.txt")); setDescription("PhotoPionProduction: IRB"); } else { throw std::runtime_error( @@ -64,23 +64,22 @@ void PhotoPionProduction::init(std::string filename) { "PhotoPionProduction: could not open file " + filename); // clear previously loaded tables - energy.clear(); - pRate.clear(); - nRate.clear(); + tabLorentz.clear(); + tabProtonRate.clear(); + tabNeutronRate.clear(); while (infile.good()) { if (infile.peek() != '#') { double a, b, c; infile >> a >> b >> c; if (infile) { - energy.push_back(a * EeV); - pRate.push_back(b / Mpc); - nRate.push_back(c / Mpc); + tabLorentz.push_back(pow(10, a)); + tabProtonRate.push_back(b / Mpc); + tabNeutronRate.push_back(c / Mpc); } } - infile.ignore(std::numeric_limits < std::streamsize > ::max(), '\n'); + infile.ignore(std::numeric_limits::max(), '\n'); } - infile.close(); } @@ -102,14 +101,10 @@ void PhotoPionProduction::process(Candidate *candidate) const { return; double z = candidate->getRedshift(); - double E = candidate->current.getEnergy(); - int A = massNumber(id); - int Z = chargeNumber(id); - int N = A - Z; - double Eeff = E / A * (1 + z); // effective energy per nucleon + double gamma = (1 + z) * candidate->current.getLorentzFactor(); // check if in tabulated energy range - if (Eeff < energy.front() or (Eeff > energy.back())) + if (gamma < tabLorentz.front() or (gamma > tabLorentz.back())) return; // find interaction with minimum random distance @@ -121,9 +116,13 @@ void PhotoPionProduction::process(Candidate *candidate) const { // comological scaling of interaction distance (comoving) double scaling = pow(1 + z, 2) * photonFieldScaling(photonField, z); + int A = massNumber(id); + int Z = chargeNumber(id); + int N = A - Z; + // check for interaction on protons if (Z > 0) { - double rate = interpolate(Eeff, energy, pRate); + double rate = interpolate(gamma, tabLorentz, tabProtonRate); rate *= nucleiModification(A, Z); rate *= scaling; totalRate += rate; @@ -133,7 +132,7 @@ void PhotoPionProduction::process(Candidate *candidate) const { // check for interaction on neutrons if (N > 0) { - double rate = interpolate(Eeff, energy, nRate); + double rate = interpolate(gamma, tabLorentz, tabNeutronRate); rate *= nucleiModification(A, N); rate *= scaling; totalRate += rate; @@ -144,7 +143,7 @@ void PhotoPionProduction::process(Candidate *candidate) const { } } - // check if interaction doesn't happen + // check if interaction does not happen if (step < randDistance) { candidate->limitNextStep(limit / totalRate); return; @@ -169,7 +168,7 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, // SOPHIA simulates interactions only for protons / neutrons // for anti-protons / neutrons assume charge symmetry and change all // interaction products from particle <--> anti-particle - int sign = (id > 0)? 1: -1; + int sign = (id > 0) ? 1 : -1; // arguments for sophia int nature = 1 - channel; // interacting particle: 0 for proton, 1 for neutron @@ -246,20 +245,22 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, } } -double PhotoPionProduction::lossLength(int id, double E, double z) { +double PhotoPionProduction::lossLength(int id, double gamma, double z) { int A = massNumber(id); int Z = chargeNumber(id); int N = A - Z; - double Eeff = E / A * (1 + z); - if ((Eeff < energy.front()) or (Eeff > energy.back())) + gamma *= (1 + z); // cosmological scaling of photon energy + if (gamma < tabLorentz.front() or (gamma > tabLorentz.back())) return std::numeric_limits::max(); double lossRate = 0; if (Z > 0) - lossRate += interpolate(Eeff, energy, pRate) * nucleiModification(A, Z); + lossRate += interpolate(gamma, tabLorentz, tabProtonRate) + * nucleiModification(A, Z); if (N > 0) - lossRate += interpolate(Eeff, energy, nRate) * nucleiModification(N, Z); + lossRate += interpolate(gamma, tabLorentz, tabProtonRate) + * nucleiModification(A, N); // protons / neutrons keep as energy the fraction of mass to delta-resonance mass // nuclei approximately lose the energy that the interacting nucleon is carrying @@ -268,6 +269,7 @@ double PhotoPionProduction::lossLength(int id, double E, double z) { // cosmological scaling of photon density lossRate *= pow(1 + z, 3) * photonFieldScaling(photonField, z); + return 1. / lossRate; } From 8edadfea3b7074c7e4accbaa0d053c4c53c3df72 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 8 Jul 2014 09:57:09 +0200 Subject: [PATCH 0432/1298] Update readme --- README.md | 73 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index c40df251b..3218bca70 100644 --- a/README.md +++ b/README.md @@ -5,47 +5,67 @@ This is the development version of [CRPropa](https://crpropa.desy.de/Main_Page). It features a very flexible setup of simulation, support for specialized extragalactic magnetic fields, galactic lensing, python - steering and parallelization. ## Install from source -1. Download the data repository +1. Download the source ``` -cd CRPropa3 -git clone https://github.com/CRPropa/CRPropa3-data.git data +git clone https://github.com/CRPropa/CRPropa3.git ``` -2. CRPropa uses CMAKE to configure. From the build directory call ccmake or cmake +2. Download the data repository +``` +git clone https://github.com/CRPropa/CRPropa3-data.git CRPropa3/data +``` +3. CRPropa uses CMAKE to configure. From the build directory call ccmake or cmake. See the next section for a list of configuration flags ``` cd build ccmake .. ``` -3. Afterward configuring run make and make install as usual +4. After the configuration run make and make install as usual ``` make make install ``` -The install path can be set with -DCMAKE_INSTALL_PREFIX=/my/path or with the option browser when using ccmake. +#### CMake flags +We recommend using ccmake to view and set the options through the user interface. +When using cmake, options can be set by adding flags to the cmake command, e.g. ``cmake -DENABLE_PYTHON=ON ..`` + ++ Set the install path +```-DCMAKE_INSTALL_PREFIX=/my/install/path``` ++ Enable OpenMP +```-DENABLE_OPENMP=ON``` ++ Enable Python +```-DENABLE_PYTHON=ON``` ++ Enable ROOT +```-DENABLE_ROOT=ON``` ++ Enable FFTW3 +```-DENABLE_FFTW3F=ON``` ++ Enable testing with googletest +```-DENABLE_TESTING=ON``` ++ Additional flags for Intel compiler +``` +-DCMAKE_SHARED_LINKER_FLAGS="-lifcore" +-DCMAKE_Fortran_COMPILER=ifort +``` -Notes for Intel Compiler: -use -DCMAKE_SHARED_LINKER_FLAGS="-lifcore" -DCMAKE_Fortran_COMPILER=ifort +#### Required dependencies ++ C++ Compiler ++ Fortran Compiler: to compile SOPHIA #### Provided dependencies -+ SOPHIA - + for photo-hadronic interactions -+ googletest - + for unit-tests ++ SOPHIA: photo-hadronic interactions ++ EleCa and dint: electromagnetic cascades ++ googletest: unit-testing ++ HepPID: particle ID library ++ kiss: small tool collection ++ pugixml: for xml steering #### Optional dependencies -+ Python and SWIG - + to use CRPropa from Python - + tested for > Python 2.7 - + tested for > SWIG 2.0 -+ FFTW3F - + for turbulent magnetic field grids - + CRPropa needs the FFTW3 library compiled with the single precision option -+ Gadget - + Magnetic fields for large scale structure data -+ OpenMP - + for shared memory parallelization -+ googleperftools - + for performance optimizations regarding shared memory parallelization ++ Python and SWIG: to use CRPropa from python (tested for > Python 2.7 and > SWIG 2.0) ++ ROOT: for ROOT output ++ FFTW3: for turbulent magnetic field grids (FFTW3 with single precision is needed) ++ Gadget: magnetic fields for large scale structure data ++ OpenMP: for shared memory parallelization ++ googleperftools: for performance optimizations regarding shared memory parallelization ++ muparser: to define the source spectrum through a mathematical formula ## Getting started @@ -62,7 +82,8 @@ For a 1D simulation try m.add(PhotoPionProduction(IRB)) m.add(PhotoDisintegration(CMB)) m.add(PhotoDisintegration(IRB)) - m.add(ElectronPairProduction(CMB_IRB)) + m.add(ElectronPairProduction(CMB)) + m.add(ElectronPairProduction(IRB)) m.add(NuclearDecay()) m.add(MinimumEnergy(1 * EeV)) m.add(Observer1D()) From 605672bc30cc62c61fac098e56c187a5079da2f9 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 8 Jul 2014 09:58:59 +0200 Subject: [PATCH 0433/1298] fix --- README.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 3218bca70..4fd8e92c2 100644 --- a/README.md +++ b/README.md @@ -6,27 +6,27 @@ It features a very flexible setup of simulation, support for specialized extraga ## Install from source 1. Download the source -``` -git clone https://github.com/CRPropa/CRPropa3.git -``` + ``` + git clone https://github.com/CRPropa/CRPropa3.git + ``` 2. Download the data repository -``` -git clone https://github.com/CRPropa/CRPropa3-data.git CRPropa3/data -``` + ``` + git clone https://github.com/CRPropa/CRPropa3-data.git CRPropa3/data + ``` 3. CRPropa uses CMAKE to configure. From the build directory call ccmake or cmake. See the next section for a list of configuration flags -``` -cd build -ccmake .. -``` + ``` + cd build + ccmake .. + ``` 4. After the configuration run make and make install as usual -``` -make -make install -``` + ``` + make + make install + ``` #### CMake flags We recommend using ccmake to view and set the options through the user interface. -When using cmake, options can be set by adding flags to the cmake command, e.g. ``cmake -DENABLE_PYTHON=ON ..`` +When using cmake, options can be set by adding flags to the cmake command, e.g. ```cmake -DENABLE_PYTHON=ON ..``` + Set the install path ```-DCMAKE_INSTALL_PREFIX=/my/install/path``` From 4558f5852fa71643280b93dea13c59c9bdabb7b5 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 10 Jul 2014 16:35:05 +0200 Subject: [PATCH 0434/1298] ElectronPairProduction: limit next step size to fraction of energy loss length (default: 10%) --- include/crpropa/module/ElectronPairProduction.h | 8 +++++--- src/module/ElectronPairProduction.cpp | 7 +++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/crpropa/module/ElectronPairProduction.h b/include/crpropa/module/ElectronPairProduction.h index 6b91f152a..d8d5a301d 100644 --- a/include/crpropa/module/ElectronPairProduction.h +++ b/include/crpropa/module/ElectronPairProduction.h @@ -11,8 +11,9 @@ namespace crpropa { @brief Electron-pair production of charged nuclei with background photons. This module simulates electron-pair production as a continuous energy loss.\n - Several photon fields can be selected. - Secondary electrons are not created. + Several photon fields can be selected.\n + The production of secondary e+/e- pairs and photons can by activated.\n + By default, the module limits the step size to 10% of the energy loss length of the particle. */ class ElectronPairProduction: public Module { private: @@ -25,11 +26,12 @@ class ElectronPairProduction: public Module { std::vector tabE; /*< tabulated proton energy in [J], 70 steps from 10^15 - 10^22 eV */ std::vector tabEe; /*< edges of electron energy bins in [J], 171 steps from 10^6.95 - 10^23.95 eV */ std::vector tabEeWidth; /*< electron energy bin width in [J], 170 steps */ + double limit; ///< fraction of energy loss length to limit the next step bool haveElectrons; public: ElectronPairProduction(PhotonField photonField = CMB, bool haveElectrons = - false); + false, double limit = 0.1); void setPhotonField(PhotonField photonField); void setHaveElectrons(bool haveElectrons); void init(); diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index d80a8b1f1..583bd4820 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -9,9 +9,10 @@ namespace crpropa { ElectronPairProduction::ElectronPairProduction(PhotonField photonField, - bool haveElectrons) { + bool haveElectrons, double limit) { this->photonField = photonField; this->haveElectrons = haveElectrons; + this->limit = limit; init(); } @@ -161,13 +162,15 @@ void ElectronPairProduction::process(Candidate *c) const { double lf = c->current.getLorentzFactor(); double z = c->getRedshift(); + double losslen = lossLength(id, lf, z); // energy loss length double step = c->getCurrentStep() / (1 + z); // step size in local frame - double loss = step / lossLength(id, lf, z); + double loss = step / losslen; // relative energy loss if (haveElectrons) addElectrons(c, loss); c->current.setLorentzFactor(lf * (1 - loss)); + c->limitNextStep(limit * losslen); } } // namespace crpropa From 4590cf62701230cd33b4e49f769589e20b987780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Tue, 15 Jul 2014 10:43:58 +0200 Subject: [PATCH 0435/1298] fix eleca isnan, and getType --- libs/EleCa/src/EnergyLoss.cpp | 2 +- libs/EleCa/src/Propagation.cpp | 2 +- libs/EleCa/src/XLoss_CBR.h | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/EleCa/src/EnergyLoss.cpp b/libs/EleCa/src/EnergyLoss.cpp index 12d58006d..03ae039ca 100644 --- a/libs/EleCa/src/EnergyLoss.cpp +++ b/libs/EleCa/src/EnergyLoss.cpp @@ -173,7 +173,7 @@ double EnergyLoss1D(double Energy, double z0, double zfin, double B) { FLAG_PROPAG = 0; } - if (isnan(Energy)) + if (std::isnan(Energy)) return 0; } diff --git a/libs/EleCa/src/Propagation.cpp b/libs/EleCa/src/Propagation.cpp index a053ce9b0..1d48324ce 100644 --- a/libs/EleCa/src/Propagation.cpp +++ b/libs/EleCa/src/Propagation.cpp @@ -447,7 +447,7 @@ void Propagation::Propagate(Particle &curr_particle, double zin = curr_particle.Getz(); double Ein = curr_particle.GetEnergy(); - int type = curr_particle.Getz(); + int type = curr_particle.GetType(); int wi_last = curr_particle.GetWeigth(); diff --git a/libs/EleCa/src/XLoss_CBR.h b/libs/EleCa/src/XLoss_CBR.h index 61b0d2e06..3945a09ba 100644 --- a/libs/EleCa/src/XLoss_CBR.h +++ b/libs/EleCa/src/XLoss_CBR.h @@ -95,7 +95,7 @@ double CMBR(double eps) { tmp = 0; } - if (isnan(tmp)) + if (std::isnan(tmp)) tmp = 0; return tmp; @@ -116,7 +116,7 @@ double CIBR(double eps) { tmp = 0; } - if (isnan(tmp)) + if (std::isnan(tmp)) tmp = 0; return tmp; @@ -156,7 +156,7 @@ double CIOBR(double eps) { tmp = 0; } - if (isnan(tmp)) + if (std::isnan(tmp)) tmp = 0; return tmp; @@ -172,7 +172,7 @@ double COBR(double eps) { tmp = 0; } - if (isnan(tmp)) + if (std::isnan(tmp)) tmp = 0; return tmp; From 202a1c710430d451b5a948e543d51205e400f5cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Tue, 15 Jul 2014 10:59:40 +0200 Subject: [PATCH 0436/1298] remove as-needed linker flag on MacOS --- CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4fb7cdcb5..48a08e83e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,11 +8,12 @@ set(CRPROPA_EXTRA_INCLUDES) set(CRPROPA_EXTRA_LIBRARIES) set(CRPROPA_SWIG_DEFINES) -if(CMAKE_COMPILER_IS_GNUCXX) +if(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--as-needed") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--as-needed") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") -endif(CMAKE_COMPILER_IS_GNUCXX) + MESSAGE(STATUS "Use --as-needed linker flags!") +endif(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) # ---------------------------------------------------------------------------- # Dependencies From b875a6dc070bc2ceb716f924f39ad791151542c6 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 16 Jul 2014 10:30:56 +0200 Subject: [PATCH 0437/1298] loadGrid: test if field grid and file size match --- src/GridTools.cpp | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/GridTools.cpp b/src/GridTools.cpp index cd69515e8..3da253f0c 100644 --- a/src/GridTools.cpp +++ b/src/GridTools.cpp @@ -200,6 +200,19 @@ void loadGrid(ref_ptr grid, std::string filename, double c) { ss << "load VectorGrid: " << filename << " not found"; throw std::runtime_error(ss.str()); } + + // get length of file and compare to size of grid + fin.seekg(0, fin.end); + int length = fin.tellg() / sizeof(float); + fin.seekg (0, fin.beg); + + size_t nx = grid->getNx(); + size_t ny = grid->getNy(); + size_t nz = grid->getNz(); + + if (length != (3 * nx * ny * nz)) + throw std::runtime_error("loadGrid: file and grid size do not match"); + for (int ix = 0; ix < grid->getNx(); ix++) { for (int iy = 0; iy < grid->getNy(); iy++) { for (int iz = 0; iz < grid->getNz(); iz++) { @@ -221,9 +234,22 @@ void loadGrid(ref_ptr grid, std::string filename, double c) { ss << "load ScalarGrid: " << filename << " not found"; throw std::runtime_error(ss.str()); } - for (int ix = 0; ix < grid->getNx(); ix++) { - for (int iy = 0; iy < grid->getNy(); iy++) { - for (int iz = 0; iz < grid->getNz(); iz++) { + + // get length of file and compare to size of grid + fin.seekg(0, fin.end); + int length = fin.tellg() / sizeof(float); + fin.seekg (0, fin.beg); + + size_t nx = grid->getNx(); + size_t ny = grid->getNy(); + size_t nz = grid->getNz(); + + if (length != (nx * ny * nz)) + throw std::runtime_error("loadGrid: file and grid size do not match"); + + for (int ix = 0; ix < nx; ix++) { + for (int iy = 0; iy < ny; iy++) { + for (int iz = 0; iz < nz; iz++) { float &b = grid->get(ix, iy, iz); fin.read((char*) &b, sizeof(float)); b *= c; From 7761e2a99db61f24488f24df295b843edc6324cd Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 16 Jul 2014 11:20:29 +0200 Subject: [PATCH 0438/1298] GridTools: add scaling and evaluation of mean/rms for ScalarGrids --- include/crpropa/GridTools.h | 9 ++++--- src/GridTools.cpp | 51 +++++++++++++++++++++++++++++-------- 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/include/crpropa/GridTools.h b/include/crpropa/GridTools.h index 316547c17..5d0b7a62a 100644 --- a/include/crpropa/GridTools.h +++ b/include/crpropa/GridTools.h @@ -6,16 +6,19 @@ namespace crpropa { -/** Evaluate the mean field vector of all grid points. */ +/** Evaluate the mean vector of all grid points. */ Vector3f meanFieldVector(ref_ptr grid); -/** Evaluate the mean field strength of all grid points. */ +/** Evaluate the mean of all grid points. */ +double meanFieldStrength(ref_ptr grid); double meanFieldStrength(ref_ptr grid); -/** Evaluate the RMS field strength of all grid points. */ +/** Evaluate the RMS of all grid points. */ +double rmsFieldStrength(ref_ptr grid); double rmsFieldStrength(ref_ptr grid); /** Multiply all grid values by a given factor. */ +void scaleGrid(ref_ptr grid, double a); void scaleGrid(ref_ptr grid, double a); #ifdef CRPROPA_HAVE_FFTW3F diff --git a/src/GridTools.cpp b/src/GridTools.cpp index 3da253f0c..3f9cc3b87 100644 --- a/src/GridTools.cpp +++ b/src/GridTools.cpp @@ -6,6 +6,20 @@ namespace crpropa { +void scaleGrid(ref_ptr grid, double a) { + for (int ix = 0; ix < grid->getNx(); ix++) + for (int iy = 0; iy < grid->getNy(); iy++) + for (int iz = 0; iz < grid->getNz(); iz++) + grid->get(ix, iy, iz) *= a; +} + +void scaleGrid(ref_ptr grid, double a) { + for (int ix = 0; ix < grid->getNx(); ix++) + for (int iy = 0; iy < grid->getNy(); iy++) + for (int iz = 0; iz < grid->getNz(); iz++) + grid->get(ix, iy, iz) *= a; +} + Vector3f meanFieldVector(ref_ptr grid) { size_t Nx = grid->getNx(); size_t Ny = grid->getNy(); @@ -30,23 +44,40 @@ double meanFieldStrength(ref_ptr grid) { return mean / Nx / Ny / Nz; } +double meanFieldStrength(ref_ptr grid) { + size_t Nx = grid->getNx(); + size_t Ny = grid->getNy(); + size_t Nz = grid->getNz(); + double mean = 0; + for (int ix = 0; ix < Nx; ix++) + for (int iy = 0; iy < Ny; iy++) + for (int iz = 0; iz < Nz; iz++) + mean += grid->get(ix, iy, iz); + return mean / Nx / Ny / Nz; +} + double rmsFieldStrength(ref_ptr grid) { size_t Nx = grid->getNx(); size_t Ny = grid->getNy(); size_t Nz = grid->getNz(); - double sumB2 = 0; + double sumV2 = 0; for (int ix = 0; ix < Nx; ix++) for (int iy = 0; iy < Ny; iy++) for (int iz = 0; iz < Nz; iz++) - sumB2 += grid->get(ix, iy, iz).getR2(); - return std::sqrt(sumB2 / Nx / Ny / Nz); + sumV2 += grid->get(ix, iy, iz).getR2(); + return std::sqrt(sumV2 / Nx / Ny / Nz); } -void scaleGrid(ref_ptr grid, double a) { - for (int ix = 0; ix < grid->getNx(); ix++) - for (int iy = 0; iy < grid->getNy(); iy++) - for (int iz = 0; iz < grid->getNz(); iz++) - grid->get(ix, iy, iz) *= a; +double rmsFieldStrength(ref_ptr grid) { + size_t Nx = grid->getNx(); + size_t Ny = grid->getNy(); + size_t Nz = grid->getNz(); + double sumV2 = 0; + for (int ix = 0; ix < Nx; ix++) + for (int iy = 0; iy < Ny; iy++) + for (int iz = 0; iz < Nz; iz++) + sumV2 += pow(grid->get(ix, iy, iz), 2); + return std::sqrt(sumV2 / Nx / Ny / Nz); } #ifdef CRPROPA_HAVE_FFTW3F @@ -203,7 +234,7 @@ void loadGrid(ref_ptr grid, std::string filename, double c) { // get length of file and compare to size of grid fin.seekg(0, fin.end); - int length = fin.tellg() / sizeof(float); + size_t length = fin.tellg() / sizeof(float); fin.seekg (0, fin.beg); size_t nx = grid->getNx(); @@ -237,7 +268,7 @@ void loadGrid(ref_ptr grid, std::string filename, double c) { // get length of file and compare to size of grid fin.seekg(0, fin.end); - int length = fin.tellg() / sizeof(float); + size_t length = fin.tellg() / sizeof(float); fin.seekg (0, fin.beg); size_t nx = grid->getNx(); From 528432a50ba360a3d6f5b9feb8aed5b83420ea30 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 17 Jul 2014 10:01:52 +0200 Subject: [PATCH 0439/1298] add unit test for propagation in zero fields --- test/testPropagation.cpp | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/test/testPropagation.cpp b/test/testPropagation.cpp index 4bd54956b..52af43d94 100644 --- a/test/testPropagation.cpp +++ b/test/testPropagation.cpp @@ -30,9 +30,33 @@ TEST(testSimplePropagation, step) { EXPECT_EQ(Vector3d(0, 1, 0), c.current.getDirection()); } + +TEST(testPropagationCK, zeroField) { + PropagationCK propa(new UniformMagneticField(Vector3d(0, 0, 0))); + + double minStep = 0.1 * kpc; + propa.setMinimumStep(minStep); + + ParticleState p; + p.setId(nucleusId(1, 1)); + p.setEnergy(100 * EeV); + p.setPosition(Vector3d(0, 0, 0)); + p.setDirection(Vector3d(0, 1, 0)); + Candidate c(p); + c.setNextStep(0); + + propa.process(&c); + + EXPECT_DOUBLE_EQ(minStep, c.getCurrentStep()); // perform minimum step + EXPECT_DOUBLE_EQ(5 * minStep, c.getNextStep()); // acceleration by factor 5 +} + TEST(testPropagationCK, proton) { PropagationCK propa(new UniformMagneticField(Vector3d(0, 0, 1 * nG))); + double minStep = 0.1 * kpc; + propa.setMinimumStep(minStep); + ParticleState p; p.setId(nucleusId(1, 1)); p.setEnergy(100 * EeV); @@ -43,8 +67,8 @@ TEST(testPropagationCK, proton) { propa.process(&c); - EXPECT_DOUBLE_EQ(0.1 * kpc, c.getCurrentStep()); - EXPECT_DOUBLE_EQ(0.5 * kpc, c.getNextStep()); + EXPECT_DOUBLE_EQ(minStep, c.getCurrentStep()); // perform minimum step + EXPECT_DOUBLE_EQ(5 * minStep, c.getNextStep()); // acceleration by factor 5 } TEST(testPropagationCK, neutron) { From d92ef721d1fa70cea838074e5761073e6dfa2817 Mon Sep 17 00:00:00 2001 From: rafaelab <8rafael@gmail.com> Date: Sun, 20 Jul 2014 21:06:03 +0200 Subject: [PATCH 0440/1298] compiling with user defined python --- python/Python.cmake | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/python/Python.cmake b/python/Python.cmake index c7a1f7b58..748c723c3 100644 --- a/python/Python.cmake +++ b/python/Python.cmake @@ -29,19 +29,25 @@ IF(APPLE) STRING(REGEX REPLACE ".*MacOSX([0-9]+)[.]([0-9]+)[.]sdk" "\\2" OSX_SDK_MINOR_VERSION "${CMAKE_OSX_SYSROOT}" ) # MESSAGE("Found OS X SDK minor version: ${OSX_SDK_MINOR_VERSION}") - IF(OSX_SDK_MINOR_VERSION GREATER 8) - SET(OSX_USE_PYTHON_FRAMEWORK "False") - MESSAGE(STATUS "Running on Mac OS X >= 10.9: Linking to Python in UNIX default way") - ELSE(OSX_SDK_MINOR_VERSION GREATER 8) - MESSAGE(STATUS "Running on Mac OS X < 10.9: Linking to Python as framework") - SET(OSX_USE_PYTHON_FRAMEWORK "True") - - INCLUDE(CMakeFindFrameworks) - # Search for the python framework on Apple. - MESSAGE(INFO "Looking for python framework as on apple system" ) - CMAKE_FIND_FRAMEWORKS(Python) - SET (PYTHON_LIBRARIES "-framework Python" CACHE FILEPATH "Python Framework" FORCE) - ENDIF(OSX_SDK_MINOR_VERSION GREATER 8) + IF (PYTHON_LIBRARIES) + SET(OSX_USE_PYTHON_FRAMEWORK "False") + MESSAGE(STATUS "Using user provided Python library: " ${PYTHON_LIBRARIES} ) + + ELSE(PYTHON_LIBRARIES) + IF(OSX_SDK_MINOR_VERSION GREATER 8) + SET(OSX_USE_PYTHON_FRAMEWORK "False") + MESSAGE(STATUS "Running on Mac OS X >= 10.9: Linking to Python in UNIX default way") + ELSE(OSX_SDK_MINOR_VERSION GREATER 8) + MESSAGE(STATUS "Running on Mac OS X < 10.9: Linking to Python as framework") + SET(OSX_USE_PYTHON_FRAMEWORK "True") + + INCLUDE(CMakeFindFrameworks) + # Search for the python framework on Apple. + MESSAGE(INFO "Looking for python framework as on apple system" ) + CMAKE_FIND_FRAMEWORKS(Python) + SET (PYTHON_LIBRARIES "-framework Python" CACHE FILEPATH "Python Framework" FORCE) + ENDIF(OSX_SDK_MINOR_VERSION GREATER 8) + ENDIF(PYTHON_LIBRARIES) ENDIF(APPLE) @@ -61,13 +67,13 @@ IF (MINGW) ) ENDIF(MINGW) -IF(NOT OSX_USE_PYTHON_FRAMEWORK AND NOT MSVC AND NOT MINGW) +IF(NOT OSX_USE_PYTHON_FRAMEWORK AND NOT PYTHON_LIBRARIES AND NOT MSVC AND NOT MINGW) execute_process( COMMAND ${PYTHON_EXECUTABLE} -c "import sys; from distutils import sysconfig; import os; libname = sysconfig.get_config_var('LDLIBRARY'); libdir = sysconfig.get_config_var('LIBPL'); lib = os.path.join(libdir,libname); out = lib if os.path.exists(lib) else os.path.join(libdir, sysconfig.get_config_var('LIBRARY')); sys.stdout.write(out);" OUTPUT_VARIABLE PYTHON_LIBRARIES OUTPUT_STRIP_TRAILING_WHITESPACE ) -ENDIF(NOT OSX_USE_PYTHON_FRAMEWORK AND NOT MSVC AND NOT MINGW) +ENDIF(NOT OSX_USE_PYTHON_FRAMEWORK AND NOT PYTHON_LIBRARIES AND NOT MSVC AND NOT MINGW) #find the site package destinaton execute_process( From be5bac279c79f1d250417d058b0c3cfdcd50b370 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 21 Jul 2014 22:19:15 +0200 Subject: [PATCH 0441/1298] CMakeLists: replace src-list with GLOB expression --- CMakeLists.txt | 146 +++++++++++++++++++------------------------------ 1 file changed, 57 insertions(+), 89 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 48a08e83e..5ff599cee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ if(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--as-needed") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--as-needed") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") - MESSAGE(STATUS "Use --as-needed linker flags!") + message(STATUS "Use --as-needed linker flags!") endif(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) # ---------------------------------------------------------------------------- @@ -25,7 +25,7 @@ if(ENABLE_TESTING) add_subdirectory(libs/gtest) if(APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_USE_OWN_TR1_TUPLE=1") - endif(APPLE) + endif(APPLE) endif(ENABLE_TESTING) # kiss (provided) @@ -62,58 +62,58 @@ list(APPEND CRPROPA_EXTRA_INCLUDES libs/EleCa/include) option(ENABLE_OPENMP "OpenMP for multithreading" ON) if(ENABLE_OPENMP) include(FindOpenMP) - if(OPENMP_FOUND) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") - endif(OPENMP_FOUND) + if(OPENMP_FOUND) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") + endif(OPENMP_FOUND) endif(ENABLE_OPENMP) # fftw3f (optional for turbulent magnetic fields) option(ENABLE_FFTW3F "FFTW3F to create turbulent fields" ON) if(ENABLE_FFTW3F) - find_package(FFTW3F) - if(FFTW3F_FOUND) - list(APPEND CRPROPA_EXTRA_INCLUDES ${FFTW3F_INCLUDE_DIR}) - list(APPEND CRPROPA_EXTRA_LIBRARIES ${FFTW3F_LIBRARY}) - add_definitions(-DCRPROPA_HAVE_FFTW3F) - list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_FFTW3F) - endif(FFTW3F_FOUND) + find_package(FFTW3F) + if(FFTW3F_FOUND) + list(APPEND CRPROPA_EXTRA_INCLUDES ${FFTW3F_INCLUDE_DIR}) + list(APPEND CRPROPA_EXTRA_LIBRARIES ${FFTW3F_LIBRARY}) + add_definitions(-DCRPROPA_HAVE_FFTW3F) + list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_FFTW3F) + endif(FFTW3F_FOUND) endif(ENABLE_FFTW3F) # Quimby (optional for SPH magnetic fields) find_package(Quimby) if(QUIMBY_FOUND) - list(APPEND CRPROPA_EXTRA_INCLUDES ${QUIMBY_INCLUDE_DIR}) - list(APPEND CRPROPA_EXTRA_LIBRARIES ${QUIMBY_LIBRARY}) - add_definitions (-DCRPROPA_HAVE_QUIMBY) - list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_QUIMBY) - list(APPEND CRPROPA_SWIG_DEFINES -I${QUIMBY_INCLUDE_DIR}/../share/quimby) - list(APPEND CRPROPA_SWIG_DEFINES -I${QUIMBY_INCLUDE_DIR}) + list(APPEND CRPROPA_EXTRA_INCLUDES ${QUIMBY_INCLUDE_DIR}) + list(APPEND CRPROPA_EXTRA_LIBRARIES ${QUIMBY_LIBRARY}) + add_definitions (-DCRPROPA_HAVE_QUIMBY) + list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_QUIMBY) + list(APPEND CRPROPA_SWIG_DEFINES -I${QUIMBY_INCLUDE_DIR}/../share/quimby) + list(APPEND CRPROPA_SWIG_DEFINES -I${QUIMBY_INCLUDE_DIR}) endif(QUIMBY_FOUND) # ROOT (optional for ROOT output) option(ENABLE_ROOT "ROOT Output" ON) if(ENABLE_ROOT) - find_package(ROOT) - if(ROOT_FOUND) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ROOT_CFLAGS}") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${ROOT_LIBS}") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${ROOT_LIBS}") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") - add_definitions(-DCRPROPA_HAVE_ROOT) - list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_ROOT) + find_package(ROOT) + if(ROOT_FOUND) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ROOT_CFLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${ROOT_LIBS}") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${ROOT_LIBS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") + add_definitions(-DCRPROPA_HAVE_ROOT) + list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_ROOT) list(APPEND CRPROPA_EXTRA_LIBRARIES Core RIO Tree) - endif(ROOT_FOUND) + endif(ROOT_FOUND) endif(ENABLE_ROOT) find_package(muParser) if(MUPARSER_FOUND) - list(APPEND CRPROPA_EXTRA_INCLUDES ${MUPARSER_INCLUDE_DIR}) - list(APPEND CRPROPA_EXTRA_LIBRARIES ${MUPARSER_LIBRARY}) - add_definitions (-DCRPROPA_HAVE_MUPARSER) - list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_MUPARSER) - list(APPEND CRPROPA_SWIG_DEFINES -I${MUPARSER_INCLUDE_DIR}) + list(APPEND CRPROPA_EXTRA_INCLUDES ${MUPARSER_INCLUDE_DIR}) + list(APPEND CRPROPA_EXTRA_LIBRARIES ${MUPARSER_LIBRARY}) + add_definitions (-DCRPROPA_HAVE_MUPARSER) + list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_MUPARSER) + list(APPEND CRPROPA_SWIG_DEFINES -I${MUPARSER_INCLUDE_DIR}) endif(MUPARSER_FOUND) @@ -121,54 +121,21 @@ endif(MUPARSER_FOUND) find_package(GooglePerfTools) set(TCMALLOC) if(GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) - set(TCMALLOC ${TCMALLOC_LIBRARY}) - list(APPEND CRPROPA_EXTRA_LIBRARIES profiler) + set(TCMALLOC ${TCMALLOC_LIBRARY}) + list(APPEND CRPROPA_EXTRA_LIBRARIES profiler) endif(GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) # ---------------------------------------------------------------------------- # Library and Binary # ---------------------------------------------------------------------------- include_directories(include ${CRPROPA_EXTRA_INCLUDES}) +file(GLOB_RECURSE + CRPROPA_SOURCES + RELATIVE ${CMAKE_SOURCE_DIR} + "${CMAKE_SOURCE_DIR}/src/*.cpp") add_library(crpropa SHARED - src/Random.cpp - src/Clock.cpp - src/ModuleList.cpp - src/Module.cpp - src/Candidate.cpp - src/ParticleState.cpp - src/ParticleID.cpp - src/ParticleMass.cpp - src/Cosmology.cpp - src/Source.cpp - src/Common.cpp - src/PhotonBackground.cpp - src/PhotonPropagation.cpp - src/GridTools.cpp - src/XmlExecute.cpp - src/module/BreakCondition.cpp - src/module/Boundary.cpp - src/module/Observer.cpp - src/module/SimplePropagation.cpp - src/module/PropagationCK.cpp - src/module/ElectronPairProduction.cpp - src/module/NuclearDecay.cpp - src/module/PhotoPionProduction.cpp - src/module/PhotoDisintegration.cpp - src/module/Redshift.cpp - src/module/OutputTXT.cpp - src/module/OutputShell.cpp - src/module/OutputROOT.cpp - src/module/OutputCRPropa2.cpp - src/module/PhotonOutput1D.cpp - src/module/PhotonDINT.cpp - src/module/PhotonDINT1D.cpp - src/module/PhotonEleCa.cpp - src/module/Tools.cpp - src/magneticField/MagneticField.cpp - src/magneticField/MagneticFieldGrid.cpp - src/magneticField/TurbulentMagneticField.cpp - src/magneticField/JF12Field.cpp - ${CRPROPA_EXTRA_SOURCES} + ${CRPROPA_SOURCES} + ${CRPROPA_EXTRA_SOURCES} ) target_link_libraries(crpropa ${CRPROPA_EXTRA_LIBRARIES}) @@ -188,15 +155,15 @@ install(DIRECTORY data/ DESTINATION share/crpropa/ PATTERN ".git" EXCLUDE) # Testing # ---------------------------------------------------------------------------- if(ENABLE_TESTING) - enable_testing() + enable_testing() add_executable(testCore test/testCore.cpp) target_link_libraries(testCore crpropa gtest gtest_main pthread) add_test(testCore testCore) - + add_executable(testVector3 test/testVector3.cpp) target_link_libraries(testVector3 crpropa gtest gtest_main pthread) add_test(testVector3 testVector3) - + add_executable(testModuleList test/testModuleList.cpp) target_link_libraries(testModuleList crpropa gtest gtest_main pthread) add_test(testModuleList testModuleList) @@ -208,19 +175,19 @@ if(ENABLE_TESTING) add_executable(testPropagation test/testPropagation.cpp) target_link_libraries(testPropagation crpropa gtest gtest_main pthread) add_test(testPropagation testPropagation) - + add_executable(testBreakCondition test/testBreakCondition.cpp) target_link_libraries(testBreakCondition crpropa gtest gtest_main pthread) add_test(testBreakCondition testBreakCondition) - - add_executable(testOutput test/testOutput.cpp) + + add_executable(testOutput test/testOutput.cpp) target_link_libraries(testOutput crpropa gtest gtest_main pthread) add_test(testOutput testOutput) - + add_executable(testInteraction test/testInteraction.cpp) target_link_libraries(testInteraction crpropa gtest gtest_main pthread) add_test(testInteraction testInteraction) - + add_executable(testSource test/testSource.cpp) target_link_libraries(testSource crpropa gtest gtest_main pthread) add_test(testSource testSource) @@ -233,18 +200,19 @@ option(ENABLE_PYTHON "Create python library via SWIG" ON) if(ENABLE_PYTHON) include(python/Python.cmake) include_directories(${PYTHON_INCLUDE_PATH}) - + file(GLOB_RECURSE CRPROPA_INCLUDES include/*.h) set_source_files_properties( ${CMAKE_CURRENT_BINARY_DIR}/crpropa_wrap.cxx PROPERTIES GENERATED true ) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/crpropa_wrap.cxx - COMMAND swig -c++ -python -I${CMAKE_SOURCE_DIR}/include ${CRPROPA_SWIG_DEFINES} -o ${CMAKE_CURRENT_BINARY_DIR}/crpropa_wrap.cxx -outdir ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/python/crpropa.i - DEPENDS ${CMAKE_SOURCE_DIR}/python/crpropa.i ${CRPROPA_INCLUDES} ) - + COMMAND swig -c++ -python -I${CMAKE_SOURCE_DIR}/include ${CRPROPA_SWIG_DEFINES} -o ${CMAKE_CURRENT_BINARY_DIR}/crpropa_wrap.cxx -outdir ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/python/crpropa.i + DEPENDS ${CMAKE_SOURCE_DIR}/python/crpropa.i ${CRPROPA_INCLUDES} ) + add_library(crpropa-swig MODULE ${CMAKE_CURRENT_BINARY_DIR}/crpropa_wrap.cxx) set_target_properties(crpropa-swig PROPERTIES PREFIX "") - set_target_properties(crpropa-swig PROPERTIES OUTPUT_NAME "_crpropa") + set_target_properties(crpropa-swig PROPERTIES OUTPUT_NAME "_crpropa") target_link_libraries(crpropa-swig crpropa ${PYTHON_LIBRARIES}) - + + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/crpropa.py" DESTINATION ${PYTHON_SITE_PACKAGES}) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/crpropa.py" DESTINATION ${PYTHON_SITE_PACKAGES}) install(TARGETS crpropa-swig LIBRARY DESTINATION ${PYTHON_SITE_PACKAGES}) endif(ENABLE_PYTHON) From 2d4940688857a6cec26e2c1e86dad86cc191c986 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 21 Jul 2014 22:52:00 +0200 Subject: [PATCH 0442/1298] python package structure and corresponding changes to CMakeLists.txt - the content of python/crpropa is copied to site-packages on make install - cpropa.py, crpropa.so are copied to site-pagackes/python Usage: - __init__.py includes a "from crpropa import *", keeping the current behaviour - other python modules can be specifically included with "from python import XYZ" --- CMakeLists.txt | 11 ++++------- python/crpropa/__init__.py | 1 + {contrib => python/crpropa}/gamale.py | 0 3 files changed, 5 insertions(+), 7 deletions(-) create mode 100644 python/crpropa/__init__.py rename {contrib => python/crpropa}/gamale.py (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ff599cee..d667f2521 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -129,10 +129,7 @@ endif(GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) # Library and Binary # ---------------------------------------------------------------------------- include_directories(include ${CRPROPA_EXTRA_INCLUDES}) -file(GLOB_RECURSE - CRPROPA_SOURCES - RELATIVE ${CMAKE_SOURCE_DIR} - "${CMAKE_SOURCE_DIR}/src/*.cpp") +file(GLOB_RECURSE CRPROPA_SOURCES "${CMAKE_SOURCE_DIR}/src/*.cpp") add_library(crpropa SHARED ${CRPROPA_SOURCES} ${CRPROPA_EXTRA_SOURCES} @@ -212,7 +209,7 @@ if(ENABLE_PYTHON) set_target_properties(crpropa-swig PROPERTIES OUTPUT_NAME "_crpropa") target_link_libraries(crpropa-swig crpropa ${PYTHON_LIBRARIES}) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/crpropa.py" DESTINATION ${PYTHON_SITE_PACKAGES}) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/crpropa.py" DESTINATION ${PYTHON_SITE_PACKAGES}) - install(TARGETS crpropa-swig LIBRARY DESTINATION ${PYTHON_SITE_PACKAGES}) + install(DIRECTORY "${CMAKE_SOURCE_DIR}/python/crpropa" DESTINATION ${PYTHON_SITE_PACKAGES}) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/crpropa.py" DESTINATION ${PYTHON_SITE_PACKAGES}/crpropa) + install(TARGETS crpropa-swig LIBRARY DESTINATION ${PYTHON_SITE_PACKAGES}/crpropa) endif(ENABLE_PYTHON) diff --git a/python/crpropa/__init__.py b/python/crpropa/__init__.py new file mode 100644 index 000000000..20688a417 --- /dev/null +++ b/python/crpropa/__init__.py @@ -0,0 +1 @@ +from crpropa import * diff --git a/contrib/gamale.py b/python/crpropa/gamale.py similarity index 100% rename from contrib/gamale.py rename to python/crpropa/gamale.py From 4826b11981927596c7f4acf831b9df619473781b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Tue, 22 Jul 2014 11:19:43 +0200 Subject: [PATCH 0443/1298] EleCa changes by Mariangela Settimo --- libs/EleCa/src/EnergyLoss.cpp | 16 ++++++++++++---- libs/EleCa/src/Particle.cpp | 4 +++- libs/EleCa/src/Propagation.cpp | 9 +++++---- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/libs/EleCa/src/EnergyLoss.cpp b/libs/EleCa/src/EnergyLoss.cpp index 03ae039ca..264446b2d 100644 --- a/libs/EleCa/src/EnergyLoss.cpp +++ b/libs/EleCa/src/EnergyLoss.cpp @@ -344,18 +344,25 @@ double ExtractPPSecondariesEnergy(Process &proc) { } } + if (cnt == 0) { + for (double Ee = f * 0.5 * (1 - beta) * E0; Ee < 0.5 * (1 + beta) * E0; + Ee *= f) { + std::cout << Ee << " " << f << " " << (1-beta) << std::endl; + } + } NormFactor = (double) 1. / (double) NormFactor; for (int i = 0; i < cnt; i++) MC_Sampling_Hist[i][2] *= NormFactor; + double rnd; - double Ee = 0; + double Ee = ElectronMass; int k = 0; while (failed) { rnd = Uniform(0., 1.0); - Ee = 0; + Ee = ElectronMass; k++; double min = 1e6; double max = -1; @@ -374,11 +381,12 @@ double ExtractPPSecondariesEnergy(Process &proc) { } } if (failed) { - std::cout << "failed in extractPP " << Ee << " " << beta << " * s: " - << s << " E: " << E0 << " eps : " << eps << " me: " + /* std::cout << "failed in extractPP " << Ee << " " << beta << " * s: " + << s << " E0: " << E0 << " eps : " << eps << " me^2/E0: " << ElectronMass * ElectronMass / E0 << " ) " << " cnt : " << cnt << std::endl; std::cout << " Limits " << proc.GetMin() << std::endl; + */ if (cnt == 0) throw std::runtime_error("failed in extractPP"); } diff --git a/libs/EleCa/src/Particle.cpp b/libs/EleCa/src/Particle.cpp index 2013544f1..5025bb82d 100644 --- a/libs/EleCa/src/Particle.cpp +++ b/libs/EleCa/src/Particle.cpp @@ -11,7 +11,9 @@ bool Particle::IsGood() { double zmax_prop1 = -0.101717; double zmax_prop2 = 0.002855; double Eloc = log10(fE0ph); - if (Eloc < 18) + if (fE0ph <=0 ) + return 0; + if (Eloc > 12 && Eloc < 18) Eloc = 18; if (fz0ph > zmax_prop0 + zmax_prop1 * Eloc + zmax_prop2 * Eloc * Eloc) return 0; diff --git a/libs/EleCa/src/Propagation.cpp b/libs/EleCa/src/Propagation.cpp index 1d48324ce..3d933e714 100644 --- a/libs/EleCa/src/Propagation.cpp +++ b/libs/EleCa/src/Propagation.cpp @@ -12,6 +12,7 @@ #include #include +//#define DEBUG_ELECA namespace eleca { Propagation::Propagation() { @@ -71,7 +72,7 @@ void Propagation::InitBkgArray(const std::string &BackRad) { } } - if (BackRad == "CIOB") { + else if (BackRad == "CIOB") { double de = pow((double) eps_ph_sup_ciob / eps_ph_inf_ciob, 1. / POINTS_VERY_FEW); double e = eps_ph_inf_ciob; @@ -82,7 +83,7 @@ void Propagation::InitBkgArray(const std::string &BackRad) { } } - if (BackRad == "URB") { + else if (BackRad == "URB") { double de = pow((double) eps_ph_sup_urb / eps_ph_inf_urb, 1. / POINTS_VERY_FEW); double e = eps_ph_inf_urb; @@ -93,7 +94,7 @@ void Propagation::InitBkgArray(const std::string &BackRad) { } } - if (BackRad == "URB") { + else { //if (BackRad == "ALL" ) { double de = pow((double) eps_ph_sup_global / eps_ph_inf_global, (double) 1. / POINTS_VERY_FEW); double e = eps_ph_inf_global; @@ -475,7 +476,7 @@ void Propagation::Propagate(Particle &curr_particle, std::vector EtargetAll = GetEtarget(proc, curr_particle); #ifdef DEBUG_ELECA - std::cout << "GetEtarget: " << EtargetAll[0] << " " << EtargetAll[1] << std::endl; + std::cout << "for initial particle : " << curr_particle.GetEnergy() << " " << Ein << " GetEtarget: " << EtargetAll[0] << " " << EtargetAll[1] << std::endl; #endif min_dist = ExtractMinDist(proc, curr_particle.GetType(), R, R2, EtargetAll); From e328becb7a74a8944055661501fb32c749041788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Tue, 22 Jul 2014 11:58:45 +0200 Subject: [PATCH 0444/1298] add initial DintPropagation method --- include/crpropa/PhotonPropagation.h | 1 + src/PhotonPropagation.cpp | 146 +++++++++++++++++++++++++++- 2 files changed, 146 insertions(+), 1 deletion(-) diff --git a/include/crpropa/PhotonPropagation.h b/include/crpropa/PhotonPropagation.h index cfb09231f..e2e2bf150 100644 --- a/include/crpropa/PhotonPropagation.h +++ b/include/crpropa/PhotonPropagation.h @@ -11,6 +11,7 @@ void EleCaPropagation(const std::string &background, std::vector &spectrum); void EleCaPropagation(const std::string &background, const std::string &inputfile, const std::string &outputfile); +void DintPropagation(const std::string &inputfile, const std::string &outputfile); } // namespace crpropa diff --git a/src/PhotonPropagation.cpp b/src/PhotonPropagation.cpp index 144717b92..0415aed1e 100644 --- a/src/PhotonPropagation.cpp +++ b/src/PhotonPropagation.cpp @@ -1,10 +1,14 @@ #include "crpropa/PhotonPropagation.h" #include "crpropa/Common.h" +#include "crpropa/Units.h" +#include "crpropa/Cosmology.h" #include "EleCa/Propagation.h" #include "EleCa/Particle.h" #include "EleCa/Common.h" +#include "dint/prop_second.h" + #include #include #include @@ -89,5 +93,145 @@ void EleCaPropagation(const std::string &background, } } -} // namespace crpropa +class PhotonDINT1DImpl { +public: + PhotonDINT1DImpl() { + // Initialize the energy grids for dint + New_dCVector(&energyGrid, NUM_MAIN_BINS); + New_dCVector(&energyWidth, NUM_MAIN_BINS); + SetEnergyBins(MIN_ENERGY_EXP, &energyGrid, &energyWidth); + } + + virtual ~PhotonDINT1DImpl() { + Delete_dCVector(&energyGrid); + Delete_dCVector(&energyWidth); + } + + dCVector energyGrid, energyWidth; + virtual void saveSpectrum(Spectrum *spectrum) = 0; +}; + +class PhotonDINT1DAsciiImpl: public PhotonDINT1DImpl { + mutable std::ofstream fout; +public: + PhotonDINT1DAsciiImpl(const std::string &filename) : + PhotonDINT1DImpl(), fout(filename.c_str()) { + for (int j = 0; j < energyGrid.dimension; j++) { + fout << (energyGrid.vector[j] * ELECTRON_MASS) << " "; + } + fout << std::endl; + } + + void saveSpectrum(Spectrum *spectrum) { + for (int j = 0; j < spectrum->numberOfMainBins; j++) { + fout << spectrum->spectrum[PHOTON][j] << " "; // spectrum: mean number of particles per energy bin + } + fout << endl; + } +}; + +void DintPropagation(const std::string &inputfile, + const std::string &outputfile) { + // Initialize the spectrum + Spectrum inputSpectrum; + NewSpectrum(&inputSpectrum, NUM_MAIN_BINS); + + dCVector energyGrid, energyWidth; + // Initialize the energy grids for dint + New_dCVector(&energyGrid, NUM_MAIN_BINS); + New_dCVector(&energyWidth, NUM_MAIN_BINS); + SetEnergyBins(MIN_ENERGY_EXP, &energyGrid, &energyWidth); + + std::ofstream outfile(outputfile.c_str()); + if (!outfile.good()) + throw std::runtime_error( + "DintPropagation: could not open file " + outputfile); + + std::ifstream infile(inputfile.c_str()); + if (!infile.good()) + throw std::runtime_error( + "DintPropagation: could not open file " + inputfile); + + // Initialize the bField + dCVector bField; + New_dCVector(&bField, 1); + + // Initialize output spectrum + Spectrum outputSpectrum; + NewSpectrum(&outputSpectrum, NUM_MAIN_BINS); + + Spectrum finalSpectrum; + NewSpectrum(&finalSpectrum, NUM_MAIN_BINS); + + std::string dataPath = getDataPath("dint"); + + size_t cnt = 0; + while (infile.good()) { + if (infile.peek() != '#') { + double E, D, pE, iE; + int Id, pId, iId; + infile >> Id >> E >> D >> pId >> pE >> iId >> iE; + cnt++; + std::cerr << cnt << std::endl; + if (infile) { + + double criticalEnergy = E * EeV / (eV * ELECTRON_MASS); // units of dint + int maxBin = (int) ((log10(criticalEnergy * ELECTRON_MASS) + - MAX_ENERGY_EXP) * BINS_PER_DECADE + NUM_MAIN_BINS); + if (Id == 22) + inputSpectrum.spectrum[PHOTON][maxBin] = 1.; + else if (Id == 11) + inputSpectrum.spectrum[ELECTRON][maxBin] = 1.; + else if (Id == -11) + inputSpectrum.spectrum[POSITRON][maxBin] = 1.; + else { + std::cerr << "DintPropagation: Unhandled particle ID " << Id << std::endl; + continue; + } + + + double h = H0() * Mpc / 1000; + double ol = omegaL(); + double om = omegaM(); + + int IRFlag(2); + int RadioFlag(2); + double Zmax(5); + int Cutcascade_Magfield(0); + + InitializeSpectrum(&outputSpectrum); + prop_second(D, &bField, &energyGrid, &energyWidth, + &inputSpectrum, &outputSpectrum, dataPath, 2, 5, 2, h, + om, ol, Cutcascade_Magfield); + // add spectrum + for (int i = 0; i < NUM_SPECIES; i++) { + for (int j = 0; j < outputSpectrum.numberOfMainBins; j++) + finalSpectrum.spectrum[i][j] += + outputSpectrum.spectrum[i][j]; + } + + } + } + infile.ignore(std::numeric_limits::max(), '\n'); + } + + for (int j = 0; j < finalSpectrum.numberOfMainBins; j++) { + outfile << (energyGrid.vector[j] / EeV * (eV * ELECTRON_MASS)) << " "; + for (int i = 0; i < NUM_SPECIES; i++) { + outfile << finalSpectrum.spectrum[i][j] << " "; + } + outfile << "\n"; + } + + DeleteSpectrum(&finalSpectrum); + DeleteSpectrum(&outputSpectrum); + DeleteSpectrum(&inputSpectrum); + Delete_dCVector(&bField); + + Delete_dCVector(&energyGrid); + Delete_dCVector(&energyWidth); + +} + +} // namespace crpropa From 255c100691ae9c2a991d485268d3adc22ac8579f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Tue, 22 Jul 2014 14:20:49 +0200 Subject: [PATCH 0445/1298] flush photon output file, fix propagation signature --- include/crpropa/PhotonPropagation.h | 12 +++--- src/PhotonPropagation.cpp | 62 +++++------------------------ src/module/PhotonOutput1D.cpp | 3 +- 3 files changed, 19 insertions(+), 58 deletions(-) diff --git a/include/crpropa/PhotonPropagation.h b/include/crpropa/PhotonPropagation.h index e2e2bf150..74a06c24f 100644 --- a/include/crpropa/PhotonPropagation.h +++ b/include/crpropa/PhotonPropagation.h @@ -6,12 +6,14 @@ namespace crpropa { -void EleCaPropagation(const std::string &background, - const std::string &inputfile, std::vector &energy, +void EleCaPropagation(const std::string &inputfile, + const std::string &background, std::vector &energy, std::vector &spectrum); -void EleCaPropagation(const std::string &background, - const std::string &inputfile, const std::string &outputfile); -void DintPropagation(const std::string &inputfile, const std::string &outputfile); +void EleCaPropagation(const std::string &inputfile, + const std::string &outputfile, const std::string &background = "ALL"); +void DintPropagation(const std::string &inputfile, + const std::string &outputfile, int IRFlag = 2, int RadioFlag = 2, + double Zmax = 5); } // namespace crpropa diff --git a/src/PhotonPropagation.cpp b/src/PhotonPropagation.cpp index 0415aed1e..ca3100d14 100644 --- a/src/PhotonPropagation.cpp +++ b/src/PhotonPropagation.cpp @@ -16,8 +16,8 @@ namespace crpropa { -void EleCaPropagation(const std::string &background, - const std::string &inputfile, std::vector &energy, +void EleCaPropagation(const std::string &inputfile, + const std::string &background, std::vector &energy, std::vector &spectrum) { std::ifstream infile(inputfile.c_str()); @@ -82,10 +82,10 @@ void EleCaPropagation(const std::string &background, infile.close(); } -void EleCaPropagation(const std::string &background, - const std::string &inputfile, const std::string &outputfile) { +void EleCaPropagation(const std::string &inputfile, + const std::string &outputfile, const std::string &background) { std::vector energy, spectrum; - EleCaPropagation(background, inputfile, energy, spectrum); + EleCaPropagation(inputfile, background, energy, spectrum); std::ofstream output(outputfile.c_str()); output << "# E N\n"; for (size_t i = 0; i < energy.size(); i++) { @@ -93,45 +93,8 @@ void EleCaPropagation(const std::string &background, } } -class PhotonDINT1DImpl { -public: - PhotonDINT1DImpl() { - // Initialize the energy grids for dint - New_dCVector(&energyGrid, NUM_MAIN_BINS); - New_dCVector(&energyWidth, NUM_MAIN_BINS); - SetEnergyBins(MIN_ENERGY_EXP, &energyGrid, &energyWidth); - } - - virtual ~PhotonDINT1DImpl() { - Delete_dCVector(&energyGrid); - Delete_dCVector(&energyWidth); - } - - dCVector energyGrid, energyWidth; - virtual void saveSpectrum(Spectrum *spectrum) = 0; -}; - -class PhotonDINT1DAsciiImpl: public PhotonDINT1DImpl { - mutable std::ofstream fout; -public: - PhotonDINT1DAsciiImpl(const std::string &filename) : - PhotonDINT1DImpl(), fout(filename.c_str()) { - for (int j = 0; j < energyGrid.dimension; j++) { - fout << (energyGrid.vector[j] * ELECTRON_MASS) << " "; - } - fout << std::endl; - } - - void saveSpectrum(Spectrum *spectrum) { - for (int j = 0; j < spectrum->numberOfMainBins; j++) { - fout << spectrum->spectrum[PHOTON][j] << " "; // spectrum: mean number of particles per energy bin - } - fout << endl; - } -}; - void DintPropagation(const std::string &inputfile, - const std::string &outputfile) { + const std::string &outputfile, int IRFlag, int RadioFlag, double Zmax) { // Initialize the spectrum Spectrum inputSpectrum; NewSpectrum(&inputSpectrum, NUM_MAIN_BINS); @@ -185,24 +148,19 @@ void DintPropagation(const std::string &inputfile, else if (Id == -11) inputSpectrum.spectrum[POSITRON][maxBin] = 1.; else { - std::cerr << "DintPropagation: Unhandled particle ID " << Id << std::endl; + std::cerr << "DintPropagation: Unhandled particle ID " << Id + << std::endl; continue; } - double h = H0() * Mpc / 1000; double ol = omegaL(); double om = omegaM(); - int IRFlag(2); - int RadioFlag(2); - double Zmax(5); - int Cutcascade_Magfield(0); - InitializeSpectrum(&outputSpectrum); prop_second(D, &bField, &energyGrid, &energyWidth, - &inputSpectrum, &outputSpectrum, dataPath, 2, 5, 2, h, - om, ol, Cutcascade_Magfield); + &inputSpectrum, &outputSpectrum, dataPath, IRFlag, Zmax, + RadioFlag, h, om, ol, 0); // add spectrum for (int i = 0; i < NUM_SPECIES; i++) { for (int j = 0; j < outputSpectrum.numberOfMainBins; j++) diff --git a/src/module/PhotonOutput1D.cpp b/src/module/PhotonOutput1D.cpp index a433e2031..b81c0cacd 100644 --- a/src/module/PhotonOutput1D.cpp +++ b/src/module/PhotonOutput1D.cpp @@ -47,7 +47,8 @@ void PhotonOutput1D::process(Candidate *candidate) const { #pragma omp critical { output.write(buffer, p); - //output.flush(); + // TODO: add begin/end methods to Modules to flush at the end of the module list only + output.flush(); } candidate->setActive(false); From 795c510b9e30c083e677e0b27d1b3846d045aa07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Tue, 22 Jul 2014 17:42:08 +0200 Subject: [PATCH 0446/1298] improve DintPropagation performance, add spectra from small bins --- src/PhotonPropagation.cpp | 115 +++++++++++++++++++++++++++----------- 1 file changed, 82 insertions(+), 33 deletions(-) diff --git a/src/PhotonPropagation.cpp b/src/PhotonPropagation.cpp index ca3100d14..1bbf5b73b 100644 --- a/src/PhotonPropagation.cpp +++ b/src/PhotonPropagation.cpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace crpropa { @@ -93,12 +94,25 @@ void EleCaPropagation(const std::string &inputfile, } } +typedef struct _Secondary { + double E, D; + int Id; +} _Secondary; + +bool _SecondarySortPredicate(const _Secondary& s1, const _Secondary& s2) { + return s1.D < s2.D; +} + +void AddSpectrum(Spectrum *a, const Spectrum *b) { + for (int i = 0; i < NUM_SPECIES; i++) { + for (int j = 0; j < a->numberOfMainBins; j++) + a->spectrum[i][j] += b->spectrum[i][j]; + } +} + void DintPropagation(const std::string &inputfile, const std::string &outputfile, int IRFlag, int RadioFlag, double Zmax) { // Initialize the spectrum - Spectrum inputSpectrum; - NewSpectrum(&inputSpectrum, NUM_MAIN_BINS); - dCVector energyGrid, energyWidth; // Initialize the energy grids for dint New_dCVector(&energyGrid, NUM_MAIN_BINS); @@ -127,51 +141,88 @@ void DintPropagation(const std::string &inputfile, NewSpectrum(&finalSpectrum, NUM_MAIN_BINS); std::string dataPath = getDataPath("dint"); + double h = H0() * Mpc / 1000; + double ol = omegaL(); + double om = omegaM(); + + const size_t nBuffer = 1 << 20; + const double dMargin = 0.01; // Mpc; size_t cnt = 0; while (infile.good()) { - if (infile.peek() != '#') { - double E, D, pE, iE; - int Id, pId, iId; - infile >> Id >> E >> D >> pId >> pE >> iId >> iE; - cnt++; - std::cerr << cnt << std::endl; - if (infile) { + // buffer for secondaries + std::vector<_Secondary> secondaries; + secondaries.reserve(nBuffer); + + // read secondaries from file + size_t n = 0; + while (infile.good() && (n < nBuffer)) { + if (infile.peek() != '#') { + double pE, iE; + int pId, iId; + _Secondary s; + infile >> s.Id >> s.E >> s.D >> pId >> pE >> iId >> iE; + if (infile) { + n++; + secondaries.push_back(s); + } + } + + infile.ignore(std::numeric_limits::max(), '\n'); + } + + if (secondaries.size() == 0) + continue; - double criticalEnergy = E * EeV / (eV * ELECTRON_MASS); // units of dint + // sort by D + std::sort(secondaries.begin(), secondaries.end(), + _SecondarySortPredicate); + + Spectrum inputSpectrum, outputSpectrum; + NewSpectrum(&inputSpectrum, NUM_MAIN_BINS); + NewSpectrum(&outputSpectrum, NUM_MAIN_BINS); + double currentDistance = secondaries.back().D; + + // process secondaries + while (secondaries.size() > 0) { + // add secondaries at the current distance to spectrum + while (secondaries.back().D >= (currentDistance - dMargin)) { + double criticalEnergy = secondaries.back().E * EeV / (eV * ELECTRON_MASS); // units of dint int maxBin = (int) ((log10(criticalEnergy * ELECTRON_MASS) - MAX_ENERGY_EXP) * BINS_PER_DECADE + NUM_MAIN_BINS); + int Id = secondaries.back().Id; if (Id == 22) - inputSpectrum.spectrum[PHOTON][maxBin] = 1.; + inputSpectrum.spectrum[PHOTON][maxBin] += 1.; else if (Id == 11) - inputSpectrum.spectrum[ELECTRON][maxBin] = 1.; + inputSpectrum.spectrum[ELECTRON][maxBin] += 1.; else if (Id == -11) - inputSpectrum.spectrum[POSITRON][maxBin] = 1.; + inputSpectrum.spectrum[POSITRON][maxBin] += 1.; else { std::cerr << "DintPropagation: Unhandled particle ID " << Id << std::endl; - continue; } + secondaries.pop_back(); + } - double h = H0() * Mpc / 1000; - double ol = omegaL(); - double om = omegaM(); - - InitializeSpectrum(&outputSpectrum); - prop_second(D, &bField, &energyGrid, &energyWidth, - &inputSpectrum, &outputSpectrum, dataPath, IRFlag, Zmax, - RadioFlag, h, om, ol, 0); - // add spectrum - for (int i = 0; i < NUM_SPECIES; i++) { - for (int j = 0; j < outputSpectrum.numberOfMainBins; j++) - finalSpectrum.spectrum[i][j] += - outputSpectrum.spectrum[i][j]; - } + double D = currentDistance; - } + // only propagate to next particle + if (secondaries.size() > 0) + D -= secondaries.back().D; + + InitializeSpectrum(&outputSpectrum); + prop_second(D, &bField, &energyGrid, &energyWidth, &inputSpectrum, + &outputSpectrum, dataPath, IRFlag, Zmax, RadioFlag, h, om, + ol, 0); + AddSpectrum(&inputSpectrum, &outputSpectrum); + + currentDistance -= D; } - infile.ignore(std::numeric_limits::max(), '\n'); + AddSpectrum(&finalSpectrum, &inputSpectrum); + + DeleteSpectrum(&outputSpectrum); + DeleteSpectrum(&inputSpectrum); } for (int j = 0; j < finalSpectrum.numberOfMainBins; j++) { @@ -183,8 +234,6 @@ void DintPropagation(const std::string &inputfile, } DeleteSpectrum(&finalSpectrum); - DeleteSpectrum(&outputSpectrum); - DeleteSpectrum(&inputSpectrum); Delete_dCVector(&bField); Delete_dCVector(&energyGrid); From 99dd566a9db53c2d987259d6f5925eb949140e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Tue, 22 Jul 2014 22:05:13 +0200 Subject: [PATCH 0447/1298] Fix PhotonOutput1D and PhotonPropagation for Dint --- src/PhotonPropagation.cpp | 31 ++++++++++++++++++++++--------- src/module/PhotonOutput1D.cpp | 2 +- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/PhotonPropagation.cpp b/src/PhotonPropagation.cpp index 1bbf5b73b..f206e2c27 100644 --- a/src/PhotonPropagation.cpp +++ b/src/PhotonPropagation.cpp @@ -131,11 +131,7 @@ void DintPropagation(const std::string &inputfile, // Initialize the bField dCVector bField; - New_dCVector(&bField, 1); - - // Initialize output spectrum - Spectrum outputSpectrum; - NewSpectrum(&outputSpectrum, NUM_MAIN_BINS); + New_dCVector(&bField, 5); Spectrum finalSpectrum; NewSpectrum(&finalSpectrum, NUM_MAIN_BINS); @@ -146,7 +142,7 @@ void DintPropagation(const std::string &inputfile, double om = omegaM(); const size_t nBuffer = 1 << 20; - const double dMargin = 0.01; // Mpc; + const double dMargin = 0.1; // Mpc; size_t cnt = 0; while (infile.good()) { @@ -185,11 +181,25 @@ void DintPropagation(const std::string &inputfile, // process secondaries while (secondaries.size() > 0) { + std::cout << secondaries.size() << " "<< currentDistance << std::endl; + // add secondaries at the current distance to spectrum - while (secondaries.back().D >= (currentDistance - dMargin)) { + while ((secondaries.size() > 0) && (secondaries.back().D >= (currentDistance - dMargin))) { double criticalEnergy = secondaries.back().E * EeV / (eV * ELECTRON_MASS); // units of dint int maxBin = (int) ((log10(criticalEnergy * ELECTRON_MASS) - MAX_ENERGY_EXP) * BINS_PER_DECADE + NUM_MAIN_BINS); + if (maxBin >= NUM_MAIN_BINS) { + std::cout << "DintPropagation: Energy too high " << secondaries.back().E + << std::endl; + secondaries.pop_back(); + continue; + } + if (maxBin < 0) { + std::cout << "DintPropagation: Energy too low " << secondaries.back().E + << std::endl; + secondaries.pop_back(); + continue; + } int Id = secondaries.back().Id; if (Id == 22) inputSpectrum.spectrum[PHOTON][maxBin] += 1.; @@ -198,18 +208,19 @@ void DintPropagation(const std::string &inputfile, else if (Id == -11) inputSpectrum.spectrum[POSITRON][maxBin] += 1.; else { - std::cerr << "DintPropagation: Unhandled particle ID " << Id + std::cout << "DintPropagation: Unhandled particle ID " << Id << std::endl; } secondaries.pop_back(); } + //std::cout << secondaries.size() << std::endl; double D = currentDistance; // only propagate to next particle if (secondaries.size() > 0) D -= secondaries.back().D; - + //std::cout << D << std::endl; InitializeSpectrum(&outputSpectrum); prop_second(D, &bField, &energyGrid, &energyWidth, &inputSpectrum, &outputSpectrum, dataPath, IRFlag, Zmax, RadioFlag, h, om, @@ -233,6 +244,8 @@ void DintPropagation(const std::string &inputfile, outfile << "\n"; } + //std::cout << "done" << std::endl; + DeleteSpectrum(&finalSpectrum); Delete_dCVector(&bField); diff --git a/src/module/PhotonOutput1D.cpp b/src/module/PhotonOutput1D.cpp index b81c0cacd..0a0c5bf7b 100644 --- a/src/module/PhotonOutput1D.cpp +++ b/src/module/PhotonOutput1D.cpp @@ -34,7 +34,7 @@ void PhotonOutput1D::process(Candidate *candidate) const { size_t p = 0; p += sprintf(buffer + p, "%4i\t", pid); - p += sprintf(buffer + p, "%8.4f\t", candidate->current.getEnergy() / EeV); + p += sprintf(buffer + p, "%g\t", candidate->current.getEnergy() / EeV); p += sprintf(buffer + p, "%8.4f\t", candidate->created.getPosition().getR() / Mpc); p += sprintf(buffer + p, "%10i\t", candidate->created.getId()); From 3deb541f600005d11fb83694ba719a9d389b8942 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sun, 27 Jul 2014 21:37:08 +0200 Subject: [PATCH 0448/1298] add more photon fields --- include/crpropa/PhotonBackground.h | 3 ++- src/PhotonBackground.cpp | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/include/crpropa/PhotonBackground.h b/include/crpropa/PhotonBackground.h index 2628bcc54..2f2427f58 100644 --- a/include/crpropa/PhotonBackground.h +++ b/include/crpropa/PhotonBackground.h @@ -4,8 +4,9 @@ namespace crpropa { // Photon fields +// The default IRB model is that of Kneiske et al. 2004 enum PhotonField { - CMB, IRB + CMB, IRB, IRB_Kneiske04, IRB_Kneiske10, IRB_Franceschini08, IRB_Stecker05 }; // Returns overall comoving scaling factor diff --git a/src/PhotonBackground.cpp b/src/PhotonBackground.cpp index 6fcbfc641..788d13a3f 100644 --- a/src/PhotonBackground.cpp +++ b/src/PhotonBackground.cpp @@ -3,6 +3,7 @@ #include #include +#include namespace crpropa { @@ -10,13 +11,23 @@ namespace crpropa { // The scaling is calculated in data-tools/PhotonField/Kneiske2004_IRB_scaling.py double a[9] = { 0, 0.2, 0.4, 0.6, 1, 2, 3, 4, 5 }; static std::vector zKneiske(a, a + sizeof(a) / sizeof(double)); -double b[9] = {1., 0.9749867, 0.93999977, 0.88430409, 0.64952017, 0.27170436, 0.130244, 0.05971749, 0.}; +double b[9] = { 1., 0.9749867, 0.93999977, 0.88430409, 0.64952017, 0.27170436, + 0.130244, 0.05971749, 0. }; static std::vector sKneiske(b, b + sizeof(b) / sizeof(double)); double photonFieldScaling(PhotonField photonField, double z) { - if (photonField == IRB) + switch (photonField) { + case CMB: + return 1.; // CMB-like scaling + case IRB: + case IRB_Kneiske04: + case IRB_Kneiske10: + case IRB_Stecker05: + case IRB_Franceschini08: return interpolate(z, zKneiske, sKneiske); - return 1.; // CMB-like scaling + default: + throw std::runtime_error("PhotonField: unknown photon background"); + } } } // namespace crpropa From 6ef664151dd2c2b948d6d24d0190bf574080e089 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sun, 27 Jul 2014 21:45:59 +0200 Subject: [PATCH 0449/1298] add new IRB models to electron-pair production update of CRPropa-data required --- src/module/ElectronPairProduction.cpp | 32 ++++++++++++++++++++------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 583bd4820..37b7b4a96 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -29,13 +29,29 @@ void ElectronPairProduction::init() { switch (photonField) { case CMB: setDescription("ElectronPairProduction: CMB"); - initRate(getDataPath("pair_rate_CMB.txt")); - initSpectrum(getDataPath("pair_spectrum_CMB.txt")); + initRate(getDataPath("epp_CMB.txt")); + initSpectrum(getDataPath("epp_spectrum_CMB.txt")); break; - case IRB: - setDescription("ElectronPairProduction: IRB"); - initRate(getDataPath("pair_rate_IRB.txt")); - initSpectrum(getDataPath("pair_spectrum_IRB.txt")); + case IRB: // default: Kneiske '04 IRB model + case IRB_Kneiske04: + setDescription("ElectronPairProduction: IRB Kneiske '04"); + initRate(getDataPath("epp_IRB_Kneiske04.txt")); + initSpectrum(getDataPath("epp_spectrum_IRB.txt")); + break; + case IRB_Kneiske10: + setDescription("ElectronPairProduction: IRB Kneiske '10 (lower limit)"); + initRate(getDataPath("epp_IRB_Kneiske10.txt")); + initSpectrum(getDataPath("epp_spectrum_IRB.txt")); + break; + case IRB_Stecker05: + setDescription("ElectronPairProduction: IRB Stecker '05"); + initRate(getDataPath("epp_IRB_Stecker05.txt")); + initSpectrum(getDataPath("epp_spectrum_IRB.txt")); + break; + case IRB_Franceschini08: + setDescription("ElectronPairProduction: IRB Franceschini '08"); + initRate(getDataPath("epp_IRB_Franceschini08.txt")); + initSpectrum(getDataPath("epp_spectrum_IRB.txt")); break; default: throw std::runtime_error( @@ -59,8 +75,8 @@ void ElectronPairProduction::initRate(std::string filename) { double a, b; infile >> a >> b; if (infile) { - tabLorentzFactor.push_back(a * eV / mass_proton / c_squared); - tabLossRate.push_back(b / a / Mpc); + tabLorentzFactor.push_back(pow(10, a)); + tabLossRate.push_back(b / Mpc); } } infile.ignore(std::numeric_limits < std::streamsize > ::max(), '\n'); From 5731b908d68bc31a9e6c38183b98599fe74e01c1 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sun, 27 Jul 2014 21:58:07 +0200 Subject: [PATCH 0450/1298] add IRB models to photo-pion production requires to pull from crpropa3-data --- src/module/PhotoPionProduction.cpp | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index d9ca2cf12..5c17b3c92 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -45,13 +45,29 @@ void PhotoPionProduction::setLimit(double l) { } void PhotoPionProduction::init() { - if (photonField == CMB) { - init(getDataPath("photopion_CMB.txt")); + switch (photonField) { + case CMB: setDescription("PhotoPionProduction: CMB"); - } else if (photonField == IRB) { - init(getDataPath("photopion_KneiskeIRB.txt")); - setDescription("PhotoPionProduction: IRB"); - } else { + init(getDataPath("ppp_CMB.txt")); + break; + case IRB: // default: Kneiske '04 IRB model + case IRB_Kneiske04: + setDescription("PhotoPionProduction: IRB Kneiske '04"); + init(getDataPath("ppp_IRB_Kneiske04.txt")); + break; + case IRB_Kneiske10: + setDescription("PhotoPionProduction: IRB Kneiske '10 (lower limit)"); + init(getDataPath("ppp_IRB_Kneiske10.txt")); + break; + case IRB_Stecker05: + setDescription("PhotoPionProduction: IRB Stecker '05"); + init(getDataPath("ppp_IRB_Stecker05.txt")); + break; + case IRB_Franceschini08: + setDescription("PhotoPionProduction: IRB Franceschini '08"); + init(getDataPath("ppp_IRB_Franceschini08.txt")); + break; + default: throw std::runtime_error( "PhotoPionProduction: unknown photon background"); } From 4252283efd5c943bd89bde265b655f92af702ec7 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 28 Jul 2014 09:56:39 +0200 Subject: [PATCH 0451/1298] refactor photo-disintegration to use total cross section and branching ratios and add IRB models to it requires updating from CRPropa3-data --- include/crpropa/module/PhotoDisintegration.h | 20 ++- src/module/PhotoDisintegration.cpp | 172 ++++++++++++------- 2 files changed, 124 insertions(+), 68 deletions(-) diff --git a/include/crpropa/module/PhotoDisintegration.h b/include/crpropa/module/PhotoDisintegration.h index 6b102fcca..26828da91 100644 --- a/include/crpropa/module/PhotoDisintegration.h +++ b/include/crpropa/module/PhotoDisintegration.h @@ -16,24 +16,30 @@ class PhotoDisintegration: public Module { private: PhotonField photonField; double limit; // fraction of mean free path for limiting the next step - struct PDMode { + + struct Branch { int channel; // number of emitted (n, p, H2, H3, He3, He4) - std::vector rate; // disintegration rate [1/m] + std::vector branchingRatio; // branching ratio as function of nucleus Lorentz factor }; - std::vector > pdTable; // pdTable[Z * 31 + N] = vector - double lgmin; // minimum log10(Lorentz-factor) - double lgmax; // maximum log10(Lorentz-factor) + std::vector > pdBranch; // pdTable[Z * 31 + N] = vector + std::vector > pdRate; // pdRate[Z * 31 + N] = total disintegration rate + + static const double lgmin = 6; // minimum log10(Lorentz-factor) + static const double lgmax = 14; // maximum log10(Lorentz-factor) + static const size_t nlg = 201; // number of Lorentz-factor steps public: PhotoDisintegration(PhotonField photonField = CMB, double limit = 0.1); void setLimit(double l); void init(PhotonField photonField); - void init(std::string filename); + void initRate(std::string filename); + void initBranching(std::string filename); void process(Candidate *candidate) const; void performInteraction(Candidate *candidate, int channel) const; /** - Calculates the loss length E dx/dE in [m]. This is not used in the simulation. + Calculates the loss length E dx/dE in [m] physical distance. + This is not used in the simulation. @param id PDG particle id @param energy particle energy [J] @param z redshift diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index f15f203f4..90051aee8 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -20,35 +20,77 @@ void PhotoDisintegration::setLimit(double l) { } void PhotoDisintegration::init(PhotonField photonField) { - this->photonField = photonField; switch (photonField) { case CMB: setDescription("PhotoDisintegration: CMB"); - init(getDataPath("photodis_CMB.txt")); + initRate(getDataPath("pd_CMB.txt")); + initBranching(getDataPath("pd_branch_CMB.txt")); break; - case IRB: - setDescription("PhotoDisintegration: IRB"); - init(getDataPath("photodis_IRB.txt")); + case IRB: // default: Kneiske '04 IRB model + case IRB_Kneiske04: + setDescription("PhotoDisintegration: IRB Kneiske '04"); + initRate(getDataPath("pd_IRB_Kneiske04.txt")); + initBranching(getDataPath("pd_branch_IRB_Kneiske04.txt")); + break; + case IRB_Kneiske10: + setDescription("PhotoDisintegration: IRB Kneiske '10 (lower limit)"); + initRate(getDataPath("pd_IRB_Kneiske10.txt")); + initBranching(getDataPath("pd_branch_IRB_Kneiske04.txt")); + break; + case IRB_Stecker05: + setDescription("PhotoDisintegration: IRB Stecker '05"); + initRate(getDataPath("pd_IRB_Stecker05.txt")); + initBranching(getDataPath("pd_branch_IRB_Kneiske04.txt")); + break; + case IRB_Franceschini08: + setDescription("PhotoDisintegration: IRB Franceschini '08"); + initRate(getDataPath("pd_IRB_Franceschini08.txt")); + initBranching(getDataPath("pd_branch_IRB_Kneiske04.txt")); break; default: throw std::runtime_error( - "crpropa::PhotoDisintegration: unknown photon background"); + "PhotoDisintegration: unknown photon background"); } } -void PhotoDisintegration::init(std::string filename) { +void PhotoDisintegration::initRate(std::string filename) { std::ifstream infile(filename.c_str()); if (not infile.good()) throw std::runtime_error( - "crpropa::PhotoDisintegration: could not open file " - + filename); + "PhotoDisintegration: could not open file " + filename); + + // clear previously loaded interaction rates + pdRate.clear(); + pdRate.resize(27 * 31); + + std::string line; + while (std::getline(infile, line)) { + if (line[0] == '#') + continue; + std::stringstream lineStream(line); - lgmin = 6; - lgmax = 13.96; + int Z, N; + lineStream >> Z; + lineStream >> N; + + double r; + for (size_t i = 0; i < nlg; i++) { + lineStream >> r; + pdRate[Z * 31 + N].push_back(r / Mpc); + } + } + infile.close(); +} + +void PhotoDisintegration::initBranching(std::string filename) { + std::ifstream infile(filename.c_str()); + if (not infile.good()) + throw std::runtime_error( + "PhotoDisintegration: could not open file " + filename); // clear previously loaded interaction rates - pdTable.clear(); - pdTable.resize(27 * 31); + pdBranch.clear(); + pdBranch.resize(27 * 31); std::string line; while (std::getline(infile, line)) { @@ -60,23 +102,23 @@ void PhotoDisintegration::init(std::string filename) { lineStream >> Z; lineStream >> N; - PDMode pd; - lineStream >> pd.channel; + Branch branch; + lineStream >> branch.channel; - double r = 0; - for (size_t i = 0; i < 200; i++) { + double r; + for (size_t i = 0; i < nlg; i++) { lineStream >> r; - pd.rate.push_back(r / Mpc); + branch.branchingRatio.push_back(r / Mpc); } - pdTable[Z * 31 + N].push_back(pd); + pdBranch[Z * 31 + N].push_back(branch); } infile.close(); } void PhotoDisintegration::process(Candidate *candidate) const { - // the loop will be executed at least once for limiting the next step + // execute the loop at least once for limiting the next step double step = candidate->getCurrentStep(); do { // check if nucleus @@ -91,8 +133,7 @@ void PhotoDisintegration::process(Candidate *candidate) const { // check if disintegration data available if ((Z > 26) or (N > 30)) return; - std::vector pdModes = pdTable[Z * 31 + N]; - if (pdModes.size() == 0) + if (pdRate[Z * 31 + N].size() == 0) return; // check if in tabulated energy range @@ -101,36 +142,37 @@ void PhotoDisintegration::process(Candidate *candidate) const { if ((lg <= lgmin) or (lg >= lgmax)) return; - // find disintegration channel with minimum random decay distance + double rate = interpolateEquidistant(lg, lgmin, lgmax, + pdRate[Z * 31 + N]); + + // comological scaling, rate per comoving distance) + rate *= pow(1 + z, 2) * photonFieldScaling(photonField, z); + Random &random = Random::instance(); - double randDistance = std::numeric_limits::max(); - int channel; - double totalRate = 0; - - // comological scaling of interaction distance (comoving units) - double scaling = pow(1 + z, 2) * photonFieldScaling(photonField, z); - - for (size_t i = 0; i < pdModes.size(); i++) { - double rate = interpolateEquidistant(lg, lgmin, lgmax, - pdModes[i].rate); - rate *= scaling; - totalRate += rate; - double d = -log(random.rand()) / rate; - if (d > randDistance) - continue; - randDistance = d; - channel = pdModes[i].channel; - } + double randDistance = -log(random.rand()) / rate; - // check if interaction doesn't happen + // check if an interaction occurs in this step if (step < randDistance) { // limit next step to a fraction of the mean free path - candidate->limitNextStep(limit / totalRate); + candidate->limitNextStep(limit / rate); return; } - // interact and repeat with remaining step + // select channel and interact + double cmp = random.rand(); + int channel; + int l = round(lg / (lgmax - lgmin) * (nlg - 1)); // index of closest tabulated point + + std::vector branches = pdBranch[Z * 31 + N]; + for (size_t i = 0; i < branches.size(); i++) { + channel = branches[i].channel; + cmp -= branches[i].branchingRatio[l]; + if (cmp <= 0) + break; + } performInteraction(candidate, channel); + + // repeat with remaining step step -= randDistance; } while (step > 0); } @@ -189,8 +231,8 @@ double PhotoDisintegration::lossLength(int id, double E, double z) { // check if disintegration data available if ((Z > 26) or (N > 30)) return std::numeric_limits::max(); - std::vector pdModes = pdTable[Z * 31 + N]; - if (pdModes.size() == 0) + std::vector rate = pdRate[Z * 31 + N]; + if (rate.size() == 0) return std::numeric_limits::max(); // check if in tabulated energy range @@ -198,24 +240,32 @@ double PhotoDisintegration::lossLength(int id, double E, double z) { if ((lg <= lgmin) or (lg >= lgmax)) return std::numeric_limits::max(); - // total rate from all disintegration channels - double lossRate = 0; - for (size_t i = 0; i < pdModes.size(); i++) { + // total interaction rate + double lossRate = interpolateEquidistant(lg, lgmin, lgmax, rate); + + // comological scaling, rate per physical distance + lossRate *= pow(1 + z, 3) * photonFieldScaling(photonField, z); + + // average number of nucleons lost for all disintegration channels + double avg_dA = 0; + std::vector branches = pdBranch[Z * 31 + N]; + for (size_t i = 0; i < branches.size(); i++) { + int channel = branches[i].channel; int dA = 0; - dA += 1 * digit(pdModes[i].channel, 100000); - dA += 1 * digit(pdModes[i].channel, 10000); - dA += 2 * digit(pdModes[i].channel, 1000); - dA += 3 * digit(pdModes[i].channel, 100); - dA += 3 * digit(pdModes[i].channel, 10); - dA += 4 * digit(pdModes[i].channel, 1); - - double rate = interpolateEquidistant(lg, lgmin, lgmax, pdModes[i].rate); - lossRate += rate * dA / A; + dA += 1 * digit(channel, 100000); + dA += 1 * digit(channel, 10000); + dA += 2 * digit(channel, 1000); + dA += 3 * digit(channel, 100); + dA += 3 * digit(channel, 10); + dA += 4 * digit(channel, 1); + + double br = interpolateEquidistant(lg, lgmin, lgmax, + branches[i].branchingRatio); + avg_dA += br * dA; } - // comological scaling of interaction distance (in physical units) - lossRate *= pow(1 + z, 3) * photonFieldScaling(photonField, z); - return 1. / lossRate; + lossRate *= avg_dA / A; + return 1 / lossRate; } } // namespace crpropa From 19147a71922478cf837d1a11d132ee2982f95efa Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 1 Aug 2014 10:15:55 +0200 Subject: [PATCH 0452/1298] fix new Observer scheme --- include/crpropa/module/Observer.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/crpropa/module/Observer.h b/include/crpropa/module/Observer.h index 293bc874d..dee2d6a47 100644 --- a/include/crpropa/module/Observer.h +++ b/include/crpropa/module/Observer.h @@ -21,7 +21,7 @@ class ObserverFeature: public Referenced { @class Observer @brief General cosmic ray observer */ -class Observer: public Referenced { +class Observer: public Module { private: std::vector > features; bool makeInactive; @@ -47,7 +47,7 @@ class ObserverSmallSphere: public ObserverFeature { }; /** - @class ObserverSmallSphere + @class ObserverLargeSphere @brief Detects particles upon exiting a sphere */ class ObserverLargeSphere: public ObserverFeature { @@ -60,8 +60,8 @@ class ObserverLargeSphere: public ObserverFeature { }; /** - @class ObserverSmallSphere - @brief Detects particles upon exiting a sphere + @class ObserverRedshiftWindow + @brief Detects particles in a given redshift window */ class ObserverRedshiftWindow: public ObserverFeature { private: From e94e5cf1ac158450527b05333c3d49e580bf7c46 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 1 Aug 2014 10:38:19 +0200 Subject: [PATCH 0453/1298] rename SourceProperty to SourceFeature rename Source::addProperty to Source::add --- include/crpropa/Source.h | 52 +++++++++++++++++++------------------- python/crpropa.i | 7 ++--- src/Source.cpp | 14 +++++----- src/XmlExecute.cpp | 24 +++++++++--------- test/testMagneticField.cpp | 2 -- test/testModuleList.cpp | 16 ++++++------ test/testSource.cpp | 22 ++++++++-------- 7 files changed, 68 insertions(+), 69 deletions(-) diff --git a/include/crpropa/Source.h b/include/crpropa/Source.h index 542403647..dc49e65d3 100644 --- a/include/crpropa/Source.h +++ b/include/crpropa/Source.h @@ -9,10 +9,10 @@ namespace crpropa { /** - @class SourceProperty - @brief Abstract class for properties of cosmic ray sources + @class SourceFeature + @brief Abstract base class cosmic ray source features */ -class SourceProperty: public Referenced { +class SourceFeature: public Referenced { public: virtual void prepareParticle(ParticleState& particle) const; virtual void prepareCandidate(Candidate& candidate) const; @@ -27,9 +27,9 @@ class SourceProperty: public Referenced { to be modified accordingly. */ class Source: public Referenced { - std::vector > properties; + std::vector > features; public: - void addProperty(SourceProperty* property); + void add(SourceFeature* feature); ref_ptr getCandidate() const; }; @@ -44,7 +44,7 @@ class SourceList: public Source { std::vector > sources; std::vector cdf; public: - void addSource(Source* source, double weight = 1); + void add(Source* source, double weight = 1); ref_ptr getCandidate() const; }; @@ -52,7 +52,7 @@ class SourceList: public Source { @class SourceParticleType @brief Particle type at the source */ -class SourceParticleType: public SourceProperty { +class SourceParticleType: public SourceFeature { double id; public: SourceParticleType(int id); @@ -63,7 +63,7 @@ class SourceParticleType: public SourceProperty { @class SourceMultipleParticleTypes @brief Multiple particle types with individual relative abundances */ -class SourceMultipleParticleTypes: public SourceProperty { +class SourceMultipleParticleTypes: public SourceFeature { std::vector particleTypes; std::vector cdf; public: @@ -75,7 +75,7 @@ class SourceMultipleParticleTypes: public SourceProperty { @class SourceEnergy @brief Sets the initial energy to a given value */ -class SourceEnergy: public SourceProperty { +class SourceEnergy: public SourceFeature { double E; public: SourceEnergy(double energy); @@ -86,7 +86,7 @@ class SourceEnergy: public SourceProperty { @class SourcePowerLawSpectrum @brief Particle energy following a power law spectrum */ -class SourcePowerLawSpectrum: public SourceProperty { +class SourcePowerLawSpectrum: public SourceFeature { double Emin; double Emax; double index; @@ -101,7 +101,7 @@ class SourcePowerLawSpectrum: public SourceProperty { See Allard et al. 2006, DOI 10.1088/1475-7516/2006/09/005 */ -class SourceComposition: public SourceProperty { +class SourceComposition: public SourceFeature { double Emin; double Rmax; double index; @@ -119,7 +119,7 @@ class SourceComposition: public SourceProperty { @class SourceGenericComposition @brief Multiple nuclei with energies described by an expression string */ -class SourceGenericComposition: public SourceProperty { +class SourceGenericComposition: public SourceFeature { struct Nucleus { int id; std::vector cdf; @@ -144,7 +144,7 @@ class SourceGenericComposition: public SourceProperty { @class SourcePosition @brief Position of a point source */ -class SourcePosition: public SourceProperty { +class SourcePosition: public SourceFeature { Vector3d position; /**< Source position */ public: SourcePosition(Vector3d position); @@ -155,7 +155,7 @@ class SourcePosition: public SourceProperty { @class SourceMultiplePositions @brief Multiple point source positions with individual luminosities */ -class SourceMultiplePositions: public SourceProperty { +class SourceMultiplePositions: public SourceFeature { std::vector positions; std::vector cdf; public: @@ -167,7 +167,7 @@ class SourceMultiplePositions: public SourceProperty { @class SourceUniformSphere @brief Uniform random source positions inside a sphere */ -class SourceUniformSphere: public SourceProperty { +class SourceUniformSphere: public SourceFeature { Vector3d center; double radius; public: @@ -179,7 +179,7 @@ class SourceUniformSphere: public SourceProperty { @class SourceUniformShell @brief Uniform random source positions on a sphere */ -class SourceUniformShell: public SourceProperty { +class SourceUniformShell: public SourceFeature { Vector3d center; double radius; public: @@ -191,7 +191,7 @@ class SourceUniformShell: public SourceProperty { @class SourceUniformBox @brief Uniform random source positions inside a box */ -class SourceUniformBox: public SourceProperty { +class SourceUniformBox: public SourceFeature { Vector3d origin; Vector3d size; public: @@ -212,7 +212,7 @@ class SourceUniformBox: public SourceProperty { This is done by drawing a light travel distance from a flat distribution and converting to a comoving distance. */ -class SourceUniform1D: public SourceProperty { +class SourceUniform1D: public SourceFeature { double minD; // minimum light travel distance double maxD; // maximum light travel distance bool withCosmology; @@ -230,7 +230,7 @@ class SourceUniform1D: public SourceProperty { @class SourceDensityGrid @brief Random source positions from a density grid */ -class SourceDensityGrid: public SourceProperty { +class SourceDensityGrid: public SourceFeature { ref_ptr grid; public: SourceDensityGrid(ref_ptr densityGrid); @@ -241,7 +241,7 @@ class SourceDensityGrid: public SourceProperty { @class SourceDensityGrid1D @brief Random source positions from a 1D density grid */ -class SourceDensityGrid1D: public SourceProperty { +class SourceDensityGrid1D: public SourceFeature { ref_ptr grid; public: SourceDensityGrid1D(ref_ptr densityGrid); @@ -252,7 +252,7 @@ class SourceDensityGrid1D: public SourceProperty { @class SourceIsotropicEmission @brief Isotropic emission from a source */ -class SourceIsotropicEmission: public SourceProperty { +class SourceIsotropicEmission: public SourceFeature { public: void prepareParticle(ParticleState &particle) const; }; @@ -261,7 +261,7 @@ class SourceIsotropicEmission: public SourceProperty { @class SourceDirection @brief Emission in a discrete direction */ -class SourceDirection: public SourceProperty { +class SourceDirection: public SourceFeature { Vector3d direction; public: SourceDirection(Vector3d direction = Vector3d(-1, 0, 0)); @@ -272,7 +272,7 @@ class SourceDirection: public SourceProperty { @class SourceEmissionCone @brief Uniform random emission inside a cone */ -class SourceEmissionCone: public SourceProperty { +class SourceEmissionCone: public SourceFeature { Vector3d direction; double aperture; public: @@ -284,7 +284,7 @@ class SourceEmissionCone: public SourceProperty { @class SourceRedshift @brief Discrete redshift (time of emission) */ -class SourceRedshift: public SourceProperty { +class SourceRedshift: public SourceFeature { double z; public: SourceRedshift(double z); @@ -295,7 +295,7 @@ class SourceRedshift: public SourceProperty { @class SourceUniformRedshift @brief Uniform redshift distribution (time of emission) */ -class SourceUniformRedshift: public SourceProperty { +class SourceUniformRedshift: public SourceFeature { double zmin, zmax; public: SourceUniformRedshift(double zmin, double zmax); @@ -309,7 +309,7 @@ class SourceUniformRedshift: public SourceProperty { This source property sets the redshift according to the distance to 0. It must be added after a position setting source property. */ -class SourceRedshift1D: public SourceProperty { +class SourceRedshift1D: public SourceFeature { public: void prepareCandidate(Candidate &candidate) const; }; diff --git a/python/crpropa.i b/python/crpropa.i index 81fd765b2..f4ac0e474 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -92,7 +92,7 @@ using std::ptrdiff_t; %ignore operator>>; %ignore *::operator=; %ignore operator crpropa::Source*; -%ignore operator crpropa::SourceProperty*; +%ignore operator crpropa::SourceFeature*; %ignore operator crpropa::Candidate*; %ignore operator crpropa::Module*; %ignore operator crpropa::ModuleList*; @@ -168,9 +168,10 @@ using std::ptrdiff_t; %template(SourceRefPtr) crpropa::ref_ptr; %feature("director") crpropa::Source; -%template(SourcePropertyRefPtr) crpropa::ref_ptr; -%feature("director") crpropa::SourceProperty; +%template(SourceFeatureRefPtr) crpropa::ref_ptr; +%feature("director") crpropa::SourceFeature; %include "crpropa/Source.h" + %template(ModuleListRefPtr) crpropa::ref_ptr; %include "crpropa/ModuleList.h" diff --git a/src/Source.cpp b/src/Source.cpp index 6c9445e53..dc160a7b1 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -12,10 +12,10 @@ namespace crpropa { -void SourceProperty::prepareParticle(ParticleState& particle) const { +void SourceFeature::prepareParticle(ParticleState& particle) const { } -void SourceProperty::prepareCandidate(Candidate& candidate) const { +void SourceFeature::prepareCandidate(Candidate& candidate) const { ParticleState &source = candidate.source; prepareParticle(source); candidate.created = source; @@ -23,18 +23,18 @@ void SourceProperty::prepareCandidate(Candidate& candidate) const { candidate.previous = source; } -void Source::addProperty(SourceProperty* property) { - properties.push_back(property); +void Source::add(SourceFeature* property) { + features.push_back(property); } ref_ptr Source::getCandidate() const { ref_ptr candidate = new Candidate(); - for (int i = 0; i < properties.size(); i++) - (*properties[i]).prepareCandidate(*candidate); + for (int i = 0; i < features.size(); i++) + (*features[i]).prepareCandidate(*candidate); return candidate; } -void SourceList::addSource(Source* source, double weight) { +void SourceList::add(Source* source, double weight) { sources.push_back(source); if (cdf.size() > 0) weight += cdf.back(); diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 2e75b6ac1..5700ad4fa 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -271,7 +271,7 @@ bool XmlExecute::load(const string &filename) { // emission direction if (!is1D) - source.addProperty(new SourceIsotropicEmission()); + source.add(new SourceIsotropicEmission()); // position type = node.attribute("type").as_string(); @@ -285,7 +285,7 @@ bool XmlExecute::load(const string &filename) { if (is1D and hasRedshift) { cout << " - Redshift according to source distance" << endl; - source.addProperty(new SourceRedshift1D()); + source.add(new SourceRedshift1D()); } // spectrum + composition @@ -536,7 +536,7 @@ void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { int nSources = childValue(node, "Number"); cout << " - Number of sources = " << nSources << endl; - ref_ptr sourceDistribution = new SourceProperty(); + ref_ptr sourceDistribution = new SourceFeature(); if (type == "Uniform") { if (is1D) { double xmin = childValue(density_node, "Xmin_Mpc") * Mpc; @@ -583,7 +583,7 @@ void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { sourcePositions->add(pos); } } - source.addProperty(sourcePositions); + source.add(sourcePositions); } void XmlExecute::loadContinuousSources(pugi::xml_node &node) { @@ -600,15 +600,15 @@ void XmlExecute::loadContinuousSources(pugi::xml_node &node) { << " Mpc" << endl; minD = lightTravel2ComovingDistance(minD); maxD = lightTravel2ComovingDistance(maxD); - source.addProperty(new SourceUniform1D(minD, maxD)); + source.add(new SourceUniform1D(minD, maxD)); } else { - source.addProperty(loadSourceHomogeneousBox(density_node)); + source.add(loadSourceHomogeneousBox(density_node)); } else if (type == "Grid") { if (is1D) { - source.addProperty(loadSourceDensityGrid1D(density_node)); + source.add(loadSourceDensityGrid1D(density_node)); } else - source.addProperty(loadSourceDensityGrid(density_node)); + source.add(loadSourceDensityGrid(density_node)); } else { throw runtime_error(" --> unknown source density type"); } @@ -623,7 +623,7 @@ void XmlExecute::loadSpectrumComposition(pugi::xml_node &node) { if (spectrum_node.child("Energy_EeV")) { double E = childValue(spectrum_node, "Energy_EeV") * EeV; cout << " - Energy: " << E / EeV << " EeV" << endl; - source.addProperty(new SourceEnergy(E)); + source.add(new SourceEnergy(E)); } else if (spectrum_node.child("Rigidity_EeV")) throw runtime_error(" --> Fixed rigidity not implemented"); else { @@ -653,13 +653,13 @@ void XmlExecute::loadSpectrumComposition(pugi::xml_node &node) { << ", abundance = " << ab << endl; comp->add(nucleusId(A, Z), ab); } - source.addProperty(comp); + source.add(comp); } else if (spectrum_node.child("Ecut_EeV")) { double Emax = childValue(spectrum_node, "Ecut_EeV") * EeV; cout << " - Maximum energy: " << Emax / EeV << " EeV" << endl; // source spectrum - source.addProperty(new SourcePowerLawSpectrum(Emin, Emax, alpha)); + source.add(new SourcePowerLawSpectrum(Emin, Emax, alpha)); // source composition loadSourceNuclei(node); @@ -684,7 +684,7 @@ void XmlExecute::loadSourceNuclei(pugi::xml_node &node) { << ab << endl; composition->add(nucleusId(A, Z), ab); } - source.addProperty(composition); + source.add(composition); } void XmlExecute::loadOutput(xml_node &node) { diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index c53f105ad..0ea32c821 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -120,8 +120,6 @@ TEST(testTurbulentMagneticField, Brms) { } Bmean /= pow(n, 3); double Brms = sqrt(sumB2 / pow(n, 3)); - std::cout << Brms << std::endl; - std::cout << Bmean << std::endl; // this turbulent field realization is not working at the moment // EXPECT_NEAR(Bmean.x, 0, 1e-6); diff --git a/test/testModuleList.cpp b/test/testModuleList.cpp index efe9a6b4f..65ea38b6c 100644 --- a/test/testModuleList.cpp +++ b/test/testModuleList.cpp @@ -31,10 +31,10 @@ TEST(ModuleList, runSource) { modules.add(new SimplePropagation()); modules.add(new MaximumTrajectoryLength(1 * Mpc)); Source source; - source.addProperty(new SourcePosition(Vector3d(10, 0, 0) * Mpc)); - source.addProperty(new SourceIsotropicEmission()); - source.addProperty(new SourcePowerLawSpectrum(5 * EeV, 100 * EeV, -2)); - source.addProperty(new SourceParticleType(nucleusId(1, 1))); + source.add(new SourcePosition(Vector3d(10, 0, 0) * Mpc)); + source.add(new SourceIsotropicEmission()); + source.add(new SourcePowerLawSpectrum(5 * EeV, 100 * EeV, -2)); + source.add(new SourceParticleType(nucleusId(1, 1))); modules.setShowProgress(true); modules.run(&source, 100, false); } @@ -46,10 +46,10 @@ TEST(ModuleList, runOpenMP) { modules.add(new SimplePropagation()); modules.add(new MaximumTrajectoryLength(1 * Mpc)); Source source; - source.addProperty(new SourcePosition(Vector3d(10, 0, 0) * Mpc)); - source.addProperty(new SourceIsotropicEmission()); - source.addProperty(new SourcePowerLawSpectrum(5 * EeV, 100 * EeV, -2)); - source.addProperty(new SourceParticleType(nucleusId(1, 1))); + source.add(new SourcePosition(Vector3d(10, 0, 0) * Mpc)); + source.add(new SourceIsotropicEmission()); + source.add(new SourcePowerLawSpectrum(5 * EeV, 100 * EeV, -2)); + source.add(new SourceParticleType(nucleusId(1, 1))); omp_set_num_threads(2); modules.run(&source, 1000, false); } diff --git a/test/testSource.cpp b/test/testSource.cpp index d094dc82c..d93062221 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -236,11 +236,11 @@ TEST(SourceComposition, throwNoIsotope) { TEST(Source, allPropertiesUsed) { Source source; - source.addProperty(new SourcePosition(Vector3d(10, 0, 0) * Mpc)); - source.addProperty(new SourceIsotropicEmission()); - source.addProperty(new SourcePowerLawSpectrum(5 * EeV, 100 * EeV, -2)); - source.addProperty(new SourceParticleType(nucleusId(8, 4))); - source.addProperty(new SourceRedshift(2)); + source.add(new SourcePosition(Vector3d(10, 0, 0) * Mpc)); + source.add(new SourceIsotropicEmission()); + source.add(new SourcePowerLawSpectrum(5 * EeV, 100 * EeV, -2)); + source.add(new SourceParticleType(nucleusId(8, 4))); + source.add(new SourceRedshift(2)); Candidate c = *source.getCandidate(); @@ -277,8 +277,8 @@ TEST(SourceList, simpleTest) { // test if source list works with one source SourceList sourceList; ref_ptr source = new Source; - source->addProperty(new SourcePosition(Vector3d(10, 0, 0))); - sourceList.addSource(source); + source->add(new SourcePosition(Vector3d(10, 0, 0))); + sourceList.add(source); ref_ptr c = sourceList.getCandidate(); @@ -298,12 +298,12 @@ TEST(SourceList, luminosity) { SourceList sourceList; ref_ptr source1 = new Source; - source1->addProperty(new SourceEnergy(100)); - sourceList.addSource(source1, 80); + source1->add(new SourceEnergy(100)); + sourceList.add(source1, 80); ref_ptr source2 = new Source; - source2->addProperty(new SourceEnergy(0)); - sourceList.addSource(source2, 20); + source2->add(new SourceEnergy(0)); + sourceList.add(source2, 20); double meanE = 0; for (int i = 0; i < 1000; i++) { From 9da07a92f207f0f97813b4b72f9a287b0d0a6014 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 1 Aug 2014 11:52:16 +0200 Subject: [PATCH 0454/1298] replace some == 0 against < numeric_limits::min() --- src/module/Observer.cpp | 3 ++- src/module/Redshift.cpp | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp index 33060a784..e9cffc9c8 100644 --- a/src/module/Observer.cpp +++ b/src/module/Observer.cpp @@ -349,7 +349,8 @@ Observer1D::Observer1D() { void Observer1D::process(Candidate *candidate) const { double x = candidate->current.getPosition().x; - if (x > 0) { + // check if position x > 0 + if (x > std::numeric_limits::min()) { candidate->limitNextStep(x); return; } diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index 4119e000e..55e17efdf 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -1,14 +1,16 @@ #include "crpropa/module/Redshift.h" #include "crpropa/Cosmology.h" -#include +#include namespace crpropa { void Redshift::process(Candidate *c) const { double z = c->getRedshift(); - if (z <= 0) - return; // nothing to do, redshift can't get smaller + + // check if z = 0 + if (z <= std::numeric_limits::min()) + return; // use small step approximation: dz = H(z) / c * ds double dz = hubbleRate(z) / c_light * c->getCurrentStep(); From 265e08a4ea8027e3a31e6b6fbdfda1ea5381478e Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sat, 2 Aug 2014 17:33:56 +0200 Subject: [PATCH 0455/1298] CMakeLists: adding XmlExecute.cpp to CRPROPA_SOURCES breaks the unit tests As globbing is not recommended for the source files, return to listing all source files --- CMakeLists.txt | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d667f2521..f121c02f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -129,9 +129,46 @@ endif(GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) # Library and Binary # ---------------------------------------------------------------------------- include_directories(include ${CRPROPA_EXTRA_INCLUDES}) -file(GLOB_RECURSE CRPROPA_SOURCES "${CMAKE_SOURCE_DIR}/src/*.cpp") + add_library(crpropa SHARED - ${CRPROPA_SOURCES} + src/Random.cpp + src/Clock.cpp + src/ModuleList.cpp + src/Module.cpp + src/Candidate.cpp + src/ParticleState.cpp + src/ParticleID.cpp + src/ParticleMass.cpp + src/Cosmology.cpp + src/Source.cpp + src/Common.cpp + src/PhotonBackground.cpp + src/PhotonPropagation.cpp + src/GridTools.cpp + src/XmlExecute.cpp + src/module/BreakCondition.cpp + src/module/Boundary.cpp + src/module/Observer.cpp + src/module/SimplePropagation.cpp + src/module/PropagationCK.cpp + src/module/ElectronPairProduction.cpp + src/module/NuclearDecay.cpp + src/module/PhotoPionProduction.cpp + src/module/PhotoDisintegration.cpp + src/module/Redshift.cpp + src/module/OutputTXT.cpp + src/module/OutputShell.cpp + src/module/OutputROOT.cpp + src/module/OutputCRPropa2.cpp + src/module/PhotonOutput1D.cpp + src/module/PhotonDINT.cpp + src/module/PhotonDINT1D.cpp + src/module/PhotonEleCa.cpp + src/module/Tools.cpp + src/magneticField/MagneticField.cpp + src/magneticField/MagneticFieldGrid.cpp + src/magneticField/TurbulentMagneticField.cpp + src/magneticField/JF12Field.cpp ${CRPROPA_EXTRA_SOURCES} ) target_link_libraries(crpropa ${CRPROPA_EXTRA_LIBRARIES}) From 1a534d7485fc7842b7f5f75dd083d0d8ae24672f Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sat, 2 Aug 2014 19:17:30 +0200 Subject: [PATCH 0456/1298] refactoring PD and EPP --- .../crpropa/module/ElectronPairProduction.h | 4 ++- include/crpropa/module/PhotoDisintegration.h | 7 +++-- src/PhotonBackground.cpp | 1 - src/module/ElectronPairProduction.cpp | 22 ++++++++------- src/module/PhotoDisintegration.cpp | 27 ++++++++++--------- 5 files changed, 34 insertions(+), 27 deletions(-) diff --git a/include/crpropa/module/ElectronPairProduction.h b/include/crpropa/module/ElectronPairProduction.h index d8d5a301d..b67e55786 100644 --- a/include/crpropa/module/ElectronPairProduction.h +++ b/include/crpropa/module/ElectronPairProduction.h @@ -32,9 +32,11 @@ class ElectronPairProduction: public Module { public: ElectronPairProduction(PhotonField photonField = CMB, bool haveElectrons = false, double limit = 0.1); + void setPhotonField(PhotonField photonField); void setHaveElectrons(bool haveElectrons); - void init(); + void setLimit(double limit); + void initRate(std::string filename); void initSpectrum(std::string filename); void process(Candidate *candidate) const; diff --git a/include/crpropa/module/PhotoDisintegration.h b/include/crpropa/module/PhotoDisintegration.h index 26828da91..46d04bb4b 100644 --- a/include/crpropa/module/PhotoDisintegration.h +++ b/include/crpropa/module/PhotoDisintegration.h @@ -30,10 +30,13 @@ class PhotoDisintegration: public Module { public: PhotoDisintegration(PhotonField photonField = CMB, double limit = 0.1); - void setLimit(double l); - void init(PhotonField photonField); + + void setPhotonField(PhotonField photonField); + void setLimit(double limit); + void initRate(std::string filename); void initBranching(std::string filename); + void process(Candidate *candidate) const; void performInteraction(Candidate *candidate, int channel) const; diff --git a/src/PhotonBackground.cpp b/src/PhotonBackground.cpp index 788d13a3f..4cc8d4ffb 100644 --- a/src/PhotonBackground.cpp +++ b/src/PhotonBackground.cpp @@ -2,7 +2,6 @@ #include "crpropa/Common.h" #include -#include #include namespace crpropa { diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 37b7b4a96..3370c8c77 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -10,22 +10,13 @@ namespace crpropa { ElectronPairProduction::ElectronPairProduction(PhotonField photonField, bool haveElectrons, double limit) { - this->photonField = photonField; + setPhotonField(photonField); this->haveElectrons = haveElectrons; this->limit = limit; - init(); } void ElectronPairProduction::setPhotonField(PhotonField photonField) { this->photonField = photonField; - init(); -} - -void ElectronPairProduction::setHaveElectrons(bool haveElectrons) { - this->haveElectrons = haveElectrons; -} - -void ElectronPairProduction::init() { switch (photonField) { case CMB: setDescription("ElectronPairProduction: CMB"); @@ -59,6 +50,14 @@ void ElectronPairProduction::init() { } } +void ElectronPairProduction::setHaveElectrons(bool haveElectrons) { + this->haveElectrons = haveElectrons; +} + +void ElectronPairProduction::setLimit(double limit) { + this->limit = limit; +} + void ElectronPairProduction::initRate(std::string filename) { std::ifstream infile(filename.c_str()); @@ -179,6 +178,9 @@ void ElectronPairProduction::process(Candidate *c) const { double lf = c->current.getLorentzFactor(); double z = c->getRedshift(); double losslen = lossLength(id, lf, z); // energy loss length + if (losslen >= std::numeric_limits::max()) + return; + double step = c->getCurrentStep() / (1 + z); // step size in local frame double loss = step / losslen; // relative energy loss diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 90051aee8..bbcd03d4b 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -10,42 +10,39 @@ namespace crpropa { -PhotoDisintegration::PhotoDisintegration(PhotonField photonField, double l) { - limit = l; - init(photonField); +PhotoDisintegration::PhotoDisintegration(PhotonField f, double limit) { + setPhotonField(f); + this->limit = limit; } -void PhotoDisintegration::setLimit(double l) { - limit = l; -} - -void PhotoDisintegration::init(PhotonField photonField) { +void PhotoDisintegration::setPhotonField(PhotonField photonField) { + this->photonField = photonField; switch (photonField) { case CMB: setDescription("PhotoDisintegration: CMB"); initRate(getDataPath("pd_CMB.txt")); - initBranching(getDataPath("pd_branch_CMB.txt")); + initBranching(getDataPath("pd_branching_CMB.txt")); break; case IRB: // default: Kneiske '04 IRB model case IRB_Kneiske04: setDescription("PhotoDisintegration: IRB Kneiske '04"); initRate(getDataPath("pd_IRB_Kneiske04.txt")); - initBranching(getDataPath("pd_branch_IRB_Kneiske04.txt")); + initBranching(getDataPath("pd_branching_IRB_Kneiske04.txt")); break; case IRB_Kneiske10: setDescription("PhotoDisintegration: IRB Kneiske '10 (lower limit)"); initRate(getDataPath("pd_IRB_Kneiske10.txt")); - initBranching(getDataPath("pd_branch_IRB_Kneiske04.txt")); + initBranching(getDataPath("pd_branching_IRB_Kneiske04.txt")); break; case IRB_Stecker05: setDescription("PhotoDisintegration: IRB Stecker '05"); initRate(getDataPath("pd_IRB_Stecker05.txt")); - initBranching(getDataPath("pd_branch_IRB_Kneiske04.txt")); + initBranching(getDataPath("pd_branching_IRB_Kneiske04.txt")); break; case IRB_Franceschini08: setDescription("PhotoDisintegration: IRB Franceschini '08"); initRate(getDataPath("pd_IRB_Franceschini08.txt")); - initBranching(getDataPath("pd_branch_IRB_Kneiske04.txt")); + initBranching(getDataPath("pd_branching_IRB_Kneiske04.txt")); break; default: throw std::runtime_error( @@ -53,6 +50,10 @@ void PhotoDisintegration::init(PhotonField photonField) { } } +void PhotoDisintegration::setLimit(double limit) { + this->limit = limit; +} + void PhotoDisintegration::initRate(std::string filename) { std::ifstream infile(filename.c_str()); if (not infile.good()) From 81faf7d1a75e400cb55da5d8fbcc9fca053adc57 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sat, 2 Aug 2014 19:17:56 +0200 Subject: [PATCH 0457/1298] fix testInteractions after changes to various interaction modules --- test/testInteraction.cpp | 75 +++++++++++----------------------------- 1 file changed, 20 insertions(+), 55 deletions(-) diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 6fd81787b..090df4af2 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -131,7 +131,7 @@ TEST(NuclearDecay, scandium44) { double gamma = c.current.getLorentzFactor(); d.process(&c); // primary - EXPECT_EQ(nucleusId(44,20), c.current.getId()); + EXPECT_EQ(nucleusId(44, 20), c.current.getId()); EXPECT_DOUBLE_EQ(gamma, c.current.getLorentzFactor()); // secondaries EXPECT_EQ(2, c.secondaries.size()); @@ -139,7 +139,7 @@ TEST(NuclearDecay, scandium44) { Candidate c2 = *c.secondaries[1]; EXPECT_EQ(-11, c1.current.getId()); // positron - EXPECT_EQ( 12, c2.current.getId()); + EXPECT_EQ(12, c2.current.getId()); // electron neutrino } @@ -153,11 +153,11 @@ TEST(NuclearDecay, lithium4) { c.current.setEnergy(4 * EeV); d.process(&c); // primary - EXPECT_EQ(nucleusId(3,2), c.current.getId()); + EXPECT_EQ(nucleusId(3, 2), c.current.getId()); EXPECT_EQ(1, c.secondaries.size()); // secondary Candidate c1 = *c.secondaries[0]; - EXPECT_EQ(nucleusId(1,1), c1.current.getId()); + EXPECT_EQ(nucleusId(1, 1), c1.current.getId()); EXPECT_EQ(1, c1.current.getEnergy() / EeV); } @@ -171,11 +171,11 @@ TEST(NuclearDecay, helium5) { c.current.setEnergy(5 * EeV); d.process(&c); // primary - EXPECT_EQ(nucleusId(4,2), c.current.getId()); + EXPECT_EQ(nucleusId(4, 2), c.current.getId()); EXPECT_EQ(4, c.current.getEnergy() / EeV); // secondary Candidate c2 = *c.secondaries[0]; - EXPECT_EQ(nucleusId(1,0), c2.current.getId()); + EXPECT_EQ(nucleusId(1, 0), c2.current.getId()); EXPECT_EQ(1, c2.current.getEnergy() / EeV); } @@ -292,7 +292,7 @@ TEST(PhotoDisintegration, iron) { } TEST(PhotoDisintegration, thisIsNotNucleonic) { - // Test if noting happens to an electron + // Test that nothing happens to an electron PhotoDisintegration pd; Candidate c; c.setCurrentStep(1 * Mpc); @@ -314,60 +314,25 @@ TEST(PhotoDisintegration, limitNextStep) { EXPECT_LT(c.getNextStep(), std::numeric_limits::max()); } -TEST(PhotoDisintegration, AllWorkingCMB) { - // Test if all photo-disintegrations are working. - PhotoDisintegration pd(CMB); +TEST(PhotoDisintegration, allIsotopes) { + // Test if all isotopes are handled. + PhotoDisintegration pd1(CMB); + PhotoDisintegration pd2(IRB); Candidate c; + c.setCurrentStep(10 * Mpc); - std::ifstream infile(getDataPath("photodis_CMB.txt").c_str()); - std::string line; - while (std::getline(infile, line)) { - if (line[0] == '#') - continue; - std::stringstream lineStream(line); - int Z, N, channel; - lineStream >> Z >> N >> channel; - - double y; - for (size_t i = 0; i < 200; i++) { - lineStream >> y; - EXPECT_TRUE(lineStream); - // test if all 200 entries are present - } + for (int Z = 1; Z <= 26; Z++) { + for (int N = 1; N <= 30; N++) { - c.current.setId(nucleusId(Z + N, Z)); - c.current.setEnergy(80 * EeV); - pd.process(&c); - } - infile.close(); -} - -TEST(PhotoDisintegration, AllWorkingIRB) { - // Test if all photo-disintegrations are working. - PhotoDisintegration pd(IRB); - Candidate c; + c.current.setId(nucleusId(Z + N, Z)); + c.current.setEnergy(80 * EeV); + pd1.process(&c); - std::ifstream infile(getDataPath("photodis_IRB.txt").c_str()); - std::string line; - while (std::getline(infile, line)) { - if (line[0] == '#') - continue; - std::stringstream lineStream(line); - int Z, N, channel; - lineStream >> Z >> N >> channel; - - double y; - for (size_t i = 0; i < 200; i++) { - lineStream >> y; - EXPECT_TRUE(lineStream); - // test if all 200 entries are present + c.current.setId(nucleusId(Z + N, Z)); + c.current.setEnergy(80 * EeV); + pd2.process(&c); } - - c.current.setId(nucleusId(Z + N, Z)); - c.current.setEnergy(80 * EeV); - pd.process(&c); } - infile.close(); } TEST(PhotoPionProduction, backgrounds) { From 20faf42e2ee0255bd9c68867656f255dd63356b3 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Sun, 3 Aug 2014 13:55:55 +0200 Subject: [PATCH 0458/1298] Use cmake to obtain data files from crpropa.desy.de crpropa-data repository is now obsolete --- .gitignore | 1 + CMakeLists.txt | 84 +++++++++++++++++++++++++++++--------------------- 2 files changed, 50 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index 65e818346..12a56e9bc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ doc/* build/* data/* data-tools/* +data.tar.gz *.png *.pyc diff --git a/CMakeLists.txt b/CMakeLists.txt index f121c02f1..09f448203 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,8 @@ endif(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) # ---------------------------------------------------------------------------- # Dependencies # ---------------------------------------------------------------------------- -# googletest (provided) +# googletest (provided, see https://code.google.com/p/googletest/wiki/FAQ +# Why is it not recommended use a pre-compiled copy of Google Test?) option(ENABLE_TESTING "Build tests and enable test target" ON) if(ENABLE_TESTING) include_directories(libs/gtest/include) @@ -58,6 +59,21 @@ add_subdirectory(libs/EleCa) list(APPEND CRPROPA_EXTRA_LIBRARIES eleca) list(APPEND CRPROPA_EXTRA_INCLUDES libs/EleCa/include) +# ROOT (optional for ROOT output) +option(ENABLE_ROOT "ROOT Output" ON) +if(ENABLE_ROOT) + find_package(ROOT) + if(ROOT_FOUND) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ROOT_CFLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${ROOT_LIBS}") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${ROOT_LIBS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") + add_definitions(-DCRPROPA_HAVE_ROOT) + list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_ROOT) + list(APPEND CRPROPA_EXTRA_LIBRARIES Core RIO Tree) + endif(ROOT_FOUND) +endif(ENABLE_ROOT) + # OpenMP (optional for shared memory multiprocessing) option(ENABLE_OPENMP "OpenMP for multithreading" ON) if(ENABLE_OPENMP) @@ -69,17 +85,22 @@ include(FindOpenMP) endif(OPENMP_FOUND) endif(ENABLE_OPENMP) -# fftw3f (optional for turbulent magnetic fields) -option(ENABLE_FFTW3F "FFTW3F to create turbulent fields" ON) -if(ENABLE_FFTW3F) - find_package(FFTW3F) - if(FFTW3F_FOUND) - list(APPEND CRPROPA_EXTRA_INCLUDES ${FFTW3F_INCLUDE_DIR}) - list(APPEND CRPROPA_EXTRA_LIBRARIES ${FFTW3F_LIBRARY}) - add_definitions(-DCRPROPA_HAVE_FFTW3F) - list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_FFTW3F) - endif(FFTW3F_FOUND) -endif(ENABLE_FFTW3F) +# Google Performance Tools (optional as possible performance tweak for OpenMP) +find_package(GooglePerfTools) +set(TCMALLOC) +if(GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) + set(TCMALLOC ${TCMALLOC_LIBRARY}) + list(APPEND CRPROPA_EXTRA_LIBRARIES profiler) +endif(GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) + +# FFTW3F (optional for turbulent magnetic fields) +find_package(FFTW3F) +if(FFTW3F_FOUND) + list(APPEND CRPROPA_EXTRA_INCLUDES ${FFTW3F_INCLUDE_DIR}) + list(APPEND CRPROPA_EXTRA_LIBRARIES ${FFTW3F_LIBRARY}) + add_definitions(-DCRPROPA_HAVE_FFTW3F) + list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_FFTW3F) +endif(FFTW3F_FOUND) # Quimby (optional for SPH magnetic fields) find_package(Quimby) @@ -92,21 +113,7 @@ if(QUIMBY_FOUND) list(APPEND CRPROPA_SWIG_DEFINES -I${QUIMBY_INCLUDE_DIR}) endif(QUIMBY_FOUND) -# ROOT (optional for ROOT output) -option(ENABLE_ROOT "ROOT Output" ON) -if(ENABLE_ROOT) - find_package(ROOT) - if(ROOT_FOUND) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ROOT_CFLAGS}") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${ROOT_LIBS}") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${ROOT_LIBS}") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ROOT_LIBS}") - add_definitions(-DCRPROPA_HAVE_ROOT) - list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_ROOT) - list(APPEND CRPROPA_EXTRA_LIBRARIES Core RIO Tree) - endif(ROOT_FOUND) -endif(ENABLE_ROOT) - +# muparser (optional for genercic source spectra) find_package(muParser) if(MUPARSER_FOUND) list(APPEND CRPROPA_EXTRA_INCLUDES ${MUPARSER_INCLUDE_DIR}) @@ -116,14 +123,21 @@ if(MUPARSER_FOUND) list(APPEND CRPROPA_SWIG_DEFINES -I${MUPARSER_INCLUDE_DIR}) endif(MUPARSER_FOUND) - -# Google Performance Tools (optional as possible performance tweak) -find_package(GooglePerfTools) -set(TCMALLOC) -if(GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) - set(TCMALLOC ${TCMALLOC_LIBRARY}) - list(APPEND CRPROPA_EXTRA_LIBRARIES profiler) -endif(GOOGLE_PERFTOOLS_FOUND AND NOT NO_TCMALLOC) +# ---------------------------------------------------------------------------- +# Downloading data files (interaction data, masses, decay times) +# ---------------------------------------------------------------------------- +# download specific data file (called with cmake) +message("Downloading data files from crpropa.desy.de ~ 30 MB") +file(DOWNLOAD https://crpropa.desy.de/images/f/ff/Data20140803.tar.gz + ${CMAKE_SOURCE_DIR}/data.tar.gz STATUS status + EXPECTED_MD5 1f0016cf3b1cf31250293de08d7fe759) +message("Download complete: ${status}") +file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/data) +# extract (called on make) +execute_process( + COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_SOURCE_DIR}/data.tar.gz + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/data +) # ---------------------------------------------------------------------------- # Library and Binary From b6cfc61739ceaff53235c08de907360caf2a5241 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 7 Aug 2014 10:40:42 +0200 Subject: [PATCH 0459/1298] download data files with wget for CMake <= 2.6 --- CMakeLists.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 09f448203..04cb2e00b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,18 +126,18 @@ endif(MUPARSER_FOUND) # ---------------------------------------------------------------------------- # Downloading data files (interaction data, masses, decay times) # ---------------------------------------------------------------------------- -# download specific data file (called with cmake) +set(DATA_URL "http://crpropa.desy.de/images/f/ff/Data20140803.tar.gz") +set(DATA_MD5SUM "1f0016cf3b1cf31250293de08d7fe759") message("Downloading data files from crpropa.desy.de ~ 30 MB") -file(DOWNLOAD https://crpropa.desy.de/images/f/ff/Data20140803.tar.gz - ${CMAKE_SOURCE_DIR}/data.tar.gz STATUS status - EXPECTED_MD5 1f0016cf3b1cf31250293de08d7fe759) +if(CMAKE_VERSION GREATER 2.6) + file(DOWNLOAD ${DATA_URL} ${CMAKE_SOURCE_DIR}/data.tar.gz STATUS status EXPECTED_MD5 ${DATA_MD5SUM}) +else() + execute_process(COMMAND wget ${DATA_URL} -O ${CMAKE_SOURCE_DIR}/data.tar.gz --no-check-certificate RESULT_VARIABLE status) +endif(CMAKE_VERSION GREATER 2.6) message("Download complete: ${status}") + file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/data) -# extract (called on make) -execute_process( - COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_SOURCE_DIR}/data.tar.gz - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/data -) +execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_SOURCE_DIR}/data.tar.gz WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/data) # ---------------------------------------------------------------------------- # Library and Binary From 985cd0c981598150ed295d69f3ffb62b8cbb0765 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Wed, 13 Aug 2014 13:08:54 +0200 Subject: [PATCH 0460/1298] Fixed wrong name of eleca data --- src/module/PhotonEleCa.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/module/PhotonEleCa.cpp b/src/module/PhotonEleCa.cpp index b3c10659f..0ef02d247 100644 --- a/src/module/PhotonEleCa.cpp +++ b/src/module/PhotonEleCa.cpp @@ -11,7 +11,8 @@ namespace crpropa { PhotonEleCa::PhotonEleCa(const std::string background, const std::string &filename) : propagation(new eleca::Propagation), saveOnlyPhotonEnergies(false) { - propagation->ReadTables(getDataPath("eleca_lee.txt")); + //propagation->ReadTables(getDataPath("eleca_lee.txt")); + propagation->ReadTables(getDataPath("EleCa/eleca.dat")); propagation->InitBkgArray(background); output.open(filename.c_str()); } From 77ec6b1f3f6047dcf423ce697d5714f3307e07d7 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Wed, 13 Aug 2014 13:09:12 +0200 Subject: [PATCH 0461/1298] Fixed hardcoded min energy --- src/PhotonPropagation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhotonPropagation.cpp b/src/PhotonPropagation.cpp index f206e2c27..d5a7d821b 100644 --- a/src/PhotonPropagation.cpp +++ b/src/PhotonPropagation.cpp @@ -28,7 +28,7 @@ void EleCaPropagation(const std::string &inputfile, energy.resize(steps); spectrum.resize(steps); for (size_t i = 0; i < steps; i++) { - energy[i] = 16 + i * step; + energy[i] = emin + i * step; spectrum[i] = 0; } From 7ddb8588a00619a89495590ff5ba9641e65f913d Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 14 Aug 2014 13:35:38 +0200 Subject: [PATCH 0462/1298] CMake info message about file download --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 04cb2e00b..4536cd85c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,6 +135,7 @@ else() execute_process(COMMAND wget ${DATA_URL} -O ${CMAKE_SOURCE_DIR}/data.tar.gz --no-check-certificate RESULT_VARIABLE status) endif(CMAKE_VERSION GREATER 2.6) message("Download complete: ${status}") +message("If the download failed, please manually obtain the file from " ${DATA_URL} " and extract to ./data before 'make install'") file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/data) execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_SOURCE_DIR}/data.tar.gz WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/data) From 96bd662dab063dbeb6a0e55dc42a107e0f60ffd2 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Wed, 20 Aug 2014 09:29:14 +0200 Subject: [PATCH 0463/1298] Eleca: Remove hardcoding of lower energy threshold --- include/crpropa/PhotonPropagation.h | 8 ++++++-- libs/EleCa/include/EleCa/Propagation.h | 2 +- src/PhotonPropagation.cpp | 11 +++++++---- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/include/crpropa/PhotonPropagation.h b/include/crpropa/PhotonPropagation.h index 74a06c24f..2ad2920a1 100644 --- a/include/crpropa/PhotonPropagation.h +++ b/include/crpropa/PhotonPropagation.h @@ -8,9 +8,13 @@ namespace crpropa { void EleCaPropagation(const std::string &inputfile, const std::string &background, std::vector &energy, - std::vector &spectrum); + std::vector &spectrum, + double lowerEnergyThreshold = 1E16 + ); void EleCaPropagation(const std::string &inputfile, - const std::string &outputfile, const std::string &background = "ALL"); + const std::string &outputfile, + double lowerEnergyThreshold = 1E16, + const std::string &background = "ALL"); void DintPropagation(const std::string &inputfile, const std::string &outputfile, int IRFlag = 2, int RadioFlag = 2, double Zmax = 5); diff --git a/libs/EleCa/include/EleCa/Propagation.h b/libs/EleCa/include/EleCa/Propagation.h index 0f04f17a8..114765a39 100644 --- a/libs/EleCa/include/EleCa/Propagation.h +++ b/libs/EleCa/include/EleCa/Propagation.h @@ -27,7 +27,7 @@ class Propagation { Propagation(); - void SetEthr(double eth); + void SetEthr(double eth) {fEthr = eth;}; double GetEthr(); ~Propagation(); diff --git a/src/PhotonPropagation.cpp b/src/PhotonPropagation.cpp index d5a7d821b..355fbd236 100644 --- a/src/PhotonPropagation.cpp +++ b/src/PhotonPropagation.cpp @@ -19,10 +19,12 @@ namespace crpropa { void EleCaPropagation(const std::string &inputfile, const std::string &background, std::vector &energy, - std::vector &spectrum) { + std::vector &spectrum, + double lowerEnergyThreshold + ) { std::ifstream infile(inputfile.c_str()); - const double emin = 16, emax = 22, step = 0.2; + const double emin = log10(lowerEnergyThreshold), emax = 22, step = 0.2; const size_t steps = (emax - emin) / step; energy.clear(); energy.resize(steps); @@ -37,6 +39,7 @@ void EleCaPropagation(const std::string &inputfile, "EleCaPropagation: could not open file " + inputfile); eleca::Propagation propagation; + propagation.SetEthr(lowerEnergyThreshold); propagation.ReadTables(getDataPath("EleCa/eleca.dat")); propagation.InitBkgArray(background); @@ -84,9 +87,9 @@ void EleCaPropagation(const std::string &inputfile, } void EleCaPropagation(const std::string &inputfile, - const std::string &outputfile, const std::string &background) { + const std::string &outputfile, double lowerEnergyThreshold, const std::string &background) { std::vector energy, spectrum; - EleCaPropagation(inputfile, background, energy, spectrum); + EleCaPropagation(inputfile, background, energy, spectrum, lowerEnergyThreshold); std::ofstream output(outputfile.c_str()); output << "# E N\n"; for (size_t i = 0; i < energy.size(); i++) { From d5ebac2056e37b6205adc239c490eaee8bed0198 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Wed, 20 Aug 2014 10:06:47 +0200 Subject: [PATCH 0464/1298] EleCa: Remove code-duplication in EnergyLoss --- libs/EleCa/src/EnergyLoss.cpp | 206 ++++++++++------------------------ 1 file changed, 59 insertions(+), 147 deletions(-) diff --git a/libs/EleCa/src/EnergyLoss.cpp b/libs/EleCa/src/EnergyLoss.cpp index 264446b2d..5f864870a 100644 --- a/libs/EleCa/src/EnergyLoss.cpp +++ b/libs/EleCa/src/EnergyLoss.cpp @@ -229,91 +229,12 @@ double dSigmadE_PP(double Ee, double E0, double eps, double theta) { } } -double ExtractPPSecondariesEnergy(Particle &pi, Particle &pt) { - /*! - Input: incident gamma Energy E0, background photon energy eps, - incidence angle theta. - Returns the energy of the produced e+ (e-) - */ - double E0 = pi.GetEnergy(); - double eps = pt.GetEnergy(); - double beta = pi.GetBeta(); - double theta = cPI; - double s2 = ElectronMass * ElectronMass - + 2 * eps * E0 * (1 - (beta) * cos(theta)); - - bool failed = 1; - - double MC_Sampling_Hist[MC_SAMPLING][3]; - for (int i = 0; i < MC_SAMPLING; i++) { - for (int j = 0; j < 3; j++) - MC_Sampling_Hist[i][j] = 0.; - } - - double f = pow((double) (1 + beta) / (1 - beta), - (double) 1. / (double) MC_SAMPLING); - int cnt = 0; - double NormFactor = 0; - - for (double Ee = f * 0.5 * (1 - beta) * E0; Ee < 0.5 * (1 + beta) * E0; - Ee *= f) { - MC_Sampling_Hist[cnt][0] = Ee; - MC_Sampling_Hist[cnt][1] = dSigmadE_PP(Ee, E0, eps, theta); - - NormFactor += MC_Sampling_Hist[cnt][1]; - MC_Sampling_Hist[cnt][2] = NormFactor; - - if (MC_Sampling_Hist[cnt][1] > 0.) { - cnt++; - } else { - break; - } - } - - NormFactor = (double) 1. / (double) NormFactor; - - for (int i = 0; i < cnt; i++) - MC_Sampling_Hist[i][2] *= NormFactor; - - double rnd; - double Ee = 0; - int k = 0; - while (failed) { - k++; - - rnd = Uniform(0, 1); - Ee = 0; - for (int i = 0; i < cnt - 1; i++) { - if (MC_Sampling_Hist[i][2] <= rnd <= MC_Sampling_Hist[i + 1][2]) { - Ee = MC_Sampling_Hist[i][0]; - failed = 0; - break; - } - if (failed) - std::cout << "cnt: " << cnt << " failed " << k << std::endl; - } - - } //end while - - if (Uniform(0, 1) < 0.5) - return Ee; - else - return E0 - Ee; -} - -double ExtractPPSecondariesEnergy(Process &proc) { - /*! - Input: incident gamma Energy E0, background photon energy eps, - incidence angle theta. - Returns the energy of the produced e+ (e-) - */ - double E0 = proc.GetIncidentParticle().GetEnergy(); - double s = proc.GetCMEnergy(); - double eps = proc.GetTargetParticle().GetEnergy(); +// Helper function for actual Monte Carlo sampling to avoid code-duplication +double __extractPPSecondariesEnergy(double E0, double eps, double beta) +{ double theta = M_PI; - double beta = sqrt(1. - 4.0 * ElectronMass * ElectronMass / s); double s2 = ElectronMass * ElectronMass + 2 * eps * E0 * (1 - (beta) * cos(theta)); @@ -355,7 +276,6 @@ double ExtractPPSecondariesEnergy(Process &proc) { for (int i = 0; i < cnt; i++) MC_Sampling_Hist[i][2] *= NormFactor; - double rnd; double Ee = ElectronMass; int k = 0; @@ -390,35 +310,55 @@ double ExtractPPSecondariesEnergy(Process &proc) { if (cnt == 0) throw std::runtime_error("failed in extractPP"); } - } //end while if (Uniform(0, 1.0) < 0.5) return Ee; else return E0 - Ee; + + } -double ExtractICSSecondariesEnergy(Particle &pi, Particle &pt) { + +double ExtractPPSecondariesEnergy(Particle &pi, Particle &pt) { /*! - Input: incident electron energy Ee, background photon energy eps, + Input: incident gamma Energy E0, background photon energy eps, incidence angle theta. - Returns the energy of the recoiled e+ (e-) + Returns the energy of the produced e+ (e-) */ - if (::abs(pi.GetType()) != 11) { - std::cerr << "something wrong in type ExtractICSEnergy " << std::endl; - return 0.; - } - - double Ee = pi.GetEnergy(); + double E0 = pi.GetEnergy(); double eps = pt.GetEnergy(); - double theta = M_PI; - double s = 2 * Ee * eps * (1 - pi.GetBeta() * cos(cPI)) - + pi.GetMass() * pi.GetMass(); + double beta = pi.GetBeta(); + + return __extractPPSecondariesEnergy(E0, eps, beta); +} + + + +double ExtractPPSecondariesEnergy(Process &proc) { + /*! + Input: incident gamma Energy E0, background photon energy eps, + incidence angle theta. + Returns the energy of the produced e+ (e-) + */ + + double E0 = proc.GetIncidentParticle().GetEnergy(); + double s = proc.GetCMEnergy(); + double eps = proc.GetTargetParticle().GetEnergy(); + double beta = sqrt(1. - 4.0 * ElectronMass * ElectronMass / s); + + return __extractPPSecondariesEnergy(E0, eps, beta); +} + +// Helper function for actual Monte Carlo sampling to avoid code-duplication +double __extractICSSecondaries(double Ee, double s, double theta) +{ double beta = (s - ElectronMass * ElectronMass) / (s + ElectronMass * ElectronMass); bool failed = 1; + // reInitialization to zero.. double MC_Sampling_Hist[MC_SAMPLING][3]; for (int i = 0; i < MC_SAMPLING; i++) { for (int j = 0; j < 3; j++) @@ -452,7 +392,7 @@ double ExtractICSSecondariesEnergy(Particle &pi, Particle &pt) { double Eer = 0; while (failed) { - rnd = Uniform(0, 1); + rnd = Uniform(0, 1.0); Eer = 0; for (int i = 0; i < cnt - 1; i++) { if (MC_Sampling_Hist[i][2] <= rnd <= MC_Sampling_Hist[i + 1][2]) { @@ -461,70 +401,42 @@ double ExtractICSSecondariesEnergy(Particle &pi, Particle &pt) { break; } } - } return Eer; } -double ExtractICSSecondariesEnergy(Process &proc) { + +double ExtractICSSecondariesEnergy(Particle &pi, Particle &pt) { /*! Input: incident electron energy Ee, background photon energy eps, incidence angle theta. Returns the energy of the recoiled e+ (e-) */ - double Ee = proc.GetIncidentParticle().GetEnergy(); - double s = proc.GetCMEnergy(); - double theta = proc.GetInteractionAngle(); - double beta = (s - ElectronMass * ElectronMass) - / (s + ElectronMass * ElectronMass); - bool failed = 1; - - // reInitialization to zero.. - double MC_Sampling_Hist[MC_SAMPLING][3]; - for (int i = 0; i < MC_SAMPLING; i++) { - for (int j = 0; j < 3; j++) - MC_Sampling_Hist[i][j] = 0.; - } - - double f = pow((double) (1 + beta) / (1 - beta), (double) 1. / MC_SAMPLING); - int cnt = 0; - double NormFactor = 0; - - for (double Eer = f * ((1 - beta) / (1 + beta)) * Ee; Eer <= Ee; Eer *= f) { - MC_Sampling_Hist[cnt][0] = Eer; - MC_Sampling_Hist[cnt][1] = dSigmadE_ICS(Ee, Eer, s, theta); - - NormFactor += MC_Sampling_Hist[cnt][1]; - MC_Sampling_Hist[cnt][2] = NormFactor; - - if (MC_Sampling_Hist[cnt][1] > 0.) { - cnt++; - } else { - break; - } + if (::abs(pi.GetType()) != 11) { + std::cerr << "something wrong in type ExtractICSEnergy " << std::endl; + return 0.; } - NormFactor = (double) 1. / (double) NormFactor; - - for (int i = 0; i < cnt; i++) - MC_Sampling_Hist[i][2] *= NormFactor; + double Ee = pi.GetEnergy(); + double eps = pt.GetEnergy(); + double theta = M_PI; + double s = 2 * Ee * eps * (1 - pi.GetBeta() * cos(cPI)) + + pi.GetMass() * pi.GetMass(); - double rnd = 0; - double Eer = 0; + return __extractICSSecondaries(Ee, s, theta); +} - while (failed) { - rnd = Uniform(0, 1.0); - Eer = 0; - for (int i = 0; i < cnt - 1; i++) { - if (MC_Sampling_Hist[i][2] <= rnd <= MC_Sampling_Hist[i + 1][2]) { - Eer = MC_Sampling_Hist[i][0]; - failed = 0; - break; - } - } +double ExtractICSSecondariesEnergy(Process &proc) { + /*! + Input: incident electron energy Ee, background photon energy eps, + incidence angle theta. + Returns the energy of the recoiled e+ (e-) + */ + double Ee = proc.GetIncidentParticle().GetEnergy(); + double s = proc.GetCMEnergy(); + double theta = proc.GetInteractionAngle(); - } - return Eer; + return __extractICSSecondaries(Ee, s , theta); } double ExtractTPPSecondariesEnergy(Particle &pi, Particle &pt) { From 4b196b31fb5e669860d1a451e699fe75c317d41f Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Wed, 20 Aug 2014 17:22:39 +0200 Subject: [PATCH 0465/1298] More verbose error output in ICS cross section --- libs/EleCa/src/EnergyLoss.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/EleCa/src/EnergyLoss.cpp b/libs/EleCa/src/EnergyLoss.cpp index 5f864870a..fe7dc7ebb 100644 --- a/libs/EleCa/src/EnergyLoss.cpp +++ b/libs/EleCa/src/EnergyLoss.cpp @@ -189,8 +189,8 @@ double dSigmadE_ICS(double Ee, double Eer, double s, double theta) { / (s + ElectronMass * ElectronMass); if (Eer / Ee < (1 - beta) / (1 + beta) || Eer / Ee > 1) { - std::cerr << "ERROR, Energy outside limits for ICS [Lee96]! " - << std::endl; + std::cerr << "ERROR, Energy outside limits for ICS [Lee96]! " << std::endl; + std::cerr << " Eer = " << Eer << " Ee = " << Ee << " Eer/Ee = " << Eer / Ee << " (1 - beta) / (1 + beta) = " << (1 - beta) / (1 + beta) << std::endl; return 0.; } else { double q = ((1 - beta) / beta) * (1 - Ee / Eer); @@ -351,6 +351,7 @@ double ExtractPPSecondariesEnergy(Process &proc) { return __extractPPSecondariesEnergy(E0, eps, beta); } + // Helper function for actual Monte Carlo sampling to avoid code-duplication double __extractICSSecondaries(double Ee, double s, double theta) { From 3f6e57360b6cbc75149f4d9e01b4e29094eec8f3 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Thu, 21 Aug 2014 10:18:19 +0200 Subject: [PATCH 0466/1298] Eleca: Replaced on-the-fly calculation of ICS Energy distribution with precalculation on grid --- libs/EleCa/include/EleCa/EnergyLoss.h | 1 + libs/EleCa/src/EnergyLoss.cpp | 195 +++++++++++++++++++------- 2 files changed, 145 insertions(+), 51 deletions(-) diff --git a/libs/EleCa/include/EleCa/EnergyLoss.h b/libs/EleCa/include/EleCa/EnergyLoss.h index a647b1374..492b644c3 100644 --- a/libs/EleCa/include/EleCa/EnergyLoss.h +++ b/libs/EleCa/include/EleCa/EnergyLoss.h @@ -25,6 +25,7 @@ double ExtractTPPSecondariesEnergy(Particle &pi, Particle &pt); double ExtractTPPSecondariesEnergy(Process &proc); double ExtractDPPSecondariesEnergy(double E0); +double __extractICSSecondaries(double Ee, double s, double theta); } // namespace eleca #endif // ELECA_ENERGY_LOSS_H_ diff --git a/libs/EleCa/src/EnergyLoss.cpp b/libs/EleCa/src/EnergyLoss.cpp index fe7dc7ebb..ef13161a4 100644 --- a/libs/EleCa/src/EnergyLoss.cpp +++ b/libs/EleCa/src/EnergyLoss.cpp @@ -187,12 +187,17 @@ double dSigmadE_ICS(double Ee, double Eer, double s, double theta) { double beta = (s - ElectronMass * ElectronMass) / (s + ElectronMass * ElectronMass); - - if (Eer / Ee < (1 - beta) / (1 + beta) || Eer / Ee > 1) { + // boundaries rewritten to avoid error due to numerical uncertainties + if ((Eer / Ee -1) / (Eer / Ee +1) > beta || Eer / Ee > 1) + { std::cerr << "ERROR, Energy outside limits for ICS [Lee96]! " << std::endl; - std::cerr << " Eer = " << Eer << " Ee = " << Ee << " Eer/Ee = " << Eer / Ee << " (1 - beta) / (1 + beta) = " << (1 - beta) / (1 + beta) << std::endl; + std::cerr << " Eer = " << Eer << " Ee = " << Ee << " Eer/Ee = " << + Eer / Ee << " (1 - beta) / (1 + beta) = " << (1 - beta) / (1 + beta) << + " beta = " << beta << std::endl; return 0.; - } else { + } + else + { double q = ((1 - beta) / beta) * (1 - Ee / Eer); double A = Eer / Ee + Ee / Eer; double k = (3.0 / 8.0) * (SigmaThompson * ElectronMass * ElectronMass) @@ -352,58 +357,144 @@ double ExtractPPSecondariesEnergy(Process &proc) { } -// Helper function for actual Monte Carlo sampling to avoid code-duplication -double __extractICSSecondaries(double Ee, double s, double theta) +/// Hold an data array to interpolate the energy distribution on +class ICSSecondariesEnergyDistribution { - double beta = (s - ElectronMass * ElectronMass) - / (s + ElectronMass * ElectronMass); - bool failed = 1; - - // reInitialization to zero.. - double MC_Sampling_Hist[MC_SAMPLING][3]; - for (int i = 0; i < MC_SAMPLING; i++) { - for (int j = 0; j < 3; j++) - MC_Sampling_Hist[i][j] = 0.; - } - - double f = pow((double) (1 + beta) / (1 - beta), (double) 1. / MC_SAMPLING); - int cnt = 0; - double NormFactor = 0; - - for (double Eer = f * ((1 - beta) / (1 + beta)) * Ee; Eer <= Ee; Eer *= f) { - MC_Sampling_Hist[cnt][0] = Eer; - MC_Sampling_Hist[cnt][1] = dSigmadE_ICS(Ee, Eer, s, theta); - - NormFactor += MC_Sampling_Hist[cnt][1]; - MC_Sampling_Hist[cnt][2] = NormFactor; + private: + double *_data; + size_t _Ns; + size_t _Nrer; + double _s_min; + double _s_max; + double _dls; + + public: + ICSSecondariesEnergyDistribution(double s_min = 2.6373E+11, double s_max =1e21, + size_t Ns = 1000, size_t Nrer = 1000 ) + { + // ToDo: this boundary is just an estimate + const double l = 1.001; + if (s_min < l * ElectronMass*ElectronMass) + { + std::cerr << "Warning: Minimum COM Energy in ICS Interpolation s = " << s_min << " < " << l << " m_e**2 selected. Setting to s_min = " << l << " m_e**2.\n" ; + s_min = l * ElectronMass*ElectronMass; + } + _Ns = Ns; + _Nrer = Nrer; + _s_min =s_min; + _s_max = s_max; + _data = new double[Ns*Nrer]; + + double theta = M_PI; + + double dls = (log(s_max) - log(s_min)) / (Ns); + double dls_min = log(s_min); + + for (size_t i = 0; i < Ns; i++) + { + const double s = exp(dls_min + i*dls); + double beta = (s - ElectronMass * ElectronMass) / (s + + ElectronMass * ElectronMass); + + double eer_0 = log((1-beta) / (1+beta)); + double deer = - log((1-beta) / (1+beta)) / Nrer; + + _data[i * Nrer] = 0; + for (size_t j = 1; j < Nrer; j++) + { + const double Ee = 1E21; + + double Eer = Ee * exp(eer_0 + (j-1)*deer); + _data[i * Nrer + j] = dSigmadE_ICS(Ee, Eer , s, theta) + _data[i * Nrer + j - 1]; + } + } + } - if (MC_Sampling_Hist[cnt][1] > 0.) { - cnt++; - } else { - break; + // returns pointer to the the integrated distribution for a given s + double* getDistribution(double s) + { + double dls = (log(_s_max) - log(_s_min)) / (_Ns); + size_t idx = (log(s) - log(_s_min)) / dls; + double *s0 = &_data[idx * _Nrer]; + return s0; } - } - NormFactor = (double) 1. / (double) NormFactor; + //samples the integrated distribution and returns Eer(Ee, s) + double sample(double Ee, double s) + { + double *s0 = getDistribution(s); + double rnd = Uniform(0, 1.0) *s0[_Nrer-1]; + for (size_t i=1; i < _Nrer; i++) + { + if (rnd < s0[i]) + { + double beta = (s - ElectronMass * ElectronMass) / (s + + ElectronMass * ElectronMass); + double eer_0 = log((1-beta) / (1+beta)); + double deer = - log((1-beta) / (1+beta)) / (_Nrer ); + return exp(eer_0 + (i-1)*deer) * Ee; + } + } + } +}; - for (int i = 0; i < cnt; i++) - MC_Sampling_Hist[i][2] *= NormFactor; - double rnd = 0; - double Eer = 0; +// Helper function for actual Monte Carlo sampling to avoid code-duplication +double __extractICSSecondaries(double Ee, double s, double theta) +{ - while (failed) { - rnd = Uniform(0, 1.0); - Eer = 0; - for (int i = 0; i < cnt - 1; i++) { - if (MC_Sampling_Hist[i][2] <= rnd <= MC_Sampling_Hist[i + 1][2]) { - Eer = MC_Sampling_Hist[i][0]; - failed = 0; - break; - } - } - } - return Eer; + static ICSSecondariesEnergyDistribution interpolation(1E11, 1E21, 1000); + return interpolation.sample(Ee, s); + + //double beta = (s - ElectronMass * ElectronMass) + // / (s + ElectronMass * ElectronMass); + //bool failed = 1; + + //// reInitialization to zero.. + //double MC_Sampling_Hist[MC_SAMPLING][3]; + //for (int i = 0; i < MC_SAMPLING; i++) { + // for (int j = 0; j < 3; j++) + // MC_Sampling_Hist[i][j] = 0.; + //} + + //double f = pow((double) (1 + beta) / (1 - beta), (double) 1. / MC_SAMPLING); + //int cnt = 0; + //double NormFactor = 0; + + //for (double Eer = f * ((1 - beta) / (1 + beta)) * Ee; Eer <= Ee; Eer *= f) { + // MC_Sampling_Hist[cnt][0] = Eer; + // MC_Sampling_Hist[cnt][1] = dSigmadE_ICS(Ee, Eer, s, theta); + + // NormFactor += MC_Sampling_Hist[cnt][1]; + // MC_Sampling_Hist[cnt][2] = NormFactor; + + // if (MC_Sampling_Hist[cnt][1] > 0.) { + // cnt++; + // } else { + // break; + // } + //} + + //NormFactor = (double) 1. / (double) NormFactor; + + //for (int i = 0; i < cnt; i++) + // MC_Sampling_Hist[i][2] *= NormFactor; + + //double rnd = 0; + //double Eer = 0; + + //while (failed) { + // rnd = Uniform(0, 1.0); + // Eer = 0; + // for (int i = 0; i < cnt - 1; i++) { + // if (MC_Sampling_Hist[i][2] <= rnd <= MC_Sampling_Hist[i + 1][2]) { + // Eer = MC_Sampling_Hist[i][0]; + // failed = 0; + // break; + // } + // } + //} + //return Eer; } @@ -427,6 +518,7 @@ double ExtractICSSecondariesEnergy(Particle &pi, Particle &pt) { return __extractICSSecondaries(Ee, s, theta); } + double ExtractICSSecondariesEnergy(Process &proc) { /*! Input: incident electron energy Ee, background photon energy eps, @@ -436,10 +528,10 @@ double ExtractICSSecondariesEnergy(Process &proc) { double Ee = proc.GetIncidentParticle().GetEnergy(); double s = proc.GetCMEnergy(); double theta = proc.GetInteractionAngle(); - return __extractICSSecondaries(Ee, s , theta); } + double ExtractTPPSecondariesEnergy(Particle &pi, Particle &pt) { /* approximation based on A. Mastichiadis et al., Astroph. Journ. 300:178-189 (1986), eq. 30. @@ -459,9 +551,9 @@ double ExtractTPPSecondariesEnergy(Particle &pi, Particle &pt) { / 2.0; //return the energy of each e+/e- in the pair. return Epp; - } + double ExtractTPPSecondariesEnergy(Process &proc) { /* approximation based on A. Mastichiadis et al., Astroph. Journ. 300:178-189 (1986), eq. 30. @@ -481,6 +573,7 @@ double ExtractTPPSecondariesEnergy(Process &proc) { return Epp; } + double ExtractDPPSecondariesEnergy(double E0) { /* we use the same assumption of lee (i.e., all the energy goes equaly shared between only 1 couple of e+e-. From 4b0857f321ed176a735e97200321044e72e46b1a Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Thu, 21 Aug 2014 11:36:51 +0200 Subject: [PATCH 0467/1298] Eleca: Replaced pow(x, int) with template to improve performance --- libs/EleCa/include/EleCa/Common.h | 15 ++++++++++ libs/EleCa/src/EnergyLoss.cpp | 10 +++---- libs/EleCa/src/XLoss_CBR.h | 48 ++++++++++++++++--------------- 3 files changed, 45 insertions(+), 28 deletions(-) diff --git a/libs/EleCa/include/EleCa/Common.h b/libs/EleCa/include/EleCa/Common.h index 0b9895e6f..90985ca1b 100644 --- a/libs/EleCa/include/EleCa/Common.h +++ b/libs/EleCa/include/EleCa/Common.h @@ -9,6 +9,21 @@ double Uniform(double min, double max); void setUniformCallback(double (*Uniform)(double min, double max)); + +// integer pow implementation as template that is evaluated at compile time +template +inline double pow_integer(double base) +{ + return pow_integer> 1>(base*base) * (((exponent & 1) > 0) ? base : 1); +} + +template <> +inline double pow_integer<0>(double base) +{ + return 1; +} + + } // namespace eleca #endif // ELECA_COMMON_H_ diff --git a/libs/EleCa/src/EnergyLoss.cpp b/libs/EleCa/src/EnergyLoss.cpp index ef13161a4..316c588ac 100644 --- a/libs/EleCa/src/EnergyLoss.cpp +++ b/libs/EleCa/src/EnergyLoss.cpp @@ -18,14 +18,14 @@ double dTdZ(double z) { return -1. / ((1 + z) * H0y * sqrt( - pow(1. + z, 3.) * OM + OL - + (1 - OM - OL) * pow(1. + z, 2.))); + pow_integer<3>(1. + z) * OM + OL + + (1 - OM - OL) * pow_integer<2>(1. + z))); } double betaRsh(double z) { // Energy loss term due to cosmological redshift return H0y - * sqrt(pow(1. + z, 3.) * OM + OL + (1 - OM - OL) * pow(1. + z, 2.)); + * sqrt(pow_integer<3>(1. + z) * OM + OL + (1 - OM - OL) * pow_integer<2>(1. + z)); } double fLossAdiabatic(double E, double z) { @@ -43,7 +43,7 @@ double AdiabaticELoss(double z0, double z, double E0) { double MeanRateSynchrotronLoss(double E, double B) { double dEdt = 0; if (B > 0) - dEdt = 3.79e-6 * pow(E / 1e9 * B, 2) * 1e9 / E; + dEdt = 3.79e-6 * pow_integer<2>(E / 1e9 * B) * 1e9 / E; return dEdt; } @@ -226,7 +226,7 @@ double dSigmadE_PP(double Ee, double E0, double eps, double theta) { double A = Ee / q + q / Ee; double B = E0 * (1 - beta * beta) * (1. / Ee + 1. / q); double C = -((1 - beta * beta) * (1 - beta * beta) * E0 * E0 / 4.0) - * pow(1. / Ee + 1. / q, 2); + * pow_integer<2>(1. / Ee + 1. / q); double dsigmadE = k * (A + B + C); diff --git a/libs/EleCa/src/XLoss_CBR.h b/libs/EleCa/src/XLoss_CBR.h index 3945a09ba..099b5af67 100644 --- a/libs/EleCa/src/XLoss_CBR.h +++ b/libs/EleCa/src/XLoss_CBR.h @@ -1,6 +1,8 @@ #ifndef ELECA_XLOSS_CBR_H #define ELECA_XLOSS_CBR_H +#include + namespace eleca { /*===================================================================== @@ -64,7 +66,7 @@ double CIB_Evolution_Fast(double z) { } double CMB_Evolution(double z) { - return pow(1. + z, 3.); + return pow_integer<3>(1. + z); } double CIB_Evolution(double z) { @@ -76,14 +78,14 @@ double CIOB_Evolution(double z) { } double COB_Evolution(double z) { - return pow(1. + z, 3.); + return pow_integer<3>(1. + z); } double URB_Evolution(double z) { //from Protheroe - Bierman astro-ph:9605119 if (z < 0.8) - return pow(1. + z, 4.); - return pow(1 + 0.8, 4); // z>= z0 + return pow_integer<4>(1. + z); + return pow_integer<4>(1 + 0.8); // z>= z0 } double CMBR(double eps) { @@ -132,25 +134,25 @@ double CIOBR(double eps) { if (eps > eps_ph_inf_ciob && eps < eps_ph_sup_ciob) { double x = log(eps); tmp = -5.32524895349885 - 0.0741140642891119 * x - - 0.252586527659431 * pow(x, 2.) - + 0.234971297531891 * pow(x, 3.) - - 0.217014471117521 * pow(x, 4.) - - 0.364936722063572 * pow(x, 5.) - + 0.0880702191711222 * pow(x, 6.) - + 0.221947767409286 * pow(x, 7.) - + 0.0445499623085708 * pow(x, 8.) - - 0.0517435600939147 * pow(x, 9.) - - 0.0295646851279071 * pow(x, 10.) - - 0.00011943632049331 * pow(x, 11.) - + 0.00461621589174355 * pow(x, 12.) - + 0.00150906100702171 * pow(x, 13.) - + 1.91459088023263e-05 * pow(x, 14.) - - 0.000110272619218937 * pow(x, 15.) - - 3.45221358079085e-05 * pow(x, 16.) - - 5.42000122025042e-06 * pow(x, 17.) - - 4.90862622314226e-07 * pow(x, 18.) - - 2.45145316799091e-08 * pow(x, 19.) - - 5.25792204884819e-10 * pow(x, 20.); + - 0.252586527659431 * pow_integer<2>(x) + + 0.234971297531891 * pow_integer<3>(x) + - 0.217014471117521 * pow_integer<4>(x) + - 0.364936722063572 * pow_integer<5>(x) + + 0.0880702191711222 * pow_integer<6>(x) + + 0.221947767409286 * pow_integer<7>(x) + + 0.0445499623085708 * pow_integer<8>(x) + - 0.0517435600939147 * pow_integer<9>(x) + - 0.0295646851279071 * pow_integer<10>(x) + - 0.00011943632049331 * pow_integer<11>(x) + + 0.00461621589174355 * pow_integer<12>(x) + + 0.00150906100702171 * pow_integer<13>(x) + + 1.91459088023263e-05 * pow_integer<14>(x) + - 0.000110272619218937 * pow_integer<15>(x) + - 3.45221358079085e-05 * pow_integer<16>(x) + - 5.42000122025042e-06 * pow_integer<17>(x) + - 4.90862622314226e-07 * pow_integer<18>(x) + - 2.45145316799091e-08 * pow_integer<19>(x) + - 5.25792204884819e-10 * pow_integer<20>(x); tmp = 0.4 * (double) exp(tmp) / eps / eps; } else { tmp = 0; From db27efdb7d3ccd99de99a834eb66b1d408b4a4c2 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 22 Aug 2014 13:52:26 +0200 Subject: [PATCH 0468/1298] Eleca: Fixed energy sampling of interpolated crossections --- libs/EleCa/src/EnergyLoss.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/libs/EleCa/src/EnergyLoss.cpp b/libs/EleCa/src/EnergyLoss.cpp index 316c588ac..2b709e901 100644 --- a/libs/EleCa/src/EnergyLoss.cpp +++ b/libs/EleCa/src/EnergyLoss.cpp @@ -240,9 +240,6 @@ double __extractPPSecondariesEnergy(double E0, double eps, double beta) { double theta = M_PI; - double s2 = ElectronMass * ElectronMass - + 2 * eps * E0 * (1 - (beta) * cos(theta)); - bool failed = 1; double MC_Sampling_Hist[MC_SAMPLING][3]; @@ -397,14 +394,14 @@ class ICSSecondariesEnergyDistribution ElectronMass * ElectronMass); double eer_0 = log((1-beta) / (1+beta)); - double deer = - log((1-beta) / (1+beta)) / Nrer; + double deer = - log((1-beta) / (1+beta)) / (Nrer-1); - _data[i * Nrer] = 0; + const double Ee = 1E21; + _data[i * Nrer] = dSigmadE_ICS(Ee, Ee * exp(eer_0), s, theta); for (size_t j = 1; j < Nrer; j++) { - const double Ee = 1E21; - double Eer = Ee * exp(eer_0 + (j-1)*deer); + double Eer = Ee * exp(eer_0 + (j)*deer); _data[i * Nrer + j] = dSigmadE_ICS(Ee, Eer , s, theta) + _data[i * Nrer + j - 1]; } } @@ -424,7 +421,7 @@ class ICSSecondariesEnergyDistribution { double *s0 = getDistribution(s); double rnd = Uniform(0, 1.0) *s0[_Nrer-1]; - for (size_t i=1; i < _Nrer; i++) + for (size_t i=0; i < _Nrer; i++) { if (rnd < s0[i]) { @@ -432,7 +429,7 @@ class ICSSecondariesEnergyDistribution ElectronMass * ElectronMass); double eer_0 = log((1-beta) / (1+beta)); double deer = - log((1-beta) / (1+beta)) / (_Nrer ); - return exp(eer_0 + (i-1)*deer) * Ee; + return exp(eer_0 + (i)*deer) * Ee; } } } From 678a367219e565f06654194891193437a62922c7 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 22 Aug 2014 14:10:03 +0200 Subject: [PATCH 0469/1298] Eleca: Replaced on-the-fly calculation of PP Energy distribution with precalculation on grid --- libs/EleCa/src/EnergyLoss.cpp | 168 ++++++++++++++++++++-------------- 1 file changed, 97 insertions(+), 71 deletions(-) diff --git a/libs/EleCa/src/EnergyLoss.cpp b/libs/EleCa/src/EnergyLoss.cpp index 2b709e901..ecd77362a 100644 --- a/libs/EleCa/src/EnergyLoss.cpp +++ b/libs/EleCa/src/EnergyLoss.cpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace eleca { @@ -234,92 +235,117 @@ double dSigmadE_PP(double Ee, double E0, double eps, double theta) { } } +/// Differential cross-section for pair production for x = E/E0 +double dSigmadE_PPx(double x, double beta) { -// Helper function for actual Monte Carlo sampling to avoid code-duplication -double __extractPPSecondariesEnergy(double E0, double eps, double beta) -{ - double theta = M_PI; + if ((x - 0.5 * (1 - beta)) < -1 * DBL_EPSILON || x - 0.5 * (1 + beta) > DBL_EPSILON ) { + std::cerr << "ERROR, Energy outside limits for PP [Lee96]! " << std::endl; + std::cerr << " x = " << x << " 0.5* (1-beta) = " << 0.5 * (1 - beta) << " 0.5* (1+beta) = " << 0.5 * (1 + beta) << " beta = " << beta << std::endl; + return 0.; + } else { - bool failed = 1; + const double A = (x / (1. - x) + (1. - x) / x ); + const double B = (1. / x + 1. / (1. - x) ); - double MC_Sampling_Hist[MC_SAMPLING][3]; - for (int i = 0; i < MC_SAMPLING; i++) { - for (int j = 0; j < 3; j++) - MC_Sampling_Hist[i][j] = 0.; + return A + (1. - beta*beta) * B + (1. - beta*beta) * (1. - beta*beta) / 4. * B*B; } +} - double f = pow((double) (1 + beta) / (1 - beta), - (double) 1. / (double) MC_SAMPLING); - int cnt = 0; - double NormFactor = 0; - - for (double Ee = f * 0.5 * (1 - beta) * E0; Ee < 0.5 * (1 + beta) * E0; - Ee *= f) { - MC_Sampling_Hist[cnt][0] = Ee; - MC_Sampling_Hist[cnt][1] = dSigmadE_PP(Ee, E0, eps, theta); - NormFactor += MC_Sampling_Hist[cnt][1]; - MC_Sampling_Hist[cnt][2] = NormFactor; - - if (MC_Sampling_Hist[cnt][1] > 0.) { - cnt++; - } else { - break; - } - } - if (cnt == 0) { - for (double Ee = f * 0.5 * (1 - beta) * E0; Ee < 0.5 * (1 + beta) * E0; - Ee *= f) { - std::cout << Ee << " " << f << " " << (1-beta) << std::endl; - } - } - NormFactor = (double) 1. / (double) NormFactor; +/// Hold an data array to interpolate the energy distribution on +class PPSecondariesEnergyDistribution +{ + private: + double *_data; + size_t _Ns; + size_t _Nrer; + double _s_min; + double _s_max; + double _dls; - for (int i = 0; i < cnt; i++) - MC_Sampling_Hist[i][2] *= NormFactor; + public: + PPSecondariesEnergyDistribution(double s_min = 2.6373E+11, double s_max =1e21, + size_t Ns = 1000, size_t Nrer = 1000 ) + { + // ToDo: this boundary is just an estimate + const double l = 1.001; + if (s_min < l * ElectronMass*ElectronMass) + { + std::cerr << "Warning: Minimum COM Energy in ICS Interpolation s = " << s_min << " < " << l << " m_e**2 selected. Setting to s_min = " << l << " m_e**2.\n" ; + s_min = l * ElectronMass*ElectronMass; + } + _Ns = Ns; + _Nrer = Nrer; + _s_min =s_min; + _s_max = s_max; + _data = new double[Ns*Nrer]; - double rnd; - double Ee = ElectronMass; - int k = 0; + double dls = (log(s_max) - log(s_min)) / (Ns); + double dls_min = log(s_min); - while (failed) { - rnd = Uniform(0., 1.0); - Ee = ElectronMass; - k++; - double min = 1e6; - double max = -1; + for (size_t i = 0; i < Ns; i++) + { + const double s = exp(dls_min + i*dls); + double beta = sqrt(1. - 4. * ElectronMass*ElectronMass /s); + + double x0 = log((1.-beta) / 2.); + double dx = ( log((1. + beta)/2) - log((1.-beta) / 2.)) / (Nrer); + _data[i * Nrer] = exp(x0) ; + for (size_t j = 1; j < Nrer; j++) + { + double x = exp(x0 + j*dx); + _data[i * Nrer + j] = dSigmadE_PPx(x, beta) + _data[i * Nrer + j - 1]; + } + } + } + + // returns pointer to the the integrated distribution for a given s + double* getDistribution(double s) + { + double dls = (log(_s_max) - log(_s_min)) / (_Ns); + size_t idx = (log(s) - log(_s_min)) / dls; + double *s0 = &_data[idx * _Nrer]; + return s0; + } - for (int i = 0; i < cnt - 1; i++) { + //samples the integrated distribution and returns Eer(Ee, s) + double sample(double E0, double eps, double theta) + { + double s = ElectronMass*ElectronMass + 2. * E0 * eps * (1-cos(theta)); + + double *s0 = getDistribution(s); + double rnd = Uniform(0, 1.0) *s0[_Nrer-1]; - if (MC_Sampling_Hist[i][2] < min) - min = MC_Sampling_Hist[i][2]; - if (MC_Sampling_Hist[i + 1][2] > max) - max = MC_Sampling_Hist[i + 1][2]; + for (size_t i=0; i < _Nrer; i++) + { + if (rnd < s0[i]) + { + double beta = (s - ElectronMass * ElectronMass) / (s + + ElectronMass * ElectronMass); - if (MC_Sampling_Hist[i][2] <= rnd <= MC_Sampling_Hist[i + 1][2]) { - Ee = MC_Sampling_Hist[i][0]; - failed = 0; - break; + double x0 = log((1.-beta) / 2.); + double dx = ( log((1. + beta)/2) - log((1.-beta) / 2.)) / (_Nrer); + if (Uniform(0, 1.0) < 0.5) + return exp(x0 + (i)*dx) * E0; + else + return E0 * (1-exp(x0 + (i)*dx) ); + } } + std::cerr << "PPSecondariesEnergyDistribution out of bounds!" << std::endl; + std::cerr << " s0[0] = " << s0[0] << " s0[_Nrer-1] = " << s0[_Nrer-1] << " rnd = " << rnd << std::endl; + throw std::runtime_error("Grave logic error in PPSecondariesEnergyDistribution!"); } - if (failed) { - /* std::cout << "failed in extractPP " << Ee << " " << beta << " * s: " - << s << " E0: " << E0 << " eps : " << eps << " me^2/E0: " - << ElectronMass * ElectronMass / E0 << " ) " << " cnt : " - << cnt << std::endl; - std::cout << " Limits " << proc.GetMin() << std::endl; - */ - if (cnt == 0) - throw std::runtime_error("failed in extractPP"); - } - } //end while +}; + - if (Uniform(0, 1.0) < 0.5) - return Ee; - else - return E0 - Ee; +// Helper function for actual Monte Carlo sampling to avoid code-duplication +double __extractPPSecondariesEnergy(double E0, double eps, double beta) +{ + double theta = M_PI; + static PPSecondariesEnergyDistribution interpolation; + return interpolation.sample(E0, eps, theta); } @@ -394,7 +420,7 @@ class ICSSecondariesEnergyDistribution ElectronMass * ElectronMass); double eer_0 = log((1-beta) / (1+beta)); - double deer = - log((1-beta) / (1+beta)) / (Nrer-1); + double deer = - log((1-beta) / (1+beta)) / (Nrer); const double Ee = 1E21; _data[i * Nrer] = dSigmadE_ICS(Ee, Ee * exp(eer_0), s, theta); @@ -440,7 +466,7 @@ class ICSSecondariesEnergyDistribution double __extractICSSecondaries(double Ee, double s, double theta) { - static ICSSecondariesEnergyDistribution interpolation(1E11, 1E21, 1000); + static ICSSecondariesEnergyDistribution interpolation; return interpolation.sample(Ee, s); //double beta = (s - ElectronMass * ElectronMass) From c76bf778f7cd236202343075260a2d08fed3e052 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 22 Aug 2014 14:54:25 +0200 Subject: [PATCH 0470/1298] Eleca: Reduce number of log10 calls in Propagation --- libs/EleCa/src/Propagation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/EleCa/src/Propagation.cpp b/libs/EleCa/src/Propagation.cpp index 3d933e714..6f7a12732 100644 --- a/libs/EleCa/src/Propagation.cpp +++ b/libs/EleCa/src/Propagation.cpp @@ -235,9 +235,9 @@ double Propagation::GetLambdaTab(const Process &proc, double E0taborg = vEtab[0]; - double dEtab = log10(vEtab[0]) - log10(vEtab[1]); + double dEtab = log10(vEtab[0] / vEtab[1]); double evolution = GetEvolution(proc.GetTargetParticle().GetEnergy(), z); - int i = (int) ((log10(E0taborg) - log10(E1 * (1 + z))) / dEtab); + int i = (int) (log10(E0taborg / (E1 * (1 + z))) / dEtab); if (i < 0) { std::cout << "WARNING!! GetLambdaTab in " << procName << " : i= " << i From 881892735dea8193f37629db3cd361394b13ee76 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 22 Aug 2014 15:52:33 +0200 Subject: [PATCH 0471/1298] Eleca: Replaced String in Process with Enum --- libs/EleCa/include/EleCa/Process.h | 19 +++++++--- libs/EleCa/include/EleCa/Propagation.h | 3 +- libs/EleCa/src/Process.cpp | 47 ++++++++++++------------ libs/EleCa/src/Propagation.cpp | 50 +++++++++++++------------- 4 files changed, 65 insertions(+), 54 deletions(-) diff --git a/libs/EleCa/include/EleCa/Process.h b/libs/EleCa/include/EleCa/Process.h index 1a0e2cf6c..07f8e047a 100644 --- a/libs/EleCa/include/EleCa/Process.h +++ b/libs/EleCa/include/EleCa/Process.h @@ -12,7 +12,15 @@ class Process { public: - std::string fname; + enum Name + { + NONE, + PP, + DPP, + TPP, + ICS + }; + double flambda; double fsmin; double fsmax; @@ -29,12 +37,12 @@ class Process { Process(); Process(const Process&); Process(Particle&, Particle&); - Process(Particle&, Particle&, std::string); + Process(Particle&, Particle&, Process::Name); ~Process(); - void SetName(std::string nm); - const std::string &GetName() const; + void SetName(Process::Name nm); + const Process::Name &GetName() const; void SetInteractionAngle(double a); double GetInteractionAngle() const; @@ -43,7 +51,7 @@ class Process { double GetLambda() const; void SetLimits(double smin, double smax); - void SetLimits(Particle& p1, std::string nameproc); + void SetLimits(Particle& p1, Process::Name nameproc); void SetLimits(); void SetMax(double smax); @@ -68,6 +76,7 @@ class Process { private: + Process::Name _name; }; } // namespace diff --git a/libs/EleCa/include/EleCa/Propagation.h b/libs/EleCa/include/EleCa/Propagation.h index 114765a39..bd4611a3b 100644 --- a/libs/EleCa/include/EleCa/Propagation.h +++ b/libs/EleCa/include/EleCa/Propagation.h @@ -2,6 +2,7 @@ #define ELECA_PROPAGATION_H #include "EleCa/Particle.h" +#include "EleCa/Process.h" #include #include @@ -39,7 +40,7 @@ class Propagation { double GetMeanThetaBFDeflection(double Bin, double Ein, int ptype, double Lin) const; - double GetLambdaTab(const Process &proc, const std::string &procName) const; + double GetLambdaTab(const Process &proc, Process::Name procName) const; double ExtractMinDist(Process &proc, int type, double R, double R2, std::vector &Etarget) const; std::vector GetEtarget(Process &proc, diff --git a/libs/EleCa/src/Process.cpp b/libs/EleCa/src/Process.cpp index 701730fa6..f9618b5c8 100644 --- a/libs/EleCa/src/Process.cpp +++ b/libs/EleCa/src/Process.cpp @@ -6,11 +6,12 @@ namespace eleca { -void Process::SetName(std::string nm) { - fname = nm; +void Process::SetName(Process::Name nm) { + _name = nm; } -const std::string &Process::GetName() const { - return fname; + +const Process::Name &Process::GetName() const { + return _name; } void Process::SetInteractionAngle(double a) { @@ -33,7 +34,7 @@ void Process::SetLimits(double smin, double smax) { } void Process::SetLimits() { - SetLimits(fPi, fname); + SetLimits(fPi, _name); } void Process::SetMax(double smax) { @@ -91,7 +92,7 @@ const std::string &Process::GetBackground() const { } Process::Process() { - fname = ""; + _name = Process::NONE; SetLimits(0.0, 1.0e23); flambda = 0; fCMEnergy = 0; @@ -106,38 +107,38 @@ Process::Process(Particle& p1, Particle& p2) { fPi = p1; fPt = p2; if (p1.GetType() == 22) - fname = "PP"; + _name = Process::PP; else if (abs(p1.GetType()) == 11) { std::cerr << "NB: by default process set to ICS" << std::endl; - fname = "ICS"; + _name = ICS; } else - fname = "NONE"; + _name = Process::NONE; SetCMEnergy(p1, p2); flambda = 0; fInteractionAngle = cPI; fback = "ALL"; - SetLimits(p1, fname); + SetLimits(p1, _name); fbackdensity = 0; feps_inf = eps_ph_inf_global; feps_sup = eps_ph_sup_global; } -Process::Process(Particle& p1, Particle& p2, std::string name) { - fname = name; +Process::Process(Particle& p1, Particle& p2, Process::Name name) { + _name = name; SetCMEnergy(p1, p2); flambda = 0; fInteractionAngle = cPI; fPi = p1; fPt = p2; fback = "ALL"; - SetLimits(p1, fname); + SetLimits(p1, _name); fbackdensity = 0; feps_inf = eps_ph_inf_global; feps_sup = eps_ph_sup_global; } Process::Process(const Process& proc2) { - fname = proc2.GetName(); + _name = proc2.GetName(); SetLimits(proc2.GetMin(), proc2.GetMax()); fCMEnergy = proc2.GetCMEnergy(); fInteractionAngle = proc2.GetInteractionAngle(); @@ -188,37 +189,37 @@ void Process::SetBackground(std::string BackRad) { } -void Process::SetLimits(Particle& p1, std::string nameproc) { +void Process::SetLimits(Particle& p1, Process::Name nameproc) { if (p1.GetType() != 22 && p1.GetType() != 11 && p1.GetType() != -11) std::cout << "error in type " << p1.GetType() << " != 11 and !=22 " << std::endl; - if (nameproc == "PP") { + if (nameproc == Process::PP) { if (abs(p1.GetType()) == 11) - std::cout << "\nERROR!! wrong particle or process!! " << nameproc + std::cout << "\nERROR!! wrong particle or process!! " << " PP " << p1.GetType() << "\n" << std::endl; fsmin = 4 * ElectronMass * ElectronMass; //min per theta = 0; fsmax = 4 * p1.GetEnergy() * feps_sup * 2.0; //(1.0-cos(fInteractionAngle)); //max per theta=3.14 } - if (nameproc == "DPP") { + if (nameproc == Process::DPP) { if (abs(p1.GetType()) == 11) - std::cout << "\nERROR!! wrong particle or process!! " << nameproc + std::cout << "\nERROR!! wrong particle or process!! " << " DPP " << p1.GetType() << "\n" << std::endl; fsmin = 16 * ElectronMass * ElectronMass; fsmax = 4 * p1.GetEnergy() * feps_sup * 2.0; } - if (nameproc == "ICS") { + if (nameproc == Process::ICS) { if (p1.GetType() == 22 || p1.GetType() == 9) - std::cout << "\nERROR!! wrong particle or process!! " << nameproc + std::cout << "\nERROR!! wrong particle or process!! " << " ICS " << p1.GetType() << "\n" << std::endl; fsmin = p1.GetMass() * p1.GetMass() + 2 * p1.GetEnergy() * feps_inf * (1 - p1.GetBeta()); fsmax = p1.GetMass() * p1.GetMass() + 2 * p1.GetEnergy() * feps_sup * (1 + p1.GetBeta()); } - if (nameproc == "TPP") { + if (nameproc == Process::TPP) { if (p1.GetType() == 22 || p1.GetType() == 9) - std::cout << "\nERROR!! wrong particle or process!! " << nameproc + std::cout << "\nERROR!! wrong particle or process!! " << " TPP " << p1.GetType() << "\n" << std::endl; fsmin = 10 * ElectronMass * ElectronMass; fsmax = 2 * p1.GetEnergy() * feps_sup * (1 + p1.GetBeta()) diff --git a/libs/EleCa/src/Propagation.cpp b/libs/EleCa/src/Propagation.cpp index 6f7a12732..38c35b834 100644 --- a/libs/EleCa/src/Propagation.cpp +++ b/libs/EleCa/src/Propagation.cpp @@ -150,20 +150,20 @@ double Propagation::ExtractMinDist(Process &proc, int type, double R, double R2, if (type == 22) { - proc1.SetName("PP"); + proc1.SetName(Process::PP); pt.SetEnergy(Etarget[0]); proc1.SetTargetParticle(pt); proc1.SetCMEnergy(); - tmp_lambda1 = GetLambdaTab(proc1, "PP"); + tmp_lambda1 = GetLambdaTab(proc1, Process::PP); min_dist1 = -tmp_lambda1 * log(R); - proc2.SetName("DPP"); + proc2.SetName(Process::DPP); pt.SetEnergy(Etarget[1]); proc2.SetTargetParticle(pt); proc2.SetCMEnergy(); - tmp_lambda2 = GetLambdaTab(proc2, "DPP"); + tmp_lambda2 = GetLambdaTab(proc2, Process::DPP); min_dist2 = -tmp_lambda2 * log(R2); #ifdef DEBUG_ELECA @@ -174,12 +174,12 @@ double Propagation::ExtractMinDist(Process &proc, int type, double R, double R2, if (min_dist2 < min_dist1) { min_dist1 = min_dist2; - proc.SetName("DPP"); + proc.SetName(Process::DPP); pt.SetEnergy(Etarget[1]); proc.SetTargetParticle(pt); proc.SetCMEnergy(); } else { - proc.SetName("PP"); + proc.SetName(Process::PP); pt.SetEnergy(Etarget[0]); proc.SetTargetParticle(pt); proc.SetCMEnergy(); @@ -187,16 +187,16 @@ double Propagation::ExtractMinDist(Process &proc, int type, double R, double R2, } //end if type 0 else if (abs(type) == 11) { - proc1.SetName("ICS"); + proc1.SetName(Process::ICS); pt.SetEnergy(Etarget[0]); proc1.SetTargetParticle(pt); - tmp_lambda1 = GetLambdaTab(proc1, "ICS"); + tmp_lambda1 = GetLambdaTab(proc1, Process::ICS); min_dist1 = -tmp_lambda1 * log(R); - proc2.SetName("TPP"); + proc2.SetName(Process::TPP); pt.SetEnergy(Etarget[1]); proc2.SetTargetParticle(pt); - tmp_lambda2 = GetLambdaTab(proc2, "TPP"); + tmp_lambda2 = GetLambdaTab(proc2, Process::TPP); min_dist2 = -tmp_lambda2 * log(R2); #ifdef DEBUG_ELECA @@ -207,12 +207,12 @@ double Propagation::ExtractMinDist(Process &proc, int type, double R, double R2, if (min_dist2 < min_dist1) { min_dist1 = min_dist2; - proc.SetName("TPP"); + proc.SetName(Process::TPP); pt.SetEnergy(Etarget[1]); proc.SetTargetParticle(pt); proc.SetCMEnergy(); } else { - proc.SetName("ICS"); + proc.SetName(Process::ICS); pt.SetEnergy(Etarget[0]); proc.SetTargetParticle(pt); proc.SetCMEnergy(); @@ -227,7 +227,7 @@ double Propagation::ExtractMinDist(Process &proc, int type, double R, double R2, } double Propagation::GetLambdaTab(const Process &proc, - const std::string &procName) const { + const Process::Name procName) const { double E1 = proc.GetIncidentParticle().GetEnergy(); double z = proc.GetIncidentParticle().Getz(); @@ -251,13 +251,13 @@ double Propagation::GetLambdaTab(const Process &proc, << ") .. returning lambda[nentries];" << std::endl; } else { - if (procName == "PP") + if (procName == Process::PP) res = vPPle[i]; - else if (procName == "DPP") + else if (procName == Process::DPP) res = vDPPle[i]; - else if (procName == "ICS") + else if (procName == Process::ICS) res = vICSle[i]; - else if (procName == "TPP") + else if (procName == Process::TPP) res = vTPPle[i]; } @@ -341,14 +341,14 @@ std::vector Propagation::GetEtarget(Process &proc, double Energy = particle.GetEnergy(); int pType = particle.GetType(); if (pType == 22) { - proc.SetName("PP"); + proc.SetName(Process::PP); proc.SetLimits(); smintmp = proc.GetMin(); Etarget_tmp = ShootPhotonEnergyMC(ElectronMass * ElectronMass / Energy, z_curr); Etarget.push_back(Etarget_tmp); - proc.SetName("DPP"); + proc.SetName(Process::DPP); proc.SetLimits(); smintmp = proc.GetMin(); Etarget_tmp = ShootPhotonEnergyMC(smintmp / (4.0 * Energy), z_curr); @@ -356,13 +356,13 @@ std::vector Propagation::GetEtarget(Process &proc, } else if (abs(pType) == 11) { - proc.SetName("ICS"); + proc.SetName(Process::ICS); proc.SetLimits(); smintmp = proc.GetMin(); Etarget_tmp = ShootPhotonEnergyMC(smintmp / (4.0 * Energy), z_curr); Etarget.push_back(Etarget_tmp); - proc.SetName("TPP"); + proc.SetName(Process::TPP); proc.SetLimits(); smintmp = proc.GetMin(); Etarget_tmp = ShootPhotonEnergyMC(smintmp / (4.0 * Energy), z_curr); @@ -581,7 +581,7 @@ void Propagation::Propagate(Particle &curr_particle, std::cerr << "******** producing secondary particles according to " << proc.GetName() << " process *********** " << std::endl; #endif - if (proc.GetName() == "PP") { + if (proc.GetName() == Process::PP) { E1 = ExtractPPSecondariesEnergy(proc); @@ -602,7 +602,7 @@ void Propagation::Propagate(Particle &curr_particle, return; } //if PP - else if (proc.GetName() == "DPP") { + else if (proc.GetName() == Process::DPP) { E1 = (Ecurr - 2 * ElectronMass) / 2.0; if (E1 == 0) std::cerr << "ERROR in DPP process E : " << E1 << std::endl; @@ -622,7 +622,7 @@ void Propagation::Propagate(Particle &curr_particle, return; } //end if DPP - else if (proc.GetName() == "ICS") { + else if (proc.GetName() == Process::ICS) { E1 = ExtractICSSecondariesEnergy(proc); E2 = Ecurr - E1; @@ -643,7 +643,7 @@ void Propagation::Propagate(Particle &curr_particle, return; } //if ics - else if (proc.GetName() == "TPP") { + else if (proc.GetName() == Process::TPP) { E1 = E2 = ExtractTPPSecondariesEnergy(proc); E3 = Ecurr - E1 - E2; if (E1 == 0 || E2 == 0 || E3 == 0) From a667c82122f47298b2dad142387a5417eeacb12c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Sun, 24 Aug 2014 21:02:54 +0200 Subject: [PATCH 0472/1298] fix Observer, add maximumTrajectory to ObserverSmallSphere --- include/crpropa/module/Observer.h | 5 ++++- src/module/Observer.cpp | 26 ++++++++++++++++++-------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/include/crpropa/module/Observer.h b/include/crpropa/module/Observer.h index dee2d6a47..9e041a8e3 100644 --- a/include/crpropa/module/Observer.h +++ b/include/crpropa/module/Observer.h @@ -5,6 +5,7 @@ #include #include +#include namespace crpropa { @@ -41,8 +42,10 @@ class ObserverSmallSphere: public ObserverFeature { private: Vector3d center; double radius; + double maximumTrajectory; public: - ObserverSmallSphere(Vector3d center = Vector3d(0.), double radius = 0); + ObserverSmallSphere(Vector3d center = Vector3d(0.), double radius = 0, + double maximumTrajectory = std::numeric_limits::max()); bool process(Candidate &candidate) const; }; diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp index e9cffc9c8..10d2490dc 100644 --- a/src/module/Observer.cpp +++ b/src/module/Observer.cpp @@ -9,29 +9,39 @@ void Observer::add(ObserverFeature *feature) { void Observer::process(Candidate *candidate) const { // loop over all features and have them check the particle + bool detected = true; for (int i = 0; i < features.size(); i++) { - bool b = (*features[i]).process(*candidate); - if (not (b)) - return; // not detected + detected = detected && features[i]->process(*candidate); } - if (makeInactive) + + if (detected && makeInactive) candidate->setActive(false); } -ObserverSmallSphere::ObserverSmallSphere(Vector3d center, double radius) : - center(center), radius(radius) { +ObserverSmallSphere::ObserverSmallSphere(Vector3d center, double radius, + double maximumTrajectory) : + center(center), radius(radius), maximumTrajectory(maximumTrajectory) { } bool ObserverSmallSphere::process(Candidate &candidate) const { // current distance to observer sphere center double d = (candidate.current.getPosition() - center).getR(); + double remainingToBorder = d - radius; + // conservatively limit next step to prevent overshooting - candidate.limitNextStep(fabs(d - radius)); + candidate.limitNextStep(fabs(remainingToBorder)); // no detection if outside of observer sphere - if (d > radius) + if (d > radius) { + // disable candidate if it cannot reach this observer + double remainingToMaximum = maximumTrajectory + - candidate.getTrajectoryLength(); + if (remainingToBorder > remainingToMaximum) + candidate.setActive(false); + return false; + } // previous distance to observer sphere center double dprev = (candidate.previous.getPosition() - center).getR(); From cd8baa0edfb7ce6f148756a235f250f7ebd8cf13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Sun, 24 Aug 2014 21:48:01 +0200 Subject: [PATCH 0473/1298] fix Observer, add DetectionState --- include/crpropa/module/Observer.h | 35 +++--- src/module/Observer.cpp | 179 ++++++++++++++++++------------ 2 files changed, 133 insertions(+), 81 deletions(-) diff --git a/include/crpropa/module/Observer.h b/include/crpropa/module/Observer.h index 9e041a8e3..dd9389d24 100644 --- a/include/crpropa/module/Observer.h +++ b/include/crpropa/module/Observer.h @@ -1,21 +1,30 @@ #ifndef CRPROPA_OBSERVER_H #define CRPROPA_OBSERVER_H -#include "crpropa/Module.h" - -#include #include #include +#include +#include + +#include "../Candidate.h" +#include "../Module.h" +#include "../Referenced.h" +#include "../Vector3.h" namespace crpropa { +enum DetectionState { + DETECTED, VETO, NOTHING +}; + /** @class ObserverFeature @brief Abstract base class for features of cosmic ray observers */ class ObserverFeature: public Referenced { public: - virtual bool process(Candidate &candidate) const = 0; + virtual DetectionState checkDetection(Candidate *candidate) const; + virtual void onDetection(Candidate *candidate) const; }; /** @@ -27,9 +36,7 @@ class Observer: public Module { std::vector > features; bool makeInactive; public: - Observer(bool makeInactive = false) : - makeInactive(makeInactive) { - } + Observer(bool makeInactive = false); void add(ObserverFeature *property); void process(Candidate *candidate) const; }; @@ -46,7 +53,7 @@ class ObserverSmallSphere: public ObserverFeature { public: ObserverSmallSphere(Vector3d center = Vector3d(0.), double radius = 0, double maximumTrajectory = std::numeric_limits::max()); - bool process(Candidate &candidate) const; + DetectionState checkDetection(Candidate *candidate) const; }; /** @@ -59,7 +66,7 @@ class ObserverLargeSphere: public ObserverFeature { double radius; public: ObserverLargeSphere(Vector3d center = Vector3d(0.), double radius = 0); - bool process(Candidate &candidate) const; + DetectionState checkDetection(Candidate *candidate) const; }; /** @@ -71,7 +78,7 @@ class ObserverRedshiftWindow: public ObserverFeature { double zmin, zmax; public: ObserverRedshiftWindow(double zmin = 0, double zmax = 0.1); - bool process(Candidate &candidate) const; + DetectionState checkDetection(Candidate *candidate) const; }; /** @@ -82,7 +89,7 @@ class ObserverRedshiftWindow: public ObserverFeature { */ class ObserverPoint: public ObserverFeature { public: - bool process(Candidate &candidate) const; + DetectionState checkDetection(Candidate *candidate) const; }; /** @@ -96,7 +103,7 @@ class ObserverOutput3D: public ObserverFeature { public: ObserverOutput3D(std::string filename, bool legacy = false); ~ObserverOutput3D(); - bool process(Candidate &candidate) const; + void onDetection(Candidate *candidate) const; }; /** @@ -110,7 +117,7 @@ class ObserverOutput1D: public ObserverFeature { public: ObserverOutput1D(std::string filename, bool legacy = false); ~ObserverOutput1D(); - bool process(Candidate &candidate) const; + void onDetection(Candidate *candidate) const; }; //////////////////////////////////////////////////////////////////////////////// @@ -122,6 +129,7 @@ class SmallObserverSphere: public Module { std::string flag; std::string flagValue; bool makeInactive; + double maximumTrajectory; public: SmallObserverSphere(Vector3d center = Vector3d(0.), double radius = 0, @@ -132,6 +140,7 @@ class SmallObserverSphere: public Module { void setRadius(double radius); void setFlag(std::string flag, std::string flagValue); void setMakeInactive(bool makeInactive); + void setMaximumTrajectory(double maximumTrajectory); std::string getDescription() const; }; diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp index 10d2490dc..45cfe1fcb 100644 --- a/src/module/Observer.cpp +++ b/src/module/Observer.cpp @@ -3,19 +3,40 @@ namespace crpropa { +DetectionState ObserverFeature::checkDetection(Candidate *candidate) const { + return NOTHING; +} + +void ObserverFeature::onDetection(Candidate *candidate) const { +} + +Observer::Observer(bool makeInactive) : + makeInactive(makeInactive) { +} + void Observer::add(ObserverFeature *feature) { features.push_back(feature); } void Observer::process(Candidate *candidate) const { // loop over all features and have them check the particle - bool detected = true; + DetectionState state = NOTHING; for (int i = 0; i < features.size(); i++) { - detected = detected && features[i]->process(*candidate); + DetectionState s = features[i]->checkDetection(candidate); + if (s == VETO) + state = VETO; + else if ((s == DETECTED) && (state != VETO)) + state = DETECTED; } - if (detected && makeInactive) - candidate->setActive(false); + if (state == DETECTED) { + for (int i = 0; i < features.size(); i++) { + features[i]->onDetection(candidate); + } + + if (makeInactive) + candidate->setActive(false); + } } ObserverSmallSphere::ObserverSmallSphere(Vector3d center, double radius, @@ -23,83 +44,84 @@ ObserverSmallSphere::ObserverSmallSphere(Vector3d center, double radius, center(center), radius(radius), maximumTrajectory(maximumTrajectory) { } -bool ObserverSmallSphere::process(Candidate &candidate) const { +DetectionState ObserverSmallSphere::checkDetection(Candidate *candidate) const { // current distance to observer sphere center - double d = (candidate.current.getPosition() - center).getR(); + double d = (candidate->current.getPosition() - center).getR(); double remainingToBorder = d - radius; // conservatively limit next step to prevent overshooting - candidate.limitNextStep(fabs(remainingToBorder)); + candidate->limitNextStep(fabs(remainingToBorder)); // no detection if outside of observer sphere if (d > radius) { // disable candidate if it cannot reach this observer double remainingToMaximum = maximumTrajectory - - candidate.getTrajectoryLength(); + - candidate->getTrajectoryLength(); if (remainingToBorder > remainingToMaximum) - candidate.setActive(false); + candidate->setActive(false); - return false; + return NOTHING; } // previous distance to observer sphere center - double dprev = (candidate.previous.getPosition() - center).getR(); + double dprev = (candidate->previous.getPosition() - center).getR(); // if particle was inside of sphere in previous step it has already been detected if (dprev <= radius) - return false; + return NOTHING; // else detection - return true; + return DETECTED; } ObserverLargeSphere::ObserverLargeSphere(Vector3d center, double radius) : center(center), radius(radius) { } -bool ObserverLargeSphere::process(Candidate &candidate) const { +DetectionState ObserverLargeSphere::checkDetection(Candidate *candidate) const { // current distance to observer sphere center - double d = (candidate.current.getPosition() - center).getR(); + double d = (candidate->current.getPosition() - center).getR(); // conservatively limit next step size to prevent overshooting - candidate.limitNextStep(fabs(radius - d)); + candidate->limitNextStep(fabs(radius - d)); // no detection if inside observer sphere if (d < radius) - return false; + return NOTHING; // previous distance to observer sphere center - double dprev = (candidate.previous.getPosition() - center).getR(); + double dprev = (candidate->previous.getPosition() - center).getR(); // if particle was outside of sphere in previous step it has already been detected if (dprev >= radius) - return false; + return NOTHING; // else: detection - return true; + return DETECTED; } -bool ObserverPoint::process(Candidate &candidate) const { - double x = candidate.current.getPosition().x; +DetectionState ObserverPoint::checkDetection(Candidate *candidate) const { + double x = candidate->current.getPosition().x; if (x > 0) { - candidate.limitNextStep(x); - return false; + candidate->limitNextStep(x); + return NOTHING; } - return true; + return DETECTED; } ObserverRedshiftWindow::ObserverRedshiftWindow(double zmin, double zmax) : zmin(zmin), zmax(zmax) { } -bool ObserverRedshiftWindow::process(Candidate & candidate) const { - double z = candidate.getRedshift(); +DetectionState ObserverRedshiftWindow::checkDetection( + Candidate *candidate) const { + double z = candidate->getRedshift(); if (z > zmax) - return false; + return VETO; if (z < zmin) - return false; - return true; + return VETO; + return NOTHING; } ObserverOutput3D::ObserverOutput3D(std::string fname, bool legacy) : @@ -133,43 +155,47 @@ ObserverOutput3D::~ObserverOutput3D() { fout.close(); } -bool ObserverOutput3D::process(Candidate &c) const { +void ObserverOutput3D::onDetection(Candidate *candidate) const { char buffer[256]; size_t p = 0; if (legacy) { p += sprintf(buffer + p, "%i ", - convertToCRPropa2NucleusId(c.current.getId())); + convertToCRPropa2NucleusId(candidate->current.getId())); p += sprintf(buffer + p, "%i ", - convertToCRPropa2NucleusId(c.source.getId())); - Vector3d ipos = c.source.getPosition() / Mpc; + convertToCRPropa2NucleusId(candidate->source.getId())); + Vector3d ipos = candidate->source.getPosition() / Mpc; p += sprintf(buffer + p, "%.4f %.4f %.4f ", ipos.x, ipos.y, ipos.z); - double iPhi = c.source.getDirection().getPhi(); - double iTheta = c.source.getDirection().getTheta(); - double iE = c.source.getEnergy() / EeV; + double iPhi = candidate->source.getDirection().getPhi(); + double iTheta = candidate->source.getDirection().getTheta(); + double iE = candidate->source.getEnergy() / EeV; p += sprintf(buffer + p, "%.4f %.4f %.4f ", iE, iPhi, iTheta); - double t = comoving2LightTravelDistance(c.getTrajectoryLength()) / Mpc; + double t = comoving2LightTravelDistance( + candidate->getTrajectoryLength()) / Mpc; p += sprintf(buffer + p, "%.4f ", t); - Vector3d pos = c.current.getPosition() / Mpc; + Vector3d pos = candidate->current.getPosition() / Mpc; p += sprintf(buffer + p, "%.4f %.4f %.4f ", pos.x, pos.y, pos.z); - double phi = c.current.getDirection().getPhi(); - double theta = c.current.getDirection().getTheta(); - double E = c.current.getEnergy() / EeV; + double phi = candidate->current.getDirection().getPhi(); + double theta = candidate->current.getDirection().getTheta(); + double E = candidate->current.getEnergy() / EeV; p += sprintf(buffer + p, "%.4f %.4f %.4f\n", E, phi, theta); } else { - p += sprintf(buffer + p, "%8.3f\t", c.getTrajectoryLength() / Mpc); - p += sprintf(buffer + p, "%10i\t", c.current.getId()); - p += sprintf(buffer + p, "%10i\t", c.source.getId()); - p += sprintf(buffer + p, "%8.4f\t", c.current.getEnergy() / EeV); - p += sprintf(buffer + p, "%8.4f\t", c.source.getEnergy() / EeV); - Vector3d pos = c.current.getPosition() / Mpc; + p += sprintf(buffer + p, "%8.3f\t", + candidate->getTrajectoryLength() / Mpc); + p += sprintf(buffer + p, "%10i\t", candidate->current.getId()); + p += sprintf(buffer + p, "%10i\t", candidate->source.getId()); + p += sprintf(buffer + p, "%8.4f\t", + candidate->current.getEnergy() / EeV); + p += sprintf(buffer + p, "%8.4f\t", + candidate->source.getEnergy() / EeV); + Vector3d pos = candidate->current.getPosition() / Mpc; p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", pos.x, pos.y, pos.z); - Vector3d ipos = c.source.getPosition() / Mpc; + Vector3d ipos = candidate->source.getPosition() / Mpc; p += sprintf(buffer + p, "%9.4f\t%9.4f\t%9.4f\t", ipos.x, ipos.y, ipos.z); - Vector3d dir = c.current.getDirection(); + Vector3d dir = candidate->current.getDirection(); p += sprintf(buffer + p, "%8.5f\t%8.5f\t%8.5f\t", dir.x, dir.y, dir.z); - Vector3d idir = c.source.getDirection(); + Vector3d idir = candidate->source.getDirection(); p += sprintf(buffer + p, "%8.5f\t%8.5f\t%8.5f\n", idir.x, idir.y, idir.z); } @@ -179,8 +205,6 @@ bool ObserverOutput3D::process(Candidate &c) const { fout.write(buffer, p); fout.flush(); } - - return true; } ObserverOutput1D::ObserverOutput1D(std::string filename, bool legacy) : @@ -208,25 +232,29 @@ ObserverOutput1D::~ObserverOutput1D() { fout.close(); } -bool ObserverOutput1D::process(Candidate& c) const { +void ObserverOutput1D::onDetection(Candidate *candidate) const { char buffer[256]; size_t p = 0; if (legacy) { p += sprintf(buffer + p, "%i ", - convertToCRPropa2NucleusId(c.current.getId())); - p += sprintf(buffer + p, "%.4f ", c.current.getEnergy() / EeV); - double t = comoving2LightTravelDistance(c.getTrajectoryLength()) / Mpc; + convertToCRPropa2NucleusId(candidate->current.getId())); + p += sprintf(buffer + p, "%.4f ", candidate->current.getEnergy() / EeV); + double t = comoving2LightTravelDistance( + candidate->getTrajectoryLength()) / Mpc; p += sprintf(buffer + p, "%.4f ", t); p += sprintf(buffer + p, "%i ", - convertToCRPropa2NucleusId(c.source.getId())); - p += sprintf(buffer + p, "%.4f\n", c.source.getEnergy() / EeV); + convertToCRPropa2NucleusId(candidate->source.getId())); + p += sprintf(buffer + p, "%.4f\n", candidate->source.getEnergy() / EeV); } else { - p += sprintf(buffer + p, "%10i\t", c.current.getId()); - p += sprintf(buffer + p, "%8.4f\t", c.current.getEnergy() / EeV); - p += sprintf(buffer + p, "%9.4f\t", c.getTrajectoryLength() / Mpc); - p += sprintf(buffer + p, "%10i\t", c.source.getId()); - p += sprintf(buffer + p, "%8.4f\n", c.source.getEnergy() / EeV); + p += sprintf(buffer + p, "%10i\t", candidate->current.getId()); + p += sprintf(buffer + p, "%8.4f\t", + candidate->current.getEnergy() / EeV); + p += sprintf(buffer + p, "%9.4f\t", + candidate->getTrajectoryLength() / Mpc); + p += sprintf(buffer + p, "%10i\t", candidate->source.getId()); + p += sprintf(buffer + p, "%8.4f\n", + candidate->source.getEnergy() / EeV); } #pragma omp critical @@ -234,7 +262,6 @@ bool ObserverOutput1D::process(Candidate& c) const { fout.write(buffer, p); fout.flush(); } - return true; } //////////////////////////////////////////////////////////////////////////////// @@ -242,19 +269,29 @@ bool ObserverOutput1D::process(Candidate& c) const { SmallObserverSphere::SmallObserverSphere(Vector3d center, double radius, std::string flag, std::string flagValue, bool makeInactive) : center(center), radius(radius), flag(flag), flagValue(flagValue), makeInactive( - makeInactive) { + makeInactive), maximumTrajectory( + std::numeric_limits::max()) { } void SmallObserverSphere::process(Candidate *candidate) const { // current distance to observer sphere center double d = (candidate->current.getPosition() - center).getR(); + double remainingToBorder = d - radius; // conservatively limit next step to prevent overshooting - candidate->limitNextStep(fabs(d - radius)); + candidate->limitNextStep(fabs(remainingToBorder)); // no detection if outside of observer sphere - if (d > radius) + if (d > radius) { + + // disable candidate if it cannot reach this observer + double remainingToMaximum = maximumTrajectory + - candidate->getTrajectoryLength(); + if (remainingToBorder > remainingToMaximum) + candidate->setActive(false); + return; + } // previous distance to observer sphere center double dprev = (candidate->previous.getPosition() - center).getR(); @@ -286,11 +323,17 @@ void SmallObserverSphere::setMakeInactive(bool b) { makeInactive = b; } +void SmallObserverSphere::setMaximumTrajectory(double maximumTrajectory) { + this->maximumTrajectory = maximumTrajectory; +} + std::string SmallObserverSphere::getDescription() const { std::stringstream s; s << "Small observer sphere: " << radius / Mpc; s << " Mpc radius around " << center / Mpc; s << " Mpc, Flag: '" << flag << "' -> '" << flagValue << "'"; + if (maximumTrajectory != std::numeric_limits::max()) + s << ", maximum trajectory: " << maximumTrajectory; if (makeInactive) s << ", render inactivate"; return s.str(); From 76d69c147357b871dff67c8a0d3510cd03c5f74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Sun, 24 Aug 2014 22:59:15 +0200 Subject: [PATCH 0474/1298] improve progrssbar and signal handling --- include/crpropa/ProgressBar.h | 62 ++---------------------------- src/ModuleList.cpp | 20 +++++++--- src/ProgressBar.cpp | 71 +++++++++++++++++++++++++++++++++++ src/module/Observer.cpp | 2 +- 4 files changed, 90 insertions(+), 65 deletions(-) create mode 100644 src/ProgressBar.cpp diff --git a/include/crpropa/ProgressBar.h b/include/crpropa/ProgressBar.h index 9f403fc42..b4a6446a3 100644 --- a/include/crpropa/ProgressBar.h +++ b/include/crpropa/ProgressBar.h @@ -21,69 +21,15 @@ class ProgressBar { public: /// Initialize a ProgressBar with [steps] number of steps, updated at [updateSteps] intervalls - ProgressBar(unsigned long steps = 0, unsigned long updateSteps = 100) : - _steps(steps), _currentCount(0), _maxbarLength(10), _updateSteps( - updateSteps), _nextStep(1), _startTime(0) { - if (_updateSteps > _steps) - _updateSteps = _steps; - arrow.append(">"); - } + ProgressBar(unsigned long steps = 0, unsigned long updateSteps = 100); + void start(const std::string &title); - void start(const std::string &title) { - _startTime = time(NULL); - std::string s = ctime(&_startTime); - s.erase(s.end() - 1, s.end()); - stringTmpl = " Started "; - stringTmpl.append(s); - stringTmpl.append(" : [%-10s] %3i%% %s: %02i:%02is %s\r"); - std::cout << title << std::endl; - - } /// update the progressbar /// should be called steps times in a loop - void update() { - _currentCount++; - if (_currentCount == _nextStep || _currentCount == _steps) { - _nextStep += long(_steps / float(_updateSteps)); - - int percentage = int(100 * _currentCount / float(_steps)); - time_t currentTime = time(NULL); - if (_currentCount < _steps) { - int j = 0; - if (arrow.size() - <= (_maxbarLength) * (_currentCount) / (_steps)) - arrow.insert(0, "="); - float tElapsed = currentTime - _startTime; - float tToGo = (_steps - _currentCount) * tElapsed - / _currentCount; - printf(stringTmpl.c_str(), arrow.c_str(), percentage, - "Finish in", int(tToGo / 60), int(tToGo) % 60, ""); - fflush(stdout); - } else { - float tElapsed = currentTime - _startTime; - std::string s = " - Finished at "; - s.append(ctime(¤tTime)); - char fs[255]; - sprintf(fs, "%c[%d;%dm Finished %c[%dm", 27, 1, 32, 27, 0); - printf(stringTmpl.c_str(), fs, percentage, "Needed", - int(tElapsed / 60), int(tElapsed) % 60, s.c_str()); - } - } - } + void update(); /// Mark the progressbar with an error - void setError() { - time_t currentTime = time(NULL); - _currentCount++; - float tElapsed = currentTime - _startTime; - std::string s = " - Finished at "; - s.append(ctime(¤tTime)); - char fs[255]; - sprintf(fs, "%c[%d;%dm ERROR %c[%dm", 27, 1, 31, 27, 0); - printf(stringTmpl.c_str(), fs, _currentCount, "Needed", - int(tElapsed / 60), int(tElapsed) % 60, s.c_str()); - } - + void setError(); }; } // namespace crpropa diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 34b09ad2f..3d1112480 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -49,9 +49,13 @@ void ModuleList::run(Candidate *candidate, bool recursive) { process(candidate); // propagate secondaries - if (recursive) - for (size_t i = 0; i < candidate->secondaries.size(); i++) + if (recursive) { + for (size_t i = 0; i < candidate->secondaries.size(); i++) { + if (g_cancel_signal_flag) + break; run(candidate->secondaries[i], recursive); + } + } } void ModuleList::run(candidate_vector_t &candidates, bool recursive) { @@ -73,8 +77,10 @@ void ModuleList::run(candidate_vector_t &candidates, bool recursive) { #pragma omp parallel for schedule(static, 1000) for (size_t i = 0; i < count; i++) { - if (!g_cancel_signal_flag) - run(candidates[i], recursive); + if (g_cancel_signal_flag) + continue; + + run(candidates[i], recursive); if (showProgress) #pragma omp critical(progressbarUpdate) @@ -102,9 +108,11 @@ void ModuleList::run(Source *source, size_t count, bool recursive) { #pragma omp parallel for schedule(static, 1000) for (size_t i = 0; i < count; i++) { + if (g_cancel_signal_flag) + continue; + ref_ptr candidate = source->getCandidate(); - if (!g_cancel_signal_flag) - run(candidate, recursive); + run(candidate, recursive); if (showProgress) #pragma omp critical(progressbarUpdate) diff --git a/src/ProgressBar.cpp b/src/ProgressBar.cpp new file mode 100644 index 000000000..0143fdcbb --- /dev/null +++ b/src/ProgressBar.cpp @@ -0,0 +1,71 @@ +#include "crpropa/ProgressBar.h" + +namespace crpropa { + +/// Initialize a ProgressBar with [steps] number of steps, updated at [updateSteps] intervalls +ProgressBar::ProgressBar(unsigned long steps, unsigned long updateSteps) : + _steps(steps), _currentCount(0), _maxbarLength(10), _updateSteps( + updateSteps), _nextStep(1), _startTime(0) { + if (_updateSteps > _steps) + _updateSteps = _steps; + arrow.append(">"); +} + +void ProgressBar::start(const std::string &title) { + _startTime = time(NULL); + std::string s = ctime(&_startTime); + s.erase(s.end() - 1, s.end()); + stringTmpl = " Started "; + stringTmpl.append(s); + stringTmpl.append(" : [%-10s] %3i%% %s: %02i:%02i:%02i %s\r"); + std::cout << title << std::endl; + +} +/// update the progressbar +/// should be called steps times in a loop +void ProgressBar::update() { + _currentCount++; + if (_currentCount == _nextStep || _currentCount == _steps + || _currentCount == 1000) { + _nextStep += long(_steps / float(_updateSteps)); + + int percentage = int(100 * _currentCount / float(_steps)); + time_t currentTime = time(NULL); + if (_currentCount < _steps) { + int j = 0; + if (arrow.size() <= (_maxbarLength) * (_currentCount) / (_steps)) + arrow.insert(0, "="); + float tElapsed = currentTime - _startTime; + float tToGo = (_steps - _currentCount) * tElapsed / _currentCount; + printf(stringTmpl.c_str(), arrow.c_str(), percentage, "Finish in", + int(tToGo / 3600), (int(tToGo) % 3600) / 60, + int(tToGo) % 60, ""); + fflush(stdout); + } else { + float tElapsed = currentTime - _startTime; + std::string s = " - Finished at "; + s.append(ctime(¤tTime)); + char fs[255]; + sprintf(fs, "%c[%d;%dm Finished %c[%dm", 27, 1, 32, 27, 0); + printf(stringTmpl.c_str(), fs, percentage, "Needed", + int(tElapsed / 3600), (int(tElapsed) % 3600) / 60, + int(tElapsed) % 60, s.c_str()); + } + } +} + +/// Mark the progressbar with an error +void ProgressBar::setError() { + time_t currentTime = time(NULL); + _currentCount++; + float tElapsed = currentTime - _startTime; + std::string s = " - Finished at "; + s.append(ctime(¤tTime)); + char fs[255]; + sprintf(fs, "%c[%d;%dm ERROR %c[%dm", 27, 1, 31, 27, 0); + printf(stringTmpl.c_str(), fs, _currentCount, "Needed", + int(tElapsed / 3600), (int(tElapsed) % 3600) / 60, + int(tElapsed) % 60, s.c_str()); +} + +} // namespace crpropa diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp index 45cfe1fcb..9d73701fb 100644 --- a/src/module/Observer.cpp +++ b/src/module/Observer.cpp @@ -333,7 +333,7 @@ std::string SmallObserverSphere::getDescription() const { s << " Mpc radius around " << center / Mpc; s << " Mpc, Flag: '" << flag << "' -> '" << flagValue << "'"; if (maximumTrajectory != std::numeric_limits::max()) - s << ", maximum trajectory: " << maximumTrajectory; + s << ", Maximum trajectory: " << maximumTrajectory / Mpc << "Mpc"; if (makeInactive) s << ", render inactivate"; return s.str(); From 9dfc6d2a186553c681f6ed698d144d9f91244c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Sun, 24 Aug 2014 23:02:43 +0200 Subject: [PATCH 0475/1298] add check if data directory exists --- CMakeLists.txt | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4536cd85c..b8f730291 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,19 +126,23 @@ endif(MUPARSER_FOUND) # ---------------------------------------------------------------------------- # Downloading data files (interaction data, masses, decay times) # ---------------------------------------------------------------------------- -set(DATA_URL "http://crpropa.desy.de/images/f/ff/Data20140803.tar.gz") -set(DATA_MD5SUM "1f0016cf3b1cf31250293de08d7fe759") -message("Downloading data files from crpropa.desy.de ~ 30 MB") -if(CMAKE_VERSION GREATER 2.6) - file(DOWNLOAD ${DATA_URL} ${CMAKE_SOURCE_DIR}/data.tar.gz STATUS status EXPECTED_MD5 ${DATA_MD5SUM}) -else() - execute_process(COMMAND wget ${DATA_URL} -O ${CMAKE_SOURCE_DIR}/data.tar.gz --no-check-certificate RESULT_VARIABLE status) -endif(CMAKE_VERSION GREATER 2.6) -message("Download complete: ${status}") -message("If the download failed, please manually obtain the file from " ${DATA_URL} " and extract to ./data before 'make install'") - -file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/data) -execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_SOURCE_DIR}/data.tar.gz WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/data) +IF(NOT IS_DIRECTORY ${CMAKE_SOURCE_DIR}/data) + set(DATA_URL "http://crpropa.desy.de/images/f/ff/Data20140803.tar.gz") + set(DATA_MD5SUM "1f0016cf3b1cf31250293de08d7fe759") + message("Downloading data files from crpropa.desy.de ~ 30 MB") + if(CMAKE_VERSION GREATER 2.6) + file(DOWNLOAD ${DATA_URL} ${CMAKE_SOURCE_DIR}/data.tar.gz STATUS status EXPECTED_MD5 ${DATA_MD5SUM}) + else() + execute_process(COMMAND wget ${DATA_URL} -O ${CMAKE_SOURCE_DIR}/data.tar.gz --no-check-certificate RESULT_VARIABLE status) + endif(CMAKE_VERSION GREATER 2.6) + message("Download complete: ${status}") + message("If the download failed, please manually obtain the file from " ${DATA_URL} " and extract to ./data before 'make install'") + + file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/data) + execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_SOURCE_DIR}/data.tar.gz WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/data) +ELSE() + message(STATUS "Using exisitng data files.") +ENDIF() # ---------------------------------------------------------------------------- # Library and Binary @@ -154,6 +158,7 @@ add_library(crpropa SHARED src/ParticleState.cpp src/ParticleID.cpp src/ParticleMass.cpp + src/ProgressBar.cpp src/Cosmology.cpp src/Source.cpp src/Common.cpp From bc660b45a65992f0ff1a8f7384200804695424e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Mon, 25 Aug 2014 13:42:30 +0200 Subject: [PATCH 0476/1298] fix/improve photodisintegration code --- src/module/PhotoDisintegration.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index bbcd03d4b..5ce2d42c8 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -130,11 +130,12 @@ void PhotoDisintegration::process(Candidate *candidate) const { int A = massNumber(id); int Z = chargeNumber(id); int N = A - Z; + size_t idx = Z * 31 + N; // check if disintegration data available if ((Z > 26) or (N > 30)) return; - if (pdRate[Z * 31 + N].size() == 0) + if (pdRate[idx].size() == 0) return; // check if in tabulated energy range @@ -144,9 +145,9 @@ void PhotoDisintegration::process(Candidate *candidate) const { return; double rate = interpolateEquidistant(lg, lgmin, lgmax, - pdRate[Z * 31 + N]); + pdRate[idx]); - // comological scaling, rate per comoving distance) + // cosmological scaling, rate per comoving distance) rate *= pow(1 + z, 2) * photonFieldScaling(photonField, z); Random &random = Random::instance(); @@ -164,10 +165,13 @@ void PhotoDisintegration::process(Candidate *candidate) const { int channel; int l = round(lg / (lgmax - lgmin) * (nlg - 1)); // index of closest tabulated point - std::vector branches = pdBranch[Z * 31 + N]; + const std::vector &branches = pdBranch[idx]; for (size_t i = 0; i < branches.size(); i++) { - channel = branches[i].channel; - cmp -= branches[i].branchingRatio[l]; + const Branch &branch = branches[i]; + channel = branch.channel; + if ((l < 0) || (l >= branch.branchingRatio.size())) + continue; + cmp -= branch.branchingRatio[l]; if (cmp <= 0) break; } @@ -228,11 +232,12 @@ double PhotoDisintegration::lossLength(int id, double E, double z) { int A = massNumber(id); int Z = chargeNumber(id); int N = A - Z; + size_t idx = Z * 31 + N; // check if disintegration data available if ((Z > 26) or (N > 30)) return std::numeric_limits::max(); - std::vector rate = pdRate[Z * 31 + N]; + const std::vector &rate = pdRate[idx]; if (rate.size() == 0) return std::numeric_limits::max(); @@ -249,7 +254,7 @@ double PhotoDisintegration::lossLength(int id, double E, double z) { // average number of nucleons lost for all disintegration channels double avg_dA = 0; - std::vector branches = pdBranch[Z * 31 + N]; + const std::vector &branches = pdBranch[idx]; for (size_t i = 0; i < branches.size(); i++) { int channel = branches[i].channel; int dA = 0; From 655f3637109c31567a5b14cc5aae2602c93931c6 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Tue, 26 Aug 2014 10:07:09 +0200 Subject: [PATCH 0477/1298] Eleca: Make spectrum binning configurable --- include/crpropa/PhotonPropagation.h | 4 +++- src/PhotonPropagation.cpp | 11 +++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/crpropa/PhotonPropagation.h b/include/crpropa/PhotonPropagation.h index 2ad2920a1..b98841e4b 100644 --- a/include/crpropa/PhotonPropagation.h +++ b/include/crpropa/PhotonPropagation.h @@ -9,11 +9,13 @@ namespace crpropa { void EleCaPropagation(const std::string &inputfile, const std::string &background, std::vector &energy, std::vector &spectrum, - double lowerEnergyThreshold = 1E16 + double lowerEnergyThreshold = 1E16, + double stepSize = 0.2 ); void EleCaPropagation(const std::string &inputfile, const std::string &outputfile, double lowerEnergyThreshold = 1E16, + double stepSize = 0.2, const std::string &background = "ALL"); void DintPropagation(const std::string &inputfile, const std::string &outputfile, int IRFlag = 2, int RadioFlag = 2, diff --git a/src/PhotonPropagation.cpp b/src/PhotonPropagation.cpp index 355fbd236..f18dc90b2 100644 --- a/src/PhotonPropagation.cpp +++ b/src/PhotonPropagation.cpp @@ -20,11 +20,12 @@ namespace crpropa { void EleCaPropagation(const std::string &inputfile, const std::string &background, std::vector &energy, std::vector &spectrum, - double lowerEnergyThreshold + double lowerEnergyThreshold, + double stepSize ) { std::ifstream infile(inputfile.c_str()); - const double emin = log10(lowerEnergyThreshold), emax = 22, step = 0.2; + const double emin = log10(lowerEnergyThreshold), emax = 22, step = stepSize; const size_t steps = (emax - emin) / step; energy.clear(); energy.resize(steps); @@ -87,9 +88,11 @@ void EleCaPropagation(const std::string &inputfile, } void EleCaPropagation(const std::string &inputfile, - const std::string &outputfile, double lowerEnergyThreshold, const std::string &background) { + const std::string &outputfile, double lowerEnergyThreshold, + double stepSize, + const std::string &background) { std::vector energy, spectrum; - EleCaPropagation(inputfile, background, energy, spectrum, lowerEnergyThreshold); + EleCaPropagation(inputfile, background, energy, spectrum, lowerEnergyThreshold, stepSize); std::ofstream output(outputfile.c_str()); output << "# E N\n"; for (size_t i = 0; i < energy.size(); i++) { From fc6b0a9bfdbef0d8e2bb7cf70dd2a353cfe7e6e9 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 26 Aug 2014 10:11:49 +0200 Subject: [PATCH 0478/1298] Fix not updating data files due to present data folder --- CMakeLists.txt | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b8f730291..f66dfe684 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,23 +126,19 @@ endif(MUPARSER_FOUND) # ---------------------------------------------------------------------------- # Downloading data files (interaction data, masses, decay times) # ---------------------------------------------------------------------------- -IF(NOT IS_DIRECTORY ${CMAKE_SOURCE_DIR}/data) - set(DATA_URL "http://crpropa.desy.de/images/f/ff/Data20140803.tar.gz") - set(DATA_MD5SUM "1f0016cf3b1cf31250293de08d7fe759") - message("Downloading data files from crpropa.desy.de ~ 30 MB") - if(CMAKE_VERSION GREATER 2.6) - file(DOWNLOAD ${DATA_URL} ${CMAKE_SOURCE_DIR}/data.tar.gz STATUS status EXPECTED_MD5 ${DATA_MD5SUM}) - else() - execute_process(COMMAND wget ${DATA_URL} -O ${CMAKE_SOURCE_DIR}/data.tar.gz --no-check-certificate RESULT_VARIABLE status) - endif(CMAKE_VERSION GREATER 2.6) - message("Download complete: ${status}") - message("If the download failed, please manually obtain the file from " ${DATA_URL} " and extract to ./data before 'make install'") - - file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/data) - execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_SOURCE_DIR}/data.tar.gz WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/data) -ELSE() - message(STATUS "Using exisitng data files.") -ENDIF() +set(DATA_URL "http://crpropa.desy.de/images/f/ff/Data20140803.tar.gz") +set(DATA_MD5SUM "1f0016cf3b1cf31250293de08d7fe759") +message("Downloading data files from crpropa.desy.de ~ 30 MB") +if(CMAKE_VERSION GREATER 2.6) + file(DOWNLOAD ${DATA_URL} ${CMAKE_SOURCE_DIR}/data.tar.gz STATUS status EXPECTED_MD5 ${DATA_MD5SUM}) +else() + execute_process(COMMAND wget ${DATA_URL} -O ${CMAKE_SOURCE_DIR}/data.tar.gz --no-check-certificate RESULT_VARIABLE status) +endif(CMAKE_VERSION GREATER 2.6) +message("Download complete: ${status}") +message("If the download failed, please manually obtain the file from " ${DATA_URL} " and extract to ./data before 'make install'") + +file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/data) +execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_SOURCE_DIR}/data.tar.gz WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/data) # ---------------------------------------------------------------------------- # Library and Binary From 52b9dfc26fc2ba598332a58004c29f9d09856b1e Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 26 Aug 2014 11:13:48 +0200 Subject: [PATCH 0479/1298] fix bug: no interactions on neutrons --- src/ParticleID.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ParticleID.cpp b/src/ParticleID.cpp index 05b7bdcf5..745d83be5 100644 --- a/src/ParticleID.cpp +++ b/src/ParticleID.cpp @@ -42,6 +42,8 @@ int massNumber(int id) { } bool isNucleus(int id) { + if (id == 2112) + return true; // consider neutron as nucleus return HepPID::isNucleus(id); } From b5b174ca4a0643377bdb979fc773b9ac04a32d93 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 26 Aug 2014 11:17:37 +0200 Subject: [PATCH 0480/1298] remove obsolete PropertyStatistics and ParticleSelector --- CMakeLists.txt | 2 +- include/crpropa/ParticleID.h | 4 +-- include/crpropa/module/Tools.h | 29 ------------------- src/ParticleID.cpp | 12 -------- src/module/Tools.cpp | 51 ---------------------------------- test/testBreakCondition.cpp | 19 ------------- 6 files changed, 2 insertions(+), 115 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f66dfe684..b49131f6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,7 +124,7 @@ if(MUPARSER_FOUND) endif(MUPARSER_FOUND) # ---------------------------------------------------------------------------- -# Downloading data files (interaction data, masses, decay times) +# Downloading data files (interaction data, masses, decay data) # ---------------------------------------------------------------------------- set(DATA_URL "http://crpropa.desy.de/images/f/ff/Data20140803.tar.gz") set(DATA_MD5SUM "1f0016cf3b1cf31250293de08d7fe759") diff --git a/include/crpropa/ParticleID.h b/include/crpropa/ParticleID.h index 986f4b369..68a1086ca 100644 --- a/include/crpropa/ParticleID.h +++ b/include/crpropa/ParticleID.h @@ -6,9 +6,6 @@ namespace crpropa { -std::vector neutrinos(); -std::vector leptons(); - /** This implements the 2012 Monte Carlo nuclear code scheme. * Ion numbers are +/- 10LZZZAAAI. * AAA is A - total baryon number @@ -19,6 +16,7 @@ std::vector leptons(); int nucleusId(int a, int z); int chargeNumber(int id); int massNumber(int id); + bool isNucleus(int id); /* CRPropa2.0 code scheme */ diff --git a/include/crpropa/module/Tools.h b/include/crpropa/module/Tools.h index 525d39ae4..7a07c350b 100644 --- a/include/crpropa/module/Tools.h +++ b/include/crpropa/module/Tools.h @@ -2,7 +2,6 @@ #define CRPROPA_MODULETOOLS_H #include "crpropa/Module.h" -#include "crpropa/AssocVector.h" #include @@ -25,34 +24,6 @@ class PerformanceModule: public Module { std::string getDescription() const; }; -class PropertyStatistics: public Module { -private: - mutable Loki::AssocVector properties; - std::string key; - -public: - PropertyStatistics(const std::string &key); - ~PropertyStatistics(); - void process(Candidate *candidate) const; -}; - -/** - @class ParticleSelector - @brief Wraps a module and only executes it for certain particle types - */ -class ParticleSelector: public Module { -private: - std::vector ids; - ref_ptr module; - -public: - ParticleSelector(Module* module); - ParticleSelector(Module* module, std::vector particleIDs); - void add(int particleId); - void process(Candidate *candidate) const; - std::string getDescription() const; -}; - } // namespace crpropa #endif // CRPROPA_MODULETOOLS_H diff --git a/src/ParticleID.cpp b/src/ParticleID.cpp index 745d83be5..ad62ce68d 100644 --- a/src/ParticleID.cpp +++ b/src/ParticleID.cpp @@ -5,18 +5,6 @@ namespace crpropa { -std::vector neutrinos() { - int a[] = { 12, -12, 14, -14, 16, -16 }; - std::vector v(a, a + sizeof(a) / sizeof(int)); - return v; -} - -std::vector leptons() { - int a[] = { 11, -11, 12, -12, 13, -13, 14, -14, 15, -15, 16, -16 }; - std::vector v(a, a + sizeof(a) / sizeof(int)); - return v; -} - int nucleusId(int a, int z) { if (z < 0) throw std::runtime_error( diff --git a/src/module/Tools.cpp b/src/module/Tools.cpp index 9d0246934..bca19cce0 100644 --- a/src/module/Tools.cpp +++ b/src/module/Tools.cpp @@ -63,55 +63,4 @@ string PerformanceModule::getDescription() const { return sstr.str(); } -PropertyStatistics::PropertyStatistics(const std::string &key) : - key(key) { - setDescription("PropertyStatistics: " + key); -} - -PropertyStatistics::~PropertyStatistics() { - std::cout << "Property Statistics for " << key << ":" << std::endl; - Loki::AssocVector::iterator i; - for (i = properties.begin(); i != properties.end(); i++) { - std::cout << i->first << "\t\t-> " << i->second << std::endl; - } -} - -void PropertyStatistics::process(Candidate *candidate) const { - std::string property; - if (candidate->getProperty(key, property)) { -#pragma omp critical - { - Loki::AssocVector::iterator i = - properties.find(property); - if (i == properties.end()) { - properties[property] = 1; - } else { - i->second++; - } - } - } -} - -ParticleSelector::ParticleSelector(Module *m) : - module(m) { -} - -ParticleSelector::ParticleSelector(Module *m, std::vector particleIDs) : - module(m), ids(particleIDs) { -} - -void ParticleSelector::add(int particleID) { - ids.push_back(particleID); -} - -void ParticleSelector::process(Candidate* candidate) const { - int id = candidate->current.getId(); - if (std::find(ids.begin(), ids.end(), id) != ids.end()) - module->process(candidate); -} - -std::string ParticleSelector::getDescription() const { - return "ParticleSelector"; -} - } // namespace crpropa diff --git a/test/testBreakCondition.cpp b/test/testBreakCondition.cpp index 9d36b52ce..87ccfe893 100644 --- a/test/testBreakCondition.cpp +++ b/test/testBreakCondition.cpp @@ -326,25 +326,6 @@ TEST(EllipsoidalBoundary, limitStep) { EXPECT_DOUBLE_EQ(c.getNextStep(), 1.5); } -//** ============================ Tools ===================================== */ -TEST(ParticleSelector, neutrinos) { - // Test if ParticleSelector only activates for neutrinos - // Use DetectAll as test module - ParticleSelector selector(new DetectAll(), neutrinos()); - - Candidate c1; - c1.current.setId(12); // electron neutrino - c1.setTrajectoryLength(5 * Mpc); - selector.process(&c1); - EXPECT_FALSE(c1.isActive()); - - Candidate c2; - c2.current.setId(nucleusId(1, 1)); // proton - c2.setTrajectoryLength(5 * Mpc); - selector.process(&c2); - EXPECT_TRUE(c2.isActive()); -} - int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); From 9caa1b576d58ab94082eb15cee04a55dba9e8630 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 26 Aug 2014 11:29:57 +0200 Subject: [PATCH 0481/1298] add obsever particle id vetos, remove elliptic boundary from small observer sphere --- include/crpropa/module/Observer.h | 32 +++++++++++++++++++++++--- src/module/Observer.cpp | 37 +++++++++++++++++++------------ 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/include/crpropa/module/Observer.h b/include/crpropa/module/Observer.h index dd9389d24..323122555 100644 --- a/include/crpropa/module/Observer.h +++ b/include/crpropa/module/Observer.h @@ -49,10 +49,8 @@ class ObserverSmallSphere: public ObserverFeature { private: Vector3d center; double radius; - double maximumTrajectory; public: - ObserverSmallSphere(Vector3d center = Vector3d(0.), double radius = 0, - double maximumTrajectory = std::numeric_limits::max()); + ObserverSmallSphere(Vector3d center = Vector3d(0.), double radius = 0); DetectionState checkDetection(Candidate *candidate) const; }; @@ -92,6 +90,33 @@ class ObserverPoint: public ObserverFeature { DetectionState checkDetection(Candidate *candidate) const; }; +/** + @class ObserverNucleusVeto + @brief Veto for nuclei (including protons and neutrons) + */ +class ObserverNucleusVeto: public ObserverFeature { +public: + DetectionState checkDetection(Candidate *candidate) const; +}; + +/** + @class ObserverNeutrinoVeto + @brief Veto for neutrinos + */ +class ObserverNeutrinoVeto: public ObserverFeature { +public: + DetectionState checkDetection(Candidate *candidate) const; +}; + +/** + @class ObserverPhotonVeto + @brief Veto for photons + */ +class ObserverPhotonVeto: public ObserverFeature { +public: + DetectionState checkDetection(Candidate *candidate) const; +}; + /** @class ObserverOutput3D @brief Plain text output of 3D properties @@ -121,6 +146,7 @@ class ObserverOutput1D: public ObserverFeature { }; //////////////////////////////////////////////////////////////////////////////// +// old observer scheme class SmallObserverSphere: public Module { private: diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp index 9d73701fb..747accbc6 100644 --- a/src/module/Observer.cpp +++ b/src/module/Observer.cpp @@ -39,30 +39,20 @@ void Observer::process(Candidate *candidate) const { } } -ObserverSmallSphere::ObserverSmallSphere(Vector3d center, double radius, - double maximumTrajectory) : - center(center), radius(radius), maximumTrajectory(maximumTrajectory) { +ObserverSmallSphere::ObserverSmallSphere(Vector3d center, double radius) : + center(center), radius(radius) { } DetectionState ObserverSmallSphere::checkDetection(Candidate *candidate) const { // current distance to observer sphere center double d = (candidate->current.getPosition() - center).getR(); - double remainingToBorder = d - radius; - // conservatively limit next step to prevent overshooting - candidate->limitNextStep(fabs(remainingToBorder)); + candidate->limitNextStep(fabs(d - radius)); // no detection if outside of observer sphere - if (d > radius) { - // disable candidate if it cannot reach this observer - double remainingToMaximum = maximumTrajectory - - candidate->getTrajectoryLength(); - if (remainingToBorder > remainingToMaximum) - candidate->setActive(false); - + if (d > radius) return NOTHING; - } // previous distance to observer sphere center double dprev = (candidate->previous.getPosition() - center).getR(); @@ -124,6 +114,25 @@ DetectionState ObserverRedshiftWindow::checkDetection( return NOTHING; } +DetectionState ObserverNucleusVeto::checkDetection(Candidate *c) const { + if (isNucleus(c->current.getId())) + return NOTHING; + return VETO; +} + +DetectionState ObserverNeutrinoVeto::checkDetection(Candidate *c) const { + int id = fabs(c->current.getId()); + if ((id == 12) or (id == 14) or (id == 16)) + return NOTHING; + return VETO; +} + +DetectionState ObserverPhotonVeto::checkDetection(Candidate *c) const { + if (c->current.getId() == 22) + return NOTHING; + return VETO; +} + ObserverOutput3D::ObserverOutput3D(std::string fname, bool legacy) : legacy(legacy) { fout.open(fname.c_str()); From 7263bd7a96e55a9524cc16622562d52642f021c1 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 28 Aug 2014 12:18:03 +0200 Subject: [PATCH 0482/1298] getDescription for ModuleList --- include/crpropa/ModuleList.h | 3 +-- src/ModuleList.cpp | 32 ++++++++++++-------------------- src/XmlExecute.cpp | 2 +- 3 files changed, 14 insertions(+), 23 deletions(-) diff --git a/include/crpropa/ModuleList.h b/include/crpropa/ModuleList.h index 3a2532fa2..31a7c7653 100644 --- a/include/crpropa/ModuleList.h +++ b/include/crpropa/ModuleList.h @@ -32,6 +32,7 @@ class ModuleList: public Referenced { module_list_t &getModules(); const module_list_t &getModules() const; + std::string getDescription() const; void showModules() const; private: @@ -41,6 +42,4 @@ class ModuleList: public Referenced { } // namespace crpropa -std::ostream &operator<<(std::ostream &out, const crpropa::ModuleList &list); - #endif // CRPROPA_MODULE_LIST_H diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 3d1112480..2db8a37a2 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -130,27 +130,19 @@ const ModuleList::module_list_t &ModuleList::getModules() const { return modules; } -void ModuleList::showModules() const { - crpropa::ModuleList::module_list_t::const_iterator iEntry; - - iEntry = getModules().begin(); - while (iEntry != getModules().end()) { - const crpropa::ref_ptr &entry = *iEntry; - iEntry++; - std::cout << " " << entry->getDescription() << "\n"; +std::string ModuleList::getDescription() const { + std::stringstream ss; + ss << "ModuleList\n"; + crpropa::ModuleList::module_list_t::const_iterator it; + for (it = modules.begin(); it != modules.end(); ++it) { + const crpropa::ref_ptr &m = *it; + ss << " " << m->getDescription() << "\n"; } + return ss.str(); } -} // namespace crpropa - -std::ostream &operator<<(std::ostream &out, const crpropa::ModuleList &list) { - crpropa::ModuleList::module_list_t::const_iterator iEntry; - - iEntry = list.getModules().begin(); - while (iEntry != list.getModules().end()) { - const crpropa::ref_ptr &entry = *iEntry; - iEntry++; - out << " " << entry->getDescription() << "\n"; - } - return out; +void ModuleList::showModules() const { + std::cout << getDescription(); } + +} // namespace crpropa diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 5700ad4fa..989417999 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -750,7 +750,7 @@ void XmlExecute::loadOutput(xml_node &node) { void XmlExecute::run() { cout << endl << "Active modules:" << endl; - modules.showModules(); + cout << modules.getDescription(); modules.setShowProgress(true); modules.run(&source, nTrajectories, true); } From 478e455c2b34320ab75d52e6ab93c5e1069935c3 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 28 Aug 2014 12:18:34 +0200 Subject: [PATCH 0483/1298] improve python pretty print --- python/crpropa.i | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/python/crpropa.i b/python/crpropa.i index f4ac0e474..a41d7fa8e 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -175,15 +175,24 @@ using std::ptrdiff_t; %template(ModuleListRefPtr) crpropa::ref_ptr; %include "crpropa/ModuleList.h" + +// nice Python print %pythoncode %{ -# nice python print Module.__str__ = Module.getDescription +Module.__repr__ = Module.getDescription + +ModuleList.__str__ = ModuleList.getDescription +ModuleList.__repr__ = ModuleList.getDescription def Vector3__str__(self): - return "(%.4e, %.4e, %.4e)" % (self.x, self.y, self.z) + return "(%.3g, %.3g, %.3g)" % (self.x, self.y, self.z) Vector3d.__str__ = Vector3__str__ Vector3f.__str__ = Vector3__str__ -# expose PropagationCK under its former name Deflection -DeflectionCK = PropagationCK +def Vector3__repr__(self): + return "Vector3 (%.3g, %.3g, %.3g)" % (self.x, self.y, self.z) +Vector3d.__repr__ = Vector3__repr__ +Vector3f.__repr__ = Vector3__repr__ + +DeflectionCK = PropagationCK # legacy name %} From e4a59b353fd44d147e7b4853e326f86c46266f0e Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 28 Aug 2014 14:09:11 +0200 Subject: [PATCH 0484/1298] Observer deactivates by default (as user would expect for 1D simulations) --- include/crpropa/module/Observer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/crpropa/module/Observer.h b/include/crpropa/module/Observer.h index 323122555..3334e4a93 100644 --- a/include/crpropa/module/Observer.h +++ b/include/crpropa/module/Observer.h @@ -36,7 +36,7 @@ class Observer: public Module { std::vector > features; bool makeInactive; public: - Observer(bool makeInactive = false); + Observer(bool makeInactive = true); void add(ObserverFeature *property); void process(Candidate *candidate) const; }; From 7714a63fd09a5e2897073ed5e51409b6a8435d90 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 28 Aug 2014 14:10:34 +0200 Subject: [PATCH 0485/1298] SourcePosition: simple constructor for 1D --- include/crpropa/Source.h | 1 + src/Source.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/include/crpropa/Source.h b/include/crpropa/Source.h index dc49e65d3..5004dfac1 100644 --- a/include/crpropa/Source.h +++ b/include/crpropa/Source.h @@ -148,6 +148,7 @@ class SourcePosition: public SourceFeature { Vector3d position; /**< Source position */ public: SourcePosition(Vector3d position); + SourcePosition(double d); void prepareParticle(ParticleState &state) const; }; diff --git a/src/Source.cpp b/src/Source.cpp index dc160a7b1..68b96ad85 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -214,6 +214,10 @@ SourcePosition::SourcePosition(Vector3d position) : position(position) { } +SourcePosition::SourcePosition(double d) : + position(Vector3d(d, 0, 0)) { +} + void SourcePosition::prepareParticle(ParticleState& particle) const { particle.setPosition(position); } From b5f580378932ed5b29ecc9b0e83e82c9ad8014f7 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 28 Aug 2014 15:14:22 +0200 Subject: [PATCH 0486/1298] getDescription and new constructors for Candidate and ParticleState --- include/crpropa/Candidate.h | 8 +++++++- include/crpropa/ParticleState.h | 13 +++++++------ src/Candidate.cpp | 19 ++++++++++++++++--- src/ParticleState.cpp | 28 ++++++++++++++++++++-------- 4 files changed, 50 insertions(+), 18 deletions(-) diff --git a/include/crpropa/Candidate.h b/include/crpropa/Candidate.h index 8c3a1b658..fc2899ffb 100644 --- a/include/crpropa/Candidate.h +++ b/include/crpropa/Candidate.h @@ -38,7 +38,11 @@ class Candidate: public Referenced { double nextStep; /**< Proposed size of the next propagation step in [m] comoving units */ public: - Candidate(); + Candidate(int id = 0, double energy = 0, + Vector3d position = Vector3d(0, 0, 0), + Vector3d direction = Vector3d(-1, 0, 0), + double z = 0); + /** Creates a candidate, initializing the Candidate::source, Candidate::created, Candidate::previous and Candidate::current state with the argument. @@ -93,6 +97,8 @@ class Candidate: public Referenced { */ void addSecondary(int id, double energy); void clearSecondaries(); + + std::string getDescription() const; }; } // namespace crpropa diff --git a/include/crpropa/ParticleState.h b/include/crpropa/ParticleState.h index 4f7b5c511..1973a1efd 100644 --- a/include/crpropa/ParticleState.h +++ b/include/crpropa/ParticleState.h @@ -2,10 +2,8 @@ #define CRPROPA_PARTICLE_STATE_H #include "crpropa/Vector3.h" -#include "crpropa/Units.h" -#include "crpropa/Common.h" -#include "crpropa/ParticleID.h" -#include "crpropa/ParticleMass.h" + +#include namespace crpropa { @@ -29,8 +27,9 @@ class ParticleState { double charge; ///< particle charge public: - /// Constructor: Create a particle at (0,0,0) pointing at (-1,0,0) - ParticleState(); + ParticleState(int id = 0, double energy = 0, + Vector3d position = Vector3d(0, 0, 0), + Vector3d direction = Vector3d(-1, 0, 0)); /// Set position in comoving coordinates void setPosition(const Vector3d &pos); @@ -52,6 +51,8 @@ class ParticleState { /// Get particle ID int getId() const; + std::string getDescription() const; + // ======== Helper methods ======== /// Electrical charge of the particle in [A] diff --git a/src/Candidate.cpp b/src/Candidate.cpp index 90bbd7f71..38d635b92 100644 --- a/src/Candidate.cpp +++ b/src/Candidate.cpp @@ -2,9 +2,14 @@ namespace crpropa { -Candidate::Candidate() : - redshift(0), trajectoryLength(0), currentStep(0), nextStep(0), active( - true) { +Candidate::Candidate(int id, double E, Vector3d pos, Vector3d dir, double z) : + trajectoryLength(0), currentStep(0), nextStep(0), active(true) { + ParticleState state(id, E, pos, dir); + source = state; + created = state; + previous = state; + current = state; + setRedshift(z); } Candidate::Candidate(const ParticleState &state) : @@ -102,4 +107,12 @@ void Candidate::clearSecondaries() { secondaries.clear(); } +std::string Candidate::getDescription() const { + std::stringstream ss; + ss << "CosmicRay\n"; + ss << " source: " << source.getDescription() << "\n"; + ss << " current: " << current.getDescription(); + return ss.str(); +} + } // namespace crpropa diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index 0f7e1f78e..e373018d3 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -1,15 +1,18 @@ #include "crpropa/ParticleState.h" +#include "crpropa/Units.h" +#include "crpropa/Common.h" +#include "crpropa/ParticleID.h" +#include "crpropa/ParticleMass.h" #include -#include -#include - namespace crpropa { -ParticleState::ParticleState() : - id(0), charge(0), pmass(0), energy(0), position(0, 0, 0), direction(-1, - 0, 0) { +ParticleState::ParticleState(int id, double E, Vector3d pos, Vector3d dir) { + setId(id); + setEnergy(E); + setPosition(pos); + setDirection(dir); } void ParticleState::setPosition(const Vector3d &pos) { @@ -38,9 +41,9 @@ double ParticleState::getEnergy() const { void ParticleState::setId(int newId) { id = newId; - if (HepPID::isNucleus(id)) { + if (isNucleus(id)) { pmass = nucleusMass(id); - charge = HepPID::Z(id) * eplus; // HepPID::charge doesn't work for nuclei + charge = chargeNumber(id) * eplus; // HepPID::charge doesn't work for nuclei if (id < 0) charge *= -1; // HepPID::Z returns positive charge numbers for anti-nuclei } else { @@ -78,4 +81,13 @@ Vector3d ParticleState::getMomentum() const { return direction * (energy / c_light); } +std::string ParticleState::getDescription() const { + std::stringstream ss; + ss << "Particle " << id << ", "; + ss << "E = " << energy / EeV << " EeV, "; + ss << "x = " << position / Mpc << " Mpc, "; + ss << "p = " << direction; + return ss.str(); +} + } // namespace crpropa From 918a6a931aff636e2a7d9483c5c748024c534828 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 28 Aug 2014 15:15:59 +0200 Subject: [PATCH 0487/1298] crpropa.i use __repr__ ( = __str__) --- python/crpropa.i | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/python/crpropa.i b/python/crpropa.i index a41d7fa8e..0b164c578 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -176,16 +176,16 @@ using std::ptrdiff_t; %include "crpropa/ModuleList.h" -// nice Python print +// pretty print %pythoncode %{ -Module.__str__ = Module.getDescription +#Module.__str__ = Module.getDescription Module.__repr__ = Module.getDescription -ModuleList.__str__ = ModuleList.getDescription +#ModuleList.__str__ = ModuleList.getDescription ModuleList.__repr__ = ModuleList.getDescription def Vector3__str__(self): - return "(%.3g, %.3g, %.3g)" % (self.x, self.y, self.z) + return "(%.3g, %.3g, %.3g)" % (self.x, self.y, self.z) Vector3d.__str__ = Vector3__str__ Vector3f.__str__ = Vector3__str__ @@ -194,5 +194,9 @@ def Vector3__repr__(self): Vector3d.__repr__ = Vector3__repr__ Vector3f.__repr__ = Vector3__repr__ +ParticleState.__repr__ = ParticleState.getDescription +Candidate.__repr__ = Candidate.getDescription + + DeflectionCK = PropagationCK # legacy name %} From 414447ac5d83cbc267f828c58f42823daec0a406 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 28 Aug 2014 15:17:23 +0200 Subject: [PATCH 0488/1298] explicitly include Units.h, ParticleID.h ... --- include/crpropa/ModuleList.h | 2 +- include/crpropa/module/PropagationCK.h | 1 + include/crpropa/module/SimplePropagation.h | 1 + src/Source.cpp | 4 ++-- src/XmlExecute.cpp | 1 + src/module/Boundary.cpp | 1 + src/module/BreakCondition.cpp | 1 + src/module/ElectronPairProduction.cpp | 2 ++ src/module/NuclearDecay.cpp | 1 + src/module/Observer.cpp | 2 ++ src/module/OutputCRPropa2.cpp | 2 ++ src/module/OutputROOT.cpp | 2 ++ src/module/OutputShell.cpp | 1 + src/module/OutputTXT.cpp | 1 + src/module/PhotoDisintegration.cpp | 2 ++ src/module/PhotoPionProduction.cpp | 1 + src/module/PhotonDINT.cpp | 1 + src/module/PhotonDINT1D.cpp | 1 + src/module/PhotonEleCa.cpp | 1 + src/module/PhotonOutput1D.cpp | 1 + src/module/Redshift.cpp | 1 + test/testCore.cpp | 4 ++++ test/testInteraction.cpp | 1 + test/testModuleList.cpp | 3 ++- test/testPropagation.cpp | 1 + test/testSource.cpp | 2 ++ 26 files changed, 37 insertions(+), 4 deletions(-) diff --git a/include/crpropa/ModuleList.h b/include/crpropa/ModuleList.h index 31a7c7653..21b82a910 100644 --- a/include/crpropa/ModuleList.h +++ b/include/crpropa/ModuleList.h @@ -6,7 +6,7 @@ #include "crpropa/Source.h" #include -#include +#include namespace crpropa { diff --git a/include/crpropa/module/PropagationCK.h b/include/crpropa/module/PropagationCK.h index 30d2215b5..3c7819ffb 100644 --- a/include/crpropa/module/PropagationCK.h +++ b/include/crpropa/module/PropagationCK.h @@ -2,6 +2,7 @@ #define CRPROPA_PROPAGATIONCK_H #include "crpropa/Module.h" +#include "crpropa/Units.h" #include "crpropa/magneticField/MagneticField.h" namespace crpropa { diff --git a/include/crpropa/module/SimplePropagation.h b/include/crpropa/module/SimplePropagation.h index a81003d4d..27b21dd47 100644 --- a/include/crpropa/module/SimplePropagation.h +++ b/include/crpropa/module/SimplePropagation.h @@ -2,6 +2,7 @@ #define SIMPLEPROPAGATION_H #include "crpropa/Module.h" +#include "crpropa/Units.h" namespace crpropa { diff --git a/src/Source.cpp b/src/Source.cpp index 68b96ad85..3f8d3a918 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -1,8 +1,8 @@ #include "crpropa/Source.h" #include "crpropa/Random.h" #include "crpropa/Cosmology.h" - -#include "HepPID/ParticleIDMethods.hh" +#include "crpropa/Common.h" +#include "crpropa/ParticleID.h" #ifdef CRPROPA_HAVE_MUPARSER #include "muParser.h" diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp index 989417999..1850dc10e 100644 --- a/src/XmlExecute.cpp +++ b/src/XmlExecute.cpp @@ -4,6 +4,7 @@ #include "crpropa/Random.h" #include "crpropa/PhotonBackground.h" #include "crpropa/Cosmology.h" +#include "crpropa/ParticleID.h" #include "crpropa/module/SimplePropagation.h" #include "crpropa/module/PropagationCK.h" #include "crpropa/module/Redshift.h" diff --git a/src/module/Boundary.cpp b/src/module/Boundary.cpp index ba65c7512..fe0f9540b 100644 --- a/src/module/Boundary.cpp +++ b/src/module/Boundary.cpp @@ -1,4 +1,5 @@ #include "crpropa/module/Boundary.h" +#include "crpropa/Units.h" #include diff --git a/src/module/BreakCondition.cpp b/src/module/BreakCondition.cpp index 299b48af8..ad98b4c67 100644 --- a/src/module/BreakCondition.cpp +++ b/src/module/BreakCondition.cpp @@ -1,4 +1,5 @@ #include "crpropa/module/BreakCondition.h" +#include "crpropa/Units.h" #include diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 3370c8c77..dc0885664 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -1,5 +1,7 @@ #include "crpropa/module/ElectronPairProduction.h" +#include "crpropa/Units.h" #include "crpropa/ParticleID.h" +#include "crpropa/ParticleMass.h" #include "crpropa/Random.h" #include diff --git a/src/module/NuclearDecay.cpp b/src/module/NuclearDecay.cpp index dcba0d568..64eb5690e 100644 --- a/src/module/NuclearDecay.cpp +++ b/src/module/NuclearDecay.cpp @@ -1,4 +1,5 @@ #include "crpropa/module/NuclearDecay.h" +#include "crpropa/Units.h" #include "crpropa/ParticleID.h" #include "crpropa/Random.h" diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp index 747accbc6..4a2ce741c 100644 --- a/src/module/Observer.cpp +++ b/src/module/Observer.cpp @@ -1,4 +1,6 @@ #include "crpropa/module/Observer.h" +#include "crpropa/Units.h" +#include "crpropa/ParticleID.h" #include "crpropa/Cosmology.h" namespace crpropa { diff --git a/src/module/OutputCRPropa2.cpp b/src/module/OutputCRPropa2.cpp index 36f808424..9cfba64af 100644 --- a/src/module/OutputCRPropa2.cpp +++ b/src/module/OutputCRPropa2.cpp @@ -1,4 +1,6 @@ #include "crpropa/module/OutputCRPropa2.h" +#include "crpropa/Units.h" +#include "crpropa/ParticleID.h" #include "crpropa/Cosmology.h" namespace crpropa { diff --git a/src/module/OutputROOT.cpp b/src/module/OutputROOT.cpp index aa988f48c..491d94321 100644 --- a/src/module/OutputROOT.cpp +++ b/src/module/OutputROOT.cpp @@ -1,4 +1,6 @@ #include "crpropa/module/OutputROOT.h" +#include "crpropa/Units.h" +#include "crpropa/ParticleID.h" #include "crpropa/Cosmology.h" #ifdef CRPROPA_HAVE_ROOT diff --git a/src/module/OutputShell.cpp b/src/module/OutputShell.cpp index 4affc36c3..af11fdbff 100644 --- a/src/module/OutputShell.cpp +++ b/src/module/OutputShell.cpp @@ -1,4 +1,5 @@ #include "crpropa/module/OutputShell.h" +#include "crpropa/Units.h" #include diff --git a/src/module/OutputTXT.cpp b/src/module/OutputTXT.cpp index 4f12ff996..991a04165 100644 --- a/src/module/OutputTXT.cpp +++ b/src/module/OutputTXT.cpp @@ -1,4 +1,5 @@ #include "crpropa/module/OutputTXT.h" +#include "crpropa/Units.h" #include diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 5ce2d42c8..ca4303eee 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -1,5 +1,7 @@ #include "crpropa/module/PhotoDisintegration.h" +#include "crpropa/Units.h" #include "crpropa/ParticleID.h" +#include "crpropa/ParticleMass.h" #include "crpropa/Random.h" #include diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 5c17b3c92..bc26228d7 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -1,4 +1,5 @@ #include "crpropa/module/PhotoPionProduction.h" +#include "crpropa/Units.h" #include "crpropa/ParticleID.h" #include "crpropa/Random.h" diff --git a/src/module/PhotonDINT.cpp b/src/module/PhotonDINT.cpp index be9160412..992851fca 100644 --- a/src/module/PhotonDINT.cpp +++ b/src/module/PhotonDINT.cpp @@ -1,4 +1,5 @@ #include "crpropa/module/PhotonDINT.h" +#include "crpropa/Units.h" #include "crpropa/Cosmology.h" #include diff --git a/src/module/PhotonDINT1D.cpp b/src/module/PhotonDINT1D.cpp index 24c9a238c..371098131 100644 --- a/src/module/PhotonDINT1D.cpp +++ b/src/module/PhotonDINT1D.cpp @@ -1,4 +1,5 @@ #include "crpropa/module/PhotonDINT1D.h" +#include "crpropa/Units.h" #include "crpropa/Cosmology.h" #include diff --git a/src/module/PhotonEleCa.cpp b/src/module/PhotonEleCa.cpp index b3c10659f..e698c7b01 100644 --- a/src/module/PhotonEleCa.cpp +++ b/src/module/PhotonEleCa.cpp @@ -1,4 +1,5 @@ #include "crpropa/module/PhotonEleCa.h" +#include "crpropa/Units.h" #include "EleCa/Propagation.h" #include "EleCa/Particle.h" diff --git a/src/module/PhotonOutput1D.cpp b/src/module/PhotonOutput1D.cpp index 0a0c5bf7b..fdf6a83e7 100644 --- a/src/module/PhotonOutput1D.cpp +++ b/src/module/PhotonOutput1D.cpp @@ -1,4 +1,5 @@ #include "crpropa/module/PhotonOutput1D.h" +#include "crpropa/Units.h" #include #include diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index 55e17efdf..1b9b20108 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -1,4 +1,5 @@ #include "crpropa/module/Redshift.h" +#include "crpropa/Units.h" #include "crpropa/Cosmology.h" #include diff --git a/test/testCore.cpp b/test/testCore.cpp index 4329c1df8..8756c37db 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -6,6 +6,10 @@ */ #include "crpropa/Candidate.h" +#include "crpropa/Common.h" +#include "crpropa/Units.h" +#include "crpropa/ParticleID.h" +#include "crpropa/ParticleMass.h" #include "crpropa/Random.h" #include "crpropa/Grid.h" #include "crpropa/GridTools.h" diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 090df4af2..098d309f9 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -1,4 +1,5 @@ #include "crpropa/Candidate.h" +#include "crpropa/Units.h" #include "crpropa/ParticleID.h" #include "crpropa/module/ElectronPairProduction.h" #include "crpropa/module/NuclearDecay.h" diff --git a/test/testModuleList.cpp b/test/testModuleList.cpp index 65ea38b6c..8bc61256e 100644 --- a/test/testModuleList.cpp +++ b/test/testModuleList.cpp @@ -1,7 +1,8 @@ #include "crpropa/ModuleList.h" +#include "crpropa/Source.h" +#include "crpropa/ParticleID.h" #include "crpropa/module/SimplePropagation.h" #include "crpropa/module/BreakCondition.h" -#include "crpropa/Source.h" #include "gtest/gtest.h" diff --git a/test/testPropagation.cpp b/test/testPropagation.cpp index 52af43d94..c119b97f5 100644 --- a/test/testPropagation.cpp +++ b/test/testPropagation.cpp @@ -1,4 +1,5 @@ #include "crpropa/Candidate.h" +#include "crpropa/ParticleID.h" #include "crpropa/module/SimplePropagation.h" #include "crpropa/module/PropagationCK.h" diff --git a/test/testSource.cpp b/test/testSource.cpp index d93062221..75e9810ce 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -1,4 +1,6 @@ #include "crpropa/Source.h" +#include "crpropa/Units.h" +#include "crpropa/ParticleID.h" #include "gtest/gtest.h" #include From 3f49916e7b1b2ccd250d0283721088b1d1e3c169 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 28 Aug 2014 15:29:36 +0200 Subject: [PATCH 0489/1298] allow massNumber for neutron = 2112 --- python/crpropa.i | 11 +---------- src/ParticleID.cpp | 2 ++ src/ParticleState.cpp | 4 ++-- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/python/crpropa.i b/python/crpropa.i index 0b164c578..2c3a2129e 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -178,25 +178,16 @@ using std::ptrdiff_t; // pretty print %pythoncode %{ -#Module.__str__ = Module.getDescription Module.__repr__ = Module.getDescription - -#ModuleList.__str__ = ModuleList.getDescription ModuleList.__repr__ = ModuleList.getDescription -def Vector3__str__(self): - return "(%.3g, %.3g, %.3g)" % (self.x, self.y, self.z) -Vector3d.__str__ = Vector3__str__ -Vector3f.__str__ = Vector3__str__ - def Vector3__repr__(self): - return "Vector3 (%.3g, %.3g, %.3g)" % (self.x, self.y, self.z) + return "Vector(%.3g, %.3g, %.3g)" % (self.x, self.y, self.z) Vector3d.__repr__ = Vector3__repr__ Vector3f.__repr__ = Vector3__repr__ ParticleState.__repr__ = ParticleState.getDescription Candidate.__repr__ = Candidate.getDescription - DeflectionCK = PropagationCK # legacy name %} diff --git a/src/ParticleID.cpp b/src/ParticleID.cpp index ad62ce68d..db132b291 100644 --- a/src/ParticleID.cpp +++ b/src/ParticleID.cpp @@ -26,6 +26,8 @@ int chargeNumber(int id) { } int massNumber(int id) { + if (id == 2112) + return 1; return HepPID::A(id); } diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index e373018d3..bf37cfebb 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -43,9 +43,9 @@ void ParticleState::setId(int newId) { id = newId; if (isNucleus(id)) { pmass = nucleusMass(id); - charge = chargeNumber(id) * eplus; // HepPID::charge doesn't work for nuclei + charge = chargeNumber(id) * eplus; if (id < 0) - charge *= -1; // HepPID::Z returns positive charge numbers for anti-nuclei + charge *= -1; } else { // pmass missing for non-nuclei charge = HepPID::charge(id) * eplus; From a00ab981f5f4466c0c52f74dc3736331184f4630 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 28 Aug 2014 16:20:16 +0200 Subject: [PATCH 0490/1298] descriptions for all ObserverFeatures --- include/crpropa/module/Observer.h | 13 ++++++- src/ParticleState.cpp | 2 +- src/module/Observer.cpp | 58 +++++++++++++++++++++++++++++-- 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/include/crpropa/module/Observer.h b/include/crpropa/module/Observer.h index 3334e4a93..1202a07ac 100644 --- a/include/crpropa/module/Observer.h +++ b/include/crpropa/module/Observer.h @@ -22,9 +22,12 @@ enum DetectionState { @brief Abstract base class for features of cosmic ray observers */ class ObserverFeature: public Referenced { +protected: + std::string description; public: virtual DetectionState checkDetection(Candidate *candidate) const; virtual void onDetection(Candidate *candidate) const; + virtual std::string getDescription() const; }; /** @@ -39,6 +42,7 @@ class Observer: public Module { Observer(bool makeInactive = true); void add(ObserverFeature *property); void process(Candidate *candidate) const; + std::string getDescription() const; }; /** @@ -52,6 +56,7 @@ class ObserverSmallSphere: public ObserverFeature { public: ObserverSmallSphere(Vector3d center = Vector3d(0.), double radius = 0); DetectionState checkDetection(Candidate *candidate) const; + std::string getDescription() const; }; /** @@ -65,6 +70,7 @@ class ObserverLargeSphere: public ObserverFeature { public: ObserverLargeSphere(Vector3d center = Vector3d(0.), double radius = 0); DetectionState checkDetection(Candidate *candidate) const; + std::string getDescription() const; }; /** @@ -77,6 +83,7 @@ class ObserverRedshiftWindow: public ObserverFeature { public: ObserverRedshiftWindow(double zmin = 0, double zmax = 0.1); DetectionState checkDetection(Candidate *candidate) const; + std::string getDescription() const; }; /** @@ -88,6 +95,7 @@ class ObserverRedshiftWindow: public ObserverFeature { class ObserverPoint: public ObserverFeature { public: DetectionState checkDetection(Candidate *candidate) const; + std::string getDescription() const; }; /** @@ -97,6 +105,7 @@ class ObserverPoint: public ObserverFeature { class ObserverNucleusVeto: public ObserverFeature { public: DetectionState checkDetection(Candidate *candidate) const; + std::string getDescription() const; }; /** @@ -106,6 +115,7 @@ class ObserverNucleusVeto: public ObserverFeature { class ObserverNeutrinoVeto: public ObserverFeature { public: DetectionState checkDetection(Candidate *candidate) const; + std::string getDescription() const; }; /** @@ -115,6 +125,7 @@ class ObserverNeutrinoVeto: public ObserverFeature { class ObserverPhotonVeto: public ObserverFeature { public: DetectionState checkDetection(Candidate *candidate) const; + std::string getDescription() const; }; /** @@ -200,7 +211,7 @@ class LargeObserverSphere: public Module { }; /** - @class Observer1D + @class OneDimObserver @brief Observer for 1D simulations Particles are detected once their x-position gets smaller than a 0. diff --git a/src/ParticleState.cpp b/src/ParticleState.cpp index bf37cfebb..ffc16fbc1 100644 --- a/src/ParticleState.cpp +++ b/src/ParticleState.cpp @@ -45,7 +45,7 @@ void ParticleState::setId(int newId) { pmass = nucleusMass(id); charge = chargeNumber(id) * eplus; if (id < 0) - charge *= -1; + charge *= -1; // anti-nucleus } else { // pmass missing for non-nuclei charge = HepPID::charge(id) * eplus; diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp index 4a2ce741c..1b3a32e2d 100644 --- a/src/module/Observer.cpp +++ b/src/module/Observer.cpp @@ -12,6 +12,10 @@ DetectionState ObserverFeature::checkDetection(Candidate *candidate) const { void ObserverFeature::onDetection(Candidate *candidate) const { } +std::string ObserverFeature::getDescription() const { + return description; +} + Observer::Observer(bool makeInactive) : makeInactive(makeInactive) { } @@ -41,6 +45,14 @@ void Observer::process(Candidate *candidate) const { } } +std::string Observer::getDescription() const { + std::stringstream ss; + ss << "Observer\n"; + for (int i = 0; i < features.size(); i++) + ss << " " << features[i]->getDescription() << "\n"; + return ss.str(); +} + ObserverSmallSphere::ObserverSmallSphere(Vector3d center, double radius) : center(center), radius(radius) { } @@ -67,6 +79,14 @@ DetectionState ObserverSmallSphere::checkDetection(Candidate *candidate) const { return DETECTED; } +std::string ObserverSmallSphere::getDescription() const { + std::stringstream ss; + ss << "ObserverSmallSphere: "; + ss << "center = " << center / Mpc << " Mpc, "; + ss << "radius = " << radius / Mpc << " Mpc"; + return ss.str(); +} + ObserverLargeSphere::ObserverLargeSphere(Vector3d center, double radius) : center(center), radius(radius) { } @@ -93,6 +113,15 @@ DetectionState ObserverLargeSphere::checkDetection(Candidate *candidate) const { return DETECTED; } +std::string ObserverLargeSphere::getDescription() const { + std::stringstream ss; + ss << "ObserverLargeSphere: "; + ss << "center = " << center / Mpc << " Mpc, "; + ss << "radius = " << radius / Mpc << " Mpc"; + return ss.str(); +} + + DetectionState ObserverPoint::checkDetection(Candidate *candidate) const { double x = candidate->current.getPosition().x; if (x > 0) { @@ -102,6 +131,11 @@ DetectionState ObserverPoint::checkDetection(Candidate *candidate) const { return DETECTED; } +std::string ObserverPoint::getDescription() const { + return "ObserverPoint: observer at x = 0"; +} + + ObserverRedshiftWindow::ObserverRedshiftWindow(double zmin, double zmax) : zmin(zmin), zmax(zmax) { } @@ -116,12 +150,22 @@ DetectionState ObserverRedshiftWindow::checkDetection( return NOTHING; } +std::string ObserverRedshiftWindow::getDescription() const { + std::stringstream ss; + ss << "ObserverRedshiftWindow: z = " << zmin << " - " << zmax; + return ss.str(); +} + DetectionState ObserverNucleusVeto::checkDetection(Candidate *c) const { if (isNucleus(c->current.getId())) return NOTHING; return VETO; } +std::string ObserverNucleusVeto::getDescription() const { + return "ObserverNucleusVeto"; +} + DetectionState ObserverNeutrinoVeto::checkDetection(Candidate *c) const { int id = fabs(c->current.getId()); if ((id == 12) or (id == 14) or (id == 16)) @@ -129,14 +173,23 @@ DetectionState ObserverNeutrinoVeto::checkDetection(Candidate *c) const { return VETO; } +std::string ObserverNeutrinoVeto::getDescription() const { + return "ObserverNeutrinoVeto"; +} + DetectionState ObserverPhotonVeto::checkDetection(Candidate *c) const { if (c->current.getId() == 22) return NOTHING; return VETO; } +std::string ObserverPhotonVeto::getDescription() const { + return "ObserverPhotonVeto"; +} + ObserverOutput3D::ObserverOutput3D(std::string fname, bool legacy) : legacy(legacy) { + description = "ObserverOutput3D: " + fname; fout.open(fname.c_str()); if (legacy) { @@ -218,9 +271,10 @@ void ObserverOutput3D::onDetection(Candidate *candidate) const { } } -ObserverOutput1D::ObserverOutput1D(std::string filename, bool legacy) : +ObserverOutput1D::ObserverOutput1D(std::string fname, bool legacy) : legacy(legacy) { - fout.open(filename.c_str()); + description = "ObserverOutput1D: " + fname; + fout.open(fname.c_str()); if (legacy) { fout << "#CRPropa - Output data file\n"; From dbb5bdf19048b6a442920d57b9ca9eeb588849d1 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 28 Aug 2014 18:33:49 +0200 Subject: [PATCH 0491/1298] descriptions and pretty print for all SourceFeatures --- include/crpropa/Source.h | 86 ++++++--- python/crpropa.i | 39 +++- src/Source.cpp | 394 +++++++++++++++++++++++++++++---------- 3 files changed, 391 insertions(+), 128 deletions(-) diff --git a/include/crpropa/Source.h b/include/crpropa/Source.h index 5004dfac1..0e7090f9d 100644 --- a/include/crpropa/Source.h +++ b/include/crpropa/Source.h @@ -13,17 +13,20 @@ namespace crpropa { @brief Abstract base class cosmic ray source features */ class SourceFeature: public Referenced { +protected: + std::string description; public: virtual void prepareParticle(ParticleState& particle) const; virtual void prepareCandidate(Candidate& candidate) const; + std::string getDescription() const; }; /** @class Source @brief General cosmic ray source - This class is a container for source properties. - The source prepares a new candidate by passing it to all its source properties + This class is a container for source features. + The source prepares a new candidate by passing it to all its source features to be modified accordingly. */ class Source: public Referenced { @@ -31,6 +34,7 @@ class Source: public Referenced { public: void add(SourceFeature* feature); ref_ptr getCandidate() const; + std::string getDescription() const; }; /** @@ -53,10 +57,11 @@ class SourceList: public Source { @brief Particle type at the source */ class SourceParticleType: public SourceFeature { - double id; + int id; public: SourceParticleType(int id); void prepareParticle(ParticleState &particle) const; + void setDescription(); }; /** @@ -67,8 +72,10 @@ class SourceMultipleParticleTypes: public SourceFeature { std::vector particleTypes; std::vector cdf; public: + SourceMultipleParticleTypes(); void add(int id, double weight = 1); void prepareParticle(ParticleState &particle) const; + void setDescription(); }; /** @@ -80,6 +87,7 @@ class SourceEnergy: public SourceFeature { public: SourceEnergy(double energy); void prepareParticle(ParticleState &particle) const; + void setDescription(); }; /** @@ -93,6 +101,7 @@ class SourcePowerLawSpectrum: public SourceFeature { public: SourcePowerLawSpectrum(double Emin, double Emax, double index); void prepareParticle(ParticleState &particle) const; + void setDescription(); }; /** @@ -112,34 +121,9 @@ class SourceComposition: public SourceFeature { void add(int id, double abundance); void add(int A, int Z, double abundance); void prepareParticle(ParticleState &particle) const; + void setDescription(); }; -#ifdef CRPROPA_HAVE_MUPARSER -/** - @class SourceGenericComposition - @brief Multiple nuclei with energies described by an expression string - */ -class SourceGenericComposition: public SourceFeature { - struct Nucleus { - int id; - std::vector cdf; - }; - - double Emin, Emax; - size_t steps; - std::string expression; - std::vector energy; - - std::vector nuclei; - std::vector cdf; -public: - SourceGenericComposition(double Emin, double Emax, std::string expression, size_t steps = 1024); - void add(int id, double abundance); - void add(int A, int Z, double abundance); - void prepareParticle(ParticleState &particle) const; -}; -#endif - /** @class SourcePosition @brief Position of a point source @@ -150,6 +134,7 @@ class SourcePosition: public SourceFeature { SourcePosition(Vector3d position); SourcePosition(double d); void prepareParticle(ParticleState &state) const; + void setDescription(); }; /** @@ -160,8 +145,10 @@ class SourceMultiplePositions: public SourceFeature { std::vector positions; std::vector cdf; public: + SourceMultiplePositions(); void add(Vector3d position, double weight = 1); void prepareParticle(ParticleState &particle) const; + void setDescription(); }; /** @@ -174,6 +161,7 @@ class SourceUniformSphere: public SourceFeature { public: SourceUniformSphere(Vector3d center, double radius); void prepareParticle(ParticleState &particle) const; + void setDescription(); }; /** @@ -186,6 +174,7 @@ class SourceUniformShell: public SourceFeature { public: SourceUniformShell(Vector3d center, double radius); void prepareParticle(ParticleState &particle) const; + void setDescription(); }; /** @@ -202,6 +191,7 @@ class SourceUniformBox: public SourceFeature { */ SourceUniformBox(Vector3d origin, Vector3d size); void prepareParticle(ParticleState &particle) const; + void setDescription(); }; /** @@ -225,6 +215,7 @@ class SourceUniform1D: public SourceFeature { */ SourceUniform1D(double minD, double maxD, bool withCosmology=true); void prepareParticle(ParticleState& particle) const; + void setDescription(); }; /** @@ -236,6 +227,7 @@ class SourceDensityGrid: public SourceFeature { public: SourceDensityGrid(ref_ptr densityGrid); void prepareParticle(ParticleState &particle) const; + void setDescription(); }; /** @@ -247,6 +239,7 @@ class SourceDensityGrid1D: public SourceFeature { public: SourceDensityGrid1D(ref_ptr densityGrid); void prepareParticle(ParticleState &particle) const; + void setDescription(); }; /** @@ -255,7 +248,9 @@ class SourceDensityGrid1D: public SourceFeature { */ class SourceIsotropicEmission: public SourceFeature { public: + SourceIsotropicEmission(); void prepareParticle(ParticleState &particle) const; + void setDescription(); }; /** @@ -267,6 +262,7 @@ class SourceDirection: public SourceFeature { public: SourceDirection(Vector3d direction = Vector3d(-1, 0, 0)); void prepareParticle(ParticleState &particle) const; + void setDescription(); }; /** @@ -279,6 +275,7 @@ class SourceEmissionCone: public SourceFeature { public: SourceEmissionCone(Vector3d direction, double aperture); void prepareParticle(ParticleState &particle) const; + void setDescription(); }; /** @@ -290,6 +287,7 @@ class SourceRedshift: public SourceFeature { public: SourceRedshift(double z); void prepareCandidate(Candidate &candidate) const; + void setDescription(); }; /** @@ -301,6 +299,7 @@ class SourceUniformRedshift: public SourceFeature { public: SourceUniformRedshift(double zmin, double zmax); void prepareCandidate(Candidate &candidate) const; + void setDescription(); }; /** @@ -312,9 +311,38 @@ class SourceUniformRedshift: public SourceFeature { */ class SourceRedshift1D: public SourceFeature { public: + SourceRedshift1D(); void prepareCandidate(Candidate &candidate) const; + void setDescription(); }; +#ifdef CRPROPA_HAVE_MUPARSER +/** + @class SourceGenericComposition + @brief Multiple nuclei with energies described by an expression string + */ +class SourceGenericComposition: public SourceFeature { + struct Nucleus { + int id; + std::vector cdf; + }; + + double Emin, Emax; + size_t steps; + std::string expression; + std::vector energy; + + std::vector nuclei; + std::vector cdf; +public: + SourceGenericComposition(double Emin, double Emax, std::string expression, size_t steps = 1024); + void add(int id, double abundance); + void add(int A, int Z, double abundance); + void prepareParticle(ParticleState &particle) const; + void setDescription(); +}; +#endif + }// namespace crpropa #endif // CRPROPA_SOURCE_H diff --git a/python/crpropa.i b/python/crpropa.i index 2c3a2129e..4ca609fc3 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -178,16 +178,49 @@ using std::ptrdiff_t; // pretty print %pythoncode %{ +ParticleState.__repr__ = ParticleState.getDescription +Candidate.__repr__ = Candidate.getDescription + Module.__repr__ = Module.getDescription ModuleList.__repr__ = ModuleList.getDescription +Source.__repr__ = Source.getDescription +SourceList.__repr__ = SourceList.getDescription +SourceParticleType.__repr__ = SourceParticleType.getDescription +SourceMultipleParticleTypes.__repr__ = SourceMultipleParticleTypes.getDescription +SourceEnergy.__repr__ = SourceEnergy.getDescription +SourcePowerLawSpectrum.__repr__ = SourcePowerLawSpectrum.getDescription +SourceMultiplePositions.__repr__ = SourceMultiplePositions.getDescription +SourceComposition.__repr__ = SourceComposition.getDescription +SourcePosition.__repr__ = SourcePosition.getDescription +SourceUniform1D.__repr__ = SourceUniform1D.getDescription +SourceUniformBox.__repr__ = SourceUniformBox.getDescription +SourceUniformShell.__repr__ = SourceUniformShell.getDescription +SourceUniformSphere.__repr__ = SourceUniformSphere.getDescription +SourceDensityGrid.__repr__ = SourceDensityGrid.getDescription +SourceDensityGrid1D.__repr__ = SourceDensityGrid1D.getDescription +SourceDirection.__repr__ = SourceDirection.getDescription +SourceIsotropicEmission.__repr__ = SourceIsotropicEmission.getDescription +SourceEmissionCone.__repr__ = SourceEmissionCone.getDescription +SourceRedshift.__repr__ = SourceRedshift.getDescription +SourceRedshift1D.__repr__ = SourceRedshift1D.getDescription +SourceUniformRedshift.__repr__ = SourceUniformRedshift.getDescription + +Observer.__repr__ = Observer.getDescription +ObserverPoint.__repr__ = ObserverPoint.getDescription +ObserverSmallSphere.__repr__ = ObserverSmallSphere.getDescription +ObserverLargeSphere.__repr__ = ObserverLargeSphere.getDescription +ObserverRedshiftWindow.__repr__ = ObserverRedshiftWindow.getDescription +ObserverNucleusVeto.__repr__ = ObserverNucleusVeto.getDescription +ObserverNeutrinoVeto.__repr__ = ObserverNeutrinoVeto.getDescription +ObserverPhotonVeto.__repr__ = ObserverPhotonVeto.getDescription +ObserverOutput1D.__repr__ = ObserverOutput1D.getDescription +ObserverOutput3D.__repr__ = ObserverOutput3D.getDescription + def Vector3__repr__(self): return "Vector(%.3g, %.3g, %.3g)" % (self.x, self.y, self.z) Vector3d.__repr__ = Vector3__repr__ Vector3f.__repr__ = Vector3__repr__ -ParticleState.__repr__ = ParticleState.getDescription -Candidate.__repr__ = Candidate.getDescription - DeflectionCK = PropagationCK # legacy name %} diff --git a/src/Source.cpp b/src/Source.cpp index 3f8d3a918..0c4e5adf5 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -2,27 +2,19 @@ #include "crpropa/Random.h" #include "crpropa/Cosmology.h" #include "crpropa/Common.h" +#include "crpropa/Units.h" #include "crpropa/ParticleID.h" #ifdef CRPROPA_HAVE_MUPARSER #include "muParser.h" #endif +#include #include namespace crpropa { -void SourceFeature::prepareParticle(ParticleState& particle) const { -} - -void SourceFeature::prepareCandidate(Candidate& candidate) const { - ParticleState &source = candidate.source; - prepareParticle(source); - candidate.created = source; - candidate.current = source; - candidate.previous = source; -} - +// Source --------------------------------------------------------------------- void Source::add(SourceFeature* property) { features.push_back(property); } @@ -34,6 +26,15 @@ ref_ptr Source::getCandidate() const { return candidate; } +std::string Source::getDescription() const { + std::stringstream ss; + ss << "Cosmic ray source\n"; + for (int i = 0; i < features.size(); i++) + ss << " " << features[i]->getDescription() << "\n"; + return ss.str(); +} + +// SourceList------------------------------------------------------------------ void SourceList::add(Source* source, double weight) { sources.push_back(source); if (cdf.size() > 0) @@ -48,104 +49,87 @@ ref_ptr SourceList::getCandidate() const { return (sources[i])->getCandidate(); } -SourceParticleType::SourceParticleType(int id) : - id(id) { +// SourceFeature--------------------------------------------------------------- +void SourceFeature::prepareParticle(ParticleState& particle) const { } -void SourceParticleType::prepareParticle(ParticleState& particle) const { - particle.setId(id); +void SourceFeature::prepareCandidate(Candidate& candidate) const { + ParticleState &source = candidate.source; + prepareParticle(source); + candidate.created = source; + candidate.current = source; + candidate.previous = source; } -SourceEnergy::SourceEnergy(double energy) : - E(energy) { +std::string SourceFeature::getDescription() const { + return description; } -void SourceEnergy::prepareParticle(ParticleState& p) const { - p.setEnergy(E); +// ---------------------------------------------------------------------------- +SourceParticleType::SourceParticleType(int id) : + id(id) { + setDescription(); } -#ifdef CRPROPA_HAVE_MUPARSER -SourceGenericComposition::SourceGenericComposition(double Emin, double Emax, std::string expression, size_t steps) : - Emin(Emin), Emax(Emax), expression(expression), steps(steps) { - - // precalculate energy bins - double logEmin = ::log10(Emin); - double logEmax = ::log10(Emax); - double logStep = (logEmax - logEmin) / (steps-1); - energy.resize(steps); - for (size_t i = 0; i < steps; i++) { - energy[i] = ::pow(10, logEmin + i * logStep); - } +void SourceParticleType::prepareParticle(ParticleState& particle) const { + particle.setId(id); } -void SourceGenericComposition::add(int id, double weight) { - int A = massNumber(id); - int Z = chargeNumber(id); - - Nucleus n; - n.id = id; - - // calculate nuclei cdf - mu::Parser p; - double E; - p.DefineVar("E", &E); - p.DefineConst("Emin", Emin); - p.DefineConst("Emax", Emax); - p.DefineConst("steps", steps); - p.DefineConst("A", (double)A); - p.DefineConst("Z", (double)Z); - p.SetExpr(expression); - - // calculate pdf - n.cdf.resize(steps); - for (std::size_t i=0; i 0) - weight += cdf.back(); - cdf.push_back(weight); + a += cdf.back(); + cdf.push_back(a); + setDescription(); } -void SourceGenericComposition::add(int A, int Z, double a) { - add(nucleusId(A, Z), a); +void SourceMultipleParticleTypes::prepareParticle(ParticleState& particle) const { + if (particleTypes.size() == 0) + throw std::runtime_error("SourceMultipleParticleTypes: no nuclei set"); + size_t i = Random::instance().randBin(cdf); + particle.setId(particleTypes[i]); } -void SourceGenericComposition::prepareParticle(ParticleState& particle) const { - if (nuclei.size() == 0) - throw std::runtime_error("SourceComposition: No source isotope set"); - - Random &random = Random::instance(); +void SourceMultipleParticleTypes::setDescription() { + std::stringstream ss; + ss << "SourceMultipleParticleTypes: Random particle type:\n"; + for (int i = 0; i < particleTypes.size(); i++) + ss << " " << particleTypes[i] << "\n"; + description = ss.str(); +} +// ---------------------------------------------------------------------------- +SourceEnergy::SourceEnergy(double energy) : + E(energy) { + setDescription(); +} - // draw random particle type - size_t iN = random.randBin(cdf); - const Nucleus &n = nuclei[iN]; - particle.setId(n.id); +void SourceEnergy::prepareParticle(ParticleState& p) const { + p.setEnergy(E); +} - // random energy - double E = interpolate(random.rand() * n.cdf.back(), n.cdf, energy); - particle.setEnergy(E); +void SourceEnergy::setDescription() { + std::stringstream ss; + ss << "SourceEnergy: " << E / EeV << " EeV"; + description = ss.str(); } -#endif +// ---------------------------------------------------------------------------- SourcePowerLawSpectrum::SourcePowerLawSpectrum(double Emin, double Emax, double index) : Emin(Emin), Emax(Emax), index(index) { + setDescription(); } void SourcePowerLawSpectrum::prepareParticle(ParticleState& particle) const { @@ -154,22 +138,18 @@ void SourcePowerLawSpectrum::prepareParticle(ParticleState& particle) const { particle.setEnergy(E); } -void SourceMultipleParticleTypes::add(int id, double a) { - particleTypes.push_back(id); - if (cdf.size() > 0) - a += cdf.back(); - cdf.push_back(a); -} - -void SourceMultipleParticleTypes::prepareParticle(ParticleState& particle) const { - if (particleTypes.size() == 0) - throw std::runtime_error("SourceMultipleParticleTypes: no nuclei set"); - size_t i = Random::instance().randBin(cdf); - particle.setId(particleTypes[i]); +void SourcePowerLawSpectrum::setDescription() { + std::stringstream ss; + ss << "SourcePowerLawSpectrum: Random energy "; + ss << "E = " << Emin / EeV << " - " << Emax / EeV << " EeV, "; + ss << "dN/dE ~ E^" << index; + description = ss.str(); } +// ---------------------------------------------------------------------------- SourceComposition::SourceComposition(double Emin, double Rmax, double index) : Emin(Emin), Rmax(Rmax), index(index) { + setDescription(); } void SourceComposition::add(int id, double weight) { @@ -188,6 +168,7 @@ void SourceComposition::add(int id, double weight) { if (cdf.size() > 0) weight += cdf.back(); cdf.push_back(weight); + setDescription(); } void SourceComposition::add(int A, int Z, double a) { @@ -210,18 +191,42 @@ void SourceComposition::prepareParticle(ParticleState& particle) const { particle.setEnergy(random.randPowerLaw(index, Emin, Z * Rmax)); } +void SourceComposition::setDescription() { + std::stringstream ss; + ss << "SourceComposition: Random element and energy "; + ss << "E = " << Emin / EeV << " - Z*" << Rmax / EeV << " EeV, "; + ss << "dN/dE ~ E^" << index << "\n"; + for (int i = 0; i < nuclei.size(); i++) + ss << " ID = " << nuclei[i] << "\n"; + description = ss.str(); +} + +// ---------------------------------------------------------------------------- SourcePosition::SourcePosition(Vector3d position) : position(position) { + setDescription(); } SourcePosition::SourcePosition(double d) : position(Vector3d(d, 0, 0)) { + setDescription(); } void SourcePosition::prepareParticle(ParticleState& particle) const { particle.setPosition(position); } +void SourcePosition::setDescription() { + std::stringstream ss; + ss << "SourcePosition: " << position / Mpc << " Mpc"; + description = ss.str(); +} + +// ---------------------------------------------------------------------------- +SourceMultiplePositions::SourceMultiplePositions() { + setDescription(); +} + void SourceMultiplePositions::add(Vector3d pos, double weight) { positions.push_back(pos); if (cdf.size() > 0) @@ -236,8 +241,18 @@ void SourceMultiplePositions::prepareParticle(ParticleState& particle) const { particle.setPosition(positions[i]); } +void SourceMultiplePositions::setDescription() { + std::stringstream ss; + ss << "SourceMultiplePositions: Random position from list\n"; + for (int i = 0; i < positions.size(); i++) + ss << " " << positions[i] / Mpc << " Mpc\n"; + description = ss.str(); +} + +// ---------------------------------------------------------------------------- SourceUniformSphere::SourceUniformSphere(Vector3d center, double radius) : center(center), radius(radius) { + setDescription(); } void SourceUniformSphere::prepareParticle(ParticleState& particle) const { @@ -246,8 +261,18 @@ void SourceUniformSphere::prepareParticle(ParticleState& particle) const { particle.setPosition(random.randVector() * r); } +void SourceUniformSphere::setDescription() { + std::stringstream ss; + ss << "SourceUniformSphere: Random position within a sphere at "; + ss << center / Mpc << " Mpc with"; + ss << radius / Mpc << " Mpc radius"; + description = ss.str(); +} + +// ---------------------------------------------------------------------------- SourceUniformShell::SourceUniformShell(Vector3d center, double radius) : center(center), radius(radius) { + setDescription(); } void SourceUniformShell::prepareParticle(ParticleState& particle) const { @@ -255,8 +280,18 @@ void SourceUniformShell::prepareParticle(ParticleState& particle) const { particle.setPosition(random.randVector() * radius); } +void SourceUniformShell::setDescription() { + std::stringstream ss; + ss << "SourceUniformShell: Random position on a spherical shell at "; + ss << center / Mpc << " Mpc with "; + ss << radius / Mpc << " Mpc radius"; + description = ss.str(); +} + +// ---------------------------------------------------------------------------- SourceUniformBox::SourceUniformBox(Vector3d origin, Vector3d size) : origin(origin), size(size) { + setDescription(); } void SourceUniformBox::prepareParticle(ParticleState& particle) const { @@ -265,6 +300,15 @@ void SourceUniformBox::prepareParticle(ParticleState& particle) const { particle.setPosition(pos * size + origin); } +void SourceUniformBox::setDescription() { + std::stringstream ss; + ss << "SourceUniformBox: Random uniform position in box with "; + ss << "origin = " << origin / Mpc << " Mpc and "; + ss << "size = " << size / Mpc << " Mpc"; + description = ss.str(); +} + +// ---------------------------------------------------------------------------- SourceUniform1D::SourceUniform1D(double minD, double maxD, bool withCosmology) { this->withCosmology = withCosmology; if (withCosmology) { @@ -274,6 +318,7 @@ SourceUniform1D::SourceUniform1D(double minD, double maxD, bool withCosmology) { this->minD = minD; this->maxD = maxD; } + setDescription(); } void SourceUniform1D::prepareParticle(ParticleState& particle) const { @@ -284,6 +329,15 @@ void SourceUniform1D::prepareParticle(ParticleState& particle) const { particle.setPosition(Vector3d(d, 0, 0)); } +void SourceUniform1D::setDescription() { + std::stringstream ss; + ss << "SourceUniform1D: Random uniform position in D = " << minD << " - " << maxD; + if (withCosmology) + ss << " (including cosmology)"; + description = ss.str(); +} + +// ---------------------------------------------------------------------------- SourceDensityGrid::SourceDensityGrid(ref_ptr grid) : grid(grid) { float sum = 0; @@ -295,6 +349,7 @@ SourceDensityGrid::SourceDensityGrid(ref_ptr grid) : } } } + setDescription(); } void SourceDensityGrid::prepareParticle(ParticleState& particle) const { @@ -313,6 +368,11 @@ void SourceDensityGrid::prepareParticle(ParticleState& particle) const { particle.setPosition(pos); } +void SourceDensityGrid::setDescription() { + description = "SourceDensityGrid: 3D source distribution according to density grid"; +} + +// ---------------------------------------------------------------------------- SourceDensityGrid1D::SourceDensityGrid1D(ref_ptr grid) : grid(grid) { if (grid->getNy() != 1) @@ -325,6 +385,7 @@ SourceDensityGrid1D::SourceDensityGrid1D(ref_ptr grid) : sum += grid->get(ix, 0, 0); grid->get(ix, 0, 0) = sum; } + setDescription(); } void SourceDensityGrid1D::prepareParticle(ParticleState& particle) const { @@ -341,21 +402,44 @@ void SourceDensityGrid1D::prepareParticle(ParticleState& particle) const { particle.setPosition(pos); } +void SourceDensityGrid1D::setDescription() { + description = "SourceDensityGrid1D: 1D source distribution according to density grid"; +} + +// ---------------------------------------------------------------------------- +SourceIsotropicEmission::SourceIsotropicEmission() { + setDescription(); +} + void SourceIsotropicEmission::prepareParticle(ParticleState& particle) const { Random &random = Random::instance(); particle.setDirection(random.randVector()); } +void SourceIsotropicEmission::setDescription() { + description = "SourceIsotropicEmission: Random isotropic direction"; +} + +// ---------------------------------------------------------------------------- SourceDirection::SourceDirection(Vector3d direction) : direction(direction) { + setDescription(); } void SourceDirection::prepareParticle(ParticleState& particle) const { particle.setDirection(direction); } +void SourceDirection::setDescription() { + std::stringstream ss; + ss << "SourceDirection: Emission direction = " << direction; + description = ss.str(); +} + +// ---------------------------------------------------------------------------- SourceEmissionCone::SourceEmissionCone(Vector3d direction, double aperture) : direction(direction), aperture(aperture) { + setDescription(); } void SourceEmissionCone::prepareParticle(ParticleState& particle) const { @@ -363,16 +447,34 @@ void SourceEmissionCone::prepareParticle(ParticleState& particle) const { particle.setDirection(random.randConeVector(direction, aperture)); } +void SourceEmissionCone::setDescription() { + std::stringstream ss; + ss << "SourceEmissionCone: Jetted emission in "; + ss << "direction = " << direction << " with "; + ss << "half-opening angle = " << aperture << " rad"; + description = ss.str(); +} + +// ---------------------------------------------------------------------------- SourceRedshift::SourceRedshift(double z) : z(z) { + setDescription(); } void SourceRedshift::prepareCandidate(Candidate& candidate) const { candidate.setRedshift(z); } +void SourceRedshift::setDescription() { + std::stringstream ss; + ss << "SourceRedshift: Redshift z = " << z; + description = ss.str(); +} + +// ---------------------------------------------------------------------------- SourceUniformRedshift::SourceUniformRedshift(double zmin, double zmax) : zmin(zmin), zmax(zmax) { + setDescription(); } void SourceUniformRedshift::prepareCandidate(Candidate& candidate) const { @@ -380,10 +482,110 @@ void SourceUniformRedshift::prepareCandidate(Candidate& candidate) const { candidate.setRedshift(z); } +void SourceUniformRedshift::setDescription() { + std::stringstream ss; + ss << "SourceUniformRedshift: Uniform redshift in z = " << zmin << " - " << zmax; + description = ss.str(); +} + +// ---------------------------------------------------------------------------- +SourceRedshift1D::SourceRedshift1D() { + setDescription(); +} + void SourceRedshift1D::prepareCandidate(Candidate& candidate) const { double d = candidate.source.getPosition().getR(); double z = comovingDistance2Redshift(d); candidate.setRedshift(z); } +void SourceRedshift1D::setDescription() { + description = "SourceRedshift1D: Redshift according to source distance"; +} + +// ---------------------------------------------------------------------------- +#ifdef CRPROPA_HAVE_MUPARSER +SourceGenericComposition::SourceGenericComposition(double Emin, double Emax, std::string expression, size_t steps) : + Emin(Emin), Emax(Emax), expression(expression), steps(steps) { + + // precalculate energy bins + double logEmin = ::log10(Emin); + double logEmax = ::log10(Emax); + double logStep = (logEmax - logEmin) / (steps-1); + energy.resize(steps); + for (size_t i = 0; i < steps; i++) { + energy[i] = ::pow(10, logEmin + i * logStep); + } + setDescription(); +} + +void SourceGenericComposition::add(int id, double weight) { + int A = massNumber(id); + int Z = chargeNumber(id); + + Nucleus n; + n.id = id; + + // calculate nuclei cdf + mu::Parser p; + double E; + p.DefineVar("E", &E); + p.DefineConst("Emin", Emin); + p.DefineConst("Emax", Emax); + p.DefineConst("steps", steps); + p.DefineConst("A", (double)A); + p.DefineConst("Z", (double)Z); + p.SetExpr(expression); + + // calculate pdf + n.cdf.resize(steps); + for (std::size_t i=0; i 0) + weight += cdf.back(); + cdf.push_back(weight); +} + +void SourceGenericComposition::add(int A, int Z, double a) { + add(nucleusId(A, Z), a); +} + +void SourceGenericComposition::prepareParticle(ParticleState& particle) const { + if (nuclei.size() == 0) + throw std::runtime_error("SourceComposition: No source isotope set"); + + Random &random = Random::instance(); + + + // draw random particle type + size_t iN = random.randBin(cdf); + const Nucleus &n = nuclei[iN]; + particle.setId(n.id); + + // random energy + double E = interpolate(random.rand() * n.cdf.back(), n.cdf, energy); + particle.setEnergy(E); +} + +void SourceGenericComposition::setDescription() { + description = "Generice source composition" + expression; +} +#endif + } // namespace crpropa From 48899176e8d04116c70331bcb1d7f456c6e8763c Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 29 Aug 2014 14:28:37 +0200 Subject: [PATCH 0492/1298] README refers to wiki --- README.md | 122 +++--------------------------------------------------- 1 file changed, 5 insertions(+), 117 deletions(-) diff --git a/README.md b/README.md index 4fd8e92c2..6dbd14b27 100644 --- a/README.md +++ b/README.md @@ -1,123 +1,11 @@ CRPropa3 ======== -This is the development version of [CRPropa](https://crpropa.desy.de/Main_Page). -It features a very flexible setup of simulation, support for specialized extragalactic magnetic fields, galactic lensing, python - steering and parallelization. +CRPropa is a publicly available code to study the propagation of ultra high energy nuclei up to iron on their voyage through an extra galactic environment. It takes into account: pion production, photodisintegration and energy losses by pair production of all relevant isotopes in the ambient low energy photon fields as well as nuclear decay. CRPropa can model the deflection in intergalactic magnetic fields, the propagation of secondary electromagnetic cascades and neutrinos for a multitude of scenarios for different source distributions and magnetic environments. It enables the user to predict the spectra of UHECR (and of their secondaries), their composition and arrival direction distribution. -## Install from source -1. Download the source - ``` - git clone https://github.com/CRPropa/CRPropa3.git - ``` -2. Download the data repository - ``` - git clone https://github.com/CRPropa/CRPropa3-data.git CRPropa3/data - ``` -3. CRPropa uses CMAKE to configure. From the build directory call ccmake or cmake. See the next section for a list of configuration flags - ``` - cd build - ccmake .. - ``` -4. After the configuration run make and make install as usual - ``` - make - make install - ``` +This is the development version of [CRPropa](https://crpropa.desy.de). +It features a very flexible setup of simulation, support for specialized extragalactic magnetic fields, galactic lensing, python steering and shared-memory parallelization. -#### CMake flags -We recommend using ccmake to view and set the options through the user interface. -When using cmake, options can be set by adding flags to the cmake command, e.g. ```cmake -DENABLE_PYTHON=ON ..``` +For installation instructions and documentation please refer to [wiki page](https://github.com/CRPropa/CRPropa3/wiki) -+ Set the install path -```-DCMAKE_INSTALL_PREFIX=/my/install/path``` -+ Enable OpenMP -```-DENABLE_OPENMP=ON``` -+ Enable Python -```-DENABLE_PYTHON=ON``` -+ Enable ROOT -```-DENABLE_ROOT=ON``` -+ Enable FFTW3 -```-DENABLE_FFTW3F=ON``` -+ Enable testing with googletest -```-DENABLE_TESTING=ON``` -+ Additional flags for Intel compiler -``` --DCMAKE_SHARED_LINKER_FLAGS="-lifcore" --DCMAKE_Fortran_COMPILER=ifort -``` - -#### Required dependencies -+ C++ Compiler -+ Fortran Compiler: to compile SOPHIA - -#### Provided dependencies -+ SOPHIA: photo-hadronic interactions -+ EleCa and dint: electromagnetic cascades -+ googletest: unit-testing -+ HepPID: particle ID library -+ kiss: small tool collection -+ pugixml: for xml steering - -#### Optional dependencies -+ Python and SWIG: to use CRPropa from python (tested for > Python 2.7 and > SWIG 2.0) -+ ROOT: for ROOT output -+ FFTW3: for turbulent magnetic field grids (FFTW3 with single precision is needed) -+ Gadget: magnetic fields for large scale structure data -+ OpenMP: for shared memory parallelization -+ googleperftools: for performance optimizations regarding shared memory parallelization -+ muparser: to define the source spectrum through a mathematical formula - - -## Getting started -We recommend using CRPropa via python. The documentation can be found on the [CRPropa wiki](https://crpropa.desy.de/CRPropa3]). -For a 1D simulation try - - ```python - from crpropa import * - - # simulation setup - m = ModuleList() - m.add(SimplePropagation(0, 10 * Mpc)) - m.add(PhotoPionProduction(CMB)) - m.add(PhotoPionProduction(IRB)) - m.add(PhotoDisintegration(CMB)) - m.add(PhotoDisintegration(IRB)) - m.add(ElectronPairProduction(CMB)) - m.add(ElectronPairProduction(IRB)) - m.add(NuclearDecay()) - m.add(MinimumEnergy(1 * EeV)) - m.add(Observer1D()) - m.add(EventOutput1D('events.txt')) - - # source setup - source = Source() - source.addProperty(SourceParticleType(nucleusId(56, 26))) - source.addProperty(SourcePowerLawSpectrum(1 * EeV, 500 * EeV, -2)) - source.addProperty(SourceUniform1D(3 * Mpc, 2000 * Mpc)) - - # run simulation - m.setShowProgress(True) - m.run(source, 1000, True) - ``` - -## CRPropa 2 compatibility -For backwards compatibility CRPropa 3 can be steered via XML cards ($cropra-xmlrun some_steeringcard.xml) -However, CRPropa 2 does not fully enforce the XML-1.0 standard (http://www.w3.org/XML). -To comply with the standard a few modifications to exisisting steering cards might have to be made. -Modification are - -1. XML-cards can have only one root node. The root node is - - - ... - - -2. All nodes including the optional header node need to be closed, e.g. - - - ... or - - -3. Values need to be embraced by quotes, e.g. - - +In case of questions please use the [ticket system](https://github.com/CRPropa/CRPropa3/issues) From e953d5872277dd7d9d2c62b0bd869bc7cc22aef4 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 3 Sep 2014 21:37:21 +0200 Subject: [PATCH 0493/1298] update README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6dbd14b27..eaf60688a 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ CRPropa3 CRPropa is a publicly available code to study the propagation of ultra high energy nuclei up to iron on their voyage through an extra galactic environment. It takes into account: pion production, photodisintegration and energy losses by pair production of all relevant isotopes in the ambient low energy photon fields as well as nuclear decay. CRPropa can model the deflection in intergalactic magnetic fields, the propagation of secondary electromagnetic cascades and neutrinos for a multitude of scenarios for different source distributions and magnetic environments. It enables the user to predict the spectra of UHECR (and of their secondaries), their composition and arrival direction distribution. This is the development version of [CRPropa](https://crpropa.desy.de). -It features a very flexible setup of simulation, support for specialized extragalactic magnetic fields, galactic lensing, python steering and shared-memory parallelization. +It features a very flexible simulation setup, support for specialized extragalactic magnetic fields, galactic propagation and galactic lensing, python steering and shared-memory parallelization. -For installation instructions and documentation please refer to [wiki page](https://github.com/CRPropa/CRPropa3/wiki) +For installation instructions and documentation please refer to the [wiki page](https://github.com/CRPropa/CRPropa3/wiki). -In case of questions please use the [ticket system](https://github.com/CRPropa/CRPropa3/issues) +In case of questions please use the [ticket system](https://github.com/CRPropa/CRPropa3/issues). From 86e4df55a1e35185335fd7df0afc7dfa73184e8a Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Mon, 15 Sep 2014 22:19:17 +0200 Subject: [PATCH 0494/1298] - clarify download tip in CMakeLists - add symbol for pc = parsec - improve default settings for the turbulent field in JF12 --- CMakeLists.txt | 2 +- include/crpropa/Units.h | 1 + src/magneticField/JF12Field.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b49131f6d..a368bf8fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,7 +135,7 @@ else() execute_process(COMMAND wget ${DATA_URL} -O ${CMAKE_SOURCE_DIR}/data.tar.gz --no-check-certificate RESULT_VARIABLE status) endif(CMAKE_VERSION GREATER 2.6) message("Download complete: ${status}") -message("If the download failed, please manually obtain the file from " ${DATA_URL} " and extract to ./data before 'make install'") +message("If the download failed, please manually obtain the file from " ${DATA_URL} " and place it in the source folder'") file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/data) execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_SOURCE_DIR}/data.tar.gz WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/data) diff --git a/include/crpropa/Units.h b/include/crpropa/Units.h index 0c256ee04..bfddd3ced 100644 --- a/include/crpropa/Units.h +++ b/include/crpropa/Units.h @@ -62,6 +62,7 @@ static const double parsec = 3.0856775807e16 * meter; static const double kiloparsec = 1e3 * parsec; static const double megaparsec = 1e6 * parsec; static const double gigaparsec = 1e9 * parsec; +static const double pc = parsec; static const double kpc = kiloparsec; static const double Mpc = megaparsec; static const double Gpc = gigaparsec; diff --git a/src/magneticField/JF12Field.cpp b/src/magneticField/JF12Field.cpp index 507593542..1ce33e22d 100644 --- a/src/magneticField/JF12Field.cpp +++ b/src/magneticField/JF12Field.cpp @@ -103,7 +103,7 @@ void JF12Field::randomTurbulent(int seed) { useTurbulent = true; // turbulent field with Kolmogorov spectrum, B_rms = 1 and Lc = 60 parsec turbulentGrid = new VectorGrid(Vector3d(0.), 256, 4 * parsec); - initTurbulence(turbulentGrid, 1, 16 * parsec, 255.5 * parsec, -11./3., seed); + initTurbulence(turbulentGrid, 1, 8 * parsec, 272 * parsec, -11./3., seed); } #endif From fe9d9c24e8a8c19e095c75acd466930adc1d97f9 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 17 Sep 2014 19:30:56 +0200 Subject: [PATCH 0495/1298] - further specify CMakeLists tip - add redshift to Candidate print --- CMakeLists.txt | 2 +- src/Candidate.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a368bf8fe..39616ee2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,7 +135,7 @@ else() execute_process(COMMAND wget ${DATA_URL} -O ${CMAKE_SOURCE_DIR}/data.tar.gz --no-check-certificate RESULT_VARIABLE status) endif(CMAKE_VERSION GREATER 2.6) message("Download complete: ${status}") -message("If the download failed, please manually obtain the file from " ${DATA_URL} " and place it in the source folder'") +message("If the download failed, please manually obtain the file from " ${DATA_URL} ", rename it to data.tar.gz and place it in the source folder'") file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/data) execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_SOURCE_DIR}/data.tar.gz WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/data) diff --git a/src/Candidate.cpp b/src/Candidate.cpp index 38d635b92..cdd93b84c 100644 --- a/src/Candidate.cpp +++ b/src/Candidate.cpp @@ -109,7 +109,7 @@ void Candidate::clearSecondaries() { std::string Candidate::getDescription() const { std::stringstream ss; - ss << "CosmicRay\n"; + ss << "CosmicRay at z = " << getRedshift() << "\n"; ss << " source: " << source.getDescription() << "\n"; ss << " current: " << current.getDescription(); return ss.str(); From a5d99f20aa62552d70c1199686b25ba31fb6f026 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 17 Sep 2014 19:32:18 +0200 Subject: [PATCH 0496/1298] changes to allow for negative redshifts --- include/crpropa/module/Redshift.h | 10 ++++++++++ src/PhotonBackground.cpp | 4 ++-- src/module/Redshift.cpp | 27 ++++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/include/crpropa/module/Redshift.h b/include/crpropa/module/Redshift.h index 96f06d42c..5b0512040 100644 --- a/include/crpropa/module/Redshift.h +++ b/include/crpropa/module/Redshift.h @@ -15,6 +15,16 @@ class Redshift: public Module { std::string getDescription() const; }; +/** + @class FutureRedshift + @brief Updates redshift and applies adiabatic energy loss according to the travelled distance. + */ +class FutureRedshift: public Module { +public: + void process(Candidate *candidate) const; + std::string getDescription() const; +}; + } // namespace crpropa #endif // CRPROPA_REDSHIFT_H diff --git a/src/PhotonBackground.cpp b/src/PhotonBackground.cpp index 4cc8d4ffb..ae898acd5 100644 --- a/src/PhotonBackground.cpp +++ b/src/PhotonBackground.cpp @@ -8,9 +8,9 @@ namespace crpropa { // Overall redshift scaling of the Kneiske et al. 2004 IRB, astro-ph/0309141 // The scaling is calculated in data-tools/PhotonField/Kneiske2004_IRB_scaling.py -double a[9] = { 0, 0.2, 0.4, 0.6, 1, 2, 3, 4, 5 }; +double a[10] = {-1, 0, 0.2, 0.4, 0.6, 1, 2, 3, 4, 5 }; static std::vector zKneiske(a, a + sizeof(a) / sizeof(double)); -double b[9] = { 1., 0.9749867, 0.93999977, 0.88430409, 0.64952017, 0.27170436, +double b[10] = {1.250665, 1., 0.9749867, 0.93999977, 0.88430409, 0.64952017, 0.27170436, 0.130244, 0.05971749, 0. }; static std::vector sKneiske(b, b + sizeof(b) / sizeof(double)); diff --git a/src/module/Redshift.cpp b/src/module/Redshift.cpp index 1b9b20108..3bdf46ba7 100644 --- a/src/module/Redshift.cpp +++ b/src/module/Redshift.cpp @@ -22,7 +22,7 @@ void Redshift::process(Candidate *c) const { // update redshift c->setRedshift(z - dz); - // adiabatic energy loss: dE / dz = E / (1+z) + // adiabatic energy loss: dE / dz = E / (1 + z) double E = c->current.getEnergy(); c->current.setEnergy(E * (1 - dz / (1 + z))); } @@ -34,4 +34,29 @@ std::string Redshift::getDescription() const { return s.str(); } +void FutureRedshift::process(Candidate *c) const { + double z = c->getRedshift(); + + // check if z = 0 + if (z <= -1) + return; + + // use small step approximation: dz = H(z) / c * ds + double dz = hubbleRate(z) / c_light * c->getCurrentStep(); + + // update redshift + c->setRedshift(z - dz); + + // adiabatic energy loss: dE / dz = E / (1 + z) + double E = c->current.getEnergy(); + c->current.setEnergy(E * (1 - dz / (1 + z))); +} + +std::string FutureRedshift::getDescription() const { + std::stringstream s; + s << "FutureRedshift: h0 = " << hubbleRate() / 1e5 * Mpc << ", omegaL = " + << omegaL() << ", omegaM = " << omegaM(); + return s.str(); +} + } // namespace crpropa From 152fd9392f140587b8a12a4b888b42b39fad518b Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 19 Sep 2014 09:33:06 +0200 Subject: [PATCH 0497/1298] Improve performance of PID lookup. --- libs/HepPID/src/ParticleIDMethods.cc | 10 ++++++++-- test/testInteraction.cpp | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/libs/HepPID/src/ParticleIDMethods.cc b/libs/HepPID/src/ParticleIDMethods.cc index cf9297073..af3f33d89 100644 --- a/libs/HepPID/src/ParticleIDMethods.cc +++ b/libs/HepPID/src/ParticleIDMethods.cc @@ -56,8 +56,14 @@ unsigned short digit( location loc, const int & pid ) { // PID digits (base 10) are: n nr nl nq1 nq2 nq3 nj // the location enum provides a convenient index into the PID - int numerator = (int) std::pow(10.0,(loc-1)); - return (abspid(pid)/numerator)%10; + // + // Modified for CRPropa: use precalculated values isntead of pow for + // performance + static unsigned int p10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, + 10000000, 100000000, 1000000000}; + return (abspid(pid)/ p10[loc-1])%10; +// int numerator = (int) std::pow(10.0,(loc-1)); +// return (abspid(pid)/numerator)%10; } // return the first two digits if this is a "fundamental" particle diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 090df4af2..300f72587 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -1,5 +1,6 @@ #include "crpropa/Candidate.h" #include "crpropa/ParticleID.h" +#include #include "crpropa/module/ElectronPairProduction.h" #include "crpropa/module/NuclearDecay.h" #include "crpropa/module/PhotoDisintegration.h" @@ -453,6 +454,21 @@ TEST(Redshift, limitRedshiftDecrease) { EXPECT_DOUBLE_EQ(0, c.getRedshift()); } + +TEST(PIDdigit, consistencyWithReferenceImplementation){ + // Tests the performance improved version against the default one + unsigned long testPID = rand() % 1000000000 + 1000000000; + for(size_t i=1; i < 8; i++) + { + HepPID::location loc = (HepPID::location) i; + unsigned short newResult = HepPID::digit(loc, testPID); + //original implementation + int numerator = (int) std::pow(10.0,(loc-1)); + EXPECT_EQ(newResult, (HepPID::abspid(testPID)/numerator)%10); + } +} + + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); From 3d5d99d7337c68d36eeb6d7c60c6da0b603a8f5e Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 19 Sep 2014 09:51:48 +0200 Subject: [PATCH 0498/1298] Added profile build-type --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b49131f6d..f6f0214dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,9 @@ if(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) message(STATUS "Use --as-needed linker flags!") endif(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) +# Add buildtype for profiling +SET(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS} -ggdb -fno-omit-frame-pointer") + # ---------------------------------------------------------------------------- # Dependencies # ---------------------------------------------------------------------------- From 83b0077ea488ab3af79c6df0574f3d2ffcb25989 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 19 Sep 2014 11:28:04 +0200 Subject: [PATCH 0499/1298] EleCa: Included changes from Mariangela send by Mail. --- libs/EleCa/include/EleCa/EnergyLoss.h | 2 +- libs/EleCa/src/EnergyLoss.cpp | 54 +++++++----- libs/EleCa/src/Particle.cpp | 4 +- libs/EleCa/src/Process.cpp | 35 ++++---- libs/EleCa/src/Propagation.cpp | 122 ++++++++++++++------------ 5 files changed, 118 insertions(+), 99 deletions(-) diff --git a/libs/EleCa/include/EleCa/EnergyLoss.h b/libs/EleCa/include/EleCa/EnergyLoss.h index a647b1374..573c4176b 100644 --- a/libs/EleCa/include/EleCa/EnergyLoss.h +++ b/libs/EleCa/include/EleCa/EnergyLoss.h @@ -16,7 +16,7 @@ double ESynchrotronAdiabaticLoss(double z, double E, double B); void InitRK(); double EnergyLoss1D(double Energy, double z0, double zfin, double B); double dSigmadE_ICS(double Ee, double Eer, double s, double theta); -double dSigmadE_PP(double Ee, double E0, double eps, double theta); +double dSigmadE_PP(double Ee, double E0, double eps, double theta, double s); double ExtractPPSecondariesEnergy(Particle &pi, Particle &pt); double ExtractPPSecondariesEnergy(Process &proc); double ExtractICSSecondariesEnergy(Particle &pi, Particle &pt); diff --git a/libs/EleCa/src/EnergyLoss.cpp b/libs/EleCa/src/EnergyLoss.cpp index 264446b2d..2fcb60d0e 100644 --- a/libs/EleCa/src/EnergyLoss.cpp +++ b/libs/EleCa/src/EnergyLoss.cpp @@ -203,11 +203,11 @@ double dSigmadE_ICS(double Ee, double Eer, double s, double theta) { } } -double dSigmadE_PP(double Ee, double E0, double eps, double theta) { + double dSigmadE_PP(double Ee, double E0, double eps, double theta, double s) { /*! Differential cross-section for pair production. */ - double s = ElectronMass * ElectronMass + 2 * eps * E0 * (1 - cos(theta)); + // double s = ElectronMass * ElectronMass + 2 * eps * E0 * (1 - cos(theta)); double beta = sqrt(1 - 4 * ElectronMass * ElectronMass / s); if (Ee / E0 <= 0.5 * (1 - beta) || Ee / E0 >= 0.5 * (1 + beta)) { @@ -239,8 +239,7 @@ double ExtractPPSecondariesEnergy(Particle &pi, Particle &pt) { double eps = pt.GetEnergy(); double beta = pi.GetBeta(); double theta = cPI; - double s2 = ElectronMass * ElectronMass - + 2 * eps * E0 * (1 - (beta) * cos(theta)); + double s2 = ElectronMass * ElectronMass + 4 * eps * E0;// * (1 - (beta) * cos(theta)); bool failed = 1; @@ -258,7 +257,7 @@ double ExtractPPSecondariesEnergy(Particle &pi, Particle &pt) { for (double Ee = f * 0.5 * (1 - beta) * E0; Ee < 0.5 * (1 + beta) * E0; Ee *= f) { MC_Sampling_Hist[cnt][0] = Ee; - MC_Sampling_Hist[cnt][1] = dSigmadE_PP(Ee, E0, eps, theta); + MC_Sampling_Hist[cnt][1] = dSigmadE_PP(Ee, E0, eps, theta,s2); NormFactor += MC_Sampling_Hist[cnt][1]; MC_Sampling_Hist[cnt][2] = NormFactor; @@ -312,10 +311,11 @@ double ExtractPPSecondariesEnergy(Process &proc) { double s = proc.GetCMEnergy(); double eps = proc.GetTargetParticle().GetEnergy(); double theta = M_PI; + s = ElectronMass * ElectronMass + 2 * eps * E0 * (1 - cos(theta)); + double beta = sqrt(1 - 4 * ElectronMass * ElectronMass / s); - double beta = sqrt(1. - 4.0 * ElectronMass * ElectronMass / s); - double s2 = ElectronMass * ElectronMass - + 2 * eps * E0 * (1 - (beta) * cos(theta)); + // double s2 = ElectronMass * ElectronMass + // + 2 * eps * E0 * (1 - (beta) * cos(theta)); bool failed = 1; @@ -333,7 +333,7 @@ double ExtractPPSecondariesEnergy(Process &proc) { for (double Ee = f * 0.5 * (1 - beta) * E0; Ee < 0.5 * (1 + beta) * E0; Ee *= f) { MC_Sampling_Hist[cnt][0] = Ee; - MC_Sampling_Hist[cnt][1] = dSigmadE_PP(Ee, E0, eps, theta); + MC_Sampling_Hist[cnt][1] = dSigmadE_PP(Ee, E0, eps, theta, s); NormFactor += MC_Sampling_Hist[cnt][1]; MC_Sampling_Hist[cnt][2] = NormFactor; @@ -352,17 +352,39 @@ double ExtractPPSecondariesEnergy(Process &proc) { } NormFactor = (double) 1. / (double) NormFactor; + if (cnt == 0) { + std::cout << " PP cnt = 0 ... returning electron mass " << std::endl; + std::cout << " " << proc.GetCMEnergy() << " new s " << s << " eps " << eps << " E0 " << E0 << std::endl << " beta: " << beta << " beta^2 " << 1 - 4 * ElectronMass * ElectronMass / s << std::endl; + + + //just for testing what's going on -- to be removed after some debug runs + for (double Ee = f * 0.5 * (1 - beta) * E0; Ee < 0.5 * (1 + beta) * E0; + Ee *= f) { + MC_Sampling_Hist[cnt][0] = Ee; + MC_Sampling_Hist[cnt][1] = dSigmadE_PP(Ee, E0, eps, theta,s); + NormFactor += MC_Sampling_Hist[cnt][1]; + MC_Sampling_Hist[cnt][2] = NormFactor; + std::cout << Ee << " " << beta << " f: " << f << " " << MC_Sampling_Hist[cnt][1] << std::endl; + if (MC_Sampling_Hist[cnt][1] > 0.) { + cnt++; + } else { + break; + } + } + return ElectronMass;} + /// throw std::runtime_error("failed in extractPP"); + for (int i = 0; i < cnt; i++) MC_Sampling_Hist[i][2] *= NormFactor; double rnd; - double Ee = ElectronMass; + double Ee = 0; int k = 0; while (failed) { rnd = Uniform(0., 1.0); - Ee = ElectronMass; + Ee = 0; k++; double min = 1e6; double max = -1; @@ -380,16 +402,6 @@ double ExtractPPSecondariesEnergy(Process &proc) { break; } } - if (failed) { - /* std::cout << "failed in extractPP " << Ee << " " << beta << " * s: " - << s << " E0: " << E0 << " eps : " << eps << " me^2/E0: " - << ElectronMass * ElectronMass / E0 << " ) " << " cnt : " - << cnt << std::endl; - std::cout << " Limits " << proc.GetMin() << std::endl; - */ - if (cnt == 0) - throw std::runtime_error("failed in extractPP"); - } } //end while diff --git a/libs/EleCa/src/Particle.cpp b/libs/EleCa/src/Particle.cpp index 5025bb82d..6643d041d 100644 --- a/libs/EleCa/src/Particle.cpp +++ b/libs/EleCa/src/Particle.cpp @@ -11,8 +11,8 @@ bool Particle::IsGood() { double zmax_prop1 = -0.101717; double zmax_prop2 = 0.002855; double Eloc = log10(fE0ph); - if (fE0ph <=0 ) - return 0; + if (fE0ph <=3.0e12) + return 0; //for interaction lengths tab if (Eloc > 12 && Eloc < 18) Eloc = 18; if (fz0ph > zmax_prop0 + zmax_prop1 * Eloc + zmax_prop2 * Eloc * Eloc) diff --git a/libs/EleCa/src/Process.cpp b/libs/EleCa/src/Process.cpp index 701730fa6..6f72ab2bb 100644 --- a/libs/EleCa/src/Process.cpp +++ b/libs/EleCa/src/Process.cpp @@ -194,35 +194,32 @@ void Process::SetLimits(Particle& p1, std::string nameproc) { << std::endl; if (nameproc == "PP") { - if (abs(p1.GetType()) == 11) + if (abs(p1.GetType()) != 22) std::cout << "\nERROR!! wrong particle or process!! " << nameproc << p1.GetType() << "\n" << std::endl; - fsmin = 4 * ElectronMass * ElectronMass; //min per theta = 0; - fsmax = 4 * p1.GetEnergy() * feps_sup * 2.0; //(1.0-cos(fInteractionAngle)); //max per theta=3.14 + fsmin = 2 * ElectronMass * ElectronMass; + fsmax = 4 * p1.GetEnergy() * feps_sup; } if (nameproc == "DPP") { - if (abs(p1.GetType()) == 11) + if (abs(p1.GetType()) != 22) std::cout << "\nERROR!! wrong particle or process!! " << nameproc << p1.GetType() << "\n" << std::endl; - fsmin = 16 * ElectronMass * ElectronMass; - fsmax = 4 * p1.GetEnergy() * feps_sup * 2.0; + fsmin = 4 * ElectronMass*ElectronMass; + fsmax = 4 * p1.GetEnergy() * feps_sup; } if (nameproc == "ICS") { - if (p1.GetType() == 22 || p1.GetType() == 9) - std::cout << "\nERROR!! wrong particle or process!! " << nameproc - << p1.GetType() << "\n" << std::endl; - fsmin = p1.GetMass() * p1.GetMass() - + 2 * p1.GetEnergy() * feps_inf * (1 - p1.GetBeta()); - fsmax = p1.GetMass() * p1.GetMass() - + 2 * p1.GetEnergy() * feps_sup * (1 + p1.GetBeta()); + if (abs(p1.GetType()) != 11) + std::cout << "\nERROR!! wrong particle or process!! " << nameproc + << p1.GetType() << "\n" << std::endl; + fsmin = 4 * 1e12 * feps_inf + ElectronMass*ElectronMass; //given the min E in lambda + fsmax = 4 * p1.GetEnergy() * feps_inf + p1.GetMass() * p1.GetMass(); } if (nameproc == "TPP") { - if (p1.GetType() == 22 || p1.GetType() == 9) - std::cout << "\nERROR!! wrong particle or process!! " << nameproc - << p1.GetType() << "\n" << std::endl; - fsmin = 10 * ElectronMass * ElectronMass; - fsmax = 2 * p1.GetEnergy() * feps_sup * (1 + p1.GetBeta()) - + p1.GetMass() * p1.GetMass(); + if (abs(p1.GetType()) != 11) + std::cout << "\nERROR!! wrong particle or process!! " << nameproc + << p1.GetType() << "\n" << std::endl; + fsmin = std::max(4 * 1e12 * feps_inf + ElectronMass*ElectronMass,3 * ElectronMass * ElectronMass); + fsmax = 4 * p1.GetEnergy() * feps_sup + p1.GetMass() * p1.GetMass(); } } diff --git a/libs/EleCa/src/Propagation.cpp b/libs/EleCa/src/Propagation.cpp index 3d933e714..c869b8ce4 100644 --- a/libs/EleCa/src/Propagation.cpp +++ b/libs/EleCa/src/Propagation.cpp @@ -4,7 +4,6 @@ #include "EleCa/Common.h" #include "EleCa/EnergyLoss.h" #include "EleCa/Constants.h" - #include "XLoss_CBR.h" #include @@ -94,7 +93,7 @@ void Propagation::InitBkgArray(const std::string &BackRad) { } } - else { //if (BackRad == "ALL" ) { + else { double de = pow((double) eps_ph_sup_global / eps_ph_inf_global, (double) 1. / POINTS_VERY_FEW); double e = eps_ph_inf_global; @@ -114,9 +113,6 @@ void Propagation::InitBkgArray(const std::string &BackRad) { double a = 1.0 / BkgA[POINTS_VERY_FEW - 1]; for (size_t i = 0; i < POINTS_VERY_FEW; i++) { BkgA[i] *= a; -#ifdef DEBUG_ELECA - std::cout << BkgE[i] << " - " << BkgA[i] << std::endl; -#endif } } @@ -149,7 +145,7 @@ double Propagation::ExtractMinDist(Process &proc, int type, double R, double R2, pt.Setz(proc.GetIncidentParticle().Getz()); if (type == 22) { - + if (Etarget[0]) { proc1.SetName("PP"); pt.SetEnergy(Etarget[0]); proc1.SetTargetParticle(pt); @@ -158,14 +154,15 @@ double Propagation::ExtractMinDist(Process &proc, int type, double R, double R2, tmp_lambda1 = GetLambdaTab(proc1, "PP"); min_dist1 = -tmp_lambda1 * log(R); - + } + if (Etarget[1]) { proc2.SetName("DPP"); pt.SetEnergy(Etarget[1]); proc2.SetTargetParticle(pt); proc2.SetCMEnergy(); tmp_lambda2 = GetLambdaTab(proc2, "DPP"); min_dist2 = -tmp_lambda2 * log(R2); - + } #ifdef DEBUG_ELECA std::cerr << "comparing 2 mindists: " << min_dist1 << "(" << tmp_lambda1 << ") vs " << min_dist2 << " ( " @@ -275,19 +272,6 @@ double Propagation::GetLambdaTab(const Process &proc, double Propagation::ShootPhotonEnergyMC(double z) const { // Routine for the MC sampling of background photon energy -// double interpolate(double x, const std::vector &X, -// const std::vector &Y) { -// std::vector::const_iterator it = std::upper_bound(X.begin(), -// X.end(), x); -// if (it == X.begin()) -// return Y.front(); -// if (it == X.end()) -// return Y.back(); -// -// size_t i = it - X.begin() - 1; -// return Y[i] + (x - X[i]) * (Y[i + 1] - Y[i]) / (X[i + 1] - X[i]); -// } - double h = Uniform(0, 1); for (int i = 0; i < POINTS_VERY_FEW; i++) { if (h < BkgA[i]) { @@ -308,8 +292,9 @@ double Propagation::ShootPhotonEnergyMC(double Emin, double z) const { std::vector::const_iterator it; // find lowest energy bin - + if (Emin == 0) return 0; it = std::lower_bound(BkgE.begin(), BkgE.end(), Emin); + size_t iE; if (it == BkgE.begin()) iE = 0; @@ -320,15 +305,15 @@ double Propagation::ShootPhotonEnergyMC(double Emin, double z) const { // random number in selected range double h = Uniform(BkgA[iE], 1); - - // find energy for random number it = std::upper_bound(BkgA.begin(), BkgA.end(), h); + if (it == BkgA.begin()) return BkgE.front(); else if (it == BkgA.end()) return BkgE.back(); else return BkgE[it - BkgA.begin()]; + } std::vector Propagation::GetEtarget(Process &proc, @@ -340,33 +325,55 @@ std::vector Propagation::GetEtarget(Process &proc, double z_curr = particle.Getz(); double Energy = particle.GetEnergy(); int pType = particle.GetType(); - if (pType == 22) { - proc.SetName("PP"); - proc.SetLimits(); - smintmp = proc.GetMin(); - Etarget_tmp = ShootPhotonEnergyMC(ElectronMass * ElectronMass / Energy, - z_curr); - Etarget.push_back(Etarget_tmp); + double Eexp = smintmp/(4.0 * Energy); - proc.SetName("DPP"); - proc.SetLimits(); - smintmp = proc.GetMin(); - Etarget_tmp = ShootPhotonEnergyMC(smintmp / (4.0 * Energy), z_curr); - Etarget.push_back(Etarget_tmp); + if (pType == 22) { + proc.SetName("PP"); + proc.SetLimits(); + smintmp = proc.GetMin(); + Eexp = std::max(proc.feps_inf,ElectronMass*ElectronMass/Energy); + if (Eexp > proc.feps_sup) { +// std::cout << proc.GetName() << " " << Eexp << " too big wrt " << proc.feps_sup << " , " << proc.feps_inf << " .. it should not interact!" << std::endl; + Eexp = 0; + Etarget.push_back(0);} + else + Etarget_tmp = ShootPhotonEnergyMC(Eexp, z_curr); + Etarget.push_back(Etarget_tmp); + + proc.SetName("DPP"); + proc.SetLimits(); + smintmp = proc.GetMin(); + Eexp = std::max(proc.feps_inf,2*ElectronMass*ElectronMass/Energy); + if (Eexp > proc.feps_sup) { +// std::cout << proc.GetName() << " " << Eexp << " too big wrt " << proc.feps_sup << " , " << proc.feps_inf << " .. it should not interact!" << std::endl; + Eexp = 0; + Etarget.push_back(0);} + else + Etarget_tmp = ShootPhotonEnergyMC(Eexp, z_curr); + Etarget.push_back(Etarget_tmp); } else if (abs(pType) == 11) { - proc.SetName("ICS"); - proc.SetLimits(); - smintmp = proc.GetMin(); - Etarget_tmp = ShootPhotonEnergyMC(smintmp / (4.0 * Energy), z_curr); - Etarget.push_back(Etarget_tmp); - - proc.SetName("TPP"); - proc.SetLimits(); - smintmp = proc.GetMin(); - Etarget_tmp = ShootPhotonEnergyMC(smintmp / (4.0 * Energy), z_curr); - Etarget.push_back(Etarget_tmp); + proc.SetName("ICS"); + proc.SetLimits(); + smintmp = proc.GetMin(); + Eexp = proc.feps_inf; + Etarget_tmp = ShootPhotonEnergyMC(Eexp, z_curr); + + Etarget.push_back(Etarget_tmp); + + proc.SetName("TPP"); + proc.SetLimits(); + smintmp = proc.GetMin(); + Eexp = std::max(proc.feps_inf,2*ElectronMass*ElectronMass/Energy); + if (Eexp > proc.feps_sup) { +// std::cout << proc.GetName() << " " << Eexp << " too big wrt " << proc.feps_sup << " , " << proc.feps_inf << " .. it should not interact!" << std::endl; + Eexp = 0; + Etarget.push_back(0);} + else + Etarget_tmp = ShootPhotonEnergyMC(Eexp, z_curr); + + Etarget.push_back(Etarget_tmp); } //end e/e else std::cerr << "something wrong in particle type ( " << pType @@ -473,6 +480,9 @@ void Propagation::Propagate(Particle &curr_particle, Process proc; proc.SetIncidentParticle(curr_particle); proc.SetBackground(Bkg); + + double Ethr2 = std::max(fEthr, std::max(ElectronMass,ElectronMass*ElectronMass/proc.feps_sup)); + if (Ecurr < Ethr2) return; std::vector EtargetAll = GetEtarget(proc, curr_particle); #ifdef DEBUG_ELECA @@ -560,7 +570,7 @@ void Propagation::Propagate(Particle &curr_particle, curr_particle.Setz(z_curr); curr_particle.SetEnergy(Ecurr); - if (z_curr > 0 && Ecurr < fEthr) { + if (z_curr > 0 && Ecurr <= Ethr2) { return; } if (z_curr <= 0) { @@ -589,12 +599,12 @@ void Propagation::Propagate(Particle &curr_particle, std::cerr << "ERROR in PP process: E : " << Ecurr << " " << E1 << " " << std::endl; - if (E1 > fEthr) { + if (E1 > Ethr2) { Particle pp(11, E1, z_curr); pp.SetWeigth(wi_last); ParticleAtMatrix.push_back(pp); } - if (Ecurr - E1 > fEthr) { + if (Ecurr - E1 > Ethr2) { Particle pe(-11, Ecurr - E1, z_curr); pe.SetWeigth(wi_last); ParticleAtMatrix.push_back(pe); @@ -603,11 +613,11 @@ void Propagation::Propagate(Particle &curr_particle, return; } //if PP else if (proc.GetName() == "DPP") { - E1 = (Ecurr - 2 * ElectronMass) / 2.0; + E1 = (Ecurr - 2 * ElectronMass) / 2.0; if (E1 == 0) std::cerr << "ERROR in DPP process E : " << E1 << std::endl; - if (E1 > fEthr) { + if (E1 > Ethr2) { Particle pp(11, E1, z_curr); if (fast == 1) pp.SetWeigth(wi_last * 2); @@ -630,12 +640,12 @@ void Propagation::Propagate(Particle &curr_particle, std::cerr << "ERROR in ICS process E : " << E1 << " " << E2 << std::endl; - if (E1 > fEthr) { + if (E1 > Ethr2) { Particle pp(curr_particle.GetType(), E1, z_curr); pp.SetWeigth(wi_last); ParticleAtMatrix.push_back(pp); } - if (E2 > fEthr) { + if (E2 > Ethr2 ) { Particle pg(22, E2, z_curr); pg.SetWeigth(wi_last); ParticleAtMatrix.push_back(pg); @@ -650,7 +660,7 @@ void Propagation::Propagate(Particle &curr_particle, std::cerr << "ERROR in TPP process E : " << E1 << " " << E2 << std::endl; - if (E1 > fEthr) { + if (E1 > Ethr2) { Particle pp(11, E1, z_curr); if (fast == 1) pp.SetWeigth(wi_last * 2); @@ -662,7 +672,7 @@ void Propagation::Propagate(Particle &curr_particle, } ParticleAtMatrix.push_back(pp); } - if (E3 > fEthr) { + if (E3 > Ethr2) { Particle psc(curr_particle.GetType(), E3, z_curr); psc.SetWeigth(wi_last); ParticleAtMatrix.push_back(psc); From 4c54cb094a14b94c355704d7d12c4070e7c99e69 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 19 Sep 2014 15:08:35 +0200 Subject: [PATCH 0500/1298] Reduce log calculations --- libs/EleCa/src/EnergyLoss.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/libs/EleCa/src/EnergyLoss.cpp b/libs/EleCa/src/EnergyLoss.cpp index dc0491fe2..62550ca37 100644 --- a/libs/EleCa/src/EnergyLoss.cpp +++ b/libs/EleCa/src/EnergyLoss.cpp @@ -280,12 +280,12 @@ class PPSecondariesEnergyDistribution _s_max = s_max; _data = new double[Ns*Nrer]; - double dls = (log(s_max) - log(s_min)) / (Ns); + _dls = (log(s_max) - log(s_min)) / (Ns); double dls_min = log(s_min); for (size_t i = 0; i < Ns; i++) { - const double s = exp(dls_min + i*dls); + const double s = exp(dls_min + i*_dls); double beta = sqrt(1. - 4. * ElectronMass*ElectronMass /s); double x0 = log((1.-beta) / 2.); @@ -302,8 +302,7 @@ class PPSecondariesEnergyDistribution // returns pointer to the the integrated distribution for a given s double* getDistribution(double s) { - double dls = (log(_s_max) - log(_s_min)) / (_Ns); - size_t idx = (log(s) - log(_s_min)) / dls; + size_t idx = (log(s / _s_min)) / _dls; double *s0 = &_data[idx * _Nrer]; return s0; } @@ -413,12 +412,12 @@ class ICSSecondariesEnergyDistribution double theta = M_PI; - double dls = (log(s_max) - log(s_min)) / (Ns); + _dls = (log(s_max) - log(s_min)) / (Ns); double dls_min = log(s_min); for (size_t i = 0; i < Ns; i++) { - const double s = exp(dls_min + i*dls); + const double s = exp(dls_min + i*_dls); double beta = (s - ElectronMass * ElectronMass) / (s + ElectronMass * ElectronMass); @@ -439,8 +438,7 @@ class ICSSecondariesEnergyDistribution // returns pointer to the the integrated distribution for a given s double* getDistribution(double s) { - double dls = (log(_s_max) - log(_s_min)) / (_Ns); - size_t idx = (log(s) - log(_s_min)) / dls; + size_t idx = (log(s / _s_min)) / _dls; double *s0 = &_data[idx * _Nrer]; return s0; } From 3ddb81934f9d72a2c4390b6db11b51e26624576b Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Mon, 22 Sep 2014 13:40:12 +0200 Subject: [PATCH 0501/1298] Enable fastmath for EleCa. --- libs/EleCa/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/EleCa/CMakeLists.txt b/libs/EleCa/CMakeLists.txt index 07cb8608a..fb3a90f37 100644 --- a/libs/EleCa/CMakeLists.txt +++ b/libs/EleCa/CMakeLists.txt @@ -10,4 +10,4 @@ add_library(eleca STATIC src/Propagation ) -SET_TARGET_PROPERTIES( eleca PROPERTIES COMPILE_FLAGS -fPIC) +SET_TARGET_PROPERTIES(eleca PROPERTIES COMPILE_FLAGS "-fPIC -ffast-math") From c7753185126442e9ca7c7951146ebc90bc5b255d Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Mon, 22 Sep 2014 13:40:55 +0200 Subject: [PATCH 0502/1298] Reduced number of log calculations --- libs/EleCa/include/EleCa/Propagation.h | 1 + libs/EleCa/src/Propagation.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libs/EleCa/include/EleCa/Propagation.h b/libs/EleCa/include/EleCa/Propagation.h index bd4611a3b..81b5802a3 100644 --- a/libs/EleCa/include/EleCa/Propagation.h +++ b/libs/EleCa/include/EleCa/Propagation.h @@ -23,6 +23,7 @@ class Propagation { std::vector BkgE, BkgA; std::string Bkg; double fEthr; + double _dEtab; public: diff --git a/libs/EleCa/src/Propagation.cpp b/libs/EleCa/src/Propagation.cpp index fc4ebb2fe..5edcd553d 100644 --- a/libs/EleCa/src/Propagation.cpp +++ b/libs/EleCa/src/Propagation.cpp @@ -46,7 +46,8 @@ void Propagation::ReadTables(const std::string &filename) { vTPPle[k] = TPPle; k++; } - + // store dEtab + _dEtab = log10(vEtab[0] / vEtab[1]); if (k != 1101) std::cerr << "Failed to read lambda_table file: " << filename << "! only " << k << " entries, expected 1101!"; @@ -231,9 +232,9 @@ double Propagation::GetLambdaTab(const Process &proc, double E0taborg = vEtab[0]; - double dEtab = log10(vEtab[0] / vEtab[1]); + //double dEtab = log10(vEtab[0] / vEtab[1]); double evolution = GetEvolution(proc.GetTargetParticle().GetEnergy(), z); - int i = (int) (log10(E0taborg / (E1 * (1 + z))) / dEtab); + int i = (int) (log10(E0taborg / (E1 * (1 + z))) / _dEtab); if (i < 0) { std::cout << "WARNING!! GetLambdaTab in " << procName << " : i= " << i From 8be61edd9202282116d19f1ecb61c1f0e2813cf1 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 26 Sep 2014 10:13:07 +0200 Subject: [PATCH 0503/1298] Added FindSWIG to CMakeLists --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 39616ee2c..d84660f2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -248,6 +248,7 @@ endif(ENABLE_TESTING) # ---------------------------------------------------------------------------- option(ENABLE_PYTHON "Create python library via SWIG" ON) if(ENABLE_PYTHON) + FIND_PACKAGE(SWIG REQUIRED) include(python/Python.cmake) include_directories(${PYTHON_INCLUDE_PATH}) From 3b39265464bf7f8712245157415775096fa3941c Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Wed, 1 Oct 2014 16:39:13 +0200 Subject: [PATCH 0504/1298] expose TurbulentMagneticField to python and make sign of spectral index consistent with the grid version --- python/crpropa.i | 2 ++ src/magneticField/TurbulentMagneticField.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/python/crpropa.i b/python/crpropa.i index 4ca609fc3..1bd19e29c 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -50,6 +50,7 @@ using std::ptrdiff_t; #include "crpropa/magneticField/QuimbyMagneticField.h" #include "crpropa/magneticField/AMRMagneticField.h" #include "crpropa/magneticField/JF12Field.h" +#include "crpropa/magneticField/TurbulentMagneticField.h" #include "crpropa/Referenced.h" #include "crpropa/Candidate.h" @@ -145,6 +146,7 @@ using std::ptrdiff_t; %include "crpropa/magneticField/QuimbyMagneticField.h" %include "crpropa/magneticField/AMRMagneticField.h" %include "crpropa/magneticField/JF12Field.h" +%include "crpropa/magneticField/TurbulentMagneticField.h" %include "crpropa/module/BreakCondition.h" %include "crpropa/module/Boundary.h" diff --git a/src/magneticField/TurbulentMagneticField.cpp b/src/magneticField/TurbulentMagneticField.cpp index 489d1ddc7..4d1aadc79 100644 --- a/src/magneticField/TurbulentMagneticField.cpp +++ b/src/magneticField/TurbulentMagneticField.cpp @@ -60,7 +60,7 @@ void TurbulentMagneticField::initialize() { // amplitude (this seems to be wrong) double dk = k * dlk; - double Gk = k * k * dk / (1 + pow(k * Lc, spectralIndex)); + double Gk = k * k * dk / (1 + pow(k * Lc, -spectralIndex)); sumGk += Gk; mode.amplitude = Brms * sqrt(Gk); From b59ccc7b3e30b11fbc8264027a96289ddf903698 Mon Sep 17 00:00:00 2001 From: Carmelo Evoli Date: Thu, 2 Oct 2014 17:08:13 +0200 Subject: [PATCH 0505/1298] Implemented variable IRB in PhotoPionProduction, testing phase --- include/crpropa/Common.h | 10 +- include/crpropa/PhotonBackground.h | 2 +- include/crpropa/module/PhotoPionProduction.h | 2 + src/Common.cpp | 31 + src/module/PhotoPionProduction.cpp | 559 ++++++++++--------- 5 files changed, 331 insertions(+), 273 deletions(-) diff --git a/include/crpropa/Common.h b/include/crpropa/Common.h index 735ab2c04..fa30db2b9 100644 --- a/include/crpropa/Common.h +++ b/include/crpropa/Common.h @@ -25,8 +25,14 @@ T clip(const T& x, const T& lower, const T& upper) { double interpolate(double x, const std::vector& X, const std::vector& Y); -// Perform linear interpolation on equidistant tabulated data -// Returns Y[0] if x < lo and Y[n-1] if x > hi + +// Perform bilinear interpolation on a set of (n,m) tabulated data points X[0 .. n-1], Y[0 .. m-1] -> Z[0.. n-1*m-1] +// Returns 0 if x < X[0] or x > X[n-1] or y < Y[0] or y > Y[m-1] + double interpolate2d(double x, double y, const std::vector& X, + const std::vector& Y, const std::vector& Z); + + // Perform linear interpolation on equidistant tabulated data + // Returns Y[0] if x < lo and Y[n-1] if x > hi double interpolateEquidistant(double x, double lo, double hi, const std::vector& Y); diff --git a/include/crpropa/PhotonBackground.h b/include/crpropa/PhotonBackground.h index 2f2427f58..1593e93d3 100644 --- a/include/crpropa/PhotonBackground.h +++ b/include/crpropa/PhotonBackground.h @@ -6,7 +6,7 @@ namespace crpropa { // Photon fields // The default IRB model is that of Kneiske et al. 2004 enum PhotonField { - CMB, IRB, IRB_Kneiske04, IRB_Kneiske10, IRB_Franceschini08, IRB_Stecker05 + CMB, IRB, IRB_Kneiske04, IRB_Kneiske10, IRB_Franceschini08, IRB_Stecker05, IRB_withRedshift_Kneiske04 }; // Returns overall comoving scaling factor diff --git a/include/crpropa/module/PhotoPionProduction.h b/include/crpropa/module/PhotoPionProduction.h index 22fc57a17..88a96618a 100644 --- a/include/crpropa/module/PhotoPionProduction.h +++ b/include/crpropa/module/PhotoPionProduction.h @@ -16,12 +16,14 @@ class PhotoPionProduction: public Module { private: PhotonField photonField; std::vector tabLorentz; ///< Lorentz factor of nucleus + std::vector tabRedshifts; ///< Redshifts for the interaction rates std::vector tabProtonRate; ///< interaction rate in [1/m] for protons std::vector tabNeutronRate; ///< interaction rate in [1/m] for neutrons double limit; ///< fraction of mean free path to limit the next step bool havePhotons; bool haveNeutrinos; bool haveAntiNucleons; + bool doRedshiftDependent; public: PhotoPionProduction(PhotonField photonField = CMB, bool photons = false, diff --git a/src/Common.cpp b/src/Common.cpp index 08a84acae..4753ef9c2 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -9,6 +9,8 @@ #include #include +#define index(i,j) ((j)+(i)*Y.size()) + namespace crpropa { std::string getDataPath(std::string filename) { @@ -66,6 +68,35 @@ double interpolate(double x, const std::vector &X, return Y[i] + (x - X[i]) * (Y[i + 1] - Y[i]) / (X[i + 1] - X[i]); } + double interpolate2d(double x, double y, const std::vector &X, + const std::vector &Y, const std::vector &Z) { + std::vector::const_iterator itx = std::upper_bound(X.begin(), X.end(), x); // Redshift + std::vector::const_iterator ity = std::upper_bound(Y.begin(), Y.end(), y); // Lorentz + + if (x >= X.back() || x <= X.front()) + return 0; + if (y >= Y.back() || y <= Y.front()) + return 0; + + if (itx == X.begin() && ity == Y.begin()) + return Z.front(); + if (itx == X.end() && ity == Y.end()) + return Z.back(); + + size_t i = itx - X.begin() - 1; + size_t j = ity - Y.begin() - 1; + + double Q11 = Z[i,j]; + double Q12 = Z[i,j+1]; + double Q21 = Z[x+1,j]; + double Q22 = Z[x+1,j+1]; + + double R1 = ((X[i+1]-x)/(X[i+1]-X[i]))*Q11+((x-X[i])/(X[i+1]-X[i]))*Q21; + double R2 = ((X[i+1]-x)/(X[i+1]-X[i]))*Q12+((x-X[i])/(X[i+1]-X[i]))*Q22; + + return ((Y[j+1]-y)/(Y[j+1]-Y[j]))*R1+((y-Y[j])/(Y[j+1]-Y[j]))*R2; + } + double interpolateEquidistant(double x, double lo, double hi, const std::vector &Y) { if (x <= lo) diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index bc26228d7..a153380a4 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -14,280 +14,299 @@ namespace crpropa { -PhotoPionProduction::PhotoPionProduction(PhotonField field, bool photons, - bool neutrinos, bool antiNucleons, double l) { - photonField = field; - havePhotons = photons; - haveNeutrinos = neutrinos; - haveAntiNucleons = antiNucleons; - limit = l; - init(); -} - -void PhotoPionProduction::setPhotonField(PhotonField photonField) { - this->photonField = photonField; - init(); -} - -void PhotoPionProduction::setHavePhotons(bool b) { - havePhotons = b; -} - -void PhotoPionProduction::setHaveNeutrinos(bool b) { - haveNeutrinos = b; -} - -void PhotoPionProduction::setHaveAntiNucleons(bool b) { - haveAntiNucleons = b; -} - -void PhotoPionProduction::setLimit(double l) { - limit = l; -} - -void PhotoPionProduction::init() { - switch (photonField) { - case CMB: - setDescription("PhotoPionProduction: CMB"); - init(getDataPath("ppp_CMB.txt")); - break; - case IRB: // default: Kneiske '04 IRB model - case IRB_Kneiske04: - setDescription("PhotoPionProduction: IRB Kneiske '04"); - init(getDataPath("ppp_IRB_Kneiske04.txt")); - break; - case IRB_Kneiske10: - setDescription("PhotoPionProduction: IRB Kneiske '10 (lower limit)"); - init(getDataPath("ppp_IRB_Kneiske10.txt")); - break; - case IRB_Stecker05: - setDescription("PhotoPionProduction: IRB Stecker '05"); - init(getDataPath("ppp_IRB_Stecker05.txt")); - break; - case IRB_Franceschini08: - setDescription("PhotoPionProduction: IRB Franceschini '08"); - init(getDataPath("ppp_IRB_Franceschini08.txt")); - break; - default: - throw std::runtime_error( - "PhotoPionProduction: unknown photon background"); + PhotoPionProduction::PhotoPionProduction(PhotonField field, bool photons, + bool neutrinos, bool antiNucleons, double l) { + photonField = field; + havePhotons = photons; + haveNeutrinos = neutrinos; + haveAntiNucleons = antiNucleons; + doRedshiftDependent = false; + limit = l; + init(); + } + + void PhotoPionProduction::setPhotonField(PhotonField photonField) { + this->photonField = photonField; + init(); + } + + void PhotoPionProduction::setHavePhotons(bool b) { + havePhotons = b; + } + + void PhotoPionProduction::setHaveNeutrinos(bool b) { + haveNeutrinos = b; + } + + void PhotoPionProduction::setHaveAntiNucleons(bool b) { + haveAntiNucleons = b; + } + + void PhotoPionProduction::setLimit(double l) { + limit = l; + } + + void PhotoPionProduction::init() { + switch (photonField) { + case CMB: + setDescription("PhotoPionProduction: CMB"); + init(getDataPath("ppp_CMB.txt")); + break; + case IRB: // default: Kneiske '04 IRB model + case IRB_Kneiske04: + setDescription("PhotoPionProduction: IRB Kneiske '04"); + init(getDataPath("ppp_IRB_Kneiske04.txt")); + break; + case IRB_Kneiske10: + setDescription("PhotoPionProduction: IRB Kneiske '10 (lower limit)"); + init(getDataPath("ppp_IRB_Kneiske10.txt")); + break; + case IRB_Stecker05: + setDescription("PhotoPionProduction: IRB Stecker '05"); + init(getDataPath("ppp_IRB_Stecker05.txt")); + break; + case IRB_Franceschini08: + setDescription("PhotoPionProduction: IRB Franceschini '08"); + init(getDataPath("ppp_IRB_Franceschini08.txt")); + break; + case IRB_withRedshift_Kneiske04: + doRedshiftDependent = true; + setDescription("PhotoPionProduction: IRB with redshift Kneiske '04"); + init(getDataPath("ppp_IRBz_Kneiske04.txt")); + break; + default: + throw std::runtime_error( + "PhotoPionProduction: unknown photon background"); + } + } + + void PhotoPionProduction::init(std::string filename) { + std::ifstream infile(filename.c_str()); + if (!infile.good()) + throw std::runtime_error( + "PhotoPionProduction: could not open file " + filename); + + // clear previously loaded tables + tabLorentz.clear(); + tabRedshifts.clear(); + tabProtonRate.clear(); + tabNeutronRate.clear(); + + double zOld = -1, aOld = -1; + bool doReadLorentz = true; + + while (infile.good()) { + if (infile.peek() != '#') { + double z, a, b, c; + if (!doRedshiftDependent) infile >> a >> b >> c; + else infile >> z >> a >> b >> c; + if (infile) { + if (doRedshiftDependent && z != zOld) tabRedshifts.push_back(z); + if (a < aOld) doReadLorentz = false; + if (doReadLorentz) tabLorentz.push_back(pow(10, a)); + tabProtonRate.push_back(b / Mpc); + tabNeutronRate.push_back(c / Mpc); + zOld = z; + aOld = a; } -} - -void PhotoPionProduction::init(std::string filename) { - std::ifstream infile(filename.c_str()); - if (!infile.good()) - throw std::runtime_error( - "PhotoPionProduction: could not open file " + filename); - - // clear previously loaded tables - tabLorentz.clear(); - tabProtonRate.clear(); - tabNeutronRate.clear(); - - while (infile.good()) { - if (infile.peek() != '#') { - double a, b, c; - infile >> a >> b >> c; - if (infile) { - tabLorentz.push_back(pow(10, a)); - tabProtonRate.push_back(b / Mpc); - tabNeutronRate.push_back(c / Mpc); - } - } - infile.ignore(std::numeric_limits::max(), '\n'); + } + infile.ignore(std::numeric_limits::max(), '\n'); + } + + std::cout<<"Read IRB table in "<getCurrentStep(); + do { + // check if nucleus + int id = candidate->current.getId(); + if (not (isNucleus(id))) + return; + + double z = candidate->getRedshift(); + double gamma = (1 + z) * candidate->current.getLorentzFactor(); + + // check if in tabulated energy range + if (gamma < tabLorentz.front() or (gamma > tabLorentz.back())) + return; + + // find interaction with minimum random distance + Random &random = Random::instance(); + double randDistance = std::numeric_limits::max(); + int channel; // interacting particle: 1 for proton, 0 for neutron + double totalRate = 0; + + // comological scaling of interaction distance (comoving) + double scaling = pow(1 + z, 2) * photonFieldScaling(photonField, z); + + int A = massNumber(id); + int Z = chargeNumber(id); + int N = A - Z; + + // check for interaction on protons + if (Z > 0) { + double rate = (!doRedshiftDependent) + ? scaling*interpolate(gamma, tabLorentz, tabProtonRate) + : interpolate2d(z, gamma, tabRedshifts, tabLorentz, tabProtonRate); + rate *= nucleiModification(A, Z); + totalRate += rate; + channel = 1; + randDistance = -log(random.rand()) / rate; + } + + // check for interaction on neutrons + if (N > 0) { + double rate = (!doRedshiftDependent) + ? scaling*interpolate(gamma, tabLorentz, tabNeutronRate) + : interpolate2d(z, gamma, tabRedshifts, tabLorentz, tabNeutronRate); + rate *= nucleiModification(A, N); + totalRate += rate; + double d = -log(random.rand()) / rate; + if (d < randDistance) { + randDistance = d; + channel = 0; } - infile.close(); -} - -double PhotoPionProduction::nucleiModification(int A, int X) const { - if (A == 1) - return 1.; - if (A <= 8) - return 0.85 * pow(X, 2. / 3.); - return 0.85 * X; -} - -void PhotoPionProduction::process(Candidate *candidate) const { - // the loop should be processed at least once for limiting the next step - double step = candidate->getCurrentStep(); - do { - // check if nucleus - int id = candidate->current.getId(); - if (not (isNucleus(id))) - return; - - double z = candidate->getRedshift(); - double gamma = (1 + z) * candidate->current.getLorentzFactor(); - - // check if in tabulated energy range - if (gamma < tabLorentz.front() or (gamma > tabLorentz.back())) - return; - - // find interaction with minimum random distance - Random &random = Random::instance(); - double randDistance = std::numeric_limits::max(); - int channel; // interacting particle: 1 for proton, 0 for neutron - double totalRate = 0; - - // comological scaling of interaction distance (comoving) - double scaling = pow(1 + z, 2) * photonFieldScaling(photonField, z); - - int A = massNumber(id); - int Z = chargeNumber(id); - int N = A - Z; - - // check for interaction on protons - if (Z > 0) { - double rate = interpolate(gamma, tabLorentz, tabProtonRate); - rate *= nucleiModification(A, Z); - rate *= scaling; - totalRate += rate; - channel = 1; - randDistance = -log(random.rand()) / rate; - } - - // check for interaction on neutrons - if (N > 0) { - double rate = interpolate(gamma, tabLorentz, tabNeutronRate); - rate *= nucleiModification(A, N); - rate *= scaling; - totalRate += rate; - double d = -log(random.rand()) / rate; - if (d < randDistance) { - randDistance = d; - channel = 0; - } - } - - // check if interaction does not happen - if (step < randDistance) { - candidate->limitNextStep(limit / totalRate); - return; - } - - // interact and repeat with remaining step - performInteraction(candidate, channel); - step -= randDistance; - } while (step > 0); -} - -void PhotoPionProduction::performInteraction(Candidate *candidate, - int channel) const { - - int id = candidate->current.getId(); - int A = massNumber(id); - int Z = chargeNumber(id); - double E = candidate->current.getEnergy(); - double EpA = E / A; - double z = candidate->getRedshift(); - - // SOPHIA simulates interactions only for protons / neutrons - // for anti-protons / neutrons assume charge symmetry and change all - // interaction products from particle <--> anti-particle - int sign = (id > 0) ? 1 : -1; - - // arguments for sophia - int nature = 1 - channel; // interacting particle: 0 for proton, 1 for neutron - double Ein = EpA / GeV; // energy of in-going nucleon in GeV - double momentaList[5][2000]; // momentum list, what are the five components? - int particleList[2000]; // particle id list - int nParticles; // number of outgoing particles - double maxRedshift = 100; // IR photon density is zero above this redshift - int dummy1; // not needed - double dummy2[2]; // not needed - int background = (photonField == CMB) ? 1 : 2; // photon background: 1 for CMB, 2 for Kneiske IRB + } + + // check if interaction does not happen + if (step < randDistance) { + candidate->limitNextStep(limit / totalRate); + return; + } + + // interact and repeat with remaining step + performInteraction(candidate, channel); + step -= randDistance; + } while (step > 0); + } + + void PhotoPionProduction::performInteraction(Candidate *candidate, + int channel) const { + + int id = candidate->current.getId(); + int A = massNumber(id); + int Z = chargeNumber(id); + double E = candidate->current.getEnergy(); + double EpA = E / A; + double z = candidate->getRedshift(); + + // SOPHIA simulates interactions only for protons / neutrons + // for anti-protons / neutrons assume charge symmetry and change all + // interaction products from particle <--> anti-particle + int sign = (id > 0) ? 1 : -1; + + // arguments for sophia + int nature = 1 - channel; // interacting particle: 0 for proton, 1 for neutron + double Ein = EpA / GeV; // energy of in-going nucleon in GeV + double momentaList[5][2000]; // momentum list, what are the five components? + int particleList[2000]; // particle id list + int nParticles; // number of outgoing particles + double maxRedshift = 100; // IR photon density is zero above this redshift + int dummy1; // not needed + double dummy2[2]; // not needed + int background = (photonField == CMB) ? 1 : 2; // photon background: 1 for CMB, 2 for Kneiske IRB #pragma omp critical - { - sophiaevent_(nature, Ein, momentaList, particleList, nParticles, z, - background, maxRedshift, dummy1, dummy2, dummy2); + { + sophiaevent_(nature, Ein, momentaList, particleList, nParticles, z, + background, maxRedshift, dummy1, dummy2, dummy2); + } + + for (int i = 0; i < nParticles; i++) { // loop over out-going particles + double Eout = momentaList[3][i] * GeV; // only the energy is used; could be changed for more detail + int pType = particleList[i]; + switch (pType) { + case 13: // proton + case 14: // neutron + if (A == 1) { + // single interacting nucleon + candidate->current.setEnergy(Eout); + candidate->current.setId(sign * nucleusId(1, 14 - pType)); + } else { + // interacting nucleon is part of nucleus: it is emitted from the nucleus + candidate->current.setEnergy(E - EpA); + candidate->current.setId(sign * nucleusId(A - 1, Z - channel)); + candidate->addSecondary(sign * nucleusId(1, 14 - pType), Eout); } - - for (int i = 0; i < nParticles; i++) { // loop over out-going particles - double Eout = momentaList[3][i] * GeV; // only the energy is used; could be changed for more detail - int pType = particleList[i]; - switch (pType) { - case 13: // proton - case 14: // neutron - if (A == 1) { - // single interacting nucleon - candidate->current.setEnergy(Eout); - candidate->current.setId(sign * nucleusId(1, 14 - pType)); - } else { - // interacting nucleon is part of nucleus: it is emitted from the nucleus - candidate->current.setEnergy(E - EpA); - candidate->current.setId(sign * nucleusId(A - 1, Z - channel)); - candidate->addSecondary(sign * nucleusId(1, 14 - pType), Eout); - } - break; - case -13: // anti-proton - case -14: // anti-neutron - if (haveAntiNucleons) - candidate->addSecondary(-sign * nucleusId(1, 14 + pType), Eout); - break; - case 1: // photon - if (havePhotons) - candidate->addSecondary(22, Eout); - break; - case 2: // positron - if (havePhotons) - candidate->addSecondary(sign * -11, Eout); - break; - case 3: // electron - if (havePhotons) - candidate->addSecondary(sign * 11, Eout); - break; - case 15: // nu_e - if (haveNeutrinos) - candidate->addSecondary(sign * 12, Eout); - break; - case 16: // antinu_e - if (haveNeutrinos) - candidate->addSecondary(sign * -12, Eout); - break; - case 17: // nu_muon - if (haveNeutrinos) - candidate->addSecondary(sign * 14, Eout); - break; - case 18: // antinu_muon - if (haveNeutrinos) - candidate->addSecondary(sign * -14, Eout); - break; - default: - throw std::runtime_error( - "PhotoPionProduction: unexpected particle " - + kiss::str(pType)); - } - } -} - -double PhotoPionProduction::lossLength(int id, double gamma, double z) { - int A = massNumber(id); - int Z = chargeNumber(id); - int N = A - Z; - - gamma *= (1 + z); // cosmological scaling of photon energy - if (gamma < tabLorentz.front() or (gamma > tabLorentz.back())) - return std::numeric_limits::max(); - - double lossRate = 0; - if (Z > 0) - lossRate += interpolate(gamma, tabLorentz, tabProtonRate) - * nucleiModification(A, Z); - if (N > 0) - lossRate += interpolate(gamma, tabLorentz, tabProtonRate) - * nucleiModification(A, N); - - // protons / neutrons keep as energy the fraction of mass to delta-resonance mass - // nuclei approximately lose the energy that the interacting nucleon is carrying - double relativeEnergyLoss = (A == 1) ? 1 - 938. / 1232. : 1. / A; - lossRate *= relativeEnergyLoss; - - // cosmological scaling of photon density - lossRate *= pow(1 + z, 3) * photonFieldScaling(photonField, z); - - return 1. / lossRate; -} + break; + case -13: // anti-proton + case -14: // anti-neutron + if (haveAntiNucleons) + candidate->addSecondary(-sign * nucleusId(1, 14 + pType), Eout); + break; + case 1: // photon + if (havePhotons) + candidate->addSecondary(22, Eout); + break; + case 2: // positron + if (havePhotons) + candidate->addSecondary(sign * -11, Eout); + break; + case 3: // electron + if (havePhotons) + candidate->addSecondary(sign * 11, Eout); + break; + case 15: // nu_e + if (haveNeutrinos) + candidate->addSecondary(sign * 12, Eout); + break; + case 16: // antinu_e + if (haveNeutrinos) + candidate->addSecondary(sign * -12, Eout); + break; + case 17: // nu_muon + if (haveNeutrinos) + candidate->addSecondary(sign * 14, Eout); + break; + case 18: // antinu_muon + if (haveNeutrinos) + candidate->addSecondary(sign * -14, Eout); + break; + default: + throw std::runtime_error( + "PhotoPionProduction: unexpected particle " + + kiss::str(pType)); + } + } + } + + double PhotoPionProduction::lossLength(int id, double gamma, double z) { + int A = massNumber(id); + int Z = chargeNumber(id); + int N = A - Z; + + gamma *= (1 + z); // cosmological scaling of photon energy + if (gamma < tabLorentz.front() or (gamma > tabLorentz.back())) + return std::numeric_limits::max(); + + double lossRate = 0; + if (Z > 0) + lossRate += interpolate(gamma, tabLorentz, tabProtonRate) + * nucleiModification(A, Z); + if (N > 0) + lossRate += interpolate(gamma, tabLorentz, tabProtonRate) + * nucleiModification(A, N); + + // protons / neutrons keep as energy the fraction of mass to delta-resonance mass + // nuclei approximately lose the energy that the interacting nucleon is carrying + double relativeEnergyLoss = (A == 1) ? 1 - 938. / 1232. : 1. / A; + lossRate *= relativeEnergyLoss; + + // cosmological scaling of photon density + lossRate *= pow(1 + z, 3) * photonFieldScaling(photonField, z); + + return 1. / lossRate; + } } // namespace crpropa From 80d4cd49ed21fb4baa197a95a9604fe5bcbff735 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Tue, 7 Oct 2014 10:14:23 +0200 Subject: [PATCH 0506/1298] Clearified parameter naming --- include/crpropa/module/PhotonEleCa.h | 2 +- src/module/PhotonEleCa.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/crpropa/module/PhotonEleCa.h b/include/crpropa/module/PhotonEleCa.h index cf3e4033d..8becff660 100644 --- a/include/crpropa/module/PhotonEleCa.h +++ b/include/crpropa/module/PhotonEleCa.h @@ -21,7 +21,7 @@ class PhotonEleCa: public Module { Vector3d observer; bool saveOnlyPhotonEnergies; public: - PhotonEleCa(const std::string background, const std::string &filename); + PhotonEleCa(const std::string background, const std::string &outputFilename); ~PhotonEleCa(); void process(Candidate *candidate) const; std::string getDescription() const; diff --git a/src/module/PhotonEleCa.cpp b/src/module/PhotonEleCa.cpp index b3fa871a0..734a7212d 100644 --- a/src/module/PhotonEleCa.cpp +++ b/src/module/PhotonEleCa.cpp @@ -10,12 +10,12 @@ namespace crpropa { PhotonEleCa::PhotonEleCa(const std::string background, - const std::string &filename) : + const std::string &outputFilename) : propagation(new eleca::Propagation), saveOnlyPhotonEnergies(false) { //propagation->ReadTables(getDataPath("eleca_lee.txt")); propagation->ReadTables(getDataPath("EleCa/eleca.dat")); propagation->InitBkgArray(background); - output.open(filename.c_str()); + output.open(outputFilename.c_str()); } PhotonEleCa::~PhotonEleCa() { From ceb09598eafbaf6df868502ef6e6240e9020f0f9 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Tue, 7 Oct 2014 11:53:38 +0200 Subject: [PATCH 0507/1298] EleCa: Set seed in Random Number Generator (temporary workaround to avboid repetition of numbers) --- libs/EleCa/include/EleCa/Common.h | 3 +++ libs/EleCa/src/Common.cpp | 18 +++++++++++------- src/PhotonPropagation.cpp | 1 + 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/libs/EleCa/include/EleCa/Common.h b/libs/EleCa/include/EleCa/Common.h index 90985ca1b..fdb10cbdc 100644 --- a/libs/EleCa/include/EleCa/Common.h +++ b/libs/EleCa/include/EleCa/Common.h @@ -7,6 +7,9 @@ double z2Mpc(double z); double Mpc2z(double D); double Uniform(double min, double max); +// set the seed for the random generator. If 0, current ime is used +void setSeed(long int seedval=0); + void setUniformCallback(double (*Uniform)(double min, double max)); diff --git a/libs/EleCa/src/Common.cpp b/libs/EleCa/src/Common.cpp index 47362d375..32a1af8c5 100644 --- a/libs/EleCa/src/Common.cpp +++ b/libs/EleCa/src/Common.cpp @@ -4,6 +4,9 @@ #include #include #include +#include + +#include namespace eleca { @@ -29,17 +32,18 @@ double Mpc2z(double D) { } } -static double (*_Uniform)(double min, double max) = 0; -void setUniformCallback(double (*uniform)(double min, double max)) { - _Uniform = uniform; +void setSeed(long int seedval) +{ + if (seedval == 0) + { // use system time + time(&seedval); + } + ::srand48(seedval); } + double Uniform(double min, double max) { - if (_Uniform) - return _Uniform(min, max); - else - //return crpropa::Random::instance().randUniform(min, max); return min + (max - min) * ::drand48(); } diff --git a/src/PhotonPropagation.cpp b/src/PhotonPropagation.cpp index f18dc90b2..450f1ace8 100644 --- a/src/PhotonPropagation.cpp +++ b/src/PhotonPropagation.cpp @@ -39,6 +39,7 @@ void EleCaPropagation(const std::string &inputfile, throw std::runtime_error( "EleCaPropagation: could not open file " + inputfile); + eleca::setSeed(); eleca::Propagation propagation; propagation.SetEthr(lowerEnergyThreshold); propagation.ReadTables(getDataPath("EleCa/eleca.dat")); From e91be384a93a03cf5a3d01d61176fa5fc50d0566 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Tue, 7 Oct 2014 17:37:19 +0200 Subject: [PATCH 0508/1298] Add width of energy bins to Dint output --- src/PhotonPropagation.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PhotonPropagation.cpp b/src/PhotonPropagation.cpp index 450f1ace8..815d52582 100644 --- a/src/PhotonPropagation.cpp +++ b/src/PhotonPropagation.cpp @@ -243,8 +243,10 @@ void DintPropagation(const std::string &inputfile, DeleteSpectrum(&inputSpectrum); } + outfile << "# BinCenter [EeV] BinWidth [EeV] Flux-Weights for photons electrons positrons ... \n"; for (int j = 0; j < finalSpectrum.numberOfMainBins; j++) { outfile << (energyGrid.vector[j] / EeV * (eV * ELECTRON_MASS)) << " "; + outfile << (energyWidth.vector[j] / EeV * (eV * ELECTRON_MASS)) << " "; for (int i = 0; i < NUM_SPECIES; i++) { outfile << finalSpectrum.spectrum[i][j] << " "; } From e41f2748ef4ab6c6069226af08ca5fc057be45ca Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Wed, 8 Oct 2014 15:05:52 +0200 Subject: [PATCH 0509/1298] Allow setting progressbar to specific value --- include/crpropa/ProgressBar.h | 5 +++- src/ProgressBar.cpp | 50 +++++++++++++++++++---------------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/include/crpropa/ProgressBar.h b/include/crpropa/ProgressBar.h index b4a6446a3..fe852e770 100644 --- a/include/crpropa/ProgressBar.h +++ b/include/crpropa/ProgressBar.h @@ -26,7 +26,10 @@ class ProgressBar { /// update the progressbar /// should be called steps times in a loop - void update(); + void update(); + + // sets the position of the bar to a given value + void setPosition(unsigned long position); /// Mark the progressbar with an error void setError(); diff --git a/src/ProgressBar.cpp b/src/ProgressBar.cpp index 0143fdcbb..ba12b80e6 100644 --- a/src/ProgressBar.cpp +++ b/src/ProgressBar.cpp @@ -27,33 +27,37 @@ void ProgressBar::update() { _currentCount++; if (_currentCount == _nextStep || _currentCount == _steps || _currentCount == 1000) { - _nextStep += long(_steps / float(_updateSteps)); + _nextStep += long(_steps / float(_updateSteps)); + setPosition(_currentCount); + } +} - int percentage = int(100 * _currentCount / float(_steps)); - time_t currentTime = time(NULL); - if (_currentCount < _steps) { - int j = 0; - if (arrow.size() <= (_maxbarLength) * (_currentCount) / (_steps)) - arrow.insert(0, "="); - float tElapsed = currentTime - _startTime; - float tToGo = (_steps - _currentCount) * tElapsed / _currentCount; - printf(stringTmpl.c_str(), arrow.c_str(), percentage, "Finish in", - int(tToGo / 3600), (int(tToGo) % 3600) / 60, - int(tToGo) % 60, ""); - fflush(stdout); - } else { - float tElapsed = currentTime - _startTime; - std::string s = " - Finished at "; - s.append(ctime(¤tTime)); - char fs[255]; - sprintf(fs, "%c[%d;%dm Finished %c[%dm", 27, 1, 32, 27, 0); - printf(stringTmpl.c_str(), fs, percentage, "Needed", - int(tElapsed / 3600), (int(tElapsed) % 3600) / 60, - int(tElapsed) % 60, s.c_str()); - } +void ProgressBar::setPosition(unsigned long position) { + int percentage = int(100 * (position / float(_steps))); + time_t currentTime = time(NULL); + if (position < _steps) { + int j = 0; + if (arrow.size() <= (_maxbarLength) * (position) / (_steps)) + arrow.insert(0, "="); + float tElapsed = currentTime - _startTime; + float tToGo = (_steps - position) * tElapsed / position; + printf(stringTmpl.c_str(), arrow.c_str(), percentage, "Finish in", + int(tToGo / 3600), (int(tToGo) % 3600) / 60, + int(tToGo) % 60, ""); + fflush(stdout); + } else { + float tElapsed = currentTime - _startTime; + std::string s = " - Finished at "; + s.append(ctime(¤tTime)); + char fs[255]; + sprintf(fs, "%c[%d;%dm Finished %c[%dm", 27, 1, 32, 27, 0); + printf(stringTmpl.c_str(), fs, percentage, "Needed", + int(tElapsed / 3600), (int(tElapsed) % 3600) / 60, + int(tElapsed) % 60, s.c_str()); } } + /// Mark the progressbar with an error void ProgressBar::setError() { time_t currentTime = time(NULL); From e5573862202eb70787e86804b3fd5af6a9099823 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Wed, 8 Oct 2014 15:06:34 +0200 Subject: [PATCH 0510/1298] Set Eleca output to single photons --- include/crpropa/PhotonPropagation.h | 11 +++--- src/PhotonPropagation.cpp | 52 +++++++++++++---------------- 2 files changed, 28 insertions(+), 35 deletions(-) diff --git a/include/crpropa/PhotonPropagation.h b/include/crpropa/PhotonPropagation.h index b98841e4b..86a15d966 100644 --- a/include/crpropa/PhotonPropagation.h +++ b/include/crpropa/PhotonPropagation.h @@ -6,17 +6,14 @@ namespace crpropa { -void EleCaPropagation(const std::string &inputfile, - const std::string &background, std::vector &energy, - std::vector &spectrum, - double lowerEnergyThreshold = 1E16, - double stepSize = 0.2 - ); + void EleCaPropagation(const std::string &inputfile, const std::string &outputfile, + bool showProgress=true, double lowerEnergyThreshold = 1E16, - double stepSize = 0.2, const std::string &background = "ALL"); + + void DintPropagation(const std::string &inputfile, const std::string &outputfile, int IRFlag = 2, int RadioFlag = 2, double Zmax = 5); diff --git a/src/PhotonPropagation.cpp b/src/PhotonPropagation.cpp index 815d52582..e0c1e380c 100644 --- a/src/PhotonPropagation.cpp +++ b/src/PhotonPropagation.cpp @@ -2,6 +2,7 @@ #include "crpropa/Common.h" #include "crpropa/Units.h" #include "crpropa/Cosmology.h" +#include "crpropa/ProgressBar.h" #include "EleCa/Propagation.h" #include "EleCa/Particle.h" @@ -18,23 +19,25 @@ namespace crpropa { void EleCaPropagation(const std::string &inputfile, - const std::string &background, std::vector &energy, - std::vector &spectrum, - double lowerEnergyThreshold, - double stepSize - ) { + const std::string &outputfile, + bool showProgress, + double lowerEnergyThreshold, + const std::string &background) { + std::ifstream infile(inputfile.c_str()); + std::streampos startPosition = infile.tellg(); + + infile.seekg(0, std::ios::end); + std::streampos endPosition = infile.tellg(); + infile.seekg(startPosition); + - const double emin = log10(lowerEnergyThreshold), emax = 22, step = stepSize; - const size_t steps = (emax - emin) / step; - energy.clear(); - energy.resize(steps); - spectrum.resize(steps); - for (size_t i = 0; i < steps; i++) { - energy[i] = emin + i * step; - spectrum[i] = 0; + ProgressBar progressbar(endPosition); + if (showProgress) { + progressbar.start("Run EleCa propagation"); } + if (!infile.good()) throw std::runtime_error( "EleCaPropagation: could not open file " + inputfile); @@ -45,12 +48,18 @@ void EleCaPropagation(const std::string &inputfile, propagation.ReadTables(getDataPath("EleCa/eleca.dat")); propagation.InitBkgArray(background); + std::ofstream output(outputfile.c_str()); while (infile.good()) { if (infile.peek() != '#') { double E, D, pE, iE; int Id, pId, iId; infile >> Id >> E >> D >> pId >> pE >> iId >> iE; + if (infile) { + + if (showProgress) { + progressbar.setPosition(infile.tellg()); + } double z = eleca::Mpc2z(D); eleca::Particle p0(Id, E * 1e18, z); @@ -72,13 +81,11 @@ void EleCaPropagation(const std::string &inputfile, } } - //propagation.WriteOutput(output, p0, ParticleAtGround); for (int i = 0; i < ParticleAtGround.size(); ++i) { eleca::Particle &p = ParticleAtGround[i]; if (p.GetType() != 22) continue; - size_t idx = (::log10(p.GetEnergy()) - emin) / step; - spectrum.at(idx) += 1; + output << p.GetType() << "\t" << p.GetEnergy() << "\n"; } } } @@ -86,20 +93,9 @@ void EleCaPropagation(const std::string &inputfile, infile.ignore(std::numeric_limits::max(), '\n'); } infile.close(); + output.close(); } -void EleCaPropagation(const std::string &inputfile, - const std::string &outputfile, double lowerEnergyThreshold, - double stepSize, - const std::string &background) { - std::vector energy, spectrum; - EleCaPropagation(inputfile, background, energy, spectrum, lowerEnergyThreshold, stepSize); - std::ofstream output(outputfile.c_str()); - output << "# E N\n"; - for (size_t i = 0; i < energy.size(); i++) { - output << energy[i] << " " << spectrum[i] << "\n"; - } -} typedef struct _Secondary { double E, D; From 8e203904760724bf3ab75bec88ae075fd1df645e Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Wed, 15 Oct 2014 10:15:28 +0200 Subject: [PATCH 0511/1298] Copied Galactic Lenses from PARSEC --- CMakeLists.txt | 40 ++ checkNumpy.py | 8 + libs/GalacticMagneticLens/CMakeLists.txt | 16 + .../include/parsec/MagneticLens.h | 269 +++++++++++ .../include/parsec/ModelMatrix.h | 139 ++++++ .../include/parsec/Pixelization.h | 117 +++++ .../include/parsec/Random.hh | 191 ++++++++ .../include/parsec/shealpix.h | 299 ++++++++++++ .../GalacticMagneticLens/src/MagneticLens.cpp | 272 +++++++++++ libs/GalacticMagneticLens/src/ModelMatrix.cpp | 156 +++++++ libs/GalacticMagneticLens/src/Pixelization.cc | 92 ++++ libs/GalacticMagneticLens/src/Random.cc | 426 ++++++++++++++++++ python/crpropa.i | 105 +++++ test/testMagneticLens.cpp | 73 +++ test/testMagneticLensPythonInterface.py | 72 +++ 15 files changed, 2275 insertions(+) create mode 100644 checkNumpy.py create mode 100644 libs/GalacticMagneticLens/CMakeLists.txt create mode 100644 libs/GalacticMagneticLens/include/parsec/MagneticLens.h create mode 100644 libs/GalacticMagneticLens/include/parsec/ModelMatrix.h create mode 100644 libs/GalacticMagneticLens/include/parsec/Pixelization.h create mode 100644 libs/GalacticMagneticLens/include/parsec/Random.hh create mode 100644 libs/GalacticMagneticLens/include/parsec/shealpix.h create mode 100644 libs/GalacticMagneticLens/src/MagneticLens.cpp create mode 100644 libs/GalacticMagneticLens/src/ModelMatrix.cpp create mode 100644 libs/GalacticMagneticLens/src/Pixelization.cc create mode 100644 libs/GalacticMagneticLens/src/Random.cc create mode 100644 test/testMagneticLens.cpp create mode 100644 test/testMagneticLensPythonInterface.py diff --git a/CMakeLists.txt b/CMakeLists.txt index d84660f2b..e5dd95359 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,26 @@ add_subdirectory(libs/EleCa) list(APPEND CRPROPA_EXTRA_LIBRARIES eleca) list(APPEND CRPROPA_EXTRA_INCLUDES libs/EleCa/include) +# GlacticMagneticLenses +option(ENABLE_GALACTICMAGETICLENS "Galactic Magnetic Lens" ON) +SET(WITH_GALACTIC_LENSES FALSE) +if (ENABLE_GALACTICMAGETICLENS) + FIND_PACKAGE(Boost) + IF(Boost_FOUND) + SET(WITH_GALACTIC_LENSES TRUE) + + list(APPEND CRPROPA_SWIG_DEFINES -DWITH_GALACTIC_LENSES) + list(APPEND CRPROPA_SWIG_DEFINES -I${CMAKE_CURRENT_SOURCE_DIR}/libs/GalacticMagneticLens/include) + + add_subdirectory(libs/GalacticMagneticLens) + list(APPEND CRPROPA_EXTRA_LIBRARIES galacticmagneticlens) + list(APPEND CRPROPA_EXTRA_INCLUDES libs/GalacticMagneticLens/include) + + ELSE(Boost_FOUND) + MESSAGE (STATUS "Cannot find BOOST which is required for GalacticMagneticLenses.") + ENDIF(Boost_FOUND) +endif (ENABLE_GALACTICMAGETICLENS) + # ROOT (optional for ROOT output) option(ENABLE_ROOT "ROOT Output" ON) if(ENABLE_ROOT) @@ -241,6 +261,15 @@ if(ENABLE_TESTING) add_executable(testSource test/testSource.cpp) target_link_libraries(testSource crpropa gtest gtest_main pthread) add_test(testSource testSource) + + if(WITH_GALACTIC_LENSES) + include_directories( + libs/GalacticMagneticLens/include + ) + add_executable(testGalacticMagneticLens test/testMagneticLens.cpp) + target_link_libraries(testGalacticMagneticLens crpropa gtest gtest_main pthread) + add_test(testGalacticMagneticLens testGalacticMagneticLens) + endif(WITH_GALACTIC_LENSES) endif(ENABLE_TESTING) # ---------------------------------------------------------------------------- @@ -252,6 +281,17 @@ if(ENABLE_PYTHON) include(python/Python.cmake) include_directories(${PYTHON_INCLUDE_PATH}) + # tries to import numpy + execute_process(COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/checkNumpy.py" OUTPUT_VARIABLE numpyIncludePath) + if(numpyIncludePath) + MESSAGE(STATUS "Found numpy headers in " ${numpyIncludePath}) + SET(CMAKE_SWIG_FLAGS -DWITHNUMPY ${CRP}) + list(APPEND CRPROPA_SWIG_DEFINES -DWITHNUMPY) + include_directories(${numpyIncludePath}) + else() + MESSAGE(STATUS "Numpy not found.") + endif() + file(GLOB_RECURSE CRPROPA_INCLUDES include/*.h) set_source_files_properties( ${CMAKE_CURRENT_BINARY_DIR}/crpropa_wrap.cxx PROPERTIES GENERATED true ) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/crpropa_wrap.cxx diff --git a/checkNumpy.py b/checkNumpy.py new file mode 100644 index 000000000..590e46676 --- /dev/null +++ b/checkNumpy.py @@ -0,0 +1,8 @@ +#Returns the nupy include path if nupy is available +#Silently exits with -1 otherwise +import sys +try: + import numpy + sys.stdout.write(numpy.get_include()) +except ImportError: + sys.exit(-1) diff --git a/libs/GalacticMagneticLens/CMakeLists.txt b/libs/GalacticMagneticLens/CMakeLists.txt new file mode 100644 index 000000000..579fe2feb --- /dev/null +++ b/libs/GalacticMagneticLens/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 2.6) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${Boost_INCLUDE_DIRS} + ${CMAKE_SOURCE_DIR}/include + ) + +add_library(galacticmagneticlens STATIC + src/MagneticLens.cpp + src/ModelMatrix.cpp + src/Pixelization.cc + src/Random.cc + ) +SET_TARGET_PROPERTIES(galacticmagneticlens PROPERTIES COMPILE_FLAGS -fPIC) + diff --git a/libs/GalacticMagneticLens/include/parsec/MagneticLens.h b/libs/GalacticMagneticLens/include/parsec/MagneticLens.h new file mode 100644 index 000000000..a9941299d --- /dev/null +++ b/libs/GalacticMagneticLens/include/parsec/MagneticLens.h @@ -0,0 +1,269 @@ +//---------------------------------------------------------------------- +// This file is part of PARSEC (http://physik.rwth-aachen.de/parsec) +// a parametrized simulation engine for cosmic rays. +// +// Copyright (C) 2011 Martin Erdmann, Peter Schiffer, Tobias Winchen +// RWTH Aachen University, Germany +// Contact: winchen@physik.rwth-aachen.de +// +// This program is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +//---------------------------------------------------------------------- + +#ifndef MAGNETICLENS_HH +#define MAGNETICLENS_HH + +#include "parsec/ModelMatrix.h" +#include "parsec/Pixelization.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + + +namespace parsec +{ + +/// Holds one matrix for the lens and information about the rigidity range +class LensPart +{ + string _filename; + double _rigidityMin; + double _rigidityMax; + ModelMatrix M; + double _maximumSumOfColumns; + bool _maximumSumOfColumns_calculated; + +public: + LensPart() + { + } + /// File containing the matrix to be used in the range rigidityMin, + /// rigidityMax with logarithmic units [log10(E / eV)] + LensPart(const std::string &filename, double rigidityMin, double rigidityMax) : + _filename(filename), _rigidityMin(rigidityMin), _rigidityMax(rigidityMax), _maximumSumOfColumns_calculated( + false), _maximumSumOfColumns(0) + { + } + + ~LensPart() + { + } + + /// Loads the matrix from file + void loadMatrixFromFile() + { + M.deserialize(_filename); + } + + /// Returns the filename of the matrix + const std::string& getFilename() + { + return _filename; + } + + /// Calculates the maximum of the sums of columns for the matrix + double getMaximumOfSumsOfColumns() + { + if (!_maximumSumOfColumns_calculated) + { // lazy calculation of maximum + _maximumSumOfColumns = M.getMaximumOfSumsOfColumns(); + _maximumSumOfColumns_calculated = true; + } + return _maximumSumOfColumns; + } + + /// Returns the minimum of the rigidity range for the lenspart in [log10(E/ eV)] + double getMinimumRigidity() + { + return _rigidityMin; + } + + /// Returns the maximum of the rigidity range for the lenspart in [log10(E/ eV)] + double getMaximumRigidity() + { + return _rigidityMax; + } + + /// Returns the modelmatrix + ModelMatrix& getMatrix() + { + return M; + } + + /// Sets the modelmatrix + void setMatrix(const ModelMatrix& m) + { + M = m; + } + + +}; + +/// Function to calculate the mean deflection [rad] of the matrix M, given a pixelization +//double calculateMeanDeflection(const ModelMatrix &M, +// const Pixelization &pixelization) +//{ +// double totalDeflection = 0; +// double weightSum = 0; +// for (const_i2_t it1 = M.begin2(); it1 != (M.end2()); it1++) +// { +// for (const_i1_t it2 = it1.begin(); it2 != it1.end(); it2++) +// { +// totalDeflection+= pixelization.angularDistance(it2.index1(), +// it2.index2()) * (*it2) ; +// weightSum+= (*it2); +// } +// } +// return totalDeflection / weightSum; +//} + +typedef std::vector::iterator LensPartIter; +typedef std::vector::const_iterator const_LensPartIter; + +/// The lens for the galactic magnetic field. +/// Note that the energies refer to protons (Z=1). To be used with other particles with a different charge number please select the rigidity accordingly. +class MagneticLens +{ + /// Loads part of a lens (one matrix) from file to use it in given rigidity range. + void loadLensPart(const string &filename, double rigidityMin, + double rigidityMax); + + // Stores the individual lenses + std::vector _lensParts; + Pixelization* _pixelization; + // Checks Matrix, raises Errors if not ok - also generate + // _pixelization if called first time + void _checkMatrix(const ModelMatrix &M); + // minimum / maximum rigidity [log10(E / eV)] that is covered by the lens + double _minimumRigidity; + double _maximumRigidity; + + static bool _randomSeeded; + +public: + /// Default constructor + MagneticLens() : + _pixelization(NULL), _minimumRigidity(-1), _maximumRigidity(-1) + { + } + + /// Constructs lens with predefined healpix order + MagneticLens(uint8_t healpixorder) : + _pixelization(NULL), _minimumRigidity(-1), _maximumRigidity(-1) + { + _pixelization = new Pixelization(healpixorder); + } + + /// Construct lens and load lens from file + MagneticLens(const string &filename) : + _pixelization(NULL), _minimumRigidity(-1), _maximumRigidity(-1) + { + loadLens(filename); + } + + /// Returns the pixelization used + const Pixelization& getPixelization() const + { + return (*_pixelization); + } + + /// Default destructor + ~MagneticLens() + { + if (_pixelization) + delete _pixelization; + for (std::vector::iterator iter = _lensParts.begin(); + iter != _lensParts.end(); iter++) + { + delete (*iter); + } + _lensParts.clear(); + } + + /// Try to transform the comsic ray to a new direction. + /// Returns false and does not change phi and theta if the cosmic ray is + /// lost due to conservation of cosmic ray flux. + /// Rigidity is given in EeV, phi and theta in rad + bool transformCosmicRay(double rigidity, double& phi, double& theta); + + /// transforms the model assuming that model points to an array of the + /// correct size + void transformModelVector(double* model, double rigidity) const; + + /// Loads M as part of a lens and use it in given rigidity range with + /// given in logarithmic units [log10(E / eV)] + void setLensPart(const ModelMatrix &M, double rigidityMin, double rigidityMax); + + /// Loads a lens from a given file, containing lines like + /// lensefile.MLDAT rigidityMin rigidityMax + void loadLens(const string &filename); + + /// Normalizes the lens parts to the maximum of sums of columns of + /// every lenspart. By doing this, the lens won't distort the spectrum + void normalizeLens(); + + /// Normalizes the lens parts individually. Normalized this way, the + /// lens generally distorts the spectrum of the sources, but deflects + /// the UHECR more efficiently. + void normalizeLensparts(); + + /// Checks if rigidity [log10(E / eV)] is covered by lens + bool rigidityCovered(double rigidity) const; + + /// Normalizes all matrix columns - the lens will then create fake + /// anisotropies, but won't drop particles + void normalizeMatrixColumns(); + + /// Returns minimum rigidity covered by lens, in EeV + double getMinimumRigidity() const + { + return pow(10, _minimumRigidity - 18); + } + /// Returns maximum rigidity covered by lens, in EeV + double getMaximumRigidity() const + { + return pow(10, _maximumRigidity - 18); + } + + /// Returns iterator to the lens part with rigidity [log10(E / eV)] + LensPart* getLensPart(double rigidity) const; + + /// Returns all lens parts + const std::vector& getLensParts() const + { + return _lensParts; + } + + //calculates the mean deflection at given rigidity [EeV] + //double getMeanDeflection(double rigidity) const + //{ + // LensPart* lp = getLensPart(log10(rigidity) + 18); + // return calculateMeanDeflection(lp->getMatrix(), *_pixelization); + //} + +}; + + + + + +} // namespace + +#endif // MAGNETICLENS_HH diff --git a/libs/GalacticMagneticLens/include/parsec/ModelMatrix.h b/libs/GalacticMagneticLens/include/parsec/ModelMatrix.h new file mode 100644 index 000000000..4f22ba3b7 --- /dev/null +++ b/libs/GalacticMagneticLens/include/parsec/ModelMatrix.h @@ -0,0 +1,139 @@ +//---------------------------------------------------------------------- +// This file is part of PARSEC (http://physik.rwth-aachen.de/parsec) +// a parametrized simulation engine for cosmic rays. +// +// Copyright (C) 2011 Martin Erdmann, Peter Schiffer, Tobias Winchen +// RWTH Aachen University, Germany +// Contact: winchen@physik.rwth-aachen.de +// +// This program is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +//---------------------------------------------------------------------- + +#ifndef MODELMATRIX_HH +#define MODELMATRIX_HH + +#define BOOST_UBLAS_SHALLOW_ARRAY_ADAPTOR 1 +#include +#include +#include +#include +#include + +//#include "crpropa/Random.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace parsec +{ + +/// ModelMatrixType specifies the used Matrix Type +/// Changes here don't break compability, as matrices are stored in a +/// selfmade format. Compressed_matrix however has been tested as the +/// fastest type +typedef boost::numeric::ublas::compressed_matrix ModelMatrixType; +typedef ModelMatrixType::iterator1 i1_t; +typedef ModelMatrixType::iterator2 i2_t; + +typedef ModelMatrixType::const_iterator1 const_i1_t; +typedef ModelMatrixType::const_iterator2 const_i2_t; + +typedef boost::numeric::ublas::compressed_vector ModelVectorType; +typedef ModelVectorType::iterator MVi_t; + +/// Adaptors for direct array access +typedef boost::numeric::ublas::shallow_array_adaptor shallow_adaptor_double; +typedef boost::numeric::ublas::vector shallow_vector_double; + +/// The class holds a Magnetic Field Model as a Matrix, with m_i,j is +/// the probability that a particle from pixel j reaches pixel i +class ModelMatrix: public ModelMatrixType +{ +public: + ModelMatrix() : + ModelMatrixType() + { + } + + /// Creates a modelmatrix M with size1 x size2 elements as sparse matrix + /// with nnz non-zero elements + ModelMatrix(uint32_t size1, uint32_t size2, uint32_t nnz) : + ModelMatrixType(size1, size2, nnz) + { + } + + /// Writes the ModelMatrix to disk as binary files with the format: + /// Int (number of non zero elements), Int (size1), Int (size2) + /// (Int, Int, Double) : (column, row, value) triples ... + void serialize(const string &filename); + + /// Reads a matrix from file + void deserialize(const string &filename); + + /// Allow construction from matrix + ModelMatrix& operator=(const ModelMatrixType & source) + { + if (this != &source) + { + this->ModelMatrixType::operator=(source); + } + return *this; + } + + /// Normalizes each row m_i, so that \f$ \Vert m_i \Vert_1 = 1 \f$ + /// Needed to ensure that each pixel on earth contains the same amount of backtracked particles. + void normalizeRows(); + + /// Normalizes each column j of the matrix so that, \f$ \Vert m_j \Vert_1 = 1 \f$ + void normalizeColumns(); + + /// Calculate the maximum of the unity norm of the column vectors of the matrix \f$\max_j(\Vert m_j \Vert_1) \f$ + double getMaximumOfSumsOfColumns() const; + + // get sum of column j + double getSumOfColumn(size_t j) const; + + /// Divides matrix by the factor f + void normalizeMatrix(double factor); + + /// Sets element \f$ m_{i,j} \f$ to value + void setElement(size_t i, size_t j, double value) + { + this->ModelMatrixType::operator()(i, j) = value; + } + + /// Returns element \f$ m_{i,j} \f$ + double getElement(size_t i, size_t j) const + { + return this->ModelMatrixType::operator()(i, j); + } + + +}; + + +} // namespace parsec + +#endif // MODELMATRIX_HH diff --git a/libs/GalacticMagneticLens/include/parsec/Pixelization.h b/libs/GalacticMagneticLens/include/parsec/Pixelization.h new file mode 100644 index 000000000..93c77491b --- /dev/null +++ b/libs/GalacticMagneticLens/include/parsec/Pixelization.h @@ -0,0 +1,117 @@ +//---------------------------------------------------------------------- +// This file is part of PARSEC (http://physik.rwth-aachen.de/parsec) +// a parametrized simulation engine for cosmic rays. +// +// Copyright (C) 2011 Martin Erdmann, Peter Schiffer, Tobias Winchen +// RWTH Aachen University, Germany +// Contact: winchen@physik.rwth-aachen.de +// +// This program is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +//---------------------------------------------------------------------- + + +#ifndef PIXELIZATION_HH +#define PIXELIZATION_HH + +#include "parsec/shealpix.h" +#include +#include + +namespace parsec +{ + +/// Helpers to makes work with Healpix smooth +const uint8_t _nOrder_max = 13; +const uint32_t _nPix[] = +{ + 48, + 192, + 768, + 3072, + 12288, + 49152, + 196608, + 786432, + 3145728, + 12582912, + 50331648, + 201326592, + 805306368 +}; + +/// Every communication with healpix is done through this class to avoid +/// bugs with missmatching coordinates (and make python hooks easier) +class Pixelization : private shealpix::sHEALPIX +{ +public: + Pixelization() : shealpix::sHEALPIX( ) + { + } + + /// Constructor creating Pixelization with healpix order 6 (about + /// 50000 pixels) + Pixelization(uint8_t order) : shealpix::sHEALPIX(order) + { + } + + /// Returns the number of the pixel which includes the direction (phi,theta) + /// phi in [-pi, pi], theta in [-pi/2, pi/2] + uint32_t direction2Pix(double longitude, double latitude) const; + + /// Returns the number of pixels of the pixelization + uint32_t nPix() const + { + return Npix(); + } + + /// Returns the number of pixels given by healpix order + static uint32_t nPix(uint8_t order); + + /// Returns the number of pixels of the pixelization + int getNumberOfPixels() + { + return Npix(); + } + + /// Returns the order, a given pixel number corresponds to. 0 if no + /// match! + static uint8_t pix2Order(uint32_t pix); + + /// Gives the center of pixel i in longitude [rad] and latitude [rad] + void pix2Direction(uint32_t i, double &longitude, double &latitude) const; + + /// Calculate the angle [rad] between the vectors pointing to pixels i and j + double angularDistance(uint32_t i, uint32_t j) const; + + /// Returns the maximum possible pixelization order + uint8_t getMaxOrder() const + { + return _nOrder_max; + } + + /// Returns healpix order + uint8_t getOrder() const + { + return Order(); + } + + +private: + void spherCo2Vec(double phi, double theta, shealpix::vec3 &V) const; + void vec2SphereCo(double &phi , double &theta, const shealpix::vec3 &V) const; +}; + + +} // namespace +#endif // PIXELIZATION_HH diff --git a/libs/GalacticMagneticLens/include/parsec/Random.hh b/libs/GalacticMagneticLens/include/parsec/Random.hh new file mode 100644 index 000000000..7d63e9c41 --- /dev/null +++ b/libs/GalacticMagneticLens/include/parsec/Random.hh @@ -0,0 +1,191 @@ +// Random.h +// Mersenne Twister random number generator -- a C++ class Random +// Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus +// Richard J. Wagner v1.0 15 May 2003 rjwagner@writeme.com + +// The Mersenne Twister is an algorithm for generating random numbers. It +// was designed with consideration of the flaws in various other generators. +// The period, 2^19937-1, and the order of equidistribution, 623 dimensions, +// are far greater. The generator is also fast; it avoids multiplication and +// division, and it benefits from caches and pipelines. For more information +// see the inventors' web page at http://www.math.keio.ac.jp/~matumoto/emt.html + +// Reference +// M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally +// Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on +// Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30. + +// Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, +// Copyright (C) 2000 - 2003, Richard J. Wagner +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The names of its contributors may not be used to endorse or promote +// products derived from this software without specific prior written +// permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// The original code included the following notice: +// +// When you use this, send an email to: matumoto@math.keio.ac.jp +// with an appropriate reference to your work. +// +// It would be nice to CC: rjwagner@writeme.com and Cokus@math.washington.edu +// when you write. + +// Parts of this file are modified beginning in 29.10.09 for adaption in +// PXL. + + +#ifndef PXL_BASE_RANDOM_HH +#define PXL_BASE_RANDOM_HH + +// Not thread safe (unless auto-initialization is avoided and each thread has +// its own Random object) +#include +#include +#include +#include + +//necessary for win32 +#ifndef M_PI + #define M_PI 3.14159265358979323846 +#endif + +#include + +namespace parsec{ + +class Random{ +public: +#ifndef uint32 + typedef unsigned long uint32; // unsigned integer type, at least 32 bits +#endif + enum { N = 624 }; // length of state vector + enum { SAVE = N + 1 }; // length of array for save() + +protected: + enum { M = 397 }; // period parameter + uint32 state[N]; // internal state + uint32 *pNext; // next value to get from state + int left; // number of values left before reload needed + + +//Methods +public: + /// initialize with a simple uint32 + Random( const uint32& oneSeed ); + // initialize with an array + Random( uint32 *const bigSeed, uint32 const seedLength = N ); + /// auto-initialize with /dev/urandom or time() and clock() + /// Do NOT use for CRYPTOGRAPHY without securely hashing several returned + /// values together, otherwise the generator state can be learned after + /// reading 624 consecutive values. + Random(); + // Access to 32-bit random numbers + double rand(); ///< real number in [0,1] + double rand( const double& n ); ///< real number in [0,n] + double randExc(); ///< real number in [0,1) + double randExc( const double& n ); ///< real number in [0,n) + double randDblExc(); ///< real number in (0,1) + double randDblExc( const double& n ); ///< real number in (0,n) + /// Pull a 32-bit integer from the generator state + /// Every other access function simply transforms the numbers extracted here + uint32 randInt(); ///< integer in [0,2^32-1] + uint32 randInt( const uint32& n ); ///< integer in [0,n] for n < 2^32 + double operator()() { return rand(); } ///< same as rand() + + /// Access to 53-bit random numbers (capacity of IEEE double precision) + double rand53(); // real number in [0,1) + ///Exponential distribution in (0,inf) + double randExponential(); + /// Normal distributed random number + double randNorm( const double& mean = 0.0, const double& variance = 1.0 ); + /// Uniform distribution in [min, max] + double randUniform(double min, double max); + /// Rayleigh distributed random number + double randRayleigh(double sigma); + /// Fisher distributed random number + double randFisher(double k); + + /// Power-Law distribution, not possible for index == -1 + double randPowerLaw(double index, double min, double max) ; + /// Broken power-law distribution + double randBrokenPowerLaw(double index1, double index2, double breakpoint, double min, double max ) ; + + /// Seed the generator with a simple uint32 + void seed( const uint32 oneSeed ); + /// Seed the generator with an array of uint32's + /// There are 2^19937-1 possible initial states. This function allows + /// all of those to be accessed by providing at least 19937 bits (with a + /// default seed length of N = 624 uint32's). Any bits above the lower 32 + /// in each element are discarded. + /// Just call seed() if you want to get array from /dev/urandom + void seed( uint32 *const bigSeed, const uint32 seedLength = N ); + /// Seed the generator with an array from /dev/urandom if available + /// Otherwise use a hash of time() and clock() values + void seed(); + + // Saving and loading generator state + void save( uint32* saveArray ) const; // to array of size SAVE + void load( uint32 *const loadArray ); // from such array + friend std::ostream& operator<<( std::ostream& os, const Random& mtrand ); + friend std::istream& operator>>( std::istream& is, Random& mtrand ); + + static Random &instance(); +protected: + /// Initialize generator state with seed + /// See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier. + /// In previous versions, most significant bits (MSBs) of the seed affect + /// only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto. + void initialize( const uint32 oneSeed ); + + /// Generate N new values in state + /// Made clearer and faster by Matthew Bellew (matthew.bellew@home.com) + void reload(); + uint32 hiBit( const uint32& u ) const { return u & 0x80000000UL; } + uint32 loBit( const uint32& u ) const { return u & 0x00000001UL; } + uint32 loBits( const uint32& u ) const { return u & 0x7fffffffUL; } + uint32 mixBits( const uint32& u, const uint32& v ) const + { return hiBit(u) | loBits(v); } + +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning( disable : 4146 ) +#endif + uint32 twist( const uint32& m, const uint32& s0, const uint32& s1 ) const + { return m ^ (mixBits(s0,s1)>>1) ^ (-loBit(s1) & 0x9908b0dfUL); } + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + + /// Get a uint32 from t and c + /// Better than uint32(x) in case x is floating point in [0,1] + /// Based on code by Lawrence Kirby (fred@genesis.demon.co.uk) + static uint32 hash( time_t t, clock_t c ); +}; +} //namespace pxl +#endif // PXL_BASE_RANDOM_HH + diff --git a/libs/GalacticMagneticLens/include/parsec/shealpix.h b/libs/GalacticMagneticLens/include/parsec/shealpix.h new file mode 100644 index 000000000..e116725de --- /dev/null +++ b/libs/GalacticMagneticLens/include/parsec/shealpix.h @@ -0,0 +1,299 @@ +// shealpix.h, 12.04.10 by Tobias Winchen, +// +// This defines the class sHEALPIX (small HEALPIX) which provides a very +// basic Hierarchical Equal Area isoLatitude Pixelization (HEALPIX) of a +// sphere like http://healpix.jpl.nasa.gov (on which it is based). +// sHEALPIX so far only provides for pixelizations in the RING scheme: +// - assoziation of a dircetion (theta, phi) with the pixel number +// - vice versa +// +// shealpix tries to be compatible to bhealpix_base +// +// sHEALPIX is published unter the GNU GPL v3 as it is based on HEALPIX +// which is published under the GNU GPL v2. +// +// sHEALPIX is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// sHEALPIX is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with sHEALPIX; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// + +#ifndef SHEALPIX_HH +#define SHEALPIX_HH + +#include +#include + +#include + + +namespace shealpix +{ + +/*! Class representing a 3D cartesian vector in healpix, copied from + * vec3.h. */ +class vec3 +{ +public: + double x; /*!< x-coordinate */ + double y; /*!< y-coordinate */ + double z; /*!< z-coordinate */ + + /*! Default constructor. Does not initialize \a x, \a y, and \a z. */ + vec3 () {} + /*! Creates a vector with the coordinates \a xc, \a yc, and \a zc. */ + vec3 (double xc, double yc, double zc) : x(xc), y(yc), z(zc) {} + + /*! Creates a unit vector from a z coordinate and an azimuthal angle. */ + void set_z_phi (double z_, double phi) + { + using namespace std; + double sintheta = sqrt((1.-z_)*(1.+z_)); + x = sintheta*cos(phi); + y = sintheta*sin(phi); + z = z_; + } + +/*! Normalizes the vector to length 1. */ + void Normalize () + { + using namespace std; + double l = 1.0/sqrt (x*x + y*y + z*z); + x*=l; y*=l; z*=l; + } + + /*! Returns the length of the vector. */ + double Length () const + { return sqrt (x*x + y*y + z*z); } + + /*! Returns the squared length of the vector. */ + double SquaredLength () const + { return (x*x + y*y + z*z); } + /*! Returns the vector with the signs of all coordinates flipped. */ + const vec3 operator- () const + { return vec3 (-x, -y, -z); } + /*! Flips the signs of all coordinates. */ + void Flip () + { x=-x; y=-y; z=-z; } + /*! Subtracts \a vec from the vector. */ + const vec3 operator- (const vec3 &vec) const + { return vec3 (x-vec.x, y-vec.y, z-vec.z); } + /*! Adds \a vec to the vector. */ + const vec3 operator+ (const vec3 &vec) const + { return vec3 (x+vec.x, y+vec.y, z+vec.z); } + /*! Returns the vector scaled by \a fact. */ + const vec3 operator* (double fact) const + { return vec3 (x*fact, y*fact, z*fact); } + /*! Returns the vector scaled by \a 1/fact. */ + const vec3 operator/ (double fact) const + { double xfact = 1./fact; return vec3 (x*xfact, y*xfact, z*xfact); } + /*! Scales the vector by \a fact. */ + vec3 &operator*= (double fact) + { x*=fact; y*=fact; z*=fact; return *this; } +}; + +/*! Returns the dot product of \a v1 and \a v2. + \relates vec3 */ +inline double dotprod(const vec3 &v1, const vec3 &v2) + { return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; } + +/*! Returns the cross product of \a a and \a b. + \relates vec3 */ +inline vec3 crossprod(const vec3 &a, const vec3 &b) + { return vec3 (a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x); } + +/*! Writes \a v to \a os. + \relates vec3 */ +inline std::ostream &operator<< (std::ostream &os, const vec3 &v) + { + os << v.x << ", " << v.y << ", " << v.z << std::endl; + return os; + } + + + + + + + + +class sHEALPIX +{ + + public: + + sHEALPIX( ) : _order(0), _npix(0), _ncap(0), _nside(0), _npface(0), _fact1(0), _fact2(0) + { + } + + sHEALPIX(int order) + { + _order = order; + // copied from healpix_base.h + _nside = 1<<_order; // _nside = 2**order + _npface = _nside << _order; // _nside * 2**order == nside**2 + _ncap = (_npface-_nside)<<1; //(nside**2-nside) * 2**1 + _npix = 12*_npface; + _fact2 = 4./_npix; + _fact1 = (_nside<<1)*_fact2; // 2*nside * fact2 + } + + void pix2ang_z_phi (int pix, double &z, double &phi) const + { + if (pix<_ncap) // North Polar cap + { + int iring = int(0.5*(1+isqrt(1+2*pix))); //counted from North pole + int iphi = (pix+1) - 2*iring*(iring-1); + + z = 1.0 - (iring*iring)*_fact2; + phi = (iphi-0.5) * M_PI/2/iring; + } + else if (pix<(_npix-_ncap)) // Equatorial region + { + int ip = pix - _ncap; + int iring = ip/(4*_nside) + _nside; // counted from North pole + int iphi = ip%(4*_nside) + 1; + // 1 if iring+nside is odd, 1/2 otherwise + double fodd = ((iring+_nside)&1) ? 1 : 0.5; + + int nl2 = 2*_nside; + z = (nl2-iring)*_fact1; + phi = (iphi-fodd) * M_PI/nl2; + } + else // South Polar cap + { + int ip = _npix - pix; + int iring = int(0.5*(1+isqrt(2*ip-1))); //counted from South pole + int iphi = 4*iring + 1 - (ip - 2*iring*(iring-1)); + + z = -1.0 + (iring*iring)*_fact2; + phi = (iphi-0.5) * M_PI/2/iring; + } + } + + int Order() const + { + return _order; + } + + int Npix() const + { + return _npix; + } + + + int ang2pix_z_phi (double z, double phi) const + { + double za = std::fabs(z); + double tt = fmodulo(phi,2*M_PI) * 2/M_PI; // in [0,4) + + if (za<=2./3.) // Equatorial region + { + double temp1 = _nside*(0.5+tt); + double temp2 = _nside*z*0.75; + int jp = int(temp1-temp2); // index of ascending edge line + int jm = int(temp1+temp2); // index of descending edge line + + // ring number counted from z=2/3 + int ir = _nside+ 1 + jp - jm; // in {1,2n+1} + int kshift = 1-(ir&1); // kshift=1 if ir even, 0 otherwise + + int ip = (jp+jm- _nside+kshift+1)/2; // in {0,4n-1} + ip = imodulo(ip,4* _nside); + + return _ncap + (ir-1)*4* _nside+ ip; + } + else // North & South polar caps + { + double tp = tt-int(tt); + double tmp = _nside*sqrt(3*(1-za)); + + int jp = int(tp*tmp); // increasing edge line index + int jm = int((1.0-tp)*tmp); // decreasing edge line index + + int ir = jp+jm+1; // ring number counted from the closest pole + int ip = int(tt*ir); // in {0,4*ir-1} + ip = imodulo(ip,4*ir); + + if (z>0) + { + return 2*ir*(ir-1) + ip; + } + else + { + return _npix - 2*ir*(ir+1) + ip; + } + } + + } + + vec3 pix2vec (int pix) const + { + double z, phi; + pix2ang_z_phi (pix,z,phi); + vec3 res; + res.set_z_phi (z, phi); + return res; + } + + int vec2pix (const vec3 &vec) const + { return ang2pix_z_phi (vec.z/vec.Length(), safe_atan2(vec.y,vec.x)); } + + + private: + int _order; // The Healpix Order (Sometimes refered to as _NSide) + int _npix; // The number of pixels + int _ncap; + int _nside; + int _npface; + double _fact1; + double _fact2; + + // Returns the remainder of the division \a v1/v2. + // The result is non-negative. + // \a v1 can be positive or negative; \a v2 must be positive. + // FROM HEALPIX, cxxsupport/cxxutils.h + inline double fmodulo (double v1, double v2) const + { + return (v1>=0) ? ((v1 inline I imodulo (I v1, I v2) const + { return (v1>=0) ? ((v1 inline unsigned int isqrt (I arg) const + { + using namespace std; + if (sizeof(I)<=4) + return unsigned (sqrt(arg+0.5)); + long double arg2 = arg; + return unsigned (sqrt(arg2+0.5)); + } + protected: + //! Returns \a atan2(y,x) if \a x!=0 or \a y!=0; else returns 0. + inline double safe_atan2 (double y, double x) const + { + using namespace std; + return ((x==0.) && (y==0.)) ? 0.0 : atan2(y,x); + } + +}; + +} // namespace sHEALPIX + +#endif // SHEALPIX_HH diff --git a/libs/GalacticMagneticLens/src/MagneticLens.cpp b/libs/GalacticMagneticLens/src/MagneticLens.cpp new file mode 100644 index 000000000..ab8bbc56c --- /dev/null +++ b/libs/GalacticMagneticLens/src/MagneticLens.cpp @@ -0,0 +1,272 @@ +//---------------------------------------------------------------------- +// This file is part of PARSEC (http://physik.rwth-aachen.de/parsec) +// a parametrized simulation engine for cosmic rays. +// +// Copyright (C) 2011 Martin Erdmann, Peter Schiffer, Tobias Winchen +// RWTH Aachen University, Germany +// Contact: winchen@physik.rwth-aachen.de +// +// This program is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +//---------------------------------------------------------------------- + +#include "parsec/MagneticLens.h" + +#include "parsec/Random.hh" +// needed for memcpy in gcc 4.3.2 +#include + +namespace parsec +{ + +void MagneticLens::loadLens(const string &filename) +{ + ifstream infile(filename.c_str()); + if (!infile) + { + throw std::runtime_error("Can't read file: " + filename); + } + string line; + + string prefix; + int sp = filename.find_last_of("/"); + if (sp >= 0) + { + prefix = filename.substr(0, sp); + prefix.append("/"); + } + string mfdatfile; + double emin, emax; + + while (!infile.eof()) + { + getline(infile, line); + if (line.find('#') == string::npos) + { + stringstream ss; + ss << line; + ss >> mfdatfile >> emin >> emax; + if (ss.fail()) + { + cerr << " ERROR READING LINE:\n " << line + << " ... line skipped!" << endl; + } + else + { + this->loadLensPart(prefix + mfdatfile, emin, emax); + } + } + } +} + +bool MagneticLens::transformCosmicRay(double rigidity, double& phi, + double& theta) +{ + uint32_t c = _pixelization->direction2Pix(phi, theta); + LensPart *lenspart = getLensPart(log10(rigidity) + 18); + if (!lenspart) + { + throw std::runtime_error("Rigidity not covered by lens"); + } + + ModelVectorType v; + v = column(lenspart->getMatrix(), c); + + uint32_t r; + + // the random number to compare with + double rn = Random::instance().rand(); + + MVi_t i = v.begin(); + double cpv = 0; + while (i != v.end()) + { + cpv += *i; + if (rn < cpv) + { + _pixelization->pix2Direction(i.index(), phi, theta); + return true; + } + else + { + ++i; + } + } + return false; +} + + +void MagneticLens::loadLensPart(const string &filename, double rigidityMin, + double rigidityMax) +{ + if (rigidityMin >= rigidityMax) + { + throw std::runtime_error("rigidityMin >= rigidityMax"); + } + if (_minimumRigidity < 0 || rigidityMin < _minimumRigidity) + { + _minimumRigidity = rigidityMin; + } + + if (_maximumRigidity < rigidityMin) + { + _maximumRigidity = rigidityMax; + } + + LensPart *p = new LensPart(filename, rigidityMin, rigidityMax); + p->loadMatrixFromFile(); + _checkMatrix(p->getMatrix()); + + _lensParts.push_back(p); +} + +void MagneticLens::_checkMatrix(const ModelMatrix &M) +{ + if (M.size1() != M.size2()) + { + throw std::runtime_error("Not a square Matrix!"); + } + + if (_pixelization) + { + if (_pixelization->nPix() != M.size1()) + { + std::cerr << "*** ERROR ***" << endl; + std::cerr << " Pixelization: " << _pixelization->nPix() << endl; + std::cerr << " Matrix Size : " << M.size1() << endl; + throw std::runtime_error("Matrix doesn't fit into Lense"); + } + } + else + { + uint32_t morder = Pixelization::pix2Order(M.size1()); + if (morder == 0) + { + throw std::runtime_error( + "Matrix size doesn't match healpix scheme!"); + } + _pixelization = new Pixelization(morder); + } +} + +void MagneticLens::setLensPart(const ModelMatrix &M, double rigidityMin, + double rigidityMax) +{ + LensPart *p = new LensPart("Direct Input", rigidityMin, rigidityMax); + if (rigidityMin >= rigidityMax) + { + throw std::runtime_error("rigidityMin >= rigidityMax"); + } + + p->setMatrix(M); + + _checkMatrix(p->getMatrix()); + _lensParts.push_back(p); +} + +LensPart* MagneticLens::getLensPart(double rigidity) const +{ + const_LensPartIter i = _lensParts.begin(); + while (i != _lensParts.end()) + { + if (((*i)->getMinimumRigidity() < rigidity) + && ((*i)->getMaximumRigidity() >= rigidity)) + { + return (*i); + } + ++i; + } + return NULL; +} + +bool MagneticLens::rigidityCovered(double rigidity) const +{ + if (getLensPart(rigidity)) + return true; + else + return false; +} + + +void MagneticLens::normalizeMatrixColumns() +{ + for (LensPartIter iter = _lensParts.begin(); iter != _lensParts.end(); + ++iter) + { + (*iter)->getMatrix().normalizeColumns(); + } +} + + +void MagneticLens::normalizeLens() +{ + // get maximum of sums of columns, and normalize each matrix to that + double norm = 0; + for (LensPartIter iter = _lensParts.begin(); iter != _lensParts.end(); + ++iter) + { + if ((*iter)->getMaximumOfSumsOfColumns() > norm) + { + norm = (*iter)->getMaximumOfSumsOfColumns(); + } + } + for (LensPartIter iter = _lensParts.begin(); iter != _lensParts.end(); + ++iter) + { + (*iter)->getMatrix().normalizeMatrix(norm); + } +} + +void MagneticLens::normalizeLensparts() +{ + double norm; + for (LensPartIter iter = _lensParts.begin(); iter != _lensParts.end(); + ++iter) + { + norm = (*iter)->getMaximumOfSumsOfColumns(); + (*iter)->getMatrix().normalizeMatrix(norm); + } +} + +void MagneticLens::transformModelVector(double* model, double rigidity) const +{ + LensPart* lenspart = (getLensPart(log10(rigidity)+18)); + + + size_t lensSize = _pixelization->nPix(); + + // copy storage of model, as matrix vector product cannot be done + // in place + double *origVectorStorage = new double[lensSize]; + memcpy(origVectorStorage, model, lensSize * sizeof(double)); + + // create shallow adapters, to access original data backup and model + // vector data with ublas + shallow_adaptor_double origVectorStorageAdaptor(lensSize, origVectorStorage); + shallow_adaptor_double modelVectorAdaptor(lensSize, model); + + // create the ublas vector "views: + shallow_vector_double origVector(lensSize, origVectorStorageAdaptor); + shallow_vector_double modelVector(lensSize, modelVectorAdaptor); + + // perform the optimized product + boost::numeric::ublas::axpy_prod(lenspart->getMatrix(), origVector, modelVector, true); + + // clean up + delete origVectorStorage; +} + + + +} // namespace parsec + diff --git a/libs/GalacticMagneticLens/src/ModelMatrix.cpp b/libs/GalacticMagneticLens/src/ModelMatrix.cpp new file mode 100644 index 000000000..2d8167e84 --- /dev/null +++ b/libs/GalacticMagneticLens/src/ModelMatrix.cpp @@ -0,0 +1,156 @@ +//---------------------------------------------------------------------- +// This file is part of PARSEC (http://physik.rwth-aachen.de/parsec) +// a parametrized simulation engine for cosmic rays. +// +// Copyright (C) 2011 Martin Erdmann, Peter Schiffer, Tobias Winchen +// RWTH Aachen University, Germany +// Contact: winchen@physik.rwth-aachen.de +// +// This program is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +//---------------------------------------------------------------------- + +#include "parsec/ModelMatrix.h" +#include +namespace parsec +{ + +void ModelMatrix::serialize(const string &filename) +{ + ofstream outfile(filename.c_str(), ios::binary); + if (!outfile) + { + throw runtime_error("Can't write file: " + filename); + } + uint32_t nnz = 0; + uint32_t C = 0; + double val; + + // first write dummy and jump back later + outfile.write((char*) &nnz, sizeof(uint32_t)); + C = (uint32_t) (this->size1()); + outfile.write((char*) &C, sizeof(uint32_t)); + C = (uint32_t) (this->size2()); + outfile.write((char*) &C, sizeof(uint32_t)); + + // serialize non zero elements + for (i2_t i2 = this->begin2(); i2 != this->end2(); ++i2) + { + for (i1_t i1 = i2.begin(); i1 != i2.end(); ++i1) + { + val = *i1; + if (val > DBL_EPSILON) + { + C = (uint32_t) i1.index1(); + outfile.write((char*) &C, sizeof(uint32_t)); + C = (uint32_t) i1.index2(); + outfile.write((char*) &C, sizeof(uint32_t)); + outfile.write((char*) &val, sizeof(val)); + nnz++; + if (outfile.fail()) + { + throw runtime_error("Error writing file: " + filename); + } + } + } + } + // jump back and write nnz + outfile.seekp(0); + outfile.write((char*) &nnz, sizeof(uint32_t)); + if (!outfile) + { + throw runtime_error("Error writing file: " + filename); + } + outfile.close(); +} + +void ModelMatrix::deserialize(const string &filename) +{ + ifstream infile(filename.c_str(), ios::binary); + if (!infile) + { + throw runtime_error("Can't read file: " + filename); + } + + uint32_t nnz, size1, size2; + double val; + infile.read((char*) &nnz, sizeof(uint32_t)); + infile.read((char*) &size1, sizeof(uint32_t)); + infile.read((char*) &size2, sizeof(uint32_t)); + boost::numeric::ublas::compressed_matrix M(size1, size2, nnz); + + for (size_t i = 0; i < nnz; i++) + { + infile.read((char*) &size1, sizeof(uint32_t)); + infile.read((char*) &size2, sizeof(uint32_t)); + infile.read((char*) &val, sizeof(double)); + //M(size1,size2) = val; + M.push_back(size1, size2, val); + } + this->ModelMatrixType::operator=(M); +} + +void ModelMatrix::normalizeRows() +{ + boost::numeric::ublas::diagonal_matrix A(this->size1(), this->size2()); + double rn; + for (size_t i = 0; i < this->size1(); i++) + { + rn = norm_1(row((*this), i)); + A(i, i) = 1 / rn; + } + *this = prod(A, (*this)); +} + +void ModelMatrix::normalizeColumns(){ + boost::numeric::ublas::diagonal_matrix A(this->size1(),this->size2()); + double rn; + ModelVectorType v; + for (size_t i=0;isize1();i++) + { + v = column(*this,i); + rn = norm_1(v); + v/=rn; + } +} + +double ModelMatrix::getSumOfColumn(size_t j) const +{ + ModelVectorType v; + v = column(*this, j); + double sum = norm_1(v); + return sum; +} + + +double ModelMatrix::getMaximumOfSumsOfColumns() const +{ + double summax = 0; + double sum = 0; + for (size_t i = 0; i < this->size2(); i++) + { + sum = getSumOfColumn(i); + if (sum > summax) + summax = sum; + } + return summax; +} + +void ModelMatrix::normalizeMatrix(double factor) +{ + *this /= factor; +} + +} // namespace parsec diff --git a/libs/GalacticMagneticLens/src/Pixelization.cc b/libs/GalacticMagneticLens/src/Pixelization.cc new file mode 100644 index 000000000..1fa42ee89 --- /dev/null +++ b/libs/GalacticMagneticLens/src/Pixelization.cc @@ -0,0 +1,92 @@ +//---------------------------------------------------------------------- +// This file is part of PARSEC (http://physik.rwth-aachen.de/parsec) +// a parametrized simulation engine for cosmic rays. +// +// Copyright (C) 2011 Martin Erdmann, Peter Schiffer, Tobias Winchen +// RWTH Aachen University, Germany +// Contact: winchen@physik.rwth-aachen.de +// +// This program is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +//---------------------------------------------------------------------- + +#include "parsec/Pixelization.h" + +namespace parsec +{ + +uint8_t Pixelization::pix2Order(uint32_t pix) +{ + for (uint8_t i = 0; i < _nOrder_max; i++) + { + if (pix == _nPix[i]) + return i + 1; + } + return 0; +} + +uint32_t Pixelization::nPix(uint8_t order) +{ + if (order > _nOrder_max) + { + return 0; + } + else + { + return _nPix[order - 1]; + } +} + +uint32_t Pixelization::direction2Pix(double longitude, double latitude) const +{ + shealpix::vec3 v; + spherCo2Vec(longitude, latitude, v); + uint32_t i = (uint32_t) vec2pix(v); + return i; +} + +void Pixelization::pix2Direction(uint32_t i, double &longitude, + double &latitude) const +{ + shealpix::vec3 v; + v = pix2vec(i); + vec2SphereCo(longitude, latitude, v); +} + +void Pixelization::spherCo2Vec(double phi, double theta, + shealpix::vec3 &V) const +{ + V.x = cos(phi) * cos(theta); + V.y = sin(phi) * cos(theta); + V.z = sin(theta); +} + +void Pixelization::vec2SphereCo(double &phi, double &theta, + const shealpix::vec3 &V) const +{ + theta = asin(V.z); + phi = safe_atan2(V.y, V.x); +} + + +double Pixelization::angularDistance(uint32_t i, uint32_t j) const +{ + shealpix::vec3 v1, v2; + v1 = pix2vec(i); + v2 = pix2vec(j); + double s = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; + // Failsafe for numerical inaccuracies + return ((s > 1) ? 0 : ((s < -1) ? M_PI : acos(s))); +} + +} // namespace diff --git a/libs/GalacticMagneticLens/src/Random.cc b/libs/GalacticMagneticLens/src/Random.cc new file mode 100644 index 000000000..dbb3915b3 --- /dev/null +++ b/libs/GalacticMagneticLens/src/Random.cc @@ -0,0 +1,426 @@ +// Random.cc is based on Random.h +// Mersenne Twister random number generator -- a C++ class Random +// Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus +// Richard J. Wagner v1.0 15 May 2003 rjwagner@writeme.com + +// The Mersenne Twister is an algorithm for generating random numbers. It +// was designed with consideration of the flaws in various other generators. +// The period, 2^19937-1, and the order of equidistribution, 623 dimensions, +// are far greater. The generator is also fast; it avoids multiplication and +// division, and it benefits from caches and pipelines. For more information +// see the inventors' web page at http://www.math.keio.ac.jp/~matumoto/emt.html + +// Reference +// M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally +// Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on +// Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30. + +// Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, +// Copyright (C) 2000 - 2003, Richard J. Wagner +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The names of its contributors may not be used to endorse or promote +// products derived from this software without specific prior written +// permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// The original code included the following notice: +// +// When you use this, send an email to: matumoto@math.keio.ac.jp +// with an appropriate reference to your work. +// +// It would be nice to CC: rjwagner@writeme.com and Cokus@math.washington.edu +// when you write. + +// Parts of this file are modified beginning in 29.10.09 for adaption in +// PXL. + +#include "parsec/Random.hh" +#include +#include + +namespace parsec +{ + +Random::Random(const uint32& oneSeed) +{ + seed(oneSeed); +} + +Random::Random(uint32 * const bigSeed, const uint32 seedLength) +{ + seed(bigSeed, seedLength); +} + +Random::Random() +{ + seed(); +} + +double Random::rand() +{ + return double(randInt()) * (1.0 / 4294967295.0); +} + +double Random::rand(const double& n) +{ + return rand() * n; +} + +double Random::randExc() +{ + return double(randInt()) * (1.0 / 4294967296.0); +} + +double Random::randExc(const double& n) +{ + return randExc() * n; +} + +double Random::randDblExc() +{ + return (double(randInt()) + 0.5) * (1.0 / 4294967296.0); +} + +double Random::randDblExc(const double& n) +{ + return randDblExc() * n; +} + +double Random::rand53() +{ + uint32 a = randInt() >> 5, b = randInt() >> 6; + return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0); // by Isaku Wada +} + +double Random::randNorm(const double& mean, const double& variance) +{ + // Return a real number from a normal (Gaussian) distribution with given + // mean and variance by Box-Muller method + double r = sqrt(-2.0 * log(1.0 - randDblExc())) * variance; + double phi = 2.0 * 3.14159265358979323846264338328 * randExc(); + return mean + r * cos(phi); +} + +double Random::randUniform(double min, double max) +{ + return min + (max - min) * this->rand(); +} + +///returns a rayleigh distributed value +double Random::randRayleigh(double sigma) +{ + return sigma * sqrt(-2.0 * log(1 - this->rand())); +} + +double Random::randFisher(double k) +{ + return acos(1. + 1. / k * log(1 - rand() * (1 - exp(-2 * k)))); +} + +double Random::randPowerLaw(double index, double min, double max) +{ + if ((min <= 0) || (max < min)) + { + throw std::runtime_error( + "Power law distribution only possible for 0 < min <= max"); + } + // index = -1 + if ((std::abs(index + 1.0)) < DBL_EPSILON) + { + double part1 = log(max); + double part2 = log(min); + return exp((part1 - part2) * this->rand() + part2); + } + else + { + double part1 = pow(max, index + 1); + double part2 = pow(min, index + 1); + double ex = 1 / (index + 1); + return pow((part1 - part2) * this->rand() + part2, ex); + } +} + +double Random::randBrokenPowerLaw(double index1, double index2, + double breakpoint, double min, double max) +{ + if ((min <= 0) || (max < min)) + { + throw std::runtime_error( + "Power law distribution only possible for 0 < min <= max"); + } + if (min >= breakpoint) + { + return this->randPowerLaw(index2, min, max); + } + else if (max <= breakpoint) + { + return this->randPowerLaw(index2, min, max); + } + else + { + double intPL1; + // check if index1 = -1 + if ((std::abs(index1 + 1.0)) < DBL_EPSILON) + { + intPL1 = log(breakpoint / min); + } + else + { + intPL1 = (pow(breakpoint, index1 + 1) - pow(min, index1 + 1)) + / (index1 + 1); + } + double intPL2; + // check if index2 = -1 + if ((std::abs(index2 + 1.0)) < DBL_EPSILON) + { + intPL2 = log(max / breakpoint) * pow(breakpoint, index1 - index2); + } + else + { + intPL2 = (pow(max, index2 + 1) - pow(breakpoint, index2 + 1)) + * pow(breakpoint, index1 - index2) / (index2 + 1); + } + if (this->rand() > intPL1 / (intPL1 + intPL2)) + return this->randPowerLaw(index2, breakpoint, max); + else + return this->randPowerLaw(index1, min, breakpoint); + } +} + +double Random::randExponential() +{ + double dum; + do + { + dum = this->rand(); + } while (dum < DBL_EPSILON); + return -1.0 * log(dum); +} + +Random::uint32 Random::randInt() +{ + + if (left == 0) + reload(); + --left; + + register uint32 s1; + s1 = *pNext++; + s1 ^= (s1 >> 11); + s1 ^= (s1 << 7) & 0x9d2c5680UL; + s1 ^= (s1 << 15) & 0xefc60000UL; + return (s1 ^ (s1 >> 18)); +} + +Random::uint32 Random::randInt(const uint32& n) +{ + // Find which bits are used in n + // Optimized by Magnus Jonsson (magnus@smartelectronix.com) + uint32 used = n; + used |= used >> 1; + used |= used >> 2; + used |= used >> 4; + used |= used >> 8; + used |= used >> 16; + + // Draw numbers until one is found in [0,n] + uint32 i; + do + i = randInt() & used; // toss unused bits to shorten search + while (i > n); + return i; +} + +void Random::seed(const uint32 oneSeed) +{ + initialize(oneSeed); + reload(); +} + +void Random::seed(uint32 * const bigSeed, const uint32 seedLength) +{ + initialize(19650218UL); + register int i = 1; + register uint32 j = 0; + register int k = (N > seedLength ? N : seedLength); + for (; k; --k) + { + state[i] = state[i] + ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1664525UL); + state[i] += (bigSeed[j] & 0xffffffffUL) + j; + state[i] &= 0xffffffffUL; + ++i; + ++j; + if (i >= N) + { + state[0] = state[N - 1]; + i = 1; + } + if (j >= seedLength) + j = 0; + } + for (k = N - 1; k; --k) + { + state[i] = state[i] + ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941UL); + state[i] -= i; + state[i] &= 0xffffffffUL; + ++i; + if (i >= N) + { + state[0] = state[N - 1]; + i = 1; + } + } + state[0] = 0x80000000UL; // MSB is 1, assuring non-zero initial array + reload(); +} + +void Random::seed() +{ + + // First try getting an array from /dev/urandom + FILE* urandom = fopen("/dev/urandom", "rb"); + if (urandom) + { + uint32 bigSeed[N]; + register uint32 *s = bigSeed; + register int i = N; + register bool success = true; + while (success && i--) + success = fread(s++, sizeof(uint32), 1, urandom) != 0; + fclose(urandom); + if (success) + { + seed(bigSeed, N); + return; + } + } + + // Was not successful, so use time() and clock() instead + seed(hash(time(NULL), clock())); +} + +void Random::initialize(const uint32 seed) +{ + register uint32 *s = state; + register uint32 *r = state; + register int i = 1; + *s++ = seed & 0xffffffffUL; + for (; i < N; ++i) + { + *s++ = (1812433253UL * (*r ^ (*r >> 30)) + i) & 0xffffffffUL; + r++; + } +} + +void Random::reload() +{ + register uint32 *p = state; + register int i; + for (i = N - M; i--; ++p) + *p = twist(p[M], p[0], p[1]); + for (i = M; --i; ++p) + *p = twist(p[M - N], p[0], p[1]); + *p = twist(p[M - N], p[0], state[0]); + + left = N, pNext = state; +} + +Random::uint32 Random::hash(time_t t, clock_t c) +{ + + static uint32 differ = 0; // guarantee time-based seeds will change + + uint32 h1 = 0; + unsigned char *p = (unsigned char *) &t; + for (size_t i = 0; i < sizeof(t); ++i) + { + h1 *= UCHAR_MAX + 2U; + h1 += p[i]; + } + uint32 h2 = 0; + p = (unsigned char *) &c; + for (size_t j = 0; j < sizeof(c); ++j) + { + h2 *= UCHAR_MAX + 2U; + h2 += p[j]; + } + return (h1 + differ++) ^ h2; +} + +void Random::save(uint32* saveArray) const +{ + register uint32 *sa = saveArray; + register const uint32 *s = state; + register int i = N; + for (; i--; *sa++ = *s++) + { + } + *sa = left; +} + +void Random::load(uint32 * const loadArray) +{ + register uint32 *s = state; + register uint32 *la = loadArray; + register int i = N; + for (; i--; *s++ = *la++) + { + } + left = *la; + pNext = &state[N - left]; +} + +std::ostream& operator<<(std::ostream& os, const Random& mtrand) +{ + register const Random::uint32 *s = mtrand.state; + register int i = mtrand.N; + for (; i--; os << *s++ << "\t") + { + } + return os << mtrand.left; +} + +std::istream& operator>>(std::istream& is, Random& mtrand) +{ + register Random::uint32 *s = mtrand.state; + register int i = mtrand.N; + for (; i--; is >> *s++) + { + } + is >> mtrand.left; + mtrand.pNext = &mtrand.state[mtrand.N - mtrand.left]; + return is; +} + + +static Random _random; +Random &Random::instance() { + return _random; +} + +} // namespace parsec diff --git a/python/crpropa.i b/python/crpropa.i index 4ca609fc3..540d34b67 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -20,6 +20,8 @@ using std::ptrdiff_t; %include std_container.i %include "exception.i" + + #ifdef CRPROPA_HAVE_QUIMBY %import (module="quimby") quimby.i #endif @@ -223,4 +225,107 @@ Vector3d.__repr__ = Vector3__repr__ Vector3f.__repr__ = Vector3__repr__ DeflectionCK = PropagationCK # legacy name + +%} + + +/* + * MagneticLens + */ + +#ifdef WITHNUMPY +%{ +/* Include numpy array interface, if available */ + #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION + #include "numpy/arrayobject.h" + #include "numpy/ufuncobject.h" +%} +#endif + +/* Initialize numpy array interface, if available */ +#ifdef WITHNUMPY +%init %{ +import_array(); +import_ufunc(); +%} + +%pythoncode %{ +import numpy +__WITHNUMPY = True +%} + +#else +%pythoncode %{ +__WITHNUMPY = False +%} +#endif + + +#ifdef WITH_GALACTIC_LENSES + +%include typemaps.i + +%{ +#include "parsec/ModelMatrix.h" +#include "parsec/Pixelization.h" +#include "parsec/MagneticLens.h" %} + +%include "parsec/ModelMatrix.h" +%apply double &INOUT {double &longitude, double &latitude}; +%ignore Pixelization::nPix(); + +%include "parsec/Pixelization.h" +%pythoncode %{ +def Pixelization_nonStaticnPix(self, order=None): + if order == None: + return Pixelization_nPix(self.getOrder()) + else: + return Pixelization_nPix(order) +Pixelization.nPix = Pixelization_nonStaticnPix +%} + +%apply double &INOUT {double &phi, double &theta}; +%ignore MagneticLens::transformModelVector(double *,double) const; +%include "parsec/MagneticLens.h" +%template(LenspartVector) std::vector< parsec::LensPart *>; + +#ifdef WITHNUMPY +%extend parsec::MagneticLens{ + PyObject * transformModelVector_numpyArray(PyObject *input, double rigidity) + { + PyArrayObject *arr = NULL; + PyArray_Descr *dtype = NULL; + int ndim = 0; + npy_intp dims[NPY_MAXDIMS]; + if (PyArray_GetArrayParamsFromObject(input, NULL, 1, &dtype, &ndim, dims, &arr, NULL) < 0) + { + return NULL; + } + + if (arr == NULL) + { + return NULL; + } + + double *dataPointer = (double*) PyArray_DATA(arr); + $self->transformModelVector(dataPointer, rigidity); + return input; + } +}; +#else +%extend parsec::MagneticLens{ + PyObject * transformModelVector_numpyArray(PyObject *input, double rigidity) + { + std::cerr << "ERROR: PARSEC was compiled without numpy support!" << std::endl; + return NULL; + } +}; +#endif + +%pythoncode %{ +MagneticLens.transformModelVector = MagneticLens.transformModelVector_numpyArray +%} + +#endif // WITH_GALACTIC_LENSES_ + diff --git a/test/testMagneticLens.cpp b/test/testMagneticLens.cpp new file mode 100644 index 000000000..012dade95 --- /dev/null +++ b/test/testMagneticLens.cpp @@ -0,0 +1,73 @@ +/// Tests gamale with a test lense from file and demonstrating basic +/// usage + +//-------------------------------------------- +// Project: Galactic magnetic Lense (GaMaLe) - +// Copyright (C) 2009 Tobias Winchen - +// RWTH Aachen, Germany - +// Contact: winchen@physik.rwth-achen.de - +// Licensed under the GNU GPL v2 - +//-------------------------------------------- + +#include +#include +#include "gtest/gtest.h" + +#include "parsec/MagneticLens.h" +#include "parsec/ModelMatrix.h" +#include "parsec/Pixelization.h" + +using namespace std; +using namespace parsec; + +TEST(MagneticLens, Deflection) +{ + MagneticLens magneticLens(5); + Pixelization P(5); + ModelMatrix M(P.nPix(),P.nPix(),P.nPix()); + + // Map any direction (p,t) to (p, -t) + for (int i=0;i 3.14: + phiout -= 3.14 + j = p.direction2Pix(phiout, thetaout) + m.setElement(i, j, 1) + self.magneticLens.setLensPart(m, 18, 20) + + def test_transformCosmicRays(self): + phi = 0 + theta = -0.01 + [r, phi, theta] = self.magneticLens.transformCosmicRay(19.0, phi, + theta) + self.assertTrue(r) + self.assertFalse(theta == -0.01) + + def test_transformModelVector_numpyArray(self): + import numpy + v = numpy.ones(self.magneticLens.getPixelization().nPix()) + self.magneticLens.transformModelVector(v, 2) + + def test_accessToPixelization(self): + self.assertEquals(self.magneticLens.getPixelization().nPix(), + self.magneticLens.getPixelization().nPix(5)) + + +class testPixelizationConsistency(unittest.TestCase): + def testConsistencyWithHealpy(self): + try: + import healpy + except ImportError: + print "Consistency with healpy not tested as healpy is" \ + "not available" + return + p = crpropa.Pixelization(4) + from numpy import linspace + from math import pi + for theta in linspace(0, pi): + for phi in linspace(-pi, pi): + crpropaIdx = p.direction2Pix(phi, pi / 2 - theta) + hpIdx = healpy.ang2pix(2 ** 4, theta, phi) + self.assertEqual(crpropaIdx, hpIdx) + + +if __name__ == '__main__': + unittest.main() From 2f7cb3a7f0c9dd09c32815892248d8f6570e0a8e Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Wed, 15 Oct 2014 10:25:14 +0200 Subject: [PATCH 0512/1298] Integrated test of magnetic lens python interface in make test --- CMakeLists.txt | 11 +++++++++++ ...rface.py => testMagneticLensPythonInterface.py.in} | 0 2 files changed, 11 insertions(+) rename test/{testMagneticLensPythonInterface.py => testMagneticLensPythonInterface.py.in} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index e5dd95359..edf4efc89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,12 @@ if(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) message(STATUS "Use --as-needed linker flags!") endif(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) +# Set default build-type to release to enable performance improvements +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif(NOT CMAKE_BUILD_TYPE) +MESSAGE(STATUS "Build Type: ${CMAKE_BUILD_TYPE}") + # ---------------------------------------------------------------------------- # Dependencies # ---------------------------------------------------------------------------- @@ -270,6 +276,11 @@ if(ENABLE_TESTING) target_link_libraries(testGalacticMagneticLens crpropa gtest gtest_main pthread) add_test(testGalacticMagneticLens testGalacticMagneticLens) endif(WITH_GALACTIC_LENSES) + + if(ENABLE_PYTHON) + CONFIGURE_FILE(test/testMagneticLensPythonInterface.py.in testMagneticLensPythonInterface.py) + ADD_TEST(testMagneticLensPythonInterface ${PYTHON_EXECUTABLE} testMagneticLensPythonInterface.py) + endif(ENABLE_PYTHON) endif(ENABLE_TESTING) # ---------------------------------------------------------------------------- diff --git a/test/testMagneticLensPythonInterface.py b/test/testMagneticLensPythonInterface.py.in similarity index 100% rename from test/testMagneticLensPythonInterface.py rename to test/testMagneticLensPythonInterface.py.in From d307f3d0de9c3da719d2ae001f05c4811deec98b Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Wed, 15 Oct 2014 17:01:12 +0200 Subject: [PATCH 0513/1298] Added particle maps container --- libs/GalacticMagneticLens/CMakeLists.txt | 5 +- .../include/parsec/ParticleMapsContainer.h | 86 ++++++++ .../src/ParticleMapsContainer.cc | 193 ++++++++++++++++++ python/crpropa.i | 50 +++++ test/testMagneticLens.cpp | 41 ++++ test/testMagneticLensPythonInterface.py.in | 11 + 6 files changed, 385 insertions(+), 1 deletion(-) create mode 100644 libs/GalacticMagneticLens/include/parsec/ParticleMapsContainer.h create mode 100644 libs/GalacticMagneticLens/src/ParticleMapsContainer.cc diff --git a/libs/GalacticMagneticLens/CMakeLists.txt b/libs/GalacticMagneticLens/CMakeLists.txt index 579fe2feb..b6b8d9d9e 100644 --- a/libs/GalacticMagneticLens/CMakeLists.txt +++ b/libs/GalacticMagneticLens/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 2.6) include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/include ${Boost_INCLUDE_DIRS} - ${CMAKE_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/libs/HepPID/include ) add_library(galacticmagneticlens STATIC @@ -11,6 +11,9 @@ add_library(galacticmagneticlens STATIC src/ModelMatrix.cpp src/Pixelization.cc src/Random.cc + src/ParticleMapsContainer.cc ) + +target_link_libraries(galacticmagneticlens HepPID) SET_TARGET_PROPERTIES(galacticmagneticlens PROPERTIES COMPILE_FLAGS -fPIC) diff --git a/libs/GalacticMagneticLens/include/parsec/ParticleMapsContainer.h b/libs/GalacticMagneticLens/include/parsec/ParticleMapsContainer.h new file mode 100644 index 000000000..d0b3c6590 --- /dev/null +++ b/libs/GalacticMagneticLens/include/parsec/ParticleMapsContainer.h @@ -0,0 +1,86 @@ +#ifndef PARTICLEMAPSCONTAINER_HH +#define PARTICLEMAPSCONTAINER_HH + +#include +#include +#include "parsec/Pixelization.h" +#include "parsec/MagneticLens.h" + +namespace parsec{ + +/// Container for particlemaps +/// The maps are stored with discrete energies on a logarithmic scale. The +/// default energy width is 0.02 with an energy bin from 10**17.99 - 10**18.01 +/// eV +class ParticleMapsContainer +{ + private: + std::map< int , std::map > _data; + std::map< int , double> _weights; + Pixelization _pixelization; + double _deltaLogE; + double _bin0lowerEdge; + + // get the bin number of the energy + int energy2Idx(double energy) const; + double idx2Energy(int idx) const; + + public: + + ParticleMapsContainer(double deltaLogE = 0.02, double bin0lowerEdge = 18) : _deltaLogE(deltaLogE), _bin0lowerEdge(bin0lowerEdge), _pixelization(6) + { + } + + ~ParticleMapsContainer(); + + size_t getNumberOfPixels() + { + return _pixelization.getNumberOfPixels(); + } + + /// returns the map for the particleId with the given energy + double *getMap(const int particleId, double energy); + + /// adds a particle to the map container + /// particleId is HEP particleId, energy [eV], galacticLongitude and + /// galacticLatitude in [rad] + void addParticle(const int particleId, double energy, double galacticLongitude, double galacticLatitude, double weight=1); + + /// reads the particles from the given file and weights the particles with + /// the energy of the mother particle at the source. + /// this assumes that the particles in the fiels are observed at earth and the galactic + /// center is in directon (0,1,0) and the galactic north-pole is in + /// direction (0,0,1). + void addParticlesFromFile(const std::string inputFileName, double sourceEnergyWeightExponent=0); + + // returns a vector of all particle ids in th + std::vector getParticleIds(); + + std::vector getEnergies(int pid); + + void applyLens(MagneticLens &lens);; + + void getRandomParticles(size_t N, vector &particleId, + vector &energy, vector &galacticLongitudes, + vector &galacticLatitudes); + +}; + + +/* +Python code that we have to write + + + + + + + +*/ + + + + +} // namespace parsec + +#endif // PARTICLEMAPSCONTAINER_HH diff --git a/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc b/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc new file mode 100644 index 000000000..6f0a35cfd --- /dev/null +++ b/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc @@ -0,0 +1,193 @@ +#include "HepPID/ParticleIDMethods.hh" +#include "parsec/Random.hh" +#include +#include "parsec/ParticleMapsContainer.h" +#include +namespace parsec +{ + +ParticleMapsContainer::~ParticleMapsContainer() +{ + for(std::map >::iterator pid_iter = _data.begin(); + pid_iter != _data.end(); ++pid_iter) { + for(std::map::iterator energy_iter = pid_iter->second.begin(); + energy_iter != pid_iter->second.end(); ++energy_iter) { + delete[] (energy_iter->second); + } + } +} + +int ParticleMapsContainer::energy2Idx(double energy) const +{ + double lE = log10(energy); + return int((lE - _bin0lowerEdge) / _deltaLogE); +} + +double ParticleMapsContainer::idx2Energy(int idx) const +{ + return pow(10, idx * _deltaLogE + _bin0lowerEdge + _deltaLogE / 2); +} + + +double* ParticleMapsContainer::getMap(const int particleId, double energy) +{ + if (_data.find(particleId) == _data.end()) + { + return NULL; + } + int energyIdx = energy2Idx(energy); + if (_data[particleId].find(energyIdx) == _data[particleId].end()) + { + return NULL; + } + return _data[particleId][energy2Idx(energy)]; +} + + +void ParticleMapsContainer::addParticle(const int particleId, double energy, double galacticLongitude, double galacticLatitude, double weight) +{ + if (_data.find(particleId) == _data.end()) + { + map M; + _data[particleId] = M; + _weights[particleId] = 0; + } + + int energyIdx = energy2Idx(energy); + if (_data[particleId].find(energyIdx) == _data[particleId].end()) + { + _data[particleId][energyIdx] = new double[_pixelization.getNumberOfPixels()]; + std::fill(_data[particleId][energyIdx], _data[particleId][energyIdx] + _pixelization.getNumberOfPixels(), 0); + } + + uint32_t pixel = _pixelization.direction2Pix(galacticLongitude, galacticLatitude); + _data[particleId][energyIdx][pixel] +=weight; + _weights[particleId] +=weight; +} + + +void ParticleMapsContainer::addParticlesFromFile(const std::string inputFileName, double sourceEnergyWeightExponent) +{ + std::ifstream infile(inputFileName.c_str()); + + while (infile.good()) { + if (infile.peek() != '#') { + int particleId, sourceId; + double trajectoryLength, energy, sourceEnergy, pX, pY, pZ, x, y, z, pX0, pY0, pZ0, x0, y0, z0, redShift; + + infile >> trajectoryLength + >> particleId + >> sourceId + >> energy + >> sourceEnergy + >> x >> y >> z + >> x0 >> y0 >> z0 + >> pX >> pY >> pZ + >> pX0 >> pY0 >> pZ0 + >> redShift; + + double weight = pow(sourceEnergy, sourceEnergyWeightExponent); + double galacticLongitude = atan2(-x, -y); + double galacticLatitude = acos(z) - M_PI /2; + addParticle(particleId, energy, galacticLongitude, galacticLatitude, weight); + } + } +} + + +// returns a vector of all particle ids in th +std::vector ParticleMapsContainer::getParticleIds() +{ + std::vector ids; + for(std::map >::iterator pid_iter = _data.begin(); + pid_iter != _data.end(); ++pid_iter) + { + ids.push_back(pid_iter->first); + } + return ids; +} + + +std::vector ParticleMapsContainer::getEnergies(int pid) +{ + std::vector energies; + if (_data.find(pid) != _data.end()) + { + for(std::map::iterator iter = _data[pid].begin(); + iter != _data[pid].end(); ++iter) + { + energies.push_back( idx2Energy(iter->first) ); + } + } + return energies; +} + + +void ParticleMapsContainer::applyLens(MagneticLens &lens) +{ + for(std::map >::iterator pid_iter = _data.begin(); + pid_iter != _data.end(); ++pid_iter) { + for(std::map::iterator energy_iter = pid_iter->second.begin(); + energy_iter != pid_iter->second.end(); ++energy_iter) { + // // transform only nuclei + double energy = idx2Energy(energy_iter->first) / 1E18; + double charge = HepPID::charge(pid_iter->first); + if (fabs(charge) > DBL_EPSILON) + { + lens.transformModelVector(energy_iter->second, energy / charge); + } + + } + } +} + + +void ParticleMapsContainer::getRandomParticles(size_t N, vector &particleId, + vector &energy, vector &galacticLongitudes, + vector &galacticLatitudes) +{ + double sumOfWeights = 0; + for(std::map::iterator iter = _weights.begin(); iter != _weights.end(); ++iter) + { + sumOfWeights += iter->second; + } + + particleId.resize(N); + energy.resize(N); + galacticLongitudes.resize(N); + galacticLatitudes.resize(N); + + for(size_t i=0; i< N; i++) + { + double r = Random::instance().rand() * sumOfWeights; + std::map::iterator iter = _weights.begin(); + + while ((r-= iter->second) > 0) + { + ++iter; + } + + particleId[i] = iter->first; + bool foundParticle = false; + + // // loop over maps + for(std::map::iterator energy_iter = + _data[iter->first].begin(); !foundParticle; ++energy_iter ) + { + for(size_t j=0; j< _pixelization.getNumberOfPixels() && !foundParticle; j++) + { + // if this is too slow I need to store the weights for the energies + // alongside the maps + r+= energy_iter->second[j]; + if (r >=0) + { + foundParticle = true; + energy[i] = idx2Energy(energy_iter->first); + _pixelization.pix2Direction (j, galacticLongitudes[i], galacticLatitudes[i]); + } + } + } + } +} + +} // namespace parsec diff --git a/python/crpropa.i b/python/crpropa.i index 540d34b67..a061c5558 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -269,6 +269,7 @@ __WITHNUMPY = False #include "parsec/ModelMatrix.h" #include "parsec/Pixelization.h" #include "parsec/MagneticLens.h" +#include "parsec/ParticleMapsContainer.h" %} %include "parsec/ModelMatrix.h" @@ -327,5 +328,54 @@ Pixelization.nPix = Pixelization_nonStaticnPix MagneticLens.transformModelVector = MagneticLens.transformModelVector_numpyArray %} + +%ignore ParticleMapsContainer::getMap; +%ignore ParticleMapsContainer::getParticleIds; +%ignore ParticleMapsContainer::getEnergies; +%include "parsec/ParticleMapsContainer.h" + +#ifdef WITHNUMPY +%extend parsec::ParticleMapsContainer{ + PyObject *getMap_numpyArray(const int particleId, double energy) + { + double* data = $self->getMap(particleId, energy); + size_t npix = $self->getNumberOfPixels(); + npy_intp dims[1] = {npix}; + return PyArray_SimpleNewFromData(1, dims, NPY_DOUBLE, (void*)data); + } + + PyObject *getParticleIds_numpyArray() + { + std::vector v = $self->getParticleIds(); + npy_intp size = {v.size()}; + PyObject *out = out = PyArray_SimpleNew(1, &size, NPY_INT); + memcpy(PyArray_DATA((PyArrayObject *) out), &v[0], v.size() * sizeof(int)); + return out; + } + + PyObject *getEnergies_numpyArray(const int pid) + { + std::vector v = $self->getEnergies(pid); + npy_intp size = {v.size()}; + PyObject *out = out = PyArray_SimpleNew(1, &size, NPY_DOUBLE); + memcpy(PyArray_DATA((PyArrayObject *) out), &v[0], v.size() * sizeof(double)); + return out; + } + +}; +#else +%extend parsec::ParticleMapsContainer{ + PyObject *getMap_numpyArray(const int particleId, double energy) + { + std::cerr << "ERROR: PARSEC was compiled without numpy support!" << std::endl; + return NULL; + } +}; +#endif +%pythoncode %{ +ParticleMapsContainer.getMap = ParticleMapsContainer.getMap_numpyArray +ParticleMapsContainer.getParticleIds = ParticleMapsContainer.getParticleIds_numpyArray +ParticleMapsContainer.getEnergies = ParticleMapsContainer.getEnergies_numpyArray +%} #endif // WITH_GALACTIC_LENSES_ diff --git a/test/testMagneticLens.cpp b/test/testMagneticLens.cpp index 012dade95..eda5334ef 100644 --- a/test/testMagneticLens.cpp +++ b/test/testMagneticLens.cpp @@ -16,6 +16,7 @@ #include "parsec/MagneticLens.h" #include "parsec/ModelMatrix.h" #include "parsec/Pixelization.h" +#include "parsec/ParticleMapsContainer.h" using namespace std; using namespace parsec; @@ -71,3 +72,43 @@ TEST(Pixelization, angularDistance) EXPECT_TRUE(ang == ang); } } + + +TEST(ParticleMapsContainer, addParticle) +{ + ParticleMapsContainer maps; + maps.addParticle(1000010010, 1E18, 0 , 0 ); + std::vector pids = maps.getParticleIds(); + EXPECT_EQ(pids.size(), 1); + EXPECT_EQ(pids[0], 1000010010); + + std::vector energies = maps.getEnergies(1000010010); + EXPECT_EQ(energies.size(), 1); +} + +TEST(ParticleMapsContainer, getRandomParticles) +{ + ParticleMapsContainer maps(0.002); + maps.addParticle(1000010010, 1E18, 0 , 0 ); + std::vector energies; + std::vector lons; + std::vector lats; + std::vector particleIds; + + size_t N = 42; + maps.getRandomParticles(N, particleIds, energies, lons, lats); + + EXPECT_EQ(energies.size(), N); + EXPECT_EQ(lons.size(), N); + EXPECT_EQ(lats.size(), N); + EXPECT_EQ(particleIds.size(), N); + + for(size_t i = 0; i < N; i++) + { + EXPECT_NEAR(log10(energies[i]), 18, 0.002); + EXPECT_EQ(particleIds[i], 1000010010); + EXPECT_NEAR(lons[i], 0, 1./180*M_PI); + EXPECT_NEAR(lats[i], 0, 1./180*M_PI); + } + +} diff --git a/test/testMagneticLensPythonInterface.py.in b/test/testMagneticLensPythonInterface.py.in index 263c9d11e..433f4fe0c 100644 --- a/test/testMagneticLensPythonInterface.py.in +++ b/test/testMagneticLensPythonInterface.py.in @@ -68,5 +68,16 @@ class testPixelizationConsistency(unittest.TestCase): self.assertEqual(crpropaIdx, hpIdx) +class testParticleMapsContainer(unittest.TestCase): + def setUp(self): + self.maps = crpropa.ParticleMapsContainer() + + def testAddParticle(self): + self.maps.addParticle(12, 1E18, 0, 0) + self.assertEquals(len(self.maps.getParticleIds()), 1) + self.assertEquals(self.maps.getParticleIds()[0], 12) + self.assertEquals(len(self.maps.getEnergies(12)), 1) + + if __name__ == '__main__': unittest.main() From 32559b8119dd303b77854a049299773f8e280fd1 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Wed, 15 Oct 2014 17:04:44 +0200 Subject: [PATCH 0514/1298] EleCa: Fixed wrong initilization of array --- libs/EleCa/src/EnergyLoss.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/EleCa/src/EnergyLoss.cpp b/libs/EleCa/src/EnergyLoss.cpp index 62550ca37..381492fec 100644 --- a/libs/EleCa/src/EnergyLoss.cpp +++ b/libs/EleCa/src/EnergyLoss.cpp @@ -79,9 +79,11 @@ void InitRK() { gRKa[5] = 1.; gRKa[6] = 7. / 8.; - for (int i = 0; i < RK_ORDER; i++) { - for (int j = 0; j < RK_ORDER + 1; j++) + for (int i = 0; i < RK_ORDER + 1; i++) { + for (int j = 0; j < RK_ORDER; j++) + { gRKb[i][j] = 0.; + } } gRKb[2][1] = 1. / 5.; From afc9ad9fc1c66f04a3591021c2aacb5c5f49e281 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Thu, 16 Oct 2014 11:56:52 +0200 Subject: [PATCH 0515/1298] Fix coordinates --- libs/GalacticMagneticLens/src/ParticleMapsContainer.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc b/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc index 6f0a35cfd..d29c733f8 100644 --- a/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc +++ b/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc @@ -87,11 +87,13 @@ void ParticleMapsContainer::addParticlesFromFile(const std::string inputFileName >> redShift; double weight = pow(sourceEnergy, sourceEnergyWeightExponent); - double galacticLongitude = atan2(-x, -y); - double galacticLatitude = acos(z) - M_PI /2; - addParticle(particleId, energy, galacticLongitude, galacticLatitude, weight); + double galacticLongitude = atan2(-pY, -pX); + double galacticLatitude = acos(pZ / sqrt(pX*pX + pY*pY + pZ*pZ)) - M_PI /2; + addParticle(particleId, energy * 1E18, galacticLongitude, galacticLatitude, weight); } + infile.ignore(std::numeric_limits < std::streamsize > ::max(), '\n'); } + infile.close(); } From f11d7794b5770a1e9b6f9a38f89e9de07e43ce93 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 17 Oct 2014 09:37:24 +0200 Subject: [PATCH 0516/1298] Use ChargeNumber instead of charge fom HepPid; add warning if rigidity is not covered. --- .../include/parsec/ParticleMapsContainer.h | 2 +- libs/GalacticMagneticLens/src/MagneticLens.cpp | 10 ++++++++-- libs/GalacticMagneticLens/src/ParticleMapsContainer.cc | 8 ++++---- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/libs/GalacticMagneticLens/include/parsec/ParticleMapsContainer.h b/libs/GalacticMagneticLens/include/parsec/ParticleMapsContainer.h index d0b3c6590..7b84a16e9 100644 --- a/libs/GalacticMagneticLens/include/parsec/ParticleMapsContainer.h +++ b/libs/GalacticMagneticLens/include/parsec/ParticleMapsContainer.h @@ -27,7 +27,7 @@ class ParticleMapsContainer public: - ParticleMapsContainer(double deltaLogE = 0.02, double bin0lowerEdge = 18) : _deltaLogE(deltaLogE), _bin0lowerEdge(bin0lowerEdge), _pixelization(6) + ParticleMapsContainer(double deltaLogE = 0.02, double bin0lowerEdge = 17.99) : _deltaLogE(deltaLogE), _bin0lowerEdge(bin0lowerEdge), _pixelization(6) { } diff --git a/libs/GalacticMagneticLens/src/MagneticLens.cpp b/libs/GalacticMagneticLens/src/MagneticLens.cpp index ab8bbc56c..16841b321 100644 --- a/libs/GalacticMagneticLens/src/MagneticLens.cpp +++ b/libs/GalacticMagneticLens/src/MagneticLens.cpp @@ -76,7 +76,8 @@ bool MagneticLens::transformCosmicRay(double rigidity, double& phi, LensPart *lenspart = getLensPart(log10(rigidity) + 18); if (!lenspart) { - throw std::runtime_error("Rigidity not covered by lens"); + std::cerr << "Warning. Trying to transform cosmic ray with rigidity " << rigidity << " which is not covered by this lens!.\n" << std::endl; + return false; } ModelVectorType v; @@ -241,7 +242,12 @@ void MagneticLens::normalizeLensparts() void MagneticLens::transformModelVector(double* model, double rigidity) const { LensPart* lenspart = (getLensPart(log10(rigidity)+18)); - + + if (!lenspart) + { + std::cerr << "Warning. Trying to transform vector with rigidity " << rigidity << " which is not covered by this lens!.\n" << std::endl; + return; + } size_t lensSize = _pixelization->nPix(); diff --git a/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc b/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc index d29c733f8..d0cecbe13 100644 --- a/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc +++ b/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc @@ -88,7 +88,7 @@ void ParticleMapsContainer::addParticlesFromFile(const std::string inputFileName double weight = pow(sourceEnergy, sourceEnergyWeightExponent); double galacticLongitude = atan2(-pY, -pX); - double galacticLatitude = acos(pZ / sqrt(pX*pX + pY*pY + pZ*pZ)) - M_PI /2; + double galacticLatitude = M_PI / 2 - acos(-pZ / sqrt(pX*pX + pY*pY + pZ*pZ)); addParticle(particleId, energy * 1E18, galacticLongitude, galacticLatitude, weight); } infile.ignore(std::numeric_limits < std::streamsize > ::max(), '\n'); @@ -133,10 +133,10 @@ void ParticleMapsContainer::applyLens(MagneticLens &lens) energy_iter != pid_iter->second.end(); ++energy_iter) { // // transform only nuclei double energy = idx2Energy(energy_iter->first) / 1E18; - double charge = HepPID::charge(pid_iter->first); - if (fabs(charge) > DBL_EPSILON) + int chargeNumber = HepPID::Z(pid_iter->first); + if (chargeNumber != 0) { - lens.transformModelVector(energy_iter->second, energy / charge); + lens.transformModelVector(energy_iter->second, energy / chargeNumber); } } From cb4ac4804d5db3478c727ad42397b0f53175a815 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 17 Oct 2014 15:47:53 +0200 Subject: [PATCH 0517/1298] remove data-tools, move to new repository --- .../generate_epairTable.py | 83 ----- data-tools/NuclearDecay/nuclear_decay.py | 300 ------------------ data-tools/NuclearMass/nuclear_mass.py | 62 ---- .../PhotoDisintegration/photodis_combine.py | 51 --- .../PhotoDisintegration/photodis_reformat.py | 98 ------ data-tools/PhotoPionProduction/photopion.py | 55 ---- .../PhotonField/Kneiske2004_IRB/z0.2.txt | 64 ---- .../PhotonField/Kneiske2004_IRB/z0.4.txt | 58 ---- .../PhotonField/Kneiske2004_IRB/z0.6.txt | 48 --- data-tools/PhotonField/Kneiske2004_IRB/z0.txt | 52 --- data-tools/PhotonField/Kneiske2004_IRB/z1.txt | 62 ---- data-tools/PhotonField/Kneiske2004_IRB/z2.txt | 65 ---- data-tools/PhotonField/Kneiske2004_IRB/z3.txt | 62 ---- data-tools/PhotonField/Kneiske2004_IRB/z4.txt | 57 ---- .../PhotonField/Kneiske2004_IRB_scaling.py | 91 ------ data-tools/PhotonField/photonField.py | 77 ----- 16 files changed, 1285 deletions(-) delete mode 100644 data-tools/ElectronPairProduction/generate_epairTable.py delete mode 100644 data-tools/NuclearDecay/nuclear_decay.py delete mode 100644 data-tools/NuclearMass/nuclear_mass.py delete mode 100644 data-tools/PhotoDisintegration/photodis_combine.py delete mode 100644 data-tools/PhotoDisintegration/photodis_reformat.py delete mode 100644 data-tools/PhotoPionProduction/photopion.py delete mode 100644 data-tools/PhotonField/Kneiske2004_IRB/z0.2.txt delete mode 100644 data-tools/PhotonField/Kneiske2004_IRB/z0.4.txt delete mode 100644 data-tools/PhotonField/Kneiske2004_IRB/z0.6.txt delete mode 100644 data-tools/PhotonField/Kneiske2004_IRB/z0.txt delete mode 100644 data-tools/PhotonField/Kneiske2004_IRB/z1.txt delete mode 100644 data-tools/PhotonField/Kneiske2004_IRB/z2.txt delete mode 100644 data-tools/PhotonField/Kneiske2004_IRB/z3.txt delete mode 100644 data-tools/PhotonField/Kneiske2004_IRB/z4.txt delete mode 100644 data-tools/PhotonField/Kneiske2004_IRB_scaling.py delete mode 100644 data-tools/PhotonField/photonField.py diff --git a/data-tools/ElectronPairProduction/generate_epairTable.py b/data-tools/ElectronPairProduction/generate_epairTable.py deleted file mode 100644 index d15a6a8b7..000000000 --- a/data-tools/ElectronPairProduction/generate_epairTable.py +++ /dev/null @@ -1,83 +0,0 @@ -from pylab import * -from crpropa import * -from scipy import interpolate, integrate - - - -def densityCMB(eps): - # CMB spectral number density [1/m^3/J] at photon energy eps [J] - return 8 * pi * eps**2 / h_planck**3 / c_light**3 / (exp(eps / k_boltzmann / 2.725) - 1) - -xKneiske, yKneiske = genfromtxt('KneiskeIRB_z0.txt', unpack=1) -def densityIRB(eps): - # IRB (Kneiske et al. 2004) spectral number density [1/m^3/J] at photon energy eps [J] - x = h_planck * c_light / eps # wavelength [m] - y = interp(x * 1e6, xKneiske, yKneiske, 0, 0) * 1e-9 # lambda * I_lambda [W/m^2/sr] - y /= x # remove scaling with lambda; I_lambda [W/m^3/sr] - y *= x**2 / h_planck / c_light # convert to I_eps (using I_eps = - dlambda / deps * I_lambda, deps = - h*c / lambda^2 dlambda) - y *= 4 * pi / c_light # convert to energy density - y /= eps # convert to number density - return y - - - -### Calculate the energy loss -dE/dx due to electron pair production -# c.f. Blumenthal 1970, Phys. Rev. D Volume 1, Number 6, Page 1596-1602 - -# Tabulated values for equation (14) taken from figure 2 -# xi = 2 * gamma * eps / (me*c^2), where eps is the photon energy, gamma the nucleus lorentz factor -# phi(xi) integral over differential cross sections -# This could be replaced with an explicit calculation of the integral -x, y = genfromtxt('Blumenthal_phi.txt', comments='#', unpack=1) -phi = interpolate.interp1d(10**x, 10**y) -xiMin = 10**x[0] -xiMax = 10**x[-1] - -# prefactor of equation (13) -r0 = 2.817940e-15 # classical electron radius [m] -alpha = 7.297352e-3 # fine-structure constant -c = alpha * r0**2 * 1**2 * mass_electron**2 * c_light**4 - - - -### generate CMB table -# integrand of equation (13) with CMB -def f(xi, gamma): - eps = xi * mass_electron * c_light**2 / 2 / gamma - return densityCMB(eps) * phi(xi) / xi**2 - -N = 21 -A1 = zeros((N, 2)) - -for i, g in enumerate(linspace(8.5, 12.5, N)): - F, err = integrate.quad(f, xiMin, xiMax, 10**g) - A1[i,1] = c * F - A1[i,0] = g - -savetxt('epair_CMB.txt', A1, header='log10(lorentzFactor) dE/dx [J/m]', fmt=['%.1f','%.6e'], delimiter='\t') - - - -### generate IRB table -def f(xi, gamma): - eps = xi * mass_electron * c_light**2 / 2 / gamma - return densityIRB(eps) * phi(xi) / xi**2 - -N = 31 -A2 = zeros((N, 2)) - -for i, g in enumerate(linspace(6.5, 12.5, N)): - F, err = integrate.quad(f, xiMin, xiMax, 10**g) - A2[i,1] = c * F - A2[i,0] = g - -savetxt('epair_IRB.txt', A2, header='log10(lorentzFactor) dE/dx [J/m]', fmt=['%.1f','%.6e'], delimiter='\t') - - - -### generate combined table -A3 = A2.copy() -A3[10:,1] += A1[:,1] - -savetxt('epair_CMB_IRB.txt', A3, header='log10(lorentzFactor) dE/dx [J/m]', fmt=['%.1f','%.6e'], delimiter='\t') - diff --git a/data-tools/NuclearDecay/nuclear_decay.py b/data-tools/NuclearDecay/nuclear_decay.py deleted file mode 100644 index 24cdc52de..000000000 --- a/data-tools/NuclearDecay/nuclear_decay.py +++ /dev/null @@ -1,300 +0,0 @@ -from numpy import * -import crpropa - -# Script to preprocess the nuclear decay data table from the BNL NuDat2 database -# See http://www.nndc.bnl.gov/nudat2/indx_sigma.jsp -# Query settings: -# Z: 0-36, output: formatted file - -class Decay: - def __init__(self): - pass - - def __repr__(self): - return 'Z=%i N=%i mode=%s tau=%.1e br=%.2f'%(self.Z, self.N, self.mode, self.tau, self.br) - - def load(self, s): - l = s.split('\t') - - # Z, N, id - self.Z = int(l[2]) - self.N = int(l[3]) - self.id = self.Z * 1000 + self.N - - # decay time - s = l[9].strip() - if s == 'infinity': - self.tau = inf - elif s == '': - self.tau = 0 - else: - self.tau = float(s) / log(2) - - # mode - self.mode = l[12].strip() - - # branching ratio - s = ''.join(c for c in l[13] if c not in ('>','<','=','~','%',' ','?','\n')) - self.brString = s - if s == '': - self.br = 0. - else: - self.br = float(s) / 100. - - def isStable(self): - return self.tau == inf - - def isBetaPlus(self): - return self.mode.find('E') > -1 - - def isBetaMinus(self): - return self.mode.find('B') > -1 - - -### parse data file -print '\nParsing data file' -print '-------------------------------------' -fin = open('NuDat2.txt','r') -lines = fin.readlines() -fin.close() - -decayTable = [[[] for n in range(31)] for z in range(27)] - -for line in lines[1:-3]: - d = Decay() - d.load(line) - # skip if Z > 26 (Fe-56) - if d.Z > 26: - continue - # skip if N > 30 (Fe-56) - if d.N > 30: - continue - # skip if isomeric transition - if d.mode == 'IT': - print d, '<- skip (isomeric transition)' - continue - # skip if lifetime missing - if d.tau == 0: - print d, '<- skip (missing lifetime)' - continue - # skip if decay mode missing - if d.mode == '': - if not(d.isStable()): - print d, '<- skip (missing decay mode)' - continue - # else store in decay table - decayTable[d.Z][d.N].append(d) - - -### remove duplicate decays -print '\n\nRemoving duplicates' -print '-------------------------------------' -for z in range(27): - for n in range(31): - dList = decayTable[z][n] - - if len(dList) < 2: - continue - - for i, d1 in enumerate(dList): - for d2 in dList[i+1:]: - if d1.mode == d2.mode: - print d1 - print d2, ' <- remove \n' - dList.remove(d2) - - -### explicitly edit some entries -print '\nExplicitly editing certain entries' -print '-------------------------------------' - -# remove Li-5 alpha decay (equivalent to existing proton emission) -d0 = decayTable[3][2][0] -d1 = decayTable[3][2][1] -print d0 -print d1, ' <- remove (equivalent to neutron emission)\n' -decayTable[3][2].remove(d1) - -# remove He-5 alpha decay (equivalent to existing neutron emission) -d0 = decayTable[2][3][0] -d1 = decayTable[2][3][1] -print d1 -print d0, ' <- remove (equivalent to neutron emission)\n' -decayTable[2][3].remove(d0) - -# modify B-12 "B3A" decay to "B2A" as it would leave an empty nucleus -d = decayTable[5][7][1] -print d, ' <- change decay mode to B2A\n' -d.mode = 'B2A' - -# Fe-45: to make beta+ decays exclusive -d = decayTable[26][19][0] -print d, ' <- set branching ratio to 0 (ratio equal to sum of following ratios)' -d.br = 0 -brSum = 0 -for d in decayTable[26][19][1:]: - print d - brSum += d.br -for d in decayTable[26][19][1:]: - d.br /= brSum - - -### calculate exclusive mean life times -print '\n\nCalculating exclusive life times' -print '-------------------------------------' -for z in range(27): - for n in range(31): - dList = decayTable[z][n] - - # skip for 0 or 1 entry - if len(dList) < 2: - continue - - # get sum of branching ratios - brSum = 0 - for d in dList: - brSum += d.br - - # if sum is 0, set branching ratios to equal values - if brSum == 0: - for d in dList: - d.br = 1. / len(dList) - - # else if sum not 1, search for an inclusive decay and/or normalize the branching ratios - elif brSum != 1.: - dInclusive = None - brSumExclusive = 0 - for i,d in enumerate(dList): - if d.br == 1.0: - dInclusive = d # inclusive decay found - else: - brSumExclusive += d.br # add exclusive branching ratio - - if dInclusive != None: - if dInclusive.br <= brSumExclusive: - dList.remove(dInclusive) # remove if purely inclusive - else: - dInclusive.br -= brSumExclusive # else make exclusive - - # normalize all branching ratios - for d in dList: - d.br /= brSum - - # finally, calculate exclusive decay time by dividing with branching ratio, while removing zeros - for d in dList: - if d.br == 0: - print d, ' <- remove (branching ratio 0)' - dList.remove(d) - else: - d.tau /= d.br - - -### correct for electron capture contribution in beta+ decays -print '\nBeta+ correction' -print '-------------------------------------' -a0 = 5.29177e-11 # Bohr radius [m] -a0 /= crpropa.c_light * (crpropa.h_planck / 2 / pi) / crpropa.eplus # convert to [1/eV] -Qe = crpropa.mass_electron * crpropa.c_squared / crpropa.eV # [eV] - -def I1(Q): - x = Q / Qe - return Qe**5 * ((2*x**4 - 9*x**2 - 8) * sqrt(x**2-1) + x*log(x+sqrt(x**2-1))) / 15 - -for z in range(27): - for n in range(31): - for d in decayTable[z][n]: - if not(d.isBetaPlus()): - continue - - m1 = crpropa.getNucleusMass(crpropa.getNucleusId(z+n, z)) - m2 = crpropa.getNucleusMass(crpropa.getNucleusId(z+n, z - 1)) - Q = (m1 - m2) * crpropa.c_squared / crpropa.eV - - Qbeta = (Q - Qe) # [eV] - Qec = (Q + Qe) # [eV] - - # check if energetically possible - if Qbeta < 0: - print d, ' <- make stable (beta+ decay not possible)' - d.tau = inf - continue - - # see Basdevant, Fundamentals in Nuclear Physics, 4.3.2 and 4.3.3 - # ratio tau_beta+ / tau_ec -# f = 2 / pi**2 * (z/a0)**3 * Qec**2 / Q**5 * 30 - f = 2 / pi**2 * (z/a0)**3 * Qec**2 / I1(Q) - print d, ' <- beta+ correction %.1e'%f - d.tau *= 1 + f - - -### set proton / neutron dripping with very short life time for all other isotopes -print '\n\nSet proton / neutron dripping for all other isotopes' -print '-------------------------------------' -for z in range(0,27): - for n in range(0,31): - if (z + n)==0: - continue - - dList = decayTable[z][n] - - if len(dList) > 0: - continue - - # else set p/n dripping - d = Decay() - d.Z = z - d.N = n - d.tau = 1e-99 - d.br = 1. - if z > n: # proton dripping - d.mode = 'P' - else: # neutron dripping - d.mode = 'N' - dList.append(d) - - -### write to file -print '\n\nWrite to file' -print '-------------------------------------' -fout = open('nuclear_decay.txt','w') -fout.write('# Z, N, Mean Life Time [s], Decay Mode (#beta- #beta+ #alpha #p #n), dE\n') - -# decay mode codes: #beta- #beta+ #alpha #p #n -modeDict = {'STABLE' : '0', - 'N' : '00001', - '2N' : '00002', - 'P' : '00010', - '2P' : '00020', - 'A' : '00100', - '2A' : '00200', - 'B-' : '10000', - '2B-': '20000', - 'BN' : '10001', - 'B2N': '10002', - 'B3N': '10003', - 'B4N': '10004', - 'BNA': '10101', - 'BA' : '10100', - 'B2A': '10200', - 'B3A': '10300', - 'EC' : '01000', - '2EC': '02000', - 'EA' : '01100', - 'EP' : '01010', - 'E2P': '01020', - 'E3P': '01030'} - -for z in range(0,27): - for n in range(0,31): - if (z + n)==0: - continue - - for d in decayTable[z][n]: - # skip stable - if d.tau == inf: - continue - fout.write('%i %i %s %e\n'%(d.Z, d.N, modeDict[d.mode], d.tau)) - -fout.close() -print 'done' - diff --git a/data-tools/NuclearMass/nuclear_mass.py b/data-tools/NuclearMass/nuclear_mass.py deleted file mode 100644 index 1a959bf42..000000000 --- a/data-tools/NuclearMass/nuclear_mass.py +++ /dev/null @@ -1,62 +0,0 @@ -from pylab import * -import crpropa - -# This script generates a table of nuclear mass for all combinations (Z,N) Z=0..26, N=0..30 -# For measured atoms, the NIST data table is used. -# All other atomic masses are taken to be A * amu -# The nuclear mass is then approximated as atomic mass minus electron mass. -# Here, electron binding energies (~keV) can be neglected compared to nuclear binding energies (~MeV) and nucleon and electron masses (~GeV, ~MeV). - -### read NIST data -# See: http://www.nist.gov/pml/data/comp.cfm -# All Isotopes, Linearized ASCII Output -# http://physics.nist.gov/cgi-bin/Compositions/stand_alone.pl?ele=&ascii=ascii2&isotype=all -fin = open('NIST.txt', 'r') -D = zeros((27, 31)) - -for i in range(4): - fin.readline() # skip header - -for line in fin.readlines(): - if line.startswith('Atomic Number'): - z = int(line.strip('Atomic Number = ')) - continue - - if line.startswith('Mass Number'): - a = int(line.strip('Mass Number = ')) - continue - - if line.startswith('Relative Atomic Mass'): - line = line.strip('Relative Atomic Mass = ') - relAtomicMass = line.translate(None, '()#\n') - - n = a - z - if a == 1: - continue # skip H-1 - if z > 26: - continue # skip isotopes with Z > 26 - if n > 30: - continue # skip isotopes with N > 30 - - # mass in [kg] minus mass of electrons - D[z, n] = float(relAtomicMass) * crpropa.amu - z * crpropa.mass_electron - - -### add neutron and proton mass -D[1, 0] = crpropa.mass_proton -D[0, 1] = crpropa.mass_neutron - -### fill empty entries in table with A * amu - Z * m_e approximation -for z in range(27): - for n in range(31): - if D[z, n] == 0: - D[z, n] = (z + n) * crpropa.amu - z * crpropa.mass_electron - -## Write to file -fout = open('nuclear_mass.txt', 'w') -fout.write('# Nuclear Mass of Isotopes Z < 26 and A < 56\n') -for z in range(27): - for n in range(31): - fout.write(str(z) + ' ' + str(n) + ' ' + str(D[z, n]) + '\n') - -fout.close() diff --git a/data-tools/PhotoDisintegration/photodis_combine.py b/data-tools/PhotoDisintegration/photodis_combine.py deleted file mode 100644 index 9016e1913..000000000 --- a/data-tools/PhotoDisintegration/photodis_combine.py +++ /dev/null @@ -1,51 +0,0 @@ -# This script combines the photodisintegration rate tables for CMB and IRB. - -from numpy import * - - -fout = open('photodis_CMB_IRB.txt', 'w') -fout.write('#Z, N, disintegration channel (#n#p#H2#H3#He3#He4), disintegration rate [1/Mpc] (200 samples for log10(gamma) = 6-14)\n') - - -data1 = genfromtxt('photodis_CMB.txt', skip_header=1, unpack=True) -Z1, N1, channel1 = data1[0], data1[1], data1[2] - -data2 = genfromtxt('photodis_IRB.txt', skip_header=1, unpack=True) -Z2, N2, channel2 = data2[0], data2[1], data2[2] - -# Create unique identifiers for each species + channel -ID1 = Z1 * 1e8 + N1 * 1e6 + channel1 -ID2 = Z2 * 1e8 + N2 * 1e6 + channel2 - - -# Create a dictionary (id -> index) of ID1 for lookups -d = {} -for i, id1 in enumerate(ID1): - d[id1] = i - - -# loop over and save all IRB data while adding the corresponding CMB data -for i, id2 in enumerate(ID2): - rate = data2[3:, i] - - # find the CMB rate for the same channel if available - if d.has_key(id2): - j = d.pop(id2) # get and remove the dictionary entry - rate += data1[3:, j] # add up the inverse mean free paths - - fout.write('%i\t%i\t%i'%(Z2[i], N2[i], channel2[i])) - for r in rate: - fout.write('\t'+str(r)) - fout.write('\n') - - -# write the remaining CMB rates -keys = d.keys() -keys.sort() -for id1 in keys: - i = d[id1] - fout.write('%i\t%i\t%i'%(Z1[i], N1[i], channel1[i])) - rate = data1[3:, i] - for r in rate: - fout.write('\t'+str(r)) - fout.write('\n') diff --git a/data-tools/PhotoDisintegration/photodis_reformat.py b/data-tools/PhotoDisintegration/photodis_reformat.py deleted file mode 100644 index 0a4470ce9..000000000 --- a/data-tools/PhotoDisintegration/photodis_reformat.py +++ /dev/null @@ -1,98 +0,0 @@ -from numpy import * - -# This script reformats the exclusive mean free path data files from CRPropa2. -# - The four CRPropa2 files are merged into one, -# - nuclides with Z>26 or N>30 are omitted and -# -# The folders with the date files being used, are found in [CRPropa2 source]/TabulatedTALYSMeanFreePath/. -# Copy the content or execute the script from within this folder. -# -# The used files are -# 'PDInitNucleusId.cmt' : Particle ID (Z*1000+A) and corresponding line numbers in 'PDExclTabMnFrPthCrossId.cmt' -# 'PDExclTabMnFrPthCrossId.cmt' : Disintegration channel (#n #p #H2 #H3 #He3 #He4) and data index in 'PDExclTabMnFrPthCross.cmt' -# 'PDExclTabMnFrPthCross.cmt' : Inverse mean free path in [1/Mpc] for 200 equidistant Lorentz-factors gamma = 10^6 - 10^14 -# -# CMB, IRB (Kneiske) - - -def getAZ(s): - # returns A, Z from the particle id (Z*1000+A) - pid = int(s) - return pid % 1000, pid // 1000 - - -def getDigit(number, d): - # returns the d-th digit, counted from the back - return number % (10**d) // (10**(d-1)) - - -def isBogus(Z, A, channel): - # checks if the disintegration channel is impossible or leaves an empty nucleus - nN = getDigit(channel, 6) - nP = getDigit(channel, 5) - nH2 = getDigit(channel, 4) - nH3 = getDigit(channel, 3) - nHe3 = getDigit(channel, 2) - nHe4 = getDigit(channel, 1) - - N = A - Z - - dZ = nP + nH2 + nH3 + 2*nHe3 + 2*nHe4 - dA = nN + nP + 2*nH2 + 3*nH3 + 3*nHe3 + 4*nHe4 - dN = dA - dZ - - if (Z - dZ < 0): - print 'Z\' < 0: skipping line', j - print 'Z=%i N=%i dZ=%i dN=%i channel=%i'%(Z,N,dZ,dN,channel)+'\n' - return True - if (N - dN < 0): - print 'N\' < 0: skipping line', j - print 'Z=%i N=%i dZ=%i dN=%i channel=%i'%(Z,N,dZ,dN,channel)+'\n' - return True - if (A - dA <= 0): - print 'A\' <= 0: skipping line', j - print 'Z=%i N=%i dZ=%i dN=%i channel=%i'%(Z,N,dZ,dN,channel)+'\n' - return True - - -def reformat(photonField): - # input files - data1 = genfromtxt(photonField+'/PDInitNucleusId.cmt', skip_header=1) - data2 = genfromtxt(photonField+'/PDExclTabMnFrPthCrossId.cmt') - data3 = genfromtxt(photonField+'/PDExclTabMnFrPthCross.cmt') - # output file - fout = open('photodis_'+photonField+'.txt','w') - fout.write('#Z, N, disintegration channel (#n#p#H2#H3#He3#He4), disintegration rate [1/Mpc] (200 samples for log10(gamma) = 6-14)') - - for i in range(size(data1, 0)): - pid = data1[i, 0] - - A, Z = getAZ(pid) # get particle charge- and mass number - N = A - Z - - if Z>26 or N>30: # skip isotopes heavier than Fe-56 - continue - - j0 = int(data1[i, 1]) # start index for channels in 'PDExclTabMnFrPthCrossId.cmt' - j1 = int(data1[i, 2]) # end index - - for j in range(j0, j1): - channel = int(data2[j, 0]) - - if isBogus(Z,A,channel): - print ' .. in line', j - continue - - fout.write('\n') - fout.write(str(Z)+'\t'+str(N)+'\t') # write the particle's Z, N - fout.write(str(channel)) # write disintegration channel - - k0 = int(data2[j, 1]) # start index in 'PDExclTabMnFrPthCross.cmt' - - for rate in data3[k0:k0 + 200]: - fout.write('\t'+str(rate)) - - -reformat('CMB') -reformat('IRB') - diff --git a/data-tools/PhotoPionProduction/photopion.py b/data-tools/PhotoPionProduction/photopion.py deleted file mode 100644 index 82f54e27f..000000000 --- a/data-tools/PhotoPionProduction/photopion.py +++ /dev/null @@ -1,55 +0,0 @@ -from numpy import * - -# This script reformats the pion production rate data files from CRPropa2. -# -# The data files used are found in CRPropa/src/Interactions/proton_sophia/ -# Copy the content or execute the script from within this folder. -# The used files are -# 'pionprodrate_n' : pion production rates of neutrons against the CMB -# 'pionprodrate_n_ir_y0' : pion production rates of neutrons against the IRB (Kneiske) -# 'pionprodrate_p' : pion production rates of protons against the CMB -# 'pionprodrate_p_ir_y0' : pion production rates of protons against the IRB (Kneiske) - -# Interaction rates smaller than 1 / 1000 Gpc are not tabulated for the CMB. -# Even when accounting for cosmology these will not influence typical simulation results. -# For symmetry with the CMB rates, and for performance reasons the threshold is also applied to the IRB rates. -threshold = 1e-6 - -# pion production rate on the CMB -energies, nRate = genfromtxt('pionprodrate_n.txt', comments='#', unpack=True) -energies2, pRate = genfromtxt('pionprodrate_p.txt', comments='#', unpack=True) -if any(energies != energies2): - print 'Mismatch of tabulated energies' - -# save to one file, skip 0 entries -fout1 = open('photopion_CMB.txt', 'w') -fout1.write('# Pion production rate for protons and neutrons on the CMB\n') -fout1.write('# Energy [EeV], Rate [1/Mpc]\n') - -for E, p, n in zip(energies, pRate, nRate): - if (p < threshold) and (n < threshold): - print 'CMB: skip', E, 'EeV:', p, n - continue - fout1.write('%7g %.6f %.6f\n'%( E, p, n )) - -fout1.close() - - -# pion production rate on the IRB (Kneiske 2002) -energies, nRate = genfromtxt('pionprodrate_n_ir_y0.txt', comments='#', unpack=True) -energies2, pRate = genfromtxt('pionprodrate_p_ir_y0.txt', comments='#', unpack=True) -if any(energies != energies2): - print 'Mismatch of tabulated energies' - -# save to one file, skip 0 entries -fout2 = open('photopion_IRB.txt', 'w') -fout2.write('# Pion production rate for protons and neutrons on IRB\n') -fout2.write('# Energy [EeV], Rate [1/Mpc]\n') - -for E, p, n in zip(energies, pRate, nRate): - if (p < threshold) and (n < threshold): - print 'IRB: skip', E, 'EeV:', p, n - continue - fout2.write('%8.6g %.6f %.6f\n'%( E, p, n )) - -fout2.close() diff --git a/data-tools/PhotonField/Kneiske2004_IRB/z0.2.txt b/data-tools/PhotonField/Kneiske2004_IRB/z0.2.txt deleted file mode 100644 index 909aec376..000000000 --- a/data-tools/PhotonField/Kneiske2004_IRB/z0.2.txt +++ /dev/null @@ -1,64 +0,0 @@ -# IRB spectrum at z=0.2 from Kneiske et al. 2004 (astro-ph/0309141) -# lambda [micrometer] lambda I_lambda [nW/m^2/sr] -0.00985395 0.1 -0.099995 0.0984353 -0.102355 0.14601 -0.105923 0.209854 -0.112089 0.326361 -0.117307 0.499609 -0.122731 0.69577 -0.12847 1.13447 -0.132901 1.4601 -0.14532 2.03338 -0.158908 2.87676 -0.171851 4.00627 -0.191997 4.69065 -0.224162 5.32142 -0.247655 5.94255 -0.292235 5.94255 -0.360437 6.13298 -0.434854 6.32951 -0.513441 7.64824 -0.619853 9.6895 -0.808412 12.2756 -1.07753 14.1477 -1.32921 15.3085 -1.79064 15.5518 -2.18354 14.3726 -2.63277 12.2756 -3.10434 9.6895 -3.66001 7.41076 -4.50919 5.40601 -5.55624 4.13465 -6.69967 3.58752 -7.73194 3.42174 -9.53837 3.76134 -12.2972 4.06995 -14.039 4.13465 -17.3111 3.94358 -21.3405 3.47613 -27.8015 3.1128 -32.4394 2.92249 -37.4451 2.96895 -45.1943 3.47613 -50.5076 4.47389 -56.4399 5.57924 -62.3863 7.29481 -68.9662 9.84353 -73.7352 12.0835 -85.1733 15.3085 -94.1327 19.0907 -107.515 22.3519 -131.185 24.9609 -169.043 23.0682 -203.8 19.0907 -240.316 15.3085 -274.161 12.4707 -326.74 8.81466 -376.703 6.13298 -443.93 4.06995 -540.492 2.30682 -629.928 1.50689 -717.957 0.909712 -836.422 0.523815 -963.886 0.316228 diff --git a/data-tools/PhotonField/Kneiske2004_IRB/z0.4.txt b/data-tools/PhotonField/Kneiske2004_IRB/z0.4.txt deleted file mode 100644 index db6792f2b..000000000 --- a/data-tools/PhotonField/Kneiske2004_IRB/z0.4.txt +++ /dev/null @@ -1,58 +0,0 @@ -# IRB spectrum at z=0.4 from Kneiske et al. 2004 (astro-ph/0309141) -# lambda [micrometer] lambda I_lambda [nW/m^2/sr] -0.0102228 0.0979217 -0.1 0.101591 -0.101108 0.185114 -0.110424 0.434323 -0.133169 2.28033 -0.177339 5.52437 -0.23616 6.57652 -0.284804 6.37481 -0.351119 6.27795 -0.428133 6.38076 -0.499533 7.83733 -0.595826 9.7801 -0.7427 11.2791 -0.946404 13.426 -1.21934 13.8647 -1.65995 14.0953 -2.04647 12.8274 -2.52298 11.1335 -2.97635 8.5158 -3.43467 6.93785 -4.14214 5.14192 -4.88647 4.25602 -5.57714 3.69335 -6.95193 3.58034 -8.11131 3.75534 -10 4.19621 -12.3285 4.13245 -15.5377 3.94336 -19.7993 3.5327 -23.8776 3.26593 -29.1149 3.11625 -32.1497 2.97276 -41.8803 3.48332 -48.3293 5.17087 -53.9582 6.8723 -60.2427 9.5766 -67.2591 12.332 -73.4562 16.6498 -81.1131 19.1964 -90.5603 22.4854 -102.228 26.3386 -121.934 27.6274 -142.269 25.9456 -164.177 23.6082 -189.458 19.8508 -231.013 14.7126 -269.539 10.5643 -325.059 7.35044 -383.471 4.65179 -452.379 2.99078 -522.039 1.83381 -609.101 1.07242 -702.894 0.657561 -793.454 0.416101 -936.035 0.214468 -989.043 0.177473 diff --git a/data-tools/PhotonField/Kneiske2004_IRB/z0.6.txt b/data-tools/PhotonField/Kneiske2004_IRB/z0.6.txt deleted file mode 100644 index f64e79d1a..000000000 --- a/data-tools/PhotonField/Kneiske2004_IRB/z0.6.txt +++ /dev/null @@ -1,48 +0,0 @@ -# IRB spectrum at z=0.6 from Kneiske et al. 2004 (astro-ph/0309141) -# lambda [micrometer] lambda I_lambda [nW/m^2/sr] -0.01 0.1 -0.0989043 0.0984246 -0.1 0.263445 -0.104505 0.431005 -0.111647 0.727895 -0.120598 1.39581 -0.133169 3.34301 -0.157099 4.44914 -0.175396 5.73615 -0.223502 6.83098 -0.311045 6.30957 -0.383471 6.21017 -0.432876 6.41057 -0.53367 8.26497 -0.695193 10 -0.967489 11.3546 -1.30266 12.2929 -1.75396 11.9086 -2.23502 10.1601 -2.94374 7.05141 -3.71003 4.97224 -4.52379 3.91835 -5.89298 3.45089 -8.20117 3.79586 -11.0424 4.0448 -16.2378 3.6772 -21.3867 3.23851 -31.1045 2.8978 -40.5187 3.85662 -52.2039 8.0066 -65.0724 14.4086 -73.4562 19.7948 -86.6561 24.3336 -101.108 27.6299 -127.427 27.6299 -153.675 23.9503 -195.824 17.4333 -231.013 13.0991 -284.804 8.13476 -343.467 4.97224 -400.747 3.0392 -467.581 1.88739 -557.714 1.06558 -665.222 0.538313 -820.117 0.243336 -956.888 0.130991 diff --git a/data-tools/PhotonField/Kneiske2004_IRB/z0.txt b/data-tools/PhotonField/Kneiske2004_IRB/z0.txt deleted file mode 100644 index 9f953c29d..000000000 --- a/data-tools/PhotonField/Kneiske2004_IRB/z0.txt +++ /dev/null @@ -1,52 +0,0 @@ -# IRB spectrum at z=0 from Kneiske et al. 2004 (astro-ph/0309141) -# lambda [micrometer] lambda I_lambda [nW/m^2/sr] -#0.0106042 0.100515 -0.108004 0.0999824 -0.131465 0.59631 -0.172908 2.01281 -0.243002 4.72253 -0.357061 5.7039 -0.425743 6.17053 -0.536264 7.94205 -0.682947 10.2219 -0.84152 13.1572 -1.01444 15.1623 -1.26395 16.9278 -1.64574 17.7392 -2.23948 16.3795 -2.82198 12.7125 -3.59536 9.71151 -4.43228 6.85565 -5.46395 4.91673 -6.51661 3.87727 -7.27515 3.36227 -8.48614 3.46904 -9.68368 3.4136 -10.8092 3.57848 -12.608 3.87142 -15.0338 3.99416 -17.5367 3.99275 -20.6839 3.68794 -25.7758 3.29997 -31.7706 2.861 -37.4707 2.77091 -44.1891 3.04543 -51.5369 3.79845 -60.1011 5.29198 -67.8134 7.37332 -79.9551 10.6022 -93.2417 14.7709 -109.949 18.4226 -126.838 20.8992 -149.583 22.2549 -194.794 19.5994 -237.481 16.2057 -283.23 12.9832 -334.122 9.46058 -377.168 7.46144 -449.894 4.9449 -530.785 3.17522 -640.183 1.91385 -763.711 1.10017 -931.467 0.531461 -984.255 0.453697 diff --git a/data-tools/PhotonField/Kneiske2004_IRB/z1.txt b/data-tools/PhotonField/Kneiske2004_IRB/z1.txt deleted file mode 100644 index 7a50f9300..000000000 --- a/data-tools/PhotonField/Kneiske2004_IRB/z1.txt +++ /dev/null @@ -1,62 +0,0 @@ -# IRB spectrum at z=1 from Kneiske et al. 2004 (astro-ph/0309141) -# lambda [micrometer] lambda I_lambda [nW/m^2/sr] -0.0101483 0.0984299 -0.0905746 0.1 -0.0945105 0.158239 -0.0954499 0.224138 -0.0963792 0.338228 -0.0983741 0.543745 -0.099387 0.689426 -0.103722 1.04036 -0.113137 1.47362 -0.121995 2.44521 -0.132982 4.25467 -0.156758 4.98419 -0.182782 5.65688 -0.217955 5.65688 -0.268684 5.22653 -0.310065 4.82891 -0.382097 4.98419 -0.431177 5.22653 -0.52532 6.12268 -0.647195 6.83993 -0.833336 7.2869 -1.04961 7.88692 -1.36665 8.01272 -1.74099 7.76309 -2.12336 6.52278 -2.42432 5.48064 -2.86151 4.25467 -3.64826 3.20003 -4.96664 2.73166 -6.46616 2.86447 -8.99049 3.25108 -11.0813 3.14979 -15.2488 2.91016 -19.0077 2.605 -27.3314 2.44521 -31.8832 2.40682 -37.152 3.35562 -41.8987 4.25467 -46.2076 6.02655 -51.5257 8.40231 -58.0827 12.2842 -64.7839 15.8239 -77.1764 21.3745 -95.0718 24.6463 -121.138 22.4138 -146.119 19.1332 -174.404 14.1645 -217.582 9.68845 -251.359 6.42037 -296.808 4.39149 -350.599 2.68877 -409.628 1.6204 -452.825 1.09094 -511.789 0.700424 -578.431 0.449698 -646.404 0.317481 -714.822 0.191332 -781.559 0.128815 -844.796 0.1 -985.441 0.1 diff --git a/data-tools/PhotonField/Kneiske2004_IRB/z2.txt b/data-tools/PhotonField/Kneiske2004_IRB/z2.txt deleted file mode 100644 index 0db035ae3..000000000 --- a/data-tools/PhotonField/Kneiske2004_IRB/z2.txt +++ /dev/null @@ -1,65 +0,0 @@ -# IRB spectrum at z=2 from Kneiske et al. 2004 (astro-ph/0309141) -# lambda [micrometer] lambda I_lambda [nW/m^2/sr] -0.0098556 0.105395 -0.0925665 0.100018 -0.0958171 0.155455 -0.0992666 0.315818 -0.1074 0.506529 -0.118811 0.851675 -0.125696 1.22341 -0.13592 1.65 -0.155211 1.81302 -0.175303 2.02382 -0.209154 2.023 -0.241404 1.99073 -0.291083 1.72685 -0.328599 1.64668 -0.379286 1.64614 -0.428278 1.69836 -0.500001 1.89569 -0.564642 2.01843 -0.711959 2.08193 -0.948682 2.18126 -1.23652 2.28543 -1.59384 2.32038 -1.90104 2.11026 -2.21784 1.88926 -2.61496 1.46779 -3.01635 1.19559 -3.29373 1.08755 -3.88526 0.973629 -4.19663 0.928523 -4.89918 1.02021 -5.91215 1.13866 -7.29561 1.37494 -8.8023 1.44086 -10.5026 1.46315 -12.6658 1.33062 -15.9623 1.17244 -21.259 1.04934 -25.9301 1.04887 -30.9403 1.082 -34.5691 1.2864 -38.6332 1.65474 -42.6906 1.96738 -46.1536 2.49134 -49.9077 3.36004 -55.1796 4.7507 -59.6498 5.82935 -65.921 7.15255 -74.4959 9.49482 -86.976 10.7663 -100.417 11.6448 -117.163 10.759 -135.174 9.33372 -155.931 7.72352 -183.824 5.72353 -223.876 3.56635 -263.75 2.15344 -314.142 1.25994 -370 0.703155 -435.702 0.368457 -496.565 0.219022 -572.151 0.126152 -604.15 0.0995907 -970.987 0.099483 diff --git a/data-tools/PhotonField/Kneiske2004_IRB/z3.txt b/data-tools/PhotonField/Kneiske2004_IRB/z3.txt deleted file mode 100644 index 02102bb22..000000000 --- a/data-tools/PhotonField/Kneiske2004_IRB/z3.txt +++ /dev/null @@ -1,62 +0,0 @@ -# IRB spectrum at z=3 from Kneiske et al. 2004 (astro-ph/0309141) -# lambda [micrometer] lambda I_lambda [nW/m^2/sr] -0.01 0.0994467 -0.0956888 0.0999894 -0.1 0.173203 -0.106834 0.241658 -0.116677 0.385215 -0.130266 0.634872 -0.134644 0.737533 -0.153675 0.828938 -0.177339 0.916316 -0.218632 0.843567 -0.263665 0.726533 -0.321497 0.636256 -0.371003 0.636475 -0.447422 0.64745 -0.527823 0.703921 -0.602427 0.7402 -0.759246 0.704538 -0.946404 0.753444 -1.1797 0.779362 -1.43845 0.833417 -1.73474 0.862018 -2.00187 0.742345 -2.25978 0.683263 -2.60776 0.523691 -2.94374 0.421916 -3.32301 0.388337 -3.96357 0.401653 -4.52379 0.459008 -5.27823 0.551442 -6.29569 0.651589 -7.427 0.744694 -8.85867 0.77023 -10.5663 0.720923 -12.8839 0.60059 -17.7339 0.517431 -23.616 0.526479 -30.7637 0.572536 -35.1119 0.735148 -39.2014 0.975846 -41.8803 1.15276 -44.7422 1.45551 -48.8647 1.96438 -52.2039 2.48028 -55.7714 3.23767 -63.6543 4.08861 -71.0681 5.24958 -82.0117 5.90034 -97.8207 6.52281 -116.677 5.61771 -136.135 4.52631 -158.839 3.41204 -183.298 2.36662 -211.524 1.58776 -238.776 1.06516 -278.597 0.636036 -325.059 0.349464 -371.003 0.226772 -414.214 0.137669 -452.379 0.102049 -1000 0.100556 diff --git a/data-tools/PhotonField/Kneiske2004_IRB/z4.txt b/data-tools/PhotonField/Kneiske2004_IRB/z4.txt deleted file mode 100644 index fb18281f2..000000000 --- a/data-tools/PhotonField/Kneiske2004_IRB/z4.txt +++ /dev/null @@ -1,57 +0,0 @@ -# IRB spectrum at z=4 from Kneiske et al. 2004 (astro-ph/0309141) -# lambda [micrometer] lambda I_lambda [nW/m^2/sr] -0.0101108 0.1 -0.101108 0.101664 -0.111647 0.164079 -0.120598 0.239844 -0.128839 0.333655 -0.139168 0.406742 -0.165995 0.406742 -0.213867 0.36236 -0.255093 0.312337 -0.307637 0.264813 -0.347272 0.252019 -0.437672 0.247894 -0.53367 0.256214 -0.650724 0.239844 -0.759246 0.235917 -0.925779 0.264813 -1.1797 0.287595 -1.64177 0.32282 -1.77339 0.317535 -2.04647 0.273701 -2.44096 0.213673 -2.87959 0.164079 -3.14491 0.139113 -3.62918 0.16681 -4.28133 0.206734 -4.9406 0.256214 -5.63892 0.32282 -6.72591 0.36236 -7.67657 0.380755 -9.15635 0.356428 -11.4134 0.292381 -13.7644 0.247894 -17.7339 0.239844 -23.1013 0.26922 -28.4804 0.278256 -31.7975 0.287595 -35.1119 0.400083 -40.0747 0.565833 -45.2379 0.813569 -51.0663 1.24961 -55.1603 1.68192 -63.6543 2.30148 -73.4562 2.89978 -83.8388 3.0977 -96.7489 3.14926 -114.134 2.58337 -133.169 2.11917 -153.675 1.4984 -181.29 0.991781 -206.914 0.645708 -241.421 0.400083 -272.525 0.256214 -304.266 0.16681 -351.119 0.101664 -989.043 0.0983629 diff --git a/data-tools/PhotonField/Kneiske2004_IRB_scaling.py b/data-tools/PhotonField/Kneiske2004_IRB_scaling.py deleted file mode 100644 index 6f277da59..000000000 --- a/data-tools/PhotonField/Kneiske2004_IRB_scaling.py +++ /dev/null @@ -1,91 +0,0 @@ -from pylab import * -from scipy.interpolate import interp1d -from scipy.integrate import quad -from scipy.optimize import brentq -from crpropa import h_planck, c_light, k_boltzmann - -# This script plots and calculates the integral of the cosmic infrared background (IRB) for different redshifts as given in Kneiske et al. 2004 (astro-ph/0309141) -# This integral can be used as an overall scaling factor for said background - -def CMBSpectralRadiance(nu, z): - """CMB spectral radiance [W/sr/m^2/Hz] at frequency nu [1/s], see http://en.wikipedia.org/wiki/Planck%27s_law""" - return 2 * nu**3 * h_planck / c_light**2 / ( exp(nu * h_planck / k_boltzmann / 2.725 / (1 + z)) - 1 ) - -def CMBSpectralEnergyDensity(nu, z): - """CMB spectral energy density [J/m^3/Hz] at frequency nu [1/s]""" - return CMBSpectralRadiance(nu, z) * 4 * pi / c_light - -def CMBSpectralNumberDensity(nu, z): - """CMB spectral number density [1/m^3/Hz] at frequency nu [1/s]""" - return CMBSpectralEnergyDensity(nu, z) / (nu * h_planck) - -def process(fname, z): - # read file - # wavelength lambda [mu m] and wavelength scaled spectral radiance lambda * I_lambda [nW/m^2/sr] - x, y = genfromtxt(fname, unpack=True) - y[y < 1.01e-1] = 0 # cut off values that are artefacts from parsing the plots from the paper - - x *= 1e-6 # [mu m] -> [m] - y *= 1e-9 # [nW/m^2/sr] -> [W/m^2/sr] - - # remove wavelength scaling - y /= x # [W/m^2/sr] -> [W/m^3/sr] - - # convert to spectral energy density dEdV_lambda - y *= 4 * pi / c_light # [W/m^3/sr] -> [J/m^3/m] - - # convert to spectral number density: divide by photon energy - y /= h_planck * c_light / x # [J/m^3/m] -> [1/m^3/m] - - # change to frequency as spectral variable: B_nu = lambda^2 / h * B_lambda - nu = c_light / x # [m] -> [Hz] - ynu = y * x**2 / c_light # [1/m^3/Hz] - - # find frequency nu0 above which the IRB number density exceeds the CMB - nu = nu[::-1] - ynu = ynu[::-1] - ynu_interp = interp1d(nu, ynu) - def objective(nu): - return CMBSpectralNumberDensity(nu, z) - ynu_interp(nu) - nu0 = brentq(objective, 3.5e11, 1e13) # frequency of intersection - - # integral of spectral number density from nu0 to nuMax - I1 = quad(ynu_interp, nu[0], nu[-1])[0] - I2 = quad(ynu_interp, nu0, nu[-1])[0] - - # plot - figure() - nuCMB = logspace(9, 14) - plot(nuCMB, CMBSpectralNumberDensity(nuCMB, z), label='CMB') - plot(nu, ynu, label='IRB Kneiske') - xlabel('Frequency [Hz]') - ylabel('Number Density [1/m$^{3}$/Hz]') - ylim(1e-16, 1) - xlim(1e9, 1e16) - text(5e14, 0.1, 'z = %.1f'%z) - loglog() - axvline(nu0, lw=1, ls='--', color='k') - savefig('z%.1f.png'%z, bbox_inches='tight') - - print z, nu0, I1, I2 - return I1, I2 - - -fnames = ['z0.txt', 'z0.2.txt', 'z0.4.txt', 'z0.6.txt', 'z1.txt', 'z2.txt', 'z3.txt', 'z4.txt'] -z = array([0, 0.2, 0.4, 0.6, 1, 2, 3, 4, 5]) - -s1, s2 = zeros(9), zeros(9) -for i in range(8): - s1[i], s2[i] = process('Kneiske2004_IRB/'+fnames[i], z[i]) - -s1 /= s1[0] -s2 /= s2[0] - -figure() -plot(z, s1) -plot(z, s2) -xlim(0, 5) -xlabel('Redshift z') -ylabel('Overall Scaling') -savefig('Kneiske2004_IRB_scaling.png',bbox_inches='tight') -show() diff --git a/data-tools/PhotonField/photonField.py b/data-tools/PhotonField/photonField.py deleted file mode 100644 index 98e6dfda1..000000000 --- a/data-tools/PhotonField/photonField.py +++ /dev/null @@ -1,77 +0,0 @@ -from pylab import * -from crpropa import h_planck, c_light, k_boltzmann, eV - - -def CMBSpectralRadiance(nu): - """CMB spectral radiance [W/sr/m^2/Hz] at frequency nu [1/s], see http://en.wikipedia.org/wiki/Planck%27s_law""" - return 2 * nu**3 * h_planck / c_light**2 / ( exp(nu * h_planck / k_boltzmann / 2.725) - 1 ) - -def CMBSpectralEnergyDensity(nu): - """CMB spectral energy density [J/m^3/Hz] at frequency nu [1/s]""" - return CMBSpectralRadiance(nu) * 4 * pi / c_light - -def CMBSpectralNumberDensity(nu): - """CMB spectral number density [1/m^3/Hz] at frequency nu [1/s]""" - return CMBSpectralEnergyDensity(nu) / (nu * h_planck) - - -def IRBSpectralRadiance(nu, fin='Kneiske2004_IRB/z0.txt'): - """IRB (Kneiske et al. 2004) spectral radiance [W/sr/m^2/Hz] at frequency nu [1/s] and z=0""" - # convert frequency [Hz] to wavelength [m] - x = c_light / nu - - # load data points - xKneiske, yKneiske = genfromtxt(fin, unpack=True) - y = interp(x * 1e6, xKneiske, yKneiske, 0, 0) * 1e-9 # lambda * I_lambda [W/m^2/sr] - - # remove scaling with lambda; I_lambda [W/m^3/sr] - y /= x - - # convert to I_nu (using I_nu = - dlambda / dnu * I_lambda, dnu = - c / lambda^2 dlambda) - y *= x**2 / c_light - return y - -def IRBSpectralEnergyDensity(nu): - """IRB (Kneiske et al. 2004) spectral energy density [J/m^3/Hz] at frequency nu [1/s]""" - return IRBSpectralRadiance(nu) * 4 * pi / c_light - -def IRBSpectralNumberDensity(nu): - """IRB (Kneiske et al. 2004) spectral number density [1/m^3/Hz] at frequency nu [1/s]""" - return IRBSpectralEnergyDensity(nu) / (nu * h_planck) - - -if __name__ == "__main__": - nu1 = logspace(-5, -2.3) * eV / h_planck - sed1 = CMBSpectralEnergyDensity(nu1) - snd1 = CMBSpectralNumberDensity(nu1) - - nu2 = logspace(-5, 1.5) * eV / h_planck - sed2 = IRBSpectralEnergyDensity(nu2) - snd2 = IRBSpectralNumberDensity(nu2) - - # number of photons per m^3 = integral over spectral number density - # integration using midpoint rule - N1 = sum( (snd1[1:] + snd1[:-1]) / 2 * (nu1[1:] - nu1[:-1]) ) - N2 = sum( (snd2[1:] + snd2[:-1]) / 2 * (nu2[1:] - nu2[:-1]) ) - print N1 / 1e6, 'CMB-photons per cubic centimeter' - print N2 / 1e6, 'IRB-photons per cubic centimeter' - - # plotting - figure() - plot(nu1, sed1, label='CMB') - plot(nu2, sed2, label='IRB Kneiske') - xlabel('Frequency [Hz]') - ylabel('Spectral Energy Density [J/m$^{3}$/Hz]') - loglog() - legend(frameon=0) -# savefig('spectralEnergyDensity.png', bbox_inches='tight') - - figure() - plot(nu1, snd1, label='CMB') - plot(nu2, snd2, label='IRB Kneiske') - xlabel('Frequency [Hz]') - ylabel('Spectral Density [1/m$^{3}$/Hz]') - loglog() - legend(frameon=0) -# savefig('spectralNumberDensity.png', bbox_inches='tight') - From a4f14bffea066443c5232b5c02d515c30a684d8b Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 17 Oct 2014 15:57:16 +0200 Subject: [PATCH 0518/1298] Fixed random aprticle generation --- .../include/parsec/ParticleMapsContainer.h | 1 - .../src/ParticleMapsContainer.cc | 25 +++++++++++++------ python/crpropa.i | 7 ++++++ 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/libs/GalacticMagneticLens/include/parsec/ParticleMapsContainer.h b/libs/GalacticMagneticLens/include/parsec/ParticleMapsContainer.h index 7b84a16e9..e6bed53c5 100644 --- a/libs/GalacticMagneticLens/include/parsec/ParticleMapsContainer.h +++ b/libs/GalacticMagneticLens/include/parsec/ParticleMapsContainer.h @@ -16,7 +16,6 @@ class ParticleMapsContainer { private: std::map< int , std::map > _data; - std::map< int , double> _weights; Pixelization _pixelization; double _deltaLogE; double _bin0lowerEdge; diff --git a/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc b/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc index d0cecbe13..43e376435 100644 --- a/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc +++ b/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc @@ -50,7 +50,6 @@ void ParticleMapsContainer::addParticle(const int particleId, double energy, dou { map M; _data[particleId] = M; - _weights[particleId] = 0; } int energyIdx = energy2Idx(energy); @@ -62,7 +61,6 @@ void ParticleMapsContainer::addParticle(const int particleId, double energy, dou uint32_t pixel = _pixelization.direction2Pix(galacticLongitude, galacticLatitude); _data[particleId][energyIdx][pixel] +=weight; - _weights[particleId] +=weight; } @@ -149,10 +147,21 @@ void ParticleMapsContainer::getRandomParticles(size_t N, vector &particleId vector &galacticLatitudes) { double sumOfWeights = 0; - for(std::map::iterator iter = _weights.begin(); iter != _weights.end(); ++iter) - { - sumOfWeights += iter->second; - } + std::map< int , double> _weights; + + for(std::map >::iterator pid_iter = _data.begin(); + pid_iter != _data.end(); ++pid_iter) { + _weights[pid_iter->first] = 0; + + for(std::map::iterator energy_iter = pid_iter->second.begin(); + energy_iter != pid_iter->second.end(); ++energy_iter) { + for(size_t j=0; j< _pixelization.getNumberOfPixels() ; j++) + { + _weights[pid_iter->first]+=energy_iter->second[j]; + } + sumOfWeights+=_weights[pid_iter->first]; + } + } particleId.resize(N); energy.resize(N); @@ -166,13 +175,13 @@ void ParticleMapsContainer::getRandomParticles(size_t N, vector &particleId while ((r-= iter->second) > 0) { - ++iter; + ++iter; } particleId[i] = iter->first; bool foundParticle = false; - // // loop over maps + //// // loop over maps for(std::map::iterator energy_iter = _data[iter->first].begin(); !foundParticle; ++energy_iter ) { diff --git a/python/crpropa.i b/python/crpropa.i index a061c5558..130f7c650 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -265,6 +265,9 @@ __WITHNUMPY = False %include typemaps.i +%template(IntVector) std::vector; +%template(DoubleVector) std::vector; + %{ #include "parsec/ModelMatrix.h" #include "parsec/Pixelization.h" @@ -362,6 +365,10 @@ MagneticLens.transformModelVector = MagneticLens.transformModelVector_numpyArray return out; } + + + + }; #else %extend parsec::ParticleMapsContainer{ From a7c28529a1670952f5a4edad057b7d9ed9afdb4e Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Mon, 20 Oct 2014 11:31:42 +0200 Subject: [PATCH 0519/1298] Fixed generation of random particles. --- .../include/parsec/MagneticLens.h | 54 +++--- .../GalacticMagneticLens/src/MagneticLens.cpp | 1 + .../src/ParticleMapsContainer.cc | 160 +++++++++--------- 3 files changed, 115 insertions(+), 100 deletions(-) diff --git a/libs/GalacticMagneticLens/include/parsec/MagneticLens.h b/libs/GalacticMagneticLens/include/parsec/MagneticLens.h index a9941299d..f1a8628d4 100644 --- a/libs/GalacticMagneticLens/include/parsec/MagneticLens.h +++ b/libs/GalacticMagneticLens/include/parsec/MagneticLens.h @@ -2,22 +2,22 @@ // This file is part of PARSEC (http://physik.rwth-aachen.de/parsec) // a parametrized simulation engine for cosmic rays. // -// Copyright (C) 2011 Martin Erdmann, Peter Schiffer, Tobias Winchen -// RWTH Aachen University, Germany +// Copyright (C) 2011 Martin Erdmann, Peter Schiffer, Tobias Winchen +// RWTH Aachen University, Germany // Contact: winchen@physik.rwth-aachen.de // -// This program is free software: you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation, either version 3 of -// the License, or (at your option) any later version. +// This program is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. // -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . //---------------------------------------------------------------------- #ifndef MAGNETICLENS_HH @@ -55,7 +55,7 @@ class LensPart { } /// File containing the matrix to be used in the range rigidityMin, - /// rigidityMax with logarithmic units [log10(E / eV)] + /// rigidityMax with logarithmic units [log10(E / eV)] LensPart(const std::string &filename, double rigidityMin, double rigidityMax) : _filename(filename), _rigidityMin(rigidityMin), _rigidityMax(rigidityMax), _maximumSumOfColumns_calculated( false), _maximumSumOfColumns(0) @@ -88,7 +88,7 @@ class LensPart } return _maximumSumOfColumns; } - + /// Returns the minimum of the rigidity range for the lenspart in [log10(E/ eV)] double getMinimumRigidity() { @@ -113,7 +113,7 @@ class LensPart M = m; } - + }; /// Function to calculate the mean deflection [rad] of the matrix M, given a pixelization @@ -154,13 +154,13 @@ class MagneticLens // minimum / maximum rigidity [log10(E / eV)] that is covered by the lens double _minimumRigidity; double _maximumRigidity; - static bool _randomSeeded; + double _norm; public: /// Default constructor MagneticLens() : - _pixelization(NULL), _minimumRigidity(-1), _maximumRigidity(-1) + _pixelization(NULL), _minimumRigidity(-1), _maximumRigidity(-1), _norm(1) { } @@ -203,7 +203,7 @@ class MagneticLens /// Rigidity is given in EeV, phi and theta in rad bool transformCosmicRay(double rigidity, double& phi, double& theta); - /// transforms the model assuming that model points to an array of the + /// transforms the model array assuming that model points to an array of the /// correct size void transformModelVector(double* model, double rigidity) const; @@ -242,6 +242,12 @@ class MagneticLens return pow(10, _maximumRigidity - 18); } + // returns the norm used for the lenses + double getNorm() + { + return _norm; + } + /// Returns iterator to the lens part with rigidity [log10(E / eV)] LensPart* getLensPart(double rigidity) const; @@ -251,12 +257,12 @@ class MagneticLens return _lensParts; } - //calculates the mean deflection at given rigidity [EeV] - //double getMeanDeflection(double rigidity) const - //{ - // LensPart* lp = getLensPart(log10(rigidity) + 18); - // return calculateMeanDeflection(lp->getMatrix(), *_pixelization); - //} + //calculates the mean deflection at given rigidity [EeV] + //double getMeanDeflection(double rigidity) const + //{ + // LensPart* lp = getLensPart(log10(rigidity) + 18); + // return calculateMeanDeflection(lp->getMatrix(), *_pixelization); + //} }; diff --git a/libs/GalacticMagneticLens/src/MagneticLens.cpp b/libs/GalacticMagneticLens/src/MagneticLens.cpp index 16841b321..b28ce29c4 100644 --- a/libs/GalacticMagneticLens/src/MagneticLens.cpp +++ b/libs/GalacticMagneticLens/src/MagneticLens.cpp @@ -226,6 +226,7 @@ void MagneticLens::normalizeLens() { (*iter)->getMatrix().normalizeMatrix(norm); } + _norm = norm; } void MagneticLens::normalizeLensparts() diff --git a/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc b/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc index 43e376435..844baffef 100644 --- a/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc +++ b/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc @@ -8,89 +8,89 @@ namespace parsec ParticleMapsContainer::~ParticleMapsContainer() { - for(std::map >::iterator pid_iter = _data.begin(); + for(std::map >::iterator pid_iter = _data.begin(); pid_iter != _data.end(); ++pid_iter) { for(std::map::iterator energy_iter = pid_iter->second.begin(); energy_iter != pid_iter->second.end(); ++energy_iter) { - delete[] (energy_iter->second); + delete[] (energy_iter->second); } } } int ParticleMapsContainer::energy2Idx(double energy) const { - double lE = log10(energy); - return int((lE - _bin0lowerEdge) / _deltaLogE); + double lE = log10(energy); + return int((lE - _bin0lowerEdge) / _deltaLogE); } double ParticleMapsContainer::idx2Energy(int idx) const { - return pow(10, idx * _deltaLogE + _bin0lowerEdge + _deltaLogE / 2); + return pow(10, idx * _deltaLogE + _bin0lowerEdge + _deltaLogE / 2); } double* ParticleMapsContainer::getMap(const int particleId, double energy) { - if (_data.find(particleId) == _data.end()) - { - return NULL; - } - int energyIdx = energy2Idx(energy); - if (_data[particleId].find(energyIdx) == _data[particleId].end()) - { - return NULL; - } - return _data[particleId][energy2Idx(energy)]; + if (_data.find(particleId) == _data.end()) + { + return NULL; + } + int energyIdx = energy2Idx(energy); + if (_data[particleId].find(energyIdx) == _data[particleId].end()) + { + return NULL; + } + return _data[particleId][energy2Idx(energy)]; } void ParticleMapsContainer::addParticle(const int particleId, double energy, double galacticLongitude, double galacticLatitude, double weight) { - if (_data.find(particleId) == _data.end()) - { - map M; - _data[particleId] = M; - } - - int energyIdx = energy2Idx(energy); - if (_data[particleId].find(energyIdx) == _data[particleId].end()) - { - _data[particleId][energyIdx] = new double[_pixelization.getNumberOfPixels()]; - std::fill(_data[particleId][energyIdx], _data[particleId][energyIdx] + _pixelization.getNumberOfPixels(), 0); - } - - uint32_t pixel = _pixelization.direction2Pix(galacticLongitude, galacticLatitude); - _data[particleId][energyIdx][pixel] +=weight; + if (_data.find(particleId) == _data.end()) + { + map M; + _data[particleId] = M; + } + + int energyIdx = energy2Idx(energy); + if (_data[particleId].find(energyIdx) == _data[particleId].end()) + { + _data[particleId][energyIdx] = new double[_pixelization.getNumberOfPixels()]; + std::fill(_data[particleId][energyIdx], _data[particleId][energyIdx] + _pixelization.getNumberOfPixels(), 0); + } + + uint32_t pixel = _pixelization.direction2Pix(galacticLongitude, galacticLatitude); + _data[particleId][energyIdx][pixel] +=weight; } void ParticleMapsContainer::addParticlesFromFile(const std::string inputFileName, double sourceEnergyWeightExponent) { - std::ifstream infile(inputFileName.c_str()); - - while (infile.good()) { - if (infile.peek() != '#') { - int particleId, sourceId; - double trajectoryLength, energy, sourceEnergy, pX, pY, pZ, x, y, z, pX0, pY0, pZ0, x0, y0, z0, redShift; - - infile >> trajectoryLength - >> particleId - >> sourceId - >> energy - >> sourceEnergy - >> x >> y >> z - >> x0 >> y0 >> z0 - >> pX >> pY >> pZ - >> pX0 >> pY0 >> pZ0 - >> redShift; - - double weight = pow(sourceEnergy, sourceEnergyWeightExponent); - double galacticLongitude = atan2(-pY, -pX); - double galacticLatitude = M_PI / 2 - acos(-pZ / sqrt(pX*pX + pY*pY + pZ*pZ)); - addParticle(particleId, energy * 1E18, galacticLongitude, galacticLatitude, weight); - } + std::ifstream infile(inputFileName.c_str()); + + while (infile.good()) { + if (infile.peek() != '#') { + int particleId, sourceId; + double trajectoryLength, energy, sourceEnergy, pX, pY, pZ, x, y, z, pX0, pY0, pZ0, x0, y0, z0, redShift; + + infile >> trajectoryLength + >> particleId + >> sourceId + >> energy + >> sourceEnergy + >> x >> y >> z + >> x0 >> y0 >> z0 + >> pX >> pY >> pZ + >> pX0 >> pY0 >> pZ0 + >> redShift; + + double weight = pow(sourceEnergy, sourceEnergyWeightExponent); + double galacticLongitude = atan2(-pY, -pX); + double galacticLatitude = M_PI / 2 - acos(-pZ / sqrt(pX*pX + pY*pY + pZ*pZ)); + addParticle(particleId, energy * 1E18, galacticLongitude, galacticLatitude, weight); + } infile.ignore(std::numeric_limits < std::streamsize > ::max(), '\n'); - } + } infile.close(); } @@ -132,11 +132,17 @@ void ParticleMapsContainer::applyLens(MagneticLens &lens) // // transform only nuclei double energy = idx2Energy(energy_iter->first) / 1E18; int chargeNumber = HepPID::Z(pid_iter->first); - if (chargeNumber != 0) - { - lens.transformModelVector(energy_iter->second, energy / chargeNumber); - } - + if (chargeNumber != 0 && lens.rigidityCovered(energy / chargeNumber)) + { + lens.transformModelVector(energy_iter->second, energy / chargeNumber); + } + else + { // still normalize the vectors + for(size_t j=0; j< _pixelization.getNumberOfPixels() ; j++) + { + energy_iter->second[j]/=lens.getNorm(); + } + } } } } @@ -147,20 +153,20 @@ void ParticleMapsContainer::getRandomParticles(size_t N, vector &particleId vector &galacticLatitudes) { double sumOfWeights = 0; - std::map< int , double> _weights; + std::map< int , double> _weights; for(std::map >::iterator pid_iter = _data.begin(); pid_iter != _data.end(); ++pid_iter) { - _weights[pid_iter->first] = 0; + _weights[pid_iter->first] = 0; for(std::map::iterator energy_iter = pid_iter->second.begin(); energy_iter != pid_iter->second.end(); ++energy_iter) { for(size_t j=0; j< _pixelization.getNumberOfPixels() ; j++) { - _weights[pid_iter->first]+=energy_iter->second[j]; - } - sumOfWeights+=_weights[pid_iter->first]; + _weights[pid_iter->first]+=energy_iter->second[j]; + } } + sumOfWeights+=_weights[pid_iter->first]; } particleId.resize(N); @@ -171,26 +177,28 @@ void ParticleMapsContainer::getRandomParticles(size_t N, vector &particleId for(size_t i=0; i< N; i++) { double r = Random::instance().rand() * sumOfWeights; - std::map::iterator iter = _weights.begin(); - - while ((r-= iter->second) > 0) - { - ++iter; - } - - particleId[i] = iter->first; + std::map::iterator iter = _weights.begin(); + while ((r-= iter->second) > 0) + { + ++iter; + } + + particleId[i] = iter->first; + bool foundParticle = false; + r = Random::instance().rand() * iter->second; //// // loop over maps - for(std::map::iterator energy_iter = - _data[iter->first].begin(); !foundParticle; ++energy_iter ) + for(std::map::iterator energy_iter = + _data[iter->first].begin(); !foundParticle; ++energy_iter ) { + for(size_t j=0; j< _pixelization.getNumberOfPixels() && !foundParticle; j++) { // if this is too slow I need to store the weights for the energies // alongside the maps - r+= energy_iter->second[j]; - if (r >=0) + r-= energy_iter->second[j]; + if (r <=0) { foundParticle = true; energy[i] = idx2Energy(energy_iter->first); From c818aa856ccc7186644824218e9c7a58b702bbf2 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 21 Oct 2014 12:08:52 +0200 Subject: [PATCH 0520/1298] revert formatting --- src/module/PhotoPionProduction.cpp | 585 +++++++++++++++-------------- 1 file changed, 296 insertions(+), 289 deletions(-) diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index a153380a4..addde8080 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -14,299 +14,306 @@ namespace crpropa { - PhotoPionProduction::PhotoPionProduction(PhotonField field, bool photons, - bool neutrinos, bool antiNucleons, double l) { - photonField = field; - havePhotons = photons; - haveNeutrinos = neutrinos; - haveAntiNucleons = antiNucleons; - doRedshiftDependent = false; - limit = l; - init(); - } - - void PhotoPionProduction::setPhotonField(PhotonField photonField) { - this->photonField = photonField; - init(); - } - - void PhotoPionProduction::setHavePhotons(bool b) { - havePhotons = b; - } - - void PhotoPionProduction::setHaveNeutrinos(bool b) { - haveNeutrinos = b; - } - - void PhotoPionProduction::setHaveAntiNucleons(bool b) { - haveAntiNucleons = b; - } - - void PhotoPionProduction::setLimit(double l) { - limit = l; - } - - void PhotoPionProduction::init() { - switch (photonField) { - case CMB: - setDescription("PhotoPionProduction: CMB"); - init(getDataPath("ppp_CMB.txt")); - break; - case IRB: // default: Kneiske '04 IRB model - case IRB_Kneiske04: - setDescription("PhotoPionProduction: IRB Kneiske '04"); - init(getDataPath("ppp_IRB_Kneiske04.txt")); - break; - case IRB_Kneiske10: - setDescription("PhotoPionProduction: IRB Kneiske '10 (lower limit)"); - init(getDataPath("ppp_IRB_Kneiske10.txt")); - break; - case IRB_Stecker05: - setDescription("PhotoPionProduction: IRB Stecker '05"); - init(getDataPath("ppp_IRB_Stecker05.txt")); - break; - case IRB_Franceschini08: - setDescription("PhotoPionProduction: IRB Franceschini '08"); - init(getDataPath("ppp_IRB_Franceschini08.txt")); - break; - case IRB_withRedshift_Kneiske04: - doRedshiftDependent = true; - setDescription("PhotoPionProduction: IRB with redshift Kneiske '04"); - init(getDataPath("ppp_IRBz_Kneiske04.txt")); - break; - default: - throw std::runtime_error( - "PhotoPionProduction: unknown photon background"); - } - } - - void PhotoPionProduction::init(std::string filename) { - std::ifstream infile(filename.c_str()); - if (!infile.good()) - throw std::runtime_error( - "PhotoPionProduction: could not open file " + filename); - - // clear previously loaded tables - tabLorentz.clear(); - tabRedshifts.clear(); - tabProtonRate.clear(); - tabNeutronRate.clear(); - - double zOld = -1, aOld = -1; - bool doReadLorentz = true; - - while (infile.good()) { - if (infile.peek() != '#') { - double z, a, b, c; - if (!doRedshiftDependent) infile >> a >> b >> c; - else infile >> z >> a >> b >> c; - if (infile) { - if (doRedshiftDependent && z != zOld) tabRedshifts.push_back(z); - if (a < aOld) doReadLorentz = false; - if (doReadLorentz) tabLorentz.push_back(pow(10, a)); - tabProtonRate.push_back(b / Mpc); - tabNeutronRate.push_back(c / Mpc); - zOld = z; - aOld = a; +PhotoPionProduction::PhotoPionProduction(PhotonField field, bool photons, + bool neutrinos, bool antiNucleons, double l) { + photonField = field; + havePhotons = photons; + haveNeutrinos = neutrinos; + haveAntiNucleons = antiNucleons; + doRedshiftDependent = false; + limit = l; + init(); +} + +void PhotoPionProduction::setPhotonField(PhotonField photonField) { + this->photonField = photonField; + init(); +} + +void PhotoPionProduction::setHavePhotons(bool b) { + havePhotons = b; +} + +void PhotoPionProduction::setHaveNeutrinos(bool b) { + haveNeutrinos = b; +} + +void PhotoPionProduction::setHaveAntiNucleons(bool b) { + haveAntiNucleons = b; +} + +void PhotoPionProduction::setLimit(double l) { + limit = l; +} + +void PhotoPionProduction::init() { + switch (photonField) { + case CMB: + setDescription("PhotoPionProduction: CMB"); + init(getDataPath("ppp_CMB.txt")); + break; + case IRB: // default: Kneiske '04 IRB model + case IRB_Kneiske04: + setDescription("PhotoPionProduction: IRB Kneiske '04"); + init(getDataPath("ppp_IRB_Kneiske04.txt")); + break; + case IRB_Kneiske10: + setDescription("PhotoPionProduction: IRB Kneiske '10 (lower limit)"); + init(getDataPath("ppp_IRB_Kneiske10.txt")); + break; + case IRB_Stecker05: + setDescription("PhotoPionProduction: IRB Stecker '05"); + init(getDataPath("ppp_IRB_Stecker05.txt")); + break; + case IRB_Franceschini08: + setDescription("PhotoPionProduction: IRB Franceschini '08"); + init(getDataPath("ppp_IRB_Franceschini08.txt")); + break; + case IRB_withRedshift_Kneiske04: + doRedshiftDependent = true; + setDescription("PhotoPionProduction: IRB with redshift Kneiske '04"); + init(getDataPath("ppp_IRBz_Kneiske04.txt")); + break; + default: + throw std::runtime_error( + "PhotoPionProduction: unknown photon background"); } - } - infile.ignore(std::numeric_limits::max(), '\n'); - } - - std::cout<<"Read IRB table in "<getCurrentStep(); - do { - // check if nucleus - int id = candidate->current.getId(); - if (not (isNucleus(id))) - return; - - double z = candidate->getRedshift(); - double gamma = (1 + z) * candidate->current.getLorentzFactor(); - - // check if in tabulated energy range - if (gamma < tabLorentz.front() or (gamma > tabLorentz.back())) - return; - - // find interaction with minimum random distance - Random &random = Random::instance(); - double randDistance = std::numeric_limits::max(); - int channel; // interacting particle: 1 for proton, 0 for neutron - double totalRate = 0; - - // comological scaling of interaction distance (comoving) - double scaling = pow(1 + z, 2) * photonFieldScaling(photonField, z); - - int A = massNumber(id); - int Z = chargeNumber(id); - int N = A - Z; - - // check for interaction on protons - if (Z > 0) { - double rate = (!doRedshiftDependent) - ? scaling*interpolate(gamma, tabLorentz, tabProtonRate) - : interpolate2d(z, gamma, tabRedshifts, tabLorentz, tabProtonRate); - rate *= nucleiModification(A, Z); - totalRate += rate; - channel = 1; - randDistance = -log(random.rand()) / rate; - } - - // check for interaction on neutrons - if (N > 0) { - double rate = (!doRedshiftDependent) - ? scaling*interpolate(gamma, tabLorentz, tabNeutronRate) - : interpolate2d(z, gamma, tabRedshifts, tabLorentz, tabNeutronRate); - rate *= nucleiModification(A, N); - totalRate += rate; - double d = -log(random.rand()) / rate; - if (d < randDistance) { - randDistance = d; - channel = 0; +} + +void PhotoPionProduction::init(std::string filename) { + std::ifstream infile(filename.c_str()); + if (!infile.good()) + throw std::runtime_error( + "PhotoPionProduction: could not open file " + filename); + + // clear previously loaded tables + tabLorentz.clear(); + tabRedshifts.clear(); + tabProtonRate.clear(); + tabNeutronRate.clear(); + + double zOld = -1, aOld = -1; + bool doReadLorentz = true; + + while (infile.good()) { + if (infile.peek() != '#') { + double z, a, b, c; + if (!doRedshiftDependent) + infile >> a >> b >> c; + else + infile >> z >> a >> b >> c; + if (infile) { + if (doRedshiftDependent && z != zOld) + tabRedshifts.push_back(z); + if (a < aOld) + doReadLorentz = false; + if (doReadLorentz) + tabLorentz.push_back(pow(10, a)); + tabProtonRate.push_back(b / Mpc); + tabNeutronRate.push_back(c / Mpc); + zOld = z; + aOld = a; + } + } + infile.ignore(std::numeric_limits::max(), '\n'); } - } - - // check if interaction does not happen - if (step < randDistance) { - candidate->limitNextStep(limit / totalRate); - return; - } - - // interact and repeat with remaining step - performInteraction(candidate, channel); - step -= randDistance; - } while (step > 0); - } - - void PhotoPionProduction::performInteraction(Candidate *candidate, - int channel) const { - - int id = candidate->current.getId(); - int A = massNumber(id); - int Z = chargeNumber(id); - double E = candidate->current.getEnergy(); - double EpA = E / A; - double z = candidate->getRedshift(); - - // SOPHIA simulates interactions only for protons / neutrons - // for anti-protons / neutrons assume charge symmetry and change all - // interaction products from particle <--> anti-particle - int sign = (id > 0) ? 1 : -1; - - // arguments for sophia - int nature = 1 - channel; // interacting particle: 0 for proton, 1 for neutron - double Ein = EpA / GeV; // energy of in-going nucleon in GeV - double momentaList[5][2000]; // momentum list, what are the five components? - int particleList[2000]; // particle id list - int nParticles; // number of outgoing particles - double maxRedshift = 100; // IR photon density is zero above this redshift - int dummy1; // not needed - double dummy2[2]; // not needed - int background = (photonField == CMB) ? 1 : 2; // photon background: 1 for CMB, 2 for Kneiske IRB + + std::cout << "Read IRB table in " << tabRedshifts.size() << "\t" + << tabLorentz.size() << "\t" << tabProtonRate.size() << "\t" + << tabNeutronRate.size() << std::endl; + infile.close(); +} + +double PhotoPionProduction::nucleiModification(int A, int X) const { + if (A == 1) + return 1.; + if (A <= 8) + return 0.85 * pow(X, 2. / 3.); + return 0.85 * X; +} + +void PhotoPionProduction::process(Candidate *candidate) const { + // the loop should be processed at least once for limiting the next step + double step = candidate->getCurrentStep(); + do { + // check if nucleus + int id = candidate->current.getId(); + if (not (isNucleus(id))) + return; + + double z = candidate->getRedshift(); + double gamma = (1 + z) * candidate->current.getLorentzFactor(); + + // check if in tabulated energy range + if (gamma < tabLorentz.front() or (gamma > tabLorentz.back())) + return; + + // find interaction with minimum random distance + Random &random = Random::instance(); + double randDistance = std::numeric_limits::max(); + int channel; // interacting particle: 1 for proton, 0 for neutron + double totalRate = 0; + + // comological scaling of interaction distance (comoving) + double scaling = pow(1 + z, 2) * photonFieldScaling(photonField, z); + + int A = massNumber(id); + int Z = chargeNumber(id); + int N = A - Z; + + // check for interaction on protons + if (Z > 0) { + double rate = (!doRedshiftDependent) ? + scaling * interpolate(gamma, tabLorentz, tabProtonRate) : + interpolate2d(z, gamma, tabRedshifts, tabLorentz, tabProtonRate); + rate *= nucleiModification(A, Z); + totalRate += rate; + channel = 1; + randDistance = -log(random.rand()) / rate; + } + + // check for interaction on neutrons + if (N > 0) { + double rate = (!doRedshiftDependent) ? + scaling * interpolate(gamma, tabLorentz, tabNeutronRate) : + interpolate2d(z, gamma, tabRedshifts, tabLorentz, tabNeutronRate); + rate *= nucleiModification(A, N); + totalRate += rate; + double d = -log(random.rand()) / rate; + if (d < randDistance) { + randDistance = d; + channel = 0; + } + } + + // check if interaction does not happen + if (step < randDistance) { + candidate->limitNextStep(limit / totalRate); + return; + } + + // interact and repeat with remaining step + performInteraction(candidate, channel); + step -= randDistance; + } while (step > 0); +} + +void PhotoPionProduction::performInteraction(Candidate *candidate, + int channel) const { + + int id = candidate->current.getId(); + int A = massNumber(id); + int Z = chargeNumber(id); + double E = candidate->current.getEnergy(); + double EpA = E / A; + double z = candidate->getRedshift(); + + // SOPHIA simulates interactions only for protons / neutrons + // for anti-protons / neutrons assume charge symmetry and change all + // interaction products from particle <--> anti-particle + int sign = (id > 0) ? 1 : -1; + + // arguments for sophia + int nature = 1 - channel; // interacting particle: 0 for proton, 1 for neutron + double Ein = EpA / GeV; // energy of in-going nucleon in GeV + double momentaList[5][2000]; // momentum list, what are the five components? + int particleList[2000]; // particle id list + int nParticles; // number of outgoing particles + double maxRedshift = 100; // IR photon density is zero above this redshift + int dummy1; // not needed + double dummy2[2]; // not needed + int background = (photonField == CMB) ? 1 : 2; // photon background: 1 for CMB, 2 for Kneiske IRB #pragma omp critical - { - sophiaevent_(nature, Ein, momentaList, particleList, nParticles, z, - background, maxRedshift, dummy1, dummy2, dummy2); - } - - for (int i = 0; i < nParticles; i++) { // loop over out-going particles - double Eout = momentaList[3][i] * GeV; // only the energy is used; could be changed for more detail - int pType = particleList[i]; - switch (pType) { - case 13: // proton - case 14: // neutron - if (A == 1) { - // single interacting nucleon - candidate->current.setEnergy(Eout); - candidate->current.setId(sign * nucleusId(1, 14 - pType)); - } else { - // interacting nucleon is part of nucleus: it is emitted from the nucleus - candidate->current.setEnergy(E - EpA); - candidate->current.setId(sign * nucleusId(A - 1, Z - channel)); - candidate->addSecondary(sign * nucleusId(1, 14 - pType), Eout); + { + sophiaevent_(nature, Ein, momentaList, particleList, nParticles, z, + background, maxRedshift, dummy1, dummy2, dummy2); } - break; - case -13: // anti-proton - case -14: // anti-neutron - if (haveAntiNucleons) - candidate->addSecondary(-sign * nucleusId(1, 14 + pType), Eout); - break; - case 1: // photon - if (havePhotons) - candidate->addSecondary(22, Eout); - break; - case 2: // positron - if (havePhotons) - candidate->addSecondary(sign * -11, Eout); - break; - case 3: // electron - if (havePhotons) - candidate->addSecondary(sign * 11, Eout); - break; - case 15: // nu_e - if (haveNeutrinos) - candidate->addSecondary(sign * 12, Eout); - break; - case 16: // antinu_e - if (haveNeutrinos) - candidate->addSecondary(sign * -12, Eout); - break; - case 17: // nu_muon - if (haveNeutrinos) - candidate->addSecondary(sign * 14, Eout); - break; - case 18: // antinu_muon - if (haveNeutrinos) - candidate->addSecondary(sign * -14, Eout); - break; - default: - throw std::runtime_error( - "PhotoPionProduction: unexpected particle " - + kiss::str(pType)); - } - } - } - - double PhotoPionProduction::lossLength(int id, double gamma, double z) { - int A = massNumber(id); - int Z = chargeNumber(id); - int N = A - Z; - - gamma *= (1 + z); // cosmological scaling of photon energy - if (gamma < tabLorentz.front() or (gamma > tabLorentz.back())) - return std::numeric_limits::max(); - - double lossRate = 0; - if (Z > 0) - lossRate += interpolate(gamma, tabLorentz, tabProtonRate) - * nucleiModification(A, Z); - if (N > 0) - lossRate += interpolate(gamma, tabLorentz, tabProtonRate) - * nucleiModification(A, N); - - // protons / neutrons keep as energy the fraction of mass to delta-resonance mass - // nuclei approximately lose the energy that the interacting nucleon is carrying - double relativeEnergyLoss = (A == 1) ? 1 - 938. / 1232. : 1. / A; - lossRate *= relativeEnergyLoss; - - // cosmological scaling of photon density - lossRate *= pow(1 + z, 3) * photonFieldScaling(photonField, z); - - return 1. / lossRate; - } + + for (int i = 0; i < nParticles; i++) { // loop over out-going particles + double Eout = momentaList[3][i] * GeV; // only the energy is used; could be changed for more detail + int pType = particleList[i]; + switch (pType) { + case 13: // proton + case 14: // neutron + if (A == 1) { + // single interacting nucleon + candidate->current.setEnergy(Eout); + candidate->current.setId(sign * nucleusId(1, 14 - pType)); + } else { + // interacting nucleon is part of nucleus: it is emitted from the nucleus + candidate->current.setEnergy(E - EpA); + candidate->current.setId(sign * nucleusId(A - 1, Z - channel)); + candidate->addSecondary(sign * nucleusId(1, 14 - pType), Eout); + } + break; + case -13: // anti-proton + case -14: // anti-neutron + if (haveAntiNucleons) + candidate->addSecondary(-sign * nucleusId(1, 14 + pType), Eout); + break; + case 1: // photon + if (havePhotons) + candidate->addSecondary(22, Eout); + break; + case 2: // positron + if (havePhotons) + candidate->addSecondary(sign * -11, Eout); + break; + case 3: // electron + if (havePhotons) + candidate->addSecondary(sign * 11, Eout); + break; + case 15: // nu_e + if (haveNeutrinos) + candidate->addSecondary(sign * 12, Eout); + break; + case 16: // antinu_e + if (haveNeutrinos) + candidate->addSecondary(sign * -12, Eout); + break; + case 17: // nu_muon + if (haveNeutrinos) + candidate->addSecondary(sign * 14, Eout); + break; + case 18: // antinu_muon + if (haveNeutrinos) + candidate->addSecondary(sign * -14, Eout); + break; + default: + throw std::runtime_error( + "PhotoPionProduction: unexpected particle " + + kiss::str(pType)); + } + } +} + +double PhotoPionProduction::lossLength(int id, double gamma, double z) { + int A = massNumber(id); + int Z = chargeNumber(id); + int N = A - Z; + + gamma *= (1 + z); // cosmological scaling of photon energy + if (gamma < tabLorentz.front() or (gamma > tabLorentz.back())) + return std::numeric_limits::max(); + + double lossRate = 0; + if (Z > 0) + lossRate += interpolate(gamma, tabLorentz, tabProtonRate) + * nucleiModification(A, Z); + if (N > 0) + lossRate += interpolate(gamma, tabLorentz, tabProtonRate) + * nucleiModification(A, N); + + // protons / neutrons keep as energy the fraction of mass to delta-resonance mass + // nuclei approximately lose the energy that the interacting nucleon is carrying + double relativeEnergyLoss = (A == 1) ? 1 - 938. / 1232. : 1. / A; + lossRate *= relativeEnergyLoss; + + // cosmological scaling of photon density + lossRate *= pow(1 + z, 3) * photonFieldScaling(photonField, z); + + return 1. / lossRate; +} } // namespace crpropa From ed6ec71652a391e8108612379ae394b155711987 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 21 Oct 2014 12:52:43 +0200 Subject: [PATCH 0521/1298] update interaction data (new integration method) add Dole06 IRB model --- CMakeLists.txt | 4 ++-- include/crpropa/PhotonBackground.h | 9 ++++++++- src/PhotonBackground.cpp | 9 ++++++--- src/module/ElectronPairProduction.cpp | 5 +++++ src/module/PhotoDisintegration.cpp | 5 +++++ src/module/PhotoPionProduction.cpp | 7 ++++--- 6 files changed, 30 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d84660f2b..de54ffdbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,8 +126,8 @@ endif(MUPARSER_FOUND) # ---------------------------------------------------------------------------- # Downloading data files (interaction data, masses, decay data) # ---------------------------------------------------------------------------- -set(DATA_URL "http://crpropa.desy.de/images/f/ff/Data20140803.tar.gz") -set(DATA_MD5SUM "1f0016cf3b1cf31250293de08d7fe759") +set(DATA_URL "https://crpropa.desy.de/images/e/e2/Data20141021.tar.gz") +set(DATA_MD5SUM "712430e27a8ae5bae501417bdce66116") message("Downloading data files from crpropa.desy.de ~ 30 MB") if(CMAKE_VERSION GREATER 2.6) file(DOWNLOAD ${DATA_URL} ${CMAKE_SOURCE_DIR}/data.tar.gz STATUS status EXPECTED_MD5 ${DATA_MD5SUM}) diff --git a/include/crpropa/PhotonBackground.h b/include/crpropa/PhotonBackground.h index 1593e93d3..8b7a8ed54 100644 --- a/include/crpropa/PhotonBackground.h +++ b/include/crpropa/PhotonBackground.h @@ -6,7 +6,14 @@ namespace crpropa { // Photon fields // The default IRB model is that of Kneiske et al. 2004 enum PhotonField { - CMB, IRB, IRB_Kneiske04, IRB_Kneiske10, IRB_Franceschini08, IRB_Stecker05, IRB_withRedshift_Kneiske04 + CMB, + IRB, + IRB_Kneiske04, + IRB_Kneiske10, + IRB_Stecker05, + IRB_Dole06, + IRB_Franceschini08, + IRB_withRedshift_Kneiske04 }; // Returns overall comoving scaling factor diff --git a/src/PhotonBackground.cpp b/src/PhotonBackground.cpp index ae898acd5..26cdbf069 100644 --- a/src/PhotonBackground.cpp +++ b/src/PhotonBackground.cpp @@ -8,10 +8,10 @@ namespace crpropa { // Overall redshift scaling of the Kneiske et al. 2004 IRB, astro-ph/0309141 // The scaling is calculated in data-tools/PhotonField/Kneiske2004_IRB_scaling.py -double a[10] = {-1, 0, 0.2, 0.4, 0.6, 1, 2, 3, 4, 5 }; +double a[10] = { -1, 0, 0.2, 0.4, 0.6, 1, 2, 3, 4, 5 }; static std::vector zKneiske(a, a + sizeof(a) / sizeof(double)); -double b[10] = {1.250665, 1., 0.9749867, 0.93999977, 0.88430409, 0.64952017, 0.27170436, - 0.130244, 0.05971749, 0. }; +double b[10] = { 1.250665, 1., 0.9749867, 0.93999977, 0.88430409, 0.64952017, + 0.27170436, 0.130244, 0.05971749, 0. }; static std::vector sKneiske(b, b + sizeof(b) / sizeof(double)); double photonFieldScaling(PhotonField photonField, double z) { @@ -22,8 +22,11 @@ double photonFieldScaling(PhotonField photonField, double z) { case IRB_Kneiske04: case IRB_Kneiske10: case IRB_Stecker05: + case IRB_Dole06: case IRB_Franceschini08: return interpolate(z, zKneiske, sKneiske); + case IRB_withRedshift_Kneiske04: + return 1; default: throw std::runtime_error("PhotonField: unknown photon background"); } diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index dc0885664..8b67fb9b1 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -41,6 +41,11 @@ void ElectronPairProduction::setPhotonField(PhotonField photonField) { initRate(getDataPath("epp_IRB_Stecker05.txt")); initSpectrum(getDataPath("epp_spectrum_IRB.txt")); break; + case IRB_Dole06: + setDescription("ElectronPairProduction: IRB Dole '06"); + initRate(getDataPath("epp_IRB_Dole06.txt")); + initSpectrum(getDataPath("epp_spectrum_IRB.txt")); + break; case IRB_Franceschini08: setDescription("ElectronPairProduction: IRB Franceschini '08"); initRate(getDataPath("epp_IRB_Franceschini08.txt")); diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index ca4303eee..55fb5000c 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -41,6 +41,11 @@ void PhotoDisintegration::setPhotonField(PhotonField photonField) { initRate(getDataPath("pd_IRB_Stecker05.txt")); initBranching(getDataPath("pd_branching_IRB_Kneiske04.txt")); break; + case IRB_Dole06: + setDescription("PhotoDisintegration: IRB Dole '06"); + initRate(getDataPath("pd_IRB_Dole06.txt")); + initBranching(getDataPath("pd_branching_IRB_Dole06.txt")); + break; case IRB_Franceschini08: setDescription("PhotoDisintegration: IRB Franceschini '08"); initRate(getDataPath("pd_IRB_Franceschini08.txt")); diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index addde8080..36d86665b 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -65,6 +65,10 @@ void PhotoPionProduction::init() { setDescription("PhotoPionProduction: IRB Stecker '05"); init(getDataPath("ppp_IRB_Stecker05.txt")); break; + case IRB_Dole06: + setDescription("PhotoPionProduction: IRB Dole '06"); + init(getDataPath("ppp_IRB_Dole06.txt")); + break; case IRB_Franceschini08: setDescription("PhotoPionProduction: IRB Franceschini '08"); init(getDataPath("ppp_IRB_Franceschini08.txt")); @@ -118,9 +122,6 @@ void PhotoPionProduction::init(std::string filename) { infile.ignore(std::numeric_limits::max(), '\n'); } - std::cout << "Read IRB table in " << tabRedshifts.size() << "\t" - << tabLorentz.size() << "\t" << tabProtonRate.size() << "\t" - << tabNeutronRate.size() << std::endl; infile.close(); } From e5bf411109bd0d1039c7984f3af456c850fba6d3 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 21 Oct 2014 15:14:38 +0200 Subject: [PATCH 0522/1298] update md5sum (new data.tar.gz had wrong folder structure) --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index de54ffdbd..919b498d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,8 +127,8 @@ endif(MUPARSER_FOUND) # Downloading data files (interaction data, masses, decay data) # ---------------------------------------------------------------------------- set(DATA_URL "https://crpropa.desy.de/images/e/e2/Data20141021.tar.gz") -set(DATA_MD5SUM "712430e27a8ae5bae501417bdce66116") -message("Downloading data files from crpropa.desy.de ~ 30 MB") +set(DATA_MD5SUM "cd9e4bdf2a31d21986e5e379a9a5f962") +message("Downloading data files from crpropa.desy.de ~ 60 MB") if(CMAKE_VERSION GREATER 2.6) file(DOWNLOAD ${DATA_URL} ${CMAKE_SOURCE_DIR}/data.tar.gz STATUS status EXPECTED_MD5 ${DATA_MD5SUM}) else() From e41b4edeff346e194db1a90821c27cb30b93e60c Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Tue, 21 Oct 2014 15:37:55 +0200 Subject: [PATCH 0523/1298] update md5sum (wrong filename pd_CMB_branching.txt) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 919b498d1..a833f057c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,7 +127,7 @@ endif(MUPARSER_FOUND) # Downloading data files (interaction data, masses, decay data) # ---------------------------------------------------------------------------- set(DATA_URL "https://crpropa.desy.de/images/e/e2/Data20141021.tar.gz") -set(DATA_MD5SUM "cd9e4bdf2a31d21986e5e379a9a5f962") +set(DATA_MD5SUM "c2e1dba052c550873e67344673013f7c") message("Downloading data files from crpropa.desy.de ~ 60 MB") if(CMAKE_VERSION GREATER 2.6) file(DOWNLOAD ${DATA_URL} ${CMAKE_SOURCE_DIR}/data.tar.gz STATUS status EXPECTED_MD5 ${DATA_MD5SUM}) From 54e89ac3e86bd209ca2cd303db2da5a76cef5e0d Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Wed, 22 Oct 2014 15:36:20 +0200 Subject: [PATCH 0524/1298] Moved lenses to crpropa namespace and directory structure --- CMakeLists.txt | 10 +- .../crpropa/magneticLens}/MagneticLens.h | 6 +- .../crpropa/magneticLens}/ModelMatrix.h | 2 +- .../magneticLens}/ParticleMapsContainer.h | 6 +- .../crpropa/magneticLens}/Pixelization.h | 4 +- .../crpropa/magneticLens}/shealpix.h | 0 libs/GalacticMagneticLens/CMakeLists.txt | 19 - .../include/parsec/Random.hh | 191 -------- libs/GalacticMagneticLens/src/Random.cc | 426 ------------------ python/crpropa.i | 30 +- .../src => src/magneticLens}/MagneticLens.cpp | 6 +- .../src => src/magneticLens}/ModelMatrix.cpp | 4 +- .../magneticLens/ParticleMapsContainer.cpp | 6 +- .../magneticLens/Pixelization.cpp | 4 +- test/testMagneticLens.cpp | 12 +- 15 files changed, 43 insertions(+), 683 deletions(-) rename {libs/GalacticMagneticLens/include/parsec => include/crpropa/magneticLens}/MagneticLens.h (98%) rename {libs/GalacticMagneticLens/include/parsec => include/crpropa/magneticLens}/ModelMatrix.h (99%) rename {libs/GalacticMagneticLens/include/parsec => include/crpropa/magneticLens}/ParticleMapsContainer.h (95%) rename {libs/GalacticMagneticLens/include/parsec => include/crpropa/magneticLens}/Pixelization.h (98%) rename {libs/GalacticMagneticLens/include/parsec => include/crpropa/magneticLens}/shealpix.h (100%) delete mode 100644 libs/GalacticMagneticLens/CMakeLists.txt delete mode 100644 libs/GalacticMagneticLens/include/parsec/Random.hh delete mode 100644 libs/GalacticMagneticLens/src/Random.cc rename {libs/GalacticMagneticLens/src => src/magneticLens}/MagneticLens.cpp (98%) rename {libs/GalacticMagneticLens/src => src/magneticLens}/ModelMatrix.cpp (98%) rename libs/GalacticMagneticLens/src/ParticleMapsContainer.cc => src/magneticLens/ParticleMapsContainer.cpp (98%) rename libs/GalacticMagneticLens/src/Pixelization.cc => src/magneticLens/Pixelization.cpp (97%) diff --git a/CMakeLists.txt b/CMakeLists.txt index edf4efc89..e0ccc24af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,12 +73,12 @@ if (ENABLE_GALACTICMAGETICLENS) IF(Boost_FOUND) SET(WITH_GALACTIC_LENSES TRUE) - list(APPEND CRPROPA_SWIG_DEFINES -DWITH_GALACTIC_LENSES) - list(APPEND CRPROPA_SWIG_DEFINES -I${CMAKE_CURRENT_SOURCE_DIR}/libs/GalacticMagneticLens/include) + list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/MagneticLens.cpp) + list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/ModelMatrix.cpp) + list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/Pixelization.cpp) + list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/ParticleMapsContainer.cpp) - add_subdirectory(libs/GalacticMagneticLens) - list(APPEND CRPROPA_EXTRA_LIBRARIES galacticmagneticlens) - list(APPEND CRPROPA_EXTRA_INCLUDES libs/GalacticMagneticLens/include) + list(APPEND CRPROPA_EXTRA_INCLUDES ${Boost_INCLUDE_DIRS}) ELSE(Boost_FOUND) MESSAGE (STATUS "Cannot find BOOST which is required for GalacticMagneticLenses.") diff --git a/libs/GalacticMagneticLens/include/parsec/MagneticLens.h b/include/crpropa/magneticLens/MagneticLens.h similarity index 98% rename from libs/GalacticMagneticLens/include/parsec/MagneticLens.h rename to include/crpropa/magneticLens/MagneticLens.h index f1a8628d4..839fe7c26 100644 --- a/libs/GalacticMagneticLens/include/parsec/MagneticLens.h +++ b/include/crpropa/magneticLens/MagneticLens.h @@ -23,8 +23,8 @@ #ifndef MAGNETICLENS_HH #define MAGNETICLENS_HH -#include "parsec/ModelMatrix.h" -#include "parsec/Pixelization.h" +#include "crpropa/magneticLens/ModelMatrix.h" +#include "crpropa/magneticLens/Pixelization.h" #include @@ -37,7 +37,7 @@ #include -namespace parsec +namespace crpropa { /// Holds one matrix for the lens and information about the rigidity range diff --git a/libs/GalacticMagneticLens/include/parsec/ModelMatrix.h b/include/crpropa/magneticLens/ModelMatrix.h similarity index 99% rename from libs/GalacticMagneticLens/include/parsec/ModelMatrix.h rename to include/crpropa/magneticLens/ModelMatrix.h index 4f22ba3b7..9cc8628e9 100644 --- a/libs/GalacticMagneticLens/include/parsec/ModelMatrix.h +++ b/include/crpropa/magneticLens/ModelMatrix.h @@ -45,7 +45,7 @@ using namespace std; -namespace parsec +namespace crpropa { /// ModelMatrixType specifies the used Matrix Type diff --git a/libs/GalacticMagneticLens/include/parsec/ParticleMapsContainer.h b/include/crpropa/magneticLens/ParticleMapsContainer.h similarity index 95% rename from libs/GalacticMagneticLens/include/parsec/ParticleMapsContainer.h rename to include/crpropa/magneticLens/ParticleMapsContainer.h index e6bed53c5..e29ce128b 100644 --- a/libs/GalacticMagneticLens/include/parsec/ParticleMapsContainer.h +++ b/include/crpropa/magneticLens/ParticleMapsContainer.h @@ -3,10 +3,10 @@ #include #include -#include "parsec/Pixelization.h" -#include "parsec/MagneticLens.h" +#include "crpropa/magneticLens/Pixelization.h" +#include "crpropa/magneticLens/MagneticLens.h" -namespace parsec{ +namespace crpropa{ /// Container for particlemaps /// The maps are stored with discrete energies on a logarithmic scale. The diff --git a/libs/GalacticMagneticLens/include/parsec/Pixelization.h b/include/crpropa/magneticLens/Pixelization.h similarity index 98% rename from libs/GalacticMagneticLens/include/parsec/Pixelization.h rename to include/crpropa/magneticLens/Pixelization.h index 93c77491b..9e50f6ce3 100644 --- a/libs/GalacticMagneticLens/include/parsec/Pixelization.h +++ b/include/crpropa/magneticLens/Pixelization.h @@ -24,11 +24,11 @@ #ifndef PIXELIZATION_HH #define PIXELIZATION_HH -#include "parsec/shealpix.h" +#include "crpropa/magneticLens/shealpix.h" #include #include -namespace parsec +namespace crpropa { /// Helpers to makes work with Healpix smooth diff --git a/libs/GalacticMagneticLens/include/parsec/shealpix.h b/include/crpropa/magneticLens/shealpix.h similarity index 100% rename from libs/GalacticMagneticLens/include/parsec/shealpix.h rename to include/crpropa/magneticLens/shealpix.h diff --git a/libs/GalacticMagneticLens/CMakeLists.txt b/libs/GalacticMagneticLens/CMakeLists.txt deleted file mode 100644 index b6b8d9d9e..000000000 --- a/libs/GalacticMagneticLens/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -cmake_minimum_required(VERSION 2.6) - -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/include - ${Boost_INCLUDE_DIRS} - ${CMAKE_SOURCE_DIR}/libs/HepPID/include - ) - -add_library(galacticmagneticlens STATIC - src/MagneticLens.cpp - src/ModelMatrix.cpp - src/Pixelization.cc - src/Random.cc - src/ParticleMapsContainer.cc - ) - -target_link_libraries(galacticmagneticlens HepPID) -SET_TARGET_PROPERTIES(galacticmagneticlens PROPERTIES COMPILE_FLAGS -fPIC) - diff --git a/libs/GalacticMagneticLens/include/parsec/Random.hh b/libs/GalacticMagneticLens/include/parsec/Random.hh deleted file mode 100644 index 7d63e9c41..000000000 --- a/libs/GalacticMagneticLens/include/parsec/Random.hh +++ /dev/null @@ -1,191 +0,0 @@ -// Random.h -// Mersenne Twister random number generator -- a C++ class Random -// Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus -// Richard J. Wagner v1.0 15 May 2003 rjwagner@writeme.com - -// The Mersenne Twister is an algorithm for generating random numbers. It -// was designed with consideration of the flaws in various other generators. -// The period, 2^19937-1, and the order of equidistribution, 623 dimensions, -// are far greater. The generator is also fast; it avoids multiplication and -// division, and it benefits from caches and pipelines. For more information -// see the inventors' web page at http://www.math.keio.ac.jp/~matumoto/emt.html - -// Reference -// M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally -// Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on -// Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30. - -// Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, -// Copyright (C) 2000 - 2003, Richard J. Wagner -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. The names of its contributors may not be used to endorse or promote -// products derived from this software without specific prior written -// permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// The original code included the following notice: -// -// When you use this, send an email to: matumoto@math.keio.ac.jp -// with an appropriate reference to your work. -// -// It would be nice to CC: rjwagner@writeme.com and Cokus@math.washington.edu -// when you write. - -// Parts of this file are modified beginning in 29.10.09 for adaption in -// PXL. - - -#ifndef PXL_BASE_RANDOM_HH -#define PXL_BASE_RANDOM_HH - -// Not thread safe (unless auto-initialization is avoided and each thread has -// its own Random object) -#include -#include -#include -#include - -//necessary for win32 -#ifndef M_PI - #define M_PI 3.14159265358979323846 -#endif - -#include - -namespace parsec{ - -class Random{ -public: -#ifndef uint32 - typedef unsigned long uint32; // unsigned integer type, at least 32 bits -#endif - enum { N = 624 }; // length of state vector - enum { SAVE = N + 1 }; // length of array for save() - -protected: - enum { M = 397 }; // period parameter - uint32 state[N]; // internal state - uint32 *pNext; // next value to get from state - int left; // number of values left before reload needed - - -//Methods -public: - /// initialize with a simple uint32 - Random( const uint32& oneSeed ); - // initialize with an array - Random( uint32 *const bigSeed, uint32 const seedLength = N ); - /// auto-initialize with /dev/urandom or time() and clock() - /// Do NOT use for CRYPTOGRAPHY without securely hashing several returned - /// values together, otherwise the generator state can be learned after - /// reading 624 consecutive values. - Random(); - // Access to 32-bit random numbers - double rand(); ///< real number in [0,1] - double rand( const double& n ); ///< real number in [0,n] - double randExc(); ///< real number in [0,1) - double randExc( const double& n ); ///< real number in [0,n) - double randDblExc(); ///< real number in (0,1) - double randDblExc( const double& n ); ///< real number in (0,n) - /// Pull a 32-bit integer from the generator state - /// Every other access function simply transforms the numbers extracted here - uint32 randInt(); ///< integer in [0,2^32-1] - uint32 randInt( const uint32& n ); ///< integer in [0,n] for n < 2^32 - double operator()() { return rand(); } ///< same as rand() - - /// Access to 53-bit random numbers (capacity of IEEE double precision) - double rand53(); // real number in [0,1) - ///Exponential distribution in (0,inf) - double randExponential(); - /// Normal distributed random number - double randNorm( const double& mean = 0.0, const double& variance = 1.0 ); - /// Uniform distribution in [min, max] - double randUniform(double min, double max); - /// Rayleigh distributed random number - double randRayleigh(double sigma); - /// Fisher distributed random number - double randFisher(double k); - - /// Power-Law distribution, not possible for index == -1 - double randPowerLaw(double index, double min, double max) ; - /// Broken power-law distribution - double randBrokenPowerLaw(double index1, double index2, double breakpoint, double min, double max ) ; - - /// Seed the generator with a simple uint32 - void seed( const uint32 oneSeed ); - /// Seed the generator with an array of uint32's - /// There are 2^19937-1 possible initial states. This function allows - /// all of those to be accessed by providing at least 19937 bits (with a - /// default seed length of N = 624 uint32's). Any bits above the lower 32 - /// in each element are discarded. - /// Just call seed() if you want to get array from /dev/urandom - void seed( uint32 *const bigSeed, const uint32 seedLength = N ); - /// Seed the generator with an array from /dev/urandom if available - /// Otherwise use a hash of time() and clock() values - void seed(); - - // Saving and loading generator state - void save( uint32* saveArray ) const; // to array of size SAVE - void load( uint32 *const loadArray ); // from such array - friend std::ostream& operator<<( std::ostream& os, const Random& mtrand ); - friend std::istream& operator>>( std::istream& is, Random& mtrand ); - - static Random &instance(); -protected: - /// Initialize generator state with seed - /// See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier. - /// In previous versions, most significant bits (MSBs) of the seed affect - /// only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto. - void initialize( const uint32 oneSeed ); - - /// Generate N new values in state - /// Made clearer and faster by Matthew Bellew (matthew.bellew@home.com) - void reload(); - uint32 hiBit( const uint32& u ) const { return u & 0x80000000UL; } - uint32 loBit( const uint32& u ) const { return u & 0x00000001UL; } - uint32 loBits( const uint32& u ) const { return u & 0x7fffffffUL; } - uint32 mixBits( const uint32& u, const uint32& v ) const - { return hiBit(u) | loBits(v); } - -#ifdef _MSC_VER - #pragma warning( push ) - #pragma warning( disable : 4146 ) -#endif - uint32 twist( const uint32& m, const uint32& s0, const uint32& s1 ) const - { return m ^ (mixBits(s0,s1)>>1) ^ (-loBit(s1) & 0x9908b0dfUL); } - -#ifdef _MSC_VER - #pragma warning( pop ) -#endif - - /// Get a uint32 from t and c - /// Better than uint32(x) in case x is floating point in [0,1] - /// Based on code by Lawrence Kirby (fred@genesis.demon.co.uk) - static uint32 hash( time_t t, clock_t c ); -}; -} //namespace pxl -#endif // PXL_BASE_RANDOM_HH - diff --git a/libs/GalacticMagneticLens/src/Random.cc b/libs/GalacticMagneticLens/src/Random.cc deleted file mode 100644 index dbb3915b3..000000000 --- a/libs/GalacticMagneticLens/src/Random.cc +++ /dev/null @@ -1,426 +0,0 @@ -// Random.cc is based on Random.h -// Mersenne Twister random number generator -- a C++ class Random -// Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus -// Richard J. Wagner v1.0 15 May 2003 rjwagner@writeme.com - -// The Mersenne Twister is an algorithm for generating random numbers. It -// was designed with consideration of the flaws in various other generators. -// The period, 2^19937-1, and the order of equidistribution, 623 dimensions, -// are far greater. The generator is also fast; it avoids multiplication and -// division, and it benefits from caches and pipelines. For more information -// see the inventors' web page at http://www.math.keio.ac.jp/~matumoto/emt.html - -// Reference -// M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally -// Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on -// Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30. - -// Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, -// Copyright (C) 2000 - 2003, Richard J. Wagner -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. The names of its contributors may not be used to endorse or promote -// products derived from this software without specific prior written -// permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// The original code included the following notice: -// -// When you use this, send an email to: matumoto@math.keio.ac.jp -// with an appropriate reference to your work. -// -// It would be nice to CC: rjwagner@writeme.com and Cokus@math.washington.edu -// when you write. - -// Parts of this file are modified beginning in 29.10.09 for adaption in -// PXL. - -#include "parsec/Random.hh" -#include -#include - -namespace parsec -{ - -Random::Random(const uint32& oneSeed) -{ - seed(oneSeed); -} - -Random::Random(uint32 * const bigSeed, const uint32 seedLength) -{ - seed(bigSeed, seedLength); -} - -Random::Random() -{ - seed(); -} - -double Random::rand() -{ - return double(randInt()) * (1.0 / 4294967295.0); -} - -double Random::rand(const double& n) -{ - return rand() * n; -} - -double Random::randExc() -{ - return double(randInt()) * (1.0 / 4294967296.0); -} - -double Random::randExc(const double& n) -{ - return randExc() * n; -} - -double Random::randDblExc() -{ - return (double(randInt()) + 0.5) * (1.0 / 4294967296.0); -} - -double Random::randDblExc(const double& n) -{ - return randDblExc() * n; -} - -double Random::rand53() -{ - uint32 a = randInt() >> 5, b = randInt() >> 6; - return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0); // by Isaku Wada -} - -double Random::randNorm(const double& mean, const double& variance) -{ - // Return a real number from a normal (Gaussian) distribution with given - // mean and variance by Box-Muller method - double r = sqrt(-2.0 * log(1.0 - randDblExc())) * variance; - double phi = 2.0 * 3.14159265358979323846264338328 * randExc(); - return mean + r * cos(phi); -} - -double Random::randUniform(double min, double max) -{ - return min + (max - min) * this->rand(); -} - -///returns a rayleigh distributed value -double Random::randRayleigh(double sigma) -{ - return sigma * sqrt(-2.0 * log(1 - this->rand())); -} - -double Random::randFisher(double k) -{ - return acos(1. + 1. / k * log(1 - rand() * (1 - exp(-2 * k)))); -} - -double Random::randPowerLaw(double index, double min, double max) -{ - if ((min <= 0) || (max < min)) - { - throw std::runtime_error( - "Power law distribution only possible for 0 < min <= max"); - } - // index = -1 - if ((std::abs(index + 1.0)) < DBL_EPSILON) - { - double part1 = log(max); - double part2 = log(min); - return exp((part1 - part2) * this->rand() + part2); - } - else - { - double part1 = pow(max, index + 1); - double part2 = pow(min, index + 1); - double ex = 1 / (index + 1); - return pow((part1 - part2) * this->rand() + part2, ex); - } -} - -double Random::randBrokenPowerLaw(double index1, double index2, - double breakpoint, double min, double max) -{ - if ((min <= 0) || (max < min)) - { - throw std::runtime_error( - "Power law distribution only possible for 0 < min <= max"); - } - if (min >= breakpoint) - { - return this->randPowerLaw(index2, min, max); - } - else if (max <= breakpoint) - { - return this->randPowerLaw(index2, min, max); - } - else - { - double intPL1; - // check if index1 = -1 - if ((std::abs(index1 + 1.0)) < DBL_EPSILON) - { - intPL1 = log(breakpoint / min); - } - else - { - intPL1 = (pow(breakpoint, index1 + 1) - pow(min, index1 + 1)) - / (index1 + 1); - } - double intPL2; - // check if index2 = -1 - if ((std::abs(index2 + 1.0)) < DBL_EPSILON) - { - intPL2 = log(max / breakpoint) * pow(breakpoint, index1 - index2); - } - else - { - intPL2 = (pow(max, index2 + 1) - pow(breakpoint, index2 + 1)) - * pow(breakpoint, index1 - index2) / (index2 + 1); - } - if (this->rand() > intPL1 / (intPL1 + intPL2)) - return this->randPowerLaw(index2, breakpoint, max); - else - return this->randPowerLaw(index1, min, breakpoint); - } -} - -double Random::randExponential() -{ - double dum; - do - { - dum = this->rand(); - } while (dum < DBL_EPSILON); - return -1.0 * log(dum); -} - -Random::uint32 Random::randInt() -{ - - if (left == 0) - reload(); - --left; - - register uint32 s1; - s1 = *pNext++; - s1 ^= (s1 >> 11); - s1 ^= (s1 << 7) & 0x9d2c5680UL; - s1 ^= (s1 << 15) & 0xefc60000UL; - return (s1 ^ (s1 >> 18)); -} - -Random::uint32 Random::randInt(const uint32& n) -{ - // Find which bits are used in n - // Optimized by Magnus Jonsson (magnus@smartelectronix.com) - uint32 used = n; - used |= used >> 1; - used |= used >> 2; - used |= used >> 4; - used |= used >> 8; - used |= used >> 16; - - // Draw numbers until one is found in [0,n] - uint32 i; - do - i = randInt() & used; // toss unused bits to shorten search - while (i > n); - return i; -} - -void Random::seed(const uint32 oneSeed) -{ - initialize(oneSeed); - reload(); -} - -void Random::seed(uint32 * const bigSeed, const uint32 seedLength) -{ - initialize(19650218UL); - register int i = 1; - register uint32 j = 0; - register int k = (N > seedLength ? N : seedLength); - for (; k; --k) - { - state[i] = state[i] - ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1664525UL); - state[i] += (bigSeed[j] & 0xffffffffUL) + j; - state[i] &= 0xffffffffUL; - ++i; - ++j; - if (i >= N) - { - state[0] = state[N - 1]; - i = 1; - } - if (j >= seedLength) - j = 0; - } - for (k = N - 1; k; --k) - { - state[i] = state[i] - ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941UL); - state[i] -= i; - state[i] &= 0xffffffffUL; - ++i; - if (i >= N) - { - state[0] = state[N - 1]; - i = 1; - } - } - state[0] = 0x80000000UL; // MSB is 1, assuring non-zero initial array - reload(); -} - -void Random::seed() -{ - - // First try getting an array from /dev/urandom - FILE* urandom = fopen("/dev/urandom", "rb"); - if (urandom) - { - uint32 bigSeed[N]; - register uint32 *s = bigSeed; - register int i = N; - register bool success = true; - while (success && i--) - success = fread(s++, sizeof(uint32), 1, urandom) != 0; - fclose(urandom); - if (success) - { - seed(bigSeed, N); - return; - } - } - - // Was not successful, so use time() and clock() instead - seed(hash(time(NULL), clock())); -} - -void Random::initialize(const uint32 seed) -{ - register uint32 *s = state; - register uint32 *r = state; - register int i = 1; - *s++ = seed & 0xffffffffUL; - for (; i < N; ++i) - { - *s++ = (1812433253UL * (*r ^ (*r >> 30)) + i) & 0xffffffffUL; - r++; - } -} - -void Random::reload() -{ - register uint32 *p = state; - register int i; - for (i = N - M; i--; ++p) - *p = twist(p[M], p[0], p[1]); - for (i = M; --i; ++p) - *p = twist(p[M - N], p[0], p[1]); - *p = twist(p[M - N], p[0], state[0]); - - left = N, pNext = state; -} - -Random::uint32 Random::hash(time_t t, clock_t c) -{ - - static uint32 differ = 0; // guarantee time-based seeds will change - - uint32 h1 = 0; - unsigned char *p = (unsigned char *) &t; - for (size_t i = 0; i < sizeof(t); ++i) - { - h1 *= UCHAR_MAX + 2U; - h1 += p[i]; - } - uint32 h2 = 0; - p = (unsigned char *) &c; - for (size_t j = 0; j < sizeof(c); ++j) - { - h2 *= UCHAR_MAX + 2U; - h2 += p[j]; - } - return (h1 + differ++) ^ h2; -} - -void Random::save(uint32* saveArray) const -{ - register uint32 *sa = saveArray; - register const uint32 *s = state; - register int i = N; - for (; i--; *sa++ = *s++) - { - } - *sa = left; -} - -void Random::load(uint32 * const loadArray) -{ - register uint32 *s = state; - register uint32 *la = loadArray; - register int i = N; - for (; i--; *s++ = *la++) - { - } - left = *la; - pNext = &state[N - left]; -} - -std::ostream& operator<<(std::ostream& os, const Random& mtrand) -{ - register const Random::uint32 *s = mtrand.state; - register int i = mtrand.N; - for (; i--; os << *s++ << "\t") - { - } - return os << mtrand.left; -} - -std::istream& operator>>(std::istream& is, Random& mtrand) -{ - register Random::uint32 *s = mtrand.state; - register int i = mtrand.N; - for (; i--; is >> *s++) - { - } - is >> mtrand.left; - mtrand.pNext = &mtrand.state[mtrand.N - mtrand.left]; - return is; -} - - -static Random _random; -Random &Random::instance() { - return _random; -} - -} // namespace parsec diff --git a/python/crpropa.i b/python/crpropa.i index 130f7c650..d283bcdda 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -269,17 +269,17 @@ __WITHNUMPY = False %template(DoubleVector) std::vector; %{ -#include "parsec/ModelMatrix.h" -#include "parsec/Pixelization.h" -#include "parsec/MagneticLens.h" -#include "parsec/ParticleMapsContainer.h" +#include "crpropa/magneticLens/ModelMatrix.h" +#include "crpropa/magneticLens/Pixelization.h" +#include "crpropa/magneticLens/MagneticLens.h" +#include "crpropa/magneticLens/ParticleMapsContainer.h" %} -%include "parsec/ModelMatrix.h" +%include "crpropa/magneticLens/ModelMatrix.h" %apply double &INOUT {double &longitude, double &latitude}; %ignore Pixelization::nPix(); -%include "parsec/Pixelization.h" +%include "crpropa/magneticLens/Pixelization.h" %pythoncode %{ def Pixelization_nonStaticnPix(self, order=None): if order == None: @@ -291,11 +291,11 @@ Pixelization.nPix = Pixelization_nonStaticnPix %apply double &INOUT {double &phi, double &theta}; %ignore MagneticLens::transformModelVector(double *,double) const; -%include "parsec/MagneticLens.h" -%template(LenspartVector) std::vector< parsec::LensPart *>; +%include "crpropa/magneticLens/MagneticLens.h" +%template(LenspartVector) std::vector< crpropa::LensPart *>; #ifdef WITHNUMPY -%extend parsec::MagneticLens{ +%extend crpropa::MagneticLens{ PyObject * transformModelVector_numpyArray(PyObject *input, double rigidity) { PyArrayObject *arr = NULL; @@ -318,7 +318,7 @@ Pixelization.nPix = Pixelization_nonStaticnPix } }; #else -%extend parsec::MagneticLens{ +%extend crpropa::MagneticLens{ PyObject * transformModelVector_numpyArray(PyObject *input, double rigidity) { std::cerr << "ERROR: PARSEC was compiled without numpy support!" << std::endl; @@ -335,10 +335,10 @@ MagneticLens.transformModelVector = MagneticLens.transformModelVector_numpyArray %ignore ParticleMapsContainer::getMap; %ignore ParticleMapsContainer::getParticleIds; %ignore ParticleMapsContainer::getEnergies; -%include "parsec/ParticleMapsContainer.h" +%include "crpropa/magneticLens/ParticleMapsContainer.h" #ifdef WITHNUMPY -%extend parsec::ParticleMapsContainer{ +%extend crpropa::ParticleMapsContainer{ PyObject *getMap_numpyArray(const int particleId, double energy) { double* data = $self->getMap(particleId, energy); @@ -365,13 +365,9 @@ MagneticLens.transformModelVector = MagneticLens.transformModelVector_numpyArray return out; } - - - - }; #else -%extend parsec::ParticleMapsContainer{ +%extend crpropa::ParticleMapsContainer{ PyObject *getMap_numpyArray(const int particleId, double energy) { std::cerr << "ERROR: PARSEC was compiled without numpy support!" << std::endl; diff --git a/libs/GalacticMagneticLens/src/MagneticLens.cpp b/src/magneticLens/MagneticLens.cpp similarity index 98% rename from libs/GalacticMagneticLens/src/MagneticLens.cpp rename to src/magneticLens/MagneticLens.cpp index b28ce29c4..0ee42eee7 100644 --- a/libs/GalacticMagneticLens/src/MagneticLens.cpp +++ b/src/magneticLens/MagneticLens.cpp @@ -20,13 +20,13 @@ // along with this program. If not, see . //---------------------------------------------------------------------- -#include "parsec/MagneticLens.h" +#include "crpropa/magneticLens/MagneticLens.h" -#include "parsec/Random.hh" +#include "crpropa/Random.h" // needed for memcpy in gcc 4.3.2 #include -namespace parsec +namespace crpropa { void MagneticLens::loadLens(const string &filename) diff --git a/libs/GalacticMagneticLens/src/ModelMatrix.cpp b/src/magneticLens/ModelMatrix.cpp similarity index 98% rename from libs/GalacticMagneticLens/src/ModelMatrix.cpp rename to src/magneticLens/ModelMatrix.cpp index 2d8167e84..08307665a 100644 --- a/libs/GalacticMagneticLens/src/ModelMatrix.cpp +++ b/src/magneticLens/ModelMatrix.cpp @@ -20,9 +20,9 @@ // along with this program. If not, see . //---------------------------------------------------------------------- -#include "parsec/ModelMatrix.h" +#include "crpropa/magneticLens/ModelMatrix.h" #include -namespace parsec +namespace crpropa { void ModelMatrix::serialize(const string &filename) diff --git a/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc b/src/magneticLens/ParticleMapsContainer.cpp similarity index 98% rename from libs/GalacticMagneticLens/src/ParticleMapsContainer.cc rename to src/magneticLens/ParticleMapsContainer.cpp index 844baffef..3e4cd046c 100644 --- a/libs/GalacticMagneticLens/src/ParticleMapsContainer.cc +++ b/src/magneticLens/ParticleMapsContainer.cpp @@ -1,9 +1,9 @@ #include "HepPID/ParticleIDMethods.hh" -#include "parsec/Random.hh" +#include "crpropa/Random.h" #include -#include "parsec/ParticleMapsContainer.h" +#include "crpropa/magneticLens/ParticleMapsContainer.h" #include -namespace parsec +namespace crpropa { ParticleMapsContainer::~ParticleMapsContainer() diff --git a/libs/GalacticMagneticLens/src/Pixelization.cc b/src/magneticLens/Pixelization.cpp similarity index 97% rename from libs/GalacticMagneticLens/src/Pixelization.cc rename to src/magneticLens/Pixelization.cpp index 1fa42ee89..be8b020e7 100644 --- a/libs/GalacticMagneticLens/src/Pixelization.cc +++ b/src/magneticLens/Pixelization.cpp @@ -20,9 +20,9 @@ // along with this program. If not, see . //---------------------------------------------------------------------- -#include "parsec/Pixelization.h" +#include "crpropa/magneticLens/Pixelization.h" -namespace parsec +namespace crpropa { uint8_t Pixelization::pix2Order(uint32_t pix) diff --git a/test/testMagneticLens.cpp b/test/testMagneticLens.cpp index eda5334ef..3e4899cb6 100644 --- a/test/testMagneticLens.cpp +++ b/test/testMagneticLens.cpp @@ -13,13 +13,13 @@ #include #include "gtest/gtest.h" -#include "parsec/MagneticLens.h" -#include "parsec/ModelMatrix.h" -#include "parsec/Pixelization.h" -#include "parsec/ParticleMapsContainer.h" +#include "crpropa/magneticLens/MagneticLens.h" +#include "crpropa/magneticLens/ModelMatrix.h" +#include "crpropa/magneticLens/Pixelization.h" +#include "crpropa/magneticLens/ParticleMapsContainer.h" using namespace std; -using namespace parsec; +using namespace crpropa; TEST(MagneticLens, Deflection) { @@ -58,7 +58,7 @@ TEST(MagneticLens, OutOfBoundsEnergy) ModelMatrix M(P.nPix(),P.nPix(),P.nPix()); magneticLens.setLensPart(M,19.0,20.0); double theta, phi; - EXPECT_THROW(magneticLens.transformCosmicRay(1.32, phi, theta), std::runtime_error); + EXPECT_FALSE(magneticLens.transformCosmicRay(1.32, phi, theta)); } From c5a57a3105d0453b1f377e40f46649ea6a60a2cc Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Wed, 22 Oct 2014 17:04:33 +0200 Subject: [PATCH 0525/1298] Reenabled build of python interface of magnetic lenses --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e0ccc24af..a98882fe9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,8 @@ if (ENABLE_GALACTICMAGETICLENS) IF(Boost_FOUND) SET(WITH_GALACTIC_LENSES TRUE) + list(APPEND CRPROPA_SWIG_DEFINES -DWITH_GALACTIC_LENSES) + list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/MagneticLens.cpp) list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/ModelMatrix.cpp) list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/Pixelization.cpp) From e6577c26d4c087554d0b51c88433d3e8fd9890d9 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Wed, 22 Oct 2014 17:05:12 +0200 Subject: [PATCH 0526/1298] Galactic lenses use now Joule as input energy --- include/crpropa/magneticLens/MagneticLens.h | 46 ++++++++----------- .../magneticLens/ParticleMapsContainer.h | 9 +++- src/magneticLens/MagneticLens.cpp | 19 ++++---- src/magneticLens/ParticleMapsContainer.cpp | 16 ++++--- test/testMagneticLens.cpp | 12 ++--- test/testMagneticLensPythonInterface.py.in | 8 ++-- 6 files changed, 57 insertions(+), 53 deletions(-) diff --git a/include/crpropa/magneticLens/MagneticLens.h b/include/crpropa/magneticLens/MagneticLens.h index 839fe7c26..9205b7bd6 100644 --- a/include/crpropa/magneticLens/MagneticLens.h +++ b/include/crpropa/magneticLens/MagneticLens.h @@ -25,6 +25,7 @@ #include "crpropa/magneticLens/ModelMatrix.h" #include "crpropa/magneticLens/Pixelization.h" +#include "crpropa/Units.h" #include @@ -55,7 +56,7 @@ class LensPart { } /// File containing the matrix to be used in the range rigidityMin, - /// rigidityMax with logarithmic units [log10(E / eV)] + /// rigidityMax in Joule LensPart(const std::string &filename, double rigidityMin, double rigidityMax) : _filename(filename), _rigidityMin(rigidityMin), _rigidityMax(rigidityMax), _maximumSumOfColumns_calculated( false), _maximumSumOfColumns(0) @@ -89,16 +90,16 @@ class LensPart return _maximumSumOfColumns; } - /// Returns the minimum of the rigidity range for the lenspart in [log10(E/ eV)] + /// Returns the minimum of the rigidity range for the lenspart in eV double getMinimumRigidity() { - return _rigidityMin; + return _rigidityMin / eV; } - /// Returns the maximum of the rigidity range for the lenspart in [log10(E/ eV)] + /// Returns the maximum of the rigidity range for the lenspart in eV double getMaximumRigidity() { - return _rigidityMax; + return _rigidityMax / eV; } /// Returns the modelmatrix @@ -151,7 +152,7 @@ class MagneticLens // Checks Matrix, raises Errors if not ok - also generate // _pixelization if called first time void _checkMatrix(const ModelMatrix &M); - // minimum / maximum rigidity [log10(E / eV)] that is covered by the lens + // minimum / maximum rigidity that is covered by the lens [Joule] double _minimumRigidity; double _maximumRigidity; static bool _randomSeeded; @@ -160,20 +161,20 @@ class MagneticLens public: /// Default constructor MagneticLens() : - _pixelization(NULL), _minimumRigidity(-1), _maximumRigidity(-1), _norm(1) + _pixelization(NULL), _minimumRigidity(DBL_MAX), _maximumRigidity(DBL_MIN), _norm(1) { } /// Constructs lens with predefined healpix order MagneticLens(uint8_t healpixorder) : - _pixelization(NULL), _minimumRigidity(-1), _maximumRigidity(-1) + _pixelization(NULL), _minimumRigidity(DBL_MAX), _maximumRigidity(DBL_MIN) { _pixelization = new Pixelization(healpixorder); } /// Construct lens and load lens from file MagneticLens(const string &filename) : - _pixelization(NULL), _minimumRigidity(-1), _maximumRigidity(-1) + _pixelization(NULL), _minimumRigidity(DBL_MAX), _maximumRigidity(DBL_MIN) { loadLens(filename); } @@ -200,19 +201,20 @@ class MagneticLens /// Try to transform the comsic ray to a new direction. /// Returns false and does not change phi and theta if the cosmic ray is /// lost due to conservation of cosmic ray flux. - /// Rigidity is given in EeV, phi and theta in rad + /// Rigidity is given in Joule, phi and theta in rad bool transformCosmicRay(double rigidity, double& phi, double& theta); /// transforms the model array assuming that model points to an array of the - /// correct size + /// correct size. Rigidity is given in Joule void transformModelVector(double* model, double rigidity) const; /// Loads M as part of a lens and use it in given rigidity range with - /// given in logarithmic units [log10(E / eV)] + /// rigidities given in Joule void setLensPart(const ModelMatrix &M, double rigidityMin, double rigidityMax); /// Loads a lens from a given file, containing lines like /// lensefile.MLDAT rigidityMin rigidityMax + /// rigidities are given in logarithmic units [log10(E / eV)] void loadLens(const string &filename); /// Normalizes the lens parts to the maximum of sums of columns of @@ -224,22 +226,22 @@ class MagneticLens /// the UHECR more efficiently. void normalizeLensparts(); - /// Checks if rigidity [log10(E / eV)] is covered by lens + /// Checks if rigidity [Joule] is covered by lens bool rigidityCovered(double rigidity) const; /// Normalizes all matrix columns - the lens will then create fake /// anisotropies, but won't drop particles void normalizeMatrixColumns(); - /// Returns minimum rigidity covered by lens, in EeV + /// Returns minimum rigidity covered by lens, in eV double getMinimumRigidity() const { - return pow(10, _minimumRigidity - 18); + return _minimumRigidity / eV; } - /// Returns maximum rigidity covered by lens, in EeV + /// Returns maximum rigidity covered by lens, in eV double getMaximumRigidity() const { - return pow(10, _maximumRigidity - 18); + return _maximumRigidity / eV; } // returns the norm used for the lenses @@ -248,7 +250,7 @@ class MagneticLens return _norm; } - /// Returns iterator to the lens part with rigidity [log10(E / eV)] + /// Returns iterator to the lens part with rigidity Joule LensPart* getLensPart(double rigidity) const; /// Returns all lens parts @@ -256,14 +258,6 @@ class MagneticLens { return _lensParts; } - - //calculates the mean deflection at given rigidity [EeV] - //double getMeanDeflection(double rigidity) const - //{ - // LensPart* lp = getLensPart(log10(rigidity) + 18); - // return calculateMeanDeflection(lp->getMatrix(), *_pixelization); - //} - }; diff --git a/include/crpropa/magneticLens/ParticleMapsContainer.h b/include/crpropa/magneticLens/ParticleMapsContainer.h index e29ce128b..c794f6fc5 100644 --- a/include/crpropa/magneticLens/ParticleMapsContainer.h +++ b/include/crpropa/magneticLens/ParticleMapsContainer.h @@ -37,11 +37,12 @@ class ParticleMapsContainer return _pixelization.getNumberOfPixels(); } - /// returns the map for the particleId with the given energy + /// returns the map for the particleId with the given energy,. energy in + /// Joule double *getMap(const int particleId, double energy); /// adds a particle to the map container - /// particleId is HEP particleId, energy [eV], galacticLongitude and + /// particleId is HEP particleId, energy [Joule], galacticLongitude and /// galacticLatitude in [rad] void addParticle(const int particleId, double energy, double galacticLongitude, double galacticLatitude, double weight=1); @@ -50,15 +51,19 @@ class ParticleMapsContainer /// this assumes that the particles in the fiels are observed at earth and the galactic /// center is in directon (0,1,0) and the galactic north-pole is in /// direction (0,0,1). + /// The energy in the fileneeds to be in eV, as it should be for CrPropa + /// output void addParticlesFromFile(const std::string inputFileName, double sourceEnergyWeightExponent=0); // returns a vector of all particle ids in th std::vector getParticleIds(); + // the energies are in eV std::vector getEnergies(int pid); void applyLens(MagneticLens &lens);; + // energy in Joule void getRandomParticles(size_t N, vector &particleId, vector &energy, vector &galacticLongitudes, vector &galacticLatitudes); diff --git a/src/magneticLens/MagneticLens.cpp b/src/magneticLens/MagneticLens.cpp index 0ee42eee7..544a6ff37 100644 --- a/src/magneticLens/MagneticLens.cpp +++ b/src/magneticLens/MagneticLens.cpp @@ -23,6 +23,8 @@ #include "crpropa/magneticLens/MagneticLens.h" #include "crpropa/Random.h" +#include "crpropa/Units.h" + // needed for memcpy in gcc 4.3.2 #include @@ -63,7 +65,7 @@ void MagneticLens::loadLens(const string &filename) } else { - this->loadLensPart(prefix + mfdatfile, emin, emax); + this->loadLensPart(prefix + mfdatfile, pow(10, emin) * eV, pow(10, emax) * eV); } } } @@ -73,10 +75,11 @@ bool MagneticLens::transformCosmicRay(double rigidity, double& phi, double& theta) { uint32_t c = _pixelization->direction2Pix(phi, theta); - LensPart *lenspart = getLensPart(log10(rigidity) + 18); + LensPart *lenspart = getLensPart(rigidity); if (!lenspart) { - std::cerr << "Warning. Trying to transform cosmic ray with rigidity " << rigidity << " which is not covered by this lens!.\n" << std::endl; + std::cerr << "Warning. Trying to transform cosmic ray with rigidity " << rigidity / eV << " eV which is not covered by this lens!.\n"; + std::cerr << " This lens covers the range " << _minimumRigidity /eV << " eV - " << _maximumRigidity << " eV.\n"; return false; } @@ -114,7 +117,7 @@ void MagneticLens::loadLensPart(const string &filename, double rigidityMin, { throw std::runtime_error("rigidityMin >= rigidityMax"); } - if (_minimumRigidity < 0 || rigidityMin < _minimumRigidity) + if (rigidityMin < _minimumRigidity) { _minimumRigidity = rigidityMin; } @@ -180,8 +183,8 @@ LensPart* MagneticLens::getLensPart(double rigidity) const const_LensPartIter i = _lensParts.begin(); while (i != _lensParts.end()) { - if (((*i)->getMinimumRigidity() < rigidity) - && ((*i)->getMaximumRigidity() >= rigidity)) + if (((*i)->getMinimumRigidity() < rigidity / eV) + && ((*i)->getMaximumRigidity() >= rigidity / eV)) { return (*i); } @@ -242,11 +245,11 @@ void MagneticLens::normalizeLensparts() void MagneticLens::transformModelVector(double* model, double rigidity) const { - LensPart* lenspart = (getLensPart(log10(rigidity)+18)); + LensPart* lenspart = getLensPart(rigidity); if (!lenspart) { - std::cerr << "Warning. Trying to transform vector with rigidity " << rigidity << " which is not covered by this lens!.\n" << std::endl; + std::cerr << "Warning. Trying to transform vector with rigidity " << rigidity / eV << "eV which is not covered by this lens!.\n" << std::endl; return; } diff --git a/src/magneticLens/ParticleMapsContainer.cpp b/src/magneticLens/ParticleMapsContainer.cpp index 3e4cd046c..0bfbcad0f 100644 --- a/src/magneticLens/ParticleMapsContainer.cpp +++ b/src/magneticLens/ParticleMapsContainer.cpp @@ -1,8 +1,10 @@ #include "HepPID/ParticleIDMethods.hh" #include "crpropa/Random.h" -#include #include "crpropa/magneticLens/ParticleMapsContainer.h" +#include "crpropa/Units.h" + #include +#include namespace crpropa { @@ -19,13 +21,13 @@ ParticleMapsContainer::~ParticleMapsContainer() int ParticleMapsContainer::energy2Idx(double energy) const { - double lE = log10(energy); + double lE = log10(energy / eV); return int((lE - _bin0lowerEdge) / _deltaLogE); } double ParticleMapsContainer::idx2Energy(int idx) const { - return pow(10, idx * _deltaLogE + _bin0lowerEdge + _deltaLogE / 2); + return pow(10, idx * _deltaLogE + _bin0lowerEdge + _deltaLogE / 2) * eV; } @@ -87,7 +89,7 @@ void ParticleMapsContainer::addParticlesFromFile(const std::string inputFileName double weight = pow(sourceEnergy, sourceEnergyWeightExponent); double galacticLongitude = atan2(-pY, -pX); double galacticLatitude = M_PI / 2 - acos(-pZ / sqrt(pX*pX + pY*pY + pZ*pZ)); - addParticle(particleId, energy * 1E18, galacticLongitude, galacticLatitude, weight); + addParticle(particleId, energy * EeV, galacticLongitude, galacticLatitude, weight); } infile.ignore(std::numeric_limits < std::streamsize > ::max(), '\n'); } @@ -116,7 +118,7 @@ std::vector ParticleMapsContainer::getEnergies(int pid) for(std::map::iterator iter = _data[pid].begin(); iter != _data[pid].end(); ++iter) { - energies.push_back( idx2Energy(iter->first) ); + energies.push_back( idx2Energy(iter->first) / eV ); } } return energies; @@ -130,7 +132,7 @@ void ParticleMapsContainer::applyLens(MagneticLens &lens) for(std::map::iterator energy_iter = pid_iter->second.begin(); energy_iter != pid_iter->second.end(); ++energy_iter) { // // transform only nuclei - double energy = idx2Energy(energy_iter->first) / 1E18; + double energy = idx2Energy(energy_iter->first); int chargeNumber = HepPID::Z(pid_iter->first); if (chargeNumber != 0 && lens.rigidityCovered(energy / chargeNumber)) { @@ -201,7 +203,7 @@ void ParticleMapsContainer::getRandomParticles(size_t N, vector &particleId if (r <=0) { foundParticle = true; - energy[i] = idx2Energy(energy_iter->first); + energy[i] = idx2Energy(energy_iter->first) / eV; _pixelization.pix2Direction (j, galacticLongitudes[i], galacticLatitudes[i]); } } diff --git a/test/testMagneticLens.cpp b/test/testMagneticLens.cpp index 3e4899cb6..0ae162ec2 100644 --- a/test/testMagneticLens.cpp +++ b/test/testMagneticLens.cpp @@ -37,7 +37,7 @@ TEST(MagneticLens, Deflection) M(i,j) =1; } - magneticLens.setLensPart(M,19.0,20.0); + magneticLens.setLensPart(M, 10 * EeV, 100 * EeV); for (int i=0; i < P.nPix(); i++) { @@ -46,7 +46,7 @@ TEST(MagneticLens, Deflection) double theta0 = theta; // No CR is allowed to be lost in this lens - EXPECT_TRUE(magneticLens.transformCosmicRay(19.32, phi, theta)); + EXPECT_TRUE(magneticLens.transformCosmicRay(20 * EeV, phi, theta)); EXPECT_NEAR(theta+theta0,0., 0.05); } } @@ -56,9 +56,9 @@ TEST(MagneticLens, OutOfBoundsEnergy) MagneticLens magneticLens(5); Pixelization P(5); ModelMatrix M(P.nPix(),P.nPix(),P.nPix()); - magneticLens.setLensPart(M,19.0,20.0); + magneticLens.setLensPart(M,10. * EeV, 100. * EeV); double theta, phi; - EXPECT_FALSE(magneticLens.transformCosmicRay(1.32, phi, theta)); + EXPECT_FALSE(magneticLens.transformCosmicRay(1. * EeV, phi, theta)); } @@ -77,7 +77,7 @@ TEST(Pixelization, angularDistance) TEST(ParticleMapsContainer, addParticle) { ParticleMapsContainer maps; - maps.addParticle(1000010010, 1E18, 0 , 0 ); + maps.addParticle(1000010010, 1 * EeV, 0 , 0 ); std::vector pids = maps.getParticleIds(); EXPECT_EQ(pids.size(), 1); EXPECT_EQ(pids[0], 1000010010); @@ -89,7 +89,7 @@ TEST(ParticleMapsContainer, addParticle) TEST(ParticleMapsContainer, getRandomParticles) { ParticleMapsContainer maps(0.002); - maps.addParticle(1000010010, 1E18, 0 , 0 ); + maps.addParticle(1000010010, 1 * EeV, 0 , 0 ); std::vector energies; std::vector lons; std::vector lats; diff --git a/test/testMagneticLensPythonInterface.py.in b/test/testMagneticLensPythonInterface.py.in index 433f4fe0c..2ea5c3503 100644 --- a/test/testMagneticLensPythonInterface.py.in +++ b/test/testMagneticLensPythonInterface.py.in @@ -30,12 +30,12 @@ class TestMagneticLens(unittest.TestCase): phiout -= 3.14 j = p.direction2Pix(phiout, thetaout) m.setElement(i, j, 1) - self.magneticLens.setLensPart(m, 18, 20) + self.magneticLens.setLensPart(m, 1 * EeV, 100 * EeV) def test_transformCosmicRays(self): phi = 0 theta = -0.01 - [r, phi, theta] = self.magneticLens.transformCosmicRay(19.0, phi, + [r, phi, theta] = self.magneticLens.transformCosmicRay(10. * EeV, phi, theta) self.assertTrue(r) self.assertFalse(theta == -0.01) @@ -43,7 +43,7 @@ class TestMagneticLens(unittest.TestCase): def test_transformModelVector_numpyArray(self): import numpy v = numpy.ones(self.magneticLens.getPixelization().nPix()) - self.magneticLens.transformModelVector(v, 2) + self.magneticLens.transformModelVector(v, 2 * EeV) def test_accessToPixelization(self): self.assertEquals(self.magneticLens.getPixelization().nPix(), @@ -73,7 +73,7 @@ class testParticleMapsContainer(unittest.TestCase): self.maps = crpropa.ParticleMapsContainer() def testAddParticle(self): - self.maps.addParticle(12, 1E18, 0, 0) + self.maps.addParticle(12, 1 * EeV, 0, 0) self.assertEquals(len(self.maps.getParticleIds()), 1) self.assertEquals(self.maps.getParticleIds()[0], 12) self.assertEquals(len(self.maps.getEnergies(12)), 1) From 306d89c0b150f23c63383096c6fb22be3b6277ab Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Thu, 23 Oct 2014 11:56:15 +0200 Subject: [PATCH 0527/1298] Removed obsolete include from magneticLens test --- CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a98882fe9..f3e3f88ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -271,9 +271,6 @@ if(ENABLE_TESTING) add_test(testSource testSource) if(WITH_GALACTIC_LENSES) - include_directories( - libs/GalacticMagneticLens/include - ) add_executable(testGalacticMagneticLens test/testMagneticLens.cpp) target_link_libraries(testGalacticMagneticLens crpropa gtest gtest_main pthread) add_test(testGalacticMagneticLens testGalacticMagneticLens) From 746c75ffeb0070e929ee183485722b0785e1c2f4 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Thu, 23 Oct 2014 11:56:53 +0200 Subject: [PATCH 0528/1298] Allow Vector3d as in[put for GalacticLenses --- include/crpropa/magneticLens/MagneticLens.h | 4 +++ .../magneticLens/ParticleMapsContainer.h | 5 ++- src/magneticLens/MagneticLens.cpp | 12 +++++++ src/magneticLens/ParticleMapsContainer.cpp | 19 +++++++---- test/testMagneticLens.cpp | 33 +++++++++++++++++++ 5 files changed, 66 insertions(+), 7 deletions(-) diff --git a/include/crpropa/magneticLens/MagneticLens.h b/include/crpropa/magneticLens/MagneticLens.h index 9205b7bd6..2d2ebc050 100644 --- a/include/crpropa/magneticLens/MagneticLens.h +++ b/include/crpropa/magneticLens/MagneticLens.h @@ -26,6 +26,7 @@ #include "crpropa/magneticLens/ModelMatrix.h" #include "crpropa/magneticLens/Pixelization.h" #include "crpropa/Units.h" +#include "crpropa/Vector3.h" #include @@ -204,6 +205,9 @@ class MagneticLens /// Rigidity is given in Joule, phi and theta in rad bool transformCosmicRay(double rigidity, double& phi, double& theta); + /// Tries transform a cosmic ray with momentum vector p + bool transformCosmicRay(double rigidity, Vector3d &p); + /// transforms the model array assuming that model points to an array of the /// correct size. Rigidity is given in Joule void transformModelVector(double* model, double rigidity) const; diff --git a/include/crpropa/magneticLens/ParticleMapsContainer.h b/include/crpropa/magneticLens/ParticleMapsContainer.h index c794f6fc5..eec2602a8 100644 --- a/include/crpropa/magneticLens/ParticleMapsContainer.h +++ b/include/crpropa/magneticLens/ParticleMapsContainer.h @@ -6,6 +6,8 @@ #include "crpropa/magneticLens/Pixelization.h" #include "crpropa/magneticLens/MagneticLens.h" +#include "crpropa/Vector3.h" + namespace crpropa{ /// Container for particlemaps @@ -44,8 +46,9 @@ class ParticleMapsContainer /// adds a particle to the map container /// particleId is HEP particleId, energy [Joule], galacticLongitude and /// galacticLatitude in [rad] - void addParticle(const int particleId, double energy, double galacticLongitude, double galacticLatitude, double weight=1); + void addParticle(const int particleId, double energy, double galacticLongitude, double galacticLatitude, double weight = 1); + void addParticle(const int particleId, double energy, const Vector3d &v, double weight = 1); /// reads the particles from the given file and weights the particles with /// the energy of the mother particle at the source. /// this assumes that the particles in the fiels are observed at earth and the galactic diff --git a/src/magneticLens/MagneticLens.cpp b/src/magneticLens/MagneticLens.cpp index 544a6ff37..6c6d139e6 100644 --- a/src/magneticLens/MagneticLens.cpp +++ b/src/magneticLens/MagneticLens.cpp @@ -109,6 +109,18 @@ bool MagneticLens::transformCosmicRay(double rigidity, double& phi, return false; } +bool MagneticLens::transformCosmicRay(double rigidity, Vector3d &p){ + + double galacticLongitude = atan2(-p.y, -p.x); + double galacticLatitude = M_PI / 2 - acos(-p.z/ sqrt(p.x*p.x + p.y*p.y + p.z*p.z)); + bool result = transformCosmicRay(rigidity, galacticLongitude, galacticLatitude); + + p.x = -1 * cos(galacticLongitude) * sin(M_PI / 2 - galacticLatitude); + p.y = -1 * sin(galacticLongitude) * sin(M_PI / 2 - galacticLatitude); + p.z = -1. * cos(M_PI / 2 - galacticLatitude); + + return result; +} void MagneticLens::loadLensPart(const string &filename, double rigidityMin, double rigidityMax) diff --git a/src/magneticLens/ParticleMapsContainer.cpp b/src/magneticLens/ParticleMapsContainer.cpp index 0bfbcad0f..210e8bc6c 100644 --- a/src/magneticLens/ParticleMapsContainer.cpp +++ b/src/magneticLens/ParticleMapsContainer.cpp @@ -64,7 +64,15 @@ void ParticleMapsContainer::addParticle(const int particleId, double energy, dou uint32_t pixel = _pixelization.direction2Pix(galacticLongitude, galacticLatitude); _data[particleId][energyIdx][pixel] +=weight; } - + + +void ParticleMapsContainer::addParticle(const int particleId, double energy, const Vector3d &p, double weight) +{ + double galacticLongitude = atan2(-p.y, -p.x); + double galacticLatitude = M_PI / 2 - acos(-p.x / p.getR()); + addParticle(particleId, energy * EeV, galacticLongitude, galacticLatitude, weight); +} + void ParticleMapsContainer::addParticlesFromFile(const std::string inputFileName, double sourceEnergyWeightExponent) { @@ -73,7 +81,8 @@ void ParticleMapsContainer::addParticlesFromFile(const std::string inputFileName while (infile.good()) { if (infile.peek() != '#') { int particleId, sourceId; - double trajectoryLength, energy, sourceEnergy, pX, pY, pZ, x, y, z, pX0, pY0, pZ0, x0, y0, z0, redShift; + double trajectoryLength, energy, sourceEnergy, x, y, z, pX0, pY0, pZ0, x0, y0, z0, redShift; + Vector3d p; infile >> trajectoryLength >> particleId @@ -82,14 +91,12 @@ void ParticleMapsContainer::addParticlesFromFile(const std::string inputFileName >> sourceEnergy >> x >> y >> z >> x0 >> y0 >> z0 - >> pX >> pY >> pZ + >> p.x >> p.y >> p.z >> pX0 >> pY0 >> pZ0 >> redShift; double weight = pow(sourceEnergy, sourceEnergyWeightExponent); - double galacticLongitude = atan2(-pY, -pX); - double galacticLatitude = M_PI / 2 - acos(-pZ / sqrt(pX*pX + pY*pY + pZ*pZ)); - addParticle(particleId, energy * EeV, galacticLongitude, galacticLatitude, weight); + addParticle(particleId, energy * EeV, p, weight); } infile.ignore(std::numeric_limits < std::streamsize > ::max(), '\n'); } diff --git a/test/testMagneticLens.cpp b/test/testMagneticLens.cpp index 0ae162ec2..e3db4f1fc 100644 --- a/test/testMagneticLens.cpp +++ b/test/testMagneticLens.cpp @@ -17,6 +17,7 @@ #include "crpropa/magneticLens/ModelMatrix.h" #include "crpropa/magneticLens/Pixelization.h" #include "crpropa/magneticLens/ParticleMapsContainer.h" +#include "crpropa/Common.h" using namespace std; using namespace crpropa; @@ -51,6 +52,38 @@ TEST(MagneticLens, Deflection) } } +TEST(MagneticLens, Vector3Deflection) +{ + MagneticLens magneticLens(5); + Pixelization P(5); + ModelMatrix M(P.nPix(),P.nPix(),P.nPix()); + + // No deflection + for (int i=0;i Date: Thu, 23 Oct 2014 12:27:39 +0200 Subject: [PATCH 0529/1298] Added tests for particleMaps python interface --- test/testMagneticLensPythonInterface.py.in | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/test/testMagneticLensPythonInterface.py.in b/test/testMagneticLensPythonInterface.py.in index 2ea5c3503..7f213be23 100644 --- a/test/testMagneticLensPythonInterface.py.in +++ b/test/testMagneticLensPythonInterface.py.in @@ -10,12 +10,14 @@ except: sys.exit(0) try: - import crpropa + import crpropa except Exception as e: print("*** CRPropa import failed") print(type(e), str(e)) sys.exit(-1) +from crpropa import EeV + class TestMagneticLens(unittest.TestCase): def setUp(self): self.magneticLens = crpropa.MagneticLens(5) @@ -78,6 +80,19 @@ class testParticleMapsContainer(unittest.TestCase): self.assertEquals(self.maps.getParticleIds()[0], 12) self.assertEquals(len(self.maps.getEnergies(12)), 1) + def testAddParticleVectorInterface(self): + self.maps.addParticle(12, 1 * EeV, crpropa.Vector3d(1, 0, 0)) + self.assertEquals(len(self.maps.getParticleIds()), 1) + self.assertEquals(self.maps.getParticleIds()[0], 12) + self.assertEquals(len(self.maps.getEnergies(12)), 1) + + def testGetRandomParticlesInterface(self): + self.maps.addParticle(12, 1 * EeV, 0, 0) + ids, lons, lats = self.maps.getRandomParticles(10) + self.assertEqual(len(ids), 10) + self.assertEqual(len(lons), 10) + self.assertEqual(len(lats), 10) + if __name__ == '__main__': unittest.main() From ec8da1afda2393644b02452daa52758831aff556 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Thu, 23 Oct 2014 14:09:45 +0200 Subject: [PATCH 0530/1298] Remove need for C-style vectors in getRandomParticles in python interface --- python/crpropa.i | 38 ++++++++++++++++++++-- test/testMagneticLensPythonInterface.py.in | 3 +- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/python/crpropa.i b/python/crpropa.i index d283bcdda..234a6096f 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -335,6 +335,7 @@ MagneticLens.transformModelVector = MagneticLens.transformModelVector_numpyArray %ignore ParticleMapsContainer::getMap; %ignore ParticleMapsContainer::getParticleIds; %ignore ParticleMapsContainer::getEnergies; +%ignore ParticleMapsContainer::getRandomParticles; %include "crpropa/magneticLens/ParticleMapsContainer.h" #ifdef WITHNUMPY @@ -351,7 +352,7 @@ MagneticLens.transformModelVector = MagneticLens.transformModelVector_numpyArray { std::vector v = $self->getParticleIds(); npy_intp size = {v.size()}; - PyObject *out = out = PyArray_SimpleNew(1, &size, NPY_INT); + PyObject *out = PyArray_SimpleNew(1, &size, NPY_INT); memcpy(PyArray_DATA((PyArrayObject *) out), &v[0], v.size() * sizeof(int)); return out; } @@ -360,11 +361,43 @@ MagneticLens.transformModelVector = MagneticLens.transformModelVector_numpyArray { std::vector v = $self->getEnergies(pid); npy_intp size = {v.size()}; - PyObject *out = out = PyArray_SimpleNew(1, &size, NPY_DOUBLE); + PyObject *out = PyArray_SimpleNew(1, &size, NPY_DOUBLE); memcpy(PyArray_DATA((PyArrayObject *) out), &v[0], v.size() * sizeof(double)); return out; } + PyObject *getRandomParticles_numpyArray(size_t N) + { + vector particleId; + vector energy; + vector galacticLongitudes; + vector galacticLatitudes; + $self->getRandomParticles(N, particleId, energy, galacticLongitudes, + galacticLatitudes); + + npy_intp size = {N}; + PyObject *oId = PyArray_SimpleNew(1, &size, NPY_INT); + PyObject *oEnergy = PyArray_SimpleNew(1, &size, NPY_DOUBLE); + PyObject *oLon = PyArray_SimpleNew(1, &size, NPY_DOUBLE); + PyObject *oLat = PyArray_SimpleNew(1, &size, NPY_DOUBLE); + + memcpy(PyArray_DATA((PyArrayObject *) oId), &particleId[0], + particleId.size() * sizeof(int)); + memcpy(PyArray_DATA((PyArrayObject *) oEnergy), &energy[0], energy.size() + * sizeof(double)); + memcpy(PyArray_DATA((PyArrayObject *) oLon), &galacticLongitudes[0], + galacticLongitudes.size() * sizeof(double)); + memcpy(PyArray_DATA((PyArrayObject *) oLat), &galacticLatitudes[0], + galacticLatitudes.size() * sizeof(double)); + + PyObject *returnList = PyList_New(4); + PyList_SET_ITEM(returnList, 0, oId); + PyList_SET_ITEM(returnList, 1, oEnergy); + PyList_SET_ITEM(returnList, 2, oLon); + PyList_SET_ITEM(returnList, 3, oLat); + return returnList; + } + }; #else %extend crpropa::ParticleMapsContainer{ @@ -379,6 +412,7 @@ MagneticLens.transformModelVector = MagneticLens.transformModelVector_numpyArray ParticleMapsContainer.getMap = ParticleMapsContainer.getMap_numpyArray ParticleMapsContainer.getParticleIds = ParticleMapsContainer.getParticleIds_numpyArray ParticleMapsContainer.getEnergies = ParticleMapsContainer.getEnergies_numpyArray +ParticleMapsContainer.getRandomParticles = ParticleMapsContainer.getRandomParticles_numpyArray %} #endif // WITH_GALACTIC_LENSES_ diff --git a/test/testMagneticLensPythonInterface.py.in b/test/testMagneticLensPythonInterface.py.in index 7f213be23..bdaa4ad06 100644 --- a/test/testMagneticLensPythonInterface.py.in +++ b/test/testMagneticLensPythonInterface.py.in @@ -88,8 +88,9 @@ class testParticleMapsContainer(unittest.TestCase): def testGetRandomParticlesInterface(self): self.maps.addParticle(12, 1 * EeV, 0, 0) - ids, lons, lats = self.maps.getRandomParticles(10) + ids, energies, lons, lats = self.maps.getRandomParticles(10) self.assertEqual(len(ids), 10) + self.assertEqual(len(energies), 10) self.assertEqual(len(lons), 10) self.assertEqual(len(lats), 10) From c21262594360de0756a29d9ba46e17cea822bab3 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 24 Oct 2014 11:45:04 +0200 Subject: [PATCH 0531/1298] Use subset of Healpix 3.11 in galactic lenses --- CMakeLists.txt | 7 + include/crpropa/magneticLens/Pixelization.h | 25 +- include/crpropa/magneticLens/shealpix.h | 299 ---- libs/healpix_base/CMakeLists.txt | 13 + libs/healpix_base/README | 3 + libs/healpix_base/error_handling.cc | 60 + libs/healpix_base/geom_utils.cc | 75 + libs/healpix_base/healpix_base.cc | 1378 +++++++++++++++++ libs/healpix_base/healpix_tables.cc | 124 ++ .../include/healpix_base/alloc_utils.h | 78 + libs/healpix_base/include/healpix_base/arr.h | 658 ++++++++ .../include/healpix_base/datatypes.h | 295 ++++ .../include/healpix_base/error_handling.h | 104 ++ .../include/healpix_base/geom_utils.h | 85 + .../include/healpix_base/healpix_base.h | 381 +++++ .../include/healpix_base/healpix_tables.h | 67 + .../include/healpix_base/lsconstants.h | 97 ++ .../include/healpix_base/math_utils.h | 183 +++ .../include/healpix_base/pointing.h | 85 + .../include/healpix_base/rangeset.h | 287 ++++ libs/healpix_base/include/healpix_base/vec3.h | 153 ++ libs/healpix_base/pointing.cc | 72 + src/magneticLens/Pixelization.cpp | 20 +- 23 files changed, 4231 insertions(+), 318 deletions(-) delete mode 100644 include/crpropa/magneticLens/shealpix.h create mode 100644 libs/healpix_base/CMakeLists.txt create mode 100644 libs/healpix_base/README create mode 100644 libs/healpix_base/error_handling.cc create mode 100644 libs/healpix_base/geom_utils.cc create mode 100644 libs/healpix_base/healpix_base.cc create mode 100644 libs/healpix_base/healpix_tables.cc create mode 100644 libs/healpix_base/include/healpix_base/alloc_utils.h create mode 100644 libs/healpix_base/include/healpix_base/arr.h create mode 100644 libs/healpix_base/include/healpix_base/datatypes.h create mode 100644 libs/healpix_base/include/healpix_base/error_handling.h create mode 100644 libs/healpix_base/include/healpix_base/geom_utils.h create mode 100644 libs/healpix_base/include/healpix_base/healpix_base.h create mode 100644 libs/healpix_base/include/healpix_base/healpix_tables.h create mode 100644 libs/healpix_base/include/healpix_base/lsconstants.h create mode 100644 libs/healpix_base/include/healpix_base/math_utils.h create mode 100644 libs/healpix_base/include/healpix_base/pointing.h create mode 100644 libs/healpix_base/include/healpix_base/rangeset.h create mode 100644 libs/healpix_base/include/healpix_base/vec3.h create mode 100644 libs/healpix_base/pointing.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index f3e3f88ad..88a9de1d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,6 +69,13 @@ list(APPEND CRPROPA_EXTRA_INCLUDES libs/EleCa/include) option(ENABLE_GALACTICMAGETICLENS "Galactic Magnetic Lens" ON) SET(WITH_GALACTIC_LENSES FALSE) if (ENABLE_GALACTICMAGETICLENS) + + + # healpix redux (provided) + add_subdirectory(libs/healpix_base) + list(APPEND CRPROPA_EXTRA_LIBRARIES healpix_base) + list(APPEND CRPROPA_EXTRA_INCLUDES libs/healpix_base//include) + FIND_PACKAGE(Boost) IF(Boost_FOUND) SET(WITH_GALACTIC_LENSES TRUE) diff --git a/include/crpropa/magneticLens/Pixelization.h b/include/crpropa/magneticLens/Pixelization.h index 9e50f6ce3..86f3bc32a 100644 --- a/include/crpropa/magneticLens/Pixelization.h +++ b/include/crpropa/magneticLens/Pixelization.h @@ -24,7 +24,7 @@ #ifndef PIXELIZATION_HH #define PIXELIZATION_HH -#include "crpropa/magneticLens/shealpix.h" +#include "healpix_base/healpix_base.h" #include #include @@ -52,17 +52,23 @@ const uint32_t _nPix[] = /// Every communication with healpix is done through this class to avoid /// bugs with missmatching coordinates (and make python hooks easier) -class Pixelization : private shealpix::sHEALPIX +class Pixelization { public: - Pixelization() : shealpix::sHEALPIX( ) + Pixelization() { } /// Constructor creating Pixelization with healpix order 6 (about /// 50000 pixels) - Pixelization(uint8_t order) : shealpix::sHEALPIX(order) + Pixelization(uint8_t order) { + _healpix = new healpix::T_Healpix_Base(order, healpix::RING); + } + + ~Pixelization() + { + delete _healpix; } /// Returns the number of the pixel which includes the direction (phi,theta) @@ -72,7 +78,7 @@ class Pixelization : private shealpix::sHEALPIX /// Returns the number of pixels of the pixelization uint32_t nPix() const { - return Npix(); + return _healpix->Npix(); } /// Returns the number of pixels given by healpix order @@ -81,7 +87,7 @@ class Pixelization : private shealpix::sHEALPIX /// Returns the number of pixels of the pixelization int getNumberOfPixels() { - return Npix(); + return _healpix->Npix(); } /// Returns the order, a given pixel number corresponds to. 0 if no @@ -103,13 +109,14 @@ class Pixelization : private shealpix::sHEALPIX /// Returns healpix order uint8_t getOrder() const { - return Order(); + return _healpix->Order(); } private: - void spherCo2Vec(double phi, double theta, shealpix::vec3 &V) const; - void vec2SphereCo(double &phi , double &theta, const shealpix::vec3 &V) const; + void spherCo2Vec(double phi, double theta, healpix::vec3 &V) const; + void vec2SphereCo(double &phi , double &theta, const healpix::vec3 &V) const; + healpix::T_Healpix_Base *_healpix; }; diff --git a/include/crpropa/magneticLens/shealpix.h b/include/crpropa/magneticLens/shealpix.h deleted file mode 100644 index e116725de..000000000 --- a/include/crpropa/magneticLens/shealpix.h +++ /dev/null @@ -1,299 +0,0 @@ -// shealpix.h, 12.04.10 by Tobias Winchen, -// -// This defines the class sHEALPIX (small HEALPIX) which provides a very -// basic Hierarchical Equal Area isoLatitude Pixelization (HEALPIX) of a -// sphere like http://healpix.jpl.nasa.gov (on which it is based). -// sHEALPIX so far only provides for pixelizations in the RING scheme: -// - assoziation of a dircetion (theta, phi) with the pixel number -// - vice versa -// -// shealpix tries to be compatible to bhealpix_base -// -// sHEALPIX is published unter the GNU GPL v3 as it is based on HEALPIX -// which is published under the GNU GPL v2. -// -// sHEALPIX is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 3 of the License, or -// (at your option) any later version. -// -// sHEALPIX is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with sHEALPIX; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -// - -#ifndef SHEALPIX_HH -#define SHEALPIX_HH - -#include -#include - -#include - - -namespace shealpix -{ - -/*! Class representing a 3D cartesian vector in healpix, copied from - * vec3.h. */ -class vec3 -{ -public: - double x; /*!< x-coordinate */ - double y; /*!< y-coordinate */ - double z; /*!< z-coordinate */ - - /*! Default constructor. Does not initialize \a x, \a y, and \a z. */ - vec3 () {} - /*! Creates a vector with the coordinates \a xc, \a yc, and \a zc. */ - vec3 (double xc, double yc, double zc) : x(xc), y(yc), z(zc) {} - - /*! Creates a unit vector from a z coordinate and an azimuthal angle. */ - void set_z_phi (double z_, double phi) - { - using namespace std; - double sintheta = sqrt((1.-z_)*(1.+z_)); - x = sintheta*cos(phi); - y = sintheta*sin(phi); - z = z_; - } - -/*! Normalizes the vector to length 1. */ - void Normalize () - { - using namespace std; - double l = 1.0/sqrt (x*x + y*y + z*z); - x*=l; y*=l; z*=l; - } - - /*! Returns the length of the vector. */ - double Length () const - { return sqrt (x*x + y*y + z*z); } - - /*! Returns the squared length of the vector. */ - double SquaredLength () const - { return (x*x + y*y + z*z); } - /*! Returns the vector with the signs of all coordinates flipped. */ - const vec3 operator- () const - { return vec3 (-x, -y, -z); } - /*! Flips the signs of all coordinates. */ - void Flip () - { x=-x; y=-y; z=-z; } - /*! Subtracts \a vec from the vector. */ - const vec3 operator- (const vec3 &vec) const - { return vec3 (x-vec.x, y-vec.y, z-vec.z); } - /*! Adds \a vec to the vector. */ - const vec3 operator+ (const vec3 &vec) const - { return vec3 (x+vec.x, y+vec.y, z+vec.z); } - /*! Returns the vector scaled by \a fact. */ - const vec3 operator* (double fact) const - { return vec3 (x*fact, y*fact, z*fact); } - /*! Returns the vector scaled by \a 1/fact. */ - const vec3 operator/ (double fact) const - { double xfact = 1./fact; return vec3 (x*xfact, y*xfact, z*xfact); } - /*! Scales the vector by \a fact. */ - vec3 &operator*= (double fact) - { x*=fact; y*=fact; z*=fact; return *this; } -}; - -/*! Returns the dot product of \a v1 and \a v2. - \relates vec3 */ -inline double dotprod(const vec3 &v1, const vec3 &v2) - { return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; } - -/*! Returns the cross product of \a a and \a b. - \relates vec3 */ -inline vec3 crossprod(const vec3 &a, const vec3 &b) - { return vec3 (a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x); } - -/*! Writes \a v to \a os. - \relates vec3 */ -inline std::ostream &operator<< (std::ostream &os, const vec3 &v) - { - os << v.x << ", " << v.y << ", " << v.z << std::endl; - return os; - } - - - - - - - - -class sHEALPIX -{ - - public: - - sHEALPIX( ) : _order(0), _npix(0), _ncap(0), _nside(0), _npface(0), _fact1(0), _fact2(0) - { - } - - sHEALPIX(int order) - { - _order = order; - // copied from healpix_base.h - _nside = 1<<_order; // _nside = 2**order - _npface = _nside << _order; // _nside * 2**order == nside**2 - _ncap = (_npface-_nside)<<1; //(nside**2-nside) * 2**1 - _npix = 12*_npface; - _fact2 = 4./_npix; - _fact1 = (_nside<<1)*_fact2; // 2*nside * fact2 - } - - void pix2ang_z_phi (int pix, double &z, double &phi) const - { - if (pix<_ncap) // North Polar cap - { - int iring = int(0.5*(1+isqrt(1+2*pix))); //counted from North pole - int iphi = (pix+1) - 2*iring*(iring-1); - - z = 1.0 - (iring*iring)*_fact2; - phi = (iphi-0.5) * M_PI/2/iring; - } - else if (pix<(_npix-_ncap)) // Equatorial region - { - int ip = pix - _ncap; - int iring = ip/(4*_nside) + _nside; // counted from North pole - int iphi = ip%(4*_nside) + 1; - // 1 if iring+nside is odd, 1/2 otherwise - double fodd = ((iring+_nside)&1) ? 1 : 0.5; - - int nl2 = 2*_nside; - z = (nl2-iring)*_fact1; - phi = (iphi-fodd) * M_PI/nl2; - } - else // South Polar cap - { - int ip = _npix - pix; - int iring = int(0.5*(1+isqrt(2*ip-1))); //counted from South pole - int iphi = 4*iring + 1 - (ip - 2*iring*(iring-1)); - - z = -1.0 + (iring*iring)*_fact2; - phi = (iphi-0.5) * M_PI/2/iring; - } - } - - int Order() const - { - return _order; - } - - int Npix() const - { - return _npix; - } - - - int ang2pix_z_phi (double z, double phi) const - { - double za = std::fabs(z); - double tt = fmodulo(phi,2*M_PI) * 2/M_PI; // in [0,4) - - if (za<=2./3.) // Equatorial region - { - double temp1 = _nside*(0.5+tt); - double temp2 = _nside*z*0.75; - int jp = int(temp1-temp2); // index of ascending edge line - int jm = int(temp1+temp2); // index of descending edge line - - // ring number counted from z=2/3 - int ir = _nside+ 1 + jp - jm; // in {1,2n+1} - int kshift = 1-(ir&1); // kshift=1 if ir even, 0 otherwise - - int ip = (jp+jm- _nside+kshift+1)/2; // in {0,4n-1} - ip = imodulo(ip,4* _nside); - - return _ncap + (ir-1)*4* _nside+ ip; - } - else // North & South polar caps - { - double tp = tt-int(tt); - double tmp = _nside*sqrt(3*(1-za)); - - int jp = int(tp*tmp); // increasing edge line index - int jm = int((1.0-tp)*tmp); // decreasing edge line index - - int ir = jp+jm+1; // ring number counted from the closest pole - int ip = int(tt*ir); // in {0,4*ir-1} - ip = imodulo(ip,4*ir); - - if (z>0) - { - return 2*ir*(ir-1) + ip; - } - else - { - return _npix - 2*ir*(ir+1) + ip; - } - } - - } - - vec3 pix2vec (int pix) const - { - double z, phi; - pix2ang_z_phi (pix,z,phi); - vec3 res; - res.set_z_phi (z, phi); - return res; - } - - int vec2pix (const vec3 &vec) const - { return ang2pix_z_phi (vec.z/vec.Length(), safe_atan2(vec.y,vec.x)); } - - - private: - int _order; // The Healpix Order (Sometimes refered to as _NSide) - int _npix; // The number of pixels - int _ncap; - int _nside; - int _npface; - double _fact1; - double _fact2; - - // Returns the remainder of the division \a v1/v2. - // The result is non-negative. - // \a v1 can be positive or negative; \a v2 must be positive. - // FROM HEALPIX, cxxsupport/cxxutils.h - inline double fmodulo (double v1, double v2) const - { - return (v1>=0) ? ((v1 inline I imodulo (I v1, I v2) const - { return (v1>=0) ? ((v1 inline unsigned int isqrt (I arg) const - { - using namespace std; - if (sizeof(I)<=4) - return unsigned (sqrt(arg+0.5)); - long double arg2 = arg; - return unsigned (sqrt(arg2+0.5)); - } - protected: - //! Returns \a atan2(y,x) if \a x!=0 or \a y!=0; else returns 0. - inline double safe_atan2 (double y, double x) const - { - using namespace std; - return ((x==0.) && (y==0.)) ? 0.0 : atan2(y,x); - } - -}; - -} // namespace sHEALPIX - -#endif // SHEALPIX_HH diff --git a/libs/healpix_base/CMakeLists.txt b/libs/healpix_base/CMakeLists.txt new file mode 100644 index 000000000..3aa2417cc --- /dev/null +++ b/libs/healpix_base/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 2.6) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) + +add_library(healpix_base STATIC + error_handling.cc + geom_utils.cc + healpix_base.cc + healpix_tables.cc + pointing.cc + ) + +SET_TARGET_PROPERTIES( healpix_base PROPERTIES COMPILE_FLAGS -fPIC) diff --git a/libs/healpix_base/README b/libs/healpix_base/README new file mode 100644 index 000000000..8b690fdec --- /dev/null +++ b/libs/healpix_base/README @@ -0,0 +1,3 @@ +This is redux version of healpix based on Healpix 3.11. It contains only +necessary code to constuct a healpix_base object wrapped in a new namespace. + diff --git a/libs/healpix_base/error_handling.cc b/libs/healpix_base/error_handling.cc new file mode 100644 index 000000000..eb824bebb --- /dev/null +++ b/libs/healpix_base/error_handling.cc @@ -0,0 +1,60 @@ + +/* + * This file is part of libcxxsupport. + * + * libcxxsupport is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * libcxxsupport is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libcxxsupport; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik + * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt + * (DLR). + */ + +/* + * Utilities for error reporting + * + * Copyright (C) 2003-2011 Max-Planck-Society + * Author: Martin Reinecke + */ + +#include "healpix_base/error_handling.h" + +namespace healpix{ +using namespace std; + +PlanckError::PlanckError(const string &message) : msg (message) {} +PlanckError::PlanckError(const char *message) : msg (message) {} + +//virtual +PlanckError::~PlanckError() {} + +void planck_failure__(const char *file, int line, const char *func, + const string &msg) + { + cerr << "Error encountered at " << file << ", line " << line << endl; + if (func) cerr << "(function " << func << ")" << endl; + if (msg!="") cerr << endl << msg << endl; + cerr << endl; + } + +void planck_failure__(const char *file, int line, const char *func, + const char *msg) + { planck_failure__ (file,line,func,string(msg)); } + +void killjob__() + { throw; } +} // namespace healpix + diff --git a/libs/healpix_base/geom_utils.cc b/libs/healpix_base/geom_utils.cc new file mode 100644 index 000000000..123f7970a --- /dev/null +++ b/libs/healpix_base/geom_utils.cc @@ -0,0 +1,75 @@ +/* + * This file is part of libcxxsupport. + * + * libcxxsupport is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * libcxxsupport is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libcxxsupport; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik + * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt + * (DLR). + */ + +/* + * Copyright (C) 2011 Max-Planck-Society + * \author Martin Reinecke + */ + +#include "healpix_base/geom_utils.h" +#include "healpix_base/arr.h" + + +namespace healpix{ +using namespace std; + + +void get_circle (const arr &point, tsize q1, tsize q2, vec3 ¢er, + double &cosrad) + { + center = (point[q1]+point[q2]).Norm(); + cosrad = dotprod(point[q1],center); + for (tsize i=0; i &point, tsize q, vec3 ¢er, + double &cosrad) + { + center = (point[0]+point[q]).Norm(); + cosrad = dotprod(point[0],center); + for (tsize i=1; i &point, vec3 ¢er, + double &cosrad) + { + tsize np=point.size(); + planck_assert(np>=3,"too few points"); + center = (point[0]+point[1]).Norm(); + cosrad = dotprod(point[0],center); + for (tsize i=2; i const int T_Healpix_Base::order_max=13; +template<> const int T_Healpix_Base::order_max=29; + +template int T_Healpix_Base::nside2order (I nside) + { + planck_assert (nside>I(0), "invalid value for Nside"); + return ((nside)&(nside-1)) ? -1 : ilog2(nside); + } +template I T_Healpix_Base::npix2nside (I npix) + { + I res=isqrt(npix/I(12)); + planck_assert (npix==res*res*I(12), "invalid value for npix"); + return res; + } + +template I T_Healpix_Base::ring_above (double z) const + { + double az=abs(z); + if (az<=twothird) // equatorial region + return I(nside_*(2-1.5*z)); + I iring = I(nside_*sqrt(3*(1-az))); + return (z>0) ? iring : 4*nside_-iring-1; + } + +namespace { + +/* Short note on the "zone": + zone = 0: pixel lies completely outside the queried shape + 1: pixel may overlap with the shape, pixel center is outside + 2: pixel center is inside the shape, but maybe not the complete pixel + 3: pixel lies completely inside the shape */ + +template inline void check_pixel (int o, int order_, + int omax, int zone, rangeset &pixset, I pix, vector > &stk, + bool inclusive, int &stacktop) + { + if (zone==0) return; + + if (o=3) + { + int sdist=2*(order_-o); // the "bit-shift distance" between map orders + pixset.append(pix<=1) + for (int i=0; i<4; ++i) + stk.push_back(make_pair(4*pix+3-i,o+1)); // add children + } + else if (o>order_) // this implies that inclusive==true + { + if (zone>=2) // pixel center in shape + { + pixset.append(pix>>(2*(o-order_))); // output the parent pixel at order_ + stk.resize(stacktop); // unwind the stack + } + else // (zone>=1): pixel center in safety range + { + if (o>(2*(o-order_))); // output the parent pixel at order_ + stk.resize(stacktop); // unwind the stack + } + } + } + else // o==order_ + { + if (zone>=2) + pixset.append(pix); + else if (inclusive) // and (zone>=1) + { + if (order_ bool check_pixel_ring (const T_Healpix_Base &b1, + const T_Healpix_Base &b2, I pix, I nr, I ipix1, int fct, + double cz, double cphi, double cosrp2, I cpix) + { + if (pix>=nr) pix-=nr; + if (pix<0) pix+=nr; + pix+=ipix1; + if (pix==cpix) return false; // disk center in pixel => overlap + int px,py,pf; + b1.pix2xyf(pix,px,py,pf); + for (int i=0; icosrp2) // overlap + return false; + b2.pix2zphi(b2.xyf2pix(ox+fct-1,oy+i,pf),pz,pphi); + if (cosdist_zphi(pz,pphi,cz,cphi)>cosrp2) // overlap + return false; + b2.pix2zphi(b2.xyf2pix(ox+fct-1-i,oy+fct-1,pf),pz,pphi); + if (cosdist_zphi(pz,pphi,cz,cphi)>cosrp2) // overlap + return false; + b2.pix2zphi(b2.xyf2pix(ox,oy+fct-1-i,pf),pz,pphi); + if (cosdist_zphi(pz,pphi,cz,cphi)>cosrp2) // overlap + return false; + } + return true; + } + +} // unnamed namespace + +template template + void T_Healpix_Base::query_disc_internal + (pointing ptg, double radius, int fact, rangeset &pixset) const + { + bool inclusive = (fact!=0); + pixset.clear(); + ptg.normalize(); + + if (scheme_==RING) + { + I fct=1; + if (inclusive) + { + planck_assert (((I(1)<=fact, + "invalid oversampling factor"); + fct = fact; + } + T_Healpix_Base b2; + double rsmall, rbig; + if (fct>1) + { + b2.SetNside(fct*nside_,RING); + rsmall = radius+b2.max_pixrad(); + rbig = radius+max_pixrad(); + } + else + rsmall = rbig = inclusive ? radius+max_pixrad() : radius; + + if (rsmall>=pi) + { pixset.append(0,npix_); return; } + + rbig = min(pi,rbig); + + double cosrsmall = cos(rsmall); + double cosrbig = cos(rbig); + + double z0 = cos(ptg.theta); + double xa = 1./sqrt((1-z0)*(1+z0)); + + I cpix=zphi2pix(z0,ptg.phi); + + double rlat1 = ptg.theta - rsmall; + double zmax = cos(rlat1); + I irmin = ring_above (zmax)+1; + + if ((rlat1<=0) && (irmin>1)) // north pole in the disk + { + I sp,rp; bool dummy; + get_ring_info_small(irmin-1,sp,rp,dummy); + pixset.append(0,sp+rp); + } + + if ((fct>1) && (rlat1>0)) irmin=max(I(1),irmin-1); + + double rlat2 = ptg.theta + rsmall; + double zmin = cos(rlat2); + I irmax = ring_above (zmin); + + if ((fct>1) && (rlat2(nr*inv_twopi*(ptg.phi-dphi) - shift)+1; + I ip_hi = ifloor(nr*inv_twopi*(ptg.phi+dphi) - shift); + + if (fct>1) + { + while ((ip_lo<=ip_hi) && check_pixel_ring + (*this,b2,ip_lo,nr,ipix1,fct,z0,ptg.phi,cosrsmall,cpix)) + ++ip_lo; + while ((ip_hi>ip_lo) && check_pixel_ring + (*this,b2,ip_hi,nr,ipix1,fct,z0,ptg.phi,cosrsmall,cpix)) + --ip_hi; + } + + if (ip_lo<=ip_hi) + { + if (ip_hi>=nr) + { ip_lo-=nr; ip_hi-=nr; } + if (ip_lo<0) + { + pixset.append(ipix1,ipix1+ip_hi+1); + pixset.append(ipix1+ip_lo+nr,ipix2+1); + } + else + pixset.append(ipix1+ip_lo,ipix1+ip_hi+1); + } + } + if ((rlat2>=pi) && (irmax+1<4*nside_)) // south pole in the disk + { + I sp,rp; bool dummy; + get_ring_info_small(irmax+1,sp,rp,dummy); + pixset.append(sp,npix_); + } + } + else // scheme_==NEST + { + if (radius>=pi) // disk covers the whole sphere + { pixset.append(0,npix_); return; } + + int oplus = 0; + if (inclusive) + { + planck_assert ((I(1)<<(order_max-order_))>=fact, + "invalid oversampling factor"); + planck_assert ((fact&(fact-1))==0, + "oversampling factor must be a power of 2"); + oplus=ilog2(fact); + } + int omax=order_+oplus; // the order up to which we test + + vec3 vptg(ptg); + arr > base(omax+1); + arr crpdr(omax+1), crmdr(omax+1); + double cosrad=cos(radius); + for (int o=0; o<=omax; ++o) // prepare data at the required orders + { + base[o].Set(o,NEST); + double dr=base[o].max_pixrad(); // safety distance + crpdr[o] = (radius+dr>pi) ? -1. : cos(radius+dr); + crmdr[o] = (radius-dr<0.) ? 1. : cos(radius-dr); + } + vector > stk; // stack for pixel numbers and their orders + stk.reserve(12+3*omax); // reserve maximum size to avoid reallocation + for (int i=0; i<12; ++i) // insert the 12 base pixels in reverse order + stk.push_back(make_pair(I(11-i),0)); + + int stacktop=0; // a place to save a stack position + + while (!stk.empty()) // as long as there are pixels on the stack + { + // pop current pixel number and order from the stack + I pix=stk.back().first; + int o=stk.back().second; + stk.pop_back(); + + double z,phi; + base[o].pix2zphi(pix,z,phi); + // cosine of angular distance between pixel center and disk center + double cangdist=cosdist_zphi(vptg.z,ptg.phi,z,phi); + + if (cangdist>crpdr[o]) + { + int zone = (cangdist void T_Healpix_Base::query_disc + (pointing ptg, double radius, rangeset &pixset) const + { + query_disc_internal (ptg, radius, 0, pixset); + } + +template void T_Healpix_Base::query_disc_inclusive + (pointing ptg, double radius, rangeset &pixset, int fact) const + { + planck_assert(fact>0,"fact must be a positive integer"); + if ((sizeof(I)<8) && (((I(1)< base2(nside_,scheme_,SET_NSIDE); + base2.query_disc_internal(ptg,radius,fact,pixset); + return; + } + query_disc_internal (ptg, radius, fact, pixset); + } + +template template + void T_Healpix_Base::query_multidisc (const arr &norm, + const arr &rad, int fact, rangeset &pixset) const + { + bool inclusive = (fact!=0); + tsize nv=norm.size(); + planck_assert(nv==rad.size(),"inconsistent input arrays"); + pixset.clear(); + + if (scheme_==RING) + { + I fct=1; + if (inclusive) + { + planck_assert (((I(1)<=fact, + "invalid oversampling factor"); + fct = fact; + } + T_Healpix_Base b2; + double rpsmall, rpbig; + if (fct>1) + { + b2.SetNside(fct*nside_,RING); + rpsmall = b2.max_pixrad(); + rpbig = max_pixrad(); + } + else + rpsmall = rpbig = inclusive ? max_pixrad() : 0; + + I irmin=1, irmax=4*nside_-1; + vector z0,xa,cosrsmall,cosrbig; + vector ptg; + vector cpix; + for (tsize i=0; i1) cpix.push_back(zphi2pix(cth,pnt.phi)); + xa.push_back(1./sqrt((1-cth)*(1+cth))); + ptg.push_back(pnt); + + double rlat1 = pnt.theta - rsmall; + double zmax = cos(rlat1); + I irmin_t = (rlat1<=0) ? 1 : ring_above (zmax)+1; + + if ((fct>1) && (rlat1>0)) irmin_t=max(I(1),irmin_t-1); + + double rlat2 = pnt.theta + rsmall; + double zmin = cos(rlat2); + I irmax_t = (rlat2>=pi) ? 4*nside_-1 : ring_above (zmin); + + if ((fct>1) && (rlat2 irmin) irmin=irmin_t; + } + } + + for (I iz=irmin; iz<=irmax; ++iz) + { + double z=ring2z(iz); + I ipix1,nr; + bool shifted; + get_ring_info_small(iz,ipix1,nr,shifted); + double shift = shifted ? 0.5 : 0.; + rangeset tr; + tr.append(ipix1,ipix1+nr); + for (tsize j=0; j(nr*inv_twopi*(ptg[j].phi-dphi) - shift)+1; + I ip_hi = ifloor(nr*inv_twopi*(ptg[j].phi+dphi) - shift); + if (fct>1) + { + while ((ip_lo<=ip_hi) && check_pixel_ring + (*this,b2,ip_lo,nr,ipix1,fct,z0[j],ptg[j].phi,cosrsmall[j],cpix[j])) + ++ip_lo; + while ((ip_hi>ip_lo) && check_pixel_ring + (*this,b2,ip_hi,nr,ipix1,fct,z0[j],ptg[j].phi,cosrsmall[j],cpix[j])) + --ip_hi; + } + if (ip_hi>=nr) + { ip_lo-=nr; ip_hi-=nr;} + if (ip_lo<0) + tr.remove(ipix1+ip_hi+1,ipix1+ip_lo+nr); + else + tr.intersect(ipix1+ip_lo,ipix1+ip_hi+1); + } + pixset.append(tr); + } + } + else // scheme_ == NEST + { + int oplus = 0; + if (inclusive) + { + planck_assert ((I(1)<<(order_max-order_))>=fact, + "invalid oversampling factor"); + planck_assert ((fact&(fact-1))==0, + "oversampling factor must be a power of 2"); + oplus=ilog2(fact); + } + int omax=order_+oplus; // the order up to which we test + + // TODO: ignore all disks with radius>=pi + + arr > base(omax+1); + arr3 crlimit(omax+1,nv,3); + for (int o=0; o<=omax; ++o) // prepare data at the required orders + { + base[o].Set(o,NEST); + double dr=base[o].max_pixrad(); // safety distance + for (tsize i=0; ipi) ? -1. : cos(rad[i]+dr); + crlimit(o,i,1) = (o==0) ? cos(rad[i]) : crlimit(0,i,1); + crlimit(o,i,2) = (rad[i]-dr<0.) ? 1. : cos(rad[i]-dr); + } + } + + vector > stk; // stack for pixel numbers and their orders + stk.reserve(12+3*omax); // reserve maximum size to avoid reallocation + for (int i=0; i<12; ++i) // insert the 12 base pixels in reverse order + stk.push_back(make_pair(I(11-i),0)); + + int stacktop=0; // a place to save a stack position + + while (!stk.empty()) // as long as there are pixels on the stack + { + // pop current pixel number and order from the stack + I pix=stk.back().first; + int o=stk.back().second; + stk.pop_back(); + + vec3 pv(base[o].pix2vec(pix)); + + tsize zone=3; + for (tsize i=0; i void T_Healpix_Base::query_multidisc_general + (const arr &norm, const arr &rad, bool inclusive, + const vector &cmds, rangeset &pixset) const + { + tsize nv=norm.size(); + planck_assert(nv==rad.size(),"inconsistent input arrays"); + pixset.clear(); + + if (scheme_==RING) + { + planck_fail ("not yet implemented"); + } + else // scheme_ == NEST + { + int oplus=inclusive ? 2 : 0; + int omax=min(order_max,order_+oplus); // the order up to which we test + + // TODO: ignore all disks with radius>=pi + + arr > base(omax+1); + arr3 crlimit(omax+1,nv,3); + for (int o=0; o<=omax; ++o) // prepare data at the required orders + { + base[o].Set(o,NEST); + double dr=base[o].max_pixrad(); // safety distance + for (tsize i=0; ipi) ? -1. : cos(rad[i]+dr); + crlimit(o,i,1) = (o==0) ? cos(rad[i]) : crlimit(0,i,1); + crlimit(o,i,2) = (rad[i]-dr<0.) ? 1. : cos(rad[i]-dr); + } + } + + vector > stk; // stack for pixel numbers and their orders + stk.reserve(12+3*omax); // reserve maximum size to avoid reallocation + for (int i=0; i<12; ++i) // insert the 12 base pixels in reverse order + stk.push_back(make_pair(I(11-i),0)); + + int stacktop=0; // a place to save a stack position + arr zone(nv); + + vector zstk; zstk.reserve(cmds.size()); + + while (!stk.empty()) // as long as there are pixels on the stack + { + // pop current pixel number and order from the stack + I pix=stk.back().first; + int o=stk.back().second; + stk.pop_back(); + + vec3 pv(base[o].pix2vec(pix)); + + for (tsize i=0; i inline int T_Healpix_Base::spread_bits (int v) const + { return utab[v&0xff] | (utab[(v>>8)&0xff]<<16); } +template<> inline int64 T_Healpix_Base::spread_bits (int v) const + { + return int64(utab[ v &0xff]) | (int64(utab[(v>> 8)&0xff])<<16) + | (int64(utab[(v>>16)&0xff])<<32) | (int64(utab[(v>>24)&0xff])<<48); + } + +template<> inline int T_Healpix_Base::compress_bits (int v) const + { + int raw = (v&0x5555) | ((v&0x55550000)>>15); + return ctab[raw&0xff] | (ctab[raw>>8]<<4); + } +template<> inline int T_Healpix_Base::compress_bits (int64 v) const + { + int64 raw = v&0x5555555555555555ull; + raw|=raw>>15; + return ctab[ raw &0xff] | (ctab[(raw>> 8)&0xff]<< 4) + | (ctab[(raw>>32)&0xff]<<16) | (ctab[(raw>>40)&0xff]<<20); + } + +template inline void T_Healpix_Base::nest2xyf (I pix, int &ix, + int &iy, int &face_num) const + { + face_num = pix>>(2*order_); + pix &= (npface_-1); + ix = compress_bits(pix); + iy = compress_bits(pix>>1); + } + +template inline I T_Healpix_Base::xyf2nest (int ix, int iy, + int face_num) const + { return (I(face_num)<<(2*order_)) + spread_bits(ix) + (spread_bits(iy)<<1); } + +template void T_Healpix_Base::ring2xyf (I pix, int &ix, int &iy, + int &face_num) const + { + I iring, iphi, kshift, nr; + I nl2 = 2*nside_; + + if (pix>1; //counted from North pole + iphi = (pix+1) - 2*iring*(iring-1); + kshift = 0; + nr = iring; + face_num=(iphi-1)/nr; + } + else if (pix<(npix_-ncap_)) // Equatorial region + { + I ip = pix - ncap_; + I tmp = (order_>=0) ? ip>>(order_+2) : ip/(4*nside_); + iring = tmp+nside_; + iphi = ip-tmp*4*nside_ + 1; + kshift = (iring+nside_)&1; + nr = nside_; + I ire = iring-nside_+1, + irm = nl2+2-ire; + I ifm = iphi - ire/2 + nside_ -1, + ifp = iphi - irm/2 + nside_ -1; + if (order_>=0) + { ifm >>= order_; ifp >>= order_; } + else + { ifm /= nside_; ifp /= nside_; } + face_num = (ifp==ifm) ? (ifp|4) : ((ifp>1; //counted from South pole + iphi = 4*iring + 1 - (ip - 2*iring*(iring-1)); + kshift = 0; + nr = iring; + iring = 2*nl2-iring; + face_num = 8 + (iphi-1)/nr; + } + + I irt = iring - (jrll[face_num]*nside_) + 1; + I ipt = 2*iphi- jpll[face_num]*nr - kshift -1; + if (ipt>=nl2) ipt-=8*nside_; + + ix = (ipt-irt) >>1; + iy = (-ipt-irt) >>1; + } + +template I T_Healpix_Base::xyf2ring (int ix, int iy, + int face_num) const + { + I nl4 = 4*nside_; + I jr = (jrll[face_num]*nside_) - ix - iy - 1; + + I nr, kshift, n_before; + + bool shifted; + get_ring_info_small(jr,n_before,nr,shifted); + nr>>=2; + kshift=1-shifted; + I jp = (jpll[face_num]*nr + ix - iy + 1 + kshift) / 2; + planck_assert(jp<=4*nr,"must not happen"); + if (jp<1) jp+=nl4; // assumption: if this triggers, then nl4==4*nr + + return n_before + jp - 1; + } + +template T_Healpix_Base::T_Healpix_Base () + : order_(-1), nside_(0), npface_(0), ncap_(0), npix_(0), + fact1_(0), fact2_(0), scheme_(RING) {} + +template void T_Healpix_Base::Set (int order, + Healpix_Ordering_Scheme scheme) + { + planck_assert ((order>=0)&&(order<=order_max), "bad order"); + order_ = order; + nside_ = I(1)< void T_Healpix_Base::SetNside (I nside, + Healpix_Ordering_Scheme scheme) + { + order_ = nside2order(nside); + planck_assert ((scheme!=NEST) || (order_>=0), + "SetNside: nside must be power of 2 for nested maps"); + nside_ = nside; + npface_ = nside_*nside_; + ncap_ = (npface_-nside_)<<1; + npix_ = 12*npface_; + fact2_ = 4./npix_; + fact1_ = (nside_<<1)*fact2_; + scheme_ = scheme; + } + +template double T_Healpix_Base::ring2z (I ring) const + { + if (ring I T_Healpix_Base::pix2ring (I pix) const + { + if (scheme_==RING) + { + if (pix>1; // counted from North pole + else if (pix<(npix_-ncap_)) // Equatorial region + return (pix-ncap_)/(4*nside_) + nside_; // counted from North pole + else // South Polar cap + return 4*nside_-((1+I(isqrt(2*(npix_-pix)-1)))>>1); + } + else + { + int face_num, ix, iy; + nest2xyf(pix,ix,iy,face_num); + return (I(jrll[face_num])< I T_Healpix_Base::nest2ring (I pix) const + { + planck_assert(order_>=0, "hierarchical map required"); + int ix, iy, face_num; + nest2xyf (pix, ix, iy, face_num); + return xyf2ring (ix, iy, face_num); + } + +template I T_Healpix_Base::ring2nest (I pix) const + { + planck_assert(order_>=0, "hierarchical map required"); + int ix, iy, face_num; + ring2xyf (pix, ix, iy, face_num); + return xyf2nest (ix, iy, face_num); + } + +template inline I T_Healpix_Base::nest_peano_helper + (I pix, int dir) const + { + int face = pix>>(2*order_); + I result = 0; + uint8 path = peano_face2path[dir][face]; + + for (int shift=2*order_-2; shift>=0; shift-=2) + { + uint8 spix = uint8((pix>>shift) & 0x3); + result <<= 2; + result |= peano_subpix[dir][path][spix]; + path=peano_subpath[dir][path][spix]; + } + + return result + (I(peano_face2face[dir][face])<<(2*order_)); + } + +template I T_Healpix_Base::nest2peano (I pix) const + { return nest_peano_helper(pix,0); } + +template I T_Healpix_Base::peano2nest (I pix) const + { return nest_peano_helper(pix,1); } + +template I T_Healpix_Base::loc2pix (double z, double phi, + double sth, bool have_sth) const + { + double za = abs(z); + double tt = fmodulo(phi*inv_halfpi,4.0); // in [0,4) + + if (scheme_==RING) + { + if (za<=twothird) // Equatorial region + { + I nl4 = 4*nside_; + double temp1 = nside_*(0.5+tt); + double temp2 = nside_*z*0.75; + I jp = I(temp1-temp2); // index of ascending edge line + I jm = I(temp1+temp2); // index of descending edge line + + // ring number counted from z=2/3 + I ir = nside_ + 1 + jp - jm; // in {1,2n+1} + I kshift = 1-(ir&1); // kshift=1 if ir even, 0 otherwise + + I t1 = jp+jm-nside_+kshift+1+nl4+nl4; + I ip = (order_>0) ? + (t1>>1)&(nl4-1) : ((t1>>1)%nl4); // in {0,4n-1} + + return ncap_ + (ir-1)*nl4 + ip; + } + else // North & South polar caps + { + double tp = tt-I(tt); + double tmp = ((za<0.99)||(!have_sth)) ? + nside_*sqrt(3*(1-za)) : + nside_*sth/sqrt((1.+za)/3.); + + I jp = I(tp*tmp); // increasing edge line index + I jm = I((1.0-tp)*tmp); // decreasing edge line index + + I ir = jp+jm+1; // ring number counted from the closest pole + I ip = I(tt*ir); // in {0,4*ir-1} + planck_assert((ip>=0)&&(ip<4*ir),"must not happen"); + //ip %= 4*ir; + + return (z>0) ? 2*ir*(ir-1) + ip : npix_ - 2*ir*(ir+1) + ip; + } + } + else // scheme_ == NEST + { + if (za<=twothird) // Equatorial region + { + double temp1 = nside_*(0.5+tt); + double temp2 = nside_*(z*0.75); + I jp = I(temp1-temp2); // index of ascending edge line + I jm = I(temp1+temp2); // index of descending edge line + I ifp = jp >> order_; // in {0,4} + I ifm = jm >> order_; + int face_num = (ifp==ifm) ? (ifp|4) : ((ifp 2/3 + { + int ntt = min(3,int(tt)); + double tp = tt-ntt; + double tmp = ((za<0.99)||(!have_sth)) ? + nside_*sqrt(3*(1-za)) : + nside_*sth/sqrt((1.+za)/3.); + + I jp = I(tp*tmp); // increasing edge line index + I jm = I((1.0-tp)*tmp); // decreasing edge line index + jp=min(jp,nside_-1); // for points too close to the boundary + jm=min(jm,nside_-1); + return (z>=0) ? + xyf2nest(nside_-jm -1,nside_-jp-1,ntt) : xyf2nest(jp,jm,ntt+8); + } + } + } + +template void T_Healpix_Base::pix2loc (I pix, double &z, + double &phi, double &sth, bool &have_sth) const + { + have_sth=false; + if (scheme_==RING) + { + if (pix>1; // counted from North pole + I iphi = (pix+1) - 2*iring*(iring-1); + + double tmp=(iring*iring)*fact2_; + z = 1.0 - tmp; + if (z>0.99) { sth=sqrt(tmp*(2.-tmp)); have_sth=true; } + phi = (iphi-0.5) * halfpi/iring; + } + else if (pix<(npix_-ncap_)) // Equatorial region + { + I nl4 = 4*nside_; + I ip = pix - ncap_; + I tmp = (order_>=0) ? ip>>(order_+2) : ip/nl4; + I iring = tmp + nside_, + iphi = ip-nl4*tmp+1; + // 1 if iring+nside is odd, 1/2 otherwise + double fodd = ((iring+nside_)&1) ? 1 : 0.5; + + z = (2*nside_-iring)*fact1_; + phi = (iphi-fodd) * pi*0.75*fact1_; + } + else // South Polar cap + { + I ip = npix_ - pix; + I iring = (1+I(isqrt(2*ip-1)))>>1; // counted from South pole + I iphi = 4*iring + 1 - (ip - 2*iring*(iring-1)); + + double tmp=(iring*iring)*fact2_; + z = tmp - 1.0; + if (z<-0.99) { sth=sqrt(tmp*(2.-tmp)); have_sth=true; } + phi = (iphi-0.5) * halfpi/iring; + } + } + else + { + int face_num, ix, iy; + nest2xyf(pix,ix,iy,face_num); + + I jr = (I(jrll[face_num])<0.99) { sth=sqrt(tmp*(2.-tmp)); have_sth=true; } + } + else if (jr > 3*nside_) + { + nr = nside_*4-jr; + double tmp=(nr*nr)*fact2_; + z = tmp - 1; + if (z<-0.99) { sth=sqrt(tmp*(2.-tmp)); have_sth=true; } + } + else + { + nr = nside_; + z = (2*nside_-jr)*fact1_; + } + + I tmp=I(jpll[face_num])*nr+ix-iy; + planck_assert(tmp<8*nr,"must not happen"); + if (tmp<0) tmp+=8*nr; + phi = (nr==nside_) ? 0.75*halfpi*tmp*fact1_ : + (0.5*halfpi*tmp)/nr; + } + } + +template template + void T_Healpix_Base::query_polygon_internal + (const vector &vertex, int fact, rangeset &pixset) const + { + bool inclusive = (fact!=0); + tsize nv=vertex.size(); + tsize ncirc = inclusive ? nv+1 : nv; + planck_assert(nv>=3,"not enough vertices in polygon"); + arr vv(nv); + for (tsize i=0; i normal(ncirc); + int flip=0; + for (tsize i=0; i1e-10,"degenerate corner"); + if (i==0) + flip = (hnd<0.) ? -1 : 1; + else + planck_assert(flip*hnd>0,"polygon is not convex"); + normal[i]*=flip/normal[i].Length(); + } + arr rad(ncirc,halfpi); + if (inclusive) + { + double cosrad; + find_enclosing_circle (vv, normal[nv], cosrad); + rad[nv]=acos(cosrad); + } + query_multidisc(normal,rad,fact,pixset); + } + +template void T_Healpix_Base::query_polygon + (const vector &vertex, rangeset &pixset) const + { + query_polygon_internal(vertex, 0, pixset); + } + +template void T_Healpix_Base::query_polygon_inclusive + (const vector &vertex, rangeset &pixset, int fact) const + { + planck_assert(fact>0,"fact must be a positive integer"); + if ((sizeof(I)<8) && (((I(1)< base2(nside_,scheme_,SET_NSIDE); + base2.query_polygon_internal(vertex,fact,pixset); + return; + } + query_polygon_internal(vertex, fact, pixset); + } + +template void T_Healpix_Base::query_strip_internal + (double theta1, double theta2, bool inclusive, rangeset &pixset) const + { + if (scheme_==RING) + { + I ring1 = max(I(1),1+ring_above(cos(theta1))), + ring2 = min(4*nside_-1,ring_above(cos(theta2))); + if (inclusive) + { + ring1 = max(I(1),ring1-1); + ring2 = min(4*nside_-1,ring2+1); + } + + I sp1,rp1,sp2,rp2; + bool dummy; + get_ring_info_small(ring1,sp1,rp1,dummy); + get_ring_info_small(ring2,sp2,rp2,dummy); + I pix1 = sp1, + pix2 = sp2+rp2; + if (pix1<=pix2) pixset.append(pix1,pix2); + } + else + planck_fail("query_strip not yet implemented for NESTED"); + } + +template void T_Healpix_Base::query_strip (double theta1, + double theta2, bool inclusive, rangeset &pixset) const + { + pixset.clear(); + + if (theta1 ps2; + query_strip_internal(theta1,pi,inclusive,ps2); + pixset.append(ps2); + } + } + +template inline void T_Healpix_Base::get_ring_info_small + (I ring, I &startpix, I &ringpix, bool &shifted) const + { + if (ring < nside_) + { + shifted = true; + ringpix = 4*ring; + startpix = 2*ring*(ring-1); + } + else if (ring < 3*nside_) + { + shifted = ((ring-nside_) & 1) == 0; + ringpix = 4*nside_; + startpix = ncap_ + (ring-nside_)*ringpix; + } + else + { + shifted = true; + I nr= 4*nside_-ring; + ringpix = 4*nr; + startpix = npix_-2*nr*(nr+1); + } + } + +template void T_Healpix_Base::get_ring_info (I ring, I &startpix, + I &ringpix, double &costheta, double &sintheta, bool &shifted) const + { + I northring = (ring>2*nside_) ? 4*nside_-ring : ring; + if (northring < nside_) + { + double tmp = northring*northring*fact2_; + costheta = 1 - tmp; + sintheta = sqrt(tmp*(2-tmp)); + ringpix = 4*northring; + shifted = true; + startpix = 2*northring*(northring-1); + } + else + { + costheta = (2*nside_-northring)*fact1_; + sintheta = sqrt((1+costheta)*(1-costheta)); + ringpix = 4*nside_; + shifted = ((northring-nside_) & 1) == 0; + startpix = ncap_ + (northring-nside_)*ringpix; + } + if (northring != ring) // southern hemisphere + { + costheta = -costheta; + startpix = npix_ - startpix - ringpix; + } + } +template void T_Healpix_Base::get_ring_info2 (I ring, + I &startpix, I &ringpix, double &theta, bool &shifted) const + { + I northring = (ring>2*nside_) ? 4*nside_-ring : ring; + if (northring < nside_) + { + double tmp = northring*northring*fact2_; + double costheta = 1 - tmp; + double sintheta = sqrt(tmp*(2-tmp)); + theta = atan2(sintheta,costheta); + ringpix = 4*northring; + shifted = true; + startpix = 2*northring*(northring-1); + } + else + { + theta = acos((2*nside_-northring)*fact1_); + ringpix = 4*nside_; + shifted = ((northring-nside_) & 1) == 0; + startpix = ncap_ + (northring-nside_)*ringpix; + } + if (northring != ring) // southern hemisphere + { + theta = pi-theta; + startpix = npix_ - startpix - ringpix; + } + } + +template void T_Healpix_Base::neighbors (I pix, + fix_arr &result) const + { + int ix, iy, face_num; + (scheme_==RING) ? + ring2xyf(pix,ix,iy,face_num) : nest2xyf(pix,ix,iy,face_num); + + const I nsm1 = nside_-1; + if ((ix>0)&&(ix0)&&(iy=nside_) + { x-=nside_; nbnum+=1; } + if (y<0) + { y+=nside_; nbnum-=3; } + else if (y>=nside_) + { y-=nside_; nbnum+=3; } + + int f = nb_facearray[nbnum][face_num]; + if (f>=0) + { + int bits = nb_swaparray[nbnum][face_num>>2]; + if (bits&1) x=nside_-x-1; + if (bits&2) y=nside_-y-1; + if (bits&4) std::swap(x,y); + result[i] = (scheme_==RING) ? xyf2ring(x,y,f) : xyf2nest(x,y,f); + } + else + result[i] = -1; + } + } + } + +template void T_Healpix_Base::get_interpol (const pointing &ptg, + fix_arr &pix, fix_arr &wgt) const + { + planck_assert((ptg.theta>=0)&&(ptg.theta<=pi),"invalid theta value"); + double z = cos (ptg.theta); + I ir1 = ring_above(z); + I ir2 = ir1+1; + double theta1, theta2, w1, tmp, dphi; + I sp,nr; + bool shift; + I i1,i2; + if (ir1>0) + { + get_ring_info2 (ir1, sp, nr, theta1, shift); + dphi = twopi/nr; + tmp = (ptg.phi/dphi - .5*shift); + i1 = (tmp<0) ? I(tmp)-1 : I(tmp); + w1 = (ptg.phi-(i1+.5*shift)*dphi)/dphi; + i2 = i1+1; + if (i1<0) i1 +=nr; + if (i2>=nr) i2 -=nr; + pix[0] = sp+i1; pix[1] = sp+i2; + wgt[0] = 1-w1; wgt[1] = w1; + } + if (ir2<(4*nside_)) + { + get_ring_info2 (ir2, sp, nr, theta2, shift); + dphi = twopi/nr; + tmp = (ptg.phi/dphi - .5*shift); + i1 = (tmp<0) ? I(tmp)-1 : I(tmp); + w1 = (ptg.phi-(i1+.5*shift)*dphi)/dphi; + i2 = i1+1; + if (i1<0) i1 +=nr; + if (i2>=nr) i2 -=nr; + pix[2] = sp+i1; pix[3] = sp+i2; + wgt[2] = 1-w1; wgt[3] = w1; + } + + if (ir1==0) + { + double wtheta = ptg.theta/theta2; + wgt[2] *= wtheta; wgt[3] *= wtheta; + double fac = (1-wtheta)*0.25; + wgt[0] = fac; wgt[1] = fac; wgt[2] += fac; wgt[3] +=fac; + pix[0] = (pix[2]+2)&3; + pix[1] = (pix[3]+2)&3; + } + else if (ir2==4*nside_) + { + double wtheta = (ptg.theta-theta1)/(pi-theta1); + wgt[0] *= (1-wtheta); wgt[1] *= (1-wtheta); + double fac = wtheta*0.25; + wgt[0] += fac; wgt[1] += fac; wgt[2] = fac; wgt[3] =fac; + pix[2] = ((pix[0]+2)&3)+npix_-4; + pix[3] = ((pix[1]+2)&3)+npix_-4; + } + else + { + double wtheta = (ptg.theta-theta1)/(theta2-theta1); + wgt[0] *= (1-wtheta); wgt[1] *= (1-wtheta); + wgt[2] *= wtheta; wgt[3] *= wtheta; + } + + if (scheme_==NEST) + for (tsize m=0; m void T_Healpix_Base::swap (T_Healpix_Base &other) + { + std::swap(order_,other.order_); + std::swap(nside_,other.nside_); + std::swap(npface_,other.npface_); + std::swap(ncap_,other.ncap_); + std::swap(npix_,other.npix_); + std::swap(fact1_,other.fact1_); + std::swap(fact2_,other.fact2_); + std::swap(scheme_,other.scheme_); + } + +template double T_Healpix_Base::max_pixrad() const + { + vec3 va,vb; + va.set_z_phi (2./3., pi/(4*nside_)); + double t1 = 1.-1./nside_; + t1*=t1; + vb.set_z_phi (1-t1/3, 0); + return v_angle(va,vb); + } + +template double T_Healpix_Base::max_pixrad(I ring) const + { + if (ring>=2*nside_) ring=4*nside_-ring; + double z=ring2z(ring), z_up=(ring>1) ? ring2z(ring-1) : 1.; + vec3 mypos, uppos; + uppos.set_z_phi(z_up,0); + if (ring<=nside_) + { + mypos.set_z_phi(z,pi/(4*ring)); + return v_angle(mypos,uppos); + } + mypos.set_z_phi(z,0); + double vdist=v_angle(mypos,uppos); + double hdist=sqrt(1.-z*z)*pi/(4*nside_); + return max(hdist,vdist); + } + +template void T_Healpix_Base::xyf2loc (double x, double y, + int face, double &z, double &phi, double &sth, bool &have_sth) const + { + have_sth = false; + double jr = jrll[face] - x - y; + double nr; + if (jr<1) + { + nr = jr; + double tmp = nr*nr/3.; + z = 1 - tmp; + if (z > 0.99) + { + sth = std::sqrt(tmp*(2.0-tmp)); + have_sth = true; + } + } + else if (jr>3) + { + nr = 4-jr; + double tmp = nr*nr/3.; + z = tmp - 1; + if (z<-0.99) + { + sth = std::sqrt(tmp*(2.-tmp)); + have_sth = true; + } + } + else + { + nr = 1; + z = (2-jr)*2./3.; + } + + double tmp=jpll[face]*nr+x-y; + if (tmp<0) tmp+=8; + if (tmp>=8) tmp-=8; + phi = (nr<1e-15) ? 0 : (0.5*halfpi*tmp)/nr; + } + +namespace { + +vec3 locToVec3 (double z, double phi, double sth, bool have_sth) + { + if (have_sth) + return vec3(sth*cos(phi),sth*sin(phi),z); + else + { + vec3 res; + res.set_z_phi (z, phi); + return res; + } + } + +} // unnamed namespace + +template void T_Healpix_Base::boundaries(I pix, tsize step, + vector &out) const + { + out.resize(4*step); + int ix, iy, face; + pix2xyf(pix, ix, iy, face); + double dc = 0.5 / nside_; + double xc = (ix + 0.5)/nside_, yc = (iy + 0.5)/nside_; + double d = 1.0/(step*nside_); + for (tsize i=0; i arr T_Healpix_Base::swap_cycles() const + { + planck_assert(order_>=0, "need hierarchical map"); + planck_assert(order_<=13, "map too large"); + arr result(swap_clen[order_]); + tsize ofs=0; + for (int m=0; m; +template class T_Healpix_Base; +} // namespace healpix + diff --git a/libs/healpix_base/healpix_tables.cc b/libs/healpix_base/healpix_tables.cc new file mode 100644 index 000000000..9d4ec4625 --- /dev/null +++ b/libs/healpix_base/healpix_tables.cc @@ -0,0 +1,124 @@ +/* + * This file is part of Healpix_cxx. + * + * Healpix_cxx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Healpix_cxx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Healpix_cxx; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * For more information about HEALPix, see http://healpix.sourceforge.net + */ + +/* + * Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik + * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt + * (DLR). + */ + +/* + * Copyright (C) 2011 Max-Planck-Society + * Author: Martin Reinecke + */ + +#include "healpix_base/healpix_tables.h" + +namespace healpix{ + +using namespace std; + +const nside_dummy SET_NSIDE=nside_dummy(); + +const uint16 Healpix_Tables::utab[] = { +#define Z(a) 0x##a##0, 0x##a##1, 0x##a##4, 0x##a##5 +#define Y(a) Z(a##0), Z(a##1), Z(a##4), Z(a##5) +#define X(a) Y(a##0), Y(a##1), Y(a##4), Y(a##5) +X(0),X(1),X(4),X(5) +#undef X +#undef Y +#undef Z +}; + +const uint16 Healpix_Tables::ctab[] = { +#define Z(a) a,a+1,a+256,a+257 +#define Y(a) Z(a),Z(a+2),Z(a+512),Z(a+514) +#define X(a) Y(a),Y(a+4),Y(a+1024),Y(a+1028) +X(0),X(8),X(2048),X(2056) +#undef X +#undef Y +#undef Z +}; + +const int Healpix_Tables::jrll[] = { 2,2,2,2,3,3,3,3,4,4,4,4 }, + Healpix_Tables::jpll[] = { 1,3,5,7,0,2,4,6,1,3,5,7 }; + +const uint8 Healpix_Tables::peano_subpix[2][8][4] = + { { {0,1,3,2}, {3,0,2,1}, {2,3,1,0}, {1,2,0,3}, + {0,3,1,2}, {1,0,2,3}, {2,1,3,0}, {3,2,0,1} }, + { {0,1,3,2}, {1,3,2,0}, {3,2,0,1}, {2,0,1,3}, + {0,2,3,1}, {1,0,2,3}, {3,1,0,2}, {2,3,1,0} } }; +const uint8 Healpix_Tables::peano_subpath[2][8][4] = + { { {4,0,6,0}, {7,5,1,1}, {2,4,2,6}, {3,3,7,5}, + {0,2,4,4}, {5,1,5,3}, {6,6,0,2}, {1,7,3,7} }, + { {4,0,0,6}, {5,1,1,7}, {6,2,2,4}, {7,3,3,5}, + {0,4,4,2}, {1,5,5,3}, {2,6,6,0}, {3,7,7,1} } }; +const uint8 Healpix_Tables::peano_face2path[2][12] = + { { 2,5,2,5,3,6,3,6,2,3,2,3 }, { 2,6,2,3,3,5,2,6,2,3,3,5 } }; +const uint8 Healpix_Tables::peano_face2face[2][12] = + { { 0,5,6,11,10,1,4,7,2,3,8,9 }, { 0,5,8,9,6,1,2,7,10,11,4,3 } }; + +const int Healpix_Tables::nb_xoffset[] = { -1,-1, 0, 1, 1, 1, 0,-1 }, + Healpix_Tables::nb_yoffset[] = { 0, 1, 1, 1, 0,-1,-1,-1 }; +const int Healpix_Tables::nb_facearray[][12] = + { { 8, 9,10,11,-1,-1,-1,-1,10,11, 8, 9 }, // S + { 5, 6, 7, 4, 8, 9,10,11, 9,10,11, 8 }, // SE + { -1,-1,-1,-1, 5, 6, 7, 4,-1,-1,-1,-1 }, // E + { 4, 5, 6, 7,11, 8, 9,10,11, 8, 9,10 }, // SW + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 }, // center + { 1, 2, 3, 0, 0, 1, 2, 3, 5, 6, 7, 4 }, // NE + { -1,-1,-1,-1, 7, 4, 5, 6,-1,-1,-1,-1 }, // W + { 3, 0, 1, 2, 3, 0, 1, 2, 4, 5, 6, 7 }, // NW + { 2, 3, 0, 1,-1,-1,-1,-1, 0, 1, 2, 3 } }; // N +const int Healpix_Tables::nb_swaparray[][3] = + { { 0,0,3 }, // S + { 0,0,6 }, // SE + { 0,0,0 }, // E + { 0,0,5 }, // SW + { 0,0,0 }, // center + { 5,0,0 }, // NE + { 0,0,0 }, // W + { 6,0,0 }, // NW + { 3,0,0 } }; // N + +const int Healpix_Tables::swap_clen[] = + { 0,7,5,4,12,10,13,18,14,19,18,17,27,21 }; +const int Healpix_Tables::swap_cycle[] = + { 0,1,8,12,16,21,40, + 0,1,2,40,114, + 0,4,160,263, + 0,4,30,49,51,87,526,1027,1105,1387,1807,2637, + 0,8,10,18,39,74,146,307,452,4737, + 0,1,2,7,9,17,80,410,1526,1921,32859,33566,38931, + 0,5,6,10,12,24,27,95,372,494,924,1409,3492,4248,9137,66043,103369,156899, + 0,1,2,3,4,45,125,351,697,24337,102940,266194,341855,419857, + 0,1,2,3,9,16,1705,2082,2126,8177,12753,15410,52642,80493,83235,88387,99444, + 1675361,2495125, + 0,2,6,8,9,11,20,50,93,152,183,2137,13671,44794,486954,741908,4803258, + 5692573, + 0,1,5,6,44,53,470,2847,3433,4906,13654,14710,400447,1797382,2744492, + 18775974,23541521, + 0,4,9,10,16,33,83,117,318,451,5759,10015,128975,171834,211256,347608, + 1278690,2154097,2590798,3427694,5581717,21012301,27023976,72522811, + 95032729,139166747,171822389, + 0,5,10,267,344,363,2968,3159,9083,18437,76602,147614,1246902,1593138, + 2035574,6529391,9511830,11340287,29565945,281666026,677946848 }; +} // namespace healpix + diff --git a/libs/healpix_base/include/healpix_base/alloc_utils.h b/libs/healpix_base/include/healpix_base/alloc_utils.h new file mode 100644 index 000000000..814ad8fc6 --- /dev/null +++ b/libs/healpix_base/include/healpix_base/alloc_utils.h @@ -0,0 +1,78 @@ + +/* + * This file is part of libcxxsupport. + * + * libcxxsupport is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * libcxxsupport is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libcxxsupport; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik + * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt + * (DLR). + */ + +/*! \file alloc_utils.h + * Classes providing raw memory allocation and deallocation support. + * + * Copyright (C) 2011 Max-Planck-Society + * \author Martin Reinecke + */ + +#ifndef PLANCK_ALLOC_UTILS_H +#define PLANCK_ALLOC_UTILS_H + +#include +#include "healpix_base/datatypes.h" + +namespace healpix{ +template class normalAlloc__ + { + public: + T *alloc(tsize sz) const { return (sz>0) ? new T[sz] : 0; } + void dealloc (T *ptr) const { delete[] ptr; } + }; + +template class alignAlloc__ + { + public: + T *alloc(tsize sz) const + { + using namespace std; + if (sz==0) return 0; + planck_assert((align&(align-1))==0,"alignment must be power of 2"); + void *res; +/* OSX up to version 10.5 does not define posix_memalign(), but fortunately + the normal malloc() returns 16 byte aligned storage */ +#ifdef __APPLE__ + planck_assert(align<=16, "bad alignment requested"); + res=malloc(sz*sizeof(T)); + planck_assert(res!=0,"error in malloc()"); +#else + planck_assert(posix_memalign(&res,align,sz*sizeof(T))==0, + "error in posix_memalign()"); +#endif + return static_cast(res); + } + void dealloc(T *ptr) const + { + using namespace std; + free(ptr); + } + }; + + +} // namespace healpix + +#endif diff --git a/libs/healpix_base/include/healpix_base/arr.h b/libs/healpix_base/include/healpix_base/arr.h new file mode 100644 index 000000000..e97ab1cc8 --- /dev/null +++ b/libs/healpix_base/include/healpix_base/arr.h @@ -0,0 +1,658 @@ +/* + * This file is part of libcxxsupport. + * + * libcxxsupport is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * libcxxsupport is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libcxxsupport; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik + * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt + * (DLR). + */ + +/*! \file arr.h + * Various high-performance array classes used by the Planck LevelS package. + * + * Copyright (C) 2002-2012 Max-Planck-Society + * \author Martin Reinecke + */ + +#ifndef PLANCK_ARR_H +#define PLANCK_ARR_H + +#include +#include +#include +#include "healpix_base/alloc_utils.h" +#include "healpix_base/datatypes.h" +#include "healpix_base/math_utils.h" + +namespace healpix{ + +/*! \defgroup arraygroup Array classes */ +/*! \{ */ + +/*! View of a 1D array */ +template class arr_ref + { + protected: + tsize s; + T *d; + + public: + /*! Constructs an \a arr_ref of size \a s_, starting at \a d_. */ + arr_ref(T *d_, tsize s_) : s(s_),d(d_) {} + + /*! Returns the current array size. */ + tsize size() const { return s; } + + /*! Writes \a val into every element of the array. */ + void fill (const T &val) + { for (tsize m=0; m T &operator[] (T2 n) {return d[n];} + /*! Returns a constant reference to element \a n */ + template const T &operator[] (T2 n) const {return d[n];} + + /*! Returns a pointer to the first array element, or NULL if the array + is zero-sized. */ + T *begin() { return d; } + /*! Returns a pointer to the one-past-last array element, or NULL if the + array is zero-sized. */ + T *end() { return d+s; } + /*! Returns a constant pointer to the first array element, or NULL if the + array is zero-sized. */ + const T *begin() const { return d; } + /*! Returns a constant pointer to the one-past-last array element, or NULL + if the array is zero-sized. */ + const T *end() const { return d+s; } + + /*! Copies all array elements to \a ptr. */ + template void copyToPtr (T *ptr) const + { for (tsize m=0; m void sort(Comp comp) + { std::sort (d,d+s,comp); } + + /*! Helper function for linear interpolation (or extrapolation). + \a idx and \a val are computed such that + \a val=d[idx]+frac*(d[idx+1]-d[idx]). If \a vald[s-1], frac will be larger than 1. In all other + cases \a 0<=frac<=1. + + The array must be ordered in ascending order; no two values may be + equal. */ + void interpol_helper (const T &val, tsize &idx, double &frac) const + { healpix::interpol_helper (d, d+s, val, idx, frac); } + + /*! Helper function for linear interpolation (or extrapolation). + \a idx and \a val are computed such that + \a val=d[idx]+frac*(d[idx+1]-d[idx]). If \a comp(val,d[0])==true, + \a frac will be negative, if \a comp(val,d[s-1])==false, frac will be + larger than 1. In all other cases \a 0<=frac<=1. + + The array must be ordered such that \a comp(d[i],d[j])==true + for \a i void interpol_helper (const T &val, Comp comp, + tsize &idx, double &frac) const + { healpix::interpol_helper (d, d+s, val, comp, idx, frac); } + + /*! Returns the minimum and maximum entry in \a minv and \a maxv, + respectively. Throws an exception if the array is zero-sized. */ + void minmax (T &minv, T &maxv) const + { + planck_assert(s>0,"trying to find min and max of a zero-sized array"); + minv=maxv=d[0]; + for (tsize m=1; mmaxv) maxv=d[m]; + } + } + + /*! Returns \a true, if \a val is found in the array, else \a false. */ + bool contains (const T &val) const + { + for (tsize m=0; m class fix_arr + { + private: + T d[sz]; + + public: + /*! Returns the size of the array. */ + tsize size() const { return sz; } + + /*! Returns a reference to element \a n */ + template T &operator[] (T2 n) {return d[n];} + /*! Returns a constant reference to element \a n */ + template const T &operator[] (T2 n) const {return d[n];} + }; + + +/*! One-dimensional array type, with selectable storage management. */ +template class arrT: public arr_ref + { + private: + storageManager stm; + bool own; + + void reset() + { this->d=0; this->s=0; own=true; } + + public: + /*! Creates a zero-sized array. */ + arrT() : arr_ref(0,0), own(true) {} + /*! Creates an array with \a sz entries. */ + arrT(tsize sz) : arr_ref(stm.alloc(sz),sz), own(true) {} + /*! Creates an array with \a sz entries, and initializes them with + \a inival. */ + arrT(tsize sz, const T &inival) : arr_ref(stm.alloc(sz),sz), own(true) + { this->fill(inival); } + /*! Creates an array with \a sz entries, which uses the memory pointed + to by \a ptr. + \note \a ptr will not be deallocated by the destructor. + \warning Only use this if you REALLY know what you are doing. + In particular, this is only safely usable if +
    +
  • \a T is a POD type
  • +
  • \a ptr survives during the lifetime of the array object
  • +
  • \a ptr is not subject to garbage collection
  • +
+ Other restrictions may apply. You have been warned. */ + arrT (T *ptr, tsize sz): arr_ref(ptr,sz), own(false) {} + /*! Creates an array which is a copy of \a orig. The data in \a orig + is duplicated. */ + arrT (const arrT &orig): arr_ref(stm.alloc(orig.s),orig.s), own(true) + { for (tsize m=0; ms; ++m) this->d[m] = orig.d[m]; } + /*! Frees the memory allocated by the object. */ + ~arrT() { if (own) stm.dealloc(this->d); } + + /*! Allocates space for \a sz elements. The content of the array is + undefined on exit. \a sz can be 0. If \a sz is the + same as the current size, no reallocation is performed. */ + void alloc (tsize sz) + { + if (sz==this->s) return; + if (own) stm.dealloc(this->d); + this->s = sz; + this->d = stm.alloc(sz); + own = true; + } + /*! Allocates space for \a sz elements. If \a sz is the + same as the current size, no reallocation is performed. + All elements are set to \a inival. */ + void allocAndFill (tsize sz, const T &inival) + { alloc(sz); this->fill(inival); } + /*! Deallocates the memory held by the array, and sets the array size + to 0. */ + void dealloc() {if (own) stm.dealloc(this->d); reset();} + /*! Resizes the array to hold \a sz elements. The existing content of the + array is copied over to the new array to the extent possible. + \a sz can be 0. If \a sz is the same as the current size, no + reallocation is performed. */ + void resize (tsize sz) + { + using namespace std; + if (sz==this->s) return; + T *tmp = stm.alloc(sz); + for (tsize m=0; ms); ++m) + tmp[m]=this->d[m]; + if (own) stm.dealloc(this->d); + this->s = sz; + this->d = tmp; + own = true; + } + + /*! Changes the array to be a copy of \a orig. */ + arrT &operator= (const arrT &orig) + { + if (this==&orig) return *this; + alloc (orig.s); + for (tsize m=0; ms; ++m) this->d[m] = orig.d[m]; + return *this; + } + + /*! Changes the array to be a copy of the std::vector \a orig. */ + template void copyFrom (const std::vector &orig) + { + alloc (orig.size()); + for (tsize m=0; ms; ++m) this->d[m] = orig[m]; + } + /*! Changes the std::vector \a vec to be a copy of the object. */ + template void copyTo (std::vector &vec) const + { + vec.clear(); vec.reserve(this->s); + for (tsize m=0; ms; ++m) vec.push_back(this->d[m]); + } + + /*! Reserves space for \a sz elements, then copies \a sz elements + from \a ptr into the array. */ + template void copyFromPtr (const T2 *ptr, tsize sz) + { + alloc(sz); + for (tsize m=0; ms; ++m) this->d[m]=ptr[m]; + } + + /*! Assigns the contents and size of \a other to the array. + \note On exit, \a other is zero-sized! */ + void transfer (arrT &other) + { + if (own) stm.dealloc(this->d); + this->d=other.d; + this->s=other.s; + own=other.own; + other.reset(); + } + /*! Swaps contents and size with \a other. */ + void swap (arrT &other) + { + std::swap(this->d,other.d); + std::swap(this->s,other.s); + std::swap(own,other.own); + } + }; + +/*! One-dimensional array type. */ +template + class arr: public arrT > + { + public: + /*! Creates a zero-sized array. */ + arr() : arrT >() {} + /*! Creates an array with \a sz entries. */ + arr(tsize sz) : arrT >(sz) {} + /*! Creates an array with \a sz entries, and initializes them with + \a inival. */ + arr(tsize sz, const T &inival) : arrT >(sz,inival) {} + /*! Creates an array with \a sz entries, which uses the memory pointed + to by \a ptr. + \note \a ptr will not be deallocated by the destructor. + \warning Only use this if you REALLY know what you are doing. + In particular, this is only safely usable if +
    +
  • \a T is a POD type
  • +
  • \a ptr survives during the lifetime of the array object
  • +
  • \a ptr is not subject to garbage collection
  • +
+ Other restrictions may apply. You have been warned. */ + arr (T *ptr, tsize sz): arrT >(ptr,sz) {} + /*! Creates an array which is a copy of \a orig. The data in \a orig + is duplicated. */ + arr (const arr &orig): arrT >(orig) {} + }; + +/*! One-dimensional array type, with selectable storage alignment. */ +template + class arr_align: public arrT > + { + public: + /*! Creates a zero-sized array. */ + arr_align() : arrT >() {} + /*! Creates an array with \a sz entries. */ + arr_align(tsize sz) : arrT >(sz) {} + /*! Creates an array with \a sz entries, and initializes them with + \a inival. */ + arr_align(tsize sz, const T &inival) + : arrT >(sz,inival) {} + }; + + +/*! Two-dimensional array type, with selectable storage management. + The storage ordering is the same as in C. + An entry is located by address arithmetic, not by double dereferencing. + The indices start at zero. */ +template class arr2T + { + private: + tsize s1, s2; + arrT d; + + public: + /*! Creates a zero-sized array. */ + arr2T() : s1(0), s2(0) {} + /*! Creates an array with the dimensions \a sz1 and \a sz2. */ + arr2T(tsize sz1, tsize sz2) + : s1(sz1), s2(sz2), d(s1*s2) {} + /*! Creates an array with the dimensions \a sz1 and \a sz2 + and initializes them with \a inival. */ + arr2T(tsize sz1, tsize sz2, const T &inival) + : s1(sz1), s2(sz2), d (s1*s2) + { fill(inival); } + /*! Creates the array as a copy of \a orig. */ + arr2T(const arr2T &orig) + : s1(orig.s1), s2(orig.s2), d(orig.d) {} + /*! Frees the memory associated with the array. */ + ~arr2T() {} + + /*! Returns the first array dimension. */ + tsize size1() const { return s1; } + /*! Returns the second array dimension. */ + tsize size2() const { return s2; } + /*! Returns the total array size, i.e. the product of both dimensions. */ + tsize size () const { return s1*s2; } + + /*! Allocates space for an array with \a sz1*sz2 elements. + The content of the array is undefined on exit. + \a sz1 or \a sz2 can be 0. If \a sz1*sz2 is the same as the + currently allocated space, no reallocation is performed. */ + void alloc (tsize sz1, tsize sz2) + { + if (sz1*sz2 != d.size()) + d.alloc(sz1*sz2); + s1=sz1; s2=sz2; + } + /*! Allocates space for an array with \a sz1*sz2 elements. + All elements are set to \a inival. + \a sz1 or \a sz2 can be 0. If \a sz1*sz2 is the same as the + currently allocated space, no reallocation is performed. */ + void allocAndFill (tsize sz1, tsize sz2, const T &inival) + { alloc(sz1,sz2); fill(inival); } + /*! Allocates space for an array with \a sz1*sz2 elements. + The content of the array is undefined on exit. + \a sz1 or \a sz2 can be 0. If \a sz1*sz2 is smaller than the + currently allocated space, no reallocation is performed. */ + void fast_alloc (tsize sz1, tsize sz2) + { + if (sz1*sz2<=d.size()) + { s1=sz1; s2=sz2; } + else + alloc(sz1,sz2); + } + /*! Deallocates the space and makes the array zero-sized. */ + void dealloc () {d.dealloc(); s1=0; s2=0;} + + /*! Sets all array elements to \a val. */ + void fill (const T &val) + { for (tsize m=0; m T *operator[] (T2 n) {return &d[n*s2];} + /*! Returns a constant pointer to the beginning of slice \a n. */ + template const T *operator[] (T2 n) const {return &d[n*s2];} + + /*! Returns a reference to the element with the indices \a n1 and \a n2. */ + template T &operator() (T2 n1, T3 n2) + {return d[n1*s2 + n2];} + /*! Returns a constant reference to the element with the indices + \a n1 and \a n2. */ + template const T &operator() (T2 n1, T3 n2) const + {return d[n1*s2 + n2];} + + /*! Returns the minimum and maximum entry in \a minv and \a maxv, + respectively. Throws an exception if the array is zero-sized. */ + void minmax (T &minv, T &maxv) const + { + planck_assert(s1*s2>0, + "trying to find min and max of a zero-sized array"); + minv=maxv=d[0]; + for (tsize m=1; mmaxv) maxv=d[m]; + } + } + + /*! Swaps contents and sizes with \a other. */ + void swap (arr2T &other) + { + d.swap(other.d); + std::swap(s1,other.s1); + std::swap(s2,other.s2); + } + + /*! Returns \c true if the array and \a other have the same dimensions, + else \c false. */ + template bool conformable + (const arr2T &other) const + { return (other.size1()==s1) && (other.size2()==s2); } + }; + +/*! Two-dimensional array type. The storage ordering is the same as in C. + An entry is located by address arithmetic, not by double dereferencing. + The indices start at zero. */ +template + class arr2: public arr2T > + { + public: + /*! Creates a zero-sized array. */ + arr2() : arr2T > () {} + /*! Creates an array with the dimensions \a sz1 and \a sz2. */ + arr2(tsize sz1, tsize sz2) : arr2T > (sz1,sz2) {} + /*! Creates an array with the dimensions \a sz1 and \a sz2 + and initializes them with \a inival. */ + arr2(tsize sz1, tsize sz2, const T &inival) + : arr2T > (sz1,sz2,inival) {} + }; + +/*! Two-dimensional array type, with selectable storage alignment. + The storage ordering is the same as in C. + An entry is located by address arithmetic, not by double dereferencing. + The indices start at zero. */ +template + class arr2_align: public arr2T > + { + public: + /*! Creates a zero-sized array. */ + arr2_align() : arr2T > () {} + /*! Creates an array with the dimensions \a sz1 and \a sz2. */ + arr2_align(tsize sz1, tsize sz2) + : arr2T > (sz1,sz2) {} + /*! Creates an array with the dimensions \a sz1 and \a sz2 + and initializes them with \a inival. */ + arr2_align(tsize sz1, tsize sz2, const T &inival) + : arr2T > (sz1,sz2,inival) {} + }; + +/*! Two-dimensional array type. An entry is located by double dereferencing, + i.e. via an array of pointers. The indices start at zero. */ +template class arr2b + { + private: + tsize s1, s2; + arr d; + arr d1; + + void fill_d1() + { for (tsize m=0; m T *operator[] (T2 n) {return d1[n];} + /*! Returns a constant pointer to the beginning of slice \a n. */ + template const T *operator[] (T2 n) const {return d1[n];} + + /*! Returns a pointer to the beginning of the pointer array. */ + T **p0() {return &d1[0];} + }; + + +/*! Three-dimensional array type. The storage ordering is the same as in C. + An entry is located by address arithmetic, not by multiple dereferencing. + The indices start at zero. */ +template class arr3 + { + private: + tsize s1, s2, s3, s2s3; + arr d; + + public: + /*! Creates a zero-sized array. */ + arr3() : s1(0), s2(0), s3(0), s2s3(0), d(0) {} + /*! Creates an array with the dimensions \a sz1, \a sz2 and \a sz3. */ + arr3(tsize sz1, tsize sz2, tsize sz3) + : s1(sz1), s2(sz2), s3(sz3), s2s3(s2*s3), d(s1*s2*s3) {} + /*! Creates the array as a copy of \a orig. */ + arr3(const arr3 &orig) + : s1(orig.s1), s2(orig.s2), s3(orig.s3), s2s3(orig.s2s3), d(orig.d) {} + /*! Frees the memory associated with the array. */ + ~arr3() {} + + /*! Returns the first array dimension. */ + tsize size1() const { return s1; } + /*! Returns the second array dimension. */ + tsize size2() const { return s2; } + /*! Returns the third array dimension. */ + tsize size3() const { return s3; } + /*! Returns the total array size, i.e. the product of all dimensions. */ + tsize size () const { return s1*s2*s3; } + + /*! Allocates space for an array with \a sz1*sz2*sz3 elements. + The content of the array is undefined on exit. */ + void alloc (tsize sz1, tsize sz2, tsize sz3) + { + d.alloc(sz1*sz2*sz3); + s1=sz1; s2=sz2; s3=sz3; s2s3=s2*s3; + } + /*! Deallocates the space and makes the array zero-sized. */ + void dealloc () {d.dealloc(); s1=0; s2=0; s3=0; s2s3=0;} + + /*! Sets all array elements to \a val. */ + void fill (const T &val) + { d.fill(val); } + + /*! Changes the array to be a copy of \a orig. */ + arr3 &operator= (const arr3 &orig) + { + if (this==&orig) return *this; + alloc (orig.s1, orig.s2, orig.s3); + d = orig.d; + return *this; + } + + /*! Returns a reference to the element with the indices + \a n1, \a n2 and \a n3. */ + template T &operator() + (T2 n1, T3 n2, T4 n3) + {return d[n1*s2s3 + n2*s3 + n3];} + /*! Returns a constant reference to the element with the indices + \a n1, \a n2 and \a n3. */ + template const T &operator() + (T2 n1, T3 n2, T4 n3) const + {return d[n1*s2s3 + n2*s3 + n3];} + + /*! Swaps contents and sizes with \a other. */ + void swap (arr3 &other) + { + d.swap(other.d); + std::swap(s1,other.s1); + std::swap(s2,other.s2); + std::swap(s3,other.s3); + std::swap(s2s3,other.s2s3); + } + + /*! Returns \c true if the array and \a other have the same dimensions, + else \c false. */ + template bool conformable (const arr3 &other) const + { return (other.size1()==s1)&&(other.size2()==s2)&&(other.size3()==s3); } + }; + +/*! \} */ + +} // namespace healpix +#endif + diff --git a/libs/healpix_base/include/healpix_base/datatypes.h b/libs/healpix_base/include/healpix_base/datatypes.h new file mode 100644 index 000000000..12d019d97 --- /dev/null +++ b/libs/healpix_base/include/healpix_base/datatypes.h @@ -0,0 +1,295 @@ +/* + * This file is part of libcxxsupport. + * + * libcxxsupport is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * libcxxsupport is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libcxxsupport; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik + * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt + * (DLR). + */ + +/*! \file datatypes.h + * This file defines various platform-independent data types. + * If any of the requested types is not available, compilation aborts + * with an error (unfortunately a rather obscure one). + * + * Copyright (C) 2004-2011 Max-Planck-Society + * \author Martin Reinecke + */ + +#ifndef PLANCK_DATATYPES_H +#define PLANCK_DATATYPES_H + +#include +#include +#include "healpix_base/error_handling.h" + +namespace healpix{ + +// Template magic to select the proper data types. These templates +// should not be used outside this file. + +template struct sizeChooserHelper__ + { typedef void TYPE; }; + +template struct sizeChooserHelper__ + { typedef T TYPE; }; + +template struct sizeChooserHelper2__ + { typedef T1 TYPE; }; + +template struct sizeChooserHelper2__ + { typedef T2 TYPE; }; + +template struct sizeChooserHelper2__ + { typedef T3 TYPE; }; + +template <> struct sizeChooserHelper2__ + { }; + +template + struct sizeChooser__ + { + typedef typename sizeChooserHelper2__ + ::TYPE, + typename sizeChooserHelper__::TYPE, + typename sizeChooserHelper__::TYPE >::TYPE TYPE; + }; + +typedef signed char int8; +typedef unsigned char uint8; + +typedef sizeChooser__<2, short, int>::TYPE + int16; +typedef sizeChooser__<2, unsigned short, unsigned int>::TYPE + uint16; + +typedef sizeChooser__<4, int, long, short>::TYPE + int32; +typedef sizeChooser__<4, unsigned int, unsigned long, unsigned short>::TYPE + uint32; + +typedef sizeChooser__<8, long, long long>::TYPE + int64; +typedef sizeChooser__<8, unsigned long, unsigned long long>::TYPE + uint64; + +typedef sizeChooser__<4, float, double>::TYPE + float32; +typedef sizeChooser__<8, double, long double>::TYPE + float64; + +/*! unsigned integer type which should be used for array sizes */ +typedef std::size_t tsize; +/*! signed integer type which should be used for relative array indices */ +typedef std::ptrdiff_t tdiff; + +/*! mapping of Planck data types to integer constants */ +enum PDT { + PLANCK_INT8 = 0, + PLANCK_UINT8 = 1, + PLANCK_INT16 = 2, + PLANCK_UINT16 = 3, + PLANCK_INT32 = 4, + PLANCK_UINT32 = 5, + PLANCK_INT64 = 6, + PLANCK_UINT64 = 7, + PLANCK_FLOAT32 = 8, + PLANCK_FLOAT64 = 9, + PLANCK_BOOL = 10, + PLANCK_STRING = 11, + PLANCK_INVALID = -1 }; + +/*! Returns the \a PDT constant associated with \a T. */ +template inline PDT planckType() + { planck_fail(T::UNSUPPORTED_DATA_TYPE); } +template<> inline PDT planckType () { return PLANCK_INT8; } +template<> inline PDT planckType () { return PLANCK_UINT8; } +template<> inline PDT planckType () { return PLANCK_INT16; } +template<> inline PDT planckType () { return PLANCK_UINT16; } +template<> inline PDT planckType () { return PLANCK_INT32; } +template<> inline PDT planckType () { return PLANCK_UINT32; } +template<> inline PDT planckType () { return PLANCK_INT64; } +template<> inline PDT planckType () { return PLANCK_UINT64; } +template<> inline PDT planckType () { return PLANCK_FLOAT32;} +template<> inline PDT planckType () { return PLANCK_FLOAT64;} +template<> inline PDT planckType () { return PLANCK_BOOL; } +template<> inline PDT planckType() { return PLANCK_STRING; } + +/*! Returns the size (in bytes) of the Planck data type \a type. */ +inline int type2size (PDT type) + { + switch (type) + { + case PLANCK_INT8 : + case PLANCK_UINT8 : + case PLANCK_BOOL : + case PLANCK_STRING : return 1; + case PLANCK_INT16 : + case PLANCK_UINT16 : return 2; + case PLANCK_INT32 : + case PLANCK_UINT32 : + case PLANCK_FLOAT32: return 4; + case PLANCK_INT64 : + case PLANCK_UINT64 : + case PLANCK_FLOAT64: return 8; + default: + planck_fail ("type2size: unsupported data type"); + } + } + +/*! Converts the string \a type to a \a PDT. */ +inline PDT string2type(const std::string &type) + { + if (type=="FLOAT64") return PLANCK_FLOAT64; + if (type=="FLOAT32") return PLANCK_FLOAT32; + if (type=="INT8") return PLANCK_INT8; + if (type=="UINT8") return PLANCK_UINT8; + if (type=="INT16") return PLANCK_INT16; + if (type=="UINT16") return PLANCK_UINT16; + if (type=="INT32") return PLANCK_INT32; + if (type=="UINT32") return PLANCK_UINT32; + if (type=="INT64") return PLANCK_INT64; + if (type=="UINT64") return PLANCK_UINT64; + if (type=="BOOL") return PLANCK_BOOL; + if (type=="STRING") return PLANCK_STRING; + planck_fail ("string2type: unknown data type '"+type+"'"); + } + +/*! Converts the Planck data type \a type to a C string. */ +inline const char *type2string (PDT type) + { + switch (type) + { + case PLANCK_INT8 : return "INT8"; + case PLANCK_UINT8 : return "UINT8"; + case PLANCK_INT16 : return "INT16"; + case PLANCK_UINT16 : return "UINT16"; + case PLANCK_INT32 : return "INT32"; + case PLANCK_UINT32 : return "UINT32"; + case PLANCK_INT64 : return "INT64"; + case PLANCK_UINT64 : return "UINT64"; + case PLANCK_FLOAT32: return "FLOAT32"; + case PLANCK_FLOAT64: return "FLOAT64"; + case PLANCK_BOOL : return "BOOL"; + case PLANCK_STRING : return "STRING"; + default: + planck_fail ("type2string: unsupported data type"); + } + } + +/*! Returns a C string describing the data type \a T. */ +template inline const char *type2typename () + { planck_fail(T::UNSUPPORTED_DATA_TYPE); } +template<> inline const char *type2typename () + { return "signed char"; } +template<> inline const char *type2typename () + { return "unsigned char"; } +template<> inline const char *type2typename () + { return "short"; } +template<> inline const char *type2typename () + { return "unsigned short"; } +template<> inline const char *type2typename () + { return "int"; } +template<> inline const char *type2typename () + { return "unsigned int"; } +template<> inline const char *type2typename () + { return "long"; } +template<> inline const char *type2typename () + { return "unsigned long"; } +template<> inline const char *type2typename () + { return "long long"; } +template<> inline const char *type2typename () + { return "unsigned long long"; } +template<> inline const char *type2typename () + { return "float"; } +template<> inline const char *type2typename () + { return "double"; } +template<> inline const char *type2typename () + { return "long double"; } +template<> inline const char *type2typename () + { return "bool"; } +template<> inline const char *type2typename () + { return "std::string"; } + +/*! mapping of "native" data types to integer constants */ +enum NDT { + NAT_CHAR, + NAT_SCHAR, + NAT_UCHAR, + NAT_SHORT, + NAT_USHORT, + NAT_INT, + NAT_UINT, + NAT_LONG, + NAT_ULONG, + NAT_LONGLONG, + NAT_ULONGLONG, + NAT_FLOAT, + NAT_DOUBLE, + NAT_LONGDOUBLE, + NAT_BOOL, + NAT_STRING }; + +/*! Returns the \a NDT constant associated with \a T. */ +template inline NDT nativeType() + { planck_fail(T::UNSUPPORTED_DATA_TYPE); } +template<> inline NDT nativeType () { return NAT_CHAR; } +template<> inline NDT nativeType () { return NAT_SCHAR; } +template<> inline NDT nativeType () { return NAT_UCHAR; } +template<> inline NDT nativeType () { return NAT_SHORT; } +template<> inline NDT nativeType () { return NAT_USHORT; } +template<> inline NDT nativeType () { return NAT_INT; } +template<> inline NDT nativeType () { return NAT_UINT; } +template<> inline NDT nativeType () { return NAT_LONG; } +template<> inline NDT nativeType () { return NAT_ULONG; } +template<> inline NDT nativeType () { return NAT_LONGLONG; } +template<> inline NDT nativeType() { return NAT_ULONGLONG; } +template<> inline NDT nativeType () { return NAT_FLOAT; } +template<> inline NDT nativeType () { return NAT_DOUBLE; } +template<> inline NDT nativeType () { return NAT_LONGDOUBLE;} +template<> inline NDT nativeType () { return NAT_BOOL; } +template<> inline NDT nativeType () { return NAT_STRING; } + +/*! Returns the size (in bytes) of the native data type \a type. */ +inline int ndt2size (NDT type) + { + switch (type) + { + case NAT_CHAR : + case NAT_SCHAR : + case NAT_UCHAR : return sizeof(char); + case NAT_SHORT : + case NAT_USHORT : return sizeof(short); + case NAT_INT : + case NAT_UINT : return sizeof(int); + case NAT_LONG : + case NAT_ULONG : return sizeof(long); + case NAT_LONGLONG : + case NAT_ULONGLONG : return sizeof(long long); + case NAT_FLOAT : return sizeof(float); + case NAT_DOUBLE : return sizeof(double); + case NAT_LONGDOUBLE: return sizeof(long double); + case NAT_BOOL : return sizeof(bool); + default: + planck_fail ("ndt2size: unsupported data type"); + } + } + +} // namespace healpix +#endif + diff --git a/libs/healpix_base/include/healpix_base/error_handling.h b/libs/healpix_base/include/healpix_base/error_handling.h new file mode 100644 index 000000000..732d910f6 --- /dev/null +++ b/libs/healpix_base/include/healpix_base/error_handling.h @@ -0,0 +1,104 @@ + +/* + * This file is part of libcxxsupport. + * + * libcxxsupport is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * libcxxsupport is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libcxxsupport; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik + * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt + * (DLR). + */ + +/*! \file error_handling.h + * Utilities for error reporting + * + * Copyright (C) 2003-2011 Max-Planck-Society + * Authors: Reinhard Hell, Martin Reinecke + */ + +#ifndef PLANCK_ERROR_HANDLING_H +#define PLANCK_ERROR_HANDLING_H + +#include +#include + +namespace healpix{ +#if defined (__GNUC__) +#define PLANCK_FUNC_NAME__ __PRETTY_FUNCTION__ +#else +#define PLANCK_FUNC_NAME__ 0 +#endif + +void planck_failure__(const char *file, int line, const char *func, + const std::string &msg); +void planck_failure__(const char *file, int line, const char *func, + const char *msg); +void killjob__(); + +class PlanckError + { + private: + std::string msg; + + public: + explicit PlanckError(const std::string &message); + explicit PlanckError(const char *message); + + virtual const char* what() const + { return msg.c_str(); } + + virtual ~PlanckError(); + }; + +/*! \defgroup errorgroup Error handling */ +/*! \{ */ + +/*! Writes diagnostic output and exits with an error status. */ +#define planck_fail(msg) \ +do { planck_failure__(__FILE__,__LINE__,PLANCK_FUNC_NAME__,msg); \ +throw PlanckError(msg); } while(0) + +/*! Throws a PlanckError without diagnostic message. */ +#define planck_fail_quietly(msg) \ +do { throw PlanckError(msg); } while(0) + +/*! Writes diagnostic output and exits with an error status if \a testval + is \a false. */ +#define planck_assert(testval,msg) \ +do { if (testval); else planck_fail(msg); } while(0) + +/*! Macro for improving error diagnostics. Should be placed immediately + after the opening brace of \c main(). Must be used in conjunction with + \c PLANCK_DIAGNOSIS_END. */ +#define PLANCK_DIAGNOSIS_BEGIN try { +/*! Macro for improving error diagnostics. Should be placed immediately + before the closing brace of \c main(). Must be used in conjunction with + \c PLANCK_DIAGNOSIS_BEGIN. */ +#define PLANCK_DIAGNOSIS_END \ +} \ +catch (PlanckError &) \ + { killjob__(); /* no need for further diagnostics; they were shown already */ } \ +catch (std::exception &e) \ + { std::cerr << "std::exception: " << e.what() << std::endl; killjob__(); } \ +catch (...) \ + { std::cerr << "Unknown exception" << std::endl; killjob__(); } + +/*! \} */ + +} // namespace healpix +#endif + diff --git a/libs/healpix_base/include/healpix_base/geom_utils.h b/libs/healpix_base/include/healpix_base/geom_utils.h new file mode 100644 index 000000000..cb3a66934 --- /dev/null +++ b/libs/healpix_base/include/healpix_base/geom_utils.h @@ -0,0 +1,85 @@ +/* + * This file is part of libcxxsupport. + * + * libcxxsupport is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * libcxxsupport is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libcxxsupport; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik + * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt + * (DLR). + */ + +/*! \file geom_utils.h + * Geometric utility functions. + * + * Copyright (C) 2003-2011 Max-Planck-Society + * \author Martin Reinecke + * \author Reinhard Hell + */ + +#ifndef PLANCK_GEOM_UTILS_H +#define PLANCK_GEOM_UTILS_H + +#include "healpix_base/math_utils.h" +#include "healpix_base/vec3.h" + +namespace healpix{ + +template class arr; + +/*! Returns the orientation when looking from point \a loc on the unit + sphere in the direction \a dir. \a loc must be normalized. The result + ranges from -pi to pi, is 0 for North and pi/2 for West, i.e. the angle + is given in mathematically positive sense. + + If \a loc is the North or South pole, the returned angle is + \a atan2(dir.y,dir.x). */ +inline double orientation (const vec3 &loc, const vec3 &dir) + { +// FIXME: here is still optimization potential + if (loc.x==0 && loc.y==0) + return (loc.z>0) ? safe_atan2(dir.y,-dir.x) : safe_atan2(dir.y,dir.x); + vec3 east (-loc.y, loc.x, 0); + vec3 north = crossprod(loc,east); + return safe_atan2(-dotprod(dir,east),dotprod(dir,north)); + } + +/*! Returns the angle between \a v1 and \a v2 in radians. */ +inline double v_angle (const vec3 &v1, const vec3 &v2) + { + using namespace std; + return atan2 (crossprod(v1,v2).Length(), dotprod(v1,v2)); + } + +/*! Returns the cosine of the angle between the two points on the sphere defined + by (\a z1, \a phi1) and (\a z2, \a phi2), respectively. \a z is the cosine + of the colatitude, and \a phi is the longitude. */ +inline double cosdist_zphi (double z1, double phi1, double z2, double phi2) + { + using namespace std; + return z1*z2+cos(phi1-phi2)*sqrt((1.-z1*z1)*(1.-z2*z2)); + } + +/*! Finds the smallest enclosing cone for a point set on the sphere according to + Barequet & Elber: Information Processing Letters 93(2005), p.83. + All points are expected to be passed as unit vectors. + The enclosing cone must have an opening angle &point, vec3 ¢er, + double &cosrad); + +} // namespace healpix +#endif + diff --git a/libs/healpix_base/include/healpix_base/healpix_base.h b/libs/healpix_base/include/healpix_base/healpix_base.h new file mode 100644 index 000000000..3c4ac0216 --- /dev/null +++ b/libs/healpix_base/include/healpix_base/healpix_base.h @@ -0,0 +1,381 @@ +/* + * This file is part of Healpix_cxx. + * + * Healpix_cxx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Healpix_cxx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Healpix_cxx; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * For more information about HEALPix, see http://healpix.sourceforge.net + */ + +/* + * Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik + * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt + * (DLR). + */ + +/*! \file healpix_base.h + * Copyright (C) 2003-2012 Max-Planck-Society + * \author Martin Reinecke + */ + +#ifndef HEALPIX_BASE_H +#define HEALPIX_BASE_H + +#include +#include "healpix_base/healpix_tables.h" +#include "healpix_base/pointing.h" +#include "healpix_base/arr.h" +#include "healpix_base/rangeset.h" + +namespace healpix{ + +/*! Functionality related to the HEALPix pixelisation. */ +template class T_Healpix_Base: public Healpix_Tables + { + protected: + /*! The order of the map; -1 for nonhierarchical map. */ + int order_; + /*! The N_side parameter of the map; 0 if not allocated. */ + I nside_; + I npface_, ncap_, npix_; + double fact1_, fact2_; + /*! The map's ordering scheme. */ + Healpix_Ordering_Scheme scheme_; + + /*! Returns the number of the next ring to the north of \a z=cos(theta). + It may return 0; in this case \a z lies north of all rings. */ + inline I ring_above (double z) const; + void in_ring (I iz, double phi0, double dphi, rangeset &pixset) const; + + template void query_multidisc (const arr &norm, + const arr &rad, int fact, rangeset &pixset) const; + + void query_multidisc_general (const arr &norm, const arr &rad, + bool inclusive, const std::vector &cmds, rangeset &pixset) const; + + void query_strip_internal (double theta1, double theta2, bool inclusive, + rangeset &pixset) const; + + inline I spread_bits (int v) const; + inline int compress_bits (I v) const; + + I xyf2nest(int ix, int iy, int face_num) const; + void nest2xyf(I pix, int &ix, int &iy, int &face_num) const; + I xyf2ring(int ix, int iy, int face_num) const; + void ring2xyf(I pix, int &ix, int &iy, int &face_num) const; + + I loc2pix (double z, double phi, double sth, bool have_sth) const; + void pix2loc (I pix, double &z, double &phi, double &sth, bool &have_sth) + const; + + void xyf2loc(double x, double y, int face, double &z, double &ph, + double &sth, bool &have_sth) const; + + I nest_peano_helper (I pix, int dir) const; + + typedef I (T_Healpix_Base::*swapfunc)(I pix) const; + + public: + static const int order_max; + + /*! Calculates the map order from its \a N_side parameter. + Returns -1 if \a nside is not a power of 2. + \param nside the \a N_side parameter */ + static int nside2order (I nside); + /*! Calculates the \a N_side parameter from the number of pixels. + \param npix the number of pixels */ + static I npix2nside (I npix); + /*! Constructs an unallocated object. */ + T_Healpix_Base (); + /*! Constructs an object with a given \a order and the ordering + scheme \a scheme. */ + T_Healpix_Base (int order, Healpix_Ordering_Scheme scheme) + { Set (order, scheme); } + /*! Constructs an object with a given \a nside and the ordering + scheme \a scheme. The \a nside_dummy parameter must be set to + SET_NSIDE. */ + T_Healpix_Base (I nside, Healpix_Ordering_Scheme scheme, const nside_dummy) + { SetNside (nside, scheme); } + + /*! Adjusts the object to \a order and \a scheme. */ + void Set (int order, Healpix_Ordering_Scheme scheme); + /*! Adjusts the object to \a nside and \a scheme. */ + void SetNside (I nside, Healpix_Ordering_Scheme scheme); + + /*! Returns the z-coordinate of the ring \a ring. This also works + for the (not really existing) rings 0 and 4*nside. */ + double ring2z (I ring) const; + /*! Returns the number of the ring in which \a pix lies. */ + I pix2ring (I pix) const; + + I xyf2pix(int ix, int iy, int face_num) const + { + return (scheme_==RING) ? + xyf2ring(ix,iy,face_num) : xyf2nest(ix,iy,face_num); + } + void pix2xyf(I pix, int &ix, int &iy, int &face_num) const + { + (scheme_==RING) ? + ring2xyf(pix,ix,iy,face_num) : nest2xyf(pix,ix,iy,face_num); + } + + /*! Translates a pixel number from NEST to RING. */ + I nest2ring (I pix) const; + /*! Translates a pixel number from RING to NEST. */ + I ring2nest (I pix) const; + /*! Translates a pixel number from NEST to its Peano index. */ + I nest2peano (I pix) const; + /*! Translates a pixel number from its Peano index to NEST. */ + I peano2nest (I pix) const; + + /*! Returns the number of the pixel which contains the angular coordinates + (\a z:=cos(theta), \a phi). + \note This method is inaccurate near the poles at high resolutions. */ + I zphi2pix (double z, double phi) const + { return loc2pix(z,phi,0.,false); } + + /*! Returns the number of the pixel which contains the angular coordinates + \a ang. */ + I ang2pix (const pointing &ang) const + { + const double pi_=3.141592653589793238462643383279502884197; + planck_assert((ang.theta>=0)&&(ang.theta<=pi_),"invalid theta value"); + return ((ang.theta<0.01) || (ang.theta > 3.14159-0.01)) ? + loc2pix(cos(ang.theta),ang.phi,sin(ang.theta),true) : + loc2pix(cos(ang.theta),ang.phi,0.,false); + } + /*! Returns the number of the pixel which contains the vector \a vec + (\a vec is normalized if necessary). */ + I vec2pix (const vec3 &vec) const + { + double xl = 1./vec.Length(); + double phi = safe_atan2(vec.y,vec.x); + double nz = vec.z*xl; + if (std::abs(nz)>0.99) + return loc2pix (nz,phi,sqrt(vec.x*vec.x+vec.y*vec.y)*xl,true); + else + return loc2pix (nz,phi,0,false); + } + + /*! Returns the angular coordinates (\a z:=cos(theta), \a phi) of the center + of the pixel with number \a pix. + \note This method is inaccurate near the poles at high resolutions. */ + void pix2zphi (I pix, double &z, double &phi) const + { + bool dum_b; + double dum_d; + pix2loc(pix,z,phi,dum_d,dum_b); + } + + /*! Returns the angular coordinates of the center of the pixel with + number \a pix. */ + pointing pix2ang (I pix) const + { + double z, phi, sth; + bool have_sth; + pix2loc (pix,z,phi,sth,have_sth); + return have_sth ? pointing(atan2(sth,z),phi) : pointing(acos(z),phi); + } + /*! Returns the vector to the center of the pixel with number \a pix. */ + vec3 pix2vec (I pix) const + { + double z, phi, sth; + bool have_sth; + pix2loc (pix,z,phi,sth,have_sth); + if (have_sth) + return vec3(sth*cos(phi),sth*sin(phi),z); + else + { + vec3 res; + res.set_z_phi (z, phi); + return res; + } + } + + template void query_disc_internal (pointing ptg, double radius, + int fact, rangeset &pixset) const; + + /*! Returns the range set of all pixels whose centers lie within the disk + defined by \a dir and \a radius. + \param dir the angular coordinates of the disk center + \param radius the radius (in radians) of the disk + \param pixset a \a rangeset object containing the indices of all pixels + whose centers lie inside the disk + \note This method is more efficient in the RING scheme. */ + void query_disc (pointing ptg, double radius, rangeset &pixset) const; + /*! Returns the range set of all pixels which overlap with the disk + defined by \a dir and \a radius. + \param dir the angular coordinates of the disk center + \param radius the radius (in radians) of the disk + \param pixset a \a rangeset object containing the indices of all pixels + overlapping with the disk. + \param fact The overlapping test will be done at the resolution + \a fact*nside. For NESTED ordering, \a fact must be a power of 2, + else it can be any positive integer. A typical choice would be 4. + \note This method may return some pixels which don't overlap with + the disk at all. The higher \a fact is chosen, the fewer false + positives are returned, at the cost of increased run time. + \note This method is more efficient in the RING scheme. */ + void query_disc_inclusive (pointing ptg, double radius, rangeset &pixset, + int fact=1) const; + + /*! \deprecated Please use the version based on \a rangeset */ + void query_disc (const pointing &dir, double radius, + std::vector &listpix) const + { + rangeset pixset; + query_disc(dir,radius,pixset); + pixset.toVector(listpix); + } + /*! \deprecated Please use the version based on \a rangeset */ + void query_disc_inclusive (const pointing &dir, double radius, + std::vector &listpix, int fact=1) const + { + rangeset pixset; + query_disc_inclusive(dir,radius,pixset,fact); + pixset.toVector(listpix); + } + + template void query_polygon_internal + (const std::vector &vertex, int fact, + rangeset &pixset) const; + + /*! Returns a range set of pixels whose centers lie within the convex + polygon defined by the \a vertex array. + \param vertex array containing the vertices of the polygon. + \param pixset a \a rangeset object containing the indices of all pixels + whose centers lie inside the polygon + \note This method is more efficient in the RING scheme. */ + void query_polygon (const std::vector &vertex, + rangeset &pixset) const; + + /*! Returns a range set of pixels which overlap with the convex + polygon defined by the \a vertex array. + \param vertex array containing the vertices of the polygon. + \param pixset a \a rangeset object containing the indices of all pixels + overlapping with the polygon. + \param fact The overlapping test will be done at the resolution + \a fact*nside. For NESTED ordering, \a fact must be a power of 2, + else it can be any positive integer. A typical choice would be 4. + \note This method may return some pixels which don't overlap with + the polygon at all. The higher \a fact is chosen, the fewer false + positives are returned, at the cost of increased run time. + \note This method is more efficient in the RING scheme. */ + void query_polygon_inclusive (const std::vector &vertex, + rangeset &pixset, int fact=1) const; + + /*! Returns a range set of pixels whose centers lie within the colatitude + range defined by \a theta1 and \a theta2 (if \a inclusive==false), or + which overlap with this region (if \a inclusive==true). If + \a theta1 &pixset) const; + + /*! Returns useful information about a given ring of the map. + \param ring the ring number (the number of the first ring is 1) + \param startpix the number of the first pixel in the ring + (NOTE: this is always given in the RING numbering scheme!) + \param ringpix the number of pixels in the ring + \param costheta the cosine of the colatitude of the ring + \param sintheta the sine of the colatitude of the ring + \param shifted if \a true, the center of the first pixel is not at + \a phi=0 */ + void get_ring_info (I ring, I &startpix, I &ringpix, + double &costheta, double &sintheta, bool &shifted) const; + /*! Returns useful information about a given ring of the map. + \param ring the ring number (the number of the first ring is 1) + \param startpix the number of the first pixel in the ring + (NOTE: this is always given in the RING numbering scheme!) + \param ringpix the number of pixels in the ring + \param theta the colatitude (in radians) of the ring + \param shifted if \a true, the center of the first pixel is not at + \a phi=0 */ + void get_ring_info2 (I ring, I &startpix, I &ringpix, + double &theta, bool &shifted) const; + /*! Returns useful information about a given ring of the map. + \param ring the ring number (the number of the first ring is 1) + \param startpix the number of the first pixel in the ring + (NOTE: this is always given in the RING numbering scheme!) + \param ringpix the number of pixels in the ring + \param shifted if \a true, the center of the first pixel is not at + \a phi=0 */ + void get_ring_info_small (I ring, I &startpix, I &ringpix, + bool &shifted) const; + /*! Returns the neighboring pixels of \a pix in \a result. + On exit, \a result contains (in this order) + the pixel numbers of the SW, W, NW, N, NE, E, SE and S neighbor + of \a pix. If a neighbor does not exist (this can only be the case + for the W, N, E and S neighbors), its entry is set to -1. + + \note This method works in both RING and NEST schemes, but is + considerably faster in the NEST scheme. */ + void neighbors (I pix, fix_arr &result) const; + /*! Returns interpolation information for the direction \a ptg. + The surrounding pixels are returned in \a pix, their corresponding + weights in \a wgt. + \note This method works in both RING and NEST schemes, but is + considerably faster in the RING scheme. */ + void get_interpol (const pointing &ptg, fix_arr &pix, + fix_arr &wgt) const; + + /*! Returns the order parameter of the object. */ + int Order() const { return order_; } + /*! Returns the \a N_side parameter of the object. */ + I Nside() const { return nside_; } + /*! Returns the number of pixels of the object. */ + I Npix() const { return npix_; } + /*! Returns the ordering scheme of the object. */ + Healpix_Ordering_Scheme Scheme() const { return scheme_; } + + /*! Returns \a true, if both objects have the same nside and scheme, + else \a false. */ + bool conformable (const T_Healpix_Base &other) const + { return ((nside_==other.nside_) && (scheme_==other.scheme_)); } + + /*! Swaps the contents of two Healpix_Base objects. */ + void swap (T_Healpix_Base &other); + + /*! Returns the maximum angular distance (in radian) between any pixel + center and its corners. */ + double max_pixrad() const; + + /*! Returns the maximum angular distance (in radian) between any pixel + center and its corners in a given ring. */ + double max_pixrad(I ring) const; + + /*! Returns a set of points along the boundary of the given pixel. + \a step=1 gives 4 points on the corners. The first point corresponds + to the northernmost corner, the subsequent points follow the pixel + boundary through west, south and east corners. + \param pix pixel index number + \param step the number of returned points is 4*step. */ + void boundaries (I pix, tsize step, std::vector &out) const; + + arr swap_cycles() const; + }; + +/*! T_Healpix_Base for Nside up to 2^13. */ +typedef T_Healpix_Base Healpix_Base; +/*! T_Healpix_Base for Nside up to 2^29. */ +typedef T_Healpix_Base Healpix_Base2; + +} // namespace healpix +#endif + diff --git a/libs/healpix_base/include/healpix_base/healpix_tables.h b/libs/healpix_base/include/healpix_base/healpix_tables.h new file mode 100644 index 000000000..90b4b1e9a --- /dev/null +++ b/libs/healpix_base/include/healpix_base/healpix_tables.h @@ -0,0 +1,67 @@ +/* + * This file is part of Healpix_cxx. + * + * Healpix_cxx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Healpix_cxx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Healpix_cxx; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * For more information about HEALPix, see http://healpix.sourceforge.net + */ + +/* + * Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik + * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt + * (DLR). + */ + +/*! \file healpix_tables.h + * Copyright (C) 2011 Max-Planck-Society + * \author Martin Reinecke + */ + +#ifndef HEALPIX_TABLES_H +#define HEALPIX_TABLES_H + +#include "healpix_base/datatypes.h" + +namespace healpix{ + +/*! The two possible ordering schemes of a HEALPix map. */ +enum Healpix_Ordering_Scheme { RING, /*!< RING scheme */ + NEST /*!< NESTED scheme */ + }; + +Healpix_Ordering_Scheme string2HealpixScheme (const std::string &inp); + +class nside_dummy {}; +extern const nside_dummy SET_NSIDE; + +class Healpix_Tables + { + protected: + static const uint16 ctab[], utab[]; + + static const int jrll[], jpll[]; + + static const uint8 peano_subpix[2][8][4], peano_subpath[2][8][4], + peano_face2path[2][12], peano_face2face[2][12]; + + static const int nb_xoffset[], nb_yoffset[], + nb_facearray[][12], nb_swaparray[][3]; + + static const int swap_clen[], swap_cycle[]; + }; + +} // namespace healpix +#endif + diff --git a/libs/healpix_base/include/healpix_base/lsconstants.h b/libs/healpix_base/include/healpix_base/lsconstants.h new file mode 100644 index 000000000..7e5315853 --- /dev/null +++ b/libs/healpix_base/include/healpix_base/lsconstants.h @@ -0,0 +1,97 @@ +/* + * This file is part of libcxxsupport. + * + * libcxxsupport is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * libcxxsupport is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libcxxsupport; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik + * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt + * (DLR). + */ + +/*! \file lsconstants.h + * Mathematical, physical and technical constants for LevelS. + */ + +#ifndef PLANCK_CONSTANTS_H +#define PLANCK_CONSTANTS_H + +namespace healpix{ + +/*! \defgroup mathconstgroup Mathematical constants */ +/*! \{ */ + +const double pi=3.141592653589793238462643383279502884197; +const double twopi=6.283185307179586476925286766559005768394; +const double inv_twopi=1.0/twopi; +const double fourpi=12.56637061435917295385057353311801153679; +const double halfpi=1.570796326794896619231321691639751442099; +const double inv_halfpi=0.6366197723675813430755350534900574; +const double inv_sqrt4pi = 0.2820947917738781434740397257803862929220; + +const double ln2 = 0.6931471805599453094172321214581766; +const double inv_ln2 = 1.4426950408889634073599246810018921; +const double ln10 = 2.3025850929940456840179914546843642; + +const double onethird=1.0/3.0; +const double twothird=2.0/3.0; +const double fourthird=4.0/3.0; + +const double degr2rad=pi/180.0; +const double arcmin2rad=degr2rad/60; +const double rad2degr=180.0/pi; + +//! Ratio between FWHM and sigma of a Gauss curve (\f$\sqrt{8\ln2}\f$). +const double sigma2fwhm=2.3548200450309493; // sqrt(8*log(2.)) +const double fwhm2sigma=1/sigma2fwhm; + +/*! \} */ + +/*! \defgroup physconstgroup Physical constants */ +/*! \{ */ + +const double Jansky2SI=1.0e-26; +const double SI2Jansky=1.0e+26; + +//! Light speed in m/s (CODATA 2006) +const double speedOfLight=2.99792458e8; + +//! Boltzmann's constant in J/K (CODATA 2006) +const double kBoltzmann=1.3806504e-23; + +//! Stefan-Boltzmann constant in W/m^2/K^4 (CODATA 2006) +const double sigmaStefanBoltzmann=5.6704e-8; + +//! Planck's constant in J s (CODATA 2006) +const double hPlanck=6.62606896e-34; + +//! Astronomical unit in m +const double astronomicalUnit=1.49597870691e11; + +//! Solar constant in W/m^2 +const double solarConstant=1368.0; + +//! Average CMB temperature in K (Mather et al. 1999, ApJ 512, 511) +const double tcmb = 2.725; + +//! offset (in seconds) between Jan 1, 1958 and Jan 1, 1970 +const double sec_58_70 = 378691200.; + +/*! \} */ + +} // namespace healpix +#endif + diff --git a/libs/healpix_base/include/healpix_base/math_utils.h b/libs/healpix_base/include/healpix_base/math_utils.h new file mode 100644 index 000000000..4a6f914db --- /dev/null +++ b/libs/healpix_base/include/healpix_base/math_utils.h @@ -0,0 +1,183 @@ +/* + * This file is part of libcxxsupport. + * + * libcxxsupport is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * libcxxsupport is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libcxxsupport; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik + * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt + * (DLR). + */ + +/*! \file math_utils.h + * Various convenience mathematical functions. + * + * Copyright (C) 2002-2012 Max-Planck-Society + * \author Martin Reinecke + */ + +#ifndef PLANCK_MATH_UTILS_H +#define PLANCK_MATH_UTILS_H + +#include +#include +#include "healpix_base/datatypes.h" + +namespace healpix{ + +/*! \defgroup mathutilsgroup Mathematical helper functions */ +/*! \{ */ + +/*! Returns \e true if | \a a-b | <= \a epsilon * | \a b |, else \e false. */ +template inline bool approx (F a, F b, F epsilon=1e-5) + { + using namespace std; + return abs(a-b) <= (epsilon*abs(b)); + } + +/*! Returns \e true if | \a a-b | <= \a epsilon, else \e false. */ +template inline bool abs_approx (F a, F b, F epsilon=1e-5) + { + using namespace std; + return abs(a-b) <= epsilon; + } + +/*! Returns the largest integer which is smaller than (or equal to) \a arg. */ +template inline I ifloor (F arg) + { + using namespace std; + return I(floor(arg)); + } + +/*! Returns the integer which is nearest to \a arg. */ +template inline I nearest (F arg) + { return ifloor(arg+0.5); } + +/*! Returns the remainder of the division \a v1/v2. + The result is non-negative. + \a v1 can be positive or negative; \a v2 must be positive. */ +inline double fmodulo (double v1, double v2) + { + using namespace std; + if (v1>=0) + return (v1=0) ? ((v1 inline I imodulo (I v1, I v2) + { I v=v1%v2; return (v>=0) ? v : v+v2; } + +/*! Returns -1 if \a signvalue is negative, else +1. */ +template inline T sign (const T& signvalue) + { return (signvalue>=0) ? 1 : -1; } + +/*! Returns \a val*pow(-1,m) */ +template inline T xpow (I m, T val) + { return (m&1) ? -val : val; } + +template struct isqrt_helper__ + {}; +template struct isqrt_helper__ + { + static uint32 isqrt (I arg) + { + using namespace std; + return uint32 (sqrt(arg+0.5)); + } + }; +template struct isqrt_helper__ + { + static uint32 isqrt (I arg) + { + using namespace std; + I res = sqrt(double(arg)+0.5); + if (arg<(int64(1)<<50)) return uint32(res); + if (res*res>arg) + --res; + else if ((res+1)*(res+1)<=arg) + ++res; + return uint32(res); + } + }; + +/*! Returns the integer \a n, which fulfills \a n*n<=arg<(n+1)*(n+1). */ +template inline uint32 isqrt (I arg) + { return isqrt_helper__4)>::isqrt(arg); } + +/*! Returns the largest integer \a n that fulfills \a 2^n<=arg. */ +template inline int ilog2 (I arg) + { + int res=0; + while (arg > 0x0000FFFF) { res+=16; arg>>=16; } + if (arg > 0x000000FF) { res|=8; arg>>=8; } + if (arg > 0x0000000F) { res|=4; arg>>=4; } + if (arg > 0x00000003) { res|=2; arg>>=2; } + if (arg > 0x00000001) { res|=1; } + return res; + } + +/*! Returns \a atan2(y,x) if \a x!=0 or \a y!=0; else returns 0. */ +inline double safe_atan2 (double y, double x) + { + using namespace std; + return ((x==0.) && (y==0.)) ? 0.0 : atan2(y,x); + } + +/*! Helper function for linear interpolation (or extrapolation). + The array must be ordered in ascending order; no two values may be equal. */ +template inline void interpol_helper + (const Iter &begin, const Iter &end, const T &val, Comp comp, tsize &idx, + T &frac) + { + using namespace std; + planck_assert((end-begin)>1,"sequence too small for interpolation"); + idx = lower_bound(begin,end,val,comp)-begin; + if (idx>0) --idx; + idx = min(tsize(end-begin-2),idx); + frac = (val-begin[idx])/(begin[idx+1]-begin[idx]); + } + +/*! Helper function for linear interpolation (or extrapolation). + The array must be ordered in ascending order; no two values may be equal. */ +template inline void interpol_helper + (const Iter &begin, const Iter &end, const T &val, tsize &idx, T &frac) + { interpol_helper (begin,end,val,std::less(),idx,frac); } + +/*! \} */ + +template inline bool multiequal (const T &a, const T &b, const T &c) + { return (a==b) && (a==c); } + +template inline bool multiequal (const T &a, const T &b, const T &c, + const T &d) + { return (a==b) && (a==c) && (a==d); } + +template inline bool multiequal (const T &a, const T &b, const T &c, + const T &d, const T &e) + { return (a==b) && (a==c) && (a==d) && (a==e); } + +template inline bool multiequal (const T &a, const T &b, const T &c, + const T &d, const T &e, const T &f) + { return (a==b) && (a==c) && (a==d) && (a==e) && (a==f); } + +} // namespace healpix +#endif + diff --git a/libs/healpix_base/include/healpix_base/pointing.h b/libs/healpix_base/include/healpix_base/pointing.h new file mode 100644 index 000000000..a804f66fb --- /dev/null +++ b/libs/healpix_base/include/healpix_base/pointing.h @@ -0,0 +1,85 @@ +/* + * This file is part of libcxxsupport. + * + * libcxxsupport is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * libcxxsupport is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libcxxsupport; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik + * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt + * (DLR). + */ + +/*! \file pointing.h + * Class representing a direction in 3D space + * + * Copyright (C) 2003-2012 Max-Planck-Society + * \author Martin Reinecke + */ + +#ifndef PLANCK_POINTING_H +#define PLANCK_POINTING_H + +#include +#include "healpix_base/vec3.h" + +namespace healpix{ + +/*! \defgroup pointinggroup Pointings */ +/*! \{ */ + +/*! Class representing a direction in 3D space or a location on the + unit sphere. All angles in radians. */ +class pointing + { + public: + /*! Colatitude of the pointing (i.e. the North pole is at \a theta=0). */ + double theta; + /*! Longitude of the pointing. */ + double phi; + + /*! Default constructor. \a theta and \a phi are not initialized. */ + pointing() {} + /*! Creates a pointing with \a Theta and \a Phi. */ + pointing (double Theta, double Phi) : theta(Theta), phi(Phi) {} + +// FIXME: should become "explicit" some time + /*! Creates a pointing from the vector \a inp. \a inp need not be + normalized. */ + pointing (const vec3 &inp) + { from_vec3(inp); } +// FIXME: should be removed some time + /*! Returns a normalized vector pointing in the same direction. */ + operator vec3() const + { return to_vec3(); } + /*! Returns a normalized vector pointing in the same direction. */ + vec3 to_vec3() const; + /*! Converts \a inp to \a ptg. \a inp need not be normalized. */ + void from_vec3 (const vec3 &inp); + /*! Changes the angles so that \a 0<=theta<=pi. */ + void normalize_theta(); + /*! Changes the angles so that \a 0<=theta<=pi and \a 0<=phi<2*pi. */ + void normalize(); + }; + +/*! Writes \a p to \a os. + \relates pointing */ +std::ostream &operator<< (std::ostream &os, const pointing &p); + +/*! \} */ + +} // namespace healpix +#endif + diff --git a/libs/healpix_base/include/healpix_base/rangeset.h b/libs/healpix_base/include/healpix_base/rangeset.h new file mode 100644 index 000000000..a816af3e4 --- /dev/null +++ b/libs/healpix_base/include/healpix_base/rangeset.h @@ -0,0 +1,287 @@ +/* + * This file is part of libcxxsupport. + * + * libcxxsupport is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * libcxxsupport is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libcxxsupport; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik + * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt + * (DLR). + */ + +/*! \file rangeset.h + * Class for storing sets of ranges of integer numbers + * + * Copyright (C) 2011, 2012 Max-Planck-Society + * \author Martin Reinecke + */ + +#ifndef PLANCK_RANGESET_H +#define PLANCK_RANGESET_H + +#include +#include +#include +#include +#include "healpix_base/datatypes.h" +#include "healpix_base/error_handling.h" + +namespace healpix{ + +/*! Class for storing sets of ranges of integer numbers */ +template class rangeset + { + private: + typedef std::vector rtype; + typedef typename rtype::iterator iterator; + typedef typename rtype::const_iterator c_iterator; + rtype r; + + tdiff iiv (const T &val) const + { return tdiff(std::upper_bound(r.begin(),r.end(),val)-r.begin())-1; } + + void addRemove (T a, T b, tdiff v) + { + tdiff pos1=iiv(a), pos2=iiv(b); + if ((pos1>=0) && (r[pos1]==a)) --pos1; + // first to delete is at pos1+1; last is at pos2 + bool insert_a = (pos1&1)==v; + bool insert_b = (pos2&1)==v; + int rmstart=pos1+1+(insert_a ? 1 : 0); + int rmend =pos2-(insert_b?1:0); + + planck_assert((rmend-rmstart)&1,"cannot happen"); + + if (insert_a && insert_b && (pos1+1>pos2)) // insert + { + r.insert(r.begin()+pos1+1,2,a); + r[pos1+2]=b; + } + else + { + if (insert_a) r[pos1+1]=a; + if (insert_b) r[pos2]=b; + r.erase(r.begin()+rmstart,r.begin()+rmend+1); + } + } + + static void generalUnion (const rtype &a, const rtype &b, + bool flip_a, bool flip_b, rtype &c) + { + planck_assert((&c!=&a)&&(&c!=&b), "cannot overwrite the rangeset"); + c.clear(); + bool state_a=flip_a, state_b=flip_b, state_res=state_a||state_b; + tsize ia=0, ea=a.size(), ib=0, eb=b.size(); + bool runa = ia!=ea, runb = ib!=eb; + while(runa||runb) + { + bool adv_a=false, adv_b=false; + T val,va=T(),vb=T(); + if (runa) va = a[ia]; + if (runb) vb = b[ib]; + if (runa && (!runb || (va<=vb))) { adv_a=true; val=va; } + if (runb && (!runa || (vb<=va))) { adv_b=true; val=vb; } + if (adv_a) { state_a=!state_a; ++ia; runa = ia!=ea; } + if (adv_b) { state_b=!state_b; ++ib; runb = ib!=eb; } + if ((state_a||state_b)!=state_res) + { c.push_back(val); state_res = !state_res; } + } + } + + public: + /*! Removes all rangeset entries. */ + void clear() { r.clear(); } + /*! Reserves space for \a n ranges. */ + void reserve(tsize n) { r.reserve(2*n); } + /*! Returns the current number of ranges. */ + tsize size() const { return r.size()>>1; } + /*! Returns the current vector of ranges. */ + const rtype &data() const { return r; } + + /*! Returns the first value of range \a i. */ + const T &ivbegin (tdiff i) const { return r[2*i]; } + /*! Returns the one-past-last value of range \a i. */ + const T &ivend (tdiff i) const { return r[2*i+1]; } + /*! Returns the length of range \a i. */ + T ivlen (tdiff i) const { return r[2*i+1]-r[2*i]; } + + /*! Appends \a [v1;v2[ to the rangeset. \a v1 must be larger + than the minimum of the last range in the rangeset. */ + void append(const T &v1, const T &v2) + { + if (v2<=v1) return; + if ((!r.empty()) && (v1<=r.back())) + { + planck_assert (v1>=r[r.size()-2],"bad append operation"); + if (v2>r.back()) r.back()=v2; + } + else + { r.push_back(v1); r.push_back(v2); } + } + /*! Appends \a [v;v+1[ to the rangeset. \a v must be larger + than the minimum of the last range in the rangeset. */ + void append(const T &v) + { append(v,v+1); } + + /*! Appends \a other to the rangeset. All values in \a other must be larger + than the minimum of the last range in the rangeset. */ + void append (const rangeset &other) + { + for (tsize j=0; j=0) && (r[pos2]==b)) --pos2; + // delete all up to pos1 (inclusive); and starting from pos2+1 + bool insert_a = (pos1&1)==0; + bool insert_b = (pos2&1)==0; + + // cut off end + r.erase(r.begin()+pos2+1,r.end()); + if (insert_b) r.push_back(b); + + // erase start + if (insert_a) r[pos1--]=a; + if (pos1>=0) + r.erase(r.begin(),r.begin()+pos1+1); + } + + /*! Returns the total number of elements in the rangeset. */ + T nval() const + { + T result=T(0); + for (tsize i=0; i &res) const + { + res.clear(); + res.reserve(nval()); + for (tsize i=0; i>1; + } + + /*! Returns \a true if the rangeset is identical to \a other, else \a false. + */ + bool equals (const rangeset &other) const + { return r==other.data(); } + + /*! Returns \a true if the rangeset contains all values in the range + \a [a;b[, else \a false. */ + bool containsAll (T a,T b) const + { + tdiff res=iiv(a); + if (res&1) return false; + return (b<=r[res+1]); + } + /*! Returns \a true if the rangeset contains the value \a v, + else \a false. */ + bool contains (T v) const + { return !(iiv(v)&1); } + /*! Returns \a true if the rangeset contains all values stored in \a other, + else \a false. */ + bool contains (const rangeset &other) const + { + tsize im=0, em=r.size(); + for (tsize i=0; ia) || (r[im+1] inline std::ostream &operator<< (std::ostream &os, + const rangeset &rs) + { + os << "{ "; + for (tsize i=0; i +#include +#include "healpix_base/datatypes.h" + +namespace healpix{ + +/*! \defgroup vec3group 3D vectors */ +/*! \{ */ + +/*! Class representing a 3D cartesian vector. */ +templateclass vec3_t + { + public: + T x, /*!< x-coordinate */ + y, /*!< y-coordinate */ + z; /*!< z-coordinate */ + + /*! Default constructor. Does not initialize \a x, \a y, and \a z. */ + vec3_t () {} + /*! Creates a vector with the coordinates \a xc, \a yc, and \a zc. */ + vec3_t (T xc, T yc, T zc) + : x(xc), y(yc), z(zc) {} + template explicit vec3_t (const vec3_t &orig) + : x(orig.x), y(orig.y), z(orig.z) {} + + /*! Sets the vector components to \a xc, \a yc, and \a zc. */ + void Set (T xc, T yc, T zc) + { x=xc; y=yc; z=zc; } + /*! Creates a unit vector from a z coordinate and an azimuthal angle. */ + void set_z_phi (T z_, T phi) + { + using namespace std; + T sintheta = sqrt((T(1)-z_)*(T(1)+z_)); + x = sintheta*cos(phi); + y = sintheta*sin(phi); + z = z_; + } + + /*! Normalizes the vector to length 1. */ + void Normalize () + { + using namespace std; + T l = T(1)/sqrt (x*x + y*y + z*z); + x*=l; y*=l; z*=l; + } + + vec3_t Norm() const + { + vec3_t res(*this); + res.Normalize(); + return res; + } + + /*! Returns the length of the vector. */ + T Length () const + { return sqrt (x*x + y*y + z*z); } + + /*! Returns the squared length of the vector. */ + T SquaredLength () const + { return (x*x + y*y + z*z); } + /*! Returns the vector with the signs of all coordinates flipped. */ + const vec3_t operator- () const + { return vec3_t (-x, -y, -z); } + /*! Flips the signs of all coordinates. */ + void Flip () + { x=-x; y=-y; z=-z; } + /*! Returns (\a *this + \a vec). */ + const vec3_t operator+ (const vec3_t &vec) const + { return vec3_t (x+vec.x, y+vec.y, z+vec.z); } + /*! Adds \a vec to \a *this. */ + vec3_t &operator+= (const vec3_t &vec) + { x+=vec.x; y+=vec.y; z+=vec.z; return *this; } + /*! Returns (\a *this - \a vec). */ + const vec3_t operator- (const vec3_t &vec) const + { return vec3_t (x-vec.x, y-vec.y, z-vec.z); } + /*! Subtracts \a vec from \a *this. */ + vec3_t &operator-= (const vec3_t &vec) + { x-=vec.x; y-=vec.y; z-=vec.z; return *this; } + /*! Returns the vector scaled by \a fact. */ + const vec3_t operator* (T fact) const + { return vec3_t (x*fact, y*fact, z*fact); } + /*! Returns the vector scaled by \a 1/fact. */ + const vec3_t operator/ (T fact) const + { T xfact = T(1)/fact; return vec3_t (x*xfact, y*xfact, z*xfact); } + /*! Scales the vector by \a fact. */ + vec3_t &operator*= (T fact) + { x*=fact; y*=fact; z*=fact; return *this; } + }; + +/*! Returns the dot product of \a v1 and \a v2. + \relates vec3_t */ +template inline T dotprod(const vec3_t &v1, const vec3_t &v2) + { return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; } + +/*! Returns the cross product of \a a and \a b. + \relates vec3_t */ +template inline vec3_t crossprod + (const vec3_t &a, const vec3_t &b) + { return vec3_t(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x); } + +/*! Writes \a v to \a os. + \relates vec3_t */ +template inline std::ostream &operator<< + (std::ostream &os, const vec3_t &v) + { + os << v.x << ", " << v.y << ", " << v.z << std::endl; + return os; + } + +/*! Specialisation of vec3_t for 64-bit floating point components */ +typedef vec3_t vec3; +/*! Specialisation of vec3_t for 32-bit floating point components */ +typedef vec3_t vec3f; + +/*! \} */ + +} // namespace healpix +#endif + diff --git a/libs/healpix_base/pointing.cc b/libs/healpix_base/pointing.cc new file mode 100644 index 000000000..d5cc7ade3 --- /dev/null +++ b/libs/healpix_base/pointing.cc @@ -0,0 +1,72 @@ +/* + * This file is part of libcxxsupport. + * + * libcxxsupport is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * libcxxsupport is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libcxxsupport; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik + * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt + * (DLR). + */ + +/*! \file pointing.cc + * Class representing a direction in 3D space + * + * Copyright (C) 2003-2012 Max-Planck-Society + * \author Martin Reinecke + */ + +#include "healpix_base/pointing.h" +#include "healpix_base/lsconstants.h" +#include "healpix_base/math_utils.h" + +namespace healpix{ + +using namespace std; + +vec3 pointing::to_vec3() const + { + double st=sin(theta); + return vec3 (st*cos(phi), st*sin(phi), cos(theta)); + } +void pointing::from_vec3 (const vec3 &inp) + { + theta = atan2(sqrt(inp.x*inp.x+inp.y*inp.y),inp.z); + phi = safe_atan2 (inp.y,inp.x); + if (phi<0.) phi += twopi; + } +void pointing::normalize_theta() + { + theta=fmodulo(theta,twopi); + if (theta>pi) + { + phi+=pi; + theta=twopi-theta; + } + } +void pointing::normalize() + { + normalize_theta(); + phi=fmodulo(phi,twopi); + } + +ostream &operator<< (ostream &os, const pointing &p) + { + os << p.theta << ", " << p.phi << std::endl; + return os; + } +} // namespace healpix + diff --git a/src/magneticLens/Pixelization.cpp b/src/magneticLens/Pixelization.cpp index be8b020e7..da7729c56 100644 --- a/src/magneticLens/Pixelization.cpp +++ b/src/magneticLens/Pixelization.cpp @@ -49,22 +49,22 @@ uint32_t Pixelization::nPix(uint8_t order) uint32_t Pixelization::direction2Pix(double longitude, double latitude) const { - shealpix::vec3 v; + healpix::vec3 v; spherCo2Vec(longitude, latitude, v); - uint32_t i = (uint32_t) vec2pix(v); + uint32_t i = (uint32_t) _healpix->vec2pix(v); return i; } void Pixelization::pix2Direction(uint32_t i, double &longitude, double &latitude) const { - shealpix::vec3 v; - v = pix2vec(i); + healpix::vec3 v; + v = _healpix->pix2vec(i); vec2SphereCo(longitude, latitude, v); } void Pixelization::spherCo2Vec(double phi, double theta, - shealpix::vec3 &V) const + healpix::vec3 &V) const { V.x = cos(phi) * cos(theta); V.y = sin(phi) * cos(theta); @@ -72,18 +72,18 @@ void Pixelization::spherCo2Vec(double phi, double theta, } void Pixelization::vec2SphereCo(double &phi, double &theta, - const shealpix::vec3 &V) const + const healpix::vec3 &V) const { theta = asin(V.z); - phi = safe_atan2(V.y, V.x); + phi = healpix::safe_atan2(V.y, V.x); } double Pixelization::angularDistance(uint32_t i, uint32_t j) const { - shealpix::vec3 v1, v2; - v1 = pix2vec(i); - v2 = pix2vec(j); + healpix::vec3 v1, v2; + v1 = _healpix->pix2vec(i); + v2 = _healpix->pix2vec(j); double s = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; // Failsafe for numerical inaccuracies return ((s > 1) ? 0 : ((s < -1) ? M_PI : acos(s))); From 200ecec8260887df0ad1cdcadfa60dbe170d972d Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 24 Oct 2014 12:28:11 +0200 Subject: [PATCH 0532/1298] Added random direction in pixel --- include/crpropa/magneticLens/Pixelization.h | 6 +++++- src/magneticLens/ParticleMapsContainer.cpp | 2 +- src/magneticLens/Pixelization.cpp | 17 +++++++++++++++++ test/testMagneticLens.cpp | 21 +++++++++++++++++++++ 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/include/crpropa/magneticLens/Pixelization.h b/include/crpropa/magneticLens/Pixelization.h index 86f3bc32a..83928f26f 100644 --- a/include/crpropa/magneticLens/Pixelization.h +++ b/include/crpropa/magneticLens/Pixelization.h @@ -55,8 +55,9 @@ const uint32_t _nPix[] = class Pixelization { public: - Pixelization() + Pixelization() { + _healpix = new healpix::T_Healpix_Base(6, healpix::RING); } /// Constructor creating Pixelization with healpix order 6 (about @@ -112,11 +113,14 @@ class Pixelization return _healpix->Order(); } + void getRandomDirectionInPixel(uint32_t i, double &longitude, double &latitude); + private: void spherCo2Vec(double phi, double theta, healpix::vec3 &V) const; void vec2SphereCo(double &phi , double &theta, const healpix::vec3 &V) const; healpix::T_Healpix_Base *_healpix; + static healpix::T_Healpix_Base _healpix_nest; }; diff --git a/src/magneticLens/ParticleMapsContainer.cpp b/src/magneticLens/ParticleMapsContainer.cpp index 210e8bc6c..5ea2037d7 100644 --- a/src/magneticLens/ParticleMapsContainer.cpp +++ b/src/magneticLens/ParticleMapsContainer.cpp @@ -211,7 +211,7 @@ void ParticleMapsContainer::getRandomParticles(size_t N, vector &particleId { foundParticle = true; energy[i] = idx2Energy(energy_iter->first) / eV; - _pixelization.pix2Direction (j, galacticLongitudes[i], galacticLatitudes[i]); + _pixelization.getRandomDirectionInPixel(j, galacticLongitudes[i], galacticLatitudes[i] ); } } } diff --git a/src/magneticLens/Pixelization.cpp b/src/magneticLens/Pixelization.cpp index da7729c56..9d3c78a2d 100644 --- a/src/magneticLens/Pixelization.cpp +++ b/src/magneticLens/Pixelization.cpp @@ -21,10 +21,14 @@ //---------------------------------------------------------------------- #include "crpropa/magneticLens/Pixelization.h" +#include "crpropa/Random.h" namespace crpropa { + healpix::T_Healpix_Base Pixelization::_healpix_nest = healpix::T_Healpix_Base(29, healpix::NEST); + + uint8_t Pixelization::pix2Order(uint32_t pix) { for (uint8_t i = 0; i < _nOrder_max; i++) @@ -89,4 +93,17 @@ double Pixelization::angularDistance(uint32_t i, uint32_t j) const return ((s > 1) ? 0 : ((s < -1) ? M_PI : acos(s))); } + void Pixelization::getRandomDirectionInPixel(uint32_t i, double &longitude, double &latitude) + { + + int64_t inest = _healpix->ring2nest(i); + + int64_t nUp = 29 - _healpix->Order(); + int64_t iUp = inest * pow(4, nUp); + iUp += Random::instance().randInt(pow(4, nUp)); + + healpix::vec3 v = _healpix_nest.pix2vec(iUp); + + vec2SphereCo(longitude, latitude, v); + } } // namespace diff --git a/test/testMagneticLens.cpp b/test/testMagneticLens.cpp index e3db4f1fc..02136c857 100644 --- a/test/testMagneticLens.cpp +++ b/test/testMagneticLens.cpp @@ -145,3 +145,24 @@ TEST(ParticleMapsContainer, getRandomParticles) } } + +TEST(Pixelization, randomDirectionInPixel) +{ + Pixelization p(6); + const double long0 = -35./180 * M_PI; + const double lat0 = 12.08/180 * M_PI; + + int pix = p.direction2Pix(long0, lat0); + + double rlon, rlat; + p.getRandomDirectionInPixel(pix, rlon, rlat); + std::cout << rlon << "\t" << rlat << std::endl; + + // new direction should be inside the pixel + EXPECT_EQ(pix, p.direction2Pix(rlon, rlat)); + + // new direction should be different from input + EXPECT_FALSE(long0 == rlon); + EXPECT_FALSE(lat0 == rlat); + +} From a063d85ebf51a18c4f87a4cc2006cbcf9f2ae236 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 24 Oct 2014 12:32:52 +0200 Subject: [PATCH 0533/1298] Fixed typos in CMakeLists --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 88a9de1d6..aeb0131ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,7 +74,7 @@ if (ENABLE_GALACTICMAGETICLENS) # healpix redux (provided) add_subdirectory(libs/healpix_base) list(APPEND CRPROPA_EXTRA_LIBRARIES healpix_base) - list(APPEND CRPROPA_EXTRA_INCLUDES libs/healpix_base//include) + list(APPEND CRPROPA_EXTRA_INCLUDES libs/healpix_base/include) FIND_PACKAGE(Boost) IF(Boost_FOUND) @@ -84,8 +84,8 @@ if (ENABLE_GALACTICMAGETICLENS) list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/MagneticLens.cpp) list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/ModelMatrix.cpp) - list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/Pixelization.cpp) - list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/ParticleMapsContainer.cpp) + list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/Pixelization.cpp) + list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/ParticleMapsContainer.cpp) list(APPEND CRPROPA_EXTRA_INCLUDES ${Boost_INCLUDE_DIRS}) From 19696af4afb911b5bfac2f3742bfc110eb88a88e Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 24 Oct 2014 17:17:50 +0200 Subject: [PATCH 0534/1298] Add beginRun / endRun method module and ObserverFeature Use endRun in output modules to flush --- include/crpropa/Module.h | 2 + include/crpropa/ModuleList.h | 19 ++-- include/crpropa/module/Observer.h | 7 +- include/crpropa/module/OutputCRPropa2.h | 4 + include/crpropa/module/OutputTXT.h | 4 + src/Module.cpp | 6 ++ src/ModuleList.cpp | 37 +++++-- src/module/Observer.cpp | 128 ++++++++++++++---------- src/module/OutputCRPropa2.cpp | 36 ++++--- src/module/OutputTXT.cpp | 101 ++++++++++--------- 10 files changed, 211 insertions(+), 133 deletions(-) diff --git a/include/crpropa/Module.h b/include/crpropa/Module.h index 9a1abad73..e50b1a574 100644 --- a/include/crpropa/Module.h +++ b/include/crpropa/Module.h @@ -23,6 +23,8 @@ class Module: public Referenced { } virtual std::string getDescription() const; void setDescription(const std::string &description); + virtual void beginRun(); + virtual void endRun(); virtual void process(Candidate *candidate) const = 0; inline void process(ref_ptr candidate) const { process(candidate.get()); diff --git a/include/crpropa/ModuleList.h b/include/crpropa/ModuleList.h index 21b82a910..0d6d5d8be 100644 --- a/include/crpropa/ModuleList.h +++ b/include/crpropa/ModuleList.h @@ -12,7 +12,7 @@ namespace crpropa { /** @class ModuleList - @brief List of modules + @brief The simulation itself: A list of simulation modules */ class ModuleList: public Referenced { public: @@ -21,17 +21,24 @@ class ModuleList: public Referenced { ModuleList(); virtual ~ModuleList(); - void setShowProgress(bool show); + void setShowProgress(bool show = true); ///< activate a progress bar void add(Module* module); - virtual void process(Candidate *candidate); + module_list_t &getModules(); + const module_list_t &getModules() const; + + /** + @class + @brief The simulation itself: A list of simulation modules + */ + void beginRun(); ///< call beginRun in all modules + void endRun(); ///< call endRun in all modules + void process(Candidate *candidate); ///< call process in all modules + void run(Candidate *candidate, bool recursive = true); void run(candidate_vector_t &candidates, bool recursive = true); void run(Source *source, size_t count, bool recursive = true); - module_list_t &getModules(); - const module_list_t &getModules() const; - std::string getDescription() const; void showModules() const; diff --git a/include/crpropa/module/Observer.h b/include/crpropa/module/Observer.h index 1202a07ac..c609aaa28 100644 --- a/include/crpropa/module/Observer.h +++ b/include/crpropa/module/Observer.h @@ -28,6 +28,8 @@ class ObserverFeature: public Referenced { virtual DetectionState checkDetection(Candidate *candidate) const; virtual void onDetection(Candidate *candidate) const; virtual std::string getDescription() const; + virtual void beginRun(); + virtual void endRun(); }; /** @@ -41,6 +43,8 @@ class Observer: public Module { public: Observer(bool makeInactive = true); void add(ObserverFeature *property); + void beginRun(); + void endRun(); void process(Candidate *candidate) const; std::string getDescription() const; }; @@ -140,6 +144,7 @@ class ObserverOutput3D: public ObserverFeature { ObserverOutput3D(std::string filename, bool legacy = false); ~ObserverOutput3D(); void onDetection(Candidate *candidate) const; + void endRun(); }; /** @@ -154,6 +159,7 @@ class ObserverOutput1D: public ObserverFeature { ObserverOutput1D(std::string filename, bool legacy = false); ~ObserverOutput1D(); void onDetection(Candidate *candidate) const; + void endRun(); }; //////////////////////////////////////////////////////////////////////////////// @@ -196,7 +202,6 @@ class LargeObserverSphere: public Module { std::string flag; std::string flagValue; bool makeInactive; - void updateDescription(); public: LargeObserverSphere(Vector3d center = Vector3d(0.), double radius = 0, diff --git a/include/crpropa/module/OutputCRPropa2.h b/include/crpropa/module/OutputCRPropa2.h index 10a23eb79..499cfe39a 100644 --- a/include/crpropa/module/OutputCRPropa2.h +++ b/include/crpropa/module/OutputCRPropa2.h @@ -16,6 +16,7 @@ class CRPropa2EventOutput3D: public Module { CRPropa2EventOutput3D(std::string filename); ~CRPropa2EventOutput3D(); void process(Candidate *candidate) const; + void endRun(); }; /** @@ -28,6 +29,7 @@ class CRPropa2TrajectoryOutput3D: public Module { CRPropa2TrajectoryOutput3D(std::string filename); ~CRPropa2TrajectoryOutput3D(); void process(Candidate *candidate) const; + void endRun(); }; /** @@ -40,6 +42,7 @@ class CRPropa2EventOutput1D: public Module { CRPropa2EventOutput1D(std::string filename); ~CRPropa2EventOutput1D(); void process(Candidate *candidate) const; + void endRun(); }; /** @@ -52,6 +55,7 @@ class CRPropa2TrajectoryOutput1D: public Module { CRPropa2TrajectoryOutput1D(std::string filename); ~CRPropa2TrajectoryOutput1D(); void process(Candidate *candidate) const; + void endRun(); }; } // namespace crpropa diff --git a/include/crpropa/module/OutputTXT.h b/include/crpropa/module/OutputTXT.h index f094205bf..cf1f2d724 100644 --- a/include/crpropa/module/OutputTXT.h +++ b/include/crpropa/module/OutputTXT.h @@ -18,6 +18,7 @@ class TrajectoryOutput: public Module { TrajectoryOutput(std::string filename); ~TrajectoryOutput(); void process(Candidate *candidate) const; + void endRun(); }; /** @@ -31,6 +32,7 @@ class ConditionalOutput: public Module { ConditionalOutput(std::string filename, std::string condition = "Detected"); ~ConditionalOutput(); void process(Candidate *candidate) const; + void endRun(); }; /** @@ -43,6 +45,7 @@ class TrajectoryOutput1D: public Module { TrajectoryOutput1D(std::string filename); ~TrajectoryOutput1D(); void process(Candidate *candidate) const; + void endRun(); }; /** @@ -55,6 +58,7 @@ class EventOutput1D: public Module { EventOutput1D(std::string filename); ~EventOutput1D(); void process(Candidate *candidate) const; + void endRun(); }; } // namespace crpropa diff --git a/src/Module.cpp b/src/Module.cpp index bd87d264f..37b5fe38e 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -17,4 +17,10 @@ void Module::setDescription(const std::string &d) { description = d; } +void Module::beginRun() { +} + +void Module::endRun() { +} + } // namespace crpropa diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 2db8a37a2..57295ab20 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -35,13 +35,22 @@ void ModuleList::add(Module *module) { modules.push_back(module); } +void ModuleList::beginRun() { + module_list_t::iterator m; + for (m = modules.begin(); m != modules.end(); m++) + (*m)->beginRun(); +} + void ModuleList::process(Candidate *candidate) { - module_list_t::iterator iEntry = modules.begin(); - while (iEntry != modules.end()) { - ref_ptr &module = *iEntry; - iEntry++; - module->process(candidate); - } + module_list_t::iterator m; + for (m = modules.begin(); m != modules.end(); m++) + (*m)->process(candidate); +} + +void ModuleList::endRun() { + module_list_t::iterator m; + for (m = modules.begin(); m != modules.end(); m++) + (*m)->endRun(); } void ModuleList::run(Candidate *candidate, bool recursive) { @@ -75,6 +84,8 @@ void ModuleList::run(candidate_vector_t &candidates, bool recursive) { sighandler_t old_signal_handler = ::signal(SIGINT, g_cancel_signal_callback); + beginRun(); // call beginRun in all modules + #pragma omp parallel for schedule(static, 1000) for (size_t i = 0; i < count; i++) { if (g_cancel_signal_flag) @@ -87,6 +98,8 @@ void ModuleList::run(candidate_vector_t &candidates, bool recursive) { progressbar.update(); } + endRun(); // call endRun in all modules + ::signal(SIGINT, old_signal_handler); } @@ -106,6 +119,8 @@ void ModuleList::run(Source *source, size_t count, bool recursive) { sighandler_t old_signal_handler = ::signal(SIGINT, g_cancel_signal_callback); + beginRun(); // call beginRun in all modules + #pragma omp parallel for schedule(static, 1000) for (size_t i = 0; i < count; i++) { if (g_cancel_signal_flag) @@ -119,6 +134,8 @@ void ModuleList::run(Source *source, size_t count, bool recursive) { progressbar.update(); } + endRun(); // call endRun in all modules + ::signal(SIGINT, old_signal_handler); } @@ -133,11 +150,9 @@ const ModuleList::module_list_t &ModuleList::getModules() const { std::string ModuleList::getDescription() const { std::stringstream ss; ss << "ModuleList\n"; - crpropa::ModuleList::module_list_t::const_iterator it; - for (it = modules.begin(); it != modules.end(); ++it) { - const crpropa::ref_ptr &m = *it; - ss << " " << m->getDescription() << "\n"; - } + crpropa::ModuleList::module_list_t::const_iterator m; + for (m = modules.begin(); m != modules.end(); m++) + ss << " " << (*m)->getDescription() << "\n"; return ss.str(); } diff --git a/src/module/Observer.cpp b/src/module/Observer.cpp index 1b3a32e2d..7b2a6eb3e 100644 --- a/src/module/Observer.cpp +++ b/src/module/Observer.cpp @@ -5,17 +5,7 @@ namespace crpropa { -DetectionState ObserverFeature::checkDetection(Candidate *candidate) const { - return NOTHING; -} - -void ObserverFeature::onDetection(Candidate *candidate) const { -} - -std::string ObserverFeature::getDescription() const { - return description; -} - +// Observer ------------------------------------------------------------------- Observer::Observer(bool makeInactive) : makeInactive(makeInactive) { } @@ -24,6 +14,16 @@ void Observer::add(ObserverFeature *feature) { features.push_back(feature); } +void crpropa::Observer::beginRun() { + for (int i = 0; i < features.size(); i++) + features[i]->beginRun(); +} + +void crpropa::Observer::endRun() { + for (int i = 0; i < features.size(); i++) + features[i]->endRun(); +} + void Observer::process(Candidate *candidate) const { // loop over all features and have them check the particle DetectionState state = NOTHING; @@ -53,6 +53,25 @@ std::string Observer::getDescription() const { return ss.str(); } +// ObserverFeature ------------------------------------------------------------ +DetectionState ObserverFeature::checkDetection(Candidate *candidate) const { + return NOTHING; +} + +void ObserverFeature::onDetection(Candidate *candidate) const { +} + +void ObserverFeature::beginRun() { +} + +void ObserverFeature::endRun() { +} + +std::string ObserverFeature::getDescription() const { + return description; +} + +// ObserverSmallSphere -------------------------------------------------------- ObserverSmallSphere::ObserverSmallSphere(Vector3d center, double radius) : center(center), radius(radius) { } @@ -87,6 +106,7 @@ std::string ObserverSmallSphere::getDescription() const { return ss.str(); } +// ObserverLargeSphere -------------------------------------------------------- ObserverLargeSphere::ObserverLargeSphere(Vector3d center, double radius) : center(center), radius(radius) { } @@ -121,7 +141,7 @@ std::string ObserverLargeSphere::getDescription() const { return ss.str(); } - +// ObserverPoint -------------------------------------------------------------- DetectionState ObserverPoint::checkDetection(Candidate *candidate) const { double x = candidate->current.getPosition().x; if (x > 0) { @@ -135,7 +155,7 @@ std::string ObserverPoint::getDescription() const { return "ObserverPoint: observer at x = 0"; } - +// ObserverRedshiftWindow ----------------------------------------------------- ObserverRedshiftWindow::ObserverRedshiftWindow(double zmin, double zmax) : zmin(zmin), zmax(zmax) { } @@ -156,6 +176,7 @@ std::string ObserverRedshiftWindow::getDescription() const { return ss.str(); } +// ObserverNucleusVeto -------------------------------------------------------- DetectionState ObserverNucleusVeto::checkDetection(Candidate *c) const { if (isNucleus(c->current.getId())) return NOTHING; @@ -166,6 +187,7 @@ std::string ObserverNucleusVeto::getDescription() const { return "ObserverNucleusVeto"; } +// ObserverNeutrinoVeto ------------------------------------------------------- DetectionState ObserverNeutrinoVeto::checkDetection(Candidate *c) const { int id = fabs(c->current.getId()); if ((id == 12) or (id == 14) or (id == 16)) @@ -177,6 +199,7 @@ std::string ObserverNeutrinoVeto::getDescription() const { return "ObserverNeutrinoVeto"; } +// ObserverPhotonVeto --------------------------------------------------------- DetectionState ObserverPhotonVeto::checkDetection(Candidate *c) const { if (c->current.getId() == 22) return NOTHING; @@ -187,31 +210,31 @@ std::string ObserverPhotonVeto::getDescription() const { return "ObserverPhotonVeto"; } +// ObserverOutput3D ----------------------------------------------------------- ObserverOutput3D::ObserverOutput3D(std::string fname, bool legacy) : legacy(legacy) { description = "ObserverOutput3D: " + fname; fout.open(fname.c_str()); if (legacy) { - fout << "#CRPropa - Output data file\n"; - fout << "#Format - Particle_Type "; - fout << "Initial_Particle_Type "; - fout << "Initial_Position[X,Y,Z](Mpc) "; - fout << "Initial_Momentum[E(EeV),theta,phi] "; - fout << "Time(Mpc, light travel distance) "; - fout << "Position[X,Y,Z](Mpc) "; - fout << "Momentum[E(EeV),theta,phi]\n"; + fout << "#CRPropa - Output data file\n" + << "#Format - Particle_Type " + << "Initial_Particle_Type " + << "Initial_Position[X,Y,Z](Mpc) " + << "Initial_Momentum[E(EeV),theta,phi] " + << "Time(Mpc, light travel distance) " + << "Position[X,Y,Z](Mpc) " + << "Momentum[E(EeV),theta,phi]\n"; } else { - fout - << "# D\tID\tID0\tE\tE0\tX\tY\tZ\tX0\tY0\tZ0\tPx\tPy\tPz\tP0x\tP0y\tP0z\n"; - fout << "#\n"; - fout << "# D Trajectory length [Mpc]\n"; - fout << "# ID Particle type (PDG MC numbering scheme)\n"; - fout << "# E Energy [EeV]\n"; - fout << "# X, Y, Z Position [Mpc]\n"; - fout << "# Px, Py, Pz Heading (unit vector of momentum)\n"; - fout << "# Initial state: ID0, E0, ...\n"; - fout << "#\n"; + fout << "# D\tID\tID0\tE\tE0\tX\tY\tZ\tX0\tY0\tZ0\tPx\tPy\tPz\tP0x\tP0y\tP0z\n" + << "#\n" + << "# D Trajectory length [Mpc]\n" + << "# ID Particle type (PDG MC numbering scheme)\n" + << "# E Energy [EeV]\n" + << "# X, Y, Z Position [Mpc]\n" + << "# Px, Py, Pz Heading (unit vector of momentum)\n" + << "# Initial state: ID0, E0, ...\n" + << "#\n"; } } @@ -265,31 +288,33 @@ void ObserverOutput3D::onDetection(Candidate *candidate) const { } #pragma omp critical - { - fout.write(buffer, p); - fout.flush(); - } + fout.write(buffer, p); } +void ObserverOutput3D::endRun() { + fout.flush(); +} + +// ObserverOutput1D ----------------------------------------------------------- ObserverOutput1D::ObserverOutput1D(std::string fname, bool legacy) : legacy(legacy) { description = "ObserverOutput1D: " + fname; fout.open(fname.c_str()); if (legacy) { - fout << "#CRPropa - Output data file\n"; - fout << "#Format - Energy(EeV) "; - fout << "Time(Mpc, light travel distance) "; - fout << "Initial_Particle_Type "; - fout << "Initial_Energy(EeV)\n"; + fout << "#CRPropa - Output data file\n" + << "#Format - Energy(EeV) " + << "Time(Mpc, light travel distance) " + << "Initial_Particle_Type " + << "Initial_Energy(EeV)\n"; } else { - fout << "#ID\tE\tD\tID0\tE0\n"; - fout << "#\n"; - fout << "# ID Particle type\n"; - fout << "# E Energy [EeV]\n"; - fout << "# D Comoving trajectory length [Mpc]\n"; - fout << "# ID0 Initial particle type\n"; - fout << "# E0 Initial energy [EeV]\n"; + fout << "#ID\tE\tD\tID0\tE0\n" + << "#\n" + << "# ID Particle type\n" + << "# E Energy [EeV]\n" + << "# D Comoving trajectory length [Mpc]\n" + << "# ID0 Initial particle type\n" + << "# E0 Initial energy [EeV]\n"; } } @@ -323,10 +348,11 @@ void ObserverOutput1D::onDetection(Candidate *candidate) const { } #pragma omp critical - { - fout.write(buffer, p); - fout.flush(); - } + fout.write(buffer, p); +} + +void ObserverOutput1D::endRun() { + fout.flush(); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/module/OutputCRPropa2.cpp b/src/module/OutputCRPropa2.cpp index 9cfba64af..d97e8da81 100644 --- a/src/module/OutputCRPropa2.cpp +++ b/src/module/OutputCRPropa2.cpp @@ -55,10 +55,11 @@ void CRPropa2EventOutput3D::process(Candidate *c) const { p += sprintf(buffer + p, "%.4f %.4f %.4f\n", E, phi, theta); #pragma omp critical - { - outfile.write(buffer, p); - outfile.flush(); - } + outfile.write(buffer, p); +} + +void CRPropa2EventOutput3D::endRun() { + outfile.flush(); } CRPropa2TrajectoryOutput3D::CRPropa2TrajectoryOutput3D(std::string filename) { @@ -96,10 +97,11 @@ void CRPropa2TrajectoryOutput3D::process(Candidate *c) const { p += sprintf(buffer + p, "%.4f\n", c->current.getEnergy() / EeV); #pragma omp critical - { - outfile.write(buffer, p); - outfile.flush(); - } + outfile.write(buffer, p); +} + +void CRPropa2TrajectoryOutput3D::endRun() { + outfile.flush(); } CRPropa2TrajectoryOutput1D::CRPropa2TrajectoryOutput1D(std::string filename) { @@ -124,10 +126,11 @@ void CRPropa2TrajectoryOutput1D::process(Candidate *c) const { p += sprintf(buffer + p, "%.4f\n", c->current.getEnergy() / EeV); #pragma omp critical - { - outfile.write(buffer, p); - outfile.flush(); - } + outfile.write(buffer, p); +} + +void CRPropa2TrajectoryOutput1D::endRun() { + outfile.flush(); } CRPropa2EventOutput1D::CRPropa2EventOutput1D(std::string filename) { @@ -162,10 +165,11 @@ void CRPropa2EventOutput1D::process(Candidate *c) const { p += sprintf(buffer + p, "%.4f\n", c->source.getEnergy() / EeV); #pragma omp critical - { - outfile.write(buffer, p); - outfile.flush(); - } + outfile.write(buffer, p); +} + +void CRPropa2EventOutput1D::endRun() { + outfile.flush(); } } // namespace crpropa diff --git a/src/module/OutputTXT.cpp b/src/module/OutputTXT.cpp index 991a04165..7a19ed49e 100644 --- a/src/module/OutputTXT.cpp +++ b/src/module/OutputTXT.cpp @@ -8,14 +8,14 @@ namespace crpropa { TrajectoryOutput::TrajectoryOutput(std::string name) { setDescription("Trajectory output"); fout.open(name.c_str()); - fout << "# D\tID\tE\tX\tY\tZ\tPx\tPy\tPz\n"; - fout << "#\n"; - fout << "# D Trajectory length\n"; - fout << "# ID Particle type (PDG MC numbering scheme)\n"; - fout << "# E Energy [EeV]\n"; - fout << "# X, Y, Z Position [Mpc]\n"; - fout << "# Px, Py, Pz Heading (unit vector of momentum)\n"; - fout << "#\n"; + fout << "# D\tID\tE\tX\tY\tZ\tPx\tPy\tPz\n" + << "#\n" + << "# D Trajectory length\n" + << "# ID Particle type (PDG MC numbering scheme)\n" + << "# E Energy [EeV]\n" + << "# X, Y, Z Position [Mpc]\n" + << "# Px, Py, Pz Heading (unit vector of momentum)\n" + << "#\n"; } TrajectoryOutput::~TrajectoryOutput() { @@ -35,10 +35,11 @@ void TrajectoryOutput::process(Candidate *c) const { p += sprintf(buffer + p, "%8.5f\t%8.5f\t%8.5f\n", dir.x, dir.y, dir.z); #pragma omp critical - { - fout.write(buffer, p); - fout.flush(); - } + fout.write(buffer, p); +} + +void TrajectoryOutput::endRun() { + fout.flush(); } ConditionalOutput::ConditionalOutput(std::string fname, std::string cond) : @@ -46,16 +47,16 @@ ConditionalOutput::ConditionalOutput(std::string fname, std::string cond) : setDescription( "Conditional output, condition: " + cond + ", filename: " + fname); fout.open(fname.c_str()); - fout << "# D\tID\tID0\tE\tE0\tX\tY\tZ\tX0\tY0\tZ0\tPx\tPy\tPz\tP0x\tP0y\tP0z\tz\n"; - fout << "#\n"; - fout << "# D Trajectory length [Mpc]\n"; - fout << "# ID Particle type (PDG MC numbering scheme)\n"; - fout << "# E Energy [EeV]\n"; - fout << "# X, Y, Z Position [Mpc]\n"; - fout << "# Px, Py, Pz Heading (unit vector of momentum)\n"; - fout << "# z Current redshift\n"; - fout << "# Initial state: ID0, E0, ...\n"; - fout << "#\n"; + fout << "# D\tID\tID0\tE\tE0\tX\tY\tZ\tX0\tY0\tZ0\tPx\tPy\tPz\tP0x\tP0y\tP0z\tz\n" + << "#\n" + << "# D Trajectory length [Mpc]\n" + << "# ID Particle type (PDG MC numbering scheme)\n" + << "# E Energy [EeV]\n" + << "# X, Y, Z Position [Mpc]\n" + << "# Px, Py, Pz Heading (unit vector of momentum)\n" + << "# z Current redshift\n" + << "# Initial state: ID0, E0, ...\n" + << "#\n"; } ConditionalOutput::~ConditionalOutput() { @@ -68,7 +69,7 @@ void ConditionalOutput::process(Candidate *c) const { c->removeProperty(condition); - char buffer[256]; + char buffer[1024]; size_t p = 0; p += sprintf(buffer + p, "%8.3f\t", c->getTrajectoryLength() / Mpc); @@ -87,20 +88,21 @@ void ConditionalOutput::process(Candidate *c) const { p += sprintf(buffer + p, "%1.3f\n", c->getRedshift()); #pragma omp critical - { - fout.write(buffer, p); - fout.flush(); - } + fout.write(buffer, p); +} + +void ConditionalOutput::endRun() { + fout.flush(); } TrajectoryOutput1D::TrajectoryOutput1D(std::string filename) { setDescription("TrajectoryOutput, filename: " + filename); fout.open(filename.c_str()); - fout << "#X\tID\tE\n"; - fout << "#\n"; - fout << "# X Position [Mpc]\n"; - fout << "# ID Particle type\n"; - fout << "# E Energy [EeV]\n"; + fout << "#X\tID\tE\n" + << "#\n" + << "# X Position [Mpc]\n" + << "# ID Particle type\n" + << "# E Energy [EeV]\n"; } TrajectoryOutput1D::~TrajectoryOutput1D() { @@ -113,23 +115,25 @@ void TrajectoryOutput1D::process(Candidate *c) const { p += sprintf(buffer + p, "%8.4f\t", c->current.getPosition().x / Mpc); p += sprintf(buffer + p, "%10i\t", c->current.getId()); p += sprintf(buffer + p, "%8.4f\n", c->current.getEnergy() / EeV); + #pragma omp critical - { - fout.write(buffer, p); - fout.flush(); - } + fout.write(buffer, p); +} + +void TrajectoryOutput1D::endRun() { + fout.flush(); } EventOutput1D::EventOutput1D(std::string filename) { setDescription("Conditional output, filename: " + filename); fout.open(filename.c_str()); - fout << "#ID\tE\tD\tID0\tE0\n"; - fout << "#\n"; - fout << "# ID Particle type\n"; - fout << "# E Energy [EeV]\n"; - fout << "# D Comoving source distance [Mpc]\n"; - fout << "# ID0 Initial particle type\n"; - fout << "# E0 Initial energy [EeV]\n"; + fout << "#ID\tE\tD\tID0\tE0\n" + << "#\n" + << "# ID Particle type\n" + << "# E Energy [EeV]\n" + << "# D Comoving source distance [Mpc]\n" + << "# ID0 Initial particle type\n" + << "# E0 Initial energy [EeV]\n"; } EventOutput1D::~EventOutput1D() { @@ -142,7 +146,7 @@ void EventOutput1D::process(Candidate *c) const { c->removeProperty("Detected"); - char buffer[256]; + char buffer[1024]; size_t p = 0; p += sprintf(buffer + p, "%10i\t", c->current.getId()); @@ -152,10 +156,11 @@ void EventOutput1D::process(Candidate *c) const { p += sprintf(buffer + p, "%8.4f\n", c->source.getEnergy() / EeV); #pragma omp critical - { - fout.write(buffer, p); - fout.flush(); - } + fout.write(buffer, p); +} + +void EventOutput1D::endRun() { + fout.flush(); } } // namespace crpropa From 72f9bac7b92674a224bdab720641c9527ff97367 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Mon, 27 Oct 2014 13:38:47 +0100 Subject: [PATCH 0535/1298] Fixed eof bug in ParticlemapContainer --- src/magneticLens/ParticleMapsContainer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/magneticLens/ParticleMapsContainer.cpp b/src/magneticLens/ParticleMapsContainer.cpp index 5ea2037d7..8474b1f55 100644 --- a/src/magneticLens/ParticleMapsContainer.cpp +++ b/src/magneticLens/ParticleMapsContainer.cpp @@ -96,7 +96,8 @@ void ParticleMapsContainer::addParticlesFromFile(const std::string inputFileName >> redShift; double weight = pow(sourceEnergy, sourceEnergyWeightExponent); - addParticle(particleId, energy * EeV, p, weight); + if (infile) + addParticle(particleId, energy * EeV, p, weight); } infile.ignore(std::numeric_limits < std::streamsize > ::max(), '\n'); } From 6c61d7c323d35fed458bcf94c34981b42616f464 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Mon, 27 Oct 2014 15:46:14 +0100 Subject: [PATCH 0536/1298] Fixed wrong coordinate in vector interface --- src/magneticLens/ParticleMapsContainer.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/magneticLens/ParticleMapsContainer.cpp b/src/magneticLens/ParticleMapsContainer.cpp index 8474b1f55..5f5b10880 100644 --- a/src/magneticLens/ParticleMapsContainer.cpp +++ b/src/magneticLens/ParticleMapsContainer.cpp @@ -35,11 +35,13 @@ double* ParticleMapsContainer::getMap(const int particleId, double energy) { if (_data.find(particleId) == _data.end()) { + std::cerr << "No map for ParticleID " << particleId << std::endl; return NULL; } int energyIdx = energy2Idx(energy); if (_data[particleId].find(energyIdx) == _data[particleId].end()) { + std::cerr << "No map for ParticleID and energy" << energy / eV << " eV" << std::endl; return NULL; } return _data[particleId][energy2Idx(energy)]; @@ -62,15 +64,15 @@ void ParticleMapsContainer::addParticle(const int particleId, double energy, dou } uint32_t pixel = _pixelization.direction2Pix(galacticLongitude, galacticLatitude); - _data[particleId][energyIdx][pixel] +=weight; + _data[particleId][energyIdx][pixel] += weight; } void ParticleMapsContainer::addParticle(const int particleId, double energy, const Vector3d &p, double weight) { double galacticLongitude = atan2(-p.y, -p.x); - double galacticLatitude = M_PI / 2 - acos(-p.x / p.getR()); - addParticle(particleId, energy * EeV, galacticLongitude, galacticLatitude, weight); + double galacticLatitude = M_PI / 2 - acos(-p.z / p.getR()); + addParticle(particleId, energy, galacticLongitude, galacticLatitude, weight); } From 03b7b4ca240f43ec9989ad0ea39d4ab66ed08a52 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Wed, 29 Oct 2014 09:42:01 +0100 Subject: [PATCH 0537/1298] Rethrow planck exceptions --- src/magneticLens/Pixelization.cpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/magneticLens/Pixelization.cpp b/src/magneticLens/Pixelization.cpp index 9d3c78a2d..e4c9372b3 100644 --- a/src/magneticLens/Pixelization.cpp +++ b/src/magneticLens/Pixelization.cpp @@ -55,15 +55,36 @@ uint32_t Pixelization::direction2Pix(double longitude, double latitude) const { healpix::vec3 v; spherCo2Vec(longitude, latitude, v); - uint32_t i = (uint32_t) _healpix->vec2pix(v); - return i; + try + { + uint32_t i = (uint32_t) _healpix->vec2pix(v); + return i; + } + catch (healpix::PlanckError &e) + { + std::cerr << "Healpix error triggered from direction2Pix(" << longitude << ", " << latitude << ")\n"; + std::cerr << " v = " << v.x <<", " << v.y << ", " << v.z << std::endl; + std::cerr << "\n The original exception reads:\n"; + std::cerr << e.what() << std::endl; + throw; + } } void Pixelization::pix2Direction(uint32_t i, double &longitude, double &latitude) const { healpix::vec3 v; - v = _healpix->pix2vec(i); + try{ + v = _healpix->pix2vec(i); + } + catch (healpix::PlanckError &e) + { + std::cerr << "Healpix error triggered from pix2Direction(" << i << ", &longitude, &latitude " << ")\n"; + std::cerr << "The original exception reads:\n"; + std::cerr << e.what() << std::endl; + throw; + } + vec2SphereCo(longitude, latitude, v); } From dc14890488a9edf87e630ce8b06616903e6f91d6 Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Thu, 6 Nov 2014 10:49:02 +0100 Subject: [PATCH 0538/1298] Fix bug in photodisintegration that caused selecting the wrong channels --- src/module/PhotoDisintegration.cpp | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 55fb5000c..f1495910a 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -151,38 +151,33 @@ void PhotoDisintegration::process(Candidate *candidate) const { if ((lg <= lgmin) or (lg >= lgmax)) return; - double rate = interpolateEquidistant(lg, lgmin, lgmax, - pdRate[idx]); + double rate = interpolateEquidistant(lg, lgmin, lgmax, pdRate[idx]); - // cosmological scaling, rate per comoving distance) + // cosmological scaling, rate per comoving distance rate *= pow(1 + z, 2) * photonFieldScaling(photonField, z); Random &random = Random::instance(); double randDistance = -log(random.rand()) / rate; // check if an interaction occurs in this step + // if not, limit next step to a fraction of the mean free path if (step < randDistance) { - // limit next step to a fraction of the mean free path candidate->limitNextStep(limit / rate); return; } - // select channel and interact - double cmp = random.rand(); - int channel; - int l = round(lg / (lgmax - lgmin) * (nlg - 1)); // index of closest tabulated point + // index of closest tabulation point + int l = round((lg - lgmin) / (lgmax - lgmin) * (nlg - 1)); + // select channel and interact const std::vector &branches = pdBranch[idx]; - for (size_t i = 0; i < branches.size(); i++) { - const Branch &branch = branches[i]; - channel = branch.channel; - if ((l < 0) || (l >= branch.branchingRatio.size())) - continue; - cmp -= branch.branchingRatio[l]; - if (cmp <= 0) - break; + double cmp = random.rand(); + size_t i = 0; + while ((i < branches.size()) and (cmp > 0)) { + cmp -= branches[i].branchingRatio[l]; + i++; } - performInteraction(candidate, channel); + performInteraction(candidate, branches[i-1].channel); // repeat with remaining step step -= randDistance; From a02b703100e2f01c9b2f15587333720c60291f61 Mon Sep 17 00:00:00 2001 From: Carmelo Evoli Date: Thu, 6 Nov 2014 12:54:08 +0100 Subject: [PATCH 0539/1298] Added CFITSIO as optional library in cmake --- CMakeLists.txt | 9 +++++++++ cmake/FindCFITSIO.cmake | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 cmake/FindCFITSIO.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index a833f057c..297fafada 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,6 +102,15 @@ if(FFTW3F_FOUND) list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_FFTW3F) endif(FFTW3F_FOUND) +# CFITSIO (optional for reading magnetic fields from FITS file) +find_package(CFITSIO) +if(CFITSIO_FOUND) + list(APPEND CRPROPA_EXTRA_INCLUDES ${CFITSIO_INCLUDE_DIR}) + list(APPEND CRPROPA_EXTRA_LIBRARIES ${CFITSIO_LIBRARY}) + add_definitions(-DCRPROPA_HAVE_CFITSIO) + list(APPEND CRPROPA_SWIG_DEFINES -DCRPROPA_HAVE_CFITSIO) +endif(CFITSIO_FOUND) + # Quimby (optional for SPH magnetic fields) find_package(Quimby) if(QUIMBY_FOUND) diff --git a/cmake/FindCFITSIO.cmake b/cmake/FindCFITSIO.cmake new file mode 100644 index 000000000..fd9441b77 --- /dev/null +++ b/cmake/FindCFITSIO.cmake @@ -0,0 +1,22 @@ +# Find CFTISIO +# CFITSIO_FOUND = true if cfitsio is found +# CFITSIO_INCLUDE_DIR = fitsio.h +# CFITSIO_LIBRARY = libcfitsio.a .so + +find_path(CFITSIO_INCLUDE_DIR fitsio.h ${CFITSIO_ROOT_DIR}/include) +find_library(CFITSIO_LIBRARY cfitsio ${CFITSIO_ROOT_DIR}/lib) + +MESSAGE(STATUS " Include: ${CFITSIO_INCLUDE_DIR}") + +set(CFITSIO_FOUND FALSE) +if(CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARY) + set(CFITSIO_FOUND TRUE) + MESSAGE(STATUS "CFITSIO: Found!") +else() + MESSAGE(STATUS "CFITSIO: NOT Found!") +endif() + +MESSAGE(STATUS " Include: ${CFITSIO_INCLUDE_DIR}") +MESSAGE(STATUS " Library: ${CFITSIO_LIBRARY}") + +mark_as_advanced(CFITSIO_INCLUDE_DIR CFITSIO_LIBRARY CFITSIO_FOUND) From 0fc180e0957f07b0b24c55272d97c49c99d67d41 Mon Sep 17 00:00:00 2001 From: Carmelo Evoli Date: Thu, 6 Nov 2014 14:00:08 +0100 Subject: [PATCH 0540/1298] Added a class to read the MagneticField from the FITS file --- .../crpropa/magneticField/FITSMagneticField.h | 42 +++++ src/magneticField/FITSMagneticField.cpp | 155 ++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 include/crpropa/magneticField/FITSMagneticField.h create mode 100644 src/magneticField/FITSMagneticField.cpp diff --git a/include/crpropa/magneticField/FITSMagneticField.h b/include/crpropa/magneticField/FITSMagneticField.h new file mode 100644 index 000000000..625d6b2d0 --- /dev/null +++ b/include/crpropa/magneticField/FITSMagneticField.h @@ -0,0 +1,42 @@ +#ifndef CRPROPA_FITSMAGNETICFIELD_H +#define CRPROPA_FITSMAGNETICFIELD_H + +#ifdef CRPROPA_HAVE_CFITSIO + +#include +#include +#include + +#include "crpropa/Units.h" +#include "crpropa/magneticField/MagneticField.h" +#include "crpropa/Vector3.h" + +#include "fitsio.h" + +namespace crpropa { + + /** + @class FITSMagneticField + @brief Read MagneticField from a given FITS file + */ + class FITSMagneticField: public MagneticField { + + private: + + double cfLength; + double cfDensity; + double cfMagneticField; + + public: + + FITSMagneticField(){}; + FITSMagneticField(const std::string&); + Vector3d getField(const Vector3d&) const; + + //dtr + }; + +} // namespace crpropa + +#endif // CRPROPA_HAVE_CFITSIO +#endif // CRPROPA_FITSMAGNETICFIELD_H diff --git a/src/magneticField/FITSMagneticField.cpp b/src/magneticField/FITSMagneticField.cpp new file mode 100644 index 000000000..efa9ab31d --- /dev/null +++ b/src/magneticField/FITSMagneticField.cpp @@ -0,0 +1,155 @@ +#include "crpropa/magneticField/FITSMagneticField.h" + +namespace crpropa { + FITSMagneticField::FITSMagneticField(const std::string& fitsFileName){ + + // Where reading these parameters? + long _fNx = 1; + long _fNy = 1; + long _fNz = 1; + double _fBmax; + double _fpB[10000]; + // + + int lStatus = 0 ; + int lAnyNull = 0 ; + int lNaxis = 0 ; + long *lNaxes = new long[3] ; + + double *lpBx = new double[_fNx*_fNy*_fNz] ; + fitsfile *lpBxFits ; + + const char *lExtBx = (fitsFileName).c_str() ; + + fits_open_file(&lpBxFits, lExtBx, READONLY, &lStatus) ; + int lDummy = 0 ; + fits_movabs_hdu(lpBxFits,1,&lDummy,&lStatus); + fits_get_img_dim(lpBxFits, &lNaxis, &lStatus) ; + //////if (lNaxis != 3) throw TFitsErr("NAXIS incorrect for Bx.") ; + fits_get_img_size(lpBxFits, 3, lNaxes, &lStatus) ; + ///if (lNaxes[0]!=_fNx || lNaxes[1]!=_fNy || lNaxes[2]!=_fNz) + /// throw TFitsErr("size of Bx array not ok with xml specifications.") ; + fits_read_img(lpBxFits, TDOUBLE, 1, _fNx*_fNy*_fNz, + NULL, lpBx, &lAnyNull, &lStatus) ; + fits_close_file(lpBxFits,&lStatus) ; + ////if (lStatus) throw TFitsErr(lStatus) ; + ////if (lAnyNull) throw TFitsErr("Undefined elements in Bx extension.") ; + + double *lpBy = new double[_fNx*_fNy*_fNz] ; + fitsfile *lpByFits ; + const char *lExtBy = (fitsFileName).c_str() ; + fits_open_file(&lpByFits, lExtBy, READONLY, &lStatus) ; + fits_movabs_hdu(lpByFits,2,&lDummy,&lStatus); + fits_get_img_dim(lpByFits, &lNaxis, &lStatus) ; + //if (lNaxis != 3) throw TFitsErr("NAXIS incorrect for By.") ; + fits_get_img_size(lpByFits, 3, lNaxes, &lStatus) ; + //if (lNaxes[0]!=_fNx || lNaxes[1]!=_fNy || lNaxes[2]!=_fNz) + // throw TFitsErr("size of By array not ok with xml specifications.") ; + fits_read_img(lpByFits, TDOUBLE, 1, _fNx*_fNy*_fNz, + NULL, lpBy, &lAnyNull, &lStatus) ; + fits_close_file(lpByFits,&lStatus) ; + //if (lStatus) throw TFitsErr(lStatus) ; + //if (lAnyNull) throw TFitsErr("Undefined elements in Bx extension.") ; + + double *lpBz = new double[_fNx*_fNy*_fNz] ; + fitsfile *lpBzFits ; + const char *lExtBz = (fitsFileName).c_str() ; + fits_open_file(&lpBzFits, lExtBz, READONLY, &lStatus) ; + fits_movabs_hdu(lpBzFits,3,&lDummy,&lStatus); + fits_get_img_dim(lpBzFits, &lNaxis, &lStatus) ; + //if (lNaxis != 3) throw TFitsErr("NAXIS incorrect for Bz.") ; + fits_get_img_size(lpBzFits, 3, lNaxes, &lStatus) ; + //if (lNaxes[0]!=_fNx || lNaxes[1]!=_fNy || lNaxes[2]!=_fNz) + // throw TFitsErr("size of Bx array not ok with xml specifications.") ; + fits_read_img(lpBzFits, TDOUBLE, 1, _fNx*_fNy*_fNz, + NULL, lpBz, &lAnyNull, &lStatus) ; + fits_close_file(lpBzFits,&lStatus) ; + //if (lStatus) throw TFitsErr(lStatus) ; + //if (lAnyNull) throw TFitsErr("Undefined elements in Bz extension.") ; + + _fBmax = 0. ; + + long lInd, lIndFits ; + for (int i=0; i<_fNx; i++) { + for (int j=0; j<_fNy; j++) { + for (int k=0; k<_fNz; k++) { + lIndFits = i+j*_fNx+k*_fNx*_fNy ; + lInd = i*_fNy*_fNz+j*_fNz+k ; + //(_fpB[lInd]).set(lpBx[lIndFits], lpBy[lIndFits], lpBz[lIndFits]); + //(_fpB[lInd]) *= gauss ; // unit in the fits file + //_fBmax = std::max(_fBmax, (_fpB[lInd]).mag() ) ; + } + } + } + delete[] lpBx; + delete[] lpBy; + delete[] lpBz ; + delete[] lNaxes ; + + return; + } + + Vector3d FITSMagneticField::getField(const Vector3d &position) const { + return Vector3d(0,0,0); + } +} + + // AMRMagneticField(const string& fitsFilename) + // { + // // + // long _fNx = 1; + // long _fNy = 1; + // long _fNz = 1; + // // + + + + + + + + // _fBmax = 0. ; + // long lInd, lIndFits ; + // for (int i=0; i<_fNx; i++) { + // for (int j=0; j<_fNy; j++) { + // for (int k=0; k<_fNz; k++) { + // lIndFits = i+j*_fNx+k*_fNx*_fNy ; + // lInd = i*_fNy*_fNz+j*_fNz+k ; + // (_fpB[lInd]).set(lpBx[lIndFits], lpBy[lIndFits], lpBz[lIndFits]); + // (_fpB[lInd]) *= gauss ; // unit in the fits file + // //if( _fBmax < (_fpB[lInd]).mag() ){ + // //std::cout<<"lInd"< b; + // #ifdef _OPENMP + // #pragma omp critical + // { + // b = field->getField(x, y, z); + // } + // #else + // b = field->getField(x, y, z); + // #endif + + // for(int i=0; i<3; i++) + // b[i]*=cfMagneticField; + // //std::cout << x*cfLength/Mpc << " " << y*cfLength/Mpc << " " << z*cfLength/Mpc << " || " << b[0] << " " << b[1] << " " << b[0] << std::endl; + + // return Vector3d(b[0], b[1], b[2]) * tesla; */ + // } From 4e8949fb93a71e06a747aebf1dac7c2d318c35da Mon Sep 17 00:00:00 2001 From: DavidWalz Date: Fri, 7 Nov 2014 09:24:56 +0100 Subject: [PATCH 0541/1298] add check for SOPHIA's energy threshold fixes CRPropa crash without error message (photopion with IRB) --- src/module/PhotoPionProduction.cpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 36d86665b..cc02d6188 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -164,9 +164,13 @@ void PhotoPionProduction::process(Candidate *candidate) const { // check for interaction on protons if (Z > 0) { - double rate = (!doRedshiftDependent) ? - scaling * interpolate(gamma, tabLorentz, tabProtonRate) : - interpolate2d(z, gamma, tabRedshifts, tabLorentz, tabProtonRate); + double rate = + (!doRedshiftDependent) ? + scaling + * interpolate(gamma, tabLorentz, + tabProtonRate) : + interpolate2d(z, gamma, tabRedshifts, tabLorentz, + tabProtonRate); rate *= nucleiModification(A, Z); totalRate += rate; channel = 1; @@ -175,9 +179,13 @@ void PhotoPionProduction::process(Candidate *candidate) const { // check for interaction on neutrons if (N > 0) { - double rate = (!doRedshiftDependent) ? - scaling * interpolate(gamma, tabLorentz, tabNeutronRate) : - interpolate2d(z, gamma, tabRedshifts, tabLorentz, tabNeutronRate); + double rate = + (!doRedshiftDependent) ? + scaling + * interpolate(gamma, tabLorentz, + tabNeutronRate) : + interpolate2d(z, gamma, tabRedshifts, tabLorentz, + tabNeutronRate); rate *= nucleiModification(A, N); totalRate += rate; double d = -log(random.rand()) / rate; @@ -225,6 +233,11 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, double dummy2[2]; // not needed int background = (photonField == CMB) ? 1 : 2; // photon background: 1 for CMB, 2 for Kneiske IRB + // check if below SOPHIA's energy threshold + double E_threshold = (photonField == CMB) ? 3.72e18 * eV : 5.83e15 * eV; + if (EpA < E_threshold) + return; + #pragma omp critical { sophiaevent_(nature, Ein, momentaList, particleList, nParticles, z, From f3315973c65cf2202bf1531e08e7c4469bfb2f60 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 7 Nov 2014 15:18:10 +0100 Subject: [PATCH 0542/1298] Use Eigen instead of UBlas for Magnetic Lenses --- CMakeLists.txt | 25 +- include/crpropa/magneticLens/MagneticLens.h | 17 +- include/crpropa/magneticLens/ModelMatrix.h | 94 +- libs/eigen3/Eigen/Core | 376 +++++ libs/eigen3/Eigen/SparseCore | 64 + libs/eigen3/Eigen/src/Core/Array.h | 308 ++++ libs/eigen3/Eigen/src/Core/ArrayBase.h | 228 +++ libs/eigen3/Eigen/src/Core/ArrayWrapper.h | 254 ++++ libs/eigen3/Eigen/src/Core/Assign.h | 583 +++++++ libs/eigen3/Eigen/src/Core/Assign_MKL.h | 224 +++ libs/eigen3/Eigen/src/Core/BandMatrix.h | 334 ++++ libs/eigen3/Eigen/src/Core/Block.h | 405 +++++ libs/eigen3/Eigen/src/Core/BooleanRedux.h | 154 ++ libs/eigen3/Eigen/src/Core/CommaInitializer.h | 154 ++ libs/eigen3/Eigen/src/Core/CoreIterators.h | 61 + libs/eigen3/Eigen/src/Core/CwiseBinaryOp.h | 229 +++ libs/eigen3/Eigen/src/Core/CwiseNullaryOp.h | 864 +++++++++++ libs/eigen3/Eigen/src/Core/CwiseUnaryOp.h | 126 ++ libs/eigen3/Eigen/src/Core/CwiseUnaryView.h | 139 ++ libs/eigen3/Eigen/src/Core/DenseBase.h | 521 +++++++ libs/eigen3/Eigen/src/Core/DenseCoeffsBase.h | 754 +++++++++ libs/eigen3/Eigen/src/Core/DenseStorage.h | 339 +++++ libs/eigen3/Eigen/src/Core/Diagonal.h | 237 +++ libs/eigen3/Eigen/src/Core/DiagonalMatrix.h | 313 ++++ libs/eigen3/Eigen/src/Core/DiagonalProduct.h | 130 ++ libs/eigen3/Eigen/src/Core/Dot.h | 263 ++++ libs/eigen3/Eigen/src/Core/EigenBase.h | 131 ++ libs/eigen3/Eigen/src/Core/Flagged.h | 140 ++ .../Eigen/src/Core/ForceAlignedAccess.h | 146 ++ libs/eigen3/Eigen/src/Core/Functors.h | 985 ++++++++++++ libs/eigen3/Eigen/src/Core/Fuzzy.h | 150 ++ libs/eigen3/Eigen/src/Core/GeneralProduct.h | 635 ++++++++ .../eigen3/Eigen/src/Core/GenericPacketMath.h | 350 +++++ libs/eigen3/Eigen/src/Core/GlobalFunctions.h | 92 ++ libs/eigen3/Eigen/src/Core/IO.h | 250 +++ libs/eigen3/Eigen/src/Core/Map.h | 192 +++ libs/eigen3/Eigen/src/Core/MapBase.h | 244 +++ libs/eigen3/Eigen/src/Core/MathFunctions.h | 768 ++++++++++ libs/eigen3/Eigen/src/Core/Matrix.h | 405 +++++ libs/eigen3/Eigen/src/Core/MatrixBase.h | 560 +++++++ libs/eigen3/Eigen/src/Core/NestByValue.h | 111 ++ libs/eigen3/Eigen/src/Core/NoAlias.h | 134 ++ libs/eigen3/Eigen/src/Core/NumTraits.h | 150 ++ .../eigen3/Eigen/src/Core/PermutationMatrix.h | 689 +++++++++ libs/eigen3/Eigen/src/Core/PlainObjectBase.h | 790 ++++++++++ libs/eigen3/Eigen/src/Core/ProductBase.h | 278 ++++ libs/eigen3/Eigen/src/Core/Random.h | 152 ++ libs/eigen3/Eigen/src/Core/Redux.h | 408 +++++ libs/eigen3/Eigen/src/Core/Ref.h | 260 ++++ libs/eigen3/Eigen/src/Core/Replicate.h | 177 +++ libs/eigen3/Eigen/src/Core/ReturnByValue.h | 88 ++ libs/eigen3/Eigen/src/Core/Reverse.h | 224 +++ libs/eigen3/Eigen/src/Core/Select.h | 162 ++ libs/eigen3/Eigen/src/Core/SelfAdjointView.h | 314 ++++ .../eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h | 197 +++ libs/eigen3/Eigen/src/Core/SolveTriangular.h | 260 ++++ .../Eigen/src/Core/SparseCore/AmbiVector.h | 373 +++++ .../src/Core/SparseCore/CompressedStorage.h | 233 +++ .../ConservativeSparseSparseProduct.h | 245 +++ .../src/Core/SparseCore/MappedSparseMatrix.h | 181 +++ .../Eigen/src/Core/SparseCore/SparseBlock.h | 409 +++++ .../src/Core/SparseCore/SparseColEtree.h | 206 +++ .../src/Core/SparseCore/SparseCwiseBinaryOp.h | 325 ++++ .../src/Core/SparseCore/SparseCwiseUnaryOp.h | 163 ++ .../src/Core/SparseCore/SparseDenseProduct.h | 320 ++++ .../Core/SparseCore/SparseDiagonalProduct.h | 196 +++ .../Eigen/src/Core/SparseCore/SparseDot.h | 101 ++ .../Eigen/src/Core/SparseCore/SparseFuzzy.h | 26 + .../Eigen/src/Core/SparseCore/SparseMatrix.h | 1259 ++++++++++++++++ .../src/Core/SparseCore/SparseMatrixBase.h | 451 ++++++ .../src/Core/SparseCore/SparsePermutation.h | 148 ++ .../Eigen/src/Core/SparseCore/SparseProduct.h | 188 +++ .../Eigen/src/Core/SparseCore/SparseRedux.h | 45 + .../Core/SparseCore/SparseSelfAdjointView.h | 507 +++++++ .../SparseSparseProductWithPruning.h | 150 ++ .../src/Core/SparseCore/SparseTranspose.h | 63 + .../Core/SparseCore/SparseTriangularView.h | 179 +++ .../Eigen/src/Core/SparseCore/SparseUtil.h | 173 +++ .../Eigen/src/Core/SparseCore/SparseVector.h | 447 ++++++ .../Eigen/src/Core/SparseCore/SparseView.h | 99 ++ .../src/Core/SparseCore/TriangularSolver.h | 334 ++++ libs/eigen3/Eigen/src/Core/StableNorm.h | 203 +++ libs/eigen3/Eigen/src/Core/Stride.h | 108 ++ libs/eigen3/Eigen/src/Core/Swap.h | 126 ++ libs/eigen3/Eigen/src/Core/Transpose.h | 419 +++++ libs/eigen3/Eigen/src/Core/Transpositions.h | 436 ++++++ libs/eigen3/Eigen/src/Core/TriangularMatrix.h | 830 ++++++++++ libs/eigen3/Eigen/src/Core/VectorBlock.h | 95 ++ libs/eigen3/Eigen/src/Core/VectorwiseOp.h | 642 ++++++++ libs/eigen3/Eigen/src/Core/Visitor.h | 237 +++ .../Eigen/src/Core/arch/AltiVec/Complex.h | 217 +++ .../Eigen/src/Core/arch/AltiVec/PacketMath.h | 501 ++++++ .../Eigen/src/Core/arch/Default/Settings.h | 49 + .../eigen3/Eigen/src/Core/arch/NEON/Complex.h | 253 ++++ .../Eigen/src/Core/arch/NEON/PacketMath.h | 410 +++++ libs/eigen3/Eigen/src/Core/arch/SSE/Complex.h | 442 ++++++ .../Eigen/src/Core/arch/SSE/MathFunctions.h | 475 ++++++ .../Eigen/src/Core/arch/SSE/PacketMath.h | 649 ++++++++ .../src/Core/products/CoeffBasedProduct.h | 441 ++++++ .../Core/products/GeneralBlockPanelKernel.h | 1341 +++++++++++++++++ .../src/Core/products/GeneralMatrixMatrix.h | 427 ++++++ .../products/GeneralMatrixMatrixTriangular.h | 278 ++++ .../GeneralMatrixMatrixTriangular_MKL.h | 146 ++ .../Core/products/GeneralMatrixMatrix_MKL.h | 118 ++ .../src/Core/products/GeneralMatrixVector.h | 566 +++++++ .../Core/products/GeneralMatrixVector_MKL.h | 131 ++ .../Eigen/src/Core/products/Parallelizer.h | 159 ++ .../Core/products/SelfadjointMatrixMatrix.h | 436 ++++++ .../products/SelfadjointMatrixMatrix_MKL.h | 295 ++++ .../Core/products/SelfadjointMatrixVector.h | 281 ++++ .../products/SelfadjointMatrixVector_MKL.h | 114 ++ .../src/Core/products/SelfadjointProduct.h | 123 ++ .../Core/products/SelfadjointRank2Update.h | 93 ++ .../Core/products/TriangularMatrixMatrix.h | 427 ++++++ .../products/TriangularMatrixMatrix_MKL.h | 309 ++++ .../Core/products/TriangularMatrixVector.h | 348 +++++ .../products/TriangularMatrixVector_MKL.h | 247 +++ .../Core/products/TriangularSolverMatrix.h | 329 ++++ .../products/TriangularSolverMatrix_MKL.h | 155 ++ .../Core/products/TriangularSolverVector.h | 139 ++ libs/eigen3/Eigen/src/Core/util/BlasUtil.h | 264 ++++ libs/eigen3/Eigen/src/Core/util/Constants.h | 438 ++++++ .../src/Core/util/DisableStupidWarnings.h | 40 + .../Eigen/src/Core/util/ForwardDeclarations.h | 299 ++++ libs/eigen3/Eigen/src/Core/util/MKL_support.h | 126 ++ libs/eigen3/Eigen/src/Core/util/Macros.h | 424 ++++++ libs/eigen3/Eigen/src/Core/util/Memory.h | 977 ++++++++++++ libs/eigen3/Eigen/src/Core/util/Meta.h | 243 +++ libs/eigen3/Eigen/src/Core/util/NonMPL2.h | 3 + .../src/Core/util/ReenableStupidWarnings.h | 14 + .../eigen3/Eigen/src/Core/util/StaticAssert.h | 206 +++ libs/eigen3/Eigen/src/Core/util/XprHelper.h | 469 ++++++ libs/eigen3/Eigen/src/SparseCore/AmbiVector.h | 373 +++++ .../Eigen/src/SparseCore/CompressedStorage.h | 233 +++ .../ConservativeSparseSparseProduct.h | 245 +++ .../Eigen/src/SparseCore/MappedSparseMatrix.h | 181 +++ .../eigen3/Eigen/src/SparseCore/SparseBlock.h | 409 +++++ .../Eigen/src/SparseCore/SparseColEtree.h | 206 +++ .../src/SparseCore/SparseCwiseBinaryOp.h | 325 ++++ .../Eigen/src/SparseCore/SparseCwiseUnaryOp.h | 163 ++ .../Eigen/src/SparseCore/SparseDenseProduct.h | 320 ++++ .../src/SparseCore/SparseDiagonalProduct.h | 196 +++ libs/eigen3/Eigen/src/SparseCore/SparseDot.h | 101 ++ .../eigen3/Eigen/src/SparseCore/SparseFuzzy.h | 26 + .../Eigen/src/SparseCore/SparseMatrix.h | 1259 ++++++++++++++++ .../Eigen/src/SparseCore/SparseMatrixBase.h | 451 ++++++ .../Eigen/src/SparseCore/SparsePermutation.h | 148 ++ .../Eigen/src/SparseCore/SparseProduct.h | 188 +++ .../eigen3/Eigen/src/SparseCore/SparseRedux.h | 45 + .../src/SparseCore/SparseSelfAdjointView.h | 507 +++++++ .../SparseSparseProductWithPruning.h | 150 ++ .../Eigen/src/SparseCore/SparseTranspose.h | 63 + .../src/SparseCore/SparseTriangularView.h | 179 +++ libs/eigen3/Eigen/src/SparseCore/SparseUtil.h | 173 +++ .../Eigen/src/SparseCore/SparseVector.h | 447 ++++++ libs/eigen3/Eigen/src/SparseCore/SparseView.h | 99 ++ .../Eigen/src/SparseCore/TriangularSolver.h | 334 ++++ .../Eigen/src/plugins/ArrayCwiseBinaryOps.h | 211 +++ .../Eigen/src/plugins/ArrayCwiseUnaryOps.h | 203 +++ libs/eigen3/Eigen/src/plugins/BlockMethods.h | 935 ++++++++++++ .../Eigen/src/plugins/CommonCwiseBinaryOps.h | 46 + .../Eigen/src/plugins/CommonCwiseUnaryOps.h | 172 +++ .../Eigen/src/plugins/MatrixCwiseBinaryOps.h | 126 ++ .../Eigen/src/plugins/MatrixCwiseUnaryOps.h | 67 + libs/eigen3/README | 1 + src/magneticLens/MagneticLens.cpp | 80 +- src/magneticLens/ModelMatrix.cpp | 133 +- test/testMagneticLens.cpp | 16 +- 168 files changed, 48547 insertions(+), 221 deletions(-) create mode 100644 libs/eigen3/Eigen/Core create mode 100644 libs/eigen3/Eigen/SparseCore create mode 100644 libs/eigen3/Eigen/src/Core/Array.h create mode 100644 libs/eigen3/Eigen/src/Core/ArrayBase.h create mode 100644 libs/eigen3/Eigen/src/Core/ArrayWrapper.h create mode 100644 libs/eigen3/Eigen/src/Core/Assign.h create mode 100644 libs/eigen3/Eigen/src/Core/Assign_MKL.h create mode 100644 libs/eigen3/Eigen/src/Core/BandMatrix.h create mode 100644 libs/eigen3/Eigen/src/Core/Block.h create mode 100644 libs/eigen3/Eigen/src/Core/BooleanRedux.h create mode 100644 libs/eigen3/Eigen/src/Core/CommaInitializer.h create mode 100644 libs/eigen3/Eigen/src/Core/CoreIterators.h create mode 100644 libs/eigen3/Eigen/src/Core/CwiseBinaryOp.h create mode 100644 libs/eigen3/Eigen/src/Core/CwiseNullaryOp.h create mode 100644 libs/eigen3/Eigen/src/Core/CwiseUnaryOp.h create mode 100644 libs/eigen3/Eigen/src/Core/CwiseUnaryView.h create mode 100644 libs/eigen3/Eigen/src/Core/DenseBase.h create mode 100644 libs/eigen3/Eigen/src/Core/DenseCoeffsBase.h create mode 100644 libs/eigen3/Eigen/src/Core/DenseStorage.h create mode 100644 libs/eigen3/Eigen/src/Core/Diagonal.h create mode 100644 libs/eigen3/Eigen/src/Core/DiagonalMatrix.h create mode 100644 libs/eigen3/Eigen/src/Core/DiagonalProduct.h create mode 100644 libs/eigen3/Eigen/src/Core/Dot.h create mode 100644 libs/eigen3/Eigen/src/Core/EigenBase.h create mode 100644 libs/eigen3/Eigen/src/Core/Flagged.h create mode 100644 libs/eigen3/Eigen/src/Core/ForceAlignedAccess.h create mode 100644 libs/eigen3/Eigen/src/Core/Functors.h create mode 100644 libs/eigen3/Eigen/src/Core/Fuzzy.h create mode 100644 libs/eigen3/Eigen/src/Core/GeneralProduct.h create mode 100644 libs/eigen3/Eigen/src/Core/GenericPacketMath.h create mode 100644 libs/eigen3/Eigen/src/Core/GlobalFunctions.h create mode 100644 libs/eigen3/Eigen/src/Core/IO.h create mode 100644 libs/eigen3/Eigen/src/Core/Map.h create mode 100644 libs/eigen3/Eigen/src/Core/MapBase.h create mode 100644 libs/eigen3/Eigen/src/Core/MathFunctions.h create mode 100644 libs/eigen3/Eigen/src/Core/Matrix.h create mode 100644 libs/eigen3/Eigen/src/Core/MatrixBase.h create mode 100644 libs/eigen3/Eigen/src/Core/NestByValue.h create mode 100644 libs/eigen3/Eigen/src/Core/NoAlias.h create mode 100644 libs/eigen3/Eigen/src/Core/NumTraits.h create mode 100644 libs/eigen3/Eigen/src/Core/PermutationMatrix.h create mode 100644 libs/eigen3/Eigen/src/Core/PlainObjectBase.h create mode 100644 libs/eigen3/Eigen/src/Core/ProductBase.h create mode 100644 libs/eigen3/Eigen/src/Core/Random.h create mode 100644 libs/eigen3/Eigen/src/Core/Redux.h create mode 100644 libs/eigen3/Eigen/src/Core/Ref.h create mode 100644 libs/eigen3/Eigen/src/Core/Replicate.h create mode 100644 libs/eigen3/Eigen/src/Core/ReturnByValue.h create mode 100644 libs/eigen3/Eigen/src/Core/Reverse.h create mode 100644 libs/eigen3/Eigen/src/Core/Select.h create mode 100644 libs/eigen3/Eigen/src/Core/SelfAdjointView.h create mode 100644 libs/eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h create mode 100644 libs/eigen3/Eigen/src/Core/SolveTriangular.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/AmbiVector.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/CompressedStorage.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/ConservativeSparseSparseProduct.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/MappedSparseMatrix.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseBlock.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseColEtree.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseCwiseBinaryOp.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseCwiseUnaryOp.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseDenseProduct.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseDiagonalProduct.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseDot.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseFuzzy.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseMatrix.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseMatrixBase.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparsePermutation.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseProduct.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseRedux.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseSelfAdjointView.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseSparseProductWithPruning.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseTranspose.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseTriangularView.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseUtil.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseVector.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/SparseView.h create mode 100644 libs/eigen3/Eigen/src/Core/SparseCore/TriangularSolver.h create mode 100644 libs/eigen3/Eigen/src/Core/StableNorm.h create mode 100644 libs/eigen3/Eigen/src/Core/Stride.h create mode 100644 libs/eigen3/Eigen/src/Core/Swap.h create mode 100644 libs/eigen3/Eigen/src/Core/Transpose.h create mode 100644 libs/eigen3/Eigen/src/Core/Transpositions.h create mode 100644 libs/eigen3/Eigen/src/Core/TriangularMatrix.h create mode 100644 libs/eigen3/Eigen/src/Core/VectorBlock.h create mode 100644 libs/eigen3/Eigen/src/Core/VectorwiseOp.h create mode 100644 libs/eigen3/Eigen/src/Core/Visitor.h create mode 100644 libs/eigen3/Eigen/src/Core/arch/AltiVec/Complex.h create mode 100644 libs/eigen3/Eigen/src/Core/arch/AltiVec/PacketMath.h create mode 100644 libs/eigen3/Eigen/src/Core/arch/Default/Settings.h create mode 100644 libs/eigen3/Eigen/src/Core/arch/NEON/Complex.h create mode 100644 libs/eigen3/Eigen/src/Core/arch/NEON/PacketMath.h create mode 100644 libs/eigen3/Eigen/src/Core/arch/SSE/Complex.h create mode 100644 libs/eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h create mode 100644 libs/eigen3/Eigen/src/Core/arch/SSE/PacketMath.h create mode 100644 libs/eigen3/Eigen/src/Core/products/CoeffBasedProduct.h create mode 100644 libs/eigen3/Eigen/src/Core/products/GeneralBlockPanelKernel.h create mode 100644 libs/eigen3/Eigen/src/Core/products/GeneralMatrixMatrix.h create mode 100644 libs/eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h create mode 100644 libs/eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_MKL.h create mode 100644 libs/eigen3/Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h create mode 100644 libs/eigen3/Eigen/src/Core/products/GeneralMatrixVector.h create mode 100644 libs/eigen3/Eigen/src/Core/products/GeneralMatrixVector_MKL.h create mode 100644 libs/eigen3/Eigen/src/Core/products/Parallelizer.h create mode 100644 libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix.h create mode 100644 libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix_MKL.h create mode 100644 libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixVector.h create mode 100644 libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixVector_MKL.h create mode 100644 libs/eigen3/Eigen/src/Core/products/SelfadjointProduct.h create mode 100644 libs/eigen3/Eigen/src/Core/products/SelfadjointRank2Update.h create mode 100644 libs/eigen3/Eigen/src/Core/products/TriangularMatrixMatrix.h create mode 100644 libs/eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h create mode 100644 libs/eigen3/Eigen/src/Core/products/TriangularMatrixVector.h create mode 100644 libs/eigen3/Eigen/src/Core/products/TriangularMatrixVector_MKL.h create mode 100644 libs/eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h create mode 100644 libs/eigen3/Eigen/src/Core/products/TriangularSolverMatrix_MKL.h create mode 100644 libs/eigen3/Eigen/src/Core/products/TriangularSolverVector.h create mode 100644 libs/eigen3/Eigen/src/Core/util/BlasUtil.h create mode 100644 libs/eigen3/Eigen/src/Core/util/Constants.h create mode 100644 libs/eigen3/Eigen/src/Core/util/DisableStupidWarnings.h create mode 100644 libs/eigen3/Eigen/src/Core/util/ForwardDeclarations.h create mode 100644 libs/eigen3/Eigen/src/Core/util/MKL_support.h create mode 100644 libs/eigen3/Eigen/src/Core/util/Macros.h create mode 100644 libs/eigen3/Eigen/src/Core/util/Memory.h create mode 100644 libs/eigen3/Eigen/src/Core/util/Meta.h create mode 100644 libs/eigen3/Eigen/src/Core/util/NonMPL2.h create mode 100644 libs/eigen3/Eigen/src/Core/util/ReenableStupidWarnings.h create mode 100644 libs/eigen3/Eigen/src/Core/util/StaticAssert.h create mode 100644 libs/eigen3/Eigen/src/Core/util/XprHelper.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/AmbiVector.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/CompressedStorage.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/MappedSparseMatrix.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseBlock.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseColEtree.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseCwiseUnaryOp.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseDenseProduct.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseDiagonalProduct.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseDot.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseFuzzy.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseMatrix.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseMatrixBase.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparsePermutation.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseProduct.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseRedux.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseSelfAdjointView.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseSparseProductWithPruning.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseTranspose.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseTriangularView.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseUtil.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseVector.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/SparseView.h create mode 100644 libs/eigen3/Eigen/src/SparseCore/TriangularSolver.h create mode 100644 libs/eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h create mode 100644 libs/eigen3/Eigen/src/plugins/ArrayCwiseUnaryOps.h create mode 100644 libs/eigen3/Eigen/src/plugins/BlockMethods.h create mode 100644 libs/eigen3/Eigen/src/plugins/CommonCwiseBinaryOps.h create mode 100644 libs/eigen3/Eigen/src/plugins/CommonCwiseUnaryOps.h create mode 100644 libs/eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h create mode 100644 libs/eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h create mode 100644 libs/eigen3/README diff --git a/CMakeLists.txt b/CMakeLists.txt index aeb0131ba..bf96eac3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,33 +65,28 @@ add_subdirectory(libs/EleCa) list(APPEND CRPROPA_EXTRA_LIBRARIES eleca) list(APPEND CRPROPA_EXTRA_INCLUDES libs/EleCa/include) + # GlacticMagneticLenses option(ENABLE_GALACTICMAGETICLENS "Galactic Magnetic Lens" ON) SET(WITH_GALACTIC_LENSES FALSE) if (ENABLE_GALACTICMAGETICLENS) + SET(WITH_GALACTIC_LENSES TRUE) + # Eigen redux (provided) + add_subdirectory(libs/eigen3) + list(APPEND CRPROPA_EXTRA_INCLUDES libs/eigen3) # healpix redux (provided) add_subdirectory(libs/healpix_base) list(APPEND CRPROPA_EXTRA_LIBRARIES healpix_base) list(APPEND CRPROPA_EXTRA_INCLUDES libs/healpix_base/include) - FIND_PACKAGE(Boost) - IF(Boost_FOUND) - SET(WITH_GALACTIC_LENSES TRUE) - - list(APPEND CRPROPA_SWIG_DEFINES -DWITH_GALACTIC_LENSES) - - list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/MagneticLens.cpp) - list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/ModelMatrix.cpp) - list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/Pixelization.cpp) - list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/ParticleMapsContainer.cpp) + list(APPEND CRPROPA_SWIG_DEFINES -DWITH_GALACTIC_LENSES) - list(APPEND CRPROPA_EXTRA_INCLUDES ${Boost_INCLUDE_DIRS}) - - ELSE(Boost_FOUND) - MESSAGE (STATUS "Cannot find BOOST which is required for GalacticMagneticLenses.") - ENDIF(Boost_FOUND) + list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/MagneticLens.cpp) + list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/ModelMatrix.cpp) + list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/Pixelization.cpp) + list(APPEND CRPROPA_EXTRA_SOURCES src/magneticLens/ParticleMapsContainer.cpp) endif (ENABLE_GALACTICMAGETICLENS) # ROOT (optional for ROOT output) diff --git a/include/crpropa/magneticLens/MagneticLens.h b/include/crpropa/magneticLens/MagneticLens.h index 2d2ebc050..46064154b 100644 --- a/include/crpropa/magneticLens/MagneticLens.h +++ b/include/crpropa/magneticLens/MagneticLens.h @@ -48,7 +48,7 @@ class LensPart string _filename; double _rigidityMin; double _rigidityMax; - ModelMatrix M; + ModelMatrixType M; double _maximumSumOfColumns; bool _maximumSumOfColumns_calculated; @@ -71,7 +71,7 @@ class LensPart /// Loads the matrix from file void loadMatrixFromFile() { - M.deserialize(_filename); + deserialize(_filename, M); } /// Returns the filename of the matrix @@ -85,7 +85,7 @@ class LensPart { if (!_maximumSumOfColumns_calculated) { // lazy calculation of maximum - _maximumSumOfColumns = M.getMaximumOfSumsOfColumns(); + _maximumSumOfColumns = maximumOfSumsOfColumns(M); _maximumSumOfColumns_calculated = true; } return _maximumSumOfColumns; @@ -104,13 +104,13 @@ class LensPart } /// Returns the modelmatrix - ModelMatrix& getMatrix() + ModelMatrixType& getMatrix() { return M; } /// Sets the modelmatrix - void setMatrix(const ModelMatrix& m) + void setMatrix(const ModelMatrixType& m) { M = m; } @@ -143,6 +143,9 @@ typedef std::vector::const_iterator const_LensPartIter; /// Note that the energies refer to protons (Z=1). To be used with other particles with a different charge number please select the rigidity accordingly. class MagneticLens { + + void updateRigidityBounds(double rigidityMin, double rigidityMax); + /// Loads part of a lens (one matrix) from file to use it in given rigidity range. void loadLensPart(const string &filename, double rigidityMin, double rigidityMax); @@ -152,7 +155,7 @@ class MagneticLens Pixelization* _pixelization; // Checks Matrix, raises Errors if not ok - also generate // _pixelization if called first time - void _checkMatrix(const ModelMatrix &M); + void _checkMatrix(const ModelMatrixType &M); // minimum / maximum rigidity that is covered by the lens [Joule] double _minimumRigidity; double _maximumRigidity; @@ -214,7 +217,7 @@ class MagneticLens /// Loads M as part of a lens and use it in given rigidity range with /// rigidities given in Joule - void setLensPart(const ModelMatrix &M, double rigidityMin, double rigidityMax); + void setLensPart(const ModelMatrixType &M, double rigidityMin, double rigidityMax); /// Loads a lens from a given file, containing lines like /// lensefile.MLDAT rigidityMin rigidityMax diff --git a/include/crpropa/magneticLens/ModelMatrix.h b/include/crpropa/magneticLens/ModelMatrix.h index 9cc8628e9..798269215 100644 --- a/include/crpropa/magneticLens/ModelMatrix.h +++ b/include/crpropa/magneticLens/ModelMatrix.h @@ -23,15 +23,6 @@ #ifndef MODELMATRIX_HH #define MODELMATRIX_HH -#define BOOST_UBLAS_SHALLOW_ARRAY_ADAPTOR 1 -#include -#include -#include -#include -#include - -//#include "crpropa/Random.h" - #include #include #include @@ -45,95 +36,34 @@ using namespace std; -namespace crpropa -{ - -/// ModelMatrixType specifies the used Matrix Type -/// Changes here don't break compability, as matrices are stored in a -/// selfmade format. Compressed_matrix however has been tested as the -/// fastest type -typedef boost::numeric::ublas::compressed_matrix ModelMatrixType; -typedef ModelMatrixType::iterator1 i1_t; -typedef ModelMatrixType::iterator2 i2_t; - -typedef ModelMatrixType::const_iterator1 const_i1_t; -typedef ModelMatrixType::const_iterator2 const_i2_t; - -typedef boost::numeric::ublas::compressed_vector ModelVectorType; -typedef ModelVectorType::iterator MVi_t; - -/// Adaptors for direct array access -typedef boost::numeric::ublas::shallow_array_adaptor shallow_adaptor_double; -typedef boost::numeric::ublas::vector shallow_vector_double; +#include -/// The class holds a Magnetic Field Model as a Matrix, with m_i,j is -/// the probability that a particle from pixel j reaches pixel i -class ModelMatrix: public ModelMatrixType +namespace crpropa { -public: - ModelMatrix() : - ModelMatrixType() - { - } - /// Creates a modelmatrix M with size1 x size2 elements as sparse matrix - /// with nnz non-zero elements - ModelMatrix(uint32_t size1, uint32_t size2, uint32_t nnz) : - ModelMatrixType(size1, size2, nnz) - { - } + typedef Eigen::SparseMatrix ModelMatrixType; + typedef Eigen::SparseVector ModelVectorType; /// Writes the ModelMatrix to disk as binary files with the format: /// Int (number of non zero elements), Int (size1), Int (size2) /// (Int, Int, Double) : (column, row, value) triples ... - void serialize(const string &filename); + void serialize(const string &filename, const ModelMatrixType &matrix); /// Reads a matrix from file - void deserialize(const string &filename); - - /// Allow construction from matrix - ModelMatrix& operator=(const ModelMatrixType & source) - { - if (this != &source) - { - this->ModelMatrixType::operator=(source); - } - return *this; - } - - /// Normalizes each row m_i, so that \f$ \Vert m_i \Vert_1 = 1 \f$ - /// Needed to ensure that each pixel on earth contains the same amount of backtracked particles. - void normalizeRows(); + void deserialize(const string &filename, ModelMatrixType &matrix); /// Normalizes each column j of the matrix so that, \f$ \Vert m_j \Vert_1 = 1 \f$ - void normalizeColumns(); + void normalizeColumns(ModelMatrixType &matrix); /// Calculate the maximum of the unity norm of the column vectors of the matrix \f$\max_j(\Vert m_j \Vert_1) \f$ - double getMaximumOfSumsOfColumns() const; + double maximumOfSumsOfColumns(const ModelMatrixType &matrix); - // get sum of column j - double getSumOfColumn(size_t j) const; - - /// Divides matrix by the factor f - void normalizeMatrix(double factor); - - /// Sets element \f$ m_{i,j} \f$ to value - void setElement(size_t i, size_t j, double value) - { - this->ModelMatrixType::operator()(i, j) = value; - } - - /// Returns element \f$ m_{i,j} \f$ - double getElement(size_t i, size_t j) const - { - return this->ModelMatrixType::operator()(i, j); - } - - -}; + double norm_1(const ModelVectorType &v); + void normalizeMatrix(ModelMatrixType& matrix, double norm); + // matrix vector product with update: model = matrix * model + void prod_up(const ModelMatrixType& matrix, double* model); } // namespace parsec #endif // MODELMATRIX_HH diff --git a/libs/eigen3/Eigen/Core b/libs/eigen3/Eigen/Core new file mode 100644 index 000000000..c87f99df3 --- /dev/null +++ b/libs/eigen3/Eigen/Core @@ -0,0 +1,376 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2007-2011 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CORE_H +#define EIGEN_CORE_H + +// first thing Eigen does: stop the compiler from committing suicide +#include "src/Core/util/DisableStupidWarnings.h" + +// then include this file where all our macros are defined. It's really important to do it first because +// it's where we do all the alignment settings (platform detection and honoring the user's will if he +// defined e.g. EIGEN_DONT_ALIGN) so it needs to be done before we do anything with vectorization. +#include "src/Core/util/Macros.h" + +// Disable the ipa-cp-clone optimization flag with MinGW 6.x or newer (enabled by default with -O3) +// See http://eigen.tuxfamily.org/bz/show_bug.cgi?id=556 for details. +#if defined(__MINGW32__) && EIGEN_GNUC_AT_LEAST(4,6) + #pragma GCC optimize ("-fno-ipa-cp-clone") +#endif + +#include + +// this include file manages BLAS and MKL related macros +// and inclusion of their respective header files +#include "src/Core/util/MKL_support.h" + +// if alignment is disabled, then disable vectorization. Note: EIGEN_ALIGN is the proper check, it takes into +// account both the user's will (EIGEN_DONT_ALIGN) and our own platform checks +#if !EIGEN_ALIGN + #ifndef EIGEN_DONT_VECTORIZE + #define EIGEN_DONT_VECTORIZE + #endif +#endif + +#ifdef _MSC_VER + #include // for _aligned_malloc -- need it regardless of whether vectorization is enabled + #if (_MSC_VER >= 1500) // 2008 or later + // Remember that usage of defined() in a #define is undefined by the standard. + // a user reported that in 64-bit mode, MSVC doesn't care to define _M_IX86_FP. + #if (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || defined(_M_X64) + #define EIGEN_SSE2_ON_MSVC_2008_OR_LATER + #endif + #endif +#else + // Remember that usage of defined() in a #define is undefined by the standard + #if (defined __SSE2__) && ( (!defined __GNUC__) || (defined __INTEL_COMPILER) || EIGEN_GNUC_AT_LEAST(4,2) ) + #define EIGEN_SSE2_ON_NON_MSVC_BUT_NOT_OLD_GCC + #endif +#endif + +#ifndef EIGEN_DONT_VECTORIZE + + #if defined (EIGEN_SSE2_ON_NON_MSVC_BUT_NOT_OLD_GCC) || defined(EIGEN_SSE2_ON_MSVC_2008_OR_LATER) + + // Defines symbols for compile-time detection of which instructions are + // used. + // EIGEN_VECTORIZE_YY is defined if and only if the instruction set YY is used + #define EIGEN_VECTORIZE + #define EIGEN_VECTORIZE_SSE + #define EIGEN_VECTORIZE_SSE2 + + // Detect sse3/ssse3/sse4: + // gcc and icc defines __SSE3__, ... + // there is no way to know about this on msvc. You can define EIGEN_VECTORIZE_SSE* if you + // want to force the use of those instructions with msvc. + #ifdef __SSE3__ + #define EIGEN_VECTORIZE_SSE3 + #endif + #ifdef __SSSE3__ + #define EIGEN_VECTORIZE_SSSE3 + #endif + #ifdef __SSE4_1__ + #define EIGEN_VECTORIZE_SSE4_1 + #endif + #ifdef __SSE4_2__ + #define EIGEN_VECTORIZE_SSE4_2 + #endif + + // include files + + // This extern "C" works around a MINGW-w64 compilation issue + // https://sourceforge.net/tracker/index.php?func=detail&aid=3018394&group_id=202880&atid=983354 + // In essence, intrin.h is included by windows.h and also declares intrinsics (just as emmintrin.h etc. below do). + // However, intrin.h uses an extern "C" declaration, and g++ thus complains of duplicate declarations + // with conflicting linkage. The linkage for intrinsics doesn't matter, but at that stage the compiler doesn't know; + // so, to avoid compile errors when windows.h is included after Eigen/Core, ensure intrinsics are extern "C" here too. + // notice that since these are C headers, the extern "C" is theoretically needed anyways. + extern "C" { + // In theory we should only include immintrin.h and not the other *mmintrin.h header files directly. + // Doing so triggers some issues with ICC. However old gcc versions seems to not have this file, thus: + #if defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1110 + #include + #else + #include + #include + #ifdef EIGEN_VECTORIZE_SSE3 + #include + #endif + #ifdef EIGEN_VECTORIZE_SSSE3 + #include + #endif + #ifdef EIGEN_VECTORIZE_SSE4_1 + #include + #endif + #ifdef EIGEN_VECTORIZE_SSE4_2 + #include + #endif + #endif + } // end extern "C" + #elif defined __ALTIVEC__ + #define EIGEN_VECTORIZE + #define EIGEN_VECTORIZE_ALTIVEC + #include + // We need to #undef all these ugly tokens defined in + // => use __vector instead of vector + #undef bool + #undef vector + #undef pixel + #elif defined __ARM_NEON__ + #define EIGEN_VECTORIZE + #define EIGEN_VECTORIZE_NEON + #include + #endif +#endif + +#if (defined _OPENMP) && (!defined EIGEN_DONT_PARALLELIZE) + #define EIGEN_HAS_OPENMP +#endif + +#ifdef EIGEN_HAS_OPENMP +#include +#endif + +// MSVC for windows mobile does not have the errno.h file +#if !(defined(_MSC_VER) && defined(_WIN32_WCE)) && !defined(__ARMCC_VERSION) +#define EIGEN_HAS_ERRNO +#endif + +#ifdef EIGEN_HAS_ERRNO +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for CHAR_BIT +// for min/max: +#include + +// for outputting debug info +#ifdef EIGEN_DEBUG_ASSIGN +#include +#endif + +// required for __cpuid, needs to be included after cmath +#if defined(_MSC_VER) && (defined(_M_IX86)||defined(_M_X64)) && (!defined(_WIN32_WCE)) + #include +#endif + +#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) + #define EIGEN_EXCEPTIONS +#endif + +#ifdef EIGEN_EXCEPTIONS + #include +#endif + +/** \brief Namespace containing all symbols from the %Eigen library. */ +namespace Eigen { + +inline static const char *SimdInstructionSetsInUse(void) { +#if defined(EIGEN_VECTORIZE_SSE4_2) + return "SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2"; +#elif defined(EIGEN_VECTORIZE_SSE4_1) + return "SSE, SSE2, SSE3, SSSE3, SSE4.1"; +#elif defined(EIGEN_VECTORIZE_SSSE3) + return "SSE, SSE2, SSE3, SSSE3"; +#elif defined(EIGEN_VECTORIZE_SSE3) + return "SSE, SSE2, SSE3"; +#elif defined(EIGEN_VECTORIZE_SSE2) + return "SSE, SSE2"; +#elif defined(EIGEN_VECTORIZE_ALTIVEC) + return "AltiVec"; +#elif defined(EIGEN_VECTORIZE_NEON) + return "ARM NEON"; +#else + return "None"; +#endif +} + +} // end namespace Eigen + +#define STAGE10_FULL_EIGEN2_API 10 +#define STAGE20_RESOLVE_API_CONFLICTS 20 +#define STAGE30_FULL_EIGEN3_API 30 +#define STAGE40_FULL_EIGEN3_STRICTNESS 40 +#define STAGE99_NO_EIGEN2_SUPPORT 99 + +#if defined EIGEN2_SUPPORT_STAGE40_FULL_EIGEN3_STRICTNESS + #define EIGEN2_SUPPORT + #define EIGEN2_SUPPORT_STAGE STAGE40_FULL_EIGEN3_STRICTNESS +#elif defined EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API + #define EIGEN2_SUPPORT + #define EIGEN2_SUPPORT_STAGE STAGE30_FULL_EIGEN3_API +#elif defined EIGEN2_SUPPORT_STAGE20_RESOLVE_API_CONFLICTS + #define EIGEN2_SUPPORT + #define EIGEN2_SUPPORT_STAGE STAGE20_RESOLVE_API_CONFLICTS +#elif defined EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API + #define EIGEN2_SUPPORT + #define EIGEN2_SUPPORT_STAGE STAGE10_FULL_EIGEN2_API +#elif defined EIGEN2_SUPPORT + // default to stage 3, that's what it's always meant + #define EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API + #define EIGEN2_SUPPORT_STAGE STAGE30_FULL_EIGEN3_API +#else + #define EIGEN2_SUPPORT_STAGE STAGE99_NO_EIGEN2_SUPPORT +#endif + +#ifdef EIGEN2_SUPPORT +#undef minor +#endif + +// we use size_t frequently and we'll never remember to prepend it with std:: everytime just to +// ensure QNX/QCC support +using std::size_t; +// gcc 4.6.0 wants std:: for ptrdiff_t +using std::ptrdiff_t; + +/** \defgroup Core_Module Core module + * This is the main module of Eigen providing dense matrix and vector support + * (both fixed and dynamic size) with all the features corresponding to a BLAS library + * and much more... + * + * \code + * #include + * \endcode + */ + +#include "src/Core/util/Constants.h" +#include "src/Core/util/ForwardDeclarations.h" +#include "src/Core/util/Meta.h" +#include "src/Core/util/StaticAssert.h" +#include "src/Core/util/XprHelper.h" +#include "src/Core/util/Memory.h" + +#include "src/Core/NumTraits.h" +#include "src/Core/MathFunctions.h" +#include "src/Core/GenericPacketMath.h" + +#if defined EIGEN_VECTORIZE_SSE + #include "src/Core/arch/SSE/PacketMath.h" + #include "src/Core/arch/SSE/MathFunctions.h" + #include "src/Core/arch/SSE/Complex.h" +#elif defined EIGEN_VECTORIZE_ALTIVEC + #include "src/Core/arch/AltiVec/PacketMath.h" + #include "src/Core/arch/AltiVec/Complex.h" +#elif defined EIGEN_VECTORIZE_NEON + #include "src/Core/arch/NEON/PacketMath.h" + #include "src/Core/arch/NEON/Complex.h" +#endif + +#include "src/Core/arch/Default/Settings.h" + +#include "src/Core/Functors.h" +#include "src/Core/DenseCoeffsBase.h" +#include "src/Core/DenseBase.h" +#include "src/Core/MatrixBase.h" +#include "src/Core/EigenBase.h" + +#ifndef EIGEN_PARSED_BY_DOXYGEN // work around Doxygen bug triggered by Assign.h r814874 + // at least confirmed with Doxygen 1.5.5 and 1.5.6 + #include "src/Core/Assign.h" +#endif + +#include "src/Core/util/BlasUtil.h" +#include "src/Core/DenseStorage.h" +#include "src/Core/NestByValue.h" +#include "src/Core/ForceAlignedAccess.h" +#include "src/Core/ReturnByValue.h" +#include "src/Core/NoAlias.h" +#include "src/Core/PlainObjectBase.h" +#include "src/Core/Matrix.h" +#include "src/Core/Array.h" +#include "src/Core/CwiseBinaryOp.h" +#include "src/Core/CwiseUnaryOp.h" +#include "src/Core/CwiseNullaryOp.h" +#include "src/Core/CwiseUnaryView.h" +#include "src/Core/SelfCwiseBinaryOp.h" +#include "src/Core/Dot.h" +#include "src/Core/StableNorm.h" +#include "src/Core/MapBase.h" +#include "src/Core/Stride.h" +#include "src/Core/Map.h" +#include "src/Core/Block.h" +#include "src/Core/VectorBlock.h" +#include "src/Core/Ref.h" +#include "src/Core/Transpose.h" +#include "src/Core/DiagonalMatrix.h" +#include "src/Core/Diagonal.h" +#include "src/Core/DiagonalProduct.h" +#include "src/Core/PermutationMatrix.h" +#include "src/Core/Transpositions.h" +#include "src/Core/Redux.h" +#include "src/Core/Visitor.h" +#include "src/Core/Fuzzy.h" +#include "src/Core/IO.h" +#include "src/Core/Swap.h" +#include "src/Core/CommaInitializer.h" +#include "src/Core/Flagged.h" +#include "src/Core/ProductBase.h" +#include "src/Core/GeneralProduct.h" +#include "src/Core/TriangularMatrix.h" +#include "src/Core/SelfAdjointView.h" +#include "src/Core/products/GeneralBlockPanelKernel.h" +#include "src/Core/products/Parallelizer.h" +#include "src/Core/products/CoeffBasedProduct.h" +#include "src/Core/products/GeneralMatrixVector.h" +#include "src/Core/products/GeneralMatrixMatrix.h" +#include "src/Core/SolveTriangular.h" +#include "src/Core/products/GeneralMatrixMatrixTriangular.h" +#include "src/Core/products/SelfadjointMatrixVector.h" +#include "src/Core/products/SelfadjointMatrixMatrix.h" +#include "src/Core/products/SelfadjointProduct.h" +#include "src/Core/products/SelfadjointRank2Update.h" +#include "src/Core/products/TriangularMatrixVector.h" +#include "src/Core/products/TriangularMatrixMatrix.h" +#include "src/Core/products/TriangularSolverMatrix.h" +#include "src/Core/products/TriangularSolverVector.h" +#include "src/Core/BandMatrix.h" +#include "src/Core/CoreIterators.h" + +#include "src/Core/BooleanRedux.h" +#include "src/Core/Select.h" +#include "src/Core/VectorwiseOp.h" +#include "src/Core/Random.h" +#include "src/Core/Replicate.h" +#include "src/Core/Reverse.h" +#include "src/Core/ArrayBase.h" +#include "src/Core/ArrayWrapper.h" + +#ifdef EIGEN_USE_BLAS +#include "src/Core/products/GeneralMatrixMatrix_MKL.h" +#include "src/Core/products/GeneralMatrixVector_MKL.h" +#include "src/Core/products/GeneralMatrixMatrixTriangular_MKL.h" +#include "src/Core/products/SelfadjointMatrixMatrix_MKL.h" +#include "src/Core/products/SelfadjointMatrixVector_MKL.h" +#include "src/Core/products/TriangularMatrixMatrix_MKL.h" +#include "src/Core/products/TriangularMatrixVector_MKL.h" +#include "src/Core/products/TriangularSolverMatrix_MKL.h" +#endif // EIGEN_USE_BLAS + +#ifdef EIGEN_USE_MKL_VML +#include "src/Core/Assign_MKL.h" +#endif + +#include "src/Core/GlobalFunctions.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#ifdef EIGEN2_SUPPORT +#include "Eigen2Support" +#endif + +#endif // EIGEN_CORE_H diff --git a/libs/eigen3/Eigen/SparseCore b/libs/eigen3/Eigen/SparseCore new file mode 100644 index 000000000..9b5be5e15 --- /dev/null +++ b/libs/eigen3/Eigen/SparseCore @@ -0,0 +1,64 @@ +#ifndef EIGEN_SPARSECORE_MODULE_H +#define EIGEN_SPARSECORE_MODULE_H + +#include "Core" + +#include "src/Core/util/DisableStupidWarnings.h" + +#include +#include +#include +#include +#include + +/** + * \defgroup SparseCore_Module SparseCore module + * + * This module provides a sparse matrix representation, and basic associatd matrix manipulations + * and operations. + * + * See the \ref TutorialSparse "Sparse tutorial" + * + * \code + * #include + * \endcode + * + * This module depends on: Core. + */ + +namespace Eigen { + +/** The type used to identify a general sparse storage. */ +struct Sparse {}; + +} + +#include "src/SparseCore/SparseUtil.h" +#include "src/SparseCore/SparseMatrixBase.h" +#include "src/SparseCore/CompressedStorage.h" +#include "src/SparseCore/AmbiVector.h" +#include "src/SparseCore/SparseMatrix.h" +#include "src/SparseCore/MappedSparseMatrix.h" +#include "src/SparseCore/SparseVector.h" +#include "src/SparseCore/SparseBlock.h" +#include "src/SparseCore/SparseTranspose.h" +#include "src/SparseCore/SparseCwiseUnaryOp.h" +#include "src/SparseCore/SparseCwiseBinaryOp.h" +#include "src/SparseCore/SparseDot.h" +#include "src/SparseCore/SparsePermutation.h" +#include "src/SparseCore/SparseRedux.h" +#include "src/SparseCore/SparseFuzzy.h" +#include "src/SparseCore/ConservativeSparseSparseProduct.h" +#include "src/SparseCore/SparseSparseProductWithPruning.h" +#include "src/SparseCore/SparseProduct.h" +#include "src/SparseCore/SparseDenseProduct.h" +#include "src/SparseCore/SparseDiagonalProduct.h" +#include "src/SparseCore/SparseTriangularView.h" +#include "src/SparseCore/SparseSelfAdjointView.h" +#include "src/SparseCore/TriangularSolver.h" +#include "src/SparseCore/SparseView.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_SPARSECORE_MODULE_H + diff --git a/libs/eigen3/Eigen/src/Core/Array.h b/libs/eigen3/Eigen/src/Core/Array.h new file mode 100644 index 000000000..0ab03eff0 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/Array.h @@ -0,0 +1,308 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_ARRAY_H +#define EIGEN_ARRAY_H + +namespace Eigen { + +/** \class Array + * \ingroup Core_Module + * + * \brief General-purpose arrays with easy API for coefficient-wise operations + * + * The %Array class is very similar to the Matrix class. It provides + * general-purpose one- and two-dimensional arrays. The difference between the + * %Array and the %Matrix class is primarily in the API: the API for the + * %Array class provides easy access to coefficient-wise operations, while the + * API for the %Matrix class provides easy access to linear-algebra + * operations. + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_ARRAY_PLUGIN. + * + * \sa \ref TutorialArrayClass, \ref TopicClassHierarchy + */ +namespace internal { +template +struct traits > : traits > +{ + typedef ArrayXpr XprKind; + typedef ArrayBase > XprBase; +}; +} + +template +class Array + : public PlainObjectBase > +{ + public: + + typedef PlainObjectBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Array) + + enum { Options = _Options }; + typedef typename Base::PlainObject PlainObject; + + protected: + template + friend struct internal::conservative_resize_like_impl; + + using Base::m_storage; + + public: + + using Base::base; + using Base::coeff; + using Base::coeffRef; + + /** + * The usage of + * using Base::operator=; + * fails on MSVC. Since the code below is working with GCC and MSVC, we skipped + * the usage of 'using'. This should be done only for operator=. + */ + template + EIGEN_STRONG_INLINE Array& operator=(const EigenBase &other) + { + return Base::operator=(other); + } + + /** Copies the value of the expression \a other into \c *this with automatic resizing. + * + * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), + * it will be initialized. + * + * Note that copying a row-vector into a vector (and conversely) is allowed. + * The resizing, if any, is then done in the appropriate way so that row-vectors + * remain row-vectors and vectors remain vectors. + */ + template + EIGEN_STRONG_INLINE Array& operator=(const ArrayBase& other) + { + return Base::_set(other); + } + + /** This is a special case of the templated operator=. Its purpose is to + * prevent a default operator= from hiding the templated operator=. + */ + EIGEN_STRONG_INLINE Array& operator=(const Array& other) + { + return Base::_set(other); + } + + /** Default constructor. + * + * For fixed-size matrices, does nothing. + * + * For dynamic-size matrices, creates an empty matrix of size 0. Does not allocate any array. Such a matrix + * is called a null matrix. This constructor is the unique way to create null matrices: resizing + * a matrix to 0 is not supported. + * + * \sa resize(Index,Index) + */ + EIGEN_STRONG_INLINE Array() : Base() + { + Base::_check_template_params(); + EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + } + +#ifndef EIGEN_PARSED_BY_DOXYGEN + // FIXME is it still needed ?? + /** \internal */ + Array(internal::constructor_without_unaligned_array_assert) + : Base(internal::constructor_without_unaligned_array_assert()) + { + Base::_check_template_params(); + EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + } +#endif + + /** Constructs a vector or row-vector with given dimension. \only_for_vectors + * + * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, + * it is redundant to pass the dimension here, so it makes more sense to use the default + * constructor Matrix() instead. + */ + EIGEN_STRONG_INLINE explicit Array(Index dim) + : Base(dim, RowsAtCompileTime == 1 ? 1 : dim, ColsAtCompileTime == 1 ? 1 : dim) + { + Base::_check_template_params(); + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Array) + eigen_assert(dim >= 0); + eigen_assert(SizeAtCompileTime == Dynamic || SizeAtCompileTime == dim); + EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_STRONG_INLINE Array(const T0& val0, const T1& val1) + { + Base::_check_template_params(); + this->template _init2(val0, val1); + } + #else + /** constructs an uninitialized matrix with \a rows rows and \a cols columns. + * + * This is useful for dynamic-size matrices. For fixed-size matrices, + * it is redundant to pass these parameters, so one should use the default constructor + * Matrix() instead. */ + Array(Index rows, Index cols); + /** constructs an initialized 2D vector with given coefficients */ + Array(const Scalar& val0, const Scalar& val1); + #endif + + /** constructs an initialized 3D vector with given coefficients */ + EIGEN_STRONG_INLINE Array(const Scalar& val0, const Scalar& val1, const Scalar& val2) + { + Base::_check_template_params(); + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Array, 3) + m_storage.data()[0] = val0; + m_storage.data()[1] = val1; + m_storage.data()[2] = val2; + } + /** constructs an initialized 4D vector with given coefficients */ + EIGEN_STRONG_INLINE Array(const Scalar& val0, const Scalar& val1, const Scalar& val2, const Scalar& val3) + { + Base::_check_template_params(); + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Array, 4) + m_storage.data()[0] = val0; + m_storage.data()[1] = val1; + m_storage.data()[2] = val2; + m_storage.data()[3] = val3; + } + + explicit Array(const Scalar *data); + + /** Constructor copying the value of the expression \a other */ + template + EIGEN_STRONG_INLINE Array(const ArrayBase& other) + : Base(other.rows() * other.cols(), other.rows(), other.cols()) + { + Base::_check_template_params(); + Base::_set_noalias(other); + } + /** Copy constructor */ + EIGEN_STRONG_INLINE Array(const Array& other) + : Base(other.rows() * other.cols(), other.rows(), other.cols()) + { + Base::_check_template_params(); + Base::_set_noalias(other); + } + /** Copy constructor with in-place evaluation */ + template + EIGEN_STRONG_INLINE Array(const ReturnByValue& other) + { + Base::_check_template_params(); + Base::resize(other.rows(), other.cols()); + other.evalTo(*this); + } + + /** \sa MatrixBase::operator=(const EigenBase&) */ + template + EIGEN_STRONG_INLINE Array(const EigenBase &other) + : Base(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) + { + Base::_check_template_params(); + Base::_resize_to_match(other); + *this = other; + } + + /** Override MatrixBase::swap() since for dynamic-sized matrices of same type it is enough to swap the + * data pointers. + */ + template + void swap(ArrayBase const & other) + { this->_swap(other.derived()); } + + inline Index innerStride() const { return 1; } + inline Index outerStride() const { return this->innerSize(); } + + #ifdef EIGEN_ARRAY_PLUGIN + #include EIGEN_ARRAY_PLUGIN + #endif + + private: + + template + friend struct internal::matrix_swap_impl; +}; + +/** \defgroup arraytypedefs Global array typedefs + * \ingroup Core_Module + * + * Eigen defines several typedef shortcuts for most common 1D and 2D array types. + * + * The general patterns are the following: + * + * \c ArrayRowsColsType where \c Rows and \c Cols can be \c 2,\c 3,\c 4 for fixed size square matrices or \c X for dynamic size, + * and where \c Type can be \c i for integer, \c f for float, \c d for double, \c cf for complex float, \c cd + * for complex double. + * + * For example, \c Array33d is a fixed-size 3x3 array type of doubles, and \c ArrayXXf is a dynamic-size matrix of floats. + * + * There are also \c ArraySizeType which are self-explanatory. For example, \c Array4cf is + * a fixed-size 1D array of 4 complex floats. + * + * \sa class Array + */ + +#define EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix) \ +/** \ingroup arraytypedefs */ \ +typedef Array Array##SizeSuffix##SizeSuffix##TypeSuffix; \ +/** \ingroup arraytypedefs */ \ +typedef Array Array##SizeSuffix##TypeSuffix; + +#define EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, Size) \ +/** \ingroup arraytypedefs */ \ +typedef Array Array##Size##X##TypeSuffix; \ +/** \ingroup arraytypedefs */ \ +typedef Array Array##X##Size##TypeSuffix; + +#define EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \ +EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 2, 2) \ +EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 3, 3) \ +EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 4, 4) \ +EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, Dynamic, X) \ +EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 2) \ +EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 3) \ +EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 4) + +EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(int, i) +EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(float, f) +EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(double, d) +EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(std::complex, cf) +EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(std::complex, cd) + +#undef EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES +#undef EIGEN_MAKE_ARRAY_TYPEDEFS + +#undef EIGEN_MAKE_ARRAY_TYPEDEFS_LARGE + +#define EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, SizeSuffix) \ +using Eigen::Matrix##SizeSuffix##TypeSuffix; \ +using Eigen::Vector##SizeSuffix##TypeSuffix; \ +using Eigen::RowVector##SizeSuffix##TypeSuffix; + +#define EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(TypeSuffix) \ +EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 2) \ +EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 3) \ +EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 4) \ +EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, X) \ + +#define EIGEN_USING_ARRAY_TYPEDEFS \ +EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(i) \ +EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(f) \ +EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(d) \ +EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(cf) \ +EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(cd) + +} // end namespace Eigen + +#endif // EIGEN_ARRAY_H diff --git a/libs/eigen3/Eigen/src/Core/ArrayBase.h b/libs/eigen3/Eigen/src/Core/ArrayBase.h new file mode 100644 index 000000000..38852600d --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/ArrayBase.h @@ -0,0 +1,228 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_ARRAYBASE_H +#define EIGEN_ARRAYBASE_H + +namespace Eigen { + +template class MatrixWrapper; + +/** \class ArrayBase + * \ingroup Core_Module + * + * \brief Base class for all 1D and 2D array, and related expressions + * + * An array is similar to a dense vector or matrix. While matrices are mathematical + * objects with well defined linear algebra operators, an array is just a collection + * of scalar values arranged in a one or two dimensionnal fashion. As the main consequence, + * all operations applied to an array are performed coefficient wise. Furthermore, + * arrays support scalar math functions of the c++ standard library (e.g., std::sin(x)), and convenient + * constructors allowing to easily write generic code working for both scalar values + * and arrays. + * + * This class is the base that is inherited by all array expression types. + * + * \tparam Derived is the derived type, e.g., an array or an expression type. + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_ARRAYBASE_PLUGIN. + * + * \sa class MatrixBase, \ref TopicClassHierarchy + */ +template class ArrayBase + : public DenseBase +{ + public: +#ifndef EIGEN_PARSED_BY_DOXYGEN + /** The base class for a given storage type. */ + typedef ArrayBase StorageBaseType; + + typedef ArrayBase Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl; + + using internal::special_scalar_op_base::Scalar, + typename NumTraits::Scalar>::Real>::operator*; + + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::packet_traits::type PacketScalar; + typedef typename NumTraits::Real RealScalar; + + typedef DenseBase Base; + using Base::RowsAtCompileTime; + using Base::ColsAtCompileTime; + using Base::SizeAtCompileTime; + using Base::MaxRowsAtCompileTime; + using Base::MaxColsAtCompileTime; + using Base::MaxSizeAtCompileTime; + using Base::IsVectorAtCompileTime; + using Base::Flags; + using Base::CoeffReadCost; + + using Base::derived; + using Base::const_cast_derived; + using Base::rows; + using Base::cols; + using Base::size; + using Base::coeff; + using Base::coeffRef; + using Base::lazyAssign; + using Base::operator=; + using Base::operator+=; + using Base::operator-=; + using Base::operator*=; + using Base::operator/=; + + typedef typename Base::CoeffReturnType CoeffReturnType; + +#endif // not EIGEN_PARSED_BY_DOXYGEN + +#ifndef EIGEN_PARSED_BY_DOXYGEN + /** \internal the plain matrix type corresponding to this expression. Note that is not necessarily + * exactly the return type of eval(): in the case of plain matrices, the return type of eval() is a const + * reference to a matrix, not a matrix! It is however guaranteed that the return type of eval() is either + * PlainObject or const PlainObject&. + */ + typedef Array::Scalar, + internal::traits::RowsAtCompileTime, + internal::traits::ColsAtCompileTime, + AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), + internal::traits::MaxRowsAtCompileTime, + internal::traits::MaxColsAtCompileTime + > PlainObject; + + + /** \internal Represents a matrix with all coefficients equal to one another*/ + typedef CwiseNullaryOp,Derived> ConstantReturnType; +#endif // not EIGEN_PARSED_BY_DOXYGEN + +#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::ArrayBase +# include "../plugins/CommonCwiseUnaryOps.h" +# include "../plugins/MatrixCwiseUnaryOps.h" +# include "../plugins/ArrayCwiseUnaryOps.h" +# include "../plugins/CommonCwiseBinaryOps.h" +# include "../plugins/MatrixCwiseBinaryOps.h" +# include "../plugins/ArrayCwiseBinaryOps.h" +# ifdef EIGEN_ARRAYBASE_PLUGIN +# include EIGEN_ARRAYBASE_PLUGIN +# endif +#undef EIGEN_CURRENT_STORAGE_BASE_CLASS + + /** Special case of the template operator=, in order to prevent the compiler + * from generating a default operator= (issue hit with g++ 4.1) + */ + Derived& operator=(const ArrayBase& other) + { + return internal::assign_selector::run(derived(), other.derived()); + } + + Derived& operator+=(const Scalar& scalar) + { return *this = derived() + scalar; } + Derived& operator-=(const Scalar& scalar) + { return *this = derived() - scalar; } + + template + Derived& operator+=(const ArrayBase& other); + template + Derived& operator-=(const ArrayBase& other); + + template + Derived& operator*=(const ArrayBase& other); + + template + Derived& operator/=(const ArrayBase& other); + + public: + ArrayBase& array() { return *this; } + const ArrayBase& array() const { return *this; } + + /** \returns an \link Eigen::MatrixBase Matrix \endlink expression of this array + * \sa MatrixBase::array() */ + MatrixWrapper matrix() { return derived(); } + const MatrixWrapper matrix() const { return derived(); } + +// template +// inline void evalTo(Dest& dst) const { dst = matrix(); } + + protected: + ArrayBase() : Base() {} + + private: + explicit ArrayBase(Index); + ArrayBase(Index,Index); + template explicit ArrayBase(const ArrayBase&); + protected: + // mixing arrays and matrices is not legal + template Derived& operator+=(const MatrixBase& ) + {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} + // mixing arrays and matrices is not legal + template Derived& operator-=(const MatrixBase& ) + {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} +}; + +/** replaces \c *this by \c *this - \a other. + * + * \returns a reference to \c *this + */ +template +template +EIGEN_STRONG_INLINE Derived & +ArrayBase::operator-=(const ArrayBase &other) +{ + SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); + tmp = other.derived(); + return derived(); +} + +/** replaces \c *this by \c *this + \a other. + * + * \returns a reference to \c *this + */ +template +template +EIGEN_STRONG_INLINE Derived & +ArrayBase::operator+=(const ArrayBase& other) +{ + SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); + tmp = other.derived(); + return derived(); +} + +/** replaces \c *this by \c *this * \a other coefficient wise. + * + * \returns a reference to \c *this + */ +template +template +EIGEN_STRONG_INLINE Derived & +ArrayBase::operator*=(const ArrayBase& other) +{ + SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); + tmp = other.derived(); + return derived(); +} + +/** replaces \c *this by \c *this / \a other coefficient wise. + * + * \returns a reference to \c *this + */ +template +template +EIGEN_STRONG_INLINE Derived & +ArrayBase::operator/=(const ArrayBase& other) +{ + SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); + tmp = other.derived(); + return derived(); +} + +} // end namespace Eigen + +#endif // EIGEN_ARRAYBASE_H diff --git a/libs/eigen3/Eigen/src/Core/ArrayWrapper.h b/libs/eigen3/Eigen/src/Core/ArrayWrapper.h new file mode 100644 index 000000000..a791bc358 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/ArrayWrapper.h @@ -0,0 +1,254 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_ARRAYWRAPPER_H +#define EIGEN_ARRAYWRAPPER_H + +namespace Eigen { + +/** \class ArrayWrapper + * \ingroup Core_Module + * + * \brief Expression of a mathematical vector or matrix as an array object + * + * This class is the return type of MatrixBase::array(), and most of the time + * this is the only way it is use. + * + * \sa MatrixBase::array(), class MatrixWrapper + */ + +namespace internal { +template +struct traits > + : public traits::type > +{ + typedef ArrayXpr XprKind; +}; +} + +template +class ArrayWrapper : public ArrayBase > +{ + public: + typedef ArrayBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(ArrayWrapper) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ArrayWrapper) + + typedef typename internal::conditional< + internal::is_lvalue::value, + Scalar, + const Scalar + >::type ScalarWithConstIfNotLvalue; + + typedef typename internal::nested::type NestedExpressionType; + + inline ArrayWrapper(ExpressionType& matrix) : m_expression(matrix) {} + + inline Index rows() const { return m_expression.rows(); } + inline Index cols() const { return m_expression.cols(); } + inline Index outerStride() const { return m_expression.outerStride(); } + inline Index innerStride() const { return m_expression.innerStride(); } + + inline ScalarWithConstIfNotLvalue* data() { return m_expression.const_cast_derived().data(); } + inline const Scalar* data() const { return m_expression.data(); } + + inline CoeffReturnType coeff(Index rowId, Index colId) const + { + return m_expression.coeff(rowId, colId); + } + + inline Scalar& coeffRef(Index rowId, Index colId) + { + return m_expression.const_cast_derived().coeffRef(rowId, colId); + } + + inline const Scalar& coeffRef(Index rowId, Index colId) const + { + return m_expression.const_cast_derived().coeffRef(rowId, colId); + } + + inline CoeffReturnType coeff(Index index) const + { + return m_expression.coeff(index); + } + + inline Scalar& coeffRef(Index index) + { + return m_expression.const_cast_derived().coeffRef(index); + } + + inline const Scalar& coeffRef(Index index) const + { + return m_expression.const_cast_derived().coeffRef(index); + } + + template + inline const PacketScalar packet(Index rowId, Index colId) const + { + return m_expression.template packet(rowId, colId); + } + + template + inline void writePacket(Index rowId, Index colId, const PacketScalar& val) + { + m_expression.const_cast_derived().template writePacket(rowId, colId, val); + } + + template + inline const PacketScalar packet(Index index) const + { + return m_expression.template packet(index); + } + + template + inline void writePacket(Index index, const PacketScalar& val) + { + m_expression.const_cast_derived().template writePacket(index, val); + } + + template + inline void evalTo(Dest& dst) const { dst = m_expression; } + + const typename internal::remove_all::type& + nestedExpression() const + { + return m_expression; + } + + /** Forwards the resizing request to the nested expression + * \sa DenseBase::resize(Index) */ + void resize(Index newSize) { m_expression.const_cast_derived().resize(newSize); } + /** Forwards the resizing request to the nested expression + * \sa DenseBase::resize(Index,Index)*/ + void resize(Index nbRows, Index nbCols) { m_expression.const_cast_derived().resize(nbRows,nbCols); } + + protected: + NestedExpressionType m_expression; +}; + +/** \class MatrixWrapper + * \ingroup Core_Module + * + * \brief Expression of an array as a mathematical vector or matrix + * + * This class is the return type of ArrayBase::matrix(), and most of the time + * this is the only way it is use. + * + * \sa MatrixBase::matrix(), class ArrayWrapper + */ + +namespace internal { +template +struct traits > + : public traits::type > +{ + typedef MatrixXpr XprKind; +}; +} + +template +class MatrixWrapper : public MatrixBase > +{ + public: + typedef MatrixBase > Base; + EIGEN_DENSE_PUBLIC_INTERFACE(MatrixWrapper) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(MatrixWrapper) + + typedef typename internal::conditional< + internal::is_lvalue::value, + Scalar, + const Scalar + >::type ScalarWithConstIfNotLvalue; + + typedef typename internal::nested::type NestedExpressionType; + + inline MatrixWrapper(ExpressionType& a_matrix) : m_expression(a_matrix) {} + + inline Index rows() const { return m_expression.rows(); } + inline Index cols() const { return m_expression.cols(); } + inline Index outerStride() const { return m_expression.outerStride(); } + inline Index innerStride() const { return m_expression.innerStride(); } + + inline ScalarWithConstIfNotLvalue* data() { return m_expression.const_cast_derived().data(); } + inline const Scalar* data() const { return m_expression.data(); } + + inline CoeffReturnType coeff(Index rowId, Index colId) const + { + return m_expression.coeff(rowId, colId); + } + + inline Scalar& coeffRef(Index rowId, Index colId) + { + return m_expression.const_cast_derived().coeffRef(rowId, colId); + } + + inline const Scalar& coeffRef(Index rowId, Index colId) const + { + return m_expression.derived().coeffRef(rowId, colId); + } + + inline CoeffReturnType coeff(Index index) const + { + return m_expression.coeff(index); + } + + inline Scalar& coeffRef(Index index) + { + return m_expression.const_cast_derived().coeffRef(index); + } + + inline const Scalar& coeffRef(Index index) const + { + return m_expression.const_cast_derived().coeffRef(index); + } + + template + inline const PacketScalar packet(Index rowId, Index colId) const + { + return m_expression.template packet(rowId, colId); + } + + template + inline void writePacket(Index rowId, Index colId, const PacketScalar& val) + { + m_expression.const_cast_derived().template writePacket(rowId, colId, val); + } + + template + inline const PacketScalar packet(Index index) const + { + return m_expression.template packet(index); + } + + template + inline void writePacket(Index index, const PacketScalar& val) + { + m_expression.const_cast_derived().template writePacket(index, val); + } + + const typename internal::remove_all::type& + nestedExpression() const + { + return m_expression; + } + + /** Forwards the resizing request to the nested expression + * \sa DenseBase::resize(Index) */ + void resize(Index newSize) { m_expression.const_cast_derived().resize(newSize); } + /** Forwards the resizing request to the nested expression + * \sa DenseBase::resize(Index,Index)*/ + void resize(Index nbRows, Index nbCols) { m_expression.const_cast_derived().resize(nbRows,nbCols); } + + protected: + NestedExpressionType m_expression; +}; + +} // end namespace Eigen + +#endif // EIGEN_ARRAYWRAPPER_H diff --git a/libs/eigen3/Eigen/src/Core/Assign.h b/libs/eigen3/Eigen/src/Core/Assign.h new file mode 100644 index 000000000..1dccc2f42 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/Assign.h @@ -0,0 +1,583 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2007 Michael Olbrich +// Copyright (C) 2006-2010 Benoit Jacob +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_ASSIGN_H +#define EIGEN_ASSIGN_H + +namespace Eigen { + +namespace internal { + +/*************************************************************************** +* Part 1 : the logic deciding a strategy for traversal and unrolling * +***************************************************************************/ + +template +struct assign_traits +{ +public: + enum { + DstIsAligned = Derived::Flags & AlignedBit, + DstHasDirectAccess = Derived::Flags & DirectAccessBit, + SrcIsAligned = OtherDerived::Flags & AlignedBit, + JointAlignment = bool(DstIsAligned) && bool(SrcIsAligned) ? Aligned : Unaligned + }; + +private: + enum { + InnerSize = int(Derived::IsVectorAtCompileTime) ? int(Derived::SizeAtCompileTime) + : int(Derived::Flags)&RowMajorBit ? int(Derived::ColsAtCompileTime) + : int(Derived::RowsAtCompileTime), + InnerMaxSize = int(Derived::IsVectorAtCompileTime) ? int(Derived::MaxSizeAtCompileTime) + : int(Derived::Flags)&RowMajorBit ? int(Derived::MaxColsAtCompileTime) + : int(Derived::MaxRowsAtCompileTime), + MaxSizeAtCompileTime = Derived::SizeAtCompileTime, + PacketSize = packet_traits::size + }; + + enum { + StorageOrdersAgree = (int(Derived::IsRowMajor) == int(OtherDerived::IsRowMajor)), + MightVectorize = StorageOrdersAgree + && (int(Derived::Flags) & int(OtherDerived::Flags) & ActualPacketAccessBit), + MayInnerVectorize = MightVectorize && int(InnerSize)!=Dynamic && int(InnerSize)%int(PacketSize)==0 + && int(DstIsAligned) && int(SrcIsAligned), + MayLinearize = StorageOrdersAgree && (int(Derived::Flags) & int(OtherDerived::Flags) & LinearAccessBit), + MayLinearVectorize = MightVectorize && MayLinearize && DstHasDirectAccess + && (DstIsAligned || MaxSizeAtCompileTime == Dynamic), + /* If the destination isn't aligned, we have to do runtime checks and we don't unroll, + so it's only good for large enough sizes. */ + MaySliceVectorize = MightVectorize && DstHasDirectAccess + && (int(InnerMaxSize)==Dynamic || int(InnerMaxSize)>=3*PacketSize) + /* slice vectorization can be slow, so we only want it if the slices are big, which is + indicated by InnerMaxSize rather than InnerSize, think of the case of a dynamic block + in a fixed-size matrix */ + }; + +public: + enum { + Traversal = int(MayInnerVectorize) ? int(InnerVectorizedTraversal) + : int(MayLinearVectorize) ? int(LinearVectorizedTraversal) + : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) + : int(MayLinearize) ? int(LinearTraversal) + : int(DefaultTraversal), + Vectorized = int(Traversal) == InnerVectorizedTraversal + || int(Traversal) == LinearVectorizedTraversal + || int(Traversal) == SliceVectorizedTraversal + }; + +private: + enum { + UnrollingLimit = EIGEN_UNROLLING_LIMIT * (Vectorized ? int(PacketSize) : 1), + MayUnrollCompletely = int(Derived::SizeAtCompileTime) != Dynamic + && int(OtherDerived::CoeffReadCost) != Dynamic + && int(Derived::SizeAtCompileTime) * int(OtherDerived::CoeffReadCost) <= int(UnrollingLimit), + MayUnrollInner = int(InnerSize) != Dynamic + && int(OtherDerived::CoeffReadCost) != Dynamic + && int(InnerSize) * int(OtherDerived::CoeffReadCost) <= int(UnrollingLimit) + }; + +public: + enum { + Unrolling = (int(Traversal) == int(InnerVectorizedTraversal) || int(Traversal) == int(DefaultTraversal)) + ? ( + int(MayUnrollCompletely) ? int(CompleteUnrolling) + : int(MayUnrollInner) ? int(InnerUnrolling) + : int(NoUnrolling) + ) + : int(Traversal) == int(LinearVectorizedTraversal) + ? ( bool(MayUnrollCompletely) && bool(DstIsAligned) ? int(CompleteUnrolling) : int(NoUnrolling) ) + : int(Traversal) == int(LinearTraversal) + ? ( bool(MayUnrollCompletely) ? int(CompleteUnrolling) : int(NoUnrolling) ) + : int(NoUnrolling) + }; + +#ifdef EIGEN_DEBUG_ASSIGN + static void debug() + { + EIGEN_DEBUG_VAR(DstIsAligned) + EIGEN_DEBUG_VAR(SrcIsAligned) + EIGEN_DEBUG_VAR(JointAlignment) + EIGEN_DEBUG_VAR(InnerSize) + EIGEN_DEBUG_VAR(InnerMaxSize) + EIGEN_DEBUG_VAR(PacketSize) + EIGEN_DEBUG_VAR(StorageOrdersAgree) + EIGEN_DEBUG_VAR(MightVectorize) + EIGEN_DEBUG_VAR(MayLinearize) + EIGEN_DEBUG_VAR(MayInnerVectorize) + EIGEN_DEBUG_VAR(MayLinearVectorize) + EIGEN_DEBUG_VAR(MaySliceVectorize) + EIGEN_DEBUG_VAR(Traversal) + EIGEN_DEBUG_VAR(UnrollingLimit) + EIGEN_DEBUG_VAR(MayUnrollCompletely) + EIGEN_DEBUG_VAR(MayUnrollInner) + EIGEN_DEBUG_VAR(Unrolling) + } +#endif +}; + +/*************************************************************************** +* Part 2 : meta-unrollers +***************************************************************************/ + +/************************ +*** Default traversal *** +************************/ + +template +struct assign_DefaultTraversal_CompleteUnrolling +{ + enum { + outer = Index / Derived1::InnerSizeAtCompileTime, + inner = Index % Derived1::InnerSizeAtCompileTime + }; + + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) + { + dst.copyCoeffByOuterInner(outer, inner, src); + assign_DefaultTraversal_CompleteUnrolling::run(dst, src); + } +}; + +template +struct assign_DefaultTraversal_CompleteUnrolling +{ + static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} +}; + +template +struct assign_DefaultTraversal_InnerUnrolling +{ + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src, typename Derived1::Index outer) + { + dst.copyCoeffByOuterInner(outer, Index, src); + assign_DefaultTraversal_InnerUnrolling::run(dst, src, outer); + } +}; + +template +struct assign_DefaultTraversal_InnerUnrolling +{ + static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &, typename Derived1::Index) {} +}; + +/*********************** +*** Linear traversal *** +***********************/ + +template +struct assign_LinearTraversal_CompleteUnrolling +{ + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) + { + dst.copyCoeff(Index, src); + assign_LinearTraversal_CompleteUnrolling::run(dst, src); + } +}; + +template +struct assign_LinearTraversal_CompleteUnrolling +{ + static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} +}; + +/************************** +*** Inner vectorization *** +**************************/ + +template +struct assign_innervec_CompleteUnrolling +{ + enum { + outer = Index / Derived1::InnerSizeAtCompileTime, + inner = Index % Derived1::InnerSizeAtCompileTime, + JointAlignment = assign_traits::JointAlignment + }; + + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) + { + dst.template copyPacketByOuterInner(outer, inner, src); + assign_innervec_CompleteUnrolling::size, Stop>::run(dst, src); + } +}; + +template +struct assign_innervec_CompleteUnrolling +{ + static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} +}; + +template +struct assign_innervec_InnerUnrolling +{ + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src, typename Derived1::Index outer) + { + dst.template copyPacketByOuterInner(outer, Index, src); + assign_innervec_InnerUnrolling::size, Stop>::run(dst, src, outer); + } +}; + +template +struct assign_innervec_InnerUnrolling +{ + static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &, typename Derived1::Index) {} +}; + +/*************************************************************************** +* Part 3 : implementation of all cases +***************************************************************************/ + +template::Traversal, + int Unrolling = assign_traits::Unrolling, + int Version = Specialized> +struct assign_impl; + +/************************ +*** Default traversal *** +************************/ + +template +struct assign_impl +{ + static inline void run(Derived1 &, const Derived2 &) { } +}; + +template +struct assign_impl +{ + typedef typename Derived1::Index Index; + static inline void run(Derived1 &dst, const Derived2 &src) + { + const Index innerSize = dst.innerSize(); + const Index outerSize = dst.outerSize(); + for(Index outer = 0; outer < outerSize; ++outer) + for(Index inner = 0; inner < innerSize; ++inner) + dst.copyCoeffByOuterInner(outer, inner, src); + } +}; + +template +struct assign_impl +{ + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) + { + assign_DefaultTraversal_CompleteUnrolling + ::run(dst, src); + } +}; + +template +struct assign_impl +{ + typedef typename Derived1::Index Index; + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) + { + const Index outerSize = dst.outerSize(); + for(Index outer = 0; outer < outerSize; ++outer) + assign_DefaultTraversal_InnerUnrolling + ::run(dst, src, outer); + } +}; + +/*********************** +*** Linear traversal *** +***********************/ + +template +struct assign_impl +{ + typedef typename Derived1::Index Index; + static inline void run(Derived1 &dst, const Derived2 &src) + { + const Index size = dst.size(); + for(Index i = 0; i < size; ++i) + dst.copyCoeff(i, src); + } +}; + +template +struct assign_impl +{ + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) + { + assign_LinearTraversal_CompleteUnrolling + ::run(dst, src); + } +}; + +/************************** +*** Inner vectorization *** +**************************/ + +template +struct assign_impl +{ + typedef typename Derived1::Index Index; + static inline void run(Derived1 &dst, const Derived2 &src) + { + const Index innerSize = dst.innerSize(); + const Index outerSize = dst.outerSize(); + const Index packetSize = packet_traits::size; + for(Index outer = 0; outer < outerSize; ++outer) + for(Index inner = 0; inner < innerSize; inner+=packetSize) + dst.template copyPacketByOuterInner(outer, inner, src); + } +}; + +template +struct assign_impl +{ + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) + { + assign_innervec_CompleteUnrolling + ::run(dst, src); + } +}; + +template +struct assign_impl +{ + typedef typename Derived1::Index Index; + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) + { + const Index outerSize = dst.outerSize(); + for(Index outer = 0; outer < outerSize; ++outer) + assign_innervec_InnerUnrolling + ::run(dst, src, outer); + } +}; + +/*************************** +*** Linear vectorization *** +***************************/ + +template +struct unaligned_assign_impl +{ + template + static EIGEN_STRONG_INLINE void run(const Derived&, OtherDerived&, typename Derived::Index, typename Derived::Index) {} +}; + +template <> +struct unaligned_assign_impl +{ + // MSVC must not inline this functions. If it does, it fails to optimize the + // packet access path. +#ifdef _MSC_VER + template + static EIGEN_DONT_INLINE void run(const Derived& src, OtherDerived& dst, typename Derived::Index start, typename Derived::Index end) +#else + template + static EIGEN_STRONG_INLINE void run(const Derived& src, OtherDerived& dst, typename Derived::Index start, typename Derived::Index end) +#endif + { + for (typename Derived::Index index = start; index < end; ++index) + dst.copyCoeff(index, src); + } +}; + +template +struct assign_impl +{ + typedef typename Derived1::Index Index; + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) + { + const Index size = dst.size(); + typedef packet_traits PacketTraits; + enum { + packetSize = PacketTraits::size, + dstAlignment = PacketTraits::AlignedOnScalar ? Aligned : int(assign_traits::DstIsAligned) , + srcAlignment = assign_traits::JointAlignment + }; + const Index alignedStart = assign_traits::DstIsAligned ? 0 + : internal::first_aligned(&dst.coeffRef(0), size); + const Index alignedEnd = alignedStart + ((size-alignedStart)/packetSize)*packetSize; + + unaligned_assign_impl::DstIsAligned!=0>::run(src,dst,0,alignedStart); + + for(Index index = alignedStart; index < alignedEnd; index += packetSize) + { + dst.template copyPacket(index, src); + } + + unaligned_assign_impl<>::run(src,dst,alignedEnd,size); + } +}; + +template +struct assign_impl +{ + typedef typename Derived1::Index Index; + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) + { + enum { size = Derived1::SizeAtCompileTime, + packetSize = packet_traits::size, + alignedSize = (size/packetSize)*packetSize }; + + assign_innervec_CompleteUnrolling::run(dst, src); + assign_DefaultTraversal_CompleteUnrolling::run(dst, src); + } +}; + +/************************** +*** Slice vectorization *** +***************************/ + +template +struct assign_impl +{ + typedef typename Derived1::Index Index; + static inline void run(Derived1 &dst, const Derived2 &src) + { + typedef packet_traits PacketTraits; + enum { + packetSize = PacketTraits::size, + alignable = PacketTraits::AlignedOnScalar, + dstAlignment = alignable ? Aligned : int(assign_traits::DstIsAligned) , + srcAlignment = assign_traits::JointAlignment + }; + const Index packetAlignedMask = packetSize - 1; + const Index innerSize = dst.innerSize(); + const Index outerSize = dst.outerSize(); + const Index alignedStep = alignable ? (packetSize - dst.outerStride() % packetSize) & packetAlignedMask : 0; + Index alignedStart = ((!alignable) || assign_traits::DstIsAligned) ? 0 + : internal::first_aligned(&dst.coeffRef(0,0), innerSize); + + for(Index outer = 0; outer < outerSize; ++outer) + { + const Index alignedEnd = alignedStart + ((innerSize-alignedStart) & ~packetAlignedMask); + // do the non-vectorizable part of the assignment + for(Index inner = 0; inner(outer, inner, src); + + // do the non-vectorizable part of the assignment + for(Index inner = alignedEnd; inner((alignedStart+alignedStep)%packetSize, innerSize); + } + } +}; + +} // end namespace internal + +/*************************************************************************** +* Part 4 : implementation of DenseBase methods +***************************************************************************/ + +template +template +EIGEN_STRONG_INLINE Derived& DenseBase + ::lazyAssign(const DenseBase& other) +{ + enum{ + SameType = internal::is_same::value + }; + + EIGEN_STATIC_ASSERT_LVALUE(Derived) + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived) + EIGEN_STATIC_ASSERT(SameType,YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + +#ifdef EIGEN_DEBUG_ASSIGN + internal::assign_traits::debug(); +#endif + eigen_assert(rows() == other.rows() && cols() == other.cols()); + internal::assign_impl::Traversal) + : int(InvalidTraversal)>::run(derived(),other.derived()); +#ifndef EIGEN_NO_DEBUG + checkTransposeAliasing(other.derived()); +#endif + return derived(); +} + +namespace internal { + +template::Flags) & EvalBeforeAssigningBit) != 0, + bool NeedToTranspose = ((int(Derived::RowsAtCompileTime) == 1 && int(OtherDerived::ColsAtCompileTime) == 1) + | // FIXME | instead of || to please GCC 4.4.0 stupid warning "suggest parentheses around &&". + // revert to || as soon as not needed anymore. + (int(Derived::ColsAtCompileTime) == 1 && int(OtherDerived::RowsAtCompileTime) == 1)) + && int(Derived::SizeAtCompileTime) != 1> +struct assign_selector; + +template +struct assign_selector { + static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.derived()); } + template + static EIGEN_STRONG_INLINE Derived& evalTo(ActualDerived& dst, const ActualOtherDerived& other) { other.evalTo(dst); return dst; } +}; +template +struct assign_selector { + static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.eval()); } +}; +template +struct assign_selector { + static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose()); } + template + static EIGEN_STRONG_INLINE Derived& evalTo(ActualDerived& dst, const ActualOtherDerived& other) { Transpose dstTrans(dst); other.evalTo(dstTrans); return dst; } +}; +template +struct assign_selector { + static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose().eval()); } +}; + +} // end namespace internal + +template +template +EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) +{ + return internal::assign_selector::run(derived(), other.derived()); +} + +template +EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) +{ + return internal::assign_selector::run(derived(), other.derived()); +} + +template +EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const MatrixBase& other) +{ + return internal::assign_selector::run(derived(), other.derived()); +} + +template +template +EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const DenseBase& other) +{ + return internal::assign_selector::run(derived(), other.derived()); +} + +template +template +EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const EigenBase& other) +{ + return internal::assign_selector::evalTo(derived(), other.derived()); +} + +template +template +EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const ReturnByValue& other) +{ + return internal::assign_selector::evalTo(derived(), other.derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_ASSIGN_H diff --git a/libs/eigen3/Eigen/src/Core/Assign_MKL.h b/libs/eigen3/Eigen/src/Core/Assign_MKL.h new file mode 100644 index 000000000..7772951b9 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/Assign_MKL.h @@ -0,0 +1,224 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * MKL VML support for coefficient-wise unary Eigen expressions like a=b.sin() + ******************************************************************************** +*/ + +#ifndef EIGEN_ASSIGN_VML_H +#define EIGEN_ASSIGN_VML_H + +namespace Eigen { + +namespace internal { + +template struct vml_call +{ enum { IsSupported = 0 }; }; + +template +class vml_assign_traits +{ + private: + enum { + DstHasDirectAccess = Dst::Flags & DirectAccessBit, + SrcHasDirectAccess = Src::Flags & DirectAccessBit, + + StorageOrdersAgree = (int(Dst::IsRowMajor) == int(Src::IsRowMajor)), + InnerSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::SizeAtCompileTime) + : int(Dst::Flags)&RowMajorBit ? int(Dst::ColsAtCompileTime) + : int(Dst::RowsAtCompileTime), + InnerMaxSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::MaxSizeAtCompileTime) + : int(Dst::Flags)&RowMajorBit ? int(Dst::MaxColsAtCompileTime) + : int(Dst::MaxRowsAtCompileTime), + MaxSizeAtCompileTime = Dst::SizeAtCompileTime, + + MightEnableVml = vml_call::IsSupported && StorageOrdersAgree && DstHasDirectAccess && SrcHasDirectAccess + && Src::InnerStrideAtCompileTime==1 && Dst::InnerStrideAtCompileTime==1, + MightLinearize = MightEnableVml && (int(Dst::Flags) & int(Src::Flags) & LinearAccessBit), + VmlSize = MightLinearize ? MaxSizeAtCompileTime : InnerMaxSize, + LargeEnough = VmlSize==Dynamic || VmlSize>=EIGEN_MKL_VML_THRESHOLD, + MayEnableVml = MightEnableVml && LargeEnough, + MayLinearize = MayEnableVml && MightLinearize + }; + public: + enum { + Traversal = MayLinearize ? LinearVectorizedTraversal + : MayEnableVml ? InnerVectorizedTraversal + : DefaultTraversal + }; +}; + +template::Traversal > +struct vml_assign_impl + : assign_impl,Traversal,Unrolling,BuiltIn> +{ +}; + +template +struct vml_assign_impl +{ + typedef typename Derived1::Scalar Scalar; + typedef typename Derived1::Index Index; + static inline void run(Derived1& dst, const CwiseUnaryOp& src) + { + // in case we want to (or have to) skip VML at runtime we can call: + // assign_impl,Traversal,Unrolling,BuiltIn>::run(dst,src); + const Index innerSize = dst.innerSize(); + const Index outerSize = dst.outerSize(); + for(Index outer = 0; outer < outerSize; ++outer) { + const Scalar *src_ptr = src.IsRowMajor ? &(src.nestedExpression().coeffRef(outer,0)) : + &(src.nestedExpression().coeffRef(0, outer)); + Scalar *dst_ptr = dst.IsRowMajor ? &(dst.coeffRef(outer,0)) : &(dst.coeffRef(0, outer)); + vml_call::run(src.functor(), innerSize, src_ptr, dst_ptr ); + } + } +}; + +template +struct vml_assign_impl +{ + static inline void run(Derived1& dst, const CwiseUnaryOp& src) + { + // in case we want to (or have to) skip VML at runtime we can call: + // assign_impl,Traversal,Unrolling,BuiltIn>::run(dst,src); + vml_call::run(src.functor(), dst.size(), src.nestedExpression().data(), dst.data() ); + } +}; + +// Macroses + +#define EIGEN_MKL_VML_SPECIALIZE_ASSIGN(TRAVERSAL,UNROLLING) \ + template \ + struct assign_impl, TRAVERSAL, UNROLLING, Specialized> { \ + static inline void run(Derived1 &dst, const Eigen::CwiseUnaryOp &src) { \ + vml_assign_impl::run(dst, src); \ + } \ + }; + +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(DefaultTraversal,NoUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(DefaultTraversal,CompleteUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(DefaultTraversal,InnerUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearTraversal,NoUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearTraversal,CompleteUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(InnerVectorizedTraversal,NoUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(InnerVectorizedTraversal,CompleteUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(InnerVectorizedTraversal,InnerUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearVectorizedTraversal,CompleteUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearVectorizedTraversal,NoUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(SliceVectorizedTraversal,NoUnrolling) + + +#if !defined (EIGEN_FAST_MATH) || (EIGEN_FAST_MATH != 1) +#define EIGEN_MKL_VML_MODE VML_HA +#else +#define EIGEN_MKL_VML_MODE VML_LA +#endif + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE) \ + template<> struct vml_call< scalar_##EIGENOP##_op > { \ + enum { IsSupported = 1 }; \ + static inline void run( const scalar_##EIGENOP##_op& /*func*/, \ + int size, const EIGENTYPE* src, EIGENTYPE* dst) { \ + VMLOP(size, (const VMLTYPE*)src, (VMLTYPE*)dst); \ + } \ + }; + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE) \ + template<> struct vml_call< scalar_##EIGENOP##_op > { \ + enum { IsSupported = 1 }; \ + static inline void run( const scalar_##EIGENOP##_op& /*func*/, \ + int size, const EIGENTYPE* src, EIGENTYPE* dst) { \ + MKL_INT64 vmlMode = EIGEN_MKL_VML_MODE; \ + VMLOP(size, (const VMLTYPE*)src, (VMLTYPE*)dst, vmlMode); \ + } \ + }; + +#define EIGEN_MKL_VML_DECLARE_POW_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE) \ + template<> struct vml_call< scalar_##EIGENOP##_op > { \ + enum { IsSupported = 1 }; \ + static inline void run( const scalar_##EIGENOP##_op& func, \ + int size, const EIGENTYPE* src, EIGENTYPE* dst) { \ + EIGENTYPE exponent = func.m_exponent; \ + MKL_INT64 vmlMode = EIGEN_MKL_VML_MODE; \ + VMLOP(&size, (const VMLTYPE*)src, (const VMLTYPE*)&exponent, \ + (VMLTYPE*)dst, &vmlMode); \ + } \ + }; + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vs##VMLOP, float, float) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vd##VMLOP, double, double) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX(EIGENOP, VMLOP) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vc##VMLOP, scomplex, MKL_Complex8) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vz##VMLOP, dcomplex, MKL_Complex16) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS(EIGENOP, VMLOP) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX(EIGENOP, VMLOP) + + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL_LA(EIGENOP, VMLOP) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vms##VMLOP, float, float) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vmd##VMLOP, double, double) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX_LA(EIGENOP, VMLOP) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vmc##VMLOP, scomplex, MKL_Complex8) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vmz##VMLOP, dcomplex, MKL_Complex16) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(EIGENOP, VMLOP) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL_LA(EIGENOP, VMLOP) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX_LA(EIGENOP, VMLOP) + + +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(sin, Sin) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(asin, Asin) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(cos, Cos) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(acos, Acos) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(tan, Tan) +//EIGEN_MKL_VML_DECLARE_UNARY_CALLS(abs, Abs) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(exp, Exp) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(log, Ln) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(sqrt, Sqrt) + +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(square, Sqr) + +// The vm*powx functions are not avaibale in the windows version of MKL. +#ifndef _WIN32 +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmspowx_, float, float) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmdpowx_, double, double) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmcpowx_, scomplex, MKL_Complex8) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmzpowx_, dcomplex, MKL_Complex16) +#endif + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_ASSIGN_VML_H diff --git a/libs/eigen3/Eigen/src/Core/BandMatrix.h b/libs/eigen3/Eigen/src/Core/BandMatrix.h new file mode 100644 index 000000000..ffd7fe8b3 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/BandMatrix.h @@ -0,0 +1,334 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_BANDMATRIX_H +#define EIGEN_BANDMATRIX_H + +namespace Eigen { + +namespace internal { + +template +class BandMatrixBase : public EigenBase +{ + public: + + enum { + Flags = internal::traits::Flags, + CoeffReadCost = internal::traits::CoeffReadCost, + RowsAtCompileTime = internal::traits::RowsAtCompileTime, + ColsAtCompileTime = internal::traits::ColsAtCompileTime, + MaxRowsAtCompileTime = internal::traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = internal::traits::MaxColsAtCompileTime, + Supers = internal::traits::Supers, + Subs = internal::traits::Subs, + Options = internal::traits::Options + }; + typedef typename internal::traits::Scalar Scalar; + typedef Matrix DenseMatrixType; + typedef typename DenseMatrixType::Index Index; + typedef typename internal::traits::CoefficientsType CoefficientsType; + typedef EigenBase Base; + + protected: + enum { + DataRowsAtCompileTime = ((Supers!=Dynamic) && (Subs!=Dynamic)) + ? 1 + Supers + Subs + : Dynamic, + SizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime,ColsAtCompileTime) + }; + + public: + + using Base::derived; + using Base::rows; + using Base::cols; + + /** \returns the number of super diagonals */ + inline Index supers() const { return derived().supers(); } + + /** \returns the number of sub diagonals */ + inline Index subs() const { return derived().subs(); } + + /** \returns an expression of the underlying coefficient matrix */ + inline const CoefficientsType& coeffs() const { return derived().coeffs(); } + + /** \returns an expression of the underlying coefficient matrix */ + inline CoefficientsType& coeffs() { return derived().coeffs(); } + + /** \returns a vector expression of the \a i -th column, + * only the meaningful part is returned. + * \warning the internal storage must be column major. */ + inline Block col(Index i) + { + EIGEN_STATIC_ASSERT((Options&RowMajor)==0,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); + Index start = 0; + Index len = coeffs().rows(); + if (i<=supers()) + { + start = supers()-i; + len = (std::min)(rows(),std::max(0,coeffs().rows() - (supers()-i))); + } + else if (i>=rows()-subs()) + len = std::max(0,coeffs().rows() - (i + 1 - rows() + subs())); + return Block(coeffs(), start, i, len, 1); + } + + /** \returns a vector expression of the main diagonal */ + inline Block diagonal() + { return Block(coeffs(),supers(),0,1,(std::min)(rows(),cols())); } + + /** \returns a vector expression of the main diagonal (const version) */ + inline const Block diagonal() const + { return Block(coeffs(),supers(),0,1,(std::min)(rows(),cols())); } + + template struct DiagonalIntReturnType { + enum { + ReturnOpposite = (Options&SelfAdjoint) && (((Index)>0 && Supers==0) || ((Index)<0 && Subs==0)), + Conjugate = ReturnOpposite && NumTraits::IsComplex, + ActualIndex = ReturnOpposite ? -Index : Index, + DiagonalSize = (RowsAtCompileTime==Dynamic || ColsAtCompileTime==Dynamic) + ? Dynamic + : (ActualIndex<0 + ? EIGEN_SIZE_MIN_PREFER_DYNAMIC(ColsAtCompileTime, RowsAtCompileTime + ActualIndex) + : EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime, ColsAtCompileTime - ActualIndex)) + }; + typedef Block BuildType; + typedef typename internal::conditional,BuildType >, + BuildType>::type Type; + }; + + /** \returns a vector expression of the \a N -th sub or super diagonal */ + template inline typename DiagonalIntReturnType::Type diagonal() + { + return typename DiagonalIntReturnType::BuildType(coeffs(), supers()-N, (std::max)(0,N), 1, diagonalLength(N)); + } + + /** \returns a vector expression of the \a N -th sub or super diagonal */ + template inline const typename DiagonalIntReturnType::Type diagonal() const + { + return typename DiagonalIntReturnType::BuildType(coeffs(), supers()-N, (std::max)(0,N), 1, diagonalLength(N)); + } + + /** \returns a vector expression of the \a i -th sub or super diagonal */ + inline Block diagonal(Index i) + { + eigen_assert((i<0 && -i<=subs()) || (i>=0 && i<=supers())); + return Block(coeffs(), supers()-i, std::max(0,i), 1, diagonalLength(i)); + } + + /** \returns a vector expression of the \a i -th sub or super diagonal */ + inline const Block diagonal(Index i) const + { + eigen_assert((i<0 && -i<=subs()) || (i>=0 && i<=supers())); + return Block(coeffs(), supers()-i, std::max(0,i), 1, diagonalLength(i)); + } + + template inline void evalTo(Dest& dst) const + { + dst.resize(rows(),cols()); + dst.setZero(); + dst.diagonal() = diagonal(); + for (Index i=1; i<=supers();++i) + dst.diagonal(i) = diagonal(i); + for (Index i=1; i<=subs();++i) + dst.diagonal(-i) = diagonal(-i); + } + + DenseMatrixType toDenseMatrix() const + { + DenseMatrixType res(rows(),cols()); + evalTo(res); + return res; + } + + protected: + + inline Index diagonalLength(Index i) const + { return i<0 ? (std::min)(cols(),rows()+i) : (std::min)(rows(),cols()-i); } +}; + +/** + * \class BandMatrix + * \ingroup Core_Module + * + * \brief Represents a rectangular matrix with a banded storage + * + * \param _Scalar Numeric type, i.e. float, double, int + * \param Rows Number of rows, or \b Dynamic + * \param Cols Number of columns, or \b Dynamic + * \param Supers Number of super diagonal + * \param Subs Number of sub diagonal + * \param _Options A combination of either \b #RowMajor or \b #ColMajor, and of \b #SelfAdjoint + * The former controls \ref TopicStorageOrders "storage order", and defaults to + * column-major. The latter controls whether the matrix represents a selfadjoint + * matrix in which case either Supers of Subs have to be null. + * + * \sa class TridiagonalMatrix + */ + +template +struct traits > +{ + typedef _Scalar Scalar; + typedef Dense StorageKind; + typedef DenseIndex Index; + enum { + CoeffReadCost = NumTraits::ReadCost, + RowsAtCompileTime = _Rows, + ColsAtCompileTime = _Cols, + MaxRowsAtCompileTime = _Rows, + MaxColsAtCompileTime = _Cols, + Flags = LvalueBit, + Supers = _Supers, + Subs = _Subs, + Options = _Options, + DataRowsAtCompileTime = ((Supers!=Dynamic) && (Subs!=Dynamic)) ? 1 + Supers + Subs : Dynamic + }; + typedef Matrix CoefficientsType; +}; + +template +class BandMatrix : public BandMatrixBase > +{ + public: + + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::traits::Index Index; + typedef typename internal::traits::CoefficientsType CoefficientsType; + + inline BandMatrix(Index rows=Rows, Index cols=Cols, Index supers=Supers, Index subs=Subs) + : m_coeffs(1+supers+subs,cols), + m_rows(rows), m_supers(supers), m_subs(subs) + { + } + + /** \returns the number of columns */ + inline Index rows() const { return m_rows.value(); } + + /** \returns the number of rows */ + inline Index cols() const { return m_coeffs.cols(); } + + /** \returns the number of super diagonals */ + inline Index supers() const { return m_supers.value(); } + + /** \returns the number of sub diagonals */ + inline Index subs() const { return m_subs.value(); } + + inline const CoefficientsType& coeffs() const { return m_coeffs; } + inline CoefficientsType& coeffs() { return m_coeffs; } + + protected: + + CoefficientsType m_coeffs; + internal::variable_if_dynamic m_rows; + internal::variable_if_dynamic m_supers; + internal::variable_if_dynamic m_subs; +}; + +template +class BandMatrixWrapper; + +template +struct traits > +{ + typedef typename _CoefficientsType::Scalar Scalar; + typedef typename _CoefficientsType::StorageKind StorageKind; + typedef typename _CoefficientsType::Index Index; + enum { + CoeffReadCost = internal::traits<_CoefficientsType>::CoeffReadCost, + RowsAtCompileTime = _Rows, + ColsAtCompileTime = _Cols, + MaxRowsAtCompileTime = _Rows, + MaxColsAtCompileTime = _Cols, + Flags = LvalueBit, + Supers = _Supers, + Subs = _Subs, + Options = _Options, + DataRowsAtCompileTime = ((Supers!=Dynamic) && (Subs!=Dynamic)) ? 1 + Supers + Subs : Dynamic + }; + typedef _CoefficientsType CoefficientsType; +}; + +template +class BandMatrixWrapper : public BandMatrixBase > +{ + public: + + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::traits::CoefficientsType CoefficientsType; + typedef typename internal::traits::Index Index; + + inline BandMatrixWrapper(const CoefficientsType& coeffs, Index rows=_Rows, Index cols=_Cols, Index supers=_Supers, Index subs=_Subs) + : m_coeffs(coeffs), + m_rows(rows), m_supers(supers), m_subs(subs) + { + EIGEN_UNUSED_VARIABLE(cols); + //internal::assert(coeffs.cols()==cols() && (supers()+subs()+1)==coeffs.rows()); + } + + /** \returns the number of columns */ + inline Index rows() const { return m_rows.value(); } + + /** \returns the number of rows */ + inline Index cols() const { return m_coeffs.cols(); } + + /** \returns the number of super diagonals */ + inline Index supers() const { return m_supers.value(); } + + /** \returns the number of sub diagonals */ + inline Index subs() const { return m_subs.value(); } + + inline const CoefficientsType& coeffs() const { return m_coeffs; } + + protected: + + const CoefficientsType& m_coeffs; + internal::variable_if_dynamic m_rows; + internal::variable_if_dynamic m_supers; + internal::variable_if_dynamic m_subs; +}; + +/** + * \class TridiagonalMatrix + * \ingroup Core_Module + * + * \brief Represents a tridiagonal matrix with a compact banded storage + * + * \param _Scalar Numeric type, i.e. float, double, int + * \param Size Number of rows and cols, or \b Dynamic + * \param _Options Can be 0 or \b SelfAdjoint + * + * \sa class BandMatrix + */ +template +class TridiagonalMatrix : public BandMatrix +{ + typedef BandMatrix Base; + typedef typename Base::Index Index; + public: + TridiagonalMatrix(Index size = Size) : Base(size,size,Options&SelfAdjoint?0:1,1) {} + + inline typename Base::template DiagonalIntReturnType<1>::Type super() + { return Base::template diagonal<1>(); } + inline const typename Base::template DiagonalIntReturnType<1>::Type super() const + { return Base::template diagonal<1>(); } + inline typename Base::template DiagonalIntReturnType<-1>::Type sub() + { return Base::template diagonal<-1>(); } + inline const typename Base::template DiagonalIntReturnType<-1>::Type sub() const + { return Base::template diagonal<-1>(); } + protected: +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_BANDMATRIX_H diff --git a/libs/eigen3/Eigen/src/Core/Block.h b/libs/eigen3/Eigen/src/Core/Block.h new file mode 100644 index 000000000..87bedfa46 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/Block.h @@ -0,0 +1,405 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2006-2010 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_BLOCK_H +#define EIGEN_BLOCK_H + +namespace Eigen { + +/** \class Block + * \ingroup Core_Module + * + * \brief Expression of a fixed-size or dynamic-size block + * + * \param XprType the type of the expression in which we are taking a block + * \param BlockRows the number of rows of the block we are taking at compile time (optional) + * \param BlockCols the number of columns of the block we are taking at compile time (optional) + * + * This class represents an expression of either a fixed-size or dynamic-size block. It is the return + * type of DenseBase::block(Index,Index,Index,Index) and DenseBase::block(Index,Index) and + * most of the time this is the only way it is used. + * + * However, if you want to directly maniputate block expressions, + * for instance if you want to write a function returning such an expression, you + * will need to use this class. + * + * Here is an example illustrating the dynamic case: + * \include class_Block.cpp + * Output: \verbinclude class_Block.out + * + * \note Even though this expression has dynamic size, in the case where \a XprType + * has fixed size, this expression inherits a fixed maximal size which means that evaluating + * it does not cause a dynamic memory allocation. + * + * Here is an example illustrating the fixed-size case: + * \include class_FixedBlock.cpp + * Output: \verbinclude class_FixedBlock.out + * + * \sa DenseBase::block(Index,Index,Index,Index), DenseBase::block(Index,Index), class VectorBlock + */ + +namespace internal { +template +struct traits > : traits +{ + typedef typename traits::Scalar Scalar; + typedef typename traits::StorageKind StorageKind; + typedef typename traits::XprKind XprKind; + typedef typename nested::type XprTypeNested; + typedef typename remove_reference::type _XprTypeNested; + enum{ + MatrixRows = traits::RowsAtCompileTime, + MatrixCols = traits::ColsAtCompileTime, + RowsAtCompileTime = MatrixRows == 0 ? 0 : BlockRows, + ColsAtCompileTime = MatrixCols == 0 ? 0 : BlockCols, + MaxRowsAtCompileTime = BlockRows==0 ? 0 + : RowsAtCompileTime != Dynamic ? int(RowsAtCompileTime) + : int(traits::MaxRowsAtCompileTime), + MaxColsAtCompileTime = BlockCols==0 ? 0 + : ColsAtCompileTime != Dynamic ? int(ColsAtCompileTime) + : int(traits::MaxColsAtCompileTime), + XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0, + IsRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 + : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 + : XprTypeIsRowMajor, + HasSameStorageOrderAsXprType = (IsRowMajor == XprTypeIsRowMajor), + InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime), + InnerStrideAtCompileTime = HasSameStorageOrderAsXprType + ? int(inner_stride_at_compile_time::ret) + : int(outer_stride_at_compile_time::ret), + OuterStrideAtCompileTime = HasSameStorageOrderAsXprType + ? int(outer_stride_at_compile_time::ret) + : int(inner_stride_at_compile_time::ret), + MaskPacketAccessBit = (InnerSize == Dynamic || (InnerSize % packet_traits::size) == 0) + && (InnerStrideAtCompileTime == 1) + ? PacketAccessBit : 0, + MaskAlignedBit = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % 16) == 0)) ? AlignedBit : 0, + FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1 || (InnerPanel && (traits::Flags&LinearAccessBit))) ? LinearAccessBit : 0, + FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, + FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, + Flags0 = traits::Flags & ( (HereditaryBits & ~RowMajorBit) | + DirectAccessBit | + MaskPacketAccessBit | + MaskAlignedBit), + Flags = Flags0 | FlagsLinearAccessBit | FlagsLvalueBit | FlagsRowMajorBit + }; +}; + +template::ret> class BlockImpl_dense; + +} // end namespace internal + +template class BlockImpl; + +template class Block + : public BlockImpl::StorageKind> +{ + typedef BlockImpl::StorageKind> Impl; + public: + //typedef typename Impl::Base Base; + typedef Impl Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(Block) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Block) + + /** Column or Row constructor + */ + inline Block(XprType& xpr, Index i) : Impl(xpr,i) + { + eigen_assert( (i>=0) && ( + ((BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) && i= 0 && BlockRows >= 1 && a_startRow + BlockRows <= xpr.rows() + && a_startCol >= 0 && BlockCols >= 1 && a_startCol + BlockCols <= xpr.cols()); + } + + /** Dynamic-size constructor + */ + inline Block(XprType& xpr, + Index a_startRow, Index a_startCol, + Index blockRows, Index blockCols) + : Impl(xpr, a_startRow, a_startCol, blockRows, blockCols) + { + eigen_assert((RowsAtCompileTime==Dynamic || RowsAtCompileTime==blockRows) + && (ColsAtCompileTime==Dynamic || ColsAtCompileTime==blockCols)); + eigen_assert(a_startRow >= 0 && blockRows >= 0 && a_startRow <= xpr.rows() - blockRows + && a_startCol >= 0 && blockCols >= 0 && a_startCol <= xpr.cols() - blockCols); + } +}; + +// The generic default implementation for dense block simplu forward to the internal::BlockImpl_dense +// that must be specialized for direct and non-direct access... +template +class BlockImpl + : public internal::BlockImpl_dense +{ + typedef internal::BlockImpl_dense Impl; + typedef typename XprType::Index Index; + public: + typedef Impl Base; + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl) + inline BlockImpl(XprType& xpr, Index i) : Impl(xpr,i) {} + inline BlockImpl(XprType& xpr, Index a_startRow, Index a_startCol) : Impl(xpr, a_startRow, a_startCol) {} + inline BlockImpl(XprType& xpr, Index a_startRow, Index a_startCol, Index blockRows, Index blockCols) + : Impl(xpr, a_startRow, a_startCol, blockRows, blockCols) {} +}; + +namespace internal { + +/** \internal Internal implementation of dense Blocks in the general case. */ +template class BlockImpl_dense + : public internal::dense_xpr_base >::type +{ + typedef Block BlockType; + public: + + typedef typename internal::dense_xpr_base::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(BlockType) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl_dense) + + class InnerIterator; + + /** Column or Row constructor + */ + inline BlockImpl_dense(XprType& xpr, Index i) + : m_xpr(xpr), + // It is a row if and only if BlockRows==1 and BlockCols==XprType::ColsAtCompileTime, + // and it is a column if and only if BlockRows==XprType::RowsAtCompileTime and BlockCols==1, + // all other cases are invalid. + // The case a 1x1 matrix seems ambiguous, but the result is the same anyway. + m_startRow( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0), + m_startCol( (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0), + m_blockRows(BlockRows==1 ? 1 : xpr.rows()), + m_blockCols(BlockCols==1 ? 1 : xpr.cols()) + {} + + /** Fixed-size constructor + */ + inline BlockImpl_dense(XprType& xpr, Index a_startRow, Index a_startCol) + : m_xpr(xpr), m_startRow(a_startRow), m_startCol(a_startCol), + m_blockRows(BlockRows), m_blockCols(BlockCols) + {} + + /** Dynamic-size constructor + */ + inline BlockImpl_dense(XprType& xpr, + Index a_startRow, Index a_startCol, + Index blockRows, Index blockCols) + : m_xpr(xpr), m_startRow(a_startRow), m_startCol(a_startCol), + m_blockRows(blockRows), m_blockCols(blockCols) + {} + + inline Index rows() const { return m_blockRows.value(); } + inline Index cols() const { return m_blockCols.value(); } + + inline Scalar& coeffRef(Index rowId, Index colId) + { + EIGEN_STATIC_ASSERT_LVALUE(XprType) + return m_xpr.const_cast_derived() + .coeffRef(rowId + m_startRow.value(), colId + m_startCol.value()); + } + + inline const Scalar& coeffRef(Index rowId, Index colId) const + { + return m_xpr.derived() + .coeffRef(rowId + m_startRow.value(), colId + m_startCol.value()); + } + + EIGEN_STRONG_INLINE const CoeffReturnType coeff(Index rowId, Index colId) const + { + return m_xpr.coeff(rowId + m_startRow.value(), colId + m_startCol.value()); + } + + inline Scalar& coeffRef(Index index) + { + EIGEN_STATIC_ASSERT_LVALUE(XprType) + return m_xpr.const_cast_derived() + .coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), + m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); + } + + inline const Scalar& coeffRef(Index index) const + { + return m_xpr.const_cast_derived() + .coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), + m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); + } + + inline const CoeffReturnType coeff(Index index) const + { + return m_xpr + .coeff(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), + m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); + } + + template + inline PacketScalar packet(Index rowId, Index colId) const + { + return m_xpr.template packet + (rowId + m_startRow.value(), colId + m_startCol.value()); + } + + template + inline void writePacket(Index rowId, Index colId, const PacketScalar& val) + { + m_xpr.const_cast_derived().template writePacket + (rowId + m_startRow.value(), colId + m_startCol.value(), val); + } + + template + inline PacketScalar packet(Index index) const + { + return m_xpr.template packet + (m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), + m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); + } + + template + inline void writePacket(Index index, const PacketScalar& val) + { + m_xpr.const_cast_derived().template writePacket + (m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), + m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0), val); + } + + #ifdef EIGEN_PARSED_BY_DOXYGEN + /** \sa MapBase::data() */ + inline const Scalar* data() const; + inline Index innerStride() const; + inline Index outerStride() const; + #endif + + const typename internal::remove_all::type& nestedExpression() const + { + return m_xpr; + } + + Index startRow() const + { + return m_startRow.value(); + } + + Index startCol() const + { + return m_startCol.value(); + } + + protected: + + const typename XprType::Nested m_xpr; + const internal::variable_if_dynamic m_startRow; + const internal::variable_if_dynamic m_startCol; + const internal::variable_if_dynamic m_blockRows; + const internal::variable_if_dynamic m_blockCols; +}; + +/** \internal Internal implementation of dense Blocks in the direct access case.*/ +template +class BlockImpl_dense + : public MapBase > +{ + typedef Block BlockType; + public: + + typedef MapBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(BlockType) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl_dense) + + /** Column or Row constructor + */ + inline BlockImpl_dense(XprType& xpr, Index i) + : Base(internal::const_cast_ptr(&xpr.coeffRef( + (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0, + (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0)), + BlockRows==1 ? 1 : xpr.rows(), + BlockCols==1 ? 1 : xpr.cols()), + m_xpr(xpr) + { + init(); + } + + /** Fixed-size constructor + */ + inline BlockImpl_dense(XprType& xpr, Index startRow, Index startCol) + : Base(internal::const_cast_ptr(&xpr.coeffRef(startRow,startCol))), m_xpr(xpr) + { + init(); + } + + /** Dynamic-size constructor + */ + inline BlockImpl_dense(XprType& xpr, + Index startRow, Index startCol, + Index blockRows, Index blockCols) + : Base(internal::const_cast_ptr(&xpr.coeffRef(startRow,startCol)), blockRows, blockCols), + m_xpr(xpr) + { + init(); + } + + const typename internal::remove_all::type& nestedExpression() const + { + return m_xpr; + } + + /** \sa MapBase::innerStride() */ + inline Index innerStride() const + { + return internal::traits::HasSameStorageOrderAsXprType + ? m_xpr.innerStride() + : m_xpr.outerStride(); + } + + /** \sa MapBase::outerStride() */ + inline Index outerStride() const + { + return m_outerStride; + } + + #ifndef __SUNPRO_CC + // FIXME sunstudio is not friendly with the above friend... + // META-FIXME there is no 'friend' keyword around here. Is this obsolete? + protected: + #endif + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** \internal used by allowAligned() */ + inline BlockImpl_dense(XprType& xpr, const Scalar* data, Index blockRows, Index blockCols) + : Base(data, blockRows, blockCols), m_xpr(xpr) + { + init(); + } + #endif + + protected: + void init() + { + m_outerStride = internal::traits::HasSameStorageOrderAsXprType + ? m_xpr.outerStride() + : m_xpr.innerStride(); + } + + typename XprType::Nested m_xpr; + Index m_outerStride; +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_BLOCK_H diff --git a/libs/eigen3/Eigen/src/Core/BooleanRedux.h b/libs/eigen3/Eigen/src/Core/BooleanRedux.h new file mode 100644 index 000000000..be9f48a8c --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/BooleanRedux.h @@ -0,0 +1,154 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_ALLANDANY_H +#define EIGEN_ALLANDANY_H + +namespace Eigen { + +namespace internal { + +template +struct all_unroller +{ + enum { + col = (UnrollCount-1) / Derived::RowsAtCompileTime, + row = (UnrollCount-1) % Derived::RowsAtCompileTime + }; + + static inline bool run(const Derived &mat) + { + return all_unroller::run(mat) && mat.coeff(row, col); + } +}; + +template +struct all_unroller +{ + static inline bool run(const Derived &/*mat*/) { return true; } +}; + +template +struct all_unroller +{ + static inline bool run(const Derived &) { return false; } +}; + +template +struct any_unroller +{ + enum { + col = (UnrollCount-1) / Derived::RowsAtCompileTime, + row = (UnrollCount-1) % Derived::RowsAtCompileTime + }; + + static inline bool run(const Derived &mat) + { + return any_unroller::run(mat) || mat.coeff(row, col); + } +}; + +template +struct any_unroller +{ + static inline bool run(const Derived & /*mat*/) { return false; } +}; + +template +struct any_unroller +{ + static inline bool run(const Derived &) { return false; } +}; + +} // end namespace internal + +/** \returns true if all coefficients are true + * + * Example: \include MatrixBase_all.cpp + * Output: \verbinclude MatrixBase_all.out + * + * \sa any(), Cwise::operator<() + */ +template +inline bool DenseBase::all() const +{ + enum { + unroll = SizeAtCompileTime != Dynamic + && CoeffReadCost != Dynamic + && NumTraits::AddCost != Dynamic + && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT + }; + if(unroll) + return internal::all_unroller::run(derived()); + else + { + for(Index j = 0; j < cols(); ++j) + for(Index i = 0; i < rows(); ++i) + if (!coeff(i, j)) return false; + return true; + } +} + +/** \returns true if at least one coefficient is true + * + * \sa all() + */ +template +inline bool DenseBase::any() const +{ + enum { + unroll = SizeAtCompileTime != Dynamic + && CoeffReadCost != Dynamic + && NumTraits::AddCost != Dynamic + && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT + }; + if(unroll) + return internal::any_unroller::run(derived()); + else + { + for(Index j = 0; j < cols(); ++j) + for(Index i = 0; i < rows(); ++i) + if (coeff(i, j)) return true; + return false; + } +} + +/** \returns the number of coefficients which evaluate to true + * + * \sa all(), any() + */ +template +inline typename DenseBase::Index DenseBase::count() const +{ + return derived().template cast().template cast().sum(); +} + +/** \returns true is \c *this contains at least one Not A Number (NaN). + * + * \sa allFinite() + */ +template +inline bool DenseBase::hasNaN() const +{ + return !((derived().array()==derived().array()).all()); +} + +/** \returns true if \c *this contains only finite numbers, i.e., no NaN and no +/-INF values. + * + * \sa hasNaN() + */ +template +inline bool DenseBase::allFinite() const +{ + return !((derived()-derived()).hasNaN()); +} + +} // end namespace Eigen + +#endif // EIGEN_ALLANDANY_H diff --git a/libs/eigen3/Eigen/src/Core/CommaInitializer.h b/libs/eigen3/Eigen/src/Core/CommaInitializer.h new file mode 100644 index 000000000..a036d8c3b --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/CommaInitializer.h @@ -0,0 +1,154 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_COMMAINITIALIZER_H +#define EIGEN_COMMAINITIALIZER_H + +namespace Eigen { + +/** \class CommaInitializer + * \ingroup Core_Module + * + * \brief Helper class used by the comma initializer operator + * + * This class is internally used to implement the comma initializer feature. It is + * the return type of MatrixBase::operator<<, and most of the time this is the only + * way it is used. + * + * \sa \ref MatrixBaseCommaInitRef "MatrixBase::operator<<", CommaInitializer::finished() + */ +template +struct CommaInitializer +{ + typedef typename XprType::Scalar Scalar; + typedef typename XprType::Index Index; + + inline CommaInitializer(XprType& xpr, const Scalar& s) + : m_xpr(xpr), m_row(0), m_col(1), m_currentBlockRows(1) + { + m_xpr.coeffRef(0,0) = s; + } + + template + inline CommaInitializer(XprType& xpr, const DenseBase& other) + : m_xpr(xpr), m_row(0), m_col(other.cols()), m_currentBlockRows(other.rows()) + { + m_xpr.block(0, 0, other.rows(), other.cols()) = other; + } + + /* Copy/Move constructor which transfers ownership. This is crucial in + * absence of return value optimization to avoid assertions during destruction. */ + // FIXME in C++11 mode this could be replaced by a proper RValue constructor + inline CommaInitializer(const CommaInitializer& o) + : m_xpr(o.m_xpr), m_row(o.m_row), m_col(o.m_col), m_currentBlockRows(o.m_currentBlockRows) { + // Mark original object as finished. In absence of R-value references we need to const_cast: + const_cast(o).m_row = m_xpr.rows(); + const_cast(o).m_col = m_xpr.cols(); + const_cast(o).m_currentBlockRows = 0; + } + + /* inserts a scalar value in the target matrix */ + CommaInitializer& operator,(const Scalar& s) + { + if (m_col==m_xpr.cols()) + { + m_row+=m_currentBlockRows; + m_col = 0; + m_currentBlockRows = 1; + eigen_assert(m_row + CommaInitializer& operator,(const DenseBase& other) + { + if(other.cols()==0 || other.rows()==0) + return *this; + if (m_col==m_xpr.cols()) + { + m_row+=m_currentBlockRows; + m_col = 0; + m_currentBlockRows = other.rows(); + eigen_assert(m_row+m_currentBlockRows<=m_xpr.rows() + && "Too many rows passed to comma initializer (operator<<)"); + } + eigen_assert(m_col + (m_row, m_col) = other; + else + m_xpr.block(m_row, m_col, other.rows(), other.cols()) = other; + m_col += other.cols(); + return *this; + } + + inline ~CommaInitializer() + { + eigen_assert((m_row+m_currentBlockRows) == m_xpr.rows() + && m_col == m_xpr.cols() + && "Too few coefficients passed to comma initializer (operator<<)"); + } + + /** \returns the built matrix once all its coefficients have been set. + * Calling finished is 100% optional. Its purpose is to write expressions + * like this: + * \code + * quaternion.fromRotationMatrix((Matrix3f() << axis0, axis1, axis2).finished()); + * \endcode + */ + inline XprType& finished() { return m_xpr; } + + XprType& m_xpr; // target expression + Index m_row; // current row id + Index m_col; // current col id + Index m_currentBlockRows; // current block height +}; + +/** \anchor MatrixBaseCommaInitRef + * Convenient operator to set the coefficients of a matrix. + * + * The coefficients must be provided in a row major order and exactly match + * the size of the matrix. Otherwise an assertion is raised. + * + * Example: \include MatrixBase_set.cpp + * Output: \verbinclude MatrixBase_set.out + * + * \note According the c++ standard, the argument expressions of this comma initializer are evaluated in arbitrary order. + * + * \sa CommaInitializer::finished(), class CommaInitializer + */ +template +inline CommaInitializer DenseBase::operator<< (const Scalar& s) +{ + return CommaInitializer(*static_cast(this), s); +} + +/** \sa operator<<(const Scalar&) */ +template +template +inline CommaInitializer +DenseBase::operator<<(const DenseBase& other) +{ + return CommaInitializer(*static_cast(this), other); +} + +} // end namespace Eigen + +#endif // EIGEN_COMMAINITIALIZER_H diff --git a/libs/eigen3/Eigen/src/Core/CoreIterators.h b/libs/eigen3/Eigen/src/Core/CoreIterators.h new file mode 100644 index 000000000..6da4683d2 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/CoreIterators.h @@ -0,0 +1,61 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_COREITERATORS_H +#define EIGEN_COREITERATORS_H + +namespace Eigen { + +/* This file contains the respective InnerIterator definition of the expressions defined in Eigen/Core + */ + +/** \ingroup SparseCore_Module + * \class InnerIterator + * \brief An InnerIterator allows to loop over the element of a sparse (or dense) matrix or expression + * + * todo + */ + +// generic version for dense matrix and expressions +template class DenseBase::InnerIterator +{ + protected: + typedef typename Derived::Scalar Scalar; + typedef typename Derived::Index Index; + + enum { IsRowMajor = (Derived::Flags&RowMajorBit)==RowMajorBit }; + public: + EIGEN_STRONG_INLINE InnerIterator(const Derived& expr, Index outer) + : m_expression(expr), m_inner(0), m_outer(outer), m_end(expr.innerSize()) + {} + + EIGEN_STRONG_INLINE Scalar value() const + { + return (IsRowMajor) ? m_expression.coeff(m_outer, m_inner) + : m_expression.coeff(m_inner, m_outer); + } + + EIGEN_STRONG_INLINE InnerIterator& operator++() { m_inner++; return *this; } + + EIGEN_STRONG_INLINE Index index() const { return m_inner; } + inline Index row() const { return IsRowMajor ? m_outer : index(); } + inline Index col() const { return IsRowMajor ? index() : m_outer; } + + EIGEN_STRONG_INLINE operator bool() const { return m_inner < m_end && m_inner>=0; } + + protected: + const Derived& m_expression; + Index m_inner; + const Index m_outer; + const Index m_end; +}; + +} // end namespace Eigen + +#endif // EIGEN_COREITERATORS_H diff --git a/libs/eigen3/Eigen/src/Core/CwiseBinaryOp.h b/libs/eigen3/Eigen/src/Core/CwiseBinaryOp.h new file mode 100644 index 000000000..586f77aaf --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/CwiseBinaryOp.h @@ -0,0 +1,229 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CWISE_BINARY_OP_H +#define EIGEN_CWISE_BINARY_OP_H + +namespace Eigen { + +/** \class CwiseBinaryOp + * \ingroup Core_Module + * + * \brief Generic expression where a coefficient-wise binary operator is applied to two expressions + * + * \param BinaryOp template functor implementing the operator + * \param Lhs the type of the left-hand side + * \param Rhs the type of the right-hand side + * + * This class represents an expression where a coefficient-wise binary operator is applied to two expressions. + * It is the return type of binary operators, by which we mean only those binary operators where + * both the left-hand side and the right-hand side are Eigen expressions. + * For example, the return type of matrix1+matrix2 is a CwiseBinaryOp. + * + * Most of the time, this is the only way that it is used, so you typically don't have to name + * CwiseBinaryOp types explicitly. + * + * \sa MatrixBase::binaryExpr(const MatrixBase &,const CustomBinaryOp &) const, class CwiseUnaryOp, class CwiseNullaryOp + */ + +namespace internal { +template +struct traits > +{ + // we must not inherit from traits since it has + // the potential to cause problems with MSVC + typedef typename remove_all::type Ancestor; + typedef typename traits::XprKind XprKind; + enum { + RowsAtCompileTime = traits::RowsAtCompileTime, + ColsAtCompileTime = traits::ColsAtCompileTime, + MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = traits::MaxColsAtCompileTime + }; + + // even though we require Lhs and Rhs to have the same scalar type (see CwiseBinaryOp constructor), + // we still want to handle the case when the result type is different. + typedef typename result_of< + BinaryOp( + typename Lhs::Scalar, + typename Rhs::Scalar + ) + >::type Scalar; + typedef typename promote_storage_type::StorageKind, + typename traits::StorageKind>::ret StorageKind; + typedef typename promote_index_type::Index, + typename traits::Index>::type Index; + typedef typename Lhs::Nested LhsNested; + typedef typename Rhs::Nested RhsNested; + typedef typename remove_reference::type _LhsNested; + typedef typename remove_reference::type _RhsNested; + enum { + LhsCoeffReadCost = _LhsNested::CoeffReadCost, + RhsCoeffReadCost = _RhsNested::CoeffReadCost, + LhsFlags = _LhsNested::Flags, + RhsFlags = _RhsNested::Flags, + SameType = is_same::value, + StorageOrdersAgree = (int(Lhs::Flags)&RowMajorBit)==(int(Rhs::Flags)&RowMajorBit), + Flags0 = (int(LhsFlags) | int(RhsFlags)) & ( + HereditaryBits + | (int(LhsFlags) & int(RhsFlags) & + ( AlignedBit + | (StorageOrdersAgree ? LinearAccessBit : 0) + | (functor_traits::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0) + ) + ) + ), + Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit), + CoeffReadCost = LhsCoeffReadCost + RhsCoeffReadCost + functor_traits::Cost + }; +}; +} // end namespace internal + +// we require Lhs and Rhs to have the same scalar type. Currently there is no example of a binary functor +// that would take two operands of different types. If there were such an example, then this check should be +// moved to the BinaryOp functors, on a per-case basis. This would however require a change in the BinaryOp functors, as +// currently they take only one typename Scalar template parameter. +// It is tempting to always allow mixing different types but remember that this is often impossible in the vectorized paths. +// So allowing mixing different types gives very unexpected errors when enabling vectorization, when the user tries to +// add together a float matrix and a double matrix. +#define EIGEN_CHECK_BINARY_COMPATIBILIY(BINOP,LHS,RHS) \ + EIGEN_STATIC_ASSERT((internal::functor_is_product_like::ret \ + ? int(internal::scalar_product_traits::Defined) \ + : int(internal::is_same::value)), \ + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + +template +class CwiseBinaryOpImpl; + +template +class CwiseBinaryOp : internal::no_assignment_operator, + public CwiseBinaryOpImpl< + BinaryOp, Lhs, Rhs, + typename internal::promote_storage_type::StorageKind, + typename internal::traits::StorageKind>::ret> +{ + public: + + typedef typename CwiseBinaryOpImpl< + BinaryOp, Lhs, Rhs, + typename internal::promote_storage_type::StorageKind, + typename internal::traits::StorageKind>::ret>::Base Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseBinaryOp) + + typedef typename internal::nested::type LhsNested; + typedef typename internal::nested::type RhsNested; + typedef typename internal::remove_reference::type _LhsNested; + typedef typename internal::remove_reference::type _RhsNested; + + EIGEN_STRONG_INLINE CwiseBinaryOp(const Lhs& aLhs, const Rhs& aRhs, const BinaryOp& func = BinaryOp()) + : m_lhs(aLhs), m_rhs(aRhs), m_functor(func) + { + EIGEN_CHECK_BINARY_COMPATIBILIY(BinaryOp,typename Lhs::Scalar,typename Rhs::Scalar); + // require the sizes to match + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Lhs, Rhs) + eigen_assert(aLhs.rows() == aRhs.rows() && aLhs.cols() == aRhs.cols()); + } + + EIGEN_STRONG_INLINE Index rows() const { + // return the fixed size type if available to enable compile time optimizations + if (internal::traits::type>::RowsAtCompileTime==Dynamic) + return m_rhs.rows(); + else + return m_lhs.rows(); + } + EIGEN_STRONG_INLINE Index cols() const { + // return the fixed size type if available to enable compile time optimizations + if (internal::traits::type>::ColsAtCompileTime==Dynamic) + return m_rhs.cols(); + else + return m_lhs.cols(); + } + + /** \returns the left hand side nested expression */ + const _LhsNested& lhs() const { return m_lhs; } + /** \returns the right hand side nested expression */ + const _RhsNested& rhs() const { return m_rhs; } + /** \returns the functor representing the binary operation */ + const BinaryOp& functor() const { return m_functor; } + + protected: + LhsNested m_lhs; + RhsNested m_rhs; + const BinaryOp m_functor; +}; + +template +class CwiseBinaryOpImpl + : public internal::dense_xpr_base >::type +{ + typedef CwiseBinaryOp Derived; + public: + + typedef typename internal::dense_xpr_base >::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE( Derived ) + + EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const + { + return derived().functor()(derived().lhs().coeff(rowId, colId), + derived().rhs().coeff(rowId, colId)); + } + + template + EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const + { + return derived().functor().packetOp(derived().lhs().template packet(rowId, colId), + derived().rhs().template packet(rowId, colId)); + } + + EIGEN_STRONG_INLINE const Scalar coeff(Index index) const + { + return derived().functor()(derived().lhs().coeff(index), + derived().rhs().coeff(index)); + } + + template + EIGEN_STRONG_INLINE PacketScalar packet(Index index) const + { + return derived().functor().packetOp(derived().lhs().template packet(index), + derived().rhs().template packet(index)); + } +}; + +/** replaces \c *this by \c *this - \a other. + * + * \returns a reference to \c *this + */ +template +template +EIGEN_STRONG_INLINE Derived & +MatrixBase::operator-=(const MatrixBase &other) +{ + SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); + tmp = other.derived(); + return derived(); +} + +/** replaces \c *this by \c *this + \a other. + * + * \returns a reference to \c *this + */ +template +template +EIGEN_STRONG_INLINE Derived & +MatrixBase::operator+=(const MatrixBase& other) +{ + SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); + tmp = other.derived(); + return derived(); +} + +} // end namespace Eigen + +#endif // EIGEN_CWISE_BINARY_OP_H diff --git a/libs/eigen3/Eigen/src/Core/CwiseNullaryOp.h b/libs/eigen3/Eigen/src/Core/CwiseNullaryOp.h new file mode 100644 index 000000000..a93bab2d0 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/CwiseNullaryOp.h @@ -0,0 +1,864 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CWISE_NULLARY_OP_H +#define EIGEN_CWISE_NULLARY_OP_H + +namespace Eigen { + +/** \class CwiseNullaryOp + * \ingroup Core_Module + * + * \brief Generic expression of a matrix where all coefficients are defined by a functor + * + * \param NullaryOp template functor implementing the operator + * \param PlainObjectType the underlying plain matrix/array type + * + * This class represents an expression of a generic nullary operator. + * It is the return type of the Ones(), Zero(), Constant(), Identity() and Random() methods, + * and most of the time this is the only way it is used. + * + * However, if you want to write a function returning such an expression, you + * will need to use this class. + * + * \sa class CwiseUnaryOp, class CwiseBinaryOp, DenseBase::NullaryExpr() + */ + +namespace internal { +template +struct traits > : traits +{ + enum { + Flags = (traits::Flags + & ( HereditaryBits + | (functor_has_linear_access::ret ? LinearAccessBit : 0) + | (functor_traits::PacketAccess ? PacketAccessBit : 0))) + | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit), + CoeffReadCost = functor_traits::Cost + }; +}; +} + +template +class CwiseNullaryOp : internal::no_assignment_operator, + public internal::dense_xpr_base< CwiseNullaryOp >::type +{ + public: + + typedef typename internal::dense_xpr_base::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(CwiseNullaryOp) + + CwiseNullaryOp(Index nbRows, Index nbCols, const NullaryOp& func = NullaryOp()) + : m_rows(nbRows), m_cols(nbCols), m_functor(func) + { + eigen_assert(nbRows >= 0 + && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == nbRows) + && nbCols >= 0 + && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == nbCols)); + } + + EIGEN_STRONG_INLINE Index rows() const { return m_rows.value(); } + EIGEN_STRONG_INLINE Index cols() const { return m_cols.value(); } + + EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const + { + return m_functor(rowId, colId); + } + + template + EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const + { + return m_functor.packetOp(rowId, colId); + } + + EIGEN_STRONG_INLINE const Scalar coeff(Index index) const + { + return m_functor(index); + } + + template + EIGEN_STRONG_INLINE PacketScalar packet(Index index) const + { + return m_functor.packetOp(index); + } + + /** \returns the functor representing the nullary operation */ + const NullaryOp& functor() const { return m_functor; } + + protected: + const internal::variable_if_dynamic m_rows; + const internal::variable_if_dynamic m_cols; + const NullaryOp m_functor; +}; + + +/** \returns an expression of a matrix defined by a custom functor \a func + * + * The parameters \a rows and \a cols are the number of rows and of columns of + * the returned matrix. Must be compatible with this MatrixBase type. + * + * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, + * it is redundant to pass \a rows and \a cols as arguments, so Zero() should be used + * instead. + * + * The template parameter \a CustomNullaryOp is the type of the functor. + * + * \sa class CwiseNullaryOp + */ +template +template +EIGEN_STRONG_INLINE const CwiseNullaryOp +DenseBase::NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func) +{ + return CwiseNullaryOp(rows, cols, func); +} + +/** \returns an expression of a matrix defined by a custom functor \a func + * + * The parameter \a size is the size of the returned vector. + * Must be compatible with this MatrixBase type. + * + * \only_for_vectors + * + * This variant is meant to be used for dynamic-size vector types. For fixed-size types, + * it is redundant to pass \a size as argument, so Zero() should be used + * instead. + * + * The template parameter \a CustomNullaryOp is the type of the functor. + * + * \sa class CwiseNullaryOp + */ +template +template +EIGEN_STRONG_INLINE const CwiseNullaryOp +DenseBase::NullaryExpr(Index size, const CustomNullaryOp& func) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + if(RowsAtCompileTime == 1) return CwiseNullaryOp(1, size, func); + else return CwiseNullaryOp(size, 1, func); +} + +/** \returns an expression of a matrix defined by a custom functor \a func + * + * This variant is only for fixed-size DenseBase types. For dynamic-size types, you + * need to use the variants taking size arguments. + * + * The template parameter \a CustomNullaryOp is the type of the functor. + * + * \sa class CwiseNullaryOp + */ +template +template +EIGEN_STRONG_INLINE const CwiseNullaryOp +DenseBase::NullaryExpr(const CustomNullaryOp& func) +{ + return CwiseNullaryOp(RowsAtCompileTime, ColsAtCompileTime, func); +} + +/** \returns an expression of a constant matrix of value \a value + * + * The parameters \a nbRows and \a nbCols are the number of rows and of columns of + * the returned matrix. Must be compatible with this DenseBase type. + * + * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, + * it is redundant to pass \a nbRows and \a nbCols as arguments, so Zero() should be used + * instead. + * + * The template parameter \a CustomNullaryOp is the type of the functor. + * + * \sa class CwiseNullaryOp + */ +template +EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Constant(Index nbRows, Index nbCols, const Scalar& value) +{ + return DenseBase::NullaryExpr(nbRows, nbCols, internal::scalar_constant_op(value)); +} + +/** \returns an expression of a constant matrix of value \a value + * + * The parameter \a size is the size of the returned vector. + * Must be compatible with this DenseBase type. + * + * \only_for_vectors + * + * This variant is meant to be used for dynamic-size vector types. For fixed-size types, + * it is redundant to pass \a size as argument, so Zero() should be used + * instead. + * + * The template parameter \a CustomNullaryOp is the type of the functor. + * + * \sa class CwiseNullaryOp + */ +template +EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Constant(Index size, const Scalar& value) +{ + return DenseBase::NullaryExpr(size, internal::scalar_constant_op(value)); +} + +/** \returns an expression of a constant matrix of value \a value + * + * This variant is only for fixed-size DenseBase types. For dynamic-size types, you + * need to use the variants taking size arguments. + * + * The template parameter \a CustomNullaryOp is the type of the functor. + * + * \sa class CwiseNullaryOp + */ +template +EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Constant(const Scalar& value) +{ + EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) + return DenseBase::NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_constant_op(value)); +} + +/** + * \brief Sets a linearly space vector. + * + * The function generates 'size' equally spaced values in the closed interval [low,high]. + * This particular version of LinSpaced() uses sequential access, i.e. vector access is + * assumed to be a(0), a(1), ..., a(size). This assumption allows for better vectorization + * and yields faster code than the random access version. + * + * When size is set to 1, a vector of length 1 containing 'high' is returned. + * + * \only_for_vectors + * + * Example: \include DenseBase_LinSpaced_seq.cpp + * Output: \verbinclude DenseBase_LinSpaced_seq.out + * + * \sa setLinSpaced(Index,const Scalar&,const Scalar&), LinSpaced(Index,Scalar,Scalar), CwiseNullaryOp + */ +template +EIGEN_STRONG_INLINE const typename DenseBase::SequentialLinSpacedReturnType +DenseBase::LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); +} + +/** + * \copydoc DenseBase::LinSpaced(Sequential_t, Index, const Scalar&, const Scalar&) + * Special version for fixed size types which does not require the size parameter. + */ +template +EIGEN_STRONG_INLINE const typename DenseBase::SequentialLinSpacedReturnType +DenseBase::LinSpaced(Sequential_t, const Scalar& low, const Scalar& high) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) + return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); +} + +/** + * \brief Sets a linearly space vector. + * + * The function generates 'size' equally spaced values in the closed interval [low,high]. + * When size is set to 1, a vector of length 1 containing 'high' is returned. + * + * \only_for_vectors + * + * Example: \include DenseBase_LinSpaced.cpp + * Output: \verbinclude DenseBase_LinSpaced.out + * + * \sa setLinSpaced(Index,const Scalar&,const Scalar&), LinSpaced(Sequential_t,Index,const Scalar&,const Scalar&,Index), CwiseNullaryOp + */ +template +EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType +DenseBase::LinSpaced(Index size, const Scalar& low, const Scalar& high) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); +} + +/** + * \copydoc DenseBase::LinSpaced(Index, const Scalar&, const Scalar&) + * Special version for fixed size types which does not require the size parameter. + */ +template +EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType +DenseBase::LinSpaced(const Scalar& low, const Scalar& high) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) + return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); +} + +/** \returns true if all coefficients in this matrix are approximately equal to \a val, to within precision \a prec */ +template +bool DenseBase::isApproxToConstant +(const Scalar& val, const RealScalar& prec) const +{ + for(Index j = 0; j < cols(); ++j) + for(Index i = 0; i < rows(); ++i) + if(!internal::isApprox(this->coeff(i, j), val, prec)) + return false; + return true; +} + +/** This is just an alias for isApproxToConstant(). + * + * \returns true if all coefficients in this matrix are approximately equal to \a value, to within precision \a prec */ +template +bool DenseBase::isConstant +(const Scalar& val, const RealScalar& prec) const +{ + return isApproxToConstant(val, prec); +} + +/** Alias for setConstant(): sets all coefficients in this expression to \a val. + * + * \sa setConstant(), Constant(), class CwiseNullaryOp + */ +template +EIGEN_STRONG_INLINE void DenseBase::fill(const Scalar& val) +{ + setConstant(val); +} + +/** Sets all coefficients in this expression to \a value. + * + * \sa fill(), setConstant(Index,const Scalar&), setConstant(Index,Index,const Scalar&), setZero(), setOnes(), Constant(), class CwiseNullaryOp, setZero(), setOnes() + */ +template +EIGEN_STRONG_INLINE Derived& DenseBase::setConstant(const Scalar& val) +{ + return derived() = Constant(rows(), cols(), val); +} + +/** Resizes to the given \a size, and sets all coefficients in this expression to the given \a value. + * + * \only_for_vectors + * + * Example: \include Matrix_setConstant_int.cpp + * Output: \verbinclude Matrix_setConstant_int.out + * + * \sa MatrixBase::setConstant(const Scalar&), setConstant(Index,Index,const Scalar&), class CwiseNullaryOp, MatrixBase::Constant(const Scalar&) + */ +template +EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setConstant(Index size, const Scalar& val) +{ + resize(size); + return setConstant(val); +} + +/** Resizes to the given size, and sets all coefficients in this expression to the given \a value. + * + * \param nbRows the new number of rows + * \param nbCols the new number of columns + * \param val the value to which all coefficients are set + * + * Example: \include Matrix_setConstant_int_int.cpp + * Output: \verbinclude Matrix_setConstant_int_int.out + * + * \sa MatrixBase::setConstant(const Scalar&), setConstant(Index,const Scalar&), class CwiseNullaryOp, MatrixBase::Constant(const Scalar&) + */ +template +EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setConstant(Index nbRows, Index nbCols, const Scalar& val) +{ + resize(nbRows, nbCols); + return setConstant(val); +} + +/** + * \brief Sets a linearly space vector. + * + * The function generates 'size' equally spaced values in the closed interval [low,high]. + * When size is set to 1, a vector of length 1 containing 'high' is returned. + * + * \only_for_vectors + * + * Example: \include DenseBase_setLinSpaced.cpp + * Output: \verbinclude DenseBase_setLinSpaced.out + * + * \sa CwiseNullaryOp + */ +template +EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(Index newSize, const Scalar& low, const Scalar& high) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return derived() = Derived::NullaryExpr(newSize, internal::linspaced_op(low,high,newSize)); +} + +/** + * \brief Sets a linearly space vector. + * + * The function fill *this with equally spaced values in the closed interval [low,high]. + * When size is set to 1, a vector of length 1 containing 'high' is returned. + * + * \only_for_vectors + * + * \sa setLinSpaced(Index, const Scalar&, const Scalar&), CwiseNullaryOp + */ +template +EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(const Scalar& low, const Scalar& high) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return setLinSpaced(size(), low, high); +} + +// zero: + +/** \returns an expression of a zero matrix. + * + * The parameters \a rows and \a cols are the number of rows and of columns of + * the returned matrix. Must be compatible with this MatrixBase type. + * + * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, + * it is redundant to pass \a rows and \a cols as arguments, so Zero() should be used + * instead. + * + * Example: \include MatrixBase_zero_int_int.cpp + * Output: \verbinclude MatrixBase_zero_int_int.out + * + * \sa Zero(), Zero(Index) + */ +template +EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Zero(Index nbRows, Index nbCols) +{ + return Constant(nbRows, nbCols, Scalar(0)); +} + +/** \returns an expression of a zero vector. + * + * The parameter \a size is the size of the returned vector. + * Must be compatible with this MatrixBase type. + * + * \only_for_vectors + * + * This variant is meant to be used for dynamic-size vector types. For fixed-size types, + * it is redundant to pass \a size as argument, so Zero() should be used + * instead. + * + * Example: \include MatrixBase_zero_int.cpp + * Output: \verbinclude MatrixBase_zero_int.out + * + * \sa Zero(), Zero(Index,Index) + */ +template +EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Zero(Index size) +{ + return Constant(size, Scalar(0)); +} + +/** \returns an expression of a fixed-size zero matrix or vector. + * + * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you + * need to use the variants taking size arguments. + * + * Example: \include MatrixBase_zero.cpp + * Output: \verbinclude MatrixBase_zero.out + * + * \sa Zero(Index), Zero(Index,Index) + */ +template +EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Zero() +{ + return Constant(Scalar(0)); +} + +/** \returns true if *this is approximately equal to the zero matrix, + * within the precision given by \a prec. + * + * Example: \include MatrixBase_isZero.cpp + * Output: \verbinclude MatrixBase_isZero.out + * + * \sa class CwiseNullaryOp, Zero() + */ +template +bool DenseBase::isZero(const RealScalar& prec) const +{ + for(Index j = 0; j < cols(); ++j) + for(Index i = 0; i < rows(); ++i) + if(!internal::isMuchSmallerThan(this->coeff(i, j), static_cast(1), prec)) + return false; + return true; +} + +/** Sets all coefficients in this expression to zero. + * + * Example: \include MatrixBase_setZero.cpp + * Output: \verbinclude MatrixBase_setZero.out + * + * \sa class CwiseNullaryOp, Zero() + */ +template +EIGEN_STRONG_INLINE Derived& DenseBase::setZero() +{ + return setConstant(Scalar(0)); +} + +/** Resizes to the given \a size, and sets all coefficients in this expression to zero. + * + * \only_for_vectors + * + * Example: \include Matrix_setZero_int.cpp + * Output: \verbinclude Matrix_setZero_int.out + * + * \sa DenseBase::setZero(), setZero(Index,Index), class CwiseNullaryOp, DenseBase::Zero() + */ +template +EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setZero(Index newSize) +{ + resize(newSize); + return setConstant(Scalar(0)); +} + +/** Resizes to the given size, and sets all coefficients in this expression to zero. + * + * \param nbRows the new number of rows + * \param nbCols the new number of columns + * + * Example: \include Matrix_setZero_int_int.cpp + * Output: \verbinclude Matrix_setZero_int_int.out + * + * \sa DenseBase::setZero(), setZero(Index), class CwiseNullaryOp, DenseBase::Zero() + */ +template +EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setZero(Index nbRows, Index nbCols) +{ + resize(nbRows, nbCols); + return setConstant(Scalar(0)); +} + +// ones: + +/** \returns an expression of a matrix where all coefficients equal one. + * + * The parameters \a nbRows and \a nbCols are the number of rows and of columns of + * the returned matrix. Must be compatible with this MatrixBase type. + * + * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, + * it is redundant to pass \a rows and \a cols as arguments, so Ones() should be used + * instead. + * + * Example: \include MatrixBase_ones_int_int.cpp + * Output: \verbinclude MatrixBase_ones_int_int.out + * + * \sa Ones(), Ones(Index), isOnes(), class Ones + */ +template +EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Ones(Index nbRows, Index nbCols) +{ + return Constant(nbRows, nbCols, Scalar(1)); +} + +/** \returns an expression of a vector where all coefficients equal one. + * + * The parameter \a newSize is the size of the returned vector. + * Must be compatible with this MatrixBase type. + * + * \only_for_vectors + * + * This variant is meant to be used for dynamic-size vector types. For fixed-size types, + * it is redundant to pass \a size as argument, so Ones() should be used + * instead. + * + * Example: \include MatrixBase_ones_int.cpp + * Output: \verbinclude MatrixBase_ones_int.out + * + * \sa Ones(), Ones(Index,Index), isOnes(), class Ones + */ +template +EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Ones(Index newSize) +{ + return Constant(newSize, Scalar(1)); +} + +/** \returns an expression of a fixed-size matrix or vector where all coefficients equal one. + * + * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you + * need to use the variants taking size arguments. + * + * Example: \include MatrixBase_ones.cpp + * Output: \verbinclude MatrixBase_ones.out + * + * \sa Ones(Index), Ones(Index,Index), isOnes(), class Ones + */ +template +EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Ones() +{ + return Constant(Scalar(1)); +} + +/** \returns true if *this is approximately equal to the matrix where all coefficients + * are equal to 1, within the precision given by \a prec. + * + * Example: \include MatrixBase_isOnes.cpp + * Output: \verbinclude MatrixBase_isOnes.out + * + * \sa class CwiseNullaryOp, Ones() + */ +template +bool DenseBase::isOnes +(const RealScalar& prec) const +{ + return isApproxToConstant(Scalar(1), prec); +} + +/** Sets all coefficients in this expression to one. + * + * Example: \include MatrixBase_setOnes.cpp + * Output: \verbinclude MatrixBase_setOnes.out + * + * \sa class CwiseNullaryOp, Ones() + */ +template +EIGEN_STRONG_INLINE Derived& DenseBase::setOnes() +{ + return setConstant(Scalar(1)); +} + +/** Resizes to the given \a newSize, and sets all coefficients in this expression to one. + * + * \only_for_vectors + * + * Example: \include Matrix_setOnes_int.cpp + * Output: \verbinclude Matrix_setOnes_int.out + * + * \sa MatrixBase::setOnes(), setOnes(Index,Index), class CwiseNullaryOp, MatrixBase::Ones() + */ +template +EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setOnes(Index newSize) +{ + resize(newSize); + return setConstant(Scalar(1)); +} + +/** Resizes to the given size, and sets all coefficients in this expression to one. + * + * \param nbRows the new number of rows + * \param nbCols the new number of columns + * + * Example: \include Matrix_setOnes_int_int.cpp + * Output: \verbinclude Matrix_setOnes_int_int.out + * + * \sa MatrixBase::setOnes(), setOnes(Index), class CwiseNullaryOp, MatrixBase::Ones() + */ +template +EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setOnes(Index nbRows, Index nbCols) +{ + resize(nbRows, nbCols); + return setConstant(Scalar(1)); +} + +// Identity: + +/** \returns an expression of the identity matrix (not necessarily square). + * + * The parameters \a nbRows and \a nbCols are the number of rows and of columns of + * the returned matrix. Must be compatible with this MatrixBase type. + * + * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, + * it is redundant to pass \a rows and \a cols as arguments, so Identity() should be used + * instead. + * + * Example: \include MatrixBase_identity_int_int.cpp + * Output: \verbinclude MatrixBase_identity_int_int.out + * + * \sa Identity(), setIdentity(), isIdentity() + */ +template +EIGEN_STRONG_INLINE const typename MatrixBase::IdentityReturnType +MatrixBase::Identity(Index nbRows, Index nbCols) +{ + return DenseBase::NullaryExpr(nbRows, nbCols, internal::scalar_identity_op()); +} + +/** \returns an expression of the identity matrix (not necessarily square). + * + * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you + * need to use the variant taking size arguments. + * + * Example: \include MatrixBase_identity.cpp + * Output: \verbinclude MatrixBase_identity.out + * + * \sa Identity(Index,Index), setIdentity(), isIdentity() + */ +template +EIGEN_STRONG_INLINE const typename MatrixBase::IdentityReturnType +MatrixBase::Identity() +{ + EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) + return MatrixBase::NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_identity_op()); +} + +/** \returns true if *this is approximately equal to the identity matrix + * (not necessarily square), + * within the precision given by \a prec. + * + * Example: \include MatrixBase_isIdentity.cpp + * Output: \verbinclude MatrixBase_isIdentity.out + * + * \sa class CwiseNullaryOp, Identity(), Identity(Index,Index), setIdentity() + */ +template +bool MatrixBase::isIdentity +(const RealScalar& prec) const +{ + for(Index j = 0; j < cols(); ++j) + { + for(Index i = 0; i < rows(); ++i) + { + if(i == j) + { + if(!internal::isApprox(this->coeff(i, j), static_cast(1), prec)) + return false; + } + else + { + if(!internal::isMuchSmallerThan(this->coeff(i, j), static_cast(1), prec)) + return false; + } + } + } + return true; +} + +namespace internal { + +template=16)> +struct setIdentity_impl +{ + static EIGEN_STRONG_INLINE Derived& run(Derived& m) + { + return m = Derived::Identity(m.rows(), m.cols()); + } +}; + +template +struct setIdentity_impl +{ + typedef typename Derived::Index Index; + static EIGEN_STRONG_INLINE Derived& run(Derived& m) + { + m.setZero(); + const Index size = (std::min)(m.rows(), m.cols()); + for(Index i = 0; i < size; ++i) m.coeffRef(i,i) = typename Derived::Scalar(1); + return m; + } +}; + +} // end namespace internal + +/** Writes the identity expression (not necessarily square) into *this. + * + * Example: \include MatrixBase_setIdentity.cpp + * Output: \verbinclude MatrixBase_setIdentity.out + * + * \sa class CwiseNullaryOp, Identity(), Identity(Index,Index), isIdentity() + */ +template +EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity() +{ + return internal::setIdentity_impl::run(derived()); +} + +/** \brief Resizes to the given size, and writes the identity expression (not necessarily square) into *this. + * + * \param nbRows the new number of rows + * \param nbCols the new number of columns + * + * Example: \include Matrix_setIdentity_int_int.cpp + * Output: \verbinclude Matrix_setIdentity_int_int.out + * + * \sa MatrixBase::setIdentity(), class CwiseNullaryOp, MatrixBase::Identity() + */ +template +EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity(Index nbRows, Index nbCols) +{ + derived().resize(nbRows, nbCols); + return setIdentity(); +} + +/** \returns an expression of the i-th unit (basis) vector. + * + * \only_for_vectors + * + * \sa MatrixBase::Unit(Index), MatrixBase::UnitX(), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() + */ +template +EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::Unit(Index newSize, Index i) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return BasisReturnType(SquareMatrixType::Identity(newSize,newSize), i); +} + +/** \returns an expression of the i-th unit (basis) vector. + * + * \only_for_vectors + * + * This variant is for fixed-size vector only. + * + * \sa MatrixBase::Unit(Index,Index), MatrixBase::UnitX(), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() + */ +template +EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::Unit(Index i) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return BasisReturnType(SquareMatrixType::Identity(),i); +} + +/** \returns an expression of the X axis unit vector (1{,0}^*) + * + * \only_for_vectors + * + * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() + */ +template +EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitX() +{ return Derived::Unit(0); } + +/** \returns an expression of the Y axis unit vector (0,1{,0}^*) + * + * \only_for_vectors + * + * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() + */ +template +EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitY() +{ return Derived::Unit(1); } + +/** \returns an expression of the Z axis unit vector (0,0,1{,0}^*) + * + * \only_for_vectors + * + * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() + */ +template +EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitZ() +{ return Derived::Unit(2); } + +/** \returns an expression of the W axis unit vector (0,0,0,1) + * + * \only_for_vectors + * + * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() + */ +template +EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitW() +{ return Derived::Unit(3); } + +} // end namespace Eigen + +#endif // EIGEN_CWISE_NULLARY_OP_H diff --git a/libs/eigen3/Eigen/src/Core/CwiseUnaryOp.h b/libs/eigen3/Eigen/src/Core/CwiseUnaryOp.h new file mode 100644 index 000000000..f2de749f9 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/CwiseUnaryOp.h @@ -0,0 +1,126 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CWISE_UNARY_OP_H +#define EIGEN_CWISE_UNARY_OP_H + +namespace Eigen { + +/** \class CwiseUnaryOp + * \ingroup Core_Module + * + * \brief Generic expression where a coefficient-wise unary operator is applied to an expression + * + * \param UnaryOp template functor implementing the operator + * \param XprType the type of the expression to which we are applying the unary operator + * + * This class represents an expression where a unary operator is applied to an expression. + * It is the return type of all operations taking exactly 1 input expression, regardless of the + * presence of other inputs such as scalars. For example, the operator* in the expression 3*matrix + * is considered unary, because only the right-hand side is an expression, and its + * return type is a specialization of CwiseUnaryOp. + * + * Most of the time, this is the only way that it is used, so you typically don't have to name + * CwiseUnaryOp types explicitly. + * + * \sa MatrixBase::unaryExpr(const CustomUnaryOp &) const, class CwiseBinaryOp, class CwiseNullaryOp + */ + +namespace internal { +template +struct traits > + : traits +{ + typedef typename result_of< + UnaryOp(typename XprType::Scalar) + >::type Scalar; + typedef typename XprType::Nested XprTypeNested; + typedef typename remove_reference::type _XprTypeNested; + enum { + Flags = _XprTypeNested::Flags & ( + HereditaryBits | LinearAccessBit | AlignedBit + | (functor_traits::PacketAccess ? PacketAccessBit : 0)), + CoeffReadCost = _XprTypeNested::CoeffReadCost + functor_traits::Cost + }; +}; +} + +template +class CwiseUnaryOpImpl; + +template +class CwiseUnaryOp : internal::no_assignment_operator, + public CwiseUnaryOpImpl::StorageKind> +{ + public: + + typedef typename CwiseUnaryOpImpl::StorageKind>::Base Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryOp) + + inline CwiseUnaryOp(const XprType& xpr, const UnaryOp& func = UnaryOp()) + : m_xpr(xpr), m_functor(func) {} + + EIGEN_STRONG_INLINE Index rows() const { return m_xpr.rows(); } + EIGEN_STRONG_INLINE Index cols() const { return m_xpr.cols(); } + + /** \returns the functor representing the unary operation */ + const UnaryOp& functor() const { return m_functor; } + + /** \returns the nested expression */ + const typename internal::remove_all::type& + nestedExpression() const { return m_xpr; } + + /** \returns the nested expression */ + typename internal::remove_all::type& + nestedExpression() { return m_xpr.const_cast_derived(); } + + protected: + typename XprType::Nested m_xpr; + const UnaryOp m_functor; +}; + +// This is the generic implementation for dense storage. +// It can be used for any expression types implementing the dense concept. +template +class CwiseUnaryOpImpl + : public internal::dense_xpr_base >::type +{ + public: + + typedef CwiseUnaryOp Derived; + typedef typename internal::dense_xpr_base >::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Derived) + + EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const + { + return derived().functor()(derived().nestedExpression().coeff(rowId, colId)); + } + + template + EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const + { + return derived().functor().packetOp(derived().nestedExpression().template packet(rowId, colId)); + } + + EIGEN_STRONG_INLINE const Scalar coeff(Index index) const + { + return derived().functor()(derived().nestedExpression().coeff(index)); + } + + template + EIGEN_STRONG_INLINE PacketScalar packet(Index index) const + { + return derived().functor().packetOp(derived().nestedExpression().template packet(index)); + } +}; + +} // end namespace Eigen + +#endif // EIGEN_CWISE_UNARY_OP_H diff --git a/libs/eigen3/Eigen/src/Core/CwiseUnaryView.h b/libs/eigen3/Eigen/src/Core/CwiseUnaryView.h new file mode 100644 index 000000000..b2638d326 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/CwiseUnaryView.h @@ -0,0 +1,139 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CWISE_UNARY_VIEW_H +#define EIGEN_CWISE_UNARY_VIEW_H + +namespace Eigen { + +/** \class CwiseUnaryView + * \ingroup Core_Module + * + * \brief Generic lvalue expression of a coefficient-wise unary operator of a matrix or a vector + * + * \param ViewOp template functor implementing the view + * \param MatrixType the type of the matrix we are applying the unary operator + * + * This class represents a lvalue expression of a generic unary view operator of a matrix or a vector. + * It is the return type of real() and imag(), and most of the time this is the only way it is used. + * + * \sa MatrixBase::unaryViewExpr(const CustomUnaryOp &) const, class CwiseUnaryOp + */ + +namespace internal { +template +struct traits > + : traits +{ + typedef typename result_of< + ViewOp(typename traits::Scalar) + >::type Scalar; + typedef typename MatrixType::Nested MatrixTypeNested; + typedef typename remove_all::type _MatrixTypeNested; + enum { + Flags = (traits<_MatrixTypeNested>::Flags & (HereditaryBits | LvalueBit | LinearAccessBit | DirectAccessBit)), + CoeffReadCost = traits<_MatrixTypeNested>::CoeffReadCost + functor_traits::Cost, + MatrixTypeInnerStride = inner_stride_at_compile_time::ret, + // need to cast the sizeof's from size_t to int explicitly, otherwise: + // "error: no integral type can represent all of the enumerator values + InnerStrideAtCompileTime = MatrixTypeInnerStride == Dynamic + ? int(Dynamic) + : int(MatrixTypeInnerStride) * int(sizeof(typename traits::Scalar) / sizeof(Scalar)), + OuterStrideAtCompileTime = outer_stride_at_compile_time::ret == Dynamic + ? int(Dynamic) + : outer_stride_at_compile_time::ret * int(sizeof(typename traits::Scalar) / sizeof(Scalar)) + }; +}; +} + +template +class CwiseUnaryViewImpl; + +template +class CwiseUnaryView : public CwiseUnaryViewImpl::StorageKind> +{ + public: + + typedef typename CwiseUnaryViewImpl::StorageKind>::Base Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryView) + + inline CwiseUnaryView(const MatrixType& mat, const ViewOp& func = ViewOp()) + : m_matrix(mat), m_functor(func) {} + + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryView) + + EIGEN_STRONG_INLINE Index rows() const { return m_matrix.rows(); } + EIGEN_STRONG_INLINE Index cols() const { return m_matrix.cols(); } + + /** \returns the functor representing unary operation */ + const ViewOp& functor() const { return m_functor; } + + /** \returns the nested expression */ + const typename internal::remove_all::type& + nestedExpression() const { return m_matrix; } + + /** \returns the nested expression */ + typename internal::remove_all::type& + nestedExpression() { return m_matrix.const_cast_derived(); } + + protected: + // FIXME changed from MatrixType::Nested because of a weird compilation error with sun CC + typename internal::nested::type m_matrix; + ViewOp m_functor; +}; + +template +class CwiseUnaryViewImpl + : public internal::dense_xpr_base< CwiseUnaryView >::type +{ + public: + + typedef CwiseUnaryView Derived; + typedef typename internal::dense_xpr_base< CwiseUnaryView >::type Base; + + EIGEN_DENSE_PUBLIC_INTERFACE(Derived) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryViewImpl) + + inline Scalar* data() { return &coeffRef(0); } + inline const Scalar* data() const { return &coeff(0); } + + inline Index innerStride() const + { + return derived().nestedExpression().innerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); + } + + inline Index outerStride() const + { + return derived().nestedExpression().outerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); + } + + EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const + { + return derived().functor()(derived().nestedExpression().coeff(row, col)); + } + + EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + return derived().functor()(derived().nestedExpression().coeff(index)); + } + + EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) + { + return derived().functor()(const_cast_derived().nestedExpression().coeffRef(row, col)); + } + + EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) + { + return derived().functor()(const_cast_derived().nestedExpression().coeffRef(index)); + } +}; + +} // end namespace Eigen + +#endif // EIGEN_CWISE_UNARY_VIEW_H diff --git a/libs/eigen3/Eigen/src/Core/DenseBase.h b/libs/eigen3/Eigen/src/Core/DenseBase.h new file mode 100644 index 000000000..c5800f6c8 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/DenseBase.h @@ -0,0 +1,521 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2007-2010 Benoit Jacob +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_DENSEBASE_H +#define EIGEN_DENSEBASE_H + +namespace Eigen { + +namespace internal { + +// The index type defined by EIGEN_DEFAULT_DENSE_INDEX_TYPE must be a signed type. +// This dummy function simply aims at checking that at compile time. +static inline void check_DenseIndex_is_signed() { + EIGEN_STATIC_ASSERT(NumTraits::IsSigned,THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE); +} + +} // end namespace internal + +/** \class DenseBase + * \ingroup Core_Module + * + * \brief Base class for all dense matrices, vectors, and arrays + * + * This class is the base that is inherited by all dense objects (matrix, vector, arrays, + * and related expression types). The common Eigen API for dense objects is contained in this class. + * + * \tparam Derived is the derived type, e.g., a matrix type or an expression. + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_DENSEBASE_PLUGIN. + * + * \sa \ref TopicClassHierarchy + */ +template class DenseBase +#ifndef EIGEN_PARSED_BY_DOXYGEN + : public internal::special_scalar_op_base::Scalar, + typename NumTraits::Scalar>::Real> +#else + : public DenseCoeffsBase +#endif // not EIGEN_PARSED_BY_DOXYGEN +{ + public: + using internal::special_scalar_op_base::Scalar, + typename NumTraits::Scalar>::Real>::operator*; + + class InnerIterator; + + typedef typename internal::traits::StorageKind StorageKind; + + /** \brief The type of indices + * \details To change this, \c \#define the preprocessor symbol \c EIGEN_DEFAULT_DENSE_INDEX_TYPE. + * \sa \ref TopicPreprocessorDirectives. + */ + typedef typename internal::traits::Index Index; + + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::packet_traits::type PacketScalar; + typedef typename NumTraits::Real RealScalar; + + typedef DenseCoeffsBase Base; + using Base::derived; + using Base::const_cast_derived; + using Base::rows; + using Base::cols; + using Base::size; + using Base::rowIndexByOuterInner; + using Base::colIndexByOuterInner; + using Base::coeff; + using Base::coeffByOuterInner; + using Base::packet; + using Base::packetByOuterInner; + using Base::writePacket; + using Base::writePacketByOuterInner; + using Base::coeffRef; + using Base::coeffRefByOuterInner; + using Base::copyCoeff; + using Base::copyCoeffByOuterInner; + using Base::copyPacket; + using Base::copyPacketByOuterInner; + using Base::operator(); + using Base::operator[]; + using Base::x; + using Base::y; + using Base::z; + using Base::w; + using Base::stride; + using Base::innerStride; + using Base::outerStride; + using Base::rowStride; + using Base::colStride; + typedef typename Base::CoeffReturnType CoeffReturnType; + + enum { + + RowsAtCompileTime = internal::traits::RowsAtCompileTime, + /**< The number of rows at compile-time. This is just a copy of the value provided + * by the \a Derived type. If a value is not known at compile-time, + * it is set to the \a Dynamic constant. + * \sa MatrixBase::rows(), MatrixBase::cols(), ColsAtCompileTime, SizeAtCompileTime */ + + ColsAtCompileTime = internal::traits::ColsAtCompileTime, + /**< The number of columns at compile-time. This is just a copy of the value provided + * by the \a Derived type. If a value is not known at compile-time, + * it is set to the \a Dynamic constant. + * \sa MatrixBase::rows(), MatrixBase::cols(), RowsAtCompileTime, SizeAtCompileTime */ + + + SizeAtCompileTime = (internal::size_at_compile_time::RowsAtCompileTime, + internal::traits::ColsAtCompileTime>::ret), + /**< This is equal to the number of coefficients, i.e. the number of + * rows times the number of columns, or to \a Dynamic if this is not + * known at compile-time. \sa RowsAtCompileTime, ColsAtCompileTime */ + + MaxRowsAtCompileTime = internal::traits::MaxRowsAtCompileTime, + /**< This value is equal to the maximum possible number of rows that this expression + * might have. If this expression might have an arbitrarily high number of rows, + * this value is set to \a Dynamic. + * + * This value is useful to know when evaluating an expression, in order to determine + * whether it is possible to avoid doing a dynamic memory allocation. + * + * \sa RowsAtCompileTime, MaxColsAtCompileTime, MaxSizeAtCompileTime + */ + + MaxColsAtCompileTime = internal::traits::MaxColsAtCompileTime, + /**< This value is equal to the maximum possible number of columns that this expression + * might have. If this expression might have an arbitrarily high number of columns, + * this value is set to \a Dynamic. + * + * This value is useful to know when evaluating an expression, in order to determine + * whether it is possible to avoid doing a dynamic memory allocation. + * + * \sa ColsAtCompileTime, MaxRowsAtCompileTime, MaxSizeAtCompileTime + */ + + MaxSizeAtCompileTime = (internal::size_at_compile_time::MaxRowsAtCompileTime, + internal::traits::MaxColsAtCompileTime>::ret), + /**< This value is equal to the maximum possible number of coefficients that this expression + * might have. If this expression might have an arbitrarily high number of coefficients, + * this value is set to \a Dynamic. + * + * This value is useful to know when evaluating an expression, in order to determine + * whether it is possible to avoid doing a dynamic memory allocation. + * + * \sa SizeAtCompileTime, MaxRowsAtCompileTime, MaxColsAtCompileTime + */ + + IsVectorAtCompileTime = internal::traits::MaxRowsAtCompileTime == 1 + || internal::traits::MaxColsAtCompileTime == 1, + /**< This is set to true if either the number of rows or the number of + * columns is known at compile-time to be equal to 1. Indeed, in that case, + * we are dealing with a column-vector (if there is only one column) or with + * a row-vector (if there is only one row). */ + + Flags = internal::traits::Flags, + /**< This stores expression \ref flags flags which may or may not be inherited by new expressions + * constructed from this one. See the \ref flags "list of flags". + */ + + IsRowMajor = int(Flags) & RowMajorBit, /**< True if this expression has row-major storage order. */ + + InnerSizeAtCompileTime = int(IsVectorAtCompileTime) ? int(SizeAtCompileTime) + : int(IsRowMajor) ? int(ColsAtCompileTime) : int(RowsAtCompileTime), + + CoeffReadCost = internal::traits::CoeffReadCost, + /**< This is a rough measure of how expensive it is to read one coefficient from + * this expression. + */ + + InnerStrideAtCompileTime = internal::inner_stride_at_compile_time::ret, + OuterStrideAtCompileTime = internal::outer_stride_at_compile_time::ret + }; + + enum { ThisConstantIsPrivateInPlainObjectBase }; + + /** \returns the number of nonzero coefficients which is in practice the number + * of stored coefficients. */ + inline Index nonZeros() const { return size(); } + /** \returns true if either the number of rows or the number of columns is equal to 1. + * In other words, this function returns + * \code rows()==1 || cols()==1 \endcode + * \sa rows(), cols(), IsVectorAtCompileTime. */ + + /** \returns the outer size. + * + * \note For a vector, this returns just 1. For a matrix (non-vector), this is the major dimension + * with respect to the \ref TopicStorageOrders "storage order", i.e., the number of columns for a + * column-major matrix, and the number of rows for a row-major matrix. */ + Index outerSize() const + { + return IsVectorAtCompileTime ? 1 + : int(IsRowMajor) ? this->rows() : this->cols(); + } + + /** \returns the inner size. + * + * \note For a vector, this is just the size. For a matrix (non-vector), this is the minor dimension + * with respect to the \ref TopicStorageOrders "storage order", i.e., the number of rows for a + * column-major matrix, and the number of columns for a row-major matrix. */ + Index innerSize() const + { + return IsVectorAtCompileTime ? this->size() + : int(IsRowMajor) ? this->cols() : this->rows(); + } + + /** Only plain matrices/arrays, not expressions, may be resized; therefore the only useful resize methods are + * Matrix::resize() and Array::resize(). The present method only asserts that the new size equals the old size, and does + * nothing else. + */ + void resize(Index newSize) + { + EIGEN_ONLY_USED_FOR_DEBUG(newSize); + eigen_assert(newSize == this->size() + && "DenseBase::resize() does not actually allow to resize."); + } + /** Only plain matrices/arrays, not expressions, may be resized; therefore the only useful resize methods are + * Matrix::resize() and Array::resize(). The present method only asserts that the new size equals the old size, and does + * nothing else. + */ + void resize(Index nbRows, Index nbCols) + { + EIGEN_ONLY_USED_FOR_DEBUG(nbRows); + EIGEN_ONLY_USED_FOR_DEBUG(nbCols); + eigen_assert(nbRows == this->rows() && nbCols == this->cols() + && "DenseBase::resize() does not actually allow to resize."); + } + +#ifndef EIGEN_PARSED_BY_DOXYGEN + + /** \internal Represents a matrix with all coefficients equal to one another*/ + typedef CwiseNullaryOp,Derived> ConstantReturnType; + /** \internal Represents a vector with linearly spaced coefficients that allows sequential access only. */ + typedef CwiseNullaryOp,Derived> SequentialLinSpacedReturnType; + /** \internal Represents a vector with linearly spaced coefficients that allows random access. */ + typedef CwiseNullaryOp,Derived> RandomAccessLinSpacedReturnType; + /** \internal the return type of MatrixBase::eigenvalues() */ + typedef Matrix::Scalar>::Real, internal::traits::ColsAtCompileTime, 1> EigenvaluesReturnType; + +#endif // not EIGEN_PARSED_BY_DOXYGEN + + /** Copies \a other into *this. \returns a reference to *this. */ + template + Derived& operator=(const DenseBase& other); + + /** Special case of the template operator=, in order to prevent the compiler + * from generating a default operator= (issue hit with g++ 4.1) + */ + Derived& operator=(const DenseBase& other); + + template + Derived& operator=(const EigenBase &other); + + template + Derived& operator+=(const EigenBase &other); + + template + Derived& operator-=(const EigenBase &other); + + template + Derived& operator=(const ReturnByValue& func); + +#ifndef EIGEN_PARSED_BY_DOXYGEN + /** Copies \a other into *this without evaluating other. \returns a reference to *this. */ + template + Derived& lazyAssign(const DenseBase& other); +#endif // not EIGEN_PARSED_BY_DOXYGEN + + CommaInitializer operator<< (const Scalar& s); + + template + const Flagged flagged() const; + + template + CommaInitializer operator<< (const DenseBase& other); + + Eigen::Transpose transpose(); + typedef typename internal::add_const >::type ConstTransposeReturnType; + ConstTransposeReturnType transpose() const; + void transposeInPlace(); +#ifndef EIGEN_NO_DEBUG + protected: + template + void checkTransposeAliasing(const OtherDerived& other) const; + public: +#endif + + + static const ConstantReturnType + Constant(Index rows, Index cols, const Scalar& value); + static const ConstantReturnType + Constant(Index size, const Scalar& value); + static const ConstantReturnType + Constant(const Scalar& value); + + static const SequentialLinSpacedReturnType + LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high); + static const RandomAccessLinSpacedReturnType + LinSpaced(Index size, const Scalar& low, const Scalar& high); + static const SequentialLinSpacedReturnType + LinSpaced(Sequential_t, const Scalar& low, const Scalar& high); + static const RandomAccessLinSpacedReturnType + LinSpaced(const Scalar& low, const Scalar& high); + + template + static const CwiseNullaryOp + NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func); + template + static const CwiseNullaryOp + NullaryExpr(Index size, const CustomNullaryOp& func); + template + static const CwiseNullaryOp + NullaryExpr(const CustomNullaryOp& func); + + static const ConstantReturnType Zero(Index rows, Index cols); + static const ConstantReturnType Zero(Index size); + static const ConstantReturnType Zero(); + static const ConstantReturnType Ones(Index rows, Index cols); + static const ConstantReturnType Ones(Index size); + static const ConstantReturnType Ones(); + + void fill(const Scalar& value); + Derived& setConstant(const Scalar& value); + Derived& setLinSpaced(Index size, const Scalar& low, const Scalar& high); + Derived& setLinSpaced(const Scalar& low, const Scalar& high); + Derived& setZero(); + Derived& setOnes(); + Derived& setRandom(); + + template + bool isApprox(const DenseBase& other, + const RealScalar& prec = NumTraits::dummy_precision()) const; + bool isMuchSmallerThan(const RealScalar& other, + const RealScalar& prec = NumTraits::dummy_precision()) const; + template + bool isMuchSmallerThan(const DenseBase& other, + const RealScalar& prec = NumTraits::dummy_precision()) const; + + bool isApproxToConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; + bool isConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; + bool isZero(const RealScalar& prec = NumTraits::dummy_precision()) const; + bool isOnes(const RealScalar& prec = NumTraits::dummy_precision()) const; + + inline bool hasNaN() const; + inline bool allFinite() const; + + inline Derived& operator*=(const Scalar& other); + inline Derived& operator/=(const Scalar& other); + + typedef typename internal::add_const_on_value_type::type>::type EvalReturnType; + /** \returns the matrix or vector obtained by evaluating this expression. + * + * Notice that in the case of a plain matrix or vector (not an expression) this function just returns + * a const reference, in order to avoid a useless copy. + */ + EIGEN_STRONG_INLINE EvalReturnType eval() const + { + // Even though MSVC does not honor strong inlining when the return type + // is a dynamic matrix, we desperately need strong inlining for fixed + // size types on MSVC. + return typename internal::eval::type(derived()); + } + + /** swaps *this with the expression \a other. + * + */ + template + void swap(const DenseBase& other, + int = OtherDerived::ThisConstantIsPrivateInPlainObjectBase) + { + SwapWrapper(derived()).lazyAssign(other.derived()); + } + + /** swaps *this with the matrix or array \a other. + * + */ + template + void swap(PlainObjectBase& other) + { + SwapWrapper(derived()).lazyAssign(other.derived()); + } + + + inline const NestByValue nestByValue() const; + inline const ForceAlignedAccess forceAlignedAccess() const; + inline ForceAlignedAccess forceAlignedAccess(); + template inline const typename internal::conditional,Derived&>::type forceAlignedAccessIf() const; + template inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); + + Scalar sum() const; + Scalar mean() const; + Scalar trace() const; + + Scalar prod() const; + + typename internal::traits::Scalar minCoeff() const; + typename internal::traits::Scalar maxCoeff() const; + + template + typename internal::traits::Scalar minCoeff(IndexType* row, IndexType* col) const; + template + typename internal::traits::Scalar maxCoeff(IndexType* row, IndexType* col) const; + template + typename internal::traits::Scalar minCoeff(IndexType* index) const; + template + typename internal::traits::Scalar maxCoeff(IndexType* index) const; + + template + typename internal::result_of::Scalar)>::type + redux(const BinaryOp& func) const; + + template + void visit(Visitor& func) const; + + inline const WithFormat format(const IOFormat& fmt) const; + + /** \returns the unique coefficient of a 1x1 expression */ + CoeffReturnType value() const + { + EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) + eigen_assert(this->rows() == 1 && this->cols() == 1); + return derived().coeff(0,0); + } + + bool all(void) const; + bool any(void) const; + Index count() const; + + typedef VectorwiseOp RowwiseReturnType; + typedef const VectorwiseOp ConstRowwiseReturnType; + typedef VectorwiseOp ColwiseReturnType; + typedef const VectorwiseOp ConstColwiseReturnType; + + ConstRowwiseReturnType rowwise() const; + RowwiseReturnType rowwise(); + ConstColwiseReturnType colwise() const; + ColwiseReturnType colwise(); + + static const CwiseNullaryOp,Derived> Random(Index rows, Index cols); + static const CwiseNullaryOp,Derived> Random(Index size); + static const CwiseNullaryOp,Derived> Random(); + + template + const Select + select(const DenseBase& thenMatrix, + const DenseBase& elseMatrix) const; + + template + inline const Select + select(const DenseBase& thenMatrix, const typename ThenDerived::Scalar& elseScalar) const; + + template + inline const Select + select(const typename ElseDerived::Scalar& thenScalar, const DenseBase& elseMatrix) const; + + template RealScalar lpNorm() const; + + template + const Replicate replicate() const; + const Replicate replicate(Index rowFacor,Index colFactor) const; + + typedef Reverse ReverseReturnType; + typedef const Reverse ConstReverseReturnType; + ReverseReturnType reverse(); + ConstReverseReturnType reverse() const; + void reverseInPlace(); + +#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::DenseBase +# include "../plugins/BlockMethods.h" +# ifdef EIGEN_DENSEBASE_PLUGIN +# include EIGEN_DENSEBASE_PLUGIN +# endif +#undef EIGEN_CURRENT_STORAGE_BASE_CLASS + +#ifdef EIGEN2_SUPPORT + + Block corner(CornerType type, Index cRows, Index cCols); + const Block corner(CornerType type, Index cRows, Index cCols) const; + template + Block corner(CornerType type); + template + const Block corner(CornerType type) const; + +#endif // EIGEN2_SUPPORT + + + // disable the use of evalTo for dense objects with a nice compilation error + template inline void evalTo(Dest& ) const + { + EIGEN_STATIC_ASSERT((internal::is_same::value),THE_EVAL_EVALTO_FUNCTION_SHOULD_NEVER_BE_CALLED_FOR_DENSE_OBJECTS); + } + + protected: + /** Default constructor. Do nothing. */ + DenseBase() + { + /* Just checks for self-consistency of the flags. + * Only do it when debugging Eigen, as this borders on paranoiac and could slow compilation down + */ +#ifdef EIGEN_INTERNAL_DEBUGGING + EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, int(IsRowMajor)) + && EIGEN_IMPLIES(MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1, int(!IsRowMajor))), + INVALID_STORAGE_ORDER_FOR_THIS_VECTOR_EXPRESSION) +#endif + } + + private: + explicit DenseBase(int); + DenseBase(int,int); + template explicit DenseBase(const DenseBase&); +}; + +} // end namespace Eigen + +#endif // EIGEN_DENSEBASE_H diff --git a/libs/eigen3/Eigen/src/Core/DenseCoeffsBase.h b/libs/eigen3/Eigen/src/Core/DenseCoeffsBase.h new file mode 100644 index 000000000..3c890f215 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/DenseCoeffsBase.h @@ -0,0 +1,754 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2010 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_DENSECOEFFSBASE_H +#define EIGEN_DENSECOEFFSBASE_H + +namespace Eigen { + +namespace internal { +template struct add_const_on_value_type_if_arithmetic +{ + typedef typename conditional::value, T, typename add_const_on_value_type::type>::type type; +}; +} + +/** \brief Base class providing read-only coefficient access to matrices and arrays. + * \ingroup Core_Module + * \tparam Derived Type of the derived class + * \tparam #ReadOnlyAccessors Constant indicating read-only access + * + * This class defines the \c operator() \c const function and friends, which can be used to read specific + * entries of a matrix or array. + * + * \sa DenseCoeffsBase, DenseCoeffsBase, + * \ref TopicClassHierarchy + */ +template +class DenseCoeffsBase : public EigenBase +{ + public: + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::packet_traits::type PacketScalar; + + // Explanation for this CoeffReturnType typedef. + // - This is the return type of the coeff() method. + // - The LvalueBit means exactly that we can offer a coeffRef() method, which means exactly that we can get references + // to coeffs, which means exactly that we can have coeff() return a const reference (as opposed to returning a value). + // - The is_artihmetic check is required since "const int", "const double", etc. will cause warnings on some systems + // while the declaration of "const T", where T is a non arithmetic type does not. Always returning "const Scalar&" is + // not possible, since the underlying expressions might not offer a valid address the reference could be referring to. + typedef typename internal::conditional::Flags&LvalueBit), + const Scalar&, + typename internal::conditional::value, Scalar, const Scalar>::type + >::type CoeffReturnType; + + typedef typename internal::add_const_on_value_type_if_arithmetic< + typename internal::packet_traits::type + >::type PacketReturnType; + + typedef EigenBase Base; + using Base::rows; + using Base::cols; + using Base::size; + using Base::derived; + + EIGEN_STRONG_INLINE Index rowIndexByOuterInner(Index outer, Index inner) const + { + return int(Derived::RowsAtCompileTime) == 1 ? 0 + : int(Derived::ColsAtCompileTime) == 1 ? inner + : int(Derived::Flags)&RowMajorBit ? outer + : inner; + } + + EIGEN_STRONG_INLINE Index colIndexByOuterInner(Index outer, Index inner) const + { + return int(Derived::ColsAtCompileTime) == 1 ? 0 + : int(Derived::RowsAtCompileTime) == 1 ? inner + : int(Derived::Flags)&RowMajorBit ? inner + : outer; + } + + /** Short version: don't use this function, use + * \link operator()(Index,Index) const \endlink instead. + * + * Long version: this function is similar to + * \link operator()(Index,Index) const \endlink, but without the assertion. + * Use this for limiting the performance cost of debugging code when doing + * repeated coefficient access. Only use this when it is guaranteed that the + * parameters \a row and \a col are in range. + * + * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this + * function equivalent to \link operator()(Index,Index) const \endlink. + * + * \sa operator()(Index,Index) const, coeffRef(Index,Index), coeff(Index) const + */ + EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const + { + eigen_internal_assert(row >= 0 && row < rows() + && col >= 0 && col < cols()); + return derived().coeff(row, col); + } + + EIGEN_STRONG_INLINE CoeffReturnType coeffByOuterInner(Index outer, Index inner) const + { + return coeff(rowIndexByOuterInner(outer, inner), + colIndexByOuterInner(outer, inner)); + } + + /** \returns the coefficient at given the given row and column. + * + * \sa operator()(Index,Index), operator[](Index) + */ + EIGEN_STRONG_INLINE CoeffReturnType operator()(Index row, Index col) const + { + eigen_assert(row >= 0 && row < rows() + && col >= 0 && col < cols()); + return derived().coeff(row, col); + } + + /** Short version: don't use this function, use + * \link operator[](Index) const \endlink instead. + * + * Long version: this function is similar to + * \link operator[](Index) const \endlink, but without the assertion. + * Use this for limiting the performance cost of debugging code when doing + * repeated coefficient access. Only use this when it is guaranteed that the + * parameter \a index is in range. + * + * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this + * function equivalent to \link operator[](Index) const \endlink. + * + * \sa operator[](Index) const, coeffRef(Index), coeff(Index,Index) const + */ + + EIGEN_STRONG_INLINE CoeffReturnType + coeff(Index index) const + { + eigen_internal_assert(index >= 0 && index < size()); + return derived().coeff(index); + } + + + /** \returns the coefficient at given index. + * + * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. + * + * \sa operator[](Index), operator()(Index,Index) const, x() const, y() const, + * z() const, w() const + */ + + EIGEN_STRONG_INLINE CoeffReturnType + operator[](Index index) const + { + #ifndef EIGEN2_SUPPORT + EIGEN_STATIC_ASSERT(Derived::IsVectorAtCompileTime, + THE_BRACKET_OPERATOR_IS_ONLY_FOR_VECTORS__USE_THE_PARENTHESIS_OPERATOR_INSTEAD) + #endif + eigen_assert(index >= 0 && index < size()); + return derived().coeff(index); + } + + /** \returns the coefficient at given index. + * + * This is synonymous to operator[](Index) const. + * + * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. + * + * \sa operator[](Index), operator()(Index,Index) const, x() const, y() const, + * z() const, w() const + */ + + EIGEN_STRONG_INLINE CoeffReturnType + operator()(Index index) const + { + eigen_assert(index >= 0 && index < size()); + return derived().coeff(index); + } + + /** equivalent to operator[](0). */ + + EIGEN_STRONG_INLINE CoeffReturnType + x() const { return (*this)[0]; } + + /** equivalent to operator[](1). */ + + EIGEN_STRONG_INLINE CoeffReturnType + y() const { return (*this)[1]; } + + /** equivalent to operator[](2). */ + + EIGEN_STRONG_INLINE CoeffReturnType + z() const { return (*this)[2]; } + + /** equivalent to operator[](3). */ + + EIGEN_STRONG_INLINE CoeffReturnType + w() const { return (*this)[3]; } + + /** \internal + * \returns the packet of coefficients starting at the given row and column. It is your responsibility + * to ensure that a packet really starts there. This method is only available on expressions having the + * PacketAccessBit. + * + * The \a LoadMode parameter may have the value \a #Aligned or \a #Unaligned. Its effect is to select + * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets + * starting at an address which is a multiple of the packet size. + */ + + template + EIGEN_STRONG_INLINE PacketReturnType packet(Index row, Index col) const + { + eigen_internal_assert(row >= 0 && row < rows() + && col >= 0 && col < cols()); + return derived().template packet(row,col); + } + + + /** \internal */ + template + EIGEN_STRONG_INLINE PacketReturnType packetByOuterInner(Index outer, Index inner) const + { + return packet(rowIndexByOuterInner(outer, inner), + colIndexByOuterInner(outer, inner)); + } + + /** \internal + * \returns the packet of coefficients starting at the given index. It is your responsibility + * to ensure that a packet really starts there. This method is only available on expressions having the + * PacketAccessBit and the LinearAccessBit. + * + * The \a LoadMode parameter may have the value \a #Aligned or \a #Unaligned. Its effect is to select + * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets + * starting at an address which is a multiple of the packet size. + */ + + template + EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + eigen_internal_assert(index >= 0 && index < size()); + return derived().template packet(index); + } + + protected: + // explanation: DenseBase is doing "using ..." on the methods from DenseCoeffsBase. + // But some methods are only available in the DirectAccess case. + // So we add dummy methods here with these names, so that "using... " doesn't fail. + // It's not private so that the child class DenseBase can access them, and it's not public + // either since it's an implementation detail, so has to be protected. + void coeffRef(); + void coeffRefByOuterInner(); + void writePacket(); + void writePacketByOuterInner(); + void copyCoeff(); + void copyCoeffByOuterInner(); + void copyPacket(); + void copyPacketByOuterInner(); + void stride(); + void innerStride(); + void outerStride(); + void rowStride(); + void colStride(); +}; + +/** \brief Base class providing read/write coefficient access to matrices and arrays. + * \ingroup Core_Module + * \tparam Derived Type of the derived class + * \tparam #WriteAccessors Constant indicating read/write access + * + * This class defines the non-const \c operator() function and friends, which can be used to write specific + * entries of a matrix or array. This class inherits DenseCoeffsBase which + * defines the const variant for reading specific entries. + * + * \sa DenseCoeffsBase, \ref TopicClassHierarchy + */ +template +class DenseCoeffsBase : public DenseCoeffsBase +{ + public: + + typedef DenseCoeffsBase Base; + + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::packet_traits::type PacketScalar; + typedef typename NumTraits::Real RealScalar; + + using Base::coeff; + using Base::rows; + using Base::cols; + using Base::size; + using Base::derived; + using Base::rowIndexByOuterInner; + using Base::colIndexByOuterInner; + using Base::operator[]; + using Base::operator(); + using Base::x; + using Base::y; + using Base::z; + using Base::w; + + /** Short version: don't use this function, use + * \link operator()(Index,Index) \endlink instead. + * + * Long version: this function is similar to + * \link operator()(Index,Index) \endlink, but without the assertion. + * Use this for limiting the performance cost of debugging code when doing + * repeated coefficient access. Only use this when it is guaranteed that the + * parameters \a row and \a col are in range. + * + * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this + * function equivalent to \link operator()(Index,Index) \endlink. + * + * \sa operator()(Index,Index), coeff(Index, Index) const, coeffRef(Index) + */ + EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) + { + eigen_internal_assert(row >= 0 && row < rows() + && col >= 0 && col < cols()); + return derived().coeffRef(row, col); + } + + EIGEN_STRONG_INLINE Scalar& + coeffRefByOuterInner(Index outer, Index inner) + { + return coeffRef(rowIndexByOuterInner(outer, inner), + colIndexByOuterInner(outer, inner)); + } + + /** \returns a reference to the coefficient at given the given row and column. + * + * \sa operator[](Index) + */ + + EIGEN_STRONG_INLINE Scalar& + operator()(Index row, Index col) + { + eigen_assert(row >= 0 && row < rows() + && col >= 0 && col < cols()); + return derived().coeffRef(row, col); + } + + + /** Short version: don't use this function, use + * \link operator[](Index) \endlink instead. + * + * Long version: this function is similar to + * \link operator[](Index) \endlink, but without the assertion. + * Use this for limiting the performance cost of debugging code when doing + * repeated coefficient access. Only use this when it is guaranteed that the + * parameters \a row and \a col are in range. + * + * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this + * function equivalent to \link operator[](Index) \endlink. + * + * \sa operator[](Index), coeff(Index) const, coeffRef(Index,Index) + */ + + EIGEN_STRONG_INLINE Scalar& + coeffRef(Index index) + { + eigen_internal_assert(index >= 0 && index < size()); + return derived().coeffRef(index); + } + + /** \returns a reference to the coefficient at given index. + * + * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. + * + * \sa operator[](Index) const, operator()(Index,Index), x(), y(), z(), w() + */ + + EIGEN_STRONG_INLINE Scalar& + operator[](Index index) + { + #ifndef EIGEN2_SUPPORT + EIGEN_STATIC_ASSERT(Derived::IsVectorAtCompileTime, + THE_BRACKET_OPERATOR_IS_ONLY_FOR_VECTORS__USE_THE_PARENTHESIS_OPERATOR_INSTEAD) + #endif + eigen_assert(index >= 0 && index < size()); + return derived().coeffRef(index); + } + + /** \returns a reference to the coefficient at given index. + * + * This is synonymous to operator[](Index). + * + * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. + * + * \sa operator[](Index) const, operator()(Index,Index), x(), y(), z(), w() + */ + + EIGEN_STRONG_INLINE Scalar& + operator()(Index index) + { + eigen_assert(index >= 0 && index < size()); + return derived().coeffRef(index); + } + + /** equivalent to operator[](0). */ + + EIGEN_STRONG_INLINE Scalar& + x() { return (*this)[0]; } + + /** equivalent to operator[](1). */ + + EIGEN_STRONG_INLINE Scalar& + y() { return (*this)[1]; } + + /** equivalent to operator[](2). */ + + EIGEN_STRONG_INLINE Scalar& + z() { return (*this)[2]; } + + /** equivalent to operator[](3). */ + + EIGEN_STRONG_INLINE Scalar& + w() { return (*this)[3]; } + + /** \internal + * Stores the given packet of coefficients, at the given row and column of this expression. It is your responsibility + * to ensure that a packet really starts there. This method is only available on expressions having the + * PacketAccessBit. + * + * The \a LoadMode parameter may have the value \a #Aligned or \a #Unaligned. Its effect is to select + * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets + * starting at an address which is a multiple of the packet size. + */ + + template + EIGEN_STRONG_INLINE void writePacket + (Index row, Index col, const typename internal::packet_traits::type& val) + { + eigen_internal_assert(row >= 0 && row < rows() + && col >= 0 && col < cols()); + derived().template writePacket(row,col,val); + } + + + /** \internal */ + template + EIGEN_STRONG_INLINE void writePacketByOuterInner + (Index outer, Index inner, const typename internal::packet_traits::type& val) + { + writePacket(rowIndexByOuterInner(outer, inner), + colIndexByOuterInner(outer, inner), + val); + } + + /** \internal + * Stores the given packet of coefficients, at the given index in this expression. It is your responsibility + * to ensure that a packet really starts there. This method is only available on expressions having the + * PacketAccessBit and the LinearAccessBit. + * + * The \a LoadMode parameter may have the value \a Aligned or \a Unaligned. Its effect is to select + * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets + * starting at an address which is a multiple of the packet size. + */ + template + EIGEN_STRONG_INLINE void writePacket + (Index index, const typename internal::packet_traits::type& val) + { + eigen_internal_assert(index >= 0 && index < size()); + derived().template writePacket(index,val); + } + +#ifndef EIGEN_PARSED_BY_DOXYGEN + + /** \internal Copies the coefficient at position (row,col) of other into *this. + * + * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code + * with usual assignments. + * + * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. + */ + + template + EIGEN_STRONG_INLINE void copyCoeff(Index row, Index col, const DenseBase& other) + { + eigen_internal_assert(row >= 0 && row < rows() + && col >= 0 && col < cols()); + derived().coeffRef(row, col) = other.derived().coeff(row, col); + } + + /** \internal Copies the coefficient at the given index of other into *this. + * + * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code + * with usual assignments. + * + * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. + */ + + template + EIGEN_STRONG_INLINE void copyCoeff(Index index, const DenseBase& other) + { + eigen_internal_assert(index >= 0 && index < size()); + derived().coeffRef(index) = other.derived().coeff(index); + } + + + template + EIGEN_STRONG_INLINE void copyCoeffByOuterInner(Index outer, Index inner, const DenseBase& other) + { + const Index row = rowIndexByOuterInner(outer,inner); + const Index col = colIndexByOuterInner(outer,inner); + // derived() is important here: copyCoeff() may be reimplemented in Derived! + derived().copyCoeff(row, col, other); + } + + /** \internal Copies the packet at position (row,col) of other into *this. + * + * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code + * with usual assignments. + * + * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. + */ + + template + EIGEN_STRONG_INLINE void copyPacket(Index row, Index col, const DenseBase& other) + { + eigen_internal_assert(row >= 0 && row < rows() + && col >= 0 && col < cols()); + derived().template writePacket(row, col, + other.derived().template packet(row, col)); + } + + /** \internal Copies the packet at the given index of other into *this. + * + * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code + * with usual assignments. + * + * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. + */ + + template + EIGEN_STRONG_INLINE void copyPacket(Index index, const DenseBase& other) + { + eigen_internal_assert(index >= 0 && index < size()); + derived().template writePacket(index, + other.derived().template packet(index)); + } + + /** \internal */ + template + EIGEN_STRONG_INLINE void copyPacketByOuterInner(Index outer, Index inner, const DenseBase& other) + { + const Index row = rowIndexByOuterInner(outer,inner); + const Index col = colIndexByOuterInner(outer,inner); + // derived() is important here: copyCoeff() may be reimplemented in Derived! + derived().template copyPacket< OtherDerived, StoreMode, LoadMode>(row, col, other); + } +#endif + +}; + +/** \brief Base class providing direct read-only coefficient access to matrices and arrays. + * \ingroup Core_Module + * \tparam Derived Type of the derived class + * \tparam #DirectAccessors Constant indicating direct access + * + * This class defines functions to work with strides which can be used to access entries directly. This class + * inherits DenseCoeffsBase which defines functions to access entries read-only using + * \c operator() . + * + * \sa \ref TopicClassHierarchy + */ +template +class DenseCoeffsBase : public DenseCoeffsBase +{ + public: + + typedef DenseCoeffsBase Base; + typedef typename internal::traits::Index Index; + typedef typename internal::traits::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + + using Base::rows; + using Base::cols; + using Base::size; + using Base::derived; + + /** \returns the pointer increment between two consecutive elements within a slice in the inner direction. + * + * \sa outerStride(), rowStride(), colStride() + */ + inline Index innerStride() const + { + return derived().innerStride(); + } + + /** \returns the pointer increment between two consecutive inner slices (for example, between two consecutive columns + * in a column-major matrix). + * + * \sa innerStride(), rowStride(), colStride() + */ + inline Index outerStride() const + { + return derived().outerStride(); + } + + // FIXME shall we remove it ? + inline Index stride() const + { + return Derived::IsVectorAtCompileTime ? innerStride() : outerStride(); + } + + /** \returns the pointer increment between two consecutive rows. + * + * \sa innerStride(), outerStride(), colStride() + */ + inline Index rowStride() const + { + return Derived::IsRowMajor ? outerStride() : innerStride(); + } + + /** \returns the pointer increment between two consecutive columns. + * + * \sa innerStride(), outerStride(), rowStride() + */ + inline Index colStride() const + { + return Derived::IsRowMajor ? innerStride() : outerStride(); + } +}; + +/** \brief Base class providing direct read/write coefficient access to matrices and arrays. + * \ingroup Core_Module + * \tparam Derived Type of the derived class + * \tparam #DirectWriteAccessors Constant indicating direct access + * + * This class defines functions to work with strides which can be used to access entries directly. This class + * inherits DenseCoeffsBase which defines functions to access entries read/write using + * \c operator(). + * + * \sa \ref TopicClassHierarchy + */ +template +class DenseCoeffsBase + : public DenseCoeffsBase +{ + public: + + typedef DenseCoeffsBase Base; + typedef typename internal::traits::Index Index; + typedef typename internal::traits::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + + using Base::rows; + using Base::cols; + using Base::size; + using Base::derived; + + /** \returns the pointer increment between two consecutive elements within a slice in the inner direction. + * + * \sa outerStride(), rowStride(), colStride() + */ + inline Index innerStride() const + { + return derived().innerStride(); + } + + /** \returns the pointer increment between two consecutive inner slices (for example, between two consecutive columns + * in a column-major matrix). + * + * \sa innerStride(), rowStride(), colStride() + */ + inline Index outerStride() const + { + return derived().outerStride(); + } + + // FIXME shall we remove it ? + inline Index stride() const + { + return Derived::IsVectorAtCompileTime ? innerStride() : outerStride(); + } + + /** \returns the pointer increment between two consecutive rows. + * + * \sa innerStride(), outerStride(), colStride() + */ + inline Index rowStride() const + { + return Derived::IsRowMajor ? outerStride() : innerStride(); + } + + /** \returns the pointer increment between two consecutive columns. + * + * \sa innerStride(), outerStride(), rowStride() + */ + inline Index colStride() const + { + return Derived::IsRowMajor ? innerStride() : outerStride(); + } +}; + +namespace internal { + +template +struct first_aligned_impl +{ + static inline typename Derived::Index run(const Derived&) + { return 0; } +}; + +template +struct first_aligned_impl +{ + static inline typename Derived::Index run(const Derived& m) + { + return internal::first_aligned(&m.const_cast_derived().coeffRef(0,0), m.size()); + } +}; + +/** \internal \returns the index of the first element of the array that is well aligned for vectorization. + * + * There is also the variant first_aligned(const Scalar*, Integer) defined in Memory.h. See it for more + * documentation. + */ +template +static inline typename Derived::Index first_aligned(const Derived& m) +{ + return first_aligned_impl + + ::run(m); +} + +template::ret> +struct inner_stride_at_compile_time +{ + enum { ret = traits::InnerStrideAtCompileTime }; +}; + +template +struct inner_stride_at_compile_time +{ + enum { ret = 0 }; +}; + +template::ret> +struct outer_stride_at_compile_time +{ + enum { ret = traits::OuterStrideAtCompileTime }; +}; + +template +struct outer_stride_at_compile_time +{ + enum { ret = 0 }; +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_DENSECOEFFSBASE_H diff --git a/libs/eigen3/Eigen/src/Core/DenseStorage.h b/libs/eigen3/Eigen/src/Core/DenseStorage.h new file mode 100644 index 000000000..a72738e55 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/DenseStorage.h @@ -0,0 +1,339 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2006-2009 Benoit Jacob +// Copyright (C) 2010 Hauke Heibel +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_MATRIXSTORAGE_H +#define EIGEN_MATRIXSTORAGE_H + +#ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN + #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN EIGEN_DENSE_STORAGE_CTOR_PLUGIN; +#else + #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN +#endif + +namespace Eigen { + +namespace internal { + +struct constructor_without_unaligned_array_assert {}; + +template void check_static_allocation_size() +{ + // if EIGEN_STACK_ALLOCATION_LIMIT is defined to 0, then no limit + #if EIGEN_STACK_ALLOCATION_LIMIT + EIGEN_STATIC_ASSERT(Size * sizeof(T) <= EIGEN_STACK_ALLOCATION_LIMIT, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG); + #endif +} + +/** \internal + * Static array. If the MatrixOrArrayOptions require auto-alignment, the array will be automatically aligned: + * to 16 bytes boundary if the total size is a multiple of 16 bytes. + */ +template +struct plain_array +{ + T array[Size]; + + plain_array() + { + check_static_allocation_size(); + } + + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size(); + } +}; + +#if defined(EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT) + #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) +#elif EIGEN_GNUC_AT_LEAST(4,7) + // GCC 4.7 is too aggressive in its optimizations and remove the alignement test based on the fact the array is declared to be aligned. + // See this bug report: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53900 + // Hiding the origin of the array pointer behind a function argument seems to do the trick even if the function is inlined: + template + EIGEN_ALWAYS_INLINE PtrType eigen_unaligned_array_assert_workaround_gcc47(PtrType array) { return array; } + #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ + eigen_assert((reinterpret_cast(eigen_unaligned_array_assert_workaround_gcc47(array)) & sizemask) == 0 \ + && "this assertion is explained here: " \ + "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \ + " **** READ THIS WEB PAGE !!! ****"); +#else + #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ + eigen_assert((reinterpret_cast(array) & sizemask) == 0 \ + && "this assertion is explained here: " \ + "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \ + " **** READ THIS WEB PAGE !!! ****"); +#endif + +template +struct plain_array +{ + EIGEN_USER_ALIGN16 T array[Size]; + + plain_array() + { + EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(0xf); + check_static_allocation_size(); + } + + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size(); + } +}; + +template +struct plain_array +{ + EIGEN_USER_ALIGN16 T array[1]; + plain_array() {} + plain_array(constructor_without_unaligned_array_assert) {} +}; + +} // end namespace internal + +/** \internal + * + * \class DenseStorage + * \ingroup Core_Module + * + * \brief Stores the data of a matrix + * + * This class stores the data of fixed-size, dynamic-size or mixed matrices + * in a way as compact as possible. + * + * \sa Matrix + */ +template class DenseStorage; + +// purely fixed-size matrix +template class DenseStorage +{ + internal::plain_array m_data; + public: + inline DenseStorage() {} + inline DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(internal::constructor_without_unaligned_array_assert()) {} + inline DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} + inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); } + static inline DenseIndex rows(void) {return _Rows;} + static inline DenseIndex cols(void) {return _Cols;} + inline void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} + inline void resize(DenseIndex,DenseIndex,DenseIndex) {} + inline const T *data() const { return m_data.array; } + inline T *data() { return m_data.array; } +}; + +// null matrix +template class DenseStorage +{ + public: + inline DenseStorage() {} + inline DenseStorage(internal::constructor_without_unaligned_array_assert) {} + inline DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} + inline void swap(DenseStorage& ) {} + static inline DenseIndex rows(void) {return _Rows;} + static inline DenseIndex cols(void) {return _Cols;} + inline void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} + inline void resize(DenseIndex,DenseIndex,DenseIndex) {} + inline const T *data() const { return 0; } + inline T *data() { return 0; } +}; + +// more specializations for null matrices; these are necessary to resolve ambiguities +template class DenseStorage +: public DenseStorage { }; + +template class DenseStorage +: public DenseStorage { }; + +template class DenseStorage +: public DenseStorage { }; + +// dynamic-size matrix with fixed-size storage +template class DenseStorage +{ + internal::plain_array m_data; + DenseIndex m_rows; + DenseIndex m_cols; + public: + inline DenseStorage() : m_rows(0), m_cols(0) {} + inline DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0), m_cols(0) {} + inline DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) : m_rows(nbRows), m_cols(nbCols) {} + inline void swap(DenseStorage& other) + { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } + inline DenseIndex rows() const {return m_rows;} + inline DenseIndex cols() const {return m_cols;} + inline void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; } + inline void resize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; } + inline const T *data() const { return m_data.array; } + inline T *data() { return m_data.array; } +}; + +// dynamic-size matrix with fixed-size storage and fixed width +template class DenseStorage +{ + internal::plain_array m_data; + DenseIndex m_rows; + public: + inline DenseStorage() : m_rows(0) {} + inline DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0) {} + inline DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex) : m_rows(nbRows) {} + inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } + inline DenseIndex rows(void) const {return m_rows;} + inline DenseIndex cols(void) const {return _Cols;} + inline void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; } + inline void resize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; } + inline const T *data() const { return m_data.array; } + inline T *data() { return m_data.array; } +}; + +// dynamic-size matrix with fixed-size storage and fixed height +template class DenseStorage +{ + internal::plain_array m_data; + DenseIndex m_cols; + public: + inline DenseStorage() : m_cols(0) {} + inline DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(internal::constructor_without_unaligned_array_assert()), m_cols(0) {} + inline DenseStorage(DenseIndex, DenseIndex, DenseIndex nbCols) : m_cols(nbCols) {} + inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } + inline DenseIndex rows(void) const {return _Rows;} + inline DenseIndex cols(void) const {return m_cols;} + inline void conservativeResize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; } + inline void resize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; } + inline const T *data() const { return m_data.array; } + inline T *data() { return m_data.array; } +}; + +// purely dynamic matrix. +template class DenseStorage +{ + T *m_data; + DenseIndex m_rows; + DenseIndex m_cols; + public: + inline DenseStorage() : m_data(0), m_rows(0), m_cols(0) {} + inline DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(0), m_rows(0), m_cols(0) {} + inline DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) + : m_data(internal::conditional_aligned_new_auto(size)), m_rows(nbRows), m_cols(nbCols) + { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } + inline ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, m_rows*m_cols); } + inline void swap(DenseStorage& other) + { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } + inline DenseIndex rows(void) const {return m_rows;} + inline DenseIndex cols(void) const {return m_cols;} + inline void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) + { + m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*m_cols); + m_rows = nbRows; + m_cols = nbCols; + } + void resize(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) + { + if(size != m_rows*m_cols) + { + internal::conditional_aligned_delete_auto(m_data, m_rows*m_cols); + if (size) + m_data = internal::conditional_aligned_new_auto(size); + else + m_data = 0; + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN + } + m_rows = nbRows; + m_cols = nbCols; + } + inline const T *data() const { return m_data; } + inline T *data() { return m_data; } +}; + +// matrix with dynamic width and fixed height (so that matrix has dynamic size). +template class DenseStorage +{ + T *m_data; + DenseIndex m_cols; + public: + inline DenseStorage() : m_data(0), m_cols(0) {} + inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {} + inline DenseStorage(DenseIndex size, DenseIndex, DenseIndex nbCols) : m_data(internal::conditional_aligned_new_auto(size)), m_cols(nbCols) + { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } + inline ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Rows*m_cols); } + inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } + static inline DenseIndex rows(void) {return _Rows;} + inline DenseIndex cols(void) const {return m_cols;} + inline void conservativeResize(DenseIndex size, DenseIndex, DenseIndex nbCols) + { + m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, _Rows*m_cols); + m_cols = nbCols; + } + EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex, DenseIndex nbCols) + { + if(size != _Rows*m_cols) + { + internal::conditional_aligned_delete_auto(m_data, _Rows*m_cols); + if (size) + m_data = internal::conditional_aligned_new_auto(size); + else + m_data = 0; + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN + } + m_cols = nbCols; + } + inline const T *data() const { return m_data; } + inline T *data() { return m_data; } +}; + +// matrix with dynamic height and fixed width (so that matrix has dynamic size). +template class DenseStorage +{ + T *m_data; + DenseIndex m_rows; + public: + inline DenseStorage() : m_data(0), m_rows(0) {} + inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {} + inline DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex) : m_data(internal::conditional_aligned_new_auto(size)), m_rows(nbRows) + { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } + inline ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Cols*m_rows); } + inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } + inline DenseIndex rows(void) const {return m_rows;} + static inline DenseIndex cols(void) {return _Cols;} + inline void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex) + { + m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*_Cols); + m_rows = nbRows; + } + EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex nbRows, DenseIndex) + { + if(size != m_rows*_Cols) + { + internal::conditional_aligned_delete_auto(m_data, _Cols*m_rows); + if (size) + m_data = internal::conditional_aligned_new_auto(size); + else + m_data = 0; + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN + } + m_rows = nbRows; + } + inline const T *data() const { return m_data; } + inline T *data() { return m_data; } +}; + +} // end namespace Eigen + +#endif // EIGEN_MATRIX_H diff --git a/libs/eigen3/Eigen/src/Core/Diagonal.h b/libs/eigen3/Eigen/src/Core/Diagonal.h new file mode 100644 index 000000000..aab8007b3 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/Diagonal.h @@ -0,0 +1,237 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2007-2009 Benoit Jacob +// Copyright (C) 2009-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_DIAGONAL_H +#define EIGEN_DIAGONAL_H + +namespace Eigen { + +/** \class Diagonal + * \ingroup Core_Module + * + * \brief Expression of a diagonal/subdiagonal/superdiagonal in a matrix + * + * \param MatrixType the type of the object in which we are taking a sub/main/super diagonal + * \param DiagIndex the index of the sub/super diagonal. The default is 0 and it means the main diagonal. + * A positive value means a superdiagonal, a negative value means a subdiagonal. + * You can also use Dynamic so the index can be set at runtime. + * + * The matrix is not required to be square. + * + * This class represents an expression of the main diagonal, or any sub/super diagonal + * of a square matrix. It is the return type of MatrixBase::diagonal() and MatrixBase::diagonal(Index) and most of the + * time this is the only way it is used. + * + * \sa MatrixBase::diagonal(), MatrixBase::diagonal(Index) + */ + +namespace internal { +template +struct traits > + : traits +{ + typedef typename nested::type MatrixTypeNested; + typedef typename remove_reference::type _MatrixTypeNested; + typedef typename MatrixType::StorageKind StorageKind; + enum { + RowsAtCompileTime = (int(DiagIndex) == DynamicIndex || int(MatrixType::SizeAtCompileTime) == Dynamic) ? Dynamic + : (EIGEN_PLAIN_ENUM_MIN(MatrixType::RowsAtCompileTime - EIGEN_PLAIN_ENUM_MAX(-DiagIndex, 0), + MatrixType::ColsAtCompileTime - EIGEN_PLAIN_ENUM_MAX( DiagIndex, 0))), + ColsAtCompileTime = 1, + MaxRowsAtCompileTime = int(MatrixType::MaxSizeAtCompileTime) == Dynamic ? Dynamic + : DiagIndex == DynamicIndex ? EIGEN_SIZE_MIN_PREFER_FIXED(MatrixType::MaxRowsAtCompileTime, + MatrixType::MaxColsAtCompileTime) + : (EIGEN_PLAIN_ENUM_MIN(MatrixType::MaxRowsAtCompileTime - EIGEN_PLAIN_ENUM_MAX(-DiagIndex, 0), + MatrixType::MaxColsAtCompileTime - EIGEN_PLAIN_ENUM_MAX( DiagIndex, 0))), + MaxColsAtCompileTime = 1, + MaskLvalueBit = is_lvalue::value ? LvalueBit : 0, + Flags = (unsigned int)_MatrixTypeNested::Flags & (HereditaryBits | LinearAccessBit | MaskLvalueBit | DirectAccessBit) & ~RowMajorBit, + CoeffReadCost = _MatrixTypeNested::CoeffReadCost, + MatrixTypeOuterStride = outer_stride_at_compile_time::ret, + InnerStrideAtCompileTime = MatrixTypeOuterStride == Dynamic ? Dynamic : MatrixTypeOuterStride+1, + OuterStrideAtCompileTime = 0 + }; +}; +} + +template class Diagonal + : public internal::dense_xpr_base< Diagonal >::type +{ + public: + + enum { DiagIndex = _DiagIndex }; + typedef typename internal::dense_xpr_base::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Diagonal) + + inline Diagonal(MatrixType& matrix, Index a_index = DiagIndex) : m_matrix(matrix), m_index(a_index) {} + + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Diagonal) + + inline Index rows() const + { return m_index.value()<0 ? (std::min)(m_matrix.cols(),m_matrix.rows()+m_index.value()) : (std::min)(m_matrix.rows(),m_matrix.cols()-m_index.value()); } + + inline Index cols() const { return 1; } + + inline Index innerStride() const + { + return m_matrix.outerStride() + 1; + } + + inline Index outerStride() const + { + return 0; + } + + typedef typename internal::conditional< + internal::is_lvalue::value, + Scalar, + const Scalar + >::type ScalarWithConstIfNotLvalue; + + inline ScalarWithConstIfNotLvalue* data() { return &(m_matrix.const_cast_derived().coeffRef(rowOffset(), colOffset())); } + inline const Scalar* data() const { return &(m_matrix.const_cast_derived().coeffRef(rowOffset(), colOffset())); } + + inline Scalar& coeffRef(Index row, Index) + { + EIGEN_STATIC_ASSERT_LVALUE(MatrixType) + return m_matrix.const_cast_derived().coeffRef(row+rowOffset(), row+colOffset()); + } + + inline const Scalar& coeffRef(Index row, Index) const + { + return m_matrix.const_cast_derived().coeffRef(row+rowOffset(), row+colOffset()); + } + + inline CoeffReturnType coeff(Index row, Index) const + { + return m_matrix.coeff(row+rowOffset(), row+colOffset()); + } + + inline Scalar& coeffRef(Index idx) + { + EIGEN_STATIC_ASSERT_LVALUE(MatrixType) + return m_matrix.const_cast_derived().coeffRef(idx+rowOffset(), idx+colOffset()); + } + + inline const Scalar& coeffRef(Index idx) const + { + return m_matrix.const_cast_derived().coeffRef(idx+rowOffset(), idx+colOffset()); + } + + inline CoeffReturnType coeff(Index idx) const + { + return m_matrix.coeff(idx+rowOffset(), idx+colOffset()); + } + + const typename internal::remove_all::type& + nestedExpression() const + { + return m_matrix; + } + + int index() const + { + return m_index.value(); + } + + protected: + typename MatrixType::Nested m_matrix; + const internal::variable_if_dynamicindex m_index; + + private: + // some compilers may fail to optimize std::max etc in case of compile-time constants... + EIGEN_STRONG_INLINE Index absDiagIndex() const { return m_index.value()>0 ? m_index.value() : -m_index.value(); } + EIGEN_STRONG_INLINE Index rowOffset() const { return m_index.value()>0 ? 0 : -m_index.value(); } + EIGEN_STRONG_INLINE Index colOffset() const { return m_index.value()>0 ? m_index.value() : 0; } + // triger a compile time error is someone try to call packet + template typename MatrixType::PacketReturnType packet(Index) const; + template typename MatrixType::PacketReturnType packet(Index,Index) const; +}; + +/** \returns an expression of the main diagonal of the matrix \c *this + * + * \c *this is not required to be square. + * + * Example: \include MatrixBase_diagonal.cpp + * Output: \verbinclude MatrixBase_diagonal.out + * + * \sa class Diagonal */ +template +inline typename MatrixBase::DiagonalReturnType +MatrixBase::diagonal() +{ + return derived(); +} + +/** This is the const version of diagonal(). */ +template +inline typename MatrixBase::ConstDiagonalReturnType +MatrixBase::diagonal() const +{ + return ConstDiagonalReturnType(derived()); +} + +/** \returns an expression of the \a DiagIndex-th sub or super diagonal of the matrix \c *this + * + * \c *this is not required to be square. + * + * The template parameter \a DiagIndex represent a super diagonal if \a DiagIndex > 0 + * and a sub diagonal otherwise. \a DiagIndex == 0 is equivalent to the main diagonal. + * + * Example: \include MatrixBase_diagonal_int.cpp + * Output: \verbinclude MatrixBase_diagonal_int.out + * + * \sa MatrixBase::diagonal(), class Diagonal */ +template +inline typename MatrixBase::template DiagonalIndexReturnType::Type +MatrixBase::diagonal(Index index) +{ + return typename DiagonalIndexReturnType::Type(derived(), index); +} + +/** This is the const version of diagonal(Index). */ +template +inline typename MatrixBase::template ConstDiagonalIndexReturnType::Type +MatrixBase::diagonal(Index index) const +{ + return typename ConstDiagonalIndexReturnType::Type(derived(), index); +} + +/** \returns an expression of the \a DiagIndex-th sub or super diagonal of the matrix \c *this + * + * \c *this is not required to be square. + * + * The template parameter \a DiagIndex represent a super diagonal if \a DiagIndex > 0 + * and a sub diagonal otherwise. \a DiagIndex == 0 is equivalent to the main diagonal. + * + * Example: \include MatrixBase_diagonal_template_int.cpp + * Output: \verbinclude MatrixBase_diagonal_template_int.out + * + * \sa MatrixBase::diagonal(), class Diagonal */ +template +template +inline typename MatrixBase::template DiagonalIndexReturnType::Type +MatrixBase::diagonal() +{ + return derived(); +} + +/** This is the const version of diagonal(). */ +template +template +inline typename MatrixBase::template ConstDiagonalIndexReturnType::Type +MatrixBase::diagonal() const +{ + return derived(); +} + +} // end namespace Eigen + +#endif // EIGEN_DIAGONAL_H diff --git a/libs/eigen3/Eigen/src/Core/DiagonalMatrix.h b/libs/eigen3/Eigen/src/Core/DiagonalMatrix.h new file mode 100644 index 000000000..e6c220f41 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/DiagonalMatrix.h @@ -0,0 +1,313 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2007-2009 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_DIAGONALMATRIX_H +#define EIGEN_DIAGONALMATRIX_H + +namespace Eigen { + +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +class DiagonalBase : public EigenBase +{ + public: + typedef typename internal::traits::DiagonalVectorType DiagonalVectorType; + typedef typename DiagonalVectorType::Scalar Scalar; + typedef typename DiagonalVectorType::RealScalar RealScalar; + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + + enum { + RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, + ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, + MaxRowsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, + MaxColsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, + IsVectorAtCompileTime = 0, + Flags = 0 + }; + + typedef Matrix DenseMatrixType; + typedef DenseMatrixType DenseType; + typedef DiagonalMatrix PlainObject; + + inline const Derived& derived() const { return *static_cast(this); } + inline Derived& derived() { return *static_cast(this); } + + DenseMatrixType toDenseMatrix() const { return derived(); } + template + void evalTo(MatrixBase &other) const; + template + void addTo(MatrixBase &other) const + { other.diagonal() += diagonal(); } + template + void subTo(MatrixBase &other) const + { other.diagonal() -= diagonal(); } + + inline const DiagonalVectorType& diagonal() const { return derived().diagonal(); } + inline DiagonalVectorType& diagonal() { return derived().diagonal(); } + + inline Index rows() const { return diagonal().size(); } + inline Index cols() const { return diagonal().size(); } + + /** \returns the diagonal matrix product of \c *this by the matrix \a matrix. + */ + template + const DiagonalProduct + operator*(const MatrixBase &matrix) const + { + return DiagonalProduct(matrix.derived(), derived()); + } + + inline const DiagonalWrapper, const DiagonalVectorType> > + inverse() const + { + return diagonal().cwiseInverse(); + } + + inline const DiagonalWrapper, const DiagonalVectorType> > + operator*(const Scalar& scalar) const + { + return diagonal() * scalar; + } + friend inline const DiagonalWrapper, const DiagonalVectorType> > + operator*(const Scalar& scalar, const DiagonalBase& other) + { + return other.diagonal() * scalar; + } + + #ifdef EIGEN2_SUPPORT + template + bool isApprox(const DiagonalBase& other, typename NumTraits::Real precision = NumTraits::dummy_precision()) const + { + return diagonal().isApprox(other.diagonal(), precision); + } + template + bool isApprox(const MatrixBase& other, typename NumTraits::Real precision = NumTraits::dummy_precision()) const + { + return toDenseMatrix().isApprox(other, precision); + } + #endif +}; + +template +template +void DiagonalBase::evalTo(MatrixBase &other) const +{ + other.setZero(); + other.diagonal() = diagonal(); +} +#endif + +/** \class DiagonalMatrix + * \ingroup Core_Module + * + * \brief Represents a diagonal matrix with its storage + * + * \param _Scalar the type of coefficients + * \param SizeAtCompileTime the dimension of the matrix, or Dynamic + * \param MaxSizeAtCompileTime the dimension of the matrix, or Dynamic. This parameter is optional and defaults + * to SizeAtCompileTime. Most of the time, you do not need to specify it. + * + * \sa class DiagonalWrapper + */ + +namespace internal { +template +struct traits > + : traits > +{ + typedef Matrix<_Scalar,SizeAtCompileTime,1,0,MaxSizeAtCompileTime,1> DiagonalVectorType; + typedef Dense StorageKind; + typedef DenseIndex Index; + enum { + Flags = LvalueBit + }; +}; +} +template +class DiagonalMatrix + : public DiagonalBase > +{ + public: + #ifndef EIGEN_PARSED_BY_DOXYGEN + typedef typename internal::traits::DiagonalVectorType DiagonalVectorType; + typedef const DiagonalMatrix& Nested; + typedef _Scalar Scalar; + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + #endif + + protected: + + DiagonalVectorType m_diagonal; + + public: + + /** const version of diagonal(). */ + inline const DiagonalVectorType& diagonal() const { return m_diagonal; } + /** \returns a reference to the stored vector of diagonal coefficients. */ + inline DiagonalVectorType& diagonal() { return m_diagonal; } + + /** Default constructor without initialization */ + inline DiagonalMatrix() {} + + /** Constructs a diagonal matrix with given dimension */ + inline DiagonalMatrix(Index dim) : m_diagonal(dim) {} + + /** 2D constructor. */ + inline DiagonalMatrix(const Scalar& x, const Scalar& y) : m_diagonal(x,y) {} + + /** 3D constructor. */ + inline DiagonalMatrix(const Scalar& x, const Scalar& y, const Scalar& z) : m_diagonal(x,y,z) {} + + /** Copy constructor. */ + template + inline DiagonalMatrix(const DiagonalBase& other) : m_diagonal(other.diagonal()) {} + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** copy constructor. prevent a default copy constructor from hiding the other templated constructor */ + inline DiagonalMatrix(const DiagonalMatrix& other) : m_diagonal(other.diagonal()) {} + #endif + + /** generic constructor from expression of the diagonal coefficients */ + template + explicit inline DiagonalMatrix(const MatrixBase& other) : m_diagonal(other) + {} + + /** Copy operator. */ + template + DiagonalMatrix& operator=(const DiagonalBase& other) + { + m_diagonal = other.diagonal(); + return *this; + } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** This is a special case of the templated operator=. Its purpose is to + * prevent a default operator= from hiding the templated operator=. + */ + DiagonalMatrix& operator=(const DiagonalMatrix& other) + { + m_diagonal = other.diagonal(); + return *this; + } + #endif + + /** Resizes to given size. */ + inline void resize(Index size) { m_diagonal.resize(size); } + /** Sets all coefficients to zero. */ + inline void setZero() { m_diagonal.setZero(); } + /** Resizes and sets all coefficients to zero. */ + inline void setZero(Index size) { m_diagonal.setZero(size); } + /** Sets this matrix to be the identity matrix of the current size. */ + inline void setIdentity() { m_diagonal.setOnes(); } + /** Sets this matrix to be the identity matrix of the given size. */ + inline void setIdentity(Index size) { m_diagonal.setOnes(size); } +}; + +/** \class DiagonalWrapper + * \ingroup Core_Module + * + * \brief Expression of a diagonal matrix + * + * \param _DiagonalVectorType the type of the vector of diagonal coefficients + * + * This class is an expression of a diagonal matrix, but not storing its own vector of diagonal coefficients, + * instead wrapping an existing vector expression. It is the return type of MatrixBase::asDiagonal() + * and most of the time this is the only way that it is used. + * + * \sa class DiagonalMatrix, class DiagonalBase, MatrixBase::asDiagonal() + */ + +namespace internal { +template +struct traits > +{ + typedef _DiagonalVectorType DiagonalVectorType; + typedef typename DiagonalVectorType::Scalar Scalar; + typedef typename DiagonalVectorType::Index Index; + typedef typename DiagonalVectorType::StorageKind StorageKind; + enum { + RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, + ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, + MaxRowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, + MaxColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, + Flags = traits::Flags & LvalueBit + }; +}; +} + +template +class DiagonalWrapper + : public DiagonalBase >, internal::no_assignment_operator +{ + public: + #ifndef EIGEN_PARSED_BY_DOXYGEN + typedef _DiagonalVectorType DiagonalVectorType; + typedef DiagonalWrapper Nested; + #endif + + /** Constructor from expression of diagonal coefficients to wrap. */ + inline DiagonalWrapper(DiagonalVectorType& a_diagonal) : m_diagonal(a_diagonal) {} + + /** \returns a const reference to the wrapped expression of diagonal coefficients. */ + const DiagonalVectorType& diagonal() const { return m_diagonal; } + + protected: + typename DiagonalVectorType::Nested m_diagonal; +}; + +/** \returns a pseudo-expression of a diagonal matrix with *this as vector of diagonal coefficients + * + * \only_for_vectors + * + * Example: \include MatrixBase_asDiagonal.cpp + * Output: \verbinclude MatrixBase_asDiagonal.out + * + * \sa class DiagonalWrapper, class DiagonalMatrix, diagonal(), isDiagonal() + **/ +template +inline const DiagonalWrapper +MatrixBase::asDiagonal() const +{ + return derived(); +} + +/** \returns true if *this is approximately equal to a diagonal matrix, + * within the precision given by \a prec. + * + * Example: \include MatrixBase_isDiagonal.cpp + * Output: \verbinclude MatrixBase_isDiagonal.out + * + * \sa asDiagonal() + */ +template +bool MatrixBase::isDiagonal(const RealScalar& prec) const +{ + using std::abs; + if(cols() != rows()) return false; + RealScalar maxAbsOnDiagonal = static_cast(-1); + for(Index j = 0; j < cols(); ++j) + { + RealScalar absOnDiagonal = abs(coeff(j,j)); + if(absOnDiagonal > maxAbsOnDiagonal) maxAbsOnDiagonal = absOnDiagonal; + } + for(Index j = 0; j < cols(); ++j) + for(Index i = 0; i < j; ++i) + { + if(!internal::isMuchSmallerThan(coeff(i, j), maxAbsOnDiagonal, prec)) return false; + if(!internal::isMuchSmallerThan(coeff(j, i), maxAbsOnDiagonal, prec)) return false; + } + return true; +} + +} // end namespace Eigen + +#endif // EIGEN_DIAGONALMATRIX_H diff --git a/libs/eigen3/Eigen/src/Core/DiagonalProduct.h b/libs/eigen3/Eigen/src/Core/DiagonalProduct.h new file mode 100644 index 000000000..c03a0c2e1 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/DiagonalProduct.h @@ -0,0 +1,130 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2007-2009 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_DIAGONALPRODUCT_H +#define EIGEN_DIAGONALPRODUCT_H + +namespace Eigen { + +namespace internal { +template +struct traits > + : traits +{ + typedef typename scalar_product_traits::ReturnType Scalar; + enum { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime, + MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, + + _StorageOrder = MatrixType::Flags & RowMajorBit ? RowMajor : ColMajor, + _ScalarAccessOnDiag = !((int(_StorageOrder) == ColMajor && int(ProductOrder) == OnTheLeft) + ||(int(_StorageOrder) == RowMajor && int(ProductOrder) == OnTheRight)), + _SameTypes = is_same::value, + // FIXME currently we need same types, but in the future the next rule should be the one + //_Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && ((!_PacketOnDiag) || (_SameTypes && bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))), + _Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))), + _LinearAccessMask = (RowsAtCompileTime==1 || ColsAtCompileTime==1) ? LinearAccessBit : 0, + + Flags = ((HereditaryBits|_LinearAccessMask) & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0) | AlignedBit,//(int(MatrixType::Flags)&int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit), + CoeffReadCost = NumTraits::MulCost + MatrixType::CoeffReadCost + DiagonalType::DiagonalVectorType::CoeffReadCost + }; +}; +} + +template +class DiagonalProduct : internal::no_assignment_operator, + public MatrixBase > +{ + public: + + typedef MatrixBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(DiagonalProduct) + + inline DiagonalProduct(const MatrixType& matrix, const DiagonalType& diagonal) + : m_matrix(matrix), m_diagonal(diagonal) + { + eigen_assert(diagonal.diagonal().size() == (ProductOrder == OnTheLeft ? matrix.rows() : matrix.cols())); + } + + EIGEN_STRONG_INLINE Index rows() const { return m_matrix.rows(); } + EIGEN_STRONG_INLINE Index cols() const { return m_matrix.cols(); } + + EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const + { + return m_diagonal.diagonal().coeff(ProductOrder == OnTheLeft ? row : col) * m_matrix.coeff(row, col); + } + + EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const + { + enum { + StorageOrder = int(MatrixType::Flags) & RowMajorBit ? RowMajor : ColMajor + }; + return coeff(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); + } + + template + EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const + { + enum { + StorageOrder = Flags & RowMajorBit ? RowMajor : ColMajor + }; + const Index indexInDiagonalVector = ProductOrder == OnTheLeft ? row : col; + return packet_impl(row,col,indexInDiagonalVector,typename internal::conditional< + ((int(StorageOrder) == RowMajor && int(ProductOrder) == OnTheLeft) + ||(int(StorageOrder) == ColMajor && int(ProductOrder) == OnTheRight)), internal::true_type, internal::false_type>::type()); + } + + template + EIGEN_STRONG_INLINE PacketScalar packet(Index idx) const + { + enum { + StorageOrder = int(MatrixType::Flags) & RowMajorBit ? RowMajor : ColMajor + }; + return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); + } + + protected: + template + EIGEN_STRONG_INLINE PacketScalar packet_impl(Index row, Index col, Index id, internal::true_type) const + { + return internal::pmul(m_matrix.template packet(row, col), + internal::pset1(m_diagonal.diagonal().coeff(id))); + } + + template + EIGEN_STRONG_INLINE PacketScalar packet_impl(Index row, Index col, Index id, internal::false_type) const + { + enum { + InnerSize = (MatrixType::Flags & RowMajorBit) ? MatrixType::ColsAtCompileTime : MatrixType::RowsAtCompileTime, + DiagonalVectorPacketLoadMode = (LoadMode == Aligned && (((InnerSize%16) == 0) || (int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit)==AlignedBit) ? Aligned : Unaligned) + }; + return internal::pmul(m_matrix.template packet(row, col), + m_diagonal.diagonal().template packet(id)); + } + + typename MatrixType::Nested m_matrix; + typename DiagonalType::Nested m_diagonal; +}; + +/** \returns the diagonal matrix product of \c *this by the diagonal matrix \a diagonal. + */ +template +template +inline const DiagonalProduct +MatrixBase::operator*(const DiagonalBase &a_diagonal) const +{ + return DiagonalProduct(derived(), a_diagonal.derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_DIAGONALPRODUCT_H diff --git a/libs/eigen3/Eigen/src/Core/Dot.h b/libs/eigen3/Eigen/src/Core/Dot.h new file mode 100644 index 000000000..9d7651f1f --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/Dot.h @@ -0,0 +1,263 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2008, 2010 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_DOT_H +#define EIGEN_DOT_H + +namespace Eigen { + +namespace internal { + +// helper function for dot(). The problem is that if we put that in the body of dot(), then upon calling dot +// with mismatched types, the compiler emits errors about failing to instantiate cwiseProduct BEFORE +// looking at the static assertions. Thus this is a trick to get better compile errors. +template +struct dot_nocheck +{ + typedef typename scalar_product_traits::Scalar,typename traits::Scalar>::ReturnType ResScalar; + static inline ResScalar run(const MatrixBase& a, const MatrixBase& b) + { + return a.template binaryExpr::Scalar,typename traits::Scalar> >(b).sum(); + } +}; + +template +struct dot_nocheck +{ + typedef typename scalar_product_traits::Scalar,typename traits::Scalar>::ReturnType ResScalar; + static inline ResScalar run(const MatrixBase& a, const MatrixBase& b) + { + return a.transpose().template binaryExpr::Scalar,typename traits::Scalar> >(b).sum(); + } +}; + +} // end namespace internal + +/** \returns the dot product of *this with other. + * + * \only_for_vectors + * + * \note If the scalar type is complex numbers, then this function returns the hermitian + * (sesquilinear) dot product, conjugate-linear in the first variable and linear in the + * second variable. + * + * \sa squaredNorm(), norm() + */ +template +template +typename internal::scalar_product_traits::Scalar,typename internal::traits::Scalar>::ReturnType +MatrixBase::dot(const MatrixBase& other) const +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) + EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived) + typedef internal::scalar_conj_product_op func; + EIGEN_CHECK_BINARY_COMPATIBILIY(func,Scalar,typename OtherDerived::Scalar); + + eigen_assert(size() == other.size()); + + return internal::dot_nocheck::run(*this, other); +} + +#ifdef EIGEN2_SUPPORT +/** \returns the dot product of *this with other, with the Eigen2 convention that the dot product is linear in the first variable + * (conjugating the second variable). Of course this only makes a difference in the complex case. + * + * This method is only available in EIGEN2_SUPPORT mode. + * + * \only_for_vectors + * + * \sa dot() + */ +template +template +typename internal::traits::Scalar +MatrixBase::eigen2_dot(const MatrixBase& other) const +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) + EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived) + EIGEN_STATIC_ASSERT((internal::is_same::value), + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + + eigen_assert(size() == other.size()); + + return internal::dot_nocheck::run(other,*this); +} +#endif + + +//---------- implementation of L2 norm and related functions ---------- + +/** \returns, for vectors, the squared \em l2 norm of \c *this, and for matrices the Frobenius norm. + * In both cases, it consists in the sum of the square of all the matrix entries. + * For vectors, this is also equals to the dot product of \c *this with itself. + * + * \sa dot(), norm() + */ +template +EIGEN_STRONG_INLINE typename NumTraits::Scalar>::Real MatrixBase::squaredNorm() const +{ + return numext::real((*this).cwiseAbs2().sum()); +} + +/** \returns, for vectors, the \em l2 norm of \c *this, and for matrices the Frobenius norm. + * In both cases, it consists in the square root of the sum of the square of all the matrix entries. + * For vectors, this is also equals to the square root of the dot product of \c *this with itself. + * + * \sa dot(), squaredNorm() + */ +template +inline typename NumTraits::Scalar>::Real MatrixBase::norm() const +{ + using std::sqrt; + return sqrt(squaredNorm()); +} + +/** \returns an expression of the quotient of *this by its own norm. + * + * \only_for_vectors + * + * \sa norm(), normalize() + */ +template +inline const typename MatrixBase::PlainObject +MatrixBase::normalized() const +{ + typedef typename internal::nested::type Nested; + typedef typename internal::remove_reference::type _Nested; + _Nested n(derived()); + return n / n.norm(); +} + +/** Normalizes the vector, i.e. divides it by its own norm. + * + * \only_for_vectors + * + * \sa norm(), normalized() + */ +template +inline void MatrixBase::normalize() +{ + *this /= norm(); +} + +//---------- implementation of other norms ---------- + +namespace internal { + +template +struct lpNorm_selector +{ + typedef typename NumTraits::Scalar>::Real RealScalar; + static inline RealScalar run(const MatrixBase& m) + { + using std::pow; + return pow(m.cwiseAbs().array().pow(p).sum(), RealScalar(1)/p); + } +}; + +template +struct lpNorm_selector +{ + static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) + { + return m.cwiseAbs().sum(); + } +}; + +template +struct lpNorm_selector +{ + static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) + { + return m.norm(); + } +}; + +template +struct lpNorm_selector +{ + static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) + { + return m.cwiseAbs().maxCoeff(); + } +}; + +} // end namespace internal + +/** \returns the \f$ \ell^p \f$ norm of *this, that is, returns the p-th root of the sum of the p-th powers of the absolute values + * of the coefficients of *this. If \a p is the special value \a Eigen::Infinity, this function returns the \f$ \ell^\infty \f$ + * norm, that is the maximum of the absolute values of the coefficients of *this. + * + * \sa norm() + */ +template +template +inline typename NumTraits::Scalar>::Real +MatrixBase::lpNorm() const +{ + return internal::lpNorm_selector::run(*this); +} + +//---------- implementation of isOrthogonal / isUnitary ---------- + +/** \returns true if *this is approximately orthogonal to \a other, + * within the precision given by \a prec. + * + * Example: \include MatrixBase_isOrthogonal.cpp + * Output: \verbinclude MatrixBase_isOrthogonal.out + */ +template +template +bool MatrixBase::isOrthogonal +(const MatrixBase& other, const RealScalar& prec) const +{ + typename internal::nested::type nested(derived()); + typename internal::nested::type otherNested(other.derived()); + return numext::abs2(nested.dot(otherNested)) <= prec * prec * nested.squaredNorm() * otherNested.squaredNorm(); +} + +/** \returns true if *this is approximately an unitary matrix, + * within the precision given by \a prec. In the case where the \a Scalar + * type is real numbers, a unitary matrix is an orthogonal matrix, whence the name. + * + * \note This can be used to check whether a family of vectors forms an orthonormal basis. + * Indeed, \c m.isUnitary() returns true if and only if the columns (equivalently, the rows) of m form an + * orthonormal basis. + * + * Example: \include MatrixBase_isUnitary.cpp + * Output: \verbinclude MatrixBase_isUnitary.out + */ +template +bool MatrixBase::isUnitary(const RealScalar& prec) const +{ + typename Derived::Nested nested(derived()); + for(Index i = 0; i < cols(); ++i) + { + if(!internal::isApprox(nested.col(i).squaredNorm(), static_cast(1), prec)) + return false; + for(Index j = 0; j < i; ++j) + if(!internal::isMuchSmallerThan(nested.col(i).dot(nested.col(j)), static_cast(1), prec)) + return false; + } + return true; +} + +} // end namespace Eigen + +#endif // EIGEN_DOT_H diff --git a/libs/eigen3/Eigen/src/Core/EigenBase.h b/libs/eigen3/Eigen/src/Core/EigenBase.h new file mode 100644 index 000000000..fadb45852 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/EigenBase.h @@ -0,0 +1,131 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Benoit Jacob +// Copyright (C) 2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_EIGENBASE_H +#define EIGEN_EIGENBASE_H + +namespace Eigen { + +/** Common base class for all classes T such that MatrixBase has an operator=(T) and a constructor MatrixBase(T). + * + * In other words, an EigenBase object is an object that can be copied into a MatrixBase. + * + * Besides MatrixBase-derived classes, this also includes special matrix classes such as diagonal matrices, etc. + * + * Notice that this class is trivial, it is only used to disambiguate overloaded functions. + * + * \sa \ref TopicClassHierarchy + */ +template struct EigenBase +{ +// typedef typename internal::plain_matrix_type::type PlainObject; + + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + + /** \returns a reference to the derived object */ + Derived& derived() { return *static_cast(this); } + /** \returns a const reference to the derived object */ + const Derived& derived() const { return *static_cast(this); } + + inline Derived& const_cast_derived() const + { return *static_cast(const_cast(this)); } + inline const Derived& const_derived() const + { return *static_cast(this); } + + /** \returns the number of rows. \sa cols(), RowsAtCompileTime */ + inline Index rows() const { return derived().rows(); } + /** \returns the number of columns. \sa rows(), ColsAtCompileTime*/ + inline Index cols() const { return derived().cols(); } + /** \returns the number of coefficients, which is rows()*cols(). + * \sa rows(), cols(), SizeAtCompileTime. */ + inline Index size() const { return rows() * cols(); } + + /** \internal Don't use it, but do the equivalent: \code dst = *this; \endcode */ + template inline void evalTo(Dest& dst) const + { derived().evalTo(dst); } + + /** \internal Don't use it, but do the equivalent: \code dst += *this; \endcode */ + template inline void addTo(Dest& dst) const + { + // This is the default implementation, + // derived class can reimplement it in a more optimized way. + typename Dest::PlainObject res(rows(),cols()); + evalTo(res); + dst += res; + } + + /** \internal Don't use it, but do the equivalent: \code dst -= *this; \endcode */ + template inline void subTo(Dest& dst) const + { + // This is the default implementation, + // derived class can reimplement it in a more optimized way. + typename Dest::PlainObject res(rows(),cols()); + evalTo(res); + dst -= res; + } + + /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheRight(*this); \endcode */ + template inline void applyThisOnTheRight(Dest& dst) const + { + // This is the default implementation, + // derived class can reimplement it in a more optimized way. + dst = dst * this->derived(); + } + + /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheLeft(*this); \endcode */ + template inline void applyThisOnTheLeft(Dest& dst) const + { + // This is the default implementation, + // derived class can reimplement it in a more optimized way. + dst = this->derived() * dst; + } + +}; + +/*************************************************************************** +* Implementation of matrix base methods +***************************************************************************/ + +/** \brief Copies the generic expression \a other into *this. + * + * \details The expression must provide a (templated) evalTo(Derived& dst) const + * function which does the actual job. In practice, this allows any user to write + * its own special matrix without having to modify MatrixBase + * + * \returns a reference to *this. + */ +template +template +Derived& DenseBase::operator=(const EigenBase &other) +{ + other.derived().evalTo(derived()); + return derived(); +} + +template +template +Derived& DenseBase::operator+=(const EigenBase &other) +{ + other.derived().addTo(derived()); + return derived(); +} + +template +template +Derived& DenseBase::operator-=(const EigenBase &other) +{ + other.derived().subTo(derived()); + return derived(); +} + +} // end namespace Eigen + +#endif // EIGEN_EIGENBASE_H diff --git a/libs/eigen3/Eigen/src/Core/Flagged.h b/libs/eigen3/Eigen/src/Core/Flagged.h new file mode 100644 index 000000000..1f2955fc1 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/Flagged.h @@ -0,0 +1,140 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_FLAGGED_H +#define EIGEN_FLAGGED_H + +namespace Eigen { + +/** \class Flagged + * \ingroup Core_Module + * + * \brief Expression with modified flags + * + * \param ExpressionType the type of the object of which we are modifying the flags + * \param Added the flags added to the expression + * \param Removed the flags removed from the expression (has priority over Added). + * + * This class represents an expression whose flags have been modified. + * It is the return type of MatrixBase::flagged() + * and most of the time this is the only way it is used. + * + * \sa MatrixBase::flagged() + */ + +namespace internal { +template +struct traits > : traits +{ + enum { Flags = (ExpressionType::Flags | Added) & ~Removed }; +}; +} + +template class Flagged + : public MatrixBase > +{ + public: + + typedef MatrixBase Base; + + EIGEN_DENSE_PUBLIC_INTERFACE(Flagged) + typedef typename internal::conditional::ret, + ExpressionType, const ExpressionType&>::type ExpressionTypeNested; + typedef typename ExpressionType::InnerIterator InnerIterator; + + inline Flagged(const ExpressionType& matrix) : m_matrix(matrix) {} + + inline Index rows() const { return m_matrix.rows(); } + inline Index cols() const { return m_matrix.cols(); } + inline Index outerStride() const { return m_matrix.outerStride(); } + inline Index innerStride() const { return m_matrix.innerStride(); } + + inline CoeffReturnType coeff(Index row, Index col) const + { + return m_matrix.coeff(row, col); + } + + inline CoeffReturnType coeff(Index index) const + { + return m_matrix.coeff(index); + } + + inline const Scalar& coeffRef(Index row, Index col) const + { + return m_matrix.const_cast_derived().coeffRef(row, col); + } + + inline const Scalar& coeffRef(Index index) const + { + return m_matrix.const_cast_derived().coeffRef(index); + } + + inline Scalar& coeffRef(Index row, Index col) + { + return m_matrix.const_cast_derived().coeffRef(row, col); + } + + inline Scalar& coeffRef(Index index) + { + return m_matrix.const_cast_derived().coeffRef(index); + } + + template + inline const PacketScalar packet(Index row, Index col) const + { + return m_matrix.template packet(row, col); + } + + template + inline void writePacket(Index row, Index col, const PacketScalar& x) + { + m_matrix.const_cast_derived().template writePacket(row, col, x); + } + + template + inline const PacketScalar packet(Index index) const + { + return m_matrix.template packet(index); + } + + template + inline void writePacket(Index index, const PacketScalar& x) + { + m_matrix.const_cast_derived().template writePacket(index, x); + } + + const ExpressionType& _expression() const { return m_matrix; } + + template + typename ExpressionType::PlainObject solveTriangular(const MatrixBase& other) const; + + template + void solveTriangularInPlace(const MatrixBase& other) const; + + protected: + ExpressionTypeNested m_matrix; +}; + +/** \returns an expression of *this with added and removed flags + * + * This is mostly for internal use. + * + * \sa class Flagged + */ +template +template +inline const Flagged +DenseBase::flagged() const +{ + return derived(); +} + +} // end namespace Eigen + +#endif // EIGEN_FLAGGED_H diff --git a/libs/eigen3/Eigen/src/Core/ForceAlignedAccess.h b/libs/eigen3/Eigen/src/Core/ForceAlignedAccess.h new file mode 100644 index 000000000..807c7a293 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/ForceAlignedAccess.h @@ -0,0 +1,146 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_FORCEALIGNEDACCESS_H +#define EIGEN_FORCEALIGNEDACCESS_H + +namespace Eigen { + +/** \class ForceAlignedAccess + * \ingroup Core_Module + * + * \brief Enforce aligned packet loads and stores regardless of what is requested + * + * \param ExpressionType the type of the object of which we are forcing aligned packet access + * + * This class is the return type of MatrixBase::forceAlignedAccess() + * and most of the time this is the only way it is used. + * + * \sa MatrixBase::forceAlignedAccess() + */ + +namespace internal { +template +struct traits > : public traits +{}; +} + +template class ForceAlignedAccess + : public internal::dense_xpr_base< ForceAlignedAccess >::type +{ + public: + + typedef typename internal::dense_xpr_base::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(ForceAlignedAccess) + + inline ForceAlignedAccess(const ExpressionType& matrix) : m_expression(matrix) {} + + inline Index rows() const { return m_expression.rows(); } + inline Index cols() const { return m_expression.cols(); } + inline Index outerStride() const { return m_expression.outerStride(); } + inline Index innerStride() const { return m_expression.innerStride(); } + + inline const CoeffReturnType coeff(Index row, Index col) const + { + return m_expression.coeff(row, col); + } + + inline Scalar& coeffRef(Index row, Index col) + { + return m_expression.const_cast_derived().coeffRef(row, col); + } + + inline const CoeffReturnType coeff(Index index) const + { + return m_expression.coeff(index); + } + + inline Scalar& coeffRef(Index index) + { + return m_expression.const_cast_derived().coeffRef(index); + } + + template + inline const PacketScalar packet(Index row, Index col) const + { + return m_expression.template packet(row, col); + } + + template + inline void writePacket(Index row, Index col, const PacketScalar& x) + { + m_expression.const_cast_derived().template writePacket(row, col, x); + } + + template + inline const PacketScalar packet(Index index) const + { + return m_expression.template packet(index); + } + + template + inline void writePacket(Index index, const PacketScalar& x) + { + m_expression.const_cast_derived().template writePacket(index, x); + } + + operator const ExpressionType&() const { return m_expression; } + + protected: + const ExpressionType& m_expression; + + private: + ForceAlignedAccess& operator=(const ForceAlignedAccess&); +}; + +/** \returns an expression of *this with forced aligned access + * \sa forceAlignedAccessIf(),class ForceAlignedAccess + */ +template +inline const ForceAlignedAccess +MatrixBase::forceAlignedAccess() const +{ + return ForceAlignedAccess(derived()); +} + +/** \returns an expression of *this with forced aligned access + * \sa forceAlignedAccessIf(), class ForceAlignedAccess + */ +template +inline ForceAlignedAccess +MatrixBase::forceAlignedAccess() +{ + return ForceAlignedAccess(derived()); +} + +/** \returns an expression of *this with forced aligned access if \a Enable is true. + * \sa forceAlignedAccess(), class ForceAlignedAccess + */ +template +template +inline typename internal::add_const_on_value_type,Derived&>::type>::type +MatrixBase::forceAlignedAccessIf() const +{ + return derived(); +} + +/** \returns an expression of *this with forced aligned access if \a Enable is true. + * \sa forceAlignedAccess(), class ForceAlignedAccess + */ +template +template +inline typename internal::conditional,Derived&>::type +MatrixBase::forceAlignedAccessIf() +{ + return derived(); +} + +} // end namespace Eigen + +#endif // EIGEN_FORCEALIGNEDACCESS_H diff --git a/libs/eigen3/Eigen/src/Core/Functors.h b/libs/eigen3/Eigen/src/Core/Functors.h new file mode 100644 index 000000000..b08b967ff --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/Functors.h @@ -0,0 +1,985 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_FUNCTORS_H +#define EIGEN_FUNCTORS_H + +namespace Eigen { + +namespace internal { + +// associative functors: + +/** \internal + * \brief Template functor to compute the sum of two scalars + * + * \sa class CwiseBinaryOp, MatrixBase::operator+, class VectorwiseOp, MatrixBase::sum() + */ +template struct scalar_sum_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_sum_op) + EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { return a + b; } + template + EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const + { return internal::padd(a,b); } + template + EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const + { return internal::predux(a); } +}; +template +struct functor_traits > { + enum { + Cost = NumTraits::AddCost, + PacketAccess = packet_traits::HasAdd + }; +}; + +/** \internal + * \brief Template functor to compute the product of two scalars + * + * \sa class CwiseBinaryOp, Cwise::operator*(), class VectorwiseOp, MatrixBase::redux() + */ +template struct scalar_product_op { + enum { + // TODO vectorize mixed product + Vectorizable = is_same::value && packet_traits::HasMul && packet_traits::HasMul + }; + typedef typename scalar_product_traits::ReturnType result_type; + EIGEN_EMPTY_STRUCT_CTOR(scalar_product_op) + EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a * b; } + template + EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const + { return internal::pmul(a,b); } + template + EIGEN_STRONG_INLINE const result_type predux(const Packet& a) const + { return internal::predux_mul(a); } +}; +template +struct functor_traits > { + enum { + Cost = (NumTraits::MulCost + NumTraits::MulCost)/2, // rough estimate! + PacketAccess = scalar_product_op::Vectorizable + }; +}; + +/** \internal + * \brief Template functor to compute the conjugate product of two scalars + * + * This is a short cut for conj(x) * y which is needed for optimization purpose; in Eigen2 support mode, this becomes x * conj(y) + */ +template struct scalar_conj_product_op { + + enum { + Conj = NumTraits::IsComplex + }; + + typedef typename scalar_product_traits::ReturnType result_type; + + EIGEN_EMPTY_STRUCT_CTOR(scalar_conj_product_op) + EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const + { return conj_helper().pmul(a,b); } + + template + EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const + { return conj_helper().pmul(a,b); } +}; +template +struct functor_traits > { + enum { + Cost = NumTraits::MulCost, + PacketAccess = internal::is_same::value && packet_traits::HasMul + }; +}; + +/** \internal + * \brief Template functor to compute the min of two scalars + * + * \sa class CwiseBinaryOp, MatrixBase::cwiseMin, class VectorwiseOp, MatrixBase::minCoeff() + */ +template struct scalar_min_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_min_op) + EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { using std::min; return (min)(a, b); } + template + EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const + { return internal::pmin(a,b); } + template + EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const + { return internal::predux_min(a); } +}; +template +struct functor_traits > { + enum { + Cost = NumTraits::AddCost, + PacketAccess = packet_traits::HasMin + }; +}; + +/** \internal + * \brief Template functor to compute the max of two scalars + * + * \sa class CwiseBinaryOp, MatrixBase::cwiseMax, class VectorwiseOp, MatrixBase::maxCoeff() + */ +template struct scalar_max_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_max_op) + EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { using std::max; return (max)(a, b); } + template + EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const + { return internal::pmax(a,b); } + template + EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const + { return internal::predux_max(a); } +}; +template +struct functor_traits > { + enum { + Cost = NumTraits::AddCost, + PacketAccess = packet_traits::HasMax + }; +}; + +/** \internal + * \brief Template functor to compute the hypot of two scalars + * + * \sa MatrixBase::stableNorm(), class Redux + */ +template struct scalar_hypot_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_hypot_op) +// typedef typename NumTraits::Real result_type; + EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& _x, const Scalar& _y) const + { + using std::max; + using std::min; + using std::sqrt; + Scalar p = (max)(_x, _y); + Scalar q = (min)(_x, _y); + Scalar qp = q/p; + return p * sqrt(Scalar(1) + qp*qp); + } +}; +template +struct functor_traits > { + enum { Cost = 5 * NumTraits::MulCost, PacketAccess=0 }; +}; + +/** \internal + * \brief Template functor to compute the pow of two scalars + */ +template struct scalar_binary_pow_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_binary_pow_op) + inline Scalar operator() (const Scalar& a, const OtherScalar& b) const { return numext::pow(a, b); } +}; +template +struct functor_traits > { + enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; +}; + +// other binary functors: + +/** \internal + * \brief Template functor to compute the difference of two scalars + * + * \sa class CwiseBinaryOp, MatrixBase::operator- + */ +template struct scalar_difference_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_difference_op) + EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { return a - b; } + template + EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const + { return internal::psub(a,b); } +}; +template +struct functor_traits > { + enum { + Cost = NumTraits::AddCost, + PacketAccess = packet_traits::HasSub + }; +}; + +/** \internal + * \brief Template functor to compute the quotient of two scalars + * + * \sa class CwiseBinaryOp, Cwise::operator/() + */ +template struct scalar_quotient_op { + enum { + // TODO vectorize mixed product + Vectorizable = is_same::value && packet_traits::HasDiv && packet_traits::HasDiv + }; + typedef typename scalar_product_traits::ReturnType result_type; + EIGEN_EMPTY_STRUCT_CTOR(scalar_quotient_op) + EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a / b; } + template + EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const + { return internal::pdiv(a,b); } +}; +template +struct functor_traits > { + enum { + Cost = (NumTraits::MulCost + NumTraits::MulCost), // rough estimate! + PacketAccess = scalar_quotient_op::Vectorizable + }; +}; + + + +/** \internal + * \brief Template functor to compute the and of two booleans + * + * \sa class CwiseBinaryOp, ArrayBase::operator&& + */ +struct scalar_boolean_and_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_and_op) + EIGEN_STRONG_INLINE bool operator() (const bool& a, const bool& b) const { return a && b; } +}; +template<> struct functor_traits { + enum { + Cost = NumTraits::AddCost, + PacketAccess = false + }; +}; + +/** \internal + * \brief Template functor to compute the or of two booleans + * + * \sa class CwiseBinaryOp, ArrayBase::operator|| + */ +struct scalar_boolean_or_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_or_op) + EIGEN_STRONG_INLINE bool operator() (const bool& a, const bool& b) const { return a || b; } +}; +template<> struct functor_traits { + enum { + Cost = NumTraits::AddCost, + PacketAccess = false + }; +}; + +// unary functors: + +/** \internal + * \brief Template functor to compute the opposite of a scalar + * + * \sa class CwiseUnaryOp, MatrixBase::operator- + */ +template struct scalar_opposite_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_opposite_op) + EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { return -a; } + template + EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const + { return internal::pnegate(a); } +}; +template +struct functor_traits > +{ enum { + Cost = NumTraits::AddCost, + PacketAccess = packet_traits::HasNegate }; +}; + +/** \internal + * \brief Template functor to compute the absolute value of a scalar + * + * \sa class CwiseUnaryOp, Cwise::abs + */ +template struct scalar_abs_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_abs_op) + typedef typename NumTraits::Real result_type; + EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { using std::abs; return abs(a); } + template + EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const + { return internal::pabs(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = NumTraits::AddCost, + PacketAccess = packet_traits::HasAbs + }; +}; + +/** \internal + * \brief Template functor to compute the squared absolute value of a scalar + * + * \sa class CwiseUnaryOp, Cwise::abs2 + */ +template struct scalar_abs2_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_abs2_op) + typedef typename NumTraits::Real result_type; + EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { return numext::abs2(a); } + template + EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const + { return internal::pmul(a,a); } +}; +template +struct functor_traits > +{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasAbs2 }; }; + +/** \internal + * \brief Template functor to compute the conjugate of a complex value + * + * \sa class CwiseUnaryOp, MatrixBase::conjugate() + */ +template struct scalar_conjugate_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_conjugate_op) + EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { using numext::conj; return conj(a); } + template + EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const { return internal::pconj(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = NumTraits::IsComplex ? NumTraits::AddCost : 0, + PacketAccess = packet_traits::HasConj + }; +}; + +/** \internal + * \brief Template functor to cast a scalar to another type + * + * \sa class CwiseUnaryOp, MatrixBase::cast() + */ +template +struct scalar_cast_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cast_op) + typedef NewType result_type; + EIGEN_STRONG_INLINE const NewType operator() (const Scalar& a) const { return cast(a); } +}; +template +struct functor_traits > +{ enum { Cost = is_same::value ? 0 : NumTraits::AddCost, PacketAccess = false }; }; + +/** \internal + * \brief Template functor to extract the real part of a complex + * + * \sa class CwiseUnaryOp, MatrixBase::real() + */ +template +struct scalar_real_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_real_op) + typedef typename NumTraits::Real result_type; + EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return numext::real(a); } +}; +template +struct functor_traits > +{ enum { Cost = 0, PacketAccess = false }; }; + +/** \internal + * \brief Template functor to extract the imaginary part of a complex + * + * \sa class CwiseUnaryOp, MatrixBase::imag() + */ +template +struct scalar_imag_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_imag_op) + typedef typename NumTraits::Real result_type; + EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return numext::imag(a); } +}; +template +struct functor_traits > +{ enum { Cost = 0, PacketAccess = false }; }; + +/** \internal + * \brief Template functor to extract the real part of a complex as a reference + * + * \sa class CwiseUnaryOp, MatrixBase::real() + */ +template +struct scalar_real_ref_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_real_ref_op) + typedef typename NumTraits::Real result_type; + EIGEN_STRONG_INLINE result_type& operator() (const Scalar& a) const { return numext::real_ref(*const_cast(&a)); } +}; +template +struct functor_traits > +{ enum { Cost = 0, PacketAccess = false }; }; + +/** \internal + * \brief Template functor to extract the imaginary part of a complex as a reference + * + * \sa class CwiseUnaryOp, MatrixBase::imag() + */ +template +struct scalar_imag_ref_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_imag_ref_op) + typedef typename NumTraits::Real result_type; + EIGEN_STRONG_INLINE result_type& operator() (const Scalar& a) const { return numext::imag_ref(*const_cast(&a)); } +}; +template +struct functor_traits > +{ enum { Cost = 0, PacketAccess = false }; }; + +/** \internal + * + * \brief Template functor to compute the exponential of a scalar + * + * \sa class CwiseUnaryOp, Cwise::exp() + */ +template struct scalar_exp_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_exp_op) + inline const Scalar operator() (const Scalar& a) const { using std::exp; return exp(a); } + typedef typename packet_traits::type Packet; + inline Packet packetOp(const Packet& a) const { return internal::pexp(a); } +}; +template +struct functor_traits > +{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasExp }; }; + +/** \internal + * + * \brief Template functor to compute the logarithm of a scalar + * + * \sa class CwiseUnaryOp, Cwise::log() + */ +template struct scalar_log_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_log_op) + inline const Scalar operator() (const Scalar& a) const { using std::log; return log(a); } + typedef typename packet_traits::type Packet; + inline Packet packetOp(const Packet& a) const { return internal::plog(a); } +}; +template +struct functor_traits > +{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasLog }; }; + +/** \internal + * \brief Template functor to multiply a scalar by a fixed other one + * + * \sa class CwiseUnaryOp, MatrixBase::operator*, MatrixBase::operator/ + */ +/* NOTE why doing the pset1() in packetOp *is* an optimization ? + * indeed it seems better to declare m_other as a Packet and do the pset1() once + * in the constructor. However, in practice: + * - GCC does not like m_other as a Packet and generate a load every time it needs it + * - on the other hand GCC is able to moves the pset1() outside the loop :) + * - simpler code ;) + * (ICC and gcc 4.4 seems to perform well in both cases, the issue is visible with y = a*x + b*y) + */ +template +struct scalar_multiple_op { + typedef typename packet_traits::type Packet; + // FIXME default copy constructors seems bugged with std::complex<> + EIGEN_STRONG_INLINE scalar_multiple_op(const scalar_multiple_op& other) : m_other(other.m_other) { } + EIGEN_STRONG_INLINE scalar_multiple_op(const Scalar& other) : m_other(other) { } + EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a * m_other; } + EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const + { return internal::pmul(a, pset1(m_other)); } + typename add_const_on_value_type::Nested>::type m_other; +}; +template +struct functor_traits > +{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; + +template +struct scalar_multiple2_op { + typedef typename scalar_product_traits::ReturnType result_type; + EIGEN_STRONG_INLINE scalar_multiple2_op(const scalar_multiple2_op& other) : m_other(other.m_other) { } + EIGEN_STRONG_INLINE scalar_multiple2_op(const Scalar2& other) : m_other(other) { } + EIGEN_STRONG_INLINE result_type operator() (const Scalar1& a) const { return a * m_other; } + typename add_const_on_value_type::Nested>::type m_other; +}; +template +struct functor_traits > +{ enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; + +/** \internal + * \brief Template functor to divide a scalar by a fixed other one + * + * This functor is used to implement the quotient of a matrix by + * a scalar where the scalar type is not necessarily a floating point type. + * + * \sa class CwiseUnaryOp, MatrixBase::operator/ + */ +template +struct scalar_quotient1_op { + typedef typename packet_traits::type Packet; + // FIXME default copy constructors seems bugged with std::complex<> + EIGEN_STRONG_INLINE scalar_quotient1_op(const scalar_quotient1_op& other) : m_other(other.m_other) { } + EIGEN_STRONG_INLINE scalar_quotient1_op(const Scalar& other) : m_other(other) {} + EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a / m_other; } + EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const + { return internal::pdiv(a, pset1(m_other)); } + typename add_const_on_value_type::Nested>::type m_other; +}; +template +struct functor_traits > +{ enum { Cost = 2 * NumTraits::MulCost, PacketAccess = packet_traits::HasDiv }; }; + +// nullary functors + +template +struct scalar_constant_op { + typedef typename packet_traits::type Packet; + EIGEN_STRONG_INLINE scalar_constant_op(const scalar_constant_op& other) : m_other(other.m_other) { } + EIGEN_STRONG_INLINE scalar_constant_op(const Scalar& other) : m_other(other) { } + template + EIGEN_STRONG_INLINE const Scalar operator() (Index, Index = 0) const { return m_other; } + template + EIGEN_STRONG_INLINE const Packet packetOp(Index, Index = 0) const { return internal::pset1(m_other); } + const Scalar m_other; +}; +template +struct functor_traits > +// FIXME replace this packet test by a safe one +{ enum { Cost = 1, PacketAccess = packet_traits::Vectorizable, IsRepeatable = true }; }; + +template struct scalar_identity_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_identity_op) + template + EIGEN_STRONG_INLINE const Scalar operator() (Index row, Index col) const { return row==col ? Scalar(1) : Scalar(0); } +}; +template +struct functor_traits > +{ enum { Cost = NumTraits::AddCost, PacketAccess = false, IsRepeatable = true }; }; + +template struct linspaced_op_impl; + +// linear access for packet ops: +// 1) initialization +// base = [low, ..., low] + ([step, ..., step] * [-size, ..., 0]) +// 2) each step (where size is 1 for coeff access or PacketSize for packet access) +// base += [size*step, ..., size*step] +// +// TODO: Perhaps it's better to initialize lazily (so not in the constructor but in packetOp) +// in order to avoid the padd() in operator() ? +template +struct linspaced_op_impl +{ + typedef typename packet_traits::type Packet; + + linspaced_op_impl(const Scalar& low, const Scalar& step) : + m_low(low), m_step(step), + m_packetStep(pset1(packet_traits::size*step)), + m_base(padd(pset1(low), pmul(pset1(step),plset(-packet_traits::size)))) {} + + template + EIGEN_STRONG_INLINE const Scalar operator() (Index i) const + { + m_base = padd(m_base, pset1(m_step)); + return m_low+Scalar(i)*m_step; + } + + template + EIGEN_STRONG_INLINE const Packet packetOp(Index) const { return m_base = padd(m_base,m_packetStep); } + + const Scalar m_low; + const Scalar m_step; + const Packet m_packetStep; + mutable Packet m_base; +}; + +// random access for packet ops: +// 1) each step +// [low, ..., low] + ( [step, ..., step] * ( [i, ..., i] + [0, ..., size] ) ) +template +struct linspaced_op_impl +{ + typedef typename packet_traits::type Packet; + + linspaced_op_impl(const Scalar& low, const Scalar& step) : + m_low(low), m_step(step), + m_lowPacket(pset1(m_low)), m_stepPacket(pset1(m_step)), m_interPacket(plset(0)) {} + + template + EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return m_low+i*m_step; } + + template + EIGEN_STRONG_INLINE const Packet packetOp(Index i) const + { return internal::padd(m_lowPacket, pmul(m_stepPacket, padd(pset1(Scalar(i)),m_interPacket))); } + + const Scalar m_low; + const Scalar m_step; + const Packet m_lowPacket; + const Packet m_stepPacket; + const Packet m_interPacket; +}; + +// ----- Linspace functor ---------------------------------------------------------------- + +// Forward declaration (we default to random access which does not really give +// us a speed gain when using packet access but it allows to use the functor in +// nested expressions). +template struct linspaced_op; +template struct functor_traits< linspaced_op > +{ enum { Cost = 1, PacketAccess = packet_traits::HasSetLinear, IsRepeatable = true }; }; +template struct linspaced_op +{ + typedef typename packet_traits::type Packet; + linspaced_op(const Scalar& low, const Scalar& high, DenseIndex num_steps) : impl((num_steps==1 ? high : low), (num_steps==1 ? Scalar() : (high-low)/Scalar(num_steps-1))) {} + + template + EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return impl(i); } + + // We need this function when assigning e.g. a RowVectorXd to a MatrixXd since + // there row==0 and col is used for the actual iteration. + template + EIGEN_STRONG_INLINE const Scalar operator() (Index row, Index col) const + { + eigen_assert(col==0 || row==0); + return impl(col + row); + } + + template + EIGEN_STRONG_INLINE const Packet packetOp(Index i) const { return impl.packetOp(i); } + + // We need this function when assigning e.g. a RowVectorXd to a MatrixXd since + // there row==0 and col is used for the actual iteration. + template + EIGEN_STRONG_INLINE const Packet packetOp(Index row, Index col) const + { + eigen_assert(col==0 || row==0); + return impl.packetOp(col + row); + } + + // This proxy object handles the actual required temporaries, the different + // implementations (random vs. sequential access) as well as the + // correct piping to size 2/4 packet operations. + const linspaced_op_impl impl; +}; + +// all functors allow linear access, except scalar_identity_op. So we fix here a quick meta +// to indicate whether a functor allows linear access, just always answering 'yes' except for +// scalar_identity_op. +// FIXME move this to functor_traits adding a functor_default +template struct functor_has_linear_access { enum { ret = 1 }; }; +template struct functor_has_linear_access > { enum { ret = 0 }; }; + +// In Eigen, any binary op (Product, CwiseBinaryOp) require the Lhs and Rhs to have the same scalar type, except for multiplication +// where the mixing of different types is handled by scalar_product_traits +// In particular, real * complex is allowed. +// FIXME move this to functor_traits adding a functor_default +template struct functor_is_product_like { enum { ret = 0 }; }; +template struct functor_is_product_like > { enum { ret = 1 }; }; +template struct functor_is_product_like > { enum { ret = 1 }; }; +template struct functor_is_product_like > { enum { ret = 1 }; }; + + +/** \internal + * \brief Template functor to add a scalar to a fixed other one + * \sa class CwiseUnaryOp, Array::operator+ + */ +/* If you wonder why doing the pset1() in packetOp() is an optimization check scalar_multiple_op */ +template +struct scalar_add_op { + typedef typename packet_traits::type Packet; + // FIXME default copy constructors seems bugged with std::complex<> + inline scalar_add_op(const scalar_add_op& other) : m_other(other.m_other) { } + inline scalar_add_op(const Scalar& other) : m_other(other) { } + inline Scalar operator() (const Scalar& a) const { return a + m_other; } + inline const Packet packetOp(const Packet& a) const + { return internal::padd(a, pset1(m_other)); } + const Scalar m_other; +}; +template +struct functor_traits > +{ enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasAdd }; }; + +/** \internal + * \brief Template functor to compute the square root of a scalar + * \sa class CwiseUnaryOp, Cwise::sqrt() + */ +template struct scalar_sqrt_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_sqrt_op) + inline const Scalar operator() (const Scalar& a) const { using std::sqrt; return sqrt(a); } + typedef typename packet_traits::type Packet; + inline Packet packetOp(const Packet& a) const { return internal::psqrt(a); } +}; +template +struct functor_traits > +{ enum { + Cost = 5 * NumTraits::MulCost, + PacketAccess = packet_traits::HasSqrt + }; +}; + +/** \internal + * \brief Template functor to compute the cosine of a scalar + * \sa class CwiseUnaryOp, ArrayBase::cos() + */ +template struct scalar_cos_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cos_op) + inline Scalar operator() (const Scalar& a) const { using std::cos; return cos(a); } + typedef typename packet_traits::type Packet; + inline Packet packetOp(const Packet& a) const { return internal::pcos(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = 5 * NumTraits::MulCost, + PacketAccess = packet_traits::HasCos + }; +}; + +/** \internal + * \brief Template functor to compute the sine of a scalar + * \sa class CwiseUnaryOp, ArrayBase::sin() + */ +template struct scalar_sin_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_sin_op) + inline const Scalar operator() (const Scalar& a) const { using std::sin; return sin(a); } + typedef typename packet_traits::type Packet; + inline Packet packetOp(const Packet& a) const { return internal::psin(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = 5 * NumTraits::MulCost, + PacketAccess = packet_traits::HasSin + }; +}; + + +/** \internal + * \brief Template functor to compute the tan of a scalar + * \sa class CwiseUnaryOp, ArrayBase::tan() + */ +template struct scalar_tan_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_tan_op) + inline const Scalar operator() (const Scalar& a) const { using std::tan; return tan(a); } + typedef typename packet_traits::type Packet; + inline Packet packetOp(const Packet& a) const { return internal::ptan(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = 5 * NumTraits::MulCost, + PacketAccess = packet_traits::HasTan + }; +}; + +/** \internal + * \brief Template functor to compute the arc cosine of a scalar + * \sa class CwiseUnaryOp, ArrayBase::acos() + */ +template struct scalar_acos_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_acos_op) + inline const Scalar operator() (const Scalar& a) const { using std::acos; return acos(a); } + typedef typename packet_traits::type Packet; + inline Packet packetOp(const Packet& a) const { return internal::pacos(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = 5 * NumTraits::MulCost, + PacketAccess = packet_traits::HasACos + }; +}; + +/** \internal + * \brief Template functor to compute the arc sine of a scalar + * \sa class CwiseUnaryOp, ArrayBase::asin() + */ +template struct scalar_asin_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_asin_op) + inline const Scalar operator() (const Scalar& a) const { using std::asin; return asin(a); } + typedef typename packet_traits::type Packet; + inline Packet packetOp(const Packet& a) const { return internal::pasin(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = 5 * NumTraits::MulCost, + PacketAccess = packet_traits::HasASin + }; +}; + +/** \internal + * \brief Template functor to raise a scalar to a power + * \sa class CwiseUnaryOp, Cwise::pow + */ +template +struct scalar_pow_op { + // FIXME default copy constructors seems bugged with std::complex<> + inline scalar_pow_op(const scalar_pow_op& other) : m_exponent(other.m_exponent) { } + inline scalar_pow_op(const Scalar& exponent) : m_exponent(exponent) {} + inline Scalar operator() (const Scalar& a) const { return numext::pow(a, m_exponent); } + const Scalar m_exponent; +}; +template +struct functor_traits > +{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; }; + +/** \internal + * \brief Template functor to compute the quotient between a scalar and array entries. + * \sa class CwiseUnaryOp, Cwise::inverse() + */ +template +struct scalar_inverse_mult_op { + scalar_inverse_mult_op(const Scalar& other) : m_other(other) {} + inline Scalar operator() (const Scalar& a) const { return m_other / a; } + template + inline const Packet packetOp(const Packet& a) const + { return internal::pdiv(pset1(m_other),a); } + Scalar m_other; +}; + +/** \internal + * \brief Template functor to compute the inverse of a scalar + * \sa class CwiseUnaryOp, Cwise::inverse() + */ +template +struct scalar_inverse_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_inverse_op) + inline Scalar operator() (const Scalar& a) const { return Scalar(1)/a; } + template + inline const Packet packetOp(const Packet& a) const + { return internal::pdiv(pset1(Scalar(1)),a); } +}; +template +struct functor_traits > +{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasDiv }; }; + +/** \internal + * \brief Template functor to compute the square of a scalar + * \sa class CwiseUnaryOp, Cwise::square() + */ +template +struct scalar_square_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_square_op) + inline Scalar operator() (const Scalar& a) const { return a*a; } + template + inline const Packet packetOp(const Packet& a) const + { return internal::pmul(a,a); } +}; +template +struct functor_traits > +{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; + +/** \internal + * \brief Template functor to compute the cube of a scalar + * \sa class CwiseUnaryOp, Cwise::cube() + */ +template +struct scalar_cube_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cube_op) + inline Scalar operator() (const Scalar& a) const { return a*a*a; } + template + inline const Packet packetOp(const Packet& a) const + { return internal::pmul(a,pmul(a,a)); } +}; +template +struct functor_traits > +{ enum { Cost = 2*NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; + +// default functor traits for STL functors: + +template +struct functor_traits > +{ enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = functor_traits::Cost, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = functor_traits::Cost, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1 + functor_traits::Cost, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1 + functor_traits::Cost, PacketAccess = false }; }; + +#ifdef EIGEN_STDEXT_SUPPORT + +template +struct functor_traits > +{ enum { Cost = 0, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 0, PacketAccess = false }; }; + +template +struct functor_traits > > +{ enum { Cost = 0, PacketAccess = false }; }; + +template +struct functor_traits > > +{ enum { Cost = 0, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = functor_traits::Cost + functor_traits::Cost, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = functor_traits::Cost + functor_traits::Cost + functor_traits::Cost, PacketAccess = false }; }; + +#endif // EIGEN_STDEXT_SUPPORT + +// allow to add new functors and specializations of functor_traits from outside Eigen. +// this macro is really needed because functor_traits must be specialized after it is declared but before it is used... +#ifdef EIGEN_FUNCTORS_PLUGIN +#include EIGEN_FUNCTORS_PLUGIN +#endif + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_FUNCTORS_H diff --git a/libs/eigen3/Eigen/src/Core/Fuzzy.h b/libs/eigen3/Eigen/src/Core/Fuzzy.h new file mode 100644 index 000000000..fe63bd298 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/Fuzzy.h @@ -0,0 +1,150 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_FUZZY_H +#define EIGEN_FUZZY_H + +namespace Eigen { + +namespace internal +{ + +template::IsInteger> +struct isApprox_selector +{ + static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar& prec) + { + using std::min; + typename internal::nested::type nested(x); + typename internal::nested::type otherNested(y); + return (nested - otherNested).cwiseAbs2().sum() <= prec * prec * (min)(nested.cwiseAbs2().sum(), otherNested.cwiseAbs2().sum()); + } +}; + +template +struct isApprox_selector +{ + static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar&) + { + return x.matrix() == y.matrix(); + } +}; + +template::IsInteger> +struct isMuchSmallerThan_object_selector +{ + static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar& prec) + { + return x.cwiseAbs2().sum() <= numext::abs2(prec) * y.cwiseAbs2().sum(); + } +}; + +template +struct isMuchSmallerThan_object_selector +{ + static bool run(const Derived& x, const OtherDerived&, const typename Derived::RealScalar&) + { + return x.matrix() == Derived::Zero(x.rows(), x.cols()).matrix(); + } +}; + +template::IsInteger> +struct isMuchSmallerThan_scalar_selector +{ + static bool run(const Derived& x, const typename Derived::RealScalar& y, const typename Derived::RealScalar& prec) + { + return x.cwiseAbs2().sum() <= numext::abs2(prec * y); + } +}; + +template +struct isMuchSmallerThan_scalar_selector +{ + static bool run(const Derived& x, const typename Derived::RealScalar&, const typename Derived::RealScalar&) + { + return x.matrix() == Derived::Zero(x.rows(), x.cols()).matrix(); + } +}; + +} // end namespace internal + + +/** \returns \c true if \c *this is approximately equal to \a other, within the precision + * determined by \a prec. + * + * \note The fuzzy compares are done multiplicatively. Two vectors \f$ v \f$ and \f$ w \f$ + * are considered to be approximately equal within precision \f$ p \f$ if + * \f[ \Vert v - w \Vert \leqslant p\,\min(\Vert v\Vert, \Vert w\Vert). \f] + * For matrices, the comparison is done using the Hilbert-Schmidt norm (aka Frobenius norm + * L2 norm). + * + * \note Because of the multiplicativeness of this comparison, one can't use this function + * to check whether \c *this is approximately equal to the zero matrix or vector. + * Indeed, \c isApprox(zero) returns false unless \c *this itself is exactly the zero matrix + * or vector. If you want to test whether \c *this is zero, use internal::isMuchSmallerThan(const + * RealScalar&, RealScalar) instead. + * + * \sa internal::isMuchSmallerThan(const RealScalar&, RealScalar) const + */ +template +template +bool DenseBase::isApprox( + const DenseBase& other, + const RealScalar& prec +) const +{ + return internal::isApprox_selector::run(derived(), other.derived(), prec); +} + +/** \returns \c true if the norm of \c *this is much smaller than \a other, + * within the precision determined by \a prec. + * + * \note The fuzzy compares are done multiplicatively. A vector \f$ v \f$ is + * considered to be much smaller than \f$ x \f$ within precision \f$ p \f$ if + * \f[ \Vert v \Vert \leqslant p\,\vert x\vert. \f] + * + * For matrices, the comparison is done using the Hilbert-Schmidt norm. For this reason, + * the value of the reference scalar \a other should come from the Hilbert-Schmidt norm + * of a reference matrix of same dimensions. + * + * \sa isApprox(), isMuchSmallerThan(const DenseBase&, RealScalar) const + */ +template +bool DenseBase::isMuchSmallerThan( + const typename NumTraits::Real& other, + const RealScalar& prec +) const +{ + return internal::isMuchSmallerThan_scalar_selector::run(derived(), other, prec); +} + +/** \returns \c true if the norm of \c *this is much smaller than the norm of \a other, + * within the precision determined by \a prec. + * + * \note The fuzzy compares are done multiplicatively. A vector \f$ v \f$ is + * considered to be much smaller than a vector \f$ w \f$ within precision \f$ p \f$ if + * \f[ \Vert v \Vert \leqslant p\,\Vert w\Vert. \f] + * For matrices, the comparison is done using the Hilbert-Schmidt norm. + * + * \sa isApprox(), isMuchSmallerThan(const RealScalar&, RealScalar) const + */ +template +template +bool DenseBase::isMuchSmallerThan( + const DenseBase& other, + const RealScalar& prec +) const +{ + return internal::isMuchSmallerThan_object_selector::run(derived(), other.derived(), prec); +} + +} // end namespace Eigen + +#endif // EIGEN_FUZZY_H diff --git a/libs/eigen3/Eigen/src/Core/GeneralProduct.h b/libs/eigen3/Eigen/src/Core/GeneralProduct.h new file mode 100644 index 000000000..2a59d9464 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/GeneralProduct.h @@ -0,0 +1,635 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2008-2011 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_GENERAL_PRODUCT_H +#define EIGEN_GENERAL_PRODUCT_H + +namespace Eigen { + +/** \class GeneralProduct + * \ingroup Core_Module + * + * \brief Expression of the product of two general matrices or vectors + * + * \param LhsNested the type used to store the left-hand side + * \param RhsNested the type used to store the right-hand side + * \param ProductMode the type of the product + * + * This class represents an expression of the product of two general matrices. + * We call a general matrix, a dense matrix with full storage. For instance, + * This excludes triangular, selfadjoint, and sparse matrices. + * It is the return type of the operator* between general matrices. Its template + * arguments are determined automatically by ProductReturnType. Therefore, + * GeneralProduct should never be used direclty. To determine the result type of a + * function which involves a matrix product, use ProductReturnType::Type. + * + * \sa ProductReturnType, MatrixBase::operator*(const MatrixBase&) + */ +template::value> +class GeneralProduct; + +enum { + Large = 2, + Small = 3 +}; + +namespace internal { + +template struct product_type_selector; + +template struct product_size_category +{ + enum { is_large = MaxSize == Dynamic || + Size >= EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD, + value = is_large ? Large + : Size == 1 ? 1 + : Small + }; +}; + +template struct product_type +{ + typedef typename remove_all::type _Lhs; + typedef typename remove_all::type _Rhs; + enum { + MaxRows = _Lhs::MaxRowsAtCompileTime, + Rows = _Lhs::RowsAtCompileTime, + MaxCols = _Rhs::MaxColsAtCompileTime, + Cols = _Rhs::ColsAtCompileTime, + MaxDepth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::MaxColsAtCompileTime, + _Rhs::MaxRowsAtCompileTime), + Depth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::ColsAtCompileTime, + _Rhs::RowsAtCompileTime), + LargeThreshold = EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD + }; + + // the splitting into different lines of code here, introducing the _select enums and the typedef below, + // is to work around an internal compiler error with gcc 4.1 and 4.2. +private: + enum { + rows_select = product_size_category::value, + cols_select = product_size_category::value, + depth_select = product_size_category::value + }; + typedef product_type_selector selector; + +public: + enum { + value = selector::ret + }; +#ifdef EIGEN_DEBUG_PRODUCT + static void debug() + { + EIGEN_DEBUG_VAR(Rows); + EIGEN_DEBUG_VAR(Cols); + EIGEN_DEBUG_VAR(Depth); + EIGEN_DEBUG_VAR(rows_select); + EIGEN_DEBUG_VAR(cols_select); + EIGEN_DEBUG_VAR(depth_select); + EIGEN_DEBUG_VAR(value); + } +#endif +}; + + +/* The following allows to select the kind of product at compile time + * based on the three dimensions of the product. + * This is a compile time mapping from {1,Small,Large}^3 -> {product types} */ +// FIXME I'm not sure the current mapping is the ideal one. +template struct product_type_selector { enum { ret = OuterProduct }; }; +template struct product_type_selector<1, 1, Depth> { enum { ret = InnerProduct }; }; +template<> struct product_type_selector<1, 1, 1> { enum { ret = InnerProduct }; }; +template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector<1, Small,Small> { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; +template<> struct product_type_selector<1, Large,Small> { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector<1, Large,Large> { enum { ret = GemvProduct }; }; +template<> struct product_type_selector<1, Small,Large> { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = GemvProduct }; }; +template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; + +} // end namespace internal + +/** \class ProductReturnType + * \ingroup Core_Module + * + * \brief Helper class to get the correct and optimized returned type of operator* + * + * \param Lhs the type of the left-hand side + * \param Rhs the type of the right-hand side + * \param ProductMode the type of the product (determined automatically by internal::product_mode) + * + * This class defines the typename Type representing the optimized product expression + * between two matrix expressions. In practice, using ProductReturnType::Type + * is the recommended way to define the result type of a function returning an expression + * which involve a matrix product. The class Product should never be + * used directly. + * + * \sa class Product, MatrixBase::operator*(const MatrixBase&) + */ +template +struct ProductReturnType +{ + // TODO use the nested type to reduce instanciations ???? +// typedef typename internal::nested::type LhsNested; +// typedef typename internal::nested::type RhsNested; + + typedef GeneralProduct Type; +}; + +template +struct ProductReturnType +{ + typedef typename internal::nested::type >::type LhsNested; + typedef typename internal::nested::type >::type RhsNested; + typedef CoeffBasedProduct Type; +}; + +template +struct ProductReturnType +{ + typedef typename internal::nested::type >::type LhsNested; + typedef typename internal::nested::type >::type RhsNested; + typedef CoeffBasedProduct Type; +}; + +// this is a workaround for sun CC +template +struct LazyProductReturnType : public ProductReturnType +{}; + +/*********************************************************************** +* Implementation of Inner Vector Vector Product +***********************************************************************/ + +// FIXME : maybe the "inner product" could return a Scalar +// instead of a 1x1 matrix ?? +// Pro: more natural for the user +// Cons: this could be a problem if in a meta unrolled algorithm a matrix-matrix +// product ends up to a row-vector times col-vector product... To tackle this use +// case, we could have a specialization for Block with: operator=(Scalar x); + +namespace internal { + +template +struct traits > + : traits::ReturnType,1,1> > +{}; + +} + +template +class GeneralProduct + : internal::no_assignment_operator, + public Matrix::ReturnType,1,1> +{ + typedef Matrix::ReturnType,1,1> Base; + public: + GeneralProduct(const Lhs& lhs, const Rhs& rhs) + { + EIGEN_STATIC_ASSERT((internal::is_same::value), + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + + Base::coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum(); + } + + /** Convertion to scalar */ + operator const typename Base::Scalar() const { + return Base::coeff(0,0); + } +}; + +/*********************************************************************** +* Implementation of Outer Vector Vector Product +***********************************************************************/ + +namespace internal { + +// Column major +template +EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest& dest, const Func& func, const false_type&) +{ + typedef typename Dest::Index Index; + // FIXME make sure lhs is sequentially stored + // FIXME not very good if rhs is real and lhs complex while alpha is real too + const Index cols = dest.cols(); + for (Index j=0; j +EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest& dest, const Func& func, const true_type&) { + typedef typename Dest::Index Index; + // FIXME make sure rhs is sequentially stored + // FIXME not very good if lhs is real and rhs complex while alpha is real too + const Index rows = dest.rows(); + for (Index i=0; i +struct traits > + : traits, Lhs, Rhs> > +{}; + +} + +template +class GeneralProduct + : public ProductBase, Lhs, Rhs> +{ + template struct IsRowMajor : internal::conditional<(int(T::Flags)&RowMajorBit), internal::true_type, internal::false_type>::type {}; + + public: + EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) + + GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) + { + EIGEN_STATIC_ASSERT((internal::is_same::value), + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + } + + struct set { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() = src; } }; + struct add { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() += src; } }; + struct sub { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() -= src; } }; + struct adds { + Scalar m_scale; + adds(const Scalar& s) : m_scale(s) {} + template void operator()(const Dst& dst, const Src& src) const { + dst.const_cast_derived() += m_scale * src; + } + }; + + template + inline void evalTo(Dest& dest) const { + internal::outer_product_selector_run(*this, dest, set(), IsRowMajor()); + } + + template + inline void addTo(Dest& dest) const { + internal::outer_product_selector_run(*this, dest, add(), IsRowMajor()); + } + + template + inline void subTo(Dest& dest) const { + internal::outer_product_selector_run(*this, dest, sub(), IsRowMajor()); + } + + template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const + { + internal::outer_product_selector_run(*this, dest, adds(alpha), IsRowMajor()); + } +}; + +/*********************************************************************** +* Implementation of General Matrix Vector Product +***********************************************************************/ + +/* According to the shape/flags of the matrix we have to distinghish 3 different cases: + * 1 - the matrix is col-major, BLAS compatible and M is large => call fast BLAS-like colmajor routine + * 2 - the matrix is row-major, BLAS compatible and N is large => call fast BLAS-like rowmajor routine + * 3 - all other cases are handled using a simple loop along the outer-storage direction. + * Therefore we need a lower level meta selector. + * Furthermore, if the matrix is the rhs, then the product has to be transposed. + */ +namespace internal { + +template +struct traits > + : traits, Lhs, Rhs> > +{}; + +template +struct gemv_selector; + +} // end namespace internal + +template +class GeneralProduct + : public ProductBase, Lhs, Rhs> +{ + public: + EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) + + typedef typename Lhs::Scalar LhsScalar; + typedef typename Rhs::Scalar RhsScalar; + + GeneralProduct(const Lhs& a_lhs, const Rhs& a_rhs) : Base(a_lhs,a_rhs) + { +// EIGEN_STATIC_ASSERT((internal::is_same::value), +// YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + } + + enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight }; + typedef typename internal::conditional::type MatrixType; + + template void scaleAndAddTo(Dest& dst, const Scalar& alpha) const + { + eigen_assert(m_lhs.rows() == dst.rows() && m_rhs.cols() == dst.cols()); + internal::gemv_selector::HasUsableDirectAccess)>::run(*this, dst, alpha); + } +}; + +namespace internal { + +// The vector is on the left => transposition +template +struct gemv_selector +{ + template + static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) + { + Transpose destT(dest); + enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor }; + gemv_selector + ::run(GeneralProduct,Transpose, GemvProduct> + (prod.rhs().transpose(), prod.lhs().transpose()), destT, alpha); + } +}; + +template struct gemv_static_vector_if; + +template +struct gemv_static_vector_if +{ + EIGEN_STRONG_INLINE Scalar* data() { eigen_internal_assert(false && "should never be called"); return 0; } +}; + +template +struct gemv_static_vector_if +{ + EIGEN_STRONG_INLINE Scalar* data() { return 0; } +}; + +template +struct gemv_static_vector_if +{ + #if EIGEN_ALIGN_STATICALLY + internal::plain_array m_data; + EIGEN_STRONG_INLINE Scalar* data() { return m_data.array; } + #else + // Some architectures cannot align on the stack, + // => let's manually enforce alignment by allocating more data and return the address of the first aligned element. + enum { + ForceAlignment = internal::packet_traits::Vectorizable, + PacketSize = internal::packet_traits::size + }; + internal::plain_array m_data; + EIGEN_STRONG_INLINE Scalar* data() { + return ForceAlignment + ? reinterpret_cast((reinterpret_cast(m_data.array) & ~(size_t(15))) + 16) + : m_data.array; + } + #endif +}; + +template<> struct gemv_selector +{ + template + static inline void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) + { + typedef typename ProductType::Index Index; + typedef typename ProductType::LhsScalar LhsScalar; + typedef typename ProductType::RhsScalar RhsScalar; + typedef typename ProductType::Scalar ResScalar; + typedef typename ProductType::RealScalar RealScalar; + typedef typename ProductType::ActualLhsType ActualLhsType; + typedef typename ProductType::ActualRhsType ActualRhsType; + typedef typename ProductType::LhsBlasTraits LhsBlasTraits; + typedef typename ProductType::RhsBlasTraits RhsBlasTraits; + typedef Map, Aligned> MappedDest; + + ActualLhsType actualLhs = LhsBlasTraits::extract(prod.lhs()); + ActualRhsType actualRhs = RhsBlasTraits::extract(prod.rhs()); + + ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) + * RhsBlasTraits::extractScalarFactor(prod.rhs()); + + enum { + // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 + // on, the other hand it is good for the cache to pack the vector anyways... + EvalToDestAtCompileTime = Dest::InnerStrideAtCompileTime==1, + ComplexByReal = (NumTraits::IsComplex) && (!NumTraits::IsComplex), + MightCannotUseDest = (Dest::InnerStrideAtCompileTime!=1) || ComplexByReal + }; + + gemv_static_vector_if static_dest; + + bool alphaIsCompatible = (!ComplexByReal) || (numext::imag(actualAlpha)==RealScalar(0)); + bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible; + + RhsScalar compatibleAlpha = get_factor::run(actualAlpha); + + ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(), + evalToDest ? dest.data() : static_dest.data()); + + if(!evalToDest) + { + #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN + int size = dest.size(); + EIGEN_DENSE_STORAGE_CTOR_PLUGIN + #endif + if(!alphaIsCompatible) + { + MappedDest(actualDestPtr, dest.size()).setZero(); + compatibleAlpha = RhsScalar(1); + } + else + MappedDest(actualDestPtr, dest.size()) = dest; + } + + general_matrix_vector_product + ::run( + actualLhs.rows(), actualLhs.cols(), + actualLhs.data(), actualLhs.outerStride(), + actualRhs.data(), actualRhs.innerStride(), + actualDestPtr, 1, + compatibleAlpha); + + if (!evalToDest) + { + if(!alphaIsCompatible) + dest += actualAlpha * MappedDest(actualDestPtr, dest.size()); + else + dest = MappedDest(actualDestPtr, dest.size()); + } + } +}; + +template<> struct gemv_selector +{ + template + static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) + { + typedef typename ProductType::LhsScalar LhsScalar; + typedef typename ProductType::RhsScalar RhsScalar; + typedef typename ProductType::Scalar ResScalar; + typedef typename ProductType::Index Index; + typedef typename ProductType::ActualLhsType ActualLhsType; + typedef typename ProductType::ActualRhsType ActualRhsType; + typedef typename ProductType::_ActualRhsType _ActualRhsType; + typedef typename ProductType::LhsBlasTraits LhsBlasTraits; + typedef typename ProductType::RhsBlasTraits RhsBlasTraits; + + typename add_const::type actualLhs = LhsBlasTraits::extract(prod.lhs()); + typename add_const::type actualRhs = RhsBlasTraits::extract(prod.rhs()); + + ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) + * RhsBlasTraits::extractScalarFactor(prod.rhs()); + + enum { + // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 + // on, the other hand it is good for the cache to pack the vector anyways... + DirectlyUseRhs = _ActualRhsType::InnerStrideAtCompileTime==1 + }; + + gemv_static_vector_if static_rhs; + + ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,actualRhs.size(), + DirectlyUseRhs ? const_cast(actualRhs.data()) : static_rhs.data()); + + if(!DirectlyUseRhs) + { + #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN + int size = actualRhs.size(); + EIGEN_DENSE_STORAGE_CTOR_PLUGIN + #endif + Map(actualRhsPtr, actualRhs.size()) = actualRhs; + } + + general_matrix_vector_product + ::run( + actualLhs.rows(), actualLhs.cols(), + actualLhs.data(), actualLhs.outerStride(), + actualRhsPtr, 1, + dest.data(), dest.innerStride(), + actualAlpha); + } +}; + +template<> struct gemv_selector +{ + template + static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) + { + typedef typename Dest::Index Index; + // TODO makes sure dest is sequentially stored in memory, otherwise use a temp + const Index size = prod.rhs().rows(); + for(Index k=0; k struct gemv_selector +{ + template + static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) + { + typedef typename Dest::Index Index; + // TODO makes sure rhs is sequentially stored in memory, otherwise use a temp + const Index rows = prod.rows(); + for(Index i=0; i +template +inline const typename ProductReturnType::Type +MatrixBase::operator*(const MatrixBase &other) const +{ + // A note regarding the function declaration: In MSVC, this function will sometimes + // not be inlined since DenseStorage is an unwindable object for dynamic + // matrices and product types are holding a member to store the result. + // Thus it does not help tagging this function with EIGEN_STRONG_INLINE. + enum { + ProductIsValid = Derived::ColsAtCompileTime==Dynamic + || OtherDerived::RowsAtCompileTime==Dynamic + || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime), + AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime, + SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived) + }; + // note to the lost user: + // * for a dot product use: v1.dot(v2) + // * for a coeff-wise product use: v1.cwiseProduct(v2) + EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), + INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) + EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), + INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) + EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) +#ifdef EIGEN_DEBUG_PRODUCT + internal::product_type::debug(); +#endif + return typename ProductReturnType::Type(derived(), other.derived()); +} + +/** \returns an expression of the matrix product of \c *this and \a other without implicit evaluation. + * + * The returned product will behave like any other expressions: the coefficients of the product will be + * computed once at a time as requested. This might be useful in some extremely rare cases when only + * a small and no coherent fraction of the result's coefficients have to be computed. + * + * \warning This version of the matrix product can be much much slower. So use it only if you know + * what you are doing and that you measured a true speed improvement. + * + * \sa operator*(const MatrixBase&) + */ +template +template +const typename LazyProductReturnType::Type +MatrixBase::lazyProduct(const MatrixBase &other) const +{ + enum { + ProductIsValid = Derived::ColsAtCompileTime==Dynamic + || OtherDerived::RowsAtCompileTime==Dynamic + || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime), + AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime, + SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived) + }; + // note to the lost user: + // * for a dot product use: v1.dot(v2) + // * for a coeff-wise product use: v1.cwiseProduct(v2) + EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), + INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) + EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), + INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) + EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) + + return typename LazyProductReturnType::Type(derived(), other.derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_PRODUCT_H diff --git a/libs/eigen3/Eigen/src/Core/GenericPacketMath.h b/libs/eigen3/Eigen/src/Core/GenericPacketMath.h new file mode 100644 index 000000000..5f783ebee --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/GenericPacketMath.h @@ -0,0 +1,350 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_GENERIC_PACKET_MATH_H +#define EIGEN_GENERIC_PACKET_MATH_H + +namespace Eigen { + +namespace internal { + +/** \internal + * \file GenericPacketMath.h + * + * Default implementation for types not supported by the vectorization. + * In practice these functions are provided to make easier the writing + * of generic vectorized code. + */ + +#ifndef EIGEN_DEBUG_ALIGNED_LOAD +#define EIGEN_DEBUG_ALIGNED_LOAD +#endif + +#ifndef EIGEN_DEBUG_UNALIGNED_LOAD +#define EIGEN_DEBUG_UNALIGNED_LOAD +#endif + +#ifndef EIGEN_DEBUG_ALIGNED_STORE +#define EIGEN_DEBUG_ALIGNED_STORE +#endif + +#ifndef EIGEN_DEBUG_UNALIGNED_STORE +#define EIGEN_DEBUG_UNALIGNED_STORE +#endif + +struct default_packet_traits +{ + enum { + HasAdd = 1, + HasSub = 1, + HasMul = 1, + HasNegate = 1, + HasAbs = 1, + HasAbs2 = 1, + HasMin = 1, + HasMax = 1, + HasConj = 1, + HasSetLinear = 1, + + HasDiv = 0, + HasSqrt = 0, + HasExp = 0, + HasLog = 0, + HasPow = 0, + + HasSin = 0, + HasCos = 0, + HasTan = 0, + HasASin = 0, + HasACos = 0, + HasATan = 0 + }; +}; + +template struct packet_traits : default_packet_traits +{ + typedef T type; + enum { + Vectorizable = 0, + size = 1, + AlignedOnScalar = 0 + }; + enum { + HasAdd = 0, + HasSub = 0, + HasMul = 0, + HasNegate = 0, + HasAbs = 0, + HasAbs2 = 0, + HasMin = 0, + HasMax = 0, + HasConj = 0, + HasSetLinear = 0 + }; +}; + +/** \internal \returns a + b (coeff-wise) */ +template inline Packet +padd(const Packet& a, + const Packet& b) { return a+b; } + +/** \internal \returns a - b (coeff-wise) */ +template inline Packet +psub(const Packet& a, + const Packet& b) { return a-b; } + +/** \internal \returns -a (coeff-wise) */ +template inline Packet +pnegate(const Packet& a) { return -a; } + +/** \internal \returns conj(a) (coeff-wise) */ +template inline Packet +pconj(const Packet& a) { return numext::conj(a); } + +/** \internal \returns a * b (coeff-wise) */ +template inline Packet +pmul(const Packet& a, + const Packet& b) { return a*b; } + +/** \internal \returns a / b (coeff-wise) */ +template inline Packet +pdiv(const Packet& a, + const Packet& b) { return a/b; } + +/** \internal \returns the min of \a a and \a b (coeff-wise) */ +template inline Packet +pmin(const Packet& a, + const Packet& b) { using std::min; return (min)(a, b); } + +/** \internal \returns the max of \a a and \a b (coeff-wise) */ +template inline Packet +pmax(const Packet& a, + const Packet& b) { using std::max; return (max)(a, b); } + +/** \internal \returns the absolute value of \a a */ +template inline Packet +pabs(const Packet& a) { using std::abs; return abs(a); } + +/** \internal \returns the bitwise and of \a a and \a b */ +template inline Packet +pand(const Packet& a, const Packet& b) { return a & b; } + +/** \internal \returns the bitwise or of \a a and \a b */ +template inline Packet +por(const Packet& a, const Packet& b) { return a | b; } + +/** \internal \returns the bitwise xor of \a a and \a b */ +template inline Packet +pxor(const Packet& a, const Packet& b) { return a ^ b; } + +/** \internal \returns the bitwise andnot of \a a and \a b */ +template inline Packet +pandnot(const Packet& a, const Packet& b) { return a & (!b); } + +/** \internal \returns a packet version of \a *from, from must be 16 bytes aligned */ +template inline Packet +pload(const typename unpacket_traits::type* from) { return *from; } + +/** \internal \returns a packet version of \a *from, (un-aligned load) */ +template inline Packet +ploadu(const typename unpacket_traits::type* from) { return *from; } + +/** \internal \returns a packet with elements of \a *from duplicated. + * For instance, for a packet of 8 elements, 4 scalar will be read from \a *from and + * duplicated to form: {from[0],from[0],from[1],from[1],,from[2],from[2],,from[3],from[3]} + * Currently, this function is only used for scalar * complex products. + */ +template inline Packet +ploaddup(const typename unpacket_traits::type* from) { return *from; } + +/** \internal \returns a packet with constant coefficients \a a, e.g.: (a,a,a,a) */ +template inline Packet +pset1(const typename unpacket_traits::type& a) { return a; } + +/** \internal \brief Returns a packet with coefficients (a,a+1,...,a+packet_size-1). */ +template inline typename packet_traits::type +plset(const Scalar& a) { return a; } + +/** \internal copy the packet \a from to \a *to, \a to must be 16 bytes aligned */ +template inline void pstore(Scalar* to, const Packet& from) +{ (*to) = from; } + +/** \internal copy the packet \a from to \a *to, (un-aligned store) */ +template inline void pstoreu(Scalar* to, const Packet& from) +{ (*to) = from; } + +/** \internal tries to do cache prefetching of \a addr */ +template inline void prefetch(const Scalar* addr) +{ +#if !defined(_MSC_VER) +__builtin_prefetch(addr); +#endif +} + +/** \internal \returns the first element of a packet */ +template inline typename unpacket_traits::type pfirst(const Packet& a) +{ return a; } + +/** \internal \returns a packet where the element i contains the sum of the packet of \a vec[i] */ +template inline Packet +preduxp(const Packet* vecs) { return vecs[0]; } + +/** \internal \returns the sum of the elements of \a a*/ +template inline typename unpacket_traits::type predux(const Packet& a) +{ return a; } + +/** \internal \returns the product of the elements of \a a*/ +template inline typename unpacket_traits::type predux_mul(const Packet& a) +{ return a; } + +/** \internal \returns the min of the elements of \a a*/ +template inline typename unpacket_traits::type predux_min(const Packet& a) +{ return a; } + +/** \internal \returns the max of the elements of \a a*/ +template inline typename unpacket_traits::type predux_max(const Packet& a) +{ return a; } + +/** \internal \returns the reversed elements of \a a*/ +template inline Packet preverse(const Packet& a) +{ return a; } + + +/** \internal \returns \a a with real and imaginary part flipped (for complex type only) */ +template inline Packet pcplxflip(const Packet& a) +{ + // FIXME: uncomment the following in case we drop the internal imag and real functions. +// using std::imag; +// using std::real; + return Packet(imag(a),real(a)); +} + +/************************** +* Special math functions +***************************/ + +/** \internal \returns the sine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet psin(const Packet& a) { using std::sin; return sin(a); } + +/** \internal \returns the cosine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pcos(const Packet& a) { using std::cos; return cos(a); } + +/** \internal \returns the tan of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet ptan(const Packet& a) { using std::tan; return tan(a); } + +/** \internal \returns the arc sine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pasin(const Packet& a) { using std::asin; return asin(a); } + +/** \internal \returns the arc cosine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pacos(const Packet& a) { using std::acos; return acos(a); } + +/** \internal \returns the exp of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pexp(const Packet& a) { using std::exp; return exp(a); } + +/** \internal \returns the log of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet plog(const Packet& a) { using std::log; return log(a); } + +/** \internal \returns the square-root of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet psqrt(const Packet& a) { using std::sqrt; return sqrt(a); } + +/*************************************************************************** +* The following functions might not have to be overwritten for vectorized types +***************************************************************************/ + +/** \internal copy a packet with constant coeficient \a a (e.g., [a,a,a,a]) to \a *to. \a to must be 16 bytes aligned */ +// NOTE: this function must really be templated on the packet type (think about different packet types for the same scalar type) +template +inline void pstore1(typename unpacket_traits::type* to, const typename unpacket_traits::type& a) +{ + pstore(to, pset1(a)); +} + +/** \internal \returns a * b + c (coeff-wise) */ +template inline Packet +pmadd(const Packet& a, + const Packet& b, + const Packet& c) +{ return padd(pmul(a, b),c); } + +/** \internal \returns a packet version of \a *from. + * If LoadMode equals #Aligned, \a from must be 16 bytes aligned */ +template +inline Packet ploadt(const typename unpacket_traits::type* from) +{ + if(LoadMode == Aligned) + return pload(from); + else + return ploadu(from); +} + +/** \internal copy the packet \a from to \a *to. + * If StoreMode equals #Aligned, \a to must be 16 bytes aligned */ +template +inline void pstoret(Scalar* to, const Packet& from) +{ + if(LoadMode == Aligned) + pstore(to, from); + else + pstoreu(to, from); +} + +/** \internal default implementation of palign() allowing partial specialization */ +template +struct palign_impl +{ + // by default data are aligned, so there is nothing to be done :) + static inline void run(PacketType&, const PacketType&) {} +}; + +/** \internal update \a first using the concatenation of the packet_size minus \a Offset last elements + * of \a first and \a Offset first elements of \a second. + * + * This function is currently only used to optimize matrix-vector products on unligned matrices. + * It takes 2 packets that represent a contiguous memory array, and returns a packet starting + * at the position \a Offset. For instance, for packets of 4 elements, we have: + * Input: + * - first = {f0,f1,f2,f3} + * - second = {s0,s1,s2,s3} + * Output: + * - if Offset==0 then {f0,f1,f2,f3} + * - if Offset==1 then {f1,f2,f3,s0} + * - if Offset==2 then {f2,f3,s0,s1} + * - if Offset==3 then {f3,s0,s1,s3} + */ +template +inline void palign(PacketType& first, const PacketType& second) +{ + palign_impl::run(first,second); +} + +/*************************************************************************** +* Fast complex products (GCC generates a function call which is very slow) +***************************************************************************/ + +template<> inline std::complex pmul(const std::complex& a, const std::complex& b) +{ return std::complex(real(a)*real(b) - imag(a)*imag(b), imag(a)*real(b) + real(a)*imag(b)); } + +template<> inline std::complex pmul(const std::complex& a, const std::complex& b) +{ return std::complex(real(a)*real(b) - imag(a)*imag(b), imag(a)*real(b) + real(a)*imag(b)); } + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_GENERIC_PACKET_MATH_H + diff --git a/libs/eigen3/Eigen/src/Core/GlobalFunctions.h b/libs/eigen3/Eigen/src/Core/GlobalFunctions.h new file mode 100644 index 000000000..2acf97723 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/GlobalFunctions.h @@ -0,0 +1,92 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2010-2012 Gael Guennebaud +// Copyright (C) 2010 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_GLOBAL_FUNCTIONS_H +#define EIGEN_GLOBAL_FUNCTIONS_H + +#define EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(NAME,FUNCTOR) \ + template \ + inline const Eigen::CwiseUnaryOp, const Derived> \ + NAME(const Eigen::ArrayBase& x) { \ + return x.derived(); \ + } + +#define EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(NAME,FUNCTOR) \ + \ + template \ + struct NAME##_retval > \ + { \ + typedef const Eigen::CwiseUnaryOp, const Derived> type; \ + }; \ + template \ + struct NAME##_impl > \ + { \ + static inline typename NAME##_retval >::type run(const Eigen::ArrayBase& x) \ + { \ + return x.derived(); \ + } \ + }; + + +namespace Eigen +{ + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(real,scalar_real_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(imag,scalar_imag_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(conj,scalar_conjugate_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sin,scalar_sin_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cos,scalar_cos_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(asin,scalar_asin_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(acos,scalar_acos_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(tan,scalar_tan_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(exp,scalar_exp_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log,scalar_log_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(abs,scalar_abs_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sqrt,scalar_sqrt_op) + + template + inline const Eigen::CwiseUnaryOp, const Derived> + pow(const Eigen::ArrayBase& x, const typename Derived::Scalar& exponent) { + return x.derived().pow(exponent); + } + + template + inline const Eigen::CwiseBinaryOp, const Derived, const Derived> + pow(const Eigen::ArrayBase& x, const Eigen::ArrayBase& exponents) + { + return Eigen::CwiseBinaryOp, const Derived, const Derived>( + x.derived(), + exponents.derived() + ); + } + + /** + * \brief Component-wise division of a scalar by array elements. + **/ + template + inline const Eigen::CwiseUnaryOp, const Derived> + operator/(const typename Derived::Scalar& s, const Eigen::ArrayBase& a) + { + return Eigen::CwiseUnaryOp, const Derived>( + a.derived(), + Eigen::internal::scalar_inverse_mult_op(s) + ); + } + + namespace internal + { + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(real,scalar_real_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(imag,scalar_imag_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(abs2,scalar_abs2_op) + } +} + +// TODO: cleanly disable those functions that are not supported on Array (numext::real_ref, internal::random, internal::isApprox...) + +#endif // EIGEN_GLOBAL_FUNCTIONS_H diff --git a/libs/eigen3/Eigen/src/Core/IO.h b/libs/eigen3/Eigen/src/Core/IO.h new file mode 100644 index 000000000..8d4bc59e9 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/IO.h @@ -0,0 +1,250 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_IO_H +#define EIGEN_IO_H + +namespace Eigen { + +enum { DontAlignCols = 1 }; +enum { StreamPrecision = -1, + FullPrecision = -2 }; + +namespace internal { +template +std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& fmt); +} + +/** \class IOFormat + * \ingroup Core_Module + * + * \brief Stores a set of parameters controlling the way matrices are printed + * + * List of available parameters: + * - \b precision number of digits for floating point values, or one of the special constants \c StreamPrecision and \c FullPrecision. + * The default is the special value \c StreamPrecision which means to use the + * stream's own precision setting, as set for instance using \c cout.precision(3). The other special value + * \c FullPrecision means that the number of digits will be computed to match the full precision of each floating-point + * type. + * - \b flags an OR-ed combination of flags, the default value is 0, the only currently available flag is \c DontAlignCols which + * allows to disable the alignment of columns, resulting in faster code. + * - \b coeffSeparator string printed between two coefficients of the same row + * - \b rowSeparator string printed between two rows + * - \b rowPrefix string printed at the beginning of each row + * - \b rowSuffix string printed at the end of each row + * - \b matPrefix string printed at the beginning of the matrix + * - \b matSuffix string printed at the end of the matrix + * + * Example: \include IOFormat.cpp + * Output: \verbinclude IOFormat.out + * + * \sa DenseBase::format(), class WithFormat + */ +struct IOFormat +{ + /** Default contructor, see class IOFormat for the meaning of the parameters */ + IOFormat(int _precision = StreamPrecision, int _flags = 0, + const std::string& _coeffSeparator = " ", + const std::string& _rowSeparator = "\n", const std::string& _rowPrefix="", const std::string& _rowSuffix="", + const std::string& _matPrefix="", const std::string& _matSuffix="") + : matPrefix(_matPrefix), matSuffix(_matSuffix), rowPrefix(_rowPrefix), rowSuffix(_rowSuffix), rowSeparator(_rowSeparator), + rowSpacer(""), coeffSeparator(_coeffSeparator), precision(_precision), flags(_flags) + { + int i = int(matSuffix.length())-1; + while (i>=0 && matSuffix[i]!='\n') + { + rowSpacer += ' '; + i--; + } + } + std::string matPrefix, matSuffix; + std::string rowPrefix, rowSuffix, rowSeparator, rowSpacer; + std::string coeffSeparator; + int precision; + int flags; +}; + +/** \class WithFormat + * \ingroup Core_Module + * + * \brief Pseudo expression providing matrix output with given format + * + * \param ExpressionType the type of the object on which IO stream operations are performed + * + * This class represents an expression with stream operators controlled by a given IOFormat. + * It is the return type of DenseBase::format() + * and most of the time this is the only way it is used. + * + * See class IOFormat for some examples. + * + * \sa DenseBase::format(), class IOFormat + */ +template +class WithFormat +{ + public: + + WithFormat(const ExpressionType& matrix, const IOFormat& format) + : m_matrix(matrix), m_format(format) + {} + + friend std::ostream & operator << (std::ostream & s, const WithFormat& wf) + { + return internal::print_matrix(s, wf.m_matrix.eval(), wf.m_format); + } + + protected: + const typename ExpressionType::Nested m_matrix; + IOFormat m_format; +}; + +/** \returns a WithFormat proxy object allowing to print a matrix the with given + * format \a fmt. + * + * See class IOFormat for some examples. + * + * \sa class IOFormat, class WithFormat + */ +template +inline const WithFormat +DenseBase::format(const IOFormat& fmt) const +{ + return WithFormat(derived(), fmt); +} + +namespace internal { + +template +struct significant_decimals_default_impl +{ + typedef typename NumTraits::Real RealScalar; + static inline int run() + { + using std::ceil; + using std::log; + return cast(ceil(-log(NumTraits::epsilon())/log(RealScalar(10)))); + } +}; + +template +struct significant_decimals_default_impl +{ + static inline int run() + { + return 0; + } +}; + +template +struct significant_decimals_impl + : significant_decimals_default_impl::IsInteger> +{}; + +/** \internal + * print the matrix \a _m to the output stream \a s using the output format \a fmt */ +template +std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& fmt) +{ + if(_m.size() == 0) + { + s << fmt.matPrefix << fmt.matSuffix; + return s; + } + + typename Derived::Nested m = _m; + typedef typename Derived::Scalar Scalar; + typedef typename Derived::Index Index; + + Index width = 0; + + std::streamsize explicit_precision; + if(fmt.precision == StreamPrecision) + { + explicit_precision = 0; + } + else if(fmt.precision == FullPrecision) + { + if (NumTraits::IsInteger) + { + explicit_precision = 0; + } + else + { + explicit_precision = significant_decimals_impl::run(); + } + } + else + { + explicit_precision = fmt.precision; + } + + std::streamsize old_precision = 0; + if(explicit_precision) old_precision = s.precision(explicit_precision); + + bool align_cols = !(fmt.flags & DontAlignCols); + if(align_cols) + { + // compute the largest width + for(Index j = 0; j < m.cols(); ++j) + for(Index i = 0; i < m.rows(); ++i) + { + std::stringstream sstr; + sstr.copyfmt(s); + sstr << m.coeff(i,j); + width = std::max(width, Index(sstr.str().length())); + } + } + s << fmt.matPrefix; + for(Index i = 0; i < m.rows(); ++i) + { + if (i) + s << fmt.rowSpacer; + s << fmt.rowPrefix; + if(width) s.width(width); + s << m.coeff(i, 0); + for(Index j = 1; j < m.cols(); ++j) + { + s << fmt.coeffSeparator; + if (width) s.width(width); + s << m.coeff(i, j); + } + s << fmt.rowSuffix; + if( i < m.rows() - 1) + s << fmt.rowSeparator; + } + s << fmt.matSuffix; + if(explicit_precision) s.precision(old_precision); + return s; +} + +} // end namespace internal + +/** \relates DenseBase + * + * Outputs the matrix, to the given stream. + * + * If you wish to print the matrix with a format different than the default, use DenseBase::format(). + * + * It is also possible to change the default format by defining EIGEN_DEFAULT_IO_FORMAT before including Eigen headers. + * If not defined, this will automatically be defined to Eigen::IOFormat(), that is the Eigen::IOFormat with default parameters. + * + * \sa DenseBase::format() + */ +template +std::ostream & operator << +(std::ostream & s, + const DenseBase & m) +{ + return internal::print_matrix(s, m.eval(), EIGEN_DEFAULT_IO_FORMAT); +} + +} // end namespace Eigen + +#endif // EIGEN_IO_H diff --git a/libs/eigen3/Eigen/src/Core/Map.h b/libs/eigen3/Eigen/src/Core/Map.h new file mode 100644 index 000000000..f804c89d6 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/Map.h @@ -0,0 +1,192 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2007-2010 Benoit Jacob +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_MAP_H +#define EIGEN_MAP_H + +namespace Eigen { + +/** \class Map + * \ingroup Core_Module + * + * \brief A matrix or vector expression mapping an existing array of data. + * + * \tparam PlainObjectType the equivalent matrix type of the mapped data + * \tparam MapOptions specifies whether the pointer is \c #Aligned, or \c #Unaligned. + * The default is \c #Unaligned. + * \tparam StrideType optionally specifies strides. By default, Map assumes the memory layout + * of an ordinary, contiguous array. This can be overridden by specifying strides. + * The type passed here must be a specialization of the Stride template, see examples below. + * + * This class represents a matrix or vector expression mapping an existing array of data. + * It can be used to let Eigen interface without any overhead with non-Eigen data structures, + * such as plain C arrays or structures from other libraries. By default, it assumes that the + * data is laid out contiguously in memory. You can however override this by explicitly specifying + * inner and outer strides. + * + * Here's an example of simply mapping a contiguous array as a \ref TopicStorageOrders "column-major" matrix: + * \include Map_simple.cpp + * Output: \verbinclude Map_simple.out + * + * If you need to map non-contiguous arrays, you can do so by specifying strides: + * + * Here's an example of mapping an array as a vector, specifying an inner stride, that is, the pointer + * increment between two consecutive coefficients. Here, we're specifying the inner stride as a compile-time + * fixed value. + * \include Map_inner_stride.cpp + * Output: \verbinclude Map_inner_stride.out + * + * Here's an example of mapping an array while specifying an outer stride. Here, since we're mapping + * as a column-major matrix, 'outer stride' means the pointer increment between two consecutive columns. + * Here, we're specifying the outer stride as a runtime parameter. Note that here \c OuterStride<> is + * a short version of \c OuterStride because the default template parameter of OuterStride + * is \c Dynamic + * \include Map_outer_stride.cpp + * Output: \verbinclude Map_outer_stride.out + * + * For more details and for an example of specifying both an inner and an outer stride, see class Stride. + * + * \b Tip: to change the array of data mapped by a Map object, you can use the C++ + * placement new syntax: + * + * Example: \include Map_placement_new.cpp + * Output: \verbinclude Map_placement_new.out + * + * This class is the return type of PlainObjectBase::Map() but can also be used directly. + * + * \sa PlainObjectBase::Map(), \ref TopicStorageOrders + */ + +namespace internal { +template +struct traits > + : public traits +{ + typedef traits TraitsBase; + typedef typename PlainObjectType::Index Index; + typedef typename PlainObjectType::Scalar Scalar; + enum { + InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0 + ? int(PlainObjectType::InnerStrideAtCompileTime) + : int(StrideType::InnerStrideAtCompileTime), + OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0 + ? int(PlainObjectType::OuterStrideAtCompileTime) + : int(StrideType::OuterStrideAtCompileTime), + HasNoInnerStride = InnerStrideAtCompileTime == 1, + HasNoOuterStride = StrideType::OuterStrideAtCompileTime == 0, + HasNoStride = HasNoInnerStride && HasNoOuterStride, + IsAligned = bool(EIGEN_ALIGN) && ((int(MapOptions)&Aligned)==Aligned), + IsDynamicSize = PlainObjectType::SizeAtCompileTime==Dynamic, + KeepsPacketAccess = bool(HasNoInnerStride) + && ( bool(IsDynamicSize) + || HasNoOuterStride + || ( OuterStrideAtCompileTime!=Dynamic + && ((static_cast(sizeof(Scalar))*OuterStrideAtCompileTime)%16)==0 ) ), + Flags0 = TraitsBase::Flags & (~NestByRefBit), + Flags1 = IsAligned ? (int(Flags0) | AlignedBit) : (int(Flags0) & ~AlignedBit), + Flags2 = (bool(HasNoStride) || bool(PlainObjectType::IsVectorAtCompileTime)) + ? int(Flags1) : int(Flags1 & ~LinearAccessBit), + Flags3 = is_lvalue::value ? int(Flags2) : (int(Flags2) & ~LvalueBit), + Flags = KeepsPacketAccess ? int(Flags3) : (int(Flags3) & ~PacketAccessBit) + }; +private: + enum { Options }; // Expressions don't have Options +}; +} + +template class Map + : public MapBase > +{ + public: + + typedef MapBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Map) + + typedef typename Base::PointerType PointerType; +#if EIGEN2_SUPPORT_STAGE <= STAGE30_FULL_EIGEN3_API + typedef const Scalar* PointerArgType; + inline PointerType cast_to_pointer_type(PointerArgType ptr) { return const_cast(ptr); } +#else + typedef PointerType PointerArgType; + inline PointerType cast_to_pointer_type(PointerArgType ptr) { return ptr; } +#endif + + inline Index innerStride() const + { + return StrideType::InnerStrideAtCompileTime != 0 ? m_stride.inner() : 1; + } + + inline Index outerStride() const + { + return StrideType::OuterStrideAtCompileTime != 0 ? m_stride.outer() + : IsVectorAtCompileTime ? this->size() + : int(Flags)&RowMajorBit ? this->cols() + : this->rows(); + } + + /** Constructor in the fixed-size case. + * + * \param dataPtr pointer to the array to map + * \param a_stride optional Stride object, passing the strides. + */ + inline Map(PointerArgType dataPtr, const StrideType& a_stride = StrideType()) + : Base(cast_to_pointer_type(dataPtr)), m_stride(a_stride) + { + PlainObjectType::Base::_check_template_params(); + } + + /** Constructor in the dynamic-size vector case. + * + * \param dataPtr pointer to the array to map + * \param a_size the size of the vector expression + * \param a_stride optional Stride object, passing the strides. + */ + inline Map(PointerArgType dataPtr, Index a_size, const StrideType& a_stride = StrideType()) + : Base(cast_to_pointer_type(dataPtr), a_size), m_stride(a_stride) + { + PlainObjectType::Base::_check_template_params(); + } + + /** Constructor in the dynamic-size matrix case. + * + * \param dataPtr pointer to the array to map + * \param nbRows the number of rows of the matrix expression + * \param nbCols the number of columns of the matrix expression + * \param a_stride optional Stride object, passing the strides. + */ + inline Map(PointerArgType dataPtr, Index nbRows, Index nbCols, const StrideType& a_stride = StrideType()) + : Base(cast_to_pointer_type(dataPtr), nbRows, nbCols), m_stride(a_stride) + { + PlainObjectType::Base::_check_template_params(); + } + + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Map) + + protected: + StrideType m_stride; +}; + +template +inline Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> + ::Array(const Scalar *data) +{ + this->_set_noalias(Eigen::Map(data)); +} + +template +inline Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> + ::Matrix(const Scalar *data) +{ + this->_set_noalias(Eigen::Map(data)); +} + +} // end namespace Eigen + +#endif // EIGEN_MAP_H diff --git a/libs/eigen3/Eigen/src/Core/MapBase.h b/libs/eigen3/Eigen/src/Core/MapBase.h new file mode 100644 index 000000000..ab50c9b81 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/MapBase.h @@ -0,0 +1,244 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2007-2010 Benoit Jacob +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_MAPBASE_H +#define EIGEN_MAPBASE_H + +#define EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) \ + EIGEN_STATIC_ASSERT((int(internal::traits::Flags) & LinearAccessBit) || Derived::IsVectorAtCompileTime, \ + YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT) + +namespace Eigen { + +/** \class MapBase + * \ingroup Core_Module + * + * \brief Base class for Map and Block expression with direct access + * + * \sa class Map, class Block + */ +template class MapBase + : public internal::dense_xpr_base::type +{ + public: + + typedef typename internal::dense_xpr_base::type Base; + enum { + RowsAtCompileTime = internal::traits::RowsAtCompileTime, + ColsAtCompileTime = internal::traits::ColsAtCompileTime, + SizeAtCompileTime = Base::SizeAtCompileTime + }; + + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::packet_traits::type PacketScalar; + typedef typename NumTraits::Real RealScalar; + typedef typename internal::conditional< + bool(internal::is_lvalue::value), + Scalar *, + const Scalar *>::type + PointerType; + + using Base::derived; +// using Base::RowsAtCompileTime; +// using Base::ColsAtCompileTime; +// using Base::SizeAtCompileTime; + using Base::MaxRowsAtCompileTime; + using Base::MaxColsAtCompileTime; + using Base::MaxSizeAtCompileTime; + using Base::IsVectorAtCompileTime; + using Base::Flags; + using Base::IsRowMajor; + + using Base::rows; + using Base::cols; + using Base::size; + using Base::coeff; + using Base::coeffRef; + using Base::lazyAssign; + using Base::eval; + + using Base::innerStride; + using Base::outerStride; + using Base::rowStride; + using Base::colStride; + + // bug 217 - compile error on ICC 11.1 + using Base::operator=; + + typedef typename Base::CoeffReturnType CoeffReturnType; + + inline Index rows() const { return m_rows.value(); } + inline Index cols() const { return m_cols.value(); } + + /** Returns a pointer to the first coefficient of the matrix or vector. + * + * \note When addressing this data, make sure to honor the strides returned by innerStride() and outerStride(). + * + * \sa innerStride(), outerStride() + */ + inline const Scalar* data() const { return m_data; } + + inline const Scalar& coeff(Index rowId, Index colId) const + { + return m_data[colId * colStride() + rowId * rowStride()]; + } + + inline const Scalar& coeff(Index index) const + { + EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) + return m_data[index * innerStride()]; + } + + inline const Scalar& coeffRef(Index rowId, Index colId) const + { + return this->m_data[colId * colStride() + rowId * rowStride()]; + } + + inline const Scalar& coeffRef(Index index) const + { + EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) + return this->m_data[index * innerStride()]; + } + + template + inline PacketScalar packet(Index rowId, Index colId) const + { + return internal::ploadt + (m_data + (colId * colStride() + rowId * rowStride())); + } + + template + inline PacketScalar packet(Index index) const + { + EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) + return internal::ploadt(m_data + index * innerStride()); + } + + inline MapBase(PointerType dataPtr) : m_data(dataPtr), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime) + { + EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) + checkSanity(); + } + + inline MapBase(PointerType dataPtr, Index vecSize) + : m_data(dataPtr), + m_rows(RowsAtCompileTime == Dynamic ? vecSize : Index(RowsAtCompileTime)), + m_cols(ColsAtCompileTime == Dynamic ? vecSize : Index(ColsAtCompileTime)) + { + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + eigen_assert(vecSize >= 0); + eigen_assert(dataPtr == 0 || SizeAtCompileTime == Dynamic || SizeAtCompileTime == vecSize); + checkSanity(); + } + + inline MapBase(PointerType dataPtr, Index nbRows, Index nbCols) + : m_data(dataPtr), m_rows(nbRows), m_cols(nbCols) + { + eigen_assert( (dataPtr == 0) + || ( nbRows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == nbRows) + && nbCols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == nbCols))); + checkSanity(); + } + + protected: + + void checkSanity() const + { + EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(internal::traits::Flags&PacketAccessBit, + internal::inner_stride_at_compile_time::ret==1), + PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); + eigen_assert(EIGEN_IMPLIES(internal::traits::Flags&AlignedBit, (size_t(m_data) % 16) == 0) + && "data is not aligned"); + } + + PointerType m_data; + const internal::variable_if_dynamic m_rows; + const internal::variable_if_dynamic m_cols; +}; + +template class MapBase + : public MapBase +{ + public: + + typedef MapBase Base; + + typedef typename Base::Scalar Scalar; + typedef typename Base::PacketScalar PacketScalar; + typedef typename Base::Index Index; + typedef typename Base::PointerType PointerType; + + using Base::derived; + using Base::rows; + using Base::cols; + using Base::size; + using Base::coeff; + using Base::coeffRef; + + using Base::innerStride; + using Base::outerStride; + using Base::rowStride; + using Base::colStride; + + typedef typename internal::conditional< + internal::is_lvalue::value, + Scalar, + const Scalar + >::type ScalarWithConstIfNotLvalue; + + inline const Scalar* data() const { return this->m_data; } + inline ScalarWithConstIfNotLvalue* data() { return this->m_data; } // no const-cast here so non-const-correct code will give a compile error + + inline ScalarWithConstIfNotLvalue& coeffRef(Index row, Index col) + { + return this->m_data[col * colStride() + row * rowStride()]; + } + + inline ScalarWithConstIfNotLvalue& coeffRef(Index index) + { + EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) + return this->m_data[index * innerStride()]; + } + + template + inline void writePacket(Index row, Index col, const PacketScalar& val) + { + internal::pstoret + (this->m_data + (col * colStride() + row * rowStride()), val); + } + + template + inline void writePacket(Index index, const PacketScalar& val) + { + EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) + internal::pstoret + (this->m_data + index * innerStride(), val); + } + + explicit inline MapBase(PointerType dataPtr) : Base(dataPtr) {} + inline MapBase(PointerType dataPtr, Index vecSize) : Base(dataPtr, vecSize) {} + inline MapBase(PointerType dataPtr, Index nbRows, Index nbCols) : Base(dataPtr, nbRows, nbCols) {} + + Derived& operator=(const MapBase& other) + { + Base::Base::operator=(other); + return derived(); + } + + using Base::Base::operator=; +}; + +#undef EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS + +} // end namespace Eigen + +#endif // EIGEN_MAPBASE_H diff --git a/libs/eigen3/Eigen/src/Core/MathFunctions.h b/libs/eigen3/Eigen/src/Core/MathFunctions.h new file mode 100644 index 000000000..2bfc5ebd9 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/MathFunctions.h @@ -0,0 +1,768 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2010 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_MATHFUNCTIONS_H +#define EIGEN_MATHFUNCTIONS_H + +namespace Eigen { + +namespace internal { + +/** \internal \struct global_math_functions_filtering_base + * + * What it does: + * Defines a typedef 'type' as follows: + * - if type T has a member typedef Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl, then + * global_math_functions_filtering_base::type is a typedef for it. + * - otherwise, global_math_functions_filtering_base::type is a typedef for T. + * + * How it's used: + * To allow to defined the global math functions (like sin...) in certain cases, like the Array expressions. + * When you do sin(array1+array2), the object array1+array2 has a complicated expression type, all what you want to know + * is that it inherits ArrayBase. So we implement a partial specialization of sin_impl for ArrayBase. + * So we must make sure to use sin_impl > and not sin_impl, otherwise our partial specialization + * won't be used. How does sin know that? That's exactly what global_math_functions_filtering_base tells it. + * + * How it's implemented: + * SFINAE in the style of enable_if. Highly susceptible of breaking compilers. With GCC, it sure does work, but if you replace + * the typename dummy by an integer template parameter, it doesn't work anymore! + */ + +template +struct global_math_functions_filtering_base +{ + typedef T type; +}; + +template struct always_void { typedef void type; }; + +template +struct global_math_functions_filtering_base + ::type + > +{ + typedef typename T::Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl type; +}; + +#define EIGEN_MATHFUNC_IMPL(func, scalar) Eigen::internal::func##_impl::type> +#define EIGEN_MATHFUNC_RETVAL(func, scalar) typename Eigen::internal::func##_retval::type>::type + +/**************************************************************************** +* Implementation of real * +****************************************************************************/ + +template::IsComplex> +struct real_default_impl +{ + typedef typename NumTraits::Real RealScalar; + static inline RealScalar run(const Scalar& x) + { + return x; + } +}; + +template +struct real_default_impl +{ + typedef typename NumTraits::Real RealScalar; + static inline RealScalar run(const Scalar& x) + { + using std::real; + return real(x); + } +}; + +template struct real_impl : real_default_impl {}; + +template +struct real_retval +{ + typedef typename NumTraits::Real type; +}; + + +/**************************************************************************** +* Implementation of imag * +****************************************************************************/ + +template::IsComplex> +struct imag_default_impl +{ + typedef typename NumTraits::Real RealScalar; + static inline RealScalar run(const Scalar&) + { + return RealScalar(0); + } +}; + +template +struct imag_default_impl +{ + typedef typename NumTraits::Real RealScalar; + static inline RealScalar run(const Scalar& x) + { + using std::imag; + return imag(x); + } +}; + +template struct imag_impl : imag_default_impl {}; + +template +struct imag_retval +{ + typedef typename NumTraits::Real type; +}; + +/**************************************************************************** +* Implementation of real_ref * +****************************************************************************/ + +template +struct real_ref_impl +{ + typedef typename NumTraits::Real RealScalar; + static inline RealScalar& run(Scalar& x) + { + return reinterpret_cast(&x)[0]; + } + static inline const RealScalar& run(const Scalar& x) + { + return reinterpret_cast(&x)[0]; + } +}; + +template +struct real_ref_retval +{ + typedef typename NumTraits::Real & type; +}; + +/**************************************************************************** +* Implementation of imag_ref * +****************************************************************************/ + +template +struct imag_ref_default_impl +{ + typedef typename NumTraits::Real RealScalar; + static inline RealScalar& run(Scalar& x) + { + return reinterpret_cast(&x)[1]; + } + static inline const RealScalar& run(const Scalar& x) + { + return reinterpret_cast(&x)[1]; + } +}; + +template +struct imag_ref_default_impl +{ + static inline Scalar run(Scalar&) + { + return Scalar(0); + } + static inline const Scalar run(const Scalar&) + { + return Scalar(0); + } +}; + +template +struct imag_ref_impl : imag_ref_default_impl::IsComplex> {}; + +template +struct imag_ref_retval +{ + typedef typename NumTraits::Real & type; +}; + +/**************************************************************************** +* Implementation of conj * +****************************************************************************/ + +template::IsComplex> +struct conj_impl +{ + static inline Scalar run(const Scalar& x) + { + return x; + } +}; + +template +struct conj_impl +{ + static inline Scalar run(const Scalar& x) + { + using std::conj; + return conj(x); + } +}; + +template +struct conj_retval +{ + typedef Scalar type; +}; + +/**************************************************************************** +* Implementation of abs2 * +****************************************************************************/ + +template +struct abs2_impl +{ + typedef typename NumTraits::Real RealScalar; + static inline RealScalar run(const Scalar& x) + { + return x*x; + } +}; + +template +struct abs2_impl > +{ + static inline RealScalar run(const std::complex& x) + { + return real(x)*real(x) + imag(x)*imag(x); + } +}; + +template +struct abs2_retval +{ + typedef typename NumTraits::Real type; +}; + +/**************************************************************************** +* Implementation of norm1 * +****************************************************************************/ + +template +struct norm1_default_impl +{ + typedef typename NumTraits::Real RealScalar; + static inline RealScalar run(const Scalar& x) + { + using std::abs; + return abs(real(x)) + abs(imag(x)); + } +}; + +template +struct norm1_default_impl +{ + static inline Scalar run(const Scalar& x) + { + using std::abs; + return abs(x); + } +}; + +template +struct norm1_impl : norm1_default_impl::IsComplex> {}; + +template +struct norm1_retval +{ + typedef typename NumTraits::Real type; +}; + +/**************************************************************************** +* Implementation of hypot * +****************************************************************************/ + +template +struct hypot_impl +{ + typedef typename NumTraits::Real RealScalar; + static inline RealScalar run(const Scalar& x, const Scalar& y) + { + using std::max; + using std::min; + using std::abs; + using std::sqrt; + RealScalar _x = abs(x); + RealScalar _y = abs(y); + RealScalar p = (max)(_x, _y); + if(p==RealScalar(0)) return 0; + RealScalar q = (min)(_x, _y); + RealScalar qp = q/p; + return p * sqrt(RealScalar(1) + qp*qp); + } +}; + +template +struct hypot_retval +{ + typedef typename NumTraits::Real type; +}; + +/**************************************************************************** +* Implementation of cast * +****************************************************************************/ + +template +struct cast_impl +{ + static inline NewType run(const OldType& x) + { + return static_cast(x); + } +}; + +// here, for once, we're plainly returning NewType: we don't want cast to do weird things. + +template +inline NewType cast(const OldType& x) +{ + return cast_impl::run(x); +} + +/**************************************************************************** +* Implementation of atanh2 * +****************************************************************************/ + +template +struct atanh2_default_impl +{ + typedef Scalar retval; + typedef typename NumTraits::Real RealScalar; + static inline Scalar run(const Scalar& x, const Scalar& y) + { + using std::abs; + using std::log; + using std::sqrt; + Scalar z = x / y; + if (y == Scalar(0) || abs(z) > sqrt(NumTraits::epsilon())) + return RealScalar(0.5) * log((y + x) / (y - x)); + else + return z + z*z*z / RealScalar(3); + } +}; + +template +struct atanh2_default_impl +{ + static inline Scalar run(const Scalar&, const Scalar&) + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + return Scalar(0); + } +}; + +template +struct atanh2_impl : atanh2_default_impl::IsInteger> {}; + +template +struct atanh2_retval +{ + typedef Scalar type; +}; + +/**************************************************************************** +* Implementation of pow * +****************************************************************************/ + +template +struct pow_default_impl +{ + typedef Scalar retval; + static inline Scalar run(const Scalar& x, const Scalar& y) + { + using std::pow; + return pow(x, y); + } +}; + +template +struct pow_default_impl +{ + static inline Scalar run(Scalar x, Scalar y) + { + Scalar res(1); + eigen_assert(!NumTraits::IsSigned || y >= 0); + if(y & 1) res *= x; + y >>= 1; + while(y) + { + x *= x; + if(y&1) res *= x; + y >>= 1; + } + return res; + } +}; + +template +struct pow_impl : pow_default_impl::IsInteger> {}; + +template +struct pow_retval +{ + typedef Scalar type; +}; + +/**************************************************************************** +* Implementation of random * +****************************************************************************/ + +template +struct random_default_impl {}; + +template +struct random_impl : random_default_impl::IsComplex, NumTraits::IsInteger> {}; + +template +struct random_retval +{ + typedef Scalar type; +}; + +template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(const Scalar& x, const Scalar& y); +template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(); + +template +struct random_default_impl +{ + static inline Scalar run(const Scalar& x, const Scalar& y) + { + return x + (y-x) * Scalar(std::rand()) / Scalar(RAND_MAX); + } + static inline Scalar run() + { + return run(Scalar(NumTraits::IsSigned ? -1 : 0), Scalar(1)); + } +}; + +enum { + floor_log2_terminate, + floor_log2_move_up, + floor_log2_move_down, + floor_log2_bogus +}; + +template struct floor_log2_selector +{ + enum { middle = (lower + upper) / 2, + value = (upper <= lower + 1) ? int(floor_log2_terminate) + : (n < (1 << middle)) ? int(floor_log2_move_down) + : (n==0) ? int(floor_log2_bogus) + : int(floor_log2_move_up) + }; +}; + +template::value> +struct floor_log2 {}; + +template +struct floor_log2 +{ + enum { value = floor_log2::middle>::value }; +}; + +template +struct floor_log2 +{ + enum { value = floor_log2::middle, upper>::value }; +}; + +template +struct floor_log2 +{ + enum { value = (n >= ((unsigned int)(1) << (lower+1))) ? lower+1 : lower }; +}; + +template +struct floor_log2 +{ + // no value, error at compile time +}; + +template +struct random_default_impl +{ + typedef typename NumTraits::NonInteger NonInteger; + + static inline Scalar run(const Scalar& x, const Scalar& y) + { + return x + Scalar((NonInteger(y)-x+1) * std::rand() / (RAND_MAX + NonInteger(1))); + } + + static inline Scalar run() + { +#ifdef EIGEN_MAKING_DOCS + return run(Scalar(NumTraits::IsSigned ? -10 : 0), Scalar(10)); +#else + enum { rand_bits = floor_log2<(unsigned int)(RAND_MAX)+1>::value, + scalar_bits = sizeof(Scalar) * CHAR_BIT, + shift = EIGEN_PLAIN_ENUM_MAX(0, int(rand_bits) - int(scalar_bits)), + offset = NumTraits::IsSigned ? (1 << (EIGEN_PLAIN_ENUM_MIN(rand_bits,scalar_bits)-1)) : 0 + }; + return Scalar((std::rand() >> shift) - offset); +#endif + } +}; + +template +struct random_default_impl +{ + static inline Scalar run(const Scalar& x, const Scalar& y) + { + return Scalar(random(real(x), real(y)), + random(imag(x), imag(y))); + } + static inline Scalar run() + { + typedef typename NumTraits::Real RealScalar; + return Scalar(random(), random()); + } +}; + +template +inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(const Scalar& x, const Scalar& y) +{ + return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(x, y); +} + +template +inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random() +{ + return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(); +} + +} // end namespace internal + +/**************************************************************************** +* Generic math function * +****************************************************************************/ + +namespace numext { + +template +inline EIGEN_MATHFUNC_RETVAL(real, Scalar) real(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(real, Scalar)::run(x); +} + +template +inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) >::type real_ref(const Scalar& x) +{ + return internal::real_ref_impl::run(x); +} + +template +inline EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) real_ref(Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(real_ref, Scalar)::run(x); +} + +template +inline EIGEN_MATHFUNC_RETVAL(imag, Scalar) imag(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(imag, Scalar)::run(x); +} + +template +inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) >::type imag_ref(const Scalar& x) +{ + return internal::imag_ref_impl::run(x); +} + +template +inline EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) imag_ref(Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(imag_ref, Scalar)::run(x); +} + +template +inline EIGEN_MATHFUNC_RETVAL(conj, Scalar) conj(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(conj, Scalar)::run(x); +} + +template +inline EIGEN_MATHFUNC_RETVAL(abs2, Scalar) abs2(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(abs2, Scalar)::run(x); +} + +template +inline EIGEN_MATHFUNC_RETVAL(norm1, Scalar) norm1(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(norm1, Scalar)::run(x); +} + +template +inline EIGEN_MATHFUNC_RETVAL(hypot, Scalar) hypot(const Scalar& x, const Scalar& y) +{ + return EIGEN_MATHFUNC_IMPL(hypot, Scalar)::run(x, y); +} + +template +inline EIGEN_MATHFUNC_RETVAL(atanh2, Scalar) atanh2(const Scalar& x, const Scalar& y) +{ + return EIGEN_MATHFUNC_IMPL(atanh2, Scalar)::run(x, y); +} + +template +inline EIGEN_MATHFUNC_RETVAL(pow, Scalar) pow(const Scalar& x, const Scalar& y) +{ + return EIGEN_MATHFUNC_IMPL(pow, Scalar)::run(x, y); +} + +// std::isfinite is non standard, so let's define our own version, +// even though it is not very efficient. +template bool (isfinite)(const T& x) +{ + return x::highest() && x>NumTraits::lowest(); +} + +} // end namespace numext + +namespace internal { + +/**************************************************************************** +* Implementation of fuzzy comparisons * +****************************************************************************/ + +template +struct scalar_fuzzy_default_impl {}; + +template +struct scalar_fuzzy_default_impl +{ + typedef typename NumTraits::Real RealScalar; + template + static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) + { + using std::abs; + return abs(x) <= abs(y) * prec; + } + static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) + { + using std::min; + using std::abs; + return abs(x - y) <= (min)(abs(x), abs(y)) * prec; + } + static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar& prec) + { + return x <= y || isApprox(x, y, prec); + } +}; + +template +struct scalar_fuzzy_default_impl +{ + typedef typename NumTraits::Real RealScalar; + template + static inline bool isMuchSmallerThan(const Scalar& x, const Scalar&, const RealScalar&) + { + return x == Scalar(0); + } + static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar&) + { + return x == y; + } + static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar&) + { + return x <= y; + } +}; + +template +struct scalar_fuzzy_default_impl +{ + typedef typename NumTraits::Real RealScalar; + template + static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) + { + return numext::abs2(x) <= numext::abs2(y) * prec * prec; + } + static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) + { + using std::min; + return numext::abs2(x - y) <= (min)(numext::abs2(x), numext::abs2(y)) * prec * prec; + } +}; + +template +struct scalar_fuzzy_impl : scalar_fuzzy_default_impl::IsComplex, NumTraits::IsInteger> {}; + +template +inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, + typename NumTraits::Real precision = NumTraits::dummy_precision()) +{ + return scalar_fuzzy_impl::template isMuchSmallerThan(x, y, precision); +} + +template +inline bool isApprox(const Scalar& x, const Scalar& y, + typename NumTraits::Real precision = NumTraits::dummy_precision()) +{ + return scalar_fuzzy_impl::isApprox(x, y, precision); +} + +template +inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, + typename NumTraits::Real precision = NumTraits::dummy_precision()) +{ + return scalar_fuzzy_impl::isApproxOrLessThan(x, y, precision); +} + +/****************************************** +*** The special case of the bool type *** +******************************************/ + +template<> struct random_impl +{ + static inline bool run() + { + return random(0,1)==0 ? false : true; + } +}; + +template<> struct scalar_fuzzy_impl +{ + typedef bool RealScalar; + + template + static inline bool isMuchSmallerThan(const bool& x, const bool&, const bool&) + { + return !x; + } + + static inline bool isApprox(bool x, bool y, bool) + { + return x == y; + } + + static inline bool isApproxOrLessThan(const bool& x, const bool& y, const bool&) + { + return (!x) || y; + } + +}; + + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_MATHFUNCTIONS_H diff --git a/libs/eigen3/Eigen/src/Core/Matrix.h b/libs/eigen3/Eigen/src/Core/Matrix.h new file mode 100644 index 000000000..d7d0b5b9a --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/Matrix.h @@ -0,0 +1,405 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2010 Benoit Jacob +// Copyright (C) 2008-2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_MATRIX_H +#define EIGEN_MATRIX_H + +namespace Eigen { + +/** \class Matrix + * \ingroup Core_Module + * + * \brief The matrix class, also used for vectors and row-vectors + * + * The %Matrix class is the work-horse for all \em dense (\ref dense "note") matrices and vectors within Eigen. + * Vectors are matrices with one column, and row-vectors are matrices with one row. + * + * The %Matrix class encompasses \em both fixed-size and dynamic-size objects (\ref fixedsize "note"). + * + * The first three template parameters are required: + * \tparam _Scalar \anchor matrix_tparam_scalar Numeric type, e.g. float, double, int or std::complex. + * User defined sclar types are supported as well (see \ref user_defined_scalars "here"). + * \tparam _Rows Number of rows, or \b Dynamic + * \tparam _Cols Number of columns, or \b Dynamic + * + * The remaining template parameters are optional -- in most cases you don't have to worry about them. + * \tparam _Options \anchor matrix_tparam_options A combination of either \b #RowMajor or \b #ColMajor, and of either + * \b #AutoAlign or \b #DontAlign. + * The former controls \ref TopicStorageOrders "storage order", and defaults to column-major. The latter controls alignment, which is required + * for vectorization. It defaults to aligning matrices except for fixed sizes that aren't a multiple of the packet size. + * \tparam _MaxRows Maximum number of rows. Defaults to \a _Rows (\ref maxrows "note"). + * \tparam _MaxCols Maximum number of columns. Defaults to \a _Cols (\ref maxrows "note"). + * + * Eigen provides a number of typedefs covering the usual cases. Here are some examples: + * + * \li \c Matrix2d is a 2x2 square matrix of doubles (\c Matrix) + * \li \c Vector4f is a vector of 4 floats (\c Matrix) + * \li \c RowVector3i is a row-vector of 3 ints (\c Matrix) + * + * \li \c MatrixXf is a dynamic-size matrix of floats (\c Matrix) + * \li \c VectorXf is a dynamic-size vector of floats (\c Matrix) + * + * \li \c Matrix2Xf is a partially fixed-size (dynamic-size) matrix of floats (\c Matrix) + * \li \c MatrixX3d is a partially dynamic-size (fixed-size) matrix of double (\c Matrix) + * + * See \link matrixtypedefs this page \endlink for a complete list of predefined \em %Matrix and \em Vector typedefs. + * + * You can access elements of vectors and matrices using normal subscripting: + * + * \code + * Eigen::VectorXd v(10); + * v[0] = 0.1; + * v[1] = 0.2; + * v(0) = 0.3; + * v(1) = 0.4; + * + * Eigen::MatrixXi m(10, 10); + * m(0, 1) = 1; + * m(0, 2) = 2; + * m(0, 3) = 3; + * \endcode + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_MATRIX_PLUGIN. + * + * Some notes: + * + *
+ *
\anchor dense Dense versus sparse:
+ *
This %Matrix class handles dense, not sparse matrices and vectors. For sparse matrices and vectors, see the Sparse module. + * + * Dense matrices and vectors are plain usual arrays of coefficients. All the coefficients are stored, in an ordinary contiguous array. + * This is unlike Sparse matrices and vectors where the coefficients are stored as a list of nonzero coefficients.
+ * + *
\anchor fixedsize Fixed-size versus dynamic-size:
+ *
Fixed-size means that the numbers of rows and columns are known are compile-time. In this case, Eigen allocates the array + * of coefficients as a fixed-size array, as a class member. This makes sense for very small matrices, typically up to 4x4, sometimes up + * to 16x16. Larger matrices should be declared as dynamic-size even if one happens to know their size at compile-time. + * + * Dynamic-size means that the numbers of rows or columns are not necessarily known at compile-time. In this case they are runtime + * variables, and the array of coefficients is allocated dynamically on the heap. + * + * Note that \em dense matrices, be they Fixed-size or Dynamic-size, do not expand dynamically in the sense of a std::map. + * If you want this behavior, see the Sparse module.
+ * + *
\anchor maxrows _MaxRows and _MaxCols:
+ *
In most cases, one just leaves these parameters to the default values. + * These parameters mean the maximum size of rows and columns that the matrix may have. They are useful in cases + * when the exact numbers of rows and columns are not known are compile-time, but it is known at compile-time that they cannot + * exceed a certain value. This happens when taking dynamic-size blocks inside fixed-size matrices: in this case _MaxRows and _MaxCols + * are the dimensions of the original matrix, while _Rows and _Cols are Dynamic.
+ *
+ * + * \see MatrixBase for the majority of the API methods for matrices, \ref TopicClassHierarchy, + * \ref TopicStorageOrders + */ + +namespace internal { +template +struct traits > +{ + typedef _Scalar Scalar; + typedef Dense StorageKind; + typedef DenseIndex Index; + typedef MatrixXpr XprKind; + enum { + RowsAtCompileTime = _Rows, + ColsAtCompileTime = _Cols, + MaxRowsAtCompileTime = _MaxRows, + MaxColsAtCompileTime = _MaxCols, + Flags = compute_matrix_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret, + CoeffReadCost = NumTraits::ReadCost, + Options = _Options, + InnerStrideAtCompileTime = 1, + OuterStrideAtCompileTime = (Options&RowMajor) ? ColsAtCompileTime : RowsAtCompileTime + }; +}; +} + +template +class Matrix + : public PlainObjectBase > +{ + public: + + /** \brief Base class typedef. + * \sa PlainObjectBase + */ + typedef PlainObjectBase Base; + + enum { Options = _Options }; + + EIGEN_DENSE_PUBLIC_INTERFACE(Matrix) + + typedef typename Base::PlainObject PlainObject; + + using Base::base; + using Base::coeffRef; + + /** + * \brief Assigns matrices to each other. + * + * \note This is a special case of the templated operator=. Its purpose is + * to prevent a default operator= from hiding the templated operator=. + * + * \callgraph + */ + EIGEN_STRONG_INLINE Matrix& operator=(const Matrix& other) + { + return Base::_set(other); + } + + /** \internal + * \brief Copies the value of the expression \a other into \c *this with automatic resizing. + * + * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), + * it will be initialized. + * + * Note that copying a row-vector into a vector (and conversely) is allowed. + * The resizing, if any, is then done in the appropriate way so that row-vectors + * remain row-vectors and vectors remain vectors. + */ + template + EIGEN_STRONG_INLINE Matrix& operator=(const MatrixBase& other) + { + return Base::_set(other); + } + + /* Here, doxygen failed to copy the brief information when using \copydoc */ + + /** + * \brief Copies the generic expression \a other into *this. + * \copydetails DenseBase::operator=(const EigenBase &other) + */ + template + EIGEN_STRONG_INLINE Matrix& operator=(const EigenBase &other) + { + return Base::operator=(other); + } + + template + EIGEN_STRONG_INLINE Matrix& operator=(const ReturnByValue& func) + { + return Base::operator=(func); + } + + /** \brief Default constructor. + * + * For fixed-size matrices, does nothing. + * + * For dynamic-size matrices, creates an empty matrix of size 0. Does not allocate any array. Such a matrix + * is called a null matrix. This constructor is the unique way to create null matrices: resizing + * a matrix to 0 is not supported. + * + * \sa resize(Index,Index) + */ + EIGEN_STRONG_INLINE Matrix() : Base() + { + Base::_check_template_params(); + EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + } + + // FIXME is it still needed + Matrix(internal::constructor_without_unaligned_array_assert) + : Base(internal::constructor_without_unaligned_array_assert()) + { Base::_check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } + + /** \brief Constructs a vector or row-vector with given dimension. \only_for_vectors + * + * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, + * it is redundant to pass the dimension here, so it makes more sense to use the default + * constructor Matrix() instead. + */ + EIGEN_STRONG_INLINE explicit Matrix(Index dim) + : Base(dim, RowsAtCompileTime == 1 ? 1 : dim, ColsAtCompileTime == 1 ? 1 : dim) + { + Base::_check_template_params(); + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Matrix) + eigen_assert(dim >= 0); + eigen_assert(SizeAtCompileTime == Dynamic || SizeAtCompileTime == dim); + EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_STRONG_INLINE Matrix(const T0& x, const T1& y) + { + Base::_check_template_params(); + Base::template _init2(x, y); + } + #else + /** \brief Constructs an uninitialized matrix with \a rows rows and \a cols columns. + * + * This is useful for dynamic-size matrices. For fixed-size matrices, + * it is redundant to pass these parameters, so one should use the default constructor + * Matrix() instead. */ + Matrix(Index rows, Index cols); + /** \brief Constructs an initialized 2D vector with given coefficients */ + Matrix(const Scalar& x, const Scalar& y); + #endif + + /** \brief Constructs an initialized 3D vector with given coefficients */ + EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z) + { + Base::_check_template_params(); + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 3) + m_storage.data()[0] = x; + m_storage.data()[1] = y; + m_storage.data()[2] = z; + } + /** \brief Constructs an initialized 4D vector with given coefficients */ + EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z, const Scalar& w) + { + Base::_check_template_params(); + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 4) + m_storage.data()[0] = x; + m_storage.data()[1] = y; + m_storage.data()[2] = z; + m_storage.data()[3] = w; + } + + explicit Matrix(const Scalar *data); + + /** \brief Constructor copying the value of the expression \a other */ + template + EIGEN_STRONG_INLINE Matrix(const MatrixBase& other) + : Base(other.rows() * other.cols(), other.rows(), other.cols()) + { + // This test resides here, to bring the error messages closer to the user. Normally, these checks + // are performed deeply within the library, thus causing long and scary error traces. + EIGEN_STATIC_ASSERT((internal::is_same::value), + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + + Base::_check_template_params(); + Base::_set_noalias(other); + } + /** \brief Copy constructor */ + EIGEN_STRONG_INLINE Matrix(const Matrix& other) + : Base(other.rows() * other.cols(), other.rows(), other.cols()) + { + Base::_check_template_params(); + Base::_set_noalias(other); + } + /** \brief Copy constructor with in-place evaluation */ + template + EIGEN_STRONG_INLINE Matrix(const ReturnByValue& other) + { + Base::_check_template_params(); + Base::resize(other.rows(), other.cols()); + other.evalTo(*this); + } + + /** \brief Copy constructor for generic expressions. + * \sa MatrixBase::operator=(const EigenBase&) + */ + template + EIGEN_STRONG_INLINE Matrix(const EigenBase &other) + : Base(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) + { + Base::_check_template_params(); + Base::_resize_to_match(other); + // FIXME/CHECK: isn't *this = other.derived() more efficient. it allows to + // go for pure _set() implementations, right? + *this = other; + } + + /** \internal + * \brief Override MatrixBase::swap() since for dynamic-sized matrices + * of same type it is enough to swap the data pointers. + */ + template + void swap(MatrixBase const & other) + { this->_swap(other.derived()); } + + inline Index innerStride() const { return 1; } + inline Index outerStride() const { return this->innerSize(); } + + /////////// Geometry module /////////// + + template + explicit Matrix(const RotationBase& r); + template + Matrix& operator=(const RotationBase& r); + + #ifdef EIGEN2_SUPPORT + template + explicit Matrix(const eigen2_RotationBase& r); + template + Matrix& operator=(const eigen2_RotationBase& r); + #endif + + // allow to extend Matrix outside Eigen + #ifdef EIGEN_MATRIX_PLUGIN + #include EIGEN_MATRIX_PLUGIN + #endif + + protected: + template + friend struct internal::conservative_resize_like_impl; + + using Base::m_storage; +}; + +/** \defgroup matrixtypedefs Global matrix typedefs + * + * \ingroup Core_Module + * + * Eigen defines several typedef shortcuts for most common matrix and vector types. + * + * The general patterns are the following: + * + * \c MatrixSizeType where \c Size can be \c 2,\c 3,\c 4 for fixed size square matrices or \c X for dynamic size, + * and where \c Type can be \c i for integer, \c f for float, \c d for double, \c cf for complex float, \c cd + * for complex double. + * + * For example, \c Matrix3d is a fixed-size 3x3 matrix type of doubles, and \c MatrixXf is a dynamic-size matrix of floats. + * + * There are also \c VectorSizeType and \c RowVectorSizeType which are self-explanatory. For example, \c Vector4cf is + * a fixed-size vector of 4 complex floats. + * + * \sa class Matrix + */ + +#define EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix) \ +/** \ingroup matrixtypedefs */ \ +typedef Matrix Matrix##SizeSuffix##TypeSuffix; \ +/** \ingroup matrixtypedefs */ \ +typedef Matrix Vector##SizeSuffix##TypeSuffix; \ +/** \ingroup matrixtypedefs */ \ +typedef Matrix RowVector##SizeSuffix##TypeSuffix; + +#define EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, Size) \ +/** \ingroup matrixtypedefs */ \ +typedef Matrix Matrix##Size##X##TypeSuffix; \ +/** \ingroup matrixtypedefs */ \ +typedef Matrix Matrix##X##Size##TypeSuffix; + +#define EIGEN_MAKE_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \ +EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 2, 2) \ +EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 3, 3) \ +EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 4, 4) \ +EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Dynamic, X) \ +EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 2) \ +EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 3) \ +EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 4) + +EIGEN_MAKE_TYPEDEFS_ALL_SIZES(int, i) +EIGEN_MAKE_TYPEDEFS_ALL_SIZES(float, f) +EIGEN_MAKE_TYPEDEFS_ALL_SIZES(double, d) +EIGEN_MAKE_TYPEDEFS_ALL_SIZES(std::complex, cf) +EIGEN_MAKE_TYPEDEFS_ALL_SIZES(std::complex, cd) + +#undef EIGEN_MAKE_TYPEDEFS_ALL_SIZES +#undef EIGEN_MAKE_TYPEDEFS +#undef EIGEN_MAKE_FIXED_TYPEDEFS + +} // end namespace Eigen + +#endif // EIGEN_MATRIX_H diff --git a/libs/eigen3/Eigen/src/Core/MatrixBase.h b/libs/eigen3/Eigen/src/Core/MatrixBase.h new file mode 100644 index 000000000..344b38f2f --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/MatrixBase.h @@ -0,0 +1,560 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2009 Benoit Jacob +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_MATRIXBASE_H +#define EIGEN_MATRIXBASE_H + +namespace Eigen { + +/** \class MatrixBase + * \ingroup Core_Module + * + * \brief Base class for all dense matrices, vectors, and expressions + * + * This class is the base that is inherited by all matrix, vector, and related expression + * types. Most of the Eigen API is contained in this class, and its base classes. Other important + * classes for the Eigen API are Matrix, and VectorwiseOp. + * + * Note that some methods are defined in other modules such as the \ref LU_Module LU module + * for all functions related to matrix inversions. + * + * \tparam Derived is the derived type, e.g. a matrix type, or an expression, etc. + * + * When writing a function taking Eigen objects as argument, if you want your function + * to take as argument any matrix, vector, or expression, just let it take a + * MatrixBase argument. As an example, here is a function printFirstRow which, given + * a matrix, vector, or expression \a x, prints the first row of \a x. + * + * \code + template + void printFirstRow(const Eigen::MatrixBase& x) + { + cout << x.row(0) << endl; + } + * \endcode + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_MATRIXBASE_PLUGIN. + * + * \sa \ref TopicClassHierarchy + */ +template class MatrixBase + : public DenseBase +{ + public: +#ifndef EIGEN_PARSED_BY_DOXYGEN + typedef MatrixBase StorageBaseType; + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::packet_traits::type PacketScalar; + typedef typename NumTraits::Real RealScalar; + + typedef DenseBase Base; + using Base::RowsAtCompileTime; + using Base::ColsAtCompileTime; + using Base::SizeAtCompileTime; + using Base::MaxRowsAtCompileTime; + using Base::MaxColsAtCompileTime; + using Base::MaxSizeAtCompileTime; + using Base::IsVectorAtCompileTime; + using Base::Flags; + using Base::CoeffReadCost; + + using Base::derived; + using Base::const_cast_derived; + using Base::rows; + using Base::cols; + using Base::size; + using Base::coeff; + using Base::coeffRef; + using Base::lazyAssign; + using Base::eval; + using Base::operator+=; + using Base::operator-=; + using Base::operator*=; + using Base::operator/=; + + typedef typename Base::CoeffReturnType CoeffReturnType; + typedef typename Base::ConstTransposeReturnType ConstTransposeReturnType; + typedef typename Base::RowXpr RowXpr; + typedef typename Base::ColXpr ColXpr; +#endif // not EIGEN_PARSED_BY_DOXYGEN + + + +#ifndef EIGEN_PARSED_BY_DOXYGEN + /** type of the equivalent square matrix */ + typedef Matrix SquareMatrixType; +#endif // not EIGEN_PARSED_BY_DOXYGEN + + /** \returns the size of the main diagonal, which is min(rows(),cols()). + * \sa rows(), cols(), SizeAtCompileTime. */ + inline Index diagonalSize() const { return (std::min)(rows(),cols()); } + + /** \brief The plain matrix type corresponding to this expression. + * + * This is not necessarily exactly the return type of eval(). In the case of plain matrices, + * the return type of eval() is a const reference to a matrix, not a matrix! It is however guaranteed + * that the return type of eval() is either PlainObject or const PlainObject&. + */ + typedef Matrix::Scalar, + internal::traits::RowsAtCompileTime, + internal::traits::ColsAtCompileTime, + AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), + internal::traits::MaxRowsAtCompileTime, + internal::traits::MaxColsAtCompileTime + > PlainObject; + +#ifndef EIGEN_PARSED_BY_DOXYGEN + /** \internal Represents a matrix with all coefficients equal to one another*/ + typedef CwiseNullaryOp,Derived> ConstantReturnType; + /** \internal the return type of MatrixBase::adjoint() */ + typedef typename internal::conditional::IsComplex, + CwiseUnaryOp, ConstTransposeReturnType>, + ConstTransposeReturnType + >::type AdjointReturnType; + /** \internal Return type of eigenvalues() */ + typedef Matrix, internal::traits::ColsAtCompileTime, 1, ColMajor> EigenvaluesReturnType; + /** \internal the return type of identity */ + typedef CwiseNullaryOp,Derived> IdentityReturnType; + /** \internal the return type of unit vectors */ + typedef Block, SquareMatrixType>, + internal::traits::RowsAtCompileTime, + internal::traits::ColsAtCompileTime> BasisReturnType; +#endif // not EIGEN_PARSED_BY_DOXYGEN + +#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::MatrixBase +# include "../plugins/CommonCwiseUnaryOps.h" +# include "../plugins/CommonCwiseBinaryOps.h" +# include "../plugins/MatrixCwiseUnaryOps.h" +# include "../plugins/MatrixCwiseBinaryOps.h" +# ifdef EIGEN_MATRIXBASE_PLUGIN +# include EIGEN_MATRIXBASE_PLUGIN +# endif +#undef EIGEN_CURRENT_STORAGE_BASE_CLASS + + /** Special case of the template operator=, in order to prevent the compiler + * from generating a default operator= (issue hit with g++ 4.1) + */ + Derived& operator=(const MatrixBase& other); + + // We cannot inherit here via Base::operator= since it is causing + // trouble with MSVC. + + template + Derived& operator=(const DenseBase& other); + + template + Derived& operator=(const EigenBase& other); + + template + Derived& operator=(const ReturnByValue& other); + +#ifndef EIGEN_PARSED_BY_DOXYGEN + template + Derived& lazyAssign(const ProductBase& other); + + template + Derived& lazyAssign(const MatrixPowerProduct& other); +#endif // not EIGEN_PARSED_BY_DOXYGEN + + template + Derived& operator+=(const MatrixBase& other); + template + Derived& operator-=(const MatrixBase& other); + + template + const typename ProductReturnType::Type + operator*(const MatrixBase &other) const; + + template + const typename LazyProductReturnType::Type + lazyProduct(const MatrixBase &other) const; + + template + Derived& operator*=(const EigenBase& other); + + template + void applyOnTheLeft(const EigenBase& other); + + template + void applyOnTheRight(const EigenBase& other); + + template + const DiagonalProduct + operator*(const DiagonalBase &diagonal) const; + + template + typename internal::scalar_product_traits::Scalar,typename internal::traits::Scalar>::ReturnType + dot(const MatrixBase& other) const; + + #ifdef EIGEN2_SUPPORT + template + Scalar eigen2_dot(const MatrixBase& other) const; + #endif + + RealScalar squaredNorm() const; + RealScalar norm() const; + RealScalar stableNorm() const; + RealScalar blueNorm() const; + RealScalar hypotNorm() const; + const PlainObject normalized() const; + void normalize(); + + const AdjointReturnType adjoint() const; + void adjointInPlace(); + + typedef Diagonal DiagonalReturnType; + DiagonalReturnType diagonal(); + typedef typename internal::add_const >::type ConstDiagonalReturnType; + ConstDiagonalReturnType diagonal() const; + + template struct DiagonalIndexReturnType { typedef Diagonal Type; }; + template struct ConstDiagonalIndexReturnType { typedef const Diagonal Type; }; + + template typename DiagonalIndexReturnType::Type diagonal(); + template typename ConstDiagonalIndexReturnType::Type diagonal() const; + + // Note: The "MatrixBase::" prefixes are added to help MSVC9 to match these declarations with the later implementations. + // On the other hand they confuse MSVC8... + #if (defined _MSC_VER) && (_MSC_VER >= 1500) // 2008 or later + typename MatrixBase::template DiagonalIndexReturnType::Type diagonal(Index index); + typename MatrixBase::template ConstDiagonalIndexReturnType::Type diagonal(Index index) const; + #else + typename DiagonalIndexReturnType::Type diagonal(Index index); + typename ConstDiagonalIndexReturnType::Type diagonal(Index index) const; + #endif + + #ifdef EIGEN2_SUPPORT + template typename internal::eigen2_part_return_type::type part(); + template const typename internal::eigen2_part_return_type::type part() const; + + // huuuge hack. make Eigen2's matrix.part() work in eigen3. Problem: Diagonal is now a class template instead + // of an integer constant. Solution: overload the part() method template wrt template parameters list. + template class U> + const DiagonalWrapper part() const + { return diagonal().asDiagonal(); } + #endif // EIGEN2_SUPPORT + + template struct TriangularViewReturnType { typedef TriangularView Type; }; + template struct ConstTriangularViewReturnType { typedef const TriangularView Type; }; + + template typename TriangularViewReturnType::Type triangularView(); + template typename ConstTriangularViewReturnType::Type triangularView() const; + + template struct SelfAdjointViewReturnType { typedef SelfAdjointView Type; }; + template struct ConstSelfAdjointViewReturnType { typedef const SelfAdjointView Type; }; + + template typename SelfAdjointViewReturnType::Type selfadjointView(); + template typename ConstSelfAdjointViewReturnType::Type selfadjointView() const; + + const SparseView sparseView(const Scalar& m_reference = Scalar(0), + const typename NumTraits::Real& m_epsilon = NumTraits::dummy_precision()) const; + static const IdentityReturnType Identity(); + static const IdentityReturnType Identity(Index rows, Index cols); + static const BasisReturnType Unit(Index size, Index i); + static const BasisReturnType Unit(Index i); + static const BasisReturnType UnitX(); + static const BasisReturnType UnitY(); + static const BasisReturnType UnitZ(); + static const BasisReturnType UnitW(); + + const DiagonalWrapper asDiagonal() const; + const PermutationWrapper asPermutation() const; + + Derived& setIdentity(); + Derived& setIdentity(Index rows, Index cols); + + bool isIdentity(const RealScalar& prec = NumTraits::dummy_precision()) const; + bool isDiagonal(const RealScalar& prec = NumTraits::dummy_precision()) const; + + bool isUpperTriangular(const RealScalar& prec = NumTraits::dummy_precision()) const; + bool isLowerTriangular(const RealScalar& prec = NumTraits::dummy_precision()) const; + + template + bool isOrthogonal(const MatrixBase& other, + const RealScalar& prec = NumTraits::dummy_precision()) const; + bool isUnitary(const RealScalar& prec = NumTraits::dummy_precision()) const; + + /** \returns true if each coefficients of \c *this and \a other are all exactly equal. + * \warning When using floating point scalar values you probably should rather use a + * fuzzy comparison such as isApprox() + * \sa isApprox(), operator!= */ + template + inline bool operator==(const MatrixBase& other) const + { return cwiseEqual(other).all(); } + + /** \returns true if at least one pair of coefficients of \c *this and \a other are not exactly equal to each other. + * \warning When using floating point scalar values you probably should rather use a + * fuzzy comparison such as isApprox() + * \sa isApprox(), operator== */ + template + inline bool operator!=(const MatrixBase& other) const + { return cwiseNotEqual(other).any(); } + + NoAlias noalias(); + + inline const ForceAlignedAccess forceAlignedAccess() const; + inline ForceAlignedAccess forceAlignedAccess(); + template inline typename internal::add_const_on_value_type,Derived&>::type>::type forceAlignedAccessIf() const; + template inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); + + Scalar trace() const; + +/////////// Array module /////////// + + template RealScalar lpNorm() const; + + MatrixBase& matrix() { return *this; } + const MatrixBase& matrix() const { return *this; } + + /** \returns an \link Eigen::ArrayBase Array \endlink expression of this matrix + * \sa ArrayBase::matrix() */ + ArrayWrapper array() { return derived(); } + const ArrayWrapper array() const { return derived(); } + +/////////// LU module /////////// + + const FullPivLU fullPivLu() const; + const PartialPivLU partialPivLu() const; + + #if EIGEN2_SUPPORT_STAGE < STAGE20_RESOLVE_API_CONFLICTS + const LU lu() const; + #endif + + #ifdef EIGEN2_SUPPORT + const LU eigen2_lu() const; + #endif + + #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS + const PartialPivLU lu() const; + #endif + + #ifdef EIGEN2_SUPPORT + template + void computeInverse(MatrixBase *result) const { + *result = this->inverse(); + } + #endif + + const internal::inverse_impl inverse() const; + template + void computeInverseAndDetWithCheck( + ResultType& inverse, + typename ResultType::Scalar& determinant, + bool& invertible, + const RealScalar& absDeterminantThreshold = NumTraits::dummy_precision() + ) const; + template + void computeInverseWithCheck( + ResultType& inverse, + bool& invertible, + const RealScalar& absDeterminantThreshold = NumTraits::dummy_precision() + ) const; + Scalar determinant() const; + +/////////// Cholesky module /////////// + + const LLT llt() const; + const LDLT ldlt() const; + +/////////// QR module /////////// + + const HouseholderQR householderQr() const; + const ColPivHouseholderQR colPivHouseholderQr() const; + const FullPivHouseholderQR fullPivHouseholderQr() const; + + #ifdef EIGEN2_SUPPORT + const QR qr() const; + #endif + + EigenvaluesReturnType eigenvalues() const; + RealScalar operatorNorm() const; + +/////////// SVD module /////////// + + JacobiSVD jacobiSvd(unsigned int computationOptions = 0) const; + + #ifdef EIGEN2_SUPPORT + SVD svd() const; + #endif + +/////////// Geometry module /////////// + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /// \internal helper struct to form the return type of the cross product + template struct cross_product_return_type { + typedef typename internal::scalar_product_traits::Scalar,typename internal::traits::Scalar>::ReturnType Scalar; + typedef Matrix type; + }; + #endif // EIGEN_PARSED_BY_DOXYGEN + template + typename cross_product_return_type::type + cross(const MatrixBase& other) const; + template + PlainObject cross3(const MatrixBase& other) const; + PlainObject unitOrthogonal(void) const; + Matrix eulerAngles(Index a0, Index a1, Index a2) const; + + #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS + ScalarMultipleReturnType operator*(const UniformScaling& s) const; + // put this as separate enum value to work around possible GCC 4.3 bug (?) + enum { HomogeneousReturnTypeDirection = ColsAtCompileTime==1?Vertical:Horizontal }; + typedef Homogeneous HomogeneousReturnType; + HomogeneousReturnType homogeneous() const; + #endif + + enum { + SizeMinusOne = SizeAtCompileTime==Dynamic ? Dynamic : SizeAtCompileTime-1 + }; + typedef Block::ColsAtCompileTime==1 ? SizeMinusOne : 1, + internal::traits::ColsAtCompileTime==1 ? 1 : SizeMinusOne> ConstStartMinusOne; + typedef CwiseUnaryOp::Scalar>, + const ConstStartMinusOne > HNormalizedReturnType; + + const HNormalizedReturnType hnormalized() const; + +////////// Householder module /////////// + + void makeHouseholderInPlace(Scalar& tau, RealScalar& beta); + template + void makeHouseholder(EssentialPart& essential, + Scalar& tau, RealScalar& beta) const; + template + void applyHouseholderOnTheLeft(const EssentialPart& essential, + const Scalar& tau, + Scalar* workspace); + template + void applyHouseholderOnTheRight(const EssentialPart& essential, + const Scalar& tau, + Scalar* workspace); + +///////// Jacobi module ///////// + + template + void applyOnTheLeft(Index p, Index q, const JacobiRotation& j); + template + void applyOnTheRight(Index p, Index q, const JacobiRotation& j); + +///////// MatrixFunctions module ///////// + + typedef typename internal::stem_function::type StemFunction; + const MatrixExponentialReturnValue exp() const; + const MatrixFunctionReturnValue matrixFunction(StemFunction f) const; + const MatrixFunctionReturnValue cosh() const; + const MatrixFunctionReturnValue sinh() const; + const MatrixFunctionReturnValue cos() const; + const MatrixFunctionReturnValue sin() const; + const MatrixSquareRootReturnValue sqrt() const; + const MatrixLogarithmReturnValue log() const; + const MatrixPowerReturnValue pow(const RealScalar& p) const; + +#ifdef EIGEN2_SUPPORT + template + Derived& operator+=(const Flagged, 0, + EvalBeforeAssigningBit>& other); + + template + Derived& operator-=(const Flagged, 0, + EvalBeforeAssigningBit>& other); + + /** \deprecated because .lazy() is deprecated + * Overloaded for cache friendly product evaluation */ + template + Derived& lazyAssign(const Flagged& other) + { return lazyAssign(other._expression()); } + + template + const Flagged marked() const; + const Flagged lazy() const; + + inline const Cwise cwise() const; + inline Cwise cwise(); + + VectorBlock start(Index size); + const VectorBlock start(Index size) const; + VectorBlock end(Index size); + const VectorBlock end(Index size) const; + template VectorBlock start(); + template const VectorBlock start() const; + template VectorBlock end(); + template const VectorBlock end() const; + + Minor minor(Index row, Index col); + const Minor minor(Index row, Index col) const; +#endif + + protected: + MatrixBase() : Base() {} + + private: + explicit MatrixBase(int); + MatrixBase(int,int); + template explicit MatrixBase(const MatrixBase&); + protected: + // mixing arrays and matrices is not legal + template Derived& operator+=(const ArrayBase& ) + {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} + // mixing arrays and matrices is not legal + template Derived& operator-=(const ArrayBase& ) + {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} +}; + + +/*************************************************************************** +* Implementation of matrix base methods +***************************************************************************/ + +/** replaces \c *this by \c *this * \a other. + * + * \returns a reference to \c *this + * + * Example: \include MatrixBase_applyOnTheRight.cpp + * Output: \verbinclude MatrixBase_applyOnTheRight.out + */ +template +template +inline Derived& +MatrixBase::operator*=(const EigenBase &other) +{ + other.derived().applyThisOnTheRight(derived()); + return derived(); +} + +/** replaces \c *this by \c *this * \a other. It is equivalent to MatrixBase::operator*=(). + * + * Example: \include MatrixBase_applyOnTheRight.cpp + * Output: \verbinclude MatrixBase_applyOnTheRight.out + */ +template +template +inline void MatrixBase::applyOnTheRight(const EigenBase &other) +{ + other.derived().applyThisOnTheRight(derived()); +} + +/** replaces \c *this by \a other * \c *this. + * + * Example: \include MatrixBase_applyOnTheLeft.cpp + * Output: \verbinclude MatrixBase_applyOnTheLeft.out + */ +template +template +inline void MatrixBase::applyOnTheLeft(const EigenBase &other) +{ + other.derived().applyThisOnTheLeft(derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_MATRIXBASE_H diff --git a/libs/eigen3/Eigen/src/Core/NestByValue.h b/libs/eigen3/Eigen/src/Core/NestByValue.h new file mode 100644 index 000000000..a893b1761 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/NestByValue.h @@ -0,0 +1,111 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_NESTBYVALUE_H +#define EIGEN_NESTBYVALUE_H + +namespace Eigen { + +/** \class NestByValue + * \ingroup Core_Module + * + * \brief Expression which must be nested by value + * + * \param ExpressionType the type of the object of which we are requiring nesting-by-value + * + * This class is the return type of MatrixBase::nestByValue() + * and most of the time this is the only way it is used. + * + * \sa MatrixBase::nestByValue() + */ + +namespace internal { +template +struct traits > : public traits +{}; +} + +template class NestByValue + : public internal::dense_xpr_base< NestByValue >::type +{ + public: + + typedef typename internal::dense_xpr_base::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(NestByValue) + + inline NestByValue(const ExpressionType& matrix) : m_expression(matrix) {} + + inline Index rows() const { return m_expression.rows(); } + inline Index cols() const { return m_expression.cols(); } + inline Index outerStride() const { return m_expression.outerStride(); } + inline Index innerStride() const { return m_expression.innerStride(); } + + inline const CoeffReturnType coeff(Index row, Index col) const + { + return m_expression.coeff(row, col); + } + + inline Scalar& coeffRef(Index row, Index col) + { + return m_expression.const_cast_derived().coeffRef(row, col); + } + + inline const CoeffReturnType coeff(Index index) const + { + return m_expression.coeff(index); + } + + inline Scalar& coeffRef(Index index) + { + return m_expression.const_cast_derived().coeffRef(index); + } + + template + inline const PacketScalar packet(Index row, Index col) const + { + return m_expression.template packet(row, col); + } + + template + inline void writePacket(Index row, Index col, const PacketScalar& x) + { + m_expression.const_cast_derived().template writePacket(row, col, x); + } + + template + inline const PacketScalar packet(Index index) const + { + return m_expression.template packet(index); + } + + template + inline void writePacket(Index index, const PacketScalar& x) + { + m_expression.const_cast_derived().template writePacket(index, x); + } + + operator const ExpressionType&() const { return m_expression; } + + protected: + const ExpressionType m_expression; +}; + +/** \returns an expression of the temporary version of *this. + */ +template +inline const NestByValue +DenseBase::nestByValue() const +{ + return NestByValue(derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_NESTBYVALUE_H diff --git a/libs/eigen3/Eigen/src/Core/NoAlias.h b/libs/eigen3/Eigen/src/Core/NoAlias.h new file mode 100644 index 000000000..768bfb18c --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/NoAlias.h @@ -0,0 +1,134 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_NOALIAS_H +#define EIGEN_NOALIAS_H + +namespace Eigen { + +/** \class NoAlias + * \ingroup Core_Module + * + * \brief Pseudo expression providing an operator = assuming no aliasing + * + * \param ExpressionType the type of the object on which to do the lazy assignment + * + * This class represents an expression with special assignment operators + * assuming no aliasing between the target expression and the source expression. + * More precisely it alloas to bypass the EvalBeforeAssignBit flag of the source expression. + * It is the return type of MatrixBase::noalias() + * and most of the time this is the only way it is used. + * + * \sa MatrixBase::noalias() + */ +template class StorageBase> +class NoAlias +{ + typedef typename ExpressionType::Scalar Scalar; + public: + NoAlias(ExpressionType& expression) : m_expression(expression) {} + + /** Behaves like MatrixBase::lazyAssign(other) + * \sa MatrixBase::lazyAssign() */ + template + EIGEN_STRONG_INLINE ExpressionType& operator=(const StorageBase& other) + { return internal::assign_selector::run(m_expression,other.derived()); } + + /** \sa MatrixBase::operator+= */ + template + EIGEN_STRONG_INLINE ExpressionType& operator+=(const StorageBase& other) + { + typedef SelfCwiseBinaryOp, ExpressionType, OtherDerived> SelfAdder; + SelfAdder tmp(m_expression); + typedef typename internal::nested::type OtherDerivedNested; + typedef typename internal::remove_all::type _OtherDerivedNested; + internal::assign_selector::run(tmp,OtherDerivedNested(other.derived())); + return m_expression; + } + + /** \sa MatrixBase::operator-= */ + template + EIGEN_STRONG_INLINE ExpressionType& operator-=(const StorageBase& other) + { + typedef SelfCwiseBinaryOp, ExpressionType, OtherDerived> SelfAdder; + SelfAdder tmp(m_expression); + typedef typename internal::nested::type OtherDerivedNested; + typedef typename internal::remove_all::type _OtherDerivedNested; + internal::assign_selector::run(tmp,OtherDerivedNested(other.derived())); + return m_expression; + } + +#ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_STRONG_INLINE ExpressionType& operator+=(const ProductBase& other) + { other.derived().addTo(m_expression); return m_expression; } + + template + EIGEN_STRONG_INLINE ExpressionType& operator-=(const ProductBase& other) + { other.derived().subTo(m_expression); return m_expression; } + + template + EIGEN_STRONG_INLINE ExpressionType& operator+=(const CoeffBasedProduct& other) + { return m_expression.derived() += CoeffBasedProduct(other.lhs(), other.rhs()); } + + template + EIGEN_STRONG_INLINE ExpressionType& operator-=(const CoeffBasedProduct& other) + { return m_expression.derived() -= CoeffBasedProduct(other.lhs(), other.rhs()); } + + template + ExpressionType& operator=(const ReturnByValue& func) + { return m_expression = func; } +#endif + + ExpressionType& expression() const + { + return m_expression; + } + + protected: + ExpressionType& m_expression; +}; + +/** \returns a pseudo expression of \c *this with an operator= assuming + * no aliasing between \c *this and the source expression. + * + * More precisely, noalias() allows to bypass the EvalBeforeAssignBit flag. + * Currently, even though several expressions may alias, only product + * expressions have this flag. Therefore, noalias() is only usefull when + * the source expression contains a matrix product. + * + * Here are some examples where noalias is usefull: + * \code + * D.noalias() = A * B; + * D.noalias() += A.transpose() * B; + * D.noalias() -= 2 * A * B.adjoint(); + * \endcode + * + * On the other hand the following example will lead to a \b wrong result: + * \code + * A.noalias() = A * B; + * \endcode + * because the result matrix A is also an operand of the matrix product. Therefore, + * there is no alternative than evaluating A * B in a temporary, that is the default + * behavior when you write: + * \code + * A = A * B; + * \endcode + * + * \sa class NoAlias + */ +template +NoAlias MatrixBase::noalias() +{ + return derived(); +} + +} // end namespace Eigen + +#endif // EIGEN_NOALIAS_H diff --git a/libs/eigen3/Eigen/src/Core/NumTraits.h b/libs/eigen3/Eigen/src/Core/NumTraits.h new file mode 100644 index 000000000..bac9e50b8 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/NumTraits.h @@ -0,0 +1,150 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2010 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_NUMTRAITS_H +#define EIGEN_NUMTRAITS_H + +namespace Eigen { + +/** \class NumTraits + * \ingroup Core_Module + * + * \brief Holds information about the various numeric (i.e. scalar) types allowed by Eigen. + * + * \param T the numeric type at hand + * + * This class stores enums, typedefs and static methods giving information about a numeric type. + * + * The provided data consists of: + * \li A typedef \a Real, giving the "real part" type of \a T. If \a T is already real, + * then \a Real is just a typedef to \a T. If \a T is \c std::complex then \a Real + * is a typedef to \a U. + * \li A typedef \a NonInteger, giving the type that should be used for operations producing non-integral values, + * such as quotients, square roots, etc. If \a T is a floating-point type, then this typedef just gives + * \a T again. Note however that many Eigen functions such as internal::sqrt simply refuse to + * take integers. Outside of a few cases, Eigen doesn't do automatic type promotion. Thus, this typedef is + * only intended as a helper for code that needs to explicitly promote types. + * \li A typedef \a Nested giving the type to use to nest a value inside of the expression tree. If you don't know what + * this means, just use \a T here. + * \li An enum value \a IsComplex. It is equal to 1 if \a T is a \c std::complex + * type, and to 0 otherwise. + * \li An enum value \a IsInteger. It is equal to \c 1 if \a T is an integer type such as \c int, + * and to \c 0 otherwise. + * \li Enum values ReadCost, AddCost and MulCost representing a rough estimate of the number of CPU cycles needed + * to by move / add / mul instructions respectively, assuming the data is already stored in CPU registers. + * Stay vague here. No need to do architecture-specific stuff. + * \li An enum value \a IsSigned. It is equal to \c 1 if \a T is a signed type and to 0 if \a T is unsigned. + * \li An enum value \a RequireInitialization. It is equal to \c 1 if the constructor of the numeric type \a T must + * be called, and to 0 if it is safe not to call it. Default is 0 if \a T is an arithmetic type, and 1 otherwise. + * \li An epsilon() function which, unlike std::numeric_limits::epsilon(), returns a \a Real instead of a \a T. + * \li A dummy_precision() function returning a weak epsilon value. It is mainly used as a default + * value by the fuzzy comparison operators. + * \li highest() and lowest() functions returning the highest and lowest possible values respectively. + */ + +template struct GenericNumTraits +{ + enum { + IsInteger = std::numeric_limits::is_integer, + IsSigned = std::numeric_limits::is_signed, + IsComplex = 0, + RequireInitialization = internal::is_arithmetic::value ? 0 : 1, + ReadCost = 1, + AddCost = 1, + MulCost = 1 + }; + + typedef T Real; + typedef typename internal::conditional< + IsInteger, + typename internal::conditional::type, + T + >::type NonInteger; + typedef T Nested; + + static inline Real epsilon() { return std::numeric_limits::epsilon(); } + static inline Real dummy_precision() + { + // make sure to override this for floating-point types + return Real(0); + } + static inline T highest() { return (std::numeric_limits::max)(); } + static inline T lowest() { return IsInteger ? (std::numeric_limits::min)() : (-(std::numeric_limits::max)()); } + +#ifdef EIGEN2_SUPPORT + enum { + HasFloatingPoint = !IsInteger + }; + typedef NonInteger FloatingPoint; +#endif +}; + +template struct NumTraits : GenericNumTraits +{}; + +template<> struct NumTraits + : GenericNumTraits +{ + static inline float dummy_precision() { return 1e-5f; } +}; + +template<> struct NumTraits : GenericNumTraits +{ + static inline double dummy_precision() { return 1e-12; } +}; + +template<> struct NumTraits + : GenericNumTraits +{ + static inline long double dummy_precision() { return 1e-15l; } +}; + +template struct NumTraits > + : GenericNumTraits > +{ + typedef _Real Real; + enum { + IsComplex = 1, + RequireInitialization = NumTraits<_Real>::RequireInitialization, + ReadCost = 2 * NumTraits<_Real>::ReadCost, + AddCost = 2 * NumTraits::AddCost, + MulCost = 4 * NumTraits::MulCost + 2 * NumTraits::AddCost + }; + + static inline Real epsilon() { return NumTraits::epsilon(); } + static inline Real dummy_precision() { return NumTraits::dummy_precision(); } +}; + +template +struct NumTraits > +{ + typedef Array ArrayType; + typedef typename NumTraits::Real RealScalar; + typedef Array Real; + typedef typename NumTraits::NonInteger NonIntegerScalar; + typedef Array NonInteger; + typedef ArrayType & Nested; + + enum { + IsComplex = NumTraits::IsComplex, + IsInteger = NumTraits::IsInteger, + IsSigned = NumTraits::IsSigned, + RequireInitialization = 1, + ReadCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits::ReadCost, + AddCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits::AddCost, + MulCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits::MulCost + }; + + static inline RealScalar epsilon() { return NumTraits::epsilon(); } + static inline RealScalar dummy_precision() { return NumTraits::dummy_precision(); } +}; + +} // end namespace Eigen + +#endif // EIGEN_NUMTRAITS_H diff --git a/libs/eigen3/Eigen/src/Core/PermutationMatrix.h b/libs/eigen3/Eigen/src/Core/PermutationMatrix.h new file mode 100644 index 000000000..1297b8413 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/PermutationMatrix.h @@ -0,0 +1,689 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Benoit Jacob +// Copyright (C) 2009-2011 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_PERMUTATIONMATRIX_H +#define EIGEN_PERMUTATIONMATRIX_H + +namespace Eigen { + +template class PermutedImpl; + +/** \class PermutationBase + * \ingroup Core_Module + * + * \brief Base class for permutations + * + * \param Derived the derived class + * + * This class is the base class for all expressions representing a permutation matrix, + * internally stored as a vector of integers. + * The convention followed here is that if \f$ \sigma \f$ is a permutation, the corresponding permutation matrix + * \f$ P_\sigma \f$ is such that if \f$ (e_1,\ldots,e_p) \f$ is the canonical basis, we have: + * \f[ P_\sigma(e_i) = e_{\sigma(i)}. \f] + * This convention ensures that for any two permutations \f$ \sigma, \tau \f$, we have: + * \f[ P_{\sigma\circ\tau} = P_\sigma P_\tau. \f] + * + * Permutation matrices are square and invertible. + * + * Notice that in addition to the member functions and operators listed here, there also are non-member + * operator* to multiply any kind of permutation object with any kind of matrix expression (MatrixBase) + * on either side. + * + * \sa class PermutationMatrix, class PermutationWrapper + */ + +namespace internal { + +template +struct permut_matrix_product_retval; +template +struct permut_sparsematrix_product_retval; +enum PermPermProduct_t {PermPermProduct}; + +} // end namespace internal + +template +class PermutationBase : public EigenBase +{ + typedef internal::traits Traits; + typedef EigenBase Base; + public: + + #ifndef EIGEN_PARSED_BY_DOXYGEN + typedef typename Traits::IndicesType IndicesType; + enum { + Flags = Traits::Flags, + CoeffReadCost = Traits::CoeffReadCost, + RowsAtCompileTime = Traits::RowsAtCompileTime, + ColsAtCompileTime = Traits::ColsAtCompileTime, + MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = Traits::MaxColsAtCompileTime + }; + typedef typename Traits::Scalar Scalar; + typedef typename Traits::Index Index; + typedef Matrix + DenseMatrixType; + typedef PermutationMatrix + PlainPermutationType; + using Base::derived; + #endif + + /** Copies the other permutation into *this */ + template + Derived& operator=(const PermutationBase& other) + { + indices() = other.indices(); + return derived(); + } + + /** Assignment from the Transpositions \a tr */ + template + Derived& operator=(const TranspositionsBase& tr) + { + setIdentity(tr.size()); + for(Index k=size()-1; k>=0; --k) + applyTranspositionOnTheRight(k,tr.coeff(k)); + return derived(); + } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** This is a special case of the templated operator=. Its purpose is to + * prevent a default operator= from hiding the templated operator=. + */ + Derived& operator=(const PermutationBase& other) + { + indices() = other.indices(); + return derived(); + } + #endif + + /** \returns the number of rows */ + inline Index rows() const { return Index(indices().size()); } + + /** \returns the number of columns */ + inline Index cols() const { return Index(indices().size()); } + + /** \returns the size of a side of the respective square matrix, i.e., the number of indices */ + inline Index size() const { return Index(indices().size()); } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + void evalTo(MatrixBase& other) const + { + other.setZero(); + for (int i=0; i=0 && j>=0 && i=0 && j>=0 && i inverse() const + { return derived(); } + /** \returns the tranpose permutation matrix. + * + * \note \note_try_to_help_rvo + */ + inline Transpose transpose() const + { return derived(); } + + /**** multiplication helpers to hopefully get RVO ****/ + + +#ifndef EIGEN_PARSED_BY_DOXYGEN + protected: + template + void assignTranspose(const PermutationBase& other) + { + for (int i=0; i + void assignProduct(const Lhs& lhs, const Rhs& rhs) + { + eigen_assert(lhs.cols() == rhs.rows()); + for (int i=0; i + inline PlainPermutationType operator*(const PermutationBase& other) const + { return PlainPermutationType(internal::PermPermProduct, derived(), other.derived()); } + + /** \returns the product of a permutation with another inverse permutation. + * + * \note \note_try_to_help_rvo + */ + template + inline PlainPermutationType operator*(const Transpose >& other) const + { return PlainPermutationType(internal::PermPermProduct, *this, other.eval()); } + + /** \returns the product of an inverse permutation with another permutation. + * + * \note \note_try_to_help_rvo + */ + template friend + inline PlainPermutationType operator*(const Transpose >& other, const PermutationBase& perm) + { return PlainPermutationType(internal::PermPermProduct, other.eval(), perm); } + + protected: + +}; + +/** \class PermutationMatrix + * \ingroup Core_Module + * + * \brief Permutation matrix + * + * \param SizeAtCompileTime the number of rows/cols, or Dynamic + * \param MaxSizeAtCompileTime the maximum number of rows/cols, or Dynamic. This optional parameter defaults to SizeAtCompileTime. Most of the time, you should not have to specify it. + * \param IndexType the interger type of the indices + * + * This class represents a permutation matrix, internally stored as a vector of integers. + * + * \sa class PermutationBase, class PermutationWrapper, class DiagonalMatrix + */ + +namespace internal { +template +struct traits > + : traits > +{ + typedef IndexType Index; + typedef Matrix IndicesType; +}; +} + +template +class PermutationMatrix : public PermutationBase > +{ + typedef PermutationBase Base; + typedef internal::traits Traits; + public: + + #ifndef EIGEN_PARSED_BY_DOXYGEN + typedef typename Traits::IndicesType IndicesType; + #endif + + inline PermutationMatrix() + {} + + /** Constructs an uninitialized permutation matrix of given size. + */ + inline PermutationMatrix(int size) : m_indices(size) + {} + + /** Copy constructor. */ + template + inline PermutationMatrix(const PermutationBase& other) + : m_indices(other.indices()) {} + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** Standard copy constructor. Defined only to prevent a default copy constructor + * from hiding the other templated constructor */ + inline PermutationMatrix(const PermutationMatrix& other) : m_indices(other.indices()) {} + #endif + + /** Generic constructor from expression of the indices. The indices + * array has the meaning that the permutations sends each integer i to indices[i]. + * + * \warning It is your responsibility to check that the indices array that you passes actually + * describes a permutation, i.e., each value between 0 and n-1 occurs exactly once, where n is the + * array's size. + */ + template + explicit inline PermutationMatrix(const MatrixBase& a_indices) : m_indices(a_indices) + {} + + /** Convert the Transpositions \a tr to a permutation matrix */ + template + explicit PermutationMatrix(const TranspositionsBase& tr) + : m_indices(tr.size()) + { + *this = tr; + } + + /** Copies the other permutation into *this */ + template + PermutationMatrix& operator=(const PermutationBase& other) + { + m_indices = other.indices(); + return *this; + } + + /** Assignment from the Transpositions \a tr */ + template + PermutationMatrix& operator=(const TranspositionsBase& tr) + { + return Base::operator=(tr.derived()); + } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** This is a special case of the templated operator=. Its purpose is to + * prevent a default operator= from hiding the templated operator=. + */ + PermutationMatrix& operator=(const PermutationMatrix& other) + { + m_indices = other.m_indices; + return *this; + } + #endif + + /** const version of indices(). */ + const IndicesType& indices() const { return m_indices; } + /** \returns a reference to the stored array representing the permutation. */ + IndicesType& indices() { return m_indices; } + + + /**** multiplication helpers to hopefully get RVO ****/ + +#ifndef EIGEN_PARSED_BY_DOXYGEN + template + PermutationMatrix(const Transpose >& other) + : m_indices(other.nestedPermutation().size()) + { + for (int i=0; i + PermutationMatrix(internal::PermPermProduct_t, const Lhs& lhs, const Rhs& rhs) + : m_indices(lhs.indices().size()) + { + Base::assignProduct(lhs,rhs); + } +#endif + + protected: + + IndicesType m_indices; +}; + + +namespace internal { +template +struct traits,_PacketAccess> > + : traits > +{ + typedef IndexType Index; + typedef Map, _PacketAccess> IndicesType; +}; +} + +template +class Map,_PacketAccess> + : public PermutationBase,_PacketAccess> > +{ + typedef PermutationBase Base; + typedef internal::traits Traits; + public: + + #ifndef EIGEN_PARSED_BY_DOXYGEN + typedef typename Traits::IndicesType IndicesType; + typedef typename IndicesType::Scalar Index; + #endif + + inline Map(const Index* indicesPtr) + : m_indices(indicesPtr) + {} + + inline Map(const Index* indicesPtr, Index size) + : m_indices(indicesPtr,size) + {} + + /** Copies the other permutation into *this */ + template + Map& operator=(const PermutationBase& other) + { return Base::operator=(other.derived()); } + + /** Assignment from the Transpositions \a tr */ + template + Map& operator=(const TranspositionsBase& tr) + { return Base::operator=(tr.derived()); } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** This is a special case of the templated operator=. Its purpose is to + * prevent a default operator= from hiding the templated operator=. + */ + Map& operator=(const Map& other) + { + m_indices = other.m_indices; + return *this; + } + #endif + + /** const version of indices(). */ + const IndicesType& indices() const { return m_indices; } + /** \returns a reference to the stored array representing the permutation. */ + IndicesType& indices() { return m_indices; } + + protected: + + IndicesType m_indices; +}; + +/** \class PermutationWrapper + * \ingroup Core_Module + * + * \brief Class to view a vector of integers as a permutation matrix + * + * \param _IndicesType the type of the vector of integer (can be any compatible expression) + * + * This class allows to view any vector expression of integers as a permutation matrix. + * + * \sa class PermutationBase, class PermutationMatrix + */ + +struct PermutationStorage {}; + +template class TranspositionsWrapper; +namespace internal { +template +struct traits > +{ + typedef PermutationStorage StorageKind; + typedef typename _IndicesType::Scalar Scalar; + typedef typename _IndicesType::Scalar Index; + typedef _IndicesType IndicesType; + enum { + RowsAtCompileTime = _IndicesType::SizeAtCompileTime, + ColsAtCompileTime = _IndicesType::SizeAtCompileTime, + MaxRowsAtCompileTime = IndicesType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = IndicesType::MaxColsAtCompileTime, + Flags = 0, + CoeffReadCost = _IndicesType::CoeffReadCost + }; +}; +} + +template +class PermutationWrapper : public PermutationBase > +{ + typedef PermutationBase Base; + typedef internal::traits Traits; + public: + + #ifndef EIGEN_PARSED_BY_DOXYGEN + typedef typename Traits::IndicesType IndicesType; + #endif + + inline PermutationWrapper(const IndicesType& a_indices) + : m_indices(a_indices) + {} + + /** const version of indices(). */ + const typename internal::remove_all::type& + indices() const { return m_indices; } + + protected: + + typename IndicesType::Nested m_indices; +}; + +/** \returns the matrix with the permutation applied to the columns. + */ +template +inline const internal::permut_matrix_product_retval +operator*(const MatrixBase& matrix, + const PermutationBase &permutation) +{ + return internal::permut_matrix_product_retval + + (permutation.derived(), matrix.derived()); +} + +/** \returns the matrix with the permutation applied to the rows. + */ +template +inline const internal::permut_matrix_product_retval + +operator*(const PermutationBase &permutation, + const MatrixBase& matrix) +{ + return internal::permut_matrix_product_retval + + (permutation.derived(), matrix.derived()); +} + +namespace internal { + +template +struct traits > +{ + typedef typename MatrixType::PlainObject ReturnType; +}; + +template +struct permut_matrix_product_retval + : public ReturnByValue > +{ + typedef typename remove_all::type MatrixTypeNestedCleaned; + typedef typename MatrixType::Index Index; + + permut_matrix_product_retval(const PermutationType& perm, const MatrixType& matrix) + : m_permutation(perm), m_matrix(matrix) + {} + + inline Index rows() const { return m_matrix.rows(); } + inline Index cols() const { return m_matrix.cols(); } + + template inline void evalTo(Dest& dst) const + { + const Index n = Side==OnTheLeft ? rows() : cols(); + // FIXME we need an is_same for expression that is not sensitive to constness. For instance + // is_same_xpr, Block >::value should be true. + if(is_same::value && extract_data(dst) == extract_data(m_matrix)) + { + // apply the permutation inplace + Matrix mask(m_permutation.size()); + mask.fill(false); + Index r = 0; + while(r < m_permutation.size()) + { + // search for the next seed + while(r=m_permutation.size()) + break; + // we got one, let's follow it until we are back to the seed + Index k0 = r++; + Index kPrev = k0; + mask.coeffRef(k0) = true; + for(Index k=m_permutation.indices().coeff(k0); k!=k0; k=m_permutation.indices().coeff(k)) + { + Block(dst, k) + .swap(Block + (dst,((Side==OnTheLeft) ^ Transposed) ? k0 : kPrev)); + + mask.coeffRef(k) = true; + kPrev = k; + } + } + } + else + { + for(int i = 0; i < n; ++i) + { + Block + (dst, ((Side==OnTheLeft) ^ Transposed) ? m_permutation.indices().coeff(i) : i) + + = + + Block + (m_matrix, ((Side==OnTheRight) ^ Transposed) ? m_permutation.indices().coeff(i) : i); + } + } + } + + protected: + const PermutationType& m_permutation; + typename MatrixType::Nested m_matrix; +}; + +/* Template partial specialization for transposed/inverse permutations */ + +template +struct traits > > + : traits +{}; + +} // end namespace internal + +template +class Transpose > + : public EigenBase > > +{ + typedef Derived PermutationType; + typedef typename PermutationType::IndicesType IndicesType; + typedef typename PermutationType::PlainPermutationType PlainPermutationType; + public: + + #ifndef EIGEN_PARSED_BY_DOXYGEN + typedef internal::traits Traits; + typedef typename Derived::DenseMatrixType DenseMatrixType; + enum { + Flags = Traits::Flags, + CoeffReadCost = Traits::CoeffReadCost, + RowsAtCompileTime = Traits::RowsAtCompileTime, + ColsAtCompileTime = Traits::ColsAtCompileTime, + MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = Traits::MaxColsAtCompileTime + }; + typedef typename Traits::Scalar Scalar; + #endif + + Transpose(const PermutationType& p) : m_permutation(p) {} + + inline int rows() const { return m_permutation.rows(); } + inline int cols() const { return m_permutation.cols(); } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + void evalTo(MatrixBase& other) const + { + other.setZero(); + for (int i=0; i friend + inline const internal::permut_matrix_product_retval + operator*(const MatrixBase& matrix, const Transpose& trPerm) + { + return internal::permut_matrix_product_retval(trPerm.m_permutation, matrix.derived()); + } + + /** \returns the matrix with the inverse permutation applied to the rows. + */ + template + inline const internal::permut_matrix_product_retval + operator*(const MatrixBase& matrix) const + { + return internal::permut_matrix_product_retval(m_permutation, matrix.derived()); + } + + const PermutationType& nestedPermutation() const { return m_permutation; } + + protected: + const PermutationType& m_permutation; +}; + +template +const PermutationWrapper MatrixBase::asPermutation() const +{ + return derived(); +} + +} // end namespace Eigen + +#endif // EIGEN_PERMUTATIONMATRIX_H diff --git a/libs/eigen3/Eigen/src/Core/PlainObjectBase.h b/libs/eigen3/Eigen/src/Core/PlainObjectBase.h new file mode 100644 index 000000000..dd34b59e5 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/PlainObjectBase.h @@ -0,0 +1,790 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_DENSESTORAGEBASE_H +#define EIGEN_DENSESTORAGEBASE_H + +#if defined(EIGEN_INITIALIZE_MATRICES_BY_ZERO) +# define EIGEN_INITIALIZE_COEFFS +# define EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED for(int i=0;i::quiet_NaN(); +#else +# undef EIGEN_INITIALIZE_COEFFS +# define EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED +#endif + +namespace Eigen { + +namespace internal { + +template struct check_rows_cols_for_overflow { + template + static EIGEN_ALWAYS_INLINE void run(Index, Index) + { + } +}; + +template<> struct check_rows_cols_for_overflow { + template + static EIGEN_ALWAYS_INLINE void run(Index rows, Index cols) + { + // http://hg.mozilla.org/mozilla-central/file/6c8a909977d3/xpcom/ds/CheckedInt.h#l242 + // we assume Index is signed + Index max_index = (size_t(1) << (8 * sizeof(Index) - 1)) - 1; // assume Index is signed + bool error = (rows == 0 || cols == 0) ? false + : (rows > max_index / cols); + if (error) + throw_std_bad_alloc(); + } +}; + +template +struct conservative_resize_like_impl; + +template struct matrix_swap_impl; + +} // end namespace internal + +/** \class PlainObjectBase + * \brief %Dense storage base class for matrices and arrays. + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_PLAINOBJECTBASE_PLUGIN. + * + * \sa \ref TopicClassHierarchy + */ +#ifdef EIGEN_PARSED_BY_DOXYGEN +namespace internal { + +// this is a warkaround to doxygen not being able to understand the inheritence logic +// when it is hidden by the dense_xpr_base helper struct. +template struct dense_xpr_base_dispatcher_for_doxygen;// : public MatrixBase {}; +/** This class is just a workaround for Doxygen and it does not not actually exist. */ +template +struct dense_xpr_base_dispatcher_for_doxygen > + : public MatrixBase > {}; +/** This class is just a workaround for Doxygen and it does not not actually exist. */ +template +struct dense_xpr_base_dispatcher_for_doxygen > + : public ArrayBase > {}; + +} // namespace internal + +template +class PlainObjectBase : public internal::dense_xpr_base_dispatcher_for_doxygen +#else +template +class PlainObjectBase : public internal::dense_xpr_base::type +#endif +{ + public: + enum { Options = internal::traits::Options }; + typedef typename internal::dense_xpr_base::type Base; + + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::packet_traits::type PacketScalar; + typedef typename NumTraits::Real RealScalar; + typedef Derived DenseType; + + using Base::RowsAtCompileTime; + using Base::ColsAtCompileTime; + using Base::SizeAtCompileTime; + using Base::MaxRowsAtCompileTime; + using Base::MaxColsAtCompileTime; + using Base::MaxSizeAtCompileTime; + using Base::IsVectorAtCompileTime; + using Base::Flags; + + template friend class Eigen::Map; + friend class Eigen::Map; + typedef Eigen::Map MapType; + friend class Eigen::Map; + typedef const Eigen::Map ConstMapType; + friend class Eigen::Map; + typedef Eigen::Map AlignedMapType; + friend class Eigen::Map; + typedef const Eigen::Map ConstAlignedMapType; + template struct StridedMapType { typedef Eigen::Map type; }; + template struct StridedConstMapType { typedef Eigen::Map type; }; + template struct StridedAlignedMapType { typedef Eigen::Map type; }; + template struct StridedConstAlignedMapType { typedef Eigen::Map type; }; + + protected: + DenseStorage m_storage; + + public: + enum { NeedsToAlign = SizeAtCompileTime != Dynamic && (internal::traits::Flags & AlignedBit) != 0 }; + EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) + + Base& base() { return *static_cast(this); } + const Base& base() const { return *static_cast(this); } + + EIGEN_STRONG_INLINE Index rows() const { return m_storage.rows(); } + EIGEN_STRONG_INLINE Index cols() const { return m_storage.cols(); } + + EIGEN_STRONG_INLINE const Scalar& coeff(Index rowId, Index colId) const + { + if(Flags & RowMajorBit) + return m_storage.data()[colId + rowId * m_storage.cols()]; + else // column-major + return m_storage.data()[rowId + colId * m_storage.rows()]; + } + + EIGEN_STRONG_INLINE const Scalar& coeff(Index index) const + { + return m_storage.data()[index]; + } + + EIGEN_STRONG_INLINE Scalar& coeffRef(Index rowId, Index colId) + { + if(Flags & RowMajorBit) + return m_storage.data()[colId + rowId * m_storage.cols()]; + else // column-major + return m_storage.data()[rowId + colId * m_storage.rows()]; + } + + EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) + { + return m_storage.data()[index]; + } + + EIGEN_STRONG_INLINE const Scalar& coeffRef(Index rowId, Index colId) const + { + if(Flags & RowMajorBit) + return m_storage.data()[colId + rowId * m_storage.cols()]; + else // column-major + return m_storage.data()[rowId + colId * m_storage.rows()]; + } + + EIGEN_STRONG_INLINE const Scalar& coeffRef(Index index) const + { + return m_storage.data()[index]; + } + + /** \internal */ + template + EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const + { + return internal::ploadt + (m_storage.data() + (Flags & RowMajorBit + ? colId + rowId * m_storage.cols() + : rowId + colId * m_storage.rows())); + } + + /** \internal */ + template + EIGEN_STRONG_INLINE PacketScalar packet(Index index) const + { + return internal::ploadt(m_storage.data() + index); + } + + /** \internal */ + template + EIGEN_STRONG_INLINE void writePacket(Index rowId, Index colId, const PacketScalar& val) + { + internal::pstoret + (m_storage.data() + (Flags & RowMajorBit + ? colId + rowId * m_storage.cols() + : rowId + colId * m_storage.rows()), val); + } + + /** \internal */ + template + EIGEN_STRONG_INLINE void writePacket(Index index, const PacketScalar& val) + { + internal::pstoret(m_storage.data() + index, val); + } + + /** \returns a const pointer to the data array of this matrix */ + EIGEN_STRONG_INLINE const Scalar *data() const + { return m_storage.data(); } + + /** \returns a pointer to the data array of this matrix */ + EIGEN_STRONG_INLINE Scalar *data() + { return m_storage.data(); } + + /** Resizes \c *this to a \a rows x \a cols matrix. + * + * This method is intended for dynamic-size matrices, although it is legal to call it on any + * matrix as long as fixed dimensions are left unchanged. If you only want to change the number + * of rows and/or of columns, you can use resize(NoChange_t, Index), resize(Index, NoChange_t). + * + * If the current number of coefficients of \c *this exactly matches the + * product \a rows * \a cols, then no memory allocation is performed and + * the current values are left unchanged. In all other cases, including + * shrinking, the data is reallocated and all previous values are lost. + * + * Example: \include Matrix_resize_int_int.cpp + * Output: \verbinclude Matrix_resize_int_int.out + * + * \sa resize(Index) for vectors, resize(NoChange_t, Index), resize(Index, NoChange_t) + */ + EIGEN_STRONG_INLINE void resize(Index nbRows, Index nbCols) + { + eigen_assert( EIGEN_IMPLIES(RowsAtCompileTime!=Dynamic,nbRows==RowsAtCompileTime) + && EIGEN_IMPLIES(ColsAtCompileTime!=Dynamic,nbCols==ColsAtCompileTime) + && EIGEN_IMPLIES(RowsAtCompileTime==Dynamic && MaxRowsAtCompileTime!=Dynamic,nbRows<=MaxRowsAtCompileTime) + && EIGEN_IMPLIES(ColsAtCompileTime==Dynamic && MaxColsAtCompileTime!=Dynamic,nbCols<=MaxColsAtCompileTime) + && nbRows>=0 && nbCols>=0 && "Invalid sizes when resizing a matrix or array."); + internal::check_rows_cols_for_overflow::run(nbRows, nbCols); + #ifdef EIGEN_INITIALIZE_COEFFS + Index size = nbRows*nbCols; + bool size_changed = size != this->size(); + m_storage.resize(size, nbRows, nbCols); + if(size_changed) EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + #else + internal::check_rows_cols_for_overflow::run(nbRows, nbCols); + m_storage.resize(nbRows*nbCols, nbRows, nbCols); + #endif + } + + /** Resizes \c *this to a vector of length \a size + * + * \only_for_vectors. This method does not work for + * partially dynamic matrices when the static dimension is anything other + * than 1. For example it will not work with Matrix. + * + * Example: \include Matrix_resize_int.cpp + * Output: \verbinclude Matrix_resize_int.out + * + * \sa resize(Index,Index), resize(NoChange_t, Index), resize(Index, NoChange_t) + */ + inline void resize(Index size) + { + EIGEN_STATIC_ASSERT_VECTOR_ONLY(PlainObjectBase) + eigen_assert(((SizeAtCompileTime == Dynamic && (MaxSizeAtCompileTime==Dynamic || size<=MaxSizeAtCompileTime)) || SizeAtCompileTime == size) && size>=0); + #ifdef EIGEN_INITIALIZE_COEFFS + bool size_changed = size != this->size(); + #endif + if(RowsAtCompileTime == 1) + m_storage.resize(size, 1, size); + else + m_storage.resize(size, size, 1); + #ifdef EIGEN_INITIALIZE_COEFFS + if(size_changed) EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + #endif + } + + /** Resizes the matrix, changing only the number of columns. For the parameter of type NoChange_t, just pass the special value \c NoChange + * as in the example below. + * + * Example: \include Matrix_resize_NoChange_int.cpp + * Output: \verbinclude Matrix_resize_NoChange_int.out + * + * \sa resize(Index,Index) + */ + inline void resize(NoChange_t, Index nbCols) + { + resize(rows(), nbCols); + } + + /** Resizes the matrix, changing only the number of rows. For the parameter of type NoChange_t, just pass the special value \c NoChange + * as in the example below. + * + * Example: \include Matrix_resize_int_NoChange.cpp + * Output: \verbinclude Matrix_resize_int_NoChange.out + * + * \sa resize(Index,Index) + */ + inline void resize(Index nbRows, NoChange_t) + { + resize(nbRows, cols()); + } + + /** Resizes \c *this to have the same dimensions as \a other. + * Takes care of doing all the checking that's needed. + * + * Note that copying a row-vector into a vector (and conversely) is allowed. + * The resizing, if any, is then done in the appropriate way so that row-vectors + * remain row-vectors and vectors remain vectors. + */ + template + EIGEN_STRONG_INLINE void resizeLike(const EigenBase& _other) + { + const OtherDerived& other = _other.derived(); + internal::check_rows_cols_for_overflow::run(other.rows(), other.cols()); + const Index othersize = other.rows()*other.cols(); + if(RowsAtCompileTime == 1) + { + eigen_assert(other.rows() == 1 || other.cols() == 1); + resize(1, othersize); + } + else if(ColsAtCompileTime == 1) + { + eigen_assert(other.rows() == 1 || other.cols() == 1); + resize(othersize, 1); + } + else resize(other.rows(), other.cols()); + } + + /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. + * + * The method is intended for matrices of dynamic size. If you only want to change the number + * of rows and/or of columns, you can use conservativeResize(NoChange_t, Index) or + * conservativeResize(Index, NoChange_t). + * + * Matrices are resized relative to the top-left element. In case values need to be + * appended to the matrix they will be uninitialized. + */ + EIGEN_STRONG_INLINE void conservativeResize(Index nbRows, Index nbCols) + { + internal::conservative_resize_like_impl::run(*this, nbRows, nbCols); + } + + /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. + * + * As opposed to conservativeResize(Index rows, Index cols), this version leaves + * the number of columns unchanged. + * + * In case the matrix is growing, new rows will be uninitialized. + */ + EIGEN_STRONG_INLINE void conservativeResize(Index nbRows, NoChange_t) + { + // Note: see the comment in conservativeResize(Index,Index) + conservativeResize(nbRows, cols()); + } + + /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. + * + * As opposed to conservativeResize(Index rows, Index cols), this version leaves + * the number of rows unchanged. + * + * In case the matrix is growing, new columns will be uninitialized. + */ + EIGEN_STRONG_INLINE void conservativeResize(NoChange_t, Index nbCols) + { + // Note: see the comment in conservativeResize(Index,Index) + conservativeResize(rows(), nbCols); + } + + /** Resizes the vector to \a size while retaining old values. + * + * \only_for_vectors. This method does not work for + * partially dynamic matrices when the static dimension is anything other + * than 1. For example it will not work with Matrix. + * + * When values are appended, they will be uninitialized. + */ + EIGEN_STRONG_INLINE void conservativeResize(Index size) + { + internal::conservative_resize_like_impl::run(*this, size); + } + + /** Resizes the matrix to \a rows x \a cols of \c other, while leaving old values untouched. + * + * The method is intended for matrices of dynamic size. If you only want to change the number + * of rows and/or of columns, you can use conservativeResize(NoChange_t, Index) or + * conservativeResize(Index, NoChange_t). + * + * Matrices are resized relative to the top-left element. In case values need to be + * appended to the matrix they will copied from \c other. + */ + template + EIGEN_STRONG_INLINE void conservativeResizeLike(const DenseBase& other) + { + internal::conservative_resize_like_impl::run(*this, other); + } + + /** This is a special case of the templated operator=. Its purpose is to + * prevent a default operator= from hiding the templated operator=. + */ + EIGEN_STRONG_INLINE Derived& operator=(const PlainObjectBase& other) + { + return _set(other); + } + + /** \sa MatrixBase::lazyAssign() */ + template + EIGEN_STRONG_INLINE Derived& lazyAssign(const DenseBase& other) + { + _resize_to_match(other); + return Base::lazyAssign(other.derived()); + } + + template + EIGEN_STRONG_INLINE Derived& operator=(const ReturnByValue& func) + { + resize(func.rows(), func.cols()); + return Base::operator=(func); + } + + EIGEN_STRONG_INLINE PlainObjectBase() : m_storage() + { +// _check_template_params(); +// EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + } + +#ifndef EIGEN_PARSED_BY_DOXYGEN + // FIXME is it still needed ? + /** \internal */ + PlainObjectBase(internal::constructor_without_unaligned_array_assert) + : m_storage(internal::constructor_without_unaligned_array_assert()) + { +// _check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + } +#endif + + EIGEN_STRONG_INLINE PlainObjectBase(Index a_size, Index nbRows, Index nbCols) + : m_storage(a_size, nbRows, nbCols) + { +// _check_template_params(); +// EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + } + + /** \copydoc MatrixBase::operator=(const EigenBase&) + */ + template + EIGEN_STRONG_INLINE Derived& operator=(const EigenBase &other) + { + _resize_to_match(other); + Base::operator=(other.derived()); + return this->derived(); + } + + /** \sa MatrixBase::operator=(const EigenBase&) */ + template + EIGEN_STRONG_INLINE PlainObjectBase(const EigenBase &other) + : m_storage(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) + { + _check_template_params(); + internal::check_rows_cols_for_overflow::run(other.derived().rows(), other.derived().cols()); + Base::operator=(other.derived()); + } + + /** \name Map + * These are convenience functions returning Map objects. The Map() static functions return unaligned Map objects, + * while the AlignedMap() functions return aligned Map objects and thus should be called only with 16-byte-aligned + * \a data pointers. + * + * \see class Map + */ + //@{ + static inline ConstMapType Map(const Scalar* data) + { return ConstMapType(data); } + static inline MapType Map(Scalar* data) + { return MapType(data); } + static inline ConstMapType Map(const Scalar* data, Index size) + { return ConstMapType(data, size); } + static inline MapType Map(Scalar* data, Index size) + { return MapType(data, size); } + static inline ConstMapType Map(const Scalar* data, Index rows, Index cols) + { return ConstMapType(data, rows, cols); } + static inline MapType Map(Scalar* data, Index rows, Index cols) + { return MapType(data, rows, cols); } + + static inline ConstAlignedMapType MapAligned(const Scalar* data) + { return ConstAlignedMapType(data); } + static inline AlignedMapType MapAligned(Scalar* data) + { return AlignedMapType(data); } + static inline ConstAlignedMapType MapAligned(const Scalar* data, Index size) + { return ConstAlignedMapType(data, size); } + static inline AlignedMapType MapAligned(Scalar* data, Index size) + { return AlignedMapType(data, size); } + static inline ConstAlignedMapType MapAligned(const Scalar* data, Index rows, Index cols) + { return ConstAlignedMapType(data, rows, cols); } + static inline AlignedMapType MapAligned(Scalar* data, Index rows, Index cols) + { return AlignedMapType(data, rows, cols); } + + template + static inline typename StridedConstMapType >::type Map(const Scalar* data, const Stride& stride) + { return typename StridedConstMapType >::type(data, stride); } + template + static inline typename StridedMapType >::type Map(Scalar* data, const Stride& stride) + { return typename StridedMapType >::type(data, stride); } + template + static inline typename StridedConstMapType >::type Map(const Scalar* data, Index size, const Stride& stride) + { return typename StridedConstMapType >::type(data, size, stride); } + template + static inline typename StridedMapType >::type Map(Scalar* data, Index size, const Stride& stride) + { return typename StridedMapType >::type(data, size, stride); } + template + static inline typename StridedConstMapType >::type Map(const Scalar* data, Index rows, Index cols, const Stride& stride) + { return typename StridedConstMapType >::type(data, rows, cols, stride); } + template + static inline typename StridedMapType >::type Map(Scalar* data, Index rows, Index cols, const Stride& stride) + { return typename StridedMapType >::type(data, rows, cols, stride); } + + template + static inline typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, const Stride& stride) + { return typename StridedConstAlignedMapType >::type(data, stride); } + template + static inline typename StridedAlignedMapType >::type MapAligned(Scalar* data, const Stride& stride) + { return typename StridedAlignedMapType >::type(data, stride); } + template + static inline typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, Index size, const Stride& stride) + { return typename StridedConstAlignedMapType >::type(data, size, stride); } + template + static inline typename StridedAlignedMapType >::type MapAligned(Scalar* data, Index size, const Stride& stride) + { return typename StridedAlignedMapType >::type(data, size, stride); } + template + static inline typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, Index rows, Index cols, const Stride& stride) + { return typename StridedConstAlignedMapType >::type(data, rows, cols, stride); } + template + static inline typename StridedAlignedMapType >::type MapAligned(Scalar* data, Index rows, Index cols, const Stride& stride) + { return typename StridedAlignedMapType >::type(data, rows, cols, stride); } + //@} + + using Base::setConstant; + Derived& setConstant(Index size, const Scalar& value); + Derived& setConstant(Index rows, Index cols, const Scalar& value); + + using Base::setZero; + Derived& setZero(Index size); + Derived& setZero(Index rows, Index cols); + + using Base::setOnes; + Derived& setOnes(Index size); + Derived& setOnes(Index rows, Index cols); + + using Base::setRandom; + Derived& setRandom(Index size); + Derived& setRandom(Index rows, Index cols); + + #ifdef EIGEN_PLAINOBJECTBASE_PLUGIN + #include EIGEN_PLAINOBJECTBASE_PLUGIN + #endif + + protected: + /** \internal Resizes *this in preparation for assigning \a other to it. + * Takes care of doing all the checking that's needed. + * + * Note that copying a row-vector into a vector (and conversely) is allowed. + * The resizing, if any, is then done in the appropriate way so that row-vectors + * remain row-vectors and vectors remain vectors. + */ + template + EIGEN_STRONG_INLINE void _resize_to_match(const EigenBase& other) + { + #ifdef EIGEN_NO_AUTOMATIC_RESIZING + eigen_assert((this->size()==0 || (IsVectorAtCompileTime ? (this->size() == other.size()) + : (rows() == other.rows() && cols() == other.cols()))) + && "Size mismatch. Automatic resizing is disabled because EIGEN_NO_AUTOMATIC_RESIZING is defined"); + EIGEN_ONLY_USED_FOR_DEBUG(other); + #else + resizeLike(other); + #endif + } + + /** + * \brief Copies the value of the expression \a other into \c *this with automatic resizing. + * + * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), + * it will be initialized. + * + * Note that copying a row-vector into a vector (and conversely) is allowed. + * The resizing, if any, is then done in the appropriate way so that row-vectors + * remain row-vectors and vectors remain vectors. + * + * \sa operator=(const MatrixBase&), _set_noalias() + * + * \internal + */ + template + EIGEN_STRONG_INLINE Derived& _set(const DenseBase& other) + { + _set_selector(other.derived(), typename internal::conditional(int(OtherDerived::Flags) & EvalBeforeAssigningBit), internal::true_type, internal::false_type>::type()); + return this->derived(); + } + + template + EIGEN_STRONG_INLINE void _set_selector(const OtherDerived& other, const internal::true_type&) { _set_noalias(other.eval()); } + + template + EIGEN_STRONG_INLINE void _set_selector(const OtherDerived& other, const internal::false_type&) { _set_noalias(other); } + + /** \internal Like _set() but additionally makes the assumption that no aliasing effect can happen (which + * is the case when creating a new matrix) so one can enforce lazy evaluation. + * + * \sa operator=(const MatrixBase&), _set() + */ + template + EIGEN_STRONG_INLINE Derived& _set_noalias(const DenseBase& other) + { + // I don't think we need this resize call since the lazyAssign will anyways resize + // and lazyAssign will be called by the assign selector. + //_resize_to_match(other); + // the 'false' below means to enforce lazy evaluation. We don't use lazyAssign() because + // it wouldn't allow to copy a row-vector into a column-vector. + return internal::assign_selector::run(this->derived(), other.derived()); + } + + template + EIGEN_STRONG_INLINE void _init2(Index nbRows, Index nbCols, typename internal::enable_if::type* = 0) + { + EIGEN_STATIC_ASSERT(bool(NumTraits::IsInteger) && + bool(NumTraits::IsInteger), + FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED) + resize(nbRows,nbCols); + } + template + EIGEN_STRONG_INLINE void _init2(const Scalar& val0, const Scalar& val1, typename internal::enable_if::type* = 0) + { + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 2) + m_storage.data()[0] = val0; + m_storage.data()[1] = val1; + } + + template + friend struct internal::matrix_swap_impl; + + /** \internal generic implementation of swap for dense storage since for dynamic-sized matrices of same type it is enough to swap the + * data pointers. + */ + template + void _swap(DenseBase const & other) + { + enum { SwapPointers = internal::is_same::value && Base::SizeAtCompileTime==Dynamic }; + internal::matrix_swap_impl::run(this->derived(), other.const_cast_derived()); + } + + public: +#ifndef EIGEN_PARSED_BY_DOXYGEN + static EIGEN_STRONG_INLINE void _check_template_params() + { + EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (Options&RowMajor)==RowMajor) + && EIGEN_IMPLIES(MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1, (Options&RowMajor)==0) + && ((RowsAtCompileTime == Dynamic) || (RowsAtCompileTime >= 0)) + && ((ColsAtCompileTime == Dynamic) || (ColsAtCompileTime >= 0)) + && ((MaxRowsAtCompileTime == Dynamic) || (MaxRowsAtCompileTime >= 0)) + && ((MaxColsAtCompileTime == Dynamic) || (MaxColsAtCompileTime >= 0)) + && (MaxRowsAtCompileTime == RowsAtCompileTime || RowsAtCompileTime==Dynamic) + && (MaxColsAtCompileTime == ColsAtCompileTime || ColsAtCompileTime==Dynamic) + && (Options & (DontAlign|RowMajor)) == Options), + INVALID_MATRIX_TEMPLATE_PARAMETERS) + } +#endif + +private: + enum { ThisConstantIsPrivateInPlainObjectBase }; +}; + +namespace internal { + +template +struct conservative_resize_like_impl +{ + typedef typename Derived::Index Index; + static void run(DenseBase& _this, Index rows, Index cols) + { + if (_this.rows() == rows && _this.cols() == cols) return; + EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Derived) + + if ( ( Derived::IsRowMajor && _this.cols() == cols) || // row-major and we change only the number of rows + (!Derived::IsRowMajor && _this.rows() == rows) ) // column-major and we change only the number of columns + { + internal::check_rows_cols_for_overflow::run(rows, cols); + _this.derived().m_storage.conservativeResize(rows*cols,rows,cols); + } + else + { + // The storage order does not allow us to use reallocation. + typename Derived::PlainObject tmp(rows,cols); + const Index common_rows = (std::min)(rows, _this.rows()); + const Index common_cols = (std::min)(cols, _this.cols()); + tmp.block(0,0,common_rows,common_cols) = _this.block(0,0,common_rows,common_cols); + _this.derived().swap(tmp); + } + } + + static void run(DenseBase& _this, const DenseBase& other) + { + if (_this.rows() == other.rows() && _this.cols() == other.cols()) return; + + // Note: Here is space for improvement. Basically, for conservativeResize(Index,Index), + // neither RowsAtCompileTime or ColsAtCompileTime must be Dynamic. If only one of the + // dimensions is dynamic, one could use either conservativeResize(Index rows, NoChange_t) or + // conservativeResize(NoChange_t, Index cols). For these methods new static asserts like + // EIGEN_STATIC_ASSERT_DYNAMIC_ROWS and EIGEN_STATIC_ASSERT_DYNAMIC_COLS would be good. + EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Derived) + EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(OtherDerived) + + if ( ( Derived::IsRowMajor && _this.cols() == other.cols()) || // row-major and we change only the number of rows + (!Derived::IsRowMajor && _this.rows() == other.rows()) ) // column-major and we change only the number of columns + { + const Index new_rows = other.rows() - _this.rows(); + const Index new_cols = other.cols() - _this.cols(); + _this.derived().m_storage.conservativeResize(other.size(),other.rows(),other.cols()); + if (new_rows>0) + _this.bottomRightCorner(new_rows, other.cols()) = other.bottomRows(new_rows); + else if (new_cols>0) + _this.bottomRightCorner(other.rows(), new_cols) = other.rightCols(new_cols); + } + else + { + // The storage order does not allow us to use reallocation. + typename Derived::PlainObject tmp(other); + const Index common_rows = (std::min)(tmp.rows(), _this.rows()); + const Index common_cols = (std::min)(tmp.cols(), _this.cols()); + tmp.block(0,0,common_rows,common_cols) = _this.block(0,0,common_rows,common_cols); + _this.derived().swap(tmp); + } + } +}; + +// Here, the specialization for vectors inherits from the general matrix case +// to allow calling .conservativeResize(rows,cols) on vectors. +template +struct conservative_resize_like_impl + : conservative_resize_like_impl +{ + using conservative_resize_like_impl::run; + + typedef typename Derived::Index Index; + static void run(DenseBase& _this, Index size) + { + const Index new_rows = Derived::RowsAtCompileTime==1 ? 1 : size; + const Index new_cols = Derived::RowsAtCompileTime==1 ? size : 1; + _this.derived().m_storage.conservativeResize(size,new_rows,new_cols); + } + + static void run(DenseBase& _this, const DenseBase& other) + { + if (_this.rows() == other.rows() && _this.cols() == other.cols()) return; + + const Index num_new_elements = other.size() - _this.size(); + + const Index new_rows = Derived::RowsAtCompileTime==1 ? 1 : other.rows(); + const Index new_cols = Derived::RowsAtCompileTime==1 ? other.cols() : 1; + _this.derived().m_storage.conservativeResize(other.size(),new_rows,new_cols); + + if (num_new_elements > 0) + _this.tail(num_new_elements) = other.tail(num_new_elements); + } +}; + +template +struct matrix_swap_impl +{ + static inline void run(MatrixTypeA& a, MatrixTypeB& b) + { + a.base().swap(b); + } +}; + +template +struct matrix_swap_impl +{ + static inline void run(MatrixTypeA& a, MatrixTypeB& b) + { + static_cast(a).m_storage.swap(static_cast(b).m_storage); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_DENSESTORAGEBASE_H diff --git a/libs/eigen3/Eigen/src/Core/ProductBase.h b/libs/eigen3/Eigen/src/Core/ProductBase.h new file mode 100644 index 000000000..a494b5f87 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/ProductBase.h @@ -0,0 +1,278 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_PRODUCTBASE_H +#define EIGEN_PRODUCTBASE_H + +namespace Eigen { + +/** \class ProductBase + * \ingroup Core_Module + * + */ + +namespace internal { +template +struct traits > +{ + typedef MatrixXpr XprKind; + typedef typename remove_all<_Lhs>::type Lhs; + typedef typename remove_all<_Rhs>::type Rhs; + typedef typename scalar_product_traits::ReturnType Scalar; + typedef typename promote_storage_type::StorageKind, + typename traits::StorageKind>::ret StorageKind; + typedef typename promote_index_type::Index, + typename traits::Index>::type Index; + enum { + RowsAtCompileTime = traits::RowsAtCompileTime, + ColsAtCompileTime = traits::ColsAtCompileTime, + MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = traits::MaxColsAtCompileTime, + Flags = (MaxRowsAtCompileTime==1 ? RowMajorBit : 0) + | EvalBeforeNestingBit | EvalBeforeAssigningBit | NestByRefBit, + // Note that EvalBeforeNestingBit and NestByRefBit + // are not used in practice because nested is overloaded for products + CoeffReadCost = 0 // FIXME why is it needed ? + }; +}; +} + +#define EIGEN_PRODUCT_PUBLIC_INTERFACE(Derived) \ + typedef ProductBase Base; \ + EIGEN_DENSE_PUBLIC_INTERFACE(Derived) \ + typedef typename Base::LhsNested LhsNested; \ + typedef typename Base::_LhsNested _LhsNested; \ + typedef typename Base::LhsBlasTraits LhsBlasTraits; \ + typedef typename Base::ActualLhsType ActualLhsType; \ + typedef typename Base::_ActualLhsType _ActualLhsType; \ + typedef typename Base::RhsNested RhsNested; \ + typedef typename Base::_RhsNested _RhsNested; \ + typedef typename Base::RhsBlasTraits RhsBlasTraits; \ + typedef typename Base::ActualRhsType ActualRhsType; \ + typedef typename Base::_ActualRhsType _ActualRhsType; \ + using Base::m_lhs; \ + using Base::m_rhs; + +template +class ProductBase : public MatrixBase +{ + public: + typedef MatrixBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(ProductBase) + + typedef typename Lhs::Nested LhsNested; + typedef typename internal::remove_all::type _LhsNested; + typedef internal::blas_traits<_LhsNested> LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef typename internal::remove_all::type _ActualLhsType; + typedef typename internal::traits::Scalar LhsScalar; + + typedef typename Rhs::Nested RhsNested; + typedef typename internal::remove_all::type _RhsNested; + typedef internal::blas_traits<_RhsNested> RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + typedef typename internal::remove_all::type _ActualRhsType; + typedef typename internal::traits::Scalar RhsScalar; + + // Diagonal of a product: no need to evaluate the arguments because they are going to be evaluated only once + typedef CoeffBasedProduct FullyLazyCoeffBaseProductType; + + public: + + typedef typename Base::PlainObject PlainObject; + + ProductBase(const Lhs& a_lhs, const Rhs& a_rhs) + : m_lhs(a_lhs), m_rhs(a_rhs) + { + eigen_assert(a_lhs.cols() == a_rhs.rows() + && "invalid matrix product" + && "if you wanted a coeff-wise or a dot product use the respective explicit functions"); + } + + inline Index rows() const { return m_lhs.rows(); } + inline Index cols() const { return m_rhs.cols(); } + + template + inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst,Scalar(1)); } + + template + inline void addTo(Dest& dst) const { scaleAndAddTo(dst,Scalar(1)); } + + template + inline void subTo(Dest& dst) const { scaleAndAddTo(dst,Scalar(-1)); } + + template + inline void scaleAndAddTo(Dest& dst, const Scalar& alpha) const { derived().scaleAndAddTo(dst,alpha); } + + const _LhsNested& lhs() const { return m_lhs; } + const _RhsNested& rhs() const { return m_rhs; } + + // Implicit conversion to the nested type (trigger the evaluation of the product) + operator const PlainObject& () const + { + m_result.resize(m_lhs.rows(), m_rhs.cols()); + derived().evalTo(m_result); + return m_result; + } + + const Diagonal diagonal() const + { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs); } + + template + const Diagonal diagonal() const + { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs); } + + const Diagonal diagonal(Index index) const + { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs).diagonal(index); } + + // restrict coeff accessors to 1x1 expressions. No need to care about mutators here since this isnt a Lvalue expression + typename Base::CoeffReturnType coeff(Index row, Index col) const + { +#ifdef EIGEN2_SUPPORT + return lhs().row(row).cwiseProduct(rhs().col(col).transpose()).sum(); +#else + EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) + eigen_assert(this->rows() == 1 && this->cols() == 1); + Matrix result = *this; + return result.coeff(row,col); +#endif + } + + typename Base::CoeffReturnType coeff(Index i) const + { + EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) + eigen_assert(this->rows() == 1 && this->cols() == 1); + Matrix result = *this; + return result.coeff(i); + } + + const Scalar& coeffRef(Index row, Index col) const + { + EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) + eigen_assert(this->rows() == 1 && this->cols() == 1); + return derived().coeffRef(row,col); + } + + const Scalar& coeffRef(Index i) const + { + EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) + eigen_assert(this->rows() == 1 && this->cols() == 1); + return derived().coeffRef(i); + } + + protected: + + LhsNested m_lhs; + RhsNested m_rhs; + + mutable PlainObject m_result; +}; + +// here we need to overload the nested rule for products +// such that the nested type is a const reference to a plain matrix +namespace internal { +template +struct nested, N, PlainObject> +{ + typedef PlainObject const& type; +}; +} + +template +class ScaledProduct; + +// Note that these two operator* functions are not defined as member +// functions of ProductBase, because, otherwise we would have to +// define all overloads defined in MatrixBase. Furthermore, Using +// "using Base::operator*" would not work with MSVC. +// +// Also note that here we accept any compatible scalar types +template +const ScaledProduct +operator*(const ProductBase& prod, const typename Derived::Scalar& x) +{ return ScaledProduct(prod.derived(), x); } + +template +typename internal::enable_if::value, + const ScaledProduct >::type +operator*(const ProductBase& prod, const typename Derived::RealScalar& x) +{ return ScaledProduct(prod.derived(), x); } + + +template +const ScaledProduct +operator*(const typename Derived::Scalar& x,const ProductBase& prod) +{ return ScaledProduct(prod.derived(), x); } + +template +typename internal::enable_if::value, + const ScaledProduct >::type +operator*(const typename Derived::RealScalar& x,const ProductBase& prod) +{ return ScaledProduct(prod.derived(), x); } + +namespace internal { +template +struct traits > + : traits, + typename NestedProduct::_LhsNested, + typename NestedProduct::_RhsNested> > +{ + typedef typename traits::StorageKind StorageKind; +}; +} + +template +class ScaledProduct + : public ProductBase, + typename NestedProduct::_LhsNested, + typename NestedProduct::_RhsNested> +{ + public: + typedef ProductBase, + typename NestedProduct::_LhsNested, + typename NestedProduct::_RhsNested> Base; + typedef typename Base::Scalar Scalar; + typedef typename Base::PlainObject PlainObject; +// EIGEN_PRODUCT_PUBLIC_INTERFACE(ScaledProduct) + + ScaledProduct(const NestedProduct& prod, const Scalar& x) + : Base(prod.lhs(),prod.rhs()), m_prod(prod), m_alpha(x) {} + + template + inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst, Scalar(1)); } + + template + inline void addTo(Dest& dst) const { scaleAndAddTo(dst, Scalar(1)); } + + template + inline void subTo(Dest& dst) const { scaleAndAddTo(dst, Scalar(-1)); } + + template + inline void scaleAndAddTo(Dest& dst, const Scalar& a_alpha) const { m_prod.derived().scaleAndAddTo(dst,a_alpha * m_alpha); } + + const Scalar& alpha() const { return m_alpha; } + + protected: + const NestedProduct& m_prod; + Scalar m_alpha; +}; + +/** \internal + * Overloaded to perform an efficient C = (A*B).lazy() */ +template +template +Derived& MatrixBase::lazyAssign(const ProductBase& other) +{ + other.derived().evalTo(derived()); + return derived(); +} + +} // end namespace Eigen + +#endif // EIGEN_PRODUCTBASE_H diff --git a/libs/eigen3/Eigen/src/Core/Random.h b/libs/eigen3/Eigen/src/Core/Random.h new file mode 100644 index 000000000..480fea408 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/Random.h @@ -0,0 +1,152 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_RANDOM_H +#define EIGEN_RANDOM_H + +namespace Eigen { + +namespace internal { + +template struct scalar_random_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_random_op) + template + inline const Scalar operator() (Index, Index = 0) const { return random(); } +}; + +template +struct functor_traits > +{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false, IsRepeatable = false }; }; + +} // end namespace internal + +/** \returns a random matrix expression + * + * The parameters \a rows and \a cols are the number of rows and of columns of + * the returned matrix. Must be compatible with this MatrixBase type. + * + * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, + * it is redundant to pass \a rows and \a cols as arguments, so Random() should be used + * instead. + * + * Example: \include MatrixBase_random_int_int.cpp + * Output: \verbinclude MatrixBase_random_int_int.out + * + * This expression has the "evaluate before nesting" flag so that it will be evaluated into + * a temporary matrix whenever it is nested in a larger expression. This prevents unexpected + * behavior with expressions involving random matrices. + * + * \sa MatrixBase::setRandom(), MatrixBase::Random(Index), MatrixBase::Random() + */ +template +inline const CwiseNullaryOp::Scalar>, Derived> +DenseBase::Random(Index rows, Index cols) +{ + return NullaryExpr(rows, cols, internal::scalar_random_op()); +} + +/** \returns a random vector expression + * + * The parameter \a size is the size of the returned vector. + * Must be compatible with this MatrixBase type. + * + * \only_for_vectors + * + * This variant is meant to be used for dynamic-size vector types. For fixed-size types, + * it is redundant to pass \a size as argument, so Random() should be used + * instead. + * + * Example: \include MatrixBase_random_int.cpp + * Output: \verbinclude MatrixBase_random_int.out + * + * This expression has the "evaluate before nesting" flag so that it will be evaluated into + * a temporary vector whenever it is nested in a larger expression. This prevents unexpected + * behavior with expressions involving random matrices. + * + * \sa MatrixBase::setRandom(), MatrixBase::Random(Index,Index), MatrixBase::Random() + */ +template +inline const CwiseNullaryOp::Scalar>, Derived> +DenseBase::Random(Index size) +{ + return NullaryExpr(size, internal::scalar_random_op()); +} + +/** \returns a fixed-size random matrix or vector expression + * + * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you + * need to use the variants taking size arguments. + * + * Example: \include MatrixBase_random.cpp + * Output: \verbinclude MatrixBase_random.out + * + * This expression has the "evaluate before nesting" flag so that it will be evaluated into + * a temporary matrix whenever it is nested in a larger expression. This prevents unexpected + * behavior with expressions involving random matrices. + * + * \sa MatrixBase::setRandom(), MatrixBase::Random(Index,Index), MatrixBase::Random(Index) + */ +template +inline const CwiseNullaryOp::Scalar>, Derived> +DenseBase::Random() +{ + return NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_random_op()); +} + +/** Sets all coefficients in this expression to random values. + * + * Example: \include MatrixBase_setRandom.cpp + * Output: \verbinclude MatrixBase_setRandom.out + * + * \sa class CwiseNullaryOp, setRandom(Index), setRandom(Index,Index) + */ +template +inline Derived& DenseBase::setRandom() +{ + return *this = Random(rows(), cols()); +} + +/** Resizes to the given \a newSize, and sets all coefficients in this expression to random values. + * + * \only_for_vectors + * + * Example: \include Matrix_setRandom_int.cpp + * Output: \verbinclude Matrix_setRandom_int.out + * + * \sa MatrixBase::setRandom(), setRandom(Index,Index), class CwiseNullaryOp, MatrixBase::Random() + */ +template +EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setRandom(Index newSize) +{ + resize(newSize); + return setRandom(); +} + +/** Resizes to the given size, and sets all coefficients in this expression to random values. + * + * \param nbRows the new number of rows + * \param nbCols the new number of columns + * + * Example: \include Matrix_setRandom_int_int.cpp + * Output: \verbinclude Matrix_setRandom_int_int.out + * + * \sa MatrixBase::setRandom(), setRandom(Index), class CwiseNullaryOp, MatrixBase::Random() + */ +template +EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setRandom(Index nbRows, Index nbCols) +{ + resize(nbRows, nbCols); + return setRandom(); +} + +} // end namespace Eigen + +#endif // EIGEN_RANDOM_H diff --git a/libs/eigen3/Eigen/src/Core/Redux.h b/libs/eigen3/Eigen/src/Core/Redux.h new file mode 100644 index 000000000..50548fa9a --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/Redux.h @@ -0,0 +1,408 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_REDUX_H +#define EIGEN_REDUX_H + +namespace Eigen { + +namespace internal { + +// TODO +// * implement other kind of vectorization +// * factorize code + +/*************************************************************************** +* Part 1 : the logic deciding a strategy for vectorization and unrolling +***************************************************************************/ + +template +struct redux_traits +{ +public: + enum { + PacketSize = packet_traits::size, + InnerMaxSize = int(Derived::IsRowMajor) + ? Derived::MaxColsAtCompileTime + : Derived::MaxRowsAtCompileTime + }; + + enum { + MightVectorize = (int(Derived::Flags)&ActualPacketAccessBit) + && (functor_traits::PacketAccess), + MayLinearVectorize = MightVectorize && (int(Derived::Flags)&LinearAccessBit), + MaySliceVectorize = MightVectorize && int(InnerMaxSize)>=3*PacketSize + }; + +public: + enum { + Traversal = int(MayLinearVectorize) ? int(LinearVectorizedTraversal) + : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) + : int(DefaultTraversal) + }; + +public: + enum { + Cost = ( Derived::SizeAtCompileTime == Dynamic + || Derived::CoeffReadCost == Dynamic + || (Derived::SizeAtCompileTime!=1 && functor_traits::Cost == Dynamic) + ) ? Dynamic + : Derived::SizeAtCompileTime * Derived::CoeffReadCost + + (Derived::SizeAtCompileTime-1) * functor_traits::Cost, + UnrollingLimit = EIGEN_UNROLLING_LIMIT * (int(Traversal) == int(DefaultTraversal) ? 1 : int(PacketSize)) + }; + +public: + enum { + Unrolling = Cost != Dynamic && Cost <= UnrollingLimit + ? CompleteUnrolling + : NoUnrolling + }; +}; + +/*************************************************************************** +* Part 2 : unrollers +***************************************************************************/ + +/*** no vectorization ***/ + +template +struct redux_novec_unroller +{ + enum { + HalfLength = Length/2 + }; + + typedef typename Derived::Scalar Scalar; + + static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) + { + return func(redux_novec_unroller::run(mat,func), + redux_novec_unroller::run(mat,func)); + } +}; + +template +struct redux_novec_unroller +{ + enum { + outer = Start / Derived::InnerSizeAtCompileTime, + inner = Start % Derived::InnerSizeAtCompileTime + }; + + typedef typename Derived::Scalar Scalar; + + static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func&) + { + return mat.coeffByOuterInner(outer, inner); + } +}; + +// This is actually dead code and will never be called. It is required +// to prevent false warnings regarding failed inlining though +// for 0 length run() will never be called at all. +template +struct redux_novec_unroller +{ + typedef typename Derived::Scalar Scalar; + static EIGEN_STRONG_INLINE Scalar run(const Derived&, const Func&) { return Scalar(); } +}; + +/*** vectorization ***/ + +template +struct redux_vec_unroller +{ + enum { + PacketSize = packet_traits::size, + HalfLength = Length/2 + }; + + typedef typename Derived::Scalar Scalar; + typedef typename packet_traits::type PacketScalar; + + static EIGEN_STRONG_INLINE PacketScalar run(const Derived &mat, const Func& func) + { + return func.packetOp( + redux_vec_unroller::run(mat,func), + redux_vec_unroller::run(mat,func) ); + } +}; + +template +struct redux_vec_unroller +{ + enum { + index = Start * packet_traits::size, + outer = index / int(Derived::InnerSizeAtCompileTime), + inner = index % int(Derived::InnerSizeAtCompileTime), + alignment = (Derived::Flags & AlignedBit) ? Aligned : Unaligned + }; + + typedef typename Derived::Scalar Scalar; + typedef typename packet_traits::type PacketScalar; + + static EIGEN_STRONG_INLINE PacketScalar run(const Derived &mat, const Func&) + { + return mat.template packetByOuterInner(outer, inner); + } +}; + +/*************************************************************************** +* Part 3 : implementation of all cases +***************************************************************************/ + +template::Traversal, + int Unrolling = redux_traits::Unrolling +> +struct redux_impl; + +template +struct redux_impl +{ + typedef typename Derived::Scalar Scalar; + typedef typename Derived::Index Index; + static EIGEN_STRONG_INLINE Scalar run(const Derived& mat, const Func& func) + { + eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); + Scalar res; + res = mat.coeffByOuterInner(0, 0); + for(Index i = 1; i < mat.innerSize(); ++i) + res = func(res, mat.coeffByOuterInner(0, i)); + for(Index i = 1; i < mat.outerSize(); ++i) + for(Index j = 0; j < mat.innerSize(); ++j) + res = func(res, mat.coeffByOuterInner(i, j)); + return res; + } +}; + +template +struct redux_impl + : public redux_novec_unroller +{}; + +template +struct redux_impl +{ + typedef typename Derived::Scalar Scalar; + typedef typename packet_traits::type PacketScalar; + typedef typename Derived::Index Index; + + static Scalar run(const Derived& mat, const Func& func) + { + const Index size = mat.size(); + eigen_assert(size && "you are using an empty matrix"); + const Index packetSize = packet_traits::size; + const Index alignedStart = internal::first_aligned(mat); + enum { + alignment = bool(Derived::Flags & DirectAccessBit) || bool(Derived::Flags & AlignedBit) + ? Aligned : Unaligned + }; + const Index alignedSize2 = ((size-alignedStart)/(2*packetSize))*(2*packetSize); + const Index alignedSize = ((size-alignedStart)/(packetSize))*(packetSize); + const Index alignedEnd2 = alignedStart + alignedSize2; + const Index alignedEnd = alignedStart + alignedSize; + Scalar res; + if(alignedSize) + { + PacketScalar packet_res0 = mat.template packet(alignedStart); + if(alignedSize>packetSize) // we have at least two packets to partly unroll the loop + { + PacketScalar packet_res1 = mat.template packet(alignedStart+packetSize); + for(Index index = alignedStart + 2*packetSize; index < alignedEnd2; index += 2*packetSize) + { + packet_res0 = func.packetOp(packet_res0, mat.template packet(index)); + packet_res1 = func.packetOp(packet_res1, mat.template packet(index+packetSize)); + } + + packet_res0 = func.packetOp(packet_res0,packet_res1); + if(alignedEnd>alignedEnd2) + packet_res0 = func.packetOp(packet_res0, mat.template packet(alignedEnd2)); + } + res = func.predux(packet_res0); + + for(Index index = 0; index < alignedStart; ++index) + res = func(res,mat.coeff(index)); + + for(Index index = alignedEnd; index < size; ++index) + res = func(res,mat.coeff(index)); + } + else // too small to vectorize anything. + // since this is dynamic-size hence inefficient anyway for such small sizes, don't try to optimize. + { + res = mat.coeff(0); + for(Index index = 1; index < size; ++index) + res = func(res,mat.coeff(index)); + } + + return res; + } +}; + +template +struct redux_impl +{ + typedef typename Derived::Scalar Scalar; + typedef typename packet_traits::type PacketScalar; + typedef typename Derived::Index Index; + + static Scalar run(const Derived& mat, const Func& func) + { + eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); + const Index innerSize = mat.innerSize(); + const Index outerSize = mat.outerSize(); + enum { + packetSize = packet_traits::size + }; + const Index packetedInnerSize = ((innerSize)/packetSize)*packetSize; + Scalar res; + if(packetedInnerSize) + { + PacketScalar packet_res = mat.template packet(0,0); + for(Index j=0; j(j,i)); + + res = func.predux(packet_res); + for(Index j=0; j::run(mat, func); + } + + return res; + } +}; + +template +struct redux_impl +{ + typedef typename Derived::Scalar Scalar; + typedef typename packet_traits::type PacketScalar; + enum { + PacketSize = packet_traits::size, + Size = Derived::SizeAtCompileTime, + VectorizedSize = (Size / PacketSize) * PacketSize + }; + static EIGEN_STRONG_INLINE Scalar run(const Derived& mat, const Func& func) + { + eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); + Scalar res = func.predux(redux_vec_unroller::run(mat,func)); + if (VectorizedSize != Size) + res = func(res,redux_novec_unroller::run(mat,func)); + return res; + } +}; + +} // end namespace internal + +/*************************************************************************** +* Part 4 : public API +***************************************************************************/ + + +/** \returns the result of a full redux operation on the whole matrix or vector using \a func + * + * The template parameter \a BinaryOp is the type of the functor \a func which must be + * an associative operator. Both current STL and TR1 functor styles are handled. + * + * \sa DenseBase::sum(), DenseBase::minCoeff(), DenseBase::maxCoeff(), MatrixBase::colwise(), MatrixBase::rowwise() + */ +template +template +EIGEN_STRONG_INLINE typename internal::result_of::Scalar)>::type +DenseBase::redux(const Func& func) const +{ + typedef typename internal::remove_all::type ThisNested; + return internal::redux_impl + ::run(derived(), func); +} + +/** \returns the minimum of all coefficients of \c *this. + * \warning the result is undefined if \c *this contains NaN. + */ +template +EIGEN_STRONG_INLINE typename internal::traits::Scalar +DenseBase::minCoeff() const +{ + return this->redux(Eigen::internal::scalar_min_op()); +} + +/** \returns the maximum of all coefficients of \c *this. + * \warning the result is undefined if \c *this contains NaN. + */ +template +EIGEN_STRONG_INLINE typename internal::traits::Scalar +DenseBase::maxCoeff() const +{ + return this->redux(Eigen::internal::scalar_max_op()); +} + +/** \returns the sum of all coefficients of *this + * + * \sa trace(), prod(), mean() + */ +template +EIGEN_STRONG_INLINE typename internal::traits::Scalar +DenseBase::sum() const +{ + if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0)) + return Scalar(0); + return this->redux(Eigen::internal::scalar_sum_op()); +} + +/** \returns the mean of all coefficients of *this +* +* \sa trace(), prod(), sum() +*/ +template +EIGEN_STRONG_INLINE typename internal::traits::Scalar +DenseBase::mean() const +{ + return Scalar(this->redux(Eigen::internal::scalar_sum_op())) / Scalar(this->size()); +} + +/** \returns the product of all coefficients of *this + * + * Example: \include MatrixBase_prod.cpp + * Output: \verbinclude MatrixBase_prod.out + * + * \sa sum(), mean(), trace() + */ +template +EIGEN_STRONG_INLINE typename internal::traits::Scalar +DenseBase::prod() const +{ + if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0)) + return Scalar(1); + return this->redux(Eigen::internal::scalar_product_op()); +} + +/** \returns the trace of \c *this, i.e. the sum of the coefficients on the main diagonal. + * + * \c *this can be any matrix, not necessarily square. + * + * \sa diagonal(), sum() + */ +template +EIGEN_STRONG_INLINE typename internal::traits::Scalar +MatrixBase::trace() const +{ + return derived().diagonal().sum(); +} + +} // end namespace Eigen + +#endif // EIGEN_REDUX_H diff --git a/libs/eigen3/Eigen/src/Core/Ref.h b/libs/eigen3/Eigen/src/Core/Ref.h new file mode 100644 index 000000000..cd6d949c4 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/Ref.h @@ -0,0 +1,260 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2012 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_REF_H +#define EIGEN_REF_H + +namespace Eigen { + +template class RefBase; +template,OuterStride<> >::type > class Ref; + +/** \class Ref + * \ingroup Core_Module + * + * \brief A matrix or vector expression mapping an existing expressions + * + * \tparam PlainObjectType the equivalent matrix type of the mapped data + * \tparam Options specifies whether the pointer is \c #Aligned, or \c #Unaligned. + * The default is \c #Unaligned. + * \tparam StrideType optionally specifies strides. By default, Ref implies a contiguous storage along the inner dimension (inner stride==1), + * but accept a variable outer stride (leading dimension). + * This can be overridden by specifying strides. + * The type passed here must be a specialization of the Stride template, see examples below. + * + * This class permits to write non template functions taking Eigen's object as parameters while limiting the number of copies. + * A Ref<> object can represent either a const expression or a l-value: + * \code + * // in-out argument: + * void foo1(Ref x); + * + * // read-only const argument: + * void foo2(const Ref& x); + * \endcode + * + * In the in-out case, the input argument must satisfies the constraints of the actual Ref<> type, otherwise a compilation issue will be triggered. + * By default, a Ref can reference any dense vector expression of float having a contiguous memory layout. + * Likewise, a Ref can reference any column major dense matrix expression of float whose column's elements are contiguously stored with + * the possibility to have a constant space inbetween each column, i.e.: the inner stride mmust be equal to 1, but the outer-stride (or leading dimension), + * can be greater than the number of rows. + * + * In the const case, if the input expression does not match the above requirement, then it is evaluated into a temporary before being passed to the function. + * Here are some examples: + * \code + * MatrixXf A; + * VectorXf a; + * foo1(a.head()); // OK + * foo1(A.col()); // OK + * foo1(A.row()); // compilation error because here innerstride!=1 + * foo2(A.row()); // The row is copied into a contiguous temporary + * foo2(2*a); // The expression is evaluated into a temporary + * foo2(A.col().segment(2,4)); // No temporary + * \endcode + * + * The range of inputs that can be referenced without temporary can be enlarged using the last two template parameter. + * Here is an example accepting an innerstride!=1: + * \code + * // in-out argument: + * void foo3(Ref > x); + * foo3(A.row()); // OK + * \endcode + * The downside here is that the function foo3 might be significantly slower than foo1 because it won't be able to exploit vectorization, and will involved more + * expensive address computations even if the input is contiguously stored in memory. To overcome this issue, one might propose to overloads internally calling a + * template function, e.g.: + * \code + * // in the .h: + * void foo(const Ref& A); + * void foo(const Ref >& A); + * + * // in the .cpp: + * template void foo_impl(const TypeOfA& A) { + * ... // crazy code goes here + * } + * void foo(const Ref& A) { foo_impl(A); } + * void foo(const Ref >& A) { foo_impl(A); } + * \endcode + * + * + * \sa PlainObjectBase::Map(), \ref TopicStorageOrders + */ + +namespace internal { + +template +struct traits > + : public traits > +{ + typedef _PlainObjectType PlainObjectType; + typedef _StrideType StrideType; + enum { + Options = _Options, + Flags = traits >::Flags | NestByRefBit + }; + + template struct match { + enum { + HasDirectAccess = internal::has_direct_access::ret, + StorageOrderMatch = PlainObjectType::IsVectorAtCompileTime || Derived::IsVectorAtCompileTime || ((PlainObjectType::Flags&RowMajorBit)==(Derived::Flags&RowMajorBit)), + InnerStrideMatch = int(StrideType::InnerStrideAtCompileTime)==int(Dynamic) + || int(StrideType::InnerStrideAtCompileTime)==int(Derived::InnerStrideAtCompileTime) + || (int(StrideType::InnerStrideAtCompileTime)==0 && int(Derived::InnerStrideAtCompileTime)==1), + OuterStrideMatch = Derived::IsVectorAtCompileTime + || int(StrideType::OuterStrideAtCompileTime)==int(Dynamic) || int(StrideType::OuterStrideAtCompileTime)==int(Derived::OuterStrideAtCompileTime), + AlignmentMatch = (_Options!=Aligned) || ((PlainObjectType::Flags&AlignedBit)==0) || ((traits::Flags&AlignedBit)==AlignedBit), + MatchAtCompileTime = HasDirectAccess && StorageOrderMatch && InnerStrideMatch && OuterStrideMatch && AlignmentMatch + }; + typedef typename internal::conditional::type type; + }; + +}; + +template +struct traits > : public traits {}; + +} + +template class RefBase + : public MapBase +{ + typedef typename internal::traits::PlainObjectType PlainObjectType; + typedef typename internal::traits::StrideType StrideType; + +public: + + typedef MapBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(RefBase) + + inline Index innerStride() const + { + return StrideType::InnerStrideAtCompileTime != 0 ? m_stride.inner() : 1; + } + + inline Index outerStride() const + { + return StrideType::OuterStrideAtCompileTime != 0 ? m_stride.outer() + : IsVectorAtCompileTime ? this->size() + : int(Flags)&RowMajorBit ? this->cols() + : this->rows(); + } + + RefBase() + : Base(0,RowsAtCompileTime==Dynamic?0:RowsAtCompileTime,ColsAtCompileTime==Dynamic?0:ColsAtCompileTime), + // Stride<> does not allow default ctor for Dynamic strides, so let' initialize it with dummy values: + m_stride(StrideType::OuterStrideAtCompileTime==Dynamic?0:StrideType::OuterStrideAtCompileTime, + StrideType::InnerStrideAtCompileTime==Dynamic?0:StrideType::InnerStrideAtCompileTime) + {} + + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(RefBase) + +protected: + + typedef Stride StrideBase; + + template + void construct(Expression& expr) + { + if(PlainObjectType::RowsAtCompileTime==1) + { + eigen_assert(expr.rows()==1 || expr.cols()==1); + ::new (static_cast(this)) Base(expr.data(), 1, expr.size()); + } + else if(PlainObjectType::ColsAtCompileTime==1) + { + eigen_assert(expr.rows()==1 || expr.cols()==1); + ::new (static_cast(this)) Base(expr.data(), expr.size(), 1); + } + else + ::new (static_cast(this)) Base(expr.data(), expr.rows(), expr.cols()); + + if(Expression::IsVectorAtCompileTime && (!PlainObjectType::IsVectorAtCompileTime) && ((Expression::Flags&RowMajorBit)!=(PlainObjectType::Flags&RowMajorBit))) + ::new (&m_stride) StrideBase(expr.innerStride(), StrideType::InnerStrideAtCompileTime==0?0:1); + else + ::new (&m_stride) StrideBase(StrideType::OuterStrideAtCompileTime==0?0:expr.outerStride(), + StrideType::InnerStrideAtCompileTime==0?0:expr.innerStride()); + } + + StrideBase m_stride; +}; + + +template class Ref + : public RefBase > +{ + typedef internal::traits Traits; + public: + + typedef RefBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Ref) + + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + inline Ref(PlainObjectBase& expr, + typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) + { + Base::construct(expr); + } + template + inline Ref(const DenseBase& expr, + typename internal::enable_if::value&&bool(Traits::template match::MatchAtCompileTime)),Derived>::type* = 0, + int = Derived::ThisConstantIsPrivateInPlainObjectBase) + #else + template + inline Ref(DenseBase& expr) + #endif + { + Base::construct(expr.const_cast_derived()); + } + + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Ref) + +}; + +// this is the const ref version +template class Ref + : public RefBase > +{ + typedef internal::traits Traits; + public: + + typedef RefBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Ref) + + template + inline Ref(const DenseBase& expr) + { +// std::cout << match_helper::HasDirectAccess << "," << match_helper::OuterStrideMatch << "," << match_helper::InnerStrideMatch << "\n"; +// std::cout << int(StrideType::OuterStrideAtCompileTime) << " - " << int(Derived::OuterStrideAtCompileTime) << "\n"; +// std::cout << int(StrideType::InnerStrideAtCompileTime) << " - " << int(Derived::InnerStrideAtCompileTime) << "\n"; + construct(expr.derived(), typename Traits::template match::type()); + } + + protected: + + template + void construct(const Expression& expr,internal::true_type) + { + Base::construct(expr); + } + + template + void construct(const Expression& expr, internal::false_type) + { + m_object.lazyAssign(expr); + Base::construct(m_object); + } + + protected: + TPlainObjectType m_object; +}; + +} // end namespace Eigen + +#endif // EIGEN_REF_H diff --git a/libs/eigen3/Eigen/src/Core/Replicate.h b/libs/eigen3/Eigen/src/Core/Replicate.h new file mode 100644 index 000000000..dde86a834 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/Replicate.h @@ -0,0 +1,177 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_REPLICATE_H +#define EIGEN_REPLICATE_H + +namespace Eigen { + +/** + * \class Replicate + * \ingroup Core_Module + * + * \brief Expression of the multiple replication of a matrix or vector + * + * \param MatrixType the type of the object we are replicating + * + * This class represents an expression of the multiple replication of a matrix or vector. + * It is the return type of DenseBase::replicate() and most of the time + * this is the only way it is used. + * + * \sa DenseBase::replicate() + */ + +namespace internal { +template +struct traits > + : traits +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename traits::StorageKind StorageKind; + typedef typename traits::XprKind XprKind; + enum { + Factor = (RowFactor==Dynamic || ColFactor==Dynamic) ? Dynamic : RowFactor*ColFactor + }; + typedef typename nested::type MatrixTypeNested; + typedef typename remove_reference::type _MatrixTypeNested; + enum { + RowsAtCompileTime = RowFactor==Dynamic || int(MatrixType::RowsAtCompileTime)==Dynamic + ? Dynamic + : RowFactor * MatrixType::RowsAtCompileTime, + ColsAtCompileTime = ColFactor==Dynamic || int(MatrixType::ColsAtCompileTime)==Dynamic + ? Dynamic + : ColFactor * MatrixType::ColsAtCompileTime, + //FIXME we don't propagate the max sizes !!! + MaxRowsAtCompileTime = RowsAtCompileTime, + MaxColsAtCompileTime = ColsAtCompileTime, + IsRowMajor = MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1 ? 1 + : MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1 ? 0 + : (MatrixType::Flags & RowMajorBit) ? 1 : 0, + Flags = (_MatrixTypeNested::Flags & HereditaryBits & ~RowMajorBit) | (IsRowMajor ? RowMajorBit : 0), + CoeffReadCost = _MatrixTypeNested::CoeffReadCost + }; +}; +} + +template class Replicate + : public internal::dense_xpr_base< Replicate >::type +{ + typedef typename internal::traits::MatrixTypeNested MatrixTypeNested; + typedef typename internal::traits::_MatrixTypeNested _MatrixTypeNested; + public: + + typedef typename internal::dense_xpr_base::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Replicate) + + template + inline explicit Replicate(const OriginalMatrixType& a_matrix) + : m_matrix(a_matrix), m_rowFactor(RowFactor), m_colFactor(ColFactor) + { + EIGEN_STATIC_ASSERT((internal::is_same::type,OriginalMatrixType>::value), + THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE) + eigen_assert(RowFactor!=Dynamic && ColFactor!=Dynamic); + } + + template + inline Replicate(const OriginalMatrixType& a_matrix, Index rowFactor, Index colFactor) + : m_matrix(a_matrix), m_rowFactor(rowFactor), m_colFactor(colFactor) + { + EIGEN_STATIC_ASSERT((internal::is_same::type,OriginalMatrixType>::value), + THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE) + } + + inline Index rows() const { return m_matrix.rows() * m_rowFactor.value(); } + inline Index cols() const { return m_matrix.cols() * m_colFactor.value(); } + + inline Scalar coeff(Index rowId, Index colId) const + { + // try to avoid using modulo; this is a pure optimization strategy + const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 + : RowFactor==1 ? rowId + : rowId%m_matrix.rows(); + const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 + : ColFactor==1 ? colId + : colId%m_matrix.cols(); + + return m_matrix.coeff(actual_row, actual_col); + } + template + inline PacketScalar packet(Index rowId, Index colId) const + { + const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 + : RowFactor==1 ? rowId + : rowId%m_matrix.rows(); + const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 + : ColFactor==1 ? colId + : colId%m_matrix.cols(); + + return m_matrix.template packet(actual_row, actual_col); + } + + const _MatrixTypeNested& nestedExpression() const + { + return m_matrix; + } + + protected: + MatrixTypeNested m_matrix; + const internal::variable_if_dynamic m_rowFactor; + const internal::variable_if_dynamic m_colFactor; +}; + +/** + * \return an expression of the replication of \c *this + * + * Example: \include MatrixBase_replicate.cpp + * Output: \verbinclude MatrixBase_replicate.out + * + * \sa VectorwiseOp::replicate(), DenseBase::replicate(Index,Index), class Replicate + */ +template +template +inline const Replicate +DenseBase::replicate() const +{ + return Replicate(derived()); +} + +/** + * \return an expression of the replication of \c *this + * + * Example: \include MatrixBase_replicate_int_int.cpp + * Output: \verbinclude MatrixBase_replicate_int_int.out + * + * \sa VectorwiseOp::replicate(), DenseBase::replicate(), class Replicate + */ +template +inline const Replicate +DenseBase::replicate(Index rowFactor,Index colFactor) const +{ + return Replicate(derived(),rowFactor,colFactor); +} + +/** + * \return an expression of the replication of each column (or row) of \c *this + * + * Example: \include DirectionWise_replicate_int.cpp + * Output: \verbinclude DirectionWise_replicate_int.out + * + * \sa VectorwiseOp::replicate(), DenseBase::replicate(), class Replicate + */ +template +const typename VectorwiseOp::ReplicateReturnType +VectorwiseOp::replicate(Index factor) const +{ + return typename VectorwiseOp::ReplicateReturnType + (_expression(),Direction==Vertical?factor:1,Direction==Horizontal?factor:1); +} + +} // end namespace Eigen + +#endif // EIGEN_REPLICATE_H diff --git a/libs/eigen3/Eigen/src/Core/ReturnByValue.h b/libs/eigen3/Eigen/src/Core/ReturnByValue.h new file mode 100644 index 000000000..d66c24ba0 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/ReturnByValue.h @@ -0,0 +1,88 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009-2010 Gael Guennebaud +// Copyright (C) 2009-2010 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_RETURNBYVALUE_H +#define EIGEN_RETURNBYVALUE_H + +namespace Eigen { + +/** \class ReturnByValue + * \ingroup Core_Module + * + */ + +namespace internal { + +template +struct traits > + : public traits::ReturnType> +{ + enum { + // We're disabling the DirectAccess because e.g. the constructor of + // the Block-with-DirectAccess expression requires to have a coeffRef method. + // Also, we don't want to have to implement the stride stuff. + Flags = (traits::ReturnType>::Flags + | EvalBeforeNestingBit) & ~DirectAccessBit + }; +}; + +/* The ReturnByValue object doesn't even have a coeff() method. + * So the only way that nesting it in an expression can work, is by evaluating it into a plain matrix. + * So internal::nested always gives the plain return matrix type. + * + * FIXME: I don't understand why we need this specialization: isn't this taken care of by the EvalBeforeNestingBit ?? + */ +template +struct nested, n, PlainObject> +{ + typedef typename traits::ReturnType type; +}; + +} // end namespace internal + +template class ReturnByValue + : internal::no_assignment_operator, public internal::dense_xpr_base< ReturnByValue >::type +{ + public: + typedef typename internal::traits::ReturnType ReturnType; + + typedef typename internal::dense_xpr_base::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(ReturnByValue) + + template + inline void evalTo(Dest& dst) const + { static_cast(this)->evalTo(dst); } + inline Index rows() const { return static_cast(this)->rows(); } + inline Index cols() const { return static_cast(this)->cols(); } + +#ifndef EIGEN_PARSED_BY_DOXYGEN +#define Unusable YOU_ARE_TRYING_TO_ACCESS_A_SINGLE_COEFFICIENT_IN_A_SPECIAL_EXPRESSION_WHERE_THAT_IS_NOT_ALLOWED_BECAUSE_THAT_WOULD_BE_INEFFICIENT + class Unusable{ + Unusable(const Unusable&) {} + Unusable& operator=(const Unusable&) {return *this;} + }; + const Unusable& coeff(Index) const { return *reinterpret_cast(this); } + const Unusable& coeff(Index,Index) const { return *reinterpret_cast(this); } + Unusable& coeffRef(Index) { return *reinterpret_cast(this); } + Unusable& coeffRef(Index,Index) { return *reinterpret_cast(this); } +#endif +}; + +template +template +Derived& DenseBase::operator=(const ReturnByValue& other) +{ + other.evalTo(derived()); + return derived(); +} + +} // end namespace Eigen + +#endif // EIGEN_RETURNBYVALUE_H diff --git a/libs/eigen3/Eigen/src/Core/Reverse.h b/libs/eigen3/Eigen/src/Core/Reverse.h new file mode 100644 index 000000000..e30ae3d28 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/Reverse.h @@ -0,0 +1,224 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2009 Ricard Marxer +// Copyright (C) 2009-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_REVERSE_H +#define EIGEN_REVERSE_H + +namespace Eigen { + +/** \class Reverse + * \ingroup Core_Module + * + * \brief Expression of the reverse of a vector or matrix + * + * \param MatrixType the type of the object of which we are taking the reverse + * + * This class represents an expression of the reverse of a vector. + * It is the return type of MatrixBase::reverse() and VectorwiseOp::reverse() + * and most of the time this is the only way it is used. + * + * \sa MatrixBase::reverse(), VectorwiseOp::reverse() + */ + +namespace internal { + +template +struct traits > + : traits +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename traits::StorageKind StorageKind; + typedef typename traits::XprKind XprKind; + typedef typename nested::type MatrixTypeNested; + typedef typename remove_reference::type _MatrixTypeNested; + enum { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime, + MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, + + // let's enable LinearAccess only with vectorization because of the product overhead + LinearAccess = ( (Direction==BothDirections) && (int(_MatrixTypeNested::Flags)&PacketAccessBit) ) + ? LinearAccessBit : 0, + + Flags = int(_MatrixTypeNested::Flags) & (HereditaryBits | LvalueBit | PacketAccessBit | LinearAccess), + + CoeffReadCost = _MatrixTypeNested::CoeffReadCost + }; +}; + +template struct reverse_packet_cond +{ + static inline PacketScalar run(const PacketScalar& x) { return preverse(x); } +}; + +template struct reverse_packet_cond +{ + static inline PacketScalar run(const PacketScalar& x) { return x; } +}; + +} // end namespace internal + +template class Reverse + : public internal::dense_xpr_base< Reverse >::type +{ + public: + + typedef typename internal::dense_xpr_base::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Reverse) + using Base::IsRowMajor; + + // next line is necessary because otherwise const version of operator() + // is hidden by non-const version defined in this file + using Base::operator(); + + protected: + enum { + PacketSize = internal::packet_traits::size, + IsColMajor = !IsRowMajor, + ReverseRow = (Direction == Vertical) || (Direction == BothDirections), + ReverseCol = (Direction == Horizontal) || (Direction == BothDirections), + OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1, + OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1, + ReversePacket = (Direction == BothDirections) + || ((Direction == Vertical) && IsColMajor) + || ((Direction == Horizontal) && IsRowMajor) + }; + typedef internal::reverse_packet_cond reverse_packet; + public: + + inline Reverse(const MatrixType& matrix) : m_matrix(matrix) { } + + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Reverse) + + inline Index rows() const { return m_matrix.rows(); } + inline Index cols() const { return m_matrix.cols(); } + + inline Index innerStride() const + { + return -m_matrix.innerStride(); + } + + inline Scalar& operator()(Index row, Index col) + { + eigen_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); + return coeffRef(row, col); + } + + inline Scalar& coeffRef(Index row, Index col) + { + return m_matrix.const_cast_derived().coeffRef(ReverseRow ? m_matrix.rows() - row - 1 : row, + ReverseCol ? m_matrix.cols() - col - 1 : col); + } + + inline CoeffReturnType coeff(Index row, Index col) const + { + return m_matrix.coeff(ReverseRow ? m_matrix.rows() - row - 1 : row, + ReverseCol ? m_matrix.cols() - col - 1 : col); + } + + inline CoeffReturnType coeff(Index index) const + { + return m_matrix.coeff(m_matrix.size() - index - 1); + } + + inline Scalar& coeffRef(Index index) + { + return m_matrix.const_cast_derived().coeffRef(m_matrix.size() - index - 1); + } + + inline Scalar& operator()(Index index) + { + eigen_assert(index >= 0 && index < m_matrix.size()); + return coeffRef(index); + } + + template + inline const PacketScalar packet(Index row, Index col) const + { + return reverse_packet::run(m_matrix.template packet( + ReverseRow ? m_matrix.rows() - row - OffsetRow : row, + ReverseCol ? m_matrix.cols() - col - OffsetCol : col)); + } + + template + inline void writePacket(Index row, Index col, const PacketScalar& x) + { + m_matrix.const_cast_derived().template writePacket( + ReverseRow ? m_matrix.rows() - row - OffsetRow : row, + ReverseCol ? m_matrix.cols() - col - OffsetCol : col, + reverse_packet::run(x)); + } + + template + inline const PacketScalar packet(Index index) const + { + return internal::preverse(m_matrix.template packet( m_matrix.size() - index - PacketSize )); + } + + template + inline void writePacket(Index index, const PacketScalar& x) + { + m_matrix.const_cast_derived().template writePacket(m_matrix.size() - index - PacketSize, internal::preverse(x)); + } + + const typename internal::remove_all::type& + nestedExpression() const + { + return m_matrix; + } + + protected: + typename MatrixType::Nested m_matrix; +}; + +/** \returns an expression of the reverse of *this. + * + * Example: \include MatrixBase_reverse.cpp + * Output: \verbinclude MatrixBase_reverse.out + * + */ +template +inline typename DenseBase::ReverseReturnType +DenseBase::reverse() +{ + return derived(); +} + +/** This is the const version of reverse(). */ +template +inline const typename DenseBase::ConstReverseReturnType +DenseBase::reverse() const +{ + return derived(); +} + +/** This is the "in place" version of reverse: it reverses \c *this. + * + * In most cases it is probably better to simply use the reversed expression + * of a matrix. However, when reversing the matrix data itself is really needed, + * then this "in-place" version is probably the right choice because it provides + * the following additional features: + * - less error prone: doing the same operation with .reverse() requires special care: + * \code m = m.reverse().eval(); \endcode + * - this API allows to avoid creating a temporary (the current implementation creates a temporary, but that could be avoided using swap) + * - it allows future optimizations (cache friendliness, etc.) + * + * \sa reverse() */ +template +inline void DenseBase::reverseInPlace() +{ + derived() = derived().reverse().eval(); +} + +} // end namespace Eigen + +#endif // EIGEN_REVERSE_H diff --git a/libs/eigen3/Eigen/src/Core/Select.h b/libs/eigen3/Eigen/src/Core/Select.h new file mode 100644 index 000000000..87993bbb5 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/Select.h @@ -0,0 +1,162 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SELECT_H +#define EIGEN_SELECT_H + +namespace Eigen { + +/** \class Select + * \ingroup Core_Module + * + * \brief Expression of a coefficient wise version of the C++ ternary operator ?: + * + * \param ConditionMatrixType the type of the \em condition expression which must be a boolean matrix + * \param ThenMatrixType the type of the \em then expression + * \param ElseMatrixType the type of the \em else expression + * + * This class represents an expression of a coefficient wise version of the C++ ternary operator ?:. + * It is the return type of DenseBase::select() and most of the time this is the only way it is used. + * + * \sa DenseBase::select(const DenseBase&, const DenseBase&) const + */ + +namespace internal { +template +struct traits > + : traits +{ + typedef typename traits::Scalar Scalar; + typedef Dense StorageKind; + typedef typename traits::XprKind XprKind; + typedef typename ConditionMatrixType::Nested ConditionMatrixNested; + typedef typename ThenMatrixType::Nested ThenMatrixNested; + typedef typename ElseMatrixType::Nested ElseMatrixNested; + enum { + RowsAtCompileTime = ConditionMatrixType::RowsAtCompileTime, + ColsAtCompileTime = ConditionMatrixType::ColsAtCompileTime, + MaxRowsAtCompileTime = ConditionMatrixType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = ConditionMatrixType::MaxColsAtCompileTime, + Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & HereditaryBits, + CoeffReadCost = traits::type>::CoeffReadCost + + EIGEN_SIZE_MAX(traits::type>::CoeffReadCost, + traits::type>::CoeffReadCost) + }; +}; +} + +template +class Select : internal::no_assignment_operator, + public internal::dense_xpr_base< Select >::type +{ + public: + + typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Select) + inline EIGEN_DEVICE_FUNC Select(const ConditionMatrixType& a_conditionMatrix, const ThenMatrixType& a_thenMatrix, const ElseMatrixType& a_elseMatrix) @@ -69,9 +67,10 @@ class Select : internal::no_assignment_operator, eigen_assert(m_condition.cols() == m_then.cols() && m_condition.cols() == m_else.cols()); } - Index rows() const { return m_condition.rows(); } - Index cols() const { return m_condition.cols(); } + inline EIGEN_DEVICE_FUNC Index rows() const { return m_condition.rows(); } + inline EIGEN_DEVICE_FUNC Index cols() const { return m_condition.cols(); } + inline EIGEN_DEVICE_FUNC const Scalar coeff(Index i, Index j) const { if (m_condition.coeff(i,j)) @@ -80,6 +79,7 @@ class Select : internal::no_assignment_operator, return m_else.coeff(i,j); } + inline EIGEN_DEVICE_FUNC const Scalar coeff(Index i) const { if (m_condition.coeff(i)) @@ -88,17 +88,17 @@ class Select : internal::no_assignment_operator, return m_else.coeff(i); } - const ConditionMatrixType& conditionMatrix() const + inline EIGEN_DEVICE_FUNC const ConditionMatrixType& conditionMatrix() const { return m_condition; } - const ThenMatrixType& thenMatrix() const + inline EIGEN_DEVICE_FUNC const ThenMatrixType& thenMatrix() const { return m_then; } - const ElseMatrixType& elseMatrix() const + inline EIGEN_DEVICE_FUNC const ElseMatrixType& elseMatrix() const { return m_else; } diff --git a/libs/eigen3/Eigen/src/Core/SelfAdjointView.h b/libs/eigen3/Eigen/src/Core/SelfAdjointView.h index 6fa7cd15e..504c98f0e 100644 --- a/libs/eigen3/Eigen/src/Core/SelfAdjointView.h +++ b/libs/eigen3/Eigen/src/Core/SelfAdjointView.h @@ -32,54 +32,60 @@ namespace internal { template struct traits > : traits { - typedef typename nested::type MatrixTypeNested; + typedef typename ref_selector::non_const_type MatrixTypeNested; typedef typename remove_all::type MatrixTypeNestedCleaned; typedef MatrixType ExpressionType; - typedef typename MatrixType::PlainObject DenseMatrixType; + typedef typename MatrixType::PlainObject FullMatrixType; enum { Mode = UpLo | SelfAdjoint, - Flags = MatrixTypeNestedCleaned::Flags & (HereditaryBits) - & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit)), // FIXME these flags should be preserved - CoeffReadCost = MatrixTypeNestedCleaned::CoeffReadCost + FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, + Flags = MatrixTypeNestedCleaned::Flags & (HereditaryBits|FlagsLvalueBit) + & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit)) // FIXME these flags should be preserved }; }; } -template -struct SelfadjointProductMatrix; -// FIXME could also be called SelfAdjointWrapper to be consistent with DiagonalWrapper ?? -template class SelfAdjointView - : public TriangularBase > +template class SelfAdjointView + : public TriangularBase > { public: + typedef _MatrixType MatrixType; typedef TriangularBase Base; typedef typename internal::traits::MatrixTypeNested MatrixTypeNested; typedef typename internal::traits::MatrixTypeNestedCleaned MatrixTypeNestedCleaned; + typedef MatrixTypeNestedCleaned NestedExpression; /** \brief The type of coefficients in this matrix */ typedef typename internal::traits::Scalar Scalar; - - typedef typename MatrixType::Index Index; + typedef typename MatrixType::StorageIndex StorageIndex; + typedef typename internal::remove_all::type MatrixConjugateReturnType; enum { - Mode = internal::traits::Mode + Mode = internal::traits::Mode, + Flags = internal::traits::Flags, + TransposeMode = ((Mode & Upper) ? Lower : 0) | ((Mode & Lower) ? Upper : 0) }; typedef typename MatrixType::PlainObject PlainObject; - inline SelfAdjointView(MatrixType& matrix) : m_matrix(matrix) + EIGEN_DEVICE_FUNC + explicit inline SelfAdjointView(MatrixType& matrix) : m_matrix(matrix) {} + EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.cols(); } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_matrix.outerStride(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_matrix.innerStride(); } /** \sa MatrixBase::coeff() * \warning the coordinates must fit into the referenced triangular part */ + EIGEN_DEVICE_FUNC inline Scalar coeff(Index row, Index col) const { Base::check_coordinates_internal(row, col); @@ -89,36 +95,46 @@ template class SelfAdjointView /** \sa MatrixBase::coeffRef() * \warning the coordinates must fit into the referenced triangular part */ + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) { + EIGEN_STATIC_ASSERT_LVALUE(SelfAdjointView); Base::check_coordinates_internal(row, col); - return m_matrix.const_cast_derived().coeffRef(row, col); + return m_matrix.coeffRef(row, col); } /** \internal */ + EIGEN_DEVICE_FUNC const MatrixTypeNestedCleaned& _expression() const { return m_matrix; } + EIGEN_DEVICE_FUNC const MatrixTypeNestedCleaned& nestedExpression() const { return m_matrix; } - MatrixTypeNestedCleaned& nestedExpression() { return *const_cast(&m_matrix); } + EIGEN_DEVICE_FUNC + MatrixTypeNestedCleaned& nestedExpression() { return m_matrix; } - /** Efficient self-adjoint matrix times vector/matrix product */ + /** Efficient triangular matrix times vector/matrix product */ template - SelfadjointProductMatrix + EIGEN_DEVICE_FUNC + const Product operator*(const MatrixBase& rhs) const { - return SelfadjointProductMatrix - - (m_matrix, rhs.derived()); + return Product(*this, rhs.derived()); } - /** Efficient vector/matrix times self-adjoint matrix product */ + /** Efficient vector/matrix times triangular matrix product */ template friend - SelfadjointProductMatrix + EIGEN_DEVICE_FUNC + const Product operator*(const MatrixBase& lhs, const SelfAdjointView& rhs) { - return SelfadjointProductMatrix - - (lhs.derived(),rhs.m_matrix); + return Product(lhs.derived(),rhs); + } + + friend EIGEN_DEVICE_FUNC + const SelfAdjointView + operator*(const Scalar& s, const SelfAdjointView& mat) + { + return (s*mat.nestedExpression()).template selfadjointView(); } /** Perform a symmetric rank 2 update of the selfadjoint matrix \c *this: @@ -132,6 +148,7 @@ template class SelfAdjointView * \sa rankUpdate(const MatrixBase&, Scalar) */ template + EIGEN_DEVICE_FUNC SelfAdjointView& rankUpdate(const MatrixBase& u, const MatrixBase& v, const Scalar& alpha = Scalar(1)); /** Perform a symmetric rank K update of the selfadjoint matrix \c *this: @@ -145,8 +162,74 @@ template class SelfAdjointView * \sa rankUpdate(const MatrixBase&, const MatrixBase&, Scalar) */ template + EIGEN_DEVICE_FUNC SelfAdjointView& rankUpdate(const MatrixBase& u, const Scalar& alpha = Scalar(1)); + /** \returns an expression of a triangular view extracted from the current selfadjoint view of a given triangular part + * + * The parameter \a TriMode can have the following values: \c #Upper, \c #StrictlyUpper, \c #UnitUpper, + * \c #Lower, \c #StrictlyLower, \c #UnitLower. + * + * If \c TriMode references the same triangular part than \c *this, then this method simply return a \c TriangularView of the nested expression, + * otherwise, the nested expression is first transposed, thus returning a \c TriangularView> object. + * + * \sa MatrixBase::triangularView(), class TriangularView + */ + template + EIGEN_DEVICE_FUNC + typename internal::conditional<(TriMode&(Upper|Lower))==(UpLo&(Upper|Lower)), + TriangularView, + TriangularView >::type + triangularView() const + { + typename internal::conditional<(TriMode&(Upper|Lower))==(UpLo&(Upper|Lower)), MatrixType&, typename MatrixType::ConstTransposeReturnType>::type tmp1(m_matrix); + typename internal::conditional<(TriMode&(Upper|Lower))==(UpLo&(Upper|Lower)), MatrixType&, typename MatrixType::AdjointReturnType>::type tmp2(tmp1); + return typename internal::conditional<(TriMode&(Upper|Lower))==(UpLo&(Upper|Lower)), + TriangularView, + TriangularView >::type(tmp2); + } + + typedef SelfAdjointView ConjugateReturnType; + /** \sa MatrixBase::conjugate() const */ + EIGEN_DEVICE_FUNC + inline const ConjugateReturnType conjugate() const + { return ConjugateReturnType(m_matrix.conjugate()); } + + typedef SelfAdjointView AdjointReturnType; + /** \sa MatrixBase::adjoint() const */ + EIGEN_DEVICE_FUNC + inline const AdjointReturnType adjoint() const + { return AdjointReturnType(m_matrix.adjoint()); } + + typedef SelfAdjointView TransposeReturnType; + /** \sa MatrixBase::transpose() */ + EIGEN_DEVICE_FUNC + inline TransposeReturnType transpose() + { + EIGEN_STATIC_ASSERT_LVALUE(MatrixType) + typename MatrixType::TransposeReturnType tmp(m_matrix); + return TransposeReturnType(tmp); + } + + typedef SelfAdjointView ConstTransposeReturnType; + /** \sa MatrixBase::transpose() const */ + EIGEN_DEVICE_FUNC + inline const ConstTransposeReturnType transpose() const + { + return ConstTransposeReturnType(m_matrix.transpose()); + } + + /** \returns a const expression of the main diagonal of the matrix \c *this + * + * This method simply returns the diagonal of the nested expression, thus by-passing the SelfAdjointView decorator. + * + * \sa MatrixBase::diagonal(), class Diagonal */ + EIGEN_DEVICE_FUNC + typename MatrixType::ConstDiagonalReturnType diagonal() const + { + return typename MatrixType::ConstDiagonalReturnType(m_matrix); + } + /////////// Cholesky module /////////// const LLT llt() const; @@ -159,31 +242,10 @@ template class SelfAdjointView /** Return type of eigenvalues() */ typedef Matrix::ColsAtCompileTime, 1> EigenvaluesReturnType; + EIGEN_DEVICE_FUNC EigenvaluesReturnType eigenvalues() const; + EIGEN_DEVICE_FUNC RealScalar operatorNorm() const; - - #ifdef EIGEN2_SUPPORT - template - SelfAdjointView& operator=(const MatrixBase& other) - { - enum { - OtherPart = UpLo == Upper ? StrictlyLower : StrictlyUpper - }; - m_matrix.const_cast_derived().template triangularView() = other; - m_matrix.const_cast_derived().template triangularView() = other.adjoint(); - return *this; - } - template - SelfAdjointView& operator=(const TriangularView& other) - { - enum { - OtherPart = UpLo == Upper ? StrictlyLower : StrictlyUpper - }; - m_matrix.const_cast_derived().template triangularView() = other.toDenseMatrix(); - m_matrix.const_cast_derived().template triangularView() = other.toDenseMatrix().adjoint(); - return *this; - } - #endif protected: MatrixTypeNested m_matrix; @@ -201,90 +263,54 @@ template class SelfAdjointView namespace internal { -template -struct triangular_assignment_selector -{ - enum { - col = (UnrollCount-1) / Derived1::RowsAtCompileTime, - row = (UnrollCount-1) % Derived1::RowsAtCompileTime - }; - - static inline void run(Derived1 &dst, const Derived2 &src) - { - triangular_assignment_selector::run(dst, src); - - if(row == col) - dst.coeffRef(row, col) = numext::real(src.coeff(row, col)); - else if(row < col) - dst.coeffRef(col, row) = numext::conj(dst.coeffRef(row, col) = src.coeff(row, col)); - } -}; - -template -struct triangular_assignment_selector -{ - static inline void run(Derived1 &, const Derived2 &) {} -}; - -template -struct triangular_assignment_selector -{ - enum { - col = (UnrollCount-1) / Derived1::RowsAtCompileTime, - row = (UnrollCount-1) % Derived1::RowsAtCompileTime - }; - - static inline void run(Derived1 &dst, const Derived2 &src) - { - triangular_assignment_selector::run(dst, src); - - if(row == col) - dst.coeffRef(row, col) = numext::real(src.coeff(row, col)); - else if(row > col) - dst.coeffRef(col, row) = numext::conj(dst.coeffRef(row, col) = src.coeff(row, col)); - } -}; - -template -struct triangular_assignment_selector +// TODO currently a selfadjoint expression has the form SelfAdjointView<.,.> +// in the future selfadjoint-ness should be defined by the expression traits +// such that Transpose > is valid. (currently TriangularBase::transpose() is overloaded to make it work) +template +struct evaluator_traits > { - static inline void run(Derived1 &, const Derived2 &) {} + typedef typename storage_kind_to_evaluator_kind::Kind Kind; + typedef SelfAdjointShape Shape; }; -template -struct triangular_assignment_selector +template +class triangular_dense_assignment_kernel + : public generic_dense_assignment_kernel { - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) +protected: + typedef generic_dense_assignment_kernel Base; + typedef typename Base::DstXprType DstXprType; + typedef typename Base::SrcXprType SrcXprType; + using Base::m_dst; + using Base::m_src; + using Base::m_functor; +public: + + typedef typename Base::DstEvaluatorType DstEvaluatorType; + typedef typename Base::SrcEvaluatorType SrcEvaluatorType; + typedef typename Base::Scalar Scalar; + typedef typename Base::AssignmentTraits AssignmentTraits; + + + EIGEN_DEVICE_FUNC triangular_dense_assignment_kernel(DstEvaluatorType &dst, const SrcEvaluatorType &src, const Functor &func, DstXprType& dstExpr) + : Base(dst, src, func, dstExpr) + {} + + EIGEN_DEVICE_FUNC void assignCoeff(Index row, Index col) { - for(Index j = 0; j < dst.cols(); ++j) - { - for(Index i = 0; i < j; ++i) - { - dst.copyCoeff(i, j, src); - dst.coeffRef(j,i) = numext::conj(dst.coeff(i,j)); - } - dst.copyCoeff(j, j, src); - } + eigen_internal_assert(row!=col); + Scalar tmp = m_src.coeff(row,col); + m_functor.assignCoeff(m_dst.coeffRef(row,col), tmp); + m_functor.assignCoeff(m_dst.coeffRef(col,row), numext::conj(tmp)); } -}; - -template -struct triangular_assignment_selector -{ - static inline void run(Derived1 &dst, const Derived2 &src) + + EIGEN_DEVICE_FUNC void assignDiagonalCoeff(Index id) { - typedef typename Derived1::Index Index; - for(Index i = 0; i < dst.rows(); ++i) - { - for(Index j = 0; j < i; ++j) - { - dst.copyCoeff(i, j, src); - dst.coeffRef(j,i) = numext::conj(dst.coeff(i,j)); - } - dst.copyCoeff(i, i, src); - } + Base::assignCoeff(id,id); } + + EIGEN_DEVICE_FUNC void assignOppositeCoeff(Index, Index) + { eigen_internal_assert(false && "should never be called"); } }; } // end namespace internal @@ -293,20 +319,30 @@ struct triangular_assignment_selector template typename MatrixBase::template ConstSelfAdjointViewReturnType::Type MatrixBase::selfadjointView() const { - return derived(); + return typename ConstSelfAdjointViewReturnType::Type(derived()); } +/** \returns an expression of a symmetric/self-adjoint view extracted from the upper or lower triangular part of the current matrix + * + * The parameter \a UpLo can be either \c #Upper or \c #Lower + * + * Example: \include MatrixBase_selfadjointView.cpp + * Output: \verbinclude MatrixBase_selfadjointView.out + * + * \sa class SelfAdjointView + */ template template typename MatrixBase::template SelfAdjointViewReturnType::Type MatrixBase::selfadjointView() { - return derived(); + return typename SelfAdjointViewReturnType::Type(derived()); } } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h b/libs/eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h index 22f3047b4..50099df82 100644 --- a/libs/eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h +++ b/libs/eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h @@ -12,183 +12,37 @@ namespace Eigen { -/** \class SelfCwiseBinaryOp - * \ingroup Core_Module - * - * \internal - * - * \brief Internal helper class for optimizing operators like +=, -= - * - * This is a pseudo expression class re-implementing the copyCoeff/copyPacket - * method to directly performs a +=/-= operations in an optimal way. In particular, - * this allows to make sure that the input/output data are loaded only once using - * aligned packet loads. - * - * \sa class SwapWrapper for a similar trick. - */ +// TODO generalize the scalar type of 'other' -namespace internal { -template -struct traits > - : traits > +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::operator*=(const Scalar& other) { - enum { - // Note that it is still a good idea to preserve the DirectAccessBit - // so that assign can correctly align the data. - Flags = traits >::Flags | (Lhs::Flags&DirectAccessBit) | (Lhs::Flags&LvalueBit), - OuterStrideAtCompileTime = Lhs::OuterStrideAtCompileTime, - InnerStrideAtCompileTime = Lhs::InnerStrideAtCompileTime - }; -}; + typedef typename Derived::PlainObject PlainObject; + internal::call_assignment(this->derived(), PlainObject::Constant(rows(),cols(),other), internal::mul_assign_op()); + return derived(); } -template class SelfCwiseBinaryOp - : public internal::dense_xpr_base< SelfCwiseBinaryOp >::type +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& ArrayBase::operator+=(const Scalar& other) { - public: - - typedef typename internal::dense_xpr_base::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(SelfCwiseBinaryOp) - - typedef typename internal::packet_traits::type Packet; - - inline SelfCwiseBinaryOp(Lhs& xpr, const BinaryOp& func = BinaryOp()) : m_matrix(xpr), m_functor(func) {} - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - inline Index outerStride() const { return m_matrix.outerStride(); } - inline Index innerStride() const { return m_matrix.innerStride(); } - inline const Scalar* data() const { return m_matrix.data(); } - - // note that this function is needed by assign to correctly align loads/stores - // TODO make Assign use .data() - inline Scalar& coeffRef(Index row, Index col) - { - EIGEN_STATIC_ASSERT_LVALUE(Lhs) - return m_matrix.const_cast_derived().coeffRef(row, col); - } - inline const Scalar& coeffRef(Index row, Index col) const - { - return m_matrix.coeffRef(row, col); - } - - // note that this function is needed by assign to correctly align loads/stores - // TODO make Assign use .data() - inline Scalar& coeffRef(Index index) - { - EIGEN_STATIC_ASSERT_LVALUE(Lhs) - return m_matrix.const_cast_derived().coeffRef(index); - } - inline const Scalar& coeffRef(Index index) const - { - return m_matrix.const_cast_derived().coeffRef(index); - } - - template - void copyCoeff(Index row, Index col, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - Scalar& tmp = m_matrix.coeffRef(row,col); - tmp = m_functor(tmp, _other.coeff(row,col)); - } - - template - void copyCoeff(Index index, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(index >= 0 && index < m_matrix.size()); - Scalar& tmp = m_matrix.coeffRef(index); - tmp = m_functor(tmp, _other.coeff(index)); - } - - template - void copyPacket(Index row, Index col, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - m_matrix.template writePacket(row, col, - m_functor.packetOp(m_matrix.template packet(row, col),_other.template packet(row, col)) ); - } - - template - void copyPacket(Index index, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(index >= 0 && index < m_matrix.size()); - m_matrix.template writePacket(index, - m_functor.packetOp(m_matrix.template packet(index),_other.template packet(index)) ); - } - - // reimplement lazyAssign to handle complex *= real - // see CwiseBinaryOp ctor for details - template - EIGEN_STRONG_INLINE SelfCwiseBinaryOp& lazyAssign(const DenseBase& rhs) - { - EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Lhs,RhsDerived) - EIGEN_CHECK_BINARY_COMPATIBILIY(BinaryOp,typename Lhs::Scalar,typename RhsDerived::Scalar); - - #ifdef EIGEN_DEBUG_ASSIGN - internal::assign_traits::debug(); - #endif - eigen_assert(rows() == rhs.rows() && cols() == rhs.cols()); - internal::assign_impl::run(*this,rhs.derived()); - #ifndef EIGEN_NO_DEBUG - this->checkTransposeAliasing(rhs.derived()); - #endif - return *this; - } - - // overloaded to honor evaluation of special matrices - // maybe another solution would be to not use SelfCwiseBinaryOp - // at first... - SelfCwiseBinaryOp& operator=(const Rhs& _rhs) - { - typename internal::nested::type rhs(_rhs); - return Base::operator=(rhs); - } - - Lhs& expression() const - { - return m_matrix; - } - - const BinaryOp& functor() const - { - return m_functor; - } - - protected: - Lhs& m_matrix; - const BinaryOp& m_functor; - - private: - SelfCwiseBinaryOp& operator=(const SelfCwiseBinaryOp&); -}; + typedef typename Derived::PlainObject PlainObject; + internal::call_assignment(this->derived(), PlainObject::Constant(rows(),cols(),other), internal::add_assign_op()); + return derived(); +} template -inline Derived& DenseBase::operator*=(const Scalar& other) +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& ArrayBase::operator-=(const Scalar& other) { typedef typename Derived::PlainObject PlainObject; - SelfCwiseBinaryOp, Derived, typename PlainObject::ConstantReturnType> tmp(derived()); - tmp = PlainObject::Constant(rows(),cols(),other); + internal::call_assignment(this->derived(), PlainObject::Constant(rows(),cols(),other), internal::sub_assign_op()); return derived(); } template -inline Derived& DenseBase::operator/=(const Scalar& other) +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::operator/=(const Scalar& other) { - typedef typename internal::conditional::IsInteger, - internal::scalar_quotient_op, - internal::scalar_product_op >::type BinOp; typedef typename Derived::PlainObject PlainObject; - SelfCwiseBinaryOp tmp(derived()); - Scalar actual_other; - if(NumTraits::IsInteger) actual_other = other; - else actual_other = Scalar(1)/other; - tmp = PlainObject::Constant(rows(),cols(), actual_other); + internal::call_assignment(this->derived(), PlainObject::Constant(rows(),cols(),other), internal::div_assign_op()); return derived(); } diff --git a/libs/eigen3/Eigen/src/Core/Solve.h b/libs/eigen3/Eigen/src/Core/Solve.h new file mode 100644 index 000000000..a8daea511 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/Solve.h @@ -0,0 +1,188 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SOLVE_H +#define EIGEN_SOLVE_H + +namespace Eigen { + +template class SolveImpl; + +/** \class Solve + * \ingroup Core_Module + * + * \brief Pseudo expression representing a solving operation + * + * \tparam Decomposition the type of the matrix or decomposion object + * \tparam Rhstype the type of the right-hand side + * + * This class represents an expression of A.solve(B) + * and most of the time this is the only way it is used. + * + */ +namespace internal { + +// this solve_traits class permits to determine the evaluation type with respect to storage kind (Dense vs Sparse) +template struct solve_traits; + +template +struct solve_traits +{ + typedef typename make_proper_matrix_type::type PlainObject; +}; + +template +struct traits > + : traits::StorageKind>::PlainObject> +{ + typedef typename solve_traits::StorageKind>::PlainObject PlainObject; + typedef typename promote_index_type::type StorageIndex; + typedef traits BaseTraits; + enum { + Flags = BaseTraits::Flags & RowMajorBit, + CoeffReadCost = HugeCost + }; +}; + +} + + +template +class Solve : public SolveImpl::StorageKind> +{ +public: + typedef typename internal::traits::PlainObject PlainObject; + typedef typename internal::traits::StorageIndex StorageIndex; + + Solve(const Decomposition &dec, const RhsType &rhs) + : m_dec(dec), m_rhs(rhs) + {} + + EIGEN_DEVICE_FUNC Index rows() const { return m_dec.cols(); } + EIGEN_DEVICE_FUNC Index cols() const { return m_rhs.cols(); } + + EIGEN_DEVICE_FUNC const Decomposition& dec() const { return m_dec; } + EIGEN_DEVICE_FUNC const RhsType& rhs() const { return m_rhs; } + +protected: + const Decomposition &m_dec; + const RhsType &m_rhs; +}; + + +// Specialization of the Solve expression for dense results +template +class SolveImpl + : public MatrixBase > +{ + typedef Solve Derived; + +public: + + typedef MatrixBase > Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Derived) + +private: + + Scalar coeff(Index row, Index col) const; + Scalar coeff(Index i) const; +}; + +// Generic API dispatcher +template +class SolveImpl : public internal::generic_xpr_base, MatrixXpr, StorageKind>::type +{ + public: + typedef typename internal::generic_xpr_base, MatrixXpr, StorageKind>::type Base; +}; + +namespace internal { + +// Evaluator of Solve -> eval into a temporary +template +struct evaluator > + : public evaluator::PlainObject> +{ + typedef Solve SolveType; + typedef typename SolveType::PlainObject PlainObject; + typedef evaluator Base; + + enum { Flags = Base::Flags | EvalBeforeNestingBit }; + + EIGEN_DEVICE_FUNC explicit evaluator(const SolveType& solve) + : m_result(solve.rows(), solve.cols()) + { + ::new (static_cast(this)) Base(m_result); + solve.dec()._solve_impl(solve.rhs(), m_result); + } + +protected: + PlainObject m_result; +}; + +// Specialization for "dst = dec.solve(rhs)" +// NOTE we need to specialize it for Dense2Dense to avoid ambiguous specialization error and a Sparse2Sparse specialization must exist somewhere +template +struct Assignment, internal::assign_op, Dense2Dense> +{ + typedef Solve SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + src.dec()._solve_impl(src.rhs(), dst); + } +}; + +// Specialization for "dst = dec.transpose().solve(rhs)" +template +struct Assignment,RhsType>, internal::assign_op, Dense2Dense> +{ + typedef Solve,RhsType> SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + src.dec().nestedExpression().template _solve_impl_transposed(src.rhs(), dst); + } +}; + +// Specialization for "dst = dec.adjoint().solve(rhs)" +template +struct Assignment, const Transpose >,RhsType>, + internal::assign_op, Dense2Dense> +{ + typedef Solve, const Transpose >,RhsType> SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + src.dec().nestedExpression().nestedExpression().template _solve_impl_transposed(src.rhs(), dst); + } +}; + +} // end namepsace internal + +} // end namespace Eigen + +#endif // EIGEN_SOLVE_H diff --git a/libs/eigen3/Eigen/src/Core/SolveTriangular.h b/libs/eigen3/Eigen/src/Core/SolveTriangular.h index ef17f288e..049890b25 100644 --- a/libs/eigen3/Eigen/src/Core/SolveTriangular.h +++ b/libs/eigen3/Eigen/src/Core/SolveTriangular.h @@ -68,7 +68,7 @@ struct triangular_solver_selector if(!useRhsDirectly) MappedRhs(actualRhs,rhs.size()) = rhs; - triangular_solve_vector ::run(actualLhs.cols(), actualLhs.data(), actualLhs.outerStride(), actualRhs); @@ -82,7 +82,6 @@ template struct triangular_solver_selector { typedef typename Rhs::Scalar Scalar; - typedef typename Rhs::Index Index; typedef blas_traits LhsProductTraits; typedef typename LhsProductTraits::DirectLinearAccessType ActualLhsType; @@ -96,7 +95,7 @@ struct triangular_solver_selector typedef internal::gemm_blocking_space<(Rhs::Flags&RowMajorBit) ? RowMajor : ColMajor,Scalar,Scalar, Rhs::MaxRowsAtCompileTime, Rhs::MaxColsAtCompileTime, Lhs::MaxRowsAtCompileTime,4> BlockingType; - BlockingType blocking(rhs.rows(), rhs.cols(), size); + BlockingType blocking(rhs.rows(), rhs.cols(), size, 1, false); triangular_solve_matrix @@ -108,32 +107,32 @@ struct triangular_solver_selector * meta-unrolling implementation ***************************************************************************/ -template +template struct triangular_solver_unroller; -template -struct triangular_solver_unroller { +template +struct triangular_solver_unroller { enum { IsLower = ((Mode&Lower)==Lower), - I = IsLower ? Index : Size - Index - 1, - S = IsLower ? 0 : I+1 + DiagIndex = IsLower ? LoopIndex : Size - LoopIndex - 1, + StartIndex = IsLower ? 0 : DiagIndex+1 }; static void run(const Lhs& lhs, Rhs& rhs) { - if (Index>0) - rhs.coeffRef(I) -= lhs.row(I).template segment(S).transpose() - .cwiseProduct(rhs.template segment(S)).sum(); + if (LoopIndex>0) + rhs.coeffRef(DiagIndex) -= lhs.row(DiagIndex).template segment(StartIndex).transpose() + .cwiseProduct(rhs.template segment(StartIndex)).sum(); if(!(Mode & UnitDiag)) - rhs.coeffRef(I) /= lhs.coeff(I,I); + rhs.coeffRef(DiagIndex) /= lhs.coeff(DiagIndex,DiagIndex); - triangular_solver_unroller::run(lhs,rhs); + triangular_solver_unroller::run(lhs,rhs); } }; -template -struct triangular_solver_unroller { +template +struct triangular_solver_unroller { static void run(const Lhs&, Rhs&) {} }; @@ -162,61 +161,35 @@ struct triangular_solver_selector { * TriangularView methods ***************************************************************************/ -/** "in-place" version of TriangularView::solve() where the result is written in \a other - * - * \warning The parameter is only marked 'const' to make the C++ compiler accept a temporary expression here. - * This function will const_cast it, so constness isn't honored here. - * - * See TriangularView:solve() for the details. - */ +#ifndef EIGEN_PARSED_BY_DOXYGEN template template -void TriangularView::solveInPlace(const MatrixBase& _other) const +void TriangularViewImpl::solveInPlace(const MatrixBase& _other) const { OtherDerived& other = _other.const_cast_derived(); - eigen_assert( cols() == rows() && ((Side==OnTheLeft && cols() == other.rows()) || (Side==OnTheRight && cols() == other.cols())) ); + eigen_assert( derived().cols() == derived().rows() && ((Side==OnTheLeft && derived().cols() == other.rows()) || (Side==OnTheRight && derived().cols() == other.cols())) ); eigen_assert((!(Mode & ZeroDiag)) && bool(Mode & (Upper|Lower))); - enum { copy = internal::traits::Flags & RowMajorBit && OtherDerived::IsVectorAtCompileTime }; + enum { copy = (internal::traits::Flags & RowMajorBit) && OtherDerived::IsVectorAtCompileTime && OtherDerived::SizeAtCompileTime!=1}; typedef typename internal::conditional::type, OtherDerived&>::type OtherCopy; OtherCopy otherCopy(other); internal::triangular_solver_selector::type, - Side, Mode>::run(nestedExpression(), otherCopy); + Side, Mode>::run(derived().nestedExpression(), otherCopy); if (copy) other = otherCopy; } -/** \returns the product of the inverse of \c *this with \a other, \a *this being triangular. - * - * This function computes the inverse-matrix matrix product inverse(\c *this) * \a other if - * \a Side==OnTheLeft (the default), or the right-inverse-multiply \a other * inverse(\c *this) if - * \a Side==OnTheRight. - * - * The matrix \c *this must be triangular and invertible (i.e., all the coefficients of the - * diagonal must be non zero). It works as a forward (resp. backward) substitution if \c *this - * is an upper (resp. lower) triangular matrix. - * - * Example: \include MatrixBase_marked.cpp - * Output: \verbinclude MatrixBase_marked.out - * - * This function returns an expression of the inverse-multiply and can works in-place if it is assigned - * to the same matrix or vector \a other. - * - * For users coming from BLAS, this function (and more specifically solveInPlace()) offer - * all the operations supported by the \c *TRSV and \c *TRSM BLAS routines. - * - * \sa TriangularView::solveInPlace() - */ template template const internal::triangular_solve_retval,Other> -TriangularView::solve(const MatrixBase& other) const +TriangularViewImpl::solve(const MatrixBase& other) const { - return internal::triangular_solve_retval(*this, other.derived()); + return internal::triangular_solve_retval(derived(), other.derived()); } +#endif namespace internal { @@ -232,7 +205,6 @@ template struct triangular_solv { typedef typename remove_all::type RhsNestedCleaned; typedef ReturnByValue Base; - typedef typename Base::Index Index; triangular_solve_retval(const TriangularType& tri, const Rhs& rhs) : m_triangularMatrix(tri), m_rhs(rhs) @@ -243,7 +215,7 @@ template struct triangular_solv template inline void evalTo(Dest& dst) const { - if(!(is_same::value && extract_data(dst) == extract_data(m_rhs))) + if(!is_same_dense(dst,m_rhs)) dst = m_rhs; m_triangularMatrix.template solveInPlace(dst); } diff --git a/libs/eigen3/Eigen/src/Core/SolverBase.h b/libs/eigen3/Eigen/src/Core/SolverBase.h new file mode 100644 index 000000000..8a4adc229 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/SolverBase.h @@ -0,0 +1,130 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SOLVERBASE_H +#define EIGEN_SOLVERBASE_H + +namespace Eigen { + +namespace internal { + + + +} // end namespace internal + +/** \class SolverBase + * \brief A base class for matrix decomposition and solvers + * + * \tparam Derived the actual type of the decomposition/solver. + * + * Any matrix decomposition inheriting this base class provide the following API: + * + * \code + * MatrixType A, b, x; + * DecompositionType dec(A); + * x = dec.solve(b); // solve A * x = b + * x = dec.transpose().solve(b); // solve A^T * x = b + * x = dec.adjoint().solve(b); // solve A' * x = b + * \endcode + * + * \warning Currently, any other usage of transpose() and adjoint() are not supported and will produce compilation errors. + * + * \sa class PartialPivLU, class FullPivLU + */ +template +class SolverBase : public EigenBase +{ + public: + + typedef EigenBase Base; + typedef typename internal::traits::Scalar Scalar; + typedef Scalar CoeffReturnType; + + enum { + RowsAtCompileTime = internal::traits::RowsAtCompileTime, + ColsAtCompileTime = internal::traits::ColsAtCompileTime, + SizeAtCompileTime = (internal::size_at_compile_time::RowsAtCompileTime, + internal::traits::ColsAtCompileTime>::ret), + MaxRowsAtCompileTime = internal::traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = internal::traits::MaxColsAtCompileTime, + MaxSizeAtCompileTime = (internal::size_at_compile_time::MaxRowsAtCompileTime, + internal::traits::MaxColsAtCompileTime>::ret), + IsVectorAtCompileTime = internal::traits::MaxRowsAtCompileTime == 1 + || internal::traits::MaxColsAtCompileTime == 1 + }; + + /** Default constructor */ + SolverBase() + {} + + ~SolverBase() + {} + + using Base::derived; + + /** \returns an expression of the solution x of \f$ A x = b \f$ using the current decomposition of A. + */ + template + inline const Solve + solve(const MatrixBase& b) const + { + eigen_assert(derived().rows()==b.rows() && "solve(): invalid number of rows of the right hand side matrix b"); + return Solve(derived(), b.derived()); + } + + /** \internal the return type of transpose() */ + typedef typename internal::add_const >::type ConstTransposeReturnType; + /** \returns an expression of the transposed of the factored matrix. + * + * A typical usage is to solve for the transposed problem A^T x = b: + * \code x = dec.transpose().solve(b); \endcode + * + * \sa adjoint(), solve() + */ + inline ConstTransposeReturnType transpose() const + { + return ConstTransposeReturnType(derived()); + } + + /** \internal the return type of adjoint() */ + typedef typename internal::conditional::IsComplex, + CwiseUnaryOp, ConstTransposeReturnType>, + ConstTransposeReturnType + >::type AdjointReturnType; + /** \returns an expression of the adjoint of the factored matrix + * + * A typical usage is to solve for the adjoint problem A' x = b: + * \code x = dec.adjoint().solve(b); \endcode + * + * For real scalar types, this function is equivalent to transpose(). + * + * \sa transpose(), solve() + */ + inline AdjointReturnType adjoint() const + { + return AdjointReturnType(derived().transpose()); + } + + protected: +}; + +namespace internal { + +template +struct generic_xpr_base +{ + typedef SolverBase type; + +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_SOLVERBASE_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/AmbiVector.h b/libs/eigen3/Eigen/src/Core/SparseCore/AmbiVector.h deleted file mode 100644 index 17fff96a7..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/AmbiVector.h +++ /dev/null @@ -1,373 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_AMBIVECTOR_H -#define EIGEN_AMBIVECTOR_H - -namespace Eigen { - -namespace internal { - -/** \internal - * Hybrid sparse/dense vector class designed for intensive read-write operations. - * - * See BasicSparseLLT and SparseProduct for usage examples. - */ -template -class AmbiVector -{ - public: - typedef _Scalar Scalar; - typedef _Index Index; - typedef typename NumTraits::Real RealScalar; - - AmbiVector(Index size) - : m_buffer(0), m_zero(0), m_size(0), m_allocatedSize(0), m_allocatedElements(0), m_mode(-1) - { - resize(size); - } - - void init(double estimatedDensity); - void init(int mode); - - Index nonZeros() const; - - /** Specifies a sub-vector to work on */ - void setBounds(Index start, Index end) { m_start = start; m_end = end; } - - void setZero(); - - void restart(); - Scalar& coeffRef(Index i); - Scalar& coeff(Index i); - - class Iterator; - - ~AmbiVector() { delete[] m_buffer; } - - void resize(Index size) - { - if (m_allocatedSize < size) - reallocate(size); - m_size = size; - } - - Index size() const { return m_size; } - - protected: - - void reallocate(Index size) - { - // if the size of the matrix is not too large, let's allocate a bit more than needed such - // that we can handle dense vector even in sparse mode. - delete[] m_buffer; - if (size<1000) - { - Index allocSize = (size * sizeof(ListEl))/sizeof(Scalar); - m_allocatedElements = (allocSize*sizeof(Scalar))/sizeof(ListEl); - m_buffer = new Scalar[allocSize]; - } - else - { - m_allocatedElements = (size*sizeof(Scalar))/sizeof(ListEl); - m_buffer = new Scalar[size]; - } - m_size = size; - m_start = 0; - m_end = m_size; - } - - void reallocateSparse() - { - Index copyElements = m_allocatedElements; - m_allocatedElements = (std::min)(Index(m_allocatedElements*1.5),m_size); - Index allocSize = m_allocatedElements * sizeof(ListEl); - allocSize = allocSize/sizeof(Scalar) + (allocSize%sizeof(Scalar)>0?1:0); - Scalar* newBuffer = new Scalar[allocSize]; - memcpy(newBuffer, m_buffer, copyElements * sizeof(ListEl)); - delete[] m_buffer; - m_buffer = newBuffer; - } - - protected: - // element type of the linked list - struct ListEl - { - Index next; - Index index; - Scalar value; - }; - - // used to store data in both mode - Scalar* m_buffer; - Scalar m_zero; - Index m_size; - Index m_start; - Index m_end; - Index m_allocatedSize; - Index m_allocatedElements; - Index m_mode; - - // linked list mode - Index m_llStart; - Index m_llCurrent; - Index m_llSize; -}; - -/** \returns the number of non zeros in the current sub vector */ -template -_Index AmbiVector<_Scalar,_Index>::nonZeros() const -{ - if (m_mode==IsSparse) - return m_llSize; - else - return m_end - m_start; -} - -template -void AmbiVector<_Scalar,_Index>::init(double estimatedDensity) -{ - if (estimatedDensity>0.1) - init(IsDense); - else - init(IsSparse); -} - -template -void AmbiVector<_Scalar,_Index>::init(int mode) -{ - m_mode = mode; - if (m_mode==IsSparse) - { - m_llSize = 0; - m_llStart = -1; - } -} - -/** Must be called whenever we might perform a write access - * with an index smaller than the previous one. - * - * Don't worry, this function is extremely cheap. - */ -template -void AmbiVector<_Scalar,_Index>::restart() -{ - m_llCurrent = m_llStart; -} - -/** Set all coefficients of current subvector to zero */ -template -void AmbiVector<_Scalar,_Index>::setZero() -{ - if (m_mode==IsDense) - { - for (Index i=m_start; i -_Scalar& AmbiVector<_Scalar,_Index>::coeffRef(_Index i) -{ - if (m_mode==IsDense) - return m_buffer[i]; - else - { - ListEl* EIGEN_RESTRICT llElements = reinterpret_cast(m_buffer); - // TODO factorize the following code to reduce code generation - eigen_assert(m_mode==IsSparse); - if (m_llSize==0) - { - // this is the first element - m_llStart = 0; - m_llCurrent = 0; - ++m_llSize; - llElements[0].value = Scalar(0); - llElements[0].index = i; - llElements[0].next = -1; - return llElements[0].value; - } - else if (i=llElements[m_llCurrent].index && "you must call restart() before inserting an element with lower or equal index"); - while (nextel >= 0 && llElements[nextel].index<=i) - { - m_llCurrent = nextel; - nextel = llElements[nextel].next; - } - - if (llElements[m_llCurrent].index==i) - { - // the coefficient already exists and we found it ! - return llElements[m_llCurrent].value; - } - else - { - if (m_llSize>=m_allocatedElements) - { - reallocateSparse(); - llElements = reinterpret_cast(m_buffer); - } - eigen_internal_assert(m_llSize -_Scalar& AmbiVector<_Scalar,_Index>::coeff(_Index i) -{ - if (m_mode==IsDense) - return m_buffer[i]; - else - { - ListEl* EIGEN_RESTRICT llElements = reinterpret_cast(m_buffer); - eigen_assert(m_mode==IsSparse); - if ((m_llSize==0) || (i= 0 && llElements[elid].index -class AmbiVector<_Scalar,_Index>::Iterator -{ - public: - typedef _Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - - /** Default constructor - * \param vec the vector on which we iterate - * \param epsilon the minimal value used to prune zero coefficients. - * In practice, all coefficients having a magnitude smaller than \a epsilon - * are skipped. - */ - Iterator(const AmbiVector& vec, const RealScalar& epsilon = 0) - : m_vector(vec) - { - using std::abs; - m_epsilon = epsilon; - m_isDense = m_vector.m_mode==IsDense; - if (m_isDense) - { - m_currentEl = 0; // this is to avoid a compilation warning - m_cachedValue = 0; // this is to avoid a compilation warning - m_cachedIndex = m_vector.m_start-1; - ++(*this); - } - else - { - ListEl* EIGEN_RESTRICT llElements = reinterpret_cast(m_vector.m_buffer); - m_currentEl = m_vector.m_llStart; - while (m_currentEl>=0 && abs(llElements[m_currentEl].value)<=m_epsilon) - m_currentEl = llElements[m_currentEl].next; - if (m_currentEl<0) - { - m_cachedValue = 0; // this is to avoid a compilation warning - m_cachedIndex = -1; - } - else - { - m_cachedIndex = llElements[m_currentEl].index; - m_cachedValue = llElements[m_currentEl].value; - } - } - } - - Index index() const { return m_cachedIndex; } - Scalar value() const { return m_cachedValue; } - - operator bool() const { return m_cachedIndex>=0; } - - Iterator& operator++() - { - using std::abs; - if (m_isDense) - { - do { - ++m_cachedIndex; - } while (m_cachedIndex(m_vector.m_buffer); - do { - m_currentEl = llElements[m_currentEl].next; - } while (m_currentEl>=0 && abs(llElements[m_currentEl].value) -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_COMPRESSED_STORAGE_H -#define EIGEN_COMPRESSED_STORAGE_H - -namespace Eigen { - -namespace internal { - -/** \internal - * Stores a sparse set of values as a list of values and a list of indices. - * - */ -template -class CompressedStorage -{ - public: - - typedef _Scalar Scalar; - typedef _Index Index; - - protected: - - typedef typename NumTraits::Real RealScalar; - - public: - - CompressedStorage() - : m_values(0), m_indices(0), m_size(0), m_allocatedSize(0) - {} - - CompressedStorage(size_t size) - : m_values(0), m_indices(0), m_size(0), m_allocatedSize(0) - { - resize(size); - } - - CompressedStorage(const CompressedStorage& other) - : m_values(0), m_indices(0), m_size(0), m_allocatedSize(0) - { - *this = other; - } - - CompressedStorage& operator=(const CompressedStorage& other) - { - resize(other.size()); - internal::smart_copy(other.m_values, other.m_values + m_size, m_values); - internal::smart_copy(other.m_indices, other.m_indices + m_size, m_indices); - return *this; - } - - void swap(CompressedStorage& other) - { - std::swap(m_values, other.m_values); - std::swap(m_indices, other.m_indices); - std::swap(m_size, other.m_size); - std::swap(m_allocatedSize, other.m_allocatedSize); - } - - ~CompressedStorage() - { - delete[] m_values; - delete[] m_indices; - } - - void reserve(size_t size) - { - size_t newAllocatedSize = m_size + size; - if (newAllocatedSize > m_allocatedSize) - reallocate(newAllocatedSize); - } - - void squeeze() - { - if (m_allocatedSize>m_size) - reallocate(m_size); - } - - void resize(size_t size, double reserveSizeFactor = 0) - { - if (m_allocatedSize(m_size); - resize(m_size+1, 1); - m_values[id] = v; - m_indices[id] = i; - } - - inline size_t size() const { return m_size; } - inline size_t allocatedSize() const { return m_allocatedSize; } - inline void clear() { m_size = 0; } - - inline Scalar& value(size_t i) { return m_values[i]; } - inline const Scalar& value(size_t i) const { return m_values[i]; } - - inline Index& index(size_t i) { return m_indices[i]; } - inline const Index& index(size_t i) const { return m_indices[i]; } - - static CompressedStorage Map(Index* indices, Scalar* values, size_t size) - { - CompressedStorage res; - res.m_indices = indices; - res.m_values = values; - res.m_allocatedSize = res.m_size = size; - return res; - } - - /** \returns the largest \c k such that for all \c j in [0,k) index[\c j]\<\a key */ - inline Index searchLowerIndex(Index key) const - { - return searchLowerIndex(0, m_size, key); - } - - /** \returns the largest \c k in [start,end) such that for all \c j in [start,k) index[\c j]\<\a key */ - inline Index searchLowerIndex(size_t start, size_t end, Index key) const - { - while(end>start) - { - size_t mid = (end+start)>>1; - if (m_indices[mid](start); - } - - /** \returns the stored value at index \a key - * If the value does not exist, then the value \a defaultValue is returned without any insertion. */ - inline Scalar at(Index key, const Scalar& defaultValue = Scalar(0)) const - { - if (m_size==0) - return defaultValue; - else if (key==m_indices[m_size-1]) - return m_values[m_size-1]; - // ^^ optimization: let's first check if it is the last coefficient - // (very common in high level algorithms) - const size_t id = searchLowerIndex(0,m_size-1,key); - return ((id=end) - return Scalar(0); - else if (end>start && key==m_indices[end-1]) - return m_values[end-1]; - // ^^ optimization: let's first check if it is the last coefficient - // (very common in high level algorithms) - const size_t id = searchLowerIndex(start,end-1,key); - return ((id=m_size || m_indices[id]!=key) - { - resize(m_size+1,1); - for (size_t j=m_size-1; j>id; --j) - { - m_indices[j] = m_indices[j-1]; - m_values[j] = m_values[j-1]; - } - m_indices[id] = key; - m_values[id] = defaultValue; - } - return m_values[id]; - } - - void prune(const Scalar& reference, const RealScalar& epsilon = NumTraits::dummy_precision()) - { - size_t k = 0; - size_t n = size(); - for (size_t i=0; i -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_CONSERVATIVESPARSESPARSEPRODUCT_H -#define EIGEN_CONSERVATIVESPARSESPARSEPRODUCT_H - -namespace Eigen { - -namespace internal { - -template -static void conservative_sparse_sparse_product_impl(const Lhs& lhs, const Rhs& rhs, ResultType& res) -{ - typedef typename remove_all::type::Scalar Scalar; - typedef typename remove_all::type::Index Index; - - // make sure to call innerSize/outerSize since we fake the storage order. - Index rows = lhs.innerSize(); - Index cols = rhs.outerSize(); - eigen_assert(lhs.outerSize() == rhs.innerSize()); - - std::vector mask(rows,false); - Matrix values(rows); - Matrix indices(rows); - - // estimate the number of non zero entries - // given a rhs column containing Y non zeros, we assume that the respective Y columns - // of the lhs differs in average of one non zeros, thus the number of non zeros for - // the product of a rhs column with the lhs is X+Y where X is the average number of non zero - // per column of the lhs. - // Therefore, we have nnz(lhs*rhs) = nnz(lhs) + nnz(rhs) - Index estimated_nnz_prod = lhs.nonZeros() + rhs.nonZeros(); - - res.setZero(); - res.reserve(Index(estimated_nnz_prod)); - // we compute each column of the result, one after the other - for (Index j=0; j use a quick sort - // otherwise => loop through the entire vector - // In order to avoid to perform an expensive log2 when the - // result is clearly very sparse we use a linear bound up to 200. - //if((nnz<200 && nnz1) std::sort(indices.data(),indices.data()+nnz); - for(Index k=0; k::Flags&RowMajorBit) ? RowMajor : ColMajor, - int RhsStorageOrder = (traits::Flags&RowMajorBit) ? RowMajor : ColMajor, - int ResStorageOrder = (traits::Flags&RowMajorBit) ? RowMajor : ColMajor> -struct conservative_sparse_sparse_product_selector; - -template -struct conservative_sparse_sparse_product_selector -{ - typedef typename remove_all::type LhsCleaned; - typedef typename LhsCleaned::Scalar Scalar; - - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { - typedef SparseMatrix RowMajorMatrix; - typedef SparseMatrix ColMajorMatrix; - ColMajorMatrix resCol(lhs.rows(),rhs.cols()); - internal::conservative_sparse_sparse_product_impl(lhs, rhs, resCol); - // sort the non zeros: - RowMajorMatrix resRow(resCol); - res = resRow; - } -}; - -template -struct conservative_sparse_sparse_product_selector -{ - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { - typedef SparseMatrix RowMajorMatrix; - RowMajorMatrix rhsRow = rhs; - RowMajorMatrix resRow(lhs.rows(), rhs.cols()); - internal::conservative_sparse_sparse_product_impl(rhsRow, lhs, resRow); - res = resRow; - } -}; - -template -struct conservative_sparse_sparse_product_selector -{ - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { - typedef SparseMatrix RowMajorMatrix; - RowMajorMatrix lhsRow = lhs; - RowMajorMatrix resRow(lhs.rows(), rhs.cols()); - internal::conservative_sparse_sparse_product_impl(rhs, lhsRow, resRow); - res = resRow; - } -}; - -template -struct conservative_sparse_sparse_product_selector -{ - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { - typedef SparseMatrix RowMajorMatrix; - RowMajorMatrix resRow(lhs.rows(), rhs.cols()); - internal::conservative_sparse_sparse_product_impl(rhs, lhs, resRow); - res = resRow; - } -}; - - -template -struct conservative_sparse_sparse_product_selector -{ - typedef typename traits::type>::Scalar Scalar; - - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { - typedef SparseMatrix ColMajorMatrix; - ColMajorMatrix resCol(lhs.rows(), rhs.cols()); - internal::conservative_sparse_sparse_product_impl(lhs, rhs, resCol); - res = resCol; - } -}; - -template -struct conservative_sparse_sparse_product_selector -{ - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { - typedef SparseMatrix ColMajorMatrix; - ColMajorMatrix lhsCol = lhs; - ColMajorMatrix resCol(lhs.rows(), rhs.cols()); - internal::conservative_sparse_sparse_product_impl(lhsCol, rhs, resCol); - res = resCol; - } -}; - -template -struct conservative_sparse_sparse_product_selector -{ - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { - typedef SparseMatrix ColMajorMatrix; - ColMajorMatrix rhsCol = rhs; - ColMajorMatrix resCol(lhs.rows(), rhs.cols()); - internal::conservative_sparse_sparse_product_impl(lhs, rhsCol, resCol); - res = resCol; - } -}; - -template -struct conservative_sparse_sparse_product_selector -{ - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { - typedef SparseMatrix RowMajorMatrix; - typedef SparseMatrix ColMajorMatrix; - RowMajorMatrix resRow(lhs.rows(),rhs.cols()); - internal::conservative_sparse_sparse_product_impl(rhs, lhs, resRow); - // sort the non zeros: - ColMajorMatrix resCol(resRow); - res = resCol; - } -}; - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_CONSERVATIVESPARSESPARSEPRODUCT_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/MappedSparseMatrix.h b/libs/eigen3/Eigen/src/Core/SparseCore/MappedSparseMatrix.h deleted file mode 100644 index ab1a266a9..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/MappedSparseMatrix.h +++ /dev/null @@ -1,181 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_MAPPED_SPARSEMATRIX_H -#define EIGEN_MAPPED_SPARSEMATRIX_H - -namespace Eigen { - -/** \class MappedSparseMatrix - * - * \brief Sparse matrix - * - * \param _Scalar the scalar type, i.e. the type of the coefficients - * - * See http://www.netlib.org/linalg/html_templates/node91.html for details on the storage scheme. - * - */ -namespace internal { -template -struct traits > : traits > -{}; -} - -template -class MappedSparseMatrix - : public SparseMatrixBase > -{ - public: - EIGEN_SPARSE_PUBLIC_INTERFACE(MappedSparseMatrix) - enum { IsRowMajor = Base::IsRowMajor }; - - protected: - - Index m_outerSize; - Index m_innerSize; - Index m_nnz; - Index* m_outerIndex; - Index* m_innerIndices; - Scalar* m_values; - - public: - - inline Index rows() const { return IsRowMajor ? m_outerSize : m_innerSize; } - inline Index cols() const { return IsRowMajor ? m_innerSize : m_outerSize; } - inline Index innerSize() const { return m_innerSize; } - inline Index outerSize() const { return m_outerSize; } - - bool isCompressed() const { return true; } - - //---------------------------------------- - // direct access interface - inline const Scalar* valuePtr() const { return m_values; } - inline Scalar* valuePtr() { return m_values; } - - inline const Index* innerIndexPtr() const { return m_innerIndices; } - inline Index* innerIndexPtr() { return m_innerIndices; } - - inline const Index* outerIndexPtr() const { return m_outerIndex; } - inline Index* outerIndexPtr() { return m_outerIndex; } - //---------------------------------------- - - inline Scalar coeff(Index row, Index col) const - { - const Index outer = IsRowMajor ? row : col; - const Index inner = IsRowMajor ? col : row; - - Index start = m_outerIndex[outer]; - Index end = m_outerIndex[outer+1]; - if (start==end) - return Scalar(0); - else if (end>0 && inner==m_innerIndices[end-1]) - return m_values[end-1]; - // ^^ optimization: let's first check if it is the last coefficient - // (very common in high level algorithms) - - const Index* r = std::lower_bound(&m_innerIndices[start],&m_innerIndices[end-1],inner); - const Index id = r-&m_innerIndices[0]; - return ((*r==inner) && (id=start && "you probably called coeffRef on a non finalized matrix"); - eigen_assert(end>start && "coeffRef cannot be called on a zero coefficient"); - Index* r = std::lower_bound(&m_innerIndices[start],&m_innerIndices[end],inner); - const Index id = r-&m_innerIndices[0]; - eigen_assert((*r==inner) && (id -class MappedSparseMatrix::InnerIterator -{ - public: - InnerIterator(const MappedSparseMatrix& mat, Index outer) - : m_matrix(mat), - m_outer(outer), - m_id(mat.outerIndexPtr()[outer]), - m_start(m_id), - m_end(mat.outerIndexPtr()[outer+1]) - {} - - inline InnerIterator& operator++() { m_id++; return *this; } - - inline Scalar value() const { return m_matrix.valuePtr()[m_id]; } - inline Scalar& valueRef() { return const_cast(m_matrix.valuePtr()[m_id]); } - - inline Index index() const { return m_matrix.innerIndexPtr()[m_id]; } - inline Index row() const { return IsRowMajor ? m_outer : index(); } - inline Index col() const { return IsRowMajor ? index() : m_outer; } - - inline operator bool() const { return (m_id < m_end) && (m_id>=m_start); } - - protected: - const MappedSparseMatrix& m_matrix; - const Index m_outer; - Index m_id; - const Index m_start; - const Index m_end; -}; - -template -class MappedSparseMatrix::ReverseInnerIterator -{ - public: - ReverseInnerIterator(const MappedSparseMatrix& mat, Index outer) - : m_matrix(mat), - m_outer(outer), - m_id(mat.outerIndexPtr()[outer+1]), - m_start(mat.outerIndexPtr()[outer]), - m_end(m_id) - {} - - inline ReverseInnerIterator& operator--() { m_id--; return *this; } - - inline Scalar value() const { return m_matrix.valuePtr()[m_id-1]; } - inline Scalar& valueRef() { return const_cast(m_matrix.valuePtr()[m_id-1]); } - - inline Index index() const { return m_matrix.innerIndexPtr()[m_id-1]; } - inline Index row() const { return IsRowMajor ? m_outer : index(); } - inline Index col() const { return IsRowMajor ? index() : m_outer; } - - inline operator bool() const { return (m_id <= m_end) && (m_id>m_start); } - - protected: - const MappedSparseMatrix& m_matrix; - const Index m_outer; - Index m_id; - const Index m_start; - const Index m_end; -}; - -} // end namespace Eigen - -#endif // EIGEN_MAPPED_SPARSEMATRIX_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparseBlock.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparseBlock.h deleted file mode 100644 index 16a20a574..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparseBlock.h +++ /dev/null @@ -1,409 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2009 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSE_BLOCK_H -#define EIGEN_SPARSE_BLOCK_H - -namespace Eigen { - -template -class BlockImpl - : public SparseMatrixBase > -{ - typedef typename internal::remove_all::type _MatrixTypeNested; - typedef Block BlockType; -public: - enum { IsRowMajor = internal::traits::IsRowMajor }; -protected: - enum { OuterSize = IsRowMajor ? BlockRows : BlockCols }; -public: - EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType) - - class InnerIterator: public XprType::InnerIterator - { - typedef typename BlockImpl::Index Index; - public: - inline InnerIterator(const BlockType& xpr, Index outer) - : XprType::InnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) - {} - inline Index row() const { return IsRowMajor ? m_outer : this->index(); } - inline Index col() const { return IsRowMajor ? this->index() : m_outer; } - protected: - Index m_outer; - }; - class ReverseInnerIterator: public XprType::ReverseInnerIterator - { - typedef typename BlockImpl::Index Index; - public: - inline ReverseInnerIterator(const BlockType& xpr, Index outer) - : XprType::ReverseInnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) - {} - inline Index row() const { return IsRowMajor ? m_outer : this->index(); } - inline Index col() const { return IsRowMajor ? this->index() : m_outer; } - protected: - Index m_outer; - }; - - inline BlockImpl(const XprType& xpr, int i) - : m_matrix(xpr), m_outerStart(i), m_outerSize(OuterSize) - {} - - inline BlockImpl(const XprType& xpr, int startRow, int startCol, int blockRows, int blockCols) - : m_matrix(xpr), m_outerStart(IsRowMajor ? startRow : startCol), m_outerSize(IsRowMajor ? blockRows : blockCols) - {} - - EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); } - - protected: - - typename XprType::Nested m_matrix; - Index m_outerStart; - const internal::variable_if_dynamic m_outerSize; - - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl) -}; - - -/*************************************************************************** -* specialisation for SparseMatrix -***************************************************************************/ - -template -class BlockImpl,BlockRows,BlockCols,true,Sparse> - : public SparseMatrixBase,BlockRows,BlockCols,true> > -{ - typedef SparseMatrix<_Scalar, _Options, _Index> SparseMatrixType; - typedef typename internal::remove_all::type _MatrixTypeNested; - typedef Block BlockType; -public: - enum { IsRowMajor = internal::traits::IsRowMajor }; - EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType) -protected: - enum { OuterSize = IsRowMajor ? BlockRows : BlockCols }; -public: - - class InnerIterator: public SparseMatrixType::InnerIterator - { - public: - inline InnerIterator(const BlockType& xpr, Index outer) - : SparseMatrixType::InnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) - {} - inline Index row() const { return IsRowMajor ? m_outer : this->index(); } - inline Index col() const { return IsRowMajor ? this->index() : m_outer; } - protected: - Index m_outer; - }; - class ReverseInnerIterator: public SparseMatrixType::ReverseInnerIterator - { - public: - inline ReverseInnerIterator(const BlockType& xpr, Index outer) - : SparseMatrixType::ReverseInnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) - {} - inline Index row() const { return IsRowMajor ? m_outer : this->index(); } - inline Index col() const { return IsRowMajor ? this->index() : m_outer; } - protected: - Index m_outer; - }; - - inline BlockImpl(const SparseMatrixType& xpr, int i) - : m_matrix(xpr), m_outerStart(i), m_outerSize(OuterSize) - {} - - inline BlockImpl(const SparseMatrixType& xpr, int startRow, int startCol, int blockRows, int blockCols) - : m_matrix(xpr), m_outerStart(IsRowMajor ? startRow : startCol), m_outerSize(IsRowMajor ? blockRows : blockCols) - {} - - template - inline BlockType& operator=(const SparseMatrixBase& other) - { - typedef typename internal::remove_all::type _NestedMatrixType; - _NestedMatrixType& matrix = const_cast<_NestedMatrixType&>(m_matrix);; - // This assignement is slow if this vector set is not empty - // and/or it is not at the end of the nonzeros of the underlying matrix. - - // 1 - eval to a temporary to avoid transposition and/or aliasing issues - SparseMatrix tmp(other); - - // 2 - let's check whether there is enough allocated memory - Index nnz = tmp.nonZeros(); - Index start = m_outerStart==0 ? 0 : matrix.outerIndexPtr()[m_outerStart]; // starting position of the current block - Index end = m_matrix.outerIndexPtr()[m_outerStart+m_outerSize.value()]; // ending posiiton of the current block - Index block_size = end - start; // available room in the current block - Index tail_size = m_matrix.outerIndexPtr()[m_matrix.outerSize()] - end; - - Index free_size = m_matrix.isCompressed() - ? Index(matrix.data().allocatedSize()) + block_size - : block_size; - - if(nnz>free_size) - { - // realloc manually to reduce copies - typename SparseMatrixType::Storage newdata(m_matrix.data().allocatedSize() - block_size + nnz); - - std::memcpy(&newdata.value(0), &m_matrix.data().value(0), start*sizeof(Scalar)); - std::memcpy(&newdata.index(0), &m_matrix.data().index(0), start*sizeof(Index)); - - std::memcpy(&newdata.value(start), &tmp.data().value(0), nnz*sizeof(Scalar)); - std::memcpy(&newdata.index(start), &tmp.data().index(0), nnz*sizeof(Index)); - - std::memcpy(&newdata.value(start+nnz), &matrix.data().value(end), tail_size*sizeof(Scalar)); - std::memcpy(&newdata.index(start+nnz), &matrix.data().index(end), tail_size*sizeof(Index)); - - newdata.resize(m_matrix.outerIndexPtr()[m_matrix.outerSize()] - block_size + nnz); - - matrix.data().swap(newdata); - } - else - { - // no need to realloc, simply copy the tail at its respective position and insert tmp - matrix.data().resize(start + nnz + tail_size); - - std::memmove(&matrix.data().value(start+nnz), &matrix.data().value(end), tail_size*sizeof(Scalar)); - std::memmove(&matrix.data().index(start+nnz), &matrix.data().index(end), tail_size*sizeof(Index)); - - std::memcpy(&matrix.data().value(start), &tmp.data().value(0), nnz*sizeof(Scalar)); - std::memcpy(&matrix.data().index(start), &tmp.data().index(0), nnz*sizeof(Index)); - } - - // update innerNonZeros - if(!m_matrix.isCompressed()) - for(Index j=0; j(other); - } - - inline const Scalar* valuePtr() const - { return m_matrix.valuePtr() + m_matrix.outerIndexPtr()[m_outerStart]; } - inline Scalar* valuePtr() - { return m_matrix.const_cast_derived().valuePtr() + m_matrix.outerIndexPtr()[m_outerStart]; } - - inline const Index* innerIndexPtr() const - { return m_matrix.innerIndexPtr() + m_matrix.outerIndexPtr()[m_outerStart]; } - inline Index* innerIndexPtr() - { return m_matrix.const_cast_derived().innerIndexPtr() + m_matrix.outerIndexPtr()[m_outerStart]; } - - inline const Index* outerIndexPtr() const - { return m_matrix.outerIndexPtr() + m_outerStart; } - inline Index* outerIndexPtr() - { return m_matrix.const_cast_derived().outerIndexPtr() + m_outerStart; } - - Index nonZeros() const - { - if(m_matrix.isCompressed()) - return std::size_t(m_matrix.outerIndexPtr()[m_outerStart+m_outerSize.value()]) - - std::size_t(m_matrix.outerIndexPtr()[m_outerStart]); - else if(m_outerSize.value()==0) - return 0; - else - return Map >(m_matrix.innerNonZeroPtr()+m_outerStart, m_outerSize.value()).sum(); - } - - const Scalar& lastCoeff() const - { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(BlockImpl); - eigen_assert(nonZeros()>0); - if(m_matrix.isCompressed()) - return m_matrix.valuePtr()[m_matrix.outerIndexPtr()[m_outerStart+1]-1]; - else - return m_matrix.valuePtr()[m_matrix.outerIndexPtr()[m_outerStart]+m_matrix.innerNonZeroPtr()[m_outerStart]-1]; - } - - EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); } - - protected: - - typename SparseMatrixType::Nested m_matrix; - Index m_outerStart; - const internal::variable_if_dynamic m_outerSize; - -}; - -//---------- - -/** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this - * is col-major (resp. row-major). - */ -template -typename SparseMatrixBase::InnerVectorReturnType SparseMatrixBase::innerVector(Index outer) -{ return InnerVectorReturnType(derived(), outer); } - -/** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this - * is col-major (resp. row-major). Read-only. - */ -template -const typename SparseMatrixBase::ConstInnerVectorReturnType SparseMatrixBase::innerVector(Index outer) const -{ return ConstInnerVectorReturnType(derived(), outer); } - -/** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this - * is col-major (resp. row-major). - */ -template -Block SparseMatrixBase::innerVectors(Index outerStart, Index outerSize) -{ - return Block(derived(), - IsRowMajor ? outerStart : 0, IsRowMajor ? 0 : outerStart, - IsRowMajor ? outerSize : rows(), IsRowMajor ? cols() : outerSize); - -} - -/** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this - * is col-major (resp. row-major). Read-only. - */ -template -const Block SparseMatrixBase::innerVectors(Index outerStart, Index outerSize) const -{ - return Block(derived(), - IsRowMajor ? outerStart : 0, IsRowMajor ? 0 : outerStart, - IsRowMajor ? outerSize : rows(), IsRowMajor ? cols() : outerSize); - -} - -/** Generic implementation of sparse Block expression. - * Real-only. - */ -template -class BlockImpl - : public SparseMatrixBase >, internal::no_assignment_operator -{ - typedef typename internal::remove_all::type _MatrixTypeNested; - typedef Block BlockType; -public: - enum { IsRowMajor = internal::traits::IsRowMajor }; - EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType) - - /** Column or Row constructor - */ - inline BlockImpl(const XprType& xpr, int i) - : m_matrix(xpr), - m_startRow( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0), - m_startCol( (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0), - m_blockRows(xpr.rows()), - m_blockCols(xpr.cols()) - {} - - /** Dynamic-size constructor - */ - inline BlockImpl(const XprType& xpr, int startRow, int startCol, int blockRows, int blockCols) - : m_matrix(xpr), m_startRow(startRow), m_startCol(startCol), m_blockRows(blockRows), m_blockCols(blockCols) - {} - - inline int rows() const { return m_blockRows.value(); } - inline int cols() const { return m_blockCols.value(); } - - inline Scalar& coeffRef(int row, int col) - { - return m_matrix.const_cast_derived() - .coeffRef(row + m_startRow.value(), col + m_startCol.value()); - } - - inline const Scalar coeff(int row, int col) const - { - return m_matrix.coeff(row + m_startRow.value(), col + m_startCol.value()); - } - - inline Scalar& coeffRef(int index) - { - return m_matrix.const_cast_derived() - .coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), - m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); - } - - inline const Scalar coeff(int index) const - { - return m_matrix - .coeff(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), - m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); - } - - inline const _MatrixTypeNested& nestedExpression() const { return m_matrix; } - - class InnerIterator : public _MatrixTypeNested::InnerIterator - { - typedef typename _MatrixTypeNested::InnerIterator Base; - const BlockType& m_block; - Index m_end; - public: - - EIGEN_STRONG_INLINE InnerIterator(const BlockType& block, Index outer) - : Base(block.derived().nestedExpression(), outer + (IsRowMajor ? block.m_startRow.value() : block.m_startCol.value())), - m_block(block), - m_end(IsRowMajor ? block.m_startCol.value()+block.m_blockCols.value() : block.m_startRow.value()+block.m_blockRows.value()) - { - while( (Base::operator bool()) && (Base::index() < (IsRowMajor ? m_block.m_startCol.value() : m_block.m_startRow.value())) ) - Base::operator++(); - } - - inline Index index() const { return Base::index() - (IsRowMajor ? m_block.m_startCol.value() : m_block.m_startRow.value()); } - inline Index outer() const { return Base::outer() - (IsRowMajor ? m_block.m_startRow.value() : m_block.m_startCol.value()); } - inline Index row() const { return Base::row() - m_block.m_startRow.value(); } - inline Index col() const { return Base::col() - m_block.m_startCol.value(); } - - inline operator bool() const { return Base::operator bool() && Base::index() < m_end; } - }; - class ReverseInnerIterator : public _MatrixTypeNested::ReverseInnerIterator - { - typedef typename _MatrixTypeNested::ReverseInnerIterator Base; - const BlockType& m_block; - Index m_begin; - public: - - EIGEN_STRONG_INLINE ReverseInnerIterator(const BlockType& block, Index outer) - : Base(block.derived().nestedExpression(), outer + (IsRowMajor ? block.m_startRow.value() : block.m_startCol.value())), - m_block(block), - m_begin(IsRowMajor ? block.m_startCol.value() : block.m_startRow.value()) - { - while( (Base::operator bool()) && (Base::index() >= (IsRowMajor ? m_block.m_startCol.value()+block.m_blockCols.value() : m_block.m_startRow.value()+block.m_blockRows.value())) ) - Base::operator--(); - } - - inline Index index() const { return Base::index() - (IsRowMajor ? m_block.m_startCol.value() : m_block.m_startRow.value()); } - inline Index outer() const { return Base::outer() - (IsRowMajor ? m_block.m_startRow.value() : m_block.m_startCol.value()); } - inline Index row() const { return Base::row() - m_block.m_startRow.value(); } - inline Index col() const { return Base::col() - m_block.m_startCol.value(); } - - inline operator bool() const { return Base::operator bool() && Base::index() >= m_begin; } - }; - protected: - friend class InnerIterator; - friend class ReverseInnerIterator; - - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl) - - typename XprType::Nested m_matrix; - const internal::variable_if_dynamic m_startRow; - const internal::variable_if_dynamic m_startCol; - const internal::variable_if_dynamic m_blockRows; - const internal::variable_if_dynamic m_blockCols; - -}; - -} // end namespace Eigen - -#endif // EIGEN_SPARSE_BLOCK_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparseColEtree.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparseColEtree.h deleted file mode 100644 index f8745f461..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparseColEtree.h +++ /dev/null @@ -1,206 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2012 Désiré Nuentsa-Wakam -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -/* - - * NOTE: This file is the modified version of sp_coletree.c file in SuperLU - - * -- SuperLU routine (version 3.1) -- - * Univ. of California Berkeley, Xerox Palo Alto Research Center, - * and Lawrence Berkeley National Lab. - * August 1, 2008 - * - * Copyright (c) 1994 by Xerox Corporation. All rights reserved. - * - * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY - * EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. - * - * Permission is hereby granted to use or copy this program for any - * purpose, provided the above notices are retained on all copies. - * Permission to modify the code and to distribute modified code is - * granted, provided the above notices are retained, and a notice that - * the code was modified is included with the above copyright notice. - */ -#ifndef SPARSE_COLETREE_H -#define SPARSE_COLETREE_H - -namespace Eigen { - -namespace internal { - -/** Find the root of the tree/set containing the vertex i : Use Path halving */ -template -Index etree_find (Index i, IndexVector& pp) -{ - Index p = pp(i); // Parent - Index gp = pp(p); // Grand parent - while (gp != p) - { - pp(i) = gp; // Parent pointer on find path is changed to former grand parent - i = gp; - p = pp(i); - gp = pp(p); - } - return p; -} - -/** Compute the column elimination tree of a sparse matrix - * \param mat The matrix in column-major format. - * \param parent The elimination tree - * \param firstRowElt The column index of the first element in each row - * \param perm The permutation to apply to the column of \b mat - */ -template -int coletree(const MatrixType& mat, IndexVector& parent, IndexVector& firstRowElt, typename MatrixType::Index *perm=0) -{ - typedef typename MatrixType::Index Index; - Index nc = mat.cols(); // Number of columns - Index m = mat.rows(); - Index diagSize = (std::min)(nc,m); - IndexVector root(nc); // root of subtree of etree - root.setZero(); - IndexVector pp(nc); // disjoint sets - pp.setZero(); // Initialize disjoint sets - parent.resize(mat.cols()); - //Compute first nonzero column in each row - Index row,col; - firstRowElt.resize(m); - firstRowElt.setConstant(nc); - firstRowElt.segment(0, diagSize).setLinSpaced(diagSize, 0, diagSize-1); - bool found_diag; - for (col = 0; col < nc; col++) - { - Index pcol = col; - if(perm) pcol = perm[col]; - for (typename MatrixType::InnerIterator it(mat, pcol); it; ++it) - { - row = it.row(); - firstRowElt(row) = (std::min)(firstRowElt(row), col); - } - } - /* Compute etree by Liu's algorithm for symmetric matrices, - except use (firstRowElt[r],c) in place of an edge (r,c) of A. - Thus each row clique in A'*A is replaced by a star - centered at its first vertex, which has the same fill. */ - Index rset, cset, rroot; - for (col = 0; col < nc; col++) - { - found_diag = col>=m; - pp(col) = col; - cset = col; - root(cset) = col; - parent(col) = nc; - /* The diagonal element is treated here even if it does not exist in the matrix - * hence the loop is executed once more */ - Index pcol = col; - if(perm) pcol = perm[col]; - for (typename MatrixType::InnerIterator it(mat, pcol); it||!found_diag; ++it) - { // A sequence of interleaved find and union is performed - Index i = col; - if(it) i = it.index(); - if (i == col) found_diag = true; - - row = firstRowElt(i); - if (row >= col) continue; - rset = internal::etree_find(row, pp); // Find the name of the set containing row - rroot = root(rset); - if (rroot != col) - { - parent(rroot) = col; - pp(cset) = rset; - cset = rset; - root(cset) = col; - } - } - } - return 0; -} - -/** - * Depth-first search from vertex n. No recursion. - * This routine was contributed by Cédric Doucet, CEDRAT Group, Meylan, France. -*/ -template -void nr_etdfs (Index n, IndexVector& parent, IndexVector& first_kid, IndexVector& next_kid, IndexVector& post, Index postnum) -{ - Index current = n, first, next; - while (postnum != n) - { - // No kid for the current node - first = first_kid(current); - - // no kid for the current node - if (first == -1) - { - // Numbering this node because it has no kid - post(current) = postnum++; - - // looking for the next kid - next = next_kid(current); - while (next == -1) - { - // No more kids : back to the parent node - current = parent(current); - // numbering the parent node - post(current) = postnum++; - - // Get the next kid - next = next_kid(current); - } - // stopping criterion - if (postnum == n+1) return; - - // Updating current node - current = next; - } - else - { - current = first; - } - } -} - - -/** - * \brief Post order a tree - * \param n the number of nodes - * \param parent Input tree - * \param post postordered tree - */ -template -void treePostorder(Index n, IndexVector& parent, IndexVector& post) -{ - IndexVector first_kid, next_kid; // Linked list of children - Index postnum; - // Allocate storage for working arrays and results - first_kid.resize(n+1); - next_kid.setZero(n+1); - post.setZero(n+1); - - // Set up structure describing children - Index v, dad; - first_kid.setConstant(-1); - for (v = n-1; v >= 0; v--) - { - dad = parent(v); - next_kid(v) = first_kid(dad); - first_kid(dad) = v; - } - - // Depth-first search from dummy root vertex #n - postnum = 0; - internal::nr_etdfs(n, parent, first_kid, next_kid, post, postnum); -} - -} // end namespace internal - -} // end namespace Eigen - -#endif // SPARSE_COLETREE_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparseCwiseBinaryOp.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparseCwiseBinaryOp.h deleted file mode 100644 index 60ca7690c..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparseCwiseBinaryOp.h +++ /dev/null @@ -1,325 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSE_CWISE_BINARY_OP_H -#define EIGEN_SPARSE_CWISE_BINARY_OP_H - -namespace Eigen { - -// Here we have to handle 3 cases: -// 1 - sparse op dense -// 2 - dense op sparse -// 3 - sparse op sparse -// We also need to implement a 4th iterator for: -// 4 - dense op dense -// Finally, we also need to distinguish between the product and other operations : -// configuration returned mode -// 1 - sparse op dense product sparse -// generic dense -// 2 - dense op sparse product sparse -// generic dense -// 3 - sparse op sparse product sparse -// generic sparse -// 4 - dense op dense product dense -// generic dense - -namespace internal { - -template<> struct promote_storage_type -{ typedef Sparse ret; }; - -template<> struct promote_storage_type -{ typedef Sparse ret; }; - -template::StorageKind, - typename _RhsStorageMode = typename traits::StorageKind> -class sparse_cwise_binary_op_inner_iterator_selector; - -} // end namespace internal - -template -class CwiseBinaryOpImpl - : public SparseMatrixBase > -{ - public: - class InnerIterator; - class ReverseInnerIterator; - typedef CwiseBinaryOp Derived; - EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) - CwiseBinaryOpImpl() - { - typedef typename internal::traits::StorageKind LhsStorageKind; - typedef typename internal::traits::StorageKind RhsStorageKind; - EIGEN_STATIC_ASSERT(( - (!internal::is_same::value) - || ((Lhs::Flags&RowMajorBit) == (Rhs::Flags&RowMajorBit))), - THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH); - } -}; - -template -class CwiseBinaryOpImpl::InnerIterator - : public internal::sparse_cwise_binary_op_inner_iterator_selector::InnerIterator> -{ - public: - typedef typename Lhs::Index Index; - typedef internal::sparse_cwise_binary_op_inner_iterator_selector< - BinaryOp,Lhs,Rhs, InnerIterator> Base; - - // NOTE: we have to prefix Index by "typename Lhs::" to avoid an ICE with VC11 - EIGEN_STRONG_INLINE InnerIterator(const CwiseBinaryOpImpl& binOp, typename Lhs::Index outer) - : Base(binOp.derived(),outer) - {} -}; - -/*************************************************************************** -* Implementation of inner-iterators -***************************************************************************/ - -// template struct internal::func_is_conjunction { enum { ret = false }; }; -// template struct internal::func_is_conjunction > { enum { ret = true }; }; - -// TODO generalize the internal::scalar_product_op specialization to all conjunctions if any ! - -namespace internal { - -// sparse - sparse (generic) -template -class sparse_cwise_binary_op_inner_iterator_selector -{ - typedef CwiseBinaryOp CwiseBinaryXpr; - typedef typename traits::Scalar Scalar; - typedef typename traits::_LhsNested _LhsNested; - typedef typename traits::_RhsNested _RhsNested; - typedef typename _LhsNested::InnerIterator LhsIterator; - typedef typename _RhsNested::InnerIterator RhsIterator; - typedef typename Lhs::Index Index; - - public: - - EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) - : m_lhsIter(xpr.lhs(),outer), m_rhsIter(xpr.rhs(),outer), m_functor(xpr.functor()) - { - this->operator++(); - } - - EIGEN_STRONG_INLINE Derived& operator++() - { - if (m_lhsIter && m_rhsIter && (m_lhsIter.index() == m_rhsIter.index())) - { - m_id = m_lhsIter.index(); - m_value = m_functor(m_lhsIter.value(), m_rhsIter.value()); - ++m_lhsIter; - ++m_rhsIter; - } - else if (m_lhsIter && (!m_rhsIter || (m_lhsIter.index() < m_rhsIter.index()))) - { - m_id = m_lhsIter.index(); - m_value = m_functor(m_lhsIter.value(), Scalar(0)); - ++m_lhsIter; - } - else if (m_rhsIter && (!m_lhsIter || (m_lhsIter.index() > m_rhsIter.index()))) - { - m_id = m_rhsIter.index(); - m_value = m_functor(Scalar(0), m_rhsIter.value()); - ++m_rhsIter; - } - else - { - m_value = 0; // this is to avoid a compilation warning - m_id = -1; - } - return *static_cast(this); - } - - EIGEN_STRONG_INLINE Scalar value() const { return m_value; } - - EIGEN_STRONG_INLINE Index index() const { return m_id; } - EIGEN_STRONG_INLINE Index row() const { return Lhs::IsRowMajor ? m_lhsIter.row() : index(); } - EIGEN_STRONG_INLINE Index col() const { return Lhs::IsRowMajor ? index() : m_lhsIter.col(); } - - EIGEN_STRONG_INLINE operator bool() const { return m_id>=0; } - - protected: - LhsIterator m_lhsIter; - RhsIterator m_rhsIter; - const BinaryOp& m_functor; - Scalar m_value; - Index m_id; -}; - -// sparse - sparse (product) -template -class sparse_cwise_binary_op_inner_iterator_selector, Lhs, Rhs, Derived, Sparse, Sparse> -{ - typedef scalar_product_op BinaryFunc; - typedef CwiseBinaryOp CwiseBinaryXpr; - typedef typename CwiseBinaryXpr::Scalar Scalar; - typedef typename traits::_LhsNested _LhsNested; - typedef typename _LhsNested::InnerIterator LhsIterator; - typedef typename traits::_RhsNested _RhsNested; - typedef typename _RhsNested::InnerIterator RhsIterator; - typedef typename Lhs::Index Index; - public: - - EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) - : m_lhsIter(xpr.lhs(),outer), m_rhsIter(xpr.rhs(),outer), m_functor(xpr.functor()) - { - while (m_lhsIter && m_rhsIter && (m_lhsIter.index() != m_rhsIter.index())) - { - if (m_lhsIter.index() < m_rhsIter.index()) - ++m_lhsIter; - else - ++m_rhsIter; - } - } - - EIGEN_STRONG_INLINE Derived& operator++() - { - ++m_lhsIter; - ++m_rhsIter; - while (m_lhsIter && m_rhsIter && (m_lhsIter.index() != m_rhsIter.index())) - { - if (m_lhsIter.index() < m_rhsIter.index()) - ++m_lhsIter; - else - ++m_rhsIter; - } - return *static_cast(this); - } - - EIGEN_STRONG_INLINE Scalar value() const { return m_functor(m_lhsIter.value(), m_rhsIter.value()); } - - EIGEN_STRONG_INLINE Index index() const { return m_lhsIter.index(); } - EIGEN_STRONG_INLINE Index row() const { return m_lhsIter.row(); } - EIGEN_STRONG_INLINE Index col() const { return m_lhsIter.col(); } - - EIGEN_STRONG_INLINE operator bool() const { return (m_lhsIter && m_rhsIter); } - - protected: - LhsIterator m_lhsIter; - RhsIterator m_rhsIter; - const BinaryFunc& m_functor; -}; - -// sparse - dense (product) -template -class sparse_cwise_binary_op_inner_iterator_selector, Lhs, Rhs, Derived, Sparse, Dense> -{ - typedef scalar_product_op BinaryFunc; - typedef CwiseBinaryOp CwiseBinaryXpr; - typedef typename CwiseBinaryXpr::Scalar Scalar; - typedef typename traits::_LhsNested _LhsNested; - typedef typename traits::RhsNested RhsNested; - typedef typename _LhsNested::InnerIterator LhsIterator; - typedef typename Lhs::Index Index; - enum { IsRowMajor = (int(Lhs::Flags)&RowMajorBit)==RowMajorBit }; - public: - - EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) - : m_rhs(xpr.rhs()), m_lhsIter(xpr.lhs(),outer), m_functor(xpr.functor()), m_outer(outer) - {} - - EIGEN_STRONG_INLINE Derived& operator++() - { - ++m_lhsIter; - return *static_cast(this); - } - - EIGEN_STRONG_INLINE Scalar value() const - { return m_functor(m_lhsIter.value(), - m_rhs.coeff(IsRowMajor?m_outer:m_lhsIter.index(),IsRowMajor?m_lhsIter.index():m_outer)); } - - EIGEN_STRONG_INLINE Index index() const { return m_lhsIter.index(); } - EIGEN_STRONG_INLINE Index row() const { return m_lhsIter.row(); } - EIGEN_STRONG_INLINE Index col() const { return m_lhsIter.col(); } - - EIGEN_STRONG_INLINE operator bool() const { return m_lhsIter; } - - protected: - RhsNested m_rhs; - LhsIterator m_lhsIter; - const BinaryFunc m_functor; - const Index m_outer; -}; - -// sparse - dense (product) -template -class sparse_cwise_binary_op_inner_iterator_selector, Lhs, Rhs, Derived, Dense, Sparse> -{ - typedef scalar_product_op BinaryFunc; - typedef CwiseBinaryOp CwiseBinaryXpr; - typedef typename CwiseBinaryXpr::Scalar Scalar; - typedef typename traits::_RhsNested _RhsNested; - typedef typename _RhsNested::InnerIterator RhsIterator; - typedef typename Lhs::Index Index; - - enum { IsRowMajor = (int(Rhs::Flags)&RowMajorBit)==RowMajorBit }; - public: - - EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) - : m_xpr(xpr), m_rhsIter(xpr.rhs(),outer), m_functor(xpr.functor()), m_outer(outer) - {} - - EIGEN_STRONG_INLINE Derived& operator++() - { - ++m_rhsIter; - return *static_cast(this); - } - - EIGEN_STRONG_INLINE Scalar value() const - { return m_functor(m_xpr.lhs().coeff(IsRowMajor?m_outer:m_rhsIter.index(),IsRowMajor?m_rhsIter.index():m_outer), m_rhsIter.value()); } - - EIGEN_STRONG_INLINE Index index() const { return m_rhsIter.index(); } - EIGEN_STRONG_INLINE Index row() const { return m_rhsIter.row(); } - EIGEN_STRONG_INLINE Index col() const { return m_rhsIter.col(); } - - EIGEN_STRONG_INLINE operator bool() const { return m_rhsIter; } - - protected: - const CwiseBinaryXpr& m_xpr; - RhsIterator m_rhsIter; - const BinaryFunc& m_functor; - const Index m_outer; -}; - -} // end namespace internal - -/*************************************************************************** -* Implementation of SparseMatrixBase and SparseCwise functions/operators -***************************************************************************/ - -template -template -EIGEN_STRONG_INLINE Derived & -SparseMatrixBase::operator-=(const SparseMatrixBase &other) -{ - return derived() = derived() - other.derived(); -} - -template -template -EIGEN_STRONG_INLINE Derived & -SparseMatrixBase::operator+=(const SparseMatrixBase& other) -{ - return derived() = derived() + other.derived(); -} - -template -template -EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE -SparseMatrixBase::cwiseProduct(const MatrixBase &other) const -{ - return EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE(derived(), other.derived()); -} - -} // end namespace Eigen - -#endif // EIGEN_SPARSE_CWISE_BINARY_OP_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparseCwiseUnaryOp.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparseCwiseUnaryOp.h deleted file mode 100644 index 5a50c7803..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparseCwiseUnaryOp.h +++ /dev/null @@ -1,163 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSE_CWISE_UNARY_OP_H -#define EIGEN_SPARSE_CWISE_UNARY_OP_H - -namespace Eigen { - -template -class CwiseUnaryOpImpl - : public SparseMatrixBase > -{ - public: - - class InnerIterator; - class ReverseInnerIterator; - - typedef CwiseUnaryOp Derived; - EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) - - protected: - typedef typename internal::traits::_XprTypeNested _MatrixTypeNested; - typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator; - typedef typename _MatrixTypeNested::ReverseInnerIterator MatrixTypeReverseIterator; -}; - -template -class CwiseUnaryOpImpl::InnerIterator - : public CwiseUnaryOpImpl::MatrixTypeIterator -{ - typedef typename CwiseUnaryOpImpl::Scalar Scalar; - typedef typename CwiseUnaryOpImpl::MatrixTypeIterator Base; - public: - - EIGEN_STRONG_INLINE InnerIterator(const CwiseUnaryOpImpl& unaryOp, typename CwiseUnaryOpImpl::Index outer) - : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) - {} - - EIGEN_STRONG_INLINE InnerIterator& operator++() - { Base::operator++(); return *this; } - - EIGEN_STRONG_INLINE typename CwiseUnaryOpImpl::Scalar value() const { return m_functor(Base::value()); } - - protected: - const UnaryOp m_functor; - private: - typename CwiseUnaryOpImpl::Scalar& valueRef(); -}; - -template -class CwiseUnaryOpImpl::ReverseInnerIterator - : public CwiseUnaryOpImpl::MatrixTypeReverseIterator -{ - typedef typename CwiseUnaryOpImpl::Scalar Scalar; - typedef typename CwiseUnaryOpImpl::MatrixTypeReverseIterator Base; - public: - - EIGEN_STRONG_INLINE ReverseInnerIterator(const CwiseUnaryOpImpl& unaryOp, typename CwiseUnaryOpImpl::Index outer) - : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) - {} - - EIGEN_STRONG_INLINE ReverseInnerIterator& operator--() - { Base::operator--(); return *this; } - - EIGEN_STRONG_INLINE typename CwiseUnaryOpImpl::Scalar value() const { return m_functor(Base::value()); } - - protected: - const UnaryOp m_functor; - private: - typename CwiseUnaryOpImpl::Scalar& valueRef(); -}; - -template -class CwiseUnaryViewImpl - : public SparseMatrixBase > -{ - public: - - class InnerIterator; - class ReverseInnerIterator; - - typedef CwiseUnaryView Derived; - EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) - - protected: - typedef typename internal::traits::_MatrixTypeNested _MatrixTypeNested; - typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator; - typedef typename _MatrixTypeNested::ReverseInnerIterator MatrixTypeReverseIterator; -}; - -template -class CwiseUnaryViewImpl::InnerIterator - : public CwiseUnaryViewImpl::MatrixTypeIterator -{ - typedef typename CwiseUnaryViewImpl::Scalar Scalar; - typedef typename CwiseUnaryViewImpl::MatrixTypeIterator Base; - public: - - EIGEN_STRONG_INLINE InnerIterator(const CwiseUnaryViewImpl& unaryOp, typename CwiseUnaryViewImpl::Index outer) - : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) - {} - - EIGEN_STRONG_INLINE InnerIterator& operator++() - { Base::operator++(); return *this; } - - EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar value() const { return m_functor(Base::value()); } - EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar& valueRef() { return m_functor(Base::valueRef()); } - - protected: - const ViewOp m_functor; -}; - -template -class CwiseUnaryViewImpl::ReverseInnerIterator - : public CwiseUnaryViewImpl::MatrixTypeReverseIterator -{ - typedef typename CwiseUnaryViewImpl::Scalar Scalar; - typedef typename CwiseUnaryViewImpl::MatrixTypeReverseIterator Base; - public: - - EIGEN_STRONG_INLINE ReverseInnerIterator(const CwiseUnaryViewImpl& unaryOp, typename CwiseUnaryViewImpl::Index outer) - : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) - {} - - EIGEN_STRONG_INLINE ReverseInnerIterator& operator--() - { Base::operator--(); return *this; } - - EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar value() const { return m_functor(Base::value()); } - EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar& valueRef() { return m_functor(Base::valueRef()); } - - protected: - const ViewOp m_functor; -}; - -template -EIGEN_STRONG_INLINE Derived& -SparseMatrixBase::operator*=(const Scalar& other) -{ - for (Index j=0; j -EIGEN_STRONG_INLINE Derived& -SparseMatrixBase::operator/=(const Scalar& other) -{ - for (Index j=0; j -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSEDENSEPRODUCT_H -#define EIGEN_SPARSEDENSEPRODUCT_H - -namespace Eigen { - -template struct SparseDenseProductReturnType -{ - typedef SparseTimeDenseProduct Type; -}; - -template struct SparseDenseProductReturnType -{ - typedef typename internal::conditional< - Lhs::IsRowMajor, - SparseDenseOuterProduct, - SparseDenseOuterProduct >::type Type; -}; - -template struct DenseSparseProductReturnType -{ - typedef DenseTimeSparseProduct Type; -}; - -template struct DenseSparseProductReturnType -{ - typedef typename internal::conditional< - Rhs::IsRowMajor, - SparseDenseOuterProduct, - SparseDenseOuterProduct >::type Type; -}; - -namespace internal { - -template -struct traits > -{ - typedef Sparse StorageKind; - typedef typename scalar_product_traits::Scalar, - typename traits::Scalar>::ReturnType Scalar; - typedef typename Lhs::Index Index; - typedef typename Lhs::Nested LhsNested; - typedef typename Rhs::Nested RhsNested; - typedef typename remove_all::type _LhsNested; - typedef typename remove_all::type _RhsNested; - - enum { - LhsCoeffReadCost = traits<_LhsNested>::CoeffReadCost, - RhsCoeffReadCost = traits<_RhsNested>::CoeffReadCost, - - RowsAtCompileTime = Tr ? int(traits::RowsAtCompileTime) : int(traits::RowsAtCompileTime), - ColsAtCompileTime = Tr ? int(traits::ColsAtCompileTime) : int(traits::ColsAtCompileTime), - MaxRowsAtCompileTime = Tr ? int(traits::MaxRowsAtCompileTime) : int(traits::MaxRowsAtCompileTime), - MaxColsAtCompileTime = Tr ? int(traits::MaxColsAtCompileTime) : int(traits::MaxColsAtCompileTime), - - Flags = Tr ? RowMajorBit : 0, - - CoeffReadCost = LhsCoeffReadCost + RhsCoeffReadCost + NumTraits::MulCost - }; -}; - -} // end namespace internal - -template -class SparseDenseOuterProduct - : public SparseMatrixBase > -{ - public: - - typedef SparseMatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(SparseDenseOuterProduct) - typedef internal::traits Traits; - - private: - - typedef typename Traits::LhsNested LhsNested; - typedef typename Traits::RhsNested RhsNested; - typedef typename Traits::_LhsNested _LhsNested; - typedef typename Traits::_RhsNested _RhsNested; - - public: - - class InnerIterator; - - EIGEN_STRONG_INLINE SparseDenseOuterProduct(const Lhs& lhs, const Rhs& rhs) - : m_lhs(lhs), m_rhs(rhs) - { - EIGEN_STATIC_ASSERT(!Tr,YOU_MADE_A_PROGRAMMING_MISTAKE); - } - - EIGEN_STRONG_INLINE SparseDenseOuterProduct(const Rhs& rhs, const Lhs& lhs) - : m_lhs(lhs), m_rhs(rhs) - { - EIGEN_STATIC_ASSERT(Tr,YOU_MADE_A_PROGRAMMING_MISTAKE); - } - - EIGEN_STRONG_INLINE Index rows() const { return Tr ? m_rhs.rows() : m_lhs.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return Tr ? m_lhs.cols() : m_rhs.cols(); } - - EIGEN_STRONG_INLINE const _LhsNested& lhs() const { return m_lhs; } - EIGEN_STRONG_INLINE const _RhsNested& rhs() const { return m_rhs; } - - protected: - LhsNested m_lhs; - RhsNested m_rhs; -}; - -template -class SparseDenseOuterProduct::InnerIterator : public _LhsNested::InnerIterator -{ - typedef typename _LhsNested::InnerIterator Base; - typedef typename SparseDenseOuterProduct::Index Index; - public: - EIGEN_STRONG_INLINE InnerIterator(const SparseDenseOuterProduct& prod, Index outer) - : Base(prod.lhs(), 0), m_outer(outer), m_factor(get(prod.rhs(), outer, typename internal::traits::StorageKind() )) - { } - - inline Index outer() const { return m_outer; } - inline Index row() const { return Transpose ? m_outer : Base::index(); } - inline Index col() const { return Transpose ? Base::index() : m_outer; } - - inline Scalar value() const { return Base::value() * m_factor; } - - protected: - static Scalar get(const _RhsNested &rhs, Index outer, Dense = Dense()) - { - return rhs.coeff(outer); - } - - static Scalar get(const _RhsNested &rhs, Index outer, Sparse = Sparse()) - { - typename Traits::_RhsNested::InnerIterator it(rhs, outer); - if (it && it.index()==0) - return it.value(); - - return Scalar(0); - } - - Index m_outer; - Scalar m_factor; -}; - -namespace internal { -template -struct traits > - : traits, Lhs, Rhs> > -{ - typedef Dense StorageKind; - typedef MatrixXpr XprKind; -}; - -template -struct sparse_time_dense_product_impl; - -template -struct sparse_time_dense_product_impl -{ - typedef typename internal::remove_all::type Lhs; - typedef typename internal::remove_all::type Rhs; - typedef typename internal::remove_all::type Res; - typedef typename Lhs::Index Index; - typedef typename Lhs::InnerIterator LhsInnerIterator; - static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const typename Res::Scalar& alpha) - { - for(Index c=0; c -struct sparse_time_dense_product_impl -{ - typedef typename internal::remove_all::type Lhs; - typedef typename internal::remove_all::type Rhs; - typedef typename internal::remove_all::type Res; - typedef typename Lhs::InnerIterator LhsInnerIterator; - typedef typename Lhs::Index Index; - static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const typename Res::Scalar& alpha) - { - for(Index c=0; c -struct sparse_time_dense_product_impl -{ - typedef typename internal::remove_all::type Lhs; - typedef typename internal::remove_all::type Rhs; - typedef typename internal::remove_all::type Res; - typedef typename Lhs::InnerIterator LhsInnerIterator; - typedef typename Lhs::Index Index; - static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const typename Res::Scalar& alpha) - { - for(Index j=0; j -struct sparse_time_dense_product_impl -{ - typedef typename internal::remove_all::type Lhs; - typedef typename internal::remove_all::type Rhs; - typedef typename internal::remove_all::type Res; - typedef typename Lhs::InnerIterator LhsInnerIterator; - typedef typename Lhs::Index Index; - static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const typename Res::Scalar& alpha) - { - for(Index j=0; j -inline void sparse_time_dense_product(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const AlphaType& alpha) -{ - sparse_time_dense_product_impl::run(lhs, rhs, res, alpha); -} - -} // end namespace internal - -template -class SparseTimeDenseProduct - : public ProductBase, Lhs, Rhs> -{ - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(SparseTimeDenseProduct) - - SparseTimeDenseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - {} - - template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const - { - internal::sparse_time_dense_product(m_lhs, m_rhs, dest, alpha); - } - - private: - SparseTimeDenseProduct& operator=(const SparseTimeDenseProduct&); -}; - - -// dense = dense * sparse -namespace internal { -template -struct traits > - : traits, Lhs, Rhs> > -{ - typedef Dense StorageKind; -}; -} // end namespace internal - -template -class DenseTimeSparseProduct - : public ProductBase, Lhs, Rhs> -{ - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(DenseTimeSparseProduct) - - DenseTimeSparseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - {} - - template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const - { - Transpose lhs_t(m_lhs); - Transpose rhs_t(m_rhs); - Transpose dest_t(dest); - internal::sparse_time_dense_product(rhs_t, lhs_t, dest_t, alpha); - } - - private: - DenseTimeSparseProduct& operator=(const DenseTimeSparseProduct&); -}; - -// sparse * dense -template -template -inline const typename SparseDenseProductReturnType::Type -SparseMatrixBase::operator*(const MatrixBase &other) const -{ - return typename SparseDenseProductReturnType::Type(derived(), other.derived()); -} - -} // end namespace Eigen - -#endif // EIGEN_SPARSEDENSEPRODUCT_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparseDiagonalProduct.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparseDiagonalProduct.h deleted file mode 100644 index 1bb590e64..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparseDiagonalProduct.h +++ /dev/null @@ -1,196 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSE_DIAGONAL_PRODUCT_H -#define EIGEN_SPARSE_DIAGONAL_PRODUCT_H - -namespace Eigen { - -// The product of a diagonal matrix with a sparse matrix can be easily -// implemented using expression template. -// We have two consider very different cases: -// 1 - diag * row-major sparse -// => each inner vector <=> scalar * sparse vector product -// => so we can reuse CwiseUnaryOp::InnerIterator -// 2 - diag * col-major sparse -// => each inner vector <=> densevector * sparse vector cwise product -// => again, we can reuse specialization of CwiseBinaryOp::InnerIterator -// for that particular case -// The two other cases are symmetric. - -namespace internal { - -template -struct traits > -{ - typedef typename remove_all::type _Lhs; - typedef typename remove_all::type _Rhs; - typedef typename _Lhs::Scalar Scalar; - typedef typename promote_index_type::Index, - typename traits::Index>::type Index; - typedef Sparse StorageKind; - typedef MatrixXpr XprKind; - enum { - RowsAtCompileTime = _Lhs::RowsAtCompileTime, - ColsAtCompileTime = _Rhs::ColsAtCompileTime, - - MaxRowsAtCompileTime = _Lhs::MaxRowsAtCompileTime, - MaxColsAtCompileTime = _Rhs::MaxColsAtCompileTime, - - SparseFlags = is_diagonal<_Lhs>::ret ? int(_Rhs::Flags) : int(_Lhs::Flags), - Flags = (SparseFlags&RowMajorBit), - CoeffReadCost = Dynamic - }; -}; - -enum {SDP_IsDiagonal, SDP_IsSparseRowMajor, SDP_IsSparseColMajor}; -template -class sparse_diagonal_product_inner_iterator_selector; - -} // end namespace internal - -template -class SparseDiagonalProduct - : public SparseMatrixBase >, - internal::no_assignment_operator -{ - typedef typename Lhs::Nested LhsNested; - typedef typename Rhs::Nested RhsNested; - - typedef typename internal::remove_all::type _LhsNested; - typedef typename internal::remove_all::type _RhsNested; - - enum { - LhsMode = internal::is_diagonal<_LhsNested>::ret ? internal::SDP_IsDiagonal - : (_LhsNested::Flags&RowMajorBit) ? internal::SDP_IsSparseRowMajor : internal::SDP_IsSparseColMajor, - RhsMode = internal::is_diagonal<_RhsNested>::ret ? internal::SDP_IsDiagonal - : (_RhsNested::Flags&RowMajorBit) ? internal::SDP_IsSparseRowMajor : internal::SDP_IsSparseColMajor - }; - - public: - - EIGEN_SPARSE_PUBLIC_INTERFACE(SparseDiagonalProduct) - - typedef internal::sparse_diagonal_product_inner_iterator_selector - <_LhsNested,_RhsNested,SparseDiagonalProduct,LhsMode,RhsMode> InnerIterator; - - // We do not want ReverseInnerIterator for diagonal-sparse products, - // but this dummy declaration is needed to make diag * sparse * diag compile. - class ReverseInnerIterator; - - EIGEN_STRONG_INLINE SparseDiagonalProduct(const Lhs& lhs, const Rhs& rhs) - : m_lhs(lhs), m_rhs(rhs) - { - eigen_assert(lhs.cols() == rhs.rows() && "invalid sparse matrix * diagonal matrix product"); - } - - EIGEN_STRONG_INLINE Index rows() const { return m_lhs.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_rhs.cols(); } - - EIGEN_STRONG_INLINE const _LhsNested& lhs() const { return m_lhs; } - EIGEN_STRONG_INLINE const _RhsNested& rhs() const { return m_rhs; } - - protected: - LhsNested m_lhs; - RhsNested m_rhs; -}; - -namespace internal { - -template -class sparse_diagonal_product_inner_iterator_selector - - : public CwiseUnaryOp,const Rhs>::InnerIterator -{ - typedef typename CwiseUnaryOp,const Rhs>::InnerIterator Base; - typedef typename Lhs::Index Index; - public: - inline sparse_diagonal_product_inner_iterator_selector( - const SparseDiagonalProductType& expr, Index outer) - : Base(expr.rhs()*(expr.lhs().diagonal().coeff(outer)), outer) - {} -}; - -template -class sparse_diagonal_product_inner_iterator_selector - - : public CwiseBinaryOp< - scalar_product_op, - const typename Rhs::ConstInnerVectorReturnType, - const typename Lhs::DiagonalVectorType>::InnerIterator -{ - typedef typename CwiseBinaryOp< - scalar_product_op, - const typename Rhs::ConstInnerVectorReturnType, - const typename Lhs::DiagonalVectorType>::InnerIterator Base; - typedef typename Lhs::Index Index; - Index m_outer; - public: - inline sparse_diagonal_product_inner_iterator_selector( - const SparseDiagonalProductType& expr, Index outer) - : Base(expr.rhs().innerVector(outer) .cwiseProduct(expr.lhs().diagonal()), 0), m_outer(outer) - {} - - inline Index outer() const { return m_outer; } - inline Index col() const { return m_outer; } -}; - -template -class sparse_diagonal_product_inner_iterator_selector - - : public CwiseUnaryOp,const Lhs>::InnerIterator -{ - typedef typename CwiseUnaryOp,const Lhs>::InnerIterator Base; - typedef typename Lhs::Index Index; - public: - inline sparse_diagonal_product_inner_iterator_selector( - const SparseDiagonalProductType& expr, Index outer) - : Base(expr.lhs()*expr.rhs().diagonal().coeff(outer), outer) - {} -}; - -template -class sparse_diagonal_product_inner_iterator_selector - - : public CwiseBinaryOp< - scalar_product_op, - const typename Lhs::ConstInnerVectorReturnType, - const Transpose >::InnerIterator -{ - typedef typename CwiseBinaryOp< - scalar_product_op, - const typename Lhs::ConstInnerVectorReturnType, - const Transpose >::InnerIterator Base; - typedef typename Lhs::Index Index; - Index m_outer; - public: - inline sparse_diagonal_product_inner_iterator_selector( - const SparseDiagonalProductType& expr, Index outer) - : Base(expr.lhs().innerVector(outer) .cwiseProduct(expr.rhs().diagonal().transpose()), 0), m_outer(outer) - {} - - inline Index outer() const { return m_outer; } - inline Index row() const { return m_outer; } -}; - -} // end namespace internal - -// SparseMatrixBase functions - -template -template -const SparseDiagonalProduct -SparseMatrixBase::operator*(const DiagonalBase &other) const -{ - return SparseDiagonalProduct(this->derived(), other.derived()); -} - -} // end namespace Eigen - -#endif // EIGEN_SPARSE_DIAGONAL_PRODUCT_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparseDot.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparseDot.h deleted file mode 100644 index db39c9aec..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparseDot.h +++ /dev/null @@ -1,101 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSE_DOT_H -#define EIGEN_SPARSE_DOT_H - -namespace Eigen { - -template -template -typename internal::traits::Scalar -SparseMatrixBase::dot(const MatrixBase& other) const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) - EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived) - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - - eigen_assert(size() == other.size()); - eigen_assert(other.size()>0 && "you are using a non initialized vector"); - - typename Derived::InnerIterator i(derived(),0); - Scalar res(0); - while (i) - { - res += numext::conj(i.value()) * other.coeff(i.index()); - ++i; - } - return res; -} - -template -template -typename internal::traits::Scalar -SparseMatrixBase::dot(const SparseMatrixBase& other) const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) - EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived) - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - - eigen_assert(size() == other.size()); - - typedef typename Derived::Nested Nested; - typedef typename OtherDerived::Nested OtherNested; - typedef typename internal::remove_all::type NestedCleaned; - typedef typename internal::remove_all::type OtherNestedCleaned; - - Nested nthis(derived()); - OtherNested nother(other.derived()); - - typename NestedCleaned::InnerIterator i(nthis,0); - typename OtherNestedCleaned::InnerIterator j(nother,0); - Scalar res(0); - while (i && j) - { - if (i.index()==j.index()) - { - res += numext::conj(i.value()) * j.value(); - ++i; ++j; - } - else if (i.index() -inline typename NumTraits::Scalar>::Real -SparseMatrixBase::squaredNorm() const -{ - return numext::real((*this).cwiseAbs2().sum()); -} - -template -inline typename NumTraits::Scalar>::Real -SparseMatrixBase::norm() const -{ - using std::sqrt; - return sqrt(squaredNorm()); -} - -template -inline typename NumTraits::Scalar>::Real -SparseMatrixBase::blueNorm() const -{ - return internal::blueNorm_impl(*this); -} -} // end namespace Eigen - -#endif // EIGEN_SPARSE_DOT_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparseFuzzy.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparseFuzzy.h deleted file mode 100644 index 45f36e9eb..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparseFuzzy.h +++ /dev/null @@ -1,26 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSE_FUZZY_H -#define EIGEN_SPARSE_FUZZY_H - -// template -// template -// bool SparseMatrixBase::isApprox( -// const OtherDerived& other, -// typename NumTraits::Real prec -// ) const -// { -// const typename internal::nested::type nested(derived()); -// const typename internal::nested::type otherNested(other.derived()); -// return (nested - otherNested).cwise().abs2().sum() -// <= prec * prec * (std::min)(nested.cwise().abs2().sum(), otherNested.cwise().abs2().sum()); -// } - -#endif // EIGEN_SPARSE_FUZZY_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparseMatrix.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparseMatrix.h deleted file mode 100644 index ba5e3a9b6..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparseMatrix.h +++ /dev/null @@ -1,1259 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSEMATRIX_H -#define EIGEN_SPARSEMATRIX_H - -namespace Eigen { - -/** \ingroup SparseCore_Module - * - * \class SparseMatrix - * - * \brief A versatible sparse matrix representation - * - * This class implements a more versatile variants of the common \em compressed row/column storage format. - * Each colmun's (resp. row) non zeros are stored as a pair of value with associated row (resp. colmiun) index. - * All the non zeros are stored in a single large buffer. Unlike the \em compressed format, there might be extra - * space inbetween the nonzeros of two successive colmuns (resp. rows) such that insertion of new non-zero - * can be done with limited memory reallocation and copies. - * - * A call to the function makeCompressed() turns the matrix into the standard \em compressed format - * compatible with many library. - * - * More details on this storage sceheme are given in the \ref TutorialSparse "manual pages". - * - * \tparam _Scalar the scalar type, i.e. the type of the coefficients - * \tparam _Options Union of bit flags controlling the storage scheme. Currently the only possibility - * is ColMajor or RowMajor. The default is 0 which means column-major. - * \tparam _Index the type of the indices. It has to be a \b signed type (e.g., short, int, std::ptrdiff_t). Default is \c int. - * - * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_SPARSEMATRIX_PLUGIN. - */ - -namespace internal { -template -struct traits > -{ - typedef _Scalar Scalar; - typedef _Index Index; - typedef Sparse StorageKind; - typedef MatrixXpr XprKind; - enum { - RowsAtCompileTime = Dynamic, - ColsAtCompileTime = Dynamic, - MaxRowsAtCompileTime = Dynamic, - MaxColsAtCompileTime = Dynamic, - Flags = _Options | NestByRefBit | LvalueBit, - CoeffReadCost = NumTraits::ReadCost, - SupportedAccessPatterns = InnerRandomAccessPattern - }; -}; - -template -struct traits, DiagIndex> > -{ - typedef SparseMatrix<_Scalar, _Options, _Index> MatrixType; - typedef typename nested::type MatrixTypeNested; - typedef typename remove_reference::type _MatrixTypeNested; - - typedef _Scalar Scalar; - typedef Dense StorageKind; - typedef _Index Index; - typedef MatrixXpr XprKind; - - enum { - RowsAtCompileTime = Dynamic, - ColsAtCompileTime = 1, - MaxRowsAtCompileTime = Dynamic, - MaxColsAtCompileTime = 1, - Flags = 0, - CoeffReadCost = _MatrixTypeNested::CoeffReadCost*10 - }; -}; - -} // end namespace internal - -template -class SparseMatrix - : public SparseMatrixBase > -{ - public: - EIGEN_SPARSE_PUBLIC_INTERFACE(SparseMatrix) - EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseMatrix, +=) - EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseMatrix, -=) - - typedef MappedSparseMatrix Map; - using Base::IsRowMajor; - typedef internal::CompressedStorage Storage; - enum { - Options = _Options - }; - - protected: - - typedef SparseMatrix TransposedSparseMatrix; - - Index m_outerSize; - Index m_innerSize; - Index* m_outerIndex; - Index* m_innerNonZeros; // optional, if null then the data is compressed - Storage m_data; - - Eigen::Map > innerNonZeros() { return Eigen::Map >(m_innerNonZeros, m_innerNonZeros?m_outerSize:0); } - const Eigen::Map > innerNonZeros() const { return Eigen::Map >(m_innerNonZeros, m_innerNonZeros?m_outerSize:0); } - - public: - - /** \returns whether \c *this is in compressed form. */ - inline bool isCompressed() const { return m_innerNonZeros==0; } - - /** \returns the number of rows of the matrix */ - inline Index rows() const { return IsRowMajor ? m_outerSize : m_innerSize; } - /** \returns the number of columns of the matrix */ - inline Index cols() const { return IsRowMajor ? m_innerSize : m_outerSize; } - - /** \returns the number of rows (resp. columns) of the matrix if the storage order column major (resp. row major) */ - inline Index innerSize() const { return m_innerSize; } - /** \returns the number of columns (resp. rows) of the matrix if the storage order column major (resp. row major) */ - inline Index outerSize() const { return m_outerSize; } - - /** \returns a const pointer to the array of values. - * This function is aimed at interoperability with other libraries. - * \sa innerIndexPtr(), outerIndexPtr() */ - inline const Scalar* valuePtr() const { return &m_data.value(0); } - /** \returns a non-const pointer to the array of values. - * This function is aimed at interoperability with other libraries. - * \sa innerIndexPtr(), outerIndexPtr() */ - inline Scalar* valuePtr() { return &m_data.value(0); } - - /** \returns a const pointer to the array of inner indices. - * This function is aimed at interoperability with other libraries. - * \sa valuePtr(), outerIndexPtr() */ - inline const Index* innerIndexPtr() const { return &m_data.index(0); } - /** \returns a non-const pointer to the array of inner indices. - * This function is aimed at interoperability with other libraries. - * \sa valuePtr(), outerIndexPtr() */ - inline Index* innerIndexPtr() { return &m_data.index(0); } - - /** \returns a const pointer to the array of the starting positions of the inner vectors. - * This function is aimed at interoperability with other libraries. - * \sa valuePtr(), innerIndexPtr() */ - inline const Index* outerIndexPtr() const { return m_outerIndex; } - /** \returns a non-const pointer to the array of the starting positions of the inner vectors. - * This function is aimed at interoperability with other libraries. - * \sa valuePtr(), innerIndexPtr() */ - inline Index* outerIndexPtr() { return m_outerIndex; } - - /** \returns a const pointer to the array of the number of non zeros of the inner vectors. - * This function is aimed at interoperability with other libraries. - * \warning it returns the null pointer 0 in compressed mode */ - inline const Index* innerNonZeroPtr() const { return m_innerNonZeros; } - /** \returns a non-const pointer to the array of the number of non zeros of the inner vectors. - * This function is aimed at interoperability with other libraries. - * \warning it returns the null pointer 0 in compressed mode */ - inline Index* innerNonZeroPtr() { return m_innerNonZeros; } - - /** \internal */ - inline Storage& data() { return m_data; } - /** \internal */ - inline const Storage& data() const { return m_data; } - - /** \returns the value of the matrix at position \a i, \a j - * This function returns Scalar(0) if the element is an explicit \em zero */ - inline Scalar coeff(Index row, Index col) const - { - eigen_assert(row>=0 && row=0 && col=0 && row=0 && col=start && "you probably called coeffRef on a non finalized matrix"); - if(end<=start) - return insert(row,col); - const Index p = m_data.searchLowerIndex(start,end-1,inner); - if((p=0 && row=0 && col::Constant(outerSize(), 2)); - } - return insertUncompressed(row,col); - } - - public: - - class InnerIterator; - class ReverseInnerIterator; - - /** Removes all non zeros but keep allocated memory */ - inline void setZero() - { - m_data.clear(); - memset(m_outerIndex, 0, (m_outerSize+1)*sizeof(Index)); - if(m_innerNonZeros) - memset(m_innerNonZeros, 0, (m_outerSize)*sizeof(Index)); - } - - /** \returns the number of non zero coefficients */ - inline Index nonZeros() const - { - if(m_innerNonZeros) - return innerNonZeros().sum(); - return static_cast(m_data.size()); - } - - /** Preallocates \a reserveSize non zeros. - * - * Precondition: the matrix must be in compressed mode. */ - inline void reserve(Index reserveSize) - { - eigen_assert(isCompressed() && "This function does not make sense in non compressed mode."); - m_data.reserve(reserveSize); - } - - #ifdef EIGEN_PARSED_BY_DOXYGEN - /** Preallocates \a reserveSize[\c j] non zeros for each column (resp. row) \c j. - * - * This function turns the matrix in non-compressed mode */ - template - inline void reserve(const SizesType& reserveSizes); - #else - template - inline void reserve(const SizesType& reserveSizes, const typename SizesType::value_type& enableif = typename SizesType::value_type()) - { - EIGEN_UNUSED_VARIABLE(enableif); - reserveInnerVectors(reserveSizes); - } - template - inline void reserve(const SizesType& reserveSizes, const typename SizesType::Scalar& enableif = - #if (!defined(_MSC_VER)) || (_MSC_VER>=1500) // MSVC 2005 fails to compile with this typename - typename - #endif - SizesType::Scalar()) - { - EIGEN_UNUSED_VARIABLE(enableif); - reserveInnerVectors(reserveSizes); - } - #endif // EIGEN_PARSED_BY_DOXYGEN - protected: - template - inline void reserveInnerVectors(const SizesType& reserveSizes) - { - if(isCompressed()) - { - std::size_t totalReserveSize = 0; - // turn the matrix into non-compressed mode - m_innerNonZeros = static_cast(std::malloc(m_outerSize * sizeof(Index))); - if (!m_innerNonZeros) internal::throw_std_bad_alloc(); - - // temporarily use m_innerSizes to hold the new starting points. - Index* newOuterIndex = m_innerNonZeros; - - Index count = 0; - for(Index j=0; j=0; --j) - { - Index innerNNZ = previousOuterIndex - m_outerIndex[j]; - for(Index i=innerNNZ-1; i>=0; --i) - { - m_data.index(newOuterIndex[j]+i) = m_data.index(m_outerIndex[j]+i); - m_data.value(newOuterIndex[j]+i) = m_data.value(m_outerIndex[j]+i); - } - previousOuterIndex = m_outerIndex[j]; - m_outerIndex[j] = newOuterIndex[j]; - m_innerNonZeros[j] = innerNNZ; - } - m_outerIndex[m_outerSize] = m_outerIndex[m_outerSize-1] + m_innerNonZeros[m_outerSize-1] + reserveSizes[m_outerSize-1]; - - m_data.resize(m_outerIndex[m_outerSize]); - } - else - { - Index* newOuterIndex = static_cast(std::malloc((m_outerSize+1)*sizeof(Index))); - if (!newOuterIndex) internal::throw_std_bad_alloc(); - - Index count = 0; - for(Index j=0; j(reserveSizes[j], alreadyReserved); - count += toReserve + m_innerNonZeros[j]; - } - newOuterIndex[m_outerSize] = count; - - m_data.resize(count); - for(Index j=m_outerSize-1; j>=0; --j) - { - Index offset = newOuterIndex[j] - m_outerIndex[j]; - if(offset>0) - { - Index innerNNZ = m_innerNonZeros[j]; - for(Index i=innerNNZ-1; i>=0; --i) - { - m_data.index(newOuterIndex[j]+i) = m_data.index(m_outerIndex[j]+i); - m_data.value(newOuterIndex[j]+i) = m_data.value(m_outerIndex[j]+i); - } - } - } - - std::swap(m_outerIndex, newOuterIndex); - std::free(newOuterIndex); - } - - } - public: - - //--- low level purely coherent filling --- - - /** \internal - * \returns a reference to the non zero coefficient at position \a row, \a col assuming that: - * - the nonzero does not already exist - * - the new coefficient is the last one according to the storage order - * - * Before filling a given inner vector you must call the statVec(Index) function. - * - * After an insertion session, you should call the finalize() function. - * - * \sa insert, insertBackByOuterInner, startVec */ - inline Scalar& insertBack(Index row, Index col) - { - return insertBackByOuterInner(IsRowMajor?row:col, IsRowMajor?col:row); - } - - /** \internal - * \sa insertBack, startVec */ - inline Scalar& insertBackByOuterInner(Index outer, Index inner) - { - eigen_assert(size_t(m_outerIndex[outer+1]) == m_data.size() && "Invalid ordered insertion (invalid outer index)"); - eigen_assert( (m_outerIndex[outer+1]-m_outerIndex[outer]==0 || m_data.index(m_data.size()-1)(m_data.size()); - Index i = m_outerSize; - // find the last filled column - while (i>=0 && m_outerIndex[i]==0) - --i; - ++i; - while (i<=m_outerSize) - { - m_outerIndex[i] = size; - ++i; - } - } - } - - //--- - - template - void setFromTriplets(const InputIterators& begin, const InputIterators& end); - - void sumupDuplicates(); - - //--- - - /** \internal - * same as insert(Index,Index) except that the indices are given relative to the storage order */ - Scalar& insertByOuterInner(Index j, Index i) - { - return insert(IsRowMajor ? j : i, IsRowMajor ? i : j); - } - - /** Turns the matrix into the \em compressed format. - */ - void makeCompressed() - { - if(isCompressed()) - return; - - Index oldStart = m_outerIndex[1]; - m_outerIndex[1] = m_innerNonZeros[0]; - for(Index j=1; j0) - { - for(Index k=0; k(std::malloc(m_outerSize * sizeof(Index))); - for (Index i = 0; i < m_outerSize; i++) - { - m_innerNonZeros[i] = m_outerIndex[i+1] - m_outerIndex[i]; - } - } - - /** Suppresses all nonzeros which are \b much \b smaller \b than \a reference under the tolerence \a epsilon */ - void prune(const Scalar& reference, const RealScalar& epsilon = NumTraits::dummy_precision()) - { - prune(default_prunning_func(reference,epsilon)); - } - - /** Turns the matrix into compressed format, and suppresses all nonzeros which do not satisfy the predicate \a keep. - * The functor type \a KeepFunc must implement the following function: - * \code - * bool operator() (const Index& row, const Index& col, const Scalar& value) const; - * \endcode - * \sa prune(Scalar,RealScalar) - */ - template - void prune(const KeepFunc& keep = KeepFunc()) - { - // TODO optimize the uncompressed mode to avoid moving and allocating the data twice - // TODO also implement a unit test - makeCompressed(); - - Index k = 0; - for(Index j=0; jrows() == rows && this->cols() == cols) return; - - // If one dimension is null, then there is nothing to be preserved - if(rows==0 || cols==0) return resize(rows,cols); - - Index innerChange = IsRowMajor ? cols - this->cols() : rows - this->rows(); - Index outerChange = IsRowMajor ? rows - this->rows() : cols - this->cols(); - Index newInnerSize = IsRowMajor ? cols : rows; - - // Deals with inner non zeros - if (m_innerNonZeros) - { - // Resize m_innerNonZeros - Index *newInnerNonZeros = static_cast(std::realloc(m_innerNonZeros, (m_outerSize + outerChange) * sizeof(Index))); - if (!newInnerNonZeros) internal::throw_std_bad_alloc(); - m_innerNonZeros = newInnerNonZeros; - - for(Index i=m_outerSize; i(std::malloc((m_outerSize+outerChange+1) * sizeof(Index))); - if (!m_innerNonZeros) internal::throw_std_bad_alloc(); - for(Index i = 0; i < m_outerSize; i++) - m_innerNonZeros[i] = m_outerIndex[i+1] - m_outerIndex[i]; - } - - // Change the m_innerNonZeros in case of a decrease of inner size - if (m_innerNonZeros && innerChange < 0) - { - for(Index i = 0; i < m_outerSize + (std::min)(outerChange, Index(0)); i++) - { - Index &n = m_innerNonZeros[i]; - Index start = m_outerIndex[i]; - while (n > 0 && m_data.index(start+n-1) >= newInnerSize) --n; - } - } - - m_innerSize = newInnerSize; - - // Re-allocate outer index structure if necessary - if (outerChange == 0) - return; - - Index *newOuterIndex = static_cast(std::realloc(m_outerIndex, (m_outerSize + outerChange + 1) * sizeof(Index))); - if (!newOuterIndex) internal::throw_std_bad_alloc(); - m_outerIndex = newOuterIndex; - if (outerChange > 0) - { - Index last = m_outerSize == 0 ? 0 : m_outerIndex[m_outerSize]; - for(Index i=m_outerSize; i(std::malloc((outerSize + 1) * sizeof(Index))); - if (!m_outerIndex) internal::throw_std_bad_alloc(); - - m_outerSize = outerSize; - } - if(m_innerNonZeros) - { - std::free(m_innerNonZeros); - m_innerNonZeros = 0; - } - memset(m_outerIndex, 0, (m_outerSize+1)*sizeof(Index)); - } - - /** \internal - * Resize the nonzero vector to \a size */ - void resizeNonZeros(Index size) - { - // TODO remove this function - m_data.resize(size); - } - - /** \returns a const expression of the diagonal coefficients */ - const Diagonal diagonal() const { return *this; } - - /** Default constructor yielding an empty \c 0 \c x \c 0 matrix */ - inline SparseMatrix() - : m_outerSize(-1), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) - { - check_template_parameters(); - resize(0, 0); - } - - /** Constructs a \a rows \c x \a cols empty matrix */ - inline SparseMatrix(Index rows, Index cols) - : m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) - { - check_template_parameters(); - resize(rows, cols); - } - - /** Constructs a sparse matrix from the sparse expression \a other */ - template - inline SparseMatrix(const SparseMatrixBase& other) - : m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) - { - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - check_template_parameters(); - *this = other.derived(); - } - - /** Constructs a sparse matrix from the sparse selfadjoint view \a other */ - template - inline SparseMatrix(const SparseSelfAdjointView& other) - : m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) - { - check_template_parameters(); - *this = other; - } - - /** Copy constructor (it performs a deep copy) */ - inline SparseMatrix(const SparseMatrix& other) - : Base(), m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) - { - check_template_parameters(); - *this = other.derived(); - } - - /** \brief Copy constructor with in-place evaluation */ - template - SparseMatrix(const ReturnByValue& other) - : Base(), m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) - { - check_template_parameters(); - initAssignment(other); - other.evalTo(*this); - } - - /** Swaps the content of two sparse matrices of the same type. - * This is a fast operation that simply swaps the underlying pointers and parameters. */ - inline void swap(SparseMatrix& other) - { - //EIGEN_DBG_SPARSE(std::cout << "SparseMatrix:: swap\n"); - std::swap(m_outerIndex, other.m_outerIndex); - std::swap(m_innerSize, other.m_innerSize); - std::swap(m_outerSize, other.m_outerSize); - std::swap(m_innerNonZeros, other.m_innerNonZeros); - m_data.swap(other.m_data); - } - - /** Sets *this to the identity matrix */ - inline void setIdentity() - { - eigen_assert(rows() == cols() && "ONLY FOR SQUARED MATRICES"); - this->m_data.resize(rows()); - Eigen::Map >(&this->m_data.index(0), rows()).setLinSpaced(0, rows()-1); - Eigen::Map >(&this->m_data.value(0), rows()).setOnes(); - Eigen::Map >(this->m_outerIndex, rows()+1).setLinSpaced(0, rows()); - } - inline SparseMatrix& operator=(const SparseMatrix& other) - { - if (other.isRValue()) - { - swap(other.const_cast_derived()); - } - else if(this!=&other) - { - initAssignment(other); - if(other.isCompressed()) - { - memcpy(m_outerIndex, other.m_outerIndex, (m_outerSize+1)*sizeof(Index)); - m_data = other.m_data; - } - else - { - Base::operator=(other); - } - } - return *this; - } - - #ifndef EIGEN_PARSED_BY_DOXYGEN - template - inline SparseMatrix& operator=(const SparseSparseProduct& product) - { return Base::operator=(product); } - - template - inline SparseMatrix& operator=(const ReturnByValue& other) - { - initAssignment(other); - return Base::operator=(other.derived()); - } - - template - inline SparseMatrix& operator=(const EigenBase& other) - { return Base::operator=(other.derived()); } - #endif - - template - EIGEN_DONT_INLINE SparseMatrix& operator=(const SparseMatrixBase& other); - - friend std::ostream & operator << (std::ostream & s, const SparseMatrix& m) - { - EIGEN_DBG_SPARSE( - s << "Nonzero entries:\n"; - if(m.isCompressed()) - for (Index i=0; i&>(m); - return s; - } - - /** Destructor */ - inline ~SparseMatrix() - { - std::free(m_outerIndex); - std::free(m_innerNonZeros); - } - -#ifndef EIGEN_PARSED_BY_DOXYGEN - /** Overloaded for performance */ - Scalar sum() const; -#endif - -# ifdef EIGEN_SPARSEMATRIX_PLUGIN -# include EIGEN_SPARSEMATRIX_PLUGIN -# endif - -protected: - - template - void initAssignment(const Other& other) - { - resize(other.rows(), other.cols()); - if(m_innerNonZeros) - { - std::free(m_innerNonZeros); - m_innerNonZeros = 0; - } - } - - /** \internal - * \sa insert(Index,Index) */ - EIGEN_DONT_INLINE Scalar& insertCompressed(Index row, Index col); - - /** \internal - * A vector object that is equal to 0 everywhere but v at the position i */ - class SingletonVector - { - Index m_index; - Index m_value; - public: - typedef Index value_type; - SingletonVector(Index i, Index v) - : m_index(i), m_value(v) - {} - - Index operator[](Index i) const { return i==m_index ? m_value : 0; } - }; - - /** \internal - * \sa insert(Index,Index) */ - EIGEN_DONT_INLINE Scalar& insertUncompressed(Index row, Index col); - -public: - /** \internal - * \sa insert(Index,Index) */ - EIGEN_STRONG_INLINE Scalar& insertBackUncompressed(Index row, Index col) - { - const Index outer = IsRowMajor ? row : col; - const Index inner = IsRowMajor ? col : row; - - eigen_assert(!isCompressed()); - eigen_assert(m_innerNonZeros[outer]<=(m_outerIndex[outer+1] - m_outerIndex[outer])); - - Index p = m_outerIndex[outer] + m_innerNonZeros[outer]++; - m_data.index(p) = inner; - return (m_data.value(p) = 0); - } - -private: - static void check_template_parameters() - { - EIGEN_STATIC_ASSERT(NumTraits::IsSigned,THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE); - EIGEN_STATIC_ASSERT((Options&(ColMajor|RowMajor))==Options,INVALID_MATRIX_TEMPLATE_PARAMETERS); - } - - struct default_prunning_func { - default_prunning_func(const Scalar& ref, const RealScalar& eps) : reference(ref), epsilon(eps) {} - inline bool operator() (const Index&, const Index&, const Scalar& value) const - { - return !internal::isMuchSmallerThan(value, reference, epsilon); - } - Scalar reference; - RealScalar epsilon; - }; -}; - -template -class SparseMatrix::InnerIterator -{ - public: - InnerIterator(const SparseMatrix& mat, Index outer) - : m_values(mat.valuePtr()), m_indices(mat.innerIndexPtr()), m_outer(outer), m_id(mat.m_outerIndex[outer]) - { - if(mat.isCompressed()) - m_end = mat.m_outerIndex[outer+1]; - else - m_end = m_id + mat.m_innerNonZeros[outer]; - } - - inline InnerIterator& operator++() { m_id++; return *this; } - - inline const Scalar& value() const { return m_values[m_id]; } - inline Scalar& valueRef() { return const_cast(m_values[m_id]); } - - inline Index index() const { return m_indices[m_id]; } - inline Index outer() const { return m_outer; } - inline Index row() const { return IsRowMajor ? m_outer : index(); } - inline Index col() const { return IsRowMajor ? index() : m_outer; } - - inline operator bool() const { return (m_id < m_end); } - - protected: - const Scalar* m_values; - const Index* m_indices; - const Index m_outer; - Index m_id; - Index m_end; -}; - -template -class SparseMatrix::ReverseInnerIterator -{ - public: - ReverseInnerIterator(const SparseMatrix& mat, Index outer) - : m_values(mat.valuePtr()), m_indices(mat.innerIndexPtr()), m_outer(outer), m_start(mat.m_outerIndex[outer]) - { - if(mat.isCompressed()) - m_id = mat.m_outerIndex[outer+1]; - else - m_id = m_start + mat.m_innerNonZeros[outer]; - } - - inline ReverseInnerIterator& operator--() { --m_id; return *this; } - - inline const Scalar& value() const { return m_values[m_id-1]; } - inline Scalar& valueRef() { return const_cast(m_values[m_id-1]); } - - inline Index index() const { return m_indices[m_id-1]; } - inline Index outer() const { return m_outer; } - inline Index row() const { return IsRowMajor ? m_outer : index(); } - inline Index col() const { return IsRowMajor ? index() : m_outer; } - - inline operator bool() const { return (m_id > m_start); } - - protected: - const Scalar* m_values; - const Index* m_indices; - const Index m_outer; - Index m_id; - const Index m_start; -}; - -namespace internal { - -template -void set_from_triplets(const InputIterator& begin, const InputIterator& end, SparseMatrixType& mat, int Options = 0) -{ - EIGEN_UNUSED_VARIABLE(Options); - enum { IsRowMajor = SparseMatrixType::IsRowMajor }; - typedef typename SparseMatrixType::Scalar Scalar; - typedef typename SparseMatrixType::Index Index; - SparseMatrix trMat(mat.rows(),mat.cols()); - - if(begin!=end) - { - // pass 1: count the nnz per inner-vector - Matrix wi(trMat.outerSize()); - wi.setZero(); - for(InputIterator it(begin); it!=end; ++it) - { - eigen_assert(it->row()>=0 && it->row()col()>=0 && it->col()col() : it->row())++; - } - - // pass 2: insert all the elements into trMat - trMat.reserve(wi); - for(InputIterator it(begin); it!=end; ++it) - trMat.insertBackUncompressed(it->row(),it->col()) = it->value(); - - // pass 3: - trMat.sumupDuplicates(); - } - - // pass 4: transposed copy -> implicit sorting - mat = trMat; -} - -} - - -/** Fill the matrix \c *this with the list of \em triplets defined by the iterator range \a begin - \a end. - * - * A \em triplet is a tuple (i,j,value) defining a non-zero element. - * The input list of triplets does not have to be sorted, and can contains duplicated elements. - * In any case, the result is a \b sorted and \b compressed sparse matrix where the duplicates have been summed up. - * This is a \em O(n) operation, with \em n the number of triplet elements. - * The initial contents of \c *this is destroyed. - * The matrix \c *this must be properly resized beforehand using the SparseMatrix(Index,Index) constructor, - * or the resize(Index,Index) method. The sizes are not extracted from the triplet list. - * - * The \a InputIterators value_type must provide the following interface: - * \code - * Scalar value() const; // the value - * Scalar row() const; // the row index i - * Scalar col() const; // the column index j - * \endcode - * See for instance the Eigen::Triplet template class. - * - * Here is a typical usage example: - * \code - typedef Triplet T; - std::vector tripletList; - triplets.reserve(estimation_of_entries); - for(...) - { - // ... - tripletList.push_back(T(i,j,v_ij)); - } - SparseMatrixType m(rows,cols); - m.setFromTriplets(tripletList.begin(), tripletList.end()); - // m is ready to go! - * \endcode - * - * \warning The list of triplets is read multiple times (at least twice). Therefore, it is not recommended to define - * an abstract iterator over a complex data-structure that would be expensive to evaluate. The triplets should rather - * be explicitely stored into a std::vector for instance. - */ -template -template -void SparseMatrix::setFromTriplets(const InputIterators& begin, const InputIterators& end) -{ - internal::set_from_triplets(begin, end, *this); -} - -/** \internal */ -template -void SparseMatrix::sumupDuplicates() -{ - eigen_assert(!isCompressed()); - // TODO, in practice we should be able to use m_innerNonZeros for that task - Matrix wi(innerSize()); - wi.fill(-1); - Index count = 0; - // for each inner-vector, wi[inner_index] will hold the position of first element into the index/value buffers - for(Index j=0; j=start) - { - // we already meet this entry => accumulate it - m_data.value(wi(i)) += m_data.value(k); - } - else - { - m_data.value(count) = m_data.value(k); - m_data.index(count) = m_data.index(k); - wi(i) = count; - ++count; - } - } - m_outerIndex[j] = start; - } - m_outerIndex[m_outerSize] = count; - - // turn the matrix into compressed form - std::free(m_innerNonZeros); - m_innerNonZeros = 0; - m_data.resize(m_outerIndex[m_outerSize]); -} - -template -template -EIGEN_DONT_INLINE SparseMatrix& SparseMatrix::operator=(const SparseMatrixBase& other) -{ - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - - const bool needToTranspose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); - if (needToTranspose) - { - // two passes algorithm: - // 1 - compute the number of coeffs per dest inner vector - // 2 - do the actual copy/eval - // Since each coeff of the rhs has to be evaluated twice, let's evaluate it if needed - typedef typename internal::nested::type OtherCopy; - typedef typename internal::remove_all::type _OtherCopy; - OtherCopy otherCopy(other.derived()); - - SparseMatrix dest(other.rows(),other.cols()); - Eigen::Map > (dest.m_outerIndex,dest.outerSize()).setZero(); - - // pass 1 - // FIXME the above copy could be merged with that pass - for (Index j=0; j positions(dest.outerSize()); - for (Index j=0; jswap(dest); - return *this; - } - else - { - if(other.isRValue()) - initAssignment(other.derived()); - // there is no special optimization - return Base::operator=(other.derived()); - } -} - -template -EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& SparseMatrix<_Scalar,_Options,_Index>::insertUncompressed(Index row, Index col) -{ - eigen_assert(!isCompressed()); - - const Index outer = IsRowMajor ? row : col; - const Index inner = IsRowMajor ? col : row; - - Index room = m_outerIndex[outer+1] - m_outerIndex[outer]; - Index innerNNZ = m_innerNonZeros[outer]; - if(innerNNZ>=room) - { - // this inner vector is full, we need to reallocate the whole buffer :( - reserve(SingletonVector(outer,std::max(2,innerNNZ))); - } - - Index startId = m_outerIndex[outer]; - Index p = startId + m_innerNonZeros[outer]; - while ( (p > startId) && (m_data.index(p-1) > inner) ) - { - m_data.index(p) = m_data.index(p-1); - m_data.value(p) = m_data.value(p-1); - --p; - } - eigen_assert((p<=startId || m_data.index(p-1)!=inner) && "you cannot insert an element that already exist, you must call coeffRef to this end"); - - m_innerNonZeros[outer]++; - - m_data.index(p) = inner; - return (m_data.value(p) = 0); -} - -template -EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& SparseMatrix<_Scalar,_Options,_Index>::insertCompressed(Index row, Index col) -{ - eigen_assert(isCompressed()); - - const Index outer = IsRowMajor ? row : col; - const Index inner = IsRowMajor ? col : row; - - Index previousOuter = outer; - if (m_outerIndex[outer+1]==0) - { - // we start a new inner vector - while (previousOuter>=0 && m_outerIndex[previousOuter]==0) - { - m_outerIndex[previousOuter] = static_cast(m_data.size()); - --previousOuter; - } - m_outerIndex[outer+1] = m_outerIndex[outer]; - } - - // here we have to handle the tricky case where the outerIndex array - // starts with: [ 0 0 0 0 0 1 ...] and we are inserted in, e.g., - // the 2nd inner vector... - bool isLastVec = (!(previousOuter==-1 && m_data.size()!=0)) - && (size_t(m_outerIndex[outer+1]) == m_data.size()); - - size_t startId = m_outerIndex[outer]; - // FIXME let's make sure sizeof(long int) == sizeof(size_t) - size_t p = m_outerIndex[outer+1]; - ++m_outerIndex[outer+1]; - - double reallocRatio = 1; - if (m_data.allocatedSize()<=m_data.size()) - { - // if there is no preallocated memory, let's reserve a minimum of 32 elements - if (m_data.size()==0) - { - m_data.reserve(32); - } - else - { - // we need to reallocate the data, to reduce multiple reallocations - // we use a smart resize algorithm based on the current filling ratio - // in addition, we use double to avoid integers overflows - double nnzEstimate = double(m_outerIndex[outer])*double(m_outerSize)/double(outer+1); - reallocRatio = (nnzEstimate-double(m_data.size()))/double(m_data.size()); - // furthermore we bound the realloc ratio to: - // 1) reduce multiple minor realloc when the matrix is almost filled - // 2) avoid to allocate too much memory when the matrix is almost empty - reallocRatio = (std::min)((std::max)(reallocRatio,1.5),8.); - } - } - m_data.resize(m_data.size()+1,reallocRatio); - - if (!isLastVec) - { - if (previousOuter==-1) - { - // oops wrong guess. - // let's correct the outer offsets - for (Index k=0; k<=(outer+1); ++k) - m_outerIndex[k] = 0; - Index k=outer+1; - while(m_outerIndex[k]==0) - m_outerIndex[k++] = 1; - while (k<=m_outerSize && m_outerIndex[k]!=0) - m_outerIndex[k++]++; - p = 0; - --k; - k = m_outerIndex[k]-1; - while (k>0) - { - m_data.index(k) = m_data.index(k-1); - m_data.value(k) = m_data.value(k-1); - k--; - } - } - else - { - // we are not inserting into the last inner vec - // update outer indices: - Index j = outer+2; - while (j<=m_outerSize && m_outerIndex[j]!=0) - m_outerIndex[j++]++; - --j; - // shift data of last vecs: - Index k = m_outerIndex[j]-1; - while (k>=Index(p)) - { - m_data.index(k) = m_data.index(k-1); - m_data.value(k) = m_data.value(k-1); - k--; - } - } - } - - while ( (p > startId) && (m_data.index(p-1) > inner) ) - { - m_data.index(p) = m_data.index(p-1); - m_data.value(p) = m_data.value(p-1); - --p; - } - - m_data.index(p) = inner; - return (m_data.value(p) = 0); -} - -} // end namespace Eigen - -#endif // EIGEN_SPARSEMATRIX_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparseMatrixBase.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparseMatrixBase.h deleted file mode 100644 index bbcf7fb1c..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparseMatrixBase.h +++ /dev/null @@ -1,451 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2011 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSEMATRIXBASE_H -#define EIGEN_SPARSEMATRIXBASE_H - -namespace Eigen { - -/** \ingroup SparseCore_Module - * - * \class SparseMatrixBase - * - * \brief Base class of any sparse matrices or sparse expressions - * - * \tparam Derived - * - * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_SPARSEMATRIXBASE_PLUGIN. - */ -template class SparseMatrixBase : public EigenBase -{ - public: - - typedef typename internal::traits::Scalar Scalar; - typedef typename internal::packet_traits::type PacketScalar; - typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; - typedef typename internal::add_const_on_value_type_if_arithmetic< - typename internal::packet_traits::type - >::type PacketReturnType; - - typedef SparseMatrixBase StorageBaseType; - typedef EigenBase Base; - - template - Derived& operator=(const EigenBase &other) - { - other.derived().evalTo(derived()); - return derived(); - } - - enum { - - RowsAtCompileTime = internal::traits::RowsAtCompileTime, - /**< The number of rows at compile-time. This is just a copy of the value provided - * by the \a Derived type. If a value is not known at compile-time, - * it is set to the \a Dynamic constant. - * \sa MatrixBase::rows(), MatrixBase::cols(), ColsAtCompileTime, SizeAtCompileTime */ - - ColsAtCompileTime = internal::traits::ColsAtCompileTime, - /**< The number of columns at compile-time. This is just a copy of the value provided - * by the \a Derived type. If a value is not known at compile-time, - * it is set to the \a Dynamic constant. - * \sa MatrixBase::rows(), MatrixBase::cols(), RowsAtCompileTime, SizeAtCompileTime */ - - - SizeAtCompileTime = (internal::size_at_compile_time::RowsAtCompileTime, - internal::traits::ColsAtCompileTime>::ret), - /**< This is equal to the number of coefficients, i.e. the number of - * rows times the number of columns, or to \a Dynamic if this is not - * known at compile-time. \sa RowsAtCompileTime, ColsAtCompileTime */ - - MaxRowsAtCompileTime = RowsAtCompileTime, - MaxColsAtCompileTime = ColsAtCompileTime, - - MaxSizeAtCompileTime = (internal::size_at_compile_time::ret), - - IsVectorAtCompileTime = RowsAtCompileTime == 1 || ColsAtCompileTime == 1, - /**< This is set to true if either the number of rows or the number of - * columns is known at compile-time to be equal to 1. Indeed, in that case, - * we are dealing with a column-vector (if there is only one column) or with - * a row-vector (if there is only one row). */ - - Flags = internal::traits::Flags, - /**< This stores expression \ref flags flags which may or may not be inherited by new expressions - * constructed from this one. See the \ref flags "list of flags". - */ - - CoeffReadCost = internal::traits::CoeffReadCost, - /**< This is a rough measure of how expensive it is to read one coefficient from - * this expression. - */ - - IsRowMajor = Flags&RowMajorBit ? 1 : 0, - - InnerSizeAtCompileTime = int(IsVectorAtCompileTime) ? int(SizeAtCompileTime) - : int(IsRowMajor) ? int(ColsAtCompileTime) : int(RowsAtCompileTime), - - #ifndef EIGEN_PARSED_BY_DOXYGEN - _HasDirectAccess = (int(Flags)&DirectAccessBit) ? 1 : 0 // workaround sunCC - #endif - }; - - /** \internal the return type of MatrixBase::adjoint() */ - typedef typename internal::conditional::IsComplex, - CwiseUnaryOp, Eigen::Transpose >, - Transpose - >::type AdjointReturnType; - - - typedef SparseMatrix PlainObject; - - -#ifndef EIGEN_PARSED_BY_DOXYGEN - /** This is the "real scalar" type; if the \a Scalar type is already real numbers - * (e.g. int, float or double) then \a RealScalar is just the same as \a Scalar. If - * \a Scalar is \a std::complex then RealScalar is \a T. - * - * \sa class NumTraits - */ - typedef typename NumTraits::Real RealScalar; - - /** \internal the return type of coeff() - */ - typedef typename internal::conditional<_HasDirectAccess, const Scalar&, Scalar>::type CoeffReturnType; - - /** \internal Represents a matrix with all coefficients equal to one another*/ - typedef CwiseNullaryOp,Matrix > ConstantReturnType; - - /** type of the equivalent square matrix */ - typedef Matrix SquareMatrixType; - - inline const Derived& derived() const { return *static_cast(this); } - inline Derived& derived() { return *static_cast(this); } - inline Derived& const_cast_derived() const - { return *static_cast(const_cast(this)); } -#endif // not EIGEN_PARSED_BY_DOXYGEN - -#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::SparseMatrixBase -# include "../plugins/CommonCwiseUnaryOps.h" -# include "../plugins/CommonCwiseBinaryOps.h" -# include "../plugins/MatrixCwiseUnaryOps.h" -# include "../plugins/MatrixCwiseBinaryOps.h" -# include "../plugins/BlockMethods.h" -# ifdef EIGEN_SPARSEMATRIXBASE_PLUGIN -# include EIGEN_SPARSEMATRIXBASE_PLUGIN -# endif -# undef EIGEN_CURRENT_STORAGE_BASE_CLASS -#undef EIGEN_CURRENT_STORAGE_BASE_CLASS - - /** \returns the number of rows. \sa cols() */ - inline Index rows() const { return derived().rows(); } - /** \returns the number of columns. \sa rows() */ - inline Index cols() const { return derived().cols(); } - /** \returns the number of coefficients, which is \a rows()*cols(). - * \sa rows(), cols(). */ - inline Index size() const { return rows() * cols(); } - /** \returns the number of nonzero coefficients which is in practice the number - * of stored coefficients. */ - inline Index nonZeros() const { return derived().nonZeros(); } - /** \returns true if either the number of rows or the number of columns is equal to 1. - * In other words, this function returns - * \code rows()==1 || cols()==1 \endcode - * \sa rows(), cols(), IsVectorAtCompileTime. */ - inline bool isVector() const { return rows()==1 || cols()==1; } - /** \returns the size of the storage major dimension, - * i.e., the number of columns for a columns major matrix, and the number of rows otherwise */ - Index outerSize() const { return (int(Flags)&RowMajorBit) ? this->rows() : this->cols(); } - /** \returns the size of the inner dimension according to the storage order, - * i.e., the number of rows for a columns major matrix, and the number of cols otherwise */ - Index innerSize() const { return (int(Flags)&RowMajorBit) ? this->cols() : this->rows(); } - - bool isRValue() const { return m_isRValue; } - Derived& markAsRValue() { m_isRValue = true; return derived(); } - - SparseMatrixBase() : m_isRValue(false) { /* TODO check flags */ } - - - template - Derived& operator=(const ReturnByValue& other) - { - other.evalTo(derived()); - return derived(); - } - - - template - inline Derived& operator=(const SparseMatrixBase& other) - { - return assign(other.derived()); - } - - inline Derived& operator=(const Derived& other) - { -// if (other.isRValue()) -// derived().swap(other.const_cast_derived()); -// else - return assign(other.derived()); - } - - protected: - - template - inline Derived& assign(const OtherDerived& other) - { - const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); - const Index outerSize = (int(OtherDerived::Flags) & RowMajorBit) ? other.rows() : other.cols(); - if ((!transpose) && other.isRValue()) - { - // eval without temporary - derived().resize(other.rows(), other.cols()); - derived().setZero(); - derived().reserve((std::max)(this->rows(),this->cols())*2); - for (Index j=0; j - inline void assignGeneric(const OtherDerived& other) - { - //const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); - eigen_assert(( ((internal::traits::SupportedAccessPatterns&OuterRandomAccessPattern)==OuterRandomAccessPattern) || - (!((Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit)))) && - "the transpose operation is supposed to be handled in SparseMatrix::operator="); - - enum { Flip = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit) }; - - const Index outerSize = other.outerSize(); - //typedef typename internal::conditional, Derived>::type TempType; - // thanks to shallow copies, we always eval to a tempary - Derived temp(other.rows(), other.cols()); - - temp.reserve((std::max)(this->rows(),this->cols())*2); - for (Index j=0; j - inline Derived& operator=(const SparseSparseProduct& product); - - friend std::ostream & operator << (std::ostream & s, const SparseMatrixBase& m) - { - typedef typename Derived::Nested Nested; - typedef typename internal::remove_all::type NestedCleaned; - - if (Flags&RowMajorBit) - { - const Nested nm(m.derived()); - for (Index row=0; row trans = m; - s << static_cast >&>(trans); - } - } - return s; - } - - template - Derived& operator+=(const SparseMatrixBase& other); - template - Derived& operator-=(const SparseMatrixBase& other); - - Derived& operator*=(const Scalar& other); - Derived& operator/=(const Scalar& other); - - #define EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE \ - CwiseBinaryOp< \ - internal::scalar_product_op< \ - typename internal::scalar_product_traits< \ - typename internal::traits::Scalar, \ - typename internal::traits::Scalar \ - >::ReturnType \ - >, \ - const Derived, \ - const OtherDerived \ - > - - template - EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE - cwiseProduct(const MatrixBase &other) const; - - // sparse * sparse - template - const typename SparseSparseProductReturnType::Type - operator*(const SparseMatrixBase &other) const; - - // sparse * diagonal - template - const SparseDiagonalProduct - operator*(const DiagonalBase &other) const; - - // diagonal * sparse - template friend - const SparseDiagonalProduct - operator*(const DiagonalBase &lhs, const SparseMatrixBase& rhs) - { return SparseDiagonalProduct(lhs.derived(), rhs.derived()); } - - /** dense * sparse (return a dense object unless it is an outer product) */ - template friend - const typename DenseSparseProductReturnType::Type - operator*(const MatrixBase& lhs, const Derived& rhs) - { return typename DenseSparseProductReturnType::Type(lhs.derived(),rhs); } - - /** sparse * dense (returns a dense object unless it is an outer product) */ - template - const typename SparseDenseProductReturnType::Type - operator*(const MatrixBase &other) const; - - /** \returns an expression of P H P^-1 where H is the matrix represented by \c *this */ - SparseSymmetricPermutationProduct twistedBy(const PermutationMatrix& perm) const - { - return SparseSymmetricPermutationProduct(derived(), perm); - } - - template - Derived& operator*=(const SparseMatrixBase& other); - - #ifdef EIGEN2_SUPPORT - // deprecated - template - typename internal::plain_matrix_type_column_major::type - solveTriangular(const MatrixBase& other) const; - - // deprecated - template - void solveTriangularInPlace(MatrixBase& other) const; - #endif // EIGEN2_SUPPORT - - template - inline const SparseTriangularView triangularView() const; - - template inline const SparseSelfAdjointView selfadjointView() const; - template inline SparseSelfAdjointView selfadjointView(); - - template Scalar dot(const MatrixBase& other) const; - template Scalar dot(const SparseMatrixBase& other) const; - RealScalar squaredNorm() const; - RealScalar norm() const; - RealScalar blueNorm() const; - - Transpose transpose() { return derived(); } - const Transpose transpose() const { return derived(); } - const AdjointReturnType adjoint() const { return transpose(); } - - // inner-vector - typedef Block InnerVectorReturnType; - typedef Block ConstInnerVectorReturnType; - InnerVectorReturnType innerVector(Index outer); - const ConstInnerVectorReturnType innerVector(Index outer) const; - - // set of inner-vectors - Block innerVectors(Index outerStart, Index outerSize); - const Block innerVectors(Index outerStart, Index outerSize) const; - - /** \internal use operator= */ - template - void evalTo(MatrixBase& dst) const - { - dst.setZero(); - for (Index j=0; j toDense() const - { - return derived(); - } - - template - bool isApprox(const SparseMatrixBase& other, - const RealScalar& prec = NumTraits::dummy_precision()) const - { return toDense().isApprox(other.toDense(),prec); } - - template - bool isApprox(const MatrixBase& other, - const RealScalar& prec = NumTraits::dummy_precision()) const - { return toDense().isApprox(other,prec); } - - /** \returns the matrix or vector obtained by evaluating this expression. - * - * Notice that in the case of a plain matrix or vector (not an expression) this function just returns - * a const reference, in order to avoid a useless copy. - */ - inline const typename internal::eval::type eval() const - { return typename internal::eval::type(derived()); } - - Scalar sum() const; - - protected: - - bool m_isRValue; -}; - -} // end namespace Eigen - -#endif // EIGEN_SPARSEMATRIXBASE_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparsePermutation.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparsePermutation.h deleted file mode 100644 index b85be93f6..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparsePermutation.h +++ /dev/null @@ -1,148 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2012 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSE_PERMUTATION_H -#define EIGEN_SPARSE_PERMUTATION_H - -// This file implements sparse * permutation products - -namespace Eigen { - -namespace internal { - -template -struct traits > -{ - typedef typename remove_all::type MatrixTypeNestedCleaned; - typedef typename MatrixTypeNestedCleaned::Scalar Scalar; - typedef typename MatrixTypeNestedCleaned::Index Index; - enum { - SrcStorageOrder = MatrixTypeNestedCleaned::Flags&RowMajorBit ? RowMajor : ColMajor, - MoveOuter = SrcStorageOrder==RowMajor ? Side==OnTheLeft : Side==OnTheRight - }; - - typedef typename internal::conditional, - SparseMatrix >::type ReturnType; -}; - -template -struct permut_sparsematrix_product_retval - : public ReturnByValue > -{ - typedef typename remove_all::type MatrixTypeNestedCleaned; - typedef typename MatrixTypeNestedCleaned::Scalar Scalar; - typedef typename MatrixTypeNestedCleaned::Index Index; - - enum { - SrcStorageOrder = MatrixTypeNestedCleaned::Flags&RowMajorBit ? RowMajor : ColMajor, - MoveOuter = SrcStorageOrder==RowMajor ? Side==OnTheLeft : Side==OnTheRight - }; - - permut_sparsematrix_product_retval(const PermutationType& perm, const MatrixType& matrix) - : m_permutation(perm), m_matrix(matrix) - {} - - inline int rows() const { return m_matrix.rows(); } - inline int cols() const { return m_matrix.cols(); } - - template inline void evalTo(Dest& dst) const - { - if(MoveOuter) - { - SparseMatrix tmp(m_matrix.rows(), m_matrix.cols()); - Matrix sizes(m_matrix.outerSize()); - for(Index j=0; j tmp(m_matrix.rows(), m_matrix.cols()); - Matrix sizes(tmp.outerSize()); - sizes.setZero(); - PermutationMatrix perm; - if((Side==OnTheLeft) ^ Transposed) - perm = m_permutation; - else - perm = m_permutation.transpose(); - - for(Index j=0; j -inline const internal::permut_sparsematrix_product_retval, SparseDerived, OnTheRight, false> -operator*(const SparseMatrixBase& matrix, const PermutationBase& perm) -{ - return internal::permut_sparsematrix_product_retval, SparseDerived, OnTheRight, false>(perm, matrix.derived()); -} - -/** \returns the matrix with the permutation applied to the rows - */ -template -inline const internal::permut_sparsematrix_product_retval, SparseDerived, OnTheLeft, false> -operator*( const PermutationBase& perm, const SparseMatrixBase& matrix) -{ - return internal::permut_sparsematrix_product_retval, SparseDerived, OnTheLeft, false>(perm, matrix.derived()); -} - - - -/** \returns the matrix with the inverse permutation applied to the columns. - */ -template -inline const internal::permut_sparsematrix_product_retval, SparseDerived, OnTheRight, true> -operator*(const SparseMatrixBase& matrix, const Transpose >& tperm) -{ - return internal::permut_sparsematrix_product_retval, SparseDerived, OnTheRight, true>(tperm.nestedPermutation(), matrix.derived()); -} - -/** \returns the matrix with the inverse permutation applied to the rows. - */ -template -inline const internal::permut_sparsematrix_product_retval, SparseDerived, OnTheLeft, true> -operator*(const Transpose >& tperm, const SparseMatrixBase& matrix) -{ - return internal::permut_sparsematrix_product_retval, SparseDerived, OnTheLeft, true>(tperm.nestedPermutation(), matrix.derived()); -} - -} // end namespace Eigen - -#endif // EIGEN_SPARSE_SELFADJOINTVIEW_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparseProduct.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparseProduct.h deleted file mode 100644 index cf7663070..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparseProduct.h +++ /dev/null @@ -1,188 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSEPRODUCT_H -#define EIGEN_SPARSEPRODUCT_H - -namespace Eigen { - -template -struct SparseSparseProductReturnType -{ - typedef typename internal::traits::Scalar Scalar; - typedef typename internal::traits::Index Index; - enum { - LhsRowMajor = internal::traits::Flags & RowMajorBit, - RhsRowMajor = internal::traits::Flags & RowMajorBit, - TransposeRhs = (!LhsRowMajor) && RhsRowMajor, - TransposeLhs = LhsRowMajor && (!RhsRowMajor) - }; - - typedef typename internal::conditional, - typename internal::nested::type>::type LhsNested; - - typedef typename internal::conditional, - typename internal::nested::type>::type RhsNested; - - typedef SparseSparseProduct Type; -}; - -namespace internal { -template -struct traits > -{ - typedef MatrixXpr XprKind; - // clean the nested types: - typedef typename remove_all::type _LhsNested; - typedef typename remove_all::type _RhsNested; - typedef typename _LhsNested::Scalar Scalar; - typedef typename promote_index_type::Index, - typename traits<_RhsNested>::Index>::type Index; - - enum { - LhsCoeffReadCost = _LhsNested::CoeffReadCost, - RhsCoeffReadCost = _RhsNested::CoeffReadCost, - LhsFlags = _LhsNested::Flags, - RhsFlags = _RhsNested::Flags, - - RowsAtCompileTime = _LhsNested::RowsAtCompileTime, - ColsAtCompileTime = _RhsNested::ColsAtCompileTime, - MaxRowsAtCompileTime = _LhsNested::MaxRowsAtCompileTime, - MaxColsAtCompileTime = _RhsNested::MaxColsAtCompileTime, - - InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(_LhsNested::ColsAtCompileTime, _RhsNested::RowsAtCompileTime), - - EvalToRowMajor = (RhsFlags & LhsFlags & RowMajorBit), - - RemovedBits = ~(EvalToRowMajor ? 0 : RowMajorBit), - - Flags = (int(LhsFlags | RhsFlags) & HereditaryBits & RemovedBits) - | EvalBeforeAssigningBit - | EvalBeforeNestingBit, - - CoeffReadCost = Dynamic - }; - - typedef Sparse StorageKind; -}; - -} // end namespace internal - -template -class SparseSparseProduct : internal::no_assignment_operator, - public SparseMatrixBase > -{ - public: - - typedef SparseMatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(SparseSparseProduct) - - private: - - typedef typename internal::traits::_LhsNested _LhsNested; - typedef typename internal::traits::_RhsNested _RhsNested; - - public: - - template - EIGEN_STRONG_INLINE SparseSparseProduct(const Lhs& lhs, const Rhs& rhs) - : m_lhs(lhs), m_rhs(rhs), m_tolerance(0), m_conservative(true) - { - init(); - } - - template - EIGEN_STRONG_INLINE SparseSparseProduct(const Lhs& lhs, const Rhs& rhs, const RealScalar& tolerance) - : m_lhs(lhs), m_rhs(rhs), m_tolerance(tolerance), m_conservative(false) - { - init(); - } - - SparseSparseProduct pruned(const Scalar& reference = 0, const RealScalar& epsilon = NumTraits::dummy_precision()) const - { - using std::abs; - return SparseSparseProduct(m_lhs,m_rhs,abs(reference)*epsilon); - } - - template - void evalTo(Dest& result) const - { - if(m_conservative) - internal::conservative_sparse_sparse_product_selector<_LhsNested, _RhsNested, Dest>::run(lhs(),rhs(),result); - else - internal::sparse_sparse_product_with_pruning_selector<_LhsNested, _RhsNested, Dest>::run(lhs(),rhs(),result,m_tolerance); - } - - EIGEN_STRONG_INLINE Index rows() const { return m_lhs.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_rhs.cols(); } - - EIGEN_STRONG_INLINE const _LhsNested& lhs() const { return m_lhs; } - EIGEN_STRONG_INLINE const _RhsNested& rhs() const { return m_rhs; } - - protected: - void init() - { - eigen_assert(m_lhs.cols() == m_rhs.rows()); - - enum { - ProductIsValid = _LhsNested::ColsAtCompileTime==Dynamic - || _RhsNested::RowsAtCompileTime==Dynamic - || int(_LhsNested::ColsAtCompileTime)==int(_RhsNested::RowsAtCompileTime), - AreVectors = _LhsNested::IsVectorAtCompileTime && _RhsNested::IsVectorAtCompileTime, - SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(_LhsNested,_RhsNested) - }; - // note to the lost user: - // * for a dot product use: v1.dot(v2) - // * for a coeff-wise product use: v1.cwise()*v2 - EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), - INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) - EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), - INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) - EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) - } - - LhsNested m_lhs; - RhsNested m_rhs; - RealScalar m_tolerance; - bool m_conservative; -}; - -// sparse = sparse * sparse -template -template -inline Derived& SparseMatrixBase::operator=(const SparseSparseProduct& product) -{ - product.evalTo(derived()); - return derived(); -} - -/** \returns an expression of the product of two sparse matrices. - * By default a conservative product preserving the symbolic non zeros is performed. - * The automatic pruning of the small values can be achieved by calling the pruned() function - * in which case a totally different product algorithm is employed: - * \code - * C = (A*B).pruned(); // supress numerical zeros (exact) - * C = (A*B).pruned(ref); - * C = (A*B).pruned(ref,epsilon); - * \endcode - * where \c ref is a meaningful non zero reference value. - * */ -template -template -inline const typename SparseSparseProductReturnType::Type -SparseMatrixBase::operator*(const SparseMatrixBase &other) const -{ - return typename SparseSparseProductReturnType::Type(derived(), other.derived()); -} - -} // end namespace Eigen - -#endif // EIGEN_SPARSEPRODUCT_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparseRedux.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparseRedux.h deleted file mode 100644 index f3da93a71..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparseRedux.h +++ /dev/null @@ -1,45 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSEREDUX_H -#define EIGEN_SPARSEREDUX_H - -namespace Eigen { - -template -typename internal::traits::Scalar -SparseMatrixBase::sum() const -{ - eigen_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix"); - Scalar res(0); - for (Index j=0; j -typename internal::traits >::Scalar -SparseMatrix<_Scalar,_Options,_Index>::sum() const -{ - eigen_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix"); - return Matrix::Map(&m_data.value(0), m_data.size()).sum(); -} - -template -typename internal::traits >::Scalar -SparseVector<_Scalar,_Options,_Index>::sum() const -{ - eigen_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix"); - return Matrix::Map(&m_data.value(0), m_data.size()).sum(); -} - -} // end namespace Eigen - -#endif // EIGEN_SPARSEREDUX_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparseSelfAdjointView.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparseSelfAdjointView.h deleted file mode 100644 index 0eda96bc4..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparseSelfAdjointView.h +++ /dev/null @@ -1,507 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSE_SELFADJOINTVIEW_H -#define EIGEN_SPARSE_SELFADJOINTVIEW_H - -namespace Eigen { - -/** \ingroup SparseCore_Module - * \class SparseSelfAdjointView - * - * \brief Pseudo expression to manipulate a triangular sparse matrix as a selfadjoint matrix. - * - * \param MatrixType the type of the dense matrix storing the coefficients - * \param UpLo can be either \c #Lower or \c #Upper - * - * This class is an expression of a sefladjoint matrix from a triangular part of a matrix - * with given dense storage of the coefficients. It is the return type of MatrixBase::selfadjointView() - * and most of the time this is the only way that it is used. - * - * \sa SparseMatrixBase::selfadjointView() - */ -template -class SparseSelfAdjointTimeDenseProduct; - -template -class DenseTimeSparseSelfAdjointProduct; - -namespace internal { - -template -struct traits > : traits { -}; - -template -void permute_symm_to_symm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm = 0); - -template -void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm = 0); - -} - -template class SparseSelfAdjointView - : public EigenBase > -{ - public: - - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::Index Index; - typedef Matrix VectorI; - typedef typename MatrixType::Nested MatrixTypeNested; - typedef typename internal::remove_all::type _MatrixTypeNested; - - inline SparseSelfAdjointView(const MatrixType& matrix) : m_matrix(matrix) - { - eigen_assert(rows()==cols() && "SelfAdjointView is only for squared matrices"); - } - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - - /** \internal \returns a reference to the nested matrix */ - const _MatrixTypeNested& matrix() const { return m_matrix; } - _MatrixTypeNested& matrix() { return m_matrix.const_cast_derived(); } - - /** \returns an expression of the matrix product between a sparse self-adjoint matrix \c *this and a sparse matrix \a rhs. - * - * Note that there is no algorithmic advantage of performing such a product compared to a general sparse-sparse matrix product. - * Indeed, the SparseSelfadjointView operand is first copied into a temporary SparseMatrix before computing the product. - */ - template - SparseSparseProduct - operator*(const SparseMatrixBase& rhs) const - { - return SparseSparseProduct(*this, rhs.derived()); - } - - /** \returns an expression of the matrix product between a sparse matrix \a lhs and a sparse self-adjoint matrix \a rhs. - * - * Note that there is no algorithmic advantage of performing such a product compared to a general sparse-sparse matrix product. - * Indeed, the SparseSelfadjointView operand is first copied into a temporary SparseMatrix before computing the product. - */ - template friend - SparseSparseProduct - operator*(const SparseMatrixBase& lhs, const SparseSelfAdjointView& rhs) - { - return SparseSparseProduct(lhs.derived(), rhs); - } - - /** Efficient sparse self-adjoint matrix times dense vector/matrix product */ - template - SparseSelfAdjointTimeDenseProduct - operator*(const MatrixBase& rhs) const - { - return SparseSelfAdjointTimeDenseProduct(m_matrix, rhs.derived()); - } - - /** Efficient dense vector/matrix times sparse self-adjoint matrix product */ - template friend - DenseTimeSparseSelfAdjointProduct - operator*(const MatrixBase& lhs, const SparseSelfAdjointView& rhs) - { - return DenseTimeSparseSelfAdjointProduct(lhs.derived(), rhs.m_matrix); - } - - /** Perform a symmetric rank K update of the selfadjoint matrix \c *this: - * \f$ this = this + \alpha ( u u^* ) \f$ where \a u is a vector or matrix. - * - * \returns a reference to \c *this - * - * To perform \f$ this = this + \alpha ( u^* u ) \f$ you can simply - * call this function with u.adjoint(). - */ - template - SparseSelfAdjointView& rankUpdate(const SparseMatrixBase& u, const Scalar& alpha = Scalar(1)); - - /** \internal triggered by sparse_matrix = SparseSelfadjointView; */ - template void evalTo(SparseMatrix& _dest) const - { - internal::permute_symm_to_fullsymm(m_matrix, _dest); - } - - template void evalTo(DynamicSparseMatrix& _dest) const - { - // TODO directly evaluate into _dest; - SparseMatrix tmp(_dest.rows(),_dest.cols()); - internal::permute_symm_to_fullsymm(m_matrix, tmp); - _dest = tmp; - } - - /** \returns an expression of P H P^-1 */ - SparseSymmetricPermutationProduct<_MatrixTypeNested,UpLo> twistedBy(const PermutationMatrix& perm) const - { - return SparseSymmetricPermutationProduct<_MatrixTypeNested,UpLo>(m_matrix, perm); - } - - template - SparseSelfAdjointView& operator=(const SparseSymmetricPermutationProduct& permutedMatrix) - { - permutedMatrix.evalTo(*this); - return *this; - } - - - SparseSelfAdjointView& operator=(const SparseSelfAdjointView& src) - { - PermutationMatrix pnull; - return *this = src.twistedBy(pnull); - } - - template - SparseSelfAdjointView& operator=(const SparseSelfAdjointView& src) - { - PermutationMatrix pnull; - return *this = src.twistedBy(pnull); - } - - - // const SparseLLT llt() const; - // const SparseLDLT ldlt() const; - - protected: - - typename MatrixType::Nested m_matrix; - mutable VectorI m_countPerRow; - mutable VectorI m_countPerCol; -}; - -/*************************************************************************** -* Implementation of SparseMatrixBase methods -***************************************************************************/ - -template -template -const SparseSelfAdjointView SparseMatrixBase::selfadjointView() const -{ - return derived(); -} - -template -template -SparseSelfAdjointView SparseMatrixBase::selfadjointView() -{ - return derived(); -} - -/*************************************************************************** -* Implementation of SparseSelfAdjointView methods -***************************************************************************/ - -template -template -SparseSelfAdjointView& -SparseSelfAdjointView::rankUpdate(const SparseMatrixBase& u, const Scalar& alpha) -{ - SparseMatrix tmp = u * u.adjoint(); - if(alpha==Scalar(0)) - m_matrix.const_cast_derived() = tmp.template triangularView(); - else - m_matrix.const_cast_derived() += alpha * tmp.template triangularView(); - - return *this; -} - -/*************************************************************************** -* Implementation of sparse self-adjoint time dense matrix -***************************************************************************/ - -namespace internal { -template -struct traits > - : traits, Lhs, Rhs> > -{ - typedef Dense StorageKind; -}; -} - -template -class SparseSelfAdjointTimeDenseProduct - : public ProductBase, Lhs, Rhs> -{ - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(SparseSelfAdjointTimeDenseProduct) - - SparseSelfAdjointTimeDenseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - {} - - template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const - { - EIGEN_ONLY_USED_FOR_DEBUG(alpha); - // TODO use alpha - eigen_assert(alpha==Scalar(1) && "alpha != 1 is not implemented yet, sorry"); - typedef typename internal::remove_all::type _Lhs; - typedef typename _Lhs::InnerIterator LhsInnerIterator; - enum { - LhsIsRowMajor = (_Lhs::Flags&RowMajorBit)==RowMajorBit, - ProcessFirstHalf = - ((UpLo&(Upper|Lower))==(Upper|Lower)) - || ( (UpLo&Upper) && !LhsIsRowMajor) - || ( (UpLo&Lower) && LhsIsRowMajor), - ProcessSecondHalf = !ProcessFirstHalf - }; - for (Index j=0; j -struct traits > - : traits, Lhs, Rhs> > -{}; -} - -template -class DenseTimeSparseSelfAdjointProduct - : public ProductBase, Lhs, Rhs> -{ - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(DenseTimeSparseSelfAdjointProduct) - - DenseTimeSparseSelfAdjointProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - {} - - template void scaleAndAddTo(Dest& /*dest*/, const Scalar& /*alpha*/) const - { - // TODO - } - - private: - DenseTimeSparseSelfAdjointProduct& operator=(const DenseTimeSparseSelfAdjointProduct&); -}; - -/*************************************************************************** -* Implementation of symmetric copies and permutations -***************************************************************************/ -namespace internal { - -template -struct traits > : traits { -}; - -template -void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm) -{ - typedef typename MatrixType::Index Index; - typedef typename MatrixType::Scalar Scalar; - typedef SparseMatrix Dest; - typedef Matrix VectorI; - - Dest& dest(_dest.derived()); - enum { - StorageOrderMatch = int(Dest::IsRowMajor) == int(MatrixType::IsRowMajor) - }; - - Index size = mat.rows(); - VectorI count; - count.resize(size); - count.setZero(); - dest.resize(size,size); - for(Index j = 0; jc) || ( UpLo==Upper && rc) || ( (UpLo&Upper)==Upper && r -void permute_symm_to_symm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm) -{ - typedef typename MatrixType::Index Index; - typedef typename MatrixType::Scalar Scalar; - SparseMatrix& dest(_dest.derived()); - typedef Matrix VectorI; - enum { - SrcOrder = MatrixType::IsRowMajor ? RowMajor : ColMajor, - StorageOrderMatch = int(SrcOrder) == int(DstOrder), - DstUpLo = DstOrder==RowMajor ? (_DstUpLo==Upper ? Lower : Upper) : _DstUpLo, - SrcUpLo = SrcOrder==RowMajor ? (_SrcUpLo==Upper ? Lower : Upper) : _SrcUpLo - }; - - Index size = mat.rows(); - VectorI count(size); - count.setZero(); - dest.resize(size,size); - for(Index j = 0; jj)) - continue; - - Index ip = perm ? perm[i] : i; - count[int(DstUpLo)==int(Lower) ? (std::min)(ip,jp) : (std::max)(ip,jp)]++; - } - } - dest.outerIndexPtr()[0] = 0; - for(Index j=0; jj)) - continue; - - Index jp = perm ? perm[j] : j; - Index ip = perm? perm[i] : i; - - Index k = count[int(DstUpLo)==int(Lower) ? (std::min)(ip,jp) : (std::max)(ip,jp)]++; - dest.innerIndexPtr()[k] = int(DstUpLo)==int(Lower) ? (std::max)(ip,jp) : (std::min)(ip,jp); - - if(!StorageOrderMatch) std::swap(ip,jp); - if( ((int(DstUpLo)==int(Lower) && ipjp))) - dest.valuePtr()[k] = numext::conj(it.value()); - else - dest.valuePtr()[k] = it.value(); - } - } -} - -} - -template -class SparseSymmetricPermutationProduct - : public EigenBase > -{ - public: - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::Index Index; - protected: - typedef PermutationMatrix Perm; - public: - typedef Matrix VectorI; - typedef typename MatrixType::Nested MatrixTypeNested; - typedef typename internal::remove_all::type _MatrixTypeNested; - - SparseSymmetricPermutationProduct(const MatrixType& mat, const Perm& perm) - : m_matrix(mat), m_perm(perm) - {} - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - - template - void evalTo(SparseMatrix& _dest) const - { -// internal::permute_symm_to_fullsymm(m_matrix,_dest,m_perm.indices().data()); - SparseMatrix tmp; - internal::permute_symm_to_fullsymm(m_matrix,tmp,m_perm.indices().data()); - _dest = tmp; - } - - template void evalTo(SparseSelfAdjointView& dest) const - { - internal::permute_symm_to_symm(m_matrix,dest.matrix(),m_perm.indices().data()); - } - - protected: - MatrixTypeNested m_matrix; - const Perm& m_perm; - -}; - -} // end namespace Eigen - -#endif // EIGEN_SPARSE_SELFADJOINTVIEW_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparseSparseProductWithPruning.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparseSparseProductWithPruning.h deleted file mode 100644 index fcc18f5c9..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparseSparseProductWithPruning.h +++ /dev/null @@ -1,150 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2011 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSESPARSEPRODUCTWITHPRUNING_H -#define EIGEN_SPARSESPARSEPRODUCTWITHPRUNING_H - -namespace Eigen { - -namespace internal { - - -// perform a pseudo in-place sparse * sparse product assuming all matrices are col major -template -static void sparse_sparse_product_with_pruning_impl(const Lhs& lhs, const Rhs& rhs, ResultType& res, const typename ResultType::RealScalar& tolerance) -{ - // return sparse_sparse_product_with_pruning_impl2(lhs,rhs,res); - - typedef typename remove_all::type::Scalar Scalar; - typedef typename remove_all::type::Index Index; - - // make sure to call innerSize/outerSize since we fake the storage order. - Index rows = lhs.innerSize(); - Index cols = rhs.outerSize(); - //Index size = lhs.outerSize(); - eigen_assert(lhs.outerSize() == rhs.innerSize()); - - // allocate a temporary buffer - AmbiVector tempVector(rows); - - // estimate the number of non zero entries - // given a rhs column containing Y non zeros, we assume that the respective Y columns - // of the lhs differs in average of one non zeros, thus the number of non zeros for - // the product of a rhs column with the lhs is X+Y where X is the average number of non zero - // per column of the lhs. - // Therefore, we have nnz(lhs*rhs) = nnz(lhs) + nnz(rhs) - Index estimated_nnz_prod = lhs.nonZeros() + rhs.nonZeros(); - - // mimics a resizeByInnerOuter: - if(ResultType::IsRowMajor) - res.resize(cols, rows); - else - res.resize(rows, cols); - - res.reserve(estimated_nnz_prod); - double ratioColRes = double(estimated_nnz_prod)/double(lhs.rows()*rhs.cols()); - for (Index j=0; j::Iterator it(tempVector,tolerance); it; ++it) - res.insertBackByOuterInner(j,it.index()) = it.value(); - } - res.finalize(); -} - -template::Flags&RowMajorBit, - int RhsStorageOrder = traits::Flags&RowMajorBit, - int ResStorageOrder = traits::Flags&RowMajorBit> -struct sparse_sparse_product_with_pruning_selector; - -template -struct sparse_sparse_product_with_pruning_selector -{ - typedef typename traits::type>::Scalar Scalar; - typedef typename ResultType::RealScalar RealScalar; - - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) - { - typename remove_all::type _res(res.rows(), res.cols()); - internal::sparse_sparse_product_with_pruning_impl(lhs, rhs, _res, tolerance); - res.swap(_res); - } -}; - -template -struct sparse_sparse_product_with_pruning_selector -{ - typedef typename ResultType::RealScalar RealScalar; - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) - { - // we need a col-major matrix to hold the result - typedef SparseMatrix SparseTemporaryType; - SparseTemporaryType _res(res.rows(), res.cols()); - internal::sparse_sparse_product_with_pruning_impl(lhs, rhs, _res, tolerance); - res = _res; - } -}; - -template -struct sparse_sparse_product_with_pruning_selector -{ - typedef typename ResultType::RealScalar RealScalar; - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) - { - // let's transpose the product to get a column x column product - typename remove_all::type _res(res.rows(), res.cols()); - internal::sparse_sparse_product_with_pruning_impl(rhs, lhs, _res, tolerance); - res.swap(_res); - } -}; - -template -struct sparse_sparse_product_with_pruning_selector -{ - typedef typename ResultType::RealScalar RealScalar; - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) - { - typedef SparseMatrix ColMajorMatrixLhs; - typedef SparseMatrix ColMajorMatrixRhs; - ColMajorMatrixLhs colLhs(lhs); - ColMajorMatrixRhs colRhs(rhs); - internal::sparse_sparse_product_with_pruning_impl(colLhs, colRhs, res, tolerance); - - // let's transpose the product to get a column x column product -// typedef SparseMatrix SparseTemporaryType; -// SparseTemporaryType _res(res.cols(), res.rows()); -// sparse_sparse_product_with_pruning_impl(rhs, lhs, _res); -// res = _res.transpose(); - } -}; - -// NOTE the 2 others cases (col row *) must never occur since they are caught -// by ProductReturnType which transforms it to (col col *) by evaluating rhs. - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_SPARSESPARSEPRODUCTWITHPRUNING_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparseTranspose.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparseTranspose.h deleted file mode 100644 index 76d031d52..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparseTranspose.h +++ /dev/null @@ -1,63 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2009 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSETRANSPOSE_H -#define EIGEN_SPARSETRANSPOSE_H - -namespace Eigen { - -template class TransposeImpl - : public SparseMatrixBase > -{ - typedef typename internal::remove_all::type _MatrixTypeNested; - public: - - EIGEN_SPARSE_PUBLIC_INTERFACE(Transpose ) - - class InnerIterator; - class ReverseInnerIterator; - - inline Index nonZeros() const { return derived().nestedExpression().nonZeros(); } -}; - -// NOTE: VC10 and VC11 trigger an ICE if don't put typename TransposeImpl:: in front of Index, -// a typedef typename TransposeImpl::Index Index; -// does not fix the issue. -// An alternative is to define the nested class in the parent class itself. -template class TransposeImpl::InnerIterator - : public _MatrixTypeNested::InnerIterator -{ - typedef typename _MatrixTypeNested::InnerIterator Base; - typedef typename TransposeImpl::Index Index; - public: - - EIGEN_STRONG_INLINE InnerIterator(const TransposeImpl& trans, typename TransposeImpl::Index outer) - : Base(trans.derived().nestedExpression(), outer) - {} - typename TransposeImpl::Index row() const { return Base::col(); } - typename TransposeImpl::Index col() const { return Base::row(); } -}; - -template class TransposeImpl::ReverseInnerIterator - : public _MatrixTypeNested::ReverseInnerIterator -{ - typedef typename _MatrixTypeNested::ReverseInnerIterator Base; - typedef typename TransposeImpl::Index Index; - public: - - EIGEN_STRONG_INLINE ReverseInnerIterator(const TransposeImpl& xpr, typename TransposeImpl::Index outer) - : Base(xpr.derived().nestedExpression(), outer) - {} - typename TransposeImpl::Index row() const { return Base::col(); } - typename TransposeImpl::Index col() const { return Base::row(); } -}; - -} // end namespace Eigen - -#endif // EIGEN_SPARSETRANSPOSE_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparseTriangularView.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparseTriangularView.h deleted file mode 100644 index 333127b78..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparseTriangularView.h +++ /dev/null @@ -1,179 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Gael Guennebaud -// Copyright (C) 2012 Désiré Nuentsa-Wakam -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSE_TRIANGULARVIEW_H -#define EIGEN_SPARSE_TRIANGULARVIEW_H - -namespace Eigen { - -namespace internal { - -template -struct traits > -: public traits -{}; - -} // namespace internal - -template class SparseTriangularView - : public SparseMatrixBase > -{ - enum { SkipFirst = ((Mode&Lower) && !(MatrixType::Flags&RowMajorBit)) - || ((Mode&Upper) && (MatrixType::Flags&RowMajorBit)), - SkipLast = !SkipFirst, - SkipDiag = (Mode&ZeroDiag) ? 1 : 0, - HasUnitDiag = (Mode&UnitDiag) ? 1 : 0 - }; - - public: - - EIGEN_SPARSE_PUBLIC_INTERFACE(SparseTriangularView) - - class InnerIterator; - class ReverseInnerIterator; - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - - typedef typename MatrixType::Nested MatrixTypeNested; - typedef typename internal::remove_reference::type MatrixTypeNestedNonRef; - typedef typename internal::remove_all::type MatrixTypeNestedCleaned; - - inline SparseTriangularView(const MatrixType& matrix) : m_matrix(matrix) {} - - /** \internal */ - inline const MatrixTypeNestedCleaned& nestedExpression() const { return m_matrix; } - - template - typename internal::plain_matrix_type_column_major::type - solve(const MatrixBase& other) const; - - template void solveInPlace(MatrixBase& other) const; - template void solveInPlace(SparseMatrixBase& other) const; - - protected: - MatrixTypeNested m_matrix; -}; - -template -class SparseTriangularView::InnerIterator : public MatrixTypeNestedCleaned::InnerIterator -{ - typedef typename MatrixTypeNestedCleaned::InnerIterator Base; - typedef typename SparseTriangularView::Index Index; - public: - - EIGEN_STRONG_INLINE InnerIterator(const SparseTriangularView& view, Index outer) - : Base(view.nestedExpression(), outer), m_returnOne(false) - { - if(SkipFirst) - { - while((*this) && ((HasUnitDiag||SkipDiag) ? this->index()<=outer : this->index()=Base::outer())) - { - if((!SkipFirst) && Base::operator bool()) - Base::operator++(); - m_returnOne = true; - } - } - - EIGEN_STRONG_INLINE InnerIterator& operator++() - { - if(HasUnitDiag && m_returnOne) - m_returnOne = false; - else - { - Base::operator++(); - if(HasUnitDiag && (!SkipFirst) && ((!Base::operator bool()) || Base::index()>=Base::outer())) - { - if((!SkipFirst) && Base::operator bool()) - Base::operator++(); - m_returnOne = true; - } - } - return *this; - } - - inline Index row() const { return (MatrixType::Flags&RowMajorBit ? Base::outer() : this->index()); } - inline Index col() const { return (MatrixType::Flags&RowMajorBit ? this->index() : Base::outer()); } - inline Index index() const - { - if(HasUnitDiag && m_returnOne) return Base::outer(); - else return Base::index(); - } - inline Scalar value() const - { - if(HasUnitDiag && m_returnOne) return Scalar(1); - else return Base::value(); - } - - EIGEN_STRONG_INLINE operator bool() const - { - if(HasUnitDiag && m_returnOne) - return true; - if(SkipFirst) return Base::operator bool(); - else - { - if (SkipDiag) return (Base::operator bool() && this->index() < this->outer()); - else return (Base::operator bool() && this->index() <= this->outer()); - } - } - protected: - bool m_returnOne; -}; - -template -class SparseTriangularView::ReverseInnerIterator : public MatrixTypeNestedCleaned::ReverseInnerIterator -{ - typedef typename MatrixTypeNestedCleaned::ReverseInnerIterator Base; - typedef typename SparseTriangularView::Index Index; - public: - - EIGEN_STRONG_INLINE ReverseInnerIterator(const SparseTriangularView& view, Index outer) - : Base(view.nestedExpression(), outer) - { - eigen_assert((!HasUnitDiag) && "ReverseInnerIterator does not support yet triangular views with a unit diagonal"); - if(SkipLast) { - while((*this) && (SkipDiag ? this->index()>=outer : this->index()>outer)) - --(*this); - } - } - - EIGEN_STRONG_INLINE ReverseInnerIterator& operator--() - { Base::operator--(); return *this; } - - inline Index row() const { return Base::row(); } - inline Index col() const { return Base::col(); } - - EIGEN_STRONG_INLINE operator bool() const - { - if (SkipLast) return Base::operator bool() ; - else - { - if(SkipDiag) return (Base::operator bool() && this->index() > this->outer()); - else return (Base::operator bool() && this->index() >= this->outer()); - } - } -}; - -template -template -inline const SparseTriangularView -SparseMatrixBase::triangularView() const -{ - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_SPARSE_TRIANGULARVIEW_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparseUtil.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparseUtil.h deleted file mode 100644 index 0ba471320..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparseUtil.h +++ /dev/null @@ -1,173 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSEUTIL_H -#define EIGEN_SPARSEUTIL_H - -namespace Eigen { - -#ifdef NDEBUG -#define EIGEN_DBG_SPARSE(X) -#else -#define EIGEN_DBG_SPARSE(X) X -#endif - -#define EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, Op) \ -template \ -EIGEN_STRONG_INLINE Derived& operator Op(const Eigen::SparseMatrixBase& other) \ -{ \ - return Base::operator Op(other.derived()); \ -} \ -EIGEN_STRONG_INLINE Derived& operator Op(const Derived& other) \ -{ \ - return Base::operator Op(other); \ -} - -#define EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, Op) \ -template \ -EIGEN_STRONG_INLINE Derived& operator Op(const Other& scalar) \ -{ \ - return Base::operator Op(scalar); \ -} - -#define EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATORS(Derived) \ -EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, =) \ -EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, +=) \ -EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, -=) \ -EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, *=) \ -EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, /=) - -#define _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, BaseClass) \ - typedef BaseClass Base; \ - typedef typename Eigen::internal::traits::Scalar Scalar; \ - typedef typename Eigen::NumTraits::Real RealScalar; \ - typedef typename Eigen::internal::nested::type Nested; \ - typedef typename Eigen::internal::traits::StorageKind StorageKind; \ - typedef typename Eigen::internal::traits::Index Index; \ - enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ - ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, \ - Flags = Eigen::internal::traits::Flags, \ - CoeffReadCost = Eigen::internal::traits::CoeffReadCost, \ - SizeAtCompileTime = Base::SizeAtCompileTime, \ - IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; \ - using Base::derived; \ - using Base::const_cast_derived; - -#define EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) \ - _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, Eigen::SparseMatrixBase) - -const int CoherentAccessPattern = 0x1; -const int InnerRandomAccessPattern = 0x2 | CoherentAccessPattern; -const int OuterRandomAccessPattern = 0x4 | CoherentAccessPattern; -const int RandomAccessPattern = 0x8 | OuterRandomAccessPattern | InnerRandomAccessPattern; - -template class SparseMatrixBase; -template class SparseMatrix; -template class DynamicSparseMatrix; -template class SparseVector; -template class MappedSparseMatrix; - -template class SparseTriangularView; -template class SparseSelfAdjointView; -template class SparseDiagonalProduct; -template class SparseView; - -template class SparseSparseProduct; -template class SparseTimeDenseProduct; -template class DenseTimeSparseProduct; -template class SparseDenseOuterProduct; - -template struct SparseSparseProductReturnType; -template::ColsAtCompileTime,internal::traits::RowsAtCompileTime)> struct DenseSparseProductReturnType; -template::ColsAtCompileTime,internal::traits::RowsAtCompileTime)> struct SparseDenseProductReturnType; -template class SparseSymmetricPermutationProduct; - -namespace internal { - -template struct sparse_eval; - -template struct eval - : public sparse_eval::RowsAtCompileTime,traits::ColsAtCompileTime> -{}; - -template struct sparse_eval { - typedef typename traits::Scalar _Scalar; - typedef typename traits::Index _Index; - public: - typedef SparseVector<_Scalar, RowMajor, _Index> type; -}; - -template struct sparse_eval { - typedef typename traits::Scalar _Scalar; - typedef typename traits::Index _Index; - public: - typedef SparseVector<_Scalar, ColMajor, _Index> type; -}; - -template struct sparse_eval { - typedef typename traits::Scalar _Scalar; - typedef typename traits::Index _Index; - enum { _Options = ((traits::Flags&RowMajorBit)==RowMajorBit) ? RowMajor : ColMajor }; - public: - typedef SparseMatrix<_Scalar, _Options, _Index> type; -}; - -template struct sparse_eval { - typedef typename traits::Scalar _Scalar; - public: - typedef Matrix<_Scalar, 1, 1> type; -}; - -template struct plain_matrix_type -{ - typedef typename traits::Scalar _Scalar; - typedef typename traits::Index _Index; - enum { _Options = ((traits::Flags&RowMajorBit)==RowMajorBit) ? RowMajor : ColMajor }; - public: - typedef SparseMatrix<_Scalar, _Options, _Index> type; -}; - -} // end namespace internal - -/** \ingroup SparseCore_Module - * - * \class Triplet - * - * \brief A small structure to hold a non zero as a triplet (i,j,value). - * - * \sa SparseMatrix::setFromTriplets() - */ -template::Index > -class Triplet -{ -public: - Triplet() : m_row(0), m_col(0), m_value(0) {} - - Triplet(const Index& i, const Index& j, const Scalar& v = Scalar(0)) - : m_row(i), m_col(j), m_value(v) - {} - - /** \returns the row index of the element */ - const Index& row() const { return m_row; } - - /** \returns the column index of the element */ - const Index& col() const { return m_col; } - - /** \returns the value of the element */ - const Scalar& value() const { return m_value; } -protected: - Index m_row, m_col; - Scalar m_value; -}; - -} // end namespace Eigen - -#endif // EIGEN_SPARSEUTIL_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparseVector.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparseVector.h deleted file mode 100644 index 7e15c814b..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparseVector.h +++ /dev/null @@ -1,447 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2009 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSEVECTOR_H -#define EIGEN_SPARSEVECTOR_H - -namespace Eigen { - -/** \ingroup SparseCore_Module - * \class SparseVector - * - * \brief a sparse vector class - * - * \tparam _Scalar the scalar type, i.e. the type of the coefficients - * - * See http://www.netlib.org/linalg/html_templates/node91.html for details on the storage scheme. - * - * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_SPARSEVECTOR_PLUGIN. - */ - -namespace internal { -template -struct traits > -{ - typedef _Scalar Scalar; - typedef _Index Index; - typedef Sparse StorageKind; - typedef MatrixXpr XprKind; - enum { - IsColVector = (_Options & RowMajorBit) ? 0 : 1, - - RowsAtCompileTime = IsColVector ? Dynamic : 1, - ColsAtCompileTime = IsColVector ? 1 : Dynamic, - MaxRowsAtCompileTime = RowsAtCompileTime, - MaxColsAtCompileTime = ColsAtCompileTime, - Flags = _Options | NestByRefBit | LvalueBit | (IsColVector ? 0 : RowMajorBit), - CoeffReadCost = NumTraits::ReadCost, - SupportedAccessPatterns = InnerRandomAccessPattern - }; -}; - -// Sparse-Vector-Assignment kinds: -enum { - SVA_RuntimeSwitch, - SVA_Inner, - SVA_Outer -}; - -template< typename Dest, typename Src, - int AssignmentKind = !bool(Src::IsVectorAtCompileTime) ? SVA_RuntimeSwitch - : Src::InnerSizeAtCompileTime==1 ? SVA_Outer - : SVA_Inner> -struct sparse_vector_assign_selector; - -} - -template -class SparseVector - : public SparseMatrixBase > -{ - typedef SparseMatrixBase SparseBase; - - public: - EIGEN_SPARSE_PUBLIC_INTERFACE(SparseVector) - EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseVector, +=) - EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseVector, -=) - - typedef internal::CompressedStorage Storage; - enum { IsColVector = internal::traits::IsColVector }; - - enum { - Options = _Options - }; - - EIGEN_STRONG_INLINE Index rows() const { return IsColVector ? m_size : 1; } - EIGEN_STRONG_INLINE Index cols() const { return IsColVector ? 1 : m_size; } - EIGEN_STRONG_INLINE Index innerSize() const { return m_size; } - EIGEN_STRONG_INLINE Index outerSize() const { return 1; } - - EIGEN_STRONG_INLINE const Scalar* valuePtr() const { return &m_data.value(0); } - EIGEN_STRONG_INLINE Scalar* valuePtr() { return &m_data.value(0); } - - EIGEN_STRONG_INLINE const Index* innerIndexPtr() const { return &m_data.index(0); } - EIGEN_STRONG_INLINE Index* innerIndexPtr() { return &m_data.index(0); } - - /** \internal */ - inline Storage& data() { return m_data; } - /** \internal */ - inline const Storage& data() const { return m_data; } - - inline Scalar coeff(Index row, Index col) const - { - eigen_assert(IsColVector ? (col==0 && row>=0 && row=0 && col=0 && i=0 && row=0 && col=0 && i(m_data.size()); } - - inline void startVec(Index outer) - { - EIGEN_UNUSED_VARIABLE(outer); - eigen_assert(outer==0); - } - - inline Scalar& insertBackByOuterInner(Index outer, Index inner) - { - EIGEN_UNUSED_VARIABLE(outer); - eigen_assert(outer==0); - return insertBack(inner); - } - inline Scalar& insertBack(Index i) - { - m_data.append(0, i); - return m_data.value(m_data.size()-1); - } - - inline Scalar& insert(Index row, Index col) - { - eigen_assert(IsColVector ? (col==0 && row>=0 && row=0 && col=0 && i= startId) && (m_data.index(p) > i) ) - { - m_data.index(p+1) = m_data.index(p); - m_data.value(p+1) = m_data.value(p); - --p; - } - m_data.index(p+1) = i; - m_data.value(p+1) = 0; - return m_data.value(p+1); - } - - /** - */ - inline void reserve(Index reserveSize) { m_data.reserve(reserveSize); } - - - inline void finalize() {} - - void prune(const Scalar& reference, const RealScalar& epsilon = NumTraits::dummy_precision()) - { - m_data.prune(reference,epsilon); - } - - void resize(Index rows, Index cols) - { - eigen_assert(rows==1 || cols==1); - resize(IsColVector ? rows : cols); - } - - void resize(Index newSize) - { - m_size = newSize; - m_data.clear(); - } - - void resizeNonZeros(Index size) { m_data.resize(size); } - - inline SparseVector() : m_size(0) { check_template_parameters(); resize(0); } - - inline SparseVector(Index size) : m_size(0) { check_template_parameters(); resize(size); } - - inline SparseVector(Index rows, Index cols) : m_size(0) { check_template_parameters(); resize(rows,cols); } - - template - inline SparseVector(const SparseMatrixBase& other) - : m_size(0) - { - check_template_parameters(); - *this = other.derived(); - } - - inline SparseVector(const SparseVector& other) - : SparseBase(other), m_size(0) - { - check_template_parameters(); - *this = other.derived(); - } - - /** Swaps the values of \c *this and \a other. - * Overloaded for performance: this version performs a \em shallow swap by swaping pointers and attributes only. - * \sa SparseMatrixBase::swap() - */ - inline void swap(SparseVector& other) - { - std::swap(m_size, other.m_size); - m_data.swap(other.m_data); - } - - inline SparseVector& operator=(const SparseVector& other) - { - if (other.isRValue()) - { - swap(other.const_cast_derived()); - } - else - { - resize(other.size()); - m_data = other.m_data; - } - return *this; - } - - template - inline SparseVector& operator=(const SparseMatrixBase& other) - { - SparseVector tmp(other.size()); - internal::sparse_vector_assign_selector::run(tmp,other.derived()); - this->swap(tmp); - return *this; - } - - #ifndef EIGEN_PARSED_BY_DOXYGEN - template - inline SparseVector& operator=(const SparseSparseProduct& product) - { - return Base::operator=(product); - } - #endif - - friend std::ostream & operator << (std::ostream & s, const SparseVector& m) - { - for (Index i=0; i::IsSigned,THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE); - EIGEN_STATIC_ASSERT((_Options&(ColMajor|RowMajor))==Options,INVALID_MATRIX_TEMPLATE_PARAMETERS); - } - - Storage m_data; - Index m_size; -}; - -template -class SparseVector::InnerIterator -{ - public: - InnerIterator(const SparseVector& vec, Index outer=0) - : m_data(vec.m_data), m_id(0), m_end(static_cast(m_data.size())) - { - EIGEN_UNUSED_VARIABLE(outer); - eigen_assert(outer==0); - } - - InnerIterator(const internal::CompressedStorage& data) - : m_data(data), m_id(0), m_end(static_cast(m_data.size())) - {} - - inline InnerIterator& operator++() { m_id++; return *this; } - - inline Scalar value() const { return m_data.value(m_id); } - inline Scalar& valueRef() { return const_cast(m_data.value(m_id)); } - - inline Index index() const { return m_data.index(m_id); } - inline Index row() const { return IsColVector ? index() : 0; } - inline Index col() const { return IsColVector ? 0 : index(); } - - inline operator bool() const { return (m_id < m_end); } - - protected: - const internal::CompressedStorage& m_data; - Index m_id; - const Index m_end; -}; - -template -class SparseVector::ReverseInnerIterator -{ - public: - ReverseInnerIterator(const SparseVector& vec, Index outer=0) - : m_data(vec.m_data), m_id(static_cast(m_data.size())), m_start(0) - { - EIGEN_UNUSED_VARIABLE(outer); - eigen_assert(outer==0); - } - - ReverseInnerIterator(const internal::CompressedStorage& data) - : m_data(data), m_id(static_cast(m_data.size())), m_start(0) - {} - - inline ReverseInnerIterator& operator--() { m_id--; return *this; } - - inline Scalar value() const { return m_data.value(m_id-1); } - inline Scalar& valueRef() { return const_cast(m_data.value(m_id-1)); } - - inline Index index() const { return m_data.index(m_id-1); } - inline Index row() const { return IsColVector ? index() : 0; } - inline Index col() const { return IsColVector ? 0 : index(); } - - inline operator bool() const { return (m_id > m_start); } - - protected: - const internal::CompressedStorage& m_data; - Index m_id; - const Index m_start; -}; - -namespace internal { - -template< typename Dest, typename Src> -struct sparse_vector_assign_selector { - static void run(Dest& dst, const Src& src) { - eigen_internal_assert(src.innerSize()==src.size()); - for(typename Src::InnerIterator it(src, 0); it; ++it) - dst.insert(it.index()) = it.value(); - } -}; - -template< typename Dest, typename Src> -struct sparse_vector_assign_selector { - static void run(Dest& dst, const Src& src) { - eigen_internal_assert(src.outerSize()==src.size()); - for(typename Dest::Index i=0; i -struct sparse_vector_assign_selector { - static void run(Dest& dst, const Src& src) { - if(src.outerSize()==1) sparse_vector_assign_selector::run(dst, src); - else sparse_vector_assign_selector::run(dst, src); - } -}; - -} - -} // end namespace Eigen - -#endif // EIGEN_SPARSEVECTOR_H diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/SparseView.h b/libs/eigen3/Eigen/src/Core/SparseCore/SparseView.h deleted file mode 100644 index fd8450463..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/SparseView.h +++ /dev/null @@ -1,99 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2011 Gael Guennebaud -// Copyright (C) 2010 Daniel Lowengrub -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSEVIEW_H -#define EIGEN_SPARSEVIEW_H - -namespace Eigen { - -namespace internal { - -template -struct traits > : traits -{ - typedef typename MatrixType::Index Index; - typedef Sparse StorageKind; - enum { - Flags = int(traits::Flags) & (RowMajorBit) - }; -}; - -} // end namespace internal - -template -class SparseView : public SparseMatrixBase > -{ - typedef typename MatrixType::Nested MatrixTypeNested; - typedef typename internal::remove_all::type _MatrixTypeNested; -public: - EIGEN_SPARSE_PUBLIC_INTERFACE(SparseView) - - SparseView(const MatrixType& mat, const Scalar& m_reference = Scalar(0), - typename NumTraits::Real m_epsilon = NumTraits::dummy_precision()) : - m_matrix(mat), m_reference(m_reference), m_epsilon(m_epsilon) {} - - class InnerIterator; - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - - inline Index innerSize() const { return m_matrix.innerSize(); } - inline Index outerSize() const { return m_matrix.outerSize(); } - -protected: - MatrixTypeNested m_matrix; - Scalar m_reference; - typename NumTraits::Real m_epsilon; -}; - -template -class SparseView::InnerIterator : public _MatrixTypeNested::InnerIterator -{ - typedef typename SparseView::Index Index; -public: - typedef typename _MatrixTypeNested::InnerIterator IterBase; - InnerIterator(const SparseView& view, Index outer) : - IterBase(view.m_matrix, outer), m_view(view) - { - incrementToNonZero(); - } - - EIGEN_STRONG_INLINE InnerIterator& operator++() - { - IterBase::operator++(); - incrementToNonZero(); - return *this; - } - - using IterBase::value; - -protected: - const SparseView& m_view; - -private: - void incrementToNonZero() - { - while((bool(*this)) && internal::isMuchSmallerThan(value(), m_view.m_reference, m_view.m_epsilon)) - { - IterBase::operator++(); - } - } -}; - -template -const SparseView MatrixBase::sparseView(const Scalar& m_reference, - const typename NumTraits::Real& m_epsilon) const -{ - return SparseView(derived(), m_reference, m_epsilon); -} - -} // end namespace Eigen - -#endif diff --git a/libs/eigen3/Eigen/src/Core/SparseCore/TriangularSolver.h b/libs/eigen3/Eigen/src/Core/SparseCore/TriangularSolver.h deleted file mode 100644 index cb8ad82b4..000000000 --- a/libs/eigen3/Eigen/src/Core/SparseCore/TriangularSolver.h +++ /dev/null @@ -1,334 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSETRIANGULARSOLVER_H -#define EIGEN_SPARSETRIANGULARSOLVER_H - -namespace Eigen { - -namespace internal { - -template::Flags) & RowMajorBit> -struct sparse_solve_triangular_selector; - -// forward substitution, row-major -template -struct sparse_solve_triangular_selector -{ - typedef typename Rhs::Scalar Scalar; - static void run(const Lhs& lhs, Rhs& other) - { - for(int col=0 ; col -struct sparse_solve_triangular_selector -{ - typedef typename Rhs::Scalar Scalar; - static void run(const Lhs& lhs, Rhs& other) - { - for(int col=0 ; col=0 ; --i) - { - Scalar tmp = other.coeff(i,col); - Scalar l_ii = 0; - typename Lhs::InnerIterator it(lhs, i); - while(it && it.index() -struct sparse_solve_triangular_selector -{ - typedef typename Rhs::Scalar Scalar; - static void run(const Lhs& lhs, Rhs& other) - { - for(int col=0 ; col -struct sparse_solve_triangular_selector -{ - typedef typename Rhs::Scalar Scalar; - static void run(const Lhs& lhs, Rhs& other) - { - for(int col=0 ; col=0; --i) - { - Scalar& tmp = other.coeffRef(i,col); - if (tmp!=Scalar(0)) // optimization when other is actually sparse - { - if(!(Mode & UnitDiag)) - { - // TODO replace this by a binary search. make sure the binary search is safe for partially sorted elements - typename Lhs::ReverseInnerIterator it(lhs, i); - while(it && it.index()!=i) - --it; - eigen_assert(it && it.index()==i); - other.coeffRef(i,col) /= it.value(); - } - typename Lhs::InnerIterator it(lhs, i); - for(; it && it.index() -template -void SparseTriangularView::solveInPlace(MatrixBase& other) const -{ - eigen_assert(m_matrix.cols() == m_matrix.rows() && m_matrix.cols() == other.rows()); - eigen_assert((!(Mode & ZeroDiag)) && bool(Mode & (Upper|Lower))); - - enum { copy = internal::traits::Flags & RowMajorBit }; - - typedef typename internal::conditional::type, OtherDerived&>::type OtherCopy; - OtherCopy otherCopy(other.derived()); - - internal::sparse_solve_triangular_selector::type, Mode>::run(m_matrix, otherCopy); - - if (copy) - other = otherCopy; -} - -template -template -typename internal::plain_matrix_type_column_major::type -SparseTriangularView::solve(const MatrixBase& other) const -{ - typename internal::plain_matrix_type_column_major::type res(other); - solveInPlace(res); - return res; -} - -// pure sparse path - -namespace internal { - -template -struct sparse_solve_triangular_sparse_selector; - -// forward substitution, col-major -template -struct sparse_solve_triangular_sparse_selector -{ - typedef typename Rhs::Scalar Scalar; - typedef typename promote_index_type::Index, - typename traits::Index>::type Index; - static void run(const Lhs& lhs, Rhs& other) - { - const bool IsLower = (UpLo==Lower); - AmbiVector tempVector(other.rows()*2); - tempVector.setBounds(0,other.rows()); - - Rhs res(other.rows(), other.cols()); - res.reserve(other.nonZeros()); - - for(int col=0 ; col=0; - i+=IsLower?1:-1) - { - tempVector.restart(); - Scalar& ci = tempVector.coeffRef(i); - if (ci!=Scalar(0)) - { - // find - typename Lhs::InnerIterator it(lhs, i); - if(!(Mode & UnitDiag)) - { - if (IsLower) - { - eigen_assert(it.index()==i); - ci /= it.value(); - } - else - ci /= lhs.coeff(i,i); - } - tempVector.restart(); - if (IsLower) - { - if (it.index()==i) - ++it; - for(; it; ++it) - tempVector.coeffRef(it.index()) -= ci * it.value(); - } - else - { - for(; it && it.index()::Iterator it(tempVector/*,1e-12*/); it; ++it) - { - ++ count; -// std::cerr << "fill " << it.index() << ", " << col << "\n"; -// std::cout << it.value() << " "; - // FIXME use insertBack - res.insert(it.index(), col) = it.value(); - } -// std::cout << "tempVector.nonZeros() == " << int(count) << " / " << (other.rows()) << "\n"; - } - res.finalize(); - other = res.markAsRValue(); - } -}; - -} // end namespace internal - -template -template -void SparseTriangularView::solveInPlace(SparseMatrixBase& other) const -{ - eigen_assert(m_matrix.cols() == m_matrix.rows() && m_matrix.cols() == other.rows()); - eigen_assert( (!(Mode & ZeroDiag)) && bool(Mode & (Upper|Lower))); - -// enum { copy = internal::traits::Flags & RowMajorBit }; - -// typedef typename internal::conditional::type, OtherDerived&>::type OtherCopy; -// OtherCopy otherCopy(other.derived()); - - internal::sparse_solve_triangular_sparse_selector::run(m_matrix, other.derived()); - -// if (copy) -// other = otherCopy; -} - -#ifdef EIGEN2_SUPPORT - -// deprecated stuff: - -/** \deprecated */ -template -template -void SparseMatrixBase::solveTriangularInPlace(MatrixBase& other) const -{ - this->template triangular().solveInPlace(other); -} - -/** \deprecated */ -template -template -typename internal::plain_matrix_type_column_major::type -SparseMatrixBase::solveTriangular(const MatrixBase& other) const -{ - typename internal::plain_matrix_type_column_major::type res(other); - derived().solveTriangularInPlace(res); - return res; -} -#endif // EIGEN2_SUPPORT - -} // end namespace Eigen - -#endif // EIGEN_SPARSETRIANGULARSOLVER_H diff --git a/libs/eigen3/Eigen/src/Core/StableNorm.h b/libs/eigen3/Eigen/src/Core/StableNorm.h index 389d94275..be04ed44d 100644 --- a/libs/eigen3/Eigen/src/Core/StableNorm.h +++ b/libs/eigen3/Eigen/src/Core/StableNorm.h @@ -17,10 +17,9 @@ namespace internal { template inline void stable_norm_kernel(const ExpressionType& bl, Scalar& ssq, Scalar& scale, Scalar& invScale) { - using std::max; Scalar maxCoeff = bl.cwiseAbs().maxCoeff(); - if (maxCoeff>scale) + if(maxCoeff>scale) { ssq = ssq * numext::abs2(scale/maxCoeff); Scalar tmp = Scalar(1)/maxCoeff; @@ -29,12 +28,21 @@ inline void stable_norm_kernel(const ExpressionType& bl, Scalar& ssq, Scalar& sc invScale = NumTraits::highest(); scale = Scalar(1)/invScale; } + else if(maxCoeff>NumTraits::highest()) // we got a INF + { + invScale = Scalar(1); + scale = maxCoeff; + } else { scale = maxCoeff; invScale = tmp; } } + else if(maxCoeff!=maxCoeff) // we got a NaN + { + scale = maxCoeff; + } // TODO if the maxCoeff is much much smaller than the current scale, // then we can neglect this sub vector @@ -47,15 +55,12 @@ inline typename NumTraits::Scalar>::Real blueNorm_impl(const EigenBase& _vec) { typedef typename Derived::RealScalar RealScalar; - typedef typename Derived::Index Index; using std::pow; - using std::min; - using std::max; using std::sqrt; using std::abs; const Derived& vec(_vec.derived()); static bool initialized = false; - static RealScalar b1, b2, s1m, s2m, overfl, rbig, relerr; + static RealScalar b1, b2, s1m, s2m, rbig, relerr; if(!initialized) { int ibeta, it, iemin, iemax, iexp; @@ -84,7 +89,6 @@ blueNorm_impl(const EigenBase& _vec) iexp = - ((iemax+it)/2); s2m = RealScalar(pow(RealScalar(ibeta),RealScalar(iexp))); // scaling factor for upper range - overfl = rbig*s2m; // overflow boundary for abig eps = RealScalar(pow(double(ibeta), 1-it)); relerr = sqrt(eps); // tolerance for neglecting asml initialized = true; @@ -101,13 +105,13 @@ blueNorm_impl(const EigenBase& _vec) else if(ax < b1) asml += numext::abs2(ax*s1m); else amed += numext::abs2(ax); } + if(amed!=amed) + return amed; // we got a NaN if(abig > RealScalar(0)) { abig = sqrt(abig); - if(abig > overfl) - { - return rbig; - } + if(abig > rbig) // overflow, or *this contains INF values + return abig; // return INF if(amed > RealScalar(0)) { abig = abig/s2m; @@ -128,8 +132,8 @@ blueNorm_impl(const EigenBase& _vec) } else return sqrt(amed); - asml = (min)(abig, amed); - abig = (max)(abig, amed); + asml = numext::mini(abig, amed); + abig = numext::maxi(abig, amed); if(asml <= abig*relerr) return abig; else @@ -152,21 +156,35 @@ template inline typename NumTraits::Scalar>::Real MatrixBase::stableNorm() const { - using std::min; using std::sqrt; + using std::abs; const Index blockSize = 4096; RealScalar scale(0); RealScalar invScale(1); RealScalar ssq(0); // sum of square + + typedef typename internal::nested_eval::type DerivedCopy; + typedef typename internal::remove_all::type DerivedCopyClean; + DerivedCopy copy(derived()); + enum { - Alignment = (int(Flags)&DirectAccessBit) || (int(Flags)&AlignedBit) ? 1 : 0 + CanAlign = ( (int(DerivedCopyClean::Flags)&DirectAccessBit) + || (int(internal::evaluator::Alignment)>0) // FIXME Alignment)>0 might not be enough + ) && (blockSize*sizeof(Scalar)*20) // if we cannot allocate on the stack, then let's not bother about this optimization }; + typedef typename internal::conditional, internal::evaluator::Alignment>, + typename DerivedCopyClean::ConstSegmentReturnType>::type SegmentWrapper; Index n = size(); - Index bi = internal::first_aligned(derived()); + + if(n==1) + return abs(this->coeff(0)); + + Index bi = internal::first_default_aligned(copy); if (bi>0) - internal::stable_norm_kernel(this->head(bi), ssq, scale, invScale); + internal::stable_norm_kernel(copy.head(bi), ssq, scale, invScale); for (; bisegment(bi,(min)(blockSize, n - bi)).template forceAlignedAccessIf(), ssq, scale, invScale); + internal::stable_norm_kernel(SegmentWrapper(copy.segment(bi,numext::mini(blockSize, n - bi))), ssq, scale, invScale); return scale * sqrt(ssq); } diff --git a/libs/eigen3/Eigen/src/Core/Stride.h b/libs/eigen3/Eigen/src/Core/Stride.h index 1e3f5fe9f..513742f34 100644 --- a/libs/eigen3/Eigen/src/Core/Stride.h +++ b/libs/eigen3/Eigen/src/Core/Stride.h @@ -31,8 +31,8 @@ namespace Eigen { * arguments to the constructor. * * Indeed, this class takes two template parameters: - * \param _OuterStrideAtCompileTime the outer stride, or Dynamic if you want to specify it at runtime. - * \param _InnerStrideAtCompileTime the inner stride, or Dynamic if you want to specify it at runtime. + * \tparam _OuterStrideAtCompileTime the outer stride, or Dynamic if you want to specify it at runtime. + * \tparam _InnerStrideAtCompileTime the inner stride, or Dynamic if you want to specify it at runtime. * * Here is an example: * \include Map_general_stride.cpp @@ -44,13 +44,14 @@ template class Stride { public: - typedef DenseIndex Index; + typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3 enum { InnerStrideAtCompileTime = _InnerStrideAtCompileTime, OuterStrideAtCompileTime = _OuterStrideAtCompileTime }; /** Default constructor, for use when strides are fixed at compile time */ + EIGEN_DEVICE_FUNC Stride() : m_outer(OuterStrideAtCompileTime), m_inner(InnerStrideAtCompileTime) { @@ -58,6 +59,7 @@ class Stride } /** Constructor allowing to pass the strides at runtime */ + EIGEN_DEVICE_FUNC Stride(Index outerStride, Index innerStride) : m_outer(outerStride), m_inner(innerStride) { @@ -65,13 +67,16 @@ class Stride } /** Copy constructor */ + EIGEN_DEVICE_FUNC Stride(const Stride& other) : m_outer(other.outer()), m_inner(other.inner()) {} /** \returns the outer stride */ + EIGEN_DEVICE_FUNC inline Index outer() const { return m_outer.value(); } /** \returns the inner stride */ + EIGEN_DEVICE_FUNC inline Index inner() const { return m_inner.value(); } protected: @@ -81,26 +86,24 @@ class Stride /** \brief Convenience specialization of Stride to specify only an inner stride * See class Map for some examples */ -template +template class InnerStride : public Stride<0, Value> { typedef Stride<0, Value> Base; public: - typedef DenseIndex Index; - InnerStride() : Base() {} - InnerStride(Index v) : Base(0, v) {} + EIGEN_DEVICE_FUNC InnerStride() : Base() {} + EIGEN_DEVICE_FUNC InnerStride(Index v) : Base(0, v) {} // FIXME making this explicit could break valid code }; /** \brief Convenience specialization of Stride to specify only an outer stride * See class Map for some examples */ -template +template class OuterStride : public Stride { typedef Stride Base; public: - typedef DenseIndex Index; - OuterStride() : Base() {} - OuterStride(Index v) : Base(v,0) {} + EIGEN_DEVICE_FUNC OuterStride() : Base() {} + EIGEN_DEVICE_FUNC OuterStride(Index v) : Base(v,0) {} // FIXME making this explicit could break valid code }; } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/Core/Swap.h b/libs/eigen3/Eigen/src/Core/Swap.h index bf58bd599..d70200918 100644 --- a/libs/eigen3/Eigen/src/Core/Swap.h +++ b/libs/eigen3/Eigen/src/Core/Swap.h @@ -12,115 +12,56 @@ namespace Eigen { -/** \class SwapWrapper - * \ingroup Core_Module - * - * \internal - * - * \brief Internal helper class for swapping two expressions - */ namespace internal { -template -struct traits > : traits {}; -} -template class SwapWrapper - : public internal::dense_xpr_base >::type +// Overload default assignPacket behavior for swapping them +template +class generic_dense_assignment_kernel, Specialized> + : public generic_dense_assignment_kernel, BuiltIn> { - public: - - typedef typename internal::dense_xpr_base::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(SwapWrapper) - typedef typename internal::packet_traits::type Packet; - - inline SwapWrapper(ExpressionType& xpr) : m_expression(xpr) {} - - inline Index rows() const { return m_expression.rows(); } - inline Index cols() const { return m_expression.cols(); } - inline Index outerStride() const { return m_expression.outerStride(); } - inline Index innerStride() const { return m_expression.innerStride(); } - - typedef typename internal::conditional< - internal::is_lvalue::value, - Scalar, - const Scalar - >::type ScalarWithConstIfNotLvalue; - - inline ScalarWithConstIfNotLvalue* data() { return m_expression.data(); } - inline const Scalar* data() const { return m_expression.data(); } - - inline Scalar& coeffRef(Index rowId, Index colId) - { - return m_expression.const_cast_derived().coeffRef(rowId, colId); - } - - inline Scalar& coeffRef(Index index) - { - return m_expression.const_cast_derived().coeffRef(index); - } - - inline Scalar& coeffRef(Index rowId, Index colId) const - { - return m_expression.coeffRef(rowId, colId); - } - - inline Scalar& coeffRef(Index index) const - { - return m_expression.coeffRef(index); - } - - template - void copyCoeff(Index rowId, Index colId, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(rowId >= 0 && rowId < rows() - && colId >= 0 && colId < cols()); - Scalar tmp = m_expression.coeff(rowId, colId); - m_expression.coeffRef(rowId, colId) = _other.coeff(rowId, colId); - _other.coeffRef(rowId, colId) = tmp; - } - - template - void copyCoeff(Index index, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(index >= 0 && index < m_expression.size()); - Scalar tmp = m_expression.coeff(index); - m_expression.coeffRef(index) = _other.coeff(index); - _other.coeffRef(index) = tmp; - } - - template - void copyPacket(Index rowId, Index colId, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(rowId >= 0 && rowId < rows() - && colId >= 0 && colId < cols()); - Packet tmp = m_expression.template packet(rowId, colId); - m_expression.template writePacket(rowId, colId, - _other.template packet(rowId, colId) - ); - _other.template writePacket(rowId, colId, tmp); - } - - template - void copyPacket(Index index, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(index >= 0 && index < m_expression.size()); - Packet tmp = m_expression.template packet(index); - m_expression.template writePacket(index, - _other.template packet(index) - ); - _other.template writePacket(index, tmp); - } - - ExpressionType& expression() const { return m_expression; } - - protected: - ExpressionType& m_expression; +protected: + typedef generic_dense_assignment_kernel, BuiltIn> Base; + using Base::m_dst; + using Base::m_src; + using Base::m_functor; + +public: + typedef typename Base::Scalar Scalar; + typedef typename Base::DstXprType DstXprType; + typedef swap_assign_op Functor; + + EIGEN_DEVICE_FUNC generic_dense_assignment_kernel(DstEvaluatorTypeT &dst, const SrcEvaluatorTypeT &src, const Functor &func, DstXprType& dstExpr) + : Base(dst, src, func, dstExpr) + {} + + template + void assignPacket(Index row, Index col) + { + PacketType tmp = m_src.template packet(row,col); + const_cast(m_src).template writePacket(row,col, m_dst.template packet(row,col)); + m_dst.template writePacket(row,col,tmp); + } + + template + void assignPacket(Index index) + { + PacketType tmp = m_src.template packet(index); + const_cast(m_src).template writePacket(index, m_dst.template packet(index)); + m_dst.template writePacket(index,tmp); + } + + // TODO find a simple way not to have to copy/paste this function from generic_dense_assignment_kernel, by simple I mean no CRTP (Gael) + template + void assignPacketByOuterInner(Index outer, Index inner) + { + Index row = Base::rowIndexByOuterInner(outer, inner); + Index col = Base::colIndexByOuterInner(outer, inner); + assignPacket(row, col); + } }; +} // namespace internal + } // end namespace Eigen #endif // EIGEN_SWAP_H diff --git a/libs/eigen3/Eigen/src/Core/Transpose.h b/libs/eigen3/Eigen/src/Core/Transpose.h index 22096ea2f..79b767bcc 100644 --- a/libs/eigen3/Eigen/src/Core/Transpose.h +++ b/libs/eigen3/Eigen/src/Core/Transpose.h @@ -2,7 +2,7 @@ // for linear algebra. // // Copyright (C) 2006-2008 Benoit Jacob -// Copyright (C) 2009-2010 Gael Guennebaud +// Copyright (C) 2009-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -13,39 +13,21 @@ namespace Eigen { -/** \class Transpose - * \ingroup Core_Module - * - * \brief Expression of the transpose of a matrix - * - * \param MatrixType the type of the object of which we are taking the transpose - * - * This class represents an expression of the transpose of a matrix. - * It is the return type of MatrixBase::transpose() and MatrixBase::adjoint() - * and most of the time this is the only way it is used. - * - * \sa MatrixBase::transpose(), MatrixBase::adjoint() - */ - namespace internal { template -struct traits > : traits +struct traits > : public traits { - typedef typename MatrixType::Scalar Scalar; - typedef typename nested::type MatrixTypeNested; + typedef typename ref_selector::type MatrixTypeNested; typedef typename remove_reference::type MatrixTypeNestedPlain; - typedef typename traits::StorageKind StorageKind; - typedef typename traits::XprKind XprKind; enum { RowsAtCompileTime = MatrixType::ColsAtCompileTime, ColsAtCompileTime = MatrixType::RowsAtCompileTime, MaxRowsAtCompileTime = MatrixType::MaxColsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxRowsAtCompileTime, FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, - Flags0 = MatrixTypeNestedPlain::Flags & ~(LvalueBit | NestByRefBit), + Flags0 = traits::Flags & ~(LvalueBit | NestByRefBit), Flags1 = Flags0 | FlagsLvalueBit, Flags = Flags1 ^ RowMajorBit, - CoeffReadCost = MatrixTypeNestedPlain::CoeffReadCost, InnerStrideAtCompileTime = inner_stride_at_compile_time::ret, OuterStrideAtCompileTime = outer_stride_at_compile_time::ret }; @@ -54,31 +36,55 @@ struct traits > : traits template class TransposeImpl; +/** \class Transpose + * \ingroup Core_Module + * + * \brief Expression of the transpose of a matrix + * + * \tparam MatrixType the type of the object of which we are taking the transpose + * + * This class represents an expression of the transpose of a matrix. + * It is the return type of MatrixBase::transpose() and MatrixBase::adjoint() + * and most of the time this is the only way it is used. + * + * \sa MatrixBase::transpose(), MatrixBase::adjoint() + */ template class Transpose : public TransposeImpl::StorageKind> { public: + typedef typename internal::ref_selector::non_const_type MatrixTypeNested; + typedef typename TransposeImpl::StorageKind>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(Transpose) + typedef typename internal::remove_all::type NestedExpression; - inline Transpose(MatrixType& a_matrix) : m_matrix(a_matrix) {} + EIGEN_DEVICE_FUNC + explicit inline Transpose(MatrixType& matrix) : m_matrix(matrix) {} EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Transpose) - inline Index rows() const { return m_matrix.cols(); } - inline Index cols() const { return m_matrix.rows(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.cols(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.rows(); } /** \returns the nested expression */ - const typename internal::remove_all::type& + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& nestedExpression() const { return m_matrix; } /** \returns the nested expression */ - typename internal::remove_all::type& - nestedExpression() { return m_matrix.const_cast_derived(); } + EIGEN_DEVICE_FUNC + typename internal::remove_reference::type& + nestedExpression() { return m_matrix; } + + /** \internal */ + void resize(Index nrows, Index ncols) { + m_matrix.resize(ncols,nrows); + } protected: - typename MatrixType::Nested m_matrix; + typename internal::ref_selector::non_const_type m_matrix; }; namespace internal { @@ -97,17 +103,27 @@ struct TransposeImpl_base } // end namespace internal +// Generic API dispatcher +template +class TransposeImpl + : public internal::generic_xpr_base >::type +{ +public: + typedef typename internal::generic_xpr_base >::type Base; +}; + template class TransposeImpl : public internal::TransposeImpl_base::type { public: typedef typename internal::TransposeImpl_base::type Base; + using Base::coeffRef; EIGEN_DENSE_PUBLIC_INTERFACE(Transpose) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(TransposeImpl) - inline Index innerStride() const { return derived().nestedExpression().innerStride(); } - inline Index outerStride() const { return derived().nestedExpression().outerStride(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return derived().nestedExpression().innerStride(); } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return derived().nestedExpression().outerStride(); } typedef typename internal::conditional< internal::is_lvalue::value, @@ -115,64 +131,21 @@ template class TransposeImpl const Scalar >::type ScalarWithConstIfNotLvalue; - inline ScalarWithConstIfNotLvalue* data() { return derived().nestedExpression().data(); } - inline const Scalar* data() const { return derived().nestedExpression().data(); } - - inline ScalarWithConstIfNotLvalue& coeffRef(Index rowId, Index colId) - { - EIGEN_STATIC_ASSERT_LVALUE(MatrixType) - return derived().nestedExpression().const_cast_derived().coeffRef(colId, rowId); - } - - inline ScalarWithConstIfNotLvalue& coeffRef(Index index) - { - EIGEN_STATIC_ASSERT_LVALUE(MatrixType) - return derived().nestedExpression().const_cast_derived().coeffRef(index); - } + EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue* data() { return derived().nestedExpression().data(); } + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return derived().nestedExpression().data(); } + // FIXME: shall we keep the const version of coeffRef? + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index rowId, Index colId) const { return derived().nestedExpression().coeffRef(colId, rowId); } + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index index) const { return derived().nestedExpression().coeffRef(index); } - - inline CoeffReturnType coeff(Index rowId, Index colId) const - { - return derived().nestedExpression().coeff(colId, rowId); - } - - inline CoeffReturnType coeff(Index index) const - { - return derived().nestedExpression().coeff(index); - } - - template - inline const PacketScalar packet(Index rowId, Index colId) const - { - return derived().nestedExpression().template packet(colId, rowId); - } - - template - inline void writePacket(Index rowId, Index colId, const PacketScalar& x) - { - derived().nestedExpression().const_cast_derived().template writePacket(colId, rowId, x); - } - - template - inline const PacketScalar packet(Index index) const - { - return derived().nestedExpression().template packet(index); - } - - template - inline void writePacket(Index index, const PacketScalar& x) - { - derived().nestedExpression().const_cast_derived().template writePacket(index, x); - } }; /** \returns an expression of the transpose of *this. @@ -198,7 +171,7 @@ template inline Transpose DenseBase::transpose() { - return derived(); + return TransposeReturnType(derived()); } /** This is the const version of transpose(). @@ -236,8 +209,7 @@ template inline const typename MatrixBase::AdjointReturnType MatrixBase::adjoint() const { - return this->transpose(); // in the complex case, the .conjugate() is be implicit here - // due to implicit conversion to return type + return AdjointReturnType(this->transpose()); } /*************************************************************************** @@ -247,18 +219,38 @@ MatrixBase::adjoint() const namespace internal { template + bool IsSquare = (MatrixType::RowsAtCompileTime == MatrixType::ColsAtCompileTime) && MatrixType::RowsAtCompileTime!=Dynamic, + bool MatchPacketSize = + (int(MatrixType::RowsAtCompileTime) == int(internal::packet_traits::size)) + && (internal::evaluator::Flags&PacketAccessBit) > struct inplace_transpose_selector; template -struct inplace_transpose_selector { // square matrix +struct inplace_transpose_selector { // square matrix static void run(MatrixType& m) { m.matrix().template triangularView().swap(m.matrix().transpose()); } }; +// TODO: vectorized path is currently limited to LargestPacketSize x LargestPacketSize cases only. template -struct inplace_transpose_selector { // non square matrix +struct inplace_transpose_selector { // PacketSize x PacketSize + static void run(MatrixType& m) { + typedef typename MatrixType::Scalar Scalar; + typedef typename internal::packet_traits::type Packet; + const Index PacketSize = internal::packet_traits::size; + const Index Alignment = internal::evaluator::Alignment; + PacketBlock A; + for (Index i=0; i(i,0); + internal::ptranspose(A); + for (Index i=0; i(m.rowIndexByOuterInner(i,0), m.colIndexByOuterInner(i,0), A.packet[i]); + } +}; + +template +struct inplace_transpose_selector { // non square matrix static void run(MatrixType& m) { if (m.rows()==m.cols()) m.matrix().template triangularView().swap(m.matrix().transpose()); @@ -331,14 +323,6 @@ inline void MatrixBase::adjointInPlace() namespace internal { -template -struct blas_traits > - : blas_traits -{ - typedef SelfCwiseBinaryOp XprType; - static inline const XprType extract(const XprType& x) { return x; } -}; - template struct check_transpose_aliasing_compile_time_selector { @@ -404,15 +388,15 @@ struct checkTransposeAliasing_impl } }; -} // end namespace internal - -template -template -void DenseBase::checkTransposeAliasing(const OtherDerived& other) const +template +void check_for_aliasing(const Dst &dst, const Src &src) { - internal::checkTransposeAliasing_impl::run(derived(), other); + internal::checkTransposeAliasing_impl::run(dst, src); } -#endif + +} // end namespace internal + +#endif // EIGEN_NO_DEBUG } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/Core/Transpositions.h b/libs/eigen3/Eigen/src/Core/Transpositions.h index e4ba0756f..19c17bb4a 100644 --- a/libs/eigen3/Eigen/src/Core/Transpositions.h +++ b/libs/eigen3/Eigen/src/Core/Transpositions.h @@ -12,39 +12,6 @@ namespace Eigen { -/** \class Transpositions - * \ingroup Core_Module - * - * \brief Represents a sequence of transpositions (row/column interchange) - * - * \param SizeAtCompileTime the number of transpositions, or Dynamic - * \param MaxSizeAtCompileTime the maximum number of transpositions, or Dynamic. This optional parameter defaults to SizeAtCompileTime. Most of the time, you should not have to specify it. - * - * This class represents a permutation transformation as a sequence of \em n transpositions - * \f$[T_{n-1} \ldots T_{i} \ldots T_{0}]\f$. It is internally stored as a vector of integers \c indices. - * Each transposition \f$ T_{i} \f$ applied on the left of a matrix (\f$ T_{i} M\f$) interchanges - * the rows \c i and \c indices[i] of the matrix \c M. - * A transposition applied on the right (e.g., \f$ M T_{i}\f$) yields a column interchange. - * - * Compared to the class PermutationMatrix, such a sequence of transpositions is what is - * computed during a decomposition with pivoting, and it is faster when applying the permutation in-place. - * - * To apply a sequence of transpositions to a matrix, simply use the operator * as in the following example: - * \code - * Transpositions tr; - * MatrixXf mat; - * mat = tr * mat; - * \endcode - * In this example, we detect that the matrix appears on both side, and so the transpositions - * are applied in-place without any temporary or extra copy. - * - * \sa class PermutationMatrix - */ - -namespace internal { -template struct transposition_matrix_product_retval; -} - template class TranspositionsBase { @@ -53,7 +20,8 @@ class TranspositionsBase public: typedef typename Traits::IndicesType IndicesType; - typedef typename IndicesType::Scalar Index; + typedef typename IndicesType::Scalar StorageIndex; + typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3 Derived& derived() { return *static_cast(this); } const Derived& derived() const { return *static_cast(this); } @@ -65,7 +33,7 @@ class TranspositionsBase indices() = other.indices(); return derived(); } - + #ifndef EIGEN_PARSED_BY_DOXYGEN /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. @@ -78,20 +46,24 @@ class TranspositionsBase #endif /** \returns the number of transpositions */ - inline Index size() const { return indices().size(); } + Index size() const { return indices().size(); } + /** \returns the number of rows of the equivalent permutation matrix */ + Index rows() const { return indices().size(); } + /** \returns the number of columns of the equivalent permutation matrix */ + Index cols() const { return indices().size(); } /** Direct access to the underlying index vector */ - inline const Index& coeff(Index i) const { return indices().coeff(i); } + inline const StorageIndex& coeff(Index i) const { return indices().coeff(i); } /** Direct access to the underlying index vector */ - inline Index& coeffRef(Index i) { return indices().coeffRef(i); } + inline StorageIndex& coeffRef(Index i) { return indices().coeffRef(i); } /** Direct access to the underlying index vector */ - inline const Index& operator()(Index i) const { return indices()(i); } + inline const StorageIndex& operator()(Index i) const { return indices()(i); } /** Direct access to the underlying index vector */ - inline Index& operator()(Index i) { return indices()(i); } + inline StorageIndex& operator()(Index i) { return indices()(i); } /** Direct access to the underlying index vector */ - inline const Index& operator[](Index i) const { return indices()(i); } + inline const StorageIndex& operator[](Index i) const { return indices()(i); } /** Direct access to the underlying index vector */ - inline Index& operator[](Index i) { return indices()(i); } + inline StorageIndex& operator[](Index i) { return indices()(i); } /** const version of indices(). */ const IndicesType& indices() const { return derived().indices(); } @@ -99,7 +71,7 @@ class TranspositionsBase IndicesType& indices() { return derived().indices(); } /** Resizes to given size. */ - inline void resize(int newSize) + inline void resize(Index newSize) { indices().resize(newSize); } @@ -107,7 +79,7 @@ class TranspositionsBase /** Sets \c *this to represents an identity transformation */ void setIdentity() { - for(int i = 0; i < indices().size(); ++i) + for(StorageIndex i = 0; i < indices().size(); ++i) coeffRef(i) = i; } @@ -144,23 +116,53 @@ class TranspositionsBase }; namespace internal { -template -struct traits > +template +struct traits > + : traits > { - typedef IndexType Index; - typedef Matrix IndicesType; + typedef Matrix<_StorageIndex, SizeAtCompileTime, 1, 0, MaxSizeAtCompileTime, 1> IndicesType; + typedef TranspositionsStorage StorageKind; }; } -template -class Transpositions : public TranspositionsBase > +/** \class Transpositions + * \ingroup Core_Module + * + * \brief Represents a sequence of transpositions (row/column interchange) + * + * \tparam SizeAtCompileTime the number of transpositions, or Dynamic + * \tparam MaxSizeAtCompileTime the maximum number of transpositions, or Dynamic. This optional parameter defaults to SizeAtCompileTime. Most of the time, you should not have to specify it. + * + * This class represents a permutation transformation as a sequence of \em n transpositions + * \f$[T_{n-1} \ldots T_{i} \ldots T_{0}]\f$. It is internally stored as a vector of integers \c indices. + * Each transposition \f$ T_{i} \f$ applied on the left of a matrix (\f$ T_{i} M\f$) interchanges + * the rows \c i and \c indices[i] of the matrix \c M. + * A transposition applied on the right (e.g., \f$ M T_{i}\f$) yields a column interchange. + * + * Compared to the class PermutationMatrix, such a sequence of transpositions is what is + * computed during a decomposition with pivoting, and it is faster when applying the permutation in-place. + * + * To apply a sequence of transpositions to a matrix, simply use the operator * as in the following example: + * \code + * Transpositions tr; + * MatrixXf mat; + * mat = tr * mat; + * \endcode + * In this example, we detect that the matrix appears on both side, and so the transpositions + * are applied in-place without any temporary or extra copy. + * + * \sa class PermutationMatrix + */ + +template +class Transpositions : public TranspositionsBase > { typedef internal::traits Traits; public: typedef TranspositionsBase Base; typedef typename Traits::IndicesType IndicesType; - typedef typename IndicesType::Scalar Index; + typedef typename IndicesType::Scalar StorageIndex; inline Transpositions() {} @@ -177,7 +179,7 @@ class Transpositions : public TranspositionsBase - explicit inline Transpositions(const MatrixBase& a_indices) : m_indices(a_indices) + explicit inline Transpositions(const MatrixBase& indices) : m_indices(indices) {} /** Copies the \a other transpositions into \c *this */ @@ -215,30 +217,32 @@ class Transpositions : public TranspositionsBase -struct traits,_PacketAccess> > +template +struct traits,_PacketAccess> > + : traits > { - typedef IndexType Index; - typedef Map, _PacketAccess> IndicesType; + typedef Map, _PacketAccess> IndicesType; + typedef _StorageIndex StorageIndex; + typedef TranspositionsStorage StorageKind; }; } -template -class Map,PacketAccess> - : public TranspositionsBase,PacketAccess> > +template +class Map,PacketAccess> + : public TranspositionsBase,PacketAccess> > { typedef internal::traits Traits; public: typedef TranspositionsBase Base; typedef typename Traits::IndicesType IndicesType; - typedef typename IndicesType::Scalar Index; + typedef typename IndicesType::Scalar StorageIndex; - inline Map(const Index* indicesPtr) + explicit inline Map(const StorageIndex* indicesPtr) : m_indices(indicesPtr) {} - inline Map(const Index* indicesPtr, Index size) + inline Map(const StorageIndex* indicesPtr, Index size) : m_indices(indicesPtr,size) {} @@ -274,9 +278,9 @@ class Map,Packe namespace internal { template struct traits > + : traits > { - typedef typename _IndicesType::Scalar Index; - typedef _IndicesType IndicesType; + typedef TranspositionsStorage StorageKind; }; } @@ -289,10 +293,10 @@ class TranspositionsWrapper typedef TranspositionsBase Base; typedef typename Traits::IndicesType IndicesType; - typedef typename IndicesType::Scalar Index; + typedef typename IndicesType::Scalar StorageIndex; - inline TranspositionsWrapper(IndicesType& a_indices) - : m_indices(a_indices) + explicit inline TranspositionsWrapper(IndicesType& indices) + : m_indices(indices) {} /** Copies the \a other transpositions into \c *this */ @@ -321,83 +325,46 @@ class TranspositionsWrapper protected: - const typename IndicesType::Nested m_indices; + typename IndicesType::Nested m_indices; }; + + /** \returns the \a matrix with the \a transpositions applied to the columns. */ -template -inline const internal::transposition_matrix_product_retval -operator*(const MatrixBase& matrix, - const TranspositionsBase &transpositions) +template +EIGEN_DEVICE_FUNC +const Product +operator*(const MatrixBase &matrix, + const TranspositionsBase& transpositions) { - return internal::transposition_matrix_product_retval - - (transpositions.derived(), matrix.derived()); + return Product + (matrix.derived(), transpositions.derived()); } /** \returns the \a matrix with the \a transpositions applied to the rows. */ -template -inline const internal::transposition_matrix_product_retval - -operator*(const TranspositionsBase &transpositions, - const MatrixBase& matrix) +template +EIGEN_DEVICE_FUNC +const Product +operator*(const TranspositionsBase &transpositions, + const MatrixBase& matrix) { - return internal::transposition_matrix_product_retval - - (transpositions.derived(), matrix.derived()); + return Product + (transpositions.derived(), matrix.derived()); } -namespace internal { - -template -struct traits > -{ - typedef typename MatrixType::PlainObject ReturnType; -}; - -template -struct transposition_matrix_product_retval - : public ReturnByValue > -{ - typedef typename remove_all::type MatrixTypeNestedCleaned; - typedef typename TranspositionType::Index Index; - - transposition_matrix_product_retval(const TranspositionType& tr, const MatrixType& matrix) - : m_transpositions(tr), m_matrix(matrix) - {} +// Template partial specialization for transposed/inverse transpositions - inline int rows() const { return m_matrix.rows(); } - inline int cols() const { return m_matrix.cols(); } - - template inline void evalTo(Dest& dst) const - { - const int size = m_transpositions.size(); - Index j = 0; - - if(!(is_same::value && extract_data(dst) == extract_data(m_matrix))) - dst = m_matrix; - - for(int k=(Transposed?size-1:0) ; Transposed?k>=0:k +struct traits > > + : traits +{}; } // end namespace internal -/* Template partial specialization for transposed/inverse transpositions */ - template class Transpose > { @@ -405,27 +372,31 @@ class Transpose > typedef typename TranspositionType::IndicesType IndicesType; public: - Transpose(const TranspositionType& t) : m_transpositions(t) {} + explicit Transpose(const TranspositionType& t) : m_transpositions(t) {} - inline int size() const { return m_transpositions.size(); } + Index size() const { return m_transpositions.size(); } + Index rows() const { return m_transpositions.size(); } + Index cols() const { return m_transpositions.size(); } /** \returns the \a matrix with the inverse transpositions applied to the columns. */ - template friend - inline const internal::transposition_matrix_product_retval - operator*(const MatrixBase& matrix, const Transpose& trt) + template friend + const Product + operator*(const MatrixBase& matrix, const Transpose& trt) { - return internal::transposition_matrix_product_retval(trt.m_transpositions, matrix.derived()); + return Product(matrix.derived(), trt.derived()); } /** \returns the \a matrix with the inverse transpositions applied to the rows. */ - template - inline const internal::transposition_matrix_product_retval - operator*(const MatrixBase& matrix) const + template + const Product + operator*(const MatrixBase& matrix) const { - return internal::transposition_matrix_product_retval(m_transpositions, matrix.derived()); + return Product(*this, matrix.derived()); } + + const TranspositionType& nestedExpression() const { return m_transpositions; } protected: const TranspositionType& m_transpositions; diff --git a/libs/eigen3/Eigen/src/Core/TriangularMatrix.h b/libs/eigen3/Eigen/src/Core/TriangularMatrix.h index 845ae1aec..667ef09dc 100644 --- a/libs/eigen3/Eigen/src/Core/TriangularMatrix.h +++ b/libs/eigen3/Eigen/src/Core/TriangularMatrix.h @@ -19,9 +19,7 @@ template struct triangular_solv } -/** \internal - * - * \class TriangularBase +/** \class TriangularBase * \ingroup Core_Module * * \brief Base class for triangular part in a matrix @@ -32,41 +30,69 @@ template class TriangularBase : public EigenBase enum { Mode = internal::traits::Mode, - CoeffReadCost = internal::traits::CoeffReadCost, RowsAtCompileTime = internal::traits::RowsAtCompileTime, ColsAtCompileTime = internal::traits::ColsAtCompileTime, MaxRowsAtCompileTime = internal::traits::MaxRowsAtCompileTime, - MaxColsAtCompileTime = internal::traits::MaxColsAtCompileTime + MaxColsAtCompileTime = internal::traits::MaxColsAtCompileTime, + + SizeAtCompileTime = (internal::size_at_compile_time::RowsAtCompileTime, + internal::traits::ColsAtCompileTime>::ret), + /**< This is equal to the number of coefficients, i.e. the number of + * rows times the number of columns, or to \a Dynamic if this is not + * known at compile-time. \sa RowsAtCompileTime, ColsAtCompileTime */ + + MaxSizeAtCompileTime = (internal::size_at_compile_time::MaxRowsAtCompileTime, + internal::traits::MaxColsAtCompileTime>::ret) + }; typedef typename internal::traits::Scalar Scalar; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; - typedef typename internal::traits::DenseMatrixType DenseMatrixType; + typedef typename internal::traits::StorageIndex StorageIndex; + typedef typename internal::traits::FullMatrixType DenseMatrixType; typedef DenseMatrixType DenseType; + typedef Derived const& Nested; + EIGEN_DEVICE_FUNC inline TriangularBase() { eigen_assert(!((Mode&UnitDiag) && (Mode&ZeroDiag))); } + EIGEN_DEVICE_FUNC inline Index rows() const { return derived().rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return derived().cols(); } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return derived().outerStride(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return derived().innerStride(); } + + // dummy resize function + void resize(Index rows, Index cols) + { + EIGEN_UNUSED_VARIABLE(rows); + EIGEN_UNUSED_VARIABLE(cols); + eigen_assert(rows==this->rows() && cols==this->cols()); + } + EIGEN_DEVICE_FUNC inline Scalar coeff(Index row, Index col) const { return derived().coeff(row,col); } + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) { return derived().coeffRef(row,col); } /** \see MatrixBase::copyCoeff(row,col) */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void copyCoeff(Index row, Index col, Other& other) { derived().coeffRef(row, col) = other.coeff(row, col); } + EIGEN_DEVICE_FUNC inline Scalar operator()(Index row, Index col) const { check_coordinates(row, col); return coeff(row,col); } + EIGEN_DEVICE_FUNC inline Scalar& operator()(Index row, Index col) { check_coordinates(row, col); @@ -74,15 +100,20 @@ template class TriangularBase : public EigenBase } #ifndef EIGEN_PARSED_BY_DOXYGEN + EIGEN_DEVICE_FUNC inline const Derived& derived() const { return *static_cast(this); } + EIGEN_DEVICE_FUNC inline Derived& derived() { return *static_cast(this); } #endif // not EIGEN_PARSED_BY_DOXYGEN template + EIGEN_DEVICE_FUNC void evalTo(MatrixBase &other) const; template + EIGEN_DEVICE_FUNC void evalToLazy(MatrixBase &other) const; + EIGEN_DEVICE_FUNC DenseMatrixType toDenseMatrix() const { DenseMatrixType res(rows(), cols()); @@ -119,17 +150,17 @@ template class TriangularBase : public EigenBase /** \class TriangularView * \ingroup Core_Module * - * \brief Base class for triangular part in a matrix + * \brief Expression of a triangular part in a matrix * * \param MatrixType the type of the object in which we are taking the triangular part * \param Mode the kind of triangular matrix expression to construct. Can be #Upper, * #Lower, #UnitUpper, #UnitLower, #StrictlyUpper, or #StrictlyLower. * This is in fact a bit field; it must have either #Upper or #Lower, - * and additionnaly it may have #UnitDiag or #ZeroDiag or neither. + * and additionally it may have #UnitDiag or #ZeroDiag or neither. * * This class represents a triangular part of a matrix, not necessarily square. Strictly speaking, for rectangular * matrices one should speak of "trapezoid" parts. This class is the return type - * of MatrixBase::triangularView() and most of the time this is the only way it is used. + * of MatrixBase::triangularView() and SparseMatrixBase::triangularView(), and most of the time this is the only way it is used. * * \sa MatrixBase::triangularView() */ @@ -137,490 +168,405 @@ namespace internal { template struct traits > : traits { - typedef typename nested::type MatrixTypeNested; + typedef typename ref_selector::non_const_type MatrixTypeNested; typedef typename remove_reference::type MatrixTypeNestedNonRef; typedef typename remove_all::type MatrixTypeNestedCleaned; + typedef typename MatrixType::PlainObject FullMatrixType; typedef MatrixType ExpressionType; - typedef typename MatrixType::PlainObject DenseMatrixType; enum { Mode = _Mode, - Flags = (MatrixTypeNestedCleaned::Flags & (HereditaryBits) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) | Mode, - CoeffReadCost = MatrixTypeNestedCleaned::CoeffReadCost + FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, + Flags = (MatrixTypeNestedCleaned::Flags & (HereditaryBits | FlagsLvalueBit) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) }; }; } -template -struct TriangularProduct; +template class TriangularViewImpl; template class TriangularView - : public TriangularBase > + : public TriangularViewImpl<_MatrixType, _Mode, typename internal::traits<_MatrixType>::StorageKind > { public: - typedef TriangularBase Base; + typedef TriangularViewImpl<_MatrixType, _Mode, typename internal::traits<_MatrixType>::StorageKind > Base; typedef typename internal::traits::Scalar Scalar; - typedef _MatrixType MatrixType; - typedef typename internal::traits::DenseMatrixType DenseMatrixType; - typedef DenseMatrixType PlainObject; protected: typedef typename internal::traits::MatrixTypeNested MatrixTypeNested; typedef typename internal::traits::MatrixTypeNestedNonRef MatrixTypeNestedNonRef; - typedef typename internal::traits::MatrixTypeNestedCleaned MatrixTypeNestedCleaned; typedef typename internal::remove_all::type MatrixConjugateReturnType; public: - using Base::evalToLazy; - typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; + typedef typename internal::traits::MatrixTypeNestedCleaned NestedExpression; enum { Mode = _Mode, + Flags = internal::traits::Flags, TransposeMode = (Mode & Upper ? Lower : 0) | (Mode & Lower ? Upper : 0) | (Mode & (UnitDiag)) - | (Mode & (ZeroDiag)) + | (Mode & (ZeroDiag)), + IsVectorAtCompileTime = false }; - inline TriangularView(const MatrixType& matrix) : m_matrix(matrix) + EIGEN_DEVICE_FUNC + explicit inline TriangularView(MatrixType& matrix) : m_matrix(matrix) {} + + using Base::operator=; + TriangularView& operator=(const TriangularView &other) + { return Base::operator=(other); } + /** \copydoc EigenBase::rows() */ + EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.rows(); } + /** \copydoc EigenBase::cols() */ + EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.cols(); } - inline Index outerStride() const { return m_matrix.outerStride(); } - inline Index innerStride() const { return m_matrix.innerStride(); } + + /** \returns a const reference to the nested expression */ + EIGEN_DEVICE_FUNC + const NestedExpression& nestedExpression() const { return m_matrix; } + + /** \returns a reference to the nested expression */ + EIGEN_DEVICE_FUNC + NestedExpression& nestedExpression() { return m_matrix; } + + typedef TriangularView ConjugateReturnType; + /** \sa MatrixBase::conjugate() const */ + EIGEN_DEVICE_FUNC + inline const ConjugateReturnType conjugate() const + { return ConjugateReturnType(m_matrix.conjugate()); } + + typedef TriangularView AdjointReturnType; + /** \sa MatrixBase::adjoint() const */ + EIGEN_DEVICE_FUNC + inline const AdjointReturnType adjoint() const + { return AdjointReturnType(m_matrix.adjoint()); } + + typedef TriangularView TransposeReturnType; + /** \sa MatrixBase::transpose() */ + EIGEN_DEVICE_FUNC + inline TransposeReturnType transpose() + { + EIGEN_STATIC_ASSERT_LVALUE(MatrixType) + typename MatrixType::TransposeReturnType tmp(m_matrix); + return TransposeReturnType(tmp); + } + + typedef TriangularView ConstTransposeReturnType; + /** \sa MatrixBase::transpose() const */ + EIGEN_DEVICE_FUNC + inline const ConstTransposeReturnType transpose() const + { + return ConstTransposeReturnType(m_matrix.transpose()); + } + + template + EIGEN_DEVICE_FUNC + inline const Solve + solve(const MatrixBase& other) const + { return Solve(*this, other.derived()); } + + // workaround MSVC ICE + #if EIGEN_COMP_MSVC + template + EIGEN_DEVICE_FUNC + inline const internal::triangular_solve_retval + solve(const MatrixBase& other) const + { return Base::template solve(other); } + #else + using Base::solve; + #endif + + /** \returns a selfadjoint view of the referenced triangular part which must be either \c #Upper or \c #Lower. + * + * This is a shortcut for \code this->nestedExpression().selfadjointView<(*this)::Mode>() \endcode + * \sa MatrixBase::selfadjointView() */ + EIGEN_DEVICE_FUNC + SelfAdjointView selfadjointView() + { + EIGEN_STATIC_ASSERT((Mode&(UnitDiag|ZeroDiag))==0,PROGRAMMING_ERROR); + return SelfAdjointView(m_matrix); + } + + /** This is the const version of selfadjointView() */ + EIGEN_DEVICE_FUNC + const SelfAdjointView selfadjointView() const + { + EIGEN_STATIC_ASSERT((Mode&(UnitDiag|ZeroDiag))==0,PROGRAMMING_ERROR); + return SelfAdjointView(m_matrix); + } + + + /** \returns the determinant of the triangular matrix + * \sa MatrixBase::determinant() */ + EIGEN_DEVICE_FUNC + Scalar determinant() const + { + if (Mode & UnitDiag) + return 1; + else if (Mode & ZeroDiag) + return 0; + else + return m_matrix.diagonal().prod(); + } + + protected: + + MatrixTypeNested m_matrix; +}; + +/** \ingroup Core_Module + * + * \brief Base class for a triangular part in a \b dense matrix + * + * This class is an abstract base class of class TriangularView, and objects of type TriangularViewImpl cannot be instantiated. + * It extends class TriangularView with additional methods which available for dense expressions only. + * + * \sa class TriangularView, MatrixBase::triangularView() + */ +template class TriangularViewImpl<_MatrixType,_Mode,Dense> + : public TriangularBase > +{ + public: + + typedef TriangularView<_MatrixType, _Mode> TriangularViewType; + typedef TriangularBase Base; + typedef typename internal::traits::Scalar Scalar; + + typedef _MatrixType MatrixType; + typedef typename MatrixType::PlainObject DenseMatrixType; + typedef DenseMatrixType PlainObject; + + public: + using Base::evalToLazy; + using Base::derived; + + typedef typename internal::traits::StorageKind StorageKind; + + enum { + Mode = _Mode, + Flags = internal::traits::Flags + }; + + /** \returns the outer-stride of the underlying dense matrix + * \sa DenseCoeffsBase::outerStride() */ + EIGEN_DEVICE_FUNC + inline Index outerStride() const { return derived().nestedExpression().outerStride(); } + /** \returns the inner-stride of the underlying dense matrix + * \sa DenseCoeffsBase::innerStride() */ + EIGEN_DEVICE_FUNC + inline Index innerStride() const { return derived().nestedExpression().innerStride(); } /** \sa MatrixBase::operator+=() */ - template TriangularView& operator+=(const DenseBase& other) { return *this = m_matrix + other.derived(); } + template + EIGEN_DEVICE_FUNC + TriangularViewType& operator+=(const DenseBase& other) { + internal::call_assignment_no_alias(derived(), other.derived(), internal::add_assign_op()); + return derived(); + } /** \sa MatrixBase::operator-=() */ - template TriangularView& operator-=(const DenseBase& other) { return *this = m_matrix - other.derived(); } + template + EIGEN_DEVICE_FUNC + TriangularViewType& operator-=(const DenseBase& other) { + internal::call_assignment_no_alias(derived(), other.derived(), internal::sub_assign_op()); + return derived(); + } + /** \sa MatrixBase::operator*=() */ - TriangularView& operator*=(const typename internal::traits::Scalar& other) { return *this = m_matrix * other; } - /** \sa MatrixBase::operator/=() */ - TriangularView& operator/=(const typename internal::traits::Scalar& other) { return *this = m_matrix / other; } + EIGEN_DEVICE_FUNC + TriangularViewType& operator*=(const typename internal::traits::Scalar& other) { return *this = derived().nestedExpression() * other; } + /** \sa DenseBase::operator/=() */ + EIGEN_DEVICE_FUNC + TriangularViewType& operator/=(const typename internal::traits::Scalar& other) { return *this = derived().nestedExpression() / other; } /** \sa MatrixBase::fill() */ + EIGEN_DEVICE_FUNC void fill(const Scalar& value) { setConstant(value); } /** \sa MatrixBase::setConstant() */ - TriangularView& setConstant(const Scalar& value) - { return *this = MatrixType::Constant(rows(), cols(), value); } + EIGEN_DEVICE_FUNC + TriangularViewType& setConstant(const Scalar& value) + { return *this = MatrixType::Constant(derived().rows(), derived().cols(), value); } /** \sa MatrixBase::setZero() */ - TriangularView& setZero() { return setConstant(Scalar(0)); } + EIGEN_DEVICE_FUNC + TriangularViewType& setZero() { return setConstant(Scalar(0)); } /** \sa MatrixBase::setOnes() */ - TriangularView& setOnes() { return setConstant(Scalar(1)); } + EIGEN_DEVICE_FUNC + TriangularViewType& setOnes() { return setConstant(Scalar(1)); } /** \sa MatrixBase::coeff() * \warning the coordinates must fit into the referenced triangular part */ + EIGEN_DEVICE_FUNC inline Scalar coeff(Index row, Index col) const { Base::check_coordinates_internal(row, col); - return m_matrix.coeff(row, col); + return derived().nestedExpression().coeff(row, col); } /** \sa MatrixBase::coeffRef() * \warning the coordinates must fit into the referenced triangular part */ + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) { + EIGEN_STATIC_ASSERT_LVALUE(TriangularViewType); Base::check_coordinates_internal(row, col); - return m_matrix.const_cast_derived().coeffRef(row, col); + return derived().nestedExpression().coeffRef(row, col); } - const MatrixTypeNestedCleaned& nestedExpression() const { return m_matrix; } - MatrixTypeNestedCleaned& nestedExpression() { return *const_cast(&m_matrix); } - /** Assigns a triangular matrix to a triangular part of a dense matrix */ template - TriangularView& operator=(const TriangularBase& other); + EIGEN_DEVICE_FUNC + TriangularViewType& operator=(const TriangularBase& other); + /** Shortcut for\code *this = other.other.triangularView<(*this)::Mode>() \endcode */ template - TriangularView& operator=(const MatrixBase& other); + EIGEN_DEVICE_FUNC + TriangularViewType& operator=(const MatrixBase& other); - TriangularView& operator=(const TriangularView& other) - { return *this = other.nestedExpression(); } +#ifndef EIGEN_PARSED_BY_DOXYGEN + EIGEN_DEVICE_FUNC + TriangularViewType& operator=(const TriangularViewImpl& other) + { return *this = other.derived().nestedExpression(); } + /** \deprecated */ template + EIGEN_DEVICE_FUNC void lazyAssign(const TriangularBase& other); + /** \deprecated */ template + EIGEN_DEVICE_FUNC void lazyAssign(const MatrixBase& other); - - /** \sa MatrixBase::conjugate() */ - inline TriangularView conjugate() - { return m_matrix.conjugate(); } - /** \sa MatrixBase::conjugate() const */ - inline const TriangularView conjugate() const - { return m_matrix.conjugate(); } - - /** \sa MatrixBase::adjoint() const */ - inline const TriangularView adjoint() const - { return m_matrix.adjoint(); } - - /** \sa MatrixBase::transpose() */ - inline TriangularView,TransposeMode> transpose() - { - EIGEN_STATIC_ASSERT_LVALUE(MatrixType) - return m_matrix.const_cast_derived().transpose(); - } - /** \sa MatrixBase::transpose() const */ - inline const TriangularView,TransposeMode> transpose() const - { - return m_matrix.transpose(); - } +#endif /** Efficient triangular matrix times vector/matrix product */ template - TriangularProduct + EIGEN_DEVICE_FUNC + const Product operator*(const MatrixBase& rhs) const { - return TriangularProduct - - (m_matrix, rhs.derived()); + return Product(derived(), rhs.derived()); } /** Efficient vector/matrix times triangular matrix product */ template friend - TriangularProduct - operator*(const MatrixBase& lhs, const TriangularView& rhs) - { - return TriangularProduct - - (lhs.derived(),rhs.m_matrix); - } - - #ifdef EIGEN2_SUPPORT - template - struct eigen2_product_return_type - { - typedef typename TriangularView::DenseMatrixType DenseMatrixType; - typedef typename OtherDerived::PlainObject::DenseType OtherPlainObject; - typedef typename ProductReturnType::Type ProdRetType; - typedef typename ProdRetType::PlainObject type; - }; - template - const typename eigen2_product_return_type::type - operator*(const EigenBase& rhs) const - { - typename OtherDerived::PlainObject::DenseType rhsPlainObject; - rhs.evalTo(rhsPlainObject); - return this->toDenseMatrix() * rhsPlainObject; - } - template - bool isApprox(const TriangularView& other, typename NumTraits::Real precision = NumTraits::dummy_precision()) const - { - return this->toDenseMatrix().isApprox(other.toDenseMatrix(), precision); - } - template - bool isApprox(const MatrixBase& other, typename NumTraits::Real precision = NumTraits::dummy_precision()) const - { - return this->toDenseMatrix().isApprox(other, precision); - } - #endif // EIGEN2_SUPPORT - + EIGEN_DEVICE_FUNC + const Product + operator*(const MatrixBase& lhs, const TriangularViewImpl& rhs) + { + return Product(lhs.derived(),rhs.derived()); + } + + /** \returns the product of the inverse of \c *this with \a other, \a *this being triangular. + * + * This function computes the inverse-matrix matrix product inverse(\c *this) * \a other if + * \a Side==OnTheLeft (the default), or the right-inverse-multiply \a other * inverse(\c *this) if + * \a Side==OnTheRight. + * + * Note that the template parameter \c Side can be ommitted, in which case \c Side==OnTheLeft + * + * The matrix \c *this must be triangular and invertible (i.e., all the coefficients of the + * diagonal must be non zero). It works as a forward (resp. backward) substitution if \c *this + * is an upper (resp. lower) triangular matrix. + * + * Example: \include Triangular_solve.cpp + * Output: \verbinclude Triangular_solve.out + * + * This function returns an expression of the inverse-multiply and can works in-place if it is assigned + * to the same matrix or vector \a other. + * + * For users coming from BLAS, this function (and more specifically solveInPlace()) offer + * all the operations supported by the \c *TRSV and \c *TRSM BLAS routines. + * + * \sa TriangularView::solveInPlace() + */ template - inline const internal::triangular_solve_retval + EIGEN_DEVICE_FUNC + inline const internal::triangular_solve_retval solve(const MatrixBase& other) const; + /** "in-place" version of TriangularView::solve() where the result is written in \a other + * + * \warning The parameter is only marked 'const' to make the C++ compiler accept a temporary expression here. + * This function will const_cast it, so constness isn't honored here. + * + * Note that the template parameter \c Side can be ommitted, in which case \c Side==OnTheLeft + * + * See TriangularView:solve() for the details. + */ template + EIGEN_DEVICE_FUNC void solveInPlace(const MatrixBase& other) const; - template - inline const internal::triangular_solve_retval - solve(const MatrixBase& other) const - { return solve(other); } - template + EIGEN_DEVICE_FUNC void solveInPlace(const MatrixBase& other) const { return solveInPlace(other); } - const SelfAdjointView selfadjointView() const - { - EIGEN_STATIC_ASSERT((Mode&UnitDiag)==0,PROGRAMMING_ERROR); - return SelfAdjointView(m_matrix); - } - SelfAdjointView selfadjointView() - { - EIGEN_STATIC_ASSERT((Mode&UnitDiag)==0,PROGRAMMING_ERROR); - return SelfAdjointView(m_matrix); - } - + /** Swaps the coefficients of the common triangular parts of two matrices */ template + EIGEN_DEVICE_FUNC +#ifdef EIGEN_PARSED_BY_DOXYGEN + void swap(TriangularBase &other) +#else void swap(TriangularBase const & other) +#endif { - TriangularView,Mode>(const_cast(m_matrix)).lazyAssign(other.derived()); + EIGEN_STATIC_ASSERT_LVALUE(OtherDerived); + call_assignment(derived(), other.const_cast_derived(), internal::swap_assign_op()); } + /** \deprecated + * Shortcut for \code (*this).swap(other.triangularView<(*this)::Mode>()) \endcode */ template + EIGEN_DEVICE_FUNC void swap(MatrixBase const & other) { - SwapWrapper swaper(const_cast(m_matrix)); - TriangularView,Mode>(swaper).lazyAssign(other.derived()); + EIGEN_STATIC_ASSERT_LVALUE(OtherDerived); + call_assignment(derived(), other.const_cast_derived(), internal::swap_assign_op()); } - Scalar determinant() const - { - if (Mode & UnitDiag) - return 1; - else if (Mode & ZeroDiag) - return 0; - else - return m_matrix.diagonal().prod(); - } - - // TODO simplify the following: - template - EIGEN_STRONG_INLINE TriangularView& operator=(const ProductBase& other) - { - setZero(); - return assignProduct(other,1); - } - - template - EIGEN_STRONG_INLINE TriangularView& operator+=(const ProductBase& other) - { - return assignProduct(other,1); + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _solve_impl(const RhsType &rhs, DstType &dst) const { + if(!internal::is_same_dense(dst,rhs)) + dst = rhs; + this->solveInPlace(dst); } - - template - EIGEN_STRONG_INLINE TriangularView& operator-=(const ProductBase& other) - { - return assignProduct(other,-1); - } - - - template - EIGEN_STRONG_INLINE TriangularView& operator=(const ScaledProduct& other) - { - setZero(); - return assignProduct(other,other.alpha()); - } - - template - EIGEN_STRONG_INLINE TriangularView& operator+=(const ScaledProduct& other) - { - return assignProduct(other,other.alpha()); - } - - template - EIGEN_STRONG_INLINE TriangularView& operator-=(const ScaledProduct& other) - { - return assignProduct(other,-other.alpha()); - } - - protected: - - template - EIGEN_STRONG_INLINE TriangularView& assignProduct(const ProductBase& prod, const Scalar& alpha); - MatrixTypeNested m_matrix; + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TriangularViewType& _assignProduct(const ProductType& prod, const Scalar& alpha, bool beta); }; /*************************************************************************** * Implementation of triangular evaluation/assignment ***************************************************************************/ -namespace internal { - -template -struct triangular_assignment_selector -{ - enum { - col = (UnrollCount-1) / Derived1::RowsAtCompileTime, - row = (UnrollCount-1) % Derived1::RowsAtCompileTime - }; - - typedef typename Derived1::Scalar Scalar; - - static inline void run(Derived1 &dst, const Derived2 &src) - { - triangular_assignment_selector::run(dst, src); - - eigen_assert( Mode == Upper || Mode == Lower - || Mode == StrictlyUpper || Mode == StrictlyLower - || Mode == UnitUpper || Mode == UnitLower); - if((Mode == Upper && row <= col) - || (Mode == Lower && row >= col) - || (Mode == StrictlyUpper && row < col) - || (Mode == StrictlyLower && row > col) - || (Mode == UnitUpper && row < col) - || (Mode == UnitLower && row > col)) - dst.copyCoeff(row, col, src); - else if(ClearOpposite) - { - if (Mode&UnitDiag && row==col) - dst.coeffRef(row, col) = Scalar(1); - else - dst.coeffRef(row, col) = Scalar(0); - } - } -}; - -// prevent buggy user code from causing an infinite recursion -template -struct triangular_assignment_selector -{ - static inline void run(Derived1 &, const Derived2 &) {} -}; - -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - typedef typename Derived1::Scalar Scalar; - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - Index maxi = (std::min)(j, dst.rows()-1); - for(Index i = 0; i <= maxi; ++i) - dst.copyCoeff(i, j, src); - if (ClearOpposite) - for(Index i = maxi+1; i < dst.rows(); ++i) - dst.coeffRef(i, j) = Scalar(0); - } - } -}; - -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - for(Index i = j; i < dst.rows(); ++i) - dst.copyCoeff(i, j, src); - Index maxi = (std::min)(j, dst.rows()); - if (ClearOpposite) - for(Index i = 0; i < maxi; ++i) - dst.coeffRef(i, j) = static_cast(0); - } - } -}; - -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - typedef typename Derived1::Scalar Scalar; - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - Index maxi = (std::min)(j, dst.rows()); - for(Index i = 0; i < maxi; ++i) - dst.copyCoeff(i, j, src); - if (ClearOpposite) - for(Index i = maxi; i < dst.rows(); ++i) - dst.coeffRef(i, j) = Scalar(0); - } - } -}; - -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - for(Index i = j+1; i < dst.rows(); ++i) - dst.copyCoeff(i, j, src); - Index maxi = (std::min)(j, dst.rows()-1); - if (ClearOpposite) - for(Index i = 0; i <= maxi; ++i) - dst.coeffRef(i, j) = static_cast(0); - } - } -}; - -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - Index maxi = (std::min)(j, dst.rows()); - for(Index i = 0; i < maxi; ++i) - dst.copyCoeff(i, j, src); - if (ClearOpposite) - { - for(Index i = maxi+1; i < dst.rows(); ++i) - dst.coeffRef(i, j) = 0; - } - } - dst.diagonal().setOnes(); - } -}; -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - Index maxi = (std::min)(j, dst.rows()); - for(Index i = maxi+1; i < dst.rows(); ++i) - dst.copyCoeff(i, j, src); - if (ClearOpposite) - { - for(Index i = 0; i < maxi; ++i) - dst.coeffRef(i, j) = 0; - } - } - dst.diagonal().setOnes(); - } -}; - -} // end namespace internal - +#ifndef EIGEN_PARSED_BY_DOXYGEN // FIXME should we keep that possibility template template inline TriangularView& -TriangularView::operator=(const MatrixBase& other) +TriangularViewImpl::operator=(const MatrixBase& other) { - if(OtherDerived::Flags & EvalBeforeAssigningBit) - { - typename internal::plain_matrix_type::type other_evaluated(other.rows(), other.cols()); - other_evaluated.template triangularView().lazyAssign(other.derived()); - lazyAssign(other_evaluated); - } - else - lazyAssign(other.derived()); - return *this; + internal::call_assignment_no_alias(derived(), other.derived(), internal::assign_op()); + return derived(); } // FIXME should we keep that possibility template template -void TriangularView::lazyAssign(const MatrixBase& other) +void TriangularViewImpl::lazyAssign(const MatrixBase& other) { - enum { - unroll = MatrixType::SizeAtCompileTime != Dynamic - && internal::traits::CoeffReadCost != Dynamic - && MatrixType::SizeAtCompileTime*internal::traits::CoeffReadCost/2 <= EIGEN_UNROLLING_LIMIT - }; - eigen_assert(m_matrix.rows() == other.rows() && m_matrix.cols() == other.cols()); - - internal::triangular_assignment_selector - ::run(m_matrix.const_cast_derived(), other.derived()); + internal::call_assignment_no_alias(derived(), other.template triangularView()); } @@ -628,38 +574,21 @@ void TriangularView::lazyAssign(const MatrixBase template template inline TriangularView& -TriangularView::operator=(const TriangularBase& other) +TriangularViewImpl::operator=(const TriangularBase& other) { eigen_assert(Mode == int(OtherDerived::Mode)); - if(internal::traits::Flags & EvalBeforeAssigningBit) - { - typename OtherDerived::DenseMatrixType other_evaluated(other.rows(), other.cols()); - other_evaluated.template triangularView().lazyAssign(other.derived().nestedExpression()); - lazyAssign(other_evaluated); - } - else - lazyAssign(other.derived().nestedExpression()); - return *this; + internal::call_assignment(derived(), other.derived()); + return derived(); } template template -void TriangularView::lazyAssign(const TriangularBase& other) +void TriangularViewImpl::lazyAssign(const TriangularBase& other) { - enum { - unroll = MatrixType::SizeAtCompileTime != Dynamic - && internal::traits::CoeffReadCost != Dynamic - && MatrixType::SizeAtCompileTime * internal::traits::CoeffReadCost / 2 - <= EIGEN_UNROLLING_LIMIT - }; - eigen_assert(m_matrix.rows() == other.rows() && m_matrix.cols() == other.cols()); - - internal::triangular_assignment_selector - ::run(m_matrix.const_cast_derived(), other.derived().nestedExpression()); + eigen_assert(Mode == int(OtherDerived::Mode)); + internal::call_assignment_no_alias(derived(), other.derived()); } +#endif /*************************************************************************** * Implementation of TriangularBase methods @@ -671,35 +600,7 @@ template template void TriangularBase::evalTo(MatrixBase &other) const { - if(internal::traits::Flags & EvalBeforeAssigningBit) - { - typename internal::plain_matrix_type::type other_evaluated(rows(), cols()); - evalToLazy(other_evaluated); - other.derived().swap(other_evaluated); - } - else - evalToLazy(other.derived()); -} - -/** Assigns a triangular or selfadjoint matrix to a dense matrix. - * If the matrix is triangular, the opposite part is set to zero. */ -template -template -void TriangularBase::evalToLazy(MatrixBase &other) const -{ - enum { - unroll = DenseDerived::SizeAtCompileTime != Dynamic - && internal::traits::CoeffReadCost != Dynamic - && DenseDerived::SizeAtCompileTime * internal::traits::CoeffReadCost / 2 - <= EIGEN_UNROLLING_LIMIT - }; - other.derived().resize(this->rows(), this->cols()); - - internal::triangular_assignment_selector - ::MatrixTypeNestedCleaned, Derived::Mode, - unroll ? int(DenseDerived::SizeAtCompileTime) : Dynamic, - true // clear the opposite triangular part - >::run(other.derived(), derived().nestedExpression()); + evalToLazy(other.derived()); } /*************************************************************************** @@ -710,49 +611,14 @@ void TriangularBase::evalToLazy(MatrixBase &other) const * Implementation of MatrixBase methods ***************************************************************************/ -#ifdef EIGEN2_SUPPORT - -// implementation of part<>(), including the SelfAdjoint case. - -namespace internal { -template -struct eigen2_part_return_type -{ - typedef TriangularView type; -}; - -template -struct eigen2_part_return_type -{ - typedef SelfAdjointView type; -}; -} - -/** \deprecated use MatrixBase::triangularView() */ -template -template -const typename internal::eigen2_part_return_type::type MatrixBase::part() const -{ - return derived(); -} - -/** \deprecated use MatrixBase::triangularView() */ -template -template -typename internal::eigen2_part_return_type::type MatrixBase::part() -{ - return derived(); -} -#endif - /** * \returns an expression of a triangular view extracted from the current matrix * * The parameter \a Mode can have the following values: \c #Upper, \c #StrictlyUpper, \c #UnitUpper, * \c #Lower, \c #StrictlyLower, \c #UnitLower. * - * Example: \include MatrixBase_extract.cpp - * Output: \verbinclude MatrixBase_extract.out + * Example: \include MatrixBase_triangularView.cpp + * Output: \verbinclude MatrixBase_triangularView.out * * \sa class TriangularView */ @@ -761,7 +627,7 @@ template typename MatrixBase::template TriangularViewReturnType::Type MatrixBase::triangularView() { - return derived(); + return typename TriangularViewReturnType::Type(derived()); } /** This is the const version of MatrixBase::triangularView() */ @@ -770,7 +636,7 @@ template typename MatrixBase::template ConstTriangularViewReturnType::Type MatrixBase::triangularView() const { - return derived(); + return typename ConstTriangularViewReturnType::Type(derived()); } /** \returns true if *this is approximately equal to an upper triangular matrix, @@ -781,21 +647,20 @@ MatrixBase::triangularView() const template bool MatrixBase::isUpperTriangular(const RealScalar& prec) const { - using std::abs; RealScalar maxAbsOnUpperPart = static_cast(-1); for(Index j = 0; j < cols(); ++j) { - Index maxi = (std::min)(j, rows()-1); + Index maxi = numext::mini(j, rows()-1); for(Index i = 0; i <= maxi; ++i) { - RealScalar absValue = abs(coeff(i,j)); + RealScalar absValue = numext::abs(coeff(i,j)); if(absValue > maxAbsOnUpperPart) maxAbsOnUpperPart = absValue; } } RealScalar threshold = maxAbsOnUpperPart * prec; for(Index j = 0; j < cols(); ++j) for(Index i = j+1; i < rows(); ++i) - if(abs(coeff(i, j)) > threshold) return false; + if(numext::abs(coeff(i, j)) > threshold) return false; return true; } @@ -807,24 +672,312 @@ bool MatrixBase::isUpperTriangular(const RealScalar& prec) const template bool MatrixBase::isLowerTriangular(const RealScalar& prec) const { - using std::abs; RealScalar maxAbsOnLowerPart = static_cast(-1); for(Index j = 0; j < cols(); ++j) for(Index i = j; i < rows(); ++i) { - RealScalar absValue = abs(coeff(i,j)); + RealScalar absValue = numext::abs(coeff(i,j)); if(absValue > maxAbsOnLowerPart) maxAbsOnLowerPart = absValue; } RealScalar threshold = maxAbsOnLowerPart * prec; for(Index j = 1; j < cols(); ++j) { - Index maxi = (std::min)(j, rows()-1); + Index maxi = numext::mini(j, rows()-1); for(Index i = 0; i < maxi; ++i) - if(abs(coeff(i, j)) > threshold) return false; + if(numext::abs(coeff(i, j)) > threshold) return false; } return true; } + +/*************************************************************************** +**************************************************************************** +* Evaluators and Assignment of triangular expressions +*************************************************************************** +***************************************************************************/ + +namespace internal { + + +// TODO currently a triangular expression has the form TriangularView<.,.> +// in the future triangular-ness should be defined by the expression traits +// such that Transpose > is valid. (currently TriangularBase::transpose() is overloaded to make it work) +template +struct evaluator_traits > +{ + typedef typename storage_kind_to_evaluator_kind::Kind Kind; + typedef typename glue_shapes::Shape, TriangularShape>::type Shape; +}; + +template +struct unary_evaluator, IndexBased> + : evaluator::type> +{ + typedef TriangularView XprType; + typedef evaluator::type> Base; + unary_evaluator(const XprType &xpr) : Base(xpr.nestedExpression()) {} +}; + +// Additional assignment kinds: +struct Triangular2Triangular {}; +struct Triangular2Dense {}; +struct Dense2Triangular {}; + + +template struct triangular_assignment_loop; + + +/** \internal Specialization of the dense assignment kernel for triangular matrices. + * The main difference is that the triangular, diagonal, and opposite parts are processed through three different functions. + * \tparam UpLo must be either Lower or Upper + * \tparam Mode must be either 0, UnitDiag, ZeroDiag, or SelfAdjoint + */ +template +class triangular_dense_assignment_kernel : public generic_dense_assignment_kernel +{ +protected: + typedef generic_dense_assignment_kernel Base; + typedef typename Base::DstXprType DstXprType; + typedef typename Base::SrcXprType SrcXprType; + using Base::m_dst; + using Base::m_src; + using Base::m_functor; +public: + + typedef typename Base::DstEvaluatorType DstEvaluatorType; + typedef typename Base::SrcEvaluatorType SrcEvaluatorType; + typedef typename Base::Scalar Scalar; + typedef typename Base::AssignmentTraits AssignmentTraits; + + + EIGEN_DEVICE_FUNC triangular_dense_assignment_kernel(DstEvaluatorType &dst, const SrcEvaluatorType &src, const Functor &func, DstXprType& dstExpr) + : Base(dst, src, func, dstExpr) + {} + +#ifdef EIGEN_INTERNAL_DEBUGGING + EIGEN_DEVICE_FUNC void assignCoeff(Index row, Index col) + { + eigen_internal_assert(row!=col); + Base::assignCoeff(row,col); + } +#else + using Base::assignCoeff; +#endif + + EIGEN_DEVICE_FUNC void assignDiagonalCoeff(Index id) + { + if(Mode==UnitDiag && SetOpposite) m_functor.assignCoeff(m_dst.coeffRef(id,id), Scalar(1)); + else if(Mode==ZeroDiag && SetOpposite) m_functor.assignCoeff(m_dst.coeffRef(id,id), Scalar(0)); + else if(Mode==0) Base::assignCoeff(id,id); + } + + EIGEN_DEVICE_FUNC void assignOppositeCoeff(Index row, Index col) + { + eigen_internal_assert(row!=col); + if(SetOpposite) + m_functor.assignCoeff(m_dst.coeffRef(row,col), Scalar(0)); + } +}; + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_triangular_assignment_loop(DstXprType& dst, const SrcXprType& src, const Functor &func) +{ + typedef evaluator DstEvaluatorType; + typedef evaluator SrcEvaluatorType; + + SrcEvaluatorType srcEvaluator(src); + + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + DstEvaluatorType dstEvaluator(dst); + + typedef triangular_dense_assignment_kernel< Mode&(Lower|Upper),Mode&(UnitDiag|ZeroDiag|SelfAdjoint),SetOpposite, + DstEvaluatorType,SrcEvaluatorType,Functor> Kernel; + Kernel kernel(dstEvaluator, srcEvaluator, func, dst.const_cast_derived()); + + enum { + unroll = DstXprType::SizeAtCompileTime != Dynamic + && SrcEvaluatorType::CoeffReadCost < HugeCost + && DstXprType::SizeAtCompileTime * (DstEvaluatorType::CoeffReadCost+SrcEvaluatorType::CoeffReadCost) / 2 <= EIGEN_UNROLLING_LIMIT + }; + + triangular_assignment_loop::run(kernel); +} + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_triangular_assignment_loop(DstXprType& dst, const SrcXprType& src) +{ + call_triangular_assignment_loop(dst, src, internal::assign_op()); +} + +template<> struct AssignmentKind { typedef Triangular2Triangular Kind; }; +template<> struct AssignmentKind { typedef Triangular2Dense Kind; }; +template<> struct AssignmentKind { typedef Dense2Triangular Kind; }; + + +template< typename DstXprType, typename SrcXprType, typename Functor> +struct Assignment +{ + EIGEN_DEVICE_FUNC static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) + { + eigen_assert(int(DstXprType::Mode) == int(SrcXprType::Mode)); + + call_triangular_assignment_loop(dst, src, func); + } +}; + +template< typename DstXprType, typename SrcXprType, typename Functor> +struct Assignment +{ + EIGEN_DEVICE_FUNC static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) + { + call_triangular_assignment_loop(dst, src, func); + } +}; + +template< typename DstXprType, typename SrcXprType, typename Functor> +struct Assignment +{ + EIGEN_DEVICE_FUNC static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) + { + call_triangular_assignment_loop(dst, src, func); + } +}; + + +template +struct triangular_assignment_loop +{ + // FIXME: this is not very clean, perhaps this information should be provided by the kernel? + typedef typename Kernel::DstEvaluatorType DstEvaluatorType; + typedef typename DstEvaluatorType::XprType DstXprType; + + enum { + col = (UnrollCount-1) / DstXprType::RowsAtCompileTime, + row = (UnrollCount-1) % DstXprType::RowsAtCompileTime + }; + + typedef typename Kernel::Scalar Scalar; + + EIGEN_DEVICE_FUNC + static inline void run(Kernel &kernel) + { + triangular_assignment_loop::run(kernel); + + if(row==col) + kernel.assignDiagonalCoeff(row); + else if( ((Mode&Lower) && row>col) || ((Mode&Upper) && row +struct triangular_assignment_loop +{ + EIGEN_DEVICE_FUNC + static inline void run(Kernel &) {} +}; + + + +// TODO: experiment with a recursive assignment procedure splitting the current +// triangular part into one rectangular and two triangular parts. + + +template +struct triangular_assignment_loop +{ + typedef typename Kernel::Scalar Scalar; + EIGEN_DEVICE_FUNC + static inline void run(Kernel &kernel) + { + for(Index j = 0; j < kernel.cols(); ++j) + { + Index maxi = numext::mini(j, kernel.rows()); + Index i = 0; + if (((Mode&Lower) && SetOpposite) || (Mode&Upper)) + { + for(; i < maxi; ++i) + if(Mode&Upper) kernel.assignCoeff(i, j); + else kernel.assignOppositeCoeff(i, j); + } + else + i = maxi; + + if(i +template +void TriangularBase::evalToLazy(MatrixBase &other) const +{ + other.derived().resize(this->rows(), this->cols()); + internal::call_triangular_assignment_loop(other.derived(), derived().nestedExpression()); +} + +namespace internal { + +// Triangular = Product +template< typename DstXprType, typename Lhs, typename Rhs, typename Scalar> +struct Assignment, internal::assign_op::Scalar>, Dense2Triangular> +{ + typedef Product SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + dst._assignProduct(src, 1, 0); + } +}; + +// Triangular += Product +template< typename DstXprType, typename Lhs, typename Rhs, typename Scalar> +struct Assignment, internal::add_assign_op::Scalar>, Dense2Triangular> +{ + typedef Product SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &) + { + dst._assignProduct(src, 1, 1); + } +}; + +// Triangular -= Product +template< typename DstXprType, typename Lhs, typename Rhs, typename Scalar> +struct Assignment, internal::sub_assign_op::Scalar>, Dense2Triangular> +{ + typedef Product SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &) + { + dst._assignProduct(src, -1, 1); + } +}; + +} // end namespace internal + } // end namespace Eigen #endif // EIGEN_TRIANGULARMATRIX_H diff --git a/libs/eigen3/Eigen/src/Core/VectorBlock.h b/libs/eigen3/Eigen/src/Core/VectorBlock.h index 1a7330f3c..d72fbf7e9 100644 --- a/libs/eigen3/Eigen/src/Core/VectorBlock.h +++ b/libs/eigen3/Eigen/src/Core/VectorBlock.h @@ -13,13 +13,23 @@ namespace Eigen { +namespace internal { +template +struct traits > + : public traits::Flags & RowMajorBit ? 1 : Size, + traits::Flags & RowMajorBit ? Size : 1> > +{ +}; +} + /** \class VectorBlock * \ingroup Core_Module * * \brief Expression of a fixed-size or dynamic-size sub-vector * - * \param VectorType the type of the object in which we are taking a sub-vector - * \param Size size of the sub-vector we are taking at compile time (optional) + * \tparam VectorType the type of the object in which we are taking a sub-vector + * \tparam Size size of the sub-vector we are taking at compile time (optional) * * This class represents an expression of either a fixed-size or dynamic-size sub-vector. * It is the return type of DenseBase::segment(Index,Index) and DenseBase::segment(Index) and @@ -43,17 +53,6 @@ namespace Eigen { * * \sa class Block, DenseBase::segment(Index,Index,Index,Index), DenseBase::segment(Index,Index) */ - -namespace internal { -template -struct traits > - : public traits::Flags & RowMajorBit ? 1 : Size, - traits::Flags & RowMajorBit ? Size : 1> > -{ -}; -} - template class VectorBlock : public Block::Flags & RowMajorBit ? 1 : Size, @@ -72,6 +71,7 @@ template class VectorBlock /** Dynamic-size constructor */ + EIGEN_DEVICE_FUNC inline VectorBlock(VectorType& vector, Index start, Index size) : Base(vector, IsColVector ? start : 0, IsColVector ? 0 : start, @@ -82,6 +82,7 @@ template class VectorBlock /** Fixed-size constructor */ + EIGEN_DEVICE_FUNC inline VectorBlock(VectorType& vector, Index start) : Base(vector, IsColVector ? start : 0, IsColVector ? 0 : start) { diff --git a/libs/eigen3/Eigen/src/Core/VectorwiseOp.h b/libs/eigen3/Eigen/src/Core/VectorwiseOp.h index d5ab03664..4fe267e9f 100644 --- a/libs/eigen3/Eigen/src/Core/VectorwiseOp.h +++ b/libs/eigen3/Eigen/src/Core/VectorwiseOp.h @@ -11,7 +11,7 @@ #ifndef EIGEN_PARTIAL_REDUX_H #define EIGEN_PARTIAL_REDUX_H -namespace Eigen { +namespace Eigen { /** \class PartialReduxExpr * \ingroup Core_Module @@ -41,64 +41,43 @@ struct traits > typedef typename traits::StorageKind StorageKind; typedef typename traits::XprKind XprKind; typedef typename MatrixType::Scalar InputScalar; - typedef typename nested::type MatrixTypeNested; - typedef typename remove_all::type _MatrixTypeNested; enum { RowsAtCompileTime = Direction==Vertical ? 1 : MatrixType::RowsAtCompileTime, ColsAtCompileTime = Direction==Horizontal ? 1 : MatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = Direction==Vertical ? 1 : MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = Direction==Horizontal ? 1 : MatrixType::MaxColsAtCompileTime, - Flags0 = (unsigned int)_MatrixTypeNested::Flags & HereditaryBits, - Flags = (Flags0 & ~RowMajorBit) | (RowsAtCompileTime == 1 ? RowMajorBit : 0), + Flags = RowsAtCompileTime == 1 ? RowMajorBit : 0, TraversalSize = Direction==Vertical ? MatrixType::RowsAtCompileTime : MatrixType::ColsAtCompileTime }; - #if EIGEN_GNUC_AT_LEAST(3,4) - typedef typename MemberOp::template Cost CostOpType; - #else - typedef typename MemberOp::template Cost CostOpType; - #endif - enum { - CoeffReadCost = TraversalSize==Dynamic ? Dynamic - : TraversalSize * traits<_MatrixTypeNested>::CoeffReadCost + int(CostOpType::value) - }; }; } template< typename MatrixType, typename MemberOp, int Direction> -class PartialReduxExpr : internal::no_assignment_operator, - public internal::dense_xpr_base< PartialReduxExpr >::type +class PartialReduxExpr : public internal::dense_xpr_base< PartialReduxExpr >::type, + internal::no_assignment_operator { public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(PartialReduxExpr) - typedef typename internal::traits::MatrixTypeNested MatrixTypeNested; - typedef typename internal::traits::_MatrixTypeNested _MatrixTypeNested; - PartialReduxExpr(const MatrixType& mat, const MemberOp& func = MemberOp()) + EIGEN_DEVICE_FUNC + explicit PartialReduxExpr(const MatrixType& mat, const MemberOp& func = MemberOp()) : m_matrix(mat), m_functor(func) {} + EIGEN_DEVICE_FUNC Index rows() const { return (Direction==Vertical ? 1 : m_matrix.rows()); } + EIGEN_DEVICE_FUNC Index cols() const { return (Direction==Horizontal ? 1 : m_matrix.cols()); } - EIGEN_STRONG_INLINE const Scalar coeff(Index i, Index j) const - { - if (Direction==Vertical) - return m_functor(m_matrix.col(j)); - else - return m_functor(m_matrix.row(i)); - } + EIGEN_DEVICE_FUNC + typename MatrixType::Nested nestedExpression() const { return m_matrix; } - const Scalar coeff(Index index) const - { - if (Direction==Vertical) - return m_functor(m_matrix.col(index)); - else - return m_functor(m_matrix.row(index)); - } + EIGEN_DEVICE_FUNC + const MemberOp& functor() const { return m_functor; } protected: - MatrixTypeNested m_matrix; + typename MatrixType::Nested m_matrix; const MemberOp m_functor; }; @@ -110,7 +89,8 @@ class PartialReduxExpr : internal::no_assignment_operator, template struct Cost \ { enum { value = COST }; }; \ template \ - EIGEN_STRONG_INLINE ResultType operator()(const XprType& mat) const \ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE \ + ResultType operator()(const XprType& mat) const \ { return mat.MEMBER(); } \ } @@ -130,17 +110,27 @@ EIGEN_MEMBER_FUNCTOR(any, (Size-1)*NumTraits::AddCost); EIGEN_MEMBER_FUNCTOR(count, (Size-1)*NumTraits::AddCost); EIGEN_MEMBER_FUNCTOR(prod, (Size-1)*NumTraits::MulCost); +template +struct member_lpnorm { + typedef ResultType result_type; + template struct Cost + { enum { value = (Size+5) * NumTraits::MulCost + (Size-1)*NumTraits::AddCost }; }; + EIGEN_DEVICE_FUNC member_lpnorm() {} + template + EIGEN_DEVICE_FUNC inline ResultType operator()(const XprType& mat) const + { return mat.template lpNorm

(); } +}; template struct member_redux { typedef typename result_of< - BinaryOp(Scalar) + BinaryOp(const Scalar&,const Scalar&) >::type result_type; template struct Cost { enum { value = (Size-1) * functor_traits::Cost }; }; - member_redux(const BinaryOp func) : m_functor(func) {} + EIGEN_DEVICE_FUNC explicit member_redux(const BinaryOp func) : m_functor(func) {} template - inline result_type operator()(const DenseBase& mat) const + EIGEN_DEVICE_FUNC inline result_type operator()(const DenseBase& mat) const { return mat.redux(m_functor); } const BinaryOp m_functor; }; @@ -151,8 +141,8 @@ struct member_redux { * * \brief Pseudo expression providing partial reduction operations * - * \param ExpressionType the type of the object on which to do partial reductions - * \param Direction indicates the direction of the redux (#Vertical or #Horizontal) + * \tparam ExpressionType the type of the object on which to do partial reductions + * \tparam Direction indicates the direction of the redux (#Vertical or #Horizontal) * * This class represents a pseudo expression with partial reduction features. * It is the return type of DenseBase::colwise() and DenseBase::rowwise() @@ -169,16 +159,15 @@ template class VectorwiseOp typedef typename ExpressionType::Scalar Scalar; typedef typename ExpressionType::RealScalar RealScalar; - typedef typename ExpressionType::Index Index; - typedef typename internal::conditional::ret, - ExpressionType, ExpressionType&>::type ExpressionTypeNested; + typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3 + typedef typename internal::ref_selector::non_const_type ExpressionTypeNested; typedef typename internal::remove_all::type ExpressionTypeNestedCleaned; template class Functor, - typename Scalar=typename internal::traits::Scalar> struct ReturnType + typename Scalar_=Scalar> struct ReturnType { typedef PartialReduxExpr, + Functor, Direction > Type; }; @@ -186,23 +175,24 @@ template class VectorwiseOp template struct ReduxReturnType { typedef PartialReduxExpr::Scalar>, + internal::member_redux, Direction > Type; }; enum { - IsVertical = (Direction==Vertical) ? 1 : 0, - IsHorizontal = (Direction==Horizontal) ? 1 : 0 + isVertical = (Direction==Vertical) ? 1 : 0, + isHorizontal = (Direction==Horizontal) ? 1 : 0 }; protected: - /** \internal - * \returns the i-th subvector according to the \c Direction */ - typedef typename internal::conditional::type SubVector; + /** \internal + * \returns the i-th subvector according to the \c Direction */ + EIGEN_DEVICE_FUNC SubVector subVector(Index i) { return SubVector(m_matrix.derived(),i); @@ -210,58 +200,62 @@ template class VectorwiseOp /** \internal * \returns the number of subvectors in the direction \c Direction */ + EIGEN_DEVICE_FUNC Index subVectors() const - { return Direction==Vertical?m_matrix.cols():m_matrix.rows(); } + { return isVertical?m_matrix.cols():m_matrix.rows(); } template struct ExtendedType { typedef Replicate Type; + isVertical ? 1 : ExpressionType::RowsAtCompileTime, + isHorizontal ? 1 : ExpressionType::ColsAtCompileTime> Type; }; /** \internal * Replicates a vector to match the size of \c *this */ template + EIGEN_DEVICE_FUNC typename ExtendedType::Type extendedTo(const DenseBase& other) const { - EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(Direction==Vertical, OtherDerived::MaxColsAtCompileTime==1), + EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(isVertical, OtherDerived::MaxColsAtCompileTime==1), YOU_PASSED_A_ROW_VECTOR_BUT_A_COLUMN_VECTOR_WAS_EXPECTED) - EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(Direction==Horizontal, OtherDerived::MaxRowsAtCompileTime==1), + EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(isHorizontal, OtherDerived::MaxRowsAtCompileTime==1), YOU_PASSED_A_COLUMN_VECTOR_BUT_A_ROW_VECTOR_WAS_EXPECTED) return typename ExtendedType::Type (other.derived(), - Direction==Vertical ? 1 : m_matrix.rows(), - Direction==Horizontal ? 1 : m_matrix.cols()); + isVertical ? 1 : m_matrix.rows(), + isHorizontal ? 1 : m_matrix.cols()); } - + template struct OppositeExtendedType { typedef Replicate Type; + isHorizontal ? 1 : ExpressionType::RowsAtCompileTime, + isVertical ? 1 : ExpressionType::ColsAtCompileTime> Type; }; /** \internal * Replicates a vector in the opposite direction to match the size of \c *this */ template + EIGEN_DEVICE_FUNC typename OppositeExtendedType::Type extendedToOpposite(const DenseBase& other) const { - EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(Direction==Horizontal, OtherDerived::MaxColsAtCompileTime==1), + EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(isHorizontal, OtherDerived::MaxColsAtCompileTime==1), YOU_PASSED_A_ROW_VECTOR_BUT_A_COLUMN_VECTOR_WAS_EXPECTED) - EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(Direction==Vertical, OtherDerived::MaxRowsAtCompileTime==1), + EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(isVertical, OtherDerived::MaxRowsAtCompileTime==1), YOU_PASSED_A_COLUMN_VECTOR_BUT_A_ROW_VECTOR_WAS_EXPECTED) return typename OppositeExtendedType::Type (other.derived(), - Direction==Horizontal ? 1 : m_matrix.rows(), - Direction==Vertical ? 1 : m_matrix.cols()); + isHorizontal ? 1 : m_matrix.rows(), + isVertical ? 1 : m_matrix.cols()); } public: - - inline VectorwiseOp(ExpressionType& matrix) : m_matrix(matrix) {} + EIGEN_DEVICE_FUNC + explicit inline VectorwiseOp(ExpressionType& matrix) : m_matrix(matrix) {} /** \internal */ + EIGEN_DEVICE_FUNC inline const ExpressionType& _expression() const { return m_matrix; } /** \returns a row or column vector expression of \c *this reduxed by \a func @@ -272,80 +266,126 @@ template class VectorwiseOp * \sa class VectorwiseOp, DenseBase::colwise(), DenseBase::rowwise() */ template + EIGEN_DEVICE_FUNC const typename ReduxReturnType::Type redux(const BinaryOp& func = BinaryOp()) const - { return typename ReduxReturnType::Type(_expression(), func); } + { return typename ReduxReturnType::Type(_expression(), internal::member_redux(func)); } + + typedef typename ReturnType::Type MinCoeffReturnType; + typedef typename ReturnType::Type MaxCoeffReturnType; + typedef typename ReturnType::Type SquaredNormReturnType; + typedef typename ReturnType::Type NormReturnType; + typedef typename ReturnType::Type BlueNormReturnType; + typedef typename ReturnType::Type StableNormReturnType; + typedef typename ReturnType::Type HypotNormReturnType; + typedef typename ReturnType::Type SumReturnType; + typedef typename ReturnType::Type MeanReturnType; + typedef typename ReturnType::Type AllReturnType; + typedef typename ReturnType::Type AnyReturnType; + typedef PartialReduxExpr, Direction> CountReturnType; + typedef typename ReturnType::Type ProdReturnType; + typedef Reverse ConstReverseReturnType; + typedef Reverse ReverseReturnType; + + template struct LpNormReturnType { + typedef PartialReduxExpr,Direction> Type; + }; /** \returns a row (or column) vector expression of the smallest coefficient * of each column (or row) of the referenced expression. - * + * * \warning the result is undefined if \c *this contains NaN. * * Example: \include PartialRedux_minCoeff.cpp * Output: \verbinclude PartialRedux_minCoeff.out * * \sa DenseBase::minCoeff() */ - const typename ReturnType::Type minCoeff() const - { return _expression(); } + EIGEN_DEVICE_FUNC + const MinCoeffReturnType minCoeff() const + { return MinCoeffReturnType(_expression()); } /** \returns a row (or column) vector expression of the largest coefficient * of each column (or row) of the referenced expression. - * + * * \warning the result is undefined if \c *this contains NaN. * * Example: \include PartialRedux_maxCoeff.cpp * Output: \verbinclude PartialRedux_maxCoeff.out * * \sa DenseBase::maxCoeff() */ - const typename ReturnType::Type maxCoeff() const - { return _expression(); } + EIGEN_DEVICE_FUNC + const MaxCoeffReturnType maxCoeff() const + { return MaxCoeffReturnType(_expression()); } /** \returns a row (or column) vector expression of the squared norm * of each column (or row) of the referenced expression. + * This is a vector with real entries, even if the original matrix has complex entries. * * Example: \include PartialRedux_squaredNorm.cpp * Output: \verbinclude PartialRedux_squaredNorm.out * * \sa DenseBase::squaredNorm() */ - const typename ReturnType::Type squaredNorm() const - { return _expression(); } + EIGEN_DEVICE_FUNC + const SquaredNormReturnType squaredNorm() const + { return SquaredNormReturnType(_expression()); } + + /** \returns a row (or column) vector expression of the norm + * of each column (or row) of the referenced expression. + * This is a vector with real entries, even if the original matrix has complex entries. + * + * Example: \include PartialRedux_norm.cpp + * Output: \verbinclude PartialRedux_norm.out + * + * \sa DenseBase::norm() */ + EIGEN_DEVICE_FUNC + const NormReturnType norm() const + { return NormReturnType(_expression()); } /** \returns a row (or column) vector expression of the norm * of each column (or row) of the referenced expression. + * This is a vector with real entries, even if the original matrix has complex entries. * * Example: \include PartialRedux_norm.cpp * Output: \verbinclude PartialRedux_norm.out * * \sa DenseBase::norm() */ - const typename ReturnType::Type norm() const - { return _expression(); } + template + EIGEN_DEVICE_FUNC + const typename LpNormReturnType

::Type lpNorm() const + { return typename LpNormReturnType

::Type(_expression()); } /** \returns a row (or column) vector expression of the norm * of each column (or row) of the referenced expression, using - * blue's algorithm. + * Blue's algorithm. + * This is a vector with real entries, even if the original matrix has complex entries. * * \sa DenseBase::blueNorm() */ - const typename ReturnType::Type blueNorm() const - { return _expression(); } + EIGEN_DEVICE_FUNC + const BlueNormReturnType blueNorm() const + { return BlueNormReturnType(_expression()); } /** \returns a row (or column) vector expression of the norm * of each column (or row) of the referenced expression, avoiding * underflow and overflow. + * This is a vector with real entries, even if the original matrix has complex entries. * * \sa DenseBase::stableNorm() */ - const typename ReturnType::Type stableNorm() const - { return _expression(); } + EIGEN_DEVICE_FUNC + const StableNormReturnType stableNorm() const + { return StableNormReturnType(_expression()); } /** \returns a row (or column) vector expression of the norm * of each column (or row) of the referenced expression, avoiding * underflow and overflow using a concatenation of hypot() calls. + * This is a vector with real entries, even if the original matrix has complex entries. * * \sa DenseBase::hypotNorm() */ - const typename ReturnType::Type hypotNorm() const - { return _expression(); } + EIGEN_DEVICE_FUNC + const HypotNormReturnType hypotNorm() const + { return HypotNormReturnType(_expression()); } /** \returns a row (or column) vector expression of the sum * of each column (or row) of the referenced expression. @@ -354,39 +394,48 @@ template class VectorwiseOp * Output: \verbinclude PartialRedux_sum.out * * \sa DenseBase::sum() */ - const typename ReturnType::Type sum() const - { return _expression(); } + EIGEN_DEVICE_FUNC + const SumReturnType sum() const + { return SumReturnType(_expression()); } /** \returns a row (or column) vector expression of the mean * of each column (or row) of the referenced expression. * * \sa DenseBase::mean() */ - const typename ReturnType::Type mean() const - { return _expression(); } + EIGEN_DEVICE_FUNC + const MeanReturnType mean() const + { return MeanReturnType(_expression()); } /** \returns a row (or column) vector expression representing * whether \b all coefficients of each respective column (or row) are \c true. + * This expression can be assigned to a vector with entries of type \c bool. * * \sa DenseBase::all() */ - const typename ReturnType::Type all() const - { return _expression(); } + EIGEN_DEVICE_FUNC + const AllReturnType all() const + { return AllReturnType(_expression()); } /** \returns a row (or column) vector expression representing * whether \b at \b least one coefficient of each respective column (or row) is \c true. + * This expression can be assigned to a vector with entries of type \c bool. * * \sa DenseBase::any() */ - const typename ReturnType::Type any() const - { return _expression(); } + EIGEN_DEVICE_FUNC + const AnyReturnType any() const + { return AnyReturnType(_expression()); } /** \returns a row (or column) vector expression representing * the number of \c true coefficients of each respective column (or row). + * This expression can be assigned to a vector whose entries have the same type as is used to + * index entries of the original matrix; for dense matrices, this is \c std::ptrdiff_t . * * Example: \include PartialRedux_count.cpp * Output: \verbinclude PartialRedux_count.out * * \sa DenseBase::count() */ - const PartialReduxExpr, Direction> count() const - { return _expression(); } + EIGEN_DEVICE_FUNC + const CountReturnType count() const + { return CountReturnType(_expression()); } /** \returns a row (or column) vector expression of the product * of each column (or row) of the referenced expression. @@ -395,8 +444,9 @@ template class VectorwiseOp * Output: \verbinclude PartialRedux_prod.out * * \sa DenseBase::prod() */ - const typename ReturnType::Type prod() const - { return _expression(); } + EIGEN_DEVICE_FUNC + const ProdReturnType prod() const + { return ProdReturnType(_expression()); } /** \returns a matrix expression @@ -406,10 +456,20 @@ template class VectorwiseOp * Output: \verbinclude Vectorwise_reverse.out * * \sa DenseBase::reverse() */ - const Reverse reverse() const - { return Reverse( _expression() ); } + EIGEN_DEVICE_FUNC + const ConstReverseReturnType reverse() const + { return ConstReverseReturnType( _expression() ); } - typedef Replicate ReplicateReturnType; + /** \returns a writable matrix expression + * where each column (or row) are reversed. + * + * \sa reverse() const */ + EIGEN_DEVICE_FUNC + ReverseReturnType reverse() + { return ReverseReturnType( _expression() ); } + + typedef Replicate ReplicateReturnType; + EIGEN_DEVICE_FUNC const ReplicateReturnType replicate(Index factor) const; /** @@ -421,17 +481,20 @@ template class VectorwiseOp * \sa VectorwiseOp::replicate(Index), DenseBase::replicate(), class Replicate */ // NOTE implemented here because of sunstudio's compilation errors - template const Replicate + // isVertical*Factor+isHorizontal instead of (isVertical?Factor:1) to handle CUDA bug with ternary operator + template const Replicate + EIGEN_DEVICE_FUNC replicate(Index factor = Factor) const { - return Replicate - (_expression(),Direction==Vertical?factor:1,Direction==Horizontal?factor:1); + return Replicate + (_expression(),isVertical?factor:1,isHorizontal?factor:1); } /////////// Artithmetic operators /////////// /** Copies the vector \a other to each subvector of \c *this */ template + EIGEN_DEVICE_FUNC ExpressionType& operator=(const DenseBase& other) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) @@ -442,6 +505,7 @@ template class VectorwiseOp /** Adds the vector \a other to each subvector of \c *this */ template + EIGEN_DEVICE_FUNC ExpressionType& operator+=(const DenseBase& other) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) @@ -451,6 +515,7 @@ template class VectorwiseOp /** Substracts the vector \a other to each subvector of \c *this */ template + EIGEN_DEVICE_FUNC ExpressionType& operator-=(const DenseBase& other) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) @@ -460,6 +525,7 @@ template class VectorwiseOp /** Multiples each subvector of \c *this by the vector \a other */ template + EIGEN_DEVICE_FUNC ExpressionType& operator*=(const DenseBase& other) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) @@ -471,6 +537,7 @@ template class VectorwiseOp /** Divides each subvector of \c *this by the vector \a other */ template + EIGEN_DEVICE_FUNC ExpressionType& operator/=(const DenseBase& other) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) @@ -481,8 +548,8 @@ template class VectorwiseOp } /** Returns the expression of the sum of the vector \a other to each subvector of \c *this */ - template EIGEN_STRONG_INLINE - CwiseBinaryOp, + template EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC + CwiseBinaryOp, const ExpressionTypeNestedCleaned, const typename ExtendedType::Type> operator+(const DenseBase& other) const @@ -494,7 +561,8 @@ template class VectorwiseOp /** Returns the expression of the difference between each subvector of \c *this and the vector \a other */ template - CwiseBinaryOp, + EIGEN_DEVICE_FUNC + CwiseBinaryOp, const ExpressionTypeNestedCleaned, const typename ExtendedType::Type> operator-(const DenseBase& other) const @@ -506,10 +574,11 @@ template class VectorwiseOp /** Returns the expression where each subvector is the product of the vector \a other * by the corresponding subvector of \c *this */ - template EIGEN_STRONG_INLINE + template EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC CwiseBinaryOp, const ExpressionTypeNestedCleaned, const typename ExtendedType::Type> + EIGEN_DEVICE_FUNC operator*(const DenseBase& other) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) @@ -521,6 +590,7 @@ template class VectorwiseOp /** Returns the expression where each subvector is the quotient of the corresponding * subvector of \c *this by the vector \a other */ template + EIGEN_DEVICE_FUNC CwiseBinaryOp, const ExpressionTypeNestedCleaned, const typename ExtendedType::Type> @@ -531,32 +601,36 @@ template class VectorwiseOp EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived) return m_matrix / extendedTo(other.derived()); } - - /** \returns an expression where each column of row of the referenced matrix are normalized. + + /** \returns an expression where each column (or row) of the referenced matrix are normalized. * The referenced matrix is \b not modified. * \sa MatrixBase::normalized(), normalize() */ + EIGEN_DEVICE_FUNC CwiseBinaryOp, const ExpressionTypeNestedCleaned, const typename OppositeExtendedType::Type>::Type> normalized() const { return m_matrix.cwiseQuotient(extendedToOpposite(this->norm())); } - - + + /** Normalize in-place each row or columns of the referenced matrix. * \sa MatrixBase::normalize(), normalized() */ - void normalize() { + EIGEN_DEVICE_FUNC void normalize() { m_matrix = this->normalized(); } + EIGEN_DEVICE_FUNC inline void reverseInPlace(); + /////////// Geometry module /////////// - #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS - Homogeneous homogeneous() const; - #endif + typedef Homogeneous HomogeneousReturnType; + EIGEN_DEVICE_FUNC + HomogeneousReturnType homogeneous() const; typedef typename ExpressionType::PlainObject CrossReturnType; template + EIGEN_DEVICE_FUNC const CrossReturnType cross(const MatrixBase& other) const; enum { @@ -581,25 +655,15 @@ template class VectorwiseOp Direction==Horizontal ? HNormalized_SizeMinusOne : 1> > HNormalizedReturnType; + EIGEN_DEVICE_FUNC const HNormalizedReturnType hnormalized() const; protected: ExpressionTypeNested m_matrix; }; -/** \returns a VectorwiseOp wrapper of *this providing additional partial reduction operations - * - * Example: \include MatrixBase_colwise.cpp - * Output: \verbinclude MatrixBase_colwise.out - * - * \sa rowwise(), class VectorwiseOp, \ref TutorialReductionsVisitorsBroadcasting - */ -template -inline const typename DenseBase::ConstColwiseReturnType -DenseBase::colwise() const -{ - return derived(); -} +//const colwise moved to DenseBase.h due to CUDA compiler bug + /** \returns a writable VectorwiseOp wrapper of *this providing additional partial reduction operations * @@ -609,22 +673,11 @@ template inline typename DenseBase::ColwiseReturnType DenseBase::colwise() { - return derived(); + return ColwiseReturnType(derived()); } -/** \returns a VectorwiseOp wrapper of *this providing additional partial reduction operations - * - * Example: \include MatrixBase_rowwise.cpp - * Output: \verbinclude MatrixBase_rowwise.out - * - * \sa colwise(), class VectorwiseOp, \ref TutorialReductionsVisitorsBroadcasting - */ -template -inline const typename DenseBase::ConstRowwiseReturnType -DenseBase::rowwise() const -{ - return derived(); -} +//const rowwise moved to DenseBase.h due to CUDA compiler bug + /** \returns a writable VectorwiseOp wrapper of *this providing additional partial reduction operations * @@ -634,7 +687,7 @@ template inline typename DenseBase::RowwiseReturnType DenseBase::rowwise() { - return derived(); + return RowwiseReturnType(derived()); } } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/Core/Visitor.h b/libs/eigen3/Eigen/src/Core/Visitor.h index 64867b7a2..54c1883d9 100644 --- a/libs/eigen3/Eigen/src/Core/Visitor.h +++ b/libs/eigen3/Eigen/src/Core/Visitor.h @@ -22,6 +22,7 @@ struct visitor_impl row = (UnrollCount-1) % Derived::RowsAtCompileTime }; + EIGEN_DEVICE_FUNC static inline void run(const Derived &mat, Visitor& visitor) { visitor_impl::run(mat, visitor); @@ -32,6 +33,7 @@ struct visitor_impl template struct visitor_impl { + EIGEN_DEVICE_FUNC static inline void run(const Derived &mat, Visitor& visitor) { return visitor.init(mat.coeff(0, 0), 0, 0); @@ -41,7 +43,7 @@ struct visitor_impl template struct visitor_impl { - typedef typename Derived::Index Index; + EIGEN_DEVICE_FUNC static inline void run(const Derived& mat, Visitor& visitor) { visitor.init(mat.coeff(0,0), 0, 0); @@ -53,6 +55,33 @@ struct visitor_impl } }; +// evaluator adaptor +template +class visitor_evaluator +{ +public: + EIGEN_DEVICE_FUNC + explicit visitor_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) {} + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + enum { + RowsAtCompileTime = XprType::RowsAtCompileTime, + CoeffReadCost = internal::evaluator::CoeffReadCost + }; + + EIGEN_DEVICE_FUNC Index rows() const { return m_xpr.rows(); } + EIGEN_DEVICE_FUNC Index cols() const { return m_xpr.cols(); } + EIGEN_DEVICE_FUNC Index size() const { return m_xpr.size(); } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const + { return m_evaluator.coeff(row, col); } + +protected: + internal::evaluator m_evaluator; + const XprType &m_xpr; +}; } // end namespace internal /** Applies the visitor \a visitor to the whole coefficients of the matrix or vector. @@ -74,16 +103,17 @@ struct visitor_impl */ template template +EIGEN_DEVICE_FUNC void DenseBase::visit(Visitor& visitor) const { - enum { unroll = SizeAtCompileTime != Dynamic - && CoeffReadCost != Dynamic - && (SizeAtCompileTime == 1 || internal::functor_traits::Cost != Dynamic) - && SizeAtCompileTime * CoeffReadCost + (SizeAtCompileTime-1) * internal::functor_traits::Cost - <= EIGEN_UNROLLING_LIMIT }; - return internal::visitor_impl::run(derived(), visitor); + typedef typename internal::visitor_evaluator ThisEvaluator; + ThisEvaluator thisEval(derived()); + + enum { + unroll = SizeAtCompileTime != Dynamic + && SizeAtCompileTime * ThisEvaluator::CoeffReadCost + (SizeAtCompileTime-1) * internal::functor_traits::Cost <= EIGEN_UNROLLING_LIMIT + }; + return internal::visitor_impl::run(thisEval, visitor); } namespace internal { @@ -94,10 +124,10 @@ namespace internal { template struct coeff_visitor { - typedef typename Derived::Index Index; typedef typename Derived::Scalar Scalar; Index row, col; Scalar res; + EIGEN_DEVICE_FUNC inline void init(const Scalar& value, Index i, Index j) { res = value; @@ -114,8 +144,8 @@ struct coeff_visitor template struct min_coeff_visitor : coeff_visitor { - typedef typename Derived::Index Index; typedef typename Derived::Scalar Scalar; + EIGEN_DEVICE_FUNC void operator() (const Scalar& value, Index i, Index j) { if(value < this->res) @@ -142,8 +172,8 @@ struct functor_traits > { template struct max_coeff_visitor : coeff_visitor { - typedef typename Derived::Index Index; - typedef typename Derived::Scalar Scalar; + typedef typename Derived::Scalar Scalar; + EIGEN_DEVICE_FUNC void operator() (const Scalar& value, Index i, Index j) { if(value > this->res) @@ -164,13 +194,15 @@ struct functor_traits > { } // end namespace internal -/** \returns the minimum of all coefficients of *this and puts in *row and *col its location. +/** \fn DenseBase::minCoeff(IndexType* rowId, IndexType* colId) const + * \returns the minimum of all coefficients of *this and puts in *row and *col its location. * \warning the result is undefined if \c *this contains NaN. * - * \sa DenseBase::minCoeff(Index*), DenseBase::maxCoeff(Index*,Index*), DenseBase::visitor(), DenseBase::minCoeff() + * \sa DenseBase::minCoeff(Index*), DenseBase::maxCoeff(Index*,Index*), DenseBase::visit(), DenseBase::minCoeff() */ template template +EIGEN_DEVICE_FUNC typename internal::traits::Scalar DenseBase::minCoeff(IndexType* rowId, IndexType* colId) const { @@ -184,27 +216,30 @@ DenseBase::minCoeff(IndexType* rowId, IndexType* colId) const /** \returns the minimum of all coefficients of *this and puts in *index its location. * \warning the result is undefined if \c *this contains NaN. * - * \sa DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::maxCoeff(IndexType*,IndexType*), DenseBase::visitor(), DenseBase::minCoeff() + * \sa DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::maxCoeff(IndexType*,IndexType*), DenseBase::visit(), DenseBase::minCoeff() */ template template +EIGEN_DEVICE_FUNC typename internal::traits::Scalar DenseBase::minCoeff(IndexType* index) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) internal::min_coeff_visitor minVisitor; this->visit(minVisitor); - *index = (RowsAtCompileTime==1) ? minVisitor.col : minVisitor.row; + *index = IndexType((RowsAtCompileTime==1) ? minVisitor.col : minVisitor.row); return minVisitor.res; } -/** \returns the maximum of all coefficients of *this and puts in *row and *col its location. +/** \fn DenseBase::maxCoeff(IndexType* rowId, IndexType* colId) const + * \returns the maximum of all coefficients of *this and puts in *row and *col its location. * \warning the result is undefined if \c *this contains NaN. * - * \sa DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::visitor(), DenseBase::maxCoeff() + * \sa DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::visit(), DenseBase::maxCoeff() */ template template +EIGEN_DEVICE_FUNC typename internal::traits::Scalar DenseBase::maxCoeff(IndexType* rowPtr, IndexType* colPtr) const { @@ -222,6 +257,7 @@ DenseBase::maxCoeff(IndexType* rowPtr, IndexType* colPtr) const */ template template +EIGEN_DEVICE_FUNC typename internal::traits::Scalar DenseBase::maxCoeff(IndexType* index) const { diff --git a/libs/eigen3/Eigen/src/Core/arch/AVX/Complex.h b/libs/eigen3/Eigen/src/Core/arch/AVX/Complex.h new file mode 100644 index 000000000..99439c8aa --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/arch/AVX/Complex.h @@ -0,0 +1,483 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner (benoit.steiner.goog@gmail.com) +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_COMPLEX_AVX_H +#define EIGEN_COMPLEX_AVX_H + +namespace Eigen { + +namespace internal { + +//---------- float ---------- +struct Packet4cf +{ + EIGEN_STRONG_INLINE Packet4cf() {} + EIGEN_STRONG_INLINE explicit Packet4cf(const __m256& a) : v(a) {} + __m256 v; +}; + +template<> struct packet_traits > : default_packet_traits +{ + typedef Packet4cf type; + typedef Packet2cf half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size = 4, + HasHalfPacket = 1, + + HasAdd = 1, + HasSub = 1, + HasMul = 1, + HasDiv = 1, + HasNegate = 1, + HasAbs = 0, + HasAbs2 = 0, + HasMin = 0, + HasMax = 0, + HasSetLinear = 0 + }; +}; + +template<> struct unpacket_traits { typedef std::complex type; enum {size=4, alignment=Aligned32}; typedef Packet2cf half; }; + +template<> EIGEN_STRONG_INLINE Packet4cf padd(const Packet4cf& a, const Packet4cf& b) { return Packet4cf(_mm256_add_ps(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet4cf psub(const Packet4cf& a, const Packet4cf& b) { return Packet4cf(_mm256_sub_ps(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet4cf pnegate(const Packet4cf& a) +{ + return Packet4cf(pnegate(a.v)); +} +template<> EIGEN_STRONG_INLINE Packet4cf pconj(const Packet4cf& a) +{ + const __m256 mask = _mm256_castsi256_ps(_mm256_setr_epi32(0x00000000,0x80000000,0x00000000,0x80000000,0x00000000,0x80000000,0x00000000,0x80000000)); + return Packet4cf(_mm256_xor_ps(a.v,mask)); +} + +template<> EIGEN_STRONG_INLINE Packet4cf pmul(const Packet4cf& a, const Packet4cf& b) +{ + __m256 tmp1 = _mm256_mul_ps(_mm256_moveldup_ps(a.v), b.v); + __m256 tmp2 = _mm256_mul_ps(_mm256_movehdup_ps(a.v), _mm256_permute_ps(b.v, _MM_SHUFFLE(2,3,0,1))); + __m256 result = _mm256_addsub_ps(tmp1, tmp2); + return Packet4cf(result); +} + +template<> EIGEN_STRONG_INLINE Packet4cf pand (const Packet4cf& a, const Packet4cf& b) { return Packet4cf(_mm256_and_ps(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet4cf por (const Packet4cf& a, const Packet4cf& b) { return Packet4cf(_mm256_or_ps(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet4cf pxor (const Packet4cf& a, const Packet4cf& b) { return Packet4cf(_mm256_xor_ps(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet4cf pandnot(const Packet4cf& a, const Packet4cf& b) { return Packet4cf(_mm256_andnot_ps(a.v,b.v)); } + +template<> EIGEN_STRONG_INLINE Packet4cf pload (const std::complex* from) { EIGEN_DEBUG_ALIGNED_LOAD return Packet4cf(pload(&numext::real_ref(*from))); } +template<> EIGEN_STRONG_INLINE Packet4cf ploadu(const std::complex* from) { EIGEN_DEBUG_UNALIGNED_LOAD return Packet4cf(ploadu(&numext::real_ref(*from))); } + + +template<> EIGEN_STRONG_INLINE Packet4cf pset1(const std::complex& from) +{ + return Packet4cf(_mm256_castpd_ps(_mm256_broadcast_sd((const double*)(const void*)&from))); +} + +template<> EIGEN_STRONG_INLINE Packet4cf ploaddup(const std::complex* from) +{ + // FIXME The following might be optimized using _mm256_movedup_pd + Packet2cf a = ploaddup(from); + Packet2cf b = ploaddup(from+1); + return Packet4cf(_mm256_insertf128_ps(_mm256_castps128_ps256(a.v), b.v, 1)); +} + +template<> EIGEN_STRONG_INLINE void pstore >(std::complex* to, const Packet4cf& from) { EIGEN_DEBUG_ALIGNED_STORE pstore(&numext::real_ref(*to), from.v); } +template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex* to, const Packet4cf& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu(&numext::real_ref(*to), from.v); } + +template<> EIGEN_DEVICE_FUNC inline Packet4cf pgather, Packet4cf>(const std::complex* from, Index stride) +{ + return Packet4cf(_mm256_set_ps(std::imag(from[3*stride]), std::real(from[3*stride]), + std::imag(from[2*stride]), std::real(from[2*stride]), + std::imag(from[1*stride]), std::real(from[1*stride]), + std::imag(from[0*stride]), std::real(from[0*stride]))); +} + +template<> EIGEN_DEVICE_FUNC inline void pscatter, Packet4cf>(std::complex* to, const Packet4cf& from, Index stride) +{ + __m128 low = _mm256_extractf128_ps(from.v, 0); + to[stride*0] = std::complex(_mm_cvtss_f32(_mm_shuffle_ps(low, low, 0)), + _mm_cvtss_f32(_mm_shuffle_ps(low, low, 1))); + to[stride*1] = std::complex(_mm_cvtss_f32(_mm_shuffle_ps(low, low, 2)), + _mm_cvtss_f32(_mm_shuffle_ps(low, low, 3))); + + __m128 high = _mm256_extractf128_ps(from.v, 1); + to[stride*2] = std::complex(_mm_cvtss_f32(_mm_shuffle_ps(high, high, 0)), + _mm_cvtss_f32(_mm_shuffle_ps(high, high, 1))); + to[stride*3] = std::complex(_mm_cvtss_f32(_mm_shuffle_ps(high, high, 2)), + _mm_cvtss_f32(_mm_shuffle_ps(high, high, 3))); + +} + +template<> EIGEN_STRONG_INLINE std::complex pfirst(const Packet4cf& a) +{ + return pfirst(Packet2cf(_mm256_castps256_ps128(a.v))); +} + +template<> EIGEN_STRONG_INLINE Packet4cf preverse(const Packet4cf& a) { + __m128 low = _mm256_extractf128_ps(a.v, 0); + __m128 high = _mm256_extractf128_ps(a.v, 1); + __m128d lowd = _mm_castps_pd(low); + __m128d highd = _mm_castps_pd(high); + low = _mm_castpd_ps(_mm_shuffle_pd(lowd,lowd,0x1)); + high = _mm_castpd_ps(_mm_shuffle_pd(highd,highd,0x1)); + __m256 result = _mm256_setzero_ps(); + result = _mm256_insertf128_ps(result, low, 1); + result = _mm256_insertf128_ps(result, high, 0); + return Packet4cf(result); +} + +template<> EIGEN_STRONG_INLINE std::complex predux(const Packet4cf& a) +{ + return predux(padd(Packet2cf(_mm256_extractf128_ps(a.v,0)), + Packet2cf(_mm256_extractf128_ps(a.v,1)))); +} + +template<> EIGEN_STRONG_INLINE Packet4cf preduxp(const Packet4cf* vecs) +{ + Packet8f t0 = _mm256_shuffle_ps(vecs[0].v, vecs[0].v, _MM_SHUFFLE(3, 1, 2 ,0)); + Packet8f t1 = _mm256_shuffle_ps(vecs[1].v, vecs[1].v, _MM_SHUFFLE(3, 1, 2 ,0)); + t0 = _mm256_hadd_ps(t0,t1); + Packet8f t2 = _mm256_shuffle_ps(vecs[2].v, vecs[2].v, _MM_SHUFFLE(3, 1, 2 ,0)); + Packet8f t3 = _mm256_shuffle_ps(vecs[3].v, vecs[3].v, _MM_SHUFFLE(3, 1, 2 ,0)); + t2 = _mm256_hadd_ps(t2,t3); + + t1 = _mm256_permute2f128_ps(t0,t2, 0 + (2<<4)); + t3 = _mm256_permute2f128_ps(t0,t2, 1 + (3<<4)); + + return Packet4cf(_mm256_add_ps(t1,t3)); +} + +template<> EIGEN_STRONG_INLINE std::complex predux_mul(const Packet4cf& a) +{ + return predux_mul(pmul(Packet2cf(_mm256_extractf128_ps(a.v, 0)), + Packet2cf(_mm256_extractf128_ps(a.v, 1)))); +} + +template +struct palign_impl +{ + static EIGEN_STRONG_INLINE void run(Packet4cf& first, const Packet4cf& second) + { + if (Offset==0) return; + palign_impl::run(first.v, second.v); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet4cf pmadd(const Packet4cf& x, const Packet4cf& y, const Packet4cf& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet4cf pmul(const Packet4cf& a, const Packet4cf& b) const + { + return internal::pmul(a, pconj(b)); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet4cf pmadd(const Packet4cf& x, const Packet4cf& y, const Packet4cf& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet4cf pmul(const Packet4cf& a, const Packet4cf& b) const + { + return internal::pmul(pconj(a), b); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet4cf pmadd(const Packet4cf& x, const Packet4cf& y, const Packet4cf& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet4cf pmul(const Packet4cf& a, const Packet4cf& b) const + { + return pconj(internal::pmul(a, b)); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet4cf pmadd(const Packet8f& x, const Packet4cf& y, const Packet4cf& c) const + { return padd(c, pmul(x,y)); } + + EIGEN_STRONG_INLINE Packet4cf pmul(const Packet8f& x, const Packet4cf& y) const + { return Packet4cf(Eigen::internal::pmul(x, y.v)); } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet4cf pmadd(const Packet4cf& x, const Packet8f& y, const Packet4cf& c) const + { return padd(c, pmul(x,y)); } + + EIGEN_STRONG_INLINE Packet4cf pmul(const Packet4cf& x, const Packet8f& y) const + { return Packet4cf(Eigen::internal::pmul(x.v, y)); } +}; + +template<> EIGEN_STRONG_INLINE Packet4cf pdiv(const Packet4cf& a, const Packet4cf& b) +{ + Packet4cf num = pmul(a, pconj(b)); + __m256 tmp = _mm256_mul_ps(b.v, b.v); + __m256 tmp2 = _mm256_shuffle_ps(tmp,tmp,0xB1); + __m256 denom = _mm256_add_ps(tmp, tmp2); + return Packet4cf(_mm256_div_ps(num.v, denom)); +} + +template<> EIGEN_STRONG_INLINE Packet4cf pcplxflip(const Packet4cf& x) +{ + return Packet4cf(_mm256_shuffle_ps(x.v, x.v, _MM_SHUFFLE(2, 3, 0 ,1))); +} + +//---------- double ---------- +struct Packet2cd +{ + EIGEN_STRONG_INLINE Packet2cd() {} + EIGEN_STRONG_INLINE explicit Packet2cd(const __m256d& a) : v(a) {} + __m256d v; +}; + +template<> struct packet_traits > : default_packet_traits +{ + typedef Packet2cd type; + typedef Packet1cd half; + enum { + Vectorizable = 1, + AlignedOnScalar = 0, + size = 2, + HasHalfPacket = 1, + + HasAdd = 1, + HasSub = 1, + HasMul = 1, + HasDiv = 1, + HasNegate = 1, + HasAbs = 0, + HasAbs2 = 0, + HasMin = 0, + HasMax = 0, + HasSetLinear = 0 + }; +}; + +template<> struct unpacket_traits { typedef std::complex type; enum {size=2, alignment=Aligned32}; typedef Packet1cd half; }; + +template<> EIGEN_STRONG_INLINE Packet2cd padd(const Packet2cd& a, const Packet2cd& b) { return Packet2cd(_mm256_add_pd(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet2cd psub(const Packet2cd& a, const Packet2cd& b) { return Packet2cd(_mm256_sub_pd(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet2cd pnegate(const Packet2cd& a) { return Packet2cd(pnegate(a.v)); } +template<> EIGEN_STRONG_INLINE Packet2cd pconj(const Packet2cd& a) +{ + const __m256d mask = _mm256_castsi256_pd(_mm256_set_epi32(0x80000000,0x0,0x0,0x0,0x80000000,0x0,0x0,0x0)); + return Packet2cd(_mm256_xor_pd(a.v,mask)); +} + +template<> EIGEN_STRONG_INLINE Packet2cd pmul(const Packet2cd& a, const Packet2cd& b) +{ + __m256d tmp1 = _mm256_shuffle_pd(a.v,a.v,0x0); + __m256d even = _mm256_mul_pd(tmp1, b.v); + __m256d tmp2 = _mm256_shuffle_pd(a.v,a.v,0xF); + __m256d tmp3 = _mm256_shuffle_pd(b.v,b.v,0x5); + __m256d odd = _mm256_mul_pd(tmp2, tmp3); + return Packet2cd(_mm256_addsub_pd(even, odd)); +} + +template<> EIGEN_STRONG_INLINE Packet2cd pand (const Packet2cd& a, const Packet2cd& b) { return Packet2cd(_mm256_and_pd(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet2cd por (const Packet2cd& a, const Packet2cd& b) { return Packet2cd(_mm256_or_pd(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet2cd pxor (const Packet2cd& a, const Packet2cd& b) { return Packet2cd(_mm256_xor_pd(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet2cd pandnot(const Packet2cd& a, const Packet2cd& b) { return Packet2cd(_mm256_andnot_pd(a.v,b.v)); } + +template<> EIGEN_STRONG_INLINE Packet2cd pload (const std::complex* from) +{ EIGEN_DEBUG_ALIGNED_LOAD return Packet2cd(pload((const double*)from)); } +template<> EIGEN_STRONG_INLINE Packet2cd ploadu(const std::complex* from) +{ EIGEN_DEBUG_UNALIGNED_LOAD return Packet2cd(ploadu((const double*)from)); } + +template<> EIGEN_STRONG_INLINE Packet2cd pset1(const std::complex& from) +{ + // in case casting to a __m128d* is really not safe, then we can still fallback to this version: (much slower though) +// return Packet2cd(_mm256_loadu2_m128d((const double*)&from,(const double*)&from)); + return Packet2cd(_mm256_broadcast_pd((const __m128d*)(const void*)&from)); +} + +template<> EIGEN_STRONG_INLINE Packet2cd ploaddup(const std::complex* from) { return pset1(*from); } + +template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet2cd& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((double*)to, from.v); } +template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet2cd& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, from.v); } + +template<> EIGEN_DEVICE_FUNC inline Packet2cd pgather, Packet2cd>(const std::complex* from, Index stride) +{ + return Packet2cd(_mm256_set_pd(std::imag(from[1*stride]), std::real(from[1*stride]), + std::imag(from[0*stride]), std::real(from[0*stride]))); +} + +template<> EIGEN_DEVICE_FUNC inline void pscatter, Packet2cd>(std::complex* to, const Packet2cd& from, Index stride) +{ + __m128d low = _mm256_extractf128_pd(from.v, 0); + to[stride*0] = std::complex(_mm_cvtsd_f64(low), _mm_cvtsd_f64(_mm_shuffle_pd(low, low, 1))); + __m128d high = _mm256_extractf128_pd(from.v, 1); + to[stride*1] = std::complex(_mm_cvtsd_f64(high), _mm_cvtsd_f64(_mm_shuffle_pd(high, high, 1))); +} + +template<> EIGEN_STRONG_INLINE std::complex pfirst(const Packet2cd& a) +{ + __m128d low = _mm256_extractf128_pd(a.v, 0); + EIGEN_ALIGN16 double res[2]; + _mm_store_pd(res, low); + return std::complex(res[0],res[1]); +} + +template<> EIGEN_STRONG_INLINE Packet2cd preverse(const Packet2cd& a) { + __m256d result = _mm256_permute2f128_pd(a.v, a.v, 1); + return Packet2cd(result); +} + +template<> EIGEN_STRONG_INLINE std::complex predux(const Packet2cd& a) +{ + return predux(padd(Packet1cd(_mm256_extractf128_pd(a.v,0)), + Packet1cd(_mm256_extractf128_pd(a.v,1)))); +} + +template<> EIGEN_STRONG_INLINE Packet2cd preduxp(const Packet2cd* vecs) +{ + Packet4d t0 = _mm256_permute2f128_pd(vecs[0].v,vecs[1].v, 0 + (2<<4)); + Packet4d t1 = _mm256_permute2f128_pd(vecs[0].v,vecs[1].v, 1 + (3<<4)); + + return Packet2cd(_mm256_add_pd(t0,t1)); +} + +template<> EIGEN_STRONG_INLINE std::complex predux_mul(const Packet2cd& a) +{ + return predux(pmul(Packet1cd(_mm256_extractf128_pd(a.v,0)), + Packet1cd(_mm256_extractf128_pd(a.v,1)))); +} + +template +struct palign_impl +{ + static EIGEN_STRONG_INLINE void run(Packet2cd& first, const Packet2cd& second) + { + if (Offset==0) return; + palign_impl::run(first.v, second.v); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet2cd pmadd(const Packet2cd& x, const Packet2cd& y, const Packet2cd& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet2cd pmul(const Packet2cd& a, const Packet2cd& b) const + { + return internal::pmul(a, pconj(b)); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet2cd pmadd(const Packet2cd& x, const Packet2cd& y, const Packet2cd& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet2cd pmul(const Packet2cd& a, const Packet2cd& b) const + { + return internal::pmul(pconj(a), b); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet2cd pmadd(const Packet2cd& x, const Packet2cd& y, const Packet2cd& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet2cd pmul(const Packet2cd& a, const Packet2cd& b) const + { + return pconj(internal::pmul(a, b)); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet2cd pmadd(const Packet4d& x, const Packet2cd& y, const Packet2cd& c) const + { return padd(c, pmul(x,y)); } + + EIGEN_STRONG_INLINE Packet2cd pmul(const Packet4d& x, const Packet2cd& y) const + { return Packet2cd(Eigen::internal::pmul(x, y.v)); } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet2cd pmadd(const Packet2cd& x, const Packet4d& y, const Packet2cd& c) const + { return padd(c, pmul(x,y)); } + + EIGEN_STRONG_INLINE Packet2cd pmul(const Packet2cd& x, const Packet4d& y) const + { return Packet2cd(Eigen::internal::pmul(x.v, y)); } +}; + +template<> EIGEN_STRONG_INLINE Packet2cd pdiv(const Packet2cd& a, const Packet2cd& b) +{ + Packet2cd num = pmul(a, pconj(b)); + __m256d tmp = _mm256_mul_pd(b.v, b.v); + __m256d denom = _mm256_hadd_pd(tmp, tmp); + return Packet2cd(_mm256_div_pd(num.v, denom)); +} + +template<> EIGEN_STRONG_INLINE Packet2cd pcplxflip(const Packet2cd& x) +{ + return Packet2cd(_mm256_shuffle_pd(x.v, x.v, 0x5)); +} + +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + __m256d P0 = _mm256_castps_pd(kernel.packet[0].v); + __m256d P1 = _mm256_castps_pd(kernel.packet[1].v); + __m256d P2 = _mm256_castps_pd(kernel.packet[2].v); + __m256d P3 = _mm256_castps_pd(kernel.packet[3].v); + + __m256d T0 = _mm256_shuffle_pd(P0, P1, 15); + __m256d T1 = _mm256_shuffle_pd(P0, P1, 0); + __m256d T2 = _mm256_shuffle_pd(P2, P3, 15); + __m256d T3 = _mm256_shuffle_pd(P2, P3, 0); + + kernel.packet[1].v = _mm256_castpd_ps(_mm256_permute2f128_pd(T0, T2, 32)); + kernel.packet[3].v = _mm256_castpd_ps(_mm256_permute2f128_pd(T0, T2, 49)); + kernel.packet[0].v = _mm256_castpd_ps(_mm256_permute2f128_pd(T1, T3, 32)); + kernel.packet[2].v = _mm256_castpd_ps(_mm256_permute2f128_pd(T1, T3, 49)); +} + +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + __m256d tmp = _mm256_permute2f128_pd(kernel.packet[0].v, kernel.packet[1].v, 0+(2<<4)); + kernel.packet[1].v = _mm256_permute2f128_pd(kernel.packet[0].v, kernel.packet[1].v, 1+(3<<4)); + kernel.packet[0].v = tmp; +} + +template<> EIGEN_STRONG_INLINE Packet4cf pinsertfirst(const Packet4cf& a, std::complex b) +{ + return Packet4cf(_mm256_blend_ps(a.v,pset1(b).v,1|2)); +} + +template<> EIGEN_STRONG_INLINE Packet2cd pinsertfirst(const Packet2cd& a, std::complex b) +{ + return Packet2cd(_mm256_blend_pd(a.v,pset1(b).v,1|2)); +} + +template<> EIGEN_STRONG_INLINE Packet4cf pinsertlast(const Packet4cf& a, std::complex b) +{ + return Packet4cf(_mm256_blend_ps(a.v,pset1(b).v,(1<<7)|(1<<6))); +} + +template<> EIGEN_STRONG_INLINE Packet2cd pinsertlast(const Packet2cd& a, std::complex b) +{ + return Packet2cd(_mm256_blend_pd(a.v,pset1(b).v,(1<<3)|(1<<2))); +} + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_COMPLEX_AVX_H diff --git a/libs/eigen3/Eigen/src/Core/arch/AVX/MathFunctions.h b/libs/eigen3/Eigen/src/Core/arch/AVX/MathFunctions.h new file mode 100644 index 000000000..6af67ce2d --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/arch/AVX/MathFunctions.h @@ -0,0 +1,439 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Pedro Gonnet (pedro.gonnet@gmail.com) +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_MATH_FUNCTIONS_AVX_H +#define EIGEN_MATH_FUNCTIONS_AVX_H + +/* The sin, cos, exp, and log functions of this file are loosely derived from + * Julien Pommier's sse math library: http://gruntthepeon.free.fr/ssemath/ + */ + +namespace Eigen { + +namespace internal { + +inline Packet8i pshiftleft(Packet8i v, int n) +{ +#ifdef EIGEN_VECTORIZE_AVX2 + return _mm256_slli_epi32(v, n); +#else + __m128i lo = _mm_slli_epi32(_mm256_extractf128_si256(v, 0), n); + __m128i hi = _mm_slli_epi32(_mm256_extractf128_si256(v, 1), n); + return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1); +#endif +} + +inline Packet8f pshiftright(Packet8f v, int n) +{ +#ifdef EIGEN_VECTORIZE_AVX2 + return _mm256_cvtepi32_ps(_mm256_srli_epi32(_mm256_castps_si256(v), n)); +#else + __m128i lo = _mm_srli_epi32(_mm256_extractf128_si256(_mm256_castps_si256(v), 0), n); + __m128i hi = _mm_srli_epi32(_mm256_extractf128_si256(_mm256_castps_si256(v), 1), n); + return _mm256_cvtepi32_ps(_mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1)); +#endif +} + +// Sine function +// Computes sin(x) by wrapping x to the interval [-Pi/4,3*Pi/4] and +// evaluating interpolants in [-Pi/4,Pi/4] or [Pi/4,3*Pi/4]. The interpolants +// are (anti-)symmetric and thus have only odd/even coefficients +template <> +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet8f +psin(const Packet8f& _x) { + Packet8f x = _x; + + // Some useful values. + _EIGEN_DECLARE_CONST_Packet8i(one, 1); + _EIGEN_DECLARE_CONST_Packet8f(one, 1.0f); + _EIGEN_DECLARE_CONST_Packet8f(two, 2.0f); + _EIGEN_DECLARE_CONST_Packet8f(one_over_four, 0.25f); + _EIGEN_DECLARE_CONST_Packet8f(one_over_pi, 3.183098861837907e-01f); + _EIGEN_DECLARE_CONST_Packet8f(neg_pi_first, -3.140625000000000e+00f); + _EIGEN_DECLARE_CONST_Packet8f(neg_pi_second, -9.670257568359375e-04f); + _EIGEN_DECLARE_CONST_Packet8f(neg_pi_third, -6.278329571784980e-07f); + _EIGEN_DECLARE_CONST_Packet8f(four_over_pi, 1.273239544735163e+00f); + + // Map x from [-Pi/4,3*Pi/4] to z in [-1,3] and subtract the shifted period. + Packet8f z = pmul(x, p8f_one_over_pi); + Packet8f shift = _mm256_floor_ps(padd(z, p8f_one_over_four)); + x = pmadd(shift, p8f_neg_pi_first, x); + x = pmadd(shift, p8f_neg_pi_second, x); + x = pmadd(shift, p8f_neg_pi_third, x); + z = pmul(x, p8f_four_over_pi); + + // Make a mask for the entries that need flipping, i.e. wherever the shift + // is odd. + Packet8i shift_ints = _mm256_cvtps_epi32(shift); + Packet8i shift_isodd = _mm256_castps_si256(_mm256_and_ps(_mm256_castsi256_ps(shift_ints), _mm256_castsi256_ps(p8i_one))); + Packet8i sign_flip_mask = pshiftleft(shift_isodd, 31); + + // Create a mask for which interpolant to use, i.e. if z > 1, then the mask + // is set to ones for that entry. + Packet8f ival_mask = _mm256_cmp_ps(z, p8f_one, _CMP_GT_OQ); + + // Evaluate the polynomial for the interval [1,3] in z. + _EIGEN_DECLARE_CONST_Packet8f(coeff_right_0, 9.999999724233232e-01f); + _EIGEN_DECLARE_CONST_Packet8f(coeff_right_2, -3.084242535619928e-01f); + _EIGEN_DECLARE_CONST_Packet8f(coeff_right_4, 1.584991525700324e-02f); + _EIGEN_DECLARE_CONST_Packet8f(coeff_right_6, -3.188805084631342e-04f); + Packet8f z_minus_two = psub(z, p8f_two); + Packet8f z_minus_two2 = pmul(z_minus_two, z_minus_two); + Packet8f right = pmadd(p8f_coeff_right_6, z_minus_two2, p8f_coeff_right_4); + right = pmadd(right, z_minus_two2, p8f_coeff_right_2); + right = pmadd(right, z_minus_two2, p8f_coeff_right_0); + + // Evaluate the polynomial for the interval [-1,1] in z. + _EIGEN_DECLARE_CONST_Packet8f(coeff_left_1, 7.853981525427295e-01f); + _EIGEN_DECLARE_CONST_Packet8f(coeff_left_3, -8.074536727092352e-02f); + _EIGEN_DECLARE_CONST_Packet8f(coeff_left_5, 2.489871967827018e-03f); + _EIGEN_DECLARE_CONST_Packet8f(coeff_left_7, -3.587725841214251e-05f); + Packet8f z2 = pmul(z, z); + Packet8f left = pmadd(p8f_coeff_left_7, z2, p8f_coeff_left_5); + left = pmadd(left, z2, p8f_coeff_left_3); + left = pmadd(left, z2, p8f_coeff_left_1); + left = pmul(left, z); + + // Assemble the results, i.e. select the left and right polynomials. + left = _mm256_andnot_ps(ival_mask, left); + right = _mm256_and_ps(ival_mask, right); + Packet8f res = _mm256_or_ps(left, right); + + // Flip the sign on the odd intervals and return the result. + res = _mm256_xor_ps(res, _mm256_castsi256_ps(sign_flip_mask)); + return res; +} + +// Natural logarithm +// Computes log(x) as log(2^e * m) = C*e + log(m), where the constant C =log(2) +// and m is in the range [sqrt(1/2),sqrt(2)). In this range, the logarithm can +// be easily approximated by a polynomial centered on m=1 for stability. +// TODO(gonnet): Further reduce the interval allowing for lower-degree +// polynomial interpolants -> ... -> profit! +template <> +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet8f +plog(const Packet8f& _x) { + Packet8f x = _x; + _EIGEN_DECLARE_CONST_Packet8f(1, 1.0f); + _EIGEN_DECLARE_CONST_Packet8f(half, 0.5f); + _EIGEN_DECLARE_CONST_Packet8f(126f, 126.0f); + + _EIGEN_DECLARE_CONST_Packet8f_FROM_INT(inv_mant_mask, ~0x7f800000); + + // The smallest non denormalized float number. + _EIGEN_DECLARE_CONST_Packet8f_FROM_INT(min_norm_pos, 0x00800000); + _EIGEN_DECLARE_CONST_Packet8f_FROM_INT(minus_inf, 0xff800000); + + // Polynomial coefficients. + _EIGEN_DECLARE_CONST_Packet8f(cephes_SQRTHF, 0.707106781186547524f); + _EIGEN_DECLARE_CONST_Packet8f(cephes_log_p0, 7.0376836292E-2f); + _EIGEN_DECLARE_CONST_Packet8f(cephes_log_p1, -1.1514610310E-1f); + _EIGEN_DECLARE_CONST_Packet8f(cephes_log_p2, 1.1676998740E-1f); + _EIGEN_DECLARE_CONST_Packet8f(cephes_log_p3, -1.2420140846E-1f); + _EIGEN_DECLARE_CONST_Packet8f(cephes_log_p4, +1.4249322787E-1f); + _EIGEN_DECLARE_CONST_Packet8f(cephes_log_p5, -1.6668057665E-1f); + _EIGEN_DECLARE_CONST_Packet8f(cephes_log_p6, +2.0000714765E-1f); + _EIGEN_DECLARE_CONST_Packet8f(cephes_log_p7, -2.4999993993E-1f); + _EIGEN_DECLARE_CONST_Packet8f(cephes_log_p8, +3.3333331174E-1f); + _EIGEN_DECLARE_CONST_Packet8f(cephes_log_q1, -2.12194440e-4f); + _EIGEN_DECLARE_CONST_Packet8f(cephes_log_q2, 0.693359375f); + + Packet8f invalid_mask = _mm256_cmp_ps(x, _mm256_setzero_ps(), _CMP_NGE_UQ); // not greater equal is true if x is NaN + Packet8f iszero_mask = _mm256_cmp_ps(x, _mm256_setzero_ps(), _CMP_EQ_OQ); + + // Truncate input values to the minimum positive normal. + x = pmax(x, p8f_min_norm_pos); + + Packet8f emm0 = pshiftright(x,23); + Packet8f e = _mm256_sub_ps(emm0, p8f_126f); + + // Set the exponents to -1, i.e. x are in the range [0.5,1). + x = _mm256_and_ps(x, p8f_inv_mant_mask); + x = _mm256_or_ps(x, p8f_half); + + // part2: Shift the inputs from the range [0.5,1) to [sqrt(1/2),sqrt(2)) + // and shift by -1. The values are then centered around 0, which improves + // the stability of the polynomial evaluation. + // if( x < SQRTHF ) { + // e -= 1; + // x = x + x - 1.0; + // } else { x = x - 1.0; } + Packet8f mask = _mm256_cmp_ps(x, p8f_cephes_SQRTHF, _CMP_LT_OQ); + Packet8f tmp = _mm256_and_ps(x, mask); + x = psub(x, p8f_1); + e = psub(e, _mm256_and_ps(p8f_1, mask)); + x = padd(x, tmp); + + Packet8f x2 = pmul(x, x); + Packet8f x3 = pmul(x2, x); + + // Evaluate the polynomial approximant of degree 8 in three parts, probably + // to improve instruction-level parallelism. + Packet8f y, y1, y2; + y = pmadd(p8f_cephes_log_p0, x, p8f_cephes_log_p1); + y1 = pmadd(p8f_cephes_log_p3, x, p8f_cephes_log_p4); + y2 = pmadd(p8f_cephes_log_p6, x, p8f_cephes_log_p7); + y = pmadd(y, x, p8f_cephes_log_p2); + y1 = pmadd(y1, x, p8f_cephes_log_p5); + y2 = pmadd(y2, x, p8f_cephes_log_p8); + y = pmadd(y, x3, y1); + y = pmadd(y, x3, y2); + y = pmul(y, x3); + + // Add the logarithm of the exponent back to the result of the interpolation. + y1 = pmul(e, p8f_cephes_log_q1); + tmp = pmul(x2, p8f_half); + y = padd(y, y1); + x = psub(x, tmp); + y2 = pmul(e, p8f_cephes_log_q2); + x = padd(x, y); + x = padd(x, y2); + + // Filter out invalid inputs, i.e. negative arg will be NAN, 0 will be -INF. + return _mm256_or_ps( + _mm256_andnot_ps(iszero_mask, _mm256_or_ps(x, invalid_mask)), + _mm256_and_ps(iszero_mask, p8f_minus_inf)); +} + +// Exponential function. Works by writing "x = m*log(2) + r" where +// "m = floor(x/log(2)+1/2)" and "r" is the remainder. The result is then +// "exp(x) = 2^m*exp(r)" where exp(r) is in the range [-1,1). +template <> +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet8f +pexp(const Packet8f& _x) { + _EIGEN_DECLARE_CONST_Packet8f(1, 1.0f); + _EIGEN_DECLARE_CONST_Packet8f(half, 0.5f); + _EIGEN_DECLARE_CONST_Packet8f(127, 127.0f); + + _EIGEN_DECLARE_CONST_Packet8f(exp_hi, 88.3762626647950f); + _EIGEN_DECLARE_CONST_Packet8f(exp_lo, -88.3762626647949f); + + _EIGEN_DECLARE_CONST_Packet8f(cephes_LOG2EF, 1.44269504088896341f); + + _EIGEN_DECLARE_CONST_Packet8f(cephes_exp_p0, 1.9875691500E-4f); + _EIGEN_DECLARE_CONST_Packet8f(cephes_exp_p1, 1.3981999507E-3f); + _EIGEN_DECLARE_CONST_Packet8f(cephes_exp_p2, 8.3334519073E-3f); + _EIGEN_DECLARE_CONST_Packet8f(cephes_exp_p3, 4.1665795894E-2f); + _EIGEN_DECLARE_CONST_Packet8f(cephes_exp_p4, 1.6666665459E-1f); + _EIGEN_DECLARE_CONST_Packet8f(cephes_exp_p5, 5.0000001201E-1f); + + // Clamp x. + Packet8f x = pmax(pmin(_x, p8f_exp_hi), p8f_exp_lo); + + // Express exp(x) as exp(m*ln(2) + r), start by extracting + // m = floor(x/ln(2) + 0.5). + Packet8f m = _mm256_floor_ps(pmadd(x, p8f_cephes_LOG2EF, p8f_half)); + +// Get r = x - m*ln(2). If no FMA instructions are available, m*ln(2) is +// subtracted out in two parts, m*C1+m*C2 = m*ln(2), to avoid accumulating +// truncation errors. Note that we don't use the "pmadd" function here to +// ensure that a precision-preserving FMA instruction is used. +#ifdef EIGEN_VECTORIZE_FMA + _EIGEN_DECLARE_CONST_Packet8f(nln2, -0.6931471805599453f); + Packet8f r = _mm256_fmadd_ps(m, p8f_nln2, x); +#else + _EIGEN_DECLARE_CONST_Packet8f(cephes_exp_C1, 0.693359375f); + _EIGEN_DECLARE_CONST_Packet8f(cephes_exp_C2, -2.12194440e-4f); + Packet8f r = psub(x, pmul(m, p8f_cephes_exp_C1)); + r = psub(r, pmul(m, p8f_cephes_exp_C2)); +#endif + + Packet8f r2 = pmul(r, r); + + // TODO(gonnet): Split into odd/even polynomials and try to exploit + // instruction-level parallelism. + Packet8f y = p8f_cephes_exp_p0; + y = pmadd(y, r, p8f_cephes_exp_p1); + y = pmadd(y, r, p8f_cephes_exp_p2); + y = pmadd(y, r, p8f_cephes_exp_p3); + y = pmadd(y, r, p8f_cephes_exp_p4); + y = pmadd(y, r, p8f_cephes_exp_p5); + y = pmadd(y, r2, r); + y = padd(y, p8f_1); + + // Build emm0 = 2^m. + Packet8i emm0 = _mm256_cvttps_epi32(padd(m, p8f_127)); + emm0 = pshiftleft(emm0, 23); + + // Return 2^m * exp(r). + return pmax(pmul(y, _mm256_castsi256_ps(emm0)), _x); +} + +// Hyperbolic Tangent function. +template <> +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet8f +ptanh(const Packet8f& x) { + return internal::generic_fast_tanh_float(x); +} + +template <> +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet4d +pexp(const Packet4d& _x) { + Packet4d x = _x; + + _EIGEN_DECLARE_CONST_Packet4d(1, 1.0); + _EIGEN_DECLARE_CONST_Packet4d(2, 2.0); + _EIGEN_DECLARE_CONST_Packet4d(half, 0.5); + + _EIGEN_DECLARE_CONST_Packet4d(exp_hi, 709.437); + _EIGEN_DECLARE_CONST_Packet4d(exp_lo, -709.436139303); + + _EIGEN_DECLARE_CONST_Packet4d(cephes_LOG2EF, 1.4426950408889634073599); + + _EIGEN_DECLARE_CONST_Packet4d(cephes_exp_p0, 1.26177193074810590878e-4); + _EIGEN_DECLARE_CONST_Packet4d(cephes_exp_p1, 3.02994407707441961300e-2); + _EIGEN_DECLARE_CONST_Packet4d(cephes_exp_p2, 9.99999999999999999910e-1); + + _EIGEN_DECLARE_CONST_Packet4d(cephes_exp_q0, 3.00198505138664455042e-6); + _EIGEN_DECLARE_CONST_Packet4d(cephes_exp_q1, 2.52448340349684104192e-3); + _EIGEN_DECLARE_CONST_Packet4d(cephes_exp_q2, 2.27265548208155028766e-1); + _EIGEN_DECLARE_CONST_Packet4d(cephes_exp_q3, 2.00000000000000000009e0); + + _EIGEN_DECLARE_CONST_Packet4d(cephes_exp_C1, 0.693145751953125); + _EIGEN_DECLARE_CONST_Packet4d(cephes_exp_C2, 1.42860682030941723212e-6); + _EIGEN_DECLARE_CONST_Packet4i(1023, 1023); + + Packet4d tmp, fx; + + // clamp x + x = pmax(pmin(x, p4d_exp_hi), p4d_exp_lo); + // Express exp(x) as exp(g + n*log(2)). + fx = pmadd(p4d_cephes_LOG2EF, x, p4d_half); + + // Get the integer modulus of log(2), i.e. the "n" described above. + fx = _mm256_floor_pd(fx); + + // Get the remainder modulo log(2), i.e. the "g" described above. Subtract + // n*log(2) out in two steps, i.e. n*C1 + n*C2, C1+C2=log2 to get the last + // digits right. + tmp = pmul(fx, p4d_cephes_exp_C1); + Packet4d z = pmul(fx, p4d_cephes_exp_C2); + x = psub(x, tmp); + x = psub(x, z); + + Packet4d x2 = pmul(x, x); + + // Evaluate the numerator polynomial of the rational interpolant. + Packet4d px = p4d_cephes_exp_p0; + px = pmadd(px, x2, p4d_cephes_exp_p1); + px = pmadd(px, x2, p4d_cephes_exp_p2); + px = pmul(px, x); + + // Evaluate the denominator polynomial of the rational interpolant. + Packet4d qx = p4d_cephes_exp_q0; + qx = pmadd(qx, x2, p4d_cephes_exp_q1); + qx = pmadd(qx, x2, p4d_cephes_exp_q2); + qx = pmadd(qx, x2, p4d_cephes_exp_q3); + + // I don't really get this bit, copied from the SSE2 routines, so... + // TODO(gonnet): Figure out what is going on here, perhaps find a better + // rational interpolant? + x = _mm256_div_pd(px, psub(qx, px)); + x = pmadd(p4d_2, x, p4d_1); + + // Build e=2^n by constructing the exponents in a 128-bit vector and + // shifting them to where they belong in double-precision values. + __m128i emm0 = _mm256_cvtpd_epi32(fx); + emm0 = _mm_add_epi32(emm0, p4i_1023); + emm0 = _mm_shuffle_epi32(emm0, _MM_SHUFFLE(3, 1, 2, 0)); + __m128i lo = _mm_slli_epi64(emm0, 52); + __m128i hi = _mm_slli_epi64(_mm_srli_epi64(emm0, 32), 52); + __m256i e = _mm256_insertf128_si256(_mm256_setzero_si256(), lo, 0); + e = _mm256_insertf128_si256(e, hi, 1); + + // Construct the result 2^n * exp(g) = e * x. The max is used to catch + // non-finite values in the input. + return pmax(pmul(x, _mm256_castsi256_pd(e)), _x); +} + +// Functions for sqrt. +// The EIGEN_FAST_MATH version uses the _mm_rsqrt_ps approximation and one step +// of Newton's method, at a cost of 1-2 bits of precision as opposed to the +// exact solution. It does not handle +inf, or denormalized numbers correctly. +// The main advantage of this approach is not just speed, but also the fact that +// it can be inlined and pipelined with other computations, further reducing its +// effective latency. This is similar to Quake3's fast inverse square root. +// For detail see here: http://www.beyond3d.com/content/articles/8/ +#if EIGEN_FAST_MATH +template <> +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet8f +psqrt(const Packet8f& _x) { + Packet8f half = pmul(_x, pset1(.5f)); + Packet8f denormal_mask = _mm256_and_ps( + _mm256_cmp_ps(_x, pset1((std::numeric_limits::min)()), + _CMP_LT_OQ), + _mm256_cmp_ps(_x, _mm256_setzero_ps(), _CMP_GE_OQ)); + + // Compute approximate reciprocal sqrt. + Packet8f x = _mm256_rsqrt_ps(_x); + // Do a single step of Newton's iteration. + x = pmul(x, psub(pset1(1.5f), pmul(half, pmul(x,x)))); + // Flush results for denormals to zero. + return _mm256_andnot_ps(denormal_mask, pmul(_x,x)); +} +#else +template <> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet8f psqrt(const Packet8f& x) { + return _mm256_sqrt_ps(x); +} +#endif +template <> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet4d psqrt(const Packet4d& x) { + return _mm256_sqrt_pd(x); +} +#if EIGEN_FAST_MATH + +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet8f prsqrt(const Packet8f& _x) { + _EIGEN_DECLARE_CONST_Packet8f_FROM_INT(inf, 0x7f800000); + _EIGEN_DECLARE_CONST_Packet8f_FROM_INT(nan, 0x7fc00000); + _EIGEN_DECLARE_CONST_Packet8f(one_point_five, 1.5f); + _EIGEN_DECLARE_CONST_Packet8f(minus_half, -0.5f); + _EIGEN_DECLARE_CONST_Packet8f_FROM_INT(flt_min, 0x00800000); + + Packet8f neg_half = pmul(_x, p8f_minus_half); + + // select only the inverse sqrt of positive normal inputs (denormals are + // flushed to zero and cause infs as well). + Packet8f le_zero_mask = _mm256_cmp_ps(_x, p8f_flt_min, _CMP_LT_OQ); + Packet8f x = _mm256_andnot_ps(le_zero_mask, _mm256_rsqrt_ps(_x)); + + // Fill in NaNs and Infs for the negative/zero entries. + Packet8f neg_mask = _mm256_cmp_ps(_x, _mm256_setzero_ps(), _CMP_LT_OQ); + Packet8f zero_mask = _mm256_andnot_ps(neg_mask, le_zero_mask); + Packet8f infs_and_nans = _mm256_or_ps(_mm256_and_ps(neg_mask, p8f_nan), + _mm256_and_ps(zero_mask, p8f_inf)); + + // Do a single step of Newton's iteration. + x = pmul(x, pmadd(neg_half, pmul(x, x), p8f_one_point_five)); + + // Insert NaNs and Infs in all the right places. + return _mm256_or_ps(x, infs_and_nans); +} + +#else +template <> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet8f prsqrt(const Packet8f& x) { + _EIGEN_DECLARE_CONST_Packet8f(one, 1.0f); + return _mm256_div_ps(p8f_one, _mm256_sqrt_ps(x)); +} +#endif + +template <> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet4d prsqrt(const Packet4d& x) { + _EIGEN_DECLARE_CONST_Packet4d(one, 1.0); + return _mm256_div_pd(p4d_one, _mm256_sqrt_pd(x)); +} + + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_MATH_FUNCTIONS_AVX_H diff --git a/libs/eigen3/Eigen/src/Core/arch/AVX/PacketMath.h b/libs/eigen3/Eigen/src/Core/arch/AVX/PacketMath.h new file mode 100644 index 000000000..195d40fb4 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/arch/AVX/PacketMath.h @@ -0,0 +1,633 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner (benoit.steiner.goog@gmail.com) +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_PACKET_MATH_AVX_H +#define EIGEN_PACKET_MATH_AVX_H + +namespace Eigen { + +namespace internal { + +#ifndef EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD +#define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 8 +#endif + +#ifndef EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS +#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS (2*sizeof(void*)) +#endif + +#ifdef __FMA__ +#ifndef EIGEN_HAS_SINGLE_INSTRUCTION_MADD +#define EIGEN_HAS_SINGLE_INSTRUCTION_MADD +#endif +#endif + +typedef __m256 Packet8f; +typedef __m256i Packet8i; +typedef __m256d Packet4d; + +template<> struct is_arithmetic<__m256> { enum { value = true }; }; +template<> struct is_arithmetic<__m256i> { enum { value = true }; }; +template<> struct is_arithmetic<__m256d> { enum { value = true }; }; + +#define _EIGEN_DECLARE_CONST_Packet8f(NAME,X) \ + const Packet8f p8f_##NAME = pset1(X) + +#define _EIGEN_DECLARE_CONST_Packet4d(NAME,X) \ + const Packet4d p4d_##NAME = pset1(X) + +#define _EIGEN_DECLARE_CONST_Packet8f_FROM_INT(NAME,X) \ + const Packet8f p8f_##NAME = _mm256_castsi256_ps(pset1(X)) + +#define _EIGEN_DECLARE_CONST_Packet8i(NAME,X) \ + const Packet8i p8i_##NAME = pset1(X) + +// Use the packet_traits defined in AVX512/PacketMath.h instead if we're going +// to leverage AVX512 instructions. +#ifndef EIGEN_VECTORIZE_AVX512 +template<> struct packet_traits : default_packet_traits +{ + typedef Packet8f type; + typedef Packet4f half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size=8, + HasHalfPacket = 1, + + HasDiv = 1, + HasSin = EIGEN_FAST_MATH, + HasCos = 0, + HasLog = 1, + HasExp = 1, + HasSqrt = 1, + HasRsqrt = 1, + HasTanh = EIGEN_FAST_MATH, + HasBlend = 1, + HasRound = 1, + HasFloor = 1, + HasCeil = 1 + }; +}; +template<> struct packet_traits : default_packet_traits +{ + typedef Packet4d type; + typedef Packet2d half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size=4, + HasHalfPacket = 1, + + HasDiv = 1, + HasExp = 1, + HasSqrt = 1, + HasRsqrt = 1, + HasBlend = 1, + HasRound = 1, + HasFloor = 1, + HasCeil = 1 + }; +}; +#endif + +template<> struct scalar_div_cost { enum { value = 14 }; }; +template<> struct scalar_div_cost { enum { value = 16 }; }; + +/* Proper support for integers is only provided by AVX2. In the meantime, we'll + use SSE instructions and packets to deal with integers. +template<> struct packet_traits : default_packet_traits +{ + typedef Packet8i type; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size=8 + }; +}; +*/ + +template<> struct unpacket_traits { typedef float type; typedef Packet4f half; enum {size=8, alignment=Aligned32}; }; +template<> struct unpacket_traits { typedef double type; typedef Packet2d half; enum {size=4, alignment=Aligned32}; }; +template<> struct unpacket_traits { typedef int type; typedef Packet4i half; enum {size=8, alignment=Aligned32}; }; + +template<> EIGEN_STRONG_INLINE Packet8f pset1(const float& from) { return _mm256_set1_ps(from); } +template<> EIGEN_STRONG_INLINE Packet4d pset1(const double& from) { return _mm256_set1_pd(from); } +template<> EIGEN_STRONG_INLINE Packet8i pset1(const int& from) { return _mm256_set1_epi32(from); } + +template<> EIGEN_STRONG_INLINE Packet8f pload1(const float* from) { return _mm256_broadcast_ss(from); } +template<> EIGEN_STRONG_INLINE Packet4d pload1(const double* from) { return _mm256_broadcast_sd(from); } + +template<> EIGEN_STRONG_INLINE Packet8f plset(const float& a) { return _mm256_add_ps(_mm256_set1_ps(a), _mm256_set_ps(7.0,6.0,5.0,4.0,3.0,2.0,1.0,0.0)); } +template<> EIGEN_STRONG_INLINE Packet4d plset(const double& a) { return _mm256_add_pd(_mm256_set1_pd(a), _mm256_set_pd(3.0,2.0,1.0,0.0)); } + +template<> EIGEN_STRONG_INLINE Packet8f padd(const Packet8f& a, const Packet8f& b) { return _mm256_add_ps(a,b); } +template<> EIGEN_STRONG_INLINE Packet4d padd(const Packet4d& a, const Packet4d& b) { return _mm256_add_pd(a,b); } + +template<> EIGEN_STRONG_INLINE Packet8f psub(const Packet8f& a, const Packet8f& b) { return _mm256_sub_ps(a,b); } +template<> EIGEN_STRONG_INLINE Packet4d psub(const Packet4d& a, const Packet4d& b) { return _mm256_sub_pd(a,b); } + +template<> EIGEN_STRONG_INLINE Packet8f pnegate(const Packet8f& a) +{ + return _mm256_sub_ps(_mm256_set1_ps(0.0),a); +} +template<> EIGEN_STRONG_INLINE Packet4d pnegate(const Packet4d& a) +{ + return _mm256_sub_pd(_mm256_set1_pd(0.0),a); +} + +template<> EIGEN_STRONG_INLINE Packet8f pconj(const Packet8f& a) { return a; } +template<> EIGEN_STRONG_INLINE Packet4d pconj(const Packet4d& a) { return a; } +template<> EIGEN_STRONG_INLINE Packet8i pconj(const Packet8i& a) { return a; } + +template<> EIGEN_STRONG_INLINE Packet8f pmul(const Packet8f& a, const Packet8f& b) { return _mm256_mul_ps(a,b); } +template<> EIGEN_STRONG_INLINE Packet4d pmul(const Packet4d& a, const Packet4d& b) { return _mm256_mul_pd(a,b); } + + +template<> EIGEN_STRONG_INLINE Packet8f pdiv(const Packet8f& a, const Packet8f& b) { return _mm256_div_ps(a,b); } +template<> EIGEN_STRONG_INLINE Packet4d pdiv(const Packet4d& a, const Packet4d& b) { return _mm256_div_pd(a,b); } +template<> EIGEN_STRONG_INLINE Packet8i pdiv(const Packet8i& /*a*/, const Packet8i& /*b*/) +{ eigen_assert(false && "packet integer division are not supported by AVX"); + return pset1(0); +} + +#ifdef __FMA__ +template<> EIGEN_STRONG_INLINE Packet8f pmadd(const Packet8f& a, const Packet8f& b, const Packet8f& c) { +#if ( EIGEN_COMP_GNUC_STRICT || (EIGEN_COMP_CLANG && (EIGEN_COMP_CLANG<308)) ) + // clang stupidly generates a vfmadd213ps instruction plus some vmovaps on registers, + // and gcc stupidly generates a vfmadd132ps instruction, + // so let's enforce it to generate a vfmadd231ps instruction since the most common use case is to accumulate + // the result of the product. + Packet8f res = c; + __asm__("vfmadd231ps %[a], %[b], %[c]" : [c] "+x" (res) : [a] "x" (a), [b] "x" (b)); + return res; +#else + return _mm256_fmadd_ps(a,b,c); +#endif +} +template<> EIGEN_STRONG_INLINE Packet4d pmadd(const Packet4d& a, const Packet4d& b, const Packet4d& c) { +#if ( EIGEN_COMP_GNUC_STRICT || (EIGEN_COMP_CLANG && (EIGEN_COMP_CLANG<308)) ) + // see above + Packet4d res = c; + __asm__("vfmadd231pd %[a], %[b], %[c]" : [c] "+x" (res) : [a] "x" (a), [b] "x" (b)); + return res; +#else + return _mm256_fmadd_pd(a,b,c); +#endif +} +#endif + +template<> EIGEN_STRONG_INLINE Packet8f pmin(const Packet8f& a, const Packet8f& b) { return _mm256_min_ps(a,b); } +template<> EIGEN_STRONG_INLINE Packet4d pmin(const Packet4d& a, const Packet4d& b) { return _mm256_min_pd(a,b); } + +template<> EIGEN_STRONG_INLINE Packet8f pmax(const Packet8f& a, const Packet8f& b) { return _mm256_max_ps(a,b); } +template<> EIGEN_STRONG_INLINE Packet4d pmax(const Packet4d& a, const Packet4d& b) { return _mm256_max_pd(a,b); } + +template<> EIGEN_STRONG_INLINE Packet8f pround(const Packet8f& a) { return _mm256_round_ps(a, _MM_FROUND_CUR_DIRECTION); } +template<> EIGEN_STRONG_INLINE Packet4d pround(const Packet4d& a) { return _mm256_round_pd(a, _MM_FROUND_CUR_DIRECTION); } + +template<> EIGEN_STRONG_INLINE Packet8f pceil(const Packet8f& a) { return _mm256_ceil_ps(a); } +template<> EIGEN_STRONG_INLINE Packet4d pceil(const Packet4d& a) { return _mm256_ceil_pd(a); } + +template<> EIGEN_STRONG_INLINE Packet8f pfloor(const Packet8f& a) { return _mm256_floor_ps(a); } +template<> EIGEN_STRONG_INLINE Packet4d pfloor(const Packet4d& a) { return _mm256_floor_pd(a); } + +template<> EIGEN_STRONG_INLINE Packet8f pand(const Packet8f& a, const Packet8f& b) { return _mm256_and_ps(a,b); } +template<> EIGEN_STRONG_INLINE Packet4d pand(const Packet4d& a, const Packet4d& b) { return _mm256_and_pd(a,b); } + +template<> EIGEN_STRONG_INLINE Packet8f por(const Packet8f& a, const Packet8f& b) { return _mm256_or_ps(a,b); } +template<> EIGEN_STRONG_INLINE Packet4d por(const Packet4d& a, const Packet4d& b) { return _mm256_or_pd(a,b); } + +template<> EIGEN_STRONG_INLINE Packet8f pxor(const Packet8f& a, const Packet8f& b) { return _mm256_xor_ps(a,b); } +template<> EIGEN_STRONG_INLINE Packet4d pxor(const Packet4d& a, const Packet4d& b) { return _mm256_xor_pd(a,b); } + +template<> EIGEN_STRONG_INLINE Packet8f pandnot(const Packet8f& a, const Packet8f& b) { return _mm256_andnot_ps(a,b); } +template<> EIGEN_STRONG_INLINE Packet4d pandnot(const Packet4d& a, const Packet4d& b) { return _mm256_andnot_pd(a,b); } + +template<> EIGEN_STRONG_INLINE Packet8f pload(const float* from) { EIGEN_DEBUG_ALIGNED_LOAD return _mm256_load_ps(from); } +template<> EIGEN_STRONG_INLINE Packet4d pload(const double* from) { EIGEN_DEBUG_ALIGNED_LOAD return _mm256_load_pd(from); } +template<> EIGEN_STRONG_INLINE Packet8i pload(const int* from) { EIGEN_DEBUG_ALIGNED_LOAD return _mm256_load_si256(reinterpret_cast(from)); } + +template<> EIGEN_STRONG_INLINE Packet8f ploadu(const float* from) { EIGEN_DEBUG_UNALIGNED_LOAD return _mm256_loadu_ps(from); } +template<> EIGEN_STRONG_INLINE Packet4d ploadu(const double* from) { EIGEN_DEBUG_UNALIGNED_LOAD return _mm256_loadu_pd(from); } +template<> EIGEN_STRONG_INLINE Packet8i ploadu(const int* from) { EIGEN_DEBUG_UNALIGNED_LOAD return _mm256_loadu_si256(reinterpret_cast(from)); } + +// Loads 4 floats from memory a returns the packet {a0, a0 a1, a1, a2, a2, a3, a3} +template<> EIGEN_STRONG_INLINE Packet8f ploaddup(const float* from) +{ + // TODO try to find a way to avoid the need of a temporary register +// Packet8f tmp = _mm256_castps128_ps256(_mm_loadu_ps(from)); +// tmp = _mm256_insertf128_ps(tmp, _mm_movehl_ps(_mm256_castps256_ps128(tmp),_mm256_castps256_ps128(tmp)), 1); +// return _mm256_unpacklo_ps(tmp,tmp); + + // _mm256_insertf128_ps is very slow on Haswell, thus: + Packet8f tmp = _mm256_broadcast_ps((const __m128*)(const void*)from); + // mimic an "inplace" permutation of the lower 128bits using a blend + tmp = _mm256_blend_ps(tmp,_mm256_castps128_ps256(_mm_permute_ps( _mm256_castps256_ps128(tmp), _MM_SHUFFLE(1,0,1,0))), 15); + // then we can perform a consistent permutation on the global register to get everything in shape: + return _mm256_permute_ps(tmp, _MM_SHUFFLE(3,3,2,2)); +} +// Loads 2 doubles from memory a returns the packet {a0, a0 a1, a1} +template<> EIGEN_STRONG_INLINE Packet4d ploaddup(const double* from) +{ + Packet4d tmp = _mm256_broadcast_pd((const __m128d*)(const void*)from); + return _mm256_permute_pd(tmp, 3<<2); +} + +// Loads 2 floats from memory a returns the packet {a0, a0 a0, a0, a1, a1, a1, a1} +template<> EIGEN_STRONG_INLINE Packet8f ploadquad(const float* from) +{ + Packet8f tmp = _mm256_castps128_ps256(_mm_broadcast_ss(from)); + return _mm256_insertf128_ps(tmp, _mm_broadcast_ss(from+1), 1); +} + +template<> EIGEN_STRONG_INLINE void pstore(float* to, const Packet8f& from) { EIGEN_DEBUG_ALIGNED_STORE _mm256_store_ps(to, from); } +template<> EIGEN_STRONG_INLINE void pstore(double* to, const Packet4d& from) { EIGEN_DEBUG_ALIGNED_STORE _mm256_store_pd(to, from); } +template<> EIGEN_STRONG_INLINE void pstore(int* to, const Packet8i& from) { EIGEN_DEBUG_ALIGNED_STORE _mm256_storeu_si256(reinterpret_cast<__m256i*>(to), from); } + +template<> EIGEN_STRONG_INLINE void pstoreu(float* to, const Packet8f& from) { EIGEN_DEBUG_UNALIGNED_STORE _mm256_storeu_ps(to, from); } +template<> EIGEN_STRONG_INLINE void pstoreu(double* to, const Packet4d& from) { EIGEN_DEBUG_UNALIGNED_STORE _mm256_storeu_pd(to, from); } +template<> EIGEN_STRONG_INLINE void pstoreu(int* to, const Packet8i& from) { EIGEN_DEBUG_UNALIGNED_STORE _mm256_storeu_si256(reinterpret_cast<__m256i*>(to), from); } + +// NOTE: leverage _mm256_i32gather_ps and _mm256_i32gather_pd if AVX2 instructions are available +// NOTE: for the record the following seems to be slower: return _mm256_i32gather_ps(from, _mm256_set1_epi32(stride), 4); +template<> EIGEN_DEVICE_FUNC inline Packet8f pgather(const float* from, Index stride) +{ + return _mm256_set_ps(from[7*stride], from[6*stride], from[5*stride], from[4*stride], + from[3*stride], from[2*stride], from[1*stride], from[0*stride]); +} +template<> EIGEN_DEVICE_FUNC inline Packet4d pgather(const double* from, Index stride) +{ + return _mm256_set_pd(from[3*stride], from[2*stride], from[1*stride], from[0*stride]); +} + +template<> EIGEN_DEVICE_FUNC inline void pscatter(float* to, const Packet8f& from, Index stride) +{ + __m128 low = _mm256_extractf128_ps(from, 0); + to[stride*0] = _mm_cvtss_f32(low); + to[stride*1] = _mm_cvtss_f32(_mm_shuffle_ps(low, low, 1)); + to[stride*2] = _mm_cvtss_f32(_mm_shuffle_ps(low, low, 2)); + to[stride*3] = _mm_cvtss_f32(_mm_shuffle_ps(low, low, 3)); + + __m128 high = _mm256_extractf128_ps(from, 1); + to[stride*4] = _mm_cvtss_f32(high); + to[stride*5] = _mm_cvtss_f32(_mm_shuffle_ps(high, high, 1)); + to[stride*6] = _mm_cvtss_f32(_mm_shuffle_ps(high, high, 2)); + to[stride*7] = _mm_cvtss_f32(_mm_shuffle_ps(high, high, 3)); +} +template<> EIGEN_DEVICE_FUNC inline void pscatter(double* to, const Packet4d& from, Index stride) +{ + __m128d low = _mm256_extractf128_pd(from, 0); + to[stride*0] = _mm_cvtsd_f64(low); + to[stride*1] = _mm_cvtsd_f64(_mm_shuffle_pd(low, low, 1)); + __m128d high = _mm256_extractf128_pd(from, 1); + to[stride*2] = _mm_cvtsd_f64(high); + to[stride*3] = _mm_cvtsd_f64(_mm_shuffle_pd(high, high, 1)); +} + +template<> EIGEN_STRONG_INLINE void pstore1(float* to, const float& a) +{ + Packet8f pa = pset1(a); + pstore(to, pa); +} +template<> EIGEN_STRONG_INLINE void pstore1(double* to, const double& a) +{ + Packet4d pa = pset1(a); + pstore(to, pa); +} +template<> EIGEN_STRONG_INLINE void pstore1(int* to, const int& a) +{ + Packet8i pa = pset1(a); + pstore(to, pa); +} + +#ifndef EIGEN_VECTORIZE_AVX512 +template<> EIGEN_STRONG_INLINE void prefetch(const float* addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); } +template<> EIGEN_STRONG_INLINE void prefetch(const double* addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); } +template<> EIGEN_STRONG_INLINE void prefetch(const int* addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); } +#endif + +template<> EIGEN_STRONG_INLINE float pfirst(const Packet8f& a) { + return _mm_cvtss_f32(_mm256_castps256_ps128(a)); +} +template<> EIGEN_STRONG_INLINE double pfirst(const Packet4d& a) { + return _mm_cvtsd_f64(_mm256_castpd256_pd128(a)); +} +template<> EIGEN_STRONG_INLINE int pfirst(const Packet8i& a) { + return _mm_cvtsi128_si32(_mm256_castsi256_si128(a)); +} + + +template<> EIGEN_STRONG_INLINE Packet8f preverse(const Packet8f& a) +{ + __m256 tmp = _mm256_shuffle_ps(a,a,0x1b); + return _mm256_permute2f128_ps(tmp, tmp, 1); +} +template<> EIGEN_STRONG_INLINE Packet4d preverse(const Packet4d& a) +{ + __m256d tmp = _mm256_shuffle_pd(a,a,5); + return _mm256_permute2f128_pd(tmp, tmp, 1); + + __m256d swap_halves = _mm256_permute2f128_pd(a,a,1); + return _mm256_permute_pd(swap_halves,5); +} + +// pabs should be ok +template<> EIGEN_STRONG_INLINE Packet8f pabs(const Packet8f& a) +{ + const Packet8f mask = _mm256_castsi256_ps(_mm256_setr_epi32(0x7FFFFFFF,0x7FFFFFFF,0x7FFFFFFF,0x7FFFFFFF,0x7FFFFFFF,0x7FFFFFFF,0x7FFFFFFF,0x7FFFFFFF)); + return _mm256_and_ps(a,mask); +} +template<> EIGEN_STRONG_INLINE Packet4d pabs(const Packet4d& a) +{ + const Packet4d mask = _mm256_castsi256_pd(_mm256_setr_epi32(0xFFFFFFFF,0x7FFFFFFF,0xFFFFFFFF,0x7FFFFFFF,0xFFFFFFFF,0x7FFFFFFF,0xFFFFFFFF,0x7FFFFFFF)); + return _mm256_and_pd(a,mask); +} + +// preduxp should be ok +// FIXME: why is this ok? why isn't the simply implementation working as expected? +template<> EIGEN_STRONG_INLINE Packet8f preduxp(const Packet8f* vecs) +{ + __m256 hsum1 = _mm256_hadd_ps(vecs[0], vecs[1]); + __m256 hsum2 = _mm256_hadd_ps(vecs[2], vecs[3]); + __m256 hsum3 = _mm256_hadd_ps(vecs[4], vecs[5]); + __m256 hsum4 = _mm256_hadd_ps(vecs[6], vecs[7]); + + __m256 hsum5 = _mm256_hadd_ps(hsum1, hsum1); + __m256 hsum6 = _mm256_hadd_ps(hsum2, hsum2); + __m256 hsum7 = _mm256_hadd_ps(hsum3, hsum3); + __m256 hsum8 = _mm256_hadd_ps(hsum4, hsum4); + + __m256 perm1 = _mm256_permute2f128_ps(hsum5, hsum5, 0x23); + __m256 perm2 = _mm256_permute2f128_ps(hsum6, hsum6, 0x23); + __m256 perm3 = _mm256_permute2f128_ps(hsum7, hsum7, 0x23); + __m256 perm4 = _mm256_permute2f128_ps(hsum8, hsum8, 0x23); + + __m256 sum1 = _mm256_add_ps(perm1, hsum5); + __m256 sum2 = _mm256_add_ps(perm2, hsum6); + __m256 sum3 = _mm256_add_ps(perm3, hsum7); + __m256 sum4 = _mm256_add_ps(perm4, hsum8); + + __m256 blend1 = _mm256_blend_ps(sum1, sum2, 0xcc); + __m256 blend2 = _mm256_blend_ps(sum3, sum4, 0xcc); + + __m256 final = _mm256_blend_ps(blend1, blend2, 0xf0); + return final; +} +template<> EIGEN_STRONG_INLINE Packet4d preduxp(const Packet4d* vecs) +{ + Packet4d tmp0, tmp1; + + tmp0 = _mm256_hadd_pd(vecs[0], vecs[1]); + tmp0 = _mm256_add_pd(tmp0, _mm256_permute2f128_pd(tmp0, tmp0, 1)); + + tmp1 = _mm256_hadd_pd(vecs[2], vecs[3]); + tmp1 = _mm256_add_pd(tmp1, _mm256_permute2f128_pd(tmp1, tmp1, 1)); + + return _mm256_blend_pd(tmp0, tmp1, 0xC); +} + +template<> EIGEN_STRONG_INLINE float predux(const Packet8f& a) +{ + return predux(Packet4f(_mm_add_ps(_mm256_castps256_ps128(a),_mm256_extractf128_ps(a,1)))); +} +template<> EIGEN_STRONG_INLINE double predux(const Packet4d& a) +{ + return predux(Packet2d(_mm_add_pd(_mm256_castpd256_pd128(a),_mm256_extractf128_pd(a,1)))); +} + +template<> EIGEN_STRONG_INLINE Packet4f predux_downto4(const Packet8f& a) +{ + return _mm_add_ps(_mm256_castps256_ps128(a),_mm256_extractf128_ps(a,1)); +} + +template<> EIGEN_STRONG_INLINE float predux_mul(const Packet8f& a) +{ + Packet8f tmp; + tmp = _mm256_mul_ps(a, _mm256_permute2f128_ps(a,a,1)); + tmp = _mm256_mul_ps(tmp, _mm256_shuffle_ps(tmp,tmp,_MM_SHUFFLE(1,0,3,2))); + return pfirst(_mm256_mul_ps(tmp, _mm256_shuffle_ps(tmp,tmp,1))); +} +template<> EIGEN_STRONG_INLINE double predux_mul(const Packet4d& a) +{ + Packet4d tmp; + tmp = _mm256_mul_pd(a, _mm256_permute2f128_pd(a,a,1)); + return pfirst(_mm256_mul_pd(tmp, _mm256_shuffle_pd(tmp,tmp,1))); +} + +template<> EIGEN_STRONG_INLINE float predux_min(const Packet8f& a) +{ + Packet8f tmp = _mm256_min_ps(a, _mm256_permute2f128_ps(a,a,1)); + tmp = _mm256_min_ps(tmp, _mm256_shuffle_ps(tmp,tmp,_MM_SHUFFLE(1,0,3,2))); + return pfirst(_mm256_min_ps(tmp, _mm256_shuffle_ps(tmp,tmp,1))); +} +template<> EIGEN_STRONG_INLINE double predux_min(const Packet4d& a) +{ + Packet4d tmp = _mm256_min_pd(a, _mm256_permute2f128_pd(a,a,1)); + return pfirst(_mm256_min_pd(tmp, _mm256_shuffle_pd(tmp, tmp, 1))); +} + +template<> EIGEN_STRONG_INLINE float predux_max(const Packet8f& a) +{ + Packet8f tmp = _mm256_max_ps(a, _mm256_permute2f128_ps(a,a,1)); + tmp = _mm256_max_ps(tmp, _mm256_shuffle_ps(tmp,tmp,_MM_SHUFFLE(1,0,3,2))); + return pfirst(_mm256_max_ps(tmp, _mm256_shuffle_ps(tmp,tmp,1))); +} + +template<> EIGEN_STRONG_INLINE double predux_max(const Packet4d& a) +{ + Packet4d tmp = _mm256_max_pd(a, _mm256_permute2f128_pd(a,a,1)); + return pfirst(_mm256_max_pd(tmp, _mm256_shuffle_pd(tmp, tmp, 1))); +} + + +template +struct palign_impl +{ + static EIGEN_STRONG_INLINE void run(Packet8f& first, const Packet8f& second) + { + if (Offset==1) + { + first = _mm256_blend_ps(first, second, 1); + Packet8f tmp1 = _mm256_permute_ps (first, _MM_SHUFFLE(0,3,2,1)); + Packet8f tmp2 = _mm256_permute2f128_ps (tmp1, tmp1, 1); + first = _mm256_blend_ps(tmp1, tmp2, 0x88); + } + else if (Offset==2) + { + first = _mm256_blend_ps(first, second, 3); + Packet8f tmp1 = _mm256_permute_ps (first, _MM_SHUFFLE(1,0,3,2)); + Packet8f tmp2 = _mm256_permute2f128_ps (tmp1, tmp1, 1); + first = _mm256_blend_ps(tmp1, tmp2, 0xcc); + } + else if (Offset==3) + { + first = _mm256_blend_ps(first, second, 7); + Packet8f tmp1 = _mm256_permute_ps (first, _MM_SHUFFLE(2,1,0,3)); + Packet8f tmp2 = _mm256_permute2f128_ps (tmp1, tmp1, 1); + first = _mm256_blend_ps(tmp1, tmp2, 0xee); + } + else if (Offset==4) + { + first = _mm256_blend_ps(first, second, 15); + Packet8f tmp1 = _mm256_permute_ps (first, _MM_SHUFFLE(3,2,1,0)); + Packet8f tmp2 = _mm256_permute2f128_ps (tmp1, tmp1, 1); + first = _mm256_permute_ps(tmp2, _MM_SHUFFLE(3,2,1,0)); + } + else if (Offset==5) + { + first = _mm256_blend_ps(first, second, 31); + first = _mm256_permute2f128_ps(first, first, 1); + Packet8f tmp = _mm256_permute_ps (first, _MM_SHUFFLE(0,3,2,1)); + first = _mm256_permute2f128_ps(tmp, tmp, 1); + first = _mm256_blend_ps(tmp, first, 0x88); + } + else if (Offset==6) + { + first = _mm256_blend_ps(first, second, 63); + first = _mm256_permute2f128_ps(first, first, 1); + Packet8f tmp = _mm256_permute_ps (first, _MM_SHUFFLE(1,0,3,2)); + first = _mm256_permute2f128_ps(tmp, tmp, 1); + first = _mm256_blend_ps(tmp, first, 0xcc); + } + else if (Offset==7) + { + first = _mm256_blend_ps(first, second, 127); + first = _mm256_permute2f128_ps(first, first, 1); + Packet8f tmp = _mm256_permute_ps (first, _MM_SHUFFLE(2,1,0,3)); + first = _mm256_permute2f128_ps(tmp, tmp, 1); + first = _mm256_blend_ps(tmp, first, 0xee); + } + } +}; + +template +struct palign_impl +{ + static EIGEN_STRONG_INLINE void run(Packet4d& first, const Packet4d& second) + { + if (Offset==1) + { + first = _mm256_blend_pd(first, second, 1); + __m256d tmp = _mm256_permute_pd(first, 5); + first = _mm256_permute2f128_pd(tmp, tmp, 1); + first = _mm256_blend_pd(tmp, first, 0xA); + } + else if (Offset==2) + { + first = _mm256_blend_pd(first, second, 3); + first = _mm256_permute2f128_pd(first, first, 1); + } + else if (Offset==3) + { + first = _mm256_blend_pd(first, second, 7); + __m256d tmp = _mm256_permute_pd(first, 5); + first = _mm256_permute2f128_pd(tmp, tmp, 1); + first = _mm256_blend_pd(tmp, first, 5); + } + } +}; + +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + __m256 T0 = _mm256_unpacklo_ps(kernel.packet[0], kernel.packet[1]); + __m256 T1 = _mm256_unpackhi_ps(kernel.packet[0], kernel.packet[1]); + __m256 T2 = _mm256_unpacklo_ps(kernel.packet[2], kernel.packet[3]); + __m256 T3 = _mm256_unpackhi_ps(kernel.packet[2], kernel.packet[3]); + __m256 T4 = _mm256_unpacklo_ps(kernel.packet[4], kernel.packet[5]); + __m256 T5 = _mm256_unpackhi_ps(kernel.packet[4], kernel.packet[5]); + __m256 T6 = _mm256_unpacklo_ps(kernel.packet[6], kernel.packet[7]); + __m256 T7 = _mm256_unpackhi_ps(kernel.packet[6], kernel.packet[7]); + __m256 S0 = _mm256_shuffle_ps(T0,T2,_MM_SHUFFLE(1,0,1,0)); + __m256 S1 = _mm256_shuffle_ps(T0,T2,_MM_SHUFFLE(3,2,3,2)); + __m256 S2 = _mm256_shuffle_ps(T1,T3,_MM_SHUFFLE(1,0,1,0)); + __m256 S3 = _mm256_shuffle_ps(T1,T3,_MM_SHUFFLE(3,2,3,2)); + __m256 S4 = _mm256_shuffle_ps(T4,T6,_MM_SHUFFLE(1,0,1,0)); + __m256 S5 = _mm256_shuffle_ps(T4,T6,_MM_SHUFFLE(3,2,3,2)); + __m256 S6 = _mm256_shuffle_ps(T5,T7,_MM_SHUFFLE(1,0,1,0)); + __m256 S7 = _mm256_shuffle_ps(T5,T7,_MM_SHUFFLE(3,2,3,2)); + kernel.packet[0] = _mm256_permute2f128_ps(S0, S4, 0x20); + kernel.packet[1] = _mm256_permute2f128_ps(S1, S5, 0x20); + kernel.packet[2] = _mm256_permute2f128_ps(S2, S6, 0x20); + kernel.packet[3] = _mm256_permute2f128_ps(S3, S7, 0x20); + kernel.packet[4] = _mm256_permute2f128_ps(S0, S4, 0x31); + kernel.packet[5] = _mm256_permute2f128_ps(S1, S5, 0x31); + kernel.packet[6] = _mm256_permute2f128_ps(S2, S6, 0x31); + kernel.packet[7] = _mm256_permute2f128_ps(S3, S7, 0x31); +} + +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + __m256 T0 = _mm256_unpacklo_ps(kernel.packet[0], kernel.packet[1]); + __m256 T1 = _mm256_unpackhi_ps(kernel.packet[0], kernel.packet[1]); + __m256 T2 = _mm256_unpacklo_ps(kernel.packet[2], kernel.packet[3]); + __m256 T3 = _mm256_unpackhi_ps(kernel.packet[2], kernel.packet[3]); + + __m256 S0 = _mm256_shuffle_ps(T0,T2,_MM_SHUFFLE(1,0,1,0)); + __m256 S1 = _mm256_shuffle_ps(T0,T2,_MM_SHUFFLE(3,2,3,2)); + __m256 S2 = _mm256_shuffle_ps(T1,T3,_MM_SHUFFLE(1,0,1,0)); + __m256 S3 = _mm256_shuffle_ps(T1,T3,_MM_SHUFFLE(3,2,3,2)); + + kernel.packet[0] = _mm256_permute2f128_ps(S0, S1, 0x20); + kernel.packet[1] = _mm256_permute2f128_ps(S2, S3, 0x20); + kernel.packet[2] = _mm256_permute2f128_ps(S0, S1, 0x31); + kernel.packet[3] = _mm256_permute2f128_ps(S2, S3, 0x31); +} + +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + __m256d T0 = _mm256_shuffle_pd(kernel.packet[0], kernel.packet[1], 15); + __m256d T1 = _mm256_shuffle_pd(kernel.packet[0], kernel.packet[1], 0); + __m256d T2 = _mm256_shuffle_pd(kernel.packet[2], kernel.packet[3], 15); + __m256d T3 = _mm256_shuffle_pd(kernel.packet[2], kernel.packet[3], 0); + + kernel.packet[1] = _mm256_permute2f128_pd(T0, T2, 32); + kernel.packet[3] = _mm256_permute2f128_pd(T0, T2, 49); + kernel.packet[0] = _mm256_permute2f128_pd(T1, T3, 32); + kernel.packet[2] = _mm256_permute2f128_pd(T1, T3, 49); +} + +template<> EIGEN_STRONG_INLINE Packet8f pblend(const Selector<8>& ifPacket, const Packet8f& thenPacket, const Packet8f& elsePacket) { + const __m256 zero = _mm256_setzero_ps(); + const __m256 select = _mm256_set_ps(ifPacket.select[7], ifPacket.select[6], ifPacket.select[5], ifPacket.select[4], ifPacket.select[3], ifPacket.select[2], ifPacket.select[1], ifPacket.select[0]); + __m256 false_mask = _mm256_cmp_ps(select, zero, _CMP_EQ_UQ); + return _mm256_blendv_ps(thenPacket, elsePacket, false_mask); +} +template<> EIGEN_STRONG_INLINE Packet4d pblend(const Selector<4>& ifPacket, const Packet4d& thenPacket, const Packet4d& elsePacket) { + const __m256d zero = _mm256_setzero_pd(); + const __m256d select = _mm256_set_pd(ifPacket.select[3], ifPacket.select[2], ifPacket.select[1], ifPacket.select[0]); + __m256d false_mask = _mm256_cmp_pd(select, zero, _CMP_EQ_UQ); + return _mm256_blendv_pd(thenPacket, elsePacket, false_mask); +} + +template<> EIGEN_STRONG_INLINE Packet8f pinsertfirst(const Packet8f& a, float b) +{ + return _mm256_blend_ps(a,pset1(b),1); +} + +template<> EIGEN_STRONG_INLINE Packet4d pinsertfirst(const Packet4d& a, double b) +{ + return _mm256_blend_pd(a,pset1(b),1); +} + +template<> EIGEN_STRONG_INLINE Packet8f pinsertlast(const Packet8f& a, float b) +{ + return _mm256_blend_ps(a,pset1(b),(1<<7)); +} + +template<> EIGEN_STRONG_INLINE Packet4d pinsertlast(const Packet4d& a, double b) +{ + return _mm256_blend_pd(a,pset1(b),(1<<3)); +} + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_PACKET_MATH_AVX_H diff --git a/libs/eigen3/Eigen/src/Core/arch/AVX/TypeCasting.h b/libs/eigen3/Eigen/src/Core/arch/AVX/TypeCasting.h new file mode 100644 index 000000000..83bfdc604 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/arch/AVX/TypeCasting.h @@ -0,0 +1,51 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_TYPE_CASTING_AVX_H +#define EIGEN_TYPE_CASTING_AVX_H + +namespace Eigen { + +namespace internal { + +// For now we use SSE to handle integers, so we can't use AVX instructions to cast +// from int to float +template <> +struct type_casting_traits { + enum { + VectorizedCast = 0, + SrcCoeffRatio = 1, + TgtCoeffRatio = 1 + }; +}; + +template <> +struct type_casting_traits { + enum { + VectorizedCast = 0, + SrcCoeffRatio = 1, + TgtCoeffRatio = 1 + }; +}; + + + +template<> EIGEN_STRONG_INLINE Packet8i pcast(const Packet8f& a) { + return _mm256_cvtps_epi32(a); +} + +template<> EIGEN_STRONG_INLINE Packet8f pcast(const Packet8i& a) { + return _mm256_cvtepi32_ps(a); +} + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_TYPE_CASTING_AVX_H diff --git a/libs/eigen3/Eigen/src/Core/arch/AVX512/MathFunctions.h b/libs/eigen3/Eigen/src/Core/arch/AVX512/MathFunctions.h new file mode 100644 index 000000000..399be0ee4 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/arch/AVX512/MathFunctions.h @@ -0,0 +1,396 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2016 Pedro Gonnet (pedro.gonnet@gmail.com) +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef THIRD_PARTY_EIGEN3_EIGEN_SRC_CORE_ARCH_AVX512_MATHFUNCTIONS_H_ +#define THIRD_PARTY_EIGEN3_EIGEN_SRC_CORE_ARCH_AVX512_MATHFUNCTIONS_H_ + +namespace Eigen { + +namespace internal { + +// Disable the code for older versions of gcc that don't support many of the required avx512 instrinsics. +#if EIGEN_GNUC_AT_LEAST(5, 3) + +#define _EIGEN_DECLARE_CONST_Packet16f(NAME, X) \ + const Packet16f p16f_##NAME = pset1(X) + +#define _EIGEN_DECLARE_CONST_Packet16f_FROM_INT(NAME, X) \ + const Packet16f p16f_##NAME = (__m512)pset1(X) + +#define _EIGEN_DECLARE_CONST_Packet8d(NAME, X) \ + const Packet8d p8d_##NAME = pset1(X) + +#define _EIGEN_DECLARE_CONST_Packet8d_FROM_INT64(NAME, X) \ + const Packet8d p8d_##NAME = _mm512_castsi512_pd(_mm512_set1_epi64(X)) + +// Natural logarithm +// Computes log(x) as log(2^e * m) = C*e + log(m), where the constant C =log(2) +// and m is in the range [sqrt(1/2),sqrt(2)). In this range, the logarithm can +// be easily approximated by a polynomial centered on m=1 for stability. +#if defined(EIGEN_VECTORIZE_AVX512DQ) +template <> +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet16f +plog(const Packet16f& _x) { + Packet16f x = _x; + _EIGEN_DECLARE_CONST_Packet16f(1, 1.0f); + _EIGEN_DECLARE_CONST_Packet16f(half, 0.5f); + _EIGEN_DECLARE_CONST_Packet16f(126f, 126.0f); + + _EIGEN_DECLARE_CONST_Packet16f_FROM_INT(inv_mant_mask, ~0x7f800000); + + // The smallest non denormalized float number. + _EIGEN_DECLARE_CONST_Packet16f_FROM_INT(min_norm_pos, 0x00800000); + _EIGEN_DECLARE_CONST_Packet16f_FROM_INT(minus_inf, 0xff800000); + _EIGEN_DECLARE_CONST_Packet16f_FROM_INT(nan, 0x7fc00000); + + // Polynomial coefficients. + _EIGEN_DECLARE_CONST_Packet16f(cephes_SQRTHF, 0.707106781186547524f); + _EIGEN_DECLARE_CONST_Packet16f(cephes_log_p0, 7.0376836292E-2f); + _EIGEN_DECLARE_CONST_Packet16f(cephes_log_p1, -1.1514610310E-1f); + _EIGEN_DECLARE_CONST_Packet16f(cephes_log_p2, 1.1676998740E-1f); + _EIGEN_DECLARE_CONST_Packet16f(cephes_log_p3, -1.2420140846E-1f); + _EIGEN_DECLARE_CONST_Packet16f(cephes_log_p4, +1.4249322787E-1f); + _EIGEN_DECLARE_CONST_Packet16f(cephes_log_p5, -1.6668057665E-1f); + _EIGEN_DECLARE_CONST_Packet16f(cephes_log_p6, +2.0000714765E-1f); + _EIGEN_DECLARE_CONST_Packet16f(cephes_log_p7, -2.4999993993E-1f); + _EIGEN_DECLARE_CONST_Packet16f(cephes_log_p8, +3.3333331174E-1f); + _EIGEN_DECLARE_CONST_Packet16f(cephes_log_q1, -2.12194440e-4f); + _EIGEN_DECLARE_CONST_Packet16f(cephes_log_q2, 0.693359375f); + + // invalid_mask is set to true when x is NaN + __mmask16 invalid_mask = + _mm512_cmp_ps_mask(x, _mm512_setzero_ps(), _CMP_NGE_UQ); + __mmask16 iszero_mask = + _mm512_cmp_ps_mask(x, _mm512_setzero_ps(), _CMP_EQ_UQ); + + // Truncate input values to the minimum positive normal. + x = pmax(x, p16f_min_norm_pos); + + // Extract the shifted exponents. + Packet16f emm0 = _mm512_cvtepi32_ps(_mm512_srli_epi32((__m512i)x, 23)); + Packet16f e = _mm512_sub_ps(emm0, p16f_126f); + + // Set the exponents to -1, i.e. x are in the range [0.5,1). + x = _mm512_and_ps(x, p16f_inv_mant_mask); + x = _mm512_or_ps(x, p16f_half); + + // part2: Shift the inputs from the range [0.5,1) to [sqrt(1/2),sqrt(2)) + // and shift by -1. The values are then centered around 0, which improves + // the stability of the polynomial evaluation. + // if( x < SQRTHF ) { + // e -= 1; + // x = x + x - 1.0; + // } else { x = x - 1.0; } + __mmask16 mask = _mm512_cmp_ps_mask(x, p16f_cephes_SQRTHF, _CMP_LT_OQ); + Packet16f tmp = _mm512_mask_blend_ps(mask, x, _mm512_setzero_ps()); + x = psub(x, p16f_1); + e = psub(e, _mm512_mask_blend_ps(mask, p16f_1, _mm512_setzero_ps())); + x = padd(x, tmp); + + Packet16f x2 = pmul(x, x); + Packet16f x3 = pmul(x2, x); + + // Evaluate the polynomial approximant of degree 8 in three parts, probably + // to improve instruction-level parallelism. + Packet16f y, y1, y2; + y = pmadd(p16f_cephes_log_p0, x, p16f_cephes_log_p1); + y1 = pmadd(p16f_cephes_log_p3, x, p16f_cephes_log_p4); + y2 = pmadd(p16f_cephes_log_p6, x, p16f_cephes_log_p7); + y = pmadd(y, x, p16f_cephes_log_p2); + y1 = pmadd(y1, x, p16f_cephes_log_p5); + y2 = pmadd(y2, x, p16f_cephes_log_p8); + y = pmadd(y, x3, y1); + y = pmadd(y, x3, y2); + y = pmul(y, x3); + + // Add the logarithm of the exponent back to the result of the interpolation. + y1 = pmul(e, p16f_cephes_log_q1); + tmp = pmul(x2, p16f_half); + y = padd(y, y1); + x = psub(x, tmp); + y2 = pmul(e, p16f_cephes_log_q2); + x = padd(x, y); + x = padd(x, y2); + + // Filter out invalid inputs, i.e. negative arg will be NAN, 0 will be -INF. + return _mm512_mask_blend_ps(iszero_mask, p16f_minus_inf, + _mm512_mask_blend_ps(invalid_mask, p16f_nan, x)); +} +#endif + +// Exponential function. Works by writing "x = m*log(2) + r" where +// "m = floor(x/log(2)+1/2)" and "r" is the remainder. The result is then +// "exp(x) = 2^m*exp(r)" where exp(r) is in the range [-1,1). +template <> +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet16f +pexp(const Packet16f& _x) { + _EIGEN_DECLARE_CONST_Packet16f(1, 1.0f); + _EIGEN_DECLARE_CONST_Packet16f(half, 0.5f); + _EIGEN_DECLARE_CONST_Packet16f(127, 127.0f); + + _EIGEN_DECLARE_CONST_Packet16f(exp_hi, 88.3762626647950f); + _EIGEN_DECLARE_CONST_Packet16f(exp_lo, -88.3762626647949f); + + _EIGEN_DECLARE_CONST_Packet16f(cephes_LOG2EF, 1.44269504088896341f); + + _EIGEN_DECLARE_CONST_Packet16f(cephes_exp_p0, 1.9875691500E-4f); + _EIGEN_DECLARE_CONST_Packet16f(cephes_exp_p1, 1.3981999507E-3f); + _EIGEN_DECLARE_CONST_Packet16f(cephes_exp_p2, 8.3334519073E-3f); + _EIGEN_DECLARE_CONST_Packet16f(cephes_exp_p3, 4.1665795894E-2f); + _EIGEN_DECLARE_CONST_Packet16f(cephes_exp_p4, 1.6666665459E-1f); + _EIGEN_DECLARE_CONST_Packet16f(cephes_exp_p5, 5.0000001201E-1f); + + // Clamp x. + Packet16f x = pmax(pmin(_x, p16f_exp_hi), p16f_exp_lo); + + // Express exp(x) as exp(m*ln(2) + r), start by extracting + // m = floor(x/ln(2) + 0.5). + Packet16f m = _mm512_floor_ps(pmadd(x, p16f_cephes_LOG2EF, p16f_half)); + + // Get r = x - m*ln(2). Note that we can do this without losing more than one + // ulp precision due to the FMA instruction. + _EIGEN_DECLARE_CONST_Packet16f(nln2, -0.6931471805599453f); + Packet16f r = _mm512_fmadd_ps(m, p16f_nln2, x); + Packet16f r2 = pmul(r, r); + + // TODO(gonnet): Split into odd/even polynomials and try to exploit + // instruction-level parallelism. + Packet16f y = p16f_cephes_exp_p0; + y = pmadd(y, r, p16f_cephes_exp_p1); + y = pmadd(y, r, p16f_cephes_exp_p2); + y = pmadd(y, r, p16f_cephes_exp_p3); + y = pmadd(y, r, p16f_cephes_exp_p4); + y = pmadd(y, r, p16f_cephes_exp_p5); + y = pmadd(y, r2, r); + y = padd(y, p16f_1); + + // Build emm0 = 2^m. + Packet16i emm0 = _mm512_cvttps_epi32(padd(m, p16f_127)); + emm0 = _mm512_slli_epi32(emm0, 23); + + // Return 2^m * exp(r). + return pmax(pmul(y, _mm512_castsi512_ps(emm0)), _x); +} + +/*template <> +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet8d +pexp(const Packet8d& _x) { + Packet8d x = _x; + + _EIGEN_DECLARE_CONST_Packet8d(1, 1.0); + _EIGEN_DECLARE_CONST_Packet8d(2, 2.0); + + _EIGEN_DECLARE_CONST_Packet8d(exp_hi, 709.437); + _EIGEN_DECLARE_CONST_Packet8d(exp_lo, -709.436139303); + + _EIGEN_DECLARE_CONST_Packet8d(cephes_LOG2EF, 1.4426950408889634073599); + + _EIGEN_DECLARE_CONST_Packet8d(cephes_exp_p0, 1.26177193074810590878e-4); + _EIGEN_DECLARE_CONST_Packet8d(cephes_exp_p1, 3.02994407707441961300e-2); + _EIGEN_DECLARE_CONST_Packet8d(cephes_exp_p2, 9.99999999999999999910e-1); + + _EIGEN_DECLARE_CONST_Packet8d(cephes_exp_q0, 3.00198505138664455042e-6); + _EIGEN_DECLARE_CONST_Packet8d(cephes_exp_q1, 2.52448340349684104192e-3); + _EIGEN_DECLARE_CONST_Packet8d(cephes_exp_q2, 2.27265548208155028766e-1); + _EIGEN_DECLARE_CONST_Packet8d(cephes_exp_q3, 2.00000000000000000009e0); + + _EIGEN_DECLARE_CONST_Packet8d(cephes_exp_C1, 0.693145751953125); + _EIGEN_DECLARE_CONST_Packet8d(cephes_exp_C2, 1.42860682030941723212e-6); + + // clamp x + x = pmax(pmin(x, p8d_exp_hi), p8d_exp_lo); + + // Express exp(x) as exp(g + n*log(2)). + const Packet8d n = + _mm512_mul_round_pd(p8d_cephes_LOG2EF, x, _MM_FROUND_TO_NEAREST_INT); + + // Get the remainder modulo log(2), i.e. the "g" described above. Subtract + // n*log(2) out in two steps, i.e. n*C1 + n*C2, C1+C2=log2 to get the last + // digits right. + const Packet8d nC1 = pmul(n, p8d_cephes_exp_C1); + const Packet8d nC2 = pmul(n, p8d_cephes_exp_C2); + x = psub(x, nC1); + x = psub(x, nC2); + + const Packet8d x2 = pmul(x, x); + + // Evaluate the numerator polynomial of the rational interpolant. + Packet8d px = p8d_cephes_exp_p0; + px = pmadd(px, x2, p8d_cephes_exp_p1); + px = pmadd(px, x2, p8d_cephes_exp_p2); + px = pmul(px, x); + + // Evaluate the denominator polynomial of the rational interpolant. + Packet8d qx = p8d_cephes_exp_q0; + qx = pmadd(qx, x2, p8d_cephes_exp_q1); + qx = pmadd(qx, x2, p8d_cephes_exp_q2); + qx = pmadd(qx, x2, p8d_cephes_exp_q3); + + // I don't really get this bit, copied from the SSE2 routines, so... + // TODO(gonnet): Figure out what is going on here, perhaps find a better + // rational interpolant? + x = _mm512_div_pd(px, psub(qx, px)); + x = pmadd(p8d_2, x, p8d_1); + + // Build e=2^n. + const Packet8d e = _mm512_castsi512_pd(_mm512_slli_epi64( + _mm512_add_epi64(_mm512_cvtpd_epi64(n), _mm512_set1_epi64(1023)), 52)); + + // Construct the result 2^n * exp(g) = e * x. The max is used to catch + // non-finite values in the input. + return pmax(pmul(x, e), _x); + }*/ + +// Functions for sqrt. +// The EIGEN_FAST_MATH version uses the _mm_rsqrt_ps approximation and one step +// of Newton's method, at a cost of 1-2 bits of precision as opposed to the +// exact solution. The main advantage of this approach is not just speed, but +// also the fact that it can be inlined and pipelined with other computations, +// further reducing its effective latency. +#if EIGEN_FAST_MATH +template <> +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet16f +psqrt(const Packet16f& _x) { + _EIGEN_DECLARE_CONST_Packet16f(one_point_five, 1.5f); + _EIGEN_DECLARE_CONST_Packet16f(minus_half, -0.5f); + _EIGEN_DECLARE_CONST_Packet16f_FROM_INT(flt_min, 0x00800000); + + Packet16f neg_half = pmul(_x, p16f_minus_half); + + // select only the inverse sqrt of positive normal inputs (denormals are + // flushed to zero and cause infs as well). + __mmask16 non_zero_mask = _mm512_cmp_ps_mask(_x, p16f_flt_min, _CMP_GE_OQ); + Packet16f x = _mm512_mask_blend_ps(non_zero_mask, _mm512_rsqrt14_ps(_x), + _mm512_setzero_ps()); + + // Do a single step of Newton's iteration. + x = pmul(x, pmadd(neg_half, pmul(x, x), p16f_one_point_five)); + + // Multiply the original _x by it's reciprocal square root to extract the + // square root. + return pmul(_x, x); +} + +template <> +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet8d +psqrt(const Packet8d& _x) { + _EIGEN_DECLARE_CONST_Packet8d(one_point_five, 1.5); + _EIGEN_DECLARE_CONST_Packet8d(minus_half, -0.5); + _EIGEN_DECLARE_CONST_Packet8d_FROM_INT64(dbl_min, 0x0010000000000000LL); + + Packet8d neg_half = pmul(_x, p8d_minus_half); + + // select only the inverse sqrt of positive normal inputs (denormals are + // flushed to zero and cause infs as well). + __mmask8 non_zero_mask = _mm512_cmp_pd_mask(_x, p8d_dbl_min, _CMP_GE_OQ); + Packet8d x = _mm512_mask_blend_pd(non_zero_mask, _mm512_rsqrt14_pd(_x), + _mm512_setzero_pd()); + + // Do a first step of Newton's iteration. + x = pmul(x, pmadd(neg_half, pmul(x, x), p8d_one_point_five)); + + // Do a second step of Newton's iteration. + x = pmul(x, pmadd(neg_half, pmul(x, x), p8d_one_point_five)); + + // Multiply the original _x by it's reciprocal square root to extract the + // square root. + return pmul(_x, x); +} +#else +template <> +EIGEN_STRONG_INLINE Packet16f psqrt(const Packet16f& x) { + return _mm512_sqrt_ps(x); +} +template <> +EIGEN_STRONG_INLINE Packet8d psqrt(const Packet8d& x) { + return _mm512_sqrt_pd(x); +} +#endif + +// Functions for rsqrt. +// Almost identical to the sqrt routine, just leave out the last multiplication +// and fill in NaN/Inf where needed. Note that this function only exists as an +// iterative version for doubles since there is no instruction for diretly +// computing the reciprocal square root in AVX-512. +#ifdef EIGEN_FAST_MATH +template <> +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet16f +prsqrt(const Packet16f& _x) { + _EIGEN_DECLARE_CONST_Packet16f_FROM_INT(inf, 0x7f800000); + _EIGEN_DECLARE_CONST_Packet16f_FROM_INT(nan, 0x7fc00000); + _EIGEN_DECLARE_CONST_Packet16f(one_point_five, 1.5f); + _EIGEN_DECLARE_CONST_Packet16f(minus_half, -0.5f); + _EIGEN_DECLARE_CONST_Packet16f_FROM_INT(flt_min, 0x00800000); + + Packet16f neg_half = pmul(_x, p16f_minus_half); + + // select only the inverse sqrt of positive normal inputs (denormals are + // flushed to zero and cause infs as well). + __mmask16 le_zero_mask = _mm512_cmp_ps_mask(_x, p16f_flt_min, _CMP_LT_OQ); + Packet16f x = _mm512_mask_blend_ps(le_zero_mask, _mm512_setzero_ps(), + _mm512_rsqrt14_ps(_x)); + + // Fill in NaNs and Infs for the negative/zero entries. + __mmask16 neg_mask = _mm512_cmp_ps_mask(_x, _mm512_setzero_ps(), _CMP_LT_OQ); + Packet16f infs_and_nans = _mm512_mask_blend_ps( + neg_mask, p16f_nan, + _mm512_mask_blend_ps(le_zero_mask, p16f_inf, _mm512_setzero_ps())); + + // Do a single step of Newton's iteration. + x = pmul(x, pmadd(neg_half, pmul(x, x), p16f_one_point_five)); + + // Insert NaNs and Infs in all the right places. + return _mm512_mask_blend_ps(le_zero_mask, infs_and_nans, x); +} + +template <> +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet8d +prsqrt(const Packet8d& _x) { + _EIGEN_DECLARE_CONST_Packet8d_FROM_INT64(inf, 0x7ff0000000000000LL); + _EIGEN_DECLARE_CONST_Packet8d_FROM_INT64(nan, 0x7ff1000000000000LL); + _EIGEN_DECLARE_CONST_Packet8d(one_point_five, 1.5); + _EIGEN_DECLARE_CONST_Packet8d(minus_half, -0.5); + _EIGEN_DECLARE_CONST_Packet8d_FROM_INT64(dbl_min, 0x0010000000000000LL); + + Packet8d neg_half = pmul(_x, p8d_minus_half); + + // select only the inverse sqrt of positive normal inputs (denormals are + // flushed to zero and cause infs as well). + __mmask8 le_zero_mask = _mm512_cmp_pd_mask(_x, p8d_dbl_min, _CMP_LT_OQ); + Packet8d x = _mm512_mask_blend_pd(le_zero_mask, _mm512_setzero_pd(), + _mm512_rsqrt14_pd(_x)); + + // Fill in NaNs and Infs for the negative/zero entries. + __mmask8 neg_mask = _mm512_cmp_pd_mask(_x, _mm512_setzero_pd(), _CMP_LT_OQ); + Packet8d infs_and_nans = _mm512_mask_blend_pd( + neg_mask, p8d_nan, + _mm512_mask_blend_pd(le_zero_mask, p8d_inf, _mm512_setzero_pd())); + + // Do a first step of Newton's iteration. + x = pmul(x, pmadd(neg_half, pmul(x, x), p8d_one_point_five)); + + // Do a second step of Newton's iteration. + x = pmul(x, pmadd(neg_half, pmul(x, x), p8d_one_point_five)); + + // Insert NaNs and Infs in all the right places. + return _mm512_mask_blend_pd(le_zero_mask, infs_and_nans, x); +} +#else +template <> +EIGEN_STRONG_INLINE Packet16f prsqrt(const Packet16f& x) { + return _mm512_rsqrt28_ps(x); +} +#endif +#endif + +} // end namespace internal + +} // end namespace Eigen + +#endif // THIRD_PARTY_EIGEN3_EIGEN_SRC_CORE_ARCH_AVX512_MATHFUNCTIONS_H_ diff --git a/libs/eigen3/Eigen/src/Core/arch/AVX512/PacketMath.h b/libs/eigen3/Eigen/src/Core/arch/AVX512/PacketMath.h new file mode 100644 index 000000000..f6500a16e --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/arch/AVX512/PacketMath.h @@ -0,0 +1,1316 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2016 Benoit Steiner (benoit.steiner.goog@gmail.com) +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_PACKET_MATH_AVX512_H +#define EIGEN_PACKET_MATH_AVX512_H + +namespace Eigen { + +namespace internal { + +#ifndef EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD +#define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 8 +#endif + +#ifndef EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS +#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS (2*sizeof(void*)) +#endif + +#ifdef __FMA__ +#ifndef EIGEN_HAS_SINGLE_INSTRUCTION_MADD +#define EIGEN_HAS_SINGLE_INSTRUCTION_MADD +#endif +#endif + +typedef __m512 Packet16f; +typedef __m512i Packet16i; +typedef __m512d Packet8d; + +template <> +struct is_arithmetic<__m512> { + enum { value = true }; +}; +template <> +struct is_arithmetic<__m512i> { + enum { value = true }; +}; +template <> +struct is_arithmetic<__m512d> { + enum { value = true }; +}; + +template<> struct packet_traits : default_packet_traits +{ + typedef Packet16f type; + typedef Packet8f half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size = 16, + HasHalfPacket = 1, +#if EIGEN_GNUC_AT_LEAST(5, 3) +#ifdef EIGEN_VECTORIZE_AVX512DQ + HasLog = 1, +#endif + HasExp = 1, + HasSqrt = 1, + HasRsqrt = 1, +#endif + HasDiv = 1 + }; + }; +template<> struct packet_traits : default_packet_traits +{ + typedef Packet8d type; + typedef Packet4d half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size = 8, + HasHalfPacket = 1, +#if EIGEN_GNUC_AT_LEAST(5, 3) + HasSqrt = 1, + HasRsqrt = EIGEN_FAST_MATH, +#endif + HasDiv = 1 + }; +}; + +/* TODO Implement AVX512 for integers +template<> struct packet_traits : default_packet_traits +{ + typedef Packet16i type; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size=8 + }; +}; +*/ + +template <> +struct unpacket_traits { + typedef float type; + typedef Packet8f half; + enum { size = 16, alignment=Aligned64 }; +}; +template <> +struct unpacket_traits { + typedef double type; + typedef Packet4d half; + enum { size = 8, alignment=Aligned64 }; +}; +template <> +struct unpacket_traits { + typedef int type; + typedef Packet8i half; + enum { size = 16, alignment=Aligned64 }; +}; + +template <> +EIGEN_STRONG_INLINE Packet16f pset1(const float& from) { + return _mm512_set1_ps(from); +} +template <> +EIGEN_STRONG_INLINE Packet8d pset1(const double& from) { + return _mm512_set1_pd(from); +} +template <> +EIGEN_STRONG_INLINE Packet16i pset1(const int& from) { + return _mm512_set1_epi32(from); +} + +template <> +EIGEN_STRONG_INLINE Packet16f pload1(const float* from) { + return _mm512_broadcastss_ps(_mm_load_ps1(from)); +} +template <> +EIGEN_STRONG_INLINE Packet8d pload1(const double* from) { + return _mm512_broadcastsd_pd(_mm_load_pd1(from)); +} + +template <> +EIGEN_STRONG_INLINE Packet16f plset(const float& a) { + return _mm512_add_ps( + _mm512_set1_ps(a), + _mm512_set_ps(15.0f, 14.0f, 13.0f, 12.0f, 11.0f, 10.0f, 9.0f, 8.0f, 7.0f, 6.0f, 5.0f, + 4.0f, 3.0f, 2.0f, 1.0f, 0.0f)); +} +template <> +EIGEN_STRONG_INLINE Packet8d plset(const double& a) { + return _mm512_add_pd(_mm512_set1_pd(a), + _mm512_set_pd(7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0)); +} + +template <> +EIGEN_STRONG_INLINE Packet16f padd(const Packet16f& a, + const Packet16f& b) { + return _mm512_add_ps(a, b); +} +template <> +EIGEN_STRONG_INLINE Packet8d padd(const Packet8d& a, + const Packet8d& b) { + return _mm512_add_pd(a, b); +} + +template <> +EIGEN_STRONG_INLINE Packet16f psub(const Packet16f& a, + const Packet16f& b) { + return _mm512_sub_ps(a, b); +} +template <> +EIGEN_STRONG_INLINE Packet8d psub(const Packet8d& a, + const Packet8d& b) { + return _mm512_sub_pd(a, b); +} + +template <> +EIGEN_STRONG_INLINE Packet16f pnegate(const Packet16f& a) { + return _mm512_sub_ps(_mm512_set1_ps(0.0), a); +} +template <> +EIGEN_STRONG_INLINE Packet8d pnegate(const Packet8d& a) { + return _mm512_sub_pd(_mm512_set1_pd(0.0), a); +} + +template <> +EIGEN_STRONG_INLINE Packet16f pconj(const Packet16f& a) { + return a; +} +template <> +EIGEN_STRONG_INLINE Packet8d pconj(const Packet8d& a) { + return a; +} +template <> +EIGEN_STRONG_INLINE Packet16i pconj(const Packet16i& a) { + return a; +} + +template <> +EIGEN_STRONG_INLINE Packet16f pmul(const Packet16f& a, + const Packet16f& b) { + return _mm512_mul_ps(a, b); +} +template <> +EIGEN_STRONG_INLINE Packet8d pmul(const Packet8d& a, + const Packet8d& b) { + return _mm512_mul_pd(a, b); +} + +template <> +EIGEN_STRONG_INLINE Packet16f pdiv(const Packet16f& a, + const Packet16f& b) { + return _mm512_div_ps(a, b); +} +template <> +EIGEN_STRONG_INLINE Packet8d pdiv(const Packet8d& a, + const Packet8d& b) { + return _mm512_div_pd(a, b); +} + +#ifdef __FMA__ +template <> +EIGEN_STRONG_INLINE Packet16f pmadd(const Packet16f& a, const Packet16f& b, + const Packet16f& c) { + return _mm512_fmadd_ps(a, b, c); +} +template <> +EIGEN_STRONG_INLINE Packet8d pmadd(const Packet8d& a, const Packet8d& b, + const Packet8d& c) { + return _mm512_fmadd_pd(a, b, c); +} +#endif + +template <> +EIGEN_STRONG_INLINE Packet16f pmin(const Packet16f& a, + const Packet16f& b) { + return _mm512_min_ps(a, b); +} +template <> +EIGEN_STRONG_INLINE Packet8d pmin(const Packet8d& a, + const Packet8d& b) { + return _mm512_min_pd(a, b); +} + +template <> +EIGEN_STRONG_INLINE Packet16f pmax(const Packet16f& a, + const Packet16f& b) { + return _mm512_max_ps(a, b); +} +template <> +EIGEN_STRONG_INLINE Packet8d pmax(const Packet8d& a, + const Packet8d& b) { + return _mm512_max_pd(a, b); +} + +template <> +EIGEN_STRONG_INLINE Packet16f pand(const Packet16f& a, + const Packet16f& b) { +#ifdef EIGEN_VECTORIZE_AVX512DQ + return _mm512_and_ps(a, b); +#else + Packet16f res = _mm512_undefined_ps(); + Packet4f lane0_a = _mm512_extractf32x4_ps(a, 0); + Packet4f lane0_b = _mm512_extractf32x4_ps(b, 0); + res = _mm512_insertf32x4(res, _mm_and_ps(lane0_a, lane0_b), 0); + + Packet4f lane1_a = _mm512_extractf32x4_ps(a, 1); + Packet4f lane1_b = _mm512_extractf32x4_ps(b, 1); + res = _mm512_insertf32x4(res, _mm_and_ps(lane1_a, lane1_b), 1); + + Packet4f lane2_a = _mm512_extractf32x4_ps(a, 2); + Packet4f lane2_b = _mm512_extractf32x4_ps(b, 2); + res = _mm512_insertf32x4(res, _mm_and_ps(lane2_a, lane2_b), 2); + + Packet4f lane3_a = _mm512_extractf32x4_ps(a, 3); + Packet4f lane3_b = _mm512_extractf32x4_ps(b, 3); + res = _mm512_insertf32x4(res, _mm_and_ps(lane3_a, lane3_b), 3); + + return res; +#endif +} +template <> +EIGEN_STRONG_INLINE Packet8d pand(const Packet8d& a, + const Packet8d& b) { +#ifdef EIGEN_VECTORIZE_AVX512DQ + return _mm512_and_pd(a, b); +#else + Packet8d res = _mm512_undefined_pd(); + Packet4d lane0_a = _mm512_extractf64x4_pd(a, 0); + Packet4d lane0_b = _mm512_extractf64x4_pd(b, 0); + res = _mm512_insertf64x4(res, _mm256_and_pd(lane0_a, lane0_b), 0); + + Packet4d lane1_a = _mm512_extractf64x4_pd(a, 1); + Packet4d lane1_b = _mm512_extractf64x4_pd(b, 1); + res = _mm512_insertf64x4(res, _mm256_and_pd(lane1_a, lane1_b), 1); + + return res; +#endif +} +template <> +EIGEN_STRONG_INLINE Packet16f por(const Packet16f& a, + const Packet16f& b) { +#ifdef EIGEN_VECTORIZE_AVX512DQ + return _mm512_or_ps(a, b); +#else + Packet16f res = _mm512_undefined_ps(); + Packet4f lane0_a = _mm512_extractf32x4_ps(a, 0); + Packet4f lane0_b = _mm512_extractf32x4_ps(b, 0); + res = _mm512_insertf32x4(res, _mm_or_ps(lane0_a, lane0_b), 0); + + Packet4f lane1_a = _mm512_extractf32x4_ps(a, 1); + Packet4f lane1_b = _mm512_extractf32x4_ps(b, 1); + res = _mm512_insertf32x4(res, _mm_or_ps(lane1_a, lane1_b), 1); + + Packet4f lane2_a = _mm512_extractf32x4_ps(a, 2); + Packet4f lane2_b = _mm512_extractf32x4_ps(b, 2); + res = _mm512_insertf32x4(res, _mm_or_ps(lane2_a, lane2_b), 2); + + Packet4f lane3_a = _mm512_extractf32x4_ps(a, 3); + Packet4f lane3_b = _mm512_extractf32x4_ps(b, 3); + res = _mm512_insertf32x4(res, _mm_or_ps(lane3_a, lane3_b), 3); + + return res; +#endif +} + +template <> +EIGEN_STRONG_INLINE Packet8d por(const Packet8d& a, + const Packet8d& b) { +#ifdef EIGEN_VECTORIZE_AVX512DQ + return _mm512_or_pd(a, b); +#else + Packet8d res = _mm512_undefined_pd(); + Packet4d lane0_a = _mm512_extractf64x4_pd(a, 0); + Packet4d lane0_b = _mm512_extractf64x4_pd(b, 0); + res = _mm512_insertf64x4(res, _mm256_or_pd(lane0_a, lane0_b), 0); + + Packet4d lane1_a = _mm512_extractf64x4_pd(a, 1); + Packet4d lane1_b = _mm512_extractf64x4_pd(b, 1); + res = _mm512_insertf64x4(res, _mm256_or_pd(lane1_a, lane1_b), 1); + + return res; +#endif +} + +template <> +EIGEN_STRONG_INLINE Packet16f pxor(const Packet16f& a, + const Packet16f& b) { +#ifdef EIGEN_VECTORIZE_AVX512DQ + return _mm512_xor_ps(a, b); +#else + Packet16f res = _mm512_undefined_ps(); + Packet4f lane0_a = _mm512_extractf32x4_ps(a, 0); + Packet4f lane0_b = _mm512_extractf32x4_ps(b, 0); + res = _mm512_insertf32x4(res, _mm_xor_ps(lane0_a, lane0_b), 0); + + Packet4f lane1_a = _mm512_extractf32x4_ps(a, 1); + Packet4f lane1_b = _mm512_extractf32x4_ps(b, 1); + res = _mm512_insertf32x4(res, _mm_xor_ps(lane1_a, lane1_b), 1); + + Packet4f lane2_a = _mm512_extractf32x4_ps(a, 2); + Packet4f lane2_b = _mm512_extractf32x4_ps(b, 2); + res = _mm512_insertf32x4(res, _mm_xor_ps(lane2_a, lane2_b), 2); + + Packet4f lane3_a = _mm512_extractf32x4_ps(a, 3); + Packet4f lane3_b = _mm512_extractf32x4_ps(b, 3); + res = _mm512_insertf32x4(res, _mm_xor_ps(lane3_a, lane3_b), 3); + + return res; +#endif +} +template <> +EIGEN_STRONG_INLINE Packet8d pxor(const Packet8d& a, + const Packet8d& b) { +#ifdef EIGEN_VECTORIZE_AVX512DQ + return _mm512_xor_pd(a, b); +#else + Packet8d res = _mm512_undefined_pd(); + Packet4d lane0_a = _mm512_extractf64x4_pd(a, 0); + Packet4d lane0_b = _mm512_extractf64x4_pd(b, 0); + res = _mm512_insertf64x4(res, _mm256_xor_pd(lane0_a, lane0_b), 0); + + Packet4d lane1_a = _mm512_extractf64x4_pd(a, 1); + Packet4d lane1_b = _mm512_extractf64x4_pd(b, 1); + res = _mm512_insertf64x4(res, _mm256_xor_pd(lane1_a, lane1_b), 1); + + return res; +#endif +} + +template <> +EIGEN_STRONG_INLINE Packet16f pandnot(const Packet16f& a, + const Packet16f& b) { +#ifdef EIGEN_VECTORIZE_AVX512DQ + return _mm512_andnot_ps(a, b); +#else + Packet16f res = _mm512_undefined_ps(); + Packet4f lane0_a = _mm512_extractf32x4_ps(a, 0); + Packet4f lane0_b = _mm512_extractf32x4_ps(b, 0); + res = _mm512_insertf32x4(res, _mm_andnot_ps(lane0_a, lane0_b), 0); + + Packet4f lane1_a = _mm512_extractf32x4_ps(a, 1); + Packet4f lane1_b = _mm512_extractf32x4_ps(b, 1); + res = _mm512_insertf32x4(res, _mm_andnot_ps(lane1_a, lane1_b), 1); + + Packet4f lane2_a = _mm512_extractf32x4_ps(a, 2); + Packet4f lane2_b = _mm512_extractf32x4_ps(b, 2); + res = _mm512_insertf32x4(res, _mm_andnot_ps(lane2_a, lane2_b), 2); + + Packet4f lane3_a = _mm512_extractf32x4_ps(a, 3); + Packet4f lane3_b = _mm512_extractf32x4_ps(b, 3); + res = _mm512_insertf32x4(res, _mm_andnot_ps(lane3_a, lane3_b), 3); + + return res; +#endif +} +template <> +EIGEN_STRONG_INLINE Packet8d pandnot(const Packet8d& a, + const Packet8d& b) { +#ifdef EIGEN_VECTORIZE_AVX512DQ + return _mm512_andnot_pd(a, b); +#else + Packet8d res = _mm512_undefined_pd(); + Packet4d lane0_a = _mm512_extractf64x4_pd(a, 0); + Packet4d lane0_b = _mm512_extractf64x4_pd(b, 0); + res = _mm512_insertf64x4(res, _mm256_andnot_pd(lane0_a, lane0_b), 0); + + Packet4d lane1_a = _mm512_extractf64x4_pd(a, 1); + Packet4d lane1_b = _mm512_extractf64x4_pd(b, 1); + res = _mm512_insertf64x4(res, _mm256_andnot_pd(lane1_a, lane1_b), 1); + + return res; +#endif +} + +template <> +EIGEN_STRONG_INLINE Packet16f pload(const float* from) { + EIGEN_DEBUG_ALIGNED_LOAD return _mm512_load_ps(from); +} +template <> +EIGEN_STRONG_INLINE Packet8d pload(const double* from) { + EIGEN_DEBUG_ALIGNED_LOAD return _mm512_load_pd(from); +} +template <> +EIGEN_STRONG_INLINE Packet16i pload(const int* from) { + EIGEN_DEBUG_ALIGNED_LOAD return _mm512_load_si512( + reinterpret_cast(from)); +} + +template <> +EIGEN_STRONG_INLINE Packet16f ploadu(const float* from) { + EIGEN_DEBUG_UNALIGNED_LOAD return _mm512_loadu_ps(from); +} +template <> +EIGEN_STRONG_INLINE Packet8d ploadu(const double* from) { + EIGEN_DEBUG_UNALIGNED_LOAD return _mm512_loadu_pd(from); +} +template <> +EIGEN_STRONG_INLINE Packet16i ploadu(const int* from) { + EIGEN_DEBUG_UNALIGNED_LOAD return _mm512_loadu_si512( + reinterpret_cast(from)); +} + +// Loads 8 floats from memory a returns the packet +// {a0, a0 a1, a1, a2, a2, a3, a3, a4, a4, a5, a5, a6, a6, a7, a7} +template <> +EIGEN_STRONG_INLINE Packet16f ploaddup(const float* from) { + Packet8f lane0 = _mm256_broadcast_ps((const __m128*)(const void*)from); + // mimic an "inplace" permutation of the lower 128bits using a blend + lane0 = _mm256_blend_ps( + lane0, _mm256_castps128_ps256(_mm_permute_ps( + _mm256_castps256_ps128(lane0), _MM_SHUFFLE(1, 0, 1, 0))), + 15); + // then we can perform a consistent permutation on the global register to get + // everything in shape: + lane0 = _mm256_permute_ps(lane0, _MM_SHUFFLE(3, 3, 2, 2)); + + Packet8f lane1 = _mm256_broadcast_ps((const __m128*)(const void*)(from + 4)); + // mimic an "inplace" permutation of the lower 128bits using a blend + lane1 = _mm256_blend_ps( + lane1, _mm256_castps128_ps256(_mm_permute_ps( + _mm256_castps256_ps128(lane1), _MM_SHUFFLE(1, 0, 1, 0))), + 15); + // then we can perform a consistent permutation on the global register to get + // everything in shape: + lane1 = _mm256_permute_ps(lane1, _MM_SHUFFLE(3, 3, 2, 2)); + +#ifdef EIGEN_VECTORIZE_AVX512DQ + Packet16f res = _mm512_undefined_ps(); + return _mm512_insertf32x8(res, lane0, 0); + return _mm512_insertf32x8(res, lane1, 1); + return res; +#else + Packet16f res = _mm512_undefined_ps(); + res = _mm512_insertf32x4(res, _mm256_extractf128_ps(lane0, 0), 0); + res = _mm512_insertf32x4(res, _mm256_extractf128_ps(lane0, 1), 1); + res = _mm512_insertf32x4(res, _mm256_extractf128_ps(lane1, 0), 2); + res = _mm512_insertf32x4(res, _mm256_extractf128_ps(lane1, 1), 3); + return res; +#endif +} +// Loads 4 doubles from memory a returns the packet {a0, a0 a1, a1, a2, a2, a3, +// a3} +template <> +EIGEN_STRONG_INLINE Packet8d ploaddup(const double* from) { + Packet4d lane0 = _mm256_broadcast_pd((const __m128d*)(const void*)from); + lane0 = _mm256_permute_pd(lane0, 3 << 2); + + Packet4d lane1 = _mm256_broadcast_pd((const __m128d*)(const void*)(from + 2)); + lane1 = _mm256_permute_pd(lane1, 3 << 2); + + Packet8d res = _mm512_undefined_pd(); + res = _mm512_insertf64x4(res, lane0, 0); + return _mm512_insertf64x4(res, lane1, 1); +} + +// Loads 4 floats from memory a returns the packet +// {a0, a0 a0, a0, a1, a1, a1, a1, a2, a2, a2, a2, a3, a3, a3, a3} +template <> +EIGEN_STRONG_INLINE Packet16f ploadquad(const float* from) { + Packet16f tmp = _mm512_undefined_ps(); + tmp = _mm512_insertf32x4(tmp, _mm_load_ps1(from), 0); + tmp = _mm512_insertf32x4(tmp, _mm_load_ps1(from + 1), 1); + tmp = _mm512_insertf32x4(tmp, _mm_load_ps1(from + 2), 2); + tmp = _mm512_insertf32x4(tmp, _mm_load_ps1(from + 3), 3); + return tmp; +} +// Loads 2 doubles from memory a returns the packet +// {a0, a0 a0, a0, a1, a1, a1, a1} +template <> +EIGEN_STRONG_INLINE Packet8d ploadquad(const double* from) { + Packet8d tmp = _mm512_undefined_pd(); + Packet2d tmp0 = _mm_load_pd1(from); + Packet2d tmp1 = _mm_load_pd1(from + 1); + Packet4d lane0 = _mm256_broadcastsd_pd(tmp0); + Packet4d lane1 = _mm256_broadcastsd_pd(tmp1); + tmp = _mm512_insertf64x4(tmp, lane0, 0); + return _mm512_insertf64x4(tmp, lane1, 1); +} + +template <> +EIGEN_STRONG_INLINE void pstore(float* to, const Packet16f& from) { + EIGEN_DEBUG_ALIGNED_STORE _mm512_store_ps(to, from); +} +template <> +EIGEN_STRONG_INLINE void pstore(double* to, const Packet8d& from) { + EIGEN_DEBUG_ALIGNED_STORE _mm512_store_pd(to, from); +} +template <> +EIGEN_STRONG_INLINE void pstore(int* to, const Packet16i& from) { + EIGEN_DEBUG_ALIGNED_STORE _mm512_storeu_si512(reinterpret_cast<__m512i*>(to), + from); +} + +template <> +EIGEN_STRONG_INLINE void pstoreu(float* to, const Packet16f& from) { + EIGEN_DEBUG_UNALIGNED_STORE _mm512_storeu_ps(to, from); +} +template <> +EIGEN_STRONG_INLINE void pstoreu(double* to, const Packet8d& from) { + EIGEN_DEBUG_UNALIGNED_STORE _mm512_storeu_pd(to, from); +} +template <> +EIGEN_STRONG_INLINE void pstoreu(int* to, const Packet16i& from) { + EIGEN_DEBUG_UNALIGNED_STORE _mm512_storeu_si512( + reinterpret_cast<__m512i*>(to), from); +} + +template <> +EIGEN_DEVICE_FUNC inline Packet16f pgather(const float* from, + Index stride) { + Packet16i stride_vector = _mm512_set1_epi32(stride); + Packet16i stride_multiplier = + _mm512_set_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + Packet16i indices = _mm512_mullo_epi32(stride_vector, stride_multiplier); + + return _mm512_i32gather_ps(indices, from, 4); +} +template <> +EIGEN_DEVICE_FUNC inline Packet8d pgather(const double* from, + Index stride) { + Packet8i stride_vector = _mm256_set1_epi32(stride); + Packet8i stride_multiplier = _mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0); + Packet8i indices = _mm256_mullo_epi32(stride_vector, stride_multiplier); + + return _mm512_i32gather_pd(indices, from, 8); +} + +template <> +EIGEN_DEVICE_FUNC inline void pscatter(float* to, + const Packet16f& from, + Index stride) { + Packet16i stride_vector = _mm512_set1_epi32(stride); + Packet16i stride_multiplier = + _mm512_set_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + Packet16i indices = _mm512_mullo_epi32(stride_vector, stride_multiplier); + _mm512_i32scatter_ps(to, indices, from, 4); +} +template <> +EIGEN_DEVICE_FUNC inline void pscatter(double* to, + const Packet8d& from, + Index stride) { + Packet8i stride_vector = _mm256_set1_epi32(stride); + Packet8i stride_multiplier = _mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0); + Packet8i indices = _mm256_mullo_epi32(stride_vector, stride_multiplier); + _mm512_i32scatter_pd(to, indices, from, 8); +} + +template <> +EIGEN_STRONG_INLINE void pstore1(float* to, const float& a) { + Packet16f pa = pset1(a); + pstore(to, pa); +} +template <> +EIGEN_STRONG_INLINE void pstore1(double* to, const double& a) { + Packet8d pa = pset1(a); + pstore(to, pa); +} +template <> +EIGEN_STRONG_INLINE void pstore1(int* to, const int& a) { + Packet16i pa = pset1(a); + pstore(to, pa); +} + +template<> EIGEN_STRONG_INLINE void prefetch(const float* addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); } +template<> EIGEN_STRONG_INLINE void prefetch(const double* addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); } +template<> EIGEN_STRONG_INLINE void prefetch(const int* addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); } + +template <> +EIGEN_STRONG_INLINE float pfirst(const Packet16f& a) { + return _mm_cvtss_f32(_mm512_extractf32x4_ps(a, 0)); +} +template <> +EIGEN_STRONG_INLINE double pfirst(const Packet8d& a) { + return _mm_cvtsd_f64(_mm256_extractf128_pd(_mm512_extractf64x4_pd(a, 0), 0)); +} +template <> +EIGEN_STRONG_INLINE int pfirst(const Packet16i& a) { + return _mm_extract_epi32(_mm512_extracti32x4_epi32(a, 0), 0); +} + +template<> EIGEN_STRONG_INLINE Packet16f preverse(const Packet16f& a) +{ + return _mm512_permutexvar_ps(_mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), a); +} + +template<> EIGEN_STRONG_INLINE Packet8d preverse(const Packet8d& a) +{ + return _mm512_permutexvar_pd(_mm512_set_epi32(0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7), a); +} + +template<> EIGEN_STRONG_INLINE Packet16f pabs(const Packet16f& a) +{ + // _mm512_abs_ps intrinsic not found, so hack around it + return (__m512)_mm512_and_si512((__m512i)a, _mm512_set1_epi32(0x7fffffff)); +} +template <> +EIGEN_STRONG_INLINE Packet8d pabs(const Packet8d& a) { + // _mm512_abs_ps intrinsic not found, so hack around it + return (__m512d)_mm512_and_si512((__m512i)a, + _mm512_set1_epi64(0x7fffffffffffffff)); +} + +#ifdef EIGEN_VECTORIZE_AVX512DQ +// AVX512F does not define _mm512_extractf32x8_ps to extract _m256 from _m512 +#define EIGEN_EXTRACT_8f_FROM_16f(INPUT, OUTPUT) \ + __m256 OUTPUT##_0 = _mm512_extractf32x8_ps(INPUT, 0) __m256 OUTPUT##_1 = \ + _mm512_extractf32x8_ps(INPUT, 1) +#else +#define EIGEN_EXTRACT_8f_FROM_16f(INPUT, OUTPUT) \ + __m256 OUTPUT##_0 = _mm256_insertf128_ps( \ + _mm256_castps128_ps256(_mm512_extractf32x4_ps(INPUT, 0)), \ + _mm512_extractf32x4_ps(INPUT, 1), 1); \ + __m256 OUTPUT##_1 = _mm256_insertf128_ps( \ + _mm256_castps128_ps256(_mm512_extractf32x4_ps(INPUT, 2)), \ + _mm512_extractf32x4_ps(INPUT, 3), 1); +#endif + +#ifdef EIGEN_VECTORIZE_AVX512DQ +#define EIGEN_INSERT_8f_INTO_16f(OUTPUT, INPUTA, INPUTB) \ + OUTPUT = _mm512_insertf32x8(OUTPUT, INPUTA, 0); \ + OUTPUT = _mm512_insertf32x8(OUTPUT, INPUTB, 1); +#else +#define EIGEN_INSERT_8f_INTO_16f(OUTPUT, INPUTA, INPUTB) \ + OUTPUT = _mm512_insertf32x4(OUTPUT, _mm256_extractf128_ps(INPUTA, 0), 0); \ + OUTPUT = _mm512_insertf32x4(OUTPUT, _mm256_extractf128_ps(INPUTA, 1), 1); \ + OUTPUT = _mm512_insertf32x4(OUTPUT, _mm256_extractf128_ps(INPUTB, 0), 2); \ + OUTPUT = _mm512_insertf32x4(OUTPUT, _mm256_extractf128_ps(INPUTB, 1), 3); +#endif +template<> EIGEN_STRONG_INLINE Packet16f preduxp(const Packet16f* +vecs) +{ + EIGEN_EXTRACT_8f_FROM_16f(vecs[0], vecs0); + EIGEN_EXTRACT_8f_FROM_16f(vecs[1], vecs1); + EIGEN_EXTRACT_8f_FROM_16f(vecs[2], vecs2); + EIGEN_EXTRACT_8f_FROM_16f(vecs[3], vecs3); + EIGEN_EXTRACT_8f_FROM_16f(vecs[4], vecs4); + EIGEN_EXTRACT_8f_FROM_16f(vecs[5], vecs5); + EIGEN_EXTRACT_8f_FROM_16f(vecs[6], vecs6); + EIGEN_EXTRACT_8f_FROM_16f(vecs[7], vecs7); + EIGEN_EXTRACT_8f_FROM_16f(vecs[8], vecs8); + EIGEN_EXTRACT_8f_FROM_16f(vecs[9], vecs9); + EIGEN_EXTRACT_8f_FROM_16f(vecs[10], vecs10); + EIGEN_EXTRACT_8f_FROM_16f(vecs[11], vecs11); + EIGEN_EXTRACT_8f_FROM_16f(vecs[12], vecs12); + EIGEN_EXTRACT_8f_FROM_16f(vecs[13], vecs13); + EIGEN_EXTRACT_8f_FROM_16f(vecs[14], vecs14); + EIGEN_EXTRACT_8f_FROM_16f(vecs[15], vecs15); + + __m256 hsum1 = _mm256_hadd_ps(vecs0_0, vecs1_0); + __m256 hsum2 = _mm256_hadd_ps(vecs2_0, vecs3_0); + __m256 hsum3 = _mm256_hadd_ps(vecs4_0, vecs5_0); + __m256 hsum4 = _mm256_hadd_ps(vecs6_0, vecs7_0); + + __m256 hsum5 = _mm256_hadd_ps(hsum1, hsum1); + __m256 hsum6 = _mm256_hadd_ps(hsum2, hsum2); + __m256 hsum7 = _mm256_hadd_ps(hsum3, hsum3); + __m256 hsum8 = _mm256_hadd_ps(hsum4, hsum4); + + __m256 perm1 = _mm256_permute2f128_ps(hsum5, hsum5, 0x23); + __m256 perm2 = _mm256_permute2f128_ps(hsum6, hsum6, 0x23); + __m256 perm3 = _mm256_permute2f128_ps(hsum7, hsum7, 0x23); + __m256 perm4 = _mm256_permute2f128_ps(hsum8, hsum8, 0x23); + + __m256 sum1 = _mm256_add_ps(perm1, hsum5); + __m256 sum2 = _mm256_add_ps(perm2, hsum6); + __m256 sum3 = _mm256_add_ps(perm3, hsum7); + __m256 sum4 = _mm256_add_ps(perm4, hsum8); + + __m256 blend1 = _mm256_blend_ps(sum1, sum2, 0xcc); + __m256 blend2 = _mm256_blend_ps(sum3, sum4, 0xcc); + + __m256 final = _mm256_blend_ps(blend1, blend2, 0xf0); + + hsum1 = _mm256_hadd_ps(vecs0_1, vecs1_1); + hsum2 = _mm256_hadd_ps(vecs2_1, vecs3_1); + hsum3 = _mm256_hadd_ps(vecs4_1, vecs5_1); + hsum4 = _mm256_hadd_ps(vecs6_1, vecs7_1); + + hsum5 = _mm256_hadd_ps(hsum1, hsum1); + hsum6 = _mm256_hadd_ps(hsum2, hsum2); + hsum7 = _mm256_hadd_ps(hsum3, hsum3); + hsum8 = _mm256_hadd_ps(hsum4, hsum4); + + perm1 = _mm256_permute2f128_ps(hsum5, hsum5, 0x23); + perm2 = _mm256_permute2f128_ps(hsum6, hsum6, 0x23); + perm3 = _mm256_permute2f128_ps(hsum7, hsum7, 0x23); + perm4 = _mm256_permute2f128_ps(hsum8, hsum8, 0x23); + + sum1 = _mm256_add_ps(perm1, hsum5); + sum2 = _mm256_add_ps(perm2, hsum6); + sum3 = _mm256_add_ps(perm3, hsum7); + sum4 = _mm256_add_ps(perm4, hsum8); + + blend1 = _mm256_blend_ps(sum1, sum2, 0xcc); + blend2 = _mm256_blend_ps(sum3, sum4, 0xcc); + + final = padd(final, _mm256_blend_ps(blend1, blend2, 0xf0)); + + hsum1 = _mm256_hadd_ps(vecs8_0, vecs9_0); + hsum2 = _mm256_hadd_ps(vecs10_0, vecs11_0); + hsum3 = _mm256_hadd_ps(vecs12_0, vecs13_0); + hsum4 = _mm256_hadd_ps(vecs14_0, vecs15_0); + + hsum5 = _mm256_hadd_ps(hsum1, hsum1); + hsum6 = _mm256_hadd_ps(hsum2, hsum2); + hsum7 = _mm256_hadd_ps(hsum3, hsum3); + hsum8 = _mm256_hadd_ps(hsum4, hsum4); + + perm1 = _mm256_permute2f128_ps(hsum5, hsum5, 0x23); + perm2 = _mm256_permute2f128_ps(hsum6, hsum6, 0x23); + perm3 = _mm256_permute2f128_ps(hsum7, hsum7, 0x23); + perm4 = _mm256_permute2f128_ps(hsum8, hsum8, 0x23); + + sum1 = _mm256_add_ps(perm1, hsum5); + sum2 = _mm256_add_ps(perm2, hsum6); + sum3 = _mm256_add_ps(perm3, hsum7); + sum4 = _mm256_add_ps(perm4, hsum8); + + blend1 = _mm256_blend_ps(sum1, sum2, 0xcc); + blend2 = _mm256_blend_ps(sum3, sum4, 0xcc); + + __m256 final_1 = _mm256_blend_ps(blend1, blend2, 0xf0); + + hsum1 = _mm256_hadd_ps(vecs8_1, vecs9_1); + hsum2 = _mm256_hadd_ps(vecs10_1, vecs11_1); + hsum3 = _mm256_hadd_ps(vecs12_1, vecs13_1); + hsum4 = _mm256_hadd_ps(vecs14_1, vecs15_1); + + hsum5 = _mm256_hadd_ps(hsum1, hsum1); + hsum6 = _mm256_hadd_ps(hsum2, hsum2); + hsum7 = _mm256_hadd_ps(hsum3, hsum3); + hsum8 = _mm256_hadd_ps(hsum4, hsum4); + + perm1 = _mm256_permute2f128_ps(hsum5, hsum5, 0x23); + perm2 = _mm256_permute2f128_ps(hsum6, hsum6, 0x23); + perm3 = _mm256_permute2f128_ps(hsum7, hsum7, 0x23); + perm4 = _mm256_permute2f128_ps(hsum8, hsum8, 0x23); + + sum1 = _mm256_add_ps(perm1, hsum5); + sum2 = _mm256_add_ps(perm2, hsum6); + sum3 = _mm256_add_ps(perm3, hsum7); + sum4 = _mm256_add_ps(perm4, hsum8); + + blend1 = _mm256_blend_ps(sum1, sum2, 0xcc); + blend2 = _mm256_blend_ps(sum3, sum4, 0xcc); + + final_1 = padd(final_1, _mm256_blend_ps(blend1, blend2, 0xf0)); + + __m512 final_output; + + EIGEN_INSERT_8f_INTO_16f(final_output, final, final_1); + return final_output; +} + +template<> EIGEN_STRONG_INLINE Packet8d preduxp(const Packet8d* vecs) +{ + Packet4d vecs0_0 = _mm512_extractf64x4_pd(vecs[0], 0); + Packet4d vecs0_1 = _mm512_extractf64x4_pd(vecs[0], 1); + + Packet4d vecs1_0 = _mm512_extractf64x4_pd(vecs[1], 0); + Packet4d vecs1_1 = _mm512_extractf64x4_pd(vecs[1], 1); + + Packet4d vecs2_0 = _mm512_extractf64x4_pd(vecs[2], 0); + Packet4d vecs2_1 = _mm512_extractf64x4_pd(vecs[2], 1); + + Packet4d vecs3_0 = _mm512_extractf64x4_pd(vecs[3], 0); + Packet4d vecs3_1 = _mm512_extractf64x4_pd(vecs[3], 1); + + Packet4d vecs4_0 = _mm512_extractf64x4_pd(vecs[4], 0); + Packet4d vecs4_1 = _mm512_extractf64x4_pd(vecs[4], 1); + + Packet4d vecs5_0 = _mm512_extractf64x4_pd(vecs[5], 0); + Packet4d vecs5_1 = _mm512_extractf64x4_pd(vecs[5], 1); + + Packet4d vecs6_0 = _mm512_extractf64x4_pd(vecs[6], 0); + Packet4d vecs6_1 = _mm512_extractf64x4_pd(vecs[6], 1); + + Packet4d vecs7_0 = _mm512_extractf64x4_pd(vecs[7], 0); + Packet4d vecs7_1 = _mm512_extractf64x4_pd(vecs[7], 1); + + Packet4d tmp0, tmp1; + + tmp0 = _mm256_hadd_pd(vecs0_0, vecs1_0); + tmp0 = _mm256_add_pd(tmp0, _mm256_permute2f128_pd(tmp0, tmp0, 1)); + + tmp1 = _mm256_hadd_pd(vecs2_0, vecs3_0); + tmp1 = _mm256_add_pd(tmp1, _mm256_permute2f128_pd(tmp1, tmp1, 1)); + + __m256d final_0 = _mm256_blend_pd(tmp0, tmp1, 0xC); + + tmp0 = _mm256_hadd_pd(vecs0_1, vecs1_1); + tmp0 = _mm256_add_pd(tmp0, _mm256_permute2f128_pd(tmp0, tmp0, 1)); + + tmp1 = _mm256_hadd_pd(vecs2_1, vecs3_1); + tmp1 = _mm256_add_pd(tmp1, _mm256_permute2f128_pd(tmp1, tmp1, 1)); + + final_0 = padd(final_0, _mm256_blend_pd(tmp0, tmp1, 0xC)); + + tmp0 = _mm256_hadd_pd(vecs4_0, vecs5_0); + tmp0 = _mm256_add_pd(tmp0, _mm256_permute2f128_pd(tmp0, tmp0, 1)); + + tmp1 = _mm256_hadd_pd(vecs6_0, vecs7_0); + tmp1 = _mm256_add_pd(tmp1, _mm256_permute2f128_pd(tmp1, tmp1, 1)); + + __m256d final_1 = _mm256_blend_pd(tmp0, tmp1, 0xC); + + tmp0 = _mm256_hadd_pd(vecs4_1, vecs5_1); + tmp0 = _mm256_add_pd(tmp0, _mm256_permute2f128_pd(tmp0, tmp0, 1)); + + tmp1 = _mm256_hadd_pd(vecs6_1, vecs7_1); + tmp1 = _mm256_add_pd(tmp1, _mm256_permute2f128_pd(tmp1, tmp1, 1)); + + final_1 = padd(final_1, _mm256_blend_pd(tmp0, tmp1, 0xC)); + + __m512d final_output = _mm512_insertf64x4(final_output, final_0, 0); + + return _mm512_insertf64x4(final_output, final_1, 1); +} + +template <> +EIGEN_STRONG_INLINE float predux(const Packet16f& a) { + //#ifdef EIGEN_VECTORIZE_AVX512DQ +#if 0 + Packet8f lane0 = _mm512_extractf32x8_ps(a, 0); + Packet8f lane1 = _mm512_extractf32x8_ps(a, 1); + Packet8f sum = padd(lane0, lane1); + Packet8f tmp0 = _mm256_hadd_ps(sum, _mm256_permute2f128_ps(a, a, 1)); + tmp0 = _mm256_hadd_ps(tmp0, tmp0); + return pfirst(_mm256_hadd_ps(tmp0, tmp0)); +#else + Packet4f lane0 = _mm512_extractf32x4_ps(a, 0); + Packet4f lane1 = _mm512_extractf32x4_ps(a, 1); + Packet4f lane2 = _mm512_extractf32x4_ps(a, 2); + Packet4f lane3 = _mm512_extractf32x4_ps(a, 3); + Packet4f sum = padd(padd(lane0, lane1), padd(lane2, lane3)); + sum = _mm_hadd_ps(sum, sum); + sum = _mm_hadd_ps(sum, _mm_permute_ps(sum, 1)); + return pfirst(sum); +#endif +} +template <> +EIGEN_STRONG_INLINE double predux(const Packet8d& a) { + Packet4d lane0 = _mm512_extractf64x4_pd(a, 0); + Packet4d lane1 = _mm512_extractf64x4_pd(a, 1); + Packet4d sum = padd(lane0, lane1); + Packet4d tmp0 = _mm256_hadd_pd(sum, _mm256_permute2f128_pd(sum, sum, 1)); + return pfirst(_mm256_hadd_pd(tmp0, tmp0)); +} + +template <> +EIGEN_STRONG_INLINE Packet8f predux_downto4(const Packet16f& a) { +#ifdef EIGEN_VECTORIZE_AVX512DQ + Packet8f lane0 = _mm512_extractf32x8_ps(a, 0); + Packet8f lane1 = _mm512_extractf32x8_ps(a, 1); + return padd(lane0, lane1); +#else + Packet4f lane0 = _mm512_extractf32x4_ps(a, 0); + Packet4f lane1 = _mm512_extractf32x4_ps(a, 1); + Packet4f lane2 = _mm512_extractf32x4_ps(a, 2); + Packet4f lane3 = _mm512_extractf32x4_ps(a, 3); + Packet4f sum0 = padd(lane0, lane2); + Packet4f sum1 = padd(lane1, lane3); + return _mm256_insertf128_ps(_mm256_castps128_ps256(sum0), sum1, 1); +#endif +} +template <> +EIGEN_STRONG_INLINE Packet4d predux_downto4(const Packet8d& a) { + Packet4d lane0 = _mm512_extractf64x4_pd(a, 0); + Packet4d lane1 = _mm512_extractf64x4_pd(a, 1); + Packet4d res = padd(lane0, lane1); + return res; +} + +template <> +EIGEN_STRONG_INLINE float predux_mul(const Packet16f& a) { +//#ifdef EIGEN_VECTORIZE_AVX512DQ +#if 0 + Packet8f lane0 = _mm512_extractf32x8_ps(a, 0); + Packet8f lane1 = _mm512_extractf32x8_ps(a, 1); + Packet8f res = pmul(lane0, lane1); + res = pmul(res, _mm256_permute2f128_ps(res, res, 1)); + res = pmul(res, _mm_permute_ps(res, _MM_SHUFFLE(0, 0, 3, 2))); + return pfirst(pmul(res, _mm_permute_ps(res, _MM_SHUFFLE(0, 0, 0, 1)))); +#else + Packet4f lane0 = _mm512_extractf32x4_ps(a, 0); + Packet4f lane1 = _mm512_extractf32x4_ps(a, 1); + Packet4f lane2 = _mm512_extractf32x4_ps(a, 2); + Packet4f lane3 = _mm512_extractf32x4_ps(a, 3); + Packet4f res = pmul(pmul(lane0, lane1), pmul(lane2, lane3)); + res = pmul(res, _mm_permute_ps(res, _MM_SHUFFLE(0, 0, 3, 2))); + return pfirst(pmul(res, _mm_permute_ps(res, _MM_SHUFFLE(0, 0, 0, 1)))); +#endif +} +template <> +EIGEN_STRONG_INLINE double predux_mul(const Packet8d& a) { + Packet4d lane0 = _mm512_extractf64x4_pd(a, 0); + Packet4d lane1 = _mm512_extractf64x4_pd(a, 1); + Packet4d res = pmul(lane0, lane1); + res = pmul(res, _mm256_permute2f128_pd(res, res, 1)); + return pfirst(pmul(res, _mm256_shuffle_pd(res, res, 1))); +} + +template <> +EIGEN_STRONG_INLINE float predux_min(const Packet16f& a) { + Packet4f lane0 = _mm512_extractf32x4_ps(a, 0); + Packet4f lane1 = _mm512_extractf32x4_ps(a, 1); + Packet4f lane2 = _mm512_extractf32x4_ps(a, 2); + Packet4f lane3 = _mm512_extractf32x4_ps(a, 3); + Packet4f res = _mm_min_ps(_mm_min_ps(lane0, lane1), _mm_min_ps(lane2, lane3)); + res = _mm_min_ps(res, _mm_permute_ps(res, _MM_SHUFFLE(0, 0, 3, 2))); + return pfirst(_mm_min_ps(res, _mm_permute_ps(res, _MM_SHUFFLE(0, 0, 0, 1)))); +} +template <> +EIGEN_STRONG_INLINE double predux_min(const Packet8d& a) { + Packet4d lane0 = _mm512_extractf64x4_pd(a, 0); + Packet4d lane1 = _mm512_extractf64x4_pd(a, 1); + Packet4d res = _mm256_min_pd(lane0, lane1); + res = _mm256_min_pd(res, _mm256_permute2f128_pd(res, res, 1)); + return pfirst(_mm256_min_pd(res, _mm256_shuffle_pd(res, res, 1))); +} + +template <> +EIGEN_STRONG_INLINE float predux_max(const Packet16f& a) { + Packet4f lane0 = _mm512_extractf32x4_ps(a, 0); + Packet4f lane1 = _mm512_extractf32x4_ps(a, 1); + Packet4f lane2 = _mm512_extractf32x4_ps(a, 2); + Packet4f lane3 = _mm512_extractf32x4_ps(a, 3); + Packet4f res = _mm_max_ps(_mm_max_ps(lane0, lane1), _mm_max_ps(lane2, lane3)); + res = _mm_max_ps(res, _mm_permute_ps(res, _MM_SHUFFLE(0, 0, 3, 2))); + return pfirst(_mm_max_ps(res, _mm_permute_ps(res, _MM_SHUFFLE(0, 0, 0, 1)))); +} +template <> +EIGEN_STRONG_INLINE double predux_max(const Packet8d& a) { + Packet4d lane0 = _mm512_extractf64x4_pd(a, 0); + Packet4d lane1 = _mm512_extractf64x4_pd(a, 1); + Packet4d res = _mm256_max_pd(lane0, lane1); + res = _mm256_max_pd(res, _mm256_permute2f128_pd(res, res, 1)); + return pfirst(_mm256_max_pd(res, _mm256_shuffle_pd(res, res, 1))); +} + +template +struct palign_impl { + static EIGEN_STRONG_INLINE void run(Packet16f& first, + const Packet16f& second) { + if (Offset != 0) { + __m512i first_idx = _mm512_set_epi32( + Offset + 15, Offset + 14, Offset + 13, Offset + 12, Offset + 11, + Offset + 10, Offset + 9, Offset + 8, Offset + 7, Offset + 6, + Offset + 5, Offset + 4, Offset + 3, Offset + 2, Offset + 1, Offset); + + __m512i second_idx = + _mm512_set_epi32(Offset - 1, Offset - 2, Offset - 3, Offset - 4, + Offset - 5, Offset - 6, Offset - 7, Offset - 8, + Offset - 9, Offset - 10, Offset - 11, Offset - 12, + Offset - 13, Offset - 14, Offset - 15, Offset - 16); + + unsigned short mask = 0xFFFF; + mask <<= (16 - Offset); + + first = _mm512_permutexvar_ps(first_idx, first); + Packet16f tmp = _mm512_permutexvar_ps(second_idx, second); + first = _mm512_mask_blend_ps(mask, first, tmp); + } + } +}; +template +struct palign_impl { + static EIGEN_STRONG_INLINE void run(Packet8d& first, const Packet8d& second) { + if (Offset != 0) { + __m512i first_idx = _mm512_set_epi32( + 0, Offset + 7, 0, Offset + 6, 0, Offset + 5, 0, Offset + 4, 0, + Offset + 3, 0, Offset + 2, 0, Offset + 1, 0, Offset); + + __m512i second_idx = _mm512_set_epi32( + 0, Offset - 1, 0, Offset - 2, 0, Offset - 3, 0, Offset - 4, 0, + Offset - 5, 0, Offset - 6, 0, Offset - 7, 0, Offset - 8); + + unsigned char mask = 0xFF; + mask <<= (8 - Offset); + + first = _mm512_permutexvar_pd(first_idx, first); + Packet8d tmp = _mm512_permutexvar_pd(second_idx, second); + first = _mm512_mask_blend_pd(mask, first, tmp); + } + } +}; + + +#define PACK_OUTPUT(OUTPUT, INPUT, INDEX, STRIDE) \ + EIGEN_INSERT_8f_INTO_16f(OUTPUT[INDEX], INPUT[INDEX], INPUT[INDEX + STRIDE]); + +EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock& kernel) { + __m512 T0 = _mm512_unpacklo_ps(kernel.packet[0], kernel.packet[1]); + __m512 T1 = _mm512_unpackhi_ps(kernel.packet[0], kernel.packet[1]); + __m512 T2 = _mm512_unpacklo_ps(kernel.packet[2], kernel.packet[3]); + __m512 T3 = _mm512_unpackhi_ps(kernel.packet[2], kernel.packet[3]); + __m512 T4 = _mm512_unpacklo_ps(kernel.packet[4], kernel.packet[5]); + __m512 T5 = _mm512_unpackhi_ps(kernel.packet[4], kernel.packet[5]); + __m512 T6 = _mm512_unpacklo_ps(kernel.packet[6], kernel.packet[7]); + __m512 T7 = _mm512_unpackhi_ps(kernel.packet[6], kernel.packet[7]); + __m512 T8 = _mm512_unpacklo_ps(kernel.packet[8], kernel.packet[9]); + __m512 T9 = _mm512_unpackhi_ps(kernel.packet[8], kernel.packet[9]); + __m512 T10 = _mm512_unpacklo_ps(kernel.packet[10], kernel.packet[11]); + __m512 T11 = _mm512_unpackhi_ps(kernel.packet[10], kernel.packet[11]); + __m512 T12 = _mm512_unpacklo_ps(kernel.packet[12], kernel.packet[13]); + __m512 T13 = _mm512_unpackhi_ps(kernel.packet[12], kernel.packet[13]); + __m512 T14 = _mm512_unpacklo_ps(kernel.packet[14], kernel.packet[15]); + __m512 T15 = _mm512_unpackhi_ps(kernel.packet[14], kernel.packet[15]); + __m512 S0 = _mm512_shuffle_ps(T0, T2, _MM_SHUFFLE(1, 0, 1, 0)); + __m512 S1 = _mm512_shuffle_ps(T0, T2, _MM_SHUFFLE(3, 2, 3, 2)); + __m512 S2 = _mm512_shuffle_ps(T1, T3, _MM_SHUFFLE(1, 0, 1, 0)); + __m512 S3 = _mm512_shuffle_ps(T1, T3, _MM_SHUFFLE(3, 2, 3, 2)); + __m512 S4 = _mm512_shuffle_ps(T4, T6, _MM_SHUFFLE(1, 0, 1, 0)); + __m512 S5 = _mm512_shuffle_ps(T4, T6, _MM_SHUFFLE(3, 2, 3, 2)); + __m512 S6 = _mm512_shuffle_ps(T5, T7, _MM_SHUFFLE(1, 0, 1, 0)); + __m512 S7 = _mm512_shuffle_ps(T5, T7, _MM_SHUFFLE(3, 2, 3, 2)); + __m512 S8 = _mm512_shuffle_ps(T8, T10, _MM_SHUFFLE(1, 0, 1, 0)); + __m512 S9 = _mm512_shuffle_ps(T8, T10, _MM_SHUFFLE(3, 2, 3, 2)); + __m512 S10 = _mm512_shuffle_ps(T9, T11, _MM_SHUFFLE(1, 0, 1, 0)); + __m512 S11 = _mm512_shuffle_ps(T9, T11, _MM_SHUFFLE(3, 2, 3, 2)); + __m512 S12 = _mm512_shuffle_ps(T12, T14, _MM_SHUFFLE(1, 0, 1, 0)); + __m512 S13 = _mm512_shuffle_ps(T12, T14, _MM_SHUFFLE(3, 2, 3, 2)); + __m512 S14 = _mm512_shuffle_ps(T13, T15, _MM_SHUFFLE(1, 0, 1, 0)); + __m512 S15 = _mm512_shuffle_ps(T13, T15, _MM_SHUFFLE(3, 2, 3, 2)); + + EIGEN_EXTRACT_8f_FROM_16f(S0, S0); + EIGEN_EXTRACT_8f_FROM_16f(S1, S1); + EIGEN_EXTRACT_8f_FROM_16f(S2, S2); + EIGEN_EXTRACT_8f_FROM_16f(S3, S3); + EIGEN_EXTRACT_8f_FROM_16f(S4, S4); + EIGEN_EXTRACT_8f_FROM_16f(S5, S5); + EIGEN_EXTRACT_8f_FROM_16f(S6, S6); + EIGEN_EXTRACT_8f_FROM_16f(S7, S7); + EIGEN_EXTRACT_8f_FROM_16f(S8, S8); + EIGEN_EXTRACT_8f_FROM_16f(S9, S9); + EIGEN_EXTRACT_8f_FROM_16f(S10, S10); + EIGEN_EXTRACT_8f_FROM_16f(S11, S11); + EIGEN_EXTRACT_8f_FROM_16f(S12, S12); + EIGEN_EXTRACT_8f_FROM_16f(S13, S13); + EIGEN_EXTRACT_8f_FROM_16f(S14, S14); + EIGEN_EXTRACT_8f_FROM_16f(S15, S15); + + PacketBlock tmp; + + tmp.packet[0] = _mm256_permute2f128_ps(S0_0, S4_0, 0x20); + tmp.packet[1] = _mm256_permute2f128_ps(S1_0, S5_0, 0x20); + tmp.packet[2] = _mm256_permute2f128_ps(S2_0, S6_0, 0x20); + tmp.packet[3] = _mm256_permute2f128_ps(S3_0, S7_0, 0x20); + tmp.packet[4] = _mm256_permute2f128_ps(S0_0, S4_0, 0x31); + tmp.packet[5] = _mm256_permute2f128_ps(S1_0, S5_0, 0x31); + tmp.packet[6] = _mm256_permute2f128_ps(S2_0, S6_0, 0x31); + tmp.packet[7] = _mm256_permute2f128_ps(S3_0, S7_0, 0x31); + + tmp.packet[8] = _mm256_permute2f128_ps(S0_1, S4_1, 0x20); + tmp.packet[9] = _mm256_permute2f128_ps(S1_1, S5_1, 0x20); + tmp.packet[10] = _mm256_permute2f128_ps(S2_1, S6_1, 0x20); + tmp.packet[11] = _mm256_permute2f128_ps(S3_1, S7_1, 0x20); + tmp.packet[12] = _mm256_permute2f128_ps(S0_1, S4_1, 0x31); + tmp.packet[13] = _mm256_permute2f128_ps(S1_1, S5_1, 0x31); + tmp.packet[14] = _mm256_permute2f128_ps(S2_1, S6_1, 0x31); + tmp.packet[15] = _mm256_permute2f128_ps(S3_1, S7_1, 0x31); + + // Second set of _m256 outputs + tmp.packet[16] = _mm256_permute2f128_ps(S8_0, S12_0, 0x20); + tmp.packet[17] = _mm256_permute2f128_ps(S9_0, S13_0, 0x20); + tmp.packet[18] = _mm256_permute2f128_ps(S10_0, S14_0, 0x20); + tmp.packet[19] = _mm256_permute2f128_ps(S11_0, S15_0, 0x20); + tmp.packet[20] = _mm256_permute2f128_ps(S8_0, S12_0, 0x31); + tmp.packet[21] = _mm256_permute2f128_ps(S9_0, S13_0, 0x31); + tmp.packet[22] = _mm256_permute2f128_ps(S10_0, S14_0, 0x31); + tmp.packet[23] = _mm256_permute2f128_ps(S11_0, S15_0, 0x31); + + tmp.packet[24] = _mm256_permute2f128_ps(S8_1, S12_1, 0x20); + tmp.packet[25] = _mm256_permute2f128_ps(S9_1, S13_1, 0x20); + tmp.packet[26] = _mm256_permute2f128_ps(S10_1, S14_1, 0x20); + tmp.packet[27] = _mm256_permute2f128_ps(S11_1, S15_1, 0x20); + tmp.packet[28] = _mm256_permute2f128_ps(S8_1, S12_1, 0x31); + tmp.packet[29] = _mm256_permute2f128_ps(S9_1, S13_1, 0x31); + tmp.packet[30] = _mm256_permute2f128_ps(S10_1, S14_1, 0x31); + tmp.packet[31] = _mm256_permute2f128_ps(S11_1, S15_1, 0x31); + + // Pack them into the output + PACK_OUTPUT(kernel.packet, tmp.packet, 0, 16); + PACK_OUTPUT(kernel.packet, tmp.packet, 1, 16); + PACK_OUTPUT(kernel.packet, tmp.packet, 2, 16); + PACK_OUTPUT(kernel.packet, tmp.packet, 3, 16); + + PACK_OUTPUT(kernel.packet, tmp.packet, 4, 16); + PACK_OUTPUT(kernel.packet, tmp.packet, 5, 16); + PACK_OUTPUT(kernel.packet, tmp.packet, 6, 16); + PACK_OUTPUT(kernel.packet, tmp.packet, 7, 16); + + PACK_OUTPUT(kernel.packet, tmp.packet, 8, 16); + PACK_OUTPUT(kernel.packet, tmp.packet, 9, 16); + PACK_OUTPUT(kernel.packet, tmp.packet, 10, 16); + PACK_OUTPUT(kernel.packet, tmp.packet, 11, 16); + + PACK_OUTPUT(kernel.packet, tmp.packet, 12, 16); + PACK_OUTPUT(kernel.packet, tmp.packet, 13, 16); + PACK_OUTPUT(kernel.packet, tmp.packet, 14, 16); + PACK_OUTPUT(kernel.packet, tmp.packet, 15, 16); +} +#define PACK_OUTPUT_2(OUTPUT, INPUT, INDEX, STRIDE) \ + EIGEN_INSERT_8f_INTO_16f(OUTPUT[INDEX], INPUT[2 * INDEX], \ + INPUT[2 * INDEX + STRIDE]); + +EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock& kernel) { + __m512 T0 = _mm512_unpacklo_ps(kernel.packet[0], kernel.packet[1]); + __m512 T1 = _mm512_unpackhi_ps(kernel.packet[0], kernel.packet[1]); + __m512 T2 = _mm512_unpacklo_ps(kernel.packet[2], kernel.packet[3]); + __m512 T3 = _mm512_unpackhi_ps(kernel.packet[2], kernel.packet[3]); + + __m512 S0 = _mm512_shuffle_ps(T0, T2, _MM_SHUFFLE(1, 0, 1, 0)); + __m512 S1 = _mm512_shuffle_ps(T0, T2, _MM_SHUFFLE(3, 2, 3, 2)); + __m512 S2 = _mm512_shuffle_ps(T1, T3, _MM_SHUFFLE(1, 0, 1, 0)); + __m512 S3 = _mm512_shuffle_ps(T1, T3, _MM_SHUFFLE(3, 2, 3, 2)); + + EIGEN_EXTRACT_8f_FROM_16f(S0, S0); + EIGEN_EXTRACT_8f_FROM_16f(S1, S1); + EIGEN_EXTRACT_8f_FROM_16f(S2, S2); + EIGEN_EXTRACT_8f_FROM_16f(S3, S3); + + PacketBlock tmp; + + tmp.packet[0] = _mm256_permute2f128_ps(S0_0, S1_0, 0x20); + tmp.packet[1] = _mm256_permute2f128_ps(S2_0, S3_0, 0x20); + tmp.packet[2] = _mm256_permute2f128_ps(S0_0, S1_0, 0x31); + tmp.packet[3] = _mm256_permute2f128_ps(S2_0, S3_0, 0x31); + + tmp.packet[4] = _mm256_permute2f128_ps(S0_1, S1_1, 0x20); + tmp.packet[5] = _mm256_permute2f128_ps(S2_1, S3_1, 0x20); + tmp.packet[6] = _mm256_permute2f128_ps(S0_1, S1_1, 0x31); + tmp.packet[7] = _mm256_permute2f128_ps(S2_1, S3_1, 0x31); + + PACK_OUTPUT_2(kernel.packet, tmp.packet, 0, 1); + PACK_OUTPUT_2(kernel.packet, tmp.packet, 1, 1); + PACK_OUTPUT_2(kernel.packet, tmp.packet, 2, 1); + PACK_OUTPUT_2(kernel.packet, tmp.packet, 3, 1); +} + +#define PACK_OUTPUT_SQ_D(OUTPUT, INPUT, INDEX, STRIDE) \ + OUTPUT[INDEX] = _mm512_insertf64x4(OUTPUT[INDEX], INPUT[INDEX], 0); \ + OUTPUT[INDEX] = _mm512_insertf64x4(OUTPUT[INDEX], INPUT[INDEX + STRIDE], 1); + +#define PACK_OUTPUT_D(OUTPUT, INPUT, INDEX, STRIDE) \ + OUTPUT[INDEX] = _mm512_insertf64x4(OUTPUT[INDEX], INPUT[(2 * INDEX)], 0); \ + OUTPUT[INDEX] = \ + _mm512_insertf64x4(OUTPUT[INDEX], INPUT[(2 * INDEX) + STRIDE], 1); + +EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock& kernel) { + __m512d T0 = _mm512_shuffle_pd(kernel.packet[0], kernel.packet[1], 0); + __m512d T1 = _mm512_shuffle_pd(kernel.packet[0], kernel.packet[1], 0xff); + __m512d T2 = _mm512_shuffle_pd(kernel.packet[2], kernel.packet[3], 0); + __m512d T3 = _mm512_shuffle_pd(kernel.packet[2], kernel.packet[3], 0xff); + + PacketBlock tmp; + + tmp.packet[0] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T0, 0), + _mm512_extractf64x4_pd(T2, 0), 0x20); + tmp.packet[1] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T1, 0), + _mm512_extractf64x4_pd(T3, 0), 0x20); + tmp.packet[2] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T0, 0), + _mm512_extractf64x4_pd(T2, 0), 0x31); + tmp.packet[3] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T1, 0), + _mm512_extractf64x4_pd(T3, 0), 0x31); + + tmp.packet[4] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T0, 1), + _mm512_extractf64x4_pd(T2, 1), 0x20); + tmp.packet[5] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T1, 1), + _mm512_extractf64x4_pd(T3, 1), 0x20); + tmp.packet[6] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T0, 1), + _mm512_extractf64x4_pd(T2, 1), 0x31); + tmp.packet[7] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T1, 1), + _mm512_extractf64x4_pd(T3, 1), 0x31); + + PACK_OUTPUT_D(kernel.packet, tmp.packet, 0, 1); + PACK_OUTPUT_D(kernel.packet, tmp.packet, 1, 1); + PACK_OUTPUT_D(kernel.packet, tmp.packet, 2, 1); + PACK_OUTPUT_D(kernel.packet, tmp.packet, 3, 1); +} + +EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock& kernel) { + __m512d T0 = _mm512_unpacklo_pd(kernel.packet[0], kernel.packet[1]); + __m512d T1 = _mm512_unpackhi_pd(kernel.packet[0], kernel.packet[1]); + __m512d T2 = _mm512_unpacklo_pd(kernel.packet[2], kernel.packet[3]); + __m512d T3 = _mm512_unpackhi_pd(kernel.packet[2], kernel.packet[3]); + __m512d T4 = _mm512_unpacklo_pd(kernel.packet[4], kernel.packet[5]); + __m512d T5 = _mm512_unpackhi_pd(kernel.packet[4], kernel.packet[5]); + __m512d T6 = _mm512_unpacklo_pd(kernel.packet[6], kernel.packet[7]); + __m512d T7 = _mm512_unpackhi_pd(kernel.packet[6], kernel.packet[7]); + + PacketBlock tmp; + + tmp.packet[0] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T0, 0), + _mm512_extractf64x4_pd(T2, 0), 0x20); + tmp.packet[1] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T1, 0), + _mm512_extractf64x4_pd(T3, 0), 0x20); + tmp.packet[2] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T0, 0), + _mm512_extractf64x4_pd(T2, 0), 0x31); + tmp.packet[3] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T1, 0), + _mm512_extractf64x4_pd(T3, 0), 0x31); + + tmp.packet[4] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T0, 1), + _mm512_extractf64x4_pd(T2, 1), 0x20); + tmp.packet[5] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T1, 1), + _mm512_extractf64x4_pd(T3, 1), 0x20); + tmp.packet[6] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T0, 1), + _mm512_extractf64x4_pd(T2, 1), 0x31); + tmp.packet[7] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T1, 1), + _mm512_extractf64x4_pd(T3, 1), 0x31); + + tmp.packet[8] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T4, 0), + _mm512_extractf64x4_pd(T6, 0), 0x20); + tmp.packet[9] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T5, 0), + _mm512_extractf64x4_pd(T7, 0), 0x20); + tmp.packet[10] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T4, 0), + _mm512_extractf64x4_pd(T6, 0), 0x31); + tmp.packet[11] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T5, 0), + _mm512_extractf64x4_pd(T7, 0), 0x31); + + tmp.packet[12] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T4, 1), + _mm512_extractf64x4_pd(T6, 1), 0x20); + tmp.packet[13] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T5, 1), + _mm512_extractf64x4_pd(T7, 1), 0x20); + tmp.packet[14] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T4, 1), + _mm512_extractf64x4_pd(T6, 1), 0x31); + tmp.packet[15] = _mm256_permute2f128_pd(_mm512_extractf64x4_pd(T5, 1), + _mm512_extractf64x4_pd(T7, 1), 0x31); + + PACK_OUTPUT_SQ_D(kernel.packet, tmp.packet, 0, 8); + PACK_OUTPUT_SQ_D(kernel.packet, tmp.packet, 1, 8); + PACK_OUTPUT_SQ_D(kernel.packet, tmp.packet, 2, 8); + PACK_OUTPUT_SQ_D(kernel.packet, tmp.packet, 3, 8); + + PACK_OUTPUT_SQ_D(kernel.packet, tmp.packet, 4, 8); + PACK_OUTPUT_SQ_D(kernel.packet, tmp.packet, 5, 8); + PACK_OUTPUT_SQ_D(kernel.packet, tmp.packet, 6, 8); + PACK_OUTPUT_SQ_D(kernel.packet, tmp.packet, 7, 8); +} +template <> +EIGEN_STRONG_INLINE Packet16f pblend(const Selector<16>& /*ifPacket*/, + const Packet16f& /*thenPacket*/, + const Packet16f& /*elsePacket*/) { + assert(false && "To be implemented"); + return Packet16f(); +} +template <> +EIGEN_STRONG_INLINE Packet8d pblend(const Selector<8>& /*ifPacket*/, + const Packet8d& /*thenPacket*/, + const Packet8d& /*elsePacket*/) { + assert(false && "To be implemented"); + return Packet8d(); +} + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_PACKET_MATH_AVX512_H diff --git a/libs/eigen3/Eigen/src/Core/arch/AltiVec/Complex.h b/libs/eigen3/Eigen/src/Core/arch/AltiVec/Complex.h index 68d9a2bff..67db2f8ee 100644 --- a/libs/eigen3/Eigen/src/Core/arch/AltiVec/Complex.h +++ b/libs/eigen3/Eigen/src/Core/arch/AltiVec/Complex.h @@ -2,30 +2,34 @@ // for linear algebra. // // Copyright (C) 2010 Gael Guennebaud +// Copyright (C) 2010-2016 Konstantinos Margaritis // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -#ifndef EIGEN_COMPLEX_ALTIVEC_H -#define EIGEN_COMPLEX_ALTIVEC_H +#ifndef EIGEN_COMPLEX32_ALTIVEC_H +#define EIGEN_COMPLEX32_ALTIVEC_H namespace Eigen { namespace internal { -static Packet4ui p4ui_CONJ_XOR = vec_mergeh((Packet4ui)p4i_ZERO, (Packet4ui)p4f_ZERO_);//{ 0x00000000, 0x80000000, 0x00000000, 0x80000000 }; -static Packet16uc p16uc_COMPLEX_RE = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 0), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 2), 8);//{ 0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11 }; -static Packet16uc p16uc_COMPLEX_IM = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 1), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 3), 8);//{ 4,5,6,7, 4,5,6,7, 12,13,14,15, 12,13,14,15 }; -static Packet16uc p16uc_COMPLEX_REV = vec_sld(p16uc_REVERSE, p16uc_REVERSE, 8);//{ 4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11 }; -static Packet16uc p16uc_COMPLEX_REV2 = vec_sld(p16uc_FORWARD, p16uc_FORWARD, 8);//{ 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; -static Packet16uc p16uc_PSET_HI = (Packet16uc) vec_mergeh((Packet4ui) vec_splat((Packet4ui)p16uc_FORWARD, 0), (Packet4ui) vec_splat((Packet4ui)p16uc_FORWARD, 1));//{ 0,1,2,3, 4,5,6,7, 0,1,2,3, 4,5,6,7 }; -static Packet16uc p16uc_PSET_LO = (Packet16uc) vec_mergeh((Packet4ui) vec_splat((Packet4ui)p16uc_FORWARD, 2), (Packet4ui) vec_splat((Packet4ui)p16uc_FORWARD, 3));//{ 8,9,10,11, 12,13,14,15, 8,9,10,11, 12,13,14,15 }; +static Packet4ui p4ui_CONJ_XOR = vec_mergeh((Packet4ui)p4i_ZERO, (Packet4ui)p4f_MZERO);//{ 0x00000000, 0x80000000, 0x00000000, 0x80000000 }; +#ifdef __VSX__ +#if defined(_BIG_ENDIAN) +static Packet2ul p2ul_CONJ_XOR1 = (Packet2ul) vec_sld((Packet4ui) p2d_MZERO, (Packet4ui) p2l_ZERO, 8);//{ 0x8000000000000000, 0x0000000000000000 }; +static Packet2ul p2ul_CONJ_XOR2 = (Packet2ul) vec_sld((Packet4ui) p2l_ZERO, (Packet4ui) p2d_MZERO, 8);//{ 0x8000000000000000, 0x0000000000000000 }; +#else +static Packet2ul p2ul_CONJ_XOR1 = (Packet2ul) vec_sld((Packet4ui) p2l_ZERO, (Packet4ui) p2d_MZERO, 8);//{ 0x8000000000000000, 0x0000000000000000 }; +static Packet2ul p2ul_CONJ_XOR2 = (Packet2ul) vec_sld((Packet4ui) p2d_MZERO, (Packet4ui) p2l_ZERO, 8);//{ 0x8000000000000000, 0x0000000000000000 }; +#endif +#endif //---------- float ---------- struct Packet2cf { - EIGEN_STRONG_INLINE Packet2cf() {} + EIGEN_STRONG_INLINE explicit Packet2cf() : v(p4f_ZERO) {} EIGEN_STRONG_INLINE explicit Packet2cf(const Packet4f& a) : v(a) {} Packet4f v; }; @@ -33,10 +37,12 @@ struct Packet2cf template<> struct packet_traits > : default_packet_traits { typedef Packet2cf type; + typedef Packet2cf half; enum { Vectorizable = 1, AlignedOnScalar = 1, size = 2, + HasHalfPacket = 0, HasAdd = 1, HasSub = 1, @@ -47,65 +53,78 @@ template<> struct packet_traits > : default_packet_traits HasAbs2 = 0, HasMin = 0, HasMax = 0, +#ifdef __VSX__ + HasBlend = 1, +#endif HasSetLinear = 0 }; }; -template<> struct unpacket_traits { typedef std::complex type; enum {size=2}; }; +template<> struct unpacket_traits { typedef std::complex type; enum {size=2, alignment=Aligned16}; typedef Packet2cf half; }; template<> EIGEN_STRONG_INLINE Packet2cf pset1(const std::complex& from) { Packet2cf res; - /* On AltiVec we cannot load 64-bit registers, so wa have to take care of alignment */ - if((ptrdiff_t(&from) % 16) == 0) + if((std::ptrdiff_t(&from) % 16) == 0) res.v = pload((const float *)&from); else res.v = ploadu((const float *)&from); - res.v = vec_perm(res.v, res.v, p16uc_PSET_HI); + res.v = vec_perm(res.v, res.v, p16uc_PSET64_HI); return res; } -template<> EIGEN_STRONG_INLINE Packet2cf padd(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(vec_add(a.v,b.v)); } -template<> EIGEN_STRONG_INLINE Packet2cf psub(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(vec_sub(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet2cf pload(const std::complex* from) { return Packet2cf(pload((const float *) from)); } +template<> EIGEN_STRONG_INLINE Packet2cf ploadu(const std::complex* from) { return Packet2cf(ploadu((const float*) from)); } +template<> EIGEN_STRONG_INLINE Packet2cf ploaddup(const std::complex* from) { return pset1(*from); } + +template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet2cf& from) { pstore((float*)to, from.v); } +template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet2cf& from) { pstoreu((float*)to, from.v); } + +template<> EIGEN_DEVICE_FUNC inline Packet2cf pgather, Packet2cf>(const std::complex* from, Index stride) +{ + std::complex EIGEN_ALIGN16 af[2]; + af[0] = from[0*stride]; + af[1] = from[1*stride]; + return pload(af); +} +template<> EIGEN_DEVICE_FUNC inline void pscatter, Packet2cf>(std::complex* to, const Packet2cf& from, Index stride) +{ + std::complex EIGEN_ALIGN16 af[2]; + pstore >((std::complex *) af, from); + to[0*stride] = af[0]; + to[1*stride] = af[1]; +} + +template<> EIGEN_STRONG_INLINE Packet2cf padd(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(a.v + b.v); } +template<> EIGEN_STRONG_INLINE Packet2cf psub(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(a.v - b.v); } template<> EIGEN_STRONG_INLINE Packet2cf pnegate(const Packet2cf& a) { return Packet2cf(pnegate(a.v)); } -template<> EIGEN_STRONG_INLINE Packet2cf pconj(const Packet2cf& a) { return Packet2cf((Packet4f)vec_xor((Packet4ui)a.v, p4ui_CONJ_XOR)); } +template<> EIGEN_STRONG_INLINE Packet2cf pconj(const Packet2cf& a) { return Packet2cf(pxor(a.v, reinterpret_cast(p4ui_CONJ_XOR))); } template<> EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, const Packet2cf& b) { Packet4f v1, v2; // Permute and multiply the real parts of a and b - v1 = vec_perm(a.v, a.v, p16uc_COMPLEX_RE); + v1 = vec_perm(a.v, a.v, p16uc_PSET32_WODD); // Get the imaginary parts of a - v2 = vec_perm(a.v, a.v, p16uc_COMPLEX_IM); + v2 = vec_perm(a.v, a.v, p16uc_PSET32_WEVEN); // multiply a_re * b v1 = vec_madd(v1, b.v, p4f_ZERO); // multiply a_im * b and get the conjugate result v2 = vec_madd(v2, b.v, p4f_ZERO); - v2 = (Packet4f) vec_xor((Packet4ui)v2, p4ui_CONJ_XOR); + v2 = reinterpret_cast(pxor(v2, reinterpret_cast(p4ui_CONJ_XOR))); // permute back to a proper order - v2 = vec_perm(v2, v2, p16uc_COMPLEX_REV); + v2 = vec_perm(v2, v2, p16uc_COMPLEX32_REV); - return Packet2cf(vec_add(v1, v2)); + return Packet2cf(padd(v1, v2)); } -template<> EIGEN_STRONG_INLINE Packet2cf pand (const Packet2cf& a, const Packet2cf& b) { return Packet2cf(vec_and(a.v,b.v)); } -template<> EIGEN_STRONG_INLINE Packet2cf por (const Packet2cf& a, const Packet2cf& b) { return Packet2cf(vec_or(a.v,b.v)); } -template<> EIGEN_STRONG_INLINE Packet2cf pxor (const Packet2cf& a, const Packet2cf& b) { return Packet2cf(vec_xor(a.v,b.v)); } -template<> EIGEN_STRONG_INLINE Packet2cf pandnot(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(vec_and(a.v, vec_nor(b.v,b.v))); } +template<> EIGEN_STRONG_INLINE Packet2cf pand (const Packet2cf& a, const Packet2cf& b) { return Packet2cf(pand(a.v, b.v)); } +template<> EIGEN_STRONG_INLINE Packet2cf por (const Packet2cf& a, const Packet2cf& b) { return Packet2cf(por(a.v, b.v)); } +template<> EIGEN_STRONG_INLINE Packet2cf pxor (const Packet2cf& a, const Packet2cf& b) { return Packet2cf(pxor(a.v, b.v)); } +template<> EIGEN_STRONG_INLINE Packet2cf pandnot(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(pandnot(a.v, b.v)); } -template<> EIGEN_STRONG_INLINE Packet2cf pload (const std::complex* from) { EIGEN_DEBUG_ALIGNED_LOAD return Packet2cf(pload((const float*)from)); } -template<> EIGEN_STRONG_INLINE Packet2cf ploadu(const std::complex* from) { EIGEN_DEBUG_UNALIGNED_LOAD return Packet2cf(ploadu((const float*)from)); } - -template<> EIGEN_STRONG_INLINE Packet2cf ploaddup(const std::complex* from) -{ - return pset1(*from); -} - -template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet2cf& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((float*)to, from.v); } -template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet2cf& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((float*)to, from.v); } - -template<> EIGEN_STRONG_INLINE void prefetch >(const std::complex * addr) { vec_dstt((float *)addr, DST_CTRL(2,2,32), DST_CHAN); } +template<> EIGEN_STRONG_INLINE void prefetch >(const std::complex * addr) { EIGEN_PPC_PREFETCH(addr); } template<> EIGEN_STRONG_INLINE std::complex pfirst(const Packet2cf& a) { @@ -118,26 +137,30 @@ template<> EIGEN_STRONG_INLINE std::complex pfirst(const Pack template<> EIGEN_STRONG_INLINE Packet2cf preverse(const Packet2cf& a) { Packet4f rev_a; - rev_a = vec_perm(a.v, a.v, p16uc_COMPLEX_REV2); + rev_a = vec_perm(a.v, a.v, p16uc_COMPLEX32_REV2); return Packet2cf(rev_a); } template<> EIGEN_STRONG_INLINE std::complex predux(const Packet2cf& a) { Packet4f b; - b = (Packet4f) vec_sld(a.v, a.v, 8); - b = padd(a.v, b); - return pfirst(Packet2cf(b)); + b = vec_sld(a.v, a.v, 8); + b = padd(a.v, b); + return pfirst(Packet2cf(b)); } template<> EIGEN_STRONG_INLINE Packet2cf preduxp(const Packet2cf* vecs) { Packet4f b1, b2; - - b1 = (Packet4f) vec_sld(vecs[0].v, vecs[1].v, 8); - b2 = (Packet4f) vec_sld(vecs[1].v, vecs[0].v, 8); - b2 = (Packet4f) vec_sld(b2, b2, 8); - b2 = padd(b1, b2); +#ifdef _BIG_ENDIAN + b1 = vec_sld(vecs[0].v, vecs[1].v, 8); + b2 = vec_sld(vecs[1].v, vecs[0].v, 8); +#else + b1 = vec_sld(vecs[1].v, vecs[0].v, 8); + b2 = vec_sld(vecs[0].v, vecs[1].v, 8); +#endif + b2 = vec_sld(b2, b2, 8); + b2 = padd(b1, b2); return Packet2cf(b2); } @@ -146,10 +169,10 @@ template<> EIGEN_STRONG_INLINE std::complex predux_mul(const P { Packet4f b; Packet2cf prod; - b = (Packet4f) vec_sld(a.v, a.v, 8); - prod = pmul(a, Packet2cf(b)); + b = vec_sld(a.v, a.v, 8); + prod = pmul(a, Packet2cf(b)); - return pfirst(prod); + return pfirst(prod); } template @@ -159,7 +182,11 @@ struct palign_impl { if (Offset==1) { +#ifdef _BIG_ENDIAN first.v = vec_sld(first.v, second.v, 8); +#else + first.v = vec_sld(second.v, first.v, 8); +#endif } } }; @@ -197,21 +224,238 @@ template<> struct conj_helper } }; +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet2cf pmadd(const Packet4f& x, const Packet2cf& y, const Packet2cf& c) const + { return padd(c, pmul(x,y)); } + + EIGEN_STRONG_INLINE Packet2cf pmul(const Packet4f& x, const Packet2cf& y) const + { return Packet2cf(internal::pmul(x, y.v)); } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet2cf pmadd(const Packet2cf& x, const Packet4f& y, const Packet2cf& c) const + { return padd(c, pmul(x,y)); } + + EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& x, const Packet4f& y) const + { return Packet2cf(internal::pmul(x.v, y)); } +}; + template<> EIGEN_STRONG_INLINE Packet2cf pdiv(const Packet2cf& a, const Packet2cf& b) { // TODO optimize it for AltiVec - Packet2cf res = conj_helper().pmul(a,b); - Packet4f s = vec_madd(b.v, b.v, p4f_ZERO); - return Packet2cf(pdiv(res.v, vec_add(s,vec_perm(s, s, p16uc_COMPLEX_REV)))); + Packet2cf res = conj_helper().pmul(a, b); + Packet4f s = pmul(b.v, b.v); + return Packet2cf(pdiv(res.v, padd(s, vec_perm(s, s, p16uc_COMPLEX32_REV)))); } template<> EIGEN_STRONG_INLINE Packet2cf pcplxflip(const Packet2cf& x) { - return Packet2cf(vec_perm(x.v, x.v, p16uc_COMPLEX_REV)); + return Packet2cf(vec_perm(x.v, x.v, p16uc_COMPLEX32_REV)); +} + +EIGEN_STRONG_INLINE void ptranspose(PacketBlock& kernel) +{ + Packet4f tmp = vec_perm(kernel.packet[0].v, kernel.packet[1].v, p16uc_TRANSPOSE64_HI); + kernel.packet[1].v = vec_perm(kernel.packet[0].v, kernel.packet[1].v, p16uc_TRANSPOSE64_LO); + kernel.packet[0].v = tmp; +} + +#ifdef __VSX__ +template<> EIGEN_STRONG_INLINE Packet2cf pblend(const Selector<2>& ifPacket, const Packet2cf& thenPacket, const Packet2cf& elsePacket) { + Packet2cf result; + result.v = reinterpret_cast(pblend(ifPacket, reinterpret_cast(thenPacket.v), reinterpret_cast(elsePacket.v))); + return result; +} +#endif + +//---------- double ---------- +#ifdef __VSX__ +struct Packet1cd +{ + EIGEN_STRONG_INLINE Packet1cd() {} + EIGEN_STRONG_INLINE explicit Packet1cd(const Packet2d& a) : v(a) {} + Packet2d v; +}; + +template<> struct packet_traits > : default_packet_traits +{ + typedef Packet1cd type; + typedef Packet1cd half; + enum { + Vectorizable = 1, + AlignedOnScalar = 0, + size = 1, + HasHalfPacket = 0, + + HasAdd = 1, + HasSub = 1, + HasMul = 1, + HasDiv = 1, + HasNegate = 1, + HasAbs = 0, + HasAbs2 = 0, + HasMin = 0, + HasMax = 0, + HasSetLinear = 0 + }; +}; + +template<> struct unpacket_traits { typedef std::complex type; enum {size=1, alignment=Aligned16}; typedef Packet1cd half; }; + +template<> EIGEN_STRONG_INLINE Packet1cd pload (const std::complex* from) { return Packet1cd(pload((const double*)from)); } +template<> EIGEN_STRONG_INLINE Packet1cd ploadu(const std::complex* from) { return Packet1cd(ploadu((const double*)from)); } +template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet1cd& from) { pstore((double*)to, from.v); } +template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet1cd& from) { pstoreu((double*)to, from.v); } + +template<> EIGEN_STRONG_INLINE Packet1cd pset1(const std::complex& from) +{ /* here we really have to use unaligned loads :( */ return ploadu(&from); } + +template<> EIGEN_DEVICE_FUNC inline Packet1cd pgather, Packet1cd>(const std::complex* from, Index stride) +{ + std::complex EIGEN_ALIGN16 af[2]; + af[0] = from[0*stride]; + af[1] = from[1*stride]; + return pload(af); +} +template<> EIGEN_DEVICE_FUNC inline void pscatter, Packet1cd>(std::complex* to, const Packet1cd& from, Index stride) +{ + std::complex EIGEN_ALIGN16 af[2]; + pstore >(af, from); + to[0*stride] = af[0]; + to[1*stride] = af[1]; +} + +template<> EIGEN_STRONG_INLINE Packet1cd padd(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(a.v + b.v); } +template<> EIGEN_STRONG_INLINE Packet1cd psub(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(a.v - b.v); } +template<> EIGEN_STRONG_INLINE Packet1cd pnegate(const Packet1cd& a) { return Packet1cd(pnegate(Packet2d(a.v))); } +template<> EIGEN_STRONG_INLINE Packet1cd pconj(const Packet1cd& a) { return Packet1cd(pxor(a.v, reinterpret_cast(p2ul_CONJ_XOR2))); } + +template<> EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) +{ + Packet2d a_re, a_im, v1, v2; + + // Permute and multiply the real parts of a and b + a_re = vec_perm(a.v, a.v, p16uc_PSET64_HI); + // Get the imaginary parts of a + a_im = vec_perm(a.v, a.v, p16uc_PSET64_LO); + // multiply a_re * b + v1 = vec_madd(a_re, b.v, p2d_ZERO); + // multiply a_im * b and get the conjugate result + v2 = vec_madd(a_im, b.v, p2d_ZERO); + v2 = reinterpret_cast(vec_sld(reinterpret_cast(v2), reinterpret_cast(v2), 8)); + v2 = pxor(v2, reinterpret_cast(p2ul_CONJ_XOR1)); + + return Packet1cd(padd(v1, v2)); +} + +template<> EIGEN_STRONG_INLINE Packet1cd pand (const Packet1cd& a, const Packet1cd& b) { return Packet1cd(pand(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd por (const Packet1cd& a, const Packet1cd& b) { return Packet1cd(por(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd pxor (const Packet1cd& a, const Packet1cd& b) { return Packet1cd(pxor(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd pandnot(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(pandnot(a.v, b.v)); } + +template<> EIGEN_STRONG_INLINE Packet1cd ploaddup(const std::complex* from) { return pset1(*from); } + +template<> EIGEN_STRONG_INLINE void prefetch >(const std::complex * addr) { EIGEN_PPC_PREFETCH(addr); } + +template<> EIGEN_STRONG_INLINE std::complex pfirst(const Packet1cd& a) +{ + std::complex EIGEN_ALIGN16 res[2]; + pstore >(res, a); + + return res[0]; +} + +template<> EIGEN_STRONG_INLINE Packet1cd preverse(const Packet1cd& a) { return a; } + +template<> EIGEN_STRONG_INLINE std::complex predux(const Packet1cd& a) { return pfirst(a); } +template<> EIGEN_STRONG_INLINE Packet1cd preduxp(const Packet1cd* vecs) { return vecs[0]; } + +template<> EIGEN_STRONG_INLINE std::complex predux_mul(const Packet1cd& a) { return pfirst(a); } + +template +struct palign_impl +{ + static EIGEN_STRONG_INLINE void run(Packet1cd& /*first*/, const Packet1cd& /*second*/) + { + // FIXME is it sure we never have to align a Packet1cd? + // Even though a std::complex has 16 bytes, it is not necessarily aligned on a 16 bytes boundary... + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet1cd& y, const Packet1cd& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) const + { + return internal::pmul(a, pconj(b)); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet1cd& y, const Packet1cd& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) const + { + return internal::pmul(pconj(a), b); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet1cd& y, const Packet1cd& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) const + { + return pconj(internal::pmul(a, b)); + } +}; +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet2d& x, const Packet1cd& y, const Packet1cd& c) const + { return padd(c, pmul(x,y)); } + + EIGEN_STRONG_INLINE Packet1cd pmul(const Packet2d& x, const Packet1cd& y) const + { return Packet1cd(internal::pmul(x, y.v)); } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet2d& y, const Packet1cd& c) const + { return padd(c, pmul(x,y)); } + + EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& x, const Packet2d& y) const + { return Packet1cd(internal::pmul(x.v, y)); } +}; + +template<> EIGEN_STRONG_INLINE Packet1cd pdiv(const Packet1cd& a, const Packet1cd& b) +{ + // TODO optimize it for AltiVec + Packet1cd res = conj_helper().pmul(a,b); + Packet2d s = pmul(b.v, b.v); + return Packet1cd(pdiv(res.v, padd(s, vec_perm(s, s, p16uc_REVERSE64)))); } +EIGEN_STRONG_INLINE Packet1cd pcplxflip/**/(const Packet1cd& x) +{ + return Packet1cd(preverse(Packet2d(x.v))); +} + +EIGEN_STRONG_INLINE void ptranspose(PacketBlock& kernel) +{ + Packet2d tmp = vec_perm(kernel.packet[0].v, kernel.packet[1].v, p16uc_TRANSPOSE64_HI); + kernel.packet[1].v = vec_perm(kernel.packet[0].v, kernel.packet[1].v, p16uc_TRANSPOSE64_LO); + kernel.packet[0].v = tmp; +} +#endif // __VSX__ } // end namespace internal } // end namespace Eigen -#endif // EIGEN_COMPLEX_ALTIVEC_H +#endif // EIGEN_COMPLEX32_ALTIVEC_H diff --git a/libs/eigen3/Eigen/src/Core/arch/AltiVec/MathFunctions.h b/libs/eigen3/Eigen/src/Core/arch/AltiVec/MathFunctions.h new file mode 100644 index 000000000..c5e4bede7 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/arch/AltiVec/MathFunctions.h @@ -0,0 +1,322 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2007 Julien Pommier +// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2016 Konstantinos Margaritis +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +/* The sin, cos, exp, and log functions of this file come from + * Julien Pommier's sse math library: http://gruntthepeon.free.fr/ssemath/ + */ + +#ifndef EIGEN_MATH_FUNCTIONS_ALTIVEC_H +#define EIGEN_MATH_FUNCTIONS_ALTIVEC_H + +namespace Eigen { + +namespace internal { + +static _EIGEN_DECLARE_CONST_Packet4f(1 , 1.0f); +static _EIGEN_DECLARE_CONST_Packet4f(half, 0.5f); +static _EIGEN_DECLARE_CONST_Packet4i(0x7f, 0x7f); +static _EIGEN_DECLARE_CONST_Packet4i(23, 23); + +static _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(inv_mant_mask, ~0x7f800000); + +/* the smallest non denormalized float number */ +static _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(min_norm_pos, 0x00800000); +static _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(minus_inf, 0xff800000); // -1.f/0.f +static _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(minus_nan, 0xffffffff); + +/* natural logarithm computed for 4 simultaneous float + return NaN for x <= 0 +*/ +static _EIGEN_DECLARE_CONST_Packet4f(cephes_SQRTHF, 0.707106781186547524f); +static _EIGEN_DECLARE_CONST_Packet4f(cephes_log_p0, 7.0376836292E-2f); +static _EIGEN_DECLARE_CONST_Packet4f(cephes_log_p1, - 1.1514610310E-1f); +static _EIGEN_DECLARE_CONST_Packet4f(cephes_log_p2, 1.1676998740E-1f); +static _EIGEN_DECLARE_CONST_Packet4f(cephes_log_p3, - 1.2420140846E-1f); +static _EIGEN_DECLARE_CONST_Packet4f(cephes_log_p4, + 1.4249322787E-1f); +static _EIGEN_DECLARE_CONST_Packet4f(cephes_log_p5, - 1.6668057665E-1f); +static _EIGEN_DECLARE_CONST_Packet4f(cephes_log_p6, + 2.0000714765E-1f); +static _EIGEN_DECLARE_CONST_Packet4f(cephes_log_p7, - 2.4999993993E-1f); +static _EIGEN_DECLARE_CONST_Packet4f(cephes_log_p8, + 3.3333331174E-1f); +static _EIGEN_DECLARE_CONST_Packet4f(cephes_log_q1, -2.12194440e-4f); +static _EIGEN_DECLARE_CONST_Packet4f(cephes_log_q2, 0.693359375f); + +static _EIGEN_DECLARE_CONST_Packet4f(exp_hi, 88.3762626647950f); +static _EIGEN_DECLARE_CONST_Packet4f(exp_lo, -88.3762626647949f); + +static _EIGEN_DECLARE_CONST_Packet4f(cephes_LOG2EF, 1.44269504088896341f); +static _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_C1, 0.693359375f); +static _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_C2, -2.12194440e-4f); + +static _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p0, 1.9875691500E-4f); +static _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p1, 1.3981999507E-3f); +static _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p2, 8.3334519073E-3f); +static _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p3, 4.1665795894E-2f); +static _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p4, 1.6666665459E-1f); +static _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p5, 5.0000001201E-1f); + +#ifdef __VSX__ +static _EIGEN_DECLARE_CONST_Packet2d(1 , 1.0); +static _EIGEN_DECLARE_CONST_Packet2d(2 , 2.0); +static _EIGEN_DECLARE_CONST_Packet2d(half, 0.5); + +static _EIGEN_DECLARE_CONST_Packet2d(exp_hi, 709.437); +static _EIGEN_DECLARE_CONST_Packet2d(exp_lo, -709.436139303); + +static _EIGEN_DECLARE_CONST_Packet2d(cephes_LOG2EF, 1.4426950408889634073599); + +static _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_p0, 1.26177193074810590878e-4); +static _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_p1, 3.02994407707441961300e-2); +static _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_p2, 9.99999999999999999910e-1); + +static _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_q0, 3.00198505138664455042e-6); +static _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_q1, 2.52448340349684104192e-3); +static _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_q2, 2.27265548208155028766e-1); +static _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_q3, 2.00000000000000000009e0); + +static _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_C1, 0.693145751953125); +static _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_C2, 1.42860682030941723212e-6); + +#ifdef __POWER8_VECTOR__ +static Packet2l p2l_1023 = { 1023, 1023 }; +static Packet2ul p2ul_52 = { 52, 52 }; +#endif + +#endif + +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet4f plog(const Packet4f& _x) +{ + Packet4f x = _x; + + Packet4i emm0; + + /* isvalid_mask is 0 if x < 0 or x is NaN. */ + Packet4ui isvalid_mask = reinterpret_cast(vec_cmpge(x, p4f_ZERO)); + Packet4ui iszero_mask = reinterpret_cast(vec_cmpeq(x, p4f_ZERO)); + + x = pmax(x, p4f_min_norm_pos); /* cut off denormalized stuff */ + emm0 = vec_sr(reinterpret_cast(x), + reinterpret_cast(p4i_23)); + + /* keep only the fractional part */ + x = pand(x, p4f_inv_mant_mask); + x = por(x, p4f_half); + + emm0 = psub(emm0, p4i_0x7f); + Packet4f e = padd(vec_ctf(emm0, 0), p4f_1); + + /* part2: + if( x < SQRTHF ) { + e -= 1; + x = x + x - 1.0; + } else { x = x - 1.0; } + */ + Packet4f mask = reinterpret_cast(vec_cmplt(x, p4f_cephes_SQRTHF)); + Packet4f tmp = pand(x, mask); + x = psub(x, p4f_1); + e = psub(e, pand(p4f_1, mask)); + x = padd(x, tmp); + + Packet4f x2 = pmul(x,x); + Packet4f x3 = pmul(x2,x); + + Packet4f y, y1, y2; + y = pmadd(p4f_cephes_log_p0, x, p4f_cephes_log_p1); + y1 = pmadd(p4f_cephes_log_p3, x, p4f_cephes_log_p4); + y2 = pmadd(p4f_cephes_log_p6, x, p4f_cephes_log_p7); + y = pmadd(y , x, p4f_cephes_log_p2); + y1 = pmadd(y1, x, p4f_cephes_log_p5); + y2 = pmadd(y2, x, p4f_cephes_log_p8); + y = pmadd(y, x3, y1); + y = pmadd(y, x3, y2); + y = pmul(y, x3); + + y1 = pmul(e, p4f_cephes_log_q1); + tmp = pmul(x2, p4f_half); + y = padd(y, y1); + x = psub(x, tmp); + y2 = pmul(e, p4f_cephes_log_q2); + x = padd(x, y); + x = padd(x, y2); + // negative arg will be NAN, 0 will be -INF + x = vec_sel(x, p4f_minus_inf, iszero_mask); + x = vec_sel(p4f_minus_nan, x, isvalid_mask); + return x; +} + +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet4f pexp(const Packet4f& _x) +{ + Packet4f x = _x; + + Packet4f tmp, fx; + Packet4i emm0; + + // clamp x + x = pmax(pmin(x, p4f_exp_hi), p4f_exp_lo); + + // express exp(x) as exp(g + n*log(2)) + fx = pmadd(x, p4f_cephes_LOG2EF, p4f_half); + + fx = pfloor(fx); + + tmp = pmul(fx, p4f_cephes_exp_C1); + Packet4f z = pmul(fx, p4f_cephes_exp_C2); + x = psub(x, tmp); + x = psub(x, z); + + z = pmul(x,x); + + Packet4f y = p4f_cephes_exp_p0; + y = pmadd(y, x, p4f_cephes_exp_p1); + y = pmadd(y, x, p4f_cephes_exp_p2); + y = pmadd(y, x, p4f_cephes_exp_p3); + y = pmadd(y, x, p4f_cephes_exp_p4); + y = pmadd(y, x, p4f_cephes_exp_p5); + y = pmadd(y, z, x); + y = padd(y, p4f_1); + + // build 2^n + emm0 = vec_cts(fx, 0); + emm0 = vec_add(emm0, p4i_0x7f); + emm0 = vec_sl(emm0, reinterpret_cast(p4i_23)); + + // Altivec's max & min operators just drop silent NaNs. Check NaNs in + // inputs and return them unmodified. + Packet4ui isnumber_mask = reinterpret_cast(vec_cmpeq(_x, _x)); + return vec_sel(_x, pmax(pmul(y, reinterpret_cast(emm0)), _x), + isnumber_mask); +} + +#ifndef EIGEN_COMP_CLANG +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet4f prsqrt(const Packet4f& x) +{ + return vec_rsqrt(x); +} +#endif + +#ifdef __VSX__ +#ifndef EIGEN_COMP_CLANG +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet2d prsqrt(const Packet2d& x) +{ + return vec_rsqrt(x); +} +#endif + +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet4f psqrt(const Packet4f& x) +{ + return vec_sqrt(x); +} + +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet2d psqrt(const Packet2d& x) +{ + return vec_sqrt(x); +} + +// VSX support varies between different compilers and even different +// versions of the same compiler. For gcc version >= 4.9.3, we can use +// vec_cts to efficiently convert Packet2d to Packet2l. Otherwise, use +// a slow version that works with older compilers. +// Update: apparently vec_cts/vec_ctf intrinsics for 64-bit doubles +// are buggy, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70963 +static inline Packet2l ConvertToPacket2l(const Packet2d& x) { +#if EIGEN_GNUC_AT_LEAST(5, 4) || \ + (EIGEN_GNUC_AT(6, 1) && __GNUC_PATCHLEVEL__ >= 1) + return vec_cts(x, 0); // TODO: check clang version. +#else + double tmp[2]; + memcpy(tmp, &x, sizeof(tmp)); + Packet2l l = { static_cast(tmp[0]), + static_cast(tmp[1]) }; + return l; +#endif +} + +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet2d pexp(const Packet2d& _x) +{ + Packet2d x = _x; + + Packet2d tmp, fx; + Packet2l emm0; + + // clamp x + x = pmax(pmin(x, p2d_exp_hi), p2d_exp_lo); + + /* express exp(x) as exp(g + n*log(2)) */ + fx = pmadd(x, p2d_cephes_LOG2EF, p2d_half); + + fx = pfloor(fx); + + tmp = pmul(fx, p2d_cephes_exp_C1); + Packet2d z = pmul(fx, p2d_cephes_exp_C2); + x = psub(x, tmp); + x = psub(x, z); + + Packet2d x2 = pmul(x,x); + + Packet2d px = p2d_cephes_exp_p0; + px = pmadd(px, x2, p2d_cephes_exp_p1); + px = pmadd(px, x2, p2d_cephes_exp_p2); + px = pmul (px, x); + + Packet2d qx = p2d_cephes_exp_q0; + qx = pmadd(qx, x2, p2d_cephes_exp_q1); + qx = pmadd(qx, x2, p2d_cephes_exp_q2); + qx = pmadd(qx, x2, p2d_cephes_exp_q3); + + x = pdiv(px,psub(qx,px)); + x = pmadd(p2d_2,x,p2d_1); + + // build 2^n + emm0 = ConvertToPacket2l(fx); + +#ifdef __POWER8_VECTOR__ + emm0 = vec_add(emm0, p2l_1023); + emm0 = vec_sl(emm0, p2ul_52); +#else + // Code is a bit complex for POWER7. There is actually a + // vec_xxsldi intrinsic but it is not supported by some gcc versions. + // So we shift (52-32) bits and do a word swap with zeros. + _EIGEN_DECLARE_CONST_Packet4i(1023, 1023); + _EIGEN_DECLARE_CONST_Packet4i(20, 20); // 52 - 32 + + Packet4i emm04i = reinterpret_cast(emm0); + emm04i = vec_add(emm04i, p4i_1023); + emm04i = vec_sl(emm04i, reinterpret_cast(p4i_20)); + static const Packet16uc perm = { + 0x14, 0x15, 0x16, 0x17, 0x00, 0x01, 0x02, 0x03, + 0x1c, 0x1d, 0x1e, 0x1f, 0x08, 0x09, 0x0a, 0x0b }; +#ifdef _BIG_ENDIAN + emm0 = reinterpret_cast(vec_perm(p4i_ZERO, emm04i, perm)); +#else + emm0 = reinterpret_cast(vec_perm(emm04i, p4i_ZERO, perm)); +#endif + +#endif + + // Altivec's max & min operators just drop silent NaNs. Check NaNs in + // inputs and return them unmodified. + Packet2ul isnumber_mask = reinterpret_cast(vec_cmpeq(_x, _x)); + return vec_sel(_x, pmax(pmul(x, reinterpret_cast(emm0)), _x), + isnumber_mask); +} +#endif + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_MATH_FUNCTIONS_ALTIVEC_H diff --git a/libs/eigen3/Eigen/src/Core/arch/AltiVec/PacketMath.h b/libs/eigen3/Eigen/src/Core/arch/AltiVec/PacketMath.h old mode 100644 new mode 100755 index e4089962d..b3f1ea199 --- a/libs/eigen3/Eigen/src/Core/arch/AltiVec/PacketMath.h +++ b/libs/eigen3/Eigen/src/Core/arch/AltiVec/PacketMath.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Konstantinos Margaritis +// Copyright (C) 2008-2016 Konstantinos Margaritis // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -18,13 +18,17 @@ namespace internal { #define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 4 #endif -#ifndef EIGEN_HAS_FUSE_CJMADD -#define EIGEN_HAS_FUSE_CJMADD 1 +#ifndef EIGEN_HAS_SINGLE_INSTRUCTION_MADD +#define EIGEN_HAS_SINGLE_INSTRUCTION_MADD +#endif + +#ifndef EIGEN_HAS_SINGLE_INSTRUCTION_CJMADD +#define EIGEN_HAS_SINGLE_INSTRUCTION_CJMADD #endif // NOTE Altivec has 32 registers, but Eigen only accepts a value of 8 or 16 #ifndef EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS -#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 16 +#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 32 #endif typedef __vector float Packet4f; @@ -38,7 +42,7 @@ typedef __vector unsigned char Packet16uc; // and it doesn't really work to declare them global, so we define macros instead #define _EIGEN_DECLARE_CONST_FAST_Packet4f(NAME,X) \ - Packet4f p4f_##NAME = (Packet4f) vec_splat_s32(X) + Packet4f p4f_##NAME = reinterpret_cast(vec_splat_s32(X)) #define _EIGEN_DECLARE_CONST_FAST_Packet4i(NAME,X) \ Packet4i p4i_##NAME = vec_splat_s32(X) @@ -46,60 +50,158 @@ typedef __vector unsigned char Packet16uc; #define _EIGEN_DECLARE_CONST_Packet4f(NAME,X) \ Packet4f p4f_##NAME = pset1(X) -#define _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(NAME,X) \ - Packet4f p4f_##NAME = vreinterpretq_f32_u32(pset1(X)) - #define _EIGEN_DECLARE_CONST_Packet4i(NAME,X) \ Packet4i p4i_##NAME = pset1(X) +#define _EIGEN_DECLARE_CONST_Packet2d(NAME,X) \ + Packet2d p2d_##NAME = pset1(X) + +#define _EIGEN_DECLARE_CONST_Packet2l(NAME,X) \ + Packet2l p2l_##NAME = pset1(X) + +#define _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(NAME,X) \ + const Packet4f p4f_##NAME = reinterpret_cast(pset1(X)) + #define DST_CHAN 1 #define DST_CTRL(size, count, stride) (((size) << 24) | ((count) << 16) | (stride)) + +// These constants are endian-agnostic +static _EIGEN_DECLARE_CONST_FAST_Packet4f(ZERO, 0); //{ 0.0, 0.0, 0.0, 0.0} +static _EIGEN_DECLARE_CONST_FAST_Packet4i(ZERO, 0); //{ 0, 0, 0, 0,} +static _EIGEN_DECLARE_CONST_FAST_Packet4i(ONE,1); //{ 1, 1, 1, 1} +static _EIGEN_DECLARE_CONST_FAST_Packet4i(MINUS16,-16); //{ -16, -16, -16, -16} +static _EIGEN_DECLARE_CONST_FAST_Packet4i(MINUS1,-1); //{ -1, -1, -1, -1} +static Packet4f p4f_MZERO = (Packet4f) vec_sl((Packet4ui)p4i_MINUS1, (Packet4ui)p4i_MINUS1); //{ 0x80000000, 0x80000000, 0x80000000, 0x80000000} +#ifndef __VSX__ +static Packet4f p4f_ONE = vec_ctf(p4i_ONE, 0); //{ 1.0, 1.0, 1.0, 1.0} +#endif + +static Packet4f p4f_COUNTDOWN = { 0.0, 1.0, 2.0, 3.0 }; +static Packet4i p4i_COUNTDOWN = { 0, 1, 2, 3 }; + +static Packet16uc p16uc_REVERSE32 = { 12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3 }; +static Packet16uc p16uc_DUPLICATE32_HI = { 0,1,2,3, 0,1,2,3, 4,5,6,7, 4,5,6,7 }; + +// Mask alignment +#ifdef __PPC64__ +#define _EIGEN_MASK_ALIGNMENT 0xfffffffffffffff0 +#else +#define _EIGEN_MASK_ALIGNMENT 0xfffffff0 +#endif + +#define _EIGEN_ALIGNED_PTR(x) ((std::ptrdiff_t)(x) & _EIGEN_MASK_ALIGNMENT) + +// Handle endianness properly while loading constants // Define global static constants: -static Packet4f p4f_COUNTDOWN = { 3.0, 2.0, 1.0, 0.0 }; -static Packet4i p4i_COUNTDOWN = { 3, 2, 1, 0 }; -static Packet16uc p16uc_REVERSE = {12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3}; +#ifdef _BIG_ENDIAN static Packet16uc p16uc_FORWARD = vec_lvsl(0, (float*)0); -static Packet16uc p16uc_DUPLICATE = {0,1,2,3, 0,1,2,3, 4,5,6,7, 4,5,6,7}; - -static _EIGEN_DECLARE_CONST_FAST_Packet4f(ZERO, 0); -static _EIGEN_DECLARE_CONST_FAST_Packet4i(ZERO, 0); -static _EIGEN_DECLARE_CONST_FAST_Packet4i(ONE,1); -static _EIGEN_DECLARE_CONST_FAST_Packet4i(MINUS16,-16); -static _EIGEN_DECLARE_CONST_FAST_Packet4i(MINUS1,-1); -static Packet4f p4f_ONE = vec_ctf(p4i_ONE, 0); -static Packet4f p4f_ZERO_ = (Packet4f) vec_sl((Packet4ui)p4i_MINUS1, (Packet4ui)p4i_MINUS1); +#ifdef __VSX__ +static Packet16uc p16uc_REVERSE64 = { 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; +#endif +static Packet16uc p16uc_PSET32_WODD = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 0), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 2), 8);//{ 0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11 }; +static Packet16uc p16uc_PSET32_WEVEN = vec_sld(p16uc_DUPLICATE32_HI, (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 3), 8);//{ 4,5,6,7, 4,5,6,7, 12,13,14,15, 12,13,14,15 }; +static Packet16uc p16uc_HALF64_0_16 = vec_sld((Packet16uc)p4i_ZERO, vec_splat((Packet16uc) vec_abs(p4i_MINUS16), 3), 8); //{ 0,0,0,0, 0,0,0,0, 16,16,16,16, 16,16,16,16}; +#else +static Packet16uc p16uc_FORWARD = p16uc_REVERSE32; +static Packet16uc p16uc_REVERSE64 = { 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; +static Packet16uc p16uc_PSET32_WODD = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 1), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 3), 8);//{ 0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11 }; +static Packet16uc p16uc_PSET32_WEVEN = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 0), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 2), 8);//{ 4,5,6,7, 4,5,6,7, 12,13,14,15, 12,13,14,15 }; +static Packet16uc p16uc_HALF64_0_16 = vec_sld(vec_splat((Packet16uc) vec_abs(p4i_MINUS16), 0), (Packet16uc)p4i_ZERO, 8); //{ 0,0,0,0, 0,0,0,0, 16,16,16,16, 16,16,16,16}; +#endif // _BIG_ENDIAN + +static Packet16uc p16uc_PSET64_HI = (Packet16uc) vec_mergeh((Packet4ui)p16uc_PSET32_WODD, (Packet4ui)p16uc_PSET32_WEVEN); //{ 0,1,2,3, 4,5,6,7, 0,1,2,3, 4,5,6,7 }; +static Packet16uc p16uc_PSET64_LO = (Packet16uc) vec_mergel((Packet4ui)p16uc_PSET32_WODD, (Packet4ui)p16uc_PSET32_WEVEN); //{ 8,9,10,11, 12,13,14,15, 8,9,10,11, 12,13,14,15 }; +static Packet16uc p16uc_TRANSPOSE64_HI = p16uc_PSET64_HI + p16uc_HALF64_0_16; //{ 0,1,2,3, 4,5,6,7, 16,17,18,19, 20,21,22,23}; +static Packet16uc p16uc_TRANSPOSE64_LO = p16uc_PSET64_LO + p16uc_HALF64_0_16; //{ 8,9,10,11, 12,13,14,15, 24,25,26,27, 28,29,30,31}; + +static Packet16uc p16uc_COMPLEX32_REV = vec_sld(p16uc_REVERSE32, p16uc_REVERSE32, 8); //{ 4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11 }; + +#ifdef _BIG_ENDIAN +static Packet16uc p16uc_COMPLEX32_REV2 = vec_sld(p16uc_FORWARD, p16uc_FORWARD, 8); //{ 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; +#else +static Packet16uc p16uc_COMPLEX32_REV2 = vec_sld(p16uc_PSET64_HI, p16uc_PSET64_LO, 8); //{ 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; +#endif // _BIG_ENDIAN + +#if EIGEN_HAS_BUILTIN(__builtin_prefetch) || EIGEN_COMP_GNUC + #define EIGEN_PPC_PREFETCH(ADDR) __builtin_prefetch(ADDR); +#else + #define EIGEN_PPC_PREFETCH(ADDR) asm( " dcbt [%[addr]]\n" :: [addr] "r" (ADDR) : "cc" ); +#endif template<> struct packet_traits : default_packet_traits { typedef Packet4f type; + typedef Packet4f half; enum { Vectorizable = 1, AlignedOnScalar = 1, size=4, - - // FIXME check the Has* + HasHalfPacket = 1, + + HasAdd = 1, + HasSub = 1, + HasMul = 1, + HasDiv = 1, + HasMin = 1, + HasMax = 1, + HasAbs = 1, HasSin = 0, HasCos = 0, HasLog = 0, - HasExp = 0, - HasSqrt = 0 + HasExp = 1, +#ifdef __VSX__ + HasSqrt = 1, +#if !EIGEN_COMP_CLANG + HasRsqrt = 1, +#else + HasRsqrt = 0, +#endif +#else + HasSqrt = 0, + HasRsqrt = 0, +#endif + HasRound = 1, + HasFloor = 1, + HasCeil = 1, + HasNegate = 1, + HasBlend = 1 }; }; template<> struct packet_traits : default_packet_traits { typedef Packet4i type; + typedef Packet4i half; enum { - // FIXME check the Has* Vectorizable = 1, AlignedOnScalar = 1, - size=4 + size = 4, + HasHalfPacket = 0, + + HasAdd = 1, + HasSub = 1, + HasMul = 1, + HasDiv = 0, + HasBlend = 1 }; }; -template<> struct unpacket_traits { typedef float type; enum {size=4}; }; -template<> struct unpacket_traits { typedef int type; enum {size=4}; }; -/* + +template<> struct unpacket_traits { typedef float type; enum {size=4, alignment=Aligned16}; typedef Packet4f half; }; +template<> struct unpacket_traits { typedef int type; enum {size=4, alignment=Aligned16}; typedef Packet4i half; }; + +inline std::ostream & operator <<(std::ostream & s, const Packet16uc & v) +{ + union { + Packet16uc v; + unsigned char n[16]; + } vt; + vt.v = v; + for (int i=0; i< 16; i++) + s << (int)vt.n[i] << ", "; + return s; +} + inline std::ostream & operator <<(std::ostream & s, const Packet4f & v) { union { @@ -133,89 +235,136 @@ inline std::ostream & operator <<(std::ostream & s, const Packet4ui & v) return s; } -inline std::ostream & operator <<(std::ostream & s, const Packetbi & v) +// Need to define them first or we get specialization after instantiation errors +template<> EIGEN_STRONG_INLINE Packet4f pload(const float* from) { - union { - Packet4bi v; - unsigned int n[4]; - } vt; - vt.v = v; - s << vt.n[0] << ", " << vt.n[1] << ", " << vt.n[2] << ", " << vt.n[3]; - return s; -} -*/ -template<> EIGEN_STRONG_INLINE Packet4f pset1(const float& from) { - // Taken from http://developer.apple.com/hardwaredrivers/ve/alignment.html - float EIGEN_ALIGN16 af[4]; - af[0] = from; - Packet4f vc = vec_ld(0, af); - vc = vec_splat(vc, 0); - return vc; + EIGEN_DEBUG_ALIGNED_LOAD +#ifdef __VSX__ + return vec_vsx_ld(0, from); +#else + return vec_ld(0, from); +#endif } -template<> EIGEN_STRONG_INLINE Packet4i pset1(const int& from) { - int EIGEN_ALIGN16 ai[4]; - ai[0] = from; - Packet4i vc = vec_ld(0, ai); - vc = vec_splat(vc, 0); - return vc; +template<> EIGEN_STRONG_INLINE Packet4i pload(const int* from) +{ + EIGEN_DEBUG_ALIGNED_LOAD +#ifdef __VSX__ + return vec_vsx_ld(0, from); +#else + return vec_ld(0, from); +#endif } -template<> EIGEN_STRONG_INLINE Packet4f plset(const float& a) { return vec_add(pset1(a), p4f_COUNTDOWN); } -template<> EIGEN_STRONG_INLINE Packet4i plset(const int& a) { return vec_add(pset1(a), p4i_COUNTDOWN); } - -template<> EIGEN_STRONG_INLINE Packet4f padd(const Packet4f& a, const Packet4f& b) { return vec_add(a,b); } -template<> EIGEN_STRONG_INLINE Packet4i padd(const Packet4i& a, const Packet4i& b) { return vec_add(a,b); } +template<> EIGEN_STRONG_INLINE void pstore(float* to, const Packet4f& from) +{ + EIGEN_DEBUG_ALIGNED_STORE +#ifdef __VSX__ + vec_vsx_st(from, 0, to); +#else + vec_st(from, 0, to); +#endif +} -template<> EIGEN_STRONG_INLINE Packet4f psub(const Packet4f& a, const Packet4f& b) { return vec_sub(a,b); } -template<> EIGEN_STRONG_INLINE Packet4i psub(const Packet4i& a, const Packet4i& b) { return vec_sub(a,b); } +template<> EIGEN_STRONG_INLINE void pstore(int* to, const Packet4i& from) +{ + EIGEN_DEBUG_ALIGNED_STORE +#ifdef __VSX__ + vec_vsx_st(from, 0, to); +#else + vec_st(from, 0, to); +#endif +} -template<> EIGEN_STRONG_INLINE Packet4f pnegate(const Packet4f& a) { return psub(p4f_ZERO, a); } -template<> EIGEN_STRONG_INLINE Packet4i pnegate(const Packet4i& a) { return psub(p4i_ZERO, a); } +template<> EIGEN_STRONG_INLINE Packet4f pset1(const float& from) { + Packet4f v = {from, from, from, from}; + return v; +} -template<> EIGEN_STRONG_INLINE Packet4f pconj(const Packet4f& a) { return a; } -template<> EIGEN_STRONG_INLINE Packet4i pconj(const Packet4i& a) { return a; } +template<> EIGEN_STRONG_INLINE Packet4i pset1(const int& from) { + Packet4i v = {from, from, from, from}; + return v; +} +template<> EIGEN_STRONG_INLINE void +pbroadcast4(const float *a, + Packet4f& a0, Packet4f& a1, Packet4f& a2, Packet4f& a3) +{ + a3 = pload(a); + a0 = vec_splat(a3, 0); + a1 = vec_splat(a3, 1); + a2 = vec_splat(a3, 2); + a3 = vec_splat(a3, 3); +} +template<> EIGEN_STRONG_INLINE void +pbroadcast4(const int *a, + Packet4i& a0, Packet4i& a1, Packet4i& a2, Packet4i& a3) +{ + a3 = pload(a); + a0 = vec_splat(a3, 0); + a1 = vec_splat(a3, 1); + a2 = vec_splat(a3, 2); + a3 = vec_splat(a3, 3); +} -template<> EIGEN_STRONG_INLINE Packet4f pmul(const Packet4f& a, const Packet4f& b) { return vec_madd(a,b,p4f_ZERO); } -/* Commented out: it's actually slower than processing it scalar - * -template<> EIGEN_STRONG_INLINE Packet4i pmul(const Packet4i& a, const Packet4i& b) +template<> EIGEN_DEVICE_FUNC inline Packet4f pgather(const float* from, Index stride) +{ + float EIGEN_ALIGN16 af[4]; + af[0] = from[0*stride]; + af[1] = from[1*stride]; + af[2] = from[2*stride]; + af[3] = from[3*stride]; + return pload(af); +} +template<> EIGEN_DEVICE_FUNC inline Packet4i pgather(const int* from, Index stride) +{ + int EIGEN_ALIGN16 ai[4]; + ai[0] = from[0*stride]; + ai[1] = from[1*stride]; + ai[2] = from[2*stride]; + ai[3] = from[3*stride]; + return pload(ai); +} +template<> EIGEN_DEVICE_FUNC inline void pscatter(float* to, const Packet4f& from, Index stride) { - // Detailed in: http://freevec.org/content/32bit_signed_integer_multiplication_altivec - //Set up constants, variables - Packet4i a1, b1, bswap, low_prod, high_prod, prod, prod_, v1sel; + float EIGEN_ALIGN16 af[4]; + pstore(af, from); + to[0*stride] = af[0]; + to[1*stride] = af[1]; + to[2*stride] = af[2]; + to[3*stride] = af[3]; +} +template<> EIGEN_DEVICE_FUNC inline void pscatter(int* to, const Packet4i& from, Index stride) +{ + int EIGEN_ALIGN16 ai[4]; + pstore((int *)ai, from); + to[0*stride] = ai[0]; + to[1*stride] = ai[1]; + to[2*stride] = ai[2]; + to[3*stride] = ai[3]; +} - // Get the absolute values - a1 = vec_abs(a); - b1 = vec_abs(b); +template<> EIGEN_STRONG_INLINE Packet4f plset(const float& a) { return pset1(a) + p4f_COUNTDOWN; } +template<> EIGEN_STRONG_INLINE Packet4i plset(const int& a) { return pset1(a) + p4i_COUNTDOWN; } - // Get the signs using xor - Packet4bi sgn = (Packet4bi) vec_cmplt(vec_xor(a, b), p4i_ZERO); +template<> EIGEN_STRONG_INLINE Packet4f padd(const Packet4f& a, const Packet4f& b) { return a + b; } +template<> EIGEN_STRONG_INLINE Packet4i padd(const Packet4i& a, const Packet4i& b) { return a + b; } - // Do the multiplication for the asbolute values. - bswap = (Packet4i) vec_rl((Packet4ui) b1, (Packet4ui) p4i_MINUS16 ); - low_prod = vec_mulo((Packet8i) a1, (Packet8i)b1); - high_prod = vec_msum((Packet8i) a1, (Packet8i) bswap, p4i_ZERO); - high_prod = (Packet4i) vec_sl((Packet4ui) high_prod, (Packet4ui) p4i_MINUS16); - prod = vec_add( low_prod, high_prod ); +template<> EIGEN_STRONG_INLINE Packet4f psub(const Packet4f& a, const Packet4f& b) { return a - b; } +template<> EIGEN_STRONG_INLINE Packet4i psub(const Packet4i& a, const Packet4i& b) { return a - b; } - // NOR the product and select only the negative elements according to the sign mask - prod_ = vec_nor(prod, prod); - prod_ = vec_sel(p4i_ZERO, prod_, sgn); +template<> EIGEN_STRONG_INLINE Packet4f pnegate(const Packet4f& a) { return p4f_ZERO - a; } +template<> EIGEN_STRONG_INLINE Packet4i pnegate(const Packet4i& a) { return p4i_ZERO - a; } - // Add 1 to the result to get the negative numbers - v1sel = vec_sel(p4i_ZERO, p4i_ONE, sgn); - prod_ = vec_add(prod_, v1sel); +template<> EIGEN_STRONG_INLINE Packet4f pconj(const Packet4f& a) { return a; } +template<> EIGEN_STRONG_INLINE Packet4i pconj(const Packet4i& a) { return a; } - // Merge the results back to the final vector. - prod = vec_sel(prod, prod_, sgn); +template<> EIGEN_STRONG_INLINE Packet4f pmul(const Packet4f& a, const Packet4f& b) { return vec_madd(a,b, p4f_MZERO); } +template<> EIGEN_STRONG_INLINE Packet4i pmul(const Packet4i& a, const Packet4i& b) { return a * b; } - return prod; -} -*/ template<> EIGEN_STRONG_INLINE Packet4f pdiv(const Packet4f& a, const Packet4f& b) { - Packet4f t, y_0, y_1, res; +#ifndef __VSX__ // VSX actually provides a div instruction + Packet4f t, y_0, y_1; // Altivec does not offer a divide instruction, we have to do a reciprocal approximation y_0 = vec_re(b); @@ -224,8 +373,10 @@ template<> EIGEN_STRONG_INLINE Packet4f pdiv(const Packet4f& a, const t = vec_nmsub(y_0, b, p4f_ONE); y_1 = vec_madd(y_0, t, y_0); - res = vec_madd(a, y_1, p4f_ZERO); - return res; + return vec_madd(a, y_1, p4f_MZERO); +#else + return vec_div(a, b); +#endif } template<> EIGEN_STRONG_INLINE Packet4i pdiv(const Packet4i& /*a*/, const Packet4i& /*b*/) @@ -234,8 +385,8 @@ template<> EIGEN_STRONG_INLINE Packet4i pdiv(const Packet4i& /*a*/, co } // for some weird raisons, it has to be overloaded for packet of integers -template<> EIGEN_STRONG_INLINE Packet4f pmadd(const Packet4f& a, const Packet4f& b, const Packet4f& c) { return vec_madd(a, b, c); } -template<> EIGEN_STRONG_INLINE Packet4i pmadd(const Packet4i& a, const Packet4i& b, const Packet4i& c) { return padd(pmul(a,b), c); } +template<> EIGEN_STRONG_INLINE Packet4f pmadd(const Packet4f& a, const Packet4f& b, const Packet4f& c) { return vec_madd(a,b,c); } +template<> EIGEN_STRONG_INLINE Packet4i pmadd(const Packet4i& a, const Packet4i& b, const Packet4i& c) { return a*b + c; } template<> EIGEN_STRONG_INLINE Packet4f pmin(const Packet4f& a, const Packet4f& b) { return vec_min(a, b); } template<> EIGEN_STRONG_INLINE Packet4i pmin(const Packet4i& a, const Packet4i& b) { return vec_min(a, b); } @@ -243,7 +394,6 @@ template<> EIGEN_STRONG_INLINE Packet4i pmin(const Packet4i& a, const template<> EIGEN_STRONG_INLINE Packet4f pmax(const Packet4f& a, const Packet4f& b) { return vec_max(a, b); } template<> EIGEN_STRONG_INLINE Packet4i pmax(const Packet4i& a, const Packet4i& b) { return vec_max(a, b); } -// Logical Operations are not supported for float, so we have to reinterpret casts using NEON intrinsics template<> EIGEN_STRONG_INLINE Packet4f pand(const Packet4f& a, const Packet4f& b) { return vec_and(a, b); } template<> EIGEN_STRONG_INLINE Packet4i pand(const Packet4i& a, const Packet4i& b) { return vec_and(a, b); } @@ -256,13 +406,14 @@ template<> EIGEN_STRONG_INLINE Packet4i pxor(const Packet4i& a, const template<> EIGEN_STRONG_INLINE Packet4f pandnot(const Packet4f& a, const Packet4f& b) { return vec_and(a, vec_nor(b, b)); } template<> EIGEN_STRONG_INLINE Packet4i pandnot(const Packet4i& a, const Packet4i& b) { return vec_and(a, vec_nor(b, b)); } -template<> EIGEN_STRONG_INLINE Packet4f pload(const float* from) { EIGEN_DEBUG_ALIGNED_LOAD return vec_ld(0, from); } -template<> EIGEN_STRONG_INLINE Packet4i pload(const int* from) { EIGEN_DEBUG_ALIGNED_LOAD return vec_ld(0, from); } +template<> EIGEN_STRONG_INLINE Packet4f pround(const Packet4f& a) { return vec_round(a); } +template<> EIGEN_STRONG_INLINE Packet4f pceil(const Packet4f& a) { return vec_ceil(a); } +template<> EIGEN_STRONG_INLINE Packet4f pfloor(const Packet4f& a) { return vec_floor(a); } +#ifdef _BIG_ENDIAN template<> EIGEN_STRONG_INLINE Packet4f ploadu(const float* from) { EIGEN_DEBUG_ALIGNED_LOAD - // Taken from http://developer.apple.com/hardwaredrivers/ve/alignment.html Packet16uc MSQ, LSQ; Packet16uc mask; MSQ = vec_ld(0, (unsigned char *)from); // most significant quadword @@ -282,25 +433,36 @@ template<> EIGEN_STRONG_INLINE Packet4i ploadu(const int* from) mask = vec_lvsl(0, from); // create the permute mask return (Packet4i) vec_perm(MSQ, LSQ, mask); // align the data } +#else +// We also need ot redefine little endian loading of Packet4i/Packet4f using VSX +template<> EIGEN_STRONG_INLINE Packet4i ploadu(const int* from) +{ + EIGEN_DEBUG_UNALIGNED_LOAD + return (Packet4i) vec_vsx_ld((long)from & 15, (const int*) _EIGEN_ALIGNED_PTR(from)); +} +template<> EIGEN_STRONG_INLINE Packet4f ploadu(const float* from) +{ + EIGEN_DEBUG_UNALIGNED_LOAD + return (Packet4f) vec_vsx_ld((long)from & 15, (const float*) _EIGEN_ALIGNED_PTR(from)); +} +#endif template<> EIGEN_STRONG_INLINE Packet4f ploaddup(const float* from) { Packet4f p; - if((ptrdiff_t(&from) % 16) == 0) p = pload(from); - else p = ploadu(from); - return vec_perm(p, p, p16uc_DUPLICATE); + if((std::ptrdiff_t(from) % 16) == 0) p = pload(from); + else p = ploadu(from); + return vec_perm(p, p, p16uc_DUPLICATE32_HI); } template<> EIGEN_STRONG_INLINE Packet4i ploaddup(const int* from) { Packet4i p; - if((ptrdiff_t(&from) % 16) == 0) p = pload(from); - else p = ploadu(from); - return vec_perm(p, p, p16uc_DUPLICATE); + if((std::ptrdiff_t(from) % 16) == 0) p = pload(from); + else p = ploadu(from); + return vec_perm(p, p, p16uc_DUPLICATE32_HI); } -template<> EIGEN_STRONG_INLINE void pstore(float* to, const Packet4f& from) { EIGEN_DEBUG_ALIGNED_STORE vec_st(from, 0, to); } -template<> EIGEN_STRONG_INLINE void pstore(int* to, const Packet4i& from) { EIGEN_DEBUG_ALIGNED_STORE vec_st(from, 0, to); } - +#ifdef _BIG_ENDIAN template<> EIGEN_STRONG_INLINE void pstoreu(float* to, const Packet4f& from) { EIGEN_DEBUG_UNALIGNED_STORE @@ -337,15 +499,33 @@ template<> EIGEN_STRONG_INLINE void pstoreu(int* to, const Packet4i& f vec_st( LSQ, 15, (unsigned char *)to ); // Store the LSQ part first vec_st( MSQ, 0, (unsigned char *)to ); // Store the MSQ part } +#else +// We also need ot redefine little endian loading of Packet4i/Packet4f using VSX +template<> EIGEN_STRONG_INLINE void pstoreu(int* to, const Packet4i& from) +{ + EIGEN_DEBUG_ALIGNED_STORE + vec_vsx_st(from, (long)to & 15, (int*) _EIGEN_ALIGNED_PTR(to)); +} +template<> EIGEN_STRONG_INLINE void pstoreu(float* to, const Packet4f& from) +{ + EIGEN_DEBUG_ALIGNED_STORE + vec_vsx_st(from, (long)to & 15, (float*) _EIGEN_ALIGNED_PTR(to)); +} +#endif -template<> EIGEN_STRONG_INLINE void prefetch(const float* addr) { vec_dstt(addr, DST_CTRL(2,2,32), DST_CHAN); } -template<> EIGEN_STRONG_INLINE void prefetch(const int* addr) { vec_dstt(addr, DST_CTRL(2,2,32), DST_CHAN); } +template<> EIGEN_STRONG_INLINE void prefetch(const float* addr) { EIGEN_PPC_PREFETCH(addr); } +template<> EIGEN_STRONG_INLINE void prefetch(const int* addr) { EIGEN_PPC_PREFETCH(addr); } -template<> EIGEN_STRONG_INLINE float pfirst(const Packet4f& a) { float EIGEN_ALIGN16 x[4]; vec_st(a, 0, x); return x[0]; } -template<> EIGEN_STRONG_INLINE int pfirst(const Packet4i& a) { int EIGEN_ALIGN16 x[4]; vec_st(a, 0, x); return x[0]; } +template<> EIGEN_STRONG_INLINE float pfirst(const Packet4f& a) { float EIGEN_ALIGN16 x; vec_ste(a, 0, &x); return x; } +template<> EIGEN_STRONG_INLINE int pfirst(const Packet4i& a) { int EIGEN_ALIGN16 x; vec_ste(a, 0, &x); return x; } -template<> EIGEN_STRONG_INLINE Packet4f preverse(const Packet4f& a) { return (Packet4f)vec_perm((Packet16uc)a,(Packet16uc)a, p16uc_REVERSE); } -template<> EIGEN_STRONG_INLINE Packet4i preverse(const Packet4i& a) { return (Packet4i)vec_perm((Packet16uc)a,(Packet16uc)a, p16uc_REVERSE); } +template<> EIGEN_STRONG_INLINE Packet4f preverse(const Packet4f& a) +{ + return reinterpret_cast(vec_perm(reinterpret_cast(a), reinterpret_cast(a), p16uc_REVERSE32)); +} +template<> EIGEN_STRONG_INLINE Packet4i preverse(const Packet4i& a) +{ + return reinterpret_cast(vec_perm(reinterpret_cast(a), reinterpret_cast(a), p16uc_REVERSE32)); } template<> EIGEN_STRONG_INLINE Packet4f pabs(const Packet4f& a) { return vec_abs(a); } template<> EIGEN_STRONG_INLINE Packet4i pabs(const Packet4i& a) { return vec_abs(a); } @@ -353,10 +533,10 @@ template<> EIGEN_STRONG_INLINE Packet4i pabs(const Packet4i& a) { return vec_abs template<> EIGEN_STRONG_INLINE float predux(const Packet4f& a) { Packet4f b, sum; - b = (Packet4f) vec_sld(a, a, 8); - sum = vec_add(a, b); - b = (Packet4f) vec_sld(sum, sum, 4); - sum = vec_add(sum, b); + b = vec_sld(a, a, 8); + sum = a + b; + b = vec_sld(sum, sum, 4); + sum += b; return pfirst(sum); } @@ -379,11 +559,11 @@ template<> EIGEN_STRONG_INLINE Packet4f preduxp(const Packet4f* vecs) // Now do the summation: // Lines 0+1 - sum[0] = vec_add(sum[0], sum[1]); + sum[0] = sum[0] + sum[1]; // Lines 2+3 - sum[1] = vec_add(sum[2], sum[3]); + sum[1] = sum[2] + sum[3]; // Add the results - sum[0] = vec_add(sum[0], sum[1]); + sum[0] = sum[0] + sum[1]; return sum[0]; } @@ -392,7 +572,11 @@ template<> EIGEN_STRONG_INLINE int predux(const Packet4i& a) { Packet4i sum; sum = vec_sums(a, p4i_ZERO); +#ifdef _BIG_ENDIAN sum = vec_sld(sum, p4i_ZERO, 12); +#else + sum = vec_sld(p4i_ZERO, sum, 4); +#endif return pfirst(sum); } @@ -415,11 +599,11 @@ template<> EIGEN_STRONG_INLINE Packet4i preduxp(const Packet4i* vecs) // Now do the summation: // Lines 0+1 - sum[0] = vec_add(sum[0], sum[1]); + sum[0] = sum[0] + sum[1]; // Lines 2+3 - sum[1] = vec_add(sum[2], sum[3]); + sum[1] = sum[2] + sum[3]; // Add the results - sum[0] = vec_add(sum[0], sum[1]); + sum[0] = sum[0] + sum[1]; return sum[0]; } @@ -429,8 +613,8 @@ template<> EIGEN_STRONG_INLINE Packet4i preduxp(const Packet4i* vecs) template<> EIGEN_STRONG_INLINE float predux_mul(const Packet4f& a) { Packet4f prod; - prod = pmul(a, (Packet4f)vec_sld(a, a, 8)); - return pfirst(pmul(prod, (Packet4f)vec_sld(prod, prod, 4))); + prod = pmul(a, vec_sld(a, a, 8)); + return pfirst(pmul(prod, vec_sld(prod, prod, 4))); } template<> EIGEN_STRONG_INLINE int predux_mul(const Packet4i& a) @@ -479,8 +663,25 @@ struct palign_impl { static EIGEN_STRONG_INLINE void run(Packet4f& first, const Packet4f& second) { - if (Offset!=0) - first = vec_sld(first, second, Offset*4); +#ifdef _BIG_ENDIAN + switch (Offset % 4) { + case 1: + first = vec_sld(first, second, 4); break; + case 2: + first = vec_sld(first, second, 8); break; + case 3: + first = vec_sld(first, second, 12); break; + } +#else + switch (Offset % 4) { + case 1: + first = vec_sld(second, first, 12); break; + case 2: + first = vec_sld(second, first, 8); break; + case 3: + first = vec_sld(second, first, 4); break; + } +#endif } }; @@ -489,11 +690,342 @@ struct palign_impl { static EIGEN_STRONG_INLINE void run(Packet4i& first, const Packet4i& second) { - if (Offset!=0) - first = vec_sld(first, second, Offset*4); +#ifdef _BIG_ENDIAN + switch (Offset % 4) { + case 1: + first = vec_sld(first, second, 4); break; + case 2: + first = vec_sld(first, second, 8); break; + case 3: + first = vec_sld(first, second, 12); break; + } +#else + switch (Offset % 4) { + case 1: + first = vec_sld(second, first, 12); break; + case 2: + first = vec_sld(second, first, 8); break; + case 3: + first = vec_sld(second, first, 4); break; + } +#endif } }; +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + Packet4f t0, t1, t2, t3; + t0 = vec_mergeh(kernel.packet[0], kernel.packet[2]); + t1 = vec_mergel(kernel.packet[0], kernel.packet[2]); + t2 = vec_mergeh(kernel.packet[1], kernel.packet[3]); + t3 = vec_mergel(kernel.packet[1], kernel.packet[3]); + kernel.packet[0] = vec_mergeh(t0, t2); + kernel.packet[1] = vec_mergel(t0, t2); + kernel.packet[2] = vec_mergeh(t1, t3); + kernel.packet[3] = vec_mergel(t1, t3); +} + +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + Packet4i t0, t1, t2, t3; + t0 = vec_mergeh(kernel.packet[0], kernel.packet[2]); + t1 = vec_mergel(kernel.packet[0], kernel.packet[2]); + t2 = vec_mergeh(kernel.packet[1], kernel.packet[3]); + t3 = vec_mergel(kernel.packet[1], kernel.packet[3]); + kernel.packet[0] = vec_mergeh(t0, t2); + kernel.packet[1] = vec_mergel(t0, t2); + kernel.packet[2] = vec_mergeh(t1, t3); + kernel.packet[3] = vec_mergel(t1, t3); +} + +template<> EIGEN_STRONG_INLINE Packet4i pblend(const Selector<4>& ifPacket, const Packet4i& thenPacket, const Packet4i& elsePacket) { + Packet4ui select = { ifPacket.select[0], ifPacket.select[1], ifPacket.select[2], ifPacket.select[3] }; + Packet4ui mask = reinterpret_cast(vec_cmpeq(reinterpret_cast(select), reinterpret_cast(p4i_ONE))); + return vec_sel(elsePacket, thenPacket, mask); +} + +template<> EIGEN_STRONG_INLINE Packet4f pblend(const Selector<4>& ifPacket, const Packet4f& thenPacket, const Packet4f& elsePacket) { + Packet4ui select = { ifPacket.select[0], ifPacket.select[1], ifPacket.select[2], ifPacket.select[3] }; + Packet4ui mask = reinterpret_cast(vec_cmpeq(reinterpret_cast(select), reinterpret_cast(p4i_ONE))); + return vec_sel(elsePacket, thenPacket, mask); +} + + +//---------- double ---------- +#ifdef __VSX__ +typedef __vector double Packet2d; +typedef __vector unsigned long long Packet2ul; +typedef __vector long long Packet2l; +#if EIGEN_COMP_CLANG +typedef Packet2ul Packet2bl; +#else +typedef __vector __bool long Packet2bl; +#endif + +static Packet2l p2l_ONE = { 1, 1 }; +static Packet2l p2l_ZERO = reinterpret_cast(p4i_ZERO); +static Packet2d p2d_ONE = { 1.0, 1.0 }; +static Packet2d p2d_ZERO = reinterpret_cast(p4f_ZERO); +static Packet2d p2d_MZERO = { -0.0, -0.0 }; + +#ifdef _BIG_ENDIAN +static Packet2d p2d_COUNTDOWN = reinterpret_cast(vec_sld(reinterpret_cast(p2d_ZERO), reinterpret_cast(p2d_ONE), 8)); +#else +static Packet2d p2d_COUNTDOWN = reinterpret_cast(vec_sld(reinterpret_cast(p2d_ONE), reinterpret_cast(p2d_ZERO), 8)); +#endif + +template Packet2d vec_splat_dbl(Packet2d& a); + +template<> EIGEN_STRONG_INLINE Packet2d vec_splat_dbl<0>(Packet2d& a) +{ + return reinterpret_cast(vec_perm(a, a, p16uc_PSET64_HI)); +} + +template<> EIGEN_STRONG_INLINE Packet2d vec_splat_dbl<1>(Packet2d& a) +{ + return reinterpret_cast(vec_perm(a, a, p16uc_PSET64_LO)); +} + +template<> struct packet_traits : default_packet_traits +{ + typedef Packet2d type; + typedef Packet2d half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size=2, + HasHalfPacket = 1, + + HasAdd = 1, + HasSub = 1, + HasMul = 1, + HasDiv = 1, + HasMin = 1, + HasMax = 1, + HasAbs = 1, + HasSin = 0, + HasCos = 0, + HasLog = 0, + HasExp = 1, + HasSqrt = 1, + HasRsqrt = 1, + HasRound = 1, + HasFloor = 1, + HasCeil = 1, + HasNegate = 1, + HasBlend = 1 + }; +}; + +template<> struct unpacket_traits { typedef double type; enum {size=2, alignment=Aligned16}; typedef Packet2d half; }; + +inline std::ostream & operator <<(std::ostream & s, const Packet2l & v) +{ + union { + Packet2l v; + int64_t n[2]; + } vt; + vt.v = v; + s << vt.n[0] << ", " << vt.n[1]; + return s; +} + +inline std::ostream & operator <<(std::ostream & s, const Packet2d & v) +{ + union { + Packet2d v; + double n[2]; + } vt; + vt.v = v; + s << vt.n[0] << ", " << vt.n[1]; + return s; +} + +// Need to define them first or we get specialization after instantiation errors +template<> EIGEN_STRONG_INLINE Packet2d pload(const double* from) +{ + EIGEN_DEBUG_ALIGNED_LOAD +#ifdef __VSX__ + return vec_vsx_ld(0, from); +#else + return vec_ld(0, from); +#endif +} + +template<> EIGEN_STRONG_INLINE void pstore(double* to, const Packet2d& from) +{ + EIGEN_DEBUG_ALIGNED_STORE +#ifdef __VSX__ + vec_vsx_st(from, 0, to); +#else + vec_st(from, 0, to); +#endif +} + +template<> EIGEN_STRONG_INLINE Packet2d pset1(const double& from) { + Packet2d v = {from, from}; + return v; +} + +template<> EIGEN_STRONG_INLINE void +pbroadcast4(const double *a, + Packet2d& a0, Packet2d& a1, Packet2d& a2, Packet2d& a3) +{ + a1 = pload(a); + a0 = vec_splat_dbl<0>(a1); + a1 = vec_splat_dbl<1>(a1); + a3 = pload(a+2); + a2 = vec_splat_dbl<0>(a3); + a3 = vec_splat_dbl<1>(a3); +} + +template<> EIGEN_DEVICE_FUNC inline Packet2d pgather(const double* from, Index stride) +{ + double EIGEN_ALIGN16 af[2]; + af[0] = from[0*stride]; + af[1] = from[1*stride]; + return pload(af); +} +template<> EIGEN_DEVICE_FUNC inline void pscatter(double* to, const Packet2d& from, Index stride) +{ + double EIGEN_ALIGN16 af[2]; + pstore(af, from); + to[0*stride] = af[0]; + to[1*stride] = af[1]; +} + +template<> EIGEN_STRONG_INLINE Packet2d plset(const double& a) { return pset1(a) + p2d_COUNTDOWN; } + +template<> EIGEN_STRONG_INLINE Packet2d padd(const Packet2d& a, const Packet2d& b) { return a + b; } + +template<> EIGEN_STRONG_INLINE Packet2d psub(const Packet2d& a, const Packet2d& b) { return a - b; } + +template<> EIGEN_STRONG_INLINE Packet2d pnegate(const Packet2d& a) { return p2d_ZERO - a; } + +template<> EIGEN_STRONG_INLINE Packet2d pconj(const Packet2d& a) { return a; } + +template<> EIGEN_STRONG_INLINE Packet2d pmul(const Packet2d& a, const Packet2d& b) { return vec_madd(a,b,p2d_MZERO); } +template<> EIGEN_STRONG_INLINE Packet2d pdiv(const Packet2d& a, const Packet2d& b) { return vec_div(a,b); } + +// for some weird raisons, it has to be overloaded for packet of integers +template<> EIGEN_STRONG_INLINE Packet2d pmadd(const Packet2d& a, const Packet2d& b, const Packet2d& c) { return vec_madd(a, b, c); } + +template<> EIGEN_STRONG_INLINE Packet2d pmin(const Packet2d& a, const Packet2d& b) { return vec_min(a, b); } + +template<> EIGEN_STRONG_INLINE Packet2d pmax(const Packet2d& a, const Packet2d& b) { return vec_max(a, b); } + +template<> EIGEN_STRONG_INLINE Packet2d pand(const Packet2d& a, const Packet2d& b) { return vec_and(a, b); } + +template<> EIGEN_STRONG_INLINE Packet2d por(const Packet2d& a, const Packet2d& b) { return vec_or(a, b); } + +template<> EIGEN_STRONG_INLINE Packet2d pxor(const Packet2d& a, const Packet2d& b) { return vec_xor(a, b); } + +template<> EIGEN_STRONG_INLINE Packet2d pandnot(const Packet2d& a, const Packet2d& b) { return vec_and(a, vec_nor(b, b)); } + +template<> EIGEN_STRONG_INLINE Packet2d pround(const Packet2d& a) { return vec_round(a); } +template<> EIGEN_STRONG_INLINE Packet2d pceil(const Packet2d& a) { return vec_ceil(a); } +template<> EIGEN_STRONG_INLINE Packet2d pfloor(const Packet2d& a) { return vec_floor(a); } + +template<> EIGEN_STRONG_INLINE Packet2d ploadu(const double* from) +{ + EIGEN_DEBUG_ALIGNED_LOAD + return (Packet2d) vec_vsx_ld((long)from & 15, (const double*) _EIGEN_ALIGNED_PTR(from)); +} + +template<> EIGEN_STRONG_INLINE Packet2d ploaddup(const double* from) +{ + Packet2d p; + if((std::ptrdiff_t(from) % 16) == 0) p = pload(from); + else p = ploadu(from); + return vec_splat_dbl<0>(p); +} + +template<> EIGEN_STRONG_INLINE void pstoreu(double* to, const Packet2d& from) +{ + EIGEN_DEBUG_ALIGNED_STORE + vec_vsx_st((Packet4f)from, (long)to & 15, (float*) _EIGEN_ALIGNED_PTR(to)); +} + +template<> EIGEN_STRONG_INLINE void prefetch(const double* addr) { EIGEN_PPC_PREFETCH(addr); } + +template<> EIGEN_STRONG_INLINE double pfirst(const Packet2d& a) { double EIGEN_ALIGN16 x[2]; pstore(x, a); return x[0]; } + +template<> EIGEN_STRONG_INLINE Packet2d preverse(const Packet2d& a) +{ + return reinterpret_cast(vec_perm(reinterpret_cast(a), reinterpret_cast(a), p16uc_REVERSE64)); +} +template<> EIGEN_STRONG_INLINE Packet2d pabs(const Packet2d& a) { return vec_abs(a); } + +template<> EIGEN_STRONG_INLINE double predux(const Packet2d& a) +{ + Packet2d b, sum; + b = reinterpret_cast(vec_sld(reinterpret_cast(a), reinterpret_cast(a), 8)); + sum = a + b; + return pfirst(sum); +} + +template<> EIGEN_STRONG_INLINE Packet2d preduxp(const Packet2d* vecs) +{ + Packet2d v[2], sum; + v[0] = vecs[0] + reinterpret_cast(vec_sld(reinterpret_cast(vecs[0]), reinterpret_cast(vecs[0]), 8)); + v[1] = vecs[1] + reinterpret_cast(vec_sld(reinterpret_cast(vecs[1]), reinterpret_cast(vecs[1]), 8)); + +#ifdef _BIG_ENDIAN + sum = reinterpret_cast(vec_sld(reinterpret_cast(v[0]), reinterpret_cast(v[1]), 8)); +#else + sum = reinterpret_cast(vec_sld(reinterpret_cast(v[1]), reinterpret_cast(v[0]), 8)); +#endif + + return sum; +} +// Other reduction functions: +// mul +template<> EIGEN_STRONG_INLINE double predux_mul(const Packet2d& a) +{ + return pfirst(pmul(a, reinterpret_cast(vec_sld(reinterpret_cast(a), reinterpret_cast(a), 8)))); +} + +// min +template<> EIGEN_STRONG_INLINE double predux_min(const Packet2d& a) +{ + return pfirst(pmin(a, reinterpret_cast(vec_sld(reinterpret_cast(a), reinterpret_cast(a), 8)))); +} + +// max +template<> EIGEN_STRONG_INLINE double predux_max(const Packet2d& a) +{ + return pfirst(pmax(a, reinterpret_cast(vec_sld(reinterpret_cast(a), reinterpret_cast(a), 8)))); +} + +template +struct palign_impl +{ + static EIGEN_STRONG_INLINE void run(Packet2d& first, const Packet2d& second) + { + if (Offset == 1) +#ifdef _BIG_ENDIAN + first = reinterpret_cast(vec_sld(reinterpret_cast(first), reinterpret_cast(second), 8)); +#else + first = reinterpret_cast(vec_sld(reinterpret_cast(second), reinterpret_cast(first), 8)); +#endif + } +}; + +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + Packet2d t0, t1; + t0 = vec_perm(kernel.packet[0], kernel.packet[1], p16uc_TRANSPOSE64_HI); + t1 = vec_perm(kernel.packet[0], kernel.packet[1], p16uc_TRANSPOSE64_LO); + kernel.packet[0] = t0; + kernel.packet[1] = t1; +} + +template<> EIGEN_STRONG_INLINE Packet2d pblend(const Selector<2>& ifPacket, const Packet2d& thenPacket, const Packet2d& elsePacket) { + Packet2l select = { ifPacket.select[0], ifPacket.select[1] }; + Packet2bl mask = vec_cmpeq(reinterpret_cast(select), reinterpret_cast(p2l_ONE)); + return vec_sel(elsePacket, thenPacket, mask); +} +#endif // __VSX__ } // end namespace internal } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/Core/arch/CUDA/Complex.h b/libs/eigen3/Eigen/src/Core/arch/CUDA/Complex.h new file mode 100644 index 000000000..9c2536509 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/arch/CUDA/Complex.h @@ -0,0 +1,103 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_COMPLEX_CUDA_H +#define EIGEN_COMPLEX_CUDA_H + +// clang-format off + +namespace Eigen { + +namespace internal { + +#if defined(__CUDACC__) && defined(EIGEN_USE_GPU) + +// Many std::complex methods such as operator+, operator-, operator* and +// operator/ are not constexpr. Due to this, clang does not treat them as device +// functions and thus Eigen functors making use of these operators fail to +// compile. Here, we manually specialize these functors for complex types when +// building for CUDA to avoid non-constexpr methods. + +// Sum +template struct scalar_sum_op, const std::complex > : binary_op_base, const std::complex > { + typedef typename std::complex result_type; + + EIGEN_EMPTY_STRUCT_CTOR(scalar_sum_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex operator() (const std::complex& a, const std::complex& b) const { + return std::complex(numext::real(a) + numext::real(b), + numext::imag(a) + numext::imag(b)); + } +}; + +template struct scalar_sum_op, std::complex > : scalar_sum_op, const std::complex > {}; + + +// Difference +template struct scalar_difference_op, const std::complex > : binary_op_base, const std::complex > { + typedef typename std::complex result_type; + + EIGEN_EMPTY_STRUCT_CTOR(scalar_difference_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex operator() (const std::complex& a, const std::complex& b) const { + return std::complex(numext::real(a) - numext::real(b), + numext::imag(a) - numext::imag(b)); + } +}; + +template struct scalar_difference_op, std::complex > : scalar_difference_op, const std::complex > {}; + + +// Product +template struct scalar_product_op, const std::complex > : binary_op_base, const std::complex > { + enum { + Vectorizable = packet_traits>::HasMul + }; + typedef typename std::complex result_type; + + EIGEN_EMPTY_STRUCT_CTOR(scalar_product_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex operator() (const std::complex& a, const std::complex& b) const { + const T a_real = numext::real(a); + const T a_imag = numext::imag(a); + const T b_real = numext::real(b); + const T b_imag = numext::imag(b); + return std::complex(a_real * b_real - a_imag * b_imag, + a_real * b_imag + a_imag * b_real); + } +}; + +template struct scalar_product_op, std::complex > : scalar_product_op, const std::complex > {}; + + +// Quotient +template struct scalar_quotient_op, const std::complex > : binary_op_base, const std::complex > { + enum { + Vectorizable = packet_traits>::HasDiv + }; + typedef typename std::complex result_type; + + EIGEN_EMPTY_STRUCT_CTOR(scalar_quotient_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex operator() (const std::complex& a, const std::complex& b) const { + const T a_real = numext::real(a); + const T a_imag = numext::imag(a); + const T b_real = numext::real(b); + const T b_imag = numext::imag(b); + const T norm = T(1) / (b_real * b_real + b_imag * b_imag); + return std::complex((a_real * b_real + a_imag * b_imag) * norm, + (a_imag * b_real - a_real * b_imag) * norm); + } +}; + +template struct scalar_quotient_op, std::complex > : scalar_quotient_op, const std::complex > {}; + +#endif + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_COMPLEX_CUDA_H diff --git a/libs/eigen3/Eigen/src/Core/arch/CUDA/Half.h b/libs/eigen3/Eigen/src/Core/arch/CUDA/Half.h new file mode 100644 index 000000000..294c517ea --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/arch/CUDA/Half.h @@ -0,0 +1,635 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// The conversion routines are Copyright (c) Fabian Giesen, 2016. +// The original license follows: +// +// Copyright (c) Fabian Giesen, 2016 +// All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Standard 16-bit float type, mostly useful for GPUs. Defines a new +// type Eigen::half (inheriting from CUDA's __half struct) with +// operator overloads such that it behaves basically as an arithmetic +// type. It will be quite slow on CPUs (so it is recommended to stay +// in fp32 for CPUs, except for simple parameter conversions, I/O +// to disk and the likes), but fast on GPUs. + + +#ifndef EIGEN_HALF_CUDA_H +#define EIGEN_HALF_CUDA_H + +#if __cplusplus > 199711L +#define EIGEN_EXPLICIT_CAST(tgt_type) explicit operator tgt_type() +#else +#define EIGEN_EXPLICIT_CAST(tgt_type) operator tgt_type() +#endif + + +namespace Eigen { + +struct half; + +namespace half_impl { + +#if !defined(EIGEN_HAS_CUDA_FP16) + +// Make our own __half definition that is similar to CUDA's. +struct __half { + EIGEN_DEVICE_FUNC __half() {} + explicit EIGEN_DEVICE_FUNC __half(unsigned short raw) : x(raw) {} + unsigned short x; +}; + +#endif + +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC __half raw_uint16_to_half(unsigned short x); +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC __half float_to_half_rtne(float ff); +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC float half_to_float(__half h); + +struct half_base : public __half { + EIGEN_DEVICE_FUNC half_base() {} + EIGEN_DEVICE_FUNC half_base(const half_base& h) : __half(h) {} + EIGEN_DEVICE_FUNC half_base(const __half& h) : __half(h) {} +}; + +} // namespace half_impl + +// Class definition. +struct half : public half_impl::half_base { + #if !defined(EIGEN_HAS_CUDA_FP16) + typedef half_impl::__half __half; + #endif + + EIGEN_DEVICE_FUNC half() {} + + EIGEN_DEVICE_FUNC half(const __half& h) : half_impl::half_base(h) {} + EIGEN_DEVICE_FUNC half(const half& h) : half_impl::half_base(h) {} + + explicit EIGEN_DEVICE_FUNC half(bool b) + : half_impl::half_base(half_impl::raw_uint16_to_half(b ? 0x3c00 : 0)) {} + template + explicit EIGEN_DEVICE_FUNC half(const T& val) + : half_impl::half_base(half_impl::float_to_half_rtne(static_cast(val))) {} + explicit EIGEN_DEVICE_FUNC half(float f) + : half_impl::half_base(half_impl::float_to_half_rtne(f)) {} + + EIGEN_DEVICE_FUNC EIGEN_EXPLICIT_CAST(bool) const { + // +0.0 and -0.0 become false, everything else becomes true. + return (x & 0x7fff) != 0; + } + EIGEN_DEVICE_FUNC EIGEN_EXPLICIT_CAST(signed char) const { + return static_cast(half_impl::half_to_float(*this)); + } + EIGEN_DEVICE_FUNC EIGEN_EXPLICIT_CAST(unsigned char) const { + return static_cast(half_impl::half_to_float(*this)); + } + EIGEN_DEVICE_FUNC EIGEN_EXPLICIT_CAST(short) const { + return static_cast(half_impl::half_to_float(*this)); + } + EIGEN_DEVICE_FUNC EIGEN_EXPLICIT_CAST(unsigned short) const { + return static_cast(half_impl::half_to_float(*this)); + } + EIGEN_DEVICE_FUNC EIGEN_EXPLICIT_CAST(int) const { + return static_cast(half_impl::half_to_float(*this)); + } + EIGEN_DEVICE_FUNC EIGEN_EXPLICIT_CAST(unsigned int) const { + return static_cast(half_impl::half_to_float(*this)); + } + EIGEN_DEVICE_FUNC EIGEN_EXPLICIT_CAST(long) const { + return static_cast(half_impl::half_to_float(*this)); + } + EIGEN_DEVICE_FUNC EIGEN_EXPLICIT_CAST(unsigned long) const { + return static_cast(half_impl::half_to_float(*this)); + } + EIGEN_DEVICE_FUNC EIGEN_EXPLICIT_CAST(long long) const { + return static_cast(half_impl::half_to_float(*this)); + } + EIGEN_DEVICE_FUNC EIGEN_EXPLICIT_CAST(unsigned long long) const { + return static_cast(half_to_float(*this)); + } + EIGEN_DEVICE_FUNC EIGEN_EXPLICIT_CAST(float) const { + return half_impl::half_to_float(*this); + } + EIGEN_DEVICE_FUNC EIGEN_EXPLICIT_CAST(double) const { + return static_cast(half_impl::half_to_float(*this)); + } + + EIGEN_DEVICE_FUNC half& operator=(const half& other) { + x = other.x; + return *this; + } +}; + +namespace half_impl { + +#if defined(EIGEN_HAS_CUDA_FP16) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530 + +// Intrinsics for native fp16 support. Note that on current hardware, +// these are no faster than fp32 arithmetic (you need to use the half2 +// versions to get the ALU speed increased), but you do save the +// conversion steps back and forth. + +__device__ half operator + (const half& a, const half& b) { + return __hadd(a, b); +} +__device__ half operator * (const half& a, const half& b) { + return __hmul(a, b); +} +__device__ half operator - (const half& a, const half& b) { + return __hsub(a, b); +} +__device__ half operator / (const half& a, const half& b) { + float num = __half2float(a); + float denom = __half2float(b); + return __float2half(num / denom); +} +__device__ half operator - (const half& a) { + return __hneg(a); +} +__device__ half& operator += (half& a, const half& b) { + a = a + b; + return a; +} +__device__ half& operator *= (half& a, const half& b) { + a = a * b; + return a; +} +__device__ half& operator -= (half& a, const half& b) { + a = a - b; + return a; +} +__device__ half& operator /= (half& a, const half& b) { + a = a / b; + return a; +} +__device__ bool operator == (const half& a, const half& b) { + return __heq(a, b); +} +__device__ bool operator != (const half& a, const half& b) { + return __hne(a, b); +} +__device__ bool operator < (const half& a, const half& b) { + return __hlt(a, b); +} +__device__ bool operator <= (const half& a, const half& b) { + return __hle(a, b); +} +__device__ bool operator > (const half& a, const half& b) { + return __hgt(a, b); +} +__device__ bool operator >= (const half& a, const half& b) { + return __hge(a, b); +} + +#else // Emulate support for half floats + +// Definitions for CPUs and older CUDA, mostly working through conversion +// to/from fp32. + +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half operator + (const half& a, const half& b) { + return half(float(a) + float(b)); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half operator * (const half& a, const half& b) { + return half(float(a) * float(b)); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half operator - (const half& a, const half& b) { + return half(float(a) - float(b)); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half operator / (const half& a, const half& b) { + return half(float(a) / float(b)); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half operator - (const half& a) { + half result; + result.x = a.x ^ 0x8000; + return result; +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half& operator += (half& a, const half& b) { + a = half(float(a) + float(b)); + return a; +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half& operator *= (half& a, const half& b) { + a = half(float(a) * float(b)); + return a; +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half& operator -= (half& a, const half& b) { + a = half(float(a) - float(b)); + return a; +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half& operator /= (half& a, const half& b) { + a = half(float(a) / float(b)); + return a; +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator == (const half& a, const half& b) { + return float(a) == float(b); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator != (const half& a, const half& b) { + return float(a) != float(b); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator < (const half& a, const half& b) { + return float(a) < float(b); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator <= (const half& a, const half& b) { + return float(a) <= float(b); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator > (const half& a, const half& b) { + return float(a) > float(b); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator >= (const half& a, const half& b) { + return float(a) >= float(b); +} + +#endif // Emulate support for half floats + +// Division by an index. Do it in full float precision to avoid accuracy +// issues in converting the denominator to half. +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half operator / (const half& a, Index b) { + return half(static_cast(a) / static_cast(b)); +} + +// Conversion routines, including fallbacks for the host or older CUDA. +// Note that newer Intel CPUs (Haswell or newer) have vectorized versions of +// these in hardware. If we need more performance on older/other CPUs, they are +// also possible to vectorize directly. + +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC __half raw_uint16_to_half(unsigned short x) { + __half h; + h.x = x; + return h; +} + +union FP32 { + unsigned int u; + float f; +}; + +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC __half float_to_half_rtne(float ff) { +#if defined(EIGEN_HAS_CUDA_FP16) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 300 + return __float2half(ff); + +#elif defined(EIGEN_HAS_FP16_C) + __half h; + h.x = _cvtss_sh(ff, 0); + return h; + +#else + FP32 f; f.f = ff; + + const FP32 f32infty = { 255 << 23 }; + const FP32 f16max = { (127 + 16) << 23 }; + const FP32 denorm_magic = { ((127 - 15) + (23 - 10) + 1) << 23 }; + unsigned int sign_mask = 0x80000000u; + __half o; + o.x = static_cast(0x0u); + + unsigned int sign = f.u & sign_mask; + f.u ^= sign; + + // NOTE all the integer compares in this function can be safely + // compiled into signed compares since all operands are below + // 0x80000000. Important if you want fast straight SSE2 code + // (since there's no unsigned PCMPGTD). + + if (f.u >= f16max.u) { // result is Inf or NaN (all exponent bits set) + o.x = (f.u > f32infty.u) ? 0x7e00 : 0x7c00; // NaN->qNaN and Inf->Inf + } else { // (De)normalized number or zero + if (f.u < (113 << 23)) { // resulting FP16 is subnormal or zero + // use a magic value to align our 10 mantissa bits at the bottom of + // the float. as long as FP addition is round-to-nearest-even this + // just works. + f.f += denorm_magic.f; + + // and one integer subtract of the bias later, we have our final float! + o.x = static_cast(f.u - denorm_magic.u); + } else { + unsigned int mant_odd = (f.u >> 13) & 1; // resulting mantissa is odd + + // update exponent, rounding bias part 1 + f.u += ((unsigned int)(15 - 127) << 23) + 0xfff; + // rounding bias part 2 + f.u += mant_odd; + // take the bits! + o.x = static_cast(f.u >> 13); + } + } + + o.x |= static_cast(sign >> 16); + return o; +#endif +} + +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC float half_to_float(__half h) { +#if defined(EIGEN_HAS_CUDA_FP16) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 300 + return __half2float(h); + +#elif defined(EIGEN_HAS_FP16_C) + return _cvtsh_ss(h.x); + +#else + const FP32 magic = { 113 << 23 }; + const unsigned int shifted_exp = 0x7c00 << 13; // exponent mask after shift + FP32 o; + + o.u = (h.x & 0x7fff) << 13; // exponent/mantissa bits + unsigned int exp = shifted_exp & o.u; // just the exponent + o.u += (127 - 15) << 23; // exponent adjust + + // handle exponent special cases + if (exp == shifted_exp) { // Inf/NaN? + o.u += (128 - 16) << 23; // extra exp adjust + } else if (exp == 0) { // Zero/Denormal? + o.u += 1 << 23; // extra exp adjust + o.f -= magic.f; // renormalize + } + + o.u |= (h.x & 0x8000) << 16; // sign bit + return o.f; +#endif +} + +// --- standard functions --- + +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool (isinf)(const half& a) { + return (a.x & 0x7fff) == 0x7c00; +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool (isnan)(const half& a) { +#if defined(EIGEN_HAS_CUDA_FP16) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530 + return __hisnan(a); +#else + return (a.x & 0x7fff) > 0x7c00; +#endif +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool (isfinite)(const half& a) { + return !(isinf EIGEN_NOT_A_MACRO (a)) && !(isnan EIGEN_NOT_A_MACRO (a)); +} + +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half abs(const half& a) { + half result; + result.x = a.x & 0x7FFF; + return result; +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half exp(const half& a) { + return half(::expf(float(a))); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half log(const half& a) { +#if defined(EIGEN_HAS_CUDA_FP16) && defined __CUDACC_VER__ && __CUDACC_VER__ >= 80000 && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530 + return Eigen::half(::hlog(a)); +#else + return half(::logf(float(a))); +#endif +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half log1p(const half& a) { + return half(numext::log1p(float(a))); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half log10(const half& a) { + return half(::log10f(float(a))); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half sqrt(const half& a) { + return half(::sqrtf(float(a))); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half pow(const half& a, const half& b) { + return half(::powf(float(a), float(b))); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half sin(const half& a) { + return half(::sinf(float(a))); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half cos(const half& a) { + return half(::cosf(float(a))); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half tan(const half& a) { + return half(::tanf(float(a))); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half tanh(const half& a) { + return half(::tanhf(float(a))); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half floor(const half& a) { + return half(::floorf(float(a))); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half ceil(const half& a) { + return half(::ceilf(float(a))); +} + +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half (min)(const half& a, const half& b) { +#if defined(EIGEN_HAS_CUDA_FP16) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530 + return __hlt(b, a) ? b : a; +#else + const float f1 = static_cast(a); + const float f2 = static_cast(b); + return f2 < f1 ? b : a; +#endif +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half (max)(const half& a, const half& b) { +#if defined(EIGEN_HAS_CUDA_FP16) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530 + return __hlt(a, b) ? b : a; +#else + const float f1 = static_cast(a); + const float f2 = static_cast(b); + return f1 < f2 ? b : a; +#endif +} + +EIGEN_ALWAYS_INLINE std::ostream& operator << (std::ostream& os, const half& v) { + os << static_cast(v); + return os; +} + +} // end namespace half_impl + +// import Eigen::half_impl::half into Eigen namespace +// using half_impl::half; + +namespace internal { + +template<> +struct random_default_impl +{ + static inline half run(const half& x, const half& y) + { + return x + (y-x) * half(float(std::rand()) / float(RAND_MAX)); + } + static inline half run() + { + return run(half(-1.f), half(1.f)); + } +}; + +template<> struct is_arithmetic { enum { value = true }; }; + +} // end namespace internal + +} // end namespace Eigen + +namespace std { +template<> +struct numeric_limits { + static const bool is_specialized = true; + static const bool is_signed = true; + static const bool is_integer = false; + static const bool is_exact = false; + static const bool has_infinity = true; + static const bool has_quiet_NaN = true; + static const bool has_signaling_NaN = true; + static const float_denorm_style has_denorm = denorm_present; + static const bool has_denorm_loss = false; + static const std::float_round_style round_style = std::round_to_nearest; + static const bool is_iec559 = false; + static const bool is_bounded = false; + static const bool is_modulo = false; + static const int digits = 11; + static const int digits10 = 2; + //static const int max_digits10 = ; + static const int radix = 2; + static const int min_exponent = -13; + static const int min_exponent10 = -4; + static const int max_exponent = 16; + static const int max_exponent10 = 4; + static const bool traps = true; + static const bool tinyness_before = false; + + static Eigen::half (min)() { return Eigen::half_impl::raw_uint16_to_half(0x400); } + static Eigen::half lowest() { return Eigen::half_impl::raw_uint16_to_half(0xfbff); } + static Eigen::half (max)() { return Eigen::half_impl::raw_uint16_to_half(0x7bff); } + static Eigen::half epsilon() { return Eigen::half_impl::raw_uint16_to_half(0x0800); } + static Eigen::half round_error() { return Eigen::half(0.5); } + static Eigen::half infinity() { return Eigen::half_impl::raw_uint16_to_half(0x7c00); } + static Eigen::half quiet_NaN() { return Eigen::half_impl::raw_uint16_to_half(0x7e00); } + static Eigen::half signaling_NaN() { return Eigen::half_impl::raw_uint16_to_half(0x7e00); } + static Eigen::half denorm_min() { return Eigen::half_impl::raw_uint16_to_half(0x1); } +}; +} + +namespace Eigen { + +template<> struct NumTraits + : GenericNumTraits +{ + enum { + IsSigned = true, + IsInteger = false, + IsComplex = false, + RequireInitialization = false + }; + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Eigen::half epsilon() { + return half_impl::raw_uint16_to_half(0x0800); + } + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Eigen::half dummy_precision() { return Eigen::half(1e-2f); } + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Eigen::half highest() { + return half_impl::raw_uint16_to_half(0x7bff); + } + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Eigen::half lowest() { + return half_impl::raw_uint16_to_half(0xfbff); + } + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Eigen::half infinity() { + return half_impl::raw_uint16_to_half(0x7c00); + } + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Eigen::half quiet_NaN() { + return half_impl::raw_uint16_to_half(0x7c01); + } +}; + +} // end namespace Eigen + +// C-like standard mathematical functions and trancendentals. +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Eigen::half fabsh(const Eigen::half& a) { + Eigen::half result; + result.x = a.x & 0x7FFF; + return result; +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Eigen::half exph(const Eigen::half& a) { + return Eigen::half(::expf(float(a))); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Eigen::half logh(const Eigen::half& a) { +#if defined __CUDACC_VER__ && __CUDACC_VER__ >= 80000 && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530 + return Eigen::half(::hlog(a)); +#else + return Eigen::half(::logf(float(a))); +#endif +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Eigen::half sqrth(const Eigen::half& a) { + return Eigen::half(::sqrtf(float(a))); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Eigen::half powh(const Eigen::half& a, const Eigen::half& b) { + return Eigen::half(::powf(float(a), float(b))); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Eigen::half floorh(const Eigen::half& a) { + return Eigen::half(::floorf(float(a))); +} +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Eigen::half ceilh(const Eigen::half& a) { + return Eigen::half(::ceilf(float(a))); +} + +namespace std { + +#if __cplusplus > 199711L +template <> +struct hash { + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::size_t operator()(const Eigen::half& a) const { + return static_cast(a.x); + } +}; +#endif + +} // end namespace std + + +// Add the missing shfl_xor intrinsic +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 300 +__device__ EIGEN_STRONG_INLINE Eigen::half __shfl_xor(Eigen::half var, int laneMask, int width=warpSize) { + return static_cast(__shfl_xor(static_cast(var), laneMask, width)); +} +#endif + +// ldg() has an overload for __half, but we also need one for Eigen::half. +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 350 +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Eigen::half __ldg(const Eigen::half* ptr) { + return Eigen::half_impl::raw_uint16_to_half( + __ldg(reinterpret_cast(ptr))); +} +#endif + + +#if defined(__CUDA_ARCH__) +namespace Eigen { +namespace numext { + +template<> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +bool (isnan)(const Eigen::half& h) { + return (half_impl::isnan)(h); +} + +template<> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +bool (isinf)(const Eigen::half& h) { + return (half_impl::isinf)(h); +} + +template<> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +bool (isfinite)(const Eigen::half& h) { + return (half_impl::isfinite)(h); +} + +} // namespace Eigen +} // namespace numext +#endif + +#endif // EIGEN_HALF_CUDA_H diff --git a/libs/eigen3/Eigen/src/Core/arch/CUDA/MathFunctions.h b/libs/eigen3/Eigen/src/Core/arch/CUDA/MathFunctions.h new file mode 100644 index 000000000..0348b41db --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/arch/CUDA/MathFunctions.h @@ -0,0 +1,91 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_MATH_FUNCTIONS_CUDA_H +#define EIGEN_MATH_FUNCTIONS_CUDA_H + +namespace Eigen { + +namespace internal { + +// Make sure this is only available when targeting a GPU: we don't want to +// introduce conflicts between these packet_traits definitions and the ones +// we'll use on the host side (SSE, AVX, ...) +#if defined(__CUDACC__) && defined(EIGEN_USE_GPU) +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +float4 plog(const float4& a) +{ + return make_float4(logf(a.x), logf(a.y), logf(a.z), logf(a.w)); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +double2 plog(const double2& a) +{ + using ::log; + return make_double2(log(a.x), log(a.y)); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +float4 plog1p(const float4& a) +{ + return make_float4(log1pf(a.x), log1pf(a.y), log1pf(a.z), log1pf(a.w)); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +double2 plog1p(const double2& a) +{ + return make_double2(log1p(a.x), log1p(a.y)); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +float4 pexp(const float4& a) +{ + return make_float4(expf(a.x), expf(a.y), expf(a.z), expf(a.w)); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +double2 pexp(const double2& a) +{ + using ::exp; + return make_double2(exp(a.x), exp(a.y)); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +float4 psqrt(const float4& a) +{ + return make_float4(sqrtf(a.x), sqrtf(a.y), sqrtf(a.z), sqrtf(a.w)); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +double2 psqrt(const double2& a) +{ + using ::sqrt; + return make_double2(sqrt(a.x), sqrt(a.y)); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +float4 prsqrt(const float4& a) +{ + return make_float4(rsqrtf(a.x), rsqrtf(a.y), rsqrtf(a.z), rsqrtf(a.w)); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +double2 prsqrt(const double2& a) +{ + return make_double2(rsqrt(a.x), rsqrt(a.y)); +} + + +#endif + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_MATH_FUNCTIONS_CUDA_H diff --git a/libs/eigen3/Eigen/src/Core/arch/CUDA/PacketMath.h b/libs/eigen3/Eigen/src/Core/arch/CUDA/PacketMath.h new file mode 100644 index 000000000..4dda63188 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/arch/CUDA/PacketMath.h @@ -0,0 +1,333 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_PACKET_MATH_CUDA_H +#define EIGEN_PACKET_MATH_CUDA_H + +namespace Eigen { + +namespace internal { + +// Make sure this is only available when targeting a GPU: we don't want to +// introduce conflicts between these packet_traits definitions and the ones +// we'll use on the host side (SSE, AVX, ...) +#if defined(__CUDACC__) && defined(EIGEN_USE_GPU) +template<> struct is_arithmetic { enum { value = true }; }; +template<> struct is_arithmetic { enum { value = true }; }; + +template<> struct packet_traits : default_packet_traits +{ + typedef float4 type; + typedef float4 half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size=4, + HasHalfPacket = 0, + + HasDiv = 1, + HasSin = 0, + HasCos = 0, + HasLog = 1, + HasExp = 1, + HasSqrt = 1, + HasRsqrt = 1, + HasLGamma = 1, + HasDiGamma = 1, + HasZeta = 1, + HasPolygamma = 1, + HasErf = 1, + HasErfc = 1, + HasIGamma = 1, + HasIGammac = 1, + HasBetaInc = 1, + + HasBlend = 0, + }; +}; + +template<> struct packet_traits : default_packet_traits +{ + typedef double2 type; + typedef double2 half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size=2, + HasHalfPacket = 0, + + HasDiv = 1, + HasLog = 1, + HasExp = 1, + HasSqrt = 1, + HasRsqrt = 1, + HasLGamma = 1, + HasDiGamma = 1, + HasZeta = 1, + HasPolygamma = 1, + HasErf = 1, + HasErfc = 1, + HasIGamma = 1, + HasIGammac = 1, + HasBetaInc = 1, + + HasBlend = 0, + }; +}; + + +template<> struct unpacket_traits { typedef float type; enum {size=4, alignment=Aligned16}; typedef float4 half; }; +template<> struct unpacket_traits { typedef double type; enum {size=2, alignment=Aligned16}; typedef double2 half; }; + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pset1(const float& from) { + return make_float4(from, from, from, from); +} +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pset1(const double& from) { + return make_double2(from, from); +} + + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 plset(const float& a) { + return make_float4(a, a+1, a+2, a+3); +} +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 plset(const double& a) { + return make_double2(a, a+1); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 padd(const float4& a, const float4& b) { + return make_float4(a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w); +} +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 padd(const double2& a, const double2& b) { + return make_double2(a.x+b.x, a.y+b.y); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 psub(const float4& a, const float4& b) { + return make_float4(a.x-b.x, a.y-b.y, a.z-b.z, a.w-b.w); +} +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 psub(const double2& a, const double2& b) { + return make_double2(a.x-b.x, a.y-b.y); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pnegate(const float4& a) { + return make_float4(-a.x, -a.y, -a.z, -a.w); +} +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pnegate(const double2& a) { + return make_double2(-a.x, -a.y); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pconj(const float4& a) { return a; } +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pconj(const double2& a) { return a; } + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pmul(const float4& a, const float4& b) { + return make_float4(a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w); +} +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pmul(const double2& a, const double2& b) { + return make_double2(a.x*b.x, a.y*b.y); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pdiv(const float4& a, const float4& b) { + return make_float4(a.x/b.x, a.y/b.y, a.z/b.z, a.w/b.w); +} +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pdiv(const double2& a, const double2& b) { + return make_double2(a.x/b.x, a.y/b.y); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pmin(const float4& a, const float4& b) { + return make_float4(fminf(a.x, b.x), fminf(a.y, b.y), fminf(a.z, b.z), fminf(a.w, b.w)); +} +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pmin(const double2& a, const double2& b) { + return make_double2(fmin(a.x, b.x), fmin(a.y, b.y)); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pmax(const float4& a, const float4& b) { + return make_float4(fmaxf(a.x, b.x), fmaxf(a.y, b.y), fmaxf(a.z, b.z), fmaxf(a.w, b.w)); +} +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pmax(const double2& a, const double2& b) { + return make_double2(fmax(a.x, b.x), fmax(a.y, b.y)); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pload(const float* from) { + return *reinterpret_cast(from); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pload(const double* from) { + return *reinterpret_cast(from); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 ploadu(const float* from) { + return make_float4(from[0], from[1], from[2], from[3]); +} +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 ploadu(const double* from) { + return make_double2(from[0], from[1]); +} + +template<> EIGEN_STRONG_INLINE float4 ploaddup(const float* from) { + return make_float4(from[0], from[0], from[1], from[1]); +} +template<> EIGEN_STRONG_INLINE double2 ploaddup(const double* from) { + return make_double2(from[0], from[0]); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pstore(float* to, const float4& from) { + *reinterpret_cast(to) = from; +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pstore(double* to, const double2& from) { + *reinterpret_cast(to) = from; +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pstoreu(float* to, const float4& from) { + to[0] = from.x; + to[1] = from.y; + to[2] = from.z; + to[3] = from.w; +} + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pstoreu(double* to, const double2& from) { + to[0] = from.x; + to[1] = from.y; +} + +template<> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float4 ploadt_ro(const float* from) { +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 350 + return __ldg((const float4*)from); +#else + return make_float4(from[0], from[1], from[2], from[3]); +#endif +} +template<> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double2 ploadt_ro(const double* from) { +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 350 + return __ldg((const double2*)from); +#else + return make_double2(from[0], from[1]); +#endif +} + +template<> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float4 ploadt_ro(const float* from) { +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 350 + return make_float4(__ldg(from+0), __ldg(from+1), __ldg(from+2), __ldg(from+3)); +#else + return make_float4(from[0], from[1], from[2], from[3]); +#endif +} +template<> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double2 ploadt_ro(const double* from) { +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 350 + return make_double2(__ldg(from+0), __ldg(from+1)); +#else + return make_double2(from[0], from[1]); +#endif +} + +template<> EIGEN_DEVICE_FUNC inline float4 pgather(const float* from, Index stride) { + return make_float4(from[0*stride], from[1*stride], from[2*stride], from[3*stride]); +} + +template<> EIGEN_DEVICE_FUNC inline double2 pgather(const double* from, Index stride) { + return make_double2(from[0*stride], from[1*stride]); +} + +template<> EIGEN_DEVICE_FUNC inline void pscatter(float* to, const float4& from, Index stride) { + to[stride*0] = from.x; + to[stride*1] = from.y; + to[stride*2] = from.z; + to[stride*3] = from.w; +} +template<> EIGEN_DEVICE_FUNC inline void pscatter(double* to, const double2& from, Index stride) { + to[stride*0] = from.x; + to[stride*1] = from.y; +} + +template<> EIGEN_DEVICE_FUNC inline float pfirst(const float4& a) { + return a.x; +} +template<> EIGEN_DEVICE_FUNC inline double pfirst(const double2& a) { + return a.x; +} + +template<> EIGEN_DEVICE_FUNC inline float predux(const float4& a) { + return a.x + a.y + a.z + a.w; +} +template<> EIGEN_DEVICE_FUNC inline double predux(const double2& a) { + return a.x + a.y; +} + +template<> EIGEN_DEVICE_FUNC inline float predux_max(const float4& a) { + return fmaxf(fmaxf(a.x, a.y), fmaxf(a.z, a.w)); +} +template<> EIGEN_DEVICE_FUNC inline double predux_max(const double2& a) { + return fmax(a.x, a.y); +} + +template<> EIGEN_DEVICE_FUNC inline float predux_min(const float4& a) { + return fminf(fminf(a.x, a.y), fminf(a.z, a.w)); +} +template<> EIGEN_DEVICE_FUNC inline double predux_min(const double2& a) { + return fmin(a.x, a.y); +} + +template<> EIGEN_DEVICE_FUNC inline float predux_mul(const float4& a) { + return a.x * a.y * a.z * a.w; +} +template<> EIGEN_DEVICE_FUNC inline double predux_mul(const double2& a) { + return a.x * a.y; +} + +template<> EIGEN_DEVICE_FUNC inline float4 pabs(const float4& a) { + return make_float4(fabsf(a.x), fabsf(a.y), fabsf(a.z), fabsf(a.w)); +} +template<> EIGEN_DEVICE_FUNC inline double2 pabs(const double2& a) { + return make_double2(fabs(a.x), fabs(a.y)); +} + +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + float tmp = kernel.packet[0].y; + kernel.packet[0].y = kernel.packet[1].x; + kernel.packet[1].x = tmp; + + tmp = kernel.packet[0].z; + kernel.packet[0].z = kernel.packet[2].x; + kernel.packet[2].x = tmp; + + tmp = kernel.packet[0].w; + kernel.packet[0].w = kernel.packet[3].x; + kernel.packet[3].x = tmp; + + tmp = kernel.packet[1].z; + kernel.packet[1].z = kernel.packet[2].y; + kernel.packet[2].y = tmp; + + tmp = kernel.packet[1].w; + kernel.packet[1].w = kernel.packet[3].y; + kernel.packet[3].y = tmp; + + tmp = kernel.packet[2].w; + kernel.packet[2].w = kernel.packet[3].z; + kernel.packet[3].z = tmp; +} + +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + double tmp = kernel.packet[0].y; + kernel.packet[0].y = kernel.packet[1].x; + kernel.packet[1].x = tmp; +} + +#endif + +} // end namespace internal + +} // end namespace Eigen + + +#endif // EIGEN_PACKET_MATH_CUDA_H diff --git a/libs/eigen3/Eigen/src/Core/arch/CUDA/PacketMathHalf.h b/libs/eigen3/Eigen/src/Core/arch/CUDA/PacketMathHalf.h new file mode 100644 index 000000000..ae54225f8 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/arch/CUDA/PacketMathHalf.h @@ -0,0 +1,1123 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2016 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_PACKET_MATH_HALF_CUDA_H +#define EIGEN_PACKET_MATH_HALF_CUDA_H + + +namespace Eigen { +namespace internal { + +// Most of the following operations require arch >= 3.0 +#if defined(EIGEN_HAS_CUDA_FP16) && defined(__CUDACC__) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 300 + +template<> struct is_arithmetic { enum { value = true }; }; + +template<> struct packet_traits : default_packet_traits +{ + typedef half2 type; + typedef half2 half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size=2, + HasHalfPacket = 0, + HasAdd = 1, + HasMul = 1, + HasDiv = 1, + HasSqrt = 1, + HasRsqrt = 1, + HasExp = 1, + HasLog = 1, + HasLog1p = 1 + }; +}; + +template<> struct unpacket_traits { typedef Eigen::half type; enum {size=2, alignment=Aligned16}; typedef half2 half; }; + +template<> __device__ EIGEN_STRONG_INLINE half2 pset1(const Eigen::half& from) { + return __half2half2(from); +} + +template<> __device__ EIGEN_STRONG_INLINE half2 pload(const Eigen::half* from) { + return *reinterpret_cast(from); +} + +template<> __device__ EIGEN_STRONG_INLINE half2 ploadu(const Eigen::half* from) { + return __halves2half2(from[0], from[1]); +} + +template<> EIGEN_STRONG_INLINE half2 ploaddup(const Eigen::half* from) { + return __halves2half2(from[0], from[0]); +} + +template<> __device__ EIGEN_STRONG_INLINE void pstore(Eigen::half* to, const half2& from) { + *reinterpret_cast(to) = from; +} + +template<> __device__ EIGEN_STRONG_INLINE void pstoreu(Eigen::half* to, const half2& from) { + to[0] = __low2half(from); + to[1] = __high2half(from); +} + +template<> + __device__ EIGEN_ALWAYS_INLINE half2 ploadt_ro(const Eigen::half* from) { +#if __CUDA_ARCH__ >= 350 + return __ldg((const half2*)from); +#else + return __halves2half2(*(from+0), *(from+1)); +#endif +} + +template<> +__device__ EIGEN_ALWAYS_INLINE half2 ploadt_ro(const Eigen::half* from) { +#if __CUDA_ARCH__ >= 350 + return __halves2half2(__ldg(from+0), __ldg(from+1)); +#else + return __halves2half2(*(from+0), *(from+1)); +#endif +} + +template<> __device__ EIGEN_STRONG_INLINE half2 pgather(const Eigen::half* from, Index stride) { + return __halves2half2(from[0*stride], from[1*stride]); +} + +template<> __device__ EIGEN_STRONG_INLINE void pscatter(Eigen::half* to, const half2& from, Index stride) { + to[stride*0] = __low2half(from); + to[stride*1] = __high2half(from); +} + +template<> __device__ EIGEN_STRONG_INLINE Eigen::half pfirst(const half2& a) { + return __low2half(a); +} + +template<> __device__ EIGEN_STRONG_INLINE half2 pabs(const half2& a) { + half2 result; + result.x = a.x & 0x7FFF7FFF; + return result; +} + + +__device__ EIGEN_STRONG_INLINE void +ptranspose(PacketBlock& kernel) { + __half a1 = __low2half(kernel.packet[0]); + __half a2 = __high2half(kernel.packet[0]); + __half b1 = __low2half(kernel.packet[1]); + __half b2 = __high2half(kernel.packet[1]); + kernel.packet[0] = __halves2half2(a1, b1); + kernel.packet[1] = __halves2half2(a2, b2); +} + +template<> __device__ EIGEN_STRONG_INLINE half2 plset(const Eigen::half& a) { +#if __CUDA_ARCH__ >= 530 + return __halves2half2(a, __hadd(a, __float2half(1.0f))); +#else + float f = __half2float(a) + 1.0f; + return __halves2half2(a, __float2half(f)); +#endif +} + +template<> __device__ EIGEN_STRONG_INLINE half2 padd(const half2& a, const half2& b) { +#if __CUDA_ARCH__ >= 530 + return __hadd2(a, b); +#else + float a1 = __low2float(a); + float a2 = __high2float(a); + float b1 = __low2float(b); + float b2 = __high2float(b); + float r1 = a1 + b1; + float r2 = a2 + b2; + return __floats2half2_rn(r1, r2); +#endif +} + +template<> __device__ EIGEN_STRONG_INLINE half2 psub(const half2& a, const half2& b) { +#if __CUDA_ARCH__ >= 530 + return __hsub2(a, b); +#else + float a1 = __low2float(a); + float a2 = __high2float(a); + float b1 = __low2float(b); + float b2 = __high2float(b); + float r1 = a1 - b1; + float r2 = a2 - b2; + return __floats2half2_rn(r1, r2); +#endif +} + +template<> __device__ EIGEN_STRONG_INLINE half2 pnegate(const half2& a) { +#if __CUDA_ARCH__ >= 530 + return __hneg2(a); +#else + float a1 = __low2float(a); + float a2 = __high2float(a); + return __floats2half2_rn(-a1, -a2); +#endif +} + +template<> __device__ EIGEN_STRONG_INLINE half2 pconj(const half2& a) { return a; } + +template<> __device__ EIGEN_STRONG_INLINE half2 pmul(const half2& a, const half2& b) { +#if __CUDA_ARCH__ >= 530 + return __hmul2(a, b); +#else + float a1 = __low2float(a); + float a2 = __high2float(a); + float b1 = __low2float(b); + float b2 = __high2float(b); + float r1 = a1 * b1; + float r2 = a2 * b2; + return __floats2half2_rn(r1, r2); +#endif +} + +template<> __device__ EIGEN_STRONG_INLINE half2 pmadd(const half2& a, const half2& b, const half2& c) { +#if __CUDA_ARCH__ >= 530 + return __hfma2(a, b, c); +#else + float a1 = __low2float(a); + float a2 = __high2float(a); + float b1 = __low2float(b); + float b2 = __high2float(b); + float c1 = __low2float(c); + float c2 = __high2float(c); + float r1 = a1 * b1 + c1; + float r2 = a2 * b2 + c2; + return __floats2half2_rn(r1, r2); +#endif +} + +template<> __device__ EIGEN_STRONG_INLINE half2 pdiv(const half2& a, const half2& b) { + float a1 = __low2float(a); + float a2 = __high2float(a); + float b1 = __low2float(b); + float b2 = __high2float(b); + float r1 = a1 / b1; + float r2 = a2 / b2; + return __floats2half2_rn(r1, r2); +} + +template<> __device__ EIGEN_STRONG_INLINE half2 pmin(const half2& a, const half2& b) { + float a1 = __low2float(a); + float a2 = __high2float(a); + float b1 = __low2float(b); + float b2 = __high2float(b); + __half r1 = a1 < b1 ? __low2half(a) : __low2half(b); + __half r2 = a2 < b2 ? __high2half(a) : __high2half(b); + return __halves2half2(r1, r2); +} + +template<> __device__ EIGEN_STRONG_INLINE half2 pmax(const half2& a, const half2& b) { + float a1 = __low2float(a); + float a2 = __high2float(a); + float b1 = __low2float(b); + float b2 = __high2float(b); + __half r1 = a1 > b1 ? __low2half(a) : __low2half(b); + __half r2 = a2 > b2 ? __high2half(a) : __high2half(b); + return __halves2half2(r1, r2); +} + +template<> __device__ EIGEN_STRONG_INLINE Eigen::half predux(const half2& a) { +#if __CUDA_ARCH__ >= 530 + return __hadd(__low2half(a), __high2half(a)); +#else + float a1 = __low2float(a); + float a2 = __high2float(a); + return Eigen::half(half_impl::raw_uint16_to_half(__float2half_rn(a1 + a2))); +#endif +} + +template<> __device__ EIGEN_STRONG_INLINE Eigen::half predux_max(const half2& a) { +#if __CUDA_ARCH__ >= 530 + __half first = __low2half(a); + __half second = __high2half(a); + return __hgt(first, second) ? first : second; +#else + float a1 = __low2float(a); + float a2 = __high2float(a); + return a1 > a2 ? __low2half(a) : __high2half(a); +#endif +} + +template<> __device__ EIGEN_STRONG_INLINE Eigen::half predux_min(const half2& a) { +#if __CUDA_ARCH__ >= 530 + __half first = __low2half(a); + __half second = __high2half(a); + return __hlt(first, second) ? first : second; +#else + float a1 = __low2float(a); + float a2 = __high2float(a); + return a1 < a2 ? __low2half(a) : __high2half(a); +#endif +} + +template<> __device__ EIGEN_STRONG_INLINE Eigen::half predux_mul(const half2& a) { +#if __CUDA_ARCH__ >= 530 + return __hmul(__low2half(a), __high2half(a)); +#else + float a1 = __low2float(a); + float a2 = __high2float(a); + return Eigen::half(half_impl::raw_uint16_to_half(__float2half_rn(a1 * a2))); +#endif +} + +template<> __device__ EIGEN_STRONG_INLINE half2 plog1p(const half2& a) { + float a1 = __low2float(a); + float a2 = __high2float(a); + float r1 = log1pf(a1); + float r2 = log1pf(a2); + return __floats2half2_rn(r1, r2); +} + +#if defined __CUDACC_VER__ && __CUDACC_VER__ >= 80000 && defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 530 + +template<> __device__ EIGEN_STRONG_INLINE +half2 plog(const half2& a) { + return h2log(a); +} + +template<> __device__ EIGEN_STRONG_INLINE +half2 pexp(const half2& a) { + return h2exp(a); +} + +template<> __device__ EIGEN_STRONG_INLINE +half2 psqrt(const half2& a) { + return h2sqrt(a); +} + +template<> __device__ EIGEN_STRONG_INLINE +half2 prsqrt(const half2& a) { + return h2rsqrt(a); +} + +#else + +template<> __device__ EIGEN_STRONG_INLINE half2 plog(const half2& a) { + float a1 = __low2float(a); + float a2 = __high2float(a); + float r1 = logf(a1); + float r2 = logf(a2); + return __floats2half2_rn(r1, r2); +} + +template<> __device__ EIGEN_STRONG_INLINE half2 pexp(const half2& a) { + float a1 = __low2float(a); + float a2 = __high2float(a); + float r1 = expf(a1); + float r2 = expf(a2); + return __floats2half2_rn(r1, r2); +} + +template<> __device__ EIGEN_STRONG_INLINE half2 psqrt(const half2& a) { + float a1 = __low2float(a); + float a2 = __high2float(a); + float r1 = sqrtf(a1); + float r2 = sqrtf(a2); + return __floats2half2_rn(r1, r2); +} + +template<> __device__ EIGEN_STRONG_INLINE half2 prsqrt(const half2& a) { + float a1 = __low2float(a); + float a2 = __high2float(a); + float r1 = rsqrtf(a1); + float r2 = rsqrtf(a2); + return __floats2half2_rn(r1, r2); +} + +#endif + +#elif defined EIGEN_VECTORIZE_AVX512 + +typedef struct { + __m256i x; +} Packet16h; + + +template<> struct is_arithmetic { enum { value = true }; }; + +template <> +struct packet_traits : default_packet_traits { + typedef Packet16h type; + // There is no half-size packet for Packet16h. + typedef Packet16h half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size = 16, + HasHalfPacket = 0, + HasAdd = 0, + HasSub = 0, + HasMul = 0, + HasNegate = 0, + HasAbs = 0, + HasAbs2 = 0, + HasMin = 0, + HasMax = 0, + HasConj = 0, + HasSetLinear = 0, + HasDiv = 0, + HasSqrt = 0, + HasRsqrt = 0, + HasExp = 0, + HasLog = 0, + HasBlend = 0 + }; +}; + + +template<> struct unpacket_traits { typedef Eigen::half type; enum {size=16, alignment=Aligned32}; typedef Packet16h half; }; + +template<> EIGEN_STRONG_INLINE Packet16h pset1(const Eigen::half& from) { + Packet16h result; + result.x = _mm256_set1_epi16(from.x); + return result; +} + +template<> EIGEN_STRONG_INLINE Eigen::half pfirst(const Packet16h& from) { + return half_impl::raw_uint16_to_half(static_cast(_mm256_extract_epi16(from.x, 0))); +} + +template<> EIGEN_STRONG_INLINE Packet16h pload(const Eigen::half* from) { + Packet16h result; + result.x = _mm256_load_si256(reinterpret_cast(from)); + return result; +} + +template<> EIGEN_STRONG_INLINE Packet16h ploadu(const Eigen::half* from) { + Packet16h result; + result.x = _mm256_loadu_si256(reinterpret_cast(from)); + return result; +} + +template<> EIGEN_STRONG_INLINE void pstore(Eigen::half* to, const Packet16h& from) { + _mm256_store_si256((__m256i*)to, from.x); +} + +template<> EIGEN_STRONG_INLINE void pstoreu(Eigen::half* to, const Packet16h& from) { + _mm256_storeu_si256((__m256i*)to, from.x); +} + +template<> EIGEN_STRONG_INLINE Packet16h +ploadquad(const Eigen::half* from) { + Packet16h result; + unsigned short a = from[0].x; + unsigned short b = from[1].x; + unsigned short c = from[2].x; + unsigned short d = from[3].x; + result.x = _mm256_set_epi16(d, d, d, d, c, c, c, c, b, b, b, b, a, a, a, a); + return result; +} + +EIGEN_STRONG_INLINE Packet16f half2float(const Packet16h& a) { +#ifdef EIGEN_HAS_FP16_C + return _mm512_cvtph_ps(a.x); +#else + EIGEN_ALIGN64 half aux[16]; + pstore(aux, a); + float f0(aux[0]); + float f1(aux[1]); + float f2(aux[2]); + float f3(aux[3]); + float f4(aux[4]); + float f5(aux[5]); + float f6(aux[6]); + float f7(aux[7]); + float f8(aux[8]); + float f9(aux[9]); + float fa(aux[10]); + float fb(aux[11]); + float fc(aux[12]); + float fd(aux[13]); + float fe(aux[14]); + float ff(aux[15]); + + return _mm512_set_ps( + ff, fe, fd, fc, fb, fa, f9, f8, f7, f6, f5, f4, f3, f2, f1, f0); +#endif +} + +EIGEN_STRONG_INLINE Packet16h float2half(const Packet16f& a) { +#ifdef EIGEN_HAS_FP16_C + Packet16h result; + result.x = _mm512_cvtps_ph(a, _MM_FROUND_TO_NEAREST_INT|_MM_FROUND_NO_EXC); + return result; +#else + EIGEN_ALIGN64 float aux[16]; + pstore(aux, a); + half h0(aux[0]); + half h1(aux[1]); + half h2(aux[2]); + half h3(aux[3]); + half h4(aux[4]); + half h5(aux[5]); + half h6(aux[6]); + half h7(aux[7]); + half h8(aux[8]); + half h9(aux[9]); + half ha(aux[10]); + half hb(aux[11]); + half hc(aux[12]); + half hd(aux[13]); + half he(aux[14]); + half hf(aux[15]); + + Packet16h result; + result.x = _mm256_set_epi16( + hf.x, he.x, hd.x, hc.x, hb.x, ha.x, h9.x, h8.x, + h7.x, h6.x, h5.x, h4.x, h3.x, h2.x, h1.x, h0.x); + return result; +#endif +} + +template<> EIGEN_STRONG_INLINE Packet16h padd(const Packet16h& a, const Packet16h& b) { + Packet16f af = half2float(a); + Packet16f bf = half2float(b); + Packet16f rf = padd(af, bf); + return float2half(rf); +} + +template<> EIGEN_STRONG_INLINE Packet16h pmul(const Packet16h& a, const Packet16h& b) { + Packet16f af = half2float(a); + Packet16f bf = half2float(b); + Packet16f rf = pmul(af, bf); + return float2half(rf); +} + +template<> EIGEN_STRONG_INLINE half predux(const Packet16h& from) { + Packet16f from_float = half2float(from); + return half(predux(from_float)); +} + +template<> EIGEN_STRONG_INLINE Packet16h pgather(const Eigen::half* from, Index stride) +{ + Packet16h result; + result.x = _mm256_set_epi16( + from[15*stride].x, from[14*stride].x, from[13*stride].x, from[12*stride].x, + from[11*stride].x, from[10*stride].x, from[9*stride].x, from[8*stride].x, + from[7*stride].x, from[6*stride].x, from[5*stride].x, from[4*stride].x, + from[3*stride].x, from[2*stride].x, from[1*stride].x, from[0*stride].x); + return result; +} + +template<> EIGEN_STRONG_INLINE void pscatter(half* to, const Packet16h& from, Index stride) +{ + EIGEN_ALIGN64 half aux[16]; + pstore(aux, from); + to[stride*0].x = aux[0].x; + to[stride*1].x = aux[1].x; + to[stride*2].x = aux[2].x; + to[stride*3].x = aux[3].x; + to[stride*4].x = aux[4].x; + to[stride*5].x = aux[5].x; + to[stride*6].x = aux[6].x; + to[stride*7].x = aux[7].x; + to[stride*8].x = aux[8].x; + to[stride*9].x = aux[9].x; + to[stride*10].x = aux[10].x; + to[stride*11].x = aux[11].x; + to[stride*12].x = aux[12].x; + to[stride*13].x = aux[13].x; + to[stride*14].x = aux[14].x; + to[stride*15].x = aux[15].x; +} + +EIGEN_STRONG_INLINE void +ptranspose(PacketBlock& kernel) { + __m256i a = kernel.packet[0].x; + __m256i b = kernel.packet[1].x; + __m256i c = kernel.packet[2].x; + __m256i d = kernel.packet[3].x; + __m256i e = kernel.packet[4].x; + __m256i f = kernel.packet[5].x; + __m256i g = kernel.packet[6].x; + __m256i h = kernel.packet[7].x; + __m256i i = kernel.packet[8].x; + __m256i j = kernel.packet[9].x; + __m256i k = kernel.packet[10].x; + __m256i l = kernel.packet[11].x; + __m256i m = kernel.packet[12].x; + __m256i n = kernel.packet[13].x; + __m256i o = kernel.packet[14].x; + __m256i p = kernel.packet[15].x; + + __m256i ab_07 = _mm256_unpacklo_epi16(a, b); + __m256i cd_07 = _mm256_unpacklo_epi16(c, d); + __m256i ef_07 = _mm256_unpacklo_epi16(e, f); + __m256i gh_07 = _mm256_unpacklo_epi16(g, h); + __m256i ij_07 = _mm256_unpacklo_epi16(i, j); + __m256i kl_07 = _mm256_unpacklo_epi16(k, l); + __m256i mn_07 = _mm256_unpacklo_epi16(m, n); + __m256i op_07 = _mm256_unpacklo_epi16(o, p); + + __m256i ab_8f = _mm256_unpackhi_epi16(a, b); + __m256i cd_8f = _mm256_unpackhi_epi16(c, d); + __m256i ef_8f = _mm256_unpackhi_epi16(e, f); + __m256i gh_8f = _mm256_unpackhi_epi16(g, h); + __m256i ij_8f = _mm256_unpackhi_epi16(i, j); + __m256i kl_8f = _mm256_unpackhi_epi16(k, l); + __m256i mn_8f = _mm256_unpackhi_epi16(m, n); + __m256i op_8f = _mm256_unpackhi_epi16(o, p); + + __m256i abcd_03 = _mm256_unpacklo_epi32(ab_07, cd_07); + __m256i abcd_47 = _mm256_unpackhi_epi32(ab_07, cd_07); + __m256i efgh_03 = _mm256_unpacklo_epi32(ef_07, gh_07); + __m256i efgh_47 = _mm256_unpackhi_epi32(ef_07, gh_07); + __m256i ijkl_03 = _mm256_unpacklo_epi32(ij_07, kl_07); + __m256i ijkl_47 = _mm256_unpackhi_epi32(ij_07, kl_07); + __m256i mnop_03 = _mm256_unpacklo_epi32(mn_07, op_07); + __m256i mnop_47 = _mm256_unpackhi_epi32(mn_07, op_07); + + __m256i abcd_8b = _mm256_unpacklo_epi32(ab_8f, cd_8f); + __m256i abcd_cf = _mm256_unpackhi_epi32(ab_8f, cd_8f); + __m256i efgh_8b = _mm256_unpacklo_epi32(ef_8f, gh_8f); + __m256i efgh_cf = _mm256_unpackhi_epi32(ef_8f, gh_8f); + __m256i ijkl_8b = _mm256_unpacklo_epi32(ij_8f, kl_8f); + __m256i ijkl_cf = _mm256_unpackhi_epi32(ij_8f, kl_8f); + __m256i mnop_8b = _mm256_unpacklo_epi32(mn_8f, op_8f); + __m256i mnop_cf = _mm256_unpackhi_epi32(mn_8f, op_8f); + + __m256i abcdefgh_01 = _mm256_unpacklo_epi64(abcd_03, efgh_03); + __m256i abcdefgh_23 = _mm256_unpackhi_epi64(abcd_03, efgh_03); + __m256i ijklmnop_01 = _mm256_unpacklo_epi64(ijkl_03, mnop_03); + __m256i ijklmnop_23 = _mm256_unpackhi_epi64(ijkl_03, mnop_03); + __m256i abcdefgh_45 = _mm256_unpacklo_epi64(abcd_47, efgh_47); + __m256i abcdefgh_67 = _mm256_unpackhi_epi64(abcd_47, efgh_47); + __m256i ijklmnop_45 = _mm256_unpacklo_epi64(ijkl_47, mnop_47); + __m256i ijklmnop_67 = _mm256_unpackhi_epi64(ijkl_47, mnop_47); + __m256i abcdefgh_89 = _mm256_unpacklo_epi64(abcd_8b, efgh_8b); + __m256i abcdefgh_ab = _mm256_unpackhi_epi64(abcd_8b, efgh_8b); + __m256i ijklmnop_89 = _mm256_unpacklo_epi64(ijkl_8b, mnop_8b); + __m256i ijklmnop_ab = _mm256_unpackhi_epi64(ijkl_8b, mnop_8b); + __m256i abcdefgh_cd = _mm256_unpacklo_epi64(abcd_cf, efgh_cf); + __m256i abcdefgh_ef = _mm256_unpackhi_epi64(abcd_cf, efgh_cf); + __m256i ijklmnop_cd = _mm256_unpacklo_epi64(ijkl_cf, mnop_cf); + __m256i ijklmnop_ef = _mm256_unpackhi_epi64(ijkl_cf, mnop_cf); + + // NOTE: no unpacklo/hi instr in this case, so using permute instr. + __m256i a_p_0 = _mm256_permute2x128_si256(abcdefgh_01, ijklmnop_01, 0x20); + __m256i a_p_1 = _mm256_permute2x128_si256(abcdefgh_01, ijklmnop_01, 0x31); + __m256i a_p_2 = _mm256_permute2x128_si256(abcdefgh_23, ijklmnop_23, 0x20); + __m256i a_p_3 = _mm256_permute2x128_si256(abcdefgh_23, ijklmnop_23, 0x31); + __m256i a_p_4 = _mm256_permute2x128_si256(abcdefgh_45, ijklmnop_45, 0x20); + __m256i a_p_5 = _mm256_permute2x128_si256(abcdefgh_45, ijklmnop_45, 0x31); + __m256i a_p_6 = _mm256_permute2x128_si256(abcdefgh_67, ijklmnop_67, 0x20); + __m256i a_p_7 = _mm256_permute2x128_si256(abcdefgh_67, ijklmnop_67, 0x31); + __m256i a_p_8 = _mm256_permute2x128_si256(abcdefgh_89, ijklmnop_89, 0x20); + __m256i a_p_9 = _mm256_permute2x128_si256(abcdefgh_89, ijklmnop_89, 0x31); + __m256i a_p_a = _mm256_permute2x128_si256(abcdefgh_ab, ijklmnop_ab, 0x20); + __m256i a_p_b = _mm256_permute2x128_si256(abcdefgh_ab, ijklmnop_ab, 0x31); + __m256i a_p_c = _mm256_permute2x128_si256(abcdefgh_cd, ijklmnop_cd, 0x20); + __m256i a_p_d = _mm256_permute2x128_si256(abcdefgh_cd, ijklmnop_cd, 0x31); + __m256i a_p_e = _mm256_permute2x128_si256(abcdefgh_ef, ijklmnop_ef, 0x20); + __m256i a_p_f = _mm256_permute2x128_si256(abcdefgh_ef, ijklmnop_ef, 0x31); + + kernel.packet[0].x = a_p_0; + kernel.packet[1].x = a_p_1; + kernel.packet[2].x = a_p_2; + kernel.packet[3].x = a_p_3; + kernel.packet[4].x = a_p_4; + kernel.packet[5].x = a_p_5; + kernel.packet[6].x = a_p_6; + kernel.packet[7].x = a_p_7; + kernel.packet[8].x = a_p_8; + kernel.packet[9].x = a_p_9; + kernel.packet[10].x = a_p_a; + kernel.packet[11].x = a_p_b; + kernel.packet[12].x = a_p_c; + kernel.packet[13].x = a_p_d; + kernel.packet[14].x = a_p_e; + kernel.packet[15].x = a_p_f; +} + +EIGEN_STRONG_INLINE void +ptranspose(PacketBlock& kernel) { + EIGEN_ALIGN64 half in[8][16]; + pstore(in[0], kernel.packet[0]); + pstore(in[1], kernel.packet[1]); + pstore(in[2], kernel.packet[2]); + pstore(in[3], kernel.packet[3]); + pstore(in[4], kernel.packet[4]); + pstore(in[5], kernel.packet[5]); + pstore(in[6], kernel.packet[6]); + pstore(in[7], kernel.packet[7]); + + EIGEN_ALIGN64 half out[8][16]; + + for (int i = 0; i < 8; ++i) { + for (int j = 0; j < 8; ++j) { + out[i][j] = in[j][2*i]; + } + for (int j = 0; j < 8; ++j) { + out[i][j+8] = in[j][2*i+1]; + } + } + + kernel.packet[0] = pload(out[0]); + kernel.packet[1] = pload(out[1]); + kernel.packet[2] = pload(out[2]); + kernel.packet[3] = pload(out[3]); + kernel.packet[4] = pload(out[4]); + kernel.packet[5] = pload(out[5]); + kernel.packet[6] = pload(out[6]); + kernel.packet[7] = pload(out[7]); +} + +EIGEN_STRONG_INLINE void +ptranspose(PacketBlock& kernel) { + EIGEN_ALIGN64 half in[4][16]; + pstore(in[0], kernel.packet[0]); + pstore(in[1], kernel.packet[1]); + pstore(in[2], kernel.packet[2]); + pstore(in[3], kernel.packet[3]); + + EIGEN_ALIGN64 half out[4][16]; + + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + out[i][j] = in[j][4*i]; + } + for (int j = 0; j < 4; ++j) { + out[i][j+4] = in[j][4*i+1]; + } + for (int j = 0; j < 4; ++j) { + out[i][j+8] = in[j][4*i+2]; + } + for (int j = 0; j < 4; ++j) { + out[i][j+12] = in[j][4*i+3]; + } + } + + kernel.packet[0] = pload(out[0]); + kernel.packet[1] = pload(out[1]); + kernel.packet[2] = pload(out[2]); + kernel.packet[3] = pload(out[3]); +} + + +#elif defined EIGEN_VECTORIZE_AVX + +typedef struct { + __m128i x; +} Packet8h; + + +template<> struct is_arithmetic { enum { value = true }; }; + +template <> +struct packet_traits : default_packet_traits { + typedef Packet8h type; + // There is no half-size packet for Packet8h. + typedef Packet8h half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size = 8, + HasHalfPacket = 0, + HasAdd = 0, + HasSub = 0, + HasMul = 0, + HasNegate = 0, + HasAbs = 0, + HasAbs2 = 0, + HasMin = 0, + HasMax = 0, + HasConj = 0, + HasSetLinear = 0, + HasDiv = 0, + HasSqrt = 0, + HasRsqrt = 0, + HasExp = 0, + HasLog = 0, + HasBlend = 0 + }; +}; + + +template<> struct unpacket_traits { typedef Eigen::half type; enum {size=8, alignment=Aligned16}; typedef Packet8h half; }; + +template<> EIGEN_STRONG_INLINE Packet8h pset1(const Eigen::half& from) { + Packet8h result; + result.x = _mm_set1_epi16(from.x); + return result; +} + +template<> EIGEN_STRONG_INLINE Eigen::half pfirst(const Packet8h& from) { + return half_impl::raw_uint16_to_half(static_cast(_mm_extract_epi16(from.x, 0))); +} + +template<> EIGEN_STRONG_INLINE Packet8h pload(const Eigen::half* from) { + Packet8h result; + result.x = _mm_load_si128(reinterpret_cast(from)); + return result; +} + +template<> EIGEN_STRONG_INLINE Packet8h ploadu(const Eigen::half* from) { + Packet8h result; + result.x = _mm_loadu_si128(reinterpret_cast(from)); + return result; +} + +template<> EIGEN_STRONG_INLINE void pstore(Eigen::half* to, const Packet8h& from) { + _mm_store_si128(reinterpret_cast<__m128i*>(to), from.x); +} + +template<> EIGEN_STRONG_INLINE void pstoreu(Eigen::half* to, const Packet8h& from) { + _mm_storeu_si128(reinterpret_cast<__m128i*>(to), from.x); +} + +template<> EIGEN_STRONG_INLINE Packet8h +ploadquad(const Eigen::half* from) { + Packet8h result; + unsigned short a = from[0].x; + unsigned short b = from[1].x; + result.x = _mm_set_epi16(b, b, b, b, a, a, a, a); + return result; +} + +EIGEN_STRONG_INLINE Packet8f half2float(const Packet8h& a) { +#ifdef EIGEN_HAS_FP16_C + return _mm256_cvtph_ps(a.x); +#else + EIGEN_ALIGN32 Eigen::half aux[8]; + pstore(aux, a); + float f0(aux[0]); + float f1(aux[1]); + float f2(aux[2]); + float f3(aux[3]); + float f4(aux[4]); + float f5(aux[5]); + float f6(aux[6]); + float f7(aux[7]); + + return _mm256_set_ps(f7, f6, f5, f4, f3, f2, f1, f0); +#endif +} + +EIGEN_STRONG_INLINE Packet8h float2half(const Packet8f& a) { +#ifdef EIGEN_HAS_FP16_C + Packet8h result; + result.x = _mm256_cvtps_ph(a, _MM_FROUND_TO_NEAREST_INT|_MM_FROUND_NO_EXC); + return result; +#else + EIGEN_ALIGN32 float aux[8]; + pstore(aux, a); + Eigen::half h0(aux[0]); + Eigen::half h1(aux[1]); + Eigen::half h2(aux[2]); + Eigen::half h3(aux[3]); + Eigen::half h4(aux[4]); + Eigen::half h5(aux[5]); + Eigen::half h6(aux[6]); + Eigen::half h7(aux[7]); + + Packet8h result; + result.x = _mm_set_epi16(h7.x, h6.x, h5.x, h4.x, h3.x, h2.x, h1.x, h0.x); + return result; +#endif +} + +template<> EIGEN_STRONG_INLINE Packet8h pconj(const Packet8h& a) { return a; } + +template<> EIGEN_STRONG_INLINE Packet8h padd(const Packet8h& a, const Packet8h& b) { + Packet8f af = half2float(a); + Packet8f bf = half2float(b); + Packet8f rf = padd(af, bf); + return float2half(rf); +} + +template<> EIGEN_STRONG_INLINE Packet8h pmul(const Packet8h& a, const Packet8h& b) { + Packet8f af = half2float(a); + Packet8f bf = half2float(b); + Packet8f rf = pmul(af, bf); + return float2half(rf); +} + +template<> EIGEN_STRONG_INLINE Packet8h pgather(const Eigen::half* from, Index stride) +{ + Packet8h result; + result.x = _mm_set_epi16(from[7*stride].x, from[6*stride].x, from[5*stride].x, from[4*stride].x, from[3*stride].x, from[2*stride].x, from[1*stride].x, from[0*stride].x); + return result; +} + +template<> EIGEN_STRONG_INLINE void pscatter(Eigen::half* to, const Packet8h& from, Index stride) +{ + EIGEN_ALIGN32 Eigen::half aux[8]; + pstore(aux, from); + to[stride*0].x = aux[0].x; + to[stride*1].x = aux[1].x; + to[stride*2].x = aux[2].x; + to[stride*3].x = aux[3].x; + to[stride*4].x = aux[4].x; + to[stride*5].x = aux[5].x; + to[stride*6].x = aux[6].x; + to[stride*7].x = aux[7].x; +} + +template<> EIGEN_STRONG_INLINE Eigen::half predux(const Packet8h& a) { + Packet8f af = half2float(a); + float reduced = predux(af); + return Eigen::half(reduced); +} + +template<> EIGEN_STRONG_INLINE Eigen::half predux_max(const Packet8h& a) { + Packet8f af = half2float(a); + float reduced = predux_max(af); + return Eigen::half(reduced); +} + +template<> EIGEN_STRONG_INLINE Eigen::half predux_min(const Packet8h& a) { + Packet8f af = half2float(a); + float reduced = predux_min(af); + return Eigen::half(reduced); +} + +template<> EIGEN_STRONG_INLINE Eigen::half predux_mul(const Packet8h& a) { + Packet8f af = half2float(a); + float reduced = predux_mul(af); + return Eigen::half(reduced); +} + +EIGEN_STRONG_INLINE void +ptranspose(PacketBlock& kernel) { + __m128i a = kernel.packet[0].x; + __m128i b = kernel.packet[1].x; + __m128i c = kernel.packet[2].x; + __m128i d = kernel.packet[3].x; + __m128i e = kernel.packet[4].x; + __m128i f = kernel.packet[5].x; + __m128i g = kernel.packet[6].x; + __m128i h = kernel.packet[7].x; + + __m128i a03b03 = _mm_unpacklo_epi16(a, b); + __m128i c03d03 = _mm_unpacklo_epi16(c, d); + __m128i e03f03 = _mm_unpacklo_epi16(e, f); + __m128i g03h03 = _mm_unpacklo_epi16(g, h); + __m128i a47b47 = _mm_unpackhi_epi16(a, b); + __m128i c47d47 = _mm_unpackhi_epi16(c, d); + __m128i e47f47 = _mm_unpackhi_epi16(e, f); + __m128i g47h47 = _mm_unpackhi_epi16(g, h); + + __m128i a01b01c01d01 = _mm_unpacklo_epi32(a03b03, c03d03); + __m128i a23b23c23d23 = _mm_unpackhi_epi32(a03b03, c03d03); + __m128i e01f01g01h01 = _mm_unpacklo_epi32(e03f03, g03h03); + __m128i e23f23g23h23 = _mm_unpackhi_epi32(e03f03, g03h03); + __m128i a45b45c45d45 = _mm_unpacklo_epi32(a47b47, c47d47); + __m128i a67b67c67d67 = _mm_unpackhi_epi32(a47b47, c47d47); + __m128i e45f45g45h45 = _mm_unpacklo_epi32(e47f47, g47h47); + __m128i e67f67g67h67 = _mm_unpackhi_epi32(e47f47, g47h47); + + __m128i a0b0c0d0e0f0g0h0 = _mm_unpacklo_epi64(a01b01c01d01, e01f01g01h01); + __m128i a1b1c1d1e1f1g1h1 = _mm_unpackhi_epi64(a01b01c01d01, e01f01g01h01); + __m128i a2b2c2d2e2f2g2h2 = _mm_unpacklo_epi64(a23b23c23d23, e23f23g23h23); + __m128i a3b3c3d3e3f3g3h3 = _mm_unpackhi_epi64(a23b23c23d23, e23f23g23h23); + __m128i a4b4c4d4e4f4g4h4 = _mm_unpacklo_epi64(a45b45c45d45, e45f45g45h45); + __m128i a5b5c5d5e5f5g5h5 = _mm_unpackhi_epi64(a45b45c45d45, e45f45g45h45); + __m128i a6b6c6d6e6f6g6h6 = _mm_unpacklo_epi64(a67b67c67d67, e67f67g67h67); + __m128i a7b7c7d7e7f7g7h7 = _mm_unpackhi_epi64(a67b67c67d67, e67f67g67h67); + + kernel.packet[0].x = a0b0c0d0e0f0g0h0; + kernel.packet[1].x = a1b1c1d1e1f1g1h1; + kernel.packet[2].x = a2b2c2d2e2f2g2h2; + kernel.packet[3].x = a3b3c3d3e3f3g3h3; + kernel.packet[4].x = a4b4c4d4e4f4g4h4; + kernel.packet[5].x = a5b5c5d5e5f5g5h5; + kernel.packet[6].x = a6b6c6d6e6f6g6h6; + kernel.packet[7].x = a7b7c7d7e7f7g7h7; +} + +EIGEN_STRONG_INLINE void +ptranspose(PacketBlock& kernel) { + EIGEN_ALIGN32 Eigen::half in[4][8]; + pstore(in[0], kernel.packet[0]); + pstore(in[1], kernel.packet[1]); + pstore(in[2], kernel.packet[2]); + pstore(in[3], kernel.packet[3]); + + EIGEN_ALIGN32 Eigen::half out[4][8]; + + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + out[i][j] = in[j][2*i]; + } + for (int j = 0; j < 4; ++j) { + out[i][j+4] = in[j][2*i+1]; + } + } + + kernel.packet[0] = pload(out[0]); + kernel.packet[1] = pload(out[1]); + kernel.packet[2] = pload(out[2]); + kernel.packet[3] = pload(out[3]); +} + + +// Disable the following code since it's broken on too many platforms / compilers. +//#elif defined(EIGEN_VECTORIZE_SSE) && (!EIGEN_ARCH_x86_64) && (!EIGEN_COMP_MSVC) +#elif 0 + +typedef struct { + __m64 x; +} Packet4h; + + +template<> struct is_arithmetic { enum { value = true }; }; + +template <> +struct packet_traits : default_packet_traits { + typedef Packet4h type; + // There is no half-size packet for Packet4h. + typedef Packet4h half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size = 4, + HasHalfPacket = 0, + HasAdd = 0, + HasSub = 0, + HasMul = 0, + HasNegate = 0, + HasAbs = 0, + HasAbs2 = 0, + HasMin = 0, + HasMax = 0, + HasConj = 0, + HasSetLinear = 0, + HasDiv = 0, + HasSqrt = 0, + HasRsqrt = 0, + HasExp = 0, + HasLog = 0, + HasBlend = 0 + }; +}; + + +template<> struct unpacket_traits { typedef Eigen::half type; enum {size=4, alignment=Aligned16}; typedef Packet4h half; }; + +template<> EIGEN_STRONG_INLINE Packet4h pset1(const Eigen::half& from) { + Packet4h result; + result.x = _mm_set1_pi16(from.x); + return result; +} + +template<> EIGEN_STRONG_INLINE Eigen::half pfirst(const Packet4h& from) { + return half_impl::raw_uint16_to_half(static_cast(_mm_cvtsi64_si32(from.x))); +} + +template<> EIGEN_STRONG_INLINE Packet4h pconj(const Packet4h& a) { return a; } + +template<> EIGEN_STRONG_INLINE Packet4h padd(const Packet4h& a, const Packet4h& b) { + __int64_t a64 = _mm_cvtm64_si64(a.x); + __int64_t b64 = _mm_cvtm64_si64(b.x); + + Eigen::half h[4]; + + Eigen::half ha = half_impl::raw_uint16_to_half(static_cast(a64)); + Eigen::half hb = half_impl::raw_uint16_to_half(static_cast(b64)); + h[0] = ha + hb; + ha = half_impl::raw_uint16_to_half(static_cast(a64 >> 16)); + hb = half_impl::raw_uint16_to_half(static_cast(b64 >> 16)); + h[1] = ha + hb; + ha = half_impl::raw_uint16_to_half(static_cast(a64 >> 32)); + hb = half_impl::raw_uint16_to_half(static_cast(b64 >> 32)); + h[2] = ha + hb; + ha = half_impl::raw_uint16_to_half(static_cast(a64 >> 48)); + hb = half_impl::raw_uint16_to_half(static_cast(b64 >> 48)); + h[3] = ha + hb; + Packet4h result; + result.x = _mm_set_pi16(h[3].x, h[2].x, h[1].x, h[0].x); + return result; +} + +template<> EIGEN_STRONG_INLINE Packet4h pmul(const Packet4h& a, const Packet4h& b) { + __int64_t a64 = _mm_cvtm64_si64(a.x); + __int64_t b64 = _mm_cvtm64_si64(b.x); + + Eigen::half h[4]; + + Eigen::half ha = half_impl::raw_uint16_to_half(static_cast(a64)); + Eigen::half hb = half_impl::raw_uint16_to_half(static_cast(b64)); + h[0] = ha * hb; + ha = half_impl::raw_uint16_to_half(static_cast(a64 >> 16)); + hb = half_impl::raw_uint16_to_half(static_cast(b64 >> 16)); + h[1] = ha * hb; + ha = half_impl::raw_uint16_to_half(static_cast(a64 >> 32)); + hb = half_impl::raw_uint16_to_half(static_cast(b64 >> 32)); + h[2] = ha * hb; + ha = half_impl::raw_uint16_to_half(static_cast(a64 >> 48)); + hb = half_impl::raw_uint16_to_half(static_cast(b64 >> 48)); + h[3] = ha * hb; + Packet4h result; + result.x = _mm_set_pi16(h[3].x, h[2].x, h[1].x, h[0].x); + return result; +} + +template<> EIGEN_STRONG_INLINE Packet4h pload(const Eigen::half* from) { + Packet4h result; + result.x = _mm_cvtsi64_m64(*reinterpret_cast(from)); + return result; +} + +template<> EIGEN_STRONG_INLINE Packet4h ploadu(const Eigen::half* from) { + Packet4h result; + result.x = _mm_cvtsi64_m64(*reinterpret_cast(from)); + return result; +} + +template<> EIGEN_STRONG_INLINE void pstore(Eigen::half* to, const Packet4h& from) { + __int64_t r = _mm_cvtm64_si64(from.x); + *(reinterpret_cast<__int64_t*>(to)) = r; +} + +template<> EIGEN_STRONG_INLINE void pstoreu(Eigen::half* to, const Packet4h& from) { + __int64_t r = _mm_cvtm64_si64(from.x); + *(reinterpret_cast<__int64_t*>(to)) = r; +} + +template<> EIGEN_STRONG_INLINE Packet4h +ploadquad(const Eigen::half* from) { + return pset1(*from); +} + +template<> EIGEN_STRONG_INLINE Packet4h pgather(const Eigen::half* from, Index stride) +{ + Packet4h result; + result.x = _mm_set_pi16(from[3*stride].x, from[2*stride].x, from[1*stride].x, from[0*stride].x); + return result; +} + +template<> EIGEN_STRONG_INLINE void pscatter(Eigen::half* to, const Packet4h& from, Index stride) +{ + __int64_t a = _mm_cvtm64_si64(from.x); + to[stride*0].x = static_cast(a); + to[stride*1].x = static_cast(a >> 16); + to[stride*2].x = static_cast(a >> 32); + to[stride*3].x = static_cast(a >> 48); +} + +EIGEN_STRONG_INLINE void +ptranspose(PacketBlock& kernel) { + __m64 T0 = _mm_unpacklo_pi16(kernel.packet[0].x, kernel.packet[1].x); + __m64 T1 = _mm_unpacklo_pi16(kernel.packet[2].x, kernel.packet[3].x); + __m64 T2 = _mm_unpackhi_pi16(kernel.packet[0].x, kernel.packet[1].x); + __m64 T3 = _mm_unpackhi_pi16(kernel.packet[2].x, kernel.packet[3].x); + + kernel.packet[0].x = _mm_unpacklo_pi32(T0, T1); + kernel.packet[1].x = _mm_unpackhi_pi32(T0, T1); + kernel.packet[2].x = _mm_unpacklo_pi32(T2, T3); + kernel.packet[3].x = _mm_unpackhi_pi32(T2, T3); +} + +#endif + +} +} + +#endif // EIGEN_PACKET_MATH_HALF_CUDA_H diff --git a/libs/eigen3/Eigen/src/Core/arch/CUDA/TypeCasting.h b/libs/eigen3/Eigen/src/Core/arch/CUDA/TypeCasting.h new file mode 100644 index 000000000..aa5fbce8e --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/arch/CUDA/TypeCasting.h @@ -0,0 +1,212 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2016 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_TYPE_CASTING_CUDA_H +#define EIGEN_TYPE_CASTING_CUDA_H + +namespace Eigen { + +namespace internal { + +template<> +struct scalar_cast_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cast_op) + typedef Eigen::half result_type; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Eigen::half operator() (const float& a) const { + #if defined(EIGEN_HAS_CUDA_FP16) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 300 + return __float2half(a); + #else + return Eigen::half(a); + #endif + } +}; + +template<> +struct functor_traits > +{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; + + +template<> +struct scalar_cast_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cast_op) + typedef Eigen::half result_type; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Eigen::half operator() (const int& a) const { + #if defined(EIGEN_HAS_CUDA_FP16) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 300 + return __float2half(static_cast(a)); + #else + return Eigen::half(static_cast(a)); + #endif + } +}; + +template<> +struct functor_traits > +{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; + + +template<> +struct scalar_cast_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cast_op) + typedef float result_type; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float operator() (const Eigen::half& a) const { + #if defined(EIGEN_HAS_CUDA_FP16) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 300 + return __half2float(a); + #else + return static_cast(a); + #endif + } +}; + +template<> +struct functor_traits > +{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; + + + +#if defined(EIGEN_HAS_CUDA_FP16) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 300 + +template <> +struct type_casting_traits { + enum { + VectorizedCast = 1, + SrcCoeffRatio = 2, + TgtCoeffRatio = 1 + }; +}; + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pcast(const half2& a, const half2& b) { + float2 r1 = __half22float2(a); + float2 r2 = __half22float2(b); + return make_float4(r1.x, r1.y, r2.x, r2.y); +} + +template <> +struct type_casting_traits { + enum { + VectorizedCast = 1, + SrcCoeffRatio = 1, + TgtCoeffRatio = 2 + }; +}; + +template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pcast(const float4& a) { + // Simply discard the second half of the input + return __floats2half2_rn(a.x, a.y); +} + +#elif defined EIGEN_VECTORIZE_AVX512 +template <> +struct type_casting_traits { + enum { + VectorizedCast = 1, + SrcCoeffRatio = 1, + TgtCoeffRatio = 1 + }; +}; + +template<> EIGEN_STRONG_INLINE Packet16f pcast(const Packet16h& a) { + return half2float(a); +} + +template <> +struct type_casting_traits { + enum { + VectorizedCast = 1, + SrcCoeffRatio = 1, + TgtCoeffRatio = 1 + }; +}; + +template<> EIGEN_STRONG_INLINE Packet16h pcast(const Packet16f& a) { + return float2half(a); +} + +#elif defined EIGEN_VECTORIZE_AVX + +template <> +struct type_casting_traits { + enum { + VectorizedCast = 1, + SrcCoeffRatio = 1, + TgtCoeffRatio = 1 + }; +}; + +template<> EIGEN_STRONG_INLINE Packet8f pcast(const Packet8h& a) { + return half2float(a); +} + +template <> +struct type_casting_traits { + enum { + VectorizedCast = 1, + SrcCoeffRatio = 1, + TgtCoeffRatio = 1 + }; +}; + +template<> EIGEN_STRONG_INLINE Packet8h pcast(const Packet8f& a) { + return float2half(a); +} + +// Disable the following code since it's broken on too many platforms / compilers. +//#elif defined(EIGEN_VECTORIZE_SSE) && (!EIGEN_ARCH_x86_64) && (!EIGEN_COMP_MSVC) +#elif 0 + +template <> +struct type_casting_traits { + enum { + VectorizedCast = 1, + SrcCoeffRatio = 1, + TgtCoeffRatio = 1 + }; +}; + +template<> EIGEN_STRONG_INLINE Packet4f pcast(const Packet4h& a) { + __int64_t a64 = _mm_cvtm64_si64(a.x); + Eigen::half h = raw_uint16_to_half(static_cast(a64)); + float f1 = static_cast(h); + h = raw_uint16_to_half(static_cast(a64 >> 16)); + float f2 = static_cast(h); + h = raw_uint16_to_half(static_cast(a64 >> 32)); + float f3 = static_cast(h); + h = raw_uint16_to_half(static_cast(a64 >> 48)); + float f4 = static_cast(h); + return _mm_set_ps(f4, f3, f2, f1); +} + +template <> +struct type_casting_traits { + enum { + VectorizedCast = 1, + SrcCoeffRatio = 1, + TgtCoeffRatio = 1 + }; +}; + +template<> EIGEN_STRONG_INLINE Packet4h pcast(const Packet4f& a) { + EIGEN_ALIGN16 float aux[4]; + pstore(aux, a); + Eigen::half h0(aux[0]); + Eigen::half h1(aux[1]); + Eigen::half h2(aux[2]); + Eigen::half h3(aux[3]); + + Packet4h result; + result.x = _mm_set_pi16(h3.x, h2.x, h1.x, h0.x); + return result; +} + +#endif + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_TYPE_CASTING_CUDA_H diff --git a/libs/eigen3/Eigen/src/Core/arch/NEON/Complex.h b/libs/eigen3/Eigen/src/Core/arch/NEON/Complex.h index f183d31de..57e9b431f 100644 --- a/libs/eigen3/Eigen/src/Core/arch/NEON/Complex.h +++ b/libs/eigen3/Eigen/src/Core/arch/NEON/Complex.h @@ -2,6 +2,7 @@ // for linear algebra. // // Copyright (C) 2010 Gael Guennebaud +// Copyright (C) 2010 Konstantinos Margaritis // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -14,8 +15,21 @@ namespace Eigen { namespace internal { -static uint32x4_t p4ui_CONJ_XOR = EIGEN_INIT_NEON_PACKET4(0x00000000, 0x80000000, 0x00000000, 0x80000000); -static uint32x2_t p2ui_CONJ_XOR = EIGEN_INIT_NEON_PACKET2(0x00000000, 0x80000000); +inline uint32x4_t p4ui_CONJ_XOR() { +// See bug 1325, clang fails to call vld1q_u64. +#if EIGEN_COMP_CLANG + uint32x4_t ret = { 0x00000000, 0x80000000, 0x00000000, 0x80000000 }; + return ret; +#else + static const uint32_t conj_XOR_DATA[] = { 0x00000000, 0x80000000, 0x00000000, 0x80000000 }; + return vld1q_u32( conj_XOR_DATA ); +#endif +} + +inline uint32x2_t p2ui_CONJ_XOR() { + static const uint32_t conj_XOR_DATA[] = { 0x00000000, 0x80000000 }; + return vld1_u32( conj_XOR_DATA ); +} //---------- float ---------- struct Packet2cf @@ -28,10 +42,12 @@ struct Packet2cf template<> struct packet_traits > : default_packet_traits { typedef Packet2cf type; + typedef Packet2cf half; enum { Vectorizable = 1, AlignedOnScalar = 1, size = 2, + HasHalfPacket = 0, HasAdd = 1, HasSub = 1, @@ -46,7 +62,7 @@ template<> struct packet_traits > : default_packet_traits }; }; -template<> struct unpacket_traits { typedef std::complex type; enum {size=2}; }; +template<> struct unpacket_traits { typedef std::complex type; enum {size=2, alignment=Aligned16}; typedef Packet2cf half; }; template<> EIGEN_STRONG_INLINE Packet2cf pset1(const std::complex& from) { @@ -62,7 +78,7 @@ template<> EIGEN_STRONG_INLINE Packet2cf pnegate(const Packet2cf& a) { return Pa template<> EIGEN_STRONG_INLINE Packet2cf pconj(const Packet2cf& a) { Packet4ui b = vreinterpretq_u32_f32(a.v); - return Packet2cf(vreinterpretq_f32_u32(veorq_u32(b, p4ui_CONJ_XOR))); + return Packet2cf(vreinterpretq_f32_u32(veorq_u32(b, p4ui_CONJ_XOR()))); } template<> EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, const Packet2cf& b) @@ -71,14 +87,14 @@ template<> EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, con // Get the real values of a | a1_re | a1_re | a2_re | a2_re | v1 = vcombine_f32(vdup_lane_f32(vget_low_f32(a.v), 0), vdup_lane_f32(vget_high_f32(a.v), 0)); - // Get the real values of a | a1_im | a1_im | a2_im | a2_im | + // Get the imag values of a | a1_im | a1_im | a2_im | a2_im | v2 = vcombine_f32(vdup_lane_f32(vget_low_f32(a.v), 1), vdup_lane_f32(vget_high_f32(a.v), 1)); // Multiply the real a with b v1 = vmulq_f32(v1, b.v); // Multiply the imag a with b v2 = vmulq_f32(v2, b.v); // Conjugate v2 - v2 = vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(v2), p4ui_CONJ_XOR)); + v2 = vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(v2), p4ui_CONJ_XOR())); // Swap real/imag elements in v2. v2 = vrev64q_f32(v2); // Add and return the result @@ -87,7 +103,7 @@ template<> EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, con template<> EIGEN_STRONG_INLINE Packet2cf pand (const Packet2cf& a, const Packet2cf& b) { - return Packet2cf(vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(a.v),vreinterpretq_u32_f32(b.v)))); + return Packet2cf(vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(a.v),vreinterpretq_u32_f32(b.v)))); } template<> EIGEN_STRONG_INLINE Packet2cf por (const Packet2cf& a, const Packet2cf& b) { @@ -110,7 +126,23 @@ template<> EIGEN_STRONG_INLINE Packet2cf ploaddup(const std::complex< template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet2cf& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((float*)to, from.v); } template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet2cf& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((float*)to, from.v); } -template<> EIGEN_STRONG_INLINE void prefetch >(const std::complex * addr) { __pld((float *)addr); } +template<> EIGEN_DEVICE_FUNC inline Packet2cf pgather, Packet2cf>(const std::complex* from, Index stride) +{ + Packet4f res = pset1(0.f); + res = vsetq_lane_f32(std::real(from[0*stride]), res, 0); + res = vsetq_lane_f32(std::imag(from[0*stride]), res, 1); + res = vsetq_lane_f32(std::real(from[1*stride]), res, 2); + res = vsetq_lane_f32(std::imag(from[1*stride]), res, 3); + return Packet2cf(res); +} + +template<> EIGEN_DEVICE_FUNC inline void pscatter, Packet2cf>(std::complex* to, const Packet2cf& from, Index stride) +{ + to[stride*0] = std::complex(vgetq_lane_f32(from.v, 0), vgetq_lane_f32(from.v, 1)); + to[stride*1] = std::complex(vgetq_lane_f32(from.v, 2), vgetq_lane_f32(from.v, 3)); +} + +template<> EIGEN_STRONG_INLINE void prefetch >(const std::complex * addr) { EIGEN_ARM_PREFETCH((float *)addr); } template<> EIGEN_STRONG_INLINE std::complex pfirst(const Packet2cf& a) { @@ -177,7 +209,7 @@ template<> EIGEN_STRONG_INLINE std::complex predux_mul(const P // Multiply the imag a with b v2 = vmul_f32(v2, a2); // Conjugate v2 - v2 = vreinterpret_f32_u32(veor_u32(vreinterpret_u32_f32(v2), p2ui_CONJ_XOR)); + v2 = vreinterpret_f32_u32(veor_u32(vreinterpret_u32_f32(v2), p2ui_CONJ_XOR())); // Swap real/imag elements in v2. v2 = vrev64_f32(v2); // Add v1, v2 @@ -235,7 +267,7 @@ template<> struct conj_helper template<> EIGEN_STRONG_INLINE Packet2cf pdiv(const Packet2cf& a, const Packet2cf& b) { - // TODO optimize it for AltiVec + // TODO optimize it for NEON Packet2cf res = conj_helper().pmul(a,b); Packet4f s, rev_s; @@ -246,6 +278,207 @@ template<> EIGEN_STRONG_INLINE Packet2cf pdiv(const Packet2cf& a, con return Packet2cf(pdiv(res.v, vaddq_f32(s,rev_s))); } +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + Packet4f tmp = vcombine_f32(vget_high_f32(kernel.packet[0].v), vget_high_f32(kernel.packet[1].v)); + kernel.packet[0].v = vcombine_f32(vget_low_f32(kernel.packet[0].v), vget_low_f32(kernel.packet[1].v)); + kernel.packet[1].v = tmp; +} + +//---------- double ---------- +#if EIGEN_ARCH_ARM64 && !EIGEN_APPLE_DOUBLE_NEON_BUG + +// See bug 1325, clang fails to call vld1q_u64. +#if EIGEN_COMP_CLANG + static uint64x2_t p2ul_CONJ_XOR = {0x0, 0x8000000000000000}; +#else + const uint64_t p2ul_conj_XOR_DATA[] = { 0x0, 0x8000000000000000 }; + static uint64x2_t p2ul_CONJ_XOR = vld1q_u64( p2ul_conj_XOR_DATA ); +#endif + +struct Packet1cd +{ + EIGEN_STRONG_INLINE Packet1cd() {} + EIGEN_STRONG_INLINE explicit Packet1cd(const Packet2d& a) : v(a) {} + Packet2d v; +}; + +template<> struct packet_traits > : default_packet_traits +{ + typedef Packet1cd type; + typedef Packet1cd half; + enum { + Vectorizable = 1, + AlignedOnScalar = 0, + size = 1, + HasHalfPacket = 0, + + HasAdd = 1, + HasSub = 1, + HasMul = 1, + HasDiv = 1, + HasNegate = 1, + HasAbs = 0, + HasAbs2 = 0, + HasMin = 0, + HasMax = 0, + HasSetLinear = 0 + }; +}; + +template<> struct unpacket_traits { typedef std::complex type; enum {size=1, alignment=Aligned16}; typedef Packet1cd half; }; + +template<> EIGEN_STRONG_INLINE Packet1cd pload(const std::complex* from) { EIGEN_DEBUG_ALIGNED_LOAD return Packet1cd(pload((const double*)from)); } +template<> EIGEN_STRONG_INLINE Packet1cd ploadu(const std::complex* from) { EIGEN_DEBUG_UNALIGNED_LOAD return Packet1cd(ploadu((const double*)from)); } + +template<> EIGEN_STRONG_INLINE Packet1cd pset1(const std::complex& from) +{ /* here we really have to use unaligned loads :( */ return ploadu(&from); } + +template<> EIGEN_STRONG_INLINE Packet1cd padd(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(padd(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd psub(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(psub(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd pnegate(const Packet1cd& a) { return Packet1cd(pnegate(a.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd pconj(const Packet1cd& a) { return Packet1cd(vreinterpretq_f64_u64(veorq_u64(vreinterpretq_u64_f64(a.v), p2ul_CONJ_XOR))); } + +template<> EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) +{ + Packet2d v1, v2; + + // Get the real values of a + v1 = vdupq_lane_f64(vget_low_f64(a.v), 0); + // Get the imag values of a + v2 = vdupq_lane_f64(vget_high_f64(a.v), 0); + // Multiply the real a with b + v1 = vmulq_f64(v1, b.v); + // Multiply the imag a with b + v2 = vmulq_f64(v2, b.v); + // Conjugate v2 + v2 = vreinterpretq_f64_u64(veorq_u64(vreinterpretq_u64_f64(v2), p2ul_CONJ_XOR)); + // Swap real/imag elements in v2. + v2 = preverse(v2); + // Add and return the result + return Packet1cd(vaddq_f64(v1, v2)); +} + +template<> EIGEN_STRONG_INLINE Packet1cd pand (const Packet1cd& a, const Packet1cd& b) +{ + return Packet1cd(vreinterpretq_f64_u64(vandq_u64(vreinterpretq_u64_f64(a.v),vreinterpretq_u64_f64(b.v)))); +} +template<> EIGEN_STRONG_INLINE Packet1cd por (const Packet1cd& a, const Packet1cd& b) +{ + return Packet1cd(vreinterpretq_f64_u64(vorrq_u64(vreinterpretq_u64_f64(a.v),vreinterpretq_u64_f64(b.v)))); +} +template<> EIGEN_STRONG_INLINE Packet1cd pxor (const Packet1cd& a, const Packet1cd& b) +{ + return Packet1cd(vreinterpretq_f64_u64(veorq_u64(vreinterpretq_u64_f64(a.v),vreinterpretq_u64_f64(b.v)))); +} +template<> EIGEN_STRONG_INLINE Packet1cd pandnot(const Packet1cd& a, const Packet1cd& b) +{ + return Packet1cd(vreinterpretq_f64_u64(vbicq_u64(vreinterpretq_u64_f64(a.v),vreinterpretq_u64_f64(b.v)))); +} + +template<> EIGEN_STRONG_INLINE Packet1cd ploaddup(const std::complex* from) { return pset1(*from); } + +template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet1cd& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((double*)to, from.v); } +template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet1cd& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, from.v); } + +template<> EIGEN_STRONG_INLINE void prefetch >(const std::complex * addr) { EIGEN_ARM_PREFETCH((double *)addr); } + +template<> EIGEN_DEVICE_FUNC inline Packet1cd pgather, Packet1cd>(const std::complex* from, Index stride) +{ + Packet2d res = pset1(0.0); + res = vsetq_lane_f64(std::real(from[0*stride]), res, 0); + res = vsetq_lane_f64(std::imag(from[0*stride]), res, 1); + return Packet1cd(res); +} + +template<> EIGEN_DEVICE_FUNC inline void pscatter, Packet1cd>(std::complex* to, const Packet1cd& from, Index stride) +{ + to[stride*0] = std::complex(vgetq_lane_f64(from.v, 0), vgetq_lane_f64(from.v, 1)); +} + + +template<> EIGEN_STRONG_INLINE std::complex pfirst(const Packet1cd& a) +{ + std::complex EIGEN_ALIGN16 res; + pstore >(&res, a); + + return res; +} + +template<> EIGEN_STRONG_INLINE Packet1cd preverse(const Packet1cd& a) { return a; } + +template<> EIGEN_STRONG_INLINE std::complex predux(const Packet1cd& a) { return pfirst(a); } + +template<> EIGEN_STRONG_INLINE Packet1cd preduxp(const Packet1cd* vecs) { return vecs[0]; } + +template<> EIGEN_STRONG_INLINE std::complex predux_mul(const Packet1cd& a) { return pfirst(a); } + +template +struct palign_impl +{ + static EIGEN_STRONG_INLINE void run(Packet1cd& /*first*/, const Packet1cd& /*second*/) + { + // FIXME is it sure we never have to align a Packet1cd? + // Even though a std::complex has 16 bytes, it is not necessarily aligned on a 16 bytes boundary... + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet1cd& y, const Packet1cd& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) const + { + return internal::pmul(a, pconj(b)); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet1cd& y, const Packet1cd& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) const + { + return internal::pmul(pconj(a), b); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet1cd& y, const Packet1cd& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) const + { + return pconj(internal::pmul(a, b)); + } +}; + +template<> EIGEN_STRONG_INLINE Packet1cd pdiv(const Packet1cd& a, const Packet1cd& b) +{ + // TODO optimize it for NEON + Packet1cd res = conj_helper().pmul(a,b); + Packet2d s = pmul(b.v, b.v); + Packet2d rev_s = preverse(s); + + return Packet1cd(pdiv(res.v, padd(s,rev_s))); +} + +EIGEN_STRONG_INLINE Packet1cd pcplxflip/**/(const Packet1cd& x) +{ + return Packet1cd(preverse(Packet2d(x.v))); +} + +EIGEN_STRONG_INLINE void ptranspose(PacketBlock& kernel) +{ + Packet2d tmp = vcombine_f64(vget_high_f64(kernel.packet[0].v), vget_high_f64(kernel.packet[1].v)); + kernel.packet[0].v = vcombine_f64(vget_low_f64(kernel.packet[0].v), vget_low_f64(kernel.packet[1].v)); + kernel.packet[1].v = tmp; +} +#endif // EIGEN_ARCH_ARM64 + } // end namespace internal } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/Core/arch/NEON/MathFunctions.h b/libs/eigen3/Eigen/src/Core/arch/NEON/MathFunctions.h new file mode 100644 index 000000000..6bb05bb92 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/arch/NEON/MathFunctions.h @@ -0,0 +1,91 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +/* The sin, cos, exp, and log functions of this file come from + * Julien Pommier's sse math library: http://gruntthepeon.free.fr/ssemath/ + */ + +#ifndef EIGEN_MATH_FUNCTIONS_NEON_H +#define EIGEN_MATH_FUNCTIONS_NEON_H + +namespace Eigen { + +namespace internal { + +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet4f pexp(const Packet4f& _x) +{ + Packet4f x = _x; + Packet4f tmp, fx; + + _EIGEN_DECLARE_CONST_Packet4f(1 , 1.0f); + _EIGEN_DECLARE_CONST_Packet4f(half, 0.5f); + _EIGEN_DECLARE_CONST_Packet4i(0x7f, 0x7f); + _EIGEN_DECLARE_CONST_Packet4f(exp_hi, 88.3762626647950f); + _EIGEN_DECLARE_CONST_Packet4f(exp_lo, -88.3762626647949f); + _EIGEN_DECLARE_CONST_Packet4f(cephes_LOG2EF, 1.44269504088896341f); + _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_C1, 0.693359375f); + _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_C2, -2.12194440e-4f); + _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p0, 1.9875691500E-4f); + _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p1, 1.3981999507E-3f); + _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p2, 8.3334519073E-3f); + _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p3, 4.1665795894E-2f); + _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p4, 1.6666665459E-1f); + _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p5, 5.0000001201E-1f); + + x = vminq_f32(x, p4f_exp_hi); + x = vmaxq_f32(x, p4f_exp_lo); + + /* express exp(x) as exp(g + n*log(2)) */ + fx = vmlaq_f32(p4f_half, x, p4f_cephes_LOG2EF); + + /* perform a floorf */ + tmp = vcvtq_f32_s32(vcvtq_s32_f32(fx)); + + /* if greater, substract 1 */ + Packet4ui mask = vcgtq_f32(tmp, fx); + mask = vandq_u32(mask, vreinterpretq_u32_f32(p4f_1)); + + fx = vsubq_f32(tmp, vreinterpretq_f32_u32(mask)); + + tmp = vmulq_f32(fx, p4f_cephes_exp_C1); + Packet4f z = vmulq_f32(fx, p4f_cephes_exp_C2); + x = vsubq_f32(x, tmp); + x = vsubq_f32(x, z); + + Packet4f y = vmulq_f32(p4f_cephes_exp_p0, x); + z = vmulq_f32(x, x); + y = vaddq_f32(y, p4f_cephes_exp_p1); + y = vmulq_f32(y, x); + y = vaddq_f32(y, p4f_cephes_exp_p2); + y = vmulq_f32(y, x); + y = vaddq_f32(y, p4f_cephes_exp_p3); + y = vmulq_f32(y, x); + y = vaddq_f32(y, p4f_cephes_exp_p4); + y = vmulq_f32(y, x); + y = vaddq_f32(y, p4f_cephes_exp_p5); + + y = vmulq_f32(y, z); + y = vaddq_f32(y, x); + y = vaddq_f32(y, p4f_1); + + /* build 2^n */ + int32x4_t mm; + mm = vcvtq_s32_f32(fx); + mm = vaddq_s32(mm, p4i_0x7f); + mm = vshlq_n_s32(mm, 23); + Packet4f pow2n = vreinterpretq_f32_s32(mm); + + y = vmulq_f32(y, pow2n); + return y; +} + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_MATH_FUNCTIONS_NEON_H diff --git a/libs/eigen3/Eigen/src/Core/arch/NEON/PacketMath.h b/libs/eigen3/Eigen/src/Core/arch/NEON/PacketMath.h index 163bac215..836fbc0dd 100644 --- a/libs/eigen3/Eigen/src/Core/arch/NEON/PacketMath.h +++ b/libs/eigen3/Eigen/src/Core/arch/NEON/PacketMath.h @@ -2,7 +2,7 @@ // for linear algebra. // // Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2010 Konstantinos Margaritis +// Copyright (C) 2010 Konstantinos Margaritis // Heavily based on Gael's SSE version. // // This Source Code Form is subject to the terms of the Mozilla @@ -20,89 +20,110 @@ namespace internal { #define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 8 #endif -// FIXME NEON has 16 quad registers, but since the current register allocator -// is so bad, it is much better to reduce it to 8 +#ifndef EIGEN_HAS_SINGLE_INSTRUCTION_MADD +#define EIGEN_HAS_SINGLE_INSTRUCTION_MADD +#endif + +#ifndef EIGEN_HAS_SINGLE_INSTRUCTION_CJMADD +#define EIGEN_HAS_SINGLE_INSTRUCTION_CJMADD +#endif + #ifndef EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS -#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 8 +#if EIGEN_ARCH_ARM64 +#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 32 +#else +#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 16 +#endif #endif +typedef float32x2_t Packet2f; typedef float32x4_t Packet4f; typedef int32x4_t Packet4i; +typedef int32x2_t Packet2i; typedef uint32x4_t Packet4ui; #define _EIGEN_DECLARE_CONST_Packet4f(NAME,X) \ const Packet4f p4f_##NAME = pset1(X) #define _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(NAME,X) \ - const Packet4f p4f_##NAME = vreinterpretq_f32_u32(pset1(X)) + const Packet4f p4f_##NAME = vreinterpretq_f32_u32(pset1(X)) #define _EIGEN_DECLARE_CONST_Packet4i(NAME,X) \ const Packet4i p4i_##NAME = pset1(X) -#if defined(__llvm__) && !defined(__clang__) - //Special treatment for Apple's llvm-gcc, its NEON packet types are unions - #define EIGEN_INIT_NEON_PACKET2(X, Y) {{X, Y}} - #define EIGEN_INIT_NEON_PACKET4(X, Y, Z, W) {{X, Y, Z, W}} +#if EIGEN_ARCH_ARM64 + // __builtin_prefetch tends to do nothing on ARM64 compilers because the + // prefetch instructions there are too detailed for __builtin_prefetch to map + // meaningfully to them. + #define EIGEN_ARM_PREFETCH(ADDR) __asm__ __volatile__("prfm pldl1keep, [%[addr]]\n" ::[addr] "r"(ADDR) : ); +#elif EIGEN_HAS_BUILTIN(__builtin_prefetch) || EIGEN_COMP_GNUC + #define EIGEN_ARM_PREFETCH(ADDR) __builtin_prefetch(ADDR); +#elif defined __pld + #define EIGEN_ARM_PREFETCH(ADDR) __pld(ADDR) +#elif EIGEN_ARCH_ARM32 + #define EIGEN_ARM_PREFETCH(ADDR) __asm__ __volatile__ ("pld [%[addr]]\n" :: [addr] "r" (ADDR) : ); #else - //Default initializer for packets - #define EIGEN_INIT_NEON_PACKET2(X, Y) {X, Y} - #define EIGEN_INIT_NEON_PACKET4(X, Y, Z, W) {X, Y, Z, W} -#endif - -#ifndef __pld -#define __pld(x) asm volatile ( " pld [%[addr]]\n" :: [addr] "r" (x) : "cc" ); + // by default no explicit prefetching + #define EIGEN_ARM_PREFETCH(ADDR) #endif template<> struct packet_traits : default_packet_traits { typedef Packet4f type; + typedef Packet4f half; // Packet2f intrinsics not implemented yet enum { Vectorizable = 1, AlignedOnScalar = 1, size = 4, + HasHalfPacket=0, // Packet2f intrinsics not implemented yet HasDiv = 1, // FIXME check the Has* HasSin = 0, HasCos = 0, HasLog = 0, - HasExp = 0, + HasExp = 1, HasSqrt = 0 }; }; -template<> struct packet_traits : default_packet_traits +template<> struct packet_traits : default_packet_traits { typedef Packet4i type; + typedef Packet4i half; // Packet2i intrinsics not implemented yet enum { Vectorizable = 1, AlignedOnScalar = 1, - size=4 + size=4, + HasHalfPacket=0 // Packet2i intrinsics not implemented yet // FIXME check the Has* }; }; -#if EIGEN_GNUC_AT_MOST(4,4) && !defined(__llvm__) +#if EIGEN_GNUC_AT_MOST(4,4) && !EIGEN_COMP_LLVM // workaround gcc 4.2, 4.3 and 4.4 compilatin issue EIGEN_STRONG_INLINE float32x4_t vld1q_f32(const float* x) { return ::vld1q_f32((const float32_t*)x); } EIGEN_STRONG_INLINE float32x2_t vld1_f32 (const float* x) { return ::vld1_f32 ((const float32_t*)x); } +EIGEN_STRONG_INLINE float32x2_t vld1_dup_f32 (const float* x) { return ::vld1_dup_f32 ((const float32_t*)x); } EIGEN_STRONG_INLINE void vst1q_f32(float* to, float32x4_t from) { ::vst1q_f32((float32_t*)to,from); } EIGEN_STRONG_INLINE void vst1_f32 (float* to, float32x2_t from) { ::vst1_f32 ((float32_t*)to,from); } #endif -template<> struct unpacket_traits { typedef float type; enum {size=4}; }; -template<> struct unpacket_traits { typedef int type; enum {size=4}; }; +template<> struct unpacket_traits { typedef float type; enum {size=4, alignment=Aligned16}; typedef Packet4f half; }; +template<> struct unpacket_traits { typedef int32_t type; enum {size=4, alignment=Aligned16}; typedef Packet4i half; }; template<> EIGEN_STRONG_INLINE Packet4f pset1(const float& from) { return vdupq_n_f32(from); } -template<> EIGEN_STRONG_INLINE Packet4i pset1(const int& from) { return vdupq_n_s32(from); } +template<> EIGEN_STRONG_INLINE Packet4i pset1(const int32_t& from) { return vdupq_n_s32(from); } -template<> EIGEN_STRONG_INLINE Packet4f plset(const float& a) +template<> EIGEN_STRONG_INLINE Packet4f plset(const float& a) { - Packet4f countdown = EIGEN_INIT_NEON_PACKET4(0, 1, 2, 3); + const float f[] = {0, 1, 2, 3}; + Packet4f countdown = vld1q_f32(f); return vaddq_f32(pset1(a), countdown); } -template<> EIGEN_STRONG_INLINE Packet4i plset(const int& a) +template<> EIGEN_STRONG_INLINE Packet4i plset(const int32_t& a) { - Packet4i countdown = EIGEN_INIT_NEON_PACKET4(0, 1, 2, 3); + const int32_t i[] = {0, 1, 2, 3}; + Packet4i countdown = vld1q_s32(i); return vaddq_s32(pset1(a), countdown); } @@ -123,6 +144,9 @@ template<> EIGEN_STRONG_INLINE Packet4i pmul(const Packet4i& a, const template<> EIGEN_STRONG_INLINE Packet4f pdiv(const Packet4f& a, const Packet4f& b) { +#if EIGEN_ARCH_ARM64 + return vdivq_f32(a,b); +#else Packet4f inv, restep, div; // NEON does not offer a divide instruction, we have to do a reciprocal approximation @@ -141,14 +165,51 @@ template<> EIGEN_STRONG_INLINE Packet4f pdiv(const Packet4f& a, const div = vmulq_f32(a, inv); return div; +#endif } + template<> EIGEN_STRONG_INLINE Packet4i pdiv(const Packet4i& /*a*/, const Packet4i& /*b*/) { eigen_assert(false && "packet integer division are not supported by NEON"); return pset1(0); } -// for some weird raisons, it has to be overloaded for packet of integers -template<> EIGEN_STRONG_INLINE Packet4f pmadd(const Packet4f& a, const Packet4f& b, const Packet4f& c) { return vmlaq_f32(c,a,b); } +// Clang/ARM wrongly advertises __ARM_FEATURE_FMA even when it's not available, +// then implements a slow software scalar fallback calling fmaf()! +// Filed LLVM bug: +// https://llvm.org/bugs/show_bug.cgi?id=27216 +#if (defined __ARM_FEATURE_FMA) && !(EIGEN_COMP_CLANG && EIGEN_ARCH_ARM) +// See bug 936. +// FMA is available on VFPv4 i.e. when compiling with -mfpu=neon-vfpv4. +// FMA is a true fused multiply-add i.e. only 1 rounding at the end, no intermediate rounding. +// MLA is not fused i.e. does 2 roundings. +// In addition to giving better accuracy, FMA also gives better performance here on a Krait (Nexus 4): +// MLA: 10 GFlop/s ; FMA: 12 GFlops/s. +template<> EIGEN_STRONG_INLINE Packet4f pmadd(const Packet4f& a, const Packet4f& b, const Packet4f& c) { return vfmaq_f32(c,a,b); } +#else +template<> EIGEN_STRONG_INLINE Packet4f pmadd(const Packet4f& a, const Packet4f& b, const Packet4f& c) { +#if EIGEN_COMP_CLANG && EIGEN_ARCH_ARM + // Clang/ARM will replace VMLA by VMUL+VADD at least for some values of -mcpu, + // at least -mcpu=cortex-a8 and -mcpu=cortex-a7. Since the former is the default on + // -march=armv7-a, that is a very common case. + // See e.g. this thread: + // http://lists.llvm.org/pipermail/llvm-dev/2013-December/068806.html + // Filed LLVM bug: + // https://llvm.org/bugs/show_bug.cgi?id=27219 + Packet4f r = c; + asm volatile( + "vmla.f32 %q[r], %q[a], %q[b]" + : [r] "+w" (r) + : [a] "w" (a), + [b] "w" (b) + : ); + return r; +#else + return vmlaq_f32(c,a,b); +#endif +} +#endif + +// No FMA instruction for int, so use MLA unconditionally. template<> EIGEN_STRONG_INLINE Packet4i pmadd(const Packet4i& a, const Packet4i& b, const Packet4i& c) { return vmlaq_s32(c,a,b); } template<> EIGEN_STRONG_INLINE Packet4f pmin(const Packet4f& a, const Packet4f& b) { return vminq_f32(a,b); } @@ -182,20 +243,20 @@ template<> EIGEN_STRONG_INLINE Packet4f pandnot(const Packet4f& a, con } template<> EIGEN_STRONG_INLINE Packet4i pandnot(const Packet4i& a, const Packet4i& b) { return vbicq_s32(a,b); } -template<> EIGEN_STRONG_INLINE Packet4f pload(const float* from) { EIGEN_DEBUG_ALIGNED_LOAD return vld1q_f32(from); } -template<> EIGEN_STRONG_INLINE Packet4i pload(const int* from) { EIGEN_DEBUG_ALIGNED_LOAD return vld1q_s32(from); } +template<> EIGEN_STRONG_INLINE Packet4f pload(const float* from) { EIGEN_DEBUG_ALIGNED_LOAD return vld1q_f32(from); } +template<> EIGEN_STRONG_INLINE Packet4i pload(const int32_t* from) { EIGEN_DEBUG_ALIGNED_LOAD return vld1q_s32(from); } -template<> EIGEN_STRONG_INLINE Packet4f ploadu(const float* from) { EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_f32(from); } -template<> EIGEN_STRONG_INLINE Packet4i ploadu(const int* from) { EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_s32(from); } +template<> EIGEN_STRONG_INLINE Packet4f ploadu(const float* from) { EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_f32(from); } +template<> EIGEN_STRONG_INLINE Packet4i ploadu(const int32_t* from) { EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_s32(from); } -template<> EIGEN_STRONG_INLINE Packet4f ploaddup(const float* from) +template<> EIGEN_STRONG_INLINE Packet4f ploaddup(const float* from) { float32x2_t lo, hi; lo = vld1_dup_f32(from); hi = vld1_dup_f32(from+1); return vcombine_f32(lo, hi); } -template<> EIGEN_STRONG_INLINE Packet4i ploaddup(const int* from) +template<> EIGEN_STRONG_INLINE Packet4i ploaddup(const int32_t* from) { int32x2_t lo, hi; lo = vld1_dup_s32(from); @@ -203,18 +264,52 @@ template<> EIGEN_STRONG_INLINE Packet4i ploaddup(const int* from) return vcombine_s32(lo, hi); } -template<> EIGEN_STRONG_INLINE void pstore(float* to, const Packet4f& from) { EIGEN_DEBUG_ALIGNED_STORE vst1q_f32(to, from); } -template<> EIGEN_STRONG_INLINE void pstore(int* to, const Packet4i& from) { EIGEN_DEBUG_ALIGNED_STORE vst1q_s32(to, from); } +template<> EIGEN_STRONG_INLINE void pstore (float* to, const Packet4f& from) { EIGEN_DEBUG_ALIGNED_STORE vst1q_f32(to, from); } +template<> EIGEN_STRONG_INLINE void pstore(int32_t* to, const Packet4i& from) { EIGEN_DEBUG_ALIGNED_STORE vst1q_s32(to, from); } + +template<> EIGEN_STRONG_INLINE void pstoreu (float* to, const Packet4f& from) { EIGEN_DEBUG_UNALIGNED_STORE vst1q_f32(to, from); } +template<> EIGEN_STRONG_INLINE void pstoreu(int32_t* to, const Packet4i& from) { EIGEN_DEBUG_UNALIGNED_STORE vst1q_s32(to, from); } -template<> EIGEN_STRONG_INLINE void pstoreu(float* to, const Packet4f& from) { EIGEN_DEBUG_UNALIGNED_STORE vst1q_f32(to, from); } -template<> EIGEN_STRONG_INLINE void pstoreu(int* to, const Packet4i& from) { EIGEN_DEBUG_UNALIGNED_STORE vst1q_s32(to, from); } +template<> EIGEN_DEVICE_FUNC inline Packet4f pgather(const float* from, Index stride) +{ + Packet4f res = pset1(0.f); + res = vsetq_lane_f32(from[0*stride], res, 0); + res = vsetq_lane_f32(from[1*stride], res, 1); + res = vsetq_lane_f32(from[2*stride], res, 2); + res = vsetq_lane_f32(from[3*stride], res, 3); + return res; +} +template<> EIGEN_DEVICE_FUNC inline Packet4i pgather(const int32_t* from, Index stride) +{ + Packet4i res = pset1(0); + res = vsetq_lane_s32(from[0*stride], res, 0); + res = vsetq_lane_s32(from[1*stride], res, 1); + res = vsetq_lane_s32(from[2*stride], res, 2); + res = vsetq_lane_s32(from[3*stride], res, 3); + return res; +} + +template<> EIGEN_DEVICE_FUNC inline void pscatter(float* to, const Packet4f& from, Index stride) +{ + to[stride*0] = vgetq_lane_f32(from, 0); + to[stride*1] = vgetq_lane_f32(from, 1); + to[stride*2] = vgetq_lane_f32(from, 2); + to[stride*3] = vgetq_lane_f32(from, 3); +} +template<> EIGEN_DEVICE_FUNC inline void pscatter(int32_t* to, const Packet4i& from, Index stride) +{ + to[stride*0] = vgetq_lane_s32(from, 0); + to[stride*1] = vgetq_lane_s32(from, 1); + to[stride*2] = vgetq_lane_s32(from, 2); + to[stride*3] = vgetq_lane_s32(from, 3); +} -template<> EIGEN_STRONG_INLINE void prefetch(const float* addr) { __pld(addr); } -template<> EIGEN_STRONG_INLINE void prefetch(const int* addr) { __pld(addr); } +template<> EIGEN_STRONG_INLINE void prefetch (const float* addr) { EIGEN_ARM_PREFETCH(addr); } +template<> EIGEN_STRONG_INLINE void prefetch(const int32_t* addr) { EIGEN_ARM_PREFETCH(addr); } // FIXME only store the 2 first elements ? -template<> EIGEN_STRONG_INLINE float pfirst(const Packet4f& a) { float EIGEN_ALIGN16 x[4]; vst1q_f32(x, a); return x[0]; } -template<> EIGEN_STRONG_INLINE int pfirst(const Packet4i& a) { int EIGEN_ALIGN16 x[4]; vst1q_s32(x, a); return x[0]; } +template<> EIGEN_STRONG_INLINE float pfirst(const Packet4f& a) { float EIGEN_ALIGN16 x[4]; vst1q_f32(x, a); return x[0]; } +template<> EIGEN_STRONG_INLINE int32_t pfirst(const Packet4i& a) { int32_t EIGEN_ALIGN16 x[4]; vst1q_s32(x, a); return x[0]; } template<> EIGEN_STRONG_INLINE Packet4f preverse(const Packet4f& a) { float32x2_t a_lo, a_hi; @@ -234,6 +329,7 @@ template<> EIGEN_STRONG_INLINE Packet4i preverse(const Packet4i& a) { a_hi = vget_high_s32(a_r64); return vcombine_s32(a_hi, a_lo); } + template<> EIGEN_STRONG_INLINE Packet4f pabs(const Packet4f& a) { return vabsq_f32(a); } template<> EIGEN_STRONG_INLINE Packet4i pabs(const Packet4i& a) { return vabsq_s32(a); } @@ -268,7 +364,7 @@ template<> EIGEN_STRONG_INLINE Packet4f preduxp(const Packet4f* vecs) return sum; } -template<> EIGEN_STRONG_INLINE int predux(const Packet4i& a) +template<> EIGEN_STRONG_INLINE int32_t predux(const Packet4i& a) { int32x2_t a_lo, a_hi, sum; @@ -315,7 +411,7 @@ template<> EIGEN_STRONG_INLINE float predux_mul(const Packet4f& a) return vget_lane_f32(prod, 0); } -template<> EIGEN_STRONG_INLINE int predux_mul(const Packet4i& a) +template<> EIGEN_STRONG_INLINE int32_t predux_mul(const Packet4i& a) { int32x2_t a_lo, a_hi, prod; @@ -343,7 +439,7 @@ template<> EIGEN_STRONG_INLINE float predux_min(const Packet4f& a) return vget_lane_f32(min, 0); } -template<> EIGEN_STRONG_INLINE int predux_min(const Packet4i& a) +template<> EIGEN_STRONG_INLINE int32_t predux_min(const Packet4i& a) { int32x2_t a_lo, a_hi, min; @@ -368,13 +464,14 @@ template<> EIGEN_STRONG_INLINE float predux_max(const Packet4f& a) return vget_lane_f32(max, 0); } -template<> EIGEN_STRONG_INLINE int predux_max(const Packet4i& a) +template<> EIGEN_STRONG_INLINE int32_t predux_max(const Packet4i& a) { int32x2_t a_lo, a_hi, max; a_lo = vget_low_s32(a); a_hi = vget_high_s32(a); max = vpmax_s32(a_lo, a_hi); + max = vpmax_s32(max, max); return vget_lane_s32(max, 0); } @@ -400,9 +497,231 @@ PALIGN_NEON(0,Packet4i,vextq_s32) PALIGN_NEON(1,Packet4i,vextq_s32) PALIGN_NEON(2,Packet4i,vextq_s32) PALIGN_NEON(3,Packet4i,vextq_s32) - + #undef PALIGN_NEON +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + float32x4x2_t tmp1 = vzipq_f32(kernel.packet[0], kernel.packet[1]); + float32x4x2_t tmp2 = vzipq_f32(kernel.packet[2], kernel.packet[3]); + + kernel.packet[0] = vcombine_f32(vget_low_f32(tmp1.val[0]), vget_low_f32(tmp2.val[0])); + kernel.packet[1] = vcombine_f32(vget_high_f32(tmp1.val[0]), vget_high_f32(tmp2.val[0])); + kernel.packet[2] = vcombine_f32(vget_low_f32(tmp1.val[1]), vget_low_f32(tmp2.val[1])); + kernel.packet[3] = vcombine_f32(vget_high_f32(tmp1.val[1]), vget_high_f32(tmp2.val[1])); +} + +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + int32x4x2_t tmp1 = vzipq_s32(kernel.packet[0], kernel.packet[1]); + int32x4x2_t tmp2 = vzipq_s32(kernel.packet[2], kernel.packet[3]); + kernel.packet[0] = vcombine_s32(vget_low_s32(tmp1.val[0]), vget_low_s32(tmp2.val[0])); + kernel.packet[1] = vcombine_s32(vget_high_s32(tmp1.val[0]), vget_high_s32(tmp2.val[0])); + kernel.packet[2] = vcombine_s32(vget_low_s32(tmp1.val[1]), vget_low_s32(tmp2.val[1])); + kernel.packet[3] = vcombine_s32(vget_high_s32(tmp1.val[1]), vget_high_s32(tmp2.val[1])); +} + +//---------- double ---------- + +// Clang 3.5 in the iOS toolchain has an ICE triggered by NEON intrisics for double. +// Confirmed at least with __apple_build_version__ = 6000054. +#ifdef __apple_build_version__ +// Let's hope that by the time __apple_build_version__ hits the 601* range, the bug will be fixed. +// https://gist.github.com/yamaya/2924292 suggests that the 3 first digits are only updated with +// major toolchain updates. +#define EIGEN_APPLE_DOUBLE_NEON_BUG (__apple_build_version__ < 6010000) +#else +#define EIGEN_APPLE_DOUBLE_NEON_BUG 0 +#endif + +#if EIGEN_ARCH_ARM64 && !EIGEN_APPLE_DOUBLE_NEON_BUG + +// Bug 907: workaround missing declarations of the following two functions in the ADK +// Defining these functions as templates ensures that if these intrinsics are +// already defined in arm_neon.h, then our workaround doesn't cause a conflict +// and has lower priority in overload resolution. +template +uint64x2_t vreinterpretq_u64_f64(T a) +{ + return (uint64x2_t) a; +} + +template +float64x2_t vreinterpretq_f64_u64(T a) +{ + return (float64x2_t) a; +} + +typedef float64x2_t Packet2d; +typedef float64x1_t Packet1d; + +template<> struct packet_traits : default_packet_traits +{ + typedef Packet2d type; + typedef Packet2d half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size = 2, + HasHalfPacket=0, + + HasDiv = 1, + // FIXME check the Has* + HasSin = 0, + HasCos = 0, + HasLog = 0, + HasExp = 0, + HasSqrt = 0 + }; +}; + +template<> struct unpacket_traits { typedef double type; enum {size=2, alignment=Aligned16}; typedef Packet2d half; }; + +template<> EIGEN_STRONG_INLINE Packet2d pset1(const double& from) { return vdupq_n_f64(from); } + +template<> EIGEN_STRONG_INLINE Packet2d plset(const double& a) +{ + const double countdown_raw[] = {0.0,1.0}; + const Packet2d countdown = vld1q_f64(countdown_raw); + return vaddq_f64(pset1(a), countdown); +} +template<> EIGEN_STRONG_INLINE Packet2d padd(const Packet2d& a, const Packet2d& b) { return vaddq_f64(a,b); } + +template<> EIGEN_STRONG_INLINE Packet2d psub(const Packet2d& a, const Packet2d& b) { return vsubq_f64(a,b); } + +template<> EIGEN_STRONG_INLINE Packet2d pnegate(const Packet2d& a) { return vnegq_f64(a); } + +template<> EIGEN_STRONG_INLINE Packet2d pconj(const Packet2d& a) { return a; } + +template<> EIGEN_STRONG_INLINE Packet2d pmul(const Packet2d& a, const Packet2d& b) { return vmulq_f64(a,b); } + +template<> EIGEN_STRONG_INLINE Packet2d pdiv(const Packet2d& a, const Packet2d& b) { return vdivq_f64(a,b); } + +#ifdef __ARM_FEATURE_FMA +// See bug 936. See above comment about FMA for float. +template<> EIGEN_STRONG_INLINE Packet2d pmadd(const Packet2d& a, const Packet2d& b, const Packet2d& c) { return vfmaq_f64(c,a,b); } +#else +template<> EIGEN_STRONG_INLINE Packet2d pmadd(const Packet2d& a, const Packet2d& b, const Packet2d& c) { return vmlaq_f64(c,a,b); } +#endif + +template<> EIGEN_STRONG_INLINE Packet2d pmin(const Packet2d& a, const Packet2d& b) { return vminq_f64(a,b); } + +template<> EIGEN_STRONG_INLINE Packet2d pmax(const Packet2d& a, const Packet2d& b) { return vmaxq_f64(a,b); } + +// Logical Operations are not supported for float, so we have to reinterpret casts using NEON intrinsics +template<> EIGEN_STRONG_INLINE Packet2d pand(const Packet2d& a, const Packet2d& b) +{ + return vreinterpretq_f64_u64(vandq_u64(vreinterpretq_u64_f64(a),vreinterpretq_u64_f64(b))); +} + +template<> EIGEN_STRONG_INLINE Packet2d por(const Packet2d& a, const Packet2d& b) +{ + return vreinterpretq_f64_u64(vorrq_u64(vreinterpretq_u64_f64(a),vreinterpretq_u64_f64(b))); +} + +template<> EIGEN_STRONG_INLINE Packet2d pxor(const Packet2d& a, const Packet2d& b) +{ + return vreinterpretq_f64_u64(veorq_u64(vreinterpretq_u64_f64(a),vreinterpretq_u64_f64(b))); +} + +template<> EIGEN_STRONG_INLINE Packet2d pandnot(const Packet2d& a, const Packet2d& b) +{ + return vreinterpretq_f64_u64(vbicq_u64(vreinterpretq_u64_f64(a),vreinterpretq_u64_f64(b))); +} + +template<> EIGEN_STRONG_INLINE Packet2d pload(const double* from) { EIGEN_DEBUG_ALIGNED_LOAD return vld1q_f64(from); } + +template<> EIGEN_STRONG_INLINE Packet2d ploadu(const double* from) { EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_f64(from); } + +template<> EIGEN_STRONG_INLINE Packet2d ploaddup(const double* from) +{ + return vld1q_dup_f64(from); +} +template<> EIGEN_STRONG_INLINE void pstore(double* to, const Packet2d& from) { EIGEN_DEBUG_ALIGNED_STORE vst1q_f64(to, from); } + +template<> EIGEN_STRONG_INLINE void pstoreu(double* to, const Packet2d& from) { EIGEN_DEBUG_UNALIGNED_STORE vst1q_f64(to, from); } + +template<> EIGEN_DEVICE_FUNC inline Packet2d pgather(const double* from, Index stride) +{ + Packet2d res = pset1(0.0); + res = vsetq_lane_f64(from[0*stride], res, 0); + res = vsetq_lane_f64(from[1*stride], res, 1); + return res; +} +template<> EIGEN_DEVICE_FUNC inline void pscatter(double* to, const Packet2d& from, Index stride) +{ + to[stride*0] = vgetq_lane_f64(from, 0); + to[stride*1] = vgetq_lane_f64(from, 1); +} +template<> EIGEN_STRONG_INLINE void prefetch(const double* addr) { EIGEN_ARM_PREFETCH(addr); } + +// FIXME only store the 2 first elements ? +template<> EIGEN_STRONG_INLINE double pfirst(const Packet2d& a) { return vgetq_lane_f64(a, 0); } + +template<> EIGEN_STRONG_INLINE Packet2d preverse(const Packet2d& a) { return vcombine_f64(vget_high_f64(a), vget_low_f64(a)); } + +template<> EIGEN_STRONG_INLINE Packet2d pabs(const Packet2d& a) { return vabsq_f64(a); } + +#if EIGEN_COMP_CLANG && defined(__apple_build_version__) +// workaround ICE, see bug 907 +template<> EIGEN_STRONG_INLINE double predux(const Packet2d& a) { return (vget_low_f64(a) + vget_high_f64(a))[0]; } +#else +template<> EIGEN_STRONG_INLINE double predux(const Packet2d& a) { return vget_lane_f64(vget_low_f64(a) + vget_high_f64(a), 0); } +#endif + +template<> EIGEN_STRONG_INLINE Packet2d preduxp(const Packet2d* vecs) +{ + float64x2_t trn1, trn2; + + // NEON zip performs interleaving of the supplied vectors. + // We perform two interleaves in a row to acquire the transposed vector + trn1 = vzip1q_f64(vecs[0], vecs[1]); + trn2 = vzip2q_f64(vecs[0], vecs[1]); + + // Do the addition of the resulting vectors + return vaddq_f64(trn1, trn2); +} +// Other reduction functions: +// mul +#if EIGEN_COMP_CLANG && defined(__apple_build_version__) +template<> EIGEN_STRONG_INLINE double predux_mul(const Packet2d& a) { return (vget_low_f64(a) * vget_high_f64(a))[0]; } +#else +template<> EIGEN_STRONG_INLINE double predux_mul(const Packet2d& a) { return vget_lane_f64(vget_low_f64(a) * vget_high_f64(a), 0); } +#endif + +// min +template<> EIGEN_STRONG_INLINE double predux_min(const Packet2d& a) { return vgetq_lane_f64(vpminq_f64(a, a), 0); } + +// max +template<> EIGEN_STRONG_INLINE double predux_max(const Packet2d& a) { return vgetq_lane_f64(vpmaxq_f64(a, a), 0); } + +// this PALIGN_NEON business is to work around a bug in LLVM Clang 3.0 causing incorrect compilation errors, +// see bug 347 and this LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=11074 +#define PALIGN_NEON(Offset,Type,Command) \ +template<>\ +struct palign_impl\ +{\ + EIGEN_STRONG_INLINE static void run(Type& first, const Type& second)\ + {\ + if (Offset!=0)\ + first = Command(first, second, Offset);\ + }\ +};\ + +PALIGN_NEON(0,Packet2d,vextq_f64) +PALIGN_NEON(1,Packet2d,vextq_f64) +#undef PALIGN_NEON + +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + float64x2_t trn1 = vzip1q_f64(kernel.packet[0], kernel.packet[1]); + float64x2_t trn2 = vzip2q_f64(kernel.packet[0], kernel.packet[1]); + + kernel.packet[0] = trn1; + kernel.packet[1] = trn2; +} +#endif // EIGEN_ARCH_ARM64 + } // end namespace internal } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/Core/arch/SSE/Complex.h b/libs/eigen3/Eigen/src/Core/arch/SSE/Complex.h index 91bba5e38..5607fe0ab 100644 --- a/libs/eigen3/Eigen/src/Core/arch/SSE/Complex.h +++ b/libs/eigen3/Eigen/src/Core/arch/SSE/Complex.h @@ -22,13 +22,18 @@ struct Packet2cf __m128 v; }; +// Use the packet_traits defined in AVX/PacketMath.h instead if we're going +// to leverage AVX instructions. +#ifndef EIGEN_VECTORIZE_AVX template<> struct packet_traits > : default_packet_traits { typedef Packet2cf type; + typedef Packet2cf half; enum { Vectorizable = 1, AlignedOnScalar = 1, size = 2, + HasHalfPacket = 0, HasAdd = 1, HasSub = 1, @@ -39,11 +44,13 @@ template<> struct packet_traits > : default_packet_traits HasAbs2 = 0, HasMin = 0, HasMax = 0, - HasSetLinear = 0 + HasSetLinear = 0, + HasBlend = 1 }; }; +#endif -template<> struct unpacket_traits { typedef std::complex type; enum {size=2}; }; +template<> struct unpacket_traits { typedef std::complex type; enum {size=2, alignment=Aligned16}; typedef Packet2cf half; }; template<> EIGEN_STRONG_INLINE Packet2cf padd(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(_mm_add_ps(a.v,b.v)); } template<> EIGEN_STRONG_INLINE Packet2cf psub(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(_mm_sub_ps(a.v,b.v)); } @@ -60,7 +67,6 @@ template<> EIGEN_STRONG_INLINE Packet2cf pconj(const Packet2cf& a) template<> EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, const Packet2cf& b) { - // TODO optimize it for SSE3 and 4 #ifdef EIGEN_VECTORIZE_SSE3 return Packet2cf(_mm_addsub_ps(_mm_mul_ps(_mm_moveldup_ps(a.v), b.v), _mm_mul_ps(_mm_movehdup_ps(a.v), @@ -104,8 +110,23 @@ template<> EIGEN_STRONG_INLINE Packet2cf pset1(const std::complex EIGEN_STRONG_INLINE Packet2cf ploaddup(const std::complex* from) { return pset1(*from); } -template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet2cf& from) { EIGEN_DEBUG_ALIGNED_STORE pstore(&numext::real_ref(*to), from.v); } -template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet2cf& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu(&numext::real_ref(*to), from.v); } +template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet2cf& from) { EIGEN_DEBUG_ALIGNED_STORE pstore(&numext::real_ref(*to), Packet4f(from.v)); } +template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet2cf& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu(&numext::real_ref(*to), Packet4f(from.v)); } + + +template<> EIGEN_DEVICE_FUNC inline Packet2cf pgather, Packet2cf>(const std::complex* from, Index stride) +{ + return Packet2cf(_mm_set_ps(std::imag(from[1*stride]), std::real(from[1*stride]), + std::imag(from[0*stride]), std::real(from[0*stride]))); +} + +template<> EIGEN_DEVICE_FUNC inline void pscatter, Packet2cf>(std::complex* to, const Packet2cf& from, Index stride) +{ + to[stride*0] = std::complex(_mm_cvtss_f32(_mm_shuffle_ps(from.v, from.v, 0)), + _mm_cvtss_f32(_mm_shuffle_ps(from.v, from.v, 1))); + to[stride*1] = std::complex(_mm_cvtss_f32(_mm_shuffle_ps(from.v, from.v, 2)), + _mm_cvtss_f32(_mm_shuffle_ps(from.v, from.v, 3))); +} template<> EIGEN_STRONG_INLINE void prefetch >(const std::complex * addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); } @@ -124,7 +145,7 @@ template<> EIGEN_STRONG_INLINE std::complex pfirst(const Pack #endif } -template<> EIGEN_STRONG_INLINE Packet2cf preverse(const Packet2cf& a) { return Packet2cf(_mm_castpd_ps(preverse(_mm_castps_pd(a.v)))); } +template<> EIGEN_STRONG_INLINE Packet2cf preverse(const Packet2cf& a) { return Packet2cf(_mm_castpd_ps(preverse(Packet2d(_mm_castps_pd(a.v))))); } template<> EIGEN_STRONG_INLINE std::complex predux(const Packet2cf& a) { @@ -214,7 +235,7 @@ template<> struct conj_helper { return padd(c, pmul(x,y)); } EIGEN_STRONG_INLINE Packet2cf pmul(const Packet4f& x, const Packet2cf& y) const - { return Packet2cf(Eigen::internal::pmul(x, y.v)); } + { return Packet2cf(Eigen::internal::pmul(x, y.v)); } }; template<> struct conj_helper @@ -223,7 +244,7 @@ template<> struct conj_helper { return padd(c, pmul(x,y)); } EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& x, const Packet4f& y) const - { return Packet2cf(Eigen::internal::pmul(x.v, y)); } + { return Packet2cf(Eigen::internal::pmul(x.v, y)); } }; template<> EIGEN_STRONG_INLINE Packet2cf pdiv(const Packet2cf& a, const Packet2cf& b) @@ -234,7 +255,7 @@ template<> EIGEN_STRONG_INLINE Packet2cf pdiv(const Packet2cf& a, con return Packet2cf(_mm_div_ps(res.v,_mm_add_ps(s,_mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(s), 0xb1))))); } -EIGEN_STRONG_INLINE Packet2cf pcplxflip/**/(const Packet2cf& x) +EIGEN_STRONG_INLINE Packet2cf pcplxflip/* */(const Packet2cf& x) { return Packet2cf(vec4f_swizzle1(x.v, 1, 0, 3, 2)); } @@ -248,13 +269,18 @@ struct Packet1cd __m128d v; }; +// Use the packet_traits defined in AVX/PacketMath.h instead if we're going +// to leverage AVX instructions. +#ifndef EIGEN_VECTORIZE_AVX template<> struct packet_traits > : default_packet_traits { typedef Packet1cd type; + typedef Packet1cd half; enum { Vectorizable = 1, AlignedOnScalar = 0, size = 1, + HasHalfPacket = 0, HasAdd = 1, HasSub = 1, @@ -268,12 +294,13 @@ template<> struct packet_traits > : default_packet_traits HasSetLinear = 0 }; }; +#endif -template<> struct unpacket_traits { typedef std::complex type; enum {size=1}; }; +template<> struct unpacket_traits { typedef std::complex type; enum {size=1, alignment=Aligned16}; typedef Packet1cd half; }; template<> EIGEN_STRONG_INLINE Packet1cd padd(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(_mm_add_pd(a.v,b.v)); } template<> EIGEN_STRONG_INLINE Packet1cd psub(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(_mm_sub_pd(a.v,b.v)); } -template<> EIGEN_STRONG_INLINE Packet1cd pnegate(const Packet1cd& a) { return Packet1cd(pnegate(a.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd pnegate(const Packet1cd& a) { return Packet1cd(pnegate(Packet2d(a.v))); } template<> EIGEN_STRONG_INLINE Packet1cd pconj(const Packet1cd& a) { const __m128d mask = _mm_castsi128_pd(_mm_set_epi32(0x80000000,0x0,0x0,0x0)); @@ -282,9 +309,8 @@ template<> EIGEN_STRONG_INLINE Packet1cd pconj(const Packet1cd& a) template<> EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) { - // TODO optimize it for SSE3 and 4 #ifdef EIGEN_VECTORIZE_SSE3 - return Packet1cd(_mm_addsub_pd(_mm_mul_pd(vec2d_swizzle1(a.v, 0, 0), b.v), + return Packet1cd(_mm_addsub_pd(_mm_mul_pd(_mm_movedup_pd(a.v), b.v), _mm_mul_pd(vec2d_swizzle1(a.v, 1, 1), vec2d_swizzle1(b.v, 1, 0)))); #else @@ -311,8 +337,8 @@ template<> EIGEN_STRONG_INLINE Packet1cd pset1(const std::complex EIGEN_STRONG_INLINE Packet1cd ploaddup(const std::complex* from) { return pset1(*from); } // FIXME force unaligned store, this is a temporary fix -template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet1cd& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((double*)to, from.v); } -template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet1cd& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, from.v); } +template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet1cd& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((double*)to, Packet2d(from.v)); } +template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet1cd& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, Packet2d(from.v)); } template<> EIGEN_STRONG_INLINE void prefetch >(const std::complex * addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); } @@ -410,7 +436,7 @@ template<> struct conj_helper { return padd(c, pmul(x,y)); } EIGEN_STRONG_INLINE Packet1cd pmul(const Packet2d& x, const Packet1cd& y) const - { return Packet1cd(Eigen::internal::pmul(x, y.v)); } + { return Packet1cd(Eigen::internal::pmul(x, y.v)); } }; template<> struct conj_helper @@ -419,7 +445,7 @@ template<> struct conj_helper { return padd(c, pmul(x,y)); } EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& x, const Packet2d& y) const - { return Packet1cd(Eigen::internal::pmul(x.v, y)); } + { return Packet1cd(Eigen::internal::pmul(x.v, y)); } }; template<> EIGEN_STRONG_INLINE Packet1cd pdiv(const Packet1cd& a, const Packet1cd& b) @@ -430,9 +456,44 @@ template<> EIGEN_STRONG_INLINE Packet1cd pdiv(const Packet1cd& a, con return Packet1cd(_mm_div_pd(res.v, _mm_add_pd(s,_mm_shuffle_pd(s, s, 0x1)))); } -EIGEN_STRONG_INLINE Packet1cd pcplxflip/**/(const Packet1cd& x) +EIGEN_STRONG_INLINE Packet1cd pcplxflip/* */(const Packet1cd& x) +{ + return Packet1cd(preverse(Packet2d(x.v))); +} + +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + __m128d w1 = _mm_castps_pd(kernel.packet[0].v); + __m128d w2 = _mm_castps_pd(kernel.packet[1].v); + + __m128 tmp = _mm_castpd_ps(_mm_unpackhi_pd(w1, w2)); + kernel.packet[0].v = _mm_castpd_ps(_mm_unpacklo_pd(w1, w2)); + kernel.packet[1].v = tmp; +} + +template<> EIGEN_STRONG_INLINE Packet2cf pblend(const Selector<2>& ifPacket, const Packet2cf& thenPacket, const Packet2cf& elsePacket) { + __m128d result = pblend(ifPacket, _mm_castps_pd(thenPacket.v), _mm_castps_pd(elsePacket.v)); + return Packet2cf(_mm_castpd_ps(result)); +} + +template<> EIGEN_STRONG_INLINE Packet2cf pinsertfirst(const Packet2cf& a, std::complex b) +{ + return Packet2cf(_mm_loadl_pi(a.v, reinterpret_cast(&b))); +} + +template<> EIGEN_STRONG_INLINE Packet1cd pinsertfirst(const Packet1cd&, std::complex b) +{ + return pset1(b); +} + +template<> EIGEN_STRONG_INLINE Packet2cf pinsertlast(const Packet2cf& a, std::complex b) +{ + return Packet2cf(_mm_loadh_pi(a.v, reinterpret_cast(&b))); +} + +template<> EIGEN_STRONG_INLINE Packet1cd pinsertlast(const Packet1cd&, std::complex b) { - return Packet1cd(preverse(x.v)); + return pset1(b); } } // end namespace internal diff --git a/libs/eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h b/libs/eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h index 99cbd0d95..7b5f948e1 100644 --- a/libs/eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h +++ b/libs/eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h @@ -32,7 +32,7 @@ Packet4f plog(const Packet4f& _x) /* the smallest non denormalized float number */ _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(min_norm_pos, 0x00800000); _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(minus_inf, 0xff800000);//-1.f/0.f); - + /* natural logarithm computed for 4 simultaneous float return NaN for x <= 0 */ @@ -52,7 +52,7 @@ Packet4f plog(const Packet4f& _x) Packet4i emm0; - Packet4f invalid_mask = _mm_cmplt_ps(x, _mm_setzero_ps()); + Packet4f invalid_mask = _mm_cmpnge_ps(x, _mm_setzero_ps()); // not greater equal is true if x is NaN Packet4f iszero_mask = _mm_cmpeq_ps(x, _mm_setzero_ps()); x = pmax(x, p4f_min_norm_pos); /* cut off denormalized stuff */ @@ -63,7 +63,7 @@ Packet4f plog(const Packet4f& _x) x = _mm_or_ps(x, p4f_half); emm0 = _mm_sub_epi32(emm0, p4i_0x7f); - Packet4f e = padd(_mm_cvtepi32_ps(emm0), p4f_1); + Packet4f e = padd(Packet4f(_mm_cvtepi32_ps(emm0)), p4f_1); /* part2: if( x < SQRTHF ) { @@ -72,9 +72,9 @@ Packet4f plog(const Packet4f& _x) } else { x = x - 1.0; } */ Packet4f mask = _mm_cmplt_ps(x, p4f_cephes_SQRTHF); - Packet4f tmp = _mm_and_ps(x, mask); + Packet4f tmp = pand(x, mask); x = psub(x, p4f_1); - e = psub(e, _mm_and_ps(p4f_1, mask)); + e = psub(e, pand(p4f_1, mask)); x = padd(x, tmp); Packet4f x2 = pmul(x,x); @@ -126,7 +126,7 @@ Packet4f pexp(const Packet4f& _x) _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p4, 1.6666665459E-1f); _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p5, 5.0000001201E-1f); - Packet4f tmp = _mm_setzero_ps(), fx; + Packet4f tmp, fx; Packet4i emm0; // clamp x @@ -166,7 +166,7 @@ Packet4f pexp(const Packet4f& _x) emm0 = _mm_cvttps_epi32(fx); emm0 = _mm_add_epi32(emm0, p4i_0x7f); emm0 = _mm_slli_epi32(emm0, 23); - return pmul(y, _mm_castsi128_ps(emm0)); + return pmax(pmul(y, Packet4f(_mm_castsi128_ps(emm0))), _x); } template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet2d pexp(const Packet2d& _x) @@ -195,7 +195,7 @@ Packet2d pexp(const Packet2d& _x) _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_C2, 1.42860682030941723212e-6); static const __m128i p4i_1023_0 = _mm_setr_epi32(1023, 1023, 0, 0); - Packet2d tmp = _mm_setzero_pd(), fx; + Packet2d tmp, fx; Packet4i emm0; // clamp x @@ -239,7 +239,7 @@ Packet2d pexp(const Packet2d& _x) emm0 = _mm_add_epi32(emm0, p4i_1023_0); emm0 = _mm_slli_epi32(emm0, 20); emm0 = _mm_shuffle_epi32(emm0, _MM_SHUFFLE(1,2,0,3)); - return pmul(x, _mm_castsi128_pd(emm0)); + return pmax(pmul(x, Packet2d(_mm_castsi128_pd(emm0))), _x); } /* evaluation of 4 sines at onces, using SSE2 intrinsics. @@ -279,7 +279,7 @@ Packet4f psin(const Packet4f& _x) _EIGEN_DECLARE_CONST_Packet4f(coscof_p2, 4.166664568298827E-002f); _EIGEN_DECLARE_CONST_Packet4f(cephes_FOPI, 1.27323954473516f); // 4 / M_PI - Packet4f xmm1, xmm2 = _mm_setzero_ps(), xmm3, sign_bit, y; + Packet4f xmm1, xmm2, xmm3, sign_bit, y; Packet4i emm0, emm2; sign_bit = x; @@ -378,7 +378,7 @@ Packet4f pcos(const Packet4f& _x) _EIGEN_DECLARE_CONST_Packet4f(coscof_p2, 4.166664568298827E-002f); _EIGEN_DECLARE_CONST_Packet4f(cephes_FOPI, 1.27323954473516f); // 4 / M_PI - Packet4f xmm1, xmm2 = _mm_setzero_ps(), xmm3, y; + Packet4f xmm1, xmm2, xmm3, y; Packet4i emm0, emm2; x = pabs(x); @@ -444,32 +444,119 @@ Packet4f pcos(const Packet4f& _x) #if EIGEN_FAST_MATH -// This is based on Quake3's fast inverse square root. +// Functions for sqrt. +// The EIGEN_FAST_MATH version uses the _mm_rsqrt_ps approximation and one step +// of Newton's method, at a cost of 1-2 bits of precision as opposed to the +// exact solution. It does not handle +inf, or denormalized numbers correctly. +// The main advantage of this approach is not just speed, but also the fact that +// it can be inlined and pipelined with other computations, further reducing its +// effective latency. This is similar to Quake3's fast inverse square root. // For detail see here: http://www.beyond3d.com/content/articles/8/ -// It lacks 1 (or 2 bits in some rare cases) of precision, and does not handle negative, +inf, or denormalized numbers correctly. template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet4f psqrt(const Packet4f& _x) { Packet4f half = pmul(_x, pset1(.5f)); + Packet4f denormal_mask = _mm_and_ps( + _mm_cmpge_ps(_x, _mm_setzero_ps()), + _mm_cmplt_ps(_x, pset1((std::numeric_limits::min)()))); - /* select only the inverse sqrt of non-zero inputs */ - Packet4f non_zero_mask = _mm_cmpge_ps(_x, pset1((std::numeric_limits::min)())); - Packet4f x = _mm_and_ps(non_zero_mask, _mm_rsqrt_ps(_x)); - + // Compute approximate reciprocal sqrt. + Packet4f x = _mm_rsqrt_ps(_x); + // Do a single step of Newton's iteration. x = pmul(x, psub(pset1(1.5f), pmul(half, pmul(x,x)))); - return pmul(_x,x); + // Flush results for denormals to zero. + return _mm_andnot_ps(denormal_mask, pmul(_x,x)); } #else -template<> EIGEN_STRONG_INLINE Packet4f psqrt(const Packet4f& x) { return _mm_sqrt_ps(x); } +template<>EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet4f psqrt(const Packet4f& x) { return _mm_sqrt_ps(x); } + +#endif + +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet2d psqrt(const Packet2d& x) { return _mm_sqrt_pd(x); } + +#if EIGEN_FAST_MATH + +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet4f prsqrt(const Packet4f& _x) { + _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(inf, 0x7f800000); + _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(nan, 0x7fc00000); + _EIGEN_DECLARE_CONST_Packet4f(one_point_five, 1.5f); + _EIGEN_DECLARE_CONST_Packet4f(minus_half, -0.5f); + _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(flt_min, 0x00800000); + + Packet4f neg_half = pmul(_x, p4f_minus_half); + + // select only the inverse sqrt of positive normal inputs (denormals are + // flushed to zero and cause infs as well). + Packet4f le_zero_mask = _mm_cmple_ps(_x, p4f_flt_min); + Packet4f x = _mm_andnot_ps(le_zero_mask, _mm_rsqrt_ps(_x)); + + // Fill in NaNs and Infs for the negative/zero entries. + Packet4f neg_mask = _mm_cmplt_ps(_x, _mm_setzero_ps()); + Packet4f zero_mask = _mm_andnot_ps(neg_mask, le_zero_mask); + Packet4f infs_and_nans = _mm_or_ps(_mm_and_ps(neg_mask, p4f_nan), + _mm_and_ps(zero_mask, p4f_inf)); + + // Do a single step of Newton's iteration. + x = pmul(x, pmadd(neg_half, pmul(x, x), p4f_one_point_five)); + + // Insert NaNs and Infs in all the right places. + return _mm_or_ps(x, infs_and_nans); +} + +#else + +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet4f prsqrt(const Packet4f& x) { + // Unfortunately we can't use the much faster mm_rqsrt_ps since it only provides an approximation. + return _mm_div_ps(pset1(1.0f), _mm_sqrt_ps(x)); +} #endif -template<> EIGEN_STRONG_INLINE Packet2d psqrt(const Packet2d& x) { return _mm_sqrt_pd(x); } +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet2d prsqrt(const Packet2d& x) { + // Unfortunately we can't use the much faster mm_rqsrt_pd since it only provides an approximation. + return _mm_div_pd(pset1(1.0), _mm_sqrt_pd(x)); +} + +// Hyperbolic Tangent function. +template <> +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet4f +ptanh(const Packet4f& x) { + return internal::generic_fast_tanh_float(x); +} } // end namespace internal +namespace numext { + +template<> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float sqrt(const float &x) +{ + return internal::pfirst(internal::Packet4f(_mm_sqrt_ss(_mm_set_ss(x)))); +} + +template<> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double sqrt(const double &x) +{ +#if EIGEN_COMP_GNUC_STRICT + // This works around a GCC bug generating poor code for _mm_sqrt_pd + // See https://bitbucket.org/eigen/eigen/commits/14f468dba4d350d7c19c9b93072e19f7b3df563b + return internal::pfirst(internal::Packet2d(__builtin_ia32_sqrtsd(_mm_set_sd(x)))); +#else + return internal::pfirst(internal::Packet2d(_mm_sqrt_pd(_mm_set_sd(x)))); +#endif +} + +} // end namespace numex + } // end namespace Eigen #endif // EIGEN_MATH_FUNCTIONS_SSE_H diff --git a/libs/eigen3/Eigen/src/Core/arch/SSE/PacketMath.h b/libs/eigen3/Eigen/src/Core/arch/SSE/PacketMath.h old mode 100644 new mode 100755 index fc8ae50fe..3832de147 --- a/libs/eigen3/Eigen/src/Core/arch/SSE/PacketMath.h +++ b/libs/eigen3/Eigen/src/Core/arch/SSE/PacketMath.h @@ -22,9 +22,40 @@ namespace internal { #define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS (2*sizeof(void*)) #endif +#ifdef __FMA__ +#ifndef EIGEN_HAS_SINGLE_INSTRUCTION_MADD +#define EIGEN_HAS_SINGLE_INSTRUCTION_MADD 1 +#endif +#endif + +#if (defined EIGEN_VECTORIZE_AVX) && (EIGEN_COMP_GNUC_STRICT || EIGEN_COMP_MINGW) && (__GXX_ABI_VERSION < 1004) +// With GCC's default ABI version, a __m128 or __m256 are the same types and therefore we cannot +// have overloads for both types without linking error. +// One solution is to increase ABI version using -fabi-version=4 (or greater). +// Otherwise, we workaround this inconvenience by wrapping 128bit types into the following helper +// structure: +template +struct eigen_packet_wrapper +{ + EIGEN_ALWAYS_INLINE operator T&() { return m_val; } + EIGEN_ALWAYS_INLINE operator const T&() const { return m_val; } + EIGEN_ALWAYS_INLINE eigen_packet_wrapper() {} + EIGEN_ALWAYS_INLINE eigen_packet_wrapper(const T &v) : m_val(v) {} + EIGEN_ALWAYS_INLINE eigen_packet_wrapper& operator=(const T &v) { + m_val = v; + return *this; + } + + T m_val; +}; +typedef eigen_packet_wrapper<__m128> Packet4f; +typedef eigen_packet_wrapper<__m128i> Packet4i; +typedef eigen_packet_wrapper<__m128d> Packet2d; +#else typedef __m128 Packet4f; typedef __m128i Packet4i; typedef __m128d Packet2d; +#endif template<> struct is_arithmetic<__m128> { enum { value = true }; }; template<> struct is_arithmetic<__m128i> { enum { value = true }; }; @@ -58,51 +89,85 @@ template<> struct is_arithmetic<__m128d> { enum { value = true }; }; const Packet4i p4i_##NAME = pset1(X) +// Use the packet_traits defined in AVX/PacketMath.h instead if we're going +// to leverage AVX instructions. +#ifndef EIGEN_VECTORIZE_AVX template<> struct packet_traits : default_packet_traits { typedef Packet4f type; + typedef Packet4f half; enum { Vectorizable = 1, AlignedOnScalar = 1, size=4, + HasHalfPacket = 0, HasDiv = 1, HasSin = EIGEN_FAST_MATH, HasCos = EIGEN_FAST_MATH, HasLog = 1, HasExp = 1, - HasSqrt = 1 + HasSqrt = 1, + HasRsqrt = 1, + HasTanh = EIGEN_FAST_MATH, + HasBlend = 1 + +#ifdef EIGEN_VECTORIZE_SSE4_1 + , + HasRound = 1, + HasFloor = 1, + HasCeil = 1 +#endif }; }; template<> struct packet_traits : default_packet_traits { typedef Packet2d type; + typedef Packet2d half; enum { Vectorizable = 1, AlignedOnScalar = 1, size=2, + HasHalfPacket = 0, HasDiv = 1, HasExp = 1, - HasSqrt = 1 + HasSqrt = 1, + HasRsqrt = 1, + HasBlend = 1 + +#ifdef EIGEN_VECTORIZE_SSE4_1 + , + HasRound = 1, + HasFloor = 1, + HasCeil = 1 +#endif }; }; +#endif template<> struct packet_traits : default_packet_traits { typedef Packet4i type; + typedef Packet4i half; enum { - // FIXME check the Has* Vectorizable = 1, AlignedOnScalar = 1, - size=4 + size=4, + + HasBlend = 1 }; }; -template<> struct unpacket_traits { typedef float type; enum {size=4}; }; -template<> struct unpacket_traits { typedef double type; enum {size=2}; }; -template<> struct unpacket_traits { typedef int type; enum {size=4}; }; +template<> struct unpacket_traits { typedef float type; enum {size=4, alignment=Aligned16}; typedef Packet4f half; }; +template<> struct unpacket_traits { typedef double type; enum {size=2, alignment=Aligned16}; typedef Packet2d half; }; +template<> struct unpacket_traits { typedef int type; enum {size=4, alignment=Aligned16}; typedef Packet4i half; }; -#if defined(_MSC_VER) && (_MSC_VER==1500) +#ifndef EIGEN_VECTORIZE_AVX +template<> struct scalar_div_cost { enum { value = 7 }; }; +template<> struct scalar_div_cost { enum { value = 8 }; }; +#endif + +#if EIGEN_COMP_MSVC==1500 // Workaround MSVC 9 internal compiler error. // TODO: It has been detected with win64 builds (amd64), so let's check whether it also happens in 32bits+SSE mode // TODO: let's check whether there does not exist a better fix, like adding a pset0() function. (it crashed on pset1(0)). @@ -110,14 +175,25 @@ template<> EIGEN_STRONG_INLINE Packet4f pset1(const float& from) { re template<> EIGEN_STRONG_INLINE Packet2d pset1(const double& from) { return _mm_set_pd(from,from); } template<> EIGEN_STRONG_INLINE Packet4i pset1(const int& from) { return _mm_set_epi32(from,from,from,from); } #else -template<> EIGEN_STRONG_INLINE Packet4f pset1(const float& from) { return _mm_set1_ps(from); } +template<> EIGEN_STRONG_INLINE Packet4f pset1(const float& from) { return _mm_set_ps1(from); } template<> EIGEN_STRONG_INLINE Packet2d pset1(const double& from) { return _mm_set1_pd(from); } template<> EIGEN_STRONG_INLINE Packet4i pset1(const int& from) { return _mm_set1_epi32(from); } #endif -template<> EIGEN_STRONG_INLINE Packet4f plset(const float& a) { return _mm_add_ps(pset1(a), _mm_set_ps(3,2,1,0)); } -template<> EIGEN_STRONG_INLINE Packet2d plset(const double& a) { return _mm_add_pd(pset1(a),_mm_set_pd(1,0)); } -template<> EIGEN_STRONG_INLINE Packet4i plset(const int& a) { return _mm_add_epi32(pset1(a),_mm_set_epi32(3,2,1,0)); } +// GCC generates a shufps instruction for _mm_set1_ps/_mm_load1_ps instead of the more efficient pshufd instruction. +// However, using inrinsics for pset1 makes gcc to generate crappy code in some cases (see bug 203) +// Using inline assembly is also not an option because then gcc fails to reorder properly the instructions. +// Therefore, we introduced the pload1 functions to be used in product kernels for which bug 203 does not apply. +// Also note that with AVX, we want it to generate a vbroadcastss. +#if EIGEN_COMP_GNUC_STRICT && (!defined __AVX__) +template<> EIGEN_STRONG_INLINE Packet4f pload1(const float *from) { + return vec4f_swizzle1(_mm_load_ss(from),0,0,0,0); +} +#endif + +template<> EIGEN_STRONG_INLINE Packet4f plset(const float& a) { return _mm_add_ps(pset1(a), _mm_set_ps(3,2,1,0)); } +template<> EIGEN_STRONG_INLINE Packet2d plset(const double& a) { return _mm_add_pd(pset1(a),_mm_set_pd(1,0)); } +template<> EIGEN_STRONG_INLINE Packet4i plset(const int& a) { return _mm_add_epi32(pset1(a),_mm_set_epi32(3,2,1,0)); } template<> EIGEN_STRONG_INLINE Packet4f padd(const Packet4f& a, const Packet4f& b) { return _mm_add_ps(a,b); } template<> EIGEN_STRONG_INLINE Packet2d padd(const Packet2d& a, const Packet2d& b) { return _mm_add_pd(a,b); } @@ -139,7 +215,7 @@ template<> EIGEN_STRONG_INLINE Packet2d pnegate(const Packet2d& a) } template<> EIGEN_STRONG_INLINE Packet4i pnegate(const Packet4i& a) { - return psub(_mm_setr_epi32(0,0,0,0), a); + return psub(Packet4i(_mm_setr_epi32(0,0,0,0)), a); } template<> EIGEN_STRONG_INLINE Packet4f pconj(const Packet4f& a) { return a; } @@ -166,13 +242,13 @@ template<> EIGEN_STRONG_INLINE Packet4i pmul(const Packet4i& a, const template<> EIGEN_STRONG_INLINE Packet4f pdiv(const Packet4f& a, const Packet4f& b) { return _mm_div_ps(a,b); } template<> EIGEN_STRONG_INLINE Packet2d pdiv(const Packet2d& a, const Packet2d& b) { return _mm_div_pd(a,b); } -template<> EIGEN_STRONG_INLINE Packet4i pdiv(const Packet4i& /*a*/, const Packet4i& /*b*/) -{ eigen_assert(false && "packet integer division are not supported by SSE"); - return pset1(0); -} // for some weird raisons, it has to be overloaded for packet of integers template<> EIGEN_STRONG_INLINE Packet4i pmadd(const Packet4i& a, const Packet4i& b, const Packet4i& c) { return padd(pmul(a,b), c); } +#ifdef __FMA__ +template<> EIGEN_STRONG_INLINE Packet4f pmadd(const Packet4f& a, const Packet4f& b, const Packet4f& c) { return _mm_fmadd_ps(a,b,c); } +template<> EIGEN_STRONG_INLINE Packet2d pmadd(const Packet2d& a, const Packet2d& b, const Packet2d& c) { return _mm_fmadd_pd(a,b,c); } +#endif template<> EIGEN_STRONG_INLINE Packet4f pmin(const Packet4f& a, const Packet4f& b) { return _mm_min_ps(a,b); } template<> EIGEN_STRONG_INLINE Packet2d pmin(const Packet2d& a, const Packet2d& b) { return _mm_min_pd(a,b); } @@ -200,6 +276,17 @@ template<> EIGEN_STRONG_INLINE Packet4i pmax(const Packet4i& a, const #endif } +#ifdef EIGEN_VECTORIZE_SSE4_1 +template<> EIGEN_STRONG_INLINE Packet4f pround(const Packet4f& a) { return _mm_round_ps(a, 0); } +template<> EIGEN_STRONG_INLINE Packet2d pround(const Packet2d& a) { return _mm_round_pd(a, 0); } + +template<> EIGEN_STRONG_INLINE Packet4f pceil(const Packet4f& a) { return _mm_ceil_ps(a); } +template<> EIGEN_STRONG_INLINE Packet2d pceil(const Packet2d& a) { return _mm_ceil_pd(a); } + +template<> EIGEN_STRONG_INLINE Packet4f pfloor(const Packet4f& a) { return _mm_floor_ps(a); } +template<> EIGEN_STRONG_INLINE Packet2d pfloor(const Packet2d& a) { return _mm_floor_pd(a); } +#endif + template<> EIGEN_STRONG_INLINE Packet4f pand(const Packet4f& a, const Packet4f& b) { return _mm_and_ps(a,b); } template<> EIGEN_STRONG_INLINE Packet2d pand(const Packet2d& a, const Packet2d& b) { return _mm_and_pd(a,b); } template<> EIGEN_STRONG_INLINE Packet4i pand(const Packet4i& a, const Packet4i& b) { return _mm_and_si128(a,b); } @@ -218,16 +305,14 @@ template<> EIGEN_STRONG_INLINE Packet4i pandnot(const Packet4i& a, con template<> EIGEN_STRONG_INLINE Packet4f pload(const float* from) { EIGEN_DEBUG_ALIGNED_LOAD return _mm_load_ps(from); } template<> EIGEN_STRONG_INLINE Packet2d pload(const double* from) { EIGEN_DEBUG_ALIGNED_LOAD return _mm_load_pd(from); } -template<> EIGEN_STRONG_INLINE Packet4i pload(const int* from) { EIGEN_DEBUG_ALIGNED_LOAD return _mm_load_si128(reinterpret_cast(from)); } +template<> EIGEN_STRONG_INLINE Packet4i pload(const int* from) { EIGEN_DEBUG_ALIGNED_LOAD return _mm_load_si128(reinterpret_cast(from)); } -#if defined(_MSC_VER) +#if EIGEN_COMP_MSVC template<> EIGEN_STRONG_INLINE Packet4f ploadu(const float* from) { EIGEN_DEBUG_UNALIGNED_LOAD - #if (_MSC_VER==1600) + #if (EIGEN_COMP_MSVC==1600) // NOTE Some version of MSVC10 generates bad code when using _mm_loadu_ps // (i.e., it does not generate an unaligned load!! - // TODO On most architectures this version should also be faster than a single _mm_loadu_ps - // so we could also enable it for MSVC08 but first we have to make this later does not generate crap when doing so... __m128 res = _mm_loadl_pi(_mm_set1_ps(0.0f), (const __m64*)(from)); res = _mm_loadh_pi(res, (const __m64*)(from+2)); return res; @@ -235,63 +320,27 @@ template<> EIGEN_STRONG_INLINE Packet4i pload(const int* from) { E return _mm_loadu_ps(from); #endif } - template<> EIGEN_STRONG_INLINE Packet2d ploadu(const double* from) { EIGEN_DEBUG_UNALIGNED_LOAD return _mm_loadu_pd(from); } - template<> EIGEN_STRONG_INLINE Packet4i ploadu(const int* from) { EIGEN_DEBUG_UNALIGNED_LOAD return _mm_loadu_si128(reinterpret_cast(from)); } #else -// Fast unaligned loads. Note that here we cannot directly use intrinsics: this would -// require pointer casting to incompatible pointer types and leads to invalid code -// because of the strict aliasing rule. The "dummy" stuff are required to enforce -// a correct instruction dependency. -// TODO: do the same for MSVC (ICC is compatible) // NOTE: with the code below, MSVC's compiler crashes! -#if defined(__GNUC__) && defined(__i386__) - // bug 195: gcc/i386 emits weird x87 fldl/fstpl instructions for _mm_load_sd - #define EIGEN_AVOID_CUSTOM_UNALIGNED_LOADS 1 -#elif defined(__clang__) - // bug 201: Segfaults in __mm_loadh_pd with clang 2.8 - #define EIGEN_AVOID_CUSTOM_UNALIGNED_LOADS 1 -#else - #define EIGEN_AVOID_CUSTOM_UNALIGNED_LOADS 0 -#endif - template<> EIGEN_STRONG_INLINE Packet4f ploadu(const float* from) { EIGEN_DEBUG_UNALIGNED_LOAD -#if EIGEN_AVOID_CUSTOM_UNALIGNED_LOADS return _mm_loadu_ps(from); -#else - __m128d res; - res = _mm_load_sd((const double*)(from)) ; - res = _mm_loadh_pd(res, (const double*)(from+2)) ; - return _mm_castpd_ps(res); -#endif } +#endif + template<> EIGEN_STRONG_INLINE Packet2d ploadu(const double* from) { EIGEN_DEBUG_UNALIGNED_LOAD -#if EIGEN_AVOID_CUSTOM_UNALIGNED_LOADS return _mm_loadu_pd(from); -#else - __m128d res; - res = _mm_load_sd(from) ; - res = _mm_loadh_pd(res,from+1); - return res; -#endif } template<> EIGEN_STRONG_INLINE Packet4i ploadu(const int* from) { EIGEN_DEBUG_UNALIGNED_LOAD -#if EIGEN_AVOID_CUSTOM_UNALIGNED_LOADS - return _mm_loadu_si128(reinterpret_cast(from)); -#else - __m128d res; - res = _mm_load_sd((const double*)(from)) ; - res = _mm_loadh_pd(res, (const double*)(from+2)) ; - return _mm_castpd_si128(res); -#endif + return _mm_loadu_si128(reinterpret_cast(from)); } -#endif + template<> EIGEN_STRONG_INLINE Packet4f ploaddup(const float* from) { @@ -302,46 +351,77 @@ template<> EIGEN_STRONG_INLINE Packet2d ploaddup(const double* from) template<> EIGEN_STRONG_INLINE Packet4i ploaddup(const int* from) { Packet4i tmp; - tmp = _mm_loadl_epi64(reinterpret_cast(from)); + tmp = _mm_loadl_epi64(reinterpret_cast(from)); return vec4i_swizzle1(tmp, 0, 0, 1, 1); } template<> EIGEN_STRONG_INLINE void pstore(float* to, const Packet4f& from) { EIGEN_DEBUG_ALIGNED_STORE _mm_store_ps(to, from); } template<> EIGEN_STRONG_INLINE void pstore(double* to, const Packet2d& from) { EIGEN_DEBUG_ALIGNED_STORE _mm_store_pd(to, from); } -template<> EIGEN_STRONG_INLINE void pstore(int* to, const Packet4i& from) { EIGEN_DEBUG_ALIGNED_STORE _mm_store_si128(reinterpret_cast(to), from); } +template<> EIGEN_STRONG_INLINE void pstore(int* to, const Packet4i& from) { EIGEN_DEBUG_ALIGNED_STORE _mm_store_si128(reinterpret_cast<__m128i*>(to), from); } + +template<> EIGEN_STRONG_INLINE void pstoreu(double* to, const Packet2d& from) { EIGEN_DEBUG_UNALIGNED_STORE _mm_storeu_pd(to, from); } +template<> EIGEN_STRONG_INLINE void pstoreu(float* to, const Packet4f& from) { EIGEN_DEBUG_UNALIGNED_STORE _mm_storeu_ps(to, from); } +template<> EIGEN_STRONG_INLINE void pstoreu(int* to, const Packet4i& from) { EIGEN_DEBUG_UNALIGNED_STORE _mm_storeu_si128(reinterpret_cast<__m128i*>(to), from); } + +template<> EIGEN_DEVICE_FUNC inline Packet4f pgather(const float* from, Index stride) +{ + return _mm_set_ps(from[3*stride], from[2*stride], from[1*stride], from[0*stride]); +} +template<> EIGEN_DEVICE_FUNC inline Packet2d pgather(const double* from, Index stride) +{ + return _mm_set_pd(from[1*stride], from[0*stride]); +} +template<> EIGEN_DEVICE_FUNC inline Packet4i pgather(const int* from, Index stride) +{ + return _mm_set_epi32(from[3*stride], from[2*stride], from[1*stride], from[0*stride]); + } -template<> EIGEN_STRONG_INLINE void pstoreu(double* to, const Packet2d& from) { - EIGEN_DEBUG_UNALIGNED_STORE - _mm_storel_pd((to), from); - _mm_storeh_pd((to+1), from); +template<> EIGEN_DEVICE_FUNC inline void pscatter(float* to, const Packet4f& from, Index stride) +{ + to[stride*0] = _mm_cvtss_f32(from); + to[stride*1] = _mm_cvtss_f32(_mm_shuffle_ps(from, from, 1)); + to[stride*2] = _mm_cvtss_f32(_mm_shuffle_ps(from, from, 2)); + to[stride*3] = _mm_cvtss_f32(_mm_shuffle_ps(from, from, 3)); +} +template<> EIGEN_DEVICE_FUNC inline void pscatter(double* to, const Packet2d& from, Index stride) +{ + to[stride*0] = _mm_cvtsd_f64(from); + to[stride*1] = _mm_cvtsd_f64(_mm_shuffle_pd(from, from, 1)); +} +template<> EIGEN_DEVICE_FUNC inline void pscatter(int* to, const Packet4i& from, Index stride) +{ + to[stride*0] = _mm_cvtsi128_si32(from); + to[stride*1] = _mm_cvtsi128_si32(_mm_shuffle_epi32(from, 1)); + to[stride*2] = _mm_cvtsi128_si32(_mm_shuffle_epi32(from, 2)); + to[stride*3] = _mm_cvtsi128_si32(_mm_shuffle_epi32(from, 3)); } -template<> EIGEN_STRONG_INLINE void pstoreu(float* to, const Packet4f& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu(reinterpret_cast(to), _mm_castps_pd(from)); } -template<> EIGEN_STRONG_INLINE void pstoreu(int* to, const Packet4i& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu(reinterpret_cast(to), _mm_castsi128_pd(from)); } // some compilers might be tempted to perform multiple moves instead of using a vector path. template<> EIGEN_STRONG_INLINE void pstore1(float* to, const float& a) { Packet4f pa = _mm_set_ss(a); - pstore(to, vec4f_swizzle1(pa,0,0,0,0)); + pstore(to, Packet4f(vec4f_swizzle1(pa,0,0,0,0))); } // some compilers might be tempted to perform multiple moves instead of using a vector path. template<> EIGEN_STRONG_INLINE void pstore1(double* to, const double& a) { Packet2d pa = _mm_set_sd(a); - pstore(to, vec2d_swizzle1(pa,0,0)); + pstore(to, Packet2d(vec2d_swizzle1(pa,0,0))); } +#ifndef EIGEN_VECTORIZE_AVX template<> EIGEN_STRONG_INLINE void prefetch(const float* addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); } template<> EIGEN_STRONG_INLINE void prefetch(const double* addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); } template<> EIGEN_STRONG_INLINE void prefetch(const int* addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); } +#endif -#if defined(_MSC_VER) && defined(_WIN64) && !defined(__INTEL_COMPILER) +#if EIGEN_COMP_MSVC_STRICT && EIGEN_OS_WIN64 // The temporary variable fixes an internal compilation error in vs <= 2008 and a wrong-result bug in vs 2010 // Direct of the struct members fixed bug #62. template<> EIGEN_STRONG_INLINE float pfirst(const Packet4f& a) { return a.m128_f32[0]; } template<> EIGEN_STRONG_INLINE double pfirst(const Packet2d& a) { return a.m128d_f64[0]; } template<> EIGEN_STRONG_INLINE int pfirst(const Packet4i& a) { int x = _mm_cvtsi128_si32(a); return x; } -#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) +#elif EIGEN_COMP_MSVC_STRICT // The temporary variable fixes an internal compilation error in vs <= 2008 and a wrong-result bug in vs 2010 template<> EIGEN_STRONG_INLINE float pfirst(const Packet4f& a) { float x = _mm_cvtss_f32(a); return x; } template<> EIGEN_STRONG_INLINE double pfirst(const Packet2d& a) { double x = _mm_cvtsd_f64(a); return x; } @@ -359,7 +439,6 @@ template<> EIGEN_STRONG_INLINE Packet2d preverse(const Packet2d& a) template<> EIGEN_STRONG_INLINE Packet4i preverse(const Packet4i& a) { return _mm_shuffle_epi32(a,0x1B); } - template<> EIGEN_STRONG_INLINE Packet4f pabs(const Packet4f& a) { const Packet4f mask = _mm_castsi128_ps(_mm_setr_epi32(0x7FFFFFFF,0x7FFFFFFF,0x7FFFFFFF,0x7FFFFFFF)); @@ -380,6 +459,38 @@ template<> EIGEN_STRONG_INLINE Packet4i pabs(const Packet4i& a) #endif } +// with AVX, the default implementations based on pload1 are faster +#ifndef __AVX__ +template<> EIGEN_STRONG_INLINE void +pbroadcast4(const float *a, + Packet4f& a0, Packet4f& a1, Packet4f& a2, Packet4f& a3) +{ + a3 = pload(a); + a0 = vec4f_swizzle1(a3, 0,0,0,0); + a1 = vec4f_swizzle1(a3, 1,1,1,1); + a2 = vec4f_swizzle1(a3, 2,2,2,2); + a3 = vec4f_swizzle1(a3, 3,3,3,3); +} +template<> EIGEN_STRONG_INLINE void +pbroadcast4(const double *a, + Packet2d& a0, Packet2d& a1, Packet2d& a2, Packet2d& a3) +{ +#ifdef EIGEN_VECTORIZE_SSE3 + a0 = _mm_loaddup_pd(a+0); + a1 = _mm_loaddup_pd(a+1); + a2 = _mm_loaddup_pd(a+2); + a3 = _mm_loaddup_pd(a+3); +#else + a1 = pload(a); + a0 = vec2d_swizzle1(a1, 0,0); + a1 = vec2d_swizzle1(a1, 1,1); + a3 = pload(a+2); + a2 = vec2d_swizzle1(a3, 0,0); + a3 = vec2d_swizzle1(a3, 1,1); +#endif +} +#endif + EIGEN_STRONG_INLINE void punpackp(Packet4f* vecs) { vecs[1] = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(vecs[0]), 0x55)); @@ -389,47 +500,17 @@ EIGEN_STRONG_INLINE void punpackp(Packet4f* vecs) } #ifdef EIGEN_VECTORIZE_SSE3 -// TODO implement SSE2 versions as well as integer versions template<> EIGEN_STRONG_INLINE Packet4f preduxp(const Packet4f* vecs) { return _mm_hadd_ps(_mm_hadd_ps(vecs[0], vecs[1]),_mm_hadd_ps(vecs[2], vecs[3])); } + template<> EIGEN_STRONG_INLINE Packet2d preduxp(const Packet2d* vecs) { return _mm_hadd_pd(vecs[0], vecs[1]); } -// SSSE3 version: -// EIGEN_STRONG_INLINE Packet4i preduxp(const Packet4i* vecs) -// { -// return _mm_hadd_epi32(_mm_hadd_epi32(vecs[0], vecs[1]),_mm_hadd_epi32(vecs[2], vecs[3])); -// } -template<> EIGEN_STRONG_INLINE float predux(const Packet4f& a) -{ - Packet4f tmp0 = _mm_hadd_ps(a,a); - return pfirst(_mm_hadd_ps(tmp0, tmp0)); -} - -template<> EIGEN_STRONG_INLINE double predux(const Packet2d& a) { return pfirst(_mm_hadd_pd(a, a)); } - -// SSSE3 version: -// EIGEN_STRONG_INLINE float predux(const Packet4i& a) -// { -// Packet4i tmp0 = _mm_hadd_epi32(a,a); -// return pfirst(_mm_hadd_epi32(tmp0, tmp0)); -// } #else -// SSE2 versions -template<> EIGEN_STRONG_INLINE float predux(const Packet4f& a) -{ - Packet4f tmp = _mm_add_ps(a, _mm_movehl_ps(a,a)); - return pfirst(_mm_add_ss(tmp, _mm_shuffle_ps(tmp,tmp, 1))); -} -template<> EIGEN_STRONG_INLINE double predux(const Packet2d& a) -{ - return pfirst(_mm_add_sd(a, _mm_unpackhi_pd(a,a))); -} - template<> EIGEN_STRONG_INLINE Packet4f preduxp(const Packet4f* vecs) { Packet4f tmp0, tmp1, tmp2; @@ -450,10 +531,45 @@ template<> EIGEN_STRONG_INLINE Packet2d preduxp(const Packet2d* vecs) } #endif // SSE3 +template<> EIGEN_STRONG_INLINE float predux(const Packet4f& a) +{ + // Disable SSE3 _mm_hadd_pd that is extremely slow on all existing Intel's architectures + // (from Nehalem to Haswell) +// #ifdef EIGEN_VECTORIZE_SSE3 +// Packet4f tmp = _mm_add_ps(a, vec4f_swizzle1(a,2,3,2,3)); +// return pfirst(_mm_hadd_ps(tmp, tmp)); +// #else + Packet4f tmp = _mm_add_ps(a, _mm_movehl_ps(a,a)); + return pfirst(_mm_add_ss(tmp, _mm_shuffle_ps(tmp,tmp, 1))); +// #endif +} + +template<> EIGEN_STRONG_INLINE double predux(const Packet2d& a) +{ + // Disable SSE3 _mm_hadd_pd that is extremely slow on all existing Intel's architectures + // (from Nehalem to Haswell) +// #ifdef EIGEN_VECTORIZE_SSE3 +// return pfirst(_mm_hadd_pd(a, a)); +// #else + return pfirst(_mm_add_sd(a, _mm_unpackhi_pd(a,a))); +// #endif +} + +#ifdef EIGEN_VECTORIZE_SSSE3 +template<> EIGEN_STRONG_INLINE Packet4i preduxp(const Packet4i* vecs) +{ + return _mm_hadd_epi32(_mm_hadd_epi32(vecs[0], vecs[1]),_mm_hadd_epi32(vecs[2], vecs[3])); +} +template<> EIGEN_STRONG_INLINE int predux(const Packet4i& a) +{ + Packet4i tmp0 = _mm_hadd_epi32(a,a); + return pfirst(_mm_hadd_epi32(tmp0,tmp0)); +} +#else template<> EIGEN_STRONG_INLINE int predux(const Packet4i& a) { Packet4i tmp = _mm_add_epi32(a, _mm_unpackhi_epi64(a,a)); - return pfirst(tmp) + pfirst(_mm_shuffle_epi32(tmp, 1)); + return pfirst(tmp) + pfirst(_mm_shuffle_epi32(tmp, 1)); } template<> EIGEN_STRONG_INLINE Packet4i preduxp(const Packet4i* vecs) @@ -469,18 +585,18 @@ template<> EIGEN_STRONG_INLINE Packet4i preduxp(const Packet4i* vecs) tmp0 = _mm_unpackhi_epi64(tmp0, tmp1); return _mm_add_epi32(tmp0, tmp2); } - +#endif // Other reduction functions: // mul template<> EIGEN_STRONG_INLINE float predux_mul(const Packet4f& a) { Packet4f tmp = _mm_mul_ps(a, _mm_movehl_ps(a,a)); - return pfirst(_mm_mul_ss(tmp, _mm_shuffle_ps(tmp,tmp, 1))); + return pfirst(_mm_mul_ss(tmp, _mm_shuffle_ps(tmp,tmp, 1))); } template<> EIGEN_STRONG_INLINE double predux_mul(const Packet2d& a) { - return pfirst(_mm_mul_sd(a, _mm_unpackhi_pd(a,a))); + return pfirst(_mm_mul_sd(a, _mm_unpackhi_pd(a,a))); } template<> EIGEN_STRONG_INLINE int predux_mul(const Packet4i& a) { @@ -496,14 +612,18 @@ template<> EIGEN_STRONG_INLINE int predux_mul(const Packet4i& a) template<> EIGEN_STRONG_INLINE float predux_min(const Packet4f& a) { Packet4f tmp = _mm_min_ps(a, _mm_movehl_ps(a,a)); - return pfirst(_mm_min_ss(tmp, _mm_shuffle_ps(tmp,tmp, 1))); + return pfirst(_mm_min_ss(tmp, _mm_shuffle_ps(tmp,tmp, 1))); } template<> EIGEN_STRONG_INLINE double predux_min(const Packet2d& a) { - return pfirst(_mm_min_sd(a, _mm_unpackhi_pd(a,a))); + return pfirst(_mm_min_sd(a, _mm_unpackhi_pd(a,a))); } template<> EIGEN_STRONG_INLINE int predux_min(const Packet4i& a) { +#ifdef EIGEN_VECTORIZE_SSE4_1 + Packet4i tmp = _mm_min_epi32(a, _mm_shuffle_epi32(a, _MM_SHUFFLE(0,0,3,2))); + return pfirst(_mm_min_epi32(tmp,_mm_shuffle_epi32(tmp, 1))); +#else // after some experiments, it is seems this is the fastest way to implement it // for GCC (eg., it does not like using std::min after the pstore !!) EIGEN_ALIGN16 int aux[4]; @@ -511,20 +631,25 @@ template<> EIGEN_STRONG_INLINE int predux_min(const Packet4i& a) int aux0 = aux[0] EIGEN_STRONG_INLINE float predux_max(const Packet4f& a) { Packet4f tmp = _mm_max_ps(a, _mm_movehl_ps(a,a)); - return pfirst(_mm_max_ss(tmp, _mm_shuffle_ps(tmp,tmp, 1))); + return pfirst(_mm_max_ss(tmp, _mm_shuffle_ps(tmp,tmp, 1))); } template<> EIGEN_STRONG_INLINE double predux_max(const Packet2d& a) { - return pfirst(_mm_max_sd(a, _mm_unpackhi_pd(a,a))); + return pfirst(_mm_max_sd(a, _mm_unpackhi_pd(a,a))); } template<> EIGEN_STRONG_INLINE int predux_max(const Packet4i& a) { +#ifdef EIGEN_VECTORIZE_SSE4_1 + Packet4i tmp = _mm_max_epi32(a, _mm_shuffle_epi32(a, _MM_SHUFFLE(0,0,3,2))); + return pfirst(_mm_max_epi32(tmp,_mm_shuffle_epi32(tmp, 1))); +#else // after some experiments, it is seems this is the fastest way to implement it // for GCC (eg., it does not like using std::min after the pstore !!) EIGEN_ALIGN16 int aux[4]; @@ -532,9 +657,10 @@ template<> EIGEN_STRONG_INLINE int predux_max(const Packet4i& a) int aux0 = aux[0]>aux[1] ? aux[0] : aux[1]; int aux2 = aux[2]>aux[3] ? aux[2] : aux[3]; return aux0>aux2 ? aux0 : aux2; +#endif // EIGEN_VECTORIZE_SSE4_1 } -#if (defined __GNUC__) +#if EIGEN_COMP_GNUC // template <> EIGEN_STRONG_INLINE Packet4f pmadd(const Packet4f& a, const Packet4f& b, const Packet4f& c) // { // Packet4f res = b; @@ -642,6 +768,110 @@ struct palign_impl }; #endif +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + _MM_TRANSPOSE4_PS(kernel.packet[0], kernel.packet[1], kernel.packet[2], kernel.packet[3]); +} + +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + __m128d tmp = _mm_unpackhi_pd(kernel.packet[0], kernel.packet[1]); + kernel.packet[0] = _mm_unpacklo_pd(kernel.packet[0], kernel.packet[1]); + kernel.packet[1] = tmp; +} + +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + __m128i T0 = _mm_unpacklo_epi32(kernel.packet[0], kernel.packet[1]); + __m128i T1 = _mm_unpacklo_epi32(kernel.packet[2], kernel.packet[3]); + __m128i T2 = _mm_unpackhi_epi32(kernel.packet[0], kernel.packet[1]); + __m128i T3 = _mm_unpackhi_epi32(kernel.packet[2], kernel.packet[3]); + + kernel.packet[0] = _mm_unpacklo_epi64(T0, T1); + kernel.packet[1] = _mm_unpackhi_epi64(T0, T1); + kernel.packet[2] = _mm_unpacklo_epi64(T2, T3); + kernel.packet[3] = _mm_unpackhi_epi64(T2, T3); +} + +template<> EIGEN_STRONG_INLINE Packet4i pblend(const Selector<4>& ifPacket, const Packet4i& thenPacket, const Packet4i& elsePacket) { + const __m128i zero = _mm_setzero_si128(); + const __m128i select = _mm_set_epi32(ifPacket.select[3], ifPacket.select[2], ifPacket.select[1], ifPacket.select[0]); + __m128i false_mask = _mm_cmpeq_epi32(select, zero); +#ifdef EIGEN_VECTORIZE_SSE4_1 + return _mm_blendv_epi8(thenPacket, elsePacket, false_mask); +#else + return _mm_or_si128(_mm_andnot_si128(false_mask, thenPacket), _mm_and_si128(false_mask, elsePacket)); +#endif +} +template<> EIGEN_STRONG_INLINE Packet4f pblend(const Selector<4>& ifPacket, const Packet4f& thenPacket, const Packet4f& elsePacket) { + const __m128 zero = _mm_setzero_ps(); + const __m128 select = _mm_set_ps(ifPacket.select[3], ifPacket.select[2], ifPacket.select[1], ifPacket.select[0]); + __m128 false_mask = _mm_cmpeq_ps(select, zero); +#ifdef EIGEN_VECTORIZE_SSE4_1 + return _mm_blendv_ps(thenPacket, elsePacket, false_mask); +#else + return _mm_or_ps(_mm_andnot_ps(false_mask, thenPacket), _mm_and_ps(false_mask, elsePacket)); +#endif +} +template<> EIGEN_STRONG_INLINE Packet2d pblend(const Selector<2>& ifPacket, const Packet2d& thenPacket, const Packet2d& elsePacket) { + const __m128d zero = _mm_setzero_pd(); + const __m128d select = _mm_set_pd(ifPacket.select[1], ifPacket.select[0]); + __m128d false_mask = _mm_cmpeq_pd(select, zero); +#ifdef EIGEN_VECTORIZE_SSE4_1 + return _mm_blendv_pd(thenPacket, elsePacket, false_mask); +#else + return _mm_or_pd(_mm_andnot_pd(false_mask, thenPacket), _mm_and_pd(false_mask, elsePacket)); +#endif +} + +template<> EIGEN_STRONG_INLINE Packet4f pinsertfirst(const Packet4f& a, float b) +{ +#ifdef EIGEN_VECTORIZE_SSE4_1 + return _mm_blend_ps(a,pset1(b),1); +#else + return _mm_move_ss(a, _mm_load_ss(&b)); +#endif +} + +template<> EIGEN_STRONG_INLINE Packet2d pinsertfirst(const Packet2d& a, double b) +{ +#ifdef EIGEN_VECTORIZE_SSE4_1 + return _mm_blend_pd(a,pset1(b),1); +#else + return _mm_move_sd(a, _mm_load_sd(&b)); +#endif +} + +template<> EIGEN_STRONG_INLINE Packet4f pinsertlast(const Packet4f& a, float b) +{ +#ifdef EIGEN_VECTORIZE_SSE4_1 + return _mm_blend_ps(a,pset1(b),(1<<3)); +#else + const Packet4f mask = _mm_castsi128_ps(_mm_setr_epi32(0x0,0x0,0x0,0xFFFFFFFF)); + return _mm_or_ps(_mm_andnot_ps(mask, a), _mm_and_ps(mask, pset1(b))); +#endif +} + +template<> EIGEN_STRONG_INLINE Packet2d pinsertlast(const Packet2d& a, double b) +{ +#ifdef EIGEN_VECTORIZE_SSE4_1 + return _mm_blend_pd(a,pset1(b),(1<<1)); +#else + const Packet2d mask = _mm_castsi128_pd(_mm_setr_epi32(0x0,0x0,0xFFFFFFFF,0xFFFFFFFF)); + return _mm_or_pd(_mm_andnot_pd(mask, a), _mm_and_pd(mask, pset1(b))); +#endif +} + +// Scalar path for pmadd with FMA to ensure consistency with vectorized path. +#ifdef __FMA__ +template<> EIGEN_STRONG_INLINE float pmadd(const float& a, const float& b, const float& c) { + return ::fmaf(a,b,c); +} +template<> EIGEN_STRONG_INLINE double pmadd(const double& a, const double& b, const double& c) { + return ::fma(a,b,c); +} +#endif + } // end namespace internal } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/Core/arch/SSE/TypeCasting.h b/libs/eigen3/Eigen/src/Core/arch/SSE/TypeCasting.h new file mode 100644 index 000000000..c84893230 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/arch/SSE/TypeCasting.h @@ -0,0 +1,77 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_TYPE_CASTING_SSE_H +#define EIGEN_TYPE_CASTING_SSE_H + +namespace Eigen { + +namespace internal { + +template <> +struct type_casting_traits { + enum { + VectorizedCast = 1, + SrcCoeffRatio = 1, + TgtCoeffRatio = 1 + }; +}; + +template<> EIGEN_STRONG_INLINE Packet4i pcast(const Packet4f& a) { + return _mm_cvttps_epi32(a); +} + + +template <> +struct type_casting_traits { + enum { + VectorizedCast = 1, + SrcCoeffRatio = 1, + TgtCoeffRatio = 1 + }; +}; + +template<> EIGEN_STRONG_INLINE Packet4f pcast(const Packet4i& a) { + return _mm_cvtepi32_ps(a); +} + + +template <> +struct type_casting_traits { + enum { + VectorizedCast = 1, + SrcCoeffRatio = 2, + TgtCoeffRatio = 1 + }; +}; + +template<> EIGEN_STRONG_INLINE Packet4f pcast(const Packet2d& a, const Packet2d& b) { + return _mm_shuffle_ps(_mm_cvtpd_ps(a), _mm_cvtpd_ps(b), (1 << 2) | (1 << 6)); +} + +template <> +struct type_casting_traits { + enum { + VectorizedCast = 1, + SrcCoeffRatio = 1, + TgtCoeffRatio = 2 + }; +}; + +template<> EIGEN_STRONG_INLINE Packet2d pcast(const Packet4f& a) { + // Simply discard the second half of the input + return _mm_cvtps_pd(a); +} + + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_TYPE_CASTING_SSE_H diff --git a/libs/eigen3/Eigen/src/Core/arch/ZVector/Complex.h b/libs/eigen3/Eigen/src/Core/arch/ZVector/Complex.h new file mode 100644 index 000000000..d39d2d105 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/arch/ZVector/Complex.h @@ -0,0 +1,394 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2010 Gael Guennebaud +// Copyright (C) 2016 Konstantinos Margaritis +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_COMPLEX32_ALTIVEC_H +#define EIGEN_COMPLEX32_ALTIVEC_H + +namespace Eigen { + +namespace internal { + +static Packet2ul p2ul_CONJ_XOR1 = (Packet2ul) vec_sld((Packet4ui) p2d_ZERO_, (Packet4ui) p2l_ZERO, 8);//{ 0x8000000000000000, 0x0000000000000000 }; +static Packet2ul p2ul_CONJ_XOR2 = (Packet2ul) vec_sld((Packet4ui) p2l_ZERO, (Packet4ui) p2d_ZERO_, 8);//{ 0x8000000000000000, 0x0000000000000000 }; + +struct Packet1cd +{ + EIGEN_STRONG_INLINE Packet1cd() {} + EIGEN_STRONG_INLINE explicit Packet1cd(const Packet2d& a) : v(a) {} + Packet2d v; +}; + +struct Packet2cf +{ + EIGEN_STRONG_INLINE Packet2cf() {} + EIGEN_STRONG_INLINE explicit Packet2cf(const Packet4f& a) : v(a) {} + union { + Packet4f v; + Packet1cd cd[2]; + }; +}; + +template<> struct packet_traits > : default_packet_traits +{ + typedef Packet2cf type; + typedef Packet2cf half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size = 2, + HasHalfPacket = 0, + + HasAdd = 1, + HasSub = 1, + HasMul = 1, + HasDiv = 1, + HasNegate = 1, + HasAbs = 0, + HasAbs2 = 0, + HasMin = 0, + HasMax = 0, + HasBlend = 1, + HasSetLinear = 0 + }; +}; + + +template<> struct packet_traits > : default_packet_traits +{ + typedef Packet1cd type; + typedef Packet1cd half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size = 1, + HasHalfPacket = 0, + + HasAdd = 1, + HasSub = 1, + HasMul = 1, + HasDiv = 1, + HasNegate = 1, + HasAbs = 0, + HasAbs2 = 0, + HasMin = 0, + HasMax = 0, + HasSetLinear = 0 + }; +}; + +template<> struct unpacket_traits { typedef std::complex type; enum {size=2, alignment=Aligned16}; typedef Packet2cf half; }; +template<> struct unpacket_traits { typedef std::complex type; enum {size=1, alignment=Aligned16}; typedef Packet1cd half; }; + +/* Forward declaration */ +EIGEN_STRONG_INLINE void ptranspose(PacketBlock& kernel); + +template<> EIGEN_STRONG_INLINE Packet2cf pload (const std::complex* from) { EIGEN_DEBUG_ALIGNED_LOAD return Packet2cf(pload((const float*)from)); } +template<> EIGEN_STRONG_INLINE Packet1cd pload (const std::complex* from) { EIGEN_DEBUG_ALIGNED_LOAD return Packet1cd(pload((const double*)from)); } +template<> EIGEN_STRONG_INLINE Packet2cf ploadu(const std::complex* from) { EIGEN_DEBUG_UNALIGNED_LOAD return Packet2cf(ploadu((const float*)from)); } +template<> EIGEN_STRONG_INLINE Packet1cd ploadu(const std::complex* from) { EIGEN_DEBUG_UNALIGNED_LOAD return Packet1cd(ploadu((const double*)from)); } +template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet2cf& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((float*)to, from.v); } +template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet1cd& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((double*)to, from.v); } +template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet2cf& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((float*)to, from.v); } +template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet1cd& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, from.v); } + +template<> EIGEN_STRONG_INLINE Packet1cd pset1(const std::complex& from) +{ /* here we really have to use unaligned loads :( */ return ploadu(&from); } + +template<> EIGEN_STRONG_INLINE Packet2cf pset1(const std::complex& from) +{ + Packet2cf res; + res.cd[0] = Packet1cd(vec_ld2f((const float *)&from)); + res.cd[1] = res.cd[0]; + return res; +} +template<> EIGEN_DEVICE_FUNC inline Packet2cf pgather, Packet2cf>(const std::complex* from, Index stride) +{ + std::complex EIGEN_ALIGN16 af[2]; + af[0] = from[0*stride]; + af[1] = from[1*stride]; + return pload(af); +} +template<> EIGEN_DEVICE_FUNC inline Packet1cd pgather, Packet1cd>(const std::complex* from, Index stride EIGEN_UNUSED) +{ + return pload(from); +} +template<> EIGEN_DEVICE_FUNC inline void pscatter, Packet2cf>(std::complex* to, const Packet2cf& from, Index stride) +{ + std::complex EIGEN_ALIGN16 af[2]; + pstore >((std::complex *) af, from); + to[0*stride] = af[0]; + to[1*stride] = af[1]; +} +template<> EIGEN_DEVICE_FUNC inline void pscatter, Packet1cd>(std::complex* to, const Packet1cd& from, Index stride EIGEN_UNUSED) +{ + pstore >(to, from); +} + +template<> EIGEN_STRONG_INLINE Packet2cf padd(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(padd(a.v, b.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd padd(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(a.v + b.v); } +template<> EIGEN_STRONG_INLINE Packet2cf psub(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(psub(a.v, b.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd psub(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(a.v - b.v); } +template<> EIGEN_STRONG_INLINE Packet1cd pnegate(const Packet1cd& a) { return Packet1cd(pnegate(Packet2d(a.v))); } +template<> EIGEN_STRONG_INLINE Packet2cf pnegate(const Packet2cf& a) { return Packet2cf(pnegate(Packet4f(a.v))); } +template<> EIGEN_STRONG_INLINE Packet1cd pconj(const Packet1cd& a) { return Packet1cd((Packet2d)vec_xor((Packet2d)a.v, (Packet2d)p2ul_CONJ_XOR2)); } +template<> EIGEN_STRONG_INLINE Packet2cf pconj(const Packet2cf& a) +{ + Packet2cf res; + res.v.v4f[0] = pconj(Packet1cd(reinterpret_cast(a.v.v4f[0]))).v; + res.v.v4f[1] = pconj(Packet1cd(reinterpret_cast(a.v.v4f[1]))).v; + return res; +} + +template<> EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) +{ + Packet2d a_re, a_im, v1, v2; + + // Permute and multiply the real parts of a and b + a_re = vec_perm(a.v, a.v, p16uc_PSET64_HI); + // Get the imaginary parts of a + a_im = vec_perm(a.v, a.v, p16uc_PSET64_LO); + // multiply a_re * b + v1 = vec_madd(a_re, b.v, p2d_ZERO); + // multiply a_im * b and get the conjugate result + v2 = vec_madd(a_im, b.v, p2d_ZERO); + v2 = (Packet2d) vec_sld((Packet4ui)v2, (Packet4ui)v2, 8); + v2 = (Packet2d) vec_xor((Packet2d)v2, (Packet2d) p2ul_CONJ_XOR1); + + return Packet1cd(v1 + v2); +} +template<> EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, const Packet2cf& b) +{ + Packet2cf res; + res.v.v4f[0] = pmul(Packet1cd(reinterpret_cast(a.v.v4f[0])), Packet1cd(reinterpret_cast(b.v.v4f[0]))).v; + res.v.v4f[1] = pmul(Packet1cd(reinterpret_cast(a.v.v4f[1])), Packet1cd(reinterpret_cast(b.v.v4f[1]))).v; + return res; +} + +template<> EIGEN_STRONG_INLINE Packet1cd pand (const Packet1cd& a, const Packet1cd& b) { return Packet1cd(vec_and(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet2cf pand (const Packet2cf& a, const Packet2cf& b) { return Packet2cf(pand(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd por (const Packet1cd& a, const Packet1cd& b) { return Packet1cd(vec_or(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet2cf por (const Packet2cf& a, const Packet2cf& b) { return Packet2cf(por(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd pxor (const Packet1cd& a, const Packet1cd& b) { return Packet1cd(vec_xor(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet2cf pxor (const Packet2cf& a, const Packet2cf& b) { return Packet2cf(pxor(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd pandnot(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(vec_and(a.v, vec_nor(b.v,b.v))); } +template<> EIGEN_STRONG_INLINE Packet2cf pandnot(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(pandnot(a.v,b.v)); } + +template<> EIGEN_STRONG_INLINE Packet1cd ploaddup(const std::complex* from) { return pset1(*from); } +template<> EIGEN_STRONG_INLINE Packet2cf ploaddup(const std::complex* from) { return pset1(*from); } + +template<> EIGEN_STRONG_INLINE void prefetch >(const std::complex * addr) { EIGEN_ZVECTOR_PREFETCH(addr); } +template<> EIGEN_STRONG_INLINE void prefetch >(const std::complex * addr) { EIGEN_ZVECTOR_PREFETCH(addr); } + +template<> EIGEN_STRONG_INLINE std::complex pfirst(const Packet1cd& a) +{ + std::complex EIGEN_ALIGN16 res; + pstore >(&res, a); + + return res; +} +template<> EIGEN_STRONG_INLINE std::complex pfirst(const Packet2cf& a) +{ + std::complex EIGEN_ALIGN16 res[2]; + pstore >(res, a); + + return res[0]; +} + +template<> EIGEN_STRONG_INLINE Packet1cd preverse(const Packet1cd& a) { return a; } +template<> EIGEN_STRONG_INLINE Packet2cf preverse(const Packet2cf& a) +{ + Packet2cf res; + res.cd[0] = a.cd[1]; + res.cd[1] = a.cd[0]; + return res; +} + +template<> EIGEN_STRONG_INLINE std::complex predux(const Packet1cd& a) +{ + return pfirst(a); +} +template<> EIGEN_STRONG_INLINE std::complex predux(const Packet2cf& a) +{ + std::complex res; + Packet1cd b = padd(a.cd[0], a.cd[1]); + vec_st2f(b.v, (float*)&res); + return res; +} + +template<> EIGEN_STRONG_INLINE Packet1cd preduxp(const Packet1cd* vecs) +{ + return vecs[0]; +} +template<> EIGEN_STRONG_INLINE Packet2cf preduxp(const Packet2cf* vecs) +{ + PacketBlock transpose; + transpose.packet[0] = vecs[0]; + transpose.packet[1] = vecs[1]; + ptranspose(transpose); + + return padd(transpose.packet[0], transpose.packet[1]); +} + +template<> EIGEN_STRONG_INLINE std::complex predux_mul(const Packet1cd& a) +{ + return pfirst(a); +} +template<> EIGEN_STRONG_INLINE std::complex predux_mul(const Packet2cf& a) +{ + std::complex res; + Packet1cd b = pmul(a.cd[0], a.cd[1]); + vec_st2f(b.v, (float*)&res); + return res; +} + +template +struct palign_impl +{ + static EIGEN_STRONG_INLINE void run(Packet1cd& /*first*/, const Packet1cd& /*second*/) + { + // FIXME is it sure we never have to align a Packet1cd? + // Even though a std::complex has 16 bytes, it is not necessarily aligned on a 16 bytes boundary... + } +}; + +template +struct palign_impl +{ + static EIGEN_STRONG_INLINE void run(Packet2cf& first, const Packet2cf& second) + { + if (Offset == 1) { + first.cd[0] = first.cd[1]; + first.cd[1] = second.cd[0]; + } + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet1cd& y, const Packet1cd& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) const + { + return internal::pmul(a, pconj(b)); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet1cd& y, const Packet1cd& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) const + { + return internal::pmul(pconj(a), b); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet1cd& y, const Packet1cd& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) const + { + return pconj(internal::pmul(a, b)); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet2cf pmadd(const Packet2cf& x, const Packet2cf& y, const Packet2cf& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, const Packet2cf& b) const + { + return internal::pmul(a, pconj(b)); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet2cf pmadd(const Packet2cf& x, const Packet2cf& y, const Packet2cf& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, const Packet2cf& b) const + { + return internal::pmul(pconj(a), b); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet2cf pmadd(const Packet2cf& x, const Packet2cf& y, const Packet2cf& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, const Packet2cf& b) const + { + return pconj(internal::pmul(a, b)); + } +}; + +template<> EIGEN_STRONG_INLINE Packet1cd pdiv(const Packet1cd& a, const Packet1cd& b) +{ + // TODO optimize it for AltiVec + Packet1cd res = conj_helper().pmul(a,b); + Packet2d s = vec_madd(b.v, b.v, p2d_ZERO_); + return Packet1cd(pdiv(res.v, s + vec_perm(s, s, p16uc_REVERSE64))); +} + +template<> EIGEN_STRONG_INLINE Packet2cf pdiv(const Packet2cf& a, const Packet2cf& b) +{ + // TODO optimize it for AltiVec + Packet2cf res; + res.cd[0] = pdiv(a.cd[0], b.cd[0]); + res.cd[1] = pdiv(a.cd[1], b.cd[1]); + return res; +} + +EIGEN_STRONG_INLINE Packet1cd pcplxflip/**/(const Packet1cd& x) +{ + return Packet1cd(preverse(Packet2d(x.v))); +} + +EIGEN_STRONG_INLINE Packet2cf pcplxflip/**/(const Packet2cf& x) +{ + Packet2cf res; + res.cd[0] = pcplxflip(x.cd[0]); + res.cd[1] = pcplxflip(x.cd[1]); + return res; +} + +EIGEN_STRONG_INLINE void ptranspose(PacketBlock& kernel) +{ + Packet2d tmp = vec_perm(kernel.packet[0].v, kernel.packet[1].v, p16uc_TRANSPOSE64_HI); + kernel.packet[1].v = vec_perm(kernel.packet[0].v, kernel.packet[1].v, p16uc_TRANSPOSE64_LO); + kernel.packet[0].v = tmp; +} + +EIGEN_STRONG_INLINE void ptranspose(PacketBlock& kernel) +{ + Packet1cd tmp = kernel.packet[0].cd[1]; + kernel.packet[0].cd[1] = kernel.packet[1].cd[0]; + kernel.packet[1].cd[0] = tmp; +} + +template<> EIGEN_STRONG_INLINE Packet2cf pblend(const Selector<2>& ifPacket, const Packet2cf& thenPacket, const Packet2cf& elsePacket) { + Packet2cf result; + const Selector<4> ifPacket4 = { ifPacket.select[0], ifPacket.select[0], ifPacket.select[1], ifPacket.select[1] }; + result.v = pblend(ifPacket4, thenPacket.v, elsePacket.v); + return result; +} + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_COMPLEX32_ALTIVEC_H diff --git a/libs/eigen3/Eigen/src/Core/arch/ZVector/MathFunctions.h b/libs/eigen3/Eigen/src/Core/arch/ZVector/MathFunctions.h new file mode 100644 index 000000000..5c7aa7256 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/arch/ZVector/MathFunctions.h @@ -0,0 +1,137 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2007 Julien Pommier +// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2016 Konstantinos Margaritis +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +/* The sin, cos, exp, and log functions of this file come from + * Julien Pommier's sse math library: http://gruntthepeon.free.fr/ssemath/ + */ + +#ifndef EIGEN_MATH_FUNCTIONS_ALTIVEC_H +#define EIGEN_MATH_FUNCTIONS_ALTIVEC_H + +namespace Eigen { + +namespace internal { + +static _EIGEN_DECLARE_CONST_Packet2d(1 , 1.0); +static _EIGEN_DECLARE_CONST_Packet2d(2 , 2.0); +static _EIGEN_DECLARE_CONST_Packet2d(half, 0.5); + +static _EIGEN_DECLARE_CONST_Packet2d(exp_hi, 709.437); +static _EIGEN_DECLARE_CONST_Packet2d(exp_lo, -709.436139303); + +static _EIGEN_DECLARE_CONST_Packet2d(cephes_LOG2EF, 1.4426950408889634073599); + +static _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_p0, 1.26177193074810590878e-4); +static _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_p1, 3.02994407707441961300e-2); +static _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_p2, 9.99999999999999999910e-1); + +static _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_q0, 3.00198505138664455042e-6); +static _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_q1, 2.52448340349684104192e-3); +static _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_q2, 2.27265548208155028766e-1); +static _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_q3, 2.00000000000000000009e0); + +static _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_C1, 0.693145751953125); +static _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_C2, 1.42860682030941723212e-6); + +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet2d pexp(const Packet2d& _x) +{ + Packet2d x = _x; + + Packet2d tmp, fx; + Packet2l emm0; + + // clamp x + x = pmax(pmin(x, p2d_exp_hi), p2d_exp_lo); + /* express exp(x) as exp(g + n*log(2)) */ + fx = pmadd(p2d_cephes_LOG2EF, x, p2d_half); + + fx = vec_floor(fx); + + tmp = pmul(fx, p2d_cephes_exp_C1); + Packet2d z = pmul(fx, p2d_cephes_exp_C2); + x = psub(x, tmp); + x = psub(x, z); + + Packet2d x2 = pmul(x,x); + + Packet2d px = p2d_cephes_exp_p0; + px = pmadd(px, x2, p2d_cephes_exp_p1); + px = pmadd(px, x2, p2d_cephes_exp_p2); + px = pmul (px, x); + + Packet2d qx = p2d_cephes_exp_q0; + qx = pmadd(qx, x2, p2d_cephes_exp_q1); + qx = pmadd(qx, x2, p2d_cephes_exp_q2); + qx = pmadd(qx, x2, p2d_cephes_exp_q3); + + x = pdiv(px,psub(qx,px)); + x = pmadd(p2d_2,x,p2d_1); + + // build 2^n + emm0 = vec_ctsl(fx, 0); + + static const Packet2l p2l_1023 = { 1023, 1023 }; + static const Packet2ul p2ul_52 = { 52, 52 }; + + emm0 = emm0 + p2l_1023; + emm0 = emm0 << reinterpret_cast(p2ul_52); + + // Altivec's max & min operators just drop silent NaNs. Check NaNs in + // inputs and return them unmodified. + Packet2ul isnumber_mask = reinterpret_cast(vec_cmpeq(_x, _x)); + return vec_sel(_x, pmax(pmul(x, reinterpret_cast(emm0)), _x), + isnumber_mask); +} + +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet4f pexp(const Packet4f& x) +{ + Packet4f res; + res.v4f[0] = pexp(x.v4f[0]); + res.v4f[1] = pexp(x.v4f[1]); + return res; +} + +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet2d psqrt(const Packet2d& x) +{ + return __builtin_s390_vfsqdb(x); +} + +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet4f psqrt(const Packet4f& x) +{ + Packet4f res; + res.v4f[0] = psqrt(x.v4f[0]); + res.v4f[1] = psqrt(x.v4f[1]); + return res; +} + +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet2d prsqrt(const Packet2d& x) { + // Unfortunately we can't use the much faster mm_rqsrt_pd since it only provides an approximation. + return pset1(1.0) / psqrt(x); +} + +template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED +Packet4f prsqrt(const Packet4f& x) { + Packet4f res; + res.v4f[0] = prsqrt(x.v4f[0]); + res.v4f[1] = prsqrt(x.v4f[1]); + return res; +} + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_MATH_FUNCTIONS_ALTIVEC_H diff --git a/libs/eigen3/Eigen/src/Core/arch/ZVector/PacketMath.h b/libs/eigen3/Eigen/src/Core/arch/ZVector/PacketMath.h new file mode 100755 index 000000000..57b01fc63 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/arch/ZVector/PacketMath.h @@ -0,0 +1,945 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2016 Konstantinos Margaritis +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_PACKET_MATH_ZVECTOR_H +#define EIGEN_PACKET_MATH_ZVECTOR_H + +#include + +namespace Eigen { + +namespace internal { + +#ifndef EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD +#define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 4 +#endif + +#ifndef EIGEN_HAS_SINGLE_INSTRUCTION_MADD +#define EIGEN_HAS_SINGLE_INSTRUCTION_MADD +#endif + +#ifndef EIGEN_HAS_SINGLE_INSTRUCTION_CJMADD +#define EIGEN_HAS_SINGLE_INSTRUCTION_CJMADD +#endif + +#ifndef EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS +#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 16 +#endif + +typedef __vector int Packet4i; +typedef __vector unsigned int Packet4ui; +typedef __vector __bool int Packet4bi; +typedef __vector short int Packet8i; +typedef __vector unsigned char Packet16uc; +typedef __vector double Packet2d; +typedef __vector unsigned long long Packet2ul; +typedef __vector long long Packet2l; + +typedef struct { + Packet2d v4f[2]; +} Packet4f; + +typedef union { + int32_t i[4]; + uint32_t ui[4]; + int64_t l[2]; + uint64_t ul[2]; + double d[2]; + Packet4i v4i; + Packet4ui v4ui; + Packet2l v2l; + Packet2ul v2ul; + Packet2d v2d; +} Packet; + +// We don't want to write the same code all the time, but we need to reuse the constants +// and it doesn't really work to declare them global, so we define macros instead + +#define _EIGEN_DECLARE_CONST_FAST_Packet4i(NAME,X) \ + Packet4i p4i_##NAME = reinterpret_cast(vec_splat_s32(X)) + +#define _EIGEN_DECLARE_CONST_FAST_Packet2d(NAME,X) \ + Packet2d p2d_##NAME = reinterpret_cast(vec_splat_s64(X)) + +#define _EIGEN_DECLARE_CONST_FAST_Packet2l(NAME,X) \ + Packet2l p2l_##NAME = reinterpret_cast(vec_splat_s64(X)) + +#define _EIGEN_DECLARE_CONST_Packet4i(NAME,X) \ + Packet4i p4i_##NAME = pset1(X) + +#define _EIGEN_DECLARE_CONST_Packet2d(NAME,X) \ + Packet2d p2d_##NAME = pset1(X) + +#define _EIGEN_DECLARE_CONST_Packet2l(NAME,X) \ + Packet2l p2l_##NAME = pset1(X) + +// These constants are endian-agnostic +//static _EIGEN_DECLARE_CONST_FAST_Packet4i(ZERO, 0); //{ 0, 0, 0, 0,} +static _EIGEN_DECLARE_CONST_FAST_Packet4i(ONE, 1); //{ 1, 1, 1, 1} + +static _EIGEN_DECLARE_CONST_FAST_Packet2d(ZERO, 0); +static _EIGEN_DECLARE_CONST_FAST_Packet2l(ZERO, 0); +static _EIGEN_DECLARE_CONST_FAST_Packet2l(ONE, 1); + +static Packet2d p2d_ONE = { 1.0, 1.0 }; +static Packet2d p2d_ZERO_ = { -0.0, -0.0 }; + +static Packet4i p4i_COUNTDOWN = { 0, 1, 2, 3 }; +static Packet4f p4f_COUNTDOWN = { 0.0, 1.0, 2.0, 3.0 }; +static Packet2d p2d_COUNTDOWN = reinterpret_cast(vec_sld(reinterpret_cast(p2d_ZERO), reinterpret_cast(p2d_ONE), 8)); + +static Packet16uc p16uc_PSET64_HI = { 0,1,2,3, 4,5,6,7, 0,1,2,3, 4,5,6,7 }; +static Packet16uc p16uc_DUPLICATE32_HI = { 0,1,2,3, 0,1,2,3, 4,5,6,7, 4,5,6,7 }; + +// Mask alignment +#define _EIGEN_MASK_ALIGNMENT 0xfffffffffffffff0 + +#define _EIGEN_ALIGNED_PTR(x) ((std::ptrdiff_t)(x) & _EIGEN_MASK_ALIGNMENT) + +// Handle endianness properly while loading constants +// Define global static constants: + +static Packet16uc p16uc_FORWARD = { 0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15 }; +static Packet16uc p16uc_REVERSE32 = { 12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3 }; +static Packet16uc p16uc_REVERSE64 = { 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; + +static Packet16uc p16uc_PSET32_WODD = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 0), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 2), 8);//{ 0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11 }; +static Packet16uc p16uc_PSET32_WEVEN = vec_sld(p16uc_DUPLICATE32_HI, (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 3), 8);//{ 4,5,6,7, 4,5,6,7, 12,13,14,15, 12,13,14,15 }; +/*static Packet16uc p16uc_HALF64_0_16 = vec_sld((Packet16uc)p4i_ZERO, vec_splat((Packet16uc) vec_abs(p4i_MINUS16), 3), 8); //{ 0,0,0,0, 0,0,0,0, 16,16,16,16, 16,16,16,16}; + +static Packet16uc p16uc_PSET64_HI = (Packet16uc) vec_mergeh((Packet4ui)p16uc_PSET32_WODD, (Packet4ui)p16uc_PSET32_WEVEN); //{ 0,1,2,3, 4,5,6,7, 0,1,2,3, 4,5,6,7 };*/ +static Packet16uc p16uc_PSET64_LO = (Packet16uc) vec_mergel((Packet4ui)p16uc_PSET32_WODD, (Packet4ui)p16uc_PSET32_WEVEN); //{ 8,9,10,11, 12,13,14,15, 8,9,10,11, 12,13,14,15 }; +/*static Packet16uc p16uc_TRANSPOSE64_HI = vec_add(p16uc_PSET64_HI, p16uc_HALF64_0_16); //{ 0,1,2,3, 4,5,6,7, 16,17,18,19, 20,21,22,23}; +static Packet16uc p16uc_TRANSPOSE64_LO = vec_add(p16uc_PSET64_LO, p16uc_HALF64_0_16); //{ 8,9,10,11, 12,13,14,15, 24,25,26,27, 28,29,30,31};*/ +static Packet16uc p16uc_TRANSPOSE64_HI = { 0,1,2,3, 4,5,6,7, 16,17,18,19, 20,21,22,23}; +static Packet16uc p16uc_TRANSPOSE64_LO = { 8,9,10,11, 12,13,14,15, 24,25,26,27, 28,29,30,31}; + +//static Packet16uc p16uc_COMPLEX32_REV = vec_sld(p16uc_REVERSE32, p16uc_REVERSE32, 8); //{ 4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11 }; + +//static Packet16uc p16uc_COMPLEX32_REV2 = vec_sld(p16uc_FORWARD, p16uc_FORWARD, 8); //{ 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; + + +#if EIGEN_HAS_BUILTIN(__builtin_prefetch) || EIGEN_COMP_GNUC + #define EIGEN_ZVECTOR_PREFETCH(ADDR) __builtin_prefetch(ADDR); +#else + #define EIGEN_ZVECTOR_PREFETCH(ADDR) asm( " pfd [%[addr]]\n" :: [addr] "r" (ADDR) : "cc" ); +#endif + +template<> struct packet_traits : default_packet_traits +{ + typedef Packet4i type; + typedef Packet4i half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size = 4, + HasHalfPacket = 0, + + HasAdd = 1, + HasSub = 1, + HasMul = 1, + HasDiv = 1, + HasBlend = 1 + }; +}; + +template<> struct packet_traits : default_packet_traits +{ + typedef Packet4f type; + typedef Packet4f half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size=4, + HasHalfPacket = 0, + + HasAdd = 1, + HasSub = 1, + HasMul = 1, + HasDiv = 1, + HasMin = 1, + HasMax = 1, + HasAbs = 1, + HasSin = 0, + HasCos = 0, + HasLog = 0, + HasExp = 1, + HasSqrt = 1, + HasRsqrt = 1, + HasRound = 1, + HasFloor = 1, + HasCeil = 1, + HasNegate = 1, + HasBlend = 1 + }; +}; + +template<> struct packet_traits : default_packet_traits +{ + typedef Packet2d type; + typedef Packet2d half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size=2, + HasHalfPacket = 1, + + HasAdd = 1, + HasSub = 1, + HasMul = 1, + HasDiv = 1, + HasMin = 1, + HasMax = 1, + HasAbs = 1, + HasSin = 0, + HasCos = 0, + HasLog = 0, + HasExp = 1, + HasSqrt = 1, + HasRsqrt = 1, + HasRound = 1, + HasFloor = 1, + HasCeil = 1, + HasNegate = 1, + HasBlend = 1 + }; +}; + +template<> struct unpacket_traits { typedef int type; enum {size=4, alignment=Aligned16}; typedef Packet4i half; }; +template<> struct unpacket_traits { typedef float type; enum {size=4, alignment=Aligned16}; typedef Packet4f half; }; +template<> struct unpacket_traits { typedef double type; enum {size=2, alignment=Aligned16}; typedef Packet2d half; }; + +/* Forward declaration */ +EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock& kernel); + +inline std::ostream & operator <<(std::ostream & s, const Packet4i & v) +{ + Packet vt; + vt.v4i = v; + s << vt.i[0] << ", " << vt.i[1] << ", " << vt.i[2] << ", " << vt.i[3]; + return s; +} + +inline std::ostream & operator <<(std::ostream & s, const Packet4ui & v) +{ + Packet vt; + vt.v4ui = v; + s << vt.ui[0] << ", " << vt.ui[1] << ", " << vt.ui[2] << ", " << vt.ui[3]; + return s; +} + +inline std::ostream & operator <<(std::ostream & s, const Packet2l & v) +{ + Packet vt; + vt.v2l = v; + s << vt.l[0] << ", " << vt.l[1]; + return s; +} + +inline std::ostream & operator <<(std::ostream & s, const Packet2ul & v) +{ + Packet vt; + vt.v2ul = v; + s << vt.ul[0] << ", " << vt.ul[1] ; + return s; +} + +inline std::ostream & operator <<(std::ostream & s, const Packet2d & v) +{ + Packet vt; + vt.v2d = v; + s << vt.d[0] << ", " << vt.d[1]; + return s; +} + +/* Helper function to simulate a vec_splat_packet4f + */ +template EIGEN_STRONG_INLINE Packet4f vec_splat_packet4f(const Packet4f& from) +{ + Packet4f splat; + switch (element) { + case 0: + splat.v4f[0] = vec_splat(from.v4f[0], 0); + splat.v4f[1] = splat.v4f[0]; + break; + case 1: + splat.v4f[0] = vec_splat(from.v4f[0], 1); + splat.v4f[1] = splat.v4f[0]; + break; + case 2: + splat.v4f[0] = vec_splat(from.v4f[1], 0); + splat.v4f[1] = splat.v4f[0]; + break; + case 3: + splat.v4f[0] = vec_splat(from.v4f[1], 1); + splat.v4f[1] = splat.v4f[0]; + break; + } + return splat; +} + +template +struct palign_impl +{ + static EIGEN_STRONG_INLINE void run(Packet4i& first, const Packet4i& second) + { + switch (Offset % 4) { + case 1: + first = vec_sld(first, second, 4); break; + case 2: + first = vec_sld(first, second, 8); break; + case 3: + first = vec_sld(first, second, 12); break; + } + } +}; + +/* This is a tricky one, we have to translate float alignment to vector elements of sizeof double + */ +template +struct palign_impl +{ + static EIGEN_STRONG_INLINE void run(Packet4f& first, const Packet4f& second) + { + switch (Offset % 4) { + case 1: + first.v4f[0] = vec_sld(first.v4f[0], first.v4f[1], 8); + first.v4f[1] = vec_sld(first.v4f[1], second.v4f[0], 8); + break; + case 2: + first.v4f[0] = first.v4f[1]; + first.v4f[1] = second.v4f[0]; + break; + case 3: + first.v4f[0] = vec_sld(first.v4f[1], second.v4f[0], 8); + first.v4f[1] = vec_sld(second.v4f[0], second.v4f[1], 8); + break; + } + } +}; + + +template +struct palign_impl +{ + static EIGEN_STRONG_INLINE void run(Packet2d& first, const Packet2d& second) + { + if (Offset == 1) + first = reinterpret_cast(vec_sld(reinterpret_cast(first), reinterpret_cast(second), 8)); + } +}; + +template<> EIGEN_STRONG_INLINE Packet4i pload(const int* from) +{ + // FIXME: No intrinsic yet + EIGEN_DEBUG_ALIGNED_LOAD + Packet *vfrom; + vfrom = (Packet *) from; + return vfrom->v4i; +} + +template<> EIGEN_STRONG_INLINE Packet4f pload(const float* from) +{ + // FIXME: No intrinsic yet + EIGEN_DEBUG_ALIGNED_LOAD + Packet4f vfrom; + vfrom.v4f[0] = vec_ld2f(&from[0]); + vfrom.v4f[1] = vec_ld2f(&from[2]); + return vfrom; +} + +template<> EIGEN_STRONG_INLINE Packet2d pload(const double* from) +{ + // FIXME: No intrinsic yet + EIGEN_DEBUG_ALIGNED_LOAD + Packet *vfrom; + vfrom = (Packet *) from; + return vfrom->v2d; +} + +template<> EIGEN_STRONG_INLINE void pstore(int* to, const Packet4i& from) +{ + // FIXME: No intrinsic yet + EIGEN_DEBUG_ALIGNED_STORE + Packet *vto; + vto = (Packet *) to; + vto->v4i = from; +} + +template<> EIGEN_STRONG_INLINE void pstore(float* to, const Packet4f& from) +{ + // FIXME: No intrinsic yet + EIGEN_DEBUG_ALIGNED_STORE + vec_st2f(from.v4f[0], &to[0]); + vec_st2f(from.v4f[1], &to[2]); +} + + +template<> EIGEN_STRONG_INLINE void pstore(double* to, const Packet2d& from) +{ + // FIXME: No intrinsic yet + EIGEN_DEBUG_ALIGNED_STORE + Packet *vto; + vto = (Packet *) to; + vto->v2d = from; +} + +template<> EIGEN_STRONG_INLINE Packet4i pset1(const int& from) +{ + return vec_splats(from); +} +template<> EIGEN_STRONG_INLINE Packet2d pset1(const double& from) { + return vec_splats(from); +} +template<> EIGEN_STRONG_INLINE Packet4f pset1(const float& from) +{ + Packet4f to; + to.v4f[0] = pset1(static_cast(from)); + to.v4f[1] = to.v4f[0]; + return to; +} + +template<> EIGEN_STRONG_INLINE void +pbroadcast4(const int *a, + Packet4i& a0, Packet4i& a1, Packet4i& a2, Packet4i& a3) +{ + a3 = pload(a); + a0 = vec_splat(a3, 0); + a1 = vec_splat(a3, 1); + a2 = vec_splat(a3, 2); + a3 = vec_splat(a3, 3); +} + +template<> EIGEN_STRONG_INLINE void +pbroadcast4(const float *a, + Packet4f& a0, Packet4f& a1, Packet4f& a2, Packet4f& a3) +{ + a3 = pload(a); + a0 = vec_splat_packet4f<0>(a3); + a1 = vec_splat_packet4f<1>(a3); + a2 = vec_splat_packet4f<2>(a3); + a3 = vec_splat_packet4f<3>(a3); +} + +template<> EIGEN_STRONG_INLINE void +pbroadcast4(const double *a, + Packet2d& a0, Packet2d& a1, Packet2d& a2, Packet2d& a3) +{ + a1 = pload(a); + a0 = vec_splat(a1, 0); + a1 = vec_splat(a1, 1); + a3 = pload(a+2); + a2 = vec_splat(a3, 0); + a3 = vec_splat(a3, 1); +} + +template<> EIGEN_DEVICE_FUNC inline Packet4i pgather(const int* from, Index stride) +{ + int EIGEN_ALIGN16 ai[4]; + ai[0] = from[0*stride]; + ai[1] = from[1*stride]; + ai[2] = from[2*stride]; + ai[3] = from[3*stride]; + return pload(ai); +} + +template<> EIGEN_DEVICE_FUNC inline Packet4f pgather(const float* from, Index stride) +{ + float EIGEN_ALIGN16 ai[4]; + ai[0] = from[0*stride]; + ai[1] = from[1*stride]; + ai[2] = from[2*stride]; + ai[3] = from[3*stride]; + return pload(ai); +} + +template<> EIGEN_DEVICE_FUNC inline Packet2d pgather(const double* from, Index stride) +{ + double EIGEN_ALIGN16 af[2]; + af[0] = from[0*stride]; + af[1] = from[1*stride]; + return pload(af); +} + +template<> EIGEN_DEVICE_FUNC inline void pscatter(int* to, const Packet4i& from, Index stride) +{ + int EIGEN_ALIGN16 ai[4]; + pstore((int *)ai, from); + to[0*stride] = ai[0]; + to[1*stride] = ai[1]; + to[2*stride] = ai[2]; + to[3*stride] = ai[3]; +} + +template<> EIGEN_DEVICE_FUNC inline void pscatter(float* to, const Packet4f& from, Index stride) +{ + float EIGEN_ALIGN16 ai[4]; + pstore((float *)ai, from); + to[0*stride] = ai[0]; + to[1*stride] = ai[1]; + to[2*stride] = ai[2]; + to[3*stride] = ai[3]; +} + +template<> EIGEN_DEVICE_FUNC inline void pscatter(double* to, const Packet2d& from, Index stride) +{ + double EIGEN_ALIGN16 af[2]; + pstore(af, from); + to[0*stride] = af[0]; + to[1*stride] = af[1]; +} + +template<> EIGEN_STRONG_INLINE Packet4i padd(const Packet4i& a, const Packet4i& b) { return (a + b); } +template<> EIGEN_STRONG_INLINE Packet4f padd(const Packet4f& a, const Packet4f& b) +{ + Packet4f c; + c.v4f[0] = a.v4f[0] + b.v4f[0]; + c.v4f[1] = a.v4f[1] + b.v4f[1]; + return c; +} +template<> EIGEN_STRONG_INLINE Packet2d padd(const Packet2d& a, const Packet2d& b) { return (a + b); } + +template<> EIGEN_STRONG_INLINE Packet4i psub(const Packet4i& a, const Packet4i& b) { return (a - b); } +template<> EIGEN_STRONG_INLINE Packet4f psub(const Packet4f& a, const Packet4f& b) +{ + Packet4f c; + c.v4f[0] = a.v4f[0] - b.v4f[0]; + c.v4f[1] = a.v4f[1] - b.v4f[1]; + return c; +} +template<> EIGEN_STRONG_INLINE Packet2d psub(const Packet2d& a, const Packet2d& b) { return (a - b); } + +template<> EIGEN_STRONG_INLINE Packet4i pmul(const Packet4i& a, const Packet4i& b) { return (a * b); } +template<> EIGEN_STRONG_INLINE Packet4f pmul(const Packet4f& a, const Packet4f& b) +{ + Packet4f c; + c.v4f[0] = a.v4f[0] * b.v4f[0]; + c.v4f[1] = a.v4f[1] * b.v4f[1]; + return c; +} +template<> EIGEN_STRONG_INLINE Packet2d pmul(const Packet2d& a, const Packet2d& b) { return (a * b); } + +template<> EIGEN_STRONG_INLINE Packet4i pdiv(const Packet4i& a, const Packet4i& b) { return (a / b); } +template<> EIGEN_STRONG_INLINE Packet4f pdiv(const Packet4f& a, const Packet4f& b) +{ + Packet4f c; + c.v4f[0] = a.v4f[0] / b.v4f[0]; + c.v4f[1] = a.v4f[1] / b.v4f[1]; + return c; +} +template<> EIGEN_STRONG_INLINE Packet2d pdiv(const Packet2d& a, const Packet2d& b) { return (a / b); } + +template<> EIGEN_STRONG_INLINE Packet4i pnegate(const Packet4i& a) { return (-a); } +template<> EIGEN_STRONG_INLINE Packet4f pnegate(const Packet4f& a) +{ + Packet4f c; + c.v4f[0] = -a.v4f[0]; + c.v4f[1] = -a.v4f[1]; + return c; +} +template<> EIGEN_STRONG_INLINE Packet2d pnegate(const Packet2d& a) { return (-a); } + +template<> EIGEN_STRONG_INLINE Packet4i pconj(const Packet4i& a) { return a; } +template<> EIGEN_STRONG_INLINE Packet4f pconj(const Packet4f& a) { return a; } +template<> EIGEN_STRONG_INLINE Packet2d pconj(const Packet2d& a) { return a; } + +template<> EIGEN_STRONG_INLINE Packet4i pmadd(const Packet4i& a, const Packet4i& b, const Packet4i& c) { return padd(pmul(a, b), c); } +template<> EIGEN_STRONG_INLINE Packet4f pmadd(const Packet4f& a, const Packet4f& b, const Packet4f& c) +{ + Packet4f res; + res.v4f[0] = vec_madd(a.v4f[0], b.v4f[0], c.v4f[0]); + res.v4f[1] = vec_madd(a.v4f[1], b.v4f[1], c.v4f[1]); + return res; +} +template<> EIGEN_STRONG_INLINE Packet2d pmadd(const Packet2d& a, const Packet2d& b, const Packet2d& c) { return vec_madd(a, b, c); } + +template<> EIGEN_STRONG_INLINE Packet4i plset(const int& a) { return padd(pset1(a), p4i_COUNTDOWN); } +template<> EIGEN_STRONG_INLINE Packet4f plset(const float& a) { return padd(pset1(a), p4f_COUNTDOWN); } +template<> EIGEN_STRONG_INLINE Packet2d plset(const double& a) { return padd(pset1(a), p2d_COUNTDOWN); } + +template<> EIGEN_STRONG_INLINE Packet4i pmin(const Packet4i& a, const Packet4i& b) { return vec_min(a, b); } +template<> EIGEN_STRONG_INLINE Packet2d pmin(const Packet2d& a, const Packet2d& b) { return vec_min(a, b); } +template<> EIGEN_STRONG_INLINE Packet4f pmin(const Packet4f& a, const Packet4f& b) +{ + Packet4f res; + res.v4f[0] = pmin(a.v4f[0], b.v4f[0]); + res.v4f[1] = pmin(a.v4f[1], b.v4f[1]); + return res; +} + +template<> EIGEN_STRONG_INLINE Packet4i pmax(const Packet4i& a, const Packet4i& b) { return vec_max(a, b); } +template<> EIGEN_STRONG_INLINE Packet2d pmax(const Packet2d& a, const Packet2d& b) { return vec_max(a, b); } +template<> EIGEN_STRONG_INLINE Packet4f pmax(const Packet4f& a, const Packet4f& b) +{ + Packet4f res; + res.v4f[0] = pmax(a.v4f[0], b.v4f[0]); + res.v4f[1] = pmax(a.v4f[1], b.v4f[1]); + return res; +} + +template<> EIGEN_STRONG_INLINE Packet4i pand(const Packet4i& a, const Packet4i& b) { return vec_and(a, b); } +template<> EIGEN_STRONG_INLINE Packet2d pand(const Packet2d& a, const Packet2d& b) { return vec_and(a, b); } +template<> EIGEN_STRONG_INLINE Packet4f pand(const Packet4f& a, const Packet4f& b) +{ + Packet4f res; + res.v4f[0] = pand(a.v4f[0], b.v4f[0]); + res.v4f[1] = pand(a.v4f[1], b.v4f[1]); + return res; +} + +template<> EIGEN_STRONG_INLINE Packet4i por(const Packet4i& a, const Packet4i& b) { return vec_or(a, b); } +template<> EIGEN_STRONG_INLINE Packet2d por(const Packet2d& a, const Packet2d& b) { return vec_or(a, b); } +template<> EIGEN_STRONG_INLINE Packet4f por(const Packet4f& a, const Packet4f& b) +{ + Packet4f res; + res.v4f[0] = pand(a.v4f[0], b.v4f[0]); + res.v4f[1] = pand(a.v4f[1], b.v4f[1]); + return res; +} + +template<> EIGEN_STRONG_INLINE Packet4i pxor(const Packet4i& a, const Packet4i& b) { return vec_xor(a, b); } +template<> EIGEN_STRONG_INLINE Packet2d pxor(const Packet2d& a, const Packet2d& b) { return vec_xor(a, b); } +template<> EIGEN_STRONG_INLINE Packet4f pxor(const Packet4f& a, const Packet4f& b) +{ + Packet4f res; + res.v4f[0] = pand(a.v4f[0], b.v4f[0]); + res.v4f[1] = pand(a.v4f[1], b.v4f[1]); + return res; +} + +template<> EIGEN_STRONG_INLINE Packet4i pandnot(const Packet4i& a, const Packet4i& b) { return pand(a, vec_nor(b, b)); } +template<> EIGEN_STRONG_INLINE Packet2d pandnot(const Packet2d& a, const Packet2d& b) { return vec_and(a, vec_nor(b, b)); } +template<> EIGEN_STRONG_INLINE Packet4f pandnot(const Packet4f& a, const Packet4f& b) +{ + Packet4f res; + res.v4f[0] = pandnot(a.v4f[0], b.v4f[0]); + res.v4f[1] = pandnot(a.v4f[1], b.v4f[1]); + return res; +} + +template<> EIGEN_STRONG_INLINE Packet4f pround(const Packet4f& a) +{ + Packet4f res; + res.v4f[0] = vec_round(a.v4f[0]); + res.v4f[1] = vec_round(a.v4f[1]); + return res; +} +template<> EIGEN_STRONG_INLINE Packet2d pround(const Packet2d& a) { return vec_round(a); } +template<> EIGEN_STRONG_INLINE Packet4f pceil(const Packet4f& a) +{ + Packet4f res; + res.v4f[0] = vec_ceil(a.v4f[0]); + res.v4f[1] = vec_ceil(a.v4f[1]); + return res; +} +template<> EIGEN_STRONG_INLINE Packet2d pceil(const Packet2d& a) { return vec_ceil(a); } +template<> EIGEN_STRONG_INLINE Packet4f pfloor(const Packet4f& a) +{ + Packet4f res; + res.v4f[0] = vec_floor(a.v4f[0]); + res.v4f[1] = vec_floor(a.v4f[1]); + return res; +} +template<> EIGEN_STRONG_INLINE Packet2d pfloor(const Packet2d& a) { return vec_floor(a); } + +template<> EIGEN_STRONG_INLINE Packet4i ploadu(const int* from) { return pload(from); } +template<> EIGEN_STRONG_INLINE Packet4f ploadu(const float* from) { return pload(from); } +template<> EIGEN_STRONG_INLINE Packet2d ploadu(const double* from) { return pload(from); } + + +template<> EIGEN_STRONG_INLINE Packet4i ploaddup(const int* from) +{ + Packet4i p = pload(from); + return vec_perm(p, p, p16uc_DUPLICATE32_HI); +} + +template<> EIGEN_STRONG_INLINE Packet4f ploaddup(const float* from) +{ + Packet4f p = pload(from); + p.v4f[1] = vec_splat(p.v4f[0], 1); + p.v4f[0] = vec_splat(p.v4f[0], 0); + return p; +} + +template<> EIGEN_STRONG_INLINE Packet2d ploaddup(const double* from) +{ + Packet2d p = pload(from); + return vec_perm(p, p, p16uc_PSET64_HI); +} + +template<> EIGEN_STRONG_INLINE void pstoreu(int* to, const Packet4i& from) { pstore(to, from); } +template<> EIGEN_STRONG_INLINE void pstoreu(float* to, const Packet4f& from) { pstore(to, from); } +template<> EIGEN_STRONG_INLINE void pstoreu(double* to, const Packet2d& from) { pstore(to, from); } + +template<> EIGEN_STRONG_INLINE void prefetch(const int* addr) { EIGEN_ZVECTOR_PREFETCH(addr); } +template<> EIGEN_STRONG_INLINE void prefetch(const float* addr) { EIGEN_ZVECTOR_PREFETCH(addr); } +template<> EIGEN_STRONG_INLINE void prefetch(const double* addr) { EIGEN_ZVECTOR_PREFETCH(addr); } + +template<> EIGEN_STRONG_INLINE int pfirst(const Packet4i& a) { int EIGEN_ALIGN16 x[4]; pstore(x, a); return x[0]; } +template<> EIGEN_STRONG_INLINE float pfirst(const Packet4f& a) { float EIGEN_ALIGN16 x[2]; vec_st2f(a.v4f[0], &x[0]); return x[0]; } +template<> EIGEN_STRONG_INLINE double pfirst(const Packet2d& a) { double EIGEN_ALIGN16 x[2]; pstore(x, a); return x[0]; } + +template<> EIGEN_STRONG_INLINE Packet4i preverse(const Packet4i& a) +{ + return reinterpret_cast(vec_perm(reinterpret_cast(a), reinterpret_cast(a), p16uc_REVERSE32)); +} + +template<> EIGEN_STRONG_INLINE Packet2d preverse(const Packet2d& a) +{ + return reinterpret_cast(vec_perm(reinterpret_cast(a), reinterpret_cast(a), p16uc_REVERSE64)); +} + +template<> EIGEN_STRONG_INLINE Packet4f preverse(const Packet4f& a) +{ + Packet4f rev; + rev.v4f[0] = preverse(a.v4f[1]); + rev.v4f[1] = preverse(a.v4f[0]); + return rev; +} + +template<> EIGEN_STRONG_INLINE Packet4i pabs(const Packet4i& a) { return vec_abs(a); } +template<> EIGEN_STRONG_INLINE Packet2d pabs(const Packet2d& a) { return vec_abs(a); } +template<> EIGEN_STRONG_INLINE Packet4f pabs(const Packet4f& a) +{ + Packet4f res; + res.v4f[0] = pabs(a.v4f[0]); + res.v4f[1] = pabs(a.v4f[1]); + return res; +} + +template<> EIGEN_STRONG_INLINE int predux(const Packet4i& a) +{ + Packet4i b, sum; + b = vec_sld(a, a, 8); + sum = padd(a, b); + b = vec_sld(sum, sum, 4); + sum = padd(sum, b); + return pfirst(sum); +} + +template<> EIGEN_STRONG_INLINE double predux(const Packet2d& a) +{ + Packet2d b, sum; + b = reinterpret_cast(vec_sld(reinterpret_cast(a), reinterpret_cast(a), 8)); + sum = padd(a, b); + return pfirst(sum); +} +template<> EIGEN_STRONG_INLINE float predux(const Packet4f& a) +{ + Packet2d sum; + sum = padd(a.v4f[0], a.v4f[1]); + double first = predux(sum); + return static_cast(first); +} + +template<> EIGEN_STRONG_INLINE Packet4i preduxp(const Packet4i* vecs) +{ + Packet4i v[4], sum[4]; + + // It's easier and faster to transpose then add as columns + // Check: http://www.freevec.org/function/matrix_4x4_transpose_floats for explanation + // Do the transpose, first set of moves + v[0] = vec_mergeh(vecs[0], vecs[2]); + v[1] = vec_mergel(vecs[0], vecs[2]); + v[2] = vec_mergeh(vecs[1], vecs[3]); + v[3] = vec_mergel(vecs[1], vecs[3]); + // Get the resulting vectors + sum[0] = vec_mergeh(v[0], v[2]); + sum[1] = vec_mergel(v[0], v[2]); + sum[2] = vec_mergeh(v[1], v[3]); + sum[3] = vec_mergel(v[1], v[3]); + + // Now do the summation: + // Lines 0+1 + sum[0] = padd(sum[0], sum[1]); + // Lines 2+3 + sum[1] = padd(sum[2], sum[3]); + // Add the results + sum[0] = padd(sum[0], sum[1]); + + return sum[0]; +} + +template<> EIGEN_STRONG_INLINE Packet2d preduxp(const Packet2d* vecs) +{ + Packet2d v[2], sum; + v[0] = padd(vecs[0], reinterpret_cast(vec_sld(reinterpret_cast(vecs[0]), reinterpret_cast(vecs[0]), 8))); + v[1] = padd(vecs[1], reinterpret_cast(vec_sld(reinterpret_cast(vecs[1]), reinterpret_cast(vecs[1]), 8))); + + sum = reinterpret_cast(vec_sld(reinterpret_cast(v[0]), reinterpret_cast(v[1]), 8)); + + return sum; +} + +template<> EIGEN_STRONG_INLINE Packet4f preduxp(const Packet4f* vecs) +{ + PacketBlock transpose; + transpose.packet[0] = vecs[0]; + transpose.packet[1] = vecs[1]; + transpose.packet[2] = vecs[2]; + transpose.packet[3] = vecs[3]; + ptranspose(transpose); + + Packet4f sum = padd(transpose.packet[0], transpose.packet[1]); + sum = padd(sum, transpose.packet[2]); + sum = padd(sum, transpose.packet[3]); + return sum; +} + +// Other reduction functions: +// mul +template<> EIGEN_STRONG_INLINE int predux_mul(const Packet4i& a) +{ + EIGEN_ALIGN16 int aux[4]; + pstore(aux, a); + return aux[0] * aux[1] * aux[2] * aux[3]; +} + +template<> EIGEN_STRONG_INLINE double predux_mul(const Packet2d& a) +{ + return pfirst(pmul(a, reinterpret_cast(vec_sld(reinterpret_cast(a), reinterpret_cast(a), 8)))); +} + +template<> EIGEN_STRONG_INLINE float predux_mul(const Packet4f& a) +{ + // Return predux_mul of the subvectors product + return static_cast(pfirst(predux_mul(pmul(a.v4f[0], a.v4f[1])))); +} + +// min +template<> EIGEN_STRONG_INLINE int predux_min(const Packet4i& a) +{ + Packet4i b, res; + b = pmin(a, vec_sld(a, a, 8)); + res = pmin(b, vec_sld(b, b, 4)); + return pfirst(res); +} + +template<> EIGEN_STRONG_INLINE double predux_min(const Packet2d& a) +{ + return pfirst(pmin(a, reinterpret_cast(vec_sld(reinterpret_cast(a), reinterpret_cast(a), 8)))); +} + +template<> EIGEN_STRONG_INLINE float predux_min(const Packet4f& a) +{ + Packet2d b, res; + b = pmin(a.v4f[0], a.v4f[1]); + res = pmin(b, reinterpret_cast(vec_sld(reinterpret_cast(b), reinterpret_cast(b), 8))); + return static_cast(pfirst(res)); +} + +// max +template<> EIGEN_STRONG_INLINE int predux_max(const Packet4i& a) +{ + Packet4i b, res; + b = pmax(a, vec_sld(a, a, 8)); + res = pmax(b, vec_sld(b, b, 4)); + return pfirst(res); +} + +// max +template<> EIGEN_STRONG_INLINE double predux_max(const Packet2d& a) +{ + return pfirst(pmax(a, reinterpret_cast(vec_sld(reinterpret_cast(a), reinterpret_cast(a), 8)))); +} + +template<> EIGEN_STRONG_INLINE float predux_max(const Packet4f& a) +{ + Packet2d b, res; + b = pmax(a.v4f[0], a.v4f[1]); + res = pmax(b, reinterpret_cast(vec_sld(reinterpret_cast(b), reinterpret_cast(b), 8))); + return static_cast(pfirst(res)); +} + +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + Packet4i t0 = vec_mergeh(kernel.packet[0], kernel.packet[2]); + Packet4i t1 = vec_mergel(kernel.packet[0], kernel.packet[2]); + Packet4i t2 = vec_mergeh(kernel.packet[1], kernel.packet[3]); + Packet4i t3 = vec_mergel(kernel.packet[1], kernel.packet[3]); + kernel.packet[0] = vec_mergeh(t0, t2); + kernel.packet[1] = vec_mergel(t0, t2); + kernel.packet[2] = vec_mergeh(t1, t3); + kernel.packet[3] = vec_mergel(t1, t3); +} + +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + Packet2d t0 = vec_perm(kernel.packet[0], kernel.packet[1], p16uc_TRANSPOSE64_HI); + Packet2d t1 = vec_perm(kernel.packet[0], kernel.packet[1], p16uc_TRANSPOSE64_LO); + kernel.packet[0] = t0; + kernel.packet[1] = t1; +} + +/* Split the Packet4f PacketBlock into 4 Packet2d PacketBlocks and transpose each one + */ +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + PacketBlock t0,t1,t2,t3; + // copy top-left 2x2 Packet2d block + t0.packet[0] = kernel.packet[0].v4f[0]; + t0.packet[1] = kernel.packet[1].v4f[0]; + + // copy top-right 2x2 Packet2d block + t1.packet[0] = kernel.packet[0].v4f[1]; + t1.packet[1] = kernel.packet[1].v4f[1]; + + // copy bottom-left 2x2 Packet2d block + t2.packet[0] = kernel.packet[2].v4f[0]; + t2.packet[1] = kernel.packet[3].v4f[0]; + + // copy bottom-right 2x2 Packet2d block + t3.packet[0] = kernel.packet[2].v4f[1]; + t3.packet[1] = kernel.packet[3].v4f[1]; + + // Transpose all 2x2 blocks + ptranspose(t0); + ptranspose(t1); + ptranspose(t2); + ptranspose(t3); + + // Copy back transposed blocks, but exchange t1 and t2 due to transposition + kernel.packet[0].v4f[0] = t0.packet[0]; + kernel.packet[0].v4f[1] = t2.packet[0]; + kernel.packet[1].v4f[0] = t0.packet[1]; + kernel.packet[1].v4f[1] = t2.packet[1]; + kernel.packet[2].v4f[0] = t1.packet[0]; + kernel.packet[2].v4f[1] = t3.packet[0]; + kernel.packet[3].v4f[0] = t1.packet[1]; + kernel.packet[3].v4f[1] = t3.packet[1]; +} + +template<> EIGEN_STRONG_INLINE Packet4i pblend(const Selector<4>& ifPacket, const Packet4i& thenPacket, const Packet4i& elsePacket) { + Packet4ui select = { ifPacket.select[0], ifPacket.select[1], ifPacket.select[2], ifPacket.select[3] }; + Packet4ui mask = vec_cmpeq(select, reinterpret_cast(p4i_ONE)); + return vec_sel(elsePacket, thenPacket, mask); +} + +template<> EIGEN_STRONG_INLINE Packet4f pblend(const Selector<4>& ifPacket, const Packet4f& thenPacket, const Packet4f& elsePacket) { + Packet2ul select_hi = { ifPacket.select[0], ifPacket.select[1] }; + Packet2ul select_lo = { ifPacket.select[2], ifPacket.select[3] }; + Packet2ul mask_hi = vec_cmpeq(select_hi, reinterpret_cast(p2l_ONE)); + Packet2ul mask_lo = vec_cmpeq(select_lo, reinterpret_cast(p2l_ONE)); + Packet4f result; + result.v4f[0] = vec_sel(elsePacket.v4f[0], thenPacket.v4f[0], mask_hi); + result.v4f[1] = vec_sel(elsePacket.v4f[1], thenPacket.v4f[1], mask_lo); + return result; +} + +template<> EIGEN_STRONG_INLINE Packet2d pblend(const Selector<2>& ifPacket, const Packet2d& thenPacket, const Packet2d& elsePacket) { + Packet2ul select = { ifPacket.select[0], ifPacket.select[1] }; + Packet2ul mask = vec_cmpeq(select, reinterpret_cast(p2l_ONE)); + return vec_sel(elsePacket, thenPacket, mask); +} + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_PACKET_MATH_ZVECTOR_H diff --git a/libs/eigen3/Eigen/src/Core/functors/AssignmentFunctors.h b/libs/eigen3/Eigen/src/Core/functors/AssignmentFunctors.h new file mode 100644 index 000000000..4153b877c --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/functors/AssignmentFunctors.h @@ -0,0 +1,168 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_ASSIGNMENT_FUNCTORS_H +#define EIGEN_ASSIGNMENT_FUNCTORS_H + +namespace Eigen { + +namespace internal { + +/** \internal + * \brief Template functor for scalar/packet assignment + * + */ +template struct assign_op { + + EIGEN_EMPTY_STRUCT_CTOR(assign_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(DstScalar& a, const SrcScalar& b) const { a = b; } + + template + EIGEN_STRONG_INLINE void assignPacket(DstScalar* a, const Packet& b) const + { internal::pstoret(a,b); } +}; + +// Empty overload for void type (used by PermutationMatrix) +template struct assign_op {}; + +template +struct functor_traits > { + enum { + Cost = NumTraits::ReadCost, + PacketAccess = is_same::value && packet_traits::Vectorizable && packet_traits::Vectorizable + }; +}; + +/** \internal + * \brief Template functor for scalar/packet assignment with addition + * + */ +template struct add_assign_op { + + EIGEN_EMPTY_STRUCT_CTOR(add_assign_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(DstScalar& a, const SrcScalar& b) const { a += b; } + + template + EIGEN_STRONG_INLINE void assignPacket(DstScalar* a, const Packet& b) const + { internal::pstoret(a,internal::padd(internal::ploadt(a),b)); } +}; +template +struct functor_traits > { + enum { + Cost = NumTraits::ReadCost + NumTraits::AddCost, + PacketAccess = is_same::value && packet_traits::HasAdd + }; +}; + +/** \internal + * \brief Template functor for scalar/packet assignment with subtraction + * + */ +template struct sub_assign_op { + + EIGEN_EMPTY_STRUCT_CTOR(sub_assign_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(DstScalar& a, const SrcScalar& b) const { a -= b; } + + template + EIGEN_STRONG_INLINE void assignPacket(DstScalar* a, const Packet& b) const + { internal::pstoret(a,internal::psub(internal::ploadt(a),b)); } +}; +template +struct functor_traits > { + enum { + Cost = NumTraits::ReadCost + NumTraits::AddCost, + PacketAccess = is_same::value && packet_traits::HasSub + }; +}; + +/** \internal + * \brief Template functor for scalar/packet assignment with multiplication + * + */ +template +struct mul_assign_op { + + EIGEN_EMPTY_STRUCT_CTOR(mul_assign_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(DstScalar& a, const SrcScalar& b) const { a *= b; } + + template + EIGEN_STRONG_INLINE void assignPacket(DstScalar* a, const Packet& b) const + { internal::pstoret(a,internal::pmul(internal::ploadt(a),b)); } +}; +template +struct functor_traits > { + enum { + Cost = NumTraits::ReadCost + NumTraits::MulCost, + PacketAccess = is_same::value && packet_traits::HasMul + }; +}; + +/** \internal + * \brief Template functor for scalar/packet assignment with diviving + * + */ +template struct div_assign_op { + + EIGEN_EMPTY_STRUCT_CTOR(div_assign_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(DstScalar& a, const SrcScalar& b) const { a /= b; } + + template + EIGEN_STRONG_INLINE void assignPacket(DstScalar* a, const Packet& b) const + { internal::pstoret(a,internal::pdiv(internal::ploadt(a),b)); } +}; +template +struct functor_traits > { + enum { + Cost = NumTraits::ReadCost + NumTraits::MulCost, + PacketAccess = is_same::value && packet_traits::HasDiv + }; +}; + +/** \internal + * \brief Template functor for scalar/packet assignment with swapping + * + * It works as follow. For a non-vectorized evaluation loop, we have: + * for(i) func(A.coeffRef(i), B.coeff(i)); + * where B is a SwapWrapper expression. The trick is to make SwapWrapper::coeff behaves like a non-const coeffRef. + * Actually, SwapWrapper might not even be needed since even if B is a plain expression, since it has to be writable + * B.coeff already returns a const reference to the underlying scalar value. + * + * The case of a vectorized loop is more tricky: + * for(i,j) func.assignPacket(&A.coeffRef(i,j), B.packet(i,j)); + * Here, B must be a SwapWrapper whose packet function actually returns a proxy object holding a Scalar*, + * the actual alignment and Packet type. + * + */ +template struct swap_assign_op { + + EIGEN_EMPTY_STRUCT_CTOR(swap_assign_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(Scalar& a, const Scalar& b) const + { +#ifdef __CUDACC__ + // FIXME is there some kind of cuda::swap? + Scalar t=b; const_cast(b)=a; a=t; +#else + using std::swap; + swap(a,const_cast(b)); +#endif + } +}; +template +struct functor_traits > { + enum { + Cost = 3 * NumTraits::ReadCost, + PacketAccess = packet_traits::Vectorizable + }; +}; + +} // namespace internal + +} // namespace Eigen + +#endif // EIGEN_ASSIGNMENT_FUNCTORS_H diff --git a/libs/eigen3/Eigen/src/Core/functors/BinaryFunctors.h b/libs/eigen3/Eigen/src/Core/functors/BinaryFunctors.h new file mode 100644 index 000000000..96747bac7 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/functors/BinaryFunctors.h @@ -0,0 +1,482 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_BINARY_FUNCTORS_H +#define EIGEN_BINARY_FUNCTORS_H + +namespace Eigen { + +namespace internal { + +//---------- associative binary functors ---------- + +template +struct binary_op_base +{ + typedef Arg1 first_argument_type; + typedef Arg2 second_argument_type; +}; + +/** \internal + * \brief Template functor to compute the sum of two scalars + * + * \sa class CwiseBinaryOp, MatrixBase::operator+, class VectorwiseOp, DenseBase::sum() + */ +template +struct scalar_sum_op : binary_op_base +{ + typedef typename ScalarBinaryOpTraits::ReturnType result_type; +#ifndef EIGEN_SCALAR_BINARY_OP_PLUGIN + EIGEN_EMPTY_STRUCT_CTOR(scalar_sum_op) +#else + scalar_sum_op() { + EIGEN_SCALAR_BINARY_OP_PLUGIN + } +#endif + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a + b; } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const + { return internal::padd(a,b); } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type predux(const Packet& a) const + { return internal::predux(a); } +}; +template +struct functor_traits > { + enum { + Cost = (NumTraits::AddCost+NumTraits::AddCost)/2, // rough estimate! + PacketAccess = is_same::value && packet_traits::HasAdd && packet_traits::HasAdd + // TODO vectorize mixed sum + }; +}; + +/** \internal + * \brief Template specialization to deprecate the summation of boolean expressions. + * This is required to solve Bug 426. + * \sa DenseBase::count(), DenseBase::any(), ArrayBase::cast(), MatrixBase::cast() + */ +template<> struct scalar_sum_op : scalar_sum_op { + EIGEN_DEPRECATED + scalar_sum_op() {} +}; + + +/** \internal + * \brief Template functor to compute the product of two scalars + * + * \sa class CwiseBinaryOp, Cwise::operator*(), class VectorwiseOp, MatrixBase::redux() + */ +template +struct scalar_product_op : binary_op_base +{ + typedef typename ScalarBinaryOpTraits::ReturnType result_type; +#ifndef EIGEN_SCALAR_BINARY_OP_PLUGIN + EIGEN_EMPTY_STRUCT_CTOR(scalar_product_op) +#else + scalar_product_op() { + EIGEN_SCALAR_BINARY_OP_PLUGIN + } +#endif + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a * b; } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const + { return internal::pmul(a,b); } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type predux(const Packet& a) const + { return internal::predux_mul(a); } +}; +template +struct functor_traits > { + enum { + Cost = (NumTraits::MulCost + NumTraits::MulCost)/2, // rough estimate! + PacketAccess = is_same::value && packet_traits::HasMul && packet_traits::HasMul + // TODO vectorize mixed product + }; +}; + +/** \internal + * \brief Template functor to compute the conjugate product of two scalars + * + * This is a short cut for conj(x) * y which is needed for optimization purpose; in Eigen2 support mode, this becomes x * conj(y) + */ +template +struct scalar_conj_product_op : binary_op_base +{ + + enum { + Conj = NumTraits::IsComplex + }; + + typedef typename ScalarBinaryOpTraits::ReturnType result_type; + + EIGEN_EMPTY_STRUCT_CTOR(scalar_conj_product_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const + { return conj_helper().pmul(a,b); } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const + { return conj_helper().pmul(a,b); } +}; +template +struct functor_traits > { + enum { + Cost = NumTraits::MulCost, + PacketAccess = internal::is_same::value && packet_traits::HasMul + }; +}; + +/** \internal + * \brief Template functor to compute the min of two scalars + * + * \sa class CwiseBinaryOp, MatrixBase::cwiseMin, class VectorwiseOp, MatrixBase::minCoeff() + */ +template +struct scalar_min_op : binary_op_base +{ + typedef typename ScalarBinaryOpTraits::ReturnType result_type; + EIGEN_EMPTY_STRUCT_CTOR(scalar_min_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return numext::mini(a, b); } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const + { return internal::pmin(a,b); } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type predux(const Packet& a) const + { return internal::predux_min(a); } +}; +template +struct functor_traits > { + enum { + Cost = (NumTraits::AddCost+NumTraits::AddCost)/2, + PacketAccess = internal::is_same::value && packet_traits::HasMin + }; +}; + +/** \internal + * \brief Template functor to compute the max of two scalars + * + * \sa class CwiseBinaryOp, MatrixBase::cwiseMax, class VectorwiseOp, MatrixBase::maxCoeff() + */ +template +struct scalar_max_op : binary_op_base +{ + typedef typename ScalarBinaryOpTraits::ReturnType result_type; + EIGEN_EMPTY_STRUCT_CTOR(scalar_max_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return numext::maxi(a, b); } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const + { return internal::pmax(a,b); } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type predux(const Packet& a) const + { return internal::predux_max(a); } +}; +template +struct functor_traits > { + enum { + Cost = (NumTraits::AddCost+NumTraits::AddCost)/2, + PacketAccess = internal::is_same::value && packet_traits::HasMax + }; +}; + +/** \internal + * \brief Template functors for comparison of two scalars + * \todo Implement packet-comparisons + */ +template struct scalar_cmp_op; + +template +struct functor_traits > { + enum { + Cost = (NumTraits::AddCost+NumTraits::AddCost)/2, + PacketAccess = false + }; +}; + +template +struct result_of(LhsScalar,RhsScalar)> { + typedef bool type; +}; + + +template +struct scalar_cmp_op : binary_op_base +{ + typedef bool result_type; + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const {return a==b;} +}; +template +struct scalar_cmp_op : binary_op_base +{ + typedef bool result_type; + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const {return a +struct scalar_cmp_op : binary_op_base +{ + typedef bool result_type; + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const {return a<=b;} +}; +template +struct scalar_cmp_op : binary_op_base +{ + typedef bool result_type; + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const {return a>b;} +}; +template +struct scalar_cmp_op : binary_op_base +{ + typedef bool result_type; + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const {return a>=b;} +}; +template +struct scalar_cmp_op : binary_op_base +{ + typedef bool result_type; + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const {return !(a<=b || b<=a);} +}; +template +struct scalar_cmp_op : binary_op_base +{ + typedef bool result_type; + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const {return a!=b;} +}; + + +/** \internal + * \brief Template functor to compute the hypot of two scalars + * + * \sa MatrixBase::stableNorm(), class Redux + */ +template +struct scalar_hypot_op : binary_op_base +{ + EIGEN_EMPTY_STRUCT_CTOR(scalar_hypot_op) +// typedef typename NumTraits::Real result_type; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& _x, const Scalar& _y) const + { + EIGEN_USING_STD_MATH(sqrt) + Scalar p, qp; + if(_x>_y) + { + p = _x; + qp = _y / p; + } + else + { + p = _y; + qp = _x / p; + } + return p * sqrt(Scalar(1) + qp*qp); + } +}; +template +struct functor_traits > { + enum + { + Cost = 3 * NumTraits::AddCost + + 2 * NumTraits::MulCost + + 2 * scalar_div_cost::value, + PacketAccess = false + }; +}; + +/** \internal + * \brief Template functor to compute the pow of two scalars + */ +template +struct scalar_pow_op : binary_op_base +{ + typedef typename ScalarBinaryOpTraits::ReturnType result_type; +#ifndef EIGEN_SCALAR_BINARY_OP_PLUGIN + EIGEN_EMPTY_STRUCT_CTOR(scalar_pow_op) +#else + scalar_pow_op() { + typedef Scalar LhsScalar; + typedef Exponent RhsScalar; + EIGEN_SCALAR_BINARY_OP_PLUGIN + } +#endif + EIGEN_DEVICE_FUNC + inline result_type operator() (const Scalar& a, const Exponent& b) const { return numext::pow(a, b); } +}; +template +struct functor_traits > { + enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; +}; + + + +//---------- non associative binary functors ---------- + +/** \internal + * \brief Template functor to compute the difference of two scalars + * + * \sa class CwiseBinaryOp, MatrixBase::operator- + */ +template +struct scalar_difference_op : binary_op_base +{ + typedef typename ScalarBinaryOpTraits::ReturnType result_type; +#ifndef EIGEN_SCALAR_BINARY_OP_PLUGIN + EIGEN_EMPTY_STRUCT_CTOR(scalar_difference_op) +#else + scalar_difference_op() { + EIGEN_SCALAR_BINARY_OP_PLUGIN + } +#endif + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a - b; } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const + { return internal::psub(a,b); } +}; +template +struct functor_traits > { + enum { + Cost = (NumTraits::AddCost+NumTraits::AddCost)/2, + PacketAccess = is_same::value && packet_traits::HasSub && packet_traits::HasSub + }; +}; + +/** \internal + * \brief Template functor to compute the quotient of two scalars + * + * \sa class CwiseBinaryOp, Cwise::operator/() + */ +template +struct scalar_quotient_op : binary_op_base +{ + typedef typename ScalarBinaryOpTraits::ReturnType result_type; +#ifndef EIGEN_SCALAR_BINARY_OP_PLUGIN + EIGEN_EMPTY_STRUCT_CTOR(scalar_quotient_op) +#else + scalar_quotient_op() { + EIGEN_SCALAR_BINARY_OP_PLUGIN + } +#endif + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a / b; } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const + { return internal::pdiv(a,b); } +}; +template +struct functor_traits > { + typedef typename scalar_quotient_op::result_type result_type; + enum { + PacketAccess = is_same::value && packet_traits::HasDiv && packet_traits::HasDiv, + Cost = scalar_div_cost::value + }; +}; + + + +/** \internal + * \brief Template functor to compute the and of two booleans + * + * \sa class CwiseBinaryOp, ArrayBase::operator&& + */ +struct scalar_boolean_and_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_and_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator() (const bool& a, const bool& b) const { return a && b; } +}; +template<> struct functor_traits { + enum { + Cost = NumTraits::AddCost, + PacketAccess = false + }; +}; + +/** \internal + * \brief Template functor to compute the or of two booleans + * + * \sa class CwiseBinaryOp, ArrayBase::operator|| + */ +struct scalar_boolean_or_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_or_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator() (const bool& a, const bool& b) const { return a || b; } +}; +template<> struct functor_traits { + enum { + Cost = NumTraits::AddCost, + PacketAccess = false + }; +}; + +/** \internal + * \brief Template functor to compute the xor of two booleans + * + * \sa class CwiseBinaryOp, ArrayBase::operator^ + */ +struct scalar_boolean_xor_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_xor_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator() (const bool& a, const bool& b) const { return a ^ b; } +}; +template<> struct functor_traits { + enum { + Cost = NumTraits::AddCost, + PacketAccess = false + }; +}; + + + +//---------- binary functors bound to a constant, thus appearing as a unary functor ---------- + +// The following two classes permits to turn any binary functor into a unary one with one argument bound to a constant value. +// They are analogues to std::binder1st/binder2nd but with the following differences: +// - they are compatible with packetOp +// - they are portable across C++ versions (the std::binder* are deprecated in C++11) +template struct bind1st_op : BinaryOp { + + typedef typename BinaryOp::first_argument_type first_argument_type; + typedef typename BinaryOp::second_argument_type second_argument_type; + typedef typename BinaryOp::result_type result_type; + + bind1st_op(const first_argument_type &val) : m_value(val) {} + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const second_argument_type& b) const { return BinaryOp::operator()(m_value,b); } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& b) const + { return BinaryOp::packetOp(internal::pset1(m_value), b); } + + first_argument_type m_value; +}; +template struct functor_traits > : functor_traits {}; + + +template struct bind2nd_op : BinaryOp { + + typedef typename BinaryOp::first_argument_type first_argument_type; + typedef typename BinaryOp::second_argument_type second_argument_type; + typedef typename BinaryOp::result_type result_type; + + bind2nd_op(const second_argument_type &val) : m_value(val) {} + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const first_argument_type& a) const { return BinaryOp::operator()(a,m_value); } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const + { return BinaryOp::packetOp(a,internal::pset1(m_value)); } + + second_argument_type m_value; +}; +template struct functor_traits > : functor_traits {}; + + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_BINARY_FUNCTORS_H diff --git a/libs/eigen3/Eigen/src/Core/functors/NullaryFunctors.h b/libs/eigen3/Eigen/src/Core/functors/NullaryFunctors.h new file mode 100644 index 000000000..b03be0269 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/functors/NullaryFunctors.h @@ -0,0 +1,188 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2016 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_NULLARY_FUNCTORS_H +#define EIGEN_NULLARY_FUNCTORS_H + +namespace Eigen { + +namespace internal { + +template +struct scalar_constant_op { + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE scalar_constant_op(const scalar_constant_op& other) : m_other(other.m_other) { } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE scalar_constant_op(const Scalar& other) : m_other(other) { } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() () const { return m_other; } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const PacketType packetOp() const { return internal::pset1(m_other); } + const Scalar m_other; +}; +template +struct functor_traits > +{ enum { Cost = 0 /* as the constant value should be loaded in register only once for the whole expression */, + PacketAccess = packet_traits::Vectorizable, IsRepeatable = true }; }; + +template struct scalar_identity_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_identity_op) + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (IndexType row, IndexType col) const { return row==col ? Scalar(1) : Scalar(0); } +}; +template +struct functor_traits > +{ enum { Cost = NumTraits::AddCost, PacketAccess = false, IsRepeatable = true }; }; + +template struct linspaced_op_impl; + +template +struct linspaced_op_impl +{ + linspaced_op_impl(const Scalar& low, const Scalar& high, Index num_steps) : + m_low(low), m_high(high), m_size1(num_steps==1 ? 1 : num_steps-1), m_step(num_steps==1 ? Scalar() : (high-low)/Scalar(num_steps-1)), + m_flip(numext::abs(high) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (IndexType i) const { + typedef typename NumTraits::Real RealScalar; + if(m_flip) + return (i==0)? m_low : (m_high - RealScalar(m_size1-i)*m_step); + else + return (i==m_size1)? m_high : (m_low + RealScalar(i)*m_step); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(IndexType i) const + { + // Principle: + // [low, ..., low] + ( [step, ..., step] * ( [i, ..., i] + [0, ..., size] ) ) + if(m_flip) + { + Packet pi = plset(Scalar(i-m_size1)); + Packet res = padd(pset1(m_high), pmul(pset1(m_step), pi)); + if(i==0) + res = pinsertfirst(res, m_low); + return res; + } + else + { + Packet pi = plset(Scalar(i)); + Packet res = padd(pset1(m_low), pmul(pset1(m_step), pi)); + if(i==m_size1-unpacket_traits::size+1) + res = pinsertlast(res, m_high); + return res; + } + } + + const Scalar m_low; + const Scalar m_high; + const Index m_size1; + const Scalar m_step; + const bool m_flip; +}; + +template +struct linspaced_op_impl +{ + linspaced_op_impl(const Scalar& low, const Scalar& high, Index num_steps) : + m_low(low), + m_multiplier((high-low)/convert_index(num_steps<=1 ? 1 : num_steps-1)), + m_divisor(convert_index((high>=low?num_steps:-num_steps)+(high-low))/((numext::abs(high-low)+1)==0?1:(numext::abs(high-low)+1))), + m_use_divisor(num_steps>1 && (numext::abs(high-low)+1) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const Scalar operator() (IndexType i) const + { + if(m_use_divisor) return m_low + convert_index(i)/m_divisor; + else return m_low + convert_index(i)*m_multiplier; + } + + const Scalar m_low; + const Scalar m_multiplier; + const Scalar m_divisor; + const bool m_use_divisor; +}; + +// ----- Linspace functor ---------------------------------------------------------------- + +// Forward declaration (we default to random access which does not really give +// us a speed gain when using packet access but it allows to use the functor in +// nested expressions). +template struct linspaced_op; +template struct functor_traits< linspaced_op > +{ + enum + { + Cost = 1, + PacketAccess = (!NumTraits::IsInteger) && packet_traits::HasSetLinear && packet_traits::HasBlend, + /*&& ((!NumTraits::IsInteger) || packet_traits::HasDiv),*/ // <- vectorization for integer is currently disabled + IsRepeatable = true + }; +}; +template struct linspaced_op +{ + linspaced_op(const Scalar& low, const Scalar& high, Index num_steps) + : impl((num_steps==1 ? high : low),high,num_steps) + {} + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (IndexType i) const { return impl(i); } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(IndexType i) const { return impl.packetOp(i); } + + // This proxy object handles the actual required temporaries and the different + // implementations (integer vs. floating point). + const linspaced_op_impl::IsInteger> impl; +}; + +// Linear access is automatically determined from the operator() prototypes available for the given functor. +// If it exposes an operator()(i,j), then we assume the i and j coefficients are required independently +// and linear access is not possible. In all other cases, linear access is enabled. +// Users should not have to deal with this structure. +template struct functor_has_linear_access { enum { ret = !has_binary_operator::value }; }; + +// For unreliable compilers, let's specialize the has_*ary_operator +// helpers so that at least built-in nullary functors work fine. +#if !( (EIGEN_COMP_MSVC>1600) || (EIGEN_GNUC_AT_LEAST(4,8)) || (EIGEN_COMP_ICC>=1600)) +template +struct has_nullary_operator,IndexType> { enum { value = 1}; }; +template +struct has_unary_operator,IndexType> { enum { value = 0}; }; +template +struct has_binary_operator,IndexType> { enum { value = 0}; }; + +template +struct has_nullary_operator,IndexType> { enum { value = 0}; }; +template +struct has_unary_operator,IndexType> { enum { value = 0}; }; +template +struct has_binary_operator,IndexType> { enum { value = 1}; }; + +template +struct has_nullary_operator,IndexType> { enum { value = 0}; }; +template +struct has_unary_operator,IndexType> { enum { value = 1}; }; +template +struct has_binary_operator,IndexType> { enum { value = 0}; }; + +template +struct has_nullary_operator,IndexType> { enum { value = 1}; }; +template +struct has_unary_operator,IndexType> { enum { value = 0}; }; +template +struct has_binary_operator,IndexType> { enum { value = 0}; }; +#endif + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_NULLARY_FUNCTORS_H diff --git a/libs/eigen3/Eigen/src/Core/functors/StlFunctors.h b/libs/eigen3/Eigen/src/Core/functors/StlFunctors.h new file mode 100644 index 000000000..6df3fa501 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/functors/StlFunctors.h @@ -0,0 +1,132 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_STL_FUNCTORS_H +#define EIGEN_STL_FUNCTORS_H + +namespace Eigen { + +namespace internal { + +// default functor traits for STL functors: + +template +struct functor_traits > +{ enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1, PacketAccess = false }; }; + +#if (__cplusplus < 201103L) && (EIGEN_COMP_MSVC <= 1900) +// std::binder* are deprecated since c++11 and will be removed in c++17 +template +struct functor_traits > +{ enum { Cost = functor_traits::Cost, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = functor_traits::Cost, PacketAccess = false }; }; +#endif + +template +struct functor_traits > +{ enum { Cost = 1 + functor_traits::Cost, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 1 + functor_traits::Cost, PacketAccess = false }; }; + +#ifdef EIGEN_STDEXT_SUPPORT + +template +struct functor_traits > +{ enum { Cost = 0, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = 0, PacketAccess = false }; }; + +template +struct functor_traits > > +{ enum { Cost = 0, PacketAccess = false }; }; + +template +struct functor_traits > > +{ enum { Cost = 0, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = functor_traits::Cost + functor_traits::Cost, PacketAccess = false }; }; + +template +struct functor_traits > +{ enum { Cost = functor_traits::Cost + functor_traits::Cost + functor_traits::Cost, PacketAccess = false }; }; + +#endif // EIGEN_STDEXT_SUPPORT + +// allow to add new functors and specializations of functor_traits from outside Eigen. +// this macro is really needed because functor_traits must be specialized after it is declared but before it is used... +#ifdef EIGEN_FUNCTORS_PLUGIN +#include EIGEN_FUNCTORS_PLUGIN +#endif + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_STL_FUNCTORS_H diff --git a/libs/eigen3/Eigen/src/Core/functors/TernaryFunctors.h b/libs/eigen3/Eigen/src/Core/functors/TernaryFunctors.h new file mode 100644 index 000000000..b254e96c6 --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/functors/TernaryFunctors.h @@ -0,0 +1,25 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2016 Eugene Brevdo +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_TERNARY_FUNCTORS_H +#define EIGEN_TERNARY_FUNCTORS_H + +namespace Eigen { + +namespace internal { + +//---------- associative ternary functors ---------- + + + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_TERNARY_FUNCTORS_H diff --git a/libs/eigen3/Eigen/src/Core/functors/UnaryFunctors.h b/libs/eigen3/Eigen/src/Core/functors/UnaryFunctors.h new file mode 100644 index 000000000..2e6a00ffd --- /dev/null +++ b/libs/eigen3/Eigen/src/Core/functors/UnaryFunctors.h @@ -0,0 +1,792 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2016 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_UNARY_FUNCTORS_H +#define EIGEN_UNARY_FUNCTORS_H + +namespace Eigen { + +namespace internal { + +/** \internal + * \brief Template functor to compute the opposite of a scalar + * + * \sa class CwiseUnaryOp, MatrixBase::operator- + */ +template struct scalar_opposite_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_opposite_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { return -a; } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const + { return internal::pnegate(a); } +}; +template +struct functor_traits > +{ enum { + Cost = NumTraits::AddCost, + PacketAccess = packet_traits::HasNegate }; +}; + +/** \internal + * \brief Template functor to compute the absolute value of a scalar + * + * \sa class CwiseUnaryOp, Cwise::abs + */ +template struct scalar_abs_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_abs_op) + typedef typename NumTraits::Real result_type; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { return numext::abs(a); } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const + { return internal::pabs(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = NumTraits::AddCost, + PacketAccess = packet_traits::HasAbs + }; +}; + +/** \internal + * \brief Template functor to compute the score of a scalar, to chose a pivot + * + * \sa class CwiseUnaryOp + */ +template struct scalar_score_coeff_op : scalar_abs_op +{ + typedef void Score_is_abs; +}; +template +struct functor_traits > : functor_traits > {}; + +/* Avoid recomputing abs when we know the score and they are the same. Not a true Eigen functor. */ +template struct abs_knowing_score +{ + EIGEN_EMPTY_STRUCT_CTOR(abs_knowing_score) + typedef typename NumTraits::Real result_type; + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a, const Score&) const { return numext::abs(a); } +}; +template struct abs_knowing_score::Score_is_abs> +{ + EIGEN_EMPTY_STRUCT_CTOR(abs_knowing_score) + typedef typename NumTraits::Real result_type; + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const Scal&, const result_type& a) const { return a; } +}; + +/** \internal + * \brief Template functor to compute the squared absolute value of a scalar + * + * \sa class CwiseUnaryOp, Cwise::abs2 + */ +template struct scalar_abs2_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_abs2_op) + typedef typename NumTraits::Real result_type; + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { return numext::abs2(a); } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const + { return internal::pmul(a,a); } +}; +template +struct functor_traits > +{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasAbs2 }; }; + +/** \internal + * \brief Template functor to compute the conjugate of a complex value + * + * \sa class CwiseUnaryOp, MatrixBase::conjugate() + */ +template struct scalar_conjugate_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_conjugate_op) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { using numext::conj; return conj(a); } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const { return internal::pconj(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = NumTraits::IsComplex ? NumTraits::AddCost : 0, + PacketAccess = packet_traits::HasConj + }; +}; + +/** \internal + * \brief Template functor to compute the phase angle of a complex + * + * \sa class CwiseUnaryOp, Cwise::arg + */ +template struct scalar_arg_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_arg_op) + typedef typename NumTraits::Real result_type; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { using numext::arg; return arg(a); } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const + { return internal::parg(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = NumTraits::IsComplex ? 5 * NumTraits::MulCost : NumTraits::AddCost, + PacketAccess = packet_traits::HasArg + }; +}; +/** \internal + * \brief Template functor to cast a scalar to another type + * + * \sa class CwiseUnaryOp, MatrixBase::cast() + */ +template +struct scalar_cast_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cast_op) + typedef NewType result_type; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const NewType operator() (const Scalar& a) const { return cast(a); } +}; +template +struct functor_traits > +{ enum { Cost = is_same::value ? 0 : NumTraits::AddCost, PacketAccess = false }; }; + +/** \internal + * \brief Template functor to extract the real part of a complex + * + * \sa class CwiseUnaryOp, MatrixBase::real() + */ +template +struct scalar_real_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_real_op) + typedef typename NumTraits::Real result_type; + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return numext::real(a); } +}; +template +struct functor_traits > +{ enum { Cost = 0, PacketAccess = false }; }; + +/** \internal + * \brief Template functor to extract the imaginary part of a complex + * + * \sa class CwiseUnaryOp, MatrixBase::imag() + */ +template +struct scalar_imag_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_imag_op) + typedef typename NumTraits::Real result_type; + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return numext::imag(a); } +}; +template +struct functor_traits > +{ enum { Cost = 0, PacketAccess = false }; }; + +/** \internal + * \brief Template functor to extract the real part of a complex as a reference + * + * \sa class CwiseUnaryOp, MatrixBase::real() + */ +template +struct scalar_real_ref_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_real_ref_op) + typedef typename NumTraits::Real result_type; + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE result_type& operator() (const Scalar& a) const { return numext::real_ref(*const_cast(&a)); } +}; +template +struct functor_traits > +{ enum { Cost = 0, PacketAccess = false }; }; + +/** \internal + * \brief Template functor to extract the imaginary part of a complex as a reference + * + * \sa class CwiseUnaryOp, MatrixBase::imag() + */ +template +struct scalar_imag_ref_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_imag_ref_op) + typedef typename NumTraits::Real result_type; + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE result_type& operator() (const Scalar& a) const { return numext::imag_ref(*const_cast(&a)); } +}; +template +struct functor_traits > +{ enum { Cost = 0, PacketAccess = false }; }; + +/** \internal + * + * \brief Template functor to compute the exponential of a scalar + * + * \sa class CwiseUnaryOp, Cwise::exp() + */ +template struct scalar_exp_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_exp_op) + EIGEN_DEVICE_FUNC inline const Scalar operator() (const Scalar& a) const { return numext::exp(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::pexp(a); } +}; +template +struct functor_traits > { + enum { + PacketAccess = packet_traits::HasExp, + // The following numbers are based on the AVX implementation. +#ifdef EIGEN_VECTORIZE_FMA + // Haswell can issue 2 add/mul/madd per cycle. + Cost = + (sizeof(Scalar) == 4 + // float: 8 pmadd, 4 pmul, 2 padd/psub, 6 other + ? (8 * NumTraits::AddCost + 6 * NumTraits::MulCost) + // double: 7 pmadd, 5 pmul, 3 padd/psub, 1 div, 13 other + : (14 * NumTraits::AddCost + + 6 * NumTraits::MulCost + + scalar_div_cost::HasDiv>::value)) +#else + Cost = + (sizeof(Scalar) == 4 + // float: 7 pmadd, 6 pmul, 4 padd/psub, 10 other + ? (21 * NumTraits::AddCost + 13 * NumTraits::MulCost) + // double: 7 pmadd, 5 pmul, 3 padd/psub, 1 div, 13 other + : (23 * NumTraits::AddCost + + 12 * NumTraits::MulCost + + scalar_div_cost::HasDiv>::value)) +#endif + }; +}; + +/** \internal + * + * \brief Template functor to compute the logarithm of a scalar + * + * \sa class CwiseUnaryOp, ArrayBase::log() + */ +template struct scalar_log_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_log_op) + EIGEN_DEVICE_FUNC inline const Scalar operator() (const Scalar& a) const { return numext::log(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::plog(a); } +}; +template +struct functor_traits > { + enum { + PacketAccess = packet_traits::HasLog, + Cost = + (PacketAccess + // The following numbers are based on the AVX implementation. +#ifdef EIGEN_VECTORIZE_FMA + // 8 pmadd, 6 pmul, 8 padd/psub, 16 other, can issue 2 add/mul/madd per cycle. + ? (20 * NumTraits::AddCost + 7 * NumTraits::MulCost) +#else + // 8 pmadd, 6 pmul, 8 padd/psub, 20 other + ? (36 * NumTraits::AddCost + 14 * NumTraits::MulCost) +#endif + // Measured cost of std::log. + : sizeof(Scalar)==4 ? 40 : 85) + }; +}; + +/** \internal + * + * \brief Template functor to compute the logarithm of 1 plus a scalar value + * + * \sa class CwiseUnaryOp, ArrayBase::log1p() + */ +template struct scalar_log1p_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_log1p_op) + EIGEN_DEVICE_FUNC inline const Scalar operator() (const Scalar& a) const { return numext::log1p(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::plog1p(a); } +}; +template +struct functor_traits > { + enum { + PacketAccess = packet_traits::HasLog1p, + Cost = functor_traits >::Cost // TODO measure cost of log1p + }; +}; + +/** \internal + * + * \brief Template functor to compute the base-10 logarithm of a scalar + * + * \sa class CwiseUnaryOp, Cwise::log10() + */ +template struct scalar_log10_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_log10_op) + EIGEN_DEVICE_FUNC inline const Scalar operator() (const Scalar& a) const { EIGEN_USING_STD_MATH(log10) return log10(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::plog10(a); } +}; +template +struct functor_traits > +{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasLog10 }; }; + +/** \internal + * \brief Template functor to compute the square root of a scalar + * \sa class CwiseUnaryOp, Cwise::sqrt() + */ +template struct scalar_sqrt_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_sqrt_op) + EIGEN_DEVICE_FUNC inline const Scalar operator() (const Scalar& a) const { return numext::sqrt(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::psqrt(a); } +}; +template +struct functor_traits > { + enum { +#if EIGEN_FAST_MATH + // The following numbers are based on the AVX implementation. + Cost = (sizeof(Scalar) == 8 ? 28 + // 4 pmul, 1 pmadd, 3 other + : (3 * NumTraits::AddCost + + 5 * NumTraits::MulCost)), +#else + // The following numbers are based on min VSQRT throughput on Haswell. + Cost = (sizeof(Scalar) == 8 ? 28 : 14), +#endif + PacketAccess = packet_traits::HasSqrt + }; +}; + +/** \internal + * \brief Template functor to compute the reciprocal square root of a scalar + * \sa class CwiseUnaryOp, Cwise::rsqrt() + */ +template struct scalar_rsqrt_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_rsqrt_op) + EIGEN_DEVICE_FUNC inline const Scalar operator() (const Scalar& a) const { return Scalar(1)/numext::sqrt(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::prsqrt(a); } +}; + +template +struct functor_traits > +{ enum { + Cost = 5 * NumTraits::MulCost, + PacketAccess = packet_traits::HasRsqrt + }; +}; + +/** \internal + * \brief Template functor to compute the cosine of a scalar + * \sa class CwiseUnaryOp, ArrayBase::cos() + */ +template struct scalar_cos_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cos_op) + EIGEN_DEVICE_FUNC inline Scalar operator() (const Scalar& a) const { return numext::cos(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::pcos(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = 5 * NumTraits::MulCost, + PacketAccess = packet_traits::HasCos + }; +}; + +/** \internal + * \brief Template functor to compute the sine of a scalar + * \sa class CwiseUnaryOp, ArrayBase::sin() + */ +template struct scalar_sin_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_sin_op) + EIGEN_DEVICE_FUNC inline const Scalar operator() (const Scalar& a) const { return numext::sin(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::psin(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = 5 * NumTraits::MulCost, + PacketAccess = packet_traits::HasSin + }; +}; + + +/** \internal + * \brief Template functor to compute the tan of a scalar + * \sa class CwiseUnaryOp, ArrayBase::tan() + */ +template struct scalar_tan_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_tan_op) + EIGEN_DEVICE_FUNC inline const Scalar operator() (const Scalar& a) const { return numext::tan(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::ptan(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = 5 * NumTraits::MulCost, + PacketAccess = packet_traits::HasTan + }; +}; + +/** \internal + * \brief Template functor to compute the arc cosine of a scalar + * \sa class CwiseUnaryOp, ArrayBase::acos() + */ +template struct scalar_acos_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_acos_op) + EIGEN_DEVICE_FUNC inline const Scalar operator() (const Scalar& a) const { return numext::acos(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::pacos(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = 5 * NumTraits::MulCost, + PacketAccess = packet_traits::HasACos + }; +}; + +/** \internal + * \brief Template functor to compute the arc sine of a scalar + * \sa class CwiseUnaryOp, ArrayBase::asin() + */ +template struct scalar_asin_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_asin_op) + EIGEN_DEVICE_FUNC inline const Scalar operator() (const Scalar& a) const { return numext::asin(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::pasin(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = 5 * NumTraits::MulCost, + PacketAccess = packet_traits::HasASin + }; +}; + + +/** \internal + * \brief Template functor to compute the atan of a scalar + * \sa class CwiseUnaryOp, ArrayBase::atan() + */ +template struct scalar_atan_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_atan_op) + EIGEN_DEVICE_FUNC inline const Scalar operator() (const Scalar& a) const { return numext::atan(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::patan(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = 5 * NumTraits::MulCost, + PacketAccess = packet_traits::HasATan + }; +}; + +/** \internal + * \brief Template functor to compute the tanh of a scalar + * \sa class CwiseUnaryOp, ArrayBase::tanh() + */ +template +struct scalar_tanh_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_tanh_op) + EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::tanh(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& x) const { return ptanh(x); } +}; + +template +struct functor_traits > { + enum { + PacketAccess = packet_traits::HasTanh, + Cost = ( (EIGEN_FAST_MATH && is_same::value) +// The following numbers are based on the AVX implementation, +#ifdef EIGEN_VECTORIZE_FMA + // Haswell can issue 2 add/mul/madd per cycle. + // 9 pmadd, 2 pmul, 1 div, 2 other + ? (2 * NumTraits::AddCost + + 6 * NumTraits::MulCost + + scalar_div_cost::HasDiv>::value) +#else + ? (11 * NumTraits::AddCost + + 11 * NumTraits::MulCost + + scalar_div_cost::HasDiv>::value) +#endif + // This number assumes a naive implementation of tanh + : (6 * NumTraits::AddCost + + 3 * NumTraits::MulCost + + 2 * scalar_div_cost::HasDiv>::value + + functor_traits >::Cost)) + }; +}; + +/** \internal + * \brief Template functor to compute the sinh of a scalar + * \sa class CwiseUnaryOp, ArrayBase::sinh() + */ +template struct scalar_sinh_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_sinh_op) + EIGEN_DEVICE_FUNC inline const Scalar operator() (const Scalar& a) const { return numext::sinh(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::psinh(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = 5 * NumTraits::MulCost, + PacketAccess = packet_traits::HasSinh + }; +}; + +/** \internal + * \brief Template functor to compute the cosh of a scalar + * \sa class CwiseUnaryOp, ArrayBase::cosh() + */ +template struct scalar_cosh_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cosh_op) + EIGEN_DEVICE_FUNC inline const Scalar operator() (const Scalar& a) const { return numext::cosh(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::pcosh(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = 5 * NumTraits::MulCost, + PacketAccess = packet_traits::HasCosh + }; +}; + +/** \internal + * \brief Template functor to compute the inverse of a scalar + * \sa class CwiseUnaryOp, Cwise::inverse() + */ +template +struct scalar_inverse_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_inverse_op) + EIGEN_DEVICE_FUNC inline Scalar operator() (const Scalar& a) const { return Scalar(1)/a; } + template + EIGEN_DEVICE_FUNC inline const Packet packetOp(const Packet& a) const + { return internal::pdiv(pset1(Scalar(1)),a); } +}; +template +struct functor_traits > +{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasDiv }; }; + +/** \internal + * \brief Template functor to compute the square of a scalar + * \sa class CwiseUnaryOp, Cwise::square() + */ +template +struct scalar_square_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_square_op) + EIGEN_DEVICE_FUNC inline Scalar operator() (const Scalar& a) const { return a*a; } + template + EIGEN_DEVICE_FUNC inline const Packet packetOp(const Packet& a) const + { return internal::pmul(a,a); } +}; +template +struct functor_traits > +{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; + +/** \internal + * \brief Template functor to compute the cube of a scalar + * \sa class CwiseUnaryOp, Cwise::cube() + */ +template +struct scalar_cube_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cube_op) + EIGEN_DEVICE_FUNC inline Scalar operator() (const Scalar& a) const { return a*a*a; } + template + EIGEN_DEVICE_FUNC inline const Packet packetOp(const Packet& a) const + { return internal::pmul(a,pmul(a,a)); } +}; +template +struct functor_traits > +{ enum { Cost = 2*NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; + +/** \internal + * \brief Template functor to compute the rounded value of a scalar + * \sa class CwiseUnaryOp, ArrayBase::round() + */ +template struct scalar_round_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_round_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { return numext::round(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::pround(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = NumTraits::MulCost, + PacketAccess = packet_traits::HasRound + }; +}; + +/** \internal + * \brief Template functor to compute the floor of a scalar + * \sa class CwiseUnaryOp, ArrayBase::floor() + */ +template struct scalar_floor_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_floor_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { return numext::floor(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::pfloor(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = NumTraits::MulCost, + PacketAccess = packet_traits::HasFloor + }; +}; + +/** \internal + * \brief Template functor to compute the ceil of a scalar + * \sa class CwiseUnaryOp, ArrayBase::ceil() + */ +template struct scalar_ceil_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_ceil_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { return numext::ceil(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::pceil(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = NumTraits::MulCost, + PacketAccess = packet_traits::HasCeil + }; +}; + +/** \internal + * \brief Template functor to compute whether a scalar is NaN + * \sa class CwiseUnaryOp, ArrayBase::isnan() + */ +template struct scalar_isnan_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_isnan_op) + typedef bool result_type; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return (numext::isnan)(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = NumTraits::MulCost, + PacketAccess = false + }; +}; + +/** \internal + * \brief Template functor to check whether a scalar is +/-inf + * \sa class CwiseUnaryOp, ArrayBase::isinf() + */ +template struct scalar_isinf_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_isinf_op) + typedef bool result_type; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return (numext::isinf)(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = NumTraits::MulCost, + PacketAccess = false + }; +}; + +/** \internal + * \brief Template functor to check whether a scalar has a finite value + * \sa class CwiseUnaryOp, ArrayBase::isfinite() + */ +template struct scalar_isfinite_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_isfinite_op) + typedef bool result_type; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return (numext::isfinite)(a); } +}; +template +struct functor_traits > +{ + enum { + Cost = NumTraits::MulCost, + PacketAccess = false + }; +}; + +/** \internal + * \brief Template functor to compute the logical not of a boolean + * + * \sa class CwiseUnaryOp, ArrayBase::operator! + */ +template struct scalar_boolean_not_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_not_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator() (const bool& a) const { return !a; } +}; +template +struct functor_traits > { + enum { + Cost = NumTraits::AddCost, + PacketAccess = false + }; +}; + +/** \internal + * \brief Template functor to compute the signum of a scalar + * \sa class CwiseUnaryOp, Cwise::sign() + */ +template::IsComplex!=0) > struct scalar_sign_op; +template +struct scalar_sign_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_sign_op) + EIGEN_DEVICE_FUNC inline const Scalar operator() (const Scalar& a) const + { + return Scalar( (a>Scalar(0)) - (a + //EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::psign(a); } +}; +template +struct scalar_sign_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_sign_op) + EIGEN_DEVICE_FUNC inline const Scalar operator() (const Scalar& a) const + { + typedef typename NumTraits::Real real_type; + real_type aa = numext::abs(a); + if (aa==real_type(0)) + return Scalar(0); + aa = real_type(1)/aa; + return Scalar(real(a)*aa, imag(a)*aa ); + } + //TODO + //template + //EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::psign(a); } +}; +template +struct functor_traits > +{ enum { + Cost = + NumTraits::IsComplex + ? ( 8*NumTraits::MulCost ) // roughly + : ( 3*NumTraits::AddCost), + PacketAccess = packet_traits::HasSign + }; +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_FUNCTORS_H diff --git a/libs/eigen3/Eigen/src/Core/products/CoeffBasedProduct.h b/libs/eigen3/Eigen/src/Core/products/CoeffBasedProduct.h deleted file mode 100644 index c06a0df1c..000000000 --- a/libs/eigen3/Eigen/src/Core/products/CoeffBasedProduct.h +++ /dev/null @@ -1,441 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2008 Benoit Jacob -// Copyright (C) 2008-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_COEFFBASED_PRODUCT_H -#define EIGEN_COEFFBASED_PRODUCT_H - -namespace Eigen { - -namespace internal { - -/********************************************************************************* -* Coefficient based product implementation. -* It is designed for the following use cases: -* - small fixed sizes -* - lazy products -*********************************************************************************/ - -/* Since the all the dimensions of the product are small, here we can rely - * on the generic Assign mechanism to evaluate the product per coeff (or packet). - * - * Note that here the inner-loops should always be unrolled. - */ - -template -struct product_coeff_impl; - -template -struct product_packet_impl; - -template -struct traits > -{ - typedef MatrixXpr XprKind; - typedef typename remove_all::type _LhsNested; - typedef typename remove_all::type _RhsNested; - typedef typename scalar_product_traits::ReturnType Scalar; - typedef typename promote_storage_type::StorageKind, - typename traits<_RhsNested>::StorageKind>::ret StorageKind; - typedef typename promote_index_type::Index, - typename traits<_RhsNested>::Index>::type Index; - - enum { - LhsCoeffReadCost = _LhsNested::CoeffReadCost, - RhsCoeffReadCost = _RhsNested::CoeffReadCost, - LhsFlags = _LhsNested::Flags, - RhsFlags = _RhsNested::Flags, - - RowsAtCompileTime = _LhsNested::RowsAtCompileTime, - ColsAtCompileTime = _RhsNested::ColsAtCompileTime, - InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(_LhsNested::ColsAtCompileTime, _RhsNested::RowsAtCompileTime), - - MaxRowsAtCompileTime = _LhsNested::MaxRowsAtCompileTime, - MaxColsAtCompileTime = _RhsNested::MaxColsAtCompileTime, - - LhsRowMajor = LhsFlags & RowMajorBit, - RhsRowMajor = RhsFlags & RowMajorBit, - - SameType = is_same::value, - - CanVectorizeRhs = RhsRowMajor && (RhsFlags & PacketAccessBit) - && (ColsAtCompileTime == Dynamic - || ( (ColsAtCompileTime % packet_traits::size) == 0 - && (RhsFlags&AlignedBit) - ) - ), - - CanVectorizeLhs = (!LhsRowMajor) && (LhsFlags & PacketAccessBit) - && (RowsAtCompileTime == Dynamic - || ( (RowsAtCompileTime % packet_traits::size) == 0 - && (LhsFlags&AlignedBit) - ) - ), - - EvalToRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 - : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 - : (RhsRowMajor && !CanVectorizeLhs), - - Flags = ((unsigned int)(LhsFlags | RhsFlags) & HereditaryBits & ~RowMajorBit) - | (EvalToRowMajor ? RowMajorBit : 0) - | NestingFlags - | (LhsFlags & RhsFlags & AlignedBit) - // TODO enable vectorization for mixed types - | (SameType && (CanVectorizeLhs || CanVectorizeRhs) ? PacketAccessBit : 0), - - CoeffReadCost = InnerSize == Dynamic ? Dynamic - : InnerSize * (NumTraits::MulCost + LhsCoeffReadCost + RhsCoeffReadCost) - + (InnerSize - 1) * NumTraits::AddCost, - - /* CanVectorizeInner deserves special explanation. It does not affect the product flags. It is not used outside - * of Product. If the Product itself is not a packet-access expression, there is still a chance that the inner - * loop of the product might be vectorized. This is the meaning of CanVectorizeInner. Since it doesn't affect - * the Flags, it is safe to make this value depend on ActualPacketAccessBit, that doesn't affect the ABI. - */ - CanVectorizeInner = SameType - && LhsRowMajor - && (!RhsRowMajor) - && (LhsFlags & RhsFlags & ActualPacketAccessBit) - && (LhsFlags & RhsFlags & AlignedBit) - && (InnerSize % packet_traits::size == 0) - }; -}; - -} // end namespace internal - -template -class CoeffBasedProduct - : internal::no_assignment_operator, - public MatrixBase > -{ - public: - - typedef MatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(CoeffBasedProduct) - typedef typename Base::PlainObject PlainObject; - - private: - - typedef typename internal::traits::_LhsNested _LhsNested; - typedef typename internal::traits::_RhsNested _RhsNested; - - enum { - PacketSize = internal::packet_traits::size, - InnerSize = internal::traits::InnerSize, - Unroll = CoeffReadCost != Dynamic && CoeffReadCost <= EIGEN_UNROLLING_LIMIT, - CanVectorizeInner = internal::traits::CanVectorizeInner - }; - - typedef internal::product_coeff_impl ScalarCoeffImpl; - - typedef CoeffBasedProduct LazyCoeffBasedProductType; - - public: - - inline CoeffBasedProduct(const CoeffBasedProduct& other) - : Base(), m_lhs(other.m_lhs), m_rhs(other.m_rhs) - {} - - template - inline CoeffBasedProduct(const Lhs& lhs, const Rhs& rhs) - : m_lhs(lhs), m_rhs(rhs) - { - // we don't allow taking products of matrices of different real types, as that wouldn't be vectorizable. - // We still allow to mix T and complex. - EIGEN_STATIC_ASSERT((internal::scalar_product_traits::Defined), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - eigen_assert(lhs.cols() == rhs.rows() - && "invalid matrix product" - && "if you wanted a coeff-wise or a dot product use the respective explicit functions"); - } - - EIGEN_STRONG_INLINE Index rows() const { return m_lhs.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_rhs.cols(); } - - EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const - { - Scalar res; - ScalarCoeffImpl::run(row, col, m_lhs, m_rhs, res); - return res; - } - - /* Allow index-based non-packet access. It is impossible though to allow index-based packed access, - * which is why we don't set the LinearAccessBit. - */ - EIGEN_STRONG_INLINE const Scalar coeff(Index index) const - { - Scalar res; - const Index row = RowsAtCompileTime == 1 ? 0 : index; - const Index col = RowsAtCompileTime == 1 ? index : 0; - ScalarCoeffImpl::run(row, col, m_lhs, m_rhs, res); - return res; - } - - template - EIGEN_STRONG_INLINE const PacketScalar packet(Index row, Index col) const - { - PacketScalar res; - internal::product_packet_impl - ::run(row, col, m_lhs, m_rhs, res); - return res; - } - - // Implicit conversion to the nested type (trigger the evaluation of the product) - EIGEN_STRONG_INLINE operator const PlainObject& () const - { - m_result.lazyAssign(*this); - return m_result; - } - - const _LhsNested& lhs() const { return m_lhs; } - const _RhsNested& rhs() const { return m_rhs; } - - const Diagonal diagonal() const - { return reinterpret_cast(*this); } - - template - const Diagonal diagonal() const - { return reinterpret_cast(*this); } - - const Diagonal diagonal(Index index) const - { return reinterpret_cast(*this).diagonal(index); } - - protected: - typename internal::add_const_on_value_type::type m_lhs; - typename internal::add_const_on_value_type::type m_rhs; - - mutable PlainObject m_result; -}; - -namespace internal { - -// here we need to overload the nested rule for products -// such that the nested type is a const reference to a plain matrix -template -struct nested, N, PlainObject> -{ - typedef PlainObject const& type; -}; - -/*************************************************************************** -* Normal product .coeff() implementation (with meta-unrolling) -***************************************************************************/ - -/************************************** -*** Scalar path - no vectorization *** -**************************************/ - -template -struct product_coeff_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res) - { - product_coeff_impl::run(row, col, lhs, rhs, res); - res += lhs.coeff(row, UnrollingIndex) * rhs.coeff(UnrollingIndex, col); - } -}; - -template -struct product_coeff_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res) - { - res = lhs.coeff(row, 0) * rhs.coeff(0, col); - } -}; - -template -struct product_coeff_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar& res) - { - eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix"); - res = lhs.coeff(row, 0) * rhs.coeff(0, col); - for(Index i = 1; i < lhs.cols(); ++i) - res += lhs.coeff(row, i) * rhs.coeff(i, col); - } -}; - -/******************************************* -*** Scalar path with inner vectorization *** -*******************************************/ - -template -struct product_coeff_vectorized_unroller -{ - typedef typename Lhs::Index Index; - enum { PacketSize = packet_traits::size }; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::PacketScalar &pres) - { - product_coeff_vectorized_unroller::run(row, col, lhs, rhs, pres); - pres = padd(pres, pmul( lhs.template packet(row, UnrollingIndex) , rhs.template packet(UnrollingIndex, col) )); - } -}; - -template -struct product_coeff_vectorized_unroller<0, Lhs, Rhs, Packet> -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::PacketScalar &pres) - { - pres = pmul(lhs.template packet(row, 0) , rhs.template packet(0, col)); - } -}; - -template -struct product_coeff_impl -{ - typedef typename Lhs::PacketScalar Packet; - typedef typename Lhs::Index Index; - enum { PacketSize = packet_traits::size }; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res) - { - Packet pres; - product_coeff_vectorized_unroller::run(row, col, lhs, rhs, pres); - product_coeff_impl::run(row, col, lhs, rhs, res); - res = predux(pres); - } -}; - -template -struct product_coeff_vectorized_dyn_selector -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) - { - res = lhs.row(row).transpose().cwiseProduct(rhs.col(col)).sum(); - } -}; - -// NOTE the 3 following specializations are because taking .col(0) on a vector is a bit slower -// NOTE maybe they are now useless since we have a specialization for Block -template -struct product_coeff_vectorized_dyn_selector -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index /*row*/, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) - { - res = lhs.transpose().cwiseProduct(rhs.col(col)).sum(); - } -}; - -template -struct product_coeff_vectorized_dyn_selector -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index /*col*/, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) - { - res = lhs.row(row).transpose().cwiseProduct(rhs).sum(); - } -}; - -template -struct product_coeff_vectorized_dyn_selector -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) - { - res = lhs.transpose().cwiseProduct(rhs).sum(); - } -}; - -template -struct product_coeff_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) - { - product_coeff_vectorized_dyn_selector::run(row, col, lhs, rhs, res); - } -}; - -/******************* -*** Packet path *** -*******************/ - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) - { - product_packet_impl::run(row, col, lhs, rhs, res); - res = pmadd(pset1(lhs.coeff(row, UnrollingIndex)), rhs.template packet(UnrollingIndex, col), res); - } -}; - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) - { - product_packet_impl::run(row, col, lhs, rhs, res); - res = pmadd(lhs.template packet(row, UnrollingIndex), pset1(rhs.coeff(UnrollingIndex, col)), res); - } -}; - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) - { - res = pmul(pset1(lhs.coeff(row, 0)),rhs.template packet(0, col)); - } -}; - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) - { - res = pmul(lhs.template packet(row, 0), pset1(rhs.coeff(0, col))); - } -}; - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res) - { - eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix"); - res = pmul(pset1(lhs.coeff(row, 0)),rhs.template packet(0, col)); - for(Index i = 1; i < lhs.cols(); ++i) - res = pmadd(pset1(lhs.coeff(row, i)), rhs.template packet(i, col), res); - } -}; - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res) - { - eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix"); - res = pmul(lhs.template packet(row, 0), pset1(rhs.coeff(0, col))); - for(Index i = 1; i < lhs.cols(); ++i) - res = pmadd(lhs.template packet(row, i), pset1(rhs.coeff(i, col)), res); - } -}; - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_COEFFBASED_PRODUCT_H diff --git a/libs/eigen3/Eigen/src/Core/products/GeneralBlockPanelKernel.h b/libs/eigen3/Eigen/src/Core/products/GeneralBlockPanelKernel.h index bcdca5b0d..45230bce5 100644 --- a/libs/eigen3/Eigen/src/Core/products/GeneralBlockPanelKernel.h +++ b/libs/eigen3/Eigen/src/Core/products/GeneralBlockPanelKernel.h @@ -10,8 +10,9 @@ #ifndef EIGEN_GENERAL_BLOCK_PANEL_H #define EIGEN_GENERAL_BLOCK_PANEL_H -namespace Eigen { - + +namespace Eigen { + namespace internal { template @@ -24,29 +25,51 @@ inline std::ptrdiff_t manage_caching_sizes_helper(std::ptrdiff_t a, std::ptrdiff return a<=0 ? b : a; } +#if EIGEN_ARCH_i386_OR_x86_64 +const std::ptrdiff_t defaultL1CacheSize = 32*1024; +const std::ptrdiff_t defaultL2CacheSize = 256*1024; +const std::ptrdiff_t defaultL3CacheSize = 2*1024*1024; +#else +const std::ptrdiff_t defaultL1CacheSize = 16*1024; +const std::ptrdiff_t defaultL2CacheSize = 512*1024; +const std::ptrdiff_t defaultL3CacheSize = 512*1024; +#endif + /** \internal */ -inline void manage_caching_sizes(Action action, std::ptrdiff_t* l1=0, std::ptrdiff_t* l2=0) -{ - static std::ptrdiff_t m_l1CacheSize = 0; - static std::ptrdiff_t m_l2CacheSize = 0; - if(m_l2CacheSize==0) - { - m_l1CacheSize = manage_caching_sizes_helper(queryL1CacheSize(),8 * 1024); - m_l2CacheSize = manage_caching_sizes_helper(queryTopLevelCacheSize(),1*1024*1024); +struct CacheSizes { + CacheSizes(): m_l1(-1),m_l2(-1),m_l3(-1) { + int l1CacheSize, l2CacheSize, l3CacheSize; + queryCacheSizes(l1CacheSize, l2CacheSize, l3CacheSize); + m_l1 = manage_caching_sizes_helper(l1CacheSize, defaultL1CacheSize); + m_l2 = manage_caching_sizes_helper(l2CacheSize, defaultL2CacheSize); + m_l3 = manage_caching_sizes_helper(l3CacheSize, defaultL3CacheSize); } - + + std::ptrdiff_t m_l1; + std::ptrdiff_t m_l2; + std::ptrdiff_t m_l3; +}; + + +/** \internal */ +inline void manage_caching_sizes(Action action, std::ptrdiff_t* l1, std::ptrdiff_t* l2, std::ptrdiff_t* l3) +{ + static CacheSizes m_cacheSizes; + if(action==SetAction) { // set the cpu cache size and cache all block sizes from a global cache size in byte eigen_internal_assert(l1!=0 && l2!=0); - m_l1CacheSize = *l1; - m_l2CacheSize = *l2; + m_cacheSizes.m_l1 = *l1; + m_cacheSizes.m_l2 = *l2; + m_cacheSizes.m_l3 = *l3; } else if(action==GetAction) { eigen_internal_assert(l1!=0 && l2!=0); - *l1 = m_l1CacheSize; - *l2 = m_l2CacheSize; + *l1 = m_cacheSizes.m_l1; + *l2 = m_cacheSizes.m_l2; + *l3 = m_cacheSizes.m_l3; } else { @@ -54,6 +77,206 @@ inline void manage_caching_sizes(Action action, std::ptrdiff_t* l1=0, std::ptrdi } } +/* Helper for computeProductBlockingSizes. + * + * Given a m x k times k x n matrix product of scalar types \c LhsScalar and \c RhsScalar, + * this function computes the blocking size parameters along the respective dimensions + * for matrix products and related algorithms. The blocking sizes depends on various + * parameters: + * - the L1 and L2 cache sizes, + * - the register level blocking sizes defined by gebp_traits, + * - the number of scalars that fit into a packet (when vectorization is enabled). + * + * \sa setCpuCacheSizes */ + +template +void evaluateProductBlockingSizesHeuristic(Index& k, Index& m, Index& n, Index num_threads = 1) +{ + typedef gebp_traits Traits; + + // Explanations: + // Let's recall that the product algorithms form mc x kc vertical panels A' on the lhs and + // kc x nc blocks B' on the rhs. B' has to fit into L2/L3 cache. Moreover, A' is processed + // per mr x kc horizontal small panels where mr is the blocking size along the m dimension + // at the register level. This small horizontal panel has to stay within L1 cache. + std::ptrdiff_t l1, l2, l3; + manage_caching_sizes(GetAction, &l1, &l2, &l3); + + if (num_threads > 1) { + typedef typename Traits::ResScalar ResScalar; + enum { + kdiv = KcFactor * (Traits::mr * sizeof(LhsScalar) + Traits::nr * sizeof(RhsScalar)), + ksub = Traits::mr * Traits::nr * sizeof(ResScalar), + kr = 8, + mr = Traits::mr, + nr = Traits::nr + }; + // Increasing k gives us more time to prefetch the content of the "C" + // registers. However once the latency is hidden there is no point in + // increasing the value of k, so we'll cap it at 320 (value determined + // experimentally). + const Index k_cache = (numext::mini)((l1-ksub)/kdiv, 320); + if (k_cache < k) { + k = k_cache - (k_cache % kr); + eigen_internal_assert(k > 0); + } + + const Index n_cache = (l2-l1) / (nr * sizeof(RhsScalar) * k); + const Index n_per_thread = numext::div_ceil(n, num_threads); + if (n_cache <= n_per_thread) { + // Don't exceed the capacity of the l2 cache. + eigen_internal_assert(n_cache >= static_cast(nr)); + n = n_cache - (n_cache % nr); + eigen_internal_assert(n > 0); + } else { + n = (numext::mini)(n, (n_per_thread + nr - 1) - ((n_per_thread + nr - 1) % nr)); + } + + if (l3 > l2) { + // l3 is shared between all cores, so we'll give each thread its own chunk of l3. + const Index m_cache = (l3-l2) / (sizeof(LhsScalar) * k * num_threads); + const Index m_per_thread = numext::div_ceil(m, num_threads); + if(m_cache < m_per_thread && m_cache >= static_cast(mr)) { + m = m_cache - (m_cache % mr); + eigen_internal_assert(m > 0); + } else { + m = (numext::mini)(m, (m_per_thread + mr - 1) - ((m_per_thread + mr - 1) % mr)); + } + } + } + else { + // In unit tests we do not want to use extra large matrices, + // so we reduce the cache size to check the blocking strategy is not flawed +#ifdef EIGEN_DEBUG_SMALL_PRODUCT_BLOCKS + l1 = 9*1024; + l2 = 32*1024; + l3 = 512*1024; +#endif + + // Early return for small problems because the computation below are time consuming for small problems. + // Perhaps it would make more sense to consider k*n*m?? + // Note that for very tiny problem, this function should be bypassed anyway + // because we use the coefficient-based implementation for them. + if((numext::maxi)(k,(numext::maxi)(m,n))<48) + return; + + typedef typename Traits::ResScalar ResScalar; + enum { + k_peeling = 8, + k_div = KcFactor * (Traits::mr * sizeof(LhsScalar) + Traits::nr * sizeof(RhsScalar)), + k_sub = Traits::mr * Traits::nr * sizeof(ResScalar) + }; + + // ---- 1st level of blocking on L1, yields kc ---- + + // Blocking on the third dimension (i.e., k) is chosen so that an horizontal panel + // of size mr x kc of the lhs plus a vertical panel of kc x nr of the rhs both fits within L1 cache. + // We also include a register-level block of the result (mx x nr). + // (In an ideal world only the lhs panel would stay in L1) + // Moreover, kc has to be a multiple of 8 to be compatible with loop peeling, leading to a maximum blocking size of: + const Index max_kc = numext::maxi(((l1-k_sub)/k_div) & (~(k_peeling-1)),1); + const Index old_k = k; + if(k>max_kc) + { + // We are really blocking on the third dimension: + // -> reduce blocking size to make sure the last block is as large as possible + // while keeping the same number of sweeps over the result. + k = (k%max_kc)==0 ? max_kc + : max_kc - k_peeling * ((max_kc-1-(k%max_kc))/(k_peeling*(k/max_kc+1))); + + eigen_internal_assert(((old_k/k) == (old_k/max_kc)) && "the number of sweeps has to remain the same"); + } + + // ---- 2nd level of blocking on max(L2,L3), yields nc ---- + + // TODO find a reliable way to get the actual amount of cache per core to use for 2nd level blocking, that is: + // actual_l2 = max(l2, l3/nb_core_sharing_l3) + // The number below is quite conservative: it is better to underestimate the cache size rather than overestimating it) + // For instance, it corresponds to 6MB of L3 shared among 4 cores. + #ifdef EIGEN_DEBUG_SMALL_PRODUCT_BLOCKS + const Index actual_l2 = l3; + #else + const Index actual_l2 = 1572864; // == 1.5 MB + #endif + + // Here, nc is chosen such that a block of kc x nc of the rhs fit within half of L2. + // The second half is implicitly reserved to access the result and lhs coefficients. + // When k= Index(Traits::nr*sizeof(RhsScalar))*k) + { + // L1 blocking + max_nc = remaining_l1 / (k*sizeof(RhsScalar)); + } + else + { + // L2 blocking + max_nc = (3*actual_l2)/(2*2*max_kc*sizeof(RhsScalar)); + } + // WARNING Below, we assume that Traits::nr is a power of two. + Index nc = numext::mini(actual_l2/(2*k*sizeof(RhsScalar)), max_nc) & (~(Traits::nr-1)); + if(n>nc) + { + // We are really blocking over the columns: + // -> reduce blocking size to make sure the last block is as large as possible + // while keeping the same number of sweeps over the packed lhs. + // Here we allow one more sweep if this gives us a perfect match, thus the commented "-1" + n = (n%nc)==0 ? nc + : (nc - Traits::nr * ((nc/*-1*/-(n%nc))/(Traits::nr*(n/nc+1)))); + } + else if(old_k==k) + { + // So far, no blocking at all, i.e., kc==k, and nc==n. + // In this case, let's perform a blocking over the rows such that the packed lhs data is kept in cache L1/L2 + // TODO: part of this blocking strategy is now implemented within the kernel itself, so the L1-based heuristic here should be obsolete. + Index problem_size = k*n*sizeof(LhsScalar); + Index actual_lm = actual_l2; + Index max_mc = m; + if(problem_size<=1024) + { + // problem is small enough to keep in L1 + // Let's choose m such that lhs's block fit in 1/3 of L1 + actual_lm = l1; + } + else if(l3!=0 && problem_size<=32768) + { + // we have both L2 and L3, and problem is small enough to be kept in L2 + // Let's choose m such that lhs's block fit in 1/3 of L2 + actual_lm = l2; + max_mc = (numext::mini)(576,max_mc); + } + Index mc = (numext::mini)(actual_lm/(3*k*sizeof(LhsScalar)), max_mc); + if (mc > Traits::mr) mc -= mc % Traits::mr; + else if (mc==0) return; + m = (m%mc)==0 ? mc + : (mc - Traits::mr * ((mc/*-1*/-(m%mc))/(Traits::mr*(m/mc+1)))); + } + } +} + +template +inline bool useSpecificBlockingSizes(Index& k, Index& m, Index& n) +{ +#ifdef EIGEN_TEST_SPECIFIC_BLOCKING_SIZES + if (EIGEN_TEST_SPECIFIC_BLOCKING_SIZES) { + k = numext::mini(k, EIGEN_TEST_SPECIFIC_BLOCKING_SIZE_K); + m = numext::mini(m, EIGEN_TEST_SPECIFIC_BLOCKING_SIZE_M); + n = numext::mini(n, EIGEN_TEST_SPECIFIC_BLOCKING_SIZE_N); + return true; + } +#else + EIGEN_UNUSED_VARIABLE(k) + EIGEN_UNUSED_VARIABLE(m) + EIGEN_UNUSED_VARIABLE(n) +#endif + return false; +} + /** \brief Computes the blocking parameters for a m x k times k x n matrix product * * \param[in,out] k Input: the third dimension of the product. Output: the blocking size along the same dimension. @@ -62,48 +285,30 @@ inline void manage_caching_sizes(Action action, std::ptrdiff_t* l1=0, std::ptrdi * * Given a m x k times k x n matrix product of scalar types \c LhsScalar and \c RhsScalar, * this function computes the blocking size parameters along the respective dimensions - * for matrix products and related algorithms. The blocking sizes depends on various - * parameters: - * - the L1 and L2 cache sizes, - * - the register level blocking sizes defined by gebp_traits, - * - the number of scalars that fit into a packet (when vectorization is enabled). + * for matrix products and related algorithms. + * + * The blocking size parameters may be evaluated: + * - either by a heuristic based on cache sizes; + * - or using fixed prescribed values (for testing purposes). * * \sa setCpuCacheSizes */ -template -void computeProductBlockingSizes(SizeType& k, SizeType& m, SizeType& n) -{ - EIGEN_UNUSED_VARIABLE(n); - // Explanations: - // Let's recall the product algorithms form kc x nc horizontal panels B' on the rhs and - // mc x kc blocks A' on the lhs. A' has to fit into L2 cache. Moreover, B' is processed - // per kc x nr vertical small panels where nr is the blocking size along the n dimension - // at the register level. For vectorization purpose, these small vertical panels are unpacked, - // e.g., each coefficient is replicated to fit a packet. This small vertical panel has to - // stay in L1 cache. - std::ptrdiff_t l1, l2; - typedef gebp_traits Traits; - enum { - kdiv = KcFactor * 2 * Traits::nr - * Traits::RhsProgress * sizeof(RhsScalar), - mr = gebp_traits::mr, - mr_mask = (0xffffffff/mr)*mr - }; - - manage_caching_sizes(GetAction, &l1, &l2); - k = std::min(k, l1/kdiv); - SizeType _m = k>0 ? l2/(4 * sizeof(LhsScalar) * k) : 0; - if(_m +void computeProductBlockingSizes(Index& k, Index& m, Index& n, Index num_threads = 1) +{ + if (!useSpecificBlockingSizes(k, m, n)) { + evaluateProductBlockingSizesHeuristic(k, m, n, num_threads); + } } -template -inline void computeProductBlockingSizes(SizeType& k, SizeType& m, SizeType& n) +template +inline void computeProductBlockingSizes(Index& k, Index& m, Index& n, Index num_threads = 1) { - computeProductBlockingSizes(k, m, n); + computeProductBlockingSizes(k, m, n, num_threads); } -#ifdef EIGEN_HAS_FUSE_CJMADD - #define MADD(CJ,A,B,C,T) C = CJ.pmadd(A,B,C); +#ifdef EIGEN_HAS_SINGLE_INSTRUCTION_CJMADD + #define CJMADD(CJ,A,B,C,T) C = CJ.pmadd(A,B,C); #else // FIXME (a bit overkill maybe ?) @@ -128,8 +333,8 @@ inline void computeProductBlockingSizes(SizeType& k, SizeType& m, SizeType& n) gebp_madd_selector::run(cj,a,b,c,t); } - #define MADD(CJ,A,B,C,T) gebp_madd(CJ,A,B,C,T); -// #define MADD(CJ,A,B,C,T) T = B; T = CJ.pmul(A,T); C = padd(C,T); + #define CJMADD(CJ,A,B,C,T) gebp_madd(CJ,A,B,C,T); +// #define CJMADD(CJ,A,B,C,T) T = B; T = CJ.pmul(A,T); C = padd(C,T); #endif /* Vectorization logic @@ -148,7 +353,7 @@ class gebp_traits public: typedef _LhsScalar LhsScalar; typedef _RhsScalar RhsScalar; - typedef typename scalar_product_traits::ReturnType ResScalar; + typedef typename ScalarBinaryOpTraits::ReturnType ResScalar; enum { ConjLhs = _ConjLhs, @@ -160,16 +365,22 @@ class gebp_traits NumberOfRegisters = EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS, - // register block size along the N direction (must be either 2 or 4) - nr = NumberOfRegisters/4, + // register block size along the N direction must be 1 or 4 + nr = 4, // register block size along the M direction (currently, this one cannot be modified) - mr = 2 * LhsPacketSize, + default_mr = (EIGEN_PLAIN_ENUM_MIN(16,NumberOfRegisters)/2/nr)*LhsPacketSize, +#if defined(EIGEN_HAS_SINGLE_INSTRUCTION_MADD) && !defined(EIGEN_VECTORIZE_ALTIVEC) && !defined(EIGEN_VECTORIZE_VSX) + // we assume 16 registers + // See bug 992, if the scalar type is not vectorizable but that EIGEN_HAS_SINGLE_INSTRUCTION_MADD is defined, + // then using 3*LhsPacketSize triggers non-implemented paths in syrk. + mr = Vectorizable ? 3*LhsPacketSize : default_mr, +#else + mr = default_mr, +#endif - WorkSpaceFactor = nr * RhsPacketSize, - LhsProgress = LhsPacketSize, - RhsProgress = RhsPacketSize + RhsProgress = 1 }; typedef typename packet_traits::type _LhsPacket; @@ -186,36 +397,67 @@ class gebp_traits { p = pset1(ResScalar(0)); } - - EIGEN_STRONG_INLINE void unpackRhs(DenseIndex n, const RhsScalar* rhs, RhsScalar* b) + + EIGEN_STRONG_INLINE void broadcastRhs(const RhsScalar* b, RhsPacket& b0, RhsPacket& b1, RhsPacket& b2, RhsPacket& b3) + { + pbroadcast4(b, b0, b1, b2, b3); + } + +// EIGEN_STRONG_INLINE void broadcastRhs(const RhsScalar* b, RhsPacket& b0, RhsPacket& b1) +// { +// pbroadcast2(b, b0, b1); +// } + + template + EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, RhsPacketType& dest) const + { + dest = pset1(*b); + } + + EIGEN_STRONG_INLINE void loadRhsQuad(const RhsScalar* b, RhsPacket& dest) const { - for(DenseIndex k=0; k(&b[k*RhsPacketSize], rhs[k]); + dest = ploadquad(b); } - EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, RhsPacket& dest) const + template + EIGEN_STRONG_INLINE void loadLhs(const LhsScalar* a, LhsPacketType& dest) const { - dest = pload(b); + dest = pload(a); } - EIGEN_STRONG_INLINE void loadLhs(const LhsScalar* a, LhsPacket& dest) const + template + EIGEN_STRONG_INLINE void loadLhsUnaligned(const LhsScalar* a, LhsPacketType& dest) const { - dest = pload(a); + dest = ploadu(a); } - EIGEN_STRONG_INLINE void madd(const LhsPacket& a, const RhsPacket& b, AccPacket& c, AccPacket& tmp) const + template + EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const { - tmp = b; tmp = pmul(a,tmp); c = padd(c,tmp); + conj_helper cj; + // It would be a lot cleaner to call pmadd all the time. Unfortunately if we + // let gcc allocate the register in which to store the result of the pmul + // (in the case where there is no FMA) gcc fails to figure out how to avoid + // spilling register. +#ifdef EIGEN_HAS_SINGLE_INSTRUCTION_MADD + EIGEN_UNUSED_VARIABLE(tmp); + c = cj.pmadd(a,b,c); +#else + tmp = b; tmp = cj.pmul(a,tmp); c = padd(c,tmp); +#endif } EIGEN_STRONG_INLINE void acc(const AccPacket& c, const ResPacket& alpha, ResPacket& r) const { r = pmadd(c,alpha,r); } + + template + EIGEN_STRONG_INLINE void acc(const ResPacketHalf& c, const ResPacketHalf& alpha, ResPacketHalf& r) const + { + r = pmadd(c,alpha,r); + } -protected: -// conj_helper cj; -// conj_helper pcj; }; template @@ -224,7 +466,7 @@ class gebp_traits, RealScalar, _ConjLhs, false> public: typedef std::complex LhsScalar; typedef RealScalar RhsScalar; - typedef typename scalar_product_traits::ReturnType ResScalar; + typedef typename ScalarBinaryOpTraits::ReturnType ResScalar; enum { ConjLhs = _ConjLhs, @@ -235,12 +477,16 @@ class gebp_traits, RealScalar, _ConjLhs, false> ResPacketSize = Vectorizable ? packet_traits::size : 1, NumberOfRegisters = EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS, - nr = NumberOfRegisters/4, - mr = 2 * LhsPacketSize, - WorkSpaceFactor = nr*RhsPacketSize, + nr = 4, +#if defined(EIGEN_HAS_SINGLE_INSTRUCTION_MADD) && !defined(EIGEN_VECTORIZE_ALTIVEC) && !defined(EIGEN_VECTORIZE_VSX) + // we assume 16 registers + mr = 3*LhsPacketSize, +#else + mr = (EIGEN_PLAIN_ENUM_MIN(16,NumberOfRegisters)/2/nr)*LhsPacketSize, +#endif LhsProgress = LhsPacketSize, - RhsProgress = RhsPacketSize + RhsProgress = 1 }; typedef typename packet_traits::type _LhsPacket; @@ -258,15 +504,14 @@ class gebp_traits, RealScalar, _ConjLhs, false> p = pset1(ResScalar(0)); } - EIGEN_STRONG_INLINE void unpackRhs(DenseIndex n, const RhsScalar* rhs, RhsScalar* b) + EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, RhsPacket& dest) const { - for(DenseIndex k=0; k(&b[k*RhsPacketSize], rhs[k]); + dest = pset1(*b); } - - EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, RhsPacket& dest) const + + EIGEN_STRONG_INLINE void loadRhsQuad(const RhsScalar* b, RhsPacket& dest) const { - dest = pload(b); + dest = pset1(*b); } EIGEN_STRONG_INLINE void loadLhs(const LhsScalar* a, LhsPacket& dest) const @@ -274,6 +519,21 @@ class gebp_traits, RealScalar, _ConjLhs, false> dest = pload(a); } + EIGEN_STRONG_INLINE void loadLhsUnaligned(const LhsScalar* a, LhsPacket& dest) const + { + dest = ploadu(a); + } + + EIGEN_STRONG_INLINE void broadcastRhs(const RhsScalar* b, RhsPacket& b0, RhsPacket& b1, RhsPacket& b2, RhsPacket& b3) + { + pbroadcast4(b, b0, b1, b2, b3); + } + +// EIGEN_STRONG_INLINE void broadcastRhs(const RhsScalar* b, RhsPacket& b0, RhsPacket& b1) +// { +// pbroadcast2(b, b0, b1); +// } + EIGEN_STRONG_INLINE void madd(const LhsPacket& a, const RhsPacket& b, AccPacket& c, RhsPacket& tmp) const { madd_impl(a, b, c, tmp, typename conditional::type()); @@ -281,7 +541,12 @@ class gebp_traits, RealScalar, _ConjLhs, false> EIGEN_STRONG_INLINE void madd_impl(const LhsPacket& a, const RhsPacket& b, AccPacket& c, RhsPacket& tmp, const true_type&) const { +#ifdef EIGEN_HAS_SINGLE_INSTRUCTION_MADD + EIGEN_UNUSED_VARIABLE(tmp); + c.v = pmadd(a.v,b,c.v); +#else tmp = b; tmp = pmul(a.v,tmp); c.v = padd(c.v,tmp); +#endif } EIGEN_STRONG_INLINE void madd_impl(const LhsScalar& a, const RhsScalar& b, ResScalar& c, RhsScalar& /*tmp*/, const false_type&) const @@ -298,6 +563,38 @@ class gebp_traits, RealScalar, _ConjLhs, false> conj_helper cj; }; +template +struct DoublePacket +{ + Packet first; + Packet second; +}; + +template +DoublePacket padd(const DoublePacket &a, const DoublePacket &b) +{ + DoublePacket res; + res.first = padd(a.first, b.first); + res.second = padd(a.second,b.second); + return res; +} + +template +const DoublePacket& predux_downto4(const DoublePacket &a) +{ + return a; +} + +template struct unpacket_traits > { typedef DoublePacket half; }; +// template +// DoublePacket pmadd(const DoublePacket &a, const DoublePacket &b) +// { +// DoublePacket res; +// res.first = padd(a.first, b.first); +// res.second = padd(a.second,b.second); +// return res; +// } + template class gebp_traits, std::complex, _ConjLhs, _ConjRhs > { @@ -314,60 +611,80 @@ class gebp_traits, std::complex, _ConjLhs, && packet_traits::Vectorizable, RealPacketSize = Vectorizable ? packet_traits::size : 1, ResPacketSize = Vectorizable ? packet_traits::size : 1, - - nr = 2, - mr = 2 * ResPacketSize, - WorkSpaceFactor = Vectorizable ? 2*nr*RealPacketSize : nr, + LhsPacketSize = Vectorizable ? packet_traits::size : 1, + RhsPacketSize = Vectorizable ? packet_traits::size : 1, + + // FIXME: should depend on NumberOfRegisters + nr = 4, + mr = ResPacketSize, LhsProgress = ResPacketSize, - RhsProgress = Vectorizable ? 2*ResPacketSize : 1 + RhsProgress = 1 }; typedef typename packet_traits::type RealPacket; typedef typename packet_traits::type ScalarPacket; - struct DoublePacket - { - RealPacket first; - RealPacket second; - }; + typedef DoublePacket DoublePacketType; typedef typename conditional::type LhsPacket; - typedef typename conditional::type RhsPacket; + typedef typename conditional::type RhsPacket; typedef typename conditional::type ResPacket; - typedef typename conditional::type AccPacket; + typedef typename conditional::type AccPacket; EIGEN_STRONG_INLINE void initAcc(Scalar& p) { p = Scalar(0); } - EIGEN_STRONG_INLINE void initAcc(DoublePacket& p) + EIGEN_STRONG_INLINE void initAcc(DoublePacketType& p) { p.first = pset1(RealScalar(0)); p.second = pset1(RealScalar(0)); } - /* Unpack the rhs coeff such that each complex coefficient is spread into - * two packects containing respectively the real and imaginary coefficient - * duplicated as many time as needed: (x+iy) => [x, ..., x] [y, ..., y] - */ - EIGEN_STRONG_INLINE void unpackRhs(DenseIndex n, const Scalar* rhs, Scalar* b) + // Scalar path + EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, ResPacket& dest) const { - for(DenseIndex k=0; k((RealScalar*)&b[k*ResPacketSize*2+0], real(rhs[k])); - pstore1((RealScalar*)&b[k*ResPacketSize*2+ResPacketSize], imag(rhs[k])); - } - else - b[k] = rhs[k]; - } + dest = pset1(*b); } - EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, ResPacket& dest) const { dest = *b; } - - EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, DoublePacket& dest) const + // Vectorized path + EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, DoublePacketType& dest) const + { + dest.first = pset1(real(*b)); + dest.second = pset1(imag(*b)); + } + + EIGEN_STRONG_INLINE void loadRhsQuad(const RhsScalar* b, ResPacket& dest) const + { + loadRhs(b,dest); + } + EIGEN_STRONG_INLINE void loadRhsQuad(const RhsScalar* b, DoublePacketType& dest) const + { + eigen_internal_assert(unpacket_traits::size<=4); + loadRhs(b,dest); + } + + EIGEN_STRONG_INLINE void broadcastRhs(const RhsScalar* b, RhsPacket& b0, RhsPacket& b1, RhsPacket& b2, RhsPacket& b3) { - dest.first = pload((const RealScalar*)b); - dest.second = pload((const RealScalar*)(b+ResPacketSize)); + // FIXME not sure that's the best way to implement it! + loadRhs(b+0, b0); + loadRhs(b+1, b1); + loadRhs(b+2, b2); + loadRhs(b+3, b3); + } + + // Vectorized path + EIGEN_STRONG_INLINE void broadcastRhs(const RhsScalar* b, DoublePacketType& b0, DoublePacketType& b1) + { + // FIXME not sure that's the best way to implement it! + loadRhs(b+0, b0); + loadRhs(b+1, b1); + } + + // Scalar path + EIGEN_STRONG_INLINE void broadcastRhs(const RhsScalar* b, RhsScalar& b0, RhsScalar& b1) + { + // FIXME not sure that's the best way to implement it! + loadRhs(b+0, b0); + loadRhs(b+1, b1); } // nothing special here @@ -376,7 +693,12 @@ class gebp_traits, std::complex, _ConjLhs, dest = pload((const typename unpacket_traits::type*)(a)); } - EIGEN_STRONG_INLINE void madd(const LhsPacket& a, const RhsPacket& b, DoublePacket& c, RhsPacket& /*tmp*/) const + EIGEN_STRONG_INLINE void loadLhsUnaligned(const LhsScalar* a, LhsPacket& dest) const + { + dest = ploadu((const typename unpacket_traits::type*)(a)); + } + + EIGEN_STRONG_INLINE void madd(const LhsPacket& a, const RhsPacket& b, DoublePacketType& c, RhsPacket& /*tmp*/) const { c.first = padd(pmul(a,b.first), c.first); c.second = padd(pmul(a,b.second),c.second); @@ -389,7 +711,7 @@ class gebp_traits, std::complex, _ConjLhs, EIGEN_STRONG_INLINE void acc(const Scalar& c, const Scalar& alpha, Scalar& r) const { r += alpha * c; } - EIGEN_STRONG_INLINE void acc(const DoublePacket& c, const ResPacket& alpha, ResPacket& r) const + EIGEN_STRONG_INLINE void acc(const DoublePacketType& c, const ResPacket& alpha, ResPacket& r) const { // assemble c ResPacket tmp; @@ -440,12 +762,12 @@ class gebp_traits, false, _ConjRhs > ResPacketSize = Vectorizable ? packet_traits::size : 1, NumberOfRegisters = EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS, + // FIXME: should depend on NumberOfRegisters nr = 4, - mr = 2*ResPacketSize, - WorkSpaceFactor = nr*RhsPacketSize, + mr = (EIGEN_PLAIN_ENUM_MIN(16,NumberOfRegisters)/2/nr)*ResPacketSize, LhsProgress = ResPacketSize, - RhsProgress = ResPacketSize + RhsProgress = 1 }; typedef typename packet_traits::type _LhsPacket; @@ -463,21 +785,38 @@ class gebp_traits, false, _ConjRhs > p = pset1(ResScalar(0)); } - EIGEN_STRONG_INLINE void unpackRhs(DenseIndex n, const RhsScalar* rhs, RhsScalar* b) + EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, RhsPacket& dest) const { - for(DenseIndex k=0; k(&b[k*RhsPacketSize], rhs[k]); + dest = pset1(*b); } - - EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, RhsPacket& dest) const + + void broadcastRhs(const RhsScalar* b, RhsPacket& b0, RhsPacket& b1, RhsPacket& b2, RhsPacket& b3) { - dest = pload(b); + pbroadcast4(b, b0, b1, b2, b3); } + +// EIGEN_STRONG_INLINE void broadcastRhs(const RhsScalar* b, RhsPacket& b0, RhsPacket& b1) +// { +// // FIXME not sure that's the best way to implement it! +// b0 = pload1(b+0); +// b1 = pload1(b+1); +// } EIGEN_STRONG_INLINE void loadLhs(const LhsScalar* a, LhsPacket& dest) const { dest = ploaddup(a); } + + EIGEN_STRONG_INLINE void loadRhsQuad(const RhsScalar* b, RhsPacket& dest) const + { + eigen_internal_assert(unpacket_traits::size<=4); + loadRhs(b,dest); + } + + EIGEN_STRONG_INLINE void loadLhsUnaligned(const LhsScalar* a, LhsPacket& dest) const + { + dest = ploaddup(a); + } EIGEN_STRONG_INLINE void madd(const LhsPacket& a, const RhsPacket& b, AccPacket& c, RhsPacket& tmp) const { @@ -486,7 +825,13 @@ class gebp_traits, false, _ConjRhs > EIGEN_STRONG_INLINE void madd_impl(const LhsPacket& a, const RhsPacket& b, AccPacket& c, RhsPacket& tmp, const true_type&) const { +#ifdef EIGEN_HAS_SINGLE_INSTRUCTION_MADD + EIGEN_UNUSED_VARIABLE(tmp); + c.v = pmadd(a,b.v,c.v); +#else tmp = b; tmp.v = pmul(a,tmp.v); c = padd(c,tmp); +#endif + } EIGEN_STRONG_INLINE void madd_impl(const LhsScalar& a, const RhsScalar& b, ResScalar& c, RhsScalar& /*tmp*/, const false_type&) const @@ -510,7 +855,7 @@ class gebp_traits, false, _ConjRhs > * |real |cplx | no vectorization yet, would require to pack A with duplication * |cplx |real | easy vectorization */ -template +template struct gebp_kernel { typedef gebp_traits Traits; @@ -520,6 +865,15 @@ struct gebp_kernel typedef typename Traits::ResPacket ResPacket; typedef typename Traits::AccPacket AccPacket; + typedef gebp_traits SwappedTraits; + typedef typename SwappedTraits::ResScalar SResScalar; + typedef typename SwappedTraits::LhsPacket SLhsPacket; + typedef typename SwappedTraits::RhsPacket SRhsPacket; + typedef typename SwappedTraits::ResPacket SResPacket; + typedef typename SwappedTraits::AccPacket SAccPacket; + + typedef typename DataMapper::LinearMapper LinearMapper; + enum { Vectorizable = Traits::Vectorizable, LhsProgress = Traits::LhsProgress, @@ -528,571 +882,788 @@ struct gebp_kernel }; EIGEN_DONT_INLINE - void operator()(ResScalar* res, Index resStride, const LhsScalar* blockA, const RhsScalar* blockB, Index rows, Index depth, Index cols, ResScalar alpha, - Index strideA=-1, Index strideB=-1, Index offsetA=0, Index offsetB=0, RhsScalar* unpackedB=0); + void operator()(const DataMapper& res, const LhsScalar* blockA, const RhsScalar* blockB, + Index rows, Index depth, Index cols, ResScalar alpha, + Index strideA=-1, Index strideB=-1, Index offsetA=0, Index offsetB=0); }; -template +template EIGEN_DONT_INLINE -void gebp_kernel - ::operator()(ResScalar* res, Index resStride, const LhsScalar* blockA, const RhsScalar* blockB, Index rows, Index depth, Index cols, ResScalar alpha, - Index strideA, Index strideB, Index offsetA, Index offsetB, RhsScalar* unpackedB) +void gebp_kernel + ::operator()(const DataMapper& res, const LhsScalar* blockA, const RhsScalar* blockB, + Index rows, Index depth, Index cols, ResScalar alpha, + Index strideA, Index strideB, Index offsetA, Index offsetB) { Traits traits; + SwappedTraits straits; if(strideA==-1) strideA = depth; if(strideB==-1) strideB = depth; conj_helper cj; -// conj_helper pcj; - Index packet_cols = (cols/nr) * nr; - const Index peeled_mc = (rows/mr)*mr; - // FIXME: - const Index peeled_mc2 = peeled_mc + (rows-peeled_mc >= LhsProgress ? LhsProgress : 0); - const Index peeled_kc = (depth/4)*4; - - if(unpackedB==0) - unpackedB = const_cast(blockB - strideB * nr * RhsProgress); - - // loops on each micro vertical panel of rhs (depth x nr) - for(Index j2=0; j2=4 ? (cols/4) * 4 : 0; + const Index peeled_mc3 = mr>=3*Traits::LhsProgress ? (rows/(3*LhsProgress))*(3*LhsProgress) : 0; + const Index peeled_mc2 = mr>=2*Traits::LhsProgress ? peeled_mc3+((rows-peeled_mc3)/(2*LhsProgress))*(2*LhsProgress) : 0; + const Index peeled_mc1 = mr>=1*Traits::LhsProgress ? (rows/(1*LhsProgress))*(1*LhsProgress) : 0; + enum { pk = 8 }; // NOTE Such a large peeling factor is important for large matrices (~ +5% when >1000 on Haswell) + const Index peeled_kc = depth & ~(pk-1); + const Index prefetch_res_offset = 32/sizeof(ResScalar); +// const Index depth2 = depth & ~1; + + //---------- Process 3 * LhsProgress rows at once ---------- + // This corresponds to 3*LhsProgress x nr register blocks. + // Usually, make sense only with FMA + if(mr>=3*Traits::LhsProgress) { - traits.unpackRhs(depth*nr,&blockB[j2*strideB+offsetB*nr],unpackedB); - - // loops on each largest micro horizontal panel of lhs (mr x depth) - // => we select a mr x nr micro block of res which is entirely - // stored into mr/packet_size x nr registers. - for(Index i=0; i(1,( (l1 - sizeof(ResScalar)*mr*nr - depth*nr*sizeof(RhsScalar)) / (depth * sizeof(LhsScalar) * 3*LhsProgress) )); + for(Index i1=0; i1(alpha); - R0 = ploadu(r0); - R1 = ploadu(r1); - R2 = ploadu(r2); - R3 = ploadu(r3); - R4 = ploadu(r0 + ResPacketSize); - R5 = ploadu(r1 + ResPacketSize); - R6 = ploadu(r2 + ResPacketSize); + R0 = r0.loadPacket(0 * Traits::ResPacketSize); + R1 = r0.loadPacket(1 * Traits::ResPacketSize); + R2 = r0.loadPacket(2 * Traits::ResPacketSize); traits.acc(C0, alphav, R0); - pstoreu(r0, R0); - R0 = ploadu(r3 + ResPacketSize); - - traits.acc(C1, alphav, R1); - traits.acc(C2, alphav, R2); - traits.acc(C3, alphav, R3); - traits.acc(C4, alphav, R4); - traits.acc(C5, alphav, R5); - traits.acc(C6, alphav, R6); - traits.acc(C7, alphav, R0); - - pstoreu(r1, R1); - pstoreu(r2, R2); - pstoreu(r3, R3); - pstoreu(r0 + ResPacketSize, R4); - pstoreu(r1 + ResPacketSize, R5); - pstoreu(r2 + ResPacketSize, R6); - pstoreu(r3 + ResPacketSize, R0); + traits.acc(C4, alphav, R1); + traits.acc(C8, alphav, R2); + r0.storePacket(0 * Traits::ResPacketSize, R0); + r0.storePacket(1 * Traits::ResPacketSize, R1); + r0.storePacket(2 * Traits::ResPacketSize, R2); + + R0 = r1.loadPacket(0 * Traits::ResPacketSize); + R1 = r1.loadPacket(1 * Traits::ResPacketSize); + R2 = r1.loadPacket(2 * Traits::ResPacketSize); + traits.acc(C1, alphav, R0); + traits.acc(C5, alphav, R1); + traits.acc(C9, alphav, R2); + r1.storePacket(0 * Traits::ResPacketSize, R0); + r1.storePacket(1 * Traits::ResPacketSize, R1); + r1.storePacket(2 * Traits::ResPacketSize, R2); + + R0 = r2.loadPacket(0 * Traits::ResPacketSize); + R1 = r2.loadPacket(1 * Traits::ResPacketSize); + R2 = r2.loadPacket(2 * Traits::ResPacketSize); + traits.acc(C2, alphav, R0); + traits.acc(C6, alphav, R1); + traits.acc(C10, alphav, R2); + r2.storePacket(0 * Traits::ResPacketSize, R0); + r2.storePacket(1 * Traits::ResPacketSize, R1); + r2.storePacket(2 * Traits::ResPacketSize, R2); + + R0 = r3.loadPacket(0 * Traits::ResPacketSize); + R1 = r3.loadPacket(1 * Traits::ResPacketSize); + R2 = r3.loadPacket(2 * Traits::ResPacketSize); + traits.acc(C3, alphav, R0); + traits.acc(C7, alphav, R1); + traits.acc(C11, alphav, R2); + r3.storePacket(0 * Traits::ResPacketSize, R0); + r3.storePacket(1 * Traits::ResPacketSize, R1); + r3.storePacket(2 * Traits::ResPacketSize, R2); + } } - else + + // Deal with remaining columns of the rhs + for(Index j2=packet_cols4; j2(alpha); - R0 = ploadu(r0); - R1 = ploadu(r1); - R4 = ploadu(r0 + ResPacketSize); + R0 = r0.loadPacket(0 * Traits::ResPacketSize); + R1 = r0.loadPacket(1 * Traits::ResPacketSize); + R2 = r0.loadPacket(2 * Traits::ResPacketSize); traits.acc(C0, alphav, R0); - pstoreu(r0, R0); - R0 = ploadu(r1 + ResPacketSize); - traits.acc(C1, alphav, R1); - traits.acc(C4, alphav, R4); - traits.acc(C5, alphav, R0); - pstoreu(r1, R1); - pstoreu(r0 + ResPacketSize, R4); - pstoreu(r1 + ResPacketSize, R0); + traits.acc(C4, alphav, R1); + traits.acc(C8, alphav, R2); + r0.storePacket(0 * Traits::ResPacketSize, R0); + r0.storePacket(1 * Traits::ResPacketSize, R1); + r0.storePacket(2 * Traits::ResPacketSize, R2); + } } - } - - if(rows-peeled_mc>=LhsProgress) + } + + //---------- Process 2 * LhsProgress rows at once ---------- + if(mr>=2*Traits::LhsProgress) + { + const Index l1 = defaultL1CacheSize; // in Bytes, TODO, l1 should be passed to this function. + // The max(1, ...) here is needed because we may be using blocking params larger than what our known l1 cache size + // suggests we should be using: either because our known l1 cache size is inaccurate (e.g. on Android, we can only guess), + // or because we are testing specific blocking sizes. + Index actual_panel_rows = (2*LhsProgress) * std::max(1,( (l1 - sizeof(ResScalar)*mr*nr - depth*nr*sizeof(RhsScalar)) / (depth * sizeof(LhsScalar) * 2*LhsProgress) )); + + for(Index i1=peeled_mc3; i1(alpha); - traits.madd(A0,B_0,C0,B_0); - traits.madd(A0,B1,C1,B1); - traits.madd(A0,B2,C2,B2); - traits.madd(A0,B3,C3,B3); + R0 = r0.loadPacket(0 * Traits::ResPacketSize); + R1 = r0.loadPacket(1 * Traits::ResPacketSize); + R2 = r1.loadPacket(0 * Traits::ResPacketSize); + R3 = r1.loadPacket(1 * Traits::ResPacketSize); + traits.acc(C0, alphav, R0); + traits.acc(C4, alphav, R1); + traits.acc(C1, alphav, R2); + traits.acc(C5, alphav, R3); + r0.storePacket(0 * Traits::ResPacketSize, R0); + r0.storePacket(1 * Traits::ResPacketSize, R1); + r1.storePacket(0 * Traits::ResPacketSize, R2); + r1.storePacket(1 * Traits::ResPacketSize, R3); + + R0 = r2.loadPacket(0 * Traits::ResPacketSize); + R1 = r2.loadPacket(1 * Traits::ResPacketSize); + R2 = r3.loadPacket(0 * Traits::ResPacketSize); + R3 = r3.loadPacket(1 * Traits::ResPacketSize); + traits.acc(C2, alphav, R0); + traits.acc(C6, alphav, R1); + traits.acc(C3, alphav, R2); + traits.acc(C7, alphav, R3); + r2.storePacket(0 * Traits::ResPacketSize, R0); + r2.storePacket(1 * Traits::ResPacketSize, R1); + r3.storePacket(0 * Traits::ResPacketSize, R2); + r3.storePacket(1 * Traits::ResPacketSize, R3); } - - blB += nr*RhsProgress; - blA += LhsProgress; } + + // Deal with remaining columns of the rhs + for(Index j2=packet_cols4; j2(alpha); - - ResScalar* r0 = &res[(j2+0)*resStride + i]; - ResScalar* r1 = r0 + resStride; - ResScalar* r2 = r1 + resStride; - ResScalar* r3 = r2 + resStride; + // gets res block as register + AccPacket C0, C4; + traits.initAcc(C0); + traits.initAcc(C4); - R0 = ploadu(r0); - R1 = ploadu(r1); - if(nr==4) R2 = ploadu(r2); - if(nr==4) R3 = ploadu(r3); + LinearMapper r0 = res.getLinearMapper(i, j2); + r0.prefetch(prefetch_res_offset); - traits.acc(C0, alphav, R0); - traits.acc(C1, alphav, R1); - if(nr==4) traits.acc(C2, alphav, R2); - if(nr==4) traits.acc(C3, alphav, R3); + // performs "inner" products + const RhsScalar* blB = &blockB[j2*strideB+offsetB]; + LhsPacket A0, A1; - pstoreu(r0, R0); - pstoreu(r1, R1); - if(nr==4) pstoreu(r2, R2); - if(nr==4) pstoreu(r3, R3); - } - for(Index i=peeled_mc2; i(alpha); - blB += nr; + R0 = r0.loadPacket(0 * Traits::ResPacketSize); + R1 = r0.loadPacket(1 * Traits::ResPacketSize); + traits.acc(C0, alphav, R0); + traits.acc(C4, alphav, R1); + r0.storePacket(0 * Traits::ResPacketSize, R0); + r0.storePacket(1 * Traits::ResPacketSize, R1); + } } - res[(j2+0)*resStride + i] += alpha*C0; - res[(j2+1)*resStride + i] += alpha*C1; - if(nr==4) res[(j2+2)*resStride + i] += alpha*C2; - if(nr==4) res[(j2+3)*resStride + i] += alpha*C3; } } - // process remaining rhs/res columns one at a time - // => do the same but with nr==1 - for(Index j2=packet_cols; j2=1*Traits::LhsProgress) { - // unpack B - traits.unpackRhs(depth, &blockB[j2*strideB+offsetB], unpackedB); - - for(Index i=0; i(alpha); - // get res block as registers - AccPacket C0, C4; - traits.initAcc(C0); - traits.initAcc(C4); + R0 = r0.loadPacket(0 * Traits::ResPacketSize); + R1 = r1.loadPacket(0 * Traits::ResPacketSize); + traits.acc(C0, alphav, R0); + traits.acc(C1, alphav, R1); + r0.storePacket(0 * Traits::ResPacketSize, R0); + r1.storePacket(0 * Traits::ResPacketSize, R1); + + R0 = r2.loadPacket(0 * Traits::ResPacketSize); + R1 = r3.loadPacket(0 * Traits::ResPacketSize); + traits.acc(C2, alphav, R0); + traits.acc(C3, alphav, R1); + r2.storePacket(0 * Traits::ResPacketSize, R0); + r3.storePacket(0 * Traits::ResPacketSize, R1); + } - const RhsScalar* blB = unpackedB; - for(Index k=0; k(alpha); + // gets res block as register + AccPacket C0; + traits.initAcc(C0); - ResScalar* r0 = &res[(j2+0)*resStride + i]; + LinearMapper r0 = res.getLinearMapper(i, j2); - R0 = ploadu(r0); - R4 = ploadu(r0+ResPacketSize); + // performs "inner" products + const RhsScalar* blB = &blockB[j2*strideB+offsetB]; + LhsPacket A0; - traits.acc(C0, alphav, R0); - traits.acc(C4, alphav, R4); + for(Index k=0; k(alpha); + R0 = r0.loadPacket(0 * Traits::ResPacketSize); + traits.acc(C0, alphav, R0); + r0.storePacket(0 * Traits::ResPacketSize, R0); + } } - if(rows-peeled_mc>=LhsProgress) + } + //---------- Process remaining rows, 1 at once ---------- + if(peeled_mc1::half SResPacketHalf; + if ((SwappedTraits::LhsProgress % 4) == 0 && + (SwappedTraits::LhsProgress <= 8) && + (SwappedTraits::LhsProgress!=8 || unpacket_traits::size==nr)) + { + SAccPacket C0, C1, C2, C3; + straits.initAcc(C0); + straits.initAcc(C1); + straits.initAcc(C2); + straits.initAcc(C3); + + const Index spk = (std::max)(1,SwappedTraits::LhsProgress/4); + const Index endk = (depth/spk)*spk; + const Index endk4 = (depth/(spk*4))*(spk*4); + + Index k=0; + for(; k=8,typename unpacket_traits::half,SResPacket>::type SResPacketHalf; + typedef typename conditional=8,typename unpacket_traits::half,SLhsPacket>::type SLhsPacketHalf; + typedef typename conditional=8,typename unpacket_traits::half,SRhsPacket>::type SRhsPacketHalf; + typedef typename conditional=8,typename unpacket_traits::half,SAccPacket>::type SAccPacketHalf; + + SResPacketHalf R = res.template gatherPacket(i, j2); + SResPacketHalf alphav = pset1(alpha); + + if(depth-endk>0) + { + // We have to handle the last row of the rhs which corresponds to a half-packet + SLhsPacketHalf a0; + SRhsPacketHalf b0; + straits.loadLhsUnaligned(blB, a0); + straits.loadRhs(blA, b0); + SAccPacketHalf c0 = predux_downto4(C0); + straits.madd(a0,b0,c0,b0); + straits.acc(c0, alphav, R); + } + else + { + straits.acc(predux_downto4(C0), alphav, R); + } + res.scatterPacket(i, j2, R); + } + else + { + SResPacket R = res.template gatherPacket(i, j2); + SResPacket alphav = pset1(alpha); + straits.acc(C0, alphav, R); + res.scatterPacket(i, j2, R); + } + } + else // scalar path + { + // get a 1 x 4 res block as registers + ResScalar C0(0), C1(0), C2(0), C3(0); + + for(Index k=0; k(alpha); - ResPacket R0 = ploadu(&res[(j2+0)*resStride + i]); - traits.acc(C0, alphav, R0); - pstoreu(&res[(j2+0)*resStride + i], R0); } - for(Index i=peeled_mc2; i -struct gemm_pack_lhs +template +struct gemm_pack_lhs { - EIGEN_DONT_INLINE void operator()(Scalar* blockA, const Scalar* EIGEN_RESTRICT _lhs, Index lhsStride, Index depth, Index rows, Index stride=0, Index offset=0); + typedef typename DataMapper::LinearMapper LinearMapper; + EIGEN_DONT_INLINE void operator()(Scalar* blockA, const DataMapper& lhs, Index depth, Index rows, Index stride=0, Index offset=0); }; -template -EIGEN_DONT_INLINE void gemm_pack_lhs - ::operator()(Scalar* blockA, const Scalar* EIGEN_RESTRICT _lhs, Index lhsStride, Index depth, Index rows, Index stride, Index offset) +template +EIGEN_DONT_INLINE void gemm_pack_lhs + ::operator()(Scalar* blockA, const DataMapper& lhs, Index depth, Index rows, Index stride, Index offset) { typedef typename packet_traits::type Packet; enum { PacketSize = packet_traits::size }; EIGEN_ASM_COMMENT("EIGEN PRODUCT PACK LHS"); - EIGEN_UNUSED_VARIABLE(stride) - EIGEN_UNUSED_VARIABLE(offset) + EIGEN_UNUSED_VARIABLE(stride); + EIGEN_UNUSED_VARIABLE(offset); eigen_assert(((!PanelMode) && stride==0 && offset==0) || (PanelMode && stride>=depth && offset<=stride)); - eigen_assert( (StorageOrder==RowMajor) || ((Pack1%PacketSize)==0 && Pack1<=4*PacketSize) ); + eigen_assert( ((Pack1%PacketSize)==0 && Pack1<=4*PacketSize) || (Pack1<=4) ); conj_if::IsComplex && Conjugate> cj; - const_blas_data_mapper lhs(_lhs,lhsStride); Index count = 0; - Index peeled_mc = (rows/Pack1)*Pack1; - for(Index i=0; i=3*PacketSize ? (rows/(3*PacketSize))*(3*PacketSize) : 0; + const Index peeled_mc2 = Pack1>=2*PacketSize ? peeled_mc3+((rows-peeled_mc3)/(2*PacketSize))*(2*PacketSize) : 0; + const Index peeled_mc1 = Pack1>=1*PacketSize ? (rows/(1*PacketSize))*(1*PacketSize) : 0; + const Index peeled_mc0 = Pack2>=1*PacketSize ? peeled_mc1 + : Pack2>1 ? (rows/Pack2)*Pack2 : 0; + + Index i=0; + + // Pack 3 packets + if(Pack1>=3*PacketSize) { - if(PanelMode) count += Pack1 * offset; + for(; i=2*PacketSize) + { + for(; i=1*PacketSize) A = ploadu(&lhs(i+0*PacketSize, k)); - if(Pack1>=2*PacketSize) B = ploadu(&lhs(i+1*PacketSize, k)); - if(Pack1>=3*PacketSize) C = ploadu(&lhs(i+2*PacketSize, k)); - if(Pack1>=4*PacketSize) D = ploadu(&lhs(i+3*PacketSize, k)); - if(Pack1>=1*PacketSize) { pstore(blockA+count, cj.pconj(A)); count+=PacketSize; } - if(Pack1>=2*PacketSize) { pstore(blockA+count, cj.pconj(B)); count+=PacketSize; } - if(Pack1>=3*PacketSize) { pstore(blockA+count, cj.pconj(C)); count+=PacketSize; } - if(Pack1>=4*PacketSize) { pstore(blockA+count, cj.pconj(D)); count+=PacketSize; } + Packet A, B; + A = lhs.loadPacket(i+0*PacketSize, k); + B = lhs.loadPacket(i+1*PacketSize, k); + pstore(blockA+count, cj.pconj(A)); count+=PacketSize; + pstore(blockA+count, cj.pconj(B)); count+=PacketSize; } + if(PanelMode) count += (2*PacketSize) * (stride-offset-depth); } - else + } + // Pack 1 packets + if(Pack1>=1*PacketSize) + { + for(; i1) + { + for(; i +struct gemm_pack_lhs +{ + typedef typename DataMapper::LinearMapper LinearMapper; + EIGEN_DONT_INLINE void operator()(Scalar* blockA, const DataMapper& lhs, Index depth, Index rows, Index stride=0, Index offset=0); +}; + +template +EIGEN_DONT_INLINE void gemm_pack_lhs + ::operator()(Scalar* blockA, const DataMapper& lhs, Index depth, Index rows, Index stride, Index offset) +{ + typedef typename packet_traits::type Packet; + enum { PacketSize = packet_traits::size }; + + EIGEN_ASM_COMMENT("EIGEN PRODUCT PACK LHS"); + EIGEN_UNUSED_VARIABLE(stride); + EIGEN_UNUSED_VARIABLE(offset); + eigen_assert(((!PanelMode) && stride==0 && offset==0) || (PanelMode && stride>=depth && offset<=stride)); + conj_if::IsComplex && Conjugate> cj; + Index count = 0; + +// const Index peeled_mc3 = Pack1>=3*PacketSize ? (rows/(3*PacketSize))*(3*PacketSize) : 0; +// const Index peeled_mc2 = Pack1>=2*PacketSize ? peeled_mc3+((rows-peeled_mc3)/(2*PacketSize))*(2*PacketSize) : 0; +// const Index peeled_mc1 = Pack1>=1*PacketSize ? (rows/(1*PacketSize))*(1*PacketSize) : 0; + + int pack = Pack1; + Index i = 0; + while(pack>0) + { + Index remaining_rows = rows-i; + Index peeled_mc = i+(remaining_rows/pack)*pack; + for(; i=PacketSize) + { + for(; k kernel; + for (int p = 0; p < PacketSize; ++p) kernel.packet[p] = lhs.loadPacket(i+p+m, k); + ptranspose(kernel); + for (int p = 0; p < PacketSize; ++p) pstore(blockA+count+m+(pack)*p, cj.pconj(kernel.packet[p])); + } + count += PacketSize*pack; + } + } + for(; k=Pack2) - { - if(PanelMode) count += Pack2*offset; - for(Index k=0; k -struct gemm_pack_rhs +template +struct gemm_pack_rhs { typedef typename packet_traits::type Packet; + typedef typename DataMapper::LinearMapper LinearMapper; enum { PacketSize = packet_traits::size }; - EIGEN_DONT_INLINE void operator()(Scalar* blockB, const Scalar* rhs, Index rhsStride, Index depth, Index cols, Index stride=0, Index offset=0); + EIGEN_DONT_INLINE void operator()(Scalar* blockB, const DataMapper& rhs, Index depth, Index cols, Index stride=0, Index offset=0); }; -template -EIGEN_DONT_INLINE void gemm_pack_rhs - ::operator()(Scalar* blockB, const Scalar* rhs, Index rhsStride, Index depth, Index cols, Index stride, Index offset) +template +EIGEN_DONT_INLINE void gemm_pack_rhs + ::operator()(Scalar* blockB, const DataMapper& rhs, Index depth, Index cols, Index stride, Index offset) { EIGEN_ASM_COMMENT("EIGEN PRODUCT PACK RHS COLMAJOR"); - EIGEN_UNUSED_VARIABLE(stride) - EIGEN_UNUSED_VARIABLE(offset) + EIGEN_UNUSED_VARIABLE(stride); + EIGEN_UNUSED_VARIABLE(offset); eigen_assert(((!PanelMode) && stride==0 && offset==0) || (PanelMode && stride>=depth && offset<=stride)); conj_if::IsComplex && Conjugate> cj; - Index packet_cols = (cols/nr) * nr; + Index packet_cols8 = nr>=8 ? (cols/8) * 8 : 0; + Index packet_cols4 = nr>=4 ? (cols/4) * 4 : 0; Index count = 0; - for(Index j2=0; j2=8) +// { +// for(Index j2=0; j2 kernel; +// for (int p = 0; p < PacketSize; ++p) { +// kernel.packet[p] = ploadu(&rhs[(j2+p)*rhsStride+k]); +// } +// ptranspose(kernel); +// for (int p = 0; p < PacketSize; ++p) { +// pstoreu(blockB+count, cj.pconj(kernel.packet[p])); +// count+=PacketSize; +// } +// } +// } +// for(; k=4) { - // skip what we have before - if(PanelMode) count += nr * offset; - const Scalar* b0 = &rhs[(j2+0)*rhsStride]; - const Scalar* b1 = &rhs[(j2+1)*rhsStride]; - const Scalar* b2 = &rhs[(j2+2)*rhsStride]; - const Scalar* b3 = &rhs[(j2+3)*rhsStride]; - for(Index k=0; k kernel; + kernel.packet[0] = dm0.loadPacket(k); + kernel.packet[1%PacketSize] = dm1.loadPacket(k); + kernel.packet[2%PacketSize] = dm2.loadPacket(k); + kernel.packet[3%PacketSize] = dm3.loadPacket(k); + ptranspose(kernel); + pstoreu(blockB+count+0*PacketSize, cj.pconj(kernel.packet[0])); + pstoreu(blockB+count+1*PacketSize, cj.pconj(kernel.packet[1%PacketSize])); + pstoreu(blockB+count+2*PacketSize, cj.pconj(kernel.packet[2%PacketSize])); + pstoreu(blockB+count+3*PacketSize, cj.pconj(kernel.packet[3%PacketSize])); + count+=4*PacketSize; + } + } + for(; k -struct gemm_pack_rhs +template +struct gemm_pack_rhs { + typedef typename packet_traits::type Packet; + typedef typename DataMapper::LinearMapper LinearMapper; enum { PacketSize = packet_traits::size }; - EIGEN_DONT_INLINE void operator()(Scalar* blockB, const Scalar* rhs, Index rhsStride, Index depth, Index cols, Index stride=0, Index offset=0); + EIGEN_DONT_INLINE void operator()(Scalar* blockB, const DataMapper& rhs, Index depth, Index cols, Index stride=0, Index offset=0); }; -template -EIGEN_DONT_INLINE void gemm_pack_rhs - ::operator()(Scalar* blockB, const Scalar* rhs, Index rhsStride, Index depth, Index cols, Index stride, Index offset) +template +EIGEN_DONT_INLINE void gemm_pack_rhs + ::operator()(Scalar* blockB, const DataMapper& rhs, Index depth, Index cols, Index stride, Index offset) { EIGEN_ASM_COMMENT("EIGEN PRODUCT PACK RHS ROWMAJOR"); - EIGEN_UNUSED_VARIABLE(stride) - EIGEN_UNUSED_VARIABLE(offset) + EIGEN_UNUSED_VARIABLE(stride); + EIGEN_UNUSED_VARIABLE(offset); eigen_assert(((!PanelMode) && stride==0 && offset==0) || (PanelMode && stride>=depth && offset<=stride)); conj_if::IsComplex && Conjugate> cj; - Index packet_cols = (cols/nr) * nr; + Index packet_cols8 = nr>=8 ? (cols/8) * 8 : 0; + Index packet_cols4 = nr>=4 ? (cols/4) * 4 : 0; Index count = 0; - for(Index j2=0; j2=8) +// { +// for(Index j2=0; j2(&rhs[k*rhsStride + j2]); +// pstoreu(blockB+count, cj.pconj(A)); +// } else if (PacketSize==4) { +// Packet A = ploadu(&rhs[k*rhsStride + j2]); +// Packet B = ploadu(&rhs[k*rhsStride + j2 + PacketSize]); +// pstoreu(blockB+count, cj.pconj(A)); +// pstoreu(blockB+count+PacketSize, cj.pconj(B)); +// } else { +// const Scalar* b0 = &rhs[k*rhsStride + j2]; +// blockB[count+0] = cj(b0[0]); +// blockB[count+1] = cj(b0[1]); +// blockB[count+2] = cj(b0[2]); +// blockB[count+3] = cj(b0[3]); +// blockB[count+4] = cj(b0[4]); +// blockB[count+5] = cj(b0[5]); +// blockB[count+6] = cj(b0[6]); +// blockB[count+7] = cj(b0[7]); +// } +// count += 8; +// } +// // skip what we have after +// if(PanelMode) count += 8 * (stride-offset-depth); +// } +// } + if(nr>=4) { - // skip what we have before - if(PanelMode) count += nr * offset; - for(Index k=0; k struct general_matrix_matrix_product { - typedef typename scalar_product_traits::ReturnType ResScalar; + typedef gebp_traits Traits; + + typedef typename ScalarBinaryOpTraits::ReturnType ResScalar; static EIGEN_STRONG_INLINE void run( Index rows, Index cols, Index depth, const LhsScalar* lhs, Index lhsStride, @@ -51,42 +53,44 @@ template< struct general_matrix_matrix_product { -typedef typename scalar_product_traits::ReturnType ResScalar; +typedef gebp_traits Traits; + +typedef typename ScalarBinaryOpTraits::ReturnType ResScalar; static void run(Index rows, Index cols, Index depth, const LhsScalar* _lhs, Index lhsStride, const RhsScalar* _rhs, Index rhsStride, - ResScalar* res, Index resStride, + ResScalar* _res, Index resStride, ResScalar alpha, level3_blocking& blocking, GemmParallelInfo* info = 0) { - const_blas_data_mapper lhs(_lhs,lhsStride); - const_blas_data_mapper rhs(_rhs,rhsStride); - - typedef gebp_traits Traits; + typedef const_blas_data_mapper LhsMapper; + typedef const_blas_data_mapper RhsMapper; + typedef blas_data_mapper ResMapper; + LhsMapper lhs(_lhs,lhsStride); + RhsMapper rhs(_rhs,rhsStride); + ResMapper res(_res, resStride); Index kc = blocking.kc(); // cache block size along the K direction Index mc = (std::min)(rows,blocking.mc()); // cache block size along the M direction - //Index nc = blocking.nc(); // cache block size along the N direction + Index nc = (std::min)(cols,blocking.nc()); // cache block size along the N direction - gemm_pack_lhs pack_lhs; - gemm_pack_rhs pack_rhs; - gebp_kernel gebp; + gemm_pack_lhs pack_lhs; + gemm_pack_rhs pack_rhs; + gebp_kernel gebp; #ifdef EIGEN_HAS_OPENMP if(info) { // this is the parallel version! - Index tid = omp_get_thread_num(); - Index threads = omp_get_num_threads(); - - std::size_t sizeA = kc*mc; - std::size_t sizeW = kc*Traits::WorkSpaceFactor; - ei_declare_aligned_stack_constructed_variable(LhsScalar, blockA, sizeA, 0); - ei_declare_aligned_stack_constructed_variable(RhsScalar, w, sizeW, 0); - - RhsScalar* blockB = blocking.blockB(); - eigen_internal_assert(blockB!=0); + int tid = omp_get_thread_num(); + int threads = omp_get_num_threads(); + + LhsScalar* blockA = blocking.blockA(); + eigen_internal_assert(blockA!=0); + + std::size_t sizeB = kc*nc; + ei_declare_aligned_stack_constructed_variable(RhsScalar, blockB, sizeB, 0); // For each horizontal panel of the rhs, and corresponding vertical panel of the lhs... for(Index k=0; k rows of B', and cols of the A' // In order to reduce the chance that a thread has to wait for the other, - // let's start by packing A'. - pack_lhs(blockA, &lhs(0,k), lhsStride, actual_kc, mc); + // let's start by packing B'. + pack_rhs(blockB, rhs.getSubMapper(k,0), actual_kc, nc); - // Pack B_k to B' in a parallel fashion: - // each thread packs the sub block B_k,j to B'_j where j is the thread id. + // Pack A_k to A' in a parallel fashion: + // each thread packs the sub block A_k,i to A'_i where i is the thread id. - // However, before copying to B'_j, we have to make sure that no other thread is still using it, + // However, before copying to A'_i, we have to make sure that no other thread is still using it, // i.e., we test that info[tid].users equals 0. // Then, we set info[tid].users to the number of threads to mark that all other threads are going to use it. while(info[tid].users!=0) {} info[tid].users += threads; - pack_rhs(blockB+info[tid].rhs_start*actual_kc, &rhs(k,info[tid].rhs_start), rhsStride, actual_kc, info[tid].rhs_length); + pack_lhs(blockA+info[tid].lhs_start*actual_kc, lhs.getSubMapper(info[tid].lhs_start,k), actual_kc, info[tid].lhs_length); - // Notify the other threads that the part B'_j is ready to go. + // Notify the other threads that the part A'_i is ready to go. info[tid].sync = k; - // Computes C_i += A' * B' per B'_j - for(Index shift=0; shift0) - while(info[j].sync!=k) {} + if (shift>0) { + while(info[i].sync!=k) { + } + } - gebp(res+info[j].rhs_start*resStride, resStride, blockA, blockB+info[j].rhs_start*actual_kc, mc, actual_kc, info[j].rhs_length, alpha, -1,-1,0,0, w); + gebp(res.getSubMapper(info[i].lhs_start, 0), blockA+info[i].lhs_start*actual_kc, blockB, info[i].lhs_length, actual_kc, nc, alpha); } - // Then keep going as usual with the remaining A' - for(Index i=mc; i Pack rhs's panel into a sequential chunk of memory (L2 caching) - // Note that this panel will be read as many times as the number of blocks in the lhs's - // vertical panel which is, in practice, a very low number. - pack_rhs(blockB, &rhs(k2,0), rhsStride, actual_kc, cols); - - // For each mc x kc block of the lhs's vertical panel... - // (==GEPP_VAR1) - for(Index i2=0; i2 Pack lhs's panel into a sequential chunk of memory (L2/L3 caching) + // Note that this panel will be read as many times as the number of blocks in the rhs's + // horizontal panel which is, in practice, a very low number. + pack_lhs(blockA, lhs.getSubMapper(i2,k2), actual_kc, actual_mc); + + // For each kc x nc block of the rhs's horizontal panel... + for(Index j2=0; j2 for "large" GEMM, i.e., +* Specialization of generic_product_impl for "large" GEMM, i.e., * implementation of the high level wrapper to general_matrix_matrix_product **********************************************************************************/ -template -struct traits > - : traits, Lhs, Rhs> > -{}; - template struct gemm_functor { - gemm_functor(const Lhs& lhs, const Rhs& rhs, Dest& dest, const Scalar& actualAlpha, - BlockingType& blocking) + gemm_functor(const Lhs& lhs, const Rhs& rhs, Dest& dest, const Scalar& actualAlpha, BlockingType& blocking) : m_lhs(lhs), m_rhs(rhs), m_dest(dest), m_actualAlpha(actualAlpha), m_blocking(blocking) {} - void initParallelSession() const + void initParallelSession(Index num_threads) const { - m_blocking.allocateB(); + m_blocking.initParallel(m_lhs.rows(), m_rhs.cols(), m_lhs.cols(), num_threads); + m_blocking.allocateA(); } void operator() (Index row, Index rows, Index col=0, Index cols=-1, GemmParallelInfo* info=0) const @@ -219,12 +224,14 @@ struct gemm_functor cols = m_rhs.cols(); Gemm::run(rows, cols, m_lhs.cols(), - /*(const Scalar*)*/&m_lhs.coeffRef(row,0), m_lhs.outerStride(), - /*(const Scalar*)*/&m_rhs.coeffRef(0,col), m_rhs.outerStride(), + &m_lhs.coeffRef(row,0), m_lhs.outerStride(), + &m_rhs.coeffRef(0,col), m_rhs.outerStride(), (Scalar*)&(m_dest.coeffRef(row,col)), m_dest.outerStride(), m_actualAlpha, m_blocking, info); } + typedef typename Gemm::Traits Traits; + protected: const Lhs& m_lhs; const Rhs& m_rhs; @@ -245,29 +252,27 @@ class level3_blocking protected: LhsScalar* m_blockA; RhsScalar* m_blockB; - RhsScalar* m_blockW; - DenseIndex m_mc; - DenseIndex m_nc; - DenseIndex m_kc; + Index m_mc; + Index m_nc; + Index m_kc; public: level3_blocking() - : m_blockA(0), m_blockB(0), m_blockW(0), m_mc(0), m_nc(0), m_kc(0) + : m_blockA(0), m_blockB(0), m_mc(0), m_nc(0), m_kc(0) {} - inline DenseIndex mc() const { return m_mc; } - inline DenseIndex nc() const { return m_nc; } - inline DenseIndex kc() const { return m_kc; } + inline Index mc() const { return m_mc; } + inline Index nc() const { return m_nc; } + inline Index kc() const { return m_kc; } inline LhsScalar* blockA() { return m_blockA; } inline RhsScalar* blockB() { return m_blockB; } - inline RhsScalar* blockW() { return m_blockW; } }; template -class gemm_blocking_space +class gemm_blocking_space : public level3_blocking< typename conditional::type, typename conditional::type> @@ -282,29 +287,38 @@ class gemm_blocking_space Traits; enum { SizeA = ActualRows * MaxDepth, - SizeB = ActualCols * MaxDepth, - SizeW = MaxDepth * Traits::WorkSpaceFactor + SizeB = ActualCols * MaxDepth }; - EIGEN_ALIGN16 LhsScalar m_staticA[SizeA]; - EIGEN_ALIGN16 RhsScalar m_staticB[SizeB]; - EIGEN_ALIGN16 RhsScalar m_staticW[SizeW]; +#if EIGEN_MAX_STATIC_ALIGN_BYTES >= EIGEN_DEFAULT_ALIGN_BYTES + EIGEN_ALIGN_MAX LhsScalar m_staticA[SizeA]; + EIGEN_ALIGN_MAX RhsScalar m_staticB[SizeB]; +#else + EIGEN_ALIGN_MAX char m_staticA[SizeA * sizeof(LhsScalar) + EIGEN_DEFAULT_ALIGN_BYTES-1]; + EIGEN_ALIGN_MAX char m_staticB[SizeB * sizeof(RhsScalar) + EIGEN_DEFAULT_ALIGN_BYTES-1]; +#endif public: - gemm_blocking_space(DenseIndex /*rows*/, DenseIndex /*cols*/, DenseIndex /*depth*/) + gemm_blocking_space(Index /*rows*/, Index /*cols*/, Index /*depth*/, Index /*num_threads*/, bool /*full_rows = false*/) { this->m_mc = ActualRows; this->m_nc = ActualCols; this->m_kc = MaxDepth; +#if EIGEN_MAX_STATIC_ALIGN_BYTES >= EIGEN_DEFAULT_ALIGN_BYTES this->m_blockA = m_staticA; this->m_blockB = m_staticB; - this->m_blockW = m_staticW; +#else + this->m_blockA = reinterpret_cast((internal::UIntPtr(m_staticA) + (EIGEN_DEFAULT_ALIGN_BYTES-1)) & ~std::size_t(EIGEN_DEFAULT_ALIGN_BYTES-1)); + this->m_blockB = reinterpret_cast((internal::UIntPtr(m_staticB) + (EIGEN_DEFAULT_ALIGN_BYTES-1)) & ~std::size_t(EIGEN_DEFAULT_ALIGN_BYTES-1)); +#endif } + void initParallel(Index, Index, Index, Index) + {} + inline void allocateA() {} inline void allocateB() {} - inline void allocateW() {} inline void allocateAll() {} }; @@ -321,22 +335,42 @@ class gemm_blocking_space::type RhsScalar; typedef gebp_traits Traits; - DenseIndex m_sizeA; - DenseIndex m_sizeB; - DenseIndex m_sizeW; + Index m_sizeA; + Index m_sizeB; public: - gemm_blocking_space(DenseIndex rows, DenseIndex cols, DenseIndex depth) + gemm_blocking_space(Index rows, Index cols, Index depth, Index num_threads, bool l3_blocking) { this->m_mc = Transpose ? cols : rows; this->m_nc = Transpose ? rows : cols; this->m_kc = depth; - computeProductBlockingSizes(this->m_kc, this->m_mc, this->m_nc); + if(l3_blocking) + { + computeProductBlockingSizes(this->m_kc, this->m_mc, this->m_nc, num_threads); + } + else // no l3 blocking + { + Index n = this->m_nc; + computeProductBlockingSizes(this->m_kc, this->m_mc, n, num_threads); + } + + m_sizeA = this->m_mc * this->m_kc; + m_sizeB = this->m_kc * this->m_nc; + } + + void initParallel(Index rows, Index cols, Index depth, Index num_threads) + { + this->m_mc = Transpose ? cols : rows; + this->m_nc = Transpose ? rows : cols; + this->m_kc = depth; + + eigen_internal_assert(this->m_blockA==0 && this->m_blockB==0); + Index m = this->m_mc; + computeProductBlockingSizes(this->m_kc, m, this->m_nc, num_threads); m_sizeA = this->m_mc * this->m_kc; m_sizeB = this->m_kc * this->m_nc; - m_sizeW = this->m_kc*Traits::WorkSpaceFactor; } void allocateA() @@ -351,77 +385,108 @@ class gemm_blocking_spacem_blockB = aligned_new(m_sizeB); } - void allocateW() - { - if(this->m_blockW==0) - this->m_blockW = aligned_new(m_sizeW); - } - void allocateAll() { allocateA(); allocateB(); - allocateW(); } ~gemm_blocking_space() { aligned_delete(this->m_blockA, m_sizeA); aligned_delete(this->m_blockB, m_sizeB); - aligned_delete(this->m_blockW, m_sizeW); } }; } // end namespace internal +namespace internal { + template -class GeneralProduct - : public ProductBase, Lhs, Rhs> +struct generic_product_impl + : generic_product_impl_base > { - enum { - MaxDepthAtCompileTime = EIGEN_SIZE_MIN_PREFER_FIXED(Lhs::MaxColsAtCompileTime,Rhs::MaxRowsAtCompileTime) - }; - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) - - typedef typename Lhs::Scalar LhsScalar; - typedef typename Rhs::Scalar RhsScalar; - typedef Scalar ResScalar; + typedef typename Product::Scalar Scalar; + typedef typename Lhs::Scalar LhsScalar; + typedef typename Rhs::Scalar RhsScalar; - GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - { - typedef internal::scalar_product_op BinOp; - EIGEN_CHECK_BINARY_COMPATIBILIY(BinOp,LhsScalar,RhsScalar); - } + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef typename internal::remove_all::type ActualLhsTypeCleaned; - template void scaleAndAddTo(Dest& dst, const Scalar& alpha) const - { - eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + typedef typename internal::remove_all::type ActualRhsTypeCleaned; - typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(m_lhs); - typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(m_rhs); + enum { + MaxDepthAtCompileTime = EIGEN_SIZE_MIN_PREFER_FIXED(Lhs::MaxColsAtCompileTime,Rhs::MaxRowsAtCompileTime) + }; - Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(m_lhs) - * RhsBlasTraits::extractScalarFactor(m_rhs); + typedef generic_product_impl lazyproduct; - typedef internal::gemm_blocking_space<(Dest::Flags&RowMajorBit) ? RowMajor : ColMajor,LhsScalar,RhsScalar, - Dest::MaxRowsAtCompileTime,Dest::MaxColsAtCompileTime,MaxDepthAtCompileTime> BlockingType; + template + static void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + if((rhs.rows()+dst.rows()+dst.cols())<20 && rhs.rows()>0) + lazyproduct::evalTo(dst, lhs, rhs); + else + { + dst.setZero(); + scaleAndAddTo(dst, lhs, rhs, Scalar(1)); + } + } - typedef internal::gemm_functor< - Scalar, Index, - internal::general_matrix_matrix_product< - Index, - LhsScalar, (_ActualLhsType::Flags&RowMajorBit) ? RowMajor : ColMajor, bool(LhsBlasTraits::NeedToConjugate), - RhsScalar, (_ActualRhsType::Flags&RowMajorBit) ? RowMajor : ColMajor, bool(RhsBlasTraits::NeedToConjugate), - (Dest::Flags&RowMajorBit) ? RowMajor : ColMajor>, - _ActualLhsType, _ActualRhsType, Dest, BlockingType> GemmFunctor; + template + static void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + if((rhs.rows()+dst.rows()+dst.cols())<20 && rhs.rows()>0) + lazyproduct::addTo(dst, lhs, rhs); + else + scaleAndAddTo(dst,lhs, rhs, Scalar(1)); + } - BlockingType blocking(dst.rows(), dst.cols(), lhs.cols()); + template + static void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + if((rhs.rows()+dst.rows()+dst.cols())<20 && rhs.rows()>0) + lazyproduct::subTo(dst, lhs, rhs); + else + scaleAndAddTo(dst, lhs, rhs, Scalar(-1)); + } - internal::parallelize_gemm<(Dest::MaxRowsAtCompileTime>32 || Dest::MaxRowsAtCompileTime==Dynamic)>(GemmFunctor(lhs, rhs, dst, actualAlpha, blocking), this->rows(), this->cols(), Dest::Flags&RowMajorBit); - } + template + static void scaleAndAddTo(Dest& dst, const Lhs& a_lhs, const Rhs& a_rhs, const Scalar& alpha) + { + eigen_assert(dst.rows()==a_lhs.rows() && dst.cols()==a_rhs.cols()); + if(a_lhs.cols()==0 || a_lhs.rows()==0 || a_rhs.cols()==0) + return; + + typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(a_lhs); + typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(a_rhs); + + Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(a_lhs) + * RhsBlasTraits::extractScalarFactor(a_rhs); + + typedef internal::gemm_blocking_space<(Dest::Flags&RowMajorBit) ? RowMajor : ColMajor,LhsScalar,RhsScalar, + Dest::MaxRowsAtCompileTime,Dest::MaxColsAtCompileTime,MaxDepthAtCompileTime> BlockingType; + + typedef internal::gemm_functor< + Scalar, Index, + internal::general_matrix_matrix_product< + Index, + LhsScalar, (ActualLhsTypeCleaned::Flags&RowMajorBit) ? RowMajor : ColMajor, bool(LhsBlasTraits::NeedToConjugate), + RhsScalar, (ActualRhsTypeCleaned::Flags&RowMajorBit) ? RowMajor : ColMajor, bool(RhsBlasTraits::NeedToConjugate), + (Dest::Flags&RowMajorBit) ? RowMajor : ColMajor>, + ActualLhsTypeCleaned, ActualRhsTypeCleaned, Dest, BlockingType> GemmFunctor; + + BlockingType blocking(dst.rows(), dst.cols(), lhs.cols(), 1, true); + internal::parallelize_gemm<(Dest::MaxRowsAtCompileTime>32 || Dest::MaxRowsAtCompileTime==Dynamic)> + (GemmFunctor(lhs, rhs, dst, actualAlpha, blocking), a_lhs.rows(), a_rhs.cols(), a_lhs.cols(), Dest::Flags&RowMajorBit); + } }; +} // end namespace internal + } // end namespace Eigen #endif // EIGEN_GENERAL_MATRIX_MATRIX_H diff --git a/libs/eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h b/libs/eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h index 5c3763909..e844e37d1 100644 --- a/libs/eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h +++ b/libs/eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h @@ -20,7 +20,7 @@ namespace internal { /********************************************************************** * This file implements a general A * B product while * evaluating only one triangular part of the product. -* This is more general version of self adjoint product (C += A A^T) +* This is a more general version of self adjoint product (C += A A^T) * as the level 3 SYRK Blas routine. **********************************************************************/ @@ -40,15 +40,16 @@ template struct general_matrix_matrix_triangular_product { - typedef typename scalar_product_traits::ReturnType ResScalar; + typedef typename ScalarBinaryOpTraits::ReturnType ResScalar; static EIGEN_STRONG_INLINE void run(Index size, Index depth,const LhsScalar* lhs, Index lhsStride, - const RhsScalar* rhs, Index rhsStride, ResScalar* res, Index resStride, const ResScalar& alpha) + const RhsScalar* rhs, Index rhsStride, ResScalar* res, Index resStride, + const ResScalar& alpha, level3_blocking& blocking) { general_matrix_matrix_triangular_product - ::run(size,depth,rhs,rhsStride,lhs,lhsStride,res,resStride,alpha); + ::run(size,depth,rhs,rhsStride,lhs,lhsStride,res,resStride,alpha,blocking); } }; @@ -56,32 +57,36 @@ template struct general_matrix_matrix_triangular_product { - typedef typename scalar_product_traits::ReturnType ResScalar; + typedef typename ScalarBinaryOpTraits::ReturnType ResScalar; static EIGEN_STRONG_INLINE void run(Index size, Index depth,const LhsScalar* _lhs, Index lhsStride, - const RhsScalar* _rhs, Index rhsStride, ResScalar* res, Index resStride, const ResScalar& alpha) + const RhsScalar* _rhs, Index rhsStride, ResScalar* _res, Index resStride, + const ResScalar& alpha, level3_blocking& blocking) { - const_blas_data_mapper lhs(_lhs,lhsStride); - const_blas_data_mapper rhs(_rhs,rhsStride); - typedef gebp_traits Traits; - Index kc = depth; // cache block size along the K direction - Index mc = size; // cache block size along the M direction - Index nc = size; // cache block size along the N direction - computeProductBlockingSizes(kc, mc, nc); + typedef const_blas_data_mapper LhsMapper; + typedef const_blas_data_mapper RhsMapper; + typedef blas_data_mapper ResMapper; + LhsMapper lhs(_lhs,lhsStride); + RhsMapper rhs(_rhs,rhsStride); + ResMapper res(_res, resStride); + + Index kc = blocking.kc(); + Index mc = (std::min)(size,blocking.mc()); + // !!! mc must be a multiple of nr: if(mc > Traits::nr) mc = (mc/Traits::nr)*Traits::nr; - std::size_t sizeW = kc*Traits::WorkSpaceFactor; - std::size_t sizeB = sizeW + kc*size; - ei_declare_aligned_stack_constructed_variable(LhsScalar, blockA, kc*mc, 0); - ei_declare_aligned_stack_constructed_variable(RhsScalar, allocatedBlockB, sizeB, 0); - RhsScalar* blockB = allocatedBlockB + sizeW; - - gemm_pack_lhs pack_lhs; - gemm_pack_rhs pack_rhs; - gebp_kernel gebp; + std::size_t sizeA = kc*mc; + std::size_t sizeB = kc*size; + + ei_declare_aligned_stack_constructed_variable(LhsScalar, blockA, sizeA, blocking.blockA()); + ei_declare_aligned_stack_constructed_variable(RhsScalar, blockB, sizeB, blocking.blockB()); + + gemm_pack_lhs pack_lhs; + gemm_pack_rhs pack_rhs; + gebp_kernel gebp; tribb_kernel sybb; for(Index k2=0; k2 processed with gebp or skipped // 2 - the actual_mc x actual_mc symmetric block => processed with a special kernel // 3 - after the diagonal => processed with gebp or skipped if (UpLo==Lower) - gebp(res+i2, resStride, blockA, blockB, actual_mc, actual_kc, (std::min)(size,i2), alpha, - -1, -1, 0, 0, allocatedBlockB); + gebp(res.getSubMapper(i2, 0), blockA, blockB, actual_mc, actual_kc, + (std::min)(size,i2), alpha, -1, -1, 0, 0); + - sybb(res+resStride*i2 + i2, resStride, blockA, blockB + actual_kc*i2, actual_mc, actual_kc, alpha, allocatedBlockB); + sybb(_res+resStride*i2 + i2, resStride, blockA, blockB + actual_kc*i2, actual_mc, actual_kc, alpha); if (UpLo==Upper) { Index j2 = i2+actual_mc; - gebp(res+resStride*j2+i2, resStride, blockA, blockB+actual_kc*j2, actual_mc, actual_kc, (std::max)(Index(0), size-j2), alpha, - -1, -1, 0, 0, allocatedBlockB); + gebp(res.getSubMapper(i2, j2), blockA, blockB+actual_kc*j2, actual_mc, + actual_kc, (std::max)(Index(0), size-j2), alpha, -1, -1, 0, 0); } } } @@ -132,14 +138,17 @@ struct tribb_kernel { typedef gebp_traits Traits; typedef typename Traits::ResScalar ResScalar; - + enum { - BlockSize = EIGEN_PLAIN_ENUM_MAX(mr,nr) + BlockSize = meta_least_common_multiple::ret }; - void operator()(ResScalar* res, Index resStride, const LhsScalar* blockA, const RhsScalar* blockB, Index size, Index depth, const ResScalar& alpha, RhsScalar* workspace) + void operator()(ResScalar* _res, Index resStride, const LhsScalar* blockA, const RhsScalar* blockB, Index size, Index depth, const ResScalar& alpha) { - gebp_kernel gebp_kernel; - Matrix buffer; + typedef blas_data_mapper ResMapper; + ResMapper res(_res, resStride); + gebp_kernel gebp_kernel; + + Matrix buffer((internal::constructor_without_unaligned_array_assert())); // let's process the block per panel of actual_mc x BlockSize, // again, each is split into three parts, etc. @@ -149,20 +158,20 @@ struct tribb_kernel const RhsScalar* actual_b = blockB+j*depth; if(UpLo==Upper) - gebp_kernel(res+j*resStride, resStride, blockA, actual_b, j, depth, actualBlockSize, alpha, - -1, -1, 0, 0, workspace); + gebp_kernel(res.getSubMapper(0, j), blockA, actual_b, j, depth, actualBlockSize, alpha, + -1, -1, 0, 0); // selfadjoint micro block { Index i = j; buffer.setZero(); // 1 - apply the kernel on the temporary buffer - gebp_kernel(buffer.data(), BlockSize, blockA+depth*i, actual_b, actualBlockSize, depth, actualBlockSize, alpha, - -1, -1, 0, 0, workspace); + gebp_kernel(ResMapper(buffer.data(), BlockSize), blockA+depth*i, actual_b, actualBlockSize, depth, actualBlockSize, alpha, + -1, -1, 0, 0); // 2 - triangular accumulation for(Index j1=0; j1 struct general_product_to_triangular_selector { - static void run(MatrixType& mat, const ProductType& prod, const typename MatrixType::Scalar& alpha) + static void run(MatrixType& mat, const ProductType& prod, const typename MatrixType::Scalar& alpha, bool beta) { typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::Index Index; typedef typename internal::remove_all::type Lhs; typedef internal::blas_traits LhsBlasTraits; @@ -209,6 +217,9 @@ struct general_product_to_triangular_selector Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs().derived()) * RhsBlasTraits::extractScalarFactor(prod.rhs().derived()); + if(!beta) + mat.template triangularView().setZero(); + enum { StorageOrder = (internal::traits::Flags&RowMajorBit) ? RowMajor : ColMajor, UseLhsDirectly = _ActualLhs::InnerStrideAtCompileTime==1, @@ -236,10 +247,8 @@ struct general_product_to_triangular_selector template struct general_product_to_triangular_selector { - static void run(MatrixType& mat, const ProductType& prod, const typename MatrixType::Scalar& alpha) + static void run(MatrixType& mat, const ProductType& prod, const typename MatrixType::Scalar& alpha, bool beta) { - typedef typename MatrixType::Index Index; - typedef typename internal::remove_all::type Lhs; typedef internal::blas_traits LhsBlasTraits; typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhs; @@ -254,23 +263,47 @@ struct general_product_to_triangular_selector typename ProductType::Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs().derived()) * RhsBlasTraits::extractScalarFactor(prod.rhs().derived()); + if(!beta) + mat.template triangularView().setZero(); + + enum { + IsRowMajor = (internal::traits::Flags&RowMajorBit) ? 1 : 0, + LhsIsRowMajor = _ActualLhs::Flags&RowMajorBit ? 1 : 0, + RhsIsRowMajor = _ActualRhs::Flags&RowMajorBit ? 1 : 0, + SkipDiag = (UpLo&(UnitDiag|ZeroDiag))!=0 + }; + + Index size = mat.cols(); + if(SkipDiag) + size--; + Index depth = actualLhs.cols(); + + typedef internal::gemm_blocking_space BlockingType; + + BlockingType blocking(size, size, depth, 1, false); + internal::general_matrix_matrix_triangular_product - ::run(mat.cols(), actualLhs.cols(), - &actualLhs.coeffRef(0,0), actualLhs.outerStride(), &actualRhs.coeffRef(0,0), actualRhs.outerStride(), - mat.data(), mat.outerStride(), actualAlpha); + typename Lhs::Scalar, LhsIsRowMajor ? RowMajor : ColMajor, LhsBlasTraits::NeedToConjugate, + typename Rhs::Scalar, RhsIsRowMajor ? RowMajor : ColMajor, RhsBlasTraits::NeedToConjugate, + IsRowMajor ? RowMajor : ColMajor, UpLo&(Lower|Upper)> + ::run(size, depth, + &actualLhs.coeffRef(SkipDiag&&(UpLo&Lower)==Lower ? 1 : 0,0), actualLhs.outerStride(), + &actualRhs.coeffRef(0,SkipDiag&&(UpLo&Upper)==Upper ? 1 : 0), actualRhs.outerStride(), + mat.data() + (SkipDiag ? (bool(IsRowMajor) != ((UpLo&Lower)==Lower) ? 1 : mat.outerStride() ) : 0), mat.outerStride(), actualAlpha, blocking); } }; template -template -TriangularView& TriangularView::assignProduct(const ProductBase& prod, const Scalar& alpha) +template +TriangularView& TriangularViewImpl::_assignProduct(const ProductType& prod, const Scalar& alpha, bool beta) { - general_product_to_triangular_selector::run(m_matrix.const_cast_derived(), prod.derived(), alpha); + EIGEN_STATIC_ASSERT((UpLo&UnitDiag)==0, WRITING_TO_TRIANGULAR_PART_WITH_UNIT_DIAGONAL_IS_NOT_SUPPORTED); + eigen_assert(derived().nestedExpression().rows() == prod.rows() && derived().cols() == prod.cols()); + + general_product_to_triangular_selector::InnerSize==1>::run(derived().nestedExpression().const_cast_derived(), prod, alpha, beta); - return *this; + return derived(); } } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_MKL.h b/libs/eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_BLAS.h similarity index 68% rename from libs/eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_MKL.h rename to libs/eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_BLAS.h index 3deed068e..41e18ff07 100644 --- a/libs/eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_MKL.h +++ b/libs/eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_BLAS.h @@ -25,15 +25,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************** - * Content : Eigen bindings to Intel(R) MKL + * Content : Eigen bindings to BLAS F77 * Level 3 BLAS SYRK/HERK implementation. ******************************************************************************** */ -#ifndef EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_MKL_H -#define EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_MKL_H +#ifndef EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_BLAS_H +#define EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_BLAS_H -namespace Eigen { +namespace Eigen { namespace internal { @@ -44,34 +44,35 @@ struct general_matrix_matrix_rankupdate : // try to go to BLAS specialization -#define EIGEN_MKL_RANKUPDATE_SPECIALIZE(Scalar) \ +#define EIGEN_BLAS_RANKUPDATE_SPECIALIZE(Scalar) \ template \ struct general_matrix_matrix_triangular_product { \ static EIGEN_STRONG_INLINE void run(Index size, Index depth,const Scalar* lhs, Index lhsStride, \ - const Scalar* rhs, Index rhsStride, Scalar* res, Index resStride, Scalar alpha) \ + const Scalar* rhs, Index rhsStride, Scalar* res, Index resStride, Scalar alpha, level3_blocking& blocking) \ { \ - if (lhs==rhs) { \ + if ( lhs==rhs && ((UpLo&(Lower|Upper)==UpLo)) ) { \ general_matrix_matrix_rankupdate \ - ::run(size,depth,lhs,lhsStride,rhs,rhsStride,res,resStride,alpha); \ + ::run(size,depth,lhs,lhsStride,rhs,rhsStride,res,resStride,alpha,blocking); \ } else { \ general_matrix_matrix_triangular_product \ - ::run(size,depth,lhs,lhsStride,rhs,rhsStride,res,resStride,alpha); \ + ::run(size,depth,lhs,lhsStride,rhs,rhsStride,res,resStride,alpha,blocking); \ } \ } \ }; -EIGEN_MKL_RANKUPDATE_SPECIALIZE(double) -//EIGEN_MKL_RANKUPDATE_SPECIALIZE(dcomplex) -EIGEN_MKL_RANKUPDATE_SPECIALIZE(float) -//EIGEN_MKL_RANKUPDATE_SPECIALIZE(scomplex) +EIGEN_BLAS_RANKUPDATE_SPECIALIZE(double) +EIGEN_BLAS_RANKUPDATE_SPECIALIZE(float) +// TODO handle complex cases +// EIGEN_BLAS_RANKUPDATE_SPECIALIZE(dcomplex) +// EIGEN_BLAS_RANKUPDATE_SPECIALIZE(scomplex) // SYRK for float/double -#define EIGEN_MKL_RANKUPDATE_R(EIGTYPE, MKLTYPE, MKLFUNC) \ +#define EIGEN_BLAS_RANKUPDATE_R(EIGTYPE, BLASTYPE, BLASFUNC) \ template \ struct general_matrix_matrix_rankupdate { \ enum { \ @@ -80,23 +81,19 @@ struct general_matrix_matrix_rankupdate& /*blocking*/) \ { \ /* typedef Matrix MatrixRhs;*/ \ \ - MKL_INT lda=lhsStride, ldc=resStride, n=size, k=depth; \ - char uplo=(IsLower) ? 'L' : 'U', trans=(AStorageOrder==RowMajor) ? 'T':'N'; \ - MKLTYPE alpha_, beta_; \ -\ -/* Set alpha_ & beta_ */ \ - assign_scalar_eig2mkl(alpha_, alpha); \ - assign_scalar_eig2mkl(beta_, EIGTYPE(1)); \ - MKLFUNC(&uplo, &trans, &n, &k, &alpha_, lhs, &lda, &beta_, res, &ldc); \ + BlasIndex lda=convert_index(lhsStride), ldc=convert_index(resStride), n=convert_index(size), k=convert_index(depth); \ + char uplo=((IsLower) ? 'L' : 'U'), trans=((AStorageOrder==RowMajor) ? 'T':'N'); \ + EIGTYPE beta(1); \ + BLASFUNC(&uplo, &trans, &n, &k, &numext::real_ref(alpha), lhs, &lda, &numext::real_ref(beta), res, &ldc); \ } \ }; // HERK for complex data -#define EIGEN_MKL_RANKUPDATE_C(EIGTYPE, MKLTYPE, RTYPE, MKLFUNC) \ +#define EIGEN_BLAS_RANKUPDATE_C(EIGTYPE, BLASTYPE, RTYPE, BLASFUNC) \ template \ struct general_matrix_matrix_rankupdate { \ enum { \ @@ -105,18 +102,15 @@ struct general_matrix_matrix_rankupdate& /*blocking*/) \ { \ typedef Matrix MatrixType; \ \ - MKL_INT lda=lhsStride, ldc=resStride, n=size, k=depth; \ - char uplo=(IsLower) ? 'L' : 'U', trans=(AStorageOrder==RowMajor) ? 'C':'N'; \ + BlasIndex lda=convert_index(lhsStride), ldc=convert_index(resStride), n=convert_index(size), k=convert_index(depth); \ + char uplo=((IsLower) ? 'L' : 'U'), trans=((AStorageOrder==RowMajor) ? 'C':'N'); \ RTYPE alpha_, beta_; \ const EIGTYPE* a_ptr; \ \ -/* Set alpha_ & beta_ */ \ -/* assign_scalar_eig2mkl(alpha_, alpha); */\ -/* assign_scalar_eig2mkl(beta_, EIGTYPE(1));*/ \ alpha_ = alpha.real(); \ beta_ = 1.0; \ /* Copy with conjugation in some cases*/ \ @@ -127,20 +121,21 @@ struct general_matrix_matrix_rankupdate \ struct general_matrix_matrix_product \ { \ +typedef gebp_traits Traits; \ +\ static void run(Index rows, Index cols, Index depth, \ const EIGTYPE* _lhs, Index lhsStride, \ const EIGTYPE* _rhs, Index rhsStride, \ @@ -64,55 +66,50 @@ static void run(Index rows, Index cols, Index depth, \ using std::conj; \ \ char transa, transb; \ - MKL_INT m, n, k, lda, ldb, ldc; \ + BlasIndex m, n, k, lda, ldb, ldc; \ const EIGTYPE *a, *b; \ - MKLTYPE alpha_, beta_; \ + EIGTYPE beta(1); \ MatrixX##EIGPREFIX a_tmp, b_tmp; \ - EIGTYPE myone(1);\ \ /* Set transpose options */ \ transa = (LhsStorageOrder==RowMajor) ? ((ConjugateLhs) ? 'C' : 'T') : 'N'; \ transb = (RhsStorageOrder==RowMajor) ? ((ConjugateRhs) ? 'C' : 'T') : 'N'; \ \ /* Set m, n, k */ \ - m = (MKL_INT)rows; \ - n = (MKL_INT)cols; \ - k = (MKL_INT)depth; \ -\ -/* Set alpha_ & beta_ */ \ - assign_scalar_eig2mkl(alpha_, alpha); \ - assign_scalar_eig2mkl(beta_, myone); \ + m = convert_index(rows); \ + n = convert_index(cols); \ + k = convert_index(depth); \ \ /* Set lda, ldb, ldc */ \ - lda = (MKL_INT)lhsStride; \ - ldb = (MKL_INT)rhsStride; \ - ldc = (MKL_INT)resStride; \ + lda = convert_index(lhsStride); \ + ldb = convert_index(rhsStride); \ + ldc = convert_index(resStride); \ \ /* Set a, b, c */ \ if ((LhsStorageOrder==ColMajor) && (ConjugateLhs)) { \ Map > lhs(_lhs,m,k,OuterStride<>(lhsStride)); \ a_tmp = lhs.conjugate(); \ a = a_tmp.data(); \ - lda = a_tmp.outerStride(); \ + lda = convert_index(a_tmp.outerStride()); \ } else a = _lhs; \ \ if ((RhsStorageOrder==ColMajor) && (ConjugateRhs)) { \ Map > rhs(_rhs,k,n,OuterStride<>(rhsStride)); \ b_tmp = rhs.conjugate(); \ b = b_tmp.data(); \ - ldb = b_tmp.outerStride(); \ + ldb = convert_index(b_tmp.outerStride()); \ } else b = _rhs; \ \ - MKLPREFIX##gemm(&transa, &transb, &m, &n, &k, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)b, &ldb, &beta_, (MKLTYPE*)res, &ldc); \ + BLASPREFIX##gemm_(&transa, &transb, &m, &n, &k, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)b, &ldb, &numext::real_ref(beta), (BLASTYPE*)res, &ldc); \ }}; -GEMM_SPECIALIZATION(double, d, double, d) -GEMM_SPECIALIZATION(float, f, float, s) -GEMM_SPECIALIZATION(dcomplex, cd, MKL_Complex16, z) -GEMM_SPECIALIZATION(scomplex, cf, MKL_Complex8, c) +GEMM_SPECIALIZATION(double, d, double, d) +GEMM_SPECIALIZATION(float, f, float, s) +GEMM_SPECIALIZATION(dcomplex, cd, double, z) +GEMM_SPECIALIZATION(scomplex, cf, float, c) } // end namespase internal } // end namespace Eigen -#endif // EIGEN_GENERAL_MATRIX_MATRIX_MKL_H +#endif // EIGEN_GENERAL_MATRIX_MATRIX_BLAS_H diff --git a/libs/eigen3/Eigen/src/Core/products/GeneralMatrixVector.h b/libs/eigen3/Eigen/src/Core/products/GeneralMatrixVector.h index 09387703e..3c1a7fc40 100644 --- a/libs/eigen3/Eigen/src/Core/products/GeneralMatrixVector.h +++ b/libs/eigen3/Eigen/src/Core/products/GeneralMatrixVector.h @@ -10,7 +10,7 @@ #ifndef EIGEN_GENERAL_MATRIX_VECTOR_H #define EIGEN_GENERAL_MATRIX_VECTOR_H -namespace Eigen { +namespace Eigen { namespace internal { @@ -26,11 +26,39 @@ namespace internal { * |real |cplx |real | alpha is converted to a cplx when calling the run function, no vectorization * |cplx |real |cplx | invalid, the caller has to do tmp: = A * B; C += alpha*tmp * |cplx |real |real | optimal case, vectorization possible via real-cplx mul + * + * Accesses to the matrix coefficients follow the following logic: + * + * - if all columns have the same alignment then + * - if the columns have the same alignment as the result vector, then easy! (-> AllAligned case) + * - otherwise perform unaligned loads only (-> NoneAligned case) + * - otherwise + * - if even columns have the same alignment then + * // odd columns are guaranteed to have the same alignment too + * - if even or odd columns have the same alignment as the result, then + * // for a register size of 2 scalars, this is guarantee to be the case (e.g., SSE with double) + * - perform half aligned and half unaligned loads (-> EvenAligned case) + * - otherwise perform unaligned loads only (-> NoneAligned case) + * - otherwise, if the register size is 4 scalars (e.g., SSE with float) then + * - one over 4 consecutive columns is guaranteed to be aligned with the result vector, + * perform simple aligned loads for this column and aligned loads plus re-alignment for the other. (-> FirstAligned case) + * // this re-alignment is done by the palign function implemented for SSE in Eigen/src/Core/arch/SSE/PacketMath.h + * - otherwise, + * // if we get here, this means the register size is greater than 4 (e.g., AVX with floats), + * // we currently fall back to the NoneAligned case + * + * The same reasoning apply for the transposed case. + * + * The last case (PacketSize>4) could probably be improved by generalizing the FirstAligned case, but since we do not support AVX yet... + * One might also wonder why in the EvenAligned case we perform unaligned loads instead of using the aligned-loads plus re-alignment + * strategy as in the FirstAligned case. The reason is that we observed that unaligned loads on a 8 byte boundary are not too slow + * compared to unaligned loads on a 4 byte boundary. + * */ -template -struct general_matrix_vector_product +template +struct general_matrix_vector_product { -typedef typename scalar_product_traits::ReturnType ResScalar; + typedef typename ScalarBinaryOpTraits::ReturnType ResScalar; enum { Vectorizable = packet_traits::Vectorizable && packet_traits::Vectorizable @@ -50,31 +78,35 @@ typedef typename conditional::type ResPacket; EIGEN_DONT_INLINE static void run( Index rows, Index cols, - const LhsScalar* lhs, Index lhsStride, - const RhsScalar* rhs, Index rhsIncr, - ResScalar* res, Index resIncr, RhsScalar alpha); + const LhsMapper& lhs, + const RhsMapper& rhs, + ResScalar* res, Index resIncr, + RhsScalar alpha); }; -template -EIGEN_DONT_INLINE void general_matrix_vector_product::run( +template +EIGEN_DONT_INLINE void general_matrix_vector_product::run( Index rows, Index cols, - const LhsScalar* lhs, Index lhsStride, - const RhsScalar* rhs, Index rhsIncr, - ResScalar* res, Index resIncr, RhsScalar alpha) + const LhsMapper& lhs, + const RhsMapper& rhs, + ResScalar* res, Index resIncr, + RhsScalar alpha) { - EIGEN_UNUSED_VARIABLE(resIncr) + EIGEN_UNUSED_VARIABLE(resIncr); eigen_internal_assert(resIncr==1); #ifdef _EIGEN_ACCUMULATE_PACKETS #error _EIGEN_ACCUMULATE_PACKETS has already been defined #endif - #define _EIGEN_ACCUMULATE_PACKETS(A0,A13,A2) \ + #define _EIGEN_ACCUMULATE_PACKETS(Alignment0,Alignment13,Alignment2) \ pstore(&res[j], \ padd(pload(&res[j]), \ padd( \ - padd(pcj.pmul(EIGEN_CAT(ploa , A0)(&lhs0[j]), ptmp0), \ - pcj.pmul(EIGEN_CAT(ploa , A13)(&lhs1[j]), ptmp1)), \ - padd(pcj.pmul(EIGEN_CAT(ploa , A2)(&lhs2[j]), ptmp2), \ - pcj.pmul(EIGEN_CAT(ploa , A13)(&lhs3[j]), ptmp3)) ))) + padd(pcj.pmul(lhs0.template load(j), ptmp0), \ + pcj.pmul(lhs1.template load(j), ptmp1)), \ + padd(pcj.pmul(lhs2.template load(j), ptmp2), \ + pcj.pmul(lhs3.template load(j), ptmp3)) ))) + + typedef typename LhsMapper::VectorMapper LhsScalars; conj_helper cj; conj_helper pcj; @@ -88,10 +120,12 @@ EIGEN_DONT_INLINE void general_matrix_vector_product1 ? alignedStart + ((size-alignedStart) & ~ResPacketAlignedMask) : 0; const Index peeledSize = alignedSize - RhsPacketSize*peels - RhsPacketSize + 1; @@ -101,19 +135,26 @@ EIGEN_DONT_INLINE void general_matrix_vector_product 4) + { + // TODO: extend the code to support aligned loads whenever possible when LhsPacketSize > 4. + // Currently, it seems to be better to perform unaligned loads anyway + alignmentPattern = NoneAligned; } else if (LhsPacketSize>1) { - eigen_internal_assert(size_t(lhs+lhsAlignmentOffset)%sizeof(LhsPacket)==0 || size= cols) || LhsPacketSize > size - || (size_t(lhs+alignedStart+lhsStride*skipColumns)%sizeof(LhsPacket))==0); + || (size_t(firstLhs+alignedStart+lhsStride*skipColumns)%sizeof(LhsPacket))==0);*/ } else if(Vectorizable) { @@ -142,20 +183,20 @@ EIGEN_DONT_INLINE void general_matrix_vector_product(alpha*rhs[i*rhsIncr]), - ptmp1 = pset1(alpha*rhs[(i+offset1)*rhsIncr]), - ptmp2 = pset1(alpha*rhs[(i+2)*rhsIncr]), - ptmp3 = pset1(alpha*rhs[(i+offset3)*rhsIncr]); + RhsPacket ptmp0 = pset1(alpha*rhs(i, 0)), + ptmp1 = pset1(alpha*rhs(i+offset1, 0)), + ptmp2 = pset1(alpha*rhs(i+2, 0)), + ptmp3 = pset1(alpha*rhs(i+offset3, 0)); // this helps a lot generating better binary code - const LhsScalar *lhs0 = lhs + i*lhsStride, *lhs1 = lhs + (i+offset1)*lhsStride, - *lhs2 = lhs + (i+2)*lhsStride, *lhs3 = lhs + (i+offset3)*lhsStride; + const LhsScalars lhs0 = lhs.getVectorMapper(0, i+0), lhs1 = lhs.getVectorMapper(0, i+offset1), + lhs2 = lhs.getVectorMapper(0, i+2), lhs3 = lhs.getVectorMapper(0, i+offset3); if (Vectorizable) { @@ -163,10 +204,10 @@ EIGEN_DONT_INLINE void general_matrix_vector_productalignedStart) @@ -175,11 +216,11 @@ EIGEN_DONT_INLINE void general_matrix_vector_product(&lhs1[alignedStart-1]); - A02 = pload(&lhs2[alignedStart-2]); - A03 = pload(&lhs3[alignedStart-3]); + A01 = lhs1.template load(alignedStart-1); + A02 = lhs2.template load(alignedStart-2); + A03 = lhs3.template load(alignedStart-3); for (; j(&lhs1[j-1+LhsPacketSize]); palign<1>(A01,A11); - A12 = pload(&lhs2[j-2+LhsPacketSize]); palign<2>(A02,A12); - A13 = pload(&lhs3[j-3+LhsPacketSize]); palign<3>(A03,A13); + A11 = lhs1.template load(j-1+LhsPacketSize); palign<1>(A01,A11); + A12 = lhs2.template load(j-2+LhsPacketSize); palign<2>(A02,A12); + A13 = lhs3.template load(j-3+LhsPacketSize); palign<3>(A03,A13); - A00 = pload(&lhs0[j]); - A10 = pload(&lhs0[j+LhsPacketSize]); + A00 = lhs0.template load(j); + A10 = lhs0.template load(j+LhsPacketSize); T0 = pcj.pmadd(A00, ptmp0, pload(&res[j])); T1 = pcj.pmadd(A10, ptmp0, pload(&res[j+ResPacketSize])); T0 = pcj.pmadd(A01, ptmp1, T0); - A01 = pload(&lhs1[j-1+2*LhsPacketSize]); palign<1>(A11,A01); + A01 = lhs1.template load(j-1+2*LhsPacketSize); palign<1>(A11,A01); T0 = pcj.pmadd(A02, ptmp2, T0); - A02 = pload(&lhs2[j-2+2*LhsPacketSize]); palign<2>(A12,A02); + A02 = lhs2.template load(j-2+2*LhsPacketSize); palign<2>(A12,A02); T0 = pcj.pmadd(A03, ptmp3, T0); pstore(&res[j],T0); - A03 = pload(&lhs3[j-3+2*LhsPacketSize]); palign<3>(A13,A03); + A03 = lhs3.template load(j-3+2*LhsPacketSize); palign<3>(A13,A03); T1 = pcj.pmadd(A11, ptmp1, T1); T1 = pcj.pmadd(A12, ptmp2, T1); T1 = pcj.pmadd(A13, ptmp3, T1); @@ -218,12 +259,12 @@ EIGEN_DONT_INLINE void general_matrix_vector_product(alpha*rhs[k*rhsIncr]); - const LhsScalar* lhs0 = lhs + k*lhsStride; + RhsPacket ptmp0 = pset1(alpha*rhs(k, 0)); + const LhsScalars lhs0 = lhs.getVectorMapper(0, k); if (Vectorizable) { /* explicit vectorization */ // process first unaligned result's coeffs for (Index j=0; j(alignedStart)) for (Index i = alignedStart;i(&lhs0[i]), ptmp0, pload(&res[i]))); + pstore(&res[i], pcj.pmadd(lhs0.template load(i), ptmp0, pload(&res[i]))); else for (Index i = alignedStart;i(&lhs0[i]), ptmp0, pload(&res[i]))); + pstore(&res[i], pcj.pmadd(lhs0.template load(i), ptmp0, pload(&res[i]))); } // process remaining scalars (or all if no explicit vectorization) for (Index i=alignedSize; i -struct general_matrix_vector_product +template +struct general_matrix_vector_product { -typedef typename scalar_product_traits::ReturnType ResScalar; +typedef typename ScalarBinaryOpTraits::ReturnType ResScalar; enum { Vectorizable = packet_traits::Vectorizable && packet_traits::Vectorizable @@ -310,73 +351,84 @@ typedef typename packet_traits::type _ResPacket; typedef typename conditional::type LhsPacket; typedef typename conditional::type RhsPacket; typedef typename conditional::type ResPacket; - + EIGEN_DONT_INLINE static void run( Index rows, Index cols, - const LhsScalar* lhs, Index lhsStride, - const RhsScalar* rhs, Index rhsIncr, - ResScalar* res, Index resIncr, + const LhsMapper& lhs, + const RhsMapper& rhs, + ResScalar* res, Index resIncr, ResScalar alpha); }; -template -EIGEN_DONT_INLINE void general_matrix_vector_product::run( +template +EIGEN_DONT_INLINE void general_matrix_vector_product::run( Index rows, Index cols, - const LhsScalar* lhs, Index lhsStride, - const RhsScalar* rhs, Index rhsIncr, + const LhsMapper& lhs, + const RhsMapper& rhs, ResScalar* res, Index resIncr, ResScalar alpha) { - EIGEN_UNUSED_VARIABLE(rhsIncr); - eigen_internal_assert(rhsIncr==1); + eigen_internal_assert(rhs.stride()==1); + #ifdef _EIGEN_ACCUMULATE_PACKETS #error _EIGEN_ACCUMULATE_PACKETS has already been defined #endif - #define _EIGEN_ACCUMULATE_PACKETS(A0,A13,A2) {\ - RhsPacket b = pload(&rhs[j]); \ - ptmp0 = pcj.pmadd(EIGEN_CAT(ploa,A0) (&lhs0[j]), b, ptmp0); \ - ptmp1 = pcj.pmadd(EIGEN_CAT(ploa,A13)(&lhs1[j]), b, ptmp1); \ - ptmp2 = pcj.pmadd(EIGEN_CAT(ploa,A2) (&lhs2[j]), b, ptmp2); \ - ptmp3 = pcj.pmadd(EIGEN_CAT(ploa,A13)(&lhs3[j]), b, ptmp3); } + #define _EIGEN_ACCUMULATE_PACKETS(Alignment0,Alignment13,Alignment2) {\ + RhsPacket b = rhs.getVectorMapper(j, 0).template load(0); \ + ptmp0 = pcj.pmadd(lhs0.template load(j), b, ptmp0); \ + ptmp1 = pcj.pmadd(lhs1.template load(j), b, ptmp1); \ + ptmp2 = pcj.pmadd(lhs2.template load(j), b, ptmp2); \ + ptmp3 = pcj.pmadd(lhs3.template load(j), b, ptmp3); } conj_helper cj; conj_helper pcj; + typedef typename LhsMapper::VectorMapper LhsScalars; + enum { AllAligned=0, EvenAligned=1, FirstAligned=2, NoneAligned=3 }; const Index rowsAtOnce = 4; const Index peels = 2; const Index RhsPacketAlignedMask = RhsPacketSize-1; const Index LhsPacketAlignedMask = LhsPacketSize-1; -// const Index PeelAlignedMask = RhsPacketSize*peels-1; const Index depth = cols; + const Index lhsStride = lhs.stride(); // How many coeffs of the result do we have to skip to be aligned. // Here we assume data are at least aligned on the base scalar type // if that's not the case then vectorization is discarded, see below. - Index alignedStart = internal::first_aligned(rhs, depth); + Index alignedStart = rhs.firstAligned(depth); Index alignedSize = RhsPacketSize>1 ? alignedStart + ((depth-alignedStart) & ~RhsPacketAlignedMask) : 0; const Index peeledSize = alignedSize - RhsPacketSize*peels - RhsPacketSize + 1; const Index alignmentStep = LhsPacketSize>1 ? (LhsPacketSize - lhsStride % LhsPacketSize) & LhsPacketAlignedMask : 0; Index alignmentPattern = alignmentStep==0 ? AllAligned - : alignmentStep==(LhsPacketSize/2) ? EvenAligned - : FirstAligned; + : alignmentStep==(LhsPacketSize/2) ? EvenAligned + : FirstAligned; // we cannot assume the first element is aligned because of sub-matrices - const Index lhsAlignmentOffset = internal::first_aligned(lhs,depth); + const Index lhsAlignmentOffset = lhs.firstAligned(depth); + const Index rhsAlignmentOffset = rhs.firstAligned(rows); // find how many rows do we have to skip to be aligned with rhs (if possible) Index skipRows = 0; // if the data cannot be aligned (TODO add some compile time tests when possible, e.g. for floats) - if( (sizeof(LhsScalar)!=sizeof(RhsScalar)) || (size_t(lhs)%sizeof(LhsScalar)) || (size_t(rhs)%sizeof(RhsScalar)) ) + if( (sizeof(LhsScalar)!=sizeof(RhsScalar)) || + (lhsAlignmentOffset < 0) || (lhsAlignmentOffset == depth) || + (rhsAlignmentOffset < 0) || (rhsAlignmentOffset == rows) ) { alignedSize = 0; alignedStart = 0; + alignmentPattern = NoneAligned; + } + else if(LhsPacketSize > 4) + { + // TODO: extend the code to support aligned loads whenever possible when LhsPacketSize > 4. + alignmentPattern = NoneAligned; } else if (LhsPacketSize>1) { - eigen_internal_assert(size_t(lhs+lhsAlignmentOffset)%sizeof(LhsPacket)==0 || depth= rows) || LhsPacketSize > depth - || (size_t(lhs+alignedStart+lhsStride*skipRows)%sizeof(LhsPacket))==0); + || (size_t(firstLhs+alignedStart+lhsStride*skipRows)%sizeof(LhsPacket))==0);*/ } else if(Vectorizable) { @@ -405,18 +457,19 @@ EIGEN_DONT_INLINE void general_matrix_vector_productalignedStart) @@ -439,11 +492,11 @@ EIGEN_DONT_INLINE void general_matrix_vector_product(&lhs1[alignedStart-1]); - A02 = pload(&lhs2[alignedStart-2]); - A03 = pload(&lhs3[alignedStart-3]); + A01 = lhs1.template load(alignedStart-1); + A02 = lhs2.template load(alignedStart-2); + A03 = lhs3.template load(alignedStart-3); for (; j(&rhs[j]); - A11 = pload(&lhs1[j-1+LhsPacketSize]); palign<1>(A01,A11); - A12 = pload(&lhs2[j-2+LhsPacketSize]); palign<2>(A02,A12); - A13 = pload(&lhs3[j-3+LhsPacketSize]); palign<3>(A03,A13); + RhsPacket b = rhs.getVectorMapper(j, 0).template load(0); + A11 = lhs1.template load(j-1+LhsPacketSize); palign<1>(A01,A11); + A12 = lhs2.template load(j-2+LhsPacketSize); palign<2>(A02,A12); + A13 = lhs3.template load(j-3+LhsPacketSize); palign<3>(A03,A13); - ptmp0 = pcj.pmadd(pload(&lhs0[j]), b, ptmp0); + ptmp0 = pcj.pmadd(lhs0.template load(j), b, ptmp0); ptmp1 = pcj.pmadd(A01, b, ptmp1); - A01 = pload(&lhs1[j-1+2*LhsPacketSize]); palign<1>(A11,A01); + A01 = lhs1.template load(j-1+2*LhsPacketSize); palign<1>(A11,A01); ptmp2 = pcj.pmadd(A02, b, ptmp2); - A02 = pload(&lhs2[j-2+2*LhsPacketSize]); palign<2>(A12,A02); + A02 = lhs2.template load(j-2+2*LhsPacketSize); palign<2>(A12,A02); ptmp3 = pcj.pmadd(A03, b, ptmp3); - A03 = pload(&lhs3[j-3+2*LhsPacketSize]); palign<3>(A13,A03); + A03 = lhs3.template load(j-3+2*LhsPacketSize); palign<3>(A13,A03); - b = pload(&rhs[j+RhsPacketSize]); - ptmp0 = pcj.pmadd(pload(&lhs0[j+LhsPacketSize]), b, ptmp0); + b = rhs.getVectorMapper(j+RhsPacketSize, 0).template load(0); + ptmp0 = pcj.pmadd(lhs0.template load(j+LhsPacketSize), b, ptmp0); ptmp1 = pcj.pmadd(A11, b, ptmp1); ptmp2 = pcj.pmadd(A12, b, ptmp2); ptmp3 = pcj.pmadd(A13, b, ptmp3); } } for (; j(tmp0); - const LhsScalar* lhs0 = lhs + i*lhsStride; + const LhsScalars lhs0 = lhs.getVectorMapper(i, 0); // process first unaligned result's coeffs // FIXME this loop get vectorized by the compiler ! for (Index j=0; jalignedStart) { // process aligned rhs coeffs - if ((size_t(lhs0+alignedStart)%sizeof(LhsPacket))==0) + if (lhs0.template aligned(alignedStart)) for (Index j = alignedStart;j(&lhs0[j]), pload(&rhs[j]), ptmp0); + ptmp0 = pcj.pmadd(lhs0.template load(j), rhs.getVectorMapper(j, 0).template load(0), ptmp0); else for (Index j = alignedStart;j(&lhs0[j]), pload(&rhs[j]), ptmp0); + ptmp0 = pcj.pmadd(lhs0.template load(j), rhs.getVectorMapper(j, 0).template load(0), ptmp0); tmp0 += predux(ptmp0); } // process remaining scalars // FIXME this loop get vectorized by the compiler ! for (Index j=alignedSize; j -struct general_matrix_vector_product_gemv : - general_matrix_vector_product {}; +template +struct general_matrix_vector_product_gemv; -#define EIGEN_MKL_GEMV_SPECIALIZE(Scalar) \ +#define EIGEN_BLAS_GEMV_SPECIALIZE(Scalar) \ template \ -struct general_matrix_vector_product { \ +struct general_matrix_vector_product,ColMajor,ConjugateLhs,Scalar,const_blas_data_mapper,ConjugateRhs,Specialized> { \ static void run( \ Index rows, Index cols, \ - const Scalar* lhs, Index lhsStride, \ - const Scalar* rhs, Index rhsIncr, \ + const const_blas_data_mapper &lhs, \ + const const_blas_data_mapper &rhs, \ Scalar* res, Index resIncr, Scalar alpha) \ { \ if (ConjugateLhs) { \ - general_matrix_vector_product::run( \ - rows, cols, lhs, lhsStride, rhs, rhsIncr, res, resIncr, alpha); \ + general_matrix_vector_product,ColMajor,ConjugateLhs,Scalar,const_blas_data_mapper,ConjugateRhs,BuiltIn>::run( \ + rows, cols, lhs, rhs, res, resIncr, alpha); \ } else { \ general_matrix_vector_product_gemv::run( \ - rows, cols, lhs, lhsStride, rhs, rhsIncr, res, resIncr, alpha); \ + rows, cols, lhs.data(), lhs.stride(), rhs.data(), rhs.stride(), res, resIncr, alpha); \ } \ } \ }; \ template \ -struct general_matrix_vector_product { \ +struct general_matrix_vector_product,RowMajor,ConjugateLhs,Scalar,const_blas_data_mapper,ConjugateRhs,Specialized> { \ static void run( \ Index rows, Index cols, \ - const Scalar* lhs, Index lhsStride, \ - const Scalar* rhs, Index rhsIncr, \ + const const_blas_data_mapper &lhs, \ + const const_blas_data_mapper &rhs, \ Scalar* res, Index resIncr, Scalar alpha) \ { \ general_matrix_vector_product_gemv::run( \ - rows, cols, lhs, lhsStride, rhs, rhsIncr, res, resIncr, alpha); \ + rows, cols, lhs.data(), lhs.stride(), rhs.data(), rhs.stride(), res, resIncr, alpha); \ } \ }; \ -EIGEN_MKL_GEMV_SPECIALIZE(double) -EIGEN_MKL_GEMV_SPECIALIZE(float) -EIGEN_MKL_GEMV_SPECIALIZE(dcomplex) -EIGEN_MKL_GEMV_SPECIALIZE(scomplex) +EIGEN_BLAS_GEMV_SPECIALIZE(double) +EIGEN_BLAS_GEMV_SPECIALIZE(float) +EIGEN_BLAS_GEMV_SPECIALIZE(dcomplex) +EIGEN_BLAS_GEMV_SPECIALIZE(scomplex) -#define EIGEN_MKL_GEMV_SPECIALIZATION(EIGTYPE,MKLTYPE,MKLPREFIX) \ +#define EIGEN_BLAS_GEMV_SPECIALIZATION(EIGTYPE,BLASTYPE,BLASPREFIX) \ template \ struct general_matrix_vector_product_gemv \ { \ @@ -98,16 +97,15 @@ static void run( \ const EIGTYPE* rhs, Index rhsIncr, \ EIGTYPE* res, Index resIncr, EIGTYPE alpha) \ { \ - MKL_INT m=rows, n=cols, lda=lhsStride, incx=rhsIncr, incy=resIncr; \ - MKLTYPE alpha_, beta_; \ - const EIGTYPE *x_ptr, myone(1); \ + BlasIndex m=convert_index(rows), n=convert_index(cols), \ + lda=convert_index(lhsStride), incx=convert_index(rhsIncr), incy=convert_index(resIncr); \ + const EIGTYPE beta(1); \ + const EIGTYPE *x_ptr; \ char trans=(LhsStorageOrder==ColMajor) ? 'N' : (ConjugateLhs) ? 'C' : 'T'; \ if (LhsStorageOrder==RowMajor) { \ - m=cols; \ - n=rows; \ + m = convert_index(cols); \ + n = convert_index(rows); \ }\ - assign_scalar_eig2mkl(alpha_, alpha); \ - assign_scalar_eig2mkl(beta_, myone); \ GEMVVector x_tmp; \ if (ConjugateRhs) { \ Map > map_x(rhs,cols,1,InnerStride<>(incx)); \ @@ -115,17 +113,17 @@ static void run( \ x_ptr=x_tmp.data(); \ incx=1; \ } else x_ptr=rhs; \ - MKLPREFIX##gemv(&trans, &m, &n, &alpha_, (const MKLTYPE*)lhs, &lda, (const MKLTYPE*)x_ptr, &incx, &beta_, (MKLTYPE*)res, &incy); \ + BLASPREFIX##gemv_(&trans, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)lhs, &lda, (const BLASTYPE*)x_ptr, &incx, &numext::real_ref(beta), (BLASTYPE*)res, &incy); \ }\ }; -EIGEN_MKL_GEMV_SPECIALIZATION(double, double, d) -EIGEN_MKL_GEMV_SPECIALIZATION(float, float, s) -EIGEN_MKL_GEMV_SPECIALIZATION(dcomplex, MKL_Complex16, z) -EIGEN_MKL_GEMV_SPECIALIZATION(scomplex, MKL_Complex8, c) +EIGEN_BLAS_GEMV_SPECIALIZATION(double, double, d) +EIGEN_BLAS_GEMV_SPECIALIZATION(float, float, s) +EIGEN_BLAS_GEMV_SPECIALIZATION(dcomplex, double, z) +EIGEN_BLAS_GEMV_SPECIALIZATION(scomplex, float, c) } // end namespase internal } // end namespace Eigen -#endif // EIGEN_GENERAL_MATRIX_VECTOR_MKL_H +#endif // EIGEN_GENERAL_MATRIX_VECTOR_BLAS_H diff --git a/libs/eigen3/Eigen/src/Core/products/Parallelizer.h b/libs/eigen3/Eigen/src/Core/products/Parallelizer.h index 5c3e9b7ac..c2f084c82 100644 --- a/libs/eigen3/Eigen/src/Core/products/Parallelizer.h +++ b/libs/eigen3/Eigen/src/Core/products/Parallelizer.h @@ -10,7 +10,7 @@ #ifndef EIGEN_PARALLELIZER_H #define EIGEN_PARALLELIZER_H -namespace Eigen { +namespace Eigen { namespace internal { @@ -49,8 +49,8 @@ inline void initParallel() { int nbt; internal::manage_multi_threading(GetAction, &nbt); - std::ptrdiff_t l1, l2; - internal::manage_caching_sizes(GetAction, &l1, &l2); + std::ptrdiff_t l1, l2, l3; + internal::manage_caching_sizes(GetAction, &l1, &l2, &l3); } /** \returns the max number of threads reserved for Eigen @@ -73,17 +73,17 @@ namespace internal { template struct GemmParallelInfo { - GemmParallelInfo() : sync(-1), users(0), rhs_start(0), rhs_length(0) {} + GemmParallelInfo() : sync(-1), users(0), lhs_start(0), lhs_length(0) {} - int volatile sync; + Index volatile sync; int volatile users; - Index rhs_start; - Index rhs_length; + Index lhs_start; + Index lhs_length; }; template -void parallelize_gemm(const Functor& func, Index rows, Index cols, bool transpose) +void parallelize_gemm(const Functor& func, Index rows, Index cols, Index depth, bool transpose) { // TODO when EIGEN_USE_BLAS is defined, // we should still enable OMP for other scalar types @@ -92,6 +92,7 @@ void parallelize_gemm(const Functor& func, Index rows, Index cols, bool transpos // the matrix product when multithreading is enabled. This is a temporary // fix to support row-major destination matrices. This whole // parallelizer mechanism has to be redisigned anyway. + EIGEN_UNUSED_VARIABLE(depth); EIGEN_UNUSED_VARIABLE(transpose); func(0,rows, 0,cols); #else @@ -102,53 +103,56 @@ void parallelize_gemm(const Functor& func, Index rows, Index cols, bool transpos // - we are not already in a parallel code // - the sizes are large enough - // 1- are we already in a parallel session? - // FIXME omp_get_num_threads()>1 only works for openmp, what if the user does not use openmp? - if((!Condition) || (omp_get_num_threads()>1)) - return func(0,rows, 0,cols); + // compute the maximal number of threads from the size of the product: + // This first heuristic takes into account that the product kernel is fully optimized when working with nr columns at once. + Index size = transpose ? rows : cols; + Index pb_max_threads = std::max(1,size / Functor::Traits::nr); - Index size = transpose ? cols : rows; + // compute the maximal number of threads from the total amount of work: + double work = static_cast(rows) * static_cast(cols) * + static_cast(depth); + double kMinTaskSize = 50000; // FIXME improve this heuristic. + pb_max_threads = std::max(1, std::min(pb_max_threads, work / kMinTaskSize)); - // 2- compute the maximal number of threads from the size of the product: - // FIXME this has to be fine tuned - Index max_threads = std::max(1,size / 32); + // compute the number of threads we are going to use + Index threads = std::min(nbThreads(), pb_max_threads); - // 3 - compute the number of threads we are going to use - Index threads = std::min(nbThreads(), max_threads); - - if(threads==1) + // if multi-threading is explicitely disabled, not useful, or if we already are in a parallel session, + // then abort multi-threading + // FIXME omp_get_num_threads()>1 only works for openmp, what if the user does not use openmp? + if((!Condition) || (threads==1) || (omp_get_num_threads()>1)) return func(0,rows, 0,cols); Eigen::initParallel(); - func.initParallelSession(); + func.initParallelSession(threads); if(transpose) std::swap(rows,cols); - Index blockCols = (cols / threads) & ~Index(0x3); - Index blockRows = (rows / threads) & ~Index(0x7); - - GemmParallelInfo* info = new GemmParallelInfo[threads]; + ei_declare_aligned_stack_constructed_variable(GemmParallelInfo,info,threads,0); - #pragma omp parallel for schedule(static,1) num_threads(threads) - for(Index i=0; i +template struct symm_pack_lhs { template inline @@ -45,25 +45,32 @@ struct symm_pack_lhs } void operator()(Scalar* blockA, const Scalar* _lhs, Index lhsStride, Index cols, Index rows) { + enum { PacketSize = packet_traits::size }; const_blas_data_mapper lhs(_lhs,lhsStride); Index count = 0; - Index peeled_mc = (rows/Pack1)*Pack1; - for(Index i=0; i(blockA, lhs, cols, i, count); - } - - if(rows-peeled_mc>=Pack2) - { - pack(blockA, lhs, cols, peeled_mc, count); - peeled_mc += Pack2; - } + //Index peeled_mc3 = (rows/Pack1)*Pack1; + + const Index peeled_mc3 = Pack1>=3*PacketSize ? (rows/(3*PacketSize))*(3*PacketSize) : 0; + const Index peeled_mc2 = Pack1>=2*PacketSize ? peeled_mc3+((rows-peeled_mc3)/(2*PacketSize))*(2*PacketSize) : 0; + const Index peeled_mc1 = Pack1>=1*PacketSize ? (rows/(1*PacketSize))*(1*PacketSize) : 0; + + if(Pack1>=3*PacketSize) + for(Index i=0; i(blockA, lhs, cols, i, count); + + if(Pack1>=2*PacketSize) + for(Index i=peeled_mc3; i(blockA, lhs, cols, i, count); + + if(Pack1>=1*PacketSize) + for(Index i=peeled_mc2; i(blockA, lhs, cols, i, count); // do the same with mr==1 - for(Index i=peeled_mc; i rhs(_rhs,rhsStride); - Index packet_cols = (cols/nr)*nr; + Index packet_cols8 = nr>=8 ? (cols/8) * 8 : 0; + Index packet_cols4 = nr>=4 ? (cols/4) * 4 : 0; // first part: normal case for(Index j2=0; j2=4) { blockB[count+2] = rhs(k,j2+2); blockB[count+3] = rhs(k,j2+3); } + if (nr>=8) + { + blockB[count+4] = rhs(k,j2+4); + blockB[count+5] = rhs(k,j2+5); + blockB[count+6] = rhs(k,j2+6); + blockB[count+7] = rhs(k,j2+7); + } count += nr; } } // second part: diagonal block - for(Index j2=k2; j2<(std::min)(k2+rows,packet_cols); j2+=nr) + Index end8 = nr>=8 ? (std::min)(k2+rows,packet_cols8) : k2; + if(nr>=8) { - // again we can split vertically in three different parts (transpose, symmetric, normal) - // transpose - for(Index k=k2; k=4) + { + for(Index j2=end8; j2<(std::min)(k2+rows,packet_cols4); j2+=4) { - blockB[count+0] = rhs(k,j2+0); - blockB[count+1] = rhs(k,j2+1); - if (nr==4) + // again we can split vertically in three different parts (transpose, symmetric, normal) + // transpose + for(Index k=k2; k=8) { - for(Index k=k2; k=4) + { + for(Index j2=(std::max)(packet_cols8,k2+rows); j2 the same with nr==1) - for(Index j2=packet_cols; j2& blocking) { product_selfadjoint_matrix::IsComplex && EIGEN_LOGICAL_XOR(LhsSelfAdjoint,ConjugateLhs), ColMajor> - ::run(cols, rows, rhs, rhsStride, lhs, lhsStride, res, resStride, alpha); + ::run(cols, rows, rhs, rhsStride, lhs, lhsStride, res, resStride, alpha, blocking); } }; @@ -234,7 +314,7 @@ struct product_selfadjoint_matrix& blocking); }; template & blocking) { Index size = rows; - const_blas_data_mapper lhs(_lhs,lhsStride); - const_blas_data_mapper rhs(_rhs,rhsStride); - typedef gebp_traits Traits; - Index kc = size; // cache block size along the K direction - Index mc = rows; // cache block size along the M direction - Index nc = cols; // cache block size along the N direction - computeProductBlockingSizes(kc, mc, nc); - // kc must smaller than mc + typedef const_blas_data_mapper LhsMapper; + typedef const_blas_data_mapper LhsTransposeMapper; + typedef const_blas_data_mapper RhsMapper; + typedef blas_data_mapper ResMapper; + LhsMapper lhs(_lhs,lhsStride); + LhsTransposeMapper lhs_transpose(_lhs,lhsStride); + RhsMapper rhs(_rhs,rhsStride); + ResMapper res(_res, resStride); + + Index kc = blocking.kc(); // cache block size along the K direction + Index mc = (std::min)(rows,blocking.mc()); // cache block size along the M direction + // kc must be smaller than mc kc = (std::min)(kc,mc); + std::size_t sizeA = kc*mc; + std::size_t sizeB = kc*cols; + ei_declare_aligned_stack_constructed_variable(Scalar, blockA, sizeA, blocking.blockA()); + ei_declare_aligned_stack_constructed_variable(Scalar, blockB, sizeB, blocking.blockB()); - std::size_t sizeW = kc*Traits::WorkSpaceFactor; - std::size_t sizeB = sizeW + kc*cols; - ei_declare_aligned_stack_constructed_variable(Scalar, blockA, kc*mc, 0); - ei_declare_aligned_stack_constructed_variable(Scalar, allocatedBlockB, sizeB, 0); - Scalar* blockB = allocatedBlockB + sizeW; - - gebp_kernel gebp_kernel; + gebp_kernel gebp_kernel; symm_pack_lhs pack_lhs; - gemm_pack_rhs pack_rhs; - gemm_pack_lhs pack_lhs_transposed; + gemm_pack_rhs pack_rhs; + gemm_pack_lhs pack_lhs_transposed; for(Index k2=0; k2 transposed packed copy @@ -289,9 +371,9 @@ EIGEN_DONT_INLINE void product_selfadjoint_matrix() - (blockA, &lhs(i2, k2), lhsStride, actual_kc, actual_mc); + gemm_pack_lhs() + (blockA, lhs.getSubMapper(i2, k2), actual_kc, actual_mc); - gebp_kernel(res+i2, resStride, blockA, blockB, actual_mc, actual_kc, cols, alpha); + gebp_kernel(res.getSubMapper(i2, 0), blockA, blockB, actual_mc, actual_kc, cols, alpha); } } } @@ -325,7 +407,7 @@ struct product_selfadjoint_matrix& blocking); }; template & blocking) { Index size = cols; - const_blas_data_mapper lhs(_lhs,lhsStride); - typedef gebp_traits Traits; - Index kc = size; // cache block size along the K direction - Index mc = rows; // cache block size along the M direction - Index nc = cols; // cache block size along the N direction - computeProductBlockingSizes(kc, mc, nc); - std::size_t sizeW = kc*Traits::WorkSpaceFactor; - std::size_t sizeB = sizeW + kc*cols; - ei_declare_aligned_stack_constructed_variable(Scalar, blockA, kc*mc, 0); - ei_declare_aligned_stack_constructed_variable(Scalar, allocatedBlockB, sizeB, 0); - Scalar* blockB = allocatedBlockB + sizeW; - - gebp_kernel gebp_kernel; - gemm_pack_lhs pack_lhs; + typedef const_blas_data_mapper LhsMapper; + typedef blas_data_mapper ResMapper; + LhsMapper lhs(_lhs,lhsStride); + ResMapper res(_res,resStride); + + Index kc = blocking.kc(); // cache block size along the K direction + Index mc = (std::min)(rows,blocking.mc()); // cache block size along the M direction + std::size_t sizeA = kc*mc; + std::size_t sizeB = kc*cols; + ei_declare_aligned_stack_constructed_variable(Scalar, blockA, sizeA, blocking.blockA()); + ei_declare_aligned_stack_constructed_variable(Scalar, blockB, sizeB, blocking.blockB()); + + gebp_kernel gebp_kernel; + gemm_pack_lhs pack_lhs; symm_pack_rhs pack_rhs; for(Index k2=0; k2 -struct traits > - : traits, Lhs, Rhs> > -{}; -} - -template -struct SelfadjointProductMatrix - : public ProductBase, Lhs, Rhs > +struct selfadjoint_product_impl { - EIGEN_PRODUCT_PUBLIC_INTERFACE(SelfadjointProductMatrix) - - SelfadjointProductMatrix(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} - + typedef typename Product::Scalar Scalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + enum { LhsIsUpper = (LhsMode&(Upper|Lower))==Upper, LhsIsSelfAdjoint = (LhsMode&SelfAdjoint)==SelfAdjoint, RhsIsUpper = (RhsMode&(Upper|Lower))==Upper, RhsIsSelfAdjoint = (RhsMode&SelfAdjoint)==SelfAdjoint }; - - template void scaleAndAddTo(Dest& dst, const Scalar& alpha) const + + template + static void run(Dest &dst, const Lhs &a_lhs, const Rhs &a_rhs, const Scalar& alpha) { - eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); + eigen_assert(dst.rows()==a_lhs.rows() && dst.cols()==a_rhs.cols()); - typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(m_lhs); - typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(m_rhs); + typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(a_lhs); + typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(a_rhs); - Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(m_lhs) - * RhsBlasTraits::extractScalarFactor(m_rhs); + Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(a_lhs) + * RhsBlasTraits::extractScalarFactor(a_rhs); + + typedef internal::gemm_blocking_space<(Dest::Flags&RowMajorBit) ? RowMajor : ColMajor,Scalar,Scalar, + Lhs::MaxRowsAtCompileTime, Rhs::MaxColsAtCompileTime, Lhs::MaxColsAtCompileTime,1> BlockingType; + + BlockingType blocking(lhs.rows(), rhs.cols(), lhs.cols(), 1, false); internal::product_selfadjoint_matrix::Flags &RowMajorBit) ? RowMajor : ColMajor, LhsIsSelfAdjoint, + EIGEN_LOGICAL_XOR(LhsIsUpper,internal::traits::Flags &RowMajorBit) ? RowMajor : ColMajor, LhsIsSelfAdjoint, NumTraits::IsComplex && EIGEN_LOGICAL_XOR(LhsIsUpper,bool(LhsBlasTraits::NeedToConjugate)), - EIGEN_LOGICAL_XOR(RhsIsUpper, - internal::traits::Flags &RowMajorBit) ? RowMajor : ColMajor, RhsIsSelfAdjoint, + EIGEN_LOGICAL_XOR(RhsIsUpper,internal::traits::Flags &RowMajorBit) ? RowMajor : ColMajor, RhsIsSelfAdjoint, NumTraits::IsComplex && EIGEN_LOGICAL_XOR(RhsIsUpper,bool(RhsBlasTraits::NeedToConjugate)), internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor> ::run( lhs.rows(), rhs.cols(), // sizes - &lhs.coeffRef(0,0), lhs.outerStride(), // lhs info - &rhs.coeffRef(0,0), rhs.outerStride(), // rhs info + &lhs.coeffRef(0,0), lhs.outerStride(), // lhs info + &rhs.coeffRef(0,0), rhs.outerStride(), // rhs info &dst.coeffRef(0,0), dst.outerStride(), // result info - actualAlpha // alpha + actualAlpha, blocking // alpha ); } }; +} // end namespace internal + } // end namespace Eigen #endif // EIGEN_SELFADJOINT_MATRIX_MATRIX_H diff --git a/libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix_MKL.h b/libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix_BLAS.h similarity index 68% rename from libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix_MKL.h rename to libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix_BLAS.h index dfa687fef..a45238d69 100644 --- a/libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix_MKL.h +++ b/libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix_BLAS.h @@ -25,13 +25,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ******************************************************************************** - * Content : Eigen bindings to Intel(R) MKL + * Content : Eigen bindings to BLAS F77 * Self adjoint matrix * matrix product functionality based on ?SYMM/?HEMM. ******************************************************************************** */ -#ifndef EIGEN_SELFADJOINT_MATRIX_MATRIX_MKL_H -#define EIGEN_SELFADJOINT_MATRIX_MATRIX_MKL_H +#ifndef EIGEN_SELFADJOINT_MATRIX_MATRIX_BLAS_H +#define EIGEN_SELFADJOINT_MATRIX_MATRIX_BLAS_H namespace Eigen { @@ -40,7 +40,7 @@ namespace internal { /* Optimized selfadjoint matrix * matrix (?SYMM/?HEMM) product */ -#define EIGEN_MKL_SYMM_L(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \ +#define EIGEN_BLAS_SYMM_L(EIGTYPE, BLASTYPE, EIGPREFIX, BLASPREFIX) \ template \ @@ -52,28 +52,23 @@ struct product_selfadjoint_matrix& /*blocking*/) \ { \ char side='L', uplo='L'; \ - MKL_INT m, n, lda, ldb, ldc; \ + BlasIndex m, n, lda, ldb, ldc; \ const EIGTYPE *a, *b; \ - MKLTYPE alpha_, beta_; \ + EIGTYPE beta(1); \ MatrixX##EIGPREFIX b_tmp; \ - EIGTYPE myone(1);\ \ /* Set transpose options */ \ /* Set m, n, k */ \ - m = (MKL_INT)rows; \ - n = (MKL_INT)cols; \ -\ -/* Set alpha_ & beta_ */ \ - assign_scalar_eig2mkl(alpha_, alpha); \ - assign_scalar_eig2mkl(beta_, myone); \ + m = convert_index(rows); \ + n = convert_index(cols); \ \ /* Set lda, ldb, ldc */ \ - lda = (MKL_INT)lhsStride; \ - ldb = (MKL_INT)rhsStride; \ - ldc = (MKL_INT)resStride; \ + lda = convert_index(lhsStride); \ + ldb = convert_index(rhsStride); \ + ldc = convert_index(resStride); \ \ /* Set a, b, c */ \ if (LhsStorageOrder==RowMajor) uplo='U'; \ @@ -83,16 +78,16 @@ struct product_selfadjoint_matrix > rhs(_rhs,n,m,OuterStride<>(rhsStride)); \ b_tmp = rhs.adjoint(); \ b = b_tmp.data(); \ - ldb = b_tmp.outerStride(); \ + ldb = convert_index(b_tmp.outerStride()); \ } else b = _rhs; \ \ - MKLPREFIX##symm(&side, &uplo, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)b, &ldb, &beta_, (MKLTYPE*)res, &ldc); \ + BLASPREFIX##symm_(&side, &uplo, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)b, &ldb, &numext::real_ref(beta), (BLASTYPE*)res, &ldc); \ \ } \ }; -#define EIGEN_MKL_HEMM_L(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \ +#define EIGEN_BLAS_HEMM_L(EIGTYPE, BLASTYPE, EIGPREFIX, BLASPREFIX) \ template \ @@ -103,36 +98,31 @@ struct product_selfadjoint_matrix& /*blocking*/) \ { \ char side='L', uplo='L'; \ - MKL_INT m, n, lda, ldb, ldc; \ + BlasIndex m, n, lda, ldb, ldc; \ const EIGTYPE *a, *b; \ - MKLTYPE alpha_, beta_; \ + EIGTYPE beta(1); \ MatrixX##EIGPREFIX b_tmp; \ Matrix a_tmp; \ - EIGTYPE myone(1); \ \ /* Set transpose options */ \ /* Set m, n, k */ \ - m = (MKL_INT)rows; \ - n = (MKL_INT)cols; \ -\ -/* Set alpha_ & beta_ */ \ - assign_scalar_eig2mkl(alpha_, alpha); \ - assign_scalar_eig2mkl(beta_, myone); \ + m = convert_index(rows); \ + n = convert_index(cols); \ \ /* Set lda, ldb, ldc */ \ - lda = (MKL_INT)lhsStride; \ - ldb = (MKL_INT)rhsStride; \ - ldc = (MKL_INT)resStride; \ + lda = convert_index(lhsStride); \ + ldb = convert_index(rhsStride); \ + ldc = convert_index(resStride); \ \ /* Set a, b, c */ \ if (((LhsStorageOrder==ColMajor) && ConjugateLhs) || ((LhsStorageOrder==RowMajor) && (!ConjugateLhs))) { \ Map, 0, OuterStride<> > lhs(_lhs,m,m,OuterStride<>(lhsStride)); \ a_tmp = lhs.conjugate(); \ a = a_tmp.data(); \ - lda = a_tmp.outerStride(); \ + lda = convert_index(a_tmp.outerStride()); \ } else a = _lhs; \ if (LhsStorageOrder==RowMajor) uplo='U'; \ \ @@ -151,23 +141,23 @@ struct product_selfadjoint_matrix(b_tmp.outerStride()); \ } \ \ - MKLPREFIX##hemm(&side, &uplo, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)b, &ldb, &beta_, (MKLTYPE*)res, &ldc); \ + BLASPREFIX##hemm_(&side, &uplo, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)b, &ldb, &numext::real_ref(beta), (BLASTYPE*)res, &ldc); \ \ } \ }; -EIGEN_MKL_SYMM_L(double, double, d, d) -EIGEN_MKL_SYMM_L(float, float, f, s) -EIGEN_MKL_HEMM_L(dcomplex, MKL_Complex16, cd, z) -EIGEN_MKL_HEMM_L(scomplex, MKL_Complex8, cf, c) +EIGEN_BLAS_SYMM_L(double, double, d, d) +EIGEN_BLAS_SYMM_L(float, float, f, s) +EIGEN_BLAS_HEMM_L(dcomplex, double, cd, z) +EIGEN_BLAS_HEMM_L(scomplex, float, cf, c) /* Optimized matrix * selfadjoint matrix (?SYMM/?HEMM) product */ -#define EIGEN_MKL_SYMM_R(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \ +#define EIGEN_BLAS_SYMM_R(EIGTYPE, BLASTYPE, EIGPREFIX, BLASPREFIX) \ template \ @@ -179,27 +169,22 @@ struct product_selfadjoint_matrix& /*blocking*/) \ { \ char side='R', uplo='L'; \ - MKL_INT m, n, lda, ldb, ldc; \ + BlasIndex m, n, lda, ldb, ldc; \ const EIGTYPE *a, *b; \ - MKLTYPE alpha_, beta_; \ + EIGTYPE beta(1); \ MatrixX##EIGPREFIX b_tmp; \ - EIGTYPE myone(1);\ \ /* Set m, n, k */ \ - m = (MKL_INT)rows; \ - n = (MKL_INT)cols; \ -\ -/* Set alpha_ & beta_ */ \ - assign_scalar_eig2mkl(alpha_, alpha); \ - assign_scalar_eig2mkl(beta_, myone); \ + m = convert_index(rows); \ + n = convert_index(cols); \ \ /* Set lda, ldb, ldc */ \ - lda = (MKL_INT)rhsStride; \ - ldb = (MKL_INT)lhsStride; \ - ldc = (MKL_INT)resStride; \ + lda = convert_index(rhsStride); \ + ldb = convert_index(lhsStride); \ + ldc = convert_index(resStride); \ \ /* Set a, b, c */ \ if (RhsStorageOrder==RowMajor) uplo='U'; \ @@ -209,16 +194,16 @@ struct product_selfadjoint_matrix > lhs(_lhs,n,m,OuterStride<>(rhsStride)); \ b_tmp = lhs.adjoint(); \ b = b_tmp.data(); \ - ldb = b_tmp.outerStride(); \ + ldb = convert_index(b_tmp.outerStride()); \ } else b = _lhs; \ \ - MKLPREFIX##symm(&side, &uplo, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)b, &ldb, &beta_, (MKLTYPE*)res, &ldc); \ + BLASPREFIX##symm_(&side, &uplo, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)b, &ldb, &numext::real_ref(beta), (BLASTYPE*)res, &ldc); \ \ } \ }; -#define EIGEN_MKL_HEMM_R(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \ +#define EIGEN_BLAS_HEMM_R(EIGTYPE, BLASTYPE, EIGPREFIX, BLASPREFIX) \ template \ @@ -229,35 +214,30 @@ struct product_selfadjoint_matrix& /*blocking*/) \ { \ char side='R', uplo='L'; \ - MKL_INT m, n, lda, ldb, ldc; \ + BlasIndex m, n, lda, ldb, ldc; \ const EIGTYPE *a, *b; \ - MKLTYPE alpha_, beta_; \ + EIGTYPE beta(1); \ MatrixX##EIGPREFIX b_tmp; \ Matrix a_tmp; \ - EIGTYPE myone(1); \ \ /* Set m, n, k */ \ - m = (MKL_INT)rows; \ - n = (MKL_INT)cols; \ -\ -/* Set alpha_ & beta_ */ \ - assign_scalar_eig2mkl(alpha_, alpha); \ - assign_scalar_eig2mkl(beta_, myone); \ + m = convert_index(rows); \ + n = convert_index(cols); \ \ /* Set lda, ldb, ldc */ \ - lda = (MKL_INT)rhsStride; \ - ldb = (MKL_INT)lhsStride; \ - ldc = (MKL_INT)resStride; \ + lda = convert_index(rhsStride); \ + ldb = convert_index(lhsStride); \ + ldc = convert_index(resStride); \ \ /* Set a, b, c */ \ if (((RhsStorageOrder==ColMajor) && ConjugateRhs) || ((RhsStorageOrder==RowMajor) && (!ConjugateRhs))) { \ Map, 0, OuterStride<> > rhs(_rhs,n,n,OuterStride<>(rhsStride)); \ a_tmp = rhs.conjugate(); \ a = a_tmp.data(); \ - lda = a_tmp.outerStride(); \ + lda = convert_index(a_tmp.outerStride()); \ } else a = _rhs; \ if (RhsStorageOrder==RowMajor) uplo='U'; \ \ @@ -276,20 +256,20 @@ struct product_selfadjoint_matrix(b_tmp.outerStride()); \ } \ \ - MKLPREFIX##hemm(&side, &uplo, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)b, &ldb, &beta_, (MKLTYPE*)res, &ldc); \ + BLASPREFIX##hemm_(&side, &uplo, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)b, &ldb, &numext::real_ref(beta), (BLASTYPE*)res, &ldc); \ } \ }; -EIGEN_MKL_SYMM_R(double, double, d, d) -EIGEN_MKL_SYMM_R(float, float, f, s) -EIGEN_MKL_HEMM_R(dcomplex, MKL_Complex16, cd, z) -EIGEN_MKL_HEMM_R(scomplex, MKL_Complex8, cf, c) +EIGEN_BLAS_SYMM_R(double, double, d, d) +EIGEN_BLAS_SYMM_R(float, float, f, s) +EIGEN_BLAS_HEMM_R(dcomplex, double, cd, z) +EIGEN_BLAS_HEMM_R(scomplex, float, cf, c) } // end namespace internal } // end namespace Eigen -#endif // EIGEN_SELFADJOINT_MATRIX_MATRIX_MKL_H +#endif // EIGEN_SELFADJOINT_MATRIX_MATRIX_BLAS_H diff --git a/libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixVector.h b/libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixVector.h index f698f67f9..3fd180e6c 100644 --- a/libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixVector.h +++ b/libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixVector.h @@ -30,7 +30,7 @@ struct selfadjoint_matrix_vector_product static EIGEN_DONT_INLINE void run( Index size, const Scalar* lhs, Index lhsStride, - const Scalar* _rhs, Index rhsIncr, + const Scalar* rhs, Scalar* res, Scalar alpha); }; @@ -39,11 +39,12 @@ template::run( Index size, const Scalar* lhs, Index lhsStride, - const Scalar* _rhs, Index rhsIncr, + const Scalar* rhs, Scalar* res, Scalar alpha) { typedef typename packet_traits::type Packet; + typedef typename NumTraits::Real RealScalar; const Index PacketSize = sizeof(Packet)/sizeof(Scalar); enum { @@ -54,23 +55,13 @@ EIGEN_DONT_INLINE void selfadjoint_matrix_vector_product::IsComplex && EIGEN_LOGICAL_XOR(ConjugateLhs, IsRowMajor), ConjugateRhs> cj0; conj_helper::IsComplex && EIGEN_LOGICAL_XOR(ConjugateLhs, !IsRowMajor), ConjugateRhs> cj1; - conj_helper::IsComplex, ConjugateRhs> cjd; + conj_helper cjd; conj_helper::IsComplex && EIGEN_LOGICAL_XOR(ConjugateLhs, IsRowMajor), ConjugateRhs> pcj0; conj_helper::IsComplex && EIGEN_LOGICAL_XOR(ConjugateLhs, !IsRowMajor), ConjugateRhs> pcj1; Scalar cjAlpha = ConjugateRhs ? numext::conj(alpha) : alpha; - // FIXME this copy is now handled outside product_selfadjoint_vector, so it could probably be removed. - // if the rhs is not sequentially stored in memory we copy it to a temporary buffer, - // this is because we need to extract packets - ei_declare_aligned_stack_constructed_variable(Scalar,rhs,size,rhsIncr==1 ? const_cast(_rhs) : 0); - if (rhsIncr!=1) - { - const Scalar* it = _rhs; - for (Index i=0; i(t3); - size_t starti = FirstTriangular ? 0 : j+2; - size_t endi = FirstTriangular ? j : size; - size_t alignedStart = (starti) + internal::first_aligned(&res[starti], endi-starti); - size_t alignedEnd = alignedStart + ((endi-alignedStart)/(PacketSize))*(PacketSize); + Index starti = FirstTriangular ? 0 : j+2; + Index endi = FirstTriangular ? j : size; + Index alignedStart = (starti) + internal::first_default_aligned(&res[starti], endi-starti); + Index alignedEnd = alignedStart + ((endi-alignedStart)/(PacketSize))*(PacketSize); - // TODO make sure this product is a real * complex and that the rhs is properly conjugated if needed res[j] += cjd.pmul(numext::real(A0[j]), t0); res[j+1] += cjd.pmul(numext::real(A1[j+1]), t1); if(FirstTriangular) @@ -111,11 +101,11 @@ EIGEN_DONT_INLINE void selfadjoint_matrix_vector_product huge speed up) // gcc 4.2 does this optimization automatically. @@ -123,7 +113,7 @@ EIGEN_DONT_INLINE void selfadjoint_matrix_vector_product(a0It); a0It += PacketSize; Packet A1i = ploadu(a1It); a1It += PacketSize; @@ -135,7 +125,7 @@ EIGEN_DONT_INLINE void selfadjoint_matrix_vector_product -struct traits > - : traits, Lhs, Rhs> > -{}; -} template -struct SelfadjointProductMatrix - : public ProductBase, Lhs, Rhs > +struct selfadjoint_product_impl { - EIGEN_PRODUCT_PUBLIC_INTERFACE(SelfadjointProductMatrix) - - enum { - LhsUpLo = LhsMode&(Upper|Lower) - }; - - SelfadjointProductMatrix(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} - - template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const + typedef typename Product::Scalar Scalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef typename internal::remove_all::type ActualLhsTypeCleaned; + + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + typedef typename internal::remove_all::type ActualRhsTypeCleaned; + + enum { LhsUpLo = LhsMode&(Upper|Lower) }; + + template + static void run(Dest& dest, const Lhs &a_lhs, const Rhs &a_rhs, const Scalar& alpha) { typedef typename Dest::Scalar ResScalar; - typedef typename Base::RhsScalar RhsScalar; - typedef Map, Aligned> MappedDest; + typedef typename Rhs::Scalar RhsScalar; + typedef Map, EIGEN_PLAIN_ENUM_MIN(AlignedMax,internal::packet_traits::size)> MappedDest; - eigen_assert(dest.rows()==m_lhs.rows() && dest.cols()==m_rhs.cols()); + eigen_assert(dest.rows()==a_lhs.rows() && dest.cols()==a_rhs.cols()); - typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(m_lhs); - typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(m_rhs); + typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(a_lhs); + typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(a_rhs); - Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(m_lhs) - * RhsBlasTraits::extractScalarFactor(m_rhs); + Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(a_lhs) + * RhsBlasTraits::extractScalarFactor(a_rhs); enum { EvalToDest = (Dest::InnerStrideAtCompileTime==1), - UseRhs = (_ActualRhsType::InnerStrideAtCompileTime==1) + UseRhs = (ActualRhsTypeCleaned::InnerStrideAtCompileTime==1) }; internal::gemv_static_vector_if static_dest; - internal::gemv_static_vector_if static_rhs; + internal::gemv_static_vector_if static_rhs; ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(), EvalToDest ? dest.data() : static_dest.data()); @@ -218,7 +206,7 @@ struct SelfadjointProductMatrix if(!EvalToDest) { #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - int size = dest.size(); + Index size = dest.size(); EIGEN_DENSE_STORAGE_CTOR_PLUGIN #endif MappedDest(actualDestPtr, dest.size()) = dest; @@ -227,18 +215,19 @@ struct SelfadjointProductMatrix if(!UseRhs) { #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - int size = rhs.size(); + Index size = rhs.size(); EIGEN_DENSE_STORAGE_CTOR_PLUGIN #endif - Map(actualRhsPtr, rhs.size()) = rhs; + Map(actualRhsPtr, rhs.size()) = rhs; } - internal::selfadjoint_matrix_vector_product::Flags&RowMajorBit) ? RowMajor : ColMajor, int(LhsUpLo), bool(LhsBlasTraits::NeedToConjugate), bool(RhsBlasTraits::NeedToConjugate)>::run + internal::selfadjoint_matrix_vector_product::Flags&RowMajorBit) ? RowMajor : ColMajor, + int(LhsUpLo), bool(LhsBlasTraits::NeedToConjugate), bool(RhsBlasTraits::NeedToConjugate)>::run ( lhs.rows(), // size &lhs.coeffRef(0,0), lhs.outerStride(), // lhs info - actualRhsPtr, 1, // rhs info + actualRhsPtr, // rhs info actualDestPtr, // result info actualAlpha // scale factor ); @@ -248,34 +237,24 @@ struct SelfadjointProductMatrix } }; -namespace internal { -template -struct traits > - : traits, Lhs, Rhs> > -{}; -} - template -struct SelfadjointProductMatrix - : public ProductBase, Lhs, Rhs > +struct selfadjoint_product_impl { - EIGEN_PRODUCT_PUBLIC_INTERFACE(SelfadjointProductMatrix) + typedef typename Product::Scalar Scalar; + enum { RhsUpLo = RhsMode&(Upper|Lower) }; - enum { - RhsUpLo = RhsMode&(Upper|Lower) - }; - - SelfadjointProductMatrix(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} - - template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const + template + static void run(Dest& dest, const Lhs &a_lhs, const Rhs &a_rhs, const Scalar& alpha) { // let's simply transpose the product Transpose destT(dest); - SelfadjointProductMatrix, int(RhsUpLo)==Upper ? Lower : Upper, false, - Transpose, 0, true>(m_rhs.transpose(), m_lhs.transpose()).scaleAndAddTo(destT, alpha); + selfadjoint_product_impl, int(RhsUpLo)==Upper ? Lower : Upper, false, + Transpose, 0, true>::run(destT, a_rhs.transpose(), a_lhs.transpose(), alpha); } }; +} // end namespace internal + } // end namespace Eigen #endif // EIGEN_SELFADJOINT_MATRIX_VECTOR_H diff --git a/libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixVector_MKL.h b/libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixVector_BLAS.h similarity index 72% rename from libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixVector_MKL.h rename to libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixVector_BLAS.h index 86684b66d..38f23accf 100644 --- a/libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixVector_MKL.h +++ b/libs/eigen3/Eigen/src/Core/products/SelfadjointMatrixVector_BLAS.h @@ -25,13 +25,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************** - * Content : Eigen bindings to Intel(R) MKL + * Content : Eigen bindings to BLAS F77 * Selfadjoint matrix-vector product functionality based on ?SYMV/HEMV. ******************************************************************************** */ -#ifndef EIGEN_SELFADJOINT_MATRIX_VECTOR_MKL_H -#define EIGEN_SELFADJOINT_MATRIX_VECTOR_MKL_H +#ifndef EIGEN_SELFADJOINT_MATRIX_VECTOR_BLAS_H +#define EIGEN_SELFADJOINT_MATRIX_VECTOR_BLAS_H namespace Eigen { @@ -47,31 +47,31 @@ template {}; -#define EIGEN_MKL_SYMV_SPECIALIZE(Scalar) \ +#define EIGEN_BLAS_SYMV_SPECIALIZE(Scalar) \ template \ struct selfadjoint_matrix_vector_product { \ static void run( \ Index size, const Scalar* lhs, Index lhsStride, \ - const Scalar* _rhs, Index rhsIncr, Scalar* res, Scalar alpha) { \ + const Scalar* _rhs, Scalar* res, Scalar alpha) { \ enum {\ IsColMajor = StorageOrder==ColMajor \ }; \ if (IsColMajor == ConjugateLhs) {\ selfadjoint_matrix_vector_product::run( \ - size, lhs, lhsStride, _rhs, rhsIncr, res, alpha); \ + size, lhs, lhsStride, _rhs, res, alpha); \ } else {\ selfadjoint_matrix_vector_product_symv::run( \ - size, lhs, lhsStride, _rhs, rhsIncr, res, alpha); \ + size, lhs, lhsStride, _rhs, res, alpha); \ }\ } \ }; \ -EIGEN_MKL_SYMV_SPECIALIZE(double) -EIGEN_MKL_SYMV_SPECIALIZE(float) -EIGEN_MKL_SYMV_SPECIALIZE(dcomplex) -EIGEN_MKL_SYMV_SPECIALIZE(scomplex) +EIGEN_BLAS_SYMV_SPECIALIZE(double) +EIGEN_BLAS_SYMV_SPECIALIZE(float) +EIGEN_BLAS_SYMV_SPECIALIZE(dcomplex) +EIGEN_BLAS_SYMV_SPECIALIZE(scomplex) -#define EIGEN_MKL_SYMV_SPECIALIZATION(EIGTYPE,MKLTYPE,MKLFUNC) \ +#define EIGEN_BLAS_SYMV_SPECIALIZATION(EIGTYPE,BLASTYPE,BLASFUNC) \ template \ struct selfadjoint_matrix_vector_product_symv \ { \ @@ -79,36 +79,33 @@ typedef Matrix SYMVVector;\ \ static void run( \ Index size, const EIGTYPE* lhs, Index lhsStride, \ -const EIGTYPE* _rhs, Index rhsIncr, EIGTYPE* res, EIGTYPE alpha) \ +const EIGTYPE* _rhs, EIGTYPE* res, EIGTYPE alpha) \ { \ enum {\ IsRowMajor = StorageOrder==RowMajor ? 1 : 0, \ IsLower = UpLo == Lower ? 1 : 0 \ }; \ - MKL_INT n=size, lda=lhsStride, incx=rhsIncr, incy=1; \ - MKLTYPE alpha_, beta_; \ - const EIGTYPE *x_ptr, myone(1); \ + BlasIndex n=convert_index(size), lda=convert_index(lhsStride), incx=1, incy=1; \ + EIGTYPE beta(1); \ + const EIGTYPE *x_ptr; \ char uplo=(IsRowMajor) ? (IsLower ? 'U' : 'L') : (IsLower ? 'L' : 'U'); \ - assign_scalar_eig2mkl(alpha_, alpha); \ - assign_scalar_eig2mkl(beta_, myone); \ SYMVVector x_tmp; \ if (ConjugateRhs) { \ - Map > map_x(_rhs,size,1,InnerStride<>(incx)); \ + Map map_x(_rhs,size,1); \ x_tmp=map_x.conjugate(); \ x_ptr=x_tmp.data(); \ - incx=1; \ } else x_ptr=_rhs; \ - MKLFUNC(&uplo, &n, &alpha_, (const MKLTYPE*)lhs, &lda, (const MKLTYPE*)x_ptr, &incx, &beta_, (MKLTYPE*)res, &incy); \ + BLASFUNC(&uplo, &n, &numext::real_ref(alpha), (const BLASTYPE*)lhs, &lda, (const BLASTYPE*)x_ptr, &incx, &numext::real_ref(beta), (BLASTYPE*)res, &incy); \ }\ }; -EIGEN_MKL_SYMV_SPECIALIZATION(double, double, dsymv) -EIGEN_MKL_SYMV_SPECIALIZATION(float, float, ssymv) -EIGEN_MKL_SYMV_SPECIALIZATION(dcomplex, MKL_Complex16, zhemv) -EIGEN_MKL_SYMV_SPECIALIZATION(scomplex, MKL_Complex8, chemv) +EIGEN_BLAS_SYMV_SPECIALIZATION(double, double, dsymv_) +EIGEN_BLAS_SYMV_SPECIALIZATION(float, float, ssymv_) +EIGEN_BLAS_SYMV_SPECIALIZATION(dcomplex, double, zhemv_) +EIGEN_BLAS_SYMV_SPECIALIZATION(scomplex, float, chemv_) } // end namespace internal } // end namespace Eigen -#endif // EIGEN_SELFADJOINT_MATRIX_VECTOR_MKL_H +#endif // EIGEN_SELFADJOINT_MATRIX_VECTOR_BLAS_H diff --git a/libs/eigen3/Eigen/src/Core/products/SelfadjointProduct.h b/libs/eigen3/Eigen/src/Core/products/SelfadjointProduct.h index 6ca4ae6c0..f038d686f 100644 --- a/libs/eigen3/Eigen/src/Core/products/SelfadjointProduct.h +++ b/libs/eigen3/Eigen/src/Core/products/SelfadjointProduct.h @@ -53,7 +53,6 @@ struct selfadjoint_product_selector static void run(MatrixType& mat, const OtherType& other, const typename MatrixType::Scalar& alpha) { typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::Index Index; typedef internal::blas_traits OtherBlasTraits; typedef typename OtherBlasTraits::DirectLinearAccessType ActualOtherType; typedef typename internal::remove_all::type _ActualOtherType; @@ -86,7 +85,6 @@ struct selfadjoint_product_selector static void run(MatrixType& mat, const OtherType& other, const typename MatrixType::Scalar& alpha) { typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::Index Index; typedef internal::blas_traits OtherBlasTraits; typedef typename OtherBlasTraits::DirectLinearAccessType ActualOtherType; typedef typename internal::remove_all::type _ActualOtherType; @@ -94,15 +92,27 @@ struct selfadjoint_product_selector Scalar actualAlpha = alpha * OtherBlasTraits::extractScalarFactor(other.derived()); - enum { IsRowMajor = (internal::traits::Flags&RowMajorBit) ? 1 : 0 }; + enum { + IsRowMajor = (internal::traits::Flags&RowMajorBit) ? 1 : 0, + OtherIsRowMajor = _ActualOtherType::Flags&RowMajorBit ? 1 : 0 + }; + + Index size = mat.cols(); + Index depth = actualOther.cols(); + + typedef internal::gemm_blocking_space BlockingType; + + BlockingType blocking(size, size, depth, 1, false); + internal::general_matrix_matrix_triangular_product::IsComplex, - Scalar, _ActualOtherType::Flags&RowMajorBit ? ColMajor : RowMajor, (!OtherBlasTraits::NeedToConjugate) && NumTraits::IsComplex, - MatrixType::Flags&RowMajorBit ? RowMajor : ColMajor, UpLo> - ::run(mat.cols(), actualOther.cols(), + Scalar, OtherIsRowMajor ? RowMajor : ColMajor, OtherBlasTraits::NeedToConjugate && NumTraits::IsComplex, + Scalar, OtherIsRowMajor ? ColMajor : RowMajor, (!OtherBlasTraits::NeedToConjugate) && NumTraits::IsComplex, + IsRowMajor ? RowMajor : ColMajor, UpLo> + ::run(size, depth, &actualOther.coeffRef(0,0), actualOther.outerStride(), &actualOther.coeffRef(0,0), actualOther.outerStride(), - mat.data(), mat.outerStride(), actualAlpha); + mat.data(), mat.outerStride(), actualAlpha, blocking); } }; diff --git a/libs/eigen3/Eigen/src/Core/products/SelfadjointRank2Update.h b/libs/eigen3/Eigen/src/Core/products/SelfadjointRank2Update.h index 8594a97ce..2ae364111 100644 --- a/libs/eigen3/Eigen/src/Core/products/SelfadjointRank2Update.h +++ b/libs/eigen3/Eigen/src/Core/products/SelfadjointRank2Update.h @@ -79,11 +79,11 @@ ::rankUpdate(const MatrixBase& u, const MatrixBase& v, const if (IsRowMajor) actualAlpha = numext::conj(actualAlpha); - internal::selfadjoint_rank2_update_selector::type>::type, - typename internal::remove_all::type>::type, + typedef typename internal::remove_all::type>::type UType; + typedef typename internal::remove_all::type>::type VType; + internal::selfadjoint_rank2_update_selector - ::run(_expression().const_cast_derived().data(),_expression().outerStride(),actualU,actualV,actualAlpha); + ::run(_expression().const_cast_derived().data(),_expression().outerStride(),UType(actualU),VType(actualV),actualAlpha); return *this; } diff --git a/libs/eigen3/Eigen/src/Core/products/TriangularMatrixMatrix.h b/libs/eigen3/Eigen/src/Core/products/TriangularMatrixMatrix.h index 8110507b5..6ec5a8a0b 100644 --- a/libs/eigen3/Eigen/src/Core/products/TriangularMatrixMatrix.h +++ b/libs/eigen3/Eigen/src/Core/products/TriangularMatrixMatrix.h @@ -108,7 +108,7 @@ EIGEN_DONT_INLINE void product_triangular_matrix_matrix& blocking) { // strip zeros @@ -117,30 +117,36 @@ EIGEN_DONT_INLINE void product_triangular_matrix_matrix lhs(_lhs,lhsStride); - const_blas_data_mapper rhs(_rhs,rhsStride); + typedef const_blas_data_mapper LhsMapper; + typedef const_blas_data_mapper RhsMapper; + typedef blas_data_mapper ResMapper; + LhsMapper lhs(_lhs,lhsStride); + RhsMapper rhs(_rhs,rhsStride); + ResMapper res(_res, resStride); Index kc = blocking.kc(); // cache block size along the K direction Index mc = (std::min)(rows,blocking.mc()); // cache block size along the M direction + // The small panel size must not be larger than blocking size. + // Usually this should never be the case because SmallPanelWidth^2 is very small + // compared to L2 cache size, but let's be safe: + Index panelWidth = (std::min)(Index(SmallPanelWidth),(std::min)(kc,mc)); std::size_t sizeA = kc*mc; std::size_t sizeB = kc*cols; - std::size_t sizeW = kc*Traits::WorkSpaceFactor; ei_declare_aligned_stack_constructed_variable(Scalar, blockA, sizeA, blocking.blockA()); ei_declare_aligned_stack_constructed_variable(Scalar, blockB, sizeB, blocking.blockB()); - ei_declare_aligned_stack_constructed_variable(Scalar, blockW, sizeW, blocking.blockW()); - Matrix triangularBuffer; + Matrix triangularBuffer((internal::constructor_without_unaligned_array_assert())); triangularBuffer.setZero(); if((Mode&ZeroDiag)==ZeroDiag) triangularBuffer.diagonal().setZero(); else triangularBuffer.diagonal().setOnes(); - gebp_kernel gebp_kernel; - gemm_pack_lhs pack_lhs; - gemm_pack_rhs pack_rhs; + gebp_kernel gebp_kernel; + gemm_pack_lhs pack_lhs; + gemm_pack_rhs pack_rhs; for(Index k2=IsLower ? depth : 0; IsLower ? k2>0 : k2 skip it @@ -167,9 +173,9 @@ EIGEN_DONT_INLINE void product_triangular_matrix_matrix(actual_kc-k1, SmallPanelWidth); + Index actualPanelWidth = std::min(actual_kc-k1, panelWidth); Index lengthTarget = IsLower ? actual_kc-k1-actualPanelWidth : k1; Index startBlock = actual_k2+k1; Index blockBOffset = k1; @@ -184,20 +190,22 @@ EIGEN_DONT_INLINE void product_triangular_matrix_matrix0) { Index startTarget = IsLower ? actual_k2+k1+actualPanelWidth : actual_k2; - pack_lhs(blockA, &lhs(startTarget,startBlock), lhsStride, actualPanelWidth, lengthTarget); + pack_lhs(blockA, lhs.getSubMapper(startTarget,startBlock), actualPanelWidth, lengthTarget); - gebp_kernel(res+startTarget, resStride, blockA, blockB, lengthTarget, actualPanelWidth, cols, alpha, - actualPanelWidth, actual_kc, 0, blockBOffset, blockW); + gebp_kernel(res.getSubMapper(startTarget, 0), blockA, blockB, + lengthTarget, actualPanelWidth, cols, alpha, + actualPanelWidth, actual_kc, 0, blockBOffset); } } } @@ -208,10 +216,11 @@ EIGEN_DONT_INLINE void product_triangular_matrix_matrix() - (blockA, &lhs(i2, actual_k2), lhsStride, actual_kc, actual_mc); + gemm_pack_lhs() + (blockA, lhs.getSubMapper(i2, actual_k2), actual_kc, actual_mc); - gebp_kernel(res+i2, resStride, blockA, blockB, actual_mc, actual_kc, cols, alpha, -1, -1, 0, 0, blockW); + gebp_kernel(res.getSubMapper(i2, 0), blockA, blockB, actual_mc, + actual_kc, cols, alpha, -1, -1, 0, 0); } } } @@ -249,40 +258,43 @@ EIGEN_DONT_INLINE void product_triangular_matrix_matrix& blocking) { + const Index PacketBytes = packet_traits::size*sizeof(Scalar); // strip zeros Index diagSize = (std::min)(_cols,_depth); Index rows = _rows; Index depth = IsLower ? _depth : diagSize; Index cols = IsLower ? diagSize : _cols; - const_blas_data_mapper lhs(_lhs,lhsStride); - const_blas_data_mapper rhs(_rhs,rhsStride); + typedef const_blas_data_mapper LhsMapper; + typedef const_blas_data_mapper RhsMapper; + typedef blas_data_mapper ResMapper; + LhsMapper lhs(_lhs,lhsStride); + RhsMapper rhs(_rhs,rhsStride); + ResMapper res(_res, resStride); Index kc = blocking.kc(); // cache block size along the K direction Index mc = (std::min)(rows,blocking.mc()); // cache block size along the M direction std::size_t sizeA = kc*mc; - std::size_t sizeB = kc*cols; - std::size_t sizeW = kc*Traits::WorkSpaceFactor; + std::size_t sizeB = kc*cols+EIGEN_MAX_ALIGN_BYTES/sizeof(Scalar); ei_declare_aligned_stack_constructed_variable(Scalar, blockA, sizeA, blocking.blockA()); ei_declare_aligned_stack_constructed_variable(Scalar, blockB, sizeB, blocking.blockB()); - ei_declare_aligned_stack_constructed_variable(Scalar, blockW, sizeW, blocking.blockW()); - Matrix triangularBuffer; + Matrix triangularBuffer((internal::constructor_without_unaligned_array_assert())); triangularBuffer.setZero(); if((Mode&ZeroDiag)==ZeroDiag) triangularBuffer.diagonal().setZero(); else triangularBuffer.diagonal().setOnes(); - gebp_kernel gebp_kernel; - gemm_pack_lhs pack_lhs; - gemm_pack_rhs pack_rhs; - gemm_pack_rhs pack_rhs_panel; + gebp_kernel gebp_kernel; + gemm_pack_lhs pack_lhs; + gemm_pack_rhs pack_rhs; + gemm_pack_rhs pack_rhs_panel; for(Index k2=IsLower ? 0 : depth; IsLower ? k20; @@ -304,8 +316,9 @@ EIGEN_DONT_INLINE void product_triangular_matrix_matrix=cols) ? 0 : actual_kc; Scalar* geb = blockB+ts*ts; + geb = geb + internal::first_aligned(geb,PacketBytes/sizeof(Scalar)); - pack_rhs(geb, &rhs(actual_k2,IsLower ? 0 : k2), rhsStride, actual_kc, rs); + pack_rhs(geb, rhs.getSubMapper(actual_k2,IsLower ? 0 : k2), actual_kc, rs); // pack the triangular part of the rhs padding the unrolled blocks with zeros if(ts>0) @@ -318,7 +331,7 @@ EIGEN_DONT_INLINE void product_triangular_matrix_matrix0) @@ -352,19 +365,18 @@ EIGEN_DONT_INLINE void product_triangular_matrix_matrix -struct traits > - : traits, Lhs, Rhs> > -{}; - } // end namespace internal +namespace internal { template -struct TriangularProduct - : public ProductBase, Lhs, Rhs > +struct triangular_product_impl { - EIGEN_PRODUCT_PUBLIC_INTERFACE(TriangularProduct) - - TriangularProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} - - template void scaleAndAddTo(Dest& dst, const Scalar& alpha) const + template static void run(Dest& dst, const Lhs &a_lhs, const Rhs &a_rhs, const typename Dest::Scalar& alpha) { - typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(m_lhs); - typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(m_rhs); + typedef typename Dest::Scalar Scalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef typename internal::remove_all::type ActualLhsTypeCleaned; + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + typedef typename internal::remove_all::type ActualRhsTypeCleaned; + + typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(a_lhs); + typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(a_rhs); - Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(m_lhs) - * RhsBlasTraits::extractScalarFactor(m_rhs); + Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(a_lhs) + * RhsBlasTraits::extractScalarFactor(a_rhs); typedef internal::gemm_blocking_space<(Dest::Flags&RowMajorBit) ? RowMajor : ColMajor,Scalar,Scalar, Lhs::MaxRowsAtCompileTime, Rhs::MaxColsAtCompileTime, Lhs::MaxColsAtCompileTime,4> BlockingType; @@ -405,23 +417,25 @@ struct TriangularProduct Index stripedDepth = LhsIsTriangular ? ((!IsLower) ? lhs.cols() : (std::min)(lhs.cols(),lhs.rows())) : ((IsLower) ? rhs.rows() : (std::min)(rhs.rows(),rhs.cols())); - BlockingType blocking(stripedRows, stripedCols, stripedDepth); + BlockingType blocking(stripedRows, stripedCols, stripedDepth, 1, false); internal::product_triangular_matrix_matrix::Flags&RowMajorBit) ? RowMajor : ColMajor, LhsBlasTraits::NeedToConjugate, - (internal::traits<_ActualRhsType>::Flags&RowMajorBit) ? RowMajor : ColMajor, RhsBlasTraits::NeedToConjugate, + (internal::traits::Flags&RowMajorBit) ? RowMajor : ColMajor, LhsBlasTraits::NeedToConjugate, + (internal::traits::Flags&RowMajorBit) ? RowMajor : ColMajor, RhsBlasTraits::NeedToConjugate, (internal::traits::Flags&RowMajorBit) ? RowMajor : ColMajor> ::run( stripedRows, stripedCols, stripedDepth, // sizes - &lhs.coeffRef(0,0), lhs.outerStride(), // lhs info - &rhs.coeffRef(0,0), rhs.outerStride(), // rhs info + &lhs.coeffRef(0,0), lhs.outerStride(), // lhs info + &rhs.coeffRef(0,0), rhs.outerStride(), // rhs info &dst.coeffRef(0,0), dst.outerStride(), // result info actualAlpha, blocking ); } }; +} // end namespace internal + } // end namespace Eigen #endif // EIGEN_TRIANGULAR_MATRIX_MATRIX_H diff --git a/libs/eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h b/libs/eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_BLAS.h similarity index 76% rename from libs/eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h rename to libs/eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_BLAS.h index ba41a1c99..aecded6bb 100644 --- a/libs/eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h +++ b/libs/eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_BLAS.h @@ -25,13 +25,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************** - * Content : Eigen bindings to Intel(R) MKL + * Content : Eigen bindings to BLAS F77 * Triangular matrix * matrix product functionality based on ?TRMM. ******************************************************************************** */ -#ifndef EIGEN_TRIANGULAR_MATRIX_MATRIX_MKL_H -#define EIGEN_TRIANGULAR_MATRIX_MATRIX_MKL_H +#ifndef EIGEN_TRIANGULAR_MATRIX_MATRIX_BLAS_H +#define EIGEN_TRIANGULAR_MATRIX_MATRIX_BLAS_H namespace Eigen { @@ -50,7 +50,7 @@ struct product_triangular_matrix_matrix_trmm : // try to go to BLAS specialization -#define EIGEN_MKL_TRMM_SPECIALIZE(Scalar, LhsIsTriangular) \ +#define EIGEN_BLAS_TRMM_SPECIALIZE(Scalar, LhsIsTriangular) \ template \ @@ -65,17 +65,17 @@ struct product_triangular_matrix_matrix \ @@ -106,13 +106,14 @@ struct product_triangular_matrix_matrix_trmm MatrixLhs; \ typedef Matrix MatrixRhs; \ \ -/* Non-square case - doesn't fit to MKL ?TRMM. Fall to default triangular product or call MKL ?GEMM*/ \ +/* Non-square case - doesn't fit to BLAS ?TRMM. Fall to default triangular product or call BLAS ?GEMM*/ \ if (rows != depth) { \ \ - int nthr = mkl_domain_get_max_threads(MKL_BLAS); \ + /* FIXME handle mkl_domain_get_max_threads */ \ + /*int nthr = mkl_domain_get_max_threads(EIGEN_BLAS_DOMAIN_BLAS);*/ int nthr = 1;\ \ if (((nthr==1) && (((std::max)(rows,depth)-diagSize)/(double)diagSize < 0.5))) { \ - /* Most likely no benefit to call TRMM or GEMM from MKL*/ \ + /* Most likely no benefit to call TRMM or GEMM from BLAS */ \ product_triangular_matrix_matrix::run( \ _rows, _cols, _depth, _lhs, lhsStride, _rhs, rhsStride, res, resStride, alpha, blocking); \ @@ -121,27 +122,23 @@ struct product_triangular_matrix_matrix_trmm > lhsMap(_lhs,rows,depth,OuterStride<>(lhsStride)); \ MatrixLhs aa_tmp=lhsMap.template triangularView(); \ - MKL_INT aStride = aa_tmp.outerStride(); \ - gemm_blocking_space gemm_blocking(_rows,_cols,_depth); \ + BlasIndex aStride = convert_index(aa_tmp.outerStride()); \ + gemm_blocking_space gemm_blocking(_rows,_cols,_depth, 1, true); \ general_matrix_matrix_product::run( \ rows, cols, depth, aa_tmp.data(), aStride, _rhs, rhsStride, res, resStride, alpha, gemm_blocking, 0); \ \ - /*std::cout << "TRMM_L: A is not square! Go to MKL GEMM implementation! " << nthr<<" \n";*/ \ + /*std::cout << "TRMM_L: A is not square! Go to BLAS GEMM implementation! " << nthr<<" \n";*/ \ } \ return; \ } \ char side = 'L', transa, uplo, diag = 'N'; \ EIGTYPE *b; \ const EIGTYPE *a; \ - MKL_INT m, n, lda, ldb; \ - MKLTYPE alpha_; \ -\ -/* Set alpha_*/ \ - assign_scalar_eig2mkl(alpha_, alpha); \ + BlasIndex m, n, lda, ldb; \ \ /* Set m, n */ \ - m = (MKL_INT)diagSize; \ - n = (MKL_INT)cols; \ + m = convert_index(diagSize); \ + n = convert_index(cols); \ \ /* Set trans */ \ transa = (LhsStorageOrder==RowMajor) ? ((ConjugateLhs) ? 'C' : 'T') : 'N'; \ @@ -152,7 +149,7 @@ struct product_triangular_matrix_matrix_trmm(b_tmp.outerStride()); \ \ /* Set uplo */ \ uplo = IsLower ? 'L' : 'U'; \ @@ -168,14 +165,14 @@ struct product_triangular_matrix_matrix_trmm(a_tmp.outerStride()); \ } else { \ a = _lhs; \ - lda = lhsStride; \ + lda = convert_index(lhsStride); \ } \ - /*std::cout << "TRMM_L: A is square! Go to MKL TRMM implementation! \n";*/ \ + /*std::cout << "TRMM_L: A is square! Go to BLAS TRMM implementation! \n";*/ \ /* call ?trmm*/ \ - MKLPREFIX##trmm(&side, &uplo, &transa, &diag, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (MKLTYPE*)b, &ldb); \ + BLASPREFIX##trmm_(&side, &uplo, &transa, &diag, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (BLASTYPE*)b, &ldb); \ \ /* Add op(a_triangular)*b into res*/ \ Map > res_tmp(res,rows,cols,OuterStride<>(resStride)); \ @@ -183,13 +180,13 @@ struct product_triangular_matrix_matrix_trmm \ @@ -220,13 +217,13 @@ struct product_triangular_matrix_matrix_trmm MatrixLhs; \ typedef Matrix MatrixRhs; \ \ -/* Non-square case - doesn't fit to MKL ?TRMM. Fall to default triangular product or call MKL ?GEMM*/ \ +/* Non-square case - doesn't fit to BLAS ?TRMM. Fall to default triangular product or call BLAS ?GEMM*/ \ if (cols != depth) { \ \ - int nthr = mkl_domain_get_max_threads(MKL_BLAS); \ + int nthr = 1 /*mkl_domain_get_max_threads(EIGEN_BLAS_DOMAIN_BLAS)*/; \ \ if ((nthr==1) && (((std::max)(cols,depth)-diagSize)/(double)diagSize < 0.5)) { \ - /* Most likely no benefit to call TRMM or GEMM from MKL*/ \ + /* Most likely no benefit to call TRMM or GEMM from BLAS*/ \ product_triangular_matrix_matrix::run( \ _rows, _cols, _depth, _lhs, lhsStride, _rhs, rhsStride, res, resStride, alpha, blocking); \ @@ -235,27 +232,23 @@ struct product_triangular_matrix_matrix_trmm > rhsMap(_rhs,depth,cols, OuterStride<>(rhsStride)); \ MatrixRhs aa_tmp=rhsMap.template triangularView(); \ - MKL_INT aStride = aa_tmp.outerStride(); \ - gemm_blocking_space gemm_blocking(_rows,_cols,_depth); \ + BlasIndex aStride = convert_index(aa_tmp.outerStride()); \ + gemm_blocking_space gemm_blocking(_rows,_cols,_depth, 1, true); \ general_matrix_matrix_product::run( \ rows, cols, depth, _lhs, lhsStride, aa_tmp.data(), aStride, res, resStride, alpha, gemm_blocking, 0); \ \ - /*std::cout << "TRMM_R: A is not square! Go to MKL GEMM implementation! " << nthr<<" \n";*/ \ + /*std::cout << "TRMM_R: A is not square! Go to BLAS GEMM implementation! " << nthr<<" \n";*/ \ } \ return; \ } \ char side = 'R', transa, uplo, diag = 'N'; \ EIGTYPE *b; \ const EIGTYPE *a; \ - MKL_INT m, n, lda, ldb; \ - MKLTYPE alpha_; \ -\ -/* Set alpha_*/ \ - assign_scalar_eig2mkl(alpha_, alpha); \ + BlasIndex m, n, lda, ldb; \ \ /* Set m, n */ \ - m = (MKL_INT)rows; \ - n = (MKL_INT)diagSize; \ + m = convert_index(rows); \ + n = convert_index(diagSize); \ \ /* Set trans */ \ transa = (RhsStorageOrder==RowMajor) ? ((ConjugateRhs) ? 'C' : 'T') : 'N'; \ @@ -266,7 +259,7 @@ struct product_triangular_matrix_matrix_trmm(b_tmp.outerStride()); \ \ /* Set uplo */ \ uplo = IsLower ? 'L' : 'U'; \ @@ -282,14 +275,14 @@ struct product_triangular_matrix_matrix_trmm(a_tmp.outerStride()); \ } else { \ a = _rhs; \ - lda = rhsStride; \ + lda = convert_index(rhsStride); \ } \ - /*std::cout << "TRMM_R: A is square! Go to MKL TRMM implementation! \n";*/ \ + /*std::cout << "TRMM_R: A is square! Go to BLAS TRMM implementation! \n";*/ \ /* call ?trmm*/ \ - MKLPREFIX##trmm(&side, &uplo, &transa, &diag, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (MKLTYPE*)b, &ldb); \ + BLASPREFIX##trmm_(&side, &uplo, &transa, &diag, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (BLASTYPE*)b, &ldb); \ \ /* Add op(a_triangular)*b into res*/ \ Map > res_tmp(res,rows,cols,OuterStride<>(resStride)); \ @@ -297,13 +290,13 @@ struct product_triangular_matrix_matrix_trmm struct triangular_matrix_vector_product { - typedef typename scalar_product_traits::ReturnType ResScalar; + typedef typename ScalarBinaryOpTraits::ReturnType ResScalar; enum { IsLower = ((Mode&Lower)==Lower), HasUnitDiag = (Mode & UnitDiag)==UnitDiag, HasZeroDiag = (Mode & ZeroDiag)==ZeroDiag }; static EIGEN_DONT_INLINE void run(Index _rows, Index _cols, const LhsScalar* _lhs, Index lhsStride, - const RhsScalar* _rhs, Index rhsIncr, ResScalar* _res, Index resIncr, const ResScalar& alpha); + const RhsScalar* _rhs, Index rhsIncr, ResScalar* _res, Index resIncr, const RhsScalar& alpha); }; template EIGEN_DONT_INLINE void triangular_matrix_vector_product ::run(Index _rows, Index _cols, const LhsScalar* _lhs, Index lhsStride, - const RhsScalar* _rhs, Index rhsIncr, ResScalar* _res, Index resIncr, const ResScalar& alpha) + const RhsScalar* _rhs, Index rhsIncr, ResScalar* _res, Index resIncr, const RhsScalar& alpha) { static const Index PanelWidth = EIGEN_TUNE_TRIANGULAR_PANEL_WIDTH; Index size = (std::min)(_rows,_cols); @@ -43,7 +43,7 @@ EIGEN_DONT_INLINE void triangular_matrix_vector_product, 0, OuterStride<> > LhsMap; const LhsMap lhs(_lhs,rows,cols,OuterStride<>(lhsStride)); typename conj_expr_if::type cjLhs(lhs); - + typedef Map, 0, InnerStride<> > RhsMap; const RhsMap rhs(_rhs,cols,InnerStride<>(rhsIncr)); typename conj_expr_if::type cjRhs(rhs); @@ -51,6 +51,9 @@ EIGEN_DONT_INLINE void triangular_matrix_vector_product > ResMap; ResMap res(_res,rows); + typedef const_blas_data_mapper LhsMapper; + typedef const_blas_data_mapper RhsMapper; + for (Index pi=0; pi0) { Index s = IsLower ? pi+actualPanelWidth : 0; - general_matrix_vector_product::run( + general_matrix_vector_product::run( r, actualPanelWidth, - &lhs.coeffRef(s,pi), lhsStride, - &rhs.coeffRef(pi), rhsIncr, + LhsMapper(&lhs.coeffRef(s,pi), lhsStride), + RhsMapper(&rhs.coeffRef(pi), rhsIncr), &res.coeffRef(s), resIncr, alpha); } } if((!IsLower) && cols>size) { - general_matrix_vector_product::run( + general_matrix_vector_product::run( rows, cols-size, - &lhs.coeffRef(0,size), lhsStride, - &rhs.coeffRef(size), rhsIncr, + LhsMapper(&lhs.coeffRef(0,size), lhsStride), + RhsMapper(&rhs.coeffRef(size), rhsIncr), _res, resIncr, alpha); } } @@ -88,7 +91,7 @@ EIGEN_DONT_INLINE void triangular_matrix_vector_product struct triangular_matrix_vector_product { - typedef typename scalar_product_traits::ReturnType ResScalar; + typedef typename ScalarBinaryOpTraits::ReturnType ResScalar; enum { IsLower = ((Mode&Lower)==Lower), HasUnitDiag = (Mode & UnitDiag)==UnitDiag, @@ -118,7 +121,10 @@ EIGEN_DONT_INLINE void triangular_matrix_vector_product, 0, InnerStride<> > ResMap; ResMap res(_res,rows,InnerStride<>(resIncr)); - + + typedef const_blas_data_mapper LhsMapper; + typedef const_blas_data_mapper RhsMapper; + for (Index pi=0; pi0) { Index s = IsLower ? 0 : pi + actualPanelWidth; - general_matrix_vector_product::run( + general_matrix_vector_product::run( actualPanelWidth, r, - &lhs.coeffRef(pi,s), lhsStride, - &rhs.coeffRef(s), rhsIncr, + LhsMapper(&lhs.coeffRef(pi,s), lhsStride), + RhsMapper(&rhs.coeffRef(s), rhsIncr), &res.coeffRef(pi), resIncr, alpha); } } if(IsLower && rows>diagSize) { - general_matrix_vector_product::run( + general_matrix_vector_product::run( rows-diagSize, cols, - &lhs.coeffRef(diagSize,0), lhsStride, - &rhs.coeffRef(0), rhsIncr, + LhsMapper(&lhs.coeffRef(diagSize,0), lhsStride), + RhsMapper(&rhs.coeffRef(0), rhsIncr), &res.coeffRef(diagSize), resIncr, alpha); } } @@ -157,83 +163,66 @@ EIGEN_DONT_INLINE void triangular_matrix_vector_product -struct traits > - : traits, Lhs, Rhs> > -{}; - -template -struct traits > - : traits, Lhs, Rhs> > -{}; - - -template +template struct trmv_selector; } // end namespace internal +namespace internal { + template -struct TriangularProduct - : public ProductBase, Lhs, Rhs > +struct triangular_product_impl { - EIGEN_PRODUCT_PUBLIC_INTERFACE(TriangularProduct) - - TriangularProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} - - template void scaleAndAddTo(Dest& dst, const Scalar& alpha) const + template static void run(Dest& dst, const Lhs &lhs, const Rhs &rhs, const typename Dest::Scalar& alpha) { - eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); + eigen_assert(dst.rows()==lhs.rows() && dst.cols()==rhs.cols()); - internal::trmv_selector<(int(internal::traits::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(*this, dst, alpha); + internal::trmv_selector::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(lhs, rhs, dst, alpha); } }; template -struct TriangularProduct - : public ProductBase, Lhs, Rhs > +struct triangular_product_impl { - EIGEN_PRODUCT_PUBLIC_INTERFACE(TriangularProduct) - - TriangularProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} - - template void scaleAndAddTo(Dest& dst, const Scalar& alpha) const + template static void run(Dest& dst, const Lhs &lhs, const Rhs &rhs, const typename Dest::Scalar& alpha) { - eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); + eigen_assert(dst.rows()==lhs.rows() && dst.cols()==rhs.cols()); - typedef TriangularProduct<(Mode & (UnitDiag|ZeroDiag)) | ((Mode & Lower) ? Upper : Lower),true,Transpose,false,Transpose,true> TriangularProductTranspose; Transpose dstT(dst); - internal::trmv_selector<(int(internal::traits::Flags)&RowMajorBit) ? ColMajor : RowMajor>::run( - TriangularProductTranspose(m_rhs.transpose(),m_lhs.transpose()), dstT, alpha); + internal::trmv_selector<(Mode & (UnitDiag|ZeroDiag)) | ((Mode & Lower) ? Upper : Lower), + (int(internal::traits::Flags)&RowMajorBit) ? ColMajor : RowMajor> + ::run(rhs.transpose(),lhs.transpose(), dstT, alpha); } }; +} // end namespace internal + namespace internal { // TODO: find a way to factorize this piece of code with gemv_selector since the logic is exactly the same. -template<> struct trmv_selector +template struct trmv_selector { - template - static void run(const TriangularProduct& prod, Dest& dest, const typename TriangularProduct::Scalar& alpha) + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) { - typedef TriangularProduct ProductType; - typedef typename ProductType::Index Index; - typedef typename ProductType::LhsScalar LhsScalar; - typedef typename ProductType::RhsScalar RhsScalar; - typedef typename ProductType::Scalar ResScalar; - typedef typename ProductType::RealScalar RealScalar; - typedef typename ProductType::ActualLhsType ActualLhsType; - typedef typename ProductType::ActualRhsType ActualRhsType; - typedef typename ProductType::LhsBlasTraits LhsBlasTraits; - typedef typename ProductType::RhsBlasTraits RhsBlasTraits; - typedef Map, Aligned> MappedDest; - - typename internal::add_const_on_value_type::type actualLhs = LhsBlasTraits::extract(prod.lhs()); - typename internal::add_const_on_value_type::type actualRhs = RhsBlasTraits::extract(prod.rhs()); - - ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) - * RhsBlasTraits::extractScalarFactor(prod.rhs()); + typedef typename Lhs::Scalar LhsScalar; + typedef typename Rhs::Scalar RhsScalar; + typedef typename Dest::Scalar ResScalar; + typedef typename Dest::RealScalar RealScalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + + typedef Map, EIGEN_PLAIN_ENUM_MIN(AlignedMax,internal::packet_traits::size)> MappedDest; + + typename internal::add_const_on_value_type::type actualLhs = LhsBlasTraits::extract(lhs); + typename internal::add_const_on_value_type::type actualRhs = RhsBlasTraits::extract(rhs); + + ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(lhs) + * RhsBlasTraits::extractScalarFactor(rhs); enum { // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 @@ -247,7 +236,7 @@ template<> struct trmv_selector bool alphaIsCompatible = (!ComplexByReal) || (numext::imag(actualAlpha)==RealScalar(0)); bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible; - + RhsScalar compatibleAlpha = get_factor::run(actualAlpha); ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(), @@ -267,7 +256,7 @@ template<> struct trmv_selector else MappedDest(actualDestPtr, dest.size()) = dest; } - + internal::triangular_matrix_vector_product struct trmv_selector } }; -template<> struct trmv_selector +template struct trmv_selector { - template - static void run(const TriangularProduct& prod, Dest& dest, const typename TriangularProduct::Scalar& alpha) + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) { - typedef TriangularProduct ProductType; - typedef typename ProductType::LhsScalar LhsScalar; - typedef typename ProductType::RhsScalar RhsScalar; - typedef typename ProductType::Scalar ResScalar; - typedef typename ProductType::Index Index; - typedef typename ProductType::ActualLhsType ActualLhsType; - typedef typename ProductType::ActualRhsType ActualRhsType; - typedef typename ProductType::_ActualRhsType _ActualRhsType; - typedef typename ProductType::LhsBlasTraits LhsBlasTraits; - typedef typename ProductType::RhsBlasTraits RhsBlasTraits; - - typename add_const::type actualLhs = LhsBlasTraits::extract(prod.lhs()); - typename add_const::type actualRhs = RhsBlasTraits::extract(prod.rhs()); - - ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) - * RhsBlasTraits::extractScalarFactor(prod.rhs()); + typedef typename Lhs::Scalar LhsScalar; + typedef typename Rhs::Scalar RhsScalar; + typedef typename Dest::Scalar ResScalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + typedef typename internal::remove_all::type ActualRhsTypeCleaned; + + typename add_const::type actualLhs = LhsBlasTraits::extract(lhs); + typename add_const::type actualRhs = RhsBlasTraits::extract(rhs); + + ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(lhs) + * RhsBlasTraits::extractScalarFactor(rhs); enum { - DirectlyUseRhs = _ActualRhsType::InnerStrideAtCompileTime==1 + DirectlyUseRhs = ActualRhsTypeCleaned::InnerStrideAtCompileTime==1 }; - gemv_static_vector_if static_rhs; + gemv_static_vector_if static_rhs; ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,actualRhs.size(), DirectlyUseRhs ? const_cast(actualRhs.data()) : static_rhs.data()); @@ -322,12 +310,12 @@ template<> struct trmv_selector if(!DirectlyUseRhs) { #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - int size = actualRhs.size(); + Index size = actualRhs.size(); EIGEN_DENSE_STORAGE_CTOR_PLUGIN #endif - Map(actualRhsPtr, actualRhs.size()) = actualRhs; + Map(actualRhsPtr, actualRhs.size()) = actualRhs; } - + internal::triangular_matrix_vector_product {}; -#define EIGEN_MKL_TRMV_SPECIALIZE(Scalar) \ +#define EIGEN_BLAS_TRMV_SPECIALIZE(Scalar) \ template \ struct triangular_matrix_vector_product { \ static void run(Index _rows, Index _cols, const Scalar* _lhs, Index lhsStride, \ @@ -65,13 +65,13 @@ struct triangular_matrix_vector_product \ struct triangular_matrix_vector_product_trmv { \ enum { \ @@ -105,17 +105,15 @@ struct triangular_matrix_vector_product_trmv(alpha_, alpha); \ - assign_scalar_eig2mkl(beta_, EIGTYPE(1)); \ + EIGTYPE beta(1); \ \ /* Set m, n */ \ - n = (MKL_INT)size; \ - lda = lhsStride; \ + n = convert_index(size); \ + lda = convert_index(lhsStride); \ incx = 1; \ - incy = resIncr; \ + incy = convert_index(resIncr); \ \ /* Set uplo, trans and diag*/ \ trans = 'N'; \ @@ -123,40 +121,39 @@ struct triangular_matrix_vector_product_trmv MatrixLhs; \ if (ConjRhs) x_tmp = rhs.conjugate(); else x_tmp = rhs; \ x = x_tmp.data(); \ if (size(rows-size); \ + n = convert_index(size); \ } \ else { \ x += size; \ y = _res; \ a = _lhs + size*lda; \ - m = size; \ - n = cols-size; \ + m = convert_index(size); \ + n = convert_index(cols-size); \ } \ - MKLPREFIX##gemv(&trans, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)x, &incx, &beta_, (MKLTYPE*)y, &incy); \ + BLASPREFIX##gemv_(&trans, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)x, &incx, &numext::real_ref(beta), (BLASTYPE*)y, &incy); \ } \ } \ }; -EIGEN_MKL_TRMV_CM(double, double, d, d) -EIGEN_MKL_TRMV_CM(dcomplex, MKL_Complex16, cd, z) -EIGEN_MKL_TRMV_CM(float, float, f, s) -EIGEN_MKL_TRMV_CM(scomplex, MKL_Complex8, cf, c) +EIGEN_BLAS_TRMV_CM(double, double, d, d) +EIGEN_BLAS_TRMV_CM(dcomplex, double, cd, z) +EIGEN_BLAS_TRMV_CM(float, float, f, s) +EIGEN_BLAS_TRMV_CM(scomplex, float, cf, c) // implements row-major: res += alpha * op(triangular) * vector -#define EIGEN_MKL_TRMV_RM(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \ +#define EIGEN_BLAS_TRMV_RM(EIGTYPE, BLASTYPE, EIGPREFIX, BLASPREFIX) \ template \ struct triangular_matrix_vector_product_trmv { \ enum { \ @@ -190,17 +187,15 @@ struct triangular_matrix_vector_product_trmv(alpha_, alpha); \ - assign_scalar_eig2mkl(beta_, EIGTYPE(1)); \ + EIGTYPE beta(1); \ \ /* Set m, n */ \ - n = (MKL_INT)size; \ - lda = lhsStride; \ + n = convert_index(size); \ + lda = convert_index(lhsStride); \ incx = 1; \ - incy = resIncr; \ + incy = convert_index(resIncr); \ \ /* Set uplo, trans and diag*/ \ trans = ConjLhs ? 'C' : 'T'; \ @@ -208,40 +203,39 @@ struct triangular_matrix_vector_product_trmv MatrixLhs; \ if (ConjRhs) x_tmp = rhs.conjugate(); else x_tmp = rhs; \ x = x_tmp.data(); \ if (size(rows-size); \ + n = convert_index(size); \ } \ else { \ x += size; \ y = _res; \ a = _lhs + size; \ - m = size; \ - n = cols-size; \ + m = convert_index(size); \ + n = convert_index(cols-size); \ } \ - MKLPREFIX##gemv(&trans, &n, &m, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)x, &incx, &beta_, (MKLTYPE*)y, &incy); \ + BLASPREFIX##gemv_(&trans, &n, &m, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)x, &incx, &numext::real_ref(beta), (BLASTYPE*)y, &incy); \ } \ } \ }; -EIGEN_MKL_TRMV_RM(double, double, d, d) -EIGEN_MKL_TRMV_RM(dcomplex, MKL_Complex16, cd, z) -EIGEN_MKL_TRMV_RM(float, float, f, s) -EIGEN_MKL_TRMV_RM(scomplex, MKL_Complex8, cf, c) +EIGEN_BLAS_TRMV_RM(double, double, d, d) +EIGEN_BLAS_TRMV_RM(dcomplex, double, cd, z) +EIGEN_BLAS_TRMV_RM(float, float, f, s) +EIGEN_BLAS_TRMV_RM(scomplex, float, cf, c) } // end namespase internal } // end namespace Eigen -#endif // EIGEN_TRIANGULAR_MATRIX_VECTOR_MKL_H +#endif // EIGEN_TRIANGULAR_MATRIX_VECTOR_BLAS_H diff --git a/libs/eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h b/libs/eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h index f103eae72..223c38b86 100644 --- a/libs/eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h +++ b/libs/eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h @@ -52,10 +52,14 @@ EIGEN_DONT_INLINE void triangular_solve_matrix& blocking) { Index cols = otherSize; - const_blas_data_mapper tri(_tri,triStride); - blas_data_mapper other(_other,otherStride); + + typedef const_blas_data_mapper TriMapper; + typedef blas_data_mapper OtherMapper; + TriMapper tri(_tri, triStride); + OtherMapper other(_other, otherStride); typedef gebp_traits Traits; + enum { SmallPanelWidth = EIGEN_PLAIN_ENUM_MAX(Traits::mr,Traits::nr), IsLower = (Mode&Lower) == Lower @@ -66,22 +70,20 @@ EIGEN_DONT_INLINE void triangular_solve_matrix conj; - gebp_kernel gebp_kernel; - gemm_pack_lhs pack_lhs; - gemm_pack_rhs pack_rhs; + gebp_kernel gebp_kernel; + gemm_pack_lhs pack_lhs; + gemm_pack_rhs pack_rhs; // the goal here is to subdivise the Rhs panels such that we keep some cache // coherence when accessing the rhs elements - std::ptrdiff_t l1, l2; - manage_caching_sizes(GetAction, &l1, &l2); - Index subcols = cols>0 ? l2/(4 * sizeof(Scalar) * otherStride) : 0; + std::ptrdiff_t l1, l2, l3; + manage_caching_sizes(GetAction, &l1, &l2, &l3); + Index subcols = cols>0 ? l2/(4 * sizeof(Scalar) * std::max(otherStride,size)) : 0; subcols = std::max((subcols/Traits::nr)*Traits::nr, Traits::nr); for(Index k2=IsLower ? 0 : size; @@ -115,8 +117,9 @@ EIGEN_DONT_INLINE void triangular_solve_matrix0) { Index startTarget = IsLower ? k2+k1+actualPanelWidth : k2-actual_kc; - pack_lhs(blockA, &tri(startTarget,startBlock), triStride, actualPanelWidth, lengthTarget); + pack_lhs(blockA, tri.getSubMapper(startTarget,startBlock), actualPanelWidth, lengthTarget); - gebp_kernel(&other(startTarget,j2), otherStride, blockA, blockB+actual_kc*j2, lengthTarget, actualPanelWidth, actual_cols, Scalar(-1), - actualPanelWidth, actual_kc, 0, blockBOffset, blockW); + gebp_kernel(other.getSubMapper(startTarget,j2), blockA, blockB+actual_kc*j2, lengthTarget, actualPanelWidth, actual_cols, Scalar(-1), + actualPanelWidth, actual_kc, 0, blockBOffset); } } } @@ -172,16 +174,16 @@ EIGEN_DONT_INLINE void triangular_solve_matrix0) { - pack_lhs(blockA, &tri(i2, IsLower ? k2 : k2-kc), triStride, actual_kc, actual_mc); + pack_lhs(blockA, tri.getSubMapper(i2, IsLower ? k2 : k2-kc), actual_kc, actual_mc); - gebp_kernel(_other+i2, otherStride, blockA, blockB, actual_mc, actual_kc, cols, Scalar(-1), -1, -1, 0, 0, blockW); + gebp_kernel(other.getSubMapper(i2, 0), blockA, blockB, actual_mc, actual_kc, cols, Scalar(-1), -1, -1, 0, 0); } } } } } -/* Optimized triangular solver with multiple left hand sides and the trinagular matrix on the right +/* Optimized triangular solver with multiple left hand sides and the triangular matrix on the right */ template struct triangular_solve_matrix @@ -200,8 +202,12 @@ EIGEN_DONT_INLINE void triangular_solve_matrix& blocking) { Index rows = otherSize; - const_blas_data_mapper rhs(_tri,triStride); - blas_data_mapper lhs(_other,otherStride); + typedef typename NumTraits::Real RealScalar; + + typedef blas_data_mapper LhsMapper; + typedef const_blas_data_mapper RhsMapper; + LhsMapper lhs(_other, otherStride); + RhsMapper rhs(_tri, triStride); typedef gebp_traits Traits; enum { @@ -215,17 +221,15 @@ EIGEN_DONT_INLINE void triangular_solve_matrix conj; - gebp_kernel gebp_kernel; - gemm_pack_rhs pack_rhs; - gemm_pack_rhs pack_rhs_panel; - gemm_pack_lhs pack_lhs_panel; + gebp_kernel gebp_kernel; + gemm_pack_rhs pack_rhs; + gemm_pack_rhs pack_rhs_panel; + gemm_pack_lhs pack_lhs_panel; for(Index k2=IsLower ? size : 0; IsLower ? k2>0 : k20) pack_rhs(geb, &rhs(actual_k2,startPanel), triStride, actual_kc, rs); + if (rs>0) pack_rhs(geb, rhs.getSubMapper(actual_k2,startPanel), actual_kc, rs); // triangular packing (we only pack the panels off the diagonal, // neglecting the blocks overlapping the diagonal @@ -252,7 +256,7 @@ EIGEN_DONT_INLINE void triangular_solve_matrix0) pack_rhs_panel(blockB+j2*actual_kc, - &rhs(actual_k2+panelOffset, actual_j2), triStride, + rhs.getSubMapper(actual_k2+panelOffset, actual_j2), panelLength, actualPanelWidth, actual_kc, panelOffset); } @@ -280,13 +284,12 @@ EIGEN_DONT_INLINE void triangular_solve_matrix0) { - gebp_kernel(&lhs(i2,absolute_j2), otherStride, + gebp_kernel(lhs.getSubMapper(i2,absolute_j2), blockA, blockB+j2*actual_kc, actual_mc, panelLength, actualPanelWidth, Scalar(-1), actual_kc, actual_kc, // strides - panelOffset, panelOffset, // offsets - blockW); // workspace + panelOffset, panelOffset); // offsets } // unblocked triangular solve @@ -302,22 +305,25 @@ EIGEN_DONT_INLINE void triangular_solve_matrix0) - gebp_kernel(_other+i2+startPanel*otherStride, otherStride, blockA, geb, + gebp_kernel(lhs.getSubMapper(i2, startPanel), blockA, geb, actual_mc, actual_kc, rs, Scalar(-1), - -1, -1, 0, 0, blockW); + -1, -1, 0, 0); } } } diff --git a/libs/eigen3/Eigen/src/Core/products/TriangularSolverMatrix_MKL.h b/libs/eigen3/Eigen/src/Core/products/TriangularSolverMatrix_BLAS.h similarity index 75% rename from libs/eigen3/Eigen/src/Core/products/TriangularSolverMatrix_MKL.h rename to libs/eigen3/Eigen/src/Core/products/TriangularSolverMatrix_BLAS.h index 6a0bb8339..88c0fb794 100644 --- a/libs/eigen3/Eigen/src/Core/products/TriangularSolverMatrix_MKL.h +++ b/libs/eigen3/Eigen/src/Core/products/TriangularSolverMatrix_BLAS.h @@ -25,20 +25,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************** - * Content : Eigen bindings to Intel(R) MKL + * Content : Eigen bindings to BLAS F77 * Triangular matrix * matrix product functionality based on ?TRMM. ******************************************************************************** */ -#ifndef EIGEN_TRIANGULAR_SOLVER_MATRIX_MKL_H -#define EIGEN_TRIANGULAR_SOLVER_MATRIX_MKL_H +#ifndef EIGEN_TRIANGULAR_SOLVER_MATRIX_BLAS_H +#define EIGEN_TRIANGULAR_SOLVER_MATRIX_BLAS_H namespace Eigen { namespace internal { // implements LeftSide op(triangular)^-1 * general -#define EIGEN_MKL_TRSM_L(EIGTYPE, MKLTYPE, MKLPREFIX) \ +#define EIGEN_BLAS_TRSM_L(EIGTYPE, BLASTYPE, BLASPREFIX) \ template \ struct triangular_solve_matrix \ { \ @@ -53,13 +53,11 @@ struct triangular_solve_matrix& /*blocking*/) \ { \ - MKL_INT m = size, n = otherSize, lda, ldb; \ + BlasIndex m = convert_index(size), n = convert_index(otherSize), lda, ldb; \ char side = 'L', uplo, diag='N', transa; \ /* Set alpha_ */ \ - MKLTYPE alpha; \ - EIGTYPE myone(1); \ - assign_scalar_eig2mkl(alpha, myone); \ - ldb = otherStride;\ + EIGTYPE alpha(1); \ + ldb = convert_index(otherStride);\ \ const EIGTYPE *a; \ /* Set trans */ \ @@ -75,25 +73,25 @@ struct triangular_solve_matrix(a_tmp.outerStride()); \ } else { \ a = _tri; \ - lda = triStride; \ + lda = convert_index(triStride); \ } \ if (IsUnitDiag) diag='U'; \ /* call ?trsm*/ \ - MKLPREFIX##trsm(&side, &uplo, &transa, &diag, &m, &n, &alpha, (const MKLTYPE*)a, &lda, (MKLTYPE*)_other, &ldb); \ + BLASPREFIX##trsm_(&side, &uplo, &transa, &diag, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (BLASTYPE*)_other, &ldb); \ } \ }; -EIGEN_MKL_TRSM_L(double, double, d) -EIGEN_MKL_TRSM_L(dcomplex, MKL_Complex16, z) -EIGEN_MKL_TRSM_L(float, float, s) -EIGEN_MKL_TRSM_L(scomplex, MKL_Complex8, c) +EIGEN_BLAS_TRSM_L(double, double, d) +EIGEN_BLAS_TRSM_L(dcomplex, double, z) +EIGEN_BLAS_TRSM_L(float, float, s) +EIGEN_BLAS_TRSM_L(scomplex, float, c) // implements RightSide general * op(triangular)^-1 -#define EIGEN_MKL_TRSM_R(EIGTYPE, MKLTYPE, MKLPREFIX) \ +#define EIGEN_BLAS_TRSM_R(EIGTYPE, BLASTYPE, BLASPREFIX) \ template \ struct triangular_solve_matrix \ { \ @@ -108,13 +106,11 @@ struct triangular_solve_matrix& /*blocking*/) \ { \ - MKL_INT m = otherSize, n = size, lda, ldb; \ + BlasIndex m = convert_index(otherSize), n = convert_index(size), lda, ldb; \ char side = 'R', uplo, diag='N', transa; \ /* Set alpha_ */ \ - MKLTYPE alpha; \ - EIGTYPE myone(1); \ - assign_scalar_eig2mkl(alpha, myone); \ - ldb = otherStride;\ + EIGTYPE alpha(1); \ + ldb = convert_index(otherStride);\ \ const EIGTYPE *a; \ /* Set trans */ \ @@ -130,26 +126,26 @@ struct triangular_solve_matrix(a_tmp.outerStride()); \ } else { \ a = _tri; \ - lda = triStride; \ + lda = convert_index(triStride); \ } \ if (IsUnitDiag) diag='U'; \ /* call ?trsm*/ \ - MKLPREFIX##trsm(&side, &uplo, &transa, &diag, &m, &n, &alpha, (const MKLTYPE*)a, &lda, (MKLTYPE*)_other, &ldb); \ + BLASPREFIX##trsm_(&side, &uplo, &transa, &diag, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (BLASTYPE*)_other, &ldb); \ /*std::cout << "TRMS_L specialization!\n";*/ \ } \ }; -EIGEN_MKL_TRSM_R(double, double, d) -EIGEN_MKL_TRSM_R(dcomplex, MKL_Complex16, z) -EIGEN_MKL_TRSM_R(float, float, s) -EIGEN_MKL_TRSM_R(scomplex, MKL_Complex8, c) +EIGEN_BLAS_TRSM_R(double, double, d) +EIGEN_BLAS_TRSM_R(dcomplex, double, z) +EIGEN_BLAS_TRSM_R(float, float, s) +EIGEN_BLAS_TRSM_R(scomplex, float, c) } // end namespace internal } // end namespace Eigen -#endif // EIGEN_TRIANGULAR_SOLVER_MATRIX_MKL_H +#endif // EIGEN_TRIANGULAR_SOLVER_MATRIX_BLAS_H diff --git a/libs/eigen3/Eigen/src/Core/products/TriangularSolverVector.h b/libs/eigen3/Eigen/src/Core/products/TriangularSolverVector.h index ce4d10088..b994759b2 100644 --- a/libs/eigen3/Eigen/src/Core/products/TriangularSolverVector.h +++ b/libs/eigen3/Eigen/src/Core/products/TriangularSolverVector.h @@ -10,7 +10,7 @@ #ifndef EIGEN_TRIANGULAR_SOLVER_VECTOR_H #define EIGEN_TRIANGULAR_SOLVER_VECTOR_H -namespace Eigen { +namespace Eigen { namespace internal { @@ -25,7 +25,7 @@ struct triangular_solve_vector::run(size, _lhs, lhsStride, rhs); } }; - + // forward and backward substitution, row-major, rhs is a vector template struct triangular_solve_vector @@ -37,6 +37,10 @@ struct triangular_solve_vector, 0, OuterStride<> > LhsMap; const LhsMap lhs(_lhs,size,size,OuterStride<>(lhsStride)); + + typedef const_blas_data_mapper LhsMapper; + typedef const_blas_data_mapper RhsMapper; + typename internal::conditional< Conjugate, const CwiseUnaryOp,LhsMap>, @@ -58,10 +62,10 @@ struct triangular_solve_vector::run( + general_matrix_vector_product::run( actualPanelWidth, r, - &lhs.coeffRef(startRow,startCol), lhsStride, - rhs + startCol, 1, + LhsMapper(&lhs.coeffRef(startRow,startCol), lhsStride), + RhsMapper(rhs + startCol, 1), rhs + startRow, 1, RhsScalar(-1)); } @@ -72,7 +76,7 @@ struct triangular_solve_vector0) rhs[i] -= (cjLhs.row(i).segment(s,k).transpose().cwiseProduct(Map >(rhs+s,k))).sum(); - + if(!(Mode & UnitDiag)) rhs[i] /= cjLhs(i,i); } @@ -91,6 +95,8 @@ struct triangular_solve_vector, 0, OuterStride<> > LhsMap; const LhsMap lhs(_lhs,size,size,OuterStride<>(lhsStride)); + typedef const_blas_data_mapper LhsMapper; + typedef const_blas_data_mapper RhsMapper; typename internal::conditional,LhsMap>, const LhsMap& @@ -122,10 +128,10 @@ struct triangular_solve_vector::run( + general_matrix_vector_product::run( r, actualPanelWidth, - &lhs.coeffRef(endBlock,startBlock), lhsStride, - rhs+startBlock, 1, + LhsMapper(&lhs.coeffRef(endBlock,startBlock), lhsStride), + RhsMapper(rhs+startBlock, 1), rhs+endBlock, 1, RhsScalar(-1)); } } diff --git a/libs/eigen3/Eigen/src/Core/util/BlasUtil.h b/libs/eigen3/Eigen/src/Core/util/BlasUtil.h old mode 100644 new mode 100755 index a28f16fa0..6e6ee119b --- a/libs/eigen3/Eigen/src/Core/util/BlasUtil.h +++ b/libs/eigen3/Eigen/src/Core/util/BlasUtil.h @@ -18,13 +18,13 @@ namespace Eigen { namespace internal { // forward declarations -template +template struct gebp_kernel; -template +template struct gemm_pack_rhs; -template +template struct gemm_pack_lhs; template< @@ -34,7 +34,9 @@ template< int ResStorageOrder> struct general_matrix_matrix_product; -template +template struct general_matrix_vector_product; @@ -42,22 +44,35 @@ template struct conj_if; template<> struct conj_if { template - inline T operator()(const T& x) { return numext::conj(x); } + inline T operator()(const T& x) const { return numext::conj(x); } template - inline T pconj(const T& x) { return internal::pconj(x); } + inline T pconj(const T& x) const { return internal::pconj(x); } }; template<> struct conj_if { template - inline const T& operator()(const T& x) { return x; } + inline const T& operator()(const T& x) const { return x; } template - inline const T& pconj(const T& x) { return x; } + inline const T& pconj(const T& x) const { return x; } +}; + +// Generic implementation for custom complex types. +template +struct conj_helper +{ + typedef typename ScalarBinaryOpTraits::ReturnType Scalar; + + EIGEN_STRONG_INLINE Scalar pmadd(const LhsScalar& x, const RhsScalar& y, const Scalar& c) const + { return padd(c, pmul(x,y)); } + + EIGEN_STRONG_INLINE Scalar pmul(const LhsScalar& x, const RhsScalar& y) const + { return conj_if()(x) * conj_if()(y); } }; template struct conj_helper { - EIGEN_STRONG_INLINE Scalar pmadd(const Scalar& x, const Scalar& y, const Scalar& c) const { return internal::pmadd(x,y,c); } - EIGEN_STRONG_INLINE Scalar pmul(const Scalar& x, const Scalar& y) const { return internal::pmul(x,y); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar pmadd(const Scalar& x, const Scalar& y, const Scalar& c) const { return internal::pmadd(x,y,c); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar pmul(const Scalar& x, const Scalar& y) const { return internal::pmul(x,y); } }; template struct conj_helper, std::complex, false,true> @@ -109,39 +124,142 @@ template struct conj_helper struct get_factor { - static EIGEN_STRONG_INLINE To run(const From& x) { return x; } + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE To run(const From& x) { return To(x); } }; template struct get_factor::Real> { + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE typename NumTraits::Real run(const Scalar& x) { return numext::real(x); } }; + +template +class BlasVectorMapper { + public: + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE BlasVectorMapper(Scalar *data) : m_data(data) {} + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Scalar operator()(Index i) const { + return m_data[i]; + } + template + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Packet load(Index i) const { + return ploadt(m_data + i); + } + + template + EIGEN_DEVICE_FUNC bool aligned(Index i) const { + return (UIntPtr(m_data+i)%sizeof(Packet))==0; + } + + protected: + Scalar* m_data; +}; + +template +class BlasLinearMapper { + public: + typedef typename packet_traits::type Packet; + typedef typename packet_traits::half HalfPacket; + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE BlasLinearMapper(Scalar *data) : m_data(data) {} + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE void prefetch(int i) const { + internal::prefetch(&operator()(i)); + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Scalar& operator()(Index i) const { + return m_data[i]; + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Packet loadPacket(Index i) const { + return ploadt(m_data + i); + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE HalfPacket loadHalfPacket(Index i) const { + return ploadt(m_data + i); + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE void storePacket(Index i, const Packet &p) const { + pstoret(m_data + i, p); + } + + protected: + Scalar *m_data; +}; + // Lightweight helper class to access matrix coefficients. -// Yes, this is somehow redundant with Map<>, but this version is much much lighter, -// and so I hope better compilation performance (time and code quality). -template -class blas_data_mapper -{ +template +class blas_data_mapper { public: - blas_data_mapper(Scalar* data, Index stride) : m_data(data), m_stride(stride) {} - EIGEN_STRONG_INLINE Scalar& operator()(Index i, Index j) - { return m_data[StorageOrder==RowMajor ? j + i*m_stride : i + j*m_stride]; } + typedef typename packet_traits::type Packet; + typedef typename packet_traits::half HalfPacket; + + typedef BlasLinearMapper LinearMapper; + typedef BlasVectorMapper VectorMapper; + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE blas_data_mapper(Scalar* data, Index stride) : m_data(data), m_stride(stride) {} + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE blas_data_mapper + getSubMapper(Index i, Index j) const { + return blas_data_mapper(&operator()(i, j), m_stride); + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE LinearMapper getLinearMapper(Index i, Index j) const { + return LinearMapper(&operator()(i, j)); + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE VectorMapper getVectorMapper(Index i, Index j) const { + return VectorMapper(&operator()(i, j)); + } + + + EIGEN_DEVICE_FUNC + EIGEN_ALWAYS_INLINE Scalar& operator()(Index i, Index j) const { + return m_data[StorageOrder==RowMajor ? j + i*m_stride : i + j*m_stride]; + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Packet loadPacket(Index i, Index j) const { + return ploadt(&operator()(i, j)); + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE HalfPacket loadHalfPacket(Index i, Index j) const { + return ploadt(&operator()(i, j)); + } + + template + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE void scatterPacket(Index i, Index j, const SubPacket &p) const { + pscatter(&operator()(i, j), p, m_stride); + } + + template + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE SubPacket gatherPacket(Index i, Index j) const { + return pgather(&operator()(i, j), m_stride); + } + + EIGEN_DEVICE_FUNC const Index stride() const { return m_stride; } + EIGEN_DEVICE_FUNC const Scalar* data() const { return m_data; } + + EIGEN_DEVICE_FUNC Index firstAligned(Index size) const { + if (UIntPtr(m_data)%sizeof(Scalar)) { + return -1; + } + return internal::first_default_aligned(m_data, size); + } + protected: - Scalar* EIGEN_RESTRICT m_data; - Index m_stride; + Scalar* EIGEN_RESTRICT m_data; + const Index m_stride; }; // lightweight helper class to access matrix coefficients (const version) template -class const_blas_data_mapper -{ +class const_blas_data_mapper : public blas_data_mapper { public: - const_blas_data_mapper(const Scalar* data, Index stride) : m_data(data), m_stride(stride) {} - EIGEN_STRONG_INLINE const Scalar& operator()(Index i, Index j) const - { return m_data[StorageOrder==RowMajor ? j + i*m_stride : i + j*m_stride]; } - protected: - const Scalar* EIGEN_RESTRICT m_data; - Index m_stride; + EIGEN_ALWAYS_INLINE const_blas_data_mapper(const Scalar *data, Index stride) : blas_data_mapper(data, stride) {} + + EIGEN_ALWAYS_INLINE const_blas_data_mapper getSubMapper(Index i, Index j) const { + return const_blas_data_mapper(&(this->operator()(i, j)), this->m_stride); + } }; @@ -188,17 +306,33 @@ struct blas_traits, NestedXpr> > }; // pop scalar multiple -template -struct blas_traits, NestedXpr> > +template +struct blas_traits, const CwiseNullaryOp,Plain>, NestedXpr> > : blas_traits { typedef blas_traits Base; - typedef CwiseUnaryOp, NestedXpr> XprType; + typedef CwiseBinaryOp, const CwiseNullaryOp,Plain>, NestedXpr> XprType; typedef typename Base::ExtractType ExtractType; - static inline ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); } + static inline ExtractType extract(const XprType& x) { return Base::extract(x.rhs()); } static inline Scalar extractScalarFactor(const XprType& x) - { return x.functor().m_other * Base::extractScalarFactor(x.nestedExpression()); } + { return x.lhs().functor().m_other * Base::extractScalarFactor(x.rhs()); } }; +template +struct blas_traits, NestedXpr, const CwiseNullaryOp,Plain> > > + : blas_traits +{ + typedef blas_traits Base; + typedef CwiseBinaryOp, NestedXpr, const CwiseNullaryOp,Plain> > XprType; + typedef typename Base::ExtractType ExtractType; + static inline ExtractType extract(const XprType& x) { return Base::extract(x.lhs()); } + static inline Scalar extractScalarFactor(const XprType& x) + { return Base::extractScalarFactor(x.lhs()) * x.rhs().functor().m_other; } +}; +template +struct blas_traits, const CwiseNullaryOp,Plain1>, + const CwiseNullaryOp,Plain2> > > + : blas_traits,Plain1> > +{}; // pop opposite template @@ -230,7 +364,7 @@ struct blas_traits > enum { IsTransposed = Base::IsTransposed ? 0 : 1 }; - static inline ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); } + static inline ExtractType extract(const XprType& x) { return ExtractType(Base::extract(x.nestedExpression())); } static inline Scalar extractScalarFactor(const XprType& x) { return Base::extractScalarFactor(x.nestedExpression()); } }; diff --git a/libs/eigen3/Eigen/src/Core/util/Constants.h b/libs/eigen3/Eigen/src/Core/util/Constants.h index 14b9624e1..7587d6842 100644 --- a/libs/eigen3/Eigen/src/Core/util/Constants.h +++ b/libs/eigen3/Eigen/src/Core/util/Constants.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2008-2015 Gael Guennebaud // Copyright (C) 2007-2009 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla @@ -30,6 +30,14 @@ const int DynamicIndex = 0xffffff; */ const int Infinity = -1; +/** This value means that the cost to evaluate an expression coefficient is either very expensive or + * cannot be known at compile time. + * + * This value has to be positive to (1) simplify cost computation, and (2) allow to distinguish between a very expensive and very very expensive expressions. + * It thus must also be large enough to make sure unrolling won't happen and that sub expressions will be evaluated, but not too large to avoid overflow. + */ +const int HugeCost = 10000; + /** \defgroup flags Flags * \ingroup Core_Module * @@ -48,19 +56,19 @@ const int Infinity = -1; * for a matrix, this means that the storage order is row-major. * If this bit is not set, the storage order is column-major. * For an expression, this determines the storage order of - * the matrix created by evaluation of that expression. - * \sa \ref TopicStorageOrders */ + * the matrix created by evaluation of that expression. + * \sa \blank \ref TopicStorageOrders */ const unsigned int RowMajorBit = 0x1; /** \ingroup flags - * * means the expression should be evaluated by the calling expression */ const unsigned int EvalBeforeNestingBit = 0x2; /** \ingroup flags - * + * \deprecated * means the expression should be evaluated before any assignment */ -const unsigned int EvalBeforeAssigningBit = 0x4; +EIGEN_DEPRECATED +const unsigned int EvalBeforeAssigningBit = 0x4; // FIXME deprecated /** \ingroup flags * @@ -141,17 +149,46 @@ const unsigned int LvalueBit = 0x20; */ const unsigned int DirectAccessBit = 0x40; -/** \ingroup flags +/** \deprecated \ingroup flags * - * means the first coefficient packet is guaranteed to be aligned */ -const unsigned int AlignedBit = 0x80; + * means the first coefficient packet is guaranteed to be aligned. + * An expression cannot has the AlignedBit without the PacketAccessBit flag. + * In other words, this means we are allow to perform an aligned packet access to the first element regardless + * of the expression kind: + * \code + * expression.packet(0); + * \endcode + */ +EIGEN_DEPRECATED const unsigned int AlignedBit = 0x80; const unsigned int NestByRefBit = 0x100; +/** \ingroup flags + * + * for an expression, this means that the storage order + * can be either row-major or column-major. + * The precise choice will be decided at evaluation time or when + * combined with other expressions. + * \sa \blank \ref RowMajorBit, \ref TopicStorageOrders */ +const unsigned int NoPreferredStorageOrderBit = 0x200; + +/** \ingroup flags + * + * Means that the underlying coefficients can be accessed through pointers to the sparse (un)compressed storage format, + * that is, the expression provides: + * \code + inline const Scalar* valuePtr() const; + inline const Index* innerIndexPtr() const; + inline const Index* outerIndexPtr() const; + inline const Index* innerNonZeroPtr() const; + \endcode + */ +const unsigned int CompressedAccessBit = 0x400; + + // list of flags that are inherited by default const unsigned int HereditaryBits = RowMajorBit - | EvalBeforeNestingBit - | EvalBeforeAssigningBit; + | EvalBeforeNestingBit; /** \defgroup enums Enumerations * \ingroup Core_Module @@ -160,9 +197,9 @@ const unsigned int HereditaryBits = RowMajorBit */ /** \ingroup enums - * Enum containing possible values for the \p Mode parameter of - * MatrixBase::selfadjointView() and MatrixBase::triangularView(). */ -enum { + * Enum containing possible values for the \c Mode or \c UpLo parameter of + * MatrixBase::selfadjointView() and MatrixBase::triangularView(), and selfadjoint solvers. */ +enum UpLoType { /** View matrix as a lower triangular matrix. */ Lower=0x1, /** View matrix as an upper triangular matrix. */ @@ -186,12 +223,31 @@ enum { }; /** \ingroup enums - * Enum for indicating whether an object is aligned or not. */ -enum { - /** Object is not correctly aligned for vectorization. */ - Unaligned=0, - /** Object is aligned for vectorization. */ - Aligned=1 + * Enum for indicating whether a buffer is aligned or not. */ +enum AlignmentType { + Unaligned=0, /**< Data pointer has no specific alignment. */ + Aligned8=8, /**< Data pointer is aligned on a 8 bytes boundary. */ + Aligned16=16, /**< Data pointer is aligned on a 16 bytes boundary. */ + Aligned32=32, /**< Data pointer is aligned on a 32 bytes boundary. */ + Aligned64=64, /**< Data pointer is aligned on a 64 bytes boundary. */ + Aligned128=128, /**< Data pointer is aligned on a 128 bytes boundary. */ + AlignedMask=255, + Aligned=16, /**< \deprecated Synonym for Aligned16. */ +#if EIGEN_MAX_ALIGN_BYTES==128 + AlignedMax = Aligned128 +#elif EIGEN_MAX_ALIGN_BYTES==64 + AlignedMax = Aligned64 +#elif EIGEN_MAX_ALIGN_BYTES==32 + AlignedMax = Aligned32 +#elif EIGEN_MAX_ALIGN_BYTES==16 + AlignedMax = Aligned16 +#elif EIGEN_MAX_ALIGN_BYTES==8 + AlignedMax = Aligned8 +#elif EIGEN_MAX_ALIGN_BYTES==0 + AlignedMax = Unaligned +#else +#error Invalid value for EIGEN_MAX_ALIGN_BYTES +#endif }; /** \ingroup enums @@ -217,7 +273,7 @@ enum DirectionType { /** \internal \ingroup enums * Enum to specify how to traverse the entries of a matrix. */ -enum { +enum TraversalType { /** \internal Default traversal, no vectorization, no index-based access */ DefaultTraversal, /** \internal No vectorization, use index-based access to have only one for loop instead of 2 nested loops */ @@ -239,7 +295,7 @@ enum { /** \internal \ingroup enums * Enum to specify whether to unroll loops when traversing over the entries of a matrix. */ -enum { +enum UnrollingType { /** \internal Do not unroll loops. */ NoUnrolling, /** \internal Unroll only the inner loop, but not the outer loop. */ @@ -251,7 +307,7 @@ enum { /** \internal \ingroup enums * Enum to specify whether to use the default (built-in) implementation or the specialization. */ -enum { +enum SpecializedType { Specialized, BuiltIn }; @@ -259,7 +315,7 @@ enum { /** \ingroup enums * Enum containing possible values for the \p _Options template parameter of * Matrix, Array and BandMatrix. */ -enum { +enum StorageOptions { /** Storage order is column major (see \ref TopicStorageOrders). */ ColMajor = 0, /** Storage order is row major (see \ref TopicStorageOrders). */ @@ -272,7 +328,7 @@ enum { /** \ingroup enums * Enum for specifying whether to apply or solve on the left or right. */ -enum { +enum SideType { /** Apply transformation on the left. */ OnTheLeft = 1, /** Apply transformation on the right. */ @@ -297,7 +353,7 @@ enum Default_t { Default }; /** \internal \ingroup enums * Used in AmbiVector. */ -enum { +enum AmbiVectorMode { IsDense = 0, IsSparse }; @@ -406,10 +462,16 @@ namespace Architecture Generic = 0x0, SSE = 0x1, AltiVec = 0x2, + VSX = 0x3, + NEON = 0x4, #if defined EIGEN_VECTORIZE_SSE Target = SSE #elif defined EIGEN_VECTORIZE_ALTIVEC Target = AltiVec +#elif defined EIGEN_VECTORIZE_VSX + Target = VSX +#elif defined EIGEN_VECTORIZE_NEON + Target = NEON #else Target = Generic #endif @@ -417,8 +479,9 @@ namespace Architecture } /** \internal \ingroup enums - * Enum used as template parameter in GeneralProduct. */ -enum { CoeffBasedProductMode, LazyCoeffBasedProductMode, OuterProduct, InnerProduct, GemvProduct, GemmProduct }; + * Enum used as template parameter in Product and product evaluators. */ +enum ProductImplType +{ DefaultProduct=0, LazyProduct, AliasFreeProduct, CoeffBasedProductMode, LazyCoeffBasedProductMode, OuterProduct, InnerProduct, GemvProduct, GemmProduct }; /** \internal \ingroup enums * Enum used in experimental parallel implementation. */ @@ -427,12 +490,58 @@ enum Action {GetAction, SetAction}; /** The type used to identify a dense storage. */ struct Dense {}; +/** The type used to identify a general sparse storage. */ +struct Sparse {}; + +/** The type used to identify a general solver (factored) storage. */ +struct SolverStorage {}; + +/** The type used to identify a permutation storage. */ +struct PermutationStorage {}; + +/** The type used to identify a permutation storage. */ +struct TranspositionsStorage {}; + /** The type used to identify a matrix expression */ struct MatrixXpr {}; /** The type used to identify an array expression */ struct ArrayXpr {}; +// An evaluator must define its shape. By default, it can be one of the following: +struct DenseShape { static std::string debugName() { return "DenseShape"; } }; +struct SolverShape { static std::string debugName() { return "SolverShape"; } }; +struct HomogeneousShape { static std::string debugName() { return "HomogeneousShape"; } }; +struct DiagonalShape { static std::string debugName() { return "DiagonalShape"; } }; +struct BandShape { static std::string debugName() { return "BandShape"; } }; +struct TriangularShape { static std::string debugName() { return "TriangularShape"; } }; +struct SelfAdjointShape { static std::string debugName() { return "SelfAdjointShape"; } }; +struct PermutationShape { static std::string debugName() { return "PermutationShape"; } }; +struct TranspositionsShape { static std::string debugName() { return "TranspositionsShape"; } }; +struct SparseShape { static std::string debugName() { return "SparseShape"; } }; + +namespace internal { + + // random access iterators based on coeff*() accessors. +struct IndexBased {}; + +// evaluator based on iterators to access coefficients. +struct IteratorBased {}; + +/** \internal + * Constants for comparison functors + */ +enum ComparisonName { + cmp_EQ = 0, + cmp_LT = 1, + cmp_LE = 2, + cmp_UNORD = 3, + cmp_NEQ = 4, + cmp_GT = 5, + cmp_GE = 6 +}; +} // end namespace internal + } // end namespace Eigen #endif // EIGEN_CONSTANTS_H diff --git a/libs/eigen3/Eigen/src/Core/util/DisableStupidWarnings.h b/libs/eigen3/Eigen/src/Core/util/DisableStupidWarnings.h old mode 100644 new mode 100755 index 6a0bf0629..7559e129c --- a/libs/eigen3/Eigen/src/Core/util/DisableStupidWarnings.h +++ b/libs/eigen3/Eigen/src/Core/util/DisableStupidWarnings.h @@ -10,24 +10,31 @@ // 4244 - 'argument' : conversion from 'type1' to 'type2', possible loss of data // 4273 - QtAlignedMalloc, inconsistent DLL linkage // 4324 - structure was padded due to declspec(align()) + // 4503 - decorated name length exceeded, name was truncated // 4512 - assignment operator could not be generated // 4522 - 'class' : multiple assignment operators specified // 4700 - uninitialized local variable 'xyz' used + // 4714 - function marked as __forceinline not inlined // 4717 - 'function' : recursive on all control paths, function will cause runtime stack overflow + // 4800 - 'type' : forcing value to bool 'true' or 'false' (performance warning) #ifndef EIGEN_PERMANENTLY_DISABLE_STUPID_WARNINGS #pragma warning( push ) #endif - #pragma warning( disable : 4100 4101 4127 4181 4211 4244 4273 4324 4512 4522 4700 4717 ) + #pragma warning( disable : 4100 4101 4127 4181 4211 4244 4273 4324 4503 4512 4522 4700 4714 4717 4800) + #elif defined __INTEL_COMPILER // 2196 - routine is both "inline" and "noinline" ("noinline" assumed) // ICC 12 generates this warning even without any inline keyword, when defining class methods 'inline' i.e. inside of class body // typedef that may be a reference type. // 279 - controlling expression is constant // ICC 12 generates this warning on assert(constant_expression_depending_on_template_params) and frankly this is a legitimate use case. + // 1684 - conversion from pointer to same-sized integral type (potential portability problem) + // 2259 - non-pointer conversion from "Eigen::Index={ptrdiff_t={long}}" to "int" may lose significant bits #ifndef EIGEN_PERMANENTLY_DISABLE_STUPID_WARNINGS #pragma warning push #endif - #pragma warning disable 2196 279 + #pragma warning disable 2196 279 1684 2259 + #elif defined __clang__ // -Wconstant-logical-operand - warning: use of logical && with constant operand; switch to bitwise & or remove constant // this is really a stupid warning as it warns on compile-time expressions involving enums @@ -35,6 +42,34 @@ #pragma clang diagnostic push #endif #pragma clang diagnostic ignored "-Wconstant-logical-operand" + +#elif defined __GNUC__ && __GNUC__>=6 + + #ifndef EIGEN_PERMANENTLY_DISABLE_STUPID_WARNINGS + #pragma GCC diagnostic push + #endif + #pragma GCC diagnostic ignored "-Wignored-attributes" + +#endif + +#if defined __NVCC__ + // Disable the "statement is unreachable" message + #pragma diag_suppress code_is_unreachable + // Disable the "dynamic initialization in unreachable code" message + #pragma diag_suppress initialization_not_reachable + // Disable the "invalid error number" message that we get with older versions of nvcc + #pragma diag_suppress 1222 + // Disable the "calling a __host__ function from a __host__ __device__ function is not allowed" messages (yes, there are many of them and they seem to change with every version of the compiler) + #pragma diag_suppress 2527 + #pragma diag_suppress 2529 + #pragma diag_suppress 2651 + #pragma diag_suppress 2653 + #pragma diag_suppress 2668 + #pragma diag_suppress 2669 + #pragma diag_suppress 2670 + #pragma diag_suppress 2671 + #pragma diag_suppress 2735 + #pragma diag_suppress 2737 #endif #endif // not EIGEN_WARNINGS_DISABLED diff --git a/libs/eigen3/Eigen/src/Core/util/ForwardDeclarations.h b/libs/eigen3/Eigen/src/Core/util/ForwardDeclarations.h index d6a814586..ea107393a 100644 --- a/libs/eigen3/Eigen/src/Core/util/ForwardDeclarations.h +++ b/libs/eigen3/Eigen/src/Core/util/ForwardDeclarations.h @@ -36,6 +36,10 @@ template struct accessors_level }; }; +template struct evaluator_traits; + +template< typename T> struct evaluator; + } // end namespace internal template struct NumTraits; @@ -51,18 +55,18 @@ class DenseCoeffsBase; template class CwiseNullaryOp; template class CwiseUnaryOp; template class CwiseUnaryView; template class CwiseBinaryOp; -template class SelfCwiseBinaryOp; -template class ProductBase; -template class GeneralProduct; -template class CoeffBasedProduct; +template class CwiseTernaryOp; +template class Solve; +template class Inverse; + +template class Product; template class DiagonalBase; template class DiagonalWrapper; @@ -108,7 +113,12 @@ template::has_write_access ? WriteAccessors : ReadOnlyAccessors > class MapBase; template class Stride; +template class InnerStride; +template class OuterStride; template > class Map; +template class RefBase; +template,OuterStride<> >::type > class Ref; template class TriangularBase; template class TriangularView; @@ -119,10 +129,10 @@ template struct CommaInitializer; template class ReturnByValue; template class ArrayWrapper; template class MatrixWrapper; +template class SolverBase; +template class InnerIterator; namespace internal { -template struct solve_retval_base; -template struct solve_retval; template struct kernel_retval_base; template struct kernel_retval; template struct image_retval_base; @@ -135,6 +145,21 @@ template struct product_type; + +template struct EnableIf; + +/** \internal + * \class product_evaluator + * Products need their own evaluator with more template arguments allowing for + * easier partial template specializations. + */ +template< typename T, + int ProductTag = internal::product_type::ret, + typename LhsShape = typename evaluator_traits::Shape, + typename RhsShape = typename evaluator_traits::Shape, + typename LhsScalar = typename traits::Scalar, + typename RhsScalar = typename traits::Scalar + > struct product_evaluator; } template struct conj_helper; -template struct scalar_sum_op; -template struct scalar_difference_op; -template struct scalar_conj_product_op; +template struct scalar_sum_op; +template struct scalar_difference_op; +template struct scalar_conj_product_op; +template struct scalar_min_op; +template struct scalar_max_op; template struct scalar_opposite_op; template struct scalar_conjugate_op; template struct scalar_real_op; @@ -160,6 +187,7 @@ template struct scalar_imag_op; template struct scalar_abs_op; template struct scalar_abs2_op; template struct scalar_sqrt_op; +template struct scalar_rsqrt_op; template struct scalar_exp_op; template struct scalar_log_op; template struct scalar_cos_op; @@ -167,24 +195,29 @@ template struct scalar_sin_op; template struct scalar_acos_op; template struct scalar_asin_op; template struct scalar_tan_op; -template struct scalar_pow_op; template struct scalar_inverse_op; template struct scalar_square_op; template struct scalar_cube_op; template struct scalar_cast_op; -template struct scalar_multiple_op; -template struct scalar_quotient1_op; -template struct scalar_min_op; -template struct scalar_max_op; template struct scalar_random_op; -template struct scalar_add_op; template struct scalar_constant_op; template struct scalar_identity_op; - +template struct scalar_sign_op; +template struct scalar_pow_op; +template struct scalar_hypot_op; template struct scalar_product_op; -template struct scalar_multiple2_op; template struct scalar_quotient_op; +// SpecialFunctions module +template struct scalar_lgamma_op; +template struct scalar_digamma_op; +template struct scalar_erf_op; +template struct scalar_erfc_op; +template struct scalar_igamma_op; +template struct scalar_igammac_op; +template struct scalar_zeta_op; +template struct scalar_betainc_op; + } // end namespace internal struct IOFormat; @@ -192,18 +225,18 @@ struct IOFormat; // Array module template class Array; @@ -221,7 +254,9 @@ template struct inverse_impl; template class HouseholderQR; template class ColPivHouseholderQR; template class FullPivHouseholderQR; +template class CompleteOrthogonalDecomposition; template class JacobiSVD; +template class BDCSVD; template class LLT; template class LDLT; template class HouseholderSequence; @@ -234,36 +269,16 @@ template class QuaternionBase; template class Rotation2D; template class AngleAxis; template class Translation; - -#ifdef EIGEN2_SUPPORT -template class eigen2_RotationBase; -template class eigen2_Cross; -template class eigen2_Quaternion; -template class eigen2_Rotation2D; -template class eigen2_AngleAxis; -template class eigen2_Transform; -template class eigen2_ParametrizedLine; -template class eigen2_Hyperplane; -template class eigen2_Translation; -template class eigen2_Scaling; -#endif - -#if EIGEN2_SUPPORT_STAGE < STAGE20_RESOLVE_API_CONFLICTS -template class Quaternion; -template class Transform; -template class ParametrizedLine; -template class Hyperplane; -template class Scaling; -#endif - -#if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS +template class AlignedBox; template class Quaternion; template class Transform; template class ParametrizedLine; template class Hyperplane; template class UniformScaling; template class Homogeneous; -#endif + +// Sparse module: +template class SparseMatrixBase; // MatrixFunctions module template struct MatrixExponentialReturnValue; @@ -271,7 +286,7 @@ template class MatrixFunctionReturnValue; template class MatrixSquareRootReturnValue; template class MatrixLogarithmReturnValue; template class MatrixPowerReturnValue; -template class MatrixPowerProduct; +template class MatrixComplexPowerReturnValue; namespace internal { template @@ -282,18 +297,6 @@ struct stem_function }; } - -#ifdef EIGEN2_SUPPORT -template class Cwise; -template class Minor; -template class LU; -template class QR; -template class SVD; -namespace internal { -template struct eigen2_part_return_type; -} -#endif - } // end namespace Eigen #endif // EIGEN_FORWARDDECLARATIONS_H diff --git a/libs/eigen3/Eigen/src/Core/util/MKL_support.h b/libs/eigen3/Eigen/src/Core/util/MKL_support.h old mode 100644 new mode 100755 index 8acca9c8c..26b59669e --- a/libs/eigen3/Eigen/src/Core/util/MKL_support.h +++ b/libs/eigen3/Eigen/src/Core/util/MKL_support.h @@ -49,7 +49,7 @@ #define EIGEN_USE_LAPACKE #endif -#if defined(EIGEN_USE_BLAS) || defined(EIGEN_USE_LAPACKE) || defined(EIGEN_USE_MKL_VML) +#if defined(EIGEN_USE_MKL_VML) #define EIGEN_USE_MKL #endif @@ -64,7 +64,6 @@ # ifndef EIGEN_USE_MKL /*If the MKL version is too old, undef everything*/ # undef EIGEN_USE_MKL_ALL -# undef EIGEN_USE_BLAS # undef EIGEN_USE_LAPACKE # undef EIGEN_USE_MKL_VML # undef EIGEN_USE_LAPACKE_STRICT @@ -73,54 +72,57 @@ #endif #if defined EIGEN_USE_MKL -#include -#define EIGEN_MKL_VML_THRESHOLD 128 - -namespace Eigen { -typedef std::complex dcomplex; -typedef std::complex scomplex; +#define EIGEN_MKL_VML_THRESHOLD 128 -namespace internal { +/* MKL_DOMAIN_BLAS, etc are defined only in 10.3 update 7 */ +/* MKL_BLAS, etc are not defined in 11.2 */ +#ifdef MKL_DOMAIN_ALL +#define EIGEN_MKL_DOMAIN_ALL MKL_DOMAIN_ALL +#else +#define EIGEN_MKL_DOMAIN_ALL MKL_ALL +#endif -template -static inline void assign_scalar_eig2mkl(MKLType& mklScalar, const EigenType& eigenScalar) { - mklScalar=eigenScalar; -} +#ifdef MKL_DOMAIN_BLAS +#define EIGEN_MKL_DOMAIN_BLAS MKL_DOMAIN_BLAS +#else +#define EIGEN_MKL_DOMAIN_BLAS MKL_BLAS +#endif -template -static inline void assign_conj_scalar_eig2mkl(MKLType& mklScalar, const EigenType& eigenScalar) { - mklScalar=eigenScalar; -} +#ifdef MKL_DOMAIN_FFT +#define EIGEN_MKL_DOMAIN_FFT MKL_DOMAIN_FFT +#else +#define EIGEN_MKL_DOMAIN_FFT MKL_FFT +#endif -template <> -inline void assign_scalar_eig2mkl(MKL_Complex16& mklScalar, const dcomplex& eigenScalar) { - mklScalar.real=eigenScalar.real(); - mklScalar.imag=eigenScalar.imag(); -} +#ifdef MKL_DOMAIN_VML +#define EIGEN_MKL_DOMAIN_VML MKL_DOMAIN_VML +#else +#define EIGEN_MKL_DOMAIN_VML MKL_VML +#endif -template <> -inline void assign_scalar_eig2mkl(MKL_Complex8& mklScalar, const scomplex& eigenScalar) { - mklScalar.real=eigenScalar.real(); - mklScalar.imag=eigenScalar.imag(); -} +#ifdef MKL_DOMAIN_PARDISO +#define EIGEN_MKL_DOMAIN_PARDISO MKL_DOMAIN_PARDISO +#else +#define EIGEN_MKL_DOMAIN_PARDISO MKL_PARDISO +#endif +#endif -template <> -inline void assign_conj_scalar_eig2mkl(MKL_Complex16& mklScalar, const dcomplex& eigenScalar) { - mklScalar.real=eigenScalar.real(); - mklScalar.imag=-eigenScalar.imag(); -} +namespace Eigen { -template <> -inline void assign_conj_scalar_eig2mkl(MKL_Complex8& mklScalar, const scomplex& eigenScalar) { - mklScalar.real=eigenScalar.real(); - mklScalar.imag=-eigenScalar.imag(); -} +typedef std::complex dcomplex; +typedef std::complex scomplex; -} // end namespace internal +#if defined(EIGEN_USE_MKL) +typedef MKL_INT BlasIndex; +#else +typedef int BlasIndex; +#endif } // end namespace Eigen +#if defined(EIGEN_USE_BLAS) +#include "../../misc/blas.h" #endif #endif // EIGEN_MKL_SUPPORT_H diff --git a/libs/eigen3/Eigen/src/Core/util/Macros.h b/libs/eigen3/Eigen/src/Core/util/Macros.h index 3a010ec6a..38d6ddb9a 100644 --- a/libs/eigen3/Eigen/src/Core/util/Macros.h +++ b/libs/eigen3/Eigen/src/Core/util/Macros.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2008-2015 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla @@ -12,94 +12,461 @@ #define EIGEN_MACROS_H #define EIGEN_WORLD_VERSION 3 -#define EIGEN_MAJOR_VERSION 2 -#define EIGEN_MINOR_VERSION 2 +#define EIGEN_MAJOR_VERSION 3 +#define EIGEN_MINOR_VERSION 4 #define EIGEN_VERSION_AT_LEAST(x,y,z) (EIGEN_WORLD_VERSION>x || (EIGEN_WORLD_VERSION>=x && \ (EIGEN_MAJOR_VERSION>y || (EIGEN_MAJOR_VERSION>=y && \ EIGEN_MINOR_VERSION>=z)))) + +// Compiler identification, EIGEN_COMP_* + +/// \internal EIGEN_COMP_GNUC set to 1 for all compilers compatible with GCC #ifdef __GNUC__ - #define EIGEN_GNUC_AT_LEAST(x,y) ((__GNUC__==x && __GNUC_MINOR__>=y) || __GNUC__>x) + #define EIGEN_COMP_GNUC 1 #else - #define EIGEN_GNUC_AT_LEAST(x,y) 0 + #define EIGEN_COMP_GNUC 0 #endif - -#ifdef __GNUC__ - #define EIGEN_GNUC_AT_MOST(x,y) ((__GNUC__==x && __GNUC_MINOR__<=y) || __GNUC__=y) || __GNUC__>x) + #define EIGEN_GNUC_AT_MOST(x,y) ((__GNUC__==x && __GNUC_MINOR__<=y) || __GNUC__=11 && (defined(__cplusplus) && (__cplusplus >= 201103L) || EIGEN_COMP_MSVC >= 1900) +#define EIGEN_HAS_CXX11 1 +#else +#define EIGEN_HAS_CXX11 0 +#endif + + +// Do we support r-value references? +#ifndef EIGEN_HAS_RVALUE_REFERENCES +#if EIGEN_MAX_CPP_VER>=11 && \ + (__has_feature(cxx_rvalue_references) || \ + (defined(__cplusplus) && __cplusplus >= 201103L) || \ + (EIGEN_COMP_MSVC >= 1600)) + #define EIGEN_HAS_RVALUE_REFERENCES 1 +#else + #define EIGEN_HAS_RVALUE_REFERENCES 0 +#endif +#endif + +// Does the compiler support C99? +#ifndef EIGEN_HAS_C99_MATH +#if EIGEN_MAX_CPP_VER>=11 && \ + ((defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)) \ + || (defined(__GNUC__) && defined(_GLIBCXX_USE_C99)) \ + || (defined(_LIBCPP_VERSION) && !defined(_MSC_VER))) + #define EIGEN_HAS_C99_MATH 1 +#else + #define EIGEN_HAS_C99_MATH 0 +#endif +#endif + +// Does the compiler support result_of? +#ifndef EIGEN_HAS_STD_RESULT_OF +#if EIGEN_MAX_CPP_VER>=11 && ((__has_feature(cxx_lambdas) || (defined(__cplusplus) && __cplusplus >= 201103L))) +#define EIGEN_HAS_STD_RESULT_OF 1 +#else +#define EIGEN_HAS_STD_RESULT_OF 0 +#endif +#endif + +// Does the compiler support variadic templates? +#ifndef EIGEN_HAS_VARIADIC_TEMPLATES +#if EIGEN_MAX_CPP_VER>=11 && (__cplusplus > 199711L || EIGEN_COMP_MSVC >= 1900) \ + && ( !defined(__NVCC__) || !EIGEN_ARCH_ARM_OR_ARM64 || (defined __CUDACC_VER__ && __CUDACC_VER__ >= 80000) ) + // ^^ Disable the use of variadic templates when compiling with versions of nvcc older than 8.0 on ARM devices: + // this prevents nvcc from crashing when compiling Eigen on Tegra X1 +#define EIGEN_HAS_VARIADIC_TEMPLATES 1 +#else +#define EIGEN_HAS_VARIADIC_TEMPLATES 0 +#endif +#endif + +// Does the compiler fully support const expressions? (as in c++14) +#ifndef EIGEN_HAS_CONSTEXPR + +#ifdef __CUDACC__ +// Const expressions are supported provided that c++11 is enabled and we're using either clang or nvcc 7.5 or above +#if EIGEN_MAX_CPP_VER>=14 && (__cplusplus > 199711L && defined(__CUDACC_VER__) && (EIGEN_COMP_CLANG || __CUDACC_VER__ >= 70500)) + #define EIGEN_HAS_CONSTEXPR 1 +#endif +#elif EIGEN_MAX_CPP_VER>=14 && (__has_feature(cxx_relaxed_constexpr) || (defined(__cplusplus) && __cplusplus >= 201402L) || \ + (EIGEN_GNUC_AT_LEAST(4,8) && (__cplusplus > 199711L))) +#define EIGEN_HAS_CONSTEXPR 1 +#endif + +#ifndef EIGEN_HAS_CONSTEXPR +#define EIGEN_HAS_CONSTEXPR 0 +#endif + +#endif + +// Does the compiler support C++11 math? +// Let's be conservative and enable the default C++11 implementation only if we are sure it exists +#ifndef EIGEN_HAS_CXX11_MATH + #if EIGEN_MAX_CPP_VER>=11 && ((__cplusplus > 201103L) || (__cplusplus >= 201103L) && (EIGEN_COMP_GNUC_STRICT || EIGEN_COMP_CLANG || EIGEN_COMP_MSVC || EIGEN_COMP_ICC) \ + && (EIGEN_ARCH_i386_OR_x86_64) && (EIGEN_OS_GNULINUX || EIGEN_OS_WIN_STRICT || EIGEN_OS_MAC)) + #define EIGEN_HAS_CXX11_MATH 1 + #else + #define EIGEN_HAS_CXX11_MATH 0 + #endif +#endif + +// Does the compiler support proper C++11 containers? +#ifndef EIGEN_HAS_CXX11_CONTAINERS + #if EIGEN_MAX_CPP_VER>=11 && \ + ((__cplusplus > 201103L) \ + || ((__cplusplus >= 201103L) && (EIGEN_COMP_GNUC_STRICT || EIGEN_COMP_CLANG || EIGEN_COMP_ICC>=1400)) \ + || EIGEN_COMP_MSVC >= 1900) + #define EIGEN_HAS_CXX11_CONTAINERS 1 + #else + #define EIGEN_HAS_CXX11_CONTAINERS 0 + #endif +#endif + +// Does the compiler support C++11 noexcept? +#ifndef EIGEN_HAS_CXX11_NOEXCEPT + #if EIGEN_MAX_CPP_VER>=11 && \ + (__has_feature(cxx_noexcept) \ + || (__cplusplus > 201103L) \ + || ((__cplusplus >= 201103L) && (EIGEN_COMP_GNUC_STRICT || EIGEN_COMP_CLANG || EIGEN_COMP_ICC>=1400)) \ + || EIGEN_COMP_MSVC >= 1900) + #define EIGEN_HAS_CXX11_NOEXCEPT 1 + #else + #define EIGEN_HAS_CXX11_NOEXCEPT 0 + #endif +#endif + /** Allows to disable some optimizations which might affect the accuracy of the result. * Such optimization are enabled by default, and set EIGEN_FAST_MATH to 0 to disable them. * They currently include: - * - single precision Cwise::sin() and Cwise::cos() when SSE vectorization is enabled. + * - single precision ArrayBase::sin() and ArrayBase::cos() for SSE and AVX vectorization. */ #ifndef EIGEN_FAST_MATH #define EIGEN_FAST_MATH 1 @@ -111,6 +478,8 @@ #define EIGEN_CAT2(a,b) a ## b #define EIGEN_CAT(a,b) EIGEN_CAT2(a,b) +#define EIGEN_COMMA , + // convert a token to a string #define EIGEN_MAKESTRING2(a) #a #define EIGEN_MAKESTRING(a) EIGEN_MAKESTRING2(a) @@ -118,7 +487,7 @@ // EIGEN_STRONG_INLINE is a stronger version of the inline, using __forceinline on MSVC, // but it still doesn't use GCC's always_inline. This is useful in (common) situations where MSVC needs forceinline // but GCC is still doing fine with just inline. -#if (defined _MSC_VER) || (defined __INTEL_COMPILER) +#if EIGEN_COMP_MSVC || EIGEN_COMP_ICC #define EIGEN_STRONG_INLINE __forceinline #else #define EIGEN_STRONG_INLINE inline @@ -128,24 +497,25 @@ // attribute to maximize inlining. This should only be used when really necessary: in particular, // it uses __attribute__((always_inline)) on GCC, which most of the time is useless and can severely harm compile times. // FIXME with the always_inline attribute, -// gcc 3.4.x reports the following compilation error: +// gcc 3.4.x and 4.1 reports the following compilation error: // Eval.h:91: sorry, unimplemented: inlining failed in call to 'const Eigen::Eval Eigen::MatrixBase::eval() const' // : function body not available -#if EIGEN_GNUC_AT_LEAST(4,0) +// See also bug 1367 +#if EIGEN_GNUC_AT_LEAST(4,2) #define EIGEN_ALWAYS_INLINE __attribute__((always_inline)) inline #else #define EIGEN_ALWAYS_INLINE EIGEN_STRONG_INLINE #endif -#if (defined __GNUC__) +#if EIGEN_COMP_GNUC #define EIGEN_DONT_INLINE __attribute__((noinline)) -#elif (defined _MSC_VER) +#elif EIGEN_COMP_MSVC #define EIGEN_DONT_INLINE __declspec(noinline) #else #define EIGEN_DONT_INLINE #endif -#if (defined __GNUC__) +#if EIGEN_COMP_GNUC #define EIGEN_PERMISSIVE_EXPR __extension__ #else #define EIGEN_PERMISSIVE_EXPR @@ -214,15 +584,15 @@ #endif #ifdef EIGEN_NO_DEBUG -#define EIGEN_ONLY_USED_FOR_DEBUG(x) (void)x +#define EIGEN_ONLY_USED_FOR_DEBUG(x) EIGEN_UNUSED_VARIABLE(x) #else #define EIGEN_ONLY_USED_FOR_DEBUG(x) #endif #ifndef EIGEN_NO_DEPRECATED_WARNING - #if (defined __GNUC__) + #if EIGEN_COMP_GNUC #define EIGEN_DEPRECATED __attribute__((deprecated)) - #elif (defined _MSC_VER) + #elif EIGEN_COMP_MSVC #define EIGEN_DEPRECATED __declspec(deprecated) #else #define EIGEN_DEPRECATED @@ -231,7 +601,7 @@ #define EIGEN_DEPRECATED #endif -#if (defined __GNUC__) +#if EIGEN_COMP_GNUC #define EIGEN_UNUSED __attribute__((unused)) #else #define EIGEN_UNUSED @@ -240,19 +610,33 @@ // Suppresses 'unused variable' warnings. namespace Eigen { namespace internal { - template void ignore_unused_variable(const T&) {} + template EIGEN_DEVICE_FUNC void ignore_unused_variable(const T&) {} } } #define EIGEN_UNUSED_VARIABLE(var) Eigen::internal::ignore_unused_variable(var); #if !defined(EIGEN_ASM_COMMENT) - #if (defined __GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) - #define EIGEN_ASM_COMMENT(X) asm("#" X) + #if EIGEN_COMP_GNUC && (EIGEN_ARCH_i386_OR_x86_64 || EIGEN_ARCH_ARM_OR_ARM64) + #define EIGEN_ASM_COMMENT(X) __asm__("#" X) #else #define EIGEN_ASM_COMMENT(X) #endif #endif + +//------------------------------------------------------------------------------------------ +// Static and dynamic alignment control +// +// The main purpose of this section is to define EIGEN_MAX_ALIGN_BYTES and EIGEN_MAX_STATIC_ALIGN_BYTES +// as the maximal boundary in bytes on which dynamically and statically allocated data may be alignment respectively. +// The values of EIGEN_MAX_ALIGN_BYTES and EIGEN_MAX_STATIC_ALIGN_BYTES can be specified by the user. If not, +// a default value is automatically computed based on architecture, compiler, and OS. +// +// This section also defines macros EIGEN_ALIGN_TO_BOUNDARY(N) and the shortcuts EIGEN_ALIGN{8,16,32,_MAX} +// to be used to declare statically aligned buffers. +//------------------------------------------------------------------------------------------ + + /* EIGEN_ALIGN_TO_BOUNDARY(n) forces data to be n-byte aligned. This is used to satisfy SIMD requirements. * However, we do that EVEN if vectorization (EIGEN_VECTORIZE) is disabled, * so that vectorization doesn't affect binary compatibility. @@ -260,27 +644,149 @@ namespace Eigen { * If we made alignment depend on whether or not EIGEN_VECTORIZE is defined, it would be impossible to link * vectorized and non-vectorized code. */ -#if (defined __GNUC__) || (defined __PGI) || (defined __IBMCPP__) || (defined __ARMCC_VERSION) +#if (defined __CUDACC__) + #define EIGEN_ALIGN_TO_BOUNDARY(n) __align__(n) +#elif EIGEN_COMP_GNUC || EIGEN_COMP_PGI || EIGEN_COMP_IBM || EIGEN_COMP_ARM #define EIGEN_ALIGN_TO_BOUNDARY(n) __attribute__((aligned(n))) -#elif (defined _MSC_VER) +#elif EIGEN_COMP_MSVC #define EIGEN_ALIGN_TO_BOUNDARY(n) __declspec(align(n)) -#elif (defined __SUNPRO_CC) +#elif EIGEN_COMP_SUNCC // FIXME not sure about this one: #define EIGEN_ALIGN_TO_BOUNDARY(n) __attribute__((aligned(n))) #else #error Please tell me what is the equivalent of __attribute__((aligned(n))) for your compiler #endif +// If the user explicitly disable vectorization, then we also disable alignment +#if defined(EIGEN_DONT_VECTORIZE) + #define EIGEN_IDEAL_MAX_ALIGN_BYTES 0 +#elif defined(EIGEN_VECTORIZE_AVX512) + // 64 bytes static alignmeent is preferred only if really required + #define EIGEN_IDEAL_MAX_ALIGN_BYTES 64 +#elif defined(__AVX__) + // 32 bytes static alignmeent is preferred only if really required + #define EIGEN_IDEAL_MAX_ALIGN_BYTES 32 +#else + #define EIGEN_IDEAL_MAX_ALIGN_BYTES 16 +#endif + + +// EIGEN_MIN_ALIGN_BYTES defines the minimal value for which the notion of explicit alignment makes sense +#define EIGEN_MIN_ALIGN_BYTES 16 + +// Defined the boundary (in bytes) on which the data needs to be aligned. Note +// that unless EIGEN_ALIGN is defined and not equal to 0, the data may not be +// aligned at all regardless of the value of this #define. + +#if (defined(EIGEN_DONT_ALIGN_STATICALLY) || defined(EIGEN_DONT_ALIGN)) && defined(EIGEN_MAX_STATIC_ALIGN_BYTES) && EIGEN_MAX_STATIC_ALIGN_BYTES>0 +#error EIGEN_MAX_STATIC_ALIGN_BYTES and EIGEN_DONT_ALIGN[_STATICALLY] are both defined with EIGEN_MAX_STATIC_ALIGN_BYTES!=0. Use EIGEN_MAX_STATIC_ALIGN_BYTES=0 as a synonym of EIGEN_DONT_ALIGN_STATICALLY. +#endif + +// EIGEN_DONT_ALIGN_STATICALLY and EIGEN_DONT_ALIGN are deprectated +// They imply EIGEN_MAX_STATIC_ALIGN_BYTES=0 +#if defined(EIGEN_DONT_ALIGN_STATICALLY) || defined(EIGEN_DONT_ALIGN) + #ifdef EIGEN_MAX_STATIC_ALIGN_BYTES + #undef EIGEN_MAX_STATIC_ALIGN_BYTES + #endif + #define EIGEN_MAX_STATIC_ALIGN_BYTES 0 +#endif + +#ifndef EIGEN_MAX_STATIC_ALIGN_BYTES + + // Try to automatically guess what is the best default value for EIGEN_MAX_STATIC_ALIGN_BYTES + + // 16 byte alignment is only useful for vectorization. Since it affects the ABI, we need to enable + // 16 byte alignment on all platforms where vectorization might be enabled. In theory we could always + // enable alignment, but it can be a cause of problems on some platforms, so we just disable it in + // certain common platform (compiler+architecture combinations) to avoid these problems. + // Only static alignment is really problematic (relies on nonstandard compiler extensions), + // try to keep heap alignment even when we have to disable static alignment. + #if EIGEN_COMP_GNUC && !(EIGEN_ARCH_i386_OR_x86_64 || EIGEN_ARCH_ARM_OR_ARM64 || EIGEN_ARCH_PPC || EIGEN_ARCH_IA64) + #define EIGEN_GCC_AND_ARCH_DOESNT_WANT_STACK_ALIGNMENT 1 + #elif EIGEN_ARCH_ARM_OR_ARM64 && EIGEN_COMP_GNUC_STRICT && EIGEN_GNUC_AT_MOST(4, 6) + // Old versions of GCC on ARM, at least 4.4, were once seen to have buggy static alignment support. + // Not sure which version fixed it, hopefully it doesn't affect 4.7, which is still somewhat in use. + // 4.8 and newer seem definitely unaffected. + #define EIGEN_GCC_AND_ARCH_DOESNT_WANT_STACK_ALIGNMENT 1 + #else + #define EIGEN_GCC_AND_ARCH_DOESNT_WANT_STACK_ALIGNMENT 0 + #endif + + // static alignment is completely disabled with GCC 3, Sun Studio, and QCC/QNX + #if !EIGEN_GCC_AND_ARCH_DOESNT_WANT_STACK_ALIGNMENT \ + && !EIGEN_GCC3_OR_OLDER \ + && !EIGEN_COMP_SUNCC \ + && !EIGEN_OS_QNX + #define EIGEN_ARCH_WANTS_STACK_ALIGNMENT 1 + #else + #define EIGEN_ARCH_WANTS_STACK_ALIGNMENT 0 + #endif + + #if EIGEN_ARCH_WANTS_STACK_ALIGNMENT + #define EIGEN_MAX_STATIC_ALIGN_BYTES EIGEN_IDEAL_MAX_ALIGN_BYTES + #else + #define EIGEN_MAX_STATIC_ALIGN_BYTES 0 + #endif + +#endif + +// If EIGEN_MAX_ALIGN_BYTES is defined, then it is considered as an upper bound for EIGEN_MAX_ALIGN_BYTES +#if defined(EIGEN_MAX_ALIGN_BYTES) && EIGEN_MAX_ALIGN_BYTES0 is the true test whether we want to align arrays on the stack or not. +// It takes into account both the user choice to explicitly enable/disable alignment (by settting EIGEN_MAX_STATIC_ALIGN_BYTES) +// and the architecture config (EIGEN_ARCH_WANTS_STACK_ALIGNMENT). +// Henceforth, only EIGEN_MAX_STATIC_ALIGN_BYTES should be used. + + +// Shortcuts to EIGEN_ALIGN_TO_BOUNDARY +#define EIGEN_ALIGN8 EIGEN_ALIGN_TO_BOUNDARY(8) #define EIGEN_ALIGN16 EIGEN_ALIGN_TO_BOUNDARY(16) +#define EIGEN_ALIGN32 EIGEN_ALIGN_TO_BOUNDARY(32) +#define EIGEN_ALIGN64 EIGEN_ALIGN_TO_BOUNDARY(64) +#if EIGEN_MAX_STATIC_ALIGN_BYTES>0 +#define EIGEN_ALIGN_MAX EIGEN_ALIGN_TO_BOUNDARY(EIGEN_MAX_STATIC_ALIGN_BYTES) +#else +#define EIGEN_ALIGN_MAX +#endif + -#if EIGEN_ALIGN_STATICALLY -#define EIGEN_USER_ALIGN_TO_BOUNDARY(n) EIGEN_ALIGN_TO_BOUNDARY(n) -#define EIGEN_USER_ALIGN16 EIGEN_ALIGN16 +// Dynamic alignment control + +#if defined(EIGEN_DONT_ALIGN) && defined(EIGEN_MAX_ALIGN_BYTES) && EIGEN_MAX_ALIGN_BYTES>0 +#error EIGEN_MAX_ALIGN_BYTES and EIGEN_DONT_ALIGN are both defined with EIGEN_MAX_ALIGN_BYTES!=0. Use EIGEN_MAX_ALIGN_BYTES=0 as a synonym of EIGEN_DONT_ALIGN. +#endif + +#ifdef EIGEN_DONT_ALIGN + #ifdef EIGEN_MAX_ALIGN_BYTES + #undef EIGEN_MAX_ALIGN_BYTES + #endif + #define EIGEN_MAX_ALIGN_BYTES 0 +#elif !defined(EIGEN_MAX_ALIGN_BYTES) + #define EIGEN_MAX_ALIGN_BYTES EIGEN_IDEAL_MAX_ALIGN_BYTES +#endif + +#if EIGEN_IDEAL_MAX_ALIGN_BYTES > EIGEN_MAX_ALIGN_BYTES +#define EIGEN_DEFAULT_ALIGN_BYTES EIGEN_IDEAL_MAX_ALIGN_BYTES #else -#define EIGEN_USER_ALIGN_TO_BOUNDARY(n) -#define EIGEN_USER_ALIGN16 +#define EIGEN_DEFAULT_ALIGN_BYTES EIGEN_MAX_ALIGN_BYTES +#endif + + +#ifndef EIGEN_UNALIGNED_VECTORIZE +#define EIGEN_UNALIGNED_VECTORIZE 1 #endif +//---------------------------------------------------------------------- + + #ifdef EIGEN_DONT_USE_RESTRICT_KEYWORD #define EIGEN_RESTRICT #endif @@ -306,27 +812,31 @@ namespace Eigen { // just an empty macro ! #define EIGEN_EMPTY -#if defined(_MSC_VER) && (!defined(__INTEL_COMPILER)) -#define EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) \ - using Base::operator =; -#elif defined(__clang__) // workaround clang bug (see http://forum.kde.org/viewtopic.php?f=74&t=102653) -#define EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) \ - using Base::operator =; \ - EIGEN_STRONG_INLINE Derived& operator=(const Derived& other) { Base::operator=(other); return *this; } \ - template \ - EIGEN_STRONG_INLINE Derived& operator=(const DenseBase& other) { Base::operator=(other.derived()); return *this; } -#else -#define EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) \ - using Base::operator =; \ - EIGEN_STRONG_INLINE Derived& operator=(const Derived& other) \ - { \ - Base::operator=(other); \ - return *this; \ - } +#if EIGEN_COMP_MSVC_STRICT && (EIGEN_COMP_MSVC < 1900 || defined(__CUDACC_VER__)) // for older MSVC versions, as well as 1900 && CUDA 8, using the base operator is sufficient (cf Bugs 1000, 1324) + #define EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) \ + using Base::operator =; +#elif EIGEN_COMP_CLANG // workaround clang bug (see http://forum.kde.org/viewtopic.php?f=74&t=102653) + #define EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) \ + using Base::operator =; \ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const Derived& other) { Base::operator=(other); return *this; } \ + template \ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const DenseBase& other) { Base::operator=(other.derived()); return *this; } +#else + #define EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) \ + using Base::operator =; \ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const Derived& other) \ + { \ + Base::operator=(other); \ + return *this; \ + } #endif -#define EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Derived) \ - EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) + +/** \internal + * \brief Macro to manually inherit assignment operators. + * This is necessary, because the implicitly defined assignment operator gets deleted when a custom operator= is defined. + */ +#define EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Derived) EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) /** * Just a side note. Commenting within defines works only by documenting @@ -340,32 +850,12 @@ namespace Eigen { typedef typename Eigen::internal::traits::Scalar Scalar; /*!< \brief Numeric type, e.g. float, double, int or std::complex. */ \ typedef typename Eigen::NumTraits::Real RealScalar; /*!< \brief The underlying numeric type for composed scalar types. \details In cases where Scalar is e.g. std::complex, T were corresponding to RealScalar. */ \ typedef typename Base::CoeffReturnType CoeffReturnType; /*!< \brief The return type for coefficient access. \details Depending on whether the object allows direct coefficient access (e.g. for a MatrixXd), this type is either 'const Scalar&' or simply 'Scalar' for objects that do not allow direct coefficient access. */ \ - typedef typename Eigen::internal::nested::type Nested; \ + typedef typename Eigen::internal::ref_selector::type Nested; \ typedef typename Eigen::internal::traits::StorageKind StorageKind; \ - typedef typename Eigen::internal::traits::Index Index; \ + typedef typename Eigen::internal::traits::StorageIndex StorageIndex; \ enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, \ Flags = Eigen::internal::traits::Flags, \ - CoeffReadCost = Eigen::internal::traits::CoeffReadCost, \ - SizeAtCompileTime = Base::SizeAtCompileTime, \ - MaxSizeAtCompileTime = Base::MaxSizeAtCompileTime, \ - IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; - - -#define EIGEN_DENSE_PUBLIC_INTERFACE(Derived) \ - typedef typename Eigen::internal::traits::Scalar Scalar; /*!< \brief Numeric type, e.g. float, double, int or std::complex. */ \ - typedef typename Eigen::NumTraits::Real RealScalar; /*!< \brief The underlying numeric type for composed scalar types. \details In cases where Scalar is e.g. std::complex, T were corresponding to RealScalar. */ \ - typedef typename Base::PacketScalar PacketScalar; \ - typedef typename Base::CoeffReturnType CoeffReturnType; /*!< \brief The return type for coefficient access. \details Depending on whether the object allows direct coefficient access (e.g. for a MatrixXd), this type is either 'const Scalar&' or simply 'Scalar' for objects that do not allow direct coefficient access. */ \ - typedef typename Eigen::internal::nested::type Nested; \ - typedef typename Eigen::internal::traits::StorageKind StorageKind; \ - typedef typename Eigen::internal::traits::Index Index; \ - enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ - ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, \ - MaxRowsAtCompileTime = Eigen::internal::traits::MaxRowsAtCompileTime, \ - MaxColsAtCompileTime = Eigen::internal::traits::MaxColsAtCompileTime, \ - Flags = Eigen::internal::traits::Flags, \ - CoeffReadCost = Eigen::internal::traits::CoeffReadCost, \ SizeAtCompileTime = Base::SizeAtCompileTime, \ MaxSizeAtCompileTime = Base::MaxSizeAtCompileTime, \ IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; \ @@ -373,6 +863,12 @@ namespace Eigen { using Base::const_cast_derived; +// FIXME Maybe the EIGEN_DENSE_PUBLIC_INTERFACE could be removed as importing PacketScalar is rarely needed +#define EIGEN_DENSE_PUBLIC_INTERFACE(Derived) \ + EIGEN_GENERIC_PUBLIC_INTERFACE(Derived) \ + typedef typename Base::PacketScalar PacketScalar; + + #define EIGEN_PLAIN_ENUM_MIN(a,b) (((int)a <= (int)b) ? (int)a : (int)b) #define EIGEN_PLAIN_ENUM_MAX(a,b) (((int)a >= (int)b) ? (int)a : (int)b) @@ -402,18 +898,10 @@ namespace Eigen { #define EIGEN_IMPLIES(a,b) (!(a) || (b)) -#define EIGEN_MAKE_CWISE_BINARY_OP(METHOD,FUNCTOR) \ - template \ - EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const OtherDerived> \ - (METHOD)(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const \ - { \ - return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); \ - } - -// the expression type of a cwise product -#define EIGEN_CWISE_PRODUCT_RETURN_TYPE(LHS,RHS) \ +// the expression type of a standard coefficient wise binary operation +#define EIGEN_CWISE_BINARY_RETURN_TYPE(LHS,RHS,OPNAME) \ CwiseBinaryOp< \ - internal::scalar_product_op< \ + EIGEN_CAT(EIGEN_CAT(internal::scalar_,OPNAME),_op)< \ typename internal::traits::Scalar, \ typename internal::traits::Scalar \ >, \ @@ -421,4 +909,84 @@ namespace Eigen { const RHS \ > +#define EIGEN_MAKE_CWISE_BINARY_OP(METHOD,OPNAME) \ + template \ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const EIGEN_CWISE_BINARY_RETURN_TYPE(Derived,OtherDerived,OPNAME) \ + (METHOD)(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const \ + { \ + return EIGEN_CWISE_BINARY_RETURN_TYPE(Derived,OtherDerived,OPNAME)(derived(), other.derived()); \ + } + +#define EIGEN_SCALAR_BINARY_SUPPORTED(OPNAME,TYPEA,TYPEB) \ + (Eigen::internal::has_ReturnType > >::value) + +#define EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(EXPR,SCALAR,OPNAME) \ + CwiseBinaryOp::Scalar,SCALAR>, const EXPR, \ + const typename internal::plain_constant_type::type> + +#define EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(SCALAR,EXPR,OPNAME) \ + CwiseBinaryOp::Scalar>, \ + const typename internal::plain_constant_type::type, const EXPR> + +// Workaround for MSVC 2010 (see ML thread "patch with compile for for MSVC 2010") +#if EIGEN_COMP_MSVC_STRICT<=1600 +#define EIGEN_MSVC10_WORKAROUND_BINARYOP_RETURN_TYPE(X) typename internal::enable_if::type +#else +#define EIGEN_MSVC10_WORKAROUND_BINARYOP_RETURN_TYPE(X) X +#endif + +#define EIGEN_MAKE_SCALAR_BINARY_OP_ONTHERIGHT(METHOD,OPNAME) \ + template EIGEN_DEVICE_FUNC inline \ + EIGEN_MSVC10_WORKAROUND_BINARYOP_RETURN_TYPE(const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Derived,typename internal::promote_scalar_arg::type,OPNAME))\ + (METHOD)(const T& scalar) const { \ + typedef typename internal::promote_scalar_arg::type PromotedT; \ + return EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Derived,PromotedT,OPNAME)(derived(), \ + typename internal::plain_constant_type::type(derived().rows(), derived().cols(), internal::scalar_constant_op(scalar))); \ + } + +#define EIGEN_MAKE_SCALAR_BINARY_OP_ONTHELEFT(METHOD,OPNAME) \ + template EIGEN_DEVICE_FUNC inline friend \ + EIGEN_MSVC10_WORKAROUND_BINARYOP_RETURN_TYPE(const EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(typename internal::promote_scalar_arg::type,Derived,OPNAME)) \ + (METHOD)(const T& scalar, const StorageBaseType& matrix) { \ + typedef typename internal::promote_scalar_arg::type PromotedT; \ + return EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(PromotedT,Derived,OPNAME)( \ + typename internal::plain_constant_type::type(matrix.derived().rows(), matrix.derived().cols(), internal::scalar_constant_op(scalar)), matrix.derived()); \ + } + +#define EIGEN_MAKE_SCALAR_BINARY_OP(METHOD,OPNAME) \ + EIGEN_MAKE_SCALAR_BINARY_OP_ONTHELEFT(METHOD,OPNAME) \ + EIGEN_MAKE_SCALAR_BINARY_OP_ONTHERIGHT(METHOD,OPNAME) + + +#ifdef EIGEN_EXCEPTIONS +# define EIGEN_THROW_X(X) throw X +# define EIGEN_THROW throw +# define EIGEN_TRY try +# define EIGEN_CATCH(X) catch (X) +#else +# ifdef __CUDA_ARCH__ +# define EIGEN_THROW_X(X) asm("trap;") +# define EIGEN_THROW asm("trap;") +# else +# define EIGEN_THROW_X(X) std::abort() +# define EIGEN_THROW std::abort() +# endif +# define EIGEN_TRY if (true) +# define EIGEN_CATCH(X) else +#endif + + +#if EIGEN_HAS_CXX11_NOEXCEPT +# define EIGEN_INCLUDE_TYPE_TRAITS +# define EIGEN_NOEXCEPT noexcept +# define EIGEN_NOEXCEPT_IF(x) noexcept(x) +# define EIGEN_NO_THROW noexcept(true) +# define EIGEN_EXCEPTION_SPEC(X) noexcept(false) +#else +# define EIGEN_NOEXCEPT +# define EIGEN_NOEXCEPT_IF(x) +# define EIGEN_NO_THROW throw() +# define EIGEN_EXCEPTION_SPEC(X) throw(X) +#endif + #endif // EIGEN_MACROS_H diff --git a/libs/eigen3/Eigen/src/Core/util/Memory.h b/libs/eigen3/Eigen/src/Core/util/Memory.h index c4011245a..c634d7ea0 100644 --- a/libs/eigen3/Eigen/src/Core/util/Memory.h +++ b/libs/eigen3/Eigen/src/Core/util/Memory.h @@ -1,11 +1,12 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2008-2015 Gael Guennebaud // Copyright (C) 2008-2009 Benoit Jacob // Copyright (C) 2009 Kenneth Riddile // Copyright (C) 2010 Hauke Heibel // Copyright (C) 2010 Thomas Capricelli +// Copyright (C) 2013 Pavel Holoborodko // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -31,7 +32,7 @@ // page 114, "[The] LP64 model [...] is used by all 64-bit UNIX ports" so it's indeed // quite safe, at least within the context of glibc, to equate 64-bit with LP64. #if defined(__GLIBC__) && ((__GLIBC__>=2 && __GLIBC_MINOR__ >= 8) || __GLIBC__>2) \ - && defined(__LP64__) && ! defined( __SANITIZE_ADDRESS__ ) + && defined(__LP64__) && ! defined( __SANITIZE_ADDRESS__ ) && (EIGEN_DEFAULT_ALIGN_BYTES == 16) #define EIGEN_GLIBC_MALLOC_ALREADY_ALIGNED 1 #else #define EIGEN_GLIBC_MALLOC_ALREADY_ALIGNED 0 @@ -41,15 +42,15 @@ // See http://svn.freebsd.org/viewvc/base/stable/6/lib/libc/stdlib/malloc.c?view=markup // FreeBSD 7 seems to have 16-byte aligned malloc except on ARM and MIPS architectures // See http://svn.freebsd.org/viewvc/base/stable/7/lib/libc/stdlib/malloc.c?view=markup -#if defined(__FreeBSD__) && !defined(__arm__) && !defined(__mips__) +#if defined(__FreeBSD__) && !(EIGEN_ARCH_ARM || EIGEN_ARCH_MIPS) && (EIGEN_DEFAULT_ALIGN_BYTES == 16) #define EIGEN_FREEBSD_MALLOC_ALREADY_ALIGNED 1 #else #define EIGEN_FREEBSD_MALLOC_ALREADY_ALIGNED 0 #endif -#if defined(__APPLE__) \ - || defined(_WIN64) \ - || EIGEN_GLIBC_MALLOC_ALREADY_ALIGNED \ +#if (EIGEN_OS_MAC && (EIGEN_DEFAULT_ALIGN_BYTES == 16)) \ + || (EIGEN_OS_WIN64 && (EIGEN_DEFAULT_ALIGN_BYTES == 16)) \ + || EIGEN_GLIBC_MALLOC_ALREADY_ALIGNED \ || EIGEN_FREEBSD_MALLOC_ALREADY_ALIGNED #define EIGEN_MALLOC_ALREADY_ALIGNED 1 #else @@ -58,36 +59,17 @@ #endif -// See bug 554 (http://eigen.tuxfamily.org/bz/show_bug.cgi?id=554) -// It seems to be unsafe to check _POSIX_ADVISORY_INFO without including unistd.h first. -// Currently, let's include it only on unix systems: -#if defined(__unix__) || defined(__unix) - #include - #if ((defined __QNXNTO__) || (defined _GNU_SOURCE) || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600))) && (defined _POSIX_ADVISORY_INFO) && (_POSIX_ADVISORY_INFO > 0) - #define EIGEN_HAS_POSIX_MEMALIGN 1 - #endif -#endif - -#ifndef EIGEN_HAS_POSIX_MEMALIGN - #define EIGEN_HAS_POSIX_MEMALIGN 0 -#endif - -#ifdef EIGEN_VECTORIZE_SSE - #define EIGEN_HAS_MM_MALLOC 1 -#else - #define EIGEN_HAS_MM_MALLOC 0 -#endif - namespace Eigen { namespace internal { +EIGEN_DEVICE_FUNC inline void throw_std_bad_alloc() { #ifdef EIGEN_EXCEPTIONS throw std::bad_alloc(); #else - std::size_t huge = -1; + std::size_t huge = static_cast(-1); new int[huge]; #endif } @@ -103,9 +85,9 @@ inline void throw_std_bad_alloc() */ inline void* handmade_aligned_malloc(std::size_t size) { - void *original = std::malloc(size+16); + void *original = std::malloc(size+EIGEN_DEFAULT_ALIGN_BYTES); if (original == 0) return 0; - void *aligned = reinterpret_cast((reinterpret_cast(original) & ~(std::size_t(15))) + 16); + void *aligned = reinterpret_cast((reinterpret_cast(original) & ~(std::size_t(EIGEN_DEFAULT_ALIGN_BYTES-1))) + EIGEN_DEFAULT_ALIGN_BYTES); *(reinterpret_cast(aligned) - 1) = original; return aligned; } @@ -118,7 +100,7 @@ inline void handmade_aligned_free(void *ptr) /** \internal * \brief Reallocates aligned memory. - * Since we know that our handmade version is based on std::realloc + * Since we know that our handmade version is based on std::malloc * we can use std::realloc to implement efficient reallocation. */ inline void* handmade_aligned_realloc(void* ptr, std::size_t size, std::size_t = 0) @@ -126,9 +108,9 @@ inline void* handmade_aligned_realloc(void* ptr, std::size_t size, std::size_t = if (ptr == 0) return handmade_aligned_malloc(size); void *original = *(reinterpret_cast(ptr) - 1); std::ptrdiff_t previous_offset = static_cast(ptr)-static_cast(original); - original = std::realloc(original,size+16); + original = std::realloc(original,size+EIGEN_DEFAULT_ALIGN_BYTES); if (original == 0) return 0; - void *aligned = reinterpret_cast((reinterpret_cast(original) & ~(std::size_t(15))) + 16); + void *aligned = reinterpret_cast((reinterpret_cast(original) & ~(std::size_t(EIGEN_DEFAULT_ALIGN_BYTES-1))) + EIGEN_DEFAULT_ALIGN_BYTES); void *previous_aligned = static_cast(original)+previous_offset; if(aligned!=previous_aligned) std::memmove(aligned, previous_aligned, size); @@ -137,93 +119,47 @@ inline void* handmade_aligned_realloc(void* ptr, std::size_t size, std::size_t = return aligned; } -/***************************************************************************** -*** Implementation of generic aligned realloc (when no realloc can be used)*** -*****************************************************************************/ - -void* aligned_malloc(std::size_t size); -void aligned_free(void *ptr); - -/** \internal - * \brief Reallocates aligned memory. - * Allows reallocation with aligned ptr types. This implementation will - * always create a new memory chunk and copy the old data. - */ -inline void* generic_aligned_realloc(void* ptr, size_t size, size_t old_size) -{ - if (ptr==0) - return aligned_malloc(size); - - if (size==0) - { - aligned_free(ptr); - return 0; - } - - void* newptr = aligned_malloc(size); - if (newptr == 0) - { - #ifdef EIGEN_HAS_ERRNO - errno = ENOMEM; // according to the standard - #endif - return 0; - } - - if (ptr != 0) - { - std::memcpy(newptr, ptr, (std::min)(size,old_size)); - aligned_free(ptr); - } - - return newptr; -} - /***************************************************************************** *** Implementation of portable aligned versions of malloc/free/realloc *** *****************************************************************************/ #ifdef EIGEN_NO_MALLOC -inline void check_that_malloc_is_allowed() +EIGEN_DEVICE_FUNC inline void check_that_malloc_is_allowed() { eigen_assert(false && "heap allocation is forbidden (EIGEN_NO_MALLOC is defined)"); } #elif defined EIGEN_RUNTIME_NO_MALLOC -inline bool is_malloc_allowed_impl(bool update, bool new_value = false) +EIGEN_DEVICE_FUNC inline bool is_malloc_allowed_impl(bool update, bool new_value = false) { static bool value = true; if (update == 1) value = new_value; return value; } -inline bool is_malloc_allowed() { return is_malloc_allowed_impl(false); } -inline bool set_is_malloc_allowed(bool new_value) { return is_malloc_allowed_impl(true, new_value); } -inline void check_that_malloc_is_allowed() +EIGEN_DEVICE_FUNC inline bool is_malloc_allowed() { return is_malloc_allowed_impl(false); } +EIGEN_DEVICE_FUNC inline bool set_is_malloc_allowed(bool new_value) { return is_malloc_allowed_impl(true, new_value); } +EIGEN_DEVICE_FUNC inline void check_that_malloc_is_allowed() { eigen_assert(is_malloc_allowed() && "heap allocation is forbidden (EIGEN_RUNTIME_NO_MALLOC is defined and g_is_malloc_allowed is false)"); } #else -inline void check_that_malloc_is_allowed() +EIGEN_DEVICE_FUNC inline void check_that_malloc_is_allowed() {} #endif -/** \internal Allocates \a size bytes. The returned pointer is guaranteed to have 16 bytes alignment. +/** \internal Allocates \a size bytes. The returned pointer is guaranteed to have 16 or 32 bytes alignment depending on the requirements. * On allocation error, the returned pointer is null, and std::bad_alloc is thrown. */ -inline void* aligned_malloc(size_t size) +EIGEN_DEVICE_FUNC inline void* aligned_malloc(std::size_t size) { check_that_malloc_is_allowed(); void *result; - #if !EIGEN_ALIGN - result = std::malloc(size); - #elif EIGEN_MALLOC_ALREADY_ALIGNED + #if (EIGEN_DEFAULT_ALIGN_BYTES==0) || EIGEN_MALLOC_ALREADY_ALIGNED result = std::malloc(size); - #elif EIGEN_HAS_POSIX_MEMALIGN - if(posix_memalign(&result, 16, size)) result = 0; - #elif EIGEN_HAS_MM_MALLOC - result = _mm_malloc(size, 16); - #elif defined(_MSC_VER) && (!defined(_WIN32_WCE)) - result = _aligned_malloc(size, 16); + #if EIGEN_DEFAULT_ALIGN_BYTES==16 + eigen_assert((size<16 || (std::size_t(result)%16)==0) && "System's malloc returned an unaligned pointer. Compile with EIGEN_MALLOC_ALREADY_ALIGNED=0 to fallback to handmade alignd memory allocator."); + #endif #else result = handmade_aligned_malloc(size); #endif @@ -235,50 +171,27 @@ inline void* aligned_malloc(size_t size) } /** \internal Frees memory allocated with aligned_malloc. */ -inline void aligned_free(void *ptr) +EIGEN_DEVICE_FUNC inline void aligned_free(void *ptr) { - #if !EIGEN_ALIGN - std::free(ptr); - #elif EIGEN_MALLOC_ALREADY_ALIGNED - std::free(ptr); - #elif EIGEN_HAS_POSIX_MEMALIGN + #if (EIGEN_DEFAULT_ALIGN_BYTES==0) || EIGEN_MALLOC_ALREADY_ALIGNED std::free(ptr); - #elif EIGEN_HAS_MM_MALLOC - _mm_free(ptr); - #elif defined(_MSC_VER) && (!defined(_WIN32_WCE)) - _aligned_free(ptr); #else handmade_aligned_free(ptr); #endif } /** -* \internal -* \brief Reallocates an aligned block of memory. -* \throws std::bad_alloc on allocation failure -**/ -inline void* aligned_realloc(void *ptr, size_t new_size, size_t old_size) + * \internal + * \brief Reallocates an aligned block of memory. + * \throws std::bad_alloc on allocation failure + */ +inline void* aligned_realloc(void *ptr, std::size_t new_size, std::size_t old_size) { EIGEN_UNUSED_VARIABLE(old_size); void *result; -#if !EIGEN_ALIGN - result = std::realloc(ptr,new_size); -#elif EIGEN_MALLOC_ALREADY_ALIGNED +#if (EIGEN_DEFAULT_ALIGN_BYTES==0) || EIGEN_MALLOC_ALREADY_ALIGNED result = std::realloc(ptr,new_size); -#elif EIGEN_HAS_POSIX_MEMALIGN - result = generic_aligned_realloc(ptr,new_size,old_size); -#elif EIGEN_HAS_MM_MALLOC - // The defined(_mm_free) is just here to verify that this MSVC version - // implements _mm_malloc/_mm_free based on the corresponding _aligned_ - // functions. This may not always be the case and we just try to be safe. - #if defined(_MSC_VER) && (!defined(_WIN32_WCE)) && defined(_mm_free) - result = _aligned_realloc(ptr,new_size,16); - #else - result = generic_aligned_realloc(ptr,new_size,old_size); - #endif -#elif defined(_MSC_VER) && (!defined(_WIN32_WCE)) - result = _aligned_realloc(ptr,new_size,16); #else result = handmade_aligned_realloc(ptr,new_size,old_size); #endif @@ -296,12 +209,12 @@ inline void* aligned_realloc(void *ptr, size_t new_size, size_t old_size) /** \internal Allocates \a size bytes. If Align is true, then the returned ptr is 16-byte-aligned. * On allocation error, the returned pointer is null, and a std::bad_alloc is thrown. */ -template inline void* conditional_aligned_malloc(size_t size) +template EIGEN_DEVICE_FUNC inline void* conditional_aligned_malloc(std::size_t size) { return aligned_malloc(size); } -template<> inline void* conditional_aligned_malloc(size_t size) +template<> EIGEN_DEVICE_FUNC inline void* conditional_aligned_malloc(std::size_t size) { check_that_malloc_is_allowed(); @@ -312,22 +225,22 @@ template<> inline void* conditional_aligned_malloc(size_t size) } /** \internal Frees memory allocated with conditional_aligned_malloc */ -template inline void conditional_aligned_free(void *ptr) +template EIGEN_DEVICE_FUNC inline void conditional_aligned_free(void *ptr) { aligned_free(ptr); } -template<> inline void conditional_aligned_free(void *ptr) +template<> EIGEN_DEVICE_FUNC inline void conditional_aligned_free(void *ptr) { std::free(ptr); } -template inline void* conditional_aligned_realloc(void* ptr, size_t new_size, size_t old_size) +template inline void* conditional_aligned_realloc(void* ptr, std::size_t new_size, std::size_t old_size) { return aligned_realloc(ptr, new_size, old_size); } -template<> inline void* conditional_aligned_realloc(void* ptr, size_t new_size, size_t) +template<> inline void* conditional_aligned_realloc(void* ptr, std::size_t new_size, std::size_t) { return std::realloc(ptr, new_size); } @@ -336,33 +249,43 @@ template<> inline void* conditional_aligned_realloc(void* ptr, size_t new *** Construction/destruction of array elements *** *****************************************************************************/ -/** \internal Constructs the elements of an array. - * The \a size parameter tells on how many objects to call the constructor of T. - */ -template inline T* construct_elements_of_array(T *ptr, size_t size) -{ - for (size_t i=0; i < size; ++i) ::new (ptr + i) T; - return ptr; -} - /** \internal Destructs the elements of an array. * The \a size parameters tells on how many objects to call the destructor of T. */ -template inline void destruct_elements_of_array(T *ptr, size_t size) +template EIGEN_DEVICE_FUNC inline void destruct_elements_of_array(T *ptr, std::size_t size) { // always destruct an array starting from the end. if(ptr) while(size) ptr[--size].~T(); } +/** \internal Constructs the elements of an array. + * The \a size parameter tells on how many objects to call the constructor of T. + */ +template EIGEN_DEVICE_FUNC inline T* construct_elements_of_array(T *ptr, std::size_t size) +{ + std::size_t i; + EIGEN_TRY + { + for (i = 0; i < size; ++i) ::new (ptr + i) T; + return ptr; + } + EIGEN_CATCH(...) + { + destruct_elements_of_array(ptr, i); + EIGEN_THROW; + } + return NULL; +} + /***************************************************************************** *** Implementation of aligned new/delete-like functions *** *****************************************************************************/ template -EIGEN_ALWAYS_INLINE void check_size_for_overflow(size_t size) +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE void check_size_for_overflow(std::size_t size) { - if(size > size_t(-1) / sizeof(T)) + if(size > std::size_t(-1) / sizeof(T)) throw_std_bad_alloc(); } @@ -370,24 +293,42 @@ EIGEN_ALWAYS_INLINE void check_size_for_overflow(size_t size) * On allocation error, the returned pointer is undefined, but a std::bad_alloc is thrown. * The default constructor of T is called. */ -template inline T* aligned_new(size_t size) +template EIGEN_DEVICE_FUNC inline T* aligned_new(std::size_t size) { check_size_for_overflow(size); T *result = reinterpret_cast(aligned_malloc(sizeof(T)*size)); - return construct_elements_of_array(result, size); + EIGEN_TRY + { + return construct_elements_of_array(result, size); + } + EIGEN_CATCH(...) + { + aligned_free(result); + EIGEN_THROW; + } + return result; } -template inline T* conditional_aligned_new(size_t size) +template EIGEN_DEVICE_FUNC inline T* conditional_aligned_new(std::size_t size) { check_size_for_overflow(size); T *result = reinterpret_cast(conditional_aligned_malloc(sizeof(T)*size)); - return construct_elements_of_array(result, size); + EIGEN_TRY + { + return construct_elements_of_array(result, size); + } + EIGEN_CATCH(...) + { + conditional_aligned_free(result); + EIGEN_THROW; + } + return result; } /** \internal Deletes objects constructed with aligned_new * The \a size parameters tells on how many objects to call the destructor of T. */ -template inline void aligned_delete(T *ptr, size_t size) +template EIGEN_DEVICE_FUNC inline void aligned_delete(T *ptr, std::size_t size) { destruct_elements_of_array(ptr, size); aligned_free(ptr); @@ -396,13 +337,13 @@ template inline void aligned_delete(T *ptr, size_t size) /** \internal Deletes objects constructed with conditional_aligned_new * The \a size parameters tells on how many objects to call the destructor of T. */ -template inline void conditional_aligned_delete(T *ptr, size_t size) +template EIGEN_DEVICE_FUNC inline void conditional_aligned_delete(T *ptr, std::size_t size) { destruct_elements_of_array(ptr, size); conditional_aligned_free(ptr); } -template inline T* conditional_aligned_realloc_new(T* pts, size_t new_size, size_t old_size) +template EIGEN_DEVICE_FUNC inline T* conditional_aligned_realloc_new(T* pts, std::size_t new_size, std::size_t old_size) { check_size_for_overflow(new_size); check_size_for_overflow(old_size); @@ -410,21 +351,43 @@ template inline T* conditional_aligned_realloc_new(T* pt destruct_elements_of_array(pts+new_size, old_size-new_size); T *result = reinterpret_cast(conditional_aligned_realloc(reinterpret_cast(pts), sizeof(T)*new_size, sizeof(T)*old_size)); if(new_size > old_size) - construct_elements_of_array(result+old_size, new_size-old_size); + { + EIGEN_TRY + { + construct_elements_of_array(result+old_size, new_size-old_size); + } + EIGEN_CATCH(...) + { + conditional_aligned_free(result); + EIGEN_THROW; + } + } return result; } -template inline T* conditional_aligned_new_auto(size_t size) +template EIGEN_DEVICE_FUNC inline T* conditional_aligned_new_auto(std::size_t size) { + if(size==0) + return 0; // short-cut. Also fixes Bug 884 check_size_for_overflow(size); T *result = reinterpret_cast(conditional_aligned_malloc(sizeof(T)*size)); if(NumTraits::RequireInitialization) - construct_elements_of_array(result, size); + { + EIGEN_TRY + { + construct_elements_of_array(result, size); + } + EIGEN_CATCH(...) + { + conditional_aligned_free(result); + EIGEN_THROW; + } + } return result; } -template inline T* conditional_aligned_realloc_new_auto(T* pts, size_t new_size, size_t old_size) +template inline T* conditional_aligned_realloc_new_auto(T* pts, std::size_t new_size, std::size_t old_size) { check_size_for_overflow(new_size); check_size_for_overflow(old_size); @@ -432,11 +395,21 @@ template inline T* conditional_aligned_realloc_new_auto( destruct_elements_of_array(pts+new_size, old_size-new_size); T *result = reinterpret_cast(conditional_aligned_realloc(reinterpret_cast(pts), sizeof(T)*new_size, sizeof(T)*old_size)); if(NumTraits::RequireInitialization && (new_size > old_size)) - construct_elements_of_array(result+old_size, new_size-old_size); + { + EIGEN_TRY + { + construct_elements_of_array(result+old_size, new_size-old_size); + } + EIGEN_CATCH(...) + { + conditional_aligned_free(result); + EIGEN_THROW; + } + } return result; } -template inline void conditional_aligned_delete_auto(T *ptr, size_t size) +template EIGEN_DEVICE_FUNC inline void conditional_aligned_delete_auto(T *ptr, std::size_t size) { if(NumTraits::RequireInitialization) destruct_elements_of_array(ptr, size); @@ -445,52 +418,62 @@ template inline void conditional_aligned_delete_auto(T * /****************************************************************************/ -/** \internal Returns the index of the first element of the array that is well aligned for vectorization. +/** \internal Returns the index of the first element of the array that is well aligned with respect to the requested \a Alignment. * + * \tparam Alignment requested alignment in Bytes. * \param array the address of the start of the array * \param size the size of the array * - * \note If no element of the array is well aligned, the size of the array is returned. Typically, - * for example with SSE, "well aligned" means 16-byte-aligned. If vectorization is disabled or if the + * \note If no element of the array is well aligned or the requested alignment is not a multiple of a scalar, + * the size of the array is returned. For example with SSE, the requested alignment is typically 16-bytes. If * packet size for the given scalar type is 1, then everything is considered well-aligned. * - * \note If the scalar type is vectorizable, we rely on the following assumptions: sizeof(Scalar) is a - * power of 2, the packet size in bytes is also a power of 2, and is a multiple of sizeof(Scalar). On the - * other hand, we do not assume that the array address is a multiple of sizeof(Scalar), as that fails for + * \note Otherwise, if the Alignment is larger that the scalar size, we rely on the assumptions that sizeof(Scalar) is a + * power of 2. On the other hand, we do not assume that the array address is a multiple of sizeof(Scalar), as that fails for * example with Scalar=double on certain 32-bit platforms, see bug #79. * * There is also the variant first_aligned(const MatrixBase&) defined in DenseCoeffsBase.h. + * \sa first_default_aligned() */ -template -static inline Index first_aligned(const Scalar* array, Index size) +template +EIGEN_DEVICE_FUNC inline Index first_aligned(const Scalar* array, Index size) { - enum { PacketSize = packet_traits::size, - PacketAlignedMask = PacketSize-1 - }; + const Index ScalarSize = sizeof(Scalar); + const Index AlignmentSize = Alignment / ScalarSize; + const Index AlignmentMask = AlignmentSize-1; - if(PacketSize==1) + if(AlignmentSize<=1) { - // Either there is no vectorization, or a packet consists of exactly 1 scalar so that all elements - // of the array have the same alignment. + // Either the requested alignment if smaller than a scalar, or it exactly match a 1 scalar + // so that all elements of the array have the same alignment. return 0; } - else if(size_t(array) & (sizeof(Scalar)-1)) + else if( (UIntPtr(array) & (sizeof(Scalar)-1)) || (Alignment%ScalarSize)!=0) { - // There is vectorization for this scalar type, but the array is not aligned to the size of a single scalar. + // The array is not aligned to the size of a single scalar, or the requested alignment is not a multiple of the scalar size. // Consequently, no element of the array is well aligned. return size; } else { - return std::min( (PacketSize - (Index((size_t(array)/sizeof(Scalar))) & PacketAlignedMask)) - & PacketAlignedMask, size); + Index first = (AlignmentSize - (Index((UIntPtr(array)/sizeof(Scalar))) & AlignmentMask)) & AlignmentMask; + return (first < size) ? first : size; } } +/** \internal Returns the index of the first element of the array that is well aligned with respect the largest packet requirement. + * \sa first_aligned(Scalar*,Index) and first_default_aligned(DenseBase) */ +template +EIGEN_DEVICE_FUNC inline Index first_default_aligned(const Scalar* array, Index size) +{ + typedef typename packet_traits::type DefaultPacketType; + return first_aligned::alignment>(array, size); +} + /** \internal Returns the smallest integer multiple of \a base and greater or equal to \a size */ template -inline static Index first_multiple(Index size, Index base) +inline Index first_multiple(Index size, Index base) { return ((size+base-1)/base)*base; } @@ -499,21 +482,59 @@ inline static Index first_multiple(Index size, Index base) // use memcpy on trivial types, i.e., on types that does not require an initialization ctor. template struct smart_copy_helper; -template void smart_copy(const T* start, const T* end, T* target) +template EIGEN_DEVICE_FUNC void smart_copy(const T* start, const T* end, T* target) { smart_copy_helper::RequireInitialization>::run(start, end, target); } template struct smart_copy_helper { - static inline void run(const T* start, const T* end, T* target) - { memcpy(target, start, std::ptrdiff_t(end)-std::ptrdiff_t(start)); } + EIGEN_DEVICE_FUNC static inline void run(const T* start, const T* end, T* target) + { + IntPtr size = IntPtr(end)-IntPtr(start); + if(size==0) return; + eigen_internal_assert(start!=0 && end!=0 && target!=0); + memcpy(target, start, size); + } }; template struct smart_copy_helper { - static inline void run(const T* start, const T* end, T* target) + EIGEN_DEVICE_FUNC static inline void run(const T* start, const T* end, T* target) { std::copy(start, end, target); } }; +// intelligent memmove. falls back to std::memmove for POD types, uses std::copy otherwise. +template struct smart_memmove_helper; + +template void smart_memmove(const T* start, const T* end, T* target) +{ + smart_memmove_helper::RequireInitialization>::run(start, end, target); +} + +template struct smart_memmove_helper { + static inline void run(const T* start, const T* end, T* target) + { + IntPtr size = IntPtr(end)-IntPtr(start); + if(size==0) return; + eigen_internal_assert(start!=0 && end!=0 && target!=0); + std::memmove(target, start, size); + } +}; + +template struct smart_memmove_helper { + static inline void run(const T* start, const T* end, T* target) + { + if (UIntPtr(target) < UIntPtr(start)) + { + std::copy(start, end, target); + } + else + { + std::ptrdiff_t count = (std::ptrdiff_t(end)-std::ptrdiff_t(start)) / sizeof(T); + std::copy_backward(start, end, target + count); + } + } +}; + /***************************************************************************** *** Implementation of runtime stack allocation (falling back to malloc) *** @@ -522,16 +543,16 @@ template struct smart_copy_helper { // you can overwrite Eigen's default behavior regarding alloca by defining EIGEN_ALLOCA // to the appropriate stack allocation function #ifndef EIGEN_ALLOCA - #if (defined __linux__) + #if EIGEN_OS_LINUX || EIGEN_OS_MAC || (defined alloca) #define EIGEN_ALLOCA alloca - #elif defined(_MSC_VER) + #elif EIGEN_COMP_MSVC #define EIGEN_ALLOCA _alloca #endif #endif // This helper class construct the allocated memory, and takes care of destructing and freeing the handled data // at destruction time. In practice this helper class is mainly useful to avoid memory leak in case of exceptions. -template class aligned_stack_memory_handler +template class aligned_stack_memory_handler : noncopyable { public: /* Creates a stack_memory_handler responsible for the buffer \a ptr of size \a size. @@ -540,7 +561,7 @@ template class aligned_stack_memory_handler * In this case, the buffer elements will also be destructed when this handler will be destructed. * Finally, if \a dealloc is true, then the pointer \a ptr is freed. **/ - aligned_stack_memory_handler(T* ptr, size_t size, bool dealloc) + aligned_stack_memory_handler(T* ptr, std::size_t size, bool dealloc) : m_ptr(ptr), m_size(size), m_deallocate(dealloc) { if(NumTraits::RequireInitialization && m_ptr) @@ -555,10 +576,34 @@ template class aligned_stack_memory_handler } protected: T* m_ptr; - size_t m_size; + std::size_t m_size; bool m_deallocate; }; +template class scoped_array : noncopyable +{ + T* m_ptr; +public: + explicit scoped_array(std::ptrdiff_t size) + { + m_ptr = new T[size]; + } + ~scoped_array() + { + delete[] m_ptr; + } + T& operator[](std::ptrdiff_t i) { return m_ptr[i]; } + const T& operator[](std::ptrdiff_t i) const { return m_ptr[i]; } + T* &ptr() { return m_ptr; } + const T* ptr() const { return m_ptr; } + operator const T*() const { return m_ptr; } +}; + +template void swap(scoped_array &a,scoped_array &b) +{ + std::swap(a.ptr(),b.ptr()); +} + } // end namespace internal /** \internal @@ -577,11 +622,13 @@ template class aligned_stack_memory_handler * The underlying stack allocation function can controlled with the EIGEN_ALLOCA preprocessor token. */ #ifdef EIGEN_ALLOCA - - #if defined(__arm__) || defined(_WIN32) - #define EIGEN_ALIGNED_ALLOCA(SIZE) reinterpret_cast((reinterpret_cast(EIGEN_ALLOCA(SIZE+16)) & ~(size_t(15))) + 16) + + #if EIGEN_DEFAULT_ALIGN_BYTES>0 + // We always manually re-align the result of EIGEN_ALLOCA. + // If alloca is already aligned, the compiler should be smart enough to optimize away the re-alignment. + #define EIGEN_ALIGNED_ALLOCA(SIZE) reinterpret_cast((internal::UIntPtr(EIGEN_ALLOCA(SIZE+EIGEN_DEFAULT_ALIGN_BYTES-1)) + EIGEN_DEFAULT_ALIGN_BYTES-1) & ~(std::size_t(EIGEN_DEFAULT_ALIGN_BYTES-1))) #else - #define EIGEN_ALIGNED_ALLOCA EIGEN_ALLOCA + #define EIGEN_ALIGNED_ALLOCA(SIZE) EIGEN_ALLOCA(SIZE) #endif #define ei_declare_aligned_stack_constructed_variable(TYPE,NAME,SIZE,BUFFER) \ @@ -606,40 +653,33 @@ template class aligned_stack_memory_handler *** Implementation of EIGEN_MAKE_ALIGNED_OPERATOR_NEW [_IF] *** *****************************************************************************/ -#if EIGEN_ALIGN - #ifdef EIGEN_EXCEPTIONS - #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_NOTHROW(NeedsToAlign) \ - void* operator new(size_t size, const std::nothrow_t&) throw() { \ - try { return Eigen::internal::conditional_aligned_malloc(size); } \ - catch (...) { return 0; } \ - return 0; \ +#if EIGEN_MAX_ALIGN_BYTES!=0 + #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_NOTHROW(NeedsToAlign) \ + void* operator new(std::size_t size, const std::nothrow_t&) EIGEN_NO_THROW { \ + EIGEN_TRY { return Eigen::internal::conditional_aligned_malloc(size); } \ + EIGEN_CATCH (...) { return 0; } \ } - #else - #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_NOTHROW(NeedsToAlign) \ - void* operator new(size_t size, const std::nothrow_t&) throw() { \ - return Eigen::internal::conditional_aligned_malloc(size); \ - } - #endif - #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) \ - void *operator new(size_t size) { \ + void *operator new(std::size_t size) { \ return Eigen::internal::conditional_aligned_malloc(size); \ } \ - void *operator new[](size_t size) { \ + void *operator new[](std::size_t size) { \ return Eigen::internal::conditional_aligned_malloc(size); \ } \ - void operator delete(void * ptr) throw() { Eigen::internal::conditional_aligned_free(ptr); } \ - void operator delete[](void * ptr) throw() { Eigen::internal::conditional_aligned_free(ptr); } \ + void operator delete(void * ptr) EIGEN_NO_THROW { Eigen::internal::conditional_aligned_free(ptr); } \ + void operator delete[](void * ptr) EIGEN_NO_THROW { Eigen::internal::conditional_aligned_free(ptr); } \ + void operator delete(void * ptr, std::size_t /* sz */) EIGEN_NO_THROW { Eigen::internal::conditional_aligned_free(ptr); } \ + void operator delete[](void * ptr, std::size_t /* sz */) EIGEN_NO_THROW { Eigen::internal::conditional_aligned_free(ptr); } \ /* in-place new and delete. since (at least afaik) there is no actual */ \ /* memory allocated we can safely let the default implementation handle */ \ /* this particular case. */ \ - static void *operator new(size_t size, void *ptr) { return ::operator new(size,ptr); } \ - static void *operator new[](size_t size, void* ptr) { return ::operator new[](size,ptr); } \ - void operator delete(void * memory, void *ptr) throw() { return ::operator delete(memory,ptr); } \ - void operator delete[](void * memory, void *ptr) throw() { return ::operator delete[](memory,ptr); } \ + static void *operator new(std::size_t size, void *ptr) { return ::operator new(size,ptr); } \ + static void *operator new[](std::size_t size, void* ptr) { return ::operator new[](size,ptr); } \ + void operator delete(void * memory, void *ptr) EIGEN_NO_THROW { return ::operator delete(memory,ptr); } \ + void operator delete[](void * memory, void *ptr) EIGEN_NO_THROW { return ::operator delete[](memory,ptr); } \ /* nothrow-new (returns zero instead of std::bad_alloc) */ \ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_NOTHROW(NeedsToAlign) \ - void operator delete(void *ptr, const std::nothrow_t&) throw() { \ + void operator delete(void *ptr, const std::nothrow_t&) EIGEN_NO_THROW { \ Eigen::internal::conditional_aligned_free(ptr); \ } \ typedef void eigen_aligned_operator_new_marker_type; @@ -649,7 +689,7 @@ template class aligned_stack_memory_handler #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(true) #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar,Size) \ - EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(bool(((Size)!=Eigen::Dynamic) && ((sizeof(Scalar)*(Size))%16==0))) + EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(bool(((Size)!=Eigen::Dynamic) && ((sizeof(Scalar)*(Size))%EIGEN_MAX_ALIGN_BYTES==0))) /****************************************************************************/ @@ -667,96 +707,56 @@ template class aligned_stack_memory_handler * std::map< int, Vector3f > my_map_vec3; * \endcode * -* \sa \ref TopicStlContainers. +* \sa \blank \ref TopicStlContainers. */ template -class aligned_allocator +class aligned_allocator : public std::allocator { public: - typedef size_t size_type; - typedef std::ptrdiff_t difference_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef T value_type; - - template - struct rebind - { - typedef aligned_allocator other; - }; - - pointer address( reference value ) const - { - return &value; - } - - const_pointer address( const_reference value ) const - { - return &value; - } - - aligned_allocator() - { - } - - aligned_allocator( const aligned_allocator& ) - { - } - - template - aligned_allocator( const aligned_allocator& ) - { - } - - ~aligned_allocator() - { - } - - size_type max_size() const - { - return (std::numeric_limits::max)(); - } + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + template + struct rebind + { + typedef aligned_allocator other; + }; - pointer allocate( size_type num, const void* hint = 0 ) - { - EIGEN_UNUSED_VARIABLE(hint); - internal::check_size_for_overflow(num); - return static_cast( internal::aligned_malloc( num * sizeof(T) ) ); - } + aligned_allocator() : std::allocator() {} - void construct( pointer p, const T& value ) - { - ::new( p ) T( value ); - } + aligned_allocator(const aligned_allocator& other) : std::allocator(other) {} - void destroy( pointer p ) - { - p->~T(); - } + template + aligned_allocator(const aligned_allocator& other) : std::allocator(other) {} - void deallocate( pointer p, size_type /*num*/ ) - { - internal::aligned_free( p ); - } + ~aligned_allocator() {} - bool operator!=(const aligned_allocator& ) const - { return false; } + pointer allocate(size_type num, const void* /*hint*/ = 0) + { + internal::check_size_for_overflow(num); + return static_cast( internal::aligned_malloc(num * sizeof(T)) ); + } - bool operator==(const aligned_allocator& ) const - { return true; } + void deallocate(pointer p, size_type /*num*/) + { + internal::aligned_free(p); + } }; //---------- Cache sizes ---------- #if !defined(EIGEN_NO_CPUID) -# if defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) -# if defined(__PIC__) && defined(__i386__) +# if EIGEN_COMP_GNUC && EIGEN_ARCH_i386_OR_x86_64 +# if defined(__PIC__) && EIGEN_ARCH_i386 // Case for x86 with PIC # define EIGEN_CPUID(abcd,func,id) \ __asm__ __volatile__ ("xchgl %%ebx, %k1;cpuid; xchgl %%ebx,%k1": "=a" (abcd[0]), "=&r" (abcd[1]), "=c" (abcd[2]), "=d" (abcd[3]) : "a" (func), "c" (id)); -# elif defined(__PIC__) && defined(__x86_64__) +# elif defined(__PIC__) && EIGEN_ARCH_x86_64 // Case for x64 with PIC. In theory this is only a problem with recent gcc and with medium or large code model, not with the default small code model. // However, we cannot detect which code model is used, and the xchg overhead is negligible anyway. # define EIGEN_CPUID(abcd,func,id) \ @@ -766,8 +766,8 @@ class aligned_allocator # define EIGEN_CPUID(abcd,func,id) \ __asm__ __volatile__ ("cpuid": "=a" (abcd[0]), "=b" (abcd[1]), "=c" (abcd[2]), "=d" (abcd[3]) : "0" (func), "2" (id) ); # endif -# elif defined(_MSC_VER) -# if (_MSC_VER > 1500) && ( defined(_M_IX86) || defined(_M_X64) ) +# elif EIGEN_COMP_MSVC +# if (EIGEN_COMP_MSVC > 1500) && EIGEN_ARCH_i386_OR_x86_64 # define EIGEN_CPUID(abcd,func,id) __cpuidex((int*)abcd,func,id) # endif # endif diff --git a/libs/eigen3/Eigen/src/Core/util/Meta.h b/libs/eigen3/Eigen/src/Core/util/Meta.h old mode 100644 new mode 100755 index 71d587108..7f6370755 --- a/libs/eigen3/Eigen/src/Core/util/Meta.h +++ b/libs/eigen3/Eigen/src/Core/util/Meta.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2008-2015 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla @@ -11,8 +11,27 @@ #ifndef EIGEN_META_H #define EIGEN_META_H +#if defined(__CUDA_ARCH__) +#include +#include +#endif + +#if EIGEN_COMP_ICC>=1600 && __cplusplus >= 201103L +#include +#endif + namespace Eigen { +typedef EIGEN_DEFAULT_DENSE_INDEX_TYPE DenseIndex; + +/** + * \brief The Index type as used for the API. + * \details To change this, \c \#define the preprocessor symbol \c EIGEN_DEFAULT_DENSE_INDEX_TYPE. + * \sa \blank \ref TopicPreprocessorDirectives, StorageIndex. + */ + +typedef EIGEN_DEFAULT_DENSE_INDEX_TYPE Index; + namespace internal { /** \internal @@ -22,6 +41,16 @@ namespace internal { * we however don't want to add a dependency to Boost. */ +// Only recent versions of ICC complain about using ptrdiff_t to hold pointers, +// and older versions do not provide *intptr_t types. +#if EIGEN_COMP_ICC>=1600 && __cplusplus >= 201103L +typedef std::intptr_t IntPtr; +typedef std::uintptr_t UIntPtr; +#else +typedef std::ptrdiff_t IntPtr; +typedef std::size_t UIntPtr; +#endif + struct true_type { enum { value = 1 }; }; struct false_type { enum { value = 0 }; }; @@ -68,6 +97,18 @@ template<> struct is_arithmetic { enum { value = true }; }; template<> struct is_arithmetic { enum { value = true }; }; template<> struct is_arithmetic { enum { value = true }; }; +template struct is_integral { enum { value = false }; }; +template<> struct is_integral { enum { value = true }; }; +template<> struct is_integral { enum { value = true }; }; +template<> struct is_integral { enum { value = true }; }; +template<> struct is_integral { enum { value = true }; }; +template<> struct is_integral { enum { value = true }; }; +template<> struct is_integral { enum { value = true }; }; +template<> struct is_integral { enum { value = true }; }; +template<> struct is_integral { enum { value = true }; }; +template<> struct is_integral { enum { value = true }; }; +template<> struct is_integral { enum { value = true }; }; + template struct add_const { typedef const T type; }; template struct add_const { typedef T& type; }; @@ -80,29 +121,163 @@ template struct add_const_on_value_type { typedef T const template struct add_const_on_value_type { typedef T const* const type; }; template struct add_const_on_value_type { typedef T const* const type; }; + +template +struct is_convertible_impl +{ +private: + struct any_conversion + { + template any_conversion(const volatile T&); + template any_conversion(T&); + }; + struct yes {int a[1];}; + struct no {int a[2];}; + + static yes test(const To&, int); + static no test(any_conversion, ...); + +public: + static From ms_from; +#ifdef __INTEL_COMPILER + #pragma warning push + #pragma warning ( disable : 2259 ) +#endif + enum { value = sizeof(test(ms_from, 0))==sizeof(yes) }; +#ifdef __INTEL_COMPILER + #pragma warning pop +#endif +}; + +template +struct is_convertible +{ + enum { value = is_convertible_impl::type, + typename remove_all::type>::value }; +}; + /** \internal Allows to enable/disable an overload * according to a compile time condition. */ -template struct enable_if; +template struct enable_if; template struct enable_if { typedef T type; }; +#if defined(__CUDA_ARCH__) +#if !defined(__FLT_EPSILON__) +#define __FLT_EPSILON__ FLT_EPSILON +#define __DBL_EPSILON__ DBL_EPSILON +#endif +namespace device { + +template struct numeric_limits +{ + EIGEN_DEVICE_FUNC + static T epsilon() { return 0; } + static T (max)() { assert(false && "Highest not supported for this type"); } + static T (min)() { assert(false && "Lowest not supported for this type"); } + static T infinity() { assert(false && "Infinity not supported for this type"); } + static T quiet_NaN() { assert(false && "quiet_NaN not supported for this type"); } +}; +template<> struct numeric_limits +{ + EIGEN_DEVICE_FUNC + static float epsilon() { return __FLT_EPSILON__; } + EIGEN_DEVICE_FUNC + static float (max)() { return CUDART_MAX_NORMAL_F; } + EIGEN_DEVICE_FUNC + static float (min)() { return FLT_MIN; } + EIGEN_DEVICE_FUNC + static float infinity() { return CUDART_INF_F; } + EIGEN_DEVICE_FUNC + static float quiet_NaN() { return CUDART_NAN_F; } +}; +template<> struct numeric_limits +{ + EIGEN_DEVICE_FUNC + static double epsilon() { return __DBL_EPSILON__; } + EIGEN_DEVICE_FUNC + static double (max)() { return DBL_MAX; } + EIGEN_DEVICE_FUNC + static double (min)() { return DBL_MIN; } + EIGEN_DEVICE_FUNC + static double infinity() { return CUDART_INF; } + EIGEN_DEVICE_FUNC + static double quiet_NaN() { return CUDART_NAN; } +}; +template<> struct numeric_limits +{ + EIGEN_DEVICE_FUNC + static int epsilon() { return 0; } + EIGEN_DEVICE_FUNC + static int (max)() { return INT_MAX; } + EIGEN_DEVICE_FUNC + static int (min)() { return INT_MIN; } +}; +template<> struct numeric_limits +{ + EIGEN_DEVICE_FUNC + static unsigned int epsilon() { return 0; } + EIGEN_DEVICE_FUNC + static unsigned int (max)() { return UINT_MAX; } + EIGEN_DEVICE_FUNC + static unsigned int (min)() { return 0; } +}; +template<> struct numeric_limits +{ + EIGEN_DEVICE_FUNC + static long epsilon() { return 0; } + EIGEN_DEVICE_FUNC + static long (max)() { return LONG_MAX; } + EIGEN_DEVICE_FUNC + static long (min)() { return LONG_MIN; } +}; +template<> struct numeric_limits +{ + EIGEN_DEVICE_FUNC + static unsigned long epsilon() { return 0; } + EIGEN_DEVICE_FUNC + static unsigned long (max)() { return ULONG_MAX; } + EIGEN_DEVICE_FUNC + static unsigned long (min)() { return 0; } +}; +template<> struct numeric_limits +{ + EIGEN_DEVICE_FUNC + static long long epsilon() { return 0; } + EIGEN_DEVICE_FUNC + static long long (max)() { return LLONG_MAX; } + EIGEN_DEVICE_FUNC + static long long (min)() { return LLONG_MIN; } +}; +template<> struct numeric_limits +{ + EIGEN_DEVICE_FUNC + static unsigned long long epsilon() { return 0; } + EIGEN_DEVICE_FUNC + static unsigned long long (max)() { return ULLONG_MAX; } + EIGEN_DEVICE_FUNC + static unsigned long long (min)() { return 0; } +}; + +} + +#endif /** \internal * A base class do disable default copy ctor and copy assignement operator. */ class noncopyable { - noncopyable(const noncopyable&); - const noncopyable& operator=(const noncopyable&); + EIGEN_DEVICE_FUNC noncopyable(const noncopyable&); + EIGEN_DEVICE_FUNC const noncopyable& operator=(const noncopyable&); protected: - noncopyable() {} - ~noncopyable() {} + EIGEN_DEVICE_FUNC noncopyable() {} + EIGEN_DEVICE_FUNC ~noncopyable() {} }; - /** \internal * Convenient struct to get the result type of a unary or binary functor. * @@ -110,14 +285,20 @@ class noncopyable * upcoming next STL generation (using a templated result member). * If none of these members is provided, then the type of the first argument is returned. FIXME, that behavior is a pretty bad hack. */ -template struct result_of {}; +#if EIGEN_HAS_STD_RESULT_OF +template struct result_of { + typedef typename std::result_of::type type1; + typedef typename remove_all::type type; +}; +#else +template struct result_of { }; struct has_none {int a[1];}; struct has_std_result_type {int a[2];}; struct has_tr1_result {int a[3];}; template -struct unary_result_of_select {typedef ArgType type;}; +struct unary_result_of_select {typedef typename internal::remove_all::type type;}; template struct unary_result_of_select {typedef typename Func::result_type type;}; @@ -128,10 +309,10 @@ struct unary_result_of_select {typedef ty template struct result_of { template - static has_std_result_type testFunctor(T const *, typename T::result_type const * = 0); + static has_std_result_type testFunctor(T const *, typename T::result_type const * = 0); template - static has_tr1_result testFunctor(T const *, typename T::template result::type const * = 0); - static has_none testFunctor(...); + static has_tr1_result testFunctor(T const *, typename T::template result::type const * = 0); + static has_none testFunctor(...); // note that the following indirection is needed for gcc-3.3 enum {FunctorType = sizeof(testFunctor(static_cast(0)))}; @@ -139,7 +320,7 @@ struct result_of { }; template -struct binary_result_of_select {typedef ArgType0 type;}; +struct binary_result_of_select {typedef typename internal::remove_all::type type;}; template struct binary_result_of_select @@ -152,16 +333,83 @@ struct binary_result_of_select template struct result_of { template - static has_std_result_type testFunctor(T const *, typename T::result_type const * = 0); + static has_std_result_type testFunctor(T const *, typename T::result_type const * = 0); template - static has_tr1_result testFunctor(T const *, typename T::template result::type const * = 0); - static has_none testFunctor(...); + static has_tr1_result testFunctor(T const *, typename T::template result::type const * = 0); + static has_none testFunctor(...); // note that the following indirection is needed for gcc-3.3 enum {FunctorType = sizeof(testFunctor(static_cast(0)))}; typedef typename binary_result_of_select::type type; }; +template +struct ternary_result_of_select {typedef typename internal::remove_all::type type;}; + +template +struct ternary_result_of_select +{typedef typename Func::result_type type;}; + +template +struct ternary_result_of_select +{typedef typename Func::template result::type type;}; + +template +struct result_of { + template + static has_std_result_type testFunctor(T const *, typename T::result_type const * = 0); + template + static has_tr1_result testFunctor(T const *, typename T::template result::type const * = 0); + static has_none testFunctor(...); + + // note that the following indirection is needed for gcc-3.3 + enum {FunctorType = sizeof(testFunctor(static_cast(0)))}; + typedef typename ternary_result_of_select::type type; +}; +#endif + +struct meta_yes { char a[1]; }; +struct meta_no { char a[2]; }; + +// Check whether T::ReturnType does exist +template +struct has_ReturnType +{ + template static meta_yes testFunctor(typename C::ReturnType const *); + template static meta_no testFunctor(...); + + enum { value = sizeof(testFunctor(0)) == sizeof(meta_yes) }; +}; + +template const T* return_ptr(); + +template +struct has_nullary_operator +{ + template static meta_yes testFunctor(C const *,typename enable_if<(sizeof(return_ptr()->operator()())>0)>::type * = 0); + static meta_no testFunctor(...); + + enum { value = sizeof(testFunctor(static_cast(0))) == sizeof(meta_yes) }; +}; + +template +struct has_unary_operator +{ + template static meta_yes testFunctor(C const *,typename enable_if<(sizeof(return_ptr()->operator()(IndexType(0)))>0)>::type * = 0); + static meta_no testFunctor(...); + + enum { value = sizeof(testFunctor(static_cast(0))) == sizeof(meta_yes) }; +}; + +template +struct has_binary_operator +{ + template static meta_yes testFunctor(C const *,typename enable_if<(sizeof(return_ptr()->operator()(IndexType(0),IndexType(0)))>0)>::type * = 0); + static meta_no testFunctor(...); + + enum { value = sizeof(testFunctor(static_cast(0))) == sizeof(meta_yes) }; +}; + /** \internal In short, it computes int(sqrt(\a Y)) with \a Y an integer. * Usage example: \code meta_sqrt<1023>::ret \endcode */ @@ -185,37 +433,26 @@ class meta_sqrt template class meta_sqrt { public: enum { ret = (SupX*SupX <= Y) ? SupX : InfX }; }; -/** \internal determines whether the product of two numeric types is allowed and what the return type is */ -template struct scalar_product_traits -{ - enum { Defined = 0 }; -}; -template struct scalar_product_traits +/** \internal Computes the least common multiple of two positive integer A and B + * at compile-time. It implements a naive algorithm testing all multiples of A. + * It thus works better if A>=B. + */ +template +struct meta_least_common_multiple { - enum { - // Cost = NumTraits::MulCost, - Defined = 1 - }; - typedef T ReturnType; + enum { ret = meta_least_common_multiple::ret }; }; - -template struct scalar_product_traits > +template +struct meta_least_common_multiple { - enum { - // Cost = 2*NumTraits::MulCost, - Defined = 1 - }; - typedef std::complex ReturnType; + enum { ret = A*K }; }; -template struct scalar_product_traits, T> +/** \internal determines whether the product of two numeric types is allowed and what the return type is */ +template struct scalar_product_traits { - enum { - // Cost = 2*NumTraits::MulCost, - Defined = 1 - }; - typedef std::complex ReturnType; + enum { Defined = 0 }; }; // FIXME quick workaround around current limitation of result_of @@ -224,19 +461,31 @@ template struct scalar_product_traits, T> // typedef typename scalar_product_traits::type, typename remove_all::type>::ReturnType type; // }; -template struct is_diagonal -{ enum { ret = false }; }; - -template struct is_diagonal > -{ enum { ret = true }; }; - -template struct is_diagonal > -{ enum { ret = true }; }; +} // end namespace internal -template struct is_diagonal > -{ enum { ret = true }; }; +namespace numext { + +#if defined(__CUDA_ARCH__) +template EIGEN_DEVICE_FUNC void swap(T &a, T &b) { T tmp = b; b = a; a = tmp; } +#else +template EIGEN_STRONG_INLINE void swap(T &a, T &b) { std::swap(a,b); } +#endif + +#if defined(__CUDA_ARCH__) +using internal::device::numeric_limits; +#else +using std::numeric_limits; +#endif + +// Integer division with rounding up. +// T is assumed to be an integer type with a>=0, and b>0 +template +T div_ceil(const T &a, const T &b) +{ + return (a+b-1) / b; +} -} // end namespace internal +} // end namespace numext } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/Core/util/ReenableStupidWarnings.h b/libs/eigen3/Eigen/src/Core/util/ReenableStupidWarnings.h index 5ddfbd4aa..86b60f52f 100644 --- a/libs/eigen3/Eigen/src/Core/util/ReenableStupidWarnings.h +++ b/libs/eigen3/Eigen/src/Core/util/ReenableStupidWarnings.h @@ -8,7 +8,20 @@ #pragma warning pop #elif defined __clang__ #pragma clang diagnostic pop + #elif defined __GNUC__ && __GNUC__>=6 + #pragma GCC diagnostic pop #endif + + #if defined __NVCC__ +// Don't reenable the diagnostic messages, as it turns out these messages need +// to be disabled at the point of the template instantiation (i.e the user code) +// otherwise they'll be triggered by nvcc. +// #pragma diag_default code_is_unreachable +// #pragma diag_default initialization_not_reachable +// #pragma diag_default 2651 +// #pragma diag_default 2653 + #endif + #endif #endif // EIGEN_WARNINGS_DISABLED diff --git a/libs/eigen3/Eigen/src/Core/util/StaticAssert.h b/libs/eigen3/Eigen/src/Core/util/StaticAssert.h index 8872c5b64..983361a45 100644 --- a/libs/eigen3/Eigen/src/Core/util/StaticAssert.h +++ b/libs/eigen3/Eigen/src/Core/util/StaticAssert.h @@ -26,7 +26,7 @@ #ifndef EIGEN_NO_STATIC_ASSERT - #if defined(__GXX_EXPERIMENTAL_CXX0X__) || (defined(_MSC_VER) && (_MSC_VER >= 1600)) + #if EIGEN_MAX_CPP_VER>=11 && (__has_feature(cxx_static_assert) || (defined(__cplusplus) && __cplusplus >= 201103L) || (EIGEN_COMP_MSVC >= 1600)) // if native static_assert is enabled, let's use it #define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG); @@ -50,6 +50,7 @@ THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE, THIS_METHOD_IS_ONLY_FOR_MATRICES_OF_A_SPECIFIC_SIZE, THIS_METHOD_IS_ONLY_FOR_OBJECTS_OF_A_SPECIFIC_SIZE, + OUT_OF_RANGE_ACCESS, YOU_MADE_A_PROGRAMMING_MISTAKE, EIGEN_INTERNAL_ERROR_PLEASE_FILE_A_BUG_REPORT, EIGEN_INTERNAL_COMPILATION_ERROR_OR_YOU_MADE_A_PROGRAMMING_MISTAKE, @@ -84,13 +85,23 @@ THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY, YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT, THIS_METHOD_IS_ONLY_FOR_1x1_EXPRESSIONS, + THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS, THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL, THIS_METHOD_IS_ONLY_FOR_ARRAYS_NOT_MATRICES, YOU_PASSED_A_ROW_VECTOR_BUT_A_COLUMN_VECTOR_WAS_EXPECTED, YOU_PASSED_A_COLUMN_VECTOR_BUT_A_ROW_VECTOR_WAS_EXPECTED, THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE, THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH, - OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG + OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG, + IMPLICIT_CONVERSION_TO_SCALAR_IS_FOR_INNER_PRODUCT_ONLY, + STORAGE_LAYOUT_DOES_NOT_MATCH, + EIGEN_INTERNAL_ERROR_PLEASE_FILE_A_BUG_REPORT__INVALID_COST_VALUE, + THIS_COEFFICIENT_ACCESSOR_TAKING_ONE_ACCESS_IS_ONLY_FOR_EXPRESSIONS_ALLOWING_LINEAR_ACCESS, + MATRIX_FREE_CONJUGATE_GRADIENT_IS_COMPATIBLE_WITH_UPPER_UNION_LOWER_MODE_ONLY, + THIS_TYPE_IS_NOT_SUPPORTED, + STORAGE_KIND_MUST_MATCH, + STORAGE_INDEX_MUST_MATCH, + CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY }; }; @@ -101,15 +112,15 @@ // Specialized implementation for MSVC to avoid "conditional // expression is constant" warnings. This implementation doesn't // appear to work under GCC, hence the multiple implementations. - #ifdef _MSC_VER + #if EIGEN_COMP_MSVC #define EIGEN_STATIC_ASSERT(CONDITION,MSG) \ {Eigen::internal::static_assertion::MSG;} #else - + // In some cases clang interprets bool(CONDITION) as function declaration #define EIGEN_STATIC_ASSERT(CONDITION,MSG) \ - if (Eigen::internal::static_assertion::MSG) {} + if (Eigen::internal::static_assertion(CONDITION)>::MSG) {} #endif @@ -157,7 +168,7 @@ #define EIGEN_PREDICATE_SAME_MATRIX_SIZE(TYPE0,TYPE1) \ ( \ - (int(TYPE0::SizeAtCompileTime)==0 && int(TYPE1::SizeAtCompileTime)==0) \ + (int(Eigen::internal::size_of_xpr_at_compile_time::ret)==0 && int(Eigen::internal::size_of_xpr_at_compile_time::ret)==0) \ || (\ (int(TYPE0::RowsAtCompileTime)==Eigen::Dynamic \ || int(TYPE1::RowsAtCompileTime)==Eigen::Dynamic \ @@ -168,13 +179,8 @@ ) \ ) -#ifdef EIGEN2_SUPPORT - #define EIGEN_STATIC_ASSERT_NON_INTEGER(TYPE) \ - eigen_assert(!NumTraits::IsInteger); -#else - #define EIGEN_STATIC_ASSERT_NON_INTEGER(TYPE) \ +#define EIGEN_STATIC_ASSERT_NON_INTEGER(TYPE) \ EIGEN_STATIC_ASSERT(!NumTraits::IsInteger, THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES) -#endif // static assertion failing if it is guaranteed at compile-time that the two matrix expression types have different sizes @@ -189,18 +195,22 @@ THIS_METHOD_IS_ONLY_FOR_1x1_EXPRESSIONS) #define EIGEN_STATIC_ASSERT_LVALUE(Derived) \ - EIGEN_STATIC_ASSERT(internal::is_lvalue::value, \ + EIGEN_STATIC_ASSERT(Eigen::internal::is_lvalue::value, \ THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY) #define EIGEN_STATIC_ASSERT_ARRAYXPR(Derived) \ - EIGEN_STATIC_ASSERT((internal::is_same::XprKind, ArrayXpr>::value), \ + EIGEN_STATIC_ASSERT((Eigen::internal::is_same::XprKind, ArrayXpr>::value), \ THIS_METHOD_IS_ONLY_FOR_ARRAYS_NOT_MATRICES) #define EIGEN_STATIC_ASSERT_SAME_XPR_KIND(Derived1, Derived2) \ - EIGEN_STATIC_ASSERT((internal::is_same::XprKind, \ - typename internal::traits::XprKind \ + EIGEN_STATIC_ASSERT((Eigen::internal::is_same::XprKind, \ + typename Eigen::internal::traits::XprKind \ >::value), \ YOU_CANNOT_MIX_ARRAYS_AND_MATRICES) +// Check that a cost value is positive, and that is stay within a reasonable range +// TODO this check could be enabled for internal debugging only +#define EIGEN_INTERNAL_CHECK_COST_VALUE(C) \ + EIGEN_STATIC_ASSERT((C)>=0 && (C)<=HugeCost*HugeCost, EIGEN_INTERNAL_ERROR_PLEASE_FILE_A_BUG_REPORT__INVALID_COST_VALUE); #endif // EIGEN_STATIC_ASSERT_H diff --git a/libs/eigen3/Eigen/src/Core/util/XprHelper.h b/libs/eigen3/Eigen/src/Core/util/XprHelper.h index 3c4773054..ba5bd186d 100644 --- a/libs/eigen3/Eigen/src/Core/util/XprHelper.h +++ b/libs/eigen3/Eigen/src/Core/util/XprHelper.h @@ -14,20 +14,77 @@ // just a workaround because GCC seems to not really like empty structs // FIXME: gcc 4.3 generates bad code when strict-aliasing is enabled // so currently we simply disable this optimization for gcc 4.3 -#if (defined __GNUG__) && !((__GNUC__==4) && (__GNUC_MINOR__==3)) +#if EIGEN_COMP_GNUC && !EIGEN_GNUC_AT(4,3) #define EIGEN_EMPTY_STRUCT_CTOR(X) \ - EIGEN_STRONG_INLINE X() {} \ - EIGEN_STRONG_INLINE X(const X& ) {} + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE X() {} \ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE X(const X& ) {} #else #define EIGEN_EMPTY_STRUCT_CTOR(X) #endif namespace Eigen { -typedef EIGEN_DEFAULT_DENSE_INDEX_TYPE DenseIndex; - namespace internal { +template +EIGEN_DEVICE_FUNC +inline IndexDest convert_index(const IndexSrc& idx) { + // for sizeof(IndexDest)>=sizeof(IndexSrc) compilers should be able to optimize this away: + eigen_internal_assert(idx <= NumTraits::highest() && "Index value to big for target type"); + return IndexDest(idx); +} + + +// promote_scalar_arg is an helper used in operation between an expression and a scalar, like: +// expression * scalar +// Its role is to determine how the type T of the scalar operand should be promoted given the scalar type ExprScalar of the given expression. +// The IsSupported template parameter must be provided by the caller as: internal::has_ReturnType >::value using the proper order for ExprScalar and T. +// Then the logic is as follows: +// - if the operation is natively supported as defined by IsSupported, then the scalar type is not promoted, and T is returned. +// - otherwise, NumTraits::Literal is returned if T is implicitly convertible to NumTraits::Literal AND that this does not imply a float to integer conversion. +// - otherwise, ExprScalar is returned if T is implicitly convertible to ExprScalar AND that this does not imply a float to integer conversion. +// - In all other cases, the promoted type is not defined, and the respective operation is thus invalid and not available (SFINAE). +template +struct promote_scalar_arg; + +template +struct promote_scalar_arg +{ + typedef T type; +}; + +// Recursively check safe conversion to PromotedType, and then ExprScalar if they are different. +template::value, + bool IsSafe = NumTraits::IsInteger || !NumTraits::IsInteger> +struct promote_scalar_arg_unsupported; + +// Start recursion with NumTraits::Literal +template +struct promote_scalar_arg : promote_scalar_arg_unsupported::Literal> {}; + +// We found a match! +template +struct promote_scalar_arg_unsupported +{ + typedef PromotedType type; +}; + +// No match, but no real-to-integer issues, and ExprScalar and current PromotedType are different, +// so let's try to promote to ExprScalar +template +struct promote_scalar_arg_unsupported + : promote_scalar_arg_unsupported +{}; + +// Unsafe real-to-integer, let's stop. +template +struct promote_scalar_arg_unsupported {}; + +// T is not even convertible to ExprScalar, let's stop. +template +struct promote_scalar_arg_unsupported {}; + //classes inheriting no_assignment_operator don't generate a default operator=. class no_assignment_operator { @@ -50,19 +107,19 @@ template class variable_if_dynamic { public: EIGEN_EMPTY_STRUCT_CTOR(variable_if_dynamic) - explicit variable_if_dynamic(T v) { EIGEN_ONLY_USED_FOR_DEBUG(v); assert(v == T(Value)); } - static T value() { return T(Value); } - void setValue(T) {} + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit variable_if_dynamic(T v) { EIGEN_ONLY_USED_FOR_DEBUG(v); eigen_assert(v == T(Value)); } + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T value() { return T(Value); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void setValue(T) {} }; template class variable_if_dynamic { T m_value; - variable_if_dynamic() { assert(false); } + EIGEN_DEVICE_FUNC variable_if_dynamic() { eigen_assert(false); } public: - explicit variable_if_dynamic(T value) : m_value(value) {} - T value() const { return m_value; } - void setValue(T value) { m_value = value; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit variable_if_dynamic(T value) : m_value(value) {} + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T value() const { return m_value; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void setValue(T value) { m_value = value; } }; /** \internal like variable_if_dynamic but for DynamicIndex @@ -71,19 +128,19 @@ template class variable_if_dynamicindex { public: EIGEN_EMPTY_STRUCT_CTOR(variable_if_dynamicindex) - explicit variable_if_dynamicindex(T v) { EIGEN_ONLY_USED_FOR_DEBUG(v); assert(v == T(Value)); } - static T value() { return T(Value); } - void setValue(T) {} + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit variable_if_dynamicindex(T v) { EIGEN_ONLY_USED_FOR_DEBUG(v); eigen_assert(v == T(Value)); } + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T value() { return T(Value); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void setValue(T) {} }; template class variable_if_dynamicindex { T m_value; - variable_if_dynamicindex() { assert(false); } + EIGEN_DEVICE_FUNC variable_if_dynamicindex() { eigen_assert(false); } public: - explicit variable_if_dynamicindex(T value) : m_value(value) {} - T value() const { return m_value; } - void setValue(T value) { m_value = value; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit variable_if_dynamicindex(T value) : m_value(value) {} + EIGEN_DEVICE_FUNC T EIGEN_STRONG_INLINE value() const { return m_value; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void setValue(T value) { m_value = value; } }; template struct functor_traits @@ -101,7 +158,73 @@ template struct packet_traits; template struct unpacket_traits { typedef T type; - enum {size=1}; + typedef T half; + enum + { + size = 1, + alignment = 1 + }; +}; + +template::size)==0 || is_same::half>::value> +struct find_best_packet_helper; + +template< int Size, typename PacketType> +struct find_best_packet_helper +{ + typedef PacketType type; +}; + +template +struct find_best_packet_helper +{ + typedef typename find_best_packet_helper::half>::type type; +}; + +template +struct find_best_packet +{ + typedef typename find_best_packet_helper::type>::type type; +}; + +#if EIGEN_MAX_STATIC_ALIGN_BYTES>0 +template +struct compute_default_alignment_helper +{ + enum { value = 0 }; +}; + +template +struct compute_default_alignment_helper // Match +{ + enum { value = AlignmentBytes }; +}; + +template +struct compute_default_alignment_helper // Try-half +{ + // current packet too large, try with an half-packet + enum { value = compute_default_alignment_helper::value }; +}; +#else +// If static alignment is disabled, no need to bother. +// This also avoids a division by zero in "bool Match = bool((ArrayBytes%AlignmentBytes)==0)" +template +struct compute_default_alignment_helper +{ + enum { value = 0 }; +}; +#endif + +template struct compute_default_alignment { + enum { value = compute_default_alignment_helper::value }; +}; + +template struct compute_default_alignment { + enum { value = EIGEN_MAX_ALIGN_BYTES }; }; template class compute_matrix_flags { - enum { - row_major_bit = Options&RowMajor ? RowMajorBit : 0, - is_dynamic_size_storage = MaxRows==Dynamic || MaxCols==Dynamic, - - aligned_bit = - ( - ((Options&DontAlign)==0) - && ( -#if EIGEN_ALIGN_STATICALLY - ((!is_dynamic_size_storage) && (((MaxCols*MaxRows*int(sizeof(Scalar))) % 16) == 0)) -#else - 0 -#endif - - || - -#if EIGEN_ALIGN - is_dynamic_size_storage -#else - 0 -#endif - - ) - ) ? AlignedBit : 0, - packet_access_bit = packet_traits::Vectorizable && aligned_bit ? PacketAccessBit : 0 - }; - + enum { row_major_bit = Options&RowMajor ? RowMajorBit : 0 }; public: - enum { ret = LinearAccessBit | LvalueBit | DirectAccessBit | NestByRefBit | packet_access_bit | row_major_bit | aligned_bit }; + // FIXME currently we still have to handle DirectAccessBit at the expression level to handle DenseCoeffsBase<> + // and then propagate this information to the evaluator's flags. + // However, I (Gael) think that DirectAccessBit should only matter at the evaluation stage. + enum { ret = DirectAccessBit | LvalueBit | NestByRefBit | row_major_bit }; }; template struct size_at_compile_time @@ -163,34 +263,43 @@ template struct size_at_compile_time enum { ret = (_Rows==Dynamic || _Cols==Dynamic) ? Dynamic : _Rows * _Cols }; }; +template struct size_of_xpr_at_compile_time +{ + enum { ret = size_at_compile_time::RowsAtCompileTime,traits::ColsAtCompileTime>::ret }; +}; + /* plain_matrix_type : the difference from eval is that plain_matrix_type is always a plain matrix type, * whereas eval is a const reference in the case of a matrix */ template::StorageKind> struct plain_matrix_type; -template struct plain_matrix_type_dense; +template struct plain_matrix_type_dense; template struct plain_matrix_type { - typedef typename plain_matrix_type_dense::XprKind>::type type; + typedef typename plain_matrix_type_dense::XprKind, traits::Flags>::type type; +}; +template struct plain_matrix_type +{ + typedef typename T::PlainObject type; }; -template struct plain_matrix_type_dense +template struct plain_matrix_type_dense { typedef Matrix::Scalar, traits::RowsAtCompileTime, traits::ColsAtCompileTime, - AutoAlign | (traits::Flags&RowMajorBit ? RowMajor : ColMajor), + AutoAlign | (Flags&RowMajorBit ? RowMajor : ColMajor), traits::MaxRowsAtCompileTime, traits::MaxColsAtCompileTime > type; }; -template struct plain_matrix_type_dense +template struct plain_matrix_type_dense { typedef Array::Scalar, traits::RowsAtCompileTime, traits::ColsAtCompileTime, - AutoAlign | (traits::Flags&RowMajorBit ? RowMajor : ColMajor), + AutoAlign | (Flags&RowMajorBit ? RowMajor : ColMajor), traits::MaxRowsAtCompileTime, traits::MaxColsAtCompileTime > type; @@ -215,6 +324,11 @@ template struct eval // > type; }; +template struct eval +{ + typedef typename plain_matrix_type::type type; +}; + // for matrices, no need to evaluate, just use a const reference to avoid a useless copy template struct eval, Dense> @@ -229,6 +343,15 @@ struct eval, Dense> }; +/* similar to plain_matrix_type, but using the evaluator's Flags */ +template::StorageKind> struct plain_object_eval; + +template +struct plain_object_eval +{ + typedef typename plain_matrix_type_dense::XprKind, evaluator::Flags>::type type; +}; + /* plain_matrix_type_column_major : same as plain_matrix_type but guaranteed to be column-major */ @@ -266,9 +389,6 @@ template struct plain_matrix_type_row_major > type; }; -// we should be able to get rid of this one too -template struct must_nest_by_value { enum { ret = false }; }; - /** \internal The reference selector for template expressions. The idea is that we don't * need to use references for expressions since they are light weight proxy * objects which should generate no copying overhead. */ @@ -280,6 +400,12 @@ struct ref_selector T const&, const T >::type type; + + typedef typename conditional< + bool(traits::Flags & NestByRefBit), + T &, + T + >::type non_const_type; }; /** \internal Adds the const qualifier on the value-type of T2 if and only if T1 is a const type */ @@ -293,55 +419,42 @@ struct transfer_constness >::type type; }; -/** \internal Determines how a given expression should be nested into another one. + +// However, we still need a mechanism to detect whether an expression which is evaluated multiple time +// has to be evaluated into a temporary. +// That's the purpose of this new nested_eval helper: +/** \internal Determines how a given expression should be nested when evaluated multiple times. * For example, when you do a * (b+c), Eigen will determine how the expression b+c should be - * nested into the bigger product expression. The choice is between nesting the expression b+c as-is, or + * evaluated into the bigger product expression. The choice is between nesting the expression b+c as-is, or * evaluating that expression b+c into a temporary variable d, and nest d so that the resulting expression is * a*d. Evaluating can be beneficial for example if every coefficient access in the resulting expression causes * many coefficient accesses in the nested expressions -- as is the case with matrix product for example. * - * \param T the type of the expression being nested - * \param n the number of coefficient accesses in the nested expression for each coefficient access in the bigger expression. - * - * Note that if no evaluation occur, then the constness of T is preserved. - * - * Example. Suppose that a, b, and c are of type Matrix3d. The user forms the expression a*(b+c). - * b+c is an expression "sum of matrices", which we will denote by S. In order to determine how to nest it, - * the Product expression uses: nested::ret, which turns out to be Matrix3d because the internal logic of - * nested determined that in this case it was better to evaluate the expression b+c into a temporary. On the other hand, - * since a is of type Matrix3d, the Product expression nests it as nested::ret, which turns out to be - * const Matrix3d&, because the internal logic of nested determined that since a was already a matrix, there was no point - * in copying it into another matrix. + * \tparam T the type of the expression being nested. + * \tparam n the number of coefficient accesses in the nested expression for each coefficient access in the bigger expression. + * \tparam PlainObject the type of the temporary if needed. */ -template::type> struct nested +template::type> struct nested_eval { enum { - // for the purpose of this test, to keep it reasonably simple, we arbitrarily choose a value of Dynamic values. - // the choice of 10000 makes it larger than any practical fixed value and even most dynamic values. - // in extreme cases where these assumptions would be wrong, we would still at worst suffer performance issues - // (poor choice of temporaries). - // it's important that this value can still be squared without integer overflowing. - DynamicAsInteger = 10000, ScalarReadCost = NumTraits::Scalar>::ReadCost, - ScalarReadCostAsInteger = ScalarReadCost == Dynamic ? int(DynamicAsInteger) : int(ScalarReadCost), - CoeffReadCost = traits::CoeffReadCost, - CoeffReadCostAsInteger = CoeffReadCost == Dynamic ? int(DynamicAsInteger) : int(CoeffReadCost), - NAsInteger = n == Dynamic ? int(DynamicAsInteger) : n, - CostEvalAsInteger = (NAsInteger+1) * ScalarReadCostAsInteger + CoeffReadCostAsInteger, - CostNoEvalAsInteger = NAsInteger * CoeffReadCostAsInteger + CoeffReadCost = evaluator::CoeffReadCost, // NOTE What if an evaluator evaluate itself into a tempory? + // Then CoeffReadCost will be small (e.g., 1) but we still have to evaluate, especially if n>1. + // This situation is already taken care by the EvalBeforeNestingBit flag, which is turned ON + // for all evaluator creating a temporary. This flag is then propagated by the parent evaluators. + // Another solution could be to count the number of temps? + NAsInteger = n == Dynamic ? HugeCost : n, + CostEval = (NAsInteger+1) * ScalarReadCost + CoeffReadCost, + CostNoEval = NAsInteger * CoeffReadCost, + Evaluate = (int(evaluator::Flags) & EvalBeforeNestingBit) || (int(CostEval) < int(CostNoEval)) }; - typedef typename conditional< - ( (int(traits::Flags) & EvalBeforeNestingBit) || - int(CostEvalAsInteger) < int(CostNoEvalAsInteger) - ), - PlainObject, - typename ref_selector::type - >::type type; + typedef typename conditional::type>::type type; }; template -T* const_cast_ptr(const T* ptr) +EIGEN_DEVICE_FUNC +inline T* const_cast_ptr(const T* ptr) { return const_cast(ptr); } @@ -364,30 +477,13 @@ struct dense_xpr_base typedef ArrayBase type; }; -/** \internal Helper base class to add a scalar multiple operator - * overloads for complex types */ -template::value > -struct special_scalar_op_base : public DenseCoeffsBase -{ - // dummy operator* so that the - // "using special_scalar_op_base::operator*" compiles - void operator*() const; -}; +template::XprKind, typename StorageKind = typename traits::StorageKind> +struct generic_xpr_base; -template -struct special_scalar_op_base : public DenseCoeffsBase +template +struct generic_xpr_base { - const CwiseUnaryOp, Derived> - operator*(const OtherScalar& scalar) const - { - return CwiseUnaryOp, Derived> - (*static_cast(this), scalar_multiple2_op(scalar)); - } - - inline friend const CwiseUnaryOp, Derived> - operator*(const OtherScalar& scalar, const Derived& matrix) - { return static_cast(matrix).operator*(scalar); } + typedef typename dense_xpr_base::type type; }; template struct cast_return_type @@ -405,9 +501,79 @@ template struct promote_storage_type { typedef A ret; }; +template struct promote_storage_type +{ + typedef A ret; +}; +template struct promote_storage_type +{ + typedef A ret; +}; + +/** \internal Specify the "storage kind" of applying a coefficient-wise + * binary operations between two expressions of kinds A and B respectively. + * The template parameter Functor permits to specialize the resulting storage kind wrt to + * the functor. + * The default rules are as follows: + * \code + * A op A -> A + * A op dense -> dense + * dense op B -> dense + * sparse op dense -> sparse + * dense op sparse -> sparse + * \endcode + */ +template struct cwise_promote_storage_type; + +template struct cwise_promote_storage_type { typedef A ret; }; +template struct cwise_promote_storage_type { typedef Dense ret; }; +template struct cwise_promote_storage_type { typedef Dense ret; }; +template struct cwise_promote_storage_type { typedef Dense ret; }; +template struct cwise_promote_storage_type { typedef Sparse ret; }; +template struct cwise_promote_storage_type { typedef Sparse ret; }; + +template struct cwise_promote_storage_order { + enum { value = LhsOrder }; +}; + +template struct cwise_promote_storage_order { enum { value = RhsOrder }; }; +template struct cwise_promote_storage_order { enum { value = LhsOrder }; }; +template struct cwise_promote_storage_order { enum { value = Order }; }; + + +/** \internal Specify the "storage kind" of multiplying an expression of kind A with kind B. + * The template parameter ProductTag permits to specialize the resulting storage kind wrt to + * some compile-time properties of the product: GemmProduct, GemvProduct, OuterProduct, InnerProduct. + * The default rules are as follows: + * \code + * K * K -> K + * dense * K -> dense + * K * dense -> dense + * diag * K -> K + * K * diag -> K + * Perm * K -> K + * K * Perm -> K + * \endcode + */ +template struct product_promote_storage_type; + +template struct product_promote_storage_type { typedef A ret;}; +template struct product_promote_storage_type { typedef Dense ret;}; +template struct product_promote_storage_type { typedef Dense ret; }; +template struct product_promote_storage_type { typedef Dense ret; }; + +template struct product_promote_storage_type { typedef A ret; }; +template struct product_promote_storage_type { typedef B ret; }; +template struct product_promote_storage_type { typedef Dense ret; }; +template struct product_promote_storage_type { typedef Dense ret; }; + +template struct product_promote_storage_type { typedef A ret; }; +template struct product_promote_storage_type { typedef B ret; }; +template struct product_promote_storage_type { typedef Dense ret; }; +template struct product_promote_storage_type { typedef Dense ret; }; /** \internal gives the plain matrix or array type to store a row/column/diagonal of a matrix type. - * \param Scalar optional parameter allowing to pass a different scalar type than the one of the MatrixType. + * \tparam Scalar optional parameter allowing to pass a different scalar type than the one of the MatrixType. */ template struct plain_row_type @@ -455,15 +621,201 @@ struct plain_diag_type >::type type; }; +template +struct plain_constant_type +{ + enum { Options = (traits::Flags&RowMajorBit)?RowMajor:0 }; + + typedef Array::RowsAtCompileTime, traits::ColsAtCompileTime, + Options, traits::MaxRowsAtCompileTime,traits::MaxColsAtCompileTime> array_type; + + typedef Matrix::RowsAtCompileTime, traits::ColsAtCompileTime, + Options, traits::MaxRowsAtCompileTime,traits::MaxColsAtCompileTime> matrix_type; + + typedef CwiseNullaryOp, const typename conditional::XprKind, MatrixXpr >::value, matrix_type, array_type>::type > type; +}; + template struct is_lvalue { - enum { value = !bool(is_const::value) && + enum { value = (!bool(is_const::value)) && bool(traits::Flags & LvalueBit) }; }; +template struct is_diagonal +{ enum { ret = false }; }; + +template struct is_diagonal > +{ enum { ret = true }; }; + +template struct is_diagonal > +{ enum { ret = true }; }; + +template struct is_diagonal > +{ enum { ret = true }; }; + +template struct glue_shapes; +template<> struct glue_shapes { typedef TriangularShape type; }; + +template +bool is_same_dense(const T1 &mat1, const T2 &mat2, typename enable_if::ret&&has_direct_access::ret, T1>::type * = 0) +{ + return (mat1.data()==mat2.data()) && (mat1.innerStride()==mat2.innerStride()) && (mat1.outerStride()==mat2.outerStride()); +} + +template +bool is_same_dense(const T1 &, const T2 &, typename enable_if::ret&&has_direct_access::ret), T1>::type * = 0) +{ + return false; +} + +// Internal helper defining the cost of a scalar division for the type T. +// The default heuristic can be specialized for each scalar type and architecture. +template +struct scalar_div_cost { + enum { value = 8*NumTraits::MulCost }; +}; + +template +struct scalar_div_cost, Vectorized> { + enum { value = 2*scalar_div_cost::value + + 6*NumTraits::MulCost + + 3*NumTraits::AddCost + }; +}; + + +template +struct scalar_div_cost::type> { enum { value = 24 }; }; +template +struct scalar_div_cost::type> { enum { value = 21 }; }; + + +#ifdef EIGEN_DEBUG_ASSIGN +std::string demangle_traversal(int t) +{ + if(t==DefaultTraversal) return "DefaultTraversal"; + if(t==LinearTraversal) return "LinearTraversal"; + if(t==InnerVectorizedTraversal) return "InnerVectorizedTraversal"; + if(t==LinearVectorizedTraversal) return "LinearVectorizedTraversal"; + if(t==SliceVectorizedTraversal) return "SliceVectorizedTraversal"; + return "?"; +} +std::string demangle_unrolling(int t) +{ + if(t==NoUnrolling) return "NoUnrolling"; + if(t==InnerUnrolling) return "InnerUnrolling"; + if(t==CompleteUnrolling) return "CompleteUnrolling"; + return "?"; +} +std::string demangle_flags(int f) +{ + std::string res; + if(f&RowMajorBit) res += " | RowMajor"; + if(f&PacketAccessBit) res += " | Packet"; + if(f&LinearAccessBit) res += " | Linear"; + if(f&LvalueBit) res += " | Lvalue"; + if(f&DirectAccessBit) res += " | Direct"; + if(f&NestByRefBit) res += " | NestByRef"; + if(f&NoPreferredStorageOrderBit) res += " | NoPreferredStorageOrderBit"; + + return res; +} +#endif + } // end namespace internal + +/** \class ScalarBinaryOpTraits + * \ingroup Core_Module + * + * \brief Determines whether the given binary operation of two numeric types is allowed and what the scalar return type is. + * + * This class permits to control the scalar return type of any binary operation performed on two different scalar types through (partial) template specializations. + * + * For instance, let \c U1, \c U2 and \c U3 be three user defined scalar types for which most operations between instances of \c U1 and \c U2 returns an \c U3. + * You can let %Eigen knows that by defining: + \code + template + struct ScalarBinaryOpTraits { typedef U3 ReturnType; }; + template + struct ScalarBinaryOpTraits { typedef U3 ReturnType; }; + \endcode + * You can then explicitly disable some particular operations to get more explicit error messages: + \code + template<> + struct ScalarBinaryOpTraits > {}; + \endcode + * Or customize the return type for individual operation: + \code + template<> + struct ScalarBinaryOpTraits > { typedef U1 ReturnType; }; + \endcode + * + * By default, the following generic combinations are supported: + + + + + +
ScalarAScalarBBinaryOpReturnTypeNote
\c T \c T \c * \c T
\c NumTraits::Real \c T \c * \c T Only if \c NumTraits::IsComplex
\c T \c NumTraits::Real \c * \c T Only if \c NumTraits::IsComplex
+ * + * \sa CwiseBinaryOp + */ +template > +struct ScalarBinaryOpTraits +#ifndef EIGEN_PARSED_BY_DOXYGEN + // for backward compatibility, use the hints given by the (deprecated) internal::scalar_product_traits class. + : internal::scalar_product_traits +#endif // EIGEN_PARSED_BY_DOXYGEN +{}; + +template +struct ScalarBinaryOpTraits +{ + typedef T ReturnType; +}; + +template +struct ScalarBinaryOpTraits::IsComplex,T>::type>::Real, BinaryOp> +{ + typedef T ReturnType; +}; +template +struct ScalarBinaryOpTraits::IsComplex,T>::type>::Real, T, BinaryOp> +{ + typedef T ReturnType; +}; + +// For Matrix * Permutation +template +struct ScalarBinaryOpTraits +{ + typedef T ReturnType; +}; + +// For Permutation * Matrix +template +struct ScalarBinaryOpTraits +{ + typedef T ReturnType; +}; + +// for Permutation*Permutation +template +struct ScalarBinaryOpTraits +{ + typedef void ReturnType; +}; + +// We require Lhs and Rhs to have "compatible" scalar types. +// It is tempting to always allow mixing different types but remember that this is often impossible in the vectorized paths. +// So allowing mixing different types gives very unexpected errors when enabling vectorization, when the user tries to +// add together a float matrix and a double matrix. +#define EIGEN_CHECK_BINARY_COMPATIBILIY(BINOP,LHS,RHS) \ + EIGEN_STATIC_ASSERT((Eigen::internal::has_ReturnType >::value), \ + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + } // end namespace Eigen #endif // EIGEN_XPRHELPER_H diff --git a/libs/eigen3/Eigen/src/SparseCore/AmbiVector.h b/libs/eigen3/Eigen/src/SparseCore/AmbiVector.h index 17fff96a7..8a5cc91f2 100644 --- a/libs/eigen3/Eigen/src/SparseCore/AmbiVector.h +++ b/libs/eigen3/Eigen/src/SparseCore/AmbiVector.h @@ -19,15 +19,15 @@ namespace internal { * * See BasicSparseLLT and SparseProduct for usage examples. */ -template +template class AmbiVector { public: typedef _Scalar Scalar; - typedef _Index Index; + typedef _StorageIndex StorageIndex; typedef typename NumTraits::Real RealScalar; - AmbiVector(Index size) + explicit AmbiVector(Index size) : m_buffer(0), m_zero(0), m_size(0), m_allocatedSize(0), m_allocatedElements(0), m_mode(-1) { resize(size); @@ -39,7 +39,7 @@ class AmbiVector Index nonZeros() const; /** Specifies a sub-vector to work on */ - void setBounds(Index start, Index end) { m_start = start; m_end = end; } + void setBounds(Index start, Index end) { m_start = convert_index(start); m_end = convert_index(end); } void setZero(); @@ -55,12 +55,16 @@ class AmbiVector { if (m_allocatedSize < size) reallocate(size); - m_size = size; + m_size = convert_index(size); } - Index size() const { return m_size; } + StorageIndex size() const { return m_size; } protected: + StorageIndex convert_index(Index idx) + { + return internal::convert_index(idx); + } void reallocate(Index size) { @@ -69,16 +73,16 @@ class AmbiVector delete[] m_buffer; if (size<1000) { - Index allocSize = (size * sizeof(ListEl))/sizeof(Scalar); - m_allocatedElements = (allocSize*sizeof(Scalar))/sizeof(ListEl); + Index allocSize = (size * sizeof(ListEl) + sizeof(Scalar) - 1)/sizeof(Scalar); + m_allocatedElements = convert_index((allocSize*sizeof(Scalar))/sizeof(ListEl)); m_buffer = new Scalar[allocSize]; } else { - m_allocatedElements = (size*sizeof(Scalar))/sizeof(ListEl); + m_allocatedElements = convert_index((size*sizeof(Scalar))/sizeof(ListEl)); m_buffer = new Scalar[size]; } - m_size = size; + m_size = convert_index(size); m_start = 0; m_end = m_size; } @@ -86,9 +90,9 @@ class AmbiVector void reallocateSparse() { Index copyElements = m_allocatedElements; - m_allocatedElements = (std::min)(Index(m_allocatedElements*1.5),m_size); + m_allocatedElements = (std::min)(StorageIndex(m_allocatedElements*1.5),m_size); Index allocSize = m_allocatedElements * sizeof(ListEl); - allocSize = allocSize/sizeof(Scalar) + (allocSize%sizeof(Scalar)>0?1:0); + allocSize = (allocSize + sizeof(Scalar) - 1)/sizeof(Scalar); Scalar* newBuffer = new Scalar[allocSize]; memcpy(newBuffer, m_buffer, copyElements * sizeof(ListEl)); delete[] m_buffer; @@ -99,30 +103,30 @@ class AmbiVector // element type of the linked list struct ListEl { - Index next; - Index index; + StorageIndex next; + StorageIndex index; Scalar value; }; // used to store data in both mode Scalar* m_buffer; Scalar m_zero; - Index m_size; - Index m_start; - Index m_end; - Index m_allocatedSize; - Index m_allocatedElements; - Index m_mode; + StorageIndex m_size; + StorageIndex m_start; + StorageIndex m_end; + StorageIndex m_allocatedSize; + StorageIndex m_allocatedElements; + StorageIndex m_mode; // linked list mode - Index m_llStart; - Index m_llCurrent; - Index m_llSize; + StorageIndex m_llStart; + StorageIndex m_llCurrent; + StorageIndex m_llSize; }; /** \returns the number of non zeros in the current sub vector */ -template -_Index AmbiVector<_Scalar,_Index>::nonZeros() const +template +Index AmbiVector<_Scalar,_StorageIndex>::nonZeros() const { if (m_mode==IsSparse) return m_llSize; @@ -130,8 +134,8 @@ _Index AmbiVector<_Scalar,_Index>::nonZeros() const return m_end - m_start; } -template -void AmbiVector<_Scalar,_Index>::init(double estimatedDensity) +template +void AmbiVector<_Scalar,_StorageIndex>::init(double estimatedDensity) { if (estimatedDensity>0.1) init(IsDense); @@ -139,8 +143,8 @@ void AmbiVector<_Scalar,_Index>::init(double estimatedDensity) init(IsSparse); } -template -void AmbiVector<_Scalar,_Index>::init(int mode) +template +void AmbiVector<_Scalar,_StorageIndex>::init(int mode) { m_mode = mode; if (m_mode==IsSparse) @@ -155,15 +159,15 @@ void AmbiVector<_Scalar,_Index>::init(int mode) * * Don't worry, this function is extremely cheap. */ -template -void AmbiVector<_Scalar,_Index>::restart() +template +void AmbiVector<_Scalar,_StorageIndex>::restart() { m_llCurrent = m_llStart; } /** Set all coefficients of current subvector to zero */ -template -void AmbiVector<_Scalar,_Index>::setZero() +template +void AmbiVector<_Scalar,_StorageIndex>::setZero() { if (m_mode==IsDense) { @@ -178,8 +182,8 @@ void AmbiVector<_Scalar,_Index>::setZero() } } -template -_Scalar& AmbiVector<_Scalar,_Index>::coeffRef(_Index i) +template +_Scalar& AmbiVector<_Scalar,_StorageIndex>::coeffRef(Index i) { if (m_mode==IsDense) return m_buffer[i]; @@ -195,7 +199,7 @@ _Scalar& AmbiVector<_Scalar,_Index>::coeffRef(_Index i) m_llCurrent = 0; ++m_llSize; llElements[0].value = Scalar(0); - llElements[0].index = i; + llElements[0].index = convert_index(i); llElements[0].next = -1; return llElements[0].value; } @@ -204,7 +208,7 @@ _Scalar& AmbiVector<_Scalar,_Index>::coeffRef(_Index i) // this is going to be the new first element of the list ListEl& el = llElements[m_llSize]; el.value = Scalar(0); - el.index = i; + el.index = convert_index(i); el.next = m_llStart; m_llStart = m_llSize; ++m_llSize; @@ -213,7 +217,7 @@ _Scalar& AmbiVector<_Scalar,_Index>::coeffRef(_Index i) } else { - Index nextel = llElements[m_llCurrent].next; + StorageIndex nextel = llElements[m_llCurrent].next; eigen_assert(i>=llElements[m_llCurrent].index && "you must call restart() before inserting an element with lower or equal index"); while (nextel >= 0 && llElements[nextel].index<=i) { @@ -237,7 +241,7 @@ _Scalar& AmbiVector<_Scalar,_Index>::coeffRef(_Index i) // let's insert a new coefficient ListEl& el = llElements[m_llSize]; el.value = Scalar(0); - el.index = i; + el.index = convert_index(i); el.next = llElements[m_llCurrent].next; llElements[m_llCurrent].next = m_llSize; ++m_llSize; @@ -247,8 +251,8 @@ _Scalar& AmbiVector<_Scalar,_Index>::coeffRef(_Index i) } } -template -_Scalar& AmbiVector<_Scalar,_Index>::coeff(_Index i) +template +_Scalar& AmbiVector<_Scalar,_StorageIndex>::coeff(Index i) { if (m_mode==IsDense) return m_buffer[i]; @@ -275,8 +279,8 @@ _Scalar& AmbiVector<_Scalar,_Index>::coeff(_Index i) } /** Iterator over the nonzero coefficients */ -template -class AmbiVector<_Scalar,_Index>::Iterator +template +class AmbiVector<_Scalar,_StorageIndex>::Iterator { public: typedef _Scalar Scalar; @@ -288,7 +292,7 @@ class AmbiVector<_Scalar,_Index>::Iterator * In practice, all coefficients having a magnitude smaller than \a epsilon * are skipped. */ - Iterator(const AmbiVector& vec, const RealScalar& epsilon = 0) + explicit Iterator(const AmbiVector& vec, const RealScalar& epsilon = 0) : m_vector(vec) { using std::abs; @@ -320,7 +324,7 @@ class AmbiVector<_Scalar,_Index>::Iterator } } - Index index() const { return m_cachedIndex; } + StorageIndex index() const { return m_cachedIndex; } Scalar value() const { return m_cachedValue; } operator bool() const { return m_cachedIndex>=0; } @@ -332,7 +336,7 @@ class AmbiVector<_Scalar,_Index>::Iterator { do { ++m_cachedIndex; - } while (m_cachedIndex::Iterator ListEl* EIGEN_RESTRICT llElements = reinterpret_cast(m_vector.m_buffer); do { m_currentEl = llElements[m_currentEl].next; - } while (m_currentEl>=0 && abs(llElements[m_currentEl].value)=0 && abs(llElements[m_currentEl].value)<=m_epsilon); if (m_currentEl<0) { m_cachedIndex = -1; @@ -359,9 +363,9 @@ class AmbiVector<_Scalar,_Index>::Iterator protected: const AmbiVector& m_vector; // the target vector - Index m_currentEl; // the current element in sparse/linked-list mode + StorageIndex m_currentEl; // the current element in sparse/linked-list mode RealScalar m_epsilon; // epsilon used to prune zero coefficients - Index m_cachedIndex; // current coordinate + StorageIndex m_cachedIndex; // current coordinate Scalar m_cachedValue; // current value bool m_isDense; // mode of the vector }; diff --git a/libs/eigen3/Eigen/src/SparseCore/CompressedStorage.h b/libs/eigen3/Eigen/src/SparseCore/CompressedStorage.h index a667cb56e..d89fa0dae 100644 --- a/libs/eigen3/Eigen/src/SparseCore/CompressedStorage.h +++ b/libs/eigen3/Eigen/src/SparseCore/CompressedStorage.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -18,13 +18,13 @@ namespace internal { * Stores a sparse set of values as a list of values and a list of indices. * */ -template +template class CompressedStorage { public: typedef _Scalar Scalar; - typedef _Index Index; + typedef _StorageIndex StorageIndex; protected: @@ -36,7 +36,7 @@ class CompressedStorage : m_values(0), m_indices(0), m_size(0), m_allocatedSize(0) {} - CompressedStorage(size_t size) + explicit CompressedStorage(Index size) : m_values(0), m_indices(0), m_size(0), m_allocatedSize(0) { resize(size); @@ -51,8 +51,11 @@ class CompressedStorage CompressedStorage& operator=(const CompressedStorage& other) { resize(other.size()); - internal::smart_copy(other.m_values, other.m_values + m_size, m_values); - internal::smart_copy(other.m_indices, other.m_indices + m_size, m_indices); + if(other.size()>0) + { + internal::smart_copy(other.m_values, other.m_values + m_size, m_values); + internal::smart_copy(other.m_indices, other.m_indices + m_size, m_indices); + } return *this; } @@ -70,9 +73,9 @@ class CompressedStorage delete[] m_indices; } - void reserve(size_t size) + void reserve(Index size) { - size_t newAllocatedSize = m_size + size; + Index newAllocatedSize = m_size + size; if (newAllocatedSize > m_allocatedSize) reallocate(newAllocatedSize); } @@ -83,39 +86,40 @@ class CompressedStorage reallocate(m_size); } - void resize(size_t size, double reserveSizeFactor = 0) + void resize(Index size, double reserveSizeFactor = 0) { if (m_allocatedSize)(NumTraits::highest(), size + Index(reserveSizeFactor*double(size))); + if(realloc_size(m_size); + Index id = m_size; resize(m_size+1, 1); m_values[id] = v; - m_indices[id] = i; + m_indices[id] = internal::convert_index(i); } - inline size_t size() const { return m_size; } - inline size_t allocatedSize() const { return m_allocatedSize; } + inline Index size() const { return m_size; } + inline Index allocatedSize() const { return m_allocatedSize; } inline void clear() { m_size = 0; } - inline Scalar& value(size_t i) { return m_values[i]; } - inline const Scalar& value(size_t i) const { return m_values[i]; } + const Scalar* valuePtr() const { return m_values; } + Scalar* valuePtr() { return m_values; } + const StorageIndex* indexPtr() const { return m_indices; } + StorageIndex* indexPtr() { return m_indices; } - inline Index& index(size_t i) { return m_indices[i]; } - inline const Index& index(size_t i) const { return m_indices[i]; } + inline Scalar& value(Index i) { eigen_internal_assert(m_values!=0); return m_values[i]; } + inline const Scalar& value(Index i) const { eigen_internal_assert(m_values!=0); return m_values[i]; } - static CompressedStorage Map(Index* indices, Scalar* values, size_t size) - { - CompressedStorage res; - res.m_indices = indices; - res.m_values = values; - res.m_allocatedSize = res.m_size = size; - return res; - } + inline StorageIndex& index(Index i) { eigen_internal_assert(m_indices!=0); return m_indices[i]; } + inline const StorageIndex& index(Index i) const { eigen_internal_assert(m_indices!=0); return m_indices[i]; } /** \returns the largest \c k such that for all \c j in [0,k) index[\c j]\<\a key */ inline Index searchLowerIndex(Index key) const @@ -124,17 +128,17 @@ class CompressedStorage } /** \returns the largest \c k in [start,end) such that for all \c j in [start,k) index[\c j]\<\a key */ - inline Index searchLowerIndex(size_t start, size_t end, Index key) const + inline Index searchLowerIndex(Index start, Index end, Index key) const { while(end>start) { - size_t mid = (end+start)>>1; + Index mid = (end+start)>>1; if (m_indices[mid](start); + return start; } /** \returns the stored value at index \a key @@ -147,20 +151,20 @@ class CompressedStorage return m_values[m_size-1]; // ^^ optimization: let's first check if it is the last coefficient // (very common in high level algorithms) - const size_t id = searchLowerIndex(0,m_size-1,key); + const Index id = searchLowerIndex(0,m_size-1,key); return ((id=end) - return Scalar(0); + return defaultValue; else if (end>start && key==m_indices[end-1]) return m_values[end-1]; // ^^ optimization: let's first check if it is the last coefficient // (very common in high level algorithms) - const size_t id = searchLowerIndex(start,end-1,key); + const Index id = searchLowerIndex(start,end-1,key); return ((id=m_size || m_indices[id]!=key) { - resize(m_size+1,1); - for (size_t j=m_size-1; j>id; --j) + if (m_allocatedSize newValues(m_allocatedSize); + internal::scoped_array newIndices(m_allocatedSize); + + // copy first chunk + internal::smart_copy(m_values, m_values +id, newValues.ptr()); + internal::smart_copy(m_indices, m_indices+id, newIndices.ptr()); + + // copy the rest + if(m_size>id) + { + internal::smart_copy(m_values +id, m_values +m_size, newValues.ptr() +id+1); + internal::smart_copy(m_indices+id, m_indices+m_size, newIndices.ptr()+id+1); + } + std::swap(m_values,newValues.ptr()); + std::swap(m_indices,newIndices.ptr()); + } + else if(m_size>id) { - m_indices[j] = m_indices[j-1]; - m_values[j] = m_values[j-1]; + internal::smart_memmove(m_values +id, m_values +m_size, m_values +id+1); + internal::smart_memmove(m_indices+id, m_indices+m_size, m_indices+id+1); } - m_indices[id] = key; + m_size++; + m_indices[id] = internal::convert_index(key); m_values[id] = defaultValue; } return m_values[id]; @@ -186,9 +209,9 @@ class CompressedStorage void prune(const Scalar& reference, const RealScalar& epsilon = NumTraits::dummy_precision()) { - size_t k = 0; - size_t n = size(); - for (size_t i=0; i newValues(size); + internal::scoped_array newIndices(size); + Index copySize = (std::min)(size, m_size); + if (copySize>0) { + internal::smart_copy(m_values, m_values+copySize, newValues.ptr()); + internal::smart_copy(m_indices, m_indices+copySize, newIndices.ptr()); + } + std::swap(m_values,newValues.ptr()); + std::swap(m_indices,newIndices.ptr()); m_allocatedSize = size; } protected: Scalar* m_values; - Index* m_indices; - size_t m_size; - size_t m_allocatedSize; + StorageIndex* m_indices; + Index m_size; + Index m_allocatedSize; }; diff --git a/libs/eigen3/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h b/libs/eigen3/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h index 5c320e2d2..492eb0a29 100644 --- a/libs/eigen3/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h +++ b/libs/eigen3/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2011 Gael Guennebaud +// Copyright (C) 2008-2015 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -15,27 +15,31 @@ namespace Eigen { namespace internal { template -static void conservative_sparse_sparse_product_impl(const Lhs& lhs, const Rhs& rhs, ResultType& res) +static void conservative_sparse_sparse_product_impl(const Lhs& lhs, const Rhs& rhs, ResultType& res, bool sortedInsertion = false) { typedef typename remove_all::type::Scalar Scalar; - typedef typename remove_all::type::Index Index; // make sure to call innerSize/outerSize since we fake the storage order. Index rows = lhs.innerSize(); Index cols = rhs.outerSize(); eigen_assert(lhs.outerSize() == rhs.innerSize()); - - std::vector mask(rows,false); - Matrix values(rows); - Matrix indices(rows); - + + ei_declare_aligned_stack_constructed_variable(bool, mask, rows, 0); + ei_declare_aligned_stack_constructed_variable(Scalar, values, rows, 0); + ei_declare_aligned_stack_constructed_variable(Index, indices, rows, 0); + + std::memset(mask,0,sizeof(bool)*rows); + + evaluator lhsEval(lhs); + evaluator rhsEval(rhs); + // estimate the number of non zero entries // given a rhs column containing Y non zeros, we assume that the respective Y columns // of the lhs differs in average of one non zeros, thus the number of non zeros for // the product of a rhs column with the lhs is X+Y where X is the average number of non zero // per column of the lhs. // Therefore, we have nnz(lhs*rhs) = nnz(lhs) + nnz(rhs) - Index estimated_nnz_prod = lhs.nonZeros() + rhs.nonZeros(); + Index estimated_nnz_prod = lhsEval.nonZerosEstimate() + rhsEval.nonZerosEstimate(); res.setZero(); res.reserve(Index(estimated_nnz_prod)); @@ -45,11 +49,11 @@ static void conservative_sparse_sparse_product_impl(const Lhs& lhs, const Rhs& r res.startVec(j); Index nnz = 0; - for (typename Rhs::InnerIterator rhsIt(rhs, j); rhsIt; ++rhsIt) + for (typename evaluator::InnerIterator rhsIt(rhsEval, j); rhsIt; ++rhsIt) { Scalar y = rhsIt.value(); Index k = rhsIt.index(); - for (typename Lhs::InnerIterator lhsIt(lhs, k); lhsIt; ++lhsIt) + for (typename evaluator::InnerIterator lhsIt(lhsEval, k); lhsIt; ++lhsIt) { Index i = lhsIt.index(); Scalar x = lhsIt.value(); @@ -64,53 +68,51 @@ static void conservative_sparse_sparse_product_impl(const Lhs& lhs, const Rhs& r values[i] += x * y; } } - - // unordered insertion - for(Index k=0; k use a quick sort - // otherwise => loop through the entire vector - // In order to avoid to perform an expensive log2 when the - // result is clearly very sparse we use a linear bound up to 200. - //if((nnz<200 && nnz1) std::sort(indices.data(),indices.data()+nnz); + // unordered insertion for(Index k=0; k use a quick sort + // otherwise => loop through the entire vector + // In order to avoid to perform an expensive log2 when the + // result is clearly very sparse we use a linear bound up to 200. + if((nnz<200 && nnz1) std::sort(indices,indices+nnz); + for(Index k=0; k RowMajorMatrix; - typedef SparseMatrix ColMajorMatrix; - ColMajorMatrix resCol(lhs.rows(),rhs.cols()); - internal::conservative_sparse_sparse_product_impl(lhs, rhs, resCol); - // sort the non zeros: - RowMajorMatrix resRow(resCol); - res = resRow; + typedef SparseMatrix RowMajorMatrix; + typedef SparseMatrix ColMajorMatrixAux; + typedef typename sparse_eval::type ColMajorMatrix; + + // If the result is tall and thin (in the extreme case a column vector) + // then it is faster to sort the coefficients inplace instead of transposing twice. + // FIXME, the following heuristic is probably not very good. + if(lhs.rows()>rhs.cols()) + { + ColMajorMatrix resCol(lhs.rows(),rhs.cols()); + // perform sorted insertion + internal::conservative_sparse_sparse_product_impl(lhs, rhs, resCol, true); + res = resCol.markAsRValue(); + } + else + { + ColMajorMatrixAux resCol(lhs.rows(),rhs.cols()); + // ressort to transpose to sort the entries + internal::conservative_sparse_sparse_product_impl(lhs, rhs, resCol, false); + RowMajorMatrix resRow(resCol); + res = resRow.markAsRValue(); + } } }; @@ -149,7 +166,7 @@ struct conservative_sparse_sparse_product_selector RowMajorMatrix; + typedef SparseMatrix RowMajorMatrix; RowMajorMatrix rhsRow = rhs; RowMajorMatrix resRow(lhs.rows(), rhs.cols()); internal::conservative_sparse_sparse_product_impl(rhsRow, lhs, resRow); @@ -162,7 +179,7 @@ struct conservative_sparse_sparse_product_selector RowMajorMatrix; + typedef SparseMatrix RowMajorMatrix; RowMajorMatrix lhsRow = lhs; RowMajorMatrix resRow(lhs.rows(), rhs.cols()); internal::conservative_sparse_sparse_product_impl(rhs, lhsRow, resRow); @@ -175,7 +192,7 @@ struct conservative_sparse_sparse_product_selector RowMajorMatrix; + typedef SparseMatrix RowMajorMatrix; RowMajorMatrix resRow(lhs.rows(), rhs.cols()); internal::conservative_sparse_sparse_product_impl(rhs, lhs, resRow); res = resRow; @@ -190,7 +207,7 @@ struct conservative_sparse_sparse_product_selector ColMajorMatrix; + typedef SparseMatrix ColMajorMatrix; ColMajorMatrix resCol(lhs.rows(), rhs.cols()); internal::conservative_sparse_sparse_product_impl(lhs, rhs, resCol); res = resCol; @@ -202,7 +219,7 @@ struct conservative_sparse_sparse_product_selector ColMajorMatrix; + typedef SparseMatrix ColMajorMatrix; ColMajorMatrix lhsCol = lhs; ColMajorMatrix resCol(lhs.rows(), rhs.cols()); internal::conservative_sparse_sparse_product_impl(lhsCol, rhs, resCol); @@ -215,7 +232,7 @@ struct conservative_sparse_sparse_product_selector ColMajorMatrix; + typedef SparseMatrix ColMajorMatrix; ColMajorMatrix rhsCol = rhs; ColMajorMatrix resCol(lhs.rows(), rhs.cols()); internal::conservative_sparse_sparse_product_impl(lhs, rhsCol, resCol); @@ -228,8 +245,8 @@ struct conservative_sparse_sparse_product_selector RowMajorMatrix; - typedef SparseMatrix ColMajorMatrix; + typedef SparseMatrix RowMajorMatrix; + typedef SparseMatrix ColMajorMatrix; RowMajorMatrix resRow(lhs.rows(),rhs.cols()); internal::conservative_sparse_sparse_product_impl(rhs, lhs, resRow); // sort the non zeros: @@ -238,6 +255,89 @@ struct conservative_sparse_sparse_product_selector +static void sparse_sparse_to_dense_product_impl(const Lhs& lhs, const Rhs& rhs, ResultType& res) +{ + typedef typename remove_all::type::Scalar Scalar; + Index cols = rhs.outerSize(); + eigen_assert(lhs.outerSize() == rhs.innerSize()); + + evaluator lhsEval(lhs); + evaluator rhsEval(rhs); + + for (Index j=0; j::InnerIterator rhsIt(rhsEval, j); rhsIt; ++rhsIt) + { + Scalar y = rhsIt.value(); + Index k = rhsIt.index(); + for (typename evaluator::InnerIterator lhsIt(lhsEval, k); lhsIt; ++lhsIt) + { + Index i = lhsIt.index(); + Scalar x = lhsIt.value(); + res.coeffRef(i,j) += x * y; + } + } + } +} + + +} // end namespace internal + +namespace internal { + +template::Flags&RowMajorBit) ? RowMajor : ColMajor, + int RhsStorageOrder = (traits::Flags&RowMajorBit) ? RowMajor : ColMajor> +struct sparse_sparse_to_dense_product_selector; + +template +struct sparse_sparse_to_dense_product_selector +{ + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) + { + internal::sparse_sparse_to_dense_product_impl(lhs, rhs, res); + } +}; + +template +struct sparse_sparse_to_dense_product_selector +{ + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) + { + typedef SparseMatrix ColMajorMatrix; + ColMajorMatrix lhsCol(lhs); + internal::sparse_sparse_to_dense_product_impl(lhsCol, rhs, res); + } +}; + +template +struct sparse_sparse_to_dense_product_selector +{ + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) + { + typedef SparseMatrix ColMajorMatrix; + ColMajorMatrix rhsCol(rhs); + internal::sparse_sparse_to_dense_product_impl(lhs, rhsCol, res); + } +}; + +template +struct sparse_sparse_to_dense_product_selector +{ + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) + { + Transpose trRes(res); + internal::sparse_sparse_to_dense_product_impl >(rhs, lhs, trRes); + } +}; + + } // end namespace internal } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/SparseCore/MappedSparseMatrix.h b/libs/eigen3/Eigen/src/SparseCore/MappedSparseMatrix.h index ab1a266a9..67718c85b 100644 --- a/libs/eigen3/Eigen/src/SparseCore/MappedSparseMatrix.h +++ b/libs/eigen3/Eigen/src/SparseCore/MappedSparseMatrix.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -10,9 +10,10 @@ #ifndef EIGEN_MAPPED_SPARSEMATRIX_H #define EIGEN_MAPPED_SPARSEMATRIX_H -namespace Eigen { +namespace Eigen { -/** \class MappedSparseMatrix +/** \deprecated Use Map > + * \class MappedSparseMatrix * * \brief Sparse matrix * @@ -22,160 +23,45 @@ namespace Eigen { * */ namespace internal { -template -struct traits > : traits > +template +struct traits > : traits > {}; -} +} // end namespace internal -template +template class MappedSparseMatrix - : public SparseMatrixBase > + : public Map > { - public: - EIGEN_SPARSE_PUBLIC_INTERFACE(MappedSparseMatrix) - enum { IsRowMajor = Base::IsRowMajor }; - - protected: - - Index m_outerSize; - Index m_innerSize; - Index m_nnz; - Index* m_outerIndex; - Index* m_innerIndices; - Scalar* m_values; + typedef Map > Base; public: - - inline Index rows() const { return IsRowMajor ? m_outerSize : m_innerSize; } - inline Index cols() const { return IsRowMajor ? m_innerSize : m_outerSize; } - inline Index innerSize() const { return m_innerSize; } - inline Index outerSize() const { return m_outerSize; } - bool isCompressed() const { return true; } - - //---------------------------------------- - // direct access interface - inline const Scalar* valuePtr() const { return m_values; } - inline Scalar* valuePtr() { return m_values; } - - inline const Index* innerIndexPtr() const { return m_innerIndices; } - inline Index* innerIndexPtr() { return m_innerIndices; } - - inline const Index* outerIndexPtr() const { return m_outerIndex; } - inline Index* outerIndexPtr() { return m_outerIndex; } - //---------------------------------------- - - inline Scalar coeff(Index row, Index col) const - { - const Index outer = IsRowMajor ? row : col; - const Index inner = IsRowMajor ? col : row; + typedef typename Base::StorageIndex StorageIndex; + typedef typename Base::Scalar Scalar; - Index start = m_outerIndex[outer]; - Index end = m_outerIndex[outer+1]; - if (start==end) - return Scalar(0); - else if (end>0 && inner==m_innerIndices[end-1]) - return m_values[end-1]; - // ^^ optimization: let's first check if it is the last coefficient - // (very common in high level algorithms) - - const Index* r = std::lower_bound(&m_innerIndices[start],&m_innerIndices[end-1],inner); - const Index id = r-&m_innerIndices[0]; - return ((*r==inner) && (id=start && "you probably called coeffRef on a non finalized matrix"); - eigen_assert(end>start && "coeffRef cannot be called on a zero coefficient"); - Index* r = std::lower_bound(&m_innerIndices[start],&m_innerIndices[end],inner); - const Index id = r-&m_innerIndices[0]; - eigen_assert((*r==inner) && (id -class MappedSparseMatrix::InnerIterator -{ - public: - InnerIterator(const MappedSparseMatrix& mat, Index outer) - : m_matrix(mat), - m_outer(outer), - m_id(mat.outerIndexPtr()[outer]), - m_start(m_id), - m_end(mat.outerIndexPtr()[outer+1]) - {} - - inline InnerIterator& operator++() { m_id++; return *this; } - - inline Scalar value() const { return m_matrix.valuePtr()[m_id]; } - inline Scalar& valueRef() { return const_cast(m_matrix.valuePtr()[m_id]); } - - inline Index index() const { return m_matrix.innerIndexPtr()[m_id]; } - inline Index row() const { return IsRowMajor ? m_outer : index(); } - inline Index col() const { return IsRowMajor ? index() : m_outer; } - - inline operator bool() const { return (m_id < m_end) && (m_id>=m_start); } - - protected: - const MappedSparseMatrix& m_matrix; - const Index m_outer; - Index m_id; - const Index m_start; - const Index m_end; -}; +namespace internal { -template -class MappedSparseMatrix::ReverseInnerIterator +template +struct evaluator > + : evaluator > > { - public: - ReverseInnerIterator(const MappedSparseMatrix& mat, Index outer) - : m_matrix(mat), - m_outer(outer), - m_id(mat.outerIndexPtr()[outer+1]), - m_start(mat.outerIndexPtr()[outer]), - m_end(m_id) - {} - - inline ReverseInnerIterator& operator--() { m_id--; return *this; } - - inline Scalar value() const { return m_matrix.valuePtr()[m_id-1]; } - inline Scalar& valueRef() { return const_cast(m_matrix.valuePtr()[m_id-1]); } - - inline Index index() const { return m_matrix.innerIndexPtr()[m_id-1]; } - inline Index row() const { return IsRowMajor ? m_outer : index(); } - inline Index col() const { return IsRowMajor ? index() : m_outer; } - - inline operator bool() const { return (m_id <= m_end) && (m_id>m_start); } - - protected: - const MappedSparseMatrix& m_matrix; - const Index m_outer; - Index m_id; - const Index m_start; - const Index m_end; + typedef MappedSparseMatrix<_Scalar,_Options,_StorageIndex> XprType; + typedef evaluator > Base; + + evaluator() : Base() {} + explicit evaluator(const XprType &mat) : Base(mat) {} }; +} + } // end namespace Eigen #endif // EIGEN_MAPPED_SPARSEMATRIX_H diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseAssign.h b/libs/eigen3/Eigen/src/SparseCore/SparseAssign.h new file mode 100644 index 000000000..18352a847 --- /dev/null +++ b/libs/eigen3/Eigen/src/SparseCore/SparseAssign.h @@ -0,0 +1,216 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2014 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSEASSIGN_H +#define EIGEN_SPARSEASSIGN_H + +namespace Eigen { + +template +template +Derived& SparseMatrixBase::operator=(const EigenBase &other) +{ + internal::call_assignment_no_alias(derived(), other.derived()); + return derived(); +} + +template +template +Derived& SparseMatrixBase::operator=(const ReturnByValue& other) +{ + // TODO use the evaluator mechanism + other.evalTo(derived()); + return derived(); +} + +template +template +inline Derived& SparseMatrixBase::operator=(const SparseMatrixBase& other) +{ + // by default sparse evaluation do not alias, so we can safely bypass the generic call_assignment routine + internal::Assignment > + ::run(derived(), other.derived(), internal::assign_op()); + return derived(); +} + +template +inline Derived& SparseMatrixBase::operator=(const Derived& other) +{ + internal::call_assignment_no_alias(derived(), other.derived()); + return derived(); +} + +namespace internal { + +template<> +struct storage_kind_to_evaluator_kind { + typedef IteratorBased Kind; +}; + +template<> +struct storage_kind_to_shape { + typedef SparseShape Shape; +}; + +struct Sparse2Sparse {}; +struct Sparse2Dense {}; + +template<> struct AssignmentKind { typedef Sparse2Sparse Kind; }; +template<> struct AssignmentKind { typedef Sparse2Sparse Kind; }; +template<> struct AssignmentKind { typedef Sparse2Dense Kind; }; +template<> struct AssignmentKind { typedef Sparse2Dense Kind; }; + + +template +void assign_sparse_to_sparse(DstXprType &dst, const SrcXprType &src) +{ + typedef typename DstXprType::Scalar Scalar; + typedef internal::evaluator DstEvaluatorType; + typedef internal::evaluator SrcEvaluatorType; + + SrcEvaluatorType srcEvaluator(src); + + const bool transpose = (DstEvaluatorType::Flags & RowMajorBit) != (SrcEvaluatorType::Flags & RowMajorBit); + const Index outerEvaluationSize = (SrcEvaluatorType::Flags&RowMajorBit) ? src.rows() : src.cols(); + if ((!transpose) && src.isRValue()) + { + // eval without temporary + dst.resize(src.rows(), src.cols()); + dst.setZero(); + dst.reserve((std::max)(src.rows(),src.cols())*2); + for (Index j=0; j::SupportedAccessPatterns & OuterRandomAccessPattern)==OuterRandomAccessPattern) || + (!((DstEvaluatorType::Flags & RowMajorBit) != (SrcEvaluatorType::Flags & RowMajorBit)))) && + "the transpose operation is supposed to be handled in SparseMatrix::operator="); + + enum { Flip = (DstEvaluatorType::Flags & RowMajorBit) != (SrcEvaluatorType::Flags & RowMajorBit) }; + + + DstXprType temp(src.rows(), src.cols()); + + temp.reserve((std::max)(src.rows(),src.cols())*2); + for (Index j=0; j +struct Assignment +{ + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &/*func*/) + { + assign_sparse_to_sparse(dst.derived(), src.derived()); + } +}; + +// Generic Sparse to Dense assignment +template< typename DstXprType, typename SrcXprType, typename Functor> +struct Assignment +{ + static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) + { + if(internal::is_same >::value) + dst.setZero(); + + internal::evaluator srcEval(src); + resize_if_allowed(dst, src, func); + internal::evaluator dstEval(dst); + + const Index outerEvaluationSize = (internal::evaluator::Flags&RowMajorBit) ? src.rows() : src.cols(); + for (Index j=0; j::InnerIterator i(srcEval,j); i; ++i) + func.assignCoeff(dstEval.coeffRef(i.row(),i.col()), i.value()); + } +}; + +// Specialization for "dst = dec.solve(rhs)" +// NOTE we need to specialize it for Sparse2Sparse to avoid ambiguous specialization error +template +struct Assignment, internal::assign_op, Sparse2Sparse> +{ + typedef Solve SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + src.dec()._solve_impl(src.rhs(), dst); + } +}; + +struct Diagonal2Sparse {}; + +template<> struct AssignmentKind { typedef Diagonal2Sparse Kind; }; + +template< typename DstXprType, typename SrcXprType, typename Functor> +struct Assignment +{ + typedef typename DstXprType::StorageIndex StorageIndex; + typedef typename DstXprType::Scalar Scalar; + typedef Array ArrayXI; + typedef Array ArrayXS; + template + static void run(SparseMatrix &dst, const SrcXprType &src, const internal::assign_op &/*func*/) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + Index size = src.diagonal().size(); + dst.makeCompressed(); + dst.resizeNonZeros(size); + Map(dst.innerIndexPtr(), size).setLinSpaced(0,StorageIndex(size)-1); + Map(dst.outerIndexPtr(), size+1).setLinSpaced(0,StorageIndex(size)); + Map(dst.valuePtr(), size) = src.diagonal(); + } + + template + static void run(SparseMatrixBase &dst, const SrcXprType &src, const internal::assign_op &/*func*/) + { + dst.diagonal() = src.diagonal(); + } + + static void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &/*func*/) + { dst.diagonal() += src.diagonal(); } + + static void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &/*func*/) + { dst.diagonal() -= src.diagonal(); } +}; +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_SPARSEASSIGN_H diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseBlock.h b/libs/eigen3/Eigen/src/SparseCore/SparseBlock.h index 16a20a574..511e92b2f 100644 --- a/libs/eigen3/Eigen/src/SparseCore/SparseBlock.h +++ b/libs/eigen3/Eigen/src/SparseCore/SparseBlock.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -10,8 +10,9 @@ #ifndef EIGEN_SPARSE_BLOCK_H #define EIGEN_SPARSE_BLOCK_H -namespace Eigen { +namespace Eigen { +// Subset of columns or rows template class BlockImpl : public SparseMatrixBase > @@ -22,172 +23,189 @@ class BlockImpl enum { IsRowMajor = internal::traits::IsRowMajor }; protected: enum { OuterSize = IsRowMajor ? BlockRows : BlockCols }; + typedef SparseMatrixBase Base; + using Base::convert_index; public: EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType) - - class InnerIterator: public XprType::InnerIterator - { - typedef typename BlockImpl::Index Index; - public: - inline InnerIterator(const BlockType& xpr, Index outer) - : XprType::InnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) - {} - inline Index row() const { return IsRowMajor ? m_outer : this->index(); } - inline Index col() const { return IsRowMajor ? this->index() : m_outer; } - protected: - Index m_outer; - }; - class ReverseInnerIterator: public XprType::ReverseInnerIterator - { - typedef typename BlockImpl::Index Index; - public: - inline ReverseInnerIterator(const BlockType& xpr, Index outer) - : XprType::ReverseInnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) - {} - inline Index row() const { return IsRowMajor ? m_outer : this->index(); } - inline Index col() const { return IsRowMajor ? this->index() : m_outer; } - protected: - Index m_outer; - }; - inline BlockImpl(const XprType& xpr, int i) - : m_matrix(xpr), m_outerStart(i), m_outerSize(OuterSize) + inline BlockImpl(XprType& xpr, Index i) + : m_matrix(xpr), m_outerStart(convert_index(i)), m_outerSize(OuterSize) {} - inline BlockImpl(const XprType& xpr, int startRow, int startCol, int blockRows, int blockCols) - : m_matrix(xpr), m_outerStart(IsRowMajor ? startRow : startCol), m_outerSize(IsRowMajor ? blockRows : blockCols) + inline BlockImpl(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) + : m_matrix(xpr), m_outerStart(convert_index(IsRowMajor ? startRow : startCol)), m_outerSize(convert_index(IsRowMajor ? blockRows : blockCols)) {} EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); } EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); } + Index nonZeros() const + { + typedef internal::evaluator EvaluatorType; + EvaluatorType matEval(m_matrix); + Index nnz = 0; + Index end = m_outerStart + m_outerSize.value(); + for(Index j=m_outerStart; j::non_const_type m_matrix; Index m_outerStart; const internal::variable_if_dynamic m_outerSize; - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl) + protected: + // Disable assignment with clear error message. + // Note that simply removing operator= yields compilation errors with ICC+MSVC + template + BlockImpl& operator=(const T&) + { + EIGEN_STATIC_ASSERT(sizeof(T)==0, THIS_SPARSE_BLOCK_SUBEXPRESSION_IS_READ_ONLY); + return *this; + } }; /*************************************************************************** -* specialisation for SparseMatrix +* specialization for SparseMatrix ***************************************************************************/ -template -class BlockImpl,BlockRows,BlockCols,true,Sparse> - : public SparseMatrixBase,BlockRows,BlockCols,true> > +namespace internal { + +template +class sparse_matrix_block_impl + : public SparseCompressedBase > { - typedef SparseMatrix<_Scalar, _Options, _Index> SparseMatrixType; typedef typename internal::remove_all::type _MatrixTypeNested; typedef Block BlockType; + typedef SparseCompressedBase > Base; + using Base::convert_index; public: enum { IsRowMajor = internal::traits::IsRowMajor }; EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType) protected: + typedef typename Base::IndexVector IndexVector; enum { OuterSize = IsRowMajor ? BlockRows : BlockCols }; public: - - class InnerIterator: public SparseMatrixType::InnerIterator - { - public: - inline InnerIterator(const BlockType& xpr, Index outer) - : SparseMatrixType::InnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) - {} - inline Index row() const { return IsRowMajor ? m_outer : this->index(); } - inline Index col() const { return IsRowMajor ? this->index() : m_outer; } - protected: - Index m_outer; - }; - class ReverseInnerIterator: public SparseMatrixType::ReverseInnerIterator - { - public: - inline ReverseInnerIterator(const BlockType& xpr, Index outer) - : SparseMatrixType::ReverseInnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) - {} - inline Index row() const { return IsRowMajor ? m_outer : this->index(); } - inline Index col() const { return IsRowMajor ? this->index() : m_outer; } - protected: - Index m_outer; - }; - inline BlockImpl(const SparseMatrixType& xpr, int i) - : m_matrix(xpr), m_outerStart(i), m_outerSize(OuterSize) + inline sparse_matrix_block_impl(SparseMatrixType& xpr, Index i) + : m_matrix(xpr), m_outerStart(convert_index(i)), m_outerSize(OuterSize) {} - inline BlockImpl(const SparseMatrixType& xpr, int startRow, int startCol, int blockRows, int blockCols) - : m_matrix(xpr), m_outerStart(IsRowMajor ? startRow : startCol), m_outerSize(IsRowMajor ? blockRows : blockCols) + inline sparse_matrix_block_impl(SparseMatrixType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) + : m_matrix(xpr), m_outerStart(convert_index(IsRowMajor ? startRow : startCol)), m_outerSize(convert_index(IsRowMajor ? blockRows : blockCols)) {} template inline BlockType& operator=(const SparseMatrixBase& other) { typedef typename internal::remove_all::type _NestedMatrixType; - _NestedMatrixType& matrix = const_cast<_NestedMatrixType&>(m_matrix);; - // This assignement is slow if this vector set is not empty + _NestedMatrixType& matrix = m_matrix; + // This assignment is slow if this vector set is not empty // and/or it is not at the end of the nonzeros of the underlying matrix. // 1 - eval to a temporary to avoid transposition and/or aliasing issues - SparseMatrix tmp(other); + Ref > tmp(other.derived()); + eigen_internal_assert(tmp.outerSize()==m_outerSize.value()); // 2 - let's check whether there is enough allocated memory Index nnz = tmp.nonZeros(); - Index start = m_outerStart==0 ? 0 : matrix.outerIndexPtr()[m_outerStart]; // starting position of the current block - Index end = m_matrix.outerIndexPtr()[m_outerStart+m_outerSize.value()]; // ending posiiton of the current block + Index start = m_outerStart==0 ? 0 : m_matrix.outerIndexPtr()[m_outerStart]; // starting position of the current block + Index end = m_matrix.outerIndexPtr()[m_outerStart+m_outerSize.value()]; // ending position of the current block Index block_size = end - start; // available room in the current block Index tail_size = m_matrix.outerIndexPtr()[m_matrix.outerSize()] - end; - + Index free_size = m_matrix.isCompressed() ? Index(matrix.data().allocatedSize()) + block_size : block_size; - if(nnz>free_size) + Index tmp_start = tmp.outerIndexPtr()[0]; + + bool update_trailing_pointers = false; + if(nnz>free_size) { // realloc manually to reduce copies typename SparseMatrixType::Storage newdata(m_matrix.data().allocatedSize() - block_size + nnz); - std::memcpy(&newdata.value(0), &m_matrix.data().value(0), start*sizeof(Scalar)); - std::memcpy(&newdata.index(0), &m_matrix.data().index(0), start*sizeof(Index)); + internal::smart_copy(m_matrix.valuePtr(), m_matrix.valuePtr() + start, newdata.valuePtr()); + internal::smart_copy(m_matrix.innerIndexPtr(), m_matrix.innerIndexPtr() + start, newdata.indexPtr()); + + internal::smart_copy(tmp.valuePtr() + tmp_start, tmp.valuePtr() + tmp_start + nnz, newdata.valuePtr() + start); + internal::smart_copy(tmp.innerIndexPtr() + tmp_start, tmp.innerIndexPtr() + tmp_start + nnz, newdata.indexPtr() + start); - std::memcpy(&newdata.value(start), &tmp.data().value(0), nnz*sizeof(Scalar)); - std::memcpy(&newdata.index(start), &tmp.data().index(0), nnz*sizeof(Index)); + internal::smart_copy(matrix.valuePtr()+end, matrix.valuePtr()+end + tail_size, newdata.valuePtr()+start+nnz); + internal::smart_copy(matrix.innerIndexPtr()+end, matrix.innerIndexPtr()+end + tail_size, newdata.indexPtr()+start+nnz); - std::memcpy(&newdata.value(start+nnz), &matrix.data().value(end), tail_size*sizeof(Scalar)); - std::memcpy(&newdata.index(start+nnz), &matrix.data().index(end), tail_size*sizeof(Index)); - newdata.resize(m_matrix.outerIndexPtr()[m_matrix.outerSize()] - block_size + nnz); matrix.data().swap(newdata); + + update_trailing_pointers = true; } else { - // no need to realloc, simply copy the tail at its respective position and insert tmp - matrix.data().resize(start + nnz + tail_size); + if(m_matrix.isCompressed()) + { + // no need to realloc, simply copy the tail at its respective position and insert tmp + matrix.data().resize(start + nnz + tail_size); - std::memmove(&matrix.data().value(start+nnz), &matrix.data().value(end), tail_size*sizeof(Scalar)); - std::memmove(&matrix.data().index(start+nnz), &matrix.data().index(end), tail_size*sizeof(Index)); + internal::smart_memmove(matrix.valuePtr()+end, matrix.valuePtr() + end+tail_size, matrix.valuePtr() + start+nnz); + internal::smart_memmove(matrix.innerIndexPtr()+end, matrix.innerIndexPtr() + end+tail_size, matrix.innerIndexPtr() + start+nnz); - std::memcpy(&matrix.data().value(start), &tmp.data().value(0), nnz*sizeof(Scalar)); - std::memcpy(&matrix.data().index(start), &tmp.data().index(0), nnz*sizeof(Index)); + update_trailing_pointers = true; + } + + internal::smart_copy(tmp.valuePtr() + tmp_start, tmp.valuePtr() + tmp_start + nnz, matrix.valuePtr() + start); + internal::smart_copy(tmp.innerIndexPtr() + tmp_start, tmp.innerIndexPtr() + tmp_start + nnz, matrix.innerIndexPtr() + start); } - - // update innerNonZeros - if(!m_matrix.isCompressed()) - for(Index j=0; j(tmp.innerVector(k).nonZeros()); + if(!m_matrix.isCompressed()) + matrix.innerNonZeroPtr()[m_outerStart+k] = nnz_k; + matrix.outerIndexPtr()[m_outerStart+k] = p; + p += nnz_k; + } + } + + if(update_trailing_pointers) + { + StorageIndex offset = internal::convert_index(nnz - block_size); + for(Index k = m_outerStart + m_outerSize.value(); k<=matrix.outerSize(); ++k) + { + matrix.outerIndexPtr()[k] += offset; + } } return derived(); @@ -199,35 +217,46 @@ class BlockImpl,BlockRows,BlockCols,true } inline const Scalar* valuePtr() const - { return m_matrix.valuePtr() + m_matrix.outerIndexPtr()[m_outerStart]; } + { return m_matrix.valuePtr(); } inline Scalar* valuePtr() - { return m_matrix.const_cast_derived().valuePtr() + m_matrix.outerIndexPtr()[m_outerStart]; } + { return m_matrix.valuePtr(); } - inline const Index* innerIndexPtr() const - { return m_matrix.innerIndexPtr() + m_matrix.outerIndexPtr()[m_outerStart]; } - inline Index* innerIndexPtr() - { return m_matrix.const_cast_derived().innerIndexPtr() + m_matrix.outerIndexPtr()[m_outerStart]; } + inline const StorageIndex* innerIndexPtr() const + { return m_matrix.innerIndexPtr(); } + inline StorageIndex* innerIndexPtr() + { return m_matrix.innerIndexPtr(); } - inline const Index* outerIndexPtr() const + inline const StorageIndex* outerIndexPtr() const + { return m_matrix.outerIndexPtr() + m_outerStart; } + inline StorageIndex* outerIndexPtr() { return m_matrix.outerIndexPtr() + m_outerStart; } - inline Index* outerIndexPtr() - { return m_matrix.const_cast_derived().outerIndexPtr() + m_outerStart; } - Index nonZeros() const + inline const StorageIndex* innerNonZeroPtr() const + { return isCompressed() ? 0 : (m_matrix.innerNonZeroPtr()+m_outerStart); } + inline StorageIndex* innerNonZeroPtr() + { return isCompressed() ? 0 : (m_matrix.innerNonZeroPtr()+m_outerStart); } + + bool isCompressed() const { return m_matrix.innerNonZeroPtr()==0; } + + inline Scalar& coeffRef(Index row, Index col) { - if(m_matrix.isCompressed()) - return std::size_t(m_matrix.outerIndexPtr()[m_outerStart+m_outerSize.value()]) - - std::size_t(m_matrix.outerIndexPtr()[m_outerStart]); - else if(m_outerSize.value()==0) - return 0; - else - return Map >(m_matrix.innerNonZeroPtr()+m_outerStart, m_outerSize.value()).sum(); + return m_matrix.coeffRef(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 : m_outerStart)); + } + + inline const Scalar coeff(Index row, Index col) const + { + return m_matrix.coeff(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 : m_outerStart)); + } + + inline const Scalar coeff(Index index) const + { + return m_matrix.coeff(IsRowMajor ? m_outerStart : index, IsRowMajor ? index : m_outerStart); } const Scalar& lastCoeff() const { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(BlockImpl); - eigen_assert(nonZeros()>0); + EIGEN_STATIC_ASSERT_VECTOR_ONLY(sparse_matrix_block_impl); + eigen_assert(Base::nonZeros()>0); if(m_matrix.isCompressed()) return m_matrix.valuePtr()[m_matrix.outerIndexPtr()[m_outerStart+1]-1]; else @@ -237,14 +266,64 @@ class BlockImpl,BlockRows,BlockCols,true EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); } EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); } + inline const SparseMatrixType& nestedExpression() const { return m_matrix; } + inline SparseMatrixType& nestedExpression() { return m_matrix; } + Index startRow() const { return IsRowMajor ? m_outerStart : 0; } + Index startCol() const { return IsRowMajor ? 0 : m_outerStart; } + Index blockRows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); } + Index blockCols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); } + protected: - typename SparseMatrixType::Nested m_matrix; + typename internal::ref_selector::non_const_type m_matrix; Index m_outerStart; const internal::variable_if_dynamic m_outerSize; }; +} // namespace internal + +template +class BlockImpl,BlockRows,BlockCols,true,Sparse> + : public internal::sparse_matrix_block_impl,BlockRows,BlockCols> +{ +public: + typedef _StorageIndex StorageIndex; + typedef SparseMatrix<_Scalar, _Options, _StorageIndex> SparseMatrixType; + typedef internal::sparse_matrix_block_impl Base; + inline BlockImpl(SparseMatrixType& xpr, Index i) + : Base(xpr, i) + {} + + inline BlockImpl(SparseMatrixType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) + : Base(xpr, startRow, startCol, blockRows, blockCols) + {} + + using Base::operator=; +}; + +template +class BlockImpl,BlockRows,BlockCols,true,Sparse> + : public internal::sparse_matrix_block_impl,BlockRows,BlockCols> +{ +public: + typedef _StorageIndex StorageIndex; + typedef const SparseMatrix<_Scalar, _Options, _StorageIndex> SparseMatrixType; + typedef internal::sparse_matrix_block_impl Base; + inline BlockImpl(SparseMatrixType& xpr, Index i) + : Base(xpr, i) + {} + + inline BlockImpl(SparseMatrixType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) + : Base(xpr, startRow, startCol, blockRows, blockCols) + {} + + using Base::operator=; +private: + template BlockImpl(const SparseMatrixBase& xpr, Index i); + template BlockImpl(const SparseMatrixBase& xpr); +}; + //---------- /** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this @@ -265,145 +344,260 @@ const typename SparseMatrixBase::ConstInnerVectorReturnType SparseMatri * is col-major (resp. row-major). */ template -Block SparseMatrixBase::innerVectors(Index outerStart, Index outerSize) +typename SparseMatrixBase::InnerVectorsReturnType +SparseMatrixBase::innerVectors(Index outerStart, Index outerSize) { return Block(derived(), IsRowMajor ? outerStart : 0, IsRowMajor ? 0 : outerStart, IsRowMajor ? outerSize : rows(), IsRowMajor ? cols() : outerSize); - + } /** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this * is col-major (resp. row-major). Read-only. */ template -const Block SparseMatrixBase::innerVectors(Index outerStart, Index outerSize) const +const typename SparseMatrixBase::ConstInnerVectorsReturnType +SparseMatrixBase::innerVectors(Index outerStart, Index outerSize) const { return Block(derived(), IsRowMajor ? outerStart : 0, IsRowMajor ? 0 : outerStart, IsRowMajor ? outerSize : rows(), IsRowMajor ? cols() : outerSize); - + } /** Generic implementation of sparse Block expression. - * Real-only. + * Real-only. */ template class BlockImpl : public SparseMatrixBase >, internal::no_assignment_operator { - typedef typename internal::remove_all::type _MatrixTypeNested; - typedef Block BlockType; + typedef Block BlockType; + typedef SparseMatrixBase Base; + using Base::convert_index; public: enum { IsRowMajor = internal::traits::IsRowMajor }; EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType) + typedef typename internal::remove_all::type _MatrixTypeNested; + /** Column or Row constructor */ - inline BlockImpl(const XprType& xpr, int i) + inline BlockImpl(XprType& xpr, Index i) : m_matrix(xpr), - m_startRow( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0), - m_startCol( (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0), - m_blockRows(xpr.rows()), - m_blockCols(xpr.cols()) + m_startRow( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? convert_index(i) : 0), + m_startCol( (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? convert_index(i) : 0), + m_blockRows(BlockRows==1 ? 1 : xpr.rows()), + m_blockCols(BlockCols==1 ? 1 : xpr.cols()) {} /** Dynamic-size constructor */ - inline BlockImpl(const XprType& xpr, int startRow, int startCol, int blockRows, int blockCols) - : m_matrix(xpr), m_startRow(startRow), m_startCol(startCol), m_blockRows(blockRows), m_blockCols(blockCols) + inline BlockImpl(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) + : m_matrix(xpr), m_startRow(convert_index(startRow)), m_startCol(convert_index(startCol)), m_blockRows(convert_index(blockRows)), m_blockCols(convert_index(blockCols)) {} - inline int rows() const { return m_blockRows.value(); } - inline int cols() const { return m_blockCols.value(); } + inline Index rows() const { return m_blockRows.value(); } + inline Index cols() const { return m_blockCols.value(); } - inline Scalar& coeffRef(int row, int col) + inline Scalar& coeffRef(Index row, Index col) { - return m_matrix.const_cast_derived() - .coeffRef(row + m_startRow.value(), col + m_startCol.value()); + return m_matrix.coeffRef(row + m_startRow.value(), col + m_startCol.value()); } - inline const Scalar coeff(int row, int col) const + inline const Scalar coeff(Index row, Index col) const { return m_matrix.coeff(row + m_startRow.value(), col + m_startCol.value()); } - inline Scalar& coeffRef(int index) + inline Scalar& coeffRef(Index index) { - return m_matrix.const_cast_derived() - .coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), - m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); + return m_matrix.coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), + m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); } - inline const Scalar coeff(int index) const + inline const Scalar coeff(Index index) const { - return m_matrix - .coeff(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), - m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); + return m_matrix.coeff(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), + m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); } - - inline const _MatrixTypeNested& nestedExpression() const { return m_matrix; } - - class InnerIterator : public _MatrixTypeNested::InnerIterator - { - typedef typename _MatrixTypeNested::InnerIterator Base; - const BlockType& m_block; - Index m_end; - public: - - EIGEN_STRONG_INLINE InnerIterator(const BlockType& block, Index outer) - : Base(block.derived().nestedExpression(), outer + (IsRowMajor ? block.m_startRow.value() : block.m_startCol.value())), - m_block(block), - m_end(IsRowMajor ? block.m_startCol.value()+block.m_blockCols.value() : block.m_startRow.value()+block.m_blockRows.value()) - { - while( (Base::operator bool()) && (Base::index() < (IsRowMajor ? m_block.m_startCol.value() : m_block.m_startRow.value())) ) - Base::operator++(); - } - inline Index index() const { return Base::index() - (IsRowMajor ? m_block.m_startCol.value() : m_block.m_startRow.value()); } - inline Index outer() const { return Base::outer() - (IsRowMajor ? m_block.m_startRow.value() : m_block.m_startCol.value()); } - inline Index row() const { return Base::row() - m_block.m_startRow.value(); } - inline Index col() const { return Base::col() - m_block.m_startCol.value(); } - - inline operator bool() const { return Base::operator bool() && Base::index() < m_end; } - }; - class ReverseInnerIterator : public _MatrixTypeNested::ReverseInnerIterator - { - typedef typename _MatrixTypeNested::ReverseInnerIterator Base; - const BlockType& m_block; - Index m_begin; - public: - - EIGEN_STRONG_INLINE ReverseInnerIterator(const BlockType& block, Index outer) - : Base(block.derived().nestedExpression(), outer + (IsRowMajor ? block.m_startRow.value() : block.m_startCol.value())), - m_block(block), - m_begin(IsRowMajor ? block.m_startCol.value() : block.m_startRow.value()) - { - while( (Base::operator bool()) && (Base::index() >= (IsRowMajor ? m_block.m_startCol.value()+block.m_blockCols.value() : m_block.m_startRow.value()+block.m_blockRows.value())) ) - Base::operator--(); - } + inline const XprType& nestedExpression() const { return m_matrix; } + inline XprType& nestedExpression() { return m_matrix; } + Index startRow() const { return m_startRow.value(); } + Index startCol() const { return m_startCol.value(); } + Index blockRows() const { return m_blockRows.value(); } + Index blockCols() const { return m_blockCols.value(); } - inline Index index() const { return Base::index() - (IsRowMajor ? m_block.m_startCol.value() : m_block.m_startRow.value()); } - inline Index outer() const { return Base::outer() - (IsRowMajor ? m_block.m_startRow.value() : m_block.m_startCol.value()); } - inline Index row() const { return Base::row() - m_block.m_startRow.value(); } - inline Index col() const { return Base::col() - m_block.m_startCol.value(); } - - inline operator bool() const { return Base::operator bool() && Base::index() >= m_begin; } - }; protected: - friend class InnerIterator; - friend class ReverseInnerIterator; - - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl) +// friend class internal::GenericSparseBlockInnerIteratorImpl; + friend struct internal::unary_evaluator, internal::IteratorBased, Scalar >; - typename XprType::Nested m_matrix; + Index nonZeros() const { return Dynamic; } + + typename internal::ref_selector::non_const_type m_matrix; const internal::variable_if_dynamic m_startRow; const internal::variable_if_dynamic m_startCol; const internal::variable_if_dynamic m_blockRows; const internal::variable_if_dynamic m_blockCols; + protected: + // Disable assignment with clear error message. + // Note that simply removing operator= yields compilation errors with ICC+MSVC + template + BlockImpl& operator=(const T&) + { + EIGEN_STATIC_ASSERT(sizeof(T)==0, THIS_SPARSE_BLOCK_SUBEXPRESSION_IS_READ_ONLY); + return *this; + } + }; +namespace internal { + +template +struct unary_evaluator, IteratorBased > + : public evaluator_base > +{ + class InnerVectorInnerIterator; + class OuterVectorInnerIterator; + public: + typedef Block XprType; + typedef typename XprType::StorageIndex StorageIndex; + typedef typename XprType::Scalar Scalar; + + enum { + IsRowMajor = XprType::IsRowMajor, + + OuterVector = (BlockCols==1 && ArgType::IsRowMajor) + | // FIXME | instead of || to please GCC 4.4.0 stupid warning "suggest parentheses around &&". + // revert to || as soon as not needed anymore. + (BlockRows==1 && !ArgType::IsRowMajor), + + CoeffReadCost = evaluator::CoeffReadCost, + Flags = XprType::Flags + }; + + typedef typename internal::conditional::type InnerIterator; + + explicit unary_evaluator(const XprType& op) + : m_argImpl(op.nestedExpression()), m_block(op) + {} + + inline Index nonZerosEstimate() const { + Index nnz = m_block.nonZeros(); + if(nnz<0) + return m_argImpl.nonZerosEstimate() * m_block.size() / m_block.nestedExpression().size(); + return nnz; + } + + protected: + typedef typename evaluator::InnerIterator EvalIterator; + + evaluator m_argImpl; + const XprType &m_block; +}; + +template +class unary_evaluator, IteratorBased>::InnerVectorInnerIterator + : public EvalIterator +{ + enum { IsRowMajor = unary_evaluator::IsRowMajor }; + const XprType& m_block; + Index m_end; +public: + + EIGEN_STRONG_INLINE InnerVectorInnerIterator(const unary_evaluator& aEval, Index outer) + : EvalIterator(aEval.m_argImpl, outer + (IsRowMajor ? aEval.m_block.startRow() : aEval.m_block.startCol())), + m_block(aEval.m_block), + m_end(IsRowMajor ? aEval.m_block.startCol()+aEval.m_block.blockCols() : aEval.m_block.startRow()+aEval.m_block.blockRows()) + { + while( (EvalIterator::operator bool()) && (EvalIterator::index() < (IsRowMajor ? m_block.startCol() : m_block.startRow())) ) + EvalIterator::operator++(); + } + + inline StorageIndex index() const { return EvalIterator::index() - convert_index(IsRowMajor ? m_block.startCol() : m_block.startRow()); } + inline Index outer() const { return EvalIterator::outer() - (IsRowMajor ? m_block.startRow() : m_block.startCol()); } + inline Index row() const { return EvalIterator::row() - m_block.startRow(); } + inline Index col() const { return EvalIterator::col() - m_block.startCol(); } + + inline operator bool() const { return EvalIterator::operator bool() && EvalIterator::index() < m_end; } +}; + +template +class unary_evaluator, IteratorBased>::OuterVectorInnerIterator +{ + enum { IsRowMajor = unary_evaluator::IsRowMajor }; + const unary_evaluator& m_eval; + Index m_outerPos; + const Index m_innerIndex; + Index m_end; + EvalIterator m_it; +public: + + EIGEN_STRONG_INLINE OuterVectorInnerIterator(const unary_evaluator& aEval, Index outer) + : m_eval(aEval), + m_outerPos( (IsRowMajor ? aEval.m_block.startCol() : aEval.m_block.startRow()) ), + m_innerIndex(IsRowMajor ? aEval.m_block.startRow() : aEval.m_block.startCol()), + m_end(IsRowMajor ? aEval.m_block.startCol()+aEval.m_block.blockCols() : aEval.m_block.startRow()+aEval.m_block.blockRows()), + m_it(m_eval.m_argImpl, m_outerPos) + { + EIGEN_UNUSED_VARIABLE(outer); + eigen_assert(outer==0); + + while(m_it && m_it.index() < m_innerIndex) ++m_it; + if((!m_it) || (m_it.index()!=m_innerIndex)) + ++(*this); + } + + inline StorageIndex index() const { return convert_index(m_outerPos - (IsRowMajor ? m_eval.m_block.startCol() : m_eval.m_block.startRow())); } + inline Index outer() const { return 0; } + inline Index row() const { return IsRowMajor ? 0 : index(); } + inline Index col() const { return IsRowMajor ? index() : 0; } + + inline Scalar value() const { return m_it.value(); } + inline Scalar& valueRef() { return m_it.valueRef(); } + + inline OuterVectorInnerIterator& operator++() + { + // search next non-zero entry + while(++m_outerPos +struct unary_evaluator,BlockRows,BlockCols,true>, IteratorBased> + : evaluator,BlockRows,BlockCols,true> > > +{ + typedef Block,BlockRows,BlockCols,true> XprType; + typedef evaluator > Base; + explicit unary_evaluator(const XprType &xpr) : Base(xpr) {} +}; + +template +struct unary_evaluator,BlockRows,BlockCols,true>, IteratorBased> + : evaluator,BlockRows,BlockCols,true> > > +{ + typedef Block,BlockRows,BlockCols,true> XprType; + typedef evaluator > Base; + explicit unary_evaluator(const XprType &xpr) : Base(xpr) {} +}; + +} // end namespace internal + + } // end namespace Eigen #endif // EIGEN_SPARSE_BLOCK_H diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseColEtree.h b/libs/eigen3/Eigen/src/SparseCore/SparseColEtree.h index f8745f461..ebe02d1ab 100644 --- a/libs/eigen3/Eigen/src/SparseCore/SparseColEtree.h +++ b/libs/eigen3/Eigen/src/SparseCore/SparseColEtree.h @@ -58,30 +58,29 @@ Index etree_find (Index i, IndexVector& pp) * \param perm The permutation to apply to the column of \b mat */ template -int coletree(const MatrixType& mat, IndexVector& parent, IndexVector& firstRowElt, typename MatrixType::Index *perm=0) +int coletree(const MatrixType& mat, IndexVector& parent, IndexVector& firstRowElt, typename MatrixType::StorageIndex *perm=0) { - typedef typename MatrixType::Index Index; - Index nc = mat.cols(); // Number of columns - Index m = mat.rows(); - Index diagSize = (std::min)(nc,m); + typedef typename MatrixType::StorageIndex StorageIndex; + StorageIndex nc = convert_index(mat.cols()); // Number of columns + StorageIndex m = convert_index(mat.rows()); + StorageIndex diagSize = (std::min)(nc,m); IndexVector root(nc); // root of subtree of etree root.setZero(); IndexVector pp(nc); // disjoint sets pp.setZero(); // Initialize disjoint sets parent.resize(mat.cols()); //Compute first nonzero column in each row - Index row,col; firstRowElt.resize(m); firstRowElt.setConstant(nc); firstRowElt.segment(0, diagSize).setLinSpaced(diagSize, 0, diagSize-1); bool found_diag; - for (col = 0; col < nc; col++) + for (StorageIndex col = 0; col < nc; col++) { - Index pcol = col; + StorageIndex pcol = col; if(perm) pcol = perm[col]; for (typename MatrixType::InnerIterator it(mat, pcol); it; ++it) { - row = it.row(); + Index row = it.row(); firstRowElt(row) = (std::min)(firstRowElt(row), col); } } @@ -89,8 +88,8 @@ int coletree(const MatrixType& mat, IndexVector& parent, IndexVector& firstRowEl except use (firstRowElt[r],c) in place of an edge (r,c) of A. Thus each row clique in A'*A is replaced by a star centered at its first vertex, which has the same fill. */ - Index rset, cset, rroot; - for (col = 0; col < nc; col++) + StorageIndex rset, cset, rroot; + for (StorageIndex col = 0; col < nc; col++) { found_diag = col>=m; pp(col) = col; @@ -99,7 +98,7 @@ int coletree(const MatrixType& mat, IndexVector& parent, IndexVector& firstRowEl parent(col) = nc; /* The diagonal element is treated here even if it does not exist in the matrix * hence the loop is executed once more */ - Index pcol = col; + StorageIndex pcol = col; if(perm) pcol = perm[col]; for (typename MatrixType::InnerIterator it(mat, pcol); it||!found_diag; ++it) { // A sequence of interleaved find and union is performed @@ -107,7 +106,7 @@ int coletree(const MatrixType& mat, IndexVector& parent, IndexVector& firstRowEl if(it) i = it.index(); if (i == col) found_diag = true; - row = firstRowElt(i); + StorageIndex row = firstRowElt(i); if (row >= col) continue; rset = internal::etree_find(row, pp); // Find the name of the set containing row rroot = root(rset); @@ -127,10 +126,11 @@ int coletree(const MatrixType& mat, IndexVector& parent, IndexVector& firstRowEl * Depth-first search from vertex n. No recursion. * This routine was contributed by Cédric Doucet, CEDRAT Group, Meylan, France. */ -template -void nr_etdfs (Index n, IndexVector& parent, IndexVector& first_kid, IndexVector& next_kid, IndexVector& post, Index postnum) +template +void nr_etdfs (typename IndexVector::Scalar n, IndexVector& parent, IndexVector& first_kid, IndexVector& next_kid, IndexVector& post, typename IndexVector::Scalar postnum) { - Index current = n, first, next; + typedef typename IndexVector::Scalar StorageIndex; + StorageIndex current = n, first, next; while (postnum != n) { // No kid for the current node @@ -174,22 +174,22 @@ void nr_etdfs (Index n, IndexVector& parent, IndexVector& first_kid, IndexVector * \param parent Input tree * \param post postordered tree */ -template -void treePostorder(Index n, IndexVector& parent, IndexVector& post) +template +void treePostorder(typename IndexVector::Scalar n, IndexVector& parent, IndexVector& post) { + typedef typename IndexVector::Scalar StorageIndex; IndexVector first_kid, next_kid; // Linked list of children - Index postnum; + StorageIndex postnum; // Allocate storage for working arrays and results first_kid.resize(n+1); next_kid.setZero(n+1); post.setZero(n+1); // Set up structure describing children - Index v, dad; first_kid.setConstant(-1); - for (v = n-1; v >= 0; v--) + for (StorageIndex v = n-1; v >= 0; v--) { - dad = parent(v); + StorageIndex dad = parent(v); next_kid(v) = first_kid(dad); first_kid(dad) = v; } diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseCompressedBase.h b/libs/eigen3/Eigen/src/SparseCore/SparseCompressedBase.h new file mode 100644 index 000000000..5ccb46656 --- /dev/null +++ b/libs/eigen3/Eigen/src/SparseCore/SparseCompressedBase.h @@ -0,0 +1,341 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSE_COMPRESSED_BASE_H +#define EIGEN_SPARSE_COMPRESSED_BASE_H + +namespace Eigen { + +template class SparseCompressedBase; + +namespace internal { + +template +struct traits > : traits +{}; + +} // end namespace internal + +/** \ingroup SparseCore_Module + * \class SparseCompressedBase + * \brief Common base class for sparse [compressed]-{row|column}-storage format. + * + * This class defines the common interface for all derived classes implementing the compressed sparse storage format, such as: + * - SparseMatrix + * - Ref + * - Map + * + */ +template +class SparseCompressedBase + : public SparseMatrixBase +{ + public: + typedef SparseMatrixBase Base; + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseCompressedBase) + using Base::operator=; + using Base::IsRowMajor; + + class InnerIterator; + class ReverseInnerIterator; + + protected: + typedef typename Base::IndexVector IndexVector; + Eigen::Map innerNonZeros() { return Eigen::Map(innerNonZeroPtr(), isCompressed()?0:derived().outerSize()); } + const Eigen::Map innerNonZeros() const { return Eigen::Map(innerNonZeroPtr(), isCompressed()?0:derived().outerSize()); } + + public: + + /** \returns the number of non zero coefficients */ + inline Index nonZeros() const + { + if(Derived::IsVectorAtCompileTime && outerIndexPtr()==0) + return derived().nonZeros(); + else if(isCompressed()) + return outerIndexPtr()[derived().outerSize()]-outerIndexPtr()[0]; + else if(derived().outerSize()==0) + return 0; + else + return innerNonZeros().sum(); + } + + /** \returns a const pointer to the array of values. + * This function is aimed at interoperability with other libraries. + * \sa innerIndexPtr(), outerIndexPtr() */ + inline const Scalar* valuePtr() const { return derived().valuePtr(); } + /** \returns a non-const pointer to the array of values. + * This function is aimed at interoperability with other libraries. + * \sa innerIndexPtr(), outerIndexPtr() */ + inline Scalar* valuePtr() { return derived().valuePtr(); } + + /** \returns a const pointer to the array of inner indices. + * This function is aimed at interoperability with other libraries. + * \sa valuePtr(), outerIndexPtr() */ + inline const StorageIndex* innerIndexPtr() const { return derived().innerIndexPtr(); } + /** \returns a non-const pointer to the array of inner indices. + * This function is aimed at interoperability with other libraries. + * \sa valuePtr(), outerIndexPtr() */ + inline StorageIndex* innerIndexPtr() { return derived().innerIndexPtr(); } + + /** \returns a const pointer to the array of the starting positions of the inner vectors. + * This function is aimed at interoperability with other libraries. + * \warning it returns the null pointer 0 for SparseVector + * \sa valuePtr(), innerIndexPtr() */ + inline const StorageIndex* outerIndexPtr() const { return derived().outerIndexPtr(); } + /** \returns a non-const pointer to the array of the starting positions of the inner vectors. + * This function is aimed at interoperability with other libraries. + * \warning it returns the null pointer 0 for SparseVector + * \sa valuePtr(), innerIndexPtr() */ + inline StorageIndex* outerIndexPtr() { return derived().outerIndexPtr(); } + + /** \returns a const pointer to the array of the number of non zeros of the inner vectors. + * This function is aimed at interoperability with other libraries. + * \warning it returns the null pointer 0 in compressed mode */ + inline const StorageIndex* innerNonZeroPtr() const { return derived().innerNonZeroPtr(); } + /** \returns a non-const pointer to the array of the number of non zeros of the inner vectors. + * This function is aimed at interoperability with other libraries. + * \warning it returns the null pointer 0 in compressed mode */ + inline StorageIndex* innerNonZeroPtr() { return derived().innerNonZeroPtr(); } + + /** \returns whether \c *this is in compressed form. */ + inline bool isCompressed() const { return innerNonZeroPtr()==0; } + + /** \returns a read-only view of the stored coefficients as a 1D array expression. + * + * \warning this method is for \b compressed \b storage \b only, and it will trigger an assertion otherwise. + * + * \sa valuePtr(), isCompressed() */ + const Map > coeffs() const { eigen_assert(isCompressed()); return Array::Map(valuePtr(),nonZeros()); } + + /** \returns a read-write view of the stored coefficients as a 1D array expression + * + * \warning this method is for \b compressed \b storage \b only, and it will trigger an assertion otherwise. + * + * Here is an example: + * \include SparseMatrix_coeffs.cpp + * and the output is: + * \include SparseMatrix_coeffs.out + * + * \sa valuePtr(), isCompressed() */ + Map > coeffs() { eigen_assert(isCompressed()); return Array::Map(valuePtr(),nonZeros()); } + + protected: + /** Default constructor. Do nothing. */ + SparseCompressedBase() {} + private: + template explicit SparseCompressedBase(const SparseCompressedBase&); +}; + +template +class SparseCompressedBase::InnerIterator +{ + public: + InnerIterator() + : m_values(0), m_indices(0), m_outer(0), m_id(0), m_end(0) + {} + + InnerIterator(const InnerIterator& other) + : m_values(other.m_values), m_indices(other.m_indices), m_outer(other.m_outer), m_id(other.m_id), m_end(other.m_end) + {} + + InnerIterator& operator=(const InnerIterator& other) + { + m_values = other.m_values; + m_indices = other.m_indices; + const_cast(m_outer).setValue(other.m_outer.value()); + m_id = other.m_id; + m_end = other.m_end; + return *this; + } + + InnerIterator(const SparseCompressedBase& mat, Index outer) + : m_values(mat.valuePtr()), m_indices(mat.innerIndexPtr()), m_outer(outer) + { + if(Derived::IsVectorAtCompileTime && mat.outerIndexPtr()==0) + { + m_id = 0; + m_end = mat.nonZeros(); + } + else + { + m_id = mat.outerIndexPtr()[outer]; + if(mat.isCompressed()) + m_end = mat.outerIndexPtr()[outer+1]; + else + m_end = m_id + mat.innerNonZeroPtr()[outer]; + } + } + + explicit InnerIterator(const SparseCompressedBase& mat) + : m_values(mat.valuePtr()), m_indices(mat.innerIndexPtr()), m_outer(0), m_id(0), m_end(mat.nonZeros()) + { + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived); + } + + explicit InnerIterator(const internal::CompressedStorage& data) + : m_values(data.valuePtr()), m_indices(data.indexPtr()), m_outer(0), m_id(0), m_end(data.size()) + { + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived); + } + + inline InnerIterator& operator++() { m_id++; return *this; } + + inline const Scalar& value() const { return m_values[m_id]; } + inline Scalar& valueRef() { return const_cast(m_values[m_id]); } + + inline StorageIndex index() const { return m_indices[m_id]; } + inline Index outer() const { return m_outer.value(); } + inline Index row() const { return IsRowMajor ? m_outer.value() : index(); } + inline Index col() const { return IsRowMajor ? index() : m_outer.value(); } + + inline operator bool() const { return (m_id < m_end); } + + protected: + const Scalar* m_values; + const StorageIndex* m_indices; + typedef internal::variable_if_dynamic OuterType; + const OuterType m_outer; + Index m_id; + Index m_end; + private: + // If you get here, then you're not using the right InnerIterator type, e.g.: + // SparseMatrix A; + // SparseMatrix::InnerIterator it(A,0); + template InnerIterator(const SparseMatrixBase&, Index outer); +}; + +template +class SparseCompressedBase::ReverseInnerIterator +{ + public: + ReverseInnerIterator(const SparseCompressedBase& mat, Index outer) + : m_values(mat.valuePtr()), m_indices(mat.innerIndexPtr()), m_outer(outer) + { + if(Derived::IsVectorAtCompileTime && mat.outerIndexPtr()==0) + { + m_start = 0; + m_id = mat.nonZeros(); + } + else + { + m_start = mat.outerIndexPtr()[outer]; + if(mat.isCompressed()) + m_id = mat.outerIndexPtr()[outer+1]; + else + m_id = m_start + mat.innerNonZeroPtr()[outer]; + } + } + + explicit ReverseInnerIterator(const SparseCompressedBase& mat) + : m_values(mat.valuePtr()), m_indices(mat.innerIndexPtr()), m_outer(0), m_start(0), m_id(mat.nonZeros()) + { + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived); + } + + explicit ReverseInnerIterator(const internal::CompressedStorage& data) + : m_values(data.valuePtr()), m_indices(data.indexPtr()), m_outer(0), m_start(0), m_id(data.size()) + { + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived); + } + + inline ReverseInnerIterator& operator--() { --m_id; return *this; } + + inline const Scalar& value() const { return m_values[m_id-1]; } + inline Scalar& valueRef() { return const_cast(m_values[m_id-1]); } + + inline StorageIndex index() const { return m_indices[m_id-1]; } + inline Index outer() const { return m_outer.value(); } + inline Index row() const { return IsRowMajor ? m_outer.value() : index(); } + inline Index col() const { return IsRowMajor ? index() : m_outer.value(); } + + inline operator bool() const { return (m_id > m_start); } + + protected: + const Scalar* m_values; + const StorageIndex* m_indices; + typedef internal::variable_if_dynamic OuterType; + const OuterType m_outer; + Index m_start; + Index m_id; +}; + +namespace internal { + +template +struct evaluator > + : evaluator_base +{ + typedef typename Derived::Scalar Scalar; + typedef typename Derived::InnerIterator InnerIterator; + + enum { + CoeffReadCost = NumTraits::ReadCost, + Flags = Derived::Flags + }; + + evaluator() : m_matrix(0), m_zero(0) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + explicit evaluator(const Derived &mat) : m_matrix(&mat), m_zero(0) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + inline Index nonZerosEstimate() const { + return m_matrix->nonZeros(); + } + + operator Derived&() { return m_matrix->const_cast_derived(); } + operator const Derived&() const { return *m_matrix; } + + typedef typename DenseCoeffsBase::CoeffReturnType CoeffReturnType; + const Scalar& coeff(Index row, Index col) const + { + Index p = find(row,col); + + if(p==Dynamic) + return m_zero; + else + return m_matrix->const_cast_derived().valuePtr()[p]; + } + + Scalar& coeffRef(Index row, Index col) + { + Index p = find(row,col); + eigen_assert(p!=Dynamic && "written coefficient does not exist"); + return m_matrix->const_cast_derived().valuePtr()[p]; + } + +protected: + + Index find(Index row, Index col) const + { + eigen_internal_assert(row>=0 && rowrows() && col>=0 && colcols()); + + const Index outer = Derived::IsRowMajor ? row : col; + const Index inner = Derived::IsRowMajor ? col : row; + + Index start = m_matrix->outerIndexPtr()[outer]; + Index end = m_matrix->isCompressed() ? m_matrix->outerIndexPtr()[outer+1] : m_matrix->outerIndexPtr()[outer] + m_matrix->innerNonZeroPtr()[outer]; + eigen_assert(end>=start && "you are using a non finalized sparse matrix or written coefficient does not exist"); + const Index p = std::lower_bound(m_matrix->innerIndexPtr()+start, m_matrix->innerIndexPtr()+end,inner) - m_matrix->innerIndexPtr(); + + return ((pinnerIndexPtr()[p]==inner)) ? p : Dynamic; + } + + const Derived *m_matrix; + const Scalar m_zero; +}; + +} + +} // end namespace Eigen + +#endif // EIGEN_SPARSE_COMPRESSED_BASE_H diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h b/libs/eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h index 60ca7690c..e315e3550 100644 --- a/libs/eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h +++ b/libs/eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -28,89 +28,57 @@ namespace Eigen { // generic sparse // 4 - dense op dense product dense // generic dense - -namespace internal { - -template<> struct promote_storage_type -{ typedef Sparse ret; }; - -template<> struct promote_storage_type -{ typedef Sparse ret; }; - -template::StorageKind, - typename _RhsStorageMode = typename traits::StorageKind> -class sparse_cwise_binary_op_inner_iterator_selector; - -} // end namespace internal +// +// TODO to ease compiler job, we could specialize product/quotient with a scalar +// and fallback to cwise-unary evaluator using bind1st_op and bind2nd_op. template class CwiseBinaryOpImpl : public SparseMatrixBase > { public: - class InnerIterator; - class ReverseInnerIterator; typedef CwiseBinaryOp Derived; + typedef SparseMatrixBase Base; EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) CwiseBinaryOpImpl() { - typedef typename internal::traits::StorageKind LhsStorageKind; - typedef typename internal::traits::StorageKind RhsStorageKind; EIGEN_STATIC_ASSERT(( - (!internal::is_same::value) - || ((Lhs::Flags&RowMajorBit) == (Rhs::Flags&RowMajorBit))), + (!internal::is_same::StorageKind, + typename internal::traits::StorageKind>::value) + || ((internal::evaluator::Flags&RowMajorBit) == (internal::evaluator::Flags&RowMajorBit))), THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH); } }; -template -class CwiseBinaryOpImpl::InnerIterator - : public internal::sparse_cwise_binary_op_inner_iterator_selector::InnerIterator> -{ - public: - typedef typename Lhs::Index Index; - typedef internal::sparse_cwise_binary_op_inner_iterator_selector< - BinaryOp,Lhs,Rhs, InnerIterator> Base; - - // NOTE: we have to prefix Index by "typename Lhs::" to avoid an ICE with VC11 - EIGEN_STRONG_INLINE InnerIterator(const CwiseBinaryOpImpl& binOp, typename Lhs::Index outer) - : Base(binOp.derived(),outer) - {} -}; - -/*************************************************************************** -* Implementation of inner-iterators -***************************************************************************/ - -// template struct internal::func_is_conjunction { enum { ret = false }; }; -// template struct internal::func_is_conjunction > { enum { ret = true }; }; - -// TODO generalize the internal::scalar_product_op specialization to all conjunctions if any ! - namespace internal { -// sparse - sparse (generic) -template -class sparse_cwise_binary_op_inner_iterator_selector -{ - typedef CwiseBinaryOp CwiseBinaryXpr; - typedef typename traits::Scalar Scalar; - typedef typename traits::_LhsNested _LhsNested; - typedef typename traits::_RhsNested _RhsNested; - typedef typename _LhsNested::InnerIterator LhsIterator; - typedef typename _RhsNested::InnerIterator RhsIterator; - typedef typename Lhs::Index Index; + +// Generic "sparse OP sparse" +template struct binary_sparse_evaluator; +template +struct binary_evaluator, IteratorBased, IteratorBased> + : evaluator_base > +{ +protected: + typedef typename evaluator::InnerIterator LhsIterator; + typedef typename evaluator::InnerIterator RhsIterator; + typedef CwiseBinaryOp XprType; + typedef typename traits::Scalar Scalar; + typedef typename XprType::StorageIndex StorageIndex; +public: + + class InnerIterator + { public: - - EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) - : m_lhsIter(xpr.lhs(),outer), m_rhsIter(xpr.rhs(),outer), m_functor(xpr.functor()) + + EIGEN_STRONG_INLINE InnerIterator(const binary_evaluator& aEval, Index outer) + : m_lhsIter(aEval.m_lhsImpl,outer), m_rhsIter(aEval.m_rhsImpl,outer), m_functor(aEval.m_functor) { this->operator++(); } - EIGEN_STRONG_INLINE Derived& operator++() + EIGEN_STRONG_INLINE InnerIterator& operator++() { if (m_lhsIter && m_rhsIter && (m_lhsIter.index() == m_rhsIter.index())) { @@ -136,12 +104,13 @@ class sparse_cwise_binary_op_inner_iterator_selector(this); + return *this; } EIGEN_STRONG_INLINE Scalar value() const { return m_value; } - EIGEN_STRONG_INLINE Index index() const { return m_id; } + EIGEN_STRONG_INLINE StorageIndex index() const { return m_id; } + EIGEN_STRONG_INLINE Index outer() const { return m_lhsIter.outer(); } EIGEN_STRONG_INLINE Index row() const { return Lhs::IsRowMajor ? m_lhsIter.row() : index(); } EIGEN_STRONG_INLINE Index col() const { return Lhs::IsRowMajor ? index() : m_lhsIter.col(); } @@ -152,25 +121,303 @@ class sparse_cwise_binary_op_inner_iterator_selector::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost, + Flags = XprType::Flags + }; + + explicit binary_evaluator(const XprType& xpr) + : m_functor(xpr.functor()), + m_lhsImpl(xpr.lhs()), + m_rhsImpl(xpr.rhs()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + inline Index nonZerosEstimate() const { + return m_lhsImpl.nonZerosEstimate() + m_rhsImpl.nonZerosEstimate(); + } + +protected: + const BinaryOp m_functor; + evaluator m_lhsImpl; + evaluator m_rhsImpl; }; -// sparse - sparse (product) -template -class sparse_cwise_binary_op_inner_iterator_selector, Lhs, Rhs, Derived, Sparse, Sparse> +// dense op sparse +template +struct binary_evaluator, IndexBased, IteratorBased> + : evaluator_base > { - typedef scalar_product_op BinaryFunc; - typedef CwiseBinaryOp CwiseBinaryXpr; - typedef typename CwiseBinaryXpr::Scalar Scalar; - typedef typename traits::_LhsNested _LhsNested; - typedef typename _LhsNested::InnerIterator LhsIterator; - typedef typename traits::_RhsNested _RhsNested; - typedef typename _RhsNested::InnerIterator RhsIterator; - typedef typename Lhs::Index Index; +protected: + typedef typename evaluator::InnerIterator RhsIterator; + typedef CwiseBinaryOp XprType; + typedef typename traits::Scalar Scalar; + typedef typename XprType::StorageIndex StorageIndex; +public: + + class InnerIterator + { + enum { IsRowMajor = (int(Rhs::Flags)&RowMajorBit)==RowMajorBit }; public: - EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) - : m_lhsIter(xpr.lhs(),outer), m_rhsIter(xpr.rhs(),outer), m_functor(xpr.functor()) + EIGEN_STRONG_INLINE InnerIterator(const binary_evaluator& aEval, Index outer) + : m_lhsEval(aEval.m_lhsImpl), m_rhsIter(aEval.m_rhsImpl,outer), m_functor(aEval.m_functor), m_value(0), m_id(-1), m_innerSize(aEval.m_expr.rhs().innerSize()) + { + this->operator++(); + } + + EIGEN_STRONG_INLINE InnerIterator& operator++() + { + ++m_id; + if(m_id &m_lhsEval; + RhsIterator m_rhsIter; + const BinaryOp& m_functor; + Scalar m_value; + StorageIndex m_id; + StorageIndex m_innerSize; + }; + + + enum { + CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost, + // Expose storage order of the sparse expression + Flags = (XprType::Flags & ~RowMajorBit) | (int(Rhs::Flags)&RowMajorBit) + }; + + explicit binary_evaluator(const XprType& xpr) + : m_functor(xpr.functor()), + m_lhsImpl(xpr.lhs()), + m_rhsImpl(xpr.rhs()), + m_expr(xpr) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + inline Index nonZerosEstimate() const { + return m_expr.size(); + } + +protected: + const BinaryOp m_functor; + evaluator m_lhsImpl; + evaluator m_rhsImpl; + const XprType &m_expr; +}; + +// sparse op dense +template +struct binary_evaluator, IteratorBased, IndexBased> + : evaluator_base > +{ +protected: + typedef typename evaluator::InnerIterator LhsIterator; + typedef CwiseBinaryOp XprType; + typedef typename traits::Scalar Scalar; + typedef typename XprType::StorageIndex StorageIndex; +public: + + class InnerIterator + { + enum { IsRowMajor = (int(Lhs::Flags)&RowMajorBit)==RowMajorBit }; + public: + + EIGEN_STRONG_INLINE InnerIterator(const binary_evaluator& aEval, Index outer) + : m_lhsIter(aEval.m_lhsImpl,outer), m_rhsEval(aEval.m_rhsImpl), m_functor(aEval.m_functor), m_value(0), m_id(-1), m_innerSize(aEval.m_expr.lhs().innerSize()) + { + this->operator++(); + } + + EIGEN_STRONG_INLINE InnerIterator& operator++() + { + ++m_id; + if(m_id &m_rhsEval; + const BinaryOp& m_functor; + Scalar m_value; + StorageIndex m_id; + StorageIndex m_innerSize; + }; + + + enum { + CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost, + // Expose storage order of the sparse expression + Flags = (XprType::Flags & ~RowMajorBit) | (int(Lhs::Flags)&RowMajorBit) + }; + + explicit binary_evaluator(const XprType& xpr) + : m_functor(xpr.functor()), + m_lhsImpl(xpr.lhs()), + m_rhsImpl(xpr.rhs()), + m_expr(xpr) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + inline Index nonZerosEstimate() const { + return m_expr.size(); + } + +protected: + const BinaryOp m_functor; + evaluator m_lhsImpl; + evaluator m_rhsImpl; + const XprType &m_expr; +}; + +template::Kind, + typename RhsKind = typename evaluator_traits::Kind, + typename LhsScalar = typename traits::Scalar, + typename RhsScalar = typename traits::Scalar> struct sparse_conjunction_evaluator; + +// "sparse .* sparse" +template +struct binary_evaluator, Lhs, Rhs>, IteratorBased, IteratorBased> + : sparse_conjunction_evaluator, Lhs, Rhs> > +{ + typedef CwiseBinaryOp, Lhs, Rhs> XprType; + typedef sparse_conjunction_evaluator Base; + explicit binary_evaluator(const XprType& xpr) : Base(xpr) {} +}; +// "dense .* sparse" +template +struct binary_evaluator, Lhs, Rhs>, IndexBased, IteratorBased> + : sparse_conjunction_evaluator, Lhs, Rhs> > +{ + typedef CwiseBinaryOp, Lhs, Rhs> XprType; + typedef sparse_conjunction_evaluator Base; + explicit binary_evaluator(const XprType& xpr) : Base(xpr) {} +}; +// "sparse .* dense" +template +struct binary_evaluator, Lhs, Rhs>, IteratorBased, IndexBased> + : sparse_conjunction_evaluator, Lhs, Rhs> > +{ + typedef CwiseBinaryOp, Lhs, Rhs> XprType; + typedef sparse_conjunction_evaluator Base; + explicit binary_evaluator(const XprType& xpr) : Base(xpr) {} +}; + +// "sparse ./ dense" +template +struct binary_evaluator, Lhs, Rhs>, IteratorBased, IndexBased> + : sparse_conjunction_evaluator, Lhs, Rhs> > +{ + typedef CwiseBinaryOp, Lhs, Rhs> XprType; + typedef sparse_conjunction_evaluator Base; + explicit binary_evaluator(const XprType& xpr) : Base(xpr) {} +}; + +// "sparse && sparse" +template +struct binary_evaluator, IteratorBased, IteratorBased> + : sparse_conjunction_evaluator > +{ + typedef CwiseBinaryOp XprType; + typedef sparse_conjunction_evaluator Base; + explicit binary_evaluator(const XprType& xpr) : Base(xpr) {} +}; +// "dense && sparse" +template +struct binary_evaluator, IndexBased, IteratorBased> + : sparse_conjunction_evaluator > +{ + typedef CwiseBinaryOp XprType; + typedef sparse_conjunction_evaluator Base; + explicit binary_evaluator(const XprType& xpr) : Base(xpr) {} +}; +// "sparse && dense" +template +struct binary_evaluator, IteratorBased, IndexBased> + : sparse_conjunction_evaluator > +{ + typedef CwiseBinaryOp XprType; + typedef sparse_conjunction_evaluator Base; + explicit binary_evaluator(const XprType& xpr) : Base(xpr) {} +}; + +// "sparse ^ sparse" +template +struct sparse_conjunction_evaluator + : evaluator_base +{ +protected: + typedef typename XprType::Functor BinaryOp; + typedef typename XprType::Lhs LhsArg; + typedef typename XprType::Rhs RhsArg; + typedef typename evaluator::InnerIterator LhsIterator; + typedef typename evaluator::InnerIterator RhsIterator; + typedef typename XprType::StorageIndex StorageIndex; + typedef typename traits::Scalar Scalar; +public: + + class InnerIterator + { + public: + + EIGEN_STRONG_INLINE InnerIterator(const sparse_conjunction_evaluator& aEval, Index outer) + : m_lhsIter(aEval.m_lhsImpl,outer), m_rhsIter(aEval.m_rhsImpl,outer), m_functor(aEval.m_functor) { while (m_lhsIter && m_rhsIter && (m_lhsIter.index() != m_rhsIter.index())) { @@ -181,7 +428,7 @@ class sparse_cwise_binary_op_inner_iterator_selector, Lhs, } } - EIGEN_STRONG_INLINE Derived& operator++() + EIGEN_STRONG_INLINE InnerIterator& operator++() { ++m_lhsIter; ++m_rhsIter; @@ -192,12 +439,13 @@ class sparse_cwise_binary_op_inner_iterator_selector, Lhs, else ++m_rhsIter; } - return *static_cast(this); + return *this; } - + EIGEN_STRONG_INLINE Scalar value() const { return m_functor(m_lhsIter.value(), m_rhsIter.value()); } - EIGEN_STRONG_INLINE Index index() const { return m_lhsIter.index(); } + EIGEN_STRONG_INLINE StorageIndex index() const { return m_lhsIter.index(); } + EIGEN_STRONG_INLINE Index outer() const { return m_lhsIter.outer(); } EIGEN_STRONG_INLINE Index row() const { return m_lhsIter.row(); } EIGEN_STRONG_INLINE Index col() const { return m_lhsIter.col(); } @@ -206,96 +454,205 @@ class sparse_cwise_binary_op_inner_iterator_selector, Lhs, protected: LhsIterator m_lhsIter; RhsIterator m_rhsIter; - const BinaryFunc& m_functor; + const BinaryOp& m_functor; + }; + + + enum { + CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost, + Flags = XprType::Flags + }; + + explicit sparse_conjunction_evaluator(const XprType& xpr) + : m_functor(xpr.functor()), + m_lhsImpl(xpr.lhs()), + m_rhsImpl(xpr.rhs()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + inline Index nonZerosEstimate() const { + return (std::min)(m_lhsImpl.nonZerosEstimate(), m_rhsImpl.nonZerosEstimate()); + } + +protected: + const BinaryOp m_functor; + evaluator m_lhsImpl; + evaluator m_rhsImpl; }; -// sparse - dense (product) -template -class sparse_cwise_binary_op_inner_iterator_selector, Lhs, Rhs, Derived, Sparse, Dense> +// "dense ^ sparse" +template +struct sparse_conjunction_evaluator + : evaluator_base { - typedef scalar_product_op BinaryFunc; - typedef CwiseBinaryOp CwiseBinaryXpr; - typedef typename CwiseBinaryXpr::Scalar Scalar; - typedef typename traits::_LhsNested _LhsNested; - typedef typename traits::RhsNested RhsNested; - typedef typename _LhsNested::InnerIterator LhsIterator; - typedef typename Lhs::Index Index; - enum { IsRowMajor = (int(Lhs::Flags)&RowMajorBit)==RowMajorBit }; - public: +protected: + typedef typename XprType::Functor BinaryOp; + typedef typename XprType::Lhs LhsArg; + typedef typename XprType::Rhs RhsArg; + typedef evaluator LhsEvaluator; + typedef typename evaluator::InnerIterator RhsIterator; + typedef typename XprType::StorageIndex StorageIndex; + typedef typename traits::Scalar Scalar; +public: + + class InnerIterator + { + enum { IsRowMajor = (int(RhsArg::Flags)&RowMajorBit)==RowMajorBit }; - EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) - : m_rhs(xpr.rhs()), m_lhsIter(xpr.lhs(),outer), m_functor(xpr.functor()), m_outer(outer) + public: + + EIGEN_STRONG_INLINE InnerIterator(const sparse_conjunction_evaluator& aEval, Index outer) + : m_lhsEval(aEval.m_lhsImpl), m_rhsIter(aEval.m_rhsImpl,outer), m_functor(aEval.m_functor), m_outer(outer) {} - EIGEN_STRONG_INLINE Derived& operator++() + EIGEN_STRONG_INLINE InnerIterator& operator++() { - ++m_lhsIter; - return *static_cast(this); + ++m_rhsIter; + return *this; } EIGEN_STRONG_INLINE Scalar value() const - { return m_functor(m_lhsIter.value(), - m_rhs.coeff(IsRowMajor?m_outer:m_lhsIter.index(),IsRowMajor?m_lhsIter.index():m_outer)); } + { return m_functor(m_lhsEval.coeff(IsRowMajor?m_outer:m_rhsIter.index(),IsRowMajor?m_rhsIter.index():m_outer), m_rhsIter.value()); } - EIGEN_STRONG_INLINE Index index() const { return m_lhsIter.index(); } - EIGEN_STRONG_INLINE Index row() const { return m_lhsIter.row(); } - EIGEN_STRONG_INLINE Index col() const { return m_lhsIter.col(); } - - EIGEN_STRONG_INLINE operator bool() const { return m_lhsIter; } + EIGEN_STRONG_INLINE StorageIndex index() const { return m_rhsIter.index(); } + EIGEN_STRONG_INLINE Index outer() const { return m_rhsIter.outer(); } + EIGEN_STRONG_INLINE Index row() const { return m_rhsIter.row(); } + EIGEN_STRONG_INLINE Index col() const { return m_rhsIter.col(); } + EIGEN_STRONG_INLINE operator bool() const { return m_rhsIter; } + protected: - RhsNested m_rhs; - LhsIterator m_lhsIter; - const BinaryFunc m_functor; + const LhsEvaluator &m_lhsEval; + RhsIterator m_rhsIter; + const BinaryOp& m_functor; const Index m_outer; + }; + + + enum { + CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost, + // Expose storage order of the sparse expression + Flags = (XprType::Flags & ~RowMajorBit) | (int(RhsArg::Flags)&RowMajorBit) + }; + + explicit sparse_conjunction_evaluator(const XprType& xpr) + : m_functor(xpr.functor()), + m_lhsImpl(xpr.lhs()), + m_rhsImpl(xpr.rhs()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + inline Index nonZerosEstimate() const { + return m_rhsImpl.nonZerosEstimate(); + } + +protected: + const BinaryOp m_functor; + evaluator m_lhsImpl; + evaluator m_rhsImpl; }; -// sparse - dense (product) -template -class sparse_cwise_binary_op_inner_iterator_selector, Lhs, Rhs, Derived, Dense, Sparse> +// "sparse ^ dense" +template +struct sparse_conjunction_evaluator + : evaluator_base { - typedef scalar_product_op BinaryFunc; - typedef CwiseBinaryOp CwiseBinaryXpr; - typedef typename CwiseBinaryXpr::Scalar Scalar; - typedef typename traits::_RhsNested _RhsNested; - typedef typename _RhsNested::InnerIterator RhsIterator; - typedef typename Lhs::Index Index; +protected: + typedef typename XprType::Functor BinaryOp; + typedef typename XprType::Lhs LhsArg; + typedef typename XprType::Rhs RhsArg; + typedef typename evaluator::InnerIterator LhsIterator; + typedef evaluator RhsEvaluator; + typedef typename XprType::StorageIndex StorageIndex; + typedef typename traits::Scalar Scalar; +public: + + class InnerIterator + { + enum { IsRowMajor = (int(LhsArg::Flags)&RowMajorBit)==RowMajorBit }; - enum { IsRowMajor = (int(Rhs::Flags)&RowMajorBit)==RowMajorBit }; public: - - EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) - : m_xpr(xpr), m_rhsIter(xpr.rhs(),outer), m_functor(xpr.functor()), m_outer(outer) + + EIGEN_STRONG_INLINE InnerIterator(const sparse_conjunction_evaluator& aEval, Index outer) + : m_lhsIter(aEval.m_lhsImpl,outer), m_rhsEval(aEval.m_rhsImpl), m_functor(aEval.m_functor), m_outer(outer) {} - EIGEN_STRONG_INLINE Derived& operator++() + EIGEN_STRONG_INLINE InnerIterator& operator++() { - ++m_rhsIter; - return *static_cast(this); + ++m_lhsIter; + return *this; } EIGEN_STRONG_INLINE Scalar value() const - { return m_functor(m_xpr.lhs().coeff(IsRowMajor?m_outer:m_rhsIter.index(),IsRowMajor?m_rhsIter.index():m_outer), m_rhsIter.value()); } - - EIGEN_STRONG_INLINE Index index() const { return m_rhsIter.index(); } - EIGEN_STRONG_INLINE Index row() const { return m_rhsIter.row(); } - EIGEN_STRONG_INLINE Index col() const { return m_rhsIter.col(); } + { return m_functor(m_lhsIter.value(), + m_rhsEval.coeff(IsRowMajor?m_outer:m_lhsIter.index(),IsRowMajor?m_lhsIter.index():m_outer)); } - EIGEN_STRONG_INLINE operator bool() const { return m_rhsIter; } + EIGEN_STRONG_INLINE StorageIndex index() const { return m_lhsIter.index(); } + EIGEN_STRONG_INLINE Index outer() const { return m_lhsIter.outer(); } + EIGEN_STRONG_INLINE Index row() const { return m_lhsIter.row(); } + EIGEN_STRONG_INLINE Index col() const { return m_lhsIter.col(); } + EIGEN_STRONG_INLINE operator bool() const { return m_lhsIter; } + protected: - const CwiseBinaryXpr& m_xpr; - RhsIterator m_rhsIter; - const BinaryFunc& m_functor; + LhsIterator m_lhsIter; + const evaluator &m_rhsEval; + const BinaryOp& m_functor; const Index m_outer; + }; + + + enum { + CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost, + // Expose storage order of the sparse expression + Flags = (XprType::Flags & ~RowMajorBit) | (int(LhsArg::Flags)&RowMajorBit) + }; + + explicit sparse_conjunction_evaluator(const XprType& xpr) + : m_functor(xpr.functor()), + m_lhsImpl(xpr.lhs()), + m_rhsImpl(xpr.rhs()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + inline Index nonZerosEstimate() const { + return m_lhsImpl.nonZerosEstimate(); + } + +protected: + const BinaryOp m_functor; + evaluator m_lhsImpl; + evaluator m_rhsImpl; }; -} // end namespace internal +} /*************************************************************************** * Implementation of SparseMatrixBase and SparseCwise functions/operators ***************************************************************************/ +template +template +Derived& SparseMatrixBase::operator+=(const EigenBase &other) +{ + call_assignment(derived(), other.derived(), internal::add_assign_op()); + return derived(); +} + +template +template +Derived& SparseMatrixBase::operator-=(const EigenBase &other) +{ + call_assignment(derived(), other.derived(), internal::assign_op()); + return derived(); +} + template template EIGEN_STRONG_INLINE Derived & @@ -314,10 +671,54 @@ SparseMatrixBase::operator+=(const SparseMatrixBase& othe template template -EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE +Derived& SparseMatrixBase::operator+=(const DiagonalBase& other) +{ + call_assignment_no_alias(derived(), other.derived(), internal::add_assign_op()); + return derived(); +} + +template +template +Derived& SparseMatrixBase::operator-=(const DiagonalBase& other) +{ + call_assignment_no_alias(derived(), other.derived(), internal::sub_assign_op()); + return derived(); +} + +template +template +EIGEN_STRONG_INLINE const typename SparseMatrixBase::template CwiseProductDenseReturnType::Type SparseMatrixBase::cwiseProduct(const MatrixBase &other) const { - return EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE(derived(), other.derived()); + return typename CwiseProductDenseReturnType::Type(derived(), other.derived()); +} + +template +EIGEN_STRONG_INLINE const CwiseBinaryOp, const DenseDerived, const SparseDerived> +operator+(const MatrixBase &a, const SparseMatrixBase &b) +{ + return CwiseBinaryOp, const DenseDerived, const SparseDerived>(a.derived(), b.derived()); +} + +template +EIGEN_STRONG_INLINE const CwiseBinaryOp, const SparseDerived, const DenseDerived> +operator+(const SparseMatrixBase &a, const MatrixBase &b) +{ + return CwiseBinaryOp, const SparseDerived, const DenseDerived>(a.derived(), b.derived()); +} + +template +EIGEN_STRONG_INLINE const CwiseBinaryOp, const DenseDerived, const SparseDerived> +operator-(const MatrixBase &a, const SparseMatrixBase &b) +{ + return CwiseBinaryOp, const DenseDerived, const SparseDerived>(a.derived(), b.derived()); +} + +template +EIGEN_STRONG_INLINE const CwiseBinaryOp, const SparseDerived, const DenseDerived> +operator-(const SparseMatrixBase &a, const MatrixBase &b) +{ + return CwiseBinaryOp, const SparseDerived, const DenseDerived>(a.derived(), b.derived()); } } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseCwiseUnaryOp.h b/libs/eigen3/Eigen/src/SparseCore/SparseCwiseUnaryOp.h index 5a50c7803..ea7973790 100644 --- a/libs/eigen3/Eigen/src/SparseCore/SparseCwiseUnaryOp.h +++ b/libs/eigen3/Eigen/src/SparseCore/SparseCwiseUnaryOp.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2008-2015 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -12,138 +12,121 @@ namespace Eigen { -template -class CwiseUnaryOpImpl - : public SparseMatrixBase > +namespace internal { + +template +struct unary_evaluator, IteratorBased> + : public evaluator_base > { public: + typedef CwiseUnaryOp XprType; class InnerIterator; - class ReverseInnerIterator; - - typedef CwiseUnaryOp Derived; - EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) + + enum { + CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost, + Flags = XprType::Flags + }; + + explicit unary_evaluator(const XprType& op) : m_functor(op.functor()), m_argImpl(op.nestedExpression()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + inline Index nonZerosEstimate() const { + return m_argImpl.nonZerosEstimate(); + } protected: - typedef typename internal::traits::_XprTypeNested _MatrixTypeNested; - typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator; - typedef typename _MatrixTypeNested::ReverseInnerIterator MatrixTypeReverseIterator; + typedef typename evaluator::InnerIterator EvalIterator; + + const UnaryOp m_functor; + evaluator m_argImpl; }; -template -class CwiseUnaryOpImpl::InnerIterator - : public CwiseUnaryOpImpl::MatrixTypeIterator +template +class unary_evaluator, IteratorBased>::InnerIterator + : public unary_evaluator, IteratorBased>::EvalIterator { - typedef typename CwiseUnaryOpImpl::Scalar Scalar; - typedef typename CwiseUnaryOpImpl::MatrixTypeIterator Base; + typedef typename XprType::Scalar Scalar; + typedef typename unary_evaluator, IteratorBased>::EvalIterator Base; public: - EIGEN_STRONG_INLINE InnerIterator(const CwiseUnaryOpImpl& unaryOp, typename CwiseUnaryOpImpl::Index outer) - : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) + EIGEN_STRONG_INLINE InnerIterator(const unary_evaluator& unaryOp, Index outer) + : Base(unaryOp.m_argImpl,outer), m_functor(unaryOp.m_functor) {} EIGEN_STRONG_INLINE InnerIterator& operator++() { Base::operator++(); return *this; } - EIGEN_STRONG_INLINE typename CwiseUnaryOpImpl::Scalar value() const { return m_functor(Base::value()); } - - protected: - const UnaryOp m_functor; - private: - typename CwiseUnaryOpImpl::Scalar& valueRef(); -}; - -template -class CwiseUnaryOpImpl::ReverseInnerIterator - : public CwiseUnaryOpImpl::MatrixTypeReverseIterator -{ - typedef typename CwiseUnaryOpImpl::Scalar Scalar; - typedef typename CwiseUnaryOpImpl::MatrixTypeReverseIterator Base; - public: - - EIGEN_STRONG_INLINE ReverseInnerIterator(const CwiseUnaryOpImpl& unaryOp, typename CwiseUnaryOpImpl::Index outer) - : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) - {} - - EIGEN_STRONG_INLINE ReverseInnerIterator& operator--() - { Base::operator--(); return *this; } - - EIGEN_STRONG_INLINE typename CwiseUnaryOpImpl::Scalar value() const { return m_functor(Base::value()); } + EIGEN_STRONG_INLINE Scalar value() const { return m_functor(Base::value()); } protected: const UnaryOp m_functor; private: - typename CwiseUnaryOpImpl::Scalar& valueRef(); + Scalar& valueRef(); }; -template -class CwiseUnaryViewImpl - : public SparseMatrixBase > +template +struct unary_evaluator, IteratorBased> + : public evaluator_base > { public: + typedef CwiseUnaryView XprType; class InnerIterator; - class ReverseInnerIterator; - - typedef CwiseUnaryView Derived; - EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) + + enum { + CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost, + Flags = XprType::Flags + }; + + explicit unary_evaluator(const XprType& op) : m_functor(op.functor()), m_argImpl(op.nestedExpression()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } protected: - typedef typename internal::traits::_MatrixTypeNested _MatrixTypeNested; - typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator; - typedef typename _MatrixTypeNested::ReverseInnerIterator MatrixTypeReverseIterator; + typedef typename evaluator::InnerIterator EvalIterator; + + const ViewOp m_functor; + evaluator m_argImpl; }; -template -class CwiseUnaryViewImpl::InnerIterator - : public CwiseUnaryViewImpl::MatrixTypeIterator +template +class unary_evaluator, IteratorBased>::InnerIterator + : public unary_evaluator, IteratorBased>::EvalIterator { - typedef typename CwiseUnaryViewImpl::Scalar Scalar; - typedef typename CwiseUnaryViewImpl::MatrixTypeIterator Base; + typedef typename XprType::Scalar Scalar; + typedef typename unary_evaluator, IteratorBased>::EvalIterator Base; public: - EIGEN_STRONG_INLINE InnerIterator(const CwiseUnaryViewImpl& unaryOp, typename CwiseUnaryViewImpl::Index outer) - : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) + EIGEN_STRONG_INLINE InnerIterator(const unary_evaluator& unaryOp, Index outer) + : Base(unaryOp.m_argImpl,outer), m_functor(unaryOp.m_functor) {} EIGEN_STRONG_INLINE InnerIterator& operator++() { Base::operator++(); return *this; } - EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar value() const { return m_functor(Base::value()); } - EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar& valueRef() { return m_functor(Base::valueRef()); } + EIGEN_STRONG_INLINE Scalar value() const { return m_functor(Base::value()); } + EIGEN_STRONG_INLINE Scalar& valueRef() { return m_functor(Base::valueRef()); } protected: const ViewOp m_functor; }; -template -class CwiseUnaryViewImpl::ReverseInnerIterator - : public CwiseUnaryViewImpl::MatrixTypeReverseIterator -{ - typedef typename CwiseUnaryViewImpl::Scalar Scalar; - typedef typename CwiseUnaryViewImpl::MatrixTypeReverseIterator Base; - public: - - EIGEN_STRONG_INLINE ReverseInnerIterator(const CwiseUnaryViewImpl& unaryOp, typename CwiseUnaryViewImpl::Index outer) - : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) - {} - - EIGEN_STRONG_INLINE ReverseInnerIterator& operator--() - { Base::operator--(); return *this; } - - EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar value() const { return m_functor(Base::value()); } - EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar& valueRef() { return m_functor(Base::valueRef()); } - - protected: - const ViewOp m_functor; -}; +} // end namespace internal template EIGEN_STRONG_INLINE Derived& SparseMatrixBase::operator*=(const Scalar& other) { + typedef typename internal::evaluator::InnerIterator EvalIterator; + internal::evaluator thisEval(derived()); for (Index j=0; j EIGEN_STRONG_INLINE Derived& SparseMatrixBase::operator/=(const Scalar& other) { + typedef typename internal::evaluator::InnerIterator EvalIterator; + internal::evaluator thisEval(derived()); for (Index j=0; j +// Copyright (C) 2008-2015 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -12,196 +12,93 @@ namespace Eigen { -template struct SparseDenseProductReturnType -{ - typedef SparseTimeDenseProduct Type; -}; - -template struct SparseDenseProductReturnType -{ - typedef typename internal::conditional< - Lhs::IsRowMajor, - SparseDenseOuterProduct, - SparseDenseOuterProduct >::type Type; -}; - -template struct DenseSparseProductReturnType -{ - typedef DenseTimeSparseProduct Type; -}; - -template struct DenseSparseProductReturnType -{ - typedef typename internal::conditional< - Rhs::IsRowMajor, - SparseDenseOuterProduct, - SparseDenseOuterProduct >::type Type; -}; - namespace internal { -template -struct traits > -{ - typedef Sparse StorageKind; - typedef typename scalar_product_traits::Scalar, - typename traits::Scalar>::ReturnType Scalar; - typedef typename Lhs::Index Index; - typedef typename Lhs::Nested LhsNested; - typedef typename Rhs::Nested RhsNested; - typedef typename remove_all::type _LhsNested; - typedef typename remove_all::type _RhsNested; - - enum { - LhsCoeffReadCost = traits<_LhsNested>::CoeffReadCost, - RhsCoeffReadCost = traits<_RhsNested>::CoeffReadCost, - - RowsAtCompileTime = Tr ? int(traits::RowsAtCompileTime) : int(traits::RowsAtCompileTime), - ColsAtCompileTime = Tr ? int(traits::ColsAtCompileTime) : int(traits::ColsAtCompileTime), - MaxRowsAtCompileTime = Tr ? int(traits::MaxRowsAtCompileTime) : int(traits::MaxRowsAtCompileTime), - MaxColsAtCompileTime = Tr ? int(traits::MaxColsAtCompileTime) : int(traits::MaxColsAtCompileTime), - - Flags = Tr ? RowMajorBit : 0, - - CoeffReadCost = LhsCoeffReadCost + RhsCoeffReadCost + NumTraits::MulCost - }; -}; - -} // end namespace internal - -template -class SparseDenseOuterProduct - : public SparseMatrixBase > -{ - public: - - typedef SparseMatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(SparseDenseOuterProduct) - typedef internal::traits Traits; - - private: - - typedef typename Traits::LhsNested LhsNested; - typedef typename Traits::RhsNested RhsNested; - typedef typename Traits::_LhsNested _LhsNested; - typedef typename Traits::_RhsNested _RhsNested; - - public: - - class InnerIterator; - - EIGEN_STRONG_INLINE SparseDenseOuterProduct(const Lhs& lhs, const Rhs& rhs) - : m_lhs(lhs), m_rhs(rhs) - { - EIGEN_STATIC_ASSERT(!Tr,YOU_MADE_A_PROGRAMMING_MISTAKE); - } - - EIGEN_STRONG_INLINE SparseDenseOuterProduct(const Rhs& rhs, const Lhs& lhs) - : m_lhs(lhs), m_rhs(rhs) - { - EIGEN_STATIC_ASSERT(Tr,YOU_MADE_A_PROGRAMMING_MISTAKE); - } - - EIGEN_STRONG_INLINE Index rows() const { return Tr ? m_rhs.rows() : m_lhs.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return Tr ? m_lhs.cols() : m_rhs.cols(); } - - EIGEN_STRONG_INLINE const _LhsNested& lhs() const { return m_lhs; } - EIGEN_STRONG_INLINE const _RhsNested& rhs() const { return m_rhs; } - - protected: - LhsNested m_lhs; - RhsNested m_rhs; -}; - -template -class SparseDenseOuterProduct::InnerIterator : public _LhsNested::InnerIterator -{ - typedef typename _LhsNested::InnerIterator Base; - typedef typename SparseDenseOuterProduct::Index Index; - public: - EIGEN_STRONG_INLINE InnerIterator(const SparseDenseOuterProduct& prod, Index outer) - : Base(prod.lhs(), 0), m_outer(outer), m_factor(get(prod.rhs(), outer, typename internal::traits::StorageKind() )) - { } - - inline Index outer() const { return m_outer; } - inline Index row() const { return Transpose ? m_outer : Base::index(); } - inline Index col() const { return Transpose ? Base::index() : m_outer; } - - inline Scalar value() const { return Base::value() * m_factor; } - - protected: - static Scalar get(const _RhsNested &rhs, Index outer, Dense = Dense()) - { - return rhs.coeff(outer); - } - - static Scalar get(const _RhsNested &rhs, Index outer, Sparse = Sparse()) - { - typename Traits::_RhsNested::InnerIterator it(rhs, outer); - if (it && it.index()==0) - return it.value(); - - return Scalar(0); - } - - Index m_outer; - Scalar m_factor; -}; - -namespace internal { -template -struct traits > - : traits, Lhs, Rhs> > -{ - typedef Dense StorageKind; - typedef MatrixXpr XprKind; -}; +template <> struct product_promote_storage_type { typedef Sparse ret; }; +template <> struct product_promote_storage_type { typedef Sparse ret; }; template struct sparse_time_dense_product_impl; template -struct sparse_time_dense_product_impl +struct sparse_time_dense_product_impl { typedef typename internal::remove_all::type Lhs; typedef typename internal::remove_all::type Rhs; typedef typename internal::remove_all::type Res; - typedef typename Lhs::Index Index; - typedef typename Lhs::InnerIterator LhsInnerIterator; + typedef typename evaluator::InnerIterator LhsInnerIterator; + typedef evaluator LhsEval; static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const typename Res::Scalar& alpha) { + LhsEval lhsEval(lhs); + + Index n = lhs.outerSize(); +#ifdef EIGEN_HAS_OPENMP + Eigen::initParallel(); + Index threads = Eigen::nbThreads(); +#endif + for(Index c=0; c1 && lhsEval.nonZerosEstimate() > 20000) + { + #pragma omp parallel for schedule(dynamic,(n+threads*4-1)/(threads*4)) num_threads(threads) + for(Index i=0; i -struct sparse_time_dense_product_impl +// FIXME: what is the purpose of the following specialization? Is it for the BlockedSparse format? +// -> let's disable it for now as it is conflicting with generic scalar*matrix and matrix*scalar operators +// template +// struct ScalarBinaryOpTraits > +// { +// enum { +// Defined = 1 +// }; +// typedef typename CwiseUnaryOp, T2>::PlainObject ReturnType; +// }; + +template +struct sparse_time_dense_product_impl { typedef typename internal::remove_all::type Lhs; typedef typename internal::remove_all::type Rhs; typedef typename internal::remove_all::type Res; - typedef typename Lhs::InnerIterator LhsInnerIterator; - typedef typename Lhs::Index Index; - static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const typename Res::Scalar& alpha) + typedef typename evaluator::InnerIterator LhsInnerIterator; + static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const AlphaType& alpha) { + evaluator lhsEval(lhs); for(Index c=0; c::ReturnType rhs_j(alpha * rhs.coeff(j,c)); + for(LhsInnerIterator it(lhsEval,j); it ;++it) res.coeffRef(it.index(),c) += it.value() * rhs_j; } } @@ -209,38 +106,38 @@ struct sparse_time_dense_product_impl -struct sparse_time_dense_product_impl +struct sparse_time_dense_product_impl { typedef typename internal::remove_all::type Lhs; typedef typename internal::remove_all::type Rhs; typedef typename internal::remove_all::type Res; - typedef typename Lhs::InnerIterator LhsInnerIterator; - typedef typename Lhs::Index Index; + typedef typename evaluator::InnerIterator LhsInnerIterator; static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const typename Res::Scalar& alpha) { + evaluator lhsEval(lhs); for(Index j=0; j -struct sparse_time_dense_product_impl +struct sparse_time_dense_product_impl { typedef typename internal::remove_all::type Lhs; typedef typename internal::remove_all::type Rhs; typedef typename internal::remove_all::type Res; - typedef typename Lhs::InnerIterator LhsInnerIterator; - typedef typename Lhs::Index Index; + typedef typename evaluator::InnerIterator LhsInnerIterator; static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const typename Res::Scalar& alpha) { + evaluator lhsEval(lhs); for(Index j=0; j inline void sparse_time_dense_product(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const AlphaType& alpha) { - sparse_time_dense_product_impl::run(lhs, rhs, res, alpha); + sparse_time_dense_product_impl::run(lhs, rhs, res, alpha); } } // end namespace internal -template -class SparseTimeDenseProduct - : public ProductBase, Lhs, Rhs> -{ - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(SparseTimeDenseProduct) - - SparseTimeDenseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - {} - - template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const - { - internal::sparse_time_dense_product(m_lhs, m_rhs, dest, alpha); - } +namespace internal { - private: - SparseTimeDenseProduct& operator=(const SparseTimeDenseProduct&); +template +struct generic_product_impl + : generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + typedef typename nested_eval::type LhsNested; + typedef typename nested_eval::type RhsNested; + LhsNested lhsNested(lhs); + RhsNested rhsNested(rhs); + internal::sparse_time_dense_product(lhsNested, rhsNested, dst, alpha); + } }; +template +struct generic_product_impl + : generic_product_impl +{}; -// dense = dense * sparse -namespace internal { -template -struct traits > - : traits, Lhs, Rhs> > +template +struct generic_product_impl + : generic_product_impl_base > { - typedef Dense StorageKind; + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + typedef typename nested_eval::type LhsNested; + typedef typename nested_eval::type RhsNested; + LhsNested lhsNested(lhs); + RhsNested rhsNested(rhs); + + // transpose everything + Transpose dstT(dst); + internal::sparse_time_dense_product(rhsNested.transpose(), lhsNested.transpose(), dstT, alpha); + } }; -} // end namespace internal -template -class DenseTimeSparseProduct - : public ProductBase, Lhs, Rhs> +template +struct generic_product_impl + : generic_product_impl +{}; + +template +struct sparse_dense_outer_product_evaluator { +protected: + typedef typename conditional::type Lhs1; + typedef typename conditional::type ActualRhs; + typedef Product ProdXprType; + + // if the actual left-hand side is a dense vector, + // then build a sparse-view so that we can seamlessly iterate over it. + typedef typename conditional::StorageKind,Sparse>::value, + Lhs1, SparseView >::type ActualLhs; + typedef typename conditional::StorageKind,Sparse>::value, + Lhs1 const&, SparseView >::type LhsArg; + + typedef evaluator LhsEval; + typedef evaluator RhsEval; + typedef typename evaluator::InnerIterator LhsIterator; + typedef typename ProdXprType::Scalar Scalar; + +public: + enum { + Flags = NeedToTranspose ? RowMajorBit : 0, + CoeffReadCost = HugeCost + }; + + class InnerIterator : public LhsIterator + { public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(DenseTimeSparseProduct) - - DenseTimeSparseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) + InnerIterator(const sparse_dense_outer_product_evaluator &xprEval, Index outer) + : LhsIterator(xprEval.m_lhsXprImpl, 0), + m_outer(outer), + m_empty(false), + m_factor(get(xprEval.m_rhsXprImpl, outer, typename internal::traits::StorageKind() )) {} + + EIGEN_STRONG_INLINE Index outer() const { return m_outer; } + EIGEN_STRONG_INLINE Index row() const { return NeedToTranspose ? m_outer : LhsIterator::index(); } + EIGEN_STRONG_INLINE Index col() const { return NeedToTranspose ? LhsIterator::index() : m_outer; } - template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const + EIGEN_STRONG_INLINE Scalar value() const { return LhsIterator::value() * m_factor; } + EIGEN_STRONG_INLINE operator bool() const { return LhsIterator::operator bool() && (!m_empty); } + + protected: + Scalar get(const RhsEval &rhs, Index outer, Dense = Dense()) const { - Transpose lhs_t(m_lhs); - Transpose rhs_t(m_rhs); - Transpose dest_t(dest); - internal::sparse_time_dense_product(rhs_t, lhs_t, dest_t, alpha); + return rhs.coeff(outer); + } + + Scalar get(const RhsEval &rhs, Index outer, Sparse = Sparse()) + { + typename RhsEval::InnerIterator it(rhs, outer); + if (it && it.index()==0 && it.value()!=Scalar(0)) + return it.value(); + m_empty = true; + return Scalar(0); } + + Index m_outer; + bool m_empty; + Scalar m_factor; + }; + + sparse_dense_outer_product_evaluator(const Lhs1 &lhs, const ActualRhs &rhs) + : m_lhs(lhs), m_lhsXprImpl(m_lhs), m_rhsXprImpl(rhs) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + // transpose case + sparse_dense_outer_product_evaluator(const ActualRhs &rhs, const Lhs1 &lhs) + : m_lhs(lhs), m_lhsXprImpl(m_lhs), m_rhsXprImpl(rhs) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + +protected: + const LhsArg m_lhs; + evaluator m_lhsXprImpl; + evaluator m_rhsXprImpl; +}; - private: - DenseTimeSparseProduct& operator=(const DenseTimeSparseProduct&); +// sparse * dense outer product +template +struct product_evaluator, OuterProduct, SparseShape, DenseShape> + : sparse_dense_outer_product_evaluator +{ + typedef sparse_dense_outer_product_evaluator Base; + + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + + explicit product_evaluator(const XprType& xpr) + : Base(xpr.lhs(), xpr.rhs()) + {} + }; -// sparse * dense -template -template -inline const typename SparseDenseProductReturnType::Type -SparseMatrixBase::operator*(const MatrixBase &other) const +template +struct product_evaluator, OuterProduct, DenseShape, SparseShape> + : sparse_dense_outer_product_evaluator { - return typename SparseDenseProductReturnType::Type(derived(), other.derived()); -} + typedef sparse_dense_outer_product_evaluator Base; + + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + + explicit product_evaluator(const XprType& xpr) + : Base(xpr.lhs(), xpr.rhs()) + {} + +}; + +} // end namespace internal } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseDiagonalProduct.h b/libs/eigen3/Eigen/src/SparseCore/SparseDiagonalProduct.h index 1bb590e64..941c03be3 100644 --- a/libs/eigen3/Eigen/src/SparseCore/SparseDiagonalProduct.h +++ b/libs/eigen3/Eigen/src/SparseCore/SparseDiagonalProduct.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2009-2015 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -26,171 +26,113 @@ namespace Eigen { namespace internal { -template -struct traits > -{ - typedef typename remove_all::type _Lhs; - typedef typename remove_all::type _Rhs; - typedef typename _Lhs::Scalar Scalar; - typedef typename promote_index_type::Index, - typename traits::Index>::type Index; - typedef Sparse StorageKind; - typedef MatrixXpr XprKind; - enum { - RowsAtCompileTime = _Lhs::RowsAtCompileTime, - ColsAtCompileTime = _Rhs::ColsAtCompileTime, - - MaxRowsAtCompileTime = _Lhs::MaxRowsAtCompileTime, - MaxColsAtCompileTime = _Rhs::MaxColsAtCompileTime, - - SparseFlags = is_diagonal<_Lhs>::ret ? int(_Rhs::Flags) : int(_Lhs::Flags), - Flags = (SparseFlags&RowMajorBit), - CoeffReadCost = Dynamic - }; +enum { + SDP_AsScalarProduct, + SDP_AsCwiseProduct }; + +template +struct sparse_diagonal_product_evaluator; -enum {SDP_IsDiagonal, SDP_IsSparseRowMajor, SDP_IsSparseColMajor}; -template -class sparse_diagonal_product_inner_iterator_selector; - -} // end namespace internal - -template -class SparseDiagonalProduct - : public SparseMatrixBase >, - internal::no_assignment_operator +template +struct product_evaluator, ProductTag, DiagonalShape, SparseShape> + : public sparse_diagonal_product_evaluator { - typedef typename Lhs::Nested LhsNested; - typedef typename Rhs::Nested RhsNested; - - typedef typename internal::remove_all::type _LhsNested; - typedef typename internal::remove_all::type _RhsNested; - - enum { - LhsMode = internal::is_diagonal<_LhsNested>::ret ? internal::SDP_IsDiagonal - : (_LhsNested::Flags&RowMajorBit) ? internal::SDP_IsSparseRowMajor : internal::SDP_IsSparseColMajor, - RhsMode = internal::is_diagonal<_RhsNested>::ret ? internal::SDP_IsDiagonal - : (_RhsNested::Flags&RowMajorBit) ? internal::SDP_IsSparseRowMajor : internal::SDP_IsSparseColMajor - }; - - public: - - EIGEN_SPARSE_PUBLIC_INTERFACE(SparseDiagonalProduct) - - typedef internal::sparse_diagonal_product_inner_iterator_selector - <_LhsNested,_RhsNested,SparseDiagonalProduct,LhsMode,RhsMode> InnerIterator; - - // We do not want ReverseInnerIterator for diagonal-sparse products, - // but this dummy declaration is needed to make diag * sparse * diag compile. - class ReverseInnerIterator; - - EIGEN_STRONG_INLINE SparseDiagonalProduct(const Lhs& lhs, const Rhs& rhs) - : m_lhs(lhs), m_rhs(rhs) - { - eigen_assert(lhs.cols() == rhs.rows() && "invalid sparse matrix * diagonal matrix product"); - } - - EIGEN_STRONG_INLINE Index rows() const { return m_lhs.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_rhs.cols(); } - - EIGEN_STRONG_INLINE const _LhsNested& lhs() const { return m_lhs; } - EIGEN_STRONG_INLINE const _RhsNested& rhs() const { return m_rhs; } - - protected: - LhsNested m_lhs; - RhsNested m_rhs; + typedef Product XprType; + enum { CoeffReadCost = HugeCost, Flags = Rhs::Flags&RowMajorBit, Alignment = 0 }; // FIXME CoeffReadCost & Flags + + typedef sparse_diagonal_product_evaluator Base; + explicit product_evaluator(const XprType& xpr) : Base(xpr.rhs(), xpr.lhs().diagonal()) {} }; -namespace internal { - -template -class sparse_diagonal_product_inner_iterator_selector - - : public CwiseUnaryOp,const Rhs>::InnerIterator +template +struct product_evaluator, ProductTag, SparseShape, DiagonalShape> + : public sparse_diagonal_product_evaluator, Lhs::Flags&RowMajorBit?SDP_AsCwiseProduct:SDP_AsScalarProduct> { - typedef typename CwiseUnaryOp,const Rhs>::InnerIterator Base; - typedef typename Lhs::Index Index; - public: - inline sparse_diagonal_product_inner_iterator_selector( - const SparseDiagonalProductType& expr, Index outer) - : Base(expr.rhs()*(expr.lhs().diagonal().coeff(outer)), outer) - {} + typedef Product XprType; + enum { CoeffReadCost = HugeCost, Flags = Lhs::Flags&RowMajorBit, Alignment = 0 }; // FIXME CoeffReadCost & Flags + + typedef sparse_diagonal_product_evaluator, Lhs::Flags&RowMajorBit?SDP_AsCwiseProduct:SDP_AsScalarProduct> Base; + explicit product_evaluator(const XprType& xpr) : Base(xpr.lhs(), xpr.rhs().diagonal().transpose()) {} }; -template -class sparse_diagonal_product_inner_iterator_selector - - : public CwiseBinaryOp< - scalar_product_op, - const typename Rhs::ConstInnerVectorReturnType, - const typename Lhs::DiagonalVectorType>::InnerIterator +template +struct sparse_diagonal_product_evaluator { - typedef typename CwiseBinaryOp< - scalar_product_op, - const typename Rhs::ConstInnerVectorReturnType, - const typename Lhs::DiagonalVectorType>::InnerIterator Base; - typedef typename Lhs::Index Index; - Index m_outer; +protected: + typedef typename evaluator::InnerIterator SparseXprInnerIterator; + typedef typename SparseXprType::Scalar Scalar; + +public: + class InnerIterator : public SparseXprInnerIterator + { public: - inline sparse_diagonal_product_inner_iterator_selector( - const SparseDiagonalProductType& expr, Index outer) - : Base(expr.rhs().innerVector(outer) .cwiseProduct(expr.lhs().diagonal()), 0), m_outer(outer) + InnerIterator(const sparse_diagonal_product_evaluator &xprEval, Index outer) + : SparseXprInnerIterator(xprEval.m_sparseXprImpl, outer), + m_coeff(xprEval.m_diagCoeffImpl.coeff(outer)) {} - inline Index outer() const { return m_outer; } - inline Index col() const { return m_outer; } -}; + EIGEN_STRONG_INLINE Scalar value() const { return m_coeff * SparseXprInnerIterator::value(); } + protected: + typename DiagonalCoeffType::Scalar m_coeff; + }; + + sparse_diagonal_product_evaluator(const SparseXprType &sparseXpr, const DiagonalCoeffType &diagCoeff) + : m_sparseXprImpl(sparseXpr), m_diagCoeffImpl(diagCoeff) + {} -template -class sparse_diagonal_product_inner_iterator_selector - - : public CwiseUnaryOp,const Lhs>::InnerIterator -{ - typedef typename CwiseUnaryOp,const Lhs>::InnerIterator Base; - typedef typename Lhs::Index Index; - public: - inline sparse_diagonal_product_inner_iterator_selector( - const SparseDiagonalProductType& expr, Index outer) - : Base(expr.lhs()*expr.rhs().diagonal().coeff(outer), outer) - {} + Index nonZerosEstimate() const { return m_sparseXprImpl.nonZerosEstimate(); } + +protected: + evaluator m_sparseXprImpl; + evaluator m_diagCoeffImpl; }; -template -class sparse_diagonal_product_inner_iterator_selector - - : public CwiseBinaryOp< - scalar_product_op, - const typename Lhs::ConstInnerVectorReturnType, - const Transpose >::InnerIterator + +template +struct sparse_diagonal_product_evaluator { - typedef typename CwiseBinaryOp< - scalar_product_op, - const typename Lhs::ConstInnerVectorReturnType, - const Transpose >::InnerIterator Base; - typedef typename Lhs::Index Index; - Index m_outer; + typedef typename SparseXprType::Scalar Scalar; + typedef typename SparseXprType::StorageIndex StorageIndex; + + typedef typename nested_eval::type DiagCoeffNested; + + class InnerIterator + { + typedef typename evaluator::InnerIterator SparseXprIter; public: - inline sparse_diagonal_product_inner_iterator_selector( - const SparseDiagonalProductType& expr, Index outer) - : Base(expr.lhs().innerVector(outer) .cwiseProduct(expr.rhs().diagonal().transpose()), 0), m_outer(outer) + InnerIterator(const sparse_diagonal_product_evaluator &xprEval, Index outer) + : m_sparseIter(xprEval.m_sparseXprEval, outer), m_diagCoeffNested(xprEval.m_diagCoeffNested) {} - inline Index outer() const { return m_outer; } - inline Index row() const { return m_outer; } + inline Scalar value() const { return m_sparseIter.value() * m_diagCoeffNested.coeff(index()); } + inline StorageIndex index() const { return m_sparseIter.index(); } + inline Index outer() const { return m_sparseIter.outer(); } + inline Index col() const { return SparseXprType::IsRowMajor ? m_sparseIter.index() : m_sparseIter.outer(); } + inline Index row() const { return SparseXprType::IsRowMajor ? m_sparseIter.outer() : m_sparseIter.index(); } + + EIGEN_STRONG_INLINE InnerIterator& operator++() { ++m_sparseIter; return *this; } + inline operator bool() const { return m_sparseIter; } + + protected: + SparseXprIter m_sparseIter; + DiagCoeffNested m_diagCoeffNested; + }; + + sparse_diagonal_product_evaluator(const SparseXprType &sparseXpr, const DiagCoeffType &diagCoeff) + : m_sparseXprEval(sparseXpr), m_diagCoeffNested(diagCoeff) + {} + + Index nonZerosEstimate() const { return m_sparseXprEval.nonZerosEstimate(); } + +protected: + evaluator m_sparseXprEval; + DiagCoeffNested m_diagCoeffNested; }; } // end namespace internal -// SparseMatrixBase functions - -template -template -const SparseDiagonalProduct -SparseMatrixBase::operator*(const DiagonalBase &other) const -{ - return SparseDiagonalProduct(this->derived(), other.derived()); -} - } // end namespace Eigen #endif // EIGEN_SPARSE_DIAGONAL_PRODUCT_H diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseDot.h b/libs/eigen3/Eigen/src/SparseCore/SparseDot.h index db39c9aec..38bc4aa9e 100644 --- a/libs/eigen3/Eigen/src/SparseCore/SparseDot.h +++ b/libs/eigen3/Eigen/src/SparseCore/SparseDot.h @@ -26,7 +26,8 @@ SparseMatrixBase::dot(const MatrixBase& other) const eigen_assert(size() == other.size()); eigen_assert(other.size()>0 && "you are using a non initialized vector"); - typename Derived::InnerIterator i(derived(),0); + internal::evaluator thisEval(derived()); + typename internal::evaluator::InnerIterator i(thisEval, 0); Scalar res(0); while (i) { @@ -49,16 +50,12 @@ SparseMatrixBase::dot(const SparseMatrixBase& other) cons eigen_assert(size() == other.size()); - typedef typename Derived::Nested Nested; - typedef typename OtherDerived::Nested OtherNested; - typedef typename internal::remove_all::type NestedCleaned; - typedef typename internal::remove_all::type OtherNestedCleaned; + internal::evaluator thisEval(derived()); + typename internal::evaluator::InnerIterator i(thisEval, 0); + + internal::evaluator otherEval(other.derived()); + typename internal::evaluator::InnerIterator j(otherEval, 0); - Nested nthis(derived()); - OtherNested nother(other.derived()); - - typename NestedCleaned::InnerIterator i(nthis,0); - typename OtherNestedCleaned::InnerIterator j(nother,0); Scalar res(0); while (i && j) { diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseFuzzy.h b/libs/eigen3/Eigen/src/SparseCore/SparseFuzzy.h index 45f36e9eb..7d47eb94d 100644 --- a/libs/eigen3/Eigen/src/SparseCore/SparseFuzzy.h +++ b/libs/eigen3/Eigen/src/SparseCore/SparseFuzzy.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -10,17 +10,20 @@ #ifndef EIGEN_SPARSE_FUZZY_H #define EIGEN_SPARSE_FUZZY_H -// template -// template -// bool SparseMatrixBase::isApprox( -// const OtherDerived& other, -// typename NumTraits::Real prec -// ) const -// { -// const typename internal::nested::type nested(derived()); -// const typename internal::nested::type otherNested(other.derived()); -// return (nested - otherNested).cwise().abs2().sum() -// <= prec * prec * (std::min)(nested.cwise().abs2().sum(), otherNested.cwise().abs2().sum()); -// } +namespace Eigen { + +template +template +bool SparseMatrixBase::isApprox(const SparseMatrixBase& other, const RealScalar &prec) const +{ + const typename internal::nested_eval::type actualA(derived()); + typename internal::conditional::type, + const PlainObject>::type actualB(other.derived()); + + return (actualA - actualB).squaredNorm() <= prec * prec * numext::mini(actualA.squaredNorm(), actualB.squaredNorm()); +} + +} // end namespace Eigen #endif // EIGEN_SPARSE_FUZZY_H diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseMap.h b/libs/eigen3/Eigen/src/SparseCore/SparseMap.h new file mode 100644 index 000000000..f99be3379 --- /dev/null +++ b/libs/eigen3/Eigen/src/SparseCore/SparseMap.h @@ -0,0 +1,305 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSE_MAP_H +#define EIGEN_SPARSE_MAP_H + +namespace Eigen { + +namespace internal { + +template +struct traits, Options, StrideType> > + : public traits > +{ + typedef SparseMatrix PlainObjectType; + typedef traits TraitsBase; + enum { + Flags = TraitsBase::Flags & (~NestByRefBit) + }; +}; + +template +struct traits, Options, StrideType> > + : public traits > +{ + typedef SparseMatrix PlainObjectType; + typedef traits TraitsBase; + enum { + Flags = TraitsBase::Flags & (~ (NestByRefBit | LvalueBit)) + }; +}; + +} // end namespace internal + +template::has_write_access ? WriteAccessors : ReadOnlyAccessors +> class SparseMapBase; + +/** \ingroup SparseCore_Module + * class SparseMapBase + * \brief Common base class for Map and Ref instance of sparse matrix and vector. + */ +template +class SparseMapBase + : public SparseCompressedBase +{ + public: + typedef SparseCompressedBase Base; + typedef typename Base::Scalar Scalar; + typedef typename Base::StorageIndex StorageIndex; + enum { IsRowMajor = Base::IsRowMajor }; + using Base::operator=; + protected: + + typedef typename internal::conditional< + bool(internal::is_lvalue::value), + Scalar *, const Scalar *>::type ScalarPointer; + typedef typename internal::conditional< + bool(internal::is_lvalue::value), + StorageIndex *, const StorageIndex *>::type IndexPointer; + + Index m_outerSize; + Index m_innerSize; + Array m_zero_nnz; + IndexPointer m_outerIndex; + IndexPointer m_innerIndices; + ScalarPointer m_values; + IndexPointer m_innerNonZeros; + + public: + + /** \copydoc SparseMatrixBase::rows() */ + inline Index rows() const { return IsRowMajor ? m_outerSize : m_innerSize; } + /** \copydoc SparseMatrixBase::cols() */ + inline Index cols() const { return IsRowMajor ? m_innerSize : m_outerSize; } + /** \copydoc SparseMatrixBase::innerSize() */ + inline Index innerSize() const { return m_innerSize; } + /** \copydoc SparseMatrixBase::outerSize() */ + inline Index outerSize() const { return m_outerSize; } + /** \copydoc SparseCompressedBase::nonZeros */ + inline Index nonZeros() const { return m_zero_nnz[1]; } + + /** \copydoc SparseCompressedBase::isCompressed */ + bool isCompressed() const { return m_innerNonZeros==0; } + + //---------------------------------------- + // direct access interface + /** \copydoc SparseMatrix::valuePtr */ + inline const Scalar* valuePtr() const { return m_values; } + /** \copydoc SparseMatrix::innerIndexPtr */ + inline const StorageIndex* innerIndexPtr() const { return m_innerIndices; } + /** \copydoc SparseMatrix::outerIndexPtr */ + inline const StorageIndex* outerIndexPtr() const { return m_outerIndex; } + /** \copydoc SparseMatrix::innerNonZeroPtr */ + inline const StorageIndex* innerNonZeroPtr() const { return m_innerNonZeros; } + //---------------------------------------- + + /** \copydoc SparseMatrix::coeff */ + inline Scalar coeff(Index row, Index col) const + { + const Index outer = IsRowMajor ? row : col; + const Index inner = IsRowMajor ? col : row; + + Index start = m_outerIndex[outer]; + Index end = isCompressed() ? m_outerIndex[outer+1] : start + m_innerNonZeros[outer]; + if (start==end) + return Scalar(0); + else if (end>0 && inner==m_innerIndices[end-1]) + return m_values[end-1]; + // ^^ optimization: let's first check if it is the last coefficient + // (very common in high level algorithms) + + const StorageIndex* r = std::lower_bound(&m_innerIndices[start],&m_innerIndices[end-1],inner); + const Index id = r-&m_innerIndices[0]; + return ((*r==inner) && (id(nnz)), m_outerIndex(outerIndexPtr), + m_innerIndices(innerIndexPtr), m_values(valuePtr), m_innerNonZeros(innerNonZerosPtr) + {} + + // for vectors + inline SparseMapBase(Index size, Index nnz, IndexPointer innerIndexPtr, ScalarPointer valuePtr) + : m_outerSize(1), m_innerSize(size), m_zero_nnz(0,internal::convert_index(nnz)), m_outerIndex(m_zero_nnz.data()), + m_innerIndices(innerIndexPtr), m_values(valuePtr), m_innerNonZeros(0) + {} + + /** Empty destructor */ + inline ~SparseMapBase() {} + + protected: + inline SparseMapBase() {} +}; + +/** \ingroup SparseCore_Module + * class SparseMapBase + * \brief Common base class for writable Map and Ref instance of sparse matrix and vector. + */ +template +class SparseMapBase + : public SparseMapBase +{ + typedef MapBase ReadOnlyMapBase; + + public: + typedef SparseMapBase Base; + typedef typename Base::Scalar Scalar; + typedef typename Base::StorageIndex StorageIndex; + enum { IsRowMajor = Base::IsRowMajor }; + + using Base::operator=; + + public: + + //---------------------------------------- + // direct access interface + using Base::valuePtr; + using Base::innerIndexPtr; + using Base::outerIndexPtr; + using Base::innerNonZeroPtr; + /** \copydoc SparseMatrix::valuePtr */ + inline Scalar* valuePtr() { return Base::m_values; } + /** \copydoc SparseMatrix::innerIndexPtr */ + inline StorageIndex* innerIndexPtr() { return Base::m_innerIndices; } + /** \copydoc SparseMatrix::outerIndexPtr */ + inline StorageIndex* outerIndexPtr() { return Base::m_outerIndex; } + /** \copydoc SparseMatrix::innerNonZeroPtr */ + inline StorageIndex* innerNonZeroPtr() { return Base::m_innerNonZeros; } + //---------------------------------------- + + /** \copydoc SparseMatrix::coeffRef */ + inline Scalar& coeffRef(Index row, Index col) + { + const Index outer = IsRowMajor ? row : col; + const Index inner = IsRowMajor ? col : row; + + Index start = Base::m_outerIndex[outer]; + Index end = Base::isCompressed() ? Base::m_outerIndex[outer+1] : start + Base::m_innerNonZeros[outer]; + eigen_assert(end>=start && "you probably called coeffRef on a non finalized matrix"); + eigen_assert(end>start && "coeffRef cannot be called on a zero coefficient"); + StorageIndex* r = std::lower_bound(&Base::m_innerIndices[start],&Base::m_innerIndices[end],inner); + const Index id = r - &Base::m_innerIndices[0]; + eigen_assert((*r==inner) && (id(Base::m_values)[id]; + } + + inline SparseMapBase(Index rows, Index cols, Index nnz, StorageIndex* outerIndexPtr, StorageIndex* innerIndexPtr, + Scalar* valuePtr, StorageIndex* innerNonZerosPtr = 0) + : Base(rows, cols, nnz, outerIndexPtr, innerIndexPtr, valuePtr, innerNonZerosPtr) + {} + + // for vectors + inline SparseMapBase(Index size, Index nnz, StorageIndex* innerIndexPtr, Scalar* valuePtr) + : Base(size, nnz, innerIndexPtr, valuePtr) + {} + + /** Empty destructor */ + inline ~SparseMapBase() {} + + protected: + inline SparseMapBase() {} +}; + +/** \ingroup SparseCore_Module + * + * \brief Specialization of class Map for SparseMatrix-like storage. + * + * \tparam SparseMatrixType the equivalent sparse matrix type of the referenced data, it must be a template instance of class SparseMatrix. + * + * \sa class Map, class SparseMatrix, class Ref + */ +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +class Map, Options, StrideType> + : public SparseMapBase, Options, StrideType> > +#else +template +class Map + : public SparseMapBase +#endif +{ + public: + typedef SparseMapBase Base; + EIGEN_SPARSE_PUBLIC_INTERFACE(Map) + enum { IsRowMajor = Base::IsRowMajor }; + + public: + + /** Constructs a read-write Map to a sparse matrix of size \a rows x \a cols, containing \a nnz non-zero coefficients, + * stored as a sparse format as defined by the pointers \a outerIndexPtr, \a innerIndexPtr, and \a valuePtr. + * If the optional parameter \a innerNonZerosPtr is the null pointer, then a standard compressed format is assumed. + * + * This constructor is available only if \c SparseMatrixType is non-const. + * + * More details on the expected storage schemes are given in the \ref TutorialSparse "manual pages". + */ + inline Map(Index rows, Index cols, Index nnz, StorageIndex* outerIndexPtr, + StorageIndex* innerIndexPtr, Scalar* valuePtr, StorageIndex* innerNonZerosPtr = 0) + : Base(rows, cols, nnz, outerIndexPtr, innerIndexPtr, valuePtr, innerNonZerosPtr) + {} +#ifndef EIGEN_PARSED_BY_DOXYGEN + /** Empty destructor */ + inline ~Map() {} +}; + +template +class Map, Options, StrideType> + : public SparseMapBase, Options, StrideType> > +{ + public: + typedef SparseMapBase Base; + EIGEN_SPARSE_PUBLIC_INTERFACE(Map) + enum { IsRowMajor = Base::IsRowMajor }; + + public: +#endif + /** This is the const version of the above constructor. + * + * This constructor is available only if \c SparseMatrixType is const, e.g.: + * \code Map > \endcode + */ + inline Map(Index rows, Index cols, Index nnz, const StorageIndex* outerIndexPtr, + const StorageIndex* innerIndexPtr, const Scalar* valuePtr, const StorageIndex* innerNonZerosPtr = 0) + : Base(rows, cols, nnz, outerIndexPtr, innerIndexPtr, valuePtr, innerNonZerosPtr) + {} + + /** Empty destructor */ + inline ~Map() {} +}; + +namespace internal { + +template +struct evaluator, Options, StrideType> > + : evaluator, Options, StrideType> > > +{ + typedef evaluator, Options, StrideType> > > Base; + typedef Map, Options, StrideType> XprType; + evaluator() : Base() {} + explicit evaluator(const XprType &mat) : Base(mat) {} +}; + +template +struct evaluator, Options, StrideType> > + : evaluator, Options, StrideType> > > +{ + typedef evaluator, Options, StrideType> > > Base; + typedef Map, Options, StrideType> XprType; + evaluator() : Base() {} + explicit evaluator(const XprType &mat) : Base(mat) {} +}; + +} + +} // end namespace Eigen + +#endif // EIGEN_SPARSE_MAP_H diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseMatrix.h b/libs/eigen3/Eigen/src/SparseCore/SparseMatrix.h index ba5e3a9b6..323c2323b 100644 --- a/libs/eigen3/Eigen/src/SparseCore/SparseMatrix.h +++ b/libs/eigen3/Eigen/src/SparseCore/SparseMatrix.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -32,18 +32,22 @@ namespace Eigen { * \tparam _Scalar the scalar type, i.e. the type of the coefficients * \tparam _Options Union of bit flags controlling the storage scheme. Currently the only possibility * is ColMajor or RowMajor. The default is 0 which means column-major. - * \tparam _Index the type of the indices. It has to be a \b signed type (e.g., short, int, std::ptrdiff_t). Default is \c int. + * \tparam _StorageIndex the type of the indices. It has to be a \b signed type (e.g., short, int, std::ptrdiff_t). Default is \c int. + * + * \warning In %Eigen 3.2, the undocumented type \c SparseMatrix::Index was improperly defined as the storage index type (e.g., int), + * whereas it is now (starting from %Eigen 3.3) deprecated and always defined as Eigen::Index. + * Codes making use of \c SparseMatrix::Index, might thus likely have to be changed to use \c SparseMatrix::StorageIndex instead. * * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_SPARSEMATRIX_PLUGIN. + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_SPARSEMATRIX_PLUGIN. */ namespace internal { -template -struct traits > +template +struct traits > { typedef _Scalar Scalar; - typedef _Index Index; + typedef _StorageIndex StorageIndex; typedef Sparse StorageKind; typedef MatrixXpr XprKind; enum { @@ -51,22 +55,21 @@ struct traits > ColsAtCompileTime = Dynamic, MaxRowsAtCompileTime = Dynamic, MaxColsAtCompileTime = Dynamic, - Flags = _Options | NestByRefBit | LvalueBit, - CoeffReadCost = NumTraits::ReadCost, + Flags = _Options | NestByRefBit | LvalueBit | CompressedAccessBit, SupportedAccessPatterns = InnerRandomAccessPattern }; }; -template -struct traits, DiagIndex> > +template +struct traits, DiagIndex> > { - typedef SparseMatrix<_Scalar, _Options, _Index> MatrixType; - typedef typename nested::type MatrixTypeNested; + typedef SparseMatrix<_Scalar, _Options, _StorageIndex> MatrixType; + typedef typename ref_selector::type MatrixTypeNested; typedef typename remove_reference::type _MatrixTypeNested; typedef _Scalar Scalar; typedef Dense StorageKind; - typedef _Index Index; + typedef _StorageIndex StorageIndex; typedef MatrixXpr XprKind; enum { @@ -74,47 +77,61 @@ struct traits, DiagIndex> ColsAtCompileTime = 1, MaxRowsAtCompileTime = Dynamic, MaxColsAtCompileTime = 1, - Flags = 0, - CoeffReadCost = _MatrixTypeNested::CoeffReadCost*10 + Flags = LvalueBit + }; +}; + +template +struct traits, DiagIndex> > + : public traits, DiagIndex> > +{ + enum { + Flags = 0 }; }; } // end namespace internal -template +template class SparseMatrix - : public SparseMatrixBase > + : public SparseCompressedBase > { + typedef SparseCompressedBase Base; + using Base::convert_index; + friend class SparseVector<_Scalar,0,_StorageIndex>; public: + using Base::isCompressed; + using Base::nonZeros; EIGEN_SPARSE_PUBLIC_INTERFACE(SparseMatrix) - EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseMatrix, +=) - EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseMatrix, -=) + using Base::operator+=; + using Base::operator-=; typedef MappedSparseMatrix Map; + typedef Diagonal DiagonalReturnType; + typedef Diagonal ConstDiagonalReturnType; + typedef typename Base::InnerIterator InnerIterator; + typedef typename Base::ReverseInnerIterator ReverseInnerIterator; + + using Base::IsRowMajor; - typedef internal::CompressedStorage Storage; + typedef internal::CompressedStorage Storage; enum { Options = _Options }; + typedef typename Base::IndexVector IndexVector; + typedef typename Base::ScalarVector ScalarVector; protected: - typedef SparseMatrix TransposedSparseMatrix; Index m_outerSize; Index m_innerSize; - Index* m_outerIndex; - Index* m_innerNonZeros; // optional, if null then the data is compressed + StorageIndex* m_outerIndex; + StorageIndex* m_innerNonZeros; // optional, if null then the data is compressed Storage m_data; - - Eigen::Map > innerNonZeros() { return Eigen::Map >(m_innerNonZeros, m_innerNonZeros?m_outerSize:0); } - const Eigen::Map > innerNonZeros() const { return Eigen::Map >(m_innerNonZeros, m_innerNonZeros?m_outerSize:0); } public: - /** \returns whether \c *this is in compressed form. */ - inline bool isCompressed() const { return m_innerNonZeros==0; } - /** \returns the number of rows of the matrix */ inline Index rows() const { return IsRowMajor ? m_outerSize : m_innerSize; } /** \returns the number of columns of the matrix */ @@ -128,38 +145,38 @@ class SparseMatrix /** \returns a const pointer to the array of values. * This function is aimed at interoperability with other libraries. * \sa innerIndexPtr(), outerIndexPtr() */ - inline const Scalar* valuePtr() const { return &m_data.value(0); } + inline const Scalar* valuePtr() const { return m_data.valuePtr(); } /** \returns a non-const pointer to the array of values. * This function is aimed at interoperability with other libraries. * \sa innerIndexPtr(), outerIndexPtr() */ - inline Scalar* valuePtr() { return &m_data.value(0); } + inline Scalar* valuePtr() { return m_data.valuePtr(); } /** \returns a const pointer to the array of inner indices. * This function is aimed at interoperability with other libraries. * \sa valuePtr(), outerIndexPtr() */ - inline const Index* innerIndexPtr() const { return &m_data.index(0); } + inline const StorageIndex* innerIndexPtr() const { return m_data.indexPtr(); } /** \returns a non-const pointer to the array of inner indices. * This function is aimed at interoperability with other libraries. * \sa valuePtr(), outerIndexPtr() */ - inline Index* innerIndexPtr() { return &m_data.index(0); } + inline StorageIndex* innerIndexPtr() { return m_data.indexPtr(); } /** \returns a const pointer to the array of the starting positions of the inner vectors. * This function is aimed at interoperability with other libraries. * \sa valuePtr(), innerIndexPtr() */ - inline const Index* outerIndexPtr() const { return m_outerIndex; } + inline const StorageIndex* outerIndexPtr() const { return m_outerIndex; } /** \returns a non-const pointer to the array of the starting positions of the inner vectors. * This function is aimed at interoperability with other libraries. * \sa valuePtr(), innerIndexPtr() */ - inline Index* outerIndexPtr() { return m_outerIndex; } + inline StorageIndex* outerIndexPtr() { return m_outerIndex; } /** \returns a const pointer to the array of the number of non zeros of the inner vectors. * This function is aimed at interoperability with other libraries. * \warning it returns the null pointer 0 in compressed mode */ - inline const Index* innerNonZeroPtr() const { return m_innerNonZeros; } + inline const StorageIndex* innerNonZeroPtr() const { return m_innerNonZeros; } /** \returns a non-const pointer to the array of the number of non zeros of the inner vectors. * This function is aimed at interoperability with other libraries. * \warning it returns the null pointer 0 in compressed mode */ - inline Index* innerNonZeroPtr() { return m_innerNonZeros; } + inline StorageIndex* innerNonZeroPtr() { return m_innerNonZeros; } /** \internal */ inline Storage& data() { return m_data; } @@ -175,7 +192,7 @@ class SparseMatrix const Index outer = IsRowMajor ? row : col; const Index inner = IsRowMajor ? col : row; Index end = m_innerNonZeros ? m_outerIndex[outer] + m_innerNonZeros[outer] : m_outerIndex[outer+1]; - return m_data.atInRange(m_outerIndex[outer], end, inner); + return m_data.atInRange(m_outerIndex[outer], end, StorageIndex(inner)); } /** \returns a non-const reference to the value of the matrix at position \a i, \a j @@ -198,7 +215,7 @@ class SparseMatrix eigen_assert(end>=start && "you probably called coeffRef on a non finalized matrix"); if(end<=start) return insert(row,col); - const Index p = m_data.searchLowerIndex(start,end-1,inner); + const Index p = m_data.searchLowerIndex(start,end-1,StorageIndex(inner)); if((pinnerSize() non zeros if reserve(Index) has not been called earlier. + * In this case, the insertion procedure is optimized for a \e sequential insertion mode where elements are assumed to be + * inserted by increasing outer-indices. + * + * If that's not the case, then it is strongly recommended to either use a triplet-list to assemble the matrix, or to first + * call reserve(const SizesType &) to reserve the appropriate number of non-zero elements per inner vector. * - * This function performs a sorted insertion in O(1) if the elements of each inner vector are - * inserted in increasing inner index order, and in O(nnz_j) for a random insertion. + * Assuming memory has been appropriately reserved, this function performs a sorted insertion in O(1) + * if the elements of each inner vector are inserted in increasing inner index order, and in O(nnz_j) for a random insertion. * */ - Scalar& insert(Index row, Index col) - { - eigen_assert(row>=0 && row=0 && col::Constant(outerSize(), 2)); - } - return insertUncompressed(row,col); - } + Scalar& insert(Index row, Index col); public: - class InnerIterator; - class ReverseInnerIterator; - - /** Removes all non zeros but keep allocated memory */ + /** Removes all non zeros but keep allocated memory + * + * This function does not free the currently allocated memory. To release as much as memory as possible, + * call \code mat.data().squeeze(); \endcode after resizing it. + * + * \sa resize(Index,Index), data() + */ inline void setZero() { m_data.clear(); - memset(m_outerIndex, 0, (m_outerSize+1)*sizeof(Index)); - if(m_innerNonZeros) - memset(m_innerNonZeros, 0, (m_outerSize)*sizeof(Index)); - } - - /** \returns the number of non zero coefficients */ - inline Index nonZeros() const - { + memset(m_outerIndex, 0, (m_outerSize+1)*sizeof(StorageIndex)); if(m_innerNonZeros) - return innerNonZeros().sum(); - return static_cast(m_data.size()); + memset(m_innerNonZeros, 0, (m_outerSize)*sizeof(StorageIndex)); } /** Preallocates \a reserveSize non zeros. @@ -262,22 +268,25 @@ class SparseMatrix #ifdef EIGEN_PARSED_BY_DOXYGEN /** Preallocates \a reserveSize[\c j] non zeros for each column (resp. row) \c j. * - * This function turns the matrix in non-compressed mode */ + * This function turns the matrix in non-compressed mode. + * + * The type \c SizesType must expose the following interface: + \code + typedef value_type; + const value_type& operator[](i) const; + \endcode + * for \c i in the [0,this->outerSize()[ range. + * Typical choices include std::vector, Eigen::VectorXi, Eigen::VectorXi::Constant, etc. + */ template inline void reserve(const SizesType& reserveSizes); #else template - inline void reserve(const SizesType& reserveSizes, const typename SizesType::value_type& enableif = typename SizesType::value_type()) - { - EIGEN_UNUSED_VARIABLE(enableif); - reserveInnerVectors(reserveSizes); - } - template - inline void reserve(const SizesType& reserveSizes, const typename SizesType::Scalar& enableif = - #if (!defined(_MSC_VER)) || (_MSC_VER>=1500) // MSVC 2005 fails to compile with this typename + inline void reserve(const SizesType& reserveSizes, const typename SizesType::value_type& enableif = + #if (!EIGEN_COMP_MSVC) || (EIGEN_COMP_MSVC>=1500) // MSVC 2005 fails to compile with this typename typename #endif - SizesType::Scalar()) + SizesType::value_type()) { EIGEN_UNUSED_VARIABLE(enableif); reserveInnerVectors(reserveSizes); @@ -289,15 +298,15 @@ class SparseMatrix { if(isCompressed()) { - std::size_t totalReserveSize = 0; + Index totalReserveSize = 0; // turn the matrix into non-compressed mode - m_innerNonZeros = static_cast(std::malloc(m_outerSize * sizeof(Index))); + m_innerNonZeros = static_cast(std::malloc(m_outerSize * sizeof(StorageIndex))); if (!m_innerNonZeros) internal::throw_std_bad_alloc(); // temporarily use m_innerSizes to hold the new starting points. - Index* newOuterIndex = m_innerNonZeros; + StorageIndex* newOuterIndex = m_innerNonZeros; - Index count = 0; + StorageIndex count = 0; for(Index j=0; j=0; --j) { - Index innerNNZ = previousOuterIndex - m_outerIndex[j]; + StorageIndex innerNNZ = previousOuterIndex - m_outerIndex[j]; for(Index i=innerNNZ-1; i>=0; --i) { m_data.index(newOuterIndex[j]+i) = m_data.index(m_outerIndex[j]+i); @@ -324,15 +333,15 @@ class SparseMatrix } else { - Index* newOuterIndex = static_cast(std::malloc((m_outerSize+1)*sizeof(Index))); + StorageIndex* newOuterIndex = static_cast(std::malloc((m_outerSize+1)*sizeof(StorageIndex))); if (!newOuterIndex) internal::throw_std_bad_alloc(); - Index count = 0; + StorageIndex count = 0; for(Index j=0; j(reserveSizes[j], alreadyReserved); + StorageIndex alreadyReserved = (m_outerIndex[j+1]-m_outerIndex[j]) - m_innerNonZeros[j]; + StorageIndex toReserve = std::max(reserveSizes[j], alreadyReserved); count += toReserve + m_innerNonZeros[j]; } newOuterIndex[m_outerSize] = count; @@ -343,7 +352,7 @@ class SparseMatrix Index offset = newOuterIndex[j] - m_outerIndex[j]; if(offset>0) { - Index innerNNZ = m_innerNonZeros[j]; + StorageIndex innerNNZ = m_innerNonZeros[j]; for(Index i=innerNNZ-1; i>=0; --i) { m_data.index(newOuterIndex[j]+i) = m_data.index(m_outerIndex[j]+i); @@ -380,11 +389,11 @@ class SparseMatrix * \sa insertBack, startVec */ inline Scalar& insertBackByOuterInner(Index outer, Index inner) { - eigen_assert(size_t(m_outerIndex[outer+1]) == m_data.size() && "Invalid ordered insertion (invalid outer index)"); + eigen_assert(Index(m_outerIndex[outer+1]) == m_data.size() && "Invalid ordered insertion (invalid outer index)"); eigen_assert( (m_outerIndex[outer+1]-m_outerIndex[outer]==0 || m_data.index(m_data.size()-1)(m_data.size()); + StorageIndex size = internal::convert_index(m_data.size()); Index i = m_outerSize; // find the last filled column while (i>=0 && m_outerIndex[i]==0) @@ -433,7 +442,13 @@ class SparseMatrix template void setFromTriplets(const InputIterators& begin, const InputIterators& end); - void sumupDuplicates(); + template + void setFromTriplets(const InputIterators& begin, const InputIterators& end, DupFunctor dup_func); + + void sumupDuplicates() { collapseDuplicates(internal::scalar_sum_op()); } + + template + void collapseDuplicates(DupFunctor dup_func = DupFunctor()); //--- @@ -451,6 +466,8 @@ class SparseMatrix if(isCompressed()) return; + eigen_internal_assert(m_outerIndex!=0 && m_outerSize>0); + Index oldStart = m_outerIndex[1]; m_outerIndex[1] = m_innerNonZeros[0]; for(Index j=1; j(std::malloc(m_outerSize * sizeof(Index))); + m_innerNonZeros = static_cast(std::malloc(m_outerSize * sizeof(StorageIndex))); for (Index i = 0; i < m_outerSize; i++) { m_innerNonZeros[i] = m_outerIndex[i+1] - m_outerIndex[i]; @@ -503,10 +520,9 @@ class SparseMatrix void prune(const KeepFunc& keep = KeepFunc()) { // TODO optimize the uncompressed mode to avoid moving and allocating the data twice - // TODO also implement a unit test makeCompressed(); - Index k = 0; + StorageIndex k = 0; for(Index j=0; jcols() : rows - this->rows(); Index outerChange = IsRowMajor ? rows - this->rows() : cols - this->cols(); - Index newInnerSize = IsRowMajor ? cols : rows; + StorageIndex newInnerSize = convert_index(IsRowMajor ? cols : rows); // Deals with inner non zeros if (m_innerNonZeros) { // Resize m_innerNonZeros - Index *newInnerNonZeros = static_cast(std::realloc(m_innerNonZeros, (m_outerSize + outerChange) * sizeof(Index))); + StorageIndex *newInnerNonZeros = static_cast(std::realloc(m_innerNonZeros, (m_outerSize + outerChange) * sizeof(StorageIndex))); if (!newInnerNonZeros) internal::throw_std_bad_alloc(); m_innerNonZeros = newInnerNonZeros; @@ -555,7 +576,7 @@ class SparseMatrix else if (innerChange < 0) { // Inner size decreased: allocate a new m_innerNonZeros - m_innerNonZeros = static_cast(std::malloc((m_outerSize+outerChange+1) * sizeof(Index))); + m_innerNonZeros = static_cast(std::malloc((m_outerSize+outerChange+1) * sizeof(StorageIndex))); if (!m_innerNonZeros) internal::throw_std_bad_alloc(); for(Index i = 0; i < m_outerSize; i++) m_innerNonZeros[i] = m_outerIndex[i+1] - m_outerIndex[i]; @@ -566,8 +587,8 @@ class SparseMatrix { for(Index i = 0; i < m_outerSize + (std::min)(outerChange, Index(0)); i++) { - Index &n = m_innerNonZeros[i]; - Index start = m_outerIndex[i]; + StorageIndex &n = m_innerNonZeros[i]; + StorageIndex start = m_outerIndex[i]; while (n > 0 && m_data.index(start+n-1) >= newInnerSize) --n; } } @@ -578,12 +599,12 @@ class SparseMatrix if (outerChange == 0) return; - Index *newOuterIndex = static_cast(std::realloc(m_outerIndex, (m_outerSize + outerChange + 1) * sizeof(Index))); + StorageIndex *newOuterIndex = static_cast(std::realloc(m_outerIndex, (m_outerSize + outerChange + 1) * sizeof(StorageIndex))); if (!newOuterIndex) internal::throw_std_bad_alloc(); m_outerIndex = newOuterIndex; if (outerChange > 0) { - Index last = m_outerSize == 0 ? 0 : m_outerIndex[m_outerSize]; + StorageIndex last = m_outerSize == 0 ? 0 : m_outerIndex[m_outerSize]; for(Index i=m_outerSize; i(std::malloc((outerSize + 1) * sizeof(Index))); + m_outerIndex = static_cast(std::malloc((outerSize + 1) * sizeof(StorageIndex))); if (!m_outerIndex) internal::throw_std_bad_alloc(); m_outerSize = outerSize; @@ -611,19 +636,24 @@ class SparseMatrix std::free(m_innerNonZeros); m_innerNonZeros = 0; } - memset(m_outerIndex, 0, (m_outerSize+1)*sizeof(Index)); + memset(m_outerIndex, 0, (m_outerSize+1)*sizeof(StorageIndex)); } /** \internal * Resize the nonzero vector to \a size */ void resizeNonZeros(Index size) { - // TODO remove this function m_data.resize(size); } - /** \returns a const expression of the diagonal coefficients */ - const Diagonal diagonal() const { return *this; } + /** \returns a const expression of the diagonal coefficients. */ + const ConstDiagonalReturnType diagonal() const { return ConstDiagonalReturnType(*this); } + + /** \returns a read-write expression of the diagonal coefficients. + * \warning If the diagonal entries are written, then all diagonal + * entries \b must already exist, otherwise an assertion will be raised. + */ + DiagonalReturnType diagonal() { return DiagonalReturnType(*this); } /** Default constructor yielding an empty \c 0 \c x \c 0 matrix */ inline SparseMatrix() @@ -649,7 +679,16 @@ class SparseMatrix EIGEN_STATIC_ASSERT((internal::is_same::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) check_template_parameters(); - *this = other.derived(); + const bool needToTranspose = (Flags & RowMajorBit) != (internal::evaluator::Flags & RowMajorBit); + if (needToTranspose) + *this = other.derived(); + else + { + #ifdef EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN + EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN + #endif + internal::call_assignment_no_alias(*this, other.derived()); + } } /** Constructs a sparse matrix from the sparse selfadjoint view \a other */ @@ -658,7 +697,7 @@ class SparseMatrix : m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) { check_template_parameters(); - *this = other; + Base::operator=(other); } /** Copy constructor (it performs a deep copy) */ @@ -678,6 +717,15 @@ class SparseMatrix initAssignment(other); other.evalTo(*this); } + + /** \brief Copy constructor with in-place evaluation */ + template + explicit SparseMatrix(const DiagonalBase& other) + : Base(), m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) + { + check_template_parameters(); + *this = other.derived(); + } /** Swaps the content of two sparse matrices of the same type. * This is a fast operation that simply swaps the underlying pointers and parameters. */ @@ -691,14 +739,17 @@ class SparseMatrix m_data.swap(other.m_data); } - /** Sets *this to the identity matrix */ + /** Sets *this to the identity matrix. + * This function also turns the matrix into compressed mode, and drop any reserved memory. */ inline void setIdentity() { eigen_assert(rows() == cols() && "ONLY FOR SQUARED MATRICES"); this->m_data.resize(rows()); - Eigen::Map >(&this->m_data.index(0), rows()).setLinSpaced(0, rows()-1); - Eigen::Map >(&this->m_data.value(0), rows()).setOnes(); - Eigen::Map >(this->m_outerIndex, rows()+1).setLinSpaced(0, rows()); + Eigen::Map(this->m_data.indexPtr(), rows()).setLinSpaced(0, StorageIndex(rows()-1)); + Eigen::Map(this->m_data.valuePtr(), rows()).setOnes(); + Eigen::Map(this->m_outerIndex, rows()+1).setLinSpaced(0, StorageIndex(rows())); + std::free(m_innerNonZeros); + m_innerNonZeros = 0; } inline SparseMatrix& operator=(const SparseMatrix& other) { @@ -708,10 +759,13 @@ class SparseMatrix } else if(this!=&other) { + #ifdef EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN + EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN + #endif initAssignment(other); if(other.isCompressed()) { - memcpy(m_outerIndex, other.m_outerIndex, (m_outerSize+1)*sizeof(Index)); + internal::smart_copy(other.m_outerIndex, other.m_outerIndex + m_outerSize + 1, m_outerIndex); m_data = other.m_data; } else @@ -722,22 +776,11 @@ class SparseMatrix return *this; } - #ifndef EIGEN_PARSED_BY_DOXYGEN - template - inline SparseMatrix& operator=(const SparseSparseProduct& product) - { return Base::operator=(product); } - - template - inline SparseMatrix& operator=(const ReturnByValue& other) - { - initAssignment(other); - return Base::operator=(other.derived()); - } - +#ifndef EIGEN_PARSED_BY_DOXYGEN template inline SparseMatrix& operator=(const EigenBase& other) { return Base::operator=(other.derived()); } - #endif +#endif // EIGEN_PARSED_BY_DOXYGEN template EIGEN_DONT_INLINE SparseMatrix& operator=(const SparseMatrixBase& other); @@ -747,30 +790,38 @@ class SparseMatrix EIGEN_DBG_SPARSE( s << "Nonzero entries:\n"; if(m.isCompressed()) + { for (Index i=0; i::IsSigned,THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE); + EIGEN_STATIC_ASSERT(NumTraits::IsSigned,THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE); EIGEN_STATIC_ASSERT((Options&(ColMajor|RowMajor))==Options,INVALID_MATRIX_TEMPLATE_PARAMETERS); } @@ -865,87 +914,20 @@ class SparseMatrix }; }; -template -class SparseMatrix::InnerIterator -{ - public: - InnerIterator(const SparseMatrix& mat, Index outer) - : m_values(mat.valuePtr()), m_indices(mat.innerIndexPtr()), m_outer(outer), m_id(mat.m_outerIndex[outer]) - { - if(mat.isCompressed()) - m_end = mat.m_outerIndex[outer+1]; - else - m_end = m_id + mat.m_innerNonZeros[outer]; - } - - inline InnerIterator& operator++() { m_id++; return *this; } - - inline const Scalar& value() const { return m_values[m_id]; } - inline Scalar& valueRef() { return const_cast(m_values[m_id]); } - - inline Index index() const { return m_indices[m_id]; } - inline Index outer() const { return m_outer; } - inline Index row() const { return IsRowMajor ? m_outer : index(); } - inline Index col() const { return IsRowMajor ? index() : m_outer; } - - inline operator bool() const { return (m_id < m_end); } - - protected: - const Scalar* m_values; - const Index* m_indices; - const Index m_outer; - Index m_id; - Index m_end; -}; - -template -class SparseMatrix::ReverseInnerIterator -{ - public: - ReverseInnerIterator(const SparseMatrix& mat, Index outer) - : m_values(mat.valuePtr()), m_indices(mat.innerIndexPtr()), m_outer(outer), m_start(mat.m_outerIndex[outer]) - { - if(mat.isCompressed()) - m_id = mat.m_outerIndex[outer+1]; - else - m_id = m_start + mat.m_innerNonZeros[outer]; - } - - inline ReverseInnerIterator& operator--() { --m_id; return *this; } - - inline const Scalar& value() const { return m_values[m_id-1]; } - inline Scalar& valueRef() { return const_cast(m_values[m_id-1]); } - - inline Index index() const { return m_indices[m_id-1]; } - inline Index outer() const { return m_outer; } - inline Index row() const { return IsRowMajor ? m_outer : index(); } - inline Index col() const { return IsRowMajor ? index() : m_outer; } - - inline operator bool() const { return (m_id > m_start); } - - protected: - const Scalar* m_values; - const Index* m_indices; - const Index m_outer; - Index m_id; - const Index m_start; -}; - namespace internal { -template -void set_from_triplets(const InputIterator& begin, const InputIterator& end, SparseMatrixType& mat, int Options = 0) +template +void set_from_triplets(const InputIterator& begin, const InputIterator& end, SparseMatrixType& mat, DupFunctor dup_func) { - EIGEN_UNUSED_VARIABLE(Options); enum { IsRowMajor = SparseMatrixType::IsRowMajor }; typedef typename SparseMatrixType::Scalar Scalar; - typedef typename SparseMatrixType::Index Index; - SparseMatrix trMat(mat.rows(),mat.cols()); + typedef typename SparseMatrixType::StorageIndex StorageIndex; + SparseMatrix trMat(mat.rows(),mat.cols()); if(begin!=end) { // pass 1: count the nnz per inner-vector - Matrix wi(trMat.outerSize()); + typename SparseMatrixType::IndexVector wi(trMat.outerSize()); wi.setZero(); for(InputIterator it(begin); it!=end; ++it) { @@ -959,7 +941,7 @@ void set_from_triplets(const InputIterator& begin, const InputIterator& end, Spa trMat.insertBackUncompressed(it->row(),it->col()) = it->value(); // pass 3: - trMat.sumupDuplicates(); + trMat.collapseDuplicates(dup_func); } // pass 4: transposed copy -> implicit sorting @@ -1006,26 +988,43 @@ void set_from_triplets(const InputIterator& begin, const InputIterator& end, Spa * an abstract iterator over a complex data-structure that would be expensive to evaluate. The triplets should rather * be explicitely stored into a std::vector for instance. */ -template +template template -void SparseMatrix::setFromTriplets(const InputIterators& begin, const InputIterators& end) +void SparseMatrix::setFromTriplets(const InputIterators& begin, const InputIterators& end) +{ + internal::set_from_triplets >(begin, end, *this, internal::scalar_sum_op()); +} + +/** The same as setFromTriplets but when duplicates are met the functor \a dup_func is applied: + * \code + * value = dup_func(OldValue, NewValue) + * \endcode + * Here is a C++11 example keeping the latest entry only: + * \code + * mat.setFromTriplets(triplets.begin(), triplets.end(), [] (const Scalar&,const Scalar &b) { return b; }); + * \endcode + */ +template +template +void SparseMatrix::setFromTriplets(const InputIterators& begin, const InputIterators& end, DupFunctor dup_func) { - internal::set_from_triplets(begin, end, *this); + internal::set_from_triplets, DupFunctor>(begin, end, *this, dup_func); } /** \internal */ -template -void SparseMatrix::sumupDuplicates() +template +template +void SparseMatrix::collapseDuplicates(DupFunctor dup_func) { eigen_assert(!isCompressed()); // TODO, in practice we should be able to use m_innerNonZeros for that task - Matrix wi(innerSize()); + IndexVector wi(innerSize()); wi.fill(-1); - Index count = 0; + StorageIndex count = 0; // for each inner-vector, wi[inner_index] will hold the position of first element into the index/value buffers for(Index j=0; j::sumupDuplicates() if(wi(i)>=start) { // we already meet this entry => accumulate it - m_data.value(wi(i)) += m_data.value(k); + m_data.value(wi(i)) = dup_func(m_data.value(wi(i)), m_data.value(k)); } else { @@ -1053,39 +1052,48 @@ void SparseMatrix::sumupDuplicates() m_data.resize(m_outerIndex[m_outerSize]); } -template +template template -EIGEN_DONT_INLINE SparseMatrix& SparseMatrix::operator=(const SparseMatrixBase& other) +EIGEN_DONT_INLINE SparseMatrix& SparseMatrix::operator=(const SparseMatrixBase& other) { EIGEN_STATIC_ASSERT((internal::is_same::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - - const bool needToTranspose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); + + #ifdef EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN + EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN + #endif + + const bool needToTranspose = (Flags & RowMajorBit) != (internal::evaluator::Flags & RowMajorBit); if (needToTranspose) { + #ifdef EIGEN_SPARSE_TRANSPOSED_COPY_PLUGIN + EIGEN_SPARSE_TRANSPOSED_COPY_PLUGIN + #endif // two passes algorithm: // 1 - compute the number of coeffs per dest inner vector // 2 - do the actual copy/eval // Since each coeff of the rhs has to be evaluated twice, let's evaluate it if needed - typedef typename internal::nested::type OtherCopy; + typedef typename internal::nested_eval::type >::type OtherCopy; typedef typename internal::remove_all::type _OtherCopy; + typedef internal::evaluator<_OtherCopy> OtherCopyEval; OtherCopy otherCopy(other.derived()); + OtherCopyEval otherCopyEval(otherCopy); SparseMatrix dest(other.rows(),other.cols()); - Eigen::Map > (dest.m_outerIndex,dest.outerSize()).setZero(); + Eigen::Map (dest.m_outerIndex,dest.outerSize()).setZero(); // pass 1 // FIXME the above copy could be merged with that pass for (Index j=0; j positions(dest.outerSize()); + StorageIndex count = 0; + IndexVector positions(dest.outerSize()); for (Index j=0; j& SparseMatrix& SparseMatrix -EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& SparseMatrix<_Scalar,_Options,_Index>::insertUncompressed(Index row, Index col) +template +typename SparseMatrix<_Scalar,_Options,_StorageIndex>::Scalar& SparseMatrix<_Scalar,_Options,_StorageIndex>::insert(Index row, Index col) +{ + eigen_assert(row>=0 && row=0 && col(std::malloc(m_outerSize * sizeof(StorageIndex))); + if(!m_innerNonZeros) internal::throw_std_bad_alloc(); + + memset(m_innerNonZeros, 0, (m_outerSize)*sizeof(StorageIndex)); + + // pack all inner-vectors to the end of the pre-allocated space + // and allocate the entire free-space to the first inner-vector + StorageIndex end = convert_index(m_data.allocatedSize()); + for(Index j=1; j<=m_outerSize; ++j) + m_outerIndex[j] = end; + } + else + { + // turn the matrix into non-compressed mode + m_innerNonZeros = static_cast(std::malloc(m_outerSize * sizeof(StorageIndex))); + if(!m_innerNonZeros) internal::throw_std_bad_alloc(); + for(Index j=0; j=0 && m_innerNonZeros[j]==0) + m_outerIndex[j--] = p; + + // push back the new element + ++m_innerNonZeros[outer]; + m_data.append(Scalar(0), inner); + + // check for reallocation + if(data_end != m_data.allocatedSize()) + { + // m_data has been reallocated + // -> move remaining inner-vectors back to the end of the free-space + // so that the entire free-space is allocated to the current inner-vector. + eigen_internal_assert(data_end < m_data.allocatedSize()); + StorageIndex new_end = convert_index(m_data.allocatedSize()); + for(Index k=outer+1; k<=m_outerSize; ++k) + if(m_outerIndex[k]==data_end) + m_outerIndex[k] = new_end; + } + return m_data.value(p); + } + + // Second case: the next inner-vector is packed to the end + // and the current inner-vector end match the used-space. + if(m_outerIndex[outer+1]==data_end && m_outerIndex[outer]+m_innerNonZeros[outer]==m_data.size()) + { + eigen_internal_assert(outer+1==m_outerSize || m_innerNonZeros[outer+1]==0); + + // add space for the new element + ++m_innerNonZeros[outer]; + m_data.resize(m_data.size()+1); + + // check for reallocation + if(data_end != m_data.allocatedSize()) + { + // m_data has been reallocated + // -> move remaining inner-vectors back to the end of the free-space + // so that the entire free-space is allocated to the current inner-vector. + eigen_internal_assert(data_end < m_data.allocatedSize()); + StorageIndex new_end = convert_index(m_data.allocatedSize()); + for(Index k=outer+1; k<=m_outerSize; ++k) + if(m_outerIndex[k]==data_end) + m_outerIndex[k] = new_end; + } + + // and insert it at the right position (sorted insertion) + Index startId = m_outerIndex[outer]; + Index p = m_outerIndex[outer]+m_innerNonZeros[outer]-1; + while ( (p > startId) && (m_data.index(p-1) > inner) ) + { + m_data.index(p) = m_data.index(p-1); + m_data.value(p) = m_data.value(p-1); + --p; + } + + m_data.index(p) = convert_index(inner); + return (m_data.value(p) = 0); + } + + if(m_data.size() != m_data.allocatedSize()) + { + // make sure the matrix is compatible to random un-compressed insertion: + m_data.resize(m_data.allocatedSize()); + this->reserveInnerVectors(Array::Constant(m_outerSize, 2)); + } + + return insertUncompressed(row,col); +} + +template +EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_StorageIndex>::Scalar& SparseMatrix<_Scalar,_Options,_StorageIndex>::insertUncompressed(Index row, Index col) { eigen_assert(!isCompressed()); const Index outer = IsRowMajor ? row : col; - const Index inner = IsRowMajor ? col : row; + const StorageIndex inner = convert_index(IsRowMajor ? col : row); Index room = m_outerIndex[outer+1] - m_outerIndex[outer]; - Index innerNNZ = m_innerNonZeros[outer]; + StorageIndex innerNNZ = m_innerNonZeros[outer]; if(innerNNZ>=room) { // this inner vector is full, we need to reallocate the whole buffer :( - reserve(SingletonVector(outer,std::max(2,innerNNZ))); + reserve(SingletonVector(outer,std::max(2,innerNNZ))); } Index startId = m_outerIndex[outer]; @@ -1139,7 +1269,7 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& Sparse m_data.value(p) = m_data.value(p-1); --p; } - eigen_assert((p<=startId || m_data.index(p-1)!=inner) && "you cannot insert an element that already exist, you must call coeffRef to this end"); + eigen_assert((p<=startId || m_data.index(p-1)!=inner) && "you cannot insert an element that already exists, you must call coeffRef to this end"); m_innerNonZeros[outer]++; @@ -1147,8 +1277,8 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& Sparse return (m_data.value(p) = 0); } -template -EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& SparseMatrix<_Scalar,_Options,_Index>::insertCompressed(Index row, Index col) +template +EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_StorageIndex>::Scalar& SparseMatrix<_Scalar,_Options,_StorageIndex>::insertCompressed(Index row, Index col) { eigen_assert(isCompressed()); @@ -1161,7 +1291,7 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& Sparse // we start a new inner vector while (previousOuter>=0 && m_outerIndex[previousOuter]==0) { - m_outerIndex[previousOuter] = static_cast(m_data.size()); + m_outerIndex[previousOuter] = convert_index(m_data.size()); --previousOuter; } m_outerIndex[outer+1] = m_outerIndex[outer]; @@ -1171,11 +1301,11 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& Sparse // starts with: [ 0 0 0 0 0 1 ...] and we are inserted in, e.g., // the 2nd inner vector... bool isLastVec = (!(previousOuter==-1 && m_data.size()!=0)) - && (size_t(m_outerIndex[outer+1]) == m_data.size()); + && (std::size_t(m_outerIndex[outer+1]) == m_data.size()); - size_t startId = m_outerIndex[outer]; - // FIXME let's make sure sizeof(long int) == sizeof(size_t) - size_t p = m_outerIndex[outer+1]; + std::size_t startId = m_outerIndex[outer]; + // FIXME let's make sure sizeof(long int) == sizeof(std::size_t) + std::size_t p = m_outerIndex[outer+1]; ++m_outerIndex[outer+1]; double reallocRatio = 1; @@ -1254,6 +1384,20 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& Sparse return (m_data.value(p) = 0); } +namespace internal { + +template +struct evaluator > + : evaluator > > +{ + typedef evaluator > > Base; + typedef SparseMatrix<_Scalar,_Options,_StorageIndex> SparseMatrixType; + evaluator() : Base() {} + explicit evaluator(const SparseMatrixType &mat) : Base(mat) {} +}; + +} + } // end namespace Eigen #endif // EIGEN_SPARSEMATRIX_H diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseMatrixBase.h b/libs/eigen3/Eigen/src/SparseCore/SparseMatrixBase.h index bbcf7fb1c..c6b548f11 100644 --- a/libs/eigen3/Eigen/src/SparseCore/SparseMatrixBase.h +++ b/libs/eigen3/Eigen/src/SparseCore/SparseMatrixBase.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2011 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -18,32 +18,41 @@ namespace Eigen { * * \brief Base class of any sparse matrices or sparse expressions * - * \tparam Derived + * \tparam Derived is the derived type, e.g. a sparse matrix type, or an expression, etc. * * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_SPARSEMATRIXBASE_PLUGIN. + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_SPARSEMATRIXBASE_PLUGIN. */ -template class SparseMatrixBase : public EigenBase +template class SparseMatrixBase + : public EigenBase { public: typedef typename internal::traits::Scalar Scalar; + + /** The numeric type of the expression' coefficients, e.g. float, double, int or std::complex, etc. + * + * It is an alias for the Scalar type */ + typedef Scalar value_type; + typedef typename internal::packet_traits::type PacketScalar; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; + + /** The integer type used to \b store indices within a SparseMatrix. + * For a \c SparseMatrix it an alias of the third template parameter \c IndexType. */ + typedef typename internal::traits::StorageIndex StorageIndex; + typedef typename internal::add_const_on_value_type_if_arithmetic< typename internal::packet_traits::type >::type PacketReturnType; typedef SparseMatrixBase StorageBaseType; - typedef EigenBase Base; + + typedef Matrix IndexVector; + typedef Matrix ScalarVector; template - Derived& operator=(const EigenBase &other) - { - other.derived().evalTo(derived()); - return derived(); - } + Derived& operator=(const EigenBase &other); enum { @@ -83,11 +92,6 @@ template class SparseMatrixBase : public EigenBase * constructed from this one. See the \ref flags "list of flags". */ - CoeffReadCost = internal::traits::CoeffReadCost, - /**< This is a rough measure of how expensive it is to read one coefficient from - * this expression. - */ - IsRowMajor = Flags&RowMajorBit ? 1 : 0, InnerSizeAtCompileTime = int(IsVectorAtCompileTime) ? int(SizeAtCompileTime) @@ -103,10 +107,11 @@ template class SparseMatrixBase : public EigenBase CwiseUnaryOp, Eigen::Transpose >, Transpose >::type AdjointReturnType; + typedef Transpose TransposeReturnType; + typedef typename internal::add_const >::type ConstTransposeReturnType; - - typedef SparseMatrix PlainObject; - + // FIXME storage order do not match evaluator storage order + typedef SparseMatrix PlainObject; #ifndef EIGEN_PARSED_BY_DOXYGEN /** This is the "real scalar" type; if the \a Scalar type is already real numbers @@ -124,6 +129,8 @@ template class SparseMatrixBase : public EigenBase /** \internal Represents a matrix with all coefficients equal to one another*/ typedef CwiseNullaryOp,Matrix > ConstantReturnType; + /** type of the equivalent dense matrix */ + typedef Matrix DenseMatrixType; /** type of the equivalent square matrix */ typedef Matrix SquareMatrixType; @@ -132,9 +139,21 @@ template class SparseMatrixBase : public EigenBase inline Derived& derived() { return *static_cast(this); } inline Derived& const_cast_derived() const { return *static_cast(const_cast(this)); } + + typedef EigenBase Base; + #endif // not EIGEN_PARSED_BY_DOXYGEN #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::SparseMatrixBase +#ifdef EIGEN_PARSED_BY_DOXYGEN +#define EIGEN_DOC_UNARY_ADDONS(METHOD,OP) /**

This method does not change the sparsity of \c *this: the OP is applied to explicitly stored coefficients only. \sa SparseCompressedBase::coeffs()

*/ +#define EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /**

\warning This method returns a read-only expression for any sparse matrices. \sa \ref TutorialSparse_SubMatrices "Sparse block operations"

*/ +#define EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(COND) /**

\warning This method returns a read-write expression for COND sparse matrices only. Otherwise, the returned expression is read-only. \sa \ref TutorialSparse_SubMatrices "Sparse block operations"

*/ +#else +#define EIGEN_DOC_UNARY_ADDONS(X,Y) +#define EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +#define EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(COND) +#endif # include "../plugins/CommonCwiseUnaryOps.h" # include "../plugins/CommonCwiseBinaryOps.h" # include "../plugins/MatrixCwiseUnaryOps.h" @@ -143,8 +162,10 @@ template class SparseMatrixBase : public EigenBase # ifdef EIGEN_SPARSEMATRIXBASE_PLUGIN # include EIGEN_SPARSEMATRIXBASE_PLUGIN # endif -# undef EIGEN_CURRENT_STORAGE_BASE_CLASS #undef EIGEN_CURRENT_STORAGE_BASE_CLASS +#undef EIGEN_DOC_UNARY_ADDONS +#undef EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +#undef EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF /** \returns the number of rows. \sa cols() */ inline Index rows() const { return derived().rows(); } @@ -153,9 +174,6 @@ template class SparseMatrixBase : public EigenBase /** \returns the number of coefficients, which is \a rows()*cols(). * \sa rows(), cols(). */ inline Index size() const { return rows() * cols(); } - /** \returns the number of nonzero coefficients which is in practice the number - * of stored coefficients. */ - inline Index nonZeros() const { return derived().nonZeros(); } /** \returns true if either the number of rows or the number of columns is equal to 1. * In other words, this function returns * \code rows()==1 || cols()==1 \endcode @@ -175,93 +193,23 @@ template class SparseMatrixBase : public EigenBase template - Derived& operator=(const ReturnByValue& other) - { - other.evalTo(derived()); - return derived(); - } - + Derived& operator=(const ReturnByValue& other); template - inline Derived& operator=(const SparseMatrixBase& other) - { - return assign(other.derived()); - } + inline Derived& operator=(const SparseMatrixBase& other); - inline Derived& operator=(const Derived& other) - { -// if (other.isRValue()) -// derived().swap(other.const_cast_derived()); -// else - return assign(other.derived()); - } + inline Derived& operator=(const Derived& other); protected: template - inline Derived& assign(const OtherDerived& other) - { - const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); - const Index outerSize = (int(OtherDerived::Flags) & RowMajorBit) ? other.rows() : other.cols(); - if ((!transpose) && other.isRValue()) - { - // eval without temporary - derived().resize(other.rows(), other.cols()); - derived().setZero(); - derived().reserve((std::max)(this->rows(),this->cols())*2); - for (Index j=0; j - inline void assignGeneric(const OtherDerived& other) - { - //const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); - eigen_assert(( ((internal::traits::SupportedAccessPatterns&OuterRandomAccessPattern)==OuterRandomAccessPattern) || - (!((Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit)))) && - "the transpose operation is supposed to be handled in SparseMatrix::operator="); - - enum { Flip = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit) }; - - const Index outerSize = other.outerSize(); - //typedef typename internal::conditional, Derived>::type TempType; - // thanks to shallow copies, we always eval to a tempary - Derived temp(other.rows(), other.cols()); - - temp.reserve((std::max)(this->rows(),this->cols())*2); - for (Index j=0; j - inline Derived& operator=(const SparseSparseProduct& product); - friend std::ostream & operator << (std::ostream & s, const SparseMatrixBase& m) { typedef typename Derived::Nested Nested; @@ -269,11 +217,12 @@ template class SparseMatrixBase : public EigenBase if (Flags&RowMajorBit) { - const Nested nm(m.derived()); + Nested nm(m.derived()); + internal::evaluator thisEval(nm); for (Index row=0; row::InnerIterator it(thisEval, row); it; ++it) { for ( ; col class SparseMatrixBase : public EigenBase } else { - const Nested nm(m.derived()); + Nested nm(m.derived()); + internal::evaluator thisEval(nm); if (m.cols() == 1) { Index row = 0; - for (typename NestedCleaned::InnerIterator it(nm.derived(), 0); it; ++it) + for (typename internal::evaluator::InnerIterator it(thisEval, 0); it; ++it) { for ( ; row class SparseMatrixBase : public EigenBase } else { - SparseMatrix trans = m; - s << static_cast >&>(trans); + SparseMatrix trans = m; + s << static_cast >&>(trans); } } return s; @@ -313,55 +263,65 @@ template class SparseMatrixBase : public EigenBase Derived& operator+=(const SparseMatrixBase& other); template Derived& operator-=(const SparseMatrixBase& other); + + template + Derived& operator+=(const DiagonalBase& other); + template + Derived& operator-=(const DiagonalBase& other); + + template + Derived& operator+=(const EigenBase &other); + template + Derived& operator-=(const EigenBase &other); Derived& operator*=(const Scalar& other); Derived& operator/=(const Scalar& other); - #define EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE \ - CwiseBinaryOp< \ - internal::scalar_product_op< \ - typename internal::scalar_product_traits< \ - typename internal::traits::Scalar, \ - typename internal::traits::Scalar \ - >::ReturnType \ - >, \ - const Derived, \ - const OtherDerived \ - > + template struct CwiseProductDenseReturnType { + typedef CwiseBinaryOp::Scalar, + typename internal::traits::Scalar + >::ReturnType>, + const Derived, + const OtherDerived + > Type; + }; template - EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE + EIGEN_STRONG_INLINE const typename CwiseProductDenseReturnType::Type cwiseProduct(const MatrixBase &other) const; - // sparse * sparse - template - const typename SparseSparseProductReturnType::Type - operator*(const SparseMatrixBase &other) const; - // sparse * diagonal template - const SparseDiagonalProduct - operator*(const DiagonalBase &other) const; + const Product + operator*(const DiagonalBase &other) const + { return Product(derived(), other.derived()); } // diagonal * sparse template friend - const SparseDiagonalProduct + const Product operator*(const DiagonalBase &lhs, const SparseMatrixBase& rhs) - { return SparseDiagonalProduct(lhs.derived(), rhs.derived()); } - - /** dense * sparse (return a dense object unless it is an outer product) */ - template friend - const typename DenseSparseProductReturnType::Type - operator*(const MatrixBase& lhs, const Derived& rhs) - { return typename DenseSparseProductReturnType::Type(lhs.derived(),rhs); } - - /** sparse * dense (returns a dense object unless it is an outer product) */ + { return Product(lhs.derived(), rhs.derived()); } + + // sparse * sparse + template + const Product + operator*(const SparseMatrixBase &other) const; + + // sparse * dense template - const typename SparseDenseProductReturnType::Type - operator*(const MatrixBase &other) const; + const Product + operator*(const MatrixBase &other) const + { return Product(derived(), other.derived()); } + + // dense * sparse + template friend + const Product + operator*(const MatrixBase &lhs, const SparseMatrixBase& rhs) + { return Product(lhs.derived(), rhs.derived()); } /** \returns an expression of P H P^-1 where H is the matrix represented by \c *this */ - SparseSymmetricPermutationProduct twistedBy(const PermutationMatrix& perm) const + SparseSymmetricPermutationProduct twistedBy(const PermutationMatrix& perm) const { return SparseSymmetricPermutationProduct(derived(), perm); } @@ -369,22 +329,16 @@ template class SparseMatrixBase : public EigenBase template Derived& operator*=(const SparseMatrixBase& other); - #ifdef EIGEN2_SUPPORT - // deprecated - template - typename internal::plain_matrix_type_column_major::type - solveTriangular(const MatrixBase& other) const; - - // deprecated - template - void solveTriangularInPlace(MatrixBase& other) const; - #endif // EIGEN2_SUPPORT - template - inline const SparseTriangularView triangularView() const; + inline const TriangularView triangularView() const; + + template struct SelfAdjointViewReturnType { typedef SparseSelfAdjointView Type; }; + template struct ConstSelfAdjointViewReturnType { typedef const SparseSelfAdjointView Type; }; - template inline const SparseSelfAdjointView selfadjointView() const; - template inline SparseSelfAdjointView selfadjointView(); + template inline + typename ConstSelfAdjointViewReturnType::Type selfadjointView() const; + template inline + typename SelfAdjointViewReturnType::Type selfadjointView(); template Scalar dot(const MatrixBase& other) const; template Scalar dot(const SparseMatrixBase& other) const; @@ -392,9 +346,9 @@ template class SparseMatrixBase : public EigenBase RealScalar norm() const; RealScalar blueNorm() const; - Transpose transpose() { return derived(); } - const Transpose transpose() const { return derived(); } - const AdjointReturnType adjoint() const { return transpose(); } + TransposeReturnType transpose() { return TransposeReturnType(derived()); } + const ConstTransposeReturnType transpose() const { return ConstTransposeReturnType(derived()); } + const AdjointReturnType adjoint() const { return AdjointReturnType(transpose()); } // inner-vector typedef Block InnerVectorReturnType; @@ -403,28 +357,19 @@ template class SparseMatrixBase : public EigenBase const ConstInnerVectorReturnType innerVector(Index outer) const; // set of inner-vectors - Block innerVectors(Index outerStart, Index outerSize); - const Block innerVectors(Index outerStart, Index outerSize) const; - - /** \internal use operator= */ - template - void evalTo(MatrixBase& dst) const - { - dst.setZero(); - for (Index j=0; j InnerVectorsReturnType; + typedef Block ConstInnerVectorsReturnType; + InnerVectorsReturnType innerVectors(Index outerStart, Index outerSize); + const ConstInnerVectorsReturnType innerVectors(Index outerStart, Index outerSize) const; - Matrix toDense() const + DenseMatrixType toDense() const { - return derived(); + return DenseMatrixType(derived()); } template bool isApprox(const SparseMatrixBase& other, - const RealScalar& prec = NumTraits::dummy_precision()) const - { return toDense().isApprox(other.toDense(),prec); } + const RealScalar& prec = NumTraits::dummy_precision()) const; template bool isApprox(const MatrixBase& other, @@ -440,10 +385,19 @@ template class SparseMatrixBase : public EigenBase { return typename internal::eval::type(derived()); } Scalar sum() const; + + inline const SparseView + pruned(const Scalar& reference = Scalar(0), const RealScalar& epsilon = NumTraits::dummy_precision()) const; protected: bool m_isRValue; + + static inline StorageIndex convert_index(const Index idx) { + return internal::convert_index(idx); + } + private: + template void evalTo(Dest &) const; }; } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/SparseCore/SparsePermutation.h b/libs/eigen3/Eigen/src/SparseCore/SparsePermutation.h index b85be93f6..ef38357ae 100644 --- a/libs/eigen3/Eigen/src/SparseCore/SparsePermutation.h +++ b/libs/eigen3/Eigen/src/SparseCore/SparsePermutation.h @@ -16,131 +16,161 @@ namespace Eigen { namespace internal { -template -struct traits > +template +struct permutation_matrix_product { - typedef typename remove_all::type MatrixTypeNestedCleaned; - typedef typename MatrixTypeNestedCleaned::Scalar Scalar; - typedef typename MatrixTypeNestedCleaned::Index Index; - enum { - SrcStorageOrder = MatrixTypeNestedCleaned::Flags&RowMajorBit ? RowMajor : ColMajor, - MoveOuter = SrcStorageOrder==RowMajor ? Side==OnTheLeft : Side==OnTheRight - }; + typedef typename nested_eval::type MatrixType; + typedef typename remove_all::type MatrixTypeCleaned; - typedef typename internal::conditional, - SparseMatrix >::type ReturnType; -}; - -template -struct permut_sparsematrix_product_retval - : public ReturnByValue > -{ - typedef typename remove_all::type MatrixTypeNestedCleaned; - typedef typename MatrixTypeNestedCleaned::Scalar Scalar; - typedef typename MatrixTypeNestedCleaned::Index Index; + typedef typename MatrixTypeCleaned::Scalar Scalar; + typedef typename MatrixTypeCleaned::StorageIndex StorageIndex; enum { - SrcStorageOrder = MatrixTypeNestedCleaned::Flags&RowMajorBit ? RowMajor : ColMajor, + SrcStorageOrder = MatrixTypeCleaned::Flags&RowMajorBit ? RowMajor : ColMajor, MoveOuter = SrcStorageOrder==RowMajor ? Side==OnTheLeft : Side==OnTheRight }; + + typedef typename internal::conditional, + SparseMatrix >::type ReturnType; - permut_sparsematrix_product_retval(const PermutationType& perm, const MatrixType& matrix) - : m_permutation(perm), m_matrix(matrix) - {} - - inline int rows() const { return m_matrix.rows(); } - inline int cols() const { return m_matrix.cols(); } - - template inline void evalTo(Dest& dst) const + template + static inline void run(Dest& dst, const PermutationType& perm, const ExpressionType& xpr) { + MatrixType mat(xpr); if(MoveOuter) { - SparseMatrix tmp(m_matrix.rows(), m_matrix.cols()); - Matrix sizes(m_matrix.outerSize()); - for(Index j=0; j tmp(mat.rows(), mat.cols()); + Matrix sizes(mat.outerSize()); + for(Index j=0; j tmp(m_matrix.rows(), m_matrix.cols()); - Matrix sizes(tmp.outerSize()); + SparseMatrix tmp(mat.rows(), mat.cols()); + Matrix sizes(tmp.outerSize()); sizes.setZero(); - PermutationMatrix perm; + PermutationMatrix perm_cpy; if((Side==OnTheLeft) ^ Transposed) - perm = m_permutation; + perm_cpy = perm; else - perm = m_permutation.transpose(); + perm_cpy = perm.transpose(); - for(Index j=0; j struct product_promote_storage_type { typedef Sparse ret; }; +template struct product_promote_storage_type { typedef Sparse ret; }; + +// TODO, the following two overloads are only needed to define the right temporary type through +// typename traits >::ReturnType +// whereas it should be correctly handled by traits >::PlainObject + +template +struct product_evaluator, ProductTag, PermutationShape, SparseShape> + : public evaluator::ReturnType> +{ + typedef Product XprType; + typedef typename permutation_matrix_product::ReturnType PlainObject; + typedef evaluator Base; + + enum { + Flags = Base::Flags | EvalBeforeNestingBit + }; + + explicit product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } +protected: + PlainObject m_result; +}; + +template +struct product_evaluator, ProductTag, SparseShape, PermutationShape > + : public evaluator::ReturnType> +{ + typedef Product XprType; + typedef typename permutation_matrix_product::ReturnType PlainObject; + typedef evaluator Base; + + enum { + Flags = Base::Flags | EvalBeforeNestingBit + }; + + explicit product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + +} // end namespace internal /** \returns the matrix with the permutation applied to the columns */ template -inline const internal::permut_sparsematrix_product_retval, SparseDerived, OnTheRight, false> +inline const Product operator*(const SparseMatrixBase& matrix, const PermutationBase& perm) -{ - return internal::permut_sparsematrix_product_retval, SparseDerived, OnTheRight, false>(perm, matrix.derived()); -} +{ return Product(matrix.derived(), perm.derived()); } /** \returns the matrix with the permutation applied to the rows */ template -inline const internal::permut_sparsematrix_product_retval, SparseDerived, OnTheLeft, false> +inline const Product operator*( const PermutationBase& perm, const SparseMatrixBase& matrix) -{ - return internal::permut_sparsematrix_product_retval, SparseDerived, OnTheLeft, false>(perm, matrix.derived()); -} - +{ return Product(perm.derived(), matrix.derived()); } /** \returns the matrix with the inverse permutation applied to the columns. */ -template -inline const internal::permut_sparsematrix_product_retval, SparseDerived, OnTheRight, true> -operator*(const SparseMatrixBase& matrix, const Transpose >& tperm) +template +inline const Product, AliasFreeProduct> +operator*(const SparseMatrixBase& matrix, const InverseImpl& tperm) { - return internal::permut_sparsematrix_product_retval, SparseDerived, OnTheRight, true>(tperm.nestedPermutation(), matrix.derived()); + return Product, AliasFreeProduct>(matrix.derived(), tperm.derived()); } /** \returns the matrix with the inverse permutation applied to the rows. */ -template -inline const internal::permut_sparsematrix_product_retval, SparseDerived, OnTheLeft, true> -operator*(const Transpose >& tperm, const SparseMatrixBase& matrix) +template +inline const Product, SparseDerived, AliasFreeProduct> +operator*(const InverseImpl& tperm, const SparseMatrixBase& matrix) { - return internal::permut_sparsematrix_product_retval, SparseDerived, OnTheLeft, true>(tperm.nestedPermutation(), matrix.derived()); + return Product, SparseDerived, AliasFreeProduct>(tperm.derived(), matrix.derived()); } } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseProduct.h b/libs/eigen3/Eigen/src/SparseCore/SparseProduct.h index cf7663070..4cbf68781 100644 --- a/libs/eigen3/Eigen/src/SparseCore/SparseProduct.h +++ b/libs/eigen3/Eigen/src/SparseCore/SparseProduct.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2008-2015 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -12,158 +12,6 @@ namespace Eigen { -template -struct SparseSparseProductReturnType -{ - typedef typename internal::traits::Scalar Scalar; - typedef typename internal::traits::Index Index; - enum { - LhsRowMajor = internal::traits::Flags & RowMajorBit, - RhsRowMajor = internal::traits::Flags & RowMajorBit, - TransposeRhs = (!LhsRowMajor) && RhsRowMajor, - TransposeLhs = LhsRowMajor && (!RhsRowMajor) - }; - - typedef typename internal::conditional, - typename internal::nested::type>::type LhsNested; - - typedef typename internal::conditional, - typename internal::nested::type>::type RhsNested; - - typedef SparseSparseProduct Type; -}; - -namespace internal { -template -struct traits > -{ - typedef MatrixXpr XprKind; - // clean the nested types: - typedef typename remove_all::type _LhsNested; - typedef typename remove_all::type _RhsNested; - typedef typename _LhsNested::Scalar Scalar; - typedef typename promote_index_type::Index, - typename traits<_RhsNested>::Index>::type Index; - - enum { - LhsCoeffReadCost = _LhsNested::CoeffReadCost, - RhsCoeffReadCost = _RhsNested::CoeffReadCost, - LhsFlags = _LhsNested::Flags, - RhsFlags = _RhsNested::Flags, - - RowsAtCompileTime = _LhsNested::RowsAtCompileTime, - ColsAtCompileTime = _RhsNested::ColsAtCompileTime, - MaxRowsAtCompileTime = _LhsNested::MaxRowsAtCompileTime, - MaxColsAtCompileTime = _RhsNested::MaxColsAtCompileTime, - - InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(_LhsNested::ColsAtCompileTime, _RhsNested::RowsAtCompileTime), - - EvalToRowMajor = (RhsFlags & LhsFlags & RowMajorBit), - - RemovedBits = ~(EvalToRowMajor ? 0 : RowMajorBit), - - Flags = (int(LhsFlags | RhsFlags) & HereditaryBits & RemovedBits) - | EvalBeforeAssigningBit - | EvalBeforeNestingBit, - - CoeffReadCost = Dynamic - }; - - typedef Sparse StorageKind; -}; - -} // end namespace internal - -template -class SparseSparseProduct : internal::no_assignment_operator, - public SparseMatrixBase > -{ - public: - - typedef SparseMatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(SparseSparseProduct) - - private: - - typedef typename internal::traits::_LhsNested _LhsNested; - typedef typename internal::traits::_RhsNested _RhsNested; - - public: - - template - EIGEN_STRONG_INLINE SparseSparseProduct(const Lhs& lhs, const Rhs& rhs) - : m_lhs(lhs), m_rhs(rhs), m_tolerance(0), m_conservative(true) - { - init(); - } - - template - EIGEN_STRONG_INLINE SparseSparseProduct(const Lhs& lhs, const Rhs& rhs, const RealScalar& tolerance) - : m_lhs(lhs), m_rhs(rhs), m_tolerance(tolerance), m_conservative(false) - { - init(); - } - - SparseSparseProduct pruned(const Scalar& reference = 0, const RealScalar& epsilon = NumTraits::dummy_precision()) const - { - using std::abs; - return SparseSparseProduct(m_lhs,m_rhs,abs(reference)*epsilon); - } - - template - void evalTo(Dest& result) const - { - if(m_conservative) - internal::conservative_sparse_sparse_product_selector<_LhsNested, _RhsNested, Dest>::run(lhs(),rhs(),result); - else - internal::sparse_sparse_product_with_pruning_selector<_LhsNested, _RhsNested, Dest>::run(lhs(),rhs(),result,m_tolerance); - } - - EIGEN_STRONG_INLINE Index rows() const { return m_lhs.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_rhs.cols(); } - - EIGEN_STRONG_INLINE const _LhsNested& lhs() const { return m_lhs; } - EIGEN_STRONG_INLINE const _RhsNested& rhs() const { return m_rhs; } - - protected: - void init() - { - eigen_assert(m_lhs.cols() == m_rhs.rows()); - - enum { - ProductIsValid = _LhsNested::ColsAtCompileTime==Dynamic - || _RhsNested::RowsAtCompileTime==Dynamic - || int(_LhsNested::ColsAtCompileTime)==int(_RhsNested::RowsAtCompileTime), - AreVectors = _LhsNested::IsVectorAtCompileTime && _RhsNested::IsVectorAtCompileTime, - SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(_LhsNested,_RhsNested) - }; - // note to the lost user: - // * for a dot product use: v1.dot(v2) - // * for a coeff-wise product use: v1.cwise()*v2 - EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), - INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) - EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), - INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) - EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) - } - - LhsNested m_lhs; - RhsNested m_rhs; - RealScalar m_tolerance; - bool m_conservative; -}; - -// sparse = sparse * sparse -template -template -inline Derived& SparseMatrixBase::operator=(const SparseSparseProduct& product) -{ - product.evalTo(derived()); - return derived(); -} - /** \returns an expression of the product of two sparse matrices. * By default a conservative product preserving the symbolic non zeros is performed. * The automatic pruning of the small values can be achieved by calling the pruned() function @@ -177,12 +25,145 @@ inline Derived& SparseMatrixBase::operator=(const SparseSparseProduct template -inline const typename SparseSparseProductReturnType::Type +inline const Product SparseMatrixBase::operator*(const SparseMatrixBase &other) const { - return typename SparseSparseProductReturnType::Type(derived(), other.derived()); + return Product(derived(), other.derived()); } +namespace internal { + +// sparse * sparse +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + evalTo(dst, lhs, rhs, typename evaluator_traits::Shape()); + } + + // dense += sparse * sparse + template + static void addTo(Dest& dst, const ActualLhs& lhs, const Rhs& rhs, typename enable_if::Shape,DenseShape>::value,int*>::type* = 0) + { + typedef typename nested_eval::type LhsNested; + typedef typename nested_eval::type RhsNested; + LhsNested lhsNested(lhs); + RhsNested rhsNested(rhs); + internal::sparse_sparse_to_dense_product_selector::type, + typename remove_all::type, Dest>::run(lhsNested,rhsNested,dst); + } + + // dense -= sparse * sparse + template + static void subTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, typename enable_if::Shape,DenseShape>::value,int*>::type* = 0) + { + addTo(dst, -lhs, rhs); + } + +protected: + + // sparse = sparse * sparse + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, SparseShape) + { + typedef typename nested_eval::type LhsNested; + typedef typename nested_eval::type RhsNested; + LhsNested lhsNested(lhs); + RhsNested rhsNested(rhs); + internal::conservative_sparse_sparse_product_selector::type, + typename remove_all::type, Dest>::run(lhsNested,rhsNested,dst); + } + + // dense = sparse * sparse + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, DenseShape) + { + dst.setZero(); + addTo(dst, lhs, rhs); + } +}; + +// sparse * sparse-triangular +template +struct generic_product_impl + : public generic_product_impl +{}; + +// sparse-triangular * sparse +template +struct generic_product_impl + : public generic_product_impl +{}; + +// dense = sparse-product (can be sparse*sparse, sparse*perm, etc.) +template< typename DstXprType, typename Lhs, typename Rhs> +struct Assignment, internal::assign_op::Scalar>, Sparse2Dense> +{ + typedef Product SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + generic_product_impl::evalTo(dst,src.lhs(),src.rhs()); + } +}; + +// dense += sparse-product (can be sparse*sparse, sparse*perm, etc.) +template< typename DstXprType, typename Lhs, typename Rhs> +struct Assignment, internal::add_assign_op::Scalar>, Sparse2Dense> +{ + typedef Product SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &) + { + generic_product_impl::addTo(dst,src.lhs(),src.rhs()); + } +}; + +// dense -= sparse-product (can be sparse*sparse, sparse*perm, etc.) +template< typename DstXprType, typename Lhs, typename Rhs> +struct Assignment, internal::sub_assign_op::Scalar>, Sparse2Dense> +{ + typedef Product SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &) + { + generic_product_impl::subTo(dst,src.lhs(),src.rhs()); + } +}; + +template +struct unary_evaluator >, IteratorBased> + : public evaluator::PlainObject> +{ + typedef SparseView > XprType; + typedef typename XprType::PlainObject PlainObject; + typedef evaluator Base; + + explicit unary_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + using std::abs; + ::new (static_cast(this)) Base(m_result); + typedef typename nested_eval::type LhsNested; + typedef typename nested_eval::type RhsNested; + LhsNested lhsNested(xpr.nestedExpression().lhs()); + RhsNested rhsNested(xpr.nestedExpression().rhs()); + + internal::sparse_sparse_product_with_pruning_selector::type, + typename remove_all::type, PlainObject>::run(lhsNested,rhsNested,m_result, + abs(xpr.reference())*xpr.epsilon()); + } + +protected: + PlainObject m_result; +}; + +} // end namespace internal + } // end namespace Eigen #endif // EIGEN_SPARSEPRODUCT_H diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseRedux.h b/libs/eigen3/Eigen/src/SparseCore/SparseRedux.h index f3da93a71..458774962 100644 --- a/libs/eigen3/Eigen/src/SparseCore/SparseRedux.h +++ b/libs/eigen3/Eigen/src/SparseCore/SparseRedux.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -18,8 +18,9 @@ SparseMatrixBase::sum() const { eigen_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix"); Scalar res(0); + internal::evaluator thisEval(derived()); for (Index j=0; j::InnerIterator iter(thisEval,j); iter; ++iter) res += iter.value(); return res; } @@ -29,7 +30,10 @@ typename internal::traits >::Scalar SparseMatrix<_Scalar,_Options,_Index>::sum() const { eigen_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix"); - return Matrix::Map(&m_data.value(0), m_data.size()).sum(); + if(this->isCompressed()) + return Matrix::Map(m_data.valuePtr(), m_data.size()).sum(); + else + return Base::sum(); } template @@ -37,7 +41,7 @@ typename internal::traits >::Scalar SparseVector<_Scalar,_Options,_Index>::sum() const { eigen_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix"); - return Matrix::Map(&m_data.value(0), m_data.size()).sum(); + return Matrix::Map(m_data.valuePtr(), m_data.size()).sum(); } } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseRef.h b/libs/eigen3/Eigen/src/SparseCore/SparseRef.h new file mode 100644 index 000000000..d91f38f97 --- /dev/null +++ b/libs/eigen3/Eigen/src/SparseCore/SparseRef.h @@ -0,0 +1,397 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSE_REF_H +#define EIGEN_SPARSE_REF_H + +namespace Eigen { + +enum { + StandardCompressedFormat = 2 /**< used by Ref to specify whether the input storage must be in standard compressed form */ +}; + +namespace internal { + +template class SparseRefBase; + +template +struct traits, _Options, _StrideType> > + : public traits > +{ + typedef SparseMatrix PlainObjectType; + enum { + Options = _Options, + Flags = traits::Flags | CompressedAccessBit | NestByRefBit + }; + + template struct match { + enum { + StorageOrderMatch = PlainObjectType::IsVectorAtCompileTime || Derived::IsVectorAtCompileTime || ((PlainObjectType::Flags&RowMajorBit)==(Derived::Flags&RowMajorBit)), + MatchAtCompileTime = (Derived::Flags&CompressedAccessBit) && StorageOrderMatch + }; + typedef typename internal::conditional::type type; + }; + +}; + +template +struct traits, _Options, _StrideType> > + : public traits, _Options, _StrideType> > +{ + enum { + Flags = (traits >::Flags | CompressedAccessBit | NestByRefBit) & ~LvalueBit + }; +}; + +template +struct traits, _Options, _StrideType> > + : public traits > +{ + typedef SparseVector PlainObjectType; + enum { + Options = _Options, + Flags = traits::Flags | CompressedAccessBit | NestByRefBit + }; + + template struct match { + enum { + MatchAtCompileTime = (Derived::Flags&CompressedAccessBit) && Derived::IsVectorAtCompileTime + }; + typedef typename internal::conditional::type type; + }; + +}; + +template +struct traits, _Options, _StrideType> > + : public traits, _Options, _StrideType> > +{ + enum { + Flags = (traits >::Flags | CompressedAccessBit | NestByRefBit) & ~LvalueBit + }; +}; + +template +struct traits > : public traits {}; + +template class SparseRefBase + : public SparseMapBase +{ +public: + + typedef SparseMapBase Base; + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseRefBase) + + SparseRefBase() + : Base(RowsAtCompileTime==Dynamic?0:RowsAtCompileTime,ColsAtCompileTime==Dynamic?0:ColsAtCompileTime, 0, 0, 0, 0, 0) + {} + +protected: + + template + void construct(Expression& expr) + { + if(expr.outerIndexPtr()==0) + ::new (static_cast(this)) Base(expr.size(), expr.nonZeros(), expr.innerIndexPtr(), expr.valuePtr()); + else + ::new (static_cast(this)) Base(expr.rows(), expr.cols(), expr.nonZeros(), expr.outerIndexPtr(), expr.innerIndexPtr(), expr.valuePtr(), expr.innerNonZeroPtr()); + } +}; + +} // namespace internal + + +/** + * \ingroup SparseCore_Module + * + * \brief A sparse matrix expression referencing an existing sparse expression + * + * \tparam SparseMatrixType the equivalent sparse matrix type of the referenced data, it must be a template instance of class SparseMatrix. + * \tparam Options specifies whether the a standard compressed format is required \c Options is \c #StandardCompressedFormat, or \c 0. + * The default is \c 0. + * + * \sa class Ref + */ +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +class Ref, Options, StrideType > + : public internal::SparseRefBase, Options, StrideType > > +#else +template +class Ref + : public SparseMapBase // yes, that's weird to use Derived here, but that works! +#endif +{ + typedef SparseMatrix PlainObjectType; + typedef internal::traits Traits; + template + inline Ref(const SparseMatrix& expr); + template + inline Ref(const MappedSparseMatrix& expr); + public: + + typedef internal::SparseRefBase Base; + EIGEN_SPARSE_PUBLIC_INTERFACE(Ref) + + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + inline Ref(SparseMatrix& expr) + { + EIGEN_STATIC_ASSERT(bool(Traits::template match >::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); + eigen_assert( ((Options & int(StandardCompressedFormat))==0) || (expr.isCompressed()) ); + Base::construct(expr.derived()); + } + + template + inline Ref(MappedSparseMatrix& expr) + { + EIGEN_STATIC_ASSERT(bool(Traits::template match >::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); + eigen_assert( ((Options & int(StandardCompressedFormat))==0) || (expr.isCompressed()) ); + Base::construct(expr.derived()); + } + + template + inline Ref(const SparseCompressedBase& expr) + #else + /** Implicit constructor from any sparse expression (2D matrix or 1D vector) */ + template + inline Ref(SparseCompressedBase& expr) + #endif + { + EIGEN_STATIC_ASSERT(bool(internal::is_lvalue::value), THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); + EIGEN_STATIC_ASSERT(bool(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); + eigen_assert( ((Options & int(StandardCompressedFormat))==0) || (expr.isCompressed()) ); + Base::construct(expr.const_cast_derived()); + } +}; + +// this is the const ref version +template +class Ref, Options, StrideType> + : public internal::SparseRefBase, Options, StrideType> > +{ + typedef SparseMatrix TPlainObjectType; + typedef internal::traits Traits; + public: + + typedef internal::SparseRefBase Base; + EIGEN_SPARSE_PUBLIC_INTERFACE(Ref) + + template + inline Ref(const SparseMatrixBase& expr) : m_hasCopy(false) + { + construct(expr.derived(), typename Traits::template match::type()); + } + + inline Ref(const Ref& other) : Base(other), m_hasCopy(false) { + // copy constructor shall not copy the m_object, to avoid unnecessary malloc and copy + } + + template + inline Ref(const RefBase& other) : m_hasCopy(false) { + construct(other.derived(), typename Traits::template match::type()); + } + + ~Ref() { + if(m_hasCopy) { + TPlainObjectType* obj = reinterpret_cast(m_object_bytes); + obj->~TPlainObjectType(); + } + } + + protected: + + template + void construct(const Expression& expr,internal::true_type) + { + if((Options & int(StandardCompressedFormat)) && (!expr.isCompressed())) + { + TPlainObjectType* obj = reinterpret_cast(m_object_bytes); + ::new (obj) TPlainObjectType(expr); + m_hasCopy = true; + Base::construct(*obj); + } + else + { + Base::construct(expr); + } + } + + template + void construct(const Expression& expr, internal::false_type) + { + TPlainObjectType* obj = reinterpret_cast(m_object_bytes); + ::new (obj) TPlainObjectType(expr); + m_hasCopy = true; + Base::construct(*obj); + } + + protected: + char m_object_bytes[sizeof(TPlainObjectType)]; + bool m_hasCopy; +}; + + + +/** + * \ingroup SparseCore_Module + * + * \brief A sparse vector expression referencing an existing sparse vector expression + * + * \tparam SparseVectorType the equivalent sparse vector type of the referenced data, it must be a template instance of class SparseVector. + * + * \sa class Ref + */ +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +class Ref, Options, StrideType > + : public internal::SparseRefBase, Options, StrideType > > +#else +template +class Ref + : public SparseMapBase +#endif +{ + typedef SparseVector PlainObjectType; + typedef internal::traits Traits; + template + inline Ref(const SparseVector& expr); + public: + + typedef internal::SparseRefBase Base; + EIGEN_SPARSE_PUBLIC_INTERFACE(Ref) + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + inline Ref(SparseVector& expr) + { + EIGEN_STATIC_ASSERT(bool(Traits::template match >::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); + Base::construct(expr.derived()); + } + + template + inline Ref(const SparseCompressedBase& expr) + #else + /** Implicit constructor from any 1D sparse vector expression */ + template + inline Ref(SparseCompressedBase& expr) + #endif + { + EIGEN_STATIC_ASSERT(bool(internal::is_lvalue::value), THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); + EIGEN_STATIC_ASSERT(bool(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); + Base::construct(expr.const_cast_derived()); + } +}; + +// this is the const ref version +template +class Ref, Options, StrideType> + : public internal::SparseRefBase, Options, StrideType> > +{ + typedef SparseVector TPlainObjectType; + typedef internal::traits Traits; + public: + + typedef internal::SparseRefBase Base; + EIGEN_SPARSE_PUBLIC_INTERFACE(Ref) + + template + inline Ref(const SparseMatrixBase& expr) : m_hasCopy(false) + { + construct(expr.derived(), typename Traits::template match::type()); + } + + inline Ref(const Ref& other) : Base(other), m_hasCopy(false) { + // copy constructor shall not copy the m_object, to avoid unnecessary malloc and copy + } + + template + inline Ref(const RefBase& other) : m_hasCopy(false) { + construct(other.derived(), typename Traits::template match::type()); + } + + ~Ref() { + if(m_hasCopy) { + TPlainObjectType* obj = reinterpret_cast(m_object_bytes); + obj->~TPlainObjectType(); + } + } + + protected: + + template + void construct(const Expression& expr,internal::true_type) + { + Base::construct(expr); + } + + template + void construct(const Expression& expr, internal::false_type) + { + TPlainObjectType* obj = reinterpret_cast(m_object_bytes); + ::new (obj) TPlainObjectType(expr); + m_hasCopy = true; + Base::construct(*obj); + } + + protected: + char m_object_bytes[sizeof(TPlainObjectType)]; + bool m_hasCopy; +}; + +namespace internal { + +// FIXME shall we introduce a general evaluatior_ref that we can specialize for any sparse object once, and thus remove this copy-pasta thing... + +template +struct evaluator, Options, StrideType> > + : evaluator, Options, StrideType> > > +{ + typedef evaluator, Options, StrideType> > > Base; + typedef Ref, Options, StrideType> XprType; + evaluator() : Base() {} + explicit evaluator(const XprType &mat) : Base(mat) {} +}; + +template +struct evaluator, Options, StrideType> > + : evaluator, Options, StrideType> > > +{ + typedef evaluator, Options, StrideType> > > Base; + typedef Ref, Options, StrideType> XprType; + evaluator() : Base() {} + explicit evaluator(const XprType &mat) : Base(mat) {} +}; + +template +struct evaluator, Options, StrideType> > + : evaluator, Options, StrideType> > > +{ + typedef evaluator, Options, StrideType> > > Base; + typedef Ref, Options, StrideType> XprType; + evaluator() : Base() {} + explicit evaluator(const XprType &mat) : Base(mat) {} +}; + +template +struct evaluator, Options, StrideType> > + : evaluator, Options, StrideType> > > +{ + typedef evaluator, Options, StrideType> > > Base; + typedef Ref, Options, StrideType> XprType; + evaluator() : Base() {} + explicit evaluator(const XprType &mat) : Base(mat) {} +}; + +} + +} // end namespace Eigen + +#endif // EIGEN_SPARSE_REF_H diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseSelfAdjointView.h b/libs/eigen3/Eigen/src/SparseCore/SparseSelfAdjointView.h index 0eda96bc4..5ab64f1a8 100644 --- a/libs/eigen3/Eigen/src/SparseCore/SparseSelfAdjointView.h +++ b/libs/eigen3/Eigen/src/SparseCore/SparseSelfAdjointView.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2009-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -11,14 +11,14 @@ #define EIGEN_SPARSE_SELFADJOINTVIEW_H namespace Eigen { - + /** \ingroup SparseCore_Module * \class SparseSelfAdjointView * * \brief Pseudo expression to manipulate a triangular sparse matrix as a selfadjoint matrix. * * \param MatrixType the type of the dense matrix storing the coefficients - * \param UpLo can be either \c #Lower or \c #Upper + * \param Mode can be either \c #Lower or \c #Upper * * This class is an expression of a sefladjoint matrix from a triangular part of a matrix * with given dense storage of the coefficients. It is the return type of MatrixBase::selfadjointView() @@ -26,38 +26,40 @@ namespace Eigen { * * \sa SparseMatrixBase::selfadjointView() */ -template -class SparseSelfAdjointTimeDenseProduct; - -template -class DenseTimeSparseSelfAdjointProduct; - namespace internal { -template -struct traits > : traits { +template +struct traits > : traits { }; -template -void permute_symm_to_symm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm = 0); +template +void permute_symm_to_symm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::StorageIndex* perm = 0); -template -void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm = 0); +template +void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::StorageIndex* perm = 0); } -template class SparseSelfAdjointView - : public EigenBase > +template class SparseSelfAdjointView + : public EigenBase > { public: - + + enum { + Mode = _Mode, + TransposeMode = ((Mode & Upper) ? Lower : 0) | ((Mode & Lower) ? Upper : 0), + RowsAtCompileTime = internal::traits::RowsAtCompileTime, + ColsAtCompileTime = internal::traits::ColsAtCompileTime + }; + + typedef EigenBase Base; typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::Index Index; - typedef Matrix VectorI; - typedef typename MatrixType::Nested MatrixTypeNested; + typedef typename MatrixType::StorageIndex StorageIndex; + typedef Matrix VectorI; + typedef typename internal::ref_selector::non_const_type MatrixTypeNested; typedef typename internal::remove_all::type _MatrixTypeNested; - - inline SparseSelfAdjointView(const MatrixType& matrix) : m_matrix(matrix) + + explicit inline SparseSelfAdjointView(MatrixType& matrix) : m_matrix(matrix) { eigen_assert(rows()==cols() && "SelfAdjointView is only for squared matrices"); } @@ -67,7 +69,7 @@ template class SparseSelfAdjointView /** \internal \returns a reference to the nested matrix */ const _MatrixTypeNested& matrix() const { return m_matrix; } - _MatrixTypeNested& matrix() { return m_matrix.const_cast_derived(); } + typename internal::remove_reference::type& matrix() { return m_matrix; } /** \returns an expression of the matrix product between a sparse self-adjoint matrix \c *this and a sparse matrix \a rhs. * @@ -75,10 +77,10 @@ template class SparseSelfAdjointView * Indeed, the SparseSelfadjointView operand is first copied into a temporary SparseMatrix before computing the product. */ template - SparseSparseProduct + Product operator*(const SparseMatrixBase& rhs) const { - return SparseSparseProduct(*this, rhs.derived()); + return Product(*this, rhs.derived()); } /** \returns an expression of the matrix product between a sparse matrix \a lhs and a sparse self-adjoint matrix \a rhs. @@ -87,26 +89,26 @@ template class SparseSelfAdjointView * Indeed, the SparseSelfadjointView operand is first copied into a temporary SparseMatrix before computing the product. */ template friend - SparseSparseProduct + Product operator*(const SparseMatrixBase& lhs, const SparseSelfAdjointView& rhs) { - return SparseSparseProduct(lhs.derived(), rhs); + return Product(lhs.derived(), rhs); } /** Efficient sparse self-adjoint matrix times dense vector/matrix product */ template - SparseSelfAdjointTimeDenseProduct + Product operator*(const MatrixBase& rhs) const { - return SparseSelfAdjointTimeDenseProduct(m_matrix, rhs.derived()); + return Product(*this, rhs.derived()); } /** Efficient dense vector/matrix times sparse self-adjoint matrix product */ template friend - DenseTimeSparseSelfAdjointProduct + Product operator*(const MatrixBase& lhs, const SparseSelfAdjointView& rhs) { - return DenseTimeSparseSelfAdjointProduct(lhs.derived(), rhs.m_matrix); + return Product(lhs.derived(), rhs); } /** Perform a symmetric rank K update of the selfadjoint matrix \c *this: @@ -120,56 +122,48 @@ template class SparseSelfAdjointView template SparseSelfAdjointView& rankUpdate(const SparseMatrixBase& u, const Scalar& alpha = Scalar(1)); - /** \internal triggered by sparse_matrix = SparseSelfadjointView; */ - template void evalTo(SparseMatrix& _dest) const - { - internal::permute_symm_to_fullsymm(m_matrix, _dest); - } - - template void evalTo(DynamicSparseMatrix& _dest) const - { - // TODO directly evaluate into _dest; - SparseMatrix tmp(_dest.rows(),_dest.cols()); - internal::permute_symm_to_fullsymm(m_matrix, tmp); - _dest = tmp; - } - /** \returns an expression of P H P^-1 */ - SparseSymmetricPermutationProduct<_MatrixTypeNested,UpLo> twistedBy(const PermutationMatrix& perm) const + // TODO implement twists in a more evaluator friendly fashion + SparseSymmetricPermutationProduct<_MatrixTypeNested,Mode> twistedBy(const PermutationMatrix& perm) const { - return SparseSymmetricPermutationProduct<_MatrixTypeNested,UpLo>(m_matrix, perm); + return SparseSymmetricPermutationProduct<_MatrixTypeNested,Mode>(m_matrix, perm); } - - template - SparseSelfAdjointView& operator=(const SparseSymmetricPermutationProduct& permutedMatrix) + + template + SparseSelfAdjointView& operator=(const SparseSymmetricPermutationProduct& permutedMatrix) { - permutedMatrix.evalTo(*this); + internal::call_assignment_no_alias_no_transpose(*this, permutedMatrix); return *this; } - SparseSelfAdjointView& operator=(const SparseSelfAdjointView& src) { - PermutationMatrix pnull; + PermutationMatrix pnull; return *this = src.twistedBy(pnull); } - template - SparseSelfAdjointView& operator=(const SparseSelfAdjointView& src) + template + SparseSelfAdjointView& operator=(const SparseSelfAdjointView& src) { - PermutationMatrix pnull; + PermutationMatrix pnull; return *this = src.twistedBy(pnull); } - - // const SparseLLT llt() const; - // const SparseLDLT ldlt() const; - + void resize(Index rows, Index cols) + { + EIGEN_ONLY_USED_FOR_DEBUG(rows); + EIGEN_ONLY_USED_FOR_DEBUG(cols); + eigen_assert(rows == this->rows() && cols == this->cols() + && "SparseSelfadjointView::resize() does not actually allow to resize."); + } + protected: - typename MatrixType::Nested m_matrix; - mutable VectorI m_countPerRow; - mutable VectorI m_countPerCol; + MatrixTypeNested m_matrix; + //mutable VectorI m_countPerRow; + //mutable VectorI m_countPerCol; + private: + template void evalTo(Dest &) const; }; /*************************************************************************** @@ -178,146 +172,268 @@ template class SparseSelfAdjointView template template -const SparseSelfAdjointView SparseMatrixBase::selfadjointView() const +typename SparseMatrixBase::template ConstSelfAdjointViewReturnType::Type SparseMatrixBase::selfadjointView() const { - return derived(); + return SparseSelfAdjointView(derived()); } template template -SparseSelfAdjointView SparseMatrixBase::selfadjointView() +typename SparseMatrixBase::template SelfAdjointViewReturnType::Type SparseMatrixBase::selfadjointView() { - return derived(); + return SparseSelfAdjointView(derived()); } /*************************************************************************** * Implementation of SparseSelfAdjointView methods ***************************************************************************/ -template +template template -SparseSelfAdjointView& -SparseSelfAdjointView::rankUpdate(const SparseMatrixBase& u, const Scalar& alpha) +SparseSelfAdjointView& +SparseSelfAdjointView::rankUpdate(const SparseMatrixBase& u, const Scalar& alpha) { - SparseMatrix tmp = u * u.adjoint(); + SparseMatrix tmp = u * u.adjoint(); if(alpha==Scalar(0)) - m_matrix.const_cast_derived() = tmp.template triangularView(); + m_matrix = tmp.template triangularView(); else - m_matrix.const_cast_derived() += alpha * tmp.template triangularView(); + m_matrix += alpha * tmp.template triangularView(); return *this; } +namespace internal { + +// TODO currently a selfadjoint expression has the form SelfAdjointView<.,.> +// in the future selfadjoint-ness should be defined by the expression traits +// such that Transpose > is valid. (currently TriangularBase::transpose() is overloaded to make it work) +template +struct evaluator_traits > +{ + typedef typename storage_kind_to_evaluator_kind::Kind Kind; + typedef SparseSelfAdjointShape Shape; +}; + +struct SparseSelfAdjoint2Sparse {}; + +template<> struct AssignmentKind { typedef SparseSelfAdjoint2Sparse Kind; }; +template<> struct AssignmentKind { typedef Sparse2Sparse Kind; }; + +template< typename DstXprType, typename SrcXprType, typename Functor> +struct Assignment +{ + typedef typename DstXprType::StorageIndex StorageIndex; + typedef internal::assign_op AssignOpType; + + template + static void run(SparseMatrix &dst, const SrcXprType &src, const AssignOpType&/*func*/) + { + internal::permute_symm_to_fullsymm(src.matrix(), dst); + } + + // FIXME: the handling of += and -= in sparse matrices should be cleanup so that next two overloads could be reduced to: + template + static void run(SparseMatrix &dst, const SrcXprType &src, const AssignFunc& func) + { + SparseMatrix tmp(src.rows(),src.cols()); + run(tmp, src, AssignOpType()); + call_assignment_no_alias_no_transpose(dst, tmp, func); + } + + template + static void run(SparseMatrix &dst, const SrcXprType &src, + const internal::add_assign_op& /* func */) + { + SparseMatrix tmp(src.rows(),src.cols()); + run(tmp, src, AssignOpType()); + dst += tmp; + } + + template + static void run(SparseMatrix &dst, const SrcXprType &src, + const internal::sub_assign_op& /* func */) + { + SparseMatrix tmp(src.rows(),src.cols()); + run(tmp, src, AssignOpType()); + dst -= tmp; + } + + template + static void run(DynamicSparseMatrix& dst, const SrcXprType &src, const AssignOpType&/*func*/) + { + // TODO directly evaluate into dst; + SparseMatrix tmp(dst.rows(),dst.cols()); + internal::permute_symm_to_fullsymm(src.matrix(), tmp); + dst = tmp; + } +}; + +} // end namespace internal + /*************************************************************************** * Implementation of sparse self-adjoint time dense matrix ***************************************************************************/ namespace internal { -template -struct traits > - : traits, Lhs, Rhs> > -{ - typedef Dense StorageKind; -}; -} -template -class SparseSelfAdjointTimeDenseProduct - : public ProductBase, Lhs, Rhs> +template +inline void sparse_selfadjoint_time_dense_product(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const AlphaType& alpha) { - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(SparseSelfAdjointTimeDenseProduct) - - SparseSelfAdjointTimeDenseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - {} + EIGEN_ONLY_USED_FOR_DEBUG(alpha); + + typedef typename internal::nested_eval::type SparseLhsTypeNested; + typedef typename internal::remove_all::type SparseLhsTypeNestedCleaned; + typedef evaluator LhsEval; + typedef typename LhsEval::InnerIterator LhsIterator; + typedef typename SparseLhsType::Scalar LhsScalar; + + enum { + LhsIsRowMajor = (LhsEval::Flags&RowMajorBit)==RowMajorBit, + ProcessFirstHalf = + ((Mode&(Upper|Lower))==(Upper|Lower)) + || ( (Mode&Upper) && !LhsIsRowMajor) + || ( (Mode&Lower) && LhsIsRowMajor), + ProcessSecondHalf = !ProcessFirstHalf + }; + + SparseLhsTypeNested lhs_nested(lhs); + LhsEval lhsEval(lhs_nested); - template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const + // work on one column at once + for (Index k=0; k::type _Lhs; - typedef typename _Lhs::InnerIterator LhsInnerIterator; - enum { - LhsIsRowMajor = (_Lhs::Flags&RowMajorBit)==RowMajorBit, - ProcessFirstHalf = - ((UpLo&(Upper|Lower))==(Upper|Lower)) - || ( (UpLo&Upper) && !LhsIsRowMajor) - || ( (UpLo&Lower) && LhsIsRowMajor), - ProcessSecondHalf = !ProcessFirstHalf - }; - for (Index j=0; j::ReturnType rhs_j(alpha*rhs(j,k)); + // accumulator for partial scalar product + typename DenseResType::Scalar res_j(0); + for(; (ProcessFirstHalf ? i && i.index() < j : i) ; ++i) + { + LhsScalar lhs_ij = i.value(); + if(!LhsIsRowMajor) lhs_ij = numext::conj(lhs_ij); + res_j += lhs_ij * rhs(i.index(),k); + res(i.index(),k) += numext::conj(lhs_ij) * rhs_j; + } + res(j,k) += alpha * res_j; + + // handle diagonal coeff + if (ProcessFirstHalf && i && (i.index()==j)) + res(j,k) += alpha * i.value() * rhs(j,k); } + } +} - private: - SparseSelfAdjointTimeDenseProduct& operator=(const SparseSelfAdjointTimeDenseProduct&); + +template +struct generic_product_impl +: generic_product_impl_base > +{ + template + static void scaleAndAddTo(Dest& dst, const LhsView& lhsView, const Rhs& rhs, const typename Dest::Scalar& alpha) + { + typedef typename LhsView::_MatrixTypeNested Lhs; + typedef typename nested_eval::type LhsNested; + typedef typename nested_eval::type RhsNested; + LhsNested lhsNested(lhsView.matrix()); + RhsNested rhsNested(rhs); + + internal::sparse_selfadjoint_time_dense_product(lhsNested, rhsNested, dst, alpha); + } }; -namespace internal { -template -struct traits > - : traits, Lhs, Rhs> > -{}; -} +template +struct generic_product_impl +: generic_product_impl_base > +{ + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const RhsView& rhsView, const typename Dest::Scalar& alpha) + { + typedef typename RhsView::_MatrixTypeNested Rhs; + typedef typename nested_eval::type LhsNested; + typedef typename nested_eval::type RhsNested; + LhsNested lhsNested(lhs); + RhsNested rhsNested(rhsView.matrix()); + + // transpose everything + Transpose dstT(dst); + internal::sparse_selfadjoint_time_dense_product(rhsNested.transpose(), lhsNested.transpose(), dstT, alpha); + } +}; -template -class DenseTimeSparseSelfAdjointProduct - : public ProductBase, Lhs, Rhs> +// NOTE: these two overloads are needed to evaluate the sparse selfadjoint view into a full sparse matrix +// TODO: maybe the copy could be handled by generic_product_impl so that these overloads would not be needed anymore + +template +struct product_evaluator, ProductTag, SparseSelfAdjointShape, SparseShape> + : public evaluator::PlainObject> { - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(DenseTimeSparseSelfAdjointProduct) + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef evaluator Base; - DenseTimeSparseSelfAdjointProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - {} + product_evaluator(const XprType& xpr) + : m_lhs(xpr.lhs()), m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, m_lhs, xpr.rhs()); + } + +protected: + typename Rhs::PlainObject m_lhs; + PlainObject m_result; +}; - template void scaleAndAddTo(Dest& /*dest*/, const Scalar& /*alpha*/) const - { - // TODO - } +template +struct product_evaluator, ProductTag, SparseShape, SparseSelfAdjointShape> + : public evaluator::PlainObject> +{ + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef evaluator Base; - private: - DenseTimeSparseSelfAdjointProduct& operator=(const DenseTimeSparseSelfAdjointProduct&); + product_evaluator(const XprType& xpr) + : m_rhs(xpr.rhs()), m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), m_rhs); + } + +protected: + typename Lhs::PlainObject m_rhs; + PlainObject m_result; }; +} // namespace internal + /*************************************************************************** * Implementation of symmetric copies and permutations ***************************************************************************/ namespace internal { - -template -struct traits > : traits { -}; -template -void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm) +template +void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::StorageIndex* perm) { - typedef typename MatrixType::Index Index; + typedef typename MatrixType::StorageIndex StorageIndex; typedef typename MatrixType::Scalar Scalar; - typedef SparseMatrix Dest; - typedef Matrix VectorI; + typedef SparseMatrix Dest; + typedef Matrix VectorI; + typedef evaluator MatEval; + typedef typename evaluator::InnerIterator MatIterator; + MatEval matEval(mat); Dest& dest(_dest.derived()); enum { StorageOrderMatch = int(Dest::IsRowMajor) == int(MatrixType::IsRowMajor) @@ -331,17 +447,17 @@ void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrixc) || ( UpLo==Upper && rc) || ( Mode==Upper && r(it.index()); Index r = it.row(); Index c = it.col(); - Index jp = perm ? perm[j] : j; - Index ip = perm ? perm[i] : i; + StorageIndex jp = perm ? perm[j] : j; + StorageIndex ip = perm ? perm[i] : i; - if(UpLo==(Upper|Lower)) + if(Mode==(Upper|Lower)) { Index k = count[StorageOrderMatch ? jp : ip]++; dest.innerIndexPtr()[k] = StorageOrderMatch ? ip : jp; @@ -382,7 +498,7 @@ void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrixc) || ( (UpLo&Upper)==Upper && rc) || ( (Mode&Upper)==Upper && r -void permute_symm_to_symm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm) +template +void permute_symm_to_symm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::StorageIndex* perm) { - typedef typename MatrixType::Index Index; + typedef typename MatrixType::StorageIndex StorageIndex; typedef typename MatrixType::Scalar Scalar; - SparseMatrix& dest(_dest.derived()); - typedef Matrix VectorI; + SparseMatrix& dest(_dest.derived()); + typedef Matrix VectorI; + typedef evaluator MatEval; + typedef typename evaluator::InnerIterator MatIterator; + enum { SrcOrder = MatrixType::IsRowMajor ? RowMajor : ColMajor, StorageOrderMatch = int(SrcOrder) == int(DstOrder), - DstUpLo = DstOrder==RowMajor ? (_DstUpLo==Upper ? Lower : Upper) : _DstUpLo, - SrcUpLo = SrcOrder==RowMajor ? (_SrcUpLo==Upper ? Lower : Upper) : _SrcUpLo + DstMode = DstOrder==RowMajor ? (_DstMode==Upper ? Lower : Upper) : _DstMode, + SrcMode = SrcOrder==RowMajor ? (_SrcMode==Upper ? Lower : Upper) : _SrcMode }; + + MatEval matEval(mat); Index size = mat.rows(); VectorI count(size); count.setZero(); dest.resize(size,size); - for(Index j = 0; jj)) + StorageIndex i = it.index(); + if((int(SrcMode)==int(Lower) && ij)) continue; - Index ip = perm ? perm[i] : i; - count[int(DstUpLo)==int(Lower) ? (std::min)(ip,jp) : (std::max)(ip,jp)]++; + StorageIndex ip = perm ? perm[i] : i; + count[int(DstMode)==int(Lower) ? (std::min)(ip,jp) : (std::max)(ip,jp)]++; } } dest.outerIndexPtr()[0] = 0; @@ -435,23 +556,23 @@ void permute_symm_to_symm(const MatrixType& mat, SparseMatrixj)) + StorageIndex i = it.index(); + if((int(SrcMode)==int(Lower) && ij)) continue; - Index jp = perm ? perm[j] : j; - Index ip = perm? perm[i] : i; + StorageIndex jp = perm ? perm[j] : j; + StorageIndex ip = perm? perm[i] : i; - Index k = count[int(DstUpLo)==int(Lower) ? (std::min)(ip,jp) : (std::max)(ip,jp)]++; - dest.innerIndexPtr()[k] = int(DstUpLo)==int(Lower) ? (std::max)(ip,jp) : (std::min)(ip,jp); + Index k = count[int(DstMode)==int(Lower) ? (std::min)(ip,jp) : (std::max)(ip,jp)]++; + dest.innerIndexPtr()[k] = int(DstMode)==int(Lower) ? (std::max)(ip,jp) : (std::min)(ip,jp); if(!StorageOrderMatch) std::swap(ip,jp); - if( ((int(DstUpLo)==int(Lower) && ipjp))) + if( ((int(DstMode)==int(Lower) && ipjp))) dest.valuePtr()[k] = numext::conj(it.value()); else dest.valuePtr()[k] = it.value(); @@ -461,19 +582,33 @@ void permute_symm_to_symm(const MatrixType& mat, SparseMatrix +// TODO implement twists in a more evaluator friendly fashion + +namespace internal { + +template +struct traits > : traits { +}; + +} + +template class SparseSymmetricPermutationProduct - : public EigenBase > + : public EigenBase > { public: typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::Index Index; + typedef typename MatrixType::StorageIndex StorageIndex; + enum { + RowsAtCompileTime = internal::traits::RowsAtCompileTime, + ColsAtCompileTime = internal::traits::ColsAtCompileTime + }; protected: - typedef PermutationMatrix Perm; + typedef PermutationMatrix Perm; public: - typedef Matrix VectorI; + typedef Matrix VectorI; typedef typename MatrixType::Nested MatrixTypeNested; - typedef typename internal::remove_all::type _MatrixTypeNested; + typedef typename internal::remove_all::type NestedExpression; SparseSymmetricPermutationProduct(const MatrixType& mat, const Perm& perm) : m_matrix(mat), m_perm(perm) @@ -481,20 +616,9 @@ class SparseSymmetricPermutationProduct inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } - - template - void evalTo(SparseMatrix& _dest) const - { -// internal::permute_symm_to_fullsymm(m_matrix,_dest,m_perm.indices().data()); - SparseMatrix tmp; - internal::permute_symm_to_fullsymm(m_matrix,tmp,m_perm.indices().data()); - _dest = tmp; - } - - template void evalTo(SparseSelfAdjointView& dest) const - { - internal::permute_symm_to_symm(m_matrix,dest.matrix(),m_perm.indices().data()); - } + + const NestedExpression& matrix() const { return m_matrix; } + const Perm& perm() const { return m_perm; } protected: MatrixTypeNested m_matrix; @@ -502,6 +626,31 @@ class SparseSymmetricPermutationProduct }; +namespace internal { + +template +struct Assignment, internal::assign_op, Sparse2Sparse> +{ + typedef SparseSymmetricPermutationProduct SrcXprType; + typedef typename DstXprType::StorageIndex DstIndex; + template + static void run(SparseMatrix &dst, const SrcXprType &src, const internal::assign_op &) + { + // internal::permute_symm_to_fullsymm(m_matrix,_dest,m_perm.indices().data()); + SparseMatrix tmp; + internal::permute_symm_to_fullsymm(src.matrix(),tmp,src.perm().indices().data()); + dst = tmp; + } + + template + static void run(SparseSelfAdjointView& dst, const SrcXprType &src, const internal::assign_op &) + { + internal::permute_symm_to_symm(src.matrix(),dst.matrix(),src.perm().indices().data()); + } +}; + +} // end namespace internal + } // end namespace Eigen #endif // EIGEN_SPARSE_SELFADJOINTVIEW_H diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseSolverBase.h b/libs/eigen3/Eigen/src/SparseCore/SparseSolverBase.h new file mode 100644 index 000000000..b4c9a422f --- /dev/null +++ b/libs/eigen3/Eigen/src/SparseCore/SparseSolverBase.h @@ -0,0 +1,124 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSESOLVERBASE_H +#define EIGEN_SPARSESOLVERBASE_H + +namespace Eigen { + +namespace internal { + + /** \internal + * Helper functions to solve with a sparse right-hand-side and result. + * The rhs is decomposed into small vertical panels which are solved through dense temporaries. + */ +template +typename enable_if::type +solve_sparse_through_dense_panels(const Decomposition &dec, const Rhs& rhs, Dest &dest) +{ + EIGEN_STATIC_ASSERT((Dest::Flags&RowMajorBit)==0,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); + typedef typename Dest::Scalar DestScalar; + // we process the sparse rhs per block of NbColsAtOnce columns temporarily stored into a dense matrix. + static const Index NbColsAtOnce = 4; + Index rhsCols = rhs.cols(); + Index size = rhs.rows(); + // the temporary matrices do not need more columns than NbColsAtOnce: + Index tmpCols = (std::min)(rhsCols, NbColsAtOnce); + Eigen::Matrix tmp(size,tmpCols); + Eigen::Matrix tmpX(size,tmpCols); + for(Index k=0; k(rhsCols-k, NbColsAtOnce); + tmp.leftCols(actualCols) = rhs.middleCols(k,actualCols); + tmpX.leftCols(actualCols) = dec.solve(tmp.leftCols(actualCols)); + dest.middleCols(k,actualCols) = tmpX.leftCols(actualCols).sparseView(); + } +} + +// Overload for vector as rhs +template +typename enable_if::type +solve_sparse_through_dense_panels(const Decomposition &dec, const Rhs& rhs, Dest &dest) +{ + typedef typename Dest::Scalar DestScalar; + Index size = rhs.rows(); + Eigen::Matrix rhs_dense(rhs); + Eigen::Matrix dest_dense(size); + dest_dense = dec.solve(rhs_dense); + dest = dest_dense.sparseView(); +} + +} // end namespace internal + +/** \class SparseSolverBase + * \ingroup SparseCore_Module + * \brief A base class for sparse solvers + * + * \tparam Derived the actual type of the solver. + * + */ +template +class SparseSolverBase : internal::noncopyable +{ + public: + + /** Default constructor */ + SparseSolverBase() + : m_isInitialized(false) + {} + + ~SparseSolverBase() + {} + + Derived& derived() { return *static_cast(this); } + const Derived& derived() const { return *static_cast(this); } + + /** \returns an expression of the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \sa compute() + */ + template + inline const Solve + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "Solver is not initialized."); + eigen_assert(derived().rows()==b.rows() && "solve(): invalid number of rows of the right hand side matrix b"); + return Solve(derived(), b.derived()); + } + + /** \returns an expression of the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \sa compute() + */ + template + inline const Solve + solve(const SparseMatrixBase& b) const + { + eigen_assert(m_isInitialized && "Solver is not initialized."); + eigen_assert(derived().rows()==b.rows() && "solve(): invalid number of rows of the right hand side matrix b"); + return Solve(derived(), b.derived()); + } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** \internal default implementation of solving with a sparse rhs */ + template + void _solve_impl(const SparseMatrixBase &b, SparseMatrixBase &dest) const + { + internal::solve_sparse_through_dense_panels(derived(), b.derived(), dest.derived()); + } + #endif // EIGEN_PARSED_BY_DOXYGEN + + protected: + + mutable bool m_isInitialized; +}; + +} // end namespace Eigen + +#endif // EIGEN_SPARSESOLVERBASE_H diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseSparseProductWithPruning.h b/libs/eigen3/Eigen/src/SparseCore/SparseSparseProductWithPruning.h index fcc18f5c9..21c419002 100644 --- a/libs/eigen3/Eigen/src/SparseCore/SparseSparseProductWithPruning.h +++ b/libs/eigen3/Eigen/src/SparseCore/SparseSparseProductWithPruning.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2011 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -22,7 +22,7 @@ static void sparse_sparse_product_with_pruning_impl(const Lhs& lhs, const Rhs& r // return sparse_sparse_product_with_pruning_impl2(lhs,rhs,res); typedef typename remove_all::type::Scalar Scalar; - typedef typename remove_all::type::Index Index; + typedef typename remove_all::type::StorageIndex StorageIndex; // make sure to call innerSize/outerSize since we fake the storage order. Index rows = lhs.innerSize(); @@ -31,24 +31,27 @@ static void sparse_sparse_product_with_pruning_impl(const Lhs& lhs, const Rhs& r eigen_assert(lhs.outerSize() == rhs.innerSize()); // allocate a temporary buffer - AmbiVector tempVector(rows); + AmbiVector tempVector(rows); + // mimics a resizeByInnerOuter: + if(ResultType::IsRowMajor) + res.resize(cols, rows); + else + res.resize(rows, cols); + + evaluator lhsEval(lhs); + evaluator rhsEval(rhs); + // estimate the number of non zero entries // given a rhs column containing Y non zeros, we assume that the respective Y columns // of the lhs differs in average of one non zeros, thus the number of non zeros for // the product of a rhs column with the lhs is X+Y where X is the average number of non zero // per column of the lhs. // Therefore, we have nnz(lhs*rhs) = nnz(lhs) + nnz(rhs) - Index estimated_nnz_prod = lhs.nonZeros() + rhs.nonZeros(); - - // mimics a resizeByInnerOuter: - if(ResultType::IsRowMajor) - res.resize(cols, rows); - else - res.resize(rows, cols); + Index estimated_nnz_prod = lhsEval.nonZerosEstimate() + rhsEval.nonZerosEstimate(); res.reserve(estimated_nnz_prod); - double ratioColRes = double(estimated_nnz_prod)/double(lhs.rows()*rhs.cols()); + double ratioColRes = double(estimated_nnz_prod)/(double(lhs.rows())*double(rhs.cols())); for (Index j=0; j::InnerIterator rhsIt(rhsEval, j); rhsIt; ++rhsIt) { // FIXME should be written like this: tmp += rhsIt.value() * lhs.col(rhsIt.index()) tempVector.restart(); Scalar x = rhsIt.value(); - for (typename Lhs::InnerIterator lhsIt(lhs, rhsIt.index()); lhsIt; ++lhsIt) + for (typename evaluator::InnerIterator lhsIt(lhsEval, rhsIt.index()); lhsIt; ++lhsIt) { tempVector.coeffRef(lhsIt.index()) += lhsIt.value() * x; } } res.startVec(j); - for (typename AmbiVector::Iterator it(tempVector,tolerance); it; ++it) + for (typename AmbiVector::Iterator it(tempVector,tolerance); it; ++it) res.insertBackByOuterInner(j,it.index()) = it.value(); } res.finalize(); @@ -100,7 +103,7 @@ struct sparse_sparse_product_with_pruning_selector SparseTemporaryType; + typedef SparseMatrix SparseTemporaryType; SparseTemporaryType _res(res.rows(), res.cols()); internal::sparse_sparse_product_with_pruning_impl(lhs, rhs, _res, tolerance); res = _res; @@ -126,8 +129,8 @@ struct sparse_sparse_product_with_pruning_selector ColMajorMatrixLhs; - typedef SparseMatrix ColMajorMatrixRhs; + typedef SparseMatrix ColMajorMatrixLhs; + typedef SparseMatrix ColMajorMatrixRhs; ColMajorMatrixLhs colLhs(lhs); ColMajorMatrixRhs colRhs(rhs); internal::sparse_sparse_product_with_pruning_impl(colLhs, colRhs, res, tolerance); @@ -140,8 +143,53 @@ struct sparse_sparse_product_with_pruning_selector +struct sparse_sparse_product_with_pruning_selector +{ + typedef typename ResultType::RealScalar RealScalar; + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) + { + typedef SparseMatrix RowMajorMatrixLhs; + RowMajorMatrixLhs rowLhs(lhs); + sparse_sparse_product_with_pruning_selector(rowLhs,rhs,res,tolerance); + } +}; + +template +struct sparse_sparse_product_with_pruning_selector +{ + typedef typename ResultType::RealScalar RealScalar; + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) + { + typedef SparseMatrix RowMajorMatrixRhs; + RowMajorMatrixRhs rowRhs(rhs); + sparse_sparse_product_with_pruning_selector(lhs,rowRhs,res,tolerance); + } +}; + +template +struct sparse_sparse_product_with_pruning_selector +{ + typedef typename ResultType::RealScalar RealScalar; + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) + { + typedef SparseMatrix ColMajorMatrixRhs; + ColMajorMatrixRhs colRhs(rhs); + internal::sparse_sparse_product_with_pruning_impl(lhs, colRhs, res, tolerance); + } +}; + +template +struct sparse_sparse_product_with_pruning_selector +{ + typedef typename ResultType::RealScalar RealScalar; + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) + { + typedef SparseMatrix ColMajorMatrixLhs; + ColMajorMatrixLhs colLhs(lhs); + internal::sparse_sparse_product_with_pruning_impl(colLhs, rhs, res, tolerance); + } +}; } // end namespace internal diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseTranspose.h b/libs/eigen3/Eigen/src/SparseCore/SparseTranspose.h index 76d031d52..3757d4c6b 100644 --- a/libs/eigen3/Eigen/src/SparseCore/SparseTranspose.h +++ b/libs/eigen3/Eigen/src/SparseCore/SparseTranspose.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2008-2015 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -12,52 +12,81 @@ namespace Eigen { -template class TransposeImpl - : public SparseMatrixBase > -{ - typedef typename internal::remove_all::type _MatrixTypeNested; +namespace internal { + template + class SparseTransposeImpl + : public SparseMatrixBase > + {}; + + template + class SparseTransposeImpl + : public SparseCompressedBase > + { + typedef SparseCompressedBase > Base; public: - - EIGEN_SPARSE_PUBLIC_INTERFACE(Transpose ) - - class InnerIterator; - class ReverseInnerIterator; + using Base::derived; + typedef typename Base::Scalar Scalar; + typedef typename Base::StorageIndex StorageIndex; inline Index nonZeros() const { return derived().nestedExpression().nonZeros(); } -}; + + inline const Scalar* valuePtr() const { return derived().nestedExpression().valuePtr(); } + inline const StorageIndex* innerIndexPtr() const { return derived().nestedExpression().innerIndexPtr(); } + inline const StorageIndex* outerIndexPtr() const { return derived().nestedExpression().outerIndexPtr(); } + inline const StorageIndex* innerNonZeroPtr() const { return derived().nestedExpression().innerNonZeroPtr(); } -// NOTE: VC10 and VC11 trigger an ICE if don't put typename TransposeImpl:: in front of Index, -// a typedef typename TransposeImpl::Index Index; -// does not fix the issue. -// An alternative is to define the nested class in the parent class itself. -template class TransposeImpl::InnerIterator - : public _MatrixTypeNested::InnerIterator + inline Scalar* valuePtr() { return derived().nestedExpression().valuePtr(); } + inline StorageIndex* innerIndexPtr() { return derived().nestedExpression().innerIndexPtr(); } + inline StorageIndex* outerIndexPtr() { return derived().nestedExpression().outerIndexPtr(); } + inline StorageIndex* innerNonZeroPtr() { return derived().nestedExpression().innerNonZeroPtr(); } + }; +} + +template class TransposeImpl + : public internal::SparseTransposeImpl { - typedef typename _MatrixTypeNested::InnerIterator Base; - typedef typename TransposeImpl::Index Index; - public: - - EIGEN_STRONG_INLINE InnerIterator(const TransposeImpl& trans, typename TransposeImpl::Index outer) - : Base(trans.derived().nestedExpression(), outer) - {} - typename TransposeImpl::Index row() const { return Base::col(); } - typename TransposeImpl::Index col() const { return Base::row(); } + protected: + typedef internal::SparseTransposeImpl Base; }; -template class TransposeImpl::ReverseInnerIterator - : public _MatrixTypeNested::ReverseInnerIterator +namespace internal { + +template +struct unary_evaluator, IteratorBased> + : public evaluator_base > { - typedef typename _MatrixTypeNested::ReverseInnerIterator Base; - typedef typename TransposeImpl::Index Index; + typedef typename evaluator::InnerIterator EvalIterator; public: + typedef Transpose XprType; + + inline Index nonZerosEstimate() const { + return m_argImpl.nonZerosEstimate(); + } - EIGEN_STRONG_INLINE ReverseInnerIterator(const TransposeImpl& xpr, typename TransposeImpl::Index outer) - : Base(xpr.derived().nestedExpression(), outer) - {} - typename TransposeImpl::Index row() const { return Base::col(); } - typename TransposeImpl::Index col() const { return Base::row(); } + class InnerIterator : public EvalIterator + { + public: + EIGEN_STRONG_INLINE InnerIterator(const unary_evaluator& unaryOp, Index outer) + : EvalIterator(unaryOp.m_argImpl,outer) + {} + + Index row() const { return EvalIterator::col(); } + Index col() const { return EvalIterator::row(); } + }; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + Flags = XprType::Flags + }; + + explicit unary_evaluator(const XprType& op) :m_argImpl(op.nestedExpression()) {} + + protected: + evaluator m_argImpl; }; +} // end namespace internal + } // end namespace Eigen #endif // EIGEN_SPARSETRANSPOSE_H diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseTriangularView.h b/libs/eigen3/Eigen/src/SparseCore/SparseTriangularView.h index 333127b78..9ac120266 100644 --- a/libs/eigen3/Eigen/src/SparseCore/SparseTriangularView.h +++ b/libs/eigen3/Eigen/src/SparseCore/SparseTriangularView.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2009-2015 Gael Guennebaud // Copyright (C) 2012 Désiré Nuentsa-Wakam // // This Source Code Form is subject to the terms of the Mozilla @@ -11,19 +11,19 @@ #ifndef EIGEN_SPARSE_TRIANGULARVIEW_H #define EIGEN_SPARSE_TRIANGULARVIEW_H -namespace Eigen { - -namespace internal { - -template -struct traits > -: public traits -{}; - -} // namespace internal - -template class SparseTriangularView - : public SparseMatrixBase > +namespace Eigen { + +/** \ingroup SparseCore_Module + * + * \brief Base class for a triangular part in a \b sparse matrix + * + * This class is an abstract base class of class TriangularView, and objects of type TriangularViewImpl cannot be instantiated. + * It extends class TriangularView with additional methods which are available for sparse expressions only. + * + * \sa class TriangularView, SparseMatrixBase::triangularView() + */ +template class TriangularViewImpl + : public SparseMatrixBase > { enum { SkipFirst = ((Mode&Lower) && !(MatrixType::Flags&RowMajorBit)) || ((Mode&Upper) && (MatrixType::Flags&RowMajorBit)), @@ -31,147 +31,157 @@ template class SparseTriangularView SkipDiag = (Mode&ZeroDiag) ? 1 : 0, HasUnitDiag = (Mode&UnitDiag) ? 1 : 0 }; + + typedef TriangularView TriangularViewType; + + protected: + // dummy solve function to make TriangularView happy. + void solve() const; + typedef SparseMatrixBase Base; public: - EIGEN_SPARSE_PUBLIC_INTERFACE(SparseTriangularView) - - class InnerIterator; - class ReverseInnerIterator; - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - + EIGEN_SPARSE_PUBLIC_INTERFACE(TriangularViewType) + typedef typename MatrixType::Nested MatrixTypeNested; typedef typename internal::remove_reference::type MatrixTypeNestedNonRef; typedef typename internal::remove_all::type MatrixTypeNestedCleaned; - inline SparseTriangularView(const MatrixType& matrix) : m_matrix(matrix) {} - - /** \internal */ - inline const MatrixTypeNestedCleaned& nestedExpression() const { return m_matrix; } - - template - typename internal::plain_matrix_type_column_major::type - solve(const MatrixBase& other) const; + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _solve_impl(const RhsType &rhs, DstType &dst) const { + if(!(internal::is_same::value && internal::extract_data(dst) == internal::extract_data(rhs))) + dst = rhs; + this->solveInPlace(dst); + } + /** Applies the inverse of \c *this to the dense vector or matrix \a other, "in-place" */ template void solveInPlace(MatrixBase& other) const; - template void solveInPlace(SparseMatrixBase& other) const; - protected: - MatrixTypeNested m_matrix; + /** Applies the inverse of \c *this to the sparse vector or matrix \a other, "in-place" */ + template void solveInPlace(SparseMatrixBase& other) const; + }; -template -class SparseTriangularView::InnerIterator : public MatrixTypeNestedCleaned::InnerIterator +namespace internal { + +template +struct unary_evaluator, IteratorBased> + : evaluator_base > { - typedef typename MatrixTypeNestedCleaned::InnerIterator Base; - typedef typename SparseTriangularView::Index Index; - public: + typedef TriangularView XprType; + +protected: + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::StorageIndex StorageIndex; + typedef typename evaluator::InnerIterator EvalIterator; + + enum { SkipFirst = ((Mode&Lower) && !(ArgType::Flags&RowMajorBit)) + || ((Mode&Upper) && (ArgType::Flags&RowMajorBit)), + SkipLast = !SkipFirst, + SkipDiag = (Mode&ZeroDiag) ? 1 : 0, + HasUnitDiag = (Mode&UnitDiag) ? 1 : 0 + }; + +public: + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + Flags = XprType::Flags + }; + + explicit unary_evaluator(const XprType &xpr) : m_argImpl(xpr.nestedExpression()), m_arg(xpr.nestedExpression()) {} + + inline Index nonZerosEstimate() const { + return m_argImpl.nonZerosEstimate(); + } + + class InnerIterator : public EvalIterator + { + typedef EvalIterator Base; + public: - EIGEN_STRONG_INLINE InnerIterator(const SparseTriangularView& view, Index outer) - : Base(view.nestedExpression(), outer), m_returnOne(false) - { - if(SkipFirst) + EIGEN_STRONG_INLINE InnerIterator(const unary_evaluator& xprEval, Index outer) + : Base(xprEval.m_argImpl,outer), m_returnOne(false), m_containsDiag(Base::outer()index()<=outer : this->index()index()<=outer : this->index()=Base::outer())) + { + if((!SkipFirst) && Base::operator bool()) + Base::operator++(); + m_returnOne = m_containsDiag; + } } - else if(HasUnitDiag && ((!Base::operator bool()) || Base::index()>=Base::outer())) + + EIGEN_STRONG_INLINE InnerIterator& operator++() { - if((!SkipFirst) && Base::operator bool()) + if(HasUnitDiag && m_returnOne) + m_returnOne = false; + else + { Base::operator++(); - m_returnOne = true; + if(HasUnitDiag && (!SkipFirst) && ((!Base::operator bool()) || Base::index()>=Base::outer())) + { + if((!SkipFirst) && Base::operator bool()) + Base::operator++(); + m_returnOne = m_containsDiag; + } + } + return *this; } - } - - EIGEN_STRONG_INLINE InnerIterator& operator++() - { - if(HasUnitDiag && m_returnOne) - m_returnOne = false; - else + + EIGEN_STRONG_INLINE operator bool() const { - Base::operator++(); - if(HasUnitDiag && (!SkipFirst) && ((!Base::operator bool()) || Base::index()>=Base::outer())) + if(HasUnitDiag && m_returnOne) + return true; + if(SkipFirst) return Base::operator bool(); + else { - if((!SkipFirst) && Base::operator bool()) - Base::operator++(); - m_returnOne = true; + if (SkipDiag) return (Base::operator bool() && this->index() < this->outer()); + else return (Base::operator bool() && this->index() <= this->outer()); } } - return *this; - } - - inline Index row() const { return (MatrixType::Flags&RowMajorBit ? Base::outer() : this->index()); } - inline Index col() const { return (MatrixType::Flags&RowMajorBit ? this->index() : Base::outer()); } - inline Index index() const - { - if(HasUnitDiag && m_returnOne) return Base::outer(); - else return Base::index(); - } - inline Scalar value() const - { - if(HasUnitDiag && m_returnOne) return Scalar(1); - else return Base::value(); - } - EIGEN_STRONG_INLINE operator bool() const - { - if(HasUnitDiag && m_returnOne) - return true; - if(SkipFirst) return Base::operator bool(); - else +// inline Index row() const { return (ArgType::Flags&RowMajorBit ? Base::outer() : this->index()); } +// inline Index col() const { return (ArgType::Flags&RowMajorBit ? this->index() : Base::outer()); } + inline StorageIndex index() const { - if (SkipDiag) return (Base::operator bool() && this->index() < this->outer()); - else return (Base::operator bool() && this->index() <= this->outer()); + if(HasUnitDiag && m_returnOne) return internal::convert_index(Base::outer()); + else return Base::index(); } - } - protected: - bool m_returnOne; -}; - -template -class SparseTriangularView::ReverseInnerIterator : public MatrixTypeNestedCleaned::ReverseInnerIterator -{ - typedef typename MatrixTypeNestedCleaned::ReverseInnerIterator Base; - typedef typename SparseTriangularView::Index Index; - public: - - EIGEN_STRONG_INLINE ReverseInnerIterator(const SparseTriangularView& view, Index outer) - : Base(view.nestedExpression(), outer) - { - eigen_assert((!HasUnitDiag) && "ReverseInnerIterator does not support yet triangular views with a unit diagonal"); - if(SkipLast) { - while((*this) && (SkipDiag ? this->index()>=outer : this->index()>outer)) - --(*this); - } - } - - EIGEN_STRONG_INLINE ReverseInnerIterator& operator--() - { Base::operator--(); return *this; } - - inline Index row() const { return Base::row(); } - inline Index col() const { return Base::col(); } - - EIGEN_STRONG_INLINE operator bool() const - { - if (SkipLast) return Base::operator bool() ; - else + inline Scalar value() const { - if(SkipDiag) return (Base::operator bool() && this->index() > this->outer()); - else return (Base::operator bool() && this->index() >= this->outer()); + if(HasUnitDiag && m_returnOne) return Scalar(1); + else return Base::value(); } - } + + protected: + bool m_returnOne; + bool m_containsDiag; + private: + Scalar& valueRef(); + }; + +protected: + evaluator m_argImpl; + const ArgType& m_arg; }; +} // end namespace internal + template template -inline const SparseTriangularView +inline const TriangularView SparseMatrixBase::triangularView() const { - return derived(); + return TriangularView(derived()); } } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseUtil.h b/libs/eigen3/Eigen/src/SparseCore/SparseUtil.h index 0ba471320..74df0d496 100644 --- a/libs/eigen3/Eigen/src/SparseCore/SparseUtil.h +++ b/libs/eigen3/Eigen/src/SparseCore/SparseUtil.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -37,43 +37,23 @@ EIGEN_STRONG_INLINE Derived& operator Op(const Other& scalar) \ } #define EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATORS(Derived) \ -EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, =) \ -EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, +=) \ -EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, -=) \ -EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, *=) \ -EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, /=) - -#define _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, BaseClass) \ - typedef BaseClass Base; \ - typedef typename Eigen::internal::traits::Scalar Scalar; \ - typedef typename Eigen::NumTraits::Real RealScalar; \ - typedef typename Eigen::internal::nested::type Nested; \ - typedef typename Eigen::internal::traits::StorageKind StorageKind; \ - typedef typename Eigen::internal::traits::Index Index; \ - enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ - ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, \ - Flags = Eigen::internal::traits::Flags, \ - CoeffReadCost = Eigen::internal::traits::CoeffReadCost, \ - SizeAtCompileTime = Base::SizeAtCompileTime, \ - IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; \ - using Base::derived; \ - using Base::const_cast_derived; +EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, =) + #define EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) \ - _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, Eigen::SparseMatrixBase) + EIGEN_GENERIC_PUBLIC_INTERFACE(Derived) + const int CoherentAccessPattern = 0x1; const int InnerRandomAccessPattern = 0x2 | CoherentAccessPattern; const int OuterRandomAccessPattern = 0x4 | CoherentAccessPattern; const int RandomAccessPattern = 0x8 | OuterRandomAccessPattern | InnerRandomAccessPattern; -template class SparseMatrixBase; -template class SparseMatrix; -template class DynamicSparseMatrix; -template class SparseVector; -template class MappedSparseMatrix; +template class SparseMatrix; +template class DynamicSparseMatrix; +template class SparseVector; +template class MappedSparseMatrix; -template class SparseTriangularView; template class SparseSelfAdjointView; template class SparseDiagonalProduct; template class SparseView; @@ -85,42 +65,44 @@ template class SparseDenseOuterProdu template struct SparseSparseProductReturnType; template::ColsAtCompileTime,internal::traits::RowsAtCompileTime)> struct DenseSparseProductReturnType; + int InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(internal::traits::ColsAtCompileTime,internal::traits::RowsAtCompileTime)> struct DenseSparseProductReturnType; + template::ColsAtCompileTime,internal::traits::RowsAtCompileTime)> struct SparseDenseProductReturnType; template class SparseSymmetricPermutationProduct; namespace internal { -template struct sparse_eval; +template struct sparse_eval; template struct eval - : public sparse_eval::RowsAtCompileTime,traits::ColsAtCompileTime> + : sparse_eval::RowsAtCompileTime,traits::ColsAtCompileTime,traits::Flags> {}; -template struct sparse_eval { +template struct sparse_eval { typedef typename traits::Scalar _Scalar; - typedef typename traits::Index _Index; + typedef typename traits::StorageIndex _StorageIndex; public: - typedef SparseVector<_Scalar, RowMajor, _Index> type; + typedef SparseVector<_Scalar, RowMajor, _StorageIndex> type; }; -template struct sparse_eval { +template struct sparse_eval { typedef typename traits::Scalar _Scalar; - typedef typename traits::Index _Index; + typedef typename traits::StorageIndex _StorageIndex; public: - typedef SparseVector<_Scalar, ColMajor, _Index> type; + typedef SparseVector<_Scalar, ColMajor, _StorageIndex> type; }; -template struct sparse_eval { +// TODO this seems almost identical to plain_matrix_type +template struct sparse_eval { typedef typename traits::Scalar _Scalar; - typedef typename traits::Index _Index; - enum { _Options = ((traits::Flags&RowMajorBit)==RowMajorBit) ? RowMajor : ColMajor }; + typedef typename traits::StorageIndex _StorageIndex; + enum { _Options = ((Flags&RowMajorBit)==RowMajorBit) ? RowMajor : ColMajor }; public: - typedef SparseMatrix<_Scalar, _Options, _Index> type; + typedef SparseMatrix<_Scalar, _Options, _StorageIndex> type; }; -template struct sparse_eval { +template struct sparse_eval { typedef typename traits::Scalar _Scalar; public: typedef Matrix<_Scalar, 1, 1> type; @@ -129,12 +111,35 @@ template struct sparse_eval { template struct plain_matrix_type { typedef typename traits::Scalar _Scalar; - typedef typename traits::Index _Index; - enum { _Options = ((traits::Flags&RowMajorBit)==RowMajorBit) ? RowMajor : ColMajor }; + typedef typename traits::StorageIndex _StorageIndex; + enum { _Options = ((evaluator::Flags&RowMajorBit)==RowMajorBit) ? RowMajor : ColMajor }; public: - typedef SparseMatrix<_Scalar, _Options, _Index> type; + typedef SparseMatrix<_Scalar, _Options, _StorageIndex> type; +}; + +template +struct plain_object_eval + : sparse_eval::RowsAtCompileTime,traits::ColsAtCompileTime, evaluator::Flags> +{}; + +template +struct solve_traits +{ + typedef typename sparse_eval::Flags>::type PlainObject; }; +template +struct generic_xpr_base +{ + typedef SparseMatrixBase type; +}; + +struct SparseTriangularShape { static std::string debugName() { return "SparseTriangularShape"; } }; +struct SparseSelfAdjointShape { static std::string debugName() { return "SparseSelfAdjointShape"; } }; + +template<> struct glue_shapes { typedef SparseSelfAdjointShape type; }; +template<> struct glue_shapes { typedef SparseTriangularShape type; }; + } // end namespace internal /** \ingroup SparseCore_Module @@ -145,26 +150,26 @@ template struct plain_matrix_type * * \sa SparseMatrix::setFromTriplets() */ -template::Index > +template::StorageIndex > class Triplet { public: Triplet() : m_row(0), m_col(0), m_value(0) {} - Triplet(const Index& i, const Index& j, const Scalar& v = Scalar(0)) + Triplet(const StorageIndex& i, const StorageIndex& j, const Scalar& v = Scalar(0)) : m_row(i), m_col(j), m_value(v) {} /** \returns the row index of the element */ - const Index& row() const { return m_row; } + const StorageIndex& row() const { return m_row; } /** \returns the column index of the element */ - const Index& col() const { return m_col; } + const StorageIndex& col() const { return m_col; } /** \returns the value of the element */ const Scalar& value() const { return m_value; } protected: - Index m_row, m_col; + StorageIndex m_row, m_col; Scalar m_value; }; diff --git a/libs/eigen3/Eigen/src/SparseCore/SparseVector.h b/libs/eigen3/Eigen/src/SparseCore/SparseVector.h index 7e15c814b..19b0fbc9d 100644 --- a/libs/eigen3/Eigen/src/SparseCore/SparseVector.h +++ b/libs/eigen3/Eigen/src/SparseCore/SparseVector.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2008-2015 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -22,15 +22,15 @@ namespace Eigen { * See http://www.netlib.org/linalg/html_templates/node91.html for details on the storage scheme. * * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_SPARSEVECTOR_PLUGIN. + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_SPARSEVECTOR_PLUGIN. */ namespace internal { -template -struct traits > +template +struct traits > { typedef _Scalar Scalar; - typedef _Index Index; + typedef _StorageIndex StorageIndex; typedef Sparse StorageKind; typedef MatrixXpr XprKind; enum { @@ -40,8 +40,7 @@ struct traits > ColsAtCompileTime = IsColVector ? 1 : Dynamic, MaxRowsAtCompileTime = RowsAtCompileTime, MaxColsAtCompileTime = ColsAtCompileTime, - Flags = _Options | NestByRefBit | LvalueBit | (IsColVector ? 0 : RowMajorBit), - CoeffReadCost = NumTraits::ReadCost, + Flags = _Options | NestByRefBit | LvalueBit | (IsColVector ? 0 : RowMajorBit) | CompressedAccessBit, SupportedAccessPatterns = InnerRandomAccessPattern }; }; @@ -61,18 +60,18 @@ struct sparse_vector_assign_selector; } -template +template class SparseVector - : public SparseMatrixBase > + : public SparseCompressedBase > { - typedef SparseMatrixBase SparseBase; - + typedef SparseCompressedBase Base; + using Base::convert_index; public: EIGEN_SPARSE_PUBLIC_INTERFACE(SparseVector) EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseVector, +=) EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseVector, -=) - typedef internal::CompressedStorage Storage; + typedef internal::CompressedStorage Storage; enum { IsColVector = internal::traits::IsColVector }; enum { @@ -84,11 +83,16 @@ class SparseVector EIGEN_STRONG_INLINE Index innerSize() const { return m_size; } EIGEN_STRONG_INLINE Index outerSize() const { return 1; } - EIGEN_STRONG_INLINE const Scalar* valuePtr() const { return &m_data.value(0); } - EIGEN_STRONG_INLINE Scalar* valuePtr() { return &m_data.value(0); } + EIGEN_STRONG_INLINE const Scalar* valuePtr() const { return m_data.valuePtr(); } + EIGEN_STRONG_INLINE Scalar* valuePtr() { return m_data.valuePtr(); } - EIGEN_STRONG_INLINE const Index* innerIndexPtr() const { return &m_data.index(0); } - EIGEN_STRONG_INLINE Index* innerIndexPtr() { return &m_data.index(0); } + EIGEN_STRONG_INLINE const StorageIndex* innerIndexPtr() const { return m_data.indexPtr(); } + EIGEN_STRONG_INLINE StorageIndex* innerIndexPtr() { return m_data.indexPtr(); } + + inline const StorageIndex* outerIndexPtr() const { return 0; } + inline StorageIndex* outerIndexPtr() { return 0; } + inline const StorageIndex* innerNonZeroPtr() const { return 0; } + inline StorageIndex* innerNonZeroPtr() { return 0; } /** \internal */ inline Storage& data() { return m_data; } @@ -103,13 +107,13 @@ class SparseVector inline Scalar coeff(Index i) const { eigen_assert(i>=0 && i=0 && row=0 && col=0 && i(m_data.size()); } + inline Index nonZeros() const { return m_data.size(); } inline void startVec(Index outer) { @@ -151,6 +156,18 @@ class SparseVector m_data.append(0, i); return m_data.value(m_data.size()-1); } + + Scalar& insertBackByOuterInnerUnordered(Index outer, Index inner) + { + EIGEN_UNUSED_VARIABLE(outer); + eigen_assert(outer==0); + return insertBackUnordered(inner); + } + inline Scalar& insertBackUnordered(Index i) + { + m_data.append(0, i); + return m_data.value(m_data.size()-1); + } inline Scalar& insert(Index row, Index col) { @@ -158,6 +175,7 @@ class SparseVector Index inner = IsColVector ? row : col; Index outer = IsColVector ? col : row; + EIGEN_ONLY_USED_FOR_DEBUG(outer); eigen_assert(outer==0); return insert(inner); } @@ -176,7 +194,7 @@ class SparseVector m_data.value(p+1) = m_data.value(p); --p; } - m_data.index(p+1) = i; + m_data.index(p+1) = convert_index(i); m_data.value(p+1) = 0; return m_data.value(p+1); } @@ -188,28 +206,59 @@ class SparseVector inline void finalize() {} + /** \copydoc SparseMatrix::prune(const Scalar&,const RealScalar&) */ void prune(const Scalar& reference, const RealScalar& epsilon = NumTraits::dummy_precision()) { m_data.prune(reference,epsilon); } + /** Resizes the sparse vector to \a rows x \a cols + * + * This method is provided for compatibility with matrices. + * For a column vector, \a cols must be equal to 1. + * For a row vector, \a rows must be equal to 1. + * + * \sa resize(Index) + */ void resize(Index rows, Index cols) { - eigen_assert(rows==1 || cols==1); + eigen_assert((IsColVector ? cols : rows)==1 && "Outer dimension must equal 1"); resize(IsColVector ? rows : cols); } + /** Resizes the sparse vector to \a newSize + * This method deletes all entries, thus leaving an empty sparse vector + * + * \sa conservativeResize(), setZero() */ void resize(Index newSize) { m_size = newSize; m_data.clear(); } + /** Resizes the sparse vector to \a newSize, while leaving old values untouched. + * + * If the size of the vector is decreased, then the storage of the out-of bounds coefficients is kept and reserved. + * Call .data().squeeze() to free extra memory. + * + * \sa reserve(), setZero() + */ + void conservativeResize(Index newSize) + { + if (newSize < m_size) + { + Index i = 0; + while (i& other) : m_size(0) { + #ifdef EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN + EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN + #endif check_template_parameters(); *this = other.derived(); } inline SparseVector(const SparseVector& other) - : SparseBase(other), m_size(0) + : Base(other), m_size(0) { check_template_parameters(); *this = other.derived(); @@ -238,6 +290,14 @@ class SparseVector m_data.swap(other.m_data); } + template + inline void swap(SparseMatrix& other) + { + eigen_assert(other.outerSize()==1); + std::swap(m_size, other.m_innerSize); + m_data.swap(other.m_data); + } + inline SparseVector& operator=(const SparseVector& other) { if (other.isRValue()) @@ -336,7 +396,7 @@ class SparseVector static void check_template_parameters() { - EIGEN_STATIC_ASSERT(NumTraits::IsSigned,THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE); + EIGEN_STATIC_ASSERT(NumTraits::IsSigned,THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE); EIGEN_STATIC_ASSERT((_Options&(ColMajor|RowMajor))==Options,INVALID_MATRIX_TEMPLATE_PARAMETERS); } @@ -344,77 +404,46 @@ class SparseVector Index m_size; }; -template -class SparseVector::InnerIterator -{ - public: - InnerIterator(const SparseVector& vec, Index outer=0) - : m_data(vec.m_data), m_id(0), m_end(static_cast(m_data.size())) - { - EIGEN_UNUSED_VARIABLE(outer); - eigen_assert(outer==0); - } - - InnerIterator(const internal::CompressedStorage& data) - : m_data(data), m_id(0), m_end(static_cast(m_data.size())) - {} - - inline InnerIterator& operator++() { m_id++; return *this; } - - inline Scalar value() const { return m_data.value(m_id); } - inline Scalar& valueRef() { return const_cast(m_data.value(m_id)); } - - inline Index index() const { return m_data.index(m_id); } - inline Index row() const { return IsColVector ? index() : 0; } - inline Index col() const { return IsColVector ? 0 : index(); } - - inline operator bool() const { return (m_id < m_end); } - - protected: - const internal::CompressedStorage& m_data; - Index m_id; - const Index m_end; -}; +namespace internal { -template -class SparseVector::ReverseInnerIterator +template +struct evaluator > + : evaluator_base > { - public: - ReverseInnerIterator(const SparseVector& vec, Index outer=0) - : m_data(vec.m_data), m_id(static_cast(m_data.size())), m_start(0) - { - EIGEN_UNUSED_VARIABLE(outer); - eigen_assert(outer==0); - } - - ReverseInnerIterator(const internal::CompressedStorage& data) - : m_data(data), m_id(static_cast(m_data.size())), m_start(0) - {} - - inline ReverseInnerIterator& operator--() { m_id--; return *this; } - - inline Scalar value() const { return m_data.value(m_id-1); } - inline Scalar& valueRef() { return const_cast(m_data.value(m_id-1)); } - - inline Index index() const { return m_data.index(m_id-1); } - inline Index row() const { return IsColVector ? index() : 0; } - inline Index col() const { return IsColVector ? 0 : index(); } - - inline operator bool() const { return (m_id > m_start); } + typedef SparseVector<_Scalar,_Options,_Index> SparseVectorType; + typedef evaluator_base Base; + typedef typename SparseVectorType::InnerIterator InnerIterator; + typedef typename SparseVectorType::ReverseInnerIterator ReverseInnerIterator; + + enum { + CoeffReadCost = NumTraits<_Scalar>::ReadCost, + Flags = SparseVectorType::Flags + }; - protected: - const internal::CompressedStorage& m_data; - Index m_id; - const Index m_start; + evaluator() : Base() {} + + explicit evaluator(const SparseVectorType &mat) : m_matrix(&mat) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + inline Index nonZerosEstimate() const { + return m_matrix->nonZeros(); + } + + operator SparseVectorType&() { return m_matrix->const_cast_derived(); } + operator const SparseVectorType&() const { return *m_matrix; } + + const SparseVectorType *m_matrix; }; -namespace internal { - template< typename Dest, typename Src> struct sparse_vector_assign_selector { static void run(Dest& dst, const Src& src) { eigen_internal_assert(src.innerSize()==src.size()); - for(typename Src::InnerIterator it(src, 0); it; ++it) + typedef internal::evaluator SrcEvaluatorType; + SrcEvaluatorType srcEval(src); + for(typename SrcEvaluatorType::InnerIterator it(srcEval, 0); it; ++it) dst.insert(it.index()) = it.value(); } }; @@ -423,9 +452,11 @@ template< typename Dest, typename Src> struct sparse_vector_assign_selector { static void run(Dest& dst, const Src& src) { eigen_internal_assert(src.outerSize()==src.size()); - for(typename Dest::Index i=0; i SrcEvaluatorType; + SrcEvaluatorType srcEval(src); + for(Index i=0; i +// Copyright (C) 2011-2014 Gael Guennebaud // Copyright (C) 2010 Daniel Lowengrub // // This Source Code Form is subject to the terms of the Mozilla @@ -18,7 +18,7 @@ namespace internal { template struct traits > : traits { - typedef typename MatrixType::Index Index; + typedef typename MatrixType::StorageIndex StorageIndex; typedef Sparse StorageKind; enum { Flags = int(traits::Flags) & (RowMajorBit) @@ -27,71 +27,225 @@ struct traits > : traits } // end namespace internal +/** \ingroup SparseCore_Module + * \class SparseView + * + * \brief Expression of a dense or sparse matrix with zero or too small values removed + * + * \tparam MatrixType the type of the object of which we are removing the small entries + * + * This class represents an expression of a given dense or sparse matrix with + * entries smaller than \c reference * \c epsilon are removed. + * It is the return type of MatrixBase::sparseView() and SparseMatrixBase::pruned() + * and most of the time this is the only way it is used. + * + * \sa MatrixBase::sparseView(), SparseMatrixBase::pruned() + */ template class SparseView : public SparseMatrixBase > { typedef typename MatrixType::Nested MatrixTypeNested; typedef typename internal::remove_all::type _MatrixTypeNested; + typedef SparseMatrixBase Base; public: EIGEN_SPARSE_PUBLIC_INTERFACE(SparseView) + typedef typename internal::remove_all::type NestedExpression; - SparseView(const MatrixType& mat, const Scalar& m_reference = Scalar(0), - typename NumTraits::Real m_epsilon = NumTraits::dummy_precision()) : - m_matrix(mat), m_reference(m_reference), m_epsilon(m_epsilon) {} - - class InnerIterator; + explicit SparseView(const MatrixType& mat, const Scalar& reference = Scalar(0), + const RealScalar &epsilon = NumTraits::dummy_precision()) + : m_matrix(mat), m_reference(reference), m_epsilon(epsilon) {} inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } inline Index innerSize() const { return m_matrix.innerSize(); } inline Index outerSize() const { return m_matrix.outerSize(); } - + + /** \returns the nested expression */ + const typename internal::remove_all::type& + nestedExpression() const { return m_matrix; } + + Scalar reference() const { return m_reference; } + RealScalar epsilon() const { return m_epsilon; } + protected: MatrixTypeNested m_matrix; Scalar m_reference; - typename NumTraits::Real m_epsilon; + RealScalar m_epsilon; }; -template -class SparseView::InnerIterator : public _MatrixTypeNested::InnerIterator -{ - typedef typename SparseView::Index Index; -public: - typedef typename _MatrixTypeNested::InnerIterator IterBase; - InnerIterator(const SparseView& view, Index outer) : - IterBase(view.m_matrix, outer), m_view(view) - { - incrementToNonZero(); - } - - EIGEN_STRONG_INLINE InnerIterator& operator++() - { - IterBase::operator++(); - incrementToNonZero(); - return *this; - } - - using IterBase::value; +namespace internal { -protected: - const SparseView& m_view; +// TODO find a way to unify the two following variants +// This is tricky because implementing an inner iterator on top of an IndexBased evaluator is +// not easy because the evaluators do not expose the sizes of the underlying expression. + +template +struct unary_evaluator, IteratorBased> + : public evaluator_base > +{ + typedef typename evaluator::InnerIterator EvalIterator; + public: + typedef SparseView XprType; + + class InnerIterator : public EvalIterator + { + typedef typename XprType::Scalar Scalar; + public: + + EIGEN_STRONG_INLINE InnerIterator(const unary_evaluator& sve, Index outer) + : EvalIterator(sve.m_argImpl,outer), m_view(sve.m_view) + { + incrementToNonZero(); + } + + EIGEN_STRONG_INLINE InnerIterator& operator++() + { + EvalIterator::operator++(); + incrementToNonZero(); + return *this; + } + + using EvalIterator::value; + + protected: + const XprType &m_view; + + private: + void incrementToNonZero() + { + while((bool(*this)) && internal::isMuchSmallerThan(value(), m_view.reference(), m_view.epsilon())) + { + EvalIterator::operator++(); + } + } + }; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + Flags = XprType::Flags + }; + + explicit unary_evaluator(const XprType& xpr) : m_argImpl(xpr.nestedExpression()), m_view(xpr) {} + + protected: + evaluator m_argImpl; + const XprType &m_view; +}; -private: - void incrementToNonZero() - { - while((bool(*this)) && internal::isMuchSmallerThan(value(), m_view.m_reference, m_view.m_epsilon)) +template +struct unary_evaluator, IndexBased> + : public evaluator_base > +{ + public: + typedef SparseView XprType; + protected: + enum { IsRowMajor = (XprType::Flags&RowMajorBit)==RowMajorBit }; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::StorageIndex StorageIndex; + public: + + class InnerIterator { - IterBase::operator++(); - } - } + public: + + EIGEN_STRONG_INLINE InnerIterator(const unary_evaluator& sve, Index outer) + : m_sve(sve), m_inner(0), m_outer(outer), m_end(sve.m_view.innerSize()) + { + incrementToNonZero(); + } + + EIGEN_STRONG_INLINE InnerIterator& operator++() + { + m_inner++; + incrementToNonZero(); + return *this; + } + + EIGEN_STRONG_INLINE Scalar value() const + { + return (IsRowMajor) ? m_sve.m_argImpl.coeff(m_outer, m_inner) + : m_sve.m_argImpl.coeff(m_inner, m_outer); + } + + EIGEN_STRONG_INLINE StorageIndex index() const { return m_inner; } + inline Index row() const { return IsRowMajor ? m_outer : index(); } + inline Index col() const { return IsRowMajor ? index() : m_outer; } + + EIGEN_STRONG_INLINE operator bool() const { return m_inner < m_end && m_inner>=0; } + + protected: + const unary_evaluator &m_sve; + Index m_inner; + const Index m_outer; + const Index m_end; + + private: + void incrementToNonZero() + { + while((bool(*this)) && internal::isMuchSmallerThan(value(), m_sve.m_view.reference(), m_sve.m_view.epsilon())) + { + m_inner++; + } + } + }; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + Flags = XprType::Flags + }; + + explicit unary_evaluator(const XprType& xpr) : m_argImpl(xpr.nestedExpression()), m_view(xpr) {} + + protected: + evaluator m_argImpl; + const XprType &m_view; }; +} // end namespace internal + +/** \ingroup SparseCore_Module + * + * \returns a sparse expression of the dense expression \c *this with values smaller than + * \a reference * \a epsilon removed. + * + * This method is typically used when prototyping to convert a quickly assembled dense Matrix \c D to a SparseMatrix \c S: + * \code + * MatrixXd D(n,m); + * SparseMatrix S; + * S = D.sparseView(); // suppress numerical zeros (exact) + * S = D.sparseView(reference); + * S = D.sparseView(reference,epsilon); + * \endcode + * where \a reference is a meaningful non zero reference value, + * and \a epsilon is a tolerance factor defaulting to NumTraits::dummy_precision(). + * + * \sa SparseMatrixBase::pruned(), class SparseView */ +template +const SparseView MatrixBase::sparseView(const Scalar& reference, + const typename NumTraits::Real& epsilon) const +{ + return SparseView(derived(), reference, epsilon); +} + +/** \returns an expression of \c *this with values smaller than + * \a reference * \a epsilon removed. + * + * This method is typically used in conjunction with the product of two sparse matrices + * to automatically prune the smallest values as follows: + * \code + * C = (A*B).pruned(); // suppress numerical zeros (exact) + * C = (A*B).pruned(ref); + * C = (A*B).pruned(ref,epsilon); + * \endcode + * where \c ref is a meaningful non zero reference value. + * */ template -const SparseView MatrixBase::sparseView(const Scalar& m_reference, - const typename NumTraits::Real& m_epsilon) const +const SparseView +SparseMatrixBase::pruned(const Scalar& reference, + const RealScalar& epsilon) const { - return SparseView(derived(), m_reference, m_epsilon); + return SparseView(derived(), reference, epsilon); } } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/SparseCore/TriangularSolver.h b/libs/eigen3/Eigen/src/SparseCore/TriangularSolver.h index cb8ad82b4..f9c56ba79 100644 --- a/libs/eigen3/Eigen/src/SparseCore/TriangularSolver.h +++ b/libs/eigen3/Eigen/src/SparseCore/TriangularSolver.h @@ -28,16 +28,19 @@ template struct sparse_solve_triangular_selector { typedef typename Rhs::Scalar Scalar; + typedef evaluator LhsEval; + typedef typename evaluator::InnerIterator LhsIterator; static void run(const Lhs& lhs, Rhs& other) { - for(int col=0 ; col struct sparse_solve_triangular_selector { typedef typename Rhs::Scalar Scalar; + typedef evaluator LhsEval; + typedef typename evaluator::InnerIterator LhsIterator; static void run(const Lhs& lhs, Rhs& other) { - for(int col=0 ; col=0 ; --i) + for(Index i=lhs.rows()-1 ; i>=0 ; --i) { Scalar tmp = other.coeff(i,col); - Scalar l_ii = 0; - typename Lhs::InnerIterator it(lhs, i); + Scalar l_ii(0); + LhsIterator it(lhsEval, i); while(it && it.index() tmp -= it.value() * other.coeff(it.index(),col); } - if (Mode & UnitDiag) - other.coeffRef(i,col) = tmp; - else - other.coeffRef(i,col) = tmp/l_ii; + if (Mode & UnitDiag) other.coeffRef(i,col) = tmp; + else other.coeffRef(i,col) = tmp/l_ii; } } } @@ -100,16 +104,19 @@ template struct sparse_solve_triangular_selector { typedef typename Rhs::Scalar Scalar; + typedef evaluator LhsEval; + typedef typename evaluator::InnerIterator LhsIterator; static void run(const Lhs& lhs, Rhs& other) { - for(int col=0 ; col struct sparse_solve_triangular_selector { typedef typename Rhs::Scalar Scalar; + typedef evaluator LhsEval; + typedef typename evaluator::InnerIterator LhsIterator; static void run(const Lhs& lhs, Rhs& other) { - for(int col=0 ; col=0; --i) + for(Index i=lhs.cols()-1; i>=0; --i) { Scalar& tmp = other.coeffRef(i,col); if (tmp!=Scalar(0)) // optimization when other is actually sparse @@ -144,13 +154,13 @@ struct sparse_solve_triangular_selector if(!(Mode & UnitDiag)) { // TODO replace this by a binary search. make sure the binary search is safe for partially sorted elements - typename Lhs::ReverseInnerIterator it(lhs, i); + LhsIterator it(lhsEval, i); while(it && it.index()!=i) - --it; + ++it; eigen_assert(it && it.index()==i); other.coeffRef(i,col) /= it.value(); } - typename Lhs::InnerIterator it(lhs, i); + LhsIterator it(lhsEval, i); for(; it && it.index() } // end namespace internal -template +#ifndef EIGEN_PARSED_BY_DOXYGEN + +template template -void SparseTriangularView::solveInPlace(MatrixBase& other) const +void TriangularViewImpl::solveInPlace(MatrixBase& other) const { - eigen_assert(m_matrix.cols() == m_matrix.rows() && m_matrix.cols() == other.rows()); + eigen_assert(derived().cols() == derived().rows() && derived().cols() == other.rows()); eigen_assert((!(Mode & ZeroDiag)) && bool(Mode & (Upper|Lower))); enum { copy = internal::traits::Flags & RowMajorBit }; @@ -174,21 +186,12 @@ void SparseTriangularView::solveInPlace(MatrixBase::type, OtherDerived&>::type OtherCopy; OtherCopy otherCopy(other.derived()); - internal::sparse_solve_triangular_selector::type, Mode>::run(m_matrix, otherCopy); + internal::sparse_solve_triangular_selector::type, Mode>::run(derived().nestedExpression(), otherCopy); if (copy) other = otherCopy; } - -template -template -typename internal::plain_matrix_type_column_major::type -SparseTriangularView::solve(const MatrixBase& other) const -{ - typename internal::plain_matrix_type_column_major::type res(other); - solveInPlace(res); - return res; -} +#endif // pure sparse path @@ -208,18 +211,18 @@ template struct sparse_solve_triangular_sparse_selector { typedef typename Rhs::Scalar Scalar; - typedef typename promote_index_type::Index, - typename traits::Index>::type Index; + typedef typename promote_index_type::StorageIndex, + typename traits::StorageIndex>::type StorageIndex; static void run(const Lhs& lhs, Rhs& other) { const bool IsLower = (UpLo==Lower); - AmbiVector tempVector(other.rows()*2); + AmbiVector tempVector(other.rows()*2); tempVector.setBounds(0,other.rows()); Rhs res(other.rows(), other.cols()); res.reserve(other.nonZeros()); - for(int col=0 ; col tempVector.coeffRef(rhsIt.index()) = rhsIt.value(); } - for(int i=IsLower?0:lhs.cols()-1; + for(Index i=IsLower?0:lhs.cols()-1; IsLower?i=0; i+=IsLower?1:-1) { @@ -267,9 +270,9 @@ struct sparse_solve_triangular_sparse_selector } - int count = 0; + Index count = 0; // FIXME compute a reference value to filter zeros - for (typename AmbiVector::Iterator it(tempVector/*,1e-12*/); it; ++it) + for (typename AmbiVector::Iterator it(tempVector/*,1e-12*/); it; ++it) { ++ count; // std::cerr << "fill " << it.index() << ", " << col << "\n"; @@ -286,11 +289,12 @@ struct sparse_solve_triangular_sparse_selector } // end namespace internal -template +#ifndef EIGEN_PARSED_BY_DOXYGEN +template template -void SparseTriangularView::solveInPlace(SparseMatrixBase& other) const +void TriangularViewImpl::solveInPlace(SparseMatrixBase& other) const { - eigen_assert(m_matrix.cols() == m_matrix.rows() && m_matrix.cols() == other.rows()); + eigen_assert(derived().cols() == derived().rows() && derived().cols() == other.rows()); eigen_assert( (!(Mode & ZeroDiag)) && bool(Mode & (Upper|Lower))); // enum { copy = internal::traits::Flags & RowMajorBit }; @@ -299,35 +303,12 @@ void SparseTriangularView::solveInPlace(SparseMatrixBase::type, OtherDerived&>::type OtherCopy; // OtherCopy otherCopy(other.derived()); - internal::sparse_solve_triangular_sparse_selector::run(m_matrix, other.derived()); + internal::sparse_solve_triangular_sparse_selector::run(derived().nestedExpression(), other.derived()); // if (copy) // other = otherCopy; } - -#ifdef EIGEN2_SUPPORT - -// deprecated stuff: - -/** \deprecated */ -template -template -void SparseMatrixBase::solveTriangularInPlace(MatrixBase& other) const -{ - this->template triangular().solveInPlace(other); -} - -/** \deprecated */ -template -template -typename internal::plain_matrix_type_column_major::type -SparseMatrixBase::solveTriangular(const MatrixBase& other) const -{ - typename internal::plain_matrix_type_column_major::type res(other); - derived().solveTriangularInPlace(res); - return res; -} -#endif // EIGEN2_SUPPORT +#endif } // end namespace Eigen diff --git a/libs/eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h b/libs/eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h index 5c8c476ee..1f8a531af 100644 --- a/libs/eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h +++ b/libs/eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h @@ -1,12 +1,14 @@ + /** \returns an expression of the coefficient wise product of \c *this and \a other * * \sa MatrixBase::cwiseProduct */ template -EIGEN_STRONG_INLINE const EIGEN_CWISE_PRODUCT_RETURN_TYPE(Derived,OtherDerived) +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE const EIGEN_CWISE_BINARY_RETURN_TYPE(Derived,OtherDerived,product) operator*(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const { - return EIGEN_CWISE_PRODUCT_RETURN_TYPE(Derived,OtherDerived)(derived(), other.derived()); + return EIGEN_CWISE_BINARY_RETURN_TYPE(Derived,OtherDerived,product)(derived(), other.derived()); } /** \returns an expression of the coefficient wise quotient of \c *this and \a other @@ -14,10 +16,11 @@ operator*(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const * \sa MatrixBase::cwiseQuotient */ template -EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const OtherDerived> +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const OtherDerived> operator/(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const { - return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); + return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); } /** \returns an expression of the coefficient-wise min of \c *this and \a other @@ -27,13 +30,14 @@ operator/(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const * * \sa max() */ -EIGEN_MAKE_CWISE_BINARY_OP(min,internal::scalar_min_op) +EIGEN_MAKE_CWISE_BINARY_OP(min,min) /** \returns an expression of the coefficient-wise min of \c *this and scalar \a other * * \sa max() */ -EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const CwiseNullaryOp, PlainObject> > #ifdef EIGEN_PARSED_BY_DOXYGEN min @@ -52,13 +56,14 @@ min * * \sa min() */ -EIGEN_MAKE_CWISE_BINARY_OP(max,internal::scalar_max_op) +EIGEN_MAKE_CWISE_BINARY_OP(max,max) /** \returns an expression of the coefficient-wise max of \c *this and scalar \a other * * \sa min() */ -EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const CwiseNullaryOp, PlainObject> > #ifdef EIGEN_PARSED_BY_DOXYGEN max @@ -70,6 +75,73 @@ max return (max)(Derived::PlainObject::Constant(rows(), cols(), other)); } +/** \returns an expression of the coefficient-wise power of \c *this to the given array of \a exponents. + * + * This function computes the coefficient-wise power. + * + * Example: \include Cwise_array_power_array.cpp + * Output: \verbinclude Cwise_array_power_array.out + */ +EIGEN_MAKE_CWISE_BINARY_OP(pow,pow) + +#ifndef EIGEN_PARSED_BY_DOXYGEN +EIGEN_MAKE_SCALAR_BINARY_OP_ONTHERIGHT(pow,pow) +#else +/** \returns an expression of the coefficients of \c *this rasied to the constant power \a exponent + * + * \tparam T is the scalar type of \a exponent. It must be compatible with the scalar type of the given expression. + * + * This function computes the coefficient-wise power. The function MatrixBase::pow() in the + * unsupported module MatrixFunctions computes the matrix power. + * + * Example: \include Cwise_pow.cpp + * Output: \verbinclude Cwise_pow.out + * + * \sa ArrayBase::pow(ArrayBase), square(), cube(), exp(), log() + */ +template +const CwiseBinaryOp,Derived,Constant > pow(const T& exponent) const; +#endif + + +// TODO code generating macros could be moved to Macros.h and could include generation of documentation +#define EIGEN_MAKE_CWISE_COMP_OP(OP, COMPARATOR) \ +template \ +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const OtherDerived> \ +OP(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const \ +{ \ + return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); \ +}\ +typedef CwiseBinaryOp, const Derived, const CwiseNullaryOp, PlainObject> > Cmp ## COMPARATOR ## ReturnType; \ +typedef CwiseBinaryOp, const CwiseNullaryOp, PlainObject>, const Derived > RCmp ## COMPARATOR ## ReturnType; \ +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Cmp ## COMPARATOR ## ReturnType \ +OP(const Scalar& s) const { \ + return this->OP(Derived::PlainObject::Constant(rows(), cols(), s)); \ +} \ +EIGEN_DEVICE_FUNC friend EIGEN_STRONG_INLINE const RCmp ## COMPARATOR ## ReturnType \ +OP(const Scalar& s, const Derived& d) { \ + return Derived::PlainObject::Constant(d.rows(), d.cols(), s).OP(d); \ +} + +#define EIGEN_MAKE_CWISE_COMP_R_OP(OP, R_OP, RCOMPARATOR) \ +template \ +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseBinaryOp, const OtherDerived, const Derived> \ +OP(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const \ +{ \ + return CwiseBinaryOp, const OtherDerived, const Derived>(other.derived(), derived()); \ +} \ +EIGEN_DEVICE_FUNC \ +inline const RCmp ## RCOMPARATOR ## ReturnType \ +OP(const Scalar& s) const { \ + return Derived::PlainObject::Constant(rows(), cols(), s).R_OP(*this); \ +} \ +friend inline const Cmp ## RCOMPARATOR ## ReturnType \ +OP(const Scalar& s, const Derived& d) { \ + return d.R_OP(Derived::PlainObject::Constant(d.rows(), d.cols(), s)); \ +} + + + /** \returns an expression of the coefficient-wise \< operator of *this and \a other * * Example: \include Cwise_less.cpp @@ -77,7 +149,7 @@ max * * \sa all(), any(), operator>(), operator<=() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator<,std::less) +EIGEN_MAKE_CWISE_COMP_OP(operator<, LT) /** \returns an expression of the coefficient-wise \<= operator of *this and \a other * @@ -86,7 +158,7 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator<,std::less) * * \sa all(), any(), operator>=(), operator<() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator<=,std::less_equal) +EIGEN_MAKE_CWISE_COMP_OP(operator<=, LE) /** \returns an expression of the coefficient-wise \> operator of *this and \a other * @@ -95,7 +167,7 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator<=,std::less_equal) * * \sa all(), any(), operator>=(), operator<() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator>,std::greater) +EIGEN_MAKE_CWISE_COMP_R_OP(operator>, operator<, LT) /** \returns an expression of the coefficient-wise \>= operator of *this and \a other * @@ -104,7 +176,7 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator>,std::greater) * * \sa all(), any(), operator>(), operator<=() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator>=,std::greater_equal) +EIGEN_MAKE_CWISE_COMP_R_OP(operator>=, operator<=, LE) /** \returns an expression of the coefficient-wise == operator of *this and \a other * @@ -118,7 +190,7 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator>=,std::greater_equal) * * \sa all(), any(), isApprox(), isMuchSmallerThan() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator==,std::equal_to) +EIGEN_MAKE_CWISE_COMP_OP(operator==, EQ) /** \returns an expression of the coefficient-wise != operator of *this and \a other * @@ -132,80 +204,129 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator==,std::equal_to) * * \sa all(), any(), isApprox(), isMuchSmallerThan() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator!=,std::not_equal_to) +EIGEN_MAKE_CWISE_COMP_OP(operator!=, NEQ) -// scalar addition +#undef EIGEN_MAKE_CWISE_COMP_OP +#undef EIGEN_MAKE_CWISE_COMP_R_OP + +// scalar addition +#ifndef EIGEN_PARSED_BY_DOXYGEN +EIGEN_MAKE_SCALAR_BINARY_OP(operator+,sum) +#else /** \returns an expression of \c *this with each coeff incremented by the constant \a scalar + * + * \tparam T is the scalar type of \a scalar. It must be compatible with the scalar type of the given expression. * * Example: \include Cwise_plus.cpp * Output: \verbinclude Cwise_plus.out * * \sa operator+=(), operator-() */ -inline const CwiseUnaryOp, const Derived> -operator+(const Scalar& scalar) const -{ - return CwiseUnaryOp, const Derived>(derived(), internal::scalar_add_op(scalar)); -} - -friend inline const CwiseUnaryOp, const Derived> -operator+(const Scalar& scalar,const EIGEN_CURRENT_STORAGE_BASE_CLASS& other) -{ - return other + scalar; -} +template +const CwiseBinaryOp,Derived,Constant > operator+(const T& scalar) const; +/** \returns an expression of \a expr with each coeff incremented by the constant \a scalar + * + * \tparam T is the scalar type of \a scalar. It must be compatible with the scalar type of the given expression. + */ +template friend +const CwiseBinaryOp,Constant,Derived> operator+(const T& scalar, const StorageBaseType& expr); +#endif +#ifndef EIGEN_PARSED_BY_DOXYGEN +EIGEN_MAKE_SCALAR_BINARY_OP(operator-,difference) +#else /** \returns an expression of \c *this with each coeff decremented by the constant \a scalar + * + * \tparam T is the scalar type of \a scalar. It must be compatible with the scalar type of the given expression. * * Example: \include Cwise_minus.cpp * Output: \verbinclude Cwise_minus.out * - * \sa operator+(), operator-=() + * \sa operator+=(), operator-() */ -inline const CwiseUnaryOp, const Derived> -operator-(const Scalar& scalar) const -{ - return *this + (-scalar); -} +template +const CwiseBinaryOp,Derived,Constant > operator-(const T& scalar) const; +/** \returns an expression of the constant matrix of value \a scalar decremented by the coefficients of \a expr + * + * \tparam T is the scalar type of \a scalar. It must be compatible with the scalar type of the given expression. + */ +template friend +const CwiseBinaryOp,Constant,Derived> operator-(const T& scalar, const StorageBaseType& expr); +#endif + + +#ifndef EIGEN_PARSED_BY_DOXYGEN + EIGEN_MAKE_SCALAR_BINARY_OP_ONTHELEFT(operator/,quotient) +#else + /** + * \brief Component-wise division of the scalar \a s by array elements of \a a. + * + * \tparam Scalar is the scalar type of \a x. It must be compatible with the scalar type of the given array expression (\c Derived::Scalar). + */ + template friend + inline const CwiseBinaryOp,Constant,Derived> + operator/(const T& s,const StorageBaseType& a); +#endif -friend inline const CwiseUnaryOp, const CwiseUnaryOp, const Derived> > -operator-(const Scalar& scalar,const EIGEN_CURRENT_STORAGE_BASE_CLASS& other) +/** \returns an expression of the coefficient-wise ^ operator of *this and \a other + * + * \warning this operator is for expression of bool only. + * + * Example: \include Cwise_boolean_xor.cpp + * Output: \verbinclude Cwise_boolean_xor.out + * + * \sa operator&&(), select() + */ +template +EIGEN_DEVICE_FUNC +inline const CwiseBinaryOp +operator^(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const { - return (-other) + scalar; + EIGEN_STATIC_ASSERT((internal::is_same::value && internal::is_same::value), + THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL); + return CwiseBinaryOp(derived(),other.derived()); } -/** \returns an expression of the coefficient-wise && operator of *this and \a other +// NOTE disabled until we agree on argument order +#if 0 +/** \cpp11 \returns an expression of the coefficient-wise polygamma function. + * + * \specialfunctions_module * - * \warning this operator is for expression of bool only. + * It returns the \a n -th derivative of the digamma(psi) evaluated at \c *this. * - * Example: \include Cwise_boolean_and.cpp - * Output: \verbinclude Cwise_boolean_and.out + * \warning Be careful with the order of the parameters: x.polygamma(n) is equivalent to polygamma(n,x) * - * \sa operator||(), select() + * \sa Eigen::polygamma() */ -template -inline const CwiseBinaryOp -operator&&(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const +template +inline const CwiseBinaryOp, const DerivedN, const Derived> +polygamma(const EIGEN_CURRENT_STORAGE_BASE_CLASS &n) const { - EIGEN_STATIC_ASSERT((internal::is_same::value && internal::is_same::value), - THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL); - return CwiseBinaryOp(derived(),other.derived()); + return CwiseBinaryOp, const DerivedN, const Derived>(n.derived(), this->derived()); } +#endif -/** \returns an expression of the coefficient-wise || operator of *this and \a other +/** \returns an expression of the coefficient-wise zeta function. + * + * \specialfunctions_module + * + * It returns the Riemann zeta function of two arguments \c *this and \a q: + * + * \param *this is the exposent, it must be > 1 + * \param q is the shift, it must be > 0 * - * \warning this operator is for expression of bool only. + * \note This function supports only float and double scalar types. To support other scalar types, the user has + * to provide implementations of zeta(T,T) for any scalar type T to be supported. * - * Example: \include Cwise_boolean_or.cpp - * Output: \verbinclude Cwise_boolean_or.out + * This method is an alias for zeta(*this,q); * - * \sa operator&&(), select() + * \sa Eigen::zeta() */ -template -inline const CwiseBinaryOp -operator||(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const +template +inline const CwiseBinaryOp, const Derived, const DerivedQ> +zeta(const EIGEN_CURRENT_STORAGE_BASE_CLASS &q) const { - EIGEN_STATIC_ASSERT((internal::is_same::value && internal::is_same::value), - THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL); - return CwiseBinaryOp(derived(),other.derived()); + return CwiseBinaryOp, const Derived, const DerivedQ>(this->derived(), q.derived()); } diff --git a/libs/eigen3/Eigen/src/plugins/ArrayCwiseUnaryOps.h b/libs/eigen3/Eigen/src/plugins/ArrayCwiseUnaryOps.h index a59636790..ebaa3f192 100644 --- a/libs/eigen3/Eigen/src/plugins/ArrayCwiseUnaryOps.h +++ b/libs/eigen3/Eigen/src/plugins/ArrayCwiseUnaryOps.h @@ -1,16 +1,62 @@ +typedef CwiseUnaryOp, const Derived> AbsReturnType; +typedef CwiseUnaryOp, const Derived> ArgReturnType; +typedef CwiseUnaryOp, const Derived> Abs2ReturnType; +typedef CwiseUnaryOp, const Derived> SqrtReturnType; +typedef CwiseUnaryOp, const Derived> RsqrtReturnType; +typedef CwiseUnaryOp, const Derived> SignReturnType; +typedef CwiseUnaryOp, const Derived> InverseReturnType; +typedef CwiseUnaryOp, const Derived> BooleanNotReturnType; + +typedef CwiseUnaryOp, const Derived> ExpReturnType; +typedef CwiseUnaryOp, const Derived> LogReturnType; +typedef CwiseUnaryOp, const Derived> Log1pReturnType; +typedef CwiseUnaryOp, const Derived> Log10ReturnType; +typedef CwiseUnaryOp, const Derived> CosReturnType; +typedef CwiseUnaryOp, const Derived> SinReturnType; +typedef CwiseUnaryOp, const Derived> TanReturnType; +typedef CwiseUnaryOp, const Derived> AcosReturnType; +typedef CwiseUnaryOp, const Derived> AsinReturnType; +typedef CwiseUnaryOp, const Derived> AtanReturnType; +typedef CwiseUnaryOp, const Derived> TanhReturnType; +typedef CwiseUnaryOp, const Derived> SinhReturnType; +typedef CwiseUnaryOp, const Derived> CoshReturnType; +typedef CwiseUnaryOp, const Derived> SquareReturnType; +typedef CwiseUnaryOp, const Derived> CubeReturnType; +typedef CwiseUnaryOp, const Derived> RoundReturnType; +typedef CwiseUnaryOp, const Derived> FloorReturnType; +typedef CwiseUnaryOp, const Derived> CeilReturnType; +typedef CwiseUnaryOp, const Derived> IsNaNReturnType; +typedef CwiseUnaryOp, const Derived> IsInfReturnType; +typedef CwiseUnaryOp, const Derived> IsFiniteReturnType; + /** \returns an expression of the coefficient-wise absolute value of \c *this * * Example: \include Cwise_abs.cpp * Output: \verbinclude Cwise_abs.out * - * \sa abs2() + * \sa Math functions, abs2() */ -EIGEN_STRONG_INLINE const CwiseUnaryOp, const Derived> +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE const AbsReturnType abs() const { - return derived(); + return AbsReturnType(derived()); +} + +/** \returns an expression of the coefficient-wise phase angle of \c *this + * + * Example: \include Cwise_arg.cpp + * Output: \verbinclude Cwise_arg.out + * + * \sa abs() + */ +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE const ArgReturnType +arg() const +{ + return ArgReturnType(derived()); } /** \returns an expression of the coefficient-wise squared absolute value of \c *this @@ -18,78 +64,190 @@ abs() const * Example: \include Cwise_abs2.cpp * Output: \verbinclude Cwise_abs2.out * - * \sa abs(), square() + * \sa Math functions, abs(), square() */ -EIGEN_STRONG_INLINE const CwiseUnaryOp, const Derived> +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE const Abs2ReturnType abs2() const { - return derived(); + return Abs2ReturnType(derived()); } /** \returns an expression of the coefficient-wise exponential of *this. + * + * This function computes the coefficient-wise exponential. The function MatrixBase::exp() in the + * unsupported module MatrixFunctions computes the matrix exponential. * * Example: \include Cwise_exp.cpp * Output: \verbinclude Cwise_exp.out * - * \sa pow(), log(), sin(), cos() + * \sa Math functions, pow(), log(), sin(), cos() */ -inline const CwiseUnaryOp, const Derived> +EIGEN_DEVICE_FUNC +inline const ExpReturnType exp() const { - return derived(); + return ExpReturnType(derived()); } /** \returns an expression of the coefficient-wise logarithm of *this. + * + * This function computes the coefficient-wise logarithm. The function MatrixBase::log() in the + * unsupported module MatrixFunctions computes the matrix logarithm. * * Example: \include Cwise_log.cpp * Output: \verbinclude Cwise_log.out * - * \sa exp() + * \sa Math functions, exp() */ -inline const CwiseUnaryOp, const Derived> +EIGEN_DEVICE_FUNC +inline const LogReturnType log() const { - return derived(); + return LogReturnType(derived()); +} + +/** \returns an expression of the coefficient-wise logarithm of 1 plus \c *this. + * + * In exact arithmetic, \c x.log() is equivalent to \c (x+1).log(), + * however, with finite precision, this function is much more accurate when \c x is close to zero. + * + * \sa Math functions, log() + */ +EIGEN_DEVICE_FUNC +inline const Log1pReturnType +log1p() const +{ + return Log1pReturnType(derived()); +} + +/** \returns an expression of the coefficient-wise base-10 logarithm of *this. + * + * This function computes the coefficient-wise base-10 logarithm. + * + * Example: \include Cwise_log10.cpp + * Output: \verbinclude Cwise_log10.out + * + * \sa Math functions, log() + */ +EIGEN_DEVICE_FUNC +inline const Log10ReturnType +log10() const +{ + return Log10ReturnType(derived()); } /** \returns an expression of the coefficient-wise square root of *this. + * + * This function computes the coefficient-wise square root. The function MatrixBase::sqrt() in the + * unsupported module MatrixFunctions computes the matrix square root. * * Example: \include Cwise_sqrt.cpp * Output: \verbinclude Cwise_sqrt.out * - * \sa pow(), square() + * \sa Math functions, pow(), square() */ -inline const CwiseUnaryOp, const Derived> +EIGEN_DEVICE_FUNC +inline const SqrtReturnType sqrt() const { - return derived(); + return SqrtReturnType(derived()); +} + +/** \returns an expression of the coefficient-wise inverse square root of *this. + * + * This function computes the coefficient-wise inverse square root. + * + * Example: \include Cwise_sqrt.cpp + * Output: \verbinclude Cwise_sqrt.out + * + * \sa pow(), square() + */ +EIGEN_DEVICE_FUNC +inline const RsqrtReturnType +rsqrt() const +{ + return RsqrtReturnType(derived()); } +/** \returns an expression of the coefficient-wise signum of *this. + * + * This function computes the coefficient-wise signum. + * + * Example: \include Cwise_sign.cpp + * Output: \verbinclude Cwise_sign.out + * + * \sa pow(), square() + */ +EIGEN_DEVICE_FUNC +inline const SignReturnType +sign() const +{ + return SignReturnType(derived()); +} + + /** \returns an expression of the coefficient-wise cosine of *this. + * + * This function computes the coefficient-wise cosine. The function MatrixBase::cos() in the + * unsupported module MatrixFunctions computes the matrix cosine. * * Example: \include Cwise_cos.cpp * Output: \verbinclude Cwise_cos.out * - * \sa sin(), acos() + * \sa Math functions, sin(), acos() */ -inline const CwiseUnaryOp, const Derived> +EIGEN_DEVICE_FUNC +inline const CosReturnType cos() const { - return derived(); + return CosReturnType(derived()); } /** \returns an expression of the coefficient-wise sine of *this. + * + * This function computes the coefficient-wise sine. The function MatrixBase::sin() in the + * unsupported module MatrixFunctions computes the matrix sine. * * Example: \include Cwise_sin.cpp * Output: \verbinclude Cwise_sin.out * - * \sa cos(), asin() + * \sa Math functions, cos(), asin() */ -inline const CwiseUnaryOp, const Derived> +EIGEN_DEVICE_FUNC +inline const SinReturnType sin() const { - return derived(); + return SinReturnType(derived()); +} + +/** \returns an expression of the coefficient-wise tan of *this. + * + * Example: \include Cwise_tan.cpp + * Output: \verbinclude Cwise_tan.out + * + * \sa Math functions, cos(), sin() + */ +EIGEN_DEVICE_FUNC +inline const TanReturnType +tan() const +{ + return TanReturnType(derived()); +} + +/** \returns an expression of the coefficient-wise arc tan of *this. + * + * Example: \include Cwise_atan.cpp + * Output: \verbinclude Cwise_atan.out + * + * \sa Math functions, tan(), asin(), acos() + */ +EIGEN_DEVICE_FUNC +inline const AtanReturnType +atan() const +{ + return AtanReturnType(derived()); } /** \returns an expression of the coefficient-wise arc cosine of *this. @@ -97,12 +255,13 @@ sin() const * Example: \include Cwise_acos.cpp * Output: \verbinclude Cwise_acos.out * - * \sa cos(), asin() + * \sa Math functions, cos(), asin() */ -inline const CwiseUnaryOp, const Derived> +EIGEN_DEVICE_FUNC +inline const AcosReturnType acos() const { - return derived(); + return AcosReturnType(derived()); } /** \returns an expression of the coefficient-wise arc sine of *this. @@ -110,42 +269,56 @@ acos() const * Example: \include Cwise_asin.cpp * Output: \verbinclude Cwise_asin.out * - * \sa sin(), acos() + * \sa Math functions, sin(), acos() */ -inline const CwiseUnaryOp, const Derived> +EIGEN_DEVICE_FUNC +inline const AsinReturnType asin() const { - return derived(); + return AsinReturnType(derived()); } -/** \returns an expression of the coefficient-wise tan of *this. +/** \returns an expression of the coefficient-wise hyperbolic tan of *this. * - * Example: \include Cwise_tan.cpp - * Output: \verbinclude Cwise_tan.out + * Example: \include Cwise_tanh.cpp + * Output: \verbinclude Cwise_tanh.out * - * \sa cos(), sin() + * \sa Math functions, tan(), sinh(), cosh() */ -inline const CwiseUnaryOp, Derived> -tan() const +EIGEN_DEVICE_FUNC +inline const TanhReturnType +tanh() const { - return derived(); + return TanhReturnType(derived()); } - -/** \returns an expression of the coefficient-wise power of *this to the given exponent. +/** \returns an expression of the coefficient-wise hyperbolic sin of *this. * - * Example: \include Cwise_pow.cpp - * Output: \verbinclude Cwise_pow.out + * Example: \include Cwise_sinh.cpp + * Output: \verbinclude Cwise_sinh.out * - * \sa exp(), log() + * \sa Math functions, sin(), tanh(), cosh() */ -inline const CwiseUnaryOp, const Derived> -pow(const Scalar& exponent) const +EIGEN_DEVICE_FUNC +inline const SinhReturnType +sinh() const { - return CwiseUnaryOp, const Derived> - (derived(), internal::scalar_pow_op(exponent)); + return SinhReturnType(derived()); } +/** \returns an expression of the coefficient-wise hyperbolic cos of *this. + * + * Example: \include Cwise_cosh.cpp + * Output: \verbinclude Cwise_cosh.out + * + * \sa Math functions, tan(), sinh(), cosh() + */ +EIGEN_DEVICE_FUNC +inline const CoshReturnType +cosh() const +{ + return CoshReturnType(derived()); +} /** \returns an expression of the coefficient-wise inverse of *this. * @@ -154,10 +327,11 @@ pow(const Scalar& exponent) const * * \sa operator/(), operator*() */ -inline const CwiseUnaryOp, const Derived> +EIGEN_DEVICE_FUNC +inline const InverseReturnType inverse() const { - return derived(); + return InverseReturnType(derived()); } /** \returns an expression of the coefficient-wise square of *this. @@ -165,12 +339,13 @@ inverse() const * Example: \include Cwise_square.cpp * Output: \verbinclude Cwise_square.out * - * \sa operator/(), operator*(), abs2() + * \sa Math functions, abs2(), cube(), pow() */ -inline const CwiseUnaryOp, const Derived> +EIGEN_DEVICE_FUNC +inline const SquareReturnType square() const { - return derived(); + return SquareReturnType(derived()); } /** \returns an expression of the coefficient-wise cube of *this. @@ -178,26 +353,200 @@ square() const * Example: \include Cwise_cube.cpp * Output: \verbinclude Cwise_cube.out * - * \sa square(), pow() + * \sa Math functions, square(), pow() */ -inline const CwiseUnaryOp, const Derived> +EIGEN_DEVICE_FUNC +inline const CubeReturnType cube() const { - return derived(); + return CubeReturnType(derived()); } -#define EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(METHOD_NAME,FUNCTOR) \ - inline const CwiseUnaryOp >, const Derived> \ - METHOD_NAME(const Scalar& s) const { \ - return CwiseUnaryOp >, const Derived> \ - (derived(), std::bind2nd(FUNCTOR(), s)); \ - } +/** \returns an expression of the coefficient-wise round of *this. + * + * Example: \include Cwise_round.cpp + * Output: \verbinclude Cwise_round.out + * + * \sa Math functions, ceil(), floor() + */ +EIGEN_DEVICE_FUNC +inline const RoundReturnType +round() const +{ + return RoundReturnType(derived()); +} + +/** \returns an expression of the coefficient-wise floor of *this. + * + * Example: \include Cwise_floor.cpp + * Output: \verbinclude Cwise_floor.out + * + * \sa Math functions, ceil(), round() + */ +EIGEN_DEVICE_FUNC +inline const FloorReturnType +floor() const +{ + return FloorReturnType(derived()); +} + +/** \returns an expression of the coefficient-wise ceil of *this. + * + * Example: \include Cwise_ceil.cpp + * Output: \verbinclude Cwise_ceil.out + * + * \sa Math functions, floor(), round() + */ +EIGEN_DEVICE_FUNC +inline const CeilReturnType +ceil() const +{ + return CeilReturnType(derived()); +} + +/** \returns an expression of the coefficient-wise isnan of *this. + * + * Example: \include Cwise_isNaN.cpp + * Output: \verbinclude Cwise_isNaN.out + * + * \sa isfinite(), isinf() + */ +EIGEN_DEVICE_FUNC +inline const IsNaNReturnType +isNaN() const +{ + return IsNaNReturnType(derived()); +} + +/** \returns an expression of the coefficient-wise isinf of *this. + * + * Example: \include Cwise_isInf.cpp + * Output: \verbinclude Cwise_isInf.out + * + * \sa isnan(), isfinite() + */ +EIGEN_DEVICE_FUNC +inline const IsInfReturnType +isInf() const +{ + return IsInfReturnType(derived()); +} + +/** \returns an expression of the coefficient-wise isfinite of *this. + * + * Example: \include Cwise_isFinite.cpp + * Output: \verbinclude Cwise_isFinite.out + * + * \sa isnan(), isinf() + */ +EIGEN_DEVICE_FUNC +inline const IsFiniteReturnType +isFinite() const +{ + return IsFiniteReturnType(derived()); +} + +/** \returns an expression of the coefficient-wise ! operator of *this + * + * \warning this operator is for expression of bool only. + * + * Example: \include Cwise_boolean_not.cpp + * Output: \verbinclude Cwise_boolean_not.out + * + * \sa operator!=() + */ +EIGEN_DEVICE_FUNC +inline const BooleanNotReturnType +operator!() const +{ + EIGEN_STATIC_ASSERT((internal::is_same::value), + THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL); + return BooleanNotReturnType(derived()); +} + + +// --- SpecialFunctions module --- + +typedef CwiseUnaryOp, const Derived> LgammaReturnType; +typedef CwiseUnaryOp, const Derived> DigammaReturnType; +typedef CwiseUnaryOp, const Derived> ErfReturnType; +typedef CwiseUnaryOp, const Derived> ErfcReturnType; + +/** \cpp11 \returns an expression of the coefficient-wise ln(|gamma(*this)|). + * + * \specialfunctions_module + * + * Example: \include Cwise_lgamma.cpp + * Output: \verbinclude Cwise_lgamma.out + * + * \note This function supports only float and double scalar types in c++11 mode. To support other scalar types, + * or float/double in non c++11 mode, the user has to provide implementations of lgamma(T) for any scalar + * type T to be supported. + * + * \sa Math functions, digamma() + */ +EIGEN_DEVICE_FUNC +inline const LgammaReturnType +lgamma() const +{ + return LgammaReturnType(derived()); +} -EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator==, std::equal_to) -EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator!=, std::not_equal_to) -EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator<, std::less) -EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator<=, std::less_equal) -EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator>, std::greater) -EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator>=, std::greater_equal) +/** \returns an expression of the coefficient-wise digamma (psi, derivative of lgamma). + * + * \specialfunctions_module + * + * \note This function supports only float and double scalar types. To support other scalar types, + * the user has to provide implementations of digamma(T) for any scalar + * type T to be supported. + * + * \sa Math functions, Eigen::digamma(), Eigen::polygamma(), lgamma() + */ +EIGEN_DEVICE_FUNC +inline const DigammaReturnType +digamma() const +{ + return DigammaReturnType(derived()); +} +/** \cpp11 \returns an expression of the coefficient-wise Gauss error + * function of *this. + * + * \specialfunctions_module + * + * Example: \include Cwise_erf.cpp + * Output: \verbinclude Cwise_erf.out + * + * \note This function supports only float and double scalar types in c++11 mode. To support other scalar types, + * or float/double in non c++11 mode, the user has to provide implementations of erf(T) for any scalar + * type T to be supported. + * + * \sa Math functions, erfc() + */ +EIGEN_DEVICE_FUNC +inline const ErfReturnType +erf() const +{ + return ErfReturnType(derived()); +} +/** \cpp11 \returns an expression of the coefficient-wise Complementary error + * function of *this. + * + * \specialfunctions_module + * + * Example: \include Cwise_erfc.cpp + * Output: \verbinclude Cwise_erfc.out + * + * \note This function supports only float and double scalar types in c++11 mode. To support other scalar types, + * or float/double in non c++11 mode, the user has to provide implementations of erfc(T) for any scalar + * type T to be supported. + * + * \sa Math functions, erf() + */ +EIGEN_DEVICE_FUNC +inline const ErfcReturnType +erfc() const +{ + return ErfcReturnType(derived()); +} diff --git a/libs/eigen3/Eigen/src/plugins/BlockMethods.h b/libs/eigen3/Eigen/src/plugins/BlockMethods.h index 2788251e0..ac35a0086 100644 --- a/libs/eigen3/Eigen/src/plugins/BlockMethods.h +++ b/libs/eigen3/Eigen/src/plugins/BlockMethods.h @@ -8,27 +8,32 @@ // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - #ifndef EIGEN_PARSED_BY_DOXYGEN -/** \internal expression type of a column */ +/// \internal expression type of a column */ typedef Block::RowsAtCompileTime, 1, !IsRowMajor> ColXpr; typedef const Block::RowsAtCompileTime, 1, !IsRowMajor> ConstColXpr; -/** \internal expression type of a row */ +/// \internal expression type of a row */ typedef Block::ColsAtCompileTime, IsRowMajor> RowXpr; typedef const Block::ColsAtCompileTime, IsRowMajor> ConstRowXpr; -/** \internal expression type of a block of whole columns */ +/// \internal expression type of a block of whole columns */ typedef Block::RowsAtCompileTime, Dynamic, !IsRowMajor> ColsBlockXpr; typedef const Block::RowsAtCompileTime, Dynamic, !IsRowMajor> ConstColsBlockXpr; -/** \internal expression type of a block of whole rows */ +/// \internal expression type of a block of whole rows */ typedef Block::ColsAtCompileTime, IsRowMajor> RowsBlockXpr; typedef const Block::ColsAtCompileTime, IsRowMajor> ConstRowsBlockXpr; -/** \internal expression type of a block of whole columns */ +/// \internal expression type of a block of whole columns */ template struct NColsBlockXpr { typedef Block::RowsAtCompileTime, N, !IsRowMajor> Type; }; template struct ConstNColsBlockXpr { typedef const Block::RowsAtCompileTime, N, !IsRowMajor> Type; }; -/** \internal expression type of a block of whole rows */ +/// \internal expression type of a block of whole rows */ template struct NRowsBlockXpr { typedef Block::ColsAtCompileTime, IsRowMajor> Type; }; template struct ConstNRowsBlockXpr { typedef const Block::ColsAtCompileTime, IsRowMajor> Type; }; +/// \internal expression of a block */ +typedef Block BlockXpr; +typedef const Block ConstBlockXpr; +/// \internal expression of a block of fixed sizes */ +template struct FixedBlockXpr { typedef Block Type; }; +template struct ConstFixedBlockXpr { typedef Block Type; }; typedef VectorBlock SegmentReturnType; typedef const VectorBlock ConstSegmentReturnType; @@ -37,378 +42,430 @@ template struct ConstFixedSegmentReturnType { typedef const VectorBloc #endif // not EIGEN_PARSED_BY_DOXYGEN -/** \returns a dynamic-size expression of a block in *this. - * - * \param startRow the first row in the block - * \param startCol the first column in the block - * \param blockRows the number of rows in the block - * \param blockCols the number of columns in the block - * - * Example: \include MatrixBase_block_int_int_int_int.cpp - * Output: \verbinclude MatrixBase_block_int_int_int_int.out - * - * \note Even though the returned expression has dynamic size, in the case - * when it is applied to a fixed-size matrix, it inherits a fixed maximal size, - * which means that evaluating it does not cause a dynamic memory allocation. - * - * \sa class Block, block(Index,Index) - */ -inline Block block(Index startRow, Index startCol, Index blockRows, Index blockCols) -{ - return Block(derived(), startRow, startCol, blockRows, blockCols); -} - -/** This is the const version of block(Index,Index,Index,Index). */ -inline const Block block(Index startRow, Index startCol, Index blockRows, Index blockCols) const -{ - return Block(derived(), startRow, startCol, blockRows, blockCols); -} - - - - -/** \returns a dynamic-size expression of a top-right corner of *this. - * - * \param cRows the number of rows in the corner - * \param cCols the number of columns in the corner - * - * Example: \include MatrixBase_topRightCorner_int_int.cpp - * Output: \verbinclude MatrixBase_topRightCorner_int_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -inline Block topRightCorner(Index cRows, Index cCols) -{ - return Block(derived(), 0, cols() - cCols, cRows, cCols); -} - -/** This is the const version of topRightCorner(Index, Index).*/ -inline const Block topRightCorner(Index cRows, Index cCols) const -{ - return Block(derived(), 0, cols() - cCols, cRows, cCols); -} - -/** \returns an expression of a fixed-size top-right corner of *this. - * - * \tparam CRows the number of rows in the corner - * \tparam CCols the number of columns in the corner - * - * Example: \include MatrixBase_template_int_int_topRightCorner.cpp - * Output: \verbinclude MatrixBase_template_int_int_topRightCorner.out - * - * \sa class Block, block(Index,Index) - */ +/// \returns a dynamic-size expression of a block in *this. +/// +/// \param startRow the first row in the block +/// \param startCol the first column in the block +/// \param blockRows the number of rows in the block +/// \param blockCols the number of columns in the block +/// +/// Example: \include MatrixBase_block_int_int_int_int.cpp +/// Output: \verbinclude MatrixBase_block_int_int_int_int.out +/// +/// \note Even though the returned expression has dynamic size, in the case +/// when it is applied to a fixed-size matrix, it inherits a fixed maximal size, +/// which means that evaluating it does not cause a dynamic memory allocation. +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa class Block, block(Index,Index) +/// +EIGEN_DEVICE_FUNC +inline BlockXpr block(Index startRow, Index startCol, Index blockRows, Index blockCols) +{ + return BlockXpr(derived(), startRow, startCol, blockRows, blockCols); +} + +/// This is the const version of block(Index,Index,Index,Index). */ +EIGEN_DEVICE_FUNC +inline const ConstBlockXpr block(Index startRow, Index startCol, Index blockRows, Index blockCols) const +{ + return ConstBlockXpr(derived(), startRow, startCol, blockRows, blockCols); +} + + + + +/// \returns a dynamic-size expression of a top-right corner of *this. +/// +/// \param cRows the number of rows in the corner +/// \param cCols the number of columns in the corner +/// +/// Example: \include MatrixBase_topRightCorner_int_int.cpp +/// Output: \verbinclude MatrixBase_topRightCorner_int_int.out +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// +EIGEN_DEVICE_FUNC +inline BlockXpr topRightCorner(Index cRows, Index cCols) +{ + return BlockXpr(derived(), 0, cols() - cCols, cRows, cCols); +} + +/// This is the const version of topRightCorner(Index, Index). +EIGEN_DEVICE_FUNC +inline const ConstBlockXpr topRightCorner(Index cRows, Index cCols) const +{ + return ConstBlockXpr(derived(), 0, cols() - cCols, cRows, cCols); +} + +/// \returns an expression of a fixed-size top-right corner of *this. +/// +/// \tparam CRows the number of rows in the corner +/// \tparam CCols the number of columns in the corner +/// +/// Example: \include MatrixBase_template_int_int_topRightCorner.cpp +/// Output: \verbinclude MatrixBase_template_int_int_topRightCorner.out +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa class Block, block(Index,Index) +/// template -inline Block topRightCorner() +EIGEN_DEVICE_FUNC +inline typename FixedBlockXpr::Type topRightCorner() { - return Block(derived(), 0, cols() - CCols); + return typename FixedBlockXpr::Type(derived(), 0, cols() - CCols); } -/** This is the const version of topRightCorner().*/ +/// This is the const version of topRightCorner(). template -inline const Block topRightCorner() const -{ - return Block(derived(), 0, cols() - CCols); -} - -/** \returns an expression of a top-right corner of *this. - * - * \tparam CRows number of rows in corner as specified at compile-time - * \tparam CCols number of columns in corner as specified at compile-time - * \param cRows number of rows in corner as specified at run-time - * \param cCols number of columns in corner as specified at run-time - * - * This function is mainly useful for corners where the number of rows is specified at compile-time - * and the number of columns is specified at run-time, or vice versa. The compile-time and run-time - * information should not contradict. In other words, \a cRows should equal \a CRows unless - * \a CRows is \a Dynamic, and the same for the number of columns. - * - * Example: \include MatrixBase_template_int_int_topRightCorner_int_int.cpp - * Output: \verbinclude MatrixBase_template_int_int_topRightCorner_int_int.out - * - * \sa class Block - */ +EIGEN_DEVICE_FUNC +inline const typename ConstFixedBlockXpr::Type topRightCorner() const +{ + return typename ConstFixedBlockXpr::Type(derived(), 0, cols() - CCols); +} + +/// \returns an expression of a top-right corner of *this. +/// +/// \tparam CRows number of rows in corner as specified at compile-time +/// \tparam CCols number of columns in corner as specified at compile-time +/// \param cRows number of rows in corner as specified at run-time +/// \param cCols number of columns in corner as specified at run-time +/// +/// This function is mainly useful for corners where the number of rows is specified at compile-time +/// and the number of columns is specified at run-time, or vice versa. The compile-time and run-time +/// information should not contradict. In other words, \a cRows should equal \a CRows unless +/// \a CRows is \a Dynamic, and the same for the number of columns. +/// +/// Example: \include MatrixBase_template_int_int_topRightCorner_int_int.cpp +/// Output: \verbinclude MatrixBase_template_int_int_topRightCorner_int_int.out +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa class Block +/// template -inline Block topRightCorner(Index cRows, Index cCols) +inline typename FixedBlockXpr::Type topRightCorner(Index cRows, Index cCols) { - return Block(derived(), 0, cols() - cCols, cRows, cCols); + return typename FixedBlockXpr::Type(derived(), 0, cols() - cCols, cRows, cCols); } -/** This is the const version of topRightCorner(Index, Index).*/ +/// This is the const version of topRightCorner(Index, Index). template -inline const Block topRightCorner(Index cRows, Index cCols) const +inline const typename ConstFixedBlockXpr::Type topRightCorner(Index cRows, Index cCols) const { - return Block(derived(), 0, cols() - cCols, cRows, cCols); + return typename ConstFixedBlockXpr::Type(derived(), 0, cols() - cCols, cRows, cCols); } -/** \returns a dynamic-size expression of a top-left corner of *this. - * - * \param cRows the number of rows in the corner - * \param cCols the number of columns in the corner - * - * Example: \include MatrixBase_topLeftCorner_int_int.cpp - * Output: \verbinclude MatrixBase_topLeftCorner_int_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -inline Block topLeftCorner(Index cRows, Index cCols) +/// \returns a dynamic-size expression of a top-left corner of *this. +/// +/// \param cRows the number of rows in the corner +/// \param cCols the number of columns in the corner +/// +/// Example: \include MatrixBase_topLeftCorner_int_int.cpp +/// Output: \verbinclude MatrixBase_topLeftCorner_int_int.out +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// +EIGEN_DEVICE_FUNC +inline BlockXpr topLeftCorner(Index cRows, Index cCols) { - return Block(derived(), 0, 0, cRows, cCols); + return BlockXpr(derived(), 0, 0, cRows, cCols); } -/** This is the const version of topLeftCorner(Index, Index).*/ -inline const Block topLeftCorner(Index cRows, Index cCols) const +/// This is the const version of topLeftCorner(Index, Index). +EIGEN_DEVICE_FUNC +inline const ConstBlockXpr topLeftCorner(Index cRows, Index cCols) const { - return Block(derived(), 0, 0, cRows, cCols); + return ConstBlockXpr(derived(), 0, 0, cRows, cCols); } -/** \returns an expression of a fixed-size top-left corner of *this. - * - * The template parameters CRows and CCols are the number of rows and columns in the corner. - * - * Example: \include MatrixBase_template_int_int_topLeftCorner.cpp - * Output: \verbinclude MatrixBase_template_int_int_topLeftCorner.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ +/// \returns an expression of a fixed-size top-left corner of *this. +/// +/// The template parameters CRows and CCols are the number of rows and columns in the corner. +/// +/// Example: \include MatrixBase_template_int_int_topLeftCorner.cpp +/// Output: \verbinclude MatrixBase_template_int_int_topLeftCorner.out +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// template -inline Block topLeftCorner() +EIGEN_DEVICE_FUNC +inline typename FixedBlockXpr::Type topLeftCorner() { - return Block(derived(), 0, 0); + return typename FixedBlockXpr::Type(derived(), 0, 0); } -/** This is the const version of topLeftCorner().*/ +/// This is the const version of topLeftCorner(). template -inline const Block topLeftCorner() const -{ - return Block(derived(), 0, 0); -} - -/** \returns an expression of a top-left corner of *this. - * - * \tparam CRows number of rows in corner as specified at compile-time - * \tparam CCols number of columns in corner as specified at compile-time - * \param cRows number of rows in corner as specified at run-time - * \param cCols number of columns in corner as specified at run-time - * - * This function is mainly useful for corners where the number of rows is specified at compile-time - * and the number of columns is specified at run-time, or vice versa. The compile-time and run-time - * information should not contradict. In other words, \a cRows should equal \a CRows unless - * \a CRows is \a Dynamic, and the same for the number of columns. - * - * Example: \include MatrixBase_template_int_int_topLeftCorner_int_int.cpp - * Output: \verbinclude MatrixBase_template_int_int_topLeftCorner_int_int.out - * - * \sa class Block - */ +EIGEN_DEVICE_FUNC +inline const typename ConstFixedBlockXpr::Type topLeftCorner() const +{ + return typename ConstFixedBlockXpr::Type(derived(), 0, 0); +} + +/// \returns an expression of a top-left corner of *this. +/// +/// \tparam CRows number of rows in corner as specified at compile-time +/// \tparam CCols number of columns in corner as specified at compile-time +/// \param cRows number of rows in corner as specified at run-time +/// \param cCols number of columns in corner as specified at run-time +/// +/// This function is mainly useful for corners where the number of rows is specified at compile-time +/// and the number of columns is specified at run-time, or vice versa. The compile-time and run-time +/// information should not contradict. In other words, \a cRows should equal \a CRows unless +/// \a CRows is \a Dynamic, and the same for the number of columns. +/// +/// Example: \include MatrixBase_template_int_int_topLeftCorner_int_int.cpp +/// Output: \verbinclude MatrixBase_template_int_int_topLeftCorner_int_int.out +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa class Block +/// template -inline Block topLeftCorner(Index cRows, Index cCols) +inline typename FixedBlockXpr::Type topLeftCorner(Index cRows, Index cCols) { - return Block(derived(), 0, 0, cRows, cCols); + return typename FixedBlockXpr::Type(derived(), 0, 0, cRows, cCols); } -/** This is the const version of topLeftCorner(Index, Index).*/ +/// This is the const version of topLeftCorner(Index, Index). template -inline const Block topLeftCorner(Index cRows, Index cCols) const +inline const typename ConstFixedBlockXpr::Type topLeftCorner(Index cRows, Index cCols) const { - return Block(derived(), 0, 0, cRows, cCols); + return typename ConstFixedBlockXpr::Type(derived(), 0, 0, cRows, cCols); } -/** \returns a dynamic-size expression of a bottom-right corner of *this. - * - * \param cRows the number of rows in the corner - * \param cCols the number of columns in the corner - * - * Example: \include MatrixBase_bottomRightCorner_int_int.cpp - * Output: \verbinclude MatrixBase_bottomRightCorner_int_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -inline Block bottomRightCorner(Index cRows, Index cCols) +/// \returns a dynamic-size expression of a bottom-right corner of *this. +/// +/// \param cRows the number of rows in the corner +/// \param cCols the number of columns in the corner +/// +/// Example: \include MatrixBase_bottomRightCorner_int_int.cpp +/// Output: \verbinclude MatrixBase_bottomRightCorner_int_int.out +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// +EIGEN_DEVICE_FUNC +inline BlockXpr bottomRightCorner(Index cRows, Index cCols) { - return Block(derived(), rows() - cRows, cols() - cCols, cRows, cCols); + return BlockXpr(derived(), rows() - cRows, cols() - cCols, cRows, cCols); } -/** This is the const version of bottomRightCorner(Index, Index).*/ -inline const Block bottomRightCorner(Index cRows, Index cCols) const +/// This is the const version of bottomRightCorner(Index, Index). +EIGEN_DEVICE_FUNC +inline const ConstBlockXpr bottomRightCorner(Index cRows, Index cCols) const { - return Block(derived(), rows() - cRows, cols() - cCols, cRows, cCols); + return ConstBlockXpr(derived(), rows() - cRows, cols() - cCols, cRows, cCols); } -/** \returns an expression of a fixed-size bottom-right corner of *this. - * - * The template parameters CRows and CCols are the number of rows and columns in the corner. - * - * Example: \include MatrixBase_template_int_int_bottomRightCorner.cpp - * Output: \verbinclude MatrixBase_template_int_int_bottomRightCorner.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ +/// \returns an expression of a fixed-size bottom-right corner of *this. +/// +/// The template parameters CRows and CCols are the number of rows and columns in the corner. +/// +/// Example: \include MatrixBase_template_int_int_bottomRightCorner.cpp +/// Output: \verbinclude MatrixBase_template_int_int_bottomRightCorner.out +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// template -inline Block bottomRightCorner() +EIGEN_DEVICE_FUNC +inline typename FixedBlockXpr::Type bottomRightCorner() { - return Block(derived(), rows() - CRows, cols() - CCols); + return typename FixedBlockXpr::Type(derived(), rows() - CRows, cols() - CCols); } -/** This is the const version of bottomRightCorner().*/ +/// This is the const version of bottomRightCorner(). template -inline const Block bottomRightCorner() const -{ - return Block(derived(), rows() - CRows, cols() - CCols); -} - -/** \returns an expression of a bottom-right corner of *this. - * - * \tparam CRows number of rows in corner as specified at compile-time - * \tparam CCols number of columns in corner as specified at compile-time - * \param cRows number of rows in corner as specified at run-time - * \param cCols number of columns in corner as specified at run-time - * - * This function is mainly useful for corners where the number of rows is specified at compile-time - * and the number of columns is specified at run-time, or vice versa. The compile-time and run-time - * information should not contradict. In other words, \a cRows should equal \a CRows unless - * \a CRows is \a Dynamic, and the same for the number of columns. - * - * Example: \include MatrixBase_template_int_int_bottomRightCorner_int_int.cpp - * Output: \verbinclude MatrixBase_template_int_int_bottomRightCorner_int_int.out - * - * \sa class Block - */ +EIGEN_DEVICE_FUNC +inline const typename ConstFixedBlockXpr::Type bottomRightCorner() const +{ + return typename ConstFixedBlockXpr::Type(derived(), rows() - CRows, cols() - CCols); +} + +/// \returns an expression of a bottom-right corner of *this. +/// +/// \tparam CRows number of rows in corner as specified at compile-time +/// \tparam CCols number of columns in corner as specified at compile-time +/// \param cRows number of rows in corner as specified at run-time +/// \param cCols number of columns in corner as specified at run-time +/// +/// This function is mainly useful for corners where the number of rows is specified at compile-time +/// and the number of columns is specified at run-time, or vice versa. The compile-time and run-time +/// information should not contradict. In other words, \a cRows should equal \a CRows unless +/// \a CRows is \a Dynamic, and the same for the number of columns. +/// +/// Example: \include MatrixBase_template_int_int_bottomRightCorner_int_int.cpp +/// Output: \verbinclude MatrixBase_template_int_int_bottomRightCorner_int_int.out +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa class Block +/// template -inline Block bottomRightCorner(Index cRows, Index cCols) +inline typename FixedBlockXpr::Type bottomRightCorner(Index cRows, Index cCols) { - return Block(derived(), rows() - cRows, cols() - cCols, cRows, cCols); + return typename FixedBlockXpr::Type(derived(), rows() - cRows, cols() - cCols, cRows, cCols); } -/** This is the const version of bottomRightCorner(Index, Index).*/ +/// This is the const version of bottomRightCorner(Index, Index). template -inline const Block bottomRightCorner(Index cRows, Index cCols) const +inline const typename ConstFixedBlockXpr::Type bottomRightCorner(Index cRows, Index cCols) const { - return Block(derived(), rows() - cRows, cols() - cCols, cRows, cCols); + return typename ConstFixedBlockXpr::Type(derived(), rows() - cRows, cols() - cCols, cRows, cCols); } -/** \returns a dynamic-size expression of a bottom-left corner of *this. - * - * \param cRows the number of rows in the corner - * \param cCols the number of columns in the corner - * - * Example: \include MatrixBase_bottomLeftCorner_int_int.cpp - * Output: \verbinclude MatrixBase_bottomLeftCorner_int_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -inline Block bottomLeftCorner(Index cRows, Index cCols) +/// \returns a dynamic-size expression of a bottom-left corner of *this. +/// +/// \param cRows the number of rows in the corner +/// \param cCols the number of columns in the corner +/// +/// Example: \include MatrixBase_bottomLeftCorner_int_int.cpp +/// Output: \verbinclude MatrixBase_bottomLeftCorner_int_int.out +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// +EIGEN_DEVICE_FUNC +inline BlockXpr bottomLeftCorner(Index cRows, Index cCols) { - return Block(derived(), rows() - cRows, 0, cRows, cCols); + return BlockXpr(derived(), rows() - cRows, 0, cRows, cCols); } -/** This is the const version of bottomLeftCorner(Index, Index).*/ -inline const Block bottomLeftCorner(Index cRows, Index cCols) const +/// This is the const version of bottomLeftCorner(Index, Index). +EIGEN_DEVICE_FUNC +inline const ConstBlockXpr bottomLeftCorner(Index cRows, Index cCols) const { - return Block(derived(), rows() - cRows, 0, cRows, cCols); + return ConstBlockXpr(derived(), rows() - cRows, 0, cRows, cCols); } -/** \returns an expression of a fixed-size bottom-left corner of *this. - * - * The template parameters CRows and CCols are the number of rows and columns in the corner. - * - * Example: \include MatrixBase_template_int_int_bottomLeftCorner.cpp - * Output: \verbinclude MatrixBase_template_int_int_bottomLeftCorner.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ +/// \returns an expression of a fixed-size bottom-left corner of *this. +/// +/// The template parameters CRows and CCols are the number of rows and columns in the corner. +/// +/// Example: \include MatrixBase_template_int_int_bottomLeftCorner.cpp +/// Output: \verbinclude MatrixBase_template_int_int_bottomLeftCorner.out +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// template -inline Block bottomLeftCorner() +EIGEN_DEVICE_FUNC +inline typename FixedBlockXpr::Type bottomLeftCorner() { - return Block(derived(), rows() - CRows, 0); + return typename FixedBlockXpr::Type(derived(), rows() - CRows, 0); } -/** This is the const version of bottomLeftCorner().*/ +/// This is the const version of bottomLeftCorner(). template -inline const Block bottomLeftCorner() const -{ - return Block(derived(), rows() - CRows, 0); -} - -/** \returns an expression of a bottom-left corner of *this. - * - * \tparam CRows number of rows in corner as specified at compile-time - * \tparam CCols number of columns in corner as specified at compile-time - * \param cRows number of rows in corner as specified at run-time - * \param cCols number of columns in corner as specified at run-time - * - * This function is mainly useful for corners where the number of rows is specified at compile-time - * and the number of columns is specified at run-time, or vice versa. The compile-time and run-time - * information should not contradict. In other words, \a cRows should equal \a CRows unless - * \a CRows is \a Dynamic, and the same for the number of columns. - * - * Example: \include MatrixBase_template_int_int_bottomLeftCorner_int_int.cpp - * Output: \verbinclude MatrixBase_template_int_int_bottomLeftCorner_int_int.out - * - * \sa class Block - */ +EIGEN_DEVICE_FUNC +inline const typename ConstFixedBlockXpr::Type bottomLeftCorner() const +{ + return typename ConstFixedBlockXpr::Type(derived(), rows() - CRows, 0); +} + +/// \returns an expression of a bottom-left corner of *this. +/// +/// \tparam CRows number of rows in corner as specified at compile-time +/// \tparam CCols number of columns in corner as specified at compile-time +/// \param cRows number of rows in corner as specified at run-time +/// \param cCols number of columns in corner as specified at run-time +/// +/// This function is mainly useful for corners where the number of rows is specified at compile-time +/// and the number of columns is specified at run-time, or vice versa. The compile-time and run-time +/// information should not contradict. In other words, \a cRows should equal \a CRows unless +/// \a CRows is \a Dynamic, and the same for the number of columns. +/// +/// Example: \include MatrixBase_template_int_int_bottomLeftCorner_int_int.cpp +/// Output: \verbinclude MatrixBase_template_int_int_bottomLeftCorner_int_int.out +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa class Block +/// template -inline Block bottomLeftCorner(Index cRows, Index cCols) +inline typename FixedBlockXpr::Type bottomLeftCorner(Index cRows, Index cCols) { - return Block(derived(), rows() - cRows, 0, cRows, cCols); + return typename FixedBlockXpr::Type(derived(), rows() - cRows, 0, cRows, cCols); } -/** This is the const version of bottomLeftCorner(Index, Index).*/ +/// This is the const version of bottomLeftCorner(Index, Index). template -inline const Block bottomLeftCorner(Index cRows, Index cCols) const +inline const typename ConstFixedBlockXpr::Type bottomLeftCorner(Index cRows, Index cCols) const { - return Block(derived(), rows() - cRows, 0, cRows, cCols); + return typename ConstFixedBlockXpr::Type(derived(), rows() - cRows, 0, cRows, cCols); } -/** \returns a block consisting of the top rows of *this. - * - * \param n the number of rows in the block - * - * Example: \include MatrixBase_topRows_int.cpp - * Output: \verbinclude MatrixBase_topRows_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ +/// \returns a block consisting of the top rows of *this. +/// +/// \param n the number of rows in the block +/// +/// Example: \include MatrixBase_topRows_int.cpp +/// Output: \verbinclude MatrixBase_topRows_int.out +/// +EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// +EIGEN_DEVICE_FUNC inline RowsBlockXpr topRows(Index n) { return RowsBlockXpr(derived(), 0, 0, n, cols()); } -/** This is the const version of topRows(Index).*/ +/// This is the const version of topRows(Index). +EIGEN_DEVICE_FUNC inline ConstRowsBlockXpr topRows(Index n) const { return ConstRowsBlockXpr(derived(), 0, 0, n, cols()); } -/** \returns a block consisting of the top rows of *this. - * - * \tparam N the number of rows in the block as specified at compile-time - * \param n the number of rows in the block as specified at run-time - * - * The compile-time and run-time information should not contradict. In other words, - * \a n should equal \a N unless \a N is \a Dynamic. - * - * Example: \include MatrixBase_template_int_topRows.cpp - * Output: \verbinclude MatrixBase_template_int_topRows.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ +/// \returns a block consisting of the top rows of *this. +/// +/// \tparam N the number of rows in the block as specified at compile-time +/// \param n the number of rows in the block as specified at run-time +/// +/// The compile-time and run-time information should not contradict. In other words, +/// \a n should equal \a N unless \a N is \a Dynamic. +/// +/// Example: \include MatrixBase_template_int_topRows.cpp +/// Output: \verbinclude MatrixBase_template_int_topRows.out +/// +EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// template +EIGEN_DEVICE_FUNC inline typename NRowsBlockXpr::Type topRows(Index n = N) { return typename NRowsBlockXpr::Type(derived(), 0, 0, n, cols()); } -/** This is the const version of topRows().*/ +/// This is the const version of topRows(). template +EIGEN_DEVICE_FUNC inline typename ConstNRowsBlockXpr::Type topRows(Index n = N) const { return typename ConstNRowsBlockXpr::Type(derived(), 0, 0, n, cols()); @@ -416,47 +473,55 @@ inline typename ConstNRowsBlockXpr::Type topRows(Index n = N) const -/** \returns a block consisting of the bottom rows of *this. - * - * \param n the number of rows in the block - * - * Example: \include MatrixBase_bottomRows_int.cpp - * Output: \verbinclude MatrixBase_bottomRows_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ +/// \returns a block consisting of the bottom rows of *this. +/// +/// \param n the number of rows in the block +/// +/// Example: \include MatrixBase_bottomRows_int.cpp +/// Output: \verbinclude MatrixBase_bottomRows_int.out +/// +EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// +EIGEN_DEVICE_FUNC inline RowsBlockXpr bottomRows(Index n) { return RowsBlockXpr(derived(), rows() - n, 0, n, cols()); } -/** This is the const version of bottomRows(Index).*/ +/// This is the const version of bottomRows(Index). +EIGEN_DEVICE_FUNC inline ConstRowsBlockXpr bottomRows(Index n) const { return ConstRowsBlockXpr(derived(), rows() - n, 0, n, cols()); } -/** \returns a block consisting of the bottom rows of *this. - * - * \tparam N the number of rows in the block as specified at compile-time - * \param n the number of rows in the block as specified at run-time - * - * The compile-time and run-time information should not contradict. In other words, - * \a n should equal \a N unless \a N is \a Dynamic. - * - * Example: \include MatrixBase_template_int_bottomRows.cpp - * Output: \verbinclude MatrixBase_template_int_bottomRows.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ +/// \returns a block consisting of the bottom rows of *this. +/// +/// \tparam N the number of rows in the block as specified at compile-time +/// \param n the number of rows in the block as specified at run-time +/// +/// The compile-time and run-time information should not contradict. In other words, +/// \a n should equal \a N unless \a N is \a Dynamic. +/// +/// Example: \include MatrixBase_template_int_bottomRows.cpp +/// Output: \verbinclude MatrixBase_template_int_bottomRows.out +/// +EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// template +EIGEN_DEVICE_FUNC inline typename NRowsBlockXpr::Type bottomRows(Index n = N) { return typename NRowsBlockXpr::Type(derived(), rows() - n, 0, n, cols()); } -/** This is the const version of bottomRows().*/ +/// This is the const version of bottomRows(). template +EIGEN_DEVICE_FUNC inline typename ConstNRowsBlockXpr::Type bottomRows(Index n = N) const { return typename ConstNRowsBlockXpr::Type(derived(), rows() - n, 0, n, cols()); @@ -464,49 +529,57 @@ inline typename ConstNRowsBlockXpr::Type bottomRows(Index n = N) const -/** \returns a block consisting of a range of rows of *this. - * - * \param startRow the index of the first row in the block - * \param n the number of rows in the block - * - * Example: \include DenseBase_middleRows_int.cpp - * Output: \verbinclude DenseBase_middleRows_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ +/// \returns a block consisting of a range of rows of *this. +/// +/// \param startRow the index of the first row in the block +/// \param n the number of rows in the block +/// +/// Example: \include DenseBase_middleRows_int.cpp +/// Output: \verbinclude DenseBase_middleRows_int.out +/// +EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// +EIGEN_DEVICE_FUNC inline RowsBlockXpr middleRows(Index startRow, Index n) { return RowsBlockXpr(derived(), startRow, 0, n, cols()); } -/** This is the const version of middleRows(Index,Index).*/ +/// This is the const version of middleRows(Index,Index). +EIGEN_DEVICE_FUNC inline ConstRowsBlockXpr middleRows(Index startRow, Index n) const { return ConstRowsBlockXpr(derived(), startRow, 0, n, cols()); } -/** \returns a block consisting of a range of rows of *this. - * - * \tparam N the number of rows in the block as specified at compile-time - * \param startRow the index of the first row in the block - * \param n the number of rows in the block as specified at run-time - * - * The compile-time and run-time information should not contradict. In other words, - * \a n should equal \a N unless \a N is \a Dynamic. - * - * Example: \include DenseBase_template_int_middleRows.cpp - * Output: \verbinclude DenseBase_template_int_middleRows.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ +/// \returns a block consisting of a range of rows of *this. +/// +/// \tparam N the number of rows in the block as specified at compile-time +/// \param startRow the index of the first row in the block +/// \param n the number of rows in the block as specified at run-time +/// +/// The compile-time and run-time information should not contradict. In other words, +/// \a n should equal \a N unless \a N is \a Dynamic. +/// +/// Example: \include DenseBase_template_int_middleRows.cpp +/// Output: \verbinclude DenseBase_template_int_middleRows.out +/// +EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// template +EIGEN_DEVICE_FUNC inline typename NRowsBlockXpr::Type middleRows(Index startRow, Index n = N) { return typename NRowsBlockXpr::Type(derived(), startRow, 0, n, cols()); } -/** This is the const version of middleRows().*/ +/// This is the const version of middleRows(). template +EIGEN_DEVICE_FUNC inline typename ConstNRowsBlockXpr::Type middleRows(Index startRow, Index n = N) const { return typename ConstNRowsBlockXpr::Type(derived(), startRow, 0, n, cols()); @@ -514,47 +587,55 @@ inline typename ConstNRowsBlockXpr::Type middleRows(Index startRow, Index n = -/** \returns a block consisting of the left columns of *this. - * - * \param n the number of columns in the block - * - * Example: \include MatrixBase_leftCols_int.cpp - * Output: \verbinclude MatrixBase_leftCols_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ +/// \returns a block consisting of the left columns of *this. +/// +/// \param n the number of columns in the block +/// +/// Example: \include MatrixBase_leftCols_int.cpp +/// Output: \verbinclude MatrixBase_leftCols_int.out +/// +EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// +EIGEN_DEVICE_FUNC inline ColsBlockXpr leftCols(Index n) { return ColsBlockXpr(derived(), 0, 0, rows(), n); } -/** This is the const version of leftCols(Index).*/ +/// This is the const version of leftCols(Index). +EIGEN_DEVICE_FUNC inline ConstColsBlockXpr leftCols(Index n) const { return ConstColsBlockXpr(derived(), 0, 0, rows(), n); } -/** \returns a block consisting of the left columns of *this. - * - * \tparam N the number of columns in the block as specified at compile-time - * \param n the number of columns in the block as specified at run-time - * - * The compile-time and run-time information should not contradict. In other words, - * \a n should equal \a N unless \a N is \a Dynamic. - * - * Example: \include MatrixBase_template_int_leftCols.cpp - * Output: \verbinclude MatrixBase_template_int_leftCols.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ +/// \returns a block consisting of the left columns of *this. +/// +/// \tparam N the number of columns in the block as specified at compile-time +/// \param n the number of columns in the block as specified at run-time +/// +/// The compile-time and run-time information should not contradict. In other words, +/// \a n should equal \a N unless \a N is \a Dynamic. +/// +/// Example: \include MatrixBase_template_int_leftCols.cpp +/// Output: \verbinclude MatrixBase_template_int_leftCols.out +/// +EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// template +EIGEN_DEVICE_FUNC inline typename NColsBlockXpr::Type leftCols(Index n = N) { return typename NColsBlockXpr::Type(derived(), 0, 0, rows(), n); } -/** This is the const version of leftCols().*/ +/// This is the const version of leftCols(). template +EIGEN_DEVICE_FUNC inline typename ConstNColsBlockXpr::Type leftCols(Index n = N) const { return typename ConstNColsBlockXpr::Type(derived(), 0, 0, rows(), n); @@ -562,47 +643,55 @@ inline typename ConstNColsBlockXpr::Type leftCols(Index n = N) const -/** \returns a block consisting of the right columns of *this. - * - * \param n the number of columns in the block - * - * Example: \include MatrixBase_rightCols_int.cpp - * Output: \verbinclude MatrixBase_rightCols_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ +/// \returns a block consisting of the right columns of *this. +/// +/// \param n the number of columns in the block +/// +/// Example: \include MatrixBase_rightCols_int.cpp +/// Output: \verbinclude MatrixBase_rightCols_int.out +/// +EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// +EIGEN_DEVICE_FUNC inline ColsBlockXpr rightCols(Index n) { return ColsBlockXpr(derived(), 0, cols() - n, rows(), n); } -/** This is the const version of rightCols(Index).*/ +/// This is the const version of rightCols(Index). +EIGEN_DEVICE_FUNC inline ConstColsBlockXpr rightCols(Index n) const { return ConstColsBlockXpr(derived(), 0, cols() - n, rows(), n); } -/** \returns a block consisting of the right columns of *this. - * - * \tparam N the number of columns in the block as specified at compile-time - * \param n the number of columns in the block as specified at run-time - * - * The compile-time and run-time information should not contradict. In other words, - * \a n should equal \a N unless \a N is \a Dynamic. - * - * Example: \include MatrixBase_template_int_rightCols.cpp - * Output: \verbinclude MatrixBase_template_int_rightCols.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ +/// \returns a block consisting of the right columns of *this. +/// +/// \tparam N the number of columns in the block as specified at compile-time +/// \param n the number of columns in the block as specified at run-time +/// +/// The compile-time and run-time information should not contradict. In other words, +/// \a n should equal \a N unless \a N is \a Dynamic. +/// +/// Example: \include MatrixBase_template_int_rightCols.cpp +/// Output: \verbinclude MatrixBase_template_int_rightCols.out +/// +EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// template +EIGEN_DEVICE_FUNC inline typename NColsBlockXpr::Type rightCols(Index n = N) { return typename NColsBlockXpr::Type(derived(), 0, cols() - n, rows(), n); } -/** This is the const version of rightCols().*/ +/// This is the const version of rightCols(). template +EIGEN_DEVICE_FUNC inline typename ConstNColsBlockXpr::Type rightCols(Index n = N) const { return typename ConstNColsBlockXpr::Type(derived(), 0, cols() - n, rows(), n); @@ -610,49 +699,57 @@ inline typename ConstNColsBlockXpr::Type rightCols(Index n = N) const -/** \returns a block consisting of a range of columns of *this. - * - * \param startCol the index of the first column in the block - * \param numCols the number of columns in the block - * - * Example: \include DenseBase_middleCols_int.cpp - * Output: \verbinclude DenseBase_middleCols_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ +/// \returns a block consisting of a range of columns of *this. +/// +/// \param startCol the index of the first column in the block +/// \param numCols the number of columns in the block +/// +/// Example: \include DenseBase_middleCols_int.cpp +/// Output: \verbinclude DenseBase_middleCols_int.out +/// +EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// +EIGEN_DEVICE_FUNC inline ColsBlockXpr middleCols(Index startCol, Index numCols) { return ColsBlockXpr(derived(), 0, startCol, rows(), numCols); } -/** This is the const version of middleCols(Index,Index).*/ +/// This is the const version of middleCols(Index,Index). +EIGEN_DEVICE_FUNC inline ConstColsBlockXpr middleCols(Index startCol, Index numCols) const { return ConstColsBlockXpr(derived(), 0, startCol, rows(), numCols); } -/** \returns a block consisting of a range of columns of *this. - * - * \tparam N the number of columns in the block as specified at compile-time - * \param startCol the index of the first column in the block - * \param n the number of columns in the block as specified at run-time - * - * The compile-time and run-time information should not contradict. In other words, - * \a n should equal \a N unless \a N is \a Dynamic. - * - * Example: \include DenseBase_template_int_middleCols.cpp - * Output: \verbinclude DenseBase_template_int_middleCols.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ +/// \returns a block consisting of a range of columns of *this. +/// +/// \tparam N the number of columns in the block as specified at compile-time +/// \param startCol the index of the first column in the block +/// \param n the number of columns in the block as specified at run-time +/// +/// The compile-time and run-time information should not contradict. In other words, +/// \a n should equal \a N unless \a N is \a Dynamic. +/// +/// Example: \include DenseBase_template_int_middleCols.cpp +/// Output: \verbinclude DenseBase_template_int_middleCols.out +/// +EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// template +EIGEN_DEVICE_FUNC inline typename NColsBlockXpr::Type middleCols(Index startCol, Index n = N) { return typename NColsBlockXpr::Type(derived(), 0, startCol, rows(), n); } -/** This is the const version of middleCols().*/ +/// This is the const version of middleCols(). template +EIGEN_DEVICE_FUNC inline typename ConstNColsBlockXpr::Type middleCols(Index startCol, Index n = N) const { return typename ConstNColsBlockXpr::Type(derived(), 0, startCol, rows(), n); @@ -660,119 +757,134 @@ inline typename ConstNColsBlockXpr::Type middleCols(Index startCol, Index n = -/** \returns a fixed-size expression of a block in *this. - * - * The template parameters \a BlockRows and \a BlockCols are the number of - * rows and columns in the block. - * - * \param startRow the first row in the block - * \param startCol the first column in the block - * - * Example: \include MatrixBase_block_int_int.cpp - * Output: \verbinclude MatrixBase_block_int_int.out - * - * \note since block is a templated member, the keyword template has to be used - * if the matrix type is also a template parameter: \code m.template block<3,3>(1,1); \endcode - * - * \sa class Block, block(Index,Index,Index,Index) - */ -template -inline Block block(Index startRow, Index startCol) -{ - return Block(derived(), startRow, startCol); -} - -/** This is the const version of block<>(Index, Index). */ -template -inline const Block block(Index startRow, Index startCol) const -{ - return Block(derived(), startRow, startCol); -} - -/** \returns an expression of a block in *this. - * - * \tparam BlockRows number of rows in block as specified at compile-time - * \tparam BlockCols number of columns in block as specified at compile-time - * \param startRow the first row in the block - * \param startCol the first column in the block - * \param blockRows number of rows in block as specified at run-time - * \param blockCols number of columns in block as specified at run-time - * - * This function is mainly useful for blocks where the number of rows is specified at compile-time - * and the number of columns is specified at run-time, or vice versa. The compile-time and run-time - * information should not contradict. In other words, \a blockRows should equal \a BlockRows unless - * \a BlockRows is \a Dynamic, and the same for the number of columns. - * - * Example: \include MatrixBase_template_int_int_block_int_int_int_int.cpp - * Output: \verbinclude MatrixBase_template_int_int_block_int_int_int_int.cpp - * - * \sa class Block, block(Index,Index,Index,Index) - */ -template -inline Block block(Index startRow, Index startCol, +/// \returns a fixed-size expression of a block in *this. +/// +/// The template parameters \a NRows and \a NCols are the number of +/// rows and columns in the block. +/// +/// \param startRow the first row in the block +/// \param startCol the first column in the block +/// +/// Example: \include MatrixBase_block_int_int.cpp +/// Output: \verbinclude MatrixBase_block_int_int.out +/// +/// \note since block is a templated member, the keyword template has to be used +/// if the matrix type is also a template parameter: \code m.template block<3,3>(1,1); \endcode +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// +template +EIGEN_DEVICE_FUNC +inline typename FixedBlockXpr::Type block(Index startRow, Index startCol) +{ + return typename FixedBlockXpr::Type(derived(), startRow, startCol); +} + +/// This is the const version of block<>(Index, Index). */ +template +EIGEN_DEVICE_FUNC +inline const typename ConstFixedBlockXpr::Type block(Index startRow, Index startCol) const +{ + return typename ConstFixedBlockXpr::Type(derived(), startRow, startCol); +} + +/// \returns an expression of a block in *this. +/// +/// \tparam NRows number of rows in block as specified at compile-time +/// \tparam NCols number of columns in block as specified at compile-time +/// \param startRow the first row in the block +/// \param startCol the first column in the block +/// \param blockRows number of rows in block as specified at run-time +/// \param blockCols number of columns in block as specified at run-time +/// +/// This function is mainly useful for blocks where the number of rows is specified at compile-time +/// and the number of columns is specified at run-time, or vice versa. The compile-time and run-time +/// information should not contradict. In other words, \a blockRows should equal \a NRows unless +/// \a NRows is \a Dynamic, and the same for the number of columns. +/// +/// Example: \include MatrixBase_template_int_int_block_int_int_int_int.cpp +/// Output: \verbinclude MatrixBase_template_int_int_block_int_int_int_int.cpp +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa class Block, block(Index,Index,Index,Index) +/// +template +inline typename FixedBlockXpr::Type block(Index startRow, Index startCol, Index blockRows, Index blockCols) { - return Block(derived(), startRow, startCol, blockRows, blockCols); + return typename FixedBlockXpr::Type(derived(), startRow, startCol, blockRows, blockCols); } -/** This is the const version of block<>(Index, Index, Index, Index). */ -template -inline const Block block(Index startRow, Index startCol, +/// This is the const version of block<>(Index, Index, Index, Index). +template +inline const typename ConstFixedBlockXpr::Type block(Index startRow, Index startCol, Index blockRows, Index blockCols) const { - return Block(derived(), startRow, startCol, blockRows, blockCols); + return typename ConstFixedBlockXpr::Type(derived(), startRow, startCol, blockRows, blockCols); } -/** \returns an expression of the \a i-th column of *this. Note that the numbering starts at 0. - * - * Example: \include MatrixBase_col.cpp - * Output: \verbinclude MatrixBase_col.out - * +/// \returns an expression of the \a i-th column of *this. Note that the numbering starts at 0. +/// +/// Example: \include MatrixBase_col.cpp +/// Output: \verbinclude MatrixBase_col.out +/// +EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) +/** * \sa row(), class Block */ +EIGEN_DEVICE_FUNC inline ColXpr col(Index i) { return ColXpr(derived(), i); } -/** This is the const version of col(). */ +/// This is the const version of col(). +EIGEN_DEVICE_FUNC inline ConstColXpr col(Index i) const { return ConstColXpr(derived(), i); } -/** \returns an expression of the \a i-th row of *this. Note that the numbering starts at 0. - * - * Example: \include MatrixBase_row.cpp - * Output: \verbinclude MatrixBase_row.out - * +/// \returns an expression of the \a i-th row of *this. Note that the numbering starts at 0. +/// +/// Example: \include MatrixBase_row.cpp +/// Output: \verbinclude MatrixBase_row.out +/// +EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) +/** * \sa col(), class Block */ +EIGEN_DEVICE_FUNC inline RowXpr row(Index i) { return RowXpr(derived(), i); } -/** This is the const version of row(). */ +/// This is the const version of row(). */ +EIGEN_DEVICE_FUNC inline ConstRowXpr row(Index i) const { return ConstRowXpr(derived(), i); } -/** \returns a dynamic-size expression of a segment (i.e. a vector block) in *this. - * - * \only_for_vectors - * - * \param start the first coefficient in the segment - * \param n the number of coefficients in the segment - * - * Example: \include MatrixBase_segment_int_int.cpp - * Output: \verbinclude MatrixBase_segment_int_int.out - * - * \note Even though the returned expression has dynamic size, in the case - * when it is applied to a fixed-size vector, it inherits a fixed maximal size, - * which means that evaluating it does not cause a dynamic memory allocation. - * - * \sa class Block, segment(Index) - */ +/// \returns a dynamic-size expression of a segment (i.e. a vector block) in *this. +/// +/// \only_for_vectors +/// +/// \param start the first coefficient in the segment +/// \param n the number of coefficients in the segment +/// +/// Example: \include MatrixBase_segment_int_int.cpp +/// Output: \verbinclude MatrixBase_segment_int_int.out +/// +/// \note Even though the returned expression has dynamic size, in the case +/// when it is applied to a fixed-size vector, it inherits a fixed maximal size, +/// which means that evaluating it does not cause a dynamic memory allocation. +/// +/// \sa class Block, segment(Index) +/// +EIGEN_DEVICE_FUNC inline SegmentReturnType segment(Index start, Index n) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) @@ -780,154 +892,165 @@ inline SegmentReturnType segment(Index start, Index n) } -/** This is the const version of segment(Index,Index).*/ +/// This is the const version of segment(Index,Index). +EIGEN_DEVICE_FUNC inline ConstSegmentReturnType segment(Index start, Index n) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return ConstSegmentReturnType(derived(), start, n); } -/** \returns a dynamic-size expression of the first coefficients of *this. - * - * \only_for_vectors - * - * \param n the number of coefficients in the segment - * - * Example: \include MatrixBase_start_int.cpp - * Output: \verbinclude MatrixBase_start_int.out - * - * \note Even though the returned expression has dynamic size, in the case - * when it is applied to a fixed-size vector, it inherits a fixed maximal size, - * which means that evaluating it does not cause a dynamic memory allocation. - * - * \sa class Block, block(Index,Index) - */ +/// \returns a dynamic-size expression of the first coefficients of *this. +/// +/// \only_for_vectors +/// +/// \param n the number of coefficients in the segment +/// +/// Example: \include MatrixBase_start_int.cpp +/// Output: \verbinclude MatrixBase_start_int.out +/// +/// \note Even though the returned expression has dynamic size, in the case +/// when it is applied to a fixed-size vector, it inherits a fixed maximal size, +/// which means that evaluating it does not cause a dynamic memory allocation. +/// +/// \sa class Block, block(Index,Index) +/// +EIGEN_DEVICE_FUNC inline SegmentReturnType head(Index n) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return SegmentReturnType(derived(), 0, n); } -/** This is the const version of head(Index).*/ +/// This is the const version of head(Index). +EIGEN_DEVICE_FUNC inline ConstSegmentReturnType head(Index n) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return ConstSegmentReturnType(derived(), 0, n); } -/** \returns a dynamic-size expression of the last coefficients of *this. - * - * \only_for_vectors - * - * \param n the number of coefficients in the segment - * - * Example: \include MatrixBase_end_int.cpp - * Output: \verbinclude MatrixBase_end_int.out - * - * \note Even though the returned expression has dynamic size, in the case - * when it is applied to a fixed-size vector, it inherits a fixed maximal size, - * which means that evaluating it does not cause a dynamic memory allocation. - * - * \sa class Block, block(Index,Index) - */ +/// \returns a dynamic-size expression of the last coefficients of *this. +/// +/// \only_for_vectors +/// +/// \param n the number of coefficients in the segment +/// +/// Example: \include MatrixBase_end_int.cpp +/// Output: \verbinclude MatrixBase_end_int.out +/// +/// \note Even though the returned expression has dynamic size, in the case +/// when it is applied to a fixed-size vector, it inherits a fixed maximal size, +/// which means that evaluating it does not cause a dynamic memory allocation. +/// +/// \sa class Block, block(Index,Index) +/// +EIGEN_DEVICE_FUNC inline SegmentReturnType tail(Index n) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return SegmentReturnType(derived(), this->size() - n, n); } -/** This is the const version of tail(Index).*/ +/// This is the const version of tail(Index). +EIGEN_DEVICE_FUNC inline ConstSegmentReturnType tail(Index n) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return ConstSegmentReturnType(derived(), this->size() - n, n); } -/** \returns a fixed-size expression of a segment (i.e. a vector block) in \c *this - * - * \only_for_vectors - * - * \tparam N the number of coefficients in the segment as specified at compile-time - * \param start the index of the first element in the segment - * \param n the number of coefficients in the segment as specified at compile-time - * - * The compile-time and run-time information should not contradict. In other words, - * \a n should equal \a N unless \a N is \a Dynamic. - * - * Example: \include MatrixBase_template_int_segment.cpp - * Output: \verbinclude MatrixBase_template_int_segment.out - * - * \sa class Block - */ +/// \returns a fixed-size expression of a segment (i.e. a vector block) in \c *this +/// +/// \only_for_vectors +/// +/// \tparam N the number of coefficients in the segment as specified at compile-time +/// \param start the index of the first element in the segment +/// \param n the number of coefficients in the segment as specified at compile-time +/// +/// The compile-time and run-time information should not contradict. In other words, +/// \a n should equal \a N unless \a N is \a Dynamic. +/// +/// Example: \include MatrixBase_template_int_segment.cpp +/// Output: \verbinclude MatrixBase_template_int_segment.out +/// +/// \sa class Block +/// template +EIGEN_DEVICE_FUNC inline typename FixedSegmentReturnType::Type segment(Index start, Index n = N) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return typename FixedSegmentReturnType::Type(derived(), start, n); } -/** This is the const version of segment(Index).*/ +/// This is the const version of segment(Index). template +EIGEN_DEVICE_FUNC inline typename ConstFixedSegmentReturnType::Type segment(Index start, Index n = N) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return typename ConstFixedSegmentReturnType::Type(derived(), start, n); } -/** \returns a fixed-size expression of the first coefficients of *this. - * - * \only_for_vectors - * - * \tparam N the number of coefficients in the segment as specified at compile-time - * \param n the number of coefficients in the segment as specified at run-time - * - * The compile-time and run-time information should not contradict. In other words, - * \a n should equal \a N unless \a N is \a Dynamic. - * - * Example: \include MatrixBase_template_int_start.cpp - * Output: \verbinclude MatrixBase_template_int_start.out - * - * \sa class Block - */ +/// \returns a fixed-size expression of the first coefficients of *this. +/// +/// \only_for_vectors +/// +/// \tparam N the number of coefficients in the segment as specified at compile-time +/// \param n the number of coefficients in the segment as specified at run-time +/// +/// The compile-time and run-time information should not contradict. In other words, +/// \a n should equal \a N unless \a N is \a Dynamic. +/// +/// Example: \include MatrixBase_template_int_start.cpp +/// Output: \verbinclude MatrixBase_template_int_start.out +/// +/// \sa class Block +/// template +EIGEN_DEVICE_FUNC inline typename FixedSegmentReturnType::Type head(Index n = N) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return typename FixedSegmentReturnType::Type(derived(), 0, n); } -/** This is the const version of head().*/ +/// This is the const version of head(). template +EIGEN_DEVICE_FUNC inline typename ConstFixedSegmentReturnType::Type head(Index n = N) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return typename ConstFixedSegmentReturnType::Type(derived(), 0, n); } -/** \returns a fixed-size expression of the last coefficients of *this. - * - * \only_for_vectors - * - * \tparam N the number of coefficients in the segment as specified at compile-time - * \param n the number of coefficients in the segment as specified at run-time - * - * The compile-time and run-time information should not contradict. In other words, - * \a n should equal \a N unless \a N is \a Dynamic. - * - * Example: \include MatrixBase_template_int_end.cpp - * Output: \verbinclude MatrixBase_template_int_end.out - * - * \sa class Block - */ +/// \returns a fixed-size expression of the last coefficients of *this. +/// +/// \only_for_vectors +/// +/// \tparam N the number of coefficients in the segment as specified at compile-time +/// \param n the number of coefficients in the segment as specified at run-time +/// +/// The compile-time and run-time information should not contradict. In other words, +/// \a n should equal \a N unless \a N is \a Dynamic. +/// +/// Example: \include MatrixBase_template_int_end.cpp +/// Output: \verbinclude MatrixBase_template_int_end.out +/// +/// \sa class Block +/// template +EIGEN_DEVICE_FUNC inline typename FixedSegmentReturnType::Type tail(Index n = N) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return typename FixedSegmentReturnType::Type(derived(), size() - n); } -/** This is the const version of tail.*/ +/// This is the const version of tail. template +EIGEN_DEVICE_FUNC inline typename ConstFixedSegmentReturnType::Type tail(Index n = N) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) diff --git a/libs/eigen3/Eigen/src/plugins/CommonCwiseBinaryOps.h b/libs/eigen3/Eigen/src/plugins/CommonCwiseBinaryOps.h index 688d22440..8b6730ede 100644 --- a/libs/eigen3/Eigen/src/plugins/CommonCwiseBinaryOps.h +++ b/libs/eigen3/Eigen/src/plugins/CommonCwiseBinaryOps.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2008-2016 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla @@ -16,7 +16,7 @@ * * \sa class CwiseBinaryOp, operator-=() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator-,internal::scalar_difference_op) +EIGEN_MAKE_CWISE_BINARY_OP(operator-,difference) /** \returns an expression of the sum of \c *this and \a other * @@ -24,7 +24,7 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator-,internal::scalar_difference_op) * * \sa class CwiseBinaryOp, operator+=() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator+,internal::scalar_sum_op) +EIGEN_MAKE_CWISE_BINARY_OP(operator+,sum) /** \returns an expression of a custom coefficient-wise operator \a func of *this and \a other * @@ -38,9 +38,78 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator+,internal::scalar_sum_op) * \sa class CwiseBinaryOp, operator+(), operator-(), cwiseProduct() */ template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseBinaryOp binaryExpr(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other, const CustomBinaryOp& func = CustomBinaryOp()) const { return CwiseBinaryOp(derived(), other.derived(), func); } + +#ifndef EIGEN_PARSED_BY_DOXYGEN +EIGEN_MAKE_SCALAR_BINARY_OP(operator*,product) +#else +/** \returns an expression of \c *this scaled by the scalar factor \a scalar + * + * \tparam T is the scalar type of \a scalar. It must be compatible with the scalar type of the given expression. + */ +template +const CwiseBinaryOp,Derived,Constant > operator*(const T& scalar) const; +/** \returns an expression of \a expr scaled by the scalar factor \a scalar + * + * \tparam T is the scalar type of \a scalar. It must be compatible with the scalar type of the given expression. + */ +template friend +const CwiseBinaryOp,Constant,Derived> operator*(const T& scalar, const StorageBaseType& expr); +#endif + + + +#ifndef EIGEN_PARSED_BY_DOXYGEN +EIGEN_MAKE_SCALAR_BINARY_OP_ONTHERIGHT(operator/,quotient) +#else +/** \returns an expression of \c *this divided by the scalar value \a scalar + * + * \tparam T is the scalar type of \a scalar. It must be compatible with the scalar type of the given expression. + */ +template +const CwiseBinaryOp,Derived,Constant > operator/(const T& scalar) const; +#endif + +/** \returns an expression of the coefficient-wise boolean \b and operator of \c *this and \a other + * + * \warning this operator is for expression of bool only. + * + * Example: \include Cwise_boolean_and.cpp + * Output: \verbinclude Cwise_boolean_and.out + * + * \sa operator||(), select() + */ +template +EIGEN_DEVICE_FUNC +inline const CwiseBinaryOp +operator&&(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const +{ + EIGEN_STATIC_ASSERT((internal::is_same::value && internal::is_same::value), + THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL); + return CwiseBinaryOp(derived(),other.derived()); +} + +/** \returns an expression of the coefficient-wise boolean \b or operator of \c *this and \a other + * + * \warning this operator is for expression of bool only. + * + * Example: \include Cwise_boolean_or.cpp + * Output: \verbinclude Cwise_boolean_or.out + * + * \sa operator&&(), select() + */ +template +EIGEN_DEVICE_FUNC +inline const CwiseBinaryOp +operator||(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const +{ + EIGEN_STATIC_ASSERT((internal::is_same::value && internal::is_same::value), + THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL); + return CwiseBinaryOp(derived(),other.derived()); +} diff --git a/libs/eigen3/Eigen/src/plugins/CommonCwiseUnaryOps.h b/libs/eigen3/Eigen/src/plugins/CommonCwiseUnaryOps.h index 08e931aad..89f4faaac 100644 --- a/libs/eigen3/Eigen/src/plugins/CommonCwiseUnaryOps.h +++ b/libs/eigen3/Eigen/src/plugins/CommonCwiseUnaryOps.h @@ -12,10 +12,6 @@ #ifndef EIGEN_PARSED_BY_DOXYGEN -/** \internal Represents a scalar multiple of an expression */ -typedef CwiseUnaryOp, const Derived> ScalarMultipleReturnType; -/** \internal Represents a quotient of an expression by a scalar*/ -typedef CwiseUnaryOp, const Derived> ScalarQuotient1ReturnType; /** \internal the return type of conjugate() */ typedef typename internal::conditional::IsComplex, const CwiseUnaryOp, const Derived>, @@ -36,137 +32,132 @@ typedef CwiseUnaryOp, const Derived> ImagReturn /** \internal the return type of imag() */ typedef CwiseUnaryView, Derived> NonConstImagReturnType; -#endif // not EIGEN_PARSED_BY_DOXYGEN - -/** \returns an expression of the opposite of \c *this - */ -inline const CwiseUnaryOp::Scalar>, const Derived> -operator-() const { return derived(); } - - -/** \returns an expression of \c *this scaled by the scalar factor \a scalar */ -inline const ScalarMultipleReturnType -operator*(const Scalar& scalar) const -{ - return CwiseUnaryOp, const Derived> - (derived(), internal::scalar_multiple_op(scalar)); -} +typedef CwiseUnaryOp, const Derived> NegativeReturnType; -#ifdef EIGEN_PARSED_BY_DOXYGEN -const ScalarMultipleReturnType operator*(const RealScalar& scalar) const; -#endif - -/** \returns an expression of \c *this divided by the scalar value \a scalar */ -inline const CwiseUnaryOp::Scalar>, const Derived> -operator/(const Scalar& scalar) const -{ - return CwiseUnaryOp, const Derived> - (derived(), internal::scalar_quotient1_op(scalar)); -} - -/** Overloaded for efficient real matrix times complex scalar value */ -inline const CwiseUnaryOp >, const Derived> -operator*(const std::complex& scalar) const -{ - return CwiseUnaryOp >, const Derived> - (*static_cast(this), internal::scalar_multiple2_op >(scalar)); -} +#endif // not EIGEN_PARSED_BY_DOXYGEN -inline friend const ScalarMultipleReturnType -operator*(const Scalar& scalar, const StorageBaseType& matrix) -{ return matrix*scalar; } - -inline friend const CwiseUnaryOp >, const Derived> -operator*(const std::complex& scalar, const StorageBaseType& matrix) -{ return matrix*scalar; } - -/** \returns an expression of *this with the \a Scalar type casted to - * \a NewScalar. - * - * The template parameter \a NewScalar is the type we are casting the scalars to. - * - * \sa class CwiseUnaryOp - */ +/// \returns an expression of the opposite of \c *this +/// +EIGEN_DOC_UNARY_ADDONS(operator-,opposite) +/// +EIGEN_DEVICE_FUNC +inline const NegativeReturnType +operator-() const { return NegativeReturnType(derived()); } + + +template struct CastXpr { typedef typename internal::cast_return_type, const Derived> >::type Type; }; + +/// \returns an expression of \c *this with the \a Scalar type casted to +/// \a NewScalar. +/// +/// The template parameter \a NewScalar is the type we are casting the scalars to. +/// +EIGEN_DOC_UNARY_ADDONS(cast,conversion function) +/// +/// \sa class CwiseUnaryOp +/// template -typename internal::cast_return_type::Scalar, NewType>, const Derived> >::type +EIGEN_DEVICE_FUNC +typename CastXpr::Type cast() const { - return derived(); + return typename CastXpr::Type(derived()); } -/** \returns an expression of the complex conjugate of \c *this. - * - * \sa adjoint() */ +/// \returns an expression of the complex conjugate of \c *this. +/// +EIGEN_DOC_UNARY_ADDONS(conjugate,complex conjugate) +/// +/// \sa Math functions, MatrixBase::adjoint() +EIGEN_DEVICE_FUNC inline ConjugateReturnType conjugate() const { return ConjugateReturnType(derived()); } -/** \returns a read-only expression of the real part of \c *this. - * - * \sa imag() */ +/// \returns a read-only expression of the real part of \c *this. +/// +EIGEN_DOC_UNARY_ADDONS(real,real part function) +/// +/// \sa imag() +EIGEN_DEVICE_FUNC inline RealReturnType -real() const { return derived(); } - -/** \returns an read-only expression of the imaginary part of \c *this. - * - * \sa real() */ +real() const { return RealReturnType(derived()); } + +/// \returns an read-only expression of the imaginary part of \c *this. +/// +EIGEN_DOC_UNARY_ADDONS(imag,imaginary part function) +/// +/// \sa real() +EIGEN_DEVICE_FUNC inline const ImagReturnType -imag() const { return derived(); } - -/** \brief Apply a unary operator coefficient-wise - * \param[in] func Functor implementing the unary operator - * \tparam CustomUnaryOp Type of \a func - * \returns An expression of a custom coefficient-wise unary operator \a func of *this - * - * The function \c ptr_fun() from the C++ standard library can be used to make functors out of normal functions. - * - * Example: - * \include class_CwiseUnaryOp_ptrfun.cpp - * Output: \verbinclude class_CwiseUnaryOp_ptrfun.out - * - * Genuine functors allow for more possibilities, for instance it may contain a state. - * - * Example: - * \include class_CwiseUnaryOp.cpp - * Output: \verbinclude class_CwiseUnaryOp.out - * - * \sa class CwiseUnaryOp, class CwiseBinaryOp - */ +imag() const { return ImagReturnType(derived()); } + +/// \brief Apply a unary operator coefficient-wise +/// \param[in] func Functor implementing the unary operator +/// \tparam CustomUnaryOp Type of \a func +/// \returns An expression of a custom coefficient-wise unary operator \a func of *this +/// +/// The function \c ptr_fun() from the C++ standard library can be used to make functors out of normal functions. +/// +/// Example: +/// \include class_CwiseUnaryOp_ptrfun.cpp +/// Output: \verbinclude class_CwiseUnaryOp_ptrfun.out +/// +/// Genuine functors allow for more possibilities, for instance it may contain a state. +/// +/// Example: +/// \include class_CwiseUnaryOp.cpp +/// Output: \verbinclude class_CwiseUnaryOp.out +/// +EIGEN_DOC_UNARY_ADDONS(unaryExpr,unary function) +/// +/// \sa unaryViewExpr, binaryExpr, class CwiseUnaryOp +/// template +EIGEN_DEVICE_FUNC inline const CwiseUnaryOp unaryExpr(const CustomUnaryOp& func = CustomUnaryOp()) const { return CwiseUnaryOp(derived(), func); } -/** \returns an expression of a custom coefficient-wise unary operator \a func of *this - * - * The template parameter \a CustomUnaryOp is the type of the functor - * of the custom unary operator. - * - * Example: - * \include class_CwiseUnaryOp.cpp - * Output: \verbinclude class_CwiseUnaryOp.out - * - * \sa class CwiseUnaryOp, class CwiseBinaryOp - */ +/// \returns an expression of a custom coefficient-wise unary operator \a func of *this +/// +/// The template parameter \a CustomUnaryOp is the type of the functor +/// of the custom unary operator. +/// +/// Example: +/// \include class_CwiseUnaryOp.cpp +/// Output: \verbinclude class_CwiseUnaryOp.out +/// +EIGEN_DOC_UNARY_ADDONS(unaryViewExpr,unary function) +/// +/// \sa unaryExpr, binaryExpr class CwiseUnaryOp +/// template +EIGEN_DEVICE_FUNC inline const CwiseUnaryView unaryViewExpr(const CustomViewOp& func = CustomViewOp()) const { return CwiseUnaryView(derived(), func); } -/** \returns a non const expression of the real part of \c *this. - * - * \sa imag() */ +/// \returns a non const expression of the real part of \c *this. +/// +EIGEN_DOC_UNARY_ADDONS(real,real part function) +/// +/// \sa imag() +EIGEN_DEVICE_FUNC inline NonConstRealReturnType -real() { return derived(); } - -/** \returns a non const expression of the imaginary part of \c *this. - * - * \sa real() */ +real() { return NonConstRealReturnType(derived()); } + +/// \returns a non const expression of the imaginary part of \c *this. +/// +EIGEN_DOC_UNARY_ADDONS(imag,imaginary part function) +/// +/// \sa real() +EIGEN_DEVICE_FUNC inline NonConstImagReturnType -imag() { return derived(); } +imag() { return NonConstImagReturnType(derived()); } diff --git a/libs/eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h b/libs/eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h index 7f62149e0..f1084abef 100644 --- a/libs/eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h +++ b/libs/eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h @@ -18,10 +18,11 @@ * \sa class CwiseBinaryOp, cwiseAbs2 */ template -EIGEN_STRONG_INLINE const EIGEN_CWISE_PRODUCT_RETURN_TYPE(Derived,OtherDerived) +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE const EIGEN_CWISE_BINARY_RETURN_TYPE(Derived,OtherDerived,product) cwiseProduct(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const { - return EIGEN_CWISE_PRODUCT_RETURN_TYPE(Derived,OtherDerived)(derived(), other.derived()); + return EIGEN_CWISE_BINARY_RETURN_TYPE(Derived,OtherDerived,product)(derived(), other.derived()); } /** \returns an expression of the coefficient-wise == operator of *this and \a other @@ -37,6 +38,7 @@ cwiseProduct(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const * \sa cwiseNotEqual(), isApprox(), isMuchSmallerThan() */ template +EIGEN_DEVICE_FUNC inline const CwiseBinaryOp, const Derived, const OtherDerived> cwiseEqual(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const { @@ -56,6 +58,7 @@ cwiseEqual(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const * \sa cwiseEqual(), isApprox(), isMuchSmallerThan() */ template +EIGEN_DEVICE_FUNC inline const CwiseBinaryOp, const Derived, const OtherDerived> cwiseNotEqual(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const { @@ -70,17 +73,19 @@ cwiseNotEqual(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const * \sa class CwiseBinaryOp, max() */ template -EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const OtherDerived> +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const OtherDerived> cwiseMin(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const { - return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); + return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); } /** \returns an expression of the coefficient-wise min of *this and scalar \a other * * \sa class CwiseBinaryOp, min() */ -EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const ConstantReturnType> +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const ConstantReturnType> cwiseMin(const Scalar &other) const { return cwiseMin(Derived::Constant(rows(), cols(), other)); @@ -94,17 +99,19 @@ cwiseMin(const Scalar &other) const * \sa class CwiseBinaryOp, min() */ template -EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const OtherDerived> +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const OtherDerived> cwiseMax(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const { - return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); + return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); } /** \returns an expression of the coefficient-wise max of *this and scalar \a other * * \sa class CwiseBinaryOp, min() */ -EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const ConstantReturnType> +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const ConstantReturnType> cwiseMax(const Scalar &other) const { return cwiseMax(Derived::Constant(rows(), cols(), other)); @@ -119,8 +126,27 @@ cwiseMax(const Scalar &other) const * \sa class CwiseBinaryOp, cwiseProduct(), cwiseInverse() */ template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const OtherDerived> cwiseQuotient(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const { return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); } + +typedef CwiseBinaryOp, const Derived, const ConstantReturnType> CwiseScalarEqualReturnType; + +/** \returns an expression of the coefficient-wise == operator of \c *this and a scalar \a s + * + * \warning this performs an exact comparison, which is generally a bad idea with floating-point types. + * In order to check for equality between two vectors or matrices with floating-point coefficients, it is + * generally a far better idea to use a fuzzy comparison as provided by isApprox() and + * isMuchSmallerThan(). + * + * \sa cwiseEqual(const MatrixBase &) const + */ +EIGEN_DEVICE_FUNC +inline const CwiseScalarEqualReturnType +cwiseEqual(const Scalar& s) const +{ + return CwiseScalarEqualReturnType(derived(), Derived::Constant(rows(), cols(), s), internal::scalar_cmp_op()); +} diff --git a/libs/eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h b/libs/eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h index 0cf0640ba..b1be3d566 100644 --- a/libs/eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h +++ b/libs/eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h @@ -8,60 +8,78 @@ // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -// This file is a base class plugin containing matrix specifics coefficient wise functions. +// This file is included into the body of the base classes supporting matrix specific coefficient-wise functions. +// This include MatrixBase and SparseMatrixBase. -/** \returns an expression of the coefficient-wise absolute value of \c *this - * - * Example: \include MatrixBase_cwiseAbs.cpp - * Output: \verbinclude MatrixBase_cwiseAbs.out - * - * \sa cwiseAbs2() - */ -EIGEN_STRONG_INLINE const CwiseUnaryOp, const Derived> -cwiseAbs() const { return derived(); } -/** \returns an expression of the coefficient-wise squared absolute value of \c *this - * - * Example: \include MatrixBase_cwiseAbs2.cpp - * Output: \verbinclude MatrixBase_cwiseAbs2.out - * - * \sa cwiseAbs() - */ -EIGEN_STRONG_INLINE const CwiseUnaryOp, const Derived> -cwiseAbs2() const { return derived(); } +typedef CwiseUnaryOp, const Derived> CwiseAbsReturnType; +typedef CwiseUnaryOp, const Derived> CwiseAbs2ReturnType; +typedef CwiseUnaryOp, const Derived> CwiseSqrtReturnType; +typedef CwiseUnaryOp, const Derived> CwiseSignReturnType; +typedef CwiseUnaryOp, const Derived> CwiseInverseReturnType; -/** \returns an expression of the coefficient-wise square root of *this. - * - * Example: \include MatrixBase_cwiseSqrt.cpp - * Output: \verbinclude MatrixBase_cwiseSqrt.out - * - * \sa cwisePow(), cwiseSquare() - */ -inline const CwiseUnaryOp, const Derived> -cwiseSqrt() const { return derived(); } +/// \returns an expression of the coefficient-wise absolute value of \c *this +/// +/// Example: \include MatrixBase_cwiseAbs.cpp +/// Output: \verbinclude MatrixBase_cwiseAbs.out +/// +EIGEN_DOC_UNARY_ADDONS(cwiseAbs,absolute value) +/// +/// \sa cwiseAbs2() +/// +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE const CwiseAbsReturnType +cwiseAbs() const { return CwiseAbsReturnType(derived()); } + +/// \returns an expression of the coefficient-wise squared absolute value of \c *this +/// +/// Example: \include MatrixBase_cwiseAbs2.cpp +/// Output: \verbinclude MatrixBase_cwiseAbs2.out +/// +EIGEN_DOC_UNARY_ADDONS(cwiseAbs2,squared absolute value) +/// +/// \sa cwiseAbs() +/// +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE const CwiseAbs2ReturnType +cwiseAbs2() const { return CwiseAbs2ReturnType(derived()); } + +/// \returns an expression of the coefficient-wise square root of *this. +/// +/// Example: \include MatrixBase_cwiseSqrt.cpp +/// Output: \verbinclude MatrixBase_cwiseSqrt.out +/// +EIGEN_DOC_UNARY_ADDONS(cwiseSqrt,square-root) +/// +/// \sa cwisePow(), cwiseSquare() +/// +EIGEN_DEVICE_FUNC +inline const CwiseSqrtReturnType +cwiseSqrt() const { return CwiseSqrtReturnType(derived()); } + +/// \returns an expression of the coefficient-wise signum of *this. +/// +/// Example: \include MatrixBase_cwiseSign.cpp +/// Output: \verbinclude MatrixBase_cwiseSign.out +/// +EIGEN_DOC_UNARY_ADDONS(cwiseSign,sign function) +/// +EIGEN_DEVICE_FUNC +inline const CwiseSignReturnType +cwiseSign() const { return CwiseSignReturnType(derived()); } + + +/// \returns an expression of the coefficient-wise inverse of *this. +/// +/// Example: \include MatrixBase_cwiseInverse.cpp +/// Output: \verbinclude MatrixBase_cwiseInverse.out +/// +EIGEN_DOC_UNARY_ADDONS(cwiseInverse,inverse) +/// +/// \sa cwiseProduct() +/// +EIGEN_DEVICE_FUNC +inline const CwiseInverseReturnType +cwiseInverse() const { return CwiseInverseReturnType(derived()); } -/** \returns an expression of the coefficient-wise inverse of *this. - * - * Example: \include MatrixBase_cwiseInverse.cpp - * Output: \verbinclude MatrixBase_cwiseInverse.out - * - * \sa cwiseProduct() - */ -inline const CwiseUnaryOp, const Derived> -cwiseInverse() const { return derived(); } -/** \returns an expression of the coefficient-wise == operator of \c *this and a scalar \a s - * - * \warning this performs an exact comparison, which is generally a bad idea with floating-point types. - * In order to check for equality between two vectors or matrices with floating-point coefficients, it is - * generally a far better idea to use a fuzzy comparison as provided by isApprox() and - * isMuchSmallerThan(). - * - * \sa cwiseEqual(const MatrixBase &) const - */ -inline const CwiseUnaryOp >, const Derived> -cwiseEqual(const Scalar& s) const -{ - return CwiseUnaryOp >,const Derived> - (derived(), std::bind1st(std::equal_to(), s)); -} diff --git a/libs/eigen3/README b/libs/eigen3/README index 164650c38..3733efccf 100644 --- a/libs/eigen3/README +++ b/libs/eigen3/README @@ -1,4 +1,3 @@ -Components of Eigen3 needed for the Magnetic Lenses -License: Mozilla Public License (MPL) version 2.0 +Components of Eigen3 needed for the Magnetic Lenses +License: Mozilla Public License (MPL) version 2.0 Reference: http://eigen.tuxfamily.org - From 798b504a9243732133337e9fb86b00f8580823c7 Mon Sep 17 00:00:00 2001 From: mertelx Date: Fri, 24 Nov 2017 16:43:20 +0100 Subject: [PATCH 1041/1298] Added simple unit tests for the Advection class and the adiabatic energy loss module --- test/testAdiabaticCooling.cpp | 7 ++++ test/testAdvectionField.cpp | 61 +++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/test/testAdiabaticCooling.cpp b/test/testAdiabaticCooling.cpp index cbebbf9ef..ac122825f 100644 --- a/test/testAdiabaticCooling.cpp +++ b/test/testAdiabaticCooling.cpp @@ -25,6 +25,13 @@ TEST (AdiabaticCooling, UniformField) { EXPECT_DOUBLE_EQ(c.current.getEnergy(), E); EXPECT_DOUBLE_EQ(c.getNextStep(), 10*kpc); + double limit = 0.2; + AdiabaticCooling AC2(new UniformAdvectionField(Vector3d(1,0,0)), limit); + + EXPECT_DOUBLE_EQ(AC2.getLimit(), limit); + + // + } TEST (AdiabaticCooling, ConstantSphericalField) { diff --git a/test/testAdvectionField.cpp b/test/testAdvectionField.cpp index 756abb58d..2199004e9 100644 --- a/test/testAdvectionField.cpp +++ b/test/testAdvectionField.cpp @@ -105,4 +105,65 @@ TEST(testSphericalAdvectionField, SimpleTest) { } +TEST(testSphericalAdvectionShock, SimpleTest) { + + Vector3d origin(0, 0, 0); + double R_0(10); + double V_0(1000); + double lambda(0.1); + double R_rot(1.); + double V_rot(100); + + + SphericalAdvectionShock A(origin, R_0, V_0, lambda); + + // Check the properties of the advection field + EXPECT_DOUBLE_EQ(A.getOrigin().x, origin.x); + EXPECT_DOUBLE_EQ(A.getOrigin().y, origin.y); + EXPECT_DOUBLE_EQ(A.getOrigin().z, origin.z); + + EXPECT_DOUBLE_EQ(A.getR0(), R_0); + EXPECT_DOUBLE_EQ(A.getV0(), V_0); + EXPECT_DOUBLE_EQ(A.getLambda(), lambda); + + // Default values for R_Rot is R_0 + // Default value for Azimuthal speed is 0 + EXPECT_DOUBLE_EQ(A.getRRot(), R_0); + EXPECT_DOUBLE_EQ(A.getAzimuthalSpeed(), 0.); + + // Field should drop to 0.625*V_0 at the shock + // That's a difference to the analytic shock model where it should + // drop to v_r(R_0)=0.25*V_0. + EXPECT_DOUBLE_EQ(A.getField(Vector3d(R_0,0,0)).getR(), 0.625*V_0); + + // Field divergence should be zero for R>>R_0 + EXPECT_NEAR(A.getDivergence(Vector3d(15,0,0)), 0., 1e-10); + + // Check field and divergence + Vector3d Pos(2, 0, 0); + Vector3d a = A.getField(Pos); + Vector3d a0 = a.getUnitVector(); + double d = A.getDivergence(Pos); + + EXPECT_DOUBLE_EQ(a0.x, 1.); + EXPECT_DOUBLE_EQ(a0.y, 0.); + EXPECT_DOUBLE_EQ(a0.z, 0.); + EXPECT_DOUBLE_EQ(a.getR(), V_0); + + //Set explicitely the azimuthal rotation speed + A.setRRot(R_rot); + A.setAzimuthalSpeed(V_rot); + + EXPECT_DOUBLE_EQ(A.getRRot(), R_rot); + EXPECT_DOUBLE_EQ(A.getAzimuthalSpeed(), V_rot); + + Vector3d pos(1., 0., 0.); + Vector3d f = A.getField(pos); + EXPECT_DOUBLE_EQ(f.x, 1000.); + EXPECT_DOUBLE_EQ(f.y, 100.); + EXPECT_DOUBLE_EQ(f.z, 0.); + + +} + } //namespace crpropa From 2cfe82279b1e2727bc14b12bed680a26d1a5d128 Mon Sep 17 00:00:00 2001 From: mertelx Date: Fri, 24 Nov 2017 16:44:52 +0100 Subject: [PATCH 1042/1298] Drop scipy dependency in Diffusion test. Include tests for combined diffusion and advection of candidates and exceptions (neutral particles etc.). --- src/module/DiffusionSDE.cpp | 8 +- test/testDiffusionSDE.py.in | 506 +++++++++++++++++++++++++++--------- 2 files changed, 390 insertions(+), 124 deletions(-) diff --git a/src/module/DiffusionSDE.cpp b/src/module/DiffusionSDE.cpp index 16bf35ad7..c7278e460 100644 --- a/src/module/DiffusionSDE.cpp +++ b/src/module/DiffusionSDE.cpp @@ -151,12 +151,16 @@ void DiffusionSDE::process(Candidate *candidate) const { driftStep(Pos, LinProp, h); current.setPosition(Pos + LinProp); candidate->setCurrentStep(h*c_light); - candidate->setNextStep(h*c_light); + double newStep = 5*h*c_light; + newStep = clip(newStep, minStep, maxStep); + candidate->setNextStep(newStep); return; } current.setPosition(Pos + dir*h*c_light); candidate->setCurrentStep(h*c_light); - candidate->setNextStep(h*c_light); + double newStep = 5*h*c_light; + newStep = clip(newStep, minStep, maxStep); + candidate->setNextStep(newStep); return; } diff --git a/test/testDiffusionSDE.py.in b/test/testDiffusionSDE.py.in index 429dbb7d9..caf9158f9 100644 --- a/test/testDiffusionSDE.py.in +++ b/test/testDiffusionSDE.py.in @@ -1,3 +1,4 @@ +# coding=utf-8 import sys try: @@ -10,167 +11,428 @@ except: sys.exit(0) try: - from scipy.stats import anderson, chisquare - from scipy.integrate import quad import numpy as np except: print("***********************************************************") - print("* WARNING!! Couldn't import python scipy or numpy framework! *") + print("* WARNING!! Couldn't import numpy framework! *") print("* No python tests have been executed *") print("***********************************************************") sys.exit(-1) try: import crpropa - from crpropa import nG, kpc, pc, TeV, PeV, c_light + from crpropa import nG, kpc, pc, GeV, TeV, PeV, c_light except Exception as e: print("*** CRPropa import failed") print(type(e), str(e)) sys.exit(-2) +def Anderson(x): + """Scipy independent version of the Anderson-Darling test + + input: x + - Array of variables to be tested + + output: A2, _Avals, sig + - A2, test statistic + - _Avals, list of critical values + - sig, significance levels in percent + + If the test statistic is larger than the critical value the Null + hypothesis (The distribution is drawn from normal distribution) + has to be rejected at the corresponding significane level. + + The implemented version of the Anderson-Darling test is a + only a test for normality of a given distribution. When it comes + to testing normality the Anderson-Darling test is one of the most + powerful tests available. It may be compared to the Kolmogorov- + Smirnov test but gives more weights to the tails of the distribution. + + Details on the Anderson-Darling test can be found e.g. [1, 2]. + + The test is strongly inspired by the scipy [3] implementation + (see [4]). + + NOTE: The results for the test statistic may differ from the ones + derived by the scipy implementation. This is due to a different + treatment of the correction factor. The ratio of critical value + and test statistic is nevertheless the same. + + [1] https://en.wikipedia.org/wiki/Anderson%E2%80%93Darling_test + + [2] http://www.itl.nist.gov/div898/handbook/prc/section2/prc213.htm + + [3] Stéfan van der Walt, S. Chris Colbert and Gaël Varoquaux. + The NumPy Array: A Structure for Efficient Numerical Computation, + Computing in Science & Engineering, 13, 22-30 (2011), + DOI:10.1109/MCSE.2011.37 + + [4] https://github.com/scipy/scipy/blob/master/scipy/stats/morestats.py + + [5] Stephens, M A, "EDF Statistics for Goodness of Fit and + Some Comparisons", Journal of he American Statistical + Association, Vol. 69, Issue 347, Sept. 1974, pp 730-737 + + [6] Merten, L + The Anderson test statistic was calculated for 6.6e6 independent samples + of the numpy.random.norm(0,1,N=10000) distribution. The 0.99999-quantile + of the test statistic distribution is used as the critical value (2.274) + for the .00001-significance level. + """ + + + def CDF_norm(x, mu=0., sigma=1.): + + """Cumulative distribution function + + input: x + - np.array, list or float + + output: cdf + - np.array or float + + This function evaluates the cdf of the normal distribution + at a given position x (see e.g. [1]) + + [1] https://en.wikipedia.org/wiki/Normal_distribution + """ + + try: + x_tilde = (x-mu)/np.sqrt(2.)/sigma + except TypeError: + x = np.array(x) + x_tilde = (x-mu)/np.sqrt(2.)/sigma + try: + cdf = [1/2.*(1.+np.math.erf(x)) for x in x_tilde] + return np.array(cdf) + except TypeError: + cdf = 1/2.*(1.+np.math.erf(x_tilde)) + return cdf + + + # Critical values from [5, 6] + _Avals = np.array([0.576, 0.656, 0.787, 0.918, 1.092, 2.274]) + # Significance level in percent + sig = np.array([15, 10, 5, 2.5, 1, .00001]) + + ###################################################### + + # The values have to be ordered x1 <= x2 <= ... <= xN + y = np.sort(x) + + # Rescale the values to a standard normal distribution + xbar = np.mean(x, axis=0) + N = len(y) + s = np.std(x, ddof=1, axis=0) + w = (y - xbar) / s + + # Calculate the natural logarithm of the cdf and (1-cdf) + logcdf = np.log(CDF_norm(w)) + logsf = np.log(np.ones(N)-CDF_norm(w)) + + # Derive the test statistic + i = np.arange(1, N + 1) + A2 = -N - np.sum((2*i - 1.0) / N * (logcdf + logsf[::-1]), axis=0) + + # Rescale it, because mu and sigma were not known + A2 *= (1 + 4./N - 25./N**2.) + + + + return {'testStatistic': A2, 'criticalValues': _Avals, 'significanceLevels': sig} + class DiffusionOneDirection(unittest.TestCase): - # magnetic field + ConstMagVec = crpropa.Vector3d(0*nG,0*nG,1*nG) BField = crpropa.UniformMagneticField(ConstMagVec) - Dif = crpropa.DiffusionSDE(BField, 1e-4, 1*pc, 10*kpc, 0.) + + precision = 1e-4 + minStep = 1*pc + maxStep = 10*kpc + epsilon = 0. + + Dif = crpropa.DiffusionSDE(BField, precision, minStep, maxStep, epsilon) + DifAdv = crpropa.DiffusionSDE(BField, precision, minStep, maxStep, epsilon) + + def test_Simple(self): + self.assertEqual(self.Dif.getTolerance(), self.precision) + self.assertEqual(self.Dif.getMinimumStep(), self.minStep) + self.assertEqual(self.Dif.getMaximumStep(), self.maxStep) + self.assertEqual(self.Dif.getEpsilon(), self.epsilon) + self.assertEqual(self.Dif.getAlpha(), 1./3.) # default Kolmogorov diffusion + self.assertEqual(self.Dif.getScale(), 1.) # default D(4GeV) = 6.1e28 cm^2/s + + def test_NeutralPropagation(self): + c = crpropa.Candidate() + c.current.setId(crpropa.nucleusId(1,0)) + c.current.setEnergy(10*TeV) + c.current.setDirection(crpropa.Vector3d(1,0,0)) + + # check for position + self.Dif.process(c) + pos = c.current.getPosition() + self.assertAlmostEqual(pos.x/pc, 1.) #AlmostEqual due to rounding error + self.assertEqual(pos.y, 0.) + self.assertEqual(pos.z, 0.) + + # Step size is increased to maxStep + self.assertAlmostEqual(c.getNextStep()/self.maxStep, 1.) #AlmostEqual due to rounding error + + def test_NoBFieldPropagation(self): + + ConstMagVec = crpropa.Vector3d(0.) + BField = crpropa.UniformMagneticField(ConstMagVec) + + precision = 1e-4 + minStep = 1*pc + maxStep = 10*kpc + epsilon = 0. + + Dif = crpropa.DiffusionSDE(BField, precision, minStep, maxStep, epsilon) + c = crpropa.Candidate() + c.current.setId(crpropa.nucleusId(1,1)) + c.current.setEnergy(10*TeV) + c.current.setDirection(crpropa.Vector3d(1,0,0)) + + # check for position + Dif.process(c) + pos = c.current.getPosition() + self.assertAlmostEqual(pos.x/pc, 1.) #AlmostEqual due to rounding error + self.assertEqual(pos.y, 0.) + self.assertEqual(pos.z, 0.) + + # Step size is increased to maxStep + self.assertAlmostEqual(c.getNextStep()/minStep, 5.) #AlmostEqual due to rounding error - maxTra = crpropa.MaximumTrajectoryLength(50 *kpc) - msg1 = "Note that this is a statistical test. It might fail by chance with a probabilty O(0.00001)! You should rerun the test to make sure there is a bug." - msg2 = "Note that this is a statistical test. It might fail by chance with a probabilty O(0.00001)! You should rerun the test to make sure there is a bug." - zPosition10 = [] - zPosition1000 = [] - zPosition100000 = [] + def test_AdvectivePropagation(self): + + ConstMagVec = crpropa.Vector3d(0.) + BField = crpropa.UniformMagneticField(ConstMagVec) + + ConstAdvVec = crpropa.Vector3d(0., 1e6, 0.) + AdvField = crpropa.UniformAdvectionField(ConstAdvVec) + + precision = 1e-4 + minStep = 1*pc + maxStep = 10*kpc + epsilon = 0. + + Dif = crpropa.DiffusionSDE(BField, AdvField, precision, minStep, maxStep, epsilon) + c = crpropa.Candidate() + c.current.setId(crpropa.nucleusId(1,1)) + c.current.setEnergy(10*TeV) + c.current.setDirection(crpropa.Vector3d(1,0,0)) + + # check for position + Dif.process(c) + pos = c.current.getPosition() + self.assertEqual(pos.x, 0.) + self.assertAlmostEqual(pos.y, minStep/c_light*1e6) + self.assertEqual(pos.z, 0.) + + # Step size is increased to maxStep + self.assertAlmostEqual(c.getNextStep()/minStep, 5.) #AlmostEqual due to rounding error - def test_DiffusionEnergy10(self): + msg1 = "Note that this is a statistical test. It might fail by chance with a probabilty O(0.00001)! You should rerun the test to make sure there is a bug." + + def test_DiffusionEnergy10TeV(self): + x, y, z = [], [], [] E = 10 * TeV - for i in range(10**4): + D = self.Dif.getScale()*6.1e24*(E/(4*GeV))**self.Dif.getAlpha() + L_max = 50 * kpc + std_exp = np.sqrt(2*D*L_max/c_light) + mean_exp = 0. + N = 10**4 + + maxTra = crpropa.MaximumTrajectoryLength(L_max) + + for i in range(N): c = crpropa.Candidate() c.current.setId(crpropa.nucleusId(1,1)) c.current.setEnergy(E) - while c.getTrajectoryLength() < 50 * kpc: - self.maxTra.process(c) + while c.getTrajectoryLength() < L_max: + maxTra.process(c) self.Dif.process(c) - self.zPosition10.append(c.current.getPosition().z) - A2, Level, significant = anderson(self.zPosition10, 'norm') - self.assertLess(A2, 2.27, msg=self.msg1) + x.append(c.current.getPosition().x) + y.append(c.current.getPosition().y) + z.append(c.current.getPosition().z) + A2 = Anderson(z)['testStatistic'] + self.assertLess(A2, 2.274, msg=self.msg1) + meanX, meanY, meanZ = np.mean(x), np.mean(y), np.mean(z) + stdZ = np.std(z) + + # no diffusion in perpendicular direction + self.assertAlmostEqual(meanX, 0.) + self.assertAlmostEqual(meanY, 0.) + + # diffusion in parallel direction + # compare the mean and std of the z-positions with expected values + # z_mean = 0. (no advection) + # z_ std = (2*D_parallel*t)^0.5 + # Take 4 sigma errors due to limited number of candidates into account + stdOfMeans = std_exp/np.sqrt(N) + stdOfStds = std_exp/np.sqrt(N)/np.sqrt(2.) + self.assertLess(abs((meanZ-mean_exp)/4./stdOfMeans), 1., msg=self.msg1) + self.assertLess(abs((stdZ-std_exp)/4./stdOfStds), 1., msg=self.msg1) + - def test_DiffusionEnergy1000(self): - E = 1 * PeV - for i in range(10**4): + def test_DiffusionEnergy1PeV(self): + x, y, z = [], [], [] + E = 1 * TeV + D = self.Dif.getScale()*6.1e24*(E/(4*GeV))**self.Dif.getAlpha() + L_max = 50 * kpc + std_exp = np.sqrt(2*D*L_max/c_light) + mean_exp = 0. + N = 10**4 + + maxTra = crpropa.MaximumTrajectoryLength(L_max) + + for i in range(N): c = crpropa.Candidate() c.current.setId(crpropa.nucleusId(1,1)) c.current.setEnergy(E) - while c.getTrajectoryLength() < 50 * kpc: - self.maxTra.process(c) + while c.getTrajectoryLength() < L_max: + maxTra.process(c) self.Dif.process(c) - self.zPosition1000.append(c.current.getPosition().z) - A2, Level, significant = anderson(self.zPosition1000, 'norm') - self.assertLess(A2, 2.27, msg=self.msg1) + x.append(c.current.getPosition().x) + y.append(c.current.getPosition().y) + z.append(c.current.getPosition().z) + A2 = Anderson(z)['testStatistic'] + self.assertLess(A2, 2.274, msg=self.msg1) + meanX, meanY, meanZ = np.mean(x), np.mean(y), np.mean(z) + stdZ = np.std(z) - def test_DiffusionEnergy100000(self): - E = 100 * PeV - for i in range(10**4): + # no diffusion in perpendicular direction + self.assertAlmostEqual(meanX, 0.) + self.assertAlmostEqual(meanY, 0.) + + # diffusion in parallel direction + # compare the mean and std of the z-positions with expected values + # z_mean = 0. (no advection) + # z_ std = (2*D_parallel*t)^0.5 + # Take 4 sigma errors due to limited number of candidates into account + stdOfMeans = std_exp/np.sqrt(N) + stdOfStds = std_exp/np.sqrt(N)/np.sqrt(2.) + self.assertLess(abs((meanZ-mean_exp)/4./stdOfMeans), 1., msg=self.msg1) + self.assertLess(abs((stdZ-std_exp)/4./stdOfStds), 1., msg=self.msg1) + + def test_DiffusionEnergy100PeV(self): + x, y, z = [], [], [] + E = 10 * PeV + D = self.Dif.getScale()*6.1e24*(E/(4*GeV))**self.Dif.getAlpha() + L_max = 50 * kpc + std_exp = np.sqrt(2*D*L_max/c_light) + mean_exp = 0. + N = 10**4 + + maxTra = crpropa.MaximumTrajectoryLength(L_max) + + for i in range(N): c = crpropa.Candidate() c.current.setId(crpropa.nucleusId(1,1)) c.current.setEnergy(E) - while c.getTrajectoryLength() < 50 * kpc: - self.maxTra.process(c) + while c.getTrajectoryLength() < L_max: + maxTra.process(c) self.Dif.process(c) - self.zPosition100000.append(c.current.getPosition().z) - A2, Level, significant = anderson(self.zPosition100000, 'norm') - self.assertLess(A2, 2.27, msg=self.msg1) - - def test_DiffusionEnergy10ChiSquare(self): - N = len(self.zPosition10) - Data = abs(np.array(self.zPosition10)) - bins = 10 - Dist = 50 * kpc - rig = 10**13 - - while min(np.histogram(Data, bins)[0]) < 5: - bins -= 1 - - f_exp = np.zeros(bins) - - hist = np.histogram(Data, bins=bins) - - def pdf(R): - D = 6.1e24*pow((rig/4.0e9), 1./3.) - t = Dist / c_light - pdf = 2 * pow(4 * np.pi * D * t, -0.5) * np.exp(- R**2. / (4 * D * t)) - return pdf - - for i in range(bins): - a, b = hist[1][i], hist[1][i+1] - f_exp[i] = N*quad(pdf, a, b)[0] - - f_obs = np.histogram(Data, bins=bins)[0] - chi2, pValue = chisquare(f_obs, f_exp) - - self.assertLess(pValue, 0.99999) - self.assertGreater(pValue, 0.00001) - - def test_DiffusionEnergy1000ChiSquare(self): - N = len(self.zPosition1000) - Data = abs(np.array(self.zPosition1000)) - bins = 10 - Dist = 50 * kpc - rig = 10**15 - - while min(np.histogram(Data, bins)[0]) < 5: - bins -= 1 - - f_exp = np.zeros(bins) - - hist = np.histogram(Data, bins=bins) - - def pdf(R): - D = 6.1e24*pow((rig/4.0e9), 1./3.) - t = Dist / c_light - pdf = 2 * pow(4 * np.pi * D * t, -0.5) * np.exp(- R**2. / (4 * D * t)) - return pdf - - for i in range(bins): - a, b = hist[1][i], hist[1][i+1] - f_exp[i] = N*quad(pdf, a, b)[0] - - f_obs = np.histogram(Data, bins=bins)[0] - chi2, pValue = chisquare(f_obs, f_exp) - - self.assertLess(pValue, 0.99999) - self.assertGreater(pValue, 0.00001) - - def test_DiffusionEnergy100000ChiSquare(self): - N = len(self.zPosition100000) - Data = abs(np.array(self.zPosition100000)) - bins = 10 - Dist = 50 * kpc - rig = 10**17 - - while min(np.histogram(Data, bins)[0]) < 5: - bins -= 1 - - f_exp = np.zeros(bins) - - hist = np.histogram(Data, bins=bins) + x.append(c.current.getPosition().x) + y.append(c.current.getPosition().y) + z.append(c.current.getPosition().z) + A2 = Anderson(z)['testStatistic'] + self.assertLess(A2, 2.274, msg=self.msg1) + meanX, meanY, meanZ = np.mean(x), np.mean(y), np.mean(z) + stdZ = np.std(z) - def pdf(R): - D = 6.1e24*pow((rig/4.0e9), 1./3.) - t = Dist / c_light - pdf = 2 * pow(4 * np.pi * D * t, -0.5) * np.exp(- R**2. / (4 * D * t)) - return pdf + # no diffusion in perpendicular direction + self.assertAlmostEqual(meanX, 0.) + self.assertAlmostEqual(meanY, 0.) - for i in range(bins): - a, b = hist[1][i], hist[1][i+1] - f_exp[i] = N*quad(pdf, a, b)[0] + # diffusion in parallel direction + # compare the mean and std of the z-positions with expected values + # z_mean = 0. (no advection) + # z_ std = (2*D_parallel*t)^0.5 + # Take 4 sigma errors due to limited number of candidates into account + stdOfMeans = std_exp/np.sqrt(N) + stdOfStds = std_exp/np.sqrt(N)/np.sqrt(2.) + self.assertLess(abs((meanZ-mean_exp)/4./stdOfMeans), 1., msg=self.msg1) + self.assertLess(abs((stdZ-std_exp)/4./stdOfStds), 1., msg=self.msg1) - f_obs = np.histogram(Data, bins=bins)[0] - chi2, pValue = chisquare(f_obs, f_exp) - self.assertLess(pValue, 0.99999) - self.assertGreater(pValue, 0.00001) - + def test_FullTransport(self): + x, y, z = [], [], [] + E = 10 * TeV + D = self.DifAdv.getScale()*6.1e24*(E/(4*GeV))**self.DifAdv.getAlpha() + L_max = 50 * kpc + epsilon = 0.1 + advSpeed = 1e6 + + std_exp_x = np.sqrt(2*epsilon*D*L_max/c_light) + std_exp_y = np.sqrt(2*epsilon*D*L_max/c_light) + std_exp_z = np.sqrt(2*D*L_max/c_light) + mean_exp_x = advSpeed * L_max / c_light + mean_exp_y = 0. + mean_exp_z = 0. + + N = 10**4 + + maxTra = crpropa.MaximumTrajectoryLength(L_max) + + ConstMagVec = crpropa.Vector3d(0*nG,0*nG,1*nG) + BField = crpropa.UniformMagneticField(ConstMagVec) + + ConstAdvVec = crpropa.Vector3d(advSpeed, 0., 0.) + AdvField = crpropa.UniformAdvectionField(ConstAdvVec) + + precision = 1e-4 + minStep = 1*pc + maxStep = 10*kpc + + DifAdv = crpropa.DiffusionSDE(BField, AdvField, precision, minStep, maxStep, epsilon) + + + for i in range(N): + c = crpropa.Candidate() + c.current.setId(crpropa.nucleusId(1,1)) + c.current.setEnergy(E) + while c.getTrajectoryLength() < L_max: + maxTra.process(c) + DifAdv.process(c) + x.append(c.current.getPosition().x) + y.append(c.current.getPosition().y) + z.append(c.current.getPosition().z) + + # test for normality + A2 = Anderson(x)['testStatistic'] + self.assertLess(A2, 2.274, msg=self.msg1) + A2 = Anderson(y)['testStatistic'] + self.assertLess(A2, 2.274, msg=self.msg1) + A2 = Anderson(z)['testStatistic'] + self.assertLess(A2, 2.274, msg=self.msg1) + + meanX, meanY, meanZ = np.mean(x), np.mean(y), np.mean(z) + stdX, stdY, stdZ = np.std(x), np.std(y), np.std(z) + + + # diffusion in parallel direction + # compare the mean and std of the z-positions with expected values + # z_mean = 0. (no advection) + # z_ std = (2*D_parallel*t)^0.5 + # Take 4 sigma errors due to limited number of candidates into account + stdOfMeans_x = std_exp_x/np.sqrt(N) + stdOfStds_x = std_exp_x/np.sqrt(N)/np.sqrt(2.) + self.assertLess(abs((meanX-mean_exp_x)/4./stdOfMeans_x), 1., msg=self.msg1) + self.assertLess(abs((stdX-std_exp_x)/4./stdOfStds_x), 1., msg=self.msg1) + + stdOfMeans_y = std_exp_y/np.sqrt(N) + stdOfStds_y = std_exp_y/np.sqrt(N)/np.sqrt(2.) + self.assertLess(abs((meanY-mean_exp_y)/4./stdOfMeans_y), 1., msg=self.msg1) + self.assertLess(abs((stdY-std_exp_y)/4./stdOfStds_y), 1., msg=self.msg1) + + stdOfMeans_z = std_exp_z/np.sqrt(N) + stdOfStds_z = std_exp_z/np.sqrt(N)/np.sqrt(2.) + self.assertLess(abs((meanZ-mean_exp_z)/4./stdOfMeans_z), 1., msg=self.msg1) + self.assertLess(abs((stdZ-std_exp_z)/4./stdOfStds_z), 1., msg=self.msg1) if __name__ == '__main__': unittest.main() + From 0681519104c305f5451b954bf381d97e10315be2 Mon Sep 17 00:00:00 2001 From: mertelx Date: Wed, 29 Nov 2017 17:51:10 +0100 Subject: [PATCH 1043/1298] Fix typos. Add include guards. Add description for advection fields. --- CMakeLists.txt | 2 +- include/CRPropa.h | 2 +- include/crpropa/Units.h | 5 +- .../crpropa/advectionField/AdvectionField.h | 50 ++++++++++++++----- ...SpiralField.h => ArchimedeanSpiralField.h} | 22 +++++--- include/crpropa/module/AdiabaticCooling.h | 11 +++- include/crpropa/module/DiffusionSDE.h | 19 ++++++- python/2_headers.i | 2 +- src/advectionField/AdvectionField.cpp | 35 ++++++++++--- ...alField.cpp => ArchimedeanSpiralField.cpp} | 22 ++++---- src/module/AdiabaticCooling.cpp | 4 +- src/module/DiffusionSDE.cpp | 27 ++++------ test/testAdiabaticCooling.cpp | 2 +- 13 files changed, 137 insertions(+), 66 deletions(-) rename include/crpropa/magneticField/{ArchmedeanSpiralField.h => ArchimedeanSpiralField.h} (59%) rename src/magneticField/{ArchmedeanSpiralField.cpp => ArchimedeanSpiralField.cpp} (59%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 02b728b52..3c7ae1d2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -392,7 +392,7 @@ add_library(crpropa SHARED src/magneticField/MagneticField.cpp src/magneticField/MagneticFieldGrid.cpp src/magneticField/PshirkovField.cpp - src/magneticField/ArchmedeanSpiralField.cpp + src/magneticField/ArchimedeanSpiralField.cpp src/advectionField/AdvectionField.cpp ${CRPROPA_EXTRA_SOURCES} ) diff --git a/include/CRPropa.h b/include/CRPropa.h index 5861114e2..fd42a52cc 100644 --- a/include/CRPropa.h +++ b/include/CRPropa.h @@ -59,7 +59,7 @@ #include "crpropa/magneticField/MagneticFieldGrid.h" #include "crpropa/magneticField/PshirkovField.h" #include "crpropa/magneticField/QuimbyMagneticField.h" -#include "crpropa/magneticField/ArchmedeanSpiralField.h" +#include "crpropa/magneticField/ArchimedeanSpiralField.h" #include "crpropa/advectionField/AdvectionField.h" diff --git a/include/crpropa/Units.h b/include/crpropa/Units.h index 0cdd7a259..51f01b152 100644 --- a/include/crpropa/Units.h +++ b/include/crpropa/Units.h @@ -89,16 +89,15 @@ static const double cm = centimeter; // second static const double nanosecond = 1e-9 * second; -static const double mikrosecond = 1e-6 * second; +static const double microsecond = 1e-6 * second; static const double millisecond = 1e-3 * second; static const double minute = 60 * second; static const double hour = 3600 * second; static const double ns = nanosecond; -static const double mus = mikrosecond; +static const double mus = microsecond; static const double ms = millisecond; static const double sec = second; static const double min = minute; -static const double h = hour; } // namespace crpropa diff --git a/include/crpropa/advectionField/AdvectionField.h b/include/crpropa/advectionField/AdvectionField.h index 30d19398e..88de6bfee 100644 --- a/include/crpropa/advectionField/AdvectionField.h +++ b/include/crpropa/advectionField/AdvectionField.h @@ -1,7 +1,7 @@ #ifndef CRPROPA_ADVECTIONFIELD_H #define CRPROPA_ADVECTIONFIELD_H -#pragma once + #include #include #include @@ -44,7 +44,7 @@ class AdvectionFieldList: public AdvectionField { /** @class UniformAdvectionField - @brief Advection field with one B-field vector. + @brief Advection field with one velocity/advection-field vector. */ class UniformAdvectionField: public AdvectionField { Vector3d value; @@ -52,30 +52,39 @@ class UniformAdvectionField: public AdvectionField { UniformAdvectionField(const Vector3d &value); Vector3d getField(const Vector3d &position) const; double getDivergence(const Vector3d &position) const; + + std::string getDescription() const; }; /** @class ConstantSphericalAdvectionField -@brief Spherical advection with a constant wind speed - +@brief Spherical advection field with a constant wind speed */ class ConstantSphericalAdvectionField: public AdvectionField { Vector3d origin; //origin of the advection sphere - double vWind; // maximum wind velocity + double vWind; // wind velocity public: - ConstantSphericalAdvectionField(Vector3d origin, double vWind); + /** Constructor + @param origin Origin of the advection field + @param vWind Constant wind velocity + +*/ + + ConstantSphericalAdvectionField(const Vector3d origin, double vWind); Vector3d getField(const Vector3d &position) const; double getDivergence(const Vector3d &position) const; - void setOrigin(Vector3d origin); + void setOrigin(const Vector3d origin); void setVWind(double vMax); Vector3d getOrigin() const; double getVWind() const; - //Add description method + std::string getDescription() const; + + }; /** @@ -91,13 +100,20 @@ class SphericalAdvectionField: public AdvectionField { double tau; // transition distance double alpha; //tuning parameter public: - SphericalAdvectionField(Vector3d origin, double radius, double vMax, double tau, double alpha); + /** Constructor + @param origin Origin of the advection sphere + @param radius Radius of the advection sphere + @param vMax Maximum wind velocity + @param tau Transition distance + @param alpha Tuning parameter +*/ + SphericalAdvectionField(const Vector3d origin, double radius, double vMax, double tau, double alpha); Vector3d getField(const Vector3d &position) const; double getDivergence(const Vector3d &position) const; double getV(const double &r) const; - void setOrigin(Vector3d origin); + void setOrigin(const Vector3d origin); void setRadius(double radius); void setVMax(double vMax); void setTau(double tau); @@ -129,7 +145,15 @@ class SphericalAdvectionShock: public AdvectionField { double v_phi; // rotation speed at r_rot public: - SphericalAdvectionShock(Vector3d origin, double r_0, double v_0, double lambda); + /** Constructor + @param origin Origin of the advection sphere + @param r_0 Position of the shock + @param v_0 Constant velocity (r< #include #include @@ -18,13 +18,13 @@ namespace crpropa { /** -@class ArchmedeanSpiralField -@brief Magnetic field model following a archmedean spiral +@class ArchimedeanSpiralField +@brief Magnetic field model following a Archimedean spiral See e.g. Jokipii, Levy & Hubbard 1977 */ -class ArchmedeanSpiralField: public MagneticField { +class ArchimedeanSpiralField: public MagneticField { private: double B_0; // Magnetic field strength at reference level double R_0; // Reference level @@ -32,7 +32,13 @@ class ArchmedeanSpiralField: public MagneticField { double V_w; // Asymptotic wind speed public: - ArchmedeanSpiralField(double B_0, double R_0, double Omega, double V_w); +/** Constructor + @param B_0 Magnetic field strength at reference level + @param R_0 Reference level + @param Omega Angular velocity of the rotation + @param V_w Asymptotic wind speed +*/ + ArchimedeanSpiralField(double B_0, double R_0, double Omega, double V_w); Vector3d getField(const Vector3d &pos) const; @@ -50,4 +56,4 @@ class ArchmedeanSpiralField: public MagneticField { } // end namespace crpropa -#endif // CRPROPA_ACHMEDEANSPIRALFIELD_H +#endif // CRPROPA_ACHIMEDEANSPIRALFIELD_H diff --git a/include/crpropa/module/AdiabaticCooling.h b/include/crpropa/module/AdiabaticCooling.h index 996482df2..ee3013181 100644 --- a/include/crpropa/module/AdiabaticCooling.h +++ b/include/crpropa/module/AdiabaticCooling.h @@ -1,4 +1,6 @@ -#pragma once +#ifndef CRPROPA_ADIABATICCOOLING_H +#define CRPROPA_ADIABATICCOOLING_H + #include #include #include @@ -9,6 +11,8 @@ #include "crpropa/Module.h" #include "crpropa/Units.h" #include "crpropa/advectionField/AdvectionField.h" +#include "kiss/logger.h" + namespace crpropa { @@ -23,6 +27,10 @@ class AdiabaticCooling: public Module { double limit; public: + /** Constructor + @param advectionField The advection field used for the adiabatic energy change + @param limit Maximum relative energy change allowed +*/ AdiabaticCooling(ref_ptr advectionField); AdiabaticCooling(ref_ptr advectionField, double limit); void process(Candidate *c) const; @@ -36,3 +44,4 @@ class AdiabaticCooling: public Module { }; // end namesspace crpropa +#endif // CRPROPA_ADIABATICCOOLING_H diff --git a/include/crpropa/module/DiffusionSDE.h b/include/crpropa/module/DiffusionSDE.h index 59f3794b6..3d63ffa4b 100644 --- a/include/crpropa/module/DiffusionSDE.h +++ b/include/crpropa/module/DiffusionSDE.h @@ -1,13 +1,20 @@ -#pragma once +#ifndef CRPROPA_DIFFUSIONSDE_H +#define CRPROPA_DIFFUSIONSDE_H + #include #include #include #include +#include +#include #include #include #include #include +#include + +#include "kiss/logger.h" namespace crpropa { @@ -35,6 +42,14 @@ class DiffusionSDE : public Module{ public: +/** Constructor + @param minStep minStep/c_light is the minimum integration timestep + @param maxStep maxStep/c_light is the maximum integration timestep + @param tolerance Tolerance is criterion for step adjustment. Step adjustment takes place when the tangential vector of the magnetic field line is calculated. + @param epsilon Ratio of parallel and perpendicular diffusion coefficient D_par = epsilon*D_perp + @param alpha Power law index of the energy dependent diffusion coefficient: D\propto E^alpha + @param scale Scaling factor for the diffusion coefficient D = scale*D_0 +*/ DiffusionSDE(ref_ptr magneticField, double tolerance = 1e-4, double minStep=(10*pc), double maxStep=(1*kpc), double epsilon=0.1); DiffusionSDE(ref_ptr magneticField, ref_ptr advectionField, double tolerance = 1e-4, double minStep=(10*pc), double maxStep=(1*kpc), double epsilon=0.1); @@ -65,3 +80,5 @@ class DiffusionSDE : public Module{ }; } //namespace crpropa + +#endif // CRPROPA_DIFFUSIONSDE_H diff --git a/python/2_headers.i b/python/2_headers.i index 1a69d27dd..db2aed4e7 100644 --- a/python/2_headers.i +++ b/python/2_headers.i @@ -308,7 +308,7 @@ %include "crpropa/magneticField/AMRMagneticField.h" %include "crpropa/magneticField/JF12Field.h" %include "crpropa/magneticField/PshirkovField.h" -%include "crpropa/magneticField/ArchmedeanSpiralField.h" +%include "crpropa/magneticField/ArchimedeanSpiralField.h" %include "crpropa/module/BreakCondition.h" %include "crpropa/module/Boundary.h" diff --git a/src/advectionField/AdvectionField.cpp b/src/advectionField/AdvectionField.cpp index f1ce4188d..45fd60d41 100644 --- a/src/advectionField/AdvectionField.cpp +++ b/src/advectionField/AdvectionField.cpp @@ -38,9 +38,15 @@ double UniformAdvectionField::getDivergence(const Vector3d &position) const { return 0.; } +std::string UniformAdvectionField::getDescription() const { + std::stringstream s; + s << "v0: " << value / km * sec << " km/s, "; + return s.str(); +} + //---------------------------------------------------------------- -ConstantSphericalAdvectionField::ConstantSphericalAdvectionField(Vector3d origin, double vWind) { +ConstantSphericalAdvectionField::ConstantSphericalAdvectionField(const Vector3d origin, double vWind) { setOrigin(origin); setVWind(vWind); } @@ -55,7 +61,7 @@ double ConstantSphericalAdvectionField::getDivergence(const Vector3d &position) return 2*vWind/R; } -void ConstantSphericalAdvectionField::setOrigin(Vector3d o) { +void ConstantSphericalAdvectionField::setOrigin(const Vector3d o) { origin=o; return; } @@ -73,11 +79,18 @@ double ConstantSphericalAdvectionField::getVWind() const { return vWind; } +std::string ConstantSphericalAdvectionField::getDescription() const { + std::stringstream s; + s << "Origin: " << origin / kpc << " kpc, "; + s << "v0: " << vWind / km * sec << " km/s, "; + return s.str(); +} + //---------------------------------------------------------------- -SphericalAdvectionField::SphericalAdvectionField(Vector3d origin, double radius, double vMax, double tau, double alpha) { +SphericalAdvectionField::SphericalAdvectionField(const Vector3d origin, double radius, double vMax, double tau, double alpha) { setOrigin(origin); setRadius(radius); setVMax(vMax); @@ -109,7 +122,7 @@ double SphericalAdvectionField::getV(const double &r) const { return f; } -void SphericalAdvectionField::setOrigin(Vector3d o) { +void SphericalAdvectionField::setOrigin(const Vector3d o) { origin = o; return; } @@ -167,7 +180,7 @@ std::string SphericalAdvectionField::getDescription() const { //----------------------------------------------------------------- -SphericalAdvectionShock::SphericalAdvectionShock(Vector3d origin, double r_0, double v_0, double l) { +SphericalAdvectionShock::SphericalAdvectionShock(const Vector3d origin, double r_0, double v_0, double l) { setOrigin(origin); setR0(r_0); setV0(v_0); @@ -210,7 +223,7 @@ double SphericalAdvectionShock::g_prime(double r) const { return 1. / (2*lambda*(1+cosh(-a))); } -void SphericalAdvectionShock::setOrigin(Vector3d o) { +void SphericalAdvectionShock::setOrigin(const Vector3d o) { origin = o; } @@ -258,5 +271,15 @@ double SphericalAdvectionShock::getAzimuthalSpeed() const { return v_phi; } +std::string SphericalAdvectionShock::getDescription() const { + std::stringstream s; + s << "Origin: " << origin / kpc << " kpc, "; + s << "r0 (shock radius): " << r_0 / kpc << " kpc, "; + s << "r_rot (norm. azimuthal velocity): " << r_rot / kpc << " kpc, "; + s << "v0 (maximum radial speed): " << v_0 / km * sec << " km/s, "; + s << "v_phi (azimuthal speed @ r_rot): " << v_phi / km * sec << " km/s, "; + s << "lambda: " << lambda / pc << " pc"; + return s.str(); +} } // namespace crpropa diff --git a/src/magneticField/ArchmedeanSpiralField.cpp b/src/magneticField/ArchimedeanSpiralField.cpp similarity index 59% rename from src/magneticField/ArchmedeanSpiralField.cpp rename to src/magneticField/ArchimedeanSpiralField.cpp index 095c7dab8..23d3bebb8 100644 --- a/src/magneticField/ArchmedeanSpiralField.cpp +++ b/src/magneticField/ArchimedeanSpiralField.cpp @@ -1,15 +1,15 @@ -#include "crpropa/magneticField/ArchmedeanSpiralField.h" +#include "crpropa/magneticField/ArchimedeanSpiralField.h" namespace crpropa { -ArchmedeanSpiralField::ArchmedeanSpiralField(double B_0, double R_0, double Omega, double V_w) { +ArchimedeanSpiralField::ArchimedeanSpiralField(double B_0, double R_0, double Omega, double V_w) { setB0(B_0); setR0(R_0); setOmega(Omega); setVw(V_w); } -Vector3d ArchmedeanSpiralField::getField(const Vector3d &pos) const { +Vector3d ArchimedeanSpiralField::getField(const Vector3d &pos) const { double r = pos.getR(); double theta = pos.getTheta(); @@ -45,40 +45,40 @@ Vector3d ArchmedeanSpiralField::getField(const Vector3d &pos) const { return B; } -void ArchmedeanSpiralField::setR0(double R) { +void ArchimedeanSpiralField::setR0(double R) { R_0 = R; return; } -void ArchmedeanSpiralField::setB0(double B) { +void ArchimedeanSpiralField::setB0(double B) { B_0 = B; return; } -void ArchmedeanSpiralField::setOmega(double Om) { +void ArchimedeanSpiralField::setOmega(double Om) { Omega = Om; return; } -void ArchmedeanSpiralField::setVw(double v) { +void ArchimedeanSpiralField::setVw(double v) { V_w = v; return; } -double ArchmedeanSpiralField::getR0() const { +double ArchimedeanSpiralField::getR0() const { return R_0; } -double ArchmedeanSpiralField::getB0() const{ +double ArchimedeanSpiralField::getB0() const{ return B_0; } -double ArchmedeanSpiralField::getOmega() const{ +double ArchimedeanSpiralField::getOmega() const{ return Omega; } -double ArchmedeanSpiralField::getVw() const { +double ArchimedeanSpiralField::getVw() const { return V_w; } diff --git a/src/module/AdiabaticCooling.cpp b/src/module/AdiabaticCooling.cpp index ab1754022..66a7db1dc 100644 --- a/src/module/AdiabaticCooling.cpp +++ b/src/module/AdiabaticCooling.cpp @@ -22,8 +22,8 @@ void AdiabaticCooling::process(Candidate *c) const { Div += advectionField->getDivergence(pos); } catch (std::exception &e) { - std::cerr << "AdiabaticCooling: Exception in getDivergence." << std::endl; - std::cerr << e.what() << std::endl; + KISS_LOG_ERROR << "AdiabaticCooling: Exception in getDivergence.\n" + << e.what(); } double dEdt = -E / 3. * Div; // cooling due to advection -p/3 * div(V_wind) diff --git a/src/module/DiffusionSDE.cpp b/src/module/DiffusionSDE.cpp index c7278e460..0b540f396 100644 --- a/src/module/DiffusionSDE.cpp +++ b/src/module/DiffusionSDE.cpp @@ -1,14 +1,5 @@ #include "crpropa/module/DiffusionSDE.h" -#include - -#include -#include -#include -#include -#include - -#include "kiss/logger.h" using namespace crpropa; @@ -107,7 +98,7 @@ void DiffusionSDE::process(Candidate *candidate) const { Vector3d DirOut = Vector3d(0.); - double propTime = TStep * pow(h, 0.5) / c_light; + double propTime = TStep * sqrt(h) / c_light; size_t counter = 0; double r=42.; //arbitrary number larger than one @@ -128,7 +119,7 @@ void DiffusionSDE::process(Candidate *candidate) const { //std::cout << "counter = " << counter << "\n"; size_t stepNumber = pow(2, counter-1); - double allowedTime = TStep * pow(h, 0.5) / c_light / stepNumber; + double allowedTime = TStep * sqrt(h) / c_light / stepNumber; Vector3d Start = PosIn; Vector3d PosOut = Vector3d(0.); Vector3d PosErr = Vector3d(0.); @@ -182,7 +173,7 @@ void DiffusionSDE::process(Candidate *candidate) const { } // Integration of the SDE with a Mayorama-Euler-method - Vector3d PO = PosOut + LinProp + (NVec * NStep + BVec * BStep) * pow(h, 0.5) ; + Vector3d PO = PosOut + LinProp + (NVec * NStep + BVec * BStep) * sqrt(h) ; // Throw error message if something went wrong with propagation. // Deactivate candidate. @@ -228,13 +219,13 @@ void DiffusionSDE::process(Candidate *candidate) const { /* const std::string AL = "arcLength"; if (candidate->hasProperty(AL) == false){ - double arcLen = (TStep + NStep + BStep) * pow(h, 0.5); + double arcLen = (TStep + NStep + BStep) * sqrt(h); candidate->setProperty(AL, arcLen); return; } else { double arcLen = candidate->getProperty(AL); - arcLen += (TStep + NStep + BStep) * pow(h, 0.5); + arcLen += (TStep + NStep + BStep) * sqrt(h); candidate->setProperty(AL, arcLen); } */ @@ -259,8 +250,8 @@ void DiffusionSDE::tryStep(const Vector3d &PosIn, Vector3d &POut, Vector3d &PosE BField = magneticField->getField(y_n, z); } catch (std::exception &e) { - std::cerr << "DiffusionSDE: Exception in getField." << std::endl; - std::cerr << e.what() << std::endl; + KISS_LOG_ERROR << "DiffusionSDE: Exception in magneticField::getField.\n" + << e.what(); } k[i] = BField.getUnitVector() * c_light; @@ -277,8 +268,8 @@ void DiffusionSDE::driftStep(const Vector3d &Pos, Vector3d &LinProp, double h) c AdvField = advectionField->getField(Pos); } catch (std::exception &e) { - std::cerr << "DiffusionSDE: Exception in getField." << std::endl; - std::cerr << e.what() << std::endl; + KISS_LOG_ERROR << "DiffusionSDE: Exception in advectionField::getField.\n" + << e.what(); } LinProp += AdvField * h; return; diff --git a/test/testAdiabaticCooling.cpp b/test/testAdiabaticCooling.cpp index ac122825f..ba6b872bc 100644 --- a/test/testAdiabaticCooling.cpp +++ b/test/testAdiabaticCooling.cpp @@ -5,7 +5,7 @@ #include "crpropa/module/AdiabaticCooling.h" #include "gtest/gtest.h" -#include +//#include namespace crpropa { From 284899883807f4a16dcc97cc3336d71ac204fe99 Mon Sep 17 00:00:00 2001 From: mertelx Date: Wed, 29 Nov 2017 17:57:41 +0100 Subject: [PATCH 1044/1298] Delete ColumnDensityColumn because it is not needed. --- src/module/TextOutput.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/module/TextOutput.cpp b/src/module/TextOutput.cpp index 30d3b1025..b907fdb9a 100644 --- a/src/module/TextOutput.cpp +++ b/src/module/TextOutput.cpp @@ -48,8 +48,6 @@ void TextOutput::printHeader() const { *out << "#"; if (fields.test(TrajectoryLengthColumn)) *out << "\tD"; - if (fields.test(ColumnDensityColumn)) - *out << "\tN"; if (fields.test(RedshiftColumn)) *out << "\tz"; if (fields.test(SerialNumberColumn)) @@ -100,8 +98,6 @@ void TextOutput::printHeader() const { if (fields.test(TrajectoryLengthColumn)) *out << "# D Trajectory length [" << lengthScale / Mpc << " Mpc]\n"; - if (fields.test(ColumnDensityColumn)) - *out << "# N Column density [a.u.]\n"; if (fields.test(RedshiftColumn)) *out << "# z Redshift\n"; if (fields.test(SerialNumberColumn)) From 47ed8a0a934679128493cab74faf9d6a3aa88c1b Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Thu, 30 Nov 2017 16:32:14 +0100 Subject: [PATCH 1045/1298] Removed whitespace --- src/module/DiffusionSDE.cpp | 62 +++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/src/module/DiffusionSDE.cpp b/src/module/DiffusionSDE.cpp index 0b540f396..1509e3bce 100644 --- a/src/module/DiffusionSDE.cpp +++ b/src/module/DiffusionSDE.cpp @@ -18,7 +18,7 @@ const double bs[] = { 2825. / 27648., 0., 18575. / 48384., 13525. -DiffusionSDE::DiffusionSDE(ref_ptr magneticField, double tolerance, +DiffusionSDE::DiffusionSDE(ref_ptr magneticField, double tolerance, double minStep, double maxStep, double epsilon) : minStep(0) { @@ -50,7 +50,7 @@ void DiffusionSDE::process(Candidate *candidate) const { ParticleState ¤t = candidate->current; candidate->previous = current; - + double h = clip(candidate->getNextStep(), minStep, maxStep) / c_light; Vector3d PosIn = current.getPosition(); Vector3d DirIn = current.getDirection(); @@ -60,7 +60,7 @@ void DiffusionSDE::process(Candidate *candidate) const { if (current.getCharge() == 0) { Vector3d dir = current.getDirection(); Vector3d Pos = current.getPosition(); - + Vector3d LinProp(0.); if (advectionField){ driftStep(Pos, LinProp, h); @@ -71,7 +71,7 @@ void DiffusionSDE::process(Candidate *candidate) const { candidate->setNextStep(maxStep); return; } - + double z = candidate->getRedshift(); double rig = current.getEnergy() / current.getCharge(); @@ -80,13 +80,13 @@ void DiffusionSDE::process(Candidate *candidate) const { double BTensor[] = {0., 0., 0., 0., 0., 0., 0., 0., 0.}; calculateBTensor(rig, BTensor, PosIn, DirIn, z); - + // Generate random numbers double eta[] = {0., 0., 0.}; for(size_t i=0; i < 3; i++) { eta[i] = Random::instance().randNorm(); } - + double TStep = BTensor[0] * eta[0]; double NStep = BTensor[4] * eta[1]; double BStep = BTensor[8] * eta[2]; @@ -94,7 +94,7 @@ void DiffusionSDE::process(Candidate *candidate) const { Vector3d TVec(0.); Vector3d NVec(0.); Vector3d BVec(0.); - + Vector3d DirOut = Vector3d(0.); @@ -112,12 +112,9 @@ void DiffusionSDE::process(Candidate *candidate) const { counter += 1; // Check for better break condition - } while (r > 1 && fabs(propTime) >= minStep/c_light); - - //std::cout << "r = " << r << "\n"; - //std::cout << "propTime = " << propTime*c_light/kpc << "\n"; - //std::cout << "counter = " << counter << "\n"; - + } while (r > 1 && fabs(propTime) >= minStep/c_light); + + size_t stepNumber = pow(2, counter-1); double allowedTime = TStep * sqrt(h) / c_light / stepNumber; Vector3d Start = PosIn; @@ -126,9 +123,8 @@ void DiffusionSDE::process(Candidate *candidate) const { for (size_t j=0; jsetNextStep(newStep); return; } - + // Choose a random perpendicular vector as the Normal-vector. // Prevent 'nan's in the NVec-vector in the case of = 0. while (NVec.getR()==0.){ @@ -174,13 +170,13 @@ void DiffusionSDE::process(Candidate *candidate) const { // Integration of the SDE with a Mayorama-Euler-method Vector3d PO = PosOut + LinProp + (NVec * NStep + BVec * BStep) * sqrt(h) ; - + // Throw error message if something went wrong with propagation. // Deactivate candidate. bool NaN = std::isnan(PO.getR()); if (NaN == true){ candidate->setActive(false); - KISS_LOG_WARNING + KISS_LOG_WARNING << "\nCandidate with 'nan'-position occured: \n" << "position = " << PO << "\n" << "PosIn = " << PosIn << "\n" @@ -193,9 +189,9 @@ void DiffusionSDE::process(Candidate *candidate) const { << "Candidate is deactivated!\n"; return; } - + //DirOut = (PO - PosIn - LinProp).getUnitVector(); //Advection does not change the momentum vector - // Random direction around the tangential direction accounts for the pitch angle average. + // Random direction around the tangential direction accounts for the pitch angle average. DirOut = Random::instance().randConeVector(TVec, M_PI/2.); current.setPosition(PO); current.setDirection(DirOut); @@ -210,12 +206,12 @@ void DiffusionSDE::process(Candidate *candidate) const { } candidate->setNextStep(nextStep); - + // Debugging and Testing // Delete comments if additional information should be stored in candidate - // This property "arcLength" can be interpreted as the effective arclength + // This property "arcLength" can be interpreted as the effective arclength // of the propagation along a magnetic field line. - + /* const std::string AL = "arcLength"; if (candidate->hasProperty(AL) == false){ @@ -229,7 +225,7 @@ void DiffusionSDE::process(Candidate *candidate) const { candidate->setProperty(AL, arcLen); } */ - + } @@ -243,22 +239,22 @@ void DiffusionSDE::tryStep(const Vector3d &PosIn, Vector3d &POut, Vector3d &PosE Vector3d y_n = PosIn; for (size_t j = 0; j < i; j++) y_n += k[j] * a[i * 6 + j] * propStep; - + // update k_i = direction of the regular magnetic mean field Vector3d BField(0.); try { BField = magneticField->getField(y_n, z); - } + } catch (std::exception &e) { KISS_LOG_ERROR << "DiffusionSDE: Exception in magneticField::getField.\n" << e.what(); } - + k[i] = BField.getUnitVector() * c_light; POut += k[i] * b[i] * propStep; PosErr += (k[i] * (b[i] - bs[i])) * propStep / kpc; - + } } @@ -266,7 +262,7 @@ void DiffusionSDE::driftStep(const Vector3d &Pos, Vector3d &LinProp, double h) c Vector3d AdvField(0.); try { AdvField = advectionField->getField(Pos); - } + } catch (std::exception &e) { KISS_LOG_ERROR << "DiffusionSDE: Exception in advectionField::getField.\n" << e.what(); @@ -276,7 +272,7 @@ void DiffusionSDE::driftStep(const Vector3d &Pos, Vector3d &LinProp, double h) c } void DiffusionSDE::calculateBTensor(double r, double BTen[], Vector3d pos, Vector3d dir, double z) const { - + double DifCoeff = scale * 6.1e24 * pow((std::abs(r) / 4.0e9), alpha); BTen[0] = pow( 2 * DifCoeff, 0.5); BTen[4] = pow(2 * epsilon * DifCoeff, 0.5); @@ -369,11 +365,11 @@ std::string DiffusionSDE::getDescription() const { s << "minStep: " << minStep / kpc << " kpc, "; s << "maxStep: " << maxStep / kpc << " kpc, "; s << "tolerance: " << tolerance << "\n"; - + if (epsilon != 0.1) { s << "epsilon: " << epsilon << ", "; } - + if (alpha != 1./3.) { s << "alpha: " << alpha << "\n"; } From 0d1ec109a523443297e1d1ab9f6fa1c6e3d78ec3 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 1 Dec 2017 16:56:05 +0100 Subject: [PATCH 1046/1298] Group SourceFeatures into Doxygen list --- doc/Doxyfile | 4 ++-- include/crpropa/Source.h | 37 ++++++++++++++++++++++++------------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/doc/Doxyfile b/doc/Doxyfile index e21fa8fd3..809eba57b 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -308,7 +308,7 @@ SUBGROUPING = YES # @ingroup) instead of on a separate page (for HTML and Man pages) or # section (for LaTeX and RTF). -INLINE_GROUPED_CLASSES = NO +INLINE_GROUPED_CLASSES = YES # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and # unions with only public data fields or simple typedef fields will be shown @@ -482,7 +482,7 @@ SORT_MEMBERS_CTORS_1ST = NO # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. -SORT_GROUP_NAMES = NO +SORT_GROUP_NAMES = YES # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to diff --git a/include/crpropa/Source.h b/include/crpropa/Source.h index ecb380824..4222aac5b 100644 --- a/include/crpropa/Source.h +++ b/include/crpropa/Source.h @@ -10,19 +10,6 @@ namespace crpropa { -/** - @class SourceFeature - @brief Abstract base class cosmic ray source features - */ -class SourceFeature: public Referenced { -protected: - std::string description; -public: - virtual void prepareParticle(ParticleState& particle) const {}; - virtual void prepareCandidate(Candidate& candidate) const; - std::string getDescription() const; -}; - /** @class SourceInterface @brief Abstract base class for cosmic ray sources @@ -65,6 +52,28 @@ class SourceList: public SourceInterface { std::string getDescription() const; }; + +/** @defgroup SourceFeature SourceFeatures + * Sourcefeatures are added to sources and manipulate the proeprties of the + * emitted candidate. + * @{ + */ + +/** + @class SourceFeature + @brief Abstract base class cosmic ray source features + */ +class SourceFeature: public Referenced { +protected: + std::string description; +public: + virtual void prepareParticle(ParticleState& particle) const {}; + virtual void prepareCandidate(Candidate& candidate) const; + std::string getDescription() const; +}; + + + /** @class SourceParticleType @brief Particle type at the source @@ -493,6 +502,8 @@ class SourceGenericComposition: public SourceFeature { std::vector cdf; }; + +/** @} */ // end of group SourceFeature #endif }// namespace crpropa From 0343fbf1ef6b94db6ce73628deedd19387f5544f Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 1 Dec 2017 17:17:08 +0100 Subject: [PATCH 1047/1298] Fixed order in Source.h --- include/crpropa/Source.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/include/crpropa/Source.h b/include/crpropa/Source.h index 4222aac5b..3b2c7fc5a 100644 --- a/include/crpropa/Source.h +++ b/include/crpropa/Source.h @@ -10,6 +10,20 @@ namespace crpropa { +/** + @class SourceFeature + @brief Abstract base class cosmic ray source features + */ +class SourceFeature: public Referenced { +protected: + std::string description; +public: + virtual void prepareParticle(ParticleState& particle) const {}; + virtual void prepareCandidate(Candidate& candidate) const; + std::string getDescription() const; +}; + + /** @class SourceInterface @brief Abstract base class for cosmic ray sources @@ -59,20 +73,6 @@ class SourceList: public SourceInterface { * @{ */ -/** - @class SourceFeature - @brief Abstract base class cosmic ray source features - */ -class SourceFeature: public Referenced { -protected: - std::string description; -public: - virtual void prepareParticle(ParticleState& particle) const {}; - virtual void prepareCandidate(Candidate& candidate) const; - std::string getDescription() const; -}; - - /** @class SourceParticleType From a40760ed05d492d1bf238439f5e56e87d57a004e Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Wed, 6 Dec 2017 17:42:43 +0000 Subject: [PATCH 1048/1298] added crpropa version to TextOutput --- src/module/TextOutput.cpp | 3 ++- test/testOutput.cpp | 21 +++++++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/module/TextOutput.cpp b/src/module/TextOutput.cpp index b907fdb9a..74eabc0a7 100644 --- a/src/module/TextOutput.cpp +++ b/src/module/TextOutput.cpp @@ -1,6 +1,7 @@ #include "crpropa/module/TextOutput.h" #include "crpropa/module/ParticleCollector.h" #include "crpropa/Units.h" +#include "crpropa/Version.h" #include #include @@ -43,7 +44,6 @@ TextOutput::TextOutput(const std::string &filename, gzip(); } - void TextOutput::printHeader() const { *out << "#"; if (fields.test(TrajectoryLengthColumn)) @@ -124,6 +124,7 @@ void TextOutput::printHeader() const { } *out << "# no index = current, 0 = at source, 1 = at point of creation\n#\n"; + *out << "# CRPropa version: " << g_GIT_DESC << "\n#\n"; } void TextOutput::process(Candidate *c) const { diff --git a/test/testOutput.cpp b/test/testOutput.cpp index 26fc99cd3..fc62a8db9 100644 --- a/test/testOutput.cpp +++ b/test/testOutput.cpp @@ -7,12 +7,14 @@ #include "crpropa/ParticleID.h" #include "crpropa/Candidate.h" #include "crpropa/Units.h" +#include "crpropa/Version.h" #include "crpropa/module/Output.h" #include "crpropa/module/TextOutput.h" #include "crpropa/module/ParticleCollector.h" #include #include "gtest/gtest.h" +#include namespace crpropa { @@ -107,6 +109,23 @@ TEST(TextOutput, printProperty) { "#\tfoo"); } +TEST(TextOutput, printHeader_Version) { + Candidate c; + TextOutput output(Output::Event1D); + + ::testing::internal::CaptureStdout(); + output.process(&c); + std::string captured = testing::internal::GetCapturedStdout(); + + EXPECT_EQ( + captured.substr( + // length of the prefix is 19 chars + captured.find("# CRPropa version: ") + 19, + captured.find("\n") + 1 + ), + g_GIT_DESC); +} + //-- ParticleCollector TEST(ParticleCollector, getCount) { @@ -138,8 +157,6 @@ TEST(ParticleCollector, reprocess) { EXPECT_EQ(output[0], c); } -#include - TEST(ParticleCollector, dumpload) { ref_ptr c = new Candidate(nucleusId(1,1), 1.234*EeV); c->current.setPosition(Vector3d(1,2,3)); From 494ad0de72d88c12859abafce843dfcdbefe714f Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Wed, 6 Dec 2017 19:09:48 +0000 Subject: [PATCH 1049/1298] testOutput bug fix --- test/testOutput.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/testOutput.cpp b/test/testOutput.cpp index fc62a8db9..735b34984 100644 --- a/test/testOutput.cpp +++ b/test/testOutput.cpp @@ -117,11 +117,13 @@ TEST(TextOutput, printHeader_Version) { output.process(&c); std::string captured = testing::internal::GetCapturedStdout(); + // length of the prefix is 19 chars + size_t version_pos = captured.find("# CRPropa version: ") + 19; + EXPECT_EQ( captured.substr( - // length of the prefix is 19 chars - captured.find("# CRPropa version: ") + 19, - captured.find("\n") + 1 + version_pos, + captured.find("\n", version_pos) - version_pos ), g_GIT_DESC); } From 618096f87c122810ae36723f69e0e22c53277c70 Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Wed, 6 Dec 2017 23:53:42 +0000 Subject: [PATCH 1050/1298] HDF5Output improved and version attribute added --- include/crpropa/module/HDF5Output.h | 30 ++++- include/crpropa/module/Output.h | 5 +- src/module/HDF5Output.cpp | 186 +++++++++++++++++----------- src/module/Output.cpp | 18 ++- 4 files changed, 163 insertions(+), 76 deletions(-) diff --git a/include/crpropa/module/HDF5Output.h b/include/crpropa/module/HDF5Output.h index 448b722a7..646bf7845 100644 --- a/include/crpropa/module/HDF5Output.h +++ b/include/crpropa/module/HDF5Output.h @@ -3,6 +3,33 @@ #ifndef CRPROPA_HDF5OUTPUT_H #define CRPROPA_HDF5OUTPUT_H +/* + * HDF5 structure: + * + * HDF5 "FILENAME.h5" { + * GROUP "/" { + * DATASET "OUTPUTTYPE" { + * DATATYPE H5T_COMPOUND { + * ... + * } + * DATASPACE SIMPLE { ( 1 ) / ( H5S_UNLIMITED ) } + * DATA { + * ... + * } + * ATTRIBUTE "Version" { + * DATATYPE H5T_STRING { + * STRSIZE 100; + * STRPAD H5T_STR_NULLTERM; + * CSET H5T_CSET_ASCII; + * CTYPE H5T_C_S1; + * } + * DATASPACE SCALAR + * DATA { (0): "VERSION" } + * } + * } } } + * + */ + #include "crpropa/module/Output.h" #include "stdint.h" #include @@ -48,7 +75,7 @@ class HDF5Output: public Output { double weight; unsigned char propertyBuffer[propertyBufferSize]; } OutputRow; - + std::string filename; hid_t file, sid; @@ -62,6 +89,7 @@ class HDF5Output: public Output { ~HDF5Output(); void process(Candidate *candidate) const; + herr_t insertVersion(); std::string getDescription() const; void open(const std::string &filename); diff --git a/include/crpropa/module/Output.h b/include/crpropa/module/Output.h index f8b8f8b65..4b05b3e00 100644 --- a/include/crpropa/module/Output.h +++ b/include/crpropa/module/Output.h @@ -8,7 +8,6 @@ #include #include - namespace crpropa { /** @@ -53,7 +52,6 @@ class Output: public Module { SerialNumberColumn, WeightColumn }; - enum OutputType { Trajectory1D, Trajectory3D, @@ -62,6 +60,9 @@ class Output: public Module { Everything }; + std::string OutputTypeName(OutputType outputtype); + const std::string outputName; + Output(); Output(OutputType outputtype); diff --git a/src/module/HDF5Output.cpp b/src/module/HDF5Output.cpp index 33862ae28..37b5bae42 100644 --- a/src/module/HDF5Output.cpp +++ b/src/module/HDF5Output.cpp @@ -1,8 +1,11 @@ #ifdef CRPROPA_HAVE_HDF5 #include "crpropa/module/HDF5Output.h" +#include "crpropa/Version.h" #include "kiss/logger.h" + #include +#include const hsize_t RANK = 1; const hsize_t BUFFER_SIZE = 1024 * 16; @@ -10,91 +13,133 @@ const hsize_t BUFFER_SIZE = 1024 * 16; namespace crpropa { // map variant types to H5T_NATIVE - - hid_t variantTypeToH5T_NATIVE(Variant::Type type) +hid_t variantTypeToH5T_NATIVE(Variant::Type type) { + if (type == Variant::TYPE_INT64) + return H5T_NATIVE_INT64; + else if(type == Variant::TYPE_BOOL) + return H5T_NATIVE_HBOOL; + else if(type == Variant::TYPE_CHAR) + return H5T_NATIVE_CHAR; + else if(type == Variant::TYPE_UCHAR) + return H5T_NATIVE_UCHAR; + else if(type == Variant::TYPE_INT16) + return H5T_NATIVE_INT16; + else if(type == Variant::TYPE_UINT16) + return H5T_NATIVE_UINT16; + else if(type == Variant::TYPE_INT32) + return H5T_NATIVE_INT32; + else if(type == Variant::TYPE_UINT32) + return H5T_NATIVE_UINT32; + else if(type == Variant::TYPE_INT64) + return H5T_NATIVE_INT64; + else if(type == Variant::TYPE_UINT64) + return H5T_NATIVE_UINT64; + else if(type == Variant::TYPE_FLOAT) + return H5T_NATIVE_FLOAT; + else if(type == Variant::TYPE_DOUBLE) + return H5T_NATIVE_DOUBLE; + else if(type == Variant::TYPE_STRING) + return H5T_C_S1; + else { - if (type == Variant::TYPE_INT64) - return H5T_NATIVE_INT64; - else if(type == Variant::TYPE_BOOL) - return H5T_NATIVE_HBOOL; - else if(type == Variant::TYPE_CHAR) - return H5T_NATIVE_CHAR; - else if(type == Variant::TYPE_UCHAR) - return H5T_NATIVE_UCHAR; - else if(type == Variant::TYPE_INT16) - return H5T_NATIVE_INT16; - else if(type == Variant::TYPE_UINT16) - return H5T_NATIVE_UINT16; - else if(type == Variant::TYPE_INT32) - return H5T_NATIVE_INT32; - else if(type == Variant::TYPE_UINT32) - return H5T_NATIVE_UINT32; - else if(type == Variant::TYPE_INT64) - return H5T_NATIVE_INT64; - else if(type == Variant::TYPE_UINT64) - return H5T_NATIVE_UINT64; - else if(type == Variant::TYPE_FLOAT) - return H5T_NATIVE_FLOAT; - else if(type == Variant::TYPE_DOUBLE) - return H5T_NATIVE_DOUBLE; - else if(type == Variant::TYPE_STRING) - return H5T_C_S1; - else - { - KISS_LOG_ERROR << "variantTypeToH5T_NATIVE:: Type: " << Variant::getTypeName(type) << " unknown."; - throw std::runtime_error("No matching HDF type for Variant type"); - } + KISS_LOG_ERROR << "variantTypeToH5T_NATIVE:: Type: " << Variant::getTypeName(type) << " unknown."; + throw std::runtime_error("No matching HDF type for Variant type"); } - +} HDF5Output::HDF5Output(const std::string& filename) : Output(), filename(filename), file(-1), sid(-1), dset(-1), dataspace(-1) { } HDF5Output::HDF5Output(const std::string& filename, OutputType outputtype) : Output(outputtype), filename(filename), file(-1), sid(-1), dset(-1), dataspace(-1) { + outputtype = outputtype; } HDF5Output::~HDF5Output() { close(); } +herr_t HDF5Output::insertVersion() { + hid_t strtype, attr_space, version_attr; + hsize_t dims = 0; + herr_t status; + + strtype = H5Tcopy(H5T_C_S1); + status = H5Tset_size(strtype, 100); + + attr_space = H5Screate_simple(0, &dims, NULL); + version_attr = H5Acreate2(dset, "Version", strtype, attr_space, H5P_DEFAULT, H5P_DEFAULT); + status = H5Awrite(version_attr, strtype, g_GIT_DESC); + status = H5Aclose(version_attr); + status = H5Sclose(attr_space); + + return status; +} + void HDF5Output::open(const std::string& filename) { file = H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); sid = H5Tcreate(H5T_COMPOUND, sizeof(OutputRow)); - H5Tinsert(sid, "D", HOFFSET(OutputRow, D), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "z", HOFFSET(OutputRow, z), H5T_NATIVE_DOUBLE); - - H5Tinsert(sid, "SN", HOFFSET(OutputRow, SN), H5T_NATIVE_UINT64); - H5Tinsert(sid, "ID", HOFFSET(OutputRow, ID), H5T_NATIVE_INT32); - H5Tinsert(sid, "E", HOFFSET(OutputRow, E), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "X", HOFFSET(OutputRow, X), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "Y", HOFFSET(OutputRow, Y), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "Z", HOFFSET(OutputRow, Z), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "Px", HOFFSET(OutputRow, Px), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "Py", HOFFSET(OutputRow, Py), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "Pz", HOFFSET(OutputRow, Pz), H5T_NATIVE_DOUBLE); - - H5Tinsert(sid, "SN0", HOFFSET(OutputRow, SN0), H5T_NATIVE_UINT64); - H5Tinsert(sid, "ID0", HOFFSET(OutputRow, ID0), H5T_NATIVE_INT32); - H5Tinsert(sid, "E0", HOFFSET(OutputRow, E0), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "X0", HOFFSET(OutputRow, X0), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "Y0", HOFFSET(OutputRow, Y0), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "Z0", HOFFSET(OutputRow, Z0), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "P0x", HOFFSET(OutputRow, P0x), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "P0y", HOFFSET(OutputRow, P0y), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "P0z", HOFFSET(OutputRow, P0z), H5T_NATIVE_DOUBLE); - - H5Tinsert(sid, "SN1", HOFFSET(OutputRow, SN1), H5T_NATIVE_UINT64); - H5Tinsert(sid, "ID1", HOFFSET(OutputRow, ID1), H5T_NATIVE_INT32); - H5Tinsert(sid, "E1", HOFFSET(OutputRow, E1), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "X1", HOFFSET(OutputRow, X1), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "Y1", HOFFSET(OutputRow, Y1), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "Z1", HOFFSET(OutputRow, Z1), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "P1x", HOFFSET(OutputRow, P1x), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "P1y", HOFFSET(OutputRow, P1y), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "P1z", HOFFSET(OutputRow, P1z), H5T_NATIVE_DOUBLE); - H5Tinsert(sid, "weight", HOFFSET(OutputRow, weight), H5T_NATIVE_DOUBLE); - + if (fields.test(TrajectoryLengthColumn)) + H5Tinsert(sid, "D", HOFFSET(OutputRow, D), H5T_NATIVE_DOUBLE); + if (fields.test(RedshiftColumn)) + H5Tinsert(sid, "z", HOFFSET(OutputRow, z), H5T_NATIVE_DOUBLE); + if (fields.test(SerialNumberColumn)) + H5Tinsert(sid, "SN", HOFFSET(OutputRow, SN), H5T_NATIVE_UINT64); + if (fields.test(CurrentIdColumn)) + H5Tinsert(sid, "ID", HOFFSET(OutputRow, ID), H5T_NATIVE_INT32); + if (fields.test(CurrentEnergyColumn)) + H5Tinsert(sid, "E", HOFFSET(OutputRow, E), H5T_NATIVE_DOUBLE); + if (fields.test(CurrentPositionColumn) && oneDimensional) + H5Tinsert(sid, "X", HOFFSET(OutputRow, X), H5T_NATIVE_DOUBLE); + if (fields.test(CurrentPositionColumn) && not oneDimensional) { + H5Tinsert(sid, "X", HOFFSET(OutputRow, X), H5T_NATIVE_DOUBLE); + H5Tinsert(sid, "Y", HOFFSET(OutputRow, Y), H5T_NATIVE_DOUBLE); + H5Tinsert(sid, "Z", HOFFSET(OutputRow, Z), H5T_NATIVE_DOUBLE); + } + if (fields.test(CurrentDirectionColumn) && not oneDimensional) { + H5Tinsert(sid, "Px", HOFFSET(OutputRow, Px), H5T_NATIVE_DOUBLE); + H5Tinsert(sid, "Py", HOFFSET(OutputRow, Py), H5T_NATIVE_DOUBLE); + H5Tinsert(sid, "Pz", HOFFSET(OutputRow, Pz), H5T_NATIVE_DOUBLE); + } + if (fields.test(SerialNumberColumn)) + H5Tinsert(sid, "SN0", HOFFSET(OutputRow, SN0), H5T_NATIVE_UINT64); + if (fields.test(SourceIdColumn)) + H5Tinsert(sid, "ID0", HOFFSET(OutputRow, ID0), H5T_NATIVE_INT32); + if (fields.test(SourceEnergyColumn)) + H5Tinsert(sid, "E0", HOFFSET(OutputRow, E0), H5T_NATIVE_DOUBLE); + if (fields.test(SourcePositionColumn) && oneDimensional) + H5Tinsert(sid, "X0", HOFFSET(OutputRow, X0), H5T_NATIVE_DOUBLE); + if (fields.test(SourcePositionColumn) && not oneDimensional){ + H5Tinsert(sid, "X0", HOFFSET(OutputRow, X0), H5T_NATIVE_DOUBLE); + H5Tinsert(sid, "Y0", HOFFSET(OutputRow, Y0), H5T_NATIVE_DOUBLE); + H5Tinsert(sid, "Z0", HOFFSET(OutputRow, Z0), H5T_NATIVE_DOUBLE); + } + if (fields.test(SourceDirectionColumn) && not oneDimensional) { + H5Tinsert(sid, "P0x", HOFFSET(OutputRow, P0x), H5T_NATIVE_DOUBLE); + H5Tinsert(sid, "P0y", HOFFSET(OutputRow, P0y), H5T_NATIVE_DOUBLE); + H5Tinsert(sid, "P0z", HOFFSET(OutputRow, P0z), H5T_NATIVE_DOUBLE); + } + if (fields.test(SerialNumberColumn)) + H5Tinsert(sid, "SN1", HOFFSET(OutputRow, SN1), H5T_NATIVE_UINT64); + if (fields.test(CreatedIdColumn)) + H5Tinsert(sid, "ID1", HOFFSET(OutputRow, ID1), H5T_NATIVE_INT32); + if (fields.test(CreatedEnergyColumn)) + H5Tinsert(sid, "E1", HOFFSET(OutputRow, E1), H5T_NATIVE_DOUBLE); + if (fields.test(CreatedPositionColumn) && oneDimensional) + H5Tinsert(sid, "X1", HOFFSET(OutputRow, X1), H5T_NATIVE_DOUBLE); + if (fields.test(CreatedPositionColumn) && not oneDimensional) { + H5Tinsert(sid, "X1", HOFFSET(OutputRow, X1), H5T_NATIVE_DOUBLE); + H5Tinsert(sid, "Y1", HOFFSET(OutputRow, Y1), H5T_NATIVE_DOUBLE); + H5Tinsert(sid, "Z1", HOFFSET(OutputRow, Z1), H5T_NATIVE_DOUBLE); + } + if (fields.test(CreatedDirectionColumn) && not oneDimensional) { + H5Tinsert(sid, "P1x", HOFFSET(OutputRow, P1x), H5T_NATIVE_DOUBLE); + H5Tinsert(sid, "P1y", HOFFSET(OutputRow, P1y), H5T_NATIVE_DOUBLE); + H5Tinsert(sid, "P1z", HOFFSET(OutputRow, P1z), H5T_NATIVE_DOUBLE); + } + if (fields.test(WeightColumn)) + H5Tinsert(sid, "weight", HOFFSET(OutputRow, weight), H5T_NATIVE_DOUBLE); + size_t pos = 0; for(std::vector::const_iterator iter = properties.begin(); iter != properties.end(); ++iter) @@ -102,7 +147,7 @@ void HDF5Output::open(const std::string& filename) { hid_t type = variantTypeToH5T_NATIVE((*iter).defaultValue.getType()); if (type == H5T_C_S1) { // set size of string field to size of default value! - type = H5Tcopy (H5T_C_S1); + type = H5Tcopy(H5T_C_S1); H5Tset_size(type, (*iter).defaultValue.toString().size()); } @@ -126,7 +171,8 @@ void HDF5Output::open(const std::string& filename) { hsize_t max_dims[RANK] = {H5S_UNLIMITED}; dataspace = H5Screate_simple(RANK, dims, max_dims); - dset = H5Dcreate2(file, "CRPROPA3", sid, dataspace, H5P_DEFAULT, plist, H5P_DEFAULT); + dset = H5Dcreate2(file, outputName.c_str(), sid, dataspace, H5P_DEFAULT, plist, H5P_DEFAULT); + insertVersion(); H5Pclose(plist); diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 48a510c86..93a15dc7d 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -5,12 +5,24 @@ namespace crpropa { -Output::Output() : lengthScale(Mpc), energyScale(EeV), oneDimensional(false), count(0) { +Output::Output() : outputName(OutputTypeName(Everything)), lengthScale(Mpc), energyScale(EeV), oneDimensional(false), count(0) { enableAll(); } -Output::Output(OutputType outputtype) : lengthScale(Mpc), energyScale(EeV), oneDimensional(false), count(0) { - setOutputType(outputtype); +Output::Output(OutputType outputtype) : outputName(OutputTypeName(outputtype)), lengthScale(Mpc), energyScale(EeV), oneDimensional(false), count(0) { + setOutputType(outputtype); +} + +std::string Output::OutputTypeName(OutputType outputtype){ + if (outputtype == Trajectory1D) + return "Trajectory1D"; + if (outputtype == Event1D) + return "Event1D"; + if (outputtype == Trajectory3D) + return "Trajectory3D"; + if (outputtype == Event3D); + return "Event3D"; + return "Everything"; } void Output::modify() { From 008becf5b5c6f5708f327c62d16d295ee4abd4b6 Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Thu, 7 Dec 2017 09:25:41 +0000 Subject: [PATCH 1051/1298] declare_version() implemented --- CMakeLists.txt | 1 - include/crpropa/Version.h | 16 ++++++++++++++++ python/2_headers.i | 4 ++++ python/crpropa-builtin.i | 5 ----- src/Version.cpp.in | 37 +++++++++++++++++++++++++++++++++++++ 5 files changed, 57 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c7ae1d2c..38bffafe8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -316,7 +316,6 @@ file(DOWNLOAD https://www.desy.de/~crpropa/data/data.tar.gz-CHECKSUM ${CMAKE_BINARY_DIR}/data.tar.gz-CHECKSUM) file(STRINGS ${CMAKE_BINARY_DIR}/data.tar.gz-CHECKSUM DATA_CHECKSUM LIMIT_COUNT 1 LENGTH_MINIMUM 32 LENGTH_MAXIMUM 32) -file(WRITE ${CMAKE_BINARY_DIR}/data.tar.gz-CHECKSUM2 ${DATA_CHECKSUM}) file(DOWNLOAD https://www.desy.de/~crpropa/data/data.tar.gz ${CMAKE_BINARY_DIR}/data.tar.gz diff --git a/include/crpropa/Version.h b/include/crpropa/Version.h index 43787921b..ee729c3ac 100644 --- a/include/crpropa/Version.h +++ b/include/crpropa/Version.h @@ -1,3 +1,19 @@ +#include + extern const char g_GIT_SHA1[]; extern const char g_GIT_REFSPEC[]; extern const char g_GIT_DESC[]; + +/** + @fn declare_version + @brief A helper function to track the steering card version + + Use at the beginning of the (python) code by putting the string of + the current version, e.g., declare_version("3.1-135-g9ec850f"). + If there is a mismatch a warning message is shown. + The current version number can be obtained through git: + git describe --tags + or through python: + print(crpropa.__version__) + */ +void declare_version(const std::string); diff --git a/python/2_headers.i b/python/2_headers.i index db2aed4e7..c80d9f09d 100644 --- a/python/2_headers.i +++ b/python/2_headers.i @@ -57,6 +57,10 @@ %include "crpropa/Logging.h" +%include "crpropa/Version.h" +%pythoncode %{ + __version__ = g_GIT_DESC +%} %include "crpropa/Vector3.h" %include "crpropa/Referenced.h" diff --git a/python/crpropa-builtin.i b/python/crpropa-builtin.i index 95aac95cf..c8d0658f0 100644 --- a/python/crpropa-builtin.i +++ b/python/crpropa-builtin.i @@ -16,11 +16,6 @@ /* 2: SWIG and CRPropa headers */ %include "2_headers.i" -%include "crpropa/Version.h" -%pythoncode %{ - __version__ = g_GIT_DESC -%} - /* 3. Pretty print for Python */ %define __REPR__( classname ) diff --git a/src/Version.cpp.in b/src/Version.cpp.in index 549c4f23f..860d04c08 100644 --- a/src/Version.cpp.in +++ b/src/Version.cpp.in @@ -1,4 +1,10 @@ #include "crpropa/Version.h" +#include "kiss/logger.h" + +#include +#include +#include +#include #define GIT_SHA1 "@GIT_SHA1@" #define GIT_REFSPEC "@GIT_REFSPEC@" @@ -6,3 +12,34 @@ const char g_GIT_SHA1[] = GIT_SHA1; const char g_GIT_REFSPEC[] = GIT_REFSPEC; const char g_GIT_DESC[] = GIT_DESC; + +std::vector split_version(std::string input) { + std::istringstream ss(input); + std::string part; + std::vector parts; + + while(std::getline(ss, part, '-')) + parts.push_back(part); + + return parts; +} + +void declare_version(const std::string input_version) { + std::string git_version(GIT_DESC); + std::vector git_parts, input_parts; + + git_parts = split_version(git_version); + input_parts = split_version(input_version); + + for(size_t i = 0; i < input_parts.size(); ++i) { + if (git_parts[i].compare(input_parts[i]) != 0) + KISS_LOG_WARNING << + "Version mismatch! To clear this warning \n" + "review the python code for potential incompatibilities and update \n" + "its version declaration or install the declared version of CRPropa. \n" + "- CRPropa version: " << git_version << "\n" + "- Python code version: " << input_version << "\n" + "Use git diff to inspect the differences: \n" + " git diff " << git_version << " " << input_version << "\n"; + } +} From 6da65f00c87ef1151cfabe280fe7c19581577405 Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Thu, 7 Dec 2017 09:32:36 +0000 Subject: [PATCH 1052/1298] version check fix - stupid mistake --- src/Version.cpp.in | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Version.cpp.in b/src/Version.cpp.in index 860d04c08..42fedffc1 100644 --- a/src/Version.cpp.in +++ b/src/Version.cpp.in @@ -32,7 +32,7 @@ void declare_version(const std::string input_version) { input_parts = split_version(input_version); for(size_t i = 0; i < input_parts.size(); ++i) { - if (git_parts[i].compare(input_parts[i]) != 0) + if (git_parts[i].compare(input_parts[i]) != 0) { KISS_LOG_WARNING << "Version mismatch! To clear this warning \n" "review the python code for potential incompatibilities and update \n" @@ -40,6 +40,8 @@ void declare_version(const std::string input_version) { "- CRPropa version: " << git_version << "\n" "- Python code version: " << input_version << "\n" "Use git diff to inspect the differences: \n" - " git diff " << git_version << " " << input_version << "\n"; + " git diff " << input_version << " " << git_version << "\n"; + break; + } } } From bdb6d858843faa2c9f7f1c814f769fd08baf1854 Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Thu, 7 Dec 2017 10:11:01 +0000 Subject: [PATCH 1053/1298] Fixed #143 - dropped the legacy XML support --- CMakeLists.txt | 42 +- include/crpropa/XmlExecute.h | 49 - libs/pugixml/CMakeLists.txt | 9 - libs/pugixml/README | 3 - libs/pugixml/pugiconfig.hpp | 69 - libs/pugixml/pugixml.cpp | 10250 ---------------- libs/pugixml/pugixml.hpp | 1265 -- src/XmlExecute.cpp | 752 -- src/main.cpp | 25 - test/xml/test1D.xml | 59 - test/xml/test1D_discreteSource.xml | 50 - .../test3D_continuousHomogeneousSources.xml | 59 - .../xml/test3D_discreteHomogeneousSources.xml | 60 - test/xml/test3D_kolmogorovBfield.xml | 84 - test/xml/test3D_noBfield.xml | 68 - test/xml/test3D_uniformBfield.xml | 78 - test/xml/testCRPropa2EventOutput1D.xml | 35 - test/xml/testCRPropa2EventOutput3D.xml | 58 - test/xml/testCRPropa2TrajectoryOutput1D.xml | 35 - test/xml/testCRPropa2TrajectoryOutput3D.xml | 58 - 20 files changed, 1 insertion(+), 13107 deletions(-) delete mode 100644 include/crpropa/XmlExecute.h delete mode 100644 libs/pugixml/CMakeLists.txt delete mode 100644 libs/pugixml/README delete mode 100644 libs/pugixml/pugiconfig.hpp delete mode 100644 libs/pugixml/pugixml.cpp delete mode 100644 libs/pugixml/pugixml.hpp delete mode 100644 src/XmlExecute.cpp delete mode 100644 src/main.cpp delete mode 100644 test/xml/test1D.xml delete mode 100644 test/xml/test1D_discreteSource.xml delete mode 100644 test/xml/test3D_continuousHomogeneousSources.xml delete mode 100644 test/xml/test3D_discreteHomogeneousSources.xml delete mode 100644 test/xml/test3D_kolmogorovBfield.xml delete mode 100644 test/xml/test3D_noBfield.xml delete mode 100644 test/xml/test3D_uniformBfield.xml delete mode 100644 test/xml/testCRPropa2EventOutput1D.xml delete mode 100644 test/xml/testCRPropa2EventOutput3D.xml delete mode 100644 test/xml/testCRPropa2TrajectoryOutput1D.xml delete mode 100644 test/xml/testCRPropa2TrajectoryOutput3D.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index 38bffafe8..6eb76b284 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,7 +92,7 @@ if(ENABLE_COVERAGE) COMMAND ${LCOV_PATH} --directory . --capture --output-file coverage.info VERBATIM # clean external libs - COMMAND ${LCOV_PATH} --remove coverage.info "/usr/include/*" "/usr/lib/*" "*/libs/gtest/*" "*/libs/eigen3/*" "*/libs/zstream-cpp/*" "*/libs/pugixml/*" "*/build/*" -o coverage.info.cleaned VERBATIM + COMMAND ${LCOV_PATH} --remove coverage.info "/usr/include/*" "/usr/lib/*" "*/libs/gtest/*" "*/libs/eigen3/*" "*/libs/zstream-cpp/*" "*/build/*" -o coverage.info.cleaned VERBATIM # Generate html output COMMAND ${GENHTML_PATH} -o coverageReport coverage.info.cleaned VERBATIM @@ -113,19 +113,11 @@ if(ENABLE_COVERAGE) endif(ENABLE_COVERAGE) -list(APPEND CRPROPA_EXTRA_INCLUDES libs/pugixml) - - # kiss (provided) add_subdirectory(libs/kiss) list(APPEND CRPROPA_EXTRA_LIBRARIES kiss) list(APPEND CRPROPA_EXTRA_INCLUDES libs/kiss/include) -# pugixml (provided) -add_subdirectory(libs/pugixml) -list(APPEND CRPROPA_EXTRA_LIBRARIES pugixml) -list(APPEND CRPROPA_EXTRA_INCLUDES libs/pugixml) - # HepID (provided) add_subdirectory(libs/HepPID) list(APPEND CRPROPA_EXTRA_LIBRARIES HepPID) @@ -328,17 +320,6 @@ execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_BINARY_DIR}/data.tar file(GLOB_RECURSE CRPROPA_INCLUDES RELATIVE ${CMAKE_SOURCE_DIR} include/*.h) include_directories(include ${CRPROPA_EXTRA_INCLUDES}) -# Creates a meta-header file for easy inclusion in 3rd party C++ projects -file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/include/crpropa/CRPropa.h) -foreach(filename ${CRPROPA_INCLUDES}) - # skip magneticLens due to additional requirements which are not available as compiled libraries later - if(NOT filename MATCHES "(.*)/magneticLens/(.*)") - string(REPLACE "include/" "" filename ${filename}) - file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/include/crpropa/CRPropa.h "#include \"${filename}\"\n") - endif() -endforeach(filename) -include_directories(include ${CMAKE_CURRENT_BINARY_DIR}/include) - add_library(crpropa SHARED src/Candidate.cpp src/Clock.cpp @@ -357,7 +338,6 @@ add_library(crpropa SHARED src/Random.cpp src/Source.cpp src/Variant.cpp - src/XmlExecute.cpp src/module/Boundary.cpp src/module/BreakCondition.cpp src/module/DiffusionSDE.cpp @@ -397,9 +377,6 @@ add_library(crpropa SHARED ) target_link_libraries(crpropa ${CRPROPA_EXTRA_LIBRARIES}) -add_executable(crpropa-xmlrun src/main.cpp) -target_link_libraries(crpropa-xmlrun crpropa) - # ---------------------------------------------------------------------------- # Python # ---------------------------------------------------------------------------- @@ -465,7 +442,6 @@ endif(ENABLE_PYTHON AND PYTHONLIBS_FOUND) # Install # ---------------------------------------------------------------------------- add_definitions(-DCRPROPA_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") -install(TARGETS crpropa-xmlrun RUNTIME DESTINATION bin) install(TARGETS crpropa DESTINATION lib) install(DIRECTORY include/ DESTINATION include FILES_MATCHING PATTERN "*.h") install(DIRECTORY ${CMAKE_BINARY_DIR}/include/ DESTINATION include FILES_MATCHING PATTERN "*.h") @@ -556,20 +532,4 @@ if(ENABLE_TESTING) add_test(testPythonExtension ${PYTHON_EXECUTABLE} testPythonExtension.py) endif(ENABLE_PYTHON AND PYTHONLIBS_FOUND) - # XML tests (CRPropa2 compatibility) - set(XML_EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/crpropa-xmlrun) - add_test(testXML1D_discreteSource ${XML_EXECUTABLE} ${CMAKE_SOURCE_DIR}/test/xml/test1D_discreteSource.xml) - add_test(testXML1D ${XML_EXECUTABLE} ${CMAKE_SOURCE_DIR}/test/xml/test1D.xml) - add_test(testXML3D_continuousHomogeneousSources ${XML_EXECUTABLE} ${CMAKE_SOURCE_DIR}/test/xml/test3D_continuousHomogeneousSources.xml) - add_test(testXML3D_discreteHomogeneousSources ${XML_EXECUTABLE} ${CMAKE_SOURCE_DIR}/test/xml/test3D_discreteHomogeneousSources.xml) - if(FFTW3F_FOUND) - add_test(testXML3D_kolmogorovBfield ${XML_EXECUTABLE} ${CMAKE_SOURCE_DIR}/test/xml/test3D_kolmogorovBfield.xml) - endif(FFTW3F_FOUND) - add_test(testXML3D_noBfield ${XML_EXECUTABLE} ${CMAKE_SOURCE_DIR}/test/xml/test3D_noBfield.xml) - add_test(testXML3D_uniformBfield ${XML_EXECUTABLE} ${CMAKE_SOURCE_DIR}/test/xml/test3D_uniformBfield.xml) - add_test(testXMLCRPropa2EventOutput1D ${XML_EXECUTABLE} ${CMAKE_SOURCE_DIR}/test/xml/testCRPropa2EventOutput1D.xml) - add_test(testXMLCRPropa2EventOutput3D ${XML_EXECUTABLE} ${CMAKE_SOURCE_DIR}/test/xml/testCRPropa2EventOutput3D.xml) - add_test(testXMLCRPropa2TrajectoryOutput1D ${XML_EXECUTABLE} ${CMAKE_SOURCE_DIR}/test/xml/testCRPropa2TrajectoryOutput1D.xml) - add_test(testXMLCRPropa2TrajectoryOutput3D ${XML_EXECUTABLE} ${CMAKE_SOURCE_DIR}/test/xml/testCRPropa2TrajectoryOutput3D.xml) - endif(ENABLE_TESTING) diff --git a/include/crpropa/XmlExecute.h b/include/crpropa/XmlExecute.h deleted file mode 100644 index 8e1823cb4..000000000 --- a/include/crpropa/XmlExecute.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef CRPROPA_XMLEXECUTE_H -#define CRPROPA_XMLEXECUTE_H - -#include "crpropa/ModuleList.h" -#include "crpropa/Source.h" -#include "crpropa/module/Observer.h" -#include "crpropa/magneticField/MagneticField.h" - -namespace pugi { -class xml_node; -} - -namespace crpropa { - -class XmlExecute { - void loadUniformMagneticField(pugi::xml_node &node); - void loadGridMagneticField(pugi::xml_node &node); - void loadDeflectionCK(pugi::xml_node &node); - void loadPeriodicBoundaries(); - void loadDiscreteSources(pugi::xml_node &node); - void loadContinuousSources(pugi::xml_node &node); - void loadSpectrumComposition(pugi::xml_node &node); - void loadSourceNuclei(pugi::xml_node &node); - void loadSophia(pugi::xml_node &node); - void loadSpheresAroundObserver(pugi::xml_node &node); - void loadSpheresAroundSource(pugi::xml_node &node); - void loadOutput(pugi::xml_node &node); - - ref_ptr magnetic_field; - ModuleList modules; - Source source; - ref_ptr observer; - bool is1D; - bool hasRedshift; - size_t nTrajectories; - double Emin; - double maxStep; - Vector3d origin; - Vector3d size; - -public: - XmlExecute(); - bool load(const std::string &filename); - void run(); -}; - -} // namespace crpropa - -#endif // CRPROPA_XMLEXECUTE_H diff --git a/libs/pugixml/CMakeLists.txt b/libs/pugixml/CMakeLists.txt deleted file mode 100644 index 0c4bf7634..000000000 --- a/libs/pugixml/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -cmake_minimum_required(VERSION 2.6) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) - -add_library(pugixml STATIC - pugixml -) - -SET_TARGET_PROPERTIES( pugixml PROPERTIES COMPILE_FLAGS -fPIC) diff --git a/libs/pugixml/README b/libs/pugixml/README deleted file mode 100644 index 380beb286..000000000 --- a/libs/pugixml/README +++ /dev/null @@ -1,3 +0,0 @@ -light-weight C++ XML processing library. -License: MIT -Reference: http://pugixml.org/ diff --git a/libs/pugixml/pugiconfig.hpp b/libs/pugixml/pugiconfig.hpp deleted file mode 100644 index 4c787125a..000000000 --- a/libs/pugixml/pugiconfig.hpp +++ /dev/null @@ -1,69 +0,0 @@ -/** - * pugixml parser - version 1.2 - * -------------------------------------------------------- - * Copyright (C) 2006-2012, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) - * Report bugs and download new versions at http://pugixml.org/ - * - * This library is distributed under the MIT License. See notice at the end - * of this file. - * - * This work is based on the pugxml parser, which is: - * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) - */ - -#ifndef HEADER_PUGICONFIG_HPP -#define HEADER_PUGICONFIG_HPP - -// Uncomment this to enable wchar_t mode -// #define PUGIXML_WCHAR_MODE - -// Uncomment this to disable XPath -// #define PUGIXML_NO_XPATH - -// Uncomment this to disable STL -// #define PUGIXML_NO_STL - -// Uncomment this to disable exceptions -// #define PUGIXML_NO_EXCEPTIONS - -// Set this to control attributes for public classes/functions, i.e.: -// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL -// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL -// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall -// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead - -// Uncomment this to switch to header-only version -// #define PUGIXML_HEADER_ONLY -// #include "pugixml.cpp" - -// Tune these constants to adjust memory-related behavior -// #define PUGIXML_MEMORY_PAGE_SIZE 32768 -// #define PUGIXML_MEMORY_OUTPUT_STACK 10240 -// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096 - -#endif - -/** - * Copyright (c) 2006-2012 Arseny Kapoulkine - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ diff --git a/libs/pugixml/pugixml.cpp b/libs/pugixml/pugixml.cpp deleted file mode 100644 index 642d92d38..000000000 --- a/libs/pugixml/pugixml.cpp +++ /dev/null @@ -1,10250 +0,0 @@ -/** - * pugixml parser - version 1.2 - * -------------------------------------------------------- - * Copyright (C) 2006-2012, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) - * Report bugs and download new versions at http://pugixml.org/ - * - * This library is distributed under the MIT License. See notice at the end - * of this file. - * - * This work is based on the pugxml parser, which is: - * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) - */ - -#ifndef SOURCE_PUGIXML_CPP -#define SOURCE_PUGIXML_CPP - -#include "pugixml.hpp" - -#include -#include -#include -#include -#include - -#ifndef PUGIXML_NO_XPATH -# include -# include -# ifdef PUGIXML_NO_EXCEPTIONS -# include -# endif -#endif - -#ifndef PUGIXML_NO_STL -# include -# include -# include -#endif - -// For placement new -#include - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4127) // conditional expression is constant -# pragma warning(disable: 4324) // structure was padded due to __declspec(align()) -# pragma warning(disable: 4611) // interaction between '_setjmp' and C++ object destruction is non-portable -# pragma warning(disable: 4702) // unreachable code -# pragma warning(disable: 4996) // this function or variable may be unsafe -# pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged -#endif - -#ifdef __INTEL_COMPILER -# pragma warning(disable: 177) // function was declared but never referenced -# pragma warning(disable: 279) // controlling expression is constant -# pragma warning(disable: 1478 1786) // function was declared "deprecated" -# pragma warning(disable: 1684) // conversion from pointer to same-sized integral type -#endif - -#if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY) -# pragma warn -8080 // symbol is declared but never used; disabling this inside push/pop bracket does not make the warning go away -#endif - -#ifdef __BORLANDC__ -# pragma option push -# pragma warn -8008 // condition is always false -# pragma warn -8066 // unreachable code -#endif - -#ifdef __SNC__ -// Using diag_push/diag_pop does not disable the warnings inside templates due to a compiler bug -# pragma diag_suppress=178 // function was declared but never referenced -# pragma diag_suppress=237 // controlling expression is constant -#endif - -// Inlining controls -#if defined(_MSC_VER) && _MSC_VER >= 1300 -# define PUGI__NO_INLINE __declspec(noinline) -#elif defined(__GNUC__) -# define PUGI__NO_INLINE __attribute__((noinline)) -#else -# define PUGI__NO_INLINE -#endif - -// Simple static assertion -#define PUGI__STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; } - -// Digital Mars C++ bug workaround for passing char loaded from memory via stack -#ifdef __DMC__ -# define PUGI__DMC_VOLATILE volatile -#else -# define PUGI__DMC_VOLATILE -#endif - -// Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy because some compilers don't have it at all) -#if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST) -using std::memcpy; -using std::memmove; -#endif - -// In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features -#if defined(_MSC_VER) && !defined(__S3E__) -# define PUGI__MSVC_CRT_VERSION _MSC_VER -#endif - -#ifdef PUGIXML_HEADER_ONLY -# define PUGI__NS_BEGIN namespace pugi { namespace impl { -# define PUGI__NS_END } } -# define PUGI__FN inline -# define PUGI__FN_NO_INLINE inline -#else -# if defined(_MSC_VER) && _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces -# define PUGI__NS_BEGIN namespace pugi { namespace impl { -# define PUGI__NS_END } } -# else -# define PUGI__NS_BEGIN namespace pugi { namespace impl { namespace { -# define PUGI__NS_END } } } -# endif -# define PUGI__FN -# define PUGI__FN_NO_INLINE PUGI__NO_INLINE -#endif - -// uintptr_t -#if !defined(_MSC_VER) || _MSC_VER >= 1600 -# include -#else -# ifndef _UINTPTR_T_DEFINED -// No native uintptr_t in MSVC6 and in some WinCE versions -typedef size_t uintptr_t; -#define _UINTPTR_T_DEFINED -# endif -PUGI__NS_BEGIN - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; -PUGI__NS_END -#endif - -// Memory allocation -PUGI__NS_BEGIN - PUGI__FN void* default_allocate(size_t size) - { - return malloc(size); - } - - PUGI__FN void default_deallocate(void* ptr) - { - free(ptr); - } - - template - struct xml_memory_management_function_storage - { - static allocation_function allocate; - static deallocation_function deallocate; - }; - - template allocation_function xml_memory_management_function_storage::allocate = default_allocate; - template deallocation_function xml_memory_management_function_storage::deallocate = default_deallocate; - - typedef xml_memory_management_function_storage xml_memory; -PUGI__NS_END - -// String utilities -PUGI__NS_BEGIN - // Get string length - PUGI__FN size_t strlength(const char_t* s) - { - assert(s); - - #ifdef PUGIXML_WCHAR_MODE - return wcslen(s); - #else - return strlen(s); - #endif - } - - // Compare two strings - PUGI__FN bool strequal(const char_t* src, const char_t* dst) - { - assert(src && dst); - - #ifdef PUGIXML_WCHAR_MODE - return wcscmp(src, dst) == 0; - #else - return strcmp(src, dst) == 0; - #endif - } - - // Compare lhs with [rhs_begin, rhs_end) - PUGI__FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count) - { - for (size_t i = 0; i < count; ++i) - if (lhs[i] != rhs[i]) - return false; - - return lhs[count] == 0; - } - -#ifdef PUGIXML_WCHAR_MODE - // Convert string to wide string, assuming all symbols are ASCII - PUGI__FN void widen_ascii(wchar_t* dest, const char* source) - { - for (const char* i = source; *i; ++i) *dest++ = *i; - *dest = 0; - } -#endif -PUGI__NS_END - -#if !defined(PUGIXML_NO_STL) || !defined(PUGIXML_NO_XPATH) -// auto_ptr-like buffer holder for exception recovery -PUGI__NS_BEGIN - struct buffer_holder - { - void* data; - void (*deleter)(void*); - - buffer_holder(void* data_, void (*deleter_)(void*)): data(data_), deleter(deleter_) - { - } - - ~buffer_holder() - { - if (data) deleter(data); - } - - void* release() - { - void* result = data; - data = 0; - return result; - } - }; -PUGI__NS_END -#endif - -PUGI__NS_BEGIN - static const size_t xml_memory_page_size = - #ifdef PUGIXML_MEMORY_PAGE_SIZE - PUGIXML_MEMORY_PAGE_SIZE - #else - 32768 - #endif - ; - - static const uintptr_t xml_memory_page_alignment = 32; - static const uintptr_t xml_memory_page_pointer_mask = ~(xml_memory_page_alignment - 1); - static const uintptr_t xml_memory_page_name_allocated_mask = 16; - static const uintptr_t xml_memory_page_value_allocated_mask = 8; - static const uintptr_t xml_memory_page_type_mask = 7; - - struct xml_allocator; - - struct xml_memory_page - { - static xml_memory_page* construct(void* memory) - { - if (!memory) return 0; //$ redundant, left for performance - - xml_memory_page* result = static_cast(memory); - - result->allocator = 0; - result->memory = 0; - result->prev = 0; - result->next = 0; - result->busy_size = 0; - result->freed_size = 0; - - return result; - } - - xml_allocator* allocator; - - void* memory; - - xml_memory_page* prev; - xml_memory_page* next; - - size_t busy_size; - size_t freed_size; - - char data[1]; - }; - - struct xml_memory_string_header - { - uint16_t page_offset; // offset from page->data - uint16_t full_size; // 0 if string occupies whole page - }; - - struct xml_allocator - { - xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size) - { - } - - xml_memory_page* allocate_page(size_t data_size) - { - size_t size = offsetof(xml_memory_page, data) + data_size; - - // allocate block with some alignment, leaving memory for worst-case padding - void* memory = xml_memory::allocate(size + xml_memory_page_alignment); - if (!memory) return 0; - - // align upwards to page boundary - void* page_memory = reinterpret_cast((reinterpret_cast(memory) + (xml_memory_page_alignment - 1)) & ~(xml_memory_page_alignment - 1)); - - // prepare page structure - xml_memory_page* page = xml_memory_page::construct(page_memory); - - page->memory = memory; - page->allocator = _root->allocator; - - return page; - } - - static void deallocate_page(xml_memory_page* page) - { - xml_memory::deallocate(page->memory); - } - - void* allocate_memory_oob(size_t size, xml_memory_page*& out_page); - - void* allocate_memory(size_t size, xml_memory_page*& out_page) - { - if (_busy_size + size > xml_memory_page_size) return allocate_memory_oob(size, out_page); - - void* buf = _root->data + _busy_size; - - _busy_size += size; - - out_page = _root; - - return buf; - } - - void deallocate_memory(void* ptr, size_t size, xml_memory_page* page) - { - if (page == _root) page->busy_size = _busy_size; - - assert(ptr >= page->data && ptr < page->data + page->busy_size); - (void)!ptr; - - page->freed_size += size; - assert(page->freed_size <= page->busy_size); - - if (page->freed_size == page->busy_size) - { - if (page->next == 0) - { - assert(_root == page); - - // top page freed, just reset sizes - page->busy_size = page->freed_size = 0; - _busy_size = 0; - } - else - { - assert(_root != page); - assert(page->prev); - - // remove from the list - page->prev->next = page->next; - page->next->prev = page->prev; - - // deallocate - deallocate_page(page); - } - } - } - - char_t* allocate_string(size_t length) - { - // allocate memory for string and header block - size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t); - - // round size up to pointer alignment boundary - size_t full_size = (size + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1); - - xml_memory_page* page; - xml_memory_string_header* header = static_cast(allocate_memory(full_size, page)); - - if (!header) return 0; - - // setup header - ptrdiff_t page_offset = reinterpret_cast(header) - page->data; - - assert(page_offset >= 0 && page_offset < (1 << 16)); - header->page_offset = static_cast(page_offset); - - // full_size == 0 for large strings that occupy the whole page - assert(full_size < (1 << 16) || (page->busy_size == full_size && page_offset == 0)); - header->full_size = static_cast(full_size < (1 << 16) ? full_size : 0); - - // round-trip through void* to avoid 'cast increases required alignment of target type' warning - // header is guaranteed a pointer-sized alignment, which should be enough for char_t - return static_cast(static_cast(header + 1)); - } - - void deallocate_string(char_t* string) - { - // this function casts pointers through void* to avoid 'cast increases required alignment of target type' warnings - // we're guaranteed the proper (pointer-sized) alignment on the input string if it was allocated via allocate_string - - // get header - xml_memory_string_header* header = static_cast(static_cast(string)) - 1; - - // deallocate - size_t page_offset = offsetof(xml_memory_page, data) + header->page_offset; - xml_memory_page* page = reinterpret_cast(static_cast(reinterpret_cast(header) - page_offset)); - - // if full_size == 0 then this string occupies the whole page - size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size; - - deallocate_memory(header, full_size, page); - } - - xml_memory_page* _root; - size_t _busy_size; - }; - - PUGI__FN_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page) - { - const size_t large_allocation_threshold = xml_memory_page_size / 4; - - xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size); - out_page = page; - - if (!page) return 0; - - if (size <= large_allocation_threshold) - { - _root->busy_size = _busy_size; - - // insert page at the end of linked list - page->prev = _root; - _root->next = page; - _root = page; - - _busy_size = size; - } - else - { - // insert page before the end of linked list, so that it is deleted as soon as possible - // the last page is not deleted even if it's empty (see deallocate_memory) - assert(_root->prev); - - page->prev = _root->prev; - page->next = _root; - - _root->prev->next = page; - _root->prev = page; - } - - // allocate inside page - page->busy_size = size; - - return page->data; - } -PUGI__NS_END - -namespace pugi -{ - /// A 'name=value' XML attribute structure. - struct xml_attribute_struct - { - /// Default ctor - xml_attribute_struct(impl::xml_memory_page* page): header(reinterpret_cast(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0) - { - } - - uintptr_t header; - - char_t* name; ///< Pointer to attribute name. - char_t* value; ///< Pointer to attribute value. - - xml_attribute_struct* prev_attribute_c; ///< Previous attribute (cyclic list) - xml_attribute_struct* next_attribute; ///< Next attribute - }; - - /// An XML document tree node. - struct xml_node_struct - { - /// Default ctor - /// \param type - node type - xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(reinterpret_cast(page) | (type - 1)), parent(0), name(0), value(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0) - { - } - - uintptr_t header; - - xml_node_struct* parent; ///< Pointer to parent - - char_t* name; ///< Pointer to element name. - char_t* value; ///< Pointer to any associated string data. - - xml_node_struct* first_child; ///< First child - - xml_node_struct* prev_sibling_c; ///< Left brother (cyclic list) - xml_node_struct* next_sibling; ///< Right brother - - xml_attribute_struct* first_attribute; ///< First attribute - }; -} - -PUGI__NS_BEGIN - struct xml_document_struct: public xml_node_struct, public xml_allocator - { - xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0) - { - } - - const char_t* buffer; - }; - - inline xml_allocator& get_allocator(const xml_node_struct* node) - { - assert(node); - - return *reinterpret_cast(node->header & xml_memory_page_pointer_mask)->allocator; - } -PUGI__NS_END - -// Low-level DOM operations -PUGI__NS_BEGIN - inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc) - { - xml_memory_page* page; - void* memory = alloc.allocate_memory(sizeof(xml_attribute_struct), page); - - return new (memory) xml_attribute_struct(page); - } - - inline xml_node_struct* allocate_node(xml_allocator& alloc, xml_node_type type) - { - xml_memory_page* page; - void* memory = alloc.allocate_memory(sizeof(xml_node_struct), page); - - return new (memory) xml_node_struct(page, type); - } - - inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc) - { - uintptr_t header = a->header; - - if (header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(a->name); - if (header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(a->value); - - alloc.deallocate_memory(a, sizeof(xml_attribute_struct), reinterpret_cast(header & xml_memory_page_pointer_mask)); - } - - inline void destroy_node(xml_node_struct* n, xml_allocator& alloc) - { - uintptr_t header = n->header; - - if (header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(n->name); - if (header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(n->value); - - for (xml_attribute_struct* attr = n->first_attribute; attr; ) - { - xml_attribute_struct* next = attr->next_attribute; - - destroy_attribute(attr, alloc); - - attr = next; - } - - for (xml_node_struct* child = n->first_child; child; ) - { - xml_node_struct* next = child->next_sibling; - - destroy_node(child, alloc); - - child = next; - } - - alloc.deallocate_memory(n, sizeof(xml_node_struct), reinterpret_cast(header & xml_memory_page_pointer_mask)); - } - - PUGI__FN_NO_INLINE xml_node_struct* append_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element) - { - xml_node_struct* child = allocate_node(alloc, type); - if (!child) return 0; - - child->parent = node; - - xml_node_struct* first_child = node->first_child; - - if (first_child) - { - xml_node_struct* last_child = first_child->prev_sibling_c; - - last_child->next_sibling = child; - child->prev_sibling_c = last_child; - first_child->prev_sibling_c = child; - } - else - { - node->first_child = child; - child->prev_sibling_c = child; - } - - return child; - } - - PUGI__FN_NO_INLINE xml_attribute_struct* append_attribute_ll(xml_node_struct* node, xml_allocator& alloc) - { - xml_attribute_struct* a = allocate_attribute(alloc); - if (!a) return 0; - - xml_attribute_struct* first_attribute = node->first_attribute; - - if (first_attribute) - { - xml_attribute_struct* last_attribute = first_attribute->prev_attribute_c; - - last_attribute->next_attribute = a; - a->prev_attribute_c = last_attribute; - first_attribute->prev_attribute_c = a; - } - else - { - node->first_attribute = a; - a->prev_attribute_c = a; - } - - return a; - } -PUGI__NS_END - -// Helper classes for code generation -PUGI__NS_BEGIN - struct opt_false - { - enum { value = 0 }; - }; - - struct opt_true - { - enum { value = 1 }; - }; -PUGI__NS_END - -// Unicode utilities -PUGI__NS_BEGIN - inline uint16_t endian_swap(uint16_t value) - { - return static_cast(((value & 0xff) << 8) | (value >> 8)); - } - - inline uint32_t endian_swap(uint32_t value) - { - return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24); - } - - struct utf8_counter - { - typedef size_t value_type; - - static value_type low(value_type result, uint32_t ch) - { - // U+0000..U+007F - if (ch < 0x80) return result + 1; - // U+0080..U+07FF - else if (ch < 0x800) return result + 2; - // U+0800..U+FFFF - else return result + 3; - } - - static value_type high(value_type result, uint32_t) - { - // U+10000..U+10FFFF - return result + 4; - } - }; - - struct utf8_writer - { - typedef uint8_t* value_type; - - static value_type low(value_type result, uint32_t ch) - { - // U+0000..U+007F - if (ch < 0x80) - { - *result = static_cast(ch); - return result + 1; - } - // U+0080..U+07FF - else if (ch < 0x800) - { - result[0] = static_cast(0xC0 | (ch >> 6)); - result[1] = static_cast(0x80 | (ch & 0x3F)); - return result + 2; - } - // U+0800..U+FFFF - else - { - result[0] = static_cast(0xE0 | (ch >> 12)); - result[1] = static_cast(0x80 | ((ch >> 6) & 0x3F)); - result[2] = static_cast(0x80 | (ch & 0x3F)); - return result + 3; - } - } - - static value_type high(value_type result, uint32_t ch) - { - // U+10000..U+10FFFF - result[0] = static_cast(0xF0 | (ch >> 18)); - result[1] = static_cast(0x80 | ((ch >> 12) & 0x3F)); - result[2] = static_cast(0x80 | ((ch >> 6) & 0x3F)); - result[3] = static_cast(0x80 | (ch & 0x3F)); - return result + 4; - } - - static value_type any(value_type result, uint32_t ch) - { - return (ch < 0x10000) ? low(result, ch) : high(result, ch); - } - }; - - struct utf16_counter - { - typedef size_t value_type; - - static value_type low(value_type result, uint32_t) - { - return result + 1; - } - - static value_type high(value_type result, uint32_t) - { - return result + 2; - } - }; - - struct utf16_writer - { - typedef uint16_t* value_type; - - static value_type low(value_type result, uint32_t ch) - { - *result = static_cast(ch); - - return result + 1; - } - - static value_type high(value_type result, uint32_t ch) - { - uint32_t msh = static_cast(ch - 0x10000) >> 10; - uint32_t lsh = static_cast(ch - 0x10000) & 0x3ff; - - result[0] = static_cast(0xD800 + msh); - result[1] = static_cast(0xDC00 + lsh); - - return result + 2; - } - - static value_type any(value_type result, uint32_t ch) - { - return (ch < 0x10000) ? low(result, ch) : high(result, ch); - } - }; - - struct utf32_counter - { - typedef size_t value_type; - - static value_type low(value_type result, uint32_t) - { - return result + 1; - } - - static value_type high(value_type result, uint32_t) - { - return result + 1; - } - }; - - struct utf32_writer - { - typedef uint32_t* value_type; - - static value_type low(value_type result, uint32_t ch) - { - *result = ch; - - return result + 1; - } - - static value_type high(value_type result, uint32_t ch) - { - *result = ch; - - return result + 1; - } - - static value_type any(value_type result, uint32_t ch) - { - *result = ch; - - return result + 1; - } - }; - - struct latin1_writer - { - typedef uint8_t* value_type; - - static value_type low(value_type result, uint32_t ch) - { - *result = static_cast(ch > 255 ? '?' : ch); - - return result + 1; - } - - static value_type high(value_type result, uint32_t ch) - { - (void)ch; - - *result = '?'; - - return result + 1; - } - }; - - template struct wchar_selector; - - template <> struct wchar_selector<2> - { - typedef uint16_t type; - typedef utf16_counter counter; - typedef utf16_writer writer; - }; - - template <> struct wchar_selector<4> - { - typedef uint32_t type; - typedef utf32_counter counter; - typedef utf32_writer writer; - }; - - typedef wchar_selector::counter wchar_counter; - typedef wchar_selector::writer wchar_writer; - - template struct utf_decoder - { - static inline typename Traits::value_type decode_utf8_block(const uint8_t* data, size_t size, typename Traits::value_type result) - { - const uint8_t utf8_byte_mask = 0x3f; - - while (size) - { - uint8_t lead = *data; - - // 0xxxxxxx -> U+0000..U+007F - if (lead < 0x80) - { - result = Traits::low(result, lead); - data += 1; - size -= 1; - - // process aligned single-byte (ascii) blocks - if ((reinterpret_cast(data) & 3) == 0) - { - // round-trip through void* to silence 'cast increases required alignment of target type' warnings - while (size >= 4 && (*static_cast(static_cast(data)) & 0x80808080) == 0) - { - result = Traits::low(result, data[0]); - result = Traits::low(result, data[1]); - result = Traits::low(result, data[2]); - result = Traits::low(result, data[3]); - data += 4; - size -= 4; - } - } - } - // 110xxxxx -> U+0080..U+07FF - else if (static_cast(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80) - { - result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask)); - data += 2; - size -= 2; - } - // 1110xxxx -> U+0800-U+FFFF - else if (static_cast(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80) - { - result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask)); - data += 3; - size -= 3; - } - // 11110xxx -> U+10000..U+10FFFF - else if (static_cast(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80) - { - result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask)); - data += 4; - size -= 4; - } - // 10xxxxxx or 11111xxx -> invalid - else - { - data += 1; - size -= 1; - } - } - - return result; - } - - static inline typename Traits::value_type decode_utf16_block(const uint16_t* data, size_t size, typename Traits::value_type result) - { - const uint16_t* end = data + size; - - while (data < end) - { - uint16_t lead = opt_swap::value ? endian_swap(*data) : *data; - - // U+0000..U+D7FF - if (lead < 0xD800) - { - result = Traits::low(result, lead); - data += 1; - } - // U+E000..U+FFFF - else if (static_cast(lead - 0xE000) < 0x2000) - { - result = Traits::low(result, lead); - data += 1; - } - // surrogate pair lead - else if (static_cast(lead - 0xD800) < 0x400 && data + 1 < end) - { - uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1]; - - if (static_cast(next - 0xDC00) < 0x400) - { - result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff)); - data += 2; - } - else - { - data += 1; - } - } - else - { - data += 1; - } - } - - return result; - } - - static inline typename Traits::value_type decode_utf32_block(const uint32_t* data, size_t size, typename Traits::value_type result) - { - const uint32_t* end = data + size; - - while (data < end) - { - uint32_t lead = opt_swap::value ? endian_swap(*data) : *data; - - // U+0000..U+FFFF - if (lead < 0x10000) - { - result = Traits::low(result, lead); - data += 1; - } - // U+10000..U+10FFFF - else - { - result = Traits::high(result, lead); - data += 1; - } - } - - return result; - } - - static inline typename Traits::value_type decode_latin1_block(const uint8_t* data, size_t size, typename Traits::value_type result) - { - for (size_t i = 0; i < size; ++i) - { - result = Traits::low(result, data[i]); - } - - return result; - } - - static inline typename Traits::value_type decode_wchar_block_impl(const uint16_t* data, size_t size, typename Traits::value_type result) - { - return decode_utf16_block(data, size, result); - } - - static inline typename Traits::value_type decode_wchar_block_impl(const uint32_t* data, size_t size, typename Traits::value_type result) - { - return decode_utf32_block(data, size, result); - } - - static inline typename Traits::value_type decode_wchar_block(const wchar_t* data, size_t size, typename Traits::value_type result) - { - return decode_wchar_block_impl(reinterpret_cast::type*>(data), size, result); - } - }; - - template PUGI__FN void convert_utf_endian_swap(T* result, const T* data, size_t length) - { - for (size_t i = 0; i < length; ++i) result[i] = endian_swap(data[i]); - } - -#ifdef PUGIXML_WCHAR_MODE - PUGI__FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length) - { - for (size_t i = 0; i < length; ++i) result[i] = static_cast(endian_swap(static_cast::type>(data[i]))); - } -#endif -PUGI__NS_END - -PUGI__NS_BEGIN - enum chartype_t - { - ct_parse_pcdata = 1, // \0, &, \r, < - ct_parse_attr = 2, // \0, &, \r, ', " - ct_parse_attr_ws = 4, // \0, &, \r, ', ", \n, tab - ct_space = 8, // \r, \n, space, tab - ct_parse_cdata = 16, // \0, ], >, \r - ct_parse_comment = 32, // \0, -, >, \r - ct_symbol = 64, // Any symbol > 127, a-z, A-Z, 0-9, _, :, -, . - ct_start_symbol = 128 // Any symbol > 127, a-z, A-Z, _, : - }; - - static const unsigned char chartype_table[256] = - { - 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0, // 0-15 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31 - 8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0, // 32-47 - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0, // 48-63 - 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 64-79 - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192, // 80-95 - 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 96-111 - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0, // 112-127 - - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 128+ - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192 - }; - - enum chartypex_t - { - ctx_special_pcdata = 1, // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, > - ctx_special_attr = 2, // Any symbol >= 0 and < 32 (except \t), &, <, >, " - ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _ - ctx_digit = 8, // 0-9 - ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, . - }; - - static const unsigned char chartypex_table[256] = - { - 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3, // 0-15 - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31 - 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 16, 16, 0, // 32-47 - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 3, 0, // 48-63 - - 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 64-79 - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 20, // 80-95 - 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 96-111 - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, // 112-127 - - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 128+ - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 - }; - -#ifdef PUGIXML_WCHAR_MODE - #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast(c) < 128 ? table[static_cast(c)] : table[128]) & (ct)) -#else - #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast(c)] & (ct)) -#endif - - #define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table) - #define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table) - - PUGI__FN bool is_little_endian() - { - unsigned int ui = 1; - - return *reinterpret_cast(&ui) == 1; - } - - PUGI__FN xml_encoding get_wchar_encoding() - { - PUGI__STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); - - if (sizeof(wchar_t) == 2) - return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - else - return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - } - - PUGI__FN xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) - { - // look for BOM in first few bytes - if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be; - if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le; - if (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be; - if (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le; - if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf) return encoding_utf8; - - // look for <, (contents); - - PUGI__DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3]; - - return guess_buffer_encoding(d0, d1, d2, d3); - } - - PUGI__FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) - { - if (is_mutable) - { - out_buffer = static_cast(const_cast(contents)); - } - else - { - void* buffer = xml_memory::allocate(size > 0 ? size : 1); - if (!buffer) return false; - - memcpy(buffer, contents, size); - - out_buffer = static_cast(buffer); - } - - out_length = size / sizeof(char_t); - - return true; - } - -#ifdef PUGIXML_WCHAR_MODE - PUGI__FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re) - { - return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) || - (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be); - } - - PUGI__FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) - { - const char_t* data = static_cast(contents); - - if (is_mutable) - { - out_buffer = const_cast(data); - } - else - { - out_buffer = static_cast(xml_memory::allocate(size > 0 ? size : 1)); - if (!out_buffer) return false; - } - - out_length = size / sizeof(char_t); - - convert_wchar_endian_swap(out_buffer, data, out_length); - - return true; - } - - PUGI__FN bool convert_buffer_utf8(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size) - { - const uint8_t* data = static_cast(contents); - - // first pass: get length in wchar_t units - out_length = utf_decoder::decode_utf8_block(data, size, 0); - - // allocate buffer of suitable length - out_buffer = static_cast(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); - if (!out_buffer) return false; - - // second pass: convert utf8 input to wchar_t - wchar_writer::value_type out_begin = reinterpret_cast(out_buffer); - wchar_writer::value_type out_end = utf_decoder::decode_utf8_block(data, size, out_begin); - - assert(out_end == out_begin + out_length); - (void)!out_end; - - return true; - } - - template PUGI__FN bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) - { - const uint16_t* data = static_cast(contents); - size_t length = size / sizeof(uint16_t); - - // first pass: get length in wchar_t units - out_length = utf_decoder::decode_utf16_block(data, length, 0); - - // allocate buffer of suitable length - out_buffer = static_cast(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); - if (!out_buffer) return false; - - // second pass: convert utf16 input to wchar_t - wchar_writer::value_type out_begin = reinterpret_cast(out_buffer); - wchar_writer::value_type out_end = utf_decoder::decode_utf16_block(data, length, out_begin); - - assert(out_end == out_begin + out_length); - (void)!out_end; - - return true; - } - - template PUGI__FN bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) - { - const uint32_t* data = static_cast(contents); - size_t length = size / sizeof(uint32_t); - - // first pass: get length in wchar_t units - out_length = utf_decoder::decode_utf32_block(data, length, 0); - - // allocate buffer of suitable length - out_buffer = static_cast(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); - if (!out_buffer) return false; - - // second pass: convert utf32 input to wchar_t - wchar_writer::value_type out_begin = reinterpret_cast(out_buffer); - wchar_writer::value_type out_end = utf_decoder::decode_utf32_block(data, length, out_begin); - - assert(out_end == out_begin + out_length); - (void)!out_end; - - return true; - } - - PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size) - { - const uint8_t* data = static_cast(contents); - - // get length in wchar_t units - out_length = size; - - // allocate buffer of suitable length - out_buffer = static_cast(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); - if (!out_buffer) return false; - - // convert latin1 input to wchar_t - wchar_writer::value_type out_begin = reinterpret_cast(out_buffer); - wchar_writer::value_type out_end = utf_decoder::decode_latin1_block(data, size, out_begin); - - assert(out_end == out_begin + out_length); - (void)!out_end; - - return true; - } - - PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) - { - // get native encoding - xml_encoding wchar_encoding = get_wchar_encoding(); - - // fast path: no conversion required - if (encoding == wchar_encoding) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); - - // only endian-swapping is required - if (need_endian_swap_utf(encoding, wchar_encoding)) return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable); - - // source encoding is utf8 - if (encoding == encoding_utf8) return convert_buffer_utf8(out_buffer, out_length, contents, size); - - // source encoding is utf16 - if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) - { - xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - - return (native_encoding == encoding) ? - convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) : - convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true()); - } - - // source encoding is utf32 - if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) - { - xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - - return (native_encoding == encoding) ? - convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : - convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); - } - - // source encoding is latin1 - if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size); - - assert(!"Invalid encoding"); - return false; - } -#else - template PUGI__FN bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) - { - const uint16_t* data = static_cast(contents); - size_t length = size / sizeof(uint16_t); - - // first pass: get length in utf8 units - out_length = utf_decoder::decode_utf16_block(data, length, 0); - - // allocate buffer of suitable length - out_buffer = static_cast(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); - if (!out_buffer) return false; - - // second pass: convert utf16 input to utf8 - uint8_t* out_begin = reinterpret_cast(out_buffer); - uint8_t* out_end = utf_decoder::decode_utf16_block(data, length, out_begin); - - assert(out_end == out_begin + out_length); - (void)!out_end; - - return true; - } - - template PUGI__FN bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) - { - const uint32_t* data = static_cast(contents); - size_t length = size / sizeof(uint32_t); - - // first pass: get length in utf8 units - out_length = utf_decoder::decode_utf32_block(data, length, 0); - - // allocate buffer of suitable length - out_buffer = static_cast(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); - if (!out_buffer) return false; - - // second pass: convert utf32 input to utf8 - uint8_t* out_begin = reinterpret_cast(out_buffer); - uint8_t* out_end = utf_decoder::decode_utf32_block(data, length, out_begin); - - assert(out_end == out_begin + out_length); - (void)!out_end; - - return true; - } - - PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size) - { - for (size_t i = 0; i < size; ++i) - if (data[i] > 127) - return i; - - return size; - } - - PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) - { - const uint8_t* data = static_cast(contents); - - // get size of prefix that does not need utf8 conversion - size_t prefix_length = get_latin1_7bit_prefix_length(data, size); - assert(prefix_length <= size); - - const uint8_t* postfix = data + prefix_length; - size_t postfix_length = size - prefix_length; - - // if no conversion is needed, just return the original buffer - if (postfix_length == 0) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); - - // first pass: get length in utf8 units - out_length = prefix_length + utf_decoder::decode_latin1_block(postfix, postfix_length, 0); - - // allocate buffer of suitable length - out_buffer = static_cast(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); - if (!out_buffer) return false; - - // second pass: convert latin1 input to utf8 - memcpy(out_buffer, data, prefix_length); - - uint8_t* out_begin = reinterpret_cast(out_buffer); - uint8_t* out_end = utf_decoder::decode_latin1_block(postfix, postfix_length, out_begin + prefix_length); - - assert(out_end == out_begin + out_length); - (void)!out_end; - - return true; - } - - PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) - { - // fast path: no conversion required - if (encoding == encoding_utf8) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); - - // source encoding is utf16 - if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) - { - xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - - return (native_encoding == encoding) ? - convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) : - convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true()); - } - - // source encoding is utf32 - if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) - { - xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - - return (native_encoding == encoding) ? - convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : - convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); - } - - // source encoding is latin1 - if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable); - - assert(!"Invalid encoding"); - return false; - } -#endif - - PUGI__FN size_t as_utf8_begin(const wchar_t* str, size_t length) - { - // get length in utf8 characters - return utf_decoder::decode_wchar_block(str, length, 0); - } - - PUGI__FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length) - { - // convert to utf8 - uint8_t* begin = reinterpret_cast(buffer); - uint8_t* end = utf_decoder::decode_wchar_block(str, length, begin); - - assert(begin + size == end); - (void)!end; - - // zero-terminate - buffer[size] = 0; - } - -#ifndef PUGIXML_NO_STL - PUGI__FN std::string as_utf8_impl(const wchar_t* str, size_t length) - { - // first pass: get length in utf8 characters - size_t size = as_utf8_begin(str, length); - - // allocate resulting string - std::string result; - result.resize(size); - - // second pass: convert to utf8 - if (size > 0) as_utf8_end(&result[0], size, str, length); - - return result; - } - - PUGI__FN std::basic_string as_wide_impl(const char* str, size_t size) - { - const uint8_t* data = reinterpret_cast(str); - - // first pass: get length in wchar_t units - size_t length = utf_decoder::decode_utf8_block(data, size, 0); - - // allocate resulting string - std::basic_string result; - result.resize(length); - - // second pass: convert to wchar_t - if (length > 0) - { - wchar_writer::value_type begin = reinterpret_cast(&result[0]); - wchar_writer::value_type end = utf_decoder::decode_utf8_block(data, size, begin); - - assert(begin + length == end); - (void)!end; - } - - return result; - } -#endif - - inline bool strcpy_insitu_allow(size_t length, uintptr_t allocated, char_t* target) - { - assert(target); - size_t target_length = strlength(target); - - // always reuse document buffer memory if possible - if (!allocated) return target_length >= length; - - // reuse heap memory if waste is not too great - const size_t reuse_threshold = 32; - - return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2); - } - - PUGI__FN bool strcpy_insitu(char_t*& dest, uintptr_t& header, uintptr_t header_mask, const char_t* source) - { - size_t source_length = strlength(source); - - if (source_length == 0) - { - // empty string and null pointer are equivalent, so just deallocate old memory - xml_allocator* alloc = reinterpret_cast(header & xml_memory_page_pointer_mask)->allocator; - - if (header & header_mask) alloc->deallocate_string(dest); - - // mark the string as not allocated - dest = 0; - header &= ~header_mask; - - return true; - } - else if (dest && strcpy_insitu_allow(source_length, header & header_mask, dest)) - { - // we can reuse old buffer, so just copy the new data (including zero terminator) - memcpy(dest, source, (source_length + 1) * sizeof(char_t)); - - return true; - } - else - { - xml_allocator* alloc = reinterpret_cast(header & xml_memory_page_pointer_mask)->allocator; - - // allocate new buffer - char_t* buf = alloc->allocate_string(source_length + 1); - if (!buf) return false; - - // copy the string (including zero terminator) - memcpy(buf, source, (source_length + 1) * sizeof(char_t)); - - // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures) - if (header & header_mask) alloc->deallocate_string(dest); - - // the string is now allocated, so set the flag - dest = buf; - header |= header_mask; - - return true; - } - } - - struct gap - { - char_t* end; - size_t size; - - gap(): end(0), size(0) - { - } - - // Push new gap, move s count bytes further (skipping the gap). - // Collapse previous gap. - void push(char_t*& s, size_t count) - { - if (end) // there was a gap already; collapse it - { - // Move [old_gap_end, new_gap_start) to [old_gap_start, ...) - assert(s >= end); - memmove(end - size, end, reinterpret_cast(s) - reinterpret_cast(end)); - } - - s += count; // end of current gap - - // "merge" two gaps - end = s; - size += count; - } - - // Collapse all gaps, return past-the-end pointer - char_t* flush(char_t* s) - { - if (end) - { - // Move [old_gap_end, current_pos) to [old_gap_start, ...) - assert(s >= end); - memmove(end - size, end, reinterpret_cast(s) - reinterpret_cast(end)); - - return s - size; - } - else return s; - } - }; - - PUGI__FN char_t* strconv_escape(char_t* s, gap& g) - { - char_t* stre = s + 1; - - switch (*stre) - { - case '#': // &#... - { - unsigned int ucsc = 0; - - if (stre[1] == 'x') // &#x... (hex code) - { - stre += 2; - - char_t ch = *stre; - - if (ch == ';') return stre; - - for (;;) - { - if (static_cast(ch - '0') <= 9) - ucsc = 16 * ucsc + (ch - '0'); - else if (static_cast((ch | ' ') - 'a') <= 5) - ucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10); - else if (ch == ';') - break; - else // cancel - return stre; - - ch = *++stre; - } - - ++stre; - } - else // &#... (dec code) - { - char_t ch = *++stre; - - if (ch == ';') return stre; - - for (;;) - { - if (static_cast(ch - '0') <= 9) - ucsc = 10 * ucsc + (ch - '0'); - else if (ch == ';') - break; - else // cancel - return stre; - - ch = *++stre; - } - - ++stre; - } - - #ifdef PUGIXML_WCHAR_MODE - s = reinterpret_cast(wchar_writer::any(reinterpret_cast(s), ucsc)); - #else - s = reinterpret_cast(utf8_writer::any(reinterpret_cast(s), ucsc)); - #endif - - g.push(s, stre - s); - return stre; - } - - case 'a': // &a - { - ++stre; - - if (*stre == 'm') // &am - { - if (*++stre == 'p' && *++stre == ';') // & - { - *s++ = '&'; - ++stre; - - g.push(s, stre - s); - return stre; - } - } - else if (*stre == 'p') // &ap - { - if (*++stre == 'o' && *++stre == 's' && *++stre == ';') // ' - { - *s++ = '\''; - ++stre; - - g.push(s, stre - s); - return stre; - } - } - break; - } - - case 'g': // &g - { - if (*++stre == 't' && *++stre == ';') // > - { - *s++ = '>'; - ++stre; - - g.push(s, stre - s); - return stre; - } - break; - } - - case 'l': // &l - { - if (*++stre == 't' && *++stre == ';') // < - { - *s++ = '<'; - ++stre; - - g.push(s, stre - s); - return stre; - } - break; - } - - case 'q': // &q - { - if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // " - { - *s++ = '"'; - ++stre; - - g.push(s, stre - s); - return stre; - } - break; - } - - default: - break; - } - - return stre; - } - - // Utility macro for last character handling - #define ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e))) - - PUGI__FN char_t* strconv_comment(char_t* s, char_t endch) - { - gap g; - - while (true) - { - while (!PUGI__IS_CHARTYPE(*s, ct_parse_comment)) ++s; - - if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair - { - *s++ = '\n'; // replace first one with 0x0a - - if (*s == '\n') g.push(s, 1); - } - else if (s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')) // comment ends here - { - *g.flush(s) = 0; - - return s + (s[2] == '>' ? 3 : 2); - } - else if (*s == 0) - { - return 0; - } - else ++s; - } - } - - PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch) - { - gap g; - - while (true) - { - while (!PUGI__IS_CHARTYPE(*s, ct_parse_cdata)) ++s; - - if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair - { - *s++ = '\n'; // replace first one with 0x0a - - if (*s == '\n') g.push(s, 1); - } - else if (s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')) // CDATA ends here - { - *g.flush(s) = 0; - - return s + 1; - } - else if (*s == 0) - { - return 0; - } - else ++s; - } - } - - typedef char_t* (*strconv_pcdata_t)(char_t*); - - template struct strconv_pcdata_impl - { - static char_t* parse(char_t* s) - { - gap g; - - while (true) - { - while (!PUGI__IS_CHARTYPE(*s, ct_parse_pcdata)) ++s; - - if (*s == '<') // PCDATA ends here - { - *g.flush(s) = 0; - - return s + 1; - } - else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair - { - *s++ = '\n'; // replace first one with 0x0a - - if (*s == '\n') g.push(s, 1); - } - else if (opt_escape::value && *s == '&') - { - s = strconv_escape(s, g); - } - else if (*s == 0) - { - return s; - } - else ++s; - } - } - }; - - PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask) - { - PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20); - - switch ((optmask >> 4) & 3) // get bitmask for flags (eol escapes) - { - case 0: return strconv_pcdata_impl::parse; - case 1: return strconv_pcdata_impl::parse; - case 2: return strconv_pcdata_impl::parse; - case 3: return strconv_pcdata_impl::parse; - default: return 0; // should not get here - } - } - - typedef char_t* (*strconv_attribute_t)(char_t*, char_t); - - template struct strconv_attribute_impl - { - static char_t* parse_wnorm(char_t* s, char_t end_quote) - { - gap g; - - // trim leading whitespaces - if (PUGI__IS_CHARTYPE(*s, ct_space)) - { - char_t* str = s; - - do ++str; - while (PUGI__IS_CHARTYPE(*str, ct_space)); - - g.push(s, str - s); - } - - while (true) - { - while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr_ws | ct_space)) ++s; - - if (*s == end_quote) - { - char_t* str = g.flush(s); - - do *str-- = 0; - while (PUGI__IS_CHARTYPE(*str, ct_space)); - - return s + 1; - } - else if (PUGI__IS_CHARTYPE(*s, ct_space)) - { - *s++ = ' '; - - if (PUGI__IS_CHARTYPE(*s, ct_space)) - { - char_t* str = s + 1; - while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str; - - g.push(s, str - s); - } - } - else if (opt_escape::value && *s == '&') - { - s = strconv_escape(s, g); - } - else if (!*s) - { - return 0; - } - else ++s; - } - } - - static char_t* parse_wconv(char_t* s, char_t end_quote) - { - gap g; - - while (true) - { - while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr_ws)) ++s; - - if (*s == end_quote) - { - *g.flush(s) = 0; - - return s + 1; - } - else if (PUGI__IS_CHARTYPE(*s, ct_space)) - { - if (*s == '\r') - { - *s++ = ' '; - - if (*s == '\n') g.push(s, 1); - } - else *s++ = ' '; - } - else if (opt_escape::value && *s == '&') - { - s = strconv_escape(s, g); - } - else if (!*s) - { - return 0; - } - else ++s; - } - } - - static char_t* parse_eol(char_t* s, char_t end_quote) - { - gap g; - - while (true) - { - while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr)) ++s; - - if (*s == end_quote) - { - *g.flush(s) = 0; - - return s + 1; - } - else if (*s == '\r') - { - *s++ = '\n'; - - if (*s == '\n') g.push(s, 1); - } - else if (opt_escape::value && *s == '&') - { - s = strconv_escape(s, g); - } - else if (!*s) - { - return 0; - } - else ++s; - } - } - - static char_t* parse_simple(char_t* s, char_t end_quote) - { - gap g; - - while (true) - { - while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr)) ++s; - - if (*s == end_quote) - { - *g.flush(s) = 0; - - return s + 1; - } - else if (opt_escape::value && *s == '&') - { - s = strconv_escape(s, g); - } - else if (!*s) - { - return 0; - } - else ++s; - } - } - }; - - PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask) - { - PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80); - - switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes) - { - case 0: return strconv_attribute_impl::parse_simple; - case 1: return strconv_attribute_impl::parse_simple; - case 2: return strconv_attribute_impl::parse_eol; - case 3: return strconv_attribute_impl::parse_eol; - case 4: return strconv_attribute_impl::parse_wconv; - case 5: return strconv_attribute_impl::parse_wconv; - case 6: return strconv_attribute_impl::parse_wconv; - case 7: return strconv_attribute_impl::parse_wconv; - case 8: return strconv_attribute_impl::parse_wnorm; - case 9: return strconv_attribute_impl::parse_wnorm; - case 10: return strconv_attribute_impl::parse_wnorm; - case 11: return strconv_attribute_impl::parse_wnorm; - case 12: return strconv_attribute_impl::parse_wnorm; - case 13: return strconv_attribute_impl::parse_wnorm; - case 14: return strconv_attribute_impl::parse_wnorm; - case 15: return strconv_attribute_impl::parse_wnorm; - default: return 0; // should not get here - } - } - - inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0) - { - xml_parse_result result; - result.status = status; - result.offset = offset; - - return result; - } - - struct xml_parser - { - xml_allocator alloc; - char_t* error_offset; - xml_parse_status error_status; - - // Parser utilities. - #define PUGI__SKIPWS() { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; } - #define PUGI__OPTSET(OPT) ( optmsk & (OPT) ) - #define PUGI__PUSHNODE(TYPE) { cursor = append_node(cursor, alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); } - #define PUGI__POPNODE() { cursor = cursor->parent; } - #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; } - #define PUGI__SCANWHILE(X) { while ((X)) ++s; } - #define PUGI__ENDSEG() { ch = *s; *s = 0; ++s; } - #define PUGI__THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast(0) - #define PUGI__CHECK_ERROR(err, m) { if (*s == 0) PUGI__THROW_ERROR(err, m); } - - xml_parser(const xml_allocator& alloc_): alloc(alloc_), error_offset(0), error_status(status_ok) - { - } - - // DOCTYPE consists of nested sections of the following possible types: - // , , "...", '...' - // - // - // First group can not contain nested groups - // Second group can contain nested groups of the same type - // Third group can contain all other groups - char_t* parse_doctype_primitive(char_t* s) - { - if (*s == '"' || *s == '\'') - { - // quoted string - char_t ch = *s++; - PUGI__SCANFOR(*s == ch); - if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); - - s++; - } - else if (s[0] == '<' && s[1] == '?') - { - // - s += 2; - PUGI__SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype - if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); - - s += 2; - } - else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-') - { - s += 4; - PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype - if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); - - s += 4; - } - else PUGI__THROW_ERROR(status_bad_doctype, s); - - return s; - } - - char_t* parse_doctype_ignore(char_t* s) - { - assert(s[0] == '<' && s[1] == '!' && s[2] == '['); - s++; - - while (*s) - { - if (s[0] == '<' && s[1] == '!' && s[2] == '[') - { - // nested ignore section - s = parse_doctype_ignore(s); - if (!s) return s; - } - else if (s[0] == ']' && s[1] == ']' && s[2] == '>') - { - // ignore section end - s += 3; - - return s; - } - else s++; - } - - PUGI__THROW_ERROR(status_bad_doctype, s); - } - - char_t* parse_doctype_group(char_t* s, char_t endch, bool toplevel) - { - assert(s[0] == '<' && s[1] == '!'); - s++; - - while (*s) - { - if (s[0] == '<' && s[1] == '!' && s[2] != '-') - { - if (s[2] == '[') - { - // ignore - s = parse_doctype_ignore(s); - if (!s) return s; - } - else - { - // some control group - s = parse_doctype_group(s, endch, false); - if (!s) return s; - } - } - else if (s[0] == '<' || s[0] == '"' || s[0] == '\'') - { - // unknown tag (forbidden), or some primitive group - s = parse_doctype_primitive(s); - if (!s) return s; - } - else if (*s == '>') - { - s++; - - return s; - } - else s++; - } - - if (!toplevel || endch != '>') PUGI__THROW_ERROR(status_bad_doctype, s); - - return s; - } - - char_t* parse_exclamation(char_t* s, xml_node_struct* cursor, unsigned int optmsk, char_t endch) - { - // parse node contents, starting with exclamation mark - ++s; - - if (*s == '-') // 'value = s; // Save the offset. - } - - if (PUGI__OPTSET(parse_eol) && PUGI__OPTSET(parse_comments)) - { - s = strconv_comment(s, endch); - - if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value); - } - else - { - // Scan for terminating '-->'. - PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')); - PUGI__CHECK_ERROR(status_bad_comment, s); - - if (PUGI__OPTSET(parse_comments)) - *s = 0; // Zero-terminate this segment at the first terminating '-'. - - s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'. - } - } - else PUGI__THROW_ERROR(status_bad_comment, s); - } - else if (*s == '[') - { - // 'value = s; // Save the offset. - - if (PUGI__OPTSET(parse_eol)) - { - s = strconv_cdata(s, endch); - - if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value); - } - else - { - // Scan for terminating ']]>'. - PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')); - PUGI__CHECK_ERROR(status_bad_cdata, s); - - *s++ = 0; // Zero-terminate this segment. - } - } - else // Flagged for discard, but we still have to scan for the terminator. - { - // Scan for terminating ']]>'. - PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')); - PUGI__CHECK_ERROR(status_bad_cdata, s); - - ++s; - } - - s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'. - } - else PUGI__THROW_ERROR(status_bad_cdata, s); - } - else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && ENDSWITH(s[6], 'E')) - { - s -= 2; - - if (cursor->parent) PUGI__THROW_ERROR(status_bad_doctype, s); - - char_t* mark = s + 9; - - s = parse_doctype_group(s, endch, true); - if (!s) return s; - - if (PUGI__OPTSET(parse_doctype)) - { - while (PUGI__IS_CHARTYPE(*mark, ct_space)) ++mark; - - PUGI__PUSHNODE(node_doctype); - - cursor->value = mark; - - assert((s[0] == 0 && endch == '>') || s[-1] == '>'); - s[*s == 0 ? 0 : -1] = 0; - - PUGI__POPNODE(); - } - } - else if (*s == 0 && endch == '-') PUGI__THROW_ERROR(status_bad_comment, s); - else if (*s == 0 && endch == '[') PUGI__THROW_ERROR(status_bad_cdata, s); - else PUGI__THROW_ERROR(status_unrecognized_tag, s); - - return s; - } - - char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor, unsigned int optmsk, char_t endch) - { - // load into registers - xml_node_struct* cursor = ref_cursor; - char_t ch = 0; - - // parse node contents, starting with question mark - ++s; - - // read PI target - char_t* target = s; - - if (!PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_pi, s); - - PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); - PUGI__CHECK_ERROR(status_bad_pi, s); - - // determine node type; stricmp / strcasecmp is not portable - bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s; - - if (declaration ? PUGI__OPTSET(parse_declaration) : PUGI__OPTSET(parse_pi)) - { - if (declaration) - { - // disallow non top-level declarations - if (cursor->parent) PUGI__THROW_ERROR(status_bad_pi, s); - - PUGI__PUSHNODE(node_declaration); - } - else - { - PUGI__PUSHNODE(node_pi); - } - - cursor->name = target; - - PUGI__ENDSEG(); - - // parse value/attributes - if (ch == '?') - { - // empty node - if (!ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_pi, s); - s += (*s == '>'); - - PUGI__POPNODE(); - } - else if (PUGI__IS_CHARTYPE(ch, ct_space)) - { - PUGI__SKIPWS(); - - // scan for tag end - char_t* value = s; - - PUGI__SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>')); - PUGI__CHECK_ERROR(status_bad_pi, s); - - if (declaration) - { - // replace ending ? with / so that 'element' terminates properly - *s = '/'; - - // we exit from this function with cursor at node_declaration, which is a signal to parse() to go to LOC_ATTRIBUTES - s = value; - } - else - { - // store value and step over > - cursor->value = value; - PUGI__POPNODE(); - - PUGI__ENDSEG(); - - s += (*s == '>'); - } - } - else PUGI__THROW_ERROR(status_bad_pi, s); - } - else - { - // scan for tag end - PUGI__SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>')); - PUGI__CHECK_ERROR(status_bad_pi, s); - - s += (s[1] == '>' ? 2 : 1); - } - - // store from registers - ref_cursor = cursor; - - return s; - } - - char_t* parse(char_t* s, xml_node_struct* xmldoc, unsigned int optmsk, char_t endch) - { - strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk); - strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk); - - char_t ch = 0; - xml_node_struct* cursor = xmldoc; - char_t* mark = s; - - while (*s != 0) - { - if (*s == '<') - { - ++s; - - LOC_TAG: - if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // '<#...' - { - PUGI__PUSHNODE(node_element); // Append a new node to the tree. - - cursor->name = s; - - PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator. - PUGI__ENDSEG(); // Save char in 'ch', terminate & step over. - - if (ch == '>') - { - // end of tag - } - else if (PUGI__IS_CHARTYPE(ch, ct_space)) - { - LOC_ATTRIBUTES: - while (true) - { - PUGI__SKIPWS(); // Eat any whitespace. - - if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #... - { - xml_attribute_struct* a = append_attribute_ll(cursor, alloc); // Make space for this attribute. - if (!a) PUGI__THROW_ERROR(status_out_of_memory, s); - - a->name = s; // Save the offset. - - PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator. - PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance - - PUGI__ENDSEG(); // Save char in 'ch', terminate & step over. - PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance - - if (PUGI__IS_CHARTYPE(ch, ct_space)) - { - PUGI__SKIPWS(); // Eat any whitespace. - PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance - - ch = *s; - ++s; - } - - if (ch == '=') // '<... #=...' - { - PUGI__SKIPWS(); // Eat any whitespace. - - if (*s == '"' || *s == '\'') // '<... #="...' - { - ch = *s; // Save quote char to avoid breaking on "''" -or- '""'. - ++s; // Step over the quote. - a->value = s; // Save the offset. - - s = strconv_attribute(s, ch); - - if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value); - - // After this line the loop continues from the start; - // Whitespaces, / and > are ok, symbols and EOF are wrong, - // everything else will be detected - if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_attribute, s); - } - else PUGI__THROW_ERROR(status_bad_attribute, s); - } - else PUGI__THROW_ERROR(status_bad_attribute, s); - } - else if (*s == '/') - { - ++s; - - if (*s == '>') - { - PUGI__POPNODE(); - s++; - break; - } - else if (*s == 0 && endch == '>') - { - PUGI__POPNODE(); - break; - } - else PUGI__THROW_ERROR(status_bad_start_element, s); - } - else if (*s == '>') - { - ++s; - - break; - } - else if (*s == 0 && endch == '>') - { - break; - } - else PUGI__THROW_ERROR(status_bad_start_element, s); - } - - // !!! - } - else if (ch == '/') // '<#.../' - { - if (!ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_start_element, s); - - PUGI__POPNODE(); // Pop. - - s += (*s == '>'); - } - else if (ch == 0) - { - // we stepped over null terminator, backtrack & handle closing tag - --s; - - if (endch != '>') PUGI__THROW_ERROR(status_bad_start_element, s); - } - else PUGI__THROW_ERROR(status_bad_start_element, s); - } - else if (*s == '/') - { - ++s; - - char_t* name = cursor->name; - if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, s); - - while (PUGI__IS_CHARTYPE(*s, ct_symbol)) - { - if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, s); - } - - if (*name) - { - if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s); - else PUGI__THROW_ERROR(status_end_element_mismatch, s); - } - - PUGI__POPNODE(); // Pop. - - PUGI__SKIPWS(); - - if (*s == 0) - { - if (endch != '>') PUGI__THROW_ERROR(status_bad_end_element, s); - } - else - { - if (*s != '>') PUGI__THROW_ERROR(status_bad_end_element, s); - ++s; - } - } - else if (*s == '?') // 'header & xml_memory_page_type_mask) + 1 == node_declaration) goto LOC_ATTRIBUTES; - } - else if (*s == '!') // 'first_child) continue; - } - } - - s = mark; - - if (cursor->parent) - { - PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree. - cursor->value = s; // Save the offset. - - s = strconv_pcdata(s); - - PUGI__POPNODE(); // Pop since this is a standalone. - - if (!*s) break; - } - else - { - PUGI__SCANFOR(*s == '<'); // '...<' - if (!*s) break; - - ++s; - } - - // We're after '<' - goto LOC_TAG; - } - } - - // check that last tag is closed - if (cursor != xmldoc) PUGI__THROW_ERROR(status_end_element_mismatch, s); - - return s; - } - - static xml_parse_result parse(char_t* buffer, size_t length, xml_node_struct* root, unsigned int optmsk) - { - xml_document_struct* xmldoc = static_cast(root); - - // store buffer for offset_debug - xmldoc->buffer = buffer; - - // early-out for empty documents - if (length == 0) return make_parse_result(status_ok); - - // create parser on stack - xml_parser parser(*xmldoc); - - // save last character and make buffer zero-terminated (speeds up parsing) - char_t endch = buffer[length - 1]; - buffer[length - 1] = 0; - - // perform actual parsing - parser.parse(buffer, xmldoc, optmsk, endch); - - xml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0); - assert(result.offset >= 0 && static_cast(result.offset) <= length); - - // update allocator state - *static_cast(xmldoc) = parser.alloc; - - // since we removed last character, we have to handle the only possible false positive - if (result && endch == '<') - { - // there's no possible well-formed document with < at the end - return make_parse_result(status_unrecognized_tag, length); - } - - return result; - } - }; - - // Output facilities - PUGI__FN xml_encoding get_write_native_encoding() - { - #ifdef PUGIXML_WCHAR_MODE - return get_wchar_encoding(); - #else - return encoding_utf8; - #endif - } - - PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding) - { - // replace wchar encoding with utf implementation - if (encoding == encoding_wchar) return get_wchar_encoding(); - - // replace utf16 encoding with utf16 with specific endianness - if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - - // replace utf32 encoding with utf32 with specific endianness - if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - - // only do autodetection if no explicit encoding is requested - if (encoding != encoding_auto) return encoding; - - // assume utf8 encoding - return encoding_utf8; - } - -#ifdef PUGIXML_WCHAR_MODE - PUGI__FN size_t get_valid_length(const char_t* data, size_t length) - { - assert(length > 0); - - // discard last character if it's the lead of a surrogate pair - return (sizeof(wchar_t) == 2 && static_cast(static_cast(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length; - } - - PUGI__FN size_t convert_buffer(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding) - { - // only endian-swapping is required - if (need_endian_swap_utf(encoding, get_wchar_encoding())) - { - convert_wchar_endian_swap(r_char, data, length); - - return length * sizeof(char_t); - } - - // convert to utf8 - if (encoding == encoding_utf8) - { - uint8_t* dest = r_u8; - uint8_t* end = utf_decoder::decode_wchar_block(data, length, dest); - - return static_cast(end - dest); - } - - // convert to utf16 - if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) - { - uint16_t* dest = r_u16; - - // convert to native utf16 - uint16_t* end = utf_decoder::decode_wchar_block(data, length, dest); - - // swap if necessary - xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - - if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); - - return static_cast(end - dest) * sizeof(uint16_t); - } - - // convert to utf32 - if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) - { - uint32_t* dest = r_u32; - - // convert to native utf32 - uint32_t* end = utf_decoder::decode_wchar_block(data, length, dest); - - // swap if necessary - xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - - if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); - - return static_cast(end - dest) * sizeof(uint32_t); - } - - // convert to latin1 - if (encoding == encoding_latin1) - { - uint8_t* dest = r_u8; - uint8_t* end = utf_decoder::decode_wchar_block(data, length, dest); - - return static_cast(end - dest); - } - - assert(!"Invalid encoding"); - return 0; - } -#else - PUGI__FN size_t get_valid_length(const char_t* data, size_t length) - { - assert(length > 4); - - for (size_t i = 1; i <= 4; ++i) - { - uint8_t ch = static_cast(data[length - i]); - - // either a standalone character or a leading one - if ((ch & 0xc0) != 0x80) return length - i; - } - - // there are four non-leading characters at the end, sequence tail is broken so might as well process the whole chunk - return length; - } - - PUGI__FN size_t convert_buffer(char_t* /* r_char */, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding) - { - if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) - { - uint16_t* dest = r_u16; - - // convert to native utf16 - uint16_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); - - // swap if necessary - xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - - if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); - - return static_cast(end - dest) * sizeof(uint16_t); - } - - if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) - { - uint32_t* dest = r_u32; - - // convert to native utf32 - uint32_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); - - // swap if necessary - xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - - if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); - - return static_cast(end - dest) * sizeof(uint32_t); - } - - if (encoding == encoding_latin1) - { - uint8_t* dest = r_u8; - uint8_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); - - return static_cast(end - dest); - } - - assert(!"Invalid encoding"); - return 0; - } -#endif - - class xml_buffered_writer - { - xml_buffered_writer(const xml_buffered_writer&); - xml_buffered_writer& operator=(const xml_buffered_writer&); - - public: - xml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding)) - { - PUGI__STATIC_ASSERT(bufcapacity >= 8); - } - - ~xml_buffered_writer() - { - flush(); - } - - void flush() - { - flush(buffer, bufsize); - bufsize = 0; - } - - void flush(const char_t* data, size_t size) - { - if (size == 0) return; - - // fast path, just write data - if (encoding == get_write_native_encoding()) - writer.write(data, size * sizeof(char_t)); - else - { - // convert chunk - size_t result = convert_buffer(scratch.data_char, scratch.data_u8, scratch.data_u16, scratch.data_u32, data, size, encoding); - assert(result <= sizeof(scratch)); - - // write data - writer.write(scratch.data_u8, result); - } - } - - void write(const char_t* data, size_t length) - { - if (bufsize + length > bufcapacity) - { - // flush the remaining buffer contents - flush(); - - // handle large chunks - if (length > bufcapacity) - { - if (encoding == get_write_native_encoding()) - { - // fast path, can just write data chunk - writer.write(data, length * sizeof(char_t)); - return; - } - - // need to convert in suitable chunks - while (length > bufcapacity) - { - // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer - // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary) - size_t chunk_size = get_valid_length(data, bufcapacity); - - // convert chunk and write - flush(data, chunk_size); - - // iterate - data += chunk_size; - length -= chunk_size; - } - - // small tail is copied below - bufsize = 0; - } - } - - memcpy(buffer + bufsize, data, length * sizeof(char_t)); - bufsize += length; - } - - void write(const char_t* data) - { - write(data, strlength(data)); - } - - void write(char_t d0) - { - if (bufsize + 1 > bufcapacity) flush(); - - buffer[bufsize + 0] = d0; - bufsize += 1; - } - - void write(char_t d0, char_t d1) - { - if (bufsize + 2 > bufcapacity) flush(); - - buffer[bufsize + 0] = d0; - buffer[bufsize + 1] = d1; - bufsize += 2; - } - - void write(char_t d0, char_t d1, char_t d2) - { - if (bufsize + 3 > bufcapacity) flush(); - - buffer[bufsize + 0] = d0; - buffer[bufsize + 1] = d1; - buffer[bufsize + 2] = d2; - bufsize += 3; - } - - void write(char_t d0, char_t d1, char_t d2, char_t d3) - { - if (bufsize + 4 > bufcapacity) flush(); - - buffer[bufsize + 0] = d0; - buffer[bufsize + 1] = d1; - buffer[bufsize + 2] = d2; - buffer[bufsize + 3] = d3; - bufsize += 4; - } - - void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4) - { - if (bufsize + 5 > bufcapacity) flush(); - - buffer[bufsize + 0] = d0; - buffer[bufsize + 1] = d1; - buffer[bufsize + 2] = d2; - buffer[bufsize + 3] = d3; - buffer[bufsize + 4] = d4; - bufsize += 5; - } - - void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5) - { - if (bufsize + 6 > bufcapacity) flush(); - - buffer[bufsize + 0] = d0; - buffer[bufsize + 1] = d1; - buffer[bufsize + 2] = d2; - buffer[bufsize + 3] = d3; - buffer[bufsize + 4] = d4; - buffer[bufsize + 5] = d5; - bufsize += 6; - } - - // utf8 maximum expansion: x4 (-> utf32) - // utf16 maximum expansion: x2 (-> utf32) - // utf32 maximum expansion: x1 - enum - { - bufcapacitybytes = - #ifdef PUGIXML_MEMORY_OUTPUT_STACK - PUGIXML_MEMORY_OUTPUT_STACK - #else - 10240 - #endif - , - bufcapacity = bufcapacitybytes / (sizeof(char_t) + 4) - }; - - char_t buffer[bufcapacity]; - - union - { - uint8_t data_u8[4 * bufcapacity]; - uint16_t data_u16[2 * bufcapacity]; - uint32_t data_u32[bufcapacity]; - char_t data_char[bufcapacity]; - } scratch; - - xml_writer& writer; - size_t bufsize; - xml_encoding encoding; - }; - - PUGI__FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type) - { - while (*s) - { - const char_t* prev = s; - - // While *s is a usual symbol - while (!PUGI__IS_CHARTYPEX(*s, type)) ++s; - - writer.write(prev, static_cast(s - prev)); - - switch (*s) - { - case 0: break; - case '&': - writer.write('&', 'a', 'm', 'p', ';'); - ++s; - break; - case '<': - writer.write('&', 'l', 't', ';'); - ++s; - break; - case '>': - writer.write('&', 'g', 't', ';'); - ++s; - break; - case '"': - writer.write('&', 'q', 'u', 'o', 't', ';'); - ++s; - break; - default: // s is not a usual symbol - { - unsigned int ch = static_cast(*s++); - assert(ch < 32); - - writer.write('&', '#', static_cast((ch / 10) + '0'), static_cast((ch % 10) + '0'), ';'); - } - } - } - } - - PUGI__FN void text_output(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags) - { - if (flags & format_no_escapes) - writer.write(s); - else - text_output_escaped(writer, s, type); - } - - PUGI__FN void text_output_cdata(xml_buffered_writer& writer, const char_t* s) - { - do - { - writer.write('<', '!', '[', 'C', 'D'); - writer.write('A', 'T', 'A', '['); - - const char_t* prev = s; - - // look for ]]> sequence - we can't output it as is since it terminates CDATA - while (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>')) ++s; - - // skip ]] if we stopped at ]]>, > will go to the next CDATA section - if (*s) s += 2; - - writer.write(prev, static_cast(s - prev)); - - writer.write(']', ']', '>'); - } - while (*s); - } - - PUGI__FN void node_output_attributes(xml_buffered_writer& writer, const xml_node& node, unsigned int flags) - { - const char_t* default_name = PUGIXML_TEXT(":anonymous"); - - for (xml_attribute a = node.first_attribute(); a; a = a.next_attribute()) - { - writer.write(' '); - writer.write(a.name()[0] ? a.name() : default_name); - writer.write('=', '"'); - - text_output(writer, a.value(), ctx_special_attr, flags); - - writer.write('"'); - } - } - - PUGI__FN void node_output(xml_buffered_writer& writer, const xml_node& node, const char_t* indent, unsigned int flags, unsigned int depth) - { - const char_t* default_name = PUGIXML_TEXT(":anonymous"); - - if ((flags & format_indent) != 0 && (flags & format_raw) == 0) - for (unsigned int i = 0; i < depth; ++i) writer.write(indent); - - switch (node.type()) - { - case node_document: - { - for (xml_node n = node.first_child(); n; n = n.next_sibling()) - node_output(writer, n, indent, flags, depth); - break; - } - - case node_element: - { - const char_t* name = node.name()[0] ? node.name() : default_name; - - writer.write('<'); - writer.write(name); - - node_output_attributes(writer, node, flags); - - if (flags & format_raw) - { - if (!node.first_child()) - writer.write(' ', '/', '>'); - else - { - writer.write('>'); - - for (xml_node n = node.first_child(); n; n = n.next_sibling()) - node_output(writer, n, indent, flags, depth + 1); - - writer.write('<', '/'); - writer.write(name); - writer.write('>'); - } - } - else if (!node.first_child()) - writer.write(' ', '/', '>', '\n'); - else if (node.first_child() == node.last_child() && (node.first_child().type() == node_pcdata || node.first_child().type() == node_cdata)) - { - writer.write('>'); - - if (node.first_child().type() == node_pcdata) - text_output(writer, node.first_child().value(), ctx_special_pcdata, flags); - else - text_output_cdata(writer, node.first_child().value()); - - writer.write('<', '/'); - writer.write(name); - writer.write('>', '\n'); - } - else - { - writer.write('>', '\n'); - - for (xml_node n = node.first_child(); n; n = n.next_sibling()) - node_output(writer, n, indent, flags, depth + 1); - - if ((flags & format_indent) != 0 && (flags & format_raw) == 0) - for (unsigned int i = 0; i < depth; ++i) writer.write(indent); - - writer.write('<', '/'); - writer.write(name); - writer.write('>', '\n'); - } - - break; - } - - case node_pcdata: - text_output(writer, node.value(), ctx_special_pcdata, flags); - if ((flags & format_raw) == 0) writer.write('\n'); - break; - - case node_cdata: - text_output_cdata(writer, node.value()); - if ((flags & format_raw) == 0) writer.write('\n'); - break; - - case node_comment: - writer.write('<', '!', '-', '-'); - writer.write(node.value()); - writer.write('-', '-', '>'); - if ((flags & format_raw) == 0) writer.write('\n'); - break; - - case node_pi: - case node_declaration: - writer.write('<', '?'); - writer.write(node.name()[0] ? node.name() : default_name); - - if (node.type() == node_declaration) - { - node_output_attributes(writer, node, flags); - } - else if (node.value()[0]) - { - writer.write(' '); - writer.write(node.value()); - } - - writer.write('?', '>'); - if ((flags & format_raw) == 0) writer.write('\n'); - break; - - case node_doctype: - writer.write('<', '!', 'D', 'O', 'C'); - writer.write('T', 'Y', 'P', 'E'); - - if (node.value()[0]) - { - writer.write(' '); - writer.write(node.value()); - } - - writer.write('>'); - if ((flags & format_raw) == 0) writer.write('\n'); - break; - - default: - assert(!"Invalid node type"); - } - } - - inline bool has_declaration(const xml_node& node) - { - for (xml_node child = node.first_child(); child; child = child.next_sibling()) - { - xml_node_type type = child.type(); - - if (type == node_declaration) return true; - if (type == node_element) return false; - } - - return false; - } - - inline bool allow_insert_child(xml_node_type parent, xml_node_type child) - { - if (parent != node_document && parent != node_element) return false; - if (child == node_document || child == node_null) return false; - if (parent != node_document && (child == node_declaration || child == node_doctype)) return false; - - return true; - } - - PUGI__FN void recursive_copy_skip(xml_node& dest, const xml_node& source, const xml_node& skip) - { - assert(dest.type() == source.type()); - - switch (source.type()) - { - case node_element: - { - dest.set_name(source.name()); - - for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute()) - dest.append_attribute(a.name()).set_value(a.value()); - - for (xml_node c = source.first_child(); c; c = c.next_sibling()) - { - if (c == skip) continue; - - xml_node cc = dest.append_child(c.type()); - assert(cc); - - recursive_copy_skip(cc, c, skip); - } - - break; - } - - case node_pcdata: - case node_cdata: - case node_comment: - case node_doctype: - dest.set_value(source.value()); - break; - - case node_pi: - dest.set_name(source.name()); - dest.set_value(source.value()); - break; - - case node_declaration: - { - dest.set_name(source.name()); - - for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute()) - dest.append_attribute(a.name()).set_value(a.value()); - - break; - } - - default: - assert(!"Invalid node type"); - } - } - - inline bool is_text_node(xml_node_struct* node) - { - xml_node_type type = static_cast((node->header & impl::xml_memory_page_type_mask) + 1); - - return type == node_pcdata || type == node_cdata; - } - - // get value with conversion functions - PUGI__FN int get_value_int(const char_t* value, int def) - { - if (!value) return def; - - #ifdef PUGIXML_WCHAR_MODE - return static_cast(wcstol(value, 0, 10)); - #else - return static_cast(strtol(value, 0, 10)); - #endif - } - - PUGI__FN unsigned int get_value_uint(const char_t* value, unsigned int def) - { - if (!value) return def; - - #ifdef PUGIXML_WCHAR_MODE - return static_cast(wcstoul(value, 0, 10)); - #else - return static_cast(strtoul(value, 0, 10)); - #endif - } - - PUGI__FN double get_value_double(const char_t* value, double def) - { - if (!value) return def; - - #ifdef PUGIXML_WCHAR_MODE - return wcstod(value, 0); - #else - return strtod(value, 0); - #endif - } - - PUGI__FN float get_value_float(const char_t* value, float def) - { - if (!value) return def; - - #ifdef PUGIXML_WCHAR_MODE - return static_cast(wcstod(value, 0)); - #else - return static_cast(strtod(value, 0)); - #endif - } - - PUGI__FN bool get_value_bool(const char_t* value, bool def) - { - if (!value) return def; - - // only look at first char - char_t first = *value; - - // 1*, t* (true), T* (True), y* (yes), Y* (YES) - return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y'); - } - - // set value with conversion functions - PUGI__FN bool set_value_buffer(char_t*& dest, uintptr_t& header, uintptr_t header_mask, char (&buf)[128]) - { - #ifdef PUGIXML_WCHAR_MODE - char_t wbuf[128]; - impl::widen_ascii(wbuf, buf); - - return strcpy_insitu(dest, header, header_mask, wbuf); - #else - return strcpy_insitu(dest, header, header_mask, buf); - #endif - } - - PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, int value) - { - char buf[128]; - sprintf(buf, "%d", value); - - return set_value_buffer(dest, header, header_mask, buf); - } - - PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, unsigned int value) - { - char buf[128]; - sprintf(buf, "%u", value); - - return set_value_buffer(dest, header, header_mask, buf); - } - - PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, double value) - { - char buf[128]; - sprintf(buf, "%g", value); - - return set_value_buffer(dest, header, header_mask, buf); - } - - PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, bool value) - { - return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); - } - - // we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick - PUGI__FN xml_parse_status get_file_size(FILE* file, size_t& out_result) - { - #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE) - // there are 64-bit versions of fseek/ftell, let's use them - typedef __int64 length_type; - - _fseeki64(file, 0, SEEK_END); - length_type length = _ftelli64(file); - _fseeki64(file, 0, SEEK_SET); - #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && !defined(__STRICT_ANSI__) - // there are 64-bit versions of fseek/ftell, let's use them - typedef off64_t length_type; - - fseeko64(file, 0, SEEK_END); - length_type length = ftello64(file); - fseeko64(file, 0, SEEK_SET); - #else - // if this is a 32-bit OS, long is enough; if this is a unix system, long is 64-bit, which is enough; otherwise we can't do anything anyway. - typedef long length_type; - - fseek(file, 0, SEEK_END); - length_type length = ftell(file); - fseek(file, 0, SEEK_SET); - #endif - - // check for I/O errors - if (length < 0) return status_io_error; - - // check for overflow - size_t result = static_cast(length); - - if (static_cast(result) != length) return status_out_of_memory; - - // finalize - out_result = result; - - return status_ok; - } - - PUGI__FN xml_parse_result load_file_impl(xml_document& doc, FILE* file, unsigned int options, xml_encoding encoding) - { - if (!file) return make_parse_result(status_file_not_found); - - // get file size (can result in I/O errors) - size_t size = 0; - xml_parse_status size_status = get_file_size(file, size); - - if (size_status != status_ok) - { - fclose(file); - return make_parse_result(size_status); - } - - // allocate buffer for the whole file - char* contents = static_cast(xml_memory::allocate(size > 0 ? size : 1)); - - if (!contents) - { - fclose(file); - return make_parse_result(status_out_of_memory); - } - - // read file in memory - size_t read_size = fread(contents, 1, size, file); - fclose(file); - - if (read_size != size) - { - xml_memory::deallocate(contents); - return make_parse_result(status_io_error); - } - - return doc.load_buffer_inplace_own(contents, size, options, encoding); - } - -#ifndef PUGIXML_NO_STL - template struct xml_stream_chunk - { - static xml_stream_chunk* create() - { - void* memory = xml_memory::allocate(sizeof(xml_stream_chunk)); - - return new (memory) xml_stream_chunk(); - } - - static void destroy(void* ptr) - { - xml_stream_chunk* chunk = static_cast(ptr); - - // free chunk chain - while (chunk) - { - xml_stream_chunk* next = chunk->next; - xml_memory::deallocate(chunk); - chunk = next; - } - } - - xml_stream_chunk(): next(0), size(0) - { - } - - xml_stream_chunk* next; - size_t size; - - T data[xml_memory_page_size / sizeof(T)]; - }; - - template PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream& stream, void** out_buffer, size_t* out_size) - { - buffer_holder chunks(0, xml_stream_chunk::destroy); - - // read file to a chunk list - size_t total = 0; - xml_stream_chunk* last = 0; - - while (!stream.eof()) - { - // allocate new chunk - xml_stream_chunk* chunk = xml_stream_chunk::create(); - if (!chunk) return status_out_of_memory; - - // append chunk to list - if (last) last = last->next = chunk; - else chunks.data = last = chunk; - - // read data to chunk - stream.read(chunk->data, static_cast(sizeof(chunk->data) / sizeof(T))); - chunk->size = static_cast(stream.gcount()) * sizeof(T); - - // read may set failbit | eofbit in case gcount() is less than read length, so check for other I/O errors - if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error; - - // guard against huge files (chunk size is small enough to make this overflow check work) - if (total + chunk->size < total) return status_out_of_memory; - total += chunk->size; - } - - // copy chunk list to a contiguous buffer - char* buffer = static_cast(xml_memory::allocate(total)); - if (!buffer) return status_out_of_memory; - - char* write = buffer; - - for (xml_stream_chunk* chunk = static_cast*>(chunks.data); chunk; chunk = chunk->next) - { - assert(write + chunk->size <= buffer + total); - memcpy(write, chunk->data, chunk->size); - write += chunk->size; - } - - assert(write == buffer + total); - - // return buffer - *out_buffer = buffer; - *out_size = total; - - return status_ok; - } - - template PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream& stream, void** out_buffer, size_t* out_size) - { - // get length of remaining data in stream - typename std::basic_istream::pos_type pos = stream.tellg(); - stream.seekg(0, std::ios::end); - std::streamoff length = stream.tellg() - pos; - stream.seekg(pos); - - if (stream.fail() || pos < 0) return status_io_error; - - // guard against huge files - size_t read_length = static_cast(length); - - if (static_cast(read_length) != length || length < 0) return status_out_of_memory; - - // read stream data into memory (guard against stream exceptions with buffer holder) - buffer_holder buffer(xml_memory::allocate((read_length > 0 ? read_length : 1) * sizeof(T)), xml_memory::deallocate); - if (!buffer.data) return status_out_of_memory; - - stream.read(static_cast(buffer.data), static_cast(read_length)); - - // read may set failbit | eofbit in case gcount() is less than read_length (i.e. line ending conversion), so check for other I/O errors - if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error; - - // return buffer - size_t actual_length = static_cast(stream.gcount()); - assert(actual_length <= read_length); - - *out_buffer = buffer.release(); - *out_size = actual_length * sizeof(T); - - return status_ok; - } - - template PUGI__FN xml_parse_result load_stream_impl(xml_document& doc, std::basic_istream& stream, unsigned int options, xml_encoding encoding) - { - void* buffer = 0; - size_t size = 0; - - // load stream to memory (using seek-based implementation if possible, since it's faster and takes less memory) - xml_parse_status status = (stream.tellg() < 0) ? load_stream_data_noseek(stream, &buffer, &size) : load_stream_data_seek(stream, &buffer, &size); - if (status != status_ok) return make_parse_result(status); - - return doc.load_buffer_inplace_own(buffer, size, options, encoding); - } -#endif - -#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && !defined(__STRICT_ANSI__)) - PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) - { - return _wfopen(path, mode); - } -#else - PUGI__FN char* convert_path_heap(const wchar_t* str) - { - assert(str); - - // first pass: get length in utf8 characters - size_t length = wcslen(str); - size_t size = as_utf8_begin(str, length); - - // allocate resulting string - char* result = static_cast(xml_memory::allocate(size + 1)); - if (!result) return 0; - - // second pass: convert to utf8 - as_utf8_end(result, size, str, length); - - return result; - } - - PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) - { - // there is no standard function to open wide paths, so our best bet is to try utf8 path - char* path_utf8 = convert_path_heap(path); - if (!path_utf8) return 0; - - // convert mode to ASCII (we mirror _wfopen interface) - char mode_ascii[4] = {0}; - for (size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast(mode[i]); - - // try to open the utf8 path - FILE* result = fopen(path_utf8, mode_ascii); - - // free dummy buffer - xml_memory::deallocate(path_utf8); - - return result; - } -#endif - - PUGI__FN bool save_file_impl(const xml_document& doc, FILE* file, const char_t* indent, unsigned int flags, xml_encoding encoding) - { - if (!file) return false; - - xml_writer_file writer(file); - doc.save(writer, indent, flags, encoding); - - int result = ferror(file); - - fclose(file); - - return result == 0; - } -PUGI__NS_END - -namespace pugi -{ - PUGI__FN xml_writer_file::xml_writer_file(void* file_): file(file_) - { - } - - PUGI__FN void xml_writer_file::write(const void* data, size_t size) - { - size_t result = fwrite(data, 1, size, static_cast(file)); - (void)!result; // unfortunately we can't do proper error handling here - } - -#ifndef PUGIXML_NO_STL - PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream >& stream): narrow_stream(&stream), wide_stream(0) - { - } - - PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream >& stream): narrow_stream(0), wide_stream(&stream) - { - } - - PUGI__FN void xml_writer_stream::write(const void* data, size_t size) - { - if (narrow_stream) - { - assert(!wide_stream); - narrow_stream->write(reinterpret_cast(data), static_cast(size)); - } - else - { - assert(wide_stream); - assert(size % sizeof(wchar_t) == 0); - - wide_stream->write(reinterpret_cast(data), static_cast(size / sizeof(wchar_t))); - } - } -#endif - - PUGI__FN xml_tree_walker::xml_tree_walker(): _depth(0) - { - } - - PUGI__FN xml_tree_walker::~xml_tree_walker() - { - } - - PUGI__FN int xml_tree_walker::depth() const - { - return _depth; - } - - PUGI__FN bool xml_tree_walker::begin(xml_node&) - { - return true; - } - - PUGI__FN bool xml_tree_walker::end(xml_node&) - { - return true; - } - - PUGI__FN xml_attribute::xml_attribute(): _attr(0) - { - } - - PUGI__FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr) - { - } - - PUGI__FN static void unspecified_bool_xml_attribute(xml_attribute***) - { - } - - PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type() const - { - return _attr ? unspecified_bool_xml_attribute : 0; - } - - PUGI__FN bool xml_attribute::operator!() const - { - return !_attr; - } - - PUGI__FN bool xml_attribute::operator==(const xml_attribute& r) const - { - return (_attr == r._attr); - } - - PUGI__FN bool xml_attribute::operator!=(const xml_attribute& r) const - { - return (_attr != r._attr); - } - - PUGI__FN bool xml_attribute::operator<(const xml_attribute& r) const - { - return (_attr < r._attr); - } - - PUGI__FN bool xml_attribute::operator>(const xml_attribute& r) const - { - return (_attr > r._attr); - } - - PUGI__FN bool xml_attribute::operator<=(const xml_attribute& r) const - { - return (_attr <= r._attr); - } - - PUGI__FN bool xml_attribute::operator>=(const xml_attribute& r) const - { - return (_attr >= r._attr); - } - - PUGI__FN xml_attribute xml_attribute::next_attribute() const - { - return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute(); - } - - PUGI__FN xml_attribute xml_attribute::previous_attribute() const - { - return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute(); - } - - PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const - { - return (_attr && _attr->value) ? _attr->value : def; - } - - PUGI__FN int xml_attribute::as_int(int def) const - { - return impl::get_value_int(_attr ? _attr->value : 0, def); - } - - PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const - { - return impl::get_value_uint(_attr ? _attr->value : 0, def); - } - - PUGI__FN double xml_attribute::as_double(double def) const - { - return impl::get_value_double(_attr ? _attr->value : 0, def); - } - - PUGI__FN float xml_attribute::as_float(float def) const - { - return impl::get_value_float(_attr ? _attr->value : 0, def); - } - - PUGI__FN bool xml_attribute::as_bool(bool def) const - { - return impl::get_value_bool(_attr ? _attr->value : 0, def); - } - - PUGI__FN bool xml_attribute::empty() const - { - return !_attr; - } - - PUGI__FN const char_t* xml_attribute::name() const - { - return (_attr && _attr->name) ? _attr->name : PUGIXML_TEXT(""); - } - - PUGI__FN const char_t* xml_attribute::value() const - { - return (_attr && _attr->value) ? _attr->value : PUGIXML_TEXT(""); - } - - PUGI__FN size_t xml_attribute::hash_value() const - { - return static_cast(reinterpret_cast(_attr) / sizeof(xml_attribute_struct)); - } - - PUGI__FN xml_attribute_struct* xml_attribute::internal_object() const - { - return _attr; - } - - PUGI__FN xml_attribute& xml_attribute::operator=(const char_t* rhs) - { - set_value(rhs); - return *this; - } - - PUGI__FN xml_attribute& xml_attribute::operator=(int rhs) - { - set_value(rhs); - return *this; - } - - PUGI__FN xml_attribute& xml_attribute::operator=(unsigned int rhs) - { - set_value(rhs); - return *this; - } - - PUGI__FN xml_attribute& xml_attribute::operator=(double rhs) - { - set_value(rhs); - return *this; - } - - PUGI__FN xml_attribute& xml_attribute::operator=(bool rhs) - { - set_value(rhs); - return *this; - } - - PUGI__FN bool xml_attribute::set_name(const char_t* rhs) - { - if (!_attr) return false; - - return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs); - } - - PUGI__FN bool xml_attribute::set_value(const char_t* rhs) - { - if (!_attr) return false; - - return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); - } - - PUGI__FN bool xml_attribute::set_value(int rhs) - { - if (!_attr) return false; - - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); - } - - PUGI__FN bool xml_attribute::set_value(unsigned int rhs) - { - if (!_attr) return false; - - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); - } - - PUGI__FN bool xml_attribute::set_value(double rhs) - { - if (!_attr) return false; - - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); - } - - PUGI__FN bool xml_attribute::set_value(bool rhs) - { - if (!_attr) return false; - - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); - } - -#ifdef __BORLANDC__ - PUGI__FN bool operator&&(const xml_attribute& lhs, bool rhs) - { - return (bool)lhs && rhs; - } - - PUGI__FN bool operator||(const xml_attribute& lhs, bool rhs) - { - return (bool)lhs || rhs; - } -#endif - - PUGI__FN xml_node::xml_node(): _root(0) - { - } - - PUGI__FN xml_node::xml_node(xml_node_struct* p): _root(p) - { - } - - PUGI__FN static void unspecified_bool_xml_node(xml_node***) - { - } - - PUGI__FN xml_node::operator xml_node::unspecified_bool_type() const - { - return _root ? unspecified_bool_xml_node : 0; - } - - PUGI__FN bool xml_node::operator!() const - { - return !_root; - } - - PUGI__FN xml_node::iterator xml_node::begin() const - { - return iterator(_root ? _root->first_child : 0, _root); - } - - PUGI__FN xml_node::iterator xml_node::end() const - { - return iterator(0, _root); - } - - PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin() const - { - return attribute_iterator(_root ? _root->first_attribute : 0, _root); - } - - PUGI__FN xml_node::attribute_iterator xml_node::attributes_end() const - { - return attribute_iterator(0, _root); - } - - PUGI__FN xml_object_range xml_node::children() const - { - return xml_object_range(begin(), end()); - } - - PUGI__FN xml_object_range xml_node::children(const char_t* name_) const - { - return xml_object_range(xml_named_node_iterator(child(name_), name_), xml_named_node_iterator()); - } - - PUGI__FN xml_object_range xml_node::attributes() const - { - return xml_object_range(attributes_begin(), attributes_end()); - } - - PUGI__FN bool xml_node::operator==(const xml_node& r) const - { - return (_root == r._root); - } - - PUGI__FN bool xml_node::operator!=(const xml_node& r) const - { - return (_root != r._root); - } - - PUGI__FN bool xml_node::operator<(const xml_node& r) const - { - return (_root < r._root); - } - - PUGI__FN bool xml_node::operator>(const xml_node& r) const - { - return (_root > r._root); - } - - PUGI__FN bool xml_node::operator<=(const xml_node& r) const - { - return (_root <= r._root); - } - - PUGI__FN bool xml_node::operator>=(const xml_node& r) const - { - return (_root >= r._root); - } - - PUGI__FN bool xml_node::empty() const - { - return !_root; - } - - PUGI__FN const char_t* xml_node::name() const - { - return (_root && _root->name) ? _root->name : PUGIXML_TEXT(""); - } - - PUGI__FN xml_node_type xml_node::type() const - { - return _root ? static_cast((_root->header & impl::xml_memory_page_type_mask) + 1) : node_null; - } - - PUGI__FN const char_t* xml_node::value() const - { - return (_root && _root->value) ? _root->value : PUGIXML_TEXT(""); - } - - PUGI__FN xml_node xml_node::child(const char_t* name_) const - { - if (!_root) return xml_node(); - - for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - if (i->name && impl::strequal(name_, i->name)) return xml_node(i); - - return xml_node(); - } - - PUGI__FN xml_attribute xml_node::attribute(const char_t* name_) const - { - if (!_root) return xml_attribute(); - - for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) - if (i->name && impl::strequal(name_, i->name)) - return xml_attribute(i); - - return xml_attribute(); - } - - PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const - { - if (!_root) return xml_node(); - - for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) - if (i->name && impl::strequal(name_, i->name)) return xml_node(i); - - return xml_node(); - } - - PUGI__FN xml_node xml_node::next_sibling() const - { - if (!_root) return xml_node(); - - if (_root->next_sibling) return xml_node(_root->next_sibling); - else return xml_node(); - } - - PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const - { - if (!_root) return xml_node(); - - for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) - if (i->name && impl::strequal(name_, i->name)) return xml_node(i); - - return xml_node(); - } - - PUGI__FN xml_node xml_node::previous_sibling() const - { - if (!_root) return xml_node(); - - if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c); - else return xml_node(); - } - - PUGI__FN xml_node xml_node::parent() const - { - return _root ? xml_node(_root->parent) : xml_node(); - } - - PUGI__FN xml_node xml_node::root() const - { - if (!_root) return xml_node(); - - impl::xml_memory_page* page = reinterpret_cast(_root->header & impl::xml_memory_page_pointer_mask); - - return xml_node(static_cast(page->allocator)); - } - - PUGI__FN xml_text xml_node::text() const - { - return xml_text(_root); - } - - PUGI__FN const char_t* xml_node::child_value() const - { - if (!_root) return PUGIXML_TEXT(""); - - for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - if (i->value && impl::is_text_node(i)) - return i->value; - - return PUGIXML_TEXT(""); - } - - PUGI__FN const char_t* xml_node::child_value(const char_t* name_) const - { - return child(name_).child_value(); - } - - PUGI__FN xml_attribute xml_node::first_attribute() const - { - return _root ? xml_attribute(_root->first_attribute) : xml_attribute(); - } - - PUGI__FN xml_attribute xml_node::last_attribute() const - { - return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute(); - } - - PUGI__FN xml_node xml_node::first_child() const - { - return _root ? xml_node(_root->first_child) : xml_node(); - } - - PUGI__FN xml_node xml_node::last_child() const - { - return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node(); - } - - PUGI__FN bool xml_node::set_name(const char_t* rhs) - { - switch (type()) - { - case node_pi: - case node_declaration: - case node_element: - return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs); - - default: - return false; - } - } - - PUGI__FN bool xml_node::set_value(const char_t* rhs) - { - switch (type()) - { - case node_pi: - case node_cdata: - case node_pcdata: - case node_comment: - case node_doctype: - return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs); - - default: - return false; - } - } - - PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_) - { - if (type() != node_element && type() != node_declaration) return xml_attribute(); - - xml_attribute a(impl::append_attribute_ll(_root, impl::get_allocator(_root))); - a.set_name(name_); - - return a; - } - - PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_) - { - if (type() != node_element && type() != node_declaration) return xml_attribute(); - - xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root))); - if (!a) return xml_attribute(); - - a.set_name(name_); - - xml_attribute_struct* head = _root->first_attribute; - - if (head) - { - a._attr->prev_attribute_c = head->prev_attribute_c; - head->prev_attribute_c = a._attr; - } - else - a._attr->prev_attribute_c = a._attr; - - a._attr->next_attribute = head; - _root->first_attribute = a._attr; - - return a; - } - - PUGI__FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr) - { - if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute(); - - // check that attribute belongs to *this - xml_attribute_struct* cur = attr._attr; - - while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c; - - if (cur != _root->first_attribute) return xml_attribute(); - - xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root))); - if (!a) return xml_attribute(); - - a.set_name(name_); - - if (attr._attr->prev_attribute_c->next_attribute) - attr._attr->prev_attribute_c->next_attribute = a._attr; - else - _root->first_attribute = a._attr; - - a._attr->prev_attribute_c = attr._attr->prev_attribute_c; - a._attr->next_attribute = attr._attr; - attr._attr->prev_attribute_c = a._attr; - - return a; - } - - PUGI__FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr) - { - if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute(); - - // check that attribute belongs to *this - xml_attribute_struct* cur = attr._attr; - - while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c; - - if (cur != _root->first_attribute) return xml_attribute(); - - xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root))); - if (!a) return xml_attribute(); - - a.set_name(name_); - - if (attr._attr->next_attribute) - attr._attr->next_attribute->prev_attribute_c = a._attr; - else - _root->first_attribute->prev_attribute_c = a._attr; - - a._attr->next_attribute = attr._attr->next_attribute; - a._attr->prev_attribute_c = attr._attr; - attr._attr->next_attribute = a._attr; - - return a; - } - - PUGI__FN xml_attribute xml_node::append_copy(const xml_attribute& proto) - { - if (!proto) return xml_attribute(); - - xml_attribute result = append_attribute(proto.name()); - result.set_value(proto.value()); - - return result; - } - - PUGI__FN xml_attribute xml_node::prepend_copy(const xml_attribute& proto) - { - if (!proto) return xml_attribute(); - - xml_attribute result = prepend_attribute(proto.name()); - result.set_value(proto.value()); - - return result; - } - - PUGI__FN xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr) - { - if (!proto) return xml_attribute(); - - xml_attribute result = insert_attribute_after(proto.name(), attr); - result.set_value(proto.value()); - - return result; - } - - PUGI__FN xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr) - { - if (!proto) return xml_attribute(); - - xml_attribute result = insert_attribute_before(proto.name(), attr); - result.set_value(proto.value()); - - return result; - } - - PUGI__FN xml_node xml_node::append_child(xml_node_type type_) - { - if (!impl::allow_insert_child(this->type(), type_)) return xml_node(); - - xml_node n(impl::append_node(_root, impl::get_allocator(_root), type_)); - - if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); - - return n; - } - - PUGI__FN xml_node xml_node::prepend_child(xml_node_type type_) - { - if (!impl::allow_insert_child(this->type(), type_)) return xml_node(); - - xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); - if (!n) return xml_node(); - - n._root->parent = _root; - - xml_node_struct* head = _root->first_child; - - if (head) - { - n._root->prev_sibling_c = head->prev_sibling_c; - head->prev_sibling_c = n._root; - } - else - n._root->prev_sibling_c = n._root; - - n._root->next_sibling = head; - _root->first_child = n._root; - - if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); - - return n; - } - - PUGI__FN xml_node xml_node::insert_child_before(xml_node_type type_, const xml_node& node) - { - if (!impl::allow_insert_child(this->type(), type_)) return xml_node(); - if (!node._root || node._root->parent != _root) return xml_node(); - - xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); - if (!n) return xml_node(); - - n._root->parent = _root; - - if (node._root->prev_sibling_c->next_sibling) - node._root->prev_sibling_c->next_sibling = n._root; - else - _root->first_child = n._root; - - n._root->prev_sibling_c = node._root->prev_sibling_c; - n._root->next_sibling = node._root; - node._root->prev_sibling_c = n._root; - - if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); - - return n; - } - - PUGI__FN xml_node xml_node::insert_child_after(xml_node_type type_, const xml_node& node) - { - if (!impl::allow_insert_child(this->type(), type_)) return xml_node(); - if (!node._root || node._root->parent != _root) return xml_node(); - - xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); - if (!n) return xml_node(); - - n._root->parent = _root; - - if (node._root->next_sibling) - node._root->next_sibling->prev_sibling_c = n._root; - else - _root->first_child->prev_sibling_c = n._root; - - n._root->next_sibling = node._root->next_sibling; - n._root->prev_sibling_c = node._root; - node._root->next_sibling = n._root; - - if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); - - return n; - } - - PUGI__FN xml_node xml_node::append_child(const char_t* name_) - { - xml_node result = append_child(node_element); - - result.set_name(name_); - - return result; - } - - PUGI__FN xml_node xml_node::prepend_child(const char_t* name_) - { - xml_node result = prepend_child(node_element); - - result.set_name(name_); - - return result; - } - - PUGI__FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node) - { - xml_node result = insert_child_after(node_element, node); - - result.set_name(name_); - - return result; - } - - PUGI__FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node) - { - xml_node result = insert_child_before(node_element, node); - - result.set_name(name_); - - return result; - } - - PUGI__FN xml_node xml_node::append_copy(const xml_node& proto) - { - xml_node result = append_child(proto.type()); - - if (result) impl::recursive_copy_skip(result, proto, result); - - return result; - } - - PUGI__FN xml_node xml_node::prepend_copy(const xml_node& proto) - { - xml_node result = prepend_child(proto.type()); - - if (result) impl::recursive_copy_skip(result, proto, result); - - return result; - } - - PUGI__FN xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node) - { - xml_node result = insert_child_after(proto.type(), node); - - if (result) impl::recursive_copy_skip(result, proto, result); - - return result; - } - - PUGI__FN xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node) - { - xml_node result = insert_child_before(proto.type(), node); - - if (result) impl::recursive_copy_skip(result, proto, result); - - return result; - } - - PUGI__FN bool xml_node::remove_attribute(const char_t* name_) - { - return remove_attribute(attribute(name_)); - } - - PUGI__FN bool xml_node::remove_attribute(const xml_attribute& a) - { - if (!_root || !a._attr) return false; - - // check that attribute belongs to *this - xml_attribute_struct* attr = a._attr; - - while (attr->prev_attribute_c->next_attribute) attr = attr->prev_attribute_c; - - if (attr != _root->first_attribute) return false; - - if (a._attr->next_attribute) a._attr->next_attribute->prev_attribute_c = a._attr->prev_attribute_c; - else if (_root->first_attribute) _root->first_attribute->prev_attribute_c = a._attr->prev_attribute_c; - - if (a._attr->prev_attribute_c->next_attribute) a._attr->prev_attribute_c->next_attribute = a._attr->next_attribute; - else _root->first_attribute = a._attr->next_attribute; - - impl::destroy_attribute(a._attr, impl::get_allocator(_root)); - - return true; - } - - PUGI__FN bool xml_node::remove_child(const char_t* name_) - { - return remove_child(child(name_)); - } - - PUGI__FN bool xml_node::remove_child(const xml_node& n) - { - if (!_root || !n._root || n._root->parent != _root) return false; - - if (n._root->next_sibling) n._root->next_sibling->prev_sibling_c = n._root->prev_sibling_c; - else if (_root->first_child) _root->first_child->prev_sibling_c = n._root->prev_sibling_c; - - if (n._root->prev_sibling_c->next_sibling) n._root->prev_sibling_c->next_sibling = n._root->next_sibling; - else _root->first_child = n._root->next_sibling; - - impl::destroy_node(n._root, impl::get_allocator(_root)); - - return true; - } - - PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const - { - if (!_root) return xml_node(); - - for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - if (i->name && impl::strequal(name_, i->name)) - { - for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) - if (impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value)) - return xml_node(i); - } - - return xml_node(); - } - - PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const - { - if (!_root) return xml_node(); - - for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) - if (impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value)) - return xml_node(i); - - return xml_node(); - } - -#ifndef PUGIXML_NO_STL - PUGI__FN string_t xml_node::path(char_t delimiter) const - { - xml_node cursor = *this; // Make a copy. - - string_t result = cursor.name(); - - while (cursor.parent()) - { - cursor = cursor.parent(); - - string_t temp = cursor.name(); - temp += delimiter; - temp += result; - result.swap(temp); - } - - return result; - } -#endif - - PUGI__FN xml_node xml_node::first_element_by_path(const char_t* path_, char_t delimiter) const - { - xml_node found = *this; // Current search context. - - if (!_root || !path_ || !path_[0]) return found; - - if (path_[0] == delimiter) - { - // Absolute path; e.g. '/foo/bar' - found = found.root(); - ++path_; - } - - const char_t* path_segment = path_; - - while (*path_segment == delimiter) ++path_segment; - - const char_t* path_segment_end = path_segment; - - while (*path_segment_end && *path_segment_end != delimiter) ++path_segment_end; - - if (path_segment == path_segment_end) return found; - - const char_t* next_segment = path_segment_end; - - while (*next_segment == delimiter) ++next_segment; - - if (*path_segment == '.' && path_segment + 1 == path_segment_end) - return found.first_element_by_path(next_segment, delimiter); - else if (*path_segment == '.' && *(path_segment+1) == '.' && path_segment + 2 == path_segment_end) - return found.parent().first_element_by_path(next_segment, delimiter); - else - { - for (xml_node_struct* j = found._root->first_child; j; j = j->next_sibling) - { - if (j->name && impl::strequalrange(j->name, path_segment, static_cast(path_segment_end - path_segment))) - { - xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter); - - if (subsearch) return subsearch; - } - } - - return xml_node(); - } - } - - PUGI__FN bool xml_node::traverse(xml_tree_walker& walker) - { - walker._depth = -1; - - xml_node arg_begin = *this; - if (!walker.begin(arg_begin)) return false; - - xml_node cur = first_child(); - - if (cur) - { - ++walker._depth; - - do - { - xml_node arg_for_each = cur; - if (!walker.for_each(arg_for_each)) - return false; - - if (cur.first_child()) - { - ++walker._depth; - cur = cur.first_child(); - } - else if (cur.next_sibling()) - cur = cur.next_sibling(); - else - { - // Borland C++ workaround - while (!cur.next_sibling() && cur != *this && !cur.parent().empty()) - { - --walker._depth; - cur = cur.parent(); - } - - if (cur != *this) - cur = cur.next_sibling(); - } - } - while (cur && cur != *this); - } - - assert(walker._depth == -1); - - xml_node arg_end = *this; - return walker.end(arg_end); - } - - PUGI__FN size_t xml_node::hash_value() const - { - return static_cast(reinterpret_cast(_root) / sizeof(xml_node_struct)); - } - - PUGI__FN xml_node_struct* xml_node::internal_object() const - { - return _root; - } - - PUGI__FN void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const - { - if (!_root) return; - - impl::xml_buffered_writer buffered_writer(writer, encoding); - - impl::node_output(buffered_writer, *this, indent, flags, depth); - } - -#ifndef PUGIXML_NO_STL - PUGI__FN void xml_node::print(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const - { - xml_writer_stream writer(stream); - - print(writer, indent, flags, encoding, depth); - } - - PUGI__FN void xml_node::print(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, unsigned int depth) const - { - xml_writer_stream writer(stream); - - print(writer, indent, flags, encoding_wchar, depth); - } -#endif - - PUGI__FN ptrdiff_t xml_node::offset_debug() const - { - xml_node_struct* r = root()._root; - - if (!r) return -1; - - const char_t* buffer = static_cast(r)->buffer; - - if (!buffer) return -1; - - switch (type()) - { - case node_document: - return 0; - - case node_element: - case node_declaration: - case node_pi: - return (_root->header & impl::xml_memory_page_name_allocated_mask) ? -1 : _root->name - buffer; - - case node_pcdata: - case node_cdata: - case node_comment: - case node_doctype: - return (_root->header & impl::xml_memory_page_value_allocated_mask) ? -1 : _root->value - buffer; - - default: - return -1; - } - } - -#ifdef __BORLANDC__ - PUGI__FN bool operator&&(const xml_node& lhs, bool rhs) - { - return (bool)lhs && rhs; - } - - PUGI__FN bool operator||(const xml_node& lhs, bool rhs) - { - return (bool)lhs || rhs; - } -#endif - - PUGI__FN xml_text::xml_text(xml_node_struct* root): _root(root) - { - } - - PUGI__FN xml_node_struct* xml_text::_data() const - { - if (!_root || impl::is_text_node(_root)) return _root; - - for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling) - if (impl::is_text_node(node)) - return node; - - return 0; - } - - PUGI__FN xml_node_struct* xml_text::_data_new() - { - xml_node_struct* d = _data(); - if (d) return d; - - return xml_node(_root).append_child(node_pcdata).internal_object(); - } - - PUGI__FN xml_text::xml_text(): _root(0) - { - } - - PUGI__FN static void unspecified_bool_xml_text(xml_text***) - { - } - - PUGI__FN xml_text::operator xml_text::unspecified_bool_type() const - { - return _data() ? unspecified_bool_xml_text : 0; - } - - PUGI__FN bool xml_text::operator!() const - { - return !_data(); - } - - PUGI__FN bool xml_text::empty() const - { - return _data() == 0; - } - - PUGI__FN const char_t* xml_text::get() const - { - xml_node_struct* d = _data(); - - return (d && d->value) ? d->value : PUGIXML_TEXT(""); - } - - PUGI__FN const char_t* xml_text::as_string(const char_t* def) const - { - xml_node_struct* d = _data(); - - return (d && d->value) ? d->value : def; - } - - PUGI__FN int xml_text::as_int(int def) const - { - xml_node_struct* d = _data(); - - return impl::get_value_int(d ? d->value : 0, def); - } - - PUGI__FN unsigned int xml_text::as_uint(unsigned int def) const - { - xml_node_struct* d = _data(); - - return impl::get_value_uint(d ? d->value : 0, def); - } - - PUGI__FN double xml_text::as_double(double def) const - { - xml_node_struct* d = _data(); - - return impl::get_value_double(d ? d->value : 0, def); - } - - PUGI__FN float xml_text::as_float(float def) const - { - xml_node_struct* d = _data(); - - return impl::get_value_float(d ? d->value : 0, def); - } - - PUGI__FN bool xml_text::as_bool(bool def) const - { - xml_node_struct* d = _data(); - - return impl::get_value_bool(d ? d->value : 0, def); - } - - PUGI__FN bool xml_text::set(const char_t* rhs) - { - xml_node_struct* dn = _data_new(); - - return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; - } - - PUGI__FN bool xml_text::set(int rhs) - { - xml_node_struct* dn = _data_new(); - - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; - } - - PUGI__FN bool xml_text::set(unsigned int rhs) - { - xml_node_struct* dn = _data_new(); - - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; - } - - PUGI__FN bool xml_text::set(double rhs) - { - xml_node_struct* dn = _data_new(); - - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; - } - - PUGI__FN bool xml_text::set(bool rhs) - { - xml_node_struct* dn = _data_new(); - - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; - } - - PUGI__FN xml_text& xml_text::operator=(const char_t* rhs) - { - set(rhs); - return *this; - } - - PUGI__FN xml_text& xml_text::operator=(int rhs) - { - set(rhs); - return *this; - } - - PUGI__FN xml_text& xml_text::operator=(unsigned int rhs) - { - set(rhs); - return *this; - } - - PUGI__FN xml_text& xml_text::operator=(double rhs) - { - set(rhs); - return *this; - } - - PUGI__FN xml_text& xml_text::operator=(bool rhs) - { - set(rhs); - return *this; - } - - PUGI__FN xml_node xml_text::data() const - { - return xml_node(_data()); - } - -#ifdef __BORLANDC__ - PUGI__FN bool operator&&(const xml_text& lhs, bool rhs) - { - return (bool)lhs && rhs; - } - - PUGI__FN bool operator||(const xml_text& lhs, bool rhs) - { - return (bool)lhs || rhs; - } -#endif - - PUGI__FN xml_node_iterator::xml_node_iterator() - { - } - - PUGI__FN xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent()) - { - } - - PUGI__FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) - { - } - - PUGI__FN bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const - { - return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; - } - - PUGI__FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const - { - return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; - } - - PUGI__FN xml_node& xml_node_iterator::operator*() const - { - assert(_wrap._root); - return _wrap; - } - - PUGI__FN xml_node* xml_node_iterator::operator->() const - { - assert(_wrap._root); - return const_cast(&_wrap); // BCC32 workaround - } - - PUGI__FN const xml_node_iterator& xml_node_iterator::operator++() - { - assert(_wrap._root); - _wrap._root = _wrap._root->next_sibling; - return *this; - } - - PUGI__FN xml_node_iterator xml_node_iterator::operator++(int) - { - xml_node_iterator temp = *this; - ++*this; - return temp; - } - - PUGI__FN const xml_node_iterator& xml_node_iterator::operator--() - { - _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child(); - return *this; - } - - PUGI__FN xml_node_iterator xml_node_iterator::operator--(int) - { - xml_node_iterator temp = *this; - --*this; - return temp; - } - - PUGI__FN xml_attribute_iterator::xml_attribute_iterator() - { - } - - PUGI__FN xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent) - { - } - - PUGI__FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) - { - } - - PUGI__FN bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const - { - return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root; - } - - PUGI__FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const - { - return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root; - } - - PUGI__FN xml_attribute& xml_attribute_iterator::operator*() const - { - assert(_wrap._attr); - return _wrap; - } - - PUGI__FN xml_attribute* xml_attribute_iterator::operator->() const - { - assert(_wrap._attr); - return const_cast(&_wrap); // BCC32 workaround - } - - PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator++() - { - assert(_wrap._attr); - _wrap._attr = _wrap._attr->next_attribute; - return *this; - } - - PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator++(int) - { - xml_attribute_iterator temp = *this; - ++*this; - return temp; - } - - PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator--() - { - _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute(); - return *this; - } - - PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator--(int) - { - xml_attribute_iterator temp = *this; - --*this; - return temp; - } - - PUGI__FN xml_named_node_iterator::xml_named_node_iterator(): _name(0) - { - } - - PUGI__FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, const char_t* name): _node(node), _name(name) - { - } - - PUGI__FN bool xml_named_node_iterator::operator==(const xml_named_node_iterator& rhs) const - { - return _node == rhs._node; - } - - PUGI__FN bool xml_named_node_iterator::operator!=(const xml_named_node_iterator& rhs) const - { - return _node != rhs._node; - } - - PUGI__FN xml_node& xml_named_node_iterator::operator*() const - { - assert(_node._root); - return _node; - } - - PUGI__FN xml_node* xml_named_node_iterator::operator->() const - { - assert(_node._root); - return const_cast(&_node); // BCC32 workaround - } - - PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator++() - { - assert(_node._root); - _node = _node.next_sibling(_name); - return *this; - } - - PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator++(int) - { - xml_named_node_iterator temp = *this; - ++*this; - return temp; - } - - PUGI__FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto) - { - } - - PUGI__FN xml_parse_result::operator bool() const - { - return status == status_ok; - } - - PUGI__FN const char* xml_parse_result::description() const - { - switch (status) - { - case status_ok: return "No error"; - - case status_file_not_found: return "File was not found"; - case status_io_error: return "Error reading from file/stream"; - case status_out_of_memory: return "Could not allocate memory"; - case status_internal_error: return "Internal error occurred"; - - case status_unrecognized_tag: return "Could not determine tag type"; - - case status_bad_pi: return "Error parsing document declaration/processing instruction"; - case status_bad_comment: return "Error parsing comment"; - case status_bad_cdata: return "Error parsing CDATA section"; - case status_bad_doctype: return "Error parsing document type declaration"; - case status_bad_pcdata: return "Error parsing PCDATA section"; - case status_bad_start_element: return "Error parsing start element tag"; - case status_bad_attribute: return "Error parsing element attribute"; - case status_bad_end_element: return "Error parsing end element tag"; - case status_end_element_mismatch: return "Start-end tags mismatch"; - - default: return "Unknown error"; - } - } - - PUGI__FN xml_document::xml_document(): _buffer(0) - { - create(); - } - - PUGI__FN xml_document::~xml_document() - { - destroy(); - } - - PUGI__FN void xml_document::reset() - { - destroy(); - create(); - } - - PUGI__FN void xml_document::reset(const xml_document& proto) - { - reset(); - - for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling()) - append_copy(cur); - } - - PUGI__FN void xml_document::create() - { - // initialize sentinel page - PUGI__STATIC_ASSERT(offsetof(impl::xml_memory_page, data) + sizeof(impl::xml_document_struct) + impl::xml_memory_page_alignment <= sizeof(_memory)); - - // align upwards to page boundary - void* page_memory = reinterpret_cast((reinterpret_cast(_memory) + (impl::xml_memory_page_alignment - 1)) & ~(impl::xml_memory_page_alignment - 1)); - - // prepare page structure - impl::xml_memory_page* page = impl::xml_memory_page::construct(page_memory); - - page->busy_size = impl::xml_memory_page_size; - - // allocate new root - _root = new (page->data) impl::xml_document_struct(page); - _root->prev_sibling_c = _root; - - // setup sentinel page - page->allocator = static_cast(_root); - } - - PUGI__FN void xml_document::destroy() - { - // destroy static storage - if (_buffer) - { - impl::xml_memory::deallocate(_buffer); - _buffer = 0; - } - - // destroy dynamic storage, leave sentinel page (it's in static memory) - if (_root) - { - impl::xml_memory_page* root_page = reinterpret_cast(_root->header & impl::xml_memory_page_pointer_mask); - assert(root_page && !root_page->prev && !root_page->memory); - - // destroy all pages - for (impl::xml_memory_page* page = root_page->next; page; ) - { - impl::xml_memory_page* next = page->next; - - impl::xml_allocator::deallocate_page(page); - - page = next; - } - - // cleanup root page - root_page->allocator = 0; - root_page->next = 0; - root_page->busy_size = root_page->freed_size = 0; - - _root = 0; - } - } - -#ifndef PUGIXML_NO_STL - PUGI__FN xml_parse_result xml_document::load(std::basic_istream >& stream, unsigned int options, xml_encoding encoding) - { - reset(); - - return impl::load_stream_impl(*this, stream, options, encoding); - } - - PUGI__FN xml_parse_result xml_document::load(std::basic_istream >& stream, unsigned int options) - { - reset(); - - return impl::load_stream_impl(*this, stream, options, encoding_wchar); - } -#endif - - PUGI__FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options) - { - // Force native encoding (skip autodetection) - #ifdef PUGIXML_WCHAR_MODE - xml_encoding encoding = encoding_wchar; - #else - xml_encoding encoding = encoding_utf8; - #endif - - return load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding); - } - - PUGI__FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding) - { - reset(); - - FILE* file = fopen(path_, "rb"); - - return impl::load_file_impl(*this, file, options, encoding); - } - - PUGI__FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding) - { - reset(); - - FILE* file = impl::open_file_wide(path_, L"rb"); - - return impl::load_file_impl(*this, file, options, encoding); - } - - PUGI__FN xml_parse_result xml_document::load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own) - { - reset(); - - // check input buffer - assert(contents || size == 0); - - // get actual encoding - xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size); - - // get private buffer - char_t* buffer = 0; - size_t length = 0; - - if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory); - - // delete original buffer if we performed a conversion - if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents); - - // parse - xml_parse_result res = impl::xml_parser::parse(buffer, length, _root, options); - - // remember encoding - res.encoding = buffer_encoding; - - // grab onto buffer if it's our buffer, user is responsible for deallocating contens himself - if (own || buffer != contents) _buffer = buffer; - - return res; - } - - PUGI__FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) - { - return load_buffer_impl(const_cast(contents), size, options, encoding, false, false); - } - - PUGI__FN xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding) - { - return load_buffer_impl(contents, size, options, encoding, true, false); - } - - PUGI__FN xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding) - { - return load_buffer_impl(contents, size, options, encoding, true, true); - } - - PUGI__FN void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const - { - impl::xml_buffered_writer buffered_writer(writer, encoding); - - if ((flags & format_write_bom) && encoding != encoding_latin1) - { - // BOM always represents the codepoint U+FEFF, so just write it in native encoding - #ifdef PUGIXML_WCHAR_MODE - unsigned int bom = 0xfeff; - buffered_writer.write(static_cast(bom)); - #else - buffered_writer.write('\xef', '\xbb', '\xbf'); - #endif - } - - if (!(flags & format_no_declaration) && !impl::has_declaration(*this)) - { - buffered_writer.write(PUGIXML_TEXT("'); - if (!(flags & format_raw)) buffered_writer.write('\n'); - } - - impl::node_output(buffered_writer, *this, indent, flags, 0); - } - -#ifndef PUGIXML_NO_STL - PUGI__FN void xml_document::save(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const - { - xml_writer_stream writer(stream); - - save(writer, indent, flags, encoding); - } - - PUGI__FN void xml_document::save(std::basic_ostream >& stream, const char_t* indent, unsigned int flags) const - { - xml_writer_stream writer(stream); - - save(writer, indent, flags, encoding_wchar); - } -#endif - - PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const - { - FILE* file = fopen(path_, (flags & format_save_file_text) ? "w" : "wb"); - return impl::save_file_impl(*this, file, indent, flags, encoding); - } - - PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const - { - FILE* file = impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"); - return impl::save_file_impl(*this, file, indent, flags, encoding); - } - - PUGI__FN xml_node xml_document::document_element() const - { - for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - if ((i->header & impl::xml_memory_page_type_mask) + 1 == node_element) - return xml_node(i); - - return xml_node(); - } - -#ifndef PUGIXML_NO_STL - PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str) - { - assert(str); - - return impl::as_utf8_impl(str, wcslen(str)); - } - - PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string& str) - { - return impl::as_utf8_impl(str.c_str(), str.size()); - } - - PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const char* str) - { - assert(str); - - return impl::as_wide_impl(str, strlen(str)); - } - - PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const std::string& str) - { - return impl::as_wide_impl(str.c_str(), str.size()); - } -#endif - - PUGI__FN void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate) - { - impl::xml_memory::allocate = allocate; - impl::xml_memory::deallocate = deallocate; - } - - PUGI__FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function() - { - return impl::xml_memory::allocate; - } - - PUGI__FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function() - { - return impl::xml_memory::deallocate; - } -} - -#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) -namespace std -{ - // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) - PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&) - { - return std::bidirectional_iterator_tag(); - } - - PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&) - { - return std::bidirectional_iterator_tag(); - } - - PUGI__FN std::forward_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator&) - { - return std::forward_iterator_tag(); - } -} -#endif - -#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) -namespace std -{ - // Workarounds for (non-standard) iterator category detection - PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator&) - { - return std::bidirectional_iterator_tag(); - } - - PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator&) - { - return std::bidirectional_iterator_tag(); - } - - PUGI__FN std::forward_iterator_tag __iterator_category(const pugi::xml_named_node_iterator&) - { - return std::forward_iterator_tag(); - } -} -#endif - -#ifndef PUGIXML_NO_XPATH - -// STL replacements -PUGI__NS_BEGIN - struct equal_to - { - template bool operator()(const T& lhs, const T& rhs) const - { - return lhs == rhs; - } - }; - - struct not_equal_to - { - template bool operator()(const T& lhs, const T& rhs) const - { - return lhs != rhs; - } - }; - - struct less - { - template bool operator()(const T& lhs, const T& rhs) const - { - return lhs < rhs; - } - }; - - struct less_equal - { - template bool operator()(const T& lhs, const T& rhs) const - { - return lhs <= rhs; - } - }; - - template void swap(T& lhs, T& rhs) - { - T temp = lhs; - lhs = rhs; - rhs = temp; - } - - template I min_element(I begin, I end, const Pred& pred) - { - I result = begin; - - for (I it = begin + 1; it != end; ++it) - if (pred(*it, *result)) - result = it; - - return result; - } - - template void reverse(I begin, I end) - { - while (begin + 1 < end) swap(*begin++, *--end); - } - - template I unique(I begin, I end) - { - // fast skip head - while (begin + 1 < end && *begin != *(begin + 1)) begin++; - - if (begin == end) return begin; - - // last written element - I write = begin++; - - // merge unique elements - while (begin != end) - { - if (*begin != *write) - *++write = *begin++; - else - begin++; - } - - // past-the-end (write points to live element) - return write + 1; - } - - template void copy_backwards(I begin, I end, I target) - { - while (begin != end) *--target = *--end; - } - - template void insertion_sort(I begin, I end, const Pred& pred, T*) - { - assert(begin != end); - - for (I it = begin + 1; it != end; ++it) - { - T val = *it; - - if (pred(val, *begin)) - { - // move to front - copy_backwards(begin, it, it + 1); - *begin = val; - } - else - { - I hole = it; - - // move hole backwards - while (pred(val, *(hole - 1))) - { - *hole = *(hole - 1); - hole--; - } - - // fill hole with element - *hole = val; - } - } - } - - // std variant for elements with == - template void partition(I begin, I middle, I end, const Pred& pred, I* out_eqbeg, I* out_eqend) - { - I eqbeg = middle, eqend = middle + 1; - - // expand equal range - while (eqbeg != begin && *(eqbeg - 1) == *eqbeg) --eqbeg; - while (eqend != end && *eqend == *eqbeg) ++eqend; - - // process outer elements - I ltend = eqbeg, gtbeg = eqend; - - for (;;) - { - // find the element from the right side that belongs to the left one - for (; gtbeg != end; ++gtbeg) - if (!pred(*eqbeg, *gtbeg)) - { - if (*gtbeg == *eqbeg) swap(*gtbeg, *eqend++); - else break; - } - - // find the element from the left side that belongs to the right one - for (; ltend != begin; --ltend) - if (!pred(*(ltend - 1), *eqbeg)) - { - if (*eqbeg == *(ltend - 1)) swap(*(ltend - 1), *--eqbeg); - else break; - } - - // scanned all elements - if (gtbeg == end && ltend == begin) - { - *out_eqbeg = eqbeg; - *out_eqend = eqend; - return; - } - - // make room for elements by moving equal area - if (gtbeg == end) - { - if (--ltend != --eqbeg) swap(*ltend, *eqbeg); - swap(*eqbeg, *--eqend); - } - else if (ltend == begin) - { - if (eqend != gtbeg) swap(*eqbeg, *eqend); - ++eqend; - swap(*gtbeg++, *eqbeg++); - } - else swap(*gtbeg++, *--ltend); - } - } - - template void median3(I first, I middle, I last, const Pred& pred) - { - if (pred(*middle, *first)) swap(*middle, *first); - if (pred(*last, *middle)) swap(*last, *middle); - if (pred(*middle, *first)) swap(*middle, *first); - } - - template void median(I first, I middle, I last, const Pred& pred) - { - if (last - first <= 40) - { - // median of three for small chunks - median3(first, middle, last, pred); - } - else - { - // median of nine - size_t step = (last - first + 1) / 8; - - median3(first, first + step, first + 2 * step, pred); - median3(middle - step, middle, middle + step, pred); - median3(last - 2 * step, last - step, last, pred); - median3(first + step, middle, last - step, pred); - } - } - - template void sort(I begin, I end, const Pred& pred) - { - // sort large chunks - while (end - begin > 32) - { - // find median element - I middle = begin + (end - begin) / 2; - median(begin, middle, end - 1, pred); - - // partition in three chunks (< = >) - I eqbeg, eqend; - partition(begin, middle, end, pred, &eqbeg, &eqend); - - // loop on larger half - if (eqbeg - begin > end - eqend) - { - sort(eqend, end, pred); - end = eqbeg; - } - else - { - sort(begin, eqbeg, pred); - begin = eqend; - } - } - - // insertion sort small chunk - if (begin != end) insertion_sort(begin, end, pred, &*begin); - } -PUGI__NS_END - -// Allocator used for AST and evaluation stacks -PUGI__NS_BEGIN - struct xpath_memory_block - { - xpath_memory_block* next; - - char data[ - #ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE - PUGIXML_MEMORY_XPATH_PAGE_SIZE - #else - 4096 - #endif - ]; - }; - - class xpath_allocator - { - xpath_memory_block* _root; - size_t _root_size; - - public: - #ifdef PUGIXML_NO_EXCEPTIONS - jmp_buf* error_handler; - #endif - - xpath_allocator(xpath_memory_block* root, size_t root_size = 0): _root(root), _root_size(root_size) - { - #ifdef PUGIXML_NO_EXCEPTIONS - error_handler = 0; - #endif - } - - void* allocate_nothrow(size_t size) - { - const size_t block_capacity = sizeof(_root->data); - - // align size so that we're able to store pointers in subsequent blocks - size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); - - if (_root_size + size <= block_capacity) - { - void* buf = _root->data + _root_size; - _root_size += size; - return buf; - } - else - { - size_t block_data_size = (size > block_capacity) ? size : block_capacity; - size_t block_size = block_data_size + offsetof(xpath_memory_block, data); - - xpath_memory_block* block = static_cast(xml_memory::allocate(block_size)); - if (!block) return 0; - - block->next = _root; - - _root = block; - _root_size = size; - - return block->data; - } - } - - void* allocate(size_t size) - { - void* result = allocate_nothrow(size); - - if (!result) - { - #ifdef PUGIXML_NO_EXCEPTIONS - assert(error_handler); - longjmp(*error_handler, 1); - #else - throw std::bad_alloc(); - #endif - } - - return result; - } - - void* reallocate(void* ptr, size_t old_size, size_t new_size) - { - // align size so that we're able to store pointers in subsequent blocks - old_size = (old_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); - new_size = (new_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); - - // we can only reallocate the last object - assert(ptr == 0 || static_cast(ptr) + old_size == _root->data + _root_size); - - // adjust root size so that we have not allocated the object at all - bool only_object = (_root_size == old_size); - - if (ptr) _root_size -= old_size; - - // allocate a new version (this will obviously reuse the memory if possible) - void* result = allocate(new_size); - assert(result); - - // we have a new block - if (result != ptr && ptr) - { - // copy old data - assert(new_size > old_size); - memcpy(result, ptr, old_size); - - // free the previous page if it had no other objects - if (only_object) - { - assert(_root->data == result); - assert(_root->next); - - xpath_memory_block* next = _root->next->next; - - if (next) - { - // deallocate the whole page, unless it was the first one - xml_memory::deallocate(_root->next); - _root->next = next; - } - } - } - - return result; - } - - void revert(const xpath_allocator& state) - { - // free all new pages - xpath_memory_block* cur = _root; - - while (cur != state._root) - { - xpath_memory_block* next = cur->next; - - xml_memory::deallocate(cur); - - cur = next; - } - - // restore state - _root = state._root; - _root_size = state._root_size; - } - - void release() - { - xpath_memory_block* cur = _root; - assert(cur); - - while (cur->next) - { - xpath_memory_block* next = cur->next; - - xml_memory::deallocate(cur); - - cur = next; - } - } - }; - - struct xpath_allocator_capture - { - xpath_allocator_capture(xpath_allocator* alloc): _target(alloc), _state(*alloc) - { - } - - ~xpath_allocator_capture() - { - _target->revert(_state); - } - - xpath_allocator* _target; - xpath_allocator _state; - }; - - struct xpath_stack - { - xpath_allocator* result; - xpath_allocator* temp; - }; - - struct xpath_stack_data - { - xpath_memory_block blocks[2]; - xpath_allocator result; - xpath_allocator temp; - xpath_stack stack; - - #ifdef PUGIXML_NO_EXCEPTIONS - jmp_buf error_handler; - #endif - - xpath_stack_data(): result(blocks + 0), temp(blocks + 1) - { - blocks[0].next = blocks[1].next = 0; - - stack.result = &result; - stack.temp = &temp; - - #ifdef PUGIXML_NO_EXCEPTIONS - result.error_handler = temp.error_handler = &error_handler; - #endif - } - - ~xpath_stack_data() - { - result.release(); - temp.release(); - } - }; -PUGI__NS_END - -// String class -PUGI__NS_BEGIN - class xpath_string - { - const char_t* _buffer; - bool _uses_heap; - - static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc) - { - char_t* result = static_cast(alloc->allocate((length + 1) * sizeof(char_t))); - assert(result); - - memcpy(result, string, length * sizeof(char_t)); - result[length] = 0; - - return result; - } - - static char_t* duplicate_string(const char_t* string, xpath_allocator* alloc) - { - return duplicate_string(string, strlength(string), alloc); - } - - public: - xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false) - { - } - - explicit xpath_string(const char_t* str, xpath_allocator* alloc) - { - bool empty_ = (*str == 0); - - _buffer = empty_ ? PUGIXML_TEXT("") : duplicate_string(str, alloc); - _uses_heap = !empty_; - } - - explicit xpath_string(const char_t* str, bool use_heap): _buffer(str), _uses_heap(use_heap) - { - } - - xpath_string(const char_t* begin, const char_t* end, xpath_allocator* alloc) - { - assert(begin <= end); - - bool empty_ = (begin == end); - - _buffer = empty_ ? PUGIXML_TEXT("") : duplicate_string(begin, static_cast(end - begin), alloc); - _uses_heap = !empty_; - } - - void append(const xpath_string& o, xpath_allocator* alloc) - { - // skip empty sources - if (!*o._buffer) return; - - // fast append for constant empty target and constant source - if (!*_buffer && !_uses_heap && !o._uses_heap) - { - _buffer = o._buffer; - } - else - { - // need to make heap copy - size_t target_length = strlength(_buffer); - size_t source_length = strlength(o._buffer); - size_t result_length = target_length + source_length; - - // allocate new buffer - char_t* result = static_cast(alloc->reallocate(_uses_heap ? const_cast(_buffer) : 0, (target_length + 1) * sizeof(char_t), (result_length + 1) * sizeof(char_t))); - assert(result); - - // append first string to the new buffer in case there was no reallocation - if (!_uses_heap) memcpy(result, _buffer, target_length * sizeof(char_t)); - - // append second string to the new buffer - memcpy(result + target_length, o._buffer, source_length * sizeof(char_t)); - result[result_length] = 0; - - // finalize - _buffer = result; - _uses_heap = true; - } - } - - const char_t* c_str() const - { - return _buffer; - } - - size_t length() const - { - return strlength(_buffer); - } - - char_t* data(xpath_allocator* alloc) - { - // make private heap copy - if (!_uses_heap) - { - _buffer = duplicate_string(_buffer, alloc); - _uses_heap = true; - } - - return const_cast(_buffer); - } - - bool empty() const - { - return *_buffer == 0; - } - - bool operator==(const xpath_string& o) const - { - return strequal(_buffer, o._buffer); - } - - bool operator!=(const xpath_string& o) const - { - return !strequal(_buffer, o._buffer); - } - - bool uses_heap() const - { - return _uses_heap; - } - }; - - PUGI__FN xpath_string xpath_string_const(const char_t* str) - { - return xpath_string(str, false); - } -PUGI__NS_END - -PUGI__NS_BEGIN - PUGI__FN bool starts_with(const char_t* string, const char_t* pattern) - { - while (*pattern && *string == *pattern) - { - string++; - pattern++; - } - - return *pattern == 0; - } - - PUGI__FN const char_t* find_char(const char_t* s, char_t c) - { - #ifdef PUGIXML_WCHAR_MODE - return wcschr(s, c); - #else - return strchr(s, c); - #endif - } - - PUGI__FN const char_t* find_substring(const char_t* s, const char_t* p) - { - #ifdef PUGIXML_WCHAR_MODE - // MSVC6 wcsstr bug workaround (if s is empty it always returns 0) - return (*p == 0) ? s : wcsstr(s, p); - #else - return strstr(s, p); - #endif - } - - // Converts symbol to lower case, if it is an ASCII one - PUGI__FN char_t tolower_ascii(char_t ch) - { - return static_cast(ch - 'A') < 26 ? static_cast(ch | ' ') : ch; - } - - PUGI__FN xpath_string string_value(const xpath_node& na, xpath_allocator* alloc) - { - if (na.attribute()) - return xpath_string_const(na.attribute().value()); - else - { - const xml_node& n = na.node(); - - switch (n.type()) - { - case node_pcdata: - case node_cdata: - case node_comment: - case node_pi: - return xpath_string_const(n.value()); - - case node_document: - case node_element: - { - xpath_string result; - - xml_node cur = n.first_child(); - - while (cur && cur != n) - { - if (cur.type() == node_pcdata || cur.type() == node_cdata) - result.append(xpath_string_const(cur.value()), alloc); - - if (cur.first_child()) - cur = cur.first_child(); - else if (cur.next_sibling()) - cur = cur.next_sibling(); - else - { - while (!cur.next_sibling() && cur != n) - cur = cur.parent(); - - if (cur != n) cur = cur.next_sibling(); - } - } - - return result; - } - - default: - return xpath_string(); - } - } - } - - PUGI__FN unsigned int node_height(xml_node n) - { - unsigned int result = 0; - - while (n) - { - ++result; - n = n.parent(); - } - - return result; - } - - PUGI__FN bool node_is_before(xml_node ln, unsigned int lh, xml_node rn, unsigned int rh) - { - // normalize heights - for (unsigned int i = rh; i < lh; i++) ln = ln.parent(); - for (unsigned int j = lh; j < rh; j++) rn = rn.parent(); - - // one node is the ancestor of the other - if (ln == rn) return lh < rh; - - // find common ancestor - while (ln.parent() != rn.parent()) - { - ln = ln.parent(); - rn = rn.parent(); - } - - // there is no common ancestor (the shared parent is null), nodes are from different documents - if (!ln.parent()) return ln < rn; - - // determine sibling order - for (; ln; ln = ln.next_sibling()) - if (ln == rn) - return true; - - return false; - } - - PUGI__FN bool node_is_ancestor(xml_node parent, xml_node node) - { - while (node && node != parent) node = node.parent(); - - return parent && node == parent; - } - - PUGI__FN const void* document_order(const xpath_node& xnode) - { - xml_node_struct* node = xnode.node().internal_object(); - - if (node) - { - if (node->name && (node->header & xml_memory_page_name_allocated_mask) == 0) return node->name; - if (node->value && (node->header & xml_memory_page_value_allocated_mask) == 0) return node->value; - return 0; - } - - xml_attribute_struct* attr = xnode.attribute().internal_object(); - - if (attr) - { - if ((attr->header & xml_memory_page_name_allocated_mask) == 0) return attr->name; - if ((attr->header & xml_memory_page_value_allocated_mask) == 0) return attr->value; - return 0; - } - - return 0; - } - - struct document_order_comparator - { - bool operator()(const xpath_node& lhs, const xpath_node& rhs) const - { - // optimized document order based check - const void* lo = document_order(lhs); - const void* ro = document_order(rhs); - - if (lo && ro) return lo < ro; - - // slow comparison - xml_node ln = lhs.node(), rn = rhs.node(); - - // compare attributes - if (lhs.attribute() && rhs.attribute()) - { - // shared parent - if (lhs.parent() == rhs.parent()) - { - // determine sibling order - for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute()) - if (a == rhs.attribute()) - return true; - - return false; - } - - // compare attribute parents - ln = lhs.parent(); - rn = rhs.parent(); - } - else if (lhs.attribute()) - { - // attributes go after the parent element - if (lhs.parent() == rhs.node()) return false; - - ln = lhs.parent(); - } - else if (rhs.attribute()) - { - // attributes go after the parent element - if (rhs.parent() == lhs.node()) return true; - - rn = rhs.parent(); - } - - if (ln == rn) return false; - - unsigned int lh = node_height(ln); - unsigned int rh = node_height(rn); - - return node_is_before(ln, lh, rn, rh); - } - }; - - struct duplicate_comparator - { - bool operator()(const xpath_node& lhs, const xpath_node& rhs) const - { - if (lhs.attribute()) return rhs.attribute() ? lhs.attribute() < rhs.attribute() : true; - else return rhs.attribute() ? false : lhs.node() < rhs.node(); - } - }; - - PUGI__FN double gen_nan() - { - #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24)) - union { float f; uint32_t i; } u[sizeof(float) == sizeof(uint32_t) ? 1 : -1]; - u[0].i = 0x7fc00000; - return u[0].f; - #else - // fallback - const volatile double zero = 0.0; - return zero / zero; - #endif - } - - PUGI__FN bool is_nan(double value) - { - #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) - return !!_isnan(value); - #elif defined(fpclassify) && defined(FP_NAN) - return fpclassify(value) == FP_NAN; - #else - // fallback - const volatile double v = value; - return v != v; - #endif - } - - PUGI__FN const char_t* convert_number_to_string_special(double value) - { - #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) - if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0; - if (_isnan(value)) return PUGIXML_TEXT("NaN"); - return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); - #elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO) - switch (fpclassify(value)) - { - case FP_NAN: - return PUGIXML_TEXT("NaN"); - - case FP_INFINITE: - return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); - - case FP_ZERO: - return PUGIXML_TEXT("0"); - - default: - return 0; - } - #else - // fallback - const volatile double v = value; - - if (v == 0) return PUGIXML_TEXT("0"); - if (v != v) return PUGIXML_TEXT("NaN"); - if (v * 2 == v) return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); - return 0; - #endif - } - - PUGI__FN bool convert_number_to_boolean(double value) - { - return (value != 0 && !is_nan(value)); - } - - PUGI__FN void truncate_zeros(char* begin, char* end) - { - while (begin != end && end[-1] == '0') end--; - - *end = 0; - } - - // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent -#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE) - PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) - { - // get base values - int sign, exponent; - _ecvt_s(buffer, buffer_size, value, DBL_DIG + 1, &exponent, &sign); - - // truncate redundant zeros - truncate_zeros(buffer, buffer + strlen(buffer)); - - // fill results - *out_mantissa = buffer; - *out_exponent = exponent; - } -#else - PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) - { - // get a scientific notation value with IEEE DBL_DIG decimals - sprintf(buffer, "%.*e", DBL_DIG, value); - assert(strlen(buffer) < buffer_size); - (void)!buffer_size; - - // get the exponent (possibly negative) - char* exponent_string = strchr(buffer, 'e'); - assert(exponent_string); - - int exponent = atoi(exponent_string + 1); - - // extract mantissa string: skip sign - char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer; - assert(mantissa[0] != '0' && mantissa[1] == '.'); - - // divide mantissa by 10 to eliminate integer part - mantissa[1] = mantissa[0]; - mantissa++; - exponent++; - - // remove extra mantissa digits and zero-terminate mantissa - truncate_zeros(mantissa, exponent_string); - - // fill results - *out_mantissa = mantissa; - *out_exponent = exponent; - } -#endif - - PUGI__FN xpath_string convert_number_to_string(double value, xpath_allocator* alloc) - { - // try special number conversion - const char_t* special = convert_number_to_string_special(value); - if (special) return xpath_string_const(special); - - // get mantissa + exponent form - char mantissa_buffer[64]; - - char* mantissa; - int exponent; - convert_number_to_mantissa_exponent(value, mantissa_buffer, sizeof(mantissa_buffer), &mantissa, &exponent); - - // make the number! - char_t result[512]; - char_t* s = result; - - // sign - if (value < 0) *s++ = '-'; - - // integer part - if (exponent <= 0) - { - *s++ = '0'; - } - else - { - while (exponent > 0) - { - assert(*mantissa == 0 || static_cast(*mantissa - '0') <= 9); - *s++ = *mantissa ? *mantissa++ : '0'; - exponent--; - } - } - - // fractional part - if (*mantissa) - { - // decimal point - *s++ = '.'; - - // extra zeroes from negative exponent - while (exponent < 0) - { - *s++ = '0'; - exponent++; - } - - // extra mantissa digits - while (*mantissa) - { - assert(static_cast(*mantissa - '0') <= 9); - *s++ = *mantissa++; - } - } - - // zero-terminate - assert(s < result + sizeof(result) / sizeof(result[0])); - *s = 0; - - return xpath_string(result, alloc); - } - - PUGI__FN bool check_string_to_number_format(const char_t* string) - { - // parse leading whitespace - while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string; - - // parse sign - if (*string == '-') ++string; - - if (!*string) return false; - - // if there is no integer part, there should be a decimal part with at least one digit - if (!PUGI__IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI__IS_CHARTYPEX(string[1], ctx_digit))) return false; - - // parse integer part - while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string; - - // parse decimal part - if (*string == '.') - { - ++string; - - while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string; - } - - // parse trailing whitespace - while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string; - - return *string == 0; - } - - PUGI__FN double convert_string_to_number(const char_t* string) - { - // check string format - if (!check_string_to_number_format(string)) return gen_nan(); - - // parse string - #ifdef PUGIXML_WCHAR_MODE - return wcstod(string, 0); - #else - return atof(string); - #endif - } - - PUGI__FN bool convert_string_to_number(const char_t* begin, const char_t* end, double* out_result) - { - char_t buffer[32]; - - size_t length = static_cast(end - begin); - char_t* scratch = buffer; - - if (length >= sizeof(buffer) / sizeof(buffer[0])) - { - // need to make dummy on-heap copy - scratch = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); - if (!scratch) return false; - } - - // copy string to zero-terminated buffer and perform conversion - memcpy(scratch, begin, length * sizeof(char_t)); - scratch[length] = 0; - - *out_result = convert_string_to_number(scratch); - - // free dummy buffer - if (scratch != buffer) xml_memory::deallocate(scratch); - - return true; - } - - PUGI__FN double round_nearest(double value) - { - return floor(value + 0.5); - } - - PUGI__FN double round_nearest_nzero(double value) - { - // same as round_nearest, but returns -0 for [-0.5, -0] - // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0) - return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5); - } - - PUGI__FN const char_t* qualified_name(const xpath_node& node) - { - return node.attribute() ? node.attribute().name() : node.node().name(); - } - - PUGI__FN const char_t* local_name(const xpath_node& node) - { - const char_t* name = qualified_name(node); - const char_t* p = find_char(name, ':'); - - return p ? p + 1 : name; - } - - struct namespace_uri_predicate - { - const char_t* prefix; - size_t prefix_length; - - namespace_uri_predicate(const char_t* name) - { - const char_t* pos = find_char(name, ':'); - - prefix = pos ? name : 0; - prefix_length = pos ? static_cast(pos - name) : 0; - } - - bool operator()(const xml_attribute& a) const - { - const char_t* name = a.name(); - - if (!starts_with(name, PUGIXML_TEXT("xmlns"))) return false; - - return prefix ? name[5] == ':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0; - } - }; - - PUGI__FN const char_t* namespace_uri(const xml_node& node) - { - namespace_uri_predicate pred = node.name(); - - xml_node p = node; - - while (p) - { - xml_attribute a = p.find_attribute(pred); - - if (a) return a.value(); - - p = p.parent(); - } - - return PUGIXML_TEXT(""); - } - - PUGI__FN const char_t* namespace_uri(const xml_attribute& attr, const xml_node& parent) - { - namespace_uri_predicate pred = attr.name(); - - // Default namespace does not apply to attributes - if (!pred.prefix) return PUGIXML_TEXT(""); - - xml_node p = parent; - - while (p) - { - xml_attribute a = p.find_attribute(pred); - - if (a) return a.value(); - - p = p.parent(); - } - - return PUGIXML_TEXT(""); - } - - PUGI__FN const char_t* namespace_uri(const xpath_node& node) - { - return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node()); - } - - PUGI__FN void normalize_space(char_t* buffer) - { - char_t* write = buffer; - - for (char_t* it = buffer; *it; ) - { - char_t ch = *it++; - - if (PUGI__IS_CHARTYPE(ch, ct_space)) - { - // replace whitespace sequence with single space - while (PUGI__IS_CHARTYPE(*it, ct_space)) it++; - - // avoid leading spaces - if (write != buffer) *write++ = ' '; - } - else *write++ = ch; - } - - // remove trailing space - if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space)) write--; - - // zero-terminate - *write = 0; - } - - PUGI__FN void translate(char_t* buffer, const char_t* from, const char_t* to) - { - size_t to_length = strlength(to); - - char_t* write = buffer; - - while (*buffer) - { - PUGI__DMC_VOLATILE char_t ch = *buffer++; - - const char_t* pos = find_char(from, ch); - - if (!pos) - *write++ = ch; // do not process - else if (static_cast(pos - from) < to_length) - *write++ = to[pos - from]; // replace - } - - // zero-terminate - *write = 0; - } - - struct xpath_variable_boolean: xpath_variable - { - xpath_variable_boolean(): value(false) - { - } - - bool value; - char_t name[1]; - }; - - struct xpath_variable_number: xpath_variable - { - xpath_variable_number(): value(0) - { - } - - double value; - char_t name[1]; - }; - - struct xpath_variable_string: xpath_variable - { - xpath_variable_string(): value(0) - { - } - - ~xpath_variable_string() - { - if (value) xml_memory::deallocate(value); - } - - char_t* value; - char_t name[1]; - }; - - struct xpath_variable_node_set: xpath_variable - { - xpath_node_set value; - char_t name[1]; - }; - - static const xpath_node_set dummy_node_set; - - PUGI__FN unsigned int hash_string(const char_t* str) - { - // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time) - unsigned int result = 0; - - while (*str) - { - result += static_cast(*str++); - result += result << 10; - result ^= result >> 6; - } - - result += result << 3; - result ^= result >> 11; - result += result << 15; - - return result; - } - - template PUGI__FN T* new_xpath_variable(const char_t* name) - { - size_t length = strlength(name); - if (length == 0) return 0; // empty variable names are invalid - - // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters - void* memory = xml_memory::allocate(sizeof(T) + length * sizeof(char_t)); - if (!memory) return 0; - - T* result = new (memory) T(); - - memcpy(result->name, name, (length + 1) * sizeof(char_t)); - - return result; - } - - PUGI__FN xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name) - { - switch (type) - { - case xpath_type_node_set: - return new_xpath_variable(name); - - case xpath_type_number: - return new_xpath_variable(name); - - case xpath_type_string: - return new_xpath_variable(name); - - case xpath_type_boolean: - return new_xpath_variable(name); - - default: - return 0; - } - } - - template PUGI__FN void delete_xpath_variable(T* var) - { - var->~T(); - xml_memory::deallocate(var); - } - - PUGI__FN void delete_xpath_variable(xpath_value_type type, xpath_variable* var) - { - switch (type) - { - case xpath_type_node_set: - delete_xpath_variable(static_cast(var)); - break; - - case xpath_type_number: - delete_xpath_variable(static_cast(var)); - break; - - case xpath_type_string: - delete_xpath_variable(static_cast(var)); - break; - - case xpath_type_boolean: - delete_xpath_variable(static_cast(var)); - break; - - default: - assert(!"Invalid variable type"); - } - } - - PUGI__FN xpath_variable* get_variable(xpath_variable_set* set, const char_t* begin, const char_t* end) - { - char_t buffer[32]; - - size_t length = static_cast(end - begin); - char_t* scratch = buffer; - - if (length >= sizeof(buffer) / sizeof(buffer[0])) - { - // need to make dummy on-heap copy - scratch = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); - if (!scratch) return 0; - } - - // copy string to zero-terminated buffer and perform lookup - memcpy(scratch, begin, length * sizeof(char_t)); - scratch[length] = 0; - - xpath_variable* result = set->get(scratch); - - // free dummy buffer - if (scratch != buffer) xml_memory::deallocate(scratch); - - return result; - } -PUGI__NS_END - -// Internal node set class -PUGI__NS_BEGIN - PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev) - { - xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted; - - if (type == xpath_node_set::type_unsorted) - { - sort(begin, end, document_order_comparator()); - - type = xpath_node_set::type_sorted; - } - - if (type != order) reverse(begin, end); - - return order; - } - - PUGI__FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type) - { - if (begin == end) return xpath_node(); - - switch (type) - { - case xpath_node_set::type_sorted: - return *begin; - - case xpath_node_set::type_sorted_reverse: - return *(end - 1); - - case xpath_node_set::type_unsorted: - return *min_element(begin, end, document_order_comparator()); - - default: - assert(!"Invalid node set type"); - return xpath_node(); - } - } - - class xpath_node_set_raw - { - xpath_node_set::type_t _type; - - xpath_node* _begin; - xpath_node* _end; - xpath_node* _eos; - - public: - xpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0) - { - } - - xpath_node* begin() const - { - return _begin; - } - - xpath_node* end() const - { - return _end; - } - - bool empty() const - { - return _begin == _end; - } - - size_t size() const - { - return static_cast(_end - _begin); - } - - xpath_node first() const - { - return xpath_first(_begin, _end, _type); - } - - void push_back(const xpath_node& node, xpath_allocator* alloc) - { - if (_end == _eos) - { - size_t capacity = static_cast(_eos - _begin); - - // get new capacity (1.5x rule) - size_t new_capacity = capacity + capacity / 2 + 1; - - // reallocate the old array or allocate a new one - xpath_node* data = static_cast(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node))); - assert(data); - - // finalize - _begin = data; - _end = data + capacity; - _eos = data + new_capacity; - } - - *_end++ = node; - } - - void append(const xpath_node* begin_, const xpath_node* end_, xpath_allocator* alloc) - { - size_t size_ = static_cast(_end - _begin); - size_t capacity = static_cast(_eos - _begin); - size_t count = static_cast(end_ - begin_); - - if (size_ + count > capacity) - { - // reallocate the old array or allocate a new one - xpath_node* data = static_cast(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size_ + count) * sizeof(xpath_node))); - assert(data); - - // finalize - _begin = data; - _end = data + size_; - _eos = data + size_ + count; - } - - memcpy(_end, begin_, count * sizeof(xpath_node)); - _end += count; - } - - void sort_do() - { - _type = xpath_sort(_begin, _end, _type, false); - } - - void truncate(xpath_node* pos) - { - assert(_begin <= pos && pos <= _end); - - _end = pos; - } - - void remove_duplicates() - { - if (_type == xpath_node_set::type_unsorted) - sort(_begin, _end, duplicate_comparator()); - - _end = unique(_begin, _end); - } - - xpath_node_set::type_t type() const - { - return _type; - } - - void set_type(xpath_node_set::type_t value) - { - _type = value; - } - }; -PUGI__NS_END - -PUGI__NS_BEGIN - struct xpath_context - { - xpath_node n; - size_t position, size; - - xpath_context(const xpath_node& n_, size_t position_, size_t size_): n(n_), position(position_), size(size_) - { - } - }; - - enum lexeme_t - { - lex_none = 0, - lex_equal, - lex_not_equal, - lex_less, - lex_greater, - lex_less_or_equal, - lex_greater_or_equal, - lex_plus, - lex_minus, - lex_multiply, - lex_union, - lex_var_ref, - lex_open_brace, - lex_close_brace, - lex_quoted_string, - lex_number, - lex_slash, - lex_double_slash, - lex_open_square_brace, - lex_close_square_brace, - lex_string, - lex_comma, - lex_axis_attribute, - lex_dot, - lex_double_dot, - lex_double_colon, - lex_eof - }; - - struct xpath_lexer_string - { - const char_t* begin; - const char_t* end; - - xpath_lexer_string(): begin(0), end(0) - { - } - - bool operator==(const char_t* other) const - { - size_t length = static_cast(end - begin); - - return strequalrange(other, begin, length); - } - }; - - class xpath_lexer - { - const char_t* _cur; - const char_t* _cur_lexeme_pos; - xpath_lexer_string _cur_lexeme_contents; - - lexeme_t _cur_lexeme; - - public: - explicit xpath_lexer(const char_t* query): _cur(query) - { - next(); - } - - const char_t* state() const - { - return _cur; - } - - void next() - { - const char_t* cur = _cur; - - while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur; - - // save lexeme position for error reporting - _cur_lexeme_pos = cur; - - switch (*cur) - { - case 0: - _cur_lexeme = lex_eof; - break; - - case '>': - if (*(cur+1) == '=') - { - cur += 2; - _cur_lexeme = lex_greater_or_equal; - } - else - { - cur += 1; - _cur_lexeme = lex_greater; - } - break; - - case '<': - if (*(cur+1) == '=') - { - cur += 2; - _cur_lexeme = lex_less_or_equal; - } - else - { - cur += 1; - _cur_lexeme = lex_less; - } - break; - - case '!': - if (*(cur+1) == '=') - { - cur += 2; - _cur_lexeme = lex_not_equal; - } - else - { - _cur_lexeme = lex_none; - } - break; - - case '=': - cur += 1; - _cur_lexeme = lex_equal; - - break; - - case '+': - cur += 1; - _cur_lexeme = lex_plus; - - break; - - case '-': - cur += 1; - _cur_lexeme = lex_minus; - - break; - - case '*': - cur += 1; - _cur_lexeme = lex_multiply; - - break; - - case '|': - cur += 1; - _cur_lexeme = lex_union; - - break; - - case '$': - cur += 1; - - if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol)) - { - _cur_lexeme_contents.begin = cur; - - while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; - - if (cur[0] == ':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // qname - { - cur++; // : - - while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; - } - - _cur_lexeme_contents.end = cur; - - _cur_lexeme = lex_var_ref; - } - else - { - _cur_lexeme = lex_none; - } - - break; - - case '(': - cur += 1; - _cur_lexeme = lex_open_brace; - - break; - - case ')': - cur += 1; - _cur_lexeme = lex_close_brace; - - break; - - case '[': - cur += 1; - _cur_lexeme = lex_open_square_brace; - - break; - - case ']': - cur += 1; - _cur_lexeme = lex_close_square_brace; - - break; - - case ',': - cur += 1; - _cur_lexeme = lex_comma; - - break; - - case '/': - if (*(cur+1) == '/') - { - cur += 2; - _cur_lexeme = lex_double_slash; - } - else - { - cur += 1; - _cur_lexeme = lex_slash; - } - break; - - case '.': - if (*(cur+1) == '.') - { - cur += 2; - _cur_lexeme = lex_double_dot; - } - else if (PUGI__IS_CHARTYPEX(*(cur+1), ctx_digit)) - { - _cur_lexeme_contents.begin = cur; // . - - ++cur; - - while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; - - _cur_lexeme_contents.end = cur; - - _cur_lexeme = lex_number; - } - else - { - cur += 1; - _cur_lexeme = lex_dot; - } - break; - - case '@': - cur += 1; - _cur_lexeme = lex_axis_attribute; - - break; - - case '"': - case '\'': - { - char_t terminator = *cur; - - ++cur; - - _cur_lexeme_contents.begin = cur; - while (*cur && *cur != terminator) cur++; - _cur_lexeme_contents.end = cur; - - if (!*cur) - _cur_lexeme = lex_none; - else - { - cur += 1; - _cur_lexeme = lex_quoted_string; - } - - break; - } - - case ':': - if (*(cur+1) == ':') - { - cur += 2; - _cur_lexeme = lex_double_colon; - } - else - { - _cur_lexeme = lex_none; - } - break; - - default: - if (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) - { - _cur_lexeme_contents.begin = cur; - - while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; - - if (*cur == '.') - { - cur++; - - while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; - } - - _cur_lexeme_contents.end = cur; - - _cur_lexeme = lex_number; - } - else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol)) - { - _cur_lexeme_contents.begin = cur; - - while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; - - if (cur[0] == ':') - { - if (cur[1] == '*') // namespace test ncname:* - { - cur += 2; // :* - } - else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname - { - cur++; // : - - while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; - } - } - - _cur_lexeme_contents.end = cur; - - _cur_lexeme = lex_string; - } - else - { - _cur_lexeme = lex_none; - } - } - - _cur = cur; - } - - lexeme_t current() const - { - return _cur_lexeme; - } - - const char_t* current_pos() const - { - return _cur_lexeme_pos; - } - - const xpath_lexer_string& contents() const - { - assert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string); - - return _cur_lexeme_contents; - } - }; - - enum ast_type_t - { - ast_op_or, // left or right - ast_op_and, // left and right - ast_op_equal, // left = right - ast_op_not_equal, // left != right - ast_op_less, // left < right - ast_op_greater, // left > right - ast_op_less_or_equal, // left <= right - ast_op_greater_or_equal, // left >= right - ast_op_add, // left + right - ast_op_subtract, // left - right - ast_op_multiply, // left * right - ast_op_divide, // left / right - ast_op_mod, // left % right - ast_op_negate, // left - right - ast_op_union, // left | right - ast_predicate, // apply predicate to set; next points to next predicate - ast_filter, // select * from left where right - ast_filter_posinv, // select * from left where right; proximity position invariant - ast_string_constant, // string constant - ast_number_constant, // number constant - ast_variable, // variable - ast_func_last, // last() - ast_func_position, // position() - ast_func_count, // count(left) - ast_func_id, // id(left) - ast_func_local_name_0, // local-name() - ast_func_local_name_1, // local-name(left) - ast_func_namespace_uri_0, // namespace-uri() - ast_func_namespace_uri_1, // namespace-uri(left) - ast_func_name_0, // name() - ast_func_name_1, // name(left) - ast_func_string_0, // string() - ast_func_string_1, // string(left) - ast_func_concat, // concat(left, right, siblings) - ast_func_starts_with, // starts_with(left, right) - ast_func_contains, // contains(left, right) - ast_func_substring_before, // substring-before(left, right) - ast_func_substring_after, // substring-after(left, right) - ast_func_substring_2, // substring(left, right) - ast_func_substring_3, // substring(left, right, third) - ast_func_string_length_0, // string-length() - ast_func_string_length_1, // string-length(left) - ast_func_normalize_space_0, // normalize-space() - ast_func_normalize_space_1, // normalize-space(left) - ast_func_translate, // translate(left, right, third) - ast_func_boolean, // boolean(left) - ast_func_not, // not(left) - ast_func_true, // true() - ast_func_false, // false() - ast_func_lang, // lang(left) - ast_func_number_0, // number() - ast_func_number_1, // number(left) - ast_func_sum, // sum(left) - ast_func_floor, // floor(left) - ast_func_ceiling, // ceiling(left) - ast_func_round, // round(left) - ast_step, // process set left with step - ast_step_root // select root node - }; - - enum axis_t - { - axis_ancestor, - axis_ancestor_or_self, - axis_attribute, - axis_child, - axis_descendant, - axis_descendant_or_self, - axis_following, - axis_following_sibling, - axis_namespace, - axis_parent, - axis_preceding, - axis_preceding_sibling, - axis_self - }; - - enum nodetest_t - { - nodetest_none, - nodetest_name, - nodetest_type_node, - nodetest_type_comment, - nodetest_type_pi, - nodetest_type_text, - nodetest_pi, - nodetest_all, - nodetest_all_in_namespace - }; - - template struct axis_to_type - { - static const axis_t axis; - }; - - template const axis_t axis_to_type::axis = N; - - class xpath_ast_node - { - private: - // node type - char _type; - char _rettype; - - // for ast_step / ast_predicate - char _axis; - char _test; - - // tree node structure - xpath_ast_node* _left; - xpath_ast_node* _right; - xpath_ast_node* _next; - - union - { - // value for ast_string_constant - const char_t* string; - // value for ast_number_constant - double number; - // variable for ast_variable - xpath_variable* variable; - // node test for ast_step (node name/namespace/node type/pi target) - const char_t* nodetest; - } _data; - - xpath_ast_node(const xpath_ast_node&); - xpath_ast_node& operator=(const xpath_ast_node&); - - template static bool compare_eq(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) - { - xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); - - if (lt != xpath_type_node_set && rt != xpath_type_node_set) - { - if (lt == xpath_type_boolean || rt == xpath_type_boolean) - return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack)); - else if (lt == xpath_type_number || rt == xpath_type_number) - return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); - else if (lt == xpath_type_string || rt == xpath_type_string) - { - xpath_allocator_capture cr(stack.result); - - xpath_string ls = lhs->eval_string(c, stack); - xpath_string rs = rhs->eval_string(c, stack); - - return comp(ls, rs); - } - } - else if (lt == xpath_type_node_set && rt == xpath_type_node_set) - { - xpath_allocator_capture cr(stack.result); - - xpath_node_set_raw ls = lhs->eval_node_set(c, stack); - xpath_node_set_raw rs = rhs->eval_node_set(c, stack); - - for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) - for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) - { - xpath_allocator_capture cri(stack.result); - - if (comp(string_value(*li, stack.result), string_value(*ri, stack.result))) - return true; - } - - return false; - } - else - { - if (lt == xpath_type_node_set) - { - swap(lhs, rhs); - swap(lt, rt); - } - - if (lt == xpath_type_boolean) - return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack)); - else if (lt == xpath_type_number) - { - xpath_allocator_capture cr(stack.result); - - double l = lhs->eval_number(c, stack); - xpath_node_set_raw rs = rhs->eval_node_set(c, stack); - - for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) - { - xpath_allocator_capture cri(stack.result); - - if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) - return true; - } - - return false; - } - else if (lt == xpath_type_string) - { - xpath_allocator_capture cr(stack.result); - - xpath_string l = lhs->eval_string(c, stack); - xpath_node_set_raw rs = rhs->eval_node_set(c, stack); - - for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) - { - xpath_allocator_capture cri(stack.result); - - if (comp(l, string_value(*ri, stack.result))) - return true; - } - - return false; - } - } - - assert(!"Wrong types"); - return false; - } - - template static bool compare_rel(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) - { - xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); - - if (lt != xpath_type_node_set && rt != xpath_type_node_set) - return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); - else if (lt == xpath_type_node_set && rt == xpath_type_node_set) - { - xpath_allocator_capture cr(stack.result); - - xpath_node_set_raw ls = lhs->eval_node_set(c, stack); - xpath_node_set_raw rs = rhs->eval_node_set(c, stack); - - for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) - { - xpath_allocator_capture cri(stack.result); - - double l = convert_string_to_number(string_value(*li, stack.result).c_str()); - - for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) - { - xpath_allocator_capture crii(stack.result); - - if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) - return true; - } - } - - return false; - } - else if (lt != xpath_type_node_set && rt == xpath_type_node_set) - { - xpath_allocator_capture cr(stack.result); - - double l = lhs->eval_number(c, stack); - xpath_node_set_raw rs = rhs->eval_node_set(c, stack); - - for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) - { - xpath_allocator_capture cri(stack.result); - - if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) - return true; - } - - return false; - } - else if (lt == xpath_type_node_set && rt != xpath_type_node_set) - { - xpath_allocator_capture cr(stack.result); - - xpath_node_set_raw ls = lhs->eval_node_set(c, stack); - double r = rhs->eval_number(c, stack); - - for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) - { - xpath_allocator_capture cri(stack.result); - - if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r)) - return true; - } - - return false; - } - else - { - assert(!"Wrong types"); - return false; - } - } - - void apply_predicate(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack) - { - assert(ns.size() >= first); - - size_t i = 1; - size_t size = ns.size() - first; - - xpath_node* last = ns.begin() + first; - - // remove_if... or well, sort of - for (xpath_node* it = last; it != ns.end(); ++it, ++i) - { - xpath_context c(*it, i, size); - - if (expr->rettype() == xpath_type_number) - { - if (expr->eval_number(c, stack) == i) - *last++ = *it; - } - else if (expr->eval_boolean(c, stack)) - *last++ = *it; - } - - ns.truncate(last); - } - - void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack) - { - if (ns.size() == first) return; - - for (xpath_ast_node* pred = _right; pred; pred = pred->_next) - { - apply_predicate(ns, first, pred->_left, stack); - } - } - - void step_push(xpath_node_set_raw& ns, const xml_attribute& a, const xml_node& parent, xpath_allocator* alloc) - { - if (!a) return; - - const char_t* name = a.name(); - - // There are no attribute nodes corresponding to attributes that declare namespaces - // That is, "xmlns:..." or "xmlns" - if (starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':')) return; - - switch (_test) - { - case nodetest_name: - if (strequal(name, _data.nodetest)) ns.push_back(xpath_node(a, parent), alloc); - break; - - case nodetest_type_node: - case nodetest_all: - ns.push_back(xpath_node(a, parent), alloc); - break; - - case nodetest_all_in_namespace: - if (starts_with(name, _data.nodetest)) - ns.push_back(xpath_node(a, parent), alloc); - break; - - default: - ; - } - } - - void step_push(xpath_node_set_raw& ns, const xml_node& n, xpath_allocator* alloc) - { - if (!n) return; - - switch (_test) - { - case nodetest_name: - if (n.type() == node_element && strequal(n.name(), _data.nodetest)) ns.push_back(n, alloc); - break; - - case nodetest_type_node: - ns.push_back(n, alloc); - break; - - case nodetest_type_comment: - if (n.type() == node_comment) - ns.push_back(n, alloc); - break; - - case nodetest_type_text: - if (n.type() == node_pcdata || n.type() == node_cdata) - ns.push_back(n, alloc); - break; - - case nodetest_type_pi: - if (n.type() == node_pi) - ns.push_back(n, alloc); - break; - - case nodetest_pi: - if (n.type() == node_pi && strequal(n.name(), _data.nodetest)) - ns.push_back(n, alloc); - break; - - case nodetest_all: - if (n.type() == node_element) - ns.push_back(n, alloc); - break; - - case nodetest_all_in_namespace: - if (n.type() == node_element && starts_with(n.name(), _data.nodetest)) - ns.push_back(n, alloc); - break; - - default: - assert(!"Unknown axis"); - } - } - - template void step_fill(xpath_node_set_raw& ns, const xml_node& n, xpath_allocator* alloc, T) - { - const axis_t axis = T::axis; - - switch (axis) - { - case axis_attribute: - { - for (xml_attribute a = n.first_attribute(); a; a = a.next_attribute()) - step_push(ns, a, n, alloc); - - break; - } - - case axis_child: - { - for (xml_node c = n.first_child(); c; c = c.next_sibling()) - step_push(ns, c, alloc); - - break; - } - - case axis_descendant: - case axis_descendant_or_self: - { - if (axis == axis_descendant_or_self) - step_push(ns, n, alloc); - - xml_node cur = n.first_child(); - - while (cur && cur != n) - { - step_push(ns, cur, alloc); - - if (cur.first_child()) - cur = cur.first_child(); - else if (cur.next_sibling()) - cur = cur.next_sibling(); - else - { - while (!cur.next_sibling() && cur != n) - cur = cur.parent(); - - if (cur != n) cur = cur.next_sibling(); - } - } - - break; - } - - case axis_following_sibling: - { - for (xml_node c = n.next_sibling(); c; c = c.next_sibling()) - step_push(ns, c, alloc); - - break; - } - - case axis_preceding_sibling: - { - for (xml_node c = n.previous_sibling(); c; c = c.previous_sibling()) - step_push(ns, c, alloc); - - break; - } - - case axis_following: - { - xml_node cur = n; - - // exit from this node so that we don't include descendants - while (cur && !cur.next_sibling()) cur = cur.parent(); - cur = cur.next_sibling(); - - for (;;) - { - step_push(ns, cur, alloc); - - if (cur.first_child()) - cur = cur.first_child(); - else if (cur.next_sibling()) - cur = cur.next_sibling(); - else - { - while (cur && !cur.next_sibling()) cur = cur.parent(); - cur = cur.next_sibling(); - - if (!cur) break; - } - } - - break; - } - - case axis_preceding: - { - xml_node cur = n; - - while (cur && !cur.previous_sibling()) cur = cur.parent(); - cur = cur.previous_sibling(); - - for (;;) - { - if (cur.last_child()) - cur = cur.last_child(); - else - { - // leaf node, can't be ancestor - step_push(ns, cur, alloc); - - if (cur.previous_sibling()) - cur = cur.previous_sibling(); - else - { - do - { - cur = cur.parent(); - if (!cur) break; - - if (!node_is_ancestor(cur, n)) step_push(ns, cur, alloc); - } - while (!cur.previous_sibling()); - - cur = cur.previous_sibling(); - - if (!cur) break; - } - } - } - - break; - } - - case axis_ancestor: - case axis_ancestor_or_self: - { - if (axis == axis_ancestor_or_self) - step_push(ns, n, alloc); - - xml_node cur = n.parent(); - - while (cur) - { - step_push(ns, cur, alloc); - - cur = cur.parent(); - } - - break; - } - - case axis_self: - { - step_push(ns, n, alloc); - - break; - } - - case axis_parent: - { - if (n.parent()) step_push(ns, n.parent(), alloc); - - break; - } - - default: - assert(!"Unimplemented axis"); - } - } - - template void step_fill(xpath_node_set_raw& ns, const xml_attribute& a, const xml_node& p, xpath_allocator* alloc, T v) - { - const axis_t axis = T::axis; - - switch (axis) - { - case axis_ancestor: - case axis_ancestor_or_self: - { - if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test - step_push(ns, a, p, alloc); - - xml_node cur = p; - - while (cur) - { - step_push(ns, cur, alloc); - - cur = cur.parent(); - } - - break; - } - - case axis_descendant_or_self: - case axis_self: - { - if (_test == nodetest_type_node) // reject attributes based on principal node type test - step_push(ns, a, p, alloc); - - break; - } - - case axis_following: - { - xml_node cur = p; - - for (;;) - { - if (cur.first_child()) - cur = cur.first_child(); - else if (cur.next_sibling()) - cur = cur.next_sibling(); - else - { - while (cur && !cur.next_sibling()) cur = cur.parent(); - cur = cur.next_sibling(); - - if (!cur) break; - } - - step_push(ns, cur, alloc); - } - - break; - } - - case axis_parent: - { - step_push(ns, p, alloc); - - break; - } - - case axis_preceding: - { - // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding - step_fill(ns, p, alloc, v); - break; - } - - default: - assert(!"Unimplemented axis"); - } - } - - template xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, T v) - { - const axis_t axis = T::axis; - bool attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self); - - xpath_node_set_raw ns; - ns.set_type((axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling) ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted); - - if (_left) - { - xpath_node_set_raw s = _left->eval_node_set(c, stack); - - // self axis preserves the original order - if (axis == axis_self) ns.set_type(s.type()); - - for (const xpath_node* it = s.begin(); it != s.end(); ++it) - { - size_t size = ns.size(); - - // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes - if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted); - - if (it->node()) - step_fill(ns, it->node(), stack.result, v); - else if (attributes) - step_fill(ns, it->attribute(), it->parent(), stack.result, v); - - apply_predicates(ns, size, stack); - } - } - else - { - if (c.n.node()) - step_fill(ns, c.n.node(), stack.result, v); - else if (attributes) - step_fill(ns, c.n.attribute(), c.n.parent(), stack.result, v); - - apply_predicates(ns, 0, stack); - } - - // child, attribute and self axes always generate unique set of nodes - // for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the same node twice - if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted) - ns.remove_duplicates(); - - return ns; - } - - public: - xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value): - _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) - { - assert(type == ast_string_constant); - _data.string = value; - } - - xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value): - _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) - { - assert(type == ast_number_constant); - _data.number = value; - } - - xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value): - _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) - { - assert(type == ast_variable); - _data.variable = value; - } - - xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = 0, xpath_ast_node* right = 0): - _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0) - { - } - - xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents): - _type(static_cast(type)), _rettype(xpath_type_node_set), _axis(static_cast(axis)), _test(static_cast(test)), _left(left), _right(0), _next(0) - { - _data.nodetest = contents; - } - - void set_next(xpath_ast_node* value) - { - _next = value; - } - - void set_right(xpath_ast_node* value) - { - _right = value; - } - - bool eval_boolean(const xpath_context& c, const xpath_stack& stack) - { - switch (_type) - { - case ast_op_or: - return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack); - - case ast_op_and: - return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack); - - case ast_op_equal: - return compare_eq(_left, _right, c, stack, equal_to()); - - case ast_op_not_equal: - return compare_eq(_left, _right, c, stack, not_equal_to()); - - case ast_op_less: - return compare_rel(_left, _right, c, stack, less()); - - case ast_op_greater: - return compare_rel(_right, _left, c, stack, less()); - - case ast_op_less_or_equal: - return compare_rel(_left, _right, c, stack, less_equal()); - - case ast_op_greater_or_equal: - return compare_rel(_right, _left, c, stack, less_equal()); - - case ast_func_starts_with: - { - xpath_allocator_capture cr(stack.result); - - xpath_string lr = _left->eval_string(c, stack); - xpath_string rr = _right->eval_string(c, stack); - - return starts_with(lr.c_str(), rr.c_str()); - } - - case ast_func_contains: - { - xpath_allocator_capture cr(stack.result); - - xpath_string lr = _left->eval_string(c, stack); - xpath_string rr = _right->eval_string(c, stack); - - return find_substring(lr.c_str(), rr.c_str()) != 0; - } - - case ast_func_boolean: - return _left->eval_boolean(c, stack); - - case ast_func_not: - return !_left->eval_boolean(c, stack); - - case ast_func_true: - return true; - - case ast_func_false: - return false; - - case ast_func_lang: - { - if (c.n.attribute()) return false; - - xpath_allocator_capture cr(stack.result); - - xpath_string lang = _left->eval_string(c, stack); - - for (xml_node n = c.n.node(); n; n = n.parent()) - { - xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang")); - - if (a) - { - const char_t* value = a.value(); - - // strnicmp / strncasecmp is not portable - for (const char_t* lit = lang.c_str(); *lit; ++lit) - { - if (tolower_ascii(*lit) != tolower_ascii(*value)) return false; - ++value; - } - - return *value == 0 || *value == '-'; - } - } - - return false; - } - - case ast_variable: - { - assert(_rettype == _data.variable->type()); - - if (_rettype == xpath_type_boolean) - return _data.variable->get_boolean(); - - // fallthrough to type conversion - } - - default: - { - switch (_rettype) - { - case xpath_type_number: - return convert_number_to_boolean(eval_number(c, stack)); - - case xpath_type_string: - { - xpath_allocator_capture cr(stack.result); - - return !eval_string(c, stack).empty(); - } - - case xpath_type_node_set: - { - xpath_allocator_capture cr(stack.result); - - return !eval_node_set(c, stack).empty(); - } - - default: - assert(!"Wrong expression for return type boolean"); - return false; - } - } - } - } - - double eval_number(const xpath_context& c, const xpath_stack& stack) - { - switch (_type) - { - case ast_op_add: - return _left->eval_number(c, stack) + _right->eval_number(c, stack); - - case ast_op_subtract: - return _left->eval_number(c, stack) - _right->eval_number(c, stack); - - case ast_op_multiply: - return _left->eval_number(c, stack) * _right->eval_number(c, stack); - - case ast_op_divide: - return _left->eval_number(c, stack) / _right->eval_number(c, stack); - - case ast_op_mod: - return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack)); - - case ast_op_negate: - return -_left->eval_number(c, stack); - - case ast_number_constant: - return _data.number; - - case ast_func_last: - return static_cast(c.size); - - case ast_func_position: - return static_cast(c.position); - - case ast_func_count: - { - xpath_allocator_capture cr(stack.result); - - return static_cast(_left->eval_node_set(c, stack).size()); - } - - case ast_func_string_length_0: - { - xpath_allocator_capture cr(stack.result); - - return static_cast(string_value(c.n, stack.result).length()); - } - - case ast_func_string_length_1: - { - xpath_allocator_capture cr(stack.result); - - return static_cast(_left->eval_string(c, stack).length()); - } - - case ast_func_number_0: - { - xpath_allocator_capture cr(stack.result); - - return convert_string_to_number(string_value(c.n, stack.result).c_str()); - } - - case ast_func_number_1: - return _left->eval_number(c, stack); - - case ast_func_sum: - { - xpath_allocator_capture cr(stack.result); - - double r = 0; - - xpath_node_set_raw ns = _left->eval_node_set(c, stack); - - for (const xpath_node* it = ns.begin(); it != ns.end(); ++it) - { - xpath_allocator_capture cri(stack.result); - - r += convert_string_to_number(string_value(*it, stack.result).c_str()); - } - - return r; - } - - case ast_func_floor: - { - double r = _left->eval_number(c, stack); - - return r == r ? floor(r) : r; - } - - case ast_func_ceiling: - { - double r = _left->eval_number(c, stack); - - return r == r ? ceil(r) : r; - } - - case ast_func_round: - return round_nearest_nzero(_left->eval_number(c, stack)); - - case ast_variable: - { - assert(_rettype == _data.variable->type()); - - if (_rettype == xpath_type_number) - return _data.variable->get_number(); - - // fallthrough to type conversion - } - - default: - { - switch (_rettype) - { - case xpath_type_boolean: - return eval_boolean(c, stack) ? 1 : 0; - - case xpath_type_string: - { - xpath_allocator_capture cr(stack.result); - - return convert_string_to_number(eval_string(c, stack).c_str()); - } - - case xpath_type_node_set: - { - xpath_allocator_capture cr(stack.result); - - return convert_string_to_number(eval_string(c, stack).c_str()); - } - - default: - assert(!"Wrong expression for return type number"); - return 0; - } - - } - } - } - - xpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack) - { - assert(_type == ast_func_concat); - - xpath_allocator_capture ct(stack.temp); - - // count the string number - size_t count = 1; - for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++; - - // gather all strings - xpath_string static_buffer[4]; - xpath_string* buffer = static_buffer; - - // allocate on-heap for large concats - if (count > sizeof(static_buffer) / sizeof(static_buffer[0])) - { - buffer = static_cast(stack.temp->allocate(count * sizeof(xpath_string))); - assert(buffer); - } - - // evaluate all strings to temporary stack - xpath_stack swapped_stack = {stack.temp, stack.result}; - - buffer[0] = _left->eval_string(c, swapped_stack); - - size_t pos = 1; - for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack); - assert(pos == count); - - // get total length - size_t length = 0; - for (size_t i = 0; i < count; ++i) length += buffer[i].length(); - - // create final string - char_t* result = static_cast(stack.result->allocate((length + 1) * sizeof(char_t))); - assert(result); - - char_t* ri = result; - - for (size_t j = 0; j < count; ++j) - for (const char_t* bi = buffer[j].c_str(); *bi; ++bi) - *ri++ = *bi; - - *ri = 0; - - return xpath_string(result, true); - } - - xpath_string eval_string(const xpath_context& c, const xpath_stack& stack) - { - switch (_type) - { - case ast_string_constant: - return xpath_string_const(_data.string); - - case ast_func_local_name_0: - { - xpath_node na = c.n; - - return xpath_string_const(local_name(na)); - } - - case ast_func_local_name_1: - { - xpath_allocator_capture cr(stack.result); - - xpath_node_set_raw ns = _left->eval_node_set(c, stack); - xpath_node na = ns.first(); - - return xpath_string_const(local_name(na)); - } - - case ast_func_name_0: - { - xpath_node na = c.n; - - return xpath_string_const(qualified_name(na)); - } - - case ast_func_name_1: - { - xpath_allocator_capture cr(stack.result); - - xpath_node_set_raw ns = _left->eval_node_set(c, stack); - xpath_node na = ns.first(); - - return xpath_string_const(qualified_name(na)); - } - - case ast_func_namespace_uri_0: - { - xpath_node na = c.n; - - return xpath_string_const(namespace_uri(na)); - } - - case ast_func_namespace_uri_1: - { - xpath_allocator_capture cr(stack.result); - - xpath_node_set_raw ns = _left->eval_node_set(c, stack); - xpath_node na = ns.first(); - - return xpath_string_const(namespace_uri(na)); - } - - case ast_func_string_0: - return string_value(c.n, stack.result); - - case ast_func_string_1: - return _left->eval_string(c, stack); - - case ast_func_concat: - return eval_string_concat(c, stack); - - case ast_func_substring_before: - { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = {stack.temp, stack.result}; - - xpath_string s = _left->eval_string(c, swapped_stack); - xpath_string p = _right->eval_string(c, swapped_stack); - - const char_t* pos = find_substring(s.c_str(), p.c_str()); - - return pos ? xpath_string(s.c_str(), pos, stack.result) : xpath_string(); - } - - case ast_func_substring_after: - { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = {stack.temp, stack.result}; - - xpath_string s = _left->eval_string(c, swapped_stack); - xpath_string p = _right->eval_string(c, swapped_stack); - - const char_t* pos = find_substring(s.c_str(), p.c_str()); - if (!pos) return xpath_string(); - - const char_t* result = pos + p.length(); - - return s.uses_heap() ? xpath_string(result, stack.result) : xpath_string_const(result); - } - - case ast_func_substring_2: - { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = {stack.temp, stack.result}; - - xpath_string s = _left->eval_string(c, swapped_stack); - size_t s_length = s.length(); - - double first = round_nearest(_right->eval_number(c, stack)); - - if (is_nan(first)) return xpath_string(); // NaN - else if (first >= s_length + 1) return xpath_string(); - - size_t pos = first < 1 ? 1 : static_cast(first); - assert(1 <= pos && pos <= s_length + 1); - - const char_t* rbegin = s.c_str() + (pos - 1); - - return s.uses_heap() ? xpath_string(rbegin, stack.result) : xpath_string_const(rbegin); - } - - case ast_func_substring_3: - { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = {stack.temp, stack.result}; - - xpath_string s = _left->eval_string(c, swapped_stack); - size_t s_length = s.length(); - - double first = round_nearest(_right->eval_number(c, stack)); - double last = first + round_nearest(_right->_next->eval_number(c, stack)); - - if (is_nan(first) || is_nan(last)) return xpath_string(); - else if (first >= s_length + 1) return xpath_string(); - else if (first >= last) return xpath_string(); - else if (last < 1) return xpath_string(); - - size_t pos = first < 1 ? 1 : static_cast(first); - size_t end = last >= s_length + 1 ? s_length + 1 : static_cast(last); - - assert(1 <= pos && pos <= end && end <= s_length + 1); - const char_t* rbegin = s.c_str() + (pos - 1); - const char_t* rend = s.c_str() + (end - 1); - - return (end == s_length + 1 && !s.uses_heap()) ? xpath_string_const(rbegin) : xpath_string(rbegin, rend, stack.result); - } - - case ast_func_normalize_space_0: - { - xpath_string s = string_value(c.n, stack.result); - - normalize_space(s.data(stack.result)); - - return s; - } - - case ast_func_normalize_space_1: - { - xpath_string s = _left->eval_string(c, stack); - - normalize_space(s.data(stack.result)); - - return s; - } - - case ast_func_translate: - { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = {stack.temp, stack.result}; - - xpath_string s = _left->eval_string(c, stack); - xpath_string from = _right->eval_string(c, swapped_stack); - xpath_string to = _right->_next->eval_string(c, swapped_stack); - - translate(s.data(stack.result), from.c_str(), to.c_str()); - - return s; - } - - case ast_variable: - { - assert(_rettype == _data.variable->type()); - - if (_rettype == xpath_type_string) - return xpath_string_const(_data.variable->get_string()); - - // fallthrough to type conversion - } - - default: - { - switch (_rettype) - { - case xpath_type_boolean: - return xpath_string_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); - - case xpath_type_number: - return convert_number_to_string(eval_number(c, stack), stack.result); - - case xpath_type_node_set: - { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = {stack.temp, stack.result}; - - xpath_node_set_raw ns = eval_node_set(c, swapped_stack); - return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result); - } - - default: - assert(!"Wrong expression for return type string"); - return xpath_string(); - } - } - } - } - - xpath_node_set_raw eval_node_set(const xpath_context& c, const xpath_stack& stack) - { - switch (_type) - { - case ast_op_union: - { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = {stack.temp, stack.result}; - - xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack); - xpath_node_set_raw rs = _right->eval_node_set(c, stack); - - // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother - rs.set_type(xpath_node_set::type_unsorted); - - rs.append(ls.begin(), ls.end(), stack.result); - rs.remove_duplicates(); - - return rs; - } - - case ast_filter: - case ast_filter_posinv: - { - xpath_node_set_raw set = _left->eval_node_set(c, stack); - - // either expression is a number or it contains position() call; sort by document order - if (_type == ast_filter) set.sort_do(); - - apply_predicate(set, 0, _right, stack); - - return set; - } - - case ast_func_id: - return xpath_node_set_raw(); - - case ast_step: - { - switch (_axis) - { - case axis_ancestor: - return step_do(c, stack, axis_to_type()); - - case axis_ancestor_or_self: - return step_do(c, stack, axis_to_type()); - - case axis_attribute: - return step_do(c, stack, axis_to_type()); - - case axis_child: - return step_do(c, stack, axis_to_type()); - - case axis_descendant: - return step_do(c, stack, axis_to_type()); - - case axis_descendant_or_self: - return step_do(c, stack, axis_to_type()); - - case axis_following: - return step_do(c, stack, axis_to_type()); - - case axis_following_sibling: - return step_do(c, stack, axis_to_type()); - - case axis_namespace: - // namespaced axis is not supported - return xpath_node_set_raw(); - - case axis_parent: - return step_do(c, stack, axis_to_type()); - - case axis_preceding: - return step_do(c, stack, axis_to_type()); - - case axis_preceding_sibling: - return step_do(c, stack, axis_to_type()); - - case axis_self: - return step_do(c, stack, axis_to_type()); - - default: - assert(!"Unknown axis"); - return xpath_node_set_raw(); - } - } - - case ast_step_root: - { - assert(!_right); // root step can't have any predicates - - xpath_node_set_raw ns; - - ns.set_type(xpath_node_set::type_sorted); - - if (c.n.node()) ns.push_back(c.n.node().root(), stack.result); - else if (c.n.attribute()) ns.push_back(c.n.parent().root(), stack.result); - - return ns; - } - - case ast_variable: - { - assert(_rettype == _data.variable->type()); - - if (_rettype == xpath_type_node_set) - { - const xpath_node_set& s = _data.variable->get_node_set(); - - xpath_node_set_raw ns; - - ns.set_type(s.type()); - ns.append(s.begin(), s.end(), stack.result); - - return ns; - } - - // fallthrough to type conversion - } - - default: - assert(!"Wrong expression for return type node set"); - return xpath_node_set_raw(); - } - } - - bool is_posinv() - { - switch (_type) - { - case ast_func_position: - return false; - - case ast_string_constant: - case ast_number_constant: - case ast_variable: - return true; - - case ast_step: - case ast_step_root: - return true; - - case ast_predicate: - case ast_filter: - case ast_filter_posinv: - return true; - - default: - if (_left && !_left->is_posinv()) return false; - - for (xpath_ast_node* n = _right; n; n = n->_next) - if (!n->is_posinv()) return false; - - return true; - } - } - - xpath_value_type rettype() const - { - return static_cast(_rettype); - } - }; - - struct xpath_parser - { - xpath_allocator* _alloc; - xpath_lexer _lexer; - - const char_t* _query; - xpath_variable_set* _variables; - - xpath_parse_result* _result; - - #ifdef PUGIXML_NO_EXCEPTIONS - jmp_buf _error_handler; - #endif - - void throw_error(const char* message) - { - _result->error = message; - _result->offset = _lexer.current_pos() - _query; - - #ifdef PUGIXML_NO_EXCEPTIONS - longjmp(_error_handler, 1); - #else - throw xpath_exception(*_result); - #endif - } - - void throw_error_oom() - { - #ifdef PUGIXML_NO_EXCEPTIONS - throw_error("Out of memory"); - #else - throw std::bad_alloc(); - #endif - } - - void* alloc_node() - { - void* result = _alloc->allocate_nothrow(sizeof(xpath_ast_node)); - - if (!result) throw_error_oom(); - - return result; - } - - const char_t* alloc_string(const xpath_lexer_string& value) - { - if (value.begin) - { - size_t length = static_cast(value.end - value.begin); - - char_t* c = static_cast(_alloc->allocate_nothrow((length + 1) * sizeof(char_t))); - if (!c) throw_error_oom(); - - memcpy(c, value.begin, length * sizeof(char_t)); - c[length] = 0; - - return c; - } - else return 0; - } - - xpath_ast_node* parse_function_helper(ast_type_t type0, ast_type_t type1, size_t argc, xpath_ast_node* args[2]) - { - assert(argc <= 1); - - if (argc == 1 && args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); - - return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]); - } - - xpath_ast_node* parse_function(const xpath_lexer_string& name, size_t argc, xpath_ast_node* args[2]) - { - switch (name.begin[0]) - { - case 'b': - if (name == PUGIXML_TEXT("boolean") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]); - - break; - - case 'c': - if (name == PUGIXML_TEXT("count") && argc == 1) - { - if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); - return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]); - } - else if (name == PUGIXML_TEXT("contains") && argc == 2) - return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("concat") && argc >= 2) - return new (alloc_node()) xpath_ast_node(ast_func_concat, xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("ceiling") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]); - - break; - - case 'f': - if (name == PUGIXML_TEXT("false") && argc == 0) - return new (alloc_node()) xpath_ast_node(ast_func_false, xpath_type_boolean); - else if (name == PUGIXML_TEXT("floor") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]); - - break; - - case 'i': - if (name == PUGIXML_TEXT("id") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]); - - break; - - case 'l': - if (name == PUGIXML_TEXT("last") && argc == 0) - return new (alloc_node()) xpath_ast_node(ast_func_last, xpath_type_number); - else if (name == PUGIXML_TEXT("lang") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_lang, xpath_type_boolean, args[0]); - else if (name == PUGIXML_TEXT("local-name") && argc <= 1) - return parse_function_helper(ast_func_local_name_0, ast_func_local_name_1, argc, args); - - break; - - case 'n': - if (name == PUGIXML_TEXT("name") && argc <= 1) - return parse_function_helper(ast_func_name_0, ast_func_name_1, argc, args); - else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1) - return parse_function_helper(ast_func_namespace_uri_0, ast_func_namespace_uri_1, argc, args); - else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1) - return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("not") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_not, xpath_type_boolean, args[0]); - else if (name == PUGIXML_TEXT("number") && argc <= 1) - return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]); - - break; - - case 'p': - if (name == PUGIXML_TEXT("position") && argc == 0) - return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number); - - break; - - case 'r': - if (name == PUGIXML_TEXT("round") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_round, xpath_type_number, args[0]); - - break; - - case 's': - if (name == PUGIXML_TEXT("string") && argc <= 1) - return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]); - else if (name == PUGIXML_TEXT("string-length") && argc <= 1) - return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_string, args[0]); - else if (name == PUGIXML_TEXT("starts-with") && argc == 2) - return new (alloc_node()) xpath_ast_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]); - else if (name == PUGIXML_TEXT("substring-before") && argc == 2) - return new (alloc_node()) xpath_ast_node(ast_func_substring_before, xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("substring-after") && argc == 2) - return new (alloc_node()) xpath_ast_node(ast_func_substring_after, xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3)) - return new (alloc_node()) xpath_ast_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("sum") && argc == 1) - { - if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); - return new (alloc_node()) xpath_ast_node(ast_func_sum, xpath_type_number, args[0]); - } - - break; - - case 't': - if (name == PUGIXML_TEXT("translate") && argc == 3) - return new (alloc_node()) xpath_ast_node(ast_func_translate, xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("true") && argc == 0) - return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean); - - break; - - default: - break; - } - - throw_error("Unrecognized function or wrong parameter count"); - - return 0; - } - - axis_t parse_axis_name(const xpath_lexer_string& name, bool& specified) - { - specified = true; - - switch (name.begin[0]) - { - case 'a': - if (name == PUGIXML_TEXT("ancestor")) - return axis_ancestor; - else if (name == PUGIXML_TEXT("ancestor-or-self")) - return axis_ancestor_or_self; - else if (name == PUGIXML_TEXT("attribute")) - return axis_attribute; - - break; - - case 'c': - if (name == PUGIXML_TEXT("child")) - return axis_child; - - break; - - case 'd': - if (name == PUGIXML_TEXT("descendant")) - return axis_descendant; - else if (name == PUGIXML_TEXT("descendant-or-self")) - return axis_descendant_or_self; - - break; - - case 'f': - if (name == PUGIXML_TEXT("following")) - return axis_following; - else if (name == PUGIXML_TEXT("following-sibling")) - return axis_following_sibling; - - break; - - case 'n': - if (name == PUGIXML_TEXT("namespace")) - return axis_namespace; - - break; - - case 'p': - if (name == PUGIXML_TEXT("parent")) - return axis_parent; - else if (name == PUGIXML_TEXT("preceding")) - return axis_preceding; - else if (name == PUGIXML_TEXT("preceding-sibling")) - return axis_preceding_sibling; - - break; - - case 's': - if (name == PUGIXML_TEXT("self")) - return axis_self; - - break; - - default: - break; - } - - specified = false; - return axis_child; - } - - nodetest_t parse_node_test_type(const xpath_lexer_string& name) - { - switch (name.begin[0]) - { - case 'c': - if (name == PUGIXML_TEXT("comment")) - return nodetest_type_comment; - - break; - - case 'n': - if (name == PUGIXML_TEXT("node")) - return nodetest_type_node; - - break; - - case 'p': - if (name == PUGIXML_TEXT("processing-instruction")) - return nodetest_type_pi; - - break; - - case 't': - if (name == PUGIXML_TEXT("text")) - return nodetest_type_text; - - break; - - default: - break; - } - - return nodetest_none; - } - - // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall - xpath_ast_node* parse_primary_expression() - { - switch (_lexer.current()) - { - case lex_var_ref: - { - xpath_lexer_string name = _lexer.contents(); - - if (!_variables) - throw_error("Unknown variable: variable set is not provided"); - - xpath_variable* var = get_variable(_variables, name.begin, name.end); - - if (!var) - throw_error("Unknown variable: variable set does not contain the given name"); - - _lexer.next(); - - return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), var); - } - - case lex_open_brace: - { - _lexer.next(); - - xpath_ast_node* n = parse_expression(); - - if (_lexer.current() != lex_close_brace) - throw_error("Unmatched braces"); - - _lexer.next(); - - return n; - } - - case lex_quoted_string: - { - const char_t* value = alloc_string(_lexer.contents()); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_string_constant, xpath_type_string, value); - _lexer.next(); - - return n; - } - - case lex_number: - { - double value = 0; - - if (!convert_string_to_number(_lexer.contents().begin, _lexer.contents().end, &value)) - throw_error_oom(); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_number_constant, xpath_type_number, value); - _lexer.next(); - - return n; - } - - case lex_string: - { - xpath_ast_node* args[2] = {0}; - size_t argc = 0; - - xpath_lexer_string function = _lexer.contents(); - _lexer.next(); - - xpath_ast_node* last_arg = 0; - - if (_lexer.current() != lex_open_brace) - throw_error("Unrecognized function call"); - _lexer.next(); - - if (_lexer.current() != lex_close_brace) - args[argc++] = parse_expression(); - - while (_lexer.current() != lex_close_brace) - { - if (_lexer.current() != lex_comma) - throw_error("No comma between function arguments"); - _lexer.next(); - - xpath_ast_node* n = parse_expression(); - - if (argc < 2) args[argc] = n; - else last_arg->set_next(n); - - argc++; - last_arg = n; - } - - _lexer.next(); - - return parse_function(function, argc, args); - } - - default: - throw_error("Unrecognizable primary expression"); - - return 0; - } - } - - // FilterExpr ::= PrimaryExpr | FilterExpr Predicate - // Predicate ::= '[' PredicateExpr ']' - // PredicateExpr ::= Expr - xpath_ast_node* parse_filter_expression() - { - xpath_ast_node* n = parse_primary_expression(); - - while (_lexer.current() == lex_open_square_brace) - { - _lexer.next(); - - xpath_ast_node* expr = parse_expression(); - - if (n->rettype() != xpath_type_node_set) throw_error("Predicate has to be applied to node set"); - - bool posinv = expr->rettype() != xpath_type_number && expr->is_posinv(); - - n = new (alloc_node()) xpath_ast_node(posinv ? ast_filter_posinv : ast_filter, xpath_type_node_set, n, expr); - - if (_lexer.current() != lex_close_square_brace) - throw_error("Unmatched square brace"); - - _lexer.next(); - } - - return n; - } - - // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep - // AxisSpecifier ::= AxisName '::' | '@'? - // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')' - // NameTest ::= '*' | NCName ':' '*' | QName - // AbbreviatedStep ::= '.' | '..' - xpath_ast_node* parse_step(xpath_ast_node* set) - { - if (set && set->rettype() != xpath_type_node_set) - throw_error("Step has to be applied to node set"); - - bool axis_specified = false; - axis_t axis = axis_child; // implied child axis - - if (_lexer.current() == lex_axis_attribute) - { - axis = axis_attribute; - axis_specified = true; - - _lexer.next(); - } - else if (_lexer.current() == lex_dot) - { - _lexer.next(); - - return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0); - } - else if (_lexer.current() == lex_double_dot) - { - _lexer.next(); - - return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0); - } - - nodetest_t nt_type = nodetest_none; - xpath_lexer_string nt_name; - - if (_lexer.current() == lex_string) - { - // node name test - nt_name = _lexer.contents(); - _lexer.next(); - - // was it an axis name? - if (_lexer.current() == lex_double_colon) - { - // parse axis name - if (axis_specified) throw_error("Two axis specifiers in one step"); - - axis = parse_axis_name(nt_name, axis_specified); - - if (!axis_specified) throw_error("Unknown axis"); - - // read actual node test - _lexer.next(); - - if (_lexer.current() == lex_multiply) - { - nt_type = nodetest_all; - nt_name = xpath_lexer_string(); - _lexer.next(); - } - else if (_lexer.current() == lex_string) - { - nt_name = _lexer.contents(); - _lexer.next(); - } - else throw_error("Unrecognized node test"); - } - - if (nt_type == nodetest_none) - { - // node type test or processing-instruction - if (_lexer.current() == lex_open_brace) - { - _lexer.next(); - - if (_lexer.current() == lex_close_brace) - { - _lexer.next(); - - nt_type = parse_node_test_type(nt_name); - - if (nt_type == nodetest_none) throw_error("Unrecognized node type"); - - nt_name = xpath_lexer_string(); - } - else if (nt_name == PUGIXML_TEXT("processing-instruction")) - { - if (_lexer.current() != lex_quoted_string) - throw_error("Only literals are allowed as arguments to processing-instruction()"); - - nt_type = nodetest_pi; - nt_name = _lexer.contents(); - _lexer.next(); - - if (_lexer.current() != lex_close_brace) - throw_error("Unmatched brace near processing-instruction()"); - _lexer.next(); - } - else - throw_error("Unmatched brace near node type test"); - - } - // QName or NCName:* - else - { - if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:* - { - nt_name.end--; // erase * - - nt_type = nodetest_all_in_namespace; - } - else nt_type = nodetest_name; - } - } - } - else if (_lexer.current() == lex_multiply) - { - nt_type = nodetest_all; - _lexer.next(); - } - else throw_error("Unrecognized node test"); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, alloc_string(nt_name)); - - xpath_ast_node* last = 0; - - while (_lexer.current() == lex_open_square_brace) - { - _lexer.next(); - - xpath_ast_node* expr = parse_expression(); - - xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, xpath_type_node_set, expr); - - if (_lexer.current() != lex_close_square_brace) - throw_error("Unmatched square brace"); - _lexer.next(); - - if (last) last->set_next(pred); - else n->set_right(pred); - - last = pred; - } - - return n; - } - - // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step - xpath_ast_node* parse_relative_location_path(xpath_ast_node* set) - { - xpath_ast_node* n = parse_step(set); - - while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) - { - lexeme_t l = _lexer.current(); - _lexer.next(); - - if (l == lex_double_slash) - n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); - - n = parse_step(n); - } - - return n; - } - - // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath - // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath - xpath_ast_node* parse_location_path() - { - if (_lexer.current() == lex_slash) - { - _lexer.next(); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); - - // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path - lexeme_t l = _lexer.current(); - - if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply) - return parse_relative_location_path(n); - else - return n; - } - else if (_lexer.current() == lex_double_slash) - { - _lexer.next(); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); - n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); - - return parse_relative_location_path(n); - } - - // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1 - return parse_relative_location_path(0); - } - - // PathExpr ::= LocationPath - // | FilterExpr - // | FilterExpr '/' RelativeLocationPath - // | FilterExpr '//' RelativeLocationPath - xpath_ast_node* parse_path_expression() - { - // Clarification. - // PathExpr begins with either LocationPath or FilterExpr. - // FilterExpr begins with PrimaryExpr - // PrimaryExpr begins with '$' in case of it being a variable reference, - // '(' in case of it being an expression, string literal, number constant or - // function call. - - if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || - _lexer.current() == lex_quoted_string || _lexer.current() == lex_number || - _lexer.current() == lex_string) - { - if (_lexer.current() == lex_string) - { - // This is either a function call, or not - if not, we shall proceed with location path - const char_t* state = _lexer.state(); - - while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state; - - if (*state != '(') return parse_location_path(); - - // This looks like a function call; however this still can be a node-test. Check it. - if (parse_node_test_type(_lexer.contents()) != nodetest_none) return parse_location_path(); - } - - xpath_ast_node* n = parse_filter_expression(); - - if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) - { - lexeme_t l = _lexer.current(); - _lexer.next(); - - if (l == lex_double_slash) - { - if (n->rettype() != xpath_type_node_set) throw_error("Step has to be applied to node set"); - - n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); - } - - // select from location path - return parse_relative_location_path(n); - } - - return n; - } - else return parse_location_path(); - } - - // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr - xpath_ast_node* parse_union_expression() - { - xpath_ast_node* n = parse_path_expression(); - - while (_lexer.current() == lex_union) - { - _lexer.next(); - - xpath_ast_node* expr = parse_union_expression(); - - if (n->rettype() != xpath_type_node_set || expr->rettype() != xpath_type_node_set) - throw_error("Union operator has to be applied to node sets"); - - n = new (alloc_node()) xpath_ast_node(ast_op_union, xpath_type_node_set, n, expr); - } - - return n; - } - - // UnaryExpr ::= UnionExpr | '-' UnaryExpr - xpath_ast_node* parse_unary_expression() - { - if (_lexer.current() == lex_minus) - { - _lexer.next(); - - xpath_ast_node* expr = parse_unary_expression(); - - return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr); - } - else return parse_union_expression(); - } - - // MultiplicativeExpr ::= UnaryExpr - // | MultiplicativeExpr '*' UnaryExpr - // | MultiplicativeExpr 'div' UnaryExpr - // | MultiplicativeExpr 'mod' UnaryExpr - xpath_ast_node* parse_multiplicative_expression() - { - xpath_ast_node* n = parse_unary_expression(); - - while (_lexer.current() == lex_multiply || (_lexer.current() == lex_string && - (_lexer.contents() == PUGIXML_TEXT("mod") || _lexer.contents() == PUGIXML_TEXT("div")))) - { - ast_type_t op = _lexer.current() == lex_multiply ? ast_op_multiply : - _lexer.contents().begin[0] == 'd' ? ast_op_divide : ast_op_mod; - _lexer.next(); - - xpath_ast_node* expr = parse_unary_expression(); - - n = new (alloc_node()) xpath_ast_node(op, xpath_type_number, n, expr); - } - - return n; - } - - // AdditiveExpr ::= MultiplicativeExpr - // | AdditiveExpr '+' MultiplicativeExpr - // | AdditiveExpr '-' MultiplicativeExpr - xpath_ast_node* parse_additive_expression() - { - xpath_ast_node* n = parse_multiplicative_expression(); - - while (_lexer.current() == lex_plus || _lexer.current() == lex_minus) - { - lexeme_t l = _lexer.current(); - - _lexer.next(); - - xpath_ast_node* expr = parse_multiplicative_expression(); - - n = new (alloc_node()) xpath_ast_node(l == lex_plus ? ast_op_add : ast_op_subtract, xpath_type_number, n, expr); - } - - return n; - } - - // RelationalExpr ::= AdditiveExpr - // | RelationalExpr '<' AdditiveExpr - // | RelationalExpr '>' AdditiveExpr - // | RelationalExpr '<=' AdditiveExpr - // | RelationalExpr '>=' AdditiveExpr - xpath_ast_node* parse_relational_expression() - { - xpath_ast_node* n = parse_additive_expression(); - - while (_lexer.current() == lex_less || _lexer.current() == lex_less_or_equal || - _lexer.current() == lex_greater || _lexer.current() == lex_greater_or_equal) - { - lexeme_t l = _lexer.current(); - _lexer.next(); - - xpath_ast_node* expr = parse_additive_expression(); - - n = new (alloc_node()) xpath_ast_node(l == lex_less ? ast_op_less : l == lex_greater ? ast_op_greater : - l == lex_less_or_equal ? ast_op_less_or_equal : ast_op_greater_or_equal, xpath_type_boolean, n, expr); - } - - return n; - } - - // EqualityExpr ::= RelationalExpr - // | EqualityExpr '=' RelationalExpr - // | EqualityExpr '!=' RelationalExpr - xpath_ast_node* parse_equality_expression() - { - xpath_ast_node* n = parse_relational_expression(); - - while (_lexer.current() == lex_equal || _lexer.current() == lex_not_equal) - { - lexeme_t l = _lexer.current(); - - _lexer.next(); - - xpath_ast_node* expr = parse_relational_expression(); - - n = new (alloc_node()) xpath_ast_node(l == lex_equal ? ast_op_equal : ast_op_not_equal, xpath_type_boolean, n, expr); - } - - return n; - } - - // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr - xpath_ast_node* parse_and_expression() - { - xpath_ast_node* n = parse_equality_expression(); - - while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT("and")) - { - _lexer.next(); - - xpath_ast_node* expr = parse_equality_expression(); - - n = new (alloc_node()) xpath_ast_node(ast_op_and, xpath_type_boolean, n, expr); - } - - return n; - } - - // OrExpr ::= AndExpr | OrExpr 'or' AndExpr - xpath_ast_node* parse_or_expression() - { - xpath_ast_node* n = parse_and_expression(); - - while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT("or")) - { - _lexer.next(); - - xpath_ast_node* expr = parse_and_expression(); - - n = new (alloc_node()) xpath_ast_node(ast_op_or, xpath_type_boolean, n, expr); - } - - return n; - } - - // Expr ::= OrExpr - xpath_ast_node* parse_expression() - { - return parse_or_expression(); - } - - xpath_parser(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result) - { - } - - xpath_ast_node* parse() - { - xpath_ast_node* result = parse_expression(); - - if (_lexer.current() != lex_eof) - { - // there are still unparsed tokens left, error - throw_error("Incorrect query"); - } - - return result; - } - - static xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result) - { - xpath_parser parser(query, variables, alloc, result); - - #ifdef PUGIXML_NO_EXCEPTIONS - int error = setjmp(parser._error_handler); - - return (error == 0) ? parser.parse() : 0; - #else - return parser.parse(); - #endif - } - }; - - struct xpath_query_impl - { - static xpath_query_impl* create() - { - void* memory = xml_memory::allocate(sizeof(xpath_query_impl)); - - return new (memory) xpath_query_impl(); - } - - static void destroy(void* ptr) - { - if (!ptr) return; - - // free all allocated pages - static_cast(ptr)->alloc.release(); - - // free allocator memory (with the first page) - xml_memory::deallocate(ptr); - } - - xpath_query_impl(): root(0), alloc(&block) - { - block.next = 0; - } - - xpath_ast_node* root; - xpath_allocator alloc; - xpath_memory_block block; - }; - - PUGI__FN xpath_string evaluate_string_impl(xpath_query_impl* impl, const xpath_node& n, xpath_stack_data& sd) - { - if (!impl) return xpath_string(); - - #ifdef PUGIXML_NO_EXCEPTIONS - if (setjmp(sd.error_handler)) return xpath_string(); - #endif - - xpath_context c(n, 1, 1); - - return impl->root->eval_string(c, sd.stack); - } -PUGI__NS_END - -namespace pugi -{ -#ifndef PUGIXML_NO_EXCEPTIONS - PUGI__FN xpath_exception::xpath_exception(const xpath_parse_result& result_): _result(result_) - { - assert(_result.error); - } - - PUGI__FN const char* xpath_exception::what() const throw() - { - return _result.error; - } - - PUGI__FN const xpath_parse_result& xpath_exception::result() const - { - return _result; - } -#endif - - PUGI__FN xpath_node::xpath_node() - { - } - - PUGI__FN xpath_node::xpath_node(const xml_node& node_): _node(node_) - { - } - - PUGI__FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_) - { - } - - PUGI__FN xml_node xpath_node::node() const - { - return _attribute ? xml_node() : _node; - } - - PUGI__FN xml_attribute xpath_node::attribute() const - { - return _attribute; - } - - PUGI__FN xml_node xpath_node::parent() const - { - return _attribute ? _node : _node.parent(); - } - - PUGI__FN static void unspecified_bool_xpath_node(xpath_node***) - { - } - - PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type() const - { - return (_node || _attribute) ? unspecified_bool_xpath_node : 0; - } - - PUGI__FN bool xpath_node::operator!() const - { - return !(_node || _attribute); - } - - PUGI__FN bool xpath_node::operator==(const xpath_node& n) const - { - return _node == n._node && _attribute == n._attribute; - } - - PUGI__FN bool xpath_node::operator!=(const xpath_node& n) const - { - return _node != n._node || _attribute != n._attribute; - } - -#ifdef __BORLANDC__ - PUGI__FN bool operator&&(const xpath_node& lhs, bool rhs) - { - return (bool)lhs && rhs; - } - - PUGI__FN bool operator||(const xpath_node& lhs, bool rhs) - { - return (bool)lhs || rhs; - } -#endif - - PUGI__FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_) - { - assert(begin_ <= end_); - - size_t size_ = static_cast(end_ - begin_); - - if (size_ <= 1) - { - // deallocate old buffer - if (_begin != &_storage) impl::xml_memory::deallocate(_begin); - - // use internal buffer - if (begin_ != end_) _storage = *begin_; - - _begin = &_storage; - _end = &_storage + size_; - } - else - { - // make heap copy - xpath_node* storage = static_cast(impl::xml_memory::allocate(size_ * sizeof(xpath_node))); - - if (!storage) - { - #ifdef PUGIXML_NO_EXCEPTIONS - return; - #else - throw std::bad_alloc(); - #endif - } - - memcpy(storage, begin_, size_ * sizeof(xpath_node)); - - // deallocate old buffer - if (_begin != &_storage) impl::xml_memory::deallocate(_begin); - - // finalize - _begin = storage; - _end = storage + size_; - } - } - - PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(&_storage), _end(&_storage) - { - } - - PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_), _begin(&_storage), _end(&_storage) - { - _assign(begin_, end_); - } - - PUGI__FN xpath_node_set::~xpath_node_set() - { - if (_begin != &_storage) impl::xml_memory::deallocate(_begin); - } - - PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(ns._type), _begin(&_storage), _end(&_storage) - { - _assign(ns._begin, ns._end); - } - - PUGI__FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns) - { - if (this == &ns) return *this; - - _type = ns._type; - _assign(ns._begin, ns._end); - - return *this; - } - - PUGI__FN xpath_node_set::type_t xpath_node_set::type() const - { - return _type; - } - - PUGI__FN size_t xpath_node_set::size() const - { - return _end - _begin; - } - - PUGI__FN bool xpath_node_set::empty() const - { - return _begin == _end; - } - - PUGI__FN const xpath_node& xpath_node_set::operator[](size_t index) const - { - assert(index < size()); - return _begin[index]; - } - - PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin() const - { - return _begin; - } - - PUGI__FN xpath_node_set::const_iterator xpath_node_set::end() const - { - return _end; - } - - PUGI__FN void xpath_node_set::sort(bool reverse) - { - _type = impl::xpath_sort(_begin, _end, _type, reverse); - } - - PUGI__FN xpath_node xpath_node_set::first() const - { - return impl::xpath_first(_begin, _end, _type); - } - - PUGI__FN xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0) - { - } - - PUGI__FN xpath_parse_result::operator bool() const - { - return error == 0; - } - - PUGI__FN const char* xpath_parse_result::description() const - { - return error ? error : "No error"; - } - - PUGI__FN xpath_variable::xpath_variable() - { - } - - PUGI__FN const char_t* xpath_variable::name() const - { - switch (_type) - { - case xpath_type_node_set: - return static_cast(this)->name; - - case xpath_type_number: - return static_cast(this)->name; - - case xpath_type_string: - return static_cast(this)->name; - - case xpath_type_boolean: - return static_cast(this)->name; - - default: - assert(!"Invalid variable type"); - return 0; - } - } - - PUGI__FN xpath_value_type xpath_variable::type() const - { - return _type; - } - - PUGI__FN bool xpath_variable::get_boolean() const - { - return (_type == xpath_type_boolean) ? static_cast(this)->value : false; - } - - PUGI__FN double xpath_variable::get_number() const - { - return (_type == xpath_type_number) ? static_cast(this)->value : impl::gen_nan(); - } - - PUGI__FN const char_t* xpath_variable::get_string() const - { - const char_t* value = (_type == xpath_type_string) ? static_cast(this)->value : 0; - return value ? value : PUGIXML_TEXT(""); - } - - PUGI__FN const xpath_node_set& xpath_variable::get_node_set() const - { - return (_type == xpath_type_node_set) ? static_cast(this)->value : impl::dummy_node_set; - } - - PUGI__FN bool xpath_variable::set(bool value) - { - if (_type != xpath_type_boolean) return false; - - static_cast(this)->value = value; - return true; - } - - PUGI__FN bool xpath_variable::set(double value) - { - if (_type != xpath_type_number) return false; - - static_cast(this)->value = value; - return true; - } - - PUGI__FN bool xpath_variable::set(const char_t* value) - { - if (_type != xpath_type_string) return false; - - impl::xpath_variable_string* var = static_cast(this); - - // duplicate string - size_t size = (impl::strlength(value) + 1) * sizeof(char_t); - - char_t* copy = static_cast(impl::xml_memory::allocate(size)); - if (!copy) return false; - - memcpy(copy, value, size); - - // replace old string - if (var->value) impl::xml_memory::deallocate(var->value); - var->value = copy; - - return true; - } - - PUGI__FN bool xpath_variable::set(const xpath_node_set& value) - { - if (_type != xpath_type_node_set) return false; - - static_cast(this)->value = value; - return true; - } - - PUGI__FN xpath_variable_set::xpath_variable_set() - { - for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _data[i] = 0; - } - - PUGI__FN xpath_variable_set::~xpath_variable_set() - { - for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) - { - xpath_variable* var = _data[i]; - - while (var) - { - xpath_variable* next = var->_next; - - impl::delete_xpath_variable(var->_type, var); - - var = next; - } - } - } - - PUGI__FN xpath_variable* xpath_variable_set::find(const char_t* name) const - { - const size_t hash_size = sizeof(_data) / sizeof(_data[0]); - size_t hash = impl::hash_string(name) % hash_size; - - // look for existing variable - for (xpath_variable* var = _data[hash]; var; var = var->_next) - if (impl::strequal(var->name(), name)) - return var; - - return 0; - } - - PUGI__FN xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type) - { - const size_t hash_size = sizeof(_data) / sizeof(_data[0]); - size_t hash = impl::hash_string(name) % hash_size; - - // look for existing variable - for (xpath_variable* var = _data[hash]; var; var = var->_next) - if (impl::strequal(var->name(), name)) - return var->type() == type ? var : 0; - - // add new variable - xpath_variable* result = impl::new_xpath_variable(type, name); - - if (result) - { - result->_type = type; - result->_next = _data[hash]; - - _data[hash] = result; - } - - return result; - } - - PUGI__FN bool xpath_variable_set::set(const char_t* name, bool value) - { - xpath_variable* var = add(name, xpath_type_boolean); - return var ? var->set(value) : false; - } - - PUGI__FN bool xpath_variable_set::set(const char_t* name, double value) - { - xpath_variable* var = add(name, xpath_type_number); - return var ? var->set(value) : false; - } - - PUGI__FN bool xpath_variable_set::set(const char_t* name, const char_t* value) - { - xpath_variable* var = add(name, xpath_type_string); - return var ? var->set(value) : false; - } - - PUGI__FN bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value) - { - xpath_variable* var = add(name, xpath_type_node_set); - return var ? var->set(value) : false; - } - - PUGI__FN xpath_variable* xpath_variable_set::get(const char_t* name) - { - return find(name); - } - - PUGI__FN const xpath_variable* xpath_variable_set::get(const char_t* name) const - { - return find(name); - } - - PUGI__FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0) - { - impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create(); - - if (!qimpl) - { - #ifdef PUGIXML_NO_EXCEPTIONS - _result.error = "Out of memory"; - #else - throw std::bad_alloc(); - #endif - } - else - { - impl::buffer_holder impl_holder(qimpl, impl::xpath_query_impl::destroy); - - qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result); - - if (qimpl->root) - { - _impl = static_cast(impl_holder.release()); - _result.error = 0; - } - } - } - - PUGI__FN xpath_query::~xpath_query() - { - impl::xpath_query_impl::destroy(_impl); - } - - PUGI__FN xpath_value_type xpath_query::return_type() const - { - if (!_impl) return xpath_type_none; - - return static_cast(_impl)->root->rettype(); - } - - PUGI__FN bool xpath_query::evaluate_boolean(const xpath_node& n) const - { - if (!_impl) return false; - - impl::xpath_context c(n, 1, 1); - impl::xpath_stack_data sd; - - #ifdef PUGIXML_NO_EXCEPTIONS - if (setjmp(sd.error_handler)) return false; - #endif - - return static_cast(_impl)->root->eval_boolean(c, sd.stack); - } - - PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const - { - if (!_impl) return impl::gen_nan(); - - impl::xpath_context c(n, 1, 1); - impl::xpath_stack_data sd; - - #ifdef PUGIXML_NO_EXCEPTIONS - if (setjmp(sd.error_handler)) return impl::gen_nan(); - #endif - - return static_cast(_impl)->root->eval_number(c, sd.stack); - } - -#ifndef PUGIXML_NO_STL - PUGI__FN string_t xpath_query::evaluate_string(const xpath_node& n) const - { - impl::xpath_stack_data sd; - - return impl::evaluate_string_impl(static_cast(_impl), n, sd).c_str(); - } -#endif - - PUGI__FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const - { - impl::xpath_stack_data sd; - - impl::xpath_string r = impl::evaluate_string_impl(static_cast(_impl), n, sd); - - size_t full_size = r.length() + 1; - - if (capacity > 0) - { - size_t size = (full_size < capacity) ? full_size : capacity; - assert(size > 0); - - memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t)); - buffer[size - 1] = 0; - } - - return full_size; - } - - PUGI__FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const - { - if (!_impl) return xpath_node_set(); - - impl::xpath_ast_node* root = static_cast(_impl)->root; - - if (root->rettype() != xpath_type_node_set) - { - #ifdef PUGIXML_NO_EXCEPTIONS - return xpath_node_set(); - #else - xpath_parse_result res; - res.error = "Expression does not evaluate to node set"; - - throw xpath_exception(res); - #endif - } - - impl::xpath_context c(n, 1, 1); - impl::xpath_stack_data sd; - - #ifdef PUGIXML_NO_EXCEPTIONS - if (setjmp(sd.error_handler)) return xpath_node_set(); - #endif - - impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack); - - return xpath_node_set(r.begin(), r.end(), r.type()); - } - - PUGI__FN const xpath_parse_result& xpath_query::result() const - { - return _result; - } - - PUGI__FN static void unspecified_bool_xpath_query(xpath_query***) - { - } - - PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type() const - { - return _impl ? unspecified_bool_xpath_query : 0; - } - - PUGI__FN bool xpath_query::operator!() const - { - return !_impl; - } - - PUGI__FN xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const - { - xpath_query q(query, variables); - return select_single_node(q); - } - - PUGI__FN xpath_node xml_node::select_single_node(const xpath_query& query) const - { - xpath_node_set s = query.evaluate_node_set(*this); - return s.empty() ? xpath_node() : s.first(); - } - - PUGI__FN xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const - { - xpath_query q(query, variables); - return select_nodes(q); - } - - PUGI__FN xpath_node_set xml_node::select_nodes(const xpath_query& query) const - { - return query.evaluate_node_set(*this); - } -} - -#endif - -#ifdef __BORLANDC__ -# pragma option pop -#endif - -// Intel C++ does not properly keep warning state for function templates, -// so popping warning state at the end of translation unit leads to warnings in the middle. -#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) -# pragma warning(pop) -#endif - -// Undefine all local macros (makes sure we're not leaking macros in header-only mode) -#undef PUGI__NO_INLINE -#undef PUGI__STATIC_ASSERT -#undef PUGI__DMC_VOLATILE -#undef PUGI__MSVC_CRT_VERSION -#undef PUGI__NS_BEGIN -#undef PUGI__NS_END -#undef PUGI__FN -#undef PUGI__FN_NO_INLINE -#undef PUGI__IS_CHARTYPE_IMPL -#undef PUGI__IS_CHARTYPE -#undef PUGI__IS_CHARTYPEX -#undef PUGI__SKIPWS -#undef PUGI__OPTSET -#undef PUGI__PUSHNODE -#undef PUGI__POPNODE -#undef PUGI__SCANFOR -#undef PUGI__SCANWHILE -#undef PUGI__ENDSEG -#undef PUGI__THROW_ERROR -#undef PUGI__CHECK_ERROR - -#endif - -/** - * Copyright (c) 2006-2012 Arseny Kapoulkine - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ diff --git a/libs/pugixml/pugixml.hpp b/libs/pugixml/pugixml.hpp deleted file mode 100644 index 894c34dcb..000000000 --- a/libs/pugixml/pugixml.hpp +++ /dev/null @@ -1,1265 +0,0 @@ -/** - * pugixml parser - version 1.2 - * -------------------------------------------------------- - * Copyright (C) 2006-2012, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) - * Report bugs and download new versions at http://pugixml.org/ - * - * This library is distributed under the MIT License. See notice at the end - * of this file. - * - * This work is based on the pugxml parser, which is: - * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) - */ - -#ifndef PUGIXML_VERSION -// Define version macro; evaluates to major * 100 + minor so that it's safe to use in less-than comparisons -# define PUGIXML_VERSION 120 -#endif - -// Include user configuration file (this can define various configuration macros) -#include "pugiconfig.hpp" - -#ifndef HEADER_PUGIXML_HPP -#define HEADER_PUGIXML_HPP - -// Include stddef.h for size_t and ptrdiff_t -#include - -// Include exception header for XPath -#if !defined(PUGIXML_NO_XPATH) && !defined(PUGIXML_NO_EXCEPTIONS) -# include -#endif - -// Include STL headers -#ifndef PUGIXML_NO_STL -# include -# include -# include -#endif - -// Macro for deprecated features -#ifndef PUGIXML_DEPRECATED -# if defined(__GNUC__) -# define PUGIXML_DEPRECATED __attribute__((deprecated)) -# elif defined(_MSC_VER) && _MSC_VER >= 1300 -# define PUGIXML_DEPRECATED __declspec(deprecated) -# else -# define PUGIXML_DEPRECATED -# endif -#endif - -// If no API is defined, assume default -#ifndef PUGIXML_API -# define PUGIXML_API -#endif - -// If no API for classes is defined, assume default -#ifndef PUGIXML_CLASS -# define PUGIXML_CLASS PUGIXML_API -#endif - -// If no API for functions is defined, assume default -#ifndef PUGIXML_FUNCTION -# define PUGIXML_FUNCTION PUGIXML_API -#endif - -// Character interface macros -#ifdef PUGIXML_WCHAR_MODE -# define PUGIXML_TEXT(t) L ## t -# define PUGIXML_CHAR wchar_t -#else -# define PUGIXML_TEXT(t) t -# define PUGIXML_CHAR char -#endif - -namespace pugi -{ - // Character type used for all internal storage and operations; depends on PUGIXML_WCHAR_MODE - typedef PUGIXML_CHAR char_t; - -#ifndef PUGIXML_NO_STL - // String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE - typedef std::basic_string, std::allocator > string_t; -#endif -} - -// The PugiXML namespace -namespace pugi -{ - // Tree node types - enum xml_node_type - { - node_null, // Empty (null) node handle - node_document, // A document tree's absolute root - node_element, // Element tag, i.e. '' - node_pcdata, // Plain character data, i.e. 'text' - node_cdata, // Character data, i.e. '' - node_comment, // Comment tag, i.e. '' - node_pi, // Processing instruction, i.e. '' - node_declaration, // Document declaration, i.e. '' - node_doctype // Document type declaration, i.e. '' - }; - - // Parsing options - - // Minimal parsing mode (equivalent to turning all other flags off). - // Only elements and PCDATA sections are added to the DOM tree, no text conversions are performed. - const unsigned int parse_minimal = 0x0000; - - // This flag determines if processing instructions (node_pi) are added to the DOM tree. This flag is off by default. - const unsigned int parse_pi = 0x0001; - - // This flag determines if comments (node_comment) are added to the DOM tree. This flag is off by default. - const unsigned int parse_comments = 0x0002; - - // This flag determines if CDATA sections (node_cdata) are added to the DOM tree. This flag is on by default. - const unsigned int parse_cdata = 0x0004; - - // This flag determines if plain character data (node_pcdata) that consist only of whitespace are added to the DOM tree. - // This flag is off by default; turning it on usually results in slower parsing and more memory consumption. - const unsigned int parse_ws_pcdata = 0x0008; - - // This flag determines if character and entity references are expanded during parsing. This flag is on by default. - const unsigned int parse_escapes = 0x0010; - - // This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default. - const unsigned int parse_eol = 0x0020; - - // This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default. - const unsigned int parse_wconv_attribute = 0x0040; - - // This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default. - const unsigned int parse_wnorm_attribute = 0x0080; - - // This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default. - const unsigned int parse_declaration = 0x0100; - - // This flag determines if document type declaration (node_doctype) is added to the DOM tree. This flag is off by default. - const unsigned int parse_doctype = 0x0200; - - // This flag determines if plain character data (node_pcdata) that is the only child of the parent node and that consists only - // of whitespace is added to the DOM tree. - // This flag is off by default; turning it on may result in slower parsing and more memory consumption. - const unsigned int parse_ws_pcdata_single = 0x0400; - - // The default parsing mode. - // Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded, - // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. - const unsigned int parse_default = parse_cdata | parse_escapes | parse_wconv_attribute | parse_eol; - - // The full parsing mode. - // Nodes of all types are added to the DOM tree, character/reference entities are expanded, - // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. - const unsigned int parse_full = parse_default | parse_pi | parse_comments | parse_declaration | parse_doctype; - - // These flags determine the encoding of input data for XML document - enum xml_encoding - { - encoding_auto, // Auto-detect input encoding using BOM or < / class xml_object_range - { - public: - typedef It const_iterator; - - xml_object_range(It b, It e): _begin(b), _end(e) - { - } - - It begin() const { return _begin; } - It end() const { return _end; } - - private: - It _begin, _end; - }; - - // Writer interface for node printing (see xml_node::print) - class PUGIXML_CLASS xml_writer - { - public: - virtual ~xml_writer() {} - - // Write memory chunk into stream/file/whatever - virtual void write(const void* data, size_t size) = 0; - }; - - // xml_writer implementation for FILE* - class PUGIXML_CLASS xml_writer_file: public xml_writer - { - public: - // Construct writer from a FILE* object; void* is used to avoid header dependencies on stdio - xml_writer_file(void* file); - - virtual void write(const void* data, size_t size); - - private: - void* file; - }; - - #ifndef PUGIXML_NO_STL - // xml_writer implementation for streams - class PUGIXML_CLASS xml_writer_stream: public xml_writer - { - public: - // Construct writer from an output stream object - xml_writer_stream(std::basic_ostream >& stream); - xml_writer_stream(std::basic_ostream >& stream); - - virtual void write(const void* data, size_t size); - - private: - std::basic_ostream >* narrow_stream; - std::basic_ostream >* wide_stream; - }; - #endif - - // A light-weight handle for manipulating attributes in DOM tree - class PUGIXML_CLASS xml_attribute - { - friend class xml_attribute_iterator; - friend class xml_node; - - private: - xml_attribute_struct* _attr; - - typedef void (*unspecified_bool_type)(xml_attribute***); - - public: - // Default constructor. Constructs an empty attribute. - xml_attribute(); - - // Constructs attribute from internal pointer - explicit xml_attribute(xml_attribute_struct* attr); - - // Safe bool conversion operator - operator unspecified_bool_type() const; - - // Borland C++ workaround - bool operator!() const; - - // Comparison operators (compares wrapped attribute pointers) - bool operator==(const xml_attribute& r) const; - bool operator!=(const xml_attribute& r) const; - bool operator<(const xml_attribute& r) const; - bool operator>(const xml_attribute& r) const; - bool operator<=(const xml_attribute& r) const; - bool operator>=(const xml_attribute& r) const; - - // Check if attribute is empty - bool empty() const; - - // Get attribute name/value, or "" if attribute is empty - const char_t* name() const; - const char_t* value() const; - - // Get attribute value, or the default value if attribute is empty - const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; - - // Get attribute value as a number, or the default value if conversion did not succeed or attribute is empty - int as_int(int def = 0) const; - unsigned int as_uint(unsigned int def = 0) const; - double as_double(double def = 0) const; - float as_float(float def = 0) const; - - // Get attribute value as bool (returns true if first character is in '1tTyY' set), or the default value if attribute is empty - bool as_bool(bool def = false) const; - - // Set attribute name/value (returns false if attribute is empty or there is not enough memory) - bool set_name(const char_t* rhs); - bool set_value(const char_t* rhs); - - // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") - bool set_value(int rhs); - bool set_value(unsigned int rhs); - bool set_value(double rhs); - bool set_value(bool rhs); - - // Set attribute value (equivalent to set_value without error checking) - xml_attribute& operator=(const char_t* rhs); - xml_attribute& operator=(int rhs); - xml_attribute& operator=(unsigned int rhs); - xml_attribute& operator=(double rhs); - xml_attribute& operator=(bool rhs); - - // Get next/previous attribute in the attribute list of the parent node - xml_attribute next_attribute() const; - xml_attribute previous_attribute() const; - - // Get hash value (unique for handles to the same object) - size_t hash_value() const; - - // Get internal pointer - xml_attribute_struct* internal_object() const; - }; - -#ifdef __BORLANDC__ - // Borland C++ workaround - bool PUGIXML_FUNCTION operator&&(const xml_attribute& lhs, bool rhs); - bool PUGIXML_FUNCTION operator||(const xml_attribute& lhs, bool rhs); -#endif - - // A light-weight handle for manipulating nodes in DOM tree - class PUGIXML_CLASS xml_node - { - friend class xml_attribute_iterator; - friend class xml_node_iterator; - friend class xml_named_node_iterator; - - protected: - xml_node_struct* _root; - - typedef void (*unspecified_bool_type)(xml_node***); - - public: - // Default constructor. Constructs an empty node. - xml_node(); - - // Constructs node from internal pointer - explicit xml_node(xml_node_struct* p); - - // Safe bool conversion operator - operator unspecified_bool_type() const; - - // Borland C++ workaround - bool operator!() const; - - // Comparison operators (compares wrapped node pointers) - bool operator==(const xml_node& r) const; - bool operator!=(const xml_node& r) const; - bool operator<(const xml_node& r) const; - bool operator>(const xml_node& r) const; - bool operator<=(const xml_node& r) const; - bool operator>=(const xml_node& r) const; - - // Check if node is empty. - bool empty() const; - - // Get node type - xml_node_type type() const; - - // Get node name/value, or "" if node is empty or it has no name/value - const char_t* name() const; - const char_t* value() const; - - // Get attribute list - xml_attribute first_attribute() const; - xml_attribute last_attribute() const; - - // Get children list - xml_node first_child() const; - xml_node last_child() const; - - // Get next/previous sibling in the children list of the parent node - xml_node next_sibling() const; - xml_node previous_sibling() const; - - // Get parent node - xml_node parent() const; - - // Get root of DOM tree this node belongs to - xml_node root() const; - - // Get text object for the current node - xml_text text() const; - - // Get child, attribute or next/previous sibling with the specified name - xml_node child(const char_t* name) const; - xml_attribute attribute(const char_t* name) const; - xml_node next_sibling(const char_t* name) const; - xml_node previous_sibling(const char_t* name) const; - - // Get child value of current node; that is, value of the first child node of type PCDATA/CDATA - const char_t* child_value() const; - - // Get child value of child with specified name. Equivalent to child(name).child_value(). - const char_t* child_value(const char_t* name) const; - - // Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value) - bool set_name(const char_t* rhs); - bool set_value(const char_t* rhs); - - // Add attribute with specified name. Returns added attribute, or empty attribute on errors. - xml_attribute append_attribute(const char_t* name); - xml_attribute prepend_attribute(const char_t* name); - xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr); - xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr); - - // Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors. - xml_attribute append_copy(const xml_attribute& proto); - xml_attribute prepend_copy(const xml_attribute& proto); - xml_attribute insert_copy_after(const xml_attribute& proto, const xml_attribute& attr); - xml_attribute insert_copy_before(const xml_attribute& proto, const xml_attribute& attr); - - // Add child node with specified type. Returns added node, or empty node on errors. - xml_node append_child(xml_node_type type = node_element); - xml_node prepend_child(xml_node_type type = node_element); - xml_node insert_child_after(xml_node_type type, const xml_node& node); - xml_node insert_child_before(xml_node_type type, const xml_node& node); - - // Add child element with specified name. Returns added node, or empty node on errors. - xml_node append_child(const char_t* name); - xml_node prepend_child(const char_t* name); - xml_node insert_child_after(const char_t* name, const xml_node& node); - xml_node insert_child_before(const char_t* name, const xml_node& node); - - // Add a copy of the specified node as a child. Returns added node, or empty node on errors. - xml_node append_copy(const xml_node& proto); - xml_node prepend_copy(const xml_node& proto); - xml_node insert_copy_after(const xml_node& proto, const xml_node& node); - xml_node insert_copy_before(const xml_node& proto, const xml_node& node); - - // Remove specified attribute - bool remove_attribute(const xml_attribute& a); - bool remove_attribute(const char_t* name); - - // Remove specified child - bool remove_child(const xml_node& n); - bool remove_child(const char_t* name); - - // Find attribute using predicate. Returns first attribute for which predicate returned true. - template xml_attribute find_attribute(Predicate pred) const - { - if (!_root) return xml_attribute(); - - for (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute()) - if (pred(attrib)) - return attrib; - - return xml_attribute(); - } - - // Find child node using predicate. Returns first child for which predicate returned true. - template xml_node find_child(Predicate pred) const - { - if (!_root) return xml_node(); - - for (xml_node node = first_child(); node; node = node.next_sibling()) - if (pred(node)) - return node; - - return xml_node(); - } - - // Find node from subtree using predicate. Returns first node from subtree (depth-first), for which predicate returned true. - template xml_node find_node(Predicate pred) const - { - if (!_root) return xml_node(); - - xml_node cur = first_child(); - - while (cur._root && cur._root != _root) - { - if (pred(cur)) return cur; - - if (cur.first_child()) cur = cur.first_child(); - else if (cur.next_sibling()) cur = cur.next_sibling(); - else - { - while (!cur.next_sibling() && cur._root != _root) cur = cur.parent(); - - if (cur._root != _root) cur = cur.next_sibling(); - } - } - - return xml_node(); - } - - // Find child node by attribute name/value - xml_node find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const; - xml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const; - - #ifndef PUGIXML_NO_STL - // Get the absolute node path from root as a text string. - string_t path(char_t delimiter = '/') const; - #endif - - // Search for a node by path consisting of node names and . or .. elements. - xml_node first_element_by_path(const char_t* path, char_t delimiter = '/') const; - - // Recursively traverse subtree with xml_tree_walker - bool traverse(xml_tree_walker& walker); - - #ifndef PUGIXML_NO_XPATH - // Select single node by evaluating XPath query. Returns first node from the resulting node set. - xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const; - xpath_node select_single_node(const xpath_query& query) const; - - // Select node set by evaluating XPath query - xpath_node_set select_nodes(const char_t* query, xpath_variable_set* variables = 0) const; - xpath_node_set select_nodes(const xpath_query& query) const; - #endif - - // Print subtree using a writer object - void print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; - - #ifndef PUGIXML_NO_STL - // Print subtree to stream - void print(std::basic_ostream >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; - void print(std::basic_ostream >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, unsigned int depth = 0) const; - #endif - - // Child nodes iterators - typedef xml_node_iterator iterator; - - iterator begin() const; - iterator end() const; - - // Attribute iterators - typedef xml_attribute_iterator attribute_iterator; - - attribute_iterator attributes_begin() const; - attribute_iterator attributes_end() const; - - // Range-based for support - xml_object_range children() const; - xml_object_range children(const char_t* name) const; - xml_object_range attributes() const; - - // Get node offset in parsed file/string (in char_t units) for debugging purposes - ptrdiff_t offset_debug() const; - - // Get hash value (unique for handles to the same object) - size_t hash_value() const; - - // Get internal pointer - xml_node_struct* internal_object() const; - }; - -#ifdef __BORLANDC__ - // Borland C++ workaround - bool PUGIXML_FUNCTION operator&&(const xml_node& lhs, bool rhs); - bool PUGIXML_FUNCTION operator||(const xml_node& lhs, bool rhs); -#endif - - // A helper for working with text inside PCDATA nodes - class PUGIXML_CLASS xml_text - { - friend class xml_node; - - xml_node_struct* _root; - - typedef void (*unspecified_bool_type)(xml_text***); - - explicit xml_text(xml_node_struct* root); - - xml_node_struct* _data_new(); - xml_node_struct* _data() const; - - public: - // Default constructor. Constructs an empty object. - xml_text(); - - // Safe bool conversion operator - operator unspecified_bool_type() const; - - // Borland C++ workaround - bool operator!() const; - - // Check if text object is empty - bool empty() const; - - // Get text, or "" if object is empty - const char_t* get() const; - - // Get text, or the default value if object is empty - const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; - - // Get text as a number, or the default value if conversion did not succeed or object is empty - int as_int(int def = 0) const; - unsigned int as_uint(unsigned int def = 0) const; - double as_double(double def = 0) const; - float as_float(float def = 0) const; - - // Get text as bool (returns true if first character is in '1tTyY' set), or the default value if object is empty - bool as_bool(bool def = false) const; - - // Set text (returns false if object is empty or there is not enough memory) - bool set(const char_t* rhs); - - // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") - bool set(int rhs); - bool set(unsigned int rhs); - bool set(double rhs); - bool set(bool rhs); - - // Set text (equivalent to set without error checking) - xml_text& operator=(const char_t* rhs); - xml_text& operator=(int rhs); - xml_text& operator=(unsigned int rhs); - xml_text& operator=(double rhs); - xml_text& operator=(bool rhs); - - // Get the data node (node_pcdata or node_cdata) for this object - xml_node data() const; - }; - -#ifdef __BORLANDC__ - // Borland C++ workaround - bool PUGIXML_FUNCTION operator&&(const xml_text& lhs, bool rhs); - bool PUGIXML_FUNCTION operator||(const xml_text& lhs, bool rhs); -#endif - - // Child node iterator (a bidirectional iterator over a collection of xml_node) - class PUGIXML_CLASS xml_node_iterator - { - friend class xml_node; - - private: - mutable xml_node _wrap; - xml_node _parent; - - xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent); - - public: - // Iterator traits - typedef ptrdiff_t difference_type; - typedef xml_node value_type; - typedef xml_node* pointer; - typedef xml_node& reference; - - #ifndef PUGIXML_NO_STL - typedef std::bidirectional_iterator_tag iterator_category; - #endif - - // Default constructor - xml_node_iterator(); - - // Construct an iterator which points to the specified node - xml_node_iterator(const xml_node& node); - - // Iterator operators - bool operator==(const xml_node_iterator& rhs) const; - bool operator!=(const xml_node_iterator& rhs) const; - - xml_node& operator*() const; - xml_node* operator->() const; - - const xml_node_iterator& operator++(); - xml_node_iterator operator++(int); - - const xml_node_iterator& operator--(); - xml_node_iterator operator--(int); - }; - - // Attribute iterator (a bidirectional iterator over a collection of xml_attribute) - class PUGIXML_CLASS xml_attribute_iterator - { - friend class xml_node; - - private: - mutable xml_attribute _wrap; - xml_node _parent; - - xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent); - - public: - // Iterator traits - typedef ptrdiff_t difference_type; - typedef xml_attribute value_type; - typedef xml_attribute* pointer; - typedef xml_attribute& reference; - - #ifndef PUGIXML_NO_STL - typedef std::bidirectional_iterator_tag iterator_category; - #endif - - // Default constructor - xml_attribute_iterator(); - - // Construct an iterator which points to the specified attribute - xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent); - - // Iterator operators - bool operator==(const xml_attribute_iterator& rhs) const; - bool operator!=(const xml_attribute_iterator& rhs) const; - - xml_attribute& operator*() const; - xml_attribute* operator->() const; - - const xml_attribute_iterator& operator++(); - xml_attribute_iterator operator++(int); - - const xml_attribute_iterator& operator--(); - xml_attribute_iterator operator--(int); - }; - - // Named node range helper - class xml_named_node_iterator - { - public: - // Iterator traits - typedef ptrdiff_t difference_type; - typedef xml_node value_type; - typedef xml_node* pointer; - typedef xml_node& reference; - - #ifndef PUGIXML_NO_STL - typedef std::forward_iterator_tag iterator_category; - #endif - - // Default constructor - xml_named_node_iterator(); - - // Construct an iterator which points to the specified node - xml_named_node_iterator(const xml_node& node, const char_t* name); - - // Iterator operators - bool operator==(const xml_named_node_iterator& rhs) const; - bool operator!=(const xml_named_node_iterator& rhs) const; - - xml_node& operator*() const; - xml_node* operator->() const; - - const xml_named_node_iterator& operator++(); - xml_named_node_iterator operator++(int); - - private: - mutable xml_node _node; - const char_t* _name; - }; - - // Abstract tree walker class (see xml_node::traverse) - class PUGIXML_CLASS xml_tree_walker - { - friend class xml_node; - - private: - int _depth; - - protected: - // Get current traversal depth - int depth() const; - - public: - xml_tree_walker(); - virtual ~xml_tree_walker(); - - // Callback that is called when traversal begins - virtual bool begin(xml_node& node); - - // Callback that is called for each node traversed - virtual bool for_each(xml_node& node) = 0; - - // Callback that is called when traversal ends - virtual bool end(xml_node& node); - }; - - // Parsing status, returned as part of xml_parse_result object - enum xml_parse_status - { - status_ok = 0, // No error - - status_file_not_found, // File was not found during load_file() - status_io_error, // Error reading from file/stream - status_out_of_memory, // Could not allocate memory - status_internal_error, // Internal error occurred - - status_unrecognized_tag, // Parser could not determine tag type - - status_bad_pi, // Parsing error occurred while parsing document declaration/processing instruction - status_bad_comment, // Parsing error occurred while parsing comment - status_bad_cdata, // Parsing error occurred while parsing CDATA section - status_bad_doctype, // Parsing error occurred while parsing document type declaration - status_bad_pcdata, // Parsing error occurred while parsing PCDATA section - status_bad_start_element, // Parsing error occurred while parsing start element tag - status_bad_attribute, // Parsing error occurred while parsing element attribute - status_bad_end_element, // Parsing error occurred while parsing end element tag - status_end_element_mismatch // There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag) - }; - - // Parsing result - struct PUGIXML_CLASS xml_parse_result - { - // Parsing status (see xml_parse_status) - xml_parse_status status; - - // Last parsed offset (in char_t units from start of input data) - ptrdiff_t offset; - - // Source document encoding - xml_encoding encoding; - - // Default constructor, initializes object to failed state - xml_parse_result(); - - // Cast to bool operator - operator bool() const; - - // Get error description - const char* description() const; - }; - - // Document class (DOM tree root) - class PUGIXML_CLASS xml_document: public xml_node - { - private: - char_t* _buffer; - - char _memory[192]; - - // Non-copyable semantics - xml_document(const xml_document&); - const xml_document& operator=(const xml_document&); - - void create(); - void destroy(); - - xml_parse_result load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own); - - public: - // Default constructor, makes empty document - xml_document(); - - // Destructor, invalidates all node/attribute handles to this document - ~xml_document(); - - // Removes all nodes, leaving the empty document - void reset(); - - // Removes all nodes, then copies the entire contents of the specified document - void reset(const xml_document& proto); - - #ifndef PUGIXML_NO_STL - // Load document from stream. - xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default); - #endif - - // Load document from zero-terminated string. No encoding conversions are applied. - xml_parse_result load(const char_t* contents, unsigned int options = parse_default); - - // Load document from file - xml_parse_result load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - xml_parse_result load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - - // Load document from buffer. Copies/converts the buffer, so it may be deleted or changed after the function returns. - xml_parse_result load_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - - // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). - // You should ensure that buffer data will persist throughout the document's lifetime, and free the buffer memory manually once document is destroyed. - xml_parse_result load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - - // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). - // You should allocate the buffer with pugixml allocation function; document will free the buffer when it is no longer needed (you can't use it anymore). - xml_parse_result load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - - // Save XML document to writer (semantics is slightly different from xml_node::print, see documentation for details). - void save(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; - - #ifndef PUGIXML_NO_STL - // Save XML document to stream (semantics is slightly different from xml_node::print, see documentation for details). - void save(std::basic_ostream >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; - void save(std::basic_ostream >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default) const; - #endif - - // Save XML to file - bool save_file(const char* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; - bool save_file(const wchar_t* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; - - // Get document element - xml_node document_element() const; - }; - -#ifndef PUGIXML_NO_XPATH - // XPath query return type - enum xpath_value_type - { - xpath_type_none, // Unknown type (query failed to compile) - xpath_type_node_set, // Node set (xpath_node_set) - xpath_type_number, // Number - xpath_type_string, // String - xpath_type_boolean // Boolean - }; - - // XPath parsing result - struct PUGIXML_CLASS xpath_parse_result - { - // Error message (0 if no error) - const char* error; - - // Last parsed offset (in char_t units from string start) - ptrdiff_t offset; - - // Default constructor, initializes object to failed state - xpath_parse_result(); - - // Cast to bool operator - operator bool() const; - - // Get error description - const char* description() const; - }; - - // A single XPath variable - class PUGIXML_CLASS xpath_variable - { - friend class xpath_variable_set; - - protected: - xpath_value_type _type; - xpath_variable* _next; - - xpath_variable(); - - // Non-copyable semantics - xpath_variable(const xpath_variable&); - xpath_variable& operator=(const xpath_variable&); - - public: - // Get variable name - const char_t* name() const; - - // Get variable type - xpath_value_type type() const; - - // Get variable value; no type conversion is performed, default value (false, NaN, empty string, empty node set) is returned on type mismatch error - bool get_boolean() const; - double get_number() const; - const char_t* get_string() const; - const xpath_node_set& get_node_set() const; - - // Set variable value; no type conversion is performed, false is returned on type mismatch error - bool set(bool value); - bool set(double value); - bool set(const char_t* value); - bool set(const xpath_node_set& value); - }; - - // A set of XPath variables - class PUGIXML_CLASS xpath_variable_set - { - private: - xpath_variable* _data[64]; - - // Non-copyable semantics - xpath_variable_set(const xpath_variable_set&); - xpath_variable_set& operator=(const xpath_variable_set&); - - xpath_variable* find(const char_t* name) const; - - public: - // Default constructor/destructor - xpath_variable_set(); - ~xpath_variable_set(); - - // Add a new variable or get the existing one, if the types match - xpath_variable* add(const char_t* name, xpath_value_type type); - - // Set value of an existing variable; no type conversion is performed, false is returned if there is no such variable or if types mismatch - bool set(const char_t* name, bool value); - bool set(const char_t* name, double value); - bool set(const char_t* name, const char_t* value); - bool set(const char_t* name, const xpath_node_set& value); - - // Get existing variable by name - xpath_variable* get(const char_t* name); - const xpath_variable* get(const char_t* name) const; - }; - - // A compiled XPath query object - class PUGIXML_CLASS xpath_query - { - private: - void* _impl; - xpath_parse_result _result; - - typedef void (*unspecified_bool_type)(xpath_query***); - - // Non-copyable semantics - xpath_query(const xpath_query&); - xpath_query& operator=(const xpath_query&); - - public: - // Construct a compiled object from XPath expression. - // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on compilation errors. - explicit xpath_query(const char_t* query, xpath_variable_set* variables = 0); - - // Destructor - ~xpath_query(); - - // Get query expression return type - xpath_value_type return_type() const; - - // Evaluate expression as boolean value in the specified context; performs type conversion if necessary. - // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. - bool evaluate_boolean(const xpath_node& n) const; - - // Evaluate expression as double value in the specified context; performs type conversion if necessary. - // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. - double evaluate_number(const xpath_node& n) const; - - #ifndef PUGIXML_NO_STL - // Evaluate expression as string value in the specified context; performs type conversion if necessary. - // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. - string_t evaluate_string(const xpath_node& n) const; - #endif - - // Evaluate expression as string value in the specified context; performs type conversion if necessary. - // At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero). - // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. - // If PUGIXML_NO_EXCEPTIONS is defined, returns empty set instead. - size_t evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const; - - // Evaluate expression as node set in the specified context. - // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors. - // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node set instead. - xpath_node_set evaluate_node_set(const xpath_node& n) const; - - // Get parsing result (used to get compilation errors in PUGIXML_NO_EXCEPTIONS mode) - const xpath_parse_result& result() const; - - // Safe bool conversion operator - operator unspecified_bool_type() const; - - // Borland C++ workaround - bool operator!() const; - }; - - #ifndef PUGIXML_NO_EXCEPTIONS - // XPath exception class - class PUGIXML_CLASS xpath_exception: public std::exception - { - private: - xpath_parse_result _result; - - public: - // Construct exception from parse result - explicit xpath_exception(const xpath_parse_result& result); - - // Get error message - virtual const char* what() const throw(); - - // Get parse result - const xpath_parse_result& result() const; - }; - #endif - - // XPath node class (either xml_node or xml_attribute) - class PUGIXML_CLASS xpath_node - { - private: - xml_node _node; - xml_attribute _attribute; - - typedef void (*unspecified_bool_type)(xpath_node***); - - public: - // Default constructor; constructs empty XPath node - xpath_node(); - - // Construct XPath node from XML node/attribute - xpath_node(const xml_node& node); - xpath_node(const xml_attribute& attribute, const xml_node& parent); - - // Get node/attribute, if any - xml_node node() const; - xml_attribute attribute() const; - - // Get parent of contained node/attribute - xml_node parent() const; - - // Safe bool conversion operator - operator unspecified_bool_type() const; - - // Borland C++ workaround - bool operator!() const; - - // Comparison operators - bool operator==(const xpath_node& n) const; - bool operator!=(const xpath_node& n) const; - }; - -#ifdef __BORLANDC__ - // Borland C++ workaround - bool PUGIXML_FUNCTION operator&&(const xpath_node& lhs, bool rhs); - bool PUGIXML_FUNCTION operator||(const xpath_node& lhs, bool rhs); -#endif - - // A fixed-size collection of XPath nodes - class PUGIXML_CLASS xpath_node_set - { - public: - // Collection type - enum type_t - { - type_unsorted, // Not ordered - type_sorted, // Sorted by document order (ascending) - type_sorted_reverse // Sorted by document order (descending) - }; - - // Constant iterator type - typedef const xpath_node* const_iterator; - - // Default constructor. Constructs empty set. - xpath_node_set(); - - // Constructs a set from iterator range; data is not checked for duplicates and is not sorted according to provided type, so be careful - xpath_node_set(const_iterator begin, const_iterator end, type_t type = type_unsorted); - - // Destructor - ~xpath_node_set(); - - // Copy constructor/assignment operator - xpath_node_set(const xpath_node_set& ns); - xpath_node_set& operator=(const xpath_node_set& ns); - - // Get collection type - type_t type() const; - - // Get collection size - size_t size() const; - - // Indexing operator - const xpath_node& operator[](size_t index) const; - - // Collection iterators - const_iterator begin() const; - const_iterator end() const; - - // Sort the collection in ascending/descending order by document order - void sort(bool reverse = false); - - // Get first node in the collection by document order - xpath_node first() const; - - // Check if collection is empty - bool empty() const; - - private: - type_t _type; - - xpath_node _storage; - - xpath_node* _begin; - xpath_node* _end; - - void _assign(const_iterator begin, const_iterator end); - }; -#endif - -#ifndef PUGIXML_NO_STL - // Convert wide string to UTF8 - std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const wchar_t* str); - std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const std::basic_string, std::allocator >& str); - - // Convert UTF8 to wide string - std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const char* str); - std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const std::basic_string, std::allocator >& str); -#endif - - // Memory allocation function interface; returns pointer to allocated memory or NULL on failure - typedef void* (*allocation_function)(size_t size); - - // Memory deallocation function interface - typedef void (*deallocation_function)(void* ptr); - - // Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions. - void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate); - - // Get current memory management functions - allocation_function PUGIXML_FUNCTION get_memory_allocation_function(); - deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function(); -} - -#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) -namespace std -{ - // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) - std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_node_iterator&); - std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_attribute_iterator&); - std::forward_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_named_node_iterator&); -} -#endif - -#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) -namespace std -{ - // Workarounds for (non-standard) iterator category detection - std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_node_iterator&); - std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_attribute_iterator&); - std::forward_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_named_node_iterator&); -} -#endif - -#endif - -/** - * Copyright (c) 2006-2012 Arseny Kapoulkine - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ diff --git a/src/XmlExecute.cpp b/src/XmlExecute.cpp deleted file mode 100644 index 75add1647..000000000 --- a/src/XmlExecute.cpp +++ /dev/null @@ -1,752 +0,0 @@ -#include "crpropa/XmlExecute.h" -#include "crpropa/magneticField/MagneticFieldGrid.h" -#include "crpropa/GridTools.h" -#include "crpropa/Random.h" -#include "crpropa/PhotonBackground.h" -#include "crpropa/Cosmology.h" -#include "crpropa/ParticleID.h" -#include "crpropa/module/SimplePropagation.h" -#include "crpropa/module/PropagationCK.h" -#include "crpropa/module/Redshift.h" -#include "crpropa/module/ElectronPairProduction.h" -#include "crpropa/module/PhotoPionProduction.h" -#include "crpropa/module/PhotoDisintegration.h" -#include "crpropa/module/NuclearDecay.h" -#include "crpropa/module/BreakCondition.h" -#include "crpropa/module/Boundary.h" -#include "crpropa/module/TextOutput.h" -#include "crpropa/module/OutputROOT.h" -#include "crpropa/module/OutputCRPropa2.h" -#include "crpropa/ModuleList.h" - -#include "pugixml.hpp" -#include "kiss/string.h" - -#include -#include -#include -#include - -using namespace pugi; -using namespace std; - -namespace crpropa { - -double childValue(xml_node parent, string childName, bool throwIfEmpty = true) { - xml_node node = parent.child(childName.c_str()); - if (!node and throwIfEmpty) { - stringstream ss; - ss << "Error reading XML card: " << childName << " not specified"; - throw runtime_error(ss.str()); - } - return node.attribute("value").as_double(); -} - -xml_node childNode(xml_node parent, string childName, - bool throwIfEmpty = true) { - xml_node node = parent.child(childName.c_str()); - if (!node and throwIfEmpty) { - stringstream ss; - ss << "Error reading XML card: " << childName << " not specified"; - throw runtime_error(ss.str()); - } - return node; -} - -ref_ptr loadSourceHomogeneousBox(pugi::xml_node &node) { - Vector3d origin; - origin.x = childValue(node, "Xmin_Mpc") * Mpc; - origin.y = childValue(node, "Ymin_Mpc") * Mpc; - origin.z = childValue(node, "Zmin_Mpc") * Mpc; - cout << " - Origin: " << origin / Mpc << endl; - - Vector3d size; - size.x = childValue(node, "Xmax_Mpc") * Mpc; - size.y = childValue(node, "Ymax_Mpc") * Mpc; - size.z = childValue(node, "Zmax_Mpc") * Mpc; - size -= origin; - cout << " - Size: " << size / Mpc << endl; - - return (new SourceUniformBox(origin, size)); -} - -ref_ptr loadSourceDensityGrid(pugi::xml_node &node) { - int nx = childValue(node, "Nx"); - int ny = childValue(node, "Ny"); - int nz = childValue(node, "Nz"); - cout << " - Nx = " << nx << ", Ny = " << ny << ", Nz = " << nz << endl; - - double spacing = childValue(node, "Step_Mpc") * Mpc; - cout << " - Spacing = " << spacing / Mpc << " Mpc" << endl; - - xml_node origin_node = childNode(node, "Origin"); - Vector3d origin; - origin.x = childValue(origin_node, "X_Mpc") * Mpc; - origin.y = childValue(origin_node, "Y_Mpc") * Mpc; - origin.z = childValue(origin_node, "Z_Mpc") * Mpc; - cout << " - Origin = " << origin / Mpc << " Mpc" << endl; - - ref_ptr grid = new ScalarGrid(origin, nx, ny, nz, spacing); - - xml_node file_node = childNode(node, "File"); - string file_type = file_node.attribute("type").as_string(); - string file_name = file_node.child_value(); - cout << " - File = " << file_name << endl; - if (file_type == "ASCII") - loadGridFromTxt(grid, file_name); - else if (file_type == "FITS") - throw runtime_error(" --> FITS files not supported"); - else - throw runtime_error(" --> unknown file type"); - - return (new SourceDensityGrid(grid)); -} - -ref_ptr loadSourceDensityGrid1D(pugi::xml_node &node) { - int nx = childValue(node, "Nx"); - cout << " - Nx = " << nx << endl; - - double spacing = childValue(node, "Step_Mpc") * Mpc; - cout << " - Spacing = " << spacing / Mpc << " Mpc" << endl; - - // convert to comoving spacing - spacing = lightTravel2ComovingDistance(spacing); - - ref_ptr grid = new ScalarGrid(Vector3d(0, 0, 0), nx, 1, 1, - spacing); - - xml_node file_node = childNode(node, "File"); - string file_type = file_node.attribute("type").as_string(); - string file_name = file_node.child_value(); - cout << " - File = " << file_name << endl; - if (file_type == "ASCII") - loadGridFromTxt(grid, file_name); - else if (file_type == "FITS") - throw runtime_error(" --> FITS files not supported"); - else - throw runtime_error(" --> unknown file type"); - - return (new SourceDensityGrid1D(grid)); -} - -XmlExecute::XmlExecute() : - is1D(false), hasRedshift(false), nTrajectories(0), Emin(0), maxStep(0) { - std::cerr << "!!! Deprecation Warning !!! Support for legacy XML steering will soon be removed from future CRPropa versions. Please switch to python based steering.\n"; -} - -bool XmlExecute::load(const string &filename) { - xml_document doc; - xml_parse_result result = doc.load_file(filename.c_str()); - - if (!result) { - cout << "Error reading XML card: " << result.description() << "\n"; - cout << "Error position: " << result.offset << "\n"; - return false; - } - - xml_node root = doc.child("CRPropa"); - if (!root) - throw runtime_error( - "Error reading XML card: Root element CRPropa not found"); - - // ----- general settings ----- - nTrajectories = (int) childValue(root, "TrajNumber"); - cout << "Number of particles: " << nTrajectories << endl; - - xml_node seed_node = root.child("RandomSeed"); - if (seed_node) { - int seed = seed_node.attribute("value").as_int(); - Random::seedThreads(seed); - cout << "Random seed: " << seed << endl; - } else - cout << "No random seed given. Using random random seed." << endl; - - // ----- environment ----- - xml_node node; - node = childNode(root, "Environment"); - string type = node.attribute("type").as_string(); - cout << "Environment: " << type << endl; - - if (type == "One Dimension") - is1D = true; - else if (type == "LSS") { - // will be overwritten if (re)defined by magnetic field - origin.x = childValue(node, "Xmin_Mpc", false) * Mpc; - origin.y = childValue(node, "Ymin_Mpc", false) * Mpc; - origin.z = childValue(node, "Zmin_Mpc", false) * Mpc; - size.x = childValue(node, "Xmax_Mpc", false) * Mpc; - size.y = childValue(node, "Ymax_Mpc", false) * Mpc; - size.z = childValue(node, "Zmax_Mpc", false) * Mpc; - size -= origin; - } else - throw runtime_error(" --> unknown environment"); - - // ----- magnetic field ----- - node = childNode(root, "MagneticField", false); - if (node) { - type = node.attribute("type").as_string(); - cout << "MagenticField: " << type << endl; - if ((type == "Null") or (type == "None")) - magnetic_field = new UniformMagneticField(Vector3d(0, 0, 0)); - else if (type == "Uniform") - loadUniformMagneticField(node); - else if ((type == "LSS-Grid") or (type == "Kolmogoroff")) - loadGridMagneticField(node); - else if (type == "1D") - cout << " --> not implemented" << endl; - else { - cout << " --> unknown, set zero field" << endl; - magnetic_field = new UniformMagneticField(Vector3d(0, 0, 0)); - } - } else { - if (!is1D) - throw runtime_error(" --> magnetic field not specified"); - } - - // ----- propagator ----- - xml_node interaction_node = childNode(root, "Interactions"); - maxStep = childValue(interaction_node, "MaxStep_Mpc", false) * Mpc; - - if (is1D) { - cout << "Propagator: 1D" << endl; - modules.add(new SimplePropagation()); - - bool noRedshift = interaction_node.child("NoRedshift"); - hasRedshift = !(noRedshift); - - if (hasRedshift) { - modules.add(new Redshift()); - - double omegaM = 0.3; - if (root.child("OmegaM")) - omegaM = childValue(root, "OmegaM"); - - double omegaL = 0.7; - if (root.child("OmegaLambda")) - omegaL = childValue(root, "OmegaLambda"); - - double H0 = 70.; - if (root.child("H0_km_s_Mpc")) - H0 = childValue(root, "H0_km_s_Mpc"); - - cout << "Cosmology: OmegaM = " << omegaM << ", OmegaLambda = " - << 1 - omegaM << ", H0 = " << H0 << " km/s/Mpc" << endl; - setCosmologyParameters(H0 / 100, omegaM); - } else { - cout << " - No redshift" << endl; - } - } else { - node = childNode(root, "Integrator"); - type = node.attribute("type").as_string(); - cout << "Propagator: " << type << endl; - if (type == "Cash-Karp RK") - loadDeflectionCK(node); - else - throw runtime_error(" --> unknown integrator"); - } - - // ----- interactions ----- - type = interaction_node.attribute("type").as_string(); - cout << "Interactions: " << type << endl; - if (type == "Sophia") - loadSophia(interaction_node); - - // ----- minimum energy ----- - Emin = childValue(root, "MinEnergy_EeV") * EeV; - cout << "Minimum energy: " << Emin / EeV << " EeV" << endl; - modules.add(new MinimumEnergy(Emin)); - - // ----- maximum trajectory length ----- - double maxTime = childValue(root, "MaxTime_Mpc") * Mpc; - cout << "Maximum time: " << maxTime / Mpc << " Mpc" << endl; - if (is1D) - maxTime = lightTravel2ComovingDistance(maxTime); // convert to comoving distance - modules.add(new MaximumTrajectoryLength(maxTime)); - - // ----- periodic boundaries ----- - if (!is1D) - loadPeriodicBoundaries(); - - // ----- sources ----- - node = childNode(root, "Sources"); - - // emission direction - if (!is1D) - source.add(new SourceIsotropicEmission()); - - // position - type = node.attribute("type").as_string(); - cout << "Source(s): " << type << endl; - if (type == "Discrete") - loadDiscreteSources(node); - else if (type == "Continuous") - loadContinuousSources(node); - else - throw runtime_error(" --> unknown source type"); - - if (is1D and hasRedshift) { - cout << " - Redshift according to source distance" << endl; - source.add(new SourceRedshift1D()); - } - - // spectrum + composition - loadSpectrumComposition(node); - - // ----- observers ----- - observer = new Observer(); - modules.add(observer); - if (is1D) { - observer->add(new ObserverPoint()); - } else { - node = root.child("Observers"); - if (!node) { - cout << "Observer(s) not specified" << endl; - } else { - string type = node.attribute("type").as_string(); - cout << "Observers: " << type << endl; - if (type == "Spheres around Observers") - loadSpheresAroundObserver(node); - else if (type == "Spheres around Source") - loadSpheresAroundSource(node); - else - cout << " --> unknown observer ('Spheres around Source' or " - << "'Spheres around Observer')" << endl; - } - } - - // ----- output ----- - node = root.child("Output"); - if (!node) - cout << "No output" << endl; - else - loadOutput(node); - - return true; -} - -void XmlExecute::loadDeflectionCK(xml_node &node) { - double epsilon = childValue(node, "MinStep_Mpc"); - cout << " - Epsilon: " << epsilon << endl; - - double minStep = childValue(node, "MinStep_Mpc") * Mpc; - cout << " - Minimum step: " << minStep / Mpc << " Mpc" << endl; - - if (maxStep == 0) - maxStep = numeric_limits::max(); - cout << " - Maximum step: " << maxStep / Mpc << " Mpc" << endl; - - if (minStep >= maxStep) - throw runtime_error( - " --> Maximum step must be larger than minimum step"); - - modules.add(new PropagationCK(magnetic_field, epsilon, minStep, maxStep)); -} - -void XmlExecute::loadUniformMagneticField(xml_node &node) { - Vector3d bField; - bField.x = childValue(node, "Bx_nG") * nG; - bField.y = childValue(node, "By_nG") * nG; - bField.z = childValue(node, "Bz_nG") * nG; - cout << " - Bx, By, Bz: " << bField / nG << " nG" << endl; - magnetic_field = new UniformMagneticField(bField); -} - -void XmlExecute::loadGridMagneticField(xml_node &node) { - xml_node origin_node = node.child("Origin"); - origin.x = childValue(origin_node, "X_Mpc") * Mpc; - origin.y = childValue(origin_node, "Y_Mpc") * Mpc; - origin.z = childValue(origin_node, "Z_Mpc") * Mpc; - cout << " - Origin: " << origin / Mpc << endl; - - int Nx = childValue(node, "Nx"); - int Ny = childValue(node, "Ny"); - int Nz = childValue(node, "Nz"); - cout << " - Samples: " << Nx << " * " << Ny << " * " << Nz << endl; - - double spacing = childValue(node, "Step_Mpc") * Mpc; - cout << " - Spacing: " << spacing / Mpc << " Mpc " << endl; - - size.x = Nx * spacing; - size.y = Ny * spacing; - size.z = Nz * spacing; - - ref_ptr field = new VectorGrid(origin, Nx, Ny, Nz, spacing); - - string type = node.attribute("type").as_string(); - if (type == "LSS-Grid") { - cout << " - Loading field from file" << endl; - - string filetype = node.child("File").attribute("type").as_string(); - cout << " - File type: " << filetype << endl; - - string filename = kiss::trim(node.child_value("File")); - cout << " - File name: " << filename << endl; - - if (filetype == "ASCII") - loadGridFromTxt(field, filename, gauss); - else if (filetype == "RAW") - loadGrid(field, filename, gauss); - else - throw runtime_error("Unsupported file type"); - - } else if (type == "Kolmogoroff") { - cout << " - Creating random turbulent field" << endl; - - double brms = childValue(node, "RMS_muG") * 1e-6 * gauss; - cout << " - Brms: " << brms / nG << " nG" << endl; - - double kMin = childValue(node, "Kmin"); - double kMax = childValue(node, "Kmax"); - double lMin = spacing / kMax; - double lMax = spacing / kMin; - cout << " - Turbulent range: " << lMin / Mpc << " - " << lMax / Mpc - << " Mpc" << endl; - - double alpha = childValue(node, "SpectralIndex"); - cout << " - Spectral index, ~ k^n, n: " << alpha << endl; - -#ifdef CRPROPA_HAVE_FFTW3F - initTurbulence(field, brms, lMin, lMax, alpha); -#endif -#ifndef CRPROPA_HAVE_FFTW3F - throw runtime_error( - "Turbulent field not available: Compile with FFTW3F."); -#endif - } else { - throw runtime_error("Unknown field type"); - } - - magnetic_field = new MagneticFieldGrid(field); -} - -void XmlExecute::loadPeriodicBoundaries() { - if ((size.x == 0) or (size.y == 0) or (size.z == 0)) - throw runtime_error(" --> Environment boundaries not set"); - cout << "Periodic boundaries" << endl; - cout << " - Lower bounds: " << origin / Mpc << " Mpc" << endl; - cout << " - Upper bounds: " << (origin + size) / Mpc << " Mpc" << endl; - modules.add(new PeriodicBox(origin, size)); -} - -void XmlExecute::loadSophia(xml_node &node) { - bool pairprodCMB = true; - bool pairprodIRB = true; - bool pionprodCMB = true; - bool pionprodIRB = true; - bool photodisCMB = true; - bool photodisIRB = true; - bool decay = true; - - if (node.child("NoPairProd")) { - cout << " - No pair production" << endl; - pairprodCMB = false; - pairprodIRB = false; - } - if (node.child("NoPionProd")) { - cout << " - No pion production" << endl; - pionprodCMB = false; - pionprodIRB = false; - } - if (node.child("NoPhotodisintegration")) { - cout << " - No photo disintegration" << endl; - photodisCMB = false; - photodisIRB = false; - } - if (node.child("NoIRO")) { - cout << " - No interactions on IRB" << endl; - pairprodIRB = false; - pionprodIRB = false; - photodisIRB = false; - } - if (node.child("NoIRPionProd")) { - cout << " - No pion production on IRB" << endl; - pionprodIRB = false; - } - if (node.child("NoDecay")) { - cout << " - No decay" << endl; - decay = false; - } - - if (pairprodCMB) - modules.add(new ElectronPairProduction(CMB)); - if (pairprodIRB) - modules.add(new ElectronPairProduction(IRB)); - - if (pionprodCMB) - modules.add(new PhotoPionProduction(CMB)); - if (pionprodIRB) - modules.add(new PhotoPionProduction(IRB)); - - if (photodisCMB) - modules.add(new PhotoDisintegration(CMB)); - if (photodisIRB) - modules.add(new PhotoDisintegration(IRB)); - - if (decay) - modules.add(new NuclearDecay); -} - -void XmlExecute::loadSpheresAroundObserver(xml_node &node) { - double r = childValue(node, "Radius_Mpc") * Mpc; - cout << " - Radius: " << r / Mpc << " Mpc" << endl; - - for (xml_node n = node.child("SphereObserver"); n; - n = n.next_sibling("SphereObserver")) { - Vector3d pos; - pos.x = childValue(n, "CoordX_Mpc") * Mpc; - pos.y = childValue(n, "CoordY_Mpc") * Mpc; - pos.z = childValue(n, "CoordZ_Mpc") * Mpc; - cout << " - Postion: " << pos / Mpc << " Mpc"; - cout << ", Detection does not stop propagation" << endl; - observer->add(new ObserverSmallSphere(pos, r)); - } -} - -void XmlExecute::loadSpheresAroundSource(pugi::xml_node &node) { - int nObs = 0; - for (xml_node n = node.child("Sphere"); n; n = n.next_sibling("Sphere")) { - nObs += 1; - Vector3d pos; - pos.x = childValue(n, "CoordX_Mpc") * Mpc; - pos.y = childValue(n, "CoordY_Mpc") * Mpc; - pos.z = childValue(n, "CoordZ_Mpc") * Mpc; - cout << " - Postion: " << pos / Mpc << " Mpc" << endl; - double r = childValue(n, "Radius_Mpc") * Mpc; - cout << " - Radius: " << r / Mpc << " Mpc" << endl; - cout << " - Detection does not stop propagation" << endl; - observer->add(new ObserverLargeSphere(pos, r)); - } -} - -void XmlExecute::loadDiscreteSources(pugi::xml_node &node) { - ref_ptr sourcePositions = - new SourceMultiplePositions(); - - xml_node density_node = node.child("Density"); - if (density_node) { - // draw positions from density distribution - string type = density_node.attribute("type").as_string(); - cout << " - Density: " << type << endl; - int nSources = childValue(node, "Number"); - cout << " - Number of sources = " << nSources << endl; - - ref_ptr sourceDistribution = new SourceFeature(); - if (type == "Uniform") { - if (is1D) { - double xmin = childValue(density_node, "Xmin_Mpc") * Mpc; - double xmax = childValue(density_node, "Xmax_Mpc") * Mpc; - xmin = lightTravel2ComovingDistance(xmin); - xmax = lightTravel2ComovingDistance(xmax); - sourceDistribution = new SourceUniform1D(xmin, xmax); - } else { - sourceDistribution = loadSourceHomogeneousBox(density_node); - } - } else if (type == "Grid") { - if (is1D) - sourceDistribution = loadSourceDensityGrid1D(density_node); - else - sourceDistribution = loadSourceDensityGrid(density_node); - } else { - throw runtime_error(" --> unknown source density type"); - } - ParticleState p; - for (int i = 0; i < nSources; i++) { - sourceDistribution->prepareParticle(p); - sourcePositions->add(p.getPosition()); - cout << " - Position = " << p.getPosition() / Mpc << " Mpc" - << endl; - } - } else { - // loop over point sources - for (xml_node n = node.child("PointSource"); n; - n = n.next_sibling("PointSource")) { - Vector3d pos(0.); - if (is1D) { - // 1D - double dlt = childValue(n, "CoordX_Mpc") * Mpc; - pos.x = lightTravel2ComovingDistance(dlt); - cout << " - Light travel distance = " << dlt / Mpc << " Mpc" - << endl; - } else { - // 3D - pos.x = childValue(n, "CoordX_Mpc") * Mpc; - pos.y = childValue(n, "CoordY_Mpc") * Mpc; - pos.z = childValue(n, "CoordZ_Mpc") * Mpc; - cout << " - Position = " << pos / Mpc << " Mpc" << endl; - } - sourcePositions->add(pos); - } - } - source.add(sourcePositions); -} - -void XmlExecute::loadContinuousSources(pugi::xml_node &node) { - xml_node density_node = node.child("Density"); - string type = density_node.attribute("type").as_string(); - cout << " - Density: " << type << endl; - if (type == "Uniform") - if (is1D) { - double minD = childValue(density_node, "Xmin_Mpc") * Mpc; - double maxD = childValue(density_node, "Xmax_Mpc") * Mpc; - cout << " - Minimum light travel distance: " << minD / Mpc - << " Mpc" << endl; - cout << " - Maximum light travel distance: " << maxD / Mpc - << " Mpc" << endl; - minD = lightTravel2ComovingDistance(minD); - maxD = lightTravel2ComovingDistance(maxD); - source.add(new SourceUniform1D(minD, maxD)); - } else { - source.add(loadSourceHomogeneousBox(density_node)); - } - else if (type == "Grid") { - if (is1D) { - source.add(loadSourceDensityGrid1D(density_node)); - } else - source.add(loadSourceDensityGrid(density_node)); - } else { - throw runtime_error(" --> unknown source density type"); - } -} - -void XmlExecute::loadSpectrumComposition(pugi::xml_node &node) { - xml_node spectrum_node = node.child("Spectrum"); - string spectrumType = spectrum_node.attribute("type").as_string(); - cout << " - Spectrum: " << spectrumType << endl; - - if (spectrumType == "Monochromatic") { - if (spectrum_node.child("Energy_EeV")) { - double E = childValue(spectrum_node, "Energy_EeV") * EeV; - cout << " - Energy: " << E / EeV << " EeV" << endl; - source.add(new SourceEnergy(E)); - } else if (spectrum_node.child("Rigidity_EeV")) - throw runtime_error(" --> Fixed rigidity not implemented"); - else { - throw runtime_error(" --> Source energy missing"); - } - loadSourceNuclei(node); - } else if (spectrumType == "Power Law") { - double alpha = -childValue(spectrum_node, "Alpha"); - cout << " - Power law index E^a, a:" << alpha << endl; - cout << " - Minimum energy: " << Emin / EeV << " EeV" << endl; - - // if the source is accelerated to a maximum rigidity - if (spectrum_node.child("Rigidity_EeV")) { - double Rmax = childValue(spectrum_node, "Rigidity_EeV") * EeV; - cout << " - Maximum rigidity: " << Rmax / EeV << " EeV" << endl; - - // combined source spectrum / composition - ref_ptr comp = new SourceComposition(Emin, Rmax, - alpha); - xml_node p = node.child("Particles"); - for (xml_node n = p.child("Species"); n; - n = n.next_sibling("Species")) { - int A = n.attribute("MassNumber").as_int(); - int Z = n.attribute("ChargeNumber").as_int(); - double ab = n.attribute("Abundance").as_double(); - cout << " - Species: Z = " << Z << ", A = " << A - << ", abundance = " << ab << endl; - comp->add(nucleusId(A, Z), ab); - } - source.add(comp); - } else if (spectrum_node.child("Ecut_EeV")) { - double Emax = childValue(spectrum_node, "Ecut_EeV") * EeV; - cout << " - Maximum energy: " << Emax / EeV << " EeV" << endl; - - // source spectrum - source.add(new SourcePowerLawSpectrum(Emin, Emax, alpha)); - - // source composition - loadSourceNuclei(node); - } else { - throw runtime_error( - " --> maximum source energy / rigidity missing"); - } - } else { - throw runtime_error(" --> unknown source spectrum"); - } -} - -void XmlExecute::loadSourceNuclei(pugi::xml_node &node) { - ref_ptr composition = - new SourceMultipleParticleTypes(); - xml_node p = node.child("Particles"); - for (xml_node n = p.child("Species"); n; n = n.next_sibling("Species")) { - int A = n.attribute("MassNumber").as_int(); - int Z = n.attribute("ChargeNumber").as_int(); - double ab = n.attribute("Abundance").as_double(); - cout << " - Species: Z = " << Z << ", A = " << A << ", abundance = " - << ab << endl; - composition->add(nucleusId(A, Z), ab); - } - source.add(composition); -} - -void XmlExecute::loadOutput(xml_node &node) { - string type = node.attribute("type").as_string(); - cout << "Output: " << type << endl; - - xml_node file_node = node.child("File"); - string format = file_node.attribute("type").as_string(); - cout << " - Filetype: " << format << endl; - - string filename = kiss::trim(node.child("File").child_value()); - cout << " - Filename: " << filename << endl; - - string option = node.child("File").attribute("option").as_string(); - if (option != "force") { - ifstream ifile(filename.c_str()); - if (ifile) - throw runtime_error("Output file already exists!"); - } - - if (format == "ASCII") { - if (type == "Full Trajectories") { - if (is1D) - modules.add(new CRPropa2TrajectoryOutput1D(filename)); - else - modules.add(new CRPropa2TrajectoryOutput3D(filename)); - } else if (type == "Events") { - if (is1D) - observer->onDetection(new CRPropa2EventOutput1D(filename)); - else - observer->onDetection(new CRPropa2EventOutput3D(filename)); - } else if (type == "None") { - return; - } else { - cout << " --> unknown output type " - << "('Events', 'Full Trajectories' or 'None')" << endl; - } - } -#ifdef CRPROPA_HAVE_ROOT - else if (format == "ROOT") { - if (type == "Full Trajectories") - if (is1D) - modules.add(new CRPropa2ROOTTrajectoryOutput1D(filename)); - else - modules.add(new CRPropa2ROOTTrajectoryOutput3D(filename)); - else if (type == "Events") - if (is1D) - observer->onDetection(new CRPropa2ROOTEventOutput1D(filename)); - else - observer->onDetection(new CRPropa2ROOTEventOutput3D(filename)); - else if (type == "None") - return; - else - cout << " --> unknown output type " - << "('Events', 'Full Trajectories' or 'None')" << endl; - } -#endif // CRPROPA_HAVE_ROOT - else { - cout << " --> unknown output format. " - << " Use 'ASCII' or 'ROOT' (if ROOT is set)" << endl; - } -} - -void XmlExecute::run() { - cout << endl << "Active modules:" << endl; - cout << modules.getDescription(); - modules.setShowProgress(true); - modules.run(&source, nTrajectories, true); -} - -} // namespace crpropa diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 13eb1029b..000000000 --- a/src/main.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "crpropa/XmlExecute.h" - -#include -#include - -int main(int argc, char **argv) { - std::cerr << "!!! Deprecation Warning !!! Support for legacy XML steering will soon be removed from future CRPropa versions. Please switch to python based steering.\n"; - if (argc < 2) { - std::cout << "crpropa-run " << std::endl; - return 1; - } - - try { - crpropa::XmlExecute exe; - if (!exe.load(argv[1])) - return 1; - exe.run(); - } catch (std::exception &e) { - std::cerr << e.what() << std::endl; - return 1; - } - - std::cerr << "!!! Deprecation Warning !!! Support for legacy XML steering will soon be removed from future CRPropa versions. Please switch to python based steering.\n"; - return 0; -} diff --git a/test/xml/test1D.xml b/test/xml/test1D.xml deleted file mode 100644 index 43f08cfa3..000000000 --- a/test/xml/test1D.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - output.txt - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/xml/test1D_discreteSource.xml b/test/xml/test1D_discreteSource.xml deleted file mode 100644 index 48beedc6f..000000000 --- a/test/xml/test1D_discreteSource.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - output.txt - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/xml/test3D_continuousHomogeneousSources.xml b/test/xml/test3D_continuousHomogeneousSources.xml deleted file mode 100644 index e3bf98a28..000000000 --- a/test/xml/test3D_continuousHomogeneousSources.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - traj3d.txt - - - diff --git a/test/xml/test3D_discreteHomogeneousSources.xml b/test/xml/test3D_discreteHomogeneousSources.xml deleted file mode 100644 index 90cf2c476..000000000 --- a/test/xml/test3D_discreteHomogeneousSources.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - traj3d.txt - - - diff --git a/test/xml/test3D_kolmogorovBfield.xml b/test/xml/test3D_kolmogorovBfield.xml deleted file mode 100644 index 25bc6d0b7..000000000 --- a/test/xml/test3D_kolmogorovBfield.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - traj3d.txt - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/xml/test3D_noBfield.xml b/test/xml/test3D_noBfield.xml deleted file mode 100644 index 86627063d..000000000 --- a/test/xml/test3D_noBfield.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - output.txt - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/xml/test3D_uniformBfield.xml b/test/xml/test3D_uniformBfield.xml deleted file mode 100644 index f4e5088ac..000000000 --- a/test/xml/test3D_uniformBfield.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - traj3d.txt - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/xml/testCRPropa2EventOutput1D.xml b/test/xml/testCRPropa2EventOutput1D.xml deleted file mode 100644 index 27fbd1b06..000000000 --- a/test/xml/testCRPropa2EventOutput1D.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - output.txt - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/xml/testCRPropa2EventOutput3D.xml b/test/xml/testCRPropa2EventOutput3D.xml deleted file mode 100644 index af86d7c31..000000000 --- a/test/xml/testCRPropa2EventOutput3D.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - output.txt - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/xml/testCRPropa2TrajectoryOutput1D.xml b/test/xml/testCRPropa2TrajectoryOutput1D.xml deleted file mode 100644 index f764093bb..000000000 --- a/test/xml/testCRPropa2TrajectoryOutput1D.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - output.txt - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/xml/testCRPropa2TrajectoryOutput3D.xml b/test/xml/testCRPropa2TrajectoryOutput3D.xml deleted file mode 100644 index ebed0fceb..000000000 --- a/test/xml/testCRPropa2TrajectoryOutput3D.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - output.txt - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 330bc358baa2fb0157cec995682119f44fa39be0 Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Thu, 7 Dec 2017 11:00:31 +0000 Subject: [PATCH 1054/1298] It takes too long to compile SWIG wrapper after we switched from stdio.h to cstdio in commit a02e504. Adding the correct namespace in front of every stdio function apparently fixed the issue. --- include/crpropa/ProgressBar.h | 2 -- include/crpropa/Random.h | 1 - src/PhotonPropagation.cpp | 12 ++++----- src/ProgressBar.cpp | 13 ++++++---- src/module/OutputCRPropa2.cpp | 42 ++++++++++++++++---------------- src/module/PhotonOutput1D.cpp | 15 ++++++------ src/module/TextOutput.cpp | 46 +++++++++++++++++------------------ 7 files changed, 66 insertions(+), 65 deletions(-) diff --git a/include/crpropa/ProgressBar.h b/include/crpropa/ProgressBar.h index d2c576bf0..f2c9a7b2d 100644 --- a/include/crpropa/ProgressBar.h +++ b/include/crpropa/ProgressBar.h @@ -1,9 +1,7 @@ #ifndef CRPROPA_PROGRESSBAR_H #define CRPROPA_PROGRESSBAR_H -#include #include -#include #include namespace crpropa { diff --git a/include/crpropa/Random.h b/include/crpropa/Random.h index 1720f3b61..1247cc33b 100644 --- a/include/crpropa/Random.h +++ b/include/crpropa/Random.h @@ -66,7 +66,6 @@ #include #include -#include #include #include #include diff --git a/src/PhotonPropagation.cpp b/src/PhotonPropagation.cpp index 625b1f1d0..73a80ab33 100644 --- a/src/PhotonPropagation.cpp +++ b/src/PhotonPropagation.cpp @@ -97,12 +97,12 @@ void ElecaPropagation( continue; char buffer[256]; size_t bufferPos = 0; - bufferPos += sprintf(buffer + bufferPos, "%i\t", p.GetType()); - bufferPos += sprintf(buffer + bufferPos, "%.4E\t", p.GetEnergy() / 1E18 ); - bufferPos += sprintf(buffer + bufferPos, "%i\t", iId); - bufferPos += sprintf(buffer + bufferPos, "%.4E\t", iE ); - bufferPos += sprintf(buffer + bufferPos, "%i", p.Generation()); - bufferPos += sprintf(buffer + bufferPos, "\n"); + bufferPos += std::sprintf(buffer + bufferPos, "%i\t", p.GetType()); + bufferPos += std::sprintf(buffer + bufferPos, "%.4E\t", p.GetEnergy() / 1E18 ); + bufferPos += std::sprintf(buffer + bufferPos, "%i\t", iId); + bufferPos += std::sprintf(buffer + bufferPos, "%.4E\t", iE ); + bufferPos += std::sprintf(buffer + bufferPos, "%i", p.Generation()); + bufferPos += std::sprintf(buffer + bufferPos, "\n"); output.write(buffer, bufferPos); } diff --git a/src/ProgressBar.cpp b/src/ProgressBar.cpp index 5020e3285..e8ff7d408 100644 --- a/src/ProgressBar.cpp +++ b/src/ProgressBar.cpp @@ -1,5 +1,8 @@ #include "crpropa/ProgressBar.h" +#include +#include + namespace crpropa { /// Initialize a ProgressBar with [steps] number of steps, updated at [updateSteps] intervalls @@ -41,7 +44,7 @@ void ProgressBar::setPosition(unsigned long position) { arrow.insert(0, "="); float tElapsed = currentTime - _startTime; float tToGo = (_steps - position) * tElapsed / position; - printf(stringTmpl.c_str(), arrow.c_str(), percentage, "Finish in", + std::printf(stringTmpl.c_str(), arrow.c_str(), percentage, "Finish in", int(tToGo / 3600), (int(tToGo) % 3600) / 60, int(tToGo) % 60, ""); fflush(stdout); @@ -50,8 +53,8 @@ void ProgressBar::setPosition(unsigned long position) { std::string s = " - Finished at "; s.append(ctime(¤tTime)); char fs[255]; - sprintf(fs, "%c[%d;%dm Finished %c[%dm", 27, 1, 32, 27, 0); - printf(stringTmpl.c_str(), fs, 100, "Needed", + std::sprintf(fs, "%c[%d;%dm Finished %c[%dm", 27, 1, 32, 27, 0); + std::printf(stringTmpl.c_str(), fs, 100, "Needed", int(tElapsed / 3600), (int(tElapsed) % 3600) / 60, int(tElapsed) % 60, s.c_str()); } @@ -66,8 +69,8 @@ void ProgressBar::setError() { std::string s = " - Finished at "; s.append(ctime(¤tTime)); char fs[255]; - sprintf(fs, "%c[%d;%dm ERROR %c[%dm", 27, 1, 31, 27, 0); - printf(stringTmpl.c_str(), fs, _currentCount, "Needed", + std::sprintf(fs, "%c[%d;%dm ERROR %c[%dm", 27, 1, 31, 27, 0); + std::printf(stringTmpl.c_str(), fs, _currentCount, "Needed", int(tElapsed / 3600), (int(tElapsed) % 3600) / 60, int(tElapsed) % 60, s.c_str()); } diff --git a/src/module/OutputCRPropa2.cpp b/src/module/OutputCRPropa2.cpp index add9107f9..5b42d8ba6 100644 --- a/src/module/OutputCRPropa2.cpp +++ b/src/module/OutputCRPropa2.cpp @@ -26,27 +26,27 @@ void CRPropa2EventOutput3D::process(Candidate *c) const { char buffer[256]; // max. 256 characters per line size_t p = 0; // length of line - p += sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->current.getId())); - p += sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->source.getId())); + p += std::sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->current.getId())); + p += std::sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->source.getId())); const Vector3d &ipos = c->source.getPosition() / Mpc; - p += sprintf(buffer + p, "%.4f %.4f %.4f ", ipos.x, ipos.y, ipos.z); + p += std::sprintf(buffer + p, "%.4f %.4f %.4f ", ipos.x, ipos.y, ipos.z); double iPhi = c->source.getDirection().getPhi(); double iTheta = c->source.getDirection().getTheta(); double iE = c->source.getEnergy() / EeV; - p += sprintf(buffer + p, "%.4f %.4f %.4f ", iE, iPhi, iTheta); + p += std::sprintf(buffer + p, "%.4f %.4f %.4f ", iE, iPhi, iTheta); double t = comoving2LightTravelDistance(c->getTrajectoryLength()) / Mpc; - p += sprintf(buffer + p, "%.4f ", t); + p += std::sprintf(buffer + p, "%.4f ", t); const Vector3d &pos = c->current.getPosition() / Mpc; - p += sprintf(buffer + p, "%.4f %.4f %.4f ", pos.x, pos.y, pos.z); + p += std::sprintf(buffer + p, "%.4f %.4f %.4f ", pos.x, pos.y, pos.z); double phi = c->current.getDirection().getPhi(); double theta = c->current.getDirection().getTheta(); double E = c->current.getEnergy() / EeV; - p += sprintf(buffer + p, "%.4f %.4f %.4f\n", E, phi, theta); + p += std::sprintf(buffer + p, "%.4f %.4f %.4f\n", E, phi, theta); #pragma omp critical outfile.write(buffer, p); @@ -76,19 +76,19 @@ void CRPropa2TrajectoryOutput3D::process(Candidate *c) const { char buffer[256]; size_t p = 0; - p += sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->current.getId())); - p += sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->source.getId())); + p += std::sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->current.getId())); + p += std::sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->source.getId())); double t = comoving2LightTravelDistance(c->getTrajectoryLength()) / Mpc; - p += sprintf(buffer + p, "%.4f ", t); + p += std::sprintf(buffer + p, "%.4f ", t); const Vector3d &pos = c->current.getPosition() / Mpc; - p += sprintf(buffer + p, "%.4f %.4f %.4f ", pos.x, pos.y, pos.z); + p += std::sprintf(buffer + p, "%.4f %.4f %.4f ", pos.x, pos.y, pos.z); const Vector3d &mom = c->current.getMomentum() / EeV; - p += sprintf(buffer + p, "%.4g %.4g %.4g ", mom.x, mom.y, mom.z); + p += std::sprintf(buffer + p, "%.4g %.4g %.4g ", mom.x, mom.y, mom.z); - p += sprintf(buffer + p, "%.4f\n", c->current.getEnergy() / EeV); + p += std::sprintf(buffer + p, "%.4f\n", c->current.getEnergy() / EeV); #pragma omp critical outfile.write(buffer, p); @@ -115,9 +115,9 @@ void CRPropa2TrajectoryOutput1D::process(Candidate *c) const { char buffer[256]; size_t p = 0; - p += sprintf(buffer + p, "%.4f ", comoving2LightTravelDistance(c->current.getPosition().x) / Mpc); - p += sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->current.getId())); - p += sprintf(buffer + p, "%.4f\n", c->current.getEnergy() / EeV); + p += std::sprintf(buffer + p, "%.4f ", comoving2LightTravelDistance(c->current.getPosition().x) / Mpc); + p += std::sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->current.getId())); + p += std::sprintf(buffer + p, "%.4f\n", c->current.getEnergy() / EeV); #pragma omp critical outfile.write(buffer, p); @@ -145,12 +145,12 @@ void CRPropa2EventOutput1D::process(Candidate *c) const { char buffer[256]; size_t p = 0; - p += sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->current.getId())); - p += sprintf(buffer + p, "%.4f ", c->current.getEnergy() / EeV); + p += std::sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->current.getId())); + p += std::sprintf(buffer + p, "%.4f ", c->current.getEnergy() / EeV); double t = comoving2LightTravelDistance(c->getTrajectoryLength()) / Mpc; - p += sprintf(buffer + p, "%.4f ", t); - p += sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->source.getId())); - p += sprintf(buffer + p, "%.4f\n", c->source.getEnergy() / EeV); + p += std::sprintf(buffer + p, "%.4f ", t); + p += std::sprintf(buffer + p, "%i ", convertToCRPropa2NucleusId(c->source.getId())); + p += std::sprintf(buffer + p, "%.4f\n", c->source.getEnergy() / EeV); #pragma omp critical outfile.write(buffer, p); diff --git a/src/module/PhotonOutput1D.cpp b/src/module/PhotonOutput1D.cpp index 18bdd4bb7..539fa98c3 100644 --- a/src/module/PhotonOutput1D.cpp +++ b/src/module/PhotonOutput1D.cpp @@ -3,6 +3,7 @@ #include #include +#include #include using namespace std; @@ -34,15 +35,15 @@ void PhotonOutput1D::process(Candidate *candidate) const { char buffer[1024]; size_t p = 0; - p += sprintf(buffer + p, "%4i\t", pid); - p += sprintf(buffer + p, "%g\t", candidate->current.getEnergy() / EeV); - p += sprintf(buffer + p, "%8.4f\t", candidate->current.getPosition().getR() / Mpc); + p += std::sprintf(buffer + p, "%4i\t", pid); + p += std::sprintf(buffer + p, "%g\t", candidate->current.getEnergy() / EeV); + p += std::sprintf(buffer + p, "%8.4f\t", candidate->current.getPosition().getR() / Mpc); - p += sprintf(buffer + p, "%10i\t", candidate->created.getId()); - p += sprintf(buffer + p, "%8.4f\t", candidate->created.getEnergy() / EeV); + p += std::sprintf(buffer + p, "%10i\t", candidate->created.getId()); + p += std::sprintf(buffer + p, "%8.4f\t", candidate->created.getEnergy() / EeV); - p += sprintf(buffer + p, "%10i\t", candidate->source.getId()); - p += sprintf(buffer + p, "%8.4f\n", candidate->source.getEnergy() / EeV); + p += std::sprintf(buffer + p, "%10i\t", candidate->source.getId()); + p += std::sprintf(buffer + p, "%8.4f\n", candidate->source.getEnergy() / EeV); #pragma omp critical diff --git a/src/module/TextOutput.cpp b/src/module/TextOutput.cpp index 74eabc0a7..ecfc187f5 100644 --- a/src/module/TextOutput.cpp +++ b/src/module/TextOutput.cpp @@ -137,91 +137,91 @@ void TextOutput::process(Candidate *c) const { std::locale old_locale = std::locale::global(std::locale::classic()); if (fields.test(TrajectoryLengthColumn)) - p += sprintf(buffer + p, "%8.5E\t", + p += std::sprintf(buffer + p, "%8.5E\t", c->getTrajectoryLength() / lengthScale); if (fields.test(RedshiftColumn)) - p += sprintf(buffer + p, "%1.5E\t", c->getRedshift()); + p += std::sprintf(buffer + p, "%1.5E\t", c->getRedshift()); if (fields.test(SerialNumberColumn)) - p += sprintf(buffer + p, "%10lu\t", + p += std::sprintf(buffer + p, "%10lu\t", c->getSerialNumber()); if (fields.test(CurrentIdColumn)) - p += sprintf(buffer + p, "%10i\t", c->current.getId()); + p += std::sprintf(buffer + p, "%10i\t", c->current.getId()); if (fields.test(CurrentEnergyColumn)) - p += sprintf(buffer + p, "%8.5E\t", + p += std::sprintf(buffer + p, "%8.5E\t", c->current.getEnergy() / energyScale); if (fields.test(CurrentPositionColumn)) { if (oneDimensional) { - p += sprintf(buffer + p, "%8.5E\t", + p += std::sprintf(buffer + p, "%8.5E\t", c->current.getPosition().x / lengthScale); } else { const Vector3d pos = c->current.getPosition() / lengthScale; - p += sprintf(buffer + p, "%8.5E\t%8.5E\t%8.5E\t", pos.x, pos.y, + p += std::sprintf(buffer + p, "%8.5E\t%8.5E\t%8.5E\t", pos.x, pos.y, pos.z); } } if (fields.test(CurrentDirectionColumn)) { if (not oneDimensional) { const Vector3d pos = c->current.getDirection(); - p += sprintf(buffer + p, "%8.5E\t%8.5E\t%8.5E\t", pos.x, pos.y, + p += std::sprintf(buffer + p, "%8.5E\t%8.5E\t%8.5E\t", pos.x, pos.y, pos.z); } } if (fields.test(SerialNumberColumn)) - p += sprintf(buffer + p, "%10lu\t", c->getSourceSerialNumber()); + p += std::sprintf(buffer + p, "%10lu\t", c->getSourceSerialNumber()); if (fields.test(SourceIdColumn)) - p += sprintf(buffer + p, "%10i\t", c->source.getId()); + p += std::sprintf(buffer + p, "%10i\t", c->source.getId()); if (fields.test(SourceEnergyColumn)) - p += sprintf(buffer + p, "%8.5E\t", + p += std::sprintf(buffer + p, "%8.5E\t", c->source.getEnergy() / energyScale); if (fields.test(SourcePositionColumn)) { if (oneDimensional) { - p += sprintf(buffer + p, "%8.5E\t", + p += std::sprintf(buffer + p, "%8.5E\t", c->source.getPosition().x / lengthScale); } else { const Vector3d pos = c->source.getPosition() / lengthScale; - p += sprintf(buffer + p, "%8.5E\t%8.5E\t%8.5E\t", pos.x, pos.y, + p += std::sprintf(buffer + p, "%8.5E\t%8.5E\t%8.5E\t", pos.x, pos.y, pos.z); } } if (fields.test(SourceDirectionColumn)) { if (not oneDimensional) { const Vector3d pos = c->source.getDirection(); - p += sprintf(buffer + p, "%8.5E\t%8.5E\t%8.5E\t", pos.x, pos.y, + p += std::sprintf(buffer + p, "%8.5E\t%8.5E\t%8.5E\t", pos.x, pos.y, pos.z); } } if (fields.test(SerialNumberColumn)) - p += sprintf(buffer + p, "%10lu\t", + p += std::sprintf(buffer + p, "%10lu\t", c->getCreatedSerialNumber()); if (fields.test(CreatedIdColumn)) - p += sprintf(buffer + p, "%10i\t", c->created.getId()); + p += std::sprintf(buffer + p, "%10i\t", c->created.getId()); if (fields.test(CreatedEnergyColumn)) - p += sprintf(buffer + p, "%8.5E\t", + p += std::sprintf(buffer + p, "%8.5E\t", c->created.getEnergy() / energyScale); if (fields.test(CreatedPositionColumn)) { if (oneDimensional) { - p += sprintf(buffer + p, "%8.5E\t", + p += std::sprintf(buffer + p, "%8.5E\t", c->created.getPosition().x / lengthScale); } else { const Vector3d pos = c->created.getPosition() / lengthScale; - p += sprintf(buffer + p, "%8.5E\t%8.5E\t%8.5E\t", pos.x, pos.y, + p += std::sprintf(buffer + p, "%8.5E\t%8.5E\t%8.5E\t", pos.x, pos.y, pos.z); } } if (fields.test(CreatedDirectionColumn)) { if (not oneDimensional) { const Vector3d pos = c->created.getDirection(); - p += sprintf(buffer + p, "%8.5E\t%8.5E\t%8.5E\t", pos.x, pos.y, + p += std::sprintf(buffer + p, "%8.5E\t%8.5E\t%8.5E\t", pos.x, pos.y, pos.z); } } if (fields.test(WeightColumn)) { - p += sprintf(buffer + p, "%8.5E\t", c->getWeight()); + p += std::sprintf(buffer + p, "%8.5E\t", c->getWeight()); } for(std::vector::const_iterator iter = properties.begin(); @@ -236,8 +236,8 @@ void TextOutput::process(Candidate *c) const { { v = (*iter).defaultValue; } - p += sprintf(buffer + p, "%s", v.toString().c_str()); - p += sprintf(buffer + p, "\t"); + p += std::sprintf(buffer + p, "%s", v.toString().c_str()); + p += std::sprintf(buffer + p, "\t"); } buffer[p - 1] = '\n'; From d4a0560a2476ed2dd2788d3a38621829d3312cb8 Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Thu, 7 Dec 2017 11:15:31 +0000 Subject: [PATCH 1055/1298] added std:: in front of stdio functions in Random.cpp --- src/Random.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Random.cpp b/src/Random.cpp index 22cfac88b..0e12fa59d 100644 --- a/src/Random.cpp +++ b/src/Random.cpp @@ -59,6 +59,8 @@ #include "crpropa/Random.h" +#include + namespace crpropa { Random::Random(const uint32& oneSeed) { @@ -323,15 +325,15 @@ void Random::seed(uint32 * const bigSeed, const uint32 seedLength) { void Random::seed() { // First try getting an array from /dev/urandom - FILE* urandom = fopen("/dev/urandom", "rb"); + FILE* urandom = std::fopen("/dev/urandom", "rb"); if (urandom) { uint32 bigSeed[N]; uint32 *s = bigSeed; int i = N; bool success = true; while (success && i--) - success = fread(s++, sizeof(uint32), 1, urandom) != 0; - fclose(urandom); + success = std::fread(s++, sizeof(uint32), 1, urandom) != 0; + std::fclose(urandom); if (success) { seed(bigSeed, N); return; From 8dca93087dcdf15937415e47e97a1c84b9b6b875 Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Fri, 8 Dec 2017 12:04:11 +0000 Subject: [PATCH 1056/1298] smart pointer in ModuleList::run --- include/crpropa/ModuleList.h | 2 +- src/ModuleList.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/crpropa/ModuleList.h b/include/crpropa/ModuleList.h index 3181e6db1..1eac61328 100644 --- a/include/crpropa/ModuleList.h +++ b/include/crpropa/ModuleList.h @@ -30,7 +30,7 @@ class ModuleList: public Module { void process(Candidate *candidate) const; ///< call process in all modules void process(ref_ptr candidate) const; ///< call process in all modules - void run(Candidate *candidate, bool recursive = true, bool secondariesFirst = false); ///< run simulation for a single candidate + void run(ref_ptr candidate, bool recursive = true, bool secondariesFirst = false); ///< run simulation for a single candidate void run(candidate_vector_t &candidates, bool recursive = true, bool secondariesFirst = false); ///< run simulation for a candidate vector void run(SourceInterface *source, size_t count, bool recursive = true, bool secondariesFirst = false); ///< run simulation for a number of candidates from the given source diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index e42f5fb92..8fe0f1cec 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -47,7 +47,7 @@ void ModuleList::process(ref_ptr candidate) const { (*m)->process(candidate); } -void ModuleList::run(Candidate *candidate, bool recursive, bool secondariesFirst) { +void ModuleList::run(ref_ptr candidate, bool recursive, bool secondariesFirst) { // propagate primary candidate until finished while (candidate->isActive() && !g_cancel_signal_flag) { process(candidate); From 064db5585a7873951307532dbf7f2a564a9e73f3 Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Fri, 8 Dec 2017 14:10:09 +0000 Subject: [PATCH 1057/1298] additional interface for smart pointers in ModuleList --- include/crpropa/ModuleList.h | 5 +++-- include/crpropa/module/PhotonEleCa.h | 2 +- src/ModuleList.cpp | 12 +++++++----- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/include/crpropa/ModuleList.h b/include/crpropa/ModuleList.h index 1eac61328..ae263f462 100644 --- a/include/crpropa/ModuleList.h +++ b/include/crpropa/ModuleList.h @@ -27,12 +27,13 @@ class ModuleList: public Module { module_list_t &getModules(); const module_list_t &getModules() const; - void process(Candidate *candidate) const; ///< call process in all modules + void process(Candidate* candidate) const; ///< call process in all modules void process(ref_ptr candidate) const; ///< call process in all modules + void run(Candidate* candidate, bool recursive = true, bool secondariesFirst = false); ///< run simulation for a single candidate void run(ref_ptr candidate, bool recursive = true, bool secondariesFirst = false); ///< run simulation for a single candidate void run(candidate_vector_t &candidates, bool recursive = true, bool secondariesFirst = false); ///< run simulation for a candidate vector - void run(SourceInterface *source, size_t count, bool recursive = true, bool secondariesFirst = false); ///< run simulation for a number of candidates from the given source + void run(SourceInterface* source, size_t count, bool recursive = true, bool secondariesFirst = false); ///< run simulation for a number of candidates from the given source std::string getDescription() const; void showModules() const; diff --git a/include/crpropa/module/PhotonEleCa.h b/include/crpropa/module/PhotonEleCa.h index 8becff660..b96ff7ef5 100644 --- a/include/crpropa/module/PhotonEleCa.h +++ b/include/crpropa/module/PhotonEleCa.h @@ -16,7 +16,7 @@ namespace crpropa { class PhotonEleCa: public Module { private: - std::auto_ptr propagation; + std::unique_ptr propagation; mutable std::ofstream output; Vector3d observer; bool saveOnlyPhotonEnergies; diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 8fe0f1cec..80e918399 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -35,19 +35,17 @@ void ModuleList::add(Module *module) { modules.push_back(module); } -void ModuleList::process(Candidate *candidate) const { +void ModuleList::process(Candidate* candidate) const { module_list_t::const_iterator m; for (m = modules.begin(); m != modules.end(); m++) (*m)->process(candidate); } void ModuleList::process(ref_ptr candidate) const { - module_list_t::const_iterator m; - for (m = modules.begin(); m != modules.end(); m++) - (*m)->process(candidate); + process((Candidate*) candidate); } -void ModuleList::run(ref_ptr candidate, bool recursive, bool secondariesFirst) { +void ModuleList::run(Candidate* candidate, bool recursive, bool secondariesFirst) { // propagate primary candidate until finished while (candidate->isActive() && !g_cancel_signal_flag) { process(candidate); @@ -72,6 +70,10 @@ void ModuleList::run(ref_ptr candidate, bool recursive, bool secondar } } +void ModuleList::run(ref_ptr candidate, bool recursive, bool secondariesFirst) { + run((Candidate*) candidate, recursive, secondariesFirst); +} + void ModuleList::run(candidate_vector_t &candidates, bool recursive, bool secondariesFirst) { size_t count = candidates.size(); From 3e6abe89e977c37df9979a294ec5d18b8da15d00 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 8 Dec 2017 15:14:45 +0100 Subject: [PATCH 1058/1298] Use ref_ptr for addSecondary, Closes: #129 --- include/crpropa/Candidate.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/crpropa/Candidate.h b/include/crpropa/Candidate.h index 1e30c95a3..57af48f09 100644 --- a/include/crpropa/Candidate.h +++ b/include/crpropa/Candidate.h @@ -112,6 +112,7 @@ class Candidate: public Referenced { Trajectory length and redshift are copied from the parent. */ void addSecondary(Candidate *c); + inline void addSecondary(ref_ptr c) { addSecondary(c.get()); }; void addSecondary(int id, double energy, double weight = 1); void addSecondary(int id, double energy, Vector3d position, double weight = 1); void clearSecondaries(); From 276f31e46220fac8f9b7da7b9f81de2df2292220 Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Fri, 8 Dec 2017 14:26:06 +0000 Subject: [PATCH 1059/1298] return to std::auto_ptr --- include/crpropa/module/PhotonEleCa.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/crpropa/module/PhotonEleCa.h b/include/crpropa/module/PhotonEleCa.h index b96ff7ef5..c3238e6fe 100644 --- a/include/crpropa/module/PhotonEleCa.h +++ b/include/crpropa/module/PhotonEleCa.h @@ -3,6 +3,7 @@ #include "crpropa/Module.h" #include "crpropa/magneticField/MagneticField.h" +#include "crpropa/Referenced.h" #include #include @@ -16,7 +17,7 @@ namespace crpropa { class PhotonEleCa: public Module { private: - std::unique_ptr propagation; + std::auto_ptr propagation; mutable std::ofstream output; Vector3d observer; bool saveOnlyPhotonEnergies; From 086eb3b1533524ead6eee4b74bfd3bd60c2c0b03 Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Sat, 9 Dec 2017 05:58:51 +0000 Subject: [PATCH 1060/1298] New feature: ParticleCollector::getTrajectory - re-run the simulation for a given event in the particle collector to retrieve the trajectory of it --- include/crpropa/Candidate.h | 10 +++- include/crpropa/module/ParticleCollector.h | 15 +++++- python/2_headers.i | 6 +-- src/Candidate.cpp | 6 +++ src/module/ParticleCollector.cpp | 42 ++++++++++----- test/testOutput.cpp | 62 +++++++++++++++++++--- 6 files changed, 115 insertions(+), 26 deletions(-) diff --git a/include/crpropa/Candidate.h b/include/crpropa/Candidate.h index 57af48f09..2970dd086 100644 --- a/include/crpropa/Candidate.h +++ b/include/crpropa/Candidate.h @@ -53,7 +53,8 @@ class Candidate: public Referenced { Vector3d position = Vector3d(0, 0, 0), Vector3d direction = Vector3d(-1, 0, 0), double z = 0, - double weight = 1); + double weight = 1 + ); /** Creates a candidate, initializing the Candidate::source, Candidate::created, @@ -112,7 +113,7 @@ class Candidate: public Referenced { Trajectory length and redshift are copied from the parent. */ void addSecondary(Candidate *c); - inline void addSecondary(ref_ptr c) { addSecondary(c.get()); }; + inline void addSecondary(ref_ptr c) { addSecondary(c.get()); }; void addSecondary(int id, double energy, double weight = 1); void addSecondary(int id, double energy, Vector3d position, double weight = 1); void clearSecondaries(); @@ -141,6 +142,11 @@ class Candidate: public Referenced { */ ref_ptr clone(bool recursive = false) const; + /** + Copy the source particle state to the current state + and activate it if inactive, e.g. restart it + */ + void restart(); }; } // namespace crpropa diff --git a/include/crpropa/module/ParticleCollector.h b/include/crpropa/module/ParticleCollector.h index bf7680068..ebd66aab3 100644 --- a/include/crpropa/module/ParticleCollector.h +++ b/include/crpropa/module/ParticleCollector.h @@ -4,6 +4,7 @@ #include #include "crpropa/Module.h" +#include "crpropa/ModuleList.h" namespace crpropa { @@ -30,19 +31,29 @@ class ParticleCollector: public Module { void reprocess(Module *action) const; void dump(const std::string &filename) const; void load(const std::string &filename); + std::size_t getCount() const; ref_ptr operator[](const std::size_t i) const; void clearContainer(); - std::string getDescription() const; + + std::string getDescription() const; std::vector > getAll() const; + void setClone(bool b); - // iterator goodies + /** iterator goodies */ typedef tContainer::iterator iterator; typedef tContainer::const_iterator const_iterator; iterator begin(); const_iterator begin() const; iterator end(); const_iterator end() const; + + /** + Retrieves the trajectory of a detected particle + Procedure: take the initial state of the particle, re-run the ModuleList for that particle, save trajectory + */ + ref_ptr getTrajectory(ModuleList* mlist, std::size_t i) const; + ref_ptr getTrajectory(ref_ptr mlist, std::size_t i) const; }; } // namespace crpropa diff --git a/python/2_headers.i b/python/2_headers.i index c80d9f09d..f0628ddb5 100644 --- a/python/2_headers.i +++ b/python/2_headers.i @@ -401,9 +401,6 @@ class RangeError {}; %} -%template(ParticleCollectorRefPtr) crpropa::ref_ptr; - -%include "crpropa/module/ParticleCollector.h" %include "crpropa/module/HDF5Output.h" %include "crpropa/module/OutputShell.h" %include "crpropa/module/OutputROOT.h" @@ -436,6 +433,9 @@ class RangeError {}; %template(ModuleListRefPtr) crpropa::ref_ptr; %include "crpropa/ModuleList.h" +%template(ParticleCollectorRefPtr) crpropa::ref_ptr; +%include "crpropa/module/ParticleCollector.h" + %exception crpropa::ParticleCollector::__getitem__ { try { $action diff --git a/src/Candidate.cpp b/src/Candidate.cpp index 525e70961..1ae2e7334 100644 --- a/src/Candidate.cpp +++ b/src/Candidate.cpp @@ -225,4 +225,10 @@ uint64_t Candidate::getNextSerialNumber() { uint64_t Candidate::nextSerialNumber = 0; +void Candidate::restart() { + setActive(true); + previous = source; + current = source; +} + } // namespace crpropa diff --git a/src/module/ParticleCollector.cpp b/src/module/ParticleCollector.cpp index 7bfab44a7..1de349e18 100644 --- a/src/module/ParticleCollector.cpp +++ b/src/module/ParticleCollector.cpp @@ -71,28 +71,46 @@ void ParticleCollector::clearContainer() { std::vector > ParticleCollector::getAll() const { return container; } + +void ParticleCollector::setClone(bool b) { + clone = b; +} + std::string ParticleCollector::getDescription() const { return "ParticleCollector"; } -ParticleCollector::iterator ParticleCollector::begin() -{ - return container.begin(); +ParticleCollector::iterator ParticleCollector::begin() { + return container.begin(); +} + +ParticleCollector::const_iterator ParticleCollector::begin() const { + return container.begin(); } -ParticleCollector::const_iterator ParticleCollector::begin() const -{ - return container.begin(); +ParticleCollector::iterator ParticleCollector::end() { + return container.end(); } -ParticleCollector::iterator ParticleCollector::end() -{ - return container.end(); +ParticleCollector::const_iterator ParticleCollector::end() const { + return container.end(); +} + +ref_ptr ParticleCollector::getTrajectory(ModuleList* mlist, std::size_t i) const { + ref_ptr trajectory = new ParticleCollector(); + ref_ptr c_tmp = container[i]->clone(); + + trajectory->setClone(true); + c_tmp->restart(); + + mlist->add(trajectory); + mlist->run(c_tmp); + + return trajectory; } -ParticleCollector::const_iterator ParticleCollector::end() const -{ - return container.end(); +ref_ptr ParticleCollector::getTrajectory(ref_ptr mlist, std::size_t i) const { + return ParticleCollector::getTrajectory((ModuleList*) mlist, i); } } // namespace crpropa diff --git a/test/testOutput.cpp b/test/testOutput.cpp index 735b34984..69230f323 100644 --- a/test/testOutput.cpp +++ b/test/testOutput.cpp @@ -4,18 +4,28 @@ ParticleCollector */ -#include "crpropa/ParticleID.h" -#include "crpropa/Candidate.h" -#include "crpropa/Units.h" -#include "crpropa/Version.h" -#include "crpropa/module/Output.h" -#include "crpropa/module/TextOutput.h" -#include "crpropa/module/ParticleCollector.h" +#include "CRPropa.h" #include #include "gtest/gtest.h" #include +// compare two arrays (intead of using Google Mock) +// https://stackoverflow.com/a/10062016/6819103 +template +::testing::AssertionResult ArraysMatch(const T (&expected)[size], + const T (&actual)[size]){ + for (size_t i(0); i < size; ++i){ + if (expected[i] != actual[i]){ + return ::testing::AssertionFailure() << "array[" << i + << "] (" << actual[i] << ") != expected[" << i + << "] (" << expected[i] << ")"; + } + } + + return ::testing::AssertionSuccess(); +} + namespace crpropa { //-- Output @@ -173,6 +183,7 @@ TEST(ParticleCollector, dumpload) { input.process(c); } + // Well, it would be nicer if we don't need to receate any file input.dump("ParticleCollector_DumpTest.txt"); output.load("ParticleCollector_DumpTest.txt"); @@ -183,6 +194,43 @@ TEST(ParticleCollector, dumpload) { EXPECT_EQ(output[3]->getRedshift(), c->getRedshift()); } +// Just test if the trajectory is on a line for rectilinear propagation +TEST(ParticleCollector, getTrajectory) { + int pos_x[10]; + int pos_x_expected[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + + + ParticleState p; + p.setPosition(Vector3d(10, 0, 0)); + p.setDirection(Vector3d(-1, 0, 0)); + ref_ptr c = new Candidate(p); + + ref_ptr output = new ParticleCollector(); + ref_ptr trajectory = new ParticleCollector(); + + ref_ptr sim = new ModuleList(); + sim->add(new SimplePropagation(1, 1)); + + ref_ptr obs = new Observer(); + obs->add(new ObserverPoint()); + obs->onDetection(output); + sim->add(obs); + + sim->run(c); + + trajectory = output->getTrajectory(sim, 0); + + Vector3d pos; int i; + + for (ParticleCollector::iterator itr = trajectory->begin(); itr != trajectory->end(); ++itr){ + pos = (*(itr->get())).current.getPosition(); + pos_x[i] = pos.getX(); + ++i; + } + + EXPECT_TRUE(ArraysMatch(pos_x_expected, pos_x)); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); From 93df8f02cd22a273a7316ce8fe25790d348e5c24 Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Sun, 10 Dec 2017 14:17:04 +0000 Subject: [PATCH 1061/1298] Changed behaviour of ParticleCollector::getTrajectory() to enable python goodies while at the same time losing the pythonic approach of using the method - the trajectory is now returned through the argument --- include/crpropa/module/ParticleCollector.h | 4 ++-- python/2_headers.i | 11 +++++------ python/3_repr.i | 4 ++++ python/4_lens.i | 11 +++++------ python/crpropa-builtin.i | 5 ----- python/crpropa.i | 1 - src/module/ParticleCollector.cpp | 9 +++------ test/testOutput.cpp | 2 +- 8 files changed, 20 insertions(+), 27 deletions(-) diff --git a/include/crpropa/module/ParticleCollector.h b/include/crpropa/module/ParticleCollector.h index ebd66aab3..e40ed1d77 100644 --- a/include/crpropa/module/ParticleCollector.h +++ b/include/crpropa/module/ParticleCollector.h @@ -52,8 +52,8 @@ class ParticleCollector: public Module { Retrieves the trajectory of a detected particle Procedure: take the initial state of the particle, re-run the ModuleList for that particle, save trajectory */ - ref_ptr getTrajectory(ModuleList* mlist, std::size_t i) const; - ref_ptr getTrajectory(ref_ptr mlist, std::size_t i) const; + void getTrajectory(ModuleList* mlist, std::size_t i, ParticleCollector* trajectory) const; + void getTrajectory(ref_ptr mlist, std::size_t i, ref_ptr trajectory) const; }; } // namespace crpropa diff --git a/python/2_headers.i b/python/2_headers.i index f0628ddb5..f64557249 100644 --- a/python/2_headers.i +++ b/python/2_headers.i @@ -57,11 +57,6 @@ %include "crpropa/Logging.h" -%include "crpropa/Version.h" -%pythoncode %{ - __version__ = g_GIT_DESC -%} - %include "crpropa/Vector3.h" %include "crpropa/Referenced.h" %include "crpropa/Units.h" @@ -73,6 +68,7 @@ %include "crpropa/ParticleState.h" %include "crpropa/ParticleID.h" %include "crpropa/ParticleMass.h" +%include "crpropa/Version.h" %import "crpropa/Variant.h" @@ -445,7 +441,7 @@ class RangeError {}; return NULL; } -} +}; %extend crpropa::ParticleCollector { crpropa::ref_ptr __getitem__(size_t i) { @@ -454,5 +450,8 @@ class RangeError {}; } return (*($self))[i]; } + size_t __len__() { + return $self->getCount(); + } }; diff --git a/python/3_repr.i b/python/3_repr.i index c86360f08..4c86a3aed 100644 --- a/python/3_repr.i +++ b/python/3_repr.i @@ -17,3 +17,7 @@ VECTOR3__REPR__( crpropa::Vector3 ); DeflectionCK = PropagationCK # legacy name %} +%pythoncode %{ + __version__ = g_GIT_DESC +%} + diff --git a/python/4_lens.i b/python/4_lens.i index 44016e82e..234af76fe 100644 --- a/python/4_lens.i +++ b/python/4_lens.i @@ -109,12 +109,11 @@ __WITHNUMPY = False #ifdef WITHNUMPY %extend crpropa::ParticleMapsContainer{ - - PyObject *addParticles(PyObject *particleIds, - PyObject *energies, - PyObject *galacticLongitudes, - PyObject *galacticLatitudes, - PyObject *weights) + PyObject *addParticles(PyObject *particleIds, + PyObject *energies, + PyObject *galacticLongitudes, + PyObject *galacticLatitudes, + PyObject *weights) { //ToDo: Handle strided arrays diff --git a/python/crpropa-builtin.i b/python/crpropa-builtin.i index c8d0658f0..2724a7431 100644 --- a/python/crpropa-builtin.i +++ b/python/crpropa-builtin.i @@ -68,11 +68,6 @@ %enddef -%pythoncode %{ -class ParticleCollector(ParticleCollector): - __getitem__ = ParticleCollector.__getitem__ -%} - /* Division of vector fix #34 */ %feature("python:slot", "nb_divide", functype="binaryfunc") *::operator/; diff --git a/python/crpropa.i b/python/crpropa.i index 92a57d76c..8119059bf 100644 --- a/python/crpropa.i +++ b/python/crpropa.i @@ -42,7 +42,6 @@ Vector3f.__repr__ = Vector3__repr__ %enddef - %include "3_repr.i" /* 4. Magnetic Lens */ diff --git a/src/module/ParticleCollector.cpp b/src/module/ParticleCollector.cpp index 1de349e18..6f210441a 100644 --- a/src/module/ParticleCollector.cpp +++ b/src/module/ParticleCollector.cpp @@ -96,8 +96,7 @@ ParticleCollector::const_iterator ParticleCollector::end() const { return container.end(); } -ref_ptr ParticleCollector::getTrajectory(ModuleList* mlist, std::size_t i) const { - ref_ptr trajectory = new ParticleCollector(); +void ParticleCollector::getTrajectory(ModuleList* mlist, std::size_t i, ParticleCollector* trajectory) const { ref_ptr c_tmp = container[i]->clone(); trajectory->setClone(true); @@ -105,12 +104,10 @@ ref_ptr ParticleCollector::getTrajectory(ModuleList* mlist, s mlist->add(trajectory); mlist->run(c_tmp); - - return trajectory; } -ref_ptr ParticleCollector::getTrajectory(ref_ptr mlist, std::size_t i) const { - return ParticleCollector::getTrajectory((ModuleList*) mlist, i); +void ParticleCollector::getTrajectory(ref_ptr mlist, std::size_t i, ref_ptr trajectory) const { + ParticleCollector::getTrajectory((ModuleList*) mlist, i, (ParticleCollector*) trajectory); } } // namespace crpropa diff --git a/test/testOutput.cpp b/test/testOutput.cpp index 69230f323..b97423707 100644 --- a/test/testOutput.cpp +++ b/test/testOutput.cpp @@ -218,7 +218,7 @@ TEST(ParticleCollector, getTrajectory) { sim->run(c); - trajectory = output->getTrajectory(sim, 0); + output->getTrajectory(sim, 0, trajectory); Vector3d pos; int i; From af0064de8302b0dac04487fec4f1d43e5625064f Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Sun, 10 Dec 2017 20:03:00 +0000 Subject: [PATCH 1062/1298] Fixed #30, #48. ModuleList mimics python list with .remove(index) ability --- include/crpropa/ModuleList.h | 13 +++++++++++-- python/2_headers.i | 29 ++++++++++++++++++++++++++++- src/ModuleList.cpp | 33 +++++++++++++++++++++++++++++---- test/testModuleList.cpp | 15 +++++++++++++++ 4 files changed, 83 insertions(+), 7 deletions(-) diff --git a/include/crpropa/ModuleList.h b/include/crpropa/ModuleList.h index ae263f462..ba59e3ead 100644 --- a/include/crpropa/ModuleList.h +++ b/include/crpropa/ModuleList.h @@ -24,8 +24,9 @@ class ModuleList: public Module { void setShowProgress(bool show = true); ///< activate a progress bar void add(Module* module); - module_list_t &getModules(); - const module_list_t &getModules() const; + void remove(std::size_t i); + std::size_t getCount() const; + ref_ptr operator[](const std::size_t i); void process(Candidate* candidate) const; ///< call process in all modules void process(ref_ptr candidate) const; ///< call process in all modules @@ -37,6 +38,14 @@ class ModuleList: public Module { std::string getDescription() const; void showModules() const; + + /** iterator goodies */ + typedef module_list_t::iterator iterator; + typedef module_list_t::const_iterator const_iterator; + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; private: module_list_t modules; diff --git a/python/2_headers.i b/python/2_headers.i index f64557249..1423497ea 100644 --- a/python/2_headers.i +++ b/python/2_headers.i @@ -14,6 +14,10 @@ %include "exception.i" %include "std_iostream.i" +/* slots */ +%feature("python:slot", "sq_length", functype="lenfunc") __len__; +%feature("python:slot", "mp_subscript", functype="binaryfunc") __getitem__; + #ifdef CRPROPA_HAVE_QUIMBY %import (module="quimby") "quimby/Referenced.h" %import (module="quimby") "quimby/Vector3.h" @@ -426,11 +430,33 @@ class RangeError {}; %feature("director") crpropa::SourceFeature; %include "crpropa/Source.h" +%exception crpropa::ModuleList::__getitem__ { + try { + $action + } + catch (RangeError) { + SWIG_exception(SWIG_IndexError, "Index out of bounds"); + return NULL; + } + +}; + +%extend crpropa::ModuleList { + crpropa::ref_ptr __getitem__(size_t i) { + if (i >= $self->getCount()) { + throw RangeError(); + } + return (*($self))[i]; + } + size_t __len__() { + return $self->getCount(); + } +}; + %template(ModuleListRefPtr) crpropa::ref_ptr; %include "crpropa/ModuleList.h" %template(ParticleCollectorRefPtr) crpropa::ref_ptr; -%include "crpropa/module/ParticleCollector.h" %exception crpropa::ParticleCollector::__getitem__ { try { @@ -455,3 +481,4 @@ class RangeError {}; } }; +%include "crpropa/module/ParticleCollector.h" diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 80e918399..646cbff47 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -35,6 +35,23 @@ void ModuleList::add(Module *module) { modules.push_back(module); } +void ModuleList::remove(std::size_t i) { + auto module_i = modules.begin(); + std::advance(module_i, i); + modules.erase(module_i); +} + +std::size_t ModuleList::getCount() const { + return modules.size(); +} + +ref_ptr ModuleList::operator[](const std::size_t i) { + auto module_i = modules.begin(); + std::advance(module_i, i); + return *module_i; +} + + void ModuleList::process(Candidate* candidate) const { module_list_t::const_iterator m; for (m = modules.begin(); m != modules.end(); m++) @@ -163,12 +180,20 @@ void ModuleList::run(SourceInterface *source, size_t count, bool recursive, bool ::signal(SIGINT, old_signal_handler); } -ModuleList::module_list_t &ModuleList::getModules() { - return modules; +ModuleList::iterator ModuleList::begin() { + return modules.begin(); +} + +ModuleList::const_iterator ModuleList::begin() const { + return modules.begin(); +} + +ModuleList::iterator ModuleList::end() { + return modules.end(); } -const ModuleList::module_list_t &ModuleList::getModules() const { - return modules; +ModuleList::const_iterator ModuleList::end() const { + return modules.end(); } std::string ModuleList::getDescription() const { diff --git a/test/testModuleList.cpp b/test/testModuleList.cpp index 8bc61256e..fc7b361fa 100644 --- a/test/testModuleList.cpp +++ b/test/testModuleList.cpp @@ -16,6 +16,21 @@ TEST(ModuleList, process) { modules.process(candidate); } +TEST(ModuleList, getModule) { + ModuleList modules; + ref_ptr prop = new SimplePropagation(); + modules.add(prop); + EXPECT_TRUE(modules[0] == prop); +} + +TEST(ModuleList, removeModule) { + ModuleList modules; + ref_ptr prop = new SimplePropagation(); + modules.add(prop); + modules.remove(0); + EXPECT_EQ(modules.getCount(), 0); +} + TEST(ModuleList, runCandidateList) { ModuleList modules; modules.add(new SimplePropagation()); From 4ed8243a0a36942dc78bd48f88aa22a130896feb Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Sun, 10 Dec 2017 20:29:08 +0000 Subject: [PATCH 1063/1298] pre-c++11 support --- src/ModuleList.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index 646cbff47..cf8e460b4 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -36,7 +36,7 @@ void ModuleList::add(Module *module) { } void ModuleList::remove(std::size_t i) { - auto module_i = modules.begin(); + iterator module_i = modules.begin(); std::advance(module_i, i); modules.erase(module_i); } @@ -46,7 +46,7 @@ std::size_t ModuleList::getCount() const { } ref_ptr ModuleList::operator[](const std::size_t i) { - auto module_i = modules.begin(); + iterator module_i = modules.begin(); std::advance(module_i, i); return *module_i; } From 5919e60abca9d36909448f83de3b90a5500bd043 Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Sun, 10 Dec 2017 21:09:44 +0000 Subject: [PATCH 1064/1298] Added slicing in ParticleCollector, renamed getCount() to size() --- include/crpropa/ModuleList.h | 2 +- include/crpropa/module/Output.h | 2 +- include/crpropa/module/ParticleCollector.h | 2 +- python/2_headers.i | 32 +++++++++++++++++++--- src/ModuleList.cpp | 2 +- src/module/Output.cpp | 2 +- src/module/ParticleCollector.cpp | 2 +- test/testModuleList.cpp | 2 +- test/testOutput.cpp | 10 +++---- 9 files changed, 40 insertions(+), 16 deletions(-) diff --git a/include/crpropa/ModuleList.h b/include/crpropa/ModuleList.h index ba59e3ead..0503672aa 100644 --- a/include/crpropa/ModuleList.h +++ b/include/crpropa/ModuleList.h @@ -25,7 +25,7 @@ class ModuleList: public Module { void add(Module* module); void remove(std::size_t i); - std::size_t getCount() const; + std::size_t size() const; ref_ptr operator[](const std::size_t i); void process(Candidate* candidate) const; ///< call process in all modules diff --git a/include/crpropa/module/Output.h b/include/crpropa/module/Output.h index 4b05b3e00..80ff332d2 100644 --- a/include/crpropa/module/Output.h +++ b/include/crpropa/module/Output.h @@ -79,7 +79,7 @@ class Output: public Module { void enableAll(); void disableAll(); void set1D(bool value); - size_t getCount() const; + size_t size() const; void process(Candidate *) const; }; diff --git a/include/crpropa/module/ParticleCollector.h b/include/crpropa/module/ParticleCollector.h index e40ed1d77..65dc4c405 100644 --- a/include/crpropa/module/ParticleCollector.h +++ b/include/crpropa/module/ParticleCollector.h @@ -32,7 +32,7 @@ class ParticleCollector: public Module { void dump(const std::string &filename) const; void load(const std::string &filename); - std::size_t getCount() const; + std::size_t size() const; ref_ptr operator[](const std::size_t i) const; void clearContainer(); diff --git a/python/2_headers.i b/python/2_headers.i index 1423497ea..726d543f0 100644 --- a/python/2_headers.i +++ b/python/2_headers.i @@ -443,13 +443,13 @@ class RangeError {}; %extend crpropa::ModuleList { crpropa::ref_ptr __getitem__(size_t i) { - if (i >= $self->getCount()) { + if (i >= $self->size()) { throw RangeError(); } return (*($self))[i]; } size_t __len__() { - return $self->getCount(); + return $self->size(); } }; @@ -471,13 +471,37 @@ class RangeError {}; %extend crpropa::ParticleCollector { crpropa::ref_ptr __getitem__(size_t i) { - if (i >= $self->getCount()) { + if (i >= $self->size()) { throw RangeError(); } return (*($self))[i]; } + std::vector< crpropa::ref_ptr > __getitem__(PyObject *param) { + std::vector< crpropa::ref_ptr > result; + + if (PySlice_Check(param)) { + Py_ssize_t len = 0, start = 0, stop = 0, step = 0, slicelength = 0, i = 0; + len = $self->size(); + + #ifdef SWIG_PYTHON3 + PySlice_GetIndicesEx(param, len, &start, &stop, &step, &slicelength); + #else + PySlice_GetIndicesEx((PySliceObject*)param, len, &start, &stop, &step, &slicelength); + #endif + + for(crpropa::ParticleCollector::iterator itr = $self->begin(); itr != $self->end(); ++itr){ + if( i >= start && i < stop){ + result.push_back(itr->get()); + } + ++i; + } + return result; + } else { + throw RangeError(); + } + } size_t __len__() { - return $self->getCount(); + return $self->size(); } }; diff --git a/src/ModuleList.cpp b/src/ModuleList.cpp index cf8e460b4..c2ba58f07 100644 --- a/src/ModuleList.cpp +++ b/src/ModuleList.cpp @@ -41,7 +41,7 @@ void ModuleList::remove(std::size_t i) { modules.erase(module_i); } -std::size_t ModuleList::getCount() const { +std::size_t ModuleList::size() const { return modules.size(); } diff --git a/src/module/Output.cpp b/src/module/Output.cpp index 93a15dc7d..1eba9b0f7 100644 --- a/src/module/Output.cpp +++ b/src/module/Output.cpp @@ -119,7 +119,7 @@ void Output::disableAll() { fields.reset(); } -size_t Output::getCount() const { +size_t Output::size() const { return count; } diff --git a/src/module/ParticleCollector.cpp b/src/module/ParticleCollector.cpp index 6f210441a..d4d3f65c2 100644 --- a/src/module/ParticleCollector.cpp +++ b/src/module/ParticleCollector.cpp @@ -56,7 +56,7 @@ ParticleCollector::~ParticleCollector() { clearContainer(); } -std::size_t ParticleCollector::getCount() const { +std::size_t ParticleCollector::size() const { return container.size(); } diff --git a/test/testModuleList.cpp b/test/testModuleList.cpp index fc7b361fa..08eb973ee 100644 --- a/test/testModuleList.cpp +++ b/test/testModuleList.cpp @@ -28,7 +28,7 @@ TEST(ModuleList, removeModule) { ref_ptr prop = new SimplePropagation(); modules.add(prop); modules.remove(0); - EXPECT_EQ(modules.getCount(), 0); + EXPECT_EQ(modules.size(), 0); } TEST(ModuleList, runCandidateList) { diff --git a/test/testOutput.cpp b/test/testOutput.cpp index b97423707..f11777831 100644 --- a/test/testOutput.cpp +++ b/test/testOutput.cpp @@ -30,12 +30,12 @@ namespace crpropa { //-- Output -TEST(Output, getCount) { +TEST(Output, size) { Candidate c; Output output; for (int it=0; it<5; ++it, output.process(&c)); - EXPECT_EQ(output.getCount(), 5); + EXPECT_EQ(output.size(), 5); } //-- TextOutput @@ -140,13 +140,13 @@ TEST(TextOutput, printHeader_Version) { //-- ParticleCollector -TEST(ParticleCollector, getCount) { +TEST(ParticleCollector, size) { ref_ptr c = new Candidate(); ParticleCollector output; for (int it=0; it<5; ++it, output.process(c)); - EXPECT_EQ(output.getCount(), 5); + EXPECT_EQ(output.size(), 5); } TEST(ParticleCollector, fetchItem) { @@ -187,7 +187,7 @@ TEST(ParticleCollector, dumpload) { input.dump("ParticleCollector_DumpTest.txt"); output.load("ParticleCollector_DumpTest.txt"); - EXPECT_EQ(input.getCount(), output.getCount()); + EXPECT_EQ(input.size(), output.size()); EXPECT_EQ(output[0]->current.getEnergy(), c->current.getEnergy()); EXPECT_EQ(output[1]->getTrajectoryLength(), c->getTrajectoryLength()); EXPECT_EQ(output[2]->current.getId(), c->current.getId()); From 1093b45acc9097dbe2ee5e34c805bbc4851575e7 Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Sun, 10 Dec 2017 21:34:37 +0000 Subject: [PATCH 1065/1298] maintained icons in README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 905e7ce42..7308dab52 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ CRPropa3 ======== [![Build Status](https://travis-ci.org/CRPropa/CRPropa3.svg?branch=master)](https://travis-ci.org/CRPropa/CRPropa3) +[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/CRPropa/CRPropa3.svg)](http://isitmaintained.com/project/CRPropa/CRPropa3 "Average time to resolve an issue") +[![Percentage of issues still open](http://isitmaintained.com/badge/open/CRPropa/CRPropa3.svg)](http://isitmaintained.com/project/CRPropa/CRPropa3 "Percentage of issues still open") CRPropa is a publicly available code to study the propagation of ultra high energy nuclei up to iron on their voyage through an extra galactic environment. It takes into account: pion production, photodisintegration and energy losses by pair production of all relevant isotopes in the ambient low energy photon fields as well as nuclear decay. CRPropa can model the deflection in intergalactic magnetic fields, the propagation of secondary electromagnetic cascades and neutrinos for a multitude of scenarios for different source distributions and magnetic environments. It enables the user to predict the spectra of UHECR (and of their secondaries), their composition and arrival direction distribution. From a20c5cc5f534ab84a712b0a9c10c07c384211ce0 Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Mon, 11 Dec 2017 09:38:55 +0000 Subject: [PATCH 1066/1298] Fixed #152. --- include/crpropa/Units.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/crpropa/Units.h b/include/crpropa/Units.h index 51f01b152..813dffbed 100644 --- a/include/crpropa/Units.h +++ b/include/crpropa/Units.h @@ -97,7 +97,6 @@ static const double ns = nanosecond; static const double mus = microsecond; static const double ms = millisecond; static const double sec = second; -static const double min = minute; } // namespace crpropa From ab27fe2738c89fe9a32c4fd2dd00bd8877448bbf Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Mon, 11 Dec 2017 14:56:06 +0000 Subject: [PATCH 1067/1298] ParticleCollector::getTrajectory accepts any Output module, not only ParticleCollector --- include/crpropa/module/ParticleCollector.h | 4 ++-- src/module/ParticleCollector.cpp | 10 +++++----- test/testOutput.cpp | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/crpropa/module/ParticleCollector.h b/include/crpropa/module/ParticleCollector.h index 65dc4c405..f1e8eb806 100644 --- a/include/crpropa/module/ParticleCollector.h +++ b/include/crpropa/module/ParticleCollector.h @@ -52,8 +52,8 @@ class ParticleCollector: public Module { Retrieves the trajectory of a detected particle Procedure: take the initial state of the particle, re-run the ModuleList for that particle, save trajectory */ - void getTrajectory(ModuleList* mlist, std::size_t i, ParticleCollector* trajectory) const; - void getTrajectory(ref_ptr mlist, std::size_t i, ref_ptr trajectory) const; + void getTrajectory(ModuleList *mlist, std::size_t i, Module *output) const; + void getTrajectory(ref_ptr mlist, std::size_t i, ref_ptr output) const; }; } // namespace crpropa diff --git a/src/module/ParticleCollector.cpp b/src/module/ParticleCollector.cpp index d4d3f65c2..f12f5c8d9 100644 --- a/src/module/ParticleCollector.cpp +++ b/src/module/ParticleCollector.cpp @@ -96,18 +96,18 @@ ParticleCollector::const_iterator ParticleCollector::end() const { return container.end(); } -void ParticleCollector::getTrajectory(ModuleList* mlist, std::size_t i, ParticleCollector* trajectory) const { +void ParticleCollector::getTrajectory(ModuleList* mlist, std::size_t i, Module *output) const { ref_ptr c_tmp = container[i]->clone(); - trajectory->setClone(true); c_tmp->restart(); - mlist->add(trajectory); + mlist->add(output); mlist->run(c_tmp); + mlist->remove(mlist->size()-1); } -void ParticleCollector::getTrajectory(ref_ptr mlist, std::size_t i, ref_ptr trajectory) const { - ParticleCollector::getTrajectory((ModuleList*) mlist, i, (ParticleCollector*) trajectory); +void ParticleCollector::getTrajectory(ref_ptr mlist, std::size_t i, ref_ptr output) const { + ParticleCollector::getTrajectory((ModuleList*) mlist, i, (Module*) output); } } // namespace crpropa diff --git a/test/testOutput.cpp b/test/testOutput.cpp index f11777831..abfcf3310 100644 --- a/test/testOutput.cpp +++ b/test/testOutput.cpp @@ -207,6 +207,7 @@ TEST(ParticleCollector, getTrajectory) { ref_ptr output = new ParticleCollector(); ref_ptr trajectory = new ParticleCollector(); + trajectory->setClone(true); ref_ptr sim = new ModuleList(); sim->add(new SimplePropagation(1, 1)); From 2fe7c14c0ea6079ff09f0071ac968c8fc43d6a0a Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Tue, 12 Dec 2017 10:30:18 +0000 Subject: [PATCH 1068/1298] Implemented proper python iterators in SWIG for ModuleList and ParticleCollector --- include/crpropa/module/ParticleCollector.h | 2 +- python/2_headers.i | 85 +++++++++++++++++++++- test/testPythonExtension.py.in | 8 ++ 3 files changed, 90 insertions(+), 5 deletions(-) diff --git a/include/crpropa/module/ParticleCollector.h b/include/crpropa/module/ParticleCollector.h index f1e8eb806..ca0fbd3d1 100644 --- a/include/crpropa/module/ParticleCollector.h +++ b/include/crpropa/module/ParticleCollector.h @@ -50,7 +50,7 @@ class ParticleCollector: public Module { /** Retrieves the trajectory of a detected particle - Procedure: take the initial state of the particle, re-run the ModuleList for that particle, save trajectory + Procedure: takes the initial state of the particle, re-runs the ModuleList for that particle and captures trajectory */ void getTrajectory(ModuleList *mlist, std::size_t i, Module *output) const; void getTrajectory(ref_ptr mlist, std::size_t i, ref_ptr output) const; diff --git a/python/2_headers.i b/python/2_headers.i index 726d543f0..aa2063d36 100644 --- a/python/2_headers.i +++ b/python/2_headers.i @@ -17,6 +17,17 @@ /* slots */ %feature("python:slot", "sq_length", functype="lenfunc") __len__; %feature("python:slot", "mp_subscript", functype="binaryfunc") __getitem__; +%feature("python:slot", "tp_iter", functype="unaryfunc") __iter__; +#ifdef SWIG_PYTHON3 +%feature("python:slot", "tp_iternext", functype="iternextfunc") __next__; +#else +%feature("python:slot", "tp_iternext", functype="iternextfunc") next; +#endif + +%inline %{ +class RangeError {}; +class StopIterator {}; +%} #ifdef CRPROPA_HAVE_QUIMBY %import (module="quimby") "quimby/Referenced.h" @@ -397,9 +408,6 @@ %include "crpropa/module/Output.h" %include "crpropa/module/DiffusionSDE.h" %include "crpropa/module/TextOutput.h" -%inline %{ -class RangeError {}; -%} %include "crpropa/module/HDF5Output.h" %include "crpropa/module/OutputShell.h" @@ -430,6 +438,29 @@ class RangeError {}; %feature("director") crpropa::SourceFeature; %include "crpropa/Source.h" +%inline %{ +class ModuleListIterator { + public: + ModuleListIterator( + crpropa::ModuleList::iterator _cur, + crpropa::ModuleList::iterator _end) : + cur(_cur), end(_end) {} + ModuleListIterator* __iter__() { return this; } + crpropa::ModuleList::iterator cur; + crpropa::ModuleList::iterator end; + }; +%} + +%exception ModuleListIterator::__next__ { + try { + $action + } + catch (StopIterator) { + PyErr_SetString(PyExc_StopIteration, "End of iterator"); + return NULL; + } +} + %exception crpropa::ModuleList::__getitem__ { try { $action @@ -441,7 +472,19 @@ class RangeError {}; }; +%extend ModuleListIterator { + crpropa::ref_ptr& __next__() { + if ($self->cur != $self->end) { + return *$self->cur++; + } + throw StopIterator(); + } +} + %extend crpropa::ModuleList { + ModuleListIterator __iter__() { + return ModuleListIterator($self->begin(), $self->end()); + } crpropa::ref_ptr __getitem__(size_t i) { if (i >= $self->size()) { throw RangeError(); @@ -458,6 +501,29 @@ class RangeError {}; %template(ParticleCollectorRefPtr) crpropa::ref_ptr; +%inline %{ +class ParticleCollectorIterator { + public: + ParticleCollectorIterator( + crpropa::ParticleCollector::iterator _cur, + crpropa::ParticleCollector::iterator _end) : + cur(_cur), end(_end) {} + ParticleCollectorIterator* __iter__() { return this; } + crpropa::ParticleCollector::iterator cur; + crpropa::ParticleCollector::iterator end; + }; +%} + +%exception ParticleCollectorIterator::__next__ { + try { + $action + } + catch (StopIterator) { + PyErr_SetString(PyExc_StopIteration, "End of iterator"); + return NULL; + } +} + %exception crpropa::ParticleCollector::__getitem__ { try { $action @@ -466,10 +532,21 @@ class RangeError {}; SWIG_exception(SWIG_IndexError, "Index out of bounds"); return NULL; } - }; +%extend ParticleCollectorIterator { + crpropa::ref_ptr& __next__() { + if ($self->cur != $self->end) { + return *$self->cur++; + } + throw StopIterator(); + } +} + %extend crpropa::ParticleCollector { + ParticleCollectorIterator __iter__() { + return ParticleCollectorIterator($self->begin(), $self->end()); + } crpropa::ref_ptr __getitem__(size_t i) { if (i >= $self->size()) { throw RangeError(); diff --git a/test/testPythonExtension.py.in b/test/testPythonExtension.py.in index b398d6bc2..9d885b92d 100644 --- a/test/testPythonExtension.py.in +++ b/test/testPythonExtension.py.in @@ -47,6 +47,14 @@ class testCrossLanguagePolymorphism(unittest.TestCase): c.current.setId(id) filter.process(c) + def test_ParticleCollector(self): + c = crp.Candidate() + p = crp.ParticleCollector() + p.process(c) + c_out = p[0] + for c_i in p: + c_out = c_i + def test_ObserverFeature(self): class CountingFeature(crp.ObserverFeature): def __init__(self): From 7ceb96ee047d05c07def1410c21669d3fdeba92a Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Tue, 12 Dec 2017 11:13:48 +0000 Subject: [PATCH 1069/1298] Python2 iterator fix in SWIG; simplify and reorganize SWIG file --- python/1_swig.i | 65 +++++++++++++++++++++++++++++++++------- python/2_headers.i | 75 ++++++++-------------------------------------- 2 files changed, 67 insertions(+), 73 deletions(-) diff --git a/python/1_swig.i b/python/1_swig.i index 26e89d974..0c7fd2e1b 100644 --- a/python/1_swig.i +++ b/python/1_swig.i @@ -20,20 +20,65 @@ using std::ptrdiff_t; %} -%exception -{ - try - { +/* SWIG headers */ + +%include "stl.i" +%include "std_set.i" +%include "std_multiset.i" +%include "std_map.i" +%include "std_pair.i" +%include "std_multimap.i" +%include "std_vector.i" +%include "std_string.i" +%include "std_list.i" +%include "stdint.i" +%include "std_container.i" +%include "exception.i" +%include "std_iostream.i" + +/* SWIG Exceptions */ + +%inline %{ +class RangeError {}; +class StopIterator {}; +%} + +%exception { + try { $action - } - catch (Swig::DirectorException &e) { + } catch (Swig::DirectorException &e) { SWIG_exception(SWIG_RuntimeError, e.getMessage()); - } - catch (const std::exception& e) { + } catch (const std::exception& e) { SWIG_exception(SWIG_RuntimeError, e.what()); - } - catch (const char *e) { + } catch (const char *e) { SWIG_exception(SWIG_RuntimeError, e); } } +/* Exceptions for Python lists and iterators */ + +#ifdef SWIG_PYTHON3 +%exception __next__ { +#else +%exception next { +#endif + try { + $action + } + catch (StopIterator) { + PyErr_SetString(PyExc_StopIteration, "End of iterator"); + return NULL; + } +} + +%exception __getitem__ { + try { + $action + } + catch (RangeError) { + SWIG_exception(SWIG_IndexError, "Index out of bounds"); + return NULL; + } + +}; + diff --git a/python/2_headers.i b/python/2_headers.i index aa2063d36..f17b27c72 100644 --- a/python/2_headers.i +++ b/python/2_headers.i @@ -1,20 +1,6 @@ -/* 2: SWIG and CRPropa headers */ - -%include "stl.i" -%include "std_set.i" -%include "std_multiset.i" -%include "std_map.i" -%include "std_pair.i" -%include "std_multimap.i" -%include "std_vector.i" -%include "std_string.i" -%include "std_list.i" -%include "stdint.i" -%include "std_container.i" -%include "exception.i" -%include "std_iostream.i" - -/* slots */ +/* 2: CRPropa headers and Python extensions */ + +/* Python slots */ %feature("python:slot", "sq_length", functype="lenfunc") __len__; %feature("python:slot", "mp_subscript", functype="binaryfunc") __getitem__; %feature("python:slot", "tp_iter", functype="unaryfunc") __iter__; @@ -24,10 +10,7 @@ %feature("python:slot", "tp_iternext", functype="iternextfunc") next; #endif -%inline %{ -class RangeError {}; -class StopIterator {}; -%} +/* Include headers */ #ifdef CRPROPA_HAVE_QUIMBY %import (module="quimby") "quimby/Referenced.h" @@ -40,7 +23,6 @@ class StopIterator {}; %import (module="saga") saga.i #endif - %{ #include "CRPropa.h" %} @@ -451,29 +433,12 @@ class ModuleListIterator { }; %} -%exception ModuleListIterator::__next__ { - try { - $action - } - catch (StopIterator) { - PyErr_SetString(PyExc_StopIteration, "End of iterator"); - return NULL; - } -} - -%exception crpropa::ModuleList::__getitem__ { - try { - $action - } - catch (RangeError) { - SWIG_exception(SWIG_IndexError, "Index out of bounds"); - return NULL; - } - -}; - %extend ModuleListIterator { +#ifdef SWIG_PYTHON3 crpropa::ref_ptr& __next__() { +#else + crpropa::ref_ptr& next() { +#endif if ($self->cur != $self->end) { return *$self->cur++; } @@ -514,28 +479,12 @@ class ParticleCollectorIterator { }; %} -%exception ParticleCollectorIterator::__next__ { - try { - $action - } - catch (StopIterator) { - PyErr_SetString(PyExc_StopIteration, "End of iterator"); - return NULL; - } -} - -%exception crpropa::ParticleCollector::__getitem__ { - try { - $action - } - catch (RangeError) { - SWIG_exception(SWIG_IndexError, "Index out of bounds"); - return NULL; - } -}; - %extend ParticleCollectorIterator { +#ifdef SWIG_PYTHON3 crpropa::ref_ptr& __next__() { +#else + crpropa::ref_ptr& next() { +#endif if ($self->cur != $self->end) { return *$self->cur++; } From fadc85045e9d3504d57324635a2614adedb34f10 Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Thu, 14 Dec 2017 07:32:57 +0000 Subject: [PATCH 1070/1298] Changed web path of the data file --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6eb76b284..04169324d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -305,11 +305,11 @@ endif() # ---------------------------------------------------------------------------- message("-- Downloading data file from crpropa.desy.de ~ 50 MB") file(DOWNLOAD - https://www.desy.de/~crpropa/data/data.tar.gz-CHECKSUM + https://www.desy.de/~crpropa/data/interaction_data/data.tar.gz-CHECKSUM ${CMAKE_BINARY_DIR}/data.tar.gz-CHECKSUM) file(STRINGS ${CMAKE_BINARY_DIR}/data.tar.gz-CHECKSUM DATA_CHECKSUM LIMIT_COUNT 1 LENGTH_MINIMUM 32 LENGTH_MAXIMUM 32) file(DOWNLOAD - https://www.desy.de/~crpropa/data/data.tar.gz + https://www.desy.de/~crpropa/data/interaction_data/data.tar.gz ${CMAKE_BINARY_DIR}/data.tar.gz EXPECTED_MD5 "${DATA_CHECKSUM}") message("-- Extracting data file") From 8056af5918a9f97e65284674b56fd4dc9b786cd1 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 15 Dec 2017 12:20:40 +0100 Subject: [PATCH 1071/1298] Added option to disable data file download --- CMakeLists.txt | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 04169324d..be4f05167 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,9 +108,6 @@ if(ENABLE_COVERAGE) message(WARNING "genhtml not found, coverage report generation not possible!") endif(NOT GENHTML_PATH) endif(LCOV_PATH AND GENHTML_PATH) - - - endif(ENABLE_COVERAGE) # kiss (provided) @@ -303,17 +300,28 @@ endif() # ---------------------------------------------------------------------------- # Download data files (interaction data, masses, decay data ...) # ---------------------------------------------------------------------------- -message("-- Downloading data file from crpropa.desy.de ~ 50 MB") -file(DOWNLOAD - https://www.desy.de/~crpropa/data/interaction_data/data.tar.gz-CHECKSUM - ${CMAKE_BINARY_DIR}/data.tar.gz-CHECKSUM) -file(STRINGS ${CMAKE_BINARY_DIR}/data.tar.gz-CHECKSUM DATA_CHECKSUM LIMIT_COUNT 1 LENGTH_MINIMUM 32 LENGTH_MAXIMUM 32) -file(DOWNLOAD - https://www.desy.de/~crpropa/data/interaction_data/data.tar.gz - ${CMAKE_BINARY_DIR}/data.tar.gz - EXPECTED_MD5 "${DATA_CHECKSUM}") -message("-- Extracting data file") -execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_BINARY_DIR}/data.tar.gz WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +OPTION(DOWNLOAD_DATA "Download CRProap Data files" ON) +if(DOWNLOAD_DATA) + message("-- Downloading data file from crpropa.desy.de ~ 50 MB") + file(DOWNLOAD + https://www.desy.de/~crpropa/data/interaction_data/data.tar.gz-CHECKSUM + ${CMAKE_BINARY_DIR}/data.tar.gz-CHECKSUM) + file(STRINGS ${CMAKE_BINARY_DIR}/data.tar.gz-CHECKSUM DATA_CHECKSUM LIMIT_COUNT 1 LENGTH_MINIMUM 32 LENGTH_MAXIMUM 32) + file(DOWNLOAD + https://www.desy.de/~crpropa/data/interaction_data/data.tar.gz + ${CMAKE_BINARY_DIR}/data.tar.gz + EXPECTED_MD5 "${DATA_CHECKSUM}") + message("-- Extracting data file") +else() + message("-- Downloading of data file disabled") +endif(DOWNLOAD_DATA) +if(EXISTS ${CMAKE_BINARY_DIR}/data.tar.gz) + execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_BINARY_DIR}/data.tar.gz WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +else() + message(WARNING "CRPropa data file not found at ${CMAKE_BINARY_DIR}/data.tar.gz +CRPropa should compile, but will likely not work properly! Please install data file manually, or use the automatic download which is enabled by default.") +endif() + # ---------------------------------------------------------------------------- # Library and Binary # ---------------------------------------------------------------------------- From e7e5f9e48bc005ecf64f4d0724e13ee518e8fa6b Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Fri, 15 Dec 2017 13:50:30 +0100 Subject: [PATCH 1072/1298] Fixed bug in test of Sc-44 decay --- test/testInteraction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 07e79565d..9d32fee36 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -151,7 +151,7 @@ TEST(NuclearDecay, scandium44) { EXPECT_DOUBLE_EQ(gamma, c.current.getLorentzFactor()); // expect at least two secondaries: positron + electron neutrino - EXPECT_GE(2, c.secondaries.size()); + EXPECT_GE(c.secondaries.size(), 2); } TEST(NuclearDecay, lithium4) { From 4e62fa64c5370404e74c14b1abfc27afe1cde795 Mon Sep 17 00:00:00 2001 From: Mike Wilbert Date: Tue, 31 Oct 2017 21:19:03 +0100 Subject: [PATCH 1073/1298] The textfiles for the new propagation module PropagationBP were created. --- include/crpropa/module/PropagationBP.h | 1 + src/module/PropagationBP.cpp | 1 + 2 files changed, 2 insertions(+) create mode 100644 include/crpropa/module/PropagationBP.h create mode 100644 src/module/PropagationBP.cpp diff --git a/include/crpropa/module/PropagationBP.h b/include/crpropa/module/PropagationBP.h new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/include/crpropa/module/PropagationBP.h @@ -0,0 +1 @@ + diff --git a/src/module/PropagationBP.cpp b/src/module/PropagationBP.cpp new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/src/module/PropagationBP.cpp @@ -0,0 +1 @@ + From 2908329ead0099ee9e5d0e8b216007ee7e2d9090 Mon Sep 17 00:00:00 2001 From: Mike Wilbert Date: Thu, 2 Nov 2017 17:13:13 +0100 Subject: [PATCH 1074/1298] First version of the PropagationBP module without adaptive step size. --- CMakeLists.txt | 1 + include/CRPropa.h | 1 + include/crpropa/module/PropagationBP.h | 30 ++++++++++ python/2_headers.i | 1 + src/module/PropagationBP.cpp | 78 ++++++++++++++++++++++++++ 5 files changed, 111 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index be4f05167..08a6a6473 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -369,6 +369,7 @@ add_library(crpropa SHARED src/module/PhotonEleCa.cpp src/module/PhotonOutput1D.cpp src/module/PropagationCK.cpp + src/module/PropagationBP.cpp src/module/Redshift.cpp src/module/SimplePropagation.cpp src/module/SynchrotronRadiation.cpp diff --git a/include/CRPropa.h b/include/CRPropa.h index fd42a52cc..727c673e2 100644 --- a/include/CRPropa.h +++ b/include/CRPropa.h @@ -46,6 +46,7 @@ #include "crpropa/module/PhotonEleCa.h" #include "crpropa/module/PhotonOutput1D.h" #include "crpropa/module/PropagationCK.h" +#include "crpropa/module/PropagationBP.h" #include "crpropa/module/Redshift.h" #include "crpropa/module/SimplePropagation.h" #include "crpropa/module/SynchrotronRadiation.h" diff --git a/include/crpropa/module/PropagationBP.h b/include/crpropa/module/PropagationBP.h index 8b1378917..8994f48e7 100644 --- a/include/crpropa/module/PropagationBP.h +++ b/include/crpropa/module/PropagationBP.h @@ -1 +1,31 @@ +#ifndef CRPROPA_PROPAGATIONBP_H +#define CRPROPA_PROPAGATIONBP_H + +#include "crpropa/Module.h" +#include "crpropa/Units.h" +#include "crpropa/magneticField/MagneticField.h" + +namespace crpropa { + + class PropagationBP: public Module { + + ref_ptr field; + double Step; + +public: + //~ PropagationBP(ref_ptr field = NULL, + //~ double Step = (0.1 * kpc)); + PropagationBP(); + + void process(Candidate &candidate) const; + + void setField(ref_ptr field); + void setStep(double Step); + double getStep() const; + +}; + +}// namespace crpropa + +#endif // CRPROPA_PROPAGATIONBP_H diff --git a/python/2_headers.i b/python/2_headers.i index f17b27c72..322ca367f 100644 --- a/python/2_headers.i +++ b/python/2_headers.i @@ -314,6 +314,7 @@ %include "crpropa/module/Observer.h" %include "crpropa/module/SimplePropagation.h" %include "crpropa/module/PropagationCK.h" +%include "crpropa/module/PropagationBP.h" %ignore crpropa::Output::enableProperty(const std::string &property, const Variant& defaultValue, const std::string &comment = ""); %extend crpropa::Output{ diff --git a/src/module/PropagationBP.cpp b/src/module/PropagationBP.cpp index 8b1378917..d1b99e4f8 100644 --- a/src/module/PropagationBP.cpp +++ b/src/module/PropagationBP.cpp @@ -1 +1,79 @@ +#include "crpropa/module/PropagationBP.h" +#include +#include +#include + +namespace crpropa { +/* +PropagationBP::PropagationBP(ref_ptr field, + double Step):Step(0) + { + //setField(field); + //setStep(Step); +} +*/ + +PropagationBP::PropagationBP() + { + std::cout << "Ich lebe!"; +} +void PropagationBP::process(Candidate &c) const { + + // update + c.previous = c.current; + + + double step = getStep(); + + // get particle properties + double q = c.current.getCharge(); + double m = c.current.getEnergy()/(c_light*c_light); + Vector3d x = c.current.getPosition(); + Vector3d v = c.current.getDirection(); + + // half leap frog step in the position + c.current.setPosition(x + c_light * v * step *1/2); + + // get B field at particle position + Vector3d B(0, 0, 0); + double z = 1; // <- Lukas fragen! + try { + B = field->getField(x, z); + } catch (std::exception &e) { + std::cerr << "PropagationBP: Exception in getField." << std::endl; + std::cerr << e.what() << std::endl; + } + + // Boris help vectors + Vector3d t = B * q/2/m * step; + Vector3d s = t *2. /(1+t.dot(t)); + Vector3d v_help; + + // Boris Push + v_help = v + v.cross(t); + v = v + v_help.cross(s); + + // full leap frog step in the velocity + c.current.setDirection(v); + + // the other half leap frog step in the position + c.current.setPosition(x + v * step *1/2); + +} + +void PropagationBP::setField(ref_ptr f) { + field = f; +} + +void PropagationBP::setStep(double min) { + if (min < 0.) + throw std::runtime_error("PropagationBP: Step < 0 "); + Step = min; +} + +double PropagationBP::getStep() const { + return Step; +} + +} From 4a37c300e669eb52c2863d2e3857b8f5ed45bb7c Mon Sep 17 00:00:00 2001 From: Mike Wilbert Date: Thu, 2 Nov 2017 17:18:56 +0100 Subject: [PATCH 1075/1298] First version of the PropagationBP module without adaptive step size. --- include/crpropa/module/PropagationBP.h | 5 ++--- src/module/PropagationBP.cpp | 12 ++++-------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/include/crpropa/module/PropagationBP.h b/include/crpropa/module/PropagationBP.h index 8994f48e7..27e7d0096 100644 --- a/include/crpropa/module/PropagationBP.h +++ b/include/crpropa/module/PropagationBP.h @@ -14,9 +14,8 @@ namespace crpropa { double Step; public: - //~ PropagationBP(ref_ptr field = NULL, - //~ double Step = (0.1 * kpc)); - PropagationBP(); + PropagationBP(ref_ptr field = NULL, + double Step = (0.1 * kpc)); void process(Candidate &candidate) const; diff --git a/src/module/PropagationBP.cpp b/src/module/PropagationBP.cpp index d1b99e4f8..8fa5a4220 100644 --- a/src/module/PropagationBP.cpp +++ b/src/module/PropagationBP.cpp @@ -5,19 +5,15 @@ #include namespace crpropa { -/* + PropagationBP::PropagationBP(ref_ptr field, double Step):Step(0) { - //setField(field); - //setStep(Step); + setField(field); + setStep(Step); } -*/ -PropagationBP::PropagationBP() - { - std::cout << "Ich lebe!"; -} + void PropagationBP::process(Candidate &c) const { // update From 3ed1482845c6083f03fcbe6e2f6e9f88672fb5f4 Mon Sep 17 00:00:00 2001 From: Mike Wilbert Date: Fri, 3 Nov 2017 18:32:25 +0100 Subject: [PATCH 1076/1298] PropagationBP::process : The parameter passing of candidate was changed from reference to pointer due to problems with swig. --- include/crpropa/module/PropagationBP.h | 6 ++-- src/module/PropagationBP.cpp | 43 ++++++++++++++------------ src/module/PropagationCK.cpp | 2 +- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/include/crpropa/module/PropagationBP.h b/include/crpropa/module/PropagationBP.h index 27e7d0096..e70370fdc 100644 --- a/include/crpropa/module/PropagationBP.h +++ b/include/crpropa/module/PropagationBP.h @@ -1,4 +1,3 @@ - #ifndef CRPROPA_PROPAGATIONBP_H #define CRPROPA_PROPAGATIONBP_H @@ -13,11 +12,12 @@ namespace crpropa { ref_ptr field; double Step; + public: PropagationBP(ref_ptr field = NULL, - double Step = (0.1 * kpc)); + double Step = (0.1 * Mpc)); - void process(Candidate &candidate) const; + void process(Candidate *candidate) const; void setField(ref_ptr field); void setStep(double Step); diff --git a/src/module/PropagationBP.cpp b/src/module/PropagationBP.cpp index 8fa5a4220..8026303f4 100644 --- a/src/module/PropagationBP.cpp +++ b/src/module/PropagationBP.cpp @@ -7,40 +7,42 @@ namespace crpropa { PropagationBP::PropagationBP(ref_ptr field, - double Step):Step(0) + double Step):Step(1* Mpc) { setField(field); setStep(Step); } -void PropagationBP::process(Candidate &c) const { +void PropagationBP::process(Candidate *c) const { // update - c.previous = c.current; + c->previous = c->current; double step = getStep(); + c->setCurrentStep(step); - // get particle properties - double q = c.current.getCharge(); - double m = c.current.getEnergy()/(c_light*c_light); - Vector3d x = c.current.getPosition(); - Vector3d v = c.current.getDirection(); + //get particle properties + double q = c->current.getCharge(); + double m = c->current.getEnergy()/(c_light*c_light); + Vector3d x = c->current.getPosition(); + Vector3d v = c->current.getDirection(); // half leap frog step in the position - c.current.setPosition(x + c_light * v * step *1/2); + c->current.setPosition(x + v * step * 1/2 ); // get B field at particle position + //Vector3d B(1 * nG, 0, 0); Vector3d B(0, 0, 0); double z = 1; // <- Lukas fragen! - try { - B = field->getField(x, z); - } catch (std::exception &e) { - std::cerr << "PropagationBP: Exception in getField." << std::endl; - std::cerr << e.what() << std::endl; - } - + //~ try { + //~ B = field->getField(x, z); + //~ } catch (std::exception &e) { + //~ std::cerr << "PropagationBP: Exception in getField." << std::endl; + //~ std::cerr << e.what() << std::endl; + //~ } + //~ // Boris help vectors Vector3d t = B * q/2/m * step; Vector3d s = t *2. /(1+t.dot(t)); @@ -51,13 +53,16 @@ void PropagationBP::process(Candidate &c) const { v = v + v_help.cross(s); // full leap frog step in the velocity - c.current.setDirection(v); + c->current.setDirection(v); + + //~ // the other half leap frog step in the position + c->current.setPosition(x + v * step *1/2); - // the other half leap frog step in the position - c.current.setPosition(x + v * step *1/2); + c->setNextStep(step); } + void PropagationBP::setField(ref_ptr f) { field = f; } diff --git a/src/module/PropagationCK.cpp b/src/module/PropagationCK.cpp index cc7ee5086..67686aefb 100644 --- a/src/module/PropagationCK.cpp +++ b/src/module/PropagationCK.cpp @@ -4,7 +4,7 @@ #include #include #include - +//~ namespace crpropa { // Cash-Karp coefficients From 15ac581405ee422f9acacca49c175a399e25e28a Mon Sep 17 00:00:00 2001 From: Mike Wilbert Date: Tue, 7 Nov 2017 17:42:54 +0100 Subject: [PATCH 1077/1298] Changes in the step size. This version without adaptive step size seems to work. --- src/module/PropagationBP.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/module/PropagationBP.cpp b/src/module/PropagationBP.cpp index 8026303f4..99d77a09c 100644 --- a/src/module/PropagationBP.cpp +++ b/src/module/PropagationBP.cpp @@ -22,6 +22,7 @@ void PropagationBP::process(Candidate *c) const { double step = getStep(); c->setCurrentStep(step); + step = step / c_light; //get particle properties double q = c->current.getCharge(); @@ -30,19 +31,19 @@ void PropagationBP::process(Candidate *c) const { Vector3d v = c->current.getDirection(); // half leap frog step in the position - c->current.setPosition(x + v * step * 1/2 ); + c->current.setPosition(x + c_light * v * step ); // get B field at particle position //Vector3d B(1 * nG, 0, 0); Vector3d B(0, 0, 0); - double z = 1; // <- Lukas fragen! - //~ try { - //~ B = field->getField(x, z); - //~ } catch (std::exception &e) { - //~ std::cerr << "PropagationBP: Exception in getField." << std::endl; - //~ std::cerr << e.what() << std::endl; - //~ } - //~ + //~ double z = 1; // <- Lukas fragen! + double z = c->getRedshift(); + try { + B = field->getField(x, z); + } catch (std::exception &e) { + std::cerr << "PropagationBP: Exception in getField." << std::endl; + std::cerr << e.what() << std::endl; + } // Boris help vectors Vector3d t = B * q/2/m * step; Vector3d s = t *2. /(1+t.dot(t)); @@ -56,8 +57,9 @@ void PropagationBP::process(Candidate *c) const { c->current.setDirection(v); //~ // the other half leap frog step in the position - c->current.setPosition(x + v * step *1/2); + c->current.setPosition(x + c_light * v * step ); + c->setCurrentStep(step); c->setNextStep(step); } From e2177404858b07454a0443de2d07676cad1bd0d3 Mon Sep 17 00:00:00 2001 From: Mike Wilbert Date: Wed, 8 Nov 2017 12:50:05 +0100 Subject: [PATCH 1078/1298] Correction of an error in the time evaluation. --- src/module/PropagationBP.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/module/PropagationBP.cpp b/src/module/PropagationBP.cpp index 99d77a09c..0660d6360 100644 --- a/src/module/PropagationBP.cpp +++ b/src/module/PropagationBP.cpp @@ -31,7 +31,7 @@ void PropagationBP::process(Candidate *c) const { Vector3d v = c->current.getDirection(); // half leap frog step in the position - c->current.setPosition(x + c_light * v * step ); + x += c_light * v * step /2. ; // get B field at particle position //Vector3d B(1 * nG, 0, 0); @@ -57,7 +57,8 @@ void PropagationBP::process(Candidate *c) const { c->current.setDirection(v); //~ // the other half leap frog step in the position - c->current.setPosition(x + c_light * v * step ); + x += c_light * v * step /2. ; + c->current.setPosition(x); c->setCurrentStep(step); c->setNextStep(step); From 313388d199118223732d2f9abc91db2c9dd45a65 Mon Sep 17 00:00:00 2001 From: Mike Wilbert Date: Mon, 20 Nov 2017 19:44:58 +0100 Subject: [PATCH 1079/1298] Designed a magnetic bottle as a MagneticField. This is just a provisional version but it works jet. --- include/crpropa/magneticField/MagneticField.h | 19 +++++ src/magneticField/MagneticField.cpp | 79 +++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/include/crpropa/magneticField/MagneticField.h b/include/crpropa/magneticField/MagneticField.h index ebf7880e2..550cb5b48 100644 --- a/include/crpropa/magneticField/MagneticField.h +++ b/include/crpropa/magneticField/MagneticField.h @@ -102,6 +102,25 @@ class MagneticDipoleField: public MagneticField { Vector3d getField(const Vector3d &position) const; }; +/** + @class MagneticBottle + @brief Magnetic bottle along the z-axis. The field has the constant value Bz_strength for z in [-width, width]. + Out of this range, the field lines run together and the B-field strength raises linearly. + */ +class MagneticBottle: public MagneticField { + + double Br_strength; + double Bz_strength; + double Bz_slope; + double width; + +public: + MagneticBottle(double Br_strength, double Bz_strength , double Bz_slope, double width) : + Br_strength(Br_strength), Bz_strength(Bz_strength), Bz_slope(Bz_slope), width(width) {} + Vector3d getField(const Vector3d &position) const; + +}; + #ifdef CRPROPA_HAVE_MUPARSER /** @class RenormalizeMagneticField diff --git a/src/magneticField/MagneticField.cpp b/src/magneticField/MagneticField.cpp index 565f6a695..f265b6729 100644 --- a/src/magneticField/MagneticField.cpp +++ b/src/magneticField/MagneticField.cpp @@ -88,6 +88,85 @@ Vector3d MagneticDipoleField::getField(const Vector3d &position) const { return unit_r * moment.dot(unit_r) / pow((r.getR()/radius), 3) * mu0 / (4*M_PI); } +Vector3d MagneticBottle::getField(const Vector3d &position) const { + +/****************PARAMETER****************/ + //~ //double Br_strength = 1.; + //~ //double Bz_strength = 4.; + //~ //double Bz_slope = 4.; + //~ //double width = 0.5; +/*****************************************/ + + double x = position.x; + double y = position.y; + double z = position.z; + + double R = sqrt(x*x + y*y); + + double Br, Bz; + + if(fabs(z) > width){ + Br = Br_strength * fabs(fabs(z)-width)/kpc*fabs(fabs(z)-width)/kpc;//-cosh((fabs(z)-width)/kpc); + }else{ + Br = 0.; + } + + if(fabs(z) < width){ + Bz = Bz_strength; + }else{ + Bz = Bz_strength + Bz_strength* 0.1 * fabs(fabs(z)) / width; + } + + Vector3d B(Br * fabs(x) / R,Br * fabs(y) / R, Bz); + + return B; + + +} + + +//~ Vector3d MagneticBottle::getField(const Vector3d &position) const { +//~ +//~ /****************PARAMETER****************/ + double Br_strength = 1.; + double Bz_strength = 4.; + double Bz_slope = 4.; + double width = 0.5; +//~ /*****************************************/ +//~ + //~ double x = position.x; + //~ double y = position.y; + //~ double z = position.z; + //~ + //~ double R = sqrt(x*x + y*y); + //~ + //~ double Br, Bz, B; + //~ + //~ double r_xy; + //~ + //~ if(fabs(z) > width){ + //~ r_xy = (1 - width/fabs(z)) ; + //~ }else{ + //~ r_xy = 0.; + //~ } + //~ + //~ double r_z = sqrt(1-2*r_xy*r_xy); + //~ + //~ if(fabs(z) < width){ + //~ B = Bz_strength; + //~ }else{ + //~ B = Bz_strength + Bz_strength * fabs(fabs(z)) / width; + //~ } + //~ +//~ // Vector3d B(Br * fabs(x) / R,Br * fabs(y) / R, Bz); + //~ + //~ Vector3d B_field(r_xy * x/R,r_xy * y/R,r_z); + //~ + //~ return B_field; + //~ + //~ +//~ } + #ifdef CRPROPA_HAVE_MUPARSER RenormalizeMagneticField::RenormalizeMagneticField(ref_ptr field, std::string expression) : From ed1635176214940b3249a3d5dd49b64988bc0439 Mon Sep 17 00:00:00 2001 From: Mike Wilbert Date: Sat, 2 Dec 2017 15:25:35 +0100 Subject: [PATCH 1080/1298] Changed the magnetic bottle field to a phyical reasonable field, that is an analytical solution for small distances from the symmetry axis (MagneticBottle) . Also added a magnetic field in which charged particles perform a gyration motion in a small and a big scale (GyroField). The right comment to these two classes is pending. --- include/crpropa/magneticField/MagneticField.h | 28 +++-- src/magneticField/MagneticField.cpp | 101 +++++++----------- 2 files changed, 60 insertions(+), 69 deletions(-) diff --git a/include/crpropa/magneticField/MagneticField.h b/include/crpropa/magneticField/MagneticField.h index 550cb5b48..223db275c 100644 --- a/include/crpropa/magneticField/MagneticField.h +++ b/include/crpropa/magneticField/MagneticField.h @@ -106,21 +106,35 @@ class MagneticDipoleField: public MagneticField { @class MagneticBottle @brief Magnetic bottle along the z-axis. The field has the constant value Bz_strength for z in [-width, width]. Out of this range, the field lines run together and the B-field strength raises linearly. - */ + This B-field was inspired by the magnetic bottle in Computer Algebra Recipes by Enns and McGuire + **/ class MagneticBottle: public MagneticField { - double Br_strength; - double Bz_strength; - double Bz_slope; - double width; + double Bz_max; + double Bz_min; + double L; public: - MagneticBottle(double Br_strength, double Bz_strength , double Bz_slope, double width) : - Br_strength(Br_strength), Bz_strength(Bz_strength), Bz_slope(Bz_slope), width(width) {} + MagneticBottle(double Bz_max, double Bz_min, double lenght) : + Bz_max(Bz_max), Bz_min(Bz_min), L(lenght) {} Vector3d getField(const Vector3d &position) const; }; +class GyroField: public MagneticField { + + const double B_max; + const double B_min; + const double radius; + +public: + GyroField(const double B_max, const double B_min, const double radius) : + B_max(B_max), B_min(B_min), radius(radius) {} + Vector3d getField(const Vector3d &position) const; + +}; + + #ifdef CRPROPA_HAVE_MUPARSER /** @class RenormalizeMagneticField diff --git a/src/magneticField/MagneticField.cpp b/src/magneticField/MagneticField.cpp index f265b6729..cdfd73f16 100644 --- a/src/magneticField/MagneticField.cpp +++ b/src/magneticField/MagneticField.cpp @@ -88,85 +88,62 @@ Vector3d MagneticDipoleField::getField(const Vector3d &position) const { return unit_r * moment.dot(unit_r) / pow((r.getR()/radius), 3) * mu0 / (4*M_PI); } -Vector3d MagneticBottle::getField(const Vector3d &position) const { - -/****************PARAMETER****************/ - //~ //double Br_strength = 1.; - //~ //double Bz_strength = 4.; - //~ //double Bz_slope = 4.; - //~ //double width = 0.5; -/*****************************************/ +Vector3d MagneticBottle::getField(const Vector3d &position) const { // Ulrich Stroth double x = position.x; double y = position.y; double z = position.z; + + if(fabs(z) <= L/2){ - double R = sqrt(x*x + y*y); + double r = sqrt( x*x + y*y ); + double phi = atan2(y,x); - double Br, Bz; - if(fabs(z) > width){ - Br = Br_strength * fabs(fabs(z)-width)/kpc*fabs(fabs(z)-width)/kpc;//-cosh((fabs(z)-width)/kpc); - }else{ - Br = 0.; - } + double B0 = (Bz_max + Bz_min)/2; + double b = Bz_max/ B0 -1; + + double k = 2 * M_PI /L; + + double Bz = B0 * ( 1 - b * ( 1 + k*k * r*r / 4 ) * cos (k*z) ); + double Br = -B0 * ( b * k*r/2 * sin(k*z) ); - if(fabs(z) < width){ - Bz = Bz_strength; + double Bx = Br * cos(phi); + double By = Br * sin(phi); + + return Vector3d(Bx, By, Bz); + }else{ - Bz = Bz_strength + Bz_strength* 0.1 * fabs(fabs(z)) / width; + + return Vector3d(0., 0., Bz_max); + } - Vector3d B(Br * fabs(x) / R,Br * fabs(y) / R, Bz); +} + +Vector3d GyroField::getField(const Vector3d &position) const { + + double x = position.x; + double y = position.y; + double z = position.z; - return B; + double r = sqrt( x*x + y*y ); + + double B; + + if (r < radius){ + B = B_max + r/radius * (B_min - B_max); + } + else{ + B = B_min; + } + + return Vector3d(0., 0., B); } -//~ Vector3d MagneticBottle::getField(const Vector3d &position) const { -//~ -//~ /****************PARAMETER****************/ - double Br_strength = 1.; - double Bz_strength = 4.; - double Bz_slope = 4.; - double width = 0.5; -//~ /*****************************************/ -//~ - //~ double x = position.x; - //~ double y = position.y; - //~ double z = position.z; - //~ - //~ double R = sqrt(x*x + y*y); - //~ - //~ double Br, Bz, B; - //~ - //~ double r_xy; - //~ - //~ if(fabs(z) > width){ - //~ r_xy = (1 - width/fabs(z)) ; - //~ }else{ - //~ r_xy = 0.; - //~ } - //~ - //~ double r_z = sqrt(1-2*r_xy*r_xy); - //~ - //~ if(fabs(z) < width){ - //~ B = Bz_strength; - //~ }else{ - //~ B = Bz_strength + Bz_strength * fabs(fabs(z)) / width; - //~ } - //~ -//~ // Vector3d B(Br * fabs(x) / R,Br * fabs(y) / R, Bz); - //~ - //~ Vector3d B_field(r_xy * x/R,r_xy * y/R,r_z); - //~ - //~ return B_field; - //~ - //~ -//~ } - #ifdef CRPROPA_HAVE_MUPARSER RenormalizeMagneticField::RenormalizeMagneticField(ref_ptr field, std::string expression) : From 687867b438c7190d67268c16a7dabbbf15722c5d Mon Sep 17 00:00:00 2001 From: Mike Wilbert Date: Tue, 16 Jan 2018 16:33:04 +0100 Subject: [PATCH 1081/1298] ome test magnetic fields were added. --- include/crpropa/magneticField/MagneticField.h | 35 +++++++++++++++ src/magneticField/MagneticField.cpp | 44 +++++++++++++++++++ src/module/PropagationBP.cpp | 12 ++--- 3 files changed, 85 insertions(+), 6 deletions(-) diff --git a/include/crpropa/magneticField/MagneticField.h b/include/crpropa/magneticField/MagneticField.h index 223db275c..44cefbf7f 100644 --- a/include/crpropa/magneticField/MagneticField.h +++ b/include/crpropa/magneticField/MagneticField.h @@ -134,6 +134,41 @@ class GyroField: public MagneticField { }; +class LongConductorField: public MagneticField { + + const double B_radius; + const double radius; + +public: + LongConductorField(const double B_radius, const double radius) : + B_radius(B_radius), radius(radius) {} + Vector3d getField(const Vector3d &position) const; + +}; + +class CircleField: public MagneticField { + + const double B; + +public: + CircleField(const double B) : + B(B) {} + Vector3d getField(const Vector3d &position) const; + +}; + +class HongQinField: public MagneticField { + + const double B; + const double delta; + +public: + HongQinField(const double B, const double delta) : + B(B), delta(delta) {} + Vector3d getField(const Vector3d &position) const; + +}; + #ifdef CRPROPA_HAVE_MUPARSER /** diff --git a/src/magneticField/MagneticField.cpp b/src/magneticField/MagneticField.cpp index cdfd73f16..11d1770dc 100644 --- a/src/magneticField/MagneticField.cpp +++ b/src/magneticField/MagneticField.cpp @@ -141,6 +141,50 @@ Vector3d GyroField::getField(const Vector3d &position) const { return Vector3d(0., 0., B); +} + +Vector3d LongConductorField::getField(const Vector3d &position) const { + + double x = position.x; + double y = position.y; + double z = position.z; + + double r = sqrt( x*x + y*y ); + double phi = atan2(y,x); + + double B = radius/r * (B_radius); + + + return Vector3d(-B*sin(phi), B*cos(phi), 0); + + +} + +Vector3d CircleField::getField(const Vector3d &position) const { + + double x = position.x; + double y = position.y; + double z = position.z; + + double phi = atan2(y,x); + + return Vector3d(-B*sin(phi), B*cos(phi), 0); + + +} + +Vector3d HongQinField::getField(const Vector3d &position) const { + + double x = position.x; + double y = position.y; + double z = position.z; + + double Bxy = 1. + delta * (x*x/4 + y*y)/ (x*x+y*y); + + + return Vector3d(0, 0, B * Bxy); + + } diff --git a/src/module/PropagationBP.cpp b/src/module/PropagationBP.cpp index 0660d6360..0d89a5dce 100644 --- a/src/module/PropagationBP.cpp +++ b/src/module/PropagationBP.cpp @@ -22,7 +22,7 @@ void PropagationBP::process(Candidate *c) const { double step = getStep(); c->setCurrentStep(step); - step = step / c_light; + double h = step / c_light; //get particle properties double q = c->current.getCharge(); @@ -31,7 +31,7 @@ void PropagationBP::process(Candidate *c) const { Vector3d v = c->current.getDirection(); // half leap frog step in the position - x += c_light * v * step /2. ; + x += c_light * v * h /2. ; // get B field at particle position //Vector3d B(1 * nG, 0, 0); @@ -45,7 +45,7 @@ void PropagationBP::process(Candidate *c) const { std::cerr << e.what() << std::endl; } // Boris help vectors - Vector3d t = B * q/2/m * step; + Vector3d t = B * q/2/m * h; Vector3d s = t *2. /(1+t.dot(t)); Vector3d v_help; @@ -57,11 +57,11 @@ void PropagationBP::process(Candidate *c) const { c->current.setDirection(v); //~ // the other half leap frog step in the position - x += c_light * v * step /2. ; + x += c_light * v * h /2. ; c->current.setPosition(x); - c->setCurrentStep(step); - c->setNextStep(step); + c->setCurrentStep(h); + c->setNextStep(h); } From 6cf4cb4177e49276def248cb60cc569f98575a9e Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Thu, 25 Jan 2018 16:50:35 +0000 Subject: [PATCH 1082/1298] Updated ParticleCollector::process() method to accept the smart pointer version of a candidate --- include/crpropa/module/ParticleCollector.h | 1 + src/module/ParticleCollector.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/include/crpropa/module/ParticleCollector.h b/include/crpropa/module/ParticleCollector.h index ca0fbd3d1..ffa607bfe 100644 --- a/include/crpropa/module/ParticleCollector.h +++ b/include/crpropa/module/ParticleCollector.h @@ -28,6 +28,7 @@ class ParticleCollector: public Module { ~ParticleCollector(); void process(Candidate *candidate) const; + void process(ref_ptr c) const; void reprocess(Module *action) const; void dump(const std::string &filename) const; void load(const std::string &filename); diff --git a/src/module/ParticleCollector.cpp b/src/module/ParticleCollector.cpp index f12f5c8d9..f9c4ef910 100644 --- a/src/module/ParticleCollector.cpp +++ b/src/module/ParticleCollector.cpp @@ -33,6 +33,10 @@ void ParticleCollector::process(Candidate *c) const { } } +void ParticleCollector::process(ref_ptr c) const { + ParticleCollector::process((Candidate*) c); +} + void ParticleCollector::reprocess(Module *action) const { for (ParticleCollector::iterator itr = container.begin(); itr != container.end(); ++itr){ if (clone) From 781141a9919ea99179d55201f39d4a37e6aae53c Mon Sep 17 00:00:00 2001 From: Andrej Dundovic Date: Fri, 26 Jan 2018 10:00:01 +0000 Subject: [PATCH 1083/1298] Added setValue to the grid template --- include/crpropa/Grid.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/crpropa/Grid.h b/include/crpropa/Grid.h index 37f682cea..791f92515 100644 --- a/include/crpropa/Grid.h +++ b/include/crpropa/Grid.h @@ -131,6 +131,10 @@ class Grid: public Referenced { return grid[ix * Ny * Nz + iy * Nz + iz]; } + void setValue(size_t ix, size_t iy, size_t iz, T value) { + grid[ix * Ny * Nz + iy * Nz + iz] = value; + } + /** Return a reference to the grid values */ std::vector &getGrid() { return grid; From aa3d3385ee3424e0539365000a14bec4ca281d51 Mon Sep 17 00:00:00 2001 From: Tobias Winchen Date: Mon, 29 Jan 2018 17:33:42 +0100 Subject: [PATCH 1084/1298] Build documentation with make doc, updated doxygen, added mainpage --- CMakeLists.txt | 13 + doc/Doxyfile | 1884 ------------------------------- doc/Doxyfile.in | 2446 +++++++++++++++++++++++++++++++++++++++++ doc/DoxygenLayout.xml | 194 ++++ doc/Mainpage.md.in | 12 + 5 files changed, 2665 insertions(+), 1884 deletions(-) delete mode 100644 doc/Doxyfile create mode 100644 doc/Doxyfile.in create mode 100644 doc/DoxygenLayout.xml create mode 100644 doc/Mainpage.md.in diff --git a/CMakeLists.txt b/CMakeLists.txt index be4f05167..25305139c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -456,6 +456,19 @@ install(DIRECTORY ${CMAKE_BINARY_DIR}/include/ DESTINATION include FILES_MATCHIN install(DIRECTORY ${CMAKE_BINARY_DIR}/data/ DESTINATION share/crpropa/ PATTERN ".git" EXCLUDE) +# ------------------------------------------------------------------ +# Documentation +# ------------------------------------------------------------------ +find_package(Doxygen) +if(DOXYGEN_FOUND) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doc/DoxygenLayout.xml ${CMAKE_CURRENT_BINARY_DIR}/DoxygenLayout.xml COPYONLY) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doc/Mainpage.md.in ${CMAKE_CURRENT_BINARY_DIR}/Mainpage.md) + add_custom_target(doc ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating API documentation with Doxygen" VERBATIM +) +endif(DOXYGEN_FOUND) + + # ---------------------------------------------------------------------------- # Testing # ---------------------------------------------------------------------------- diff --git a/doc/Doxyfile b/doc/Doxyfile deleted file mode 100644 index 809eba57b..000000000 --- a/doc/Doxyfile +++ /dev/null @@ -1,1884 +0,0 @@ -# Doxyfile 1.8.4 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or sequence of words) that should -# identify the project. Note that if you do not use Doxywizard you need -# to put quotes around the project name if it contains spaces. - -PROJECT_NAME = "CRPropa 3" - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer -# a quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = "Propagation of ultra-relativistic particles through galactic and extragalactic space" - -# With the PROJECT_LOGO tag one can specify an logo or icon that is -# included in the documentation. The maximum height of the logo should not -# exceed 55 pixels and the maximum width should not exceed 200 pixels. -# Doxygen will copy the logo to the output directory. - -PROJECT_LOGO = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, -# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English -# messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian, -# Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, -# Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = YES - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = NO - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. Note that you specify absolute paths here, but also -# relative paths, which will be relative from the directory where doxygen is -# started. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = ../include - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful if your file system -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = NO - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 8 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding -# "class=itcl::class" will allow you to use the command class in the -# itcl::class meaning. - -TCL_SUBST = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given -# extension. Doxygen has a built-in mapping, but you can override or extend it -# using this tag. The format is ext=language, where ext is a file extension, -# and language is one of the parsers supported by doxygen: IDL, Java, -# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, -# C++. For instance to make doxygen treat .inc files as Fortran files (default -# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note -# that for custom extensions you also need to set FILE_PATTERNS otherwise the -# files are not read by doxygen. - -EXTENSION_MAPPING = - -# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all -# comments according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you -# can mix doxygen, HTML, and XML commands with Markdown formatting. -# Disable only in case of backward compatibilities issues. - -MARKDOWN_SUPPORT = YES - -# When enabled doxygen tries to link words that correspond to documented -# classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by by putting a % sign in front of the word -# or globally by setting AUTOLINK_SUPPORT to NO. - -AUTOLINK_SUPPORT = YES - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also makes the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = YES - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate -# getter and setter methods for a property. Setting this option to YES (the -# default) will make doxygen replace the get and set methods by a property in -# the documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and -# unions are shown inside the group in which they are included (e.g. using -# @ingroup) instead of on a separate page (for HTML and Man pages) or -# section (for LaTeX and RTF). - -INLINE_GROUPED_CLASSES = YES - -# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and -# unions with only public data fields or simple typedef fields will be shown -# inline in the documentation of the scope in which they are defined (i.e. file, -# namespace, or group documentation), provided this scope is documented. If set -# to NO (the default), structs, classes, and unions are shown on a separate -# page (for HTML and Man pages) or section (for LaTeX and RTF). - -INLINE_SIMPLE_STRUCTS = NO - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = NO - -# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This -# cache is used to resolve symbols given their name and scope. Since this can -# be an expensive process and often the same symbol appear multiple times in -# the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too -# small doxygen will become slower. If the cache is too large, memory is wasted. -# The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid -# range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536 -# symbols. - -LOOKUP_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = NO - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal -# scope will be included in the documentation. - -EXTRACT_PACKAGE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = YES - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = NO - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespaces are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = YES - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = NO - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen -# will list include files with double quotes in the documentation -# rather than with sharp brackets. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen -# will sort the (brief and detailed) documentation of class members so that -# constructors and destructors are listed first. If set to NO (the default) -# the constructors will appear in the respective orders defined by -# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. -# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO -# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = YES - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to -# do proper type resolution of all parameters of a function it will reject a -# match between the prototype and the implementation of a member function even -# if there is only one candidate or it is obvious which candidate to choose -# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen -# will still accept a match between prototype and implementation in such cases. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = NO - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = NO - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = NO - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= NO - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if section-label ... \endif -# and \cond section-label ... \endcond blocks. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or macro consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and macros in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. -# You can optionally specify a file name after the option, if omitted -# DoxygenLayout.xml will be used as the name of the layout file. - -LAYOUT_FILE = - -# The CITE_BIB_FILES tag can be used to specify one or more bib files -# containing the references data. This must be a list of .bib files. The -# .bib extension is automatically appended if omitted. Using this command -# requires the bibtex tool to be installed. See also -# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style -# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this -# feature you need bibtex and perl available in the search path. Do not use -# file names with spaces, bibtex cannot handle them. - -CITE_BIB_FILES = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# The WARN_NO_PARAMDOC option can be enabled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = "../include" - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh -# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py -# *.f90 *.f *.for *.vhd *.vhdl - -FILE_PATTERNS = - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should be -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. -# Note that relative paths are relative to the directory from which doxygen is -# run. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = Loki::* \ - ProgressBar* - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = Loki::* \ - ProgressBar - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be ignored. -# Note that the filter must not add or remove lines; it is applied before the -# code is scanned, but not when the output code is generated. If lines are added -# or removed, the anchors will not be placed correctly. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty or if -# non of the patterns match the file name, INPUT_FILTER is applied. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) -# and it is also possible to disable source filtering for a specific pattern -# using *.ext= (so without naming a filter). This option only has effect when -# FILTER_SOURCE_FILES is enabled. - -FILTER_SOURCE_PATTERNS = - -# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that -# is part of the input, its contents will be placed on the main page -# (index.html). This can be useful if you have a project on for instance GitHub -# and want reuse the introduction page also for the doxygen output. - -USE_MDFILE_AS_MAINPAGE = - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = YES - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C, C++ and Fortran comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentation. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = YES - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. Note that when using a custom header you are responsible -# for the proper inclusion of any scripts and style sheets that doxygen -# needs, which is dependent on the configuration options used. -# It is advised to generate a default header using "doxygen -w html -# header.html footer.html stylesheet.css YourConfigFile" and then modify -# that header. Note that the header is subject to change so you typically -# have to redo this when upgrading to a newer version of doxygen or when -# changing the value of configuration settings such as GENERATE_TREEVIEW! - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If left blank doxygen will -# generate a default style sheet. Note that it is recommended to use -# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this -# tag will in the future become obsolete. - -HTML_STYLESHEET = - -# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional -# user-defined cascading style sheet that is included after the standard -# style sheets created by doxygen. Using this option one can overrule -# certain style aspects. This is preferred over using HTML_STYLESHEET -# since it does not replace the standard style sheet and is therefor more -# robust against future updates. Doxygen will copy the style sheet file to -# the output directory. - -HTML_EXTRA_STYLESHEET = - -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that -# the files will be copied as-is; there are no commands or markers available. - -HTML_EXTRA_FILES = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. -# Doxygen will adjust the colors in the style sheet and background images -# according to this color. Hue is specified as an angle on a colorwheel, -# see http://en.wikipedia.org/wiki/Hue for more information. -# For instance the value 0 represents red, 60 is yellow, 120 is green, -# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. -# The allowed range is 0 to 359. - -HTML_COLORSTYLE_HUE = 220 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of -# the colors in the HTML output. For a value of 0 the output will use -# grayscales only. A value of 255 will produce the most vivid colors. - -HTML_COLORSTYLE_SAT = 100 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to -# the luminance component of the colors in the HTML output. Values below -# 100 gradually make the output lighter, whereas values above 100 make -# the output darker. The value divided by 100 is the actual gamma applied, -# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, -# and 100 does not change the gamma. - -HTML_COLORSTYLE_GAMMA = 80 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting -# this to NO can help when comparing the output of multiple runs. - -HTML_TIMESTAMP = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. - -HTML_DYNAMIC_SECTIONS = NO - -# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of -# entries shown in the various tree structured indices initially; the user -# can expand and collapse entries dynamically later on. Doxygen will expand -# the tree to such a level that at most the specified number of entries are -# visible (unless a fully collapsed tree already exceeds this amount). -# So setting the number of entries 1 will produce a full collapsed tree by -# default. 0 is a special value representing an infinite number of entries -# and will result in a full expanded tree by default. - -HTML_INDEX_NUM_ENTRIES = 100 - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely -# identify the documentation publisher. This should be a reverse domain-name -# style string, e.g. com.mycompany.MyDocSet.documentation. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. - -CHM_INDEX_ENCODING = - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated -# that can be used as input for Qt's qhelpgenerator to generate a -# Qt Compressed Help (.qch) of the generated HTML documentation. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders - -QHP_VIRTUAL_FOLDER = doc - -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to -# add. For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see -# -# Qt Help Project / Custom Filters. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's -# filter section matches. -# -# Qt Help Project / Filter Attributes. - -QHP_SECT_FILTER_ATTRS = - -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files -# will be generated, which together with the HTML files, form an Eclipse help -# plugin. To install this plugin and make it available under the help contents -# menu in Eclipse, the contents of the directory containing the HTML and XML -# files needs to be copied into the plugins directory of eclipse. The name of -# the directory within the plugins directory should be the same as -# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before -# the help appears. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have -# this name. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) -# at top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. Since the tabs have the same information as the -# navigation tree you can set this option to NO if you already set -# GENERATE_TREEVIEW to YES. - -DISABLE_INDEX = NO - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to YES, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). -# Windows users are probably better off using the HTML help feature. -# Since the tree basically has the same information as the tab index you -# could consider to set DISABLE_INDEX to NO when enabling this option. - -GENERATE_TREEVIEW = NO - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values -# (range [0,1..20]) that doxygen will group on one line in the generated HTML -# documentation. Note that a value of 0 will completely suppress the enum -# values from appearing in the overview section. - -ENUM_VALUES_PER_LINE = 4 - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open -# links to external symbols imported via tag files in a separate window. - -EXT_LINKS_IN_WINDOW = NO - -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are -# not supported properly for IE 6.0, but are supported on all modern browsers. -# Note that when changing this option you need to delete any form_*.png files -# in the HTML output before the changes have effect. - -FORMULA_TRANSPARENT = YES - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax -# (see http://www.mathjax.org) which uses client side Javascript for the -# rendering instead of using prerendered bitmaps. Use this if you do not -# have LaTeX installed or if you want to formulas look prettier in the HTML -# output. When enabled you may also need to install MathJax separately and -# configure the path to it using the MATHJAX_RELPATH option. - -USE_MATHJAX = NO - -# When MathJax is enabled you can set the default output format to be used for -# the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and -# SVG. The default value is HTML-CSS, which is slower, but has the best -# compatibility. - -MATHJAX_FORMAT = HTML-CSS - -# When MathJax is enabled you need to specify the location relative to the -# HTML output directory using the MATHJAX_RELPATH option. The destination -# directory should contain the MathJax.js script. For instance, if the mathjax -# directory is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to -# the MathJax Content Delivery Network so you can quickly see the result without -# installing MathJax. However, it is strongly recommended to install a local -# copy of MathJax from http://www.mathjax.org before deployment. - -MATHJAX_RELPATH = http://www.mathjax.org/mathjax - -# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension -# names that should be enabled during MathJax rendering. - -MATHJAX_EXTENSIONS = - -# The MATHJAX_CODEFILE tag can be used to specify a file with javascript -# pieces of code that will be used on startup of the MathJax code. - -MATHJAX_CODEFILE = - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box -# for the HTML output. The underlying search engine uses javascript -# and DHTML and should work on any modern browser. Note that when using -# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets -# (GENERATE_DOCSET) there is already a search function so this one should -# typically be disabled. For large projects the javascript based search engine -# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. - -SEARCHENGINE = YES - -# When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a web server instead of a web client using Javascript. -# There are two flavours of web server based search depending on the -# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for -# searching and an index file used by the script. When EXTERNAL_SEARCH is -# enabled the indexing and searching needs to be provided by external tools. -# See the manual for details. - -SERVER_BASED_SEARCH = NO - -# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP -# script for searching. Instead the search results are written to an XML file -# which needs to be processed by an external indexer. Doxygen will invoke an -# external search engine pointed to by the SEARCHENGINE_URL option to obtain -# the search results. Doxygen ships with an example indexer (doxyindexer) and -# search engine (doxysearch.cgi) which are based on the open source search -# engine library Xapian. See the manual for configuration details. - -EXTERNAL_SEARCH = NO - -# The SEARCHENGINE_URL should point to a search engine hosted by a web server -# which will returned the search results when EXTERNAL_SEARCH is enabled. -# Doxygen ships with an example search engine (doxysearch) which is based on -# the open source search engine library Xapian. See the manual for configuration -# details. - -SEARCHENGINE_URL = - -# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed -# search data is written to a file for indexing by an external tool. With the -# SEARCHDATA_FILE tag the name of this file can be specified. - -SEARCHDATA_FILE = searchdata.xml - -# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the -# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is -# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple -# projects and redirect the results back to the right project. - -EXTERNAL_SEARCH_ID = - -# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen -# projects other than the one defined by this configuration file, but that are -# all added to the same external search index. Each project needs to have a -# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id -# of to a relative location where the documentation can be found. -# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ... - -EXTRA_SEARCH_MAPPINGS = - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = YES - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. -# Note that when enabling USE_PDFLATEX this option is only used for -# generating bitmaps for formulas in the HTML output, but not in the -# Makefile that is written to the output directory. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, letter, legal and -# executive. If left blank a4 will be used. - -PAPER_TYPE = a4 - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for -# the generated latex document. The footer should contain everything after -# the last chapter. If it is left blank doxygen will generate a -# standard footer. Notice: only use this tag if you know what you are doing! - -LATEX_FOOTER = - -# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images -# or other source files which should be copied to the LaTeX output directory. -# Note that the files will be copied as-is; there are no commands or markers -# available. - -LATEX_EXTRA_FILES = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -# If LATEX_SOURCE_CODE is set to YES then doxygen will include -# source code with syntax highlighting in the LaTeX output. -# Note that which sources are shown also depends on other settings -# such as SOURCE_BROWSER. - -LATEX_SOURCE_CODE = NO - -# The LATEX_BIB_STYLE tag can be used to specify the style to use for the -# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See -# http://en.wikipedia.org/wiki/BibTeX for more info. - -LATEX_BIB_STYLE = plain - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load style sheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = YES - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = NO - -#--------------------------------------------------------------------------- -# configuration options related to the DOCBOOK output -#--------------------------------------------------------------------------- - -# If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files -# that can be used to generate PDF. - -GENERATE_DOCBOOK = NO - -# The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in -# front of it. If left blank docbook will be used as the default path. - -DOCBOOK_OUTPUT = docbook - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = YES - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = YES - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# pointed to by INCLUDE_PATH will be searched when a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = MPC_HAVE_ROOT \ - MPC_HAVE_GADGET \ - MPC_HAVE_FFTW3F \ - "protected=private -" - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition that -# overrules the definition found in the source code. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all references to function-like macros -# that are alone on a line, have an all uppercase name, and do not end with a -# semicolon, because these will confuse the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. For each -# tag file the location of the external documentation should be added. The -# format of a tag file without this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths -# or URLs. Note that each tag file must have a unique name (where the name does -# NOT include the path). If a tag file is not located in the directory in which -# doxygen is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed -# in the related pages index. If set to NO, only the current project's -# pages will be listed. - -EXTERNAL_PAGES = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option also works with HAVE_DOT disabled, but it is recommended to -# install and use dot, since it yields more powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is -# allowed to run in parallel. When set to 0 (the default) doxygen will -# base this on the number of processors available in the system. You can set it -# explicitly to a value larger than 0 to get control over the balance -# between CPU load and processing speed. - -DOT_NUM_THREADS = 0 - -# By default doxygen will use the Helvetica font for all dot files that -# doxygen generates. When you want a differently looking font you can specify -# the font name using DOT_FONTNAME. You need to make sure dot is able to find -# the font, which can be done by putting it in a standard location or by setting -# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the -# directory containing the font. - -DOT_FONTNAME = Helvetica - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the Helvetica font. -# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to -# set the path where dot can find it. - -DOT_FONTPATH = - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If the UML_LOOK tag is enabled, the fields and methods are shown inside -# the class node. If there are many fields or methods and many nodes the -# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS -# threshold limits the number of items for each type to make the size more -# manageable. Set this to 0 for no limit. Note that the threshold may be -# exceeded by 50% before the limit is enforced. - -UML_LIMIT_NUM_FIELDS = 10 - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will generate a graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are svg, png, jpg, or gif. -# If left blank png will be used. If you choose svg you need to set -# HTML_FILE_EXTENSION to xhtml in order to make the SVG files -# visible in IE 9+ (other browsers do not have this requirement). - -DOT_IMAGE_FORMAT = png - -# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to -# enable generation of interactive SVG images that allow zooming and panning. -# Note that this requires a modern browser other than Internet Explorer. -# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you -# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files -# visible. Older versions of IE do not have SVG support. - -INTERACTIVE_SVG = NO - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the -# \mscfile command). - -MSCFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = YES - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in new file mode 100644 index 000000000..30f6f5706 --- /dev/null +++ b/doc/Doxyfile.in @@ -0,0 +1,2446 @@ +# Doxyfile 1.8.13 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "CRPropa 3" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Propagation of ultra-relativistic particles through galactic and extragalactic space" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = NO + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = ../include + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = YES + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = YES + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = NO + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = NO + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = NO + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= NO + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = NO + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = "@CMAKE_SOURCE_DIR@/include" "@CMAKE_SOURCE_DIR@/src" "@CMAKE_CURRENT_BINARY_DIR@/Mainpage.md" + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = Loki::* \ + ProgressBar* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = Loki::* \ + ProgressBar + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = "Mainpage.md" + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = NO + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse-libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /