diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ead196becdbc4c8094ecc786bd0cad1a0a725f82..7939deeeeaa9765d1ea510f7f0f52a972119e453 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -27,6 +27,7 @@ variables: allow_failure: true timeout: 30 minutes before_script: + - brew tap davidchall/hep - brew bundle --file=CI/Brewfile # install third-party dependencies, if needed - export PATH="/usr/local/opt/expat/bin:$PATH" # to make CMake use expat from Homebrew instead of the old one shipped with the system in /usr/lib - export LDFLAGS="-L/usr/local/opt/expat/lib" @@ -50,7 +51,7 @@ variables: .ubuntu-template-job-default: &ubuntu-job <<: *ubuntu-job-base before_script: - - apt-get update -qq && apt-get install -y -qq git wget unzip build-essential freeglut3-dev libboost-all-dev qtbase5-dev libqt5opengl5-dev mercurial libeigen3-dev libsqlite3-dev nlohmann-json3-dev libexpat1-dev libxerces-c-dev libhdf5-dev cmake + - apt-get update -qq && apt-get install -y -qq git wget unzip build-essential freeglut3-dev libboost-all-dev qtbase5-dev libqt5opengl5-dev mercurial libeigen3-dev libsqlite3-dev nlohmann-json3-dev libexpat1-dev libxerces-c-dev libhdf5-dev libhepmc3-dev cmake # .ubuntu-template-job-registry: &ubuntu-job-registry @@ -253,6 +254,14 @@ mac-gm-fullsimlight: CMAKE_ARGS: ${CMAKE_BASE_ARGS} CMAKE_CONFIG_FLAGS: -DGEOMODEL_BUILD_FULLSIMLIGHT=TRUE +mac-gm-atlasextras: + <<: *macos-job + <<: *geomodel-job + stage: step-C + variables: + CMAKE_ARGS: ${CMAKE_BASE_ARGS} + CMAKE_CONFIG_FLAGS: -DGEOMODEL_BUILD_ATLASEXTENSIONS=TRUE + ### UBUNTU BUILD JOBS ubu-coin: @@ -334,6 +343,15 @@ ubu-gm-fullsimlight: CMAKE_ARGS: ${CMAKE_BASE_ARGS} CMAKE_CONFIG_FLAGS: -DGEOMODEL_BUILD_FULLSIMLIGHT=TRUE +ubu-gm-atlasextras: + <<: *ubuntu-job + <<: *geomodel-job + stage: step-C + needs: ["ubu-geant4"] + variables: + CMAKE_ARGS: ${CMAKE_BASE_ARGS} + CMAKE_CONFIG_FLAGS: -DGEOMODEL_BUILD_ATLASEXTENSIONS=TRUE + #TODO: this does not work properly. Needs some work... # ubu-gm-fullsimlight-customxercesc-builtinjson: diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/CMakeLists.txt b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..dc42a307dfad2272e3f1fed980a1ab01227fd1ac --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/CMakeLists.txt @@ -0,0 +1,83 @@ +# Set up the project. +cmake_minimum_required( VERSION 3.1 ) + +set(CMAKE_CXX_STANDARD 17) + +project( "ATLASMagneticFieldMapPlugin" ) + + +#Set up the project. Check if we build it with GeoModel or individually +if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) + # I am built as a top-level project. + # Make the root module directory visible to CMake. + list( APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ) + # get global GeoModel version + #include( GeoModelATLAS-version ) + # set the project, with the version taken from the GeoModel parent project + project( "ATLASMagneticFieldMapPlugin" VERSION 1.0 LANGUAGES CXX ) + # Define color codes for CMake messages + include( cmake_colors_defs ) + # Use the GNU install directory names. + include( GNUInstallDirs ) + # Set a default build type + include( BuildType ) + # Set default build and C++ options + include( configure_cpp_options ) + # Print Build Info on screen + include( PrintBuildInfo ) + # Warn the users about what they are doing + message(STATUS "${BoldGreen}Building ${PROJECT_NAME} individually, as a top-level project.${ColourReset}") + # Set default build and C++ options + include( configure_cpp_options ) + set( CMAKE_FIND_FRAMEWORK "LAST" CACHE STRING + "Framework finding behaviour on macOS" ) + # GeoModel dependencies + find_package( GeoModelCore REQUIRED ) +else() + # I am called from other project with add_subdirectory(). + message( STATUS "Building ${PROJECT_NAME} as part of the root project.") + # Set the project + project( "ATLASMagneticFieldMapPlugin" VERSION 1.0 LANGUAGES CXX ) +endif() + + + +# Find the header and source files. +file( GLOB SOURCES src/*.cxx ) +file(GLOB HEADERS src/*.h) + +set(PROJECT_SOURCES ${SOURCES} ${HEADERS}) + +# Set up the library. +add_library(ATLASMagneticFieldMapPlugin SHARED ${SOURCES}) + +find_package (Eigen3 REQUIRED) +find_package(Geant4 REQUIRED) +#find_package(FullSimLight) + +message( STATUS "Found Geant4: ${Geant4_INCLUDE_DIR}") +#message("Geant4_USE_FILE: ${Geant4_USE_FILE}") # debug msg +include(${Geant4_USE_FILE}) + +# Use the GNU install directory names. +include( GNUInstallDirs ) + +target_include_directories( ATLASMagneticFieldMapPlugin PUBLIC ${CMAKE_SOURCE_DIR}/FullSimLight ) + + +target_link_libraries ( ATLASMagneticFieldMapPlugin PUBLIC ${CMAKE_DL_LIBS} ${Geant4_LIBRARIES} Eigen3::Eigen) + + +set_target_properties( ATLASMagneticFieldMapPlugin PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} ) + + + +install( TARGETS ATLASMagneticFieldMapPlugin + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT Runtime + NAMELINK_COMPONENT Development ) + + + diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/cmake/BuildType.cmake b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/cmake/BuildType.cmake new file mode 100644 index 0000000000000000000000000000000000000000..14a12a8ccc0c22511e31288d7ab3b4fea69fb561 --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/cmake/BuildType.cmake @@ -0,0 +1,28 @@ + +# Author: Marcus D. Hanwell +# Source: https://blog.kitware.com/cmake-and-the-default-build-type/ + +# Set a default build type if none was specified +set(default_build_type "Release") + +# TODO: at the moment, we want to build in Release mode by default, +# even if we build from a Git clone, because that is the default mode +# for our users to get the source code. +# But maybe we will want to change this behavior, later? +# if(EXISTS "${CMAKE_SOURCE_DIR}/.git") +# set(default_build_type "Debug") +# endif() + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + if( COLOR_DEFS ) + message(STATUS "${Blue}INFO: Setting build type to '${default_build_type}' as none was specified.${ColourReset}") + else() + message(STATUS "INFO: Setting build type to '${default_build_type}' as none was specified.") + endif() + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE + STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/cmake/PrintBuildInfo.cmake b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/cmake/PrintBuildInfo.cmake new file mode 100644 index 0000000000000000000000000000000000000000..862a34b45c7506c83a229d7ef71ff604d182acb6 --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/cmake/PrintBuildInfo.cmake @@ -0,0 +1,13 @@ +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + +if( COLOR_DEFS ) + message(STATUS "-----") + message(STATUS "${BoldYellow}Building with type: ${CMAKE_BUILD_TYPE}${ColourReset}") + message(STATUS "${BoldYellow}Using C++ standard: ${CMAKE_CXX_STANDARD}${ColourReset}") + message(STATUS "-----") +else() + message(STATUS "-----") + message(STATUS "Building with type: ${CMAKE_BUILD_TYPE}") + message(STATUS "Using C++ standard: ${CMAKE_CXX_STANDARD}") + message(STATUS "-----") +endif() diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/cmake/cmake_colors_defs.cmake b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/cmake/cmake_colors_defs.cmake new file mode 100644 index 0000000000000000000000000000000000000000..b6eea59ba9e72a50754ac0afb36d25cfcac59e09 --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/cmake/cmake_colors_defs.cmake @@ -0,0 +1,25 @@ + +# Copyright: "Fraser" (https://stackoverflow.com/users/2556117/fraser) +# CC BY-SA 3.0 +# Source: https://stackoverflow.com/a/19578320/320369 + +if(NOT WIN32) + set( COLOR_DEFS TRUE CACHE BOOL "Define color escape sequences to be used in CMake messages." ) + string(ASCII 27 Esc) + set(ColourReset "${Esc}[m") + set(ColourBold "${Esc}[1m") + set(Red "${Esc}[31m") + set(Green "${Esc}[32m") + set(Yellow "${Esc}[33m") + set(Blue "${Esc}[34m") + set(Magenta "${Esc}[35m") + set(Cyan "${Esc}[36m") + set(White "${Esc}[37m") + set(BoldRed "${Esc}[1;31m") + set(BoldGreen "${Esc}[1;32m") + set(BoldYellow "${Esc}[1;33m") + set(BoldBlue "${Esc}[1;34m") + set(BoldMagenta "${Esc}[1;35m") + set(BoldCyan "${Esc}[1;36m") + set(BoldWhite "${Esc}[1;37m") +endif() diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/cmake/configure_cpp_options.cmake b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/cmake/configure_cpp_options.cmake new file mode 100644 index 0000000000000000000000000000000000000000..9a6cc8a7902de8bd14d412f0ca4fc86a3bc116fc --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/cmake/configure_cpp_options.cmake @@ -0,0 +1,34 @@ + +# +# Set build options and C++ standards and options +# +# This file sets up +# +# CMAKE_BUILD_TYPE +# CMAKE_CXX_STANDARD +# CMAKE_CXX_EXTENSIONS +# CMAKE_CXX_STANDARD_REQUIRED +# +# The options can be overridden at configuration time by using, e.g.: +# `cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_STANDARD=14 ../GeoModelIO` +# on the command line. +# + +# Set default build options. +set( CMAKE_BUILD_TYPE "Release" CACHE STRING "CMake build mode to use" ) +set( CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard used for the build" ) +set( CMAKE_CXX_EXTENSIONS FALSE CACHE BOOL "(Dis)allow using GNU extensions" ) +set( CMAKE_CXX_STANDARD_REQUIRED TRUE CACHE BOOL + "Require the specified C++ standard for the build" ) + +# Setting CMAKE_CXX_FLAGS to avoid "deprecated" warnings +set(CMAKE_CXX_FLAGS "-Wno-deprecated-declarations" ) # very basic +#set(CMAKE_CXX_FLAGS "-Wall -Werror -pedantic-errors -Wno-deprecated-declarations" ) # good enough for a quick, better check +#set(CMAKE_CXX_FLAGS "-Wall -Wextra -Werror -pedantic-errors -Wno-deprecated-declarations" ) # better for a thorough check +#set(CMAKE_CXX_FLAGS "-Wall -Wextra -Werror -pedantic-errors" ) # better for an even more severe check +#set(CMAKE_CXX_FLAGS "-Weverything -Werror -pedantic-errors" ) # not recommended, it warns for really EVERYTHING! + + +# TODO: for Debug and with GCC, do we want to set the flags below by default? +# set( CMAKE_BUILD_TYPE DEBUG ) +# set(CMAKE_CXX_FLAGS "-fPIC -O0 -g -gdwarf-2" ) diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/ATLASMagneticFieldMapPlugin.cxx b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/ATLASMagneticFieldMapPlugin.cxx new file mode 100644 index 0000000000000000000000000000000000000000..911ff026683c03e5645fa1095a4ff2b893934e5f --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/ATLASMagneticFieldMapPlugin.cxx @@ -0,0 +1,91 @@ +#include <iostream> +#include "G4MagneticField.hh" +#include "FullSimLight/MagFieldPlugin.h" +#include "AtlasFieldSvc.h" +#include "IMagFieldSvc.h" + +class AtlasField : public G4MagneticField +{ + public: + + // Construct the field object from the IMagFieldSvc + AtlasField(MagField::IMagFieldSvc* m); + + // Implementation of G4 method to retrieve field value + void GetFieldValue(const double *point, double *field) const + { + m_magFieldSvc_AtlasField->getField(point, field); + } + + private: + + // Pointer to the magnetic field service. + // We use a raw pointer here to avoid ServiceHandle overhead. + MagField::IMagFieldSvc* m_magFieldSvc_AtlasField; +}; + + +AtlasField::AtlasField(MagField::IMagFieldSvc* mfield) + : m_magFieldSvc_AtlasField(mfield) +{ + std::cout<<"New instance of AtlasField, setting m_magFieldSvc_AtlasField: "<<m_magFieldSvc_AtlasField<<" to "<<mfield<<std::endl; + +} + + + + + +class ATLASMagneticFieldMapPlugin: public MagFieldPlugin + +{ + +public: + //Constructor + ATLASMagneticFieldMapPlugin(); + + //Destructor + ~ATLASMagneticFieldMapPlugin(); + +protected: + //Overriding virtual function + G4MagneticField* getField(std::string map_path); + +private: + MagField::IMagFieldSvc* m_magFieldSvc; +}; + +ATLASMagneticFieldMapPlugin::ATLASMagneticFieldMapPlugin() { + + std::cout << "HELLO from Atlas Magnetic Field Plugin" << std::endl; + + +} + +ATLASMagneticFieldMapPlugin::~ATLASMagneticFieldMapPlugin() { + +std::cout << "GOODBYE from Atlas Magnetic Field Plugin" << std::endl; +} + +G4MagneticField* ATLASMagneticFieldMapPlugin::getField(std::string map_path) +{ + + MagField::AtlasFieldSvc * atlasFieldSvs = new MagField::AtlasFieldSvc(map_path,true); + atlasFieldSvs->handle(); + m_magFieldSvc = atlasFieldSvs; + + + std::cout<<"AtlasFieldSvc::makeField with m_magFieldSvc "<<m_magFieldSvc<<std::endl; + return new AtlasField( &*m_magFieldSvc ); +} + + + + +extern "C" ATLASMagneticFieldMapPlugin* createATLASMagneticFieldMapPlugin() +{ + return new ATLASMagneticFieldMapPlugin; +} + + + diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/AtlasFieldSvc.cxx b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/AtlasFieldSvc.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e5b3c32363e7d8152f9d43829289b554c47ece6e --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/AtlasFieldSvc.cxx @@ -0,0 +1,1856 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/////////////////////////////////////////////////////////////////// +// AtlasFieldSvc.cxx, (c) ATLAS Detector software +/////////////////////////////////////////////////////////////////// + +#include <iostream> +#include <fstream> + +// ISF_Services include +#include "AtlasFieldSvc.h" + +// PathResolver +//#include "PathResolver/PathResolver.h" + +// StoreGate +//#include "StoreGate/StoreGateSvc.h" + +// Athena Pool +//#include "AthenaPoolUtilities/AthenaAttributeList.h" +//#include "AthenaPoolUtilities/CondAttrListCollection.h" + +// IncidentSvc +//#include "GaudiKernel/IIncidentSvc.h" + +// CLHEP +#include "CLHEP/Units/SystemOfUnits.h" +// Units +//#include "GeoModelKernel/Units.h" +//#define SYSTEM_OF_UNITS GeoModelKernelUnits // so we will get, e.g., 'GeoModelKernelUnits::cm' +// **** + +// ROOT +//#include "TFile.h" +//#include "TTree.h" + +#include "G4RootAnalysisReader.hh" + +/** Constructor **/ +MagField::AtlasFieldSvc::AtlasFieldSvc(bool isAscii) : + //base_class(name,svc), + //base_class(name), + m_fullMapAscii ("bmagatlas_09_fullAsym20400.data"), + m_isAscii (isAscii), + m_fullMapFilename("full_bfieldmap_7730_20400_14m_version5.root"), + m_soleMapFilename("solenoid_bfieldmap_7730_0_14m_version5.root"), + m_toroMapFilename("toroid_bfieldmap_0_20400_14m_version5.root"), + m_mapSoleCurrent(7730.), + m_mapToroCurrent(20400.), + m_soleMinCurrent(1.0), + m_toroMinCurrent(1.0), + //m_useDCS(false), + //m_coolCurrentsFolderName("/EXT/DCS/MAGNETS/SENSORDATA"), + //m_useMapsFromCOOL(true), + //m_coolMapsFolderName("/GLOBAL/BField/Maps"), + m_useSoleCurrent(7730.), + m_useToroCurrent(20400.), + m_lockMapCurrents(false), + //m_mapHandle(), + //m_currentHandle(), + m_zone(), + m_meshZR(nullptr), + m_edge(), + m_edgeLUT(), + m_invq(), + m_zoneLUT(), + m_zmin(0.), + m_zmax(0.), + m_nz(0), + m_rmax(0.), + m_nr(0), + m_nphi(0) + /* , + m_doManipulation(false), + m_manipulator("undefined") */ +{ + +// declareProperty("FullMapFile", m_fullMapFilename, "File storing the full magnetic field map"); +// declareProperty("SoleMapFile", m_soleMapFilename, "File storing the solenoid-only magnetic field map"); +// declareProperty("ToroMapFile", m_toroMapFilename, "File storing the toroid-only magnetic field map"); +// declareProperty("MapSoleCurrent", m_mapSoleCurrent, "Nominal solenoid current (A)"); +// declareProperty("MapToroCurrent", m_mapToroCurrent, "Nominal toroid current (A)"); +// declareProperty("SoleMinCurrent", m_soleMinCurrent, "Minimum solenoid current (A) for which solenoid is considered ON"); +// declareProperty("ToroMinCurrent", m_toroMinCurrent, "Minimum toroid current (A) for which toroid is considered ON"); +// declareProperty("UseDCS", m_useDCS, "Get magnet currents from DCS through COOL"); +// declareProperty("COOLCurrentsFolderName", m_coolCurrentsFolderName, "Name of the COOL folder containing magnet currents"); +// declareProperty("UseMapsFromCOOL", m_useMapsFromCOOL, "Get magnetic field map filenames from COOL"); +// declareProperty("COOLMapsFolderName", m_coolMapsFolderName, "Name of the COOL folder containing field maps"); +// declareProperty("UseSoleCurrent", m_useSoleCurrent, "Set actual solenoid current (A)"); +// declareProperty("UseToroCurrent", m_useToroCurrent, "Set actual toroid current (A)"); +// declareProperty("LockMapCurrents", m_lockMapCurrents, "Do not rescale currents (use the map values)"); + /* declareProperty("DoManipulation", m_doManipulation, "Apply field manipulation"); + declareProperty("ManipulatorTool", m_manipulator, "Tool handle for field manipulation"); */ +} + +/** Constructor **/ +MagField::AtlasFieldSvc::AtlasFieldSvc( const std::string& name, bool isAscii, bool solenoidOFF, bool toroidsOFF): + m_isAscii(isAscii), + m_mapSoleCurrent(7730.), + m_mapToroCurrent(20400.), + m_soleMinCurrent(1.0), + m_toroMinCurrent(1.0), + m_useSoleCurrent(7730.), + m_useToroCurrent(20400.), + m_lockMapCurrents(false), + m_zone(), + m_meshZR(nullptr), + m_edge(), + m_edgeLUT(), + m_invq(), + m_zoneLUT(), + m_zmin(0.), + m_zmax(0.), + m_nz(0), + m_rmax(0.), + m_nr(0), + m_nphi(0) + { + if (m_isAscii) { + m_fullMapAscii = name; + std::cout<<"Magnetic field map file is ascii, will open "<<name<<std::endl; + } + else {m_fullMapFilename = name; + std::cout<<"File is root, will open "<<name<<std::endl; + } + if(solenoidOFF) { + setSolenoidCurrent(0.); + m_toroMapFilename = name; + + } + if(toroidsOFF) { + setToroidsCurrent (0.); + m_soleMapFilename = name; + } + } + +MagField::AtlasFieldSvc::~AtlasFieldSvc() +{ + delete m_meshZR; +} + +/** framework methods */ +bool MagField::AtlasFieldSvc::initialize() +{ + std::cout<< "initialize() ..." << std::endl; + +// // determine map location from COOL, if available +// if ( m_useMapsFromCOOL ) { +// // Register callback +// StoreGateSvc* detStore; +// if ( service( "DetectorStore", detStore ).isFailure() ) { +// //ATH_MSG_FATAL( "Could not get detector store" ); +// return false; +// } +// std::string folder( m_coolMapsFolderName ); +// std::cout<<"maps will be chosen reading COOL folder " << folder << std::endl; +// if ( detStore->regFcn( &MagField::AtlasFieldSvc::updateMapFilenames, this, +// m_mapHandle, folder ).isFailure() ) { +// //ATH_MSG_FATAL( "Could not book callback for " << folder ); +// return false; +// } +// } + + // are we going to get the magnet currents from DCS? +// if ( m_useDCS ) { +// // Register callback +// StoreGateSvc* detStore; +// if ( service( "DetectorStore", detStore ).isFailure() ) { +// //ATH_MSG_FATAL( "Could not get detector store" ); +// return false; +// } +// std::string folder( m_coolCurrentsFolderName ); +// std::cout<<"magnet currents will be read from COOL folder " << folder<< std::endl; +// if ( detStore->regFcn( &MagField::AtlasFieldSvc::updateCurrent, this, +// m_currentHandle, folder ).isFailure() ) { +// //ATH_MSG_FATAL( "Could not book callback for " << folder ); +// return false; +// } +// std::cout<< "Booked callback for " << folder << std::endl; +// // actual initalization has to wait for the fist callback +// } else { +// std::cout<< "Currents are set-up by jobOptions - delaying map initialization until BeginRun incident happens" << std::endl; +// +// ServiceHandle<IIncidentSvc> incidentSvc("IncidentSvc", name()); +// if (incidentSvc.retrieve().isFailure()) { +// //ATH_MSG_FATAL( "Unable to retrieve the IncidentSvc" ); +// return false; +// } else { +// incidentSvc->addListener( this, IncidentType::BeginRun ); +// std::cout<< "Added listener to BeginRun incident" << std::endl; +// } + //} + + // retrieve thread-local storage + AtlasFieldSvcTLS &tls = getAtlasFieldSvcTLS(); + + // clear the map for zero field + clearMap(tls); + setSolenoidCurrent(0.0); + setToroidsCurrent(0.0); + + /* // retrieve the manipulator tool + if (m_doManipulation) { + std::cout<< "field will be manipulated, retrieving tool" << std::endl; + if (m_manipulator.retrieve().isFailure()) { + //ATH_MSG_FATAL( "unable to retrieve manipulation tool" ); + } else { + std::cout<< "manipulation tool retrieved" << std::endl; + getFieldActual = &MagField::AtlasFieldSvc::getFieldManipulated; + } + } else { + std::cout<< "no manipulation set up" << std::endl; + getFieldActual = &MagField::AtlasFieldSvc::getFieldStandard; + } */ + + std::cout<< "initialize() successful" << std::endl; + return true; +} + +void MagField::AtlasFieldSvc::handle() +{ + // get thread-local storage + AtlasFieldSvcTLS &tls = getAtlasFieldSvcTLS(); + if (! importCurrents(tls)) + { + std::cout<< "Failure in setting of currents" <<std::endl; + + } +} + +bool MagField::AtlasFieldSvc::importCurrents(AtlasFieldSvcTLS &tls) +{ + std::cout<< "\nImportCurrents() ..." << std::endl; + + // take the current values from JobOptions + double solcur(m_useSoleCurrent); + double torcur(m_useToroCurrent); + if ( solcur < m_soleMinCurrent ) { + solcur = 0.0; + std::cout<< "Solenoid is off." << std::endl; + } + if ( torcur < m_toroMinCurrent) { + torcur = 0.0; + std::cout<< "Toroids are off." << std::endl; + } + setSolenoidCurrent(solcur); + setToroidsCurrent(torcur); + // read the map file + if ( !initializeMap(tls)) { + //ATH_MSG_FATAL( "Failed to initialize field map" ); + std::cout<< "FATAL! Failed to initialize field map" << std::endl; + return false; + } + + std::cout<< "Currents imported and map initialized successfully!" << std::endl; + return true; +} + +/** callback for possible magnet current update **/ +//bool MagField::AtlasFieldSvc::updateCurrent(IOVSVC_CALLBACK_ARGS) +//{ +// // get magnet currents from DCS +// double solcur(0.); +// double torcur(0.); +// bool gotsol(false); +// bool gottor(false); +// +// // due to inconsistencies between CONDBR2 and OFLP200/COMP200 (the former includes channel names +// // in the /EXT/DCS/MAGNETS/SENSORDATA folder, the latter don't), we try to read currents in +// // both ways +// bool hasChanNames(false); +// +// std::cout<< "Attempt 1 at reading currents from DCS (using channel name)" << std::endl; +// for ( CondAttrListCollection::const_iterator itr = m_currentHandle->begin(); +// itr != m_currentHandle->end(); ++itr ) { +// +// std::string name = m_currentHandle->chanName(itr->first); +// std::cout<< "Trying to read from DCS: [channel name, index, value] " << name << " , " << itr->first << " , " << itr->second["value"].data<float>() << std::endl; +// +// if (name.compare("") != 0) { +// hasChanNames = true; +// } +// +// if ( name.compare("CentralSol_Current") == 0 ) { +// // channel 1 is solenoid current +// solcur = itr->second["value"].data<float>(); +// gotsol = true; +// } else if ( name.compare("Toroids_Current") == 0 ) { +// // channel 3 is toroid current +// torcur = itr->second["value"].data<float>(); +// gottor = true; +// } +// } +// if ( !hasChanNames ) { +// std::cout<< "Attempt 2 at reading currents from DCS (using channel index)" << std::endl; +// // in no channel is named, try again using channel index instead +// for ( CondAttrListCollection::const_iterator itr = m_currentHandle->begin(); +// itr != m_currentHandle->end(); ++itr ) { +// +// if ( itr->first == 1 ) { +// // channel 1 is solenoid current +// solcur = itr->second["value"].data<float>(); +// gotsol = true; +// } else if ( itr->first == 3 ) { +// // channel 3 is toroid current +// torcur = itr->second["value"].data<float>(); +// gottor = true; +// } +// } +// } +// +// if ( !gotsol || !gottor ) { +// //if ( !gotsol ) ATH_MSG_ERROR( "Missing solenoid current in DCS information" ); +// //if ( !gottor ) ATH_MSG_ERROR( "Missing toroid current in DCS information" ); +// return false; +// } +// std::cout<< "Currents read from DCS: solenoid " << solcur << " toroid " << torcur << std::endl; +// // round to zero if close to zero +// if ( solcur < m_soleMinCurrent) { +// solcur = 0.0; +// std::cout<< "Solenoid is off" << std::endl; +// } +// if ( torcur < m_toroMinCurrent) { +// torcur = 0.0; +// std::cout<< "Toroids are off" << std::endl; +// } +// // did solenoid/toroid change status between on and off? +// bool solWasOn( solenoidOn() ); +// bool torWasOn( toroidsOn() ); +// setSolenoidCurrent( solcur ); +// setToroidsCurrent( torcur ); +// if ( solenoidOn() != solWasOn || toroidsOn() != torWasOn ) { +// // get thread-local storage +// AtlasFieldSvcTLS &tls = getAtlasFieldSvcTLS(); +// +// // map has changed. re-initialize the map +// if ( initializeMap(tls).isFailure() ) { +// //ATH_MSG_ERROR( "Failed to re-initialize field map" ); +// return false; +// } +// } else { +// // map is still valid. just scale the currents +// if (!m_lockMapCurrents) +// scaleField(); +// else +// std::cout<< "Currents are NOT scaled - using map values sole=" << m_mapSoleCurrent << " toro=" << m_mapToroCurrent << std::endl; +// } +// +// return true; +//} +// +///** callback for possible field map filenames update **/ +//bool MagField::AtlasFieldSvc::updateMapFilenames(IOVSVC_CALLBACK_ARGS) +//{ +// std::cout<< "reading magnetic field map filenames from COOL" << std::endl; +// +// std::string fullMapFilename(""); +// std::string soleMapFilename(""); +// std::string toroMapFilename(""); +// +// for (CondAttrListCollection::const_iterator itr = m_mapHandle->begin(); itr != m_mapHandle->end(); ++itr) { +// const coral::AttributeList &attr = itr->second; +// const std::string &mapType = attr["FieldType"].data<std::string>(); +// const std::string &mapFile = attr["MapFileName"].data<std::string>(); +// const float soleCur = attr["SolenoidCurrent"].data<float>(); +// const float toroCur = attr["ToroidCurrent"].data<float>(); +// +// std::cout<<"found map of type " << mapType << " with soleCur=" << soleCur << " toroCur=" << toroCur << " (path " << mapFile << ")")<< std::endl; +// +// // first 5 letters are reserved (like "file:") +// const std::string mapFile_decoded = mapFile.substr(5); +// if (mapType == "GlobalMap") { +// fullMapFilename = mapFile_decoded; +// m_mapSoleCurrent = soleCur; +// m_mapToroCurrent = toroCur; +// } else if (mapType == "SolenoidMap") { +// soleMapFilename = mapFile_decoded; +// } else if (mapType == "ToroidMap") { +// toroMapFilename = mapFile_decoded; +// } +// // note: the idea is that the folder contains exactly three maps +// // (if it contains more than 3 maps, then this logic doesn't work perfectly) +// // nominal currents are read from the global map +// } +// +// if (fullMapFilename == "" || soleMapFilename == "" || toroMapFilename == "") { +// //ATH_MSG_ERROR("unexpected content in COOL field map folder"); +// return false; +// } +// +// // check if maps really changed +// if (fullMapFilename != m_fullMapFilename || soleMapFilename != m_soleMapFilename || toroMapFilename != m_toroMapFilename) { +// std::cout<< "map set is new! reinitializing map"<< std::endl; +// m_fullMapFilename = fullMapFilename; +// m_soleMapFilename = soleMapFilename; +// m_toroMapFilename = toroMapFilename; +// +// // retrieve the thread-local storage +// AtlasFieldSvcTLS &tls = getAtlasFieldSvcTLS(); +// +// // trigger map reinitialization +// if ( initializeMap(tls).isFailure() ) { +// //ATH_MSG_ERROR( "failed to re-initialize field map" ); +// return false; +// } +// } else { +// std::cout<< "no need to update map set"<< std::endl; +// } +// +// return true; +//} + +// +// read and initialize map +// +bool MagField::AtlasFieldSvc::initializeMap(AtlasFieldSvcTLS &tls) +{ + std::cout<< "Initializing the field map (solenoidCurrent=" << getSolenoidCurrent() << " toroidCurrent=" << getToroidsCurrent() << ")" << std::endl; + // empty the current map first + clearMap(tls); + + // determine the map to load + std::string mapFile(""); + //ALL the Magnets are ON + if ( solenoidOn() && toroidsOn() ) { + if(m_isAscii) mapFile = m_fullMapAscii; + else mapFile = m_fullMapFilename; + std::cout<<"mapFile::: "<<mapFile<<std::endl; + } else if ( solenoidOn() ) { + mapFile = m_soleMapFilename; + } else if ( toroidsOn() ) { + mapFile = m_toroMapFilename; + } else { + // all magnets OFF. no need to read map + return true; + } + // find the path to the map file + //std::string resolvedMapFile = PathResolver::find_file( mapFile.c_str(), "DATAPATH" ); + std::string resolvedMapFile = mapFile.c_str(); + if ( resolvedMapFile == "" ) { + std::cout<<"Field map file " << mapFile << " not found" <<std::endl; + return false; + } + + if ( strstr(mapFile.c_str(), ".root") != 0 ) + { + // read the ROOT map file + //if ( !readMap( resolvedMapFile.c_str() ) ) + if ( !readMapRoot( resolvedMapFile ) ) + { + std::cout<<"\nERROR! Magnetic field map cannot be read!"<<std::endl; + std::cout<<"Alternatively, you can set a constant Magnetic Field through the macro.g4 file."<<std::endl; + exit (-1); + return false; + } + + }else if ( strstr(mapFile.c_str(), ".data") != 0 ) + { + std::filebuf fb; + if (fb.open (mapFile,std::ios::in)) + { + std::istream is(&fb); + std::cout<<"Reading field map from " << mapFile <<std::endl; + readMap(is); + fb.close(); + } + else + { + std::cout<<"\nERROR! Magnetic field map file cannot be opened. Please make sure the file is available."<<std::endl; + std::cout<<"Alternatively, you can set a constant Magnetic Field through the macro.g4 file."<<std::endl; + + exit (-1); + } + }else + { + std::cout<<"ERROR: Sorry, Magnetic field map file extensions supported are .root or .data files!"; + std::cout<<"Alternatively, you can set a constant Magnetic Field through the macro.g4 file."<<std::endl; + exit(-1); + + } + std::cout<< "Initialized the field map from " << resolvedMapFile << std::endl; + // scale magnet current as needed + if (!m_lockMapCurrents) + scaleField(); + else + std::cout<< "Currents are NOT scaled - using map values sole=" << m_mapSoleCurrent << " toro=" << m_mapToroCurrent << std::endl; + + return true; +} + +void MagField::AtlasFieldSvc::scaleField() +{ + BFieldZone *solezone(0); + // + if ( solenoidOn() ) { + solezone = findZoneSlow( 0.0, 0.0, 0.0 ); + if ( m_mapSoleCurrent > 0.0 && + std::abs( getSolenoidCurrent()/m_mapSoleCurrent - 1.0 ) > 0.001 ) { + // scale the field in the solenoid zone + double factor = getSolenoidCurrent()/m_mapSoleCurrent; + solezone->scaleField( factor ); + // remake the fast map + buildZR(); + std::cout<< "Scaled the solenoid field by a factor " << factor << std::endl; + } + } + // + if ( toroidsOn() ) + { + if ( m_mapToroCurrent > 0.0 && + std::abs( getToroidsCurrent()/m_mapToroCurrent - 1.0 ) > 0.001 ) { + // scale the field in all zones except for the solenoid zone + double factor = getToroidsCurrent()/m_mapToroCurrent; + for ( unsigned i = 0; i < m_zone.size(); i++ ) { + if ( &(m_zone[i]) != solezone ) { + m_zone[i].scaleField( factor ); + } + } + std::cout<< "Scaled the toroid field by a factor " << factor << std::endl; + } + } +} + +/** framework methods */ +bool MagField::AtlasFieldSvc::finalize() +{ + // finalization code would go here + // + std::cout<< "Finalize() AtlasFieldSvc successful!" << std::endl; + return true; +} + +/* void MagField::AtlasFieldSvc::getFieldStandard(const double *xyz, double *bxyz, double *deriv) */ +void MagField::AtlasFieldSvc::getField(const double *xyz, double *bxyz, double *deriv) const +{ + + const double &x(xyz[0]); + const double &y(xyz[1]); + const double &z(xyz[2]); + double r = std::sqrt(x * x + y * y); + double phi = std::atan2(y, x); + + // retrieve the thread-local storage + AtlasFieldSvcTLS &tls = getAtlasFieldSvcTLS(); + BFieldCache &cache = tls.cache; + + // test if the TLS was initialized and the cache is valid + if ( !tls.isInitialized || !cache.inside(z, r, phi) ) { + // cache is invalid -> refresh cache + if (!fillFieldCache(z, r, phi, tls)) { + + // caching failed -> outside the valid map volume + // return default field (0.1 gauss) + const double defaultB(0.1*CLHEP::gauss); + //std::cout<<"Cache failed, return default field !"<<std::sqrt(3*defaultB*defaultB)/CLHEP::tesla<<std::endl; + bxyz[0] = bxyz[1] = bxyz[2] = defaultB; + // return zero gradient if requested + if ( deriv ) { + for ( int i = 0; i < 9; i++ ) { + deriv[i] = 0.; + } + } + return; + } + } + // do interpolation + cache.getB(xyz, r, phi, bxyz, deriv); + + // add biot savart component + if (tls.cond) { + const size_t condSize = tls.cond->size(); + for (size_t i = 0; i < condSize; i++) { + (*tls.cond)[i].addBiotSavart(xyz, bxyz, deriv); + } + } +} + +/* +void MagField::AtlasFieldSvc::getFieldManipulated(const double *xyz, double *bxyz, double *deriv) +{ + // this operation involves three steps: + // - first we move the point at which the field is evaluated + // ex1: solenoid translation by vector +a => xyz -= a + // ex2: solenoid rotation R by angle +phi => rotate xyz by -phi (inverse rotation R_inv) + // - then, we evaluate B in this new point + // ex1: B(-a) + // ex2: B(R_inv(xyz)) + // - then, we change the field + // ex1: identity transformation + // ex2: rotate the field properly + + // step 1 + double xyz_new[3]; + m_manipulator->modifyPosition(xyz, xyz_new); + + // step 2 + getFieldStandard(xyz_new, bxyz, deriv); + + // step 3 + m_manipulator->modifyField(bxyz, deriv); +} + +void MagField::AtlasFieldSvc::getField(const double *xyz, double *bxyz, double *deriv) { + (this->*this->getFieldActual)(xyz, bxyz, deriv); +} +*/ + +void MagField::AtlasFieldSvc::getFieldZR(const double *xyz, double *bxyz, double *deriv) const +{ + + const double &x(xyz[0]); + const double &y(xyz[1]); + const double &z(xyz[2]); + double r = sqrt(x * x + y * y); + + // get thread-local storage + AtlasFieldSvcTLS &tls = getAtlasFieldSvcTLS(); + BFieldCacheZR &cacheZR = tls.cacheZR; + + // test if the TLS was initialized and the cache is valid + if ( !tls.isInitialized || !cacheZR.inside(z, r) ) { + // cache is invalid -> refresh cache + if (!fillFieldCacheZR(z, r, tls)) { + // caching failed -> outside the valid z-r map volume + // call the full version of getField() + getField(xyz, bxyz, deriv); + return; + } + } + + // do interpolation + cacheZR.getB(xyz, r, bxyz, deriv); +} + +// +// Clear the map. +// Subsequent call should return zero magnetic field. +// +void MagField::AtlasFieldSvc::clearMap(AtlasFieldSvcTLS &tls) +{ + tls.cache.invalidate(); + tls.cacheZR.invalidate(); + + tls.cond = nullptr; + // Next lines clear m_zone, m_edge[3], m_edgeLUT[3], and m_zoneLUT and deallocate their memory. + std::vector<BFieldZone>().swap(m_zone); + for ( int i = 0; i < 3; i++ ) { + std::vector<double>().swap(m_edge[i]); + std::vector<int>().swap(m_edgeLUT[i]); + } + std::vector<const BFieldZone*>().swap(m_zoneLUT); + // Next lines ensure findZone() will fail + m_zmin = 0.0; + m_zmax = -1.0; + m_rmax = -1.0; + m_nz = m_nr = m_nphi = 0; + delete m_meshZR; + m_meshZR = nullptr; +} + +// +// Read the solenoid map from file. +// The filename must end with ".root". +// +bool MagField::AtlasFieldSvc::readMap( const char* filename ) +{ + if ( strstr(filename, ".root") != 0 ) { + std::cout<<"Sorry, ROOT map is not supported at the moment!"<<std::endl; + return false; + } + std::cout<<"This method should not be called, call readMapRoot!"<<std::endl; + return false; + +// std::cout<<"root: "<<filename<<std::endl; +// if ( strstr(filename, ".root") == 0 ) { +// std::cout<<"input file name '" << filename << "' does not end with .root"<< std::endl; +// //ATH_MSG_ERROR("input file name '" << filename << "' does not end with .root"); +// return false; +// } +// +// TFile* rootfile = new TFile(filename, "OLD"); +// if ( ! rootfile ) { +// std::cout<<"failed to open " << filename<< std::endl; +// //ATH_MSG_ERROR("failed to open " << filename); +// return false; +// } +// std::cout<<"reading the map from " << filename<< std::endl; +// if ( !readMap(rootfile) ) { +// std::cout<<"something went wrong while trying to read the ROOT field map file"<<std::endl; +// //ATH_MSG_ERROR("something went wrong while trying to read the ROOT field map file"); +// return false; +// } +// +// rootfile->Close(); +// delete rootfile; +// return true; +} + +// +// read an ASCII field map from istream +// convert units m -> mm, and T -> kT +// +bool MagField::AtlasFieldSvc::readMap( std::istream& input ) +{ + std::cout<<"Reading the map"<<std::endl; + const std::string myname("readMap()"); + // first line contains version, date, time + std::string word; + int version; + int date; + int time; + input >> word >> version; + if ( word != "FORMAT-VERSION" ) { + std::cout<<"ERROR: "<< myname << ": found '" << word << "' instead of 'FORMAT-VERSION'"<<std::endl; + return false; + } + if ( version < 5 || version > 6) { + std::cout<<"ERROR: "<< myname << ": version number is " << version << " instead of 5 or 6"<<std::endl; + return false; + } + input >> word >> date; + if ( word != "DATE" ) { + std::cout<<"ERROR: "<< myname << ": found '" << word << "' instead of 'DATE'" <<std::endl; + return false; + } + input >> word >> time; + if ( word != "TIME" ) { + std::cout<<"ERROR: "<< myname << ": found '" << word << "' instead of 'TIME'" <<std::endl; + return false; + } + + // read and skip header cards + int nheader; + input >> word >> nheader; + if ( word != "HEADERS" ) { + std::cout<<"ERROR: "<< myname << ": found '" << word << "' instead of 'HEADERS'" <<std::endl; + return false; + } + std::string restofline; + getline( input, restofline ); + for ( int i = 0; i < nheader; i++ ) { + std::string header; + getline( input, header ); + } + + // read zone definitions + int nzone; + input >> word >> nzone; + if ( word != "ZONES" ) { + std::cout<<"ERROR: "<< myname << ": found '" << word << "' instead of 'ZONES'" <<std::endl; + return false; + } + std::vector<int> jz(nzone), nz(nzone); + std::vector<int> jr(nzone), nr(nzone); + std::vector<int> jphi(nzone), nphi(nzone); + std::vector<int> jbs(nzone), nbs(nzone); + std::vector<int> jcoil(nzone), ncoil(nzone); + std::vector<int> jfield(nzone), nfield(nzone); + std::vector<int> jaux(nzone), naux(nzone); + + + for ( int i = 0; i < nzone; i++ ) + { + int id; + int nrep, map; // unused + double z1, z2, r1, r2, phi1, phi2; + int nzrphi0; // unused + double tol; // unused + int mzn, mxsym, mrefl, mback; // unused + double qz, qr, qphi; // unused + double bscale; + input >> id >> nrep; + if ( version == 6 ) input >> map; + input >> z1 >> z2 >> nz[i] + >> r1 >> r2 >> nr[i] + >> phi1 >> phi2 >> nphi[i] + >> nzrphi0 >> tol + >> jbs[i] >> nbs[i] + >> jcoil[i] >> ncoil[i] + >> jz[i] >> jr[i] >> jphi[i] + >> jfield[i] >> nfield[i] + >> mzn; + if ( version == 6 ) input >> mxsym; + input >> mrefl >> mback + >> jaux[i] >> naux[i] + >> qz >> qr >> qphi >> bscale; + if ( id >= 0 ) { // remove dummy zone + z1 *= CLHEP::meter; + z2 *= CLHEP::meter; + r1 *= CLHEP::meter; + r2 *= CLHEP::meter; + phi1 *= CLHEP::degree; + phi2 *= CLHEP::degree; + bscale *= CLHEP::tesla; + BFieldZone zone( id, z1, z2, r1, r2, phi1, phi2, bscale ); + m_zone.push_back(zone); + } + } + + // read Biot-Savart data + int nbiot; + input >> word >> nbiot; + if ( word != "BIOT" ) { + std::cout<<"ERROR: "<< myname << ": found '" << word << "' instead of 'BIOT'" <<std::endl; + return false; + } + std::vector<BFieldCond> bslist; + for ( int i = 0; i < nbiot; i++ ) { + char dummy; // unused + char cfinite; + double xyz1[3], xyz2[3]; + double phirot; // unused + double curr; + input >> dummy >> cfinite + >> xyz1[0] >> xyz1[1] >> xyz1[2] + >> xyz2[0] >> xyz2[1] >> xyz2[2] + >> phirot >> curr; + bool finite = ( cfinite == 'T' ); + for ( int j = 0; j < 3; j++ ) { + xyz1[j] *= CLHEP::meter; + if ( finite ) xyz2[j] *= CLHEP::meter; + } + BFieldCond bs( finite, xyz1, xyz2, curr ); + bslist.push_back(bs); + } + // attach them to the zones + for ( unsigned i = 0; i < m_zone.size(); i++ ) { + // copy the range that belongs to this zone + for ( int j = 0; j < nbs[i]; j++ ) { + // Fortran -> C conversion requires "-1" + m_zone[i].appendCond( bslist[jbs[i]+j-1] ); + } + } + + // read and skip coil data + int nc; + input >> word >> nc; + if ( word != "COIL" ) { + std::cout<<"ERROR: "<< myname << ": found '" << word << "' instead of 'COIL'" <<std::endl; + return false; + } + getline( input, restofline ); + for ( int i = 0; i < nc; i++ ) { + std::string coildata; + getline( input, coildata ); + } + + // read and skip auxiliary array = list of subzones + int nauxarr; + input >> word >> nauxarr; + if ( word != "AUXARR" ) { + std::cout<<"ERROR: "<< myname << ": found '" << word << "' instead of 'AUXARR'" <<std::endl; + return false; + } + if ( version == 6 ) input >> word; // skip 'T' + for ( int i = 0; i < nauxarr; i++ ) { + int aux; + input >> aux; + } + + // read mesh definition + int nmesh; + input >> word >> nmesh; + if ( word != "MESH" ) { + std::cout<<"ERROR: "<< myname << ": found '" << word << "' instead of 'MESH'" <<std::endl; + return false; + } + std::vector<double> meshlist; + for ( int i = 0; i < nmesh; i++ ) { + double mesh; + input >> mesh; + meshlist.push_back(mesh); + } + // attach them to the zones + for ( unsigned i = 0; i < m_zone.size(); i++ ) { + m_zone[i].reserve( nz[i], nr[i], nphi[i] ); + for ( int j = 0; j < nz[i]; j++ ) { + m_zone[i].appendMesh( 0, meshlist[jz[i]+j-1]*CLHEP::meter ); + } + for ( int j = 0; j < nr[i]; j++ ) { + m_zone[i].appendMesh( 1, meshlist[jr[i]+j-1]*CLHEP::meter ); + } + for ( int j = 0; j < nphi[i]; j++ ) { + m_zone[i].appendMesh( 2, meshlist[jphi[i]+j-1] ); + } + } + + // read field values + int nf, nzlist; + std::string ftype, bytype; + input >> word >> nf >> nzlist >> ftype >> bytype; + if ( word != "FIELD" ) { + std::cout<<"ERROR: "<< myname << ": found '" << word << "' instead of 'FIELD'" <<std::endl; + return false; + } + if ( ftype != "I2PACK" ) { + std::cout<<"ERROR: "<< myname << ": found '" << ftype << "' instead of 'I2PACK'" <<std::endl; + return false; + } + if ( bytype != "FBYTE" ) { + std::cout<<"ERROR: "<< myname << ": found '" << bytype << "' instead of 'FBYTE'" <<std::endl; + return false; + } + // read zone by zone + for ( int i = 0; i < nzlist; i++ ) { + int izone, idzone, nfzone; + input >> izone >> idzone >> nfzone; + izone--; // fortran -> C++ + if ( idzone != m_zone[izone].id() ) { + std::cout<<"ERROR: "<< myname << ": zone id " << idzone << " != " << m_zone[izone].id() <<std::endl; + //return StatusCode(2); + return true; // TO DO - it shoudl be recoverable - handle ! enum class ErrorCode : code_t { FAILURE = 0, SUCCESS = 1, RECOVERABLE = 2 }; + } + + std::vector<int> data[3]; + + // for field data in 2 bytes + for ( int j = 0; j < 3; j++ ) { // repeat z, r, phi + int ierr = read_packed_data( input, data[j] ); + //if ( ierr != 0 ) return StatusCode(ierr); + if ( ierr != 0 ) return true; // TODO it could be 2 .. to handle! enum class ErrorCode : code_t { FAILURE = 0, SUCCESS = 1, RECOVERABLE = 2 }; + for ( int k = 0; k < nfzone; k++ ) { + // recover sign + data[j][k] = ( data[j][k]%2==0 ) ? data[j][k]/2 : -(data[j][k]+1)/2; + // second-order diff + if ( k >= 2 ) data[j][k] += 2*data[j][k-1] - data[j][k-2]; + } + } + // store + for ( int k = 0; k < nfzone; k++ ) { + BFieldVector<short> B( data[0][k], data[1][k], data[2][k] ); + m_zone[izone].appendField( B ); + } + + // skip fbyte + char c; + while ( input.good() ) { + input >> c; + if ( input.eof() || c == '}' ) break; + } + } + + // build the LUTs and ZR zone + buildLUT(); + buildZR(); + + return true; +} + +// +// write the map to a ROOT file +// +//void MagField::AtlasFieldSvc::writeMap( std::string filename ) const +//{ +// +// TFile* rootfile = new TFile(filename.c_str(), "RECREATE"); +// //if ( rootfile == 0 ) return; // no file +// //if ( rootfile->cd() == false ) return; // could not make it current directory +// // define the tree +// TTree* tree = new TTree( "BFieldMap", "BFieldMap version 5" ); +// TTree* tmax = new TTree( "BFieldMapSize", "Buffer size information" ); +// int id; +// double zmin, zmax, rmin, rmax, phimin, phimax; +// double bscale; +// int ncond; +// //bool *finite; +// int *finite; +// double *p1x, *p1y, *p1z, *p2x, *p2y, *p2z; +// double *curr; +// int nmeshz, nmeshr, nmeshphi; +// double *meshz, *meshr, *meshphi; +// int nfield; +// double *fieldz, *fieldr, *fieldphi; +// +// // prepare arrays - need to know the maximum sizes +// unsigned maxcond(0), maxmeshz(0), maxmeshr(0), maxmeshphi(0), maxfield(0); +// for ( unsigned i = 0; i < m_zone.size(); i++ ) { +// maxcond = std::max( maxcond, m_zone[i].ncond() ); +// maxmeshz = std::max( maxmeshz, m_zone[i].nmesh(0) ); +// maxmeshr = std::max( maxmeshr, m_zone[i].nmesh(1) ); +// maxmeshphi = std::max( maxmeshphi, m_zone[i].nmesh(2) ); +// maxfield = std::max( maxfield, m_zone[i].nfield() ); +// } +// // store the maximum sizes +// tmax->Branch( "maxcond", &maxcond, "maxcond/i"); +// tmax->Branch( "maxmeshz", &maxmeshz, "maxmeshz/i"); +// tmax->Branch( "maxmeshr", &maxmeshr, "maxmeshr/i"); +// tmax->Branch( "maxmeshphi", &maxmeshphi, "maxmeshphi/i"); +// tmax->Branch( "maxfield", &maxfield, "maxfield/i"); +// tmax->Fill(); +// // prepare buffers +// //finite = new bool[maxcond]; +// finite = new int[maxcond]; +// p1x = new double[maxcond]; +// p1y = new double[maxcond]; +// p1z = new double[maxcond]; +// p2x = new double[maxcond]; +// p2y = new double[maxcond]; +// p2z = new double[maxcond]; +// curr = new double[maxcond]; +// meshz = new double[maxmeshz]; +// meshr = new double[maxmeshr]; +// meshphi = new double[maxmeshphi]; +// fieldz = new double[maxfield]; +// fieldr = new double[maxfield]; +// fieldphi = new double[maxfield]; +// // define the tree branches +// tree->Branch( "id", &id, "id/I" ); +// tree->Branch( "zmin", &zmin, "zmin/D" ); +// tree->Branch( "zmax", &zmax, "zmax/D" ); +// tree->Branch( "rmin", &rmin, "rmin/D" ); +// tree->Branch( "rmax", &rmax, "rmax/D" ); +// tree->Branch( "phimin", &phimin, "phimin/D" ); +// tree->Branch( "phimax", &phimax, "phimax/D" ); +// tree->Branch( "bscale", &bscale, "bscale/D" ); +// tree->Branch( "ncond", &ncond, "ncond/I" ); +// tree->Branch( "finite", finite, "finite[ncond]/I" ); +// tree->Branch( "p1x", p1x, "p1x[ncond]/D" ); +// tree->Branch( "p1y", p1y, "p1y[ncond]/D" ); +// tree->Branch( "p1z", p1z, "p1z[ncond]/D" ); +// tree->Branch( "p2x", p2x, "p2x[ncond]/D" ); +// tree->Branch( "p2y", p2y, "p2y[ncond]/D" ); +// tree->Branch( "p2z", p2z, "p2z[ncond]/D" ); +// tree->Branch( "curr", curr, "curr[ncond]/D" ); +// tree->Branch( "nmeshz", &nmeshz, "nmeshz/I" ); +// tree->Branch( "meshz", meshz, "meshz[nmeshz]/D" ); +// tree->Branch( "nmeshr", &nmeshr, "nmeshr/I" ); +// tree->Branch( "meshr", meshr, "meshr[nmeshr]/D" ); +// tree->Branch( "nmeshphi", &nmeshphi, "nmeshphi/I" ); +// tree->Branch( "meshphi", meshphi, "meshphi[nmeshphi]/D" ); +// tree->Branch( "nfield", &nfield, "nfield/I" ); +// tree->Branch( "fieldz", fieldz, "fieldz[nfield]/D" ); +// tree->Branch( "fieldr", fieldr, "fieldr[nfield]/D" ); +// tree->Branch( "fieldphi", fieldphi, "fieldphi[nfield]/D" ); +// // loop over zones to write +// for ( unsigned i = 0; i < m_zone.size(); i++ ) { +// const BFieldZone z = m_zone[i]; +// id = z.id(); +// zmin = z.zmin(); zmax = z.zmax(); +// rmin = z.rmin(); rmax = z.rmax(); +// phimin = z.phimin(); phimax = z.phimax(); +// bscale = z.bscale(); +// ncond = z.ncond(); +// for ( int j = 0; j < ncond; j++ ) { +// const BFieldCond c = z.cond(j); +// finite[j] = c.finite(); +// p1x[j] = c.p1(0); +// p1y[j] = c.p1(1); +// p1z[j] = c.p1(2); +// p2x[j] = c.p2(0); +// p2y[j] = c.p2(1); +// p2z[j] = c.p2(2); +// curr[j] = c.curr(); +// } +// nmeshz = z.nmesh(0); +// for ( int j = 0; j < nmeshz; j++ ) { +// meshz[j] = z.mesh(0,j); +// } +// nmeshr = z.nmesh(1); +// for ( int j = 0; j < nmeshr; j++ ) { +// meshr[j] = z.mesh(1,j); +// } +// nmeshphi = z.nmesh(2); +// for ( int j = 0; j < nmeshphi; j++ ) { +// meshphi[j] = z.mesh(2,j); +// } +// nfield = z.nfield(); +// for ( int j = 0; j < nfield; j++ ) { +// const BFieldVector<short> f = z.field(j); +// fieldz[j] = f.z(); +// fieldr[j] = f.r(); +// fieldphi[j] = f.phi(); +// } +// tree->Fill(); +// } +// rootfile->Write(); +// // clean up +// delete[] finite; +// delete[] p1x; +// delete[] p1y; +// delete[] p1z; +// delete[] p2x; +// delete[] p2y; +// delete[] p2z; +// delete[] curr; +// delete[] meshz; +// delete[] meshr; +// delete[] meshphi; +// delete[] fieldz; +// delete[] fieldr; +// delete[] fieldphi; +//} + + +//bool MagField::AtlasFieldSvc::translateMap (std::string inFile, +// std::string outFile, +// std::string outTreeName, +// bool rz, +// double bScalor, +// double lScalor) const{ +// +// std::cout << "Registering new ASCII FieldMap File : " << outFile << std::endl; +// TFile* rootFile = TFile::Open(inFile.c_str(), "RECREATE"); +// if (!rootFile) std::cout << "Could not open '" << inFile << std::endl; +// +// if ( rootFile->cd() == false ) { +// std::cout<<"Error, input file is not correct!!! "<<std::endl; +// return false; +// } +// // open the tree +// TTree* tree = (TTree*)rootFile->Get("BFieldMap"); +// if ( tree == 0 ) { +// // no tree +// std::cout<<"Error translateMap(): TTree 'BFieldMap' does not exist in ROOT field map"<<std::endl; +// return false; +// } +// int id; +// double zmin, zmax, rmin, rmax, phimin, phimax; +// double bscale; +// int ncond; +// bool *finite; +// double *p1x, *p1y, *p1z, *p2x, *p2y, *p2z; +// double *curr; +// int nmeshz, nmeshr, nmeshphi; +// double *meshz, *meshr, *meshphi; +// int nfield; +// short *fieldz, *fieldr, *fieldphi; +// // define the fixed-sized branches first +// tree->SetBranchAddress( "id", &id ); +// tree->SetBranchAddress( "zmin", &zmin ); +// tree->SetBranchAddress( "zmax", &zmax ); +// tree->SetBranchAddress( "rmin", &rmin ); +// tree->SetBranchAddress( "rmax", &rmax ); +// tree->SetBranchAddress( "phimin", &phimin ); +// tree->SetBranchAddress( "phimax", &phimax ); +// tree->SetBranchAddress( "bscale", &bscale ); +// tree->SetBranchAddress( "ncond", &ncond ); +// tree->SetBranchAddress( "nmeshz", &nmeshz ); +// tree->SetBranchAddress( "nmeshr", &nmeshr ); +// tree->SetBranchAddress( "nmeshphi", &nmeshphi ); +// tree->SetBranchAddress( "nfield", &nfield ); +// // prepare arrays - need to know the maximum sizes +// // open the tree of buffer sizes (may not exist in old maps) +// unsigned maxcond(0), maxmeshz(0), maxmeshr(0), maxmeshphi(0), maxfield(0); +// TTree* tmax = (TTree*)rootFile->Get("BFieldMapSize"); +// if ( tmax != 0 ) { +// tmax->SetBranchAddress( "maxcond", &maxcond ); +// tmax->SetBranchAddress( "maxmeshz", &maxmeshz ); +// tmax->SetBranchAddress( "maxmeshr", &maxmeshr ); +// tmax->SetBranchAddress( "maxmeshphi", &maxmeshphi ); +// tmax->SetBranchAddress( "maxfield", &maxfield ); +// tmax->GetEntry(0); +// } else { // "BFieldMapSize" tree does not exist +// for ( int i = 0; i < tree->GetEntries(); i++ ) { +// tree->GetEntry(i); +// maxcond = std::max( maxcond, (unsigned)ncond ); +// maxmeshz = std::max( maxmeshz, (unsigned)nmeshz ); +// maxmeshr = std::max( maxmeshr, (unsigned)nmeshr ); +// maxmeshphi = std::max( maxmeshphi, (unsigned)nmeshphi ); +// maxfield = std::max( maxfield, (unsigned)nfield ); +// } +// } +// finite = new bool[maxcond]; +// p1x = new double[maxcond]; +// p1y = new double[maxcond]; +// p1z = new double[maxcond]; +// p2x = new double[maxcond]; +// p2y = new double[maxcond]; +// p2z = new double[maxcond]; +// curr = new double[maxcond]; +// meshz = new double[maxmeshz]; +// meshr = new double[maxmeshr]; +// meshphi = new double[maxmeshphi]; +// fieldz = new short[maxfield]; +// fieldr = new short[maxfield]; +// fieldphi = new short[maxfield]; +// // define the variable length branches +// tree->SetBranchAddress( "finite", finite ); +// tree->SetBranchAddress( "p1x", p1x ); +// tree->SetBranchAddress( "p1y", p1y ); +// tree->SetBranchAddress( "p1z", p1z ); +// tree->SetBranchAddress( "p2x", p2x ); +// tree->SetBranchAddress( "p2y", p2y ); +// tree->SetBranchAddress( "p2z", p2z ); +// tree->SetBranchAddress( "curr", curr ); +// tree->SetBranchAddress( "meshz", meshz ); +// tree->SetBranchAddress( "meshr", meshr ); +// tree->SetBranchAddress( "meshphi", meshphi ); +// tree->SetBranchAddress( "fieldz", fieldz ); +// tree->SetBranchAddress( "fieldr", fieldr ); +// tree->SetBranchAddress( "fieldphi", fieldphi ); +// +// // reserve the space for m_zone so that it won't move as the vector grows +//// m_zone.reserve( tree->GetEntries() ); +// // read all tree and store +//// for ( int i = 0; i < tree->GetEntries(); i++ ) +//// { +//// tree->GetEntry(i); +//// BFieldZone z( id, zmin, zmax, rmin, rmax, phimin, phimax, bscale ); +//// m_zone.push_back(z); +//// m_zone.back().reserve( nmeshz, nmeshr, nmeshphi ); +//// for ( int j = 0; j < ncond; j++ ) { +//// double p1[3], p2[3]; +//// p1[0] = p1x[j]; +//// p1[1] = p1y[j]; +//// p1[2] = p1z[j]; +//// p2[0] = p2x[j]; +//// p2[1] = p2y[j]; +//// p2[2] = p2z[j]; +//// BFieldCond cond( finite[j], p1, p2, curr[j] ); +//// m_zone.back().appendCond(cond); +//// } +//// for ( int j = 0; j < nmeshz; j++ ) { +//// m_zone.back().appendMesh( 0, meshz[j] ); +//// } +//// for ( int j = 0; j < nmeshr; j++ ) { +//// m_zone.back().appendMesh( 1, meshr[j] ); +//// } +//// for ( int j = 0; j < nmeshphi; j++ ) { +//// m_zone.back().appendMesh( 2, meshphi[j] ); +//// } +//// for ( int j = 0; j < nfield; j++ ) { +//// BFieldVector<short> field( fieldz[j], fieldr[j], fieldphi[j] ); +//// m_zone.back().appendField( field ); +//// } +//// } +// // clean up +// tree->Delete(); +// delete[] finite; +// delete[] p1x; +// delete[] p1y; +// delete[] p1z; +// delete[] p2x; +// delete[] p2y; +// delete[] p2z; +// delete[] curr; +// delete[] meshz; +// delete[] meshr; +// delete[] meshphi; +// delete[] fieldz; +// delete[] fieldr; +// delete[] fieldphi; +// +// +//// if (rz) { +//// +//// /// [1] Read in field map file +//// std::cout << "Opening new txt/csv input File : " << outFile << std::endl; +//// std::ifstream map_file(inFile.c_str(), std::ios::in); +//// // [1] Read in file and fill values +//// std::string line; +//// double rpos = 0., zpos = 0.; +//// double br = 0., bz = 0.; +//// +// +// +//} + +bool MagField::AtlasFieldSvc::readMapRoot (std::string filename) +{ + + // Create (or get) analysis reader + G4RootAnalysisReader* analysisReader = G4RootAnalysisReader::Instance(); + analysisReader->SetVerboseLevel(-1); + + // Define a base file name + analysisReader->SetFileName(filename); + int ntupleId =analysisReader->GetNtuple("BFieldMap"); + + if ( ntupleId < 0 ) { + // no tree + std::cout<<"readMap(): TTree 'BFieldMap' does not exist in ROOT field map"<<std::endl; + return false; + } + int id; + double zmin, zmax, rmin, rmax, phimin, phimax; + double bscale; + int ncond; + //int finite; + //double p1x, p1y, p1z, p2x, p2y, p2z; + //double curr; + int nmeshz, nmeshr, nmeshphi; + //double meshz, meshr, meshphi; + int nfield; + //double fieldz, fieldr, fieldphi; + + if ( ntupleId >= 0 ) { + + analysisReader->SetNtupleIColumn(ntupleId,"id", id); + analysisReader->SetNtupleDColumn(ntupleId,"zmin", zmin); + analysisReader->SetNtupleDColumn(ntupleId,"zmax", zmax); + analysisReader->SetNtupleDColumn(ntupleId,"rmin", rmin); + analysisReader->SetNtupleDColumn(ntupleId,"rmax",rmax); + analysisReader->SetNtupleDColumn(ntupleId,"phimin", phimin); + analysisReader->SetNtupleDColumn(ntupleId,"phimax", phimax); + analysisReader->SetNtupleDColumn(ntupleId,"bscale", bscale); + analysisReader->SetNtupleIColumn(ntupleId,"ncond", ncond); + analysisReader->SetNtupleIColumn(ntupleId,"nmeshz", nmeshz); + analysisReader->SetNtupleIColumn(ntupleId,"nmeshr", nmeshr); + analysisReader->SetNtupleIColumn(ntupleId,"nmeshphi", nmeshphi); + analysisReader->SetNtupleIColumn(ntupleId,"nfield", nfield); + } + + // prepare arrays - need to know the maximum sizes + // open the tree of buffer sizes (may not exist in old maps) + + int maxcond(0), maxmeshz(0), maxmeshr(0), maxmeshphi(0), maxfield(0); + + int ntupleId2 =analysisReader->GetNtuple("BFieldMapSize"); + //TTree* tmax = (TTree*)rootfile->Get("BFieldMapSize"); + if ( ntupleId2 >= 0 ) { + + analysisReader->SetNtupleIColumn(ntupleId2, "maxcond", maxcond); + analysisReader->SetNtupleIColumn(ntupleId2, "maxmeshz", maxmeshz); + analysisReader->SetNtupleIColumn(ntupleId2, "maxmeshr", maxmeshr ); + analysisReader->SetNtupleIColumn(ntupleId2, "maxmeshphi", maxmeshphi); + analysisReader->SetNtupleIColumn(ntupleId2, "maxfield", maxfield); + + analysisReader->GetNtupleRow(ntupleId2); //Get one entry + std::cout<<"maxcond: "<<maxcond<<"\tmaxmeshz: "<<maxmeshz<<"\tmaxmeshr: "<<maxmeshr<<"\tmaxmeshphi: "<<maxmeshphi<<"\tmaxfield: "<<maxfield<<std::endl; + } + std::vector<int> finite(maxcond); + std::vector<double> p1x(maxcond); + std::vector<double> p1y(maxcond); + std::vector<double> p1z(maxcond); + std::vector<double> p2x(maxcond); + std::vector<double> p2y(maxcond); + std::vector<double> p2z(maxcond); + std::vector<double> curr(maxcond); + std::vector<double> meshz(maxmeshz); + std::vector<double> meshr (maxmeshr); + std::vector<double> meshphi(maxmeshphi); + std::vector<double> fieldz (maxfield); + std::vector<double> fieldr (maxfield); + std::vector<double> fieldphi (maxfield); + + analysisReader->SetNtupleIColumn(ntupleId,"finite", finite); + analysisReader->SetNtupleDColumn(ntupleId,"p1x", p1x); + analysisReader->SetNtupleDColumn(ntupleId,"p1y", p1y); + analysisReader->SetNtupleDColumn(ntupleId,"p1z", p1z); + analysisReader->SetNtupleDColumn(ntupleId,"p2x", p2x); + analysisReader->SetNtupleDColumn(ntupleId,"p2y", p2y); + analysisReader->SetNtupleDColumn(ntupleId,"p2z", p2z); + analysisReader->SetNtupleDColumn(ntupleId,"curr", curr ); + analysisReader->SetNtupleDColumn(ntupleId,"meshz", meshz); + analysisReader->SetNtupleDColumn(ntupleId,"meshr", meshr); + analysisReader->SetNtupleDColumn(ntupleId,"meshphi", meshphi); + analysisReader->SetNtupleDColumn(ntupleId,"fieldz", fieldz); + analysisReader->SetNtupleDColumn(ntupleId,"fieldr", fieldr); + analysisReader->SetNtupleDColumn(ntupleId,"fieldphi", fieldphi); + + std::cout << "Ntuples reading" << std::endl; + // reserve the space for m_zone so that it won't move as the vector grows + m_zone.reserve( 406 ); + //int counter = 0; + while ( analysisReader->GetNtupleRow(ntupleId) ) + { +// std::cout << " Entry: "<<counter<<std::endl; +// counter++; +// std::cout << " id: " << id << "\tzmin: " << zmin <<"\tzmax: " << zmax <<std::endl; +// std::cout << " rmin: " << rmin << "\trmax: " << rmax <<std::endl; +// std::cout << " phimin: " << phimin << "\tphimax: " << phimax <<"\tbscale: "<<bscale<<std::endl; + + BFieldZone z( id, zmin, zmax, rmin, rmax, phimin, phimax, bscale ); + m_zone.push_back(z); + m_zone.back().reserve( nmeshz, nmeshr, nmeshphi ); + for ( int j = 0; j < ncond; j++ ) { + double p1[3], p2[3]; + p1[0] = p1x[j]; + p1[1] = p1y[j]; + p1[2] = p1z[j]; + p2[0] = p2x[j]; + p2[1] = p2y[j]; + p2[2] = p2z[j]; + bool fini = (bool) finite[j]; + BFieldCond cond( fini, p1, p2, curr[j] ); + m_zone.back().appendCond(cond); + } + for ( int j = 0; j < nmeshz; j++ ) { + m_zone.back().appendMesh( 0, meshz[j] ); + } + for ( int j = 0; j < nmeshr; j++ ) { + m_zone.back().appendMesh( 1, meshr[j] ); + } + for ( int j = 0; j < nmeshphi; j++ ) { + m_zone.back().appendMesh( 2, meshphi[j] ); + } + for ( int j = 0; j < nfield; j++ ) { + BFieldVector<short> field( fieldz[j], fieldr[j], fieldphi[j] ); + m_zone.back().appendField( field ); + } + } + + // build the LUTs + buildLUT(); + buildZR(); + return true; +} + +// +// read the map from a ROOT file. +// returns 0 if successful. +// +//bool MagField::AtlasFieldSvc::readMap( TFile* rootfile ) +//{ +// +// if ( rootfile == 0 ) { +// // no file +// //ATH_MSG_ERROR("readMap(): unable to read field map, no TFile given"); +// std::cout<<"readMap(): unable to read field map, no TFile given"<<std::endl; +// return false; +// } +// if ( rootfile->cd() == false ) { +// // could not make it current directory +// //ATH_MSG_ERROR("readMap(): unable to cd() into the ROOT field map TFile"); +// std::cout<<"readMap(): unable to cd() into the ROOT field map TFile"<<std::endl; +// return false; +// } +// // open the tree +// TTree* tree = (TTree*)rootfile->Get("BFieldMap"); +// if ( tree == 0 ) { +// // no tree +// //ATH_MSG_ERROR("readMap(): TTree 'BFieldMap' does not exist in ROOT field map"); +// std::cout<<"readMap(): TTree 'BFieldMap' does not exist in ROOT field map"<<std::endl; +// return false; +// } +// int id; +// double zmin, zmax, rmin, rmax, phimin, phimax; +// double bscale; +// int ncond; +// bool *finite; +// double *p1x, *p1y, *p1z, *p2x, *p2y, *p2z; +// double *curr; +// int nmeshz, nmeshr, nmeshphi; +// double *meshz, *meshr, *meshphi; +// int nfield; +// short *fieldz, *fieldr, *fieldphi; +// // define the fixed-sized branches first +// tree->SetBranchAddress( "id", &id ); +// tree->SetBranchAddress( "zmin", &zmin ); +// tree->SetBranchAddress( "zmax", &zmax ); +// tree->SetBranchAddress( "rmin", &rmin ); +// tree->SetBranchAddress( "rmax", &rmax ); +// tree->SetBranchAddress( "phimin", &phimin ); +// tree->SetBranchAddress( "phimax", &phimax ); +// tree->SetBranchAddress( "bscale", &bscale ); +// tree->SetBranchAddress( "ncond", &ncond ); +// tree->SetBranchAddress( "nmeshz", &nmeshz ); +// tree->SetBranchAddress( "nmeshr", &nmeshr ); +// tree->SetBranchAddress( "nmeshphi", &nmeshphi ); +// tree->SetBranchAddress( "nfield", &nfield ); +// // prepare arrays - need to know the maximum sizes +// // open the tree of buffer sizes (may not exist in old maps) +// unsigned maxcond(0), maxmeshz(0), maxmeshr(0), maxmeshphi(0), maxfield(0); +// TTree* tmax = (TTree*)rootfile->Get("BFieldMapSize"); +// if ( tmax != 0 ) { +// tmax->SetBranchAddress( "maxcond", &maxcond ); +// tmax->SetBranchAddress( "maxmeshz", &maxmeshz ); +// tmax->SetBranchAddress( "maxmeshr", &maxmeshr ); +// tmax->SetBranchAddress( "maxmeshphi", &maxmeshphi ); +// tmax->SetBranchAddress( "maxfield", &maxfield ); +// tmax->GetEntry(0); +// } else { // "BFieldMapSize" tree does not exist +// for ( int i = 0; i < tree->GetEntries(); i++ ) { +// tree->GetEntry(i); +// maxcond = std::max( maxcond, (unsigned)ncond ); +// maxmeshz = std::max( maxmeshz, (unsigned)nmeshz ); +// maxmeshr = std::max( maxmeshr, (unsigned)nmeshr ); +// maxmeshphi = std::max( maxmeshphi, (unsigned)nmeshphi ); +// maxfield = std::max( maxfield, (unsigned)nfield ); +// } +// } +// finite = new bool[maxcond]; +// p1x = new double[maxcond]; +// p1y = new double[maxcond]; +// p1z = new double[maxcond]; +// p2x = new double[maxcond]; +// p2y = new double[maxcond]; +// p2z = new double[maxcond]; +// curr = new double[maxcond]; +// meshz = new double[maxmeshz]; +// meshr = new double[maxmeshr]; +// meshphi = new double[maxmeshphi]; +// fieldz = new short[maxfield]; +// fieldr = new short[maxfield]; +// fieldphi = new short[maxfield]; +// // define the variable length branches +// tree->SetBranchAddress( "finite", finite ); +// tree->SetBranchAddress( "p1x", p1x ); +// tree->SetBranchAddress( "p1y", p1y ); +// tree->SetBranchAddress( "p1z", p1z ); +// tree->SetBranchAddress( "p2x", p2x ); +// tree->SetBranchAddress( "p2y", p2y ); +// tree->SetBranchAddress( "p2z", p2z ); +// tree->SetBranchAddress( "curr", curr ); +// tree->SetBranchAddress( "meshz", meshz ); +// tree->SetBranchAddress( "meshr", meshr ); +// tree->SetBranchAddress( "meshphi", meshphi ); +// tree->SetBranchAddress( "fieldz", fieldz ); +// tree->SetBranchAddress( "fieldr", fieldr ); +// tree->SetBranchAddress( "fieldphi", fieldphi ); +// +// // reserve the space for m_zone so that it won't move as the vector grows +// m_zone.reserve( tree->GetEntries() ); +// // read all tree and store +// for ( int i = 0; i < tree->GetEntries(); i++ ) { +// tree->GetEntry(i); +// BFieldZone z( id, zmin, zmax, rmin, rmax, phimin, phimax, bscale ); +// m_zone.push_back(z); +// m_zone.back().reserve( nmeshz, nmeshr, nmeshphi ); +// for ( int j = 0; j < ncond; j++ ) { +// double p1[3], p2[3]; +// p1[0] = p1x[j]; +// p1[1] = p1y[j]; +// p1[2] = p1z[j]; +// p2[0] = p2x[j]; +// p2[1] = p2y[j]; +// p2[2] = p2z[j]; +// BFieldCond cond( finite[j], p1, p2, curr[j] ); +// m_zone.back().appendCond(cond); +// } +// for ( int j = 0; j < nmeshz; j++ ) { +// m_zone.back().appendMesh( 0, meshz[j] ); +// } +// for ( int j = 0; j < nmeshr; j++ ) { +// m_zone.back().appendMesh( 1, meshr[j] ); +// } +// for ( int j = 0; j < nmeshphi; j++ ) { +// m_zone.back().appendMesh( 2, meshphi[j] ); +// } +// for ( int j = 0; j < nfield; j++ ) { +// BFieldVector<short> field( fieldz[j], fieldr[j], fieldphi[j] ); +// m_zone.back().appendField( field ); +// } +// } +// // clean up +// tree->Delete(); +// delete[] finite; +// delete[] p1x; +// delete[] p1y; +// delete[] p1z; +// delete[] p2x; +// delete[] p2y; +// delete[] p2z; +// delete[] curr; +// delete[] meshz; +// delete[] meshr; +// delete[] meshphi; +// delete[] fieldz; +// delete[] fieldr; +// delete[] fieldphi; +// // build the LUTs +// buildLUT(); +// buildZR(); +// +// return true; +//} + +// +// utility function used by readMap() +// +int MagField::AtlasFieldSvc::read_packed_data( std::istream& input, std::vector<int>& data ) const +{ + const std::string myname("BFieldMap::read_packed_data()"); + + data.resize(0); + char mode = 'u'; + char c; + while ( input.good() ) { + input >> c; + if ( input.eof() ) return 0; + else if (c == '}') { // end of record + return 0; + } + else if (c == 'z') { // series of zeros + int n; + int ierr = read_packed_int( input, n ); + if ( ierr != 0 ) return ierr; + for ( int i = 0; i < n; i++ ) { + data.push_back(0); + } + } + else if (c >= 'u' && c <= 'y') { // mode change + mode = c; + } + else if (c <= ' ' || c > 'z') { + //ATH_MSG_ERROR( myname << ": unexpected letter '" << c << "' in input" ); + return 3; + } + else { // normal letter in the range '!' - 't' + switch (mode) { + case 'u': + { + input.putback( c ); + int n; + int ierr = read_packed_int( input, n ); + if ( ierr != 0 ) return ierr; + data.push_back(n); + } + break; + case 'v': + { + int n = c - '!'; + for ( int i = 0; i < 4; i++ ) { + input >> c; + data.push_back(c - '!' + 84*(n%3)); + n = n/3; + } + } + break; + case 'w': + data.push_back(c - '!'); + break; + case 'x': + { + int n = c - '!'; + data.push_back(n/9); + data.push_back(n%9); + } + break; + case 'y': + { + int n = c - '!'; + data.push_back(n/27); + data.push_back((n/9)%3); + data.push_back((n/3)%3); + data.push_back(n%3); + } + break; + } + } + } + return 0; +} + +// +// utility function used by read_packed_data() +// +int MagField::AtlasFieldSvc::read_packed_int( std::istream &input, int &n ) const +{ + const std::string myname("BFieldMap::read_packed_int()"); + n = 0; + char c; + input >> c; + while ( c >= '!' && c <= 'J') { + n = 42*n + c - '!'; + input >> c; + } + if ( c >= 'K' && c <= 't' ) { + n = 42*n + c - 'K'; + } else { + //ATH_MSG_ERROR( myname << ": unexpected letter '" << c << "' in input" ); + return 4; + } + return 0; +} + +// +// Search for the zone that contains a point (z, r, phi) +// This is a linear-search version, used only to construct the LUT. +// +BFieldZone* MagField::AtlasFieldSvc::findZoneSlow( double z, double r, double phi ) +{ + for ( int j = m_zone.size()-1; j >= 0; --j ) { + if ( m_zone[j].inside( z, r, phi ) ) return &m_zone[j]; + } + return 0; +} + +// +// Build the look-up table used by FindZone(). +// Called by readMap() +// It also calls buildLUT() for all zones. +// +void MagField::AtlasFieldSvc::buildLUT() +{ + // make lists of (z,r,phi) edges of all zones + for ( int j = 0; j < 3; j++ ) { // z, r, phi + for ( unsigned i = 0; i < m_zone.size(); i++ ) { + double e[2]; + e[0] = m_zone[i].min(j); + e[1] = m_zone[i].max(j); + for ( int k = 0; k < 2; k++ ) { + // for the phi edge, fit into [-pi,pi] + if ( j==2 && e[k] > M_PI ) e[k] -= 2.0*M_PI; + m_edge[j].push_back(e[k]); + } + } + // add -pi and +pi to phi, just in case + m_edge[2].push_back(-M_PI); + m_edge[2].push_back(M_PI); + // sort + sort( m_edge[j].begin(), m_edge[j].end() ); + // remove duplicates + // must do this by hand to allow small differences due to rounding in phi + int index = 0; + for ( unsigned k = 1; k < m_edge[j].size(); k++ ) { + if ( fabs(m_edge[j][index] - m_edge[j][k]) < 1.0e-6 ) continue; + m_edge[j][++index] = m_edge[j][k]; + } + m_edge[j].resize( index+1 ); + // because of the small differences allowed in the comparison above, + // m_edge[][] values do not exactly match the m_zone[] boundaries. + // we have to fix this up in order to avoid invalid field values + // very close to the zone boundaries. + for ( unsigned i = 0; i < m_zone.size(); i++ ) { + for ( unsigned k = 0; k < m_edge[j].size(); k++ ) { + if ( fabs(m_zone[i].min(j) - m_edge[j][k]) < 1.0e-6 ) { + m_zone[i].adjustMin(j,m_edge[j][k]); + } + if ( fabs(m_zone[i].max(j) - m_edge[j][k]) < 1.0e-6 ) { + m_zone[i].adjustMax(j,m_edge[j][k]); + } + } + } + } + // build LUT for edge finding + for ( int j = 0; j < 3; j++ ) { // z, r, phi + // find the size of the smallest interval + double width = m_edge[j].back() - m_edge[j].front(); + double q(width); + for ( unsigned i = 0; i < m_edge[j].size()-1; i++ ) { + q = std::min( q, m_edge[j][i+1] - m_edge[j][i] ); + } + // find the number of cells in the LUT + int n = int(width/q) + 1; + q = width/(n+0.5); + m_invq[j] = 1.0/q; + n++; + // fill the LUT + int m = 0; + for ( int i = 0; i < n; i++ ) { // index of LUT + if ( q*i+m_edge[j].front() > m_edge[j][m+1] ) m++; + m_edgeLUT[j].push_back(m); + } + } + // store min/max for speedup + m_zmin=m_edge[0].front(); + m_zmax=m_edge[0].back(); + m_rmax=m_edge[1].back(); + +// std::cout<<" m_zmin: "<<m_zmin<<std::endl; +// std::cout<<" m_zmax: "<<m_zmax<<std::endl; +// std::cout<<" m_rmax: "<<m_rmax<<std::endl; + + // build LUT for zone finding + m_nz = m_edge[0].size() - 1; + m_nr = m_edge[1].size() - 1; + m_nphi = m_edge[2].size() - 1; + m_zoneLUT.reserve( m_nz*m_nr*m_nphi ); + for ( int iz = 0; iz < m_nz; iz++ ) { + double z = 0.5*(m_edge[0][iz]+m_edge[0][iz+1]); + for ( int ir = 0; ir < m_nr; ir++ ) { + double r = 0.5*(m_edge[1][ir]+m_edge[1][ir+1]); + for ( int iphi = 0; iphi < m_nphi; iphi++ ) { + double phi = 0.5*(m_edge[2][iphi]+m_edge[2][iphi+1]); + const BFieldZone* zone = findZoneSlow( z, r, phi ); + m_zoneLUT.push_back( zone ); + } + } + } + // build LUT in each zone + for ( unsigned i = 0; i < m_zone.size(); i++ ) { + m_zone[i].buildLUT(); + } +} + + +// +// Build the z-r 2d map for fast solenoid field +// +void MagField::AtlasFieldSvc::buildZR() +{ + // delete if previously allocated + delete m_meshZR; + + // find the solenoid zone + // solenoid zone always covers 100 < R < 1000, but not necessarily R < 100 + // so we search for the zone that contains a point at R = 200, Z = 0 + const BFieldZone *solezone = findZone( 0.0, 200.0, 0.0 ); + + // instantiate the new ZR map with the same external coverage as the solenoid zone + // make sure R = 0 is covered + m_meshZR = new BFieldMeshZR( solezone->zmin(), solezone->zmax(), 0.0, solezone->rmax() ); + + // reserve the right amount of memroy + unsigned nmeshz = solezone->nmesh(0); + unsigned nmeshr = solezone->nmesh(1); + if ( solezone->rmin() > 0.0 ) nmeshr++; + m_meshZR->reserve( nmeshz, nmeshr ); + + // copy the mesh structure in z/r + // take care of R = 0 first + if ( solezone->rmin() > 0.0 ) { + m_meshZR->appendMesh( 1, 0.0 ); + } + // copy the rest + for ( int i = 0; i < 2; i++ ) { // z, r + for ( unsigned j = 0; j < solezone->nmesh(i); j++ ) { // loop over mesh points + m_meshZR->appendMesh( i, solezone->mesh( i, j ) ); + } + } + + // loop through the mesh and compute the phi-averaged field + for ( unsigned iz = 0; iz < m_meshZR->nmesh(0); iz++ ) { // loop over z + double z = m_meshZR->mesh( 0, iz ); + for ( unsigned ir = 0; ir < m_meshZR->nmesh(1); ir++ ) { // loop over r + double r = m_meshZR->mesh( 1, ir ); + const int nphi(200); // number of phi slices to average + double Br = 0.0; + double Bz = 0.0; + for ( int iphi = 0; iphi < nphi; iphi++ ) { + double phi = double(iphi)/double(nphi)*2.*M_PI; + double xyz[3]; + xyz[0] = r*cos(phi); + xyz[1] = r*sin(phi); + xyz[2] = z; + double B[3]; + solezone->getB( xyz, B, 0 ); + Br += B[0]*cos(phi) + B[1]*sin(phi); + Bz += B[2]; + } + Br *= 1.0/double(nphi); + Bz *= 1.0/double(nphi); + m_meshZR->appendField( BFieldVectorZR( Bz, Br ) ); + } + } + + // build the internal LUT + m_meshZR->buildLUT(); +} + +// +// Approximate memory footprint +// +int MagField::AtlasFieldSvc::memSize() const +{ + int size = 0; + size += sizeof(BFieldCache); + size += sizeof(BFieldCacheZR); + for ( unsigned i = 0; i < m_zone.size(); i++ ) { + size += m_zone[i].memSize(); + } + for ( int i = 0; i < 3; i++ ) { + size += sizeof(double)*m_edge[i].capacity(); + size += sizeof(int)*m_edgeLUT[i].capacity(); + } + size += sizeof(BFieldZone*)*m_zoneLUT.capacity(); + if ( m_meshZR ) { + size += m_meshZR->memSize(); + } + return size; +} + diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/AtlasFieldSvc.h b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/AtlasFieldSvc.h new file mode 100644 index 0000000000000000000000000000000000000000..10648a456668e27e91ea23304c9905fa5a6b0853 --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/AtlasFieldSvc.h @@ -0,0 +1,285 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/////////////////////////////////////////////////////////////////// +// AtlasFieldSvc.h, (c) ATLAS Detector software +/////////////////////////////////////////////////////////////////// + +#ifndef MAGFIELDSERVICES_ATLASFIELDSVC_H +#define MAGFIELDSERVICES_ATLASFIELDSVC_H 1 + +// FrameWork includes +//#include "AthenaBaseComps/AthService.h" +//#include "GaudiKernel/ToolHandle.h" +//#include "GaudiKernel/IIncidentListener.h" + +// MagField includes +#include "IMagFieldSvc.h" +#include "AtlasFieldSvcTLS.h" +#include "BFieldCache.h" +#include "BFieldCacheZR.h" +#include "BFieldCond.h" +#include "BFieldZone.h" +#include "BFieldMeshZR.h" +#include "IMagFieldManipulator.h" + +// STL includes +#include <vector> +#include <iostream> + +// forward declarations +//class CondAttrListCollection; +class BFieldZone; +//class TFile; +//class Incident; + +namespace MagField { + + /** @class AtlasFieldSvc + @author Elmar.Ritsch -at- cern.ch + */ + class AtlasFieldSvc: public IMagFieldSvc { + //class AtlasFieldSvc : public extends<AthService, IMagFieldSvc, IIncidentListener> { + public: + + /** Constructor with parameters */ + AtlasFieldSvc(bool isAscii=true); + + /** Constructor with parameters */ + AtlasFieldSvc( const std::string& name, bool isAscii=true, bool solenoidOFF = false, bool toroidsOFF = false); + + /** Destructor */ + virtual ~AtlasFieldSvc(); + + /** Athena algorithm's interface methods */ +// virtual bool initialize() override; +// virtual bool finalize() override; + virtual bool initialize() ; + virtual bool finalize() ; + + /** Read **/ + virtual void handle(); + + /** writeMap, can be enabled when fROOT dependency is on **/ + //void writeMap( std::string filename ) const; + + /** Call back for possible magnet current update **/ + //StatusCode updateCurrent(IOVSVC_CALLBACK_ARGS); + + /** Call back for possible magnet filename update **/ + //StatusCode updateMapFilenames(IOVSVC_CALLBACK_ARGS); + + /** get B field value at given position */ + /** xyz[3] is in mm, bxyz[3] is in kT */ + /** if deriv[9] is given, field derivatives are returned in kT/mm */ + virtual void getField(const double *xyz, double *bxyz, double *deriv = nullptr) const override final; + virtual void getFieldZR(const double *xyz, double *bxyz, double *deriv = nullptr) const override final; + + double GetUseSolenoidCurrent(){return m_useSoleCurrent;} + void SetUseSolenoidCurrent(double current){m_useSoleCurrent = current;} + double GetUseToroidsCurrent(){return m_useToroCurrent;} + void SetUseToroidsCurrent(double current){m_useToroCurrent = current;} + + private: + /** Retrieve, initialize and return a thread-local storage object */ + inline struct AtlasFieldSvcTLS &getAtlasFieldSvcTLS() const; + + + /* // Methods called to get field + // pointer to actual function + typedef void (AtlasFieldSvc::*FuncPtr)(const double *, double *, double *); + FuncPtr getFieldActual; + // standard calculation + void getFieldStandard(const double *xyz, double *bxyz, double *deriv = 0); + // manipulated field + void getFieldManipulated(const double *xyz, double *bxyz, double *deriv = 0); + */ + + // Functions used by getField[ZR] + // search for a "zone" to which the point (z,r,phi) belongs + inline const BFieldZone* findZone( double z, double r, double phi ) const; + // slow search is used during initialization to build the LUT + BFieldZone* findZoneSlow( double z, double r, double phi ); + // fill the cache. return true if successful + // return false if the position is outside the valid map volume + inline bool fillFieldCache(double z, double r, double phi, AtlasFieldSvcTLS &tls) const; + inline bool fillFieldCacheZR(double z, double r, AtlasFieldSvcTLS &tls) const; + + // set currents from when DCS is not read + bool importCurrents(AtlasFieldSvcTLS &tls); + // initialize map + bool initializeMap(AtlasFieldSvcTLS &tls); + // read the field map from an ASCII or ROOT file + bool readMap( const char* filename ); + bool readMap( std::istream& input ); + /** readMap, can be enabled when fROOT dependency is on **/ + //bool readMap( TFile* rootfile ); + /** read the field map from a ROOT file, no fROOT dependency needed**/ + bool readMapRoot (std::string filename); + + // translate the map from root file into ascii file and write it out + bool translateMap (std::string inFile, + std::string outFile, + std::string outTreeName, + bool rz, + double bScalor = 1., + double lScalor = 1.) const; + // clear the field map + void clearMap(AtlasFieldSvcTLS &tls); + + // utility functions used by readMap + int read_packed_data( std::istream& input, std::vector<int>& data ) const; + int read_packed_int( std::istream& input, int &n ) const; + void buildLUT(); + void buildZR(); + + // scale field according to the current + void scaleField(); + + /** approximate memory footprint in bytes */ + int memSize() const; + + /** Data Members **/ + std::string m_fullMapAscii; // all magnets on + bool m_isAscii; //read the map from ascii file if true + // field map names root + std::string m_fullMapFilename; // all magnets on + std::string m_soleMapFilename; // solenoid on / toroid off + std::string m_toroMapFilename; // toroid on / solenoid off + // current associated with the map + double m_mapSoleCurrent; // solenoid current in A + double m_mapToroCurrent; // toroid current in A + // threshold below which currents are considered zero + double m_soleMinCurrent; // minimum solenoid current to be considered ON + double m_toroMinCurrent; // minimum toroid current to be considered ON + // flag to use magnet current from DCS in COOL + //bool m_useDCS; + // COOL folder name containing current information + //std::string m_coolCurrentsFolderName; + // flag to read magnet map filenames from COOL + //bool m_useMapsFromCOOL; + // COOL folder name containing field maps + //std::string m_coolMapsFolderName; + // actual current if DCS is not in use + double m_useSoleCurrent; // solenoid current in A + double m_useToroCurrent; // toroid current in A + // flag to skip current rescale and use map currents as they are + bool m_lockMapCurrents; + + + // handle for COOL field map filenames + //const DataHandle<CondAttrListCollection> m_mapHandle; + // handle for COOL currents + //const DataHandle<CondAttrListCollection> m_currentHandle; + + // full 3d map (made of multiple zones) + std::vector<BFieldZone> m_zone; + + // fast 2d map (made of one zone) + BFieldMeshZR *m_meshZR; + + // data members used in zone-finding + std::vector<double> m_edge[3]; // zone boundaries in z, r, phi + std::vector<int> m_edgeLUT[3]; // look-up table for zone edges + double m_invq[3]; // 1/stepsize in m_edgeLUT + std::vector<const BFieldZone*> m_zoneLUT; // look-up table for zones + // more data members to speed up zone-finding + double m_zmin; // minimum z + double m_zmax; // maximum z + int m_nz; // number of z bins in zoneLUT + double m_rmax; // maximum r + int m_nr; // number of r bins in zoneLUT + int m_nphi; // number of phi bins in zoneLUT + + /* // handle for field manipulator, if any + bool m_doManipulation; + ToolHandle<IMagFieldManipulator> m_manipulator; */ + + }; +} + +// inline functions + +// +// Initialize and return a thread-local storage object +// +struct MagField::AtlasFieldSvcTLS& +MagField::AtlasFieldSvc::getAtlasFieldSvcTLS() const { + static thread_local AtlasFieldSvcTLS tls = AtlasFieldSvcTLS(); + // return thread-local object + return tls; +} + +// +// Search for the zone that contains a point (z, r, phi) +// Fast version utilizing the LUT. +// +const BFieldZone* +MagField::AtlasFieldSvc::findZone( double z, double r, double phi ) const +{ + // make sure it's inside the largest zone + // NB: the sign of the logic is chosen in order to return 0 on NaN inputs + if ( z >= m_zmin && z <= m_zmax && r <= m_rmax ) { + // find the edges of the zone + // z + const std::vector<double>& edgez(m_edge[0]); + int iz = int(m_invq[0]*(z-m_zmin)); // index to LUT + iz = m_edgeLUT[0][iz]; // tentative index from LUT + if ( z > edgez[iz+1] ) iz++; + // r + const std::vector<double>& edger(m_edge[1]); + int ir = int(m_invq[1]*r); // index to LUT - note minimum r is always 0 + ir = m_edgeLUT[1][ir]; // tentative index from LUT + if ( r > edger[ir+1] ) ir++; + // phi + const std::vector<double>& edgephi(m_edge[2]); + int iphi = int(m_invq[2]*(phi+M_PI)); // index to LUT - minimum phi is -pi + iphi = m_edgeLUT[2][iphi]; // tentative index from LUT + if ( phi > edgephi[iphi+1] ) iphi++; + // use LUT to get the zone + return m_zoneLUT[(iz*m_nr+ir)*m_nphi+iphi]; + } else { + // std::cout<<"z is :"<<z<<" and should be >= "<<m_zmin<<" && z <= "<<m_zmax<< " && r is "<<r <<" and shoud be <= "<<m_rmax<<std::endl; + return 0; + } +} + +/** fill given magnetic field zone */ +bool +MagField::AtlasFieldSvc::fillFieldCache(double z, double r, double phi, AtlasFieldSvcTLS &tls) const +{ + // search for the zone + const BFieldZone* zone = findZone( z, r, phi ); + if ( zone == 0 ) { + // outsize all zones + return false; + } + // fill the cache + zone->getCache( z, r, phi, tls.cache ); + + // pointer to the conductors in the zone + tls.cond = zone->condVector(); + + // set a flag that the thread-local storage is initialized + tls.isInitialized = true; + + return true; +} + +/** fill Z-R cache for solenoid */ +bool +MagField::AtlasFieldSvc::fillFieldCacheZR(double z, double r, AtlasFieldSvcTLS &tls) const +{ + // is it inside the solenoid zone? + if ( m_meshZR && m_meshZR->inside( z, r ) ) { + // fill the cache + m_meshZR->getCache( z, r, tls.cacheZR ); + } else { + // outside solenoid + return false; + } + return true; +} + +#endif //> !MAGFIELDSERVICES_ATLASFIELDSVC_H diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/AtlasFieldSvcTLS.h b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/AtlasFieldSvcTLS.h new file mode 100644 index 0000000000000000000000000000000000000000..314b6de9a1e88270860d10be6f98e44c2c5412d9 --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/AtlasFieldSvcTLS.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @author Elmar.Ritsch -at- cern.ch + * @author Robert.Langenberg -at- cern.ch + * @date March 2017 + * @brief Thread-local storage object used by MagField::AtlasFieldSvc + */ + +#ifndef MAGFIELDSERVICES_ATLASFIELDSVCTLS_H +#define MAGFIELDSERVICES_ATLASFIELDSVCTLS_H 1 + +// MagField includes +#include "BFieldCond.h" +#include "BFieldZone.h" +#include "BFieldMeshZR.h" + +namespace MagField { + +/** @class AtlasFieldSvcTLS + * + * @brief Thread-local storage object used by MagField::AtlasFieldSvc + * + * @author Elmar.Ritsch -at- cern.ch + * @author Robert.Langenberg -at- cern.ch + */ +struct AtlasFieldSvcTLS { + + /// Constructor + AtlasFieldSvcTLS() : isInitialized(false), cond(nullptr), cache(), cacheZR() { ; } + + /// Is the current AtlasFieldSvcTLS object properly initialized + bool isInitialized; + + /// Pointer to the conductors in the current field zone (to compute Biot-Savart component) + const std::vector<BFieldCond> *cond; + + /// Full 3d field + BFieldCache cache; + /// Fast 2d field + BFieldCacheZR cacheZR; +}; + +} // namespace MagField + +#endif // MAGFIELDSERVICES_ATLASFIELDSVCTLS_H diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldCache.h b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldCache.h new file mode 100644 index 0000000000000000000000000000000000000000..a60ab96c2b6600168477385e2b17d8a15494c9b8 --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldCache.h @@ -0,0 +1,127 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// +// BFieldCache.h +// +// Cashe of one bin of the magnetic field map. +// Defined by ranges in z, r, phi, and the B vectors at the 8 corners of the "bin". +// +// Masahiro Morii, Harvard University +// +#ifndef BFIELDCACHE_H +#define BFIELDCACHE_H + +#include <iostream> +#include <cmath> +#include "BFieldVector.h" + +class BFieldCache { +public: + // default constructor sets unphysical boundaries, so that inside() will fail + BFieldCache() : m_zmin(0.0), m_zmax(0.0), m_rmin(0.0), m_rmax(0.0), m_phimin(0.0), m_phimax(-1.0) {;} + // make this cache invalid, so that inside() will fail + void invalidate() { m_phimin = 0.0; m_phimax = -1.0; } + // set the z, r, phi range that defines the bin + void setRange( double zmin, double zmax, double rmin, double rmax, double phimin, double phimax ) + { m_zmin = zmin; m_zmax = zmax; m_rmin = rmin; m_rmax = rmax; m_phimin = phimin; m_phimax = phimax; + m_invz = 1.0/(zmax-zmin); m_invr = 1.0/(rmax-rmin); m_invphi = 1.0/(phimax-phimin); } + // set the field values at each corner + void setField( int i, const BFieldVector<double> &field ) { for(int j=0; j<3; j++) m_field[j][i] = field[j]; } + void setField( int i, const BFieldVector<short> &field ) { for(int j=0; j<3; j++) m_field[j][i] = field[j]; } // set the multiplicative factor for the field vectors + void setBscale( double bscale ) { m_scale = bscale; } + // test if (z, r, phi) is inside this bin + bool inside( double z, double r, double phi ) const + { if ( phi < m_phimin ) phi += 2.0*M_PI; + return ( phi >= m_phimin && phi <= m_phimax && z >= m_zmin && z <= m_zmax && r >= m_rmin && r <= m_rmax ); } + // interpolate the field and return B[3]. + // also compute field derivatives if deriv[9] is given. + inline void getB( const double *xyz, double r, double phi, double *B, double *deriv=0 ) const; +private: + double m_zmin, m_zmax; // bin range in z + double m_rmin, m_rmax; // bin range in r + double m_phimin, m_phimax; // bin range in phi + float m_invz, m_invr, m_invphi; // 1/(bin size) in z, r, phi + float m_field[3][8]; // (Bz,Br,Bphi) at 8 corners of the bin + float m_scale; // unit of m_field in kT +}; + +// inline methods + +void +BFieldCache::getB( const double *xyz, double r, double phi, double *B, double *deriv ) const +{ + const double &x(xyz[0]); + const double &y(xyz[1]); + const double &z(xyz[2]); + // make sure phi is inside [m_phimin,m_phimax] + if ( phi < m_phimin ) phi += 2*M_PI; + // fractional position inside this bin + float fz = (z-m_zmin)*m_invz; + float gz = 1.0 - fz; + float fr = (r-m_rmin)*m_invr; + float gr = 1.0 - fr; + float fphi = (phi-m_phimin)*m_invphi; + float gphi = 1.0 - fphi; + // interpolate field values in z, r, phi + float Bzrphi[3]; + for ( int i = 0; i < 3; i++ ) { // z, r, phi components + const float *field = m_field[i]; + Bzrphi[i] = m_scale*( gz*( gr*( gphi*field[0] + fphi*field[1] ) + + fr*( gphi*field[2] + fphi*field[3] ) ) + + fz*( gr*( gphi*field[4] + fphi*field[5] ) + + fr*( gphi*field[6] + fphi*field[7] ) ) ); + } + // convert (Bz,Br,Bphi) to (Bx,By,Bz) + float invr, c, es; + if ( r > 0.0 ) { + invr = 1.0/r; + c = x*invr; + es = y*invr; + } else { + invr = 0.0; + c = cos(m_phimin); + es = sin(m_phimin); + } + B[0] = Bzrphi[1]*c - Bzrphi[2]*es; + B[1] = Bzrphi[1]*es + Bzrphi[2]*c; + B[2] = Bzrphi[0]; + + // compute field derivatives if requested + if ( deriv ) { + float sz = m_scale*m_invz; + float esr = m_scale*m_invr; + float sphi = m_scale*m_invphi; + float dBdz[3], dBdr[3], dBdphi[3]; + for ( int j = 0; j < 3; j++ ) { // Bz, Br, Bphi components + const float *field = m_field[j]; + dBdz[j] = sz*( gr*( gphi*(field[4]-field[0]) + fphi*(field[5]-field[1]) ) + + fr*( gphi*(field[6]-field[2]) + fphi*(field[7]-field[3]) ) ); + dBdr[j] = esr*( gz*( gphi*(field[2]-field[0]) + fphi*(field[3]-field[1]) ) + + fz*( gphi*(field[6]-field[4]) + fphi*(field[7]-field[5]) ) ); + dBdphi[j] = sphi*( gz*( gr*(field[1]-field[0]) + fr*(field[3]-field[2]) ) + + fz*( gr*(field[5]-field[4]) + fr*(field[7]-field[6]) ) ); + } + // convert to cartesian coordinates + float cc = c*c; + float cs = c*es; + float ss = es*es; + float ccinvr = cc*invr; + float csinvr = cs*invr; + float ssinvr = ss*invr; + float sinvr = es*invr; + float cinvr = c*invr; + deriv[0] = cc*dBdr[1] - cs*dBdr[2] - csinvr*dBdphi[1] + ssinvr*dBdphi[2] + sinvr*B[1]; + deriv[1] = cs*dBdr[1] - ss*dBdr[2] + ccinvr*dBdphi[1] - csinvr*dBdphi[2] - cinvr*B[1]; + deriv[2] = c*dBdz[1] - es*dBdz[2]; + deriv[3] = cs*dBdr[1] + cc*dBdr[2] - ssinvr*dBdphi[1] - csinvr*dBdphi[2] - sinvr*B[0]; + deriv[4] = ss*dBdr[1] + cs*dBdr[2] + csinvr*dBdphi[1] + ccinvr*dBdphi[2] + cinvr*B[0]; + deriv[5] = es*dBdz[1] + c*dBdz[2]; + deriv[6] = c*dBdr[0] - sinvr*dBdphi[0]; + deriv[7] = es*dBdr[0] + cinvr*dBdphi[0]; + deriv[8] = dBdz[0]; + } +} + +#endif diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldCacheZR.h b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldCacheZR.h new file mode 100644 index 0000000000000000000000000000000000000000..a4fcc5369d9109e36587c7fd562acfd6d3e5116d --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldCacheZR.h @@ -0,0 +1,105 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// +// BFieldCacheZR.h +// +// Cashe of one bin of the magnetic field map. +// Defined by ranges in z, r, and the (Bz, Br) vectors at the 4 corners of the "bin". +// +// Masahiro Morii, Harvard University +// +#ifndef BFIELDCACHEZR_H +#define BFIELDCACHEZR_H + +#include "BFieldVectorZR.h" +#include <iostream> +#include <cmath> + +class BFieldCacheZR { +public: + // default constructor sets unphysical boundaries, so that inside() will fail + BFieldCacheZR() : m_zmin(0.0), m_zmax(-1.0), m_rmin(0.0), m_rmax(-1.0) {;} + // invalidate this cache, so that inside() will fail + void invalidate() { m_rmin = 0.0; m_rmax = -1.0; } + // set the z, r range that defines the bin + void setRange( double zmin, double zmax, double rmin, double rmax ) + { m_zmin = zmin; m_zmax = zmax; m_rmin = rmin; m_rmax = rmax; + m_invz = 1.0/(zmax-zmin); m_invr = 1.0/(rmax-rmin); } + // set the field values at each corner + void setField( int i, const BFieldVectorZR &field ) + { m_field[0][i] = field[0]; m_field[1][i] = field[1]; } + // set the multiplicative factor for the field vectors + // test if (z, r) is inside this bin + bool inside( double z, double r ) const + { return ( z >= m_zmin && z <= m_zmax && r >= m_rmin && r <= m_rmax ); } + // interpolate the field and return B[3]. + // also compute field derivatives if deriv[9] is given. + inline void getB( const double *xyz, double r, double *B, double *deriv=0 ) const; +private: + double m_zmin, m_zmax; // bin range in z + double m_rmin, m_rmax; // bin range in r + float m_invz, m_invr; // 1/(bin size) in z, r + float m_field[2][4]; // (Bz,Br) at 4 corners of the bin +}; + +// inline methods + +void +BFieldCacheZR::getB( const double *xyz, double r, double *B, double *deriv ) const +{ + const double &x(xyz[0]); + const double &y(xyz[1]); + const double &z(xyz[2]); + // fractional position inside this bin + float fz = (z-m_zmin)*m_invz; + float gz = 1.0 - fz; + float fr = (r-m_rmin)*m_invr; + float gr = 1.0 - fr; + // interpolate field values in z, r + float Bzr[2]; + for ( int i = 0; i < 2; i++ ) { // z, r components + const float *field = m_field[i]; + Bzr[i] = gz*( gr*field[0] + fr*field[1] ) + fz*( gr*field[2] + fr*field[3] ); + } + // convert (Bz,Br) to (Bx,By,Bz) + float invr; + if ( r > 0.0 ) { + invr = 1.0/r; + } else { + invr = 0.0; + } + float c(x*invr); + float es(y*invr); + B[0] = Bzr[1]*c; + B[1] = Bzr[1]*es; + B[2] = Bzr[0]; + + // compute field derivatives if requested + if ( deriv ) { + float dBdz[2], dBdr[2]; + for ( int j = 0; j < 2; j++ ) { // Bz, Br components + const float *field = m_field[j]; + dBdz[j] = m_invz*( gr*(field[2]-field[0]) + fr*(field[3]-field[1]) ); + dBdr[j] = m_invr*( gz*(field[1]-field[0]) + fz*(field[3]-field[2]) ); + } + // convert to cartesian coordinates + float cc = c*c; + float cs = c*es; + float ss = es*es; + float sinvr = es*invr; + float cinvr = c*invr; + deriv[0] = cc*dBdr[1] + sinvr*B[1]; + deriv[1] = cs*dBdr[1] - cinvr*B[1]; + deriv[2] = c*dBdz[1]; + deriv[3] = cs*dBdr[1] - sinvr*B[0]; + deriv[4] = ss*dBdr[1] + cinvr*B[0]; + deriv[5] = es*dBdz[1]; + deriv[6] = c*dBdr[0]; + deriv[7] = es*dBdr[0]; + deriv[8] = dBdz[0]; + } +} + +#endif diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldCond.h b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldCond.h new file mode 100644 index 0000000000000000000000000000000000000000..9857ef4a0bc6c993f1d7e0e0eeb47ffd85ecbe26 --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldCond.h @@ -0,0 +1,108 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// +// BFieldCond.h +// +// Current conductors used in BFieldZone. +// It may be finite : p1 to p2. +// It may be infinite : passing p1 and direction parallel to p2. +// +// Masahiro Morii, Harvard University +// +#ifndef BFIELDCOND_H +#define BFIELDCOND_H + +#include <Eigen/Dense> +#include <cmath> + +class BFieldCond { +public: + // constructor + BFieldCond( bool finite, const double *p1, const double *p2, double curr ): + m_finite(finite), + m_p1(Eigen::Map<const Eigen::Vector3d>(p1)), + m_p2(Eigen::Map<const Eigen::Vector3d>(p2)), + m_u(finite ? (m_p2 - m_p1).normalized() : m_p2), + m_curr(curr), + m_nomCurr(curr) + {} + + // compute magnetic field, plus derivatives if requested, and add + inline void addBiotSavart( const double *xyz, double *B, double *deriv=0 ) const; + // scale the current wrt the nominal current + void scaleCurrent( double factor ) { m_curr = factor*m_nomCurr; } + // accessors + bool finite() const { return m_finite; } + double p1( int i ) const { return m_p1[i]; } + double p2( int i ) const { return m_p2[i]; } + double curr() const { return m_curr; } +private: + bool m_finite; // true if the conductor is finite in length + + /* + * m_p1: One end of a finite conductor, or one point on an infinite conductor + * m_p2: The other end of a finite conductor, or the direction vector of an infinite conductor + * m_u : Direction vector (= m_p2 if infinite) + */ + const Eigen::Vector3d m_p1, m_p2, m_u; + double m_curr; // current (in A) flowing through the conductor + double m_nomCurr; // nominal current (in A) read from the map file +}; + +// +// Compute the Biot-Savart field due to this conductor +// If deriv[9] is passed, also computes the field derivatives +// The results are _added_ to B[] and deriv[]. +// +void +BFieldCond::addBiotSavart( const double *xyz, double *B_in, double *deriv ) const +{ + static const double mu04pi = 1.0e-7; // mu_0/4pi + static const double minvsq = 10.*10.; // (1 cm)^2 + + const Eigen::Map<const Eigen::Vector3d> pos(xyz); + Eigen::Map<Eigen::Vector3d> B(B_in); + + const Eigen::Vector3d r1 = pos - m_p1; + const Eigen::Vector3d r2 = pos - m_p2; + const Eigen::Vector3d v = m_u.cross(r1); + const double vsq = std::max(v.squaredNorm(), minvsq); + + const double r1u = r1.dot(m_u), r2u = r2.dot(m_u); + const double r1n = r1.norm(), r2n = r2.norm(); + + const double f0 = mu04pi * m_curr / vsq; + const double f1 = f0 * (m_finite ? r1u / r1n - r2u / r2n : 2.0); + const double f2 = 2.0 * f1 / vsq; + + B += f1 * v; + + if (deriv) { + Eigen::Map<Eigen::Matrix<double, 3, 3, Eigen::RowMajor>> D(deriv); + + D(0, 1) -= f1 * m_u(2); + D(0, 2) += f1 * m_u(1); + D(1, 0) += f1 * m_u(2); + D(1, 2) -= f1 * m_u(0); + D(2, 0) -= f1 * m_u(1); + D(2, 1) += f1 * m_u(0); + + if (vsq > minvsq) { + Eigen::Vector3d w = f2 * (m_u * r1u - r1); + + if (m_finite) { + // Finite conductor segment + w += f0 * ( + (m_u - r1 * r1u / (r1n * r1n)) / r1n - + (m_u - r2 * r2u / (r2n * r2n)) / r2n + ); + } + + D += v * w.transpose(); + } + } +} + +#endif diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldH8Grid.cxx b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldH8Grid.cxx new file mode 100644 index 0000000000000000000000000000000000000000..9817715da6287ac398d58ae9a717b55aea3cd573 --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldH8Grid.cxx @@ -0,0 +1,143 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// +// BFieldH8Grid.cxx +// +// Masahiro Morii, Harvard University +// +#include "BFieldH8Grid.h" + +BFieldH8Grid::BFieldH8Grid() +{ + for ( int i=0; i<3; i++ ) { + m_n[i] = 0; + m_min[i] = 0.0; + m_max[i] = 0.0; + m_d[i] = 0.0; + } +} + +void +BFieldH8Grid::readMap( std::istream& input ) +{ + // read the magnet header line + char name[256]; + double cor; + m_n[0] = 0; + input >> name; + for ( int i=0; i<3; i++ ) input >> m_n[i]; + for ( int i=0; i<3; i++ ) input >> m_min[i] >> m_max[i]; + for ( int i=0; i<3; i++ ) input >> m_d[i]; + input >> cor; + // anything read? + if ( m_n[0] == 0 ) return; + // convert unit to mm + const double meter(1000.); // m in mm + for ( int i=0; i<3; i++ ) { + m_min[i] *= meter; + m_max[i] *= meter; + m_d[i] *= meter; + } + // prepare space for the field data + int nxyz = m_n[0]*m_n[1]*m_n[2]; + for ( int i=0; i<3; i++ ) m_B[i].resize(nxyz); + // read the field data + double xyz[3]; + double B[3]; + for ( int k=0; k<nxyz; k++ ) { + input >> xyz[0] >> xyz[1] >> xyz[2] >> B[0] >> B[1] >> B[2]; + // adjust unit and scale + const double cm(10.); // cm in mm + const double tesla(0.001); // T in kT + for ( int i=0; i<3; i++ ) { + xyz[i] *= cm; + B[i] *= -cor*tesla; + } + // find the grid number + int j[3]; + for ( int i=0; i<3; i++ ) { + j[i] = int((xyz[i]-m_min[i])/(m_max[i]-m_min[i])*(m_n[i]-1)+0.5); + } + // store + int ixyz = j[0] + m_n[0]*(j[1] + m_n[1]*j[2]); + for ( int i=0; i<3; i++ ) { + m_B[i][ixyz] = B[i]; + } + } + // apply offset to the range + for ( int i=0; i<3; i++ ) { + m_min[i] += m_d[i]; + m_max[i] += m_d[i]; + } +} + +void +BFieldH8Grid::getB( const double *xyz, double *B, double *deriv ) const +{ + if ( !defined() || !inside( xyz ) ) { + B[0] = B[1] = B[2] = 0.0; + if ( deriv != 0 ) { + for ( int j = 0; j < 9; j++ ) deriv[j] = 0.0; + } + return; + } + // find the grid index + double invunit[3]; + int j[3]; + double f[3]; + double g[3]; + for ( int i=0; i<3; i++ ) { + invunit[i] = (m_n[i]-1) / (m_max[i]-m_min[i]); + double a = (xyz[i]-m_min[i]) * invunit[i]; + j[i] = int(a); + f[i] = a - j[i]; + g[i] = 1.0 - f[i]; + } + int ixyz[8]; + ixyz[0] = j[0] + m_n[0]*(j[1] + m_n[1]*j[2]); + ixyz[1] = ixyz[0] + 1; + ixyz[2] = ixyz[0] + m_n[0]; + ixyz[3] = ixyz[2] + 1; + ixyz[4] = ixyz[0] + m_n[0]*m_n[1]; + ixyz[5] = ixyz[4] + 1; + ixyz[6] = ixyz[4] + m_n[0]; + ixyz[7] = ixyz[6] + 1; + // interpolate field values + for ( int i=0; i<3; i++ ) { // Bx, By, Bz + B[i] = g[2]*( g[1]*( g[0]*m_B[i][ixyz[0]] + f[0]*m_B[i][ixyz[1]] ) + + f[1]*( g[0]*m_B[i][ixyz[2]] + f[0]*m_B[i][ixyz[3]] ) ) + + f[2]*( g[1]*( g[0]*m_B[i][ixyz[4]] + f[0]*m_B[i][ixyz[5]] ) + + f[1]*( g[0]*m_B[i][ixyz[6]] + f[0]*m_B[i][ixyz[7]] ) ); + } + // derivatives + if ( deriv != 0 ) { + for ( int i=0; i<3; i++ ) { // Bx, By, Bz + deriv[i*3 ] = ( g[2]*( g[1]*(m_B[i][ixyz[1]] - m_B[i][ixyz[0]] ) + + f[1]*(m_B[i][ixyz[3]] - m_B[i][ixyz[2]] ) ) + + f[2]*( g[1]*(m_B[i][ixyz[5]] - m_B[i][ixyz[4]] ) + + f[1]*(m_B[i][ixyz[7]] - m_B[i][ixyz[6]] ) ) ) * invunit[0]; + deriv[i*3+1] = ( g[2]*( g[0]*(m_B[i][ixyz[2]] - m_B[i][ixyz[0]] ) + + f[0]*(m_B[i][ixyz[3]] - m_B[i][ixyz[1]] ) ) + + f[2]*( g[0]*(m_B[i][ixyz[6]] - m_B[i][ixyz[4]] ) + + f[0]*(m_B[i][ixyz[7]] - m_B[i][ixyz[5]] ) ) ) * invunit[1]; + deriv[i*3+2] = ( g[1]*( g[0]*(m_B[i][ixyz[4]] - m_B[i][ixyz[0]] ) + + f[0]*(m_B[i][ixyz[5]] - m_B[i][ixyz[1]] ) ) + + f[1]*( g[0]*(m_B[i][ixyz[6]] - m_B[i][ixyz[2]] ) + + f[0]*(m_B[i][ixyz[7]] - m_B[i][ixyz[3]] ) ) ) * invunit[2]; + } + } +} + +void +BFieldH8Grid::setOffset( const double *dxyz ) +{ + // update the range by the change in offset + for ( int i=0; i<3; i++ ) { + m_min[i] += dxyz[i] - m_d[i]; + m_max[i] += dxyz[i] - m_d[i]; + m_d[i] = dxyz[i]; + } +} + diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldH8Grid.h b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldH8Grid.h new file mode 100644 index 0000000000000000000000000000000000000000..112a5983184f9d111a2131e53388fadb5076b513 --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldH8Grid.h @@ -0,0 +1,51 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// +// BFieldH8Grid.h +// +// A regular x-y-z grid of field data for H8 field map +// +// Masahiro Morii, Harvard University +// +#ifndef BFIELDH8GRID_H +#define BFIELDH8GRID_H + +#include <vector> +#include <iostream> + +class BFieldH8Grid { +public: + // constructor + BFieldH8Grid(); + // read map data from a text file + void readMap( std::istream& input ); + // compute magnetic field + derivatives + void getB( const double *xyz, double *B, double *deriv=0 ) const; + // true if the grid has been defined + bool defined() const { return ( m_n[0] > 0 ); } + // true if xyz[3] is inside this grid + bool inside( const double *xyz ) const + { return ( xyz[0]>=m_min[0] && xyz[0]<=m_max[0] && + xyz[1]>=m_min[1] && xyz[1]<=m_max[1] && + xyz[2]>=m_min[2] && xyz[2]<=m_max[2] ); } + // set x-y-z offset of the grid coordinates + void setOffset( const double *dxyz ); + // get copies of size vectors + void getBounds(double *out_min, double *out_max, double *out_d) const + { for (unsigned i = 0; i < 3; i++) { + out_min[i] = m_min[i]; + out_max[i] = m_max[i]; + out_d[i] = m_d[i]; + } + return; + } +private: + int m_n[3]; // number of grid points + double m_min[3], m_max[3]; // range in x,y,z (mm) + double m_d[3]; // offset in x,y,z (mm) + std::vector<double> m_B[3]; // Bz,By,Bz (kT) +}; + +#endif diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldMesh.h b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldMesh.h new file mode 100644 index 0000000000000000000000000000000000000000..cc6a1d003f6716a41c0495c0ec3edd49598d5271 --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldMesh.h @@ -0,0 +1,294 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// +// BFieldMesh.h +// +// Generic 3-d mesh representing a simple field map. +// The field type is templated - it may be short (for the toroid) or double (for the solenoid) +// +// Masahiro Morii, Harvard University +// +#ifndef BFIELDMESH_H +#define BFIELDMESH_H + +#include <iostream> +#include <vector> +#include <cmath> +#include "BFieldVector.h" +#include "BFieldCache.h" + +template <class T> +class BFieldMesh { +public: + // constructor + BFieldMesh() : m_scale(1.0) {;} + BFieldMesh( double zmin, double zmax, double rmin, double rmax, double phimin, double phimax, + double bscale ) + : m_scale(bscale), m_nomScale(bscale) + { m_min[0] = zmin; m_max[0] = zmax; m_min[1] = rmin; m_max[1] = rmax; m_min[2] = phimin; m_max[2] = phimax; } + // set ranges + void setRange( double zmin, double zmax, double rmin, double rmax, double phimin, double phimax ) + { m_min[0] = zmin; m_max[0] = zmax; m_min[1] = rmin; m_max[1] = rmax; m_min[2] = phimin; m_max[2] = phimax; } + // set bscale + void setBscale( double bscale ) { m_scale = m_nomScale = bscale; } + // scale bscale by a factor + void scaleBscale( double factor ) { m_scale = factor*m_nomScale; } + // allocate space to vectors + void reserve( int nz, int nr, int nphi, int nfield ); + void reserve( int nz, int nr, int nphi ) { reserve( nz, nr, nphi, nz*nr*nphi ); } + // add elements to vectors + void appendMesh( int i, double mesh ) { m_mesh[i].push_back(mesh); } + void appendField( const BFieldVector<T> & field ) { m_field.push_back(field); } + // build LUT + void buildLUT(); + // test if a point is inside this zone + inline bool inside( double z, double r, double phi ) const; + // find the bin + inline void getCache( double z, double r, double phi, BFieldCache & cache ) const; + // get the B field + void getB( const double *xyz, double *B, double* deriv=0 ) const; + // accessors + double min( int i ) const { return m_min[i]; } + double max( int i ) const { return m_max[i]; } + double zmin() const { return m_min[0]; } + double zmax() const { return m_max[0]; } + double rmin() const { return m_min[1]; } + double rmax() const { return m_max[1]; } + double phimin() const { return m_min[2]; } + double phimax() const { return m_max[2]; } + unsigned nmesh( int i ) const { return m_mesh[i].size(); } + double mesh( int i, int j ) const { return m_mesh[i][j]; } + unsigned nfield() const { return m_field.size(); } + const BFieldVector<T> & field( int i ) const { return m_field[i]; } + double bscale() const { return m_scale; } + int memSize() const; +protected: + double m_min[3], m_max[3]; + std::vector<double> m_mesh[3]; +private: + std::vector< BFieldVector<T> > m_field; + double m_scale; + double m_nomScale; // nominal m_scale from the map + // look-up table and related variables + std::vector<int> m_LUT[3]; + double m_invUnit[3]; // inverse unit size in the LUT + int m_roff, m_zoff; +}; + +// +// Implemnetation follows +// + +// +// Reserve space in the vectors to avoid unnecessary memory re-allocations. +// +template <class T> +void BFieldMesh<T>::reserve( int nz, int nr, int nphi, int nfield ) +{ + m_mesh[0].reserve( nz ); + m_mesh[1].reserve( nr ); + m_mesh[2].reserve( nphi ); + m_field.reserve( nfield ); +} + +// +// Test if a point (z,r,phi) is inside this mesh region. +// +template <class T> +bool BFieldMesh<T>::inside( double z, double r, double phi ) const +{ + // assume phi is in [-pi,pi]. + // phimax() is in [0,2pi], but phimin() may be < 0 if the range crosses phi = 0. + // we have to test twice to get all possible cases. + if ( phi < phimin() ) phi += 2.0*M_PI; + return ( phi >= phimin() && phi <= phimax() && + z >= zmin() && z <= zmax() && r >= rmin() && r <= rmax() ); +} + +// +// Find and return the cache of the bin containing (z,r,phi) +// +template <class T> +void BFieldMesh<T>::getCache( double z, double r, double phi, BFieldCache & cache ) const +{ + // make sure phi is inside this zone + if ( phi < phimin() ) phi += 2.0*M_PI; + // find the mesh, and relative location in the mesh + // z + const std::vector<double>& mz(m_mesh[0]); + int iz = int((z-zmin())*m_invUnit[0]); // index to LUT + iz = m_LUT[0][iz]; // tentative mesh index from LUT + if ( z > mz[iz+1] ) iz++; + // r + const std::vector<double>& mr(m_mesh[1]); + int ir = int((r-rmin())*m_invUnit[1]); // index to LUT + ir = m_LUT[1][ir]; // tentative mesh index from LUT + if ( r > mr[ir+1] ) ir++; + // phi + const std::vector<double>& mphi(m_mesh[2]); + int iphi = int((phi-phimin())*m_invUnit[2]); // index to LUT + iphi = m_LUT[2][iphi]; // tentative mesh index from LUT + if ( phi > mphi[iphi+1] ) iphi++; + // store the bin edges + cache.setRange( mz[iz], mz[iz+1], mr[ir], mr[ir+1], mphi[iphi], mphi[iphi+1] ); + // store the B field at the 8 corners + int im0 = iz*m_zoff+ir*m_roff+iphi; // index of the first corner + cache.setField( 0, m_field[im0 ] ); + cache.setField( 1, m_field[im0 +1] ); + cache.setField( 2, m_field[im0 +m_roff ] ); + cache.setField( 3, m_field[im0 +m_roff+1] ); + cache.setField( 4, m_field[im0+m_zoff ] ); + cache.setField( 5, m_field[im0+m_zoff +1] ); + cache.setField( 6, m_field[im0+m_zoff+m_roff ] ); + cache.setField( 7, m_field[im0+m_zoff+m_roff+1] ); + // store the B scale + cache.setBscale( m_scale ); + return; +} + +// +// Compute the magnetic field (and the derivatives) without caching +// +template <class T> +void BFieldMesh<T>::getB( const double *xyz, double *B, double* deriv ) const +{ + // cylindrical coordinates + double x = xyz[0]; + double y = xyz[1]; + double z = xyz[2]; + double r = sqrt( x*x + y*y ); + double phi = atan2( y, x ); + if ( phi < phimin() ) phi += 2.0*M_PI; + // is it inside this map? + if ( ! inside( z, r, phi ) ) { // no + B[0] = B[1] = B[2] = 0.0; + if ( deriv ) for ( int i = 0; i < 9; i++ ) deriv[i] = 0.0; + return; + } + // find the bin + // z + const std::vector<double>& mz(m_mesh[0]); + int iz = int((z-zmin())*m_invUnit[0]); // index to LUT + iz = m_LUT[0][iz]; // tentative mesh index from LUT + if ( z > mz[iz+1] ) iz++; + // r + const std::vector<double>& mr(m_mesh[1]); + int ir = int((r-rmin())*m_invUnit[1]); // index to LUT + ir = m_LUT[1][ir]; // tentative mesh index from LUT + if ( r > mr[ir+1] ) ir++; + // phi + const std::vector<double>& mphi(m_mesh[2]); + int iphi = int((phi-phimin())*m_invUnit[2]); // index to LUT + iphi = m_LUT[2][iphi]; // tentative mesh index from LUT + if ( phi > mphi[iphi+1] ) iphi++; + // get the B field at the 8 corners + int im0 = iz*m_zoff+ir*m_roff+iphi; // index of the first corner + BFieldVector<T> field[8]; + field[0] = m_field[im0 ]; + field[1] = m_field[im0 +1]; + field[2] = m_field[im0 +m_roff ]; + field[3] = m_field[im0 +m_roff+1]; + field[4] = m_field[im0+m_zoff ]; + field[5] = m_field[im0+m_zoff +1]; + field[6] = m_field[im0+m_zoff+m_roff ]; + field[7] = m_field[im0+m_zoff+m_roff+1]; + // fractional position inside this mesh + double fz = (z-mz[iz]) / (mz[iz+1]-mz[iz]); + double gz = 1.0 - fz; + double fr = (r-mr[ir]) / (mr[ir+1]-mr[ir]); + double gr = 1.0 - fr; + double fphi = (phi-mphi[iphi]) / (mphi[iphi+1]-mphi[iphi]); + double gphi = 1.0 - fphi; + // interpolate field values in z, r, phi + double Bzrphi[3]; + for ( int i = 0; i < 3; i++ ) { // z, r, phi + Bzrphi[i] = m_scale*( gz*( gr*( gphi*field[0][i] + fphi*field[1][i] ) + + fr*( gphi*field[2][i] + fphi*field[3][i] ) ) + + fz*( gr*( gphi*field[4][i] + fphi*field[5][i] ) + + fr*( gphi*field[6][i] + fphi*field[7][i] ) ) ); + } + // convert (Bz,Br,Bphi) to (Bx,By,Bz) + double c = (r>0.0) ? x/r : cos(mphi[iphi]); + double es = (r>0.0) ? y/r : sin(mphi[iphi]); + B[0] = Bzrphi[1]*c - Bzrphi[2]*es; + B[1] = Bzrphi[1]*es + Bzrphi[2]*c; + B[2] = Bzrphi[0]; + + // compute field derivatives if requested + if ( deriv ) { + double sz = m_scale/(mz[iz+1]-mz[iz]); + double esr = m_scale/(mr[ir+1]-mr[ir]); + double sphi = m_scale/(mphi[iphi+1]-mphi[iphi]); + double dBdz[3], dBdr[3], dBdphi[3]; + for ( int j = 0; j < 3; j++ ) { // Bz, Br, Bphi components + dBdz[j] = sz*( gr*( gphi*(field[4][j]-field[0][j]) + fphi*(field[5][j]-field[1][j]) ) + + fr*( gphi*(field[6][j]-field[2][j]) + fphi*(field[7][j]-field[3][j]) ) ); + dBdr[j] = esr*( gz*( gphi*(field[2][j]-field[0][j]) + fphi*(field[3][j]-field[1][j]) ) + + fz*( gphi*(field[6][j]-field[4][j]) + fphi*(field[7][j]-field[5][j]) ) ); + dBdphi[j] = sphi*( gz*( gr*(field[1][j]-field[0][j]) + fr*(field[3][j]-field[2][j]) ) + + fz*( gr*(field[5][j]-field[4][j]) + fr*(field[7][j]-field[6][j]) ) ); + } + // convert to cartesian coordinates + double cc = c*c; + double cs = c*es; + double ss = es*es; + deriv[0] = cc*dBdr[1] - cs*dBdr[2] - cs*dBdphi[1]/r + ss*dBdphi[2]/r + es*B[1]/r; + deriv[1] = cs*dBdr[1] - ss*dBdr[2] + cc*dBdphi[1]/r - cs*dBdphi[2]/r - c*B[1]/r; + deriv[2] = c*dBdz[1] - es*dBdz[2]; + deriv[3] = cs*dBdr[1] + cc*dBdr[2] - ss*dBdphi[1]/r - cs*dBdphi[2]/r - es*B[0]/r; + deriv[5] = es*dBdz[1] + c*dBdz[2]; + deriv[6] = c*dBdr[0] - es*dBdphi[0]/r; + deriv[7] = es*dBdr[1] + c*dBdphi[0]/r; + deriv[8] = dBdz[0]; + } + return; +} + +// +// Construct the look-up table to accelerate bin-finding. +// +template <class T> +void BFieldMesh<T>::buildLUT() +{ + for ( int j = 0; j < 3; j++ ) { // z, r, phi + // align the m_mesh edges to m_min/m_max + m_mesh[j].front() = m_min[j]; + m_mesh[j].back() = m_max[j]; + // determine the unit size, q, to be used in the LUTs + double width = m_mesh[j].back() - m_mesh[j].front(); + double q(width); + for ( unsigned i = 0; i < m_mesh[j].size()-1; i++ ) { + q = std::min( q, m_mesh[j][i+1] - m_mesh[j][i] ); + } + // find the number of units in the LUT + int n = int(width/q) + 1; + q = width/(n+0.5); + m_invUnit[j] = 1.0/q; // new unit size + n++; + int m_number = 0; // mesh number + for ( int i = 0; i < n; i++ ) { // LUT index + if ( i*q + m_mesh[j].front() > m_mesh[j][m_number+1] ) m_number++; + m_LUT[j].push_back(m_number); + } + } + m_roff = m_mesh[2].size(); // index offset for incrementing r by 1 + m_zoff = m_roff*m_mesh[1].size(); // index offset for incrementing z by 1 +} + +template <class T> +int BFieldMesh<T>::memSize() const +{ + int size = 0; + size += sizeof(double)*10; + size += sizeof(int)*2; + for ( int i = 0; i < 3; i++ ) { + size += sizeof(double)*m_mesh[i].capacity(); + size += sizeof(int)*m_LUT[i].capacity(); + } + size += sizeof(BFieldVector<T>)*m_field.capacity(); + return size; +} + +#endif diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldMeshZR.cxx b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldMeshZR.cxx new file mode 100644 index 0000000000000000000000000000000000000000..450e825a15af0841f49b9bb8e8cd8a4d6dbd56ea --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldMeshZR.cxx @@ -0,0 +1,54 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// +// BFieldMeshZR.cxx +// +// A 2-dim z-r mesh inside the solenoid field map +// +// Masahiro Morii, Harvard University +// +#include "BFieldMeshZR.h" + +// +// Construct the look-up table to accelerate bin-finding. +// +void +BFieldMeshZR::buildLUT() +{ + for ( int j = 0; j < 2; j++ ) { // z, r + // determine the unit size, q, to be used in the LUTs + double width = m_mesh[j].back() - m_mesh[j].front(); + double q(width); + for ( unsigned i = 0; i < m_mesh[j].size()-1; i++ ) { + q = std::min( q, m_mesh[j][i+1] - m_mesh[j][i] ); + } + // find the number of units in the LUT + int n = int(width/q) + 1; + q = width/(n+0.5); + m_invUnit[j] = 1.0/q; // new unit size + n++; + int m = 0; // mesh number + m_LUT[j].reserve(n); + for ( int i = 0; i < n; i++ ) { // LUT index + if ( i*q + m_mesh[j].front() > m_mesh[j][m+1] ) m++; + m_LUT[j].push_back(m); + } + } + m_zoff = m_mesh[1].size(); // index offset for incrementing z by 1 +} + +int BFieldMeshZR::memSize() const +{ + int size = 0; + size += sizeof(double)*6; + size += sizeof(int)*1; + for ( int i = 0; i < 2; i++ ) { + size += sizeof(double)*m_mesh[i].capacity(); + size += sizeof(int)*m_LUT[i].capacity(); + } + size += sizeof(BFieldVectorZR)*m_field.capacity(); + return size; +} + diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldMeshZR.h b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldMeshZR.h new file mode 100644 index 0000000000000000000000000000000000000000..65e0bada7da28ad203f7347cb69524754a35a0ba --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldMeshZR.h @@ -0,0 +1,88 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// +// BFieldMeshZR.h +// +// A 2-dim z-r mesh inside the solenoid field map +// +// Masahiro Morii, Harvard University +// +#ifndef BFIELDMESHZR_H +#define BFIELDMESHZR_H + +#include <vector> +#include <cmath> +#include "BFieldVectorZR.h" +#include "BFieldCacheZR.h" + +class BFieldMeshZR { +public: + // constructor + BFieldMeshZR( double zmin, double zmax, double rmin, double rmax ) + { m_min[0] = zmin; m_max[0] = zmax; m_min[1] = rmin; m_max[1] = rmax; } + // allocate space to vectors + void reserve( int nz, int nr ) + { m_mesh[0].reserve( nz ); m_mesh[1].reserve( nr ); m_field.reserve( nz*nr ); } + // add elements to vectors + void appendMesh( int i, double mesh ) { m_mesh[i].push_back(mesh); } + void appendField( const BFieldVectorZR &field ) { m_field.push_back(field); } + // build LUT + void buildLUT(); + // test if a point is inside this zone + inline bool inside( double z, double r ) const + { return ( z >= zmin() && z <= zmax() && r >= rmin() && r <= rmax() ); } + // find the bin + inline void getCache( double z, double r, BFieldCacheZR & cache ) const; + // accessors + double min( int i ) const { return m_min[i]; } + double max( int i ) const { return m_max[i]; } + double zmin() const { return m_min[0]; } + double zmax() const { return m_max[0]; } + double rmin() const { return m_min[1]; } + double rmax() const { return m_max[1]; } + unsigned nmesh( int i ) const { return m_mesh[i].size(); } + double mesh( int i, int j ) const { return m_mesh[i][j]; } + unsigned nfield() const { return m_field.size(); } + const BFieldVectorZR & field( int i ) const { return m_field[i]; } + int memSize() const; +private: + double m_min[2], m_max[2]; + std::vector<double> m_mesh[2]; + std::vector<BFieldVectorZR> m_field; + // look-up table and related variables + std::vector<int> m_LUT[2]; + double m_invUnit[2]; // inverse unit size in the LUT + int m_zoff; +}; + +// +// Find and return the cache of the bin containing (z,r) +// +inline void +BFieldMeshZR::getCache( double z, double r, BFieldCacheZR & cache ) const +{ + // find the mesh, and relative location in the mesh + // z + const std::vector<double>& mz(m_mesh[0]); + int iz = int((z-zmin())*m_invUnit[0]); // index to LUT + iz = m_LUT[0][iz]; // tentative mesh index from LUT + if ( z > mz[iz+1] ) iz++; + // r + const std::vector<double>& mr(m_mesh[1]); + int ir = int((r-rmin())*m_invUnit[1]); // index to LUT + ir = m_LUT[1][ir]; // tentative mesh index from LUT + if ( r > mr[ir+1] ) ir++; + // store the bin edges + cache.setRange( mz[iz], mz[iz+1], mr[ir], mr[ir+1] ); + // store the B field at the 8 corners + int im0 = iz*m_zoff+ir; // index of the first corner + cache.setField( 0, m_field[im0 ] ); + cache.setField( 1, m_field[im0 +1] ); + cache.setField( 2, m_field[im0+m_zoff ] ); + cache.setField( 3, m_field[im0+m_zoff+1] ); + return; +} + +#endif diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldSolenoid.cxx b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldSolenoid.cxx new file mode 100644 index 0000000000000000000000000000000000000000..48d96575559e2886034a1e6d2890e9d77a677131 --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldSolenoid.cxx @@ -0,0 +1,344 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// +// BFieldSolenoid.cxx +// +#include "BFieldSolenoid.h" +#include <string> +#include <cmath> +#include <algorithm> +//#include "TTree.h" +using namespace std; + +// +// read an ASCII field map from istream +// return 0 if successful +// +int +BFieldSolenoid::readMap( istream& input ) +{ + const double meter(1000.0); // meter in mm + const double gauss(1.0e-7); // gauss in kT + const string myname("BFieldSolenoid::readMap()"); + if ( m_orig == m_tilt ) delete m_orig; + else { delete m_orig; delete m_tilt; } + m_orig = m_tilt = new BFieldMesh<double>; + // first line contains version + int version; + input >> version; + if ( version != 4 ) { + cerr << myname << ": version number is " << version << " instead of 4" << endl; + return 1; + } + // second line contains number of bins + int nz, nr, nphi; + double unused; + input >> nz >> nr >> nphi >> unused >> unused >> unused; + m_orig->reserve( nz, nr, nphi+1 ); // extra phi at 2pi + // read mesh definitions + double x; + for ( int i = 0; i < nr; i++ ) { input >> x; m_orig->appendMesh(1,x*meter); } + for ( int i = 0; i < nz; i++ ) { input >> x; m_orig->appendMesh(0,x*meter); } + for ( int i = 0; i < nphi; i++ ) { input >> x; m_orig->appendMesh(2,x); } + m_orig->appendMesh(2,2*M_PI); // extra phi at 2pi + double zmin = m_orig->mesh(0,0); + double zmax = m_orig->mesh(0,nz-1); + double rmin = m_orig->mesh(1,0); + double rmax = m_orig->mesh(1,nr-1); + double phimin = m_orig->mesh(2,0); + double phimax = m_orig->mesh(2,nphi); + m_orig->setRange( zmin, zmax, rmin, rmax, phimin, phimax ); + // skip one record + input >> unused >> unused >> unused >> unused >> unused; + // read field values + // the index order is opposite to the toroid - have to reorder + // also convert from gauss to Tesla here. + vector<double> Bz, Br, Bphi; + double b; + for ( int k = 0; k < nphi; k++ ) { + for ( int j = 0; j < nr; j++ ) { + for ( int i = 0; i < nz; i++ ) { input >> b; Bz.push_back(b*gauss); } + } + for ( int j = 0; j < nr; j++ ) { + for ( int i = 0; i < nz; i++ ) { input >> b; Br.push_back(b*gauss); } + } + for ( int j = 0; j < nr; j++ ) { + for ( int i = 0; i < nz; i++ ) { input >> b; Bphi.push_back(b*gauss); } + } + } + for ( int i = 0; i < nz; i++ ) { + for ( int j = 0; j < nr; j++ ) { + for ( int k = 0; k < nphi; k++ ) { + int index = i + nz*(j + nr*k); + BFieldVector<double> field( Bz[index], Br[index], Bphi[index] ); + m_orig->appendField( field ); + } + // close phi at 2pi + int index = i + nz*j; + BFieldVector<double> field( Bz[index], Br[index], Bphi[index] ); + m_orig->appendField( field ); + } + } + // build the LUT + m_orig->buildLUT(); + + return 0; +} + +// +// wrire the map to a ROOT file +// if tilted = true, write the moved-and-tilted map. +// ohterwise, write the original map. +// +//void +//BFieldSolenoid::writeMap( TFile* rootfile, bool tilted ) +//{ +// BFieldMesh<double> *map = tilted ? m_tilt : m_orig; +// if ( map == 0 ) return; // no map to write +// if ( rootfile == 0 ) return; // no file +// if ( rootfile->cd() == false ) return; // could not make it current directory +// // define the tree +// TTree* tree = new TTree( "BFieldSolenoid", "BFieldSolenoid version 4" ); +// double zmin = map->zmin(); +// double zmax = map->zmax(); +// double rmin = map->rmin(); +// double rmax = map->rmax(); +// double phimin = map->phimin(); +// double phimax = map->phimax(); +// int nmeshz = map->nmesh(0); +// int nmeshr = map->nmesh(1); +// int nmeshphi = map->nmesh(2); +// double *meshz, *meshr, *meshphi; +// int nfield = nmeshz*nmeshr*nmeshphi; +// double *fieldz, *fieldr, *fieldphi; +// meshz = new double[nmeshz]; +// meshr = new double[nmeshr]; +// meshphi = new double[nmeshphi]; +// fieldz = new double[nfield]; +// fieldr = new double[nfield]; +// fieldphi = new double[nfield]; +// // define the tree branches +// tree->Branch( "zmin", &zmin, "zmin/D" ); +// tree->Branch( "zmax", &zmax, "zmax/D" ); +// tree->Branch( "rmin", &rmin, "rmin/D" ); +// tree->Branch( "rmax", &rmax, "rmax/D" ); +// tree->Branch( "phimin", &phimin, "phimin/D" ); +// tree->Branch( "phimax", &phimax, "phimax/D" ); +// tree->Branch( "nmeshz", &nmeshz, "nmeshz/I" ); +// tree->Branch( "meshz", meshz, "meshz[nmeshz]/D" ); +// tree->Branch( "nmeshr", &nmeshr, "nmeshr/I" ); +// tree->Branch( "meshr", meshr, "meshr[nmeshr]/D" ); +// tree->Branch( "nmeshphi", &nmeshphi, "nmeshphi/I" ); +// tree->Branch( "meshphi", meshphi, "meshphi[nmeshphi]/D" ); +// tree->Branch( "nfield", &nfield, "nfield/I" ); +// tree->Branch( "fieldz", fieldz, "fieldz[nfield]/D" ); +// tree->Branch( "fieldr", fieldr, "fieldr[nfield]/D" ); +// tree->Branch( "fieldphi", fieldphi, "fieldphi[nfield]/D" ); +// // fill the mesh and field arrays +// for ( int j = 0; j < nmeshz; j++ ) { +// meshz[j] = map->mesh(0,j); +// } +// for ( int j = 0; j < nmeshr; j++ ) { +// meshr[j] = map->mesh(1,j); +// } +// for ( int j = 0; j < nmeshphi; j++ ) { +// meshphi[j] = map->mesh(2,j); +// } +// for ( int j = 0; j < nfield; j++ ) { +// const BFieldVector<double> f = map->field(j); +// fieldz[j] = f.z(); +// fieldr[j] = f.r(); +// fieldphi[j] = f.phi(); +// } +// // write +// tree->Fill(); +// rootfile->Write(); +// // clean up +// delete[] meshz; +// delete[] meshr; +// delete[] meshphi; +// delete[] fieldz; +// delete[] fieldr; +// delete[] fieldphi; +//} + +// +// read the map from a ROOT file. +// returns 0 if successful. +// +//int +//BFieldSolenoid::readMap( TFile* rootfile ) +//{ +// if ( rootfile == 0 ) return 1; // no file +// if ( rootfile->cd() == false ) return 2; // could not make it current directory +// if ( m_orig == m_tilt ) delete m_orig; +// else { delete m_orig; delete m_tilt; } +// m_orig = m_tilt = new BFieldMesh<double>; +// // open the tree +// TTree* tree = (TTree*)rootfile->Get("BFieldSolenoid"); +// if ( tree == 0 ) return 3; // no tree +// double zmin, zmax, rmin, rmax, phimin, phimax; +// int nmeshz, nmeshr, nmeshphi; +// double *meshz, *meshr, *meshphi; +// int nfield; +// double *fieldz, *fieldr, *fieldphi; +// //unsigned char *fbyte; +// // define the fixed-sized branches first +// tree->SetBranchAddress( "zmin", &zmin ); +// tree->SetBranchAddress( "zmax", &zmax ); +// tree->SetBranchAddress( "rmin", &rmin ); +// tree->SetBranchAddress( "rmax", &rmax ); +// tree->SetBranchAddress( "phimin", &phimin ); +// tree->SetBranchAddress( "phimax", &phimax ); +// tree->SetBranchAddress( "nmeshz", &nmeshz ); +// tree->SetBranchAddress( "nmeshr", &nmeshr ); +// tree->SetBranchAddress( "nmeshphi", &nmeshphi ); +// tree->SetBranchAddress( "nfield", &nfield ); +// // prepare arrays - need to know the maximum sizes +// tree->GetEntry(0); +// meshz = new double[nmeshz]; +// meshr = new double[nmeshr]; +// meshphi = new double[nmeshphi]; +// fieldz = new double[nfield]; +// fieldr = new double[nfield]; +// fieldphi = new double[nfield]; +// // define the variable length branches +// tree->SetBranchAddress( "meshz", meshz ); +// tree->SetBranchAddress( "meshr", meshr ); +// tree->SetBranchAddress( "meshphi", meshphi ); +// tree->SetBranchAddress( "fieldz", fieldz ); +// tree->SetBranchAddress( "fieldr", fieldr ); +// tree->SetBranchAddress( "fieldphi", fieldphi ); +// // read again, and copy data +// tree->GetEntry(0); +// m_orig->setRange( zmin, zmax, rmin, rmax, phimin, phimax ); +// m_orig->reserve( nmeshz, nmeshr, nmeshphi ); +// for ( int j = 0; j < nmeshz; j++ ) { +// m_orig->appendMesh( 0, meshz[j] ); +// } +// for ( int j = 0; j < nmeshr; j++ ) { +// m_orig->appendMesh( 1, meshr[j] ); +// } +// for ( int j = 0; j < nmeshphi; j++ ) { +// m_orig->appendMesh( 2, meshphi[j] ); +// } +// for ( int j = 0; j < nfield; j++ ) { +// BFieldVector<double> field( fieldz[j], fieldr[j], fieldphi[j] ); +// m_orig->appendField( field ); +// } +// // clean up +// tree->Delete(); +// delete[] meshz; +// delete[] meshr; +// delete[] meshphi; +// delete[] fieldz; +// delete[] fieldr; +// delete[] fieldphi; +// // build the LUTs +// m_orig->buildLUT(); +// +// return 0; +//} + +// +// Returns the magnetic field at any position. +// +void +BFieldSolenoid::getB( const double *xyz, double *B, double *deriv ) const +{ + double z = xyz[2]; + double r = sqrt(xyz[0]*xyz[0] + xyz[1]*xyz[1]); + double phi = atan2( xyz[1], xyz[0] ); + if ( m_tilt && m_tilt->inside( z, r, phi ) ) { + m_tilt->getB( xyz, B, deriv ); + } else { + B[0] = B[1] = B[2] = 0.0; + if ( deriv ) for ( int i = 0; i < 9; i++ ) deriv[i] = 0.0; + } +} + +// +// Move and tilt the solenoid. +// Modify the m_tilt copy and keep the m_orig copy. +// +void +BFieldSolenoid::moveMap( double dx, double dy, double dz, double ax, double ay ) +{ + if ( m_orig==0 ) { + cerr << "BFieldSolenoid::moveMap() : original map has not been read" << endl; + return; + } + if ( m_tilt != m_orig ) delete m_tilt; + // + // copy the mesh and make it a bit smaller + // + const double zlim = 2820.; // mm + const double rlim = 1075.; // mm + m_tilt = new BFieldMesh<double>( -zlim, zlim, 0.0, rlim, 0.0, 2*M_PI, 1.0 ); + // z + m_tilt->appendMesh( 0, -zlim ); + for ( unsigned i = 0; i < m_orig->nmesh(0); i++ ) { + if ( abs(m_orig->mesh(0,i)) < zlim ) m_tilt->appendMesh( 0, m_orig->mesh(0,i) ); + } + m_tilt->appendMesh( 0, zlim ); + // r + for ( unsigned i = 0; i < m_orig->nmesh(1); i++ ) { + if ( m_orig->mesh(1,i) < rlim ) m_tilt->appendMesh( 1, m_orig->mesh(1,i) ); + } + m_tilt->appendMesh( 1, rlim ); + // phi (no change) + for ( unsigned i = 0; i < m_orig->nmesh(2); i++ ) { + m_tilt->appendMesh( 2, m_orig->mesh(2,i) ); + } + // + // loop over the new mesh, and compute the field at the + // corresponding location in the original map + // + double sinax( sin(ax) ); + double cosax( cos(ax) ); + double sinay( sin(ay) ); + double cosay( cos(ay) ); + for ( unsigned i = 0; i < m_tilt->nmesh(0); i++ ) { + double z0( m_tilt->mesh(0,i) ); + for ( unsigned j = 0; j < m_tilt->nmesh(1); j++ ) { + double r0( m_tilt->mesh(1,j) ); + for ( unsigned k = 0; k < m_tilt->nmesh(2); k++ ) { + double phi0( m_tilt->mesh(2,k) ); + double x0( r0*cos(phi0) ); + double y0( r0*sin(phi0) ); + // shift + double x1( x0 - dx ); + double y1( y0 - dy ); + double z1( z0 - dz ); + // rotate around x by -ax + double x2( x1 ); + double y2( y1*cosax + z1*sinax ); + double z2( z1*cosax - y1*sinax ); + // rotate around y by -ay + double xyz3[3] = { x2*cosay-z2*sinay, y2, z2*cosay + x2*sinay }; + // get (Bx,By,Bz) in the original frame + double B[3]; + m_orig->getB( xyz3, B ); + // rotate around y by +ay + double Bx1( B[0]*cosay + B[2]*sinay ); + double By1( B[1] ); + double Bz1( B[2]*cosay - B[0]*sinay ); + // rotate around x by +ax + double Bx2( Bx1 ); + double By2( By1*cosax - Bz1*sinax ); + double Bz2( Bz1*cosax + By1*sinax ); + // convert to cylindrical + double cosphi0( cos(phi0) ); + double sinphi0( sin(phi0) ); + double Br( Bx2*cosphi0 + By2*sinphi0 ); + double Bphi( -Bx2*sinphi0 + By2*cosphi0 ); + BFieldVector<double> field( Bz2, Br, Bphi ); + m_tilt->appendField( field ); + } + } + } + m_tilt->buildLUT(); +} + diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldSolenoid.h b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldSolenoid.h new file mode 100644 index 0000000000000000000000000000000000000000..a996b259d4de848fe0e84f322c2d5d84d1ba402e --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldSolenoid.h @@ -0,0 +1,44 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// +// BFieldSolenoid.h +// +// Magnetic field map for the ATLAS solenoid +// +// Masahiro Morii, Harvard University +// +#ifndef BFIELDSOLENOID_H +#define BFIELDSOLENOID_H + +#include <vector> +#include <iostream> +//#include "TFile.h" +#include "BFieldZone.h" + +class BFieldSolenoid { +public: + // constructor + BFieldSolenoid() : m_orig(0), m_tilt(0) {;} + // destructor + ~BFieldSolenoid() { delete m_orig; if (m_orig!=m_tilt) delete m_tilt; } + // read/write map from/to file + int readMap( std::istream& input ); + //int readMap( TFile* rootfile ); + //void writeMap( TFile* rootfile, bool tilted = false ); + // move and tilt the map + void moveMap( double dx, double dy, double dz, double ax, double ay ); + // compute magnetic field + void getB( const double *xyz, double *B, double *deriv=0 ) const; + // accessor + const BFieldMesh<double> *tiltedMap() const { return m_tilt; } +private: + // data members + BFieldMesh<double> *m_orig; // original map as it was read from file + BFieldMesh<double> *m_tilt; // tilted and moved map + // cache for speed + mutable BFieldCache m_cache; +}; + +#endif diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldVector.h b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldVector.h new file mode 100644 index 0000000000000000000000000000000000000000..db04ebbd4f3ff9e4ee9009359e88e5984e13946b --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldVector.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// +// BFieldVector.h +// +// Magnetic field value stored in the map. +// It may be either short (toroid) or double (solenoid). +// +// Masahiro Morii, Harvard University +// +#ifndef BFIELDVECTOR_H +#define BFIELDVECTOR_H + +template <class T> +class BFieldVector { +public: + // constructor + BFieldVector() {;} + BFieldVector( T Bz, T Br, T Bphi ) { m_B[0] = Bz; m_B[1] = Br; m_B[2] = Bphi; } + // setter + void set( T Bz, T Br, T Bphi ) { m_B[0] = Bz; m_B[1] = Br; m_B[2] = Bphi; } + // accessors + T z() const { return m_B[0]; } + T r() const { return m_B[1]; } + T phi() const { return m_B[2]; } + // array-like accessor + T operator[]( int i ) const { return m_B[i]; } +private: + T m_B[3]; +}; + +#endif diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldVectorZR.h b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldVectorZR.h new file mode 100644 index 0000000000000000000000000000000000000000..45c519c2fbcf5648d2e8d2cae641c3484dd18e9e --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldVectorZR.h @@ -0,0 +1,31 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// +// BFieldVectorZR.h +// +// Magnetic field value (Bz,Br) stored in 2d map. +// +// Masahiro Morii, Harvard University +// +#ifndef BFIELDVECTORZR_H +#define BFIELDVECTORZR_H + +class BFieldVectorZR { +public: + // constructor + BFieldVectorZR() {;} + BFieldVectorZR( float Bz, float Br ) { m_B[0] = Bz; m_B[1] = Br; } + // setter + void set( float Bz, float Br ) { m_B[0] = Bz; m_B[1] = Br; } + // accessors + float z() const { return m_B[0]; } + float r() const { return m_B[1]; } + // array-like accessor + float operator[]( int i ) const { return m_B[i]; } +private: + float m_B[2]; +}; + +#endif diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldZone.h b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldZone.h new file mode 100644 index 0000000000000000000000000000000000000000..4b15a3524bae00ffdefbfec4a4a625c3a83a033a --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/BFieldZone.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// +// BFieldZone.h +// +// A "zone" inside the toroid field map +// +// Masahiro Morii, Harvard University +// +#ifndef BFIELDZONE_H +#define BFIELDZONE_H + +#include <vector> +#include "BFieldMesh.h" +#include "BFieldCond.h" + +class BFieldZone : public BFieldMesh<short> { +public: + // constructor + BFieldZone( int id, double zmin, double zmax, double rmin, double rmax, double phimin, double phimax, + double scale ) + : BFieldMesh<short>(zmin,zmax,rmin,rmax,phimin,phimax,scale), m_id(id) {;} + // add elements to vectors + void appendCond( const BFieldCond& cond ) { m_cond.push_back(cond); } + // compute Biot-Savart magnetic field and add to B[3] + inline void addBiotSavart( const double *xyz, double *B, double *deriv=0 ) const; + // scale B field by a multiplicative factor + void scaleField( double factor ) + { scaleBscale(factor); for (unsigned i=0; i<ncond(); i++) { m_cond[i].scaleCurrent(factor); } } + // accessors + int id() const { return m_id; } + unsigned ncond() const { return m_cond.size(); } + const BFieldCond& cond(int i) const { return m_cond[i]; } + const std::vector<BFieldCond> *condVector() const { return &m_cond; } + int memSize() const + { return BFieldMesh<short>::memSize() + sizeof(int) + sizeof(BFieldCond)*m_cond.capacity(); } + // adjust the min/max edges to a new value + void adjustMin( int i, double x ) { m_min[i] = x; m_mesh[i].front() = x; } + void adjustMax( int i, double x ) { m_max[i] = x; m_mesh[i].back() = x; } +private: + int m_id; // zone ID number + std::vector<BFieldCond> m_cond; // list of current conductors +}; + +// inline functions + +// +// Compute magnetic field due to the conductors +// +void +BFieldZone::addBiotSavart( const double *xyz, double *B, double *deriv ) const +{ + for ( unsigned i = 0; i < m_cond.size(); i++ ) { + m_cond[i].addBiotSavart( xyz, B, deriv ); + } +} + +#endif diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/H8FieldSvc.cxx b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/H8FieldSvc.cxx new file mode 100644 index 0000000000000000000000000000000000000000..37305d7e31eecb30a306f5af5230f199522d1ade --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/H8FieldSvc.cxx @@ -0,0 +1,159 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// +// H8FieldSvc.cxx +// +// Masahiro Morii, Harvard University +// + +#include <iostream> +#include <fstream> + +// ISF_Services include +#include "H8FieldSvc.h" + +// PathResolver +//#include "PathResolver/PathResolver.h" + +// StoreGate +//#include "StoreGate/StoreGateSvc.h" + +// Athena Pool +//#include "AthenaPoolUtilities/CondAttrListCollection.h" + +// CLHEP +#include "CLHEP/Units/SystemOfUnits.h" + +/** Constructor **/ +MagField::H8FieldSvc::H8FieldSvc( const std::string& /* name,ISvcLocator* svc */) : + //base_class(name,svc), + m_H8MapFilename("MagneticFieldMaps/mbps1-all-id-800-mbps2-muons-800x4.data"), + m_dx1(0), + m_dy1(0), + m_dz1(0), + m_dx2(43830), // default H8MS2 x offset + m_dy2(0), + m_dz2(0) +{ +// declareProperty("H8MapFile", m_H8MapFilename, "File storing the H8 magnetic field map"); +// declareProperty("dx1", m_dx1, "x component of magnet #1 shift (in mm)"); +// declareProperty("dy1", m_dy1, "y component of magnet #1 shift (in mm)"); +// declareProperty("dz1", m_dz1, "z component of magnet #1 shift (in mm)"); +// declareProperty("dx2", m_dx2, "x component of magnet #2 shift (in mm)"); +// declareProperty("dy2", m_dy2, "y component of magnet #2 shift (in mm)"); +// declareProperty("dz2", m_dz2, "z component of magnet #2 shift (in mm)"); +} + +MagField::H8FieldSvc::~H8FieldSvc() +{ +} + +/** framework methods */ +bool MagField::H8FieldSvc::initialize() +{ + //ATH_MSG_INFO( "initialize() ..." ); + return true; +} + +bool MagField::H8FieldSvc::start() +{ + //ATH_MSG_INFO( "start() ..." ); + return readMap( m_H8MapFilename ); +} + +bool MagField::H8FieldSvc::finalize() +{ + //ATH_MSG_INFO( "finalize() ..." ); + return true; +} + +bool MagField::H8FieldSvc::readMap( const std::string mapFile ) +{ + // find the path to the map file + //std::string resolvedMapFile = PathResolver::find_file( mapFile.c_str(), "DATAPATH" ); + std::string resolvedMapFile = mapFile.c_str(); + if ( resolvedMapFile == "" ) { + //ATH_MSG_ERROR( "Field map file " << mapFile << " not found" ); + return false; + } + // opne the map file + std::ifstream input( resolvedMapFile.c_str() ); + if ( ! input.good() ) { + //ATH_MSG_ERROR( "Failed to open the field map " << resolvedMapFile ); + return false; + } + // skip the file header line + char line[256]; + input.getline( line, 256 ); + // read grids + unsigned igrid(0); + double offset[3]; + while (1) { + // first determine offset + if (igrid == 0) { + // magnet #1 + offset[0] = m_dx1; + offset[1] = m_dy1; + offset[2] = m_dz1; + } else if (igrid == 1) { + // magnet #2 + offset[0] = m_dx2; + offset[1] = m_dy2; + offset[2] = m_dz2; + } else { + // shift up to two magnets + offset[0] = 0; + offset[1] = 0; + offset[2] = 0; + } + + // then, read the map and shift it + BFieldH8Grid grid; + grid.readMap( input ); + grid.setOffset(offset); + + if ( grid.defined() ) { + //ATH_MSG_INFO("setting offset for magnet " << igrid << " to " << offset[0] << ", " << offset[1] << ", " << offset[2] << " mm"); + // save grid + double its_min[3]; + double its_max[3]; + double its_d[3]; + grid.getBounds(its_min, its_max, its_d); + //ATH_MSG_INFO("new magnet grid #" << igrid << " found"); + //ATH_MSG_INFO(" - min (mm) " << its_min[0] << ", " << its_min[1] << ", " << its_min[2]); + //ATH_MSG_INFO(" - max (mm) " << its_max[0] << ", " << its_max[1] << ", " << its_max[2]); + //ATH_MSG_INFO(" - offset (mm) " << its_d[0] << ", " << its_d[1] << ", " << its_d[2]); + m_grid.push_back( grid ); + igrid++; + } else { + break; + } + } + //ATH_MSG_INFO( "Initialized the field map from " << resolvedMapFile ); + return true; +} + +void MagField::H8FieldSvc::getField( const double *xyz, double *B, double *deriv ) const +{ + for ( unsigned i = 0; i < m_grid.size(); i++ ) { + // find the grid that contains xyz + if ( m_grid[i].inside( xyz ) ) { + m_grid[i].getB( xyz, B, deriv ); + return; + } + } + // xyz is outside all grids + B[0] = B[1] = B[2] = 0.0; + if ( deriv != 0 ) { + for ( int j = 0; j < 9; j++ ) deriv[j] = 0.0; + } + return; +} + +void MagField::H8FieldSvc::getFieldZR( const double *xyz, double *B, double *deriv ) const +{ + getField( xyz, B, deriv ); + return; +} diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/H8FieldSvc.h b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/H8FieldSvc.h new file mode 100644 index 0000000000000000000000000000000000000000..cb47c812bc215e9d6371018d68f5a748d521b1fa --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/H8FieldSvc.h @@ -0,0 +1,78 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// +// H8FieldSvc.h +// +// Magnetic field map of the H8 beam test +// +// Masahiro Morii, Harvard University +// +#ifndef H8FIELDSVC_H +#define H8FIELDSVC_H + +// FrameWork includes +//#include "AthenaBaseComps/AthService.h" + +// MagField includes +#include "IMagFieldSvc.h" +#include "BFieldH8Grid.h" + +// STL includes +#include <vector> +#include <string> + +// forward declarations +class CondAttrListCollection; + +namespace MagField { +//class H8FieldSvc{ : public extends<AthService, IMagFieldSvc> { + class H8FieldSvc: public IMagFieldSvc{ + public: + + //** Constructor with parameters */ + H8FieldSvc( const std::string& name/*, ISvcLocator* pSvcLocator*/ ); + + /** Destructor */ + virtual ~H8FieldSvc(); + + /** Athena algorithm's interface methods */ + bool initialize(); + bool start(); + bool finalize(); + + /** get B field value at given position */ + /** xyz[3] is in mm, bxyz[3] is in kT */ + /** if deriv[9] is given, field derivatives are returned in kT/mm */ + virtual void getField( const double *xyz, double *bxyz, double *deriv = nullptr ) const; + /** getFieldZR simply calls getField **/ + virtual void getFieldZR( const double *xyz, double *bxyz, double *deriv = nullptr ) const; + + private: + // initialize map + bool initializeMap(); + // read the field map + bool readMap( const std::string mapFile ); + + /** Data members **/ + + // field map name + std::string m_H8MapFilename; + + // field data + std::vector<BFieldH8Grid> m_grid; + + // first magnet offset + double m_dx1; + double m_dy1; + double m_dz1; + // second magnet offset + double m_dx2; + double m_dy2; + double m_dz2; + + }; +} + +#endif diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/IMagFieldManipulator.h b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/IMagFieldManipulator.h new file mode 100644 index 0000000000000000000000000000000000000000..da0b02457dd23d61a97fc28943a3039a273a42c5 --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/IMagFieldManipulator.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/////////////////////////////////////////////////////////////////// +// IMagFieldManipulator.h, (c) ATLAS Detector software +/////////////////////////////////////////////////////////////////// +#ifndef MAGFIELDINTERFACES_IMAGFIELDMANIPULATOR_H +#define MAGFIELDINTERFACES_IMAGFIELDMANIPULATOR_H + +#include <cmath> +#include <iostream> + +// Framework includes +//#include "GaudiKernel/IAlgTool.h" + +// Amg classes +//#include "GeoPrimitives/GeoPrimitives.h" + +/** Declaration of the interface ID ( interface id, major version, minor version) */ +//static const InterfaceID IID_IMagFieldManipulator("IMagFieldManipulator", 1, 0); + +namespace MagField { + +/** @ class IMagFieldManipulator + + @ author Valerio.Ippolito -at- cern.ch + */ + //class IMagFieldManipulator: virtual public IAlgTool { + + class IMagFieldManipulator{ + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + /** constructor */ + IMagFieldManipulator() {;} + + /** Retrieve interface ID */ +// static const InterfaceID& interfaceID() { +// return IID_IMagFieldManipulator; +// } + + /** change the point where the field should be evaluated */ + /** in AtlasFieldSvc, this is called before B field is evaluated and */ + /** fed into modifyField **/ + /** xyz_new[3] and xyz_old[3] are in mm */ + virtual void modifyPosition(const double *xyz_old, double *xyz_new) = 0; + + /** correct B field value at a position xyz */ + /** bxyz[3] is in kT */ + /** if deriv[9] is given, field derivatives are returned in kT/mm */ + virtual void modifyField(double *bxyz, double *deriv = 0) = 0; + }; +} + +#endif //> !MAGFIELDINTERFACES_IMAGFIELDMANIPULATOR_H diff --git a/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/IMagFieldSvc.h b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/IMagFieldSvc.h new file mode 100644 index 0000000000000000000000000000000000000000..88c2f4f7ecb4c1eae1c8b72df131bf053f4baed9 --- /dev/null +++ b/ATLAS-Extensions/ATLASMagneticFieldMapPlugin/src/IMagFieldSvc.h @@ -0,0 +1,75 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/////////////////////////////////////////////////////////////////// +// IMagFieldSvc.h, (c) ATLAS Detector software +/////////////////////////////////////////////////////////////////// +#ifndef MAGFIELDINTERFACES_IMAGFIELDSVC_H +#define MAGFIELDINTERFACES_IMAGFIELDSVC_H + +#include <cmath> +#include <iostream> + +// Framework includes +//#include "GaudiKernel/IInterface.h" + +// Amg classes +//#include "GeoPrimitives/GeoPrimitives.h" + +namespace MagField { + +/** @ class IMagFieldSvc + + @ author Elmar.Ritsch -at- cern.ch + */ + //class IMagFieldSvc: virtual public IInterface { + class IMagFieldSvc{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + /** Creates the InterfaceID and interfaceID() method */ + //DeclareInterfaceID(IMagFieldSvc, 1, 0); + + /** constructor */ + IMagFieldSvc() : m_solenoidCurrent(0.0), m_toroidsCurrent(0.0) {;} + + /** get B field value at given position */ + /** xyz[3] is in mm, bxyz[3] is in kT */ + /** if deriv[9] is given, field derivatives are returned in kT/mm */ + virtual void getField(const double *xyz, double *bxyz, double *deriv = nullptr) const = 0; + + /** a getField() wrapper for Amg classes */ + //void getField(const Amg::Vector3D *xyz, Amg::Vector3D *bxyz) const { + // getField( xyz->data(), bxyz->data(), nullptr ); + //} + //void getField(const Amg::Vector3D *xyz, Amg::Vector3D *bxyz, Amg::RotationMatrix3D *deriv) const { + // getField( xyz->data(), bxyz->data(), deriv->data() ); + //} + + /** get B field value on the z-r plane at given position */ + /** works only inside the solenoid; otherwise calls getField() above */ + /** xyz[3] is in mm, bxyz[3] is in kT */ + /** if deriv[9] is given, field derivatives are returned in kT/mm */ + virtual void getFieldZR(const double *xyz, double *bxyz, double *deriv = nullptr) const = 0; + + /** status of the magnets */ + bool solenoidOn() const { return getSolenoidCurrent()> 0.0;} + bool toroidsOn () const { return getToroidsCurrent() > 0.0; } + float getSolenoidCurrent() const { return m_solenoidCurrent; } + float getToroidsCurrent () const { return m_toroidsCurrent; } + + //protected: + void setSolenoidCurrent(float current) { m_solenoidCurrent = current; } + void setToroidsCurrent (float current) { m_toroidsCurrent = current; } + + private: + float m_solenoidCurrent; // solenoid current in ampere + float m_toroidsCurrent; // toroid current in ampere + }; +} + +#endif //> !MAGFIELDINTERFACES_IMAGFIELDSVC_H diff --git a/ATLAS-Extensions/CMakeLists.txt b/ATLAS-Extensions/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7156f4b96d484833d8a27d24c4b81489af9e3bb0 --- /dev/null +++ b/ATLAS-Extensions/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + +# CMake settings +cmake_minimum_required( VERSION 3.14 ) + +# Dummy call to 'project()', needed to set 'PROJECT_SOURCE_DIR' +project( "ATLAS-Extensions" ) + +#Set up the project. Check if we build it with GeoModel or individually +if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) + # I am built as a top-level project. + # Make the root module directory visible to CMake. + list( APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake ) + # get global GeoModel version + include( GeoModel-version ) + # set the project, with the version taken from the GeoModel parent project + project( "ATLAS-Extensions" VERSION ${GeoModel_VERSION} LANGUAGES CXX ) + # Define color codes for CMake messages + include( cmake_colors_defs ) + # Warn the users about what they are doing + message(STATUS "${BoldGreen}Building ${PROJECT_NAME} individually, as a top-level project.${ColourReset}") + # Set default build and C++ options + include( configure_cpp_options ) + set( CMAKE_FIND_FRAMEWORK "LAST" CACHE STRING + "Framework finding behaviour on macOS" ) + # Set up how the project handle some of its dependenices. Either by picking them + # up from the environment, or building them itself. + + # Find the base GeoModel packages, which must be installed on the target system already + find_package( GeoModelCore REQUIRED ) + # Set a flag to steer the build of the subpackages + #set( VISUALIZATION_INDIVIDUAL_BUILD ON ) +else() + # I am called from other project with add_subdirectory(). + message( STATUS "Building ${PROJECT_NAME} as part of the root GeoModel project.") + # Set the project + project( "ATLAS-Extensions" VERSION ${GeoModel_VERSION} LANGUAGES CXX ) +endif() + + +# Use the GNU install directory names. +include( GNUInstallDirs ) + +# Set up the build of the libraries of the project. +add_subdirectory(HitsPlugin) +add_subdirectory(ATLASMagneticFieldMapPlugin) +add_subdirectory(LArCustomSolidExtension) + + + + diff --git a/ATLAS-Extensions/HitsPlugin/CMakeLists.txt b/ATLAS-Extensions/HitsPlugin/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..01f39a0185ed71cb69b042153dbfa24e90540e03 --- /dev/null +++ b/ATLAS-Extensions/HitsPlugin/CMakeLists.txt @@ -0,0 +1,82 @@ +# Set up the project. +cmake_minimum_required( VERSION 3.1 ) + +set(CMAKE_CXX_STANDARD 17) + +project( "GenerateHitsPlugin" ) + +#Set up the project. Check if we build it with GeoModel or individually +if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) + # I am built as a top-level project. + # Make the root module directory visible to CMake. + list( APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ) + # get global GeoModel version + #include( GeoModelATLAS-version ) + # set the project, with the version taken from the GeoModel parent project + project( "GenerateHitsPlugin" VERSION 1.0 LANGUAGES CXX ) + # Define color codes for CMake messages + include( cmake_colors_defs ) + # Use the GNU install directory names. + include( GNUInstallDirs ) + # Set a default build type + include( BuildType ) + # Set default build and C++ options + include( configure_cpp_options ) + # Print Build Info on screen + include( PrintBuildInfo ) + # Warn the users about what they are doing + message(STATUS "${BoldGreen}Building ${PROJECT_NAME} individually, as a top-level project.${ColourReset}") + # Set default build and C++ options + include( configure_cpp_options ) + set( CMAKE_FIND_FRAMEWORK "LAST" CACHE STRING + "Framework finding behaviour on macOS" ) + # GeoModel dependencies + find_package( GeoModelCore REQUIRED ) +else() + # I am called from other project with add_subdirectory(). + message( STATUS "Building ${PROJECT_NAME} as part of the root project.") + # Set the project + project( "GenerateHitsPlugin" VERSION 1.0 LANGUAGES CXX ) +endif() + + + +# Find the header and source files. +file( GLOB SOURCES src/*.cxx ) + +set(PROJECT_SOURCES ${SOURCES}) + +# Set up the library. +add_library(GenerateHitsPlugin SHARED ${SOURCES}) + +#find_package (Eigen3 REQUIRED) +find_package(Geant4 REQUIRED) +#find_package(FullSimLight REQUIRED) +find_package( HDF5 REQUIRED COMPONENTS CXX ) + +message( STATUS "Found Geant4: ${Geant4_INCLUDE_DIR}") +#message("Geant4_USE_FILE: ${Geant4_USE_FILE}") # debug msg +include(${Geant4_USE_FILE}) + +# Use the GNU install directory names. +include( GNUInstallDirs ) + +target_include_directories( GenerateHitsPlugin PUBLIC ${CMAKE_SOURCE_DIR}/FullSimLight ${HDF5_CXX_INCLUDE_DIRS}) + +target_link_libraries ( GenerateHitsPlugin PUBLIC ${CMAKE_DL_LIBS} ${Geant4_LIBRARIES} ${HDF5_CXX_LIBRARIES}) + + + +set_target_properties( GenerateHitsPlugin PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} ) + + + +install( TARGETS GenerateHitsPlugin + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT Runtime + NAMELINK_COMPONENT Development ) + + + diff --git a/ATLAS-Extensions/HitsPlugin/cmake/BuildType.cmake b/ATLAS-Extensions/HitsPlugin/cmake/BuildType.cmake new file mode 100644 index 0000000000000000000000000000000000000000..14a12a8ccc0c22511e31288d7ab3b4fea69fb561 --- /dev/null +++ b/ATLAS-Extensions/HitsPlugin/cmake/BuildType.cmake @@ -0,0 +1,28 @@ + +# Author: Marcus D. Hanwell +# Source: https://blog.kitware.com/cmake-and-the-default-build-type/ + +# Set a default build type if none was specified +set(default_build_type "Release") + +# TODO: at the moment, we want to build in Release mode by default, +# even if we build from a Git clone, because that is the default mode +# for our users to get the source code. +# But maybe we will want to change this behavior, later? +# if(EXISTS "${CMAKE_SOURCE_DIR}/.git") +# set(default_build_type "Debug") +# endif() + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + if( COLOR_DEFS ) + message(STATUS "${Blue}INFO: Setting build type to '${default_build_type}' as none was specified.${ColourReset}") + else() + message(STATUS "INFO: Setting build type to '${default_build_type}' as none was specified.") + endif() + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE + STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + diff --git a/ATLAS-Extensions/HitsPlugin/cmake/PrintBuildInfo.cmake b/ATLAS-Extensions/HitsPlugin/cmake/PrintBuildInfo.cmake new file mode 100644 index 0000000000000000000000000000000000000000..862a34b45c7506c83a229d7ef71ff604d182acb6 --- /dev/null +++ b/ATLAS-Extensions/HitsPlugin/cmake/PrintBuildInfo.cmake @@ -0,0 +1,13 @@ +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + +if( COLOR_DEFS ) + message(STATUS "-----") + message(STATUS "${BoldYellow}Building with type: ${CMAKE_BUILD_TYPE}${ColourReset}") + message(STATUS "${BoldYellow}Using C++ standard: ${CMAKE_CXX_STANDARD}${ColourReset}") + message(STATUS "-----") +else() + message(STATUS "-----") + message(STATUS "Building with type: ${CMAKE_BUILD_TYPE}") + message(STATUS "Using C++ standard: ${CMAKE_CXX_STANDARD}") + message(STATUS "-----") +endif() diff --git a/ATLAS-Extensions/HitsPlugin/cmake/cmake_colors_defs.cmake b/ATLAS-Extensions/HitsPlugin/cmake/cmake_colors_defs.cmake new file mode 100644 index 0000000000000000000000000000000000000000..b6eea59ba9e72a50754ac0afb36d25cfcac59e09 --- /dev/null +++ b/ATLAS-Extensions/HitsPlugin/cmake/cmake_colors_defs.cmake @@ -0,0 +1,25 @@ + +# Copyright: "Fraser" (https://stackoverflow.com/users/2556117/fraser) +# CC BY-SA 3.0 +# Source: https://stackoverflow.com/a/19578320/320369 + +if(NOT WIN32) + set( COLOR_DEFS TRUE CACHE BOOL "Define color escape sequences to be used in CMake messages." ) + string(ASCII 27 Esc) + set(ColourReset "${Esc}[m") + set(ColourBold "${Esc}[1m") + set(Red "${Esc}[31m") + set(Green "${Esc}[32m") + set(Yellow "${Esc}[33m") + set(Blue "${Esc}[34m") + set(Magenta "${Esc}[35m") + set(Cyan "${Esc}[36m") + set(White "${Esc}[37m") + set(BoldRed "${Esc}[1;31m") + set(BoldGreen "${Esc}[1;32m") + set(BoldYellow "${Esc}[1;33m") + set(BoldBlue "${Esc}[1;34m") + set(BoldMagenta "${Esc}[1;35m") + set(BoldCyan "${Esc}[1;36m") + set(BoldWhite "${Esc}[1;37m") +endif() diff --git a/ATLAS-Extensions/HitsPlugin/cmake/configure_cpp_options.cmake b/ATLAS-Extensions/HitsPlugin/cmake/configure_cpp_options.cmake new file mode 100644 index 0000000000000000000000000000000000000000..9a6cc8a7902de8bd14d412f0ca4fc86a3bc116fc --- /dev/null +++ b/ATLAS-Extensions/HitsPlugin/cmake/configure_cpp_options.cmake @@ -0,0 +1,34 @@ + +# +# Set build options and C++ standards and options +# +# This file sets up +# +# CMAKE_BUILD_TYPE +# CMAKE_CXX_STANDARD +# CMAKE_CXX_EXTENSIONS +# CMAKE_CXX_STANDARD_REQUIRED +# +# The options can be overridden at configuration time by using, e.g.: +# `cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_STANDARD=14 ../GeoModelIO` +# on the command line. +# + +# Set default build options. +set( CMAKE_BUILD_TYPE "Release" CACHE STRING "CMake build mode to use" ) +set( CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard used for the build" ) +set( CMAKE_CXX_EXTENSIONS FALSE CACHE BOOL "(Dis)allow using GNU extensions" ) +set( CMAKE_CXX_STANDARD_REQUIRED TRUE CACHE BOOL + "Require the specified C++ standard for the build" ) + +# Setting CMAKE_CXX_FLAGS to avoid "deprecated" warnings +set(CMAKE_CXX_FLAGS "-Wno-deprecated-declarations" ) # very basic +#set(CMAKE_CXX_FLAGS "-Wall -Werror -pedantic-errors -Wno-deprecated-declarations" ) # good enough for a quick, better check +#set(CMAKE_CXX_FLAGS "-Wall -Wextra -Werror -pedantic-errors -Wno-deprecated-declarations" ) # better for a thorough check +#set(CMAKE_CXX_FLAGS "-Wall -Wextra -Werror -pedantic-errors" ) # better for an even more severe check +#set(CMAKE_CXX_FLAGS "-Weverything -Werror -pedantic-errors" ) # not recommended, it warns for really EVERYTHING! + + +# TODO: for Debug and with GCC, do we want to set the flags below by default? +# set( CMAKE_BUILD_TYPE DEBUG ) +# set(CMAKE_CXX_FLAGS "-fPIC -O0 -g -gdwarf-2" ) diff --git a/ATLAS-Extensions/HitsPlugin/src/HitsPlugin.cxx b/ATLAS-Extensions/HitsPlugin/src/HitsPlugin.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b32c8ed7325fcb8dd069a1143d7f3a58ad551815 --- /dev/null +++ b/ATLAS-Extensions/HitsPlugin/src/HitsPlugin.cxx @@ -0,0 +1,270 @@ +// +// Plugin to Generate Hits +// +#include "H5Cpp.h" +#include "FullSimLight/FSLUserActionPlugin.h" +#include "G4UserSteppingAction.hh" +#include "G4UserEventAction.hh" +#include "G4UserRunAction.hh" +#include <iostream> +#include <fstream> +#include "G4Step.hh" +#include "G4Run.hh" +#include <string> +#include <G4Event.hh> +#include <G4String.hh> +#include <map> +#include <mutex> + +//----------------------------------------------------------------------// + +struct Hit{ + float x; + float y; + float z; + unsigned int id; +}; + +std::map<G4String, unsigned int> particle_ids { {"gamma", 1}, {"e-", 2}, {"e+", 2}, {"mu-", 3}, {"mu+", 3}, }; + + +//----------------------------------------------------------------------// + + +class GenerateHitsStep: +public G4UserSteppingAction +{ +public: + + + // Constructor: + GenerateHitsStep(); + + // Destructor: + ~GenerateHitsStep(); + + //Overriding Function + void UserSteppingAction(const G4Step* step) override; + + //Hits vector + std::vector<Hit> hits; + + //Clear Hits + void clearhits(){hits.clear();} + + + }; + +GenerateHitsStep::GenerateHitsStep(){} + +GenerateHitsStep::~GenerateHitsStep() {} + + +void GenerateHitsStep::UserSteppingAction(const G4Step* step){ + + Hit hit_inst; + hit_inst.x = step->GetPreStepPoint()->GetPosition()[0]; + hit_inst.y = step->GetPreStepPoint()->GetPosition()[1]; + hit_inst.z = step->GetPreStepPoint()->GetPosition()[2]; + + //Checking to see if particle is in particle map defined above + if (particle_ids.count(step->GetTrack()->GetParticleDefinition()->GetParticleName())>0) + { + hit_inst.id = particle_ids.find(step->GetTrack()->GetParticleDefinition()->GetParticleName())->second; + } + + //Otherwise assigning it a default particle id of 9 for now. + else + { + hit_inst.id = 9; + } + hits.push_back(hit_inst); + +} + +//----------------------------------------------------------------------// + +class GenerateHitsEvent: +public G4UserEventAction + { +public: + + // Constructor: + GenerateHitsEvent(); + + // Destructor: + ~GenerateHitsEvent(); + + //Overriding Function + void EndOfEventAction(const G4Event* evt) override; + + //Set Stepping Action + void SetSteppingAction(GenerateHitsStep* stepact){step = stepact;} + + //Set file + void assignfile(H5::H5File &filename){file = &filename;} + + //Set DataType + void assignDataType(H5::CompType &data_type){datatype = &data_type;} + + + + private: + + GenerateHitsStep* step; + unsigned int event_ID; + std::vector<Hit> hits; + H5::H5File* file; + H5::CompType* datatype; + std::mutex mutex; + + + + }; + + + +GenerateHitsEvent::GenerateHitsEvent(){} + +GenerateHitsEvent::~GenerateHitsEvent(){} + +void GenerateHitsEvent::EndOfEventAction(const G4Event* evt) +{ + event_ID = evt->GetEventID(); + hits = step->hits; + mutex.lock(); + hsize_t numberOfHits= hits.size(); + H5::DataSpace dataspace(1,&numberOfHits,nullptr); + const std::string datasetName="EVENT-"+std::to_string(event_ID); + H5::DataSet dataset=file->createDataSet(datasetName, *datatype, dataspace); + dataset.write(hits.data(),*datatype); + step->clearhits(); + mutex.unlock(); +} + + +//----------------------------------------------------------------------// + + + + +class GenerateHitsRun: +public G4UserRunAction + { +public: + + // Constructor: + GenerateHitsRun(); + + // Destructor: + ~GenerateHitsRun(); + + //Overriding Function + virtual void BeginOfRunAction(const G4Run*) override final; + virtual void EndOfRunAction(const G4Run*) override final; + + //Setting other User Actions + void SetEventAction(GenerateHitsEvent* evt) {event = evt;} + + + + + private: + + GenerateHitsEvent* event; + static H5::CompType datatype; + static std::string path; + static H5::H5File file; + + + }; + +std::string GenerateHitsRun::path = "hits.h5"; +H5::H5File GenerateHitsRun::file = H5::H5File(path, H5F_ACC_TRUNC); +H5::CompType GenerateHitsRun::datatype = sizeof(Hit); + +GenerateHitsRun::GenerateHitsRun(){} +GenerateHitsRun::~GenerateHitsRun(){} + + +void GenerateHitsRun::BeginOfRunAction(const G4Run*) +{ + if(IsMaster()) + { + + + datatype.insertMember("X", HOFFSET(Hit,x),H5::PredType::NATIVE_FLOAT); + datatype.insertMember("Y", HOFFSET(Hit,y),H5::PredType::NATIVE_FLOAT); + datatype.insertMember("Z", HOFFSET(Hit,z),H5::PredType::NATIVE_FLOAT); + datatype.insertMember("ID", HOFFSET(Hit,id),H5::PredType::NATIVE_UINT); + + } + + event->assignfile(file); + event->assignDataType(datatype); + +} + +void GenerateHitsRun::EndOfRunAction(const G4Run*) +{ + if(IsMaster()) + { + std::cout << "Hits file written at: " << path << std::endl; + } + +} + + + + + + + + + + + +//----------------------------------------------------------------------// + + +class GenerateHitsPlugin:public FSLUserActionPlugin { + +public: + + GenerateHitsPlugin(); + virtual G4UserSteppingAction *getSteppingAction() const final override; + virtual G4UserEventAction *getEventAction() const final override; + virtual G4UserRunAction *getRunAction() const final override; + GenerateHitsEvent* eventaction = new GenerateHitsEvent(); + GenerateHitsStep* stepaction = new GenerateHitsStep(); + GenerateHitsRun* runaction = new GenerateHitsRun(); + +}; + +GenerateHitsPlugin::GenerateHitsPlugin() +{ + +eventaction->SetSteppingAction(stepaction); +runaction->SetEventAction(eventaction); + +} + +G4UserSteppingAction *GenerateHitsPlugin::getSteppingAction() const { + return stepaction; +} + +G4UserEventAction *GenerateHitsPlugin::getEventAction() const { + return eventaction; + +} + +G4UserRunAction *GenerateHitsPlugin::getRunAction() const { + return runaction; + +} + + +extern "C" GenerateHitsPlugin *createGenerateHitsPlugin() { + return new GenerateHitsPlugin(); +} + diff --git a/ATLAS-Extensions/LArCustomSolidExtension/CMakeLists.txt b/ATLAS-Extensions/LArCustomSolidExtension/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..4951093a4dc2bb48567ccded2a94e713795cb7ef --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/CMakeLists.txt @@ -0,0 +1,64 @@ +# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration + +cmake_minimum_required( VERSION 3.12 ) +project( "LArCustomShapeExtensionSolid" ) + + +#Set up the project. Check if we build it with GeoModel or individually +if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) + # I am built as a top-level project. + # Make the root module directory visible to CMake. + list( APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ) + # get global GeoModel version + #include( GeoModelATLAS-version ) + # set the project, with the version taken from the GeoModel parent project + project( "LArCustomShapeExtensionSolid" VERSION 1.0 LANGUAGES CXX ) + # Define color codes for CMake messages + include( cmake_colors_defs ) + # Use the GNU install directory names. + include( GNUInstallDirs ) + # Set a default build type + include( BuildType ) + # Set default build and C++ options + include( configure_cpp_options ) + # Print Build Info on screen + include( PrintBuildInfo ) + # Warn the users about what they are doing + message(STATUS "${BoldGreen}Building ${PROJECT_NAME} individually, as a top-level project.${ColourReset}") + # Set default build and C++ options + include( configure_cpp_options ) + set( CMAKE_FIND_FRAMEWORK "LAST" CACHE STRING + "Framework finding behaviour on macOS" ) + # GeoModel dependencies + find_package( GeoModelCore REQUIRED ) +else() + # I am called from other project with add_subdirectory(). + message( STATUS "Building ${PROJECT_NAME} as part of the root project.") + # Set the project + project( "LArCustomShapeExtensionSolid" VERSION 1.0 LANGUAGES CXX ) +endif() + +# Other project's dependencies. + +find_package( Geant4 REQUIRED ) + +include(${Geant4_USE_FILE}) + +# Find the header and source files. +file( GLOB SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/*.cxx ${CMAKE_CURRENT_SOURCE_DIR}/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/*.cxx ${CMAKE_CURRENT_SOURCE_DIR}/import/Simulation/G4Utilities/Geo2G4/src/*.cxx ${CMAKE_CURRENT_SOURCE_DIR}/LArCustomShapeExtensionSolid/*.cxx) + +# Define include directories +include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/import/Control/CxxUtils ${CMAKE_CURRENT_SOURCE_DIR}/import/DetectorDescription/GeoModel/GeoSpecialShapes ${CMAKE_CURRENT_SOURCE_DIR}/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl ${CMAKE_CURRENT_SOURCE_DIR}/import/Simulation/G4Utilities/Geo2G4 ${CMAKE_CURRENT_SOURCE_DIR}/import/Simulation/G4Utilities/Geo2G4/src ${GEANT4_INCLUDE_DIRS} ) + +add_definitions ( -DPORTABLE_LAR_SHAPE ) + +add_library( LArCustomShapeExtensionSolid SHARED ${SOURCES} ) +target_link_libraries( LArCustomShapeExtensionSolid PUBLIC GeoModelCore::GeoModelKernel ${Geant4_LIBRARIES} ) +set_target_properties( LArCustomShapeExtensionSolid PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} ) + +install( TARGETS LArCustomShapeExtensionSolid + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT Runtime + NAMELINK_COMPONENT Development ) diff --git a/ATLAS-Extensions/LArCustomSolidExtension/LArCustomShapeExtensionSolid/LArCustomShapeExtensionSolid.cxx b/ATLAS-Extensions/LArCustomSolidExtension/LArCustomShapeExtensionSolid/LArCustomShapeExtensionSolid.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4ff2f11041ddb2155d6b1099b5016a9c58c3a361 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/LArCustomShapeExtensionSolid/LArCustomShapeExtensionSolid.cxx @@ -0,0 +1,196 @@ +#include "GeoModelKernel/GeoVG4ExtensionSolid.h" +#include "GeoModelKernel/GeoUnidentifiedShape.h" +#include "LArWheelSolid_type.h" +#include "LArWheelSolid.h" +#include "LArWheelSliceSolid.h" +#include "LArWheelSolid_type.h" +#include "GeoSpecialShapes/EMECData.h" +#include <iostream> +class LArCustomShapeExtensionSolid:public GeoVG4ExtensionSolid { + +public: + + + //Constructor: + LArCustomShapeExtensionSolid(); + + //Destructor: + virtual ~LArCustomShapeExtensionSolid(); + + //Convert to G4 + G4VSolid *newG4Solid(GeoUnidentifiedShape const*) const; + +private: + + typedef std::map<std::string, G4VSolid*,std::less<std::string> > CustomSolidMap; + mutable CustomSolidMap customSolids; + +}; + +//Constructor: +LArCustomShapeExtensionSolid::LArCustomShapeExtensionSolid() { + std::cout << "HELLO from LArCustomShapeExtensionSolid" << std::endl; +} + //Destructor: +LArCustomShapeExtensionSolid::~LArCustomShapeExtensionSolid() { + std::cout << "GOODBYE from LArCustomShapeExtensionSolid" << std::endl; +} + +G4VSolid *LArCustomShapeExtensionSolid::newG4Solid(GeoUnidentifiedShape const* customShape) const{ + + typedef std::pair<LArWheelSolid_t, int> LArWheelSolidDef_t; + typedef std::map<std::string, LArWheelSolidDef_t> TypeMap; + static const TypeMap types = { + /* entries w/o explicit Pos/Neg kept for backward compatibility */ + { "LAr::EMEC::InnerWheel::Absorber", {InnerAbsorberWheel, 1} }, + { "LAr::EMEC::InnerWheel::Electrode", {InnerElectrodWheel, 1} }, + { "LAr::EMEC::InnerWheel::Glue", {InnerGlueWheel, 1} }, + { "LAr::EMEC::InnerWheel::Lead", {InnerLeadWheel, 1} }, + + { "LAr::EMEC::OuterWheel::Absorber", {OuterAbsorberWheel, 1} }, + { "LAr::EMEC::OuterWheel::Electrode", {OuterElectrodWheel, 1} }, + { "LAr::EMEC::OuterWheel::Glue", {OuterGlueWheel, 1} }, + { "LAr::EMEC::OuterWheel::Lead", {OuterLeadWheel, 1} }, + + { "LAr::EMEC::Pos::InnerWheel::Absorber", {InnerAbsorberWheel, 1} }, + { "LAr::EMEC::Pos::InnerWheel::Electrode", {InnerElectrodWheel, 1} }, + { "LAr::EMEC::Pos::InnerWheel::Glue", {InnerGlueWheel, 1} }, + { "LAr::EMEC::Pos::InnerWheel::Lead", {InnerLeadWheel, 1} }, + + { "LAr::EMEC::Pos::OuterWheel::Absorber", {OuterAbsorberWheel, 1} }, + { "LAr::EMEC::Pos::OuterWheel::Electrode", {OuterElectrodWheel, 1} }, + { "LAr::EMEC::Pos::OuterWheel::Glue", {OuterGlueWheel, 1} }, + { "LAr::EMEC::Pos::OuterWheel::Lead", {OuterLeadWheel, 1} }, + + { "LAr::EMEC::Neg::InnerWheel::Absorber", {InnerAbsorberWheel, -1} }, + { "LAr::EMEC::Neg::InnerWheel::Electrode", {InnerElectrodWheel, -1} }, + { "LAr::EMEC::Neg::InnerWheel::Glue", {InnerGlueWheel, -1} }, + { "LAr::EMEC::Neg::InnerWheel::Lead", {InnerLeadWheel, -1} }, + + { "LAr::EMEC::Neg::OuterWheel::Absorber", {OuterAbsorberWheel, -1} }, + { "LAr::EMEC::Neg::OuterWheel::Electrode", {OuterElectrodWheel, -1} }, + { "LAr::EMEC::Neg::OuterWheel::Glue", {OuterGlueWheel, -1} }, + { "LAr::EMEC::Neg::OuterWheel::Lead", {OuterLeadWheel, -1} }, + + { "LAr::EMEC::InnerModule::Absorber", {InnerAbsorberModule, 1} }, + { "LAr::EMEC::InnerModule::Electrode", {InnerElectrodModule, 1} }, + { "LAr::EMEC::OuterModule::Absorber", {OuterAbsorberModule, 1} }, + { "LAr::EMEC::OuterModule::Electrode", {OuterElectrodModule, 1} }, + + { "LAr::EMEC::Pos::InnerCone::Absorber", {InnerAbsorberCone, 1} }, + { "LAr::EMEC::Pos::InnerCone::Electrode", {InnerElectrodCone, 1} }, + { "LAr::EMEC::Pos::InnerCone::Glue", {InnerGlueCone, 1} }, + { "LAr::EMEC::Pos::InnerCone::Lead", {InnerLeadCone, 1} }, + + { "LAr::EMEC::Neg::InnerCone::Absorber", {InnerAbsorberCone, -1} }, + { "LAr::EMEC::Neg::InnerCone::Electrode", {InnerElectrodCone, -1} }, + { "LAr::EMEC::Neg::InnerCone::Glue", {InnerGlueCone, -1} }, + { "LAr::EMEC::Neg::InnerCone::Lead", {InnerLeadCone, -1} }, + + { "LAr::EMEC::Pos::OuterFrontCone::Absorber", {OuterAbsorberFrontCone, 1} }, + { "LAr::EMEC::Pos::OuterFrontCone::Electrode", {OuterElectrodFrontCone, 1} }, + { "LAr::EMEC::Pos::OuterFrontCone::Glue", {OuterGlueFrontCone, 1} }, + { "LAr::EMEC::Pos::OuterFrontCone::Lead", {OuterLeadFrontCone, 1} }, + + { "LAr::EMEC::Neg::OuterFrontCone::Absorber", {OuterAbsorberFrontCone, -1} }, + { "LAr::EMEC::Neg::OuterFrontCone::Electrode", {OuterElectrodFrontCone, -1} }, + { "LAr::EMEC::Neg::OuterFrontCone::Glue", {OuterGlueFrontCone, -1} }, + { "LAr::EMEC::Neg::OuterFrontCone::Lead", {OuterLeadFrontCone, -1} }, + + { "LAr::EMEC::Pos::OuterBackCone::Absorber", {OuterAbsorberBackCone, 1} }, + { "LAr::EMEC::Pos::OuterBackCone::Electrode", {OuterElectrodBackCone, 1} }, + { "LAr::EMEC::Pos::OuterBackCone::Glue", {OuterGlueBackCone, 1} }, + { "LAr::EMEC::Pos::OuterBackCone::Lead", {OuterLeadBackCone, 1} }, + + { "LAr::EMEC::Neg::OuterBackCone::Absorber", {OuterAbsorberBackCone, -1} }, + { "LAr::EMEC::Neg::OuterBackCone::Electrode", {OuterElectrodBackCone, -1} }, + { "LAr::EMEC::Neg::OuterBackCone::Glue", {OuterGlueBackCone, -1} }, + { "LAr::EMEC::Neg::OuterBackCone::Lead", {OuterLeadBackCone, -1} } + + }; + + EMECData data; + EMECGEOMETRY emecgeometry; + EMECWHEELPARAMETERS emecwheelparameters[2]; + EMECPARAMS emecparams; + EMECMAGICNUMBERS emecmagicnumbers; + EMECFAN emecfan; + COLDCONTRACTION coldcontraction; + + emecgeometry.Z0=368.95; + emecgeometry.Z1=369.1; + emecgeometry.DCF=368.9; + emecgeometry.DCRACK=.15; + emecgeometry.RLIMIT=203.4; + emecgeometry.ZSHIFT=4.5; + + emecwheelparameters[0].ETAINT=3.2; + emecwheelparameters[0].ETAEXT=2.5; + emecwheelparameters[0].NABS=256; + emecwheelparameters[0].NACC=6; + emecwheelparameters[1].ETAEXT=1.375; + emecwheelparameters[1].NABS=768; + emecwheelparameters[1].NACC=9; + + emecmagicnumbers.ACTIVELENGTH=510; + emecmagicnumbers.STRAIGHTSTARTSECTION=2; + emecmagicnumbers.REFTOACTIVE=11; + + emecparams.PHIROTATION="off"; + emecparams.SAGGING="off"; + emecparams.INNERSLANTPARAM="default"; + emecparams.OUTERSLANTPARAM="default"; + + coldcontraction.ABSORBERCONTRACTION=0.991; + coldcontraction.ELECTRODEINVCONTRACTION=1.0036256; + + emecfan.LEADTHICKNESSINNER=2.2; + emecfan.LEADTHICKNESSOUTER=1.69; + emecfan.STEELTHICKNESS=0.2; + emecfan.GLUETHICKNESS=0.1; + emecfan.ELECTRODETOTALTHICKNESS=0.275; + + data.emecgeometry.push_back(emecgeometry); + data.emecwheelparameters.push_back(emecwheelparameters[0]); + data.emecwheelparameters.push_back(emecwheelparameters[1]); + data.emecmagicnumbers.push_back(emecmagicnumbers); + data.emecparams.push_back(emecparams); + data.emecfan.push_back(emecfan); + data.coldcontraction.push_back(coldcontraction); + + + + + G4VSolid *theSolid=nullptr; + + if (customShape->name()=="LArCustomShape") { + std::string customName = customShape->asciiData(); + CustomSolidMap::const_iterator it = customSolids.find(customName); + if(it!=customSolids.end()) + theSolid = it->second; + else { + theSolid = nullptr; + + if(customName.find("Slice") != std::string::npos){ + theSolid = new LArWheelSliceSolid(customShape->asciiData(),&data); + } else { + theSolid = new LArWheelSolid(customShape->asciiData(), types.at(customShape->asciiData()).first, types.at(customShape->asciiData()).second,nullptr,&data); + } + if ( nullptr == theSolid ) { + std::string error = std::string("Can't create LArWheelSolid for name ") + customName + " in LArCustomShapeExtensionSolid"; + throw std::runtime_error(error); + } + if(theSolid != nullptr) customSolids[customName] = theSolid; + + } + + } + + return theSolid; +} + + +extern "C" LArCustomShapeExtensionSolid *createLArCustomShapeExtensionSolid() { + + return new LArCustomShapeExtensionSolid; +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/README.md b/ATLAS-Extensions/LArCustomSolidExtension/README.md new file mode 100644 index 0000000000000000000000000000000000000000..0495343967a2ea9838725d5c51d0e6715783b910 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/README.md @@ -0,0 +1,21 @@ +# LArCustomSolid Extension + +This repository contains the LArCustomSolid Extension that describe the ATLAS LAr EMEC custom shape. The LAr EMEC custom shape extension is build starting from a copy of the corresponding code in the [Athena](https://gitlab.cern.ch/atlas/athena) repository. + +## How to build the LArCustomSolid Extension +The LArCustomSolid Extension depends on GeoModel, so you need to install first GeoModel from this [repository](https://gitlab.cern.ch/GeoModelDev/GeoModel). + +```bash +git clone https://gitlab.cern.ch/SolidExtensions/LArCustomSolidExtension.git +cd LArCustomSolidExtension +mkdir build +cd build +cmake ../ -DCMAKE_INSTALL_PREFIX=<path_to_GeoModel_install_dir> +make -j +make install +``` +This will produce a LArCustomSolidExtension.so/dylib library that can be used to build the EMEC detector. + +## How to update the LArCustomSolid Extension + +To keep the code of the LArCustomSolid Extention synchronized with the latest available version in the [Athena](https://gitlab.cern.ch/atlas/athena) repository, just run the autonomous-lar.sh script. diff --git a/ATLAS-Extensions/LArCustomSolidExtension/autonomous-lar.sh b/ATLAS-Extensions/LArCustomSolidExtension/autonomous-lar.sh new file mode 100755 index 0000000000000000000000000000000000000000..1fab024b44cf9c14b78abd813bccd2612ef13a2e --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/autonomous-lar.sh @@ -0,0 +1,64 @@ +#!/bin/bash +mkdir -p import +cd import + +git init +git config core.sparsecheckout true + +echo Control/CxxUtils/CxxUtils/features.h > .git/info/sparse-checkout +echo Control/CxxUtils/CxxUtils/restrict.h >> .git/info/sparse-checkout +echo Control/CxxUtils/CxxUtils/sincos.h >> .git/info/sparse-checkout +echo Control/CxxUtils/CxxUtils/vec.h >> .git/info/sparse-checkout + + +echo DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/EMECData.h >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/toEMECData.h >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/LArWheelCalculatorEnums.h >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/LArWheelCalculator.h >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/vec_parametrized_sincos.h >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/PortableMsgStream/PortableMsgStream.h >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator.cxx >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculatorGeometry.cxx >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorFactory.cxx >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorSaggingOff.cxx >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorSaggingOn.cxx >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/FanCalculatorFactory.cxx >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/ModuleFanCalculator.cxx >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/sincos_poly.cxx >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorFactory.h >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorSaggingOff.h >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorSaggingOn.h >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/FanCalculatorFactory.h >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/ModuleFanCalculator.h >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/WheelFanCalculator.h >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/IFanCalculator.h >> .git/info/sparse-checkout +echo DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/IDistanceCalculator.h >> .git/info/sparse-checkout + + + +echo Simulation/G4Utilities/Geo2G4/src/LArFanSection.cxx >> .git/info/sparse-checkout +echo Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolid.cxx >> .git/info/sparse-checkout +echo Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolidDisToIn.cxx >> .git/info/sparse-checkout +echo Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolidDisToOut.cxx >> .git/info/sparse-checkout +echo Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolidInit.cxx >> .git/info/sparse-checkout +echo Simulation/G4Utilities/Geo2G4/src/LArWheelSolid.cxx >> .git/info/sparse-checkout +echo Simulation/G4Utilities/Geo2G4/src/LArWheelSolidDisToIn.cxx >> .git/info/sparse-checkout +echo Simulation/G4Utilities/Geo2G4/src/LArWheelSolidDisToOut.cxx >> .git/info/sparse-checkout +echo Simulation/G4Utilities/Geo2G4/src/LArWheelSolidInit.cxx >> .git/info/sparse-checkout +echo Simulation/G4Utilities/Geo2G4/src/G4ShiftedCone.cxx >> .git/info/sparse-checkout +echo Simulation/G4Utilities/Geo2G4/src/LArFanSection.h >> .git/info/sparse-checkout +echo Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolid.h >> .git/info/sparse-checkout +echo Simulation/G4Utilities/Geo2G4/src/LArWheelSolid_type.h >> .git/info/sparse-checkout +echo Simulation/G4Utilities/Geo2G4/src/LArWheelSolid.h >> .git/info/sparse-checkout +echo Simulation/G4Utilities/Geo2G4/src/G4ShiftedCone.h >> .git/info/sparse-checkout +echo Simulation/G4Utilities/Geo2G4/src/G4ShiftedCone.icc >> .git/info/sparse-checkout + + +git remote add -f origin https://gitlab.cern.ch/atlas/athena.git +git pull origin master +rm -rf .git + + + + + diff --git a/ATLAS-Extensions/LArCustomSolidExtension/cmake/BuildType.cmake b/ATLAS-Extensions/LArCustomSolidExtension/cmake/BuildType.cmake new file mode 100644 index 0000000000000000000000000000000000000000..14a12a8ccc0c22511e31288d7ab3b4fea69fb561 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/cmake/BuildType.cmake @@ -0,0 +1,28 @@ + +# Author: Marcus D. Hanwell +# Source: https://blog.kitware.com/cmake-and-the-default-build-type/ + +# Set a default build type if none was specified +set(default_build_type "Release") + +# TODO: at the moment, we want to build in Release mode by default, +# even if we build from a Git clone, because that is the default mode +# for our users to get the source code. +# But maybe we will want to change this behavior, later? +# if(EXISTS "${CMAKE_SOURCE_DIR}/.git") +# set(default_build_type "Debug") +# endif() + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + if( COLOR_DEFS ) + message(STATUS "${Blue}INFO: Setting build type to '${default_build_type}' as none was specified.${ColourReset}") + else() + message(STATUS "INFO: Setting build type to '${default_build_type}' as none was specified.") + endif() + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE + STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + diff --git a/ATLAS-Extensions/LArCustomSolidExtension/cmake/PrintBuildInfo.cmake b/ATLAS-Extensions/LArCustomSolidExtension/cmake/PrintBuildInfo.cmake new file mode 100644 index 0000000000000000000000000000000000000000..862a34b45c7506c83a229d7ef71ff604d182acb6 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/cmake/PrintBuildInfo.cmake @@ -0,0 +1,13 @@ +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + +if( COLOR_DEFS ) + message(STATUS "-----") + message(STATUS "${BoldYellow}Building with type: ${CMAKE_BUILD_TYPE}${ColourReset}") + message(STATUS "${BoldYellow}Using C++ standard: ${CMAKE_CXX_STANDARD}${ColourReset}") + message(STATUS "-----") +else() + message(STATUS "-----") + message(STATUS "Building with type: ${CMAKE_BUILD_TYPE}") + message(STATUS "Using C++ standard: ${CMAKE_CXX_STANDARD}") + message(STATUS "-----") +endif() diff --git a/ATLAS-Extensions/LArCustomSolidExtension/cmake/cmake_colors_defs.cmake b/ATLAS-Extensions/LArCustomSolidExtension/cmake/cmake_colors_defs.cmake new file mode 100644 index 0000000000000000000000000000000000000000..b6eea59ba9e72a50754ac0afb36d25cfcac59e09 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/cmake/cmake_colors_defs.cmake @@ -0,0 +1,25 @@ + +# Copyright: "Fraser" (https://stackoverflow.com/users/2556117/fraser) +# CC BY-SA 3.0 +# Source: https://stackoverflow.com/a/19578320/320369 + +if(NOT WIN32) + set( COLOR_DEFS TRUE CACHE BOOL "Define color escape sequences to be used in CMake messages." ) + string(ASCII 27 Esc) + set(ColourReset "${Esc}[m") + set(ColourBold "${Esc}[1m") + set(Red "${Esc}[31m") + set(Green "${Esc}[32m") + set(Yellow "${Esc}[33m") + set(Blue "${Esc}[34m") + set(Magenta "${Esc}[35m") + set(Cyan "${Esc}[36m") + set(White "${Esc}[37m") + set(BoldRed "${Esc}[1;31m") + set(BoldGreen "${Esc}[1;32m") + set(BoldYellow "${Esc}[1;33m") + set(BoldBlue "${Esc}[1;34m") + set(BoldMagenta "${Esc}[1;35m") + set(BoldCyan "${Esc}[1;36m") + set(BoldWhite "${Esc}[1;37m") +endif() diff --git a/ATLAS-Extensions/LArCustomSolidExtension/cmake/configure_cpp_options.cmake b/ATLAS-Extensions/LArCustomSolidExtension/cmake/configure_cpp_options.cmake new file mode 100644 index 0000000000000000000000000000000000000000..9a6cc8a7902de8bd14d412f0ca4fc86a3bc116fc --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/cmake/configure_cpp_options.cmake @@ -0,0 +1,34 @@ + +# +# Set build options and C++ standards and options +# +# This file sets up +# +# CMAKE_BUILD_TYPE +# CMAKE_CXX_STANDARD +# CMAKE_CXX_EXTENSIONS +# CMAKE_CXX_STANDARD_REQUIRED +# +# The options can be overridden at configuration time by using, e.g.: +# `cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_STANDARD=14 ../GeoModelIO` +# on the command line. +# + +# Set default build options. +set( CMAKE_BUILD_TYPE "Release" CACHE STRING "CMake build mode to use" ) +set( CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard used for the build" ) +set( CMAKE_CXX_EXTENSIONS FALSE CACHE BOOL "(Dis)allow using GNU extensions" ) +set( CMAKE_CXX_STANDARD_REQUIRED TRUE CACHE BOOL + "Require the specified C++ standard for the build" ) + +# Setting CMAKE_CXX_FLAGS to avoid "deprecated" warnings +set(CMAKE_CXX_FLAGS "-Wno-deprecated-declarations" ) # very basic +#set(CMAKE_CXX_FLAGS "-Wall -Werror -pedantic-errors -Wno-deprecated-declarations" ) # good enough for a quick, better check +#set(CMAKE_CXX_FLAGS "-Wall -Wextra -Werror -pedantic-errors -Wno-deprecated-declarations" ) # better for a thorough check +#set(CMAKE_CXX_FLAGS "-Wall -Wextra -Werror -pedantic-errors" ) # better for an even more severe check +#set(CMAKE_CXX_FLAGS "-Weverything -Werror -pedantic-errors" ) # not recommended, it warns for really EVERYTHING! + + +# TODO: for Debug and with GCC, do we want to set the flags below by default? +# set( CMAKE_BUILD_TYPE DEBUG ) +# set(CMAKE_CXX_FLAGS "-fPIC -O0 -g -gdwarf-2" ) diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Control/CxxUtils/CxxUtils/features.h b/ATLAS-Extensions/LArCustomSolidExtension/import/Control/CxxUtils/CxxUtils/features.h new file mode 100644 index 0000000000000000000000000000000000000000..e063f476568470b1fd6d0ed2b1d4a557e7870b5e --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Control/CxxUtils/CxxUtils/features.h @@ -0,0 +1,84 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ +/** + * @file CxxUtils/features.h + * @author scott snyder <snyder@bnl.gov> + * @date May, 2018 + * @brief Some additional feature test macros. + */ + +#ifndef CXXUTILS_FEATURES_H +#define CXXUTILS_FEATURES_H + +#include <features.h> + +/// Do we have function multiversioning? GCC and clang > 7 support +/// the target attribute +#if ( defined(__i386__) || defined(__x86_64__) ) && \ + defined(__ELF__) && defined(__GNUC__) && !defined(__CLING__) && \ + !defined(__ICC) && !defined(__COVERITY__) && !defined(__CUDACC__) && \ + !defined(CL_SYCL_LANGUAGE_VERSION) && !defined(SYCL_LANGUAGE_VERSION) && \ + !defined(__HIP__) +# define HAVE_FUNCTION_MULTIVERSIONING 1 +#else +# define HAVE_FUNCTION_MULTIVERSIONING 0 +#endif + +/// Do we have the target_clones attribute? clang does not support it +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && \ + !defined(__COVERITY__) && !defined(__CUDACC__) +# define HAVE_TARGET_CLONES 1 +#else +# define HAVE_TARGET_CLONES 0 +#endif + +/// Do we have support for all GCC intrinsics? +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && \ + !defined(__COVERITY__) && !defined(__CUDACC__) +# define HAVE_GCC_INTRINSICS 1 +#else +# define HAVE_GCC_INTRINSICS 0 +#endif + +/// Do we have the bit-counting intrinsics? +// __builtin_ctz +// __builtin_ctzl +// __builtin_ctzll +// __builtin_clz +// __builtin_clzl +// __builtin_clzll +// __builtin_popcount +// __builtin_popcountl +// __builtin_popcountll +#if defined(__GNUC__) || defined(__clang__) +# define HAVE_BITCOUNT_INTRINSICS 1 +#else +# define HAVE_BITCOUNT_INTRINSICS 0 +#endif + +// Do we have the vector_size attribute for writing explicitly +// vectorized code? +#if (defined(__GNUC__) || defined(__clang__)) && !defined(__CLING__) && \ + !defined(__ICC) && !defined(__COVERITY__) && !defined(__CUDACC__) +#define HAVE_VECTOR_SIZE_ATTRIBUTE 1 +#else +# define HAVE_VECTOR_SIZE_ATTRIBUTE 0 +#endif + +// Do we additionally support the clang +// __builtin_convertvector +// GCC>=9 does +#if HAVE_VECTOR_SIZE_ATTRIBUTE && (defined(__clang__) || (__GNUC__ >= 9)) +#define HAVE_CONVERT_VECTOR 1 +#else +#define HAVE_CONVERT_VECTOR 0 +#endif + +// Do we have mallinfo2? Present in glibc 2.33, +// in which mallinfo is deprecated. +#define HAVE_MALLINFO2 (__GLIBC_PREREQ(2, 33)) + + +#endif // not CXXUTILS_FEATURES_H diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Control/CxxUtils/CxxUtils/restrict.h b/ATLAS-Extensions/LArCustomSolidExtension/import/Control/CxxUtils/CxxUtils/restrict.h new file mode 100644 index 0000000000000000000000000000000000000000..da806b3aa758f62358a2f0c4eeeec3e9826538c4 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Control/CxxUtils/CxxUtils/restrict.h @@ -0,0 +1,35 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. +/* + * Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration. + */ +/** + * @file CxxUtils/restrict.h + * @author scott snyder <snyder@bnl.gov> + * @date May, 2019 + * @brief Macro wrapping the nonstandard restrict keyword. + * + * Use the @c ATH_RESTRICT macro for the non-standard __restrict__ keyword. + */ + + +#ifndef CXXUTILS_RESTRICT_H +#define CXXUTILS_RESTRICT_H + + +#ifndef ATH_HAS_RESTRICT +# if defined(__GNUC__) || defined(__clang__) +# define ATH_HAS_RESTRICT 1 +# else +# define ATH_HAS_RESTRICT 0 +# endif +#endif + + +#if ATH_HAS_RESTRICT +# define ATH_RESTRICT __restrict__ +#else +# define ATH_RESTRICT +#endif + + +#endif // not CXXUTILS_RESTRICT_H diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Control/CxxUtils/CxxUtils/sincos.h b/ATLAS-Extensions/LArCustomSolidExtension/import/Control/CxxUtils/CxxUtils/sincos.h new file mode 100644 index 0000000000000000000000000000000000000000..e6ba0026b44134ff1c4488195064af2ff38c254e --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Control/CxxUtils/CxxUtils/sincos.h @@ -0,0 +1,109 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: sincos.h,v 1.1 2008-11-24 04:34:07 ssnyder Exp $ + +/** + * @file CxxUtils/sincos.h + * @author scott snyder + * @date Nov 2008, from older D0 code. + * @brief Helper to simultaneously calculate sin and cos of the same angle. + */ + + +#ifndef CXXUTILS_SINCOS_H +#define CXXUTILS_SINCOS_H + + +#include <cmath> + + +namespace CxxUtils { + + +/** + * @brief Helper to simultaneously calculate sin and cos of the same angle. + * + * Instantiate an instance of this object, passing the angle to the + * constructor. The sin and cos are then available as the sn and cs + * members. In addition, the apply() method may be used to calculate + * a*sin(x) + b*cos(x). + * + * Implementation notes: + * + * The i386/x87 architecture has an instruction to do this. + * So, on that platform, we use that instruction directly. + * It seems to be a win to use it even if we're using SSE math, + * so we'll use it for x86_64 too. + * Otherwise, we'll use sincos() if it's available (it's a GNU extension). + * Otherwise, just call sin() and cos() separately. + * + * Note that the fsincos instruction only works correctly + * if the input angle is in the range -2^63 ... 2^63. + * This is not likely to be an issue for us. + * + * Why prefer using the fsincos instruction directly to calling + * the sincos() library function? + * + * - It turns out to be a little difficult to ensure that + * sincos() actually gets inlined. In general, one needs -ffast-math + * (which isn't on for standard Atlas builds), but even that's not always + * sufficient. + * + * - The library version includes extra code that we + * don't really need to handle the case where + * abs(angle) > 2^63. (Runtime penalty, though, is + * moving the FPU status word to $eax and one + * taken branch.) + * + * - Most importantly, though, the library function + * takes pointers into which the results are stored. + * Playing with this, i was unable to prevent the + * calculated values from being spilled to memory. + * With the definition used below, we don't necessarily + * spill to memory. A sequence like + * + * sincos sc (ang); + * double a = sc.apply (x, y) + * + * can be calculated entirely in the FPU register file, + * with no spills. + */ +struct sincos +{ + // cppcheck-suppress uninitMemberVar ; false positive + /// Calculate sine and cosine of x. + sincos (double x) +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + // Inline assembly version. Uses x87 FPU. + { __asm __volatile__ ("fsincos\n\t" : "=t" (cs), "=u" (sn) : "0" (x)); } +#elif defined(__USE_GNU) + // Version using the GNU sincos() function. + { ::sincos(x, &sn, &cs); } +#else + // Generic version. + : sn (std::sin (x)), cs (std::cos (x)) {} +#endif + + /// @f$\sin(x)@f$ + double sn; + + /// @f$\cos(x)@f$ + double cs; + + /// @f$a\sin(x) + b\cos(x)@f$ + double apply (double a, double b) const { return a*sn + b*cs; } + + /// @f$a\sin^2(x) + b\sin(x)\cos(x) + c\cos^2(x)@f$ + double apply2 (double a, double b, double c) const + { return a*sn*sn + b*sn*cs + c*cs*cs; } +}; + + +} // namespace CxxUtils + + +#endif //not CXXUTILS_SINCOS_H diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Control/CxxUtils/CxxUtils/vec.h b/ATLAS-Extensions/LArCustomSolidExtension/import/Control/CxxUtils/CxxUtils/vec.h new file mode 100644 index 0000000000000000000000000000000000000000..b53500189ce2c6a8a77ce6538fc4b0fa83f8d9a1 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Control/CxxUtils/CxxUtils/vec.h @@ -0,0 +1,414 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. +/* + * Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration. + */ +/** + * @file CxxUtils/vec.h + * @author scott snyder <snyder@bnl.gov> + * @author Christos Anastopoulos (additional helper methods) + * @date Mar, 2020 + * @brief Vectorization helpers. + * + * gcc and clang provide built-in types for writing vectorized code, + * using the vector_size attribute. This usually results in code + * that is much easier to read and more portable than one would get + * using intrinsics directly. However, it is still non-standard, + * and there are some operations which are kind of awkward. + * + * This file provides some helpers for writing vectorized code + * in C++. + * + * A vectorized type may be named as @c CxxUtils::vec<T, N>. Here @c T is the + * element type, which should be an elementary integer or floating-point type. + * @c N is the number of elements in the vector; it should be a power of 2. + * This will either be a built-in vector type if the @c vector_size + * attribute is supported or a fallback C++ class intended to be + * (mostly) functionally equivalent (see vec_fb.h) + * + * + * The GCC, clang and fallback vector types support: + * ++, --, +,-,*,/,%, =, &,|,^,~, >>,<<, !, &&, ||, + * ==, !=, >, <, >=, <=, =, sizeof and Initialization from brace-enclosed lists + * + * Furthermore the GCC and clang vector types support the ternary operator. + * + * We also support some additional operations. + * + * Deducing useful types: + * + * - @c CxxUtils::vec_type_t<VEC> is the element type of @c VEC. + * - @c CxxUtils::vec_mask_type_t<VEC> is the vector type return by relational + * operations. + * + * Deducing the num of elements in a vectorized type: + * + * - @c CxxUtils::vec_size<VEC>() is the number of elements in @c VEC. + * - @c CxxUtils::vec_size(const VEC&) is the number of elements in @c VEC. + * + * Additional Helpers for common SIMD operations: + * + * - @c CxxUtils::vbroadcast (VEC& v, T x) initializes each element of + * @c v with @c x. + * - @c CxxUtils::vload (VEC& dst, const vec_type_t<VEC>* src) + * loads elements from @c src + * to @c dst + * - @c CxxUtils::vstore (vec_type_t<VEC>* dst, const VEC& src) + * stores elements from @c src + * to @c dst + * - @c CxxUtils::vselect (VEC& dst, const VEC& a, const VEC& b, const + * vec_mask_type_t<VEC>& mask) copies elements + * from @c a or @c b, depending + * on the value of @c mask to @c dst. + * dst[i] = mask[i] ? a[i] : b[i] + * - @c CxxUtils::vmin (VEC& dst, const VEC& a, const VEC& b) + * copies to @c dst[i] the min(a[i],b[i]) + * - @c CxxUtils::vmax (VEC& dst, const VEC& a, const VEC& b) + * copies to @c dst[i] the max(a[i],b[i]) + * - @c CxxUtils::vconvert (VEC1& dst, const VEC2& src) + * Fills @c dst with the result of a + * static_cast of every element of @c src + * to the element type of dst. + * dst[i] = static_cast<vec_type_t<VEC1>>(src[i]) + * + * Functions that construct a permutation of elements from one or two vectors + * and return a vector of the same type as the input vector(s). + * The mask has the same element count as the vectors. + * Intentionally kept compatible with gcc's _builtin_shuffle. + * If we move to gcc>=12 we could unify with clang's _builtin_shuffle_vector + * and relax some of these requirements + * + * - @c CxxUtils::vpermute<mask> (VEC& dst, const VEC& src) + * Fills dst with permutation of src + * according to mask. + * @c mask is a list of integers that specifies the elements + * that should be extracted and returned in @c src. + * dst[i] = src[mask[i]] where mask[i] is the ith integer + * in the @c mask. + * + * - @c CxxUtils::vpermute2<mask> (VEC& dst, const VEC& src1,const VEC& src2) + * Fills @c dst with permutation of @c src1 and @c src2 + * according to @c mask. + * @c mask is a list of integers that specifies the elements + * that should be extracted from @c src1 and @c src2. + * An index i in the interval [0,N) indicates that element number i + * from the first input vector should be placed in the + * corresponding position in the result vector. + * An index in the interval [N,2N) + * indicates that the element number i-N + * from the second input vector should be placed + * in the corresponding position in the result vector. + * + * In terms of expected performance it might be advantageous to + * use vector types that fit the size of the ISA. + * e.g 128 bit wide for SSE, 256 wide for AVX. + * + * Specifying a combination that is not valid for the current architecture + * causes the compiler to synthesize the instructions using a narrower mode. + * + * Consider using Function Multiversioning (CxxUtils/features.h) + * if you really need to target efficiently multiple ISAs. + */ + +#ifndef CXXUTILS_VEC_H +#define CXXUTILS_VEC_H + +#include "CxxUtils/features.h" +#include <cstdlib> +#include <cstring> +#include <type_traits> + + +// Define @c WANT_VECTOR_FALLBACK prior to including this file to +// make the fallback class @c vec_fb visible, even if we support the +// built-in type. +// Intended for testing. +#ifndef WANT_VECTOR_FALLBACK +# define WANT_VECTOR_FALLBACK 0 +#endif + +#if (!HAVE_VECTOR_SIZE_ATTRIBUTE) || WANT_VECTOR_FALLBACK!=0 +#include "CxxUtils/vec_fb.h" +#endif // !HAVE_VECTOR_SIZE_ATTRIBUTE || WANT_VECTOR_FALLBACK + +namespace CxxUtils { + + +/** + * @brief check the type and the size of the vector. + * Choose between the built-in (if available or + * fallback type. + */ +template <typename T, size_t N> +struct vec_typedef{ + static_assert((N & (N-1)) == 0, "N must be a power of 2."); + static_assert(std::is_arithmetic_v<T>, "T not an arithmetic type"); + +#if HAVE_VECTOR_SIZE_ATTRIBUTE + + using type __attribute__ ((vector_size(N*sizeof(T)))) = T; + +#else + + using type vec_fb<T, N>; + +#endif +}; + +/** + * @brief Define a nice alias for the vectorized type + */ +template <typename T, size_t N> +using vec = typename vec_typedef<T,N>::type; + +/** + * @brief Deduce the element type from a vectorized type. + */ +template <class VEC> +struct vec_type +{ + // Requires c++20. + //typedef typename std::invoke_result< decltype([](const VEC& v){return v[0];}), VEC& >::type type; + + // Works in c++17. + static auto elt (const VEC& v) -> decltype( v[0] ); + typedef typename std::invoke_result< decltype(elt), const VEC& >::type type1; + typedef std::remove_cv_t<std::remove_reference_t<type1> > type; +}; + +/** + * @brief Define a nice alias for the element type of a vectorized type + */ +template<class VEC> +using vec_type_t = typename vec_type<VEC>::type; + +/** + * @brief Deduce the type of the mask returned by relational operations, + * for a vectorized type. + */ +template<class VEC> +struct vec_mask_type +{ + static auto maskt(const VEC& v1, const VEC& v2) -> decltype(v1 < v2); + typedef + typename std::invoke_result<decltype(maskt), const VEC&, const VEC&>::type type1; + typedef std::remove_cv_t<std::remove_reference_t<type1>> type; +}; + +/** + * @brief Define a nice alias for the mask type for a vectorized type. + */ +template<class VEC> +using vec_mask_type_t = typename vec_mask_type<VEC>::type; + +/** + * @brief Return the number of elements in a vectorized type. + */ +template<class VEC> +inline constexpr size_t +vec_size() +{ + typedef vec_type_t<VEC> ELT; + return sizeof(VEC) / sizeof(ELT); +} + +/** + * @brief Return the number of elements in a vectorized type. + */ +template<class VEC> +inline constexpr size_t +vec_size(const VEC&) +{ + typedef vec_type_t<VEC> ELT; + return sizeof(VEC) / sizeof(ELT); +} + +/** + * @brief Copy a scalar to each element of a vectorized type. + */ +template<typename VEC, typename T> +inline void +vbroadcast(VEC& v, T x) +{ +#if !HAVE_VECTOR_SIZE_ATTRIBUTE || WANT_VECTOR_FALLBACK + constexpr size_t N = CxxUtils::vec_size<VEC>(); + for (size_t i = 0; i < N; ++i) { + v[i] = x; + } +#else + // using - to avoid sign conversions. + v = x - VEC{ 0 }; +#endif +} + +/* + * @brief load elements from memory address src (C-array) + * to a vectorized type dst. + * Used memcpy to avoid alignment issues + */ +template<typename VEC> +inline void +vload(VEC& dst, vec_type_t<VEC> const* src) +{ + std::memcpy(&dst, src, sizeof(VEC)); +} + +/* + * @brief store elements from a vectorized type src to + * to a memory address dst (C-array). + * Uses memcpy to avoid alignment issues + */ +template<typename VEC> +inline void +vstore(vec_type_t<VEC>* dst, const VEC& src) +{ + std::memcpy(dst, &src, sizeof(VEC)); +} + +/* + * @brief select elements based on a mask + * Fill dst according to + * dst[i] = mask[i] ? a[i] : b[i] + */ +template<typename VEC> +inline void +vselect(VEC& dst, const VEC& a, const VEC& b, const vec_mask_type_t<VEC>& mask) +{ +#if !HAVE_VECTOR_SIZE_ATTRIBUTE || WANT_VECTOR_FALLBACK + constexpr size_t N = vec_size<VEC>(); + for (size_t i = 0; i < N; ++i) { + dst[i] = mask[i] ? a[i] : b[i]; + } +#else + dst = mask ? a : b; +#endif +} + +/* + * @brief vectorized min. + * copies to @c dst[i] the min(a[i],b[i]) + */ +template<typename VEC> +inline void +vmin(VEC& dst, const VEC& a, const VEC& b) +{ +#if !HAVE_VECTOR_SIZE_ATTRIBUTE || WANT_VECTOR_FALLBACK + constexpr size_t N = vec_size<VEC>(); + for (size_t i = 0; i < N; ++i) { + dst[i] = a[i] < b[i] ? a[i] : b[i]; + } +#else + dst = a < b ? a : b; +#endif +} + +/* + * @brief vectorized max. + * copies to @c dst[i] the max(a[i],b[i]) + */ +template<typename VEC> +inline void +vmax(VEC& dst, const VEC& a, const VEC& b) +{ +#if !HAVE_VECTOR_SIZE_ATTRIBUTE || WANT_VECTOR_FALLBACK + constexpr size_t N = vec_size<VEC>(); + for (size_t i = 0; i < N; ++i) { + dst[i] = a[i] > b[i] ? a[i] : b[i]; + } +#else + dst = a > b ? a : b; +#endif +} + +template<typename VEC1, typename VEC2> +inline void +vconvert(VEC1& dst, const VEC2& src) +{ + static_assert((vec_size<VEC1>() == vec_size<VEC2>()), + "vconvert dst and src have different number of elements"); + +#if !HAVE_CONVERT_VECTOR || WANT_VECTOR_FALLBACK + typedef vec_type_t<VEC1> ELT; + constexpr size_t N = vec_size<VEC1>(); + for (size_t i = 0; i < N; ++i) { + dst[i] = static_cast<ELT>(src[i]); + } +#else + dst = __builtin_convertvector(src, VEC1); +#endif +} + +/** + * @brief Helper for static asserts for argument packs + */ +namespace bool_pack_helper { +template<bool...> +struct bool_pack; +template<bool... bs> +using all_true = std::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>; +} +/** + * @brief vpermute function. + * move any element of a vector src + * into any or multiple position inside dst. + */ +template<size_t... Indices, typename VEC> +inline void +vpermute(VEC& dst, const VEC& src) +{ + + constexpr size_t N = vec_size<VEC>(); + static_assert((sizeof...(Indices) == N), + "vpermute number of indices different than vector size"); + static_assert( + bool_pack_helper::all_true<(Indices >= 0 && Indices < N)...>::value, + "vpermute value of a mask index is outside the allowed range"); + +#if !HAVE_VECTOR_SIZE_ATTRIBUTE || WANT_VECTOR_FALLBACK + dst = VEC{ src[Indices]... }; +#elif defined(__clang__) + dst = __builtin_shufflevector(src, src, Indices...); +#else // gcc + dst = __builtin_shuffle(src, vec_mask_type_t<VEC>{ Indices... }); +#endif +} + +/** + * @brief vpermute2 function. + * move any element of a vector src + * into any or multiple position inside dst. + */ +template<size_t... Indices, typename VEC> +inline void +vpermute2(VEC& dst, const VEC& src1, const VEC& src2) +{ + constexpr size_t N = vec_size<VEC>(); + static_assert( + (sizeof...(Indices) == N), + "vpermute2 number of indices different than vector size"); + static_assert( + bool_pack_helper::all_true<(Indices >= 0 && Indices < 2 * N)...>::value, + "vpermute2 value of a mask index is outside the allowed range"); + +#if !HAVE_VECTOR_SIZE_ATTRIBUTE || WANT_VECTOR_FALLBACK + VEC tmp; + size_t pos{0}; + for (auto index: { Indices... }) { + if (index < N) { + tmp[pos] = src1[index]; + } else { + tmp[pos] = src2[index - N]; + } + ++pos; + } + dst = tmp; +#elif defined(__clang__) + dst = __builtin_shufflevector(src1, src2, Indices...); +#else // gcc + dst = __builtin_shuffle(src1, src2, vec_mask_type_t<VEC>{ Indices... }); +#endif +} + + +} // namespace CxxUtils + +#endif // not CXXUTILS_VEC_H diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/EMECData.h b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/EMECData.h new file mode 100644 index 0000000000000000000000000000000000000000..4daeff027b4b9506306271516ee8655de07428f7 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/EMECData.h @@ -0,0 +1,141 @@ +/* + Copyright (C) 2022 CERN for the benefit of the ATLAS collaboration +*/ + + +//--------------------------------------------------------------- +// +// Data structures which determine properties (such as geometry) +// of the EMEC detector in ATLAS. May be filled by the database +// +//---------------------------------------------------------------- + +#ifndef EMEC_DATA_H +#define EMEC_DATA_H +#include <string> +#include <vector> + + +struct EMECGEOMETRY { + double EFIELD ; + double MLGAP ; + double SABL ; + double SBAR ; + double SBRN ; + double SCRB ; + double Z1 ; + double Z0 ; + double DCF ; + double RLIMIT ; + double EPS ; + double RHOIN ; + double RCKP ; + double ETOT ; + double EKAP ; + double ECU ; + double EPREP ; + double EINOX ; + int NLAYER; + double RMIN ; + double RMAX ; + double DZENDE ; + double ZORIG ; + double DCRACK ; + double DZPLA ; + double DZDSE ; + double DZDSM ; + double DZDSI ; + int NUREG ; + double DETA_0 ; + double DETA_1 ; + double DETA_2 ; + double DETA_3 ; + double DETA_4 ; + double DETA_5 ; + double DETA_6 ; + double DETA_7 ; + double DETA_8 ; + double DETA_9 ; + double DETA_10 ; + double DPHI_0 ; + double DPHI_1 ; + double DPHI_2 ; + double DPHI_3 ; + double DPHI_4 ; + double DPHI_5 ; + double DPHI_6 ; + double DPHI_7 ; + double DPHI_8 ; + double DPHI_9 ; + double DPHI_10 ; + double ETASTR_0 ; + double ETASTR_1 ; + double ETASTR_2 ; + double ETASTR_3 ; + double ETASTR_4 ; + double ETASTR_5 ; + double ETASTR_6 ; + double EMHIT ; + double EMDIGI ; + double GAP0 ; + double ZSHIFT ; + +}; + +struct EMECPARAMS { + std::string PHIROTATION; + std::string SAGGING; + std::string INNERSLANTPARAM; + std::string OUTERSLANTPARAM; +}; + + +struct EMECWHEELPARAMETERS { + int IWHEEL; + int NABS; + int NACC; + double ETAINT; + double ETAEXT; + int NWSAMP; +}; + + +struct EMECMAGICNUMBERS { + double STRAIGHTSTARTSECTION; + double FOCALTOREF ; + double REFTOACTIVE ; + double ACTIVELENGTH ; + double REFTOPRESAMPLER; + double PRESAMPLERLENGTH; + +}; + +struct COLDCONTRACTION { + double ABSORBERCONTRACTION; + double G10RINGCONTRACTION; + double MOTHERBOARDCONTRACTION; + double CABLECONTRACTION; + double COLDWINDOWCONTRACTION; + double ELECTRODEINVCONTRACTION; +}; + +struct EMECFAN { + double LEADTHICKNESSINNER; + double LEADTHICKNESSOUTER; + double STEELTHICKNESS; + double GLUETHICKNESS; + double ELECTRODETOTALTHICKNESS; +}; + + +struct EMECData { + std::vector<EMECGEOMETRY> emecgeometry; + std::vector<EMECPARAMS> emecparams; + std::vector<EMECWHEELPARAMETERS> emecwheelparameters; + std::vector<EMECMAGICNUMBERS> emecmagicnumbers; + std::vector<COLDCONTRACTION> coldcontraction; + std::vector<EMECFAN> emecfan; +}; + +#endif + diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/LArWheelCalculator.h b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/LArWheelCalculator.h new file mode 100644 index 0000000000000000000000000000000000000000..906057ecf49909ee1008e4787971ee58f2b2506a --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/LArWheelCalculator.h @@ -0,0 +1,247 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef GEOSPECIALSHAPES_LARWHEELCALCULATOR_H +#define GEOSPECIALSHAPES_LARWHEELCALCULATOR_H + +#include <vector> + +// FMV and other checks +#ifndef PORTABLE_LAR_SHAPE +// For athena + #include "CxxUtils/features.h" +#else +// When run outside of Athena + #define HAVE_VECTOR_SIZE_ATTRIBUTE 1 + #ifdef __APPLE__ + #define CXXUTILS_FEATURES_H 1 + #endif +#endif + +#include "CLHEP/Vector/ThreeVector.h" +#if !defined(XAOD_STANDALONE) && !defined(PORTABLE_LAR_SHAPE) + #include "AthenaKernel/CLASS_DEF.h" +#endif // XAOD_STANDALONE + +#if HAVE_VECTOR_SIZE_ATTRIBUTE + #include "vec_parametrized_sincos.h" +#endif +#include "GeoSpecialShapes/LArWheelCalculatorEnums.h" + +#define LARWC_SINCOS_POLY 5 +#define LARWC_DTNF_NEW + +struct EMECData; + +//#define HARDDEBUG + +// Forward declarations +namespace LArWheelCalculator_Impl { + class IDistanceCalculator; + class DistanceCalculatorSaggingOff; + class DistanceCalculatorSaggingOn; + + class IFanCalculator; + class ModuleFanCalculator; + template <typename SaggingType> class WheelFanCalculator; + template <typename SaggingType> class DistanceToTheNeutralFibre_OfFan; +} + +/// @class LArWheelCalculator +/// This class separates some of the geometry details of the LAr +/// endcap. +/// 26-May-2009 AMS: remove all previous comments from here as obsoleted +/// +class LArWheelCalculator +{ + + friend class LArWheelCalculator_Impl::DistanceCalculatorSaggingOff; + friend class LArWheelCalculator_Impl::DistanceCalculatorSaggingOn; + friend class LArWheelCalculator_Impl::ModuleFanCalculator; + template <typename SaggingType> friend class LArWheelCalculator_Impl::WheelFanCalculator; + template <typename SaggingType> friend class LArWheelCalculator_Impl::DistanceToTheNeutralFibre_OfFan; + + public: + + LArWheelCalculator(const EMECData & emecData, LArG4::LArWheelCalculator_t a_wheelType, int zside = 1); + virtual ~LArWheelCalculator(); + + LArWheelCalculator (const LArWheelCalculator&) = delete; + LArWheelCalculator& operator= (const LArWheelCalculator&) = delete; + + static const char *LArWheelCalculatorTypeString(LArG4::LArWheelCalculator_t); + double GetFanHalfThickness(LArG4::LArWheelCalculator_t) const; + + // "Get constant" methods: + double GetWheelThickness() const { return m_WheelThickness; } + double GetdWRPtoFrontFace() const { return m_dWRPtoFrontFace; } + double GetStraightStartSection() const { return m_StraightStartSection; } + virtual LArG4::LArWheelCalculator_t type() const { return m_type; } + // "zShift" is the z-distance (cm) that the EM endcap is shifted + // (due to cabling, etc.) + int GetAtlasZside() const { return m_AtlasZside; } + double zShift() const { return m_zShift; } + double GetFanFoldRadius() const { return m_FanFoldRadius; } + double GetZeroFanPhi() const { return m_ZeroFanPhi; } + int GetNumberOfWaves() const { return m_NumberOfWaves; } + int GetNumberOfHalfWaves() const { return m_NumberOfHalfWaves; } + int GetNumberOfFans() const { return m_NumberOfFans; } + + double GetActiveLength() const { return m_ActiveLength; } + double GetFanStepOnPhi() const { return m_FanStepOnPhi; } + double GetHalfWaveLength() const { return m_HalfWaveLength; } + double GetQuarterWaveLength() const { return m_QuarterWaveLength; } + double GetWheelRefPoint() const { return m_zWheelRefPoint; } + double GetFanHalfThickness() const { return m_FanHalfThickness; } + + bool GetisModule() const { return m_isModule; } + bool GetisElectrode() const { return m_isElectrode; } + bool GetisInner() const { return m_isInner; } + bool GetisBarrette() const { return m_isBarrette; } + bool GetisBarretteCalib() const { return m_isBarretteCalib; } + + double GetWheelInnerRadius(double *) const; + void GetWheelOuterRadius(double *) const; + + double GetElecFocaltoWRP() const { return m_dElecFocaltoWRP; } + // "set constant" method: + + int GetFirstFan() const { return m_FirstFan; } + int GetLastFan() const { return m_LastFan; } + + int GetStartGapNumber() const { return m_ZeroGapNumber; } + void SetStartGapNumber(int n) { m_ZeroGapNumber = n; } + + /// @name geometry methods + /// @{ + + /// Determines the nearest to the input point fan. + /// Rotates point p to the localFan coordinates and returns the + /// fan number to out_fan_number parameter. + double DistanceToTheNearestFan(CLHEP::Hep3Vector &p, int & out_fan_number) const; + + /// Calculates aproximate, probably underestimate, distance to the + /// neutral fibre of the vertical fan. Sign of return value means + /// side of the fan; negative - lower phi. + double DistanceToTheNeutralFibre(const CLHEP::Hep3Vector &p, int fan_number) const; + + CLHEP::Hep3Vector NearestPointOnNeutralFibre(const CLHEP::Hep3Vector &p, + int fan_number) const; + std::vector<double> NearestPointOnNeutralFibre_asVector(const CLHEP::Hep3Vector &p, + int fan_number) const; + int GetPhiGap(const CLHEP::Hep3Vector &p) const { return GetPhiGapAndSide(p).first; } + int PhiGapNumberForWheel(int) const; + std::pair<int, int> GetPhiGapAndSide(const CLHEP::Hep3Vector &p) const; + double AmplitudeOfSurface(const CLHEP::Hep3Vector& P, int side, int fan_number) const; + + /// @} + + private: + LArG4::LArWheelCalculator_t m_type; + + int m_AtlasZside; + bool m_SaggingOn; // ! + bool m_phiRotation; + bool m_slant_use_default; + double m_slant_parametrization[5]; // pol4 + double m_sin_parametrization[7]; // up to pol6 + double m_cos_parametrization[7]; + std::vector<std::vector<double> > m_sagging_parameter; // ! + + double m_ActiveLength; + double m_StraightStartSection; + double m_dWRPtoFrontFace; + double m_HalfGapBetweenWheels; + double m_zWheelRefPoint; + double m_dMechFocaltoWRP; + double m_dElecFocaltoWRP; + double m_rOuterCutoff; + double m_eta_hi, m_eta_mid, m_eta_low; + double m_zShift; + + double m_WheelThickness; + double m_HalfWheelThickness; + double m_zWheelFrontFace, m_zWheelBackFace; + + double m_QuarterWaveLength; + double m_HalfWaveLength; + double m_FanFoldRadius; + double m_ZeroFanPhi; + double m_ZeroFanPhi_ForDetNeaFan; + double m_FanStepOnPhi; + int m_NumberOfWaves; + int m_NumberOfHalfWaves; + int m_NumberOfFans; + //int m_HalfNumberOfFans; removed because unused. DM 2015-07-30 + double m_FanHalfThickness; + int m_ZeroGapNumber; + int m_FirstFan; + int m_LastFan; + + bool m_isModule; + bool m_isElectrode; + bool m_isInner; + bool m_isBarrette; + bool m_isBarretteCalib; + + + double m_leadThicknessInner; + double m_leadThicknessOuter; + double m_steelThickness; + double m_glueThickness; + double m_electrodeTotalThickness; + double m_coldContraction; + double m_electrodeInvContraction; + + + // int m_fan_number; // break thread-safety -> removed DM 2015-07-30 + + void outer_wheel_init(const EMECData &); + void inner_wheel_init(const EMECData &); + void module_init(); + + public: + + /*void set_m_fan_number(const int &fan_number) + { + m_fan_number = fan_number; + if(m_fan_number < 0) m_fan_number += m_NumberOfFans; + m_fan_number += m_ZeroGapNumber; + if(m_fan_number >= m_NumberOfFans) m_fan_number -= m_NumberOfFans; + }*/ + int adjust_fan_number(int fan_number) const { + int res_fan_number = fan_number; + if(res_fan_number < 0) res_fan_number += m_NumberOfFans; + res_fan_number += m_ZeroGapNumber; + if(res_fan_number >= m_NumberOfFans) res_fan_number -= m_NumberOfFans; + return res_fan_number; + } + + /// Calculates wave slant angle using parametrization for current wheel + /// for given distance from calorimeter axis + double parameterized_slant_angle(double) const; + + private: + + void parameterized_sincos(const double, double &, double &) const; + void parameterized_sin(const double, double &, double &) const; + + private: + + LArWheelCalculator_Impl::IDistanceCalculator *m_distanceCalcImpl; + LArWheelCalculator_Impl::IFanCalculator *m_fanCalcImpl; + void fill_sincos_parameterization(); +#if HAVE_VECTOR_SIZE_ATTRIBUTE + vsincos_par m_vsincos_par{}; +#endif + +}; + +#if !defined(XAOD_STANDALONE) && !defined(PORTABLE_LAR_SHAPE) + //using the macro below we can assign an identifier (and a version) + //This is required and checked at compile time when you try to record/retrieve + CLASS_DEF(LArWheelCalculator , 900345678 , 1) +#endif // XAOD_STANDALONE + +#endif // GEOSPECIALSHAPES_LARWHEELCALCULATOR_H diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/LArWheelCalculatorEnums.h b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/LArWheelCalculatorEnums.h new file mode 100644 index 0000000000000000000000000000000000000000..dcea707a7ec26374f55280cbec8a6dc8fa7d546f --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/LArWheelCalculatorEnums.h @@ -0,0 +1,25 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef GEOSPECIALSHAPES_LARWHEELCALCULATORENUMS_H +#define GEOSPECIALSHAPES_LARWHEELCALCULATORENUMS_H + +namespace LArG4 { + + enum LArWheelCalculator_t { + InnerAbsorberWheel, OuterAbsorberWheel, + InnerElectrodWheel, OuterElectrodWheel, + InnerAbsorberModule, OuterAbsorberModule, + InnerElectrodModule, OuterElectrodModule, + BackInnerBarretteWheel, BackOuterBarretteWheel, + BackInnerBarretteWheelCalib, BackOuterBarretteWheelCalib, + BackInnerBarretteModule, BackOuterBarretteModule, + BackInnerBarretteModuleCalib, BackOuterBarretteModuleCalib, + InnerGlueWheel, OuterGlueWheel, + InnerLeadWheel, OuterLeadWheel + }; + + struct ROOT6_NamespaceAutoloadHook_WheelCalc{}; +} +#endif diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/toEMECData.h b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/toEMECData.h new file mode 100644 index 0000000000000000000000000000000000000000..f149078ad9da6673899d1cb831026e3c557c5d58 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/toEMECData.h @@ -0,0 +1,166 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +*/ +#ifndef _TO_EMEC_DATA_H +#define _TO_EMEC_DATA_H +#include "GeoSpecialShapes/EMECData.h" +class IRDBAccessSvc; +class DecodeVersionKey; +#include <iostream> +// This code is inline in order to be inoffensive in environments +// that do not link to the full ATLAS software. Link dependencies +// then only arise when the routine is actually needed. + +inline EMECData toEMECData(IRDBAccessSvc *rdbAccess, const DecodeVersionKey &larVersionKey) { + + EMECData data; + + // Little lambda function here: retreive recordset and fall back to default version if empty: + auto getRecordsetPtr=[rdbAccess] (const std::string& node, const std::string& tag, const std::string& tag2node,const std::string & fallbackTag2Node) { + + // try with specified tag/node + IRDBRecordset_ptr ptr=rdbAccess->getRecordsetPtr(node,tag, tag2node); + // if failure, try with fallback tag/node + if (ptr->size()==0) { + ptr=rdbAccess->getRecordsetPtr(node,fallbackTag2Node); + } + return ptr; + }; + + + IRDBRecordset_ptr emecGeometry = getRecordsetPtr("EmecGeometry", larVersionKey.tag(),larVersionKey.node(),"EmecGeometry-00"); + IRDBRecordset_ptr emecMagicNumbers = getRecordsetPtr("EmecMagicNumbers", larVersionKey.tag(), larVersionKey.node(),"EmecMagicNumbers-00"); + IRDBRecordset_ptr emecParams = getRecordsetPtr("EmecParams", larVersionKey.tag(), larVersionKey.node(),"EMECParams-00"); + IRDBRecordset_ptr emecWheelParameters = getRecordsetPtr("EmecWheelParameters", larVersionKey.tag(), larVersionKey.node(),"EmecWheelParameters-00"); + IRDBRecordset_ptr emecFan = getRecordsetPtr("EmecFan", larVersionKey.tag(), larVersionKey.node(),"EmecFan-00"); + IRDBRecordset_ptr coldContraction = getRecordsetPtr("ColdContraction", larVersionKey.tag(), larVersionKey.node(),"ColdContraction-00"); + + + for (size_t i=0;i<emecParams->size();i++) { + EMECPARAMS emecparams; + emecparams.PHIROTATION=(*emecParams)[i]->getString("PHIROTATION"); + emecparams.SAGGING=(*emecParams)[i]->getString("SAGGING"); + emecparams.INNERSLANTPARAM=(*emecParams)[i]->getString("INNERSLANTPARAM"); + emecparams.OUTERSLANTPARAM=(*emecParams)[i]->getString("OUTERSLANTPARAM"); + data.emecparams.push_back(emecparams); + } + + + for (size_t i=0;i<emecWheelParameters->size();i++) { + EMECWHEELPARAMETERS emecwheelparameters; + emecwheelparameters.IWHEEL=(*emecWheelParameters)[i]->getInt("IWHEEL"); + emecwheelparameters.NABS=(*emecWheelParameters)[i]->getInt("NABS"); + emecwheelparameters.NACC=(*emecWheelParameters)[i]->getInt("NACC"); + emecwheelparameters.ETAINT=(*emecWheelParameters)[i]->getDouble("ETAINT"); + emecwheelparameters.ETAEXT=(*emecWheelParameters)[i]->getDouble("ETAEXT"); + emecwheelparameters.NWSAMP=(*emecWheelParameters)[i]->getInt("NWSAMP"); + data.emecwheelparameters.push_back(emecwheelparameters); + } + + for (size_t i=0;i<emecMagicNumbers->size();i++) { + EMECMAGICNUMBERS emecmagicnumbers; + emecmagicnumbers.STRAIGHTSTARTSECTION=(*emecMagicNumbers)[i]->getDouble("STRAIGHTSTARTSECTION"); + emecmagicnumbers.FOCALTOREF=(*emecMagicNumbers)[i]->getDouble("FOCALTOREF"); + emecmagicnumbers.REFTOACTIVE=(*emecMagicNumbers)[i]->getDouble("REFTOACTIVE"); + emecmagicnumbers.ACTIVELENGTH=(*emecMagicNumbers)[i]->getDouble("ACTIVELENGTH"); + emecmagicnumbers.REFTOPRESAMPLER=(*emecMagicNumbers)[i]->getDouble("REFTOPRESAMPLER"); + emecmagicnumbers.PRESAMPLERLENGTH=(*emecMagicNumbers)[i]->getDouble("PRESAMPLERLENGTH"); + data.emecmagicnumbers.push_back(emecmagicnumbers); + } + + for (size_t i=0;i<emecFan->size();i++) { + EMECFAN emecfan; + emecfan.LEADTHICKNESSINNER=(*emecFan)[i]->getDouble("LEADTHICKNESSINNER"); + emecfan.LEADTHICKNESSOUTER=(*emecFan)[i]->getDouble("LEADTHICKNESSOUTER"); + emecfan.STEELTHICKNESS=(*emecFan)[i]->getDouble("STEELTHICKNESS"); + emecfan.GLUETHICKNESS=(*emecFan)[i]->getDouble("GLUETHICKNESS"); + emecfan.ELECTRODETOTALTHICKNESS=(*emecFan)[i]->getDouble("ELECTRODETOTALTHICKNESS"); + data.emecfan.push_back(emecfan); + } + + + for (size_t i=0;i<coldContraction->size();i++) { + COLDCONTRACTION coldcontraction; + coldcontraction.ABSORBERCONTRACTION=(*coldContraction)[i]->getDouble("ABSORBERCONTRACTION"); + coldcontraction.G10RINGCONTRACTION=(*coldContraction)[i]->getDouble("G10RINGCONTRACTION"); + coldcontraction.MOTHERBOARDCONTRACTION=(*coldContraction)[i]->getDouble("MOTHERBOARDCONTRACTION"); + coldcontraction.CABLECONTRACTION=(*coldContraction)[i]->getDouble("CABLECONTRACTION"); + coldcontraction.COLDWINDOWCONTRACTION=(*coldContraction)[i]->getDouble("COLDWINDOWCONTRACTION"); + coldcontraction.ELECTRODEINVCONTRACTION=(*coldContraction)[i]->getDouble("ELECTRODEINVCONTRACTION"); + data.coldcontraction.push_back(coldcontraction); + } + + + for (size_t i=0;i<emecGeometry->size();i++) { + EMECGEOMETRY emecgeometry; + emecgeometry.EFIELD=(*emecGeometry)[i]->getDouble("EFIELD"); + emecgeometry.MLGAP=(*emecGeometry)[i]->getDouble("MLGAP"); + emecgeometry.SABL=(*emecGeometry)[i]->getDouble("SABL"); + emecgeometry.SBAR=(*emecGeometry)[i]->getDouble("SBAR"); + emecgeometry.SBRN=(*emecGeometry)[i]->getDouble("SBRN"); + emecgeometry.SCRB=(*emecGeometry)[i]->getDouble("SCRB"); + emecgeometry.Z1=(*emecGeometry)[i]->getDouble("Z1"); + emecgeometry.Z0=(*emecGeometry)[i]->getDouble("Z0"); + emecgeometry.DCF=(*emecGeometry)[i]->getDouble("DCF"); + emecgeometry.RLIMIT=(*emecGeometry)[i]->getDouble("RLIMIT"); + emecgeometry.EPS=(*emecGeometry)[i]->getDouble("EPS"); + emecgeometry.RHOIN=(*emecGeometry)[i]->getDouble("RHOIN"); + emecgeometry.RCKP=(*emecGeometry)[i]->getDouble("RCKP"); + emecgeometry.ETOT=(*emecGeometry)[i]->getDouble("ETOT"); + emecgeometry.EKAP=(*emecGeometry)[i]->getDouble("EKAP"); + emecgeometry.ECU=(*emecGeometry)[i]->getDouble("ECU"); + emecgeometry.EPREP=(*emecGeometry)[i]->getDouble("EPREP"); + emecgeometry.EINOX=(*emecGeometry)[i]->getDouble("EINOX"); + emecgeometry.NLAYER=(*emecGeometry)[i]->getInt("NLAYER"); + emecgeometry.RMIN=(*emecGeometry)[i]->getDouble("RMIN"); + emecgeometry.RMAX=(*emecGeometry)[i]->getDouble("RMAX"); + emecgeometry.DZENDE=(*emecGeometry)[i]->getDouble("DZENDE"); + emecgeometry.ZORIG=(*emecGeometry)[i]->getDouble("ZORIG"); + emecgeometry.DCRACK=(*emecGeometry)[i]->getDouble("DCRACK"); + emecgeometry.DZPLA=(*emecGeometry)[i]->getDouble("DZPLA"); + emecgeometry.DZDSE=(*emecGeometry)[i]->getDouble("DZDSE"); + emecgeometry.DZDSM=(*emecGeometry)[i]->getDouble("DZDSM"); + emecgeometry.DZDSI=(*emecGeometry)[i]->getDouble("DZDSI"); + emecgeometry.NUREG=(*emecGeometry)[i]->getInt("NUREG"); + emecgeometry.DETA_0=(*emecGeometry)[i]->getDouble("DETA_0"); + emecgeometry.DETA_1=(*emecGeometry)[i]->getDouble("DETA_1"); + emecgeometry.DETA_2=(*emecGeometry)[i]->getDouble("DETA_2"); + emecgeometry.DETA_3=(*emecGeometry)[i]->getDouble("DETA_3"); + emecgeometry.DETA_4=(*emecGeometry)[i]->getDouble("DETA_4"); + emecgeometry.DETA_5=(*emecGeometry)[i]->getDouble("DETA_5"); + emecgeometry.DETA_6=(*emecGeometry)[i]->getDouble("DETA_6"); + emecgeometry.DETA_7=(*emecGeometry)[i]->getDouble("DETA_7"); + emecgeometry.DETA_8=(*emecGeometry)[i]->getDouble("DETA_8"); + emecgeometry.DETA_9=(*emecGeometry)[i]->getDouble("DETA_9"); + emecgeometry.DETA_10=(*emecGeometry)[i]->getDouble("DETA_10"); + emecgeometry.DPHI_0=(*emecGeometry)[i]->getDouble("DPHI_0"); + emecgeometry.DPHI_1=(*emecGeometry)[i]->getDouble("DPHI_1"); + emecgeometry.DPHI_2=(*emecGeometry)[i]->getDouble("DPHI_2"); + emecgeometry.DPHI_3=(*emecGeometry)[i]->getDouble("DPHI_3"); + emecgeometry.DPHI_4=(*emecGeometry)[i]->getDouble("DPHI_4"); + emecgeometry.DPHI_5=(*emecGeometry)[i]->getDouble("DPHI_5"); + emecgeometry.DPHI_6=(*emecGeometry)[i]->getDouble("DPHI_6"); + emecgeometry.DPHI_7=(*emecGeometry)[i]->getDouble("DPHI_7"); + emecgeometry.DPHI_8=(*emecGeometry)[i]->getDouble("DPHI_8"); + emecgeometry.DPHI_9=(*emecGeometry)[i]->getDouble("DPHI_9"); + emecgeometry.DPHI_10=(*emecGeometry)[i]->getDouble("DPHI_10"); + emecgeometry.ETASTR_0=(*emecGeometry)[i]->getDouble("ETASTR_0"); + emecgeometry.ETASTR_1=(*emecGeometry)[i]->getDouble("ETASTR_1"); + emecgeometry.ETASTR_2=(*emecGeometry)[i]->getDouble("ETASTR_2"); + emecgeometry.ETASTR_3=(*emecGeometry)[i]->getDouble("ETASTR_3"); + emecgeometry.ETASTR_4=(*emecGeometry)[i]->getDouble("ETASTR_4"); + emecgeometry.ETASTR_5=(*emecGeometry)[i]->getDouble("ETASTR_5"); + emecgeometry.ETASTR_6=(*emecGeometry)[i]->getDouble("ETASTR_6"); + emecgeometry.EMHIT=(*emecGeometry)[i]->getDouble("EMHIT"); + emecgeometry.EMDIGI=(*emecGeometry)[i]->getDouble("EMDIGI"); + emecgeometry.GAP0=(*emecGeometry)[i]->getDouble("GAP0"); + emecgeometry.ZSHIFT=(*emecGeometry)[i]->getDouble("ZSHIFT"); + data.emecgeometry.push_back(emecgeometry); + } + + + return data; +} + + +#endif diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/vec_parametrized_sincos.h b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/vec_parametrized_sincos.h new file mode 100644 index 0000000000000000000000000000000000000000..f662fbf1799365a40b320832b6b27166e89259b8 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/GeoSpecialShapes/vec_parametrized_sincos.h @@ -0,0 +1,75 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @brief vectorized version of parametrized sincos + * see ATLASSIM-4753 for details + * @author Miha Muskinja, Chistos Anastopoulos +*/ +#ifndef VEC_PARAMETRIZED_SINCOS_H +#define VEC_PARAMETRIZED_SINCOS_H + +#include "CxxUtils/restrict.h" +#include "CxxUtils/vec.h" +struct vsincos_par +{ + + CxxUtils::vec<double, 4> param_0 = {}; + CxxUtils::vec<double, 4> param_1 = {}; + CxxUtils::vec<double, 4> param_2 = {}; + +#if HAVE_FUNCTION_MULTIVERSIONING +#if defined(__x86_64__) + + __attribute__((target("avx2,fma"))) + + void + evaluate(const double r, + double &ATH_RESTRICT sin_a, + double &ATH_RESTRICT cos_a) const ATH_RESTRICT + { + const double r2 = r * r; + CxxUtils::vec<double, 4> P = r2 * param_0 + param_1; + P = r2 * P + param_2; + CxxUtils::vec<double, 4> P2 = {P[1], P[0], P[3], P[2]}; + CxxUtils::vec<double, 4> res = r * P2 + P; + sin_a = res[0]; + cos_a = res[2]; + } + + __attribute__((target("avx2"))) + + void + eval(const double r, + double &ATH_RESTRICT sin_a, + double &ATH_RESTRICT cos_a) const ATH_RESTRICT + { + const double r2 = r * r; + CxxUtils::vec<double, 4> P = r2 * param_0 + param_1; + P = r2 * P + param_2; + CxxUtils::vec<double, 4> P2 = {P[1], P[0], P[3], P[2]}; + CxxUtils::vec<double, 4> res = r * P2 + P; + sin_a = res[0]; + cos_a = res[2]; + } + + __attribute__((target("default"))) + +#endif // x86 +#endif // FMV + + void + eval(const double r, + double &ATH_RESTRICT sin_a, + double &ATH_RESTRICT cos_a) const ATH_RESTRICT + { + const double r2 = r * r; + CxxUtils::vec<double, 4> P = r2 * param_0 + param_1; + P = r2 * P + param_2; + sin_a = r * P[1] + P[0]; + cos_a = r * P[3] + P[2]; + } +}; + +#endif diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/PortableMsgStream/PortableMsgStream.h b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/PortableMsgStream/PortableMsgStream.h new file mode 100644 index 0000000000000000000000000000000000000000..9017f810a6b0718babd9bc1f7c93ffc47d8f6e95 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/PortableMsgStream/PortableMsgStream.h @@ -0,0 +1,106 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +*/ + +// JFB Feb 2022 +// This is an ersatz message stream class. It directs messages to cout. +// This is not used within Athena. It is for portability (e.g. to FullSimLight). +// + +#ifndef __LArWheelCalculator_Impl_PortableMsgStream_H__ +#define __LArWheelCalculator_Impl_PortableMsgStream_H__ +#ifdef PORTABLE_LAR_SHAPE +#include <iostream> +#include <sstream> +#include <string> + + +namespace MSG { + enum Level {VERBOSE, DEBUG, INFO, WARNING, ERROR, FATAL}; +} + +class PortableMsgStream; +PortableMsgStream& endmsg( PortableMsgStream& s ); + + +class PortableMsgStream { +public: + + PortableMsgStream(const std::string label="",MSG::Level threshold=MSG::INFO,std::ostream & stream=std::cout) : + m_ostream(stream), + m_label(label), + m_threshold(threshold) + { + } + + template<typename T> PortableMsgStream & operator << (const T & t) { + if (m_level>=m_threshold) m_sstream << t; + return *this; + } + + PortableMsgStream& operator<<( PortableMsgStream& ( *t )(PortableMsgStream&)) { + if (t==endmsg) { + if (m_level>=m_threshold) { + return doOutput(); + } + else { + m_ostream.clear(); + return *this; + } + } + return *this; + } + + PortableMsgStream& operator << (MSG::Level level) { + m_level=level; + return *this; + } + + PortableMsgStream & doOutput() { + + switch (m_level) { + case MSG::VERBOSE: + m_ostream << "VERBOSE: "; + break; + case MSG::DEBUG: + m_ostream << "DEBUG : "; + break; + case MSG::INFO: + m_ostream << "INFO : "; + break; + case MSG::WARNING: + m_ostream << "WARNING: "; + break; + case MSG::ERROR: + m_ostream << "ERROR : "; + break; + case MSG::FATAL: + m_ostream << "FATAL : "; + break; + }; + m_ostream << m_label; + m_ostream << m_sstream.str() << std::endl; + m_sstream.str(""); + m_sstream.clear(); + return *this; + } + + +private: + + PortableMsgStream (const PortableMsgStream &) = delete; + PortableMsgStream & operator=(const PortableMsgStream &) = delete; + + std::ostringstream m_sstream; + std::ostream & m_ostream; + const std::string m_label; + MSG::Level m_level; + MSG::Level m_threshold; +}; + +inline PortableMsgStream& endmsg( PortableMsgStream& s ) { return s.doOutput(); } + + +#endif //LAR_PORTABLE_SHAPE +#endif // __LArWheelCalculator_Impl_PortableMsgStream_H__ + diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator.cxx b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator.cxx new file mode 100644 index 0000000000000000000000000000000000000000..41a4cdb44d01bb17150497cb3e7891288d45dfd5 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator.cxx @@ -0,0 +1,534 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +// LArWheelCalculator 19-Apr-2001 Bill Seligman +// 26-May-2009 AMS: remove all previous comments from here as obsoleted + +#include <cmath> +#include <climits> +#include <cassert> +#ifndef PORTABLE_LAR_SHAPE +#include "GaudiKernel/Bootstrap.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/MsgStream.h" +#else +#include "PortableMsgStream/PortableMsgStream.h" +#endif + +#include "GeoSpecialShapes/LArWheelCalculator.h" +#include "GeoSpecialShapes/EMECData.h" + +#include "./LArWheelCalculator_Impl/DistanceCalculatorFactory.h" +#include "./LArWheelCalculator_Impl/FanCalculatorFactory.h" + + +#include "GeoModelKernel/Units.h" + +using namespace GeoModelKernelUnits; + + +// these numbers are taken from DB in constructor, +// hardcoded values here are just for reference +/* + double LArWheelCalculator::zWheelRefPoint = 3689.5*mm; //=endg_z0 + double LArWheelCalculator::dMechFocaltoWRP = 3691. *mm; //=endg_z1 + double LArWheelCalculator::dElecFocaltoWRP = 3689. *mm; //=endg_dcf + double LArWheelCalculator::rOuterCutoff = 2034. *mm; //=endg_rlimit + double LArWheelCalculator::HalfGapBetweenWheels = 0.15*cm; // In DB EMECGEOMETRY.DCRACK + float LArWheelCalculator::m_zShift = 4. *cm; // endg_zshift + double LArWheelCalculator::eta_hi = 3.2; // from EmecWheelParameters + double LArWheelCalculator::eta_mid = 2.5; + double LArWheelCalculator::eta_low = 1.375; +*/ + +// these values are taken from "EMECParams" DB +/* + bool LArWheelCalculator::SaggingOn = false; + bool LArWheelCalculator::phiRotation = false; +*/ + +// these were internal constants, now everything in DB +//const double LArWheelCalculator::s_dWRPtoFrontFace = 11.*mm; +//const double LArWheelCalculator::s_WheelThickness = 514.*mm; +// 2x2mm are to be substracted from value of wheel thickness +// - for straight 2-mm domains at start and finish of absorber +//const double LArWheelCalculator::s_StraightStartSection = 2.*mm; +//const double LArWheelCalculator::s_HalfWheelThickness = s_WheelThickness * 0.5; +//const double LArWheelCalculator::s_WheelThickness_wo_2sss = s_WheelThickness - 2.*s_StraightStartSection; + +static const double default_slant_parametrization[2][5] = { + { -50.069, 0.50073, -0.10127E-02, 0.10390E-05, -0.42176E-09 }, // inner + { -34.254, 0.15528, -0.11670E-03, 0.45018E-07, -0.68473E-11 } //outer +}; + +const char *LArWheelCalculator::LArWheelCalculatorTypeString(LArG4::LArWheelCalculator_t type) +{ + switch(type){ + case LArG4::InnerAbsorberWheel: return("InnerAbsorberWheel"); + case LArG4::OuterAbsorberWheel: return("OuterAbsorberWheel"); + case LArG4::InnerElectrodWheel: return("InnerElectrodWheel"); + case LArG4::OuterElectrodWheel: return("OuterElectrodWheel"); + case LArG4::InnerAbsorberModule: return("InnerAbsorberModule"); + case LArG4::OuterAbsorberModule: return("OuterAbsorberModule"); + case LArG4::InnerElectrodModule: return("InnerElectrodModule"); + case LArG4::OuterElectrodModule: return("OuterElectrodModule"); + case LArG4::BackOuterBarretteWheel: return("BackOuterBarretteWheel"); + case LArG4::BackInnerBarretteWheel: return("BackInnerBarretteWheel"); + case LArG4::BackOuterBarretteModule: return("BackOuterBarretteModule"); + case LArG4::BackInnerBarretteModule: return("BackInnerBarretteModule"); + case LArG4::BackOuterBarretteWheelCalib: return("BackOuterBarretteWheelCalib"); + case LArG4::BackInnerBarretteWheelCalib: return("BackInnerBarretteWheelCalib"); + case LArG4::BackOuterBarretteModuleCalib: return("BackOuterBarretteModuleCalib"); + case LArG4::BackInnerBarretteModuleCalib: return("BackInnerBarretteModuleCalib"); + case LArG4::InnerGlueWheel: return("InnerGlueWheel"); + case LArG4::InnerLeadWheel: return("InnerLeadWheel"); + case LArG4::OuterGlueWheel: return("OuterGlueWheel"); + case LArG4::OuterLeadWheel: return("OuterLeadWheel"); + } + return("unknown"); +} + +LArWheelCalculator::~LArWheelCalculator() { + delete m_distanceCalcImpl; + m_distanceCalcImpl = 0; + delete m_fanCalcImpl; + m_fanCalcImpl = 0; +} + +LArWheelCalculator::LArWheelCalculator(const EMECData & emecData, LArG4::LArWheelCalculator_t a_wheelType, int zside) : + m_type(a_wheelType), + m_AtlasZside(zside), + m_distanceCalcImpl(0), + m_fanCalcImpl(0) +{ + +#ifndef PORTABLE_LAR_SHAPE + // Get pointer to the message service + ISvcLocator* svcLocator = Gaudi::svcLocator(); + IMessageSvc* msgSvc; + StatusCode status = svcLocator->service("MessageSvc", msgSvc); + if(status.isFailure()){ + throw std::runtime_error("LArWheelCalculator constructor: cannot initialze message service"); + } + MsgStream msg(msgSvc, "LArWheelCalculator"); +#else + PortableMsgStream msg("LArWheelCalculator"); +#endif + msg << MSG::VERBOSE << "LArWheelCalculator constructor at " << this + << " (type " << LArWheelCalculatorTypeString(m_type) + << "):" << endmsg; + + + msg << MSG::VERBOSE << "LArWheelCalculator constructor at " << this + << " (type " << LArWheelCalculatorTypeString(m_type) + << "):" << endmsg; + +#ifdef LARWC_DTNF_NEW + msg << MSG::VERBOSE << "compiled with new DTNF" << endmsg; +#endif + + // Access source of detector parameters. + msg << MSG::VERBOSE + << "initializing data members from DB..." << endmsg; + + m_zWheelRefPoint =emecData.emecgeometry[0].Z0*cm; + m_dMechFocaltoWRP =emecData.emecgeometry[0].Z1*cm; + m_dElecFocaltoWRP =emecData.emecgeometry[0].DCF*cm; + m_HalfGapBetweenWheels =emecData.emecgeometry[0].DCRACK*cm; + m_rOuterCutoff =emecData.emecgeometry[0].RLIMIT*cm; + m_zShift =emecData.emecgeometry[0].ZSHIFT*cm; + + + m_eta_hi =emecData.emecwheelparameters[0].ETAINT; + m_eta_mid =emecData.emecwheelparameters[0].ETAEXT; + m_eta_low =emecData.emecwheelparameters[1].ETAEXT; + + + + m_leadThicknessInner=emecData.emecfan[0].LEADTHICKNESSINNER*mm; + m_leadThicknessOuter=emecData.emecfan[0].LEADTHICKNESSOUTER*mm; + m_steelThickness=emecData.emecfan[0].STEELTHICKNESS*mm; + m_glueThickness=emecData.emecfan[0].GLUETHICKNESS*mm; + m_electrodeTotalThickness=emecData.emecfan[0].ELECTRODETOTALTHICKNESS*mm; + m_coldContraction=emecData.coldcontraction[0].ABSORBERCONTRACTION; + m_electrodeInvContraction=emecData.coldcontraction[0].ELECTRODEINVCONTRACTION; + + + + m_ActiveLength =emecData.emecmagicnumbers[0].ACTIVELENGTH*mm; + m_StraightStartSection =emecData.emecmagicnumbers[0].STRAIGHTSTARTSECTION*mm; + m_dWRPtoFrontFace =emecData.emecmagicnumbers[0].REFTOACTIVE*mm; + + + m_WheelThickness = m_ActiveLength + 2.*m_StraightStartSection; + m_HalfWheelThickness = m_WheelThickness * 0.5; + + std::string pr_opt_value=emecData.emecparams[0].PHIROTATION; + std::string sagging_opt_value=emecData.emecparams[0].SAGGING; + + m_phiRotation = pr_opt_value == "g3"? true: false; + + m_zWheelFrontFace = m_dMechFocaltoWRP + m_dWRPtoFrontFace; + m_zWheelBackFace = m_zWheelFrontFace + m_WheelThickness; + + msg << MSG::DEBUG << "... got these values:" << endmsg + << "m_zWheelRefPoint : " << m_zWheelRefPoint / cm << " [cm]" << endmsg + << "m_dMechFocaltoWRP : " << m_dMechFocaltoWRP / cm << " [cm]" << endmsg + << "m_dElecFocaltoWRP : " << m_dElecFocaltoWRP / cm << " [cm]" << endmsg + << "m_HalfGapBetweenWheels : " << m_HalfGapBetweenWheels / cm << " [cm]" << endmsg + << "m_rOuterCutoff : " << m_rOuterCutoff / cm << " [cm]" << endmsg + << "m_zWheelFrontFace : " << m_zWheelFrontFace / cm << " [cm]" << endmsg + << "m_zWheelBackFace : " << m_zWheelBackFace / cm << " [cm]" << endmsg + << "m_zShift : " << m_zShift / cm << " [cm]" << endmsg + << "Phi rotation : " << (m_phiRotation? "true": "false") << "" << endmsg + << "eta wheels limits : " << m_eta_low << ", " << m_eta_mid << ", " << m_eta_hi + << endmsg; + msg << MSG::VERBOSE << "hardcoded constants: " << endmsg + << "m_WheelThickness : " << m_WheelThickness / cm << " [cm]" << endmsg + << "m_dWRPtoFrontFace : " << m_dWRPtoFrontFace / cm << " [cm]" + << endmsg; + + + // Constructor initializes the geometry. + + m_isBarrette = false; + m_isBarretteCalib = false; + m_isModule = false; + m_isElectrode = false; + m_isInner = false; + m_FirstFan = 0; + m_LastFan = 0; + + switch(m_type){ + case LArG4::BackInnerBarretteWheelCalib: + m_isBarretteCalib = true; + /* FALLTHROUGH */ + case LArG4::BackInnerBarretteWheel: + m_isBarrette = true; + m_type = LArG4::InnerAbsorberWheel; + /* FALLTHROUGH */ + case LArG4::InnerAbsorberWheel: + case LArG4::InnerGlueWheel: + case LArG4::InnerLeadWheel: + inner_wheel_init(emecData); + m_ZeroFanPhi = m_FanStepOnPhi * 0.5; + if(m_phiRotation) m_ZeroFanPhi += m_FanStepOnPhi * 0.5; + break; + case LArG4::BackOuterBarretteWheelCalib: + m_isBarretteCalib = true; + /* FALLTHROUGH */ + case LArG4::BackOuterBarretteWheel: + m_isBarrette = true; + m_type = LArG4::OuterAbsorberWheel; + /* FALLTHROUGH */ + case LArG4::OuterAbsorberWheel: + case LArG4::OuterGlueWheel: + case LArG4::OuterLeadWheel: + outer_wheel_init(emecData); + m_ZeroFanPhi = m_FanStepOnPhi * 0.5; + if(m_phiRotation) m_ZeroFanPhi += m_FanStepOnPhi * 0.5; + break; + case LArG4::InnerElectrodWheel: + inner_wheel_init(emecData); + m_ZeroFanPhi = 0; + if(m_phiRotation) m_ZeroFanPhi += m_FanStepOnPhi * 0.5; + m_isElectrode = true; + break; + case LArG4::OuterElectrodWheel: + outer_wheel_init(emecData); + m_ZeroFanPhi = 0; + if(m_phiRotation) m_ZeroFanPhi += m_FanStepOnPhi * 0.5; + m_isElectrode = true; + break; + case LArG4::BackInnerBarretteModuleCalib: + m_isBarretteCalib = true; + /* FALLTHROUGH */ + case LArG4::BackInnerBarretteModule: + m_isBarrette = true; + m_type = LArG4::InnerAbsorberModule; + /* FALLTHROUGH */ + case LArG4::InnerAbsorberModule: + inner_wheel_init(emecData); + module_init(); + m_ZeroFanPhi += m_FanStepOnPhi * 0.5; + // later for all? m_ZeroFanPhi_ForDetNeaFan = m_ZeroFanPhi - m_FanStepOnPhi * 0.5; + break; + case LArG4::BackOuterBarretteModuleCalib: + m_isBarretteCalib = true; + /* FALLTHROUGH */ + case LArG4::BackOuterBarretteModule: + m_isBarrette = true; + m_type = LArG4::OuterAbsorberModule; + /* FALLTHROUGH */ + case LArG4::OuterAbsorberModule: + outer_wheel_init(emecData); + module_init(); + m_ZeroFanPhi += m_FanStepOnPhi * 0.5; + // later for all? m_ZeroFanPhi_ForDetNeaFan = m_ZeroFanPhi - m_FanStepOnPhi * 0.5; + break; + case LArG4::InnerElectrodModule: + inner_wheel_init(emecData); + module_init(); + m_FirstFan ++; + m_isElectrode = true; + break; + case LArG4::OuterElectrodModule: + outer_wheel_init(emecData); + module_init(); + m_FirstFan ++; + m_isElectrode = true; + break; + default: + throw std::runtime_error("LArWheelCalculator constructor:unknown LArWheelCalculator_t"); + } + m_ZeroFanPhi_ForDetNeaFan = m_ZeroFanPhi - m_FanStepOnPhi * 0.5; + m_NumberOfHalfWaves = m_NumberOfWaves * 2; + m_HalfWaveLength = m_ActiveLength / m_NumberOfHalfWaves; + m_QuarterWaveLength = m_HalfWaveLength * 0.5; + //m_HalfNumberOfFans = m_NumberOfFans / 2; + m_FanHalfThickness = GetFanHalfThickness(m_type); + + // Init sagging + // value read above + // std::string sagging_opt_value = (*DB_EMECParams)[0]->getString("SAGGING"); + + msg << MSG::VERBOSE << "SAGGING value = " << sagging_opt_value << endmsg; + + // the same condition is in DistanceCalculatorFactory::Create + m_SaggingOn = (sagging_opt_value != "" && sagging_opt_value != "off")? true: false; + + m_distanceCalcImpl = LArWheelCalculator_Impl::DistanceCalculatorFactory::Create( + sagging_opt_value, this); + if (m_SaggingOn) { + msg << MSG::VERBOSE << "Creating DistanceCalculatorSaggingOn = " << this + << ',' << m_distanceCalcImpl << endmsg; + } else { + msg << MSG::VERBOSE << "Creating DistanceCalculatorSaggingOff = " << this + << ',' << m_distanceCalcImpl << endmsg; + } + + m_fanCalcImpl = LArWheelCalculator_Impl::FanCalculatorFactory::Create( + m_SaggingOn, m_isModule, this); + + //-------------------------- + // At this place there was the loading of sagging parameters + // Transfered to DistanceCalculatorSaggingOn + //-------------------------- + + // Get option: Slant params. + msg << MSG::VERBOSE << "Loading SlantAngle parameters ..."; + std::string slant_params; + + if (m_isInner) { + slant_params=emecData.emecparams[0].INNERSLANTPARAM; + } else { + slant_params=emecData.emecparams[0].OUTERSLANTPARAM; + } + + msg << (m_isInner?" InnerWheel ":" OuterWheel ") << slant_params << endmsg; + + if(slant_params != "" && slant_params != "default"){ + double a, b, c, d, e; + if(sscanf(slant_params.c_str(), "%80le %80le %80le %80le %80le", &a, &b, &c, &d, &e) != 5){ + msg << MSG::ERROR + << "LArWheelCalculator: ERROR: wrong value(s) " + << "for EMEC slant angle parameters: " + << slant_params << ", " + << "defaults are used" << endmsg; + } else { + m_slant_parametrization[0] = a; + m_slant_parametrization[1] = b; + m_slant_parametrization[2] = c; + m_slant_parametrization[3] = d; + m_slant_parametrization[4] = e; + m_slant_use_default = false; + } + } // else already initialized in inner/outer_wheel_init() + + fill_sincos_parameterization(); // initialize sin&cos parameterization + + msg << MSG::VERBOSE << "All params initialized. Print some internal variables" << endmsg; + + msg << MSG::VERBOSE << "Data members:" << endmsg + << "m_AtlasZside = " << m_AtlasZside << "" << endmsg + << "m_NumberOfFans = " << m_NumberOfFans << "" << endmsg + << "m_ZeroFanPhi = " << m_ZeroFanPhi << "" << endmsg + << "m_ZeroFanPhi_ForDetNeaFan = " << m_ZeroFanPhi_ForDetNeaFan << "" << endmsg + << "m_FanStepOnPhi = " << m_FanStepOnPhi << "" << endmsg + << "m_FanHalfThickness = " << m_FanHalfThickness << "" << endmsg + //<< "Sagging parameters : " << m_sagging_parameter[0][0] << " " << m_sagging_parameter[0][1] << "" << endmsg + //<< "Sagging parameters : " << m_sagging_parameter[1][0] << " " << m_sagging_parameter[1][1] << "" << endmsg + << "slant_params = " << slant_params << "" << endmsg + << "Sagging option = " << sagging_opt_value << "" << endmsg + << "SaggingOn = " << (m_SaggingOn? "true": "false") << "" << endmsg + << "Slant parameters : "; + for(int i = 0; i < 5; i ++) msg << " " << m_slant_parametrization[i]; + msg << endmsg; + + if(m_isModule){ + msg << MSG::VERBOSE + << "module_init: FirstFan = " << m_FirstFan + << ", LastFan = " << m_LastFan + << ", ZeroFanPhi = " << m_ZeroFanPhi + << endmsg; + } + + //m_fan_number = -1000; + + // Is the following code fragment obsoleted? DM 2015-03-13 + /* to compare various methods of slant angle computation: + if(isInner) return; + FILE *O = fopen("slant_stat.table1.txt", "w"); + if(O == 0) abort(); + struct timeval t1, t2; + struct timezone tz; + std::vector<double> alpha; + gettimeofday(&t1, &tz); + for(double r = 600.; r < 2100.; r += .01){ + alpha.push_back(parameterized_slant_angle(r)); + } + gettimeofday(&t2, &tz); + + fprintf(O, "%d.%06d %d.%06d" << endmsg, t1.tv_sec, t1.tv_usec, t2.tv_sec, t2.tv_usec); + int i = 0; + for(double r = 600.; r < 2100.; r += .01, i ++){ + fprintf(O, "%f %f\n", r, alpha[i]); + } + + fclose(O); + exit(0); + */ +} + +/* converts module gap number into wheel gap number */ +int LArWheelCalculator::PhiGapNumberForWheel(int i) const +{ + return m_fanCalcImpl->PhiGapNumberForWheel(i); +} + +void LArWheelCalculator::inner_wheel_init(const EMECData & emecData) +{ + for(int i = 0; i < 5; ++ i) { + m_slant_parametrization[i] = default_slant_parametrization[0][i]; + } + m_slant_use_default = true; + + m_NumberOfFans=emecData.emecwheelparameters[0].NABS; + m_NumberOfWaves=emecData.emecwheelparameters[0].NACC; + + m_FanFoldRadius = 3.25*mm; + m_ZeroGapNumber = 64; // internal constant, should not be taken from DB + m_FanStepOnPhi = 2*M_PI / m_NumberOfFans; + m_isInner = true; +} + +void LArWheelCalculator::outer_wheel_init(const EMECData & emecData) +{ + for(int i = 0; i < 5; ++ i) { + m_slant_parametrization[i] = default_slant_parametrization[1][i]; + } + m_slant_use_default = true; + + m_NumberOfFans=emecData.emecwheelparameters[1].NABS; + m_NumberOfWaves=emecData.emecwheelparameters[1].NACC; + + + m_FanFoldRadius = 3.0*mm; + m_ZeroGapNumber = 192; // internal constant, should not be taken from DB + m_FanStepOnPhi = 2*M_PI / m_NumberOfFans; + m_isInner = false; +} + +double LArWheelCalculator::GetFanHalfThickness(LArG4::LArWheelCalculator_t t) const +{ + + switch(t){ + case LArG4::BackInnerBarretteWheelCalib: + case LArG4::BackInnerBarretteModuleCalib: + case LArG4::BackInnerBarretteWheel: + case LArG4::BackInnerBarretteModule: + case LArG4::InnerAbsorberWheel: + case LArG4::InnerAbsorberModule: + return (m_leadThicknessInner / 2 + m_steelThickness + m_glueThickness)*m_coldContraction; // new values, 02.11.06 J.T. with contraction in cold + // lead / 2 + steel + glue + case LArG4::InnerGlueWheel: + return (m_leadThicknessInner / 2 + m_glueThickness)*m_coldContraction; + case LArG4::InnerLeadWheel: + return m_leadThicknessInner / 2 * m_coldContraction; + + case LArG4::BackOuterBarretteWheelCalib: + case LArG4::BackOuterBarretteModuleCalib: + case LArG4::BackOuterBarretteWheel: + case LArG4::BackOuterBarretteModule: + case LArG4::OuterAbsorberWheel: + case LArG4::OuterAbsorberModule: + return (m_leadThicknessOuter / 2 + m_steelThickness + m_glueThickness)*m_coldContraction; // new values, 02.11.06 J.T. + case LArG4::OuterGlueWheel: + return (m_leadThicknessOuter / 2 + m_glueThickness)*m_coldContraction; + case LArG4::OuterLeadWheel: + return m_leadThicknessOuter / 2 * m_coldContraction; + + case LArG4::InnerElectrodWheel: + case LArG4::OuterElectrodWheel: + case LArG4::InnerElectrodModule: + case LArG4::OuterElectrodModule: + return m_electrodeTotalThickness/m_electrodeInvContraction * 0.5; //new values, 02.11.06 J.T + } + throw std::runtime_error("LArWheelCalculator::GetFanHalfThickness: wrong wheel type"); +} + +void LArWheelCalculator::module_init() +{ + m_isModule = true; + m_LastFan = m_NumberOfFans / 8; + m_FirstFan = 0; + m_ZeroFanPhi = - m_LastFan / 2 * m_FanStepOnPhi; +} + +/* + array of r is filled with: + for inner wheel - 2 elements { r_front, r_back } + for outer wheel - 3 elements { r_front, r_middle, r_back } + return value - delta_z of middle point in case of outer wheel +*/ +double LArWheelCalculator::GetWheelInnerRadius(double *r) const +{ + double zMid = 0.; + if(m_isInner){ + double tanThetaInner = 2. * exp(-m_eta_hi ) / (1. - exp(-2.*m_eta_hi )); + r[0] = m_zWheelFrontFace * tanThetaInner; + r[1] = m_zWheelBackFace * tanThetaInner; + } else { + double tanThetaMid = 2. * exp(-m_eta_mid) / (1. - exp(-2.*m_eta_mid)); + double inv_tanThetaOuter = (1. - exp(-2.*m_eta_low)) / (2. * exp(-m_eta_low)); + // Note that there is a 3mm gap between the outer surface of the + // inner wheel and the inner surface of the outer wheel. + r[0] = m_zWheelFrontFace * tanThetaMid + m_HalfGapBetweenWheels; + r[1] = m_rOuterCutoff * inv_tanThetaOuter * tanThetaMid + m_HalfGapBetweenWheels; + r[2] = m_zWheelBackFace * tanThetaMid + m_HalfGapBetweenWheels; + zMid = m_rOuterCutoff * inv_tanThetaOuter - m_zWheelFrontFace; + } + return zMid; +} + +/* + array of r is filled with: + for inner wheel - 2 elements { r_front, r_back } + for outer wheel - 3 elements { r_front, r_middle, r_back } +*/ +void LArWheelCalculator::GetWheelOuterRadius(double *r) const +{ + if(m_isInner){ + double tanThetaMid = 2. * exp(-m_eta_mid) / (1. - exp(-2.*m_eta_mid)); + // Note that there is a 3mm gap between the outer surface of the + // inner wheel and the inner surface of the outer wheel. + r[0] = m_zWheelFrontFace * tanThetaMid - m_HalfGapBetweenWheels; + r[1] = m_zWheelBackFace * tanThetaMid - m_HalfGapBetweenWheels; + } else { + double tanThetaOuter = 2. * exp(-m_eta_low) / (1. - exp(-2.*m_eta_low)); + r[0] = m_zWheelFrontFace * tanThetaOuter; + r[1] = m_rOuterCutoff; + r[2] = m_rOuterCutoff; + } +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculatorGeometry.cxx b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculatorGeometry.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b985a3efe37c64e1adacfb649f4796116f1193bd --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculatorGeometry.cxx @@ -0,0 +1,133 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "CxxUtils/sincos.h" +//#include <cmath> +#include <climits> +#include <cassert> +#include <iostream> + +#include "GeoSpecialShapes/LArWheelCalculator.h" +#include "./LArWheelCalculator_Impl/IDistanceCalculator.h" +#include "./LArWheelCalculator_Impl/IFanCalculator.h" +#include "GeoModelKernel/Units.h" +#ifdef HARDDEBUG +#include<stdio.h> +#endif + +using namespace GeoModelKernelUnits; + +void LArWheelCalculator::parameterized_sin(const double r, double &sin_a, double &cos_a) const +{ + const double r2 = r*r; + const double r3 = r2*r; + const double r4 = r2*r2; +#if LARWC_SINCOS_POLY > 4 + const double r5 = r4*r; +#endif + sin_a = m_sin_parametrization[0] + + m_sin_parametrization[1]*r + + m_sin_parametrization[2]*r2 + + m_sin_parametrization[3]*r3 + + m_sin_parametrization[4]*r4 +#if LARWC_SINCOS_POLY > 4 + + m_sin_parametrization[5]*r5 +#endif + ; + cos_a = sqrt(1. - sin_a*sin_a); +} + +void LArWheelCalculator::parameterized_sincos(const double r, double &sin_a, double &cos_a) const +{ + const double r2 = r*r; + const double r3 = r2*r; + const double r4 = r2*r2; +#if LARWC_SINCOS_POLY > 4 + const double r5 = r4*r; +#endif + sin_a = m_sin_parametrization[0] + + m_sin_parametrization[1]*r + + m_sin_parametrization[2]*r2 + + m_sin_parametrization[3]*r3 + + m_sin_parametrization[4]*r4 +#if LARWC_SINCOS_POLY > 4 + + m_sin_parametrization[5]*r5 +#endif + ; + cos_a = m_cos_parametrization[0] + + m_cos_parametrization[1]*r + + m_cos_parametrization[2]*r2 + + m_cos_parametrization[3]*r3 + + m_cos_parametrization[4]*r4 +#if LARWC_SINCOS_POLY > 4 + + m_cos_parametrization[5]*r5 +#endif + ; +} + +// calculates wave slant angle using parametrization for current wheel +// for given distance from calorimeter axis +double LArWheelCalculator::parameterized_slant_angle(double r) const +{ + const double r2 = r*r; + const double r3 = r2*r; + const double r4 = r2*r2; + const double result = m_slant_parametrization[0] + + r*m_slant_parametrization[1] + + r2*m_slant_parametrization[2] + + r3*m_slant_parametrization[3] + + r4*m_slant_parametrization[4]; + return result*deg; +} + +// Determines the nearest to the input point fan. +// Relays on the fact that each two fans have a fan of a different type between +// them. +// Returns distance to the nearest fan. Vector p is set to nearest fan coord. +// system. +// m_fan_number is set to nearest fan number +double LArWheelCalculator::DistanceToTheNearestFan(CLHEP::Hep3Vector &p, int & out_fan_number) const +{ + return m_fanCalcImpl->DistanceToTheNearestFan(p, out_fan_number); +} + +// Relays on the fact that each two fans have a fan of a different type between +// them. +// Affects m_fan_number. +std::pair<int, int> LArWheelCalculator::GetPhiGapAndSide(const CLHEP::Hep3Vector &p) const +{ + return m_fanCalcImpl->GetPhiGapAndSide(p); +} + +// Represents aproximate, probably underestimate, distance to the +// neutral fibre of the vertical fan. Sign of return value means +// side of the fan; negative - lower phi. +// +// Uses m_fan_number to compute sagging. +double LArWheelCalculator::DistanceToTheNeutralFibre(const CLHEP::Hep3Vector& P, int fan_number) const +{ + return m_distanceCalcImpl->DistanceToTheNeutralFibre(P, fan_number); +} + +CLHEP::Hep3Vector LArWheelCalculator::NearestPointOnNeutralFibre(const CLHEP::Hep3Vector &P, int fan_number) const +{ + return m_distanceCalcImpl->NearestPointOnNeutralFibre(P, fan_number); +} + +std::vector<double> LArWheelCalculator::NearestPointOnNeutralFibre_asVector(const CLHEP::Hep3Vector &p, int fan_number) const +{ + CLHEP::Hep3Vector np = NearestPointOnNeutralFibre(p, fan_number); + return std::vector<double> { np.x(), np.y(), np.z() }; +} + +/* +input is in local fan's coordinate system +side: < 0 - lower phi + > 0 - greater phi + = 0 - neutral fibre +*/ +double LArWheelCalculator::AmplitudeOfSurface(const CLHEP::Hep3Vector& P, int side, int fan_number) const +{ + return m_distanceCalcImpl->AmplitudeOfSurface(P, side, fan_number); +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorFactory.cxx b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorFactory.cxx new file mode 100644 index 0000000000000000000000000000000000000000..cb130827c5888647cace5b119230915b85bcf614 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorFactory.cxx @@ -0,0 +1,28 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "DistanceCalculatorFactory.h" + +#include "DistanceCalculatorSaggingOff.h" +#include "DistanceCalculatorSaggingOn.h" + +namespace LArWheelCalculator_Impl +{ + + IDistanceCalculator* DistanceCalculatorFactory::Create(const std::string & sagging_opt, + LArWheelCalculator* lwc) + + { + // the same condition is in LArWheelCalculator constructor + bool SaggingOn = (sagging_opt != "" && sagging_opt != "off")? true: false; + + if (SaggingOn) { + return new DistanceCalculatorSaggingOn(sagging_opt, lwc); + } else { + return new DistanceCalculatorSaggingOff(lwc); + } + } + +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorFactory.h b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..397e44c8e076dee08fa050673cd2720c2a0e0bed --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorFactory.h @@ -0,0 +1,26 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef __LArWheelCalculator_Impl_DistanceCalculatorFactory_H__ +#define __LArWheelCalculator_Impl_DistanceCalculatorFactory_H__ + +// DistanceCalculator factory +// calculator creation depends on sagging mode + +#include <string> +#include "IDistanceCalculator.h" +class LArWheelCalculator; +namespace LArWheelCalculator_Impl +{ + /// @todo Why is this a class??? + class DistanceCalculatorFactory + { + public: + static IDistanceCalculator* Create(const std::string & sagging_opt, + LArWheelCalculator* lwc); + }; + +} + +#endif // __LArWheelCalculator_Impl_DistanceCalculatorFactory_H__ diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorSaggingOff.cxx b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorSaggingOff.cxx new file mode 100644 index 0000000000000000000000000000000000000000..fe4edc65fc5cc0e9ce33ad72406cbfb969885c6a --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorSaggingOff.cxx @@ -0,0 +1,517 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +#include "DistanceCalculatorSaggingOff.h" +#include "GeoSpecialShapes/LArWheelCalculator.h" + +#include<cassert> + +//#define LWC_PARAM_ANGLE + +#ifdef LWC_PARAM_ANGLE +#include <CxxUtils/sincos.h> +#endif + +#include<signal.h> + + +namespace LArWheelCalculator_Impl +{ + + DistanceCalculatorSaggingOff::DistanceCalculatorSaggingOff(LArWheelCalculator* c) + : m_lwc(c) + { + m_EndQuarterWave = lwc()->m_ActiveLength - lwc()->m_QuarterWaveLength; + } + +#ifndef LARWC_DTNF_NEW + double DistanceCalculatorSaggingOff::DistanceToTheNeutralFibre(const CLHEP::Hep3Vector& P, int /*fan_number*/) const +#else + double DistanceCalculatorSaggingOff::DistanceToTheNeutralFibre_ref(const CLHEP::Hep3Vector& P, int /*fan_number*/) const +#endif + { + assert(P.y() > 0.); + double distance = 0.; + double z = P.z() - lwc()->m_StraightStartSection; + double x = P.x(); + +#ifdef LWC_PARAM_ANGLE //old variant + const double alpha = lwc()->parameterized_slant_angle(P.y()); + //double cos_a, sin_a; + //::sincos(alpha, &sin_a, &cos_a); + CxxUtils::sincos scalpha(alpha); + const double cos_a = scalpha.cs, sin_a = scalpha.sn; +#else // parameterized sine + double cos_a, sin_a; + lwc()->m_vsincos_par.eval(P.y(), sin_a, cos_a); +#endif + // determination of the nearest quarter-wave number + int nqwave = (z < 0.) ? 0 : int(z / lwc()->m_QuarterWaveLength); + //if(z < 0.) nqwave = 0; + //else nqwave = int(z / lwc()->m_QuarterWaveLength); + + bool begin_qw = false; + if((nqwave % 2) != 0){ + nqwave ++; + begin_qw = true; + } + + nqwave /= 2; + + // now nqwave is not the number of quarter-wave but the number of half-wave + // half-waves with last and zero numbers are not really half-waves but start + // and finish quarter-waves + // It means that half-wave number 1 begins after starting quarter-wave + if(nqwave != 0 && nqwave != lwc()->m_NumberOfHalfWaves){ // regular half-waves + z -= nqwave * lwc()->m_HalfWaveLength; + // there are some symmetries, so use them + if((nqwave % 2) == 0) x = -x; + if(begin_qw){ + z = -z; + x = -x; + } + // certain situation: rising slope of wave, z is positive + // rotate to prime-coordinate system (see description) + const double z_prime = z * cos_a + x * sin_a; + const double x_prime = x * cos_a - z * sin_a; + const double straight_part = (lwc()->m_QuarterWaveLength - lwc()->m_FanFoldRadius * sin_a) / cos_a; + if(z_prime > straight_part){// fold region + const double dz = straight_part - z_prime; + const double dx = x_prime + lwc()->m_FanFoldRadius; + distance = sqrt(dz*dz + dx*dx) - lwc()->m_FanFoldRadius; + } else if(z_prime > -straight_part){ + distance = x_prime; // straight part of the quarter-wave + } else {// fold region + const double dz = straight_part + z_prime; + const double dx = x_prime - lwc()->m_FanFoldRadius; + distance = lwc()->m_FanFoldRadius - sqrt(dz*dz + dx*dx); + } + // set correct sign for result + if(!begin_qw) distance = -distance; + if((nqwave % 2) == 0) distance = -distance; + + } else { // start and finish quarter-waves + if(nqwave == 0) { // start quarter-wave + x = - x; + } else { // finish quarter-wave + z = lwc()->m_ActiveLength - z; + } + + const double tan_beta = sin_a/(1.0 + cos_a); //tan(alpha * 0.5); + const double local_straight_section = lwc()->m_FanFoldRadius * tan_beta; + if( z < - local_straight_section && + ( x < lwc()->m_FanFoldRadius || + x < - lwc()->m_StraightStartSection * z / local_straight_section / tan_beta ) ) + { + distance = - x; + } + else { + const double z_prime = z * cos_a + x * sin_a; + const double x_prime = x * cos_a - z * sin_a; + if (z_prime < local_straight_section) { // start fold region + const double dz = local_straight_section - z_prime; + const double dx = x_prime - lwc()->m_FanFoldRadius; + distance = sqrt(dz*dz + dx*dx) - lwc()->m_FanFoldRadius; + } else { + const double straight_part = (lwc()->m_QuarterWaveLength - lwc()->m_FanFoldRadius * sin_a) / cos_a; + if (z_prime <= straight_part) { // straight part of quarter-wave + distance = - x_prime; + } else { // regular fold region of the quarter-wave + const double dz = straight_part - z_prime; + const double dx = x_prime + lwc()->m_FanFoldRadius; + distance = lwc()->m_FanFoldRadius - sqrt(dz*dz + dx*dx); + } + } + } + // set correct sign + if (nqwave == 0) distance = -distance; + } +#ifdef HARDDEBUG + double dd = DistanceToTheNeutralFibre_ref(P); + if(fabs(dd - distance) > 0.000001){ + //static int cnt = 0; + std::cout << "DTNF MISMATCH " << this << " " << P << " " + << dd << " vs " << distance << std::endl; + //cnt ++; + //if(cnt > 100) exit(0); + } +#endif + return distance; + } + + // IMPROVED PERFORMANCE +#ifdef LARWC_DTNF_NEW + double DistanceCalculatorSaggingOff::DistanceToTheNeutralFibre(const CLHEP::Hep3Vector& P, int /*fan_number*/) const +#else + double DistanceCalculatorSaggingOff::DistanceToTheNeutralFibre_ref(const CLHEP::Hep3Vector& P, int /*fan_number*/) const +#endif + { + double z = P.z() - lwc()->m_StraightStartSection; + double x = P.x(); + +#ifdef LWC_PARAM_ANGLE //old variant + const double alpha = lwc()->parameterized_slant_angle(P.y()); + CxxUtils::sincos scalpha(alpha); + double cos_a = scalpha.cs, sin_a = scalpha.sn; +#else // parameterized sine + double cos_a, sin_a; + lwc()->m_vsincos_par.eval(P.y(), sin_a, cos_a); +#endif + + bool sqw = false; + if(z > lwc()->m_QuarterWaveLength){ + if(z < m_EndQuarterWave){ // regular half-waves + unsigned int nhwave = (unsigned int)(z / lwc()->m_HalfWaveLength + 0.5); + z -= lwc()->m_HalfWaveLength * nhwave; + const double straight_part = (lwc()->m_QuarterWaveLength - lwc()->m_FanFoldRadius * sin_a) / cos_a; + nhwave &= 1U; + if(nhwave == 0) sin_a = - sin_a; + double z_prime = z * cos_a + x * sin_a; + const double x_prime = z * sin_a - x * cos_a; + if(z_prime > straight_part){ // up fold region + const double dz = z_prime - straight_part; + if(nhwave == 0){ + const double dx = x_prime + lwc()->m_FanFoldRadius; + return sqrt(dz*dz + dx*dx) - lwc()->m_FanFoldRadius; + } else { + const double dx = x_prime - lwc()->m_FanFoldRadius; + return lwc()->m_FanFoldRadius - sqrt(dz*dz + dx*dx); + } + } + z_prime += straight_part; + if(z_prime > 0){ + return x_prime; // straight part of the quarter-wave + } else { // low fold region + const double &dz = z_prime; + if(nhwave == 0){ + const double dx = x_prime - lwc()->m_FanFoldRadius; + return lwc()->m_FanFoldRadius - sqrt(dz*dz + dx*dx); + } else { + const double dx = x_prime + lwc()->m_FanFoldRadius; + return sqrt(dz*dz + dx*dx) - lwc()->m_FanFoldRadius; + } + } + } else { // ending quarter-wave + z = lwc()->m_ActiveLength - z; + } + } else { // starting quarter-wave + x = - x; + sqw = true; + } + + // start and finish quarter-waves + const double tan_beta = sin_a/(1.0 + cos_a); //tan(alpha * 0.5); + const double local_straight_section = lwc()->m_FanFoldRadius * tan_beta; + if(z < - local_straight_section && + ( x < lwc()->m_FanFoldRadius || + x < - lwc()->m_StraightStartSection * z / local_straight_section / tan_beta )) + { + return sqw? x: (-x); + } + else { + const double z_prime = z * cos_a + x * sin_a; + const double x_prime = x * cos_a - z * sin_a; + if (z_prime < local_straight_section) { // start fold region + const double dz = local_straight_section - z_prime; + const double dx = x_prime - lwc()->m_FanFoldRadius; + if(sqw) return lwc()->m_FanFoldRadius - sqrt(dz*dz + dx*dx); + else return sqrt(dz*dz + dx*dx) - lwc()->m_FanFoldRadius; + } else { + const double straight_part = + (lwc()->m_QuarterWaveLength - lwc()->m_FanFoldRadius * sin_a) / cos_a; + if (z_prime <= straight_part) { // straight part of quarter-wave + return sqw? x_prime: (-x_prime); + } else { // regular fold region of the quarter-wave + const double dz = straight_part - z_prime; + const double dx = x_prime + lwc()->m_FanFoldRadius; + if(sqw) return sqrt(dz*dz + dx*dx) - lwc()->m_FanFoldRadius; + else return lwc()->m_FanFoldRadius - sqrt(dz*dz + dx*dx); + } + } + } + // ??? + std::abort(); + } + + CLHEP::Hep3Vector DistanceCalculatorSaggingOff::NearestPointOnNeutralFibre(const CLHEP::Hep3Vector &P, int /*fan_number*/) const + { + CLHEP::Hep3Vector result; + double z = P.z() - lwc()->m_StraightStartSection; + double x = P.x(); + double y = P.y(); + +#ifdef LWC_PARAM_ANGLE //old variant + const double alpha = lwc()->parameterized_slant_angle(P.y()); + CxxUtils::sincos scalpha(alpha); + const double cos_a = scalpha.cs, sin_a = scalpha.sn; +#else // parameterized sine + double cos_a, sin_a; + lwc()->m_vsincos_par.eval(P.y(), sin_a, cos_a); +#endif + + int nqwave; + if(z < 0.) nqwave = 0; + else nqwave = int(z / lwc()->m_QuarterWaveLength); + bool begin_qw = false; + if((nqwave % 2) != 0){ + nqwave ++; + begin_qw = true; + } + nqwave /= 2; + if(nqwave != 0 && nqwave != lwc()->m_NumberOfHalfWaves){ + z -= nqwave * lwc()->m_HalfWaveLength; + if((nqwave % 2) == 0) x = -x; + if(begin_qw){ + z = -z; + x = -x; + } + const double z_prime = z * cos_a + x * sin_a; + const double x_prime = x * cos_a - z * sin_a; + const double straight_part = (lwc()->m_QuarterWaveLength - lwc()->m_FanFoldRadius * sin_a) / cos_a; + const double dz = straight_part - z_prime; + if (dz > 0) result.set(0., y, z_prime); + else { + double a = atan(fabs(dz / (x_prime + lwc()->m_FanFoldRadius))); + result.set(lwc()->m_FanFoldRadius * (cos(a) - 1), y, straight_part + lwc()->m_FanFoldRadius * sin(a)); + } + result.rotateY(asin(sin_a)); + if(begin_qw){ + result.setX(-result.x()); + result.setZ(-result.z()); + } + if((nqwave % 2) == 0) result.setX(-result.x()); + result.setZ(result.z() + nqwave * lwc()->m_HalfWaveLength); + } else { + if(nqwave == 0) x = -x; + else z = lwc()->m_ActiveLength - z; + const double tan_beta = sin_a/(1.0+cos_a); //tan(alpha * 0.5); + const double local_straight_section = lwc()->m_FanFoldRadius * tan_beta; + if(z < - local_straight_section && + ( x < lwc()->m_FanFoldRadius || + x < - lwc()->m_StraightStartSection * z / local_straight_section / tan_beta)) + { + result.set(0., y, z); + } + else { + const double z_prime = z * cos_a + x * sin_a; + const double x_prime = x * cos_a - z * sin_a; + if(z_prime < local_straight_section) { + double a = fabs(atan((local_straight_section - z_prime) / (x_prime - lwc()->m_FanFoldRadius))); + + result.set(lwc()->m_FanFoldRadius * (1 - cos(a)), y, local_straight_section - lwc()->m_FanFoldRadius * sin(a)); + } else { + double straight_part = (lwc()->m_QuarterWaveLength - lwc()->m_FanFoldRadius * sin_a) / cos_a; + if(z_prime <= straight_part) { + result.set(0., y, z_prime); + } else { + double a = fabs(atan((straight_part - z_prime) / (x_prime + lwc()->m_FanFoldRadius)) ); + result.set(lwc()->m_FanFoldRadius * (cos(a) - 1), y, straight_part + lwc()->m_FanFoldRadius * sin(a)); + } + } + result.rotateY(asin(sin_a)); + } + if(nqwave != 0){ + result.setZ(lwc()->m_ActiveLength - result.z()); + } else { + result.setX(-result.x()); + } + } + result.setZ(result.z() + lwc()->m_StraightStartSection); + return result; + } + + // IMPROVED VERSION + CLHEP::Hep3Vector DistanceCalculatorSaggingOff::NearestPointOnNeutralFibre_ref(const CLHEP::Hep3Vector &P, int /*fan_number*/) const + { + CLHEP::Hep3Vector result; + double z = P.z() - lwc()->m_StraightStartSection; + double x = P.x(); + double y = P.y(); + +#ifdef LWC_PARAM_ANGLE //old variant + const double alpha = lwc()->parameterized_slant_angle(P.y()); + CxxUtils::sincos scalpha(alpha); + double cos_a = scalpha.cs, sin_a = scalpha.sn; +#else // parameterized sine + double cos_a, sin_a; + lwc()->m_vsincos_par.eval(P.y(), sin_a, cos_a); +#endif + + bool sqw = false; + if(z > lwc()->m_QuarterWaveLength){ + if(z < m_EndQuarterWave){ // regular half-waves + unsigned int nhwave = (unsigned int)(z / lwc()->m_HalfWaveLength + 0.5); + const double zshift = lwc()->m_HalfWaveLength * nhwave; + z -= zshift; + const double straight_part = + (lwc()->m_QuarterWaveLength - lwc()->m_FanFoldRadius * sin_a) / cos_a; + nhwave &= 1U; + if(nhwave == 0) sin_a = - sin_a; + const double z_prime = z * cos_a + x * sin_a; + if(z_prime > straight_part){ // up fold + const double x_prime = x * cos_a - z * sin_a; + const double dz = straight_part - z_prime; + double a1 = atan(fabs(dz / (x_prime + lwc()->m_FanFoldRadius))); + const double x1 = lwc()->m_FanFoldRadius * (cos(a1) - 1.); + const double z1 = straight_part + lwc()->m_FanFoldRadius * sin(a1); + result.set(x1*cos_a - z1*sin_a, y, z1*cos_a + z1*sin_a); + return result; + } else if(z_prime > -straight_part){ // straight part + result.set(-z_prime * sin_a, y, z_prime*cos_a + zshift); + return result; + } else { // low fold + const double x_prime = x * cos_a - z * sin_a; + const double dz = straight_part + z_prime; + double a1 = atan(fabs(dz / (x_prime + lwc()->m_FanFoldRadius))); + const double x1 = lwc()->m_FanFoldRadius * (cos(a1) - 1.); + const double z1 = straight_part + lwc()->m_FanFoldRadius * sin(a1); + result.set(x1*cos_a - z1*sin_a, y, z1*cos_a + z1*sin_a); + return result; + } + } else { // ending quarter-wave + z = lwc()->m_ActiveLength - z; + } + } else { // starting quarter-wave + x = - x; + sqw = true; + } + + // start and finish quarter-waves + const double tan_beta = sin_a / (1.0 + cos_a); + const double local_straight_section = lwc()->m_FanFoldRadius * tan_beta; + if(z < - local_straight_section && + (x < lwc()->m_FanFoldRadius || + x < - lwc()->m_StraightStartSection * z / local_straight_section / tan_beta)) + { + result.set(0., y, z); + } + else { + const double z_prime = z * cos_a + x * sin_a; + const double x_prime = x * cos_a - z * sin_a; + if(z_prime < local_straight_section) { + double a = fabs(atan((local_straight_section - z_prime) / (x_prime - lwc()->m_FanFoldRadius))); + result.set(lwc()->m_FanFoldRadius * (1 - cos(a)), y, local_straight_section - lwc()->m_FanFoldRadius * sin(a)); + } else { + double straight_part = (lwc()->m_QuarterWaveLength - lwc()->m_FanFoldRadius * sin_a) / cos_a; + if(z_prime <= straight_part) { + result.set(0., y, z_prime); + } else { + double a = fabs(atan((straight_part - z_prime) / (x_prime + lwc()->m_FanFoldRadius)) ); + result.set(lwc()->m_FanFoldRadius * (cos(a) - 1), y, straight_part + lwc()->m_FanFoldRadius * sin(a)); + } + } + result.rotateY(asin(sin_a)); + } + if(sqw) result.setX(-result.x()); + else result.setZ(lwc()->m_ActiveLength - result.z()); + result.setZ(result.z() + lwc()->m_StraightStartSection); + return result; + } + + /* + input is in local fan's coordinate system + side: < 0 - lower phi + > 0 - greater phi + = 0 - neutral fibre + */ + double DistanceCalculatorSaggingOff::AmplitudeOfSurface(const CLHEP::Hep3Vector& P, int side, int /*fan_number*/) const + { + double result = 0.; + double rho = lwc()->m_FanFoldRadius; + double z = P.z() - lwc()->m_StraightStartSection; + +#ifdef LWC_PARAM_ANGLE //old variant + const double alpha = lwc()->parameterized_slant_angle(P.y()); + //double cos_a, sin_a; + //::sincos(alpha, &sin_a, &cos_a); + CxxUtils::sincos scalpha(alpha); + const double cos_a = scalpha.cs, sin_a = scalpha.sn; + // parameterized sine +#else + double cos_a, sin_a; + lwc()->m_vsincos_par.eval(P.y(), sin_a, cos_a); +#endif + + // determination of the nearest quarter-wave number + int nqwave; + if(z < 0.) nqwave = 0; + else nqwave = int(z / lwc()->m_QuarterWaveLength); + bool begin_qw = false; + if((nqwave % 2) != 0){ + nqwave ++; + begin_qw = true; + } + nqwave /= 2; + // now nqwave is not the number of quarter-wave but the number of half-wave + // half-waves with last and zero numbers are not really half-waves but start + // and finish quarter-waves + // It means that half-wave number 1 begins after starting quarter-wave + if(nqwave != 0 && nqwave != lwc()->m_NumberOfHalfWaves){ // regular half-waves + z -= nqwave * lwc()->m_HalfWaveLength; + if(begin_qw) z = -z; + double dz = lwc()->m_QuarterWaveLength - z; + + int local_side = 1; + if((nqwave % 2) == 0){ + if(begin_qw) local_side = -1; + } else { + if(!begin_qw) local_side = -1; + } + + rho += lwc()->m_FanHalfThickness * local_side * side; + + if(dz >= rho * sin_a){ + result = z * sin_a / cos_a; // straight part of the quarter-wave + } else { // fold region + result = (lwc()->m_QuarterWaveLength * sin_a - rho) / cos_a + + sqrt(rho * rho - dz * dz); + } + result *= -local_side; + if(side < 0) result += lwc()->m_FanHalfThickness / cos_a; + else if(side > 0) result -= lwc()->m_FanHalfThickness / cos_a; + + } else { // start and finish quarter-waves + int local_side = 1; + if(nqwave == 0) { // start quarter-wave + local_side = -1; + } else { // finish quarter-wave + z = lwc()->m_ActiveLength - z; + } + + const double rho1i = lwc()->m_FanFoldRadius; + const double tan_beta = sin_a/(1.0+cos_a); //tan(alpha * 0.5); + const double min_local_fold_region = rho1i * tan_beta; + + if(z <= - min_local_fold_region){ + result = - side * lwc()->m_FanHalfThickness; + } else { + const double rho1 = rho1i + lwc()->m_FanHalfThickness * side * local_side; + + const double max_local_fold_region = rho1 * sin_a - min_local_fold_region; + //const double max_local_fold_region = rho1 * tan_beta * (1. + cos_a) - min_local_fold_region; + if(z < max_local_fold_region){ // start fold region + z += min_local_fold_region; + result = rho1 - sqrt(rho1 * rho1 - z * z); + if(nqwave == 0) result = -result; + if(side < 0) result += lwc()->m_FanHalfThickness; + else if(side > 0) result -= lwc()->m_FanHalfThickness; + } else { + rho -= lwc()->m_FanHalfThickness * local_side * side; + const double dz = lwc()->m_QuarterWaveLength - z; + if(dz >= rho * sin_a){ + result = z * sin_a / cos_a; // straight part of the quarter-wave + } else { // regular fold region + result = (lwc()->m_QuarterWaveLength * sin_a - rho) / cos_a + + sqrt(rho * rho - dz * dz); + } + if(nqwave == 0) result = -result; + if(side < 0) result += lwc()->m_FanHalfThickness / cos_a; + else if(side > 0) result -= lwc()->m_FanHalfThickness / cos_a; + } + } + } + return result; + } + +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorSaggingOff.h b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorSaggingOff.h new file mode 100644 index 0000000000000000000000000000000000000000..979d3fb64d6990b524ca345467a799a5bcaa7852 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorSaggingOff.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef __LArWheelCalculator_Impl_DistanceCalculatorSaggingOff_H__ +#define __LArWheelCalculator_Impl_DistanceCalculatorSaggingOff_H__ + + +#include "IDistanceCalculator.h" + +class LArWheelCalculator; + +namespace LArWheelCalculator_Impl +{ + + /// @class DistanceCalculatorSaggingOff + /// @brief Implements details of distance calculation to parts of the + /// LAr endcap without sagging corrections. + /// + class DistanceCalculatorSaggingOff : public IDistanceCalculator + { + + public: + + /// Constructor + DistanceCalculatorSaggingOff(LArWheelCalculator* lwc); + + /// @name Geometry methods + /// @{ + virtual double DistanceToTheNeutralFibre(const CLHEP::Hep3Vector &p, int fan_number) const; + virtual double DistanceToTheNeutralFibre_ref(const CLHEP::Hep3Vector &p, int fan_number) const; + virtual CLHEP::Hep3Vector NearestPointOnNeutralFibre(const CLHEP::Hep3Vector &p, int fan_number) const; + virtual CLHEP::Hep3Vector NearestPointOnNeutralFibre_ref(const CLHEP::Hep3Vector &p, int fan_number) const; + virtual double AmplitudeOfSurface(const CLHEP::Hep3Vector& P, int side, int fan_number) const; + /// @} + + /// Return the calculator: + inline const LArWheelCalculator *lwc() const { return m_lwc; }; + + private: + + LArWheelCalculator* m_lwc; + double m_EndQuarterWave; + + }; + +} + +#endif // __LArWheelCalculator_Impl_IDistanceCalculatorOff_H__ diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorSaggingOn.cxx b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorSaggingOn.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e68c10d06fa8c87e09855e99b93c6aa70117fadc --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorSaggingOn.cxx @@ -0,0 +1,173 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef PORTABLE_LAR_SHAPE + #include "GaudiKernel/MsgStream.h" + #include "GaudiKernel/ISvcLocator.h" + #include "GaudiKernel/Bootstrap.h" +#else + #include "PortableMsgStream/PortableMsgStream.h" +#endif +#include "DistanceCalculatorSaggingOn.h" +#include "CLHEP/Vector/ThreeVector.h" + +#include <vector> +#include <stdexcept> + +#include "GeoSpecialShapes/LArWheelCalculator.h" + +#include "GeoModelKernel/Units.h" + +using GeoModelKernelUnits::mm; + + +namespace LArWheelCalculator_Impl +{ + DistanceCalculatorSaggingOn::DistanceCalculatorSaggingOn(const std::string& saggingOptions, + LArWheelCalculator* lwc) + : parent(lwc), + m_saggingOptions(saggingOptions) + + { + init_sagging_parameters(); + } + + void DistanceCalculatorSaggingOn::init_sagging_parameters() + { + + // Get pointer to the message service +#ifndef PORTABLE_LAR_SHAPE + ISvcLocator* svcLocator = Gaudi::svcLocator(); + IMessageSvc* msgSvc; + StatusCode status = svcLocator->service("MessageSvc", msgSvc); + if(status.isFailure()){ + throw std::runtime_error("LArWheelCalculator constructor: \ + cannot initialze message service"); + } + MsgStream msg(msgSvc, "LArWheelCalculator_Impl::DistanceCalculatorSaggingOn"); +#else + PortableMsgStream msg("LArWheelCalculator_Impl::DistanceCalculatorSaggingOn"); +#endif + std::string sagging_opt_value = m_saggingOptions; + m_sagging_parameter.resize (lwc()->m_NumberOfFans, std::vector<double> (5, 0.)); + // if(m_SaggingOn) { + if(sagging_opt_value.substr(0, 4) == "file"){ + std::string sag_file = sagging_opt_value.substr(5); + msg << MSG::DEBUG + << "geting sagging parameters from file " + << sag_file << " ..." << endmsg; + FILE *F = fopen(sag_file.c_str(), "r"); + if(F == 0){ + msg << MSG::FATAL + << "cannot open EMEC sagging parameters file " + << sag_file + << endmsg; + throw std::runtime_error("LArWheelCalculator: read sagging parameters from file"); + } + int s, w, t, n; + double p0, p1, p2, p3, p4; + while(!feof(F) && + fscanf(F, "%80d %80d %80d %80d %80le %80le %80le %80le %80le", + &s, &w, &t, &n, &p0, &p1, &p2, &p3, &p4) == 9) + { + if(s == lwc()->m_AtlasZside && + ((w == 0 && lwc()->m_isInner) || (w == 1 && !lwc()->m_isInner)) && + ((t == 0 && !lwc()->m_isElectrode) || (t == 1 && lwc()->m_isElectrode)) && + (n >= 0 && n < lwc()->m_NumberOfFans)) + { + m_sagging_parameter[n][0] = p0; + m_sagging_parameter[n][1] = p1; + m_sagging_parameter[n][2] = p2; + m_sagging_parameter[n][3] = p3; + m_sagging_parameter[n][4] = p4; + msg << MSG::VERBOSE + << "sagging for " << s << " " << w << " " << t + << " " << n << ": " << p0 << " " << p1 << " " + << p2 << " " << p3 << endmsg; + } + } + fclose(F); + } else { + double a, b, c, d; + if(sscanf(sagging_opt_value.c_str(), "%80le %80le %80le %80le", &a, &b, &c, &d) != 4){ + msg << MSG::ERROR + << "wrong value(s) " + << " for EMEC sagging parameters: " + << sagging_opt_value << ", defaults are used" << endmsg; + } else { + for(int j = 0; j < lwc()->m_NumberOfFans; j ++){ + if(lwc()->m_isInner){ + m_sagging_parameter[j][1] = a; + m_sagging_parameter[j][0] = b * mm; + } else { + m_sagging_parameter[j][1] = c; + m_sagging_parameter[j][0] = d * mm; + } + } + } + } + // } + msg << MSG::INFO << "Sagging parameters : " << m_sagging_parameter[0][0] << " " << m_sagging_parameter[0][1] << endmsg + << "Sagging parameters : " << m_sagging_parameter[1][0] << " " << m_sagging_parameter[1][1] << endmsg; + } + + // Represents aproximate, probably underestimate, distance to the + // neutral fibre of the vertical fan. Sign of return value means + // side of the fan; negative - lower phi. + // + // Uses m_fan_number to compute sagging. + double DistanceCalculatorSaggingOn::DistanceToTheNeutralFibre(const CLHEP::Hep3Vector &p, int fan_number) const { + CLHEP::Hep3Vector sagging_corrected( p.x()+get_sagging(p, fan_number), p.y(), p.z() ); + return parent::DistanceToTheNeutralFibre(sagging_corrected, fan_number); + } + + CLHEP::Hep3Vector DistanceCalculatorSaggingOn::NearestPointOnNeutralFibre(const CLHEP::Hep3Vector &p, int fan_number) const { + CLHEP::Hep3Vector sagging_corrected( p.x()+get_sagging(p, fan_number), p.y(), p.z() ); + return parent::NearestPointOnNeutralFibre(sagging_corrected, fan_number); + } + + double DistanceCalculatorSaggingOn::AmplitudeOfSurface(const CLHEP::Hep3Vector& p, int side, int fan_number) const { + return parent::AmplitudeOfSurface(p, side, fan_number) - get_sagging(p, fan_number); + } + + + // the function uses m_fan_number for phi-dependent sagging computation + double DistanceCalculatorSaggingOn::get_sagging(const CLHEP::Hep3Vector &P, int fan_number) const { +#ifdef HARDDEBUG + std::cout << "get_sagging: MFN = " << fan_number << std::endl; +#endif + double dx = P.z() / lwc()->m_HalfWheelThickness - 1.; + dx *= dx; + dx = 1. - dx; + //dx *= SaggingAmplitude * sin(FanStepOnPhi * m_fan_number + ZeroFanPhi); + //int n = m_fan_number; + //if(n < 0) n += m_NumberOfFans; + //n += m_ZeroGapNumber; + //if(n >= m_NumberOfFans) n -= m_NumberOfFans; + //const std::vector<double>& sp = m_sagging_parameter[n]; + const std::vector<double>& sp = m_sagging_parameter[fan_number]; + double R = P.r() / mm; + double r = R; + double result = sp[0]; + result += R * sp[1]; + R *= r; + result += R * sp[2]; + R *= r; + result += R * sp[3]; + R *= r; + result += R * sp[4]; + +#ifdef HARDDEBUG + /*printf("get_sagging: (%6.3f, %6.3f, %6.3f) %6.3f; MFN %4d;" + "n %3d; sp %6.4f %6.4f; dx %6.3f; %.6f\n", P.x()/mm, P.y()/mm, P.z()/mm, + r, m_fan_number, n, sp[0], sp[1], dx, result*dx);*/ + printf("get_sagging: (%6.3f, %6.3f, %6.3f) %6.3f;" + " sp %6.4f %6.4f; dx %6.3f; %.6f\n", P.x()/mm, P.y()/mm, P.z()/mm, + r, sp[0], sp[1], dx, result*dx); +#endif //HARDDEBUG + + return result * dx; + } + +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorSaggingOn.h b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorSaggingOn.h new file mode 100644 index 0000000000000000000000000000000000000000..082db31eeb9552d42f598d5cdc487d124eaf5894 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/DistanceCalculatorSaggingOn.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef __LArWheelCalculator_Impl_DistanceCalculatorSaggingOn_H__ +#define __LArWheelCalculator_Impl_DistanceCalculatorSaggingOn_H__ + +#include "DistanceCalculatorSaggingOff.h" +#include <vector> +class LArWheelCalculator; +namespace LArWheelCalculator_Impl +{ + + /// @class DistanceCalculatorSaggingOn + /// @brief Implements details of distance calculation to parts of the + /// LAr endcap with sagging taken into account. + /// + class DistanceCalculatorSaggingOn : public DistanceCalculatorSaggingOff + { + + public: + + typedef DistanceCalculatorSaggingOff parent; + + /// Constructor + DistanceCalculatorSaggingOn(const std::string& saggingOptions, + LArWheelCalculator* lwc); + + /// @name Geometry methods + /// @{ + virtual double DistanceToTheNeutralFibre(const CLHEP::Hep3Vector &p, int fan_number) const; + virtual CLHEP::Hep3Vector NearestPointOnNeutralFibre(const CLHEP::Hep3Vector &p, int fan_number) const; + virtual double AmplitudeOfSurface(const CLHEP::Hep3Vector& P, int side, int fan_number) const; + /// @} + + private: + + double get_sagging(const CLHEP::Hep3Vector &P, int fan_number) const; + void init_sagging_parameters(); + + std::vector<std::vector<double> > m_sagging_parameter; + std::string m_saggingOptions; + + }; + +} + +#endif // __LArWheelCalculator_Impl_IDistanceCalculatorOn_H__ diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/FanCalculatorFactory.cxx b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/FanCalculatorFactory.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4b7c30941af1b6df7d3a3a46575469c046ed5332 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/FanCalculatorFactory.cxx @@ -0,0 +1,27 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "FanCalculatorFactory.h" +#include "ModuleFanCalculator.h" +#include "WheelFanCalculator.h" + +namespace LArWheelCalculator_Impl +{ + + IFanCalculator* FanCalculatorFactory::Create(bool isSaggingOn, bool isModule, + LArWheelCalculator* lwc) + + { + if (isModule) { + return new ModuleFanCalculator(lwc); + } + if (isSaggingOn) { + return new WheelFanCalculator<SaggingOn_t>(lwc); + } else { + return new WheelFanCalculator<SaggingOff_t>(lwc); + } + } + +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/FanCalculatorFactory.h b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/FanCalculatorFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..e4f8f377c4e8ee5ee6395020a8a9c4fe30c57351 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/FanCalculatorFactory.h @@ -0,0 +1,30 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef __LArWheelCalculator_Impl_FanCalculatorFactory_H__ +#define __LArWheelCalculator_Impl_FanCalculatorFactory_H__ + + +#include "IFanCalculator.h" + +class LArWheelCalculator; + +namespace LArWheelCalculator_Impl +{ + + /// @class FanCalculatorFactory + /// @brief A factory for FanCalculators + /// + /// Calculator creation depends on sagging mode and wheel/module calo. + /// + class FanCalculatorFactory + { + public: + static IFanCalculator* Create(bool isSaggingOn, bool isModule, + LArWheelCalculator* lwc); + }; + +} + +#endif // __LArWheelCalculator_Impl_FanCalculatorFactory_H__ diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/IDistanceCalculator.h b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/IDistanceCalculator.h new file mode 100644 index 0000000000000000000000000000000000000000..d45f4743c22d4051719065ca51c55ffb4d88c7a3 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/IDistanceCalculator.h @@ -0,0 +1,44 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef __LArWheelCalculator_Impl_IDistanceCalculator_H__ +#define __LArWheelCalculator_Impl_IDistanceCalculator_H__ + + +#include "CLHEP/Vector/ThreeVector.h" + +namespace LArWheelCalculator_Impl +{ + + /// @class IDistanceCalculator + /// Abstract interface for calculator classes that handle distance + /// calculation to parts of the LAr endcap. + /// + class IDistanceCalculator + { + + public: + + /// Virtual destructor + virtual ~IDistanceCalculator() {}; + + /// @name Geometry methods + /// @{ + + virtual double DistanceToTheNeutralFibre(const CLHEP::Hep3Vector &p, + int fan_number) const = 0; + + virtual CLHEP::Hep3Vector NearestPointOnNeutralFibre(const CLHEP::Hep3Vector &p, + int fan_number) const = 0; + + virtual double AmplitudeOfSurface(const CLHEP::Hep3Vector& p, int side, + int fan_number) const = 0; + + /// @} + + }; + +} + +#endif // __LArWheelCalculator_Impl_IDistanceCalculator_H__ diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/IFanCalculator.h b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/IFanCalculator.h new file mode 100644 index 0000000000000000000000000000000000000000..4cd70f9643594ab4df7054c5d3dab955f43b25a9 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/IFanCalculator.h @@ -0,0 +1,42 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef __LArWheelCalculator_Impl_IFanCalculator_H__ +#define __LArWheelCalculator_Impl_IFanCalculator_H__ + + +#include "CLHEP/Vector/ThreeVector.h" + +namespace LArWheelCalculator_Impl +{ + + /// @class IFanCalculator + /// Abstract interface for fan calculator classes that handle distance + /// calculation to parts of the LAr endcap. + /// + class IFanCalculator + { + + public: + + /// Virtual destructor + virtual ~IFanCalculator() {}; + + /// @name Geometry methods + /// @{ + + virtual double DistanceToTheNearestFan(CLHEP::Hep3Vector &p, + int & out_fan_number) const = 0; + + virtual int PhiGapNumberForWheel(int i) const = 0; + + virtual std::pair<int, int> GetPhiGapAndSide(const CLHEP::Hep3Vector &p) const = 0; + + /// @} + + }; + +} + +#endif // __LArWheelCalculator_Impl_IFanCalculator_H__ diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/ModuleFanCalculator.cxx b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/ModuleFanCalculator.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a512fbdd5590556ea3f2c5d861847f7dd3b53bcd --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/ModuleFanCalculator.cxx @@ -0,0 +1,106 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "ModuleFanCalculator.h" + +#include "GeoSpecialShapes/LArWheelCalculator.h" + + + +#ifdef HARDDEBUG +#undef HARDDEBUG +#endif + +namespace LArWheelCalculator_Impl +{ + + ModuleFanCalculator::ModuleFanCalculator(LArWheelCalculator* lwc) + : m_lwc(lwc) + { + } + + double ModuleFanCalculator::DistanceToTheNearestFan(CLHEP::Hep3Vector &p, int & out_fan_number) const + { + static const double halfpi=M_PI/2.0; + int fan_number = int((p.phi() - halfpi - lwc()->m_ZeroFanPhi_ForDetNeaFan) / lwc()->m_FanStepOnPhi); + double angle = lwc()->m_FanStepOnPhi * fan_number + lwc()->m_ZeroFanPhi_ForDetNeaFan; +#ifdef HARDDEBUG + printf("DistanceToTheNearestFan: initial FN %4d\n", fan_number); +#endif + p.rotateZ(-angle); + // determine search direction + double d0 = lwc()->DistanceToTheNeutralFibre(p, lwc()->adjust_fan_number(fan_number)); + double d1 = d0; + int delta = 1; + if(d0 < 0.) delta = -1; // search direction has been determined + angle = - lwc()->m_FanStepOnPhi * delta; + do { // search: + p.rotateZ(angle); + fan_number += delta; + d1 = lwc()->DistanceToTheNeutralFibre(p, lwc()->adjust_fan_number(fan_number)); + } while(d0 * d1 > 0.); + // if signs of d1 and d0 are different, the point is between current pair + if(delta > 0) fan_number --; + + int adj_fan_number = fan_number; + if(adj_fan_number < lwc()->m_FirstFan) { + p.rotateZ((adj_fan_number - lwc()->m_FirstFan) * lwc()->m_FanStepOnPhi); + adj_fan_number = lwc()->m_FirstFan; + } else if(adj_fan_number >= lwc()->m_LastFan) { + p.rotateZ((adj_fan_number - lwc()->m_LastFan + 1) * lwc()->m_FanStepOnPhi); + adj_fan_number = lwc()->m_LastFan - 1; + } + + p.rotateZ(-0.5 * angle); + out_fan_number = adj_fan_number; + return lwc()->DistanceToTheNeutralFibre(p, adj_fan_number); + } + + int ModuleFanCalculator::PhiGapNumberForWheel(int i) const { + i += lwc()->m_ZeroGapNumber; + i -= lwc()->m_LastFan / 2; + if(i < 0) i += lwc()->m_NumberOfFans; + if(i >= lwc()->m_NumberOfFans) i -= lwc()->m_NumberOfFans; + return i; + } + + std::pair<int, int> ModuleFanCalculator::GetPhiGapAndSide(const CLHEP::Hep3Vector &p) const + { + // Note: this object was changed from static to local for thread-safety. + // If this is found to be too costly we can re-evaluate. + CLHEP::Hep3Vector p1 = p; + static const double halfpi=M_PI/2.0; + int fan_number = int((p.phi() - halfpi - lwc()->m_ZeroFanPhi) / lwc()->m_FanStepOnPhi); + + double angle = lwc()->m_FanStepOnPhi * fan_number + lwc()->m_ZeroFanPhi; + p1.rotateZ(-angle); + + double d0 = lwc()->DistanceToTheNeutralFibre(p1, lwc()->adjust_fan_number(fan_number)); + double d1 = d0; + + int delta = 1; + if(d0 < 0.) delta = -1; + angle = - lwc()->m_FanStepOnPhi * delta; + do { + p1.rotateZ(angle); + fan_number += delta; + d1 = lwc()->DistanceToTheNeutralFibre(p1, lwc()->adjust_fan_number(fan_number)); + } while(d0 * d1 > 0.); + if(delta > 0) fan_number --; + if(!lwc()->m_isElectrode) fan_number ++; + + int adj_fan_number = fan_number; + if(adj_fan_number < lwc()->m_FirstFan) adj_fan_number = lwc()->m_FirstFan - 1; + else if(adj_fan_number > lwc()->m_LastFan) adj_fan_number = lwc()->m_LastFan; + + p1.rotateZ(-0.5 * angle); + double dd = lwc()->DistanceToTheNeutralFibre(p1, adj_fan_number); + int side = dd < 0.? -1: 1; +#ifdef HARDDEBUG + printf("GetPhiGapAndSide: MFN %4d\n", adj_fan_number); +#endif + return std::pair<int, int>(adj_fan_number, side); + } + +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/ModuleFanCalculator.h b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/ModuleFanCalculator.h new file mode 100644 index 0000000000000000000000000000000000000000..b9e3987af6bbcbbbe818804d0e1d64f777fef799 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/ModuleFanCalculator.h @@ -0,0 +1,35 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef __LArWheelCalculator_Impl_ModuleFanCalculator_H__ +#define __LArWheelCalculator_Impl_ModuleFanCalculator_H__ + +#include "IFanCalculator.h" + +class LArWheelCalculator; + +namespace LArWheelCalculator_Impl +{ + + /// This is an interface of distance calculation to parts of the LAr endcap. + class ModuleFanCalculator : public IFanCalculator + { + public: + ModuleFanCalculator(LArWheelCalculator* lwc); + + // geometry methods: + virtual double DistanceToTheNearestFan(CLHEP::Hep3Vector &p, int & out_fan_number) const; + virtual int PhiGapNumberForWheel(int i) const; + virtual std::pair<int, int> GetPhiGapAndSide(const CLHEP::Hep3Vector &p) const; + + inline const LArWheelCalculator *lwc() const { return m_lwc; }; + + private: + LArWheelCalculator* m_lwc; + + }; + +} + +#endif // __LArWheelCalculator_Impl_ModuleFanCalculator_H__ diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/WheelFanCalculator.h b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/WheelFanCalculator.h new file mode 100644 index 0000000000000000000000000000000000000000..12c9a5a716a2929aeef76d69a3f4d6534ec989ac --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/WheelFanCalculator.h @@ -0,0 +1,264 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef LARWHEELCALCULATOR_IMPL_WHEELFANCALCULATOR_H +#define LARWHEELCALCULATOR_IMPL_WHEELFANCALCULATOR_H + +#include "IFanCalculator.h" +#include "GeoSpecialShapes/LArWheelCalculator.h" + +#ifdef HARDDEBUG +#undef HARDDEBUG +#endif + +namespace LArWheelCalculator_Impl +{ + + // mode marker classes + class SaggingOn_t {}; + class SaggingOff_t {}; + + template <typename SaggingType> + class DistanceToTheNeutralFibre_OfFan {}; + + template<> + class DistanceToTheNeutralFibre_OfFan<SaggingOn_t> + { + public: + static inline double calculate(const LArWheelCalculator* lwc, int fan_number, CLHEP::Hep3Vector &p) { + //lwc->set_m_fan_number(fan_number); + return lwc->DistanceToTheNeutralFibre(p, lwc->adjust_fan_number(fan_number)); + } + }; + + template<> class DistanceToTheNeutralFibre_OfFan<SaggingOff_t> + { + public: + static inline double calculate(const LArWheelCalculator* lwc, int /*fan_number*/, CLHEP::Hep3Vector &p) { + // saggingOff distance calculations does not use fan_number, use arbitrary recognisible magic number + return lwc->DistanceToTheNeutralFibre(p, -531135); + } + }; + + enum FanSearchDirection_t { + FORWARD = 1, // delta = 1 + BACKWARD = -1 // delta = -1 + }; + + + template <typename SaggingType, FanSearchDirection_t dir > + class StepFan {}; + + + template <FanSearchDirection_t dir > + class StepFan<SaggingOff_t, dir> + { + public: + static inline void next(int &/*fan_number*/) {} + static inline void adjust(int &/*fan_number*/) {} + }; + + + template <> + class StepFan<SaggingOn_t, FORWARD> + { + public: + static inline void next(int &fan_number) { + fan_number++; + } + static inline void adjust(int &fan_number) { + fan_number--; + } + }; + + template <> + class StepFan<SaggingOn_t, BACKWARD> + { + public: + static inline void next(int &fan_number) { + fan_number--; + } + static inline void adjust(int &/*fan_number*/) {} + }; + + template <FanSearchDirection_t dir> + class DoSearch {}; + + template <> + class DoSearch<FORWARD> + { + public: + template <typename T > + static inline bool pred(T val) { + return (val > 0.); + } + }; + + template <> + class DoSearch<BACKWARD> + { + public: + template <typename T > + static inline bool pred(T val) { + return (val < 0.); + } + }; + + /// @todo Needs documentation + template <typename SaggingType, FanSearchDirection_t dir, class NFDistance > + inline void rotate_to_nearest_fan(const LArWheelCalculator* lwc, int &fan_number, + const double angle, CLHEP::Hep3Vector &p) + { + p.rotateZ(angle); + StepFan<SaggingType, dir>::next(fan_number); + //fan_number += delta; + double d1 = NFDistance::calculate(lwc, fan_number, p); + + //while(d0 * d1 > 0.) -> dir*d1 > 0 -> FORWARD: d1 > 0., BACKWARD: d1 < 0. + + while ( DoSearch<dir>::pred(d1) ) { // search: + p.rotateZ(angle); + StepFan<SaggingType, dir>::next(fan_number); + //fan_number += delta; + + d1 = NFDistance::calculate(lwc, fan_number, p); + //lwc()->set_m_fan_number(fan_number); + //d1 = lwc()->DistanceToTheNeutralFibre(p); + + } + // if signs of d1 and d0 are different, the point is between current pair + StepFan<SaggingType, dir>::adjust(fan_number); + //if(delta > 0) fan_number --; + } + + + /// LAr wheel fan calculator, templated for sagging settings. + /// + template <typename SaggingType> + class WheelFanCalculator : public IFanCalculator + { + public: + WheelFanCalculator(LArWheelCalculator* lwc) + : m_lwc(lwc) + { + } + + /// @name Geometry methods + /// @{ + + virtual double DistanceToTheNearestFan(CLHEP::Hep3Vector &p, int & out_fan_number) const + { + static const double halfpi=M_PI/2.0; + int fan_number = int((p.phi() - halfpi - lwc()->m_ZeroFanPhi_ForDetNeaFan) / lwc()->m_FanStepOnPhi); + const double angle = lwc()->m_FanStepOnPhi * fan_number + lwc()->m_ZeroFanPhi_ForDetNeaFan; +#ifdef HARDDEBUG + printf("DistanceToTheNearestFan: initial FN %4d\n", fan_number); +#endif + p.rotateZ(-angle); + // determine search direction + typedef DistanceToTheNeutralFibre_OfFan<SaggingType> NFDistance; + + const double d0 = NFDistance::calculate(lwc(), fan_number, p); + //lwc()->set_m_fan_number(fan_number); + //double d0 = lwc()->DistanceToTheNeutralFibre(p); + + const int delta = (d0 < 0.) ? -1 : 1; + //int delta = 1; // delta = signof(d0) + //if(d0 < 0.) delta = -1; // search direction has been determined + + const double step_angle = - lwc()->m_FanStepOnPhi * delta; + + if (delta > 0) { // forward search + rotate_to_nearest_fan< SaggingType, FORWARD, NFDistance >( lwc(), fan_number, step_angle, p); + } else { // backward search + rotate_to_nearest_fan< SaggingType, BACKWARD, NFDistance >( lwc(), fan_number, step_angle, p); + } + + /* + double d1 = d0; + do { // search: + p.rotateZ(angle); + fan_number += delta; + + d1 = NFDistance::calculate(lwc(), fan_number, p); + //lwc()->set_m_fan_number(fan_number); + //d1 = lwc()->DistanceToTheNeutralFibre(p); + +#ifdef HARDDEBUG + printf("DistanceToTheNearestFan: step FN %4d %4d\n", fan_number, lwc()->m_fan_number); +#endif + } while(d0 * d1 > 0.); + // if signs of d1 and d0 are different, the point is between current pair + if(delta > 0) fan_number --; + */ + + p.rotateZ(-0.5 * step_angle); +#ifdef HARDDEBUG + printf("DistanceToTheNearestFan: final FN %4d\n", fan_number); +#endif + + out_fan_number = lwc()->adjust_fan_number(fan_number); + return lwc()->DistanceToTheNeutralFibre(p, out_fan_number); + } + + virtual int PhiGapNumberForWheel(int i) const + { + return i; + } + + virtual std::pair<int, int> GetPhiGapAndSide(const CLHEP::Hep3Vector &p) const + { + static const double halfpi=M_PI/2.0; + CLHEP::Hep3Vector p1 = p; + + int fan_number = int((p.phi() - halfpi - lwc()->m_ZeroFanPhi) / lwc()->m_FanStepOnPhi); + const double angle = lwc()->m_FanStepOnPhi * fan_number + lwc()->m_ZeroFanPhi; + p1.rotateZ(-angle); + + typedef DistanceToTheNeutralFibre_OfFan<SaggingType> NFDistance; + + const double d0 = NFDistance::calculate(lwc(), fan_number, p1); + //lwc()->set_m_fan_number(fan_number); + //double d0 = lwc()->DistanceToTheNeutralFibre(p1); + + double d1 = d0; + + const int delta = (d0 < 0.) ? -1 : 1; + //int delta = 1; + //if(d0 < 0.) delta = -1; + const double step_angle = - lwc()->m_FanStepOnPhi * delta; + do { + p1.rotateZ(step_angle); + fan_number += delta; + d1 = NFDistance::calculate(lwc(), fan_number, p1); + //lwc()->set_m_fan_number(fan_number); + //d1 = lwc()->DistanceToTheNeutralFibre(p1); + } while(d0 * d1 > 0.); + + if(delta > 0) fan_number --; + if(!lwc()->m_isElectrode) fan_number ++; + + p1.rotateZ(-0.5 * step_angle); + + const int a_fan_number = lwc()->adjust_fan_number(fan_number); + double dd = lwc()->DistanceToTheNeutralFibre(p1, a_fan_number); + int side = dd < 0.? -1: 1; +#ifdef HARDDEBUG + printf("GetPhiGapAndSide: MFN %4d\n", a_fan_number); +#endif + return std::pair<int, int>(a_fan_number, side); + } + + /// @} + + inline const LArWheelCalculator *lwc() const { return m_lwc; }; + + private: + LArWheelCalculator* m_lwc; + + }; + +} + +#endif // LARWHEELCALCULATOR_IMPL_WHEELFANCALCULATOR_H diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/sincos_poly.cxx b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/sincos_poly.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b9e35d653962f6da89d25a7953afefaac62ce7f2 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/DetectorDescription/GeoModel/GeoSpecialShapes/src/LArWheelCalculator_Impl/sincos_poly.cxx @@ -0,0 +1,298 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +#include "GeoSpecialShapes/LArWheelCalculator.h" + +#include "CxxUtils/sincos.h" + +#ifdef PORTABLE_LAR_SHAPE +#define SINCOSPOLY_USE_EIGEN 1 +#endif + +#ifndef SINCOSPOLY_USE_EIGEN +#include "TMath.h" +#include "TMatrixD.h" +#include "TVectorD.h" +#include "TMatrixDLazy.h" +#include "TDecompLU.h" +#include "TDecompSVD.h" +typedef TVectorD VECTOR; +typedef TMatrixD MATRIX; +typedef TMatrixDSym SYMMATRIX; +#else +#include "Eigen/Dense" +typedef Eigen::VectorXd VECTOR; +typedef Eigen::MatrixXd MATRIX; +typedef Eigen::MatrixXd SYMMATRIX; +#define Int_t int +#define Double_t double +#endif + +#include <sys/time.h> +#include <iostream> +#include <iomanip> +#include <math.h> +#include <mutex> + +#define DEBUGPRINT 0 +#include "GeoModelKernel/Units.h" +using namespace GeoModelKernelUnits; + +#ifndef SINCOSPOLY_USE_EIGEN +template<typename T, typename Q> +std::ostream & operator << (std::ostream & ostr, const TVectorT<T> & v) +{ + std::ios_base::fmtflags save_flags(ostr.flags()); + ostr << '['; + ostr << std::scientific; + for(Int_t idx=v.GetLwb();idx<v.GetUpb();idx++) { + ostr << v[idx] << ", "; + } + ostr << v[v.GetUpb()]; + ostr << ']'; + ostr.flags(save_flags); + return ostr; +} +#endif + +// find best approximation of y values using linear combination of basis functions in bf +static VECTOR findLinearApproximation( + const Int_t dataLen, const Int_t nBasisFuntions, + const VECTOR &y, const MATRIX & bf) +{ +#ifndef SINCOSPOLY_USE_EIGEN + SYMMATRIX A(nBasisFuntions); + VECTOR vY(nBasisFuntions); +#else + SYMMATRIX A=SYMMATRIX::Zero(nBasisFuntions,nBasisFuntions); + VECTOR vY=VECTOR::Zero(nBasisFuntions); +#endif + for(Int_t j = 0; j < nBasisFuntions; ++ j){ + for(Int_t k = 0; k < nBasisFuntions; ++ k){ + Double_t Ajk = 0.0; + for(Int_t i = 0; i < dataLen; ++ i){ + Ajk += bf(j, i) * bf(k, i); + } + A(j, k) = Ajk; + } + } + + for(Int_t k = 0; k < nBasisFuntions; ++ k){ + Double_t vYk = 0.0; + for(Int_t i = 0; i < dataLen; ++ i){ + vYk += y[i]*bf(k,i); + } + vY[k] = vYk; + } +#ifndef SINCOSPOLY_USE_EIGEN + SYMMATRIX Ainv(A); + Ainv.Invert(); + return Ainv*vY; +#else + return A.inverse()*vY; +#endif +} + +using namespace CLHEP; + +void LArWheelCalculator::fill_sincos_parameterization() +{ + const Int_t nrPolyDegree = LARWC_SINCOS_POLY; +#if LARWC_SINCOS_POLY > 4 && DEBUGPRINT + std::cout << "LARWC_SINCOS_POLY: " << LARWC_SINCOS_POLY << std::endl; +#endif + const Int_t nBasisFunctions = nrPolyDegree + 1; + + // We compute the polynomial approximations once per side, and store them in + // the static variables below for reuse in successive calculator instances. + // For multi-threading, then, this code needs to be mutex locked. + // FIXME: this could done in a cleaner way. + static std::mutex fillParamMutex; + std::lock_guard<std::mutex> lock(fillParamMutex); + + static bool filled[2] = { false, false }; + static double sin_parametrization[2][nBasisFunctions]; + static double cos_parametrization[2][nBasisFunctions]; + + // Reuse the computation if already performed + size_t S = m_isInner? 0: 1; + if(filled[S]){ + for(Int_t i = 0; i < nBasisFunctions; ++ i){ + m_sin_parametrization[i] = sin_parametrization[S][i]; + m_cos_parametrization[i] = cos_parametrization[S][i]; + } + + // Parameterization for the vectorized sincos calculation + // see ATLASSIM-4753 for details + // s4, s5, c4, c5 + // s2, s3, c2, c3 + // s0, s1, c0, c1 + m_vsincos_par.param_0[0] = m_sin_parametrization[4]; + m_vsincos_par.param_0[1] = m_sin_parametrization[5]; + m_vsincos_par.param_0[2] = m_cos_parametrization[4]; + m_vsincos_par.param_0[3] = m_cos_parametrization[5]; + m_vsincos_par.param_1[0] = m_sin_parametrization[2]; + m_vsincos_par.param_1[1] = m_sin_parametrization[3]; + m_vsincos_par.param_1[2] = m_cos_parametrization[2]; + m_vsincos_par.param_1[3] = m_cos_parametrization[3]; + m_vsincos_par.param_2[0] = m_sin_parametrization[0]; + m_vsincos_par.param_2[1] = m_sin_parametrization[1]; + m_vsincos_par.param_2[2] = m_cos_parametrization[0]; + m_vsincos_par.param_2[3] = m_cos_parametrization[1]; + return; + } + + //const Double_t Rmin = m_isInner? 290.*mm: 600.*mm; + //const Double_t Rmax = m_isInner? 710.*mm: 2050.*mm; + const Double_t Rmin = m_isInner? 250.*mm: 560.*mm; + const Double_t Rmax = m_isInner? 750.*mm: 2090.*mm; + //const Double_t Rmin = m_isInner? 220.*mm: 530.*mm; + //const Double_t Rmax = m_isInner? 780.*mm: 2120.*mm; + const Double_t Rstep = 1.*mm; + const Int_t nrPoints = (Rmax - Rmin) * (1./Rstep); + const Int_t dataLen = nrPoints + 1; +#ifndef SINCOSPOLY_USE_EIGEN + VECTOR x(dataLen); // angle points + VECTOR ysin(dataLen); // to be approximated function values at angle points - sin + VECTOR ycos(dataLen); // to be approximated function values at angle points - cos + MATRIX bf(nBasisFunctions, dataLen); // Matrix of values of basis functions at angle points +#else + VECTOR x=VECTOR::Zero(dataLen); // angle points + VECTOR ysin=VECTOR::Zero(dataLen); // to be approximated function values at angle points - sin + VECTOR ycos=VECTOR::Zero(dataLen); // to be approximated function values at angle points - cos + MATRIX bf=MATRIX::Zero(nBasisFunctions, dataLen); // Matrix of values of basis functions at angle points +#endif + for(Int_t i = 0; i < dataLen; ++ i){ + const Double_t a = Rmin + i * Rstep; + x[i] = a; + CxxUtils::sincos scalpha(parameterized_slant_angle(a)); + ysin[i] = scalpha.sn; + ycos[i] = scalpha.cs; + for(Int_t n = 0; n < nBasisFunctions; ++ n) { + bf(n, i) = pow(a, n); + } + } + + VECTOR params_sin = + findLinearApproximation(dataLen, nBasisFunctions, ysin, bf); + VECTOR params_cos = + findLinearApproximation(dataLen, nBasisFunctions, ycos, bf); + + for(Int_t i = 0; i < nBasisFunctions; ++ i){ + m_sin_parametrization[i] = params_sin[i]; + m_cos_parametrization[i] = params_cos[i]; + sin_parametrization[S][i] = params_sin[i]; + cos_parametrization[S][i] = params_cos[i]; + } + + // Parameterization for the vectorized sincos calculation + // see ATLASSIM-4753 for details + // s4, s5, c4, c5 + // s2, s3, c2, c3 + // s0, s1, c0, c1 + m_vsincos_par.param_0[0] = m_sin_parametrization[4]; + m_vsincos_par.param_0[1] = m_sin_parametrization[5]; + m_vsincos_par.param_0[2] = m_cos_parametrization[4]; + m_vsincos_par.param_0[3] = m_cos_parametrization[5]; + m_vsincos_par.param_1[0] = m_sin_parametrization[2]; + m_vsincos_par.param_1[1] = m_sin_parametrization[3]; + m_vsincos_par.param_1[2] = m_cos_parametrization[2]; + m_vsincos_par.param_1[3] = m_cos_parametrization[3]; + m_vsincos_par.param_2[0] = m_sin_parametrization[0]; + m_vsincos_par.param_2[1] = m_sin_parametrization[1]; + m_vsincos_par.param_2[2] = m_cos_parametrization[0]; + m_vsincos_par.param_2[3] = m_cos_parametrization[1]; + filled[S] = true; + + // FIXME: nothing below is needed unless debug printing + +#if DEBUGPRINT + std::cout << "sin params:" << params_sin << std::endl; + std::cout << "cos params:" << params_cos << std::endl; + + double dsinr = 0., dcosr = 0.; + double dtrigr = 0; +#endif + + double dsin = 0., dcos = 0.; + double dtrig = 0.; + for(double r = Rmin + 40.; r < Rmax - 40.; r += Rstep / 10.){ + CxxUtils::sincos scalpha(parameterized_slant_angle(r)); + double sin_a, cos_a; + double sin_a_v, cos_a_v; + parameterized_sincos(r, sin_a, cos_a); + m_vsincos_par.eval(r, sin_a_v, cos_a_v); +#if DEBUGPRINT + std::streamsize ss = std::cout.precision(); + std::cout.precision(16); + std::cout << "def: " << r << " " << sin_a << " " << cos_a << std::endl; + std::cout << "vec: " << r << " " << sin_a_v << " " << cos_a_v << std::endl; + std::cout << "dif: " << r << " " << (sin_a - sin_a_v) / sin_a << " " << (cos_a - cos_a_v) / cos_a << std::endl; + std::cout.precision(ss); +#endif + double ds = fabs(scalpha.sn - sin_a); + if(ds > dsin){ + dsin = ds; +#if DEBUGPRINT + dsinr = r; +#endif + } + double dc = fabs(scalpha.cs - cos_a); + if(dc > dcos){ + dcos = dc; +#if DEBUGPRINT + dcosr = r; +#endif + } + double dt = fabs(sin_a*sin_a + cos_a*cos_a - 1.); + if(dt > dtrig){ + dtrig = dt; +#if DEBUGPRINT + dtrigr = r; +#endif + } + } + +#if DEBUGPRINT + std::cout << "Max. difference: " << std::endl + << "\tsin: " << dsin << " at " << dsinr << std::endl + << "\tcos: " << dcos << " at " << dcosr << std::endl + << "\tsin^2+cos^2: " << dtrig << " at " << dtrigr << std::endl; +#endif + +#ifdef HARDDEBUG + TVectorD y_test(dataLen); + const Int_t nIter=10000; + std::cout << "Perfomance test started, " << nIter << " iterations" << std::endl; + + double y_testsin[dataLen]; + double y_testcos[dataLen]; + struct timeval tvsincos_start, tvsincos_stop; + gettimeofday(&tvsincos_start, 0); + for(Int_t iIter=0;iIter<nIter;iIter++) { + for(Int_t i=0;i<dataLen;i++) { + sincos(parameterized_slant_angle(x[i]), &y_testsin[i], &y_testcos[i]); + } + } + gettimeofday(&tvsincos_stop, 0); + double timeSinCos=(tvsincos_stop.tv_sec-tvsincos_start.tv_sec + 1E-6*(tvsincos_stop.tv_usec-tvsincos_start.tv_usec))/nIter; + + std::cout.unsetf ( std::ios::fixed | std::ios::scientific ); + std::cout << "Time to fill 2x" << dataLen << " elements using sincos function: " << timeSinCos << std::endl; + + struct timeval tvpoly_start, tvpoly_stop; + gettimeofday(&tvpoly_start, 0); + for(Int_t iIter=0;iIter<nIter;iIter++) { + for(Int_t i=0;i<dataLen;i++) { + parameterized_sincos(x[i], y_testsin[i], y_testcos[i]); + } + } + gettimeofday(&tvpoly_stop, 0); + double timePoly=(tvpoly_stop.tv_sec - tvpoly_start.tv_sec + 1E-6*(tvpoly_stop.tv_usec - tvpoly_start.tv_usec))/nIter; + std::cout << "Time to fill 2x" << dataLen << " elements using approximation sin&cos: " << timePoly << std::endl; + std::cout.unsetf ( std::ios::fixed | std::ios::scientific ); + std::cout << "Approximation is " << timeSinCos/timePoly << " faster " << std::endl; +#endif + +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/G4ShiftedCone.cxx b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/G4ShiftedCone.cxx new file mode 100644 index 0000000000000000000000000000000000000000..82743f9a2f8f37ee804520b2257273f63d4a5d6b --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/G4ShiftedCone.cxx @@ -0,0 +1,2266 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +// +// The G4ShiftedCone class copied from standard G4Cons and modified to: +// 1) have an arbitrary position along Z axis, +// 2) represent a twopi-cone. Sectors are not supported but the +// corresponding code kept and just commented out. +// + +// +// ******************************************************************** +// * License and Disclaimer * +// * * +// * The Geant4 software is copyright of the Copyright Holders of * +// * the Geant4 Collaboration. It is provided under the terms and * +// * conditions of the Geant4 Software License, included in the file * +// * LICENSE and available at http://cern.ch/geant4/license . These * +// * include a list of copyright holders. * +// * * +// * Neither the authors of this software system, nor their employing * +// * institutes,nor the agencies providing financial support for this * +// * work make any representation or warranty, express or implied, * +// * regarding this software system or assume any liability for its * +// * use. Please see the license in the file LICENSE and URL above * +// * for the full disclaimer and the limitation of liability. * +// * * +// * This code implementation is the result of the scientific and * +// * technical work of the GEANT4 collaboration. * +// * By using, copying, modifying or distributing the software (or * +// * any work based on the software) you agree to acknowledge its * +// * use in resulting scientific publications, and indicate your * +// * acceptance of all terms of the Geant4 Software license. * +// ******************************************************************** +// +// +// +// +// class G4ShiftedCone +// +// Implementation for G4ShiftedCone class +// +// History: +// 03.07.2019 A. Sukharev: copied from G4Cons +// -------------------------------------------------------------------- + +#include "G4ShiftedCone.h" + +#include "G4GeomTools.hh" +#include "G4VoxelLimits.hh" +#include "G4AffineTransform.hh" +#include "G4BoundingEnvelope.hh" +#include "G4GeometryTolerance.hh" + +#include "G4VPVParameterisation.hh" + +#include "meshdefs.hh" + +#include "Randomize.hh" + +#include "G4VGraphicsScene.hh" + +using namespace CLHEP; + +//////////////////////////////////////////////////////////////////////// +// +// Private enum: Not for external use - used by distanceToOut + +enum ESide {kNull,kRMin,kRMax,kSPhi,kEPhi,kPZ,kMZ}; + +// used by normal + +enum ENorm {kNRMin,kNRMax,kNSPhi,kNEPhi,kNZ}; + +////////////////////////////////////////////////////////////////////////// +// +// constructor - check parameters, convert angles so 0<sphi+dpshi<=2_PI +// - note if pDPhi>2PI then reset to 2PI + +G4ShiftedCone::G4ShiftedCone( const G4String& pName, + G4double pZ1, G4double pZ2, + G4double pRmin1, G4double pRmax1, + G4double pRmin2, G4double pRmax2) +// G4double pDz, +// G4double pSPhi, G4double pDPhi) + : G4CSGSolid(pName), + kRadTolerance (G4GeometryTolerance::GetInstance()->GetRadialTolerance()), + kAngTolerance (G4GeometryTolerance::GetInstance()->GetAngularTolerance()), + fRmin1(pRmin1), fRmin2(pRmin2), + fRmax1(pRmax1), fRmax2(pRmax2), + fDz((pZ2 - pZ1) * 0.5), fZshift(pZ1 + fDz), + // fSPhi(0.), fDPhi(0.) + halfCarTolerance (kCarTolerance*0.5), + halfRadTolerance (kRadTolerance*0.5), + halfAngTolerance (kAngTolerance*0.5) +{ + // Check z-len + // + if ( fDz < 0 ) + { + std::ostringstream message; + message << "Invalid Z half-length for Solid: " << GetName() << G4endl + << " hZ = " << fDz; + G4Exception("G4ShiftedCone::G4ShiftedCone()", "GeomSolids0002", + FatalException, message); + } + + // Check radii + // + if (((pRmin1>=pRmax1) || (pRmin2>=pRmax2) || (pRmin1<0)) && (pRmin2<0)) + { + std::ostringstream message; + message << "Invalid values of radii for Solid: " << GetName() << G4endl + << " pRmin1 = " << pRmin1 << ", pRmin2 = " << pRmin2 + << ", pRmax1 = " << pRmax1 << ", pRmax2 = " << pRmax2; + G4Exception("G4ShiftedCone::G4ShiftedCone()", "GeomSolids0002", + FatalException, message) ; + } + if( (pRmin1 == 0.0) && (pRmin2 > 0.0) ) { fRmin1 = 1e3*kRadTolerance ; } + if( (pRmin2 == 0.0) && (pRmin1 > 0.0) ) { fRmin2 = 1e3*kRadTolerance ; } + + // Check angles + // +// CheckPhiAngles(pSPhi, pDPhi); +} + +/////////////////////////////////////////////////////////////////////// +// +// Fake default constructor - sets only member data and allocates memory +// for usage restricted to object persistency. +// +G4ShiftedCone::G4ShiftedCone( __void__& a ) + : G4CSGSolid(a), kRadTolerance(0.), kAngTolerance(0.), + fRmin1(0.), fRmin2(0.), fRmax1(0.), fRmax2(0.), + fDz(0.), fZshift(0.), +// fSPhi(0.), fDPhi(0.), sinCPhi(0.), cosCPhi(0.), cosHDPhiOT(0.), +// cosHDPhiIT(0.), sinSPhi(0.), cosSPhi(0.), sinEPhi(0.), cosEPhi(0.), +// fPhiFullCone(false), + halfCarTolerance(0.), halfRadTolerance(0.), halfAngTolerance(0.) +{ +} + +/////////////////////////////////////////////////////////////////////// +// +// Destructor + +G4ShiftedCone::~G4ShiftedCone() +{ +} + +////////////////////////////////////////////////////////////////////////// +// +// Copy constructor + +G4ShiftedCone::G4ShiftedCone(const G4ShiftedCone& rhs) + : G4CSGSolid(rhs), kRadTolerance(rhs.kRadTolerance), + kAngTolerance(rhs.kAngTolerance), fRmin1(rhs.fRmin1), fRmin2(rhs.fRmin2), + fRmax1(rhs.fRmax1), fRmax2(rhs.fRmax2), fDz(rhs.fDz), fZshift(rhs.fZshift), +// fSPhi(rhs.fSPhi), +// fDPhi(rhs.fDPhi), sinCPhi(rhs.sinCPhi), cosCPhi(rhs.cosCPhi), +// cosHDPhiOT(rhs.cosHDPhiOT), cosHDPhiIT(rhs.cosHDPhiIT), +// sinSPhi(rhs.sinSPhi), cosSPhi(rhs.cosSPhi), sinEPhi(rhs.sinEPhi), +// cosEPhi(rhs.cosEPhi), fPhiFullCone(rhs.fPhiFullCone), + halfCarTolerance(rhs.halfCarTolerance), + halfRadTolerance(rhs.halfRadTolerance), + halfAngTolerance(rhs.halfAngTolerance) +{ +} + +////////////////////////////////////////////////////////////////////////// +// +// Assignment operator + +G4ShiftedCone& G4ShiftedCone::operator = (const G4ShiftedCone& rhs) +{ + // Check assignment to self + // + if (this == &rhs) { return *this; } + + // Copy base class data + // + G4CSGSolid::operator=(rhs); + + // Copy data + // + kRadTolerance = rhs.kRadTolerance; + kAngTolerance = rhs.kAngTolerance; + fRmin1 = rhs.fRmin1; fRmin2 = rhs.fRmin2; + fRmax1 = rhs.fRmax1; fRmax2 = rhs.fRmax2; + fDz = rhs.fDz; fZshift = rhs.fZshift; +// fSPhi = rhs.fSPhi; fDPhi = rhs.fDPhi; +// sinCPhi = rhs.sinCPhi; cosCPhi = rhs.cosCPhi; +// cosHDPhiOT = rhs.cosHDPhiOT; cosHDPhiIT = rhs.cosHDPhiIT; +// sinSPhi = rhs.sinSPhi; cosSPhi = rhs.cosSPhi; +// sinEPhi = rhs.sinEPhi; cosEPhi = rhs.cosEPhi; +// fPhiFullCone = rhs.fPhiFullCone; + halfCarTolerance = rhs.halfCarTolerance; + halfRadTolerance = rhs.halfRadTolerance; + halfAngTolerance = rhs.halfAngTolerance; + + return *this; +} + +///////////////////////////////////////////////////////////////////// +// +// Return whether point inside/outside/on surface + +EInside G4ShiftedCone::Inside(const G4ThreeVector& p) const +{ + G4double r2, rl, rh, /*pPhi,*/ tolRMin, tolRMax; // rh2, rl2 ; + EInside in; + + G4double z = p.z() - fZshift; + + if (std::fabs(z) > fDz + halfCarTolerance ) { return in = kOutside; } + else if(std::fabs(z) >= fDz - halfCarTolerance ) { in = kSurface; } + else { in = kInside; } + + r2 = p.x()*p.x() + p.y()*p.y() ; + rl = 0.5*(fRmin2*(z + fDz) + fRmin1*(fDz - z))/fDz ; + rh = 0.5*(fRmax2*(z+fDz)+fRmax1*(fDz-z))/fDz; + + // rh2 = rh*rh; + + tolRMin = rl - halfRadTolerance; + if ( tolRMin < 0 ) { tolRMin = 0; } + tolRMax = rh + halfRadTolerance; + + if ( (r2<tolRMin*tolRMin) || (r2>tolRMax*tolRMax) ) { return in = kOutside; } + + if (rl) { tolRMin = rl + halfRadTolerance; } + else { tolRMin = 0.0; } + tolRMax = rh - halfRadTolerance; + + if (in == kInside) // else it's kSurface already + { + if ( (r2 < tolRMin*tolRMin) || (r2 >= tolRMax*tolRMax) ) { in = kSurface; } + } +/* + if ( !fPhiFullCone && ((p.x() != 0.0) || (p.y() != 0.0)) ) + { + pPhi = std::atan2(p.y(),p.x()) ; + + if ( pPhi < fSPhi - halfAngTolerance ) { pPhi += twopi; } + else if ( pPhi > fSPhi + fDPhi + halfAngTolerance ) { pPhi -= twopi; } + + if ( (pPhi < fSPhi - halfAngTolerance) || + (pPhi > fSPhi + fDPhi + halfAngTolerance) ) { return in = kOutside; } + + else if (in == kInside) // else it's kSurface anyway already + { + if ( (pPhi < fSPhi + halfAngTolerance) || + (pPhi > fSPhi + fDPhi - halfAngTolerance) ) { in = kSurface; } + } + } + else if ( !fPhiFullCone ) { in = kSurface; } +*/ + return in ; +} + +///////////////////////////////////////////////////////////////////////// +// +// Dispatch to parameterisation for replication mechanism dimension +// computation & modification. + +void G4ShiftedCone::ComputeDimensions( G4VPVParameterisation*,// p, + const G4int ,//n, + const G4VPhysicalVolume* )//pRep ) +{ + std::ostringstream message; + message << "ComputeDimensions is not implemented for Solid: " << GetName(); + G4Exception("G4ShiftedCone::ComputeDimensions()", "GeomSolids0002", + FatalException, message) ; +// p->ComputeDimensions(*this,n,pRep) ; +} + +/////////////////////////////////////////////////////////////////////// +// +// Get bounding box + +void G4ShiftedCone::BoundingLimits(G4ThreeVector& pMin, G4ThreeVector& pMax) const +{ +// G4double rmin = std::min(GetInnerRadiusMinusZ(),GetInnerRadiusPlusZ()); + G4double rmax = std::max(GetOuterRadiusMinusZ(),GetOuterRadiusPlusZ()); + + // Find bounding box + // +/* if (GetDeltaPhiAngle() < twopi) + { + G4double dz = GetZHalfLength(); + G4TwoVector vmin,vmax; + G4GeomTools::DiskExtent(rmin,rmax, + GetSinStartPhi(),GetCosStartPhi(), + GetSinEndPhi(),GetCosEndPhi(), + vmin,vmax); + pMin.set(vmin.x(),vmin.y(),-dz); + pMax.set(vmax.x(),vmax.y(), dz); + } + else*/ + { + pMin.set(-rmax,-rmax, fZshift - fDz); + pMax.set( rmax, rmax, fZshift + fDz); + } + + // Check correctness of the bounding box + // + if (pMin.x() >= pMax.x() || pMin.y() >= pMax.y() || pMin.z() >= pMax.z()) + { + std::ostringstream message; + message << "Bad bounding box (min >= max) for solid: " + << GetName() << " !" + << "\npMin = " << pMin + << "\npMax = " << pMax; + G4Exception("G4ShiftedCone::BoundingLimits()", "GeomMgt0001", + JustWarning, message); + DumpInfo(); + } +} + +/////////////////////////////////////////////////////////////////////// +// +// Calculate extent under transform and specified limit + +G4bool G4ShiftedCone::CalculateExtent( const EAxis pAxis, + const G4VoxelLimits& pVoxelLimit, + const G4AffineTransform& pTransform, + G4double& pMin, + G4double& pMax ) const +{ + G4ThreeVector bmin, bmax; + G4bool exist; + + // Get bounding box + BoundingLimits(bmin,bmax); + + // Check bounding box + G4BoundingEnvelope bbox(bmin,bmax); +#ifdef G4BBOX_EXTENT + if (true) return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax); +#endif + if (bbox.BoundingBoxVsVoxelLimits(pAxis,pVoxelLimit,pTransform,pMin,pMax)) + { + return exist = (pMin < pMax) ? true : false; + } + + // Get parameters of the solid + G4double rmin1 = GetInnerRadiusMinusZ(); + G4double rmax1 = GetOuterRadiusMinusZ(); + G4double rmin2 = GetInnerRadiusPlusZ(); + G4double rmax2 = GetOuterRadiusPlusZ(); + G4double z1 = GetZ1(); + G4double z2 = GetZ2(); + G4double dphi = GetDeltaPhiAngle(); + + // Find bounding envelope and calculate extent + // + const G4int NSTEPS = 24; // number of steps for whole circle + G4double astep = twopi/NSTEPS; // max angle for one step + G4int ksteps = (dphi <= astep) ? 1 : (G4int)((dphi-deg)/astep) + 1; + G4double ang = dphi/ksteps; + + G4double sinHalf = std::sin(0.5*ang); + G4double cosHalf = std::cos(0.5*ang); + G4double sinStep = 2.*sinHalf*cosHalf; + G4double cosStep = 1. - 2.*sinHalf*sinHalf; + G4double rext1 = rmax1/cosHalf; + G4double rext2 = rmax2/cosHalf; + + // bounding envelope for full cone without hole consists of two polygons, + // in other cases it is a sequence of quadrilaterals + if (rmin1 == 0 && rmin2 == 0 && dphi == twopi) + { + G4double sinCur = sinHalf; + G4double cosCur = cosHalf; + + G4ThreeVectorList baseA(NSTEPS),baseB(NSTEPS); + for (G4int k=0; k<NSTEPS; ++k) + { + baseA[k].set(rext1*cosCur,rext1*sinCur, z1); + baseB[k].set(rext2*cosCur,rext2*sinCur, z2); + + G4double sinTmp = sinCur; + sinCur = sinCur*cosStep + cosCur*sinStep; + cosCur = cosCur*cosStep - sinTmp*sinStep; + } + std::vector<const G4ThreeVectorList *> polygons(2); + polygons[0] = &baseA; + polygons[1] = &baseB; + G4BoundingEnvelope benv(bmin,bmax,polygons); + exist = benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax); + } + else + { + + G4double sinStart = GetSinStartPhi(); + G4double cosStart = GetCosStartPhi(); + G4double sinEnd = GetSinEndPhi(); + G4double cosEnd = GetCosEndPhi(); + G4double sinCur = sinStart*cosHalf + cosStart*sinHalf; + G4double cosCur = cosStart*cosHalf - sinStart*sinHalf; + + // set quadrilaterals + G4ThreeVectorList pols[NSTEPS+2]; + for (G4int k=0; k<ksteps+2; ++k) pols[k].resize(4); + pols[0][0].set(rmin2*cosStart,rmin2*sinStart, z2); + pols[0][1].set(rmin1*cosStart,rmin1*sinStart, z1); + pols[0][2].set(rmax1*cosStart,rmax1*sinStart, z1); + pols[0][3].set(rmax2*cosStart,rmax2*sinStart, z2); + for (G4int k=1; k<ksteps+1; ++k) + { + pols[k][0].set(rmin2*cosCur,rmin2*sinCur, z2); + pols[k][1].set(rmin1*cosCur,rmin1*sinCur, z1); + pols[k][2].set(rext1*cosCur,rext1*sinCur, z1); + pols[k][3].set(rext2*cosCur,rext2*sinCur, z2); + + G4double sinTmp = sinCur; + sinCur = sinCur*cosStep + cosCur*sinStep; + cosCur = cosCur*cosStep - sinTmp*sinStep; + } + pols[ksteps+1][0].set(rmin2*cosEnd,rmin2*sinEnd, z2); + pols[ksteps+1][1].set(rmin1*cosEnd,rmin1*sinEnd, z1); + pols[ksteps+1][2].set(rmax1*cosEnd,rmax1*sinEnd, z1); + pols[ksteps+1][3].set(rmax2*cosEnd,rmax2*sinEnd, z2); + + // set envelope and calculate extent + std::vector<const G4ThreeVectorList *> polygons; + polygons.resize(ksteps+2); + for (G4int k=0; k<ksteps+2; ++k) polygons[k] = &pols[k]; + G4BoundingEnvelope benv(bmin,bmax,polygons); + exist = benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax); + } + return exist; +} + +//////////////////////////////////////////////////////////////////////// +// +// Return unit normal of surface closest to p +// - note if point on z axis, ignore phi divided sides +// - unsafe if point close to z axis a rmin=0 - no explicit checks + +G4ThreeVector G4ShiftedCone::SurfaceNormal( const G4ThreeVector& p) const +{ + G4int noSurfaces = 0; + G4double rho;//, pPhi; + G4double distZ, distRMin, distRMax; +// G4double distSPhi = kInfinity, distEPhi = kInfinity; + G4double tanRMin, secRMin, pRMin, widRMin; + G4double tanRMax, secRMax, pRMax, widRMax; + + G4ThreeVector norm, sumnorm(0.,0.,0.), nZ = G4ThreeVector(0.,0.,1.); + G4ThreeVector nR, nr(0.,0.,0.), nPs, nPe; + + G4double z = p.z() - fZshift; + + distZ = std::fabs(std::fabs(z) - fDz); + rho = std::sqrt(p.x()*p.x() + p.y()*p.y()); + + tanRMin = (fRmin2 - fRmin1)*0.5/fDz; + secRMin = std::sqrt(1 + tanRMin*tanRMin); + pRMin = rho - z*tanRMin; + widRMin = fRmin2 - fDz*tanRMin; + distRMin = std::fabs(pRMin - widRMin)/secRMin; + + tanRMax = (fRmax2 - fRmax1)*0.5/fDz; + secRMax = std::sqrt(1+tanRMax*tanRMax); + pRMax = rho - z*tanRMax; + widRMax = fRmax2 - fDz*tanRMax; + distRMax = std::fabs(pRMax - widRMax)/secRMax; +/* + if (!fPhiFullCone) // Protected against (0,0,z) + { + if ( rho ) + { + pPhi = std::atan2(p.y(),p.x()); + + if (pPhi < fSPhi-halfCarTolerance) { pPhi += twopi; } + else if (pPhi > fSPhi+fDPhi+halfCarTolerance) { pPhi -= twopi; } + + distSPhi = std::fabs( pPhi - fSPhi ); + distEPhi = std::fabs( pPhi - fSPhi - fDPhi ); + } + else if( !(fRmin1) || !(fRmin2) ) + { + distSPhi = 0.; + distEPhi = 0.; + } + nPs = G4ThreeVector(std::sin(fSPhi), -std::cos(fSPhi), 0); + nPe = G4ThreeVector(-std::sin(fSPhi+fDPhi), std::cos(fSPhi+fDPhi), 0); + }*/ + if ( rho > halfCarTolerance ) + { + nR = G4ThreeVector(p.x()/rho/secRMax, p.y()/rho/secRMax, -tanRMax/secRMax); + if (fRmin1 || fRmin2) + { + nr = G4ThreeVector(-p.x()/rho/secRMin,-p.y()/rho/secRMin,tanRMin/secRMin); + } + } + + if( distRMax <= halfCarTolerance ) + { + noSurfaces ++; + sumnorm += nR; + } + if( (fRmin1 || fRmin2) && (distRMin <= halfCarTolerance) ) + { + noSurfaces ++; + sumnorm += nr; + } +/* if( !fPhiFullCone ) + { + if (distSPhi <= halfAngTolerance) + { + noSurfaces ++; + sumnorm += nPs; + } + if (distEPhi <= halfAngTolerance) + { + noSurfaces ++; + sumnorm += nPe; + } + }*/ + if (distZ <= halfCarTolerance) + { + noSurfaces ++; + if ( z >= 0.) { sumnorm += nZ; } + else { sumnorm -= nZ; } + } + if ( noSurfaces == 0 ) + { +#ifdef G4CSGDEBUG + G4Exception("G4ShiftedCone::SurfaceNormal(p)", "GeomSolids1002", + JustWarning, "Point p is not on surface !?" ); +#endif + norm = ApproxSurfaceNormal(p); + } + else if ( noSurfaces == 1 ) { norm = sumnorm; } + else { norm = sumnorm.unit(); } + + return norm ; +} + +//////////////////////////////////////////////////////////////////////////// +// +// Algorithm for SurfaceNormal() following the original specification +// for points not on the surface + +G4ThreeVector G4ShiftedCone::ApproxSurfaceNormal( const G4ThreeVector& p ) const +{ + ENorm side ; + G4ThreeVector norm ; + G4double rho;//, phi ; + G4double distZ, distRMin, distRMax;//, distSPhi, distEPhi, distMin ; + G4double tanRMin, secRMin, pRMin, widRMin ; + G4double tanRMax, secRMax, pRMax, widRMax ; + + G4double z = p.z() - fZshift; + + distZ = std::fabs(std::fabs(z) - fDz) ; + rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ; + + tanRMin = (fRmin2 - fRmin1)*0.5/fDz ; + secRMin = std::sqrt(1 + tanRMin*tanRMin) ; + pRMin = rho - z*tanRMin ; + widRMin = fRmin2 - fDz*tanRMin ; + distRMin = std::fabs(pRMin - widRMin)/secRMin ; + + tanRMax = (fRmax2 - fRmax1)*0.5/fDz ; + secRMax = std::sqrt(1+tanRMax*tanRMax) ; + pRMax = rho - z*tanRMax ; + widRMax = fRmax2 - fDz*tanRMax ; + distRMax = std::fabs(pRMax - widRMax)/secRMax ; + + if (distRMin < distRMax) // First minimum + { + if (distZ < distRMin) + { +// distMin = distZ ; + side = kNZ ; + } + else + { +// distMin = distRMin ; + side = kNRMin ; + } + } + else + { + if (distZ < distRMax) + { +// distMin = distZ ; + side = kNZ ; + } + else + { +// distMin = distRMax ; + side = kNRMax ; + } + } +/* + if ( !fPhiFullCone && rho ) // Protected against (0,0,z) + { + phi = std::atan2(p.y(),p.x()) ; + + if (phi < 0) { phi += twopi; } + + if (fSPhi < 0) { distSPhi = std::fabs(phi - (fSPhi + twopi))*rho; } + else { distSPhi = std::fabs(phi - fSPhi)*rho; } + + distEPhi = std::fabs(phi - fSPhi - fDPhi)*rho ; + + // Find new minimum + + if (distSPhi < distEPhi) + { + if (distSPhi < distMin) { side = kNSPhi; } + } + else + { + if (distEPhi < distMin) { side = kNEPhi; } + } + }*/ + switch (side) + { + case kNRMin: // Inner radius + rho *= secRMin ; + norm = G4ThreeVector(-p.x()/rho, -p.y()/rho, tanRMin/secRMin) ; + break ; + case kNRMax: // Outer radius + rho *= secRMax ; + norm = G4ThreeVector(p.x()/rho, p.y()/rho, -tanRMax/secRMax) ; + break ; + case kNZ: // +/- dz + if (z > 0) { norm = G4ThreeVector(0,0,1); } + else { norm = G4ThreeVector(0,0,-1); } + break ; +// case kNSPhi: +// norm = G4ThreeVector(std::sin(fSPhi), -std::cos(fSPhi), 0) ; +// break ; +// case kNEPhi: +// norm=G4ThreeVector(-std::sin(fSPhi+fDPhi), std::cos(fSPhi+fDPhi), 0) ; +// break ; + default: // Should never reach this case... + DumpInfo(); + G4Exception("G4ShiftedCone::ApproxSurfaceNormal()", + "GeomSolids1002", JustWarning, + "Undefined side for valid surface normal to solid."); + break ; + } + return norm ; +} + +//////////////////////////////////////////////////////////////////////// +// +// Calculate distance to shape from outside, along normalised vector +// - return kInfinity if no intersection, or intersection distance <= tolerance +// +// - Compute the intersection with the z planes +// - if at valid r, phi, return +// +// -> If point is outside cone, compute intersection with rmax1*0.5 +// - if at valid phi,z return +// - if inside outer cone, handle case when on tolerant outer cone +// boundary and heading inwards(->0 to in) +// +// -> Compute intersection with inner cone, taking largest +ve root +// - if valid (in z,phi), save intersction +// +// -> If phi segmented, compute intersections with phi half planes +// - return smallest of valid phi intersections and +// inner radius intersection +// +// NOTE: +// - `if valid' implies tolerant checking of intersection points +// - z, phi intersection from Tubs + +G4double G4ShiftedCone::DistanceToIn( const G4ThreeVector& p, + const G4ThreeVector& v ) const +{ + G4double snxt = kInfinity ; // snxt = default return value + const G4double dRmax = 50*(fRmax1+fRmax2);// 100*(Rmax1+Rmax2)/2. + + G4double tanRMax,secRMax,rMaxAv;//,rMaxOAv ; // Data for cones + G4double tanRMin,secRMin,rMinAv;//,rMinOAv ; + G4double rout,rin ; + + G4double tolORMin,/*tolORMin2,*/tolIRMin,tolIRMin2 ; // `generous' radii squared + G4double /*tolORMax2,*/tolIRMax,tolIRMax2 ; + G4double tolODz,tolIDz ; + + G4double /*Dist,*/ sd,xi,yi,zi,ri=0.,risec,rhoi2;//,cosPsi ; // Intersection point vars + + G4double t1,t2,t3,b,c,d ; // Quadratic solver variables + G4double nt1,nt2,nt3 ; +// G4double Comp ; + + G4ThreeVector Normal; + + G4double z = p.z() - fZshift; + + // Cone Precalcs + + tanRMin = (fRmin2 - fRmin1)*0.5/fDz ; + secRMin = std::sqrt(1.0 + tanRMin*tanRMin) ; + rMinAv = (fRmin1 + fRmin2)*0.5 ; +/* + if (rMinAv > halfRadTolerance) + { + rMinOAv = rMinAv - halfRadTolerance ; + } + else + { + rMinOAv = 0.0 ; + }*/ + tanRMax = (fRmax2 - fRmax1)*0.5/fDz ; + secRMax = std::sqrt(1.0 + tanRMax*tanRMax) ; + rMaxAv = (fRmax1 + fRmax2)*0.5 ; +// rMaxOAv = rMaxAv + halfRadTolerance ; + + // Intersection with z-surfaces + + tolIDz = fDz - halfCarTolerance ; + tolODz = fDz + halfCarTolerance ; + + if (std::fabs(z) >= tolIDz) + { + if ( z*v.z() < 0 ) // at +Z going in -Z or visa versa + { + sd = (std::fabs(z) - fDz)/std::fabs(v.z()) ; // Z intersect distance + + if( sd < 0.0 ) { sd = 0.0; } // negative dist -> zero + + xi = p.x() + sd*v.x() ; // Intersection coords + yi = p.y() + sd*v.y() ; + rhoi2 = xi*xi + yi*yi ; + + // Check validity of intersection + // Calculate (outer) tolerant radi^2 at intersecion + + if (v.z() > 0) + { + tolORMin = fRmin1 - halfRadTolerance*secRMin ; + tolIRMin = fRmin1 + halfRadTolerance*secRMin ; + tolIRMax = fRmax1 - halfRadTolerance*secRMin ; + // tolORMax2 = (fRmax1 + halfRadTolerance*secRMax)* + // (fRmax1 + halfRadTolerance*secRMax) ; + } + else + { + tolORMin = fRmin2 - halfRadTolerance*secRMin ; + tolIRMin = fRmin2 + halfRadTolerance*secRMin ; + tolIRMax = fRmax2 - halfRadTolerance*secRMin ; + // tolORMax2 = (fRmax2 + halfRadTolerance*secRMax)* + // (fRmax2 + halfRadTolerance*secRMax) ; + } + if ( tolORMin > 0 ) + { + // tolORMin2 = tolORMin*tolORMin ; + tolIRMin2 = tolIRMin*tolIRMin ; + } + else + { + // tolORMin2 = 0.0 ; + tolIRMin2 = 0.0 ; + } + if ( tolIRMax > 0 ) { tolIRMax2 = tolIRMax*tolIRMax; } + else { tolIRMax2 = 0.0; } + + if ( (tolIRMin2 <= rhoi2) && (rhoi2 <= tolIRMax2) ) + { +/* if ( !fPhiFullCone && rhoi2 ) + { + // Psi = angle made with central (average) phi of shape + + cosPsi = (xi*cosCPhi + yi*sinCPhi)/std::sqrt(rhoi2) ; + + if (cosPsi >= cosHDPhiIT) { return sd; } + } + else */ + { + return sd; + } + } + } + else // On/outside extent, and heading away -> cannot intersect + { + return snxt ; + } + } + +// ----> Can not intersect z surfaces + + +// Intersection with outer cone (possible return) and +// inner cone (must also check phi) +// +// Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc. +// +// Intersects with x^2+y^2=(a*z+b)^2 +// +// where a=tanRMax or tanRMin +// b=rMaxAv or rMinAv +// +// (vx^2+vy^2-(a*vz)^2)t^2+2t(pxvx+pyvy-a*vz(a*pz+b))+px^2+py^2-(a*pz+b)^2=0 ; +// t1 t2 t3 +// +// \--------u-------/ \-----------v----------/ \---------w--------/ +// + + t1 = 1.0 - v.z()*v.z() ; + t2 = p.x()*v.x() + p.y()*v.y() ; + t3 = p.x()*p.x() + p.y()*p.y() ; + rin = tanRMin*z + rMinAv ; + rout = tanRMax*z + rMaxAv ; + + // Outer Cone Intersection + // Must be outside/on outer cone for valid intersection + + nt1 = t1 - (tanRMax*v.z())*(tanRMax*v.z()) ; + nt2 = t2 - tanRMax*v.z()*rout ; + nt3 = t3 - rout*rout ; + + if (std::fabs(nt1) > kRadTolerance) // Equation quadratic => 2 roots + { + b = nt2/nt1; + c = nt3/nt1; + d = b*b-c ; + if ( (nt3 > rout*rout*kRadTolerance*kRadTolerance*secRMax*secRMax) + || (rout < 0) ) + { + // If outside real cone (should be rho-rout>kRadTolerance*0.5 + // NOT rho^2 etc) saves a std::sqrt() at expense of accuracy + + if (d >= 0) + { + + if ((rout < 0) && (nt3 <= 0)) + { + // Inside `shadow cone' with -ve radius + // -> 2nd root could be on real cone + + if (b>0) { sd = c/(-b-std::sqrt(d)); } + else { sd = -b + std::sqrt(d); } + } + else + { + if ((b <= 0) && (c >= 0)) // both >=0, try smaller root + { + sd=c/(-b+std::sqrt(d)); + } + else + { + if ( c <= 0 ) // second >=0 + { + sd = -b + std::sqrt(d) ; + if((sd<0) & (sd>-halfRadTolerance)) sd=0; + } + else // both negative, travel away + { + return kInfinity ; + } + } + } + if ( sd >= 0 ) // If 'forwards'. Check z intersection + { + if ( sd>dRmax ) // Avoid rounding errors due to precision issues on + { // 64 bits systems. Split long distances and recompute + G4double fTerm = sd-std::fmod(sd,dRmax); + sd = fTerm + DistanceToIn(p+fTerm*v,v); + } + zi = z + sd*v.z() ; + + if (std::fabs(zi) <= tolODz) + { + // Z ok. Check phi intersection if reqd + + return sd; +/* if ( fPhiFullCone ) { return sd; } + else + { + xi = p.x() + sd*v.x() ; + yi = p.y() + sd*v.y() ; + ri = rMaxAv + zi*tanRMax ; + cosPsi = (xi*cosCPhi + yi*sinCPhi)/ri ; + + if ( cosPsi >= cosHDPhiIT ) { return sd; } + }*/ + } + } // end if (sd>0) + } + } + else + { + // Inside outer cone + // check not inside, and heading through G4ShiftedCone (-> 0 to in) + + if ( ( t3 > (rin + halfRadTolerance*secRMin)* + (rin + halfRadTolerance*secRMin) ) + && (nt2 < 0) && (d >= 0) && (std::fabs(z) <= tolIDz) ) + { + // Inside cones, delta r -ve, inside z extent + // Point is on the Surface => check Direction using Normal.dot(v) + + xi = p.x() ; + yi = p.y() ; + risec = std::sqrt(xi*xi + yi*yi)*secRMax ; + Normal = G4ThreeVector(xi/risec,yi/risec,-tanRMax/secRMax) ; +/* if ( !fPhiFullCone ) + { + cosPsi = (p.x()*cosCPhi + p.y()*sinCPhi)/std::sqrt(t3) ; + if ( cosPsi >= cosHDPhiIT ) + { + if ( Normal.dot(v) <= 0 ) { return 0.0; } + } + } + else*/ + { + if ( Normal.dot(v) <= 0 ) { return 0.0; } + } + } + } + } + else // Single root case + { + if ( std::fabs(nt2) > kRadTolerance ) + { + sd = -0.5*nt3/nt2 ; + + if ( sd < 0 ) { return kInfinity; } // travel away + else // sd >= 0, If 'forwards'. Check z intersection + { + zi = z + sd*v.z() ; + + if ((std::fabs(zi) <= tolODz) && (nt2 < 0)) + { + // Z ok. Check phi intersection if reqd + return sd; +/* if ( fPhiFullCone ) { return sd; } + else + { + xi = p.x() + sd*v.x() ; + yi = p.y() + sd*v.y() ; + ri = rMaxAv + zi*tanRMax ; + cosPsi = (xi*cosCPhi + yi*sinCPhi)/ri ; + + if (cosPsi >= cosHDPhiIT) { return sd; } + }*/ + } + } + } + else // travel || cone surface from its origin + { + sd = kInfinity ; + } + } + + // Inner Cone Intersection + // o Space is divided into 3 areas: + // 1) Radius greater than real inner cone & imaginary cone & outside + // tolerance + // 2) Radius less than inner or imaginary cone & outside tolarance + // 3) Within tolerance of real or imaginary cones + // - Extra checks needed for 3's intersections + // => lots of duplicated code + + if (rMinAv) + { + nt1 = t1 - (tanRMin*v.z())*(tanRMin*v.z()) ; + nt2 = t2 - tanRMin*v.z()*rin ; + nt3 = t3 - rin*rin ; + + if ( nt1 ) + { + if ( nt3 > rin*kRadTolerance*secRMin ) + { + // At radius greater than real & imaginary cones + // -> 2nd root, with zi check + + b = nt2/nt1 ; + c = nt3/nt1 ; + d = b*b-c ; + if (d >= 0) // > 0 + { + if(b>0){sd = c/( -b-std::sqrt(d));} + else {sd = -b + std::sqrt(d) ;} + + if ( sd >= 0 ) // > 0 + { + if ( sd>dRmax ) // Avoid rounding errors due to precision issues on + { // 64 bits systems. Split long distance and recompute + G4double fTerm = sd-std::fmod(sd,dRmax); + sd = fTerm + DistanceToIn(p+fTerm*v,v); + } + zi = z + sd*v.z() ; + + if ( std::fabs(zi) <= tolODz ) + { +/* if ( !fPhiFullCone ) + { + xi = p.x() + sd*v.x() ; + yi = p.y() + sd*v.y() ; + ri = rMinAv + zi*tanRMin ; + cosPsi = (xi*cosCPhi + yi*sinCPhi)/ri ; + + if (cosPsi >= cosHDPhiIT) + { + if ( sd > halfRadTolerance ) { snxt=sd; } + else + { + // Calculate a normal vector in order to check Direction + + risec = std::sqrt(xi*xi + yi*yi)*secRMin ; + Normal = G4ThreeVector(-xi/risec,-yi/risec,tanRMin/secRMin); + if ( Normal.dot(v) <= 0 ) { snxt = sd; } + } + } + } + else */ + { + if ( sd > halfRadTolerance ) { return sd; } + else + { + // Calculate a normal vector in order to check Direction + + xi = p.x() + sd*v.x() ; + yi = p.y() + sd*v.y() ; + risec = std::sqrt(xi*xi + yi*yi)*secRMin ; + Normal = G4ThreeVector(-xi/risec,-yi/risec,tanRMin/secRMin) ; + if ( Normal.dot(v) <= 0 ) { return sd; } + } + } + } + } + } + } + else if ( nt3 < -rin*kRadTolerance*secRMin ) + { + // Within radius of inner cone (real or imaginary) + // -> Try 2nd root, with checking intersection is with real cone + // -> If check fails, try 1st root, also checking intersection is + // on real cone + + b = nt2/nt1 ; + c = nt3/nt1 ; + d = b*b - c ; + + if ( d >= 0 ) // > 0 + { + if (b>0) { sd = c/(-b-std::sqrt(d)); } + else { sd = -b + std::sqrt(d); } + zi = z + sd*v.z() ; + ri = rMinAv + zi*tanRMin ; + + if ( ri > 0 ) + { + if ( (sd >= 0) && (std::fabs(zi) <= tolODz) ) // sd > 0 + { + if ( sd>dRmax ) // Avoid rounding errors due to precision issues + { // seen on 64 bits systems. Split and recompute + G4double fTerm = sd-std::fmod(sd,dRmax); + sd = fTerm + DistanceToIn(p+fTerm*v,v); + } +/* if ( !fPhiFullCone ) + { + xi = p.x() + sd*v.x() ; + yi = p.y() + sd*v.y() ; + cosPsi = (xi*cosCPhi + yi*sinCPhi)/ri ; + + if (cosPsi >= cosHDPhiOT) + { + if ( sd > halfRadTolerance ) { snxt=sd; } + else + { + // Calculate a normal vector in order to check Direction + + risec = std::sqrt(xi*xi + yi*yi)*secRMin ; + Normal = G4ThreeVector(-xi/risec,-yi/risec,tanRMin/secRMin); + if ( Normal.dot(v) <= 0 ) { snxt = sd; } + } + } + } + else */ + { + if( sd > halfRadTolerance ) { return sd; } + else + { + // Calculate a normal vector in order to check Direction + + xi = p.x() + sd*v.x() ; + yi = p.y() + sd*v.y() ; + risec = std::sqrt(xi*xi + yi*yi)*secRMin ; + Normal = G4ThreeVector(-xi/risec,-yi/risec,tanRMin/secRMin) ; + if ( Normal.dot(v) <= 0 ) { return sd; } + } + } + } + } + else + { + if (b>0) { sd = -b - std::sqrt(d); } + else { sd = c/(-b+std::sqrt(d)); } + zi = z + sd*v.z() ; + ri = rMinAv + zi*tanRMin ; + + if ( (sd >= 0) && (ri > 0) && (std::fabs(zi) <= tolODz) ) // sd>0 + { + if ( sd>dRmax ) // Avoid rounding errors due to precision issues + { // seen on 64 bits systems. Split and recompute + G4double fTerm = sd-std::fmod(sd,dRmax); + sd = fTerm + DistanceToIn(p+fTerm*v,v); + } +/* if ( !fPhiFullCone ) + { + xi = p.x() + sd*v.x() ; + yi = p.y() + sd*v.y() ; + cosPsi = (xi*cosCPhi + yi*sinCPhi)/ri ; + + if (cosPsi >= cosHDPhiIT) + { + if ( sd > halfRadTolerance ) { snxt=sd; } + else + { + // Calculate a normal vector in order to check Direction + + risec = std::sqrt(xi*xi + yi*yi)*secRMin ; + Normal = G4ThreeVector(-xi/risec,-yi/risec,tanRMin/secRMin); + if ( Normal.dot(v) <= 0 ) { snxt = sd; } + } + } + } + else */ + { + if ( sd > halfRadTolerance ) { return sd; } + else + { + // Calculate a normal vector in order to check Direction + + xi = p.x() + sd*v.x() ; + yi = p.y() + sd*v.y() ; + risec = std::sqrt(xi*xi + yi*yi)*secRMin ; + Normal = G4ThreeVector(-xi/risec,-yi/risec,tanRMin/secRMin) ; + if ( Normal.dot(v) <= 0 ) { return sd; } + } + } + } + } + } + } + else + { + // Within kRadTol*0.5 of inner cone (real OR imaginary) + // ----> Check not travelling through (=>0 to in) + // ----> if not: + // -2nd root with validity check + + if ( std::fabs(z) <= tolODz ) + { + if ( nt2 > 0 ) + { + // Inside inner real cone, heading outwards, inside z range + +/* if ( !fPhiFullCone ) + { + cosPsi = (p.x()*cosCPhi + p.y()*sinCPhi)/std::sqrt(t3) ; + + if (cosPsi >= cosHDPhiIT) { return 0.0; } + } + else */ { return 0.0; } + } + else + { + // Within z extent, but not travelling through + // -> 2nd root or kInfinity if 1st root on imaginary cone + + b = nt2/nt1 ; + c = nt3/nt1 ; + d = b*b - c ; + + if ( d >= 0 ) // > 0 + { + if (b>0) { sd = -b - std::sqrt(d); } + else { sd = c/(-b+std::sqrt(d)); } + zi = z + sd*v.z() ; + ri = rMinAv + zi*tanRMin ; + + if ( ri > 0 ) // 2nd root + { + if (b>0) { sd = c/(-b-std::sqrt(d)); } + else { sd = -b + std::sqrt(d); } + + zi = z + sd*v.z() ; + + if ( (sd >= 0) && (std::fabs(zi) <= tolODz) ) // sd>0 + { + if ( sd>dRmax ) // Avoid rounding errors due to precision issue + { // seen on 64 bits systems. Split and recompute + G4double fTerm = sd-std::fmod(sd,dRmax); + sd = fTerm + DistanceToIn(p+fTerm*v,v); + } +/* if ( !fPhiFullCone ) + { + xi = p.x() + sd*v.x() ; + yi = p.y() + sd*v.y() ; + ri = rMinAv + zi*tanRMin ; + cosPsi = (xi*cosCPhi + yi*sinCPhi)/ri ; + + if ( cosPsi >= cosHDPhiIT ) { snxt = sd; } + } + else */ { return sd; } + } + } + else { return kInfinity; } + } + } + } + else // 2nd root + { + b = nt2/nt1 ; + c = nt3/nt1 ; + d = b*b - c ; + + if ( d > 0 ) + { + if (b>0) { sd = c/(-b-std::sqrt(d)); } + else { sd = -b + std::sqrt(d) ; } + zi = z + sd*v.z() ; + + if ( (sd >= 0) && (std::fabs(zi) <= tolODz) ) // sd>0 + { + if ( sd>dRmax ) // Avoid rounding errors due to precision issues + { // seen on 64 bits systems. Split and recompute + G4double fTerm = sd-std::fmod(sd,dRmax); + sd = fTerm + DistanceToIn(p+fTerm*v,v); + } +/* if ( !fPhiFullCone ) + { + xi = p.x() + sd*v.x(); + yi = p.y() + sd*v.y(); + ri = rMinAv + zi*tanRMin ; + cosPsi = (xi*cosCPhi + yi*sinCPhi)/ri; + + if (cosPsi >= cosHDPhiIT) { snxt = sd; } + } + else */ { return sd; } + } + } + } + } + } + } + + // Phi segment intersection + // + // o Tolerant of points inside phi planes by up to kCarTolerance*0.5 + // + // o NOTE: Large duplication of code between sphi & ephi checks + // -> only diffs: sphi -> ephi, Comp -> -Comp and half-plane + // intersection check <=0 -> >=0 + // -> Should use some form of loop Construct +/* + if ( !fPhiFullCone ) + { + // First phi surface (starting phi) + + Comp = v.x()*sinSPhi - v.y()*cosSPhi ; + + if ( Comp < 0 ) // Component in outwards normal dirn + { + Dist = (p.y()*cosSPhi - p.x()*sinSPhi) ; + + if (Dist < halfCarTolerance) + { + sd = Dist/Comp ; + + if ( sd < snxt ) + { + if ( sd < 0 ) { sd = 0.0; } + + zi = z + sd*v.z() ; + + if ( std::fabs(zi) <= tolODz ) + { + xi = p.x() + sd*v.x() ; + yi = p.y() + sd*v.y() ; + rhoi2 = xi*xi + yi*yi ; + tolORMin2 = (rMinOAv + zi*tanRMin)*(rMinOAv + zi*tanRMin) ; + tolORMax2 = (rMaxOAv + zi*tanRMax)*(rMaxOAv + zi*tanRMax) ; + + if ( (rhoi2 >= tolORMin2) && (rhoi2 <= tolORMax2) ) + { + // z and r intersections good - check intersecting with + // correct half-plane + + if ((yi*cosCPhi - xi*sinCPhi) <= 0 ) { snxt = sd; } + } + } + } + } + } + + // Second phi surface (Ending phi) + + Comp = -(v.x()*sinEPhi - v.y()*cosEPhi) ; + + if ( Comp < 0 ) // Component in outwards normal dirn + { + Dist = -(p.y()*cosEPhi - p.x()*sinEPhi) ; + if (Dist < halfCarTolerance) + { + sd = Dist/Comp ; + + if ( sd < snxt ) + { + if ( sd < 0 ) { sd = 0.0; } + + zi = z + sd*v.z() ; + + if (std::fabs(zi) <= tolODz) + { + xi = p.x() + sd*v.x() ; + yi = p.y() + sd*v.y() ; + rhoi2 = xi*xi + yi*yi ; + tolORMin2 = (rMinOAv + zi*tanRMin)*(rMinOAv + zi*tanRMin) ; + tolORMax2 = (rMaxOAv + zi*tanRMax)*(rMaxOAv + zi*tanRMax) ; + + if ( (rhoi2 >= tolORMin2) && (rhoi2 <= tolORMax2) ) + { + // z and r intersections good - check intersecting with + // correct half-plane + + if ( (yi*cosCPhi - xi*sinCPhi) >= 0.0 ) { snxt = sd; } + } + } + } + } + } + }*/ + if (snxt < halfCarTolerance) { snxt = 0.; } + + return snxt ; +} + +////////////////////////////////////////////////////////////////////////////// +// +// Calculate distance (<= actual) to closest surface of shape from outside +// - Calculate distance to z, radial planes +// - Only to phi planes if outside phi extent +// - Return 0 if point inside + +G4double G4ShiftedCone::DistanceToIn(const G4ThreeVector& p) const +{ + G4double safe=0.0, rho, safeR1, safeR2, safeZ;//, safePhi, cosPsi ; + G4double tanRMin, secRMin, pRMin ; + G4double tanRMax, secRMax, pRMax ; + + G4double z = p.z() - fZshift; + + rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ; + safeZ = std::fabs(z) - fDz ; + + if ( fRmin1 || fRmin2 ) + { + tanRMin = (fRmin2 - fRmin1)*0.5/fDz ; + secRMin = std::sqrt(1.0 + tanRMin*tanRMin) ; + pRMin = tanRMin*z + (fRmin1 + fRmin2)*0.5 ; + safeR1 = (pRMin - rho)/secRMin ; + + tanRMax = (fRmax2 - fRmax1)*0.5/fDz ; + secRMax = std::sqrt(1.0 + tanRMax*tanRMax) ; + pRMax = tanRMax*z + (fRmax1 + fRmax2)*0.5 ; + safeR2 = (rho - pRMax)/secRMax ; + + if ( safeR1 > safeR2) { safe = safeR1; } + else { safe = safeR2; } + } + else + { + tanRMax = (fRmax2 - fRmax1)*0.5/fDz ; + secRMax = std::sqrt(1.0 + tanRMax*tanRMax) ; + pRMax = tanRMax*z + (fRmax1 + fRmax2)*0.5 ; + safe = (rho - pRMax)/secRMax ; + } + if ( safeZ > safe ) { safe = safeZ; } + +/* if ( !fPhiFullCone && rho ) + { + // Psi=angle from central phi to point + + cosPsi = (p.x()*cosCPhi + p.y()*sinCPhi)/rho ; + + if ( cosPsi < std::cos(fDPhi*0.5) ) // Point lies outside phi range + { + if ( (p.y()*cosCPhi - p.x()*sinCPhi) <= 0.0 ) + { + safePhi = std::fabs(p.x()*std::sin(fSPhi)-p.y()*std::cos(fSPhi)); + } + else + { + safePhi = std::fabs(p.x()*sinEPhi-p.y()*cosEPhi); + } + if ( safePhi > safe ) { safe = safePhi; } + } + }*/ + if ( safe < 0.0 ) { safe = 0.0; } + + return safe ; +} + +/////////////////////////////////////////////////////////////// +// +// Calculate distance to surface of shape from 'inside', allowing for tolerance +// - Only Calc rmax intersection if no valid rmin intersection + +G4double G4ShiftedCone::DistanceToOut( const G4ThreeVector& p, + const G4ThreeVector& v, + const G4bool calcNorm, + G4bool *validNorm, + G4ThreeVector *n) const +{ + ESide side = kNull, sider = kNull;//, sidephi = kNull; + + G4double snxt,srd,/*sphi,*/pdist ; + + G4double tanRMax, secRMax, rMaxAv ; // Data for outer cone + G4double tanRMin, secRMin, rMinAv ; // Data for inner cone + + G4double t1, t2, t3, rout, rin, nt1, nt2, nt3 ; + G4double b, c, d, sr2, sr3 ; + + // Vars for intersection within tolerance + + ESide sidetol = kNull ; + G4double slentol = kInfinity ; + + // Vars for phi intersection: + +// G4double pDistS, compS, pDistE, compE, sphi2, vphi ; + G4double zi, ri, deltaRoi2, xi, yi, risec ; + + // Z plane intersection + + G4double z = p.z() - fZshift; + + if ( v.z() > 0.0 ) + { + pdist = fDz - z ; + + if (pdist > halfCarTolerance) + { + snxt = pdist/v.z() ; + side = kPZ ; + } + else + { + if (calcNorm) + { + *n = G4ThreeVector(0,0,1) ; + *validNorm = true ; + } + return snxt = 0.0; + } + } + else if ( v.z() < 0.0 ) + { + pdist = fDz + z ; + + if ( pdist > halfCarTolerance) + { + snxt = -pdist/v.z() ; + side = kMZ ; + } + else + { + if ( calcNorm ) + { + *n = G4ThreeVector(0,0,-1) ; + *validNorm = true ; + } + return snxt = 0.0 ; + } + } + else // Travel perpendicular to z axis + { + snxt = kInfinity ; + side = kNull ; + } + + // Radial Intersections + // + // Intersection with outer cone (possible return) and + // inner cone (must also check phi) + // + // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc. + // + // Intersects with x^2+y^2=(a*z+b)^2 + // + // where a=tanRMax or tanRMin + // b=rMaxAv or rMinAv + // + // (vx^2+vy^2-(a*vz)^2)t^2+2t(pxvx+pyvy-a*vz(a*pz+b))+px^2+py^2-(a*pz+b)^2=0 ; + // t1 t2 t3 + // + // \--------u-------/ \-----------v----------/ \---------w--------/ + + tanRMax = (fRmax2 - fRmax1)*0.5/fDz ; + secRMax = std::sqrt(1.0 + tanRMax*tanRMax) ; + rMaxAv = (fRmax1 + fRmax2)*0.5 ; + + + t1 = 1.0 - v.z()*v.z() ; // since v normalised + t2 = p.x()*v.x() + p.y()*v.y() ; + t3 = p.x()*p.x() + p.y()*p.y() ; + rout = tanRMax*z + rMaxAv ; + + nt1 = t1 - (tanRMax*v.z())*(tanRMax*v.z()) ; + nt2 = t2 - tanRMax*v.z()*rout ; + nt3 = t3 - rout*rout ; + + if (v.z() > 0.0) + { + deltaRoi2 = snxt*snxt*t1 + 2*snxt*t2 + t3 + - fRmax2*(fRmax2 + kRadTolerance*secRMax); + } + else if ( v.z() < 0.0 ) + { + deltaRoi2 = snxt*snxt*t1 + 2*snxt*t2 + t3 + - fRmax1*(fRmax1 + kRadTolerance*secRMax); + } + else + { + deltaRoi2 = 1.0; + } + + if ( nt1 && (deltaRoi2 > 0.0) ) + { + // Equation quadratic => 2 roots : second root must be leaving + + b = nt2/nt1 ; + c = nt3/nt1 ; + d = b*b - c ; + + if ( d >= 0 ) + { + // Check if on outer cone & heading outwards + // NOTE: Should use rho-rout>-kRadTolerance*0.5 + + if (nt3 > -halfRadTolerance && nt2 >= 0 ) + { + if (calcNorm) + { + risec = std::sqrt(t3)*secRMax ; + *validNorm = true ; + *n = G4ThreeVector(p.x()/risec,p.y()/risec,-tanRMax/secRMax); + } + return snxt=0 ; + } + else + { + sider = kRMax ; + if (b>0) { srd = -b - std::sqrt(d); } + else { srd = c/(-b+std::sqrt(d)) ; } + + zi = z + srd*v.z() ; + ri = tanRMax*zi + rMaxAv ; + + if ((ri >= 0) && (-halfRadTolerance <= srd) && (srd <= halfRadTolerance)) + { + // An intersection within the tolerance + // we will Store it in case it is good - + // + slentol = srd ; + sidetol = kRMax ; + } + if ( (ri < 0) || (srd < halfRadTolerance) ) + { + // Safety: if both roots -ve ensure that srd cannot `win' + // distance to out + + if (b>0) { sr2 = c/(-b-std::sqrt(d)); } + else { sr2 = -b + std::sqrt(d); } + zi = z + sr2*v.z() ; + ri = tanRMax*zi + rMaxAv ; + + if ((ri >= 0) && (sr2 > halfRadTolerance)) + { + srd = sr2; + } + else + { + srd = kInfinity ; + + if( (-halfRadTolerance <= sr2) && ( sr2 <= halfRadTolerance) ) + { + // An intersection within the tolerance. + // Storing it in case it is good. + + slentol = sr2 ; + sidetol = kRMax ; + } + } + } + } + } + else + { + // No intersection with outer cone & not parallel + // -> already outside, no intersection + + if ( calcNorm ) + { + risec = std::sqrt(t3)*secRMax; + *validNorm = true; + *n = G4ThreeVector(p.x()/risec,p.y()/risec,-tanRMax/secRMax); + } + return snxt = 0.0 ; + } + } + else if ( nt2 && (deltaRoi2 > 0.0) ) + { + // Linear case (only one intersection) => point outside outer cone + + if ( calcNorm ) + { + risec = std::sqrt(t3)*secRMax; + *validNorm = true; + *n = G4ThreeVector(p.x()/risec,p.y()/risec,-tanRMax/secRMax); + } + return snxt = 0.0 ; + } + else + { + // No intersection -> parallel to outer cone + // => Z or inner cone intersection + + srd = kInfinity ; + } + + // Check possible intersection within tolerance + + if ( slentol <= halfCarTolerance ) + { + // An intersection within the tolerance was found. + // We must accept it only if the momentum points outwards. + // + // G4ThreeVector ptTol ; // The point of the intersection + // ptTol= p + slentol*v ; + // ri=tanRMax*zi+rMaxAv ; + // + // Calculate a normal vector, as below + + xi = p.x() + slentol*v.x(); + yi = p.y() + slentol*v.y(); + risec = std::sqrt(xi*xi + yi*yi)*secRMax; + G4ThreeVector Normal = G4ThreeVector(xi/risec,yi/risec,-tanRMax/secRMax); + + if ( Normal.dot(v) > 0 ) // We will leave the Cone immediatelly + { + if ( calcNorm ) + { + *n = Normal.unit() ; + *validNorm = true ; + } + return snxt = 0.0 ; + } + else // On the surface, but not heading out so we ignore this intersection + { // (as it is within tolerance). + slentol = kInfinity ; + } + } + + // Inner Cone intersection + + if ( fRmin1 || fRmin2 ) + { + tanRMin = (fRmin2 - fRmin1)*0.5/fDz ; + nt1 = t1 - (tanRMin*v.z())*(tanRMin*v.z()) ; + + if ( nt1 ) + { + secRMin = std::sqrt(1.0 + tanRMin*tanRMin) ; + rMinAv = (fRmin1 + fRmin2)*0.5 ; + rin = tanRMin*z + rMinAv ; + nt2 = t2 - tanRMin*v.z()*rin ; + nt3 = t3 - rin*rin ; + + // Equation quadratic => 2 roots : first root must be leaving + + b = nt2/nt1 ; + c = nt3/nt1 ; + d = b*b - c ; + + if ( d >= 0.0 ) + { + // NOTE: should be rho-rin<kRadTolerance*0.5, + // but using squared versions for efficiency + + if (nt3 < kRadTolerance*(rin + kRadTolerance*0.25)) + { + if ( nt2 < 0.0 ) + { + if (calcNorm) { *validNorm = false; } + return snxt = 0.0; + } + } + else + { + if (b>0) { sr2 = -b - std::sqrt(d); } + else { sr2 = c/(-b+std::sqrt(d)); } + zi = z + sr2*v.z() ; + ri = tanRMin*zi + rMinAv ; + + if( (ri>=0.0)&&(-halfRadTolerance<=sr2)&&(sr2<=halfRadTolerance) ) + { + // An intersection within the tolerance + // storing it in case it is good. + + slentol = sr2 ; + sidetol = kRMax ; + } + if( (ri<0) || (sr2 < halfRadTolerance) ) + { + if (b>0) { sr3 = c/(-b-std::sqrt(d)); } + else { sr3 = -b + std::sqrt(d) ; } + + // Safety: if both roots -ve ensure that srd cannot `win' + // distancetoout + + if ( sr3 > halfRadTolerance ) + { + if( sr3 < srd ) + { + zi = z + sr3*v.z() ; + ri = tanRMin*zi + rMinAv ; + + if ( ri >= 0.0 ) + { + srd=sr3 ; + sider=kRMin ; + } + } + } + else if ( sr3 > -halfRadTolerance ) + { + // Intersection in tolerance. Store to check if it's good + + slentol = sr3 ; + sidetol = kRMin ; + } + } + else if ( (sr2 < srd) && (sr2 > halfCarTolerance) ) + { + srd = sr2 ; + sider = kRMin ; + } + else if (sr2 > -halfCarTolerance) + { + // Intersection in tolerance. Store to check if it's good + + slentol = sr2 ; + sidetol = kRMin ; + } + if( slentol <= halfCarTolerance ) + { + // An intersection within the tolerance was found. + // We must accept it only if the momentum points outwards. + + G4ThreeVector Normal ; + + // Calculate a normal vector, as below + + xi = p.x() + slentol*v.x() ; + yi = p.y() + slentol*v.y() ; + if( sidetol==kRMax ) + { + risec = std::sqrt(xi*xi + yi*yi)*secRMax ; + Normal = G4ThreeVector(xi/risec,yi/risec,-tanRMax/secRMax) ; + } + else + { + risec = std::sqrt(xi*xi + yi*yi)*secRMin ; + Normal = G4ThreeVector(-xi/risec,-yi/risec,tanRMin/secRMin) ; + } + if( Normal.dot(v) > 0 ) + { + // We will leave the cone immediately + + if( calcNorm ) + { + *n = Normal.unit() ; + *validNorm = true ; + } + return snxt = 0.0 ; + } + else + { + // On the surface, but not heading out so we ignore this + // intersection (as it is within tolerance). + + slentol = kInfinity ; + } + } + } + } + } + } + + // Linear case => point outside inner cone ---> outer cone intersect + // + // Phi Intersection +/* + if ( !fPhiFullCone ) + { + // add angle calculation with correction + // of the difference in domain of atan2 and Sphi + + vphi = std::atan2(v.y(),v.x()) ; + + if ( vphi < fSPhi - halfAngTolerance ) { vphi += twopi; } + else if ( vphi > fSPhi + fDPhi + halfAngTolerance ) { vphi -= twopi; } + + if ( p.x() || p.y() ) // Check if on z axis (rho not needed later) + { + // pDist -ve when inside + + pDistS = p.x()*sinSPhi - p.y()*cosSPhi ; + pDistE = -p.x()*sinEPhi + p.y()*cosEPhi ; + + // Comp -ve when in direction of outwards normal + + compS = -sinSPhi*v.x() + cosSPhi*v.y() ; + compE = sinEPhi*v.x() - cosEPhi*v.y() ; + + sidephi = kNull ; + + if( ( (fDPhi <= pi) && ( (pDistS <= halfCarTolerance) + && (pDistE <= halfCarTolerance) ) ) + || ( (fDPhi > pi) && !((pDistS > halfCarTolerance) + && (pDistE > halfCarTolerance) ) ) ) + { + // Inside both phi *full* planes + if ( compS < 0 ) + { + sphi = pDistS/compS ; + if (sphi >= -halfCarTolerance) + { + xi = p.x() + sphi*v.x() ; + yi = p.y() + sphi*v.y() ; + + // Check intersecting with correct half-plane + // (if not -> no intersect) + // + if ( (std::fabs(xi)<=kCarTolerance) + && (std::fabs(yi)<=kCarTolerance) ) + { + sidephi= kSPhi; + if ( ( fSPhi-halfAngTolerance <= vphi ) + && ( fSPhi+fDPhi+halfAngTolerance >=vphi ) ) + { + sphi = kInfinity; + } + } + else + if ( (yi*cosCPhi-xi*sinCPhi)>=0 ) + { + sphi = kInfinity ; + } + else + { + sidephi = kSPhi ; + if ( pDistS > -halfCarTolerance ) + { + sphi = 0.0 ; // Leave by sphi immediately + } + } + } + else + { + sphi = kInfinity ; + } + } + else + { + sphi = kInfinity ; + } + + if ( compE < 0 ) + { + sphi2 = pDistE/compE ; + + // Only check further if < starting phi intersection + // + if ( (sphi2 > -halfCarTolerance) && (sphi2 < sphi) ) + { + xi = p.x() + sphi2*v.x() ; + yi = p.y() + sphi2*v.y() ; + + // Check intersecting with correct half-plane + + if ( (std::fabs(xi)<=kCarTolerance) + && (std::fabs(yi)<=kCarTolerance) ) + { + // Leaving via ending phi + + if(!( (fSPhi-halfAngTolerance <= vphi) + && (fSPhi+fDPhi+halfAngTolerance >= vphi) ) ) + { + sidephi = kEPhi ; + if ( pDistE <= -halfCarTolerance ) { sphi = sphi2; } + else { sphi = 0.0; } + } + } + else // Check intersecting with correct half-plane + if ( yi*cosCPhi-xi*sinCPhi >= 0 ) + { + // Leaving via ending phi + + sidephi = kEPhi ; + if ( pDistE <= -halfCarTolerance ) { sphi = sphi2; } + else { sphi = 0.0; } + } + } + } + } + else + { + sphi = kInfinity ; + } + } + else + { + // On z axis + travel not || to z axis -> if phi of vector direction + // within phi of shape, Step limited by rmax, else Step =0 + + if ( (fSPhi-halfAngTolerance <= vphi) + && (vphi <= fSPhi+fDPhi+halfAngTolerance) ) + { + sphi = kInfinity ; + } + else + { + sidephi = kSPhi ; // arbitrary + sphi = 0.0 ; + } + } + if ( sphi < snxt ) // Order intersecttions + { + snxt=sphi ; + side=sidephi ; + } + } +*/ + if ( srd < snxt ) // Order intersections + { + snxt = srd ; + side = sider ; + } + if (calcNorm) + { + switch(side) + { // Note: returned vector not normalised + case kRMax: // (divide by frmax for unit vector) + xi = p.x() + snxt*v.x() ; + yi = p.y() + snxt*v.y() ; + risec = std::sqrt(xi*xi + yi*yi)*secRMax ; + *n = G4ThreeVector(xi/risec,yi/risec,-tanRMax/secRMax) ; + *validNorm = true ; + break ; + case kRMin: + *validNorm = false ; // Rmin is inconvex + break ; +/* case kSPhi: + if ( fDPhi <= pi ) + { + *n = G4ThreeVector(sinSPhi, -cosSPhi, 0); + *validNorm = true ; + } + else + { + *validNorm = false ; + } + break ; + case kEPhi: + if ( fDPhi <= pi ) + { + *n = G4ThreeVector(-sinEPhi, cosEPhi, 0); + *validNorm = true ; + } + else + { + *validNorm = false ; + } + break ;*/ + case kPZ: + *n = G4ThreeVector(0,0,1) ; + *validNorm = true ; + break ; + case kMZ: + *n = G4ThreeVector(0,0,-1) ; + *validNorm = true ; + break ; + default: + G4cout << G4endl ; + DumpInfo(); + std::ostringstream message; + G4int oldprc = message.precision(16) ; + message << "Undefined side for valid surface normal to solid." + << G4endl + << "Position:" << G4endl << G4endl + << "p.x() = " << p.x()/mm << " mm" << G4endl + << "p.y() = " << p.y()/mm << " mm" << G4endl + << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl + << "pho at z = " << std::sqrt( p.x()*p.x()+p.y()*p.y() )/mm + << " mm" << G4endl << G4endl ; + if( p.x() != 0. || p.y() != 0.) + { + message << "point phi = " << std::atan2(p.y(),p.x())/degree + << " degree" << G4endl << G4endl ; + } + message << "Direction:" << G4endl << G4endl + << "v.x() = " << v.x() << G4endl + << "v.y() = " << v.y() << G4endl + << "v.z() = " << v.z() << G4endl<< G4endl + << "Proposed distance :" << G4endl<< G4endl + << "snxt = " << snxt/mm << " mm" << G4endl ; + message.precision(oldprc) ; + G4Exception("G4ShiftedCone::DistanceToOut(p,v,..)","GeomSolids1002", + JustWarning, message) ; + break ; + } + } + if (snxt < halfCarTolerance) { snxt = 0.; } + + return snxt ; +} + +////////////////////////////////////////////////////////////////// +// +// Calculate distance (<=actual) to closest surface of shape from inside + +G4double G4ShiftedCone::DistanceToOut(const G4ThreeVector& p) const +{ + G4double safe=0.0, rho, safeR1, safeR2, safeZ;//, safePhi; + G4double tanRMin, secRMin, pRMin; + G4double tanRMax, secRMax, pRMax; + +#ifdef G4CSGDEBUG + if( Inside(p) == kOutside ) + { + G4int oldprc=G4cout.precision(16) ; + G4cout << G4endl ; + DumpInfo(); + G4cout << "Position:" << G4endl << G4endl ; + G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ; + G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ; + G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ; + G4cout << "pho at z = " << std::sqrt( p.x()*p.x()+p.y()*p.y() )/mm + << " mm" << G4endl << G4endl ; + if( (p.x() != 0.) || (p.x() != 0.) ) + { + G4cout << "point phi = " << std::atan2(p.y(),p.x())/degree + << " degree" << G4endl << G4endl ; + } + G4cout.precision(oldprc) ; + G4Exception("G4ShiftedCone::DistanceToOut(p)", "GeomSolids1002", + JustWarning, "Point p is outside !?" ); + } +#endif + + G4double z = p.z() - fZshift; + + rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ; + safeZ = fDz - std::fabs(z) ; + + if (fRmin1 || fRmin2) + { + tanRMin = (fRmin2 - fRmin1)*0.5/fDz ; + secRMin = std::sqrt(1.0 + tanRMin*tanRMin) ; + pRMin = tanRMin*z + (fRmin1 + fRmin2)*0.5 ; + safeR1 = (rho - pRMin)/secRMin ; + } + else + { + safeR1 = kInfinity ; + } + + tanRMax = (fRmax2 - fRmax1)*0.5/fDz ; + secRMax = std::sqrt(1.0 + tanRMax*tanRMax) ; + pRMax = tanRMax*z + (fRmax1+fRmax2)*0.5 ; + safeR2 = (pRMax - rho)/secRMax ; + + if (safeR1 < safeR2) { safe = safeR1; } + else { safe = safeR2; } + if (safeZ < safe) { safe = safeZ ; } + + // Check if phi divided, Calc distances closest phi plane +/* + if (!fPhiFullCone) + { + // Above/below central phi of G4ShiftedCone? + + if ( (p.y()*cosCPhi - p.x()*sinCPhi) <= 0 ) + { + safePhi = -(p.x()*sinSPhi - p.y()*cosSPhi) ; + } + else + { + safePhi = (p.x()*sinEPhi - p.y()*cosEPhi) ; + } + if (safePhi < safe) { safe = safePhi; } + }*/ + if ( safe < 0 ) { safe = 0; } + + return safe ; +} + +////////////////////////////////////////////////////////////////////////// +// +// GetEntityType + +G4GeometryType G4ShiftedCone::GetEntityType() const +{ + return G4String("G4ShiftedCone"); +} + +////////////////////////////////////////////////////////////////////////// +// +// Make a clone of the object +// +G4VSolid* G4ShiftedCone::Clone() const +{ + return new G4ShiftedCone(*this); +} + +////////////////////////////////////////////////////////////////////////// +// +// Stream object contents to an output stream + +std::ostream& G4ShiftedCone::StreamInfo(std::ostream& os) const +{ + G4int oldprc = os.precision(16); + os << "-----------------------------------------------------------\n" + << " *** Dump for solid - " << GetName() << " ***\n" + << " ===================================================\n" + << " Solid type: G4ShiftedCone\n" + << " Parameters: \n" + << " inside -fDz radius: " << fRmin1/mm << " mm \n" + << " outside -fDz radius: " << fRmax1/mm << " mm \n" + << " inside +fDz radius: " << fRmin2/mm << " mm \n" + << " outside +fDz radius: " << fRmax2/mm << " mm \n" + << " Z1 : " << GetZ1()/mm << " mm \n" + << " Z2 : " << GetZ2()/mm << " mm \n" +// << " starting angle of segment: " << fSPhi/degree << " degrees \n" +// << " delta angle of segment : " << fDPhi/degree << " degrees \n" + << "-----------------------------------------------------------\n"; + os.precision(oldprc); + + return os; +} + + + +///////////////////////////////////////////////////////////////////////// +// +// GetPointOnSurface + +G4ThreeVector G4ShiftedCone::GetPointOnSurface() const +{ + // declare working variables + // + G4double rone = (fRmax1-fRmax2)/(2.*fDz); + G4double rtwo = (fRmin1-fRmin2)/(2.*fDz); + G4double qone = (fRmax1 == fRmax2) ? 0. : fDz*(fRmax1+fRmax2)/(fRmax1-fRmax2); + G4double qtwo = (fRmin1 == fRmin2) ? 0. : fDz*(fRmin1+fRmin2)/(fRmin1-fRmin2); + + G4double slin = std::hypot(fRmin1-fRmin2, 2.*fDz); + G4double slout = std::hypot(fRmax1-fRmax2, 2.*fDz); + G4double Aone = 0.5*GetDeltaPhiAngle()*(fRmax2 + fRmax1)*slout; // outer surface + G4double Atwo = 0.5*GetDeltaPhiAngle()*(fRmin2 + fRmin1)*slin; // inner surface + G4double Athree = 0.5*GetDeltaPhiAngle()*(fRmax1*fRmax1-fRmin1*fRmin1); // base at -Dz + G4double Afour = 0.5*GetDeltaPhiAngle()*(fRmax2*fRmax2-fRmin2*fRmin2); // base at +Dz + G4double Afive = fDz*(fRmax1-fRmin1+fRmax2-fRmin2); // phi section + + G4double phi = G4RandFlat::shoot(GetStartPhiAngle(),GetStartPhiAngle() + GetDeltaPhiAngle()); + G4double cosu = std::cos(phi); + G4double sinu = std::sin(phi); + G4double rRand1 = GetRadiusInRing(fRmin1, fRmax1); + G4double rRand2 = GetRadiusInRing(fRmin2, fRmax2); + + G4bool fPhiFullCone = true; + if ( (GetStartPhiAngle() == 0.) && fPhiFullCone ) { Afive = 0.; } + G4double chose = G4RandFlat::shoot(0.,Aone+Atwo+Athree+Afour+2.*Afive); + + if( (chose >= 0.) && (chose < Aone) ) // outer surface + { + if(fRmax1 != fRmax2) + { + G4double zRand = G4RandFlat::shoot(-1.*fDz,fDz); + return G4ThreeVector (rone*cosu*(qone-zRand), + rone*sinu*(qone-zRand), zRand + fZshift); + } + else + { + return G4ThreeVector(fRmax1*cosu, fRmax2*sinu, + G4RandFlat::shoot(-1.*fDz,fDz) + fZshift); + } + } + else if( (chose >= Aone) && (chose < Aone + Atwo) ) // inner surface + { + if(fRmin1 != fRmin2) + { + G4double zRand = G4RandFlat::shoot(-1.*fDz,fDz); + return G4ThreeVector (rtwo*cosu*(qtwo-zRand), + rtwo*sinu*(qtwo-zRand), zRand + fZshift); + } + else + { + return G4ThreeVector(fRmin1*cosu, fRmin2*sinu, + G4RandFlat::shoot(-1.*fDz,fDz) + fZshift); + } + } + else if( (chose >= Aone + Atwo) && (chose < Aone + Atwo + Athree) ) // base at -Dz + { + return G4ThreeVector (rRand1*cosu, rRand1*sinu, -1*fDz + fZshift); + } + else if( (chose >= Aone + Atwo + Athree) + && (chose < Aone + Atwo + Athree + Afour) ) // base at +Dz + { + return G4ThreeVector (rRand2*cosu,rRand2*sinu,fDz + fZshift); + } + else if( (chose >= Aone + Atwo + Athree + Afour) // SPhi section + && (chose < Aone + Atwo + Athree + Afour + Afive) ) + { + G4double zRand = G4RandFlat::shoot(-1.*fDz,fDz); + rRand1 = G4RandFlat::shoot(fRmin2-((zRand-fDz)/(2.*fDz))*(fRmin1-fRmin2), + fRmax2-((zRand-fDz)/(2.*fDz))*(fRmax1-fRmax2)); + return G4ThreeVector (rRand1*GetCosStartPhi(), + rRand1*GetSinStartPhi(), zRand + fZshift); + } + else // SPhi+DPhi section + { + G4double zRand = G4RandFlat::shoot(-1.*fDz,fDz); + rRand1 = G4RandFlat::shoot(fRmin2-((zRand-fDz)/(2.*fDz))*(fRmin1-fRmin2), + fRmax2-((zRand-fDz)/(2.*fDz))*(fRmax1-fRmax2)); + return G4ThreeVector (rRand1*GetCosEndPhi(), + rRand1*GetSinEndPhi(), zRand + fZshift); + } +} + +////////////////////////////////////////////////////////////////////////// +// +// Methods for visualisation + +void G4ShiftedCone::DescribeYourselfTo (G4VGraphicsScene& scene) const +{ + scene.AddSolid (*this); +} + +G4Polyhedron* G4ShiftedCone::CreatePolyhedron () const +{ + G4double rmin[2] = { GetRmin1(), GetRmin2() }; + G4double rmax[2] = { GetRmax1(), GetRmax2() }; + G4double z[2] = { GetZ1(), GetZ2() }; + return new G4PolyhedronPcon( + GetStartPhiAngle(), GetDeltaPhiAngle(), 2, z, rmin, rmax + ); +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/G4ShiftedCone.h b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/G4ShiftedCone.h new file mode 100644 index 0000000000000000000000000000000000000000..8107ba9347bd639ba9e2cab64da46cffb9cca0b1 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/G4ShiftedCone.h @@ -0,0 +1,247 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +// +// The G4ShiftedCone class copied from standard G4Cons and modified to: +// 1) have an arbitrary position along Z axis, +// 2) represent a twopi-cone. Sectors are not supported but the +// corresponding code kept and just commented out. +// + +// +// ******************************************************************** +// * License and Disclaimer * +// * * +// * The Geant4 software is copyright of the Copyright Holders of * +// * the Geant4 Collaboration. It is provided under the terms and * +// * conditions of the Geant4 Software License, included in the file * +// * LICENSE and available at http://cern.ch/geant4/license . These * +// * include a list of copyright holders. * +// * * +// * Neither the authors of this software system, nor their employing * +// * institutes,nor the agencies providing financial support for this * +// * work make any representation or warranty, express or implied, * +// * regarding this software system or assume any liability for its * +// * use. Please see the license in the file LICENSE and URL above * +// * for the full disclaimer and the limitation of liability. * +// * * +// * This code implementation is the result of the scientific and * +// * technical work of the GEANT4 collaboration. * +// * By using, copying, modifying or distributing the software (or * +// * any work based on the software) you agree to acknowledge its * +// * use in resulting scientific publications, and indicate your * +// * acceptance of all terms of the Geant4 Software license. * +// ******************************************************************** +// +// +// +// +// -------------------------------------------------------------------- +// GEANT 4 class header file +// +// G4ShiftedCone +// +// Class description: +// +// A G4ShiftedCone is, in the general case, a Phi segment of a cone, +// inner and outer radii specified at z1 and z2. +// This version does not support phi segmetation, but the code is kept +// in case it would be necessary later. +// The Phi segment is described by a starting fSPhi angle, and the +// +fDPhi delta angle for the shape. +// If the delta angle is >=2*pi, the shape is treated as continuous +// in Phi +// +// Member Data: +// +// fRmin1 inside radius at z1 +// fRmin2 inside radius at z2 +// fRmax1 outside radius at z1 +// fRmax2 outside radius at z2 +// fDz half length in z +// +// fSPhi starting angle of the segment in radians +// fDPhi delta angle of the segment in radians +// +// fPhiFullCone Boolean variable used for indicate the Phi Section +// always true in the current version, hope compiler optimize +// +// Note: +// Internally fSPhi & fDPhi are adjusted so that fDPhi<=2PI, +// and fDPhi+fSPhi<=2PI. This enables simpler comparisons to be +// made with (say) Phi of a point. + +// History: +// 03.07.2019 A. Sukharev copied from G4Cons for ATLAS EMEC needs +// -------------------------------------------------------------------- +#ifndef G4ShiftedCone_HH +#define G4ShiftedCone_HH + +#include <CLHEP/Units/PhysicalConstants.h> + +#include "G4CSGSolid.hh" +#include "G4Polyhedron.hh" + +class G4ShiftedCone : public G4CSGSolid +{ + public: // with description + + G4ShiftedCone(const G4String& pName, + G4double pZ1, G4double pZ2, + G4double pRmin1, G4double pRmax1, + G4double pRmin2, G4double pRmax2); + // G4double pSPhi, G4double pDPhi); + // + // Constructs a cone with the given name and dimensions + + ~G4ShiftedCone() ; + // + // Destructor + + // Accessors + + inline G4double GetInnerRadiusMinusZ() const; + inline G4double GetOuterRadiusMinusZ() const; + inline G4double GetInnerRadiusPlusZ() const; + inline G4double GetOuterRadiusPlusZ() const; + inline G4double GetZHalfLength() const; + inline G4double GetZ1() const; + inline G4double GetZ2() const; + inline G4double GetStartPhiAngle() const; + inline G4double GetDeltaPhiAngle() const; + inline G4double GetSinStartPhi() const; + inline G4double GetCosStartPhi() const; + inline G4double GetSinEndPhi() const; + inline G4double GetCosEndPhi() const; + + // Modifiers + + inline void SetInnerRadiusMinusZ (G4double Rmin1 ); + inline void SetOuterRadiusMinusZ (G4double Rmax1 ); + inline void SetInnerRadiusPlusZ (G4double Rmin2 ); + inline void SetOuterRadiusPlusZ (G4double Rmax2 ); +// inline void SetStartPhiAngle (G4double newSPhi, G4bool trig=true); +// inline void SetDeltaPhiAngle (G4double newDPhi); + + // Other methods for solid + + inline G4double GetCubicVolume(); + inline G4double GetSurfaceArea(); + + void ComputeDimensions( G4VPVParameterisation* p, + const G4int n, + const G4VPhysicalVolume* pRep ); + + void BoundingLimits(G4ThreeVector& pMin, G4ThreeVector& pMax) const; + + G4bool CalculateExtent( const EAxis pAxis, + const G4VoxelLimits& pVoxelLimit, + const G4AffineTransform& pTransform, + G4double& pMin, G4double& pMax ) const; + + EInside Inside( const G4ThreeVector& p ) const; + + G4ThreeVector SurfaceNormal( const G4ThreeVector& p ) const; + + G4double DistanceToIn (const G4ThreeVector& p, + const G4ThreeVector& v) const; + G4double DistanceToIn (const G4ThreeVector& p) const; + G4double DistanceToOut(const G4ThreeVector& p, + const G4ThreeVector& v, + const G4bool calcNorm=G4bool(false), + G4bool *validNorm=0, + G4ThreeVector *n=0) const; + G4double DistanceToOut(const G4ThreeVector& p) const; + + G4GeometryType GetEntityType() const; + + G4ThreeVector GetPointOnSurface() const; + + G4VSolid* Clone() const; + + std::ostream& StreamInfo(std::ostream& os) const; + + // Visualisation functions + + void DescribeYourselfTo( G4VGraphicsScene& scene ) const; + G4Polyhedron* CreatePolyhedron() const; + + public: // without description + + G4ShiftedCone(__void__&); + // + // Fake default constructor for usage restricted to direct object + // persistency for clients requiring preallocation of memory for + // persistifiable objects. + + G4ShiftedCone(const G4ShiftedCone& rhs); + G4ShiftedCone& operator=(const G4ShiftedCone& rhs); + // Copy constructor and assignment operator. + + // Old access functions + + inline G4double GetRmin1() const; + inline G4double GetRmax1() const; + inline G4double GetRmin2() const; + inline G4double GetRmax2() const; +// inline G4double GetSPhi() const; +// inline G4double GetDPhi() const; + + private: + + inline void Initialize(); + // + // Reset relevant values to zero + +// inline void CheckSPhiAngle(G4double sPhi); +// inline void CheckDPhiAngle(G4double dPhi); +// inline void CheckPhiAngles(G4double sPhi, G4double dPhi); + // + // Reset relevant flags and angle values + + inline void InitializeTrigonometry(); + // + // Recompute relevant trigonometric values and cache them + + G4ThreeVector ApproxSurfaceNormal(const G4ThreeVector& p) const; + // + // Algorithm for SurfaceNormal() following the original + // specification for points not on the surface + + private: + + // Used by distanceToOut + // + enum ESide {kNull,kRMin,kRMax,kSPhi,kEPhi,kPZ,kMZ}; + + // used by normal + // + enum ENorm {kNRMin,kNRMax,kNSPhi,kNEPhi,kNZ}; + + G4double kRadTolerance, kAngTolerance; + // + // Radial and angular tolerances + + G4double fRmin1, fRmin2, fRmax1, fRmax2; + G4double fDz, fZshift;//, fSPhi, fDPhi; + // + // Radial and angular dimensions + +// G4double sinCPhi, cosCPhi, cosHDPhiOT, cosHDPhiIT, +// sinSPhi, cosSPhi, sinEPhi, cosEPhi; + // + // Cached trigonometric values + +// const G4bool fPhiFullCone; + // + // Flag for identification of section or full cone + + G4double halfCarTolerance, halfRadTolerance, halfAngTolerance; + // + // Cached half tolerance values +}; + +#include "G4ShiftedCone.icc" + +#endif diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/G4ShiftedCone.icc b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/G4ShiftedCone.icc new file mode 100644 index 0000000000000000000000000000000000000000..1d78d11180e0a87c9e425667aa2478355c1bb7fb --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/G4ShiftedCone.icc @@ -0,0 +1,337 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +// +// ******************************************************************** +// * License and Disclaimer * +// * * +// * The Geant4 software is copyright of the Copyright Holders of * +// * the Geant4 Collaboration. It is provided under the terms and * +// * conditions of the Geant4 Software License, included in the file * +// * LICENSE and available at http://cern.ch/geant4/license . These * +// * include a list of copyright holders. * +// * * +// * Neither the authors of this software system, nor their employing * +// * institutes,nor the agencies providing financial support for this * +// * work make any representation or warranty, express or implied, * +// * regarding this software system or assume any liability for its * +// * use. Please see the license in the file LICENSE and URL above * +// * for the full disclaimer and the limitation of liability. * +// * * +// * This code implementation is the result of the scientific and * +// * technical work of the GEANT4 collaboration. * +// * By using, copying, modifying or distributing the software (or * +// * any work based on the software) you agree to acknowledge its * +// * use in resulting scientific publications, and indicate your * +// * acceptance of all terms of the Geant4 Software license. * +// ******************************************************************** +// +// +// +// -------------------------------------------------------------------- +// GEANT 4 inline definitions file +// +// G4ShiftedCone.icc +// +// Implementation of inline methods of G4ShiftedCone +// -------------------------------------------------------------------- + +inline +G4double G4ShiftedCone::GetInnerRadiusMinusZ() const +{ + return fRmin1 ; +} + +inline +G4double G4ShiftedCone::GetOuterRadiusMinusZ() const +{ + return fRmax1 ; +} + +inline +G4double G4ShiftedCone::GetInnerRadiusPlusZ() const +{ + return fRmin2 ; +} + +inline +G4double G4ShiftedCone::GetOuterRadiusPlusZ() const +{ + return fRmax2 ; +} + +inline +G4double G4ShiftedCone::GetZHalfLength() const +{ + return fDz ; +} + +inline +G4double G4ShiftedCone::GetZ1() const +{ + return fZshift - fDz ; +} + +inline +G4double G4ShiftedCone::GetZ2() const +{ + return fZshift + fDz ; +} + +inline +G4double G4ShiftedCone::GetStartPhiAngle() const +{ + return 0.; // fSPhi ; +} + +inline +G4double G4ShiftedCone::GetDeltaPhiAngle() const +{ + return CLHEP::twopi; //fDPhi; +} + +inline +G4double G4ShiftedCone::GetSinStartPhi() const +{ + return 0.; //sinSPhi; +} + +inline +G4double G4ShiftedCone::GetCosStartPhi() const +{ + return 1.;// cosSPhi; +} + +inline +G4double G4ShiftedCone::GetSinEndPhi() const +{ + return 0.;// sinEPhi; +} + +inline +G4double G4ShiftedCone::GetCosEndPhi() const +{ + return 1.;//cosEPhi; +} + +inline +void G4ShiftedCone::Initialize() +{ + fCubicVolume = 0.; + fSurfaceArea = 0.; + fRebuildPolyhedron = true; +} + +/* +inline +void G4ShiftedCone::InitializeTrigonometry() +{ + G4double hDPhi = 0.5*fDPhi; // half delta phi + G4double cPhi = fSPhi + hDPhi; + G4double ePhi = fSPhi + fDPhi; + + sinCPhi = std::sin(cPhi); + cosCPhi = std::cos(cPhi); + cosHDPhiIT = std::cos(hDPhi - 0.5*kAngTolerance); // inner/outer tol half dphi + cosHDPhiOT = std::cos(hDPhi + 0.5*kAngTolerance); + sinSPhi = std::sin(fSPhi); + cosSPhi = std::cos(fSPhi); + sinEPhi = std::sin(ePhi); + cosEPhi = std::cos(ePhi); +} + +inline void G4ShiftedCone::CheckSPhiAngle(G4double sPhi) +{ + // Ensure fSphi in 0-2PI or -2PI-0 range if shape crosses 0 + + if ( sPhi < 0 ) + { + fSPhi = CLHEP::twopi - std::fmod(std::fabs(sPhi),CLHEP::twopi); + } + else + { + fSPhi = std::fmod(sPhi,CLHEP::twopi) ; + } + if ( fSPhi+fDPhi > CLHEP::twopi ) + { + fSPhi -= CLHEP::twopi ; + } +} + +inline void G4ShiftedCone::CheckDPhiAngle(G4double dPhi) +{ + fPhiFullCone = true; + if ( dPhi >= CLHEP::twopi-kAngTolerance*0.5 ) + { + fDPhi=CLHEP::twopi; + fSPhi=0; + } + else + { + fPhiFullCone = false; + if ( dPhi > 0 ) + { + fDPhi = dPhi; + } + else + { + std::ostringstream message; + message << "Invalid dphi." << G4endl + << "Negative or zero delta-Phi (" << dPhi << ") in solid: " + << GetName(); + G4Exception("G4ShiftedCone::CheckDPhiAngle()", "GeomSolids0002", + FatalException, message); + } + } +} + +inline void G4ShiftedCone::CheckPhiAngles(G4double sPhi, G4double dPhi) +{ + CheckDPhiAngle(dPhi); + if ( (fDPhi<CLHEP::twopi) && (sPhi) ) { CheckSPhiAngle(sPhi); } + InitializeTrigonometry(); +} +*/ + +inline +void G4ShiftedCone::SetInnerRadiusMinusZ( G4double Rmin1 ) +{ + fRmin1= Rmin1 ; + Initialize(); +} + +inline +void G4ShiftedCone::SetOuterRadiusMinusZ( G4double Rmax1 ) +{ + fRmax1= Rmax1 ; + Initialize(); +} + +inline +void G4ShiftedCone::SetInnerRadiusPlusZ ( G4double Rmin2 ) +{ + fRmin2= Rmin2 ; + Initialize(); +} + +inline +void G4ShiftedCone::SetOuterRadiusPlusZ ( G4double Rmax2 ) +{ + fRmax2= Rmax2 ; + Initialize(); +} + +/*inline +void G4ShiftedCone::SetZHalfLength ( G4double newDz ) +{ + fDz= newDz ; + Initialize(); +}*/ + +/* +inline +void G4ShiftedCone::SetStartPhiAngle ( G4double newSPhi, G4bool compute ) +{ + // Flag 'compute' can be used to explicitely avoid recomputation of + // trigonometry in case SetDeltaPhiAngle() is invoked afterwards + + CheckSPhiAngle(newSPhi); + fPhiFullCone = false; + if (compute) { InitializeTrigonometry(); } + Initialize(); +} + +void G4ShiftedCone::SetDeltaPhiAngle ( G4double newDPhi ) +{ + CheckPhiAngles(fSPhi, newDPhi); + Initialize(); +} +*/ +// Old access methods ... + +inline +G4double G4ShiftedCone::GetRmin1() const +{ + return GetInnerRadiusMinusZ(); +} + +inline +G4double G4ShiftedCone::GetRmax1() const +{ + return GetOuterRadiusMinusZ(); +} + +inline +G4double G4ShiftedCone::GetRmin2() const +{ + return GetInnerRadiusPlusZ(); +} + +inline +G4double G4ShiftedCone::GetRmax2() const +{ + return GetOuterRadiusPlusZ(); +} +/* +inline +G4double G4ShiftedCone::GetDz() const +{ + return GetZHalfLength(); +} + +inline +G4double G4ShiftedCone::GetSPhi() const +{ + return GetStartPhiAngle(); +} + +inline +G4double G4ShiftedCone::GetDPhi() const +{ + return GetDeltaPhiAngle(); +} +*/ +inline +G4double G4ShiftedCone::GetCubicVolume() +{ + if(fCubicVolume != 0.) {;} + else + { + G4double Rmean, rMean, deltaR, deltar; + + Rmean = 0.5*(fRmax1+fRmax2); + deltaR = fRmax1-fRmax2; + + rMean = 0.5*(fRmin1+fRmin2); + deltar = fRmin1-fRmin2; + fCubicVolume = GetDeltaPhiAngle()*fDz*(Rmean*Rmean-rMean*rMean + +(deltaR*deltaR-deltar*deltar)/12); + } + return fCubicVolume; +} + +inline +G4double G4ShiftedCone::GetSurfaceArea() +{ + if(fSurfaceArea != 0.) {;} + else + { + G4double mmin, mmax, dmin, dmax; + + mmin= (fRmin1+fRmin2)*0.5; + mmax= (fRmax1+fRmax2)*0.5; + dmin= (fRmin2-fRmin1); + dmax= (fRmax2-fRmax1); + + fSurfaceArea = GetDeltaPhiAngle()*( mmin * std::sqrt(dmin*dmin+4*fDz*fDz) + + mmax * std::sqrt(dmax*dmax+4*fDz*fDz) + + 0.5*(fRmax1*fRmax1-fRmin1*fRmin1 + +fRmax2*fRmax2-fRmin2*fRmin2 )); +/* if(!fPhiFullCone) + { + fSurfaceArea = fSurfaceArea+4*fDz*(mmax-mmin); + }*/ + } + return fSurfaceArea; +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArFanSection.cxx b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArFanSection.cxx new file mode 100644 index 0000000000000000000000000000000000000000..62987dc38723cc36f02417c69e92c5c71483b44c --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArFanSection.cxx @@ -0,0 +1,265 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +*/ + +#include "LArWheelSolid.h" +#include "LArFanSection.h" +#include "GeoSpecialShapes/LArWheelCalculator.h" +#include <iostream> +#include <cassert> + +void LArFanSections::print(void) const +{ + std::cout << "LArFanSections at " << this << std::endl + << "Amin = " << Amin << ", Amax = " << Amax + << std::endl + << "Bmin = " << Bmin << ", Bmax = " << Bmax << std::endl + << "xmin = " << xmin << ", xmax = " << xmax + << "Cflat2 = " << Cflat2 << std::endl; +} + +LArFanSections::LArFanSections( + G4double ri1, G4double ri2, G4double ro1, G4double ro2, + G4double Xmax, G4double z1, G4double z2 +) + : Amin ((ri2 - ri1) / (z2 - z1)), + Amax ((ro2 - ro1) / (z2 - z1)), + Bmin (ri1 - Amin * z1), + Bmax (ro1 - Amax * z1), + Amin2 (Amin*Amin), + Amax2 (Amax*Amax), + Bmin2 (Bmin*Bmin), + Bmax2 (Bmax*Bmax), + xmin (-Xmax), + xmax (Xmax), + Cflat2 (ro2*ro2), + ABmax (Amax*Bmax), + ABmin (Amin*Bmin) +{ +} + +G4bool LArWheelSolid::check_D( + G4double &t1, G4double A, G4double B, G4double C, G4bool out +) const +{ + // G4bool out is to be set true if the point is surface-outside + // then have to discard first intersection + + const G4double D = B*B - A*C; + LWSDBG(8, std::cout << "check D=" << D << " out=" << out << std::endl); + if(D < 0.) return false; + + const G4double D1 = sqrt(D); + t1 = (-B + D1) / A; + const G4double t2 = (-B - D1) / A; + LWSDBG(8, std::cout << "t1=" << t1 << " t2=" << t2 << std::endl); + if(t1 > 0.){ + if(t2 > 0.){ + if(out){ + if(t2 > t1) t1 = t2; + } else { + if(t2 < t1) t1 = t2; + } + } else if(t2 < 0.){ + if(out) return false; + } else { // answer is t1 + } + } else if(t1 < 0.){ + if(t2 > 0.){ + if(out) return false; + t1 = t2; + } else if(t2 < 0.){ + return false; + } else { + return false; + } + } else { + if(t2 > 0.){ + t1 = t2; + } else if(t2 < 0.){ + return false; + } else { + return false; + } + } + return true; +} + +// p must be not outside of the "FanBound" +// if track crosses inner cone in valid (z, x) interval, +// returns true, sets q to the cross point +bool LArWheelSolid::fs_cross_lower( + const G4ThreeVector &p, const G4ThreeVector &v, + G4ThreeVector &q) const +{ + LWSDBG(7, std::cout << "fcl" << std::endl); + const G4double A = v.perp2() - m_fs->Amin2*v.z()*v.z(); + const G4double B = p.x()*v.x() + p.y()*v.y() + - m_fs->Amin2*p.z()*v.z() - m_fs->ABmin*v.z(); + const G4double C = p.perp2() - m_fs->Amin2*p.z()*p.z() + - 2.*m_fs->ABmin*p.z() - m_fs->Bmin2; + G4double t1(0.0); + const G4double out_dist = m_fs->Amin*p.z() + m_fs->Bmin - p.perp(); + LWSDBG(8, std::cout << "fcl out_dist(p)=" << out_dist << " Tolerance=" << s_Tolerance << std::endl); + const G4bool out = out_dist >= 0.0; + if(check_D(t1, A, B, C, out)){ + const G4double zz1 = p.z() + v.z() * t1; + if(zz1 < m_Zsect.front() || zz1 > m_Zsect.back()){ + LWSDBG(8, std::cout << "fcl out on Z " << zz1 << std::endl); + return false; + } + const G4double xx1 = p.x() + v.x() * t1; + if(xx1 < m_fs->xmin || xx1 > m_fs->xmax){ + LWSDBG(8, std::cout << "fcl out on X " << xx1 << std::endl); + return false; + } + if(out_dist == 0.){ // entry point is exactly on the cone + // here we got t1 > 0 from check_D, founded point seems to be in x and z ranges + // if the track leaves the surface, then the entry is the intersection, + // and the distance is 0 + // if the track is on the surface, then there is no lower cone intersection + + // estimate deviation of the track from the surface + // (exact calculations are too complicated) + const G4double xx2 = p.x() + v.x() * t1 * 0.5; + const G4double yy2 = p.y() + v.y() * t1 * 0.5; + const G4double dev = fabs(sqrt(xx2 *xx2 + yy2*yy2) + - m_fs->Amin*(p.z() + zz1)*0.5 + - m_fs->Bmin); + if(dev < s_Tolerance){ + LWSDBG(8, std::cout << "fcl on the surface" << std::endl); + return false; + } else { + LWSDBG(8, std::cout << "fcl out = in" << std::endl); + q = p; + return true; + } + } + q.setX(xx1); + q.setY(p.y() + v.y() * t1); + q.setZ(zz1); + LWSDBG(8, std::cout << "fcl got " << t1 << std::endl); + return true; + } + LWSDBG(8, std::cout << "fcl no intersection" << std::endl); + return false; +} + +// p must be not outside of the "FanBound" +// if track crosses outer cone in valid (z, x) interval, +// returns true, adds to b the distance to the cross point, +// sets q to the cross point +bool LArWheelSolid::fs_cross_upper( + const G4ThreeVector &p, const G4ThreeVector &v, + G4ThreeVector &q) const +{ + LWSDBG(7, std::cout << "fcu" << std::endl); + G4double A = v.perp2(); + G4double B = p.x()*v.x() + p.y()*v.y(); + G4double C = p.perp2(); + + if(m_IsOuter){ + const G4double &Af = A, &Bf = B; + const G4double Cf = C - m_fs->Cflat2; + G4double b1; + if(check_D(b1, Af, Bf, Cf, Cf >= 0.)){ + const G4double zz1 = p.z() + v.z() * b1; + if(zz1 >= m_Zmid && zz1 <= m_Zsect.back()){ + const G4double xx1 = p.x() + v.x() * b1; + if(xx1 < m_fs->xmin || xx1 > m_fs->xmax) return false; + q.setX(xx1); + q.setY(p.y() + v.y() * b1); + q.setZ(zz1); + return true; + } + } + LWSDBG(8, std::cout << "fcu no cyl intersection" << std::endl); + } + + A -= m_fs->Amax2*v.z()*v.z(); + B -= m_fs->Amax2*p.z()*v.z() + m_fs->ABmax*v.z(); + C -= m_fs->Amax2*p.z()*p.z() + 2.*m_fs->ABmax*p.z() + m_fs->Bmax2; + + G4double t1; + const G4bool out = m_fs->Amax*p.z() + m_fs->Bmax <= p.perp(); + if(check_D(t1, A, B, C, out)){ + const G4double zz1 = p.z() + v.z() * t1; + LWSDBG(8, std::cout << "fcu z = " << zz1 << ", lim: (" << m_Zsect.front() << ", " << m_Zmid << ")" << std::endl); + if(zz1 < m_Zsect.front() || zz1 > m_Zmid) return false; + const G4double xx1 = p.x() + v.x() * t1; + LWSDBG(8, std::cout << "fcu x = " << xx1 << ", lim: (" << m_fs->xmin << ", " << m_fs->xmax << ")" << std::endl); + if(xx1 < m_fs->xmin || xx1 > m_fs->xmax) return false; + q.setX(xx1); + q.setY(p.y() + v.y() * t1); + q.setZ(zz1); + return true; + } + LWSDBG(8, std::cout << "fcu no cone intersection" << std::endl); + return false; +} + +/* p must be not outside "FanBound" */ +LArWheelSolid::FanBoundExit_t LArWheelSolid::find_exit_point( + const G4ThreeVector &p, const G4ThreeVector &v, + G4ThreeVector &q) const +{ + LWSDBG(6, std::cout << "in fep p" << MSG_VECTOR(p)<< ", v"<< MSG_VECTOR(v) << ", q" << MSG_VECTOR(q) << std::endl); + +/* by construction, cannot have true from both upper and lower */ +/* the only problem is the points on surface but "slightly outside" */ +/* fs_cross_* account for (x, z) range */ +// lower has to be checked first, since outer might find more distant +// intersection in the acceptable (x, z) range + if(fs_cross_lower(p, v, q)) return ExitAtInner; + LWSDBG(6, std::cout << "after fs_cross_lower q" << MSG_VECTOR(q) << std::endl); + if(fs_cross_upper(p, v, q)) return ExitAtOuter; + LWSDBG(6, std::cout << "after fs_cross_upper q" << MSG_VECTOR(q) << std::endl); + + FanBoundExit_t result = ExitAtSide; + G4double d; + if(v.x() > 0.) d = (m_fs->xmax - p.x()) / v.x(); + else if(v.x() < 0.) d = (m_fs->xmin - p.x()) / v.x(); + else d = kInfinity; + + G4double dz; + FanBoundExit_t resultz = NoCross; + if(v.z() > 0.){ + dz = (m_Zsect.back() - p.z()) / v.z(); + resultz = ExitAtBack; + } else if(v.z() < 0.){ + dz = (m_Zsect.front() - p.z()) / v.z(); + resultz = ExitAtFront; + } else { + dz = kInfinity; + } + if(d > dz){ + d = dz; + result = resultz; + } + q = p + v * d; + LWSDBG(7, std::cout << "fep side " << d << " " << result << " q" << MSG_VECTOR(q) << std::endl); + const G4double out_distlower = m_fs->Amin*q.z() + m_fs->Bmin - q.perp(); // > 0 - below lower cone + LWSDBG(7, std::cout << "fep out_distlower(q)=" << out_distlower << " Tolerance=" << s_Tolerance << std::endl); + if (out_distlower >= 0.0) { + // side intersection point is below lower cone + // initial point p was at exit boundary + q = p; + return NoCross; + } + + if (m_IsOuter && q.z() >= m_Zmid && q.z() <= m_Zsect.back()+s_Tolerance && q.perp2() >= m_fs->Cflat2) { + // outside of upper cylinder + q = p; + return NoCross; + } + const G4double out_distupper = m_fs->Amax*q.z() + m_fs->Bmax - q.perp(); // < 0 - above upper cone + LWSDBG(7, std::cout << "fep out_distupper(q)=" << out_distupper << " Tolerance=" << s_Tolerance << std::endl); + if (out_distupper <= 0.0) { + // side intersection point is above upper cone + // initial point p was at exit boundary + q = p; + return NoCross; + } + assert((q - p).mag() < kInfinity); + return result; +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArFanSection.h b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArFanSection.h new file mode 100644 index 0000000000000000000000000000000000000000..af3327c318256ae78aca0c77a9269b8e92505509 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArFanSection.h @@ -0,0 +1,30 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef __LARFANSECTION_H__ +#define __LARFANSECTION_H__ + +// helper class to replace G4Polycone +// in certain LArWheelSolid operations + +class LArFanSections +{ +public: + G4double Amin, Amax; + G4double Bmin, Bmax; + G4double Amin2, Amax2; + G4double Bmin2, Bmax2; + G4double xmin, xmax; + G4double Cflat2, ABmax, ABmin; + + LArFanSections( + G4double ri1, G4double ri2, + G4double ro1, G4double ro2, + G4double Xmax, G4double z1, G4double z2 + ); + + void print(void) const; +}; + +#endif // __LARFANSECTION_H__ diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolid.cxx b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolid.cxx new file mode 100644 index 0000000000000000000000000000000000000000..dd7a61903fd47354f305a76e924980a59313ec9a --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolid.cxx @@ -0,0 +1,104 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "G4VGraphicsScene.hh" +#include "G4VisExtent.hh" + +#include "GeoSpecialShapes/LArWheelCalculator.h" +#include "LArWheelSliceSolid.h" + +class G4NURBS; +class G4VoxelLimits; +class G4AffineTransform; + +EInside LArWheelSliceSolid::Inside(const G4ThreeVector &inputP) const +{ + LWSDBG(10, std::cout << std::setprecision(25)); + LWSDBG(1, std::cout << TypeStr() << " Inside " << MSG_VECTOR(inputP) << std::endl); + const EInside inside_BS = m_BoundingShape->Inside(inputP); + if(inside_BS == kOutside){ + LWSDBG(2, std::cout << "outside BS" << std::endl); + return kOutside; + } + G4ThreeVector p(inputP); + int p_fan = 0; + const G4double d = fabs(GetCalculator()->DistanceToTheNearestFan(p, p_fan)); + if(d > m_FHTplusT){ + LWSDBG(2, std::cout << "outside fan d=" << d << ", m_FHTplusT=" << m_FHTplusT << std::endl); + return kOutside; + } + if(d < m_FHTminusT){ + LWSDBG(2, std::cout << "inside fan d=" << d << ", m_FHTminusT=" << m_FHTminusT << ", inside_BS=" << inside(inside_BS) << std::endl); + return inside_BS; + } + LWSDBG(2, std::cout << "surface" << std::endl); + return kSurface; +} + +G4ThreeVector LArWheelSliceSolid::SurfaceNormal(const G4ThreeVector &inputP) const +{ + LWSDBG(1, std::cout << TypeStr() << " SurfaceNormal" << MSG_VECTOR(inputP) << std::endl); + EInside inside_BS = m_BoundingShape->Inside(inputP); + if(inside_BS != kInside){ + LWSDBG(2, std::cout << "not inside BS" << std::endl); + return m_BoundingShape->SurfaceNormal(inputP); + } + G4ThreeVector p( inputP ); + int p_fan = 0; + GetCalculator()->DistanceToTheNearestFan(p, p_fan); + G4ThreeVector d = GetCalculator()->NearestPointOnNeutralFibre(p, p_fan); + d.rotateZ(inputP.phi() - p.phi()); // rotate back to initial position + LWSDBG(4, std::cout << "npnf" << MSG_VECTOR(d) << std::endl); + p = inputP - d; + LWSDBG(2, std::cout << "sn " << MSG_VECTOR(p.unit()) << std::endl); + return(p.unit()); +} + +G4bool LArWheelSliceSolid::CalculateExtent( + const EAxis a, const G4VoxelLimits &vl, + const G4AffineTransform &t, G4double &p, + G4double &q +) const +{ + return m_BoundingShape->CalculateExtent(a, vl, t, p, q); +} + +G4String LArWheelSliceSolid::TypeStr(void) const +{ + G4String ret(""); + switch(m_Pos){ + case Inner: + switch(m_Type){ + case Absorber: ret = "LArInnerAbsorberWheel"; break; + case Electrode: ret = "LArInnerElectrodWheel"; break; + case Glue: ret = "LArInnerGlueWheel"; break; + case Lead: ret = "LArInnerLeadWheel"; break; + } + break; + case Outer: + switch(m_Type){ + case Absorber: ret = "LArOuterAbsorberWheel"; break; + case Electrode: ret = "LArOuterElectrodWheel"; break; + case Glue: ret = "LArOuterGlueWheel"; break; + case Lead: ret = "LArOuterLeadWheel"; break; + } + break; + } + return ret; +} + +void LArWheelSliceSolid::DescribeYourselfTo(G4VGraphicsScene &scene) const +{ + scene.AddSolid(*this); +} + +G4VisExtent LArWheelSliceSolid::GetExtent() const +{ + return m_BoundingShape->GetExtent(); +} + +G4Polyhedron* LArWheelSliceSolid::CreatePolyhedron() const +{ + return m_BoundingShape->CreatePolyhedron(); +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolid.h b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolid.h new file mode 100644 index 0000000000000000000000000000000000000000..7d05aaa2d305de53486c75ab19c63b86aa39e9f7 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolid.h @@ -0,0 +1,196 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef GEO2G4_LARWHEELSLICESOLID_H +#define GEO2G4_LARWHEELSLICESOLID_H +#ifndef PORTABLE_LAR_SHAPE +#include "AthenaKernel/MsgStreamMember.h" +#endif +#include "G4VSolid.hh" + +// set this to allow debug output in LArWheelSliceSolid methods +// disabled by default to avoid any performance degradation +//#define DEBUG_LARWHEELSLICESOLID + +// set this to check in dti and dto functions if particle direction +// pointing inside or outside of volume to return zero fast when it is required by spec. +// currently at development stage, requires accurate surface normal calculations +//#define CHECK_DIRTONORM_ANGLE_ON_SURFACE + +#ifdef DEBUG_LARWHEELSLICESOLID +#define LWSDBG(a, b) if(Verbose >= a) b +#define MSG_VECTOR(v) "(" << v.x() << ", " << v.y() << ", " << v.z() << ")" +//#define LWS_HARD_TEST_DTI +//#define LWS_HARD_TEST_DTO +#else +#define LWSDBG(a, b) +#endif + +// Forward declarations. +class G4VGraphicsScene; +class G4VisExtent; +class G4Polyhedron; +class G4NURBS; +class G4VoxelLimits; +class G4AffineTransform; +class LArWheelCalculator; +class TF1; +class G4Polyhedra; +struct EMECData; +class LArWheelSliceSolid : public G4VSolid +{ + public: + typedef enum { Inner, Outer } pos_t; + typedef enum { Absorber, Electrode, Glue, Lead } type_t; + + LArWheelSliceSolid( + const G4String& name, + pos_t pos, type_t type, size_t slice, + G4int zside = 1, + const LArWheelCalculator *calc = 0, + const EMECData * emecData=0 + ); + LArWheelSliceSolid(const G4String& name, const EMECData *emecData); + virtual ~LArWheelSliceSolid(){} + + // Mandatory for custom solid Geant4 functions + EInside Inside(const G4ThreeVector&) const; + G4double DistanceToIn(const G4ThreeVector&, + const G4ThreeVector&) const; + G4double DistanceToIn(const G4ThreeVector&) const; + G4double DistanceToOut(const G4ThreeVector&, + const G4ThreeVector&, + const G4bool calcNorm = false, + G4bool* validNorm = 0, + G4ThreeVector* n = 0) const; + G4double DistanceToOut(const G4ThreeVector&) const; + G4ThreeVector SurfaceNormal (const G4ThreeVector&) const; + G4bool CalculateExtent(const EAxis, + const G4VoxelLimits&, + const G4AffineTransform&, + G4double&, + G4double&) const; + G4GeometryType GetEntityType() const { return TypeStr(); } + void DescribeYourselfTo(G4VGraphicsScene&) const; + G4VisExtent GetExtent() const; + G4Polyhedron* CreatePolyhedron() const; + virtual std::ostream& StreamInfo(std::ostream& os) const { return os; } + +#ifndef PORTABLE_LAR_SHAPE + G4ThreeVector GetPointOnSurface(void) const; + G4double GetCubicVolume(void); + G4double GetSurfaceArea(void); +#endif + // + + const G4VSolid *GetBoundingShape(void) const { return m_BoundingShape; } + const LArWheelCalculator *GetCalculator(void) const { return m_Calculator; } + + private: + static const G4double s_Tolerance; + static const G4double s_AngularTolerance; + static const G4double s_IterationPrecision; + static const G4double s_IterationPrecision2; + static const unsigned int s_IterationsLimit; + + pos_t m_Pos; + type_t m_Type; + const LArWheelCalculator *m_Calculator; + G4VSolid* m_BoundingShape; + + G4double m_FanHalfThickness, m_FHTplusT, m_FHTminusT; + + // limits used in DTI + G4double m_Xmin, m_Xmax; + + // Special limit, used in dto + G4double m_Ymin; + + // limits for use in service functions + G4double m_Zmin, m_Zmax, m_Rmin, m_Rmax; + + void inner_solid_init(const G4String &, size_t slice); + void outer_solid_init(const G4String &, size_t slice); + void fill_zsect(std::vector<G4double> &, G4double zMid = 0.) const; + + virtual G4double distance_to_in(G4ThreeVector &, const G4ThreeVector &, int) const; + G4double in_iteration_process(const G4ThreeVector &, + G4double, G4ThreeVector &, int) const; + G4double search_for_nearest_point( + const G4ThreeVector &, const G4double, + const G4ThreeVector &, int + ) const; + G4bool search_for_most_remoted_point( + const G4ThreeVector &, const G4ThreeVector &, + G4ThreeVector &, const int + ) const; + G4double out_iteration_process( + const G4ThreeVector &, G4ThreeVector &, const int + ) const; + +#ifndef PORTABLE_LAR_SHAPE + EInside Inside_accordion(const G4ThreeVector&) const; + void get_point_on_accordion_surface(G4ThreeVector &) const; + void get_point_on_polycone_surface(G4ThreeVector &) const; + void get_point_on_flat_surface(G4ThreeVector &) const; + void set_failover_point(G4ThreeVector &p, const char *m = 0) const; + + G4double get_area_on_polycone(void) const; + G4double get_area_on_face(void) const; + G4double get_area_on_side(void) const; + + G4double get_area_at_r(G4double r) const; + G4double get_length_at_r(G4double r) const; + + void test(void); + void clean_tests(void); + void init_tests(void); + /// Log a message using the Athena controlled logging system + MsgStream& msg( MSG::Level lvl ) const { return m_msg << lvl; } + /// Check whether the logging system is active at the provided verbosity level + bool msgLvl( MSG::Level lvl ) const { return m_msg.get().level() <= lvl; } +#endif + +protected: + /// Private message stream member +#ifndef PORTABLE_LAR_SHAPE + mutable Athena::MsgStreamMember m_msg; + + TF1 *m_f_area, *m_f_vol, *m_f_area_on_pc, *m_f_length, *m_f_side_area; +#endif + + double m_test_index; + friend double LArWheelSliceSolid_fcn_area(double *, double *); + friend double LArWheelSliceSolid_fcn_vol(double *, double *); + friend double LArWheelSliceSolid_fcn_area_on_pc(double *, double *); + friend double LArWheelSliceSolid_get_dl(double *, double *, G4int); + friend double LArWheelSliceSolid_fcn_side_area(double *, double *); + +#ifdef DEBUG_LARWHEELSLICESOLID + static const char* inside(EInside i) + { + switch(i){ + case kInside: return "inside"; break; + case kSurface: return "surface"; break; + case kOutside: return "outside"; break; + } + return "unknown"; + } + + public: + static G4int Verbose; + void SetVerbose(G4int v){ Verbose = v; } + G4bool test_dti(const G4ThreeVector &p, + const G4ThreeVector &v, const G4double distance) const; + G4bool test_dto(const G4ThreeVector &p, + const G4ThreeVector &v, const G4double distance) const; +#endif + private: + G4String TypeStr(void) const; + + void createSolid(const G4String& name, G4int zside, size_t slice, const EMECData *emecData); + inline void check_slice(size_t size, size_t slice) const; +}; + +#endif // GEO2G4_LARWHEELSLICESOLID_H diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolidDisToIn.cxx b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolidDisToIn.cxx new file mode 100644 index 0000000000000000000000000000000000000000..56a6ac4f7f97b64d73130ecf5c9f625ebb3494f1 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolidDisToIn.cxx @@ -0,0 +1,266 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +*/ + +// DistanceToIn stuff for LArWheelSliceSolid +#include <cassert> +#ifndef PORTABLE_LAR_SHAPE +#include "AthenaBaseComps/AthMsgStreamMacros.h" +#endif +#include "CLHEP/Units/PhysicalConstants.h" + +#include "GeoSpecialShapes/LArWheelCalculator.h" +#include "LArWheelSliceSolid.h" + +G4double LArWheelSliceSolid::DistanceToIn(const G4ThreeVector &inputP) const +{ + LWSDBG(1, std::cout << TypeStr() << " DisToIn" << MSG_VECTOR(inputP) << std::endl); + if(m_BoundingShape->Inside(inputP) == kOutside) { + // here is an approximation - for the point outside m_BoundingShape + // the solid looks like a m_BoundingShape + // it's okay since the result could be underestimated + LWSDBG(2, std::cout << "Outside BS" << std::endl); + return m_BoundingShape->DistanceToIn(inputP); + } + G4ThreeVector p(inputP); + + // + // DistanceToTheNearestFan: + // rotates point p to the localFan coordinates and returns fan number to out_fan_number parameter + // returns distance to fan as result + // + + int p_fan = 0; + const G4double d = fabs(GetCalculator()->DistanceToTheNearestFan(p, p_fan)); + if(d > m_FHTplusT){ + const G4double result = d - m_FanHalfThickness; + LWSDBG(2, std::cout << "dti result = " << result << std::endl); + return result; + } + LWSDBG(2, std::cout << "already inside, return 0" << MSG_VECTOR(p) << std::endl); + return 0.; +} + +G4double LArWheelSliceSolid::DistanceToIn(const G4ThreeVector &inputP, + const G4ThreeVector &inputV) const +{ + LWSDBG(1, std::cout << TypeStr() << " DisToIn" << MSG_VECTOR(inputP) + << MSG_VECTOR(inputV) << std::endl); + + G4double distance = 0.; + const EInside inside_BS = m_BoundingShape->Inside(inputP); + G4ThreeVector p(inputP); + if(inside_BS == kOutside) { + distance = m_BoundingShape->DistanceToIn(inputP, inputV); + if(distance == kInfinity) { + LWSDBG(2, std::cout << "Infinity distance to m_BoundingShape" + << MSG_VECTOR(inputP) << MSG_VECTOR(inputV) + << std::endl); + return kInfinity; + } + p += inputV * distance; + assert(m_BoundingShape->Inside(p) != kOutside); + LWSDBG(2, std::cout << "shift" << MSG_VECTOR(inputP) << std::endl); + } + + const G4double phi0 = p.phi(); + int p_fan = 0; + const G4double d = GetCalculator()->DistanceToTheNearestFan(p, p_fan); + if(fabs(d) < m_FHTminusT){ + LWSDBG(2, std::cout << "already inside fan" << MSG_VECTOR(p) << std::endl); + // if initial point is on BS surface and inside fan volume it is a real surface + if(inside_BS == kSurface) { + LWSDBG(2, std::cout << "On BS surface" << std::endl); + return m_BoundingShape->DistanceToIn(inputP, inputV); + } + return distance; + } + G4ThreeVector v(inputV); + v.rotateZ(p.phi() - phi0); + + const G4double d0 = distance_to_in(p, v, p_fan); + distance += d0; + +#ifdef DEBUG_LARWHEELSLICESOLID + if(Verbose > 2){ + if(Verbose > 3){ + std::cout << MSG_VECTOR(inputP) + << " " << MSG_VECTOR(inputV) << std::endl; + } + std::cout << "dti: " << d0 << ", DTI: " << distance << std::endl; + } + if(Verbose > 3){ + if(d0 < kInfinity){ + G4ThreeVector p2 = inputP + inputV*distance; + EInside i = Inside(p2); + std::cout << "DTI hit at dist. " << distance << ", point " + << MSG_VECTOR(p2) << ", " + << inside(i) << std::endl; + } else { + std::cout << "got infinity from dti" << std::endl; + } + } +#ifdef LWS_HARD_TEST_DTI + if(test_dti(inputP, inputV, distance)){ + if(Verbose == 1){ + std::cout << TypeStr() << " DisToIn" << MSG_VECTOR(inputP) + << MSG_VECTOR(inputV) << std::endl; + } + } + if(Verbose == 1){ + std::cout << TypeStr() << " DisToIn" << MSG_VECTOR(inputP) + << MSG_VECTOR(inputV) << " " << distance << std::endl; + } +#endif // ifdef LWS_HARD_TEST_DTI + +#endif // ifdef DEBUG_LARWHEELSLICESOLID + + return distance; +} + +G4double LArWheelSliceSolid::distance_to_in(G4ThreeVector &p, const G4ThreeVector &v, int p_fan) const +{ + LWSDBG(4, std::cout << "dti: " << MSG_VECTOR(p) << " " + << MSG_VECTOR(v) << std::endl); + + G4double distance = 0.; + + if(p.x() > m_Xmax) { + if(v.x() >= 0.) return kInfinity; + const G4double b = (m_Xmax - p.x()) / v.x(); + const G4double y2 = p.y() + v.y() * b; + const G4double z2 = p.z() + v.z() * b; + p.set(m_Xmax, y2, z2); + distance += b; + } else if(p.x() < m_Xmin) { + if(v.x() <= 0.) return kInfinity; + const G4double b = (m_Xmin - p.x()) / v.x(); + const G4double y2 = p.y() + v.y() * b; + const G4double z2 = p.z() + v.z() * b; + p.set(m_Xmin, y2, z2); + distance += b; + } + +// here p is on surface of or inside the "FanBound", +// distance corrected, misses are accounted for + LWSDBG(5, std::cout << "dti corrected: " << MSG_VECTOR(p) << std::endl); + + G4double dist_p = GetCalculator()->DistanceToTheNeutralFibre(p, p_fan); + if(fabs(dist_p) < m_FHTminusT) { + LWSDBG(5, std::cout << "hit fan dist_p=" << dist_p << ", m_FHTminusT=" << m_FHTminusT << std::endl); + return distance; + } + + G4ThreeVector q; + q = p + v * m_BoundingShape->DistanceToOut(p, v); + G4double dist_q = GetCalculator()->DistanceToTheNeutralFibre(q, p_fan); + LWSDBG(5, std::cout << "dti exit point: " << MSG_VECTOR(q) << " " + << dist_q << std::endl); + G4double dd = kInfinity; + if(dist_p * dist_q < 0.){// it certanly cross current half-wave + dd = in_iteration_process(p, dist_p, q, p_fan); + } + G4double d2 = search_for_nearest_point(p, dist_p, q, p_fan); + if(d2 < kInfinity){ + return distance + d2; // this half-wave is intersected + } else if(dd < kInfinity){ + return distance + dd; + } + return kInfinity; +} + +// This functions should be called in the case when we are sure that +// points p (which sould be OUTSIDE of vertical fan) and out_point have +// the surface of the vertical fan between them. +// returns distance from point p to absorber surface +// sets last parameter to the founded point +G4double LArWheelSliceSolid::in_iteration_process( + const G4ThreeVector &p, G4double dist_p, G4ThreeVector &B, int p_fan +) const +{ + LWSDBG(6, std::cout << "iip from " << p << " to " << B + << " dir " << (B - p).unit() + << std::endl); + + G4ThreeVector A, C, diff; + A = p; + G4double dist_c; + unsigned int niter = 0; + // assert(fabs(GetCalculator()->DistanceToTheNeutralFibre(A)) > m_FHTplusT); + // assert(GetCalculator()->DistanceToTheNeutralFibre(A) == dist_p); + do { + C = A + B; + C *= 0.5; + dist_c = GetCalculator()->DistanceToTheNeutralFibre(C, p_fan); + if(dist_c * dist_p < 0. || fabs(dist_c) < m_FHTminusT){ + B = C; + } else { + A = C; + } + niter ++; + diff = A - B; + } while(diff.mag2() > s_IterationPrecision2 && niter < s_IterationsLimit); + assert(niter < s_IterationsLimit); + assert(fabs(GetCalculator()->DistanceToTheNeutralFibre(B, p_fan)) < m_FHTplusT); + diff = p - B; + LWSDBG(7, std::cout << "iip result in " << niter << " = " << B + << " " << diff.mag() << std::endl); + return diff.mag(); +} + +// search for the nearest to the neutral fibre of the vertical fan point +// on the segment between p_in and p_out +G4double LArWheelSliceSolid::search_for_nearest_point( + const G4ThreeVector &p_in, const G4double dist_p_in, + const G4ThreeVector &p_out, int p_fan +) const +{ + LWSDBG(6, std::cout << "sfnp " << MSG_VECTOR(p_in) << " " + << MSG_VECTOR(p_out) << std::endl); + + G4ThreeVector A, B, C, l, diff; + A = p_in; + B = p_out; + diff = B - A; + l = diff.unit() * s_IterationPrecision; + // this is to correctly take the sign of the distance into account + G4double sign = dist_p_in < 0.? -1. : 1.; + G4double d_prime; + G4double dist_c; + unsigned long niter = 0; + do { + C = A + B; + C *= 0.5; + dist_c = GetCalculator()->DistanceToTheNeutralFibre(C, p_fan); + if(dist_c * sign <= 0.){ // we are in coditions for in_iteration_process + LWSDBG(7, std::cout << "sfnp0 " << dist_c << std::endl); + return in_iteration_process(p_in, dist_p_in, C, p_fan); + } + // calculate sign of derivative of distance to the neutral fibre + // hope this substitution is acceptable + diff = C - l; + d_prime = (dist_c - GetCalculator()->DistanceToTheNeutralFibre(diff, p_fan)) * sign; + if(d_prime < 0.) A = C; + else B = C; + niter ++; + diff = A - B; + } while(diff.mag2() > s_IterationPrecision2 && niter < s_IterationsLimit); + assert(niter < s_IterationsLimit); + if(fabs(dist_c) < m_FHTminusT){ + LWSDBG(7, std::cout << "sfnp1 " << dist_c << std::endl); + return in_iteration_process(p_in, dist_p_in, C, p_fan); + } + // let's check at p_in and p_out + if(dist_p_in * sign < dist_c * sign){ + C = p_in; + dist_c = dist_p_in; + } + G4double dist_p_out = GetCalculator()->DistanceToTheNeutralFibre(p_out, p_fan); + if(dist_p_out *sign < dist_c * sign) C = p_out; + if(fabs(dist_p_out) < m_FHTminusT){ + LWSDBG(7, std::cout << "sfnp2 " << dist_p_out << std::endl); + return in_iteration_process(p_in, dist_p_in, C, p_fan); + } + return kInfinity; +} + diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolidDisToOut.cxx b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolidDisToOut.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c64837128115ea2d08092ae3f282d7aa6f00f8fe --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolidDisToOut.cxx @@ -0,0 +1,206 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include <cassert> + +#include "GeoSpecialShapes/LArWheelCalculator.h" +#include "LArWheelSliceSolid.h" + +G4double LArWheelSliceSolid::DistanceToOut(const G4ThreeVector &inputP) const +{ + LWSDBG(1, std::cout << TypeStr() << " DisToOut" << MSG_VECTOR(inputP) << std::endl); + if(m_BoundingShape->Inside(inputP) != kInside){ + LWSDBG(2, std::cout << "DistanceToOut(p):" + << " point " << MSG_VECTOR(inputP) + << " is not inside of the m_BoundingShape." + << std::endl); + return 0.; + } + G4ThreeVector p(inputP); + int p_fan = 0; + const G4double d = m_FanHalfThickness - fabs(GetCalculator()->DistanceToTheNearestFan(p, p_fan)); + if(d < s_Tolerance){ + LWSDBG(2, std::cout << "already not inside " << MSG_VECTOR(p) << std::endl); + return 0.; + } + const G4double d0 = m_BoundingShape->DistanceToOut(inputP); + LWSDBG(2, std::cout << "dto " << d << " " << d0 << std::endl); + if(d > d0) return d0; + else return d; +} + +G4double LArWheelSliceSolid::DistanceToOut(const G4ThreeVector &inputP, + const G4ThreeVector &inputV, + const G4bool calcNorm, + G4bool* validNorm, + G4ThreeVector* sn) const +{ + LWSDBG(1, std::cout << TypeStr() << " DisToOut" << MSG_VECTOR(inputP) + << MSG_VECTOR(inputV) << std::endl); + + const EInside inside_BS = m_BoundingShape->Inside(inputP); + if(inside_BS == kOutside){ + LWSDBG(2, std::cout << "DistanceToOut(p):" + << " point " << MSG_VECTOR(inputP) + << " is outside of m_BoundingShape." << std::endl); + if(calcNorm) *validNorm = false; + return 0.; + } + + // If here inside or on surface of BS + G4ThreeVector p(inputP); + int p_fan = 0; + const G4double adtnf_p = fabs(GetCalculator()->DistanceToTheNearestFan(p, p_fan)); + if(adtnf_p >= m_FHTplusT) { + LWSDBG(2, std::cout << "DistanceToOut(p, v): point " + << MSG_VECTOR(inputP) + << " is outside of solid." << std::endl); + if(calcNorm) *validNorm = false; + return 0.; + } + + G4ThreeVector v(inputV); + const G4double phi0 = p.phi() - inputP.phi(); + v.rotateZ(phi0); + +// former distance_to_out starts here + LWSDBG(4, std::cout << "dto: " << MSG_VECTOR(p) << " " + << MSG_VECTOR(v) << std::endl); + + G4ThreeVector q(p); + + const G4double dto_bs = m_BoundingShape->DistanceToOut( + inputP, inputV, calcNorm, validNorm, sn + ); + q = p + v * dto_bs; + if(q.y() < m_Ymin){ + LWSDBG(5, std::cout << "dto exit point too low " << MSG_VECTOR(q) << std::endl); + const G4double dy = (m_Ymin - p.y()) / v.y(); + q.setX(p.x() + v.x() * dy); + q.setY(m_Ymin); + q.setZ(p.z() + v.z() * dy); + } + LWSDBG(5, std::cout << "dto exit point " << MSG_VECTOR(q) << std::endl); + + G4double tmp; + G4double distance = 0.; + if(fabs(GetCalculator()->DistanceToTheNeutralFibre(q, p_fan)) > m_FHTplusT){ + LWSDBG(5, std::cout << "q=" << MSG_VECTOR(q) + << " outside fan cur distance=" + << distance << ", m_FHTplusT=" + << m_FHTplusT << std::endl); + tmp = out_iteration_process(p, q, p_fan); + } else { + tmp = (q - p).mag(); + } + G4ThreeVector C; + if(search_for_most_remoted_point(p, q, C, p_fan)){ + tmp = out_iteration_process(p, C, p_fan); + } + distance += tmp; + + LWSDBG(5, std::cout << "At end_dto distance=" << distance << std::endl); + if(calcNorm && distance < dto_bs) *validNorm = false; + +#ifdef DEBUG_LARWHEELSLICESOLID + if(Verbose > 2){ + std::cout << "DTO: " << distance << " "; + if (*validNorm) { + std::cout << *validNorm << " " << MSG_VECTOR((*sn)); + } else { + std::cout << "Norm is not valid"; + } + std::cout << std::endl; + if(Verbose > 3){ + G4ThreeVector p2 = inputP + inputV * distance; + EInside i = Inside(p2); + std::cout << "DTO hit at " << MSG_VECTOR(p2) << ", " + << inside(i) << std::endl; + } + } +#ifdef LWS_HARD_TEST_DTO + if(test_dto(inputP, inputV, distance)){ + if(Verbose == 1){ + std::cout << TypeStr() << " DisToOut" << MSG_VECTOR(inputP) + << MSG_VECTOR(inputV) << std::endl; + } + } +#endif +#endif + return distance; +} + +// This functions should be called in the case when we are sure that +// point p is NOT OUTSIDE of vertical fan and point out is NOT INSIDE vertical fan +// returns distance from point p to fan surface, sets last +// parameter to the found point +// may give wrong answer - see description +G4double LArWheelSliceSolid::out_iteration_process(const G4ThreeVector &p, + G4ThreeVector &B, const int p_fan) const +{ + LWSDBG(6, std::cout << "oip: " << p << " " << B); + assert(fabs(GetCalculator()->DistanceToTheNeutralFibre(p, p_fan)) < m_FHTplusT); + assert(fabs(GetCalculator()->DistanceToTheNeutralFibre(B, p_fan)) > m_FHTminusT); + G4ThreeVector A(p), C, diff; + unsigned int niter = 0; + do { + C = A + B; + C *= 0.5; + if(fabs(GetCalculator()->DistanceToTheNeutralFibre(C, p_fan)) < m_FHTplusT){ + A = C; + } else { + B = C; + } + niter ++; + diff = A - B; + } while(diff.mag2() > s_IterationPrecision2 && niter < s_IterationsLimit); + assert(fabs(GetCalculator()->DistanceToTheNeutralFibre(B, p_fan)) > m_FHTplusT); + assert(niter < s_IterationsLimit); + diff = p - B; + LWSDBG(7, std::cout << " -> " << B << " " << diff.mag()); + LWSDBG(6, std::cout << std::endl); + return diff.mag(); +} + +// returns true if the point being outside vert. fan is found, also set C to +// that point in this case +// returns false if the whole track looks like being inside vert. fan +G4bool LArWheelSliceSolid::search_for_most_remoted_point( + const G4ThreeVector &a, const G4ThreeVector &b, G4ThreeVector &C, const int p_fan +) const +{ + LWSDBG(6, std::cout << "sfmrp " << a << " " << b << std::endl); + G4ThreeVector diff(b - a); + + if(diff.mag2() <= s_IterationPrecision2) return false; + G4ThreeVector A(a), B(b), l(diff.unit() * s_IterationPrecision); + // find the most remoted point on the line AB + // and check if it is outside vertical fan + // small vector along the segment AB + G4double d1, d2; + unsigned int niter = 0; + // searching for maximum of (GetCalculator()->DistanceToTheNeutralFibre)^2 along AB + do { + C = A + B; + C *= 0.5; + d1 = GetCalculator()->DistanceToTheNeutralFibre(C, p_fan); + if(fabs(d1) > m_FHTplusT){ + // here out_iteration_process gives the answer + LWSDBG(7, std::cout << "sfmrp -> " << C << " " << fabs(d1) + << " " << (C - a).unit() << " " + << (C - a).mag() << std::endl); + return true; + } + // sign of derivative + //d1 = GetCalculator()->DistanceToTheNeutralFibre(C + l); + d2 = GetCalculator()->DistanceToTheNeutralFibre(C - l, p_fan); + if(d1 * d1 - d2 * d2 > 0.) A = C; + else B = C; + niter ++; + diff = A - B; + } while(diff.mag2() > s_IterationPrecision2 && niter < s_IterationsLimit); + // the line entirely lies inside fan + assert(niter < s_IterationsLimit); + return false; +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolidInit.cxx b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolidInit.cxx new file mode 100644 index 0000000000000000000000000000000000000000..252ff49b421322ea3b08938fc02ab456abb255c7 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSliceSolidInit.cxx @@ -0,0 +1,283 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +*/ + +#include <cassert> +#include <stdexcept> +#include <iostream> + +#ifndef PORTABLE_LAR_SHAPE +#include "RDBAccessSvc/IRDBAccessSvc.h" +#include "RDBAccessSvc/IRDBRecord.h" +#include "RDBAccessSvc/IRDBRecordset.h" + +#include "GeoModelInterfaces/IGeoModelSvc.h" +#include "GeoModelInterfaces/IGeoDbTagSvc.h" +#include "GeoModelUtilities/DecodeVersionKey.h" +#include "GeoSpecialShapes/toEMECData.h" + + +#include "GaudiKernel/Bootstrap.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/IMessageSvc.h" +#endif + +#include "GeoSpecialShapes/EMECData.h" +#include "CLHEP/Units/PhysicalConstants.h" +#ifndef PORTABLE_LAR_SHAPE +#include "AthenaBaseComps/AthMsgStreamMacros.h" +#include "AthenaBaseComps/AthCheckMacros.h" +#endif +#include "G4GeometryTolerance.hh" + +#include "GeoSpecialShapes/LArWheelCalculator.h" +#include "LArWheelSliceSolid.h" +#include "G4ShiftedCone.h" + +#ifdef DEBUG_LARWHEELSLICESOLID +G4int LArWheelSliceSolid::Verbose = 0; +#endif + +// these are internal technical constants, should not go in DB +const unsigned int LArWheelSliceSolid::s_IterationsLimit = 50; // That's enough even for 10e-15 IterationPrecision +const G4double LArWheelSliceSolid::s_Tolerance = G4GeometryTolerance::GetInstance()->GetSurfaceTolerance() / 2; +const G4double LArWheelSliceSolid::s_AngularTolerance = G4GeometryTolerance::GetInstance()->GetAngularTolerance() / 2; +const G4double LArWheelSliceSolid::s_IterationPrecision = 0.001*CLHEP::mm; +const G4double LArWheelSliceSolid::s_IterationPrecision2 = s_IterationPrecision * s_IterationPrecision; + +LArWheelSliceSolid::LArWheelSliceSolid( + const G4String& name, + pos_t pos, type_t type, size_t slice, + G4int zside, + const LArWheelCalculator *calc, + const EMECData *emecData +) : G4VSolid(name), m_Pos(pos), m_Type(type), + m_Calculator(calc) +#ifndef PORTABLE_LAR_SHAPE + ,m_msg("LArWSS") +#endif +{ + createSolid(name, zside, slice, emecData); +} + +LArWheelSliceSolid::LArWheelSliceSolid(const G4String& name, const EMECData *emecData) + : G4VSolid(name), m_Calculator(0) +#ifndef PORTABLE_LAR_SHAPE + , m_msg("LArWSS") +#endif +{ + if(name.find("::Inner") != G4String::npos) m_Pos = Inner; + else if(name.find("::Outer") != G4String::npos) m_Pos = Outer; + else G4Exception( + "LArWheelSliceSolid", "NoPos", FatalException, + (std::string("Constructor: can't get Inner/Outer from ") + name).c_str() + ); + + if(name.find("::Absorber") != G4String::npos) m_Type = Absorber; + else if(name.find("::Electrode") != G4String::npos) m_Type = Electrode; + else if(name.find("::Glue") != G4String::npos) m_Type = Glue; + else if(name.find("::Lead") != G4String::npos) m_Type = Lead; + else G4Exception( + "LArWheelSliceSolid", "NoType", FatalException, + (std::string("Constructor: can't get Type from ") + name).c_str() + ); + + size_t s = name.find("Slice"); + size_t slice = 0; + if(G4String::npos != s){ + slice = (size_t) atoi(name.substr(s + 5, 2).c_str()); + } else G4Exception( + "LArWheelSliceSolid", "NoSlice", FatalException, + (std::string("Constructor: can't get Slice from ") + name).c_str() + ); + + G4int zside = 0; + if(name.find("::Pos::") != G4String::npos) zside = 1; + else if(name.find("::Neg::") != G4String::npos) zside = -1; + else G4Exception( + "LArWheelSliceSolid", "NoSide", FatalException, + (std::string("Constructor: can't get zSide from ") + name).c_str() + ); + createSolid(name, zside, slice, emecData); +} + +void LArWheelSliceSolid::createSolid(const G4String& name, G4int zside, size_t slice, const EMECData *emecData) +{ +#ifndef PORTABLE_LAR_SHAPE + m_f_area = m_f_vol = m_f_area_on_pc = m_f_length = m_f_side_area = 0; +#endif + + LArG4::LArWheelCalculator_t calc_type = LArG4::LArWheelCalculator_t(0); + switch(m_Pos){ + case Inner: + switch(m_Type){ + case Absorber: calc_type = LArG4::InnerAbsorberWheel; break; + case Electrode: calc_type = LArG4::InnerElectrodWheel; break; + case Glue: calc_type = LArG4::InnerGlueWheel; break; + case Lead: calc_type = LArG4::InnerLeadWheel; break; + } + break; + case Outer: + switch(m_Type){ + case Absorber: calc_type = LArG4::OuterAbsorberWheel; break; + case Electrode: calc_type = LArG4::OuterElectrodWheel; break; + case Glue: calc_type = LArG4::OuterGlueWheel; break; + case Lead: calc_type = LArG4::OuterLeadWheel; break; + } + break; + } + if(m_Calculator == 0) { + m_Calculator = new LArWheelCalculator(*emecData, calc_type, zside); + + } + else if(m_Calculator->type() != calc_type){ + G4Exception( + "LArWheelSliceSolid", "WrongCalculatorType", FatalException, + "Constructor: external LArWheelCalculator of wrong type provided" + ); + } + + const G4String bs_name = name + "-Bounding"; + +#ifdef DEBUG_LARWHEELSLICESOLID + const char *venv = getenv("LARWHEELSLICESOLID_VERBOSE"); + if(venv) Verbose = atoi(venv); + static bool first = true; + if(first){ + std::cout << "The LArWheelSliceSolid build " + << __DATE__ << " " << __TIME__ << std::endl + << "LArWheelSliceSolid verbosity level is " + << Verbose << std::endl; + first = false; + } +#endif + + m_FanHalfThickness = GetCalculator()->GetFanHalfThickness(); + m_FHTplusT = m_FanHalfThickness + s_Tolerance; + m_FHTminusT = m_FanHalfThickness - s_Tolerance; + + switch(m_Pos){ + case Inner: inner_solid_init(bs_name, slice); break; + case Outer: outer_solid_init(bs_name, slice); break; + } +#ifndef PORTABLE_LAR_SHAPE + ATH_MSG_DEBUG(m_BoundingShape->GetName() + " is the m_BoundingShape"); + + init_tests(); + test(); // activated by env. variable + clean_tests(); + + ATH_MSG_DEBUG("slice " << m_Pos << " " << m_Type + << " " << slice << " initialized" << endmsg); + +#endif + + #ifdef DEBUG_LARWHEELSLICESOLID + std::cout << "LArWSS(" << m_Pos << ", " << m_Type + << "): slice " << slice << ", Zmin = " << m_Zmin + << ", Zmax = " << m_Zmax << std::endl + << GetName() << std::endl; +#endif +} + +inline void LArWheelSliceSolid::check_slice(size_t size, size_t slice) const +{ + if(size <= slice + 1){ + G4Exception( + "LArWheelSliceSolid", "WrongSlice", FatalException, + std::string("Constructor: Slice number too big: " + GetName()).c_str() + ); + } +} + +void LArWheelSliceSolid::inner_solid_init(const G4String &bs_name, size_t slice) +{ + G4double zPlane[2], rInner[2], rOuter[2]; + zPlane[0] = 0.; + zPlane[1] = GetCalculator()->GetWheelThickness(); + GetCalculator()->GetWheelInnerRadius(rInner); + GetCalculator()->GetWheelOuterRadius(rOuter); + + std::vector<G4double> zsect; + fill_zsect(zsect); + check_slice(zsect.size(), slice); + + m_Zmin = zsect[slice]; m_Zmax = zsect[slice + 1]; + m_Rmin = rInner[0]; m_Rmax = rOuter[1]; + const G4double ainn = (rInner[1] - rInner[0]) / (zPlane[1] - zPlane[0]); + const G4double aout = (rOuter[1] - rOuter[0]) / (zPlane[1] - zPlane[0]); + const G4double R1inn = ainn * (m_Zmin - zPlane[0]) + rInner[0]; + const G4double R1out = aout * (m_Zmin - zPlane[0]) + rOuter[0]; + const G4double R2inn = ainn * (m_Zmax - zPlane[0]) + rInner[0]; + const G4double R2out = aout * (m_Zmax - zPlane[0]) + rOuter[0]; + + m_BoundingShape = new G4ShiftedCone( + bs_name + "Cone", m_Zmin, m_Zmax, R1inn, R1out, R2inn, R2out + ); + + const G4double FanPhiAmplitude = 0.065; // internal technical constant, should not go in DB + const G4double phi_min = CLHEP::halfpi + - FanPhiAmplitude + - GetCalculator()->GetFanStepOnPhi() * 2; + m_Xmax = rOuter[1]*cos(phi_min); + m_Xmin = -m_Xmax; + + m_Ymin = m_Rmin * 0.9; +} + +void LArWheelSliceSolid::outer_solid_init(const G4String &bs_name, size_t slice) +{ + G4double zPlane[3], rInner[3], rOuter[3]; + zPlane[0] = 0.; + zPlane[1] = GetCalculator()->GetWheelInnerRadius(rInner); + zPlane[2] = GetCalculator()->GetWheelThickness(); + GetCalculator()->GetWheelOuterRadius(rOuter); + + std::vector<G4double> zsect; + fill_zsect(zsect, zPlane[1]); + check_slice(zsect.size(), slice); + + m_Zmin = zsect[slice]; m_Zmax = zsect[slice + 1]; + m_Rmin = rInner[0]; m_Rmax = rOuter[1]; + const size_t i = m_Zmax > zPlane[1]? 1: 0; + const G4double dz = zPlane[i + 1] - zPlane[i]; + const G4double ainn = (rInner[i + 1] - rInner[i]) / dz; + const G4double aout = (rOuter[i + 1] - rOuter[i]) / dz; + const G4double R1inn = ainn * (m_Zmin - zPlane[i]) + rInner[i]; + const G4double R1out = aout * (m_Zmin - zPlane[i]) + rOuter[i]; + const G4double R2inn = ainn * (m_Zmax - zPlane[i]) + rInner[i]; + const G4double R2out = aout * (m_Zmax - zPlane[i]) + rOuter[i]; + + m_BoundingShape = new G4ShiftedCone( + bs_name + "Cone", m_Zmin, m_Zmax, R1inn, R1out, R2inn, R2out + ); + + const G4double FanPhiAmplitude = 0.02; // internal technical constant, should not go in DB + const G4double phi_min = CLHEP::halfpi + - FanPhiAmplitude + - GetCalculator()->GetFanStepOnPhi() * 2; + m_Xmax = rOuter[1]*cos(phi_min); + m_Xmin = -m_Xmax; + + m_Ymin = m_Rmin * 0.9; +} + +void LArWheelSliceSolid::fill_zsect(std::vector<G4double> &zsect, G4double zMid) const +{ + const G4double half_wave_length = GetCalculator()->GetHalfWaveLength(); + const G4double sss = GetCalculator()->GetStraightStartSection(); + const G4int num_fs = GetCalculator()->GetNumberOfHalfWaves() + 1; + const G4double wheel_thickness = GetCalculator()->GetWheelThickness(); + + zsect.push_back(0.); + zsect.push_back(sss + half_wave_length * 0.25); + for(G4int i = 2; i < num_fs; i ++){ + const G4double zi = half_wave_length * (i - 1) + sss; + if(m_Pos == Outer && zsect.back() < zMid && zi > zMid){ + zsect.push_back(zMid); + } + zsect.push_back(zi); + } + zsect.push_back(wheel_thickness - sss - half_wave_length * 0.25); + zsect.push_back(wheel_thickness); +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSolid.cxx b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSolid.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a0224fed57ef4690083d182b3a6f70f6d222a7a9 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSolid.cxx @@ -0,0 +1,170 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "G4VGraphicsScene.hh" +#include "G4VisExtent.hh" + +#include "GeoSpecialShapes/LArWheelCalculator.h" +#include "LArWheelSolid.h" + +class G4NURBS; +class G4VoxelLimits; +class G4AffineTransform; + +EInside LArWheelSolid::Inside(const G4ThreeVector &inputP) const +{ + LWSDBG(10, std::cout << std::setprecision(25)); + LWSDBG(1, std::cout << TypeStr() << " Inside " << MSG_VECTOR(inputP) << std::endl); + const EInside inside_BS = m_BoundingShape->Inside(inputP); + if(inside_BS == kOutside){ + LWSDBG(2, std::cout << "outside BS" << std::endl); + return kOutside; + } + G4ThreeVector p( inputP ); + int p_fan = 0; + const G4double d = fabs(GetCalculator()->DistanceToTheNearestFan(p, p_fan)); + if(d > m_FHTplusT){ + LWSDBG(2, std::cout << "outside fan d=" << d << ", m_FHTplusT=" << m_FHTplusT << std::endl); + return kOutside; + } + if(d < m_FHTminusT){ + LWSDBG(2, std::cout << "inside fan d=" << d << ", m_FHTminusT=" << m_FHTminusT << ", inside_BS=" << inside(inside_BS) << std::endl); + return inside_BS; + } + LWSDBG(2, std::cout << "surface" << std::endl); + return kSurface; +} + +G4ThreeVector LArWheelSolid::SurfaceNormal(const G4ThreeVector &inputP) const +{ + LWSDBG(1, std::cout << TypeStr() << " SurfaceNormal" << MSG_VECTOR(inputP) << std::endl); + EInside inside_BS = m_BoundingShape->Inside(inputP); + if(inside_BS != kInside){ + LWSDBG(2, std::cout << "not inside BS" << std::endl); + return m_BoundingShape->SurfaceNormal(inputP); + } + G4ThreeVector p( inputP ); + int p_fan = 0; + GetCalculator()->DistanceToTheNearestFan(p, p_fan); + G4ThreeVector d = GetCalculator()->NearestPointOnNeutralFibre(p, p_fan); + d.rotateZ(inputP.phi() - p.phi()); // rotate back to initial position + LWSDBG(4, std::cout << "npnf" << MSG_VECTOR(d) << std::endl); + p = inputP - d; + LWSDBG(2, std::cout << "sn " << MSG_VECTOR(p.unit()) << std::endl); + return(p.unit()); +} + +G4bool LArWheelSolid::CalculateExtent(const EAxis a, const G4VoxelLimits &vl, + const G4AffineTransform &t, G4double &p, + G4double &q) const +{ + return m_BoundingShape->CalculateExtent(a, vl, t, p, q); +} + +G4GeometryType LArWheelSolid::GetEntityType() const +{ + switch(m_Type){ + case InnerAbsorberWheel: + return G4String("LArInnerAbsorberWheel"); + break; + case OuterAbsorberWheel: + return G4String("LArOuterAbsorberWheel"); + break; + case InnerElectrodWheel: + return G4String("LArInnerElecrodWheel"); + break; + case OuterElectrodWheel: + return G4String("LArOuterElecrodWheel"); + break; + case InnerAbsorberModule: + return G4String("LArInnerAbsorberModule"); + break; + case OuterAbsorberModule: + return G4String("LArOuterAbsorberModule"); + break; + case InnerElectrodModule: + return G4String("LArInnerElecrodModule"); + break; + case OuterElectrodModule: + return G4String("LArOuterElecrodModule"); + break; + case InnerGlueWheel: + return G4String("LArInnerGlueWheel"); + break; + case OuterGlueWheel: + return G4String("LArOuterGlueWheel"); + break; + case InnerLeadWheel: + return G4String("LArInnerLeadWheel"); + break; + case OuterLeadWheel: + return G4String("LArOuterLeadWheel"); + break; + case InnerAbsorberCone: + return G4String("LArInnerAbsorberCone"); + break; + case InnerElectrodCone: + return G4String("LArInnerElectrodCone"); + break; + case InnerGlueCone: + return G4String("LArInnerGlueCone"); + break; + case InnerLeadCone: + return G4String("LArInnerLeadCone"); + break; + case OuterAbsorberFrontCone: + return G4String("LArOuterAbsorberFrontCone"); + break; + case OuterElectrodFrontCone: + return G4String("LArOuterElectrodFrontCone"); + break; + case OuterGlueFrontCone: + return G4String("LArOuterGlueFrontCone"); + break; + case OuterLeadFrontCone: + return G4String("LArOuterLeadFrontCone"); + break; + case OuterAbsorberBackCone: + return G4String("LArOuterAbsorberBackCone"); + break; + case OuterElectrodBackCone: + return G4String("LArOuterElectrodBackCone"); + break; + case OuterGlueBackCone: + return G4String("LArOuterGlueBackCone"); + break; + case OuterLeadBackCone: + return G4String("LArOuterLeadBackCone"); + break; + default: + G4Exception("LArWheelSolid", "UnknownSolidType", FatalException,"GetEntityType: Unknown LArWheelType."); + } + return G4String(""); +} + +void LArWheelSolid::DescribeYourselfTo(G4VGraphicsScene &scene) const +{ + scene.AddSolid(*this); +} + +G4VisExtent LArWheelSolid::GetExtent() const +{ + return m_BoundingShape->GetExtent(); +} + +G4Polyhedron* LArWheelSolid::CreatePolyhedron() const +{ + return m_BoundingShape->CreatePolyhedron(); +} + +/* + * returns the number of lower z boundary of z-section containing Z + */ +G4int LArWheelSolid::select_section(const G4double &Z) const +{ + for(G4int i = m_Zsect_start_search; i > 0; -- i){ + if(Z > m_Zsect[i]) return i; + } + return 0; +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSolid.h b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSolid.h new file mode 100644 index 0000000000000000000000000000000000000000..f52005db4d015bbd507715f2a4ffcc5f9f1ca79c --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSolid.h @@ -0,0 +1,266 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef GEO2G4_LARWHEELSOLID_H +#define GEO2G4_LARWHEELSOLID_H +#ifndef PORTABLE_LAR_SHAPE +#include "AthenaKernel/MsgStreamMember.h" +#endif +#include "G4VSolid.hh" + +// set this to allow debug output in LArWheelSolid methods +// disabled by default to avoid any performance degradation +//#define DEBUG_LARWHEELSOLID + +// set this to use native G4 FanBound's methods for DisToIn +// instead of local calculations +//#define LARWHEELSOLID_USE_FANBOUND + +// set this to use BoundingShape's methods for DisToOut +// instead of local calculations +#define LARWHEELSOLID_USE_BS_DTO + +// change this to have more z sections +#define LARWHEELSOLID_ZSECT_MULT 1 + + +// set this to check in dti and dto functions if particle direction +// pointing inside or outside of volume to return zero fast when it is required by spec. +// currently at development stage, requires accurate surface normal calculations +//#define CHECK_DIRTONORM_ANGLE_ON_SURFACE + +#ifdef DEBUG_LARWHEELSOLID +#define LWSDBG(a, b) if(Verbose >= a) b +#define MSG_VECTOR(v) "(" << v.x() << ", " << v.y() << ", " << v.z() << ")" +//#define LWS_HARD_TEST_DTI +//#define LWS_HARD_TEST_DTO +#else +#define LWSDBG(a, b) +#endif + +// Forward declarations. +class G4VGraphicsScene; +class G4VisExtent; +class G4Polyhedron; +class G4NURBS; +class G4VoxelLimits; +class G4AffineTransform; +class G4Polycone; +class LArWheelCalculator; +class TF1; +class LArFanSections; +class G4Polyhedra; +struct EMECData; + +#include "LArWheelSolid_type.h" + +inline const char *LArWheelSolidTypeString(LArWheelSolid_t type) +{ + switch(type){ + case InnerAbsorberWheel: return("InnerAbsorberWheel"); + case OuterAbsorberWheel: return("OuterAbsorberWheel"); + case InnerElectrodWheel: return("InnerElectrodWheel"); + case OuterElectrodWheel: return("OuterElectrodWheel"); + case InnerAbsorberModule: return("InnerAbsorberModule"); + case OuterAbsorberModule: return("OuterAbsorberModule"); + case InnerElectrodModule: return("InnerElectrodModule"); + case OuterElectrodModule: return("OuterElectrodModule"); + case InnerLeadWheel: return("InnerLeadWheel"); + case OuterLeadWheel: return("OuterLeadWheel"); + case InnerGlueWheel: return("InnerGlueWheel"); + case OuterGlueWheel: return("OuterGlueWheel"); + case InnerAbsorberCone: return("InnerAbsorberCone"); + case InnerElectrodCone: return("InnerElectrodCone"); + case InnerGlueCone: return("InnerGlueCone"); + case InnerLeadCone: return("InnerLeadCone"); + case OuterAbsorberFrontCone: return("OuterAbsorberFrontCone"); + case OuterElectrodFrontCone: return("OuterElectrodFrontCone"); + case OuterGlueFrontCone: return("OuterGlueFrontCone"); + case OuterLeadFrontCone: return("OuterLeadFrontCone"); + case OuterAbsorberBackCone: return("OuterAbsorberBackCone"); + case OuterElectrodBackCone: return("OuterElectrodBackCone"); + case OuterGlueBackCone: return("OuterGlueBackCone"); + case OuterLeadBackCone: return("OuterLeadBackCone"); + } + return("unknown"); +} + +class LArWheelSolid : public G4VSolid +{ +public: + + LArWheelSolid(const G4String& name, LArWheelSolid_t type, + G4int zside = 1, + LArWheelCalculator *calc = 0, + const EMECData *emecData=0 + ); + virtual ~LArWheelSolid(); + + // Mandatory for custom solid Geant4 functions + EInside Inside(const G4ThreeVector&) const; + G4double DistanceToIn(const G4ThreeVector&, + const G4ThreeVector&) const; + G4double DistanceToIn(const G4ThreeVector&) const; + G4double DistanceToOut(const G4ThreeVector&, + const G4ThreeVector&, + const G4bool calcNorm = false, + G4bool* validNorm = 0, + G4ThreeVector* n = 0) const; + G4double DistanceToOut(const G4ThreeVector&) const; + G4ThreeVector SurfaceNormal (const G4ThreeVector&) const; + G4bool CalculateExtent(const EAxis, + const G4VoxelLimits&, + const G4AffineTransform&, + G4double&, + G4double&) const; + G4GeometryType GetEntityType() const; + void DescribeYourselfTo(G4VGraphicsScene&) const; + G4VisExtent GetExtent() const; + G4Polyhedron* CreatePolyhedron() const; + + // 07-Feb-2003 WGS: For compatibility with Geant 4.5.0 + virtual std::ostream& StreamInfo(std::ostream& os) const { return os; } + + const G4VSolid *GetBoundingShape(void) const { return m_BoundingShape; } + const LArWheelCalculator *GetCalculator(void) const { return m_Calculator; } + LArWheelSolid_t GetType(void) const { return m_Type; } + +#ifndef PORTABLE_LAR_SHAPE + G4ThreeVector GetPointOnSurface(void) const; + G4double GetCubicVolume(void); + G4double GetSurfaceArea(void); +#endif + +private: + static const G4double s_Tolerance; + static const G4double s_AngularTolerance; + static const G4double s_IterationPrecision; + static const G4double s_IterationPrecision2; + static const unsigned int s_IterationsLimit; + + G4bool m_IsOuter; + const LArWheelSolid_t m_Type; + LArWheelCalculator *m_Calculator; + G4double m_FanHalfThickness, m_FHTplusT, m_FHTminusT; + G4double m_FanPhiAmplitude; + G4double m_MinPhi; + G4double m_MaxPhi; + const G4double m_PhiPosition; + G4VSolid* m_BoundingShape; +#ifdef LARWHEELSOLID_USE_FANBOUND + G4VSolid* m_FanBound; +#endif + + std::vector<G4double> m_Zsect; + G4int m_Zsect_start_search; + + LArFanSections *m_fs; + + // z at outer wheel "bend" + G4double m_Zmid; + // Special limit, used in dto + G4double m_Ymin; + // limits for use in service functions + G4double m_Zmin, m_Zmax, m_Rmin, m_Rmax; + //artificial level to distinguish between inner and outer cones + G4double m_Ymid; + + void inner_solid_init(const G4String &); + void outer_solid_init(const G4String &); + void set_phi_size(void); + + virtual G4double distance_to_in(G4ThreeVector &, + const G4ThreeVector &, int) const; + G4double in_iteration_process(const G4ThreeVector &, + G4double, G4ThreeVector &, int) const; + G4double search_for_nearest_point(const G4ThreeVector &, const G4double, + const G4ThreeVector &, int) const; + G4bool search_for_most_remoted_point(const G4ThreeVector &, + const G4ThreeVector &, + G4ThreeVector &, const int) const; + G4double out_iteration_process(const G4ThreeVector &, + G4ThreeVector &, const int) const; + + typedef enum { + NoCross, ExitAtInner, ExitAtOuter, + ExitAtFront, ExitAtBack, ExitAtSide + } FanBoundExit_t; + + FanBoundExit_t find_exit_point(const G4ThreeVector &p, + const G4ThreeVector &v, + G4ThreeVector &q) const; + G4bool fs_cross_lower(const G4ThreeVector &p, const G4ThreeVector &v, + G4ThreeVector &q) const; + G4bool fs_cross_upper(const G4ThreeVector &p, const G4ThreeVector &v, + G4ThreeVector &q) const; + G4bool check_D(G4double &b, + G4double A, G4double B, G4double C, G4bool) const; + + G4int select_section(const G4double &Z) const; + +#ifndef PORTABLE_LAR_SHAPE + EInside Inside_accordion(const G4ThreeVector&) const; + void get_point_on_accordion_surface(G4ThreeVector &) const; + void get_point_on_polycone_surface(G4ThreeVector &) const; + void get_point_on_flat_surface(G4ThreeVector &) const; + void set_failover_point(G4ThreeVector &p, const char *m = 0) const; + + G4double get_area_on_polycone(void) const; + G4double get_area_on_face(void) const; + G4double get_area_on_side(void) const; + + G4double get_area_at_r(G4double r) const; + G4double get_length_at_r(G4double r) const; + + void test(void); + void clean_tests(void); + void init_tests(void); + /// Log a message using the Athena controlled logging system + MsgStream& msg( MSG::Level lvl ) const { return m_msg << lvl; } + /// Check whether the logging system is active at the provided verbosity level + bool msgLvl( MSG::Level lvl ) const { return m_msg.get().level() <= lvl; } +#endif + +protected: + /// Private message stream member +#ifndef PORTABLE_LAR_SHAPE + mutable Athena::MsgStreamMember m_msg; +#endif + + TF1 *m_f_area, *m_f_vol, *m_f_area_on_pc, *m_f_length, *m_f_side_area; + + double m_test_index; + friend double LArWheelSolid_fcn_area(double *, double *); + friend double LArWheelSolid_fcn_vol(double *, double *); + friend double LArWheelSolid_fcn_area_on_pc(double *, double *); + friend double LArWheelSolid_get_dl(double *, double *, G4int); + friend double LArWheelSolid_fcn_side_area(double *, double *); + +#ifdef DEBUG_LARWHEELSOLID + static const char* inside(EInside i) + { + switch(i){ + case kInside: return "inside"; break; + case kSurface: return "surface"; break; + case kOutside: return "outside"; break; + } + return "unknown"; + } + +public: + static G4int Verbose; + void SetVerbose(G4int v){ Verbose = v; } +#ifndef PORTABLE_LAR_SHAPE + G4bool test_dti(const G4ThreeVector &p, + const G4ThreeVector &v, const G4double distance) const; + G4bool test_dto(const G4ThreeVector &p, + const G4ThreeVector &v, const G4double distance) const; +#endif +private: + const char *TypeStr(void) const { return LArWheelSolidTypeString(m_Type); } +#endif +}; + +#endif // GEO2G4_LARWHEELSOLID_H + diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSolidDisToIn.cxx b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSolidDisToIn.cxx new file mode 100644 index 0000000000000000000000000000000000000000..74937cfe67c33209106d04234d1a64e36c99e1bb --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSolidDisToIn.cxx @@ -0,0 +1,325 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +*/ + +// DistanceToIn stuff for LArWheelSolid +#include <cassert> +#ifndef PORTABLE_LAR_SHAPE +#include "AthenaBaseComps/AthMsgStreamMacros.h" +#else +#endif +#include "CLHEP/Units/PhysicalConstants.h" + +#include "GeoSpecialShapes/LArWheelCalculator.h" +#include "LArWheelSolid.h" +#include "LArFanSection.h" + +G4double LArWheelSolid::DistanceToIn(const G4ThreeVector &inputP) const +{ + LWSDBG(1, std::cout << TypeStr() << " DisToIn" << MSG_VECTOR(inputP) << std::endl); + if(m_BoundingShape->Inside(inputP) == kOutside) { + // here is an approximation - for the point outside m_BoundingShape + // the solid looks like a m_BoundingShape + // it's okay since the result could be underestimated + LWSDBG(2, std::cout << "Outside BS" << std::endl); + return m_BoundingShape->DistanceToIn(inputP); + } + G4ThreeVector p(inputP); + + // + // DistanceToTheNearestFan: + // rotates point p to the localFan coordinates and returns fan number to out_fan_number parameter + // returns distance to fan as result + // + + int p_fan = 0; + const G4double d = fabs(GetCalculator()->DistanceToTheNearestFan(p, p_fan)); + if(d > m_FHTplusT){ + const G4double result = d - m_FanHalfThickness; + LWSDBG(2, std::cout << "dti result = " << result << std::endl); + return result; + } + LWSDBG(2, std::cout << "already inside, return 0" << MSG_VECTOR(p) << std::endl); + return 0.; +} + +G4double LArWheelSolid::DistanceToIn(const G4ThreeVector &inputP, + const G4ThreeVector &inputV) const +{ + LWSDBG(1, std::cout << TypeStr() << " DisToIn" << MSG_VECTOR(inputP) + << MSG_VECTOR(inputV) << std::endl); + + G4double distance = 0.; + const EInside inside_BS = m_BoundingShape->Inside(inputP); + G4ThreeVector p(inputP); + if(inside_BS == kOutside) { + distance = m_BoundingShape->DistanceToIn(inputP, inputV); + if(distance == kInfinity) { + LWSDBG(2, std::cout << "Infinity distance to m_BoundingShape" << MSG_VECTOR(inputP) << MSG_VECTOR(inputV) << std::endl); + return kInfinity; + } + p += inputV * distance; + assert(m_BoundingShape->Inside(p) != kOutside); + LWSDBG(2, std::cout << "shift" << MSG_VECTOR(inputP) << std::endl); + } + + const G4double phi0 = p.phi(); + int p_fan = 0; + const G4double d = GetCalculator()->DistanceToTheNearestFan(p, p_fan); + if(fabs(d) < m_FHTminusT){ + LWSDBG(2, std::cout << "already inside fan" << MSG_VECTOR(p) << std::endl); + // if initial point is on BS surface and inside fan volume it is a real surface + if(inside_BS == kSurface) { + LWSDBG(2, std::cout << "On BS surface" << std::endl); + return m_BoundingShape->DistanceToIn(inputP, inputV); + } + return distance; + } + G4ThreeVector v(inputV); + v.rotateZ(p.phi() - phi0); + + const G4double d0 = distance_to_in(p, v, p_fan); + distance += d0; + +#ifdef DEBUG_LARWHEELSOLID + if(Verbose > 2){ + if(Verbose > 3){ + std::cout << MSG_VECTOR(inputP) + << " " << MSG_VECTOR(inputV) << std::endl; + } + std::cout << "dti: " << d0 << ", DTI: " << distance << std::endl; + } + if(Verbose > 3){ + if(d0 < kInfinity){ + G4ThreeVector p2 = inputP + inputV*distance; + EInside i = Inside(p2); + std::cout << "DTI hit at dist. " << distance << ", point " + << MSG_VECTOR(p2) << ", " + << inside(i) << std::endl; + } else { + std::cout << "got infinity from dti" << std::endl; + } + } +#ifdef LWS_HARD_TEST_DTI + if(test_dti(inputP, inputV, distance)){ + if(Verbose == 1){ + std::cout << TypeStr() << " DisToIn" << MSG_VECTOR(inputP) + << MSG_VECTOR(inputV) << std::endl; + } + } + if(Verbose == 1){ + std::cout << TypeStr() << " DisToIn" << MSG_VECTOR(inputP) + << MSG_VECTOR(inputV) << " " << distance << std::endl; + } +#endif // ifdef LWS_HARD_TEST_DTI + +#endif // ifdef DEBUG_LARWHEELSOLID + + return distance; +} + +// This functions should be called in the case when we are sure that +// points p (which sould be OUTSIDE of vertical fan) and out_point have +// the surface of the vertical fan between them. +// returns distance from point p to absorber surface +// sets last parameter to the founded point +G4double LArWheelSolid::in_iteration_process( + const G4ThreeVector &p, G4double dist_p, G4ThreeVector &B, int p_fan +) const +{ + LWSDBG(6, std::cout << "iip from " << p << " to " << B + << " dir " << (B - p).unit() + << std::endl); + + G4ThreeVector A, C, diff; + A = p; + G4double dist_c; + unsigned int niter = 0; + // assert(fabs(GetCalculator()->DistanceToTheNeutralFibre(A)) > m_FHTplusT); + // assert(GetCalculator()->DistanceToTheNeutralFibre(A) == dist_p); + do { + C = A + B; + C *= 0.5; + dist_c = GetCalculator()->DistanceToTheNeutralFibre(C, p_fan); + if(dist_c * dist_p < 0. || fabs(dist_c) < m_FHTminusT){ + B = C; + } else { + A = C; + } + niter ++; + diff = A - B; + } while(diff.mag2() > s_IterationPrecision2 && niter < s_IterationsLimit); + assert(niter < s_IterationsLimit); + assert(fabs(GetCalculator()->DistanceToTheNeutralFibre(B, p_fan)) < m_FHTplusT); + diff = p - B; + LWSDBG(7, std::cout << "iip result in " << niter << " = " << B + << " " << diff.mag() << std::endl); + return diff.mag(); +} + +// search for the nearest to the neutral fibre of the vertical fan point +// on the segment between p_in and p_out +G4double LArWheelSolid::search_for_nearest_point( + const G4ThreeVector &p_in, const G4double dist_p_in, + const G4ThreeVector &p_out, int p_fan +) const +{ + LWSDBG(6, std::cout << "sfnp " << MSG_VECTOR(p_in) << " " + << MSG_VECTOR(p_out) << std::endl); + + G4ThreeVector A, B, C, l, diff; + A = p_in; + B = p_out; + diff = B - A; + l = diff.unit() * s_IterationPrecision; + // this is to correctly take the sign of the distance into account + G4double sign = dist_p_in < 0.? -1. : 1.; + G4double d_prime; + G4double dist_c; + unsigned long niter = 0; + do { + C = A + B; + C *= 0.5; + dist_c = GetCalculator()->DistanceToTheNeutralFibre(C, p_fan); + if(dist_c * sign <= 0.){ // we are in coditions for in_iteration_process + LWSDBG(7, std::cout << "sfnp0 " << dist_c << std::endl); + return in_iteration_process(p_in, dist_p_in, C, p_fan); + } + // calculate sign of derivative of distance to the neutral fibre + // hope this substitution is acceptable + diff = C - l; + d_prime = (dist_c - GetCalculator()->DistanceToTheNeutralFibre(diff, p_fan)) * sign; + if(d_prime < 0.) A = C; + else B = C; + niter ++; + diff = A - B; + } while(diff.mag2() > s_IterationPrecision2 && niter < s_IterationsLimit); + assert(niter < s_IterationsLimit); + if(fabs(dist_c) < m_FHTminusT){ + LWSDBG(7, std::cout << "sfnp1 " << dist_c << std::endl); + return in_iteration_process(p_in, dist_p_in, C, p_fan); + } + // let's check at p_in and p_out + if(dist_p_in * sign < dist_c * sign){ + C = p_in; + dist_c = dist_p_in; + } + G4double dist_p_out = GetCalculator()->DistanceToTheNeutralFibre(p_out, p_fan); + if(dist_p_out *sign < dist_c * sign) C = p_out; + if(fabs(dist_p_out) < m_FHTminusT){ + LWSDBG(7, std::cout << "sfnp2 " << dist_p_out << std::endl); + return in_iteration_process(p_in, dist_p_in, C, p_fan); + } + return kInfinity; +} + +G4double LArWheelSolid::distance_to_in(G4ThreeVector &p, const G4ThreeVector &v, int p_fan) const +{ + LWSDBG(4, std::cout << "dti: " << MSG_VECTOR(p) << " " + << MSG_VECTOR(v) << std::endl); + + G4double distance = 0.; +#ifdef LARWHEELSOLID_USE_FANBOUND + if(FanBound->Inside(p) == kOutside) { + const G4double d = FanBound->DistanceToIn(p, v); + p += v * d; + distance += d; + } +#else + if(p.x() > m_fs->xmax) { + if(v.x() >= 0.) return kInfinity; + const G4double b = (m_fs->xmax - p.x()) / v.x(); + const G4double y2 = p.y() + v.y() * b; + const G4double z2 = p.z() + v.z() * b; + p.set(m_fs->xmax, y2, z2); + distance += b; + } else if(p.x() < m_fs->xmin) { + if(v.x() <= 0.) return kInfinity; + const G4double b = (m_fs->xmin - p.x()) / v.x(); + const G4double y2 = p.y() + v.y() * b; + const G4double z2 = p.z() + v.z() * b; + p.set(m_fs->xmin, y2, z2); + distance += b; + } +#endif + +// here p is on surface of or inside the "FanBound", +// distance corrected, misses are accounted for + LWSDBG(5, std::cout << "dti corrected: " << MSG_VECTOR(p) << std::endl); + + G4double dist_p = GetCalculator()->DistanceToTheNeutralFibre(p, p_fan); + if(fabs(dist_p) < m_FHTminusT) { + LWSDBG(5, std::cout << "hit fan dist_p=" << dist_p << ", m_FHTminusT=" << m_FHTminusT << std::endl); + return distance; + } + +#ifdef CHECK_DIRTONORM_ANGLE_ON_SURFACE + if(fabs(dist_p) > m_FHTplusT) { + LWSDBG(5, std::cout << "outside fan dist_p=" << dist_p << ", m_FHTplusT=" << m_FHTplusT << std::endl); + } else { + LWSDBG(5, std::cout << "on fan surface dist_p=" << dist_p << ", m_FHTplusT=" << m_FHTplusT << ", m_FHTminusT=" << m_FHTminusT << std::endl); + + const G4ThreeVector d = GetCalculator()->NearestPointOnNeutralFibre(p, p_fan); + // check dot product between normal and v + if ( (p-d).cosTheta(v) < -AngularTolerance ) { + // direction "v" definitely pointing inside + // return 0.0, it should be in "distance" + return distance; + } + } +#endif + + G4ThreeVector q; +#ifdef LARWHEELSOLID_USE_FANBOUND + q = p + v * FanBound->DistanceToOut(p, v); +#else + find_exit_point(p, v, q); +#endif + + G4int start = select_section(p.z()); + G4int stop = select_section(q.z()); + G4int step = -1; + if(stop > start) { step = 1; start ++; stop ++; } + LWSDBG(5, std::cout << "dti sections " << start << " " << stop + << " " << step << std::endl); + G4ThreeVector p1; + for(G4int i = start; i != stop; i += step){ +// v.z() can't be 0, otherwise start == stop, so the exit point could be only +// at z border of the fan section + const G4double d1 = (m_Zsect[i] - p.z()) / v.z(); + const G4double x1 = p.x() + v.x() * d1, y1 = p.y() + v.y() * d1; + p1.set(x1, y1, m_Zsect[i]); + G4double dist_p1 = GetCalculator()->DistanceToTheNeutralFibre(p1, p_fan); + LWSDBG(5, std::cout << i << ">" << p << " " << dist_p << " " + << p1 << " " << dist_p1 << std::endl); + G4double dd = kInfinity; + if(dist_p * dist_p1 < 0.){// it certanly cross current half-wave + dd = in_iteration_process(p, dist_p, p1, p_fan); + } + G4double d2 = search_for_nearest_point(p, dist_p, p1, p_fan); + LWSDBG(6, std::cout << i << "> dd=" << dd << ", d2=" << d2 << ", distance=" << distance << std::endl); + if(d2 < kInfinity){ + return distance + d2; // this half-wave is intersected + } else if(dd < kInfinity){ + return distance + dd; + } + distance += d1; + p.set(x1, y1, m_Zsect[i]); + dist_p = dist_p1; + } + + G4double dist_q = GetCalculator()->DistanceToTheNeutralFibre(q, p_fan); + LWSDBG(5, std::cout << "dti exit point: " << MSG_VECTOR(q) << " " + << dist_q << std::endl); + G4double dd = kInfinity; + if(dist_p * dist_q < 0.){// it certanly cross current half-wave + dd = in_iteration_process(p, dist_p, q, p_fan); + } + G4double d2 = search_for_nearest_point(p, dist_p, q, p_fan); + if(d2 < kInfinity){ + return distance + d2; // this half-wave is intersected + } else if(dd < kInfinity){ + return distance + dd; + } + return kInfinity; +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSolidDisToOut.cxx b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSolidDisToOut.cxx new file mode 100644 index 0000000000000000000000000000000000000000..847a7c03f7213de8e607efd94e39248e36fa2320 --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSolidDisToOut.cxx @@ -0,0 +1,296 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <cassert> + +#include "GeoSpecialShapes/LArWheelCalculator.h" +#include "LArWheelSolid.h" +#include "LArFanSection.h" + +G4double LArWheelSolid::DistanceToOut(const G4ThreeVector &inputP) const +{ + LWSDBG(1, std::cout << TypeStr() << " DisToOut" << MSG_VECTOR(inputP) << std::endl); + if(m_BoundingShape->Inside(inputP) != kInside){ + LWSDBG(2, std::cout << "DistanceToOut(p):" + << " point " << MSG_VECTOR(inputP) + << " is not inside of the m_BoundingShape." + << std::endl); + return 0.; + } + G4ThreeVector p( inputP ); + int p_fan = 0; + const G4double d = m_FanHalfThickness - fabs(GetCalculator()->DistanceToTheNearestFan(p, p_fan)); + if(d < s_Tolerance){ + LWSDBG(2, std::cout << "already not inside " << MSG_VECTOR(p) << std::endl); + return 0.; + } + const G4double d0 = m_BoundingShape->DistanceToOut(inputP); + LWSDBG(2, std::cout << "dto " << d << " " << d0 << std::endl); + if(d > d0) return d0; + else return d; +} + +G4double LArWheelSolid::DistanceToOut(const G4ThreeVector &inputP, + const G4ThreeVector &inputV, + const G4bool calcNorm, + G4bool* validNorm, + G4ThreeVector* sn) const +{ + LWSDBG(1, std::cout << TypeStr() << " DisToOut" << MSG_VECTOR(inputP) + << MSG_VECTOR(inputV) << std::endl); + + const EInside inside_BS = m_BoundingShape->Inside(inputP); + if(inside_BS == kOutside){ + LWSDBG(2, std::cout << "DistanceToOut(p):" + << " point " << MSG_VECTOR(inputP) + << " is outside of m_BoundingShape." << std::endl); + if(calcNorm) *validNorm = false; + return 0.; + } + + // If here inside or on surface of BS + G4ThreeVector p(inputP); + int p_fan = 0; + const G4double adtnf_p = fabs(GetCalculator()->DistanceToTheNearestFan(p, p_fan)); + if(adtnf_p >= m_FHTplusT) { + LWSDBG(2, std::cout << "DistanceToOut(p, v): point " + << MSG_VECTOR(inputP) + << " is outside of solid." << std::endl); + if(calcNorm) *validNorm = false; + return 0.; + } + + G4ThreeVector v(inputV); + const G4double phi0 = p.phi() - inputP.phi(); + v.rotateZ(phi0); + +#ifdef CHECK_DIRTONORM_ANGLE_ON_SURFACE + if(adtnf_p < FHTminusT) { + LWSDBG(5, std::cout << "inside fan point " << MSG_VECTOR(inputP) << ", FHTminusT=" << FHTminusT << std::endl); + } else { + LWSDBG(5, std::cout << "on fan surface adtnf_p=" << adtnf_p << ", m_FHTplusT=" << m_FHTplusT << ", FHTminusT=" << FHTminusT << std::endl); + + const G4ThreeVector d = GetCalculator()->NearestPointOnNeutralFibre(p, p_fan); + // check dot product between normal and v + if ( (p-d).cosTheta(v) > AngularTolerance ) { + // direction "v" definitely pointing outside + // return 0.0 + return 0.; + } + } +#endif + +// former distance_to_out starts here + LWSDBG(4, std::cout << "dto: " << MSG_VECTOR(p) << " " + << MSG_VECTOR(v) << std::endl); + + G4ThreeVector q(p); +#ifdef LARWHEELSOLID_USE_BS_DTO + const G4double dto_bs = m_BoundingShape->DistanceToOut( + inputP, inputV, calcNorm, validNorm, sn + ); + q = p + v * dto_bs; + if(q.y() < m_Ymin){ + LWSDBG(5, std::cout << "dto exit point too low " << MSG_VECTOR(q) << std::endl); + const G4double dy = (m_Ymin - p.y()) / v.y(); + q.setX(p.x() + v.x() * dy); + q.setY(m_Ymin); + q.setZ(p.z() + v.z() * dy); + } +#else + FanBoundExit_t exit = find_exit_point(p, v, q); + LWSDBG(5, std::cout << "dto exit " << exit << std::endl); +#endif + LWSDBG(5, std::cout << "dto exit point " << MSG_VECTOR(q) << std::endl); + + G4double distance = 0.; + G4int start = select_section(p.z()); + G4int stop = select_section(q.z()); + G4int step = -1; + if(stop > start){ step = 1; start ++; stop ++; } + LWSDBG(5, std::cout << "dto sections " << start << " " << stop << " " << step << std::endl); + + G4double tmp; + G4ThreeVector p1, C; + + for(G4int i = start; i != stop; i += step){ + const G4double d1 = (m_Zsect[i] - p.z()) / v.z(); +// v.z() can't be 0, otherwise start == stop, so the exit point could be only +// at z border of the fan section + LWSDBG(5, std::cout << "at " << i << " dist to zsec = " << d1 << std::endl); + const G4double x1 = p.x() + v.x() * d1, y1 = p.y() + v.y() * d1; + p1.set(x1, y1, m_Zsect[i]); + const G4double dd = fabs(GetCalculator()->DistanceToTheNeutralFibre(p1, p_fan)); + if(dd > m_FHTplusT){ + tmp = out_iteration_process(p, p1, p_fan); + //while(search_for_most_remoted_point(p, out_section, C)){ + if(search_for_most_remoted_point(p, p1, C, p_fan)){ + tmp = out_iteration_process(p, C, p_fan); + } + distance += tmp; +#ifndef LARWHEELSOLID_USE_BS_DTO + exit = NoCross; +#endif + goto end_dto; + } + if(search_for_most_remoted_point(p, p1, C, p_fan)){ + distance += out_iteration_process(p, C, p_fan); +#ifndef LARWHEELSOLID_USE_BS_DTO + exit = NoCross; +#endif + goto end_dto; + } + distance += d1; + p.set(x1, y1, m_Zsect[i]); + } + + if(fabs(GetCalculator()->DistanceToTheNeutralFibre(q, p_fan)) > m_FHTplusT){ + LWSDBG(5, std::cout << "q=" << MSG_VECTOR(q) << " outside fan cur distance=" << distance << ", m_FHTplusT=" << m_FHTplusT << std::endl); + tmp = out_iteration_process(p, q, p_fan); +#ifndef LARWHEELSOLID_USE_BS_DTO + exit = NoCross; +#endif + } else { + tmp = (q - p).mag(); + } + //while(search_for_most_remoted_point(out, out1, C, p_fan)){ + if(search_for_most_remoted_point(p, q, C, p_fan)){ + tmp = out_iteration_process(p, C, p_fan); +#ifndef LARWHEELSOLID_USE_BS_DTO + exit = NoCross; +#endif + } + distance += tmp; +// former distance_to_out ends here + end_dto: + LWSDBG(5, std::cout << "At end_dto distance=" << distance << std::endl); +#ifdef LARWHEELSOLID_USE_BS_DTO + if(calcNorm && distance < dto_bs) *validNorm = false; +#else + if(calcNorm){ + LWSDBG(5, std::cout << "dto calc norm " << exit << std::endl); + switch(exit){ + case ExitAtBack: + sn->set(0., 0., 1.); + *validNorm = true; + break; + case ExitAtFront: + sn->set(0., 0., -1.); + *validNorm = true; + break; + case ExitAtOuter: + q.rotateZ(-phi0); + sn->set(q.x(), q.y(), 0.); + if(q.z() <= m_Zmid) sn->setZ(- q.perp() * m_fs->Amax); + sn->setMag(1.0); + *validNorm = true; + break; + default: + *validNorm = false; + break; + } + } +#endif + +#ifdef DEBUG_LARWHEELSOLID + if(Verbose > 2){ + std::cout << "DTO: " << distance << " "; + if (*validNorm) { + std::cout << *validNorm << " " << MSG_VECTOR((*sn)); + } else { + std::cout << "Norm is not valid"; + } + std::cout << std::endl; + if(Verbose > 3){ + G4ThreeVector p2 = inputP + inputV * distance; + EInside i = Inside(p2); + std::cout << "DTO hit at " << MSG_VECTOR(p2) << ", " + << inside(i) << std::endl; + } + } +#ifdef LWS_HARD_TEST_DTO + if(test_dto(inputP, inputV, distance)){ + if(Verbose == 1){ + std::cout << TypeStr() << " DisToOut" << MSG_VECTOR(inputP) + << MSG_VECTOR(inputV) << std::endl; + } + } +#endif +#endif + return distance; +} + +// This functions should be called in the case when we are sure that +// point p is NOT OUTSIDE of vertical fan and point out is NOT INSIDE vertical fan +// returns distance from point p to fan surface, sets last +// parameter to the found point +// may give wrong answer - see description +G4double LArWheelSolid::out_iteration_process(const G4ThreeVector &p, + G4ThreeVector &B, const int p_fan) const +{ + LWSDBG(6, std::cout << "oip: " << p << " " << B); + assert(fabs(GetCalculator()->DistanceToTheNeutralFibre(p, p_fan)) < m_FHTplusT); + assert(fabs(GetCalculator()->DistanceToTheNeutralFibre(B, p_fan)) > m_FHTminusT); + G4ThreeVector A(p), C, diff; + unsigned int niter = 0; + do { + C = A + B; + C *= 0.5; + if(fabs(GetCalculator()->DistanceToTheNeutralFibre(C, p_fan)) < m_FHTplusT){ + A = C; + } else { + B = C; + } + niter ++; + diff = A - B; + } while(diff.mag2() > s_IterationPrecision2 && niter < s_IterationsLimit); + assert(fabs(GetCalculator()->DistanceToTheNeutralFibre(B, p_fan)) > m_FHTplusT); + assert(niter < s_IterationsLimit); + diff = p - B; + LWSDBG(7, std::cout << " -> " << B << " " << diff.mag()); + LWSDBG(6, std::cout << std::endl); + return diff.mag(); +} + +// returns true if the point being outside vert. fan is found, also set C to +// that point in this case +// returns false if the whole track looks like being inside vert. fan +G4bool LArWheelSolid::search_for_most_remoted_point( + const G4ThreeVector &a, const G4ThreeVector &b, G4ThreeVector &C, const int p_fan +) const +{ + LWSDBG(6, std::cout << "sfmrp " << a << " " << b << std::endl); + G4ThreeVector diff(b - a); + + if(diff.mag2() <= s_IterationPrecision2) return false; + G4ThreeVector A(a), B(b), l(diff.unit() * s_IterationPrecision); + // find the most remoted point on the line AB + // and check if it is outside vertical fan + // small vector along the segment AB + G4double d1, d2; + unsigned int niter = 0; + // searching for maximum of (GetCalculator()->DistanceToTheNeutralFibre)^2 along AB + do { + C = A + B; + C *= 0.5; + d1 = GetCalculator()->DistanceToTheNeutralFibre(C, p_fan); + if(fabs(d1) > m_FHTplusT){ + // here out_iteration_process gives the answer + LWSDBG(7, std::cout << "sfmrp -> " << C << " " << fabs(d1) + << " " << (C - a).unit() << " " + << (C - a).mag() << std::endl); + return true; + } + // sign of derivative + //d1 = GetCalculator()->DistanceToTheNeutralFibre(C + l); + d2 = GetCalculator()->DistanceToTheNeutralFibre(C - l, p_fan); + if(d1 * d1 - d2 * d2 > 0.) A = C; + else B = C; + niter ++; + diff = A - B; + } while(diff.mag2() > s_IterationPrecision2 && niter < s_IterationsLimit); + // the line entirely lies inside fan + assert(niter < s_IterationsLimit); + return false; +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSolidInit.cxx b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSolidInit.cxx new file mode 100644 index 0000000000000000000000000000000000000000..3055281847d5e30fa53a74391e781c21a4b0fdda --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSolidInit.cxx @@ -0,0 +1,403 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +*/ + +#include <cassert> +#include <stdexcept> +#include <iostream> + + +#include "GeoSpecialShapes/EMECData.h" + +#include "CLHEP/Units/PhysicalConstants.h" +#include "G4GeometryTolerance.hh" +#include "G4Polycone.hh" + +#include "GeoSpecialShapes/LArWheelCalculator.h" +#include "LArWheelSolid.h" +#include "LArFanSection.h" +#include "G4ShiftedCone.h" + +#ifndef PORTABLE_LAR_SHAPE +#include "AthenaBaseComps/AthMsgStreamMacros.h" +#endif + +#ifdef DEBUG_LARWHEELSOLID +G4int LArWheelSolid::Verbose = 0; +#endif + +// these are internal technical constants, should not go in DB +const unsigned int LArWheelSolid::s_IterationsLimit = 50; // That's enough even for 10e-15 IterationPrecision +const G4double LArWheelSolid::s_Tolerance = G4GeometryTolerance::GetInstance()->GetSurfaceTolerance() / 2; +const G4double LArWheelSolid::s_AngularTolerance = G4GeometryTolerance::GetInstance()->GetAngularTolerance() / 2; +const G4double LArWheelSolid::s_IterationPrecision = 0.001*CLHEP::mm; +const G4double LArWheelSolid::s_IterationPrecision2 = s_IterationPrecision * s_IterationPrecision; + +LArWheelSolid::LArWheelSolid(const G4String& name, LArWheelSolid_t type, + G4int zside, + LArWheelCalculator *calc, + const EMECData *emecData + ) + : G4VSolid(name), m_Type(type), m_Calculator(calc), m_PhiPosition(CLHEP::halfpi), m_fs(0) +#ifndef PORTABLE_LAR_SHAPE + , m_msg("LArWheelSolid") +#endif +{ +#ifndef PORTABLE_LAR_SHAPE +#ifdef LARWHEELSOLID_USE_FANBOUND + ATH_MSG_INFO ( "compiled with G4 FanBound" ); +#else + ATH_MSG_INFO ( "compiled with private find_exit_point" ); +#endif +#endif + + LArG4::LArWheelCalculator_t calc_type = LArG4::LArWheelCalculator_t(0); + switch(m_Type){ + case InnerAbsorberWheel: + calc_type = LArG4::InnerAbsorberWheel; + break; + case OuterAbsorberWheel: + calc_type = LArG4::OuterAbsorberWheel; + break; + case InnerElectrodWheel: + calc_type = LArG4::InnerElectrodWheel; + break; + case OuterElectrodWheel: + calc_type = LArG4::OuterElectrodWheel; + break; + case InnerAbsorberModule: + calc_type = LArG4::InnerAbsorberModule; + break; + case OuterAbsorberModule: + calc_type = LArG4::OuterAbsorberModule; + break; + case InnerElectrodModule: + calc_type = LArG4::InnerElectrodModule; + break; + case OuterElectrodModule: + calc_type = LArG4::OuterElectrodModule; + break; + case InnerGlueWheel: + calc_type = LArG4::InnerGlueWheel; + break; + case OuterGlueWheel: + calc_type = LArG4::OuterGlueWheel; + break; + case InnerLeadWheel: + calc_type = LArG4::InnerLeadWheel; + break; + case OuterLeadWheel: + calc_type = LArG4::OuterLeadWheel; + break; + case InnerAbsorberCone: + calc_type = LArG4::InnerAbsorberWheel; + break; + case InnerElectrodCone: + calc_type = LArG4::InnerElectrodWheel; + break; + case InnerGlueCone: + calc_type = LArG4::InnerGlueWheel; + break; + case InnerLeadCone: + calc_type = LArG4::InnerLeadWheel; + break; + case OuterAbsorberFrontCone: + calc_type = LArG4::OuterAbsorberWheel; + break; + case OuterElectrodFrontCone: + calc_type = LArG4::OuterElectrodWheel; + break; + case OuterGlueFrontCone: + calc_type = LArG4::OuterGlueWheel; + break; + case OuterLeadFrontCone: + calc_type = LArG4::OuterLeadWheel; + break; + case OuterAbsorberBackCone: + calc_type = LArG4::OuterAbsorberWheel; + break; + case OuterElectrodBackCone: + calc_type = LArG4::OuterElectrodWheel; + break; + case OuterGlueBackCone: + calc_type = LArG4::OuterGlueWheel; + break; + case OuterLeadBackCone: + calc_type = LArG4::OuterLeadWheel; + break; + default: + G4Exception("LArWheelSolid", "UnknownSolidType", FatalException, + "Constructor: unknown LArWheelSolid_t"); + } + + if(m_Calculator == 0) m_Calculator = new LArWheelCalculator(*emecData,calc_type, zside); + + const G4String bs_name = name + "-Bounding"; +#ifdef DEBUG_LARWHEELSOLID + const char *venv = getenv("LARWHEELSOLID_VERBOSE"); + if(venv) Verbose = atoi(venv); + std::cout << "The LArWheelSolid build " << __DATE__ << " " << __TIME__ + << std::endl; + std::cout << "LArWheelSolid verbosity level is " << Verbose << std::endl; +#endif + + // Initialize code that depends on wheel type: + m_FanHalfThickness = GetCalculator()->GetFanHalfThickness(); + m_FHTplusT = m_FanHalfThickness + s_Tolerance; + m_FHTminusT = m_FanHalfThickness - s_Tolerance; + switch(m_Type){ + case InnerAbsorberWheel: + case InnerElectrodWheel: + case InnerAbsorberModule: + case InnerElectrodModule: + case InnerGlueWheel: + case InnerLeadWheel: + case InnerAbsorberCone: + case InnerElectrodCone: + case InnerGlueCone: + case InnerLeadCone: + inner_solid_init(bs_name); + break; + case OuterAbsorberWheel: + case OuterElectrodWheel: + case OuterAbsorberModule: + case OuterElectrodModule: + case OuterGlueWheel: + case OuterLeadWheel: + case OuterAbsorberFrontCone: + case OuterElectrodFrontCone: + case OuterGlueFrontCone: + case OuterLeadFrontCone: + case OuterAbsorberBackCone: + case OuterElectrodBackCone: + case OuterGlueBackCone: + case OuterLeadBackCone: + outer_solid_init(bs_name); + break; + default: + G4Exception("LArWheelSolid", "UnknownSolidType", FatalException, + "Constructor: unknown LArWheelSolid_t"); + } + + m_Zsect_start_search = (m_Zsect.size() - 1) - 1; +#ifndef PORTABLE_LAR_SHAPE + init_tests(); + test(); // activated by env. variable + clean_tests(); +#endif + +#ifdef DEBUG_LARWHEELSOLID + m_fs->print(); + std::cout << "Limits: (" << m_Zsect.size() << ")" << std::endl; + for(size_t i = 0; i < m_Zsect.size(); ++ i){ + std::cout << i << " " << m_Zsect[i] << std::endl; + } +#endif +#ifndef PORTABLE_LAR_SHAPE + ATH_MSG_DEBUG ( "solid of type " + << LArWheelCalculator::LArWheelCalculatorTypeString(calc_type) + << " initialized" ); +#endif +} + +LArWheelSolid::~LArWheelSolid() +{ + if(m_fs) delete m_fs; +} + +// initialization of inner Absorber or Electrod wheels +void LArWheelSolid::inner_solid_init(const G4String &bs_name) +{ + m_IsOuter = false; + m_FanPhiAmplitude = 0.065; // internal technical constant, should not go in DB + set_phi_size(); + + G4double zPlane[2], rInner[2], rOuter[2]; + zPlane[0] = 0.; + zPlane[1] = GetCalculator()->GetWheelThickness(); + G4double wheel_thickness = zPlane[1] - zPlane[0]; + GetCalculator()->GetWheelInnerRadius(rInner); + GetCalculator()->GetWheelOuterRadius(rOuter); + const G4double phi_min = m_PhiPosition - m_FanPhiAmplitude + - GetCalculator()->GetFanStepOnPhi() * 2; + + m_Zmin = zPlane[0]; m_Zmax = zPlane[1]; + m_Rmin = rInner[0]; m_Rmax = rOuter[1]; + m_Ymin = m_Rmin * 0.9; + m_Zmid = zPlane[1]; + m_Ymid = (rInner[0] + rOuter[1]) * 0.5; + + if(m_Type == InnerAbsorberCone + || m_Type == InnerElectrodCone + || m_Type == InnerGlueCone + || m_Type == InnerLeadCone + ){ + m_BoundingShape = new G4ShiftedCone( + bs_name + "Cone", zPlane[0], zPlane[1], + rInner[0], rOuter[0], rInner[1], rOuter[1] + ); + } else { + m_BoundingShape = new G4Polycone( + bs_name + "Polycone", m_MinPhi, m_MaxPhi - m_MinPhi, + 2, zPlane, rInner, rOuter + ); + } +#ifdef LARWHEELSOLID_USE_FANBOUND + const G4double phi_size = (m_FanPhiAmplitude + GetCalculator()->GetFanStepOnPhi() * 2) * 2; + FanBound = new G4Polycone(bs_name + "ofFan", phi_min, phi_size, + 2, zPlane, rInner, rOuter); +#endif +#ifndef PORTABLE_LAR_SHAPE + ATH_MSG_INFO(m_BoundingShape->GetName() + " is the m_BoundingShape"); +#endif + + const G4double half_wave_length = GetCalculator()->GetHalfWaveLength(); + const G4double sss = GetCalculator()->GetStraightStartSection(); + m_Zsect.push_back(0.); + m_Zsect.push_back(sss + half_wave_length * 0.25); + const G4int num_fs = GetCalculator()->GetNumberOfHalfWaves() + 1; + for(G4int i = 2; i < num_fs; i ++){ + const G4double zi = half_wave_length * (i - 1) + sss; +#if LARWHEELSOLID_ZSECT_MULT > 1 + for(G4int j = LARWHEELSOLID_ZSECT_MULT - 1; j > 0; -- j){ + m_Zsect.push_back(zi - half_wave_length * j / LARWHEELSOLID_ZSECT_MULT); + } +#endif + m_Zsect.push_back(zi); + } + m_Zsect.push_back(wheel_thickness - m_Zsect[1]); + m_Zsect.push_back(wheel_thickness - m_Zsect[0]); + + m_fs = new LArFanSections( + rInner[0], rInner[1], rOuter[0], rOuter[1], + m_Rmax*cos(phi_min), m_Zsect.front(), m_Zsect.back() + ); +} + +// initialization of outer Absorber or Electrod wheels +void LArWheelSolid::outer_solid_init(const G4String &bs_name) +{ + m_IsOuter = true; + m_FanPhiAmplitude = 0.02; // internal technical constant, should not go in DB + set_phi_size(); + + G4double zPlane[3], rInner[3], rOuter[3]; + zPlane[0] = 0.; + zPlane[2] = GetCalculator()->GetWheelThickness(); + G4double wheel_thickness = zPlane[2] - zPlane[0]; + zPlane[1] = GetCalculator()->GetWheelInnerRadius(rInner); + GetCalculator()->GetWheelOuterRadius(rOuter); + const G4double phi_min = + m_PhiPosition - m_FanPhiAmplitude - + GetCalculator()->GetFanStepOnPhi() * 2; + + m_Zmid = zPlane[1]; + m_Ymid = (rInner[0] + rOuter[2]) * 0.5; + + bool hasFrontSections = false; + bool hasBackSections = false; + if(m_Type == OuterAbsorberFrontCone + || m_Type == OuterElectrodFrontCone + || m_Type == OuterGlueFrontCone + || m_Type == OuterLeadFrontCone + ){ + m_Zmin = zPlane[0]; m_Zmax = zPlane[1]; + m_Rmin = rInner[0]; m_Rmax = rOuter[1]; + m_BoundingShape = new G4ShiftedCone( + bs_name + "FrontCone", zPlane[0], zPlane[1], + rInner[0], rOuter[0], rInner[1], rOuter[1] + ); + hasFrontSections = true; + } else if(m_Type == OuterAbsorberBackCone + || m_Type == OuterElectrodBackCone + || m_Type == OuterGlueBackCone + || m_Type == OuterLeadBackCone + ){ + m_Zmin = zPlane[1]; m_Zmax = zPlane[2]; + m_Rmin = rInner[1]; m_Rmax = rOuter[2]; + m_BoundingShape = new G4ShiftedCone( + bs_name + "BackCone", zPlane[1], zPlane[2], + rInner[1], rOuter[1], rInner[2], rOuter[2] + ); + hasBackSections = true; + } else { + m_Zmin = zPlane[0]; m_Zmax = zPlane[2]; + m_Rmin = rInner[0]; m_Rmax = rOuter[2]; + m_BoundingShape = new G4Polycone( + bs_name + "Polycone", m_MinPhi, m_MaxPhi - m_MinPhi, + 3, zPlane, rInner, rOuter + ); + hasFrontSections = true; + hasBackSections = true; + } + + m_Ymin = m_Rmin * 0.9; + +#ifdef LARWHEELSOLID_USE_FANBOUND + const G4double phi_size = (m_FanPhiAmplitude + GetCalculator()->GetFanStepOnPhi() * 2) * 2; + FanBound = new G4Polycone(bs_name + "ofFan", phi_min, phi_size, + 3, zPlane, rInner, rOuter); +#endif +#ifndef PORTABLE_LAR_SHAPE + ATH_MSG_INFO(m_BoundingShape->GetName() + " is the m_BoundingShape"); +#endif + const G4double half_wave_length = GetCalculator()->GetHalfWaveLength(); + const G4double sss = GetCalculator()->GetStraightStartSection(); + + if(hasFrontSections){ + m_Zsect.push_back(0.); + m_Zsect.push_back(sss + half_wave_length * 0.25); + } else { + m_Zsect.push_back(m_Zmid); + } + const G4int num_fs = GetCalculator()->GetNumberOfHalfWaves() + 1; + + for(G4int i = 2; i < num_fs; i ++){ + const G4double zi = half_wave_length * (i - 1) + sss; +#if LARWHEELSOLID_ZSECT_MULT > 1 + for(G4int j = LARWHEELSOLID_ZSECT_MULT - 1; j > 0; -- j){ + G4double zj = zi - half_wave_length * j / LARWHEELSOLID_ZSECT_MULT; + if(hasFrontSections && hasBackSections + && m_Zsect.back() < m_Zmid && zj >= m_Zmid){ + m_Zsect.push_back(m_Zmid); + } + if((zj < m_Zmid && hasFrontSections) + || (zj > m_Zmid && hasBackSections)){ + m_Zsect.push_back(zj); + } + } +#endif + if(hasFrontSections && hasBackSections + && m_Zsect.back() < m_Zmid && zi >= m_Zmid){ + m_Zsect.push_back(m_Zmid); + } + if((zi < m_Zmid && hasFrontSections) + || (zi > m_Zmid && hasBackSections)){ + m_Zsect.push_back(zi); + } + } + if(hasBackSections){ + m_Zsect.push_back(wheel_thickness - sss - half_wave_length * 0.25); + m_Zsect.push_back(wheel_thickness); + } else { + m_Zsect.push_back(m_Zmid); + } + + m_fs = new LArFanSections( + rInner[0], rInner[1], rOuter[0], rOuter[1], + m_Rmax*cos(phi_min), m_Zsect.front(), m_Zmid + ); +} + +// it should be called after m_FanPhiAmplitude has been set +// and before m_BoundingShape creation +void LArWheelSolid::set_phi_size(void) +{ + if(GetCalculator()->GetisModule()){ + m_MinPhi = m_PhiPosition - CLHEP::pi * (1. / 8.) - m_FanPhiAmplitude; + m_MaxPhi = m_PhiPosition + CLHEP::pi * (1. / 8.) + m_FanPhiAmplitude; + } else { + m_MinPhi = 0.; + m_MaxPhi = CLHEP::twopi; + } +} diff --git a/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSolid_type.h b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSolid_type.h new file mode 100644 index 0000000000000000000000000000000000000000..c7b692841c551b1713bd4a313b5afcf24d82bb8d --- /dev/null +++ b/ATLAS-Extensions/LArCustomSolidExtension/import/Simulation/G4Utilities/Geo2G4/src/LArWheelSolid_type.h @@ -0,0 +1,40 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// LArWheelSolid_type +// Author: D. A. Maximov +// typedefs for LArWheelSolid + +#ifndef __LArWheelSolid_type_HH__ +#define __LArWheelSolid_type_HH__ + +typedef enum { + InnerAbsorberWheel, + OuterAbsorberWheel, + InnerElectrodWheel, + OuterElectrodWheel, + InnerAbsorberModule, + OuterAbsorberModule, + InnerElectrodModule, + OuterElectrodModule, + InnerGlueWheel, + OuterGlueWheel, + InnerLeadWheel, + OuterLeadWheel, + InnerAbsorberCone, + InnerElectrodCone, + InnerGlueCone, + InnerLeadCone, + OuterAbsorberFrontCone, + OuterElectrodFrontCone, + OuterGlueFrontCone, + OuterLeadFrontCone, + OuterAbsorberBackCone, + OuterElectrodBackCone, + OuterGlueBackCone, + OuterLeadBackCone, +} LArWheelSolid_t; + + +#endif // __LArWheelSolid_type_HH__ diff --git a/CI/Brewfile b/CI/Brewfile index f2c87b601cdcb429b435f069ddfd4780d7b34f9f..3e753495074701637cfc0bd178df17de19e420f7 100644 --- a/CI/Brewfile +++ b/CI/Brewfile @@ -14,3 +14,4 @@ brew "nlohmann-json" brew "xerces-c" brew "eigen" brew "hdf5" +brew "hepmc3" diff --git a/CI/DockerfileBase b/CI/DockerfileBase index 2627e7b237e832933440e8200f8fcd38e1683d68..64c15cbe021cd7910d5e2418815951b29b90a205 100755 --- a/CI/DockerfileBase +++ b/CI/DockerfileBase @@ -32,8 +32,11 @@ RUN apt-get update && apt-get install -y sqlite3 libsqlite3-dev ### Install eigen to avoid the own installation RUN apt-get update && apt-get install -y libeigen3-dev -### Install eigen to avoid the own installation -RUN apt-get update && apt-get install -y libhdf5-dev +### Install hdf5 to avoid the own installation +RUN apt-get update && apt-get install -y libhdf5-dev + +### Install hepmc3 to avoid the own installation +RUN apt-get update && apt-get install -y libhepmc3-dev ### Another layer of building xer RUN wget https://cern.ch/lcgpackages/tarFiles/sources/xerces-c-${XercesC_VERSION}.tar.gz && \ diff --git a/CMakeLists.txt b/CMakeLists.txt index c685519ef51ef8d95f5f5055a6e42f8f707c5190..5e45b305379473cf2adcc23a380a85789fa807c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,7 +53,10 @@ option(GEOMODEL_BUILD_VISUALIZATION "Enable the build of GeoModelVisualization" option(GEOMODEL_BUILD_GEOMODELG4 "Enable the build of GeoModelG4" OFF) option(GEOMODEL_BUILD_FULLSIMLIGHT "Enable the build of FullSimLight" OFF) option(GEOMODEL_BUILD_FULLSIMLIGHT_PROFILING "Enable FullSimLight profiling targets" OFF) -option(GEOMODEL_BUILD_LARCUSTOMSOLIDEXTENSION "Build the LArCustomSolidExtension" OFF) +#option(GEOMODEL_BUILD_LARCUSTOMSOLIDEXTENSION "Build the LArCustomSolidExtension" OFF) +option(GEOMODEL_BUILD_ATLASEXTENSIONS "Build the Custom ATLAS Extensions" OFF) + + if(GEOMODEL_BUILD_FULLSIMLIGHT_PROFILING) set(GEOMODEL_BUILD_FULLSIMLIGHT ON CACHE BOOL "Enable the build of FullSimLight" FORCE) @@ -98,11 +101,17 @@ if(GEOMODEL_BUILD_FULLSIMLIGHT) list( APPEND BUILT_PACKAGES "FSL") endif() -if(GEOMODEL_BUILD_LARCUSTOMSOLIDEXTENSION) - add_subdirectory(LArCustomSolidExtension) - list( APPEND BUILT_PACKAGES "LArCustomSolidExtension") +#if(GEOMODEL_BUILD_LARCUSTOMSOLIDEXTENSION) +# add_subdirectory(LArCustomSolidExtension) +# list( APPEND BUILT_PACKAGES "LArCustomSolidExtension") +#endif() + +if(GEOMODEL_BUILD_ATLASEXTENSIONS) + add_subdirectory(ATLAS-Extensions) + list( APPEND BUILT_PACKAGES "ATLAS-Extensions") endif() + if(GEOMODEL_BUILD_GEOMODELG4 OR GEOMODEL_BUILD_EXAMPLES_W_GEANT4) add_subdirectory(GeoModelG4) list( APPEND BUILT_PACKAGES "GeoModelG4") diff --git a/FSL/src/BetterTextBrowser.h b/FSL/src/BetterTextBrowser.h new file mode 100644 index 0000000000000000000000000000000000000000..56ee88ca8aaa8d21ca519f24275ebba52d26f69d --- /dev/null +++ b/FSL/src/BetterTextBrowser.h @@ -0,0 +1,49 @@ +#ifndef _BETTERTEXTBROWSER_H_ +#define _BETTERTEXTBROWSER_H_ +#include <QTextBrowser> +#include <QMenu> +#include <QAction> +#include <iostream> +#include <QContextMenuEvent> +#include <QIcon> +#include <QStyle> +#include "fsl_mainwindow.h" +class BetterTextBrowser:public QTextBrowser { + Q_OBJECT + + + public: + + // Constructor: + BetterTextBrowser(QWidget * parent):QTextBrowser(parent){} + + // Destructor: + ~BetterTextBrowser() {} + + // Set main window: + void setMainWindow(FSLMainWindow *mainWindow) { + m_mainWindow=mainWindow; + } + + // Override from base class. Add an action for "save text to file" + void contextMenuEvent(QContextMenuEvent *event) { + + QMenu *menu = createStandardContextMenu(); + QAction *action=menu->addAction(tr("Save to file")); + + + action->setIcon((style()->standardIcon(QStyle::StandardPixmap(QStyle::SP_DialogSaveButton), nullptr, this))); + action->setEnabled(!document()->isEmpty()); + + action->setShortcut(QKeySequence(QKeySequence(Qt::CTRL + Qt::Key_S))); + connect(action, &QAction::triggered, m_mainWindow, &FSLMainWindow::save_display_output); + menu->exec(event->globalPos()); + delete menu; + } + + + private: + FSLMainWindow *m_mainWindow {nullptr}; + +}; +#endif diff --git a/FSL/src/fsl_mainwindow.cpp b/FSL/src/fsl_mainwindow.cpp index cb463517100bfb44f5171ccb30ea7b0571fcc88e..bd422077bd28dba2ae11875555a5923903db1cd8 100644 --- a/FSL/src/fsl_mainwindow.cpp +++ b/FSL/src/fsl_mainwindow.cpp @@ -20,19 +20,24 @@ FSLMainWindow::FSLMainWindow(QWidget *parent) , ui(new Ui::FSLMainWindow) { ui->setupUi(this); - this->setWindowTitle("FullSimLight-GUI (beta version)"); + this->setWindowTitle("FullSimLight-GUI"); std::setlocale(LC_NUMERIC, "C"); - //Setting up Models - sens_det_model = new QStringListModel(this); - g4ui_model = new QStringListModel(this); - // shape_model = new QStringListModel(this); - // ui->shape_view->setEditTriggers(QAbstractItemView::DoubleClicked); - ui->sens_det_view->setModel(sens_det_model); - ui->g4ui_view->setModel(g4ui_model); - // ui->shape_view->setModel(shape_model); - ui->sens_det_view->setEditTriggers(QAbstractItemView::DoubleClicked); - ui->g4ui_view->setEditTriggers(QAbstractItemView::DoubleClicked); + ui->tB_view_config->setMainWindow(this); + + //Setting up g4ui Model + //g4ui_model = new QStringListModel(this); + //ui->g4ui_view->setModel(g4ui_model); + //ui->g4ui_view->setEditTriggers(QAbstractItemView::DoubleClicked); + + //Setting up Sensitive Detector Model + sens_det_model = new QStandardItemModel(this); + sens_det_horizontalHeader.append("Plugins List"); + sens_det_model->setHorizontalHeaderLabels(sens_det_horizontalHeader); + ui->sens_det_table->setModel(sens_det_model); + ui->sens_det_table->horizontalHeader()->setStretchLastSection(true); + ui->sens_det_table->resizeRowsToContents(); + ui->sens_det_table->resizeColumnsToContents(); //Setting up the Regions Display @@ -54,7 +59,7 @@ FSLMainWindow::FSLMainWindow(QWidget *parent) //Setting up the User Actions Display user_action_model = new QStandardItemModel(this); // user_action_horizontalHeader.append("Type of Action"); - user_action_horizontalHeader.append("File"); + user_action_horizontalHeader.append("Plugins List"); user_action_model->setHorizontalHeaderLabels(user_action_horizontalHeader); ui->user_action_table->setModel(user_action_model); ui->user_action_table->horizontalHeader()->setStretchLastSection(true); @@ -65,6 +70,8 @@ FSLMainWindow::FSLMainWindow(QWidget *parent) //Setting up Connections connect(ui->pB_geom, &QPushButton::released, this, &FSLMainWindow::assign_geom_file); connect(ui->actionSave, &QAction::triggered, this, &FSLMainWindow::save_configuration); + connect(ui->pB_save_config, &QPushButton::released, this, &FSLMainWindow::save_configuration); + connect(ui->actionSave_as, &QAction::triggered, this, &FSLMainWindow::save_configuration_as); connect(ui->actionOpen, &QAction::triggered, this, &FSLMainWindow::load_configuration); connect(ui->pB_view, &QPushButton::released, this, &FSLMainWindow::view_configuration); @@ -72,7 +79,10 @@ FSLMainWindow::FSLMainWindow(QWidget *parent) connect(ui->pB_gmex, &QPushButton::released, this, &FSLMainWindow::run_gmex); connect(ui->pB_gmclash, &QPushButton::released, this, &FSLMainWindow::run_gmclash); connect(ui->pB_main_clear, &QPushButton::released, this, &FSLMainWindow::clear_main_status); + connect(ui->pB_browse_phys_list, &QPushButton::released, this, &FSLMainWindow::assign_phys_list_plugin); connect(ui->pB_pythia_browse, &QPushButton::released, this, &FSLMainWindow::assign_pythia_file); + connect(ui->pB_hepmc3_browse_files, &QPushButton::released, this, &FSLMainWindow::assign_hepmc3_file); + connect(ui->pB_gen_plug_browse_files, &QPushButton::released, this, &FSLMainWindow::assign_gen_plug_file); connect(ui->pB_magnetic_field_plugin, &QPushButton::released, this, &FSLMainWindow::assign_magnetic_field_plugin_file); connect(ui->pB_magnetic_field_map, &QPushButton::released, this, &FSLMainWindow::assign_magnetic_field_map); @@ -80,8 +90,8 @@ FSLMainWindow::FSLMainWindow(QWidget *parent) connect(ui->pB_del_sens_det, &QPushButton::released, this, &FSLMainWindow::del_sens_det); connect(ui->pB_add_region, &QPushButton::released, this, &FSLMainWindow::pop_up_regions); connect(ui->pB_del_region, &QPushButton::released, this, &FSLMainWindow::del_region); - connect(ui->pB_add_g4ui, &QPushButton::released, this, &FSLMainWindow::add_g4ui); - connect(ui->pB_del_g4ui, &QPushButton::released, this, &FSLMainWindow::del_g4ui); + //connect(ui->pB_add_g4ui, &QPushButton::released, this, &FSLMainWindow::add_g4ui); + //connect(ui->pB_del_g4ui, &QPushButton::released, this, &FSLMainWindow::del_g4ui); // connect(ui->pB_add_shape_ext_file, &QPushButton::released, this, &FSLMainWindow::add_shape_ext); // connect(ui->pB_del_shape_ext_file, &QPushButton::released, this, &FSLMainWindow::del_shape_ext); @@ -99,6 +109,7 @@ FSLMainWindow::FSLMainWindow(QWidget *parent) //Setting widget properties ui->sB_NOE->setMaximum(10000); + ui->sB_NOT->setMinimum(1); ui->sB_NOT->setMaximum(std::thread::hardware_concurrency()); ui->sB_control->setMaximum(5); ui->sB_run->setMaximum(5); @@ -108,6 +119,9 @@ FSLMainWindow::FSLMainWindow(QWidget *parent) ui->cB_particle->setCurrentIndex(0); ui->pB_pythia_browse->setEnabled(false); ui->cB_pythia_type_of_eve->setEnabled(false); + ui->pB_hepmc3_browse_files->setEnabled(false); + ui->cB_hepmc3_type_of_eve->setEnabled(false); + ui->pB_gen_plug_browse_files->setEnabled(false); ui->pB_magnetic_field_map->setEnabled(false); ui->pB_magnetic_field_plugin->setEnabled(false); ui->cB_particle->setCurrentIndex(0); @@ -120,8 +134,8 @@ FSLMainWindow::FSLMainWindow(QWidget *parent) ui->sB_NOT->setValue(std::thread::hardware_concurrency()); ui->sB_NOE->setValue(10); number_of_primaries_per_event = 1; - ui->lE_hits->setText("HITS.root"); - ui->lE_histo->setText("HISTO.root"); + // ui->lE_hits->setText("HITS.root"); + // ui->lE_histo->setText("HISTO.root"); ui->tB_view_config->setCurrentFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); ui->tB_view_config->setFontPointSize(13); @@ -143,8 +157,8 @@ FSLMainWindow::FSLMainWindow(QWidget *parent) ui->lE_pz->setValidator(p_z_validator); ui->lE_fixed_MF->setValidator(mag_field_validator); - ui->lE_hits->setEnabled(false); - ui->lE_histo->setEnabled(false); + // ui->lE_hits->setEnabled(false); + // ui->lE_histo->setEnabled(false); // ui->tab->setEnabled(false);//Shape tab (Change name on UI) @@ -158,9 +172,9 @@ FSLMainWindow::FSLMainWindow(QWidget *parent) connect(ui->cB_magnetic_field, QOverload<int>::of(&QComboBox::currentIndexChanged), this ,&FSLMainWindow::configure_magnetic_field); connect(ui->cB_pythia_type_of_eve, QOverload<int>::of(&QComboBox::currentIndexChanged), this ,&FSLMainWindow::check_if_pythia_file); - connect(this, &FSLMainWindow::send_error_message, this, &FSLMainWindow::catch_error_message); - connect(ui->sens_det_view, SIGNAL(clicked(QModelIndex)), this, SLOT(get_sens_det_index(QModelIndex))); - connect(ui->g4ui_view, SIGNAL(clicked(QModelIndex)), this, SLOT(get_g4ui_index(QModelIndex))); + //connect(this, &FSLMainWindow::send_error_message, this, &FSLMainWindow::catch_error_message); + // connect(ui->sens_det_view, SIGNAL(clicked(QModelIndex)), this, SLOT(get_sens_det_index(QModelIndex))); + //connect(ui->g4ui_view, SIGNAL(clicked(QModelIndex)), this, SLOT(get_g4ui_index(QModelIndex))); // connect(ui->shape_view, SIGNAL(clicked(QModelIndex)), this, SLOT(get_shape_index(QModelIndex))); connect(region,&ConfigRegions::send_config,this,&FSLMainWindow::add_region); connect(&fullSimLight_process,SIGNAL(readyReadStandardOutput()),this,SLOT(fsmlreadyReadStandardOutput())); @@ -179,7 +193,7 @@ FSLMainWindow::~FSLMainWindow() { delete ui; delete sens_det_model; - delete g4ui_model; + //delete g4ui_model; delete region; delete region_model; delete user_action_model; @@ -193,26 +207,27 @@ FSLMainWindow::~FSLMainWindow() //Custom Signal to append to status bars -void FSLMainWindow::catch_error_message(std::string info) +/*void FSLMainWindow::catch_error_message(std::string info) { std::cout << info << std::endl; -} +}*/ //Get index of the row in the sensitive detector extensions display when clicked -void FSLMainWindow::get_sens_det_index(QModelIndex sens_det_index) +/*void FSLMainWindow::get_sens_det_index(QModelIndex sens_det_index) { sens_det_number = sens_det_index.row(); -} +}*/ //Add the Sensitive detector file void FSLMainWindow::add_sens_det() { - std::string sens_det_file = this->get_file_name(); - if(sens_det_file.find(".dylib") != std::string::npos || sens_det_file.find(".so") != std::string::npos) - {QString q_sens_det_file = QString::fromUtf8(sens_det_file.c_str()); - sens_det_model->insertRow(sens_det_model->rowCount()); - QModelIndex sens_det_index = sens_det_model->index(sens_det_model->rowCount()-1); - sens_det_model->setData(sens_det_index, q_sens_det_file); + QString q_sens_det_file_name = QString::fromUtf8((this->get_file_name()).c_str()); + + if(q_sens_det_file_name!="") + { + int rows = ui->sens_det_table->model()->rowCount(); + ui->sens_det_table->model()->insertRows(rows,1); + ui->sens_det_table->model()->setData(ui->sens_det_table->model()->index(rows,0),q_sens_det_file_name); } } @@ -220,7 +235,11 @@ void FSLMainWindow::add_sens_det() //Delete the sensitive_detector_ext void FSLMainWindow::del_sens_det() { - sens_det_model->removeRow(sens_det_number); + QModelIndexList sens_det_indexes = ui->sens_det_table->selectionModel()->selectedRows(); + int countRow = sens_det_indexes.count(); + + for( int i = countRow; i > 0; i--) + sens_det_model->removeRow( sens_det_indexes.at(i-1).row(), QModelIndex()); } @@ -228,77 +247,91 @@ void FSLMainWindow::del_sens_det() void FSLMainWindow::configure_sens_det_actions() { sensitive_detector_extensions.clear(); - for(int i = 0; i<=ui->sens_det_view->model()->rowCount()-1; i++) + + for(int row = 0 ; row < ui->sens_det_table->model()->rowCount(); ++row ) { - sensitive_detector_extensions.push_back((sens_det_model-> - index( i, 0 ).data( Qt::DisplayRole ).toString()).toStdString()); + std::string associated_file = ((ui->sens_det_table->model()->index(row,0)).data().toString()).toStdString(); + sensitive_detector_extensions.push_back(associated_file); } -} -//Get index of the row in the Shape extensions display when clicked -/*void FSLMainWindow::get_shape_index(QModelIndex shape_index) -{ - shape_number = shape_index.row(); } -//Add a shape extension -void FSLMainWindow::add_shape_ext() -{ - std::string shape_ext_file = this->get_file_name(); - if(shape_ext_file.find(".dylib") != std::string::npos || shape_ext_file.find(".so") != std::string::npos) - {QString q_shape_ext_file = QString::fromUtf8(shape_ext_file.c_str()); - shape_model->insertRow(shape_model->rowCount()); - QModelIndex shape_index = shape_model->index(shape_model->rowCount()-1); - shape_model->setData(shape_index, q_shape_ext_file); - } -} - -//Delete the shape extension -void FSLMainWindow::del_shape_ext() -{ - shape_model->removeRow(shape_number); -} - -//Add the shape extenions to the shape extensions list. -void FSLMainWindow::configure_shape_ext() -{ - shape_extensions.clear(); - for(int i = 0; i<=ui->shape_view->model()->rowCount()-1; i++) - { - shape_extensions.push_back((shape_model-> - index( i, 0 ).data( Qt::DisplayRole ).toString()).toStdString()); - - } -}*/ - //Get index of row in g4ui display when clicked -void FSLMainWindow::get_g4ui_index(QModelIndex sens_det_index) +/*void FSLMainWindow::get_g4ui_index(QModelIndex sens_det_index) { g4ui_number = sens_det_index.row(); -} +}*/ //Add a g4ui command -void FSLMainWindow::add_g4ui() +/*void FSLMainWindow::add_g4ui() { - QString g4ui_comm = ui->lE_g4ui->text(); - if(g4ui_comm!="") + QString q_g4ui_comm =ui->lE_g4ui->text(); + std::string g4ui_comm = ui->lE_g4ui->text().toStdString(); + + if(g4ui_comm=="") + { + QMessageBox::information(this, "Info", "Can't add empty command"); + } + + else if(g4ui_comm.find("/FSLgun/energy") != std::string::npos) + { + QMessageBox::information(this, "Info", "Particle energy is set from Generator tab"); + } + + else if(g4ui_comm.find("/FSLgun/particle") != std::string::npos) + { + QMessageBox::information(this, "Info", "Particle must be set from Generator tab"); + } + + else if(g4ui_comm.find("/FSLgun/direction") != std::string::npos) + { + QMessageBox::information(this, "Info", "Particle direction is set from Generator tab"); + } + + else if(g4ui_comm.find("/FSLdet/setField") != std::string::npos) + { + QMessageBox::information(this, "Info", "Magnetic Field is set from Magnetic Field tab"); + } + + else if(g4ui_comm.find("/FSLgun/primaryPerEvt") != std::string::npos) + { + QMessageBox::information(this, "Info", "Primary per evt can be set by editing config file in external editor"); + } + + else if(g4ui_comm.find("/run/numberOfThreads") != std::string::npos) + { + QMessageBox::information(this, "Info", "Number of Threads can be set in the main tab"); + } + + else if(g4ui_comm.find("/run/initialize") != std::string::npos) + { + QMessageBox::information(this, "Info", "Command already executed in FullSimLight"); + } + + else if(g4ui_comm.find("/run/beamOn") != std::string::npos) + { + QMessageBox::information(this, "Info", "Command already executed in FullSimLight"); + } + + else { g4ui_model->insertRow(g4ui_model->rowCount()); QModelIndex g4ui_index = g4ui_model->index(g4ui_model->rowCount()-1); - g4ui_model->setData(g4ui_index, g4ui_comm); + g4ui_model->setData(g4ui_index, q_g4ui_comm); ui->lE_g4ui->clear(); } + } //Delete a g4ui command void FSLMainWindow::del_g4ui() { g4ui_model->removeRow(g4ui_number); -} +}*/ //Add g4ui commands to g4ui commands list void FSLMainWindow::configure_g4ui_command() @@ -334,13 +367,13 @@ void FSLMainWindow::configure_g4ui_command() g4ui_commands.push_back(tracking_command); } - for(int row = 0; row < ui->g4ui_view->model()->rowCount(); ++row) + /*for(int row = 0; row < ui->g4ui_view->model()->rowCount(); ++row) { std::string comm = (ui->g4ui_view->model()->index(row,0).data().toString()).toStdString(); if(comm != ""){ g4ui_commands.push_back(comm); } - } + }*/ g4ui_commands.push_back("/control/cout/prefixString G4Worker_"); g4ui_commands.push_back("/run/numberOfThreads " + ui->sB_NOT->text().toStdString()); @@ -354,13 +387,18 @@ void FSLMainWindow::configure_g4ui_command() { g4ui_commands.push_back("/run/initialize"); } + + if(generator=="HepMC3 File") + { + g4ui_commands.push_back("/run/initialize"); + } if(generator=="Particle Gun") { g4ui_commands.push_back("/FSLgun/primaryPerEvt " + std::to_string(number_of_primaries_per_event)); - g4ui_commands.push_back("/FSLgun/energy " + particle_energy); - g4ui_commands.push_back("/FSLgun/particle " + particle); - g4ui_commands.push_back("/FSLgun/direction " + particle_direction); + g4ui_commands.push_back("/FSLgun/energy " + particle_energy); + g4ui_commands.push_back("/FSLgun/particle " + particle); + g4ui_commands.push_back("/FSLgun/direction " + particle_direction); } @@ -657,12 +695,31 @@ void FSLMainWindow::assign_geom_file() } } +//Function to Physics List Plugin +void FSLMainWindow::assign_phys_list_plugin() +{ + std::string phys_list = this->get_file_name(); + if(phys_list!=""){ui->lE_PLN->setText(phys_list.c_str());} +} + //Function to select a pythia file void FSLMainWindow::assign_pythia_file() { pythia_input_file = this->get_file_name(); } +//Function to select a HepMC3 file +void FSLMainWindow::assign_hepmc3_file() +{ + hepmc3_input_file = this->get_file_name(); +} + +//Function to select a Generator Plugin +void FSLMainWindow::assign_gen_plug_file() +{ + generator_plugin = this->get_file_name(); +} + void FSLMainWindow::check_if_pythia_file() { if(ui->cB_pythia_type_of_eve->currentIndex()==3) @@ -715,9 +772,14 @@ void FSLMainWindow::configure_generator() if(generator=="Particle Gun") { + ui->sB_NOT->setEnabled(true); + this->configure_energy_direction(); ui->pB_pythia_browse->setEnabled(false); ui->cB_pythia_type_of_eve->setEnabled(false); + ui->pB_hepmc3_browse_files->setEnabled(false); + ui->cB_hepmc3_type_of_eve->setEnabled(false); + ui->pB_gen_plug_browse_files->setEnabled(false); ui->cB_particle->setEnabled(true); ui->lE_px->setEnabled(true); ui->lE_py->setEnabled(true); @@ -727,16 +789,25 @@ void FSLMainWindow::configure_generator() particle = (ui->cB_particle->currentText()).toStdString(); pythia_type_of_event = ""; pythia_input_file = ""; + hepmc3_input_file = ""; + hepmc3_type_of_file = ""; + generator_plugin = ""; } else if(generator=="Pythia") { + ui->sB_NOT->setEnabled(true); + ui->cB_pythia_type_of_eve->setEnabled(true); ui->cB_particle->setEnabled(false); ui->lE_px->setEnabled(false); ui->lE_py->setEnabled(false); ui->lE_pz->setEnabled(false); + ui->pB_hepmc3_browse_files->setEnabled(false); + ui->cB_hepmc3_type_of_eve->setEnabled(false); + ui->pB_gen_plug_browse_files->setEnabled(false); + if(ui->cB_pythia_type_of_eve->currentIndex()==3) { @@ -756,11 +827,76 @@ void FSLMainWindow::configure_generator() particle = ""; particle_energy = ""; particle_direction = ""; + hepmc3_input_file = ""; + hepmc3_type_of_file = ""; + generator_plugin = ""; p_x = 0; p_y = 0; p_z = 0; } + + else if(generator=="HepMC3 File") + { + ui->sB_NOT->setValue(1); + ui->sB_NOT->setEnabled(false); + + ui->pB_hepmc3_browse_files->setEnabled(true); + ui->cB_hepmc3_type_of_eve->setEnabled(true); + + ui->cB_particle->setEnabled(false); + ui->lE_px->setEnabled(false); + ui->lE_py->setEnabled(false); + ui->lE_pz->setEnabled(false); + ui->pB_pythia_browse->setEnabled(false); + ui->cB_pythia_type_of_eve->setEnabled(false); + ui->pB_gen_plug_browse_files->setEnabled(false); + + hepmc3_type_of_file = (ui->cB_hepmc3_type_of_eve->currentText()).toStdString(); + + + particle = ""; + particle_energy = ""; + particle_direction = ""; + pythia_type_of_event = ""; + pythia_input_file = ""; + generator_plugin = ""; + p_x = 0; + p_y = 0; + p_z = 0; + + } + + + else if(generator=="Generator Plugin") + { + ui->sB_NOT->setEnabled(true); + + ui->pB_gen_plug_browse_files->setEnabled(true); + + ui->pB_hepmc3_browse_files->setEnabled(false); + ui->cB_hepmc3_type_of_eve->setEnabled(false); + + ui->cB_particle->setEnabled(false); + ui->lE_px->setEnabled(false); + ui->lE_py->setEnabled(false); + ui->lE_pz->setEnabled(false); + ui->pB_pythia_browse->setEnabled(false); + ui->cB_pythia_type_of_eve->setEnabled(false); + + + particle = ""; + particle_energy = ""; + particle_direction = ""; + pythia_type_of_event = ""; + pythia_input_file = ""; + hepmc3_input_file = ""; + hepmc3_type_of_file = ""; + p_x = 0; + p_y = 0; + p_z = 0; + + } } @@ -838,6 +974,24 @@ void FSLMainWindow::save_configuration() o << std::setw(4) << j << std::endl; } +void FSLMainWindow::save_display_output() +{ + std::string text = ui->tB_view_config->toPlainText().toStdString(); + if (save_display_directory.empty()) save_display_directory= (QDir::currentPath()).toStdString() +"/fullSimLight.log"; + + QString displayfileName = QFileDialog::getSaveFileName(this, + tr("Save Output"), save_display_directory.c_str(), tr("Log Files (*.log)")); + if (displayfileName.isEmpty()) return; + std::string save_display_file=displayfileName.toStdString(); + std::string save_display_base=basename(const_cast<char *> (save_display_file.c_str())); + save_display_directory=dirname(const_cast<char *> (save_display_file.c_str())); + + std::ofstream DisplayFile(save_display_directory+"/"+save_display_base); + DisplayFile << text; + DisplayFile.close(); + +} + //Function to save current configuration void FSLMainWindow::save_configuration_as() { @@ -1022,20 +1176,22 @@ void FSLMainWindow::load_configuration() physics_list_name = j_load["Physics list name"]; ui->lE_PLN->setText(QString::fromUtf8(physics_list_name.c_str())); - number_of_threads = j_load["Number of threads"]; - ui->sB_NOT->setValue(number_of_threads); + // number_of_threads = j_load["Number of threads"]; + // ui->sB_NOT->setValue(number_of_threads); number_of_events = j_load["Number of events"]; ui->sB_NOE->setValue(number_of_events); - magnetic_field = j_load["Magnetic Field Intensity"]; - ui->lE_fixed_MF->setText(QString::fromUtf8(magnetic_field.c_str())); + // magnetic_field = j_load["Magnetic Field Intensity"]; + // ui->lE_fixed_MF->setText(QString::fromUtf8(magnetic_field.c_str())); generator = j_load["Generator"]; if(generator=="Particle Gun") { + ui->sB_NOT->setEnabled(true); + ui->cB_gen_options->setCurrentIndex(0); ui->cB_particle->setEnabled(true); @@ -1043,8 +1199,8 @@ void FSLMainWindow::load_configuration() ui->lE_py->setEnabled(true); ui->lE_pz->setEnabled(true); - particle = j_load["Particle"]; - ui->cB_particle->setCurrentText(QString::fromUtf8(particle.c_str())); + // particle = j_load["Particle"]; + // ui->cB_particle->setCurrentText(QString::fromUtf8(particle.c_str())); p_x = j_load["p_x"]; p_y = j_load["p_y"]; @@ -1058,17 +1214,25 @@ void FSLMainWindow::load_configuration() ui->cB_pythia_type_of_eve->setCurrentIndex(0); ui->pB_pythia_browse->setEnabled(false); ui->cB_pythia_type_of_eve->setEnabled(false); + + ui->cB_hepmc3_type_of_eve->setCurrentIndex(0); + ui->pB_hepmc3_browse_files->setEnabled(false); + ui->cB_hepmc3_type_of_eve->setEnabled(false); + + ui->pB_gen_plug_browse_files->setEnabled(false); + } - else + else if(generator=="Pythia") { + ui->sB_NOT->setEnabled(true); + + ui->cB_gen_options->setCurrentIndex(1); ui->cB_pythia_type_of_eve->setEnabled(true); - ui->cB_gen_options->setCurrentIndex(1); - - pythia_type_of_event = j_load["Type of event"]; + pythia_type_of_event = j_load["Pythia type of event"]; if(pythia_type_of_event != "") { @@ -1078,7 +1242,7 @@ void FSLMainWindow::load_configuration() } else { - pythia_input_file = j_load["Event input file"]; + pythia_input_file = j_load["Pythia event input file"]; ui->cB_pythia_type_of_eve->setCurrentIndex(3); ui->pB_pythia_browse->setEnabled(true); @@ -1089,23 +1253,519 @@ void FSLMainWindow::load_configuration() ui->lE_px->clear(); ui->lE_py->clear(); ui->lE_pz->clear(); + ui->cB_particle->setCurrentIndex(0); + ui->cB_particle->setEnabled(false); + ui->lE_px->setEnabled(false); + ui->lE_py->setEnabled(false); + ui->lE_pz->setEnabled(false); + + ui->cB_hepmc3_type_of_eve->setCurrentIndex(0); + ui->pB_hepmc3_browse_files->setEnabled(false); + ui->cB_hepmc3_type_of_eve->setEnabled(false); + + ui->pB_gen_plug_browse_files->setEnabled(false); + } + + else if(generator=="HepMC3 File") + { + ui->sB_NOT->setValue(1); + ui->sB_NOT->setEnabled(false); + + ui->cB_gen_options->setCurrentIndex(2); + ui->pB_hepmc3_browse_files->setEnabled(true); + ui->cB_hepmc3_type_of_eve->setEnabled(true); + + hepmc3_type_of_file = j_load["HepMC3 type of file"]; + hepmc3_input_file = j_load["HepMC3 file"]; + + ui->cB_hepmc3_type_of_eve->setCurrentText(QString::fromUtf8(hepmc3_type_of_file.c_str())); + + ui->lE_px->clear(); + ui->lE_py->clear(); + ui->lE_pz->clear(); + ui->cB_particle->setCurrentIndex(0); ui->cB_particle->setEnabled(false); ui->lE_px->setEnabled(false); ui->lE_py->setEnabled(false); ui->lE_pz->setEnabled(false); + + ui->cB_pythia_type_of_eve->setCurrentIndex(0); + ui->pB_pythia_browse->setEnabled(false); + ui->cB_pythia_type_of_eve->setEnabled(false); + + ui->pB_gen_plug_browse_files->setEnabled(false); + + } + + else if(generator=="Generator Plugin") + { + ui->sB_NOT->setEnabled(true); + + ui->cB_gen_options->setCurrentIndex(3); + ui->pB_gen_plug_browse_files->setEnabled(true); + generator_plugin = j_load["Generator Plugin"]; + + ui->lE_px->clear(); + ui->lE_py->clear(); + ui->lE_pz->clear(); + ui->cB_particle->setCurrentIndex(0); + ui->cB_particle->setEnabled(false); + ui->lE_px->setEnabled(false); + ui->lE_py->setEnabled(false); + ui->lE_pz->setEnabled(false); + + ui->cB_pythia_type_of_eve->setCurrentIndex(0); + ui->pB_pythia_browse->setEnabled(false); + ui->cB_pythia_type_of_eve->setEnabled(false); + + ui->cB_hepmc3_type_of_eve->setCurrentIndex(0); + ui->pB_hepmc3_browse_files->setEnabled(false); + ui->cB_hepmc3_type_of_eve->setEnabled(false); + + } sens_det_model->removeRows(0,sens_det_model->rowCount()); - for(const auto& element : j_load["Sensitive Detector Extensions"] ) + for(const auto& element : j_load["Sensitive Detector Extensions"]) + { + std::string sens_det_file = element; + QString q_sens_det_file = QString::fromUtf8(sens_det_file.c_str()); + int rows = ui->sens_det_table->model()->rowCount(); + ui->sens_det_table->model()->insertRows(rows,1); + ui->sens_det_table->model()->setData(ui->sens_det_table->model()->index(rows,0),q_sens_det_file); + + } + + region_model->removeRows(0,region_model->rowCount()); + for(const auto& element: j_load["Regions data"]){ + Region r; + from_json(element,r); + + int rows = ui->regions_table->model()->rowCount(); + ui->regions_table->model()->insertRows(rows,1); + + QString q_r_name = QString::fromUtf8(r.Region_name.c_str()); + std::string r_froot = ""; + + for(const auto& element: r.fRootLVnames) + { + r_froot = r_froot+element+","; + } + + if(r_froot!="") + { + r_froot.pop_back(); + } + + QString q_r_froot = QString::fromUtf8(r_froot.c_str()); + + + ui->regions_table->model()->setData(ui->regions_table->model()->index(rows,0),q_r_name); + ui->regions_table->model()->setData(ui->regions_table->model()->index(rows,1),q_r_froot); + ui->regions_table->model()->setData(ui->regions_table->model()->index(rows,2),r.electron_cut); + ui->regions_table->model()->setData(ui->regions_table->model()->index(rows,3),r.proton_cut); + ui->regions_table->model()->setData(ui->regions_table->model()->index(rows,4),r.positron_cut); + ui->regions_table->model()->setData(ui->regions_table->model()->index(rows,5),r.gamma_cut); + + + } + + magnetic_field_type = j_load["Magnetic Field Type"]; + + if(magnetic_field_type == "Fixed Axial") + { + ui->lE_fixed_MF->setEnabled(true); + ui->cB_magnetic_field->setCurrentIndex(0); + // magnetic_field = j_load["Magnetic Field Intensity"]; + //ui->lE_fixed_MF->setText(QString::fromUtf8(magnetic_field.c_str())); + + + magnetic_field_plugin_file = ""; + // ui->lE_magnetic_field_map->clear(); + // ui->lE_magnetic_field_map->setEnabled(false); + magnetic_field_map = ""; + ui->pB_magnetic_field_map->setEnabled(false); + ui->pB_magnetic_field_plugin->setEnabled(false); + + } + + else{ + ui->pB_magnetic_field_map->setEnabled(true); + ui->pB_magnetic_field_plugin->setEnabled(true); + ui->cB_magnetic_field->setCurrentIndex(1); + magnetic_field_plugin_file = j_load["Magnetic Field Plugin"]; + magnetic_field_map = j_load["Magnetic Field Map"]; + // ui->lE_magnetic_field_map->setText(QString::fromUtf8(magnetic_field_map.c_str())); + + magnetic_field = ""; + ui->lE_fixed_MF->clear(); + ui->lE_fixed_MF->setEnabled(false); + + + } + + //g4ui_model->removeRows(0,g4ui_model->rowCount()); + ui->cB_control->setCheckState(Qt::Unchecked); + ui->cB_event->setCheckState(Qt::Unchecked); + ui->cB_run->setCheckState(Qt::Unchecked); + ui->cB_tracking->setCheckState(Qt::Unchecked); + ui->sB_control->setValue(0); + ui->sB_event->setValue(0); + ui->sB_run->setValue(0); + ui->sB_tracking->setValue(0); + + for(const auto& element : j_load["g4ui_commands"]) + { + std::string g4ui_comm = element; + + + if(g4ui_comm.find("/run/verbose") != std::string::npos) + { + ui->cB_run->setCheckState(Qt::Checked); + int verbosity = g4ui_comm.back() - '0'; + ui->sB_run->setValue(verbosity); + + } + + else if(g4ui_comm.find("/control/verbose") != std::string::npos) + { + ui->cB_control->setCheckState(Qt::Checked); + int verbosity = g4ui_comm.back() - '0'; + ui->sB_control->setValue(verbosity); + + } + + else if(g4ui_comm.find("/event/verbose") != std::string::npos) + { + ui->cB_event->setCheckState(Qt::Checked); + int verbosity = g4ui_comm.back() - '0'; + ui->sB_event->setValue(verbosity); + + } + + else if(g4ui_comm.find("/tracking/verbose") != std::string::npos) + { + ui->cB_tracking->setCheckState(Qt::Checked); + int verbosity = g4ui_comm.back() - '0'; + ui->sB_tracking->setValue(verbosity); + + } + + else if(g4ui_comm.find("/FSLdet/setField") != std::string::npos) + + { + magnetic_field = g4ui_comm.substr(17,g4ui_comm.size()-17-6); + ui->lE_fixed_MF->setText(QString::fromUtf8(magnetic_field.c_str())); + } + + else if(g4ui_comm.find("/FSLgun/particle") != std::string::npos) + { + particle = g4ui_comm.substr(17,g4ui_comm.size()-16); + ui->cB_particle->setCurrentText(QString::fromUtf8(particle.c_str())); + } + + else if(g4ui_comm.find("/run/numberOfThreads") != std::string::npos) + { + number_of_threads = stoi(g4ui_comm.substr(21,g4ui_comm.size()-20)); + if(generator!="HepMC3 File"){ui->sB_NOT->setValue(number_of_threads);} + } + + else if(g4ui_comm.find("/FSLgun/primaryPerEvt") != std::string::npos) + { + number_of_primaries_per_event = stoi(g4ui_comm.substr(22,g4ui_comm.size()-21)); + } + + else if(g4ui_comm.find("/FSLgun/energy") != std::string::npos + || g4ui_comm.find("/FSLgun/direction") != std::string::npos + || g4ui_comm.find("/control/cout/prefixString G4Worker_") != std::string::npos + || g4ui_comm.find("/run/initialize") != std::string::npos + || g4ui_comm.find("/run/beamOn") != std::string::npos) + { + + } + + else + { + // QString q_g4ui_comm = QString::fromUtf8(g4ui_comm.c_str()); + // g4ui_model->insertRow(g4ui_model->rowCount()); + // QModelIndex g4ui_index = g4ui_model->index(g4ui_model->rowCount()-1); + //g4ui_model->setData(g4ui_index, q_g4ui_comm); + } + + + } + + /* user_action_model->removeRows(0,user_action_model->rowCount()); + for(const auto& element : j_load["Run Actions"]) + { + std::string run_file = element; + QString q_run_file = QString::fromUtf8(run_file.c_str()); + int rows = ui->user_action_table->model()->rowCount(); + ui->user_action_table->model()->insertRows(rows,1); + ui->user_action_table->model()->setData(ui->user_action_table->model()->index(rows,0),"Run"); + ui->user_action_table->model()->setData(ui->user_action_table->model()->index(rows,1),q_run_file); + + } + + for(const auto& element : j_load["Event Actions"]) + { + std::string event_file = element; + QString q_event_file = QString::fromUtf8(event_file.c_str()); + int rows = ui->user_action_table->model()->rowCount(); + ui->user_action_table->model()->insertRows(rows,1); + ui->user_action_table->model()->setData(ui->user_action_table->model()->index(rows,0),"Event"); + ui->user_action_table->model()->setData(ui->user_action_table->model()->index(rows,1),q_event_file); + + } + + for(const auto& element : j_load["Stepping Actions"]) + { + std::string stepping_file = element; + QString q_stepping_file = QString::fromUtf8(stepping_file.c_str()); + int rows = ui->user_action_table->model()->rowCount(); + ui->user_action_table->model()->insertRows(rows,1); + ui->user_action_table->model()->setData(ui->user_action_table->model()->index(rows,0),"Stepping"); + ui->user_action_table->model()->setData(ui->user_action_table->model()->index(rows,1),q_stepping_file); + + } + + for(const auto& element : j_load["Stacking Actions"]) + { + std::string stacking_file = element; + QString q_stacking_file = QString::fromUtf8(stacking_file.c_str()); + int rows = ui->user_action_table->model()->rowCount(); + ui->user_action_table->model()->insertRows(rows,1); + ui->user_action_table->model()->setData(ui->user_action_table->model()->index(rows,0),"Stacking"); + ui->user_action_table->model()->setData(ui->user_action_table->model()->index(rows,1),q_stacking_file); + + } + + for(const auto& element : j_load["Tracking Actions"]) + { + std::string tracking_file = element; + QString q_tracking_file = QString::fromUtf8(tracking_file.c_str()); + int rows = ui->user_action_table->model()->rowCount(); + ui->user_action_table->model()->insertRows(rows,1); + ui->user_action_table->model()->setData(ui->user_action_table->model()->index(rows,0),"Tracking"); + ui->user_action_table->model()->setData(ui->user_action_table->model()->index(rows,1),q_tracking_file); + + } + */ + + /* shape_model->removeRows(0,shape_model->rowCount()); + for(const auto& element : j_load["Shape Extensions"] ) { std::string ele = element; QString q_element = QString::fromUtf8(ele.c_str()); - sens_det_model->insertRow(sens_det_model->rowCount()); - QModelIndex sens_det_index = sens_det_model->index(sens_det_model->rowCount()-1); - sens_det_model->setData(sens_det_index, q_element); + shape_model->insertRow(shape_model->rowCount()); + QModelIndex shape_index = shape_model->index(shape_model->rowCount()-1); + shape_model->setData(shape_index, q_element); + }*/ + + + user_action_model->removeRows(0,user_action_model->rowCount()); + for(const auto& element : j_load["User Action Extensions"]) + { + std::string run_file = element; + QString q_run_file = QString::fromUtf8(run_file.c_str()); + int rows = ui->user_action_table->model()->rowCount(); + ui->user_action_table->model()->insertRows(rows,1); + ui->user_action_table->model()->setData(ui->user_action_table->model()->index(rows,0),q_run_file); + + } + +} + +} + + +//Function to load configuration from Command Line +void FSLMainWindow::load_configuration_CL(std::string config_file_path) +{ + config_file_name = config_file_path; + + if(config_file_name.find(".json") != std::string::npos) + { + std::ifstream ifs(config_file_name); + auto j_load = nlohmann::json::parse(ifs); + + // QFileInfo file(QString::fromUtf8(load_file_name.c_str())); + ui->lE_CFN->setText(("Config file: " + config_file_name).c_str()); + ui->lE_CFN->adjustSize(); + + geom_file_address = j_load["Geometry"]; + + ui->le_GI->setText(geom_file_address.c_str()); + ui->le_GI->adjustSize(); + + + physics_list_name = j_load["Physics list name"]; + ui->lE_PLN->setText(QString::fromUtf8(physics_list_name.c_str())); + + // number_of_threads = j_load["Number of threads"]; + // ui->sB_NOT->setValue(number_of_threads); + + number_of_events = j_load["Number of events"]; + ui->sB_NOE->setValue(number_of_events); + + // magnetic_field = j_load["Magnetic Field Intensity"]; + // ui->lE_fixed_MF->setText(QString::fromUtf8(magnetic_field.c_str())); + + + generator = j_load["Generator"]; + + if(generator=="Particle Gun") + { + ui->sB_NOT->setEnabled(true); + + ui->cB_gen_options->setCurrentIndex(0); + + ui->cB_particle->setEnabled(true); + ui->lE_px->setEnabled(true); + ui->lE_py->setEnabled(true); + ui->lE_pz->setEnabled(true); + + // particle = j_load["Particle"]; + // ui->cB_particle->setCurrentText(QString::fromUtf8(particle.c_str())); + + p_x = j_load["p_x"]; + p_y = j_load["p_y"]; + p_z = j_load["p_z"]; + + ui->lE_px->setText(QString::number(p_x)); + ui->lE_py->setText(QString::number(p_y)); + ui->lE_pz->setText(QString::number(p_z)); + + + ui->cB_pythia_type_of_eve->setCurrentIndex(0); + ui->pB_pythia_browse->setEnabled(false); + ui->cB_pythia_type_of_eve->setEnabled(false); + + ui->cB_hepmc3_type_of_eve->setCurrentIndex(0); + ui->pB_hepmc3_browse_files->setEnabled(false); + ui->cB_hepmc3_type_of_eve->setEnabled(false); + + ui->pB_gen_plug_browse_files->setEnabled(false); + + + } + + else if(generator=="Pythia") + { + ui->sB_NOT->setEnabled(true); + + ui->cB_gen_options->setCurrentIndex(1); + + ui->cB_pythia_type_of_eve->setEnabled(true); + + pythia_type_of_event = j_load["Pythia type of event"]; + + if(pythia_type_of_event != "") + { + ui->cB_pythia_type_of_eve->setCurrentText(QString::fromUtf8(pythia_type_of_event.c_str())); + ui->pB_pythia_browse->setEnabled(false); + + } + else + { + pythia_input_file = j_load["Pythia event input file"]; + ui->cB_pythia_type_of_eve->setCurrentIndex(3); + ui->pB_pythia_browse->setEnabled(true); + + } + + + + ui->lE_px->clear(); + ui->lE_py->clear(); + ui->lE_pz->clear(); + ui->cB_particle->setCurrentIndex(0); + ui->cB_particle->setEnabled(false); + ui->lE_px->setEnabled(false); + ui->lE_py->setEnabled(false); + ui->lE_pz->setEnabled(false); + + ui->cB_hepmc3_type_of_eve->setCurrentIndex(0); + ui->pB_hepmc3_browse_files->setEnabled(false); + ui->cB_hepmc3_type_of_eve->setEnabled(false); + + ui->pB_gen_plug_browse_files->setEnabled(false); + + + } + + else if(generator=="HepMC3 File") + { + ui->sB_NOT->setValue(1); + ui->sB_NOT->setEnabled(false); + + ui->cB_gen_options->setCurrentIndex(2); + ui->pB_hepmc3_browse_files->setEnabled(true); + ui->cB_hepmc3_type_of_eve->setEnabled(true); + + hepmc3_type_of_file = j_load["HepMC3 type of file"]; + hepmc3_input_file = j_load["HepMC3 file"]; + + ui->cB_hepmc3_type_of_eve->setCurrentText(QString::fromUtf8(hepmc3_type_of_file.c_str())); + + ui->lE_px->clear(); + ui->lE_py->clear(); + ui->lE_pz->clear(); + ui->cB_particle->setCurrentIndex(0); + ui->cB_particle->setEnabled(false); + ui->lE_px->setEnabled(false); + ui->lE_py->setEnabled(false); + ui->lE_pz->setEnabled(false); + + ui->cB_pythia_type_of_eve->setCurrentIndex(0); + ui->pB_pythia_browse->setEnabled(false); + ui->cB_pythia_type_of_eve->setEnabled(false); + + ui->pB_gen_plug_browse_files->setEnabled(false); + + + } + + else if(generator=="Generator Plugin") + { + ui->sB_NOT->setEnabled(true); + + ui->cB_gen_options->setCurrentIndex(3); + ui->pB_gen_plug_browse_files->setEnabled(true); + generator_plugin = j_load["Generator Plugin"]; + + ui->lE_px->clear(); + ui->lE_py->clear(); + ui->lE_pz->clear(); + ui->cB_particle->setCurrentIndex(0); + ui->cB_particle->setEnabled(false); + ui->lE_px->setEnabled(false); + ui->lE_py->setEnabled(false); + ui->lE_pz->setEnabled(false); + + ui->cB_pythia_type_of_eve->setCurrentIndex(0); + ui->pB_pythia_browse->setEnabled(false); + ui->cB_pythia_type_of_eve->setEnabled(false); + + ui->cB_hepmc3_type_of_eve->setCurrentIndex(0); + ui->pB_hepmc3_browse_files->setEnabled(false); + ui->cB_hepmc3_type_of_eve->setEnabled(false); + + + } + + sens_det_model->removeRows(0,sens_det_model->rowCount()); + for(const auto& element : j_load["Sensitive Detector Extensions"]) + { + std::string sens_det_file = element; + QString q_sens_det_file = QString::fromUtf8(sens_det_file.c_str()); + int rows = ui->sens_det_table->model()->rowCount(); + ui->sens_det_table->model()->insertRows(rows,1); + ui->sens_det_table->model()->setData(ui->sens_det_table->model()->index(rows,0),q_sens_det_file); + } region_model->removeRows(0,region_model->rowCount()); @@ -1148,8 +1808,8 @@ void FSLMainWindow::load_configuration() { ui->lE_fixed_MF->setEnabled(true); ui->cB_magnetic_field->setCurrentIndex(0); - magnetic_field = j_load["Magnetic Field Intensity"]; - ui->lE_fixed_MF->setText(QString::fromUtf8(magnetic_field.c_str())); + // magnetic_field = j_load["Magnetic Field Intensity"]; + //ui->lE_fixed_MF->setText(QString::fromUtf8(magnetic_field.c_str())); magnetic_field_plugin_file = ""; @@ -1176,7 +1836,7 @@ void FSLMainWindow::load_configuration() } - g4ui_model->removeRows(0,g4ui_model->rowCount()); + //g4ui_model->removeRows(0,g4ui_model->rowCount()); ui->cB_control->setCheckState(Qt::Unchecked); ui->cB_event->setCheckState(Qt::Unchecked); ui->cB_run->setCheckState(Qt::Unchecked); @@ -1223,14 +1883,33 @@ void FSLMainWindow::load_configuration() } - else if(g4ui_comm.find("/FSLdet/setField") != std::string::npos - || g4ui_comm.find("/FSLgun/primaryPerEvt") != std::string::npos - || g4ui_comm.find("/FSLgun/energy") != std::string::npos - || g4ui_comm.find("/FSLgun/particle") != std::string::npos + else if(g4ui_comm.find("/FSLdet/setField") != std::string::npos) + + { + magnetic_field = g4ui_comm.substr(17,g4ui_comm.size()-17-6); + ui->lE_fixed_MF->setText(QString::fromUtf8(magnetic_field.c_str())); + } + + else if(g4ui_comm.find("/FSLgun/particle") != std::string::npos) + { + particle = g4ui_comm.substr(17,g4ui_comm.size()-16); + ui->cB_particle->setCurrentText(QString::fromUtf8(particle.c_str())); + } + + else if(g4ui_comm.find("/run/numberOfThreads") != std::string::npos) + { + number_of_threads = stoi(g4ui_comm.substr(21,g4ui_comm.size()-20)); + if(generator!="HepMC3 File"){ui->sB_NOT->setValue(number_of_threads);} + } + + else if(g4ui_comm.find("/FSLgun/primaryPerEvt") != std::string::npos) + { + number_of_primaries_per_event = stoi(g4ui_comm.substr(22,g4ui_comm.size()-21)); + } + + else if(g4ui_comm.find("/FSLgun/energy") != std::string::npos || g4ui_comm.find("/FSLgun/direction") != std::string::npos - || g4ui_comm.find("/run/numberOfThreads") != std::string::npos || g4ui_comm.find("/control/cout/prefixString G4Worker_") != std::string::npos - || g4ui_comm.find("/process/list") != std::string::npos || g4ui_comm.find("/run/initialize") != std::string::npos || g4ui_comm.find("/run/beamOn") != std::string::npos) { @@ -1239,15 +1918,16 @@ void FSLMainWindow::load_configuration() else { - QString q_g4ui_comm = QString::fromUtf8(g4ui_comm.c_str()); - g4ui_model->insertRow(g4ui_model->rowCount()); - QModelIndex g4ui_index = g4ui_model->index(g4ui_model->rowCount()-1); - g4ui_model->setData(g4ui_index, q_g4ui_comm); + // QString q_g4ui_comm = QString::fromUtf8(g4ui_comm.c_str()); + //g4ui_model->insertRow(g4ui_model->rowCount()); + // QModelIndex g4ui_index = g4ui_model->index(g4ui_model->rowCount()-1); + //g4ui_model->setData(g4ui_index, q_g4ui_comm); } } + /* user_action_model->removeRows(0,user_action_model->rowCount()); for(const auto& element : j_load["Run Actions"]) { @@ -1328,6 +2008,7 @@ void FSLMainWindow::load_configuration() } } + else {std::cout << "File must be of json type" << std::endl; exit(-1);} } @@ -1338,33 +2019,37 @@ void FSLMainWindow::create_configuration() number_of_events = ui->sB_NOE->value(); number_of_threads = ui->sB_NOT->value(); physics_list_name = (ui->lE_PLN->text()).toStdString(); - hits_file = (ui->lE_hits->text()).toStdString(); - histo_file = (ui->lE_histo->text()).toStdString(); + // hits_file = (ui->lE_hits->text()).toStdString(); + // histo_file = (ui->lE_histo->text()).toStdString(); j["Geometry"] = geom_file_address; j["Physics list name"] = physics_list_name; - j["Number of threads"] = number_of_threads; + // j["Number of threads"] = number_of_threads; j["Number of events"] = number_of_events; this->configure_generator(); j["Generator"] = generator; - j["Particle"] = particle; + // j["Particle"] = particle; j["p_x"] = p_x; j["p_y"] = p_y; j["p_z"] = p_z; - j["Particle energy"] = particle_energy; - j["Particle direction"] = particle_direction; - j["Event input file"] = pythia_input_file; - j["Type of event"] = pythia_type_of_event; +// j["Particle energy"] = particle_energy; +// j["Particle direction"] = particle_direction; + j["Pythia event input file"] = pythia_input_file; + j["Pythia type of event"] = pythia_type_of_event; + j["HepMC3 file"] = hepmc3_input_file; + j["HepMC3 type of file"] = hepmc3_type_of_file; + j["Generator Plugin"] = generator_plugin; + this->configure_sens_det_actions(); j["Sensitive Detector Extensions"] = sensitive_detector_extensions; - j["Output Hits file"] = hits_file; - j["Output Histo file"] = histo_file; + // j["Output Hits file"] = hits_file; + // j["Output Histo file"] = histo_file; this->configure_magnetic_field(); j["Magnetic Field Type"] = magnetic_field_type; - j["Magnetic Field Intensity"] = magnetic_field; + // j["Magnetic Field Intensity"] = magnetic_field; j["Magnetic Field Map"] = magnetic_field_map; j["Magnetic Field Plugin"] = magnetic_field_plugin_file; diff --git a/FSL/src/fsl_mainwindow.h b/FSL/src/fsl_mainwindow.h index e0879c1765babefc46796a68d9cdb5b71bfe6cdf..78b0f30d14eea02c61ba205b9d00d31310ab821a 100644 --- a/FSL/src/fsl_mainwindow.h +++ b/FSL/src/fsl_mainwindow.h @@ -66,7 +66,8 @@ public: int number_of_events = 0; std::string config_file_name = ""; std::string save_directory = ""; - + std::string save_display_directory = ""; + //Parameters associated with the Generator tab std::string generator = ""; std::string particle = ""; @@ -81,12 +82,16 @@ public: int number_of_primaries_per_event; std::string pythia_input_file = ""; std::string pythia_type_of_event = ""; + + std::string hepmc3_input_file = ""; + std::string hepmc3_type_of_file = ""; + std::string generator_plugin = ""; //Parameters associated with the Sensitive Detectors tab std::vector<std::string> sensitive_detector_extensions; - int sens_det_number; - std::string hits_file = ""; - std::string histo_file = ""; + //int sens_det_number; + // std::string hits_file = ""; + // std::string histo_file = ""; //Parameters associated with the Magnetic field tab std::string magnetic_field_type = ""; @@ -104,7 +109,7 @@ public: //Parameters associated with the g4ui commands tab std::vector<std::string> g4ui_commands; - int g4ui_number; + // int g4ui_number; //Parameters associated with the shape commands tab // int shape_number; @@ -124,12 +129,14 @@ public: //Functions used in Configuration void save_configuration(); void save_configuration_as(); + void save_display_output(); void create_configuration(); void view_configuration(); void run_configuration(); void run_gmex(); void run_gmclash(); void load_configuration(); + void load_configuration_CL(std::string config_file_path); //Load configuration from Command Line std::vector<std::string> display_configuration(const std::string &s); void clear_main_status(); @@ -140,8 +147,8 @@ public: void del_sens_det(); void configure_sens_det_actions(); - void add_g4ui(); - void del_g4ui(); + // void add_g4ui(); + // void del_g4ui(); void configure_g4ui_command(); void pop_up_regions(); @@ -159,6 +166,9 @@ public: // void configure_shape_ext(); void assign_geom_file(); + void assign_phys_list_plugin(); + void assign_gen_plug_file(); + void assign_hepmc3_file(); void assign_pythia_file(); void assign_magnetic_field_plugin_file(); void assign_magnetic_field_map(); @@ -187,9 +197,9 @@ signals: void send_error_message(std::string info); private slots: - void catch_error_message(std::string info); - void get_sens_det_index(QModelIndex region_index); - void get_g4ui_index(QModelIndex g4ui_index); + // void catch_error_message(std::string info); + // void get_sens_det_index(QModelIndex region_index); + // void get_g4ui_index(QModelIndex g4ui_index); // void get_shape_index(QModelIndex g4ui_index); void add_region(std::string region_name, std::string frootLV_names ,double electron_cut , double proton_cut @@ -209,14 +219,16 @@ private slots: private: Ui::FSLMainWindow *ui; - QStringListModel *sens_det_model; - QStringListModel *g4ui_model; + // QStringListModel *sens_det_model; + // QStringListModel *g4ui_model; // QStringListModel *shape_model; ConfigRegions *region; QStandardItemModel *region_model; QStandardItemModel *user_action_model; + QStandardItemModel *sens_det_model; QStringList region_horizontalHeader; QStringList user_action_horizontalHeader; + QStringList sens_det_horizontalHeader; QDoubleValidator *p_x_validator; QDoubleValidator *p_y_validator; QDoubleValidator *p_z_validator; diff --git a/FSL/src/fsl_mainwindow.ui b/FSL/src/fsl_mainwindow.ui index cdfe65a92fbf2fa200996073a66a4fbe6c09ad26..030dc0f7011f2d95edd1658231526986a7cb8d09 100644 --- a/FSL/src/fsl_mainwindow.ui +++ b/FSL/src/fsl_mainwindow.ui @@ -6,7 +6,7 @@ <rect> <x>0</x> <y>0</y> - <width>1261</width> + <width>1355</width> <height>726</height> </rect> </property> @@ -35,133 +35,24 @@ <attribute name="title"> <string>Main</string> </attribute> - <layout class="QGridLayout" name="gridLayout_10"> - <item row="1" column="0" colspan="2"> - <widget class="QTextBrowser" name="tB_view_config"> - <property name="textInteractionFlags"> - <set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QGroupBox" name="groupBox_3"> - <property name="font"> - <font> - <pointsize>15</pointsize> - </font> - </property> + <layout class="QGridLayout" name="gridLayout_15"> + <item row="3" column="0" colspan="2"> + <widget class="QGroupBox" name="groupBox_11"> <property name="title"> <string/> </property> - <layout class="QGridLayout" name="gridLayout_9"> - <item row="2" column="0"> - <widget class="QPushButton" name="pB_geom"> - <property name="text"> - <string>Geometry input</string> - </property> - </widget> - </item> - <item row="0" column="0" colspan="2"> - <widget class="QLabel" name="lE_CFN"> - <property name="text"> - <string/> - </property> - <property name="scaledContents"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="6" column="0"> - <widget class="QLabel" name="label_2"> - <property name="font"> - <font> - <pointsize>15</pointsize> - </font> - </property> - <property name="text"> - <string>Number of Events</string> - </property> - </widget> - </item> - <item row="6" column="1"> - <widget class="QSpinBox" name="sB_NOE"/> - </item> - <item row="4" column="1"> - <widget class="QSpinBox" name="sB_NOT"/> - </item> - <item row="2" column="1"> - <widget class="QLabel" name="le_GI"> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="label"> - <property name="font"> - <font> - <pointsize>15</pointsize> - </font> - </property> - <property name="text"> - <string>Physics List Name</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QLineEdit" name="lE_PLN"/> - </item> - <item row="4" column="0"> - <widget class="QLabel" name="label_3"> - <property name="font"> - <font> - <pointsize>15</pointsize> - </font> - </property> + <layout class="QGridLayout" name="gridLayout_10"> + <item row="0" column="4"> + <widget class="QCommandLinkButton" name="pB_gmex"> <property name="text"> - <string>Number of Threads</string> + <string>Gmex</string> </property> </widget> </item> - </layout> - </widget> - </item> - <item row="2" column="0"> - <widget class="QGroupBox" name="groupBox_11"> - <property name="title"> - <string/> - </property> - <layout class="QGridLayout" name="gridLayout_13"> - <item row="0" column="0"> - <spacer name="horizontalSpacer_28"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>110</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="1"> - <spacer name="horizontalSpacer_32"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>109</width> - <height>17</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="2"> - <widget class="QPushButton" name="pB_view"> + <item row="0" column="6"> + <widget class="QCommandLinkButton" name="pB_Run"> <property name="text"> - <string>View</string> + <string>FullSimLight</string> </property> </widget> </item> @@ -178,57 +69,260 @@ </property> </spacer> </item> - <item row="0" column="4"> - <widget class="QPushButton" name="pB_main_clear"> + <item row="0" column="1"> + <widget class="QPushButton" name="pB_save_config"> <property name="text"> - <string>Clear</string> + <string>Save Configuration</string> </property> </widget> </item> - <item row="0" column="5"> - <spacer name="horizontalSpacer_26"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>58</width> - <height>17</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="6"> - <widget class="QCommandLinkButton" name="pB_gmex"> + <item row="0" column="2"> + <widget class="QPushButton" name="pB_view"> <property name="text"> - <string>Gmex</string> + <string>View Configuration</string> </property> </widget> </item> - <item row="0" column="7"> + <item row="0" column="5"> <widget class="QCommandLinkButton" name="pB_gmclash"> <property name="text"> <string>Gmclash</string> </property> </widget> </item> - <item row="0" column="8"> - <widget class="QCommandLinkButton" name="pB_Run"> + <item row="0" column="0"> + <widget class="QPushButton" name="pB_main_clear"> <property name="text"> - <string>FullSimLight</string> + <string>Clear</string> </property> </widget> </item> </layout> </widget> </item> + <item row="0" column="0" rowspan="3" colspan="2"> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QGridLayout" name="gridLayout_11"> + <item row="0" column="0" rowspan="2"> + <widget class="QGroupBox" name="groupBox_3"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> + <property name="title"> + <string/> + </property> + <layout class="QGridLayout" name="gridLayout_9"> + <item row="0" column="0"> + <widget class="QLabel" name="lE_CFN"> + <property name="text"> + <string/> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QPushButton" name="pB_geom"> + <property name="text"> + <string>Geometry input</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="le_GI"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> + <property name="text"> + <string>Physics List Name</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="lE_PLN"/> + </item> + <item row="2" column="2"> + <widget class="QPushButton" name="pB_browse_phys_list"> + <property name="text"> + <string>+</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_3"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> + <property name="text"> + <string>Number of Threads</string> + </property> + </widget> + </item> + <item row="3" column="1" colspan="2"> + <widget class="QSpinBox" name="sB_NOT"/> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_2"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> + <property name="text"> + <string>Number of Events</string> + </property> + </widget> + </item> + <item row="4" column="1" colspan="2"> + <widget class="QSpinBox" name="sB_NOE"/> + </item> + </layout> + </widget> + </item> + <item row="0" column="1"> + <widget class="QGroupBox" name="groupBox_8"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> + <property name="title"> + <string/> + </property> + <layout class="QGridLayout" name="gridLayout_12"> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="verticalLayout_7"> + <item> + <widget class="QLabel" name="label_26"> + <property name="font"> + <font> + <pointsize>16</pointsize> + </font> + </property> + <property name="text"> + <string>G4Ui Commands</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_36"> + <property name="font"> + <font> + <pointsize>16</pointsize> + </font> + </property> + <property name="text"> + <string>Verbosity </string> + </property> + </widget> + </item> + </layout> + </item> + <item row="0" column="1"> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QCheckBox" name="cB_control"> + <property name="text"> + <string> Control</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="sB_control"/> + </item> + </layout> + </item> + <item row="0" column="2"> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QCheckBox" name="cB_event"> + <property name="text"> + <string> Event</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="sB_event"/> + </item> + </layout> + </item> + <item row="0" column="3"> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QCheckBox" name="cB_run"> + <property name="text"> + <string> Run</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="sB_run"/> + </item> + </layout> + </item> + <item row="0" column="4"> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <item> + <widget class="QCheckBox" name="cB_tracking"> + <property name="text"> + <string> Tracking</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="sB_tracking"/> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </item> + <item> + <widget class="BetterTextBrowser" name="tB_view_config"> + <property name="textInteractionFlags"> + <set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + </layout> + </item> + <item row="1" column="0"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>18</height> + </size> + </property> + </spacer> + </item> </layout> </widget> <widget class="QWidget" name="generator"> <attribute name="title"> <string>Generator</string> </attribute> - <layout class="QGridLayout" name="gridLayout_8"> + <layout class="QGridLayout" name="gridLayout_14"> <item row="0" column="0"> <widget class="QLabel" name="label_11"> <property name="font"> @@ -267,7 +361,7 @@ </property> </spacer> </item> - <item row="1" column="4"> + <item row="1" column="3"> <widget class="QGroupBox" name="groupBox_2"> <property name="font"> <font> @@ -293,12 +387,22 @@ <string>Pythia</string> </property> </item> + <item> + <property name="text"> + <string>HepMC3 File</string> + </property> + </item> + <item> + <property name="text"> + <string>Generator Plugin</string> + </property> + </item> </widget> </item> </layout> </widget> </item> - <item row="1" column="5"> + <item row="1" column="4"> <spacer name="horizontalSpacer_22"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -374,6 +478,11 @@ <string>geantino</string> </property> </item> + <item> + <property name="text"> + <string>gamma</string> + </property> + </item> </widget> </item> <item row="1" column="0" colspan="2"> @@ -472,7 +581,7 @@ </layout> </widget> </item> - <item row="2" column="3"> + <item row="2" column="3" rowspan="2"> <spacer name="verticalSpacer_3"> <property name="orientation"> <enum>Qt::Vertical</enum> @@ -485,20 +594,7 @@ </property> </spacer> </item> - <item row="3" column="0" colspan="2"> - <spacer name="horizontalSpacer_4"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>122</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="3" column="5" rowspan="2"> + <item row="2" column="4"> <widget class="QGroupBox" name="groupBox_5"> <property name="font"> <font> @@ -567,282 +663,163 @@ </layout> </widget> </item> - <item row="4" column="3" colspan="2"> - <spacer name="horizontalSpacer_5"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>186</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="4" column="6"> - <spacer name="horizontalSpacer_20"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>104</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="5" column="2"> - <spacer name="verticalSpacer_10"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>32</height> - </size> - </property> - </spacer> - </item> - <item row="5" column="5"> - <spacer name="verticalSpacer_11"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>32</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <widget class="QWidget" name="G4UI"> - <attribute name="title"> - <string>G4UI</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_14"> - <item row="0" column="0" colspan="2"> - <widget class="QGroupBox" name="groupBox_8"> + <item row="3" column="4"> + <widget class="QGroupBox" name="groupBox_10"> <property name="font"> <font> <pointsize>15</pointsize> </font> </property> <property name="title"> - <string>Set Commands</string> + <string>HepMC3</string> </property> - <layout class="QGridLayout" name="gridLayout_12"> + <layout class="QGridLayout" name="gridLayout_7"> <item row="0" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_7"> - <item> - <widget class="QLabel" name="label_26"> - <property name="font"> - <font> - <pointsize>16</pointsize> - </font> - </property> - <property name="text"> - <string>G4Ui Commands</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="label_36"> - <property name="font"> - <font> - <pointsize>16</pointsize> - </font> - </property> - <property name="text"> - <string>Set Verbosity</string> - </property> - </widget> - </item> - </layout> + <widget class="QLabel" name="label_16"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> + <property name="text"> + <string>HepMC3 Event File</string> + </property> + </widget> </item> <item row="0" column="1"> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <item> - <widget class="QCheckBox" name="cB_control"> - <property name="text"> - <string> Control</string> - </property> - </widget> - </item> - <item> - <widget class="QSpinBox" name="sB_control"/> - </item> - </layout> - </item> - <item row="0" column="2"> - <layout class="QVBoxLayout" name="verticalLayout_4"> - <item> - <widget class="QCheckBox" name="cB_event"> - <property name="text"> - <string> Event</string> - </property> - </widget> - </item> - <item> - <widget class="QSpinBox" name="sB_event"/> - </item> - </layout> + <widget class="QPushButton" name="pB_hepmc3_browse_files"> + <property name="text"> + <string>Browse Files</string> + </property> + </widget> </item> - <item row="0" column="3"> - <layout class="QVBoxLayout" name="verticalLayout_5"> - <item> - <widget class="QCheckBox" name="cB_run"> - <property name="text"> - <string> Run</string> - </property> - </widget> - </item> - <item> - <widget class="QSpinBox" name="sB_run"/> - </item> - </layout> + <item row="1" column="0"> + <widget class="QLabel" name="label_17"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> + <property name="text"> + <string>File Format</string> + </property> + </widget> </item> - <item row="0" column="4"> - <layout class="QVBoxLayout" name="verticalLayout_6"> + <item row="1" column="1"> + <widget class="QComboBox" name="cB_hepmc3_type_of_eve"> <item> - <widget class="QCheckBox" name="cB_tracking"> - <property name="text"> - <string> Tracking</string> - </property> - </widget> + <property name="text"> + <string>Ascii</string> + </property> </item> <item> - <widget class="QSpinBox" name="sB_tracking"/> + <property name="text"> + <string>Asciiv3</string> + </property> </item> - </layout> + </widget> </item> </layout> </widget> </item> - <item row="4" column="0" rowspan="2"> - <widget class="QGroupBox" name="groupBox_9"> + <item row="4" column="0" colspan="2"> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>122</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="4" column="4" rowspan="2"> + <widget class="QGroupBox" name="groupBox_12"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> <property name="title"> - <string/> + <string>Plugin</string> </property> - <layout class="QGridLayout" name="gridLayout_15"> + <layout class="QGridLayout" name="gridLayout_8"> <item row="0" column="0"> - <widget class="QPushButton" name="pB_add_g4ui"> + <widget class="QLabel" name="label_18"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> <property name="text"> - <string>Add Command</string> + <string>Generator Plugin</string> </property> </widget> </item> <item row="0" column="1"> - <widget class="QLineEdit" name="lE_g4ui"/> + <widget class="QPushButton" name="pB_gen_plug_browse_files"> + <property name="text"> + <string>Browse Files</string> + </property> + </widget> </item> </layout> </widget> </item> - <item row="3" column="0" colspan="6"> - <widget class="QListView" name="g4ui_view"/> - </item> - <item row="1" column="3" colspan="3"> - <spacer name="horizontalSpacer_11"> + <item row="5" column="3"> + <spacer name="horizontalSpacer_5"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> - <width>361</width> + <width>186</width> <height>20</height> </size> </property> </spacer> </item> <item row="5" column="5"> - <spacer name="verticalSpacer_6"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>58</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="2"> - <spacer name="verticalSpacer_5"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>108</height> - </size> - </property> - </spacer> - </item> - <item row="4" column="4"> - <spacer name="horizontalSpacer_12"> + <spacer name="horizontalSpacer_20"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> - <width>275</width> + <width>104</width> <height>20</height> </size> </property> </spacer> </item> - <item row="4" column="3" rowspan="2"> - <spacer name="verticalSpacer_4"> + <item row="6" column="2"> + <spacer name="verticalSpacer_10"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>20</width> - <height>95</height> + <height>32</height> </size> </property> </spacer> </item> - <item row="4" column="5"> - <widget class="QPushButton" name="pB_del_g4ui"> - <property name="text"> - <string>−</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <spacer name="horizontalSpacer_9"> + <item row="6" column="4"> + <spacer name="verticalSpacer_11"> <property name="orientation"> - <enum>Qt::Horizontal</enum> + <enum>Qt::Vertical</enum> </property> <property name="sizeHint" stdset="0"> <size> - <width>320</width> - <height>20</height> + <width>20</width> + <height>106</height> </size> </property> </spacer> </item> - <item row="1" column="1"> - <widget class="QLabel" name="label_45"> - <property name="font"> - <font> - <pointsize>16</pointsize> - </font> - </property> - <property name="text"> - <string>Additional G4Ui Commands</string> - </property> - </widget> - </item> </layout> </widget> <widget class="QWidget" name="Mag_Field"> @@ -1078,44 +1055,6 @@ <string>Regions</string> </attribute> <layout class="QGridLayout" name="gridLayout_5"> - <item row="0" column="0" colspan="2"> - <spacer name="horizontalSpacer_7"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>405</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="2"> - <widget class="QLabel" name="label_43"> - <property name="font"> - <font> - <pointsize>15</pointsize> - </font> - </property> - <property name="text"> - <string>Regions</string> - </property> - </widget> - </item> - <item row="0" column="3"> - <spacer name="horizontalSpacer_8"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>458</width> - <height>20</height> - </size> - </property> - </spacer> - </item> <item row="1" column="0" colspan="4"> <widget class="QTableView" name="regions_table"/> </item> @@ -1150,70 +1089,26 @@ </property> </spacer> </item> - </layout> - </widget> - <widget class="QWidget" name="Sens_det"> - <attribute name="title"> - <string>Sensitive Detectors</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_7"> <item row="0" column="0"> - <widget class="QLabel" name="label_33"> - <property name="font"> - <font> - <pointsize>15</pointsize> - </font> - </property> - <property name="text"> - <string>Output Hits</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLineEdit" name="lE_hits"/> - </item> - <item row="0" column="2" rowspan="2"> - <spacer name="verticalSpacer_7"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>49</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_34"> + <widget class="QLabel" name="label_43"> <property name="font"> <font> <pointsize>15</pointsize> </font> </property> <property name="text"> - <string>Output Histo</string> + <string>Regions</string> </property> </widget> </item> - <item row="1" column="1"> - <widget class="QLineEdit" name="lE_histo"/> - </item> - <item row="2" column="0" colspan="2"> - <spacer name="horizontalSpacer_13"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>332</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="2" column="2"> + </layout> + </widget> + <widget class="QWidget" name="Sens_det"> + <attribute name="title"> + <string>Sensitive Detectors</string> + </attribute> + <layout class="QGridLayout" name="gridLayout_6"> + <item row="0" column="0" colspan="2"> <widget class="QLabel" name="label_27"> <property name="font"> <font> @@ -1225,23 +1120,10 @@ </property> </widget> </item> - <item row="2" column="3"> - <spacer name="horizontalSpacer_14"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>378</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="3" column="0" colspan="4"> - <widget class="QListView" name="sens_det_view"/> + <item row="1" column="0" colspan="2"> + <widget class="QTableView" name="sens_det_table"/> </item> - <item row="4" column="0"> + <item row="2" column="0"> <layout class="QHBoxLayout" name="horizontalLayout_8"> <item> <widget class="QPushButton" name="pB_add_sens_det"> @@ -1259,7 +1141,7 @@ </item> </layout> </item> - <item row="4" column="1" colspan="3"> + <item row="2" column="1"> <spacer name="horizontalSpacer_19"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -1279,20 +1161,7 @@ <string>User Actions</string> </attribute> <layout class="QGridLayout" name="gridLayout_4"> - <item row="0" column="1"> - <spacer name="horizontalSpacer_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>362</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="2"> + <item row="0" column="0" colspan="2"> <widget class="QLabel" name="label_25"> <property name="font"> <font> @@ -1304,18 +1173,8 @@ </property> </widget> </item> - <item row="0" column="3"> - <spacer name="horizontalSpacer_3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>144</width> - <height>20</height> - </size> - </property> - </spacer> + <item row="1" column="0" colspan="2"> + <widget class="QTableView" name="user_action_table"/> </item> <item row="2" column="0"> <layout class="QHBoxLayout" name="horizontalLayout_12"> @@ -1335,7 +1194,7 @@ </item> </layout> </item> - <item row="2" column="1" colspan="3"> + <item row="2" column="1"> <spacer name="horizontalSpacer_24"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -1348,9 +1207,6 @@ </property> </spacer> </item> - <item row="1" column="0" colspan="4"> - <widget class="QTableView" name="user_action_table"/> - </item> </layout> </widget> </widget> @@ -1362,7 +1218,7 @@ <rect> <x>0</x> <y>0</y> - <width>1261</width> + <width>1355</width> <height>24</height> </rect> </property> @@ -1406,6 +1262,13 @@ </property> </action> </widget> + <customwidgets> + <customwidget> + <class>BetterTextBrowser</class> + <extends>QTextBrowser</extends> + <header>../FSL/src/BetterTextBrowser.h</header> + </customwidget> + </customwidgets> <resources/> <connections/> </ui> diff --git a/FSL/src/main.cpp b/FSL/src/main.cpp index e87b71ddedc08cc2751586563e9ed6122a0c39a7..d193ee356f990bed17c8519eb059a718dd7e0352 100644 --- a/FSL/src/main.cpp +++ b/FSL/src/main.cpp @@ -1,5 +1,5 @@ #include "fsl_mainwindow.h" - +#include <iostream> #include <QApplication> int main(int argc, char *argv[]) @@ -7,6 +7,28 @@ int main(int argc, char *argv[]) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication a(argc, argv); FSLMainWindow w; + + + if(argc>1 && std::string(argv[1]) == "-c") + { + w.show(); + w.load_configuration_CL(std::string(argv[2])); + } + + else if(argc>1 && std::string(argv[1]) != "-c") + { + std::cout << std::endl; + std::cerr << "Usage:" << std::endl; + std::cerr << "fsl" << std::endl; + std::cerr << "fsl -c /path/to/ConfigFile" << std::endl; + std::cout << std::endl; + exit(-1); + } + + else + { w.show(); + } + return a.exec(); } diff --git a/FullSimLight/CMakeLists.txt b/FullSimLight/CMakeLists.txt index 4eb3ca1aca317a8e2ecf41e9793aba938ab06e08..e3cb021a129c1b867b8b7628b1aed917d1f64643 100644 --- a/FullSimLight/CMakeLists.txt +++ b/FullSimLight/CMakeLists.txt @@ -55,6 +55,10 @@ message( STATUS "Found Geant4: ${Geant4_INCLUDE_DIR}") #---------------------------------------------------------------------------- find_package(Pythia QUIET) # optional +find_package(HepMC3 REQUIRED) +#find_package(ROOT QUIET) #optional +#option(HEPMC3_ROOTIO_USE "Enable the use of HEPMC3 with ROOT" OFF) + #---------------------------------------------------------------------------- # Setup Geant4 include directories and compile definitions @@ -117,6 +121,26 @@ if(Pythia_FOUND) target_link_libraries(fullSimLight PRIVATE Pythia::Pythia) endif() +#if(HEPMC3_ROOTIO_USE) +# message( STATUS "HEPMC3 Root Dependency Switched on") +# target_link_libraries(gmclash PUBLIC ${HEPMC3_ROOTIO_LIB} ${ROOT_LIBRARIES}) + # target_link_libraries(gmmasscalc PUBLIC ${HEPMC3_ROOTIO_LIB} ${ROOT_LIBRARIES}) + # target_link_libraries(fullSimLight PUBLIC ${HEPMC3_ROOTIO_LIB} ${ROOT_LIBRARIES}) + # target_link_libraries(gmgeantino PUBLIC ${HEPMC3_ROOTIO_LIB} ${ROOT_LIBRARIES}) + # target_link_libraries(gm2gdml PUBLIC ${HEPMC3_ROOTIO_LIB} ${ROOT_LIBRARIES}) + # target_include_directories(gmclash PUBLIC ${ROOT_INCLUDE_DIRS}) + # target_include_directories(gmmasscalc PUBLIC ${ROOT_INCLUDE_DIRS}) + # target_include_directories(fullSimLight PUBLIC ${ROOT_INCLUDE_DIRS}) + # target_include_directories(gmgeantino PUBLIC ${ROOT_INCLUDE_DIRS}) + # target_include_directories(gm2gdml PUBLIC ${ROOT_INCLUDE_DIRS}) + + # target_compile_definitions(gmclash PRIVATE USE_ROOT) + #target_compile_definitions(gmmasscalc PRIVATE USE_ROOT) + # target_compile_definitions(fullSimLight PRIVATE USE_ROOT) + # target_compile_definitions(gmgeantino PRIVATE USE_ROOT) + # target_compile_definitions(gm2gdml PRIVATE USE_ROOT) +#endif() + #---------------------------------------------------------------------------- # Add extra 'include' directories # @@ -152,11 +176,17 @@ target_link_libraries(testMagneticField ${Geant4_LIBRARIES} MagFieldServices Mag #target_link_libraries(plotGeantinoMaps ${ROOT_LIBRARIES}) -target_link_libraries(gmclash PUBLIC GeoModel2G4 ${Geant4_LIBRARIES} MagFieldServices MagFieldInterfaces) -target_link_libraries(gmmasscalc PUBLIC GeoModel2G4 ${Geant4_LIBRARIES} MagFieldServices MagFieldInterfaces) -target_link_libraries(fullSimLight PUBLIC GeoModel2G4 ${Geant4_LIBRARIES} MagFieldServices MagFieldInterfaces) -target_link_libraries(gmgeantino PUBLIC GeoModel2G4 ${Geant4_LIBRARIES} MagFieldServices MagFieldInterfaces) -target_link_libraries(gm2gdml PUBLIC GeoModel2G4 ${Geant4_LIBRARIES} MagFieldServices MagFieldInterfaces) +target_link_libraries(gmclash PUBLIC GeoModel2G4 ${Geant4_LIBRARIES} MagFieldServices MagFieldInterfaces ${HEPMC3_LIB}) +target_link_libraries(gmmasscalc PUBLIC GeoModel2G4 ${Geant4_LIBRARIES} MagFieldServices MagFieldInterfaces ${HEPMC3_LIB}) +target_link_libraries(fullSimLight PUBLIC GeoModel2G4 ${Geant4_LIBRARIES} MagFieldServices MagFieldInterfaces ${HEPMC3_LIB}) +target_link_libraries(gmgeantino PUBLIC GeoModel2G4 ${Geant4_LIBRARIES} MagFieldServices MagFieldInterfaces ${HEPMC3_LIB}) +target_link_libraries(gm2gdml PUBLIC GeoModel2G4 ${Geant4_LIBRARIES} MagFieldServices MagFieldInterfaces ${HEPMC3_LIB}) + +target_include_directories(gmclash PUBLIC ${HEPMC3_INCLUDE_DIR}) +target_include_directories(gmmasscalc PUBLIC ${HEPMC3_INCLUDE_DIR}) +target_include_directories(fullSimLight PUBLIC ${HEPMC3_INCLUDE_DIR}) +target_include_directories(gmgeantino PUBLIC ${HEPMC3_INCLUDE_DIR}) +target_include_directories(gm2gdml PUBLIC ${HEPMC3_INCLUDE_DIR}) # Check if we are building FullSimLight individually, # or as a part of the main GeoModel. @@ -292,15 +322,15 @@ install( TARGETS FullSimLight INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) -install(FILES include/FSLSensitiveDetectorPlugin.h - include/MagFieldPlugin.h - include/FSLPhysicsListPlugin.h - include/FSLUserActionPlugin.h - include/FSLUserRunActionPlugin.h - include/FSLUserEventActionPlugin.h - include/FSLUserSteppingActionPlugin.h - include/FSLUserTrackingActionPlugin.h - include/FSLUserStackingActionPlugin.h +install(FILES FullSimLight/FSLSensitiveDetectorPlugin.h + FullSimLight/MagFieldPlugin.h + FullSimLight/FSLPhysicsListPlugin.h + FullSimLight/FSLUserActionPlugin.h + FullSimLight/FSLUserRunActionPlugin.h + FullSimLight/FSLUserEventActionPlugin.h + FullSimLight/FSLUserSteppingActionPlugin.h + FullSimLight/FSLUserTrackingActionPlugin.h + FullSimLight/FSLUserStackingActionPlugin.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/FullSimLight COMPONENT Development ) diff --git a/FullSimLight/include/FSLPhysicsListPlugin.h b/FullSimLight/FullSimLight/FSLPhysicsListPlugin.h similarity index 100% rename from FullSimLight/include/FSLPhysicsListPlugin.h rename to FullSimLight/FullSimLight/FSLPhysicsListPlugin.h diff --git a/FullSimLight/include/FSLSensitiveDetectorPlugin.h b/FullSimLight/FullSimLight/FSLSensitiveDetectorPlugin.h similarity index 100% rename from FullSimLight/include/FSLSensitiveDetectorPlugin.h rename to FullSimLight/FullSimLight/FSLSensitiveDetectorPlugin.h diff --git a/FullSimLight/include/FSLUserActionPlugin.h b/FullSimLight/FullSimLight/FSLUserActionPlugin.h similarity index 88% rename from FullSimLight/include/FSLUserActionPlugin.h rename to FullSimLight/FullSimLight/FSLUserActionPlugin.h index 729c260e5acc3d98af8bf29b3cab2abcc6cbf3a2..9b1318da895d96d94ff9b42201288d9a75aad91c 100644 --- a/FullSimLight/include/FSLUserActionPlugin.h +++ b/FullSimLight/FullSimLight/FSLUserActionPlugin.h @@ -5,6 +5,7 @@ class G4UserRunAction; class G4UserSteppingAction; class G4UserTrackingAction; class G4UserStackingAction; +class G4VUserPrimaryGeneratorAction; class FSLUserActionPlugin { @@ -23,6 +24,8 @@ class FSLUserActionPlugin { virtual G4UserSteppingAction *getSteppingAction() const { return nullptr;} virtual G4UserTrackingAction *getTrackingAction() const { return nullptr;} virtual G4UserStackingAction *getStackingAction() const { return nullptr;} + virtual G4VUserPrimaryGeneratorAction *getPrimaryGeneratorAction() const {return nullptr;} + private: diff --git a/FullSimLight/include/FSLUserEventActionPlugin.h b/FullSimLight/FullSimLight/FSLUserEventActionPlugin.h similarity index 100% rename from FullSimLight/include/FSLUserEventActionPlugin.h rename to FullSimLight/FullSimLight/FSLUserEventActionPlugin.h diff --git a/FullSimLight/include/FSLUserRunActionPlugin.h b/FullSimLight/FullSimLight/FSLUserRunActionPlugin.h similarity index 100% rename from FullSimLight/include/FSLUserRunActionPlugin.h rename to FullSimLight/FullSimLight/FSLUserRunActionPlugin.h diff --git a/FullSimLight/include/FSLUserStackingActionPlugin.h b/FullSimLight/FullSimLight/FSLUserStackingActionPlugin.h similarity index 100% rename from FullSimLight/include/FSLUserStackingActionPlugin.h rename to FullSimLight/FullSimLight/FSLUserStackingActionPlugin.h diff --git a/FullSimLight/include/FSLUserSteppingActionPlugin.h b/FullSimLight/FullSimLight/FSLUserSteppingActionPlugin.h similarity index 100% rename from FullSimLight/include/FSLUserSteppingActionPlugin.h rename to FullSimLight/FullSimLight/FSLUserSteppingActionPlugin.h diff --git a/FullSimLight/include/FSLUserTrackingActionPlugin.h b/FullSimLight/FullSimLight/FSLUserTrackingActionPlugin.h similarity index 100% rename from FullSimLight/include/FSLUserTrackingActionPlugin.h rename to FullSimLight/FullSimLight/FSLUserTrackingActionPlugin.h diff --git a/FullSimLight/include/MagFieldPlugin.h b/FullSimLight/FullSimLight/MagFieldPlugin.h similarity index 85% rename from FullSimLight/include/MagFieldPlugin.h rename to FullSimLight/FullSimLight/MagFieldPlugin.h index 7bd6cf15d7829ec7530cf8ed56ef885375621aef..eb2f0af05f8385af563408685673fca94266f2c0 100644 --- a/FullSimLight/include/MagFieldPlugin.h +++ b/FullSimLight/FullSimLight/MagFieldPlugin.h @@ -11,7 +11,7 @@ class MagFieldPlugin { // Destructor virtual ~MagFieldPlugin()=default; - virtual const G4MagneticField *getField() const=0; + virtual G4MagneticField *getField(std::string map_path) =0; private: diff --git a/FullSimLight/fullSimLight.cc b/FullSimLight/fullSimLight.cc index ee219783bcf5611bf1bd8313702455cd594fe1ca..7105c247f9f1ed0598140430c2a87ee03e8db123 100644 --- a/FullSimLight/fullSimLight.cc +++ b/FullSimLight/fullSimLight.cc @@ -24,7 +24,7 @@ #include "FSLActionInitialization.hh" #include "FSLConfigurator.hh" #include "PythiaPrimaryGeneratorAction.hh" -#include "FSLUserActionPlugin.h" +#include "FullSimLight/FSLUserActionPlugin.h" #include <getopt.h> #include <err.h> #include <iostream> @@ -189,6 +189,14 @@ int main(int argc, char** argv) { ); } + + if(!isBatch) + { + actInit->SetGenerator(simConfig::fsl.eventGeneratorName); + actInit->SetHepMC3FilePath(simConfig::fsl.hepmc3InputFile); + actInit->SetHepMC3FileType(simConfig::fsl.hepmc3TypeOfFile); + actInit->SetGeneratorPlugin(simConfig::fsl.generatorPlugin); + } // set the name of a region in which we are interested to see a very basic simulation // stat e.g. "EMEC" (NOTE: only if the given region can be found and executed in @@ -224,6 +232,12 @@ int main(int argc, char** argv) { detector->SetGeometryFileName (simConfig::fsl.geometry); runManager->SetUserInitialization(detector); + + if(simConfig::fsl.magFieldType=="Map") + { + detector->SetMagFieldPluginPath(simConfig::fsl.magFieldPlugin); + detector->SetMagFieldMapPath(simConfig::fsl.magFieldMap); + } //parse RegionsData @@ -288,7 +302,7 @@ int main(int argc, char** argv) { << " Geometry file = " << simConfig::fsl.geometry << G4endl << " Physics list name = " << simConfig::fsl.physicsList << G4endl << " Generator = " << simConfig::fsl.eventGeneratorName << G4endl - << " Magnetic Field = " << simConfig::fsl.magFieldIntensity << G4endl + << " Magnetic Field = " << simConfig::fsl.magFieldType << G4endl << " Run Overlap Check = " << parRunOverlapCheck << G4endl << " ===================================================== " << G4endl; diff --git a/FullSimLight/include/FSLActionInitialization.hh b/FullSimLight/include/FSLActionInitialization.hh index 08675e5047380fa180993b5f66410e6a8483ca05..217308a03eafb635ade008303f665d43c9e1c7e1 100644 --- a/FullSimLight/include/FSLActionInitialization.hh +++ b/FullSimLight/include/FSLActionInitialization.hh @@ -23,13 +23,33 @@ public: { userActions = usrActions; }; + void SetGenerator(std::string gen) + { + generator = gen; + } + void SetHepMC3FilePath(std::string file_path) + { + hepmc3_file_path = file_path; + } + void SetHepMC3FileType(std::string file_type) + { + hepmc3_file_type = file_type; + } + void SetGeneratorPlugin(std::string gen_plug) + { + generator_plugin = gen_plug; + } private: GeantinoMapsConfigurator* fGeantinoMapsConfig; bool fIsPerformance; bool fCustomUserActions; G4String fSpecialScoringRegionName; - + std::string generator; + std::string hepmc3_file_path = ""; + std::string hepmc3_file_type = ""; + std::string generator_plugin = ""; + std::vector<std::string> userActions; diff --git a/FullSimLight/include/FSLConfigurator.hh b/FullSimLight/include/FSLConfigurator.hh index bc678af605db6c47fcfae46360a3c41da9fa9ce9..54160424622c32cc633e09b8e2b4c3161044aba1 100644 --- a/FullSimLight/include/FSLConfigurator.hh +++ b/FullSimLight/include/FSLConfigurator.hh @@ -50,14 +50,19 @@ struct fslConfig{ std::string eventInputFile; std::string typeOfEvent; + std::string hepmc3InputFile; + std::string hepmc3TypeOfFile; + + std::string generatorPlugin; + std::vector<std::string> sensitiveDetectors; - std::string outputHitsFile; - std::string outputHistoFile; + // std::string outputHitsFile; + // std::string outputHistoFile; std::vector<regionConfig> regionsData; std::string magFieldType; - std::string magFieldIntensity; + // std::string magFieldIntensity; std::string magFieldMap; std::string magFieldPlugin; @@ -72,7 +77,10 @@ regionConfig rc; json jf; inline void to_json(json& j, const fslConfig& p) { - j = json{{"Geometry", p.geometry},{"Physics list name", p.physicsList},{"Number of events", p.nEvents},{"Magnetic Field Intensity", p.magFieldIntensity},{"Generator", p.eventGeneratorName},{"Event input file", p.eventInputFile},{"Type of event", p.typeOfEvent},{"Sensitive Detector Extensions", p.sensitiveDetectors},{"Output Hits file", p.outputHitsFile},{"Output Histo file", p.outputHistoFile},{"Magnetic Field Type", p.magFieldType},{"Magnetic Field Map", p.magFieldMap},{"Magnetic Field Plugin", p.magFieldPlugin},{"User Action Extensions", p.userActions},{"g4ui_commands", p.g4UiCommands}}; + j = json{{"Geometry", p.geometry},{"Physics list name", p.physicsList},{"Number of events", p.nEvents},{"Generator", p.eventGeneratorName},{"Pythia event input file", p.eventInputFile},{"Pythia type of event", p.typeOfEvent},{"Sensitive Detector Extensions", p.sensitiveDetectors},{"Magnetic Field Type", p.magFieldType},{"Magnetic Field Map", p.magFieldMap},{"Magnetic Field Plugin", p.magFieldPlugin},{"User Action Extensions", p.userActions},{"g4ui_commands", p.g4UiCommands}, + {"HepMC3 file", p.hepmc3InputFile}, {"HepMC3 type of file", p.hepmc3TypeOfFile}, + {"Generator Plugin", p.generatorPlugin} + }; } inline void to_json(json& j, const regionConfig& r) { @@ -83,19 +91,17 @@ inline void from_json(const json& j, fslConfig& p) { p.physicsList=j.at("Physics list name").get<std::string>(); p.nEvents=j.at("Number of events").get<int>(); p.magFieldType=j.at("Magnetic Field Type").get<std::string>(); - p.magFieldIntensity=j.at("Magnetic Field Intensity").get<std::string>(); p.eventGeneratorName=j.at("Generator").get<std::string>(); - p.eventInputFile=j.at("Event input file").get<std::string>(); - p.typeOfEvent=j.at("Type of event").get<std::string>(); + p.eventInputFile=j.at("Pythia event input file").get<std::string>(); + p.typeOfEvent=j.at("Pythia type of event").get<std::string>(); p.sensitiveDetectors=j.at("Sensitive Detector Extensions").get<std::vector<std::string>>(); - p.outputHitsFile=j.at("Output Hits file").get<std::string>(); - p.outputHistoFile=j.at("Output Histo file").get<std::string>(); p.magFieldMap=j.at("Magnetic Field Map").get<std::string>(); p.magFieldPlugin=j.at("Magnetic Field Plugin").get<std::string>(); p.userActions=j.at("User Action Extensions").get<std::vector<std::string>>(); - p.g4UiCommands=j.at("g4ui_commands").get<std::vector<std::string>>(); - + p.hepmc3InputFile = j.at("HepMC3 file").get<std::string>(); + p.hepmc3TypeOfFile = j.at("HepMC3 type of file").get<std::string>(); + p.generatorPlugin = j.at("Generator Plugin").get<std::string>(); } inline void from_json(const json& j, regionConfig& r) { diff --git a/FullSimLight/include/FSLDetectorConstruction.hh b/FullSimLight/include/FSLDetectorConstruction.hh index cdc727f3d504a05af38fa79a6b853230f0e36231..997224bfb0ee4bff7e84d8dd16dfc241cb22d180 100644 --- a/FullSimLight/include/FSLDetectorConstruction.hh +++ b/FullSimLight/include/FSLDetectorConstruction.hh @@ -65,6 +65,8 @@ public: } void AddSensitiveDetectorPlugin(const std::string & SDPluginName) { sensitiveDetectorPluginName.push_back(SDPluginName);} + void SetMagFieldPluginPath(const std::string &MFPluginName) {mag_field_plugin_path = MFPluginName;} + void SetMagFieldMapPath(const std::string &MFPathName){mag_field_map_path = MFPathName;} void ConfigureRegionsFSL(std::vector<std::string> reg, std::vector<std::vector<G4String>> root_lv_names, @@ -119,6 +121,8 @@ private: std::vector<std::string> sensitiveDetectorPluginName; + std::string mag_field_plugin_path; + std::string mag_field_map_path; //Regions Data std::vector<std::string> Regions; diff --git a/FullSimLight/include/HepMC3G4AsciiReader.hh b/FullSimLight/include/HepMC3G4AsciiReader.hh new file mode 100644 index 0000000000000000000000000000000000000000..c97669533a8c325b58d5922cba14024aac40538b --- /dev/null +++ b/FullSimLight/include/HepMC3G4AsciiReader.hh @@ -0,0 +1,65 @@ + +#ifndef HEPMC3_G4_ASCII_READER_H +#define HEPMC3_G4_ASCII_READER_H + +#include "HepMC3G4Interface.hh" +#include "HepMC3/GenEvent.h" +#include "HepMC3/Print.h" +#include "HepMC3/Units.h" +#include "G4AutoLock.hh" +#include "HepMC3/ReaderAsciiHepMC2.h" +#include "HepMC3/ReaderAscii.h" + + +/*#if USE_ROOT +#include "HepMC3/ReaderRoot.h" +#endif*/ + +namespace { +G4Mutex mutino = G4MUTEX_INITIALIZER; + +} +class HepMC3G4AsciiReader : public HepMC3G4Interface { + +public: + + ~HepMC3G4AsciiReader(); + static HepMC3G4AsciiReader * GetInstance(G4String name,G4String reader_type) + { + if (m_pOnlyOneInstance == NULL) + { + G4cout<<"Going to lock in HepMC3G4AsciiReader::GetInstance"<<G4endl; + G4AutoLock lock(mutino); + G4cout<<"HepMC3G4AsciiReader::GetInstance MUTEX IS MINE"<<G4endl; + if (m_pOnlyOneInstance == NULL) + // Solution 1 and 2 gaps addressed by moving + // critical section block and by re-doing this check! + { + m_pOnlyOneInstance = new HepMC3G4AsciiReader(name,reader_type); + } + lock.unlock(); + G4cout<<"HepMC3G4AsciiReader::GetInstance MUTEX unlocked"<<G4endl; + } + return m_pOnlyOneInstance; + } +protected: + HepMC3G4AsciiReader(G4String name,G4String reader_type ); + HepMC3::ReaderAsciiHepMC2* asciiInput; + HepMC3::ReaderAscii* asciiv3Input; + +/*#if USE_ROOT + HepMC3::ReaderRoot* rootInput; +#endif*/ + + std::shared_ptr<HepMC3::GenEvent> evt; + //HepMC3::ReaderMT<HepMC3::ReaderAsciiHepMC2,8> *asciiInput; + virtual HepMC3::GenEvent* GenerateHepMC3Event() final override; +private: + G4String reader; + static HepMC3G4AsciiReader * m_pOnlyOneInstance; + +}; + + +#endif + diff --git a/FullSimLight/include/HepMC3G4Interface.hh b/FullSimLight/include/HepMC3G4Interface.hh new file mode 100644 index 0000000000000000000000000000000000000000..d3d43e2b21c164843540006618b6e2abcbf5038e --- /dev/null +++ b/FullSimLight/include/HepMC3G4Interface.hh @@ -0,0 +1,53 @@ + +#ifndef HEPMC3_G4_INTERFACE_H +#define HEPMC3_G4_INTERFACE_H + +#include "G4VPrimaryGenerator.hh" +#include "HepMC3/GenEvent.h" +#include "HepMC3/GenVertex.h" +#include "HepMC3/GenParticle.h" + + +/// A base class for primary generation via HepMC3 object. +/// This class is derived from G4VPrimaryGenerator. + +class HepMC3G4Interface : public G4VPrimaryGenerator { +protected: + // Note that the life of HepMC3 event object must be handled by users. + // In the default implementation, a current HepMC event will be + // deleted at GeneratePrimaryVertex() in the next event. + HepMC3::GenEvent* hepmcEvent; // (care for single event case only) + + // We have to take care for the position of primaries because + // primary vertices outside the world voulme give rise to G4Execption. + // If the default implementation is not adequate, an alternative + // can be implemented in your own class. + virtual G4bool CheckVertexInsideWorld(const G4ThreeVector& pos) const; + + // service method for conversion from HepMC::GenEvent to G4Event + void HepMC32G4(const HepMC3::GenEvent* hepmcevt, G4Event* g4event); + + // Implement this method in his/her own concrete class. + // An empty event will be created in default. + virtual HepMC3::GenEvent* GenerateHepMC3Event(); + +public: + HepMC3G4Interface(); + virtual ~HepMC3G4Interface(); + + // set/get methods + HepMC3::GenEvent* GetHepMC3GenEvent() const; + + // The default behavior is that a single HepMC event generated by + // GenerateHepMCEvent() will be converted to G4Event through HepMC2G4(). + virtual void GeneratePrimaryVertex(G4Event* anEvent); +}; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... +inline HepMC3::GenEvent* HepMC3G4Interface::GetHepMC3GenEvent() const +{ + return hepmcEvent; +} + +#endif + diff --git a/FullSimLight/include/HepMC3PrimaryGeneratorAction.hh b/FullSimLight/include/HepMC3PrimaryGeneratorAction.hh new file mode 100644 index 0000000000000000000000000000000000000000..7e642239db39c65116de3e31b55375b6f0626423 --- /dev/null +++ b/FullSimLight/include/HepMC3PrimaryGeneratorAction.hh @@ -0,0 +1,27 @@ +#ifndef HepMC3PrimaryGeneratorAction_h +#define HepMC3PrimaryGeneratorAction_h 1 + +#include "G4VUserPrimaryGeneratorAction.hh" +#include "globals.hh" +#include "HepMC3G4AsciiReader.hh" + +class G4Event; +class G4VPrimaryGenerator; + +class HepMC3PrimaryGeneratorAction : public G4VUserPrimaryGeneratorAction + +{ + +public: + HepMC3PrimaryGeneratorAction(std::string file_path,std::string file_type); + ~HepMC3PrimaryGeneratorAction(); + virtual void GeneratePrimaries(G4Event* anEvent); + +private: + HepMC3G4AsciiReader* HEPMC3_generator; + + + +}; + +#endif diff --git a/FullSimLight/src/FSLActionInitialization.cc b/FullSimLight/src/FSLActionInitialization.cc index a7a8c9943af116e9dd3971325b54bbb7f4e587a7..60ce0820bde90b72903dd41c92a490f0b040c728 100644 --- a/FullSimLight/src/FSLActionInitialization.cc +++ b/FullSimLight/src/FSLActionInitialization.cc @@ -1,18 +1,18 @@ - #include "FSLActionInitialization.hh" #include "GeoModelKernel/GeoPluginLoader.h" #include "FSLPrimaryGeneratorAction.hh" +#include "HepMC3PrimaryGeneratorAction.hh" #include "FSLRunAction.hh" #include "FSLEventAction.hh" #include "FSLSteppingAction.hh" #include "FSLTrackingAction.hh" #include "PythiaPrimaryGeneratorAction.hh" -#include "FSLUserActionPlugin.h" -#include "FSLUserRunActionPlugin.h" -#include "FSLUserEventActionPlugin.h" -#include "FSLUserStackingActionPlugin.h" -#include "FSLUserTrackingActionPlugin.h" -#include "FSLUserSteppingActionPlugin.h" +#include "FullSimLight/FSLUserActionPlugin.h" +#include "FullSimLight/FSLUserRunActionPlugin.h" +#include "FullSimLight/FSLUserEventActionPlugin.h" +#include "FullSimLight/FSLUserStackingActionPlugin.h" +#include "FullSimLight/FSLUserTrackingActionPlugin.h" +#include "FullSimLight/FSLUserSteppingActionPlugin.h" #include "G4Version.hh" @@ -71,7 +71,31 @@ void FSLActionInitialization::BuildForMaster() const { void FSLActionInitialization::Build() const { #if !USE_PYTHIA - SetUserAction(new FSLPrimaryGeneratorAction()); + + if(generator == "HepMC3 File") + { + std::cout << "Reading in events from file: " << hepmc3_file_path << std::endl; + SetUserAction(new HepMC3PrimaryGeneratorAction(hepmc3_file_path,hepmc3_file_type)); + + } + + else if(generator == "Generator Plugin") + { + std::cout << "Loading in event generator from plugin" << std::endl; + GeoPluginLoader<FSLUserActionPlugin> generator_loader; + const FSLUserActionPlugin * gen_plugin = generator_loader.load(generator_plugin); + + if (gen_plugin->getPrimaryGeneratorAction()) SetUserAction(gen_plugin->getPrimaryGeneratorAction()); + else + { + std::cout << "Error loading in Plugin, exiting now..." << std::endl; + exit(-1); + } + + } + else + {SetUserAction(new FSLPrimaryGeneratorAction());} + #else if (use_pythia()) { // seed each generator/thread by 1234 if perfomance mode run and use the event @@ -79,7 +103,30 @@ void FSLActionInitialization::Build() const { G4int pythiaSeed = fIsPerformance ? -1 : 0; SetUserAction(new PythiaPrimaryGeneratorAction(pythiaSeed)); } else { - SetUserAction(new FSLPrimaryGeneratorAction()); + if(generator == "HepMC3 File") + { + std::cout << "Reading in events from file: " << hepmc3_file_path << std::endl; + SetUserAction(new HepMC3PrimaryGeneratorAction(hepmc3_file_path,hepmc3_file_type)); + + } + + else if(generator == "Generator Plugin") + { + std::cout << "Loading in event generator from plugin" << std::endl; + GeoPluginLoader<FSLUserActionPlugin> generator_loader; + const FSLUserActionPlugin * gen_plugin = generator_loader.load(generator_plugin); + + if (gen_plugin->getPrimaryGeneratorAction()) SetUserAction(gen_plugin->getPrimaryGeneratorAction()); + else + { + std::cout << "Error loading in Plugin, exiting now..." << std::endl; + exit(-1); + } + + } + else + {SetUserAction(new FSLPrimaryGeneratorAction());} + } #endif diff --git a/FullSimLight/src/FSLDetectorConstruction.cc b/FullSimLight/src/FSLDetectorConstruction.cc index 377126b0d4bb6bc288342d837a52f9f0f62adacf..2864c2d74b7f691219878cba37210fe101b51eaa 100644 --- a/FullSimLight/src/FSLDetectorConstruction.cc +++ b/FullSimLight/src/FSLDetectorConstruction.cc @@ -1,6 +1,7 @@ #include "FSLDetectorConstruction.hh" #include "FSLDetectorMessenger.hh" #include "RegionConfigurator.hh" +#include "FullSimLight/MagFieldPlugin.h" #include "MassCalculator.hh" #include "ClashDetector.hh" #include "MagFieldServices/AtlasFieldSvc.h" @@ -71,7 +72,7 @@ #include "GeoModelKernel/GeoVolumeCursor.h" // For Sensitive Detector plugins: -#include "FSLSensitiveDetectorPlugin.h" +#include "FullSimLight/FSLSensitiveDetectorPlugin.h" #include "FSLSDPluginLoader.h" #include "G4VSensitiveDetector.hh" #include "G4LogicalVolumeStore.hh" @@ -410,14 +411,26 @@ void FSLDetectorConstruction::ConstructSDandField() G4cout << G4endl << " *** MAGNETIC FIELD IS OFF *** " << G4endl << G4endl; } else // if (!fFieldConstant) - { - G4cout << G4endl << " *** MAGNETIC FIELD SET FROM FILE *** " << G4endl << G4endl; - if (fField.Get() == 0) - { - StandardFieldSvc* FSLMagField = new StandardFieldSvc("StandardFieldSvc"); - G4MagneticField* g4Field = FSLMagField->getField(); - if(g4Field==nullptr) std::cout<<"Error, g4Field is null!"<<std::endl; - fField.Put(g4Field); + { + G4cout << G4endl << " *** MAGNETIC FIELD SET FROM FILE *** " << G4endl << G4endl; + if (fField.Get() == 0) + { + if(mag_field_plugin_path == "") + { + StandardFieldSvc* FSLMagField = new StandardFieldSvc("StandardFieldSvc"); + G4MagneticField* g4Field = FSLMagField->getField(); + if(g4Field==nullptr) std::cout<<"Error, g4Field is null!"<<std::endl; + fField.Put(g4Field); + } + else + { + GeoPluginLoader<MagFieldPlugin> loader; + MagFieldPlugin *plugin=loader.load(mag_field_plugin_path); + G4MagneticField *g4Field=plugin->getField(mag_field_map_path); + delete plugin; + if(g4Field==nullptr) std::cout<<"Error, g4Field is null!"<<std::endl; + fField.Put(g4Field); + } //This is thread-local G4FieldManager* fieldMgr = diff --git a/FullSimLight/src/FSLPhysListFactory.cc b/FullSimLight/src/FSLPhysListFactory.cc index 34e9584786dd240144e743ef65c31986089bd427..35527802982f64de2bafa464be44ac2a8417cfd9 100644 --- a/FullSimLight/src/FSLPhysListFactory.cc +++ b/FullSimLight/src/FSLPhysListFactory.cc @@ -11,7 +11,7 @@ #include "EmExtraPhysics.hh" #include "GeoModelKernel/GeoPluginLoader.h" -#include "FSLPhysicsListPlugin.h" +#include "FullSimLight/FSLPhysicsListPlugin.h" #include <string> @@ -107,4 +107,4 @@ G4VModularPhysicsList* FSLPhysListFactory::GetPhysList(const std::string physLis } -//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... \ No newline at end of file +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... diff --git a/FullSimLight/src/HepMC3G4AsciiReader.cc b/FullSimLight/src/HepMC3G4AsciiReader.cc new file mode 100644 index 0000000000000000000000000000000000000000..91588d2ed06bf1b818063cd4f92ce893e4ded35b --- /dev/null +++ b/FullSimLight/src/HepMC3G4AsciiReader.cc @@ -0,0 +1,100 @@ + + +#include "HepMC3G4AsciiReader.hh" +#include <iostream> +#include <fstream> +#include "G4AutoLock.hh" + + +HepMC3G4AsciiReader* HepMC3G4AsciiReader::m_pOnlyOneInstance=nullptr; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... +HepMC3G4AsciiReader::HepMC3G4AsciiReader(G4String name,G4String reader_type ) +{ + // evt = HepMC3::GenEvent(HepMC3::Units::GEV ,HepMC3::Units::MM); + +reader = reader_type; +evt= std::make_shared<HepMC3::GenEvent>(); + + // + if(reader=="Ascii") + { + asciiInput = new HepMC3::ReaderAsciiHepMC2(name.c_str()); + } + else if (reader=="Asciiv3") + { + asciiv3Input = new HepMC3::ReaderAscii(name.c_str()); + } +/*#if USE_ROOT + else if (reader=="Root") + { + rootInput = new HepMC3::ReaderRoot(name.c_str()); + } +#endif*/ + else + { + std::cout << "Unsupported Event File type: Exiting now" << std::endl; + exit(-1); + } + +//std::cout << "Hey once!!!!!" << std::endl; + + //asciiInput = new HepMC3::ReaderMT<HepMC3::ReaderAsciiHepMC2,8>(filename); +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... +HepMC3G4AsciiReader::~HepMC3G4AsciiReader() +{ + if(reader=="Ascii") + { + delete asciiInput; + } + else if (reader=="Asciiv3") + { + delete asciiv3Input; + } +/*#if USE_ROOT + else if (reader=="Root") + { + delete rootInput; + } +#endif*/ +} + + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... +HepMC3::GenEvent* HepMC3G4AsciiReader::GenerateHepMC3Event() +{ + evt->clear(); + // evt = HepMC3::GenEvent(HepMC3::Units::GEV ,HepMC3::Units::MM); + // evt= std::make_shared<HepMC3::GenEvent>(); + + if(reader=="Ascii") + { + asciiInput->read_event(*evt); + HepMC3::Print::listing(*evt); + HepMC3::Print::content(*evt); + if(asciiInput->failed()) return 0; + } + + else if(reader=="Asciiv3") + { + asciiv3Input->read_event(*evt); + HepMC3::Print::listing(*evt); + HepMC3::Print::content(*evt); + if(asciiv3Input->failed()) return 0; + } + +/*#if USE_ROOT + + else if(reader=="Root") + { + rootInput->read_event(*evt); + if(rootInput->failed()) return 0; + } +#endif*/ + // no more event + + return evt.get(); +} + diff --git a/FullSimLight/src/HepMC3G4Interface.cc b/FullSimLight/src/HepMC3G4Interface.cc new file mode 100644 index 0000000000000000000000000000000000000000..851d3acd57d00b4ce0b1345acbcc208aa5fd713c --- /dev/null +++ b/FullSimLight/src/HepMC3G4Interface.cc @@ -0,0 +1,116 @@ + +#include "HepMC3G4Interface.hh" + +#include "G4RunManager.hh" +#include "G4LorentzVector.hh" +#include "G4Event.hh" +#include "G4PrimaryParticle.hh" +#include "G4PrimaryVertex.hh" +#include "G4TransportationManager.hh" +#include "G4PhysicalConstants.hh" +#include "G4SystemOfUnits.hh" + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... +HepMC3G4Interface::HepMC3G4Interface() +{ +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... +HepMC3G4Interface::~HepMC3G4Interface() +{ + //delete hepmcEvent; +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... +G4bool HepMC3G4Interface::CheckVertexInsideWorld + (const G4ThreeVector& pos) const +{ + G4Navigator* navigator= G4TransportationManager::GetTransportationManager() + -> GetNavigatorForTracking(); + + G4VPhysicalVolume* world= navigator-> GetWorldVolume(); + G4VSolid* solid= world-> GetLogicalVolume()-> GetSolid(); + EInside qinside= solid-> Inside(pos); + + if( qinside != kInside) return false; + else return true; +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... +void HepMC3G4Interface::HepMC32G4(const HepMC3::GenEvent* hepmcevt,G4Event* g4event) +{ + for(const auto &vitr : hepmcevt->vertices() ) { // loop for vertex ... + + // real vertex? + G4bool qvtx=false; + for (const auto &pitr : vitr->particles_out()) { + + if (!pitr->end_vertex() && pitr->status()==1) { + qvtx=true; + break; + } + } + + if (!qvtx) continue; + + // check world boundary + HepMC3::FourVector pos= vitr->position(); + G4LorentzVector xvtx(pos.x(), pos.y(), pos.z(), pos.t()); + if (! CheckVertexInsideWorld(xvtx.vect()*mm)) + { + G4cout<<"Vertex is not inside the World"<<G4endl; + continue; + + } + + // create G4PrimaryVertex and associated G4PrimaryParticles + G4PrimaryVertex* g4vtx= + new G4PrimaryVertex(xvtx.x()*mm, xvtx.y()*mm, xvtx.z()*mm, + xvtx.t()*mm/c_light); + + for (const auto &vpitr : vitr->particles_out()) { + + if( vpitr->status() != 1 ) { + G4cout<<"Status not equal to one!"<<G4endl; + continue; + + } + + G4int pdgcode= vpitr-> pid(); + G4cout << "Particle pdgcode: "<<pdgcode << G4endl; + HepMC3::FourVector pos1= vpitr->momentum(); + G4LorentzVector p(pos1.px(), pos1.py(), pos1.pz(), pos1.e()); + G4PrimaryParticle* g4prim= + new G4PrimaryParticle(pdgcode, p.x()*GeV, p.y()*GeV, p.z()*GeV); + + g4vtx-> SetPrimary(g4prim); + } + g4event-> AddPrimaryVertex(g4vtx); + } +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... +HepMC3::GenEvent* HepMC3G4Interface::GenerateHepMC3Event() +{ + HepMC3::GenEvent* aevent= new HepMC3::GenEvent(); + return aevent; +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... +void HepMC3G4Interface::GeneratePrimaryVertex(G4Event* anEvent) +{ + // delete previous event object + + + // generate next event + hepmcEvent= GenerateHepMC3Event(); + if(! hepmcEvent) { + G4cout << "HepMCInterface: no generated particles. run terminated..." + << G4endl; + G4RunManager::GetRunManager()-> AbortRun(); + return; + } + HepMC32G4(hepmcEvent, anEvent); + //delete hepmcEvent; +} + diff --git a/FullSimLight/src/HepMC3PrimaryGeneratorAction.cc b/FullSimLight/src/HepMC3PrimaryGeneratorAction.cc new file mode 100644 index 0000000000000000000000000000000000000000..1b4f7b138ed7b085d23671ee07d470875204bb17 --- /dev/null +++ b/FullSimLight/src/HepMC3PrimaryGeneratorAction.cc @@ -0,0 +1,30 @@ +#include "HepMC3PrimaryGeneratorAction.hh" +#include "G4ParticleGun.hh" +#include "HepMC3G4AsciiReader.hh" +#include "G4AutoLock.hh" + +namespace { + G4Mutex mutex_gen = G4MUTEX_INITIALIZER; + +} + + +HepMC3PrimaryGeneratorAction::HepMC3PrimaryGeneratorAction(std::string file_path,std::string file_type) : G4VUserPrimaryGeneratorAction() +{ + HEPMC3_generator=HepMC3G4AsciiReader::GetInstance(file_path, file_type); +} +HepMC3PrimaryGeneratorAction::~HepMC3PrimaryGeneratorAction() +{ +delete HEPMC3_generator; +} + +void HepMC3PrimaryGeneratorAction::GeneratePrimaries(G4Event* anEvent) + +{ + G4cout<<"HepMC3PrimaryGeneratorAction::GeneratePrimaries going to lock"<<G4endl; + G4AutoLock lock(&mutex_gen); + G4cout<<"HepMC3PrimaryGeneratorAction::GeneratePrimaries MUTEX IS MINE"<<G4endl; + HEPMC3_generator->GeneratePrimaryVertex(anEvent); + lock.unlock(); + G4cout<<"HepMC3PrimaryGeneratorAction::GeneratePrimaries MUTEX unlocked"<<G4endl; +} diff --git a/GeoModelVisualization/GXHitDisplaySystems/CMakeLists.txt b/GeoModelVisualization/GXHitDisplaySystems/CMakeLists.txt index ff87b6186a4dbf20aa68ad3b0bd62246fb99483b..6637e020d8f1144db3c3632cbf85051d6c462fb9 100644 --- a/GeoModelVisualization/GXHitDisplaySystems/CMakeLists.txt +++ b/GeoModelVisualization/GXHitDisplaySystems/CMakeLists.txt @@ -4,12 +4,12 @@ file( GLOB SOURCES src/*.cxx ) file( GLOB HEADERS GXHitDisplaySystems/*.h ) file( GLOB UIS src/*.ui ) - +find_package (HDF5 REQUIRED) # Add the library. add_library( GXHitDisplaySystems SHARED ${SOURCES} ${HEADERS} ${UIS} ) target_link_libraries( GXHitDisplaySystems PUBLIC Coin::Coin GXBase - PRIVATE Qt5::Core Qt5::Widgets ${HDF5_LIBRARIES} ) + PRIVATE Qt5::Core Qt5::Widgets ${HDF5_CXX_LIBRARIES} ${HDF5_LIBRARIES} ) target_include_directories( GXHitDisplaySystems PUBLIC ${HDF5_CXX_INCLUDE_DIRS} $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> diff --git a/LArCustomSolidExtension b/LArCustomSolidExtension deleted file mode 160000 index b0c7b11bca941c71200572bb80d55ca3f2e398d5..0000000000000000000000000000000000000000 --- a/LArCustomSolidExtension +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b0c7b11bca941c71200572bb80d55ca3f2e398d5